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

Error recovery for Rascal #490

Draft
wants to merge 39 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
20948c6
Update `parse` call to use error recovery
sungshik Oct 8, 2024
ea87d9e
Update `pom.xml` for development
sungshik Oct 8, 2024
6fa7a82
Add reporting of diagnostics for error nodes
sungshik Oct 8, 2024
1aa3634
Make error recovery backward-compatible
sungshik Oct 8, 2024
35a3b02
Add flag to `loadParser` call to set allowRecovery to false for now
sungshik Oct 8, 2024
ea9919f
Fix a bug that adds irrelevant diagnostics
sungshik Oct 9, 2024
2d5dc04
Add exception handler when the location of a parse error is malformed
sungshik Oct 9, 2024
9643852
Add first version parse debouncing
sungshik Oct 11, 2024
f94f08f
Merge branch 'main' into error-recovery/rascal
PieterOlivier Oct 15, 2024
04eaedd
Revert "Add first version parse debouncing"
PieterOlivier Oct 15, 2024
a3dbfbd
Show skipped part and use error tree for outlining
PieterOlivier Oct 16, 2024
17bcab1
Add debounce to parsing in `TextDocumentState`
sungshik Oct 24, 2024
b085657
Merge branch 'error-recovery/rascal' into error-recovery/rascal-debou…
sungshik Oct 24, 2024
6b35288
Use `compareAndSet` instead of `weak...`
sungshik Oct 24, 2024
2749e49
Fix typos in documentation
sungshik Oct 24, 2024
f1bacae
Merge pull request #475 from usethesource/error-recovery/rascal-debou…
sungshik Oct 24, 2024
9d803d0
Merge pull request #476 from usethesource/recovery/skipped
PieterOlivier Oct 25, 2024
b947d04
Upgrade `pom.xml` and `package.sh`
sungshik Oct 25, 2024
073b675
Both outline and codelenses support can now handle error trees
PieterOlivier Oct 25, 2024
5d60fde
Removed spurious hasErrors
PieterOlivier Oct 25, 2024
91d0e6b
Merge pull request #491 from usethesource/recovery/outline-and-code-l…
PieterOlivier Oct 25, 2024
a9d5a06
Move parse error processing (including error nodes) completely to `Te…
sungshik Oct 25, 2024
770561e
Merge branch 'error-recovery/rascal' into error-recovery/rascal-diagn…
sungshik Oct 25, 2024
aeb1a9f
Refine parse error messages
sungshik Oct 25, 2024
90ab10c
Remove unused imports
sungshik Oct 28, 2024
d86c659
Move class `Debouncer` to its own file
sungshik Oct 28, 2024
b095617
Merge pull request #492 from usethesource/error-recovery/rascal-diagn…
sungshik Oct 30, 2024
ea02b93
Merge branch 'main' into error-recovery/rascal
PieterOlivier Nov 5, 2024
92cc913
Remove function that should have been deleted during merge from main
PieterOlivier Nov 5, 2024
066c5df
Bumped rascal version number
PieterOlivier Nov 6, 2024
ed3dd87
Simplify debouncer (joint with @PieterOlivier)
sungshik Nov 8, 2024
7f16037
Improve API of `DebouncedSupplier`
sungshik Nov 8, 2024
761ab06
Add tests for `DebouncedSupplier`
sungshik Nov 8, 2024
15aaa0f
Improve documentations of `DebouncedSupplier`
sungshik Nov 8, 2024
b81dfc4
Revert signature change to `parseIfNotParsing`
sungshik Nov 8, 2024
87e5959
Rename methods to make the names more precise
sungshik Nov 8, 2024
9653e26
Merge branch 'main' into error-recovery/rascal
PieterOlivier Nov 10, 2024
5a123b2
Merge pull request #512 from usethesource/error-recovery/rascal-simpl…
sungshik Nov 11, 2024
819d7a3
Merge branch 'main' into error-recovery/rascal
PieterOlivier Nov 18, 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
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.eclipse.lsp4j.jsonrpc.messages.ResponseErrorCode;
import org.rascalmpl.exceptions.Throw;
import org.rascalmpl.interpreter.Evaluator;
import org.rascalmpl.library.util.ErrorRecovery;
import org.rascalmpl.library.util.PathConfig;
import org.rascalmpl.values.IRascalValueFactory;
import org.rascalmpl.values.functions.IFunction;
Expand All @@ -76,6 +77,7 @@

public class RascalLanguageServices {
private static final IValueFactory VF = IRascalValueFactory.getInstance();
private static final ErrorRecovery RECOVERY = new ErrorRecovery(IRascalValueFactory.getInstance());

private static final Logger logger = LogManager.getLogger(RascalLanguageServices.class);

Expand Down Expand Up @@ -236,8 +238,13 @@ public List<CodeLensSuggestion> locateCodeLenses(ITree tree) {
List<CodeLensSuggestion> result = new ArrayList<>(2);
result.add(new CodeLensSuggestion(module, "Import in new Rascal terminal", "rascalmpl.importModule", moduleName));

for (IValue topLevel : TreeAdapter
.getListASTArgs(TreeAdapter.getArg(TreeAdapter.getArg(tree, "body"), "toplevels"))) {
ITree body = TreeAdapter.getArg(tree, "body");
ITree toplevels = TreeAdapter.getArg(body, "toplevels");
for (IValue topLevel : TreeAdapter.getListASTArgs(toplevels)) {
if (RECOVERY.hasErrors((ITree) topLevel)) {
continue;
}

ITree decl = TreeAdapter.getArg((ITree) topLevel, "declaration");
if ("function".equals(TreeAdapter.getConstructorName(decl))) {
ITree signature = TreeAdapter.getArg(TreeAdapter.getArg(decl, "functionDeclaration"), "signature");
Expand Down
72 changes: 47 additions & 25 deletions rascal-lsp/src/main/rascal/lang/rascal/lsp/Outline.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -31,38 +31,58 @@ import String;
import ParseTree;
import lang::rascal::\syntax::Rascal;
import util::LanguageServer;
import util::ErrorRecovery;

list[DocumentSymbol] outlineRascalModule(start[Module] \mod) {
m= \mod.top;
children = [];

top-down-break visit (m) {
case (Declaration) `<Tags _> <Visibility _> <Type t> <{Variable ","}+ vars>;`:
children += [symbol(clean("<v.name>"), variable(), v@\loc, detail="variable <t> <v>") | v <- vars];

case (Declaration) `<Tags _> <Visibility _> anno <Type t> <Type ot>@<Name name>;`:
children += [symbol(clean("<name>"), field(), t@\loc, detail="anno <t> <ot>")];

case (Declaration) `<Tags _> <Visibility _> alias <UserType u> = <Type al>;`:
children += [symbol(clean("<u.name>"), struct(), u@\loc, detail="<u> = <al>")];
if (!(m has header) || hasErrors(m.header)) {
return [];
}

case (Declaration) `<Tags _> <Visibility _> tag <Kind k> <Name name> on <{Type ","}+ ts>;`:
children += [symbol(clean("<name>"), \key(), name@\loc, detail="tag <k> <name> on <ts>")];
children = [];

case (Declaration) `<Tags _> <Visibility _> data <UserType u> <CommonKeywordParameters kws>;`: {
kwlist = [symbol(".<k.name>", property(), k@\loc, detail="<k.\type>") | kws is present, KeywordFormal k <- kws.keywordFormalList];
children += [symbol("<u.name>", struct(), u@\loc, detail="data <u> <kws>", children=kwlist)];
top-down-break visit (m) {
case decl: (Declaration) `<Tags _> <Visibility _> <Type t> <{Variable ","}+ vars>;`:
if (!hasErrors(decl)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm missing something here. If a node like this matches then it has enough structure to produce the symbol. What does it matter if there are errors inside?

Copy link
Member

@jurgenvinju jurgenvinju Nov 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of the error trees is that they will be there but won't match with any of the expected language constructs. So you can ignore them typically.

For the case where you encounter one during recursion, a match on the error tree has to be added that ignores it or does something useful like a short yield: "<error tree>"[..25]

Copy link
Member

@jurgenvinju jurgenvinju Nov 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yield of an error tree is guaranteed to work: "<myStat>" will yield the entire string that was accepted to fill in for a real statement.

children += [symbol(clean("<v.name>"), variable(), v@\loc, detail="variable <t> <v>") | v <- vars, !hasErrors(v)];
}

case decl: (Declaration) `<Tags _> <Visibility _> anno <Type t> <Type ot>@<Name name>;`:
if (!hasErrors(decl)) {
children += [symbol(clean("<name>"), field(), t@\loc, detail="anno <t> <ot>")];
}

case decl: (Declaration) `<Tags _> <Visibility _> alias <UserType u> = <Type al>;`:
if (!hasErrors(decl)) {
children += [symbol(clean("<u.name>"), struct(), u@\loc, detail="<u> = <al>")];
}

case decl: (Declaration) `<Tags _> <Visibility _> tag <Kind k> <Name name> on <{Type ","}+ ts>;`:
if (!hasErrors(decl)) {
children += [symbol(clean("<name>"), \key(), name@\loc, detail="tag <k> <name> on <ts>")];
}

case decl: (Declaration) `<Tags _> <Visibility _> data <UserType u> <CommonKeywordParameters kws>;`: {
if (!hasErrors(decl)) {
kwlist = [symbol(".<k.name>", property(), k@\loc, detail="<k.\type>") | kws is present, KeywordFormal k <- kws.keywordFormalList];
children += [symbol("<u.name>", struct(), u@\loc, detail="data <u> <kws>", children=kwlist)];
}
}

case (Declaration) `<Tags _> <Visibility _> data <UserType u> <CommonKeywordParameters kws> = <{Variant "|"}+ variants>;` : {
kwlist = [symbol(".<k.name>", property(), k@\loc, detail="<k.\type>") | kws is present, KeywordFormal k <- kws.keywordFormalList];
variantlist = [symbol(clean("<v>"), \constructor(), v@\loc) | v <- variants];
case decl: (Declaration) `<Tags _> <Visibility _> data <UserType u> <CommonKeywordParameters kws> = <{Variant "|"}+ variants>;` : {
if (!hasErrors(decl)) {
kwlist = [symbol(".<k.name>", property(), k@\loc, detail="<k.\type>") | kws is present, KeywordFormal k <- kws.keywordFormalList];
variantlist = [symbol(clean("<v>"), \constructor(), v@\loc) | v <- variants];

children += [symbol("<u.name>", struct(), u@\loc, detail="data <u> <kws>", children=kwlist + variantlist)];
children += [symbol("<u.name>", struct(), u@\loc, detail="data <u> <kws>", children=kwlist + variantlist)];
}
}

case FunctionDeclaration func :
children += [symbol("<func.signature.name><func.signature.parameters>", \function(), (func.signature)@\loc, detail="<func.signature.\type>")];
if (!hasErrors(func)) {
children += [symbol("<func.signature.name><func.signature.parameters>", \function(), (func.signature)@\loc, detail="<func.signature.\type>")];
}

/*
case (Import) `extend <ImportedModule mm>;` :
Expand All @@ -76,11 +96,13 @@ list[DocumentSymbol] outlineRascalModule(start[Module] \mod) {
*/

case SyntaxDefinition def : {
rs = [symbol(clean("<prefix> <p.syms>"), \function(), p@\loc)
| /Prod p := def.production, p is labeled || p is unlabeled,
str prefix := (p is labeled ? "<p.name>: " : "")
];
children += [symbol(clean("<def.defined>"), \struct(), def@\loc, children=rs)];
if (!hasErrors(def)) {
rs = [symbol(clean("<prefix> <p.syms>"), \function(), p@\loc)
| /Prod p := def.production, !hasErrors(p) && (p is labeled || p is unlabeled),
str prefix := (p is labeled ? "<p.name>: " : "")
];
children += [symbol(clean("<def.defined>"), \struct(), def@\loc, children=rs)];
}
}
}

Expand Down
Loading