diff options
author | Sergio Queiroz <sqmedeiros@gmail.com> | 2016-11-10 16:26:11 -0300 |
---|---|---|
committer | Sergio Queiroz <sqmedeiros@gmail.com> | 2016-11-10 16:26:11 -0300 |
commit | fd28f9d9e54f33bf7ae3a5e12dc71478f9c91aea (patch) | |
tree | 875ab38000e52376583bc13741b18701c6294f80 /testlabel.lua | |
parent | d84dd6b3659f94b09e67eb90a10e71eb05c5630e (diff) | |
download | lpeglabel-fd28f9d9e54f33bf7ae3a5e12dc71478f9c91aea.tar.gz lpeglabel-fd28f9d9e54f33bf7ae3a5e12dc71478f9c91aea.tar.bz2 lpeglabel-fd28f9d9e54f33bf7ae3a5e12dc71478f9c91aea.zip |
Removing labeled choice, updating testlabel, and disabling an optmization related to Throw
Diffstat (limited to 'testlabel.lua')
-rw-r--r-- | testlabel.lua | 453 |
1 files changed, 309 insertions, 144 deletions
diff --git a/testlabel.lua b/testlabel.lua index 25036b2..cb92657 100644 --- a/testlabel.lua +++ b/testlabel.lua | |||
@@ -11,6 +11,15 @@ local function checkeqlab (x, ...) | |||
11 | end | 11 | end |
12 | end | 12 | end |
13 | 13 | ||
14 | local function checkeq (x, y, p) | ||
15 | if p then print(x,y) end | ||
16 | if type(x) ~= "table" then assert(x == y) | ||
17 | else | ||
18 | for k,v in pairs(x) do checkeq(v, y[k], p) end | ||
19 | for k,v in pairs(y) do checkeq(v, x[k], p) end | ||
20 | end | ||
21 | end | ||
22 | |||
14 | -- throws a label | 23 | -- throws a label |
15 | p = m.T(1) | 24 | p = m.T(1) |
16 | s = "abc" | 25 | s = "abc" |
@@ -32,48 +41,97 @@ local g = m.P{ | |||
32 | r, l, serror = g:match(s) | 41 | r, l, serror = g:match(s) |
33 | assert(r == nil and l == 1 and serror == "abc") | 42 | assert(r == nil and l == 1 and serror == "abc") |
34 | 43 | ||
35 | --[==[ TODO: labeled choice does not work anymore | 44 | |
36 | -- throws a label that is not caught by labeled choice | 45 | -- throws a label that is not caught by the recovery operator |
37 | p = m.Lc(m.T(2), m.P"a", 1, 3) | 46 | p = m.Rec(m.T(2), m.P"a", 1, 3) |
38 | r, l, serror = p:match(s) | 47 | r, l, serror = p:match(s) |
39 | assert(r == nil and l == 2 and serror == "abc") | 48 | assert(r == nil and l == 2 and serror == "abc") |
40 | 49 | ||
41 | -- modifies previous pattern | 50 | -- wraps the previous pattern with a recovery that catches label "2" |
42 | -- adds another labeled choice to catch label "2" | 51 | p = m.Rec(p, m.P"a", 2) |
43 | p = m.Lc(p, m.P"a", 2) | ||
44 | assert(p:match(s) == 2) | 52 | assert(p:match(s) == 2) |
45 | 53 | ||
46 | -- throws a label that is caught by labeled choice | 54 | -- throws a label that is caught by recovery |
47 | p = m.Lc(m.T(25), m.P"a", 25) | 55 | p = m.Rec(m.T(25), m.P"a", 25) |
48 | assert(p:match(s) == 2) | 56 | assert(p:match(s) == 2) |
49 | 57 | ||
50 | -- "fail" is label "0" | 58 | -- "fail" is label "0" |
51 | -- throws the "fail" label that is not caught by the labeled choice | 59 | -- throws the "fail" label after the recovery |
52 | s = "bola" | 60 | s = "bola" |
53 | r, l, serror = p:match("bola") | 61 | r, l, serror = p:match("bola") |
54 | assert(r == nil and l == 0 and serror == "bola") | 62 | assert(r == nil and l == 0 and serror == "bola") |
55 | 63 | ||
56 | -- labeled choice does not catch "fail" by default | 64 | -- Recovery does not catch "fail" by default |
57 | p = m.Lc(m.P"b", m.P"a", 1) | 65 | p = m.Rec(m.P"b", m.P"a", 1) |
58 | 66 | ||
59 | r, l, serror = p:match("abc") | 67 | r, l, serror = p:match("abc") |
60 | assert(r == nil and l == 0 and serror == "abc") | 68 | assert(r == nil and l == 0 and serror == "abc") |
61 | 69 | ||
62 | assert(p:match("bola") == 2) | 70 | assert(p:match("bola") == 2) |
63 | 71 | ||
64 | -- labeled choice can catch "fail" | 72 | |
65 | p = m.Lc(m.P"b", m.P"a", 0) | 73 | -- recovery operator catches "1" or "3" |
74 | p = m.Rec((m.P"a" + m.T(1)) * m.T(3), (m.P"a" + m.P"b"), 1, 3) | ||
75 | assert(p:match("aac") == 3) | ||
76 | assert(p:match("abc") == 3) | ||
77 | r, l, serror = p:match("acc") | ||
78 | assert(r == nil and l == 0 and serror == "cc") | ||
79 | |||
80 | --throws 1, recovery pattern matches 'b', throw 3, and rec pat mathces 'a' | ||
81 | assert(p:match("bac") == 3) | ||
82 | |||
83 | r, l, serror = p:match("cab") | ||
84 | assert(r == nil and l == 0 and serror == "cab") | ||
85 | |||
86 | |||
87 | -- associativity | ||
88 | -- (p1 / %1) //{1} (p2 / %2) //{2} p3 | ||
89 | -- left-associativity | ||
90 | -- ("a" //{1} "b") //{2} "c" | ||
91 | p = m.Rec(m.Rec(m.P"a" + m.T(1), m.P"b" + m.T(2), 1), m.P"c", 2) | ||
66 | assert(p:match("abc") == 2) | 92 | assert(p:match("abc") == 2) |
67 | assert(p:match("bola") == 2) | 93 | assert(p:match("bac") == 2) |
94 | assert(p:match("cab") == 2) | ||
95 | r, l, serror = p:match("dab") | ||
96 | assert(r == nil and l == 0 and serror == "dab") | ||
68 | 97 | ||
69 | -- "fail" is label "0" | 98 | |
70 | -- labeled choice catches "fail" or "3" | 99 | -- righ-associativity |
71 | p = m.Lc(m.P"a" * m.T(3), (m.P"a" + m.P"b"), 0, 3) | 100 | -- "a" //{1} ("b" //{2} "c") |
101 | p = m.Rec(m.P"a" + m.T(1), m.Rec(m.P"b" + m.T(2), m.P"c", 2), 1) | ||
72 | assert(p:match("abc") == 2) | 102 | assert(p:match("abc") == 2) |
73 | assert(p:match("bac") == 2) | 103 | assert(p:match("bac") == 2) |
104 | assert(p:match("cab") == 2) | ||
105 | r, l, serror = p:match("dab") | ||
106 | assert(r == nil and l == 0 and serror == "dab") | ||
107 | |||
108 | |||
109 | -- associativity -> in this case the error thrown by p1 is only | ||
110 | -- recovered when we have a left-associative operator | ||
111 | -- (p1 / %2) //{1} (p2 / %2) //{2} p3 | ||
112 | -- left-associativity | ||
113 | -- ("a" //{1} "b") //{2} "c" | ||
114 | p = m.Rec(m.Rec(m.P"a" + m.T(2), m.P"b" + m.T(2), 1), m.P"c", 2) | ||
115 | assert(p:match("abc") == 2) | ||
116 | r, l, serror = p:match("bac") | ||
117 | assert(r == nil and l == 0 and serror == "bac") | ||
118 | assert(p:match("cab") == 2) | ||
119 | r, l, serror = p:match("dab") | ||
120 | assert(r == nil and l == 0 and serror == "dab") | ||
121 | |||
74 | 122 | ||
123 | -- righ-associativity | ||
124 | -- "a" //{1} ("b" //{2} "c") | ||
125 | p = m.Rec(m.P"a" + m.T(2), m.Rec(m.P"b" + m.T(2), m.P"c", 2), 1) | ||
126 | assert(p:match("abc") == 2) | ||
127 | r, l, serror = p:match("bac") | ||
128 | assert(r == nil and l == 2 and serror == "bac") | ||
75 | r, l, serror = p:match("cab") | 129 | r, l, serror = p:match("cab") |
76 | assert(r == nil and l == 0 and serror == "cab") | 130 | assert(r == nil and l == 2 and serror == "cab") |
131 | r, l, serror = p:match("dab") | ||
132 | assert(r == nil and l == 2 and serror == "dab") | ||
133 | |||
134 | |||
77 | 135 | ||
78 | -- tests related to predicates | 136 | -- tests related to predicates |
79 | p = #m.T(1) + m.P"a" | 137 | p = #m.T(1) + m.P"a" |
@@ -84,74 +142,66 @@ p = ##m.T(1) + m.P"a" | |||
84 | r, l, serror = p:match("abc") | 142 | r, l, serror = p:match("abc") |
85 | assert(r == nil and l == 1 and serror == "abc") | 143 | assert(r == nil and l == 1 and serror == "abc") |
86 | 144 | ||
87 | p = #m.T(0) * m.P"a" | ||
88 | assert(p:match("abc") == fail) | ||
89 | |||
90 | p = #m.T(0) + m.P"a" | ||
91 | assert(p:match("abc") == 2) | ||
92 | |||
93 | p = -m.T(1) * m.P"a" | 145 | p = -m.T(1) * m.P"a" |
94 | r, l, serror = p:match("abc") | 146 | r, l, serror = p:match("abc") |
95 | assert(r == nil and l == 1 and serror == "abc") | 147 | assert(r == nil and l == 1 and serror == "abc") |
96 | 148 | ||
149 | p = -m.T(1) * m.P"a" | ||
150 | r, l, serror = p:match("bbc") | ||
151 | assert(r == nil and l == 1 and serror == "bbc") | ||
152 | |||
97 | p = -(-m.T(1)) * m.P"a" | 153 | p = -(-m.T(1)) * m.P"a" |
98 | r, l, serror = p:match("abc") | 154 | r, l, serror = p:match("abc") |
99 | assert(r == nil and l == 1 and serror == "abc") | 155 | assert(r == nil and l == 1 and serror == "abc") |
100 | 156 | ||
101 | p = -m.T(0) * m.P"a" | 157 | p = m.Rec(-m.T(22), m.P"a", 22) |
102 | assert(p:match("abc") == 2) | 158 | r, l, serror = p:match("abc") |
159 | assert(r == nil and l == 0 and serror == "bc") | ||
103 | 160 | ||
104 | p = -m.T(0) + m.P"a" | 161 | assert(p:match("bbc") == 1) |
105 | assert(p:match("abc") == 1) | ||
106 | 162 | ||
107 | p = -(-m.T(0)) + m.P"a" | 163 | p = m.Rec(#m.T(22), m.P"a", 22) |
108 | assert(p:match("abc") == 2) | 164 | assert(p:match("abc") == 1) |
109 | 165 | ||
110 | p = m.Lc(-m.T(22), m.P"a", 22) | 166 | p = #m.Rec(m.T(22), m.P"a", 22) |
111 | assert(p:match("abc") == 2) | 167 | assert(p:match("abc") == 1) |
112 | 168 | ||
113 | p = m.Lc(-m.T(0), m.P"a", 0) | 169 | p = m.Rec(m.T(22), #m.P"a", 22) |
114 | assert(p:match("abc") == 1) | 170 | assert(p:match("abc") == 1) |
115 | 171 | ||
116 | p = m.Lc(#m.T(22), m.P"a", 22) | 172 | p = m.Rec(#m.T(22), m.P"a", 22) |
117 | assert(p:match("abc") == 2) | 173 | r, l, serror = p:match("bbc") |
174 | assert(r == nil and l == 0 and serror == "bbc") | ||
118 | 175 | ||
119 | p = m.Lc(#m.T(0), m.P"a", 0) | ||
120 | assert(p:match("abc") == 2) | ||
121 | 176 | ||
122 | -- tests related to repetition | 177 | -- tests related to repetition |
123 | p = m.T(1)^0 | 178 | p = m.T(1)^0 |
124 | r, l, serror = p:match("ab") | 179 | r, l, serror = p:match("ab") |
125 | assert(r == nil and l == 1 and serror == "ab") | 180 | assert(r == nil and l == 1 and serror == "ab") |
126 | 181 | ||
127 | p = m.T(0)^0 | ||
128 | assert(p:match("ab") == 1) | ||
129 | |||
130 | p = (m.P"a" + m.T(1))^0 | 182 | p = (m.P"a" + m.T(1))^0 |
131 | r, l, serror = p:match("aa") | 183 | r, l, serror = p:match("aa") |
132 | assert(r == nil and l == 1 and serror == "") | 184 | assert(r == nil and l == 1 and serror == "") |
133 | 185 | ||
134 | p = (m.P"a" + m.T(0))^0 | ||
135 | assert(p:match("aa") == 3) | ||
136 | 186 | ||
137 | -- Bug reported by Matthew Allen | 187 | -- Bug reported by Matthew Allen |
138 | -- some optmizations performed by LPeg should not be | 188 | -- some optmizations performed by LPeg should not be |
139 | -- applied in case of labeled choices | 189 | -- applied in case of labeled choices |
140 | p = m.Lc(m.P"A", m.P(true), 1) + m.P("B") | 190 | p = m.Rec(m.P"A", m.P(true), 1) + m.P("B") |
141 | assert(p:match("B") == 2) | 191 | assert(p:match("B") == 2) |
142 | 192 | ||
143 | p = m.Lc(m.P"A", m.P(false), 1) + m.P("B") | 193 | p = m.Rec(m.P"A", m.P(false), 1) + m.P("B") |
144 | assert(p:match("B") == 2) | 194 | assert(p:match("B") == 2) |
145 | 195 | ||
146 | 196 | ||
147 | --[[ | 197 | --[[ |
148 | S -> A /{1} 'a' | 198 | S -> A //{1} 'a' |
149 | A -> B | 199 | A -> B |
150 | B -> %1 | 200 | B -> %1 |
151 | ]] | 201 | ]] |
152 | g = m.P{ | 202 | g = m.P{ |
153 | "S", | 203 | "S", |
154 | S = m.Lc(m.V"A", m.P"a", 1), | 204 | S = m.Rec(m.V"A", m.P"a", 1), |
155 | A = m.V"B", | 205 | A = m.V"B", |
156 | B = m.T(1), | 206 | B = m.T(1), |
157 | } | 207 | } |
@@ -177,66 +227,96 @@ r, l, serror = g:match("a;a") | |||
177 | assert(r == nil and l == 1 and serror == "") | 227 | assert(r == nil and l == 1 and serror == "") |
178 | 228 | ||
179 | 229 | ||
180 | -- %1 /{1,3} %2 /{2} 'a' | 230 | -- %1 //{1,3} %2 //{2} 'a' |
181 | p = m.Lc(m.Lc(m.T(1), m.T(2), 1, 3), m.P"a", 2) | 231 | p = m.Rec(m.Rec(m.T(1), m.T(2), 1, 3), m.P"a", 2) |
182 | assert(p:match("abc") == 2) | 232 | assert(p:match("abc") == 2) |
183 | 233 | ||
184 | r, l, serror = p:match("") | 234 | r, l, serror = p:match("") |
185 | assert(r == nil and l == 0 and serror == "") | 235 | assert(r == nil and l == 0 and serror == "") |
186 | 236 | ||
187 | p = m.Lc(m.T(1), m.Lc(m.T(2), m.P"a", 2), 1, 3) | 237 | p = m.Rec(m.T(1), m.Rec(m.T(2), m.P"a", 2), 1, 3) |
188 | assert(p:match("abc") == 2) | 238 | assert(p:match("abc") == 2) |
189 | 239 | ||
190 | r, l, serror = p:match("") | 240 | r, l, serror = p:match("") |
191 | assert(r == nil and l == 0 and serror == "") | 241 | assert(r == nil and l == 0 and serror == "") |
192 | ]==] | 242 | |
243 | |||
244 | -- Infinte Loop TODO: check the semantics | ||
245 | -- %1 //{1} %1 | ||
246 | p = m.Rec(m.T(1), m.T(1), 1) | ||
247 | --r, l, serror = p:match("ab") | ||
248 | --assert(r == nil and l == 1 and serror == "ab") | ||
249 | |||
250 | -- %1 //{1} 'a' (!. / %1) | ||
251 | p = m.Rec(m.T(1), m.P"a" * (-m.P(1) + m.T(1)), 1) | ||
252 | r, l, serror = p:match("ab") | ||
253 | assert(r == nil and l == 0 and serror == "b") | ||
254 | |||
255 | r, l, serror = p:match("cd") | ||
256 | assert(r == nil and l == 0 and serror == "cd") | ||
257 | |||
258 | -- %1 //{1} . (!. / %1) | ||
259 | p = m.Rec(m.T(1), m.P(1) * (-m.P(1) + m.T(1)), 1) | ||
260 | assert(p:match("abc") == 4) | ||
261 | |||
193 | 262 | ||
194 | -- testing the limit of labels | 263 | -- testing the limit of labels |
195 | p = m.T(0) | 264 | -- can only throw labels between 1 and 255 |
196 | s = "abc" | 265 | local r = pcall(m.Rec, m.P"b", m.P"a", 0) |
197 | r, l, serror = p:match(s) | 266 | assert(r == false) |
198 | assert(r == nil and l == 0 and serror == "abc") | ||
199 | 267 | ||
200 | p = m.T(255) | 268 | local r = pcall(m.Rec, m.P"b", m.P"a", 256) |
201 | s = "abc" | 269 | assert(r == false) |
202 | r, l, serror = p:match(s) | ||
203 | assert(r == nil and l == 255 and serror == "abc") | ||
204 | 270 | ||
205 | local r = pcall(m.T, -1) | 271 | local r = pcall(m.Rec, m.P"b", m.P"a", -1) |
272 | assert(r == false) | ||
273 | |||
274 | local r = pcall(m.T, 0) | ||
206 | assert(r == false) | 275 | assert(r == false) |
207 | 276 | ||
208 | local r = pcall(m.T, 256) | 277 | local r = pcall(m.T, 256) |
209 | assert(r == false) | 278 | assert(r == false) |
210 | 279 | ||
280 | local r = pcall(m.T, -1) | ||
281 | assert(r == false) | ||
282 | |||
283 | |||
284 | local r = m.Rec(m.P"b", m.P"a", 255) | ||
285 | assert(p:match("a") == 2) | ||
286 | |||
287 | p = m.T(255) | ||
288 | s = "abc" | ||
289 | r, l, serror = p:match(s) | ||
290 | assert(r == nil and l == 255 and serror == "abc") | ||
291 | |||
292 | |||
211 | 293 | ||
212 | print("+") | 294 | print("+") |
213 | 295 | ||
214 | --[==[ TODO: labeled choice does not work anymore | ||
215 | --[[ grammar based on Figure 8 of paper submitted to SCP | 296 | --[[ grammar based on Figure 8 of paper submitted to SCP |
216 | S -> S0 /{1} ID /{2} ID '=' Exp /{3} 'unsigned'* 'int' ID /{4} 'unsigned'* ID ID / %error | 297 | S -> S0 //{1} ID //{2} ID '=' Exp //{3} 'unsigned'* 'int' ID //{4} 'unsigned'* ID ID / %error |
217 | S0 -> ID S1 / 'unsigned' S2 / 'int' %3 | 298 | S0 -> S1 / S2 / &'int' %3 |
218 | S1 -> '=' %2 / !. %1 / ID %4 | 299 | S1 -> &(ID '=') %2 / &(ID !.) %1 / &ID %4 |
219 | S2 -> 'unsigned' S2 / ID %4 / 'int' %3 | 300 | S2 -> &('unsigned'+ ID) %4 / & ('unsigned'+ 'int') %3 |
220 | ]] | 301 | ]] |
221 | |||
222 | local sp = m.S" \t\n"^0 | 302 | local sp = m.S" \t\n"^0 |
223 | local eq = sp * m.P"=" | 303 | local eq = sp * m.P"=" |
224 | 304 | ||
225 | g = m.P{ | 305 | g = m.P{ |
226 | "S", | 306 | "S", |
227 | S = m.Lc( | 307 | S = m.Rec( |
228 | m.Lc( | 308 | m.Rec( |
229 | m.Lc( | 309 | m.Rec( |
230 | m.Lc(m.V"S0", m.V"ID" * (m.P(1) + ""), 1), | 310 | m.Rec(m.V"S0", m.V"ID", 1), |
231 | m.V"ID" * eq * m.V"Exp", 2 | 311 | m.V"ID" * eq * m.V"Exp", 2 |
232 | ), | 312 | ), |
233 | m.V"U"^0 * m.V"I" * m.V"ID", 3 | 313 | m.V"U"^0 * m.V"I" * m.V"ID", 3 |
234 | ), | 314 | ), |
235 | m.V"U"^0 * m.V"ID" * m.V"ID", 4) | 315 | m.V"U"^0 * m.V"ID" * m.V"ID", 4) |
236 | + m.T(5), -- error | 316 | + m.T(5), -- error |
237 | S0 = m.V"ID" * m.V"S1" + m.V"U" * m.V"S2" + m.V"I" * m.T(3), | 317 | S0 = m.V"S1" + m.V"S2" + #m.V"I" * m.T(3), |
238 | S1 = eq * m.T(2) + sp * -m.P(1) * m.T(1) + m.V"ID" * m.T(4), | 318 | S1 = #(m.V"ID" * eq) * m.T(2) + sp * #(m.V"ID" * -m.P(1)) * m.T(1) + #m.V"ID" * m.T(4), |
239 | S2 = m.V"U" * m.V"S2" + m.V"ID" * m.T(4) + m.V"I" * m.T(3), | 319 | S2 = #(m.V"U"^1 * m.V"ID") * m.T(4) + #(m.V"U"^1 * m.V"I") * m.T(3), |
240 | ID = sp * m.P"a", | 320 | ID = sp * m.P"a", |
241 | U = sp * m.P"unsigned", | 321 | U = sp * m.P"unsigned", |
242 | I = sp * m.P"int", | 322 | I = sp * m.P"int", |
@@ -273,53 +353,59 @@ assert(r == nil and l == 5 and serror == s) | |||
273 | 353 | ||
274 | print("+") | 354 | print("+") |
275 | 355 | ||
276 | local re = require 'relabel' | ||
277 | 356 | ||
278 | g = re.compile[['a' /{4,9} [a-z] | 357 | local re = require 'relabelrec' |
358 | |||
359 | g = re.compile[['a' //{4,9} [a-z] | ||
279 | ]] | 360 | ]] |
280 | assert(g:match("a") == 2) | 361 | assert(g:match("a") == 2) |
281 | r, l, serror = g:match("b") | 362 | r, l, serror = g:match("b") |
282 | assert(r == nil and l == 0 and serror == "b") | 363 | assert(r == nil and l == 0 and serror == "b") |
283 | 364 | ||
284 | g = re.compile[['a' /{4,9} [a-f] /{5, 7} [a-z] | 365 | g = re.compile[['a' //{4,9} [a-f] //{5, 7} [a-z] |
285 | ]] | 366 | ]] |
286 | assert(g:match("a") == 2) | 367 | assert(g:match("a") == 2) |
287 | r, l, serror = g:match("b") | 368 | r, l, serror = g:match("b") |
288 | assert(r == nil and l == 0 and serror == "b") | 369 | assert(r == nil and l == 0 and serror == "b") |
289 | 370 | ||
290 | g = re.compile[[%{1} /{4,9} [a-z] | 371 | g = re.compile[[%{1} //{4,9} [a-z] |
291 | ]] | 372 | ]] |
292 | r, l, serror = g:match("a") | 373 | r, l, serror = g:match("a") |
293 | assert(r == nil and l == 1 and serror == "a") | 374 | assert(r == nil and l == 1 and serror == "a") |
294 | 375 | ||
295 | 376 | ||
296 | g = re.compile[[%{1} /{4,1} [a-f] | 377 | g = re.compile[[%{1} //{4,1} [a-f] |
297 | ]] | 378 | ]] |
298 | assert(g:match("a") == 2) | 379 | assert(g:match("a") == 2) |
299 | r, l, serror = g:match("h") | 380 | r, l, serror = g:match("h") |
300 | assert(r == nil and l == 0 and serror == "h") | 381 | assert(r == nil and l == 0 and serror == "h") |
301 | 382 | ||
302 | g = re.compile[[[a-f]%{9} /{4,9} [a-c]%{7} /{5, 7} [a-z] ]] | 383 | g = re.compile[[[a-f]%{9} //{4,9} [a-c]%{7} //{5, 7} [a-z] ]] |
303 | assert(g:match("a") == 2) | 384 | r, l, serror = g:match("a") |
304 | assert(g:match("c") == 2) | 385 | assert(r == nil and l == 0 and serror == "") |
305 | r, l, serror = g:match("d") | 386 | r, l, serror = g:match("aa") |
387 | assert(r == nil and l == 0 and serror == "") | ||
388 | assert(g:match("aaa") == 4) | ||
389 | |||
390 | r, l, serror = g:match("ad") | ||
306 | assert(r == nil and l == 0 and serror == "d") | 391 | assert(r == nil and l == 0 and serror == "d") |
392 | |||
307 | r, l, serror = g:match("g") | 393 | r, l, serror = g:match("g") |
308 | assert(r == nil and l == 0 and serror == "g") | 394 | assert(r == nil and l == 0 and serror == "g") |
309 | 395 | ||
396 | |||
310 | --[[ grammar based on Figure 8 of paper submitted to SCP | 397 | --[[ grammar based on Figure 8 of paper submitted to SCP |
311 | S -> S0 /{1} ID /{2} ID '=' Exp /{3} 'unsigned'* 'int' ID /{4} 'unsigned'* ID ID / %error | 398 | S -> S0 //{1} ID //{2} ID '=' Exp //{3} 'unsigned'* 'int' ID //{4} 'unsigned'* ID ID / %error |
312 | S0 -> ID S1 / 'unsigned' S2 / 'int' %3 | 399 | S0 -> S1 / S2 / &'int' %3 |
313 | S1 -> '=' %2 / !. %1 / ID %4 | 400 | S1 -> &(ID '=') %2 / &(ID !.) %1 / &ID %4 |
314 | S2 -> 'unsigned' S2 / ID %4 / 'int' %3 | 401 | S2 -> &('unsigned'+ ID) %4 / & ('unsigned'+ 'int') %3 |
315 | ]] | 402 | ]] |
316 | 403 | ||
317 | |||
318 | g = re.compile([[ | 404 | g = re.compile([[ |
319 | S <- S0 /{1} ID /{2} ID %s* '=' Exp /{3} U* Int ID /{4} U ID ID /{0} %{5} | 405 | S <- S0 //{1} ID //{2} ID %s* '=' Exp //{3} U* Int ID //{4} U ID ID / %{5} |
320 | S0 <- ID S1 / U S2 / Int %{3} | 406 | S0 <- S1 / S2 / &Int %{3} |
321 | S1 <- %s* '=' %{2} / !. %{1} / ID %{4} | 407 | S1 <- &(ID %s* '=') %{2} / &(ID !.) %{1} / &ID %{4} |
322 | S2 <- U S2 / ID %{4} / Int %{3} | 408 | S2 <- &(U+ ID) %{4} / &(U+ Int) %{3} |
323 | ID <- %s* 'a' | 409 | ID <- %s* 'a' |
324 | U <- %s* 'unsigned' | 410 | U <- %s* 'unsigned' |
325 | Int <- %s* 'int' | 411 | Int <- %s* 'int' |
@@ -349,6 +435,8 @@ s = "unsigned int" | |||
349 | r, l, serror = g:match(s) | 435 | r, l, serror = g:match(s) |
350 | assert(r == nil and l == 5 and serror == s) | 436 | assert(r == nil and l == 5 and serror == s) |
351 | 437 | ||
438 | |||
439 | |||
352 | local terror = { ['cmdSeq'] = "Missing ';' in CmdSeq", | 440 | local terror = { ['cmdSeq'] = "Missing ';' in CmdSeq", |
353 | ['ifExp'] = "Error in expresion of 'if'", | 441 | ['ifExp'] = "Error in expresion of 'if'", |
354 | ['ifThen'] = "Error matching 'then' keyword", | 442 | ['ifThen'] = "Error matching 'then' keyword", |
@@ -370,12 +458,12 @@ local terror = { ['cmdSeq'] = "Missing ';' in CmdSeq", | |||
370 | ['undefined'] = "Undefined Error"} | 458 | ['undefined'] = "Undefined Error"} |
371 | 459 | ||
372 | g = re.compile([[ | 460 | g = re.compile([[ |
373 | Tiny <- CmdSeq /{1} '' -> cmdSeq /{2} '' -> ifExp /{3} '' -> ifThen /{4} '' -> ifThenCmdSeq | 461 | Tiny <- CmdSeq //{1} '' -> cmdSeq //{2} '' -> ifExp //{3} '' -> ifThen //{4} '' -> ifThenCmdSeq |
374 | /{5} '' -> ifElseCmdSeq /{6} '' -> ifEnd /{7} '' -> repeatCmdSeq | 462 | //{5} '' -> ifElseCmdSeq //{6} '' -> ifEnd //{7} '' -> repeatCmdSeq |
375 | /{8} '' -> repeatUntil /{9} '' -> repeatExp /{10} '' -> assignOp | 463 | //{8} '' -> repeatUntil //{9} '' -> repeatExp //{10} '' -> assignOp |
376 | /{11} '' -> assignExp /{12} '' -> readName /{13} '' -> writeExp | 464 | //{11} '' -> assignExp //{12} '' -> readName //{13} '' -> writeExp |
377 | /{14} '' -> simpleExp /{15} '' -> term /{16} '' -> factor | 465 | //{14} '' -> simpleExp //{15} '' -> term //{16} '' -> factor |
378 | /{17} '' -> openParExp /{18} '' -> closePar /{0} '' -> undefined | 466 | //{17} '' -> openParExp //{18} '' -> closePar / '' -> undefined |
379 | CmdSeq <- (Cmd (SEMICOLON / %{1})) (Cmd (SEMICOLON / %{1}))* | 467 | CmdSeq <- (Cmd (SEMICOLON / %{1})) (Cmd (SEMICOLON / %{1}))* |
380 | Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd | 468 | Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd |
381 | IfCmd <- IF (Exp / %{2}) (THEN / %{3}) (CmdSeq / %{4}) (ELSE (CmdSeq / %{5}) / '') (END / %{6}) | 469 | IfCmd <- IF (Exp / %{2}) (THEN / %{3}) (CmdSeq / %{4}) (ELSE (CmdSeq / %{5}) / '') (END / %{6}) |
@@ -551,21 +639,14 @@ assert(g:match(s) == terror['undefined']) | |||
551 | 639 | ||
552 | 640 | ||
553 | print("+") | 641 | print("+") |
554 | ]==] | ||
555 | 642 | ||
556 | -- test recovery operator | ||
557 | p = m.Rec("a", "b") | ||
558 | assert(p:match("a") == 2) | ||
559 | --assert(p:match("b") == 2) | ||
560 | checkeqlab({nil, 0, "b"}, p:match("b")) | ||
561 | checkeqlab({nil, 0, "c"}, p:match("c")) | ||
562 | 643 | ||
563 | p = m.Rec("a", "b", 3) | 644 | p = m.Rec("a", "b", 3) |
564 | assert(p:match("a") == 2) | 645 | assert(p:match("a") == 2) |
565 | checkeqlab({nil, 0, "b"}, p:match("b")) | 646 | checkeqlab({nil, 0, "b"}, p:match("b")) |
566 | checkeqlab({nil, 0, "c"}, p:match("c")) | 647 | checkeqlab({nil, 0, "c"}, p:match("c")) |
567 | 648 | ||
568 | p = m.Rec(m.T(3), "b") | 649 | p = m.Rec(m.T(3), "b", 1) |
569 | checkeqlab({nil, 3, "a"}, p:match("a")) | 650 | checkeqlab({nil, 3, "a"}, p:match("a")) |
570 | checkeqlab({nil, 3, "b"}, p:match("b")) | 651 | checkeqlab({nil, 3, "b"}, p:match("b")) |
571 | 652 | ||
@@ -574,56 +655,26 @@ checkeqlab({nil, 0, "a"}, p:match("a")) | |||
574 | assert(p:match("b") == 2) | 655 | assert(p:match("b") == 2) |
575 | 656 | ||
576 | --[[ | 657 | --[[ |
577 | S -> (A //{fail} (!c .)*) C | 658 | S -> (A //{128} (!c .)*) C |
578 | A -> a*b | 659 | A -> a*b / %128 |
579 | C -> c+ | ||
580 | ]] | ||
581 | g = m.P{ | ||
582 | "S", | ||
583 | S = m.Rec(m.V"A", (-m.P"c" * m.P(1))^0) * m.V"C", | ||
584 | A = m.P"a"^0 * "b", | ||
585 | C = m.P"c"^1, | ||
586 | } | ||
587 | |||
588 | assert(g:match("abc") == 4) | ||
589 | assert(g:match("aabc") == 5) | ||
590 | --assert(g:match("aadc") == 5) --old semantics | ||
591 | checkeqlab({nil, 0, "dc"}, g:match("aadc")) --new semantics | ||
592 | assert(g:match("bc") == 3) -- new semantics | ||
593 | checkeqlab({nil, 0, "bc"}, g:match("bbc")) | ||
594 | --assert(g:match("xxc") == 4) old semantics | ||
595 | checkeqlab({nil, 0, "xxc"}, g:match("xxc")) --new semantics | ||
596 | --assert(g:match("c") == 2) --old semantics | ||
597 | checkeqlab({nil, 0, "c"}, g:match("c")) --new semantics | ||
598 | --checkeqlab({nil, 0, ""}, g:match("fail")) --old semantics | ||
599 | checkeqlab({nil, 0, "fail"}, g:match("fail")) --new semantics | ||
600 | --checkeqlab({nil, 0, ""}, g:match("aaxx")) --old semantics | ||
601 | checkeqlab({nil, 0, "xx"}, g:match("aaxx")) --new semantics | ||
602 | |||
603 | |||
604 | --[[ | ||
605 | S -> (A //{0} (!c .)*) C | ||
606 | A -> a*b / ^{0} | ||
607 | C -> c+ | 660 | C -> c+ |
608 | ]] | 661 | ]] |
609 | g = m.P{ | 662 | g = m.P{ |
610 | "S", | 663 | "S", |
611 | S = m.Rec(m.V"A", (-m.P"c" * m.P(1))^0, 0) * m.V"C", --explicitly put 0 in Rec | 664 | S = m.Rec(m.V"A", (-m.P"c" * m.P(1))^0, 128) * m.V"C", |
612 | A = m.P"a"^0 * m.P"b" + m.T(0), | 665 | A = m.P"a"^0 * "b" + m.T(128), |
613 | C = m.P"c"^1, | 666 | C = m.P"c"^1, |
614 | } | 667 | } |
615 | 668 | ||
616 | assert(g:match("abc") == 4) | 669 | assert(g:match("abc") == 4) |
617 | assert(g:match("aabc") == 5) | 670 | assert(g:match("aabc") == 5) |
618 | assert(g:match("aadc") == 5) --updated | 671 | assert(g:match("aadc") == 5) |
619 | assert(g:match("bc") == 3) -- new semantics | 672 | assert(g:match("dc") == 3) |
620 | checkeqlab({nil, 0, "bc"}, g:match("bbc")) | 673 | checkeqlab({nil, 0, "bc"}, g:match("bbc")) |
621 | assert(g:match("xxc") == 4) | 674 | assert(g:match("xxc") == 4) |
622 | assert(g:match("c") == 2) --old semantics updated | 675 | assert(g:match("c") == 2) |
623 | checkeqlab({nil, 0, ""}, g:match("fail")) --old semantics updated | 676 | checkeqlab({nil, 0, ""}, g:match("fail")) |
624 | checkeqlab({nil, 0, ""}, g:match("aaxx")) --old semantics updated | 677 | checkeqlab({nil, 0, ""}, g:match("aaxx")) |
625 | |||
626 | |||
627 | 678 | ||
628 | 679 | ||
629 | --[[ | 680 | --[[ |
@@ -810,6 +861,120 @@ checkeqlab({nil, 4, "dc"}, g3:match("dc")) | |||
810 | checkeqlab({nil, 4, "d"}, g3:match(".d")) | 861 | checkeqlab({nil, 4, "d"}, g3:match(".d")) |
811 | 862 | ||
812 | 863 | ||
864 | -- testing more captures | ||
865 | local g = re.compile[[ | ||
866 | S <- ( %s* &. {A} )* | ||
867 | A <- [0-9]+ / %{5} | ||
868 | ]] | ||
813 | 869 | ||
814 | print("OK") | 870 | checkeq({"523", "624", "346", "888"} , {g:match("523 624 346\n888")}) |
871 | checkeq({nil, 5, "a 123"}, {g:match("44 a 123")}) | ||
872 | |||
873 | local g2 = m.Rec(g, ((-m.R("09") * m.P(1))^0) / "58", 5) | ||
874 | |||
875 | checkeq({"523", "624", "346", "888"} , {g2:match("523 624 346\n888")}) | ||
876 | checkeq({"44", "a ", "58", "123"}, {g2:match("44 a 123")}) | ||
877 | |||
878 | |||
879 | local g = re.compile[[ | ||
880 | S <- ( %s* &. A )* | ||
881 | A <- {[0-9]+} / %{5} | ||
882 | ]] | ||
883 | |||
884 | checkeq({"523", "624", "346", "888"} , {g:match("523 624 346\n888")}) | ||
885 | checkeq({nil, 5, "a 123"}, {g:match("44 a 123")}) | ||
886 | |||
887 | local g2 = m.Rec(g, ((-m.R("09") * m.P(1))^0) / "58", 5) | ||
888 | |||
889 | checkeq({"523", "624", "346", "888"} , {g2:match("523 624 346\n888")}) | ||
890 | checkeq({"44", "58", "123"}, {g2:match("44 a 123")}) | ||
891 | |||
892 | |||
893 | local R, S, P, V = lpeg.R, lpeg.S, lpeg.P, lpeg.V | ||
894 | local C, Cc, Ct, Cmt = lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cmt | ||
895 | local T, Lc, Rec = lpeg.T, lpeg.Lc, lpeg.Rec | ||
896 | |||
897 | local labels = { | ||
898 | {"NoExp", "no expression found"}, | ||
899 | {"Extra", "extra characters found after the expression"}, | ||
900 | {"ExpTerm", "expected a term after the operator"}, | ||
901 | {"ExpExp", "expected an expression after the parenthesis"}, | ||
902 | {"MisClose", "missing a closing ')' after the expression"}, | ||
903 | } | ||
904 | |||
905 | local function labelindex(labname) | ||
906 | for i, elem in ipairs(labels) do | ||
907 | if elem[1] == labname then | ||
908 | return i | ||
909 | end | ||
910 | end | ||
911 | error("could not find label: " .. labname) | ||
912 | end | ||
913 | |||
914 | local errors = {} | ||
915 | |||
916 | local function expect(patt, labname, recpatt) | ||
917 | local i = labelindex(labname) | ||
918 | function recorderror(input, pos) | ||
919 | table.insert(errors, {i, pos}) | ||
920 | return true | ||
921 | end | ||
922 | if not recpatt then recpatt = P"" end | ||
923 | --return Rec(patt, Cmt("", recorderror) * recpatt) | ||
924 | return patt + T(i) | ||
925 | end | ||
926 | |||
927 | local num = R("09")^1 / tonumber | ||
928 | local op = S("+-*/") | ||
929 | |||
930 | local function compute(tokens) | ||
931 | local result = tokens[1] | ||
932 | for i = 2, #tokens, 2 do | ||
933 | if tokens[i] == '+' then | ||
934 | result = result + tokens[i+1] | ||
935 | elseif tokens[i] == '-' then | ||
936 | result = result - tokens[i+1] | ||
937 | elseif tokens[i] == '*' then | ||
938 | result = result * tokens[i+1] | ||
939 | elseif tokens[i] == '/' then | ||
940 | result = result / tokens[i+1] | ||
941 | else | ||
942 | error('unknown operation: ' .. tokens[i]) | ||
943 | end | ||
944 | end | ||
945 | return result | ||
946 | end | ||
815 | 947 | ||
948 | |||
949 | local g = P { | ||
950 | "Exp", | ||
951 | Exp = Ct(V"Term" * (C(op) * V"Operand")^0) / compute, | ||
952 | Operand = expect(V"Term", "ExpTerm"), | ||
953 | Term = num, | ||
954 | } | ||
955 | local rg = Rec(g, Cc(3), labelindex("ExpTerm")) | ||
956 | |||
957 | local function eval(input) | ||
958 | local result, label, suffix = rg:match(input) | ||
959 | if #errors == 0 then | ||
960 | return result | ||
961 | else | ||
962 | local out = {} | ||
963 | for i, err in ipairs(errors) do | ||
964 | local pos = err[2] | ||
965 | local msg = labels[err[1]][2] | ||
966 | table.insert(out, "syntax error: " .. msg .. " (at index " .. pos .. ")") | ||
967 | end | ||
968 | errors = {} | ||
969 | return nil, table.concat(out, "\n") | ||
970 | end | ||
971 | end | ||
972 | |||
973 | assert(eval("98-76*54/32") == 37.125) | ||
974 | --> 37.125 | ||
975 | |||
976 | assert(eval("1+") == 4) | ||
977 | --> syntax error: expected a term after the operator (at index 3) | ||
978 | |||
979 | |||
980 | print("OK") | ||