41
41
42
42
package com .oracle .graal .python .nodes .literal ;
43
43
44
+ import java .util .ArrayList ;
45
+
44
46
import org .junit .Assert ;
45
47
import org .junit .Test ;
46
48
47
- import com .oracle .graal .python .runtime .PythonParser ;
49
+ import com .oracle .graal .python .PythonLanguage ;
50
+ import com .oracle .graal .python .builtins .PythonBuiltinClassType ;
51
+ import com .oracle .graal .python .parser .sst .FormatStringParser ;
52
+ import com .oracle .graal .python .parser .sst .FormatStringParser .Token ;
53
+ import com .oracle .graal .python .runtime .PythonParser .ErrorType ;
54
+ import com .oracle .graal .python .runtime .PythonParser .ParserErrorCallback ;
48
55
import com .oracle .graal .python .test .parser .ParserTestBase ;
49
- import com .oracle .truffle .api .Truffle ;
50
- import com .oracle .truffle .api .frame .FrameDescriptor ;
51
- import com .oracle .truffle .api .frame .VirtualFrame ;
52
56
import com .oracle .truffle .api .nodes .Node ;
57
+ import com .oracle .truffle .api .source .Source ;
58
+ import com .oracle .truffle .api .source .SourceSection ;
53
59
54
60
public class FormatStringTests extends ParserTestBase {
55
61
@@ -238,6 +244,11 @@ public void parser05() throws Exception {
238
244
testFormatString ("f'It {name} was'" , "It +format((name))+ was" );
239
245
}
240
246
247
+ @ Test
248
+ public void strWithColon () throws Exception {
249
+ testFormatString ("f'{myarray[:1]}'" , "format((myarray[:1]))" );
250
+ }
251
+
241
252
@ Test
242
253
public void str01 () throws Exception {
243
254
testFormatString ("f'{name!s}'" , "format(str((name)))" );
@@ -255,37 +266,37 @@ public void ascii01() throws Exception {
255
266
256
267
@ Test
257
268
public void emptyExpression01 () throws Exception {
258
- checkSyntaxError ("f'{}'" , FormatStringLiteralNode .ERROR_MESSAGE_EMPTY_EXPRESSION );
269
+ checkSyntaxError ("f'{}'" , FormatStringParser .ERROR_MESSAGE_EMPTY_EXPRESSION );
259
270
}
260
271
261
272
@ Test
262
273
public void emptyExpression02 () throws Exception {
263
- checkSyntaxError ("f'start{}end'" , FormatStringLiteralNode .ERROR_MESSAGE_EMPTY_EXPRESSION );
274
+ checkSyntaxError ("f'start{}end'" , FormatStringParser .ERROR_MESSAGE_EMPTY_EXPRESSION );
264
275
}
265
276
266
277
@ Test
267
278
public void emptyExpression03 () throws Exception {
268
- checkSyntaxError ("f'start{}}end'" , FormatStringLiteralNode .ERROR_MESSAGE_EMPTY_EXPRESSION );
279
+ checkSyntaxError ("f'start{}}end'" , FormatStringParser .ERROR_MESSAGE_EMPTY_EXPRESSION );
269
280
}
270
281
271
282
@ Test
272
283
public void emptyExpression04 () throws Exception {
273
- checkSyntaxError ("f'start{{{}}}end'" , FormatStringLiteralNode .ERROR_MESSAGE_EMPTY_EXPRESSION );
284
+ checkSyntaxError ("f'start{{{}}}end'" , FormatStringParser .ERROR_MESSAGE_EMPTY_EXPRESSION );
274
285
}
275
286
276
287
@ Test
277
288
public void singleBracket01 () throws Exception {
278
- checkSyntaxError ("f'}'" , FormatStringLiteralNode .ERROR_MESSAGE_SINGLE_BRACE );
289
+ checkSyntaxError ("f'}'" , FormatStringParser .ERROR_MESSAGE_SINGLE_BRACE );
279
290
}
280
291
281
292
@ Test
282
293
public void singleBracket02 () throws Exception {
283
- checkSyntaxError ("f'start}end'" , FormatStringLiteralNode .ERROR_MESSAGE_SINGLE_BRACE );
294
+ checkSyntaxError ("f'start}end'" , FormatStringParser .ERROR_MESSAGE_SINGLE_BRACE );
284
295
}
285
296
286
297
@ Test
287
298
public void singleBracket03 () throws Exception {
288
- checkSyntaxError ("f'start{{}end'" , FormatStringLiteralNode .ERROR_MESSAGE_SINGLE_BRACE );
299
+ checkSyntaxError ("f'start{{}end'" , FormatStringParser .ERROR_MESSAGE_SINGLE_BRACE );
289
300
}
290
301
291
302
@ Test
@@ -315,73 +326,91 @@ public void missingSpecifier02() throws Exception {
315
326
316
327
@ Test
317
328
public void missingExpression01 () throws Exception {
318
- checkSyntaxError ("f'{!x}'" , FormatStringLiteralNode .ERROR_MESSAGE_EMPTY_EXPRESSION );
329
+ checkSyntaxError ("f'{!x}'" , FormatStringParser .ERROR_MESSAGE_EMPTY_EXPRESSION );
319
330
}
320
331
321
332
@ Test
322
333
public void missingExpression02 () throws Exception {
323
- checkSyntaxError ("f'{ !x}'" , FormatStringLiteralNode .ERROR_MESSAGE_EMPTY_EXPRESSION );
334
+ checkSyntaxError ("f'{ !x}'" , FormatStringParser .ERROR_MESSAGE_EMPTY_EXPRESSION );
324
335
}
325
336
326
337
@ Test
327
338
public void missingExpression03 () throws Exception {
328
- checkSyntaxError ("f'{ !xr:a}'" , FormatStringLiteralNode .ERROR_MESSAGE_EMPTY_EXPRESSION );
339
+ checkSyntaxError ("f'{ !xr:a}'" , FormatStringParser .ERROR_MESSAGE_EMPTY_EXPRESSION );
329
340
}
330
341
331
342
@ Test
332
343
public void missingExpression04 () throws Exception {
333
- checkSyntaxError ("f'{:x'" , FormatStringLiteralNode .ERROR_MESSAGE_EMPTY_EXPRESSION );
344
+ checkSyntaxError ("f'{:x'" , FormatStringParser .ERROR_MESSAGE_EMPTY_EXPRESSION );
334
345
}
335
346
336
347
@ Test
337
348
public void missingExpression05 () throws Exception {
338
- checkSyntaxError ("f'{!'" , FormatStringLiteralNode .ERROR_MESSAGE_EMPTY_EXPRESSION );
349
+ checkSyntaxError ("f'{!'" , FormatStringParser .ERROR_MESSAGE_EMPTY_EXPRESSION );
339
350
}
340
351
341
352
@ Test
342
353
public void missingExpression06 () throws Exception {
343
- checkSyntaxError ("f'{10:{ }}'" , FormatStringLiteralNode .ERROR_MESSAGE_EMPTY_EXPRESSION );
354
+ checkSyntaxError ("f'{10:{ }}'" , FormatStringParser .ERROR_MESSAGE_EMPTY_EXPRESSION );
344
355
}
345
356
346
- private void checkSyntaxError (String text , String expectedMessage ) throws Exception {
357
+ private static void checkSyntaxError (String text , String expectedMessage ) throws Exception {
347
358
try {
348
359
testFormatString (text , "Expected Error: " + expectedMessage );
349
360
} catch (RuntimeException e ) {
350
361
Assert .assertEquals ("SyntaxError: " + expectedMessage , e .getMessage ());
351
362
}
352
363
}
353
364
354
- private void testFormatString (String text , String expected ) throws Exception {
355
- VirtualFrame frame = Truffle .getRuntime ().createVirtualFrame (new Object [8 ], new FrameDescriptor ());
356
-
357
- Node parserResult = parse (text , "<fstringtest>" , PythonParser .ParserMode .InlineEvaluation , frame );
358
-
359
- Assert .assertTrue ("The source has to be just fstring" , parserResult instanceof FormatStringLiteralNode );
360
- FormatStringLiteralNode fsl = (FormatStringLiteralNode ) parserResult ;
361
- int [][] tokens = FormatStringLiteralNode .createTokens (fsl , fsl .getValues ());
362
- FormatStringLiteralNode .StringPart [] fslParts = fsl .getValues ();
363
- String [] expressions = FormatStringLiteralNode .createExpressionSources (fslParts , tokens , 0 , tokens .length );
365
+ private static void testFormatString (String fstring , String expected ) throws Exception {
366
+ assert fstring .startsWith ("f'" ) && fstring .endsWith ("'" );
367
+ // remove the f'...', to extract the text of the f-string
368
+ String text = fstring .substring (2 ).substring (0 , fstring .length () - 3 );
369
+ ArrayList <Token > tokens = new ArrayList <>();
370
+ FormatStringParser .createTokens (tokens , new MockErrorCallback (), 0 , text , 0 );
371
+ ArrayList <String > expressions = FormatStringParser .createExpressionSources (text , tokens , 0 , tokens .size (), tokens .size ());
364
372
int expressionsIndex = 0 ;
365
373
StringBuilder actual = new StringBuilder ();
366
374
boolean first = true ;
367
375
boolean wasLastString = true ;
368
- for (int index = 0 ; index < tokens .length ; index ++) {
369
- int [] token = tokens [ index ] ;
376
+ for (int index = 0 ; index < tokens .size () ; index ++) {
377
+ Token token = tokens . get ( index ) ;
370
378
if (first ) {
371
379
first = false ;
372
- } else if (!(wasLastString && token [ 0 ] == FormatStringLiteralNode .TOKEN_TYPE_STRING )) {
380
+ } else if (!(wasLastString && token . type == FormatStringParser .TOKEN_TYPE_STRING )) {
373
381
actual .append ("+" );
374
382
}
375
- if (token [ 0 ] == FormatStringLiteralNode .TOKEN_TYPE_STRING ) {
376
- actual .append (fslParts [ token [ 1 ]]. getText (). substring ( token [ 2 ] , token [ 3 ]) );
383
+ if (token . type == FormatStringParser .TOKEN_TYPE_STRING ) {
384
+ actual .append (text , token . startIndex , token . endIndex );
377
385
wasLastString = true ;
378
386
} else {
379
- actual .append (expressions [ expressionsIndex ] );
380
- index += token [ 4 ] ;
387
+ actual .append (expressions . get ( expressionsIndex ) );
388
+ index += token . formatTokensCount ;
381
389
wasLastString = false ;
382
390
}
383
391
}
384
392
Assert .assertEquals (expected , actual .toString ());
385
393
}
386
394
395
+ private static final class MockErrorCallback implements ParserErrorCallback {
396
+ @ Override
397
+ public RuntimeException raise (PythonBuiltinClassType type , String message , Object ... args ) {
398
+ throw new RuntimeException ("SyntaxError: " + String .format (message , args ));
399
+ }
400
+
401
+ @ Override
402
+ public RuntimeException raiseInvalidSyntax (ErrorType type , Source source , SourceSection section , String message , Object ... arguments ) {
403
+ throw new RuntimeException ("SyntaxError: " + String .format (message , arguments ));
404
+ }
405
+
406
+ @ Override
407
+ public RuntimeException raiseInvalidSyntax (ErrorType type , Node location , String message , Object ... arguments ) {
408
+ throw new RuntimeException ("SyntaxError: " + String .format (message , arguments ));
409
+ }
410
+
411
+ @ Override
412
+ public PythonLanguage getLanguage () {
413
+ return null ;
414
+ }
415
+ }
387
416
}
0 commit comments