13514
|
1 /*
|
|
2 * Copyright (c) 2013 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 1.0
|
|
7 * GNU General Public License version 2
|
|
8 * GNU Lesser General Public License version 2.1
|
|
9 */
|
|
10 package com.oracle.truffle.ruby.parser;
|
|
11
|
|
12 import java.math.*;
|
|
13 import java.util.*;
|
|
14 import java.util.regex.*;
|
|
15
|
|
16 import com.oracle.truffle.api.*;
|
|
17 import com.oracle.truffle.api.frame.*;
|
|
18 import com.oracle.truffle.api.impl.*;
|
|
19 import com.oracle.truffle.ruby.nodes.*;
|
|
20 import com.oracle.truffle.ruby.nodes.call.*;
|
|
21 import com.oracle.truffle.ruby.nodes.cast.*;
|
|
22 import com.oracle.truffle.ruby.nodes.constants.*;
|
|
23 import com.oracle.truffle.ruby.nodes.control.*;
|
|
24 import com.oracle.truffle.ruby.nodes.core.*;
|
|
25 import com.oracle.truffle.ruby.nodes.debug.*;
|
|
26 import com.oracle.truffle.ruby.nodes.literal.*;
|
|
27 import com.oracle.truffle.ruby.nodes.literal.array.*;
|
|
28 import com.oracle.truffle.ruby.nodes.methods.*;
|
|
29 import com.oracle.truffle.ruby.nodes.methods.locals.*;
|
|
30 import com.oracle.truffle.ruby.nodes.objects.*;
|
|
31 import com.oracle.truffle.ruby.nodes.objects.instancevariables.*;
|
|
32 import com.oracle.truffle.ruby.nodes.yield.*;
|
|
33 import com.oracle.truffle.ruby.runtime.*;
|
|
34 import com.oracle.truffle.ruby.runtime.core.*;
|
|
35 import com.oracle.truffle.ruby.runtime.core.range.*;
|
|
36 import com.oracle.truffle.ruby.runtime.debug.*;
|
|
37 import com.oracle.truffle.ruby.runtime.methods.*;
|
|
38
|
|
39 /**
|
|
40 * A JRuby parser node visitor which translates JRuby AST nodes into our Ruby nodes, implementing a
|
|
41 * Ruby parser. Therefore there is some namespace contention here! We make all references to JRuby
|
|
42 * explicit. This is the only place though - it doesn't leak out elsewhere.
|
|
43 */
|
|
44 public class Translator implements org.jrubyparser.NodeVisitor {
|
|
45
|
|
46 protected final Translator parent;
|
|
47
|
|
48 protected final RubyContext context;
|
|
49 protected final TranslatorEnvironment environment;
|
|
50 protected final Source source;
|
|
51
|
|
52 private boolean translatingForStatement = false;
|
|
53
|
|
54 private static final Map<Class, String> nodeDefinedNames = new HashMap<>();
|
|
55
|
|
56 static {
|
|
57 nodeDefinedNames.put(org.jrubyparser.ast.SelfNode.class, "self");
|
|
58 nodeDefinedNames.put(org.jrubyparser.ast.NilNode.class, "nil");
|
|
59 nodeDefinedNames.put(org.jrubyparser.ast.TrueNode.class, "true");
|
|
60 nodeDefinedNames.put(org.jrubyparser.ast.FalseNode.class, "false");
|
|
61 nodeDefinedNames.put(org.jrubyparser.ast.LocalAsgnNode.class, "assignment");
|
|
62 nodeDefinedNames.put(org.jrubyparser.ast.DAsgnNode.class, "assignment");
|
|
63 nodeDefinedNames.put(org.jrubyparser.ast.GlobalAsgnNode.class, "assignment");
|
|
64 nodeDefinedNames.put(org.jrubyparser.ast.InstAsgnNode.class, "assignment");
|
|
65 nodeDefinedNames.put(org.jrubyparser.ast.ClassVarAsgnNode.class, "assignment");
|
|
66 nodeDefinedNames.put(org.jrubyparser.ast.OpAsgnAndNode.class, "assignment");
|
|
67 nodeDefinedNames.put(org.jrubyparser.ast.OpAsgnOrNode.class, "assignment");
|
|
68 nodeDefinedNames.put(org.jrubyparser.ast.OpAsgnNode.class, "assignment");
|
|
69 nodeDefinedNames.put(org.jrubyparser.ast.OpElementAsgnNode.class, "assignment");
|
|
70 nodeDefinedNames.put(org.jrubyparser.ast.MultipleAsgnNode.class, "assignment");
|
|
71 nodeDefinedNames.put(org.jrubyparser.ast.GlobalVarNode.class, "global-variable");
|
|
72 nodeDefinedNames.put(org.jrubyparser.ast.StrNode.class, "expression");
|
|
73 nodeDefinedNames.put(org.jrubyparser.ast.DStrNode.class, "expression");
|
|
74 nodeDefinedNames.put(org.jrubyparser.ast.FixnumNode.class, "expression");
|
|
75 nodeDefinedNames.put(org.jrubyparser.ast.BignumNode.class, "expression");
|
|
76 nodeDefinedNames.put(org.jrubyparser.ast.FloatNode.class, "expression");
|
|
77 nodeDefinedNames.put(org.jrubyparser.ast.RegexpNode.class, "expression");
|
|
78 nodeDefinedNames.put(org.jrubyparser.ast.DRegexpNode.class, "expression");
|
|
79 nodeDefinedNames.put(org.jrubyparser.ast.ArrayNode.class, "expression");
|
|
80 nodeDefinedNames.put(org.jrubyparser.ast.HashNode.class, "expression");
|
|
81 nodeDefinedNames.put(org.jrubyparser.ast.SymbolNode.class, "expression");
|
|
82 nodeDefinedNames.put(org.jrubyparser.ast.DotNode.class, "expression");
|
|
83 nodeDefinedNames.put(org.jrubyparser.ast.NotNode.class, "expression");
|
|
84 nodeDefinedNames.put(org.jrubyparser.ast.AndNode.class, "expression");
|
|
85 nodeDefinedNames.put(org.jrubyparser.ast.OrNode.class, "expression");
|
|
86 nodeDefinedNames.put(org.jrubyparser.ast.LocalVarNode.class, "local-variable");
|
|
87 nodeDefinedNames.put(org.jrubyparser.ast.DVarNode.class, "local-variable");
|
|
88 }
|
|
89
|
|
90 /**
|
|
91 * Global variables which in common usage have frame local semantics.
|
|
92 */
|
|
93 public static final Set<String> FRAME_LOCAL_GLOBAL_VARIABLES = new HashSet<>(Arrays.asList("$_"));
|
|
94
|
|
95 public Translator(RubyContext context, Translator parent, TranslatorEnvironment environment, Source source) {
|
|
96 this.context = context;
|
|
97 this.parent = parent;
|
|
98 this.environment = environment;
|
|
99 this.source = source;
|
|
100 }
|
|
101
|
|
102 @Override
|
|
103 public Object visitAliasNode(org.jrubyparser.ast.AliasNode node) {
|
|
104 final SourceSection sourceSection = translate(node.getPosition());
|
|
105
|
|
106 final org.jrubyparser.ast.LiteralNode oldName = (org.jrubyparser.ast.LiteralNode) node.getOldName();
|
|
107 final org.jrubyparser.ast.LiteralNode newName = (org.jrubyparser.ast.LiteralNode) node.getNewName();
|
|
108
|
|
109 final ClassNode classNode = new ClassNode(context, sourceSection, new SelfNode(context, sourceSection));
|
|
110
|
|
111 return new AliasNode(context, sourceSection, classNode, newName.getName(), oldName.getName());
|
|
112 }
|
|
113
|
|
114 @Override
|
|
115 public Object visitAndNode(org.jrubyparser.ast.AndNode node) {
|
|
116 final SourceSection sourceSection = translate(node.getPosition());
|
|
117
|
|
118 RubyNode x;
|
|
119
|
|
120 if (node.getFirst() == null) {
|
|
121 x = new NilNode(context, sourceSection);
|
|
122 } else {
|
|
123 x = (RubyNode) node.getFirst().accept(this);
|
|
124 }
|
|
125
|
|
126 RubyNode y;
|
|
127
|
|
128 if (node.getSecond() == null) {
|
|
129 y = new NilNode(context, sourceSection);
|
|
130 } else {
|
|
131 y = (RubyNode) node.getSecond().accept(this);
|
|
132 }
|
|
133
|
|
134 return AndNodeFactory.create(context, sourceSection, x, y);
|
|
135 }
|
|
136
|
|
137 @Override
|
|
138 public Object visitArgsCatNode(org.jrubyparser.ast.ArgsCatNode node) {
|
|
139 final List<org.jrubyparser.ast.Node> nodes = new ArrayList<>();
|
|
140 collectArgsCatNodes(nodes, node);
|
|
141
|
|
142 final List<RubyNode> translatedNodes = new ArrayList<>();
|
|
143
|
|
144 for (org.jrubyparser.ast.Node catNode : nodes) {
|
|
145 translatedNodes.add((RubyNode) catNode.accept(this));
|
|
146 }
|
|
147
|
|
148 return new ArrayConcatNode(context, translate(node.getPosition()), translatedNodes.toArray(new RubyNode[translatedNodes.size()]));
|
|
149 }
|
|
150
|
|
151 // ArgsCatNodes can be nested - this collects them into a flat list of children
|
|
152 private void collectArgsCatNodes(List<org.jrubyparser.ast.Node> nodes, org.jrubyparser.ast.ArgsCatNode node) {
|
|
153 if (node.getFirst() instanceof org.jrubyparser.ast.ArgsCatNode) {
|
|
154 collectArgsCatNodes(nodes, (org.jrubyparser.ast.ArgsCatNode) node.getFirst());
|
|
155 } else {
|
|
156 nodes.add(node.getFirst());
|
|
157 }
|
|
158
|
|
159 if (node.getSecond() instanceof org.jrubyparser.ast.ArgsCatNode) {
|
|
160 collectArgsCatNodes(nodes, (org.jrubyparser.ast.ArgsCatNode) node.getSecond());
|
|
161 } else {
|
|
162 nodes.add(node.getSecond());
|
|
163 }
|
|
164 }
|
|
165
|
|
166 @Override
|
|
167 public Object visitArgsNode(org.jrubyparser.ast.ArgsNode node) {
|
|
168 return unimplemented(node);
|
|
169 }
|
|
170
|
|
171 @Override
|
|
172 public Object visitArgsPushNode(org.jrubyparser.ast.ArgsPushNode node) {
|
|
173 return new ArrayPushNode(context, translate(node.getPosition()), (RubyNode) node.getFirstNode().accept(this), (RubyNode) node.getSecondNode().accept(this));
|
|
174 }
|
|
175
|
|
176 @Override
|
|
177 public Object visitArrayNode(org.jrubyparser.ast.ArrayNode node) {
|
|
178 final List<org.jrubyparser.ast.Node> values = node.childNodes();
|
|
179
|
|
180 final RubyNode[] translatedValues = new RubyNode[values.size()];
|
|
181
|
|
182 for (int n = 0; n < values.size(); n++) {
|
|
183 translatedValues[n] = (RubyNode) values.get(n).accept(this);
|
|
184 }
|
|
185
|
|
186 return new UninitialisedArrayLiteralNode(context, translate(node.getPosition()), translatedValues);
|
|
187 }
|
|
188
|
|
189 @Override
|
|
190 public Object visitAttrAssignNode(org.jrubyparser.ast.AttrAssignNode node) {
|
|
191 return visitAttrAssignNodeExtraArgument(node, null);
|
|
192 }
|
|
193
|
|
194 /**
|
|
195 * See translateDummyAssignment to understand what this is for.
|
|
196 */
|
|
197 public RubyNode visitAttrAssignNodeExtraArgument(org.jrubyparser.ast.AttrAssignNode node, RubyNode extraArgument) {
|
|
198 final org.jrubyparser.ast.CallNode callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), node.getReceiver(), node.getName(), node.getArgs());
|
|
199 return visitCallNodeExtraArgument(callNode, extraArgument);
|
|
200 }
|
|
201
|
|
202 @Override
|
|
203 public Object visitBackRefNode(org.jrubyparser.ast.BackRefNode node) {
|
|
204 return unimplemented(node);
|
|
205 }
|
|
206
|
|
207 @Override
|
|
208 public Object visitBeginNode(org.jrubyparser.ast.BeginNode node) {
|
|
209 return node.getBody().accept(this);
|
|
210 }
|
|
211
|
|
212 @Override
|
|
213 public Object visitBignumNode(org.jrubyparser.ast.BignumNode node) {
|
|
214 return new BignumLiteralNode(context, translate(node.getPosition()), node.getValue());
|
|
215 }
|
|
216
|
|
217 @Override
|
|
218 public Object visitBlockArg18Node(org.jrubyparser.ast.BlockArg18Node node) {
|
|
219 return unimplemented(node);
|
|
220 }
|
|
221
|
|
222 @Override
|
|
223 public Object visitBlockArgNode(org.jrubyparser.ast.BlockArgNode node) {
|
|
224 return unimplemented(node);
|
|
225 }
|
|
226
|
|
227 @Override
|
|
228 public Object visitBlockNode(org.jrubyparser.ast.BlockNode node) {
|
|
229 final List<org.jrubyparser.ast.Node> children = node.childNodes();
|
|
230
|
|
231 final List<RubyNode> translatedChildren = new ArrayList<>();
|
|
232
|
|
233 for (int n = 0; n < children.size(); n++) {
|
|
234 final RubyNode translatedChild = (RubyNode) children.get(n).accept(this);
|
|
235
|
|
236 if (!(translatedChild instanceof DeadNode)) {
|
|
237 translatedChildren.add(translatedChild);
|
|
238 }
|
|
239 }
|
|
240
|
|
241 if (translatedChildren.size() == 1) {
|
|
242 return translatedChildren.get(0);
|
|
243 } else {
|
|
244 return new SequenceNode(context, translate(node.getPosition()), translatedChildren.toArray(new RubyNode[translatedChildren.size()]));
|
|
245 }
|
|
246 }
|
|
247
|
|
248 @Override
|
|
249 public Object visitBlockPassNode(org.jrubyparser.ast.BlockPassNode node) {
|
|
250 return unimplemented(node);
|
|
251 }
|
|
252
|
|
253 @Override
|
|
254 public Object visitBreakNode(org.jrubyparser.ast.BreakNode node) {
|
|
255 final SourceSection sourceSection = translate(node.getPosition());
|
|
256
|
|
257 RubyNode resultNode;
|
|
258
|
|
259 if (node.getValueNode() == null) {
|
|
260 resultNode = new NilNode(context, sourceSection);
|
|
261 } else {
|
|
262 resultNode = (RubyNode) node.getValueNode().accept(this);
|
|
263 }
|
|
264
|
|
265 return new BreakNode(context, sourceSection, resultNode);
|
|
266 }
|
|
267
|
|
268 @Override
|
|
269 public Object visitCallNode(org.jrubyparser.ast.CallNode node) {
|
|
270 return visitCallNodeExtraArgument(node, null);
|
|
271 }
|
|
272
|
|
273 /**
|
|
274 * See translateDummyAssignment to understand what this is for.
|
|
275 */
|
|
276 public RubyNode visitCallNodeExtraArgument(org.jrubyparser.ast.CallNode node, RubyNode extraArgument) {
|
|
277 final SourceSection sourceSection = translate(node.getPosition());
|
|
278
|
|
279 final RubyNode receiverTranslated = (RubyNode) node.getReceiver().accept(this);
|
|
280
|
|
281 org.jrubyparser.ast.Node args = node.getArgs();
|
|
282 org.jrubyparser.ast.Node block = node.getIter();
|
|
283
|
|
284 if (block == null && args instanceof org.jrubyparser.ast.IterNode) {
|
|
285 final org.jrubyparser.ast.Node temp = args;
|
|
286 args = block;
|
|
287 block = temp;
|
|
288 }
|
|
289
|
|
290 final ArgumentsAndBlockTranslation argumentsAndBlock = translateArgumentsAndBlock(sourceSection, block, args, extraArgument);
|
|
291
|
|
292 return new CallNode(context, sourceSection, node.getName(), receiverTranslated, argumentsAndBlock.getBlock(), argumentsAndBlock.isSplatted(), argumentsAndBlock.getArguments());
|
|
293 }
|
|
294
|
|
295 protected class ArgumentsAndBlockTranslation {
|
|
296
|
|
297 private final RubyNode block;
|
|
298 private final RubyNode[] arguments;
|
|
299 private final boolean isSplatted;
|
|
300
|
|
301 public ArgumentsAndBlockTranslation(RubyNode block, RubyNode[] arguments, boolean isSplatted) {
|
|
302 super();
|
|
303 this.block = block;
|
|
304 this.arguments = arguments;
|
|
305 this.isSplatted = isSplatted;
|
|
306 }
|
|
307
|
|
308 public RubyNode getBlock() {
|
|
309 return block;
|
|
310 }
|
|
311
|
|
312 public RubyNode[] getArguments() {
|
|
313 return arguments;
|
|
314 }
|
|
315
|
|
316 public boolean isSplatted() {
|
|
317 return isSplatted;
|
|
318 }
|
|
319
|
|
320 }
|
|
321
|
|
322 protected ArgumentsAndBlockTranslation translateArgumentsAndBlock(SourceSection sourceSection, org.jrubyparser.ast.Node iterNode, org.jrubyparser.ast.Node argsNode, RubyNode extraArgument) {
|
|
323 assert !(argsNode instanceof org.jrubyparser.ast.IterNode);
|
|
324
|
|
325 final List<org.jrubyparser.ast.Node> arguments = new ArrayList<>();
|
|
326 org.jrubyparser.ast.Node blockPassNode = null;
|
|
327
|
|
328 boolean isSplatted = false;
|
|
329
|
|
330 if (argsNode instanceof org.jrubyparser.ast.ListNode) {
|
|
331 arguments.addAll(((org.jrubyparser.ast.ListNode) argsNode).childNodes());
|
|
332 } else if (argsNode instanceof org.jrubyparser.ast.BlockPassNode) {
|
|
333 final org.jrubyparser.ast.BlockPassNode blockPass = (org.jrubyparser.ast.BlockPassNode) argsNode;
|
|
334
|
|
335 final org.jrubyparser.ast.Node blockPassArgs = blockPass.getArgs();
|
|
336
|
|
337 if (blockPassArgs instanceof org.jrubyparser.ast.ListNode) {
|
|
338 arguments.addAll(((org.jrubyparser.ast.ListNode) blockPassArgs).childNodes());
|
|
339 } else if (blockPassArgs instanceof org.jrubyparser.ast.ArgsCatNode) {
|
|
340 arguments.add(blockPassArgs);
|
|
341 } else if (blockPassArgs != null) {
|
|
342 throw new UnsupportedOperationException("Don't know how to block pass " + blockPassArgs);
|
|
343 }
|
|
344
|
|
345 blockPassNode = blockPass.getBody();
|
|
346 } else if (argsNode instanceof org.jrubyparser.ast.SplatNode) {
|
|
347 isSplatted = true;
|
|
348 arguments.add(argsNode);
|
|
349 } else if (argsNode instanceof org.jrubyparser.ast.ArgsCatNode) {
|
|
350 isSplatted = true;
|
|
351 arguments.add(argsNode);
|
|
352 } else if (argsNode != null) {
|
|
353 isSplatted = true;
|
|
354 arguments.add(argsNode);
|
|
355 }
|
|
356
|
|
357 RubyNode blockTranslated;
|
|
358
|
|
359 if (blockPassNode != null && iterNode != null) {
|
|
360 throw new UnsupportedOperationException("Don't know how to pass both an block and a block-pass argument");
|
|
361 } else if (iterNode != null) {
|
|
362 blockTranslated = (BlockDefinitionNode) iterNode.accept(this);
|
|
363 } else if (blockPassNode != null) {
|
|
364 blockTranslated = ProcCastNodeFactory.create(context, sourceSection, (RubyNode) blockPassNode.accept(this));
|
|
365 } else {
|
|
366 blockTranslated = null;
|
|
367 }
|
|
368
|
|
369 final List<RubyNode> argumentsTranslated = new ArrayList<>();
|
|
370
|
|
371 for (org.jrubyparser.ast.Node argument : arguments) {
|
|
372 argumentsTranslated.add((RubyNode) argument.accept(this));
|
|
373 }
|
|
374
|
|
375 if (extraArgument != null) {
|
|
376 argumentsTranslated.add(extraArgument);
|
|
377 }
|
|
378
|
|
379 final RubyNode[] argumentsTranslatedArray = argumentsTranslated.toArray(new RubyNode[argumentsTranslated.size()]);
|
|
380
|
|
381 return new ArgumentsAndBlockTranslation(blockTranslated, argumentsTranslatedArray, isSplatted);
|
|
382 }
|
|
383
|
|
384 @Override
|
|
385 public Object visitCaseNode(org.jrubyparser.ast.CaseNode node) {
|
|
386 final SourceSection sourceSection = translate(node.getPosition());
|
|
387
|
|
388 RubyNode elseNode;
|
|
389
|
|
390 if (node.getElse() != null) {
|
|
391 elseNode = (RubyNode) node.getElse().accept(this);
|
|
392 } else {
|
|
393 elseNode = new NilNode(context, sourceSection);
|
|
394 }
|
|
395
|
|
396 /*
|
|
397 * There are two sorts of case - one compares a list of expressions against a value, the
|
|
398 * other just checks a list of expressions for truth.
|
|
399 */
|
|
400
|
|
401 if (node.getCase() != null) {
|
|
402 // Evaluate the case expression and store it in a local
|
|
403
|
|
404 final String tempName = environment.allocateLocalTemp();
|
|
405
|
|
406 final RubyNode readTemp = environment.findLocalVarNode(tempName, sourceSection);
|
|
407
|
|
408 final RubyNode assignTemp = ((ReadNode) readTemp).makeWriteNode((RubyNode) node.getCase().accept(this));
|
|
409
|
|
410 /*
|
|
411 * Build an if expression from the whens and else. Work backwards because the first if
|
|
412 * contains all the others in its else clause.
|
|
413 */
|
|
414
|
|
415 for (int n = node.getCases().size() - 1; n >= 0; n--) {
|
|
416 final org.jrubyparser.ast.WhenNode when = (org.jrubyparser.ast.WhenNode) node.getCases().get(n);
|
|
417
|
|
418 // Make a condition from the one or more expressions combined in an or expression
|
|
419
|
|
420 final List<org.jrubyparser.ast.Node> expressions;
|
|
421
|
|
422 if (when.getExpression() instanceof org.jrubyparser.ast.ListNode) {
|
|
423 expressions = ((org.jrubyparser.ast.ListNode) when.getExpression()).childNodes();
|
|
424 } else {
|
|
425 expressions = Arrays.asList(when.getExpression());
|
|
426 }
|
|
427
|
|
428 final List<RubyNode> comparisons = new ArrayList<>();
|
|
429
|
|
430 for (org.jrubyparser.ast.Node expressionNode : expressions) {
|
|
431 final RubyNode rubyExpression = (RubyNode) expressionNode.accept(this);
|
|
432
|
|
433 final CallNode comparison = new CallNode(context, sourceSection, "===", rubyExpression, null, false, new RubyNode[]{environment.findLocalVarNode(tempName, sourceSection)});
|
|
434
|
|
435 comparisons.add(comparison);
|
|
436 }
|
|
437
|
|
438 RubyNode conditionNode = comparisons.get(comparisons.size() - 1);
|
|
439
|
|
440 // As with the if nodes, we work backwards to make it left associative
|
|
441
|
|
442 for (int i = comparisons.size() - 2; i >= 0; i--) {
|
|
443 conditionNode = OrNodeFactory.create(context, sourceSection, comparisons.get(i), conditionNode);
|
|
444 }
|
|
445
|
|
446 // Create the if node
|
|
447
|
|
448 final BooleanCastNode conditionCastNode = BooleanCastNodeFactory.create(context, sourceSection, conditionNode);
|
|
449
|
|
450 RubyNode thenNode;
|
|
451
|
|
452 if (when.getBody() == null) {
|
|
453 thenNode = new NilNode(context, sourceSection);
|
|
454 } else {
|
|
455 thenNode = (RubyNode) when.getBody().accept(this);
|
|
456 }
|
|
457
|
|
458 final IfNode ifNode = new IfNode(context, sourceSection, conditionCastNode, thenNode, elseNode);
|
|
459
|
|
460 // This if becomes the else for the next if
|
|
461
|
|
462 elseNode = ifNode;
|
|
463 }
|
|
464
|
|
465 final RubyNode ifNode = elseNode;
|
|
466
|
|
467 // A top-level block assigns the temp then runs the if
|
|
468
|
|
469 return new SequenceNode(context, sourceSection, assignTemp, ifNode);
|
|
470 } else {
|
|
471 for (int n = node.getCases().size() - 1; n >= 0; n--) {
|
|
472 final org.jrubyparser.ast.WhenNode when = (org.jrubyparser.ast.WhenNode) node.getCases().get(n);
|
|
473
|
|
474 // Make a condition from the one or more expressions combined in an or expression
|
|
475
|
|
476 final List<org.jrubyparser.ast.Node> expressions;
|
|
477
|
|
478 if (when.getExpression() instanceof org.jrubyparser.ast.ListNode) {
|
|
479 expressions = ((org.jrubyparser.ast.ListNode) when.getExpression()).childNodes();
|
|
480 } else {
|
|
481 expressions = Arrays.asList(when.getExpression());
|
|
482 }
|
|
483
|
|
484 final List<RubyNode> tests = new ArrayList<>();
|
|
485
|
|
486 for (org.jrubyparser.ast.Node expressionNode : expressions) {
|
|
487 final RubyNode rubyExpression = (RubyNode) expressionNode.accept(this);
|
|
488 tests.add(rubyExpression);
|
|
489 }
|
|
490
|
|
491 RubyNode conditionNode = tests.get(tests.size() - 1);
|
|
492
|
|
493 // As with the if nodes, we work backwards to make it left associative
|
|
494
|
|
495 for (int i = tests.size() - 2; i >= 0; i--) {
|
|
496 conditionNode = OrNodeFactory.create(context, sourceSection, tests.get(i), conditionNode);
|
|
497 }
|
|
498
|
|
499 // Create the if node
|
|
500
|
|
501 final BooleanCastNode conditionCastNode = BooleanCastNodeFactory.create(context, sourceSection, conditionNode);
|
|
502
|
|
503 final RubyNode thenNode = (RubyNode) when.getBody().accept(this);
|
|
504
|
|
505 final IfNode ifNode = new IfNode(context, sourceSection, conditionCastNode, thenNode, elseNode);
|
|
506
|
|
507 // This if becomes the else for the next if
|
|
508
|
|
509 elseNode = ifNode;
|
|
510 }
|
|
511
|
|
512 return elseNode;
|
|
513 }
|
|
514 }
|
|
515
|
|
516 @Override
|
|
517 public Object visitClassNode(org.jrubyparser.ast.ClassNode node) {
|
|
518 final SourceSection sourceSection = translate(node.getPosition());
|
|
519
|
|
520 final String name = node.getCPath().getName();
|
|
521
|
|
522 final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getParser().allocateReturnID(), true, true,
|
|
523 new UniqueMethodIdentifier());
|
|
524 final ModuleTranslator classTranslator = new ModuleTranslator(context, this, newEnvironment, source);
|
|
525
|
|
526 final MethodDefinitionNode definitionMethod = classTranslator.compileClassNode(node.getPosition(), node.getCPath().getName(), node.getBody());
|
|
527
|
|
528 /*
|
|
529 * See my note in visitDefnNode about where the class gets defined - the same applies here.
|
|
530 */
|
|
531
|
|
532 RubyNode superClass;
|
|
533
|
|
534 if (node.getSuper() != null) {
|
|
535 superClass = (RubyNode) node.getSuper().accept(this);
|
|
536 } else {
|
|
537 superClass = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getObjectClass());
|
|
538 }
|
|
539
|
|
540 final DefineOrGetClassNode defineOrGetClass = new DefineOrGetClassNode(context, sourceSection, name, getModuleToDefineModulesIn(sourceSection), superClass);
|
|
541
|
|
542 return new OpenModuleNode(context, sourceSection, defineOrGetClass, definitionMethod);
|
|
543 }
|
|
544
|
|
545 protected RubyNode getModuleToDefineModulesIn(SourceSection sourceSection) {
|
|
546 return new ClassNode(context, sourceSection, new SelfNode(context, sourceSection));
|
|
547 }
|
|
548
|
|
549 @Override
|
|
550 public Object visitClassVarAsgnNode(org.jrubyparser.ast.ClassVarAsgnNode node) {
|
|
551 final SourceSection sourceSection = translate(node.getPosition());
|
|
552
|
|
553 final RubyNode receiver = new ClassNode(context, sourceSection, new SelfNode(context, sourceSection));
|
|
554
|
|
555 final RubyNode rhs = (RubyNode) node.getValue().accept(this);
|
|
556
|
|
557 return new WriteClassVariableNode(context, sourceSection, node.getName(), receiver, rhs);
|
|
558 }
|
|
559
|
|
560 @Override
|
|
561 public Object visitClassVarDeclNode(org.jrubyparser.ast.ClassVarDeclNode node) {
|
|
562 return unimplemented(node);
|
|
563 }
|
|
564
|
|
565 @Override
|
|
566 public Object visitClassVarNode(org.jrubyparser.ast.ClassVarNode node) {
|
|
567 final SourceSection sourceSection = translate(node.getPosition());
|
|
568 return new ReadClassVariableNode(context, sourceSection, node.getName(), new SelfNode(context, sourceSection));
|
|
569 }
|
|
570
|
|
571 @Override
|
|
572 public Object visitColon2Node(org.jrubyparser.ast.Colon2Node node) {
|
|
573 final RubyNode lhs = (RubyNode) node.getLeftNode().accept(this);
|
|
574
|
|
575 return new UninitializedReadConstantNode(context, translate(node.getPosition()), node.getName(), lhs);
|
|
576 }
|
|
577
|
|
578 @Override
|
|
579 public Object visitColon3Node(org.jrubyparser.ast.Colon3Node node) {
|
|
580 // Colon3 means the root namespace, as in ::Foo
|
|
581
|
|
582 final SourceSection sourceSection = translate(node.getPosition());
|
|
583
|
|
584 final ObjectLiteralNode root = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getMainObject());
|
|
585
|
|
586 return new UninitializedReadConstantNode(context, sourceSection, node.getName(), root);
|
|
587 }
|
|
588
|
|
589 @Override
|
|
590 public Object visitConstDeclNode(org.jrubyparser.ast.ConstDeclNode node) {
|
|
591 final SourceSection sourceSection = translate(node.getPosition());
|
|
592
|
|
593 final ClassNode classNode = new ClassNode(context, sourceSection, new SelfNode(context, sourceSection));
|
|
594
|
|
595 return new WriteConstantNode(context, sourceSection, node.getName(), classNode, (RubyNode) node.getValue().accept(this));
|
|
596 }
|
|
597
|
|
598 @Override
|
|
599 public Object visitConstNode(org.jrubyparser.ast.ConstNode node) {
|
|
600 final SourceSection sourceSection = translate(node.getPosition());
|
|
601
|
|
602 return new UninitializedReadConstantNode(context, sourceSection, node.getName(), new SelfNode(context, sourceSection));
|
|
603 }
|
|
604
|
|
605 @Override
|
|
606 public Object visitDAsgnNode(org.jrubyparser.ast.DAsgnNode node) {
|
|
607 return new org.jrubyparser.ast.LocalAsgnNode(node.getPosition(), node.getName(), node.getDepth(), node.getValue()).accept(this);
|
|
608 }
|
|
609
|
|
610 @Override
|
|
611 public Object visitDRegxNode(org.jrubyparser.ast.DRegexpNode node) {
|
|
612 SourceSection sourceSection = translate(node.getPosition());
|
|
613
|
|
614 final RubyNode stringNode = translateInterpolatedString(sourceSection, node.childNodes());
|
|
615
|
|
616 return StringToRegexpNodeFactory.create(context, sourceSection, stringNode);
|
|
617 }
|
|
618
|
|
619 @Override
|
|
620 public Object visitDStrNode(org.jrubyparser.ast.DStrNode node) {
|
|
621 return translateInterpolatedString(translate(node.getPosition()), node.childNodes());
|
|
622 }
|
|
623
|
|
624 @Override
|
|
625 public Object visitDSymbolNode(org.jrubyparser.ast.DSymbolNode node) {
|
|
626 SourceSection sourceSection = translate(node.getPosition());
|
|
627
|
|
628 final RubyNode stringNode = translateInterpolatedString(sourceSection, node.childNodes());
|
|
629
|
|
630 return StringToSymbolNodeFactory.create(context, sourceSection, stringNode);
|
|
631 }
|
|
632
|
|
633 private RubyNode translateInterpolatedString(SourceSection sourceSection, List<org.jrubyparser.ast.Node> childNodes) {
|
|
634 final List<RubyNode> children = new ArrayList<>();
|
|
635
|
|
636 for (org.jrubyparser.ast.Node child : childNodes) {
|
|
637 children.add((RubyNode) child.accept(this));
|
|
638 }
|
|
639
|
|
640 return new InterpolatedStringNode(context, sourceSection, children.toArray(new RubyNode[children.size()]));
|
|
641 }
|
|
642
|
|
643 @Override
|
|
644 public Object visitDVarNode(org.jrubyparser.ast.DVarNode node) {
|
|
645 RubyNode readNode = environment.findLocalVarNode(node.getName(), translate(node.getPosition()));
|
|
646
|
|
647 if (readNode == null) {
|
|
648 context.implementationMessage("can't find variable %s at %s, using noop", node.getName(), node.getPosition());
|
|
649 readNode = new NilNode(context, translate(node.getPosition()));
|
|
650 }
|
|
651
|
|
652 return readNode;
|
|
653 }
|
|
654
|
|
655 @Override
|
|
656 public Object visitDXStrNode(org.jrubyparser.ast.DXStrNode node) {
|
|
657 SourceSection sourceSection = translate(node.getPosition());
|
|
658
|
|
659 final RubyNode string = translateInterpolatedString(sourceSection, node.childNodes());
|
|
660
|
|
661 return new SystemNode(context, sourceSection, string);
|
|
662 }
|
|
663
|
|
664 @Override
|
|
665 public Object visitDefinedNode(org.jrubyparser.ast.DefinedNode node) {
|
|
666 final SourceSection sourceSection = translate(node.getPosition());
|
|
667
|
|
668 org.jrubyparser.ast.Node expressionNode = node.getExpression();
|
|
669
|
|
670 while (expressionNode instanceof org.jrubyparser.ast.NewlineNode) {
|
|
671 expressionNode = ((org.jrubyparser.ast.NewlineNode) expressionNode).getNextNode();
|
|
672 }
|
|
673
|
|
674 final String name = nodeDefinedNames.get(expressionNode.getClass());
|
|
675
|
|
676 if (name != null) {
|
|
677 final StringLiteralNode literal = new StringLiteralNode(context, sourceSection, name);
|
|
678 return literal;
|
|
679 }
|
|
680
|
|
681 return new DefinedNode(context, sourceSection, (RubyNode) node.getExpression().accept(this));
|
|
682 }
|
|
683
|
|
684 @Override
|
|
685 public Object visitDefnNode(org.jrubyparser.ast.DefnNode node) {
|
|
686 final SourceSection sourceSection = translate(node.getPosition());
|
|
687 final ClassNode classNode = new ClassNode(context, sourceSection, new SelfNode(context, sourceSection));
|
|
688 return translateMethodDefinition(sourceSection, classNode, node.getName(), node.getArgs(), node.getBody());
|
|
689 }
|
|
690
|
|
691 @Override
|
|
692 public Object visitDefsNode(org.jrubyparser.ast.DefsNode node) {
|
|
693 final SourceSection sourceSection = translate(node.getPosition());
|
|
694
|
|
695 final RubyNode objectNode = (RubyNode) node.getReceiver().accept(this);
|
|
696
|
|
697 final SingletonClassNode singletonClassNode = new SingletonClassNode(context, sourceSection, objectNode);
|
|
698
|
|
699 return translateMethodDefinition(sourceSection, singletonClassNode, node.getName(), node.getArgs(), node.getBody());
|
|
700 }
|
|
701
|
|
702 private RubyNode translateMethodDefinition(SourceSection sourceSection, RubyNode classNode, String methodName, org.jrubyparser.ast.ArgsNode argsNode, org.jrubyparser.ast.Node bodyNode) {
|
|
703 final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getParser().allocateReturnID(), true, true,
|
|
704 new UniqueMethodIdentifier());
|
|
705
|
|
706 // ownScopeForAssignments is the same for the defined method as the current one.
|
|
707
|
|
708 final MethodTranslator methodCompiler = new MethodTranslator(context, this, newEnvironment, false, source);
|
|
709
|
|
710 final MethodDefinitionNode functionExprNode = methodCompiler.compileFunctionNode(sourceSection, methodName, argsNode, bodyNode);
|
|
711
|
|
712 /*
|
|
713 * In the top-level, methods are defined in the class of the main object. This is
|
|
714 * counter-intuitive - I would have expected them to be defined in the singleton class.
|
|
715 * Apparently this is a design decision to make top-level methods sort of global.
|
|
716 *
|
|
717 * http://stackoverflow.com/questions/1761148/where-are-methods-defined-at-the-ruby-top-level
|
|
718 */
|
|
719
|
|
720 return new AddMethodNode(context, sourceSection, classNode, functionExprNode);
|
|
721 }
|
|
722
|
|
723 @Override
|
|
724 public Object visitDotNode(org.jrubyparser.ast.DotNode node) {
|
|
725 final RubyNode begin = (RubyNode) node.getBegin().accept(this);
|
|
726 final RubyNode end = (RubyNode) node.getEnd().accept(this);
|
|
727 SourceSection sourceSection = translate(node.getPosition());
|
|
728
|
|
729 if (begin instanceof FixnumLiteralNode && end instanceof FixnumLiteralNode) {
|
|
730 final int beginValue = ((FixnumLiteralNode) begin).getValue();
|
|
731 final int endValue = ((FixnumLiteralNode) end).getValue();
|
|
732
|
|
733 return new ObjectLiteralNode(context, sourceSection, new FixnumRange(context.getCoreLibrary().getRangeClass(), beginValue, endValue, node.isExclusive()));
|
|
734 }
|
|
735 // See RangeNode for why there is a node specifically for creating this one type
|
|
736 return RangeLiteralNodeFactory.create(context, sourceSection, node.isExclusive(), begin, end);
|
|
737 }
|
|
738
|
|
739 @Override
|
|
740 public Object visitEncodingNode(org.jrubyparser.ast.EncodingNode node) {
|
|
741 return unimplemented(node);
|
|
742 }
|
|
743
|
|
744 @Override
|
|
745 public Object visitEnsureNode(org.jrubyparser.ast.EnsureNode node) {
|
|
746 final RubyNode tryPart = (RubyNode) node.getBody().accept(this);
|
|
747 final RubyNode ensurePart = (RubyNode) node.getEnsure().accept(this);
|
|
748 return new EnsureNode(context, translate(node.getPosition()), tryPart, ensurePart);
|
|
749 }
|
|
750
|
|
751 @Override
|
|
752 public Object visitEvStrNode(org.jrubyparser.ast.EvStrNode node) {
|
|
753 return node.getBody().accept(this);
|
|
754 }
|
|
755
|
|
756 @Override
|
|
757 public Object visitFCallNode(org.jrubyparser.ast.FCallNode node) {
|
|
758 final org.jrubyparser.ast.Node receiver = new org.jrubyparser.ast.SelfNode(node.getPosition());
|
|
759 final org.jrubyparser.ast.Node callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), receiver, node.getName(), node.getArgs(), node.getIter());
|
|
760
|
|
761 return callNode.accept(this);
|
|
762 }
|
|
763
|
|
764 @Override
|
|
765 public Object visitFalseNode(org.jrubyparser.ast.FalseNode node) {
|
|
766 return new BooleanLiteralNode(context, translate(node.getPosition()), false);
|
|
767 }
|
|
768
|
|
769 @Override
|
|
770 public Object visitFixnumNode(org.jrubyparser.ast.FixnumNode node) {
|
|
771 final long value = node.getValue();
|
|
772
|
|
773 if (value >= RubyFixnum.MIN_VALUE && value <= RubyFixnum.MAX_VALUE) {
|
|
774 return new FixnumLiteralNode(context, translate(node.getPosition()), (int) value);
|
|
775 }
|
|
776 return new BignumLiteralNode(context, translate(node.getPosition()), BigInteger.valueOf(value));
|
|
777 }
|
|
778
|
|
779 @Override
|
|
780 public Object visitFlipNode(org.jrubyparser.ast.FlipNode node) {
|
|
781 final SourceSection sourceSection = translate(node.getPosition());
|
|
782
|
|
783 final RubyNode begin = (RubyNode) node.getBegin().accept(this);
|
|
784 final RubyNode end = (RubyNode) node.getEnd().accept(this);
|
|
785
|
|
786 final BooleanCastNode beginCast = BooleanCastNodeFactory.create(context, sourceSection, begin);
|
|
787 final BooleanCastNode endCast = BooleanCastNodeFactory.create(context, sourceSection, end);
|
|
788 final FlipFlopStateNode stateNode = createFlipFlopState(sourceSection, 0);
|
|
789
|
|
790 return new FlipFlopNode(context, sourceSection, beginCast, endCast, stateNode, node.isExclusive());
|
|
791 }
|
|
792
|
|
793 protected FlipFlopStateNode createFlipFlopState(SourceSection sourceSection, int depth) {
|
|
794 final FrameSlot frameSlot = environment.declareVar(environment.allocateLocalTemp());
|
|
795 environment.getFlipFlopStates().add(frameSlot);
|
|
796
|
|
797 if (depth == 0) {
|
|
798 return new LocalFlipFlopStateNode(sourceSection, frameSlot);
|
|
799 } else {
|
|
800 return new LevelFlipFlopStateNode(sourceSection, depth, frameSlot);
|
|
801 }
|
|
802 }
|
|
803
|
|
804 @Override
|
|
805 public Object visitFloatNode(org.jrubyparser.ast.FloatNode node) {
|
|
806 return new FloatLiteralNode(context, translate(node.getPosition()), node.getValue());
|
|
807 }
|
|
808
|
|
809 @Override
|
|
810 public Object visitForNode(org.jrubyparser.ast.ForNode node) {
|
|
811 /**
|
|
812 * A Ruby for-loop, such as:
|
|
813 *
|
|
814 * <pre>
|
|
815 * for x in y
|
|
816 * z = x
|
|
817 * puts z
|
|
818 * end
|
|
819 * </pre>
|
|
820 *
|
|
821 * naively desugars to:
|
|
822 *
|
|
823 * <pre>
|
|
824 * y.each do |x|
|
|
825 * z = x
|
|
826 * puts z
|
|
827 * end
|
|
828 * </pre>
|
|
829 *
|
|
830 * The main difference is that z is always going to be local to the scope outside the block,
|
|
831 * so it's a bit more like:
|
|
832 *
|
|
833 * <pre>
|
|
834 * z = nil unless z is already defined
|
|
835 * y.each do |x|
|
|
836 * z = x
|
|
837 * puts x
|
|
838 * end
|
|
839 * </pre>
|
|
840 *
|
|
841 * Which forces z to be defined in the correct scope. The parser already correctly calls z a
|
|
842 * local, but then that causes us a problem as if we're going to translate to a block we
|
|
843 * need a formal parameter - not a local variable. My solution to this is to add a
|
|
844 * temporary:
|
|
845 *
|
|
846 * <pre>
|
|
847 * z = nil unless z is already defined
|
|
848 * y.each do |temp|
|
|
849 * x = temp
|
|
850 * z = x
|
|
851 * puts x
|
|
852 * end
|
|
853 * </pre>
|
|
854 *
|
|
855 * We also need that temp because the expression assigned in the for could be index
|
|
856 * assignment, multiple assignment, or whatever:
|
|
857 *
|
|
858 * <pre>
|
|
859 * for x[0] in y
|
|
860 * z = x[0]
|
|
861 * puts z
|
|
862 * end
|
|
863 * </pre>
|
|
864 *
|
|
865 * http://blog.grayproductions.net/articles/the_evils_of_the_for_loop
|
|
866 * http://stackoverflow.com/questions/3294509/for-vs-each-in-ruby
|
|
867 *
|
|
868 * The other complication is that normal locals should be defined in the enclosing scope,
|
|
869 * unlike a normal block. We do that by setting a flag on this translator object when we
|
|
870 * visit the new iter, translatingForStatement, which we recognise when visiting an iter
|
|
871 * node.
|
|
872 *
|
|
873 * Finally, note that JRuby's terminology is strange here. Normally 'iter' is a different
|
|
874 * term for a block. Here, JRuby calls the object being iterated over the 'iter'.
|
|
875 */
|
|
876
|
|
877 final String temp = environment.allocateLocalTemp();
|
|
878
|
|
879 final org.jrubyparser.ast.Node receiver = node.getIter();
|
|
880
|
|
881 /*
|
|
882 * The x in for x in ... is like the nodes in multiple assignment - it has a dummy RHS which
|
|
883 * we need to replace with our temp. Just like in multiple assignment this is really awkward
|
|
884 * with the JRuby AST.
|
|
885 */
|
|
886
|
|
887 final org.jrubyparser.ast.LocalVarNode readTemp = new org.jrubyparser.ast.LocalVarNode(node.getPosition(), 0, temp);
|
|
888 final org.jrubyparser.ast.Node forVar = node.getVar();
|
|
889 final org.jrubyparser.ast.Node assignTemp = setRHS(forVar, readTemp);
|
|
890
|
|
891 final org.jrubyparser.ast.BlockNode bodyWithTempAssign = new org.jrubyparser.ast.BlockNode(node.getPosition());
|
|
892 bodyWithTempAssign.add(assignTemp);
|
|
893 bodyWithTempAssign.add(node.getBody());
|
|
894
|
|
895 final org.jrubyparser.ast.ArgumentNode blockVar = new org.jrubyparser.ast.ArgumentNode(node.getPosition(), temp);
|
|
896 final org.jrubyparser.ast.ListNode blockArgsPre = new org.jrubyparser.ast.ListNode(node.getPosition(), blockVar);
|
|
897 final org.jrubyparser.ast.ArgsNode blockArgs = new org.jrubyparser.ast.ArgsNode(node.getPosition(), blockArgsPre, null, null, null, null, null, null);
|
|
898 final org.jrubyparser.ast.IterNode block = new org.jrubyparser.ast.IterNode(node.getPosition(), blockArgs, node.getScope(), bodyWithTempAssign);
|
|
899
|
|
900 final org.jrubyparser.ast.CallNode callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), receiver, "each", null, block);
|
|
901
|
|
902 translatingForStatement = true;
|
|
903 final RubyNode translated = (RubyNode) callNode.accept(this);
|
|
904 translatingForStatement = false;
|
|
905
|
|
906 return translated;
|
|
907 }
|
|
908
|
|
909 private static org.jrubyparser.ast.Node setRHS(org.jrubyparser.ast.Node node, org.jrubyparser.ast.Node rhs) {
|
|
910 if (node instanceof org.jrubyparser.ast.LocalAsgnNode) {
|
|
911 final org.jrubyparser.ast.LocalAsgnNode localAsgnNode = (org.jrubyparser.ast.LocalAsgnNode) node;
|
|
912 return new org.jrubyparser.ast.LocalAsgnNode(node.getPosition(), localAsgnNode.getName(), 0, rhs);
|
|
913 } else if (node instanceof org.jrubyparser.ast.DAsgnNode) {
|
|
914 final org.jrubyparser.ast.DAsgnNode dAsgnNode = (org.jrubyparser.ast.DAsgnNode) node;
|
|
915 return new org.jrubyparser.ast.DAsgnNode(node.getPosition(), dAsgnNode.getName(), 0, rhs);
|
|
916 } else if (node instanceof org.jrubyparser.ast.MultipleAsgnNode) {
|
|
917 final org.jrubyparser.ast.MultipleAsgnNode multAsgnNode = (org.jrubyparser.ast.MultipleAsgnNode) node;
|
|
918 return new org.jrubyparser.ast.MultipleAsgnNode(node.getPosition(), multAsgnNode.getPre(), multAsgnNode.getRest(), multAsgnNode.getPost());
|
|
919 } else if (node instanceof org.jrubyparser.ast.InstAsgnNode) {
|
|
920 final org.jrubyparser.ast.InstAsgnNode instAsgnNode = (org.jrubyparser.ast.InstAsgnNode) node;
|
|
921 return new org.jrubyparser.ast.InstAsgnNode(node.getPosition(), instAsgnNode.getName(), rhs);
|
|
922 } else if (node instanceof org.jrubyparser.ast.ClassVarAsgnNode) {
|
|
923 final org.jrubyparser.ast.ClassVarAsgnNode instAsgnNode = (org.jrubyparser.ast.ClassVarAsgnNode) node;
|
|
924 return new org.jrubyparser.ast.ClassVarAsgnNode(node.getPosition(), instAsgnNode.getName(), rhs);
|
|
925 } else if (node instanceof org.jrubyparser.ast.ConstDeclNode) {
|
|
926 final org.jrubyparser.ast.ConstDeclNode constDeclNode = (org.jrubyparser.ast.ConstDeclNode) node;
|
|
927 return new org.jrubyparser.ast.ConstDeclNode(node.getPosition(), constDeclNode.getName(), (org.jrubyparser.ast.INameNode) constDeclNode.getConstNode(), rhs);
|
|
928 } else {
|
|
929 throw new UnsupportedOperationException("Don't know how to set the RHS of a " + node.getClass().getName());
|
|
930 }
|
|
931 }
|
|
932
|
|
933 @Override
|
|
934 public Object visitGlobalAsgnNode(org.jrubyparser.ast.GlobalAsgnNode node) {
|
|
935 final SourceSection sourceSection = translate(node.getPosition());
|
|
936
|
|
937 final String name = "$" + node.getName();
|
|
938 final RubyNode rhs = (RubyNode) node.getValue().accept(this);
|
|
939
|
|
940 if (FRAME_LOCAL_GLOBAL_VARIABLES.contains(name)) {
|
|
941 context.implementationMessage("Assigning to frame local global variables not implemented at %s", node.getPosition());
|
|
942
|
|
943 return rhs;
|
|
944 } else {
|
|
945 final ObjectLiteralNode globalVariablesObjectNode = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getGlobalVariablesObject());
|
|
946
|
|
947 return new UninitializedWriteInstanceVariableNode(context, sourceSection, name, globalVariablesObjectNode, rhs);
|
|
948 }
|
|
949 }
|
|
950
|
|
951 @Override
|
|
952 public Object visitGlobalVarNode(org.jrubyparser.ast.GlobalVarNode node) {
|
|
953 final String name = "$" + node.getName();
|
|
954 final SourceSection sourceSection = translate(node.getPosition());
|
|
955
|
|
956 if (FRAME_LOCAL_GLOBAL_VARIABLES.contains(name)) {
|
|
957 // Assignment is implicit for many of these, so we need to declare when we use
|
|
958
|
|
959 environment.declareVar(name);
|
|
960
|
|
961 final RubyNode readNode = environment.findLocalVarNode(name, sourceSection);
|
|
962
|
|
963 return readNode;
|
|
964 } else {
|
|
965 final ObjectLiteralNode globalVariablesObjectNode = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getGlobalVariablesObject());
|
|
966
|
|
967 return new UninitializedReadInstanceVariableNode(context, sourceSection, name, globalVariablesObjectNode);
|
|
968 }
|
|
969 }
|
|
970
|
|
971 @Override
|
|
972 public Object visitHashNode(org.jrubyparser.ast.HashNode node) {
|
|
973 final SourceSection sourceSection = translate(node.getPosition());
|
|
974
|
|
975 final List<RubyNode> keys = new ArrayList<>();
|
|
976 final List<RubyNode> values = new ArrayList<>();
|
|
977
|
|
978 final org.jrubyparser.ast.ListNode entries = node.getListNode();
|
|
979
|
|
980 assert entries.size() % 2 == 0;
|
|
981
|
|
982 for (int n = 0; n < entries.size(); n += 2) {
|
|
983 if (entries.get(n) == null) {
|
|
984 final NilNode nilNode = new NilNode(context, sourceSection);
|
|
985 keys.add(nilNode);
|
|
986 } else {
|
|
987 keys.add((RubyNode) entries.get(n).accept(this));
|
|
988 }
|
|
989
|
|
990 if (entries.get(n + 1) == null) {
|
|
991 final NilNode nilNode = new NilNode(context, sourceSection);
|
|
992 values.add(nilNode);
|
|
993 } else {
|
|
994 values.add((RubyNode) entries.get(n + 1).accept(this));
|
|
995 }
|
|
996 }
|
|
997
|
|
998 return new HashLiteralNode(translate(node.getPosition()), keys.toArray(new RubyNode[keys.size()]), values.toArray(new RubyNode[values.size()]), context);
|
|
999 }
|
|
1000
|
|
1001 @Override
|
|
1002 public Object visitIfNode(org.jrubyparser.ast.IfNode node) {
|
|
1003 final SourceSection sourceSection = translate(node.getPosition());
|
|
1004
|
|
1005 org.jrubyparser.ast.Node thenBody = node.getThenBody();
|
|
1006
|
|
1007 if (thenBody == null) {
|
|
1008 thenBody = new org.jrubyparser.ast.NilNode(node.getPosition());
|
|
1009 }
|
|
1010
|
|
1011 org.jrubyparser.ast.Node elseBody = node.getElseBody();
|
|
1012
|
|
1013 if (elseBody == null) {
|
|
1014 elseBody = new org.jrubyparser.ast.NilNode(node.getPosition());
|
|
1015 }
|
|
1016
|
|
1017 RubyNode condition;
|
|
1018
|
|
1019 if (node.getCondition() == null) {
|
|
1020 condition = new NilNode(context, sourceSection);
|
|
1021 } else {
|
|
1022 condition = (RubyNode) node.getCondition().accept(this);
|
|
1023 }
|
|
1024
|
|
1025 final BooleanCastNode conditionCast = BooleanCastNodeFactory.create(context, sourceSection, condition);
|
|
1026
|
|
1027 final RubyNode thenBodyTranslated = (RubyNode) thenBody.accept(this);
|
|
1028 final RubyNode elseBodyTranslated = (RubyNode) elseBody.accept(this);
|
|
1029
|
|
1030 return new IfNode(context, sourceSection, conditionCast, thenBodyTranslated, elseBodyTranslated);
|
|
1031 }
|
|
1032
|
|
1033 @Override
|
|
1034 public Object visitInstAsgnNode(org.jrubyparser.ast.InstAsgnNode node) {
|
|
1035 final SourceSection sourceSection = translate(node.getPosition());
|
|
1036 final String nameWithoutSigil = node.getName();
|
|
1037
|
|
1038 final RubyNode receiver = new SelfNode(context, sourceSection);
|
|
1039
|
|
1040 RubyNode rhs;
|
|
1041
|
|
1042 if (node.getValue() == null) {
|
|
1043 rhs = new DeadNode(context, sourceSection);
|
|
1044 } else {
|
|
1045 rhs = (RubyNode) node.getValue().accept(this);
|
|
1046 }
|
|
1047
|
|
1048 return new UninitializedWriteInstanceVariableNode(context, sourceSection, nameWithoutSigil, receiver, rhs);
|
|
1049 }
|
|
1050
|
|
1051 @Override
|
|
1052 public Object visitInstVarNode(org.jrubyparser.ast.InstVarNode node) {
|
|
1053 final SourceSection sourceSection = translate(node.getPosition());
|
|
1054 final String nameWithoutSigil = node.getName();
|
|
1055
|
|
1056 final RubyNode receiver = new SelfNode(context, sourceSection);
|
|
1057
|
|
1058 return new UninitializedReadInstanceVariableNode(context, sourceSection, nameWithoutSigil, receiver);
|
|
1059 }
|
|
1060
|
|
1061 @Override
|
|
1062 public Object visitIterNode(org.jrubyparser.ast.IterNode node) {
|
|
1063 /*
|
|
1064 * In a block we do NOT allocate a new return ID - returns will return from the method, not
|
|
1065 * the block (in the general case, see Proc and the difference between Proc and Lambda for
|
|
1066 * specifics).
|
|
1067 */
|
|
1068
|
|
1069 final boolean hasOwnScope = !translatingForStatement;
|
|
1070
|
|
1071 // Unset this flag for any for any blocks within the for statement's body
|
|
1072
|
|
1073 translatingForStatement = false;
|
|
1074
|
|
1075 final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getReturnID(), hasOwnScope, false,
|
|
1076 new UniqueMethodIdentifier());
|
|
1077 final MethodTranslator methodCompiler = new MethodTranslator(context, this, newEnvironment, true, source);
|
|
1078
|
|
1079 org.jrubyparser.ast.ArgsNode argsNode;
|
|
1080
|
|
1081 if (node.getVar() instanceof org.jrubyparser.ast.ArgsNode) {
|
|
1082 argsNode = (org.jrubyparser.ast.ArgsNode) node.getVar();
|
|
1083 } else if (node.getVar() instanceof org.jrubyparser.ast.DAsgnNode) {
|
|
1084 final org.jrubyparser.ast.ArgumentNode arg = new org.jrubyparser.ast.ArgumentNode(node.getPosition(), ((org.jrubyparser.ast.DAsgnNode) node.getVar()).getName());
|
|
1085 final org.jrubyparser.ast.ListNode preArgs = new org.jrubyparser.ast.ArrayNode(node.getPosition(), arg);
|
|
1086 argsNode = new org.jrubyparser.ast.ArgsNode(node.getPosition(), preArgs, null, null, null, null, null, null);
|
|
1087 } else if (node.getVar() == null) {
|
|
1088 argsNode = null;
|
|
1089 } else {
|
|
1090 throw new UnsupportedOperationException();
|
|
1091 }
|
|
1092
|
|
1093 return methodCompiler.compileFunctionNode(translate(node.getPosition()), "(block)", argsNode, node.getBody());
|
|
1094 }
|
|
1095
|
|
1096 @Override
|
|
1097 public Object visitLiteralNode(org.jrubyparser.ast.LiteralNode node) {
|
|
1098 return unimplemented(node);
|
|
1099 }
|
|
1100
|
|
1101 @Override
|
|
1102 public Object visitLocalAsgnNode(org.jrubyparser.ast.LocalAsgnNode node) {
|
|
1103
|
|
1104 final SourceSection sourceSection = translate(node.getPosition());
|
|
1105
|
|
1106 if (environment.getNeverAssignInParentScope()) {
|
|
1107 environment.declareVar(node.getName());
|
|
1108 }
|
|
1109
|
|
1110 RubyNode lhs = environment.findLocalVarNode(node.getName(), sourceSection);
|
|
1111
|
|
1112 if (lhs == null) {
|
|
1113 if (environment.hasOwnScopeForAssignments()) {
|
|
1114 environment.declareVar(node.getName());
|
|
1115 }
|
|
1116
|
|
1117 TranslatorEnvironment environmentToDeclareIn = environment;
|
|
1118
|
|
1119 while (!environmentToDeclareIn.hasOwnScopeForAssignments()) {
|
|
1120 environmentToDeclareIn = environmentToDeclareIn.getParent();
|
|
1121 }
|
|
1122
|
|
1123 environmentToDeclareIn.declareVar(node.getName());
|
|
1124 lhs = environment.findLocalVarNode(node.getName(), sourceSection);
|
|
1125
|
|
1126 if (lhs == null) {
|
|
1127 throw new RuntimeException("shoudln't be here");
|
|
1128 }
|
|
1129 }
|
|
1130
|
|
1131 RubyNode rhs;
|
|
1132
|
|
1133 if (node.getValue() == null) {
|
|
1134 rhs = new DeadNode(context, sourceSection);
|
|
1135 } else {
|
|
1136 rhs = (RubyNode) node.getValue().accept(this);
|
|
1137 }
|
|
1138
|
|
1139 RubyNode translated = ((ReadNode) lhs).makeWriteNode(rhs);
|
|
1140
|
|
1141 if (context.getConfiguration().getDebug()) {
|
|
1142 final UniqueMethodIdentifier methodIdentifier = environment.findMethodForLocalVar(node.getName());
|
|
1143
|
|
1144 RubyProxyNode proxy;
|
|
1145 if (translated instanceof RubyProxyNode) {
|
|
1146 proxy = (RubyProxyNode) translated;
|
|
1147 } else {
|
|
1148 proxy = new RubyProxyNode(context, translated);
|
|
1149 }
|
|
1150 context.getDebugManager().registerLocalDebugProxy(methodIdentifier, node.getName(), proxy.getProbeChain());
|
|
1151
|
|
1152 translated = proxy;
|
|
1153 }
|
|
1154
|
|
1155 return translated;
|
|
1156 }
|
|
1157
|
|
1158 @Override
|
|
1159 public Object visitLocalVarNode(org.jrubyparser.ast.LocalVarNode node) {
|
|
1160 final SourceSection sourceSection = translate(node.getPosition());
|
|
1161
|
|
1162 final String name = node.getName();
|
|
1163
|
|
1164 RubyNode readNode = environment.findLocalVarNode(name, sourceSection);
|
|
1165
|
|
1166 if (readNode == null) {
|
|
1167 context.implementationMessage("Local variable found by parser but not by translator - " + name + " at " + node.getPosition());
|
|
1168 readNode = environment.findLocalVarNode(environment.allocateLocalTemp(), sourceSection);
|
|
1169 }
|
|
1170
|
|
1171 return readNode;
|
|
1172 }
|
|
1173
|
|
1174 @Override
|
|
1175 public Object visitMatch2Node(org.jrubyparser.ast.Match2Node node) {
|
|
1176 final org.jrubyparser.ast.Node argsNode = buildArrayNode(node.getPosition(), node.getValue());
|
|
1177 final org.jrubyparser.ast.Node callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), node.getReceiver(), "=~", argsNode, null);
|
|
1178 return callNode.accept(this);
|
|
1179 }
|
|
1180
|
|
1181 @Override
|
|
1182 public Object visitMatch3Node(org.jrubyparser.ast.Match3Node node) {
|
|
1183 final org.jrubyparser.ast.Node argsNode = buildArrayNode(node.getPosition(), node.getValue());
|
|
1184 final org.jrubyparser.ast.Node callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), node.getReceiver(), "=~", argsNode, null);
|
|
1185 return callNode.accept(this);
|
|
1186 }
|
|
1187
|
|
1188 @Override
|
|
1189 public Object visitMatchNode(org.jrubyparser.ast.MatchNode node) {
|
|
1190 return unimplemented(node);
|
|
1191 }
|
|
1192
|
|
1193 @Override
|
|
1194 public Object visitModuleNode(org.jrubyparser.ast.ModuleNode node) {
|
|
1195 // See visitClassNode
|
|
1196
|
|
1197 final SourceSection sourceSection = translate(node.getPosition());
|
|
1198
|
|
1199 final String name = node.getCPath().getName();
|
|
1200
|
|
1201 final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getParser().allocateReturnID(), true, true,
|
|
1202 new UniqueMethodIdentifier());
|
|
1203 final ModuleTranslator classTranslator = new ModuleTranslator(context, this, newEnvironment, source);
|
|
1204
|
|
1205 final MethodDefinitionNode definitionMethod = classTranslator.compileClassNode(node.getPosition(), node.getCPath().getName(), node.getBody());
|
|
1206
|
|
1207 final DefineOrGetModuleNode defineModuleNode = new DefineOrGetModuleNode(context, sourceSection, name, getModuleToDefineModulesIn(sourceSection));
|
|
1208
|
|
1209 return new OpenModuleNode(context, sourceSection, defineModuleNode, definitionMethod);
|
|
1210 }
|
|
1211
|
|
1212 @Override
|
|
1213 public Object visitMultipleAsgnNode(org.jrubyparser.ast.MultipleAsgnNode node) {
|
|
1214 final SourceSection sourceSection = translate(node.getPosition());
|
|
1215
|
|
1216 final org.jrubyparser.ast.ArrayNode preArray = (org.jrubyparser.ast.ArrayNode) node.getPre();
|
|
1217 final org.jrubyparser.ast.Node rhs = node.getValue();
|
|
1218
|
|
1219 RubyNode rhsTranslated;
|
|
1220
|
|
1221 if (rhs == null) {
|
|
1222 context.implementationMessage("warning: no RHS for multiple assignment - using noop");
|
|
1223 rhsTranslated = new NilNode(context, sourceSection);
|
|
1224 } else {
|
|
1225 rhsTranslated = (RubyNode) rhs.accept(this);
|
|
1226 }
|
|
1227
|
|
1228 /*
|
|
1229 * One very common case is to do
|
|
1230 *
|
|
1231 * a, b = c, d
|
|
1232 */
|
|
1233
|
|
1234 if (preArray != null && node.getPost() == null && node.getRest() == null && rhsTranslated instanceof UninitialisedArrayLiteralNode &&
|
|
1235 ((UninitialisedArrayLiteralNode) rhsTranslated).getValues().length == preArray.size()) {
|
|
1236 /*
|
|
1237 * We can deal with this common case be rewriting as
|
|
1238 *
|
|
1239 * temp1 = c; temp2 = d; a = temp1; b = temp2
|
|
1240 *
|
|
1241 * We can't just do
|
|
1242 *
|
|
1243 * a = c; b = d
|
|
1244 *
|
|
1245 * As we don't know if d depends on the original value of a.
|
|
1246 *
|
|
1247 * We also need to return an array [c, d], but we make that result elidable so it isn't
|
|
1248 * executed if it isn't actually demanded.
|
|
1249 */
|
|
1250
|
|
1251 final RubyNode[] rhsValues = ((UninitialisedArrayLiteralNode) rhsTranslated).getValues();
|
|
1252 final int assignedValuesCount = preArray.size();
|
|
1253
|
|
1254 final RubyNode[] sequence = new RubyNode[assignedValuesCount * 2];
|
|
1255
|
|
1256 final RubyNode[] tempValues = new RubyNode[assignedValuesCount];
|
|
1257
|
|
1258 for (int n = 0; n < assignedValuesCount; n++) {
|
|
1259 final String tempName = environment.allocateLocalTemp();
|
|
1260 final RubyNode readTemp = environment.findLocalVarNode(tempName, sourceSection);
|
|
1261 final RubyNode assignTemp = ((ReadNode) readTemp).makeWriteNode(rhsValues[n]);
|
|
1262 final RubyNode assignFinalValue = translateDummyAssignment(preArray.get(n), readTemp);
|
|
1263
|
|
1264 sequence[n] = assignTemp;
|
|
1265 sequence[assignedValuesCount + n] = assignFinalValue;
|
|
1266
|
|
1267 tempValues[n] = readTemp;
|
|
1268 }
|
|
1269
|
|
1270 final RubyNode blockNode = new SequenceNode(context, sourceSection, sequence);
|
|
1271
|
|
1272 final UninitialisedArrayLiteralNode arrayNode = new UninitialisedArrayLiteralNode(context, sourceSection, tempValues);
|
|
1273
|
|
1274 final ElidableResultNode elidableResult = new ElidableResultNode(context, sourceSection, blockNode, arrayNode);
|
|
1275
|
|
1276 return elidableResult;
|
|
1277 } else if (preArray != null) {
|
|
1278 /*
|
|
1279 * The other simple case is
|
|
1280 *
|
|
1281 * a, b, c = x
|
|
1282 *
|
|
1283 * If x is an array, then it's
|
|
1284 *
|
|
1285 * a[0] = x[0] etc
|
|
1286 *
|
|
1287 * If x isn't an array then it's
|
|
1288 *
|
|
1289 * a, b, c = [x, nil, nil]
|
|
1290 *
|
|
1291 * Which I believe is the same effect as
|
|
1292 *
|
|
1293 * a, b, c, = *x
|
|
1294 *
|
|
1295 * So we insert the splat cast node, even though it isn't there.
|
|
1296 */
|
|
1297
|
|
1298 /*
|
|
1299 * Create a temp for the array.
|
|
1300 */
|
|
1301
|
|
1302 final String tempName = environment.allocateLocalTemp();
|
|
1303
|
|
1304 /*
|
|
1305 * Create a sequence of instructions, with the first being the literal array assigned to
|
|
1306 * the temp.
|
|
1307 */
|
|
1308
|
|
1309 final List<RubyNode> sequence = new ArrayList<>();
|
|
1310
|
|
1311 final RubyNode splatCastNode = SplatCastNodeFactory.create(context, sourceSection, rhsTranslated);
|
|
1312
|
|
1313 final RubyNode writeTemp = ((ReadNode) environment.findLocalVarNode(tempName, sourceSection)).makeWriteNode(splatCastNode);
|
|
1314
|
|
1315 sequence.add(writeTemp);
|
|
1316
|
|
1317 /*
|
|
1318 * Then index the temp array for each assignment on the LHS.
|
|
1319 */
|
|
1320
|
|
1321 for (int n = 0; n < preArray.size(); n++) {
|
|
1322 final ArrayIndexNode assignedValue = ArrayIndexNodeFactory.create(context, sourceSection, n, environment.findLocalVarNode(tempName, sourceSection));
|
|
1323
|
|
1324 sequence.add(translateDummyAssignment(preArray.get(n), assignedValue));
|
|
1325 }
|
|
1326
|
|
1327 if (node.getRest() != null) {
|
|
1328 final ArrayRestNode assignedValue = new ArrayRestNode(context, sourceSection, preArray.size(), environment.findLocalVarNode(tempName, sourceSection));
|
|
1329
|
|
1330 sequence.add(translateDummyAssignment(node.getRest(), assignedValue));
|
|
1331 }
|
|
1332
|
|
1333 return new SequenceNode(context, sourceSection, sequence.toArray(new RubyNode[sequence.size()]));
|
|
1334 } else if (node.getPre() == null && node.getPost() == null && node.getRest() instanceof org.jrubyparser.ast.StarNode) {
|
|
1335 return rhsTranslated;
|
|
1336 } else if (node.getPre() == null && node.getPost() == null && node.getRest() != null && rhs != null && !(rhs instanceof org.jrubyparser.ast.ArrayNode)) {
|
|
1337 /*
|
|
1338 * *a = b
|
|
1339 *
|
|
1340 * >= 1.8, this seems to be the same as:
|
|
1341 *
|
|
1342 * a = *b
|
|
1343 */
|
|
1344
|
|
1345 final RubyNode restTranslated = ((RubyNode) node.getRest().accept(this)).getNonProxyNode();
|
|
1346
|
|
1347 /*
|
|
1348 * Sometimes rest is a corrupt write with no RHS, like in other multiple assignments,
|
|
1349 * and sometimes it is already a read.
|
|
1350 */
|
|
1351
|
|
1352 ReadNode restRead;
|
|
1353
|
|
1354 if (restTranslated instanceof ReadNode) {
|
|
1355 restRead = (ReadNode) restTranslated;
|
|
1356 } else if (restTranslated instanceof WriteNode) {
|
|
1357 restRead = (ReadNode) ((WriteNode) restTranslated).makeReadNode();
|
|
1358 } else {
|
|
1359 throw new RuntimeException("Unknown form of multiple assignment " + node + " at " + node.getPosition());
|
|
1360 }
|
|
1361
|
|
1362 final SplatCastNode rhsSplatCast = SplatCastNodeFactory.create(context, sourceSection, rhsTranslated);
|
|
1363
|
|
1364 return restRead.makeWriteNode(rhsSplatCast);
|
|
1365 } else if (node.getPre() == null && node.getPost() == null && node.getRest() != null && rhs != null && rhs instanceof org.jrubyparser.ast.ArrayNode) {
|
|
1366 /*
|
|
1367 * *a = [b, c]
|
|
1368 *
|
|
1369 * This seems to be the same as:
|
|
1370 *
|
|
1371 * a = [b, c]
|
|
1372 */
|
|
1373
|
|
1374 final RubyNode restTranslated = ((RubyNode) node.getRest().accept(this)).getNonProxyNode();
|
|
1375
|
|
1376 /*
|
|
1377 * Sometimes rest is a corrupt write with no RHS, like in other multiple assignments,
|
|
1378 * and sometimes it is already a read.
|
|
1379 */
|
|
1380
|
|
1381 ReadNode restRead;
|
|
1382
|
|
1383 if (restTranslated instanceof ReadNode) {
|
|
1384 restRead = (ReadNode) restTranslated;
|
|
1385 } else if (restTranslated instanceof WriteNode) {
|
|
1386 restRead = (ReadNode) ((WriteNode) restTranslated).makeReadNode();
|
|
1387 } else {
|
|
1388 throw new RuntimeException("Unknown form of multiple assignment " + node + " at " + node.getPosition());
|
|
1389 }
|
|
1390
|
|
1391 return restRead.makeWriteNode(rhsTranslated);
|
|
1392 } else {
|
|
1393 throw new RuntimeException("Unknown form of multiple assignment " + node + " at " + node.getPosition());
|
|
1394 }
|
|
1395 }
|
|
1396
|
|
1397 private RubyNode translateDummyAssignment(org.jrubyparser.ast.Node dummyAssignment, RubyNode rhs) {
|
|
1398 final SourceSection sourceSection = translate(dummyAssignment.getPosition());
|
|
1399
|
|
1400 /*
|
|
1401 * This is tricky. To represent the RHS of a multiple assignment they use corrupt assignment
|
|
1402 * values, in some cases with no value to be assigned, and in other cases with a dummy
|
|
1403 * value. We can't visit them normally, as they're corrupt. We can't just modify them to
|
|
1404 * have our RHS, as that's a node in our AST, not theirs. We can't use a dummy value in
|
|
1405 * their AST because I can't add new visitors to this interface.
|
|
1406 */
|
|
1407
|
|
1408 RubyNode translated;
|
|
1409
|
|
1410 if (dummyAssignment instanceof org.jrubyparser.ast.LocalAsgnNode) {
|
|
1411 /*
|
|
1412 * They have a dummy NilImplicitNode as the RHS. Translate, convert to read, convert to
|
|
1413 * write which allows us to set the RHS.
|
|
1414 */
|
|
1415
|
|
1416 final WriteNode dummyTranslated = (WriteNode) ((RubyNode) dummyAssignment.accept(this)).getNonProxyNode();
|
|
1417 translated = ((ReadNode) dummyTranslated.makeReadNode()).makeWriteNode(rhs);
|
|
1418 } else if (dummyAssignment instanceof org.jrubyparser.ast.InstAsgnNode) {
|
|
1419 /*
|
|
1420 * Same as before, just a different type of assignment.
|
|
1421 */
|
|
1422
|
|
1423 final WriteInstanceVariableNode dummyTranslated = (WriteInstanceVariableNode) dummyAssignment.accept(this);
|
|
1424 translated = dummyTranslated.makeReadNode().makeWriteNode(rhs);
|
|
1425 } else if (dummyAssignment instanceof org.jrubyparser.ast.AttrAssignNode) {
|
|
1426 /*
|
|
1427 * They've given us an AttrAssignNode with the final argument, the assigned value,
|
|
1428 * missing. If we translate that we'll get foo.[]=(index), so missing the value. To
|
|
1429 * solve we have a special version of the visitCallNode that allows us to pass another
|
|
1430 * already translated argument, visitCallNodeExtraArgument. However, we initially have
|
|
1431 * an AttrAssignNode, so we also need a special version of that.
|
|
1432 */
|
|
1433
|
|
1434 final org.jrubyparser.ast.AttrAssignNode dummyAttrAssignment = (org.jrubyparser.ast.AttrAssignNode) dummyAssignment;
|
|
1435 translated = visitAttrAssignNodeExtraArgument(dummyAttrAssignment, rhs);
|
|
1436 } else if (dummyAssignment instanceof org.jrubyparser.ast.DAsgnNode) {
|
|
1437 final RubyNode dummyTranslated = (RubyNode) dummyAssignment.accept(this);
|
|
1438
|
|
1439 if (dummyTranslated.getNonProxyNode() instanceof WriteLevelVariableNode) {
|
|
1440 translated = ((ReadNode) ((WriteLevelVariableNode) dummyTranslated.getNonProxyNode()).makeReadNode()).makeWriteNode(rhs);
|
|
1441 } else {
|
|
1442 translated = ((ReadNode) ((WriteLocalVariableNode) dummyTranslated.getNonProxyNode()).makeReadNode()).makeWriteNode(rhs);
|
|
1443 }
|
|
1444 } else {
|
|
1445 translated = ((ReadNode) environment.findLocalVarNode(environment.allocateLocalTemp(), sourceSection)).makeWriteNode(rhs);
|
|
1446 }
|
|
1447
|
|
1448 return translated;
|
|
1449 }
|
|
1450
|
|
1451 @Override
|
|
1452 public Object visitNewlineNode(org.jrubyparser.ast.NewlineNode node) {
|
|
1453 RubyNode translated = (RubyNode) node.getNextNode().accept(this);
|
|
1454
|
|
1455 if (context.getConfiguration().getDebug()) {
|
|
1456
|
|
1457 RubyProxyNode proxy;
|
|
1458 SourceSection sourceSection;
|
|
1459 if (translated instanceof RubyProxyNode) {
|
|
1460 proxy = (RubyProxyNode) translated;
|
|
1461 sourceSection = proxy.getChild().getSourceSection();
|
|
1462 } else {
|
|
1463 proxy = new RubyProxyNode(context, translated);
|
|
1464 sourceSection = translated.getSourceSection();
|
|
1465 }
|
|
1466 context.getDebugManager().registerProbeChain(sourceSection, proxy.getProbeChain());
|
|
1467 translated = proxy;
|
|
1468 }
|
|
1469
|
|
1470 if (context.getConfiguration().getTrace()) {
|
|
1471 RubyProxyNode proxy;
|
|
1472 if (translated instanceof RubyProxyNode) {
|
|
1473 proxy = (RubyProxyNode) translated;
|
|
1474 } else {
|
|
1475 proxy = new RubyProxyNode(context, translated);
|
|
1476 }
|
|
1477 proxy.getProbeChain().appendProbe(new RubyTraceProbe(context));
|
|
1478
|
|
1479 translated = proxy;
|
|
1480 }
|
|
1481
|
|
1482 return translated;
|
|
1483 }
|
|
1484
|
|
1485 @Override
|
|
1486 public Object visitNextNode(org.jrubyparser.ast.NextNode node) {
|
|
1487 return new NextNode(context, translate(node.getPosition()));
|
|
1488 }
|
|
1489
|
|
1490 @Override
|
|
1491 public Object visitNilNode(org.jrubyparser.ast.NilNode node) {
|
|
1492 return new NilNode(context, translate(node.getPosition()));
|
|
1493 }
|
|
1494
|
|
1495 @Override
|
|
1496 public Object visitNotNode(org.jrubyparser.ast.NotNode node) {
|
|
1497 final SourceSection sourceSection = translate(node.getPosition());
|
|
1498
|
|
1499 final BooleanCastNode booleanCastNode = BooleanCastNodeFactory.create(context, sourceSection, (RubyNode) node.getCondition().accept(this));
|
|
1500
|
|
1501 return new NotNode(context, sourceSection, booleanCastNode);
|
|
1502 }
|
|
1503
|
|
1504 @Override
|
|
1505 public Object visitNthRefNode(org.jrubyparser.ast.NthRefNode node) {
|
|
1506 final SourceSection sourceSection = translate(node.getPosition());
|
|
1507
|
|
1508 final String name = "$" + node.getMatchNumber();
|
|
1509
|
|
1510 RubyNode readLocal = environment.findLocalVarNode(name, sourceSection);
|
|
1511
|
|
1512 if (readLocal == null) {
|
|
1513 environment.declareVar(name);
|
|
1514 readLocal = environment.findLocalVarNode(name, sourceSection);
|
|
1515 }
|
|
1516
|
|
1517 return readLocal;
|
|
1518 }
|
|
1519
|
|
1520 @Override
|
|
1521 public Object visitOpAsgnAndNode(org.jrubyparser.ast.OpAsgnAndNode node) {
|
|
1522 final org.jrubyparser.ast.Node lhs = node.getFirst();
|
|
1523 final org.jrubyparser.ast.Node rhs = node.getSecond();
|
|
1524
|
|
1525 return AndNodeFactory.create(context, translate(node.getPosition()), (RubyNode) lhs.accept(this), (RubyNode) rhs.accept(this));
|
|
1526 }
|
|
1527
|
|
1528 @Override
|
|
1529 public Object visitOpAsgnNode(org.jrubyparser.ast.OpAsgnNode node) {
|
|
1530 /*
|
|
1531 * We're going to de-sugar a.foo += c into a.foo = a.foo + c. Note that we can't evaluate a
|
|
1532 * more than once, so we put it into a temporary, and we're doing something more like:
|
|
1533 *
|
|
1534 * temp = a; temp.foo = temp.foo + c
|
|
1535 */
|
|
1536
|
|
1537 final String temp = environment.allocateLocalTemp();
|
|
1538 final org.jrubyparser.ast.Node writeReceiverToTemp = new org.jrubyparser.ast.LocalAsgnNode(node.getPosition(), temp, 0, node.getReceiver());
|
|
1539 final org.jrubyparser.ast.Node readReceiverFromTemp = new org.jrubyparser.ast.LocalVarNode(node.getPosition(), 0, temp);
|
|
1540
|
|
1541 final org.jrubyparser.ast.Node readMethod = new org.jrubyparser.ast.CallNode(node.getPosition(), readReceiverFromTemp, node.getVariableName(), null);
|
|
1542 final org.jrubyparser.ast.Node operation = new org.jrubyparser.ast.CallNode(node.getPosition(), readMethod, node.getOperatorName(), buildArrayNode(node.getPosition(), node.getValue()));
|
|
1543 final org.jrubyparser.ast.Node writeMethod = new org.jrubyparser.ast.CallNode(node.getPosition(), readReceiverFromTemp, node.getVariableName() + "=", buildArrayNode(node.getPosition(),
|
|
1544 operation));
|
|
1545
|
|
1546 final org.jrubyparser.ast.BlockNode block = new org.jrubyparser.ast.BlockNode(node.getPosition());
|
|
1547 block.add(writeReceiverToTemp);
|
|
1548 block.add(writeMethod);
|
|
1549
|
|
1550 return block.accept(this);
|
|
1551 }
|
|
1552
|
|
1553 @Override
|
|
1554 public Object visitOpAsgnOrNode(org.jrubyparser.ast.OpAsgnOrNode node) {
|
|
1555 /*
|
|
1556 * De-sugar x ||= y into x || x = y. No repeated evaluations there so it's easy. It's also
|
|
1557 * basically how jruby-parser represents it already. We'll do it directly, rather than via
|
|
1558 * another JRuby AST node.
|
|
1559 */
|
|
1560
|
|
1561 final org.jrubyparser.ast.Node lhs = node.getFirst();
|
|
1562 final org.jrubyparser.ast.Node rhs = node.getSecond();
|
|
1563
|
|
1564 return OrNodeFactory.create(context, translate(node.getPosition()), (RubyNode) lhs.accept(this), (RubyNode) rhs.accept(this));
|
|
1565 }
|
|
1566
|
|
1567 @Override
|
|
1568 public Object visitOpElementAsgnNode(org.jrubyparser.ast.OpElementAsgnNode node) {
|
|
1569 /*
|
|
1570 * We're going to de-sugar a[b] += c into a[b] = a[b] + c. See discussion in
|
|
1571 * visitOpAsgnNode.
|
|
1572 */
|
|
1573
|
|
1574 org.jrubyparser.ast.Node index;
|
|
1575
|
|
1576 if (node.getArgs() == null) {
|
|
1577 index = null;
|
|
1578 } else {
|
|
1579 index = node.getArgs().childNodes().get(0);
|
|
1580 }
|
|
1581
|
|
1582 final org.jrubyparser.ast.Node operand = node.getValue();
|
|
1583
|
|
1584 final String temp = environment.allocateLocalTemp();
|
|
1585 final org.jrubyparser.ast.Node writeArrayToTemp = new org.jrubyparser.ast.LocalAsgnNode(node.getPosition(), temp, 0, node.getReceiver());
|
|
1586 final org.jrubyparser.ast.Node readArrayFromTemp = new org.jrubyparser.ast.LocalVarNode(node.getPosition(), 0, temp);
|
|
1587
|
|
1588 final org.jrubyparser.ast.Node arrayRead = new org.jrubyparser.ast.CallNode(node.getPosition(), readArrayFromTemp, "[]", buildArrayNode(node.getPosition(), index));
|
|
1589
|
|
1590 final String op = node.getOperatorName();
|
|
1591
|
|
1592 org.jrubyparser.ast.Node operation = null;
|
|
1593
|
|
1594 if (op.equals("||")) {
|
|
1595 operation = new org.jrubyparser.ast.OrNode(node.getPosition(), arrayRead, operand);
|
|
1596 } else if (op.equals("&&")) {
|
|
1597 operation = new org.jrubyparser.ast.AndNode(node.getPosition(), arrayRead, operand);
|
|
1598 } else {
|
|
1599 operation = new org.jrubyparser.ast.CallNode(node.getPosition(), arrayRead, node.getOperatorName(), buildArrayNode(node.getPosition(), operand));
|
|
1600 }
|
|
1601
|
|
1602 final org.jrubyparser.ast.Node arrayWrite = new org.jrubyparser.ast.CallNode(node.getPosition(), readArrayFromTemp, "[]=", buildArrayNode(node.getPosition(), index, operation));
|
|
1603
|
|
1604 final org.jrubyparser.ast.BlockNode block = new org.jrubyparser.ast.BlockNode(node.getPosition());
|
|
1605 block.add(writeArrayToTemp);
|
|
1606 block.add(arrayWrite);
|
|
1607
|
|
1608 return block.accept(this);
|
|
1609 }
|
|
1610
|
|
1611 private static org.jrubyparser.ast.ArrayNode buildArrayNode(org.jrubyparser.SourcePosition sourcePosition, org.jrubyparser.ast.Node first, org.jrubyparser.ast.Node... rest) {
|
|
1612 if (first == null) {
|
|
1613 return new org.jrubyparser.ast.ArrayNode(sourcePosition);
|
|
1614 }
|
|
1615
|
|
1616 final org.jrubyparser.ast.ArrayNode array = new org.jrubyparser.ast.ArrayNode(sourcePosition, first);
|
|
1617
|
|
1618 for (org.jrubyparser.ast.Node node : rest) {
|
|
1619 array.add(node);
|
|
1620 }
|
|
1621
|
|
1622 return array;
|
|
1623 }
|
|
1624
|
|
1625 @Override
|
|
1626 public Object visitOrNode(org.jrubyparser.ast.OrNode node) {
|
|
1627 final SourceSection sourceSection = translate(node.getPosition());
|
|
1628
|
|
1629 RubyNode x;
|
|
1630
|
|
1631 if (node.getFirst() == null) {
|
|
1632 x = new NilNode(context, sourceSection);
|
|
1633 } else {
|
|
1634 x = (RubyNode) node.getFirst().accept(this);
|
|
1635 }
|
|
1636
|
|
1637 RubyNode y;
|
|
1638
|
|
1639 if (node.getSecond() == null) {
|
|
1640 y = new NilNode(context, sourceSection);
|
|
1641 } else {
|
|
1642 y = (RubyNode) node.getSecond().accept(this);
|
|
1643 }
|
|
1644
|
|
1645 return OrNodeFactory.create(context, sourceSection, x, y);
|
|
1646 }
|
|
1647
|
|
1648 @Override
|
|
1649 public Object visitPostExeNode(org.jrubyparser.ast.PostExeNode node) {
|
|
1650 return unimplemented(node);
|
|
1651 }
|
|
1652
|
|
1653 @Override
|
|
1654 public Object visitPreExeNode(org.jrubyparser.ast.PreExeNode node) {
|
|
1655 return unimplemented(node);
|
|
1656 }
|
|
1657
|
|
1658 @Override
|
|
1659 public Object visitRedoNode(org.jrubyparser.ast.RedoNode node) {
|
|
1660 return new RedoNode(context, translate(node.getPosition()));
|
|
1661 }
|
|
1662
|
|
1663 @Override
|
|
1664 public Object visitRegexpNode(org.jrubyparser.ast.RegexpNode node) {
|
|
1665 RubyRegexp regexp;
|
|
1666
|
|
1667 try {
|
|
1668 final String patternText = node.getValue();
|
|
1669
|
|
1670 int flags = Pattern.MULTILINE | Pattern.UNIX_LINES;
|
|
1671
|
|
1672 final org.jrubyparser.RegexpOptions options = node.getOptions();
|
|
1673
|
|
1674 if (options.isIgnorecase()) {
|
|
1675 flags |= Pattern.CASE_INSENSITIVE;
|
|
1676 }
|
|
1677
|
|
1678 if (options.isMultiline()) {
|
|
1679 // TODO(cs): isn't this the default?
|
|
1680 flags |= Pattern.MULTILINE;
|
|
1681 }
|
|
1682
|
|
1683 final Pattern pattern = Pattern.compile(patternText, flags);
|
|
1684
|
|
1685 regexp = new RubyRegexp(context.getCoreLibrary().getRegexpClass(), pattern);
|
|
1686 } catch (PatternSyntaxException e) {
|
|
1687 context.implementationMessage("failed to parse Ruby regexp " + node.getValue() + " as Java regexp - replacing with .");
|
|
1688 regexp = new RubyRegexp(context.getCoreLibrary().getRegexpClass(), ".");
|
|
1689 }
|
|
1690
|
|
1691 final ObjectLiteralNode literalNode = new ObjectLiteralNode(context, translate(node.getPosition()), regexp);
|
|
1692 return literalNode;
|
|
1693 }
|
|
1694
|
|
1695 @Override
|
|
1696 public Object visitRescueBodyNode(org.jrubyparser.ast.RescueBodyNode node) {
|
|
1697 return unimplemented(node);
|
|
1698 }
|
|
1699
|
|
1700 @Override
|
|
1701 public Object visitRescueNode(org.jrubyparser.ast.RescueNode node) {
|
|
1702 final SourceSection sourceSection = translate(node.getPosition());
|
|
1703
|
|
1704 RubyNode tryPart;
|
|
1705
|
|
1706 if (node.getBody() != null) {
|
|
1707 tryPart = (RubyNode) node.getBody().accept(this);
|
|
1708 } else {
|
|
1709 tryPart = new NilNode(context, sourceSection);
|
|
1710 }
|
|
1711
|
|
1712 final List<RescueNode> rescueNodes = new ArrayList<>();
|
|
1713
|
|
1714 org.jrubyparser.ast.RescueBodyNode rescueBody = node.getRescue();
|
|
1715
|
|
1716 while (rescueBody != null) {
|
|
1717 if (rescueBody.getExceptions() != null) {
|
|
1718 if (rescueBody.getExceptions() instanceof org.jrubyparser.ast.ArrayNode) {
|
|
1719 final List<org.jrubyparser.ast.Node> exceptionNodes = ((org.jrubyparser.ast.ArrayNode) rescueBody.getExceptions()).childNodes();
|
|
1720
|
|
1721 final RubyNode[] handlingClasses = new RubyNode[exceptionNodes.size()];
|
|
1722
|
|
1723 for (int n = 0; n < handlingClasses.length; n++) {
|
|
1724 handlingClasses[n] = (RubyNode) exceptionNodes.get(n).accept(this);
|
|
1725 }
|
|
1726
|
|
1727 RubyNode translatedBody;
|
|
1728
|
|
1729 if (rescueBody.getBody() == null) {
|
|
1730 translatedBody = new NilNode(context, sourceSection);
|
|
1731 } else {
|
|
1732 translatedBody = (RubyNode) rescueBody.getBody().accept(this);
|
|
1733 }
|
|
1734
|
|
1735 final RescueClassesNode rescueNode = new RescueClassesNode(context, sourceSection, handlingClasses, translatedBody);
|
|
1736 rescueNodes.add(rescueNode);
|
|
1737 } else if (rescueBody.getExceptions() instanceof org.jrubyparser.ast.SplatNode) {
|
|
1738 final org.jrubyparser.ast.SplatNode splat = (org.jrubyparser.ast.SplatNode) rescueBody.getExceptions();
|
|
1739
|
|
1740 RubyNode splatTranslated;
|
|
1741
|
|
1742 if (splat.getValue() == null) {
|
|
1743 splatTranslated = new NilNode(context, sourceSection);
|
|
1744 } else {
|
|
1745 splatTranslated = (RubyNode) splat.getValue().accept(this);
|
|
1746 }
|
|
1747
|
|
1748 RubyNode bodyTranslated;
|
|
1749
|
|
1750 if (rescueBody.getBody() == null) {
|
|
1751 bodyTranslated = new NilNode(context, sourceSection);
|
|
1752 } else {
|
|
1753 bodyTranslated = (RubyNode) rescueBody.getBody().accept(this);
|
|
1754 }
|
|
1755
|
|
1756 final RescueSplatNode rescueNode = new RescueSplatNode(context, sourceSection, splatTranslated, bodyTranslated);
|
|
1757 rescueNodes.add(rescueNode);
|
|
1758 } else {
|
|
1759 unimplemented(node);
|
|
1760 }
|
|
1761 } else {
|
|
1762 RubyNode bodyNode;
|
|
1763
|
|
1764 if (rescueBody.getBody() == null) {
|
|
1765 bodyNode = new NilNode(context, sourceSection);
|
|
1766 } else {
|
|
1767 bodyNode = (RubyNode) rescueBody.getBody().accept(this);
|
|
1768 }
|
|
1769
|
|
1770 final RescueAnyNode rescueNode = new RescueAnyNode(context, sourceSection, bodyNode);
|
|
1771 rescueNodes.add(rescueNode);
|
|
1772 }
|
|
1773
|
|
1774 rescueBody = rescueBody.getOptRescue();
|
|
1775 }
|
|
1776
|
|
1777 RubyNode elsePart;
|
|
1778
|
|
1779 if (node.getElse() != null) {
|
|
1780 elsePart = (RubyNode) node.getElse().accept(this);
|
|
1781 } else {
|
|
1782 elsePart = new NilNode(context, sourceSection);
|
|
1783 }
|
|
1784
|
|
1785 return new TryNode(context, sourceSection, tryPart, rescueNodes.toArray(new RescueNode[rescueNodes.size()]), elsePart);
|
|
1786 }
|
|
1787
|
|
1788 @Override
|
|
1789 public Object visitRestArgNode(org.jrubyparser.ast.RestArgNode node) {
|
|
1790 return unimplemented(node);
|
|
1791 }
|
|
1792
|
|
1793 @Override
|
|
1794 public Object visitRetryNode(org.jrubyparser.ast.RetryNode node) {
|
|
1795 return new RetryNode(context, translate(node.getPosition()));
|
|
1796 }
|
|
1797
|
|
1798 @Override
|
|
1799 public Object visitReturnNode(org.jrubyparser.ast.ReturnNode node) {
|
|
1800 final SourceSection sourceSection = translate(node.getPosition());
|
|
1801
|
|
1802 RubyNode translatedChild;
|
|
1803
|
|
1804 if (node.getValue() == null) {
|
|
1805 translatedChild = new NilNode(context, sourceSection);
|
|
1806 } else {
|
|
1807 translatedChild = (RubyNode) node.getValue().accept(this);
|
|
1808 }
|
|
1809
|
|
1810 return new ReturnNode(context, sourceSection, environment.getReturnID(), translatedChild);
|
|
1811 }
|
|
1812
|
|
1813 @Override
|
|
1814 public Object visitRootNode(org.jrubyparser.ast.RootNode node) {
|
|
1815 return unimplemented(node);
|
|
1816 }
|
|
1817
|
|
1818 @Override
|
|
1819 public Object visitSClassNode(org.jrubyparser.ast.SClassNode node) {
|
|
1820 final SourceSection sourceSection = translate(node.getPosition());
|
|
1821
|
|
1822 final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getParser().allocateReturnID(), true, true,
|
|
1823 new UniqueMethodIdentifier());
|
|
1824 final ModuleTranslator classTranslator = new ModuleTranslator(context, this, newEnvironment, source);
|
|
1825
|
|
1826 final MethodDefinitionNode definitionMethod = classTranslator.compileClassNode(node.getPosition(), "singleton", node.getBody());
|
|
1827
|
|
1828 final RubyNode receiverNode = (RubyNode) node.getReceiver().accept(this);
|
|
1829
|
|
1830 final SingletonClassNode singletonClassNode = new SingletonClassNode(context, sourceSection, receiverNode);
|
|
1831
|
|
1832 return new OpenModuleNode(context, sourceSection, singletonClassNode, definitionMethod);
|
|
1833 }
|
|
1834
|
|
1835 @Override
|
|
1836 public Object visitSValueNode(org.jrubyparser.ast.SValueNode node) {
|
|
1837 return node.getValue().accept(this);
|
|
1838 }
|
|
1839
|
|
1840 @Override
|
|
1841 public Object visitSelfNode(org.jrubyparser.ast.SelfNode node) {
|
|
1842 return new SelfNode(context, translate(node.getPosition()));
|
|
1843 }
|
|
1844
|
|
1845 @Override
|
|
1846 public Object visitSplatNode(org.jrubyparser.ast.SplatNode node) {
|
|
1847 final SourceSection sourceSection = translate(node.getPosition());
|
|
1848
|
|
1849 RubyNode value;
|
|
1850
|
|
1851 if (node.getValue() == null) {
|
|
1852 value = new NilNode(context, sourceSection);
|
|
1853 } else {
|
|
1854 value = (RubyNode) node.getValue().accept(this);
|
|
1855 }
|
|
1856
|
|
1857 return SplatCastNodeFactory.create(context, sourceSection, value);
|
|
1858 }
|
|
1859
|
|
1860 @Override
|
|
1861 public Object visitStrNode(org.jrubyparser.ast.StrNode node) {
|
|
1862 return new StringLiteralNode(context, translate(node.getPosition()), node.getValue());
|
|
1863 }
|
|
1864
|
|
1865 @Override
|
|
1866 public Object visitSuperNode(org.jrubyparser.ast.SuperNode node) {
|
|
1867 return unimplemented(node);
|
|
1868 }
|
|
1869
|
|
1870 @Override
|
|
1871 public Object visitSymbolNode(org.jrubyparser.ast.SymbolNode node) {
|
|
1872 return new ObjectLiteralNode(context, translate(node.getPosition()), new RubySymbol(context.getCoreLibrary().getSymbolClass(), node.getName()));
|
|
1873 }
|
|
1874
|
|
1875 @Override
|
|
1876 public Object visitToAryNode(org.jrubyparser.ast.ToAryNode node) {
|
|
1877 return unimplemented(node);
|
|
1878 }
|
|
1879
|
|
1880 @Override
|
|
1881 public Object visitTrueNode(org.jrubyparser.ast.TrueNode node) {
|
|
1882 return new BooleanLiteralNode(context, translate(node.getPosition()), true);
|
|
1883 }
|
|
1884
|
|
1885 @Override
|
|
1886 public Object visitUndefNode(org.jrubyparser.ast.UndefNode node) {
|
|
1887 return unimplemented(node);
|
|
1888 }
|
|
1889
|
|
1890 @Override
|
|
1891 public Object visitUntilNode(org.jrubyparser.ast.UntilNode node) {
|
|
1892 final SourceSection sourceSection = translate(node.getPosition());
|
|
1893
|
|
1894 RubyNode condition;
|
|
1895
|
|
1896 if (node.getCondition() == null) {
|
|
1897 condition = new NilNode(context, sourceSection);
|
|
1898 } else {
|
|
1899 condition = (RubyNode) node.getCondition().accept(this);
|
|
1900 }
|
|
1901
|
|
1902 final BooleanCastNode conditionCast = BooleanCastNodeFactory.create(context, sourceSection, condition);
|
|
1903 final NotNode conditionCastNot = new NotNode(context, sourceSection, conditionCast);
|
|
1904 final BooleanCastNode conditionCastNotCast = BooleanCastNodeFactory.create(context, sourceSection, conditionCastNot);
|
|
1905
|
|
1906 final RubyNode body = (RubyNode) node.getBody().accept(this);
|
|
1907
|
|
1908 return new WhileNode(context, sourceSection, conditionCastNotCast, body);
|
|
1909 }
|
|
1910
|
|
1911 @Override
|
|
1912 public Object visitVAliasNode(org.jrubyparser.ast.VAliasNode node) {
|
|
1913 return unimplemented(node);
|
|
1914 }
|
|
1915
|
|
1916 @Override
|
|
1917 public Object visitVCallNode(org.jrubyparser.ast.VCallNode node) {
|
|
1918 final org.jrubyparser.ast.Node receiver = new org.jrubyparser.ast.SelfNode(node.getPosition());
|
|
1919 final org.jrubyparser.ast.Node args = null;
|
|
1920 final org.jrubyparser.ast.Node callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), receiver, node.getName(), args);
|
|
1921
|
|
1922 return callNode.accept(this);
|
|
1923 }
|
|
1924
|
|
1925 @Override
|
|
1926 public Object visitWhenNode(org.jrubyparser.ast.WhenNode node) {
|
|
1927 return unimplemented(node);
|
|
1928 }
|
|
1929
|
|
1930 @Override
|
|
1931 public Object visitWhileNode(org.jrubyparser.ast.WhileNode node) {
|
|
1932 final SourceSection sourceSection = translate(node.getPosition());
|
|
1933
|
|
1934 RubyNode condition;
|
|
1935
|
|
1936 if (node.getCondition() == null) {
|
|
1937 condition = new NilNode(context, sourceSection);
|
|
1938 } else {
|
|
1939 condition = (RubyNode) node.getCondition().accept(this);
|
|
1940 }
|
|
1941
|
|
1942 final BooleanCastNode conditionCast = BooleanCastNodeFactory.create(context, sourceSection, condition);
|
|
1943
|
|
1944 final RubyNode body = (RubyNode) node.getBody().accept(this);
|
|
1945
|
|
1946 return new WhileNode(context, sourceSection, conditionCast, body);
|
|
1947 }
|
|
1948
|
|
1949 @Override
|
|
1950 public Object visitXStrNode(org.jrubyparser.ast.XStrNode node) {
|
|
1951 SourceSection sourceSection = translate(node.getPosition());
|
|
1952
|
|
1953 final StringLiteralNode literal = new StringLiteralNode(context, sourceSection, node.getValue());
|
|
1954
|
|
1955 return new SystemNode(context, sourceSection, literal);
|
|
1956 }
|
|
1957
|
|
1958 @Override
|
|
1959 public Object visitYieldNode(org.jrubyparser.ast.YieldNode node) {
|
|
1960 final List<org.jrubyparser.ast.Node> arguments = new ArrayList<>();
|
|
1961
|
|
1962 final org.jrubyparser.ast.Node argsNode = node.getArgs();
|
|
1963
|
|
1964 if (argsNode != null) {
|
|
1965 if (argsNode instanceof org.jrubyparser.ast.ListNode) {
|
|
1966 arguments.addAll(((org.jrubyparser.ast.ListNode) node.getArgs()).childNodes());
|
|
1967 } else {
|
|
1968 arguments.add(node.getArgs());
|
|
1969 }
|
|
1970 }
|
|
1971
|
|
1972 final List<RubyNode> argumentsTranslated = new ArrayList<>();
|
|
1973
|
|
1974 for (org.jrubyparser.ast.Node argument : arguments) {
|
|
1975 argumentsTranslated.add((RubyNode) argument.accept(this));
|
|
1976 }
|
|
1977
|
|
1978 final RubyNode[] argumentsTranslatedArray = argumentsTranslated.toArray(new RubyNode[argumentsTranslated.size()]);
|
|
1979
|
|
1980 return new YieldNode(context, translate(node.getPosition()), argumentsTranslatedArray);
|
|
1981 }
|
|
1982
|
|
1983 @Override
|
|
1984 public Object visitZArrayNode(org.jrubyparser.ast.ZArrayNode node) {
|
|
1985 final RubyNode[] values = new RubyNode[0];
|
|
1986
|
|
1987 return new UninitialisedArrayLiteralNode(context, translate(node.getPosition()), values);
|
|
1988 }
|
|
1989
|
|
1990 @Override
|
|
1991 public Object visitZSuperNode(org.jrubyparser.ast.ZSuperNode node) {
|
|
1992 return unimplemented(node);
|
|
1993 }
|
|
1994
|
|
1995 public Object visitArgumentNode(org.jrubyparser.ast.ArgumentNode node) {
|
|
1996 return unimplemented(node);
|
|
1997 }
|
|
1998
|
|
1999 public Object visitCommentNode(org.jrubyparser.ast.CommentNode node) {
|
|
2000 return unimplemented(node);
|
|
2001 }
|
|
2002
|
|
2003 public Object visitKeywordArgNode(org.jrubyparser.ast.KeywordArgNode node) {
|
|
2004 return unimplemented(node);
|
|
2005 }
|
|
2006
|
|
2007 public Object visitKeywordRestArgNode(org.jrubyparser.ast.KeywordRestArgNode node) {
|
|
2008 return unimplemented(node);
|
|
2009 }
|
|
2010
|
|
2011 public Object visitListNode(org.jrubyparser.ast.ListNode node) {
|
|
2012 return unimplemented(node);
|
|
2013 }
|
|
2014
|
|
2015 public Object visitMethodNameNode(org.jrubyparser.ast.MethodNameNode node) {
|
|
2016 return unimplemented(node);
|
|
2017 }
|
|
2018
|
|
2019 public Object visitOptArgNode(org.jrubyparser.ast.OptArgNode node) {
|
|
2020 return unimplemented(node);
|
|
2021 }
|
|
2022
|
|
2023 public Object visitSyntaxNode(org.jrubyparser.ast.SyntaxNode node) {
|
|
2024 return unimplemented(node);
|
|
2025 }
|
|
2026
|
|
2027 public Object visitImplicitNilNode(org.jrubyparser.ast.ImplicitNilNode node) {
|
|
2028 return new NilNode(context, translate(node.getPosition()));
|
|
2029 }
|
|
2030
|
|
2031 public Object visitLambdaNode(org.jrubyparser.ast.LambdaNode node) {
|
|
2032 // TODO(cs): code copied and modified from visitIterNode - extract common
|
|
2033
|
|
2034 final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParser(), environment.getReturnID(), false, false, new UniqueMethodIdentifier());
|
|
2035 final MethodTranslator methodCompiler = new MethodTranslator(context, this, newEnvironment, false, source);
|
|
2036
|
|
2037 org.jrubyparser.ast.ArgsNode argsNode;
|
|
2038
|
|
2039 if (node.getVar() instanceof org.jrubyparser.ast.ArgsNode) {
|
|
2040 argsNode = (org.jrubyparser.ast.ArgsNode) node.getVar();
|
|
2041 } else if (node.getVar() instanceof org.jrubyparser.ast.DAsgnNode) {
|
|
2042 final org.jrubyparser.ast.ArgumentNode arg = new org.jrubyparser.ast.ArgumentNode(node.getPosition(), ((org.jrubyparser.ast.DAsgnNode) node.getVar()).getName());
|
|
2043 final org.jrubyparser.ast.ListNode preArgs = new org.jrubyparser.ast.ArrayNode(node.getPosition(), arg);
|
|
2044 argsNode = new org.jrubyparser.ast.ArgsNode(node.getPosition(), preArgs, null, null, null, null, null, null);
|
|
2045 } else if (node.getVar() == null) {
|
|
2046 argsNode = null;
|
|
2047 } else {
|
|
2048 throw new UnsupportedOperationException();
|
|
2049 }
|
|
2050
|
|
2051 final MethodDefinitionNode definitionNode = methodCompiler.compileFunctionNode(translate(node.getPosition()), "(lambda)", argsNode, node.getBody());
|
|
2052
|
|
2053 return new LambdaNode(context, translate(node.getPosition()), definitionNode);
|
|
2054 }
|
|
2055
|
|
2056 public Object visitUnaryCallNode(org.jrubyparser.ast.UnaryCallNode node) {
|
|
2057 final org.jrubyparser.ast.Node callNode = new org.jrubyparser.ast.CallNode(node.getPosition(), node.getReceiver(), node.getName(), null, null);
|
|
2058 return callNode.accept(this);
|
|
2059 }
|
|
2060
|
|
2061 protected Object unimplemented(org.jrubyparser.ast.Node node) {
|
|
2062 context.implementationMessage("warning: %s at %s does nothing", node, node.getPosition());
|
|
2063 return new NilNode(context, translate(node.getPosition()));
|
|
2064 }
|
|
2065
|
|
2066 protected SourceSection translate(final org.jrubyparser.SourcePosition sourcePosition) {
|
|
2067 try {
|
|
2068 // TODO(cs): get an identifier
|
|
2069 final String identifier = "(identifier)";
|
|
2070
|
|
2071 // TODO(cs): work out the start column
|
|
2072 final int startColumn = -1;
|
|
2073
|
|
2074 final int charLength = sourcePosition.getEndOffset() - sourcePosition.getStartOffset();
|
|
2075
|
|
2076 return new DefaultSourceSection(source, identifier, sourcePosition.getStartLine() + 1, startColumn, sourcePosition.getStartOffset(), charLength);
|
|
2077 } catch (UnsupportedOperationException e) {
|
|
2078 // In some circumstances JRuby can't tell you what the position is
|
|
2079 return translate(new org.jrubyparser.SourcePosition("(unknown)", 0, 0));
|
|
2080 }
|
|
2081 }
|
|
2082
|
|
2083 protected SequenceNode initFlipFlopStates(SourceSection sourceSection) {
|
|
2084 final RubyNode[] initNodes = new RubyNode[environment.getFlipFlopStates().size()];
|
|
2085
|
|
2086 for (int n = 0; n < initNodes.length; n++) {
|
|
2087 initNodes[n] = new InitFlipFlopSlotNode(context, sourceSection, environment.getFlipFlopStates().get(n));
|
|
2088 }
|
|
2089
|
|
2090 return new SequenceNode(context, sourceSection, initNodes);
|
|
2091 }
|
|
2092
|
|
2093 }
|