@@ -223,9 +223,8 @@ public Collection<? extends Snippet> createExpressions(Context context) {
223
223
List <Snippet > snippets = new ArrayList <>();
224
224
225
225
// @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 ));
226
+ 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 )));
227
+ 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
228
230
229
addExpressionSnippet (context , snippets , "-" , "lambda x, y: x - y" , NUMBER , union (BOOLEAN , NUMBER ), union (BOOLEAN , NUMBER ));
231
230
@@ -350,7 +349,7 @@ private abstract static class PResultVerifier implements ResultVerifier {
350
349
/**
351
350
* Only accepts exact matches of types.
352
351
*/
353
- private static class PNoListCoercionVerifier extends PResultVerifier {
352
+ private static class AddVerifier extends PResultVerifier {
354
353
355
354
public void accept (SnippetRun snippetRun ) throws PolyglotException {
356
355
List <? extends Value > parameters = snippetRun .getParameters ();
@@ -363,14 +362,81 @@ public void accept(SnippetRun snippetRun) throws PolyglotException {
363
362
// ignore '(1,2) + [3,4]'.
364
363
if (par0 .hasArrayElements () && par1 .hasArrayElements ()) {
365
364
if (par0 .getMetaObject () == par1 .getMetaObject ()) {
366
- ResultVerifier .getDefaultResultVerifier ().accept (snippetRun );
365
+ assert snippetRun .getException () == null ;
366
+ TypeDescriptor resultType = TypeDescriptor .forValue (snippetRun .getResult ());
367
+ assert array (ANY ).isAssignable (resultType );
367
368
}
369
+ } else if (par0 .isString () && par1 .isString ()) {
370
+ assert snippetRun .getException () == null ;
371
+ TypeDescriptor resultType = TypeDescriptor .forValue (snippetRun .getResult ());
372
+ assert STRING .isAssignable (resultType );
373
+ } else if ((par0 .isNumber () || par0 .isBoolean ()) && (par1 .isNumber () || par1 .isBoolean ())) {
374
+ assert snippetRun .getException () == null ;
375
+ TypeDescriptor resultType = TypeDescriptor .forValue (snippetRun .getResult ());
376
+ assert NUMBER .isAssignable (resultType );
368
377
} else {
369
- ResultVerifier .getDefaultResultVerifier ().accept (snippetRun );
378
+ assert snippetRun .getException () != null ;
379
+ TypeDescriptor argType = union (STRING , BOOLEAN , NUMBER , array (ANY ));
380
+ TypeDescriptor par0Type = TypeDescriptor .forValue (par0 );
381
+ TypeDescriptor par1Type = TypeDescriptor .forValue (par1 );
382
+ if (!argType .isAssignable (par0Type ) || !argType .isAssignable (par1Type )) {
383
+ // argument type error, rethrow
384
+ throw snippetRun .getException ();
385
+ } else {
386
+ // arguments are ok, just don't work in this combination
387
+ }
388
+ }
389
+ }
390
+
391
+ private static final AddVerifier INSTANCE = new AddVerifier ();
392
+ }
393
+
394
+ private static class MulVerifier extends PResultVerifier {
395
+
396
+ private static boolean isStringMul (Value x , Value y ) {
397
+ return x .isString () && (y .isBoolean () || (y .isNumber () && y .fitsInInt ()));
398
+ }
399
+
400
+ private static boolean isArrayMul (Value x , Value y ) {
401
+ return x .hasArrayElements () && (y .isBoolean () || (y .isNumber () && (y .fitsInInt () || (y .fitsInLong () && y .asLong () < 0 ))));
402
+ }
403
+
404
+ public void accept (SnippetRun snippetRun ) throws PolyglotException {
405
+ List <? extends Value > parameters = snippetRun .getParameters ();
406
+ assert parameters .size () == 2 ;
407
+
408
+ Value par0 = parameters .get (0 );
409
+ Value par1 = parameters .get (1 );
410
+
411
+ if (isStringMul (par0 , par1 ) || isStringMul (par1 , par0 )) {
412
+ // string * number => string
413
+ assert snippetRun .getException () == null ;
414
+ TypeDescriptor resultType = TypeDescriptor .forValue (snippetRun .getResult ());
415
+ assert STRING .isAssignable (resultType );
416
+ } else if (isArrayMul (par0 , par1 ) || isArrayMul (par1 , par0 )) {
417
+ // array * number => array
418
+ assert snippetRun .getException () == null ;
419
+ TypeDescriptor resultType = TypeDescriptor .forValue (snippetRun .getResult ());
420
+ assert array (ANY ).isAssignable (resultType );
421
+ } else if ((par0 .isNumber () || par0 .isBoolean ()) && (par1 .isNumber () || par1 .isBoolean ())) {
422
+ assert snippetRun .getException () == null ;
423
+ TypeDescriptor resultType = TypeDescriptor .forValue (snippetRun .getResult ());
424
+ assert NUMBER .isAssignable (resultType );
425
+ } else {
426
+ assert snippetRun .getException () != null ;
427
+ TypeDescriptor argType = union (STRING , BOOLEAN , NUMBER , array (ANY ));
428
+ TypeDescriptor par0Type = TypeDescriptor .forValue (par0 );
429
+ TypeDescriptor par1Type = TypeDescriptor .forValue (par1 );
430
+ if (!argType .isAssignable (par0Type ) || !argType .isAssignable (par1Type )) {
431
+ // argument type error, rethrow
432
+ throw snippetRun .getException ();
433
+ } else {
434
+ // arguments are ok, just don't work in this combination
435
+ }
370
436
}
371
437
}
372
438
373
- private static final PNoListCoercionVerifier INSTANCE = new PNoListCoercionVerifier ();
439
+ private static final MulVerifier INSTANCE = new MulVerifier ();
374
440
}
375
441
376
442
/**
0 commit comments