Mercurial > hg > graal-compiler
comparison graal/com.oracle.truffle.ruby.nodes/src/com/oracle/truffle/ruby/nodes/core/KernelNodes.java @ 13514:0fbee3eb71f0
Ruby: import project.
author | Chris Seaton <chris.seaton@oracle.com> |
---|---|
date | Mon, 06 Jan 2014 17:12:09 +0000 |
parents | |
children | 497fada09efb |
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 java.io.*; | |
13 import java.math.*; | |
14 import java.util.*; | |
15 | |
16 import com.oracle.truffle.api.CompilerDirectives.SlowPath; | |
17 import com.oracle.truffle.api.*; | |
18 import com.oracle.truffle.api.dsl.*; | |
19 import com.oracle.truffle.api.frame.*; | |
20 import com.oracle.truffle.api.nodes.*; | |
21 import com.oracle.truffle.ruby.nodes.*; | |
22 import com.oracle.truffle.ruby.nodes.call.*; | |
23 import com.oracle.truffle.ruby.nodes.cast.*; | |
24 import com.oracle.truffle.ruby.nodes.control.*; | |
25 import com.oracle.truffle.ruby.nodes.literal.*; | |
26 import com.oracle.truffle.ruby.nodes.yield.*; | |
27 import com.oracle.truffle.ruby.runtime.*; | |
28 import com.oracle.truffle.ruby.runtime.configuration.*; | |
29 import com.oracle.truffle.ruby.runtime.control.*; | |
30 import com.oracle.truffle.ruby.runtime.core.*; | |
31 import com.oracle.truffle.ruby.runtime.core.array.*; | |
32 import com.oracle.truffle.ruby.runtime.objects.*; | |
33 import com.oracle.truffle.ruby.runtime.subsystems.*; | |
34 | |
35 @CoreClass(name = "Kernel") | |
36 public abstract class KernelNodes { | |
37 | |
38 @CoreMethod(names = "Array", isModuleMethod = true, needsSelf = false, isSplatted = true) | |
39 public abstract static class ArrayNode extends CoreMethodNode { | |
40 | |
41 public ArrayNode(RubyContext context, SourceSection sourceSection) { | |
42 super(context, sourceSection); | |
43 } | |
44 | |
45 public ArrayNode(ArrayNode prev) { | |
46 super(prev); | |
47 } | |
48 | |
49 @Specialization | |
50 public RubyArray array(Object[] args) { | |
51 if (args.length == 1 && args[0] instanceof RubyArray) { | |
52 return (RubyArray) args[0]; | |
53 } else { | |
54 return RubyArray.specializedFromObjects(getContext().getCoreLibrary().getArrayClass(), args); | |
55 } | |
56 } | |
57 | |
58 } | |
59 | |
60 @CoreMethod(names = "at_exit", isModuleMethod = true, needsSelf = false, needsBlock = true, maxArgs = 0) | |
61 public abstract static class AtExitNode extends CoreMethodNode { | |
62 | |
63 public AtExitNode(RubyContext context, SourceSection sourceSection) { | |
64 super(context, sourceSection); | |
65 } | |
66 | |
67 public AtExitNode(AtExitNode prev) { | |
68 super(prev); | |
69 } | |
70 | |
71 @Specialization | |
72 public Object atExit(RubyProc block) { | |
73 getContext().getAtExitManager().add(block); | |
74 return NilPlaceholder.INSTANCE; | |
75 } | |
76 } | |
77 | |
78 @CoreMethod(names = "binding", isModuleMethod = true, needsSelf = true, maxArgs = 0) | |
79 public abstract static class BindingNode extends CoreMethodNode { | |
80 | |
81 public BindingNode(RubyContext context, SourceSection sourceSection) { | |
82 super(context, sourceSection); | |
83 } | |
84 | |
85 public BindingNode(BindingNode prev) { | |
86 super(prev); | |
87 } | |
88 | |
89 @Specialization | |
90 public Object binding(VirtualFrame frame, Object self) { | |
91 return new RubyBinding(getContext().getCoreLibrary().getBindingClass(), self, frame.getCaller().unpack().materialize()); | |
92 } | |
93 } | |
94 | |
95 @CoreMethod(names = "block_given?", isModuleMethod = true, needsSelf = false, maxArgs = 0) | |
96 public abstract static class BlockGivenNode extends CoreMethodNode { | |
97 | |
98 public BlockGivenNode(RubyContext context, SourceSection sourceSection) { | |
99 super(context, sourceSection); | |
100 } | |
101 | |
102 public BlockGivenNode(BlockGivenNode prev) { | |
103 super(prev); | |
104 } | |
105 | |
106 @Specialization | |
107 public boolean blockGiven(VirtualFrame frame) { | |
108 return frame.getCaller().unpack().getArguments(RubyArguments.class).getBlock() != null; | |
109 } | |
110 } | |
111 | |
112 // TODO(CS): should hide this in a feature | |
113 | |
114 @CoreMethod(names = "callcc", isModuleMethod = true, needsSelf = false, needsBlock = true, maxArgs = 0) | |
115 public abstract static class CallccNode extends CoreMethodNode { | |
116 | |
117 public CallccNode(RubyContext context, SourceSection sourceSection) { | |
118 super(context, sourceSection); | |
119 } | |
120 | |
121 public CallccNode(CallccNode prev) { | |
122 super(prev); | |
123 } | |
124 | |
125 @Specialization | |
126 public Object callcc(RubyProc block) { | |
127 final RubyContext context = getContext(); | |
128 | |
129 if (block == null) { | |
130 // TODO(CS): should really have acceptsBlock and needsBlock to do this automatically | |
131 throw new RaiseException(context.getCoreLibrary().localJumpError("no block given")); | |
132 } | |
133 | |
134 final RubyContinuation continuation = new RubyContinuation(context.getCoreLibrary().getContinuationClass()); | |
135 return continuation.enter(block); | |
136 } | |
137 } | |
138 | |
139 @CoreMethod(names = "catch", isModuleMethod = true, needsSelf = false, needsBlock = true, minArgs = 1, maxArgs = 1) | |
140 public abstract static class CatchNode extends YieldingCoreMethodNode { | |
141 | |
142 public CatchNode(RubyContext context, SourceSection sourceSection) { | |
143 super(context, sourceSection); | |
144 } | |
145 | |
146 public CatchNode(CatchNode prev) { | |
147 super(prev); | |
148 } | |
149 | |
150 @Specialization | |
151 public Object doCatch(VirtualFrame frame, Object tag, RubyProc block) { | |
152 try { | |
153 return yield(frame, block); | |
154 } catch (ThrowException e) { | |
155 if (e.getTag().equals(tag)) { | |
156 // TODO(cs): unset rather than set to Nil? | |
157 getContext().getCoreLibrary().getGlobalVariablesObject().setInstanceVariable("$!", NilPlaceholder.INSTANCE); | |
158 return e.getValue(); | |
159 } else { | |
160 throw e; | |
161 } | |
162 } | |
163 } | |
164 } | |
165 | |
166 @CoreMethod(names = "eval", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 2) | |
167 public abstract static class EvalNode extends CoreMethodNode { | |
168 | |
169 public EvalNode(RubyContext context, SourceSection sourceSection) { | |
170 super(context, sourceSection); | |
171 } | |
172 | |
173 public EvalNode(EvalNode prev) { | |
174 super(prev); | |
175 } | |
176 | |
177 @Specialization | |
178 public Object eval(RubyString source, @SuppressWarnings("unused") UndefinedPlaceholder binding) { | |
179 return getContext().eval(source.toString()); | |
180 } | |
181 | |
182 @Specialization | |
183 public Object eval(RubyString source, RubyBinding binding) { | |
184 return getContext().eval(source.toString(), binding); | |
185 } | |
186 | |
187 } | |
188 | |
189 @CoreMethod(names = "exec", isModuleMethod = true, needsSelf = false, minArgs = 1, isSplatted = true) | |
190 public abstract static class ExecNode extends CoreMethodNode { | |
191 | |
192 public ExecNode(RubyContext context, SourceSection sourceSection) { | |
193 super(context, sourceSection); | |
194 } | |
195 | |
196 public ExecNode(ExecNode prev) { | |
197 super(prev); | |
198 } | |
199 | |
200 @Specialization | |
201 public Object require(Object[] args) { | |
202 final String[] commandLine = new String[args.length]; | |
203 | |
204 for (int n = 0; n < args.length; n++) { | |
205 commandLine[n] = args[n].toString(); | |
206 } | |
207 | |
208 exec(getContext(), commandLine); | |
209 | |
210 return null; | |
211 } | |
212 | |
213 @SlowPath | |
214 private static void exec(RubyContext context, String[] commandLine) { | |
215 context.implementationMessage("starting child process to simulate exec: "); | |
216 | |
217 for (int n = 0; n < commandLine.length; n++) { | |
218 if (n > 0) { | |
219 System.err.print(" "); | |
220 } | |
221 | |
222 System.err.print(commandLine[n]); | |
223 } | |
224 | |
225 final ProcessBuilder builder = new ProcessBuilder(commandLine); | |
226 builder.inheritIO(); | |
227 | |
228 final RubyHash env = (RubyHash) context.getCoreLibrary().getObjectClass().lookupConstant("ENV"); | |
229 | |
230 for (Map.Entry<Object, Object> entry : env.getMap().entrySet()) { | |
231 builder.environment().put(entry.getKey().toString(), entry.getValue().toString()); | |
232 } | |
233 | |
234 Process process; | |
235 | |
236 try { | |
237 process = builder.start(); | |
238 } catch (IOException e) { | |
239 // TODO(cs): proper Ruby exception | |
240 throw new RuntimeException(e); | |
241 } | |
242 | |
243 int exitCode; | |
244 | |
245 while (true) { | |
246 try { | |
247 exitCode = process.waitFor(); | |
248 break; | |
249 } catch (InterruptedException e) { | |
250 continue; | |
251 } | |
252 } | |
253 | |
254 context.implementationMessage("child process simulating exec finished"); | |
255 | |
256 System.exit(exitCode); | |
257 } | |
258 | |
259 } | |
260 | |
261 @CoreMethod(names = "exit", isModuleMethod = true, needsSelf = false, minArgs = 0, maxArgs = 1) | |
262 public abstract static class ExitNode extends CoreMethodNode { | |
263 | |
264 public ExitNode(RubyContext context, SourceSection sourceSection) { | |
265 super(context, sourceSection); | |
266 } | |
267 | |
268 public ExitNode(ExitNode prev) { | |
269 super(prev); | |
270 } | |
271 | |
272 @Specialization | |
273 public Object exit(@SuppressWarnings("unused") UndefinedPlaceholder exitCode) { | |
274 getContext().shutdown(); | |
275 System.exit(0); | |
276 return null; | |
277 } | |
278 | |
279 @Specialization | |
280 public Object exit(int exitCode) { | |
281 getContext().shutdown(); | |
282 System.exit(exitCode); | |
283 return null; | |
284 } | |
285 | |
286 } | |
287 | |
288 @CoreMethod(names = "gets", isModuleMethod = true, needsSelf = false, maxArgs = 0) | |
289 public abstract static class GetsNode extends CoreMethodNode { | |
290 | |
291 public GetsNode(RubyContext context, SourceSection sourceSection) { | |
292 super(context, sourceSection); | |
293 } | |
294 | |
295 public GetsNode(GetsNode prev) { | |
296 super(prev); | |
297 } | |
298 | |
299 @Specialization | |
300 public RubyString gets(VirtualFrame frame) { | |
301 final RubyContext context = getContext(); | |
302 | |
303 final ThreadManager threadManager = context.getThreadManager(); | |
304 | |
305 RubyString line; | |
306 | |
307 try { | |
308 final RubyThread runningThread = threadManager.leaveGlobalLock(); | |
309 | |
310 try { | |
311 line = context.makeString(context.getConfiguration().getInputReader().readLine("")); | |
312 } finally { | |
313 threadManager.enterGlobalLock(runningThread); | |
314 } | |
315 } catch (IOException e) { | |
316 throw new RuntimeException(e); | |
317 } | |
318 | |
319 // Set the local variable $_ in the caller | |
320 | |
321 final Frame unpacked = frame.getCaller().unpack(); | |
322 final FrameSlot slot = unpacked.getFrameDescriptor().findFrameSlot("$_"); | |
323 | |
324 if (slot != null) { | |
325 unpacked.setObject(slot, line); | |
326 } | |
327 | |
328 return line; | |
329 } | |
330 } | |
331 | |
332 @CoreMethod(names = "Integer", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) | |
333 public abstract static class IntegerNode extends CoreMethodNode { | |
334 | |
335 @Child protected DispatchHeadNode toInt; | |
336 | |
337 public IntegerNode(RubyContext context, SourceSection sourceSection) { | |
338 super(context, sourceSection); | |
339 toInt = adoptChild(new DispatchHeadNode(context, getSourceSection(), "to_int", false)); | |
340 } | |
341 | |
342 public IntegerNode(IntegerNode prev) { | |
343 super(prev); | |
344 toInt = adoptChild(prev.toInt); | |
345 } | |
346 | |
347 @Specialization | |
348 public int integer(int value) { | |
349 return value; | |
350 } | |
351 | |
352 @Specialization | |
353 public BigInteger integer(BigInteger value) { | |
354 return value; | |
355 } | |
356 | |
357 @Specialization | |
358 public int integer(double value) { | |
359 return (int) value; | |
360 } | |
361 | |
362 @Specialization | |
363 public Object integer(RubyString value) { | |
364 return value.toInteger(); | |
365 } | |
366 | |
367 @Specialization | |
368 public Object integer(VirtualFrame frame, Object value) { | |
369 return toInt.dispatch(frame, value, null); | |
370 } | |
371 | |
372 } | |
373 | |
374 @CoreMethod(names = "lambda", isModuleMethod = true, needsBlock = true, maxArgs = 0) | |
375 public abstract static class LambdaNode extends CoreMethodNode { | |
376 | |
377 public LambdaNode(RubyContext context, SourceSection sourceSection) { | |
378 super(context, sourceSection); | |
379 } | |
380 | |
381 public LambdaNode(LambdaNode prev) { | |
382 super(prev); | |
383 } | |
384 | |
385 @Specialization | |
386 public RubyProc proc(Object self, RubyProc block) { | |
387 return new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.LAMBDA, self, block, block.getMethod()); | |
388 | |
389 } | |
390 } | |
391 | |
392 @CoreMethod(names = "load", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) | |
393 public abstract static class LoadNode extends CoreMethodNode { | |
394 | |
395 public LoadNode(RubyContext context, SourceSection sourceSection) { | |
396 super(context, sourceSection); | |
397 } | |
398 | |
399 public LoadNode(LoadNode prev) { | |
400 super(prev); | |
401 } | |
402 | |
403 @Specialization | |
404 public boolean load(RubyString file) { | |
405 getContext().loadFile(file.toString()); | |
406 return true; | |
407 } | |
408 } | |
409 | |
410 @CoreMethod(names = "loop", isModuleMethod = true, needsSelf = false, maxArgs = 0) | |
411 public abstract static class LoopNode extends CoreMethodNode { | |
412 | |
413 @Child protected WhileNode whileNode; | |
414 | |
415 public LoopNode(RubyContext context, SourceSection sourceSection) { | |
416 super(context, sourceSection); | |
417 whileNode = adoptChild(new WhileNode(context, sourceSection, BooleanCastNodeFactory.create(context, sourceSection, new BooleanLiteralNode(context, sourceSection, true)), new YieldNode( | |
418 context, getSourceSection(), new RubyNode[]{}))); | |
419 } | |
420 | |
421 public LoopNode(LoopNode prev) { | |
422 super(prev); | |
423 whileNode = adoptChild(prev.whileNode); | |
424 } | |
425 | |
426 @Specialization | |
427 public Object loop(VirtualFrame frame) { | |
428 return whileNode.execute(frame); | |
429 } | |
430 } | |
431 | |
432 @CoreMethod(names = "print", isModuleMethod = true, needsSelf = false, isSplatted = true) | |
433 public abstract static class PrintNode extends CoreMethodNode { | |
434 | |
435 public PrintNode(RubyContext context, SourceSection sourceSection) { | |
436 super(context, sourceSection); | |
437 } | |
438 | |
439 public PrintNode(PrintNode prev) { | |
440 super(prev); | |
441 } | |
442 | |
443 @Specialization | |
444 public NilPlaceholder print(Object[] args) { | |
445 final RubyContext context = getContext(); | |
446 final ThreadManager threadManager = context.getThreadManager(); | |
447 | |
448 final RubyThread runningThread = threadManager.leaveGlobalLock(); | |
449 | |
450 try { | |
451 for (Object arg : args) { | |
452 /* | |
453 * TODO(cs): If it's a RubyString and made up of bytes, just write the bytes out | |
454 * - using toString will mess up the encoding. We need to stop using toString | |
455 * everywhere, and write our own bytes, possibly using JRuby's library for this. | |
456 */ | |
457 | |
458 if (arg instanceof RubyString && !((RubyString) arg).isFromJavaString()) { | |
459 try { | |
460 context.getConfiguration().getStandardOut().write(((RubyString) arg).getBytes()); | |
461 } catch (IOException e) { | |
462 throw new RuntimeException(e); | |
463 } | |
464 } else { | |
465 context.getConfiguration().getStandardOut().print(arg); | |
466 } | |
467 } | |
468 } finally { | |
469 threadManager.enterGlobalLock(runningThread); | |
470 } | |
471 | |
472 return NilPlaceholder.INSTANCE; | |
473 } | |
474 } | |
475 | |
476 @CoreMethod(names = "printf", isModuleMethod = true, needsSelf = false, isSplatted = true) | |
477 public abstract static class PrintfNode extends CoreMethodNode { | |
478 | |
479 public PrintfNode(RubyContext context, SourceSection sourceSection) { | |
480 super(context, sourceSection); | |
481 } | |
482 | |
483 public PrintfNode(PrintfNode prev) { | |
484 super(prev); | |
485 } | |
486 | |
487 @Specialization | |
488 public NilPlaceholder printf(Object[] args) { | |
489 final RubyContext context = getContext(); | |
490 final ThreadManager threadManager = context.getThreadManager(); | |
491 | |
492 if (args.length > 0) { | |
493 final String format = ((RubyString) args[0]).toString(); | |
494 final List<Object> values = Arrays.asList(args).subList(1, args.length); | |
495 | |
496 final RubyThread runningThread = threadManager.leaveGlobalLock(); | |
497 | |
498 try { | |
499 StringFormatter.format(context.getConfiguration().getStandardOut(), format, values); | |
500 } finally { | |
501 threadManager.enterGlobalLock(runningThread); | |
502 } | |
503 } | |
504 | |
505 return NilPlaceholder.INSTANCE; | |
506 } | |
507 } | |
508 | |
509 /* | |
510 * Kernel#pretty_inspect is normally part of stdlib, in pp.rb, but we aren't able to execute | |
511 * that file yet. Instead we implement a very simple version here, which is the solution | |
512 * suggested by RubySpec. | |
513 */ | |
514 | |
515 @CoreMethod(names = "pretty_inspect", maxArgs = 0) | |
516 public abstract static class PrettyInspectNode extends CoreMethodNode { | |
517 | |
518 @Child protected DispatchHeadNode toS; | |
519 | |
520 public PrettyInspectNode(RubyContext context, SourceSection sourceSection) { | |
521 super(context, sourceSection); | |
522 toS = adoptChild(new DispatchHeadNode(context, getSourceSection(), "to_s", false)); | |
523 } | |
524 | |
525 public PrettyInspectNode(PrettyInspectNode prev) { | |
526 super(prev); | |
527 toS = adoptChild(prev.toS); | |
528 } | |
529 | |
530 @Specialization | |
531 public Object prettyInspect(VirtualFrame frame, Object self) { | |
532 return toS.dispatch(frame, self, null); | |
533 | |
534 } | |
535 } | |
536 | |
537 @CoreMethod(names = "proc", isModuleMethod = true, needsBlock = true, maxArgs = 0, versions = RubyVersion.RUBY_18) | |
538 public abstract static class Proc18Node extends CoreMethodNode { | |
539 | |
540 public Proc18Node(RubyContext context, SourceSection sourceSection) { | |
541 super(context, sourceSection); | |
542 } | |
543 | |
544 public Proc18Node(Proc18Node prev) { | |
545 super(prev); | |
546 } | |
547 | |
548 @Specialization | |
549 public RubyProc proc(Object self, RubyProc block) { | |
550 return new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.LAMBDA, self, block, block.getMethod()); | |
551 | |
552 } | |
553 } | |
554 | |
555 @CoreMethod(names = "proc", isModuleMethod = true, needsBlock = true, maxArgs = 0, versions = {RubyVersion.RUBY_19, RubyVersion.RUBY_20, RubyVersion.RUBY_21}) | |
556 public abstract static class ProcNode extends CoreMethodNode { | |
557 | |
558 public ProcNode(RubyContext context, SourceSection sourceSection) { | |
559 super(context, sourceSection); | |
560 } | |
561 | |
562 public ProcNode(ProcNode prev) { | |
563 super(prev); | |
564 } | |
565 | |
566 @Specialization | |
567 public RubyProc proc(Object self, RubyProc block) { | |
568 return new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.PROC, self, block, block.getMethod()); | |
569 | |
570 } | |
571 } | |
572 | |
573 @CoreMethod(names = "puts", isModuleMethod = true, needsSelf = false, isSplatted = true) | |
574 public abstract static class PutsNode extends CoreMethodNode { | |
575 | |
576 public PutsNode(RubyContext context, SourceSection sourceSection) { | |
577 super(context, sourceSection); | |
578 } | |
579 | |
580 public PutsNode(PutsNode prev) { | |
581 super(prev); | |
582 } | |
583 | |
584 @ExplodeLoop | |
585 @Specialization | |
586 public NilPlaceholder puts(Object[] args) { | |
587 final RubyContext context = getContext(); | |
588 final ThreadManager threadManager = context.getThreadManager(); | |
589 final PrintStream standardOut = context.getConfiguration().getStandardOut(); | |
590 | |
591 final RubyThread runningThread = threadManager.leaveGlobalLock(); | |
592 | |
593 try { | |
594 if (args.length == 0) { | |
595 standardOut.println(); | |
596 } else { | |
597 for (int n = 0; n < args.length; n++) { | |
598 puts(context, standardOut, args[n]); | |
599 } | |
600 } | |
601 } finally { | |
602 threadManager.enterGlobalLock(runningThread); | |
603 } | |
604 | |
605 return NilPlaceholder.INSTANCE; | |
606 } | |
607 | |
608 @SlowPath | |
609 private void puts(RubyContext context, PrintStream standardOut, Object value) { | |
610 if (value instanceof RubyArray) { | |
611 final RubyArray array = (RubyArray) value; | |
612 | |
613 for (int n = 0; n < array.size(); n++) { | |
614 puts(context, standardOut, array.get(n)); | |
615 } | |
616 } else { | |
617 // TODO(CS): slow path send | |
618 standardOut.println(context.getCoreLibrary().box(value).send("to_s", null)); | |
619 } | |
620 } | |
621 | |
622 } | |
623 | |
624 @CoreMethod(names = "raise", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 2) | |
625 public abstract static class RaiseNode extends CoreMethodNode { | |
626 | |
627 @Child protected DispatchHeadNode initialize; | |
628 | |
629 public RaiseNode(RubyContext context, SourceSection sourceSection) { | |
630 super(context, sourceSection); | |
631 initialize = adoptChild(new DispatchHeadNode(context, getSourceSection(), "initialize", false)); | |
632 } | |
633 | |
634 public RaiseNode(RaiseNode prev) { | |
635 super(prev); | |
636 initialize = adoptChild(prev.initialize); | |
637 } | |
638 | |
639 @Specialization(order = 1) | |
640 public Object raise(VirtualFrame frame, RubyString message, @SuppressWarnings("unused") UndefinedPlaceholder undefined) { | |
641 return raise(frame, getContext().getCoreLibrary().getRuntimeErrorClass(), message); | |
642 } | |
643 | |
644 @Specialization(order = 2) | |
645 public Object raise(VirtualFrame frame, RubyClass exceptionClass, @SuppressWarnings("unused") UndefinedPlaceholder undefined) { | |
646 return raise(frame, exceptionClass, getContext().makeString("")); | |
647 } | |
648 | |
649 @Specialization(order = 3) | |
650 public Object raise(VirtualFrame frame, RubyClass exceptionClass, RubyString message) { | |
651 final RubyContext context = getContext(); | |
652 | |
653 if (context.getConfiguration().getPrintRubyExceptions()) { | |
654 context.implementationMessage("Ruby raise: %s", message); | |
655 new Exception().printStackTrace(); | |
656 } | |
657 | |
658 final RubyBasicObject exception = exceptionClass.newInstance(); | |
659 initialize.dispatch(frame, exception, null, message); | |
660 throw new RaiseException(exception); | |
661 } | |
662 | |
663 } | |
664 | |
665 @CoreMethod(names = "require", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) | |
666 public abstract static class RequireNode extends CoreMethodNode { | |
667 | |
668 public RequireNode(RubyContext context, SourceSection sourceSection) { | |
669 super(context, sourceSection); | |
670 } | |
671 | |
672 public RequireNode(RequireNode prev) { | |
673 super(prev); | |
674 } | |
675 | |
676 @Specialization | |
677 public boolean require(RubyString feature) { | |
678 try { | |
679 getContext().getFeatureManager().require(feature.toString()); | |
680 } catch (IOException e) { | |
681 throw new RuntimeException(e); | |
682 } | |
683 | |
684 return true; | |
685 } | |
686 } | |
687 | |
688 @CoreMethod(names = "set_trace_func", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) | |
689 public abstract static class SetTraceFuncNode extends CoreMethodNode { | |
690 | |
691 public SetTraceFuncNode(RubyContext context, SourceSection sourceSection) { | |
692 super(context, sourceSection); | |
693 } | |
694 | |
695 public SetTraceFuncNode(SetTraceFuncNode prev) { | |
696 super(prev); | |
697 } | |
698 | |
699 @Specialization | |
700 public NilPlaceholder setTraceFunc(NilPlaceholder proc) { | |
701 getContext().getTraceManager().setTraceProc(null); | |
702 return proc; | |
703 } | |
704 | |
705 @Specialization | |
706 public RubyProc setTraceFunc(RubyProc proc) { | |
707 getContext().getTraceManager().setTraceProc(proc); | |
708 return proc; | |
709 } | |
710 | |
711 } | |
712 | |
713 @CoreMethod(names = "String", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 1) | |
714 public abstract static class StringNode extends CoreMethodNode { | |
715 | |
716 @Child protected DispatchHeadNode toS; | |
717 | |
718 public StringNode(RubyContext context, SourceSection sourceSection) { | |
719 super(context, sourceSection); | |
720 toS = adoptChild(new DispatchHeadNode(context, getSourceSection(), "to_s", false)); | |
721 } | |
722 | |
723 public StringNode(StringNode prev) { | |
724 super(prev); | |
725 toS = adoptChild(prev.toS); | |
726 } | |
727 | |
728 @Specialization | |
729 public RubyString string(int value) { | |
730 return getContext().makeString(Integer.toString(value)); | |
731 } | |
732 | |
733 @Specialization | |
734 public RubyString string(BigInteger value) { | |
735 return getContext().makeString(value.toString()); | |
736 } | |
737 | |
738 @Specialization | |
739 public RubyString string(double value) { | |
740 return getContext().makeString(Double.toString(value)); | |
741 } | |
742 | |
743 @Specialization | |
744 public RubyString string(RubyString value) { | |
745 return value; | |
746 } | |
747 | |
748 @Specialization | |
749 public Object string(VirtualFrame frame, Object value) { | |
750 return toS.dispatch(frame, value, null); | |
751 } | |
752 | |
753 } | |
754 | |
755 @CoreMethod(names = "sleep", isModuleMethod = true, needsSelf = false, maxArgs = 1) | |
756 public abstract static class SleepNode extends CoreMethodNode { | |
757 | |
758 public SleepNode(RubyContext context, SourceSection sourceSection) { | |
759 super(context, sourceSection); | |
760 } | |
761 | |
762 public SleepNode(SleepNode prev) { | |
763 super(prev); | |
764 } | |
765 | |
766 @Specialization | |
767 public double sleep(double duration) { | |
768 final RubyContext context = getContext(); | |
769 | |
770 final RubyThread runningThread = context.getThreadManager().leaveGlobalLock(); | |
771 | |
772 try { | |
773 final long start = System.nanoTime(); | |
774 | |
775 try { | |
776 Thread.sleep((long) (duration * 1000)); | |
777 } catch (InterruptedException e) { | |
778 // Ignore interruption | |
779 } | |
780 | |
781 final long end = System.nanoTime(); | |
782 | |
783 return (end - start) / 1e9; | |
784 } finally { | |
785 context.getThreadManager().enterGlobalLock(runningThread); | |
786 } | |
787 } | |
788 | |
789 @Specialization | |
790 public double sleep(int duration) { | |
791 return sleep((double) duration); | |
792 } | |
793 | |
794 } | |
795 | |
796 @CoreMethod(names = "throw", isModuleMethod = true, needsSelf = false, minArgs = 1, maxArgs = 2) | |
797 public abstract static class ThrowNode extends CoreMethodNode { | |
798 | |
799 public ThrowNode(RubyContext context, SourceSection sourceSection) { | |
800 super(context, sourceSection); | |
801 } | |
802 | |
803 public ThrowNode(ThrowNode prev) { | |
804 super(prev); | |
805 } | |
806 | |
807 @Specialization | |
808 public Object doThrow(Object tag, UndefinedPlaceholder value) { | |
809 return doThrow(tag, (Object) value); | |
810 } | |
811 | |
812 @Specialization | |
813 public Object doThrow(Object tag, Object value) { | |
814 if (value instanceof UndefinedPlaceholder) { | |
815 throw new ThrowException(tag, NilPlaceholder.INSTANCE); | |
816 } else { | |
817 throw new ThrowException(tag, value); | |
818 } | |
819 } | |
820 | |
821 } | |
822 | |
823 } |