@@ -82,12 +82,13 @@ public class PythonProvider implements LanguageProvider {
8282
8383 private static final String ID = "python" ;
8484
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 ;
8990 private static final TypeDescriptor COMPLEX = intersection (OBJECT );
90- private static final TypeDescriptor NONE = intersection ( OBJECT , NULL ) ;
91+ private static final TypeDescriptor NONE = NULL ;
9192 private static final TypeDescriptor STR = intersection (OBJECT , STRING , ITERABLE , array (STRING ));
9293 private static final TypeDescriptor BYTES = intersection (OBJECT , ITERABLE , array (INT ));
9394 private static final TypeDescriptor BYTEARRAY = intersection (OBJECT , ITERABLE , array (INT ));
@@ -223,15 +224,14 @@ public Collection<? extends Snippet> createExpressions(Context context) {
223224 List <Snippet > snippets = new ArrayList <>();
224225
225226 // @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 )));
229229
230230 addExpressionSnippet (context , snippets , "-" , "lambda x, y: x - y" , NUMBER , union (BOOLEAN , NUMBER ), union (BOOLEAN , NUMBER ));
231231
232232 addExpressionSnippet (context , snippets , "/" , "lambda x, y: x / y" , NUMBER , PDivByZeroVerifier .INSTANCE , union (BOOLEAN , NUMBER ), union (BOOLEAN , NUMBER ));
233233
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)));
235235
236236 addExpressionSnippet (context , snippets , "==" , "lambda x, y: x == y" , BOOLEAN , ANY , ANY );
237237 addExpressionSnippet (context , snippets , "!=" , "lambda x, y: x != y" , BOOLEAN , ANY , ANY );
@@ -266,10 +266,10 @@ public Collection<? extends Snippet> createStatements(Context context) {
266266 " return False\n \n " +
267267 "gen_if" , BOOLEAN , ANY );
268268
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));
273273
274274 // any exception honours the finally block, but non-exception cannot be raised
275275 addStatementSnippet (context , snippets , "try-finally" , "def gen_tryfinally(exc):\n " +
@@ -350,7 +350,7 @@ private abstract static class PResultVerifier implements ResultVerifier {
350350 /**
351351 * Only accepts exact matches of types.
352352 */
353- private static class PNoListCoercionVerifier extends PResultVerifier {
353+ private static class AddVerifier extends PResultVerifier {
354354
355355 public void accept (SnippetRun snippetRun ) throws PolyglotException {
356356 List <? extends Value > parameters = snippetRun .getParameters ();
@@ -363,14 +363,81 @@ public void accept(SnippetRun snippetRun) throws PolyglotException {
363363 // ignore '(1,2) + [3,4]'.
364364 if (par0 .hasArrayElements () && par1 .hasArrayElements ()) {
365365 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 );
367369 }
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 );
368378 } 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+ }
370437 }
371438 }
372439
373- private static final PNoListCoercionVerifier INSTANCE = new PNoListCoercionVerifier ();
440+ private static final MulVerifier INSTANCE = new MulVerifier ();
374441 }
375442
376443 /**
0 commit comments