Skip to content

Commit d6a19b5

Browse files
committed
[GR-24682] More fstrings fixes.
PullRequest: graalpython/1167
2 parents 894bfc9 + a0870f6 commit d6a19b5

File tree

15 files changed

+186
-55
lines changed

15 files changed

+186
-55
lines changed

graalpython/com.oracle.graal.python.cext/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353

5454
verbosity = '--verbose' if sys.flags.verbose else '--quiet'
5555
darwin_native = sys.platform == "darwin" and __graalpython__.platform_id == "native"
56-
relative_rpath = "@loader_path" if darwin_native else "\$ORIGIN"
56+
relative_rpath = "@loader_path" if darwin_native else r"\$ORIGIN"
5757
so_ext = get_config_var("EXT_SUFFIX")
5858
SOABI = get_config_var("SOABI")
5959

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/nodes/literal/FormatStringTests.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,12 +362,12 @@ private static void checkSyntaxError(String text, String expectedMessage) throws
362362
}
363363
}
364364

365-
private static void testFormatString(String fstring, String expected) throws Exception {
365+
private static void testFormatString(String fstring, String expected) {
366366
assert fstring.startsWith("f'") && fstring.endsWith("'");
367367
// remove the f'...', to extract the text of the f-string
368368
String text = fstring.substring(2).substring(0, fstring.length() - 3);
369369
ArrayList<Token> tokens = new ArrayList<>();
370-
FormatStringParser.createTokens(tokens, new MockErrorCallback(), 0, text, 0);
370+
FormatStringParser.createTokens(tokens, new MockErrorCallback(), 0, text, false, 0);
371371
ArrayList<String> expressions = FormatStringParser.createExpressionSources(text, tokens, 0, tokens.size(), tokens.size());
372372
int expressionsIndex = 0;
373373
StringBuilder actual = new StringBuilder();
@@ -408,6 +408,11 @@ public RuntimeException raiseInvalidSyntax(ErrorType type, Node location, String
408408
throw new RuntimeException("SyntaxError: " + String.format(message, arguments));
409409
}
410410

411+
@Override
412+
public void warn(Object type, String format, Object... args) {
413+
throw new RuntimeException("Warning: " + String.format(format, args));
414+
}
415+
411416
@Override
412417
public PythonLanguage getLanguage() {
413418
return null;

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/parser/StringUtilsTests.java

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,35 +40,73 @@
4040
*/
4141
package com.oracle.graal.python.test.parser;
4242

43-
import com.oracle.graal.python.parser.sst.StringUtils;
4443
import org.junit.Assert;
4544
import org.junit.Test;
4645

46+
import com.oracle.graal.python.PythonLanguage;
47+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
48+
import com.oracle.graal.python.parser.sst.StringUtils;
49+
import com.oracle.graal.python.runtime.PythonParser.ErrorType;
50+
import com.oracle.graal.python.runtime.PythonParser.ParserErrorCallback;
51+
import com.oracle.truffle.api.nodes.Node;
52+
import com.oracle.truffle.api.source.Source;
53+
import com.oracle.truffle.api.source.SourceSection;
54+
4755
public class StringUtilsTests extends ParserTestBase {
56+
private static final ParserErrorCallback errorCallback = new ParserErrorCallback() {
57+
@Override
58+
public RuntimeException raise(PythonBuiltinClassType type, String message, Object... args) {
59+
Assert.fail("Unexpected error: " + String.format(message, args));
60+
return null;
61+
}
62+
63+
@Override
64+
public RuntimeException raiseInvalidSyntax(ErrorType type, Source source, SourceSection section, String message, Object... arguments) {
65+
Assert.fail("Unexpected error: " + String.format(message, arguments));
66+
return null;
67+
}
68+
69+
@Override
70+
public RuntimeException raiseInvalidSyntax(ErrorType type, Node location, String message, Object... arguments) {
71+
Assert.fail("Unexpected error: " + String.format(message, arguments));
72+
return null;
73+
}
74+
75+
@Override
76+
public void warn(Object type, String format, Object... args) {
77+
Assert.fail("Unexpected warning: " + String.format(format, args));
78+
}
79+
80+
@Override
81+
public PythonLanguage getLanguage() {
82+
return null;
83+
}
84+
};
85+
4886
@Test
4987
public void unicodeCharNameBasic() throws Exception {
50-
Assert.assertEquals("Δ", StringUtils.unescapeJavaString("\\N{GREEK CAPITAL LETTER DELTA}"));
51-
Assert.assertEquals("A", StringUtils.unescapeJavaString("\\N{LATIN CAPITAL LETTER A}"));
52-
Assert.assertEquals("A", StringUtils.unescapeJavaString("\\N{LATIN CAPITAL LETTER a}"));
53-
Assert.assertEquals("A", StringUtils.unescapeJavaString("\\N{LATIN CAPITAL LETTEr a}"));
54-
Assert.assertEquals("A", StringUtils.unescapeJavaString("\\N{latin capital letter a}"));
55-
Assert.assertEquals("AHOJ", StringUtils.unescapeJavaString("A\\N{LATIN CAPITAL LETTER H}OJ"));
56-
Assert.assertEquals("AHOJ", StringUtils.unescapeJavaString("\\N{LATIN CAPITAL LETTER A}\\N{LATIN CAPITAL LETTER H}\\N{LATIN CAPITAL LETTER O}\\N{LATIN CAPITAL LETTER J}"));
88+
Assert.assertEquals("Δ", StringUtils.unescapeJavaString(errorCallback, "\\N{GREEK CAPITAL LETTER DELTA}"));
89+
Assert.assertEquals("A", StringUtils.unescapeJavaString(errorCallback, "\\N{LATIN CAPITAL LETTER A}"));
90+
Assert.assertEquals("A", StringUtils.unescapeJavaString(errorCallback, "\\N{LATIN CAPITAL LETTER a}"));
91+
Assert.assertEquals("A", StringUtils.unescapeJavaString(errorCallback, "\\N{LATIN CAPITAL LETTEr a}"));
92+
Assert.assertEquals("A", StringUtils.unescapeJavaString(errorCallback, "\\N{latin capital letter a}"));
93+
Assert.assertEquals("AHOJ", StringUtils.unescapeJavaString(errorCallback, "A\\N{LATIN CAPITAL LETTER H}OJ"));
94+
Assert.assertEquals("AHOJ", StringUtils.unescapeJavaString(errorCallback, "\\N{LATIN CAPITAL LETTER A}\\N{LATIN CAPITAL LETTER H}\\N{LATIN CAPITAL LETTER O}\\N{LATIN CAPITAL LETTER J}"));
5795
checkUnknownChar("ahoj");
5896
}
5997

6098
@Test
6199
public void blockHangulSyllables() throws Exception {
62-
Assert.assertEquals("가", StringUtils.unescapeJavaString("\\N{HANGUL SYLLABLE GA}"));
63-
Assert.assertEquals("돐", StringUtils.unescapeJavaString("\\N{HANGUL SYLLABLE DOLS}"));
64-
Assert.assertEquals("똜", StringUtils.unescapeJavaString("\\N{HANGUL SYLLABLE DDOLS}"));
100+
Assert.assertEquals("가", StringUtils.unescapeJavaString(errorCallback, "\\N{HANGUL SYLLABLE GA}"));
101+
Assert.assertEquals("돐", StringUtils.unescapeJavaString(errorCallback, "\\N{HANGUL SYLLABLE DOLS}"));
102+
Assert.assertEquals("똜", StringUtils.unescapeJavaString(errorCallback, "\\N{HANGUL SYLLABLE DDOLS}"));
65103
}
66104

67105
@Test
68106
public void blockCjkUnifiedIdeograph() throws Exception {
69-
Assert.assertEquals("㐀", StringUtils.unescapeJavaString("\\N{CJK Unified Ideograph-3400}"));
70-
Assert.assertEquals("𫝜", StringUtils.unescapeJavaString("\\N{CJK Unified Ideograph-2B75C}"));
71-
Assert.assertEquals("丳", StringUtils.unescapeJavaString("\\N{CJK Unified Ideograph-4E33}"));
107+
Assert.assertEquals("㐀", StringUtils.unescapeJavaString(errorCallback, "\\N{CJK Unified Ideograph-3400}"));
108+
Assert.assertEquals("𫝜", StringUtils.unescapeJavaString(errorCallback, "\\N{CJK Unified Ideograph-2B75C}"));
109+
Assert.assertEquals("丳", StringUtils.unescapeJavaString(errorCallback, "\\N{CJK Unified Ideograph-4E33}"));
72110
}
73111

74112
@Test
@@ -82,6 +120,7 @@ public void blockCjkUnifiedIdeographUnknownCharacters() throws Exception {
82120

83121
@Test
84122
public void malformedError() throws Exception {
123+
checkSyntaxErrorMessage("'\\N'", "SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 0-1: malformed \\N character escape");
85124
checkSyntaxErrorMessage("'\\N {LATIN CAPITAL LETTER A}'", "SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 0-1: malformed \\N character escape");
86125
checkSyntaxErrorMessage("'\\N LATIN CAPITAL LETTER A}'", "SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 0-1: malformed \\N character escape");
87126
checkSyntaxErrorMessage("'\\N{LATIN CAPITAL LETTER A'", "SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 0-24: malformed \\N character escape");

graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_fstring.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515
*graalpython.lib-python.3.test.test_fstring.TestCase.test_compile_time_concat
1616
*graalpython.lib-python.3.test.test_fstring.TestCase.test_compile_time_concat_errors
1717
*graalpython.lib-python.3.test.test_fstring.TestCase.test_conversions
18+
*graalpython.lib-python.3.test.test_fstring.TestCase.test_backslashes_in_string_part
19+
*graalpython.lib-python.3.test.test_fstring.TestCase.test_debug_conversion
20+
*graalpython.lib-python.3.test.test_fstring.TestCase.test_format_specifier_expressions
21+
*graalpython.lib-python.3.test.test_fstring.TestCase.test_errors
22+
*graalpython.lib-python.3.test.test_fstring.TestCase.test_global
23+
*graalpython.lib-python.3.test.test_fstring.TestCase.test_lambda
24+
*graalpython.lib-python.3.test.test_fstring.TestCase.test_misformed_unicode_character_name
25+
*graalpython.lib-python.3.test.test_fstring.TestCase.test_no_backslashes_in_expression_part
1826
*graalpython.lib-python.3.test.test_fstring.TestCase.test_del
1927
*graalpython.lib-python.3.test.test_fstring.TestCase.test_dict
2028
*graalpython.lib-python.3.test.test_fstring.TestCase.test_docstring

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@
174174
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetNameNode;
175175
import com.oracle.graal.python.builtins.objects.zipimporter.ZipImporterBuiltins;
176176
import com.oracle.graal.python.nodes.BuiltinNames;
177+
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromDynamicObjectNode;
178+
import com.oracle.graal.python.nodes.call.CallNode;
177179
import com.oracle.graal.python.nodes.call.GenericInvokeNode;
178180
import com.oracle.graal.python.runtime.PythonCodeSerializer;
179181
import com.oracle.graal.python.runtime.PythonContext;
@@ -210,7 +212,7 @@ public final class Python3Core implements PythonCore {
210212

211213
public static final Pattern MISSING_PARENTHESES_PATTERN = Pattern.compile("^(print|exec) +([^(][^;]*).*");
212214

213-
private static final String[] initializeCoreFiles() {
215+
private static String[] initializeCoreFiles() {
214216
// Order matters!
215217
List<String> coreFiles = new ArrayList<>(Arrays.asList(
216218
"_descriptor",
@@ -305,7 +307,7 @@ private static final String[] initializeCoreFiles() {
305307
c = null;
306308
}
307309

308-
private static final PythonBuiltins[] initializeBuiltins() {
310+
private static PythonBuiltins[] initializeBuiltins() {
309311
List<PythonBuiltins> builtins = new ArrayList<>(Arrays.asList(
310312
new BuiltinConstructors(),
311313
new BuiltinFunctions(),
@@ -490,6 +492,7 @@ public boolean isInitialized() {
490492
return initialized;
491493
}
492494

495+
@Override
493496
public void initialize(PythonContext context) {
494497
singletonContext = context;
495498
initializeJavaCore();
@@ -525,16 +528,19 @@ public void postInitialize() {
525528
}
526529
}
527530

531+
@Override
528532
@TruffleBoundary
529533
public PythonModule lookupBuiltinModule(String name) {
530534
return builtinModules.get(name);
531535
}
532536

537+
@Override
533538
public PythonBuiltinClass lookupType(PythonBuiltinClassType type) {
534539
assert builtinTypes[type.ordinal()] != null;
535540
return builtinTypes[type.ordinal()];
536541
}
537542

543+
@Override
538544
@TruffleBoundary
539545
public String[] builtinModuleNames() {
540546
return builtinModules.keySet().toArray(new String[0]);
@@ -557,6 +563,14 @@ public PException raise(PythonBuiltinClassType type, String format, Object... ar
557563
throw PException.fromObject(instance, null, PythonOptions.isPExceptionWithJavaStacktrace(getLanguage()));
558564
}
559565

566+
@Override
567+
@TruffleBoundary
568+
public void warn(Object type, String format, Object... args) {
569+
PythonModule warningsModule = lookupBuiltinModule("_warnings");
570+
Object warn = ReadAttributeFromDynamicObjectNode.getUncached().execute(warningsModule.getStorage(), "warn");
571+
CallNode.getUncached().execute(warn, String.format(format, args), type);
572+
}
573+
560574
private void publishBuiltinModules() {
561575
PythonModule sysModule = builtinModules.get("sys");
562576
PDict sysModules = (PDict) sysModule.getAttribute("modules");
@@ -704,23 +718,28 @@ private void loadFile(String s, String prefix) {
704718
GenericInvokeNode.getUncached().execute(callTarget, PArguments.withGlobals(mod));
705719
}
706720

721+
@Override
707722
public PythonObjectFactory factory() {
708723
return objectFactory;
709724
}
710725

726+
@Override
711727
public void setContext(PythonContext context) {
712728
assert singletonContext == null;
713729
singletonContext = context;
714730
}
715731

732+
@Override
716733
public PInt getTrue() {
717734
return pyTrue;
718735
}
719736

737+
@Override
720738
public PInt getFalse() {
721739
return pyFalse;
722740
}
723741

742+
@Override
724743
public PFloat getNaN() {
725744
return pyNaN;
726745
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/CodecsModuleBuiltins.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,12 @@
8484
import com.oracle.truffle.api.CompilerDirectives;
8585
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
8686
import com.oracle.truffle.api.dsl.Cached;
87+
import com.oracle.truffle.api.dsl.Cached.Shared;
8788
import com.oracle.truffle.api.dsl.Fallback;
8889
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
8990
import com.oracle.truffle.api.dsl.NodeFactory;
9091
import com.oracle.truffle.api.dsl.Specialization;
9192
import com.oracle.truffle.api.dsl.TypeSystemReference;
92-
import com.oracle.truffle.api.dsl.Cached.Shared;
9393
import com.oracle.truffle.api.frame.VirtualFrame;
9494
import com.oracle.truffle.api.library.CachedLibrary;
9595

@@ -159,7 +159,7 @@ Object encode(VirtualFrame frame, Object bytes, @SuppressWarnings("unused") Stri
159159
PythonCore core = getCore();
160160
byte[] byteArray = toBytes.execute(frame, bytes);
161161
String string = strFromBytes(byteArray);
162-
String unescapedString = core.getParser().unescapeJavaString(string);
162+
String unescapedString = core.getParser().unescapeJavaString(core, string);
163163
return factory().createTuple(new Object[]{unescapedString, byteArray.length});
164164
}
165165

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/ObjectBuiltins.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode;
9191
import com.oracle.graal.python.nodes.object.GetClassNode;
9292
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
93+
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
9394
import com.oracle.graal.python.nodes.util.SplitArgsNode;
9495
import com.oracle.truffle.api.CompilerDirectives;
9596
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
@@ -100,6 +101,7 @@
100101
import com.oracle.truffle.api.dsl.ImportStatic;
101102
import com.oracle.truffle.api.dsl.NodeFactory;
102103
import com.oracle.truffle.api.dsl.Specialization;
104+
import com.oracle.truffle.api.dsl.TypeSystemReference;
103105
import com.oracle.truffle.api.frame.VirtualFrame;
104106
import com.oracle.truffle.api.interop.InteropLibrary;
105107
import com.oracle.truffle.api.interop.UnsupportedMessageException;
@@ -572,11 +574,16 @@ Object raise(Object self, @SuppressWarnings("unused") Object dict) {
572574
}
573575

574576
@Builtin(name = __FORMAT__, minNumOfPositionalArgs = 2)
577+
@TypeSystemReference(PythonArithmeticTypes.class)
575578
@GenerateNodeFactory
576579
abstract static class FormatNode extends PythonBinaryBuiltinNode {
580+
577581
@Specialization(guards = "isString(formatString)")
578-
Object format(VirtualFrame frame, Object self, @SuppressWarnings("unused") Object formatString,
582+
Object format(VirtualFrame frame, Object self, String formatString,
579583
@Cached("create(__STR__)") LookupAndCallUnaryNode strCall) {
584+
if (formatString.length() > 0) {
585+
raise(PythonBuiltinClassType.TypeError, ErrorMessages.UNSUPPORTED_FORMAT_STRING_PASSED_TO_P_FORMAT, self);
586+
}
580587
return strCall.executeObject(frame, self);
581588
}
582589

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
@@ -554,4 +554,5 @@ public abstract class ErrorMessages {
554554
public static final String HPY_LOAD_ERROR = "Could not load HPy C API from %s.";
555555
public static final String CANNOT_CONVERT_NEGATIVE_VALUE_TO_UNSIGNED_INT = "can't convert negative value to unsigned int";
556556
public static final String SEND_NON_NONE_TO_UNSTARTED_GENERATOR = "can't send non-None value to a just-started generator";
557+
public static final String UNSUPPORTED_FORMAT_STRING_PASSED_TO_P_FORMAT = "unsupported format string passed to %p.__format__";
557558
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,8 +389,8 @@ public boolean isIdentifier(PythonCore core, String snippet) {
389389

390390
@Override
391391
@TruffleBoundary
392-
public String unescapeJavaString(String str) {
393-
return StringUtils.unescapeJavaString(str);
392+
public String unescapeJavaString(PythonCore core, String str) {
393+
return StringUtils.unescapeJavaString(core, str);
394394
}
395395

396396
private static PException handleParserError(ParserErrorCallback errors, Source source, Exception e) {

0 commit comments

Comments
 (0)