Found a couple things

This commit is contained in:
Étienne Fildadut 2025-06-27 22:08:10 +02:00
parent daef111089
commit 5214fed9d3
3 changed files with 344 additions and 1 deletions

70
sexpr.lua Normal file
View 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("()")