|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- definers.lua: blogme3's def, DEF and friends, rewritten.
-- This file:
-- http://angg.twu.net/blogme4/definers.lua.html
-- http://angg.twu.net/blogme4/definers.lua
-- (find-blogme4 "definers.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
-- Version: 2011feb17
-- License: GPL3
--
-- See: (find-angg "LUA/canvas2.lua" "Class")
-- (find-blogme3 "definers.lua")
-- (find-blogme3 "definers.lua" "def")
-- «.undollar» (to "undollar")
-- «.BlogmeWord» (to "BlogmeWord")
-- «.def» (to "def")
-- «.test-def» (to "test-def")
require "eoo" -- (find-blogme4 "eoo.lua")
-- «undollar» (to ".undollar")
-- 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 = code:gsub("%$([a-z]+)", "\"..%1..\"")
code = code:gsub("%$(%b())", "\"..%1..\"")
code = code:gsub("%$(%b[])", function (s)
return "]]..("..s:sub(2, -2)..")..[["
end)
return code
end
wrap_f = function (arglist, statements)
return "function ("..arglist..")\n"..statements.."\nend"
end
wrap_fr = function (arglist, expr)
return "function ("..arglist..")\nreturn "..expr.."\nend"
end
wrap_rf = function (arglist, statements)
return "return function ("..arglist..")\n"..statements.."\nend"
end
wrap_rfr = function (arglist, expr)
return "return function ("..arglist..")\nreturn "..expr.."\nend"
end
-- wrap_fu = function (argl, body) return wrap_f (argl, undollar(body)) end
-- wrap_fru = function (argl, body) return wrap_fr(argl, undollar(body)) end
-- «BlogmeWord» (to ".BlogmeWord")
-- The class of blogme words,
-- and a way to create a bword from a string.
-- See: (find-blogme4 "eoo.lua")
--
BlogmeWord = Class {
type = "BlogmeWord",
__index = {
fu = function (bw) return wrap_f (bw.arglist, undollar(bw.body)) end,
fru = function (bw) return wrap_fr(bw.arglist, undollar(bw.body)) end,
},
__call = function (bw, ...) return bw.fun(...) end,
}
BlogmeWordFrom = function (defspec)
local name, argp, arglist, body =
string.match(defspec, "^%s*(%S+)%s+(%S+)%s+(%S+)%s(.*)")
assert(name, "defspec is not of the form \"name argp arglist body\"")
local bw = BlogmeWord {name=name, argp=argp, arglist=arglist, body=body}
return bw
end
-- «def» (to ".def")
-- Old version: (find-blogme3 "definers.lua" "def")
-- Examples of usage: (find-blogme4 "anggdefs.lua")
-- Here we define Def_, Def, def_ and def, where:
-- Def_ and def_ store a BW in _B,
-- Def and def store a BW in _B and in _G.
-- Def_ and Def expect a series of statements,
-- def_ and def expect an expression.
-- and:
-- _G is the table of global symbols (usually lua functions),
-- _B is the table of blogme words (instances of BlogmeWord).
-- Here's the trick for remembering which function does what.
-- In "Def_" and "Def" everything is bigger: they start with an
-- uppercase letter (yeah!) and they expect a longer, more serious
-- piece of code, made of several statements, possibly even starting
-- with declarations of local variables, and usually ending with a
-- "return". In contrast, "def_" and "def" are for smaller things,
-- and they expect an expression (because internally they prepend a
-- "return " to their code).
-- An "_" always suggests "low-level", so "Def_" and "def_" do less
-- than "Def" and "def". "Def_" and "def_" install the newly-defined
-- word only in _B, while "Def" and "def" also copy it to _G.
_B = {}
Def_ = function (defspec, prefix)
local bw = BlogmeWordFrom(defspec)
local arglist = bw.arglist
local body = bw.body
local code = wrap_rf(arglist, (prefix or "")..undollar(body))
-- PP(bw.name, code)
bw.fun = assert(loadstring(code, bw.name))()
_B[bw.name] = bw
return bw
end
Def = function (defspec, prefix)
local bw = Def_(defspec, prefix)
_G[bw.name] = bw
return bw
end
def_ = function (defspec) return Def_(defspec, "return ") end
def = function (defspec) return Def (defspec, "return ") end
-- dump-to: tests
--[==[
-- «test-def» (to ".test-def")
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
-- userocks()
-- chdir "~/blogme4/"
require "def"
_B = {}
def [[ H2 1 str "<h2>$str</h2>\n" ]]
PP(_B)
--> {"H2"={"arglist"="str", "body"=" \"<h2>$str</h2>\\n\" ", "fun"=<function: 0x9763268>, "name"="H2", "nargs"="1"}}
PP(_B.H2)
--> {"arglist"="str", "body"=" \"<h2>$str</h2>\\n\" ", "fun"=<function: 0x9763268>, "name"="H2", "nargs"="1"}
= _B.H2:fru()
--> function (str)
-- return "<h2>"..str.."</h2>\n"
-- end
= _B.H2 "foo"
--> <h2>foo</h2>
= H2 "foo"
--> <h2>foo</h2>
= undollar [[ "foo $bar plic" ]]
--> "foo "..bar.." plic"
= undollar [[ "foo$(bar)plic" ]]
--> "foo"..(bar).."plic"
= undollar " [[foo$[1+2]bar]] "
--> [[foo]]..(1+2)..[[bar]]
--]==]
-- Local Variables:
-- coding: raw-text-unix
-- ee-anchor-format: "«%s»"
-- End: