lang-bootstrap/06/lpeglabel/examples/expRecAut.lua
Dawid Sobczak e6b88d5a0f Add stage 06: Lua bootstrap
The goal of stage 06 is to try parse zig synax in lua. I pulled in
lpeglable 1.2.0 and parser-gen off github to get started. All of this
needs to be cleaned up rather soon.

Lua boostraps using tcc and musl from the previous stage. Since musl
0.6.0 doesn't support dynamic linking this build of lua doesn't support
shared libraries. I couldn't easily patch musl with dlopen and friends
so instead I link statically and call deps with c api.
2023-07-06 12:32:47 +01:00

122 lines
2.6 KiB
Lua

local m = require"lpeglabel"
local re = require"relabel"
local num = m.R("09")^1 / tonumber
local op = m.S("+-")
local labels = {}
local nlabels = 0
local function newError(lab, msg, psync, pcap)
nlabels = nlabels + 1
psync = psync or m.P(-1)
pcap = pcap or m.P""
labels[lab] = { id = nlabels, msg = msg, psync = psync, pcap = pcap }
end
newError("ExpTermFirst", "expected an expression", op + ")", m.Cc(1000))
newError("ExpTermOp", "expected a term after the operator", op + ")", m.Cc(1000))
newError("MisClose", "missing a closing ')' after the expression", m.P")")
newError("Extra", "extra characters found after the expression")
local errors, subject
local function expect(patt, labname)
local i = labels[labname].id
return patt + m.T(i)
end
local function compute(tokens)
local result = tokens[1]
for i = 2, #tokens, 2 do
if tokens[i] == '+' then
result = result + tokens[i+1]
elseif tokens[i] == '-' then
result = result - tokens[i+1]
else
error('unknown operation: ' .. tokens[i])
end
end
return result
end
local g = m.P {
"Exp",
Exp = m.Ct(m.V"OperandFirst" * (m.C(op) * m.V"Operand")^0) / compute,
OperandFirst = expect(m.V"Term", "ExpTermFirst"),
Operand = expect(m.V"Term", "ExpTermOp"),
Term = num + m.V"Group",
Group = "(" * m.V"Exp" * expect(")", "MisClose"),
}
function recorderror(pos, lab)
local line, col = re.calcline(subject, pos)
table.insert(errors, { line = line, col = col, msg = labels[lab].msg })
end
function record (labname)
return (m.Cp() * m.Cc(labname)) / recorderror
end
function sync (p)
return (-p * m.P(1))^0
end
function defaultValue (p)
return p or m.Cc(1000)
end
local grec = g * expect(m.P(-1), "Extra")
for k, v in pairs(labels) do
grec = m.Rec(grec, record(k) * sync(v.psync) * v.pcap, v.id)
end
local function eval(input)
errors = {}
io.write("Input: ", input, "\n")
subject = input
local result, label, suffix = grec:match(input)
io.write("Syntactic errors found: " .. #errors, "\n")
if #errors > 0 then
local out = {}
for i, err in ipairs(errors) do
local pos = err.col
local msg = err.msg
table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")")
end
print(table.concat(out, "\n"))
end
io.write("Result = ")
return result
end
print(eval "90-70-(5)+3")
--> 18
print(eval "15+")
--> 2 + 0
print(eval "-2")
--> 0 - 2
print(eval "1+3+-9")
--> 1 + 3 + [0] - 9
print(eval "1+()3+")
--> 1 + ([0]) [+] 3 + [0]
print(eval "8-(2+)-5")
--> 8 - (2 + [0]) - 5
print(eval "()")
print(eval "")
print(eval "1+()+")
print(eval "1+(")
print(eval "3)")
print(eval "11+()3")
--> 1 + ([0]) [+] 3 + [0]