|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- This file:
-- http://anggtwu.net/LUA/Code2.lua.html
-- http://anggtwu.net/LUA/Code2.lua
-- (find-angg "LUA/Code2.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
-- Version: 2024jan08
-- Public domain.
--
-- Also here: (find-angg "LUA/lua50init.lua" "Code")
-- Supersedes: (find-angg "LUA/Code.lua")
--
-- (defun e () (interactive) (find-angg "LUA/Code2.lua"))
-- (defun o () (interactive) (find-angg "LUA/Code.lua"))
-- «.Code» (to "Code")
-- «.Code-tests» (to "Code-tests")
-- ____ _
-- / ___|___ __| | ___
-- | | / _ \ / _` |/ _ \
-- | |__| (_) | (_| | __/
-- \____\___/ \__,_|\___|
--
-- «Code» (to ".Code")
-- Also here: (find-angg "LUA/lua50init.lua" "Code")
-- Based on: (find-angg "LUA/Code.lua")
--
-- The class Code "converts strings to executable code" in nice ways.
-- Initially there are two basic ways to do the conversion:
--
-- Code.ve [[ a,b => 10*a + b ]] (3, 4)
-- Code.vc [[ a,b => print(a); return 10*a + b ]] (3, 4)
--
-- roughly,
--
-- Code.ve interprets its argument as "var => expr", and
-- Code.vc interprets its argument as "var => code".
--
-- It is relatively easy to add other ways to interpret the "code".
-- An object of the class Code has two fields: .src, with the "code"
-- in the original received form, and .code, with it converted to Lua
-- code that can be run with loadstring. TA-DA: an object of the class
-- Code does NOT contain a compiled version of its .code field! 8-O
Code = Class {
type = "Code",
from = function (src) return Code{src=src}:parse() end,
expr = function (src) return Code{src=src}:mkbody("_expr") end,
eval = function (src) return Code{src=src}:mkbody("_eval") end,
ve = function (src) return Code.from(src):mkbody("_ve") end,
vc = function (src) return Code.from(src):mkbody("_vc") end,
__tostring = function (c) return c:tostring() end,
__call = function (c,...) return c:f()(...) end,
__index = {
tostring = function (c)
local f = function (k) return format("%8s: %s", k, c[k]) end
return mapconcat(f, sortedkeys(c), "\n")
end,
--
srcpat = "^%s*([%w_,]+)%s*[%-=]>%s*(.*)$",
parse = function (c)
local srcvars,srcbody = c.src:match(c.srcpat)
if not srcvars then error("Code.parse can't parse: "..c.src) end
c.srcvars,c.srcbody = srcvars,srcbody
return c
end,
--
_ve = "local <srcvars> = ...; return <srcbody>",
_vc = "local <srcvars> = ...; <srcbody>",
_expr = "return <src>",
_eval = "<src>",
mkbody = function (c,k) return c:mkbody0(c[k]) end,
mkbody0 = function (c,fmt)
local f = function (s) return c[s] end
c.body = fmt:gsub("<(.-)>", f)
return c
end,
f = function (c) return assert(loadstring(c.body)) end,
},
}
-- «Code-tests» (to ".Code-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Code2.lua"
= Code.expr [[ 2+3 ]]
= Code.eval [[ print(2+3) ]]
= Code.ve [[ a,b => 10*a + b ]]
= Code.vc [[ a,b => print(10*a + b) ]]
c = Code.from [[ a,b => 10*a + b ]]
c = Code.ve [[ a,b => 10*a + b ]]
= c
= c.src
= c(3,4)
= Code.from [[ a,b => 10*a + b ]] :parse()
= Code.ve [[ a,b => 10*a + b ]]
= Code.ve [[ a,b => 10*a + b ]] :f()
= Code.ve [[ a,b => 10*a + b ]] :f() (3, 4)
= Code.ve [[ a,b => 10*a + b ]] (3, 4)
= Code.ve [[ a,b => 10*a + b ]] .src
= Code.ve [[ a,b => 10*a + b ]] .body
= Code.vc [[ a,b => print(a); return 10*a + b ]]
= Code.vc [[ a,b => print(a); return 10*a + b ]] :f()
= Code.vc [[ a,b => print(a); return 10*a + b ]] :f() (3, 4)
= Code.vc [[ a,b => print(a); return 10*a + b ]] (3, 4)
= Code.vc [[ a,b => print(a); return 10*a + b ]] .src
= Code.vc [[ a,b => print(a); return 10*a + b ]] .body
L = Code.ve
= L 'a,b=>100*a+b' (3,4)
= L 'a,b->100*a+b' (3,4)
= L 'a,b!>100*a+b' (3,4) -- err
--]==]
-- Local Variables:
-- coding: utf-8-unix
-- End: