35
35
36
36
import java .io .IOException ;
37
37
import java .nio .file .InvalidPathException ;
38
+ import java .util .ArrayList ;
38
39
import java .util .Arrays ;
39
40
import java .util .EnumSet ;
41
+ import java .util .HashSet ;
40
42
import java .util .List ;
41
43
import java .util .concurrent .ConcurrentHashMap ;
42
44
import java .util .concurrent .Semaphore ;
74
76
import com .oracle .graal .python .nodes .exception .TopLevelExceptionHandler ;
75
77
import com .oracle .graal .python .nodes .frame .GetFrameLocalsNode ;
76
78
import com .oracle .graal .python .nodes .frame .MaterializeFrameNode ;
79
+ import com .oracle .graal .python .pegparser .FutureFeature ;
77
80
import com .oracle .graal .python .pegparser .InputType ;
78
81
import com .oracle .graal .python .pegparser .NodeFactory ;
79
82
import com .oracle .graal .python .pegparser .Parser ;
131
134
name = PythonLanguage .NAME , //
132
135
implementationName = PythonLanguage .IMPLEMENTATION_NAME , //
133
136
version = PythonLanguage .VERSION , //
134
- characterMimeTypes = {PythonLanguage .MIME_TYPE , "text/x-python-eval-0-0" , "text/x-python-eval-0-1" , "text/x-python-eval-1-0" , "text/x-python-eval-1-1" , "text/x-python-eval-2-0" ,
135
- "text/x-python-eval-2-1" , "text/x-python-compile-0-0" , "text/x-python-compile-0-1" , "text/x-python-compile-1-0" , "text/x-python-compile-1-1" ,
136
- "text/x-python-compile-2-0" ,
137
- "text/x-python-compile-2-1" }, //
137
+ characterMimeTypes = {PythonLanguage .MIME_TYPE ,
138
+ "text/x-python-\0 \u0000 -eval" , "text/x-python-\0 \u0000 -compile" , "text/x-python-\1 \u0000 -eval" , "text/x-python-\1 \u0000 -compile" , "text/x-python-\2 \u0000 -eval" ,
139
+ "text/x-python-\2 \u0000 -compile" , "text/x-python-\0 \u0100 -eval" , "text/x-python-\0 \u0100 -compile" , "text/x-python-\1 \u0100 -eval" , "text/x-python-\1 \u0100 -compile" ,
140
+ "text/x-python-\2 \u0100 -eval" , "text/x-python-\2 \u0100 -compile" , "text/x-python-\0 \u0040 -eval" , "text/x-python-\0 \u0040 -compile" , "text/x-python-\1 \u0040 -eval" ,
141
+ "text/x-python-\1 \u0040 -compile" , "text/x-python-\2 \u0040 -eval" , "text/x-python-\2 \u0040 -compile" , "text/x-python-\0 \u0140 -eval" , "text/x-python-\0 \u0140 -compile" ,
142
+ "text/x-python-\1 \u0140 -eval" , "text/x-python-\1 \u0140 -compile" , "text/x-python-\2 \u0140 -eval" , "text/x-python-\2 \u0140 -compile" }, //
138
143
byteMimeTypes = {PythonLanguage .MIME_TYPE_BYTECODE }, //
139
144
defaultMimeType = PythonLanguage .MIME_TYPE , //
140
145
dependentLanguages = {"nfi" , "llvm" }, //
@@ -209,17 +214,44 @@ public final class PythonLanguage extends TruffleLanguage<PythonContext> {
209
214
public static final String MIME_TYPE = "text/x-python" ;
210
215
211
216
// the syntax for mime types is as follows
212
- // <mime> ::= "text/x-python-" <kind> "-" <optlevel > "-" <future_annotations>
217
+ // <mime> ::= "text/x-python-" <optlevel> <flags > "-" kind
213
218
// <kind> ::= "compile" | "eval"
214
- // <optlevel> ::= "0" | "1" | "2"
215
- // <future_annotations> ::= "0" | "1"
219
+ // <optlevel> ::= "\0" | "\1" | "\2"
220
+ // <flags> ::= "\u0040" | "\u0100" | "\u0140" | "\u0000"
221
+ // where 0100 implies annotations, and 0040 implies barry_as_flufl
216
222
static final String MIME_PREFIX = MIME_TYPE + "-" ;
223
+ static final int OPT_FLAGS_LEN = 2 ; // 1 char is optlevel, 1 char is flags
217
224
static final String MIME_KIND_COMPILE = "compile" ;
218
225
static final String MIME_KIND_EVAL = "eval" ;
219
- static final int MIME_KIND_IDX = 0 ;
220
- static final int MIME_OPTLEVEL_IDX = 1 ;
221
- static final int MIME_FUTURE_ANNOTATIONS_IDX = 2 ;
222
- static final int MIME_FIELD_COUNT = 3 ;
226
+ // Since flags are greater than the highest unicode codepoint, we shift them into more
227
+ // reasonable values in the mime type. 4 hex digits
228
+ static final int MIME_FLAG_SHIFTBY = 4 * 4 ;
229
+ // a dash follows after the opt flag pair
230
+ static final int MIME_KIND_START = MIME_PREFIX .length () + OPT_FLAGS_LEN + 1 ;
231
+
232
+ static {
233
+ ArrayList <String > mimeTypes = new ArrayList <>();
234
+ ArrayList <String > mimeJavaStrings = new ArrayList <>();
235
+ FutureFeature [] all = FutureFeature .values ();
236
+ for (int flagset = 0 ; flagset < (1 << all .length ); ++flagset ) {
237
+ int flags = 0 ;
238
+ for (int i = 0 ; i < all .length ; ++i ) {
239
+ if ((flagset & (1 << i )) != 0 ) {
240
+ flags |= all [i ].flagValue ;
241
+ }
242
+ }
243
+ for (int opt = 0 ; opt <= 2 ; opt ++) {
244
+ for (String typ : new String []{MIME_KIND_EVAL , MIME_KIND_COMPILE }) {
245
+ mimeTypes .add (MIME_PREFIX + optFlagsToMime (opt , flags ) + "-" + typ );
246
+ mimeJavaStrings .add (String .format ("\" %s\\ %d\\ u%04x-%s\" " , MIME_PREFIX , opt , flags >> MIME_FLAG_SHIFTBY , typ ));
247
+ }
248
+ }
249
+ }
250
+ HashSet <String > currentMimeTypes = new HashSet <>(List .of (PythonLanguage .class .getAnnotation (Registration .class ).characterMimeTypes ()));
251
+ if (!currentMimeTypes .containsAll (mimeTypes )) {
252
+ assert false : "Expected all of {" + String .join (", " , mimeJavaStrings ) + "} in the PythonLanguage characterMimeTypes" ;
253
+ }
254
+ }
223
255
224
256
public static final String MIME_TYPE_BYTECODE = "application/x-python-bytecode" ;
225
257
@@ -395,29 +427,26 @@ protected void initializeContext(PythonContext context) {
395
427
context .initialize ();
396
428
}
397
429
398
- public static String getCompileMimeType (int optimize , boolean futureAnnotations ) {
399
- String futureAnnField = futureAnnotations ? "1" : "0" ;
400
- String compile = MIME_PREFIX + "compile-" ;
401
- if (optimize <= 0 ) {
402
- return compile + "0-" + futureAnnField ;
403
- } else if (optimize == 1 ) {
404
- return compile + "1-" + futureAnnField ;
405
- } else {
406
- return compile + "2-" + futureAnnField ;
430
+ private static String optFlagsToMime (int optimize , int flags ) {
431
+ if (optimize < 0 ) {
432
+ optimize = 0 ;
433
+ } else if (optimize > 2 ) {
434
+ optimize = 2 ;
407
435
}
436
+ String optField = new String (new byte []{(byte ) optimize });
437
+ String flagField = new String (new int []{(flags & FutureFeature .ALL_FLAGS ) >> MIME_FLAG_SHIFTBY }, 0 , 1 );
438
+ assert flagField .length () == 1 : "flags in mime type ended up a surrogate" ;
439
+ return optField + flagField ;
408
440
}
409
441
410
- // TODO inherit other implemented
411
- public static String getEvalMimeType (int optimize , boolean futureAnnotations ) {
412
- String futureAnnField = futureAnnotations ? "1" : "0" ;
413
- String eval = MIME_PREFIX + "eval-" ;
414
- if (optimize <= 0 ) {
415
- return eval + "0-" + futureAnnField ;
416
- } else if (optimize == 1 ) {
417
- return eval + "1-" + futureAnnField ;
418
- } else {
419
- return eval + "2-" + futureAnnField ;
420
- }
442
+ public static String getCompileMimeType (int optimize , int flags ) {
443
+ String optFlags = optFlagsToMime (optimize , flags );
444
+ return MIME_PREFIX + optFlags + "-compile" ;
445
+ }
446
+
447
+ public static String getEvalMimeType (int optimize , int flags ) {
448
+ String optFlags = optFlagsToMime (optimize , flags );
449
+ return MIME_PREFIX + optFlags + "-eval" ;
421
450
}
422
451
423
452
@ Override
@@ -429,7 +458,7 @@ protected CallTarget parse(ParsingRequest request) {
429
458
throw new IllegalStateException ("parse with arguments not allowed for interactive sources" );
430
459
}
431
460
InputType inputType = source .isInteractive () ? InputType .SINGLE : InputType .FILE ;
432
- return parse (context , source , inputType , true , 0 , source .isInteractive (), request .getArgumentNames (), false );
461
+ return parse (context , source , inputType , true , 0 , source .isInteractive (), request .getArgumentNames (), EnumSet . noneOf ( FutureFeature . class ) );
433
462
}
434
463
if (!request .getArgumentNames ().isEmpty ()) {
435
464
throw new IllegalStateException ("parse with arguments is only allowed for " + MIME_TYPE + " mime type" );
@@ -468,34 +497,24 @@ protected CallTarget parse(ParsingRequest request) {
468
497
String mime = source .getMimeType ();
469
498
String prefix = mime .substring (0 , MIME_PREFIX .length ());
470
499
if (!prefix .equals (MIME_PREFIX )) {
471
- throw CompilerDirectives .shouldNotReachHere ("unknown mime type: " + source .getMimeType ());
472
- }
473
- String [] fields = mime .substring (MIME_PREFIX .length ()).split ("-" );
474
- if (fields .length != MIME_FIELD_COUNT ) {
475
- throw CompilerDirectives .shouldNotReachHere ("unknown mime type: " + source .getMimeType ());
500
+ throw CompilerDirectives .shouldNotReachHere ("unknown mime type: " + mime );
476
501
}
477
- String kind = fields [ MIME_KIND_IDX ] ;
502
+ String kind = mime . substring ( MIME_KIND_START ) ;
478
503
InputType type ;
479
504
if (kind .equals (MIME_KIND_COMPILE )) {
480
505
type = InputType .FILE ;
481
506
} else if (kind .equals (MIME_KIND_EVAL )) {
482
507
type = InputType .EVAL ;
483
508
} else {
484
- throw CompilerDirectives .shouldNotReachHere ("unknown mime type: " + source .getMimeType ());
485
- }
486
- int optimize ;
487
- int futureAnnotations ;
488
- try {
489
- optimize = Integer .parseInt (fields [MIME_OPTLEVEL_IDX ]);
490
- futureAnnotations = Integer .parseInt (fields [MIME_FUTURE_ANNOTATIONS_IDX ]);
491
- } catch (NumberFormatException e ) {
492
- throw CompilerDirectives .shouldNotReachHere ("unknown mime type: " + source .getMimeType ());
509
+ throw CompilerDirectives .shouldNotReachHere ("unknown compilation kind: " + kind + " from mime type: " + mime );
493
510
}
494
- if (0 > optimize || optimize > 2 || 0 > futureAnnotations || futureAnnotations > 2 ) {
495
- throw CompilerDirectives .shouldNotReachHere ("unknown mime type: " + source .getMimeType ());
511
+ int optimize = mime .codePointAt (MIME_PREFIX .length ());
512
+ int flags = mime .codePointAt (MIME_PREFIX .length () + 1 ) << MIME_FLAG_SHIFTBY ;
513
+ if (0 > optimize || optimize > 2 || (flags & ~FutureFeature .ALL_FLAGS ) != 0 ) {
514
+ throw CompilerDirectives .shouldNotReachHere ("Invalid value for optlevel or flags: " + optimize + "," + flags + " from mime type: " + mime );
496
515
}
497
516
assert !source .isInteractive ();
498
- return parse (context , source , type , false , optimize , false , null , futureAnnotations == 1 );
517
+ return parse (context , source , type , false , optimize , false , null , FutureFeature . fromFlags ( flags ) );
499
518
}
500
519
501
520
private static Source tryLoadSource (PythonContext context , CodeUnit code , boolean internal , String path ) {
@@ -507,13 +526,13 @@ private static Source tryLoadSource(PythonContext context, CodeUnit code, boolea
507
526
}
508
527
509
528
public RootCallTarget parse (PythonContext context , Source source , InputType type , boolean topLevel , int optimize , boolean interactiveTerminal , List <String > argumentNames ,
510
- boolean futureAnnotations ) {
529
+ EnumSet < FutureFeature > futureFeatures ) {
511
530
RaisePythonExceptionErrorCallback errorCb = new RaisePythonExceptionErrorCallback (source , PythonOptions .isPExceptionWithJavaStacktrace (this ));
512
531
try {
513
532
Parser parser = Compiler .createParser (source .getCharacters ().toString (), errorCb , type , interactiveTerminal );
514
533
ModTy mod = (ModTy ) parser .parse ();
515
534
assert mod != null ;
516
- return compileForBytecodeInterpreter (context , mod , source , topLevel , optimize , argumentNames , errorCb , futureAnnotations );
535
+ return compileForBytecodeInterpreter (context , mod , source , topLevel , optimize , argumentNames , errorCb , futureFeatures );
517
536
} catch (PException e ) {
518
537
if (topLevel ) {
519
538
PythonUtils .getOrCreateCallTarget (new TopLevelExceptionHandler (this , e )).call ();
@@ -524,7 +543,7 @@ public RootCallTarget parse(PythonContext context, Source source, InputType type
524
543
525
544
@ TruffleBoundary
526
545
public RootCallTarget compileForBytecodeInterpreter (PythonContext context , ModTy mod , Source source , boolean topLevel , int optimize , List <String > argumentNames ,
527
- RaisePythonExceptionErrorCallback errorCallback , boolean futureAnnotations ) {
546
+ RaisePythonExceptionErrorCallback errorCallback , EnumSet < FutureFeature > futureFeatures ) {
528
547
RaisePythonExceptionErrorCallback errorCb = errorCallback ;
529
548
if (errorCb == null ) {
530
549
errorCb = new RaisePythonExceptionErrorCallback (source , PythonOptions .isPExceptionWithJavaStacktrace (this ));
@@ -535,7 +554,7 @@ public RootCallTarget compileForBytecodeInterpreter(PythonContext context, ModTy
535
554
if (hasArguments ) {
536
555
mod = transformASTForExecutionWithArguments (argumentNames , mod );
537
556
}
538
- CompilationUnit cu = compiler .compile (mod , EnumSet .noneOf (Compiler .Flags .class ), optimize , futureAnnotations );
557
+ CompilationUnit cu = compiler .compile (mod , EnumSet .noneOf (Compiler .Flags .class ), optimize , futureFeatures );
539
558
CodeUnit co = cu .assemble ();
540
559
RootNode rootNode = PBytecodeRootNode .create (this , co , source , errorCb );
541
560
if (topLevel ) {
@@ -620,7 +639,7 @@ public String getName() {
620
639
@ Override
621
640
public ExecutableNode parse (InlineParsingRequest request ) {
622
641
PythonContext context = PythonContext .get (null );
623
- RootCallTarget callTarget = parse (context , request .getSource (), InputType .EVAL , false , 0 , false , null , false );
642
+ RootCallTarget callTarget = parse (context , request .getSource (), InputType .EVAL , false , 0 , false , null , EnumSet . noneOf ( FutureFeature . class ) );
624
643
return new ExecutableNode (this ) {
625
644
@ Child private GilNode gilNode = GilNode .create ();
626
645
@ Child private GenericInvokeNode invokeNode = GenericInvokeNode .create ();
0 commit comments