Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement basic error recovery #2020

Merged
merged 91 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from 82 commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
9deefa3
recovered Recoverer from git history
jurgenvinju Mar 30, 2022
d1fdf89
Merge branch 'main' into revive-robust-parsing
jurgenvinju Mar 30, 2022
9ae895c
fixed imports and whitespace
jurgenvinju Mar 31, 2022
4e43070
added documentation
jurgenvinju Mar 31, 2022
ff99ac9
renamed recoverer and simplified to whitespace only and all context-f…
jurgenvinju Mar 31, 2022
d2a0b66
removed unused javadoc plugin that produced warnings
jurgenvinju Mar 31, 2022
d9439a4
fixed compiler warnings
jurgenvinju Mar 31, 2022
d87b4b8
fixed warnings
jurgenvinju Mar 31, 2022
4897d88
fixed warnings
jurgenvinju Mar 31, 2022
5803411
added boolean parameter \'robust\' to parsing API
jurgenvinju Mar 31, 2022
3adee6c
wired boolean parameter for robustness from Rascal function down to p…
jurgenvinju Mar 31, 2022
7318e8f
added override
jurgenvinju Mar 31, 2022
f6e13d8
minor additions to make recovery work and removed dead code
jurgenvinju Apr 11, 2022
ba0fb43
recovered a missing piece from the recovery code
jurgenvinju Apr 13, 2022
650224a
Debugging error recovery
jurgenvinju Apr 14, 2022
6d5d49b
added possibility for recovered nodes to start back in time (at earli…
jurgenvinju Apr 15, 2022
78ee76b
fixed off-by-one: error nodes should be scheduled one character ahead…
jurgenvinju Apr 15, 2022
d9f8fc9
fixed another off-by-one
jurgenvinju Apr 15, 2022
685198d
added initial construction of skipped nodes
jurgenvinju Apr 15, 2022
1d5435b
gave skipped productions a type such that all trees have a type
jurgenvinju Apr 15, 2022
50edd09
Merge branch 'main' into revive-robust-parsing
jurgenvinju Apr 19, 2022
5265ef0
updated template
jurgenvinju Apr 20, 2022
a2162c9
bumped rascal-maven-plugin to 0.8.0 to see if we can benefit from opt…
jurgenvinju Apr 20, 2022
91fb32b
upgraded to rascal-maven-plugin 0.8.1
jurgenvinju Apr 21, 2022
018826f
[maven-release-plugin] prepare release v0.23.1
jurgenvinju Apr 21, 2022
7b6e8b8
[maven-release-plugin] prepare for next development iteration
jurgenvinju Apr 21, 2022
4aefd52
make sure that (a) BasicIDEServices are registered for the commandlin…
jurgenvinju Apr 22, 2022
dde9bd9
basic IDE services can now also browse contents of files which are no…
jurgenvinju Apr 25, 2022
6f9b2b9
Merge branch 'main' into robust-parsing-merge-main
PieterOlivier Jun 6, 2024
d88ac77
Merge branch 'main' into revive-robust-parsing
PieterOlivier Jun 9, 2024
517df9c
Started working on a simple recovery test
PieterOlivier Jun 10, 2024
c779820
Added 'toString' methods and fixed issue in recoverer.
PieterOlivier Jun 17, 2024
13ffcef
Added 'allowRecovery` keyword parameter in parsing functions.
PieterOlivier Jun 18, 2024
b8eb72e
Removed 'Reflective' prefix from StackNodeIdDispenser class name
PieterOlivier Jun 18, 2024
f82006c
WIP: recovery starting to work
PieterOlivier Jun 27, 2024
c8faf66
Merge branch 'main' into robust-parsing/simple-test
PieterOlivier Jul 8, 2024
88cddc3
Added some methods to analyze recovered parse errors in parse trees
PieterOlivier Jul 10, 2024
6d19281
Added comment and removed unused import
PieterOlivier Jul 10, 2024
bcd5914
Enabled logging when error recovery is in effect
PieterOlivier Jul 10, 2024
fb6ffe5
Made printing of productions more robust (it crashed on 'regular' pro…
PieterOlivier Jul 10, 2024
27f1afc
Added some basic recovery tests
PieterOlivier Jul 10, 2024
15fedbf
Implemented parser datastructure visualization using graphviz
PieterOlivier Jul 18, 2024
0eed9a1
Implemented skipping of remaining characters when top-level productio…
PieterOlivier Jul 18, 2024
2b044fd
Reinstated end-of-input check before recovering (for now)
PieterOlivier Jul 18, 2024
d5dbe8c
Minor comment and test changes
PieterOlivier Aug 6, 2024
2246e06
In addition to using whitespace we now also skip until after the last…
PieterOlivier Aug 8, 2024
4b11450
Implemented dynamic last/follow calculations
PieterOlivier Aug 19, 2024
8ef03b4
Minor cleanup of parser tests and debug support
PieterOlivier Aug 20, 2024
7d82f20
Implemented error tree fixup (including source locations)
PieterOlivier Aug 21, 2024
706662b
Renamed RecoveryNodeFlattener to SkippedNodeFlattener
PieterOlivier Aug 21, 2024
7d68129
Implemented basic error disambiguation
PieterOlivier Aug 22, 2024
6b2939c
Added support for error and skipped productions in vis::Text
PieterOlivier Aug 22, 2024
ff350ca
Look "through" non-terminals when finding end/next matchers
PieterOlivier Aug 26, 2024
6d3d58d
Merge branch 'main' into to-token-recoverer
PieterOlivier Aug 26, 2024
2b6a69f
Miscellaneous cleanup of error recovery code
PieterOlivier Aug 28, 2024
7ee16aa
Removed unused fields from SkippedNode
PieterOlivier Aug 28, 2024
002e7a6
Switched from hardcoding to environment variable for the parser visua…
PieterOlivier Aug 28, 2024
238e4c2
Fixed some compiler warnings in the DebugVisualizer
PieterOlivier Aug 28, 2024
704726b
Fixed some compiler warnings
PieterOlivier Aug 28, 2024
af7b5d5
INtroduced StackNodeVisitor
PieterOlivier Aug 28, 2024
2d3fbb1
Fixed more warnings
PieterOlivier Aug 28, 2024
e95b1aa
Madde AbstractStackNode.visit public
PieterOlivier Aug 28, 2024
c06dc6d
Use visitor pattern instead of instanceof in ToTokenRecoverer
PieterOlivier Aug 28, 2024
d584dfe
Renamed DebugVisualizer to ParseStateVisualizer
PieterOlivier Aug 28, 2024
41ea6e8
Generalized AbstractStackNode visitor to be able to return values
PieterOlivier Aug 28, 2024
82c156d
Removed debug print
PieterOlivier Aug 28, 2024
c406e2b
Added license header to files introduced for error recovery
PieterOlivier Aug 28, 2024
c884ceb
Added license header to more files and fixed years.
PieterOlivier Aug 28, 2024
9dce66d
Fixed bug when inputURI is missing
PieterOlivier Aug 28, 2024
a139019
Fixed issues when location information is missing
PieterOlivier Aug 29, 2024
150131e
Fixed off-by-one-error
PieterOlivier Aug 29, 2024
5b1561e
Now looking deep to find error trees in getBestErrorTree
PieterOlivier Sep 1, 2024
23d23b4
Removed prints
PieterOlivier Sep 1, 2024
93611fe
Added 'recovery' tests and introduced artificial failure to see if te…
PieterOlivier Sep 1, 2024
bd2d1ee
Added recovery tests
PieterOlivier Sep 1, 2024
dec2b29
Worked on error recovery tests
PieterOlivier Sep 1, 2024
9abd0bc
Improved comments
PieterOlivier Sep 2, 2024
4cf173e
Renamed 'input' field to 'inputUri'.
PieterOlivier Sep 2, 2024
bcb2753
Removed some obsolete comments
PieterOlivier Sep 2, 2024
5a2266b
Added backwards compatible 'parser' function
PieterOlivier Sep 4, 2024
2be0d9b
Renamed input to inputUri
PieterOlivier Sep 4, 2024
36d4964
Disabled tutor because it requires forward-compatibility of Java code…
PieterOlivier Sep 4, 2024
96fc604
Various changes based on an excellent code review by Sung.
PieterOlivier Sep 6, 2024
cf16c82
Layout changes
PieterOlivier Sep 6, 2024
b94bc02
Moved tests, replaced UnicodeConverter with String constructor
PieterOlivier Sep 17, 2024
9444d21
Control parser visualization by environment variable
PieterOlivier Sep 17, 2024
2200fdf
Introduced NopDebugListener so we can remove all the if checks
PieterOlivier Sep 17, 2024
177e425
Fixed compiler error
PieterOlivier Sep 18, 2024
377a2e1
Fixed debugListener NPE
PieterOlivier Sep 18, 2024
074b5bf
Improved parser datastructure visualization
PieterOlivier Sep 18, 2024
30b935a
Look through "nullable" productions
PieterOlivier Sep 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"request": "launch",
"mainClass": "org.rascalmpl.shell.RascalShell",
"projectName": "rascal",
"cwd" : "${workspaceFolder}/../rascal-tutor",
"cwd": "${workspaceFolder}/../rascal-tutor",
"vmArgs": "-Xss80m -Xmx2g -ea"
},
{
Expand Down
2 changes: 2 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
<goal>package</goal>
</goals>
</execution>
<!--
PieterOlivier marked this conversation as resolved.
Show resolved Hide resolved
<execution>
<id>default-cli</id>
<phase>compile</phase>
Expand All @@ -177,6 +178,7 @@
</ignores>
</configuration>
</execution>
-->
</executions>
</plugin>
<plugin>
Expand Down
2 changes: 1 addition & 1 deletion src/org/rascalmpl/interpreter/Evaluator.java
Original file line number Diff line number Diff line change
Expand Up @@ -989,7 +989,7 @@ private IFunction parserForCurrentModule(RascalFunctionValueFactory vf, ModuleEn
IMap syntaxDefinition = curMod.getSyntaxDefinition();
IMap grammar = (IMap) getParserGenerator().getGrammarFromModules(getMonitor(), curMod.getName(), syntaxDefinition).get("rules");
IConstructor reifiedType = vf.reifiedType(dummy, grammar);
return vf.parsers(reifiedType, vf.bool(false), vf.bool(false), vf.bool(false), vf.set());
return vf.parsers(reifiedType, vf.bool(false), vf.bool(false), vf.bool(false), vf.bool(false), vf.set());
}

private Result<IValue> evalMore(String command, ISourceLocation location)
Expand Down
277 changes: 192 additions & 85 deletions src/org/rascalmpl/library/ParseTree.rsc

Large diffs are not rendered by default.

26 changes: 15 additions & 11 deletions src/org/rascalmpl/library/Prelude.java
Original file line number Diff line number Diff line change
Expand Up @@ -2377,20 +2377,24 @@ public INode arbNode() {

protected final TypeReifier tr;

public IFunction parser(IValue start, IBool allowAmbiguity, IBool allowRecovery, IBool hasSideEffects, ISet filters) {
return rascalValues.parser(start, allowAmbiguity, allowRecovery, hasSideEffects, values.bool(false), filters);
}

public IFunction parser(IValue start, IBool allowAmbiguity, IBool hasSideEffects, ISet filters) {
return rascalValues.parser(start, allowAmbiguity, hasSideEffects, values.bool(false), filters);
return rascalValues.parser(start, allowAmbiguity, values.bool(false), hasSideEffects, values.bool(false), filters);
}

public IFunction firstAmbiguityFinder(IValue start, IBool hasSideEffects, ISet filters) {
return rascalValues.parser(start, values.bool(true), hasSideEffects, values.bool(true), filters);
public IFunction firstAmbiguityFinder(IValue start, IBool allowRecovery, IBool hasSideEffects, ISet filters) {
PieterOlivier marked this conversation as resolved.
Show resolved Hide resolved
return rascalValues.parser(start, values.bool(true), allowRecovery, hasSideEffects, values.bool(true), filters);
}

public IFunction parsers(IValue start, IBool allowAmbiguity, IBool hasSideEffects, ISet filters) {
return rascalValues.parsers(start, allowAmbiguity, hasSideEffects, values.bool(false), filters);
public IFunction parsers(IValue start, IBool allowAmbiguity, IBool allowRecovery, IBool hasSideEffects, ISet filters) {
return rascalValues.parsers(start, allowAmbiguity, allowRecovery, hasSideEffects, values.bool(false), filters);
}

public IFunction firstAmbiguityFinders(IValue start, IBool hasSideEffects, ISet filters) {
return rascalValues.parsers(start, values.bool(true), hasSideEffects, values.bool(true), filters);
public IFunction firstAmbiguityFinders(IValue start, IBool allowRecovery, IBool hasSideEffects, ISet filters) {
return rascalValues.parsers(start, values.bool(true), allowRecovery, hasSideEffects, values.bool(true), filters);
}

public void storeParsers(IValue start, ISourceLocation saveLocation) {
Expand All @@ -2405,18 +2409,18 @@ public void storeParsers(IValue start, ISourceLocation saveLocation) {
}
}

public IFunction loadParsers(ISourceLocation savedLocation, IBool allowAmbiguity, IBool hasSideEffects, ISet filters) {
public IFunction loadParsers(ISourceLocation savedLocation, IBool allowAmbiguity, IBool allowRecovery, IBool hasSideEffects, ISet filters) {
try {
return rascalValues.loadParsers(savedLocation, allowAmbiguity, hasSideEffects, values.bool(false), filters);
return rascalValues.loadParsers(savedLocation, allowAmbiguity, allowRecovery, hasSideEffects, values.bool(false), filters);
}
catch (IOException | ClassNotFoundException e) {
throw RuntimeExceptionFactory.io(e.getMessage());
}
}

public IFunction loadParser(IValue grammar, ISourceLocation savedLocation, IBool allowAmbiguity, IBool hasSideEffects, ISet filters) {
public IFunction loadParser(IValue grammar, ISourceLocation savedLocation, IBool allowRecovery, IBool allowAmbiguity, IBool hasSideEffects, ISet filters) {
try {
return rascalValues.loadParser(grammar, savedLocation, allowAmbiguity, hasSideEffects, values.bool(false), filters);
return rascalValues.loadParser(grammar, savedLocation, allowAmbiguity, allowRecovery, hasSideEffects, values.bool(false), filters);
}
catch (IOException | ClassNotFoundException e) {
throw RuntimeExceptionFactory.io(e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
PieterOlivier marked this conversation as resolved.
Show resolved Hide resolved
* Copyright (c) 2024, NWO-I Centrum Wiskunde & Informatica (CWI)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/

module lang::rascal::tests::recovery::BasicRecoveryTests

import ParseTree;

layout Layout = [\ ]* !>> [\ ];

syntax S = T;

syntax T = ABC End;
syntax ABC = 'a' 'b' 'c';
syntax End = "$";

private Tree parseS(str input, bool visualize=false)
PieterOlivier marked this conversation as resolved.
Show resolved Hide resolved
= parser(#S, allowRecovery=true, allowAmbiguity=true)(input, |unknown:///?visualize=<"<visualize>">|);
PieterOlivier marked this conversation as resolved.
Show resolved Hide resolved

test bool basicOk() {
return !hasErrors(parseS("a b c $", visualize=true));
}

test bool abx() {
Tree t = parseS("a b x $", visualize=true);
return getErrorText(findFirstError(defaultErrorDisambiguationFilter(t))) == "x ";
}

test bool axc() {
Tree t = parseS("a x c $", visualize=true);
return getErrorText(findFirstError(t)) == "x c";
}

test bool ax() {
Tree t = parseS("a x $", visualize=true);
return getErrorText(findFirstError(t)) == "x ";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2024, NWO-I Centrum Wiskunde & Informatica (CWI)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/

module lang::rascal::tests::recovery::ListRecoveryTests

import ParseTree;
import IO;

layout Layout = [\ ]* !>> [\ ];

syntax S = T End;

syntax T = { AB "," }*;
syntax AB = "a" "b";
syntax End = "$";

Tree parseList(str s, bool visualize=false) {
return parser(#S, allowRecovery=true, allowAmbiguity=true)(s, |unknown:///?visualize=<"<visualize>">|);
}

test bool listOk() {
return !hasErrors(parseList("a b , a b , a b $", visualize=true));
}

test bool listTypo() {
Tree t = parseList("a b, a x, ab $", visualize=true);
return hasErrors(t);
}

test bool listTypoWs() {
Tree t = parseList("a b , a x , a b $", visualize=true);
return hasErrors(t);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Copyright (c) 2024, NWO-I Centrum Wiskunde & Informatica (CWI)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/

module lang::rascal::tests::recovery::NestedRecoveryTests

import ParseTree;
import IO;

layout Layout = [\ ]* !>> [\ ];

syntax S = T;

syntax T = A B C;

syntax A = "a";
syntax B = "b" "b";
syntax C = "c";

private Tree parseS(str input, bool visualize=false)
= parser(#S, allowRecovery=true, allowAmbiguity=true)(input, |unknown:///?visualize=<"<visualize>">|);

test bool nestedOk() {
return !hasErrors(parseS("a b b c"));
}

test bool nestedTypo() {
Tree t = parseS("a b x c");
return getErrorText(findFirstError(defaultErrorDisambiguationFilter(t))) == "x ";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* Copyright (c) 2024, NWO-I Centrum Wiskunde & Informatica (CWI)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/

module lang::rascal::tests::recovery::PicoRecoveryTests

import lang::pico::\syntax::Main;

import ParseTree;
import IO;

Tree parsePico(str input, bool visualize=false)
= parser(#Program, allowRecovery=true, allowAmbiguity=true)(input, |unknown:///?visualize=<"<visualize>">|);

test bool picoOk() {
t = parsePico("begin declare input : natural,
output : natural,
repnr : natural,
rep : natural;
input := 14;
output := 0;
while input - 1 do
rep := output;
repnr := input;
while repnr - 1 do
output := output + rep;
repnr := repnr - 1
od;
input := input - 1
od
end");
return !hasErrors(t);
}

test bool picoTypo() {
t = parsePico("begin declare input : natural,
output : natural,
repnr : natural,
rep : natural;
input := 14;
output := 0;
while input - 1 do
rep := output;
repnr := input;
while repnr - 1 do
output := output x rep;
repnr := repnr - 1
od;
input := input - 1
od
end");
Tree error = findFirstError(defaultErrorDisambiguationFilter(t));
return getErrorText(error) == "output x rep";
}

test bool picoMissingSemi() {
t = parsePico("begin declare input : natural,
output : natural,
repnr : natural,
rep : natural;
input := 14;
output := 0;
while input - 1 do
rep := output;
repnr := input;
while repnr - 1 do
output := output + rep;
repnr := repnr - 1
od
input := input - 1
od
end");
Tree error = findFirstError(defaultErrorDisambiguationFilter(t));
return getErrorText(error) == "input := input - 1\n od";
}

test bool picoTypoSmall() {
t = parsePico(
"begin declare;
while input do
input x= 14;
output := 0
od
end");

Tree error = findFirstError(defaultErrorDisambiguationFilter(t));
return getErrorText(error) == "x= 14";
}

test bool picoMissingSemiSmall() {
t = parsePico(
"begin declare;
while input do
input := 14
output := 0
od
end");

Tree error = findFirstError(defaultErrorDisambiguationFilter(t));
return getErrorText(error) == "output := 0\n od";
}
Loading