Skip to content

Commit d935095

Browse files
committed
[Truffle] Extracted Kernel#eval's to_str coercion to a new node.
1 parent f8392f9 commit d935095

File tree

2 files changed

+105
-48
lines changed

2 files changed

+105
-48
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright (c) 2015 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+
11+
package org.jruby.truffle.nodes.coerce;
12+
13+
import com.oracle.truffle.api.dsl.NodeChild;
14+
import com.oracle.truffle.api.dsl.Specialization;
15+
import com.oracle.truffle.api.frame.VirtualFrame;
16+
import com.oracle.truffle.api.source.SourceSection;
17+
import org.jruby.truffle.nodes.RubyNode;
18+
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
19+
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
20+
import org.jruby.truffle.runtime.RubyContext;
21+
import org.jruby.truffle.runtime.control.RaiseException;
22+
import org.jruby.truffle.runtime.core.RubyString;
23+
24+
@NodeChild(value = "child", type = RubyNode.class)
25+
public abstract class ToStrNode extends RubyNode {
26+
27+
@Child private CallDispatchHeadNode toStr;
28+
29+
public ToStrNode(RubyContext context, SourceSection sourceSection) {
30+
super(context, sourceSection);
31+
toStr = DispatchHeadNodeFactory.createMethodCall(context);
32+
}
33+
34+
public ToStrNode(ToStrNode prev) {
35+
super(prev);
36+
toStr = prev.toStr;
37+
}
38+
39+
@Specialization
40+
public RubyString doRubyString(RubyString string) {
41+
return string;
42+
}
43+
44+
@Specialization(guards = "!isRubyString")
45+
public RubyString doObject(VirtualFrame frame, Object object) {
46+
notDesignedForCompilation();
47+
48+
final Object coerced;
49+
50+
try {
51+
coerced = toStr.call(frame, object, "to_str", null);
52+
} catch (RaiseException e) {
53+
if (e.getRubyException().getLogicalClass() == getContext().getCoreLibrary().getNoMethodErrorClass()) {
54+
throw new RaiseException(
55+
getContext().getCoreLibrary().typeError(
56+
String.format("no implicit conversion of %s into String", getContext().getCoreLibrary().getLogicalClass(object).getName()),
57+
this));
58+
} else {
59+
throw e;
60+
}
61+
}
62+
63+
if (coerced instanceof RubyString) {
64+
return (RubyString) coerced;
65+
} else {
66+
final String uncoercedClassName = getContext().getCoreLibrary().getLogicalClass(object).getName();
67+
68+
throw new RaiseException(
69+
getContext().getCoreLibrary().typeError(
70+
String.format("can't convert %s to String (%s#to_str gives %s)",
71+
uncoercedClassName,
72+
uncoercedClassName,
73+
getContext().getCoreLibrary().getLogicalClass(coerced).getName()),
74+
this));
75+
}
76+
}
77+
78+
@Override
79+
public abstract RubyString executeRubyString(VirtualFrame frame);
80+
81+
public abstract RubyString executeRubyString(VirtualFrame frame, Object object);
82+
83+
@Override
84+
public final Object execute(VirtualFrame frame) {
85+
return executeRubyString(frame);
86+
}
87+
}

truffle/src/main/java/org/jruby/truffle/nodes/core/KernelNodes.java

Lines changed: 18 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
import com.oracle.truffle.api.CompilerDirectives;
1313
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
1414
import com.oracle.truffle.api.Truffle;
15+
import com.oracle.truffle.api.dsl.CreateCast;
16+
import com.oracle.truffle.api.dsl.NodeChild;
17+
import com.oracle.truffle.api.dsl.NodeChildren;
1518
import com.oracle.truffle.api.dsl.Specialization;
1619
import com.oracle.truffle.api.frame.*;
1720
import com.oracle.truffle.api.nodes.UnexpectedResultException;
@@ -25,6 +28,8 @@
2528
import org.jruby.truffle.nodes.cast.BooleanCastNodeFactory;
2629
import org.jruby.truffle.nodes.cast.NumericToFloatNode;
2730
import org.jruby.truffle.nodes.cast.NumericToFloatNodeFactory;
31+
import org.jruby.truffle.nodes.coerce.ToStrNode;
32+
import org.jruby.truffle.nodes.coerce.ToStrNodeFactory;
2833
import org.jruby.truffle.nodes.control.WhileNode;
2934
import org.jruby.truffle.nodes.core.KernelNodesFactory.SameOrEqualNodeFactory;
3035
import org.jruby.truffle.nodes.dispatch.*;
@@ -513,19 +518,27 @@ public Object dup(VirtualFrame frame, RubyBasicObject self) {
513518
}
514519

515520
@CoreMethod(names = "eval", isModuleFunction = true, required = 1, optional = 3)
516-
public abstract static class EvalNode extends CoreMethodNode {
521+
@NodeChildren({
522+
@NodeChild(value = "source", type = RubyNode.class),
523+
@NodeChild(value = "binding", type = RubyNode.class),
524+
@NodeChild(value = "filename", type = RubyNode.class),
525+
@NodeChild(value = "lineNumber", type = RubyNode.class)
526+
})
527+
public abstract static class EvalNode extends RubyNode {
517528

518529
@Child private CallDispatchHeadNode toStr;
519530
@Child private BindingNode bindingNode;
520531

521532
public EvalNode(RubyContext context, SourceSection sourceSection) {
522533
super(context, sourceSection);
523-
toStr = DispatchHeadNodeFactory.createMethodCall(context);
524534
}
525535

526536
public EvalNode(EvalNode prev) {
527537
super(prev);
528-
toStr = prev.toStr;
538+
}
539+
540+
@CreateCast("source") public RubyNode coerceSourceToString(RubyNode source) {
541+
return ToStrNodeFactory.create(getContext(), getSourceSection(), source);
529542
}
530543

531544
protected RubyBinding getCallerBinding(VirtualFrame frame) {
@@ -574,57 +587,14 @@ public Object eval(RubyString source, RubyBinding binding, RubyString filename,
574587
return getContext().eval(source.getBytes(), binding, false, this);
575588
}
576589

577-
@Specialization(guards = "!isRubyString(arguments[0])")
578-
public Object eval(VirtualFrame frame, RubyBasicObject object, UndefinedPlaceholder binding, UndefinedPlaceholder filename, UndefinedPlaceholder lineNumber) {
579-
notDesignedForCompilation();
580-
581-
return evalCoerced(frame, object, getCallerBinding(frame), true, filename, lineNumber);
582-
}
583-
584-
@Specialization(guards = "!isRubyString(arguments[0])")
585-
public Object eval(VirtualFrame frame, RubyBasicObject object, RubyBinding binding, UndefinedPlaceholder filename, UndefinedPlaceholder lineNumber) {
586-
notDesignedForCompilation();
587-
588-
return evalCoerced(frame, object, binding, false, filename, lineNumber);
589-
}
590-
591-
@Specialization(guards = "!isRubyBinding(arguments[1])")
592-
public Object eval(RubyBasicObject source, RubyBasicObject badBinding, UndefinedPlaceholder filename, UndefinedPlaceholder lineNumber) {
590+
@Specialization(guards = "!isRubyBinding(binding)")
591+
public Object eval(RubyString source, RubyBasicObject badBinding, UndefinedPlaceholder filename, UndefinedPlaceholder lineNumber) {
593592
throw new RaiseException(
594593
getContext().getCoreLibrary().typeError(
595594
String.format("wrong argument type %s (expected binding)",
596595
badBinding.getLogicalClass().getName()),
597596
this));
598597
}
599-
600-
private Object evalCoerced(VirtualFrame frame, RubyBasicObject object, RubyBinding binding, boolean ownScopeForAssignments, UndefinedPlaceholder filename, UndefinedPlaceholder lineNumber) {
601-
Object coerced;
602-
603-
try {
604-
coerced = toStr.call(frame, object, "to_str", null);
605-
} catch (RaiseException e) {
606-
if (e.getRubyException().getLogicalClass() == getContext().getCoreLibrary().getNoMethodErrorClass()) {
607-
throw new RaiseException(
608-
getContext().getCoreLibrary().typeError(
609-
String.format("no implicit conversion of %s into String", object.getLogicalClass().getName()),
610-
this));
611-
} else {
612-
throw e;
613-
}
614-
}
615-
616-
if (coerced instanceof RubyString) {
617-
return getContext().eval(((RubyString) coerced).getBytes(), binding, ownScopeForAssignments, this);
618-
} else {
619-
throw new RaiseException(
620-
getContext().getCoreLibrary().typeError(
621-
String.format("can't convert %s to String (%s#to_str gives %s)",
622-
object.getLogicalClass().getName(),
623-
object.getLogicalClass().getName(),
624-
getContext().getCoreLibrary().getLogicalClass(coerced).getName()),
625-
this));
626-
}
627-
}
628598
}
629599

630600
@CoreMethod(names = "exec", isModuleFunction = true, required = 1, argumentsAsArray = true)

0 commit comments

Comments
 (0)