Skip to content

Commit a6f5a6f

Browse files
eregonandrykonchin
authored andcommitted
Introduce YARPBaseTranslator
1 parent 65fdeba commit a6f5a6f

12 files changed

+296
-240
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,12 @@ public ReadLocalVariableNode readNode(int slot, SourceIndexLength sourceSection)
276276
return node;
277277
}
278278

279+
public ReadLocalVariableNode readNode(int slot, Nodes.Node yarpNode) {
280+
var node = new ReadLocalVariableNode(LocalVariableType.FRAME_LOCAL, slot);
281+
node.unsafeSetSourceSection(yarpNode.startOffset, yarpNode.length);
282+
return node;
283+
}
284+
279285
public RubyNode findLocalVarOrNilNode(String name, SourceIndexLength sourceSection) {
280286
RubyNode node = findLocalVarNode(name, sourceSection);
281287
if (node == null) {
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
/*
2+
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. This
3+
* code is released under a tri EPL/GPL/LGPL license. You can use it,
4+
* redistribute it and/or modify it under the terms of the:
5+
*
6+
* Eclipse Public License version 2.0, or
7+
* GNU General Public License version 2, or
8+
* GNU Lesser General Public License version 2.1.
9+
*/
10+
package org.truffleruby.parser;
11+
12+
import java.util.List;
13+
14+
import org.prism.AbstractNodeVisitor;
15+
import org.prism.Nodes;
16+
import org.truffleruby.RubyLanguage;
17+
import org.truffleruby.core.DummyNode;
18+
import org.truffleruby.core.encoding.RubyEncoding;
19+
import org.truffleruby.core.encoding.TStringUtils;
20+
import org.truffleruby.language.RubyContextSourceNode;
21+
import org.truffleruby.language.RubyNode;
22+
import org.truffleruby.language.arguments.NoKeywordArgumentsDescriptor;
23+
import org.truffleruby.language.control.SequenceNode;
24+
import org.truffleruby.language.dispatch.RubyCallNodeParameters;
25+
import org.truffleruby.language.literal.NilLiteralNode;
26+
27+
import com.oracle.truffle.api.TruffleSafepoint;
28+
import com.oracle.truffle.api.source.Source;
29+
import com.oracle.truffle.api.source.SourceSection;
30+
import com.oracle.truffle.api.strings.TruffleString;
31+
32+
public abstract class YARPBaseTranslator extends AbstractNodeVisitor<RubyNode> {
33+
34+
protected final RubyLanguage language;
35+
protected final TranslatorEnvironment environment;
36+
protected final RubySource rubySource;
37+
38+
// For convenient/concise access, actually redundant with the rubySource field
39+
protected final Source source;
40+
protected final byte[] sourceBytes;
41+
protected final RubyEncoding sourceEncoding;
42+
43+
public static final Nodes.Node[] EMPTY_NODE_ARRAY = Nodes.Node.EMPTY_ARRAY;
44+
45+
public static final Nodes.ParametersNode ZERO_PARAMETERS_NODE = new Nodes.ParametersNode(EMPTY_NODE_ARRAY,
46+
EMPTY_NODE_ARRAY, null, EMPTY_NODE_ARRAY, EMPTY_NODE_ARRAY, null, null, 0, 0);
47+
48+
public static final short NO_FLAGS = 0;
49+
50+
public YARPBaseTranslator(
51+
RubyLanguage language,
52+
TranslatorEnvironment environment,
53+
RubySource rubySource) {
54+
this.language = language;
55+
this.environment = environment;
56+
this.rubySource = rubySource;
57+
this.source = rubySource.getSource();
58+
this.sourceBytes = rubySource.getBytes();
59+
this.sourceEncoding = rubySource.getEncoding();
60+
}
61+
62+
public final TranslatorEnvironment getEnvironment() {
63+
return environment;
64+
}
65+
66+
@Override
67+
protected RubyNode defaultVisit(Nodes.Node node) {
68+
String code = toString(node);
69+
throw new Error(
70+
this.getClass().getSimpleName() + " does not know how to translate " + node.getClass().getSimpleName() +
71+
" at " + RubyLanguage.getCurrentContext().fileLine(getSourceSection(node)) +
72+
"\nCode snippet:\n" + code + "\nPrism AST:\n" + node);
73+
}
74+
75+
protected static RubyNode[] createArray(int size) {
76+
return size == 0 ? RubyNode.EMPTY_ARRAY : new RubyNode[size];
77+
}
78+
79+
protected final RubyNode translateNodeOrNil(Nodes.Node node) {
80+
final RubyNode rubyNode;
81+
if (node == null) {
82+
rubyNode = new NilLiteralNode();
83+
} else {
84+
rubyNode = node.accept(this);
85+
}
86+
return rubyNode;
87+
}
88+
89+
protected final RubyNode translateNodeOrDeadNode(Nodes.Node node, String label) {
90+
if (node != null) {
91+
return node.accept(this);
92+
} else {
93+
return new DeadNode(label);
94+
}
95+
}
96+
97+
protected final RubyContextSourceNode createCallNode(RubyNode receiver, String method, RubyNode... arguments) {
98+
return createCallNode(true, receiver, method, arguments);
99+
}
100+
101+
protected final RubyContextSourceNode createCallNode(boolean ignoreVisibility, RubyNode receiver, String method,
102+
RubyNode... arguments) {
103+
var parameters = new RubyCallNodeParameters(
104+
receiver,
105+
method,
106+
null,
107+
NoKeywordArgumentsDescriptor.INSTANCE,
108+
arguments,
109+
ignoreVisibility);
110+
return language.coreMethodAssumptions.createCallNode(parameters);
111+
}
112+
113+
protected static Nodes.CallNode callNode(Nodes.Node location, Nodes.Node receiver, String methodName,
114+
Nodes.Node... arguments) {
115+
return callNode(location, NO_FLAGS, receiver, methodName, arguments);
116+
}
117+
118+
protected static Nodes.CallNode callNode(Nodes.Node location, short flags, Nodes.Node receiver, String methodName,
119+
Nodes.Node... arguments) {
120+
return new Nodes.CallNode(flags, receiver, methodName,
121+
new Nodes.ArgumentsNode(NO_FLAGS, arguments, location.startOffset, location.length), null,
122+
location.startOffset, location.length);
123+
}
124+
125+
protected final TruffleString toTString(Nodes.Node node) {
126+
return TruffleString.fromByteArrayUncached(sourceBytes, node.startOffset, node.length, sourceEncoding.tencoding,
127+
false);
128+
}
129+
130+
protected final TruffleString toTString(String string) {
131+
return TStringUtils.fromJavaString(string, sourceEncoding);
132+
}
133+
134+
protected final String toString(Nodes.Node node) {
135+
return TStringUtils.toJavaStringOrThrow(toTString(node), sourceEncoding);
136+
}
137+
138+
protected final TruffleString toTString(byte[] bytes) {
139+
return TruffleString.fromByteArrayUncached(bytes, sourceEncoding.tencoding, false);
140+
}
141+
142+
protected final String toString(byte[] bytes) {
143+
return TStringUtils.toJavaStringOrThrow(toTString(bytes), sourceEncoding);
144+
}
145+
146+
protected final SourceSection getSourceSection(Nodes.Node yarpNode) {
147+
return source.createSection(yarpNode.startOffset, yarpNode.length);
148+
}
149+
150+
public final RubyNode assignPositionAndFlags(Nodes.Node yarpNode, RubyNode rubyNode) {
151+
assignPositionOnly(yarpNode, rubyNode);
152+
copyNewlineFlag(yarpNode, rubyNode);
153+
return rubyNode;
154+
}
155+
156+
public final RubyNode assignPositionAndFlagsIfMissing(Nodes.Node yarpNode, RubyNode rubyNode) {
157+
if (rubyNode.hasSource()) {
158+
return rubyNode;
159+
}
160+
161+
assignPositionOnly(yarpNode, rubyNode);
162+
copyNewlineFlag(yarpNode, rubyNode);
163+
return rubyNode;
164+
}
165+
166+
protected static void assignPositionOnly(Nodes.Node yarpNode, RubyNode rubyNode) {
167+
rubyNode.unsafeSetSourceSection(yarpNode.startOffset, yarpNode.length);
168+
}
169+
170+
// assign position based on a list of nodes (arguments list, exception classes list in a rescue section, etc)
171+
protected final void assignPositionOnly(Nodes.Node[] nodes, RubyNode rubyNode) {
172+
final Nodes.Node first = nodes[0];
173+
final Nodes.Node last = nodes[nodes.length - 1];
174+
175+
final int length = last.endOffset() - first.startOffset;
176+
rubyNode.unsafeSetSourceSection(first.startOffset, length);
177+
}
178+
179+
protected final void copyNewlineFlag(Nodes.Node yarpNode, RubyNode rubyNode) {
180+
if (yarpNode.hasNewLineFlag()) {
181+
TruffleSafepoint.poll(DummyNode.INSTANCE);
182+
183+
if (environment.getParseEnvironment().isCoverageEnabled()) {
184+
rubyNode.unsafeSetIsCoverageLine();
185+
int startLine = environment.getParseEnvironment().yarpSource.line(yarpNode.startOffset);
186+
language.coverageManager.setLineHasCode(source, startLine);
187+
}
188+
189+
rubyNode.unsafeSetIsNewLine();
190+
}
191+
}
192+
193+
protected static RubyNode sequence(Nodes.Node yarpNode, List<RubyNode> sequence) {
194+
assert !yarpNode.hasNewLineFlag() : "Expected node passed to sequence() to not have a newline flag";
195+
196+
RubyNode sequenceNode = sequence(sequence);
197+
198+
if (!sequenceNode.hasSource()) {
199+
assignPositionOnly(yarpNode, sequenceNode);
200+
}
201+
202+
return sequenceNode;
203+
}
204+
205+
protected static RubyNode sequence(List<RubyNode> sequence) {
206+
final List<RubyNode> flattened = Translator.flatten(sequence, true);
207+
208+
if (flattened.isEmpty()) {
209+
return new NilLiteralNode();
210+
} else if (flattened.size() == 1) {
211+
return flattened.get(0);
212+
} else {
213+
final RubyNode[] flatSequence = flattened.toArray(RubyNode.EMPTY_ARRAY);
214+
return new SequenceNode(flatSequence);
215+
}
216+
}
217+
218+
protected final RubyNode[] translate(Nodes.Node[] nodes) {
219+
if (nodes.length == 0) {
220+
return RubyNode.EMPTY_ARRAY;
221+
}
222+
223+
RubyNode[] rubyNodes = new RubyNode[nodes.length];
224+
225+
for (int i = 0; i < nodes.length; i++) {
226+
rubyNodes[i] = nodes[i].accept(this);
227+
}
228+
229+
return rubyNodes;
230+
}
231+
232+
}

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

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,13 @@
1212
import com.oracle.truffle.api.RootCallTarget;
1313
import com.oracle.truffle.api.nodes.Node;
1414
import com.oracle.truffle.api.nodes.NodeUtil;
15-
import com.oracle.truffle.api.source.Source;
1615
import com.oracle.truffle.api.source.SourceSection;
1716
import org.prism.Nodes;
1817
import org.truffleruby.RubyLanguage;
1918
import org.truffleruby.annotations.Split;
2019
import org.truffleruby.core.IsNilNode;
2120
import org.truffleruby.core.cast.SplatCastNode;
2221
import org.truffleruby.core.cast.SplatCastNodeGen;
23-
import org.truffleruby.core.encoding.RubyEncoding;
2422
import org.truffleruby.core.proc.ProcCallTargets;
2523
import org.truffleruby.core.proc.ProcType;
2624
import org.truffleruby.language.RubyLambdaRootNode;
@@ -45,18 +43,17 @@
4543
import java.util.function.Supplier;
4644

4745
public final class YARPBlockNodeTranslator extends YARPTranslator {
46+
4847
private final Arity arity;
4948

5049
public YARPBlockNodeTranslator(
5150
RubyLanguage language,
5251
TranslatorEnvironment environment,
53-
byte[] sourceBytes,
54-
Source source,
55-
RubyEncoding sourceEncoding,
52+
RubySource rubySource,
5653
ParserContext parserContext,
5754
Node currentNode,
5855
Arity arity) {
59-
super(language, environment, sourceBytes, source, sourceEncoding, parserContext, currentNode);
56+
super(language, environment, rubySource, parserContext, currentNode);
6057
this.arity = arity;
6158
}
6259

@@ -66,9 +63,10 @@ public RubyNode compileBlockNode(Nodes.Node body, Nodes.ParametersNode parameter
6663
declareLocalVariables(locals);
6764

6865
final RubyNode loadArguments = new YARPLoadArgumentsTranslator(
69-
parameters,
7066
language,
7167
environment,
68+
rubySource,
69+
parameters,
7270
arity,
7371
!isStabbyLambda,
7472
false,
@@ -166,10 +164,11 @@ private RubyNode preludeProc(
166164
final RubyNode readArrayNode = new ReadLocalVariableNode(LocalVariableType.FRAME_LOCAL, arraySlot);
167165

168166
final var translator = new YARPParametersNodeToDestructureTranslator(
167+
language,
168+
environment,
169+
rubySource,
169170
parameters,
170171
readArrayNode,
171-
environment,
172-
language,
173172
this);
174173
final RubyNode newDestructureArguments = translator.translate();
175174

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

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,25 @@
1313

1414
import org.truffleruby.RubyLanguage;
1515
import org.truffleruby.annotations.Split;
16-
import org.truffleruby.core.encoding.RubyEncoding;
1716
import org.truffleruby.language.RubyMethodRootNode;
1817
import org.truffleruby.language.RubyNode;
1918
import org.truffleruby.language.methods.Arity;
2019
import org.truffleruby.language.methods.CachedLazyCallTargetSupplier;
2120

2221
import com.oracle.truffle.api.nodes.Node;
23-
import com.oracle.truffle.api.source.Source;
2422
import org.prism.Nodes;
2523

2624
public final class YARPDefNodeTranslator extends YARPTranslator {
25+
2726
private final boolean shouldLazyTranslate;
2827

2928
public YARPDefNodeTranslator(
3029
RubyLanguage language,
3130
TranslatorEnvironment environment,
32-
byte[] sourceBytes,
33-
Source source,
34-
RubyEncoding sourceEncoding,
31+
RubySource rubySource,
3532
ParserContext parserContext,
3633
Node currentNode) {
37-
super(language, environment, sourceBytes, source, sourceEncoding, parserContext, currentNode);
34+
super(language, environment, rubySource, parserContext, currentNode);
3835

3936
if (parserContext.isEval() || environment.getParseEnvironment().isCoverageEnabled()) {
4037
shouldLazyTranslate = false;
@@ -49,9 +46,10 @@ private RubyNode compileMethodBody(Nodes.DefNode node, Nodes.ParametersNode para
4946
declareLocalVariables(node);
5047

5148
final RubyNode loadArguments = new YARPLoadArgumentsTranslator(
52-
parameters,
5349
language,
5450
environment,
51+
rubySource,
52+
parameters,
5553
arity,
5654
false,
5755
true,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
/** Similar to ValueFromNode class but for YARP nodes */
2020
public final class YARPExecutedOnceExpression {
21+
2122
final String name;
2223
final int slot;
2324
final Nodes.Node node;

0 commit comments

Comments
 (0)