From 167f7d23442db5a3b09adc32d37159c5ca8c16db Mon Sep 17 00:00:00 2001 From: stepan <stepan.sindelar@oracle.com> Date: Wed, 7 Mar 2018 11:41:53 +0100 Subject: [PATCH] Implement the `function` builtin --- .../r/engine/RRuntimeASTAccessImpl.java | 2 + .../r/nodes/builtin/base/BasePackage.java | 3 +- .../truffle/r/nodes/builtin/base/Call.java | 29 ++------ .../builtin/base/infix/FunctionBuiltin.java | 67 +++++++++++++++++-- .../oracle/truffle/r/nodes/RASTBuilder.java | 28 ++++++++ .../oracle/truffle/r/runtime/RDeparse.java | 35 +++++++++- .../com/oracle/truffle/r/runtime/RError.java | 1 + .../truffle/r/runtime/nodes/RCodeBuilder.java | 10 ++- .../truffle/r/test/ExpectedTestOutput.test | 26 +++++-- .../r/test/builtins/TestBuiltin_ascall.java | 6 +- .../r/test/builtins/TestBuiltin_function.java | 37 ++++++++++ 11 files changed, 205 insertions(+), 39 deletions(-) create mode 100644 com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_function.java diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java index 1e8fa828c1..bfd35372ed 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java @@ -67,6 +67,7 @@ import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntimeASTAccess; import com.oracle.truffle.r.runtime.RSrcref; @@ -84,6 +85,7 @@ 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.RNull; +import com.oracle.truffle.r.runtime.data.RPairList; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index 17a34fa9a8..601f97464f 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -72,7 +72,6 @@ import com.oracle.truffle.r.nodes.builtin.base.infix.BreakBuiltinNodeGen; import com.oracle.truffle.r.nodes.builtin.base.infix.ForBuiltin; import com.oracle.truffle.r.nodes.builtin.base.infix.ForBuiltinNodeGen; import com.oracle.truffle.r.nodes.builtin.base.infix.FunctionBuiltin; -import com.oracle.truffle.r.nodes.builtin.base.infix.FunctionBuiltinNodeGen; import com.oracle.truffle.r.nodes.builtin.base.infix.IfBuiltin; import com.oracle.truffle.r.nodes.builtin.base.infix.IfBuiltinNodeGen; import com.oracle.truffle.r.nodes.builtin.base.infix.NextBuiltin; @@ -798,7 +797,7 @@ public class BasePackage extends RBuiltinPackage { add(BraceBuiltin.class, BraceBuiltinNodeGen::create); add(BreakBuiltin.class, BreakBuiltinNodeGen::create); add(ForBuiltin.class, ForBuiltinNodeGen::create); - add(FunctionBuiltin.class, FunctionBuiltinNodeGen::create); + add(FunctionBuiltin.class, FunctionBuiltin::create); add(IfBuiltin.class, IfBuiltinNodeGen::create); add(NextBuiltin.class, NextBuiltinNodeGen::create); add(ParenBuiltin.class, ParenBuiltin::new, ParenBuiltin::special); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java index da1db2993a..c60c75338c 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Call.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,8 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.builtin.base.infix.FunctionBuiltin; +import com.oracle.truffle.r.nodes.function.FunctionExpressionNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; @@ -79,32 +81,15 @@ public abstract class Call extends RBuiltinNode.Arg2 { @TruffleBoundary public static RLanguage makeCall(TruffleRLanguage language, RSyntaxNode target, Object[] arguments, ArgumentsSignature signature) { assert arguments.length == signature.getLength(); - if (target instanceof RSyntaxLookup && "function".equals(((RSyntaxLookup) target).getIdentifier())) { - return makeFunction(language, arguments); + if (target instanceof RSyntaxLookup && "function".equals(((RSyntaxLookup) target).getIdentifier()) && arguments.length == 2) { + // this optimization is not strictly necessary, `function` builtin is functional too. + FunctionExpressionNode function = FunctionBuiltin.createFunctionExpressionNode(language, arguments[0], arguments[1]); + return RDataFactory.createLanguage(Closure.createLanguageClosure(function.asRNode())); } else { return makeCall0(target, arguments, signature); } } - private static RLanguage makeFunction(TruffleRLanguage language, Object[] arguments) { - CompilerAsserts.neverPartOfCompilation(); - Object body = arguments.length <= 1 ? RNull.instance : arguments[1]; - Object argList = arguments.length == 0 ? RNull.instance : arguments[0]; - ArrayList<RCodeBuilder.Argument<RSyntaxNode>> finalArgs = new ArrayList<>(); - while (argList != RNull.instance) { - if (!(argList instanceof RPairList)) { - throw RError.error(RError.SHOW_CALLER, Message.BAD_FUNCTION_EXPR); - } - RPairList pl = (RPairList) argList; - String name = ((RSymbol) pl.getTag()).getName(); - RSyntaxNode value = RASTUtils.createNodeForValue(pl.car()).asRSyntaxNode(); - finalArgs.add(RCodeBuilder.argument(RSyntaxNode.LAZY_DEPARSE, name, value)); - argList = pl.cdr(); - } - RSyntaxNode function = RContext.getASTBuilder().function(language, RSyntaxNode.LAZY_DEPARSE, finalArgs, RASTUtils.createNodeForValue(body).asRSyntaxNode(), null); - return RDataFactory.createLanguage(Closure.createLanguageClosure(function.asRNode())); - } - @TruffleBoundary private static RLanguage makeCall0(RSyntaxNode target, Object[] arguments, ArgumentsSignature signature) { RSyntaxNode[] args = new RSyntaxNode[arguments.length]; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/FunctionBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/FunctionBuiltin.java index 3909ffbb92..4f885fac2f 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/FunctionBuiltin.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/infix/FunctionBuiltin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,23 +22,78 @@ */ package com.oracle.truffle.r.nodes.builtin.base.infix; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean; +import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX; import static com.oracle.truffle.r.runtime.builtins.RBehavior.READS_FRAME; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; +import java.util.ArrayList; +import java.util.List; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.MaterializedFrame; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.function.FunctionExpressionNode; +import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.context.TruffleRLanguage; +import com.oracle.truffle.r.runtime.data.Closure; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RExpression; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RPairList; +import com.oracle.truffle.r.runtime.data.RPromise; +import com.oracle.truffle.r.runtime.data.RSymbol; +import com.oracle.truffle.r.runtime.nodes.RCodeBuilder; +import com.oracle.truffle.r.runtime.nodes.RCodeBuilder.Argument; +import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; -@RBuiltin(name = "function", kind = PRIMITIVE, parameterNames = {"x"}, behavior = READS_FRAME) -public abstract class FunctionBuiltin extends RBuiltinNode.Arg1 { +@RBuiltin(name = "function", kind = PRIMITIVE, nonEvalArgs = 1, parameterNames = {"args", "body"}, behavior = COMPLEX) +public final class FunctionBuiltin extends RBuiltinNode.Arg2 { static { Casts.noCasts(FunctionBuiltin.class); } - @Specialization - protected Object doIt(@SuppressWarnings("unused") Object x) { - throw RInternalError.unimplemented(); + @Child private CreateAndExecuteFunctionExpr createFunNode; + + @Override + public Object execute(VirtualFrame frame, Object args, Object body) { + if (createFunNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + createFunNode = insert(new CreateAndExecuteFunctionExpr()); + } + return createFunNode.execute(frame.materialize(), getRLanguage(), args, body); + } + + public static FunctionBuiltin create() { + return new FunctionBuiltin(); + } + + protected static final class CreateAndExecuteFunctionExpr extends TruffleBoundaryNode { + @Child private FunctionExpressionNode funExprNode; + + @TruffleBoundary + public Object execute(MaterializedFrame frame, TruffleRLanguage language, Object args, Object body) { + funExprNode = insert(createFunctionExpressionNode(getRLanguage(), args, body)); + return funExprNode.execute(frame); + } + } + + public static FunctionExpressionNode createFunctionExpressionNode(TruffleRLanguage language, Object args, Object body) { + List<Argument<RSyntaxNode>> finalArgs = RContext.getASTBuilder().getFunctionExprArgs(args); + return (FunctionExpressionNode) RContext.getASTBuilder().function(language, RSyntaxNode.LAZY_DEPARSE, finalArgs, RASTUtils.createNodeForValue(body).asRSyntaxNode(), null); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java index f970469231..b682b1268a 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java @@ -22,8 +22,10 @@ */ package com.oracle.truffle.r.nodes; +import java.util.ArrayList; import java.util.List; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameDescriptor; @@ -53,12 +55,17 @@ import com.oracle.truffle.r.nodes.function.signature.MissingNode; import com.oracle.truffle.r.nodes.function.signature.QuoteNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.FastROptions; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.builtins.FastPathFactory; import com.oracle.truffle.r.runtime.context.TruffleRLanguage; import com.oracle.truffle.r.runtime.data.REmpty; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RPairList; import com.oracle.truffle.r.runtime.data.RShareable; +import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; import com.oracle.truffle.r.runtime.nodes.EvaluatedArgumentsVisitor; import com.oracle.truffle.r.runtime.nodes.RCodeBuilder; @@ -190,6 +197,27 @@ public final class RASTBuilder implements RCodeBuilder<RSyntaxNode> { return FunctionExpressionNode.create(source, callTarget); } + @Override + public ArrayList<Argument<RSyntaxNode>> getFunctionExprArgs(Object args) { + CompilerAsserts.neverPartOfCompilation(); + if (!(args instanceof RPairList || args == RNull.instance)) { + throw RError.error(RError.SHOW_CALLER, Message.INVALID_FORMAL_ARG_LIST, "function"); + } + ArrayList<Argument<RSyntaxNode>> finalArgs = new ArrayList<>(); + Object argList = args; + while (argList != RNull.instance) { + if (!(argList instanceof RPairList)) { + throw RError.error(RError.SHOW_CALLER, Message.INVALID_FORMAL_ARG_LIST, "function"); + } + RPairList pl = (RPairList) argList; + String name = ((RSymbol) pl.getTag()).getName(); + RSyntaxNode value = RASTUtils.createNodeForValue(pl.car()).asRSyntaxNode(); + finalArgs.add(RCodeBuilder.argument(RSyntaxNode.LAZY_DEPARSE, name, value)); + argList = pl.cdr(); + } + return finalArgs; + } + @Override public RootCallTarget rootFunction(TruffleRLanguage language, SourceSection source, List<Argument<RSyntaxNode>> params, RSyntaxNode body, String name) { // Parse argument list diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java index 7bef648d8b..0b5398bfaa 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java @@ -28,6 +28,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.interop.TruffleObject; @@ -35,6 +36,7 @@ import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RAttributesLayout; @@ -67,6 +69,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle; import com.oracle.truffle.r.runtime.interop.TruffleObjectConverter; +import com.oracle.truffle.r.runtime.nodes.RCodeBuilder; +import com.oracle.truffle.r.runtime.nodes.RCodeBuilder.Argument; import com.oracle.truffle.r.runtime.nodes.RSyntaxCall; import com.oracle.truffle.r.runtime.nodes.RSyntaxConstant; import com.oracle.truffle.r.runtime.nodes.RSyntaxElement; @@ -521,6 +525,9 @@ public class RDeparse { RSyntaxElement[] args = call.getSyntaxArguments(); if (lhs instanceof RSyntaxLookup) { String symbol = ((RSyntaxLookup) lhs).getIdentifier(); + if ("function".equals(symbol)) { + return visitFunctionFunction(args); + } RDeparse.Func func = RDeparse.getFunc(symbol); if (func != null) { PPInfo info = func.info; @@ -675,10 +682,34 @@ public class RDeparse { @Override protected Void visit(RSyntaxFunction function) { + return visitFunctionExpr(function.getSyntaxSignature(), function.getSyntaxArgumentDefaults(), function.getSyntaxBody()); + } + + private Void visitFunctionExpr(ArgumentsSignature signature, RSyntaxElement[] argsDefaults, RSyntaxElement body) { append("function("); - appendArgs(function.getSyntaxSignature(), function.getSyntaxArgumentDefaults(), 0, true); + appendArgs(signature, argsDefaults, 0, true); append(") "); - appendFunctionBody(function.getSyntaxBody()); + appendFunctionBody(body); + return null; + } + + private Void visitFunctionFunction(RSyntaxElement[] args) { + if (args.length > 0 && !(args[0] instanceof RSyntaxConstant)) { + throw RError.error(RError.SHOW_CALLER2, Message.BAD_FUNCTION_EXPR); + } + Object funArgsValue = args.length > 0 ? ((RSyntaxConstant) args[0]).getValue() : RNull.instance; + List<Argument<RSyntaxNode>> syntaxArgs = RContext.getASTBuilder().getFunctionExprArgs(funArgsValue); + String[] names = new String[syntaxArgs.size()]; + RSyntaxNode[] values = new RSyntaxNode[syntaxArgs.size()]; + for (int i = 0; i < syntaxArgs.size(); i++) { + names[i] = syntaxArgs.get(i).name; + values[i] = syntaxArgs.get(i).value; + } + Object body = args.length <= 1 ? RNull.instance : args[1]; + if (!(body instanceof RSyntaxElement)) { + body = RContext.getASTBuilder().constant(RSyntaxNode.SOURCE_UNAVAILABLE, body); + } + visitFunctionExpr(ArgumentsSignature.get(names), values, (RSyntaxElement) body); return null; } } 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 a0282f634e..9c04e55fe4 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 @@ -944,6 +944,7 @@ public final class RError extends RuntimeException implements TruffleException { VERSION_N_NOT_SUPPORTED("version %d not supported"), ATOMIC_VECTOR_ARGUMENTS_ONLY("atomic vector arguments only"), MUST_BE_COMPLEX_MATRIX("'%s' must be a complex matrix"), + INVALID_FORMAL_ARG_LIST("invalid formal argument list for \"%s\""), SINGULAR_BACKSOLVE("singular matrix in 'backsolve'. First zero in diagonal [%d]"); public final String message; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java index 1071ca6c13..9d4415f7ab 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RCodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.context.TruffleRLanguage; +import com.oracle.truffle.r.runtime.data.RNull; /** * Implementers of this interface can be used to generate a representation of an R closure. @@ -120,6 +121,13 @@ public interface RCodeBuilder<T> { */ RootCallTarget rootFunction(TruffleRLanguage language, SourceSection source, List<Argument<T>> arguments, T body, String name); + /** + * Given a {@link com.oracle.truffle.r.runtime.data.RPairList} or {@link RNull}, this method + * creates a corresponding list of named arguments with default values if any, like if passed to + * the `function` expression. + */ + List<Argument<RSyntaxNode>> getFunctionExprArgs(Object args); + void setContext(CodeBuilderContext context); CodeBuilderContext getContext(); 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 1a21c8090a..440ac65414 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 @@ -5917,10 +5917,6 @@ foo() #call('function') function() NULL -##com.oracle.truffle.r.test.builtins.TestBuiltin_ascall.testAsCall#Output.IgnoreWhitespace# -#call('function', 'a') -Error: badly formed function expression - ##com.oracle.truffle.r.test.builtins.TestBuiltin_ascall.testAsCall#Output.IgnoreWhitespace# #call('function', pairlist(a=1)) function(a = 1) NULL @@ -5949,6 +5945,13 @@ pairlist(a = )() #e <- substitute(a$b(c)); as.call(lapply(e, function(x) x)) a$b(c) +##com.oracle.truffle.r.test.builtins.TestBuiltin_ascall.testAsCall#Output.IgnoreWhitespace# +#invisible(call('function', 'a')) + +##com.oracle.truffle.r.test.builtins.TestBuiltin_ascall.testAsCall#Output.IgnoreWhitespace# +#length(call('function', 'a')) +[1] 2 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_ascall.testAsCall# #typeof(as.call(list(substitute(graphics::par)))) [1] "language" @@ -28261,6 +28264,21 @@ Error: atomic vector arguments only #argv <- structure(list(pv = 0.200965994008331, digits = 3), .Names = c('pv', 'digits'));do.call('format.pval', argv) [1] "0.201" +##com.oracle.truffle.r.test.builtins.TestBuiltin_function.testFunctionFunction# +#do.call('function', list(as.pairlist(list(x=4)), expression(x + 1)[[1]])) +function (x = 4) +x + 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_function.testFunctionFunction#Output.IgnoreErrorContext# +#eval(call('function', 1, expression(x + 1)[[1]])) +Error in eval(call("function", 1, expression(x + 1)[[1]])) : + invalid formal argument list for "function" + +##com.oracle.truffle.r.test.builtins.TestBuiltin_function.testFunctionFunction# +#eval(call('function', as.pairlist(list(x=4)), expression(x + 1)[[1]])) +function (x = 4) +x + 1 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_g.testg1#Output.IgnoreErrorContext# #argv <- list(1);g(argv[[1]]); Error in g(argv[[1]]) : could not find function "g" diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascall.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascall.java index 7b55239637..bc6fff85e3 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascall.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_ascall.java @@ -4,7 +4,7 @@ * http://www.gnu.org/licenses/gpl-2.0.html * * Copyright (c) 2012-2014, Purdue University - * Copyright (c) 2013, 2017, Oracle and/or its affiliates + * Copyright (c) 2013, 2018, Oracle and/or its affiliates * * All rights reserved. */ @@ -68,7 +68,9 @@ public class TestBuiltin_ascall extends TestBase { assertEval(Output.IgnoreWhitespace, "e <- expression(function(a) b); as.call(list(e[[1]][[1]]))"); assertEval("e <- expression(function(a) b); as.call(list(e[[1]][[2]]))"); assertEval("call('foo')"); - assertEval(Output.IgnoreWhitespace, "call('function', 'a')"); + // Note: call('function', 'a') should not cause the exception, it should be the printing + assertEval(Output.IgnoreWhitespace, "invisible(call('function', 'a'))"); + assertEval(Output.IgnoreWhitespace, "length(call('function', 'a'))"); assertEval(Output.IgnoreWhitespace, "call('function', pairlist(a=1))"); assertEval(Output.IgnoreWhitespace, "call('function', pairlist(a=1), 3)"); assertEval(Output.IgnoreWhitespace, "call('function', pairlist(a=1), 5,3)"); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_function.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_function.java new file mode 100644 index 0000000000..eac9c3629d --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_function.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.test.builtins; + +import org.junit.Test; + +import com.oracle.truffle.r.test.TestBase; + +// Checkstyle: stop line length check +public class TestBuiltin_function extends TestBase { + @Test + public void testFunctionFunction() { + assertEval(Output.IgnoreErrorContext, "eval(call('function', 1, expression(x + 1)[[1]]))"); + assertEval("eval(call('function', as.pairlist(list(x=4)), expression(x + 1)[[1]]))"); + assertEval("do.call('function', list(as.pairlist(list(x=4)), expression(x + 1)[[1]]))"); + } +} -- GitLab