Runtime Syntax


This utility module automates the run-time simulation of what resembles syntax extensions. It's somewhat of a hack, intended mostly as a proof of concept, and not well tested. For a truer implementation of this type of thing, see MetaLua.

Example:

-- Define syntax
local S = require "runtimesyntax"
S["insert (x) .into (t)"] = function(x,t)
 table.insert(t, x)
end
S["increment (t) .by (n)"] = function(t,n)
 for i in ipairs(t) do t[i] = t[i] + n end
end
S["check (a) '>' (b) '<' (c)"] = function(a,b,c)
 local ok = a > b and a < c
 print(string.format("checking %f < %f < %f", b, a, c),
 "...", ok and "pass" or "fail")
end
-- using it
local t = {}
insert (5) .into (t)
insert (6) .into (t)
increment (t) .by (10)
assert(t[1] == 15 and t[2] == 16)
check (#t) '>' (1) '<' (3)
print 'done'
-- This cases "syntax error: missing (c) at @insert.lua:?:25"
check (#t) '>' (1) '<'

Implementation:

-- runtimesyntax.lua
-- runtime simulatation of syntax extensions in Lua.
--
-- WARNING: not well tested.
--
-- (c) 2009 David Manura
-- Licensed under the same terms as Lua (MIT license).
-- Detect incomplete syntax (optional)
local function wrap(o, syntax, pos)
 if syntax:match'^%s*$' then return o end
 -- http://lua-users.org/wiki/HiddenFeatures
 local ud = newproxy(true)
 local mt = getmetatable(ud)
 mt.__call = type(o) == 'function' and
 function(_, ...) return o(...) end or nil
 mt.__index = type(o) == 'table' and getmetatable(o).__index or nil
 mt.__gc = function()
 io.stderr:write("syntax error: missing ", syntax, " at ", pos, "\n")
 end
 return ud
end
local function clear(o)
 if type(o) == 'userdata' then
 getmetatable(o).__gc = nil
 end
end
-- Build function for rest of syntax.
-- syntax - syntax string
-- vars - arguments passed to function
-- (with n count field to support nils)
-- f - function to call after building, passing
-- unpacked vars
-- oprev - previous function or userdata this syntax
-- is appended to
-- pos - string indicating position in source
local function make(syntax, vars, f, oprev, pos)
 local var, moresyntax = syntax:match("^%s*%(%s*(%w+)%s*%)(.*)")
 if var then
 local o
 o = wrap(function(vara)
 clear(oprev)
 vars[vars.n+1] = vara
 vars.n = vars.n + 1
 return make(moresyntax, vars, f, o, pos)
 end, moresyntax, pos)
 return o
 end
 local prep, moresyntax = syntax:match("^%s*%.(%w+)%s*(.*)")
 if prep then
 local o
 local mt = {}
 function mt:__index(prepa)
 clear(oprev)
 if prep ~= prepa then
 error(string.format("syntax error: expecting (%s) got (%s)",
 prep, tostring(prepa)))
 end
 return make(moresyntax, vars, f, o, pos)
 end
 o = wrap(setmetatable({}, mt), moresyntax, pos)
 return o
 end
 local prep, moresyntax = syntax:match("^%s*'([^']+)'(.*)")
 if prep then
 local o
 o = wrap(function(prepa)
 clear(oprev)
 if prep ~= prepa then
 error(string.format("syntax error: expecting (%s) got (%s)",
 prep, tostring(prepa)))
 end
 return make(moresyntax, vars, f, o, pos)
 end, moresyntax, pos)
 return o
 end
 if syntax:match'^%s*$' then
 return f(unpack(vars, 1, vars.n)), true
 end
 error("unrecognized:" .. syntax)
end
local M = {}
local M_mt = {}
function M_mt:__newindex(syntax, f)
 local w, moresyntax = syntax:match("^%s*(%w+)(.*)")
 if w then
 _G[w] = function(...)
 local info = debug.getinfo(2)
 local pos = (info.source or '?') .. ':' ..
 (info.name or '?') .. ':' ..
 (info.currentline or '?')
 return make(moresyntax, {n=0}, f, nil, pos)(...)
 end
 end
end
setmetatable(M, M_mt)
return M

--DavidManura

See Also


RecentChanges · preferences
edit · history
Last edited May 1, 2009 8:35 pm GMT (diff)

AltStyle によって変換されたページ (->オリジナル) /