Skip to content

Commit 99d03a3

Browse files
committed
Adopt CallNodeFlags.isAttributeWrite
1 parent 3493741 commit 99d03a3

File tree

3 files changed

+99
-75
lines changed

3 files changed

+99
-75
lines changed

src/main/java/org/truffleruby/parser/YARPMultiTargetNodeTranslator.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ public AssignableNode visitClassVariableTargetNode(Nodes.ClassVariableTargetNode
8989
}
9090

9191
@Override
92-
public AssignableNode visitCallNode(Nodes.CallNode node) {
93-
final RubyNode rubyNode = yarpTranslator.translateCallTargetNode(node);
92+
public AssignableNode visitCallTargetNode(Nodes.CallTargetNode node) {
93+
final RubyNode rubyNode = node.accept(yarpTranslator);
9494
return ((AssignableNode) rubyNode).toAssignableNode();
9595
}
9696

@@ -112,6 +112,12 @@ public AssignableNode visitGlobalVariableTargetNode(Nodes.GlobalVariableTargetNo
112112
return ((AssignableNode) rubyNode).toAssignableNode();
113113
}
114114

115+
@Override
116+
public AssignableNode visitIndexTargetNode(Nodes.IndexTargetNode node) {
117+
final RubyNode rubyNode = node.accept(yarpTranslator);
118+
return ((AssignableNode) rubyNode).toAssignableNode();
119+
}
120+
115121
@Override
116122
public AssignableNode visitInstanceVariableTargetNode(Nodes.InstanceVariableTargetNode node) {
117123
final RubyNode rubyNode = node.accept(yarpTranslator);

src/main/java/org/truffleruby/parser/YARPMultiWriteNodeTranslator.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ public AssignableNode visitClassVariableTargetNode(Nodes.ClassVariableTargetNode
7676
}
7777

7878
@Override
79-
public AssignableNode visitCallNode(Nodes.CallNode node) {
80-
final RubyNode rubyNode = yarpTranslator.translateCallTargetNode(node);
79+
public AssignableNode visitCallTargetNode(Nodes.CallTargetNode node) {
80+
final RubyNode rubyNode = node.accept(yarpTranslator);
8181
return ((AssignableNode) rubyNode).toAssignableNode();
8282
}
8383

@@ -99,6 +99,12 @@ public AssignableNode visitGlobalVariableTargetNode(Nodes.GlobalVariableTargetNo
9999
return ((AssignableNode) rubyNode).toAssignableNode();
100100
}
101101

102+
@Override
103+
public AssignableNode visitIndexTargetNode(Nodes.IndexTargetNode node) {
104+
final RubyNode rubyNode = node.accept(yarpTranslator);
105+
return ((AssignableNode) rubyNode).toAssignableNode();
106+
}
107+
102108
@Override
103109
public AssignableNode visitInstanceVariableTargetNode(Nodes.InstanceVariableTargetNode node) {
104110
final RubyNode rubyNode = node.accept(yarpTranslator);

src/main/java/org/truffleruby/parser/YARPTranslator.java

Lines changed: 83 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -594,10 +594,11 @@ public RubyNode visitCallAndWriteNode(Nodes.CallAndWriteNode node) {
594594
final var writeReceiverNode = receiverExpression.getWriteNode();
595595
final var readReceiver = receiverExpression.getReadYARPNode();
596596

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
599599
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);
601602
final RubyNode andNode = AndNodeGen.create(readNode, writeNode);
602603

603604
final RubyNode sequence;
@@ -622,15 +623,10 @@ public RubyNode visitCallNode(Nodes.CallNode node) {
622623
var argumentsAndBlock = translateArgumentsAndBlock(node.arguments, node.block, methodName);
623624
var translatedArguments = argumentsAndBlock.arguments();
624625

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
626627
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();
632628

633-
if (environment.getParseEnvironment().inCore() && isVariableCall && methodName.equals("undefined")) {
629+
if (environment.getParseEnvironment().inCore() && node.isVariableCall() && methodName.equals("undefined")) {
634630
// translate undefined
635631
final RubyNode rubyNode = new ObjectLiteralNode(NotProvided.INSTANCE);
636632
return assignPositionAndFlags(node, rubyNode);
@@ -667,9 +663,9 @@ public RubyNode visitCallNode(Nodes.CallNode node) {
667663
translatedArguments,
668664
argumentsAndBlock.isSplatted(),
669665
ignoreVisibility,
670-
isVariableCall,
671-
isSafeNavigation,
672-
isAttrAssign);
666+
node.isVariableCall(),
667+
node.isSafeNavigation(),
668+
node.isAttributeWrite());
673669
final RubyNode callNode = language.coreMethodAssumptions.createCallNode(callNodeParameters);
674670

675671
final var rubyNode = wrapCallWithLiteralBlock(argumentsAndBlock, callNode);
@@ -776,14 +772,6 @@ private ArgumentsDescriptor getKeywordArgumentsDescriptor(Nodes.Node[] arguments
776772
}
777773
}
778774

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-
787775
@Override
788776
public RubyNode visitCallOperatorWriteNode(Nodes.CallOperatorWriteNode node) {
789777
// e.g. `a.b += value` is translated into `a.b = a.b + value`,
@@ -795,11 +783,12 @@ public RubyNode visitCallOperatorWriteNode(Nodes.CallOperatorWriteNode node) {
795783
final var writeReceiverNode = receiverExpression.getWriteNode();
796784
final var readReceiver = receiverExpression.getReadYARPNode();
797785

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
800788
final Nodes.Node read = callNode(node, readReceiver, node.read_name, Nodes.Node.EMPTY_ARRAY);
801789
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);
803792

804793
final RubyNode writeNode = write.accept(this);
805794
final RubyNode rubyNode;
@@ -828,10 +817,11 @@ public RubyNode visitCallOrWriteNode(Nodes.CallOrWriteNode node) {
828817
final var writeReceiverNode = receiverExpression.getWriteNode();
829818
final var readReceiver = receiverExpression.getReadYARPNode();
830819

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
833822
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);
835825
final RubyNode orNode = OrNodeGen.create(readNode, writeNode);
836826

837827
final RubyNode sequence;
@@ -848,6 +838,23 @@ public RubyNode visitCallOrWriteNode(Nodes.CallOrWriteNode node) {
848838
return assignPositionAndFlags(node, rubyNode);
849839
}
850840

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+
851858
@Override
852859
public RubyNode visitCapturePatternNode(Nodes.CapturePatternNode node) {
853860
return defaultVisit(node);
@@ -1800,6 +1807,7 @@ public RubyNode visitIndexOperatorWriteNode(Nodes.IndexOperatorWriteNode node) {
18001807
readArguments[i] = expression.getReadYARPNode();
18011808
}
18021809

1810+
// Prism doesn't set any flag for IndexOperatorWriteNode right now
18031811
final Nodes.Node read = new Nodes.CallNode(NO_FLAGS, readReceiver, "[]",
18041812
new Nodes.ArgumentsNode(NO_FLAGS, readArguments, 0, 0), blockArgument, 0, 0);
18051813
final Nodes.Node executeOperator = callNode(node, read, node.operator, node.value);
@@ -1808,7 +1816,7 @@ public RubyNode visitIndexOperatorWriteNode(Nodes.IndexOperatorWriteNode node) {
18081816
System.arraycopy(readArguments, 0, readArgumentsAndResult, 0, argumentsCount);
18091817
readArgumentsAndResult[argumentsCount] = executeOperator;
18101818

1811-
final Nodes.Node write = new Nodes.CallNode(NO_FLAGS, readReceiver, "[]=",
1819+
final Nodes.Node write = new Nodes.CallNode(Nodes.CallNodeFlags.ATTRIBUTE_WRITE, readReceiver, "[]=",
18121820
new Nodes.ArgumentsNode(NO_FLAGS, readArgumentsAndResult, 0, 0), blockArgument, 0, 0);
18131821
final RubyNode writeNode = write.accept(this);
18141822
final RubyNode writeArgumentsNode = sequence(Arrays.asList(writeArgumentsNodes));
@@ -1839,6 +1847,43 @@ public RubyNode visitIndexOrWriteNode(Nodes.IndexOrWriteNode node) {
18391847
return assignPositionAndFlags(node, rubyNode);
18401848
}
18411849

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+
18421887
private RubyNode translateIndexOrAndIndexAndWriteNodes(boolean isAndOperator, Nodes.Node receiver,
18431888
Nodes.Node[] arguments, Nodes.Node block, Nodes.Node value) {
18441889
// Handle both &&= and ||= operators:
@@ -1878,6 +1923,7 @@ private RubyNode translateIndexOrAndIndexAndWriteNodes(boolean isAndOperator, No
18781923
blockArgument = null;
18791924
}
18801925

1926+
// Prism doesn't set any flag for IndexAndWriteNode and IndexOrWriteNode right now
18811927
final Nodes.Node read = new Nodes.CallNode(NO_FLAGS, readReceiver, "[]",
18821928
new Nodes.ArgumentsNode(NO_FLAGS, readArguments, 0, 0), blockArgument, 0, 0);
18831929
final RubyNode readNode = read.accept(this);
@@ -1886,7 +1932,7 @@ private RubyNode translateIndexOrAndIndexAndWriteNodes(boolean isAndOperator, No
18861932
System.arraycopy(readArguments, 0, readArgumentsAndValue, 0, arguments.length);
18871933
readArgumentsAndValue[arguments.length] = value;
18881934

1889-
final Nodes.Node write = new Nodes.CallNode(NO_FLAGS, readReceiver, "[]=",
1935+
final Nodes.Node write = new Nodes.CallNode(Nodes.CallNodeFlags.ATTRIBUTE_WRITE, readReceiver, "[]=",
18901936
new Nodes.ArgumentsNode(NO_FLAGS, readArgumentsAndValue, 0, 0), blockArgument, 0, 0);
18911937
final RubyNode writeNode = write.accept(this);
18921938

@@ -3109,51 +3155,12 @@ private RubyNode translateControlFlowArguments(Nodes.ArgumentsNode node) {
31093155
return assignPositionAndFlags(node, rubyNode);
31103156
}
31113157

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);
31213160
final AssignableNode assignableNode = (AssignableNode) rubyNode;
31223161
return new AssignRescueVariableNode(assignableNode);
31233162
}
31243163

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-
31573164
private RubyNode translateWhileNode(Nodes.Node node, Nodes.Node predicate, Nodes.StatementsNode statements,
31583165
boolean conditionInversed, boolean evaluateConditionBeforeBody) {
31593166
RubyNode condition = predicate.accept(this);
@@ -3315,7 +3322,12 @@ protected static RubyNode sequence(List<RubyNode> sequence) {
33153322

33163323
protected static Nodes.CallNode callNode(Nodes.Node location, Nodes.Node receiver, String methodName,
33173324
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,
33193331
new Nodes.ArgumentsNode(NO_FLAGS, arguments, location.startOffset, location.length), null,
33203332
location.startOffset, location.length);
33213333
}

0 commit comments

Comments
 (0)