From 19119a91005506ec2133948f3a127e68b6e93f30 Mon Sep 17 00:00:00 2001 From: Sérgio Queiroz Date: Fri, 29 Dec 2017 13:51:36 -0300 Subject: Updating the documentation --- README.md | 766 ++++-------- examples/listId2.lua | 16 +- examples/listId2Rec2Cap.lua | 20 +- examples/listId3.lua | 35 + examples/tiny.lua | 5 +- examples/toast.lua | 16 + examples/typedlua/test.lua | 2572 ---------------------------------------- examples/typedlua/tlerror.lua | 66 -- examples/typedlua/tllexer.lua | 105 -- examples/typedlua/tlp.lua | 20 - examples/typedlua/tlparser.lua | 245 ---- 11 files changed, 314 insertions(+), 3552 deletions(-) create mode 100644 examples/listId3.lua create mode 100644 examples/toast.lua delete mode 100755 examples/typedlua/test.lua delete mode 100644 examples/typedlua/tlerror.lua delete mode 100644 examples/typedlua/tllexer.lua delete mode 100644 examples/typedlua/tlp.lua delete mode 100644 examples/typedlua/tlparser.lua diff --git a/README.md b/README.md index b8595ad..88b4fc3 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ patterns of LPeg. Besides that, LPegLabel also reports the farthest failure position in case of an ordinary failure -(which is represented by label **0**). +(which is represented by label **fail**). This document describes the new functions available in LpegLabel and presents some examples of usage. @@ -27,13 +27,13 @@ between an ordinary failure and an error. Usually, an ordinary failure is produced when the matching of a character fails, and this failure is caught by ordered choice. An error (a non-ordinary failure), by its turn, is produced -by the throw operator and may be caught by the recovery operator. +by the throw operator and may be caught by a recovery rule. In LPegLabel, the result of an unsuccessful matching is a triple **nil, lab, errpos**, where **lab** -is the label associated with the failure, and -**errpos** is the input position being matched when -**lab** was thrown. +is the label associated with the failure (a string or +an integer), and **errpos** is the input position being +matched when **lab** was thrown. When **lab** is an ordinary failure and no error was thrown before, **errpos** is the farthest position where an ordinary failure occurred. @@ -47,31 +47,15 @@ Below there is a brief summary of the new functions provided by LpegLabel: FunctionDescription lpeglabel.T (l) Throws a label l to signal an error -lpeglabel.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. -lpeglabel.Lc (p1, p2, l1, ..., ln) - Matches p1 and tries to match p2 - if the matching of p1 gives one of l1, ..., ln - %{l} Syntax of relabel module. Equivalent to lpeglabel.T(l) p^l Syntax sugar available at relabel for p / %{l} -p1 //{l1 [, l2, ..., ln} p2 - Syntax of relabel module. Equivalent to lpeglabel.Rec(p1, p2, l1, ..., ln) - -p1 /{l1, ..., ln} p2 - Syntax of relabel module. Equivalent to lpeg.Lc(p1, p2, l1, ..., ln) - relabel.calcline(subject, i) Calculates line and column information regarding position i of the subject -relabel.setlabels (tlabel) - Allows to specicify a table with mnemonic labels. - @@ -80,60 +64,39 @@ Below there is a brief summary of the new functions provided by LpegLabel: #### lpeglabel.T(l) -Returns a pattern that throws the label `l`. -A label must be an integer between 1 and 255. - -This pattern always causes a failure, whose associated -position will be used to set **errpos**, no matter -whether this is the farthest failure position or not. - - -#### lpeglabel.Rec(p1, p2, l1, ..., ln) - -Returns a *recovery pattern*. -If the matching of `p1` gives one of the labels `l1, ..., ln`, -then the matching of `p2` is tried from the failure position of `p1`. -Otherwise, the result of the matching of `p1` is the pattern's result. - - -#### lpeglabel.Lc(p1, p2, l1, ..., ln) - -Returns a pattern equivalent to a *labeled ordered choice*. -If the matching of `p1` gives one of the labels `l1, ..., ln`, -then the matching of `p2` is tried from the same position. Otherwise, -the result of the matching of `p1` is the pattern's result. +Returns a pattern that throws the label `l`, which +can be an integer or a string. - +When a label is thrown, the current subject position +is used to set **errpos**, no matter whether it is the +fartherst failure position or not. -Although PEG's ordered choice is associative, the labeled ordered choice is not. -When using this function, the user should take care to build a left-associative -labeled ordered choice pattern. +In case the PEG grammar has a rule `l`, after a label is thrown +this rule will be used as a recovery rule, otherwise the whole +matching fails. + +The recovery rule will try to match the input from the subject +position where `l` was thrown. In case the matching of the recovery +rule succeeds, the regular matching is resumed. Otherwise, the +result of the recovery rule is the matching result. + +When we have a predicate such as `-p` or `#p` and a label `l` is thrown +during the matching of `p`, this causes the failure of `p`, but does +not propagate `l`, or calls its associated recovery rule. #### %{l} Syntax of *relabel* module. Equivalent to `lpeg.T(l)`. +Label `l` must be a valid identifier name. -#### p1 //{l1, ..., ln} p2 - -Syntax of *relabel* module. Equivalent to `lpeglabel.Rec(p1, p2, l1, ..., ln)`. - -The `//{}` operator is left-associative. - +#### p^l -#### p1 /{l1, ..., ln} p2 +Syntax of *relabel* module. The pattern `p^l` is equivalent +to `p / lpeglabel.T(l)`. -Syntax of *relabel* module. Equivalent to `lpeg.Lc(p1, p2, l1, ..., ln)`. - -The `/{}` operator is left-associative. - -A grammar can use both choice operators (`/` and `/{}`), -but a single choice can not mix them. That is, the parser of `relabel` -module will not recognize a pattern as `p1 / p2 /{l1} p3`. +Label `l` must be a valid identifier name. #### relabel.calcline (subject, i) @@ -141,12 +104,6 @@ module will not recognize a pattern as `p1 / p2 /{l1} p3`. Returns line and column information regarding position i of the subject. -#### relabel.setlabels (tlabel) - -Allows to specicify a table with labels. They keys of -`tlabel` must be strings and the associated values must -be integers between 1 and 255. - ### Examples @@ -159,9 +116,9 @@ in the *examples* directory. This example illustrates the new values returned by the *match* function in case of an unsuccessful -matching. As no error is thrown, when the matching -fails *errpos* represents the farthest suffix where -an ordinary failure occurred. +matching. As no error is thrown in this example, +when the matching fails *errpos* represents the +farthest suffix where an ordinary failure occurred. ```lua local m = require'lpeglabel' @@ -172,124 +129,165 @@ function matchPrint(p, s) end local p = m.P"a"^0 * m.P"b" + m.P"c" -matchPrint(p, "abc") --> r: 3 lab: nil errpos: nil -matchPrint(p, "c") --> r: 2 lab: nil errpos: nil -matchPrint(p, "aac") --> r: nil lab: 0 errpos: 3 -matchPrint(p, "xxc") --> r: nil lab: 0 errpos: 1 +matchPrint(p, "abc") --> r: 3 lab: nil errpos: nil +matchPrint(p, "c") --> r: 2 lab: nil errpos: nil +matchPrint(p, "aac") --> r: nil lab: fail errpos: 3 +matchPrint(p, "xxc") --> r: nil lab: fail errpos: 1 ``` #### Matching a list of identifiers separated by commas The following example defines a grammar that matches -a list of identifiers separated by commas. A label -is thrown when there is an error matching an identifier -or a comma. - -We use function `newError` to store error messages in a -table and to return the index associated with each error message. +a (possibly empty) list of identifiers separated by commas. +A label is thrown when there is no identifier after a comma, +or when the whole input is not matched. ```lua local m = require'lpeglabel' local re = require'relabel' -local terror = {} - -local function newError(s) - table.insert(terror, s) - return #terror -end +local terror = { + ErrId = "expecting an identifier", + ErrEnd = "expecting EOF", + fail = "undefined" +} -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" * ",", - Sp = m.S" \n\t"^0, + 'S', + S = m.V'List' * (-m.P(1) + m.T'ErrEnd'), + List = m.V'Id' * (m.V'Comma' * (m.V'Id' + m.T'ErrId'))^0, + Id = m.V'Sp' * id, + Comma = m.V'Sp' * ',', + Sp = m.S' \n\t'^0, } + function mymatch (g, s) - local r, e, sfail = g:match(s) + local r, e, pos = g:match(s) if not r then - local line, col = re.calcline(s, #s - #sfail) + local line, col = re.calcline(s, pos) local msg = "Error at line " .. line .. " (col " .. col .. "): " - return r, msg .. terror[e] .. " before '" .. sfail .. "'" + return r, msg .. terror[e] .. " before '" .. s:sub(pos) .. "'" 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 '' +print(mymatch(g, "one,two")) +print(mymatch(g, "one two")) +print(mymatch(g, "one,\n two,\nthree,4")) ``` In this example we could think about writing rule List as follows: ```lua -List = ((m.V"Comma" + m.T(errComma)) * (m.V"Id" + m.T(errId)))^0, +List = m.V'Id' * ((m.V'Comma' + m.T'ErrComma') * (m.V'Id' + m.T'ErrId'))^0, ``` -but when matching this expression against the end of input +but when matching m.V'Comma' + m.T'ErrComma' against the end of input we would get a failure whose associated label would be **errComma**, and this would cause the failure of the *whole* repetition. +Below we rewrite the previous grammar to indicate an error when there is no +comma after an identifer. Before tyring to match a comma, we check if +we have reached the end of input: + +```lua +local m = require'lpeglabel' +local re = require'relabel' + +local terror = { + ErrId = "expecting an identifier", + ErrComma = "expecting ','", + fail = "undefined" +} + +local id = m.R'az'^1 + +local g = m.P{ + 'S', + S = m.V'List', + List = m.V'Id' * (#m.P(1) * m.V'Comma' * (m.V'Id' + m.T'ErrId'))^0, + Id = m.V'Sp' * id, + Comma = m.V'Sp' * ',' + m.T'ErrComma', + Sp = m.S' \n\t'^0, +} + + +function mymatch (g, s) + local r, e, pos = g:match(s) + if not r then + local line, col = re.calcline(s, pos) + local msg = "Error at line " .. line .. " (col " .. col .. "): " + return r, msg .. terror[e] .. " before '" .. s:sub(pos) .. "'" + end + return r +end + +print(mymatch(g, "one,two")) +print(mymatch(g, "one two")) +print(mymatch(g, "one,\n two,\nthree,4")) +print(mymatch(g, " 1,2")) + +``` #### Error Recovery -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 when a failure occur the label 42 -is thrown and then we will try to match the recovery pattern `recp`: +We can specify a recovery rule that should +be matched when a label is thrown. After matching +the recovery rule, and possibly recording the error, +the parser will resume the regular matching. +The recovery rule must have the same name (or number) +of the label that was thrown. + + +For example, in the example below we expect to match rule *A*, +but when a failure occur the label `Err` is thrown and then we +will try to match rule *Err*: ```lua local m = require'lpeglabel' 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.V'A' * '.', + A = m.P't' * (m.P'est' + m.T'Err'), + Err = m.P'oast' } 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 fail oast. +print(g:match("toward.")) --> nil fail ward. ``` -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 trying to match subject 'toast.', in rule *A* the first +'t' is matched, then the matching of `m.P"est"` fails and label +`Err` is thrown, with the associated inpux suffix 'oast.'. +The recovery rule *Err* successfully matches 'oast', so +the regular matching continues, and pattern `'.'` matches +the rest of the input. When matching subject 'oast.', pattern `m.P"t"` fails, and -the result of the matching is nil, 0, oast.. +the result of the matching is nil, fail, 1. -When matching 'toward.', label 42 is thrown after matching 't', +When matching 'toward.', label `Err` 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.. +recovery pattern fails, the result is nil, fail, 3. 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. Below we rewrite the grammar that describes a list of identifiers -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`. +to use a recovery strategy, with the help of some auxiliary functions. 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 +that consumes the input while it is not possible to match a given pattern `p`. When the matching of an identifier fails, a defaul value ('NONE') @@ -299,26 +297,11 @@ is provided. local m = require'lpeglabel' local re = require'relabel' -local terror = {} - -local function newError(s) - table.insert(terror, s) - return #terror -end - -local errUndef = newError("undefined") -local errId = newError("expecting an identifier") -local errComma = newError("expecting ','") - -local id = m.R'az'^1 - -local g = m.P{ - "S", - S = m.V"Id" * m.V"List", - List = -m.P(1) + m.V"Comma" * m.V"Id" * m.V"List", - Id = m.V"Sp" * m.C(id) + m.T(errId), - Comma = m.V"Sp" * "," + m.T(errComma), - Sp = m.S" \n\t"^0, +local terror = { + ErrId = "expecting an identifier", + ErrComma = "expecting ','", + ErrList = "expecting a list of identifiers", + fail = "undefined" } local subject, errors @@ -340,14 +323,20 @@ function defaultValue () return m.Cc"NONE" end -local grec = m.P{ +local id = m.R'az'^1 + +local g = m.P{ "S", - S = m.Rec(m.Rec(g, m.V"ErrComma", errComma), m.V"ErrId", errId), - ErrComma = record(errComma) * sync(id), - ErrId = record(errId) * sync(m.P",") * defaultValue(), + S = m.V"List" + (m.P(1) * m.T'ErrList'), + List = m.V'Id' * (#m.P(1) * m.V'Comma' * (m.V'Id' + m.T'ErrId'))^0, + Id = m.V'Sp' * m.C(id), + Comma = m.V'Sp' * ',' + m.T'ErrComma', + Sp = m.S' \n\t'^0, + ErrId = record'ErrId' * sync(m.P",") * defaultValue(), + ErrComma = record'ErrComma' * sync(id), + ErrList = record'ErrList' * sync(m.P(-1)) * defaultValue() } - function mymatch (g, s) errors = {} subject = s @@ -371,387 +360,114 @@ function mymatch (g, s) return r end -mymatch(grec, "one,two") -mymatch(grec, "one two three") -mymatch(grec, "1,\n two, \n3,") -mymatch(grec, "one\n two123, \nthree,") +mymatch(g, "one,two") +mymatch(g, "one two three") +mymatch(g, "1,\n two, \n3,") +mymatch(g, "one\n two123, \nthree,") ``` ##### *relabel* syntax -Below we describe again a grammar that matches a list of identifiers, -now using the syntax supported by *relabel*, where `//{}` is the -recovery operator, and `%{}` is the throw operator: +Below we write a grammar for a simple programming language +using the syntax supported by *relabel*, where `%{}` is the throw +operator, and the syntax `p^l` is syntatic sugar for +`p / %{l}` (given that *l* is a valid identifier name): ```lua -local re = require 'relabel' - -local errinfo = { - {"errUndef", "undefined"}, - {"errId", "expecting an identifier"}, - {"errComma", "expecting ','"}, +local re = require 'relabel' + +local terror = { + cmdSeq = "Missing ';' in CmdSeq", + ifExp = "Error in expresion of 'if'", + ifThen = "Error matching 'then' keyword", + ifThenCmdSeq = "Error matching CmdSeq of 'then' branch", + ifElseCmdSeq = "Error matching CmdSeq of 'else' branch", + ifEnd = "Error matching 'end' keyword of 'if'", + repeatCmdSeq = "Error matching CmdSeq of 'repeat'", + repeatUntil = "Error matching 'until' keyword", + repeatExp = "Error matching expression of 'until'", + assignOp = "Error matching ':='", + assignExp = "Error matching expression of assignment", + readName = "Error matching 'NAME' after 'read'", + writeExp = "Error matching expression after 'write'", + simpleExp = "Error matching 'SimpleExp'", + term = "Error matching 'Term'", + factor = "Error matching 'Factor'", + openParExp = "Error matching expression after '('", + closePar = "Error matching ')'", + eof = "Error, expecting EOF", + undefined = "Undefined Error" } -local errmsgs = {} -local labels = {} - -for i, err in ipairs(errinfo) do - errmsgs[i] = err[2] - labels[err[1]] = i -end - -re.setlabels(labels) - -local g = re.compile[[ - S <- Id List - List <- !. / Comma Id List - Id <- Sp {[a-z]+} / %{errId} - Comma <- Sp ',' / %{errComma} - Sp <- %s* -]] - -local errors - -function recorderror (subject, pos, label) - local line, col = re.calcline(subject, pos) - table.insert(errors, { line = line, col = col, msg = errmsgs[labels[label]] }) - return true -end - -function sync (p) - return '( !(' .. p .. ') .)*' -end - -local grec = re.compile( - "S <- %g //{errComma} ErrComma //{errId} ErrId" .. "\n" .. - "ErrComma <- ('' -> 'errComma' => recorderror) " .. sync('[a-z]+') .. "\n" .. - "ErrId <- ('' -> 'errId' => recorderror) " .. sync('","') .. "-> default" - , {g = g, recorderror = recorderror, default = "NONE"} -) - -function mymatch (g, s) - errors = {} - subject = s - io.write("Input: ", s, "\n") - local r = { g:match(s) } - io.write("Captures (separated by ';'): ") - for k, v in pairs(r) do - io.write(v .. "; ") - end - io.write("\nSyntactic errors found: " .. #errors) - if #errors > 0 then - io.write("\n") - local out = {} - for i, err in ipairs(errors) do - local msg = "Error at line " .. err.line .. " (col " .. err.col .. "): " .. err.msg - table.insert(out, msg) - end - io.write(table.concat(out, "\n")) - end - print("\n") - return r -end - -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 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. - -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. - -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"lpeglabel" -local re = require"relabel" - -local labels = { - {"ExpTermFirst", "expected an expression"}, - {"ExpTermOp", "expected a term after the operator"}, - {"MisClose", "missing a closing ')' after the expression"}, -} - -local function labelindex(labname) - for i, elem in ipairs(labels) do - if elem[1] == labname then - return i - end - end - error("could not find label: " .. labname) -end - -local errors, subject - -local function expect(patt, labname) - local i = labelindex(labname) - return patt + m.T(i) -end - - -local num = m.R("09")^1 / tonumber -local op = m.S("+-") - -local function compute(tokens) - local result = tokens[1] - for i = 2, #tokens, 2 do - if tokens[i] == '+' then - result = result + tokens[i+1] - elseif tokens[i] == '-' then - result = result - tokens[i+1] - else - error('unknown operation: ' .. tokens[i]) - end - end - return result -end - -local g = m.P { - "Exp", - Exp = m.Ct(m.V"OperandFirst" * (m.C(op) * m.V"Operand")^0) / compute, - OperandFirst = expect(m.V"Term", "ExpTermFirst"), - Operand = expect(m.V"Term", "ExpTermOp"), - Term = num + m.V"Group", - Group = "(" * m.V"Exp" * expect(")", "MisClose"), -} - -function recorderror(pos, lab) - local line, col = re.calcline(subject, pos) - table.insert(errors, { line = line, col = col, msg = labels[lab][2] }) -end - -function record (labname) - return (m.Cp() * m.Cc(labelindex(labname))) / recorderror -end - -function sync (p) - return (-p * m.P(1))^0 -end - -function defaultValue (p) - return p or m.Cc(1000) -end - -local grec = m.P { - "S", - S = m.Rec(m.V"A", m.V"ErrExpTermFirst", labelindex("ExpTermFirst")), - 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 +g = re.compile([[ + Tiny <- CmdSeq (!. / %{eof}) + CmdSeq <- (Cmd SEMICOLON^cmdSeq) (Cmd SEMICOLON^cmdSeq)* + Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd + IfCmd <- IF Exp^ifExp THEN^ifThen CmdSeq^ifThenCmdSeq (ELSE CmdSeq^ifElseCmdSeq / '') END^ifEnd + RepeatCmd <- REPEAT CmdSeq^repeatCmdSeq UNTIL^repeatUntil Exp^repeatExp + AssignCmd <- NAME ASSIGNMENT^assignOp Exp^assignExp + ReadCmd <- READ NAME^readName + WriteCmd <- WRITE Exp^writeExp + Exp <- SimpleExp ((LESS / EQUAL) SimpleExp^simpleExp / '') + SimpleExp <- Term ((ADD / SUB) Term^term)* + Term <- Factor ((MUL / DIV) Factor^factor)* + Factor <- OPENPAR Exp^openParExp CLOSEPAR^closePar / NUMBER / NAME + ADD <- Sp '+' + ASSIGNMENT <- Sp ':=' + CLOSEPAR <- Sp ')' + DIV <- Sp '/' + IF <- Sp 'if' + ELSE <- Sp 'else' + END <- Sp 'end' + EQUAL <- Sp '=' + LESS <- Sp '<' + MUL <- Sp '*' + NAME <- !RESERVED Sp [a-z]+ + NUMBER <- Sp [0-9]+ + OPENPAR <- Sp '(' + READ <- Sp 'read' + REPEAT <- Sp 'repeat' + SEMICOLON <- Sp ';' + SUB <- Sp '-' + THEN <- Sp 'then' + UNTIL <- Sp 'until' + WRITE <- Sp 'write' + RESERVED <- (IF / ELSE / END / READ / REPEAT / THEN / UNTIL / WRITE) ![a-z]+ + Sp <- (%s / %nl)* +]], terror) + + +local function mymatch(g, s) + local r, e, pos = g:match(s) + if not r then + local line, col = re.calcline(s, pos) + local msg = "Error at line " .. line .. " (col " .. col .. "): " + return r, msg .. terror[e] + end + return r end -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 +local s = [[ +n := 5; +f := 1; +repeat + f := f + n; + n := n - 1 +until (n < 1); +write f;]] +print(mymatch(g, s)) + +print(mymatch(g, "a : 2")) +print(mymatch(g, "a := 2; 6")) ``` -#### Automatically Building the Recovery Grammar +### Caveats -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. +Does not use the number **1** to specify a recovery rule, +since that this index is used to indicate the first rule +of a grammar. -```lua -local m = require"lpeglabel" -local re = require"relabel" - -local num = m.R("09")^1 / tonumber -local op = m.S("+-") - -local labels = {} -local nlabels = 0 - -local function newError(lab, msg, psync, pcap) - nlabels = nlabels + 1 - psync = psync or m.P(-1) - pcap = pcap or m.P"" - labels[lab] = { id = nlabels, msg = msg, psync = psync, pcap = pcap } -end - -newError("ExpTermFirst", "expected an expression", op + ")", m.Cc(1000)) -newError("ExpTermOp", "expected a term after the operator", op + ")", m.Cc(1000)) -newError("MisClose", "missing a closing ')' after the expression", m.P")") -newError("Extra", "extra characters found after the expression") - -local errors, subject - -local function expect(patt, labname) - local i = labels[labname].id - return patt + m.T(i) -end - -local function compute(tokens) - local result = tokens[1] - for i = 2, #tokens, 2 do - if tokens[i] == '+' then - result = result + tokens[i+1] - elseif tokens[i] == '-' then - result = result - tokens[i+1] - else - error('unknown operation: ' .. tokens[i]) - end - end - return result -end - -local g = m.P { - "Exp", - Exp = m.Ct(m.V"OperandFirst" * (m.C(op) * m.V"Operand")^0) / compute, - OperandFirst = expect(m.V"Term", "ExpTermFirst"), - Operand = expect(m.V"Term", "ExpTermOp"), - Term = num + m.V"Group", - Group = "(" * m.V"Exp" * expect(")", "MisClose"), -} - -function recorderror(pos, lab) - local line, col = re.calcline(subject, pos) - table.insert(errors, { line = line, col = col, msg = labels[lab].msg }) -end - -function record (labname) - return (m.Cp() * m.Cc(labname)) / recorderror -end - -function sync (p) - return (-p * m.P(1))^0 -end - -function defaultValue (p) - return p or m.Cc(1000) -end - -local grec = g * expect(m.P(-1), "Extra") -for k, v in pairs(labels) do - grec = m.Rec(grec, record(k) * sync(v.psync) * v.pcap, v.id) -end - -local function eval(input) - errors = {} - io.write("Input: ", input, "\n") - subject = input - local result, label, suffix = grec:match(input) - io.write("Syntactic errors found: " .. #errors, "\n") - if #errors > 0 then - local out = {} - for i, err in ipairs(errors) do - local pos = err.col - local msg = err.msg - table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") - end - print(table.concat(out, "\n")) - end - io.write("Result = ") - return result -end - -print(eval "90-70-(5)+3") --- 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 -``` +In case your grammar has many regular and recovery rules, +you may get an error message such as grammar: has too many rules. +In this case, we need to change *MAXRULES* in `lptypes.h`. + diff --git a/examples/listId2.lua b/examples/listId2.lua index 322d432..dc30ce5 100644 --- a/examples/listId2.lua +++ b/examples/listId2.lua @@ -3,19 +3,19 @@ local re = require'relabel' local terror = { ErrId = "expecting an identifier", - ErrComma = "expecting ','", + ErrEnd = "expecting EOF", fail = "undefined" } 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, + 'S', + S = m.V'List' * (-m.P(1) + m.T'ErrEnd'), + List = m.V'Id' * (m.V'Comma' * (m.V'Id' + m.T'ErrId'))^0, + Id = m.V'Sp' * id, + Comma = m.V'Sp' * ',', + Sp = m.S' \n\t'^0, } @@ -31,4 +31,4 @@ end print(mymatch(g, "one,two")) print(mymatch(g, "one two")) -print(mymatch(g, "one,\n two,\nthree,")) +print(mymatch(g, "one,\n two,\nthree,4")) diff --git a/examples/listId2Rec2Cap.lua b/examples/listId2Rec2Cap.lua index 7fbe700..952540a 100644 --- a/examples/listId2Rec2Cap.lua +++ b/examples/listId2Rec2Cap.lua @@ -3,7 +3,9 @@ local re = require'relabel' local terror = { ErrId = "expecting an identifier", - ErrComma = "expecting ','" + ErrComma = "expecting ','", + ErrList = "expecting a list of identifiers", + fail = "undefined" } local subject, errors @@ -29,16 +31,16 @@ 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, - ErrId = record('ErrId') * sync(m.P",") * defaultValue(), - ErrComma = record('ErrComma') * sync(id), + S = m.V"List" + (m.P(1) * m.T'ErrList'), + List = m.V'Id' * (#m.P(1) * m.V'Comma' * (m.V'Id' + m.T'ErrId'))^0, + Id = m.V'Sp' * m.C(id), + Comma = m.V'Sp' * ',' + m.T'ErrComma', + Sp = m.S' \n\t'^0, + ErrId = record'ErrId' * sync(m.P",") * defaultValue(), + ErrComma = record'ErrComma' * sync(id), + ErrList = record'ErrList' * sync(m.P(-1)) * defaultValue() } - function mymatch (g, s) errors = {} subject = s diff --git a/examples/listId3.lua b/examples/listId3.lua new file mode 100644 index 0000000..03da97d --- /dev/null +++ b/examples/listId3.lua @@ -0,0 +1,35 @@ +local m = require'lpeglabel' +local re = require'relabel' + +local terror = { + ErrId = "expecting an identifier", + ErrComma = "expecting ','", + fail = "undefined" +} + +local id = m.R'az'^1 + +local g = m.P{ + 'S', + S = m.V'List', + List = m.V'Id' * (#m.P(1) * m.V'Comma' * (m.V'Id' + m.T'ErrId'))^0, + Id = m.V'Sp' * id, + Comma = m.V'Sp' * ',' + m.T'ErrComma', + Sp = m.S' \n\t'^0, +} + + +function mymatch (g, s) + local r, e, pos = g:match(s) + if not r then + local line, col = re.calcline(s, pos) + local msg = "Error at line " .. line .. " (col " .. col .. "): " + return r, msg .. terror[e] .. " before '" .. s:sub(pos) .. "'" + end + return r +end + +print(mymatch(g, "one,two")) +print(mymatch(g, "one two")) +print(mymatch(g, "one,\n two,\nthree,4")) +print(mymatch(g, " 1,2")) diff --git a/examples/tiny.lua b/examples/tiny.lua index fe0bced..7548995 100644 --- a/examples/tiny.lua +++ b/examples/tiny.lua @@ -19,11 +19,12 @@ local terror = { factor = "Error matching 'Factor'", openParExp = "Error matching expression after '('", closePar = "Error matching ')'", + eof = "Error, expecting EOF", undefined = "Undefined Error" } g = re.compile([[ - Tiny <- CmdSeq^undefined + Tiny <- CmdSeq (!. / %{eof}) CmdSeq <- (Cmd SEMICOLON^cmdSeq) (Cmd SEMICOLON^cmdSeq)* Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd IfCmd <- IF Exp^ifExp THEN^ifThen CmdSeq^ifThenCmdSeq (ELSE CmdSeq^ifElseCmdSeq / '') END^ifEnd @@ -118,5 +119,5 @@ repeat print(mymatch(g, s)) print(mymatch(g, "a : 2")) -print(mymatch(g, "a := (2")) +print(mymatch(g, "a := 2; 6")) diff --git a/examples/toast.lua b/examples/toast.lua new file mode 100644 index 0000000..c355642 --- /dev/null +++ b/examples/toast.lua @@ -0,0 +1,16 @@ +local m = require'lpeglabel' + +local recp = m.P"oast" + +local g = m.P{ + 'S', + S = m.V'A' * '.', + A = m.P't' * (m.P'est' + m.T'Err'), + Err = m.P'oast' +} + +print(g:match("test.")) --> 6 +print(g:match("toast.")) --> 7 +print(g:match("oast.")) --> nil 0 oast. +print(g:match("toward.")) --> nil 0 ward. + diff --git a/examples/typedlua/test.lua b/examples/typedlua/test.lua deleted file mode 100755 index 95474ba..0000000 --- a/examples/typedlua/test.lua +++ /dev/null @@ -1,2572 +0,0 @@ -#!/usr/bin/env lua - -local tlparser = require "tlparser" - --- expected result, result, message, subject -local e, r, m, s - -local filename = "test.lua" - -local function parse (s) - local r, m = tlparser.parse(s,filename,false,false) - if not r then m = m .. "\n" end - return r, m -end - -print("> testing lexer...") - --- syntax ok - --- empty files - -s = [=[ -]=] ---[=[ -{ } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ --- testing empty file -]=] ---[=[ -{ } -]=] - -r, m = parse(s) -assert(r == true) - --- expressions - -s = [=[ -local _nil,_false,_true,_dots = nil,false,true,... -]=] ---[=[ -{ `Local{ { `Id "_nil", `Id "_false", `Id "_true", `Id "_dots" }, { `Nil, `False, `True, `Dots } } } -]=] - -r, m = parse(s) -assert(r == true) - --- floating points - -s = [=[ -local f1 = 1. -local f2 = 1.1 -]=] ---[=[ -{ `Local{ { `Id "f1" }, { `Number "1.0" } }, `Local{ { `Id "f2" }, { `Number "1.1" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local f1 = 1.e-1 -local f2 = 1.e1 -]=] ---[=[ -{ `Local{ { `Id "f1" }, { `Number "0.1" } }, `Local{ { `Id "f2" }, { `Number "10.0" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local f1 = 1.1e+1 -local f2 = 1.1e1 -]=] ---[=[ -{ `Local{ { `Id "f1" }, { `Number "11.0" } }, `Local{ { `Id "f2" }, { `Number "11.0" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local f1 = .1 -local f2 = .1e1 -]=] ---[=[ -{ `Local{ { `Id "f1" }, { `Number "0.1" } }, `Local{ { `Id "f2" }, { `Number "1.0" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local f1 = 1E1 -local f2 = 1e-1 -]=] ---[=[ -{ `Local{ { `Id "f1" }, { `Number "10.0" } }, `Local{ { `Id "f2" }, { `Number "0.1" } } } -]=] - -r, m = parse(s) -assert(r == true) - --- integers - -s = [=[ -local i = 1 -local h = 0xff -]=] ---[=[ -{ `Local{ { `Id "i" }, { `Number "1" } }, `Local{ { `Id "h" }, { `Number "255" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local h = 0x76c -local i = 4294967296 -- 2^32 -]=] ---[=[ -{ `Local{ { `Id "h" }, { `Number "1900" } }, `Local{ { `Id "i" }, { `Number "4294967296" } } } -]=] - -r, m = parse(s) -assert(r == true) - --- long comments - -s = [=[ ---[======[ -testing -long -comment -[==[ one ]==] -[===[ more ]===] -[====[ time ]====] -bye -]======] -]=] ---[=[ -{ } -]=] - -r, m = parse(s) -assert(r == true) - --- long strings - -s = [=[ ---[[ -testing long string1 begin -]] - -local ls1 = -[[ -testing long string -]] - ---[[ -testing long string1 end -]] -]=] ---[=[ -{ `Local{ { `Id "ls1" }, { `String "testing long string\n" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ ---[==[ -testing long string2 begin -]==] - -local ls2 = [==[ testing \n [[ long ]] \t [===[ string ]===] -\a ]==] - ---[==[ -[[ testing long string2 end ]] -]==] -]=] ---[=[ -{ `Local{ { `Id "ls2" }, { `String " testing \\n [[ long ]] \\t [===[ string ]===]\n\\a " } } } -]=] - -r, m = parse(s) -assert(r == true) - --- short strings - -s = [=[ --- short string test begin - -local ss1_a = "ola mundo\a" -local ss1_b = 'ola mundo\a' - --- short string test end -]=] ---[=[ -{ `Local{ { `Id "ss1_a" }, { `String "ola mundo\a" } }, `Local{ { `Id "ss1_b" }, { `String "ola mundo\a" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ --- short string test begin - -local ss2_a = "testando,\tteste\n1\n2\n3 --> \"tchau\"" -local ss2_b = 'testando,\tteste\n1\n2\n3 --> \'tchau\'' - --- short string test end -]=] ---[=[ -{ `Local{ { `Id "ss2_a" }, { `String "testando,\tteste\n1\n2\n3 --> \"tchau\"" } }, `Local{ { `Id "ss2_b" }, { `String "testando,\tteste\n1\n2\n3 --> 'tchau'" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ --- short string test begin - -local ss3_a = "ola \ -'mundo'!" - -local ss3_b = 'ola \ -"mundo"!' - --- short string test end -]=] ---[=[ -{ `Local{ { `Id "ss3_a" }, { `String "ola \n'mundo'!" } }, `Local{ { `Id "ss3_b" }, { `String "ola \n\"mundo\"!" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ --- short string test begin - -local ss4_a = "C:\\Temp/" - -local ss4_b = 'C:\\Temp/' - --- short string test end -]=] ---[=[ -{ `Local{ { `Id "ss4_a" }, { `String "C:\\Temp/" } }, `Local{ { `Id "ss4_b" }, { `String "C:\\Temp/" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ --- short string test begin - -local ss5_a = "ola \ -mundo \\ \ -cruel" - -local ss5_b = 'ola \ -mundo \\ \ -cruel' - --- short string test end -]=] ---[=[ -{ `Local{ { `Id "ss5_a" }, { `String "ola \nmundo \\ \ncruel" } }, `Local{ { `Id "ss5_b" }, { `String "ola \nmundo \\ \ncruel" } } } -]=] - -r, m = parse(s) -assert(r == true) - --- syntax error - --- floating points - -s = [=[ -local f = 9e -]=] ---[=[ -test.lua:2:1: syntax error, unexpected 'EOF', expecting '=', ',', 'String', '{', '(', ':', '[', '.' -]=] -e = [=[ -test.lua:1:12: malformed -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local f = 5.e -]=] ---[=[ -test.lua:2:1: syntax error, unexpected 'EOF', expecting '=', ',', 'String', '{', '(', ':', '[', '.' -]=] -e = [=[ -test.lua:1:13: malformed -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local f = .9e- -]=] ---[=[ -test.lua:1:14: syntax error, unexpected '-', expecting '=', ',', 'String', '{', '(', ':', '[', '.' -]=] -e = [=[ -test.lua:1:14: malformed -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local f = 5.9e+ -]=] ---[=[ -test.lua:1:15: syntax error, unexpected '+', expecting '=', ',', 'String', '{', '(', ':', '[', '.' -]=] -e = [=[ -test.lua:1:15: malformed -]=] - -r, m = parse(s) -assert(m == e) - --- integers - -s = [=[ --- invalid hexadecimal number - -local hex = 0xG -]=] ---[=[ -test.lua:4:1: syntax error, unexpected 'EOF', expecting '=', ',', 'String', '{', '(', ':', '[', '.' -]=] -e = [=[ -test.lua:3:14: malformed -]=] - -r, m = parse(s) -assert(m == e) - --- long strings - -s = [=[ ---[==[ -testing long string3 begin -]==] - -local ls3 = [===[ -testing -unfinised -long string -]==] - ---[==[ -[[ testing long string3 end ]] -]==] -]=] ---[=[ -test.lua:5:13: syntax error, unexpected '[', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' -]=] -e = [=[ -test.lua:14:1: unfinished long string -]=] - -r, m = parse(s) -assert(m == e) - --- short strings - -s = [=[ --- short string test begin - -local ss6 = "testing unfinished string - --- short string test end -]=] ---[=[ -test.lua:3:13: syntax error, unexpected '"', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' -]=] -e = [=[ -test.lua:6:1: malformed -]=] - -r, m = parse(s) -assert(m == e) - --- unfinished comments - -s = [=[ ---[[ - -testing -unfinished - -comment - ]=] ---[=[ -test.lua:3:1: syntax error, unexpected 'comment', expecting '=', ',', 'String', '{', '(', ':', '[', '.' -]=] -e = [=[ -test.lua:1:2: unfinished long comment -]=] - -r, m = parse(s) -assert(m == e) - -print("> testing parser...") - --- syntax ok - --- anonymous functions - -s = [=[ -local a,b,c = function () end -]=] ---[=[ -{ `Local{ { `Id "a", `Id "b", `Id "c" }, { `Function{ { }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local test = function ( a , b , ... ) end -]=] ---[=[ -{ `Local{ { `Id "test" }, { `Function{ { `Id "a", `Id "b", `Dots }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local test = function (...) return ...,0 end -]=] ---[=[ -{ `Local{ { `Id "test" }, { `Function{ { `Dots }, { `Return{ `Dots, `Number "0" } } } } } } -]=] - -r, m = parse(s) -assert(r == true) - --- arithmetic expressions - -s = [=[ -local arithmetic = 1 - 2 * 3 + 4 -]=] ---[=[ -{ `Local{ { `Id "arithmetic" }, { `Op{ "add", `Op{ "sub", `Number "1", `Op{ "mul", `Number "2", `Number "3" } }, `Number "4" } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local pow = -3^-2^2 -]=] ---[=[ -{ `Local{ { `Id "pow" }, { `Op{ "unm", `Op{ "pow", `Number "3", `Op{ "unm", `Op{ "pow", `Number "2", `Number "2" } } } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -q, r, f = 3//2, 3%2, 3/2 -]=] ---[=[ -{ `Set{ { `Index{ `Id "_ENV", `String "q" }, `Index{ `Id "_ENV", `String "r" }, `Index{ `Id "_ENV", `String "f" } }, { `Op{ "idiv", `Number "3", `Number "2" }, `Op{ "mod", `Number "3", `Number "2" }, `Op{ "div", `Number "3", `Number "2" } } } } -]=] - -r, m = parse(s) -assert(r == true) - --- assignments - -s = [=[ -a = f()[1] -]=] ---[=[ -{ `Set{ { `Index{ `Id "_ENV", `String "a" } }, { `Index{ `Call{ `Index{ `Id "_ENV", `String "f" } }, `Number "1" } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -a()[1] = 1; -]=] ---[=[ -{ `Set{ { `Index{ `Call{ `Index{ `Id "_ENV", `String "a" } }, `Number "1" } }, { `Number "1" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -i = a.f(1) -]=] ---[=[ -{ `Set{ { `Index{ `Id "_ENV", `String "i" } }, { `Call{ `Index{ `Index{ `Id "_ENV", `String "a" }, `String "f" }, `Number "1" } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -i = a[f(1)] -]=] ---[=[ -{ `Set{ { `Index{ `Id "_ENV", `String "i" } }, { `Index{ `Index{ `Id "_ENV", `String "a" }, `Call{ `Index{ `Id "_ENV", `String "f" }, `Number "1" } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -a[f()] = sub -i = i + 1 -]=] ---[=[ -{ `Set{ { `Index{ `Index{ `Id "_ENV", `String "a" }, `Call{ `Index{ `Id "_ENV", `String "f" } } } }, { `Index{ `Id "_ENV", `String "sub" } } }, `Set{ { `Index{ `Id "_ENV", `String "i" } }, { `Op{ "add", `Index{ `Id "_ENV", `String "i" }, `Number "1" } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -a:b(1)._ = some_value -]=] ---[=[ -{ `Set{ { `Index{ `Invoke{ `Index{ `Id "_ENV", `String "a" }, `String "b", `Number "1" }, `String "_" } }, { `Index{ `Id "_ENV", `String "some_value" } } } } -]=] - -r, m = parse(s) -assert(r == true) - --- bitwise expressions - -s = [=[ -b = 1 & 0 | 1 ~ 1 -]=] ---[=[ -{ `Set{ { `Index{ `Id "_ENV", `String "b" } }, { `Op{ "bor", `Op{ "band", `Number "1", `Number "0" }, `Op{ "bxor", `Number "1", `Number "1" } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -b = 1 & 0 | 1 >> 1 ~ 1 -]=] ---[=[ -{ `Set{ { `Index{ `Id "_ENV", `String "b" } }, { `Op{ "bor", `Op{ "band", `Number "1", `Number "0" }, `Op{ "bxor", `Op{ "shr", `Number "1", `Number "1" }, `Number "1" } } } } } -]=] - -r, m = parse(s) -assert(r == true) - --- break - -s = [=[ -while 1 do - break -end -]=] ---[=[ -{ `While{ `Number "1", { `Break } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -while 1 do - while 1 do - break - end - break -end -]=] ---[=[ -{ `While{ `Number "1", { `While{ `Number "1", { `Break } }, `Break } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -repeat - if 2 > 1 then break end -until 1 -]=] ---[=[ -{ `Repeat{ { `If{ `Op{ "lt", `Number "1", `Number "2" }, { `Break } } }, `Number "1" } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -for i=1,10 do - do - break - break - return - end -end -]=] ---[=[ -{ `Fornum{ `Id "i", `Number "1", `Number "10", { `Do{ `Break, `Break, `Return } } } } -]=] - -r, m = parse(s) -assert(r == true) - --- block statements - -s = [=[ -do - local var = 2+2; - return -end -]=] ---[=[ -{ `Do{ `Local{ { `Id "var" }, { `Op{ "add", `Number "2", `Number "2" } } }, `Return } } -]=] - -r, m = parse(s) -assert(r == true) - --- calls - -s = [=[ -f() -t:m() -]=] ---[=[ -{ `Call{ `Index{ `Id "_ENV", `String "f" } }, `Invoke{ `Index{ `Id "_ENV", `String "t" }, `String "m" } } -]=] - -r, m = parse(s) -assert(r == true) - --- concatenation expressions - -s = [=[ -local concat1 = 1 .. 2^3 -]=] ---[=[ -{ `Local{ { `Id "concat1" }, { `Op{ "concat", `Number "1", `Op{ "pow", `Number "2", `Number "3" } } } } } -]=] - -r, m = parse(s) -assert(r == true) - --- empty files - -s = [=[ -; -]=] ---[=[ -{ } -]=] - -r, m = parse(s) -assert(r == true) - --- for generic - -s = [=[ -for k,v in pairs(t) do print (k,v) end -]=] ---[=[ -{ `Forin{ { `Id "k", `Id "v" }, { `Call{ `Index{ `Id "_ENV", `String "pairs" }, `Index{ `Id "_ENV", `String "t" } } }, { `Call{ `Index{ `Id "_ENV", `String "print" }, `Id "k", `Id "v" } } } } -]=] - -r, m = parse(s) -assert(r == true) - --- for numeric - -s = [=[ -for i = 1 , 10 , 2 do end -]=] ---[=[ -{ `Fornum{ `Id "i", `Number "1", `Number "10", `Number "2", { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -for i=1,10 do end -]=] ---[=[ -{ `Fornum{ `Id "i", `Number "1", `Number "10", { } } } -]=] - -r, m = parse(s) -assert(r == true) - --- global functions - -s = [=[ -function test(a , b , ...) end -]=] ---[=[ -{ `Set{ { `Index{ `Id "_ENV", `String "test" } }, { `Function{ { `Id "a", `Id "b", `Dots }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -function test (...) end -]=] ---[=[ -{ `Set{ { `Index{ `Id "_ENV", `String "test" } }, { `Function{ { `Dots }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -function t.a:b() end -]=] ---[=[ -{ `Set{ { `Index{ `Index{ `Index{ `Id "_ENV", `String "t" }, `String "a" }, `String "b" } }, { `Function{ { `Id "self" }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -function t.a() end -]=] ---[=[ -{ `Set{ { `Index{ `Index{ `Id "_ENV", `String "t" }, `String "a" } }, { `Function{ { }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -function testando . funcao . com : espcacos ( e, com , parametros, ... ) end -]=] ---[=[ -{ `Set{ { `Index{ `Index{ `Index{ `Index{ `Id "_ENV", `String "testando" }, `String "funcao" }, `String "com" }, `String "espcacos" } }, { `Function{ { `Id "self", `Id "e", `Id "com", `Id "parametros", `Dots }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - --- goto - -s = [=[ -goto label -:: label :: return -]=] ---[=[ -{ `Goto{ "label" }, `Label{ "label" }, `Return } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -::label:: -goto label -]=] ---[=[ -{ `Label{ "label" }, `Goto{ "label" } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -goto label -::label:: -]=] ---[=[ -{ `Goto{ "label" }, `Label{ "label" } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -::label:: -do ::label:: goto label end -]=] ---[=[ -{ `Label{ "label" }, `Do{ `Label{ "label" }, `Goto{ "label" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -::label:: -do goto label ; ::label:: end -]=] ---[=[ -{ `Label{ "label" }, `Do{ `Goto{ "label" }, `Label{ "label" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -::label:: -do goto label end -]=] ---[=[ -{ `Label{ "label" }, `Do{ `Goto{ "label" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -do goto label end -::label:: -]=] ---[=[ -{ `Do{ `Goto{ "label" } }, `Label{ "label" } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -do do do do do goto label end end end end end -::label:: -]=] ---[=[ -{ `Do{ `Do{ `Do{ `Do{ `Do{ `Goto{ "label" } } } } } }, `Label{ "label" } } -]=] - -r, m = parse(s) -assert(r == true) - --- if-else - -s = [=[ -if a then end -]=] ---[=[ -{ `If{ `Index{ `Id "_ENV", `String "a" }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -if a then return a else return end -]=] ---[=[ -{ `If{ `Index{ `Id "_ENV", `String "a" }, { `Return{ `Index{ `Id "_ENV", `String "a" } } }, { `Return } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -if a then - return a -else - local c = d - d = d + 1 - return d -end -]=] ---[=[ -{ `If{ `Index{ `Id "_ENV", `String "a" }, { `Return{ `Index{ `Id "_ENV", `String "a" } } }, { `Local{ { `Id "c" }, { `Index{ `Id "_ENV", `String "d" } } }, `Set{ { `Index{ `Id "_ENV", `String "d" } }, { `Op{ "add", `Index{ `Id "_ENV", `String "d" }, `Number "1" } } }, `Return{ `Index{ `Id "_ENV", `String "d" } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -if a then - return a -elseif b then - return b -elseif c then - return c -end -]=] ---[=[ -{ `If{ `Index{ `Id "_ENV", `String "a" }, { `Return{ `Index{ `Id "_ENV", `String "a" } } }, `Index{ `Id "_ENV", `String "b" }, { `Return{ `Index{ `Id "_ENV", `String "b" } } }, `Index{ `Id "_ENV", `String "c" }, { `Return{ `Index{ `Id "_ENV", `String "c" } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -if a then return a -elseif b then return -else ; -end -]=] ---[=[ -{ `If{ `Index{ `Id "_ENV", `String "a" }, { `Return{ `Index{ `Id "_ENV", `String "a" } } }, `Index{ `Id "_ENV", `String "b" }, { `Return }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -if a then - return -elseif c then -end -]=] ---[=[ -{ `If{ `Index{ `Id "_ENV", `String "a" }, { `Return }, `Index{ `Id "_ENV", `String "c" }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - --- interfaces - -s = [=[ -local interface Empty end -]=] ---[=[ -{ `Interface{ Empty, `TTable{ } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local interface X - x, y, z:number -end -]=] ---[=[ -{ `Interface{ X, `TTable{ `TLiteral x:`TBase number, `TLiteral y:`TBase number, `TLiteral z:`TBase number } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local interface Person - firstname:string - lastname:string -end -]=] ---[=[ -{ `Interface{ Person, `TTable{ `TLiteral firstname:`TBase string, `TLiteral lastname:`TBase string } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local interface Element - info:number - next:Element? -end -]=] ---[=[ -{ `Interface{ Element, `TRecursive{ Element, `TTable{ `TLiteral info:`TBase number, `TLiteral next:`TUnion{ `TVariable Element, `TNil } } } } } -]=] - -r, m = parse(s) -assert(r == true) - --- labels - -s = [=[ -::label:: -do ::label:: end -::other_label:: -]=] ---[=[ -{ `Label{ "label" }, `Do{ `Label{ "label" } }, `Label{ "other_label" } } -]=] - -r, m = parse(s) -assert(r == true) - --- locals - -s = [=[ -local a -]=] ---[=[ -{ `Local{ { `Id "a" }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local a,b,c -]=] ---[=[ -{ `Local{ { `Id "a", `Id "b", `Id "c" }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local a = 1 , 1 + 2, 5.1 -]=] ---[=[ -{ `Local{ { `Id "a" }, { `Number "1", `Op{ "add", `Number "1", `Number "2" }, `Number "5.1" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local a,b,c = 1.9 -]=] ---[=[ -{ `Local{ { `Id "a", `Id "b", `Id "c" }, { `Number "1.9" } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function test() end -]=] ---[=[ -{ `Localrec{ { `Id "test" }, { `Function{ { }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function test ( a , b , c , ... ) end -]=] ---[=[ -{ `Localrec{ { `Id "test" }, { `Function{ { `Id "a", `Id "b", `Id "c", `Dots }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function test(...) return ... end -]=] ---[=[ -{ `Localrec{ { `Id "test" }, { `Function{ { `Dots }, { `Return{ `Dots } } } } } } -]=] - -r, m = parse(s) -assert(r == true) - --- relational expressions - -s = [=[ -local relational = 1 < 2 >= 3 == 4 ~= 5 < 6 <= 7 -]=] ---[=[ -{ `Local{ { `Id "relational" }, { `Op{ "le", `Op{ "lt", `Op{ "not", `Op{ "eq", `Op{ "eq", `Op{ "le", `Number "3", `Op{ "lt", `Number "1", `Number "2" } }, `Number "4" }, `Number "5" } }, `Number "6" }, `Number "7" } } } } -]=] - -r, m = parse(s) -assert(r == true) - --- repeat - -s = [=[ -repeat - local a,b,c = 1+1,2+2,3+3 - break -until a < 1 -]=] ---[=[ -{ `Repeat{ { `Local{ { `Id "a", `Id "b", `Id "c" }, { `Op{ "add", `Number "1", `Number "1" }, `Op{ "add", `Number "2", `Number "2" }, `Op{ "add", `Number "3", `Number "3" } } }, `Break }, `Op{ "lt", `Index{ `Id "_ENV", `String "a" }, `Number "1" } } } -]=] - -r, m = parse(s) -assert(r == true) - --- return - -s = [=[ -return -]=] ---[=[ -{ `Return } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -return 1 -]=] ---[=[ -{ `Return{ `Number "1" } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -return 1,1-2*3+4,"alo" -]=] ---[=[ -{ `Return{ `Number "1", `Op{ "add", `Op{ "sub", `Number "1", `Op{ "mul", `Number "2", `Number "3" } }, `Number "4" }, `String "alo" } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -return; -]=] ---[=[ -{ `Return } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -return 1; -]=] ---[=[ -{ `Return{ `Number "1" } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -return 1,1-2*3+4,"alo"; -]=] ---[=[ -{ `Return{ `Number "1", `Op{ "add", `Op{ "sub", `Number "1", `Op{ "mul", `Number "2", `Number "3" } }, `Number "4" }, `String "alo" } } -]=] - -r, m = parse(s) -assert(r == true) - --- tables - -s = [=[ -local t = { [1] = "alo", alo = 1, 2; } -]=] ---[=[ -{ `Local{ { `Id "t" }, { `Table{ `Pair{ `Number "1", `String "alo" }, `Pair{ `String "alo", `Number "1" }, `Number "2" } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local t = { 1.5 } -]=] ---[=[ -{ `Local{ { `Id "t" }, { `Table{ `Number "1.5" } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local t = {1,2; -3, -4, - - - -5} -]=] ---[=[ -{ `Local{ { `Id "t" }, { `Table{ `Number "1", `Number "2", `Number "3", `Number "4", `Number "5" } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local t = {[1]=1,[2]=2; -[3]=3, -[4]=4, - - - -[5]=5} -]=] ---[=[ -{ `Local{ { `Id "t" }, { `Table{ `Pair{ `Number "1", `Number "1" }, `Pair{ `Number "2", `Number "2" }, `Pair{ `Number "3", `Number "3" }, `Pair{ `Number "4", `Number "4" }, `Pair{ `Number "5", `Number "5" } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local t = {{{}}, {"alo"}} -]=] ---[=[ -{ `Local{ { `Id "t" }, { `Table{ `Table{ `Table }, `Table{ `String "alo" } } } } } -]=] - -r, m = parse(s) -assert(r == true) - --- vararg - -s = [=[ -local f = function (...) - return ... -end -]=] ---[=[ -{ `Local{ { `Id "f" }, { `Function{ { `Dots }, { `Return{ `Dots } } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local f = function () - local g = function (x, y, ...) - return ...,...,... - end -end -]=] ---[=[ -{ `Local{ { `Id "f" }, { `Function{ { }, { `Local{ { `Id "g" }, { `Function{ { `Id "x", `Id "y", `Dots }, { `Return{ `Dots, `Dots, `Dots } } } } } } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f (x, ...) - return ... -end -]=] ---[=[ -{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x", `Dots }, { `Return{ `Dots } } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local f = function (x, ...) - return ... -end -]=] ---[=[ -{ `Local{ { `Id "f" }, { `Function{ { `Id "x", `Dots }, { `Return{ `Dots } } } } } } -]=] - -r, m = parse(s) -assert(r == true) - --- while - -s = [=[ -local i = 0 -while (i < 10) -do - i = i + 1 -end -]=] ---[=[ -{ `Local{ { `Id "i" }, { `Number "0" } }, `While{ `Paren{ `Op{ "lt", `Id "i", `Number "10" } }, { `Set{ { `Id "i" }, { `Op{ "add", `Id "i", `Number "1" } } } } } } -]=] - -r, m = parse(s) -assert(r == true) - --- type annotations - -s = [=[ -local x:nil -]=] ---[=[ -{ `Local{ { `Id "x":`TNil }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:false, y:true -]=] ---[=[ -{ `Local{ { `Id "x":`TLiteral false, `Id "y":`TLiteral true }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:1, y:1.1 -]=] ---[=[ -{ `Local{ { `Id "x":`TLiteral 1, `Id "y":`TLiteral 1.1 }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:"hello", y:'world' -]=] ---[=[ -{ `Local{ { `Id "x":`TLiteral hello, `Id "y":`TLiteral world }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:boolean, y:number, z:string -]=] ---[=[ -{ `Local{ { `Id "x":`TBase boolean, `Id "y":`TBase number, `Id "z":`TBase string }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:any -]=] ---[=[ -{ `Local{ { `Id "x":`TAny }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:number? -]=] ---[=[ -{ `Local{ { `Id "x":`TUnion{ `TBase number, `TNil } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:number|nil -]=] ---[=[ -{ `Local{ { `Id "x":`TUnion{ `TBase number, `TNil } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:number|string|nil -]=] ---[=[ -{ `Local{ { `Id "x":`TUnion{ `TBase number, `TBase string, `TNil } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:number|nil|nil|nil|nil -]=] ---[=[ -{ `Local{ { `Id "x":`TUnion{ `TBase number, `TNil } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:number|nil|string|nil|number|boolean|string -]=] ---[=[ -{ `Local{ { `Id "x":`TUnion{ `TNil, `TBase number, `TBase boolean, `TBase string } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:number|string? -]=] ---[=[ -{ `Local{ { `Id "x":`TUnion{ `TBase number, `TBase string, `TNil } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:(number) -> (number) -]=] ---[=[ -{ `Local{ { `Id "x":`TFunction{ `TTuple{ `TBase number, `TVararg{ `TValue } }, `TTuple{ `TBase number, `TVararg{ `TNil } } } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:(value*) -> (nil*) -]=] ---[=[ -{ `Local{ { `Id "x":`TFunction{ `TTuple{ `TVararg{ `TValue } }, `TTuple{ `TVararg{ `TNil } } } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:(number,string,boolean) -> (string,number,boolean) -]=] ---[=[ -{ `Local{ { `Id "x":`TFunction{ `TTuple{ `TBase number, `TBase string, `TBase boolean, `TVararg{ `TValue } }, `TTuple{ `TBase string, `TBase number, `TBase boolean, `TVararg{ `TNil } } } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:(number,string,value*) -> (string,number,nil*) -]=] ---[=[ -{ `Local{ { `Id "x":`TFunction{ `TTuple{ `TBase number, `TBase string, `TVararg{ `TValue } }, `TTuple{ `TBase string, `TBase number, `TVararg{ `TNil } } } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:{} -]=] ---[=[ -{ `Local{ { `Id "x":`TTable{ } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:{{{{{}}}}} -]=] ---[=[ -{ `Local{ { `Id "x":`TTable{ `TBase number:`TUnion{ `TTable{ `TBase number:`TUnion{ `TTable{ `TBase number:`TUnion{ `TTable{ `TBase number:`TUnion{ `TTable{ }, `TNil } }, `TNil } }, `TNil } }, `TNil } } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:{string} -]=] ---[=[ -{ `Local{ { `Id "x":`TTable{ `TBase number:`TUnion{ `TBase string, `TNil } } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:{string:number} -]=] ---[=[ -{ `Local{ { `Id "x":`TTable{ `TBase string:`TUnion{ `TBase number, `TNil } } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:{'firstname':string, 'lastname':string} -]=] ---[=[ -{ `Local{ { `Id "x":`TTable{ `TLiteral firstname:`TBase string, `TLiteral lastname:`TBase string } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:{'tag':string, number:string} -]=] ---[=[ -{ `Local{ { `Id "x":`TTable{ `TLiteral tag:`TBase string, `TBase number:`TUnion{ `TBase string, `TNil } } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local x:{'f':(number) -> (number), 't':{number:number}} -]=] ---[=[ -{ `Local{ { `Id "x":`TTable{ `TLiteral f:`TFunction{ `TTuple{ `TBase number, `TVararg{ `TValue } }, `TTuple{ `TBase number, `TVararg{ `TNil } } }, `TLiteral t:`TTable{ `TBase number:`TUnion{ `TBase number, `TNil } } } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -for k:number, v:string in ipairs({"hello", "world"}) do end -]=] ---[=[ -{ `Forin{ { `Id "k":`TBase number, `Id "v":`TBase string }, { `Call{ `Index{ `Id "_ENV", `String "ipairs" }, `Table{ `String "hello", `String "world" } } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -for k:string, v in pairs({}) do end -]=] ---[=[ -{ `Forin{ { `Id "k":`TBase string, `Id "v" }, { `Call{ `Index{ `Id "_ENV", `String "pairs" }, `Table } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -for k, v:boolean in pairs({}) do end -]=] ---[=[ -{ `Forin{ { `Id "k", `Id "v":`TBase boolean }, { `Call{ `Index{ `Id "_ENV", `String "pairs" }, `Table } }, { } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f (x:any) end -]=] ---[=[ -{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TAny }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f (x:any):(any) end -]=] ---[=[ -{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TAny }:`TTuple{ `TAny, `TVararg{ `TNil } }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f (...:any) end -]=] ---[=[ -{ `Localrec{ { `Id "f" }, { `Function{ { `Dots:`TAny }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f (x:any, ...:any) end -]=] ---[=[ -{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TAny, `Dots:`TAny }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f (x, ...:any) end -]=] ---[=[ -{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x", `Dots:`TAny }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f (x:any, ...) end -]=] ---[=[ -{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TAny, `Dots }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f (x:any, ...:any):(any) end -]=] ---[=[ -{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TAny, `Dots:`TAny }:`TTuple{ `TAny, `TVararg{ `TNil } }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f (x:(any) -> (any)):((any) -> (any)) end -]=] ---[=[ -{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TFunction{ `TTuple{ `TAny, `TVararg{ `TValue } }, `TTuple{ `TAny, `TVararg{ `TNil } } } }:`TTuple{ `TFunction{ `TTuple{ `TAny, `TVararg{ `TValue } }, `TTuple{ `TAny, `TVararg{ `TNil } } }, `TVararg{ `TNil } }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f (x:(number, number) -> (number, nil*)):(number*) end -]=] ---[=[ -{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TFunction{ `TTuple{ `TBase number, `TBase number, `TVararg{ `TValue } }, `TTuple{ `TBase number, `TVararg{ `TNil } } } }:`TTuple{ `TVararg{ `TBase number } }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f ():(number, nil*) end -]=] ---[=[ -{ `Localrec{ { `Id "f" }, { `Function{ { }:`TTuple{ `TBase number, `TVararg{ `TNil } }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f ():number end -]=] ---[=[ -{ `Localrec{ { `Id "f" }, { `Function{ { }:`TTuple{ `TBase number, `TVararg{ `TNil } }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f ():number? end -]=] ---[=[ -{ `Localrec{ { `Id "f" }, { `Function{ { }:`TTuple{ `TUnion{ `TBase number, `TNil }, `TVararg{ `TNil } }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f ():(number) | (nil,string) end -]=] ---[=[ -{ `Localrec{ { `Id "f" }, { `Function{ { }:`TUnionlist{ `TTuple{ `TBase number, `TVararg{ `TNil } }, `TTuple{ `TNil, `TBase string, `TVararg{ `TNil } } }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f ():(number)? end -]=] ---[=[ -{ `Localrec{ { `Id "f" }, { `Function{ { }:`TUnionlist{ `TTuple{ `TBase number, `TVararg{ `TNil } }, `TTuple{ `TNil, `TBase string, `TVararg{ `TNil } } }, { } } } } } -]=] - -r, m = parse(s) -assert(r == true) - --- syntax error - --- anonymous functions - -s = [=[ -a = function (a,b,) end -]=] ---[=[ -test.lua:1:19: syntax error, unexpected ')', expecting '...', 'Name' -]=] -e = [=[ -test.lua:1:18: expecting '...' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -a = function (...,a) end -]=] ---[=[ -test.lua:1:18: syntax error, unexpected ',', expecting ')', ':' -]=] -e = [=[ -test.lua:1:17: missing ')' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local a = function (1) end -]=] ---[=[ -test.lua:1:21: syntax error, unexpected '1', expecting ')', '...', 'Name' -]=] -e = [=[ -test.lua:1:20: missing ')' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local test = function ( a , b , c , ... ) -]=] ---[=[ -test.lua:2:1: syntax error, unexpected 'EOF', expecting 'end', 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ':' -]=] -e = [=[ -test.lua:2:1: missing 'end' to close function declaration -]=] - -r, m = parse(s) -assert(m == e) - --- arithmetic expressions - -s = [=[ -a = 3 / / 2 -]=] ---[=[ -test.lua:1:9: syntax error, unexpected '/', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' -]=] -e = [=[ -test.lua:1:8: malformed multiplication expression -]=] - -r, m = parse(s) -assert(m == e) - --- bitwise expressions - -s = [=[ -b = 1 && 1 -]=] ---[=[ -test.lua:1:8: syntax error, unexpected '&', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' -]=] -e = [=[ -test.lua:1:7: malformed '&' expression -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -b = 1 <> 0 -]=] ---[=[ -test.lua:1:8: syntax error, unexpected '>', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' -]=] -e = [=[ -test.lua:1:7: malformed relational expression -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -b = 1 < < 0 -]=] ---[=[ -test.lua:1:9: syntax error, unexpected '<', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' -]=] -e = [=[ -test.lua:1:8: malformed relational expression -]=] - -r, m = parse(s) -assert(m == e) - --- concatenation expressions - -s = [=[ -concat2 = 2^3..1 -]=] ---[=[ -test.lua:1:15: syntax error, unexpected '.1', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^' -]=] -e = [=[ -test.lua:1:14: malformed -]=] - -r, m = parse(s) -assert(m == e) - --- for generic - -s = [=[ -for k;v in pairs(t) do end -]=] ---[=[ -test.lua:1:6: syntax error, unexpected ';', expecting 'in', ',', ':', '=' -]=] -e = [=[ -test.lua:1:5: expecting 'in' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -for k,v in pairs(t:any) do end -]=] ---[=[ -test.lua:1:23: syntax error, unexpected ')', expecting 'String', '{', '(' -]=] -e = [=[ -test.lua:1:22: expecting '(' for method call -]=] - -r, m = parse(s) -assert(m == e) - --- for numeric - -s = [=[ -for i=1,10, do end -]=] ---[=[ -test.lua:1:13: syntax error, unexpected 'do', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' -]=] -e = [=[ -test.lua:1:10: missing 'do' in for statement -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -for i=1,n:number do end -]=] ---[=[ -test.lua:1:18: syntax error, unexpected 'do', expecting 'String', '{', '(' -]=] -e = [=[ -test.lua:1:17: expecting '(' for method call -]=] - -r, m = parse(s) -assert(m == e) - --- global functions - -s = [=[ -function func(a,b,c,) end -]=] ---[=[ -test.lua:1:21: syntax error, unexpected ')', expecting '...', 'Name' -]=] -e = [=[ -test.lua:1:20: expecting '...' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -function func(...,a) end -]=] ---[=[ -test.lua:1:18: syntax error, unexpected ',', expecting ')', ':' -]=] -e = [=[ -test.lua:1:17: missing ')' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -function a.b:c:d () end -]=] ---[=[ -test.lua:1:15: syntax error, unexpected ':', expecting '(' -]=] -e = [=[ -test.lua:1:14: missing '(' -]=] - -r, m = parse(s) -assert(m == e) - --- goto - -s = [=[ -:: label :: return -goto label -]=] ---[=[ -test.lua:2:1: syntax error, unexpected 'goto', expecting ';', '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' -]=] -e = [=[ -test.lua:2:1: invalid statement after 'return' -]=] - -r, m = parse(s) -assert(m == e) - --- if-else - -s = [=[ -if a then -]=] ---[=[ -test.lua:2:1: syntax error, unexpected 'EOF', expecting 'end', 'else', 'elseif', 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';' -]=] -e = [=[ -test.lua:2:1: missing 'end' to close if statement -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -if a then else -]=] ---[=[ -test.lua:2:1: syntax error, unexpected 'EOF', expecting 'end', 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';' -]=] -e = [=[ -test.lua:2:1: missing 'end' to close if statement -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -if a then - return a -elseif b then - return b -elseif - -end -]=] ---[=[ -test.lua:7:1: syntax error, unexpected 'end', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' -]=] -e = [=[ -test.lua:7:1: expecting after 'elseif' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -if a:any then else end -]=] ---[=[ -test.lua:1:10: syntax error, unexpected 'then', expecting 'String', '{', '(' -]=] -e = [=[ -test.lua:1:9: expecting '(' for method call -]=] - -r, m = parse(s) -assert(m == e) - --- labels - -s = [=[ -:: blah :: -:: not :: -]=] ---[=[ -test.lua:2:4: syntax error, unexpected 'not', expecting 'Name' -]=] -e = [=[ -test.lua:2:3: expecting after '::' -]=] - -r, m = parse(s) -assert(m == e) - --- locals - -s = [=[ -local a = -]=] ---[=[ -test.lua:2:1: syntax error, unexpected 'EOF', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' -]=] -e = [=[ -test.lua:2:1: expecting expression list after '=' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local function t.a() end -]=] ---[=[ -test.lua:1:17: syntax error, unexpected '.', expecting '(' -]=] -e = [=[ -test.lua:1:16: missing '(' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local function test (a,) end -]=] ---[=[ -test.lua:1:24: syntax error, unexpected ')', expecting '...', 'Name' -]=] -e = [=[ -test.lua:1:23: expecting '...' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local function test(...,a) end -]=] ---[=[ -test.lua:1:24: syntax error, unexpected ',', expecting ')', ':' -]=] -e = [=[ -test.lua:1:23: missing ')' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local function (a, b, c, ...) end -]=] ---[=[ -test.lua:1:16: syntax error, unexpected '(', expecting 'Name' -]=] -e = [=[ -test.lua:1:15: expecting in local function declaration -]=] - -r, m = parse(s) -assert(m == e) - --- repeat - -s = [=[ -repeat - a,b,c = 1+1,2+2,3+3 - break -]=] ---[=[ -test.lua:4:1: syntax error, unexpected 'EOF', expecting 'until', 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';' -]=] -e = [=[ -test.lua:4:1: missing 'until' in repeat statement -]=] - -r, m = parse(s) -assert(m == e) - --- return - -s = [=[ -return -return 1 -return 1,1-2*3+4,"alo" -return; -return 1; -return 1,1-2*3+4,"alo"; -]=] ---[=[ -test.lua:2:1: syntax error, unexpected 'return', expecting ';', '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not' -]=] -e = [=[ -test.lua:2:1: invalid statement -]=] - -r, m = parse(s) -assert(m == e) - --- tables - -s = [=[ -t = { , } -]=] ---[=[ -test.lua:1:7: syntax error, unexpected ',', expecting '}', '(', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not', 'Name', '[', 'const' -]=] -e = [=[ -test.lua:1:6: missing '}' -]=] - -r, m = parse(s) -assert(m == e) - --- while - -s = [=[ -i = 0 -while (i < 10) - i = i + 1 -end -]=] ---[=[ -test.lua:3:3: syntax error, unexpected 'i', expecting 'do', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^', 'String', '{', '(', ':', '[', '.' -]=] -e = [=[ -test.lua:3:2: missing 'do' in while statement -]=] - -r, m = parse(s) -assert(m == e) - --- type annotations - -s = [=[ -t[x:any] = 1 -]=] ---[=[ -test.lua:1:8: syntax error, unexpected ']', expecting 'String', '{', '(' -]=] -e = [=[ -test.lua:1:7: expecting '(' for method call -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -x:number, y, z:boolean = 1, nil, true -]=] ---[=[ -test.lua:1:9: syntax error, unexpected ',', expecting 'String', '{', '(' -]=] -e = [=[ -test.lua:1:8: expecting '(' for method call -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -x = x:any -]=] ---[=[ -test.lua:2:1: syntax error, unexpected 'EOF', expecting 'String', '{', '(' -]=] -e = [=[ -test.lua:2:1: expecting '(' for method call -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -x = ...:any -]=] ---[=[ -test.lua:1:8: syntax error, unexpected ':', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^' -]=] -e = [=[ -test.lua:1:7: invalid statement -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -f(x:any) -]=] ---[=[ -test.lua:1:8: syntax error, unexpected ')', expecting 'String', '{', '(' -]=] -e = [=[ -test.lua:1:7: expecting '(' for method call -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -f(...:any) -]=] ---[=[ -test.lua:1:6: syntax error, unexpected ':', expecting ')', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^' -]=] -e = [=[ -test.lua:1:5: missing ')' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local x:number* -]=] ---[=[ -test.lua:1:15: syntax error, unexpected '*', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', '=', ',', '?', '|' -]=] -e = [=[ -test.lua:1:6: invalid local declaration -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local x:number| -]=] ---[=[ -test.lua:2:1: syntax error, unexpected 'EOF', expecting '{', '(', 'Type' -]=] -e = [=[ -test.lua:2:1: expecting after '|' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local x:number?|string? -]=] ---[=[ -test.lua:1:16: syntax error, unexpected '|', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', '=', ',' -]=] -e = [=[ -test.lua:1:6: invalid local declaration -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local x:() -> number -]=] ---[=[ -test.lua:1:15: syntax error, unexpected 'number', expecting '(' -]=] -e = [=[ -test.lua:1:14: expecting after '->' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local x:() -> (number)? | (string)? -]=] ---[=[ -test.lua:1:35: syntax error, unexpected '?', expecting '->' -]=] -e = [=[ -test.lua:1:26: expecting after '|' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local x:{()->():string} -]=] ---[=[ -test.lua:1:16: syntax error, unexpected ':', expecting '}', '?', '|' -]=] -e = [=[ -test.lua:1:15: missing '}' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local x:{string:t 1} -]=] ---[=[ -test.lua:1:19: syntax error, unexpected '1', expecting '}', '?', '|' -]=] -e = [=[ -test.lua:1:18: missing '}' -]=] - -r, m = parse(s) -assert(m == e) - -s = [=[ -local x:{{{{{}}}} -]=] ---[=[ -test.lua:2:1: syntax error, unexpected 'EOF', expecting '}', '?', '|' -]=] -e = [=[ -test.lua:2:1: missing '}' -]=] - -r, m = parse(s) -assert(m == e) - --- syntax errors that depend on some semantic information - --- break - -s = [=[ -break -]=] ---[=[ -test.lua:1:1: syntax error, not inside a loop -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -function f (x) - if 1 then break end -end -]=] ---[=[ -test.lua:2:13: syntax error, not inside a loop -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -while 1 do -end -break -]=] ---[=[ -test.lua:3:1: syntax error, not inside a loop -]=] - -r, m = parse(s) -assert(r == true) - --- goto - -s = [=[ -goto label -]=] ---[=[ -test.lua:1:1: syntax error, no visible label 'label' for -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -goto label -::other_label:: -]=] ---[=[ -test.lua:1:1: syntax error, no visible label 'label' for -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -::other_label:: -do do do goto label end end end -]=] ---[=[ -test.lua:2:10: syntax error, no visible label 'label' for -]=] - -r, m = parse(s) -assert(r == true) - --- interfaces - -s = [=[ -local interface X - x:number - y:number - z:number - x:number -end -]=] ---[=[ -test.lua:1:7: syntax error, attempt to redeclare field 'x' -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local interface X - x, y, z, x:number -end -]=] ---[=[ -test.lua:1:7: syntax error, attempt to redeclare field 'x' -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local interface boolean end -]=] ---[=[ -test.lua:1:7: syntax error, attempt to redeclare type 'boolean' -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local interface number end -]=] ---[=[ -test.lua:1:7: syntax error, attempt to redeclare type 'number' -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local interface string end -]=] ---[=[ -test.lua:1:7: syntax error, attempt to redeclare type 'string' -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local interface value end -]=] ---[=[ -test.lua:1:7: syntax error, attempt to redeclare type 'value' -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local interface any end -]=] ---[=[ -test.lua:1:7: syntax error, attempt to redeclare type 'any' -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local interface self end -]=] ---[=[ -test.lua:1:7: syntax error, attempt to redeclare type 'self' -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local interface const end -]=] ---[=[ -test.lua:1:7: syntax error, attempt to redeclare type 'const' -]=] - -r, m = parse(s) -assert(r == true) - --- labels - -s = [=[ -::label:: -::other_label:: -::label:: -]=] ---[=[ -test.lua:3:1: syntax error, label 'label' already defined -]=] - -r, m = parse(s) -assert(r == true) - --- vararg - -s = [=[ -function f () - return ... -end -]=] ---[=[ -test.lua:2:10: syntax error, cannot use '...' outside a vararg function -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -function f () - function g (x, y) - return ...,...,... - end -end -]=] ---[=[ -test.lua:3:12: syntax error, cannot use '...' outside a vararg function -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local function f (x) - return ... -end -]=] ---[=[ -test.lua:2:10: syntax error, cannot use '...' outside a vararg function -]=] - -r, m = parse(s) -assert(r == true) - -s = [=[ -local f = function (x) - return ... -end -]=] ---[=[ -test.lua:2:10: syntax error, cannot use '...' outside a vararg function -]=] - -r, m = parse(s) -assert(r == true) - -print("OK") diff --git a/examples/typedlua/tlerror.lua b/examples/typedlua/tlerror.lua deleted file mode 100644 index 94be024..0000000 --- a/examples/typedlua/tlerror.lua +++ /dev/null @@ -1,66 +0,0 @@ - -local errors = {} -local function new_error (label, msg) - table.insert(errors, { label = label, msg = msg }) -end - -new_error("Number", "malformed ") -new_error("String", "malformed ") -new_error("LongString", "unfinished long string") -new_error("LongComment", "unfinished long comment") -new_error("MissingOP", "missing '('") -new_error("MissingCP", "missing ')'") -new_error("MissingCC", "missing '}'") -new_error("MissingCB", "missing ']'") -new_error("UnionType", "expecting after '|'") -new_error("FunctionType", "expecting after '->'") -new_error("MethodType", "expecting after '=>'") -new_error("TupleType", "expecting after ','") -new_error("Type", "expecting after ':'") -new_error("TypeDecEnd", "missing 'end' in type declaration") -new_error("TypeAliasName", "expecting after 'typealias'") -new_error("MissingEqTypeAlias", "missing '=' in 'typealias'") -new_error("DotIndex", "expecting after '.'") -new_error("MethodName", "expecting after ':'") -new_error("Then", "missing 'then'") -new_error("IfEnd", "missing 'end' to close if statement") -new_error("WhileDo", "missing 'do' in while statement") -new_error("WhileEnd", "missing 'end' to close while statement") -new_error("BlockEnd", "missing 'end' to close block") -new_error("ForDo", "missing 'do' in for statement") -new_error("ForEnd", "missing 'end' to close for statement") -new_error("Until", "missing 'until' in repeat statement") -new_error("FuncEnd", "missing 'end' to close function declaration") -new_error("ParList", "expecting '...'") -new_error("MethodCall", "expecting '(' for method call") -new_error("Label1", "expecting after '::'") -new_error("Label2", "expecting '::' to close label declaration") -new_error("LocalAssign1", "expecting expression list after '='") -new_error("LocalAssign2", "invalid local declaration") -new_error("ForGen", "expecting 'in'") -new_error("LocalFunc", "expecting in local function declaration") -new_error("RetStat", "invalid statement after 'return'") -new_error("ElseIf", "expecting after 'elseif'") -new_error("SubExpr_1", "malformed 'or' expression") -new_error("SubExpr_2", "malformed 'and' expression") -new_error("SubExpr_3", "malformed relational expression") -new_error("SubExpr_4", "malformed '|' expression") -new_error("SubExpr_5", "malformed '~' expression") -new_error("SubExpr_6", "malformed '&' expression") -new_error("SubExpr_7", "malformed shift expression") -new_error("SubExpr_8", "malformed '..' expression") -new_error("SubExpr_9", "malformed addition expression") -new_error("SubExpr_10", "malformed multiplication expression") -new_error("SubExpr_11", "malformed unary expression") -new_error("SubExpr_12", "malformed '^' expression") -new_error("Stat", "invalid statement") - -local labels = {} -for k, v in ipairs(errors) do - labels[v.label] = k -end - -return { - errors = errors, - labels = labels, -} diff --git a/examples/typedlua/tllexer.lua b/examples/typedlua/tllexer.lua deleted file mode 100644 index 96f296d..0000000 --- a/examples/typedlua/tllexer.lua +++ /dev/null @@ -1,105 +0,0 @@ -local tllexer = {} - -local lpeg = require "lpeglabel" -lpeg.locale(lpeg) - -local tlerror = require "tlerror" - -function tllexer.try (pat, label) - return pat + lpeg.T(tlerror.labels[label]) -end - -local function setffp (s, i, t, n) - if not t.ffp or i > t.ffp then - t.ffp = i - t.list = {} - t.list[n] = true - t.expected = "'" .. n .. "'" - elseif i == t.ffp then - if not t.list[n] then - t.list[n] = true - t.expected = "'" .. n .. "', " .. t.expected - end - end - return false -end - -local function updateffp (name) - return lpeg.Cmt(lpeg.Carg(1) * lpeg.Cc(name), setffp) -end - -tllexer.Shebang = lpeg.P("#") * (lpeg.P(1) - lpeg.P("\n"))^0 * lpeg.P("\n") - -local Space = lpeg.space^1 - -local Equals = lpeg.P("=")^0 -local Open = "[" * lpeg.Cg(Equals, "init") * "[" * lpeg.P("\n")^-1 -local Close = "]" * lpeg.C(Equals) * "]" -local CloseEQ = lpeg.Cmt(Close * lpeg.Cb("init"), - function (s, i, a, b) return a == b end) - -local LongString = Open * (lpeg.P(1) - CloseEQ)^0 * tllexer.try(Close, "LongString") / - function (s, o) return s end - -local LongStringCm1 = Open * (lpeg.P(1) - CloseEQ)^0 * Close / - function (s, o) return s end - -local Comment = lpeg.Rec(lpeg.P"--" * #Open * (LongStringCm1 / function() return end + lpeg.T(tlerror.labels["LongString"])), - lpeg.T(tlerror.labels["LongComment"]), tlerror.labels["LongString"]) + - lpeg.P("--") * (lpeg.P(1) - lpeg.P("\n"))^0 - -tllexer.Skip = (Space + Comment)^0 - -local idStart = lpeg.alpha + lpeg.P("_") -local idRest = lpeg.alnum + lpeg.P("_") - -local Keywords = lpeg.P("and") + "break" + "do" + "elseif" + "else" + "end" + - "false" + "for" + "function" + "goto" + "if" + "in" + - "local" + "nil" + "not" + "or" + "repeat" + "return" + - "then" + "true" + "until" + "while" - -tllexer.Reserved = Keywords * -idRest - -local Identifier = idStart * idRest^0 - -tllexer.Name = -tllexer.Reserved * Identifier * -idRest - -function tllexer.token (pat, name) - return pat * tllexer.Skip + updateffp(name) * lpeg.P(false) -end - -function tllexer.symb (str) - return tllexer.token(lpeg.P(str), str) -end - -function tllexer.kw (str) - return tllexer.token(lpeg.P(str) * -idRest, str) -end - -local Hex = (lpeg.P("0x") + lpeg.P("0X")) * tllexer.try(lpeg.xdigit^1, "Number") -local Expo = lpeg.S("eE") * lpeg.S("+-")^-1 * tllexer.try(lpeg.digit^1, "Number") -local Float = (((lpeg.digit^1 * lpeg.P(".") * lpeg.digit^0 * tllexer.try(-lpeg.P("."), "Number")) + - (lpeg.P(".") * lpeg.digit^1)) * Expo^-1) + - (lpeg.digit^1 * Expo) -local Int = lpeg.digit^1 - -tllexer.Number = Hex + Float + Int - -local ShortString = lpeg.P('"') * - ((lpeg.P('\\') * lpeg.P(1)) + (lpeg.P(1) - lpeg.P('"')))^0 * - tllexer.try(lpeg.P('"'), "String") + - lpeg.P("'") * - ((lpeg.P("\\") * lpeg.P(1)) + (lpeg.P(1) - lpeg.P("'")))^0 * - tllexer.try(lpeg.P("'"), "String") - -tllexer.String = LongString + ShortString - --- for error reporting -tllexer.OneWord = tllexer.Name + - tllexer.Number + - tllexer.String + - tllexer.Reserved + - lpeg.P("...") + - lpeg.P(1) - -return tllexer diff --git a/examples/typedlua/tlp.lua b/examples/typedlua/tlp.lua deleted file mode 100644 index 2a4a736..0000000 --- a/examples/typedlua/tlp.lua +++ /dev/null @@ -1,20 +0,0 @@ -local tlparser = require "tlparser" - -local function getcontents(filename) - file = assert(io.open(filename, "r")) - contents = file:read("*a") - file:close() - return contents -end - -if #arg ~= 1 then - print ("Usage: lua tlp.lua ") - os.exit(1) -end - -local filename = arg[1] -local subject = getcontents(filename) -local r, msg = tlparser.parse(subject, filename, false, true) -if not r then print(msg) end - -os.exit(0) diff --git a/examples/typedlua/tlparser.lua b/examples/typedlua/tlparser.lua deleted file mode 100644 index 2ede2eb..0000000 --- a/examples/typedlua/tlparser.lua +++ /dev/null @@ -1,245 +0,0 @@ -local tlparser = {} - -local lpeg = require "lpeglabel" -lpeg.locale(lpeg) - -local tllexer = require "tllexer" -local tlerror = require "tlerror" - -local function chainl1 (pat, sep, label) - return pat * (sep * tllexer.try(pat, label))^0 -end - -local G = lpeg.P { "TypedLua"; - TypedLua = tllexer.Shebang^-1 * tllexer.Skip * lpeg.V("Chunk") * tllexer.try(-1, "Stat"); - -- type language - Type = lpeg.V("NilableType"); - NilableType = lpeg.V("UnionType") * tllexer.symb("?")^-1; - UnionType = lpeg.V("PrimaryType") * (tllexer.symb("|") * tllexer.try(lpeg.V("PrimaryType"), "UnionType"))^0; - PrimaryType = lpeg.V("LiteralType") + - lpeg.V("BaseType") + - lpeg.V("NilType") + - lpeg.V("ValueType") + - lpeg.V("AnyType") + - lpeg.V("SelfType") + - lpeg.V("FunctionType") + - lpeg.V("TableType") + - lpeg.V("VariableType"); - LiteralType = tllexer.token("false", "false") + - tllexer.token("true", "true") + - tllexer.token(tllexer.Number, "Number") + - tllexer.token(tllexer.String, "String"); - BaseType = tllexer.token("boolean", "boolean") + - tllexer.token("number", "number") + - tllexer.token("string", "string") + - tllexer.token("integer", "integer"); - NilType = tllexer.token("nil", "nil"); - ValueType = tllexer.token("value", "value"); - AnyType = tllexer.token("any", "any"); - SelfType = tllexer.token("self", "self"); - FunctionType = lpeg.V("InputType") * tllexer.symb("->") * tllexer.try(lpeg.V("NilableTuple"), "FunctionType"); - MethodType = lpeg.V("InputType") * tllexer.symb("=>") * tllexer.try(lpeg.V("NilableTuple"), "MethodType"); - InputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP"); - NilableTuple = lpeg.V("UnionlistType") * tllexer.symb("?")^-1; - UnionlistType = lpeg.V("OutputType") * (tllexer.symb("|") * tllexer.try(lpeg.V("OutputType"), "UnionType"))^0; - OutputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP"); - TupleType = lpeg.V("Type") * (tllexer.symb(",") * tllexer.try(lpeg.V("Type"), "TupleType"))^0 * tllexer.symb("*")^-1; - TableType = tllexer.symb("{") * lpeg.V("TableTypeBody")^-1 * tllexer.try(tllexer.symb("}"), "MissingCC"); - TableTypeBody = lpeg.V("RecordType") + - lpeg.V("HashType") + - lpeg.V("ArrayType"); - RecordType = lpeg.V("RecordField") * (tllexer.symb(",") * lpeg.V("RecordField"))^0 * - (tllexer.symb(",") * (lpeg.V("HashType") + lpeg.V("ArrayType")))^-1; - RecordField = tllexer.kw("const")^-1 * - lpeg.V("LiteralType") * tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type"); - HashType = lpeg.V("KeyType") * tllexer.symb(":") * tllexer.try(lpeg.V("FieldType"), "Type"); - ArrayType = lpeg.V("FieldType"); - KeyType = lpeg.V("BaseType") + lpeg.V("ValueType") + lpeg.V("AnyType"); - FieldType = lpeg.V("Type"); - VariableType = tllexer.token(tllexer.Name, "Name"); - RetType = lpeg.V("NilableTuple") + - lpeg.V("Type"); - Id = tllexer.token(tllexer.Name, "Name"); - TypeDecId = (tllexer.kw("const") * lpeg.V("Id")) + - lpeg.V("Id"); - IdList = lpeg.V("TypeDecId") * (tllexer.symb(",") * tllexer.try(lpeg.V("TypeDecId"), "TupleType"))^0; - IdDec = lpeg.V("IdList") * tllexer.symb(":") * tllexer.try((lpeg.V("Type") + lpeg.V("MethodType")), "Type"); - IdDecList = (lpeg.V("IdDec")^1)^-1; - TypeDec = tllexer.token(tllexer.Name, "Name") * lpeg.V("IdDecList") * tllexer.try(tllexer.kw("end"), "TypeDecEnd"); - Interface = tllexer.kw("interface") * lpeg.V("TypeDec") + - tllexer.kw("typealias") * - tllexer.try(tllexer.token(tllexer.Name, "Name"), "TypeAliasName") * - tllexer.try(tllexer.symb("="), "MissingEqTypeAlias") * lpeg.V("Type"); - -- parser - Chunk = lpeg.V("Block"); - StatList = (tllexer.symb(";") + lpeg.V("Stat"))^0; - Var = lpeg.V("Id"); - TypedId = tllexer.token(tllexer.Name, "Name") * (tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type"))^-1; - FunctionDef = tllexer.kw("function") * lpeg.V("FuncBody"); - FieldSep = tllexer.symb(",") + tllexer.symb(";"); - Field = ((tllexer.symb("[") * lpeg.V("Expr") * tllexer.try(tllexer.symb("]"), "MissingCB")) + - (tllexer.token(tllexer.Name, "Name"))) * - tllexer.symb("=") * lpeg.V("Expr") + - lpeg.V("Expr"); - TField = (tllexer.kw("const") * lpeg.V("Field")) + - lpeg.V("Field"); - FieldList = (lpeg.V("TField") * (lpeg.V("FieldSep") * lpeg.V("TField"))^0 * - lpeg.V("FieldSep")^-1)^-1; - Constructor = tllexer.symb("{") * lpeg.V("FieldList") * tllexer.try(tllexer.symb("}"), "MissingCC"); - NameList = lpeg.V("TypedId") * (tllexer.symb(",") * lpeg.V("TypedId"))^0; - ExpList = lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0; - FuncArgs = tllexer.symb("(") * - (lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 * - tllexer.try(tllexer.symb(")"), "MissingCP") + - lpeg.V("Constructor") + - tllexer.token(tllexer.String, "String"); - OrOp = tllexer.kw("or"); - AndOp = tllexer.kw("and"); - RelOp = tllexer.symb("~=") + - tllexer.symb("==") + - tllexer.symb("<=") + - tllexer.symb(">=") + - tllexer.symb("<") + - tllexer.symb(">"); - BOrOp = tllexer.symb("|"); - BXorOp = tllexer.symb("~") * -lpeg.P("="); - BAndOp = tllexer.symb("&"); - ShiftOp = tllexer.symb("<<") + - tllexer.symb(">>"); - ConOp = tllexer.symb(".."); - AddOp = tllexer.symb("+") + - tllexer.symb("-"); - MulOp = tllexer.symb("*") + - tllexer.symb("//") + - tllexer.symb("/") + - tllexer.symb("%"); - UnOp = tllexer.kw("not") + - tllexer.symb("-") + - tllexer.symb("~") + - tllexer.symb("#"); - PowOp = tllexer.symb("^"); - Expr = lpeg.V("SubExpr_1"); - SubExpr_1 = chainl1(lpeg.V("SubExpr_2"), lpeg.V("OrOp"), "SubExpr_1"); - SubExpr_2 = chainl1(lpeg.V("SubExpr_3"), lpeg.V("AndOp"), "SubExpr_2"); - SubExpr_3 = chainl1(lpeg.V("SubExpr_4"), lpeg.V("RelOp"), "SubExpr_3"); - SubExpr_4 = chainl1(lpeg.V("SubExpr_5"), lpeg.V("BOrOp"), "SubExpr_4"); - SubExpr_5 = chainl1(lpeg.V("SubExpr_6"), lpeg.V("BXorOp"), "SubExpr_5"); - SubExpr_6 = chainl1(lpeg.V("SubExpr_7"), lpeg.V("BAndOp"), "SubExpr_6"); - SubExpr_7 = chainl1(lpeg.V("SubExpr_8"), lpeg.V("ShiftOp"), "SubExpr_7"); - SubExpr_8 = lpeg.V("SubExpr_9") * lpeg.V("ConOp") * tllexer.try(lpeg.V("SubExpr_8"), "SubExpr_8") + - lpeg.V("SubExpr_9"); - SubExpr_9 = chainl1(lpeg.V("SubExpr_10"), lpeg.V("AddOp"), "SubExpr_9"); - SubExpr_10 = chainl1(lpeg.V("SubExpr_11"), lpeg.V("MulOp"), "SubExpr_10"); - SubExpr_11 = lpeg.V("UnOp") * tllexer.try(lpeg.V("SubExpr_11"), "SubExpr_11") + - lpeg.V("SubExpr_12"); - SubExpr_12 = lpeg.V("SimpleExp") * (lpeg.V("PowOp") * tllexer.try(lpeg.V("SubExpr_11"), "SubExpr_12"))^-1; - SimpleExp = tllexer.token(tllexer.Number, "Number") + - tllexer.token(tllexer.String, "String") + - tllexer.kw("nil") + - tllexer.kw("false") + - tllexer.kw("true") + - tllexer.symb("...") + - lpeg.V("FunctionDef") + - lpeg.V("Constructor") + - lpeg.V("SuffixedExp"); - SuffixedExp = lpeg.V("PrimaryExp") * ( - (tllexer.symb(".") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "DotIndex")) / "index" + - (tllexer.symb("[") * lpeg.V("Expr") * tllexer.try(tllexer.symb("]"), "MissingCB")) / "index" + - (tllexer.symb(":") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "MethodName") * tllexer.try(lpeg.V("FuncArgs"), "MethodCall")) / "call" + - lpeg.V("FuncArgs") / "call")^0 / function (...) local l = {...}; return l[#l] end; - PrimaryExp = lpeg.V("Var") / "var" + - tllexer.symb("(") * lpeg.V("Expr") * tllexer.try(tllexer.symb(")"), "MissingCP"); - Block = lpeg.V("StatList") * lpeg.V("RetStat")^-1; - IfStat = tllexer.kw("if") * lpeg.V("Expr") * tllexer.try(tllexer.kw("then"), "Then") * lpeg.V("Block") * - (tllexer.kw("elseif") * tllexer.try(lpeg.V("Expr"), "ElseIf") * tllexer.try(tllexer.kw("then"), "Then") * lpeg.V("Block"))^0 * - (tllexer.kw("else") * lpeg.V("Block"))^-1 * - tllexer.try(tllexer.kw("end"), "IfEnd"); - WhileStat = tllexer.kw("while") * lpeg.V("Expr") * - tllexer.try(tllexer.kw("do"), "WhileDo") * lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "WhileEnd"); - DoStat = tllexer.kw("do") * lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "BlockEnd"); - ForBody = tllexer.try(tllexer.kw("do"), "ForDo") * lpeg.V("Block"); - ForNum = lpeg.V("Id") * tllexer.symb("=") * lpeg.V("Expr") * tllexer.symb(",") * - lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^-1 * - lpeg.V("ForBody"); - ForGen = lpeg.V("NameList") * tllexer.try(tllexer.kw("in"), "ForGen") * - lpeg.V("ExpList") * lpeg.V("ForBody"); - ForStat = tllexer.kw("for") * (lpeg.V("ForNum") + lpeg.V("ForGen")) * tllexer.try(tllexer.kw("end"), "ForEnd"); - RepeatStat = tllexer.kw("repeat") * lpeg.V("Block") * - tllexer.try(tllexer.kw("until"), "Until") * lpeg.V("Expr"); - FuncName = lpeg.V("Id") * (tllexer.symb(".") * - (tllexer.token(tllexer.Name, "Name")))^0 * - (tllexer.symb(":") * (tllexer.token(tllexer.Name, "Name")))^-1; - ParList = lpeg.V("NameList") * (tllexer.symb(",") * tllexer.try(lpeg.V("TypedVarArg"), "ParList"))^-1 + - lpeg.V("TypedVarArg"); - TypedVarArg = tllexer.symb("...") * (tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type"))^-1; - FuncBody = tllexer.try(tllexer.symb("("), "MissingOP") * lpeg.V("ParList")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP") * - (tllexer.symb(":") * tllexer.try(lpeg.V("RetType"), "Type"))^-1 * - lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "FuncEnd"); - FuncStat = tllexer.kw("const")^-1 * - tllexer.kw("function") * lpeg.V("FuncName") * lpeg.V("FuncBody"); - LocalFunc = tllexer.kw("function") * - tllexer.try(lpeg.V("Id"), "LocalFunc") * lpeg.V("FuncBody"); - LocalAssign = lpeg.V("NameList") * tllexer.symb("=") * tllexer.try(lpeg.V("ExpList"), "LocalAssign1") + - lpeg.V("NameList") * (#(-tllexer.symb("=") * (lpeg.V("Stat") + -1)) * lpeg.P(true)) + lpeg.T(tlerror.labels["LocalAssign2"]); - LocalStat = tllexer.kw("local") * - (lpeg.V("LocalTypeDec") + lpeg.V("LocalFunc") + lpeg.V("LocalAssign")); - LabelStat = tllexer.symb("::") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "Label1") * tllexer.try(tllexer.symb("::"), "Label2"); - BreakStat = tllexer.kw("break"); - GoToStat = tllexer.kw("goto") * tllexer.token(tllexer.Name, "Name"); - RetStat = tllexer.kw("return") * tllexer.try(-lpeg.V("Stat"), "RetStat") * - (lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 * - tllexer.symb(";")^-1; - TypeDecStat = lpeg.V("Interface"); - LocalTypeDec = lpeg.V("TypeDecStat"); - LVar = (tllexer.kw("const") * lpeg.V("SuffixedExp")) + - lpeg.V("SuffixedExp"); - ExprStat = lpeg.Cmt(lpeg.V("LVar") * lpeg.V("Assignment"), - function (s, i, ...) - local l = {...} - local i = 1 - while l[i] ~= "=" do - local se = l[i] - if se ~= "var" and se ~= "index" then return false end - i = i + 1 - end - return true - end) + - lpeg.Cmt(lpeg.V("SuffixedExp"), - function (s, i, se) - if se ~= "call" then return false end - return true - end); - Assignment = ((tllexer.symb(",") * lpeg.V("LVar"))^1)^-1 * (tllexer.symb("=") / "=") * lpeg.V("ExpList"); - Stat = lpeg.V("IfStat") + lpeg.V("WhileStat") + lpeg.V("DoStat") + lpeg.V("ForStat") + - lpeg.V("RepeatStat") + lpeg.V("FuncStat") + lpeg.V("LocalStat") + - lpeg.V("LabelStat") + lpeg.V("BreakStat") + lpeg.V("GoToStat") + - lpeg.V("TypeDecStat") + lpeg.V("ExprStat"); -} - -local function lineno (s, i) - if i == 1 then return 1, 1 end - local rest, num = s:sub(1,i):gsub("[^\n]*\n", "") - local r = #rest - return 1 + num, r ~= 0 and r or 1 -end - -function tlparser.parse (subject, filename, strict, integer) - local errorinfo = {} - lpeg.setmaxstack(1000) - local ast, label, pos = lpeg.match(G, subject, nil, errorinfo, strict, integer) - if not ast then - local line, col = lineno(subject, pos) - local error_msg = string.format("%s:%d:%d: ", filename, line, col) - if label ~= 0 then - error_msg = error_msg .. tlerror.errors[label].msg - else - local u = lpeg.match(lpeg.C(tllexer.OneWord) + lpeg.Cc("EOF"), subject, errorinfo.ffp) - error_msg = error_msg .. string.format("unexpected '%s', expecting %s", u, errorinfo.expected) - end - return nil, error_msg - else - return true - end -end - -return tlparser -- cgit v1.2.3-55-g6feb