From bb7ea53ef229763e33f0b9a750825102cd591b58 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Fri, 8 Nov 2024 16:39:39 +0100 Subject: [PATCH 1/5] made field projection in parse trees robust against parse error trees --- .../values/parsetrees/ProductionAdapter.java | 9 +++++ .../values/parsetrees/TreeAdapter.java | 39 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/org/rascalmpl/values/parsetrees/ProductionAdapter.java b/src/org/rascalmpl/values/parsetrees/ProductionAdapter.java index 069bd300d8..23312c01c0 100644 --- a/src/org/rascalmpl/values/parsetrees/ProductionAdapter.java +++ b/src/org/rascalmpl/values/parsetrees/ProductionAdapter.java @@ -16,6 +16,7 @@ package org.rascalmpl.values.parsetrees; import io.usethesource.vallang.IConstructor; +import io.usethesource.vallang.IInteger; import io.usethesource.vallang.IList; import io.usethesource.vallang.IListWriter; import io.usethesource.vallang.INode; @@ -206,4 +207,12 @@ public static boolean shouldFlatten(IConstructor surrounding, IConstructor neste } return false; } + + public static int getErrorDot(IConstructor prod) { + return ((IInteger) prod.get("dot")).intValue(); + } + + public static IConstructor getErrorProd(IConstructor prod) { + return (IConstructor) prod.get("prod"); + } } diff --git a/src/org/rascalmpl/values/parsetrees/TreeAdapter.java b/src/org/rascalmpl/values/parsetrees/TreeAdapter.java index 4ab329a2a9..0a2a4040ab 100644 --- a/src/org/rascalmpl/values/parsetrees/TreeAdapter.java +++ b/src/org/rascalmpl/values/parsetrees/TreeAdapter.java @@ -24,6 +24,7 @@ import org.fusesource.jansi.Ansi.Color; import org.rascalmpl.exceptions.ImplementationError; import org.rascalmpl.interpreter.utils.LimitedResultWriter; +import org.rascalmpl.values.IRascalValueFactory; import org.rascalmpl.values.RascalValueFactory; import org.rascalmpl.values.ValueFactoryFactory; import org.rascalmpl.values.parsetrees.visitors.TreeVisitor; @@ -139,6 +140,9 @@ public static IConstructor getProduction(ITree tree) { /** * This function assumes that getLabeledField does not return null for the same parameters! */ + // TODO @PieterOlivier I guess we could extend this the way we also extended the getLabeledField. + // if the field is still on the parsed side of the dot then we're fine. Otherwise we could + // think about shifting the dot if we put in correct trees at the right places? public static ITree putLabeledField(ITree tree, String field, ITree repl) { if (isAppl(tree)) { IConstructor prod = TreeAdapter.getProduction(tree); @@ -266,6 +270,41 @@ else if (ProductionAdapter.isRegular(prod)) { return null; } } + else if (ProductionAdapter.isError(prod)) { + int dot = ProductionAdapter.getErrorDot(prod); + IConstructor eprod = ProductionAdapter.getErrorProd(prod); + IList syms = ProductionAdapter.getSymbols(eprod); + int index = SymbolAdapter.indexOfLabel(syms, field); + + if (index != -1) { + IConstructor sym = (IConstructor) syms.get(index); + sym = SymbolAdapter.stripLabelsAndConditions(sym); + + if (dot <= index) { + // we have parsed the field so we can just return it. + // this is a likely scenario + return new FieldResult(sym, (ITree) tree.getArgs().get(index)); + } + else { + // We have the right prodction and the field would be there, if we didn't recover from a parse error + // and are missing some of the children (including the indicated field). + // So we return a quasi tree that is of the right type, but it otherwise just an error tree + // like its parent. This tree does not have content, because we wouldn't know which of the skipped + // parts are meant. + var vf = IRascalValueFactory.getInstance(); + // @PieterOlivier is this the right way to do this? I just need an empty tree of the right symbol. + var skipped = vf.constructor(RascalValueFactory.Production_Skipped); + var skippedProd = vf.constructor(RascalValueFactory.Production_Error, sym, skipped, vf.integer(0)); + var skippedTree = vf.appl(skippedProd); + var parentLoc = getLocation(tree); + if (parentLoc != null) { + // TODO @PieterOlivier I guess we need the location of the last parsed element, and use an + // empty range that is just beyond that. But for now I'd like to test with this. + } + return new FieldResult(sym, skippedTree); + } + } + } } return null; From 262ac79ca033788bf5c20c518e6e7f3ca2623a2e Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Wed, 13 Nov 2024 10:52:18 +0100 Subject: [PATCH 2/5] implemented setField on error trees --- .../values/parsetrees/TreeAdapter.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/org/rascalmpl/values/parsetrees/TreeAdapter.java b/src/org/rascalmpl/values/parsetrees/TreeAdapter.java index 0a2a4040ab..5ebdba4f39 100644 --- a/src/org/rascalmpl/values/parsetrees/TreeAdapter.java +++ b/src/org/rascalmpl/values/parsetrees/TreeAdapter.java @@ -194,6 +194,26 @@ else if (ProductionAdapter.isRegular(prod)) { return null; } } + else if (ProductionAdapter.isError(prod)) { + var eprod = ProductionAdapter.getErrorProd(prod); + int dot = ProductionAdapter.getErrorDot(prod); + int index = SymbolAdapter.indexOfLabel(ProductionAdapter.getSymbols(eprod), field); + IList args = getArgs(tree); + + if (index != -1) { + if (index < dot) { + // changing the normal part of the tree + return setArgs(tree, args.put(index, repl)); + } + else if (index == dot) { + // extending the accepted part of the tree by one field + eprod = prod.set("prod", IRascalValueFactory.getInstance().integer(dot + 1)); + return setProduction(setArgs(tree, args.append(repl)), eprod); + } + + // otherwise we return null which indicates the field does not exist. + } + } } return null; From 6050c36f1593bb870eb69fea5ea57b56a7e53a17 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Wed, 13 Nov 2024 10:53:59 +0100 Subject: [PATCH 3/5] removed experiment of building error trees on the fly if they are not there --- .../values/parsetrees/TreeAdapter.java | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/org/rascalmpl/values/parsetrees/TreeAdapter.java b/src/org/rascalmpl/values/parsetrees/TreeAdapter.java index 5ebdba4f39..2bf2c46859 100644 --- a/src/org/rascalmpl/values/parsetrees/TreeAdapter.java +++ b/src/org/rascalmpl/values/parsetrees/TreeAdapter.java @@ -210,8 +210,10 @@ else if (index == dot) { eprod = prod.set("prod", IRascalValueFactory.getInstance().integer(dot + 1)); return setProduction(setArgs(tree, args.append(repl)), eprod); } - - // otherwise we return null which indicates the field does not exist. + else { + // otherwise we return null which indicates the field does not exist. + return null; + } } } } @@ -306,22 +308,8 @@ else if (ProductionAdapter.isError(prod)) { return new FieldResult(sym, (ITree) tree.getArgs().get(index)); } else { - // We have the right prodction and the field would be there, if we didn't recover from a parse error - // and are missing some of the children (including the indicated field). - // So we return a quasi tree that is of the right type, but it otherwise just an error tree - // like its parent. This tree does not have content, because we wouldn't know which of the skipped - // parts are meant. - var vf = IRascalValueFactory.getInstance(); - // @PieterOlivier is this the right way to do this? I just need an empty tree of the right symbol. - var skipped = vf.constructor(RascalValueFactory.Production_Skipped); - var skippedProd = vf.constructor(RascalValueFactory.Production_Error, sym, skipped, vf.integer(0)); - var skippedTree = vf.appl(skippedProd); - var parentLoc = getLocation(tree); - if (parentLoc != null) { - // TODO @PieterOlivier I guess we need the location of the last parsed element, and use an - // empty range that is just beyond that. But for now I'd like to test with this. - } - return new FieldResult(sym, skippedTree); + // we simply don't have that field yet. too bad. + return null; } } } From 7774c359d5385892390a514e8bbd1321c3a859e5 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Wed, 13 Nov 2024 10:56:42 +0100 Subject: [PATCH 4/5] made has operator robust before the dot --- .../interpreter/result/ConcreteSyntaxResult.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/org/rascalmpl/interpreter/result/ConcreteSyntaxResult.java b/src/org/rascalmpl/interpreter/result/ConcreteSyntaxResult.java index dc2d0bd7bc..135d5b5f55 100644 --- a/src/org/rascalmpl/interpreter/result/ConcreteSyntaxResult.java +++ b/src/org/rascalmpl/interpreter/result/ConcreteSyntaxResult.java @@ -145,6 +145,22 @@ public Result has(Name name) { } } } + else if (ProductionAdapter.isError(prod)) { + var eprod = ProductionAdapter.getErrorProd(prod); + int dot = ProductionAdapter.getErrorDot(prod); + IList syms = ProductionAdapter.getSymbols(eprod); + String tmp = Names.name(name); + + // only look before the dot. + for (int i = 0; i < dot; i++) { + var sym = syms.get(i); + if (SymbolAdapter.isLabel((IConstructor) sym)) { + if (SymbolAdapter.getLabel((IConstructor) sym).equals(tmp)) { + return ResultFactory.bool(true, ctx); + } + } + } + } } return super.has(name); } From e964a650db84b8c4f37cf5f8059b52ca7546f973 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Wed, 13 Nov 2024 10:59:48 +0100 Subject: [PATCH 5/5] returns "recovered" for getConstructor name on error productions such that "is" operator and others work on error trees. This does reserve the constructor name "recovered" for use in error versions.. --- .../interpreter/result/ConcreteSyntaxResult.java | 1 + .../values/parsetrees/ProductionAdapter.java | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/org/rascalmpl/interpreter/result/ConcreteSyntaxResult.java b/src/org/rascalmpl/interpreter/result/ConcreteSyntaxResult.java index 135d5b5f55..8eaf7ff721 100644 --- a/src/org/rascalmpl/interpreter/result/ConcreteSyntaxResult.java +++ b/src/org/rascalmpl/interpreter/result/ConcreteSyntaxResult.java @@ -55,6 +55,7 @@ public Result is(Name name) { return ResultFactory.bool(Names.name(name).equals(consName), ctx); } } + return ResultFactory.bool(false, ctx); } diff --git a/src/org/rascalmpl/values/parsetrees/ProductionAdapter.java b/src/org/rascalmpl/values/parsetrees/ProductionAdapter.java index 23312c01c0..d66d2027a0 100644 --- a/src/org/rascalmpl/values/parsetrees/ProductionAdapter.java +++ b/src/org/rascalmpl/values/parsetrees/ProductionAdapter.java @@ -38,10 +38,15 @@ private ProductionAdapter() { * @return a constructor name if present or null otherwise */ public static String getConstructorName(IConstructor tree) { - IConstructor def = getDefined(tree); + if (isDefault(tree)) { + IConstructor def = getDefined(tree); - if (SymbolAdapter.isLabel(def)) { - return SymbolAdapter.getLabel(def); + if (SymbolAdapter.isLabel(def)) { + return SymbolAdapter.getLabel(def); + } + } + else if (isError(tree)) { + return "recovered"; } return null;