From 448762908fd822fbc101a4fe66fac9cd8aa913b5 Mon Sep 17 00:00:00 2001 From: Sergio Queiroz Date: Mon, 14 Nov 2016 17:15:27 -0300 Subject: Changing documentation and examples with recovery --- examples/listId1.lua | 12 +++++---- examples/listId2.lua | 13 ++++++---- examples/listId2Rec2.lua | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 10 deletions(-) create mode 100644 examples/listId2Rec2.lua (limited to 'examples') diff --git a/examples/listId1.lua b/examples/listId1.lua index 8976f5f..dee46e9 100644 --- a/examples/listId1.lua +++ b/examples/listId1.lua @@ -1,12 +1,14 @@ -local m = require'lpeglabel' -local re = require'relabel' +local m = require'lpeglabelrec' +local re = require'relabelrec' + +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.T(2)) * (m.V"Id" + m.T(1)) * m.V"List", - Id = m.V"Sp" * m.R'az'^1, - Comma = m.V"Sp" * ",", + 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, } diff --git a/examples/listId2.lua b/examples/listId2.lua index 509fda4..46f0063 100644 --- a/examples/listId2.lua +++ b/examples/listId2.lua @@ -1,5 +1,5 @@ -local m = require'lpeglabel' -local re = require'relabel' +local m = require'lpeglabelrec' +local re = require'relabelrec' local terror = {} @@ -12,15 +12,18 @@ 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.T(errComma)) * (m.V"Id" + m.T(errId)) * m.V"List", - Id = m.V"Sp" * m.R'az'^1, - Comma = m.V"Sp" * ",", + 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 diff --git a/examples/listId2Rec2.lua b/examples/listId2Rec2.lua new file mode 100644 index 0000000..a347a5b --- /dev/null +++ b/examples/listId2Rec2.lua @@ -0,0 +1,67 @@ +local m = require'lpeglabelrec' +local re = require'relabelrec' + +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(-m.P(1) + id), + ErrId = record(errId) * sync(-m.P(1) + ",") +} + + +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") + 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,")) -- cgit v1.2.3-55-g6feb From 96284f8b4a6a25efd3c0c5ce9c7595604ba3143f Mon Sep 17 00:00:00 2001 From: Sergio Queiroz Date: Thu, 17 Nov 2016 15:55:24 -0300 Subject: Updating examples using the recovery operator --- examples/listId2Rec2Cap.lua | 79 +++++++++++++++++++++++++++++++++++++++++++++ examples/listIdRe1.lua | 8 ++--- examples/listIdRe2.lua | 50 ++++++++++++++++++++-------- 3 files changed, 119 insertions(+), 18 deletions(-) create mode 100644 examples/listId2Rec2Cap.lua (limited to 'examples') diff --git a/examples/listId2Rec2Cap.lua b/examples/listId2Rec2Cap.lua new file mode 100644 index 0000000..f9fc2bd --- /dev/null +++ b/examples/listId2Rec2Cap.lua @@ -0,0 +1,79 @@ +local m = require'lpeglabelrec' +local re = require'relabelrec' + +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(-m.P(1) + id), + ErrId = record(errId) * sync(-m.P(1) + ",") * 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,") diff --git a/examples/listIdRe1.lua b/examples/listIdRe1.lua index d092566..3988a3b 100644 --- a/examples/listIdRe1.lua +++ b/examples/listIdRe1.lua @@ -1,10 +1,10 @@ -local re = require 'relabel' +local re = require 'relabelrec' local g = re.compile[[ S <- Id List - List <- !. / (',' / %{2}) (Id / %{1}) List - Id <- Sp [a-z]+ - Comma <- Sp ',' + List <- !. / Comma Id List + Id <- Sp [a-z]+ / %{2} + Comma <- Sp ',' / %{3} Sp <- %s* ]] diff --git a/examples/listIdRe2.lua b/examples/listIdRe2.lua index fe30535..070bcdb 100644 --- a/examples/listIdRe2.lua +++ b/examples/listIdRe2.lua @@ -1,4 +1,4 @@ -local re = require 'relabel' +local re = require 'relabelrec' local errinfo = { {"errUndef", "undefined"}, @@ -18,23 +18,45 @@ re.setlabels(labels) local g = re.compile[[ S <- Id List - List <- !. / (',' / %{errComma}) (Id / %{errId}) List - Id <- Sp [a-z]+ - Comma <- Sp ',' + 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) (!(!. / ',') .)*" + , {g = g, recorderror = recorderror}) + 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 .. errmsgs[e] .. " before '" .. sfail .. "'" + errors = {} + 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") end return r end - -print(mymatch(g, "one,two")) -print(mymatch(g, "one two")) -print(mymatch(g, "one,\n two,\nthree,")) - + +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,")) -- cgit v1.2.3-55-g6feb From 5a4165922a1a6e0ed9cdb65446157c453667ed9c Mon Sep 17 00:00:00 2001 From: Sergio Queiroz Date: Fri, 18 Nov 2016 16:42:15 -0300 Subject: Updating examples. Example recoveryFabio is not complete --- examples/listIdCatch.lua | 28 ----------- examples/listIdCatchRe.lua | 34 ------------- examples/recovery.lua | 2 +- examples/recoveryFabio.lua | 119 ++++++++++++++++++++++++++++++++++++++++++++ examples/recoveryOpFail.lua | 2 +- examples/tiny.lua | 84 ++++++++++++++----------------- 6 files changed, 157 insertions(+), 112 deletions(-) delete mode 100644 examples/listIdCatch.lua delete mode 100644 examples/listIdCatchRe.lua create mode 100644 examples/recoveryFabio.lua (limited to 'examples') diff --git a/examples/listIdCatch.lua b/examples/listIdCatch.lua deleted file mode 100644 index 5ad6f2d..0000000 --- a/examples/listIdCatch.lua +++ /dev/null @@ -1,28 +0,0 @@ -local m = require'lpeglabel' - -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 g = m.P{ - "S", - S = m.Lc(m.Lc(m.V"Id" * m.V"List", m.V"ErrId", errId), - m.V"ErrComma", errComma), - List = -m.P(1) + (m.V"Comma" + m.T(errComma)) * (m.V"Id" + m.T(errId)) * m.V"List", - Id = m.V"Sp" * m.R'az'^1, - Comma = m.V"Sp" * ",", - Sp = m.S" \n\t"^0, - ErrId = m.Cc(errId) / terror, - ErrComma = m.Cc(errComma) / terror -} - -print(m.match(g, "one,two")) -print(m.match(g, "one two")) -print(m.match(g, "one,\n two,\nthree,")) diff --git a/examples/listIdCatchRe.lua b/examples/listIdCatchRe.lua deleted file mode 100644 index 8971191..0000000 --- a/examples/listIdCatchRe.lua +++ /dev/null @@ -1,34 +0,0 @@ -local re = require'relabel' - -local terror = {} - -local function newError(l, msg) - table.insert(terror, { l = l, msg = msg } ) -end - -newError("errId", "Error: expecting an identifier") -newError("errComma", "Error: expecting ','") - -local labelCode = {} -local labelMsg = {} -for k, v in ipairs(terror) do - labelCode[v.l] = k - labelMsg[v.l] = v.msg -end - -re.setlabels(labelCode) - -local p = re.compile([[ - S <- Id List /{errId} ErrId /{errComma} ErrComma - List <- !. / Comma Id List - Id <- [a-z]+ / %{errId} - Comma <- ',' / %{errComma} - ErrId <- '' -> errId - ErrComma <- '' -> errComma -]], labelMsg) - -print(p:match("a,b")) -print(p:match("a b")) -print(p:match(",b")) - - diff --git a/examples/recovery.lua b/examples/recovery.lua index 3272ae7..bb17b54 100644 --- a/examples/recovery.lua +++ b/examples/recovery.lua @@ -1,4 +1,4 @@ -local lpeg = require"lpeglabel" +local lpeg = require"lpeglabelrec" local R, S, P, V = lpeg.R, lpeg.S, lpeg.P, lpeg.V local C, Cc, Ct, Cmt = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cmt diff --git a/examples/recoveryFabio.lua b/examples/recoveryFabio.lua new file mode 100644 index 0000000..f16c9e7 --- /dev/null +++ b/examples/recoveryFabio.lua @@ -0,0 +1,119 @@ +local lpeg = require"lpeglabelrec" + +local R, S, P, V = lpeg.R, lpeg.S, lpeg.P, lpeg.V +local C, Cc, Ct, Cmt = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cmt +local T, Rec = lpeg.T, lpeg.Rec + +local labels = { + {"NoExp", "no expression found"}, + {"Extra", "extra characters found after the expression"}, + {"ExpTerm", "expected a term after the operator"}, + {"ExpExp", "expected an expression after the parenthesis"}, + {"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 = {} + +local function expect(patt, labname, recpatt) + local i = labelindex(labname) + function recorderror(input, pos) + table.insert(errors, {i, pos}) + return true + end + return patt + T(i) +end + +local num = R("09")^1 / tonumber +local op = 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 = P { + "Exp", + Exp = Ct(V"Operand" * (C(op) * V"Operand")^0) / compute, + Operand = expect(V"Term", "ExpTerm"), + Term = num + V"Group", + Group = "(" * V"InnerExp" * expect(")", "MisClose", ""); + InnerExp = expect(V"Exp", "ExpExp", (P(1) - ")")^0 * Cc(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 (labname) + return (m.Cp() * m.Cc(labelindex(labname))) / recorderror +end + +function sync (p) + return (-p * m.P(1))^0 +end + +function defaultValue () + return m.Cc"NONE" +end + +local recg = P { + "S", + S = Rec(m.V"A", Cc(0), labelindex("ExpTerm")), -- default value is 0 + A = Rec(m.V"B", Cc(0), labelindex("ExpExp")), + B = Rec(m.V"Sg", Cc(0), labelindex("InnerExp")), + Sg = Rec(g, Cc(0), labelindex("MisClose")), + ErrExpTerm = record(labelindex("ExpTerm")) * sync() * defaultValue() +} + + +local function eval(input) + local result, label, suffix = recg:match(input) + if #errors == 0 then + return result + else + local out = {} + for i, err in ipairs(errors) do + local pos = err[2] + local msg = labels[err[1]][2] + table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") + end + errors = {} + return nil, table.concat(out, "\n") + end +end + +print(eval "90-70*5") +--> 20 + +print(eval "2+") +--> 2 + 0 + +print(eval "-2") +--> 0 - 2 + + +print(eval "1+3+-9") +--> 1 + 3 + 0 - 9 + diff --git a/examples/recoveryOpFail.lua b/examples/recoveryOpFail.lua index d65b9e0..bd1beb7 100644 --- a/examples/recoveryOpFail.lua +++ b/examples/recoveryOpFail.lua @@ -1,4 +1,4 @@ -local lpeg = require"lpeglabel" +local lpeg = require"lpeglabelrec" local R, S, P, V = lpeg.R, lpeg.S, lpeg.P, lpeg.V local C, Cc, Ct, Cmt = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cmt diff --git a/examples/tiny.lua b/examples/tiny.lua index 99c3144..784e031 100644 --- a/examples/tiny.lua +++ b/examples/tiny.lua @@ -1,4 +1,4 @@ -local re = require 'relabel' +local re = require 'relabelrec' local terror = {} @@ -25,21 +25,6 @@ newError("errFactor", "Error: expected '(', ID, or number after '*' or '/'") newError("errExpFac", "Error: expected expression after '('") newError("errClosePar", "Error: expected ')' after expression") -local line - -local function incLine() - line = line + 1 - return true -end - -local function countLine(s, i) - line = 1 - local p = re.compile([[ - S <- (%nl -> incLine / .)* - ]], { incLine = incLine}) - p:match(s:sub(1, i)) - return true -end local labelCode = {} for k, v in ipairs(terror) do @@ -48,7 +33,7 @@ end re.setlabels(labelCode) -local g = re.compile([[ +local g = re.compile[[ Tiny <- CmdSeq CmdSeq <- (Cmd (SEMICOLON / ErrSemi)) (Cmd (SEMICOLON / ErrSemi))* Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd @@ -61,25 +46,24 @@ local g = re.compile([[ SimpleExp <- Term ((ADD / SUB) (Term / ErrTerm))* Term <- Factor ((MUL / DIV) (Factor / ErrFactor))* Factor <- OPENPAR (Exp / ErrExpFac) (CLOSEPAR / ErrClosePar) / NUMBER / NAME - ErrSemi <- ErrCount %{errSemi} - ErrExpIf <- ErrCount %{errExpIf} - ErrThen <- ErrCount %{errThen} - ErrCmdSeq1 <- ErrCount %{errCmdSeq1} - ErrCmdSeq2 <- ErrCount %{errCmdSeq2} - ErrEnd <- ErrCount %{errEnd} - ErrCmdSeqRep <- ErrCount %{errCmdSeqRep} - ErrUntil <- ErrCount %{errUntil} - ErrExpRep <- ErrCount %{errExpRep} - ErrAssignOp <- ErrCount %{errAssignOp} - ErrExpAssign <- ErrCount %{errExpAssign} - ErrReadName <- ErrCount %{errReadName} - ErrWriteExp <- ErrCount %{errWriteExp} - ErrSimpExp <- ErrCount %{errSimpExp} - ErrTerm <- ErrCount %{errTerm} - ErrFactor <- ErrCount %{errFactor} - ErrExpFac <- ErrCount %{errExpFac} - ErrClosePar <- ErrCount %{errClosePar} - ErrCount <- '' => countLine + 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 ')' @@ -102,12 +86,17 @@ local g = re.compile([[ WRITE <- Sp 'write' RESERVED <- (IF / ELSE / END / READ / REPEAT / THEN / UNTIL / WRITE) ![a-z]+ Sp <- %s* -]], { countLine = countLine }) +]] -local function printError(n, e) - assert(n == nil) - print("Line " .. line .. ": " .. terror[e].msg) +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 = [[ @@ -118,7 +107,7 @@ repeat n := n - 1 until (n < 1); write f;]] -printError(g:match(s)) +print(mymatch(g, s)) s = [[ n := 5; @@ -128,14 +117,14 @@ repeat n := n - 1; until (n < 1); read ;]] -printError(g:match(s)) +print(mymatch(g, s)) s = [[ if a < 1 then b := 2; else b := 3;]] -printError(g:match(s)) +print(mymatch(g, s)) s = [[ n := 5; @@ -145,7 +134,7 @@ repeat n := n - 1; untill (n < 1); ]] -printError(g:match(s)) +print(mymatch(g, s)) s = [[ n := 5; @@ -155,9 +144,8 @@ repeat n := n - 1; 3 (n < 1); ]] -printError(g:match(s)) - -printError(g:match("a : 2")) -printError(g:match("a := (2")) +print(mymatch(g, s)) +print(mymatch(g, "a : 2")) +print(mymatch(g, "a := (2")) -- cgit v1.2.3-55-g6feb From 3a5f5683bf6d676ea4118c3a8d0fc25de317d91f Mon Sep 17 00:00:00 2001 From: Sergio Queiroz Date: Wed, 23 Nov 2016 15:22:46 -0300 Subject: Updating examples to use the recovery operator --- examples/listId2Rec2.lua | 4 +- examples/listId2Rec2Cap.lua | 4 +- examples/recoveryFabio.lua | 119 ------------------------------------------- examples/recoveryRecCap.lua | 121 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 123 deletions(-) delete mode 100644 examples/recoveryFabio.lua create mode 100644 examples/recoveryRecCap.lua (limited to 'examples') diff --git a/examples/listId2Rec2.lua b/examples/listId2Rec2.lua index a347a5b..ab8f1dd 100644 --- a/examples/listId2Rec2.lua +++ b/examples/listId2Rec2.lua @@ -41,8 +41,8 @@ end local grec = m.P{ "S", S = m.Rec(m.Rec(g, m.V"ErrComma", errComma), m.V"ErrId", errId), - ErrComma = record(errComma) * sync(-m.P(1) + id), - ErrId = record(errId) * sync(-m.P(1) + ",") + ErrComma = record(errComma) * sync(id), + ErrId = record(errId) * sync(m.P",") } diff --git a/examples/listId2Rec2Cap.lua b/examples/listId2Rec2Cap.lua index f9fc2bd..1c22c88 100644 --- a/examples/listId2Rec2Cap.lua +++ b/examples/listId2Rec2Cap.lua @@ -45,8 +45,8 @@ end local grec = m.P{ "S", S = m.Rec(m.Rec(g, m.V"ErrComma", errComma), m.V"ErrId", errId), - ErrComma = record(errComma) * sync(-m.P(1) + id), - ErrId = record(errId) * sync(-m.P(1) + ",") * defaultValue() + ErrComma = record(errComma) * sync(id), + ErrId = record(errId) * sync(m.P",") * defaultValue(), } diff --git a/examples/recoveryFabio.lua b/examples/recoveryFabio.lua deleted file mode 100644 index f16c9e7..0000000 --- a/examples/recoveryFabio.lua +++ /dev/null @@ -1,119 +0,0 @@ -local lpeg = require"lpeglabelrec" - -local R, S, P, V = lpeg.R, lpeg.S, lpeg.P, lpeg.V -local C, Cc, Ct, Cmt = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cmt -local T, Rec = lpeg.T, lpeg.Rec - -local labels = { - {"NoExp", "no expression found"}, - {"Extra", "extra characters found after the expression"}, - {"ExpTerm", "expected a term after the operator"}, - {"ExpExp", "expected an expression after the parenthesis"}, - {"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 = {} - -local function expect(patt, labname, recpatt) - local i = labelindex(labname) - function recorderror(input, pos) - table.insert(errors, {i, pos}) - return true - end - return patt + T(i) -end - -local num = R("09")^1 / tonumber -local op = 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 = P { - "Exp", - Exp = Ct(V"Operand" * (C(op) * V"Operand")^0) / compute, - Operand = expect(V"Term", "ExpTerm"), - Term = num + V"Group", - Group = "(" * V"InnerExp" * expect(")", "MisClose", ""); - InnerExp = expect(V"Exp", "ExpExp", (P(1) - ")")^0 * Cc(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 (labname) - return (m.Cp() * m.Cc(labelindex(labname))) / recorderror -end - -function sync (p) - return (-p * m.P(1))^0 -end - -function defaultValue () - return m.Cc"NONE" -end - -local recg = P { - "S", - S = Rec(m.V"A", Cc(0), labelindex("ExpTerm")), -- default value is 0 - A = Rec(m.V"B", Cc(0), labelindex("ExpExp")), - B = Rec(m.V"Sg", Cc(0), labelindex("InnerExp")), - Sg = Rec(g, Cc(0), labelindex("MisClose")), - ErrExpTerm = record(labelindex("ExpTerm")) * sync() * defaultValue() -} - - -local function eval(input) - local result, label, suffix = recg:match(input) - if #errors == 0 then - return result - else - local out = {} - for i, err in ipairs(errors) do - local pos = err[2] - local msg = labels[err[1]][2] - table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") - end - errors = {} - return nil, table.concat(out, "\n") - end -end - -print(eval "90-70*5") ---> 20 - -print(eval "2+") ---> 2 + 0 - -print(eval "-2") ---> 0 - 2 - - -print(eval "1+3+-9") ---> 1 + 3 + 0 - 9 - diff --git a/examples/recoveryRecCap.lua b/examples/recoveryRecCap.lua new file mode 100644 index 0000000..c1b3a53 --- /dev/null +++ b/examples/recoveryRecCap.lua @@ -0,0 +1,121 @@ +local m = require"lpeglabelrec" +local re = require"relabelrec" + +local R, S, P, V = m.R, m.S, m.P, m.V +local C, Cc, Ct, Cmt = m.C, m.Cc, m.Ct, m.Cmt +local T, Rec = m.T, m.Rec + +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, recpatt) + local i = labelindex(labname) + return patt + T(i) +end + + +local num = R("09")^1 / tonumber +local op = 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 = P { + "Exp", + Exp = Ct(V"OperandFirst" * (C(op) * V"Operand")^0) / compute, + OperandFirst = expect(V"Term", "ExpTermFirst"), + Operand = expect(V"Term", "ExpTermOp"), + Term = num + V"Group", + Group = "(" * 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(0) +end + +local recg = P { + "S", + S = Rec(V"A", V"ErrExpTermFirst", labelindex("ExpTermFirst")), -- default value is 0 + A = Rec(V"Sg", V"ErrExpTermOp", labelindex("ExpTermOp")), + Sg = Rec(g, V"ErrMisClose", labelindex("MisClose")), + ErrExpTermFirst = record("ExpTermFirst") * sync(op + ")") * defaultValue(), + ErrExpTermOp = record("ExpTermOp") * sync(op + ")") * defaultValue(), + ErrMisClose = record("MisClose") * sync(P")") * defaultValue(m.P""), +} + + +local function eval(input) + errors = {} + subject = input + local result, label, suffix = recg:match(input) + 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 + return result +end + +print(eval "90-70*5") +--> 20 + +print(eval "2+") +--> 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 "") -- cgit v1.2.3-55-g6feb From e7e17699870f0bd6ba43b4e946297fb581d28b48 Mon Sep 17 00:00:00 2001 From: Sergio Queiroz Date: Tue, 29 Nov 2016 18:06:10 -0300 Subject: Updating examples --- examples/expressionRecovery.lua | 127 ++++++++++++++++++++++++++++++++++++++++ examples/recoveryOpFail.lua | 108 ---------------------------------- examples/recoveryOpLab.lua | 107 --------------------------------- examples/recoveryRecCap.lua | 121 -------------------------------------- examples/typedlua/test.lua | 9 ++- examples/typedlua/tllexer.lua | 11 ++-- examples/typedlua/tlparser.lua | 2 +- testlabel.lua | 9 +++ 8 files changed, 148 insertions(+), 346 deletions(-) create mode 100644 examples/expressionRecovery.lua delete mode 100644 examples/recoveryOpFail.lua delete mode 100644 examples/recoveryOpLab.lua delete mode 100644 examples/recoveryRecCap.lua (limited to 'examples') diff --git a/examples/expressionRecovery.lua b/examples/expressionRecovery.lua new file mode 100644 index 0000000..a4a3288 --- /dev/null +++ b/examples/expressionRecovery.lua @@ -0,0 +1,127 @@ +local m = require"lpeglabelrec" +local re = require"relabelrec" + +local R, S, P, V = m.R, m.S, m.P, m.V +local C, Cc, Ct, Cmt = m.C, m.Cc, m.Ct, m.Cmt +local T, Rec = m.T, m.Rec + +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, recpatt) + local i = labelindex(labname) + return patt + T(i) +end + + +local num = R("09")^1 / tonumber +local op = 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 = P { + "Exp", + Exp = Ct(V"OperandFirst" * (C(op) * V"Operand")^0) / compute, + OperandFirst = expect(V"Term", "ExpTermFirst"), + Operand = expect(V"Term", "ExpTermOp"), + Term = num + V"Group", + Group = "(" * 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 recg = P { + "S", + S = Rec(V"A", V"ErrExpTermFirst", labelindex("ExpTermFirst")), -- default value is 0 + A = Rec(V"Sg", V"ErrExpTermOp", labelindex("ExpTermOp")), + Sg = Rec(g, V"ErrMisClose", labelindex("MisClose")), + ErrExpTermFirst = record("ExpTermFirst") * sync(op + ")") * defaultValue(), + ErrExpTermOp = record("ExpTermOp") * sync(op + ")") * defaultValue(), + ErrMisClose = record("MisClose") * sync(P")") * defaultValue(m.P""), +} + + +local function eval(input) + errors = {} + subject = input + local result, label, suffix = recg:match(input) + if #errors > 0 then + local out = {} + for i, err in ipairs(errors) do + local pos = err.col + local msg = err.msg + print("sub", subject) + table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") + end + print(table.concat(out, "\n")) + end + return result +end + +print(eval "90-70*5") +--> 20 + +print(eval "2+") +--> 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 "3)") + diff --git a/examples/recoveryOpFail.lua b/examples/recoveryOpFail.lua deleted file mode 100644 index bd1beb7..0000000 --- a/examples/recoveryOpFail.lua +++ /dev/null @@ -1,108 +0,0 @@ -local lpeg = require"lpeglabelrec" - -local R, S, P, V = lpeg.R, lpeg.S, lpeg.P, lpeg.V -local C, Cc, Ct, Cmt = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cmt -local T, Lc, Rec = lpeg.T, lpeg.Lc, lpeg.Rec - -local labels = { - {"NoExp", "no expression found"}, - {"Extra", "extra characters found after the expression"}, - {"ExpTerm", "expected a term after the operator"}, - {"ExpExp", "expected an expression after the parenthesis"}, - {"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 = {} - -local function expect(patt, labname, recpatt) - local i = labelindex(labname) - function recorderror(input, pos) - table.insert(errors, {i, pos}) - return true - end - if not recpatt then recpatt = P"" end - return Rec(patt, Cmt("", recorderror) * recpatt) -end - -local num = R("09")^1 / tonumber -local op = 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] - elseif 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 = P { - "Exp", - Exp = Ct(V"Term" * (C(op) * V"OpRecov")^0) / compute; - OpRecov = V"Operand"; - Operand = expect(V"Term", "ExpTerm", Cc(0)); - Term = num + V"Group"; - Group = "(" * V"InnerExp" * expect(")", "MisClose", ""); - InnerExp = expect(V"Exp", "ExpExp", (P(1) - ")")^0 * Cc(0)); -} - -g = expect(g, "NoExp", P(1)^0) * expect(-P(1), "Extra") - -local function eval(input) - local result, label, suffix = g:match(input) - if #errors == 0 then - return result - else - local out = {} - for i, err in ipairs(errors) do - local pos = err[2] - local msg = labels[err[1]][2] - table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") - end - errors = {} - return nil, table.concat(out, "\n") - end -end - -print(eval "98-76*(54/32)") ---> 37.125 - -print(eval "(1+1-1*2/2") ---> syntax error: missing a closing ')' after the expression (at index 11) - -print(eval "(1+)-1*(2/2)") ---> syntax error: expected a term after the operator (at index 4) - -print(eval "(1+1)-1*(/2)") ---> syntax error: expected an expression after the parenthesis (at index 10) - -print(eval "1+(1-(1*2))/2x") ---> syntax error: extra chracters found after the expression (at index 14) - -print(eval "-1+(1-(1*2))/2") ---> syntax error: no expression found (at index 1) - -print(eval "(1+1-1*(2/2+)-():") ---> syntax error: expected a term after the operator (at index 13) ---> syntax error: expected an expression after the parenthesis (at index 16) ---> syntax error: missing a closing ')' after the expression (at index 17) ---> syntax error: extra characters found after the expression (at index 17) diff --git a/examples/recoveryOpLab.lua b/examples/recoveryOpLab.lua deleted file mode 100644 index 6697f8b..0000000 --- a/examples/recoveryOpLab.lua +++ /dev/null @@ -1,107 +0,0 @@ -local lpeg = require"lpeglabel" - -local R, S, P, V = lpeg.R, lpeg.S, lpeg.P, lpeg.V -local C, Cc, Ct, Cmt = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cmt -local T, Lc, Rec = lpeg.T, lpeg.Lc, lpeg.Rec - -local labels = { - {"NoExp", "no expression found"}, - {"Extra", "extra characters found after the expression"}, - {"ExpTerm", "expected a term after the operator"}, - {"ExpExp", "expected an expression after the parenthesis"}, - {"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 = {} - -local function expect(patt, labname) - local i = labelindex(labname) - function recorderror(input, pos) - table.insert(errors, {i, pos}) - return true - end - return patt + Cmt("", recorderror) * T(i) -end - -local num = R("09")^1 / tonumber -local op = 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] - elseif 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 = P { - "Exp", - Exp = Ct(V"Term" * (C(op) * V"OpRecov")^0) / compute; - OpRecov = Rec(V"Operand", Cc(0), labelindex("ExpTerm")); - Operand = expect(V"Term", "ExpTerm"); - Term = num + Rec(V"Group", P"", labelindex("MisClose")); - Group = "(" * Rec(V"InnerExp", (P(1) - ")")^0 * Cc(0), labelindex("ExpExp")) * expect(")", "MisClose"); - InnerExp = expect(V"Exp", "ExpExp"); -} - -g = expect(g, "NoExp") * expect(-P(1), "Extra") - -local function eval(input) - local result, label, suffix = g:match(input) - if #errors == 0 then - return result - else - local out = {} - for i, err in ipairs(errors) do - local pos = err[2] - local msg = labels[err[1]][2] - table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") - end - errors = {} - return nil, table.concat(out, "\n") - end -end - -print(eval "98-76*(54/32)") ---> 37.125 - -print(eval "(1+1-1*2/2") ---> syntax error: missing a closing ')' after the expression (at index 11) - -print(eval "(1+)-1*(2/2)") ---> syntax error: expected a term after the operator (at index 4) - -print(eval "(1+1)-1*(/2)") ---> syntax error: expected an expression after the parenthesis (at index 10) - -print(eval "1+(1-(1*2))/2x") ---> syntax error: extra chracters found after the expression (at index 14) - -print(eval "-1+(1-(1*2))/2") ---> syntax error: no expression found (at index 1) - -print(eval "(1+1-1*(2/2+)-():") ---> syntax error: expected a term after the operator (at index 13) ---> syntax error: expected an expression after the parenthesis (at index 16) ---> syntax error: missing a closing ')' after the expression (at index 17) ---> syntax error: extra characters found after the expression (at index 17) diff --git a/examples/recoveryRecCap.lua b/examples/recoveryRecCap.lua deleted file mode 100644 index c1b3a53..0000000 --- a/examples/recoveryRecCap.lua +++ /dev/null @@ -1,121 +0,0 @@ -local m = require"lpeglabelrec" -local re = require"relabelrec" - -local R, S, P, V = m.R, m.S, m.P, m.V -local C, Cc, Ct, Cmt = m.C, m.Cc, m.Ct, m.Cmt -local T, Rec = m.T, m.Rec - -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, recpatt) - local i = labelindex(labname) - return patt + T(i) -end - - -local num = R("09")^1 / tonumber -local op = 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 = P { - "Exp", - Exp = Ct(V"OperandFirst" * (C(op) * V"Operand")^0) / compute, - OperandFirst = expect(V"Term", "ExpTermFirst"), - Operand = expect(V"Term", "ExpTermOp"), - Term = num + V"Group", - Group = "(" * 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(0) -end - -local recg = P { - "S", - S = Rec(V"A", V"ErrExpTermFirst", labelindex("ExpTermFirst")), -- default value is 0 - A = Rec(V"Sg", V"ErrExpTermOp", labelindex("ExpTermOp")), - Sg = Rec(g, V"ErrMisClose", labelindex("MisClose")), - ErrExpTermFirst = record("ExpTermFirst") * sync(op + ")") * defaultValue(), - ErrExpTermOp = record("ExpTermOp") * sync(op + ")") * defaultValue(), - ErrMisClose = record("MisClose") * sync(P")") * defaultValue(m.P""), -} - - -local function eval(input) - errors = {} - subject = input - local result, label, suffix = recg:match(input) - 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 - return result -end - -print(eval "90-70*5") ---> 20 - -print(eval "2+") ---> 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 "") diff --git a/examples/typedlua/test.lua b/examples/typedlua/test.lua index ed4e7a1..95474ba 100755 --- a/examples/typedlua/test.lua +++ b/examples/typedlua/test.lua @@ -401,15 +401,18 @@ assert(m == e) -- unfinished comments s = [=[ ---[[ testing +--[[ + +testing unfinished + comment -]=] + ]=] --[=[ test.lua:3:1: syntax error, unexpected 'comment', expecting '=', ',', 'String', '{', '(', ':', '[', '.' ]=] e = [=[ -test.lua:1:1: unfinished long comment +test.lua:1:2: unfinished long comment ]=] r, m = parse(s) diff --git a/examples/typedlua/tllexer.lua b/examples/typedlua/tllexer.lua index 6517ba5..d6033ec 100644 --- a/examples/typedlua/tllexer.lua +++ b/examples/typedlua/tllexer.lua @@ -1,6 +1,6 @@ local tllexer = {} -local lpeg = require "lpeglabel" +local lpeg = require "lpeglabelrec" lpeg.locale(lpeg) local tlerror = require "tlerror" @@ -9,10 +9,6 @@ function tllexer.try (pat, label) return pat + lpeg.T(tlerror.labels[label]) end -function tllexer.catch (pat, label) - return lpeg.Lc(pat, lpeg.P(false), tlerror.labels[label]) -end - local function setffp (s, i, t, n) if not t.ffp or i > t.ffp then t.ffp = i @@ -45,7 +41,10 @@ local CloseEQ = lpeg.Cmt(Close * lpeg.Cb("init"), local LongString = Open * (lpeg.P(1) - CloseEQ)^0 * tllexer.try(Close, "LongString") / function (s, o) return s end -local Comment = lpeg.Lc(lpeg.P("--") * LongString / function () return 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 diff --git a/examples/typedlua/tlparser.lua b/examples/typedlua/tlparser.lua index a301fa6..fe4fd5e 100644 --- a/examples/typedlua/tlparser.lua +++ b/examples/typedlua/tlparser.lua @@ -1,6 +1,6 @@ local tlparser = {} -local lpeg = require "lpeglabel" +local lpeg = require "lpeglabelrec" lpeg.locale(lpeg) local tllexer = require "tllexer" diff --git a/testlabel.lua b/testlabel.lua index cb92657..d9bac64 100644 --- a/testlabel.lua +++ b/testlabel.lua @@ -173,6 +173,15 @@ p = m.Rec(#m.T(22), m.P"a", 22) r, l, serror = p:match("bbc") assert(r == nil and l == 0 and serror == "bbc") +p = m.Rec(#m.P("a") * m.T(22), m.T(15), 22) +r, l, serror = p:match("abc") +assert(r == nil and l == 15 and serror == "abc") + +p = m.Rec(#(m.P("a") * m.T(22)), m.T(15), 22) +r, l, serror = p:match("abc") +assert(r == nil and l == 15 and serror == "bc") + + -- tests related to repetition p = m.T(1)^0 -- cgit v1.2.3-55-g6feb From a4bdec34353ad1849f99e6ab0e5f2ad5e74c83b1 Mon Sep 17 00:00:00 2001 From: Sergio Queiroz Date: Tue, 29 Nov 2016 18:38:55 -0300 Subject: New example shows how to build recovery grammar semiautomatically --- examples/expressionRecAut.lua | 132 ++++++++++++++++++++++++++++++++++++++++ examples/expressionRecovery.lua | 3 +- 2 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 examples/expressionRecAut.lua (limited to 'examples') diff --git a/examples/expressionRecAut.lua b/examples/expressionRecAut.lua new file mode 100644 index 0000000..e098078 --- /dev/null +++ b/examples/expressionRecAut.lua @@ -0,0 +1,132 @@ +local m = require"lpeglabelrec" +local re = require"relabelrec" + +local R, S, P, V = m.R, m.S, m.P, m.V +local C, Cc, Ct, Cmt = m.C, m.Cc, m.Ct, m.Cmt +local T, Rec = m.T, m.Rec + +local num = R("09")^1 / tonumber +local op = 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 + 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 = P { + "Exp", + Exp = Ct(V"OperandFirst" * (C(op) * V"Operand")^0) / compute, + OperandFirst = expect(V"Term", "ExpTermFirst"), + Operand = expect(V"Term", "ExpTermOp"), + Term = num + V"Group", + Group = "(" * 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 recg2 = g +for k, v in pairs(labels) do + recg2 = Rec(recg2, record(k) * sync(v.psync) * v.pcap, v.id) +end + +local recg = P { + "S", + S = Rec(V"A", V"ErrExpTermFirst", labels["ExpTermFirst"].id), -- default value is 0 + A = Rec(V"Sg", V"ErrExpTermOp", labels["ExpTermOp"].id), + Sg = Rec(g, V"ErrMisClose", labels["MisClose"].id), + ErrExpTermFirst = record("ExpTermFirst") * sync(op + ")") * defaultValue(), + ErrExpTermOp = record("ExpTermOp") * sync(op + ")") * defaultValue(), + ErrMisClose = record("MisClose") * sync(P")") * defaultValue(m.P""), +} + + +local function eval(input) + errors = {} + subject = input + local result, label, suffix = recg2:match(input) + 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 + return result +end + +print(eval "90-70*5") +--> 20 + +print(eval "2+") +--> 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)") + diff --git a/examples/expressionRecovery.lua b/examples/expressionRecovery.lua index a4a3288..c5cbcca 100644 --- a/examples/expressionRecovery.lua +++ b/examples/expressionRecovery.lua @@ -91,7 +91,6 @@ local function eval(input) for i, err in ipairs(errors) do local pos = err.col local msg = err.msg - print("sub", subject) table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") end print(table.concat(out, "\n")) @@ -123,5 +122,7 @@ print(eval "") print(eval "1+()+") +print(eval "1+(") + print(eval "3)") -- cgit v1.2.3-55-g6feb From 2ea15094a1d4a9f422c983480aab7231951ee20e Mon Sep 17 00:00:00 2001 From: Sergio Queiroz Date: Wed, 7 Dec 2016 08:50:03 -0300 Subject: Renaming files and removing example based on another version --- examples/expRec.lua | 128 ++++++++++++++++++++++++++++++++++++++ examples/expRecAut.lua | 132 ++++++++++++++++++++++++++++++++++++++++ examples/expect.lua | 98 ----------------------------- examples/expressionRecAut.lua | 132 ---------------------------------------- examples/expressionRecovery.lua | 128 -------------------------------------- 5 files changed, 260 insertions(+), 358 deletions(-) create mode 100644 examples/expRec.lua create mode 100644 examples/expRecAut.lua delete mode 100644 examples/expect.lua delete mode 100644 examples/expressionRecAut.lua delete mode 100644 examples/expressionRecovery.lua (limited to 'examples') diff --git a/examples/expRec.lua b/examples/expRec.lua new file mode 100644 index 0000000..c5cbcca --- /dev/null +++ b/examples/expRec.lua @@ -0,0 +1,128 @@ +local m = require"lpeglabelrec" +local re = require"relabelrec" + +local R, S, P, V = m.R, m.S, m.P, m.V +local C, Cc, Ct, Cmt = m.C, m.Cc, m.Ct, m.Cmt +local T, Rec = m.T, m.Rec + +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, recpatt) + local i = labelindex(labname) + return patt + T(i) +end + + +local num = R("09")^1 / tonumber +local op = 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 = P { + "Exp", + Exp = Ct(V"OperandFirst" * (C(op) * V"Operand")^0) / compute, + OperandFirst = expect(V"Term", "ExpTermFirst"), + Operand = expect(V"Term", "ExpTermOp"), + Term = num + V"Group", + Group = "(" * 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 recg = P { + "S", + S = Rec(V"A", V"ErrExpTermFirst", labelindex("ExpTermFirst")), -- default value is 0 + A = Rec(V"Sg", V"ErrExpTermOp", labelindex("ExpTermOp")), + Sg = Rec(g, V"ErrMisClose", labelindex("MisClose")), + ErrExpTermFirst = record("ExpTermFirst") * sync(op + ")") * defaultValue(), + ErrExpTermOp = record("ExpTermOp") * sync(op + ")") * defaultValue(), + ErrMisClose = record("MisClose") * sync(P")") * defaultValue(m.P""), +} + + +local function eval(input) + errors = {} + subject = input + local result, label, suffix = recg:match(input) + 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 + return result +end + +print(eval "90-70*5") +--> 20 + +print(eval "2+") +--> 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)") + diff --git a/examples/expRecAut.lua b/examples/expRecAut.lua new file mode 100644 index 0000000..e098078 --- /dev/null +++ b/examples/expRecAut.lua @@ -0,0 +1,132 @@ +local m = require"lpeglabelrec" +local re = require"relabelrec" + +local R, S, P, V = m.R, m.S, m.P, m.V +local C, Cc, Ct, Cmt = m.C, m.Cc, m.Ct, m.Cmt +local T, Rec = m.T, m.Rec + +local num = R("09")^1 / tonumber +local op = 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 + 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 = P { + "Exp", + Exp = Ct(V"OperandFirst" * (C(op) * V"Operand")^0) / compute, + OperandFirst = expect(V"Term", "ExpTermFirst"), + Operand = expect(V"Term", "ExpTermOp"), + Term = num + V"Group", + Group = "(" * 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 recg2 = g +for k, v in pairs(labels) do + recg2 = Rec(recg2, record(k) * sync(v.psync) * v.pcap, v.id) +end + +local recg = P { + "S", + S = Rec(V"A", V"ErrExpTermFirst", labels["ExpTermFirst"].id), -- default value is 0 + A = Rec(V"Sg", V"ErrExpTermOp", labels["ExpTermOp"].id), + Sg = Rec(g, V"ErrMisClose", labels["MisClose"].id), + ErrExpTermFirst = record("ExpTermFirst") * sync(op + ")") * defaultValue(), + ErrExpTermOp = record("ExpTermOp") * sync(op + ")") * defaultValue(), + ErrMisClose = record("MisClose") * sync(P")") * defaultValue(m.P""), +} + + +local function eval(input) + errors = {} + subject = input + local result, label, suffix = recg2:match(input) + 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 + return result +end + +print(eval "90-70*5") +--> 20 + +print(eval "2+") +--> 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)") + diff --git a/examples/expect.lua b/examples/expect.lua deleted file mode 100644 index cb68d38..0000000 --- a/examples/expect.lua +++ /dev/null @@ -1,98 +0,0 @@ -local lpeg = require"lpeglabel" - -local R, S, P, V, C, Ct, T = lpeg.R, lpeg.S, lpeg.P, lpeg.V, lpeg.C, lpeg.Ct, lpeg.T - --- The `labels` table contains the list of labels that we will be using --- as well as the corresponding error message for each label, which will --- be used in our error reporting later on. -local labels = { - {"NoExp", "no expression found"}, - {"Extra", "extra characters found after the expression"}, - {"ExpTerm", "expected a term after the operator"}, - {"ExpExp", "expected an expression after the parenthesis"}, - {"MisClose", "missing a closing ')' after the expression"}, -} - --- The `expect` function takes a pattern and a label defined in --- the `labels` table and returns a pattern that throws the specified --- label if the original pattern fails to match. --- Note: LPegLabel requires us to use integers for the labels, so we --- use the index of the label in the `labels` table to represent it. -local function expect(patt, labname) - for i, elem in ipairs(labels) do - if elem[1] == labname then - return patt + T(i) - end - end - - error("could not find label: " .. labname) -end - -local num = R("09")^1 / tonumber -local op = S("+-*/") - --- The `compute` function takes an alternating list of numbers and --- operators and computes the result of applying the operations --- to the numbers in a left to right order (no operator precedence). -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] - elseif 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 - --- Our grammar is a simple arithmetic expression of integers that --- does not take operator precedence into account but allows grouping --- via parenthesis. -local g = P { - "Exp", - Exp = Ct(V"Term" * (C(op) * expect(V"Term", "ExpTerm"))^0) / compute; - Term = num + V"Group"; - Group = "(" * expect(V"Exp", "ExpExp") * expect(")", "MisClose"); -} - -g = expect(g, "NoExp") * expect(-P(1), "Extra") - --- The `eval` function takes an input string to match against the grammar --- we've just defined. If the input string matches, then the result of the --- computation is returned, otherwise we return the error message and --- position of the first failure encountered. -local function eval(input) - local result, label, suffix = g:match(input) - if result ~= nil then - return result - else - local pos = input:len() - suffix:len() + 1 - local msg = labels[label][2] - return nil, "syntax error: " .. msg .. " (at index " .. pos .. ")" - end -end - -print(eval "98-76*(54/32)") ---> 37.125 - -print(eval "(1+1-1*2/2") ---> syntax error: missing a closing ')' after the expression (at index 11) - -print(eval "(1+)-1*(2/2)") ---> syntax error: expected a term after the operator (at index 4) - -print(eval "(1+1)-1*(/2)") ---> syntax error: expected an expression after the parenthesis (at index 10) - -print(eval "1+(1-(1*2))/2x") ---> syntax error: extra chracters found after the expression (at index 14) - -print(eval "-1+(1-(1*2))/2") ---> syntax error: no expression found (at index 1) diff --git a/examples/expressionRecAut.lua b/examples/expressionRecAut.lua deleted file mode 100644 index e098078..0000000 --- a/examples/expressionRecAut.lua +++ /dev/null @@ -1,132 +0,0 @@ -local m = require"lpeglabelrec" -local re = require"relabelrec" - -local R, S, P, V = m.R, m.S, m.P, m.V -local C, Cc, Ct, Cmt = m.C, m.Cc, m.Ct, m.Cmt -local T, Rec = m.T, m.Rec - -local num = R("09")^1 / tonumber -local op = 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 + 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 = P { - "Exp", - Exp = Ct(V"OperandFirst" * (C(op) * V"Operand")^0) / compute, - OperandFirst = expect(V"Term", "ExpTermFirst"), - Operand = expect(V"Term", "ExpTermOp"), - Term = num + V"Group", - Group = "(" * 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 recg2 = g -for k, v in pairs(labels) do - recg2 = Rec(recg2, record(k) * sync(v.psync) * v.pcap, v.id) -end - -local recg = P { - "S", - S = Rec(V"A", V"ErrExpTermFirst", labels["ExpTermFirst"].id), -- default value is 0 - A = Rec(V"Sg", V"ErrExpTermOp", labels["ExpTermOp"].id), - Sg = Rec(g, V"ErrMisClose", labels["MisClose"].id), - ErrExpTermFirst = record("ExpTermFirst") * sync(op + ")") * defaultValue(), - ErrExpTermOp = record("ExpTermOp") * sync(op + ")") * defaultValue(), - ErrMisClose = record("MisClose") * sync(P")") * defaultValue(m.P""), -} - - -local function eval(input) - errors = {} - subject = input - local result, label, suffix = recg2:match(input) - 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 - return result -end - -print(eval "90-70*5") ---> 20 - -print(eval "2+") ---> 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)") - diff --git a/examples/expressionRecovery.lua b/examples/expressionRecovery.lua deleted file mode 100644 index c5cbcca..0000000 --- a/examples/expressionRecovery.lua +++ /dev/null @@ -1,128 +0,0 @@ -local m = require"lpeglabelrec" -local re = require"relabelrec" - -local R, S, P, V = m.R, m.S, m.P, m.V -local C, Cc, Ct, Cmt = m.C, m.Cc, m.Ct, m.Cmt -local T, Rec = m.T, m.Rec - -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, recpatt) - local i = labelindex(labname) - return patt + T(i) -end - - -local num = R("09")^1 / tonumber -local op = 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 = P { - "Exp", - Exp = Ct(V"OperandFirst" * (C(op) * V"Operand")^0) / compute, - OperandFirst = expect(V"Term", "ExpTermFirst"), - Operand = expect(V"Term", "ExpTermOp"), - Term = num + V"Group", - Group = "(" * 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 recg = P { - "S", - S = Rec(V"A", V"ErrExpTermFirst", labelindex("ExpTermFirst")), -- default value is 0 - A = Rec(V"Sg", V"ErrExpTermOp", labelindex("ExpTermOp")), - Sg = Rec(g, V"ErrMisClose", labelindex("MisClose")), - ErrExpTermFirst = record("ExpTermFirst") * sync(op + ")") * defaultValue(), - ErrExpTermOp = record("ExpTermOp") * sync(op + ")") * defaultValue(), - ErrMisClose = record("MisClose") * sync(P")") * defaultValue(m.P""), -} - - -local function eval(input) - errors = {} - subject = input - local result, label, suffix = recg:match(input) - 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 - return result -end - -print(eval "90-70*5") ---> 20 - -print(eval "2+") ---> 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)") - -- cgit v1.2.3-55-g6feb From 2f1e173c3d7670f802a087cd2c80afc5b0ed23c3 Mon Sep 17 00:00:00 2001 From: sergio Date: Fri, 9 Dec 2016 10:50:34 -0300 Subject: Updating documentantion and polishing examples --- README.md | 542 +++++++++++++++++++++++++++-------------------- examples/expRec.lua | 50 ++--- examples/expRecAut.lua | 52 ++--- examples/listId2Rec2.lua | 2 +- examples/listIdRe2.lua | 31 ++- 5 files changed, 376 insertions(+), 301 deletions(-) (limited to 'examples') diff --git a/README.md b/README.md index 5e27796..9bc162d 100644 --- a/README.md +++ b/README.md @@ -37,13 +37,13 @@ Below there is a brief summary of the new functions provided by LpegLabel: FunctionDescription lpeglabelrec.T (l) Throws a label l to signal an error -lpeglabelrec.Rec (p1, p2, l1, [l2, ..., ln]) +lpeglabelrec.Rec (p1, p2, l1 [, l2, ..., ln]) Specifies a recovery pattern p2 for p1, when the matching of p1 gives one of the labels l1, ..., ln. %{l} Syntax of relabelrec module. Equivalent to lpeglabelrec.T(l) -p1 //{l1, ..., ln} p2 +p1 //{l1 [, l2, ..., ln} p2 Syntax of relabelrec module. Equivalent to lpeglabelrec.Rec(p1, p2, l1, ..., ln) relabelrec.calcline(subject, i) @@ -173,41 +173,38 @@ By using the `Rec` function we can specify a recovery pattern that should be matched when a label is thrown. After matching the recovery pattern, and possibly recording the error, the parser will resume the regular matching. For example, in the example below -we expect to match rule `A`, but in case label 42 is thrown -then we will try to match `recp`: +we expect to match rule `A`, but when a failure occur the label 42 +is thrown and then we will try to match the recovery pattern `recp`: ```lua local m = require'lpeglabelrec' local recp = m.P"oast" local g = m.P{ - "S", - S = m.Rec(m.V"A", recp, 42) * ".", - A = m.P"t" * (m.P("est") + m.T(42)) + "S", + S = m.Rec(m.V"A", recp, 42) * ".", + A = m.P"t" * (m.P"est" + m.T(42)) } print(g:match("test.")) --> 6 - print(g:match("toast.")) --> 7 - -print(g:match("oast.")) --> nil 0 oast. - -print(g:match("toward.")) --> nil 0 ward. +print(g:match("oast.")) --> nil 0 oast. +print(g:match("toward.")) --> nil 0 ward. ``` -When trying to match 'toast.', in rule `A` the first -'t' is matched, and then label 42 is thrown, with the associated -inpux suffix 'oast.'. In rule `S` this label is caught -and the recovery pattern matches 'oast', so pattern `'.'` -matches the rest of the input. +When trying to match subject 'toast.', in rule `A` the first +'t' is matched, then the matching of `m.P"est"` fails and label 42 +is thrown, with the associated inpux suffix 'oast.'. In rule +`S` label 42 is caught and the recovery pattern matches 'oast', +so pattern `'.'` matches the rest of the input. -When matching 'oast.', pattern `m.P"t"` fails, and -the result of the matching is nil, 0, oast.. +When matching subject 'oast.', pattern `m.P"t"` fails, and +the result of the matching is nil, 0, oast.. -When matching 'toward.', label 42 is throw, with the associated -input suffix 'oward.'. The matching of the recovery pattern fails to, -so the result of the matching is nil, 0, ward.. +When matching 'toward.', label 42 is thrown after matching 't', +with the associated input suffix 'oward.'. As the matching of the +recovery pattern fails, the result is nil, 0, ward.. -Usually, the recovery pattern is an expression that never fails. +Usually, the recovery pattern is an expression that does not fail. In the previous example, we could have used `(m.P(1) - m.P".")^0` as the recovery pattern. @@ -216,11 +213,14 @@ to use a recovery strategy. Grammar `g` remains the same, but we add a recovery grammar `grec` that handles the labels thrown by `g`. In grammar `grec` we use functions `record` and `sync`. -Function `record` gives us a pattern that captures two -values: the current subject position (where a label was thrown) -and the label itself. These values will be used to record -all the errors found. Function `sync` give us synchronization -pattern, that macthes the input +Function `record`, plus function `recorderror`, will help +us to save the input position where a label was thrown, +while function `sync` will give us a synchronization pattern, +that consumes the input while is not possible to match a given +pattern `p`. + +When the matching of an identifier fails, a defaul value ('NONE') +is provided. ```lua local m = require'lpeglabelrec' @@ -266,8 +266,8 @@ end local grec = m.P{ "S", S = m.Rec(m.Rec(g, m.V"ErrComma", errComma), m.V"ErrId", errId), - ErrComma = record(errComma) * sync(-m.P(1) + id), - ErrId = record(errId) * sync(-m.P(1) + ",") + ErrComma = record(errComma) * sync(id), + ErrId = record(errId) * sync(m.P",") } @@ -281,58 +281,41 @@ function mymatch (g, s) local msg = "Error at line " .. err.line .. " (col " .. err.col .. "): " .. err.msg table.insert(out, msg) end - return nil, table.concat(out, "\n") + return nil, table.concat(out, "\n") .. "\n" end return r end print(mymatch(grec, "one,two")) +-- Captures (separated by ';'): one; two; +-- Syntactic errors found: 0 + print(mymatch(grec, "one two three")) +-- Captures (separated by ';'): one; two; three; +-- Syntactic errors found: 2 +-- Error at line 1 (col 4): expecting ',' +-- Error at line 1 (col 8): expecting ',' + print(mymatch(grec, "1,\n two, \n3,")) +-- Captures (separated by ';'): NONE; two; NONE; NONE; +-- Syntactic errors found: 3 +-- Error at line 1 (col 1): expecting an identifier +-- Error at line 2 (col 6): expecting an identifier +-- Error at line 3 (col 2): expecting an identifier + print(mymatch(grec, "one\n two123, \nthree,")) +-- Captures (separated by ';'): one; two; three; NONE; +-- Syntactic errors found: 3 +-- Error at line 2 (col 1): expecting ',' +-- Error at line 2 (col 5): expecting ',' +-- Error at line 3 (col 6): expecting an identifier ``` - - ##### *relabelrec* syntax -Now we rewrite the previous example using the syntax -supported by *relabelrec*: - -```lua -local re = require 'relabelrec' - -local g = re.compile[[ - S <- Id List - List <- !. / (',' / %{2}) (Id / %{1}) List - Id <- Sp [a-z]+ - Comma <- Sp ',' - 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")) --> 8 -print(mymatch(g, "one two")) --> nil Error at line 1 (col 3): expecting ',' before ' two' -print(mymatch(g, "one,\n two,\nthree,")) --> nil Error at line 3 (col 6): expecting an identifier before '' -``` - -With the help of function *setlabels* we can also rewrite the previous example to use -mnemonic labels instead of plain numbers: +Below we describe again a grammar that matches a list of identifiers, +now using the syntax supported by *relabelrec*, where `//{}` is the +recovery operator, and `%{}` is the throw operator: ```lua local re = require 'relabelrec' @@ -355,64 +338,124 @@ re.setlabels(labels) local g = re.compile[[ S <- Id List - List <- !. / (',' / %{errComma}) (Id / %{errId}) List - Id <- Sp [a-z]+ - Comma <- Sp ',' + 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) - 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 .. errmsgs[e] .. " before '" .. sfail .. "'" + 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 -print(mymatch(g, "one,two")) --> 8 -print(mymatch(g, "one two")) --> nil Error at line 1 (col 3): expecting ',' before ' two' -print(mymatch(g, "one,\n two,\nthree,")) --> nil Error at line 3 (col 6): expecting an identifier before '' -``` - +print(mymatch(grec, "one,two")) +-- Captures (separated by ';'): one; two; +-- Syntactic errors found: 0 +print(mymatch(grec, "one two three")) +-- Captures (separated by ';'): one; two; three; +-- Syntactic errors found: 2 +-- Error at line 1 (col 4): expecting ',' +-- Error at line 1 (col 8): expecting ',' +print(mymatch(grec, "1,\n two, \n3,")) +-- Captures (separated by ';'): NONE; two; NONE; NONE; +-- Syntactic errors found: 3 +-- Error at line 1 (col 1): expecting an identifier +-- Error at line 2 (col 6): expecting an identifier +-- Error at line 3 (col 2): expecting an identifier +print(mymatch(grec, "one\n two123, \nthree,")) +-- Captures (separated by ';'): one; two; three; NONE; +-- Syntactic errors found: 3 +-- Error at line 2 (col 1): expecting ',' +-- Error at line 2 (col 5): expecting ',' +-- Error at line 3 (col 6): expecting an identifier +``` #### Arithmetic Expressions -Here's an example of an LPegLabel grammar that make its own function called -'expect', which takes a pattern and a label as parameters and throws the label -if the pattern fails to be matched. This function can be extended later on to -record all errors encountered once error recovery is implemented. +Here's an example of an LPegLabel grammar that matches an expression. +We have used a function `expect`, that takes a pattern `patt` and a label as +parameters and builds a new pattern that throws this label when `patt` +fails. -```lua -local lpeg = require"lpeglabel" +When a subexpression is syntactically invalid, a default value of 1000 +is provided by the recovery pattern, so the evaluation of an expression +should always produce a numeric value. -local R, S, P, V, C, Ct, T = lpeg.R, lpeg.S, lpeg.P, lpeg.V, lpeg.C, lpeg.Ct, lpeg.T +In this example, we can see that it may be a tedious and error prone +task to build manually the recovery grammar `grec`. In the next example +we will show how to build the recovery grammar in a more automatic way. + +```lua +local m = require"lpeglabelrec" +local re = require"relabelrec" local labels = { - {"NoExp", "no expression found"}, - {"Extra", "extra characters found after the expression"}, - {"ExpTerm", "expected a term after the operator"}, - {"ExpExp", "expected an expression after the parenthesis"}, + {"ExpTermFirst", "expected an expression"}, + {"ExpTermOp", "expected a term after the operator"}, {"MisClose", "missing a closing ')' after the expression"}, } -local function expect(patt, labname) +local function labelindex(labname) for i, elem in ipairs(labels) do if elem[1] == labname then - return patt + T(i) + return i end end - error("could not find label: " .. labname) end -local num = R("09")^1 / tonumber -local op = S("+-*/") +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] @@ -421,10 +464,6 @@ local function compute(tokens) result = result + tokens[i+1] elseif tokens[i] == '-' then result = result - tokens[i+1] - elseif tokens[i] == '*' then - result = result * tokens[i+1] - elseif tokens[i] == '/' then - result = result / tokens[i+1] else error('unknown operation: ' .. tokens[i]) end @@ -432,128 +471,128 @@ local function compute(tokens) return result end -local g = P { +local g = m.P { "Exp", - Exp = Ct(V"Term" * (C(op) * expect(V"Term", "ExpTerm"))^0) / compute; - Term = num + V"Group"; - Group = "(" * expect(V"Exp", "ExpExp") * expect(")", "MisClose"); + 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"), } -g = expect(g, "NoExp") * expect(-P(1), "Extra") - -local function eval(input) - local result, label, suffix = g:match(input) - if result ~= nil then - return result - else - local pos = input:len() - suffix:len() + 1 - local msg = labels[label][2] - return nil, "syntax error: " .. msg .. " (at index " .. pos .. ")" - end +function recorderror(pos, lab) + local line, col = re.calcline(subject, pos) + table.insert(errors, { line = line, col = col, msg = labels[lab][2] }) end -print(eval "98-76*(54/32)") ---> 37.125 - -print(eval "(1+1-1*2/2") ---> syntax error: missing a closing ')' after the expression (at index 11) - -print(eval "(1+)-1*(2/2)") ---> syntax error: expected a term after the operator (at index 4) - -print(eval "(1+1)-1*(/2)") ---> syntax error: expected an expression after the parenthesis (at index 10) - -print(eval "1+(1-(1*2))/2x") ---> syntax error: extra chracters found after the expression (at index 14) - -print(eval "-1+(1-(1*2))/2") ---> syntax error: no expression found (at index 1) -``` - -#### Catching labels - -When a label is thrown, the grammar itself can handle this label -by using the labeled ordered choice. Below we rewrite the example -of the list of identifiers to show this feature: - - -```lua -local m = require'lpeglabel' - -local terror = {} +function record (labname) + return (m.Cp() * m.Cc(labelindex(labname))) / recorderror +end -local function newError(s) - table.insert(terror, s) - return #terror +function sync (p) + return (-p * m.P(1))^0 end -local errUndef = newError("undefined") -local errId = newError("expecting an identifier") -local errComma = newError("expecting ','") +function defaultValue (p) + return p or m.Cc(1000) +end -local g = m.P{ +local grec = m.P { "S", - S = m.Lc(m.Lc(m.V"Id" * m.V"List", m.V"ErrId", errId), - m.V"ErrComma", errComma), - List = -m.P(1) + (m.V"Comma" + m.T(errComma)) * (m.V"Id" + m.T(errId)) * m.V"List", - Id = m.V"Sp" * m.R'az'^1, - Comma = m.V"Sp" * ",", - Sp = m.S" \n\t"^0, - ErrId = m.Cc(errId) / terror, - ErrComma = m.Cc(errComma) / terror + S = m.Rec(m.V"A", m.V"ErrExpTermFirst", labelindex("ExpTermFirst")), + 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(m.match(g, "one,two")) --> 8 -print(m.match(g, "one two")) --> expecting ',' -print(m.match(g, "one,\n two,\nthree,")) --> expecting an identifier +print(eval "90-70-(5)+3") +-- Syntactic errors found: 0 +-- Result = 18 + +print(eval "15+") +-- Syntactic errors found: 1 +-- syntax error: expected a term after the operator (at index 3) +-- Result = 1015 + +print(eval "-2") +-- Syntactic errors found: 1 +-- syntax error: expected an expression (at index 1) +-- Result = 998 + +print(eval "1+()+") +-- Syntactic errors found: 2 +-- syntax error: expected an expression (at index 4) +-- syntax error: expected a term after the operator (at index 5) +-- Result = 2001 + +print(eval "1+(") +-- Syntactic errors found: 2 +-- syntax error: expected an expression (at index 3) +-- syntax error: missing a closing ')' after the expression (at index 3) +-- Result = 1001 + +print(eval "3)") +-- Syntactic errors found: 0 +-- Result = 3 ``` -#### Error Recovery +#### Automatically Building the Recovery Grammar -By using labeled ordered choice or the recovery operator, when a label -is thrown, the parser may record the error and still continue parsing -to find more errors. We can even record the error right away without -actually throwing a label (relying on the regular PEG failure instead). -Below we rewrite the arithmetic expression example and modify -the `expect` function to use the recovery operator for error recovery: +Below we rewrite the previous example to automatically +build the recovery grammar based on information provided +by the user for each label (error message, recovery pattern, etc). +In the example below we also throw an error when the grammar +does not match the whole subject. ```lua -local lpeg = require"lpeglabel" +local m = require"lpeglabelrec" +local re = require"relabelrec" -local R, S, P, V = lpeg.R, lpeg.S, lpeg.P, lpeg.V -local C, Cc, Ct, Cmt, Carg = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cmt, lpeg.Carg -local T, Lc, Rec = lpeg.T, lpeg.Lc, lpeg.Rec +local num = m.R("09")^1 / tonumber +local op = m.S("+-") -local labels = { - {"NoExp", "no expression found"}, - {"Extra", "extra characters found after the expression"}, - {"ExpTerm", "expected a term after the operator"}, - {"ExpExp", "expected an expression after the parenthesis"}, - {"MisClose", "missing a closing ')' after the expression"}, -} +local labels = {} +local nlabels = 0 -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) +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 -local function expect(patt, labname, recpatt) - local i = labelindex(labname) - local function recorderror(input, pos, errors) - table.insert(errors, {i, pos}) - return true - end - if not recpatt then recpatt = P"" end - return Rec(patt, Cmt(Carg(1), recorderror) * recpatt) -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 num = R("09")^1 / tonumber -local op = S("+-*/") +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] @@ -562,10 +601,6 @@ local function compute(tokens) result = result + tokens[i+1] elseif tokens[i] == '-' then result = result - tokens[i+1] - elseif tokens[i] == '*' then - result = result * tokens[i+1] - elseif tokens[i] == '/' then - result = result / tokens[i+1] else error('unknown operation: ' .. tokens[i]) end @@ -573,43 +608,84 @@ local function compute(tokens) return result end - -local g = P { +local g = m.P { "Exp", - Exp = Ct(V"Term" * (C(op) * V"Operand")^0) / compute; - Operand = expect(V"Term", "ExpTerm", Cc(0)); - Term = num + V"Group"; - Group = "(" * V"InnerExp" * expect(")", "MisClose"); - InnerExp = expect(V"Exp", "ExpExp", (P(1) - ")")^0 * Cc(0)); + 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"), } -g = expect(g, "NoExp", P(1)^0) * expect(-P(1), "Extra") +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) - local errors = {} - local result, label, suffix = g:match(input, 1, errors) - if #errors == 0 then - return result - else + 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[2] - local msg = labels[err[1]][2] + local pos = err.col + local msg = err.msg table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") end - return nil, table.concat(out, "\n") + print(table.concat(out, "\n")) end + io.write("Result = ") + return result end -print(eval "98-76*(54/32)") ---> 37.125 - -print(eval "-1+(1-(1*2))/2") ---> syntax error: no expression found (at index 1) - -print(eval "(1+1-1*(2/2+)-():") ---> syntax error: expected a term after the operator (at index 13) ---> syntax error: expected an expression after the parenthesis (at index 16) ---> syntax error: missing a closing ')' after the expression (at index 17) ---> syntax error: extra characters found after the expression (at index 17) +print(eval "90-70-(5)+3") +-- Syntactic errors found: 0 +-- Result = 18 + +print(eval "15+") +-- Syntactic errors found: 1 +-- syntax error: expected a term after the operator (at index 3) +-- Result = 1015 + +print(eval "-2") +-- Syntactic errors found: 1 +-- syntax error: expected an expression (at index 1) +-- Result = 998 + +print(eval "1+()+") +-- Syntactic errors found: 2 +-- syntax error: expected an expression (at index 4) +-- syntax error: expected a term after the operator (at index 5) +-- Result = 2001 + +print(eval "1+(") +-- Syntactic errors found: 2 +-- syntax error: expected an expression (at index 3) +-- syntax error: missing a closing ')' after the expression (at index 3) +-- Result = 1001 + +print(eval "3)") +-- Syntactic errors found: 1 +-- syntax error: extra characters found after the expression (at index 2) +-- Result = 3 ``` diff --git a/examples/expRec.lua b/examples/expRec.lua index c5cbcca..5c5fd7d 100644 --- a/examples/expRec.lua +++ b/examples/expRec.lua @@ -1,10 +1,6 @@ local m = require"lpeglabelrec" local re = require"relabelrec" -local R, S, P, V = m.R, m.S, m.P, m.V -local C, Cc, Ct, Cmt = m.C, m.Cc, m.Ct, m.Cmt -local T, Rec = m.T, m.Rec - local labels = { {"ExpTermFirst", "expected an expression"}, {"ExpTermOp", "expected a term after the operator"}, @@ -22,14 +18,14 @@ end local errors, subject -local function expect(patt, labname, recpatt) +local function expect(patt, labname) local i = labelindex(labname) - return patt + T(i) + return patt + m.T(i) end -local num = R("09")^1 / tonumber -local op = S("+-") +local num = m.R("09")^1 / tonumber +local op = m.S("+-") local function compute(tokens) local result = tokens[1] @@ -45,13 +41,13 @@ local function compute(tokens) return result end -local g = P { +local g = m.P { "Exp", - Exp = Ct(V"OperandFirst" * (C(op) * V"Operand")^0) / compute, - OperandFirst = expect(V"Term", "ExpTermFirst"), - Operand = expect(V"Term", "ExpTermOp"), - Term = num + V"Group", - Group = "(" * V"Exp" * expect(")", "MisClose"), + 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) @@ -71,22 +67,23 @@ function defaultValue (p) return p or m.Cc(1000) end -local recg = P { +local grec = m.P { "S", - S = Rec(V"A", V"ErrExpTermFirst", labelindex("ExpTermFirst")), -- default value is 0 - A = Rec(V"Sg", V"ErrExpTermOp", labelindex("ExpTermOp")), - Sg = Rec(g, V"ErrMisClose", labelindex("MisClose")), + 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(P")") * defaultValue(m.P""), + 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 = recg:match(input) - if #errors > 0 then + 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 @@ -95,13 +92,14 @@ local function eval(input) end print(table.concat(out, "\n")) end + io.write("Result = ") return result end -print(eval "90-70*5") +print(eval "90-70-(5)+3") --> 20 -print(eval "2+") +print(eval "15+") --> 2 + 0 print(eval "-2") @@ -126,3 +124,5 @@ print(eval "1+(") print(eval "3)") +print(eval "11+())3") + diff --git a/examples/expRecAut.lua b/examples/expRecAut.lua index e098078..f870d73 100644 --- a/examples/expRecAut.lua +++ b/examples/expRecAut.lua @@ -1,12 +1,8 @@ local m = require"lpeglabelrec" local re = require"relabelrec" -local R, S, P, V = m.R, m.S, m.P, m.V -local C, Cc, Ct, Cmt = m.C, m.Cc, m.Ct, m.Cmt -local T, Rec = m.T, m.Rec - -local num = R("09")^1 / tonumber -local op = S("+-") +local num = m.R("09")^1 / tonumber +local op = m.S("+-") local labels = {} local nlabels = 0 @@ -27,7 +23,7 @@ local errors, subject local function expect(patt, labname) local i = labels[labname].id - return patt + T(i) + return patt + m.T(i) end local function compute(tokens) @@ -44,13 +40,13 @@ local function compute(tokens) return result end -local g = P { +local g = m.P { "Exp", - Exp = Ct(V"OperandFirst" * (C(op) * V"Operand")^0) / compute, - OperandFirst = expect(V"Term", "ExpTermFirst"), - Operand = expect(V"Term", "ExpTermOp"), - Term = num + V"Group", - Group = "(" * V"Exp" * expect(")", "MisClose"), + 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) @@ -70,27 +66,18 @@ function defaultValue (p) return p or m.Cc(1000) end -local recg2 = g +local grec = g * expect(m.P(-1), "Extra") for k, v in pairs(labels) do - recg2 = Rec(recg2, record(k) * sync(v.psync) * v.pcap, v.id) + grec = m.Rec(grec, record(k) * sync(v.psync) * v.pcap, v.id) end -local recg = P { - "S", - S = Rec(V"A", V"ErrExpTermFirst", labels["ExpTermFirst"].id), -- default value is 0 - A = Rec(V"Sg", V"ErrExpTermOp", labels["ExpTermOp"].id), - Sg = Rec(g, V"ErrMisClose", labels["MisClose"].id), - ErrExpTermFirst = record("ExpTermFirst") * sync(op + ")") * defaultValue(), - ErrExpTermOp = record("ExpTermOp") * sync(op + ")") * defaultValue(), - ErrMisClose = record("MisClose") * sync(P")") * defaultValue(m.P""), -} - - local function eval(input) errors = {} + io.write("Input: ", input, "\n") subject = input - local result, label, suffix = recg2:match(input) - if #errors > 0 then + 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 @@ -99,13 +86,14 @@ local function eval(input) end print(table.concat(out, "\n")) end + io.write("Result = ") return result end -print(eval "90-70*5") ---> 20 +print(eval "90-70-(5)+3") +--> 18 -print(eval "2+") +print(eval "15+") --> 2 + 0 print(eval "-2") @@ -130,3 +118,5 @@ print(eval "1+(") print(eval "3)") +print(eval "11+()3") +--> 1 + ([0]) [+] 3 + [0] diff --git a/examples/listId2Rec2.lua b/examples/listId2Rec2.lua index ab8f1dd..c6705dd 100644 --- a/examples/listId2Rec2.lua +++ b/examples/listId2Rec2.lua @@ -56,7 +56,7 @@ function mymatch (g, s) local msg = "Error at line " .. err.line .. " (col " .. err.col .. "): " .. err.msg table.insert(out, msg) end - return nil, table.concat(out, "\n") + return nil, table.concat(out, "\n") .. "\n" end return r end diff --git a/examples/listIdRe2.lua b/examples/listIdRe2.lua index 070bcdb..6bab6ba 100644 --- a/examples/listIdRe2.lua +++ b/examples/listIdRe2.lua @@ -19,7 +19,7 @@ re.setlabels(labels) local g = re.compile[[ S <- Id List List <- !. / Comma Id List - Id <- Sp [a-z]+ / %{errId} + Id <- Sp {[a-z]+} / %{errId} Comma <- Sp ',' / %{errComma} Sp <- %s* ]] @@ -38,25 +38,34 @@ end local grec = re.compile( "S <- %g //{errComma} ErrComma //{errId} ErrId" .. "\n" .. - "ErrComma <- ('' -> 'errComma' => recorderror) " .. sync('!. / [a-z]+') .. "\n" .. - "ErrId <- ('' -> 'errId' => recorderror) (!(!. / ',') .)*" - , {g = g, recorderror = recorderror}) + "ErrComma <- ('' -> 'errComma' => recorderror) " .. sync('[a-z]+') .. "\n" .. + "ErrId <- ('' -> 'errId' => recorderror) " .. sync('","') .. "-> default" + , {g = g, recorderror = recorderror, default = "NONE"}) function mymatch (g, s) errors = {} - local r, e, sfail = g:match(s) + 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 - return nil, table.concat(out, "\n") + io.write(table.concat(out, "\n")) end - return r + print("\n") + 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,")) +mymatch(grec, "one,two") +mymatch(grec, "one two three") +mymatch(grec, "1,\n two, \n3,") +mymatch(grec, "one\n two123, \nthree,") -- cgit v1.2.3-55-g6feb From 1322d612d72ac658f2aa443dca94954b819c0993 Mon Sep 17 00:00:00 2001 From: Sergio Queiroz Date: Tue, 13 Dec 2016 13:30:36 -0300 Subject: Removing example "recovery.lua" --- examples/recovery.lua | 134 -------------------------------------------------- 1 file changed, 134 deletions(-) delete mode 100644 examples/recovery.lua (limited to 'examples') diff --git a/examples/recovery.lua b/examples/recovery.lua deleted file mode 100644 index bb17b54..0000000 --- a/examples/recovery.lua +++ /dev/null @@ -1,134 +0,0 @@ -local lpeg = require"lpeglabelrec" - -local R, S, P, V = lpeg.R, lpeg.S, lpeg.P, lpeg.V -local C, Cc, Ct, Cmt = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cmt -local T, Lc = lpeg.T, lpeg.Lc - --- The `labels` table contains the list of labels that we will be using --- as well as the corresponding error message for each label, which will --- be used in our error reporting later on. -local labels = { - {"NoExp", "no expression found"}, - {"Extra", "extra characters found after the expression"}, - {"ExpTerm", "expected a term after the operator"}, - {"ExpExp", "expected an expression after the parenthesis"}, - {"MisClose", "missing a closing ')' after the expression"}, -} - --- The `labelindex` function gives us the index of a label in the --- `labels` table, which serves as the integer representation of the label. --- We need this because LPegLabel requires us to use integers for the labels. -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 - --- The `errors` table will hold the list of errors recorded during parsing -local errors = {} - --- The `expect` function takes a pattern and a label and returns a pattern --- that throws the specified label if the original pattern fails to match. --- Before throwing the label, it records the label to be thrown along with --- the position of the failure (index in input string) into the `errors` table. -local function expect(patt, labname) - local i = labelindex(labname) - function recorderror(input, pos) - table.insert(errors, {i, pos}) - return true - end - return patt + Cmt("", recorderror) * T(i) -end - -local num = R("09")^1 / tonumber -local op = S("+-*/") - --- The `compute` function takes an alternating list of numbers and --- operators and computes the result of applying the operations --- to the numbers in a left to right order (no operator precedence). -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] - elseif 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 - --- Our grammar is a simple arithmetic expression of integers that --- does not take operator precedence into account but allows grouping --- via parenthesis. We have incorporated some error recovery startegies --- to our grammar so that it may resume parsing even after encountering --- an error, which allows us to report more errors. -local g = P { - "Exp", - Exp = Ct(V"Term" * (C(op) * V"OpRecov")^0) / compute; - -- `OpRecov` handles missing terms/operands by returning a dummy (zero). - OpRecov = Lc(V"Operand", Cc(0), labelindex("ExpTerm")); - Operand = expect(V"Term", "ExpTerm"); - Term = num + V"Group"; - -- `Group` handles missing closing parenthesis by simply ignoring it. - -- Like all the others, the error is still recorded of course. - Group = "(" * V"InnerExp" * Lc(expect(")", "MisClose"), P"", labelindex("MisClose")); - -- `InnerExp` handles missing expressions by skipping to the next closing - -- parenthesis. A dummy (zero) is returned in place of the expression. - InnerExp = Lc(expect(V"Exp", "ExpExp"), (P(1) - ")")^0 * Cc(0), labelindex("ExpExp")); -} - -g = expect(g, "NoExp") * expect(-P(1), "Extra") - --- The `eval` function takes an input string to match against the grammar --- we've just defined. If the input string matches, then the result of the --- computation is returned, otherwise we return the error messages and --- positions of all the failures encountered. -local function eval(input) - local result, label, suffix = g:match(input) - if #errors == 0 then - return result - else - local out = {} - for i, err in ipairs(errors) do - local pos = err[2] - local msg = labels[err[1]][2] - table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") - end - errors = {} - return nil, table.concat(out, "\n") - end -end - -print(eval "98-76*(54/32)") ---> 37.125 - -print(eval "(1+1-1*2/2") ---> syntax error: missing a closing ')' after the expression (at index 11) - -print(eval "(1+)-1*(2/2)") ---> syntax error: expected a term after the operator (at index 4) - -print(eval "(1+1)-1*(/2)") ---> syntax error: expected an expression after the parenthesis (at index 10) - -print(eval "1+(1-(1*2))/2x") ---> syntax error: extra chracters found after the expression (at index 14) - -print(eval "-1+(1-(1*2))/2") ---> syntax error: no expression found (at index 1) - -print(eval "(1+1-1*(2/2+)-():") ---> syntax error: expected a term after the operator (at index 13) ---> syntax error: expected an expression after the parenthesis (at index 16) ---> syntax error: missing a closing ')' after the expression (at index 17) ---> syntax error: extra characters found after the expression (at index 17) -- cgit v1.2.3-55-g6feb