@@ -82,12 +82,13 @@ public class PythonProvider implements LanguageProvider {
82
82
83
83
private static final String ID = "python" ;
84
84
85
- private static final TypeDescriptor INT = intersection (OBJECT , NUMBER );
86
- // as per interop contract, we cannot be boolean and number at the same time
87
- private static final TypeDescriptor BOOL = intersection (OBJECT , BOOLEAN );
88
- private static final TypeDescriptor FLOAT = intersection (OBJECT , NUMBER );
85
+ private static final TypeDescriptor INT = NUMBER ;
86
+ // as per interop contract, we cannot be boolean and number at the same time, so it's only a
87
+ // boolean
88
+ private static final TypeDescriptor BOOL = BOOLEAN ;
89
+ private static final TypeDescriptor FLOAT = NUMBER ;
89
90
private static final TypeDescriptor COMPLEX = intersection (OBJECT );
90
- private static final TypeDescriptor NONE = intersection ( OBJECT , NULL ) ;
91
+ private static final TypeDescriptor NONE = NULL ;
91
92
private static final TypeDescriptor STR = intersection (OBJECT , STRING , ITERABLE , array (STRING ));
92
93
private static final TypeDescriptor BYTES = intersection (OBJECT , ITERABLE , array (INT ));
93
94
private static final TypeDescriptor BYTEARRAY = intersection (OBJECT , ITERABLE , array (INT ));
@@ -223,15 +224,14 @@ public Collection<? extends Snippet> createExpressions(Context context) {
223
224
List <Snippet > snippets = new ArrayList <>();
224
225
225
226
// @formatter:off
226
- addExpressionSnippet (context , snippets , "+" , "lambda x, y: x + y" , NUMBER , union (BOOLEAN , NUMBER ), union (BOOLEAN , NUMBER ));
227
- addExpressionSnippet (context , snippets , "+ str" , "lambda x, y: x + y" , NUMBER , union (BOOLEAN , NUMBER ), union (BOOLEAN , NUMBER ));
228
- addExpressionSnippet (context , snippets , "+ list" , "lambda x, y: x + y" , array (ANY ), PNoListCoercionVerifier .INSTANCE , array (ANY ), array (ANY ));
227
+ addExpressionSnippet (context , snippets , "+" , "lambda x, y: x + y" , union (STRING , NUMBER , array (ANY )), AddVerifier .INSTANCE , union (STRING , BOOLEAN , NUMBER , array (ANY )), union (STRING , BOOLEAN , NUMBER , array (ANY )));
228
+ addExpressionSnippet (context , snippets , "*" , "lambda x, y: x * y" , union (STRING , NUMBER , array (ANY )), MulVerifier .INSTANCE , union (STRING , BOOLEAN , NUMBER , array (ANY )), union (STRING , BOOLEAN , NUMBER , array (ANY )));
229
229
230
230
addExpressionSnippet (context , snippets , "-" , "lambda x, y: x - y" , NUMBER , union (BOOLEAN , NUMBER ), union (BOOLEAN , NUMBER ));
231
231
232
232
addExpressionSnippet (context , snippets , "/" , "lambda x, y: x / y" , NUMBER , PDivByZeroVerifier .INSTANCE , union (BOOLEAN , NUMBER ), union (BOOLEAN , NUMBER ));
233
233
234
- addExpressionSnippet (context , snippets , "list-from-foreign" , "lambda x: list(x)" , array (ANY ), union (STRING , iterable (ANY ), iterator (ANY ), array (ANY )));
234
+ // addExpressionSnippet(context, snippets, "list-from-foreign", "lambda x: list(x)", array(ANY), union(STRING, iterable(ANY), iterator(ANY), array(ANY)));
235
235
236
236
addExpressionSnippet (context , snippets , "==" , "lambda x, y: x == y" , BOOLEAN , ANY , ANY );
237
237
addExpressionSnippet (context , snippets , "!=" , "lambda x, y: x != y" , BOOLEAN , ANY , ANY );
@@ -266,10 +266,10 @@ public Collection<? extends Snippet> createStatements(Context context) {
266
266
" return False\n \n " +
267
267
"gen_if" , BOOLEAN , ANY );
268
268
269
- addStatementSnippet (context , snippets , "for" , "def gen_for(l):\n " +
270
- " for x in l:\n " +
271
- " return x\n \n " +
272
- "gen_for" , ANY , union (array (ANY ), iterable (ANY ), iterator (ANY ), STRING ));
269
+ // addStatementSnippet(context, snippets, "for", "def gen_for(l):\n" +
270
+ // " for x in l:\n" +
271
+ // " return x\n\n" +
272
+ // "gen_for", ANY, union(array(ANY), iterable(ANY), iterator(ANY), STRING));
273
273
274
274
// any exception honours the finally block, but non-exception cannot be raised
275
275
addStatementSnippet (context , snippets , "try-finally" , "def gen_tryfinally(exc):\n " +
@@ -350,7 +350,7 @@ private abstract static class PResultVerifier implements ResultVerifier {
350
350
/**
351
351
* Only accepts exact matches of types.
352
352
*/
353
- private static class PNoListCoercionVerifier extends PResultVerifier {
353
+ private static class AddVerifier extends PResultVerifier {
354
354
355
355
public void accept (SnippetRun snippetRun ) throws PolyglotException {
356
356
List <? extends Value > parameters = snippetRun .getParameters ();
@@ -363,14 +363,81 @@ public void accept(SnippetRun snippetRun) throws PolyglotException {
363
363
// ignore '(1,2) + [3,4]'.
364
364
if (par0 .hasArrayElements () && par1 .hasArrayElements ()) {
365
365
if (par0 .getMetaObject () == par1 .getMetaObject ()) {
366
- ResultVerifier .getDefaultResultVerifier ().accept (snippetRun );
366
+ assert snippetRun .getException () == null ;
367
+ TypeDescriptor resultType = TypeDescriptor .forValue (snippetRun .getResult ());
368
+ assert array (ANY ).isAssignable (resultType );
367
369
}
370
+ } else if (par0 .isString () && par1 .isString ()) {
371
+ assert snippetRun .getException () == null ;
372
+ TypeDescriptor resultType = TypeDescriptor .forValue (snippetRun .getResult ());
373
+ assert STRING .isAssignable (resultType );
374
+ } else if ((par0 .isNumber () || par0 .isBoolean ()) && (par1 .isNumber () || par1 .isBoolean ())) {
375
+ assert snippetRun .getException () == null ;
376
+ TypeDescriptor resultType = TypeDescriptor .forValue (snippetRun .getResult ());
377
+ assert NUMBER .isAssignable (resultType );
368
378
} else {
369
- ResultVerifier .getDefaultResultVerifier ().accept (snippetRun );
379
+ assert snippetRun .getException () != null ;
380
+ TypeDescriptor argType = union (STRING , BOOLEAN , NUMBER , array (ANY ));
381
+ TypeDescriptor par0Type = TypeDescriptor .forValue (par0 );
382
+ TypeDescriptor par1Type = TypeDescriptor .forValue (par1 );
383
+ if (!argType .isAssignable (par0Type ) || !argType .isAssignable (par1Type )) {
384
+ // argument type error, rethrow
385
+ throw snippetRun .getException ();
386
+ } else {
387
+ // arguments are ok, just don't work in this combination
388
+ }
389
+ }
390
+ }
391
+
392
+ private static final AddVerifier INSTANCE = new AddVerifier ();
393
+ }
394
+
395
+ private static class MulVerifier extends PResultVerifier {
396
+
397
+ private static boolean isStringMul (Value x , Value y ) {
398
+ return x .isString () && (y .isBoolean () || (y .isNumber () && y .fitsInInt ()));
399
+ }
400
+
401
+ private static boolean isArrayMul (Value x , Value y ) {
402
+ return x .hasArrayElements () && (y .isBoolean () || (y .isNumber () && (y .fitsInInt () || (y .fitsInLong () && y .asLong () < 0 ))));
403
+ }
404
+
405
+ public void accept (SnippetRun snippetRun ) throws PolyglotException {
406
+ List <? extends Value > parameters = snippetRun .getParameters ();
407
+ assert parameters .size () == 2 ;
408
+
409
+ Value par0 = parameters .get (0 );
410
+ Value par1 = parameters .get (1 );
411
+
412
+ if (isStringMul (par0 , par1 ) || isStringMul (par1 , par0 )) {
413
+ // string * number => string
414
+ assert snippetRun .getException () == null ;
415
+ TypeDescriptor resultType = TypeDescriptor .forValue (snippetRun .getResult ());
416
+ assert STRING .isAssignable (resultType );
417
+ } else if (isArrayMul (par0 , par1 ) || isArrayMul (par1 , par0 )) {
418
+ // array * number => array
419
+ assert snippetRun .getException () == null ;
420
+ TypeDescriptor resultType = TypeDescriptor .forValue (snippetRun .getResult ());
421
+ assert array (ANY ).isAssignable (resultType );
422
+ } else if ((par0 .isNumber () || par0 .isBoolean ()) && (par1 .isNumber () || par1 .isBoolean ())) {
423
+ assert snippetRun .getException () == null ;
424
+ TypeDescriptor resultType = TypeDescriptor .forValue (snippetRun .getResult ());
425
+ assert NUMBER .isAssignable (resultType );
426
+ } else {
427
+ assert snippetRun .getException () != null ;
428
+ TypeDescriptor argType = union (STRING , BOOLEAN , NUMBER , array (ANY ));
429
+ TypeDescriptor par0Type = TypeDescriptor .forValue (par0 );
430
+ TypeDescriptor par1Type = TypeDescriptor .forValue (par1 );
431
+ if (!argType .isAssignable (par0Type ) || !argType .isAssignable (par1Type )) {
432
+ // argument type error, rethrow
433
+ throw snippetRun .getException ();
434
+ } else {
435
+ // arguments are ok, just don't work in this combination
436
+ }
370
437
}
371
438
}
372
439
373
- private static final PNoListCoercionVerifier INSTANCE = new PNoListCoercionVerifier ();
440
+ private static final MulVerifier INSTANCE = new MulVerifier ();
374
441
}
375
442
376
443
/**
0 commit comments