comparison graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/ModuleNodes.java @ 13514:0fbee3eb71f0

Ruby: import project.
author Chris Seaton <chris.seaton@oracle.com>
date Mon, 06 Jan 2014 17:12:09 +0000
parents
children 232eb6708943
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.nodes.core;
11
12 import com.oracle.truffle.api.*;
13 import com.oracle.truffle.api.dsl.*;
14 import com.oracle.truffle.api.frame.*;
15 import com.oracle.truffle.api.nodes.*;
16 import com.oracle.truffle.ruby.nodes.*;
17 import com.oracle.truffle.ruby.nodes.control.*;
18 import com.oracle.truffle.ruby.nodes.methods.arguments.*;
19 import com.oracle.truffle.ruby.nodes.objects.*;
20 import com.oracle.truffle.ruby.nodes.objects.instancevariables.*;
21 import com.oracle.truffle.ruby.runtime.*;
22 import com.oracle.truffle.ruby.runtime.RubyParser.*;
23 import com.oracle.truffle.ruby.runtime.core.*;
24 import com.oracle.truffle.ruby.runtime.core.array.*;
25 import com.oracle.truffle.ruby.runtime.methods.*;
26
27 @CoreClass(name = "Module")
28 public abstract class ModuleNodes {
29
30 @CoreMethod(names = "alias_method", minArgs = 2, maxArgs = 2)
31 public abstract static class AliasMethodNode extends CoreMethodNode {
32
33 public AliasMethodNode(RubyContext context, SourceSection sourceSection) {
34 super(context, sourceSection);
35 }
36
37 public AliasMethodNode(AliasMethodNode prev) {
38 super(prev);
39 }
40
41 @Specialization
42 public RubyModule aliasMethod(RubyModule module, RubySymbol newName, RubySymbol oldName) {
43 module.alias(newName.toString(), oldName.toString());
44 return module;
45 }
46 }
47
48 @CoreMethod(names = "append_features", minArgs = 1, maxArgs = 1)
49 public abstract static class AppendFeaturesNode extends CoreMethodNode {
50
51 public AppendFeaturesNode(RubyContext context, SourceSection sourceSection) {
52 super(context, sourceSection);
53 }
54
55 public AppendFeaturesNode(AppendFeaturesNode prev) {
56 super(prev);
57 }
58
59 @Specialization
60 public NilPlaceholder appendFeatures(RubyModule module, RubyModule other) {
61 module.appendFeatures(other);
62 return NilPlaceholder.INSTANCE;
63 }
64 }
65
66 @CoreMethod(names = "attr_reader", isSplatted = true, appendCallNode = true)
67 public abstract static class AttrReaderNode extends CoreMethodNode {
68
69 public AttrReaderNode(RubyContext context, SourceSection sourceSection) {
70 super(context, sourceSection);
71 }
72
73 public AttrReaderNode(AttrReaderNode prev) {
74 super(prev);
75 }
76
77 @Specialization
78 public NilPlaceholder attrReader(RubyModule module, Object[] args) {
79 final Node callSite = (Node) args[args.length - 1];
80 final SourceSection sourceSection = callSite.getSourceSection();
81
82 for (int n = 0; n < args.length - 1; n++) {
83 attrReader(getContext(), sourceSection, module, args[n].toString());
84 }
85
86 return NilPlaceholder.INSTANCE;
87 }
88
89 public static void attrReader(RubyContext context, SourceSection sourceSection, RubyModule module, String name) {
90 CompilerDirectives.transferToInterpreter();
91
92 final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, Arity.NO_ARGS);
93
94 final SelfNode self = new SelfNode(context, sourceSection);
95 final UninitializedReadInstanceVariableNode readInstanceVariable = new UninitializedReadInstanceVariableNode(context, sourceSection, name, self);
96
97 final SequenceNode block = new SequenceNode(context, sourceSection, checkArity, readInstanceVariable);
98
99 final RubyRootNode pristineRoot = new RubyRootNode(sourceSection, name + "(attr_reader)", block);
100 final CallTarget callTarget = Truffle.getRuntime().createCallTarget(NodeUtil.cloneNode(pristineRoot));
101 final InlinableMethodImplementation methodImplementation = new InlinableMethodImplementation(callTarget, null, new FrameDescriptor(), pristineRoot, true, false);
102 final RubyMethod method = new RubyMethod(sourceSection, module, new UniqueMethodIdentifier(), null, name, Visibility.PUBLIC, false, methodImplementation);
103
104 module.addMethod(method);
105 }
106 }
107
108 @CoreMethod(names = "attr_writer", isSplatted = true, appendCallNode = true)
109 public abstract static class AttrWriterNode extends CoreMethodNode {
110
111 public AttrWriterNode(RubyContext context, SourceSection sourceSection) {
112 super(context, sourceSection);
113 }
114
115 public AttrWriterNode(AttrWriterNode prev) {
116 super(prev);
117 }
118
119 @Specialization
120 public NilPlaceholder attrWriter(RubyModule module, Object[] args) {
121 final Node callSite = (Node) args[args.length - 1];
122 final SourceSection sourceSection = callSite.getSourceSection();
123
124 for (int n = 0; n < args.length - 1; n++) {
125 attrWriter(getContext(), sourceSection, module, args[n].toString());
126 }
127
128 return NilPlaceholder.INSTANCE;
129 }
130
131 public static void attrWriter(RubyContext context, SourceSection sourceSection, RubyModule module, String name) {
132 CompilerDirectives.transferToInterpreter();
133
134 final CheckArityNode checkArity = new CheckArityNode(context, sourceSection, Arity.ONE_ARG);
135
136 final SelfNode self = new SelfNode(context, sourceSection);
137 final ReadPreArgumentNode readArgument = new ReadPreArgumentNode(context, sourceSection, 0, false);
138 final UninitializedWriteInstanceVariableNode writeInstanceVariable = new UninitializedWriteInstanceVariableNode(context, sourceSection, name, self, readArgument);
139
140 final SequenceNode block = new SequenceNode(context, sourceSection, checkArity, writeInstanceVariable);
141
142 final RubyRootNode pristineRoot = new RubyRootNode(sourceSection, name + "(attr_writer)", block);
143 final CallTarget callTarget = Truffle.getRuntime().createCallTarget(NodeUtil.cloneNode(pristineRoot));
144 final InlinableMethodImplementation methodImplementation = new InlinableMethodImplementation(callTarget, null, new FrameDescriptor(), pristineRoot, true, false);
145 final RubyMethod method = new RubyMethod(sourceSection, module, new UniqueMethodIdentifier(), null, name + "=", Visibility.PUBLIC, false, methodImplementation);
146
147 module.addMethod(method);
148 }
149 }
150
151 @CoreMethod(names = {"attr_accessor", "attr"}, isSplatted = true, appendCallNode = true)
152 public abstract static class AttrAccessorNode extends CoreMethodNode {
153
154 public AttrAccessorNode(RubyContext context, SourceSection sourceSection) {
155 super(context, sourceSection);
156 }
157
158 public AttrAccessorNode(AttrAccessorNode prev) {
159 super(prev);
160 }
161
162 @Specialization
163 public NilPlaceholder attrAccessor(RubyModule module, Object[] args) {
164 final Node callSite = (Node) args[args.length - 1];
165 final SourceSection sourceSection = callSite.getSourceSection();
166
167 for (int n = 0; n < args.length - 1; n++) {
168 attrAccessor(getContext(), sourceSection, module, args[n].toString());
169 }
170
171 return NilPlaceholder.INSTANCE;
172 }
173
174 public static void attrAccessor(RubyContext context, SourceSection sourceSection, RubyModule module, String name) {
175 CompilerDirectives.transferToInterpreter();
176 AttrReaderNode.attrReader(context, sourceSection, module, name);
177 AttrWriterNode.attrWriter(context, sourceSection, module, name);
178 }
179
180 }
181
182 @CoreMethod(names = "class_eval", minArgs = 1, maxArgs = 3)
183 public abstract static class ClassEvalNode extends CoreMethodNode {
184
185 public ClassEvalNode(RubyContext context, SourceSection sourceSection) {
186 super(context, sourceSection);
187 }
188
189 public ClassEvalNode(ClassEvalNode prev) {
190 super(prev);
191 }
192
193 @Specialization
194 public Object classEval(VirtualFrame frame, RubyModule module, RubyString code, @SuppressWarnings("unused") UndefinedPlaceholder file, @SuppressWarnings("unused") UndefinedPlaceholder line) {
195 final Source source = getContext().getSourceManager().get("(eval)", code.toString());
196 return getContext().execute(getContext(), source, ParserContext.MODULE, module, frame.materialize());
197 }
198
199 @Specialization
200 public Object classEval(VirtualFrame frame, RubyModule module, RubyString code, RubyString file, @SuppressWarnings("unused") UndefinedPlaceholder line) {
201 final Source source = getContext().getSourceManager().get(file.toString(), code.toString());
202 return getContext().execute(getContext(), source, ParserContext.MODULE, module, frame.materialize());
203 }
204
205 @Specialization
206 public Object classEval(VirtualFrame frame, RubyModule module, RubyString code, RubyString file, @SuppressWarnings("unused") int line) {
207 final Source source = getContext().getSourceManager().get(file.toString(), code.toString());
208 return getContext().execute(getContext(), source, ParserContext.MODULE, module, frame.materialize());
209 }
210
211 }
212
213 @CoreMethod(names = "class_variable_defined?", maxArgs = 0)
214 public abstract static class ClassVariableDefinedNode extends CoreMethodNode {
215
216 public ClassVariableDefinedNode(RubyContext context, SourceSection sourceSection) {
217 super(context, sourceSection);
218 }
219
220 public ClassVariableDefinedNode(ClassVariableDefinedNode prev) {
221 super(prev);
222 }
223
224 @Specialization
225 public boolean isClassVariableDefined(RubyModule module, RubyString name) {
226 return module.lookupClassVariable(name.toString()) != null;
227 }
228
229 @Specialization
230 public boolean isClassVariableDefined(RubyModule module, RubySymbol name) {
231 return module.lookupClassVariable(name.toString()) != null;
232 }
233
234 }
235
236 @CoreMethod(names = "constants", maxArgs = 0)
237 public abstract static class ConstantsNode extends CoreMethodNode {
238
239 public ConstantsNode(RubyContext context, SourceSection sourceSection) {
240 super(context, sourceSection);
241 }
242
243 public ConstantsNode(ConstantsNode prev) {
244 super(prev);
245 }
246
247 @Specialization
248 public RubyArray constants(@SuppressWarnings("unused") RubyModule module) {
249 getContext().implementationMessage("Module#constants returns an empty array");
250 return new RubyArray(getContext().getCoreLibrary().getArrayClass());
251 }
252 }
253
254 @CoreMethod(names = "const_defined?", minArgs = 1, maxArgs = 2)
255 public abstract static class ConstDefinedNode extends CoreMethodNode {
256
257 public ConstDefinedNode(RubyContext context, SourceSection sourceSection) {
258 super(context, sourceSection);
259 }
260
261 public ConstDefinedNode(ConstDefinedNode prev) {
262 super(prev);
263 }
264
265 @Specialization(order = 1)
266 public boolean isConstDefined(RubyModule module, RubyString name, @SuppressWarnings("unused") UndefinedPlaceholder inherit) {
267 return module.lookupConstant(name.toString()) != null;
268 }
269
270 @Specialization(order = 2)
271 public boolean isConstDefined(RubyModule module, RubyString name, boolean inherit) {
272 if (inherit) {
273 return module.lookupConstant(name.toString()) != null;
274 } else {
275 return module.getConstants().containsKey(name.toString());
276 }
277 }
278
279 @Specialization(order = 3)
280 public boolean isConstDefined(RubyModule module, RubySymbol name, @SuppressWarnings("unused") UndefinedPlaceholder inherit) {
281 return module.lookupConstant(name.toString()) != null;
282 }
283
284 public boolean isConstDefined(RubyModule module, RubySymbol name, boolean inherit) {
285 if (inherit) {
286 return module.lookupConstant(name.toString()) != null;
287 } else {
288 return module.getConstants().containsKey(name.toString());
289 }
290 }
291
292 }
293
294 @CoreMethod(names = "define_method", needsBlock = true, minArgs = 1, maxArgs = 2)
295 public abstract static class DefineMethodNode extends CoreMethodNode {
296
297 public DefineMethodNode(RubyContext context, SourceSection sourceSection) {
298 super(context, sourceSection);
299 }
300
301 public DefineMethodNode(DefineMethodNode prev) {
302 super(prev);
303 }
304
305 @Specialization(order = 1)
306 public RubyMethod defineMethod(RubyModule module, RubyString name, @SuppressWarnings("unused") UndefinedPlaceholder proc, RubyProc block) {
307 final RubyMethod method = block.getMethod();
308 module.addMethod(method.withNewName(name.toString()));
309 return method;
310 }
311
312 @Specialization(order = 2)
313 public RubyMethod defineMethod(RubyModule module, RubyString name, RubyProc proc, @SuppressWarnings("unused") UndefinedPlaceholder block) {
314 final RubyMethod method = proc.getMethod();
315 module.addMethod(method.withNewName(name.toString()));
316 return method;
317 }
318
319 @Specialization(order = 3)
320 public RubyMethod defineMethod(RubyModule module, RubySymbol name, @SuppressWarnings("unused") UndefinedPlaceholder proc, RubyProc block) {
321 final RubyMethod method = block.getMethod();
322 module.addMethod(method.withNewName(name.toString()));
323 return method;
324 }
325
326 @Specialization(order = 4)
327 public RubyMethod defineMethod(RubyModule module, RubySymbol name, RubyProc proc, @SuppressWarnings("unused") UndefinedPlaceholder block) {
328 final RubyMethod method = proc.getMethod();
329 module.addMethod(method.withNewName(name.toString()));
330 return method;
331 }
332
333 }
334
335 @CoreMethod(names = "include", isSplatted = true, minArgs = 1)
336 public abstract static class IncludeNode extends CoreMethodNode {
337
338 public IncludeNode(RubyContext context, SourceSection sourceSection) {
339 super(context, sourceSection);
340 }
341
342 public IncludeNode(IncludeNode prev) {
343 super(prev);
344 }
345
346 @Specialization
347 public NilPlaceholder include(RubyModule module, Object[] args) {
348 // Note that we traverse the arguments backwards
349
350 for (int n = args.length - 1; n >= 0; n--) {
351 if (args[n] instanceof RubyModule) {
352 final RubyModule included = (RubyModule) args[n];
353
354 // Note that we do appear to do full method lookup here
355 included.getLookupNode().lookupMethod("append_features").call(null, included, null, module);
356
357 // TODO(cs): call included hook
358 }
359 }
360
361 return NilPlaceholder.INSTANCE;
362 }
363 }
364
365 @CoreMethod(names = "method_defined?", minArgs = 1, maxArgs = 2)
366 public abstract static class MethodDefinedNode extends CoreMethodNode {
367
368 public MethodDefinedNode(RubyContext context, SourceSection sourceSection) {
369 super(context, sourceSection);
370 }
371
372 public MethodDefinedNode(MethodDefinedNode prev) {
373 super(prev);
374 }
375
376 @Specialization(order = 1)
377 public boolean isMethodDefined(RubyModule module, RubyString name, @SuppressWarnings("unused") UndefinedPlaceholder inherit) {
378 return module.lookupMethod(name.toString()) != null;
379 }
380
381 @Specialization(order = 2)
382 public boolean isMethodDefined(RubyModule module, RubyString name, boolean inherit) {
383 if (inherit) {
384 return module.lookupMethod(name.toString()) != null;
385 } else {
386 return module.getMethods().containsKey(name.toString());
387 }
388 }
389
390 @Specialization(order = 3)
391 public boolean isMethodDefined(RubyModule module, RubySymbol name, @SuppressWarnings("unused") UndefinedPlaceholder inherit) {
392 return module.lookupMethod(name.toString()) != null;
393 }
394
395 public boolean isMethodDefined(RubyModule module, RubySymbol name, boolean inherit) {
396 if (inherit) {
397 return module.lookupMethod(name.toString()) != null;
398 } else {
399 return module.getMethods().containsKey(name.toString());
400 }
401 }
402 }
403
404 @CoreMethod(names = "module_eval", minArgs = 1, maxArgs = 3)
405 public abstract static class ModuleEvalNode extends CoreMethodNode {
406
407 public ModuleEvalNode(RubyContext context, SourceSection sourceSection) {
408 super(context, sourceSection);
409 }
410
411 public ModuleEvalNode(ModuleEvalNode prev) {
412 super(prev);
413 }
414
415 @Specialization
416 public RubyModule moduleEval(RubyModule module, RubyString code, @SuppressWarnings("unused") Object file, @SuppressWarnings("unused") Object line) {
417 module.moduleEval(code.toString());
418 return module;
419 }
420 }
421
422 @CoreMethod(names = "module_function", isSplatted = true)
423 public abstract static class ModuleFunctionNode extends CoreMethodNode {
424
425 public ModuleFunctionNode(RubyContext context, SourceSection sourceSection) {
426 super(context, sourceSection);
427 }
428
429 public ModuleFunctionNode(ModuleFunctionNode prev) {
430 super(prev);
431 }
432
433 @Specialization
434 public NilPlaceholder moduleFunction(VirtualFrame frame, RubyModule module, Object... args) {
435 if (args.length == 0) {
436 final Frame unpacked = frame.getCaller().unpack();
437
438 final FrameSlot slot = unpacked.getFrameDescriptor().findFrameSlot(RubyModule.MODULE_FUNCTION_FLAG_FRAME_SLOT_ID);
439
440 /*
441 * setObject, even though it's a boolean, so we can getObject and either get the
442 * default Nil or the boolean value without triggering deoptimization.
443 */
444
445 unpacked.setObject(slot, true);
446 } else {
447 for (Object argument : args) {
448 final String methodName = argument.toString();
449 module.getSingletonClass().addMethod(module.lookupMethod(methodName));
450 }
451 }
452
453 return NilPlaceholder.INSTANCE;
454 }
455 }
456
457 @CoreMethod(names = "public", isSplatted = true)
458 public abstract static class PublicNode extends CoreMethodNode {
459
460 public PublicNode(RubyContext context, SourceSection sourceSection) {
461 super(context, sourceSection);
462 }
463
464 public PublicNode(PublicNode prev) {
465 super(prev);
466 }
467
468 @Specialization
469 public RubyModule doPublic(VirtualFrame frame, RubyModule module, Object... args) {
470 module.visibilityMethod(frame.getCaller(), args, Visibility.PUBLIC);
471 return module;
472 }
473 }
474
475 @CoreMethod(names = "private", isSplatted = true)
476 public abstract static class PrivateNode extends CoreMethodNode {
477
478 public PrivateNode(RubyContext context, SourceSection sourceSection) {
479 super(context, sourceSection);
480 }
481
482 public PrivateNode(PrivateNode prev) {
483 super(prev);
484 }
485
486 @Specialization
487 public RubyModule doPrivate(VirtualFrame frame, RubyModule module, Object... args) {
488 module.visibilityMethod(frame.getCaller(), args, Visibility.PRIVATE);
489 return module;
490 }
491 }
492
493 @CoreMethod(names = "private_class_method", isSplatted = true)
494 public abstract static class PrivateClassMethodNode extends CoreMethodNode {
495
496 public PrivateClassMethodNode(RubyContext context, SourceSection sourceSection) {
497 super(context, sourceSection);
498 }
499
500 public PrivateClassMethodNode(PrivateClassMethodNode prev) {
501 super(prev);
502 }
503
504 @Specialization
505 public RubyModule privateClassMethod(RubyModule module, Object... args) {
506 final RubyClass moduleSingleton = module.getSingletonClass();
507
508 for (Object arg : args) {
509 final RubyMethod method = moduleSingleton.lookupMethod(arg.toString());
510
511 if (method == null) {
512 throw new RuntimeException("Couldn't find method " + arg.toString());
513 }
514
515 moduleSingleton.addMethod(method.withNewVisibility(Visibility.PRIVATE));
516 }
517
518 return module;
519 }
520 }
521
522 @CoreMethod(names = "private_constant", isSplatted = true)
523 public abstract static class PrivateConstantNode extends CoreMethodNode {
524
525 public PrivateConstantNode(RubyContext context, SourceSection sourceSection) {
526 super(context, sourceSection);
527 }
528
529 public PrivateConstantNode(PrivateConstantNode prev) {
530 super(prev);
531 }
532
533 @Specialization
534 public RubyModule privateConstnat(RubyModule module, @SuppressWarnings("unused") Object... args) {
535 getContext().implementationMessage("private_constant does nothing at the moment");
536 return module;
537 }
538 }
539
540 @CoreMethod(names = "protected", isSplatted = true)
541 public abstract static class ProtectedNode extends CoreMethodNode {
542
543 public ProtectedNode(RubyContext context, SourceSection sourceSection) {
544 super(context, sourceSection);
545 }
546
547 public ProtectedNode(ProtectedNode prev) {
548 super(prev);
549 }
550
551 @Specialization
552 public RubyModule doProtected(RubyModule module, @SuppressWarnings("unused") Object... args) {
553 getContext().implementationMessage("protected does nothing at the moment");
554 return module;
555 }
556 }
557
558 @CoreMethod(names = "remove_class_variable", minArgs = 1, maxArgs = 1)
559 public abstract static class RemoveClassVariableNode extends CoreMethodNode {
560
561 public RemoveClassVariableNode(RubyContext context, SourceSection sourceSection) {
562 super(context, sourceSection);
563 }
564
565 public RemoveClassVariableNode(RemoveClassVariableNode prev) {
566 super(prev);
567 }
568
569 @Specialization
570 public RubyModule removeClassVariable(RubyModule module, RubyString name) {
571 module.removeClassVariable(name.toString());
572 return module;
573 }
574
575 @Specialization
576 public RubyModule removeClassVariable(RubyModule module, RubySymbol name) {
577 module.removeClassVariable(name.toString());
578 return module;
579 }
580
581 }
582
583 @CoreMethod(names = "remove_method", minArgs = 1, maxArgs = 1)
584 public abstract static class RemoveMethodNode extends CoreMethodNode {
585
586 public RemoveMethodNode(RubyContext context, SourceSection sourceSection) {
587 super(context, sourceSection);
588 }
589
590 public RemoveMethodNode(RemoveMethodNode prev) {
591 super(prev);
592 }
593
594 @Specialization
595 public RubyModule removeMethod(RubyModule module, RubyString name) {
596 module.removeMethod(name.toString());
597 return module;
598 }
599
600 @Specialization
601 public RubyModule removeMethod(RubyModule module, RubySymbol name) {
602 module.removeMethod(name.toString());
603 return module;
604 }
605
606 }
607
608 @CoreMethod(names = "to_s", maxArgs = 0)
609 public abstract static class ToSNode extends CoreMethodNode {
610
611 public ToSNode(RubyContext context, SourceSection sourceSection) {
612 super(context, sourceSection);
613 }
614
615 public ToSNode(ToSNode prev) {
616 super(prev);
617 }
618
619 @Specialization
620 public RubyString toS(RubyModule module) {
621 return getContext().makeString(module.getName());
622 }
623 }
624
625 @CoreMethod(names = "undef_method", minArgs = 1, maxArgs = 1)
626 public abstract static class UndefMethodNode extends CoreMethodNode {
627
628 public UndefMethodNode(RubyContext context, SourceSection sourceSection) {
629 super(context, sourceSection);
630 }
631
632 public UndefMethodNode(UndefMethodNode prev) {
633 super(prev);
634 }
635
636 @Specialization
637 public RubyModule undefMethod(RubyModule module, RubyString name) {
638 final RubyMethod method = module.lookupMethod(name.toString());
639 module.undefMethod(method);
640 return module;
641 }
642
643 @Specialization
644 public RubyModule undefMethod(RubyModule module, RubySymbol name) {
645 final RubyMethod method = module.lookupMethod(name.toString());
646 module.undefMethod(method);
647 return module;
648 }
649
650 }
651
652 }