diff options
| -rw-r--r-- | relabel.lua | 12 | ||||
| -rw-r--r-- | testlabel.lua | 213 |
2 files changed, 223 insertions, 2 deletions
diff --git a/relabel.lua b/relabel.lua index 87269be..642b0fe 100644 --- a/relabel.lua +++ b/relabel.lua | |||
| @@ -241,6 +241,13 @@ local function choicerec (...) | |||
| 241 | return p | 241 | return p |
| 242 | end | 242 | end |
| 243 | 243 | ||
| 244 | local function getlab (f) | ||
| 245 | if not tlabels[f] then | ||
| 246 | error("undefined label: " .. f) | ||
| 247 | end | ||
| 248 | return mm.T(tlabels[f]) | ||
| 249 | end | ||
| 250 | |||
| 244 | local exp = m.P{ "Exp", | 251 | local exp = m.P{ "Exp", |
| 245 | Exp = S * ( m.V"Grammar" | 252 | Exp = S * ( m.V"Grammar" |
| 246 | + (m.V"Seq" * (S * ((m.C(m.P"//" + "/") * m.Ct(m.V"Labels")) + (m.C"/" * m.Cc(false))) | 253 | + (m.V"Seq" * (S * ((m.C(m.P"//" + "/") * m.Ct(m.V"Labels")) + (m.C"/" * m.Cc(false))) |
| @@ -260,6 +267,7 @@ local exp = m.P{ "Exp", | |||
| 260 | + m.P"?" * m.Cc(-1, mt.__pow) | 267 | + m.P"?" * m.Cc(-1, mt.__pow) |
| 261 | + "^" * expect( m.Cg(num * m.Cc(mult)) | 268 | + "^" * expect( m.Cg(num * m.Cc(mult)) |
| 262 | + m.Cg(m.C(m.S"+-" * m.R"09"^1) * m.Cc(mt.__pow) | 269 | + m.Cg(m.C(m.S"+-" * m.R"09"^1) * m.Cc(mt.__pow) |
| 270 | + name * m.Cc"lab" | ||
| 263 | ), | 271 | ), |
| 264 | "ExpNum") | 272 | "ExpNum") |
| 265 | + "->" * expect(S * ( m.Cg((String + num) * m.Cc(mt.__div)) | 273 | + "->" * expect(S * ( m.Cg((String + num) * m.Cc(mt.__div)) |
| @@ -270,7 +278,7 @@ local exp = m.P{ "Exp", | |||
| 270 | + "=>" * expect(S * m.Cg(Def / getdef * m.Cc(m.Cmt)), | 278 | + "=>" * expect(S * m.Cg(Def / getdef * m.Cc(m.Cmt)), |
| 271 | "ExpName1") | 279 | "ExpName1") |
| 272 | ) | 280 | ) |
| 273 | )^0, function (a,b,f) return f(a,b) end ); | 281 | )^0, function (a,b,f) if f == "lab" then return a + getlab(b) else return f(a,b) end end ); |
| 274 | Primary = "(" * expect(m.V"Exp", "ExpPatt4") * expect(S * ")", "MisClose1") | 282 | Primary = "(" * expect(m.V"Exp", "ExpPatt4") * expect(S * ")", "MisClose1") |
| 275 | + String / mm.P | 283 | + String / mm.P |
| 276 | + Class | 284 | + Class |
| @@ -293,7 +301,7 @@ local exp = m.P{ "Exp", | |||
| 293 | + m.P"." * m.Cc(any) | 301 | + m.P"." * m.Cc(any) |
| 294 | + (name * -arrow + "<" * expect(name, "ExpName3") | 302 | + (name * -arrow + "<" * expect(name, "ExpName3") |
| 295 | * expect(">", "MisClose6")) * m.Cb("G") / NT; | 303 | * expect(">", "MisClose6")) * m.Cb("G") / NT; |
| 296 | Label = num + name / function (f) return tlabels[f] end; | 304 | Label = num + name / function (f) return getlab(f) end; |
| 297 | Definition = name * arrow * expect(m.V"Exp", "ExpPatt8"); | 305 | Definition = name * arrow * expect(m.V"Exp", "ExpPatt8"); |
| 298 | Grammar = m.Cg(m.Cc(true), "G") | 306 | Grammar = m.Cg(m.Cc(true), "G") |
| 299 | * m.Cf(m.V"Definition" / firstdef * (S * m.Cg(m.V"Definition"))^0, | 307 | * m.Cf(m.V"Definition" / firstdef * (S * m.Cg(m.V"Definition"))^0, |
diff --git a/testlabel.lua b/testlabel.lua index 2d9233a..d3d95b1 100644 --- a/testlabel.lua +++ b/testlabel.lua | |||
| @@ -1267,4 +1267,217 @@ assert(eval("1+") == 4) | |||
| 1267 | --> syntax error: expected a term after the operator (at index 3) | 1267 | --> syntax error: expected a term after the operator (at index 3) |
| 1268 | 1268 | ||
| 1269 | 1269 | ||
| 1270 | -- tests related to the use of '^' in relabel to throw labels | ||
| 1271 | local errinfo = { | ||
| 1272 | { 'cmdSeq', "Missing ';' in CmdSeq"}, | ||
| 1273 | { 'ifExp', "Error in expresion of 'if'"}, | ||
| 1274 | { 'ifThen', "Error matching 'then' keyword"}, | ||
| 1275 | { 'ifThenCmdSeq', "Error matching CmdSeq of 'then' branch"}, | ||
| 1276 | { 'ifElseCmdSeq', "Error matching CmdSeq of 'else' branch"}, | ||
| 1277 | { 'ifEnd', "Error matching 'end' keyword of 'if'"}, | ||
| 1278 | { 'repeatCmdSeq', "Error matching CmdSeq of 'repeat'"}, | ||
| 1279 | { 'repeatUntil', "Error matching 'until' keyword"}, | ||
| 1280 | { 'repeatExp', "Error matching expression of 'until'"}, | ||
| 1281 | { 'assignOp', "Error matching ':='"}, | ||
| 1282 | { 'assignExp', "Error matching expression of assignment"}, | ||
| 1283 | { 'readName', "Error matching 'NAME' after 'read'"}, | ||
| 1284 | { 'writeExp', "Error matching expression after 'write'"}, | ||
| 1285 | { 'simpleExp', "Error matching 'SimpleExp'"}, | ||
| 1286 | { 'term', "Error matching 'Term'"}, | ||
| 1287 | { 'factor', "Error matching 'Factor'"}, | ||
| 1288 | { 'openParExp', "Error matching expression after '('"}, | ||
| 1289 | { 'closePar', "Error matching ')'"}, | ||
| 1290 | { 'undefined', "Undefined Error" } | ||
| 1291 | } | ||
| 1292 | |||
| 1293 | |||
| 1294 | local errmsgs = {} | ||
| 1295 | local labels = {} | ||
| 1296 | |||
| 1297 | for i, err in ipairs(errinfo) do | ||
| 1298 | errmsgs[i] = err[2] | ||
| 1299 | labels[err[1]] = i | ||
| 1300 | end | ||
| 1301 | |||
| 1302 | re.setlabels(labels) | ||
| 1303 | |||
| 1304 | g = re.compile([[ | ||
| 1305 | Tiny <- CmdSeq | ||
| 1306 | CmdSeq <- (Cmd SEMICOLON^cmdSeq) (Cmd SEMICOLON^cmdSeq)* | ||
| 1307 | Cmd <- IfCmd / RepeatCmd / ReadCmd / WriteCmd / AssignCmd | ||
| 1308 | IfCmd <- IF Exp^ifExp THEN^ifThen CmdSeq^ifThenCmdSeq (ELSE CmdSeq^ifElseCmdSeq / '') END^ifEnd | ||
| 1309 | RepeatCmd <- REPEAT CmdSeq^repeatCmdSeq UNTIL^repeatUntil Exp^repeatExp | ||
| 1310 | AssignCmd <- NAME ASSIGNMENT^assignOp Exp^assignExp | ||
| 1311 | ReadCmd <- READ NAME^readName | ||
| 1312 | WriteCmd <- WRITE Exp^writeExp | ||
| 1313 | Exp <- SimpleExp ((LESS / EQUAL) SimpleExp^simpleExp / '') | ||
| 1314 | SimpleExp <- Term ((ADD / SUB) Term^term)* | ||
| 1315 | Term <- Factor ((MUL / DIV) Factor^factor)* | ||
| 1316 | Factor <- OPENPAR Exp^openParExp CLOSEPAR^closePar / NUMBER / NAME | ||
| 1317 | ADD <- Sp '+' | ||
| 1318 | ASSIGNMENT <- Sp ':=' | ||
| 1319 | CLOSEPAR <- Sp ')' | ||
| 1320 | DIV <- Sp '/' | ||
| 1321 | IF <- Sp 'if' | ||
| 1322 | ELSE <- Sp 'else' | ||
| 1323 | END <- Sp 'end' | ||
| 1324 | EQUAL <- Sp '=' | ||
| 1325 | LESS <- Sp '<' | ||
| 1326 | MUL <- Sp '*' | ||
| 1327 | NAME <- !RESERVED Sp [a-z]+ | ||
| 1328 | NUMBER <- Sp [0-9]+ | ||
| 1329 | OPENPAR <- Sp '(' | ||
| 1330 | READ <- Sp 'read' | ||
| 1331 | REPEAT <- Sp 'repeat' | ||
| 1332 | SEMICOLON <- Sp ';' | ||
| 1333 | SUB <- Sp '-' | ||
| 1334 | THEN <- Sp 'then' | ||
| 1335 | UNTIL <- Sp 'until' | ||
| 1336 | WRITE <- Sp 'write' | ||
| 1337 | RESERVED <- (IF / ELSE / END / READ / REPEAT / THEN / UNTIL / WRITE) ![a-z]+ | ||
| 1338 | Sp <- (%s / %nl)* | ||
| 1339 | ]], terror) | ||
| 1340 | |||
| 1341 | s = [[ | ||
| 1342 | n := 5;]] | ||
| 1343 | assert(g:match(s) == #s + 1) | ||
| 1344 | |||
| 1345 | s = [[ | ||
| 1346 | n := 5; | ||
| 1347 | f := 1; | ||
| 1348 | repeat | ||
| 1349 | f := f * n; | ||
| 1350 | n := n - 1; | ||
| 1351 | until (n < 1); | ||
| 1352 | write f;]] | ||
| 1353 | assert(g:match(s) == #s + 1) | ||
| 1354 | |||
| 1355 | -- a ';' is missing in 'read a' | ||
| 1356 | s = [[ | ||
| 1357 | read a]] | ||
| 1358 | assert(table.pack(g:match(s))[2] == labels['cmdSeq']) | ||
| 1359 | |||
| 1360 | |||
| 1361 | -- a ';' is missing in 'n := n - 1' | ||
| 1362 | s = [[ | ||
| 1363 | n := 5; | ||
| 1364 | f := 1; | ||
| 1365 | repeat | ||
| 1366 | f := f * n; | ||
| 1367 | n := n - 1 | ||
| 1368 | until (n < 1); | ||
| 1369 | write f;]] | ||
| 1370 | assert(table.pack(g:match(s))[2] == labels['cmdSeq']) | ||
| 1371 | |||
| 1372 | |||
| 1373 | -- IF expression | ||
| 1374 | s = [[ | ||
| 1375 | if a then a := a + 1; end;]] | ||
| 1376 | assert(g:match(s) == #s + 1) | ||
| 1377 | |||
| 1378 | -- IF expression | ||
| 1379 | s = [[ | ||
| 1380 | if a then a := a + 1; else write 2; end;]] | ||
| 1381 | assert(g:match(s) == #s + 1) | ||
| 1382 | |||
| 1383 | -- Error in expression of 'if'. 'A' is not a valida name | ||
| 1384 | s = [[ | ||
| 1385 | if A then a := a + 1; else write 2; end;]] | ||
| 1386 | assert(table.pack(g:match(s))[2] == labels['ifExp']) | ||
| 1387 | |||
| 1388 | -- Error matching the 'then' keyword | ||
| 1389 | s = [[ | ||
| 1390 | if a a := a + 1; else write 2; end;]] | ||
| 1391 | assert(table.pack(g:match(s))[2] == labels['ifThen']) | ||
| 1392 | |||
| 1393 | -- Error matching the CmdSeq inside of 'then' branch | ||
| 1394 | s = [[ | ||
| 1395 | if a then 3 := 2; else write 2; end;]] | ||
| 1396 | assert(table.pack(g:match(s))[2] == labels['ifThenCmdSeq']) | ||
| 1397 | |||
| 1398 | -- Error matching the CmdSeq inside of 'else' branch | ||
| 1399 | s = [[ | ||
| 1400 | if a then b := 2; else A := 2; end;]] | ||
| 1401 | assert(table.pack(g:match(s))[2] == labels['ifElseCmdSeq']) | ||
| 1402 | |||
| 1403 | -- Error matching 'end' of 'if' | ||
| 1404 | s = [[ | ||
| 1405 | if a then b := 2; else a := 2; 77;]] | ||
| 1406 | assert(table.pack(g:match(s))[2] == labels['ifEnd']) | ||
| 1407 | |||
| 1408 | -- Error matching the CmdSeq of 'repeat' | ||
| 1409 | s = [[repeat | ||
| 1410 | F := f * n; | ||
| 1411 | n := n - 1; | ||
| 1412 | until (n < 1);]] | ||
| 1413 | assert(table.pack(g:match(s))[2] == labels['repeatCmdSeq']) | ||
| 1414 | |||
| 1415 | -- Error matching 'until' | ||
| 1416 | s = [[repeat | ||
| 1417 | f := f * n; | ||
| 1418 | n := n - 1; | ||
| 1419 | 88 (n < 1);]] | ||
| 1420 | assert(table.pack(g:match(s))[2] == labels['repeatUntil']) | ||
| 1421 | |||
| 1422 | -- Error matching expression of 'until' | ||
| 1423 | s = [[repeat | ||
| 1424 | f := f * n; | ||
| 1425 | n := n - 1; | ||
| 1426 | until ; (n < 1);]] | ||
| 1427 | assert(table.pack(g:match(s))[2] == labels['repeatExp']) | ||
| 1428 | |||
| 1429 | -- Error matching ':=' | ||
| 1430 | s = [[ | ||
| 1431 | f = f * n;]] | ||
| 1432 | assert(table.pack(g:match(s))[2] == labels['assignOp']) | ||
| 1433 | |||
| 1434 | -- Error matching expression of assignment | ||
| 1435 | s = [[ | ||
| 1436 | f := A * n;]] | ||
| 1437 | assert(table.pack(g:match(s))[2] == labels['assignExp']) | ||
| 1438 | |||
| 1439 | -- Error matching 'name' | ||
| 1440 | s = [[ | ||
| 1441 | read 2;]] | ||
| 1442 | assert(table.pack(g:match(s))[2] == labels['readName']) | ||
| 1443 | |||
| 1444 | -- Error matching expression after 'write' | ||
| 1445 | s = [[ | ||
| 1446 | write [a] := 2;]] | ||
| 1447 | assert(table.pack(g:match(s))[2] == labels['writeExp']) | ||
| 1448 | |||
| 1449 | -- Error matching 'SimpleExp' | ||
| 1450 | s = [[ | ||
| 1451 | a := a < A;]] | ||
| 1452 | assert(table.pack(g:match(s))[2] == labels['simpleExp']) | ||
| 1453 | |||
| 1454 | -- Error matching 'Term' | ||
| 1455 | s = [[ | ||
| 1456 | a := a + A;]] | ||
| 1457 | assert(table.pack(g:match(s))[2] == labels['term']) | ||
| 1458 | |||
| 1459 | -- Error matching 'Factor' | ||
| 1460 | s = [[ | ||
| 1461 | a := a * A;]] | ||
| 1462 | assert(table.pack(g:match(s))[2] == labels['factor']) | ||
| 1463 | |||
| 1464 | -- Error matching expression after '(' | ||
| 1465 | s = [[ | ||
| 1466 | a := (A);]] | ||
| 1467 | assert(table.pack(g:match(s))[2] == labels['openParExp']) | ||
| 1468 | |||
| 1469 | -- Error matching ')' | ||
| 1470 | s = [[ | ||
| 1471 | a := (a];]] | ||
| 1472 | assert(table.pack(g:match(s))[2] == labels['closePar']) | ||
| 1473 | |||
| 1474 | -- Error undefined | ||
| 1475 | s = [[ | ||
| 1476 | A := a;]] | ||
| 1477 | assert(table.pack(g:match(s))[2] == 0) | ||
| 1478 | |||
| 1479 | |||
| 1480 | |||
| 1481 | |||
| 1482 | |||
| 1270 | print("OK") | 1483 | print("OK") |
