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 237533d83dd08fa6fbec0849afc019331ae913a1..369665c95238c204826bd40f60ee244c6f9c3a96 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 @@ -334,6 +334,7 @@ public class BasePackage extends RBuiltinPackage { add(EnvFunctions.SetParentEnv.class, EnvFunctionsFactory.SetParentEnvNodeGen::create); add(EnvFunctions.UnlockBinding.class, EnvFunctionsFactory.UnlockBindingNodeGen::create); add(Eval.class, EvalNodeGen::create); + add(RecordGraphics.class, RecordGraphics::create); add(WithVisible.class, WithVisibleNodeGen::create); add(Exists.class, ExistsNodeGen::create); add(Expression.class, ExpressionNodeGen::create); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RecordGraphics.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RecordGraphics.java new file mode 100644 index 0000000000000000000000000000000000000000..b0be4bf5342b864edfc78816e3218bb41c1494fb --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RecordGraphics.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017, 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.nodes.builtin.base; + +import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX; +import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; + +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.builtin.RList2EnvNode; +import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode; +import com.oracle.truffle.r.runtime.RCaller; +import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RExpression; +import com.oracle.truffle.r.runtime.data.RLanguage; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.env.REnvironment; + +/** + * The {@code expr} parameter is supposed to be R graphics code, e.g. {@code rect(4,2,...);}, which + * is supposed to be run and recorded (probably in order to be re-run as is if the device size is + * changed). The visible behavior is that a e.g. rectangle created via {@code recordGraphics} + * maintains its size regardless of resizes of the device (e.g. window). + * + * TODO: the current implementation is a stub that only runs the command, but does not fiddle with + * the recording like GnuR does. + */ +@RBuiltin(name = "recordGraphics", kind = INTERNAL, parameterNames = {"expr", "list", "env"}, behavior = COMPLEX) +public abstract class RecordGraphics extends RBuiltinNode { + @Child private SetVisibilityNode visibility = SetVisibilityNode.create(); + @Child private RList2EnvNode list2EnvNode = new RList2EnvNode(); + + public static RecordGraphics create() { + return RecordGraphicsNodeGen.create(); + } + + @Specialization + protected Object doEval(VirtualFrame frame, RLanguage expr, RList list, REnvironment env) { + RCaller rCaller = RCaller.create(frame, getOriginalCall()); + try { + return RContext.getEngine().eval(expr, createEnv(list, env), rCaller); + } finally { + visibility.executeAfterCall(frame, rCaller); + } + } + + @Specialization + protected Object doEval(VirtualFrame frame, RExpression expr, RList list, REnvironment env) { + RCaller rCaller = RCaller.create(frame, getOriginalCall()); + try { + return RContext.getEngine().eval(expr, createEnv(list, env), rCaller); + } finally { + visibility.executeAfterCall(frame, rCaller); + } + } + + private REnvironment createEnv(RList list, REnvironment parent) { + REnvironment newEnv = RDataFactory.createNewEnv("<recordGraphics env>", true, list.getLength()); + newEnv.setParent(parent); + return list2EnvNode.execute(list, newEnv); + } +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sprintf.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sprintf.java index c40704dc7ac64ab00be24a7d4c7259cbf1ee3f7f..a18ee23a793b911520dc0b9359999da104b20040 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sprintf.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Sprintf.java @@ -337,7 +337,11 @@ public abstract class Sprintf extends RBuiltinNode { } conversions[fi.numArg - 1] = fi.conversion; } - sb.append(fi.conversion); + char conversion = fi.conversion; + if (conversion == 'g' && args[fi.numArg - 1] instanceof Integer) { + conversion = 'd'; + } + sb.append(conversion); i = fi.nextChar; } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java index ddd2f3bd7a8b00a12bb440caf1af03a056d82d30..a268a72ea9b9f4677852e5ad457217a8234a5989 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java @@ -657,13 +657,24 @@ public class CallAndExternalFunctions { * package) */ @SuppressWarnings("unused") - @Specialization(limit = "1", guards = {"cached == symbol"}) + @Specialization(limit = "2", guards = {"cached == symbol"}) protected Object callNamedFunction(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName, @Cached("symbol") RList cached, @Cached("extractSymbolInfo(frame, symbol)") NativeCallInfo nativeCallInfo) { return callRFFINode.invokeCall(nativeCallInfo, args.getArguments()); } + /** + * For some reason, the list instance may change, although it carries the same info. For + * such cases there is this generic version. + */ + @SuppressWarnings("unused") + @Specialization(contains = "callNamedFunction") + protected Object callNamedFunctionGeneric(VirtualFrame frame, RList symbol, RArgsValuesAndNames args, Object packageName) { + NativeCallInfo nativeCallInfo = extractSymbolInfo(frame, symbol); + return callRFFINode.invokeCall(nativeCallInfo, args.getArguments()); + } + /** * {@code .NAME = string}, no package specified. */ diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/InternalNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/InternalNode.java index 5ebc1526540a534bb45e1b1645e0bee0f0751f85..16694345d4e53e6f2b41047e2dae9db567cce76f 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/InternalNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/InternalNode.java @@ -353,7 +353,7 @@ public abstract class InternalNode extends OperatorNode { "phyper", "qhyper", "dnbeta", "pnbeta", "qnbeta", "dnf", "pnf", "qnf", "dtukey", "ptukey", "qtukey", "rchisq", "rexp", "rgeom", "rpois", "rt", "rsignrank", "rbeta", "rbinom", "rcauchy", "rf", "rgamma", "rlnorm", "rlogis", "rnbinom", "rnbinom_mu", "rnchisq", "rnorm", "runif", "rweibull", "rwilcox", "rhyper", "format.info", "grepRaw", "regexec", "adist", "aregexec", "chartr", "packBits", "strtrim", "eapply", "machine", "save", "dump", "prmatrix", "gcinfo", "gctorture", "gctorture2", - "memory.profile", "recordGraphics", "sys.on.exit", "builtins", "bodyCode", "rapply", "inspect", + "memory.profile", "sys.on.exit", "builtins", "bodyCode", "rapply", "inspect", "mem.limits", "capabilitiesX11", "Cstack_info", "file.choose", "polyroot", "mkCode", "bcClose", "is.builtin.internal", "disassemble", "bcVersion", "load.from.file", "save.to.file", "growconst", "putconst", "getconst", "setNumMathThreads", "setMaxNumMathThreads", "isatty", "isIncomplete", "pipe", "fifo", "unz", "truncate", "rawConnection", "rawConnectionValue", "sockSelect", "gzcon", "memCompress", "memDecompress", "mkUnbound", "env.profile", "setSessionTimeLimit", "icuSetCollate", "findInterval", "rowsum_df", diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RList2EnvNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RList2EnvNode.java index 7dab79c0e30abdb9bbedfdb426db9dafc9e4fa36..a50458a51a216058dcab72e3f6c6ef9989e731b0 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RList2EnvNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/RList2EnvNode.java @@ -30,7 +30,7 @@ import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.nodes.RBaseNode; /** - * Abstracted for use by {@code List2Env}, {@code AsEnvironment}, {@code SubsituteDirect}. + * Abstracted for use by other nodes that need to convert a list into an environment. */ public final class RList2EnvNode extends RBaseNode { diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFI.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFI.java index eb76d0fb7fac997632e30bf934b5f2fd6e32d4d6..498519f4837e28824ff4fa6d9fc840e2c3636967 100644 --- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFI.java +++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/JavaUpCallsRFFI.java @@ -67,6 +67,7 @@ import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.data.RRawVector; import com.oracle.truffle.r.runtime.data.RS4Object; +import com.oracle.truffle.r.runtime.data.RSequence; import com.oracle.truffle.r.runtime.data.RShareable; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; @@ -783,12 +784,12 @@ public class JavaUpCallsRFFI implements UpCallsRFFI { tracer.Rf_duplicate(x, deep); } guarantee(x != null, "unexpected type: null instead of " + x.getClass().getSimpleName()); - guarantee(x instanceof RShareable || x instanceof RIntSequence || x instanceof RExternalPtr, + guarantee(x instanceof RShareable || x instanceof RSequence || x instanceof RExternalPtr, "unexpected type: " + x + " is " + x.getClass().getSimpleName() + " instead of RShareable or RExternalPtr"); if (x instanceof RShareable) { return deep == 1 ? ((RShareable) x).deepCopy() : ((RShareable) x).copy(); - } else if (x instanceof RIntSequence) { - return ((RIntSequence) x).materialize(); + } else if (x instanceof RSequence) { + return ((RSequence) x).materializeToShareable(); } else { return ((RExternalPtr) x).copy(); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java index 9bb2fb9d4f8e06129cc41295aeae915fdf31d113..69c2599300c388ce484e940738d183958cfec5ac 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/Utils.java @@ -475,31 +475,36 @@ public final class Utils { @TruffleBoundary public Frame visitFrame(FrameInstance frameInstance) { Frame f = RArguments.unwrap(frameInstance.getFrame(FrameAccess.READ_ONLY, true)); - if (RArguments.isRFrame(f) && RArguments.getFunction(f) != null) { - if (skip > 0) { - skip--; - } else { - RCaller call = RArguments.getCall(f); - assert call != null; - RLanguage rl = RContext.getRRuntimeASTAccess().getSyntaxCaller(call); - RSyntaxNode sn = (RSyntaxNode) rl.getRep(); - SourceSection ss = sn != null ? sn.getSourceSection() : null; - // fabricate a srcref attribute from ss - Source source = ss != null ? ss.getSource() : null; - String path = RSource.getPath(source); - RStringVector callerSource = RDataFactory.createStringVectorFromScalar(RContext.getRRuntimeASTAccess().getCallerSource(call)); - if (path != null) { - callerSource.setAttr(RRuntime.R_SRCREF, RSrcref.createLloc(ss, path)); - } - RPairList pl = RDataFactory.createPairList(callerSource); - if (prev != null) { - prev.setCdr(pl); - } else { - head = pl; - } - prev = pl; - } + if (!RArguments.isRFrame(f) || RArguments.getFunction(f) == null) { + return null; + } + RCaller call = RArguments.getCall(f); + assert call != null; + if (!call.isValidCaller()) { + // this is extra robustness. In ideal world we should not encounter invalid ones + return null; + } + if (skip > 0) { + skip--; + return null; + } + RLanguage rl = RContext.getRRuntimeASTAccess().getSyntaxCaller(call); + RSyntaxNode sn = (RSyntaxNode) rl.getRep(); + SourceSection ss = sn != null ? sn.getSourceSection() : null; + // fabricate a srcref attribute from ss + Source source = ss != null ? ss.getSource() : null; + String path = RSource.getPath(source); + RStringVector callerSource = RDataFactory.createStringVectorFromScalar(RContext.getRRuntimeASTAccess().getCallerSource(call)); + if (path != null) { + callerSource.setAttr(RRuntime.R_SRCREF, RSrcref.createLloc(ss, path)); + } + RPairList pl = RDataFactory.createPairList(callerSource); + if (prev != null) { + prev.setCdr(pl); + } else { + head = pl; } + prev = pl; return null; } } @@ -888,7 +893,7 @@ public final class Utils { } public static String toHexString(byte[] data) { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (byte b : data) { int ub = Byte.toUnsignedInt(b); if (ub > 15) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java index 2e9e1b3f2187f011e457e03470d0e78349eb608f..eaf92cff20f646ea6e4d988beded67914d17ea40 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, 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 @@ -36,7 +36,7 @@ public final class RDoubleSequence extends RSequence implements RAbstractDoubleV RDoubleSequence(double start, double stride, int length) { super(length); - assert length > 0; + assert length >= 0; this.start = start; this.stride = stride; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java index 62549bae7802a481d7f906799eb76c325d454955..ed1daeb266c538e015a5cad9b09785e962c9ae09 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, 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 @@ -36,7 +36,7 @@ public final class RIntSequence extends RSequence implements RAbstractIntVector RIntSequence(int start, int stride, int length) { super(length); - // assert length > 0; + assert length >= 0; this.start = start; this.stride = stride; } 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 b69fe6363cea325c1fe0f2c2c43fd62d13deb516..fd0bc58414949badf9651378c51a4a05d354ca46 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 @@ -57379,6 +57379,10 @@ NAs introduced by coercion #{ seq_len(-1) } Error in seq_len(-1) : argument must be coercible to non-negative integer +##com.oracle.truffle.r.test.builtins.TestBuiltin_seq_len.testSeqLen# +#{ seq_len(0) + 1.1; } +numeric(0) + ##com.oracle.truffle.r.test.builtins.TestBuiltin_seq_len.testSeqLen# #{ seq_len(10) } [1] 1 2 3 4 5 6 7 8 9 10 @@ -60049,6 +60053,10 @@ character(0) #{ sprintf("foo") } [1] "foo" +##com.oracle.truffle.r.test.builtins.TestBuiltin_sprintf.testSprintf# +#{ sprintf('plot_%02g', 3L) } +[1] "plot_03" + ##com.oracle.truffle.r.test.builtins.TestBuiltin_sprintf.testSprintf# #{ sprintf(c("foo %f %d", "bar %f %d"), 7, 42L) } [1] "foo 7.000000 42" "bar 7.000000 42" diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_seq_len.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_seq_len.java index 1352e6e6b1ddd89b724530c169118a2d696e2b62..c74dd2a81ff239a03f1c5133f8fabd0cff103936 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_seq_len.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_seq_len.java @@ -48,5 +48,7 @@ public class TestBuiltin_seq_len extends TestBase { assertEval("{ seq_len(-1) }"); assertEval("{ seq_len(NULL) }"); assertEval(Output.IgnoreWarningContext, "{ seq_len(\"foo\") }"); + // Note: tests conversion of empty integer sequence to empty double sequence + assertEval("{ seq_len(0) + 1.1; }"); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sprintf.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sprintf.java index 7a95cae93403ae46a6ad845bfd074cbbbba7db0d..d48f6c25f09d12b5d23eb290dfc1bf7642aafe83 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sprintf.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_sprintf.java @@ -146,5 +146,6 @@ public class TestBuiltin_sprintf extends TestBase { assertEval("{ sprintf(c(\"foo %f %d\", \"bar %f %d\"), 7, 42L) }"); assertEval("{ sprintf(c(\"foo %f %d\", \"bar %f %d\"), c(7,1), c(42L, 2L)) }"); assertEval("{ sprintf(\"%.3g\", 1.234) }"); + assertEval("{ sprintf('plot_%02g', 3L) }"); } }