comparison graal/com.oracle.truffle.ruby.parser/src/com/oracle/truffle/ruby/parser/Translator.java @ 13514:0fbee3eb71f0

Ruby: import project.
author Chris Seaton <chris.seaton@oracle.com>
date Mon, 06 Jan 2014 17:12:09 +0000
parents
children 44288fe54352 1894412de0ed
comparison
equal deleted inserted replaced
13513:64a23ce736a0 13514:0fbee3eb71f0
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 }