Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- definers.lua - code to define blogme words. -- This is part of blogme3. -- The semantics for a blogme word FOO is determined by an "argument -- parsing" function for FOO, stored in _A["FOO"], and by the "blogme -- code" for FOO, a function stored in _B["FOO"]; see -- (find-blogme3 "brackets.lua") -- for the details. -- -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2007apr16 -- <http://anggtwu.net/blogme3/definers.lua> -- <http://anggtwu.net/blogme3/definers.lua.html> -- License: GPL. -- -- (find-a2ps (buffer-file-name)) -- «._AA» (to "_AA") -- «.undollar» (to "undollar") -- «.tools» (to "tools") -- «.def» (to "def") -- «.odef» (to "odef") -- «_AA» (to "._AA") --------[ Short names for arglist parsers ]-------- _AA = {} for short,long in each2(split [[ 1 readvrest 1L readvlist 1Q readqrest 0 nop 2 readvvrest 2L readvvlist 2Q readqqrest * readvargs 3 readvvvrest 3L readvvvlist 3Q readqqqrest 4 readvvvvrest 4L readvvvvlist 4Q readqqqqrest 5 readvvvvvrest 5L readvvvvvlist 5Q readqqqqqrest ]]) do _AA[short] = _G[long] or error(format("Not in _G (to fill _AA[%q]): %s", short, long)) end -- «undollar» (to ".undollar") --------[ Functions to transform code ]-------- wrap_f = function (arglist, body) -- here body is made of statements return "function ("..arglist..")\n"..body.."\nend" end wrap_fr = function (arglist, body) -- here body is an expression return "function ("..arglist..")\nreturn "..body.."\nend" end -- undollar: apply three kinds of "string interpolations" on code. -- This is very hard to understand without examples, so: -- -- undollar [[ "foo $bar plic" ]] --> [[ "foo "..bar.." plic" ]] -- undollar [[ "foo$(bar)plic" ]] --> [[ "foo"..(bar).."plic" ]] -- undollar " [[foo$[1+2]bar]] " --> " [[foo]]..(1+2)..[[bar]] " -- undollar = function (code) code = string.gsub(code, "%$([a-z]+)", "\"..%1..\"") code = string.gsub(code, "%$(%b())", "\"..%1..\"") code = string.gsub(code, "%$(%b[])", function (s) return "]]..("..strsub(s, 2, -2)..")..[[" end) return code end -- «tools» (to ".tools") --------[ Tool functions for def ]-------- -- Note: it is possible to define blogme words that are "private to -- the blogme vocabulary" by putting their code in _B["wordname"], but -- it is also possible to make blogme words accessible as lua globals. -- The evaluator, evalblock(startpos), searches for the blogme code of -- a word, say, "foo", first in _B["foo"], then in _G["foo"]; and if -- it is stored in _G["foo"] then we can call foo from Lua as -- foo(arg1, arg2, ...). -- -- Some of the functions below come in pairs - one variant stores the -- blogme code in _G, another one in _B. _S = _S or {} def_split = function (defstr) return string.match(defstr, "^%s*(%S+)%s+(%S+)%s+(%S+)%s(.*)") end def_set_A = function (name, apspec) _A[name] = _AA[apspec] or _G[apspec] or error(format("Not in _AA or _G (to fill _A[%q]): %q", name, apspec)) end def_set_B = function (name, funtext) _B[name] = assert(loadstring("return " .. funtext, name))() _S[name] = funtext end def_set_G = function (name, funtext) _G[name] = assert(loadstring("return " .. funtext, name))() _S[name] = funtext end --------[ More tools for def, with support for precompilation ]-------- _defs = _defs or {} def_set_AB = function (name, apspec, funtext) def_set_A(name, apspec) def_set_B(name, funtext) tinsert(_defs, {name, apspec, "_B", funtext}) end def_set_AG = function (name, apspec, funtext) def_set_A(name, apspec) def_set_G(name, funtext) tinsert(_defs, {name, apspec, "_G", funtext}) end def_as_lua = function (navc, bdelim, edelim) local name, apspec, var, code = unpack(navc) return format([[ _A[%q] = _AA[%q] or _G[%q] %s[%q] = %s _S[%q] = %s%s%s ]], name, apspec, apspec, var, name, code, name, (bdelim or "[=["), code, (edelim or "]=]")) end defs_as_lua = function () return table.concat(map(def_as_lua, _defs), "\n") end -- «def» (to ".def") -- New version: (find-blogme4 "def.lua" "def") --------[ def itself, plus variations ]-------- -- In def and bdef a "return" is added; the "body" is an expression. -- In def_ and bdef_ no "return" is added; the body is made of statements. -- In bdef and bdef_ the new word is stored in _B and it does not -- become a lua global. def = function (defstr) local name, apspec, arglist, body = def_split(defstr) def_set_AG(name, apspec, wrap_fr(arglist, undollar(body))) end bdef = function (defstr) local name, apspec, arglist, body = def_split(defstr) def_set_AB(name, apspec, wrap_fr(arglist, undollar(body))) end def_ = function (defstr) local name, apspec, arglist, body = def_split(defstr) def_set_AG(name, apspec, wrap_f(arglist, undollar(body))) end bdef_ = function (defstr) local name, apspec, arglist, body = def_split(defstr) def_set_AB(name, apspec, wrap_f(arglist, undollar(body))) end --------[ odef ]-------- -- «odef» (to ".odef") -- 2014jan25, from (find-blogme3 "youtube.lua") -- See: (find-blogme3 "options.lua") lua_eval = function (str) return assert(loadstring(str))() end lua_expr = function (str) return assert(loadstring("return "..str))() end odef_split = function (odefstr) return string.match(odefstr, "^%s*(%S+)%s+(%S+)%s+(.*)") end odef_ = function (odefstr) local optname, argstr, body = odef_split(odefstr) return format('_O["-%s"] = function (%s)\n%s\ndooptions(...)\nend\n'.. 'dooption_%s = _O["-%s"]\n', optname, argstr, body, optname, optname) end odef = function (odefstr) lua_eval(odef_(odefstr)) end --------[ DEF ]-------- -- DEF: a quick hack to define Blogme words from inside Blogme code, -- without having execute any Lua code directly. Here's an example: -- the BlogMe block below -- -- [DEF DEFED-HREF 2 url,text <a href="[$ url]">[$ text]</a>] -- -- defines a word DEFED-HREF by running this, in Lua: -- -- _A["DEFED-HREF"] = _AA["2"] or _G["2"] -- _G["DEFED-HREF"] = function (url,text) -- return runwithvars(splitatcommas("url,text"), {url,text}, -- doblogme, -- "<a href=\"[$ url]\">[$ text]</a>") -- end -- -- But hey, beware!!! DEF passes arguments (and restores them later) -- using global variables... This makes a big buggy mess when we start -- to call one DEF-defined word from inside another one, or when we -- choose bad names for the arguments. Welcome to the worst side of -- the macro languages of the 70's!... :-) -- See: (find-elnode "Scope") -- (find-blogme3file "definers.lua" "def =") -- (find-blogmefile "blogme2-middle.lua" "`[DEF ...]'") -- (find-blogmefile "blogme2-middle.lua" "withvars =") -- (find-anggfile "TH/index.blogme3" "DEF BOX") runwithvars = function (varnames, values, f, ...) local backups = {} for i,varname in ipairs(varnames) do -- for each varname, backups[i] = _G[i] -- backup global variable, _G[varname] = values[i] -- then set global variable end local results = pack(f(unpack(arg))) -- run f (in the changed environment) for i,varname in ipairs(varnames) do -- for each varname, _G[varname] = backups[i] -- restore global variable end return unpack(results) end splitatcommas = function (str) return split(str, "([^,]+)") end wrap_rwvdoblogme = function (vars, body) return format("runwithvars(splitatcommas(%q), {%s},\ doblogme,\ %q)", vars, vars, body) end def [[ DEF 4Q name,apspec,arglist,body def_set_AG(name, apspec, wrap_fr(arglist, wrap_rwvdoblogme(arglist, body))) ]] --------[ DDEF ]-------- -- DDEF: another quick hack to define blogme words in pure blogme. -- The name means "Dollar(-centric) DEF". Calls to this word look like -- calls to DEF, but without the quotes to convert the "body" into a -- Lua expression; the body is expanded immediately using `doblogme', -- then the result is converted to a constant Lua string expression -- with format("%q", ...), and then the dollar-constructs - $varname -- and $(varname) - in that are transformed by `undollar' into code to -- concatenate the value of the variable "varname" at the string at thet -- point. No error-checking is performed at all! -- This is experimental and has not been adequately tested. -- -- An example (not checked): -- -- [DDEF FOOHREF 2 url,text foo[HREF $url $text]bar ] -- --> body = [[foo<a href="$url">$text</a>bar ]] -- --> qbody = [["foo<a href=\"$url\">$text</a>bar "]] -- --> eqbody = [["foo<a href=\""..url.."\">"..text.."</a>bar "]] -- -- def [[FOOHREF 2 url,text "foo<a href=\""..url.."\">"..text.."</a>bar "]] -- -- def_set_AG("FOOHREF", "2", "url,text", -- wrap_fr [["foo<a href=\""..url.."\">"..text.."</a>bar "]]) -- -- Note that the arglist parser specifier is "4", not "4Q" - this -- makes the "body" be expanded by the argument parser before becoming -- the argument for a Lua function. def [[ DDEF 4 name,apspec,arglist,body def_set_AG(name, apspec, wrap_fr(arglist, undollar(format("%q", body)))) ]] ---- Untested: -- ddef = function (defstr) -- local name, apspec, arglist, body = def_split(defstr) -- def_set_AG(name, apspec, wrap_fr(arglist, undollar(format "%s", body))) -- end --[=[ * (eepitch-lua51) dofile "brackets.lua" dofile "definers.lua" PP(_AA) --]=] -- (find-lua51file "src/lstrlib.c" "case 's' : res = isspace(c)") -- (find-node "(libc)Classification of Characters" "int isspace") -- Local Variables: -- coding: raw-text-unix -- ee-anchor-format: "«%s»" -- End: