@@ -247,12 +247,14 @@ export class EvaluationContext {
247
247
toInt ( this . evaluate ( expression . if ) ) !== 0 ? expression . then : expression . else ,
248
248
) ;
249
249
case 'comparison' :
250
+ const _lhs = this . evaluate ( expression . lhs ) ;
251
+ const _rhs = this . evaluate ( expression . rhs ) ;
250
252
return bool (
251
253
this . evaluateComparison (
252
254
expression . operator ,
253
255
expression . matchCase ?? configuration . ignorecase ,
254
- expression . lhs ,
255
- expression . rhs ,
256
+ _lhs ,
257
+ _rhs ,
256
258
) ,
257
259
) ;
258
260
default : {
@@ -511,81 +513,79 @@ export class EvaluationContext {
511
513
private evaluateComparison (
512
514
operator : ComparisonOp ,
513
515
matchCase : boolean ,
514
- lhsExpr : Expression ,
515
- rhsExpr : Expression ,
516
+ lhs : Value ,
517
+ rhs : Value ,
516
518
) : boolean {
517
519
switch ( operator ) {
518
520
case '==' :
519
- return this . evaluateBasicComparison ( '==' , matchCase , lhsExpr , rhsExpr ) ;
521
+ return this . evaluateBasicComparison ( '==' , matchCase , lhs , rhs ) ;
520
522
case '!=' :
521
- return ! this . evaluateBasicComparison ( '==' , matchCase , lhsExpr , rhsExpr ) ;
523
+ return ! this . evaluateBasicComparison ( '==' , matchCase , lhs , rhs ) ;
522
524
case '>' :
523
- return this . evaluateBasicComparison ( '>' , matchCase , lhsExpr , rhsExpr ) ;
525
+ return this . evaluateBasicComparison ( '>' , matchCase , lhs , rhs ) ;
524
526
case '>=' :
525
527
return (
526
- this . evaluateBasicComparison ( '>' , matchCase , lhsExpr , rhsExpr ) ||
527
- this . evaluateBasicComparison ( '==' , matchCase , lhsExpr , rhsExpr )
528
+ this . evaluateBasicComparison ( '>' , matchCase , lhs , rhs ) ||
529
+ this . evaluateBasicComparison ( '==' , matchCase , lhs , rhs )
528
530
) ;
529
531
case '<' :
530
- return this . evaluateBasicComparison ( '>' , matchCase , rhsExpr , lhsExpr ) ;
532
+ return this . evaluateBasicComparison ( '>' , matchCase , rhs , lhs ) ;
531
533
case '<=' :
532
- return ! this . evaluateBasicComparison ( '>' , matchCase , lhsExpr , rhsExpr ) ;
534
+ return ! this . evaluateBasicComparison ( '>' , matchCase , lhs , rhs ) ;
533
535
case '=~' :
534
- return this . evaluateBasicComparison ( '=~' , matchCase , lhsExpr , rhsExpr ) ;
536
+ return this . evaluateBasicComparison ( '=~' , matchCase , lhs , rhs ) ;
535
537
case '!~' :
536
- return ! this . evaluateBasicComparison ( '=~' , matchCase , lhsExpr , rhsExpr ) ;
538
+ return ! this . evaluateBasicComparison ( '=~' , matchCase , lhs , rhs ) ;
537
539
case 'is' :
538
- return this . evaluateBasicComparison ( 'is' , matchCase , lhsExpr , rhsExpr ) ;
540
+ return this . evaluateBasicComparison ( 'is' , matchCase , lhs , rhs ) ;
539
541
case 'isnot' :
540
- return ! this . evaluateBasicComparison ( 'is' , matchCase , lhsExpr , rhsExpr ) ;
542
+ return ! this . evaluateBasicComparison ( 'is' , matchCase , lhs , rhs ) ;
541
543
}
542
544
}
543
545
544
546
private evaluateBasicComparison (
545
547
operator : '==' | '>' | '=~' | 'is' ,
546
548
matchCase : boolean ,
547
- lhsExpr : Expression ,
548
- rhsExpr : Expression ,
549
+ lhs : Value ,
550
+ rhs : Value ,
549
551
topLevel : boolean = true ,
550
552
) : boolean {
551
- if ( operator === 'is' && lhsExpr . type !== rhsExpr . type ) {
553
+ if ( operator === 'is' && lhs . type !== rhs . type ) {
552
554
return false ;
553
555
}
554
556
555
- if ( lhsExpr . type === 'list' ) {
556
- if ( rhsExpr . type === 'list' ) {
557
+ if ( lhs . type === 'list' ) {
558
+ if ( rhs . type === 'list' ) {
557
559
switch ( operator ) {
558
560
case '==' :
561
+ const rhsItems = rhs . items ;
559
562
return (
560
- lhsExpr . items . length === rhsExpr . items . length &&
561
- lhsExpr . items . every ( ( left , idx ) =>
562
- this . evaluateBasicComparison ( '==' , matchCase , left , rhsExpr . items [ idx ] , false ) ,
563
+ lhs . items . length === rhsItems . length &&
564
+ lhs . items . every ( ( left , idx ) =>
565
+ this . evaluateBasicComparison ( '==' , matchCase , left , rhsItems [ idx ] , false ) ,
563
566
)
564
567
) ;
565
568
case 'is' :
566
- return lhsExpr . items === rhsExpr . items ;
569
+ return lhs . items === rhs . items ;
567
570
default :
568
571
throw VimError . fromCode ( ErrorCode . InvalidOperationForList ) ;
569
572
}
570
573
} else {
571
574
throw VimError . fromCode ( ErrorCode . CanOnlyCompareListWithList ) ;
572
575
}
573
- } else if ( rhsExpr . type === 'list' ) {
576
+ } else if ( rhs . type === 'list' ) {
574
577
throw VimError . fromCode ( ErrorCode . CanOnlyCompareListWithList ) ;
575
- } else if ( lhsExpr . type === 'dictionary' ) {
576
- if ( rhsExpr . type === 'dictionary' ) {
577
- const [ lhs , rhs ] = [ this . evaluate ( lhsExpr ) , this . evaluate ( rhsExpr ) ] as [
578
- DictionaryValue ,
579
- DictionaryValue ,
580
- ] ;
578
+ } else if ( lhs . type === 'dict_val' ) {
579
+ if ( rhs . type === 'dict_val' ) {
581
580
switch ( operator ) {
582
581
case '==' :
582
+ const rhsItems = rhs . items ;
583
583
return (
584
- lhs . items . size === rhs . items . size &&
584
+ lhs . items . size === rhsItems . size &&
585
585
[ ...lhs . items . entries ( ) ] . every (
586
586
( [ key , value ] ) =>
587
- rhs . items . has ( key ) &&
588
- this . evaluateBasicComparison ( '==' , matchCase , value , rhs . items . get ( key ) ! , false ) ,
587
+ rhsItems . has ( key ) &&
588
+ this . evaluateBasicComparison ( '==' , matchCase , value , rhsItems . get ( key ) ! , false ) ,
589
589
)
590
590
) ;
591
591
case 'is' :
@@ -596,14 +596,43 @@ export class EvaluationContext {
596
596
} else {
597
597
throw VimError . fromCode ( ErrorCode . CanOnlyCompareDictionaryWithDictionary ) ;
598
598
}
599
- } else if ( rhsExpr . type === 'dictionary ' ) {
599
+ } else if ( rhs . type === 'dict_val ' ) {
600
600
throw VimError . fromCode ( ErrorCode . CanOnlyCompareDictionaryWithDictionary ) ;
601
+ } else if ( lhs . type === 'funcref' ) {
602
+ if ( rhs . type === 'funcref' ) {
603
+ switch ( operator ) {
604
+ case '==' :
605
+ return lhs . name === rhs . name && lhs . dict === rhs . dict ;
606
+ case 'is' :
607
+ return lhs === rhs ;
608
+ default :
609
+ throw VimError . fromCode ( ErrorCode . InvalidOperationForFuncrefs ) ;
610
+ }
611
+ } else {
612
+ return false ;
613
+ }
614
+ } else if ( rhs . type === 'funcref' ) {
615
+ return false ;
616
+ } else if ( lhs . type === 'blob' ) {
617
+ if ( rhs . type === 'blob' ) {
618
+ switch ( operator ) {
619
+ case '==' :
620
+ const [ _lhs , _rhs ] = [ new Uint8Array ( lhs . data ) , new Uint8Array ( rhs . data ) ] ;
621
+ return _lhs . length === _rhs . length && _lhs . every ( ( byte , idx ) => byte === _rhs [ idx ] ) ;
622
+ case 'is' :
623
+ return lhs . data === rhs . data ;
624
+ default :
625
+ throw VimError . fromCode ( ErrorCode . InvalidOperationForBlob ) ;
626
+ }
627
+ } else {
628
+ throw VimError . fromCode ( ErrorCode . CanOnlyCompareBlobWithBlob ) ;
629
+ }
630
+ } else if ( rhs . type === 'blob' ) {
631
+ throw VimError . fromCode ( ErrorCode . CanOnlyCompareBlobWithBlob ) ;
601
632
} else {
602
- let [ lhs , rhs ] = [ this . evaluate ( lhsExpr ) , this . evaluate ( rhsExpr ) ] as [
603
- NumberValue | StringValue ,
604
- NumberValue | StringValue ,
605
- ] ;
606
- if ( lhs . type === 'number' || rhs . type === 'number' ) {
633
+ if ( lhs . type === 'float' || rhs . type === 'float' ) {
634
+ [ lhs , rhs ] = [ float ( toFloat ( lhs ) ) , float ( toFloat ( rhs ) ) ] ;
635
+ } else if ( lhs . type === 'number' || rhs . type === 'number' ) {
607
636
if ( topLevel ) {
608
637
// Strings are automatically coerced to numbers, except within a list/dict
609
638
// i.e. 4 == "4" but [4] != ["4"]
0 commit comments