Found a couple things
This commit is contained in:
parent
daef111089
commit
5214fed9d3
3 changed files with 344 additions and 1 deletions
70
sexpr.lua
Normal file
70
sexpr.lua
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
--- simple s expressions parser
|
||||
|
||||
local parse, parse_exp, parse_atom
|
||||
|
||||
-- expression: starts with ( and ends with ), contains a whietspace separated list of expressions and tokens
|
||||
-- s has no leading whitespace, starts with (
|
||||
-- returns exp, r (r has no leading whitespace)
|
||||
-- returns nil, err
|
||||
parse_exp = function(s)
|
||||
local r = s:match("^%(%s*(.*)$")
|
||||
if not r then return nil, "no expression found" end
|
||||
local exp = {}
|
||||
repeat
|
||||
local item, r_item = parse(r)
|
||||
if item then
|
||||
table.insert(exp, item)
|
||||
r = r_item
|
||||
end
|
||||
until not item
|
||||
if not r:match("^%)") then
|
||||
return nil, "expected closing )"
|
||||
end
|
||||
return exp, r:match("^%)%s*(.-)$")
|
||||
end
|
||||
|
||||
-- atom: litteral delimited by whitespace, ), or (; and with escaping using \
|
||||
-- s has no leading whitespace
|
||||
-- returns exp, r (r has no leading whitespace)
|
||||
-- returns nil, err
|
||||
parse_atom = function(s)
|
||||
local atom = {}
|
||||
local n, r = s:match("^([^%s%(%)\\]*)(.-)$")
|
||||
if #n > 0 then table.insert(atom, n) end
|
||||
while r:match("^\\") do
|
||||
table.insert(atom, r:match("^\\(.)"))
|
||||
n, r = r:match("^\\.([^%s%(%)\\]*)(.-)$")
|
||||
if #n > 0 then table.insert(atom, n) end
|
||||
end
|
||||
if #atom == 0 then return nil, "no atom found" end
|
||||
return table.concat(atom), r:match("^%s*(.-)$")
|
||||
end
|
||||
|
||||
-- s has no leading whitespace
|
||||
-- returns exp, r (r has no leading whitespace)
|
||||
-- returns nil, err
|
||||
parse = function(s)
|
||||
local i, r = parse_exp(s)
|
||||
if i then return i, r end
|
||||
i, r = parse_atom(s)
|
||||
if i then return i, r end
|
||||
return nil, "no expression found"
|
||||
end
|
||||
|
||||
local function test(s)
|
||||
local trimmed = s:match("^%s*(.-)$")
|
||||
local parsed, r = parse(s)
|
||||
if not parsed then
|
||||
print(r)
|
||||
elseif r:match(".") then
|
||||
print(("unexpected %q at end of expression"):format(r))
|
||||
else
|
||||
print(require("inspect")(parsed))
|
||||
end
|
||||
end
|
||||
|
||||
test("((str (Hel\\)lo world) sa mère) (lol))")
|
||||
|
||||
test("\\lol\\ wut")
|
||||
|
||||
test("()")
|
||||
Loading…
Add table
Add a link
Reference in a new issue