Warning: this is an htmlized version!
The original is across this link,
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://angg.twu.net/blogme3/definers.lua>
-- <http://angg.twu.net/blogme3/definers.lua.html>
-- License: GPL.
--
-- (find-a2ps (buffer-file-name))


-- «._AA»	(to "_AA")
-- «.undollar»	(to "undollar")
-- «.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


--------[ 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: