Fixed some diagnostics warnings
Moved examples to tofix because fixing them is besides the point right now.
This commit is contained in:
parent
52164c82e3
commit
858fe11666
166 changed files with 68 additions and 264 deletions
128
06/deps/lpeglabel/examples/expRec.lua
Normal file
128
06/deps/lpeglabel/examples/expRec.lua
Normal file
|
@ -0,0 +1,128 @@
|
|||
local m = require "lpeglabel"
|
||||
local re = require "relabel"
|
||||
|
||||
local labels = {
|
||||
{"ExpTermFirst", "expected an expression"},
|
||||
{"ExpTermOp", "expected a term after the operator"},
|
||||
{"MisClose", "missing a closing ')' after the expression"},
|
||||
}
|
||||
|
||||
local function labelindex(labname)
|
||||
for i, elem in ipairs(labels) do
|
||||
if elem[1] == labname then
|
||||
return i
|
||||
end
|
||||
end
|
||||
error("could not find label: " .. labname)
|
||||
end
|
||||
|
||||
local errors, subject
|
||||
|
||||
local function expect(patt, labname)
|
||||
local i = labelindex(labname)
|
||||
return patt + m.T(i)
|
||||
end
|
||||
|
||||
|
||||
local num = m.R("09")^1 / tonumber
|
||||
local op = m.S("+-")
|
||||
|
||||
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][2] })
|
||||
end
|
||||
|
||||
function record (labname)
|
||||
return (m.Cp() * m.Cc(labelindex(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 = m.P {
|
||||
"S",
|
||||
S = m.Rec(m.V"A", m.V"ErrExpTermFirst", labelindex("ExpTermFirst")), -- default value is 0
|
||||
A = m.Rec(m.V"Sg", m.V"ErrExpTermOp", labelindex("ExpTermOp")),
|
||||
Sg = m.Rec(g, m.V"ErrMisClose", labelindex("MisClose")),
|
||||
ErrExpTermFirst = record("ExpTermFirst") * sync(op + ")") * defaultValue(),
|
||||
ErrExpTermOp = record("ExpTermOp") * sync(op + ")") * defaultValue(),
|
||||
ErrMisClose = record("MisClose") * sync(m.P")") * defaultValue(m.P""),
|
||||
}
|
||||
|
||||
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")
|
||||
--> 20
|
||||
|
||||
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")
|
||||
|
122
06/deps/lpeglabel/examples/expRecAut.lua
Normal file
122
06/deps/lpeglabel/examples/expRecAut.lua
Normal file
|
@ -0,0 +1,122 @@
|
|||
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]
|
14
06/deps/lpeglabel/examples/farthest.lua
Normal file
14
06/deps/lpeglabel/examples/farthest.lua
Normal file
|
@ -0,0 +1,14 @@
|
|||
local m = require'lpeglabel'
|
||||
|
||||
function matchPrint(p, s)
|
||||
local r, lab, sfail = p:match(s)
|
||||
print("r: ", r, "lab: ", lab, "sfail: ", sfail)
|
||||
end
|
||||
|
||||
local p = m.P"a"^0 * m.P"b" + m.P"c"
|
||||
matchPrint(p, "abc") --> r: 3 lab: nil sfail: nil
|
||||
matchPrint(p, "c") --> r: 2 lab: nil sfail: nil
|
||||
matchPrint(p, "aac") --> r: nil lab: 0 sfail: c
|
||||
matchPrint(p, "xxc") --> r: nil lab: 0 sfail: xxc
|
||||
|
||||
|
33
06/deps/lpeglabel/examples/listId1.lua
Normal file
33
06/deps/lpeglabel/examples/listId1.lua
Normal file
|
@ -0,0 +1,33 @@
|
|||
local m = require'lpeglabel'
|
||||
local re = require'relabel'
|
||||
|
||||
local id = m.R'az'^1
|
||||
|
||||
local g = m.P{
|
||||
"S",
|
||||
S = m.V"Id" * m.V"List",
|
||||
List = -m.P(1) + m.V"Comma" * m.V"Id" * m.V"List",
|
||||
Id = m.V"Sp" * id + m.T(1),
|
||||
Comma = m.V"Sp" * "," + m.T(2),
|
||||
Sp = m.S" \n\t"^0,
|
||||
}
|
||||
|
||||
function mymatch (g, s)
|
||||
local r, e, sfail = g:match(s)
|
||||
if not r then
|
||||
local line, col = re.calcline(s, #s - #sfail)
|
||||
local msg = "Error at line " .. line .. " (col " .. col .. ")"
|
||||
if e == 1 then
|
||||
return r, msg .. ": expecting an identifier before '" .. sfail .. "'"
|
||||
elseif e == 2 then
|
||||
return r, msg .. ": expecting ',' before '" .. sfail .. "'"
|
||||
else
|
||||
return r, msg
|
||||
end
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
print(mymatch(g, "one,two"))
|
||||
print(mymatch(g, "one two"))
|
||||
print(mymatch(g, "one,\n two,\nthree,"))
|
39
06/deps/lpeglabel/examples/listId2.lua
Normal file
39
06/deps/lpeglabel/examples/listId2.lua
Normal file
|
@ -0,0 +1,39 @@
|
|||
local m = require'lpeglabel'
|
||||
local re = require'relabel'
|
||||
|
||||
local terror = {}
|
||||
|
||||
local function newError(s)
|
||||
table.insert(terror, s)
|
||||
return #terror
|
||||
end
|
||||
|
||||
local errUndef = newError("undefined")
|
||||
local errId = newError("expecting an identifier")
|
||||
local errComma = newError("expecting ','")
|
||||
|
||||
local id = m.R'az'^1
|
||||
|
||||
local g = m.P{
|
||||
"S",
|
||||
S = m.V"Id" * m.V"List",
|
||||
List = -m.P(1) + m.V"Comma" * m.V"Id" * m.V"List",
|
||||
Id = m.V"Sp" * id + m.T(errId),
|
||||
Comma = m.V"Sp" * "," + m.T(errComma),
|
||||
Sp = m.S" \n\t"^0,
|
||||
}
|
||||
|
||||
|
||||
function mymatch (g, s)
|
||||
local r, e, sfail = g:match(s)
|
||||
if not r then
|
||||
local line, col = re.calcline(s, #s - #sfail)
|
||||
local msg = "Error at line " .. line .. " (col " .. col .. "): "
|
||||
return r, msg .. terror[e] .. " before '" .. sfail .. "'"
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
print(mymatch(g, "one,two"))
|
||||
print(mymatch(g, "one two"))
|
||||
print(mymatch(g, "one,\n two,\nthree,"))
|
67
06/deps/lpeglabel/examples/listId2Rec2.lua
Normal file
67
06/deps/lpeglabel/examples/listId2Rec2.lua
Normal file
|
@ -0,0 +1,67 @@
|
|||
local m = require'lpeglabel'
|
||||
local re = require'relabel'
|
||||
|
||||
local terror = {}
|
||||
|
||||
local function newError(s)
|
||||
table.insert(terror, s)
|
||||
return #terror
|
||||
end
|
||||
|
||||
local errUndef = newError("undefined")
|
||||
local errId = newError("expecting an identifier")
|
||||
local errComma = newError("expecting ','")
|
||||
|
||||
local id = m.R'az'^1
|
||||
|
||||
local g = m.P{
|
||||
"S",
|
||||
S = m.V"Id" * m.V"List",
|
||||
List = -m.P(1) + m.V"Comma" * m.V"Id" * m.V"List",
|
||||
Id = m.V"Sp" * id + m.T(errId),
|
||||
Comma = m.V"Sp" * "," + m.T(errComma),
|
||||
Sp = m.S" \n\t"^0,
|
||||
}
|
||||
|
||||
local subject, errors
|
||||
|
||||
function recorderror(pos, lab)
|
||||
local line, col = re.calcline(subject, pos)
|
||||
table.insert(errors, { line = line, col = col, msg = terror[lab] })
|
||||
end
|
||||
|
||||
function record (lab)
|
||||
return (m.Cp() * m.Cc(lab)) / recorderror
|
||||
end
|
||||
|
||||
function sync (p)
|
||||
return (-p * m.P(1))^0
|
||||
end
|
||||
|
||||
local grec = m.P{
|
||||
"S",
|
||||
S = m.Rec(m.Rec(g, m.V"ErrComma", errComma), m.V"ErrId", errId),
|
||||
ErrComma = record(errComma) * sync(id),
|
||||
ErrId = record(errId) * sync(m.P",")
|
||||
}
|
||||
|
||||
|
||||
function mymatch (g, s)
|
||||
errors = {}
|
||||
subject = s
|
||||
local r, e, sfail = g:match(s)
|
||||
if #errors > 0 then
|
||||
local out = {}
|
||||
for i, err in ipairs(errors) do
|
||||
local msg = "Error at line " .. err.line .. " (col " .. err.col .. "): " .. err.msg
|
||||
table.insert(out, msg)
|
||||
end
|
||||
return nil, table.concat(out, "\n") .. "\n"
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
print(mymatch(grec, "one,two"))
|
||||
print(mymatch(grec, "one two three"))
|
||||
print(mymatch(grec, "1,\n two, \n3,"))
|
||||
print(mymatch(grec, "one\n two123, \nthree,"))
|
79
06/deps/lpeglabel/examples/listId2Rec2Cap.lua
Normal file
79
06/deps/lpeglabel/examples/listId2Rec2Cap.lua
Normal file
|
@ -0,0 +1,79 @@
|
|||
local m = require'lpeglabel'
|
||||
local re = require'relabel'
|
||||
|
||||
local terror = {}
|
||||
|
||||
local function newError(s)
|
||||
table.insert(terror, s)
|
||||
return #terror
|
||||
end
|
||||
|
||||
local errUndef = newError("undefined")
|
||||
local errId = newError("expecting an identifier")
|
||||
local errComma = newError("expecting ','")
|
||||
|
||||
local id = m.R'az'^1
|
||||
|
||||
local g = m.P{
|
||||
"S",
|
||||
S = m.V"Id" * m.V"List",
|
||||
List = -m.P(1) + m.V"Comma" * m.V"Id" * m.V"List",
|
||||
Id = m.V"Sp" * m.C(id) + m.T(errId),
|
||||
Comma = m.V"Sp" * "," + m.T(errComma),
|
||||
Sp = m.S" \n\t"^0,
|
||||
}
|
||||
|
||||
local subject, errors
|
||||
|
||||
function recorderror(pos, lab)
|
||||
local line, col = re.calcline(subject, pos)
|
||||
table.insert(errors, { line = line, col = col, msg = terror[lab] })
|
||||
end
|
||||
|
||||
function record (lab)
|
||||
return (m.Cp() * m.Cc(lab)) / recorderror
|
||||
end
|
||||
|
||||
function sync (p)
|
||||
return (-p * m.P(1))^0
|
||||
end
|
||||
|
||||
function defaultValue ()
|
||||
return m.Cc"NONE"
|
||||
end
|
||||
|
||||
local grec = m.P{
|
||||
"S",
|
||||
S = m.Rec(m.Rec(g, m.V"ErrComma", errComma), m.V"ErrId", errId),
|
||||
ErrComma = record(errComma) * sync(id),
|
||||
ErrId = record(errId) * sync(m.P",") * defaultValue(),
|
||||
}
|
||||
|
||||
|
||||
function mymatch (g, s)
|
||||
errors = {}
|
||||
subject = s
|
||||
io.write("Input: ", s, "\n")
|
||||
local r = { g:match(s) }
|
||||
io.write("Captures (separated by ';'): ")
|
||||
for k, v in pairs(r) do
|
||||
io.write(v .. "; ")
|
||||
end
|
||||
io.write("\nSyntactic errors found: " .. #errors)
|
||||
if #errors > 0 then
|
||||
io.write("\n")
|
||||
local out = {}
|
||||
for i, err in ipairs(errors) do
|
||||
local msg = "Error at line " .. err.line .. " (col " .. err.col .. "): " .. err.msg
|
||||
table.insert(out, msg)
|
||||
end
|
||||
io.write(table.concat(out, "\n"))
|
||||
end
|
||||
print("\n")
|
||||
return r
|
||||
end
|
||||
|
||||
mymatch(grec, "one,two")
|
||||
mymatch(grec, "one two three")
|
||||
mymatch(grec, "1,\n two, \n3,")
|
||||
mymatch(grec, "one\n two123, \nthree,")
|
30
06/deps/lpeglabel/examples/listIdRe1.lua
Normal file
30
06/deps/lpeglabel/examples/listIdRe1.lua
Normal file
|
@ -0,0 +1,30 @@
|
|||
local re = require 'relabel'
|
||||
|
||||
local g = re.compile[[
|
||||
S <- Id List
|
||||
List <- !. / Comma Id List
|
||||
Id <- Sp [a-z]+ / %{2}
|
||||
Comma <- Sp ',' / %{3}
|
||||
Sp <- %s*
|
||||
]]
|
||||
|
||||
function mymatch (g, s)
|
||||
local r, e, sfail = g:match(s)
|
||||
if not r then
|
||||
local line, col = re.calcline(s, #s - #sfail)
|
||||
local msg = "Error at line " .. line .. " (col " .. col .. ")"
|
||||
if e == 1 then
|
||||
return r, msg .. ": expecting an identifier before '" .. sfail .. "'"
|
||||
elseif e == 2 then
|
||||
return r, msg .. ": expecting ',' before '" .. sfail .. "'"
|
||||
else
|
||||
return r, msg
|
||||
end
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
print(mymatch(g, "one,two"))
|
||||
print(mymatch(g, "one two"))
|
||||
print(mymatch(g, "one,\n two,\nthree,"))
|
||||
|
71
06/deps/lpeglabel/examples/listIdRe2.lua
Normal file
71
06/deps/lpeglabel/examples/listIdRe2.lua
Normal file
|
@ -0,0 +1,71 @@
|
|||
local re = require 'relabel'
|
||||
|
||||
local errinfo = {
|
||||
{"errUndef", "undefined"},
|
||||
{"errId", "expecting an identifier"},
|
||||
{"errComma", "expecting ','"},
|
||||
}
|
||||
|
||||
local errmsgs = {}
|
||||
local labels = {}
|
||||
|
||||
for i, err in ipairs(errinfo) do
|
||||
errmsgs[i] = err[2]
|
||||
labels[err[1]] = i
|
||||
end
|
||||
|
||||
re.setlabels(labels)
|
||||
|
||||
local g = re.compile[[
|
||||
S <- Id List
|
||||
List <- !. / Comma Id List
|
||||
Id <- Sp {[a-z]+} / %{errId}
|
||||
Comma <- Sp ',' / %{errComma}
|
||||
Sp <- %s*
|
||||
]]
|
||||
|
||||
local errors
|
||||
|
||||
function recorderror (subject, pos, label)
|
||||
local line, col = re.calcline(subject, pos)
|
||||
table.insert(errors, { line = line, col = col, msg = errmsgs[labels[label]] })
|
||||
return true
|
||||
end
|
||||
|
||||
function sync (p)
|
||||
return '( !(' .. p .. ') .)*'
|
||||
end
|
||||
|
||||
local grec = re.compile(
|
||||
"S <- %g //{errComma} ErrComma //{errId} ErrId" .. "\n" ..
|
||||
"ErrComma <- ('' -> 'errComma' => recorderror) " .. sync('[a-z]+') .. "\n" ..
|
||||
"ErrId <- ('' -> 'errId' => recorderror) " .. sync('","') .. "-> default"
|
||||
, {g = g, recorderror = recorderror, default = "NONE"})
|
||||
|
||||
function mymatch (g, s)
|
||||
errors = {}
|
||||
subject = s
|
||||
io.write("Input: ", s, "\n")
|
||||
local r = { g:match(s) }
|
||||
io.write("Captures (separated by ';'): ")
|
||||
for k, v in pairs(r) do
|
||||
io.write(v .. "; ")
|
||||
end
|
||||
io.write("\nSyntactic errors found: " .. #errors)
|
||||
if #errors > 0 then
|
||||
io.write("\n")
|
||||
local out = {}
|
||||
for i, err in ipairs(errors) do
|
||||
local msg = "Error at line " .. err.line .. " (col " .. err.col .. "): " .. err.msg
|
||||
table.insert(out, msg)
|
||||
end
|
||||
io.write(table.concat(out, "\n"))
|
||||
end
|
||||
print("\n")
|
||||
return r
|
||||
end
|
||||
|
||||
mymatch(grec, "one,two")
|
||||
mymatch(grec, "one two three")
|
||||
mymatch(grec, "1,\n two, \n3,")
|
||||
mymatch(grec, "one\n two123, \nthree,")
|
151
06/deps/lpeglabel/examples/tiny.lua
Normal file
151
06/deps/lpeglabel/examples/tiny.lua
Normal file
|
@ -0,0 +1,151 @@
|
|||
local re = require 'relabel'
|
||||
|
||||
local terror = {}
|
||||
|
||||
local function newError(l, msg)
|
||||
table.insert(terror, { l = l, msg = msg} )
|
||||
end
|
||||
|
||||
newError("errSemi", "Error: missing ';'")
|
||||
newError("errExpIf", "Error: expected expression after 'if'")
|
||||
newError("errThen", "Error: expected 'then' keyword")
|
||||
newError("errCmdSeq1", "Error: expected at least a command after 'then'")
|
||||
newError("errCmdSeq2", "Error: expected at least a command after 'else'")
|
||||
newError("errEnd", "Error: expected 'end' keyword")
|
||||
newError("errCmdSeqRep", "Error: expected at least a command after 'repeat'")
|
||||
newError("errUntil", "Error: expected 'until' keyword")
|
||||
newError("errExpRep", "Error: expected expression after 'until'")
|
||||
newError("errAssignOp", "Error: expected ':=' in assigment")
|
||||
newError("errExpAssign", "Error: expected expression after ':='")
|
||||
newError("errReadName", "Error: expected an identifier after 'read'")
|
||||
newError("errWriteExp", "Error: expected expression after 'write'")
|
||||
newError("errSimpExp", "Error: expected '(', ID, or number after '<' or '='")
|
||||
newError("errTerm", "Error: expected '(', ID, or number after '+' or '-'")
|
||||
newError("errFactor", "Error: expected '(', ID, or number after '*' or '/'")
|
||||
newError("errExpFac", "Error: expected expression after '('")
|
||||
newError("errClosePar", "Error: expected ')' after expression")
|
||||
|
||||
|
||||
local labelCode = {}
|
||||
for k, v in ipairs(terror) do
|
||||
labelCode[v.l] = k
|
||||
end
|
||||
|
||||
re.setlabels(labelCode)
|
||||
|
||||
local g = re.compile[[
|
||||
Tiny <- CmdSeq
|
||||
CmdSeq <- (Cmd (SEMICOLON / ErrSemi)) (Cmd (SEMICOLON / ErrSemi))*
|
||||
Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd
|
||||
IfCmd <- IF (Exp / ErrExpIf) (THEN / ErrThen) (CmdSeq / ErrCmdSeq1) (ELSE (CmdSeq / ErrCmdSeq2) / '') (END / ErrEnd)
|
||||
RepeatCmd <- REPEAT (CmdSeq / ErrCmdSeqRep) (UNTIL / ErrUntil) (Exp / ErrExpRep)
|
||||
AssignCmd <- NAME (ASSIGNMENT / ErrAssignOp) (Exp / ErrExpAssign)
|
||||
ReadCmd <- READ (NAME / ErrReadName)
|
||||
WriteCmd <- WRITE (Exp / ErrWriteExp)
|
||||
Exp <- SimpleExp ((LESS / EQUAL) (SimpleExp / ErrSimpExp) / '')
|
||||
SimpleExp <- Term ((ADD / SUB) (Term / ErrTerm))*
|
||||
Term <- Factor ((MUL / DIV) (Factor / ErrFactor))*
|
||||
Factor <- OPENPAR (Exp / ErrExpFac) (CLOSEPAR / ErrClosePar) / NUMBER / NAME
|
||||
ErrSemi <- %{errSemi}
|
||||
ErrExpIf <- %{errExpIf}
|
||||
ErrThen <- %{errThen}
|
||||
ErrCmdSeq1 <- %{errCmdSeq1}
|
||||
ErrCmdSeq2 <- %{errCmdSeq2}
|
||||
ErrEnd <- %{errEnd}
|
||||
ErrCmdSeqRep <- %{errCmdSeqRep}
|
||||
ErrUntil <- %{errUntil}
|
||||
ErrExpRep <- %{errExpRep}
|
||||
ErrAssignOp <- %{errAssignOp}
|
||||
ErrExpAssign <- %{errExpAssign}
|
||||
ErrReadName <- %{errReadName}
|
||||
ErrWriteExp <- %{errWriteExp}
|
||||
ErrSimpExp <- %{errSimpExp}
|
||||
ErrTerm <- %{errTerm}
|
||||
ErrFactor <- %{errFactor}
|
||||
ErrExpFac <- %{errExpFac}
|
||||
ErrClosePar <- %{errClosePar}
|
||||
ADD <- Sp '+'
|
||||
ASSIGNMENT <- Sp ':='
|
||||
CLOSEPAR <- Sp ')'
|
||||
DIV <- Sp '/'
|
||||
IF <- Sp 'if'
|
||||
ELSE <- Sp 'else'
|
||||
END <- Sp 'end'
|
||||
EQUAL <- Sp '='
|
||||
LESS <- Sp '<'
|
||||
MUL <- Sp '*'
|
||||
NAME <- Sp !RESERVED [a-z]+
|
||||
NUMBER <- Sp [0-9]+
|
||||
OPENPAR <- Sp '('
|
||||
READ <- Sp 'read'
|
||||
REPEAT <- Sp 'repeat'
|
||||
SEMICOLON <- Sp ';'
|
||||
SUB <- Sp '-'
|
||||
THEN <- Sp 'then'
|
||||
UNTIL <- Sp 'until'
|
||||
WRITE <- Sp 'write'
|
||||
RESERVED <- (IF / ELSE / END / READ / REPEAT / THEN / UNTIL / WRITE) ![a-z]+
|
||||
Sp <- %s*
|
||||
]]
|
||||
|
||||
|
||||
local function mymatch(g, s)
|
||||
local r, e, sfail = g:match(s)
|
||||
if not r then
|
||||
local line, col = re.calcline(s, #s - #sfail)
|
||||
local msg = "Error at line " .. line .. " (col " .. col .. "): "
|
||||
return r, msg .. terror[e].msg
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
local s = [[
|
||||
n := 5;
|
||||
f := 1;
|
||||
repeat
|
||||
f := f + n;
|
||||
n := n - 1
|
||||
until (n < 1);
|
||||
write f;]]
|
||||
print(mymatch(g, s))
|
||||
|
||||
s = [[
|
||||
n := 5;
|
||||
f := 1;
|
||||
repeat
|
||||
f := f + n;
|
||||
n := n - 1;
|
||||
until (n < 1);
|
||||
read ;]]
|
||||
print(mymatch(g, s))
|
||||
|
||||
s = [[
|
||||
if a < 1 then
|
||||
b := 2;
|
||||
else
|
||||
b := 3;]]
|
||||
print(mymatch(g, s))
|
||||
|
||||
s = [[
|
||||
n := 5;
|
||||
f := 1;
|
||||
repeat
|
||||
f := f + n;
|
||||
n := n - 1;
|
||||
untill (n < 1);
|
||||
]]
|
||||
print(mymatch(g, s))
|
||||
|
||||
s = [[
|
||||
n := 5;
|
||||
f := 1;
|
||||
repeat
|
||||
f := f + n;
|
||||
n := n - 1;
|
||||
3 (n < 1);
|
||||
]]
|
||||
print(mymatch(g, s))
|
||||
|
||||
print(mymatch(g, "a : 2"))
|
||||
print(mymatch(g, "a := (2"))
|
||||
|
2572
06/deps/lpeglabel/examples/typedlua/test.lua
Executable file
2572
06/deps/lpeglabel/examples/typedlua/test.lua
Executable file
File diff suppressed because it is too large
Load diff
66
06/deps/lpeglabel/examples/typedlua/tlerror.lua
Normal file
66
06/deps/lpeglabel/examples/typedlua/tlerror.lua
Normal file
|
@ -0,0 +1,66 @@
|
|||
|
||||
local errors = {}
|
||||
local function new_error (label, msg)
|
||||
table.insert(errors, { label = label, msg = msg })
|
||||
end
|
||||
|
||||
new_error("Number", "malformed <number>")
|
||||
new_error("String", "malformed <string>")
|
||||
new_error("LongString", "unfinished long string")
|
||||
new_error("LongComment", "unfinished long comment")
|
||||
new_error("MissingOP", "missing '('")
|
||||
new_error("MissingCP", "missing ')'")
|
||||
new_error("MissingCC", "missing '}'")
|
||||
new_error("MissingCB", "missing ']'")
|
||||
new_error("UnionType", "expecting <type> after '|'")
|
||||
new_error("FunctionType", "expecting <type> after '->'")
|
||||
new_error("MethodType", "expecting <type> after '=>'")
|
||||
new_error("TupleType", "expecting <type> after ','")
|
||||
new_error("Type", "expecting <type> after ':'")
|
||||
new_error("TypeDecEnd", "missing 'end' in type declaration")
|
||||
new_error("TypeAliasName", "expecting <name> after 'typealias'")
|
||||
new_error("MissingEqTypeAlias", "missing '=' in 'typealias'")
|
||||
new_error("DotIndex", "expecting <name> after '.'")
|
||||
new_error("MethodName", "expecting <name> after ':'")
|
||||
new_error("Then", "missing 'then'")
|
||||
new_error("IfEnd", "missing 'end' to close if statement")
|
||||
new_error("WhileDo", "missing 'do' in while statement")
|
||||
new_error("WhileEnd", "missing 'end' to close while statement")
|
||||
new_error("BlockEnd", "missing 'end' to close block")
|
||||
new_error("ForDo", "missing 'do' in for statement")
|
||||
new_error("ForEnd", "missing 'end' to close for statement")
|
||||
new_error("Until", "missing 'until' in repeat statement")
|
||||
new_error("FuncEnd", "missing 'end' to close function declaration")
|
||||
new_error("ParList", "expecting '...'")
|
||||
new_error("MethodCall", "expecting '(' for method call")
|
||||
new_error("Label1", "expecting <name> after '::'")
|
||||
new_error("Label2", "expecting '::' to close label declaration")
|
||||
new_error("LocalAssign1", "expecting expression list after '='")
|
||||
new_error("LocalAssign2", "invalid local declaration")
|
||||
new_error("ForGen", "expecting 'in'")
|
||||
new_error("LocalFunc", "expecting <name> in local function declaration")
|
||||
new_error("RetStat", "invalid statement after 'return'")
|
||||
new_error("ElseIf", "expecting <exp> after 'elseif'")
|
||||
new_error("SubExpr_1", "malformed 'or' expression")
|
||||
new_error("SubExpr_2", "malformed 'and' expression")
|
||||
new_error("SubExpr_3", "malformed relational expression")
|
||||
new_error("SubExpr_4", "malformed '|' expression")
|
||||
new_error("SubExpr_5", "malformed '~' expression")
|
||||
new_error("SubExpr_6", "malformed '&' expression")
|
||||
new_error("SubExpr_7", "malformed shift expression")
|
||||
new_error("SubExpr_8", "malformed '..' expression")
|
||||
new_error("SubExpr_9", "malformed addition expression")
|
||||
new_error("SubExpr_10", "malformed multiplication expression")
|
||||
new_error("SubExpr_11", "malformed unary expression")
|
||||
new_error("SubExpr_12", "malformed '^' expression")
|
||||
new_error("Stat", "invalid statement")
|
||||
|
||||
local labels = {}
|
||||
for k, v in ipairs(errors) do
|
||||
labels[v.label] = k
|
||||
end
|
||||
|
||||
return {
|
||||
errors = errors,
|
||||
labels = labels,
|
||||
}
|
105
06/deps/lpeglabel/examples/typedlua/tllexer.lua
Normal file
105
06/deps/lpeglabel/examples/typedlua/tllexer.lua
Normal file
|
@ -0,0 +1,105 @@
|
|||
local tllexer = {}
|
||||
|
||||
local lpeg = require "lpeglabel"
|
||||
lpeg.locale(lpeg)
|
||||
|
||||
local tlerror = require "tlerror"
|
||||
|
||||
function tllexer.try (pat, label)
|
||||
return pat + lpeg.T(tlerror.labels[label])
|
||||
end
|
||||
|
||||
local function setffp (s, i, t, n)
|
||||
if not t.ffp or i > t.ffp then
|
||||
t.ffp = i
|
||||
t.list = {}
|
||||
t.list[n] = true
|
||||
t.expected = "'" .. n .. "'"
|
||||
elseif i == t.ffp then
|
||||
if not t.list[n] then
|
||||
t.list[n] = true
|
||||
t.expected = "'" .. n .. "', " .. t.expected
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function updateffp (name)
|
||||
return lpeg.Cmt(lpeg.Carg(1) * lpeg.Cc(name), setffp)
|
||||
end
|
||||
|
||||
tllexer.Shebang = lpeg.P("#") * (lpeg.P(1) - lpeg.P("\n"))^0 * lpeg.P("\n")
|
||||
|
||||
local Space = lpeg.space^1
|
||||
|
||||
local Equals = lpeg.P("=")^0
|
||||
local Open = "[" * lpeg.Cg(Equals, "init") * "[" * lpeg.P("\n")^-1
|
||||
local Close = "]" * lpeg.C(Equals) * "]"
|
||||
local CloseEQ = lpeg.Cmt(Close * lpeg.Cb("init"),
|
||||
function (s, i, a, b) return a == b end)
|
||||
|
||||
local LongString = Open * (lpeg.P(1) - CloseEQ)^0 * tllexer.try(Close, "LongString") /
|
||||
function (s, o) return s end
|
||||
|
||||
local LongStringCm1 = Open * (lpeg.P(1) - CloseEQ)^0 * Close /
|
||||
function (s, o) return s end
|
||||
|
||||
local Comment = lpeg.Rec(lpeg.P"--" * #Open * (LongStringCm1 / function() return end + lpeg.T(tlerror.labels["LongString"])),
|
||||
lpeg.T(tlerror.labels["LongComment"]), tlerror.labels["LongString"]) +
|
||||
lpeg.P("--") * (lpeg.P(1) - lpeg.P("\n"))^0
|
||||
|
||||
tllexer.Skip = (Space + Comment)^0
|
||||
|
||||
local idStart = lpeg.alpha + lpeg.P("_")
|
||||
local idRest = lpeg.alnum + lpeg.P("_")
|
||||
|
||||
local Keywords = lpeg.P("and") + "break" + "do" + "elseif" + "else" + "end" +
|
||||
"false" + "for" + "function" + "goto" + "if" + "in" +
|
||||
"local" + "nil" + "not" + "or" + "repeat" + "return" +
|
||||
"then" + "true" + "until" + "while"
|
||||
|
||||
tllexer.Reserved = Keywords * -idRest
|
||||
|
||||
local Identifier = idStart * idRest^0
|
||||
|
||||
tllexer.Name = -tllexer.Reserved * Identifier * -idRest
|
||||
|
||||
function tllexer.token (pat, name)
|
||||
return pat * tllexer.Skip + updateffp(name) * lpeg.P(false)
|
||||
end
|
||||
|
||||
function tllexer.symb (str)
|
||||
return tllexer.token(lpeg.P(str), str)
|
||||
end
|
||||
|
||||
function tllexer.kw (str)
|
||||
return tllexer.token(lpeg.P(str) * -idRest, str)
|
||||
end
|
||||
|
||||
local Hex = (lpeg.P("0x") + lpeg.P("0X")) * tllexer.try(lpeg.xdigit^1, "Number")
|
||||
local Expo = lpeg.S("eE") * lpeg.S("+-")^-1 * tllexer.try(lpeg.digit^1, "Number")
|
||||
local Float = (((lpeg.digit^1 * lpeg.P(".") * lpeg.digit^0 * tllexer.try(-lpeg.P("."), "Number")) +
|
||||
(lpeg.P(".") * lpeg.digit^1)) * Expo^-1) +
|
||||
(lpeg.digit^1 * Expo)
|
||||
local Int = lpeg.digit^1
|
||||
|
||||
tllexer.Number = Hex + Float + Int
|
||||
|
||||
local ShortString = lpeg.P('"') *
|
||||
((lpeg.P('\\') * lpeg.P(1)) + (lpeg.P(1) - lpeg.P('"')))^0 *
|
||||
tllexer.try(lpeg.P('"'), "String") +
|
||||
lpeg.P("'") *
|
||||
((lpeg.P("\\") * lpeg.P(1)) + (lpeg.P(1) - lpeg.P("'")))^0 *
|
||||
tllexer.try(lpeg.P("'"), "String")
|
||||
|
||||
tllexer.String = LongString + ShortString
|
||||
|
||||
-- for error reporting
|
||||
tllexer.OneWord = tllexer.Name +
|
||||
tllexer.Number +
|
||||
tllexer.String +
|
||||
tllexer.Reserved +
|
||||
lpeg.P("...") +
|
||||
lpeg.P(1)
|
||||
|
||||
return tllexer
|
20
06/deps/lpeglabel/examples/typedlua/tlp.lua
Normal file
20
06/deps/lpeglabel/examples/typedlua/tlp.lua
Normal file
|
@ -0,0 +1,20 @@
|
|||
local tlparser = require "tlparser"
|
||||
|
||||
local function getcontents(filename)
|
||||
file = assert(io.open(filename, "r"))
|
||||
contents = file:read("*a")
|
||||
file:close()
|
||||
return contents
|
||||
end
|
||||
|
||||
if #arg ~= 1 then
|
||||
print ("Usage: lua tlp.lua <file>")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
local filename = arg[1]
|
||||
local subject = getcontents(filename)
|
||||
local r, msg = tlparser.parse(subject, filename, false, true)
|
||||
if not r then print(msg) end
|
||||
|
||||
os.exit(0)
|
245
06/deps/lpeglabel/examples/typedlua/tlparser.lua
Normal file
245
06/deps/lpeglabel/examples/typedlua/tlparser.lua
Normal file
|
@ -0,0 +1,245 @@
|
|||
local tlparser = {}
|
||||
|
||||
local lpeg = require "lpeglabel"
|
||||
lpeg.locale(lpeg)
|
||||
|
||||
local tllexer = require "tllexer"
|
||||
local tlerror = require "tlerror"
|
||||
|
||||
local function chainl1 (pat, sep, label)
|
||||
return pat * (sep * tllexer.try(pat, label))^0
|
||||
end
|
||||
|
||||
local G = lpeg.P { "TypedLua";
|
||||
TypedLua = tllexer.Shebang^-1 * tllexer.Skip * lpeg.V("Chunk") * tllexer.try(-1, "Stat");
|
||||
-- type language
|
||||
Type = lpeg.V("NilableType");
|
||||
NilableType = lpeg.V("UnionType") * tllexer.symb("?")^-1;
|
||||
UnionType = lpeg.V("PrimaryType") * (tllexer.symb("|") * tllexer.try(lpeg.V("PrimaryType"), "UnionType"))^0;
|
||||
PrimaryType = lpeg.V("LiteralType") +
|
||||
lpeg.V("BaseType") +
|
||||
lpeg.V("NilType") +
|
||||
lpeg.V("ValueType") +
|
||||
lpeg.V("AnyType") +
|
||||
lpeg.V("SelfType") +
|
||||
lpeg.V("FunctionType") +
|
||||
lpeg.V("TableType") +
|
||||
lpeg.V("VariableType");
|
||||
LiteralType = tllexer.token("false", "false") +
|
||||
tllexer.token("true", "true") +
|
||||
tllexer.token(tllexer.Number, "Number") +
|
||||
tllexer.token(tllexer.String, "String");
|
||||
BaseType = tllexer.token("boolean", "boolean") +
|
||||
tllexer.token("number", "number") +
|
||||
tllexer.token("string", "string") +
|
||||
tllexer.token("integer", "integer");
|
||||
NilType = tllexer.token("nil", "nil");
|
||||
ValueType = tllexer.token("value", "value");
|
||||
AnyType = tllexer.token("any", "any");
|
||||
SelfType = tllexer.token("self", "self");
|
||||
FunctionType = lpeg.V("InputType") * tllexer.symb("->") * tllexer.try(lpeg.V("NilableTuple"), "FunctionType");
|
||||
MethodType = lpeg.V("InputType") * tllexer.symb("=>") * tllexer.try(lpeg.V("NilableTuple"), "MethodType");
|
||||
InputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP");
|
||||
NilableTuple = lpeg.V("UnionlistType") * tllexer.symb("?")^-1;
|
||||
UnionlistType = lpeg.V("OutputType") * (tllexer.symb("|") * tllexer.try(lpeg.V("OutputType"), "UnionType"))^0;
|
||||
OutputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP");
|
||||
TupleType = lpeg.V("Type") * (tllexer.symb(",") * tllexer.try(lpeg.V("Type"), "TupleType"))^0 * tllexer.symb("*")^-1;
|
||||
TableType = tllexer.symb("{") * lpeg.V("TableTypeBody")^-1 * tllexer.try(tllexer.symb("}"), "MissingCC");
|
||||
TableTypeBody = lpeg.V("RecordType") +
|
||||
lpeg.V("HashType") +
|
||||
lpeg.V("ArrayType");
|
||||
RecordType = lpeg.V("RecordField") * (tllexer.symb(",") * lpeg.V("RecordField"))^0 *
|
||||
(tllexer.symb(",") * (lpeg.V("HashType") + lpeg.V("ArrayType")))^-1;
|
||||
RecordField = tllexer.kw("const")^-1 *
|
||||
lpeg.V("LiteralType") * tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type");
|
||||
HashType = lpeg.V("KeyType") * tllexer.symb(":") * tllexer.try(lpeg.V("FieldType"), "Type");
|
||||
ArrayType = lpeg.V("FieldType");
|
||||
KeyType = lpeg.V("BaseType") + lpeg.V("ValueType") + lpeg.V("AnyType");
|
||||
FieldType = lpeg.V("Type");
|
||||
VariableType = tllexer.token(tllexer.Name, "Name");
|
||||
RetType = lpeg.V("NilableTuple") +
|
||||
lpeg.V("Type");
|
||||
Id = tllexer.token(tllexer.Name, "Name");
|
||||
TypeDecId = (tllexer.kw("const") * lpeg.V("Id")) +
|
||||
lpeg.V("Id");
|
||||
IdList = lpeg.V("TypeDecId") * (tllexer.symb(",") * tllexer.try(lpeg.V("TypeDecId"), "TupleType"))^0;
|
||||
IdDec = lpeg.V("IdList") * tllexer.symb(":") * tllexer.try((lpeg.V("Type") + lpeg.V("MethodType")), "Type");
|
||||
IdDecList = (lpeg.V("IdDec")^1)^-1;
|
||||
TypeDec = tllexer.token(tllexer.Name, "Name") * lpeg.V("IdDecList") * tllexer.try(tllexer.kw("end"), "TypeDecEnd");
|
||||
Interface = tllexer.kw("interface") * lpeg.V("TypeDec") +
|
||||
tllexer.kw("typealias") *
|
||||
tllexer.try(tllexer.token(tllexer.Name, "Name"), "TypeAliasName") *
|
||||
tllexer.try(tllexer.symb("="), "MissingEqTypeAlias") * lpeg.V("Type");
|
||||
-- parser
|
||||
Chunk = lpeg.V("Block");
|
||||
StatList = (tllexer.symb(";") + lpeg.V("Stat"))^0;
|
||||
Var = lpeg.V("Id");
|
||||
TypedId = tllexer.token(tllexer.Name, "Name") * (tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type"))^-1;
|
||||
FunctionDef = tllexer.kw("function") * lpeg.V("FuncBody");
|
||||
FieldSep = tllexer.symb(",") + tllexer.symb(";");
|
||||
Field = ((tllexer.symb("[") * lpeg.V("Expr") * tllexer.try(tllexer.symb("]"), "MissingCB")) +
|
||||
(tllexer.token(tllexer.Name, "Name"))) *
|
||||
tllexer.symb("=") * lpeg.V("Expr") +
|
||||
lpeg.V("Expr");
|
||||
TField = (tllexer.kw("const") * lpeg.V("Field")) +
|
||||
lpeg.V("Field");
|
||||
FieldList = (lpeg.V("TField") * (lpeg.V("FieldSep") * lpeg.V("TField"))^0 *
|
||||
lpeg.V("FieldSep")^-1)^-1;
|
||||
Constructor = tllexer.symb("{") * lpeg.V("FieldList") * tllexer.try(tllexer.symb("}"), "MissingCC");
|
||||
NameList = lpeg.V("TypedId") * (tllexer.symb(",") * lpeg.V("TypedId"))^0;
|
||||
ExpList = lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0;
|
||||
FuncArgs = tllexer.symb("(") *
|
||||
(lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 *
|
||||
tllexer.try(tllexer.symb(")"), "MissingCP") +
|
||||
lpeg.V("Constructor") +
|
||||
tllexer.token(tllexer.String, "String");
|
||||
OrOp = tllexer.kw("or");
|
||||
AndOp = tllexer.kw("and");
|
||||
RelOp = tllexer.symb("~=") +
|
||||
tllexer.symb("==") +
|
||||
tllexer.symb("<=") +
|
||||
tllexer.symb(">=") +
|
||||
tllexer.symb("<") +
|
||||
tllexer.symb(">");
|
||||
BOrOp = tllexer.symb("|");
|
||||
BXorOp = tllexer.symb("~") * -lpeg.P("=");
|
||||
BAndOp = tllexer.symb("&");
|
||||
ShiftOp = tllexer.symb("<<") +
|
||||
tllexer.symb(">>");
|
||||
ConOp = tllexer.symb("..");
|
||||
AddOp = tllexer.symb("+") +
|
||||
tllexer.symb("-");
|
||||
MulOp = tllexer.symb("*") +
|
||||
tllexer.symb("//") +
|
||||
tllexer.symb("/") +
|
||||
tllexer.symb("%");
|
||||
UnOp = tllexer.kw("not") +
|
||||
tllexer.symb("-") +
|
||||
tllexer.symb("~") +
|
||||
tllexer.symb("#");
|
||||
PowOp = tllexer.symb("^");
|
||||
Expr = lpeg.V("SubExpr_1");
|
||||
SubExpr_1 = chainl1(lpeg.V("SubExpr_2"), lpeg.V("OrOp"), "SubExpr_1");
|
||||
SubExpr_2 = chainl1(lpeg.V("SubExpr_3"), lpeg.V("AndOp"), "SubExpr_2");
|
||||
SubExpr_3 = chainl1(lpeg.V("SubExpr_4"), lpeg.V("RelOp"), "SubExpr_3");
|
||||
SubExpr_4 = chainl1(lpeg.V("SubExpr_5"), lpeg.V("BOrOp"), "SubExpr_4");
|
||||
SubExpr_5 = chainl1(lpeg.V("SubExpr_6"), lpeg.V("BXorOp"), "SubExpr_5");
|
||||
SubExpr_6 = chainl1(lpeg.V("SubExpr_7"), lpeg.V("BAndOp"), "SubExpr_6");
|
||||
SubExpr_7 = chainl1(lpeg.V("SubExpr_8"), lpeg.V("ShiftOp"), "SubExpr_7");
|
||||
SubExpr_8 = lpeg.V("SubExpr_9") * lpeg.V("ConOp") * tllexer.try(lpeg.V("SubExpr_8"), "SubExpr_8") +
|
||||
lpeg.V("SubExpr_9");
|
||||
SubExpr_9 = chainl1(lpeg.V("SubExpr_10"), lpeg.V("AddOp"), "SubExpr_9");
|
||||
SubExpr_10 = chainl1(lpeg.V("SubExpr_11"), lpeg.V("MulOp"), "SubExpr_10");
|
||||
SubExpr_11 = lpeg.V("UnOp") * tllexer.try(lpeg.V("SubExpr_11"), "SubExpr_11") +
|
||||
lpeg.V("SubExpr_12");
|
||||
SubExpr_12 = lpeg.V("SimpleExp") * (lpeg.V("PowOp") * tllexer.try(lpeg.V("SubExpr_11"), "SubExpr_12"))^-1;
|
||||
SimpleExp = tllexer.token(tllexer.Number, "Number") +
|
||||
tllexer.token(tllexer.String, "String") +
|
||||
tllexer.kw("nil") +
|
||||
tllexer.kw("false") +
|
||||
tllexer.kw("true") +
|
||||
tllexer.symb("...") +
|
||||
lpeg.V("FunctionDef") +
|
||||
lpeg.V("Constructor") +
|
||||
lpeg.V("SuffixedExp");
|
||||
SuffixedExp = lpeg.V("PrimaryExp") * (
|
||||
(tllexer.symb(".") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "DotIndex")) / "index" +
|
||||
(tllexer.symb("[") * lpeg.V("Expr") * tllexer.try(tllexer.symb("]"), "MissingCB")) / "index" +
|
||||
(tllexer.symb(":") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "MethodName") * tllexer.try(lpeg.V("FuncArgs"), "MethodCall")) / "call" +
|
||||
lpeg.V("FuncArgs") / "call")^0 / function (...) local l = {...}; return l[#l] end;
|
||||
PrimaryExp = lpeg.V("Var") / "var" +
|
||||
tllexer.symb("(") * lpeg.V("Expr") * tllexer.try(tllexer.symb(")"), "MissingCP");
|
||||
Block = lpeg.V("StatList") * lpeg.V("RetStat")^-1;
|
||||
IfStat = tllexer.kw("if") * lpeg.V("Expr") * tllexer.try(tllexer.kw("then"), "Then") * lpeg.V("Block") *
|
||||
(tllexer.kw("elseif") * tllexer.try(lpeg.V("Expr"), "ElseIf") * tllexer.try(tllexer.kw("then"), "Then") * lpeg.V("Block"))^0 *
|
||||
(tllexer.kw("else") * lpeg.V("Block"))^-1 *
|
||||
tllexer.try(tllexer.kw("end"), "IfEnd");
|
||||
WhileStat = tllexer.kw("while") * lpeg.V("Expr") *
|
||||
tllexer.try(tllexer.kw("do"), "WhileDo") * lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "WhileEnd");
|
||||
DoStat = tllexer.kw("do") * lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "BlockEnd");
|
||||
ForBody = tllexer.try(tllexer.kw("do"), "ForDo") * lpeg.V("Block");
|
||||
ForNum = lpeg.V("Id") * tllexer.symb("=") * lpeg.V("Expr") * tllexer.symb(",") *
|
||||
lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^-1 *
|
||||
lpeg.V("ForBody");
|
||||
ForGen = lpeg.V("NameList") * tllexer.try(tllexer.kw("in"), "ForGen") *
|
||||
lpeg.V("ExpList") * lpeg.V("ForBody");
|
||||
ForStat = tllexer.kw("for") * (lpeg.V("ForNum") + lpeg.V("ForGen")) * tllexer.try(tllexer.kw("end"), "ForEnd");
|
||||
RepeatStat = tllexer.kw("repeat") * lpeg.V("Block") *
|
||||
tllexer.try(tllexer.kw("until"), "Until") * lpeg.V("Expr");
|
||||
FuncName = lpeg.V("Id") * (tllexer.symb(".") *
|
||||
(tllexer.token(tllexer.Name, "Name")))^0 *
|
||||
(tllexer.symb(":") * (tllexer.token(tllexer.Name, "Name")))^-1;
|
||||
ParList = lpeg.V("NameList") * (tllexer.symb(",") * tllexer.try(lpeg.V("TypedVarArg"), "ParList"))^-1 +
|
||||
lpeg.V("TypedVarArg");
|
||||
TypedVarArg = tllexer.symb("...") * (tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type"))^-1;
|
||||
FuncBody = tllexer.try(tllexer.symb("("), "MissingOP") * lpeg.V("ParList")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP") *
|
||||
(tllexer.symb(":") * tllexer.try(lpeg.V("RetType"), "Type"))^-1 *
|
||||
lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "FuncEnd");
|
||||
FuncStat = tllexer.kw("const")^-1 *
|
||||
tllexer.kw("function") * lpeg.V("FuncName") * lpeg.V("FuncBody");
|
||||
LocalFunc = tllexer.kw("function") *
|
||||
tllexer.try(lpeg.V("Id"), "LocalFunc") * lpeg.V("FuncBody");
|
||||
LocalAssign = lpeg.V("NameList") * tllexer.symb("=") * tllexer.try(lpeg.V("ExpList"), "LocalAssign1") +
|
||||
lpeg.V("NameList") * (#(-tllexer.symb("=") * (lpeg.V("Stat") + -1)) * lpeg.P(true)) + lpeg.T(tlerror.labels["LocalAssign2"]);
|
||||
LocalStat = tllexer.kw("local") *
|
||||
(lpeg.V("LocalTypeDec") + lpeg.V("LocalFunc") + lpeg.V("LocalAssign"));
|
||||
LabelStat = tllexer.symb("::") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "Label1") * tllexer.try(tllexer.symb("::"), "Label2");
|
||||
BreakStat = tllexer.kw("break");
|
||||
GoToStat = tllexer.kw("goto") * tllexer.token(tllexer.Name, "Name");
|
||||
RetStat = tllexer.kw("return") * tllexer.try(-lpeg.V("Stat"), "RetStat") *
|
||||
(lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 *
|
||||
tllexer.symb(";")^-1;
|
||||
TypeDecStat = lpeg.V("Interface");
|
||||
LocalTypeDec = lpeg.V("TypeDecStat");
|
||||
LVar = (tllexer.kw("const") * lpeg.V("SuffixedExp")) +
|
||||
lpeg.V("SuffixedExp");
|
||||
ExprStat = lpeg.Cmt(lpeg.V("LVar") * lpeg.V("Assignment"),
|
||||
function (s, i, ...)
|
||||
local l = {...}
|
||||
local i = 1
|
||||
while l[i] ~= "=" do
|
||||
local se = l[i]
|
||||
if se ~= "var" and se ~= "index" then return false end
|
||||
i = i + 1
|
||||
end
|
||||
return true
|
||||
end) +
|
||||
lpeg.Cmt(lpeg.V("SuffixedExp"),
|
||||
function (s, i, se)
|
||||
if se ~= "call" then return false end
|
||||
return true
|
||||
end);
|
||||
Assignment = ((tllexer.symb(",") * lpeg.V("LVar"))^1)^-1 * (tllexer.symb("=") / "=") * lpeg.V("ExpList");
|
||||
Stat = lpeg.V("IfStat") + lpeg.V("WhileStat") + lpeg.V("DoStat") + lpeg.V("ForStat") +
|
||||
lpeg.V("RepeatStat") + lpeg.V("FuncStat") + lpeg.V("LocalStat") +
|
||||
lpeg.V("LabelStat") + lpeg.V("BreakStat") + lpeg.V("GoToStat") +
|
||||
lpeg.V("TypeDecStat") + lpeg.V("ExprStat");
|
||||
}
|
||||
|
||||
local function lineno (s, i)
|
||||
if i == 1 then return 1, 1 end
|
||||
local rest, num = s:sub(1,i):gsub("[^\n]*\n", "")
|
||||
local r = #rest
|
||||
return 1 + num, r ~= 0 and r or 1
|
||||
end
|
||||
|
||||
function tlparser.parse (subject, filename, strict, integer)
|
||||
local errorinfo = {}
|
||||
lpeg.setmaxstack(1000)
|
||||
local ast, label, suffix = lpeg.match(G, subject, nil, errorinfo, strict, integer)
|
||||
if not ast then
|
||||
local line, col = lineno(subject, string.len(subject) - string.len(suffix))
|
||||
local error_msg = string.format("%s:%d:%d: ", filename, line, col)
|
||||
if label ~= 0 then
|
||||
error_msg = error_msg .. tlerror.errors[label].msg
|
||||
else
|
||||
local u = lpeg.match(lpeg.C(tllexer.OneWord) + lpeg.Cc("EOF"), subject, errorinfo.ffp)
|
||||
error_msg = error_msg .. string.format("unexpected '%s', expecting %s", u, errorinfo.expected)
|
||||
end
|
||||
return nil, error_msg
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return tlparser
|
Loading…
Add table
Add a link
Reference in a new issue