Skip to content

Commit 78786c7

Browse files
committed
Fix interactive multi-line continuation
1 parent bc647d0 commit 78786c7

File tree

3 files changed

+52
-1
lines changed

3 files changed

+52
-1
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/parser/antlr/DescriptiveBailErrorListener.java

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -41,11 +41,14 @@
4141
package com.oracle.graal.python.parser.antlr;
4242

4343
import org.antlr.v4.runtime.BaseErrorListener;
44+
import org.antlr.v4.runtime.ParserRuleContext;
4445
import org.antlr.v4.runtime.RecognitionException;
4546
import org.antlr.v4.runtime.Recognizer;
4647
import org.antlr.v4.runtime.Token;
48+
import org.antlr.v4.runtime.TokenStream;
4749
import org.antlr.v4.runtime.misc.IntervalSet;
4850

51+
import com.oracle.graal.python.parser.antlr.Python3Parser.Single_inputContext;
4952
import com.oracle.graal.python.runtime.PythonParser.PIncompleteSourceException;
5053
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
5154

@@ -74,6 +77,12 @@ public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol,
7477
throw handleRecognitionException;
7578
}
7679
}
80+
if (isInteractive(recognizer)) {
81+
PIncompleteSourceException handleRecognitionException = handleInteractiveException(recognizer);
82+
if (handleRecognitionException != null) {
83+
throw handleRecognitionException;
84+
}
85+
}
7786
if (offendingSymbol instanceof Token) {
7887
throw new RuntimeException(entireMessage, new EmptyRecognitionException(entireMessage, recognizer, (Token) offendingSymbol));
7988
}
@@ -87,6 +96,40 @@ private static PIncompleteSourceException handleRecognitionException(IntervalSet
8796
return null;
8897
}
8998

99+
private static PIncompleteSourceException handleInteractiveException(Recognizer<?, ?> recognizer) {
100+
if (isOpened(((Python3Parser) recognizer).getTokenStream())) {
101+
return new PIncompleteSourceException("", null, -1);
102+
}
103+
return null;
104+
}
105+
106+
private static ParserRuleContext getRootCtx(ParserRuleContext ctx) {
107+
ParserRuleContext c = ctx;
108+
while (c.getParent() != null) {
109+
c = c.getParent();
110+
}
111+
return c;
112+
}
113+
114+
private static boolean isInteractive(Recognizer<?, ?> recognizer) {
115+
if (!(recognizer instanceof Python3Parser)) {
116+
return false;
117+
}
118+
ParserRuleContext ctx = getRootCtx(((Python3Parser) recognizer).getContext());
119+
if (ctx instanceof Single_inputContext) {
120+
return ((Single_inputContext) ctx).interactive;
121+
}
122+
return false;
123+
}
124+
125+
/**
126+
* @return true if there are an open '(', '[' or '{'.
127+
*/
128+
private static boolean isOpened(TokenStream input) {
129+
final Python3Lexer lexer = (Python3Lexer) input.getTokenSource();
130+
return lexer.isOpened();
131+
}
132+
90133
private static class EmptyRecognitionException extends RecognitionException {
91134
private static final long serialVersionUID = 1L;
92135
private Token offendingToken;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/parser/antlr/Python3.g4

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ tokens { INDENT, DEDENT }
9292
return tokens.isEmpty() ? next : tokens.poll();
9393
}
9494

95+
public boolean isOpened() {
96+
return opened > 0;
97+
}
98+
9599
private Token createDedent() {
96100
CommonToken dedent = commonToken(Python3Parser.DEDENT, "");
97101
dedent.setLine(this.lastToken.getLine());

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/parser/antlr/Python3Lexer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ public Token nextToken() {
219219
return tokens.isEmpty() ? next : tokens.poll();
220220
}
221221

222+
public boolean isOpened() {
223+
return opened > 0;
224+
}
225+
222226
private Token createDedent() {
223227
CommonToken dedent = commonToken(Python3Parser.DEDENT, "");
224228
dedent.setLine(this.lastToken.getLine());

0 commit comments

Comments
 (0)