Skip to content

Commit 346f0b4

Browse files
committed
[GR-23325] make test_print pass
PullRequest: graalpython/1393
2 parents fb40069 + 2b00a2b commit 346f0b4

File tree

10 files changed

+81
-37
lines changed

10 files changed

+81
-37
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
*graalpython.lib-python.3.test.test_print.TestPrint.test_print
22
*graalpython.lib-python.3.test.test_print.TestPrint.test_print_flush
33
*graalpython.lib-python.3.test.test_print.TestPy2MigrationHint.test_normal_string
4+
*graalpython.lib-python.3.test.test_print.TestPy2MigrationHint.test_stream_redirection_hint_for_py2_migration
5+
*graalpython.lib-python.3.test.test_print.TestPy2MigrationHint.test_string_in_loop_on_same_line
46
*graalpython.lib-python.3.test.test_print.TestPy2MigrationHint.test_string_with_excessive_whitespace
7+
*graalpython.lib-python.3.test.test_print.TestPy2MigrationHint.test_string_with_leading_whitespace
58
*graalpython.lib-python.3.test.test_print.TestPy2MigrationHint.test_string_with_semicolon
69
*graalpython.lib-python.3.test.test_print.TestPy2MigrationHint.test_string_with_soft_space

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

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.IndentationError;
2929
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TabError;
30+
import static com.oracle.graal.python.nodes.BuiltinNames.PRINT;
3031
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__PACKAGE__;
3132
import static com.oracle.graal.python.runtime.exception.PythonErrorType.SyntaxError;
3233

@@ -796,29 +797,25 @@ public RuntimeException raiseInvalidSyntax(PythonParser.ErrorType type, Node loc
796797
instance.setAttribute("text", section.isAvailable() ? source.getCharacters(section.getStartLine()) : PNone.NONE);
797798
instance.setAttribute("lineno", section.getStartLine());
798799
instance.setAttribute("offset", section.getStartColumn());
799-
String msg;
800-
if (section.getCharIndex() == source.getLength()) {
801-
msg = "unexpected EOF while parsing";
802-
} else if (message != null) {
803-
msg = (new ErrorMessageFormatter()).format(message, arguments);
804-
} else {
805-
msg = "invalid syntax";
806-
}
807-
if (section.isAvailable() && type == PythonParser.ErrorType.Generic) {
808-
Matcher matcher = MISSING_PARENTHESES_PATTERN.matcher(source.getCharacters(section.getStartLine()));
800+
String msg = "invalid syntax";
801+
if (type == PythonParser.ErrorType.Print) {
802+
CharSequence line = source.getCharacters(section.getStartLine());
803+
line = line.subSequence(line.toString().lastIndexOf(PRINT), line.length());
804+
Matcher matcher = MISSING_PARENTHESES_PATTERN.matcher(line);
809805
if (matcher.matches()) {
810-
String fn = matcher.group(1);
811-
if (fn.equals("print")) {
812-
String arg = matcher.group(2).trim();
813-
String maybeEnd = "";
814-
if (arg.endsWith(",")) {
815-
maybeEnd = " end=\" \"";
816-
}
817-
msg = (new ErrorMessageFormatter()).format("Missing parentheses in call to 'print'. Did you mean print(%s%s)?", arg, maybeEnd);
818-
} else {
819-
msg = "Missing parentheses in call to 'exec'";
806+
String arg = matcher.group(2).trim();
807+
String maybeEnd = "";
808+
if (arg.endsWith(",")) {
809+
maybeEnd = " end=\" \"";
820810
}
811+
msg = (new ErrorMessageFormatter()).format("Missing parentheses in call to 'print'. Did you mean print(%s%s)?", arg, maybeEnd);
821812
}
813+
} else if (type == PythonParser.ErrorType.Exec) {
814+
msg = "Missing parentheses in call to 'exec'";
815+
} else if (section.getCharIndex() == source.getLength()) {
816+
msg = "unexpected EOF while parsing";
817+
} else if (message != null) {
818+
msg = (new ErrorMessageFormatter()).format(message, arguments);
822819
}
823820
instance.setAttribute("msg", msg);
824821
throw PException.fromObject(instance, location, PythonOptions.isPExceptionWithJavaStacktrace(getLanguage()));

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/PBaseException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ public String getFormattedMessage(PythonObjectLibrary lib) {
226226
@Override
227227
public String toString() {
228228
CompilerAsserts.neverPartOfCompilation();
229-
return getFormattedMessage(null);
229+
return getFormattedMessage(PythonObjectLibrary.getUncached());
230230
}
231231

232232
public LazyTraceback internalReifyException(PFrame.Reference curFrameInfo) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,7 @@ public abstract class ErrorMessages {
570570
public static final String UNSUPPORTED_OBJ_IN = "unsupported object in '%s'";
571571
public static final String UNSUPPORTED_OPERAND_P = "unsupported operand '%p'";
572572
public static final String UNSUPPORTED_OPERAND_TYPES_FOR_S_P_AND_P = "unsupported operand type(s) for %s: '%p' and '%p'";
573+
public static final String UNSUPPORTED_OPERAND_TYPES_FOR_S_P_AND_P_PRINT = UNSUPPORTED_OPERAND_TYPES_FOR_S_P_AND_P + ". Did you mean \"print(<message>, file=<output_stream>)\"?";
573574
public static final String UNSUPPORTED_OPERAND_TYPES_FOR_S_P_P_P = "unsupported operand type(s) for %s(): '%p', '%p', '%p'";
574575
public static final String UNSUPPORTED_OPERAND_TYPES_FOR_S_PR_S_P_AND_P = "unsupported operand type(s) for %s or %s(): '%p' and '%p'";
575576
public static final String UNSUPPORTED_SIZE_WAS = "unsupported %s size; was: %d";

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/expression/BinaryArithmetic.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,13 @@
4040
*/
4141
package com.oracle.graal.python.nodes.expression;
4242

43+
import static com.oracle.graal.python.nodes.BuiltinNames.PRINT;
4344
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
4445

4546
import com.oracle.graal.python.PythonLanguage;
4647
import com.oracle.graal.python.builtins.objects.function.PArguments;
4748
import com.oracle.graal.python.builtins.objects.function.Signature;
49+
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
4850
import com.oracle.graal.python.nodes.ErrorMessages;
4951
import com.oracle.graal.python.nodes.PRaiseNode;
5052
import com.oracle.graal.python.nodes.SpecialMethodNames;
@@ -87,7 +89,7 @@ public enum BinaryArithmetic {
8789
this.notImplementedHandler = () -> new NotImplementedHandler() {
8890
@Override
8991
public Object execute(VirtualFrame frame, Object arg, Object arg2) {
90-
throw PRaiseNode.getUncached().raise(TypeError, ErrorMessages.UNSUPPORTED_OPERAND_TYPES_FOR_S_P_AND_P, operator, arg, arg2);
92+
throw PRaiseNode.getUncached().raise(TypeError, getErrorMessage(operator, arg), operator, arg, arg2);
9193
}
9294
};
9395
}
@@ -100,6 +102,14 @@ public String getOperator() {
100102
return operator;
101103
}
102104

105+
@CompilerDirectives.TruffleBoundary
106+
private static String getErrorMessage(String operator, Object arg) {
107+
if (operator.equals(">>") && arg instanceof PBuiltinMethod && ((PBuiltinMethod) arg).getFunction().getName().equals(PRINT)) {
108+
return ErrorMessages.UNSUPPORTED_OPERAND_TYPES_FOR_S_P_AND_P_PRINT;
109+
}
110+
return ErrorMessages.UNSUPPORTED_OPERAND_TYPES_FOR_S_P_AND_P;
111+
}
112+
103113
/**
104114
* A helper root node that dispatches to {@link LookupAndCallBinaryNode} to execute the provided
105115
* binary operator. This node is mostly useful to use such operators from a location without a

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
*/
4141
package com.oracle.graal.python.parser;
4242

43+
import static com.oracle.graal.python.nodes.BuiltinNames.EXEC;
44+
import static com.oracle.graal.python.nodes.BuiltinNames.PRINT;
45+
4346
import org.antlr.v4.runtime.DefaultErrorStrategy;
4447
import org.antlr.v4.runtime.InputMismatchException;
4548
import org.antlr.v4.runtime.NoViableAltException;
@@ -78,9 +81,22 @@ static SourceSection getPosition(Source source, Exception e) {
7881
return source.createSection(token.getStartIndex(), Math.max(0, token.getStopIndex() - token.getStartIndex()));
7982
}
8083

81-
static ErrorType getErrorType(Exception e) {
84+
static ErrorType getErrorType(Exception e, SourceSection section) {
8285
if (e instanceof DescriptiveBailErrorListener.EmptyRecognitionException) {
83-
return ((DescriptiveBailErrorListener.EmptyRecognitionException) e).getErrorType();
86+
DescriptiveBailErrorListener.EmptyRecognitionException except = ((DescriptiveBailErrorListener.EmptyRecognitionException) e);
87+
ErrorType type = except.getErrorType();
88+
if (section.isAvailable() && type == ErrorType.Generic) {
89+
String prev = except.getPreviousToken();
90+
if (prev != null) {
91+
if (prev.equals(PRINT)) {
92+
return ErrorType.Print;
93+
}
94+
if (prev.equals(EXEC)) {
95+
return ErrorType.Exec;
96+
}
97+
}
98+
}
99+
return type;
84100
}
85101
return ErrorType.Generic;
86102
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@
3333
import java.util.regex.Matcher;
3434
import java.util.regex.Pattern;
3535

36-
import com.oracle.truffle.api.CompilerDirectives;
37-
import com.oracle.truffle.api.interop.ExceptionType;
38-
import com.oracle.truffle.api.interop.InteropLibrary;
39-
import com.oracle.truffle.api.interop.UnsupportedMessageException;
4036
import org.antlr.v4.runtime.CharStreams;
4137
import org.antlr.v4.runtime.CommonTokenStream;
4238
import org.antlr.v4.runtime.Token;
@@ -67,10 +63,14 @@
6763
import com.oracle.graal.python.runtime.PythonOptions;
6864
import com.oracle.graal.python.runtime.PythonParser;
6965
import com.oracle.graal.python.runtime.exception.PException;
66+
import com.oracle.truffle.api.CompilerDirectives;
7067
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
7168
import com.oracle.truffle.api.TruffleLanguage.Env;
7269
import com.oracle.truffle.api.frame.Frame;
7370
import com.oracle.truffle.api.frame.FrameDescriptor;
71+
import com.oracle.truffle.api.interop.ExceptionType;
72+
import com.oracle.truffle.api.interop.InteropLibrary;
73+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
7474
import com.oracle.truffle.api.nodes.Node;
7575
import com.oracle.truffle.api.nodes.RootNode;
7676
import com.oracle.truffle.api.source.Source;
@@ -408,7 +408,7 @@ private static PException handleParserError(ParserErrorCallback errors, Source s
408408
SourceSection section = PythonErrorStrategy.getPosition(source, e);
409409
// from parser we are getting RuntimeExceptions
410410
String message = e instanceof RuntimeException && e.getMessage() != null ? e.getMessage() : "invalid syntax";
411-
ErrorType errorType = PythonErrorStrategy.getErrorType(e);
411+
ErrorType errorType = PythonErrorStrategy.getErrorType(e, section);
412412
throw errors.raiseInvalidSyntax(errorType, source, section, message);
413413
}
414414
}

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
import org.antlr.v4.runtime.BaseErrorListener;
4444
import org.antlr.v4.runtime.CharStream;
45+
import org.antlr.v4.runtime.CommonTokenStream;
4546
import org.antlr.v4.runtime.ParserRuleContext;
4647
import org.antlr.v4.runtime.RecognitionException;
4748
import org.antlr.v4.runtime.Recognizer;
@@ -192,13 +193,30 @@ private static boolean isBackslash(Object offendingSymbol) {
192193

193194
public static class EmptyRecognitionException extends RecognitionException {
194195
private static final long serialVersionUID = 1L;
195-
private Token offendingToken;
196-
private ErrorType errorType;
196+
private final Token offendingToken;
197+
private final ErrorType errorType;
198+
private final CommonTokenStream inputStream;
197199

198200
public EmptyRecognitionException(ErrorType errorType, String message, Recognizer<?, ?> recognizer, Token offendingToken) {
199201
super(message, recognizer, offendingToken.getInputStream(), null);
200202
this.errorType = errorType;
201203
this.offendingToken = offendingToken;
204+
if (recognizer.getInputStream() instanceof CommonTokenStream) {
205+
this.inputStream = (CommonTokenStream) recognizer.getInputStream();
206+
} else {
207+
this.inputStream = null;
208+
}
209+
}
210+
211+
public String getPreviousToken() {
212+
if (inputStream == null) {
213+
return null;
214+
}
215+
int previousTokenIndex = offendingToken.getTokenIndex() - 1;
216+
if (previousTokenIndex >= 0) {
217+
return inputStream.get(offendingToken.getTokenIndex() - 1).getText();
218+
}
219+
return null;
202220
}
203221

204222
@Override

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,9 @@ public enum ParserMode {
9393
enum ErrorType {
9494
Generic,
9595
Indentation,
96-
Tab
96+
Tab,
97+
Print,
98+
Exec
9799
}
98100

99101
public interface ParserErrorCallback {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/formatting/ErrorMessageFormatter.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public class ErrorMessageFormatter {
7272
private static Pattern fsPattern = Pattern.compile(formatSpecifier);
7373

7474
public String format(String format, Object... args) {
75-
return format(null, format, args);
75+
return format(PythonObjectLibrary.getUncached(), format, args);
7676
}
7777

7878
@TruffleBoundary
@@ -128,10 +128,7 @@ private static String getMessage(Throwable exception) {
128128
}
129129

130130
private static String getClassName(PythonObjectLibrary lib, Object obj) {
131-
if (lib != null) {
132-
return getClassNameOfClass(lib.getLazyPythonClass(obj));
133-
}
134-
return getClassNameOfClass(PythonObjectLibrary.getUncached().getLazyPythonClass(obj));
131+
return getClassNameOfClass(lib.getLazyPythonClass(obj));
135132
}
136133

137134
private static String getClassNameOfClass(Object obj) {

0 commit comments

Comments
 (0)