Skip to content

Commit ca27c3f

Browse files
committed
Raise IndentationError for mismatched dedent
1 parent 6cd19c0 commit ca27c3f

File tree

5 files changed

+70
-21
lines changed

5 files changed

+70
-21
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
*/
2626
package com.oracle.graal.python.builtins;
2727

28+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.IndentationError;
29+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TabError;
2830
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__PACKAGE__;
2931
import static com.oracle.graal.python.runtime.exception.PythonErrorType.SyntaxError;
3032

@@ -168,6 +170,7 @@
168170
import com.oracle.graal.python.builtins.objects.thread.ThreadBuiltins;
169171
import com.oracle.graal.python.builtins.objects.traceback.TracebackBuiltins;
170172
import com.oracle.graal.python.builtins.objects.tuple.TupleBuiltins;
173+
import com.oracle.graal.python.builtins.objects.type.LazyPythonClass;
171174
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
172175
import com.oracle.graal.python.builtins.objects.type.TypeBuiltins;
173176
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetNameNode;
@@ -725,22 +728,34 @@ public PFloat getNaN() {
725728
}
726729

727730
@Override
728-
public RuntimeException raiseInvalidSyntax(Source source, SourceSection section, String message, Object... arguments) {
731+
public RuntimeException raiseInvalidSyntax(PythonParser.ErrorType type, Source source, SourceSection section, String message, Object... arguments) {
729732
CompilerDirectives.transferToInterpreter();
730733
Node location = new Node() {
731734
@Override
732735
public SourceSection getSourceSection() {
733736
return section;
734737
}
735738
};
736-
throw raiseInvalidSyntax(location, message, arguments);
739+
throw raiseInvalidSyntax(type, location, message, arguments);
737740
}
738741

739742
@Override
740743
@TruffleBoundary
741-
public RuntimeException raiseInvalidSyntax(Node location, String message, Object... arguments) {
744+
public RuntimeException raiseInvalidSyntax(PythonParser.ErrorType type, Node location, String message, Object... arguments) {
742745
PBaseException instance;
743-
instance = factory().createBaseException(SyntaxError, message, arguments);
746+
LazyPythonClass cls;
747+
switch (type) {
748+
case Indentation:
749+
cls = IndentationError;
750+
break;
751+
case Tab:
752+
cls = TabError;
753+
break;
754+
default:
755+
cls = SyntaxError;
756+
break;
757+
}
758+
instance = factory().createBaseException(cls, message, arguments);
744759
SourceSection section = location.getSourceSection();
745760
Source source = section.getSource();
746761
String path = source.getPath();

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/parser/PythonErrorStrategy.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
import org.antlr.v4.runtime.TokenStream;
5050
import org.antlr.v4.runtime.misc.Interval;
5151

52+
import com.oracle.graal.python.parser.antlr.DescriptiveBailErrorListener;
53+
import com.oracle.graal.python.runtime.PythonParser.ErrorType;
5254
import com.oracle.truffle.api.source.Source;
5355
import com.oracle.truffle.api.source.SourceSection;
5456

@@ -76,6 +78,13 @@ static SourceSection getPosition(Source source, Exception e) {
7678
return source.createSection(token.getStartIndex(), Math.max(0, token.getStopIndex() - token.getStartIndex()));
7779
}
7880

81+
static ErrorType getErrorType(Exception e) {
82+
if (e instanceof DescriptiveBailErrorListener.EmptyRecognitionException) {
83+
return ((DescriptiveBailErrorListener.EmptyRecognitionException) e).getErrorType();
84+
}
85+
return ErrorType.Generic;
86+
}
87+
7988
private static String getTokeLineText(Parser recognizer, Token token) {
8089
TokenStream tokenStream = recognizer.getTokenStream();
8190
int index = token.getTokenIndex();

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/parser/PythonParserImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ private static PException handleParserError(ParserErrorCallback errors, Source s
370370
SourceSection section = PythonErrorStrategy.getPosition(source, e);
371371
// from parser we are getting RuntimeExceptions
372372
String message = e instanceof RuntimeException && e.getMessage() != null ? e.getMessage() : "invalid syntax";
373-
throw errors.raiseInvalidSyntax(source, section, message);
373+
ErrorType errorType = PythonErrorStrategy.getErrorType(e);
374+
throw errors.raiseInvalidSyntax(errorType, source, section, message);
374375
}
375376
}

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

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import org.antlr.v4.runtime.misc.IntervalSet;
5151

5252
import com.oracle.graal.python.parser.antlr.Python3Parser.Single_inputContext;
53+
import com.oracle.graal.python.runtime.PythonParser.ErrorType;
5354
import com.oracle.graal.python.runtime.PythonParser.PIncompleteSourceException;
5455
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
5556

@@ -67,25 +68,28 @@ public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol,
6768

6869
String entireMessage = e == null || e.getMessage() == null ? "invalid syntax" : e.getMessage();
6970

70-
if (e != null) {
71-
PIncompleteSourceException handleRecognitionException = handleRecognitionException(e.getExpectedTokens(), entireMessage, e, line);
72-
if (handleRecognitionException != null) {
73-
throw handleRecognitionException;
71+
if (isInteractive(recognizer)) {
72+
PIncompleteSourceException handleRecognitionException = null;
73+
if (e != null) {
74+
handleRecognitionException = handleRecognitionException(e.getExpectedTokens(), entireMessage, e, line);
75+
} else if (recognizer instanceof Python3Parser) {
76+
handleRecognitionException = handleRecognitionException(((Python3Parser) recognizer).getExpectedTokens(), entireMessage, null, line);
7477
}
75-
} else if (recognizer instanceof Python3Parser) {
76-
PIncompleteSourceException handleRecognitionException = handleRecognitionException(((Python3Parser) recognizer).getExpectedTokens(), entireMessage, null, line);
77-
if (handleRecognitionException != null) {
78-
throw handleRecognitionException;
78+
if (handleRecognitionException == null) {
79+
handleRecognitionException = handleInteractiveException(recognizer, offendingSymbol);
7980
}
80-
}
81-
if (isInteractive(recognizer)) {
82-
PIncompleteSourceException handleRecognitionException = handleInteractiveException(recognizer, offendingSymbol);
8381
if (handleRecognitionException != null) {
8482
throw handleRecognitionException;
8583
}
8684
}
8785
if (offendingSymbol instanceof Token) {
88-
throw new RuntimeException(entireMessage, new EmptyRecognitionException(entireMessage, recognizer, (Token) offendingSymbol));
86+
Token token = (Token) offendingSymbol;
87+
ErrorType errorType = ErrorType.Generic;
88+
if (token.getType() == Python3Parser.INDENT_ERROR) {
89+
entireMessage = "unindent does not match any outer indentation level";
90+
errorType = ErrorType.Indentation;
91+
}
92+
throw new EmptyRecognitionException(errorType, entireMessage, recognizer, token);
8993
}
9094
throw new RuntimeException(entireMessage, e);
9195
}
@@ -143,18 +147,24 @@ private static boolean isBackslash(Object offendingSymbol) {
143147
return false;
144148
}
145149

146-
private static class EmptyRecognitionException extends RecognitionException {
150+
public static class EmptyRecognitionException extends RecognitionException {
147151
private static final long serialVersionUID = 1L;
148152
private Token offendingToken;
153+
private ErrorType errorType;
149154

150-
public EmptyRecognitionException(String message, Recognizer<?, ?> recognizer, Token offendingToken) {
155+
public EmptyRecognitionException(ErrorType errorType, String message, Recognizer<?, ?> recognizer, Token offendingToken) {
151156
super(message, recognizer, offendingToken.getInputStream(), null);
157+
this.errorType = errorType;
152158
this.offendingToken = offendingToken;
153159
}
154160

155161
@Override
156162
public Token getOffendingToken() {
157163
return offendingToken;
158164
}
165+
166+
public ErrorType getErrorType() {
167+
return errorType;
168+
}
159169
}
160170
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonParser.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,26 @@ public enum ParserMode {
7575
Deserialization;
7676
}
7777

78+
enum ErrorType {
79+
Generic,
80+
Indentation,
81+
Tab
82+
}
83+
7884
public interface ParserErrorCallback {
7985
RuntimeException raise(PythonBuiltinClassType type, String message, Object... args);
8086

81-
RuntimeException raiseInvalidSyntax(Source source, SourceSection section, String message, Object... arguments);
87+
default RuntimeException raiseInvalidSyntax(Source source, SourceSection section, String message, Object... arguments) {
88+
return raiseInvalidSyntax(ErrorType.Generic, source, section, message, arguments);
89+
}
90+
91+
RuntimeException raiseInvalidSyntax(ErrorType type, Source source, SourceSection section, String message, Object... arguments);
92+
93+
default RuntimeException raiseInvalidSyntax(Node location, String message, Object... arguments) {
94+
return raiseInvalidSyntax(ErrorType.Generic, location, message, arguments);
95+
}
8296

83-
RuntimeException raiseInvalidSyntax(Node location, String message, Object... arguments);
97+
RuntimeException raiseInvalidSyntax(ErrorType type, Node location, String message, Object... arguments);
8498

8599
default RuntimeException raiseInvalidSyntax(Source source, SourceSection section) {
86100
return raiseInvalidSyntax(source, section, ErrorMessages.INVALID_SYNTAX, new Object[0]);

0 commit comments

Comments
 (0)