@@ -594,10 +594,11 @@ public RubyNode visitCallAndWriteNode(Nodes.CallAndWriteNode node) {
594
594
final var writeReceiverNode = receiverExpression .getWriteNode ();
595
595
final var readReceiver = receiverExpression .getReadYARPNode ();
596
596
597
- // Use Prism nodes and rely on CallNode translation to automatically set
598
- // fields like dispatchConfig and attribute-assignment flag (for `a.b = c`)
597
+ // Use Prism nodes and rely on CallNode translation to automatically set CallNode flags
598
+ // Ignore node.flags - it could be only SAFE_NAVIGATION that is handled manually
599
599
final RubyNode readNode = callNode (node , readReceiver , node .read_name , Nodes .Node .EMPTY_ARRAY ).accept (this );
600
- final RubyNode writeNode = callNode (node , readReceiver , node .write_name , node .value ).accept (this );
600
+ final RubyNode writeNode = callNode (node , Nodes .CallNodeFlags .ATTRIBUTE_WRITE , readReceiver , node .write_name ,
601
+ node .value ).accept (this );
601
602
final RubyNode andNode = AndNodeGen .create (readNode , writeNode );
602
603
603
604
final RubyNode sequence ;
@@ -622,15 +623,10 @@ public RubyNode visitCallNode(Nodes.CallNode node) {
622
623
var argumentsAndBlock = translateArgumentsAndBlock (node .arguments , node .block , methodName );
623
624
var translatedArguments = argumentsAndBlock .arguments ();
624
625
625
- // If the receiver is explicit or implicit 'self' then we can call private methods
626
+ // if the receiver is explicit or implicit 'self' then we can call private methods
626
627
final boolean ignoreVisibility = node .receiver == null || node .receiver instanceof Nodes .SelfNode ;
627
- final boolean isVariableCall = node .isVariableCall ();
628
- // This isn't fully accurate and doesn't handle cases like #===, #!=, a.foo=(42)
629
- // the issue is tracked in https://github.com/ruby/prism/issues/1715
630
- final boolean isAttrAssign = isAttrAssign (node .name );
631
- final boolean isSafeNavigation = node .isSafeNavigation ();
632
628
633
- if (environment .getParseEnvironment ().inCore () && isVariableCall && methodName .equals ("undefined" )) {
629
+ if (environment .getParseEnvironment ().inCore () && node . isVariableCall () && methodName .equals ("undefined" )) {
634
630
// translate undefined
635
631
final RubyNode rubyNode = new ObjectLiteralNode (NotProvided .INSTANCE );
636
632
return assignPositionAndFlags (node , rubyNode );
@@ -667,9 +663,9 @@ public RubyNode visitCallNode(Nodes.CallNode node) {
667
663
translatedArguments ,
668
664
argumentsAndBlock .isSplatted (),
669
665
ignoreVisibility ,
670
- isVariableCall ,
671
- isSafeNavigation ,
672
- isAttrAssign );
666
+ node . isVariableCall () ,
667
+ node . isSafeNavigation () ,
668
+ node . isAttributeWrite () );
673
669
final RubyNode callNode = language .coreMethodAssumptions .createCallNode (callNodeParameters );
674
670
675
671
final var rubyNode = wrapCallWithLiteralBlock (argumentsAndBlock , callNode );
@@ -776,14 +772,6 @@ private ArgumentsDescriptor getKeywordArgumentsDescriptor(Nodes.Node[] arguments
776
772
}
777
773
}
778
774
779
- private boolean isAttrAssign (String methodName ) {
780
- if (!methodName .endsWith ("=" ) || methodName .length () < 2 ) {
781
- return false ;
782
- }
783
- char before = methodName .charAt (methodName .length () - 2 );
784
- return before != '=' && before != '!' && before != '<' && before != '>' ;
785
- }
786
-
787
775
@ Override
788
776
public RubyNode visitCallOperatorWriteNode (Nodes .CallOperatorWriteNode node ) {
789
777
// e.g. `a.b += value` is translated into `a.b = a.b + value`,
@@ -795,11 +783,12 @@ public RubyNode visitCallOperatorWriteNode(Nodes.CallOperatorWriteNode node) {
795
783
final var writeReceiverNode = receiverExpression .getWriteNode ();
796
784
final var readReceiver = receiverExpression .getReadYARPNode ();
797
785
798
- // Use Prism nodes and rely on CallNode translation to automatically set
799
- // fields like dispatchConfig and attribute-assignment flag (for `a.b = c`)
786
+ // Use Prism nodes and rely on CallNode translation to automatically set CallNode flags
787
+ // Ignore node.flags - it could be only SAFE_NAVIGATION that is handled manually
800
788
final Nodes .Node read = callNode (node , readReceiver , node .read_name , Nodes .Node .EMPTY_ARRAY );
801
789
final Nodes .Node executeOperator = callNode (node , read , node .operator , node .value );
802
- final Nodes .Node write = callNode (node , readReceiver , node .write_name , executeOperator );
790
+ final Nodes .Node write = callNode (node , Nodes .CallNodeFlags .ATTRIBUTE_WRITE , readReceiver , node .write_name ,
791
+ executeOperator );
803
792
804
793
final RubyNode writeNode = write .accept (this );
805
794
final RubyNode rubyNode ;
@@ -828,10 +817,11 @@ public RubyNode visitCallOrWriteNode(Nodes.CallOrWriteNode node) {
828
817
final var writeReceiverNode = receiverExpression .getWriteNode ();
829
818
final var readReceiver = receiverExpression .getReadYARPNode ();
830
819
831
- // Use Prism nodes and rely on CallNode translation to automatically set
832
- // fields like dispatchConfig and attribute-assignment flag (for `a.b = c`)
820
+ // Use Prism nodes and rely on CallNode translation to automatically set CallNode flags
821
+ // Ignore node.flags - it could be only SAFE_NAVIGATION that is handled manually
833
822
final RubyNode readNode = callNode (node , readReceiver , node .read_name , Nodes .Node .EMPTY_ARRAY ).accept (this );
834
- final RubyNode writeNode = callNode (node , readReceiver , node .write_name , node .value ).accept (this );
823
+ final RubyNode writeNode = callNode (node , Nodes .CallNodeFlags .ATTRIBUTE_WRITE , readReceiver , node .write_name ,
824
+ node .value ).accept (this );
835
825
final RubyNode orNode = OrNodeGen .create (readNode , writeNode );
836
826
837
827
final RubyNode sequence ;
@@ -848,6 +838,23 @@ public RubyNode visitCallOrWriteNode(Nodes.CallOrWriteNode node) {
848
838
return assignPositionAndFlags (node , rubyNode );
849
839
}
850
840
841
+ public RubyNode visitCallTargetNode (Nodes .CallTargetNode node ) {
842
+ // extra argument should be added before node translation
843
+ // to trigger correctly replacement with inlined nodes (e.g. InlinedIndexSetNodeGen)
844
+ // that relies on arguments count
845
+ assert node .name .endsWith ("=" );
846
+
847
+ final Nodes .Node [] arguments = { new Nodes .NilNode (0 , 0 ) };
848
+ final var argumentsNode = new Nodes .ArgumentsNode (NO_FLAGS , arguments , 0 , 0 );
849
+
850
+ // Prism may set SAFE_NAVIGATION flag
851
+ short flags = (short ) (node .flags | Nodes .CallNodeFlags .ATTRIBUTE_WRITE );
852
+
853
+ final var callNode = new Nodes .CallNode (flags , node .receiver , node .name , argumentsNode , null ,
854
+ node .startOffset , node .length );
855
+ return callNode .accept (this );
856
+ }
857
+
851
858
@ Override
852
859
public RubyNode visitCapturePatternNode (Nodes .CapturePatternNode node ) {
853
860
return defaultVisit (node );
@@ -1800,6 +1807,7 @@ public RubyNode visitIndexOperatorWriteNode(Nodes.IndexOperatorWriteNode node) {
1800
1807
readArguments [i ] = expression .getReadYARPNode ();
1801
1808
}
1802
1809
1810
+ // Prism doesn't set any flag for IndexOperatorWriteNode right now
1803
1811
final Nodes .Node read = new Nodes .CallNode (NO_FLAGS , readReceiver , "[]" ,
1804
1812
new Nodes .ArgumentsNode (NO_FLAGS , readArguments , 0 , 0 ), blockArgument , 0 , 0 );
1805
1813
final Nodes .Node executeOperator = callNode (node , read , node .operator , node .value );
@@ -1808,7 +1816,7 @@ public RubyNode visitIndexOperatorWriteNode(Nodes.IndexOperatorWriteNode node) {
1808
1816
System .arraycopy (readArguments , 0 , readArgumentsAndResult , 0 , argumentsCount );
1809
1817
readArgumentsAndResult [argumentsCount ] = executeOperator ;
1810
1818
1811
- final Nodes .Node write = new Nodes .CallNode (NO_FLAGS , readReceiver , "[]=" ,
1819
+ final Nodes .Node write = new Nodes .CallNode (Nodes . CallNodeFlags . ATTRIBUTE_WRITE , readReceiver , "[]=" ,
1812
1820
new Nodes .ArgumentsNode (NO_FLAGS , readArgumentsAndResult , 0 , 0 ), blockArgument , 0 , 0 );
1813
1821
final RubyNode writeNode = write .accept (this );
1814
1822
final RubyNode writeArgumentsNode = sequence (Arrays .asList (writeArgumentsNodes ));
@@ -1839,6 +1847,43 @@ public RubyNode visitIndexOrWriteNode(Nodes.IndexOrWriteNode node) {
1839
1847
return assignPositionAndFlags (node , rubyNode );
1840
1848
}
1841
1849
1850
+ public RubyNode visitIndexTargetNode (Nodes .IndexTargetNode node ) {
1851
+ // extra argument should be added before node translation
1852
+ // to trigger correctly replacement with inlined nodes (e.g. InlinedIndexSetNodeGen)
1853
+ // that relies on arguments count
1854
+
1855
+ final Nodes .Node [] arguments ;
1856
+ final Nodes .ArgumentsNode argumentsNode ;
1857
+
1858
+ if (node .arguments == null ) {
1859
+ arguments = new Nodes .Node [1 ];
1860
+ } else {
1861
+ arguments = new Nodes .Node [node .arguments .arguments .length + 1 ];
1862
+ for (int i = 0 ; i < node .arguments .arguments .length ; i ++) {
1863
+ arguments [i ] = node .arguments .arguments [i ];
1864
+ }
1865
+ }
1866
+
1867
+ arguments [arguments .length - 1 ] = new Nodes .NilNode (0 , 0 );
1868
+
1869
+ if (node .arguments == null ) {
1870
+ argumentsNode = new Nodes .ArgumentsNode (NO_FLAGS , arguments , 0 , 0 );
1871
+ } else {
1872
+ argumentsNode = new Nodes .ArgumentsNode (node .arguments .flags , arguments , node .arguments .startOffset ,
1873
+ node .arguments .length );
1874
+ }
1875
+
1876
+ // Prism doesn't set any flag for IndexTargetNode right now
1877
+ // but let's still take flags into account as far as there may be additional flags or other changes
1878
+ short flags = (short ) (node .flags | Nodes .CallNodeFlags .ATTRIBUTE_WRITE );
1879
+
1880
+ final var callNode = new Nodes .CallNode (flags , node .receiver , "[]=" , argumentsNode , node .block ,
1881
+ node .startOffset ,
1882
+ node .length );
1883
+ return callNode .accept (this );
1884
+ }
1885
+
1886
+
1842
1887
private RubyNode translateIndexOrAndIndexAndWriteNodes (boolean isAndOperator , Nodes .Node receiver ,
1843
1888
Nodes .Node [] arguments , Nodes .Node block , Nodes .Node value ) {
1844
1889
// Handle both &&= and ||= operators:
@@ -1878,6 +1923,7 @@ private RubyNode translateIndexOrAndIndexAndWriteNodes(boolean isAndOperator, No
1878
1923
blockArgument = null ;
1879
1924
}
1880
1925
1926
+ // Prism doesn't set any flag for IndexAndWriteNode and IndexOrWriteNode right now
1881
1927
final Nodes .Node read = new Nodes .CallNode (NO_FLAGS , readReceiver , "[]" ,
1882
1928
new Nodes .ArgumentsNode (NO_FLAGS , readArguments , 0 , 0 ), blockArgument , 0 , 0 );
1883
1929
final RubyNode readNode = read .accept (this );
@@ -1886,7 +1932,7 @@ private RubyNode translateIndexOrAndIndexAndWriteNodes(boolean isAndOperator, No
1886
1932
System .arraycopy (readArguments , 0 , readArgumentsAndValue , 0 , arguments .length );
1887
1933
readArgumentsAndValue [arguments .length ] = value ;
1888
1934
1889
- final Nodes .Node write = new Nodes .CallNode (NO_FLAGS , readReceiver , "[]=" ,
1935
+ final Nodes .Node write = new Nodes .CallNode (Nodes . CallNodeFlags . ATTRIBUTE_WRITE , readReceiver , "[]=" ,
1890
1936
new Nodes .ArgumentsNode (NO_FLAGS , readArgumentsAndValue , 0 , 0 ), blockArgument , 0 , 0 );
1891
1937
final RubyNode writeNode = write .accept (this );
1892
1938
@@ -3109,51 +3155,12 @@ private RubyNode translateControlFlowArguments(Nodes.ArgumentsNode node) {
3109
3155
return assignPositionAndFlags (node , rubyNode );
3110
3156
}
3111
3157
3112
- private RubyNode translateRescueException (Nodes .Node exception ) {
3113
- final RubyNode rubyNode ;
3114
-
3115
- if (exception instanceof Nodes .CallNode callNode ) {
3116
- rubyNode = translateCallTargetNode (callNode );
3117
- } else {
3118
- rubyNode = exception .accept (this );
3119
- }
3120
-
3158
+ private RubyNode translateRescueException (Nodes .Node target ) {
3159
+ final RubyNode rubyNode = target .accept (this );
3121
3160
final AssignableNode assignableNode = (AssignableNode ) rubyNode ;
3122
3161
return new AssignRescueVariableNode (assignableNode );
3123
3162
}
3124
3163
3125
- public RubyNode translateCallTargetNode (Nodes .CallNode node ) {
3126
- // extra argument should be added before node translation
3127
- // to trigger correctly replacement with inlined nodes (e.g. InlinedIndexSetNodeGen)
3128
- // that relies on arguments count
3129
- if (node .name .endsWith ("=" )) {
3130
- final Nodes .Node [] arguments ;
3131
- final Nodes .ArgumentsNode argumentsNode ;
3132
-
3133
- if (node .arguments == null ) {
3134
- arguments = new Nodes .Node [1 ];
3135
- } else {
3136
- arguments = new Nodes .Node [node .arguments .arguments .length + 1 ];
3137
- for (int i = 0 ; i < node .arguments .arguments .length ; i ++) {
3138
- arguments [i ] = node .arguments .arguments [i ];
3139
- }
3140
- }
3141
-
3142
- arguments [arguments .length - 1 ] = new Nodes .NilNode (0 , 0 );
3143
-
3144
- if (node .arguments == null ) {
3145
- argumentsNode = new Nodes .ArgumentsNode (NO_FLAGS , arguments , 0 , 0 );
3146
- } else {
3147
- argumentsNode = new Nodes .ArgumentsNode (node .arguments .flags , arguments , node .arguments .startOffset ,
3148
- node .arguments .length );
3149
- }
3150
- node = new Nodes .CallNode (node .flags , node .receiver , node .name , argumentsNode , node .block , node .startOffset ,
3151
- node .length );
3152
- }
3153
-
3154
- return node .accept (this );
3155
- }
3156
-
3157
3164
private RubyNode translateWhileNode (Nodes .Node node , Nodes .Node predicate , Nodes .StatementsNode statements ,
3158
3165
boolean conditionInversed , boolean evaluateConditionBeforeBody ) {
3159
3166
RubyNode condition = predicate .accept (this );
@@ -3315,7 +3322,12 @@ protected static RubyNode sequence(List<RubyNode> sequence) {
3315
3322
3316
3323
protected static Nodes .CallNode callNode (Nodes .Node location , Nodes .Node receiver , String methodName ,
3317
3324
Nodes .Node ... arguments ) {
3318
- return new Nodes .CallNode (NO_FLAGS , receiver , methodName ,
3325
+ return callNode (location , NO_FLAGS , receiver , methodName , arguments );
3326
+ }
3327
+
3328
+ protected static Nodes .CallNode callNode (Nodes .Node location , short flags , Nodes .Node receiver , String methodName ,
3329
+ Nodes .Node ... arguments ) {
3330
+ return new Nodes .CallNode (flags , receiver , methodName ,
3319
3331
new Nodes .ArgumentsNode (NO_FLAGS , arguments , location .startOffset , location .length ), null ,
3320
3332
location .startOffset , location .length );
3321
3333
}
0 commit comments