@@ -3706,57 +3706,38 @@ private static int lengthOrZero(Object[] p) {
3706
3706
return p == null ? 0 : p .length ;
3707
3707
}
3708
3708
3709
- private void doVisitPattern (PatternTy .MatchMapping node , PatternContext pc ) {
3710
- ExprTy [] keys = node .keys ;
3711
- PatternTy [] patterns = node .patterns ;
3712
-
3713
- int key_len = lengthOrZero (keys );
3714
- int pat_len = lengthOrZero (patterns );
3715
-
3716
- if (key_len != pat_len ) {
3717
- ctx .errorCallback .onError (ErrorType .Syntax , node .getSourceRange (), "keys (%d) / patterns (%d) length mismatch in mapping pattern" , key_len , pat_len );
3718
- }
3719
-
3720
- String starTarget = node .rest ;
3721
- if (key_len == 0 && starTarget == null ) {
3722
- b .emitLoadConstant (false );
3723
- return ;
3724
- }
3725
- if (Integer .MAX_VALUE < key_len - 1 ) {
3726
- ctx .errorCallback .onError (ErrorType .Syntax , node .getSourceRange (), "too many sub-patterns in mapping pattern" );
3727
- }
3728
-
3729
- b .beginPrimitiveBoolAnd (); // AND for sanity checks (length matching, etc.)
3730
-
3731
- if (key_len > 0 ) {
3732
- // If the pattern has any keys in it, perform a length check:
3733
- b .beginGe ();
3734
- b .beginGetLen ();
3735
- b .emitLoadLocal (pc .subject );
3736
- b .endGetLen ();
3737
- b .emitLoadConstant (key_len );
3738
- b .endGe ();
3739
- }
3740
-
3741
- b .beginBlock ();
3742
-
3743
- // save pc.subject
3744
- BytecodeLocal pc_save = b .createLocal ();
3745
- b .beginStoreLocal (pc_save );
3746
- b .emitLoadLocal (pc .subject );
3747
- b .endStoreLocal ();
3748
-
3749
- // check that type matches
3750
- b .beginCheckTypeFlags (TypeFlags .MAPPING );
3709
+ /**
3710
+ * Checks if keys in pattern are, if present, longer than keys in subject. If yes, pattern should fail,
3711
+ * otherwise, we should continue with evaluation.
3712
+ *
3713
+ * Generates result of the comparison (boolean).
3714
+ *
3715
+ * @param keyLen Number of keys in pattern.
3716
+ * @param pc Pattern context.
3717
+ */
3718
+ private void checkPatternKeysLength (int keyLen , PatternContext pc ) {
3719
+ b .beginGe ();
3720
+ b .beginGetLen ();
3751
3721
b .emitLoadLocal (pc .subject );
3752
- b .endCheckTypeFlags ();
3722
+ b .endGetLen ();
3723
+ b .emitLoadConstant (keyLen );
3724
+ b .endGe ();
3725
+ }
3753
3726
3754
- // match keys and get array of values
3755
- BytecodeLocal keys_local = b .createLocal ();
3756
- b .beginStoreLocal (keys_local );
3757
- b .beginCollectToObjectArray ();
3727
+ /**
3728
+ * Will process pattern keys: Attributes evaluation and constant folding. Checks for duplicate keys and
3729
+ * that only literals and attributes lookups are being matched.
3730
+ *
3731
+ * Generates array.
3732
+ *
3733
+ * @param keys Pattern keys.
3734
+ * @param keyLen Length of pattern keys.
3735
+ * @param node Pattern matching node, for source range in errors.
3736
+ */
3737
+ private void processPatternKeys (ExprTy [] keys , int keyLen , PatternTy .MatchMapping node ) {
3738
+ b .beginCollectToObjectArray (); // keys (from pattern)
3758
3739
List <Object > seen = new ArrayList <>();
3759
- for (int i = 0 ; i < key_len ; i ++) {
3740
+ for (int i = 0 ; i < keyLen ; i ++) {
3760
3741
ExprTy key = keys [i ];
3761
3742
if (key instanceof ExprTy .Attribute ) {
3762
3743
key .accept (this );
@@ -3782,75 +3763,149 @@ private void doVisitPattern(PatternTy.MatchMapping node, PatternContext pc) {
3782
3763
}
3783
3764
}
3784
3765
b .endCollectToObjectArray ();
3785
- b .endStoreLocal ();
3786
-
3787
- // save match result AND values
3788
- BytecodeLocal key_match_and_values = b .createLocal ();
3789
- b .beginStoreLocal (key_match_and_values );
3790
- b .beginMatchKeys ();
3791
- b .emitLoadLocal (pc .subject );
3792
- b .emitLoadLocal (keys_local );
3793
- b .endMatchKeys ();
3794
- b .endStoreLocal ();
3795
-
3796
- BytecodeLocal temp = b .createLocal ();
3797
- b .beginStoreLocal (temp );
3798
-
3799
- b .beginPrimitiveBoolAnd (); // AND keys and values
3766
+ }
3800
3767
3801
- // emit if everything matched
3802
- b .beginArrayIndex (0 );
3803
- b .emitLoadLocal (key_match_and_values );
3804
- b .endArrayIndex ();
3768
+ /**
3769
+ * Visit all sub-patterns for mapping in pattern (not subject).
3770
+ *
3771
+ * Generates boolean value (AND of result of all sub-patterns).
3772
+ *
3773
+ * @param patterns Sub-patterns to iterate through.
3774
+ * @param values Patterns from subject to set as subject for evaluated sub-patterns.
3775
+ * @param pc Pattern context.
3776
+ */
3777
+ private void mappingVisitSubpatterns (PatternTy [] patterns , BytecodeLocal values , PatternContext pc ) {
3778
+ int patLen = patterns .length ;
3805
3779
3806
3780
b .beginBlock ();
3781
+ // unpack values from pc.subject
3782
+ BytecodeLocal valuesUnpacked = b .createLocal ();
3783
+ b .beginStoreLocal (valuesUnpacked );
3784
+ b .beginUnpackSequence (patLen );
3785
+ b .emitLoadLocal (values );
3786
+ b .endUnpackSequence ();
3787
+ b .endStoreLocal ();
3807
3788
3808
- // unpack values from pc.subject
3809
- BytecodeLocal values_unpacked = b .createLocal ();
3810
- b .beginStoreLocal (values_unpacked );
3811
- b .beginUnpackSequence (pat_len );
3812
- b .beginArrayIndex (1 );
3813
- b .emitLoadLocal (key_match_and_values );
3814
- b .endArrayIndex ();
3815
- b .endUnpackSequence ();
3816
- b .endStoreLocal ();
3817
-
3818
- b .beginPrimitiveBoolAnd (); // AND for sub-pats
3789
+ // backup pc.subject, it will get replaced for sub-patterns
3790
+ BytecodeLocal pcSave = b .createLocal ();
3791
+ b .beginStoreLocal (pcSave );
3792
+ b .emitLoadLocal (pc .subject );
3793
+ b .endStoreLocal ();
3819
3794
3820
- for (int i = 0 ; i < pat_len ; i ++) {
3821
- b .beginBlock ();
3795
+ BytecodeLocal temp = b .createLocal ();
3796
+ b .beginStoreLocal (temp );
3797
+ b .beginPrimitiveBoolAnd ();
3798
+ boolean hadNonWildcardPattern = false ;
3799
+ for (int i = 0 ; i < patLen ; i ++) {
3800
+ if (wildcardCheck (patterns [i ])) {
3801
+ continue ;
3802
+ }
3803
+ hadNonWildcardPattern = true ;
3804
+ b .beginBlock ();
3805
+ b .beginStoreLocal (pc .subject );
3806
+ b .beginArrayIndex (i );
3807
+ b .emitLoadLocal (valuesUnpacked );
3808
+ b .endArrayIndex ();
3809
+ b .endStoreLocal ();
3810
+
3811
+ visitSubpattern (patterns [i ], pc );
3812
+ b .endBlock ();
3813
+ }
3814
+ if (!hadNonWildcardPattern ) {
3815
+ b .emitLoadConstant (true );
3816
+ }
3817
+ b .endPrimitiveBoolAnd ();
3818
+ b .endStoreLocal ();
3822
3819
3823
3820
b .beginStoreLocal (pc .subject );
3824
- b .beginArrayIndex (i );
3825
- b .emitLoadLocal (values_unpacked );
3826
- b .endArrayIndex ();
3821
+ b .emitLoadLocal (pcSave );
3827
3822
b .endStoreLocal ();
3828
3823
3829
- visitSubpattern (patterns [i ], pc );
3830
-
3831
- b .endBlock ();
3832
- }
3824
+ b .emitLoadLocal (temp );
3825
+ b .endBlock ();
3826
+ }
3833
3827
3834
- b .emitLoadConstant (true );
3828
+ private void doVisitPattern (PatternTy .MatchMapping node , PatternContext pc ) {
3829
+ /**
3830
+ * Mapping pattern match will take the keys and check, whether the keys in the pattern are
3831
+ * present in the subject. This is good enough, since the pattern needs only to be a subset of the subject.
3832
+ * Keys aren't evaluated as subpatterns.
3833
+ *
3834
+ * After the key check, the values of the pattern are patterns as well and are evaluated as sub-patterns
3835
+ * with values in the subject used as separate respective subjects.
3836
+ */
3837
+ ExprTy [] keys = node .keys ;
3838
+ PatternTy [] patterns = node .patterns ;
3835
3839
3836
- b .endPrimitiveBoolAnd (); // AND for sub-pats
3840
+ int keyLen = lengthOrZero (keys );
3841
+ int patLen = lengthOrZero (patterns );
3837
3842
3838
- b .endBlock ();
3843
+ if (keyLen != patLen ) {
3844
+ ctx .errorCallback .onError (ErrorType .Syntax , node .getSourceRange (), "keys (%d) / patterns (%d) length mismatch in mapping pattern" , keyLen , patLen );
3845
+ }
3846
+ // @formatter:off
3839
3847
3840
- b .endPrimitiveBoolAnd (); // AND keys and values
3848
+ b .beginPrimitiveBoolAnd (); // AND for type, trivial and key length matching
3849
+ // check that type matches
3850
+ b .beginCheckTypeFlags (TypeFlags .MAPPING );
3851
+ b .emitLoadLocal (pc .subject );
3852
+ b .endCheckTypeFlags ();
3841
3853
3842
- b .endStoreLocal (); // temp
3854
+ String starTarget = node .rest ;
3855
+ if (keyLen == 0 && starTarget == null ) {
3856
+ b .emitLoadConstant (true );
3857
+ b .endPrimitiveBoolAnd ();
3858
+ return ;
3859
+ }
3860
+ if (Integer .MAX_VALUE < keyLen - 1 ) {
3861
+ ctx .errorCallback .onError (ErrorType .Syntax , node .getSourceRange (), "too many sub-patterns in mapping pattern" );
3862
+ }
3843
3863
3844
- // restore saved pc.subject
3845
- b . beginStoreLocal ( pc . subject );
3846
- b . emitLoadLocal ( pc_save );
3847
- b . endStoreLocal ();
3864
+ // If the pattern has any keys in it, perform a length check:
3865
+ if ( keyLen > 0 ) {
3866
+ checkPatternKeysLength ( keyLen , pc );
3867
+ }
3848
3868
3849
- b .emitLoadLocal (temp );
3869
+ b .beginBlock ();
3870
+ BytecodeLocal subjectPatterns = b .createLocal ();
3871
+ BytecodeLocal temp = b .createLocal ();
3872
+ BytecodeLocal keysChecked = b .createLocal ();
3873
+
3874
+ b .beginStoreLocal (temp );
3875
+ b .beginPrimitiveBoolAnd (); // AND process keys and sub-patterns
3876
+ b .beginBlock ();
3877
+ b .beginStoreLocal (keysChecked );
3878
+ processPatternKeys (keys , keyLen , node );
3879
+ b .endStoreLocal ();
3880
+
3881
+ // save match result together with values
3882
+ b .beginMatchKeys (subjectPatterns );
3883
+ b .emitLoadLocal (pc .subject );
3884
+ b .emitLoadLocal (keysChecked );
3885
+ b .endMatchKeys ();
3886
+ b .endBlock ();
3887
+
3888
+ if (patLen > 0 ) {
3889
+ mappingVisitSubpatterns (patterns , subjectPatterns , pc );
3890
+ }
3891
+ b .endPrimitiveBoolAnd (); // AND process keys and sub-patterns
3892
+ b .endStoreLocal (); // temp
3893
+
3894
+ if (starTarget != null ) {
3895
+ BytecodeLocal starVariable = pc .allocateBindVariable (starTarget );
3896
+ b .beginStoreLocal (starVariable );
3897
+ b .beginCopyDictWithoutKeys ();
3898
+ b .emitLoadLocal (pc .subject );
3899
+ b .emitLoadLocal (keysChecked );
3900
+ b .endCopyDictWithoutKeys ();
3901
+ b .endStoreLocal ();
3902
+ }
3850
3903
3851
- b .endBlock ();
3904
+ b .emitLoadLocal (temp );
3905
+ b .endBlock ();
3906
+ b .endPrimitiveBoolAnd (); // AND for key length matching
3852
3907
3853
- b . endPrimitiveBoolAnd (); // AND for sanity checks (length matching, etc.)
3908
+ // @formatter:on
3854
3909
}
3855
3910
3856
3911
private void checkAlternativePatternDifferentNames (Set <String > control , Map <String , BytecodeLocal > bindVariables ) {
0 commit comments