Skip to content

Commit 1231dba

Browse files
committed
Improve parser error handling
1 parent 6808d5f commit 1231dba

File tree

3 files changed

+74
-46
lines changed

3 files changed

+74
-46
lines changed

convex-core/src/main/antlr4/convex/core/lang/reader/antlr/Convex.g4

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ primary
2020
| resolve
2121
| atom
2222
;
23-
24-
2523

2624
singleForm: form EOF;
2725

convex-core/src/main/java/convex/core/lang/reader/AntlrReader.java

Lines changed: 73 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88
import org.antlr.v4.runtime.CommonTokenStream;
99
import org.antlr.v4.runtime.Lexer;
1010
import org.antlr.v4.runtime.ParserRuleContext;
11+
import org.antlr.v4.runtime.TokenStream;
1112
import org.antlr.v4.runtime.atn.PredictionMode;
1213
import org.antlr.v4.runtime.tree.ErrorNode;
1314
import org.antlr.v4.runtime.tree.ParseTree;
14-
import org.antlr.v4.runtime.tree.ParseTreeWalker;
15+
import org.antlr.v4.runtime.tree.ParseTreeListener;
1516
import org.antlr.v4.runtime.tree.TerminalNode;
1617

1718
import convex.core.data.ACell;
@@ -140,8 +141,7 @@ public void exitForm(FormContext ctx) {
140141

141142
@Override
142143
public void enterForms(FormsContext ctx) {
143-
// We add a new ArrayList to the stack to capture values
144-
pushList();
144+
// Nothing to do
145145
}
146146

147147
@Override
@@ -161,7 +161,7 @@ public void exitDataStructure(DataStructureContext ctx) {
161161

162162
@Override
163163
public void enterList(ListContext ctx) {
164-
// Nothing to do
164+
pushList(); // We add a new ArrayList to the stack to capture values
165165
}
166166

167167
@Override
@@ -172,7 +172,7 @@ public void exitList(ListContext ctx) {
172172

173173
@Override
174174
public void enterVector(VectorContext ctx) {
175-
// Nothing to do
175+
pushList(); // We add a new ArrayList to the stack to capture values
176176
}
177177

178178
@Override
@@ -183,7 +183,7 @@ public void exitVector(VectorContext ctx) {
183183

184184
@Override
185185
public void enterSet(SetContext ctx) {
186-
// Nothing to do
186+
pushList(); // We add a new ArrayList to the stack to capture values
187187
}
188188

189189
@Override
@@ -194,7 +194,7 @@ public void exitSet(SetContext ctx) {
194194

195195
@Override
196196
public void enterMap(MapContext ctx) {
197-
// Nothing to do
197+
pushList(); // We add a new ArrayList to the stack to capture values
198198
}
199199

200200
@Override
@@ -237,7 +237,7 @@ public void enterDoubleValue(DoubleValueContext ctx) {
237237

238238
@Override
239239
public void exitDoubleValue(DoubleValueContext ctx) {
240-
String s=ctx.getText();
240+
String s=ctx.getStop().getText();
241241
CVMDouble v=CVMDouble.parse(s);
242242
if (v==null) throw new ParseException("Bad double format: "+s);
243243
push(v);
@@ -457,7 +457,7 @@ public void enterSpecialLiteral(SpecialLiteralContext ctx) {
457457

458458
@Override
459459
public void exitSpecialLiteral(SpecialLiteralContext ctx) {
460-
String s=ctx.getText();
460+
String s=ctx.getStop().getText();
461461
ACell special=ReaderUtils.specialLiteral(s);
462462
if (special==null) throw new ParseException("Invalid special literal: "+s);
463463
push(special);
@@ -511,8 +511,8 @@ public void exitSingleForm(SingleFormContext ctx) {
511511

512512
@Override
513513
public void enterAllForms(AllFormsContext ctx) {
514-
// Nothing
515-
514+
// Add a new list to stack to capture all forms. readAll() will pop this
515+
pushList();
516516
}
517517

518518
@Override
@@ -540,9 +540,6 @@ public void enterPrimary(PrimaryContext ctx) {
540540
public void exitPrimary(PrimaryContext ctx) {
541541
// Nothing
542542
}
543-
544-
545-
546543
}
547544

548545
public static ACell read(String s) {
@@ -555,47 +552,79 @@ public static ACell read(java.io.Reader r) throws IOException {
555552

556553
private static final ConvexErrorListener ERROR_LISTENER=new ConvexErrorListener();
557554

558-
static ACell read(CharStream cs) {
559-
try {
560-
ConvexLexer lexer=new ConvexLexer(cs);
561-
lexer.removeErrorListeners();
562-
lexer.addErrorListener(ERROR_LISTENER);
563-
CommonTokenStream tokens = new CommonTokenStream(lexer);
564-
ConvexParser parser = new ConvexParser(tokens);
565-
566-
// We don't need a parse tree, just want to visit everything in our listener
567-
parser.setBuildParseTree(false);
568-
parser.removeErrorListeners();
569-
parser.getInterpreter().setPredictionMode(PredictionMode.SLL); // Seems OK for our grammar?
570-
parser.addErrorListener(ERROR_LISTENER);
571-
CRListener visitor=new CRListener();
572-
parser.addParseListener(visitor);
573-
574-
parser.singleForm();
575-
// ParseTreeWalker.DEFAULT.walk(visitor, tree);
576-
577-
ArrayList<ACell> top=visitor.popList();
578-
if (top.size()!=1) {
579-
throw new ParseException("Bad parse output: "+top);
555+
// Recommended in https://github.com/antlr/antlr4/blob/dev/doc/listeners.md
556+
static class CatchingParser extends ConvexParser {
557+
protected boolean listenerExceptionOccurred = false;
558+
public CatchingParser(TokenStream input) {
559+
super(input);
560+
}
561+
562+
@Override
563+
protected void triggerExitRuleEvent() {
564+
if ( listenerExceptionOccurred ) return;
565+
try {
566+
// reverse order walk of listeners
567+
for (int i = _parseListeners.size() - 1; i >= 0; i--) {
568+
ParseTreeListener listener = _parseListeners.get(i);
569+
_ctx.exitRule(listener);
570+
listener.exitEveryRule(_ctx);
571+
}
580572
}
581-
582-
return top.get(0);
583-
} catch (Exception e) {
584-
throw new ParseException("Unexpected Parse Error",e);
573+
catch (ParseException e) {
574+
// If an exception is thrown in the user's listener code, we need to bail out
575+
// completely out of the parser, without executing anymore user code. We
576+
// must also stop the parse otherwise other listener actions will attempt to execute
577+
// almost certainly with invalid results. So, record the fact an exception occurred
578+
listenerExceptionOccurred = true;
579+
throw e;
580+
}
581+
}
582+
583+
}
584+
585+
static ConvexParser getParser(CharStream cs, CRListener listener) {
586+
// Create lexer and paser for the CharStream
587+
ConvexLexer lexer=new ConvexLexer(cs);
588+
lexer.removeErrorListeners();
589+
lexer.addErrorListener(ERROR_LISTENER);
590+
CommonTokenStream tokens = new CommonTokenStream(lexer);
591+
ConvexParser parser = new CatchingParser(tokens);
592+
593+
// We don't need a parse tree, just want to visit everything in our listener
594+
parser.setBuildParseTree(false);
595+
parser.removeErrorListeners();
596+
parser.getInterpreter().setPredictionMode(PredictionMode.SLL); // Seems OK for our grammar?
597+
parser.addErrorListener(ERROR_LISTENER);
598+
599+
parser.addParseListener(listener);
600+
return parser;
601+
}
602+
603+
static ACell read(CharStream cs) {
604+
CRListener listener=new CRListener();
605+
ConvexParser parser=getParser(cs,listener);
606+
607+
parser.singleForm();
608+
609+
ArrayList<ACell> top=listener.popList();
610+
if (top.size()!=1) {
611+
throw new ParseException("Bad parse output: "+top);
585612
}
613+
614+
return top.get(0);
586615
}
587616

588617
public static AList<ACell> readAll(String source) {
589618
return readAll(CharStreams.fromString(source));
590619
}
591620

592621
static AList<ACell> readAll(CharStream cs) {
593-
ParseTree tree = getParseTree(cs);
622+
CRListener listener=new CRListener();
623+
ConvexParser parser=getParser(cs,listener);
594624

595-
CRListener visitor=new CRListener();
596-
ParseTreeWalker.DEFAULT.walk(visitor, tree);
625+
parser.allForms();
597626

598-
ArrayList<ACell> top=visitor.popList();
627+
ArrayList<ACell> top=listener.popList();
599628
return Lists.create(top);
600629
}
601630

convex-core/src/test/java/convex/core/lang/ReaderTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ public void testMaps() {
278278

279279
@Test
280280
public void testMapError() {
281+
assertParseException(()->Reader.read("{1}"));
281282
assertParseException(()->Reader.read("{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}"));
282283
}
283284

0 commit comments

Comments
 (0)