aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSérgio Queiroz <sqmedeiros@gmail.com>2017-12-29 13:51:36 -0300
committerSérgio Queiroz <sqmedeiros@gmail.com>2017-12-29 13:51:36 -0300
commit19119a91005506ec2133948f3a127e68b6e93f30 (patch)
tree9f5ff03b6ddde8454f398e01229b889b469de996
parent261e41117c2ec8d50b9aff1ecaaa701d2af5c211 (diff)
downloadlpeglabel-19119a91005506ec2133948f3a127e68b6e93f30.tar.gz
lpeglabel-19119a91005506ec2133948f3a127e68b6e93f30.tar.bz2
lpeglabel-19119a91005506ec2133948f3a127e68b6e93f30.zip
Updating the documentation
-rw-r--r--README.md766
-rw-r--r--examples/listId2.lua16
-rw-r--r--examples/listId2Rec2Cap.lua20
-rw-r--r--examples/listId3.lua35
-rw-r--r--examples/tiny.lua5
-rw-r--r--examples/toast.lua16
-rwxr-xr-xexamples/typedlua/test.lua2572
-rw-r--r--examples/typedlua/tlerror.lua66
-rw-r--r--examples/typedlua/tllexer.lua105
-rw-r--r--examples/typedlua/tlp.lua20
-rw-r--r--examples/typedlua/tlparser.lua245
11 files changed, 314 insertions, 3552 deletions
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.
17 17
18Besides that, LPegLabel also reports the farthest 18Besides that, LPegLabel also reports the farthest
19failure position in case of an ordinary failure 19failure position in case of an ordinary failure
20(which is represented by label **0**). 20(which is represented by label **fail**).
21 21
22This document describes the new functions available 22This document describes the new functions available
23in LpegLabel and presents some examples of usage. 23in LpegLabel and presents some examples of usage.
@@ -27,13 +27,13 @@ between an ordinary failure and an error. Usually, an
27ordinary failure is produced when the matching of a 27ordinary failure is produced when the matching of a
28character fails, and this failure is caught by ordered choice. 28character fails, and this failure is caught by ordered choice.
29An error (a non-ordinary failure), by its turn, is produced 29An error (a non-ordinary failure), by its turn, is produced
30by the throw operator and may be caught by the recovery operator. 30by the throw operator and may be caught by a recovery rule.
31 31
32In LPegLabel, the result of an unsuccessful matching 32In LPegLabel, the result of an unsuccessful matching
33is a triple **nil, lab, errpos**, where **lab** 33is a triple **nil, lab, errpos**, where **lab**
34is the label associated with the failure, and 34is the label associated with the failure (a string or
35**errpos** is the input position being matched when 35an integer), and **errpos** is the input position being
36**lab** was thrown. 36matched when **lab** was thrown.
37 37
38When **lab** is an ordinary failure and no error was thrown before, 38When **lab** is an ordinary failure and no error was thrown before,
39**errpos** is the farthest position where an ordinary failure occurred. 39**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:
47<tbody><tr><td><b>Function</b></td><td><b>Description</b></td></tr> 47<tbody><tr><td><b>Function</b></td><td><b>Description</b></td></tr>
48<tr><td><a href="#f-t"><code>lpeglabel.T (l)</code></a></td> 48<tr><td><a href="#f-t"><code>lpeglabel.T (l)</code></a></td>
49 <td>Throws a label <code>l</code> to signal an error</td></tr> 49 <td>Throws a label <code>l</code> to signal an error</td></tr>
50<tr><td><a href="#f-rec"><code>lpeglabel.Rec (p1, p2, l1 [, l2, ..., ln])</code></a></td>
51 <td>Specifies a recovery pattern <code>p2</code> for <code>p1</code>,
52 when the matching of <code>p1</code> gives one of the labels l1, ..., ln.</td></tr>
53<tr><td><a href="#f-lc"><code>lpeglabel.Lc (p1, p2, l1, ..., ln)</code></a></td>
54 <td>Matches <code>p1</code> and tries to match <code>p2</code>
55 if the matching of <code>p1</code> gives one of l<sub>1</sub>, ..., l<sub>n</sub>
56 </td></tr>
57<tr><td><a href="#re-t"><code>%{l}</code></a></td> 50<tr><td><a href="#re-t"><code>%{l}</code></a></td>
58 <td>Syntax of <em>relabel</em> module. Equivalent to <code>lpeglabel.T(l)</code> 51 <td>Syntax of <em>relabel</em> module. Equivalent to <code>lpeglabel.T(l)</code>
59 </td></tr> 52 </td></tr>
60<tr><td><a href="#re-pow"><code>p^l</code></a></td> 53<tr><td><a href="#re-pow"><code>p^l</code></a></td>
61 <td>Syntax sugar available at <em>relabel</em> for <code>p / %{l}</code> 54 <td>Syntax sugar available at <em>relabel</em> for <code>p / %{l}</code>
62 </td></tr> 55 </td></tr>
63<tr><td><a href="#re-rec"><code>p1 //{l1 [, l2, ..., ln} p2</code></a></td>
64 <td>Syntax of <em>relabel</em> module. Equivalent to <code>lpeglabel.Rec(p1, p2, l1, ..., ln)</code>
65 </td></tr>
66<tr><td><a href="#re-lc"><code>p1 /{l1, ..., ln} p2</code></a></td>
67 <td>Syntax of <em>relabel</em> module. Equivalent to <code>lpeg.Lc(p1, p2, l1, ..., ln)</code>
68 </td></tr>
69<tr><td><a href="#re-line"><code>relabel.calcline(subject, i)</code></a></td> 56<tr><td><a href="#re-line"><code>relabel.calcline(subject, i)</code></a></td>
70 <td>Calculates line and column information regarding position <i>i</i> of the subject</code> 57 <td>Calculates line and column information regarding position <i>i</i> of the subject</code>
71 </td></tr> 58 </td></tr>
72<tr><td><a href="#re-setl"><code>relabel.setlabels (tlabel)</code></a></td>
73 <td>Allows to specicify a table with mnemonic labels.
74 </td></tr>
75</tbody></table> 59</tbody></table>
76 60
77 61
@@ -80,60 +64,39 @@ Below there is a brief summary of the new functions provided by LpegLabel:
80 64
81#### <a name="f-t"></a><code>lpeglabel.T(l)</code> 65#### <a name="f-t"></a><code>lpeglabel.T(l)</code>
82 66
83Returns a pattern that throws the label `l`. 67Returns a pattern that throws the label `l`, which
84A label must be an integer between 1 and 255. 68can be an integer or a string.
85
86This pattern always causes a failure, whose associated
87position will be used to set **errpos**, no matter
88whether this is the farthest failure position or not.
89
90
91#### <a name="f-rec"></a><code>lpeglabel.Rec(p1, p2, l1, ..., ln)</code>
92
93Returns a *recovery pattern*.
94If the matching of `p1` gives one of the labels `l1, ..., ln`,
95then the matching of `p2` is tried from the failure position of `p1`.
96Otherwise, the result of the matching of `p1` is the pattern's result.
97
98
99#### <a name="f-lc"></a><code>lpeglabel.Lc(p1, p2, l1, ..., ln)</code>
100
101Returns a pattern equivalent to a *labeled ordered choice*.
102If the matching of `p1` gives one of the labels `l1, ..., ln`,
103then the matching of `p2` is tried from the same position. Otherwise,
104the result of the matching of `p1` is the pattern's result.
105 69
106<!--- 70When a label is thrown, the current subject position
107The labeled ordered choice `lpeg.Lc(p1, p2, 0)` is equivalent to the 71is used to set **errpos**, no matter whether it is the
108regular ordered choice `p1 / p2`. 72fartherst failure position or not.
109-->
110 73
111Although PEG's ordered choice is associative, the labeled ordered choice is not. 74In case the PEG grammar has a rule `l`, after a label is thrown
112When using this function, the user should take care to build a left-associative 75this rule will be used as a recovery rule, otherwise the whole
113labeled ordered choice pattern. 76matching fails.
77
78The recovery rule will try to match the input from the subject
79position where `l` was thrown. In case the matching of the recovery
80rule succeeds, the regular matching is resumed. Otherwise, the
81result of the recovery rule is the matching result.
82
83When we have a predicate such as `-p` or `#p` and a label `l` is thrown
84during the matching of `p`, this causes the failure of `p`, but does
85not propagate `l`, or calls its associated recovery rule.
114 86
115 87
116#### <a name="re-t"></a><code>%{l}</code> 88#### <a name="re-t"></a><code>%{l}</code>
117 89
118Syntax of *relabel* module. Equivalent to `lpeg.T(l)`. 90Syntax of *relabel* module. Equivalent to `lpeg.T(l)`.
119 91
92Label `l` must be a valid identifier name.
120 93
121#### <a name="re-rec"></a><code>p1 //{l1, ..., ln} p2</code> 94#### <a name="re-pow"></a><code>p^l</code>
122
123Syntax of *relabel* module. Equivalent to `lpeglabel.Rec(p1, p2, l1, ..., ln)`.
124
125The `//{}` operator is left-associative.
126
127 95
128#### <a name="re-lc"></a><code>p1 /{l1, ..., ln} p2</code> 96Syntax of *relabel* module. The pattern `p^l` is equivalent
97to `p / lpeglabel.T(l)`.
129 98
130Syntax of *relabel* module. Equivalent to `lpeg.Lc(p1, p2, l1, ..., ln)`. 99Label `l` must be a valid identifier name.
131
132The `/{}` operator is left-associative.
133
134A grammar can use both choice operators (`/` and `/{}`),
135but a single choice can not mix them. That is, the parser of `relabel`
136module will not recognize a pattern as `p1 / p2 /{l1} p3`.
137 100
138 101
139#### <a name="re-line"></a><code>relabel.calcline (subject, i)</code> 102#### <a name="re-line"></a><code>relabel.calcline (subject, i)</code>
@@ -141,12 +104,6 @@ module will not recognize a pattern as `p1 / p2 /{l1} p3`.
141Returns line and column information regarding position <i>i</i> of the subject. 104Returns line and column information regarding position <i>i</i> of the subject.
142 105
143 106
144#### <a name="re-setl"></a><code>relabel.setlabels (tlabel)</code>
145
146Allows to specicify a table with labels. They keys of
147`tlabel` must be strings and the associated values must
148be integers between 1 and 255.
149
150 107
151### Examples 108### Examples
152 109
@@ -159,9 +116,9 @@ in the *examples* directory.
159 116
160This example illustrates the new values returned 117This example illustrates the new values returned
161by the *match* function in case of an unsuccessful 118by the *match* function in case of an unsuccessful
162matching. As no error is thrown, when the matching 119matching. As no error is thrown in this example,
163fails *errpos* represents the farthest suffix where 120when the matching fails *errpos* represents the
164an ordinary failure occurred. 121farthest suffix where an ordinary failure occurred.
165 122
166```lua 123```lua
167local m = require'lpeglabel' 124local m = require'lpeglabel'
@@ -172,124 +129,165 @@ function matchPrint(p, s)
172end 129end
173 130
174local p = m.P"a"^0 * m.P"b" + m.P"c" 131local p = m.P"a"^0 * m.P"b" + m.P"c"
175matchPrint(p, "abc") --> r: 3 lab: nil errpos: nil 132matchPrint(p, "abc") --> r: 3 lab: nil errpos: nil
176matchPrint(p, "c") --> r: 2 lab: nil errpos: nil 133matchPrint(p, "c") --> r: 2 lab: nil errpos: nil
177matchPrint(p, "aac") --> r: nil lab: 0 errpos: 3 134matchPrint(p, "aac") --> r: nil lab: fail errpos: 3
178matchPrint(p, "xxc") --> r: nil lab: 0 errpos: 1 135matchPrint(p, "xxc") --> r: nil lab: fail errpos: 1
179``` 136```
180 137
181 138
182#### Matching a list of identifiers separated by commas 139#### Matching a list of identifiers separated by commas
183 140
184The following example defines a grammar that matches 141The following example defines a grammar that matches
185a list of identifiers separated by commas. A label 142a (possibly empty) list of identifiers separated by commas.
186is thrown when there is an error matching an identifier 143A label is thrown when there is no identifier after a comma,
187or a comma. 144or when the whole input is not matched.
188
189We use function `newError` to store error messages in a
190table and to return the index associated with each error message.
191 145
192 146
193```lua 147```lua
194local m = require'lpeglabel' 148local m = require'lpeglabel'
195local re = require'relabel' 149local re = require'relabel'
196 150
197local terror = {} 151local terror = {
198 152 ErrId = "expecting an identifier",
199local function newError(s) 153 ErrEnd = "expecting EOF",
200 table.insert(terror, s) 154 fail = "undefined"
201 return #terror 155}
202end
203 156
204local errUndef = newError("undefined") 157local id = m.R'az'^1
205local errId = newError("expecting an identifier")
206local errComma = newError("expecting ','")
207 158
208local g = m.P{ 159local g = m.P{
209 "S", 160 'S',
210 S = m.V"Id" * m.V"List", 161 S = m.V'List' * (-m.P(1) + m.T'ErrEnd'),
211 List = -m.P(1) + (m.V"Comma" + m.T(errComma)) * (m.V"Id" + m.T(errId)) * m.V"List", 162 List = m.V'Id' * (m.V'Comma' * (m.V'Id' + m.T'ErrId'))^0,
212 Id = m.V"Sp" * m.R'az'^1, 163 Id = m.V'Sp' * id,
213 Comma = m.V"Sp" * ",", 164 Comma = m.V'Sp' * ',',
214 Sp = m.S" \n\t"^0, 165 Sp = m.S' \n\t'^0,
215} 166}
216 167
168
217function mymatch (g, s) 169function mymatch (g, s)
218 local r, e, sfail = g:match(s) 170 local r, e, pos = g:match(s)
219 if not r then 171 if not r then
220 local line, col = re.calcline(s, #s - #sfail) 172 local line, col = re.calcline(s, pos)
221 local msg = "Error at line " .. line .. " (col " .. col .. "): " 173 local msg = "Error at line " .. line .. " (col " .. col .. "): "
222 return r, msg .. terror[e] .. " before '" .. sfail .. "'" 174 return r, msg .. terror[e] .. " before '" .. s:sub(pos) .. "'"
223 end 175 end
224 return r 176 return r
225end 177end
226 178
227print(mymatch(g, "one,two")) --> 8 179print(mymatch(g, "one,two"))
228print(mymatch(g, "one two")) --> nil Error at line 1 (col 3): expecting ',' before ' two' 180print(mymatch(g, "one two"))
229print(mymatch(g, "one,\n two,\nthree,")) --> nil Error at line 3 (col 6): expecting an identifier before '' 181print(mymatch(g, "one,\n two,\nthree,4"))
230``` 182```
231 183
232In this example we could think about writing rule <em>List</em> as follows: 184In this example we could think about writing rule <em>List</em> as follows:
233```lua 185```lua
234List = ((m.V"Comma" + m.T(errComma)) * (m.V"Id" + m.T(errId)))^0, 186List = m.V'Id' * ((m.V'Comma' + m.T'ErrComma') * (m.V'Id' + m.T'ErrId'))^0,
235``` 187```
236 188
237but when matching this expression against the end of input 189but when matching <code>m.V'Comma' + m.T'ErrComma'</code> against the end of input
238we would get a failure whose associated label would be **errComma**, 190we would get a failure whose associated label would be **errComma**,
239and this would cause the failure of the *whole* repetition. 191and this would cause the failure of the *whole* repetition.
240 192
193Below we rewrite the previous grammar to indicate an error when there is no
194comma after an identifer. Before tyring to match a comma, we check if
195we have reached the end of input:
196
197```lua
198local m = require'lpeglabel'
199local re = require'relabel'
200
201local terror = {
202 ErrId = "expecting an identifier",
203 ErrComma = "expecting ','",
204 fail = "undefined"
205}
206
207local id = m.R'az'^1
208
209local g = m.P{
210 'S',
211 S = m.V'List',
212 List = m.V'Id' * (#m.P(1) * m.V'Comma' * (m.V'Id' + m.T'ErrId'))^0,
213 Id = m.V'Sp' * id,
214 Comma = m.V'Sp' * ',' + m.T'ErrComma',
215 Sp = m.S' \n\t'^0,
216}
217
218
219function mymatch (g, s)
220 local r, e, pos = g:match(s)
221 if not r then
222 local line, col = re.calcline(s, pos)
223 local msg = "Error at line " .. line .. " (col " .. col .. "): "
224 return r, msg .. terror[e] .. " before '" .. s:sub(pos) .. "'"
225 end
226 return r
227end
228
229print(mymatch(g, "one,two"))
230print(mymatch(g, "one two"))
231print(mymatch(g, "one,\n two,\nthree,4"))
232print(mymatch(g, " 1,2"))
233
234```
241 235
242 236
243#### Error Recovery 237#### Error Recovery
244 238
245By using the `Rec` function we can specify a recovery pattern that 239We can specify a recovery rule that should
246should be matched when a label is thrown. After matching the recovery 240be matched when a label is thrown. After matching
247pattern, and possibly recording the error, the parser will resume 241the recovery rule, and possibly recording the error,
248the <em>regular</em> matching. For example, in the example below 242the parser will resume the <em>regular</em> matching.
249we expect to match rule `A`, but when a failure occur the label 42 243The recovery rule must have the same name (or number)
250is thrown and then we will try to match the recovery pattern `recp`: 244of the label that was thrown.
245
246
247For example, in the example below we expect to match rule *A*,
248but when a failure occur the label `Err` is thrown and then we
249will try to match rule *Err*:
251```lua 250```lua
252local m = require'lpeglabel' 251local m = require'lpeglabel'
253 252
254local recp = m.P"oast" 253local recp = m.P"oast"
255 254
256local g = m.P{ 255local g = m.P{
257 "S", 256 'S',
258 S = m.Rec(m.V"A", recp, 42) * ".", 257 S = m.V'A' * '.',
259 A = m.P"t" * (m.P"est" + m.T(42)) 258 A = m.P't' * (m.P'est' + m.T'Err'),
259 Err = m.P'oast'
260} 260}
261 261
262print(g:match("test.")) --> 6 262print(g:match("test.")) --> 6
263print(g:match("toast.")) --> 7 263print(g:match("toast.")) --> 7
264print(g:match("oast.")) --> nil 0 oast. 264print(g:match("oast.")) --> nil fail oast.
265print(g:match("toward.")) --> nil 0 ward. 265print(g:match("toward.")) --> nil fail ward.
266``` 266```
267When trying to match subject 'toast.', in rule `A` the first 267When trying to match subject 'toast.', in rule *A* the first
268't' is matched, then the matching of `m.P"est"` fails and label 42 268't' is matched, then the matching of `m.P"est"` fails and label
269is thrown, with the associated inpux suffix 'oast.'. In rule 269`Err` is thrown, with the associated inpux suffix 'oast.'.
270`S` label 42 is caught and the recovery pattern matches 'oast', 270The recovery rule *Err* successfully matches 'oast', so
271so pattern `'.'` matches the rest of the input. 271the regular matching continues, and pattern `'.'` matches
272the rest of the input.
272 273
273When matching subject 'oast.', pattern `m.P"t"` fails, and 274When matching subject 'oast.', pattern `m.P"t"` fails, and
274the result of the matching is <b>nil, 0, oast.</b>. 275the result of the matching is <b>nil, fail, 1</b>.
275 276
276When matching 'toward.', label 42 is thrown after matching 't', 277When matching 'toward.', label `Err` is thrown after matching 't',
277with the associated input suffix 'oward.'. As the matching of the 278with the associated input suffix 'oward.'. As the matching of the
278recovery pattern fails, the result is <b>nil, 0, ward.</b>. 279recovery pattern fails, the result is <b>nil, fail, 3</b>.
279 280
280Usually, the recovery pattern is an expression that does not fail. 281Usually, the recovery pattern is an expression that does not fail.
281In the previous example, we could have used `(m.P(1) - m.P".")^0` 282In the previous example, we could have used `(m.P(1) - m.P".")^0`
282as the recovery pattern. 283as the recovery pattern.
283 284
284Below we rewrite the grammar that describes a list of identifiers 285Below we rewrite the grammar that describes a list of identifiers
285to use a recovery strategy. Grammar `g` remains the same, but we add a 286to use a recovery strategy, with the help of some auxiliary functions.
286recovery grammar `grec` that handles the labels thrown by `g`.
287
288In grammar `grec` we use functions `record` and `sync`.
289Function `record`, plus function `recorderror`, will help 287Function `record`, plus function `recorderror`, will help
290us to save the input position where a label was thrown, 288us to save the input position where a label was thrown,
291while function `sync` will give us a synchronization pattern, 289while function `sync` will give us a synchronization pattern,
292that consumes the input while is not possible to match a given 290that consumes the input while it is not possible to match a given
293pattern `p`. 291pattern `p`.
294 292
295When the matching of an identifier fails, a defaul value ('NONE') 293When the matching of an identifier fails, a defaul value ('NONE')
@@ -299,26 +297,11 @@ is provided.
299local m = require'lpeglabel' 297local m = require'lpeglabel'
300local re = require'relabel' 298local re = require'relabel'
301 299
302local terror = {} 300local terror = {
303 301 ErrId = "expecting an identifier",
304local function newError(s) 302 ErrComma = "expecting ','",
305 table.insert(terror, s) 303 ErrList = "expecting a list of identifiers",
306 return #terror 304 fail = "undefined"
307end
308
309local errUndef = newError("undefined")
310local errId = newError("expecting an identifier")
311local errComma = newError("expecting ','")
312
313local id = m.R'az'^1
314
315local g = m.P{
316 "S",
317 S = m.V"Id" * m.V"List",
318 List = -m.P(1) + m.V"Comma" * m.V"Id" * m.V"List",
319 Id = m.V"Sp" * m.C(id) + m.T(errId),
320 Comma = m.V"Sp" * "," + m.T(errComma),
321 Sp = m.S" \n\t"^0,
322} 305}
323 306
324local subject, errors 307local subject, errors
@@ -340,14 +323,20 @@ function defaultValue ()
340 return m.Cc"NONE" 323 return m.Cc"NONE"
341end 324end
342 325
343local grec = m.P{ 326local id = m.R'az'^1
327
328local g = m.P{
344 "S", 329 "S",
345 S = m.Rec(m.Rec(g, m.V"ErrComma", errComma), m.V"ErrId", errId), 330 S = m.V"List" + (m.P(1) * m.T'ErrList'),
346 ErrComma = record(errComma) * sync(id), 331 List = m.V'Id' * (#m.P(1) * m.V'Comma' * (m.V'Id' + m.T'ErrId'))^0,
347 ErrId = record(errId) * sync(m.P",") * defaultValue(), 332 Id = m.V'Sp' * m.C(id),
333 Comma = m.V'Sp' * ',' + m.T'ErrComma',
334 Sp = m.S' \n\t'^0,
335 ErrId = record'ErrId' * sync(m.P",") * defaultValue(),
336 ErrComma = record'ErrComma' * sync(id),
337 ErrList = record'ErrList' * sync(m.P(-1)) * defaultValue()
348} 338}
349 339
350
351function mymatch (g, s) 340function mymatch (g, s)
352 errors = {} 341 errors = {}
353 subject = s 342 subject = s
@@ -371,387 +360,114 @@ function mymatch (g, s)
371 return r 360 return r
372end 361end
373 362
374mymatch(grec, "one,two") 363mymatch(g, "one,two")
375mymatch(grec, "one two three") 364mymatch(g, "one two three")
376mymatch(grec, "1,\n two, \n3,") 365mymatch(g, "1,\n two, \n3,")
377mymatch(grec, "one\n two123, \nthree,") 366mymatch(g, "one\n two123, \nthree,")
378``` 367```
379 368
380##### *relabel* syntax 369##### *relabel* syntax
381 370
382Below we describe again a grammar that matches a list of identifiers, 371Below we write a grammar for a simple programming language
383now using the syntax supported by *relabel*, where `//{}` is the 372using the syntax supported by *relabel*, where `%{}` is the throw
384recovery operator, and `%{}` is the throw operator: 373operator, and the syntax `p^l` is syntatic sugar for
374`p / %{l}` (given that *l* is a valid identifier name):
385 375
386```lua 376```lua
387local re = require 'relabel' 377local re = require 'relabel'
388 378
389local errinfo = { 379local terror = {
390 {"errUndef", "undefined"}, 380 cmdSeq = "Missing ';' in CmdSeq",
391 {"errId", "expecting an identifier"}, 381 ifExp = "Error in expresion of 'if'",
392 {"errComma", "expecting ','"}, 382 ifThen = "Error matching 'then' keyword",
383 ifThenCmdSeq = "Error matching CmdSeq of 'then' branch",
384 ifElseCmdSeq = "Error matching CmdSeq of 'else' branch",
385 ifEnd = "Error matching 'end' keyword of 'if'",
386 repeatCmdSeq = "Error matching CmdSeq of 'repeat'",
387 repeatUntil = "Error matching 'until' keyword",
388 repeatExp = "Error matching expression of 'until'",
389 assignOp = "Error matching ':='",
390 assignExp = "Error matching expression of assignment",
391 readName = "Error matching 'NAME' after 'read'",
392 writeExp = "Error matching expression after 'write'",
393 simpleExp = "Error matching 'SimpleExp'",
394 term = "Error matching 'Term'",
395 factor = "Error matching 'Factor'",
396 openParExp = "Error matching expression after '('",
397 closePar = "Error matching ')'",
398 eof = "Error, expecting EOF",
399 undefined = "Undefined Error"
393} 400}
394 401
395local errmsgs = {} 402g = re.compile([[
396local labels = {} 403 Tiny <- CmdSeq (!. / %{eof})
397 404 CmdSeq <- (Cmd SEMICOLON^cmdSeq) (Cmd SEMICOLON^cmdSeq)*
398for i, err in ipairs(errinfo) do 405 Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd
399 errmsgs[i] = err[2] 406 IfCmd <- IF Exp^ifExp THEN^ifThen CmdSeq^ifThenCmdSeq (ELSE CmdSeq^ifElseCmdSeq / '') END^ifEnd
400 labels[err[1]] = i 407 RepeatCmd <- REPEAT CmdSeq^repeatCmdSeq UNTIL^repeatUntil Exp^repeatExp
401end 408 AssignCmd <- NAME ASSIGNMENT^assignOp Exp^assignExp
402 409 ReadCmd <- READ NAME^readName
403re.setlabels(labels) 410 WriteCmd <- WRITE Exp^writeExp
404 411 Exp <- SimpleExp ((LESS / EQUAL) SimpleExp^simpleExp / '')
405local g = re.compile[[ 412 SimpleExp <- Term ((ADD / SUB) Term^term)*
406 S <- Id List 413 Term <- Factor ((MUL / DIV) Factor^factor)*
407 List <- !. / Comma Id List 414 Factor <- OPENPAR Exp^openParExp CLOSEPAR^closePar / NUMBER / NAME
408 Id <- Sp {[a-z]+} / %{errId} 415 ADD <- Sp '+'
409 Comma <- Sp ',' / %{errComma} 416 ASSIGNMENT <- Sp ':='
410 Sp <- %s* 417 CLOSEPAR <- Sp ')'
411]] 418 DIV <- Sp '/'
412 419 IF <- Sp 'if'
413local errors 420 ELSE <- Sp 'else'
414 421 END <- Sp 'end'
415function recorderror (subject, pos, label) 422 EQUAL <- Sp '='
416 local line, col = re.calcline(subject, pos) 423 LESS <- Sp '<'
417 table.insert(errors, { line = line, col = col, msg = errmsgs[labels[label]] }) 424 MUL <- Sp '*'
418 return true 425 NAME <- !RESERVED Sp [a-z]+
419end 426 NUMBER <- Sp [0-9]+
420 427 OPENPAR <- Sp '('
421function sync (p) 428 READ <- Sp 'read'
422 return '( !(' .. p .. ') .)*' 429 REPEAT <- Sp 'repeat'
423end 430 SEMICOLON <- Sp ';'
424 431 SUB <- Sp '-'
425local grec = re.compile( 432 THEN <- Sp 'then'
426 "S <- %g //{errComma} ErrComma //{errId} ErrId" .. "\n" .. 433 UNTIL <- Sp 'until'
427 "ErrComma <- ('' -> 'errComma' => recorderror) " .. sync('[a-z]+') .. "\n" .. 434 WRITE <- Sp 'write'
428 "ErrId <- ('' -> 'errId' => recorderror) " .. sync('","') .. "-> default" 435 RESERVED <- (IF / ELSE / END / READ / REPEAT / THEN / UNTIL / WRITE) ![a-z]+
429 , {g = g, recorderror = recorderror, default = "NONE"} 436 Sp <- (%s / %nl)*
430) 437]], terror)
431 438
432function mymatch (g, s) 439
433 errors = {} 440local function mymatch(g, s)
434 subject = s 441 local r, e, pos = g:match(s)
435 io.write("Input: ", s, "\n") 442 if not r then
436 local r = { g:match(s) } 443 local line, col = re.calcline(s, pos)
437 io.write("Captures (separated by ';'): ") 444 local msg = "Error at line " .. line .. " (col " .. col .. "): "
438 for k, v in pairs(r) do 445 return r, msg .. terror[e]
439 io.write(v .. "; ") 446 end
440 end 447 return r
441 io.write("\nSyntactic errors found: " .. #errors)
442 if #errors > 0 then
443 io.write("\n")
444 local out = {}
445 for i, err in ipairs(errors) do
446 local msg = "Error at line " .. err.line .. " (col " .. err.col .. "): " .. err.msg
447 table.insert(out, msg)
448 end
449 io.write(table.concat(out, "\n"))
450 end
451 print("\n")
452 return r
453end
454
455print(mymatch(grec, "one,two"))
456-- Captures (separated by ';'): one; two;
457-- Syntactic errors found: 0
458
459print(mymatch(grec, "one two three"))
460-- Captures (separated by ';'): one; two; three;
461-- Syntactic errors found: 2
462-- Error at line 1 (col 4): expecting ','
463-- Error at line 1 (col 8): expecting ','
464
465print(mymatch(grec, "1,\n two, \n3,"))
466-- Captures (separated by ';'): NONE; two; NONE; NONE;
467-- Syntactic errors found: 3
468-- Error at line 1 (col 1): expecting an identifier
469-- Error at line 2 (col 6): expecting an identifier
470-- Error at line 3 (col 2): expecting an identifier
471
472print(mymatch(grec, "one\n two123, \nthree,"))
473-- Captures (separated by ';'): one; two; three; NONE;
474-- Syntactic errors found: 3
475-- Error at line 2 (col 1): expecting ','
476-- Error at line 2 (col 5): expecting ','
477-- Error at line 3 (col 6): expecting an identifier
478```
479
480
481#### Arithmetic Expressions
482
483Here's an example of an LPegLabel grammar that matches an expression.
484We have used a function `expect`, that takes a pattern `patt` and a label as
485parameters and builds a new pattern that throws this label when `patt`
486fails.
487
488When a subexpression is syntactically invalid, a default value of 1000
489is provided by the recovery pattern, so the evaluation of an expression
490should always produce a numeric value.
491
492In this example, we can see that it may be a tedious and error prone
493task to build manually the recovery grammar `grec`. In the next example
494we will show how to build the recovery grammar in a more automatic way.
495
496```lua
497local m = require"lpeglabel"
498local re = require"relabel"
499
500local labels = {
501 {"ExpTermFirst", "expected an expression"},
502 {"ExpTermOp", "expected a term after the operator"},
503 {"MisClose", "missing a closing ')' after the expression"},
504}
505
506local function labelindex(labname)
507 for i, elem in ipairs(labels) do
508 if elem[1] == labname then
509 return i
510 end
511 end
512 error("could not find label: " .. labname)
513end
514
515local errors, subject
516
517local function expect(patt, labname)
518 local i = labelindex(labname)
519 return patt + m.T(i)
520end
521
522
523local num = m.R("09")^1 / tonumber
524local op = m.S("+-")
525
526local function compute(tokens)
527 local result = tokens[1]
528 for i = 2, #tokens, 2 do
529 if tokens[i] == '+' then
530 result = result + tokens[i+1]
531 elseif tokens[i] == '-' then
532 result = result - tokens[i+1]
533 else
534 error('unknown operation: ' .. tokens[i])
535 end
536 end
537 return result
538end
539
540local g = m.P {
541 "Exp",
542 Exp = m.Ct(m.V"OperandFirst" * (m.C(op) * m.V"Operand")^0) / compute,
543 OperandFirst = expect(m.V"Term", "ExpTermFirst"),
544 Operand = expect(m.V"Term", "ExpTermOp"),
545 Term = num + m.V"Group",
546 Group = "(" * m.V"Exp" * expect(")", "MisClose"),
547}
548
549function recorderror(pos, lab)
550 local line, col = re.calcline(subject, pos)
551 table.insert(errors, { line = line, col = col, msg = labels[lab][2] })
552end
553
554function record (labname)
555 return (m.Cp() * m.Cc(labelindex(labname))) / recorderror
556end
557
558function sync (p)
559 return (-p * m.P(1))^0
560end
561
562function defaultValue (p)
563 return p or m.Cc(1000)
564end
565
566local grec = m.P {
567 "S",
568 S = m.Rec(m.V"A", m.V"ErrExpTermFirst", labelindex("ExpTermFirst")),
569 A = m.Rec(m.V"Sg", m.V"ErrExpTermOp", labelindex("ExpTermOp")),
570 Sg = m.Rec(g, m.V"ErrMisClose", labelindex("MisClose")),
571 ErrExpTermFirst = record("ExpTermFirst") * sync(op + ")") * defaultValue(),
572 ErrExpTermOp = record("ExpTermOp") * sync(op + ")") * defaultValue(),
573 ErrMisClose = record("MisClose") * sync(m.P")") * defaultValue(m.P""),
574}
575
576local function eval(input)
577 errors = {}
578 io.write("Input: ", input, "\n")
579 subject = input
580 local result, label, suffix = grec:match(input)
581 io.write("Syntactic errors found: " .. #errors, "\n")
582 if #errors > 0 then
583 local out = {}
584 for i, err in ipairs(errors) do
585 local pos = err.col
586 local msg = err.msg
587 table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")")
588 end
589 print(table.concat(out, "\n"))
590 end
591 io.write("Result = ")
592 return result
593end 448end
594 449
595print(eval "90-70-(5)+3") 450local s = [[
596-- Syntactic errors found: 0 451n := 5;
597-- Result = 18 452f := 1;
598 453repeat
599print(eval "15+") 454 f := f + n;
600-- Syntactic errors found: 1 455 n := n - 1
601-- syntax error: expected a term after the operator (at index 3) 456until (n < 1);
602-- Result = 1015 457write f;]]
603 458print(mymatch(g, s))
604print(eval "-2") 459
605-- Syntactic errors found: 1 460print(mymatch(g, "a : 2"))
606-- syntax error: expected an expression (at index 1) 461print(mymatch(g, "a := 2; 6"))
607-- Result = 998
608
609print(eval "1+()+")
610-- Syntactic errors found: 2
611-- syntax error: expected an expression (at index 4)
612-- syntax error: expected a term after the operator (at index 5)
613-- Result = 2001
614
615print(eval "1+(")
616-- Syntactic errors found: 2
617-- syntax error: expected an expression (at index 3)
618-- syntax error: missing a closing ')' after the expression (at index 3)
619-- Result = 1001
620
621print(eval "3)")
622-- Syntactic errors found: 0
623-- Result = 3
624``` 462```
625 463
626#### Automatically Building the Recovery Grammar 464### Caveats
627 465
628Below we rewrite the previous example to automatically 466Does not use the number **1** to specify a recovery rule,
629build the recovery grammar based on information provided 467since that this index is used to indicate the first rule
630by the user for each label (error message, recovery pattern, etc). 468of a grammar.
631In the example below we also throw an error when the grammar
632does not match the whole subject.
633 469
634```lua 470In case your grammar has many regular and recovery rules,
635local m = require"lpeglabel" 471you may get an error message such as grammar: <em>has too many rules</em>.
636local re = require"relabel" 472In this case, we need to change *MAXRULES* in `lptypes.h`.
637 473
638local num = m.R("09")^1 / tonumber
639local op = m.S("+-")
640
641local labels = {}
642local nlabels = 0
643
644local function newError(lab, msg, psync, pcap)
645 nlabels = nlabels + 1
646 psync = psync or m.P(-1)
647 pcap = pcap or m.P""
648 labels[lab] = { id = nlabels, msg = msg, psync = psync, pcap = pcap }
649end
650
651newError("ExpTermFirst", "expected an expression", op + ")", m.Cc(1000))
652newError("ExpTermOp", "expected a term after the operator", op + ")", m.Cc(1000))
653newError("MisClose", "missing a closing ')' after the expression", m.P")")
654newError("Extra", "extra characters found after the expression")
655
656local errors, subject
657
658local function expect(patt, labname)
659 local i = labels[labname].id
660 return patt + m.T(i)
661end
662
663local function compute(tokens)
664 local result = tokens[1]
665 for i = 2, #tokens, 2 do
666 if tokens[i] == '+' then
667 result = result + tokens[i+1]
668 elseif tokens[i] == '-' then
669 result = result - tokens[i+1]
670 else
671 error('unknown operation: ' .. tokens[i])
672 end
673 end
674 return result
675end
676
677local g = m.P {
678 "Exp",
679 Exp = m.Ct(m.V"OperandFirst" * (m.C(op) * m.V"Operand")^0) / compute,
680 OperandFirst = expect(m.V"Term", "ExpTermFirst"),
681 Operand = expect(m.V"Term", "ExpTermOp"),
682 Term = num + m.V"Group",
683 Group = "(" * m.V"Exp" * expect(")", "MisClose"),
684}
685
686function recorderror(pos, lab)
687 local line, col = re.calcline(subject, pos)
688 table.insert(errors, { line = line, col = col, msg = labels[lab].msg })
689end
690
691function record (labname)
692 return (m.Cp() * m.Cc(labname)) / recorderror
693end
694
695function sync (p)
696 return (-p * m.P(1))^0
697end
698
699function defaultValue (p)
700 return p or m.Cc(1000)
701end
702
703local grec = g * expect(m.P(-1), "Extra")
704for k, v in pairs(labels) do
705 grec = m.Rec(grec, record(k) * sync(v.psync) * v.pcap, v.id)
706end
707
708local function eval(input)
709 errors = {}
710 io.write("Input: ", input, "\n")
711 subject = input
712 local result, label, suffix = grec:match(input)
713 io.write("Syntactic errors found: " .. #errors, "\n")
714 if #errors > 0 then
715 local out = {}
716 for i, err in ipairs(errors) do
717 local pos = err.col
718 local msg = err.msg
719 table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")")
720 end
721 print(table.concat(out, "\n"))
722 end
723 io.write("Result = ")
724 return result
725end
726
727print(eval "90-70-(5)+3")
728-- Syntactic errors found: 0
729-- Result = 18
730
731print(eval "15+")
732-- Syntactic errors found: 1
733-- syntax error: expected a term after the operator (at index 3)
734-- Result = 1015
735
736print(eval "-2")
737-- Syntactic errors found: 1
738-- syntax error: expected an expression (at index 1)
739-- Result = 998
740
741print(eval "1+()+")
742-- Syntactic errors found: 2
743-- syntax error: expected an expression (at index 4)
744-- syntax error: expected a term after the operator (at index 5)
745-- Result = 2001
746
747print(eval "1+(")
748-- Syntactic errors found: 2
749-- syntax error: expected an expression (at index 3)
750-- syntax error: missing a closing ')' after the expression (at index 3)
751-- Result = 1001
752
753print(eval "3)")
754-- Syntactic errors found: 1
755-- syntax error: extra characters found after the expression (at index 2)
756-- Result = 3
757```
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'
3 3
4local terror = { 4local terror = {
5 ErrId = "expecting an identifier", 5 ErrId = "expecting an identifier",
6 ErrComma = "expecting ','", 6 ErrEnd = "expecting EOF",
7 fail = "undefined" 7 fail = "undefined"
8} 8}
9 9
10local id = m.R'az'^1 10local id = m.R'az'^1
11 11
12local g = m.P{ 12local g = m.P{
13 "S", 13 'S',
14 S = m.V"Id" * m.V"List", 14 S = m.V'List' * (-m.P(1) + m.T'ErrEnd'),
15 List = -m.P(1) + m.V"Comma" * m.V"Id" * m.V"List", 15 List = m.V'Id' * (m.V'Comma' * (m.V'Id' + m.T'ErrId'))^0,
16 Id = m.V"Sp" * id + m.T'ErrId', 16 Id = m.V'Sp' * id,
17 Comma = m.V"Sp" * "," + m.T'ErrComma', 17 Comma = m.V'Sp' * ',',
18 Sp = m.S" \n\t"^0, 18 Sp = m.S' \n\t'^0,
19} 19}
20 20
21 21
@@ -31,4 +31,4 @@ end
31 31
32print(mymatch(g, "one,two")) 32print(mymatch(g, "one,two"))
33print(mymatch(g, "one two")) 33print(mymatch(g, "one two"))
34print(mymatch(g, "one,\n two,\nthree,")) 34print(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'
3 3
4local terror = { 4local terror = {
5 ErrId = "expecting an identifier", 5 ErrId = "expecting an identifier",
6 ErrComma = "expecting ','" 6 ErrComma = "expecting ','",
7 ErrList = "expecting a list of identifiers",
8 fail = "undefined"
7} 9}
8 10
9local subject, errors 11local subject, errors
@@ -29,16 +31,16 @@ local id = m.R'az'^1
29 31
30local g = m.P{ 32local g = m.P{
31 "S", 33 "S",
32 S = m.V"Id" * m.V"List", 34 S = m.V"List" + (m.P(1) * m.T'ErrList'),
33 List = -m.P(1) + m.V"Comma" * m.V"Id" * m.V"List", 35 List = m.V'Id' * (#m.P(1) * m.V'Comma' * (m.V'Id' + m.T'ErrId'))^0,
34 Id = m.V"Sp" * m.C(id) + m.T'ErrId', 36 Id = m.V'Sp' * m.C(id),
35 Comma = m.V"Sp" * "," + m.T'ErrComma', 37 Comma = m.V'Sp' * ',' + m.T'ErrComma',
36 Sp = m.S" \n\t"^0, 38 Sp = m.S' \n\t'^0,
37 ErrId = record('ErrId') * sync(m.P",") * defaultValue(), 39 ErrId = record'ErrId' * sync(m.P",") * defaultValue(),
38 ErrComma = record('ErrComma') * sync(id), 40 ErrComma = record'ErrComma' * sync(id),
41 ErrList = record'ErrList' * sync(m.P(-1)) * defaultValue()
39} 42}
40 43
41
42function mymatch (g, s) 44function mymatch (g, s)
43 errors = {} 45 errors = {}
44 subject = s 46 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 @@
1local m = require'lpeglabel'
2local re = require'relabel'
3
4local terror = {
5 ErrId = "expecting an identifier",
6 ErrComma = "expecting ','",
7 fail = "undefined"
8}
9
10local id = m.R'az'^1
11
12local g = m.P{
13 'S',
14 S = m.V'List',
15 List = m.V'Id' * (#m.P(1) * m.V'Comma' * (m.V'Id' + m.T'ErrId'))^0,
16 Id = m.V'Sp' * id,
17 Comma = m.V'Sp' * ',' + m.T'ErrComma',
18 Sp = m.S' \n\t'^0,
19}
20
21
22function mymatch (g, s)
23 local r, e, pos = g:match(s)
24 if not r then
25 local line, col = re.calcline(s, pos)
26 local msg = "Error at line " .. line .. " (col " .. col .. "): "
27 return r, msg .. terror[e] .. " before '" .. s:sub(pos) .. "'"
28 end
29 return r
30end
31
32print(mymatch(g, "one,two"))
33print(mymatch(g, "one two"))
34print(mymatch(g, "one,\n two,\nthree,4"))
35print(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 = {
19 factor = "Error matching 'Factor'", 19 factor = "Error matching 'Factor'",
20 openParExp = "Error matching expression after '('", 20 openParExp = "Error matching expression after '('",
21 closePar = "Error matching ')'", 21 closePar = "Error matching ')'",
22 eof = "Error, expecting EOF",
22 undefined = "Undefined Error" 23 undefined = "Undefined Error"
23} 24}
24 25
25g = re.compile([[ 26g = re.compile([[
26 Tiny <- CmdSeq^undefined 27 Tiny <- CmdSeq (!. / %{eof})
27 CmdSeq <- (Cmd SEMICOLON^cmdSeq) (Cmd SEMICOLON^cmdSeq)* 28 CmdSeq <- (Cmd SEMICOLON^cmdSeq) (Cmd SEMICOLON^cmdSeq)*
28 Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd 29 Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd
29 IfCmd <- IF Exp^ifExp THEN^ifThen CmdSeq^ifThenCmdSeq (ELSE CmdSeq^ifElseCmdSeq / '') END^ifEnd 30 IfCmd <- IF Exp^ifExp THEN^ifThen CmdSeq^ifThenCmdSeq (ELSE CmdSeq^ifElseCmdSeq / '') END^ifEnd
@@ -118,5 +119,5 @@ repeat
118print(mymatch(g, s)) 119print(mymatch(g, s))
119 120
120print(mymatch(g, "a : 2")) 121print(mymatch(g, "a : 2"))
121print(mymatch(g, "a := (2")) 122print(mymatch(g, "a := 2; 6"))
122 123
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 @@
1local m = require'lpeglabel'
2
3local recp = m.P"oast"
4
5local g = m.P{
6 'S',
7 S = m.V'A' * '.',
8 A = m.P't' * (m.P'est' + m.T'Err'),
9 Err = m.P'oast'
10}
11
12print(g:match("test.")) --> 6
13print(g:match("toast.")) --> 7
14print(g:match("oast.")) --> nil 0 oast.
15print(g:match("toward.")) --> nil 0 ward.
16
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 @@
1#!/usr/bin/env lua
2
3local tlparser = require "tlparser"
4
5-- expected result, result, message, subject
6local e, r, m, s
7
8local filename = "test.lua"
9
10local function parse (s)
11 local r, m = tlparser.parse(s,filename,false,false)
12 if not r then m = m .. "\n" end
13 return r, m
14end
15
16print("> testing lexer...")
17
18-- syntax ok
19
20-- empty files
21
22s = [=[
23]=]
24--[=[
25{ }
26]=]
27
28r, m = parse(s)
29assert(r == true)
30
31s = [=[
32-- testing empty file
33]=]
34--[=[
35{ }
36]=]
37
38r, m = parse(s)
39assert(r == true)
40
41-- expressions
42
43s = [=[
44local _nil,_false,_true,_dots = nil,false,true,...
45]=]
46--[=[
47{ `Local{ { `Id "_nil", `Id "_false", `Id "_true", `Id "_dots" }, { `Nil, `False, `True, `Dots } } }
48]=]
49
50r, m = parse(s)
51assert(r == true)
52
53-- floating points
54
55s = [=[
56local f1 = 1.
57local f2 = 1.1
58]=]
59--[=[
60{ `Local{ { `Id "f1" }, { `Number "1.0" } }, `Local{ { `Id "f2" }, { `Number "1.1" } } }
61]=]
62
63r, m = parse(s)
64assert(r == true)
65
66s = [=[
67local f1 = 1.e-1
68local f2 = 1.e1
69]=]
70--[=[
71{ `Local{ { `Id "f1" }, { `Number "0.1" } }, `Local{ { `Id "f2" }, { `Number "10.0" } } }
72]=]
73
74r, m = parse(s)
75assert(r == true)
76
77s = [=[
78local f1 = 1.1e+1
79local f2 = 1.1e1
80]=]
81--[=[
82{ `Local{ { `Id "f1" }, { `Number "11.0" } }, `Local{ { `Id "f2" }, { `Number "11.0" } } }
83]=]
84
85r, m = parse(s)
86assert(r == true)
87
88s = [=[
89local f1 = .1
90local f2 = .1e1
91]=]
92--[=[
93{ `Local{ { `Id "f1" }, { `Number "0.1" } }, `Local{ { `Id "f2" }, { `Number "1.0" } } }
94]=]
95
96r, m = parse(s)
97assert(r == true)
98
99s = [=[
100local f1 = 1E1
101local f2 = 1e-1
102]=]
103--[=[
104{ `Local{ { `Id "f1" }, { `Number "10.0" } }, `Local{ { `Id "f2" }, { `Number "0.1" } } }
105]=]
106
107r, m = parse(s)
108assert(r == true)
109
110-- integers
111
112s = [=[
113local i = 1
114local h = 0xff
115]=]
116--[=[
117{ `Local{ { `Id "i" }, { `Number "1" } }, `Local{ { `Id "h" }, { `Number "255" } } }
118]=]
119
120r, m = parse(s)
121assert(r == true)
122
123s = [=[
124local h = 0x76c
125local i = 4294967296 -- 2^32
126]=]
127--[=[
128{ `Local{ { `Id "h" }, { `Number "1900" } }, `Local{ { `Id "i" }, { `Number "4294967296" } } }
129]=]
130
131r, m = parse(s)
132assert(r == true)
133
134-- long comments
135
136s = [=[
137--[======[
138testing
139long
140comment
141[==[ one ]==]
142[===[ more ]===]
143[====[ time ]====]
144bye
145]======]
146]=]
147--[=[
148{ }
149]=]
150
151r, m = parse(s)
152assert(r == true)
153
154-- long strings
155
156s = [=[
157--[[
158testing long string1 begin
159]]
160
161local ls1 =
162[[
163testing long string
164]]
165
166--[[
167testing long string1 end
168]]
169]=]
170--[=[
171{ `Local{ { `Id "ls1" }, { `String "testing long string\n" } } }
172]=]
173
174r, m = parse(s)
175assert(r == true)
176
177s = [=[
178--[==[
179testing long string2 begin
180]==]
181
182local ls2 = [==[ testing \n [[ long ]] \t [===[ string ]===]
183\a ]==]
184
185--[==[
186[[ testing long string2 end ]]
187]==]
188]=]
189--[=[
190{ `Local{ { `Id "ls2" }, { `String " testing \\n [[ long ]] \\t [===[ string ]===]\n\\a " } } }
191]=]
192
193r, m = parse(s)
194assert(r == true)
195
196-- short strings
197
198s = [=[
199-- short string test begin
200
201local ss1_a = "ola mundo\a"
202local ss1_b = 'ola mundo\a'
203
204-- short string test end
205]=]
206--[=[
207{ `Local{ { `Id "ss1_a" }, { `String "ola mundo\a" } }, `Local{ { `Id "ss1_b" }, { `String "ola mundo\a" } } }
208]=]
209
210r, m = parse(s)
211assert(r == true)
212
213s = [=[
214-- short string test begin
215
216local ss2_a = "testando,\tteste\n1\n2\n3 --> \"tchau\""
217local ss2_b = 'testando,\tteste\n1\n2\n3 --> \'tchau\''
218
219-- short string test end
220]=]
221--[=[
222{ `Local{ { `Id "ss2_a" }, { `String "testando,\tteste\n1\n2\n3 --> \"tchau\"" } }, `Local{ { `Id "ss2_b" }, { `String "testando,\tteste\n1\n2\n3 --> 'tchau'" } } }
223]=]
224
225r, m = parse(s)
226assert(r == true)
227
228s = [=[
229-- short string test begin
230
231local ss3_a = "ola \
232'mundo'!"
233
234local ss3_b = 'ola \
235"mundo"!'
236
237-- short string test end
238]=]
239--[=[
240{ `Local{ { `Id "ss3_a" }, { `String "ola \n'mundo'!" } }, `Local{ { `Id "ss3_b" }, { `String "ola \n\"mundo\"!" } } }
241]=]
242
243r, m = parse(s)
244assert(r == true)
245
246s = [=[
247-- short string test begin
248
249local ss4_a = "C:\\Temp/"
250
251local ss4_b = 'C:\\Temp/'
252
253-- short string test end
254]=]
255--[=[
256{ `Local{ { `Id "ss4_a" }, { `String "C:\\Temp/" } }, `Local{ { `Id "ss4_b" }, { `String "C:\\Temp/" } } }
257]=]
258
259r, m = parse(s)
260assert(r == true)
261
262s = [=[
263-- short string test begin
264
265local ss5_a = "ola \
266mundo \\ \
267cruel"
268
269local ss5_b = 'ola \
270mundo \\ \
271cruel'
272
273-- short string test end
274]=]
275--[=[
276{ `Local{ { `Id "ss5_a" }, { `String "ola \nmundo \\ \ncruel" } }, `Local{ { `Id "ss5_b" }, { `String "ola \nmundo \\ \ncruel" } } }
277]=]
278
279r, m = parse(s)
280assert(r == true)
281
282-- syntax error
283
284-- floating points
285
286s = [=[
287local f = 9e
288]=]
289--[=[
290test.lua:2:1: syntax error, unexpected 'EOF', expecting '=', ',', 'String', '{', '(', ':', '[', '.'
291]=]
292e = [=[
293test.lua:1:12: malformed <number>
294]=]
295
296r, m = parse(s)
297assert(m == e)
298
299s = [=[
300local f = 5.e
301]=]
302--[=[
303test.lua:2:1: syntax error, unexpected 'EOF', expecting '=', ',', 'String', '{', '(', ':', '[', '.'
304]=]
305e = [=[
306test.lua:1:13: malformed <number>
307]=]
308
309r, m = parse(s)
310assert(m == e)
311
312s = [=[
313local f = .9e-
314]=]
315--[=[
316test.lua:1:14: syntax error, unexpected '-', expecting '=', ',', 'String', '{', '(', ':', '[', '.'
317]=]
318e = [=[
319test.lua:1:14: malformed <number>
320]=]
321
322r, m = parse(s)
323assert(m == e)
324
325s = [=[
326local f = 5.9e+
327]=]
328--[=[
329test.lua:1:15: syntax error, unexpected '+', expecting '=', ',', 'String', '{', '(', ':', '[', '.'
330]=]
331e = [=[
332test.lua:1:15: malformed <number>
333]=]
334
335r, m = parse(s)
336assert(m == e)
337
338-- integers
339
340s = [=[
341-- invalid hexadecimal number
342
343local hex = 0xG
344]=]
345--[=[
346test.lua:4:1: syntax error, unexpected 'EOF', expecting '=', ',', 'String', '{', '(', ':', '[', '.'
347]=]
348e = [=[
349test.lua:3:14: malformed <number>
350]=]
351
352r, m = parse(s)
353assert(m == e)
354
355-- long strings
356
357s = [=[
358--[==[
359testing long string3 begin
360]==]
361
362local ls3 = [===[
363testing
364unfinised
365long string
366]==]
367
368--[==[
369[[ testing long string3 end ]]
370]==]
371]=]
372--[=[
373test.lua:5:13: syntax error, unexpected '[', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not'
374]=]
375e = [=[
376test.lua:14:1: unfinished long string
377]=]
378
379r, m = parse(s)
380assert(m == e)
381
382-- short strings
383
384s = [=[
385-- short string test begin
386
387local ss6 = "testing unfinished string
388
389-- short string test end
390]=]
391--[=[
392test.lua:3:13: syntax error, unexpected '"', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not'
393]=]
394e = [=[
395test.lua:6:1: malformed <string>
396]=]
397
398r, m = parse(s)
399assert(m == e)
400
401-- unfinished comments
402
403s = [=[
404--[[
405
406testing
407unfinished
408
409comment
410 ]=]
411--[=[
412test.lua:3:1: syntax error, unexpected 'comment', expecting '=', ',', 'String', '{', '(', ':', '[', '.'
413]=]
414e = [=[
415test.lua:1:2: unfinished long comment
416]=]
417
418r, m = parse(s)
419assert(m == e)
420
421print("> testing parser...")
422
423-- syntax ok
424
425-- anonymous functions
426
427s = [=[
428local a,b,c = function () end
429]=]
430--[=[
431{ `Local{ { `Id "a", `Id "b", `Id "c" }, { `Function{ { }, { } } } } }
432]=]
433
434r, m = parse(s)
435assert(r == true)
436
437s = [=[
438local test = function ( a , b , ... ) end
439]=]
440--[=[
441{ `Local{ { `Id "test" }, { `Function{ { `Id "a", `Id "b", `Dots }, { } } } } }
442]=]
443
444r, m = parse(s)
445assert(r == true)
446
447s = [=[
448local test = function (...) return ...,0 end
449]=]
450--[=[
451{ `Local{ { `Id "test" }, { `Function{ { `Dots }, { `Return{ `Dots, `Number "0" } } } } } }
452]=]
453
454r, m = parse(s)
455assert(r == true)
456
457-- arithmetic expressions
458
459s = [=[
460local arithmetic = 1 - 2 * 3 + 4
461]=]
462--[=[
463{ `Local{ { `Id "arithmetic" }, { `Op{ "add", `Op{ "sub", `Number "1", `Op{ "mul", `Number "2", `Number "3" } }, `Number "4" } } } }
464]=]
465
466r, m = parse(s)
467assert(r == true)
468
469s = [=[
470local pow = -3^-2^2
471]=]
472--[=[
473{ `Local{ { `Id "pow" }, { `Op{ "unm", `Op{ "pow", `Number "3", `Op{ "unm", `Op{ "pow", `Number "2", `Number "2" } } } } } } }
474]=]
475
476r, m = parse(s)
477assert(r == true)
478
479s = [=[
480q, r, f = 3//2, 3%2, 3/2
481]=]
482--[=[
483{ `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" } } } }
484]=]
485
486r, m = parse(s)
487assert(r == true)
488
489-- assignments
490
491s = [=[
492a = f()[1]
493]=]
494--[=[
495{ `Set{ { `Index{ `Id "_ENV", `String "a" } }, { `Index{ `Call{ `Index{ `Id "_ENV", `String "f" } }, `Number "1" } } } }
496]=]
497
498r, m = parse(s)
499assert(r == true)
500
501s = [=[
502a()[1] = 1;
503]=]
504--[=[
505{ `Set{ { `Index{ `Call{ `Index{ `Id "_ENV", `String "a" } }, `Number "1" } }, { `Number "1" } } }
506]=]
507
508r, m = parse(s)
509assert(r == true)
510
511s = [=[
512i = a.f(1)
513]=]
514--[=[
515{ `Set{ { `Index{ `Id "_ENV", `String "i" } }, { `Call{ `Index{ `Index{ `Id "_ENV", `String "a" }, `String "f" }, `Number "1" } } } }
516]=]
517
518r, m = parse(s)
519assert(r == true)
520
521s = [=[
522i = a[f(1)]
523]=]
524--[=[
525{ `Set{ { `Index{ `Id "_ENV", `String "i" } }, { `Index{ `Index{ `Id "_ENV", `String "a" }, `Call{ `Index{ `Id "_ENV", `String "f" }, `Number "1" } } } } }
526]=]
527
528r, m = parse(s)
529assert(r == true)
530
531s = [=[
532a[f()] = sub
533i = i + 1
534]=]
535--[=[
536{ `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" } } } }
537]=]
538
539r, m = parse(s)
540assert(r == true)
541
542s = [=[
543a:b(1)._ = some_value
544]=]
545--[=[
546{ `Set{ { `Index{ `Invoke{ `Index{ `Id "_ENV", `String "a" }, `String "b", `Number "1" }, `String "_" } }, { `Index{ `Id "_ENV", `String "some_value" } } } }
547]=]
548
549r, m = parse(s)
550assert(r == true)
551
552-- bitwise expressions
553
554s = [=[
555b = 1 & 0 | 1 ~ 1
556]=]
557--[=[
558{ `Set{ { `Index{ `Id "_ENV", `String "b" } }, { `Op{ "bor", `Op{ "band", `Number "1", `Number "0" }, `Op{ "bxor", `Number "1", `Number "1" } } } } }
559]=]
560
561r, m = parse(s)
562assert(r == true)
563
564s = [=[
565b = 1 & 0 | 1 >> 1 ~ 1
566]=]
567--[=[
568{ `Set{ { `Index{ `Id "_ENV", `String "b" } }, { `Op{ "bor", `Op{ "band", `Number "1", `Number "0" }, `Op{ "bxor", `Op{ "shr", `Number "1", `Number "1" }, `Number "1" } } } } }
569]=]
570
571r, m = parse(s)
572assert(r == true)
573
574-- break
575
576s = [=[
577while 1 do
578 break
579end
580]=]
581--[=[
582{ `While{ `Number "1", { `Break } } }
583]=]
584
585r, m = parse(s)
586assert(r == true)
587
588s = [=[
589while 1 do
590 while 1 do
591 break
592 end
593 break
594end
595]=]
596--[=[
597{ `While{ `Number "1", { `While{ `Number "1", { `Break } }, `Break } } }
598]=]
599
600r, m = parse(s)
601assert(r == true)
602
603s = [=[
604repeat
605 if 2 > 1 then break end
606until 1
607]=]
608--[=[
609{ `Repeat{ { `If{ `Op{ "lt", `Number "1", `Number "2" }, { `Break } } }, `Number "1" } }
610]=]
611
612r, m = parse(s)
613assert(r == true)
614
615s = [=[
616for i=1,10 do
617 do
618 break
619 break
620 return
621 end
622end
623]=]
624--[=[
625{ `Fornum{ `Id "i", `Number "1", `Number "10", { `Do{ `Break, `Break, `Return } } } }
626]=]
627
628r, m = parse(s)
629assert(r == true)
630
631-- block statements
632
633s = [=[
634do
635 local var = 2+2;
636 return
637end
638]=]
639--[=[
640{ `Do{ `Local{ { `Id "var" }, { `Op{ "add", `Number "2", `Number "2" } } }, `Return } }
641]=]
642
643r, m = parse(s)
644assert(r == true)
645
646-- calls
647
648s = [=[
649f()
650t:m()
651]=]
652--[=[
653{ `Call{ `Index{ `Id "_ENV", `String "f" } }, `Invoke{ `Index{ `Id "_ENV", `String "t" }, `String "m" } }
654]=]
655
656r, m = parse(s)
657assert(r == true)
658
659-- concatenation expressions
660
661s = [=[
662local concat1 = 1 .. 2^3
663]=]
664--[=[
665{ `Local{ { `Id "concat1" }, { `Op{ "concat", `Number "1", `Op{ "pow", `Number "2", `Number "3" } } } } }
666]=]
667
668r, m = parse(s)
669assert(r == true)
670
671-- empty files
672
673s = [=[
674;
675]=]
676--[=[
677{ }
678]=]
679
680r, m = parse(s)
681assert(r == true)
682
683-- for generic
684
685s = [=[
686for k,v in pairs(t) do print (k,v) end
687]=]
688--[=[
689{ `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" } } } }
690]=]
691
692r, m = parse(s)
693assert(r == true)
694
695-- for numeric
696
697s = [=[
698for i = 1 , 10 , 2 do end
699]=]
700--[=[
701{ `Fornum{ `Id "i", `Number "1", `Number "10", `Number "2", { } } }
702]=]
703
704r, m = parse(s)
705assert(r == true)
706
707s = [=[
708for i=1,10 do end
709]=]
710--[=[
711{ `Fornum{ `Id "i", `Number "1", `Number "10", { } } }
712]=]
713
714r, m = parse(s)
715assert(r == true)
716
717-- global functions
718
719s = [=[
720function test(a , b , ...) end
721]=]
722--[=[
723{ `Set{ { `Index{ `Id "_ENV", `String "test" } }, { `Function{ { `Id "a", `Id "b", `Dots }, { } } } } }
724]=]
725
726r, m = parse(s)
727assert(r == true)
728
729s = [=[
730function test (...) end
731]=]
732--[=[
733{ `Set{ { `Index{ `Id "_ENV", `String "test" } }, { `Function{ { `Dots }, { } } } } }
734]=]
735
736r, m = parse(s)
737assert(r == true)
738
739s = [=[
740function t.a:b() end
741]=]
742--[=[
743{ `Set{ { `Index{ `Index{ `Index{ `Id "_ENV", `String "t" }, `String "a" }, `String "b" } }, { `Function{ { `Id "self" }, { } } } } }
744]=]
745
746r, m = parse(s)
747assert(r == true)
748
749s = [=[
750function t.a() end
751]=]
752--[=[
753{ `Set{ { `Index{ `Index{ `Id "_ENV", `String "t" }, `String "a" } }, { `Function{ { }, { } } } } }
754]=]
755
756r, m = parse(s)
757assert(r == true)
758
759s = [=[
760function testando . funcao . com : espcacos ( e, com , parametros, ... ) end
761]=]
762--[=[
763{ `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 }, { } } } } }
764]=]
765
766r, m = parse(s)
767assert(r == true)
768
769-- goto
770
771s = [=[
772goto label
773:: label :: return
774]=]
775--[=[
776{ `Goto{ "label" }, `Label{ "label" }, `Return }
777]=]
778
779r, m = parse(s)
780assert(r == true)
781
782s = [=[
783::label::
784goto label
785]=]
786--[=[
787{ `Label{ "label" }, `Goto{ "label" } }
788]=]
789
790r, m = parse(s)
791assert(r == true)
792
793s = [=[
794goto label
795::label::
796]=]
797--[=[
798{ `Goto{ "label" }, `Label{ "label" } }
799]=]
800
801r, m = parse(s)
802assert(r == true)
803
804s = [=[
805::label::
806do ::label:: goto label end
807]=]
808--[=[
809{ `Label{ "label" }, `Do{ `Label{ "label" }, `Goto{ "label" } } }
810]=]
811
812r, m = parse(s)
813assert(r == true)
814
815s = [=[
816::label::
817do goto label ; ::label:: end
818]=]
819--[=[
820{ `Label{ "label" }, `Do{ `Goto{ "label" }, `Label{ "label" } } }
821]=]
822
823r, m = parse(s)
824assert(r == true)
825
826s = [=[
827::label::
828do goto label end
829]=]
830--[=[
831{ `Label{ "label" }, `Do{ `Goto{ "label" } } }
832]=]
833
834r, m = parse(s)
835assert(r == true)
836
837s = [=[
838do goto label end
839::label::
840]=]
841--[=[
842{ `Do{ `Goto{ "label" } }, `Label{ "label" } }
843]=]
844
845r, m = parse(s)
846assert(r == true)
847
848s = [=[
849do do do do do goto label end end end end end
850::label::
851]=]
852--[=[
853{ `Do{ `Do{ `Do{ `Do{ `Do{ `Goto{ "label" } } } } } }, `Label{ "label" } }
854]=]
855
856r, m = parse(s)
857assert(r == true)
858
859-- if-else
860
861s = [=[
862if a then end
863]=]
864--[=[
865{ `If{ `Index{ `Id "_ENV", `String "a" }, { } } }
866]=]
867
868r, m = parse(s)
869assert(r == true)
870
871s = [=[
872if a then return a else return end
873]=]
874--[=[
875{ `If{ `Index{ `Id "_ENV", `String "a" }, { `Return{ `Index{ `Id "_ENV", `String "a" } } }, { `Return } } }
876]=]
877
878r, m = parse(s)
879assert(r == true)
880
881s = [=[
882if a then
883 return a
884else
885 local c = d
886 d = d + 1
887 return d
888end
889]=]
890--[=[
891{ `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" } } } } }
892]=]
893
894r, m = parse(s)
895assert(r == true)
896
897s = [=[
898if a then
899 return a
900elseif b then
901 return b
902elseif c then
903 return c
904end
905]=]
906--[=[
907{ `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" } } } } }
908]=]
909
910r, m = parse(s)
911assert(r == true)
912
913s = [=[
914if a then return a
915elseif b then return
916else ;
917end
918]=]
919--[=[
920{ `If{ `Index{ `Id "_ENV", `String "a" }, { `Return{ `Index{ `Id "_ENV", `String "a" } } }, `Index{ `Id "_ENV", `String "b" }, { `Return }, { } } }
921]=]
922
923r, m = parse(s)
924assert(r == true)
925
926s = [=[
927if a then
928 return
929elseif c then
930end
931]=]
932--[=[
933{ `If{ `Index{ `Id "_ENV", `String "a" }, { `Return }, `Index{ `Id "_ENV", `String "c" }, { } } }
934]=]
935
936r, m = parse(s)
937assert(r == true)
938
939-- interfaces
940
941s = [=[
942local interface Empty end
943]=]
944--[=[
945{ `Interface{ Empty, `TTable{ } } }
946]=]
947
948r, m = parse(s)
949assert(r == true)
950
951s = [=[
952local interface X
953 x, y, z:number
954end
955]=]
956--[=[
957{ `Interface{ X, `TTable{ `TLiteral x:`TBase number, `TLiteral y:`TBase number, `TLiteral z:`TBase number } } }
958]=]
959
960r, m = parse(s)
961assert(r == true)
962
963s = [=[
964local interface Person
965 firstname:string
966 lastname:string
967end
968]=]
969--[=[
970{ `Interface{ Person, `TTable{ `TLiteral firstname:`TBase string, `TLiteral lastname:`TBase string } } }
971]=]
972
973r, m = parse(s)
974assert(r == true)
975
976s = [=[
977local interface Element
978 info:number
979 next:Element?
980end
981]=]
982--[=[
983{ `Interface{ Element, `TRecursive{ Element, `TTable{ `TLiteral info:`TBase number, `TLiteral next:`TUnion{ `TVariable Element, `TNil } } } } }
984]=]
985
986r, m = parse(s)
987assert(r == true)
988
989-- labels
990
991s = [=[
992::label::
993do ::label:: end
994::other_label::
995]=]
996--[=[
997{ `Label{ "label" }, `Do{ `Label{ "label" } }, `Label{ "other_label" } }
998]=]
999
1000r, m = parse(s)
1001assert(r == true)
1002
1003-- locals
1004
1005s = [=[
1006local a
1007]=]
1008--[=[
1009{ `Local{ { `Id "a" }, { } } }
1010]=]
1011
1012r, m = parse(s)
1013assert(r == true)
1014
1015s = [=[
1016local a,b,c
1017]=]
1018--[=[
1019{ `Local{ { `Id "a", `Id "b", `Id "c" }, { } } }
1020]=]
1021
1022r, m = parse(s)
1023assert(r == true)
1024
1025s = [=[
1026local a = 1 , 1 + 2, 5.1
1027]=]
1028--[=[
1029{ `Local{ { `Id "a" }, { `Number "1", `Op{ "add", `Number "1", `Number "2" }, `Number "5.1" } } }
1030]=]
1031
1032r, m = parse(s)
1033assert(r == true)
1034
1035s = [=[
1036local a,b,c = 1.9
1037]=]
1038--[=[
1039{ `Local{ { `Id "a", `Id "b", `Id "c" }, { `Number "1.9" } } }
1040]=]
1041
1042r, m = parse(s)
1043assert(r == true)
1044
1045s = [=[
1046local function test() end
1047]=]
1048--[=[
1049{ `Localrec{ { `Id "test" }, { `Function{ { }, { } } } } }
1050]=]
1051
1052r, m = parse(s)
1053assert(r == true)
1054
1055s = [=[
1056local function test ( a , b , c , ... ) end
1057]=]
1058--[=[
1059{ `Localrec{ { `Id "test" }, { `Function{ { `Id "a", `Id "b", `Id "c", `Dots }, { } } } } }
1060]=]
1061
1062r, m = parse(s)
1063assert(r == true)
1064
1065s = [=[
1066local function test(...) return ... end
1067]=]
1068--[=[
1069{ `Localrec{ { `Id "test" }, { `Function{ { `Dots }, { `Return{ `Dots } } } } } }
1070]=]
1071
1072r, m = parse(s)
1073assert(r == true)
1074
1075-- relational expressions
1076
1077s = [=[
1078local relational = 1 < 2 >= 3 == 4 ~= 5 < 6 <= 7
1079]=]
1080--[=[
1081{ `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" } } } }
1082]=]
1083
1084r, m = parse(s)
1085assert(r == true)
1086
1087-- repeat
1088
1089s = [=[
1090repeat
1091 local a,b,c = 1+1,2+2,3+3
1092 break
1093until a < 1
1094]=]
1095--[=[
1096{ `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" } } }
1097]=]
1098
1099r, m = parse(s)
1100assert(r == true)
1101
1102-- return
1103
1104s = [=[
1105return
1106]=]
1107--[=[
1108{ `Return }
1109]=]
1110
1111r, m = parse(s)
1112assert(r == true)
1113
1114s = [=[
1115return 1
1116]=]
1117--[=[
1118{ `Return{ `Number "1" } }
1119]=]
1120
1121r, m = parse(s)
1122assert(r == true)
1123
1124s = [=[
1125return 1,1-2*3+4,"alo"
1126]=]
1127--[=[
1128{ `Return{ `Number "1", `Op{ "add", `Op{ "sub", `Number "1", `Op{ "mul", `Number "2", `Number "3" } }, `Number "4" }, `String "alo" } }
1129]=]
1130
1131r, m = parse(s)
1132assert(r == true)
1133
1134s = [=[
1135return;
1136]=]
1137--[=[
1138{ `Return }
1139]=]
1140
1141r, m = parse(s)
1142assert(r == true)
1143
1144s = [=[
1145return 1;
1146]=]
1147--[=[
1148{ `Return{ `Number "1" } }
1149]=]
1150
1151r, m = parse(s)
1152assert(r == true)
1153
1154s = [=[
1155return 1,1-2*3+4,"alo";
1156]=]
1157--[=[
1158{ `Return{ `Number "1", `Op{ "add", `Op{ "sub", `Number "1", `Op{ "mul", `Number "2", `Number "3" } }, `Number "4" }, `String "alo" } }
1159]=]
1160
1161r, m = parse(s)
1162assert(r == true)
1163
1164-- tables
1165
1166s = [=[
1167local t = { [1] = "alo", alo = 1, 2; }
1168]=]
1169--[=[
1170{ `Local{ { `Id "t" }, { `Table{ `Pair{ `Number "1", `String "alo" }, `Pair{ `String "alo", `Number "1" }, `Number "2" } } } }
1171]=]
1172
1173r, m = parse(s)
1174assert(r == true)
1175
1176s = [=[
1177local t = { 1.5 }
1178]=]
1179--[=[
1180{ `Local{ { `Id "t" }, { `Table{ `Number "1.5" } } } }
1181]=]
1182
1183r, m = parse(s)
1184assert(r == true)
1185
1186s = [=[
1187local t = {1,2;
11883,
11894,
1190
1191
1192
11935}
1194]=]
1195--[=[
1196{ `Local{ { `Id "t" }, { `Table{ `Number "1", `Number "2", `Number "3", `Number "4", `Number "5" } } } }
1197]=]
1198
1199r, m = parse(s)
1200assert(r == true)
1201
1202s = [=[
1203local t = {[1]=1,[2]=2;
1204[3]=3,
1205[4]=4,
1206
1207
1208
1209[5]=5}
1210]=]
1211--[=[
1212{ `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" } } } } }
1213]=]
1214
1215r, m = parse(s)
1216assert(r == true)
1217
1218s = [=[
1219local t = {{{}}, {"alo"}}
1220]=]
1221--[=[
1222{ `Local{ { `Id "t" }, { `Table{ `Table{ `Table }, `Table{ `String "alo" } } } } }
1223]=]
1224
1225r, m = parse(s)
1226assert(r == true)
1227
1228-- vararg
1229
1230s = [=[
1231local f = function (...)
1232 return ...
1233end
1234]=]
1235--[=[
1236{ `Local{ { `Id "f" }, { `Function{ { `Dots }, { `Return{ `Dots } } } } } }
1237]=]
1238
1239r, m = parse(s)
1240assert(r == true)
1241
1242s = [=[
1243local f = function ()
1244 local g = function (x, y, ...)
1245 return ...,...,...
1246 end
1247end
1248]=]
1249--[=[
1250{ `Local{ { `Id "f" }, { `Function{ { }, { `Local{ { `Id "g" }, { `Function{ { `Id "x", `Id "y", `Dots }, { `Return{ `Dots, `Dots, `Dots } } } } } } } } } }
1251]=]
1252
1253r, m = parse(s)
1254assert(r == true)
1255
1256s = [=[
1257local function f (x, ...)
1258 return ...
1259end
1260]=]
1261--[=[
1262{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x", `Dots }, { `Return{ `Dots } } } } } }
1263]=]
1264
1265r, m = parse(s)
1266assert(r == true)
1267
1268s = [=[
1269local f = function (x, ...)
1270 return ...
1271end
1272]=]
1273--[=[
1274{ `Local{ { `Id "f" }, { `Function{ { `Id "x", `Dots }, { `Return{ `Dots } } } } } }
1275]=]
1276
1277r, m = parse(s)
1278assert(r == true)
1279
1280-- while
1281
1282s = [=[
1283local i = 0
1284while (i < 10)
1285do
1286 i = i + 1
1287end
1288]=]
1289--[=[
1290{ `Local{ { `Id "i" }, { `Number "0" } }, `While{ `Paren{ `Op{ "lt", `Id "i", `Number "10" } }, { `Set{ { `Id "i" }, { `Op{ "add", `Id "i", `Number "1" } } } } } }
1291]=]
1292
1293r, m = parse(s)
1294assert(r == true)
1295
1296-- type annotations
1297
1298s = [=[
1299local x:nil
1300]=]
1301--[=[
1302{ `Local{ { `Id "x":`TNil }, { } } }
1303]=]
1304
1305r, m = parse(s)
1306assert(r == true)
1307
1308s = [=[
1309local x:false, y:true
1310]=]
1311--[=[
1312{ `Local{ { `Id "x":`TLiteral false, `Id "y":`TLiteral true }, { } } }
1313]=]
1314
1315r, m = parse(s)
1316assert(r == true)
1317
1318s = [=[
1319local x:1, y:1.1
1320]=]
1321--[=[
1322{ `Local{ { `Id "x":`TLiteral 1, `Id "y":`TLiteral 1.1 }, { } } }
1323]=]
1324
1325r, m = parse(s)
1326assert(r == true)
1327
1328s = [=[
1329local x:"hello", y:'world'
1330]=]
1331--[=[
1332{ `Local{ { `Id "x":`TLiteral hello, `Id "y":`TLiteral world }, { } } }
1333]=]
1334
1335r, m = parse(s)
1336assert(r == true)
1337
1338s = [=[
1339local x:boolean, y:number, z:string
1340]=]
1341--[=[
1342{ `Local{ { `Id "x":`TBase boolean, `Id "y":`TBase number, `Id "z":`TBase string }, { } } }
1343]=]
1344
1345r, m = parse(s)
1346assert(r == true)
1347
1348s = [=[
1349local x:any
1350]=]
1351--[=[
1352{ `Local{ { `Id "x":`TAny }, { } } }
1353]=]
1354
1355r, m = parse(s)
1356assert(r == true)
1357
1358s = [=[
1359local x:number?
1360]=]
1361--[=[
1362{ `Local{ { `Id "x":`TUnion{ `TBase number, `TNil } }, { } } }
1363]=]
1364
1365r, m = parse(s)
1366assert(r == true)
1367
1368s = [=[
1369local x:number|nil
1370]=]
1371--[=[
1372{ `Local{ { `Id "x":`TUnion{ `TBase number, `TNil } }, { } } }
1373]=]
1374
1375r, m = parse(s)
1376assert(r == true)
1377
1378s = [=[
1379local x:number|string|nil
1380]=]
1381--[=[
1382{ `Local{ { `Id "x":`TUnion{ `TBase number, `TBase string, `TNil } }, { } } }
1383]=]
1384
1385r, m = parse(s)
1386assert(r == true)
1387
1388s = [=[
1389local x:number|nil|nil|nil|nil
1390]=]
1391--[=[
1392{ `Local{ { `Id "x":`TUnion{ `TBase number, `TNil } }, { } } }
1393]=]
1394
1395r, m = parse(s)
1396assert(r == true)
1397
1398s = [=[
1399local x:number|nil|string|nil|number|boolean|string
1400]=]
1401--[=[
1402{ `Local{ { `Id "x":`TUnion{ `TNil, `TBase number, `TBase boolean, `TBase string } }, { } } }
1403]=]
1404
1405r, m = parse(s)
1406assert(r == true)
1407
1408s = [=[
1409local x:number|string?
1410]=]
1411--[=[
1412{ `Local{ { `Id "x":`TUnion{ `TBase number, `TBase string, `TNil } }, { } } }
1413]=]
1414
1415r, m = parse(s)
1416assert(r == true)
1417
1418s = [=[
1419local x:(number) -> (number)
1420]=]
1421--[=[
1422{ `Local{ { `Id "x":`TFunction{ `TTuple{ `TBase number, `TVararg{ `TValue } }, `TTuple{ `TBase number, `TVararg{ `TNil } } } }, { } } }
1423]=]
1424
1425r, m = parse(s)
1426assert(r == true)
1427
1428s = [=[
1429local x:(value*) -> (nil*)
1430]=]
1431--[=[
1432{ `Local{ { `Id "x":`TFunction{ `TTuple{ `TVararg{ `TValue } }, `TTuple{ `TVararg{ `TNil } } } }, { } } }
1433]=]
1434
1435r, m = parse(s)
1436assert(r == true)
1437
1438s = [=[
1439local x:(number,string,boolean) -> (string,number,boolean)
1440]=]
1441--[=[
1442{ `Local{ { `Id "x":`TFunction{ `TTuple{ `TBase number, `TBase string, `TBase boolean, `TVararg{ `TValue } }, `TTuple{ `TBase string, `TBase number, `TBase boolean, `TVararg{ `TNil } } } }, { } } }
1443]=]
1444
1445r, m = parse(s)
1446assert(r == true)
1447
1448s = [=[
1449local x:(number,string,value*) -> (string,number,nil*)
1450]=]
1451--[=[
1452{ `Local{ { `Id "x":`TFunction{ `TTuple{ `TBase number, `TBase string, `TVararg{ `TValue } }, `TTuple{ `TBase string, `TBase number, `TVararg{ `TNil } } } }, { } } }
1453]=]
1454
1455r, m = parse(s)
1456assert(r == true)
1457
1458s = [=[
1459local x:{}
1460]=]
1461--[=[
1462{ `Local{ { `Id "x":`TTable{ } }, { } } }
1463]=]
1464
1465r, m = parse(s)
1466assert(r == true)
1467
1468s = [=[
1469local x:{{{{{}}}}}
1470]=]
1471--[=[
1472{ `Local{ { `Id "x":`TTable{ `TBase number:`TUnion{ `TTable{ `TBase number:`TUnion{ `TTable{ `TBase number:`TUnion{ `TTable{ `TBase number:`TUnion{ `TTable{ }, `TNil } }, `TNil } }, `TNil } }, `TNil } } }, { } } }
1473]=]
1474
1475r, m = parse(s)
1476assert(r == true)
1477
1478s = [=[
1479local x:{string}
1480]=]
1481--[=[
1482{ `Local{ { `Id "x":`TTable{ `TBase number:`TUnion{ `TBase string, `TNil } } }, { } } }
1483]=]
1484
1485r, m = parse(s)
1486assert(r == true)
1487
1488s = [=[
1489local x:{string:number}
1490]=]
1491--[=[
1492{ `Local{ { `Id "x":`TTable{ `TBase string:`TUnion{ `TBase number, `TNil } } }, { } } }
1493]=]
1494
1495r, m = parse(s)
1496assert(r == true)
1497
1498s = [=[
1499local x:{'firstname':string, 'lastname':string}
1500]=]
1501--[=[
1502{ `Local{ { `Id "x":`TTable{ `TLiteral firstname:`TBase string, `TLiteral lastname:`TBase string } }, { } } }
1503]=]
1504
1505r, m = parse(s)
1506assert(r == true)
1507
1508s = [=[
1509local x:{'tag':string, number:string}
1510]=]
1511--[=[
1512{ `Local{ { `Id "x":`TTable{ `TLiteral tag:`TBase string, `TBase number:`TUnion{ `TBase string, `TNil } } }, { } } }
1513]=]
1514
1515r, m = parse(s)
1516assert(r == true)
1517
1518s = [=[
1519local x:{'f':(number) -> (number), 't':{number:number}}
1520]=]
1521--[=[
1522{ `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 } } } }, { } } }
1523]=]
1524
1525r, m = parse(s)
1526assert(r == true)
1527
1528s = [=[
1529for k:number, v:string in ipairs({"hello", "world"}) do end
1530]=]
1531--[=[
1532{ `Forin{ { `Id "k":`TBase number, `Id "v":`TBase string }, { `Call{ `Index{ `Id "_ENV", `String "ipairs" }, `Table{ `String "hello", `String "world" } } }, { } } }
1533]=]
1534
1535r, m = parse(s)
1536assert(r == true)
1537
1538s = [=[
1539for k:string, v in pairs({}) do end
1540]=]
1541--[=[
1542{ `Forin{ { `Id "k":`TBase string, `Id "v" }, { `Call{ `Index{ `Id "_ENV", `String "pairs" }, `Table } }, { } } }
1543]=]
1544
1545r, m = parse(s)
1546assert(r == true)
1547
1548s = [=[
1549for k, v:boolean in pairs({}) do end
1550]=]
1551--[=[
1552{ `Forin{ { `Id "k", `Id "v":`TBase boolean }, { `Call{ `Index{ `Id "_ENV", `String "pairs" }, `Table } }, { } } }
1553]=]
1554
1555r, m = parse(s)
1556assert(r == true)
1557
1558s = [=[
1559local function f (x:any) end
1560]=]
1561--[=[
1562{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TAny }, { } } } } }
1563]=]
1564
1565r, m = parse(s)
1566assert(r == true)
1567
1568s = [=[
1569local function f (x:any):(any) end
1570]=]
1571--[=[
1572{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TAny }:`TTuple{ `TAny, `TVararg{ `TNil } }, { } } } } }
1573]=]
1574
1575r, m = parse(s)
1576assert(r == true)
1577
1578s = [=[
1579local function f (...:any) end
1580]=]
1581--[=[
1582{ `Localrec{ { `Id "f" }, { `Function{ { `Dots:`TAny }, { } } } } }
1583]=]
1584
1585r, m = parse(s)
1586assert(r == true)
1587
1588s = [=[
1589local function f (x:any, ...:any) end
1590]=]
1591--[=[
1592{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TAny, `Dots:`TAny }, { } } } } }
1593]=]
1594
1595r, m = parse(s)
1596assert(r == true)
1597
1598s = [=[
1599local function f (x, ...:any) end
1600]=]
1601--[=[
1602{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x", `Dots:`TAny }, { } } } } }
1603]=]
1604
1605r, m = parse(s)
1606assert(r == true)
1607
1608s = [=[
1609local function f (x:any, ...) end
1610]=]
1611--[=[
1612{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TAny, `Dots }, { } } } } }
1613]=]
1614
1615r, m = parse(s)
1616assert(r == true)
1617
1618s = [=[
1619local function f (x:any, ...:any):(any) end
1620]=]
1621--[=[
1622{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TAny, `Dots:`TAny }:`TTuple{ `TAny, `TVararg{ `TNil } }, { } } } } }
1623]=]
1624
1625r, m = parse(s)
1626assert(r == true)
1627
1628s = [=[
1629local function f (x:(any) -> (any)):((any) -> (any)) end
1630]=]
1631--[=[
1632{ `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 } }, { } } } } }
1633]=]
1634
1635r, m = parse(s)
1636assert(r == true)
1637
1638s = [=[
1639local function f (x:(number, number) -> (number, nil*)):(number*) end
1640]=]
1641--[=[
1642{ `Localrec{ { `Id "f" }, { `Function{ { `Id "x":`TFunction{ `TTuple{ `TBase number, `TBase number, `TVararg{ `TValue } }, `TTuple{ `TBase number, `TVararg{ `TNil } } } }:`TTuple{ `TVararg{ `TBase number } }, { } } } } }
1643]=]
1644
1645r, m = parse(s)
1646assert(r == true)
1647
1648s = [=[
1649local function f ():(number, nil*) end
1650]=]
1651--[=[
1652{ `Localrec{ { `Id "f" }, { `Function{ { }:`TTuple{ `TBase number, `TVararg{ `TNil } }, { } } } } }
1653]=]
1654
1655r, m = parse(s)
1656assert(r == true)
1657
1658s = [=[
1659local function f ():number end
1660]=]
1661--[=[
1662{ `Localrec{ { `Id "f" }, { `Function{ { }:`TTuple{ `TBase number, `TVararg{ `TNil } }, { } } } } }
1663]=]
1664
1665r, m = parse(s)
1666assert(r == true)
1667
1668s = [=[
1669local function f ():number? end
1670]=]
1671--[=[
1672{ `Localrec{ { `Id "f" }, { `Function{ { }:`TTuple{ `TUnion{ `TBase number, `TNil }, `TVararg{ `TNil } }, { } } } } }
1673]=]
1674
1675r, m = parse(s)
1676assert(r == true)
1677
1678s = [=[
1679local function f ():(number) | (nil,string) end
1680]=]
1681--[=[
1682{ `Localrec{ { `Id "f" }, { `Function{ { }:`TUnionlist{ `TTuple{ `TBase number, `TVararg{ `TNil } }, `TTuple{ `TNil, `TBase string, `TVararg{ `TNil } } }, { } } } } }
1683]=]
1684
1685r, m = parse(s)
1686assert(r == true)
1687
1688s = [=[
1689local function f ():(number)? end
1690]=]
1691--[=[
1692{ `Localrec{ { `Id "f" }, { `Function{ { }:`TUnionlist{ `TTuple{ `TBase number, `TVararg{ `TNil } }, `TTuple{ `TNil, `TBase string, `TVararg{ `TNil } } }, { } } } } }
1693]=]
1694
1695r, m = parse(s)
1696assert(r == true)
1697
1698-- syntax error
1699
1700-- anonymous functions
1701
1702s = [=[
1703a = function (a,b,) end
1704]=]
1705--[=[
1706test.lua:1:19: syntax error, unexpected ')', expecting '...', 'Name'
1707]=]
1708e = [=[
1709test.lua:1:18: expecting '...'
1710]=]
1711
1712r, m = parse(s)
1713assert(m == e)
1714
1715s = [=[
1716a = function (...,a) end
1717]=]
1718--[=[
1719test.lua:1:18: syntax error, unexpected ',', expecting ')', ':'
1720]=]
1721e = [=[
1722test.lua:1:17: missing ')'
1723]=]
1724
1725r, m = parse(s)
1726assert(m == e)
1727
1728s = [=[
1729local a = function (1) end
1730]=]
1731--[=[
1732test.lua:1:21: syntax error, unexpected '1', expecting ')', '...', 'Name'
1733]=]
1734e = [=[
1735test.lua:1:20: missing ')'
1736]=]
1737
1738r, m = parse(s)
1739assert(m == e)
1740
1741s = [=[
1742local test = function ( a , b , c , ... )
1743]=]
1744--[=[
1745test.lua:2:1: syntax error, unexpected 'EOF', expecting 'end', 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ':'
1746]=]
1747e = [=[
1748test.lua:2:1: missing 'end' to close function declaration
1749]=]
1750
1751r, m = parse(s)
1752assert(m == e)
1753
1754-- arithmetic expressions
1755
1756s = [=[
1757a = 3 / / 2
1758]=]
1759--[=[
1760test.lua:1:9: syntax error, unexpected '/', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not'
1761]=]
1762e = [=[
1763test.lua:1:8: malformed multiplication expression
1764]=]
1765
1766r, m = parse(s)
1767assert(m == e)
1768
1769-- bitwise expressions
1770
1771s = [=[
1772b = 1 && 1
1773]=]
1774--[=[
1775test.lua:1:8: syntax error, unexpected '&', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not'
1776]=]
1777e = [=[
1778test.lua:1:7: malformed '&' expression
1779]=]
1780
1781r, m = parse(s)
1782assert(m == e)
1783
1784s = [=[
1785b = 1 <> 0
1786]=]
1787--[=[
1788test.lua:1:8: syntax error, unexpected '>', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not'
1789]=]
1790e = [=[
1791test.lua:1:7: malformed relational expression
1792]=]
1793
1794r, m = parse(s)
1795assert(m == e)
1796
1797s = [=[
1798b = 1 < < 0
1799]=]
1800--[=[
1801test.lua:1:9: syntax error, unexpected '<', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not'
1802]=]
1803e = [=[
1804test.lua:1:8: malformed relational expression
1805]=]
1806
1807r, m = parse(s)
1808assert(m == e)
1809
1810-- concatenation expressions
1811
1812s = [=[
1813concat2 = 2^3..1
1814]=]
1815--[=[
1816test.lua:1:15: syntax error, unexpected '.1', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^'
1817]=]
1818e = [=[
1819test.lua:1:14: malformed <number>
1820]=]
1821
1822r, m = parse(s)
1823assert(m == e)
1824
1825-- for generic
1826
1827s = [=[
1828for k;v in pairs(t) do end
1829]=]
1830--[=[
1831test.lua:1:6: syntax error, unexpected ';', expecting 'in', ',', ':', '='
1832]=]
1833e = [=[
1834test.lua:1:5: expecting 'in'
1835]=]
1836
1837r, m = parse(s)
1838assert(m == e)
1839
1840s = [=[
1841for k,v in pairs(t:any) do end
1842]=]
1843--[=[
1844test.lua:1:23: syntax error, unexpected ')', expecting 'String', '{', '('
1845]=]
1846e = [=[
1847test.lua:1:22: expecting '(' for method call
1848]=]
1849
1850r, m = parse(s)
1851assert(m == e)
1852
1853-- for numeric
1854
1855s = [=[
1856for i=1,10, do end
1857]=]
1858--[=[
1859test.lua:1:13: syntax error, unexpected 'do', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not'
1860]=]
1861e = [=[
1862test.lua:1:10: missing 'do' in for statement
1863]=]
1864
1865r, m = parse(s)
1866assert(m == e)
1867
1868s = [=[
1869for i=1,n:number do end
1870]=]
1871--[=[
1872test.lua:1:18: syntax error, unexpected 'do', expecting 'String', '{', '('
1873]=]
1874e = [=[
1875test.lua:1:17: expecting '(' for method call
1876]=]
1877
1878r, m = parse(s)
1879assert(m == e)
1880
1881-- global functions
1882
1883s = [=[
1884function func(a,b,c,) end
1885]=]
1886--[=[
1887test.lua:1:21: syntax error, unexpected ')', expecting '...', 'Name'
1888]=]
1889e = [=[
1890test.lua:1:20: expecting '...'
1891]=]
1892
1893r, m = parse(s)
1894assert(m == e)
1895
1896s = [=[
1897function func(...,a) end
1898]=]
1899--[=[
1900test.lua:1:18: syntax error, unexpected ',', expecting ')', ':'
1901]=]
1902e = [=[
1903test.lua:1:17: missing ')'
1904]=]
1905
1906r, m = parse(s)
1907assert(m == e)
1908
1909s = [=[
1910function a.b:c:d () end
1911]=]
1912--[=[
1913test.lua:1:15: syntax error, unexpected ':', expecting '('
1914]=]
1915e = [=[
1916test.lua:1:14: missing '('
1917]=]
1918
1919r, m = parse(s)
1920assert(m == e)
1921
1922-- goto
1923
1924s = [=[
1925:: label :: return
1926goto label
1927]=]
1928--[=[
1929test.lua:2:1: syntax error, unexpected 'goto', expecting ';', '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not'
1930]=]
1931e = [=[
1932test.lua:2:1: invalid statement after 'return'
1933]=]
1934
1935r, m = parse(s)
1936assert(m == e)
1937
1938-- if-else
1939
1940s = [=[
1941if a then
1942]=]
1943--[=[
1944test.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', ';'
1945]=]
1946e = [=[
1947test.lua:2:1: missing 'end' to close if statement
1948]=]
1949
1950r, m = parse(s)
1951assert(m == e)
1952
1953s = [=[
1954if a then else
1955]=]
1956--[=[
1957test.lua:2:1: syntax error, unexpected 'EOF', expecting 'end', 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';'
1958]=]
1959e = [=[
1960test.lua:2:1: missing 'end' to close if statement
1961]=]
1962
1963r, m = parse(s)
1964assert(m == e)
1965
1966s = [=[
1967if a then
1968 return a
1969elseif b then
1970 return b
1971elseif
1972
1973end
1974]=]
1975--[=[
1976test.lua:7:1: syntax error, unexpected 'end', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not'
1977]=]
1978e = [=[
1979test.lua:7:1: expecting <exp> after 'elseif'
1980]=]
1981
1982r, m = parse(s)
1983assert(m == e)
1984
1985s = [=[
1986if a:any then else end
1987]=]
1988--[=[
1989test.lua:1:10: syntax error, unexpected 'then', expecting 'String', '{', '('
1990]=]
1991e = [=[
1992test.lua:1:9: expecting '(' for method call
1993]=]
1994
1995r, m = parse(s)
1996assert(m == e)
1997
1998-- labels
1999
2000s = [=[
2001:: blah ::
2002:: not ::
2003]=]
2004--[=[
2005test.lua:2:4: syntax error, unexpected 'not', expecting 'Name'
2006]=]
2007e = [=[
2008test.lua:2:3: expecting <name> after '::'
2009]=]
2010
2011r, m = parse(s)
2012assert(m == e)
2013
2014-- locals
2015
2016s = [=[
2017local a =
2018]=]
2019--[=[
2020test.lua:2:1: syntax error, unexpected 'EOF', expecting '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not'
2021]=]
2022e = [=[
2023test.lua:2:1: expecting expression list after '='
2024]=]
2025
2026r, m = parse(s)
2027assert(m == e)
2028
2029s = [=[
2030local function t.a() end
2031]=]
2032--[=[
2033test.lua:1:17: syntax error, unexpected '.', expecting '('
2034]=]
2035e = [=[
2036test.lua:1:16: missing '('
2037]=]
2038
2039r, m = parse(s)
2040assert(m == e)
2041
2042s = [=[
2043local function test (a,) end
2044]=]
2045--[=[
2046test.lua:1:24: syntax error, unexpected ')', expecting '...', 'Name'
2047]=]
2048e = [=[
2049test.lua:1:23: expecting '...'
2050]=]
2051
2052r, m = parse(s)
2053assert(m == e)
2054
2055s = [=[
2056local function test(...,a) end
2057]=]
2058--[=[
2059test.lua:1:24: syntax error, unexpected ',', expecting ')', ':'
2060]=]
2061e = [=[
2062test.lua:1:23: missing ')'
2063]=]
2064
2065r, m = parse(s)
2066assert(m == e)
2067
2068s = [=[
2069local function (a, b, c, ...) end
2070]=]
2071--[=[
2072test.lua:1:16: syntax error, unexpected '(', expecting 'Name'
2073]=]
2074e = [=[
2075test.lua:1:15: expecting <name> in local function declaration
2076]=]
2077
2078r, m = parse(s)
2079assert(m == e)
2080
2081-- repeat
2082
2083s = [=[
2084repeat
2085 a,b,c = 1+1,2+2,3+3
2086 break
2087]=]
2088--[=[
2089test.lua:4:1: syntax error, unexpected 'EOF', expecting 'until', 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';'
2090]=]
2091e = [=[
2092test.lua:4:1: missing 'until' in repeat statement
2093]=]
2094
2095r, m = parse(s)
2096assert(m == e)
2097
2098-- return
2099
2100s = [=[
2101return
2102return 1
2103return 1,1-2*3+4,"alo"
2104return;
2105return 1;
2106return 1,1-2*3+4,"alo";
2107]=]
2108--[=[
2109test.lua:2:1: syntax error, unexpected 'return', expecting ';', '(', 'Name', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not'
2110]=]
2111e = [=[
2112test.lua:2:1: invalid statement
2113]=]
2114
2115r, m = parse(s)
2116assert(m == e)
2117
2118-- tables
2119
2120s = [=[
2121t = { , }
2122]=]
2123--[=[
2124test.lua:1:7: syntax error, unexpected ',', expecting '}', '(', '{', 'function', '...', 'true', 'false', 'nil', 'String', 'Number', '#', '~', '-', 'not', 'Name', '[', 'const'
2125]=]
2126e = [=[
2127test.lua:1:6: missing '}'
2128]=]
2129
2130r, m = parse(s)
2131assert(m == e)
2132
2133-- while
2134
2135s = [=[
2136i = 0
2137while (i < 10)
2138 i = i + 1
2139end
2140]=]
2141--[=[
2142test.lua:3:3: syntax error, unexpected 'i', expecting 'do', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^', 'String', '{', '(', ':', '[', '.'
2143]=]
2144e = [=[
2145test.lua:3:2: missing 'do' in while statement
2146]=]
2147
2148r, m = parse(s)
2149assert(m == e)
2150
2151-- type annotations
2152
2153s = [=[
2154t[x:any] = 1
2155]=]
2156--[=[
2157test.lua:1:8: syntax error, unexpected ']', expecting 'String', '{', '('
2158]=]
2159e = [=[
2160test.lua:1:7: expecting '(' for method call
2161]=]
2162
2163r, m = parse(s)
2164assert(m == e)
2165
2166s = [=[
2167x:number, y, z:boolean = 1, nil, true
2168]=]
2169--[=[
2170test.lua:1:9: syntax error, unexpected ',', expecting 'String', '{', '('
2171]=]
2172e = [=[
2173test.lua:1:8: expecting '(' for method call
2174]=]
2175
2176r, m = parse(s)
2177assert(m == e)
2178
2179s = [=[
2180x = x:any
2181]=]
2182--[=[
2183test.lua:2:1: syntax error, unexpected 'EOF', expecting 'String', '{', '('
2184]=]
2185e = [=[
2186test.lua:2:1: expecting '(' for method call
2187]=]
2188
2189r, m = parse(s)
2190assert(m == e)
2191
2192s = [=[
2193x = ...:any
2194]=]
2195--[=[
2196test.lua:1:8: syntax error, unexpected ':', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^'
2197]=]
2198e = [=[
2199test.lua:1:7: invalid statement
2200]=]
2201
2202r, m = parse(s)
2203assert(m == e)
2204
2205s = [=[
2206f(x:any)
2207]=]
2208--[=[
2209test.lua:1:8: syntax error, unexpected ')', expecting 'String', '{', '('
2210]=]
2211e = [=[
2212test.lua:1:7: expecting '(' for method call
2213]=]
2214
2215r, m = parse(s)
2216assert(m == e)
2217
2218s = [=[
2219f(...:any)
2220]=]
2221--[=[
2222test.lua:1:6: syntax error, unexpected ':', expecting ')', ',', 'or', 'and', '>', '<', '>=', '<=', '==', '~=', '|', '~', '&', '>>', '<<', '..', '-', '+', '%', '/', '//', '*', '^'
2223]=]
2224e = [=[
2225test.lua:1:5: missing ')'
2226]=]
2227
2228r, m = parse(s)
2229assert(m == e)
2230
2231s = [=[
2232local x:number*
2233]=]
2234--[=[
2235test.lua:1:15: syntax error, unexpected '*', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', '=', ',', '?', '|'
2236]=]
2237e = [=[
2238test.lua:1:6: invalid local declaration
2239]=]
2240
2241r, m = parse(s)
2242assert(m == e)
2243
2244s = [=[
2245local x:number|
2246]=]
2247--[=[
2248test.lua:2:1: syntax error, unexpected 'EOF', expecting '{', '(', 'Type'
2249]=]
2250e = [=[
2251test.lua:2:1: expecting <type> after '|'
2252]=]
2253
2254r, m = parse(s)
2255assert(m == e)
2256
2257s = [=[
2258local x:number?|string?
2259]=]
2260--[=[
2261test.lua:1:16: syntax error, unexpected '|', expecting 'return', '(', 'Name', 'typealias', 'interface', 'goto', 'break', '::', 'local', 'function', 'const', 'repeat', 'for', 'do', 'while', 'if', ';', '=', ','
2262]=]
2263e = [=[
2264test.lua:1:6: invalid local declaration
2265]=]
2266
2267r, m = parse(s)
2268assert(m == e)
2269
2270s = [=[
2271local x:() -> number
2272]=]
2273--[=[
2274test.lua:1:15: syntax error, unexpected 'number', expecting '('
2275]=]
2276e = [=[
2277test.lua:1:14: expecting <type> after '->'
2278]=]
2279
2280r, m = parse(s)
2281assert(m == e)
2282
2283s = [=[
2284local x:() -> (number)? | (string)?
2285]=]
2286--[=[
2287test.lua:1:35: syntax error, unexpected '?', expecting '->'
2288]=]
2289e = [=[
2290test.lua:1:26: expecting <type> after '|'
2291]=]
2292
2293r, m = parse(s)
2294assert(m == e)
2295
2296s = [=[
2297local x:{()->():string}
2298]=]
2299--[=[
2300test.lua:1:16: syntax error, unexpected ':', expecting '}', '?', '|'
2301]=]
2302e = [=[
2303test.lua:1:15: missing '}'
2304]=]
2305
2306r, m = parse(s)
2307assert(m == e)
2308
2309s = [=[
2310local x:{string:t 1}
2311]=]
2312--[=[
2313test.lua:1:19: syntax error, unexpected '1', expecting '}', '?', '|'
2314]=]
2315e = [=[
2316test.lua:1:18: missing '}'
2317]=]
2318
2319r, m = parse(s)
2320assert(m == e)
2321
2322s = [=[
2323local x:{{{{{}}}}
2324]=]
2325--[=[
2326test.lua:2:1: syntax error, unexpected 'EOF', expecting '}', '?', '|'
2327]=]
2328e = [=[
2329test.lua:2:1: missing '}'
2330]=]
2331
2332r, m = parse(s)
2333assert(m == e)
2334
2335-- syntax errors that depend on some semantic information
2336
2337-- break
2338
2339s = [=[
2340break
2341]=]
2342--[=[
2343test.lua:1:1: syntax error, <break> not inside a loop
2344]=]
2345
2346r, m = parse(s)
2347assert(r == true)
2348
2349s = [=[
2350function f (x)
2351 if 1 then break end
2352end
2353]=]
2354--[=[
2355test.lua:2:13: syntax error, <break> not inside a loop
2356]=]
2357
2358r, m = parse(s)
2359assert(r == true)
2360
2361s = [=[
2362while 1 do
2363end
2364break
2365]=]
2366--[=[
2367test.lua:3:1: syntax error, <break> not inside a loop
2368]=]
2369
2370r, m = parse(s)
2371assert(r == true)
2372
2373-- goto
2374
2375s = [=[
2376goto label
2377]=]
2378--[=[
2379test.lua:1:1: syntax error, no visible label 'label' for <goto>
2380]=]
2381
2382r, m = parse(s)
2383assert(r == true)
2384
2385s = [=[
2386goto label
2387::other_label::
2388]=]
2389--[=[
2390test.lua:1:1: syntax error, no visible label 'label' for <goto>
2391]=]
2392
2393r, m = parse(s)
2394assert(r == true)
2395
2396s = [=[
2397::other_label::
2398do do do goto label end end end
2399]=]
2400--[=[
2401test.lua:2:10: syntax error, no visible label 'label' for <goto>
2402]=]
2403
2404r, m = parse(s)
2405assert(r == true)
2406
2407-- interfaces
2408
2409s = [=[
2410local interface X
2411 x:number
2412 y:number
2413 z:number
2414 x:number
2415end
2416]=]
2417--[=[
2418test.lua:1:7: syntax error, attempt to redeclare field 'x'
2419]=]
2420
2421r, m = parse(s)
2422assert(r == true)
2423
2424s = [=[
2425local interface X
2426 x, y, z, x:number
2427end
2428]=]
2429--[=[
2430test.lua:1:7: syntax error, attempt to redeclare field 'x'
2431]=]
2432
2433r, m = parse(s)
2434assert(r == true)
2435
2436s = [=[
2437local interface boolean end
2438]=]
2439--[=[
2440test.lua:1:7: syntax error, attempt to redeclare type 'boolean'
2441]=]
2442
2443r, m = parse(s)
2444assert(r == true)
2445
2446s = [=[
2447local interface number end
2448]=]
2449--[=[
2450test.lua:1:7: syntax error, attempt to redeclare type 'number'
2451]=]
2452
2453r, m = parse(s)
2454assert(r == true)
2455
2456s = [=[
2457local interface string end
2458]=]
2459--[=[
2460test.lua:1:7: syntax error, attempt to redeclare type 'string'
2461]=]
2462
2463r, m = parse(s)
2464assert(r == true)
2465
2466s = [=[
2467local interface value end
2468]=]
2469--[=[
2470test.lua:1:7: syntax error, attempt to redeclare type 'value'
2471]=]
2472
2473r, m = parse(s)
2474assert(r == true)
2475
2476s = [=[
2477local interface any end
2478]=]
2479--[=[
2480test.lua:1:7: syntax error, attempt to redeclare type 'any'
2481]=]
2482
2483r, m = parse(s)
2484assert(r == true)
2485
2486s = [=[
2487local interface self end
2488]=]
2489--[=[
2490test.lua:1:7: syntax error, attempt to redeclare type 'self'
2491]=]
2492
2493r, m = parse(s)
2494assert(r == true)
2495
2496s = [=[
2497local interface const end
2498]=]
2499--[=[
2500test.lua:1:7: syntax error, attempt to redeclare type 'const'
2501]=]
2502
2503r, m = parse(s)
2504assert(r == true)
2505
2506-- labels
2507
2508s = [=[
2509::label::
2510::other_label::
2511::label::
2512]=]
2513--[=[
2514test.lua:3:1: syntax error, label 'label' already defined
2515]=]
2516
2517r, m = parse(s)
2518assert(r == true)
2519
2520-- vararg
2521
2522s = [=[
2523function f ()
2524 return ...
2525end
2526]=]
2527--[=[
2528test.lua:2:10: syntax error, cannot use '...' outside a vararg function
2529]=]
2530
2531r, m = parse(s)
2532assert(r == true)
2533
2534s = [=[
2535function f ()
2536 function g (x, y)
2537 return ...,...,...
2538 end
2539end
2540]=]
2541--[=[
2542test.lua:3:12: syntax error, cannot use '...' outside a vararg function
2543]=]
2544
2545r, m = parse(s)
2546assert(r == true)
2547
2548s = [=[
2549local function f (x)
2550 return ...
2551end
2552]=]
2553--[=[
2554test.lua:2:10: syntax error, cannot use '...' outside a vararg function
2555]=]
2556
2557r, m = parse(s)
2558assert(r == true)
2559
2560s = [=[
2561local f = function (x)
2562 return ...
2563end
2564]=]
2565--[=[
2566test.lua:2:10: syntax error, cannot use '...' outside a vararg function
2567]=]
2568
2569r, m = parse(s)
2570assert(r == true)
2571
2572print("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 @@
1
2local errors = {}
3local function new_error (label, msg)
4 table.insert(errors, { label = label, msg = msg })
5end
6
7new_error("Number", "malformed <number>")
8new_error("String", "malformed <string>")
9new_error("LongString", "unfinished long string")
10new_error("LongComment", "unfinished long comment")
11new_error("MissingOP", "missing '('")
12new_error("MissingCP", "missing ')'")
13new_error("MissingCC", "missing '}'")
14new_error("MissingCB", "missing ']'")
15new_error("UnionType", "expecting <type> after '|'")
16new_error("FunctionType", "expecting <type> after '->'")
17new_error("MethodType", "expecting <type> after '=>'")
18new_error("TupleType", "expecting <type> after ','")
19new_error("Type", "expecting <type> after ':'")
20new_error("TypeDecEnd", "missing 'end' in type declaration")
21new_error("TypeAliasName", "expecting <name> after 'typealias'")
22new_error("MissingEqTypeAlias", "missing '=' in 'typealias'")
23new_error("DotIndex", "expecting <name> after '.'")
24new_error("MethodName", "expecting <name> after ':'")
25new_error("Then", "missing 'then'")
26new_error("IfEnd", "missing 'end' to close if statement")
27new_error("WhileDo", "missing 'do' in while statement")
28new_error("WhileEnd", "missing 'end' to close while statement")
29new_error("BlockEnd", "missing 'end' to close block")
30new_error("ForDo", "missing 'do' in for statement")
31new_error("ForEnd", "missing 'end' to close for statement")
32new_error("Until", "missing 'until' in repeat statement")
33new_error("FuncEnd", "missing 'end' to close function declaration")
34new_error("ParList", "expecting '...'")
35new_error("MethodCall", "expecting '(' for method call")
36new_error("Label1", "expecting <name> after '::'")
37new_error("Label2", "expecting '::' to close label declaration")
38new_error("LocalAssign1", "expecting expression list after '='")
39new_error("LocalAssign2", "invalid local declaration")
40new_error("ForGen", "expecting 'in'")
41new_error("LocalFunc", "expecting <name> in local function declaration")
42new_error("RetStat", "invalid statement after 'return'")
43new_error("ElseIf", "expecting <exp> after 'elseif'")
44new_error("SubExpr_1", "malformed 'or' expression")
45new_error("SubExpr_2", "malformed 'and' expression")
46new_error("SubExpr_3", "malformed relational expression")
47new_error("SubExpr_4", "malformed '|' expression")
48new_error("SubExpr_5", "malformed '~' expression")
49new_error("SubExpr_6", "malformed '&' expression")
50new_error("SubExpr_7", "malformed shift expression")
51new_error("SubExpr_8", "malformed '..' expression")
52new_error("SubExpr_9", "malformed addition expression")
53new_error("SubExpr_10", "malformed multiplication expression")
54new_error("SubExpr_11", "malformed unary expression")
55new_error("SubExpr_12", "malformed '^' expression")
56new_error("Stat", "invalid statement")
57
58local labels = {}
59for k, v in ipairs(errors) do
60 labels[v.label] = k
61end
62
63return {
64 errors = errors,
65 labels = labels,
66}
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 @@
1local tllexer = {}
2
3local lpeg = require "lpeglabel"
4lpeg.locale(lpeg)
5
6local tlerror = require "tlerror"
7
8function tllexer.try (pat, label)
9 return pat + lpeg.T(tlerror.labels[label])
10end
11
12local function setffp (s, i, t, n)
13 if not t.ffp or i > t.ffp then
14 t.ffp = i
15 t.list = {}
16 t.list[n] = true
17 t.expected = "'" .. n .. "'"
18 elseif i == t.ffp then
19 if not t.list[n] then
20 t.list[n] = true
21 t.expected = "'" .. n .. "', " .. t.expected
22 end
23 end
24 return false
25end
26
27local function updateffp (name)
28 return lpeg.Cmt(lpeg.Carg(1) * lpeg.Cc(name), setffp)
29end
30
31tllexer.Shebang = lpeg.P("#") * (lpeg.P(1) - lpeg.P("\n"))^0 * lpeg.P("\n")
32
33local Space = lpeg.space^1
34
35local Equals = lpeg.P("=")^0
36local Open = "[" * lpeg.Cg(Equals, "init") * "[" * lpeg.P("\n")^-1
37local Close = "]" * lpeg.C(Equals) * "]"
38local CloseEQ = lpeg.Cmt(Close * lpeg.Cb("init"),
39 function (s, i, a, b) return a == b end)
40
41local LongString = Open * (lpeg.P(1) - CloseEQ)^0 * tllexer.try(Close, "LongString") /
42 function (s, o) return s end
43
44local LongStringCm1 = Open * (lpeg.P(1) - CloseEQ)^0 * Close /
45 function (s, o) return s end
46
47local Comment = lpeg.Rec(lpeg.P"--" * #Open * (LongStringCm1 / function() return end + lpeg.T(tlerror.labels["LongString"])),
48 lpeg.T(tlerror.labels["LongComment"]), tlerror.labels["LongString"]) +
49 lpeg.P("--") * (lpeg.P(1) - lpeg.P("\n"))^0
50
51tllexer.Skip = (Space + Comment)^0
52
53local idStart = lpeg.alpha + lpeg.P("_")
54local idRest = lpeg.alnum + lpeg.P("_")
55
56local Keywords = lpeg.P("and") + "break" + "do" + "elseif" + "else" + "end" +
57 "false" + "for" + "function" + "goto" + "if" + "in" +
58 "local" + "nil" + "not" + "or" + "repeat" + "return" +
59 "then" + "true" + "until" + "while"
60
61tllexer.Reserved = Keywords * -idRest
62
63local Identifier = idStart * idRest^0
64
65tllexer.Name = -tllexer.Reserved * Identifier * -idRest
66
67function tllexer.token (pat, name)
68 return pat * tllexer.Skip + updateffp(name) * lpeg.P(false)
69end
70
71function tllexer.symb (str)
72 return tllexer.token(lpeg.P(str), str)
73end
74
75function tllexer.kw (str)
76 return tllexer.token(lpeg.P(str) * -idRest, str)
77end
78
79local Hex = (lpeg.P("0x") + lpeg.P("0X")) * tllexer.try(lpeg.xdigit^1, "Number")
80local Expo = lpeg.S("eE") * lpeg.S("+-")^-1 * tllexer.try(lpeg.digit^1, "Number")
81local Float = (((lpeg.digit^1 * lpeg.P(".") * lpeg.digit^0 * tllexer.try(-lpeg.P("."), "Number")) +
82 (lpeg.P(".") * lpeg.digit^1)) * Expo^-1) +
83 (lpeg.digit^1 * Expo)
84local Int = lpeg.digit^1
85
86tllexer.Number = Hex + Float + Int
87
88local ShortString = lpeg.P('"') *
89 ((lpeg.P('\\') * lpeg.P(1)) + (lpeg.P(1) - lpeg.P('"')))^0 *
90 tllexer.try(lpeg.P('"'), "String") +
91 lpeg.P("'") *
92 ((lpeg.P("\\") * lpeg.P(1)) + (lpeg.P(1) - lpeg.P("'")))^0 *
93 tllexer.try(lpeg.P("'"), "String")
94
95tllexer.String = LongString + ShortString
96
97-- for error reporting
98tllexer.OneWord = tllexer.Name +
99 tllexer.Number +
100 tllexer.String +
101 tllexer.Reserved +
102 lpeg.P("...") +
103 lpeg.P(1)
104
105return 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 @@
1local tlparser = require "tlparser"
2
3local function getcontents(filename)
4 file = assert(io.open(filename, "r"))
5 contents = file:read("*a")
6 file:close()
7 return contents
8end
9
10if #arg ~= 1 then
11 print ("Usage: lua tlp.lua <file>")
12 os.exit(1)
13end
14
15local filename = arg[1]
16local subject = getcontents(filename)
17local r, msg = tlparser.parse(subject, filename, false, true)
18if not r then print(msg) end
19
20os.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 @@
1local tlparser = {}
2
3local lpeg = require "lpeglabel"
4lpeg.locale(lpeg)
5
6local tllexer = require "tllexer"
7local tlerror = require "tlerror"
8
9local function chainl1 (pat, sep, label)
10 return pat * (sep * tllexer.try(pat, label))^0
11end
12
13local G = lpeg.P { "TypedLua";
14 TypedLua = tllexer.Shebang^-1 * tllexer.Skip * lpeg.V("Chunk") * tllexer.try(-1, "Stat");
15 -- type language
16 Type = lpeg.V("NilableType");
17 NilableType = lpeg.V("UnionType") * tllexer.symb("?")^-1;
18 UnionType = lpeg.V("PrimaryType") * (tllexer.symb("|") * tllexer.try(lpeg.V("PrimaryType"), "UnionType"))^0;
19 PrimaryType = lpeg.V("LiteralType") +
20 lpeg.V("BaseType") +
21 lpeg.V("NilType") +
22 lpeg.V("ValueType") +
23 lpeg.V("AnyType") +
24 lpeg.V("SelfType") +
25 lpeg.V("FunctionType") +
26 lpeg.V("TableType") +
27 lpeg.V("VariableType");
28 LiteralType = tllexer.token("false", "false") +
29 tllexer.token("true", "true") +
30 tllexer.token(tllexer.Number, "Number") +
31 tllexer.token(tllexer.String, "String");
32 BaseType = tllexer.token("boolean", "boolean") +
33 tllexer.token("number", "number") +
34 tllexer.token("string", "string") +
35 tllexer.token("integer", "integer");
36 NilType = tllexer.token("nil", "nil");
37 ValueType = tllexer.token("value", "value");
38 AnyType = tllexer.token("any", "any");
39 SelfType = tllexer.token("self", "self");
40 FunctionType = lpeg.V("InputType") * tllexer.symb("->") * tllexer.try(lpeg.V("NilableTuple"), "FunctionType");
41 MethodType = lpeg.V("InputType") * tllexer.symb("=>") * tllexer.try(lpeg.V("NilableTuple"), "MethodType");
42 InputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP");
43 NilableTuple = lpeg.V("UnionlistType") * tllexer.symb("?")^-1;
44 UnionlistType = lpeg.V("OutputType") * (tllexer.symb("|") * tllexer.try(lpeg.V("OutputType"), "UnionType"))^0;
45 OutputType = tllexer.symb("(") * lpeg.V("TupleType")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP");
46 TupleType = lpeg.V("Type") * (tllexer.symb(",") * tllexer.try(lpeg.V("Type"), "TupleType"))^0 * tllexer.symb("*")^-1;
47 TableType = tllexer.symb("{") * lpeg.V("TableTypeBody")^-1 * tllexer.try(tllexer.symb("}"), "MissingCC");
48 TableTypeBody = lpeg.V("RecordType") +
49 lpeg.V("HashType") +
50 lpeg.V("ArrayType");
51 RecordType = lpeg.V("RecordField") * (tllexer.symb(",") * lpeg.V("RecordField"))^0 *
52 (tllexer.symb(",") * (lpeg.V("HashType") + lpeg.V("ArrayType")))^-1;
53 RecordField = tllexer.kw("const")^-1 *
54 lpeg.V("LiteralType") * tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type");
55 HashType = lpeg.V("KeyType") * tllexer.symb(":") * tllexer.try(lpeg.V("FieldType"), "Type");
56 ArrayType = lpeg.V("FieldType");
57 KeyType = lpeg.V("BaseType") + lpeg.V("ValueType") + lpeg.V("AnyType");
58 FieldType = lpeg.V("Type");
59 VariableType = tllexer.token(tllexer.Name, "Name");
60 RetType = lpeg.V("NilableTuple") +
61 lpeg.V("Type");
62 Id = tllexer.token(tllexer.Name, "Name");
63 TypeDecId = (tllexer.kw("const") * lpeg.V("Id")) +
64 lpeg.V("Id");
65 IdList = lpeg.V("TypeDecId") * (tllexer.symb(",") * tllexer.try(lpeg.V("TypeDecId"), "TupleType"))^0;
66 IdDec = lpeg.V("IdList") * tllexer.symb(":") * tllexer.try((lpeg.V("Type") + lpeg.V("MethodType")), "Type");
67 IdDecList = (lpeg.V("IdDec")^1)^-1;
68 TypeDec = tllexer.token(tllexer.Name, "Name") * lpeg.V("IdDecList") * tllexer.try(tllexer.kw("end"), "TypeDecEnd");
69 Interface = tllexer.kw("interface") * lpeg.V("TypeDec") +
70 tllexer.kw("typealias") *
71 tllexer.try(tllexer.token(tllexer.Name, "Name"), "TypeAliasName") *
72 tllexer.try(tllexer.symb("="), "MissingEqTypeAlias") * lpeg.V("Type");
73 -- parser
74 Chunk = lpeg.V("Block");
75 StatList = (tllexer.symb(";") + lpeg.V("Stat"))^0;
76 Var = lpeg.V("Id");
77 TypedId = tllexer.token(tllexer.Name, "Name") * (tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type"))^-1;
78 FunctionDef = tllexer.kw("function") * lpeg.V("FuncBody");
79 FieldSep = tllexer.symb(",") + tllexer.symb(";");
80 Field = ((tllexer.symb("[") * lpeg.V("Expr") * tllexer.try(tllexer.symb("]"), "MissingCB")) +
81 (tllexer.token(tllexer.Name, "Name"))) *
82 tllexer.symb("=") * lpeg.V("Expr") +
83 lpeg.V("Expr");
84 TField = (tllexer.kw("const") * lpeg.V("Field")) +
85 lpeg.V("Field");
86 FieldList = (lpeg.V("TField") * (lpeg.V("FieldSep") * lpeg.V("TField"))^0 *
87 lpeg.V("FieldSep")^-1)^-1;
88 Constructor = tllexer.symb("{") * lpeg.V("FieldList") * tllexer.try(tllexer.symb("}"), "MissingCC");
89 NameList = lpeg.V("TypedId") * (tllexer.symb(",") * lpeg.V("TypedId"))^0;
90 ExpList = lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0;
91 FuncArgs = tllexer.symb("(") *
92 (lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 *
93 tllexer.try(tllexer.symb(")"), "MissingCP") +
94 lpeg.V("Constructor") +
95 tllexer.token(tllexer.String, "String");
96 OrOp = tllexer.kw("or");
97 AndOp = tllexer.kw("and");
98 RelOp = tllexer.symb("~=") +
99 tllexer.symb("==") +
100 tllexer.symb("<=") +
101 tllexer.symb(">=") +
102 tllexer.symb("<") +
103 tllexer.symb(">");
104 BOrOp = tllexer.symb("|");
105 BXorOp = tllexer.symb("~") * -lpeg.P("=");
106 BAndOp = tllexer.symb("&");
107 ShiftOp = tllexer.symb("<<") +
108 tllexer.symb(">>");
109 ConOp = tllexer.symb("..");
110 AddOp = tllexer.symb("+") +
111 tllexer.symb("-");
112 MulOp = tllexer.symb("*") +
113 tllexer.symb("//") +
114 tllexer.symb("/") +
115 tllexer.symb("%");
116 UnOp = tllexer.kw("not") +
117 tllexer.symb("-") +
118 tllexer.symb("~") +
119 tllexer.symb("#");
120 PowOp = tllexer.symb("^");
121 Expr = lpeg.V("SubExpr_1");
122 SubExpr_1 = chainl1(lpeg.V("SubExpr_2"), lpeg.V("OrOp"), "SubExpr_1");
123 SubExpr_2 = chainl1(lpeg.V("SubExpr_3"), lpeg.V("AndOp"), "SubExpr_2");
124 SubExpr_3 = chainl1(lpeg.V("SubExpr_4"), lpeg.V("RelOp"), "SubExpr_3");
125 SubExpr_4 = chainl1(lpeg.V("SubExpr_5"), lpeg.V("BOrOp"), "SubExpr_4");
126 SubExpr_5 = chainl1(lpeg.V("SubExpr_6"), lpeg.V("BXorOp"), "SubExpr_5");
127 SubExpr_6 = chainl1(lpeg.V("SubExpr_7"), lpeg.V("BAndOp"), "SubExpr_6");
128 SubExpr_7 = chainl1(lpeg.V("SubExpr_8"), lpeg.V("ShiftOp"), "SubExpr_7");
129 SubExpr_8 = lpeg.V("SubExpr_9") * lpeg.V("ConOp") * tllexer.try(lpeg.V("SubExpr_8"), "SubExpr_8") +
130 lpeg.V("SubExpr_9");
131 SubExpr_9 = chainl1(lpeg.V("SubExpr_10"), lpeg.V("AddOp"), "SubExpr_9");
132 SubExpr_10 = chainl1(lpeg.V("SubExpr_11"), lpeg.V("MulOp"), "SubExpr_10");
133 SubExpr_11 = lpeg.V("UnOp") * tllexer.try(lpeg.V("SubExpr_11"), "SubExpr_11") +
134 lpeg.V("SubExpr_12");
135 SubExpr_12 = lpeg.V("SimpleExp") * (lpeg.V("PowOp") * tllexer.try(lpeg.V("SubExpr_11"), "SubExpr_12"))^-1;
136 SimpleExp = tllexer.token(tllexer.Number, "Number") +
137 tllexer.token(tllexer.String, "String") +
138 tllexer.kw("nil") +
139 tllexer.kw("false") +
140 tllexer.kw("true") +
141 tllexer.symb("...") +
142 lpeg.V("FunctionDef") +
143 lpeg.V("Constructor") +
144 lpeg.V("SuffixedExp");
145 SuffixedExp = lpeg.V("PrimaryExp") * (
146 (tllexer.symb(".") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "DotIndex")) / "index" +
147 (tllexer.symb("[") * lpeg.V("Expr") * tllexer.try(tllexer.symb("]"), "MissingCB")) / "index" +
148 (tllexer.symb(":") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "MethodName") * tllexer.try(lpeg.V("FuncArgs"), "MethodCall")) / "call" +
149 lpeg.V("FuncArgs") / "call")^0 / function (...) local l = {...}; return l[#l] end;
150 PrimaryExp = lpeg.V("Var") / "var" +
151 tllexer.symb("(") * lpeg.V("Expr") * tllexer.try(tllexer.symb(")"), "MissingCP");
152 Block = lpeg.V("StatList") * lpeg.V("RetStat")^-1;
153 IfStat = tllexer.kw("if") * lpeg.V("Expr") * tllexer.try(tllexer.kw("then"), "Then") * lpeg.V("Block") *
154 (tllexer.kw("elseif") * tllexer.try(lpeg.V("Expr"), "ElseIf") * tllexer.try(tllexer.kw("then"), "Then") * lpeg.V("Block"))^0 *
155 (tllexer.kw("else") * lpeg.V("Block"))^-1 *
156 tllexer.try(tllexer.kw("end"), "IfEnd");
157 WhileStat = tllexer.kw("while") * lpeg.V("Expr") *
158 tllexer.try(tllexer.kw("do"), "WhileDo") * lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "WhileEnd");
159 DoStat = tllexer.kw("do") * lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "BlockEnd");
160 ForBody = tllexer.try(tllexer.kw("do"), "ForDo") * lpeg.V("Block");
161 ForNum = lpeg.V("Id") * tllexer.symb("=") * lpeg.V("Expr") * tllexer.symb(",") *
162 lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^-1 *
163 lpeg.V("ForBody");
164 ForGen = lpeg.V("NameList") * tllexer.try(tllexer.kw("in"), "ForGen") *
165 lpeg.V("ExpList") * lpeg.V("ForBody");
166 ForStat = tllexer.kw("for") * (lpeg.V("ForNum") + lpeg.V("ForGen")) * tllexer.try(tllexer.kw("end"), "ForEnd");
167 RepeatStat = tllexer.kw("repeat") * lpeg.V("Block") *
168 tllexer.try(tllexer.kw("until"), "Until") * lpeg.V("Expr");
169 FuncName = lpeg.V("Id") * (tllexer.symb(".") *
170 (tllexer.token(tllexer.Name, "Name")))^0 *
171 (tllexer.symb(":") * (tllexer.token(tllexer.Name, "Name")))^-1;
172 ParList = lpeg.V("NameList") * (tllexer.symb(",") * tllexer.try(lpeg.V("TypedVarArg"), "ParList"))^-1 +
173 lpeg.V("TypedVarArg");
174 TypedVarArg = tllexer.symb("...") * (tllexer.symb(":") * tllexer.try(lpeg.V("Type"), "Type"))^-1;
175 FuncBody = tllexer.try(tllexer.symb("("), "MissingOP") * lpeg.V("ParList")^-1 * tllexer.try(tllexer.symb(")"), "MissingCP") *
176 (tllexer.symb(":") * tllexer.try(lpeg.V("RetType"), "Type"))^-1 *
177 lpeg.V("Block") * tllexer.try(tllexer.kw("end"), "FuncEnd");
178 FuncStat = tllexer.kw("const")^-1 *
179 tllexer.kw("function") * lpeg.V("FuncName") * lpeg.V("FuncBody");
180 LocalFunc = tllexer.kw("function") *
181 tllexer.try(lpeg.V("Id"), "LocalFunc") * lpeg.V("FuncBody");
182 LocalAssign = lpeg.V("NameList") * tllexer.symb("=") * tllexer.try(lpeg.V("ExpList"), "LocalAssign1") +
183 lpeg.V("NameList") * (#(-tllexer.symb("=") * (lpeg.V("Stat") + -1)) * lpeg.P(true)) + lpeg.T(tlerror.labels["LocalAssign2"]);
184 LocalStat = tllexer.kw("local") *
185 (lpeg.V("LocalTypeDec") + lpeg.V("LocalFunc") + lpeg.V("LocalAssign"));
186 LabelStat = tllexer.symb("::") * tllexer.try(tllexer.token(tllexer.Name, "Name"), "Label1") * tllexer.try(tllexer.symb("::"), "Label2");
187 BreakStat = tllexer.kw("break");
188 GoToStat = tllexer.kw("goto") * tllexer.token(tllexer.Name, "Name");
189 RetStat = tllexer.kw("return") * tllexer.try(-lpeg.V("Stat"), "RetStat") *
190 (lpeg.V("Expr") * (tllexer.symb(",") * lpeg.V("Expr"))^0)^-1 *
191 tllexer.symb(";")^-1;
192 TypeDecStat = lpeg.V("Interface");
193 LocalTypeDec = lpeg.V("TypeDecStat");
194 LVar = (tllexer.kw("const") * lpeg.V("SuffixedExp")) +
195 lpeg.V("SuffixedExp");
196 ExprStat = lpeg.Cmt(lpeg.V("LVar") * lpeg.V("Assignment"),
197 function (s, i, ...)
198 local l = {...}
199 local i = 1
200 while l[i] ~= "=" do
201 local se = l[i]
202 if se ~= "var" and se ~= "index" then return false end
203 i = i + 1
204 end
205 return true
206 end) +
207 lpeg.Cmt(lpeg.V("SuffixedExp"),
208 function (s, i, se)
209 if se ~= "call" then return false end
210 return true
211 end);
212 Assignment = ((tllexer.symb(",") * lpeg.V("LVar"))^1)^-1 * (tllexer.symb("=") / "=") * lpeg.V("ExpList");
213 Stat = lpeg.V("IfStat") + lpeg.V("WhileStat") + lpeg.V("DoStat") + lpeg.V("ForStat") +
214 lpeg.V("RepeatStat") + lpeg.V("FuncStat") + lpeg.V("LocalStat") +
215 lpeg.V("LabelStat") + lpeg.V("BreakStat") + lpeg.V("GoToStat") +
216 lpeg.V("TypeDecStat") + lpeg.V("ExprStat");
217}
218
219local function lineno (s, i)
220 if i == 1 then return 1, 1 end
221 local rest, num = s:sub(1,i):gsub("[^\n]*\n", "")
222 local r = #rest
223 return 1 + num, r ~= 0 and r or 1
224end
225
226function tlparser.parse (subject, filename, strict, integer)
227 local errorinfo = {}
228 lpeg.setmaxstack(1000)
229 local ast, label, pos = lpeg.match(G, subject, nil, errorinfo, strict, integer)
230 if not ast then
231 local line, col = lineno(subject, pos)
232 local error_msg = string.format("%s:%d:%d: ", filename, line, col)
233 if label ~= 0 then
234 error_msg = error_msg .. tlerror.errors[label].msg
235 else
236 local u = lpeg.match(lpeg.C(tllexer.OneWord) + lpeg.Cc("EOF"), subject, errorinfo.ffp)
237 error_msg = error_msg .. string.format("unexpected '%s', expecting %s", u, errorinfo.expected)
238 end
239 return nil, error_msg
240 else
241 return true
242 end
243end
244
245return tlparser