diff options
| author | Sérgio Medeiros <sqmedeiros@gmail.com> | 2016-08-19 08:59:42 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-08-19 08:59:42 -0300 |
| commit | fcb4f1bf2172186cef1fa3fb57be5cd03aaba713 (patch) | |
| tree | 917926c063a8e713fcbfa138f53c722929131576 | |
| parent | 28a44f01cb7a75068b75a99c0badb3abdaf7047a (diff) | |
| parent | ef26e7c4b777ebe9c9c3844bcc818de811369fff (diff) | |
| download | lpeglabel-fcb4f1bf2172186cef1fa3fb57be5cd03aaba713.tar.gz lpeglabel-fcb4f1bf2172186cef1fa3fb57be5cd03aaba713.tar.bz2 lpeglabel-fcb4f1bf2172186cef1fa3fb57be5cd03aaba713.zip | |
Merge pull request #11 from undecidabot/master
Removing error recovery (moving it out to a different branch)
| -rw-r--r-- | relabel.lua | 91 | ||||
| -rw-r--r-- | testrelabelparser.lua | 174 |
2 files changed, 28 insertions, 237 deletions
diff --git a/relabel.lua b/relabel.lua index ff2e486..7fe8645 100644 --- a/relabel.lua +++ b/relabel.lua | |||
| @@ -82,15 +82,9 @@ for i, err in ipairs(errinfo) do | |||
| 82 | labels[err[1]] = i | 82 | labels[err[1]] = i |
| 83 | end | 83 | end |
| 84 | 84 | ||
| 85 | local syntaxerrs = {} | ||
| 86 | |||
| 87 | local function expect (pattern, labelname) | 85 | local function expect (pattern, labelname) |
| 88 | local label = labels[labelname] | 86 | local label = labels[labelname] |
| 89 | local record = function (input, pos) | 87 | return pattern + m.T(label) |
| 90 | tinsert(syntaxerrs, { label = label, pos = pos }) | ||
| 91 | return true | ||
| 92 | end | ||
| 93 | return pattern + m.Cmt("", record) * m.T(label) | ||
| 94 | end | 88 | end |
| 95 | 89 | ||
| 96 | 90 | ||
| @@ -236,72 +230,20 @@ local function labchoice (...) | |||
| 236 | return p | 230 | return p |
| 237 | end | 231 | end |
| 238 | 232 | ||
| 239 | -- error recovery | ||
| 240 | local skip = m.P { "Skip", | ||
| 241 | Skip = (-m.P"/" * -m.P(name * arrow) * m.V"Ignored")^0 * m.Cc(dummy); | ||
| 242 | Ignored = m.V"Group" + any; | ||
| 243 | Group = "(" * (-m.P")" * m.V"Ignored")^0 * ")" | ||
| 244 | + "{" * (-m.P"}" * m.V"Ignored")^0 * "}" | ||
| 245 | + "[" * (-m.P"]" * m.V"Ignored")^0 * "]" | ||
| 246 | + "'" * (-m.P"'" * m.V"Ignored")^0 * "'" | ||
| 247 | + '"' * (-m.P'"' * m.V"Ignored")^0 * '"'; | ||
| 248 | } | ||
| 249 | |||
| 250 | local ignore = m.Cmt(any, function (input, pos) | ||
| 251 | return syntaxerrs[#syntaxerrs].pos, dummy | ||
| 252 | end) | ||
| 253 | |||
| 254 | local pointAtStart = m.Cmt(any, function (input, pos) | ||
| 255 | -- like ignore but makes the last syntax error point at the start | ||
| 256 | local ret = syntaxerrs[#syntaxerrs].pos | ||
| 257 | syntaxerrs[#syntaxerrs].pos = pos-1 | ||
| 258 | return ret, dummy | ||
| 259 | end) | ||
| 260 | |||
| 261 | |||
| 262 | local function labify (labelnames) | ||
| 263 | for i, l in ipairs(labelnames) do | ||
| 264 | labelnames[i] = labels[l] | ||
| 265 | end | ||
| 266 | return labelnames | ||
| 267 | end | ||
| 268 | |||
| 269 | local labelset1 = labify { | ||
| 270 | "ExpPatt2", "ExpPatt3", | ||
| 271 | "ExpPatt4", "ExpPatt5", "ExpPatt6", "ExpPatt7", | ||
| 272 | "ExpPatt8", "ExpPattOrClose", | ||
| 273 | "ExpNum", "ExpCap", | ||
| 274 | "ExpName1", "ExpName2", "ExpName3", | ||
| 275 | "ExpNameOrLab", "ExpItem", | ||
| 276 | "MisClose6", "MisClose7" | ||
| 277 | } | ||
| 278 | |||
| 279 | local labelset2 = labify { | ||
| 280 | "MisClose1", "MisClose2", "MisClose3", "MisClose4", "MisClose5" | ||
| 281 | } | ||
| 282 | |||
| 283 | local labelset3 = labify { | ||
| 284 | "ExpPatt1", "ExpLab1", "ExpLab2", "MisClose7" | ||
| 285 | } | ||
| 286 | |||
| 287 | local exp = m.P{ "Exp", | 233 | local exp = m.P{ "Exp", |
| 288 | Exp = S * ( m.V"Grammar" | 234 | Exp = S * ( m.V"Grammar" |
| 289 | + (m.V"RecovSeq" * (S * "/" * m.Lc((m.Ct(m.V"Labels") + m.Cc(nil)) | 235 | + (m.V"Seq" * (S * "/" * (m.Ct(m.V"Labels") + m.Cc(nil)) |
| 290 | * expect(S * m.V"RecovSeq", | 236 | * expect(S * m.V"Seq", "ExpPatt1") |
| 291 | "ExpPatt1"), | ||
| 292 | m.Cc(nil) * skip, | ||
| 293 | unpack(labelset3)) | ||
| 294 | )^0 | 237 | )^0 |
| 295 | ) / labchoice); | 238 | ) / labchoice); |
| 296 | Labels = m.P"{" * expect(S * m.V"Label", "ExpLab1") | 239 | Labels = m.P"{" * expect(S * m.V"Label", "ExpLab1") |
| 297 | * (S * "," * expect(S * m.V"Label", "ExpLab2"))^0 | 240 | * (S * "," * expect(S * m.V"Label", "ExpLab2"))^0 |
| 298 | * expect(S * "}", "MisClose7"); | 241 | * expect(S * "}", "MisClose7"); |
| 299 | RecovSeq = m.Lc(m.V"Seq", skip, unpack(labelset1)); | ||
| 300 | Seq = m.Cf(m.Cc(m.P"") * m.V"Prefix" * (S * m.V"Prefix")^0, mt.__mul); | 242 | Seq = m.Cf(m.Cc(m.P"") * m.V"Prefix" * (S * m.V"Prefix")^0, mt.__mul); |
| 301 | Prefix = "&" * expect(S * m.V"Prefix", "ExpPatt2") / mt.__len | 243 | Prefix = "&" * expect(S * m.V"Prefix", "ExpPatt2") / mt.__len |
| 302 | + "!" * expect(S * m.V"Prefix", "ExpPatt3") / mt.__unm | 244 | + "!" * expect(S * m.V"Prefix", "ExpPatt3") / mt.__unm |
| 303 | + m.V"Suffix"; | 245 | + m.V"Suffix"; |
| 304 | Suffix = m.Cf(m.V"RecovPrimary" * | 246 | Suffix = m.Cf(m.V"Primary" * |
| 305 | ( S * ( m.P"+" * m.Cc(1, mt.__pow) | 247 | ( S * ( m.P"+" * m.Cc(1, mt.__pow) |
| 306 | + m.P"*" * m.Cc(0, mt.__pow) | 248 | + m.P"*" * m.Cc(0, mt.__pow) |
| 307 | + m.P"?" * m.Cc(-1, mt.__pow) | 249 | + m.P"?" * m.Cc(-1, mt.__pow) |
| @@ -318,11 +260,9 @@ local exp = m.P{ "Exp", | |||
| 318 | "ExpName1") | 260 | "ExpName1") |
| 319 | ) | 261 | ) |
| 320 | )^0, function (a,b,f) return f(a,b) end ); | 262 | )^0, function (a,b,f) return f(a,b) end ); |
| 321 | RecovPrimary = m.Lc(m.V"Primary", ignore, unpack(labelset2)); | ||
| 322 | Primary = "(" * expect(m.V"Exp", "ExpPatt4") * expect(S * ")", "MisClose1") | 263 | Primary = "(" * expect(m.V"Exp", "ExpPatt4") * expect(S * ")", "MisClose1") |
| 323 | + m.Lc(String / mm.P, pointAtStart, | 264 | + String / mm.P |
| 324 | labels["MisTerm1"], labels["MisTerm2"]) | 265 | + Class |
| 325 | + m.Lc(Class, pointAtStart, labels["MisClose8"]) | ||
| 326 | + defined | 266 | + defined |
| 327 | + "%" * expect(m.V"Labels", "ExpNameOrLab") / mm.T | 267 | + "%" * expect(m.V"Labels", "ExpNameOrLab") / mm.T |
| 328 | + "{:" * (name * ":" + m.Cc(nil)) * expect(m.V"Exp", "ExpPatt5") | 268 | + "{:" * (name * ":" + m.Cc(nil)) * expect(m.V"Exp", "ExpPatt5") |
| @@ -374,23 +314,20 @@ local function compile (p, defs) | |||
| 374 | if mm.type(p) == "pattern" then return p end -- already compiled | 314 | if mm.type(p) == "pattern" then return p end -- already compiled |
| 375 | p = p .. " " -- for better reporting of column numbers in errors when at EOF | 315 | p = p .. " " -- for better reporting of column numbers in errors when at EOF |
| 376 | local ok, cp, label, suffix = pcall(function() return pattern:match(p, 1, defs) end) | 316 | local ok, cp, label, suffix = pcall(function() return pattern:match(p, 1, defs) end) |
| 377 | if not ok and #syntaxerrs == 0 then | 317 | if not ok and cp then |
| 378 | if type(cp) == "string" then | 318 | if type(cp) == "string" then |
| 379 | cp = cp:gsub("^[^:]+:[^:]+: ", "") | 319 | cp = cp:gsub("^[^:]+:[^:]+: ", "") |
| 380 | end | 320 | end |
| 381 | error(cp, 3) | 321 | error(cp, 3) |
| 382 | end | 322 | end |
| 383 | if #syntaxerrs > 0 then | 323 | if not cp then |
| 384 | local lines = splitlines(p) | 324 | local lines = splitlines(p) |
| 385 | local errors = {} | 325 | local line, col = lineno(p, #p - #suffix + 1) |
| 386 | for i, err in ipairs(syntaxerrs) do | 326 | local err = {} |
| 387 | local line, col = lineno(p, err.pos) | 327 | tinsert(err, "L" .. line .. ":C" .. col .. ": " .. errmsgs[label]) |
| 388 | tinsert(errors, "L" .. line .. ":C" .. col .. ": " .. errmsgs[err.label]) | 328 | tinsert(err, lines[line]) |
| 389 | tinsert(errors, lines[line]) | 329 | tinsert(err, rep(" ", col-1) .. "^") |
| 390 | tinsert(errors, rep(" ", col-1) .. "^") | 330 | error("syntax error(s) in pattern\n" .. concat(err, "\n"), 3) |
| 391 | end | ||
| 392 | syntaxerrs = {} | ||
| 393 | error("syntax error(s) in pattern\n" .. concat(errors, "\n"), 3) | ||
| 394 | end | 331 | end |
| 395 | return cp | 332 | return cp |
| 396 | end | 333 | end |
diff --git a/testrelabelparser.lua b/testrelabelparser.lua index 1c5bb9f..46e01ee 100644 --- a/testrelabelparser.lua +++ b/testrelabelparser.lua | |||
| @@ -199,9 +199,6 @@ testerror([[{ {~ } ~}]], [[ | |||
| 199 | L1:C5: expected a pattern after '{~' | 199 | L1:C5: expected a pattern after '{~' |
| 200 | { {~ } ~} | 200 | { {~ } ~} |
| 201 | ^ | 201 | ^ |
| 202 | L1:C10: missing closing '}' | ||
| 203 | { {~ } ~} | ||
| 204 | ^ | ||
| 205 | ]]) | 202 | ]]) |
| 206 | 203 | ||
| 207 | testerror([[{~ ^_^ ~}]], [[ | 204 | testerror([[{~ ^_^ ~}]], [[ |
| @@ -421,9 +418,6 @@ testerror([[{: group: 'p' :}]], [[ | |||
| 421 | L1:C9: missing closing ':}' | 418 | L1:C9: missing closing ':}' |
| 422 | {: group: 'p' :} | 419 | {: group: 'p' :} |
| 423 | ^ | 420 | ^ |
| 424 | L1:C9: unexpected characters after the pattern | ||
| 425 | {: group: 'p' :} | ||
| 426 | ^ | ||
| 427 | ]]) | 421 | ]]) |
| 428 | 422 | ||
| 429 | testerror([[S <- {: 'p' T <- 'q']], [[ | 423 | testerror([[S <- {: 'p' T <- 'q']], [[ |
| @@ -447,9 +441,6 @@ testerror([['p' {| 'q' / 'r' }]], [[ | |||
| 447 | L1:C17: missing closing '|}' | 441 | L1:C17: missing closing '|}' |
| 448 | 'p' {| 'q' / 'r' } | 442 | 'p' {| 'q' / 'r' } |
| 449 | ^ | 443 | ^ |
| 450 | L1:C18: unexpected characters after the pattern | ||
| 451 | 'p' {| 'q' / 'r' } | ||
| 452 | ^ | ||
| 453 | ]]) | 444 | ]]) |
| 454 | 445 | ||
| 455 | -- testing MisClose5 | 446 | -- testing MisClose5 |
| @@ -485,186 +476,49 @@ L1:C12: missing closing '}' | |||
| 485 | -- testing MisClose8 | 476 | -- testing MisClose8 |
| 486 | 477 | ||
| 487 | testerror([[[]], [[ | 478 | testerror([[[]], [[ |
| 488 | L1:C1: missing closing ']' | 479 | L1:C2: missing closing ']' |
| 489 | [ | 480 | [ |
| 490 | ^ | 481 | ^ |
| 491 | ]]) | 482 | ]]) |
| 492 | 483 | ||
| 493 | testerror([[[^]], [[ | 484 | testerror([[[^]], [[ |
| 494 | L1:C1: missing closing ']' | 485 | L1:C3: missing closing ']' |
| 495 | [^ | 486 | [^ |
| 496 | ^ | 487 | ^ |
| 497 | ]]) | 488 | ]]) |
| 498 | 489 | ||
| 499 | testerror([[[] ]], [[ | 490 | testerror([[[] ]], [[ |
| 500 | L1:C1: missing closing ']' | 491 | L1:C4: missing closing ']' |
| 501 | [] | 492 | [] |
| 502 | ^ | 493 | ^ |
| 503 | ]]) | 494 | ]]) |
| 504 | 495 | ||
| 505 | testerror([[[^] ]], [[ | 496 | testerror([[[^] ]], [[ |
| 506 | L1:C1: missing closing ']' | 497 | L1:C6: missing closing ']' |
| 507 | [^] | 498 | [^] |
| 508 | ^ | 499 | ^ |
| 509 | ]]) | 500 | ]]) |
| 510 | 501 | ||
| 511 | testerror([[[_-___-_|]], [[ | 502 | testerror([[[_-___-_|]], [[ |
| 512 | L1:C1: missing closing ']' | 503 | L1:C10: missing closing ']' |
| 513 | [_-___-_| | 504 | [_-___-_| |
| 514 | ^ | 505 | ^ |
| 515 | ]]) | 506 | ]]) |
| 516 | 507 | ||
| 517 | -- testing MisTerm1 | 508 | -- testing MisTerm1 |
| 518 | 509 | ||
| 519 | testerror([['That is the question...]], [[ | 510 | testerror([['That is the question...]], [[ |
| 520 | L1:C1: missing terminating single quote | 511 | L1:C25: missing terminating single quote |
| 521 | 'That is the question... | 512 | 'That is the question... |
| 522 | ^ | 513 | ^ |
| 523 | ]]) | 514 | ]]) |
| 524 | 515 | ||
| 525 | -- testing MisTerm2 | 516 | -- testing MisTerm2 |
| 526 | 517 | ||
| 527 | testerror([[Q <- "To be or not to be...]], [[ | 518 | testerror([[Q <- "To be or not to be...]], [[ |
| 528 | L1:C6: missing terminating double quote | 519 | L1:C28: missing terminating double quote |
| 529 | Q <- "To be or not to be... | 520 | Q <- "To be or not to be... |
| 530 | ^ | 521 | ^ |
| 531 | ]]) | ||
| 532 | |||
| 533 | -- testing error recovery, more complex grammars (multiline), | ||
| 534 | -- and pointer positions in error recovery | ||
| 535 | |||
| 536 | testerror([[&'p'/&/!/'p'^'q']], [[ | ||
| 537 | L1:C7: expected a pattern after '&' | ||
| 538 | &'p'/&/!/'p'^'q' | ||
| 539 | ^ | ||
| 540 | L1:C9: expected a pattern after '!' | ||
| 541 | &'p'/&/!/'p'^'q' | ||
| 542 | ^ | ||
| 543 | L1:C14: expected a number after '^', '+' or '-' (no space) | ||
| 544 | &'p'/&/!/'p'^'q' | ||
| 545 | ^ | ||
| 546 | ]]) | ||
| 547 | |||
| 548 | testerror([[ | ||
| 549 | A <- 'a' (B 'b' | ||
| 550 | B <- 'x' / ! | ||
| 551 | C <- 'c' | ||
| 552 | ]], [[ | ||
| 553 | L1:C18: missing closing ')' | ||
| 554 | A <- 'a' (B 'b' | ||
| 555 | ^ | ||
| 556 | L2:C15: expected a pattern after '!' | ||
| 557 | B <- 'x' / ! | ||
| 558 | ^ | ||
| 559 | ]]) | ||
| 560 | |||
| 561 | testerror([['a' / &@ ('c' / 'd')]], [[ | ||
| 562 | L1:C8: expected a pattern after '&' | ||
| 563 | 'a' / &@ ('c' / 'd') | ||
| 564 | ^ | ||
| 565 | ]]) | ||
| 566 | |||
| 567 | testerror([['x' / & / 'y']], [[ | ||
| 568 | L1:C8: expected a pattern after '&' | ||
| 569 | 'x' / & / 'y' | ||
| 570 | ^ | ||
| 571 | ]]) | ||
| 572 | |||
| 573 | testerror([[&/'p'/!/'q']], [[ | ||
| 574 | L1:C2: expected a pattern after '&' | ||
| 575 | &/'p'/!/'q' | ||
| 576 | ^ | ||
| 577 | L1:C8: expected a pattern after '!' | ||
| 578 | &/'p'/!/'q' | ||
| 579 | ^ | ||
| 580 | ]]) | ||
| 581 | |||
| 582 | testerror([['p'//'q']], [[ | ||
| 583 | L1:C5: expected a pattern after '/' or the label(s) | ||
| 584 | 'p'//'q' | ||
| 585 | ^ | ||
| 586 | ]]) | ||
| 587 | |||
| 588 | testerror([[ | ||
| 589 | S <- 'forgot to close / T | ||
| 590 | T <- 'T' & / 't' | ||
| 591 | ]], [[ | ||
| 592 | L1:C8: missing terminating single quote | ||
| 593 | S <- 'forgot to close / T | ||
| 594 | ^ | ||
| 595 | L2:C13: expected a pattern after '&' | ||
| 596 | T <- 'T' & / 't' | ||
| 597 | ^ | ||
| 598 | ]]) | ||
| 599 | |||
| 600 | testerror([[ | ||
| 601 | S <- [a-z / T | ||
| 602 | T <- 'x' / & / 'y' | ||
| 603 | ]], [[ | ||
| 604 | L1:C8: missing closing ']' | ||
| 605 | S <- [a-z / T | ||
| 606 | ^ | ||
| 607 | L2:C15: expected a pattern after '&' | ||
| 608 | T <- 'x' / & / 'y' | ||
| 609 | ^ | ||
| 610 | ]]) | ||
| 611 | |||
| 612 | testerror([[ | ||
| 613 | S <- ('p' -- comment | ||
| 614 | ]], [[ | ||
| 615 | L1:C12: missing closing ')' | ||
| 616 | S <- ('p' -- comment | ||
| 617 | ^ | ||
| 618 | ]]) | ||
| 619 | |||
| 620 | -- an unfortunate second error exists because we don't know | ||
| 621 | -- what's part of the quotation | ||
| 622 | testerror([[ | ||
| 623 | X <- ('p / Q (R | ||
| 624 | / S)) | ||
| 625 | Q <- 'q' | ||
| 626 | R <- 'r' | ||
| 627 | S <- 's' | ||
| 628 | ]], [[ | ||
| 629 | L1:C9: missing terminating single quote | ||
| 630 | X <- ('p / Q (R | ||
| 631 | ^ | ||
| 632 | L2:C9: unexpected characters after the pattern | ||
| 633 | / S)) | ||
| 634 | ^ | ||
| 635 | ]]) | ||
| 636 | |||
| 637 | testerror([[ | ||
| 638 | A <- 'A' /{'lab'} B / ! | ||
| 639 | |||
| 640 | B <- %{1, 2 3} 'b' / '6' & / 'B' | ||
| 641 | |||
| 642 | C <- A^B | ||
| 643 | ]], [[ | ||
| 644 | L1:C14: expected at least one label after '{' | ||
| 645 | A <- 'A' /{'lab'} B / ! | ||
| 646 | ^ | ||
| 647 | L1:C26: expected a pattern after '!' | ||
| 648 | A <- 'A' /{'lab'} B / ! | ||
| 649 | ^ | ||
| 650 | L3:C15: missing closing '}' | ||
| 651 | B <- %{1, 2 3} 'b' / '6' & / 'B' | ||
| 652 | ^ | ||
| 653 | L3:C29: expected a pattern after '&' | ||
| 654 | B <- %{1, 2 3} 'b' / '6' & / 'B' | ||
| 655 | ^ | ||
| 656 | L5:C10: expected a number after '^', '+' or '-' (no space) | ||
| 657 | C <- A^B | ||
| 658 | ^ | ||
| 659 | ]]) | ||
| 660 | |||
| 661 | testerror([['p'/{1/'q'/&]], [[ | ||
| 662 | L1:C7: missing closing '}' | ||
| 663 | 'p'/{1/'q'/& | ||
| 664 | ^ | ||
| 665 | L1:C13: expected a pattern after '&' | ||
| 666 | 'p'/{1/'q'/& | ||
| 667 | ^ | ||
| 668 | ]]) | 522 | ]]) |
| 669 | 523 | ||
| 670 | -- testing non-syntax errors | 524 | -- testing non-syntax errors |
