diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java index 7afbe27d40577b1c9665fb2ad129a876f53815b4..dbef3184430bd0dcab9fb401b0e1c81702becf48 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java @@ -22,19 +22,20 @@ */ package com.oracle.truffle.r.nodes.builtin.base; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.*; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; -import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.r.nodes.access.AccessArgumentNode; import com.oracle.truffle.r.nodes.access.ConstantNode; import com.oracle.truffle.r.nodes.access.WriteVariableNode; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; +import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.function.FormalArguments; import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; @@ -50,11 +51,11 @@ import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RExpression; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RLanguage; -import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; +import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; @@ -64,9 +65,16 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; @RBuiltin(name = "as.function.default", kind = INTERNAL, parameterNames = {"x", "envir"}, behavior = PURE) public abstract class AsFunction extends RBuiltinNode { + + @Override + protected void createCasts(CastBuilder casts) { + casts.arg("x").mustBe(instanceOf(RAbstractListVector.class).or(instanceOf(RExpression.class)), RError.SHOW_CALLER2, RError.Message.TYPE_EXPECTED, RType.List.getName()); + casts.arg("envir").mustBe(instanceOf(REnvironment.class), RError.Message.INVALID_ENVIRONMENT); + } + @Specialization @TruffleBoundary - protected RFunction asFunction(RList x, REnvironment envir) { + protected RFunction asFunction(RAbstractListVector x, REnvironment envir) { if (x.getLength() == 0) { throw RError.error(this, RError.Message.GENERIC, "argument must have length at least 1"); } @@ -147,11 +155,4 @@ public abstract class AsFunction extends RBuiltinNode { protected RFunction asFunction(RExpression x, REnvironment envir) { return asFunction(x.getList(), envir); } - - @SuppressWarnings("unused") - @Fallback - @TruffleBoundary - protected RFunction asFunction(Object x, Object envir) { - throw RError.error(this, RError.Message.TYPE_EXPECTED, RType.List.getName()); - } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java index eed6487e7d200d01f870fc30c9c3217d6c11d3d1..3622943accf8632b7ddd6e475f491e09b7a0d148 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Bind.java @@ -36,6 +36,7 @@ import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.r.nodes.RASTUtils; +import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode; import com.oracle.truffle.r.nodes.function.UseMethodInternalNode; @@ -90,7 +91,7 @@ public abstract class Bind extends RBaseNode { protected static final int LIST_PRECEDENCE = PrecedenceNode.LIST_PRECEDENCE; protected static final int EXPRESSION_PRECEDENCE = PrecedenceNode.EXPRESSION_PRECEDENCE; - public abstract Object execute(VirtualFrame frame, Object deparseLevelObj, Object[] args, RArgsValuesAndNames promiseArgs, int precedence); + public abstract Object execute(VirtualFrame frame, int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, int precedence); @Child private CastToVectorNode castVector; @Child private UseMethodInternalNode dcn; @@ -139,7 +140,7 @@ public abstract class Bind extends RBaseNode { @SuppressWarnings("unused") @Specialization(guards = "precedence == NO_PRECEDENCE") - protected RNull allNull(VirtualFrame frame, Object deparseLevelObj, Object[] args, RArgsValuesAndNames promiseArgs, int precedence) { + protected RNull allNull(VirtualFrame frame, int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, int precedence) { return RNull.instance; } @@ -148,7 +149,7 @@ public abstract class Bind extends RBaseNode { private static final RStringVector DATA_FRAME_CLASS = RDataFactory.createStringVectorFromScalar("data.frame"); @Specialization(guards = {"args.length > 1", "isDataFrame(args)"}) - protected Object allDataFrame(VirtualFrame frame, Object deparseLevel, @SuppressWarnings("unused") Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence) { + protected Object allDataFrame(VirtualFrame frame, int deparseLevel, @SuppressWarnings("unused") Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence) { if (dcn == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); dcn = insert(new UseMethodInternalNode(type.toString(), SIGNATURE, false)); @@ -160,7 +161,7 @@ public abstract class Bind extends RBaseNode { } } - private Object bindInternal(Object deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, CastNode castNode, boolean needsVectorCast) { + private Object bindInternal(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, CastNode castNode, boolean needsVectorCast) { ArgumentsSignature signature = promiseArgs.getSignature(); String[] vecNames = nullNamesProfile.profile(signature.getNonNullCount() == 0) ? null : new String[signature.getLength()]; RAbstractVector[] vectors = new RAbstractVector[args.length]; @@ -203,31 +204,31 @@ public abstract class Bind extends RBaseNode { } @Specialization(guards = {"precedence == INT_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"}) - protected Object allInt(Object deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, // + protected Object allInt(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, // @Cached("create()") CastIntegerNode cast) { return bindInternal(deparseLevel, args, promiseArgs, cast, true); } @Specialization(guards = {"precedence == DOUBLE_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"}) - protected Object allDouble(Object deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, // + protected Object allDouble(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, // @Cached("create()") CastDoubleNode cast) { return bindInternal(deparseLevel, args, promiseArgs, cast, true); } @Specialization(guards = {"precedence == STRING_PRECEDENCE", "args.length> 1", "!isDataFrame(args)"}) - protected Object allString(Object deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, // + protected Object allString(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, // @Cached("create()") CastStringNode cast) { return bindInternal(deparseLevel, args, promiseArgs, cast, true); } @Specialization(guards = {"precedence == COMPLEX_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"}) - protected Object allComplex(Object deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, // + protected Object allComplex(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, // @Cached("create()") CastComplexNode cast) { return bindInternal(deparseLevel, args, promiseArgs, cast, true); } @Specialization(guards = {"precedence == LIST_PRECEDENCE", "args.length > 1", "!isDataFrame(args)"}) - protected Object allList(Object deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, // + protected Object allList(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence, // @Cached("create()") CastListNode cast) { return bindInternal(deparseLevel, args, promiseArgs, cast, false); } @@ -267,7 +268,7 @@ public abstract class Bind extends RBaseNode { * Compute dimnames for columns (cbind) or rows (rbind) from names of vectors being combined or * by deparsing. */ - protected int getDimResultNamesFromVectors(RArgsValuesAndNames promiseArgs, RAbstractVector vec, String[] argNames, int resDim, int oldInd, int vecInd, Object deparseLevelObj, + protected int getDimResultNamesFromVectors(RArgsValuesAndNames promiseArgs, RAbstractVector vec, String[] argNames, int resDim, int oldInd, int vecInd, int deparseLevel, String[] dimNamesArray, int dimNamesInd) { int ind = oldInd; @@ -294,7 +295,6 @@ public abstract class Bind extends RBaseNode { return -ind; } else if (!vec.isArray() || vec.getDimensions().length == 1) { if (argNames == null) { - int deparseLevel = deparseLevel(deparseLevelObj); if (deparseLevel == 0) { dimNamesArray[ind++] = RRuntime.NAMES_ATTR_EMPTY_VALUE; return -ind; @@ -350,15 +350,6 @@ public abstract class Bind extends RBaseNode { return notEqualDims; } - protected int deparseLevel(Object deparseLevelObj) { - RAbstractLogicalVector v = (RAbstractLogicalVector) castLogical(castVector(deparseLevelObj), true); - if (v.getLength() == 0 || v.getDataAt(0) == 0) { - return 0; - } else { - return v.getDataAt(0); - } - } - protected int[] getDimensions(RAbstractVector vector) { int[] dimensions = vector.getDimensions(); if (dimensions == null || dimensions.length != 2) { @@ -404,6 +395,11 @@ public abstract class Bind extends RBaseNode { @Child private Bind bind = BindNodeGen.create(BindType.cbind); @Child private PrecedenceNode precedenceNode = PrecedenceNodeGen.create(); + @Override + protected void createCasts(CastBuilder casts) { + casts.arg("deparse.level").asIntegerVector().findFirst(); + } + private int precedence(Object[] args) { int precedence = -1; for (int i = 0; i < args.length; i++) { @@ -413,8 +409,8 @@ public abstract class Bind extends RBaseNode { } @Specialization - protected Object bind(VirtualFrame frame, Object deparseLevelObj, RArgsValuesAndNames args) { - return bind.execute(frame, deparseLevelObj, args.getArguments(), (RArgsValuesAndNames) RArguments.getArgument(frame, 0), precedence(args.getArguments())); + protected Object bind(VirtualFrame frame, int deparseLevel, RArgsValuesAndNames args) { + return bind.execute(frame, deparseLevel, args.getArguments(), (RArgsValuesAndNames) RArguments.getArgument(frame, 0), precedence(args.getArguments())); } } @@ -422,7 +418,7 @@ public abstract class Bind extends RBaseNode { private final BranchProfile everSeenNotEqualColumns = BranchProfile.create(); @Specialization(guards = {"precedence != NO_PRECEDENCE", "args.length == 1"}) - protected Object allOneElem(Object deparseLevelObj, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence) { + protected Object allOneElem(int deparseLevel, Object[] args, RArgsValuesAndNames promiseArgs, @SuppressWarnings("unused") int precedence) { RAbstractVector vec = castVector(args[0]); if (vec.isMatrix()) { return vec; @@ -435,7 +431,6 @@ public abstract class Bind extends RBaseNode { ArgumentsSignature signature = promiseArgs.getSignature(); if (signature.getNonNullCount() == 0) { - int deparseLevel = deparseLevel(deparseLevelObj); if (deparseLevel == 0) { dimNamesB = RNull.instance; } else { @@ -457,7 +452,7 @@ public abstract class Bind extends RBaseNode { return res; } - public RVector genericCBind(RArgsValuesAndNames promiseArgs, RAbstractVector[] vectors, boolean complete, String[] vecNames, boolean vecNamesComplete, Object deparseLevel) { + public RVector genericCBind(RArgsValuesAndNames promiseArgs, RAbstractVector[] vectors, boolean complete, String[] vecNames, boolean vecNamesComplete, int deparseLevel) { int[] resultDimensions = new int[2]; int[] secondDims = new int[vectors.length]; @@ -518,6 +513,11 @@ public abstract class Bind extends RBaseNode { @Child private Bind bind = BindNodeGen.create(BindType.rbind); @Child private PrecedenceNode precedenceNode = PrecedenceNodeGen.create(); + @Override + protected void createCasts(CastBuilder casts) { + casts.arg("deparse.level").asIntegerVector().findFirst(); + } + private int precedence(Object[] args) { int precedence = -1; for (int i = 0; i < args.length; i++) { @@ -527,12 +527,12 @@ public abstract class Bind extends RBaseNode { } @Specialization - protected Object bind(VirtualFrame frame, Object deparseLevelObj, RArgsValuesAndNames args) { - return bind.execute(frame, deparseLevelObj, args.getArguments(), (RArgsValuesAndNames) RArguments.getArgument(frame, 0), precedence(args.getArguments())); + protected Object bind(VirtualFrame frame, int deparseLevel, RArgsValuesAndNames args) { + return bind.execute(frame, deparseLevel, args.getArguments(), (RArgsValuesAndNames) RArguments.getArgument(frame, 0), precedence(args.getArguments())); } } - public RVector genericRBind(RArgsValuesAndNames promiseArgs, RAbstractVector[] vectors, boolean complete, String[] vecNames, boolean vecNamesComplete, Object deparseLevel) { + public RVector genericRBind(RArgsValuesAndNames promiseArgs, RAbstractVector[] vectors, boolean complete, String[] vecNames, boolean vecNamesComplete, int deparseLevel) { int[] resultDimensions = new int[2]; int[] firstDims = new int[vectors.length]; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java index b1e8b8809410ffaade8698147faf38c847b2b085..a2527d8e6e5a10fc63638a4654c25af041d201b2 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java @@ -368,7 +368,7 @@ public final class RError extends RuntimeException { // below: not exactly GNU-R message PROMISE_CYCLE("promise already under evaluation: recursive default argument reference or earlier problems?"), MISSING_ARGUMENTS("'missing' can only be used for arguments"), - INVALID_ENVIRONMENT("invalid environment specified"), + INVALID_ENVIRONMENT("invalid environment"), ENVIR_NOT_LENGTH_ONE("numeric 'envir' arg not of length one"), FMT_NOT_CHARACTER("'fmt' is not a character vector"), UNSUPPORTED_TYPE("unsupported type"), diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index 747b14fce59ab65bc0324e28d1ca11432e604e52..f1dc824c72aaca9c94b7fa3e2124a04d6450d925 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -6001,6 +6001,15 @@ a + foo(c) * b #foo <- function(x) x*2; f <- function() a+foo(c)*b; as.function(c(alist(a=1+14, b=foo(x),c=), body(f)))(c=3,b=1) [1] 21 +##com.oracle.truffle.r.test.builtins.TestBuiltin_asfunction.testasfunction +#{ .Internal(as.function.default(alist(a+b), "foo")) } +Error in as.function.default(alist(a + b), "foo") : invalid environment + +##com.oracle.truffle.r.test.builtins.TestBuiltin_asfunction.testasfunction +#{ .Internal(as.function.default(function() 42, parent.frame())) } +Error in as.function.default(function() 42, parent.frame()) : + list argument expected + ##com.oracle.truffle.r.test.builtins.TestBuiltin_asfunction.testasfunction #{ as.function(alist("foo"))() } [1] "foo" diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asfunction.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asfunction.java index fd5ab3b839035c4da732444ea11a2285d5ed31f5..b0432a40b7d1b1a86be53c5f91686a31760b0bb6 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asfunction.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asfunction.java @@ -40,5 +40,7 @@ public class TestBuiltin_asfunction extends TestBase { assertEval("{ as.function(alist(\"foo\"))() }"); assertEval("{ as.function(alist(7+42i))() }"); assertEval("{ as.function(alist(as.raw(7)))() }"); + assertEval(Output.IgnoreErrorContext, "{ .Internal(as.function.default(alist(a+b), \"foo\")) }"); + assertEval(Output.IgnoreErrorContext, "{ .Internal(as.function.default(function() 42, parent.frame())) }"); } }