diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/CPar.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/CPar.java index 4f520f1f2ab9159d8f48ae00fd8f13fd00f48263..f076d1a5e64fc162513b8369fe2d4d50108ec9d0 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/CPar.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/CPar.java @@ -31,6 +31,7 @@ import com.oracle.truffle.r.library.fastrGrid.device.DrawingContext; import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; import com.oracle.truffle.r.library.fastrGrid.grDevices.OpenDefaultDevice; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; +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; @@ -114,7 +115,11 @@ public final class CPar extends RExternalBuiltinNode { // TODO: return RDataFactory.createLogicalVectorFromScalar(false); default: - throw RError.nyi(RError.NO_CALLER, "C_Par parameter '" + name + "'"); + if (!FastROptions.IgnoreGraphicsCalls.getBooleanValue()) { + throw RError.nyi(RError.NO_CALLER, "C_Par parameter '" + name + "'"); + } else { + return RNull.instance; + } } } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/R/fastrGraphics.R b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/R/fastrGraphics.R index 2ffbef80c874914e8e0457462f1055a3f1d6ed33..f1d333aa7dfd2e9030bf4bc2c8136ee0b2e0992e 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/R/fastrGraphics.R +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/graphics/R/fastrGraphics.R @@ -25,24 +25,29 @@ # prints a warning message instructing the user to use grid/lattice/ggplot2 instead eval(expression({ - graphicsWarning <- function(name) { - # lookup original function and fetch signature - fun <- tryCatch(get(name, environment()), error=function(x) NULL) - if(!is.null(fun)) { - sig <- formals(fun) - } else { - sig <- NULL - } - - replacementFun <- function(...) { - warning(paste0(name, " not supported.", " Note: FastR does not support graphics package and most of its functions. Please use grid package or grid based packages like lattice instead.")) - NULL - } + if (.fastr.option('IgnoreGraphicsCalls')) { + # we force the arguments to be evaluated, but otherwise do nothing + graphicsWarning <- function(name) function(...) { list(...); invisible(NULL); } + } else { + graphicsWarning <- function(name) { + # lookup original function and fetch signature + fun <- tryCatch(get(name, environment()), error=function(x) NULL) + if(!is.null(fun)) { + sig <- formals(fun) + } else { + sig <- NULL + } + + replacementFun <- function(...) { + warning(paste0(name, " not supported.", " Note: FastR does not support graphics package and most of its functions. Please use grid package or grid based packages like lattice instead.")) + NULL + } - if(!is.null(sig)) { - formals(replacementFun) <- sig + if(!is.null(sig)) { + formals(replacementFun) <- sig + } + return(replacementFun) } - return(replacementFun) } plot.default <- function (x, y = NULL, type = "p", xlim = NULL, ylim = NULL, diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java index bbce2245242a70a7436c27bae48116004676e96c..349a1f8e3be3f65f7012aa410ef9b8badbfc2a7d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsVector.java @@ -66,6 +66,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RPairList; import com.oracle.truffle.r.runtime.data.RSharingAttributeStorage; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; @@ -260,6 +261,12 @@ public abstract class AsVector extends RBuiltinNode.Arg2 { return RNull.instance; } + @Specialization + @TruffleBoundary + protected Object doPairList(RPairList list) { + return list.copy(); + } + @Fallback protected Object castPairlist(Object x) { throw RInternalError.unimplemented("non-list casts to pairlist for " + x.getClass().getSimpleName()); 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 de74bbaa12896b6f15044afdb7da4d79709bf5af..438bccd17c05f57b5621b8b478ef68ff75fe6749 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 @@ -109,6 +109,7 @@ import com.oracle.truffle.r.nodes.builtin.fastr.FastRInterop; import com.oracle.truffle.r.nodes.builtin.fastr.FastRInteropFactory; import com.oracle.truffle.r.nodes.builtin.fastr.FastRLibPaths; import com.oracle.truffle.r.nodes.builtin.fastr.FastRLibPathsNodeGen; +import com.oracle.truffle.r.nodes.builtin.fastr.FastROptionBuiltin; import com.oracle.truffle.r.nodes.builtin.fastr.FastRPkgSource; import com.oracle.truffle.r.nodes.builtin.fastr.FastRPkgSourceNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastRRefCountInfo; @@ -435,6 +436,7 @@ public class BasePackage extends RBuiltinPackage { add(FastRSetBreakpoint.class, FastRSetBreakpointNodeGen::create); add(FastRHelp.class, FastRHelpNodeGen::create); add(FastRIdentity.class, FastRIdentityNodeGen::create); + add(FastROptionBuiltin.class, FastROptionBuiltin::create); add(FastRTry.class, FastRTryNodeGen::create); add(FastRInspect.class, FastRInspectNodeGen::create); add(FastRInterop.Eval.class, FastRInteropFactory.EvalNodeGen::create); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java index cee07fbd4bbce686c77f167e96131042d7bf0c49..c1002705f1527f1de76d9b2759a3f7fd9b165218 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java @@ -50,9 +50,11 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.conn.RConnection; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.REmpty; 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.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.RTypedValue; @@ -112,6 +114,15 @@ public abstract class Cat extends RBuiltinNode.Arg6 { @TruffleBoundary private RNull output(RList args, int file, RAbstractStringVector sepVec, int fillWidth, RAbstractStringVector labels, @SuppressWarnings("unused") boolean append) { + for (int i = 0; i < args.getLength(); i++) { + Object obj = args.getDataAt(i); + if (obj == REmpty.instance) { + // Note: we cannot easily get the name of the original argument, so we use a + // different error message than GNUR. + throw error(Message.MISSING_INVALID); + } + } + RConnection conn = RConnection.fromIndex(file); boolean filling = fillWidth > 0; ensureToString(); @@ -128,7 +139,7 @@ public abstract class Cat extends RBuiltinNode.Arg6 { for (int j = 0; j < stringVec.getLength(); j++) { stringVecs.add(stringVec.getDataAt(j)); } - } else if (obj instanceof RNull) { + } else if (obj == RNull.instance || obj == RMissing.instance) { continue; } else if (obj instanceof String) { stringVecs.add((String) obj); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java index 43d5493d06ba6c9e958597448d8b78aad39c9420..747c673fc0db715916387ac6b7eb72c2eec6d0ea 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/OptionsFunctions.java @@ -28,7 +28,12 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.MODIFIES_STATE; import static com.oracle.truffle.r.runtime.builtins.RBehavior.READS_STATE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; +import java.text.Collator; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Locale; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -41,6 +46,7 @@ import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RLocale; import com.oracle.truffle.r.runtime.ROptions; import com.oracle.truffle.r.runtime.ROptions.OptionsException; import com.oracle.truffle.r.runtime.builtins.RBuiltin; @@ -72,8 +78,22 @@ public class OptionsFunctions { Set<Map.Entry<String, Object>> optionSettings = RContext.getInstance().stateROptions.getValues(); Object[] data = new Object[optionSettings.size()]; String[] names = new String[data.length]; + + @SuppressWarnings({"unchecked", "rawtypes"}) + Map.Entry<String, Object>[] entries = optionSettings.toArray(new Map.Entry[optionSettings.size()]); + Locale locale = RContext.getInstance().stateRLocale.getLocale(RLocale.COLLATE); + Collator collator = locale == Locale.ROOT || locale == null ? null : RLocale.getOrderCollator(locale); + Arrays.sort(entries, new Comparator<Map.Entry<String, Object>>() { + @Override + public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) { + String k1 = o1.getKey(); + String k2 = o2.getKey(); + return collator == null ? k1.compareTo(k2) : collator.compare(k1, k2); + } + }); + int i = 0; - for (Map.Entry<String, Object> entry : optionSettings) { + for (Map.Entry<String, Object> entry : entries) { names[i] = entry.getKey(); data[i] = entry.getValue(); i++; @@ -119,7 +139,7 @@ public class OptionsFunctions { for (int i = 0; i < values.length; i++) { String argName = signature.getName(i); Object value = values[i]; - if (argNameNull.profile(argName == null)) { + if (argNameNull.profile(argName == null || value instanceof RList)) { // getting String optionName = null; if (value instanceof RStringVector) { @@ -146,6 +166,8 @@ public class OptionsFunctions { listNames[j] = name; options.setValue(name, list.getDataAtAsObject(j)); } + // any settings means result is invisible + visible = false; // if this is the only argument, no need to copy, can just return if (values.length == 1) { data = listData; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java index a3aa04791edfcdee8f32877b9552a29d4a481f69..c188ea4ce08a296a3bf0c5e8b7750583ecf8c6ea 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Order.java @@ -20,8 +20,6 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; import java.text.CollationKey; import java.text.Collator; -import java.text.ParseException; -import java.text.RuleBasedCollator; import java.util.Locale; import com.oracle.truffle.api.CompilerDirectives; @@ -40,7 +38,6 @@ import com.oracle.truffle.r.nodes.builtin.base.SortFunctions.RadixSort; import com.oracle.truffle.r.nodes.unary.CastToVectorNode; import com.oracle.truffle.r.nodes.unary.CastToVectorNodeGen; import com.oracle.truffle.r.runtime.RError; -import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RLocale; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; @@ -566,14 +563,7 @@ public abstract class Order extends RPrecedenceBuiltinNode { } } else { int length = dv.getLength(); - Collator baseCollator = Collator.getInstance(locale); - String rules = ((RuleBasedCollator) baseCollator).getRules(); - Collator collator; - try { - collator = new RuleBasedCollator(rules.replaceAll("<'\u005f'", "<' '<'\u005f'")); - } catch (ParseException e) { - throw RInternalError.shouldNotReachHere(e); - } + Collator collator = RLocale.getOrderCollator(locale); CollationKey[] entries = new CollationKey[length]; for (int i = 0; i < length; i++) { entries[i] = collator.getCollationKey(dv.getDataAt(i)); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastROptionBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastROptionBuiltin.java new file mode 100644 index 0000000000000000000000000000000000000000..a5b8a799baf880c2f5445a08ed02b72c11af395b --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastROptionBuiltin.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015, 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.fastr; + +import static com.oracle.truffle.r.runtime.RVisibility.OFF; +import static com.oracle.truffle.r.runtime.RVisibility.ON; +import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX; +import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.runtime.FastROptions; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.data.RMissing; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; + +/** + * Allows to read {@link FastROptions} from (e.g. internal) R code. + */ +@RBuiltin(name = ".fastr.option", visibility = ON, kind = PRIMITIVE, parameterNames = {"name"}, behavior = COMPLEX) +public abstract class FastROptionBuiltin extends RBuiltinNode.Arg1 { + + static { + Casts casts = new Casts(FastROptionBuiltin.class); + casts.arg("name").asStringVector().findFirst(); + } + + @Specialization + @TruffleBoundary + protected Object getOption(String name) { + FastROptions opt = null; + try { + opt = Enum.valueOf(FastROptions.class, name); + } catch (IllegalArgumentException e) { + return RNull.instance; + } + return opt.isBoolean() ? RRuntime.asLogical(opt.getBooleanValue()) : opt.getStringValue(); + } + + public static FastROptionBuiltin create() { + return FastROptionBuiltinNodeGen.create(); + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConvertBooleanNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConvertBooleanNode.java index ff55cf9f8b2ea74de50f2a1f1f5752d537e31fd9..0541c5523b79038b7dbd6c335f7e281640464bd9 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConvertBooleanNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ConvertBooleanNode.java @@ -32,18 +32,17 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.RComplex; -import com.oracle.truffle.r.runtime.data.RComplexVector; -import com.oracle.truffle.r.runtime.data.RList; -import com.oracle.truffle.r.runtime.data.RLogicalVector; +import com.oracle.truffle.r.runtime.data.RLogical; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RRaw; -import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator; import com.oracle.truffle.r.runtime.interop.ForeignArray2R; import com.oracle.truffle.r.runtime.nodes.RNode; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; @@ -53,6 +52,8 @@ import com.oracle.truffle.r.runtime.ops.na.NAProfile; @ImportStatic(RRuntime.class) public abstract class ConvertBooleanNode extends RNode { + protected static final int ATOMIC_VECTOR_LIMIT = 8; + private final NAProfile naProfile = NAProfile.create(); private final BranchProfile invalidElementCountBranch = BranchProfile.create(); @Child private ConvertBooleanNode recursiveConvertBoolean; @@ -120,10 +121,16 @@ public abstract class ConvertBooleanNode extends RNode { return RRuntime.raw2logical(value.getValue()); } - private void checkLength(RAbstractVector value) { - if (value.getLength() != 1) { + @Specialization + protected byte doRLogical(RLogical value) { + // fast path for very common case, handled also in doAtomicVector + return value.getValue(); + } + + private void checkLength(int length) { + if (length != 1) { invalidElementCountBranch.enter(); - if (value.getLength() == 0) { + if (length == 0) { throw error(RError.Message.LENGTH_ZERO); } else { warning(RError.Message.LENGTH_GT_1); @@ -131,46 +138,33 @@ public abstract class ConvertBooleanNode extends RNode { } } - @Specialization - protected byte doIntVector(RAbstractIntVector value) { - checkLength(value); - return doInt(value.getDataAt(0)); - } - - @Specialization - protected byte doDoubleVector(RAbstractDoubleVector value) { - checkLength(value); - return doDouble(value.getDataAt(0)); - } - - @Specialization - protected byte doLogicalVector(RLogicalVector value) { - checkLength(value); - return doLogical(value.getDataAt(0)); - } - - @Specialization - protected byte doComplexVector(RComplexVector value) { - checkLength(value); - return doComplex(value.getDataAt(0)); - } - - @Specialization - protected byte doStringVector(RStringVector value) { - checkLength(value); - return doString(value.getDataAt(0)); - } - - @Specialization - protected byte doRawVector(RRawVector value) { - checkLength(value); - return RRuntime.raw2logical(value.getRawDataAt(0)); + @Specialization(guards = "access.supports(value)", limit = "ATOMIC_VECTOR_LIMIT") + protected byte doVector(RAbstractVector value, + @Cached("value.access()") VectorAccess access) { + SequentialIterator it = access.access(value); + checkLength(access.getLength(it)); + access.next(it); + switch (access.getType()) { + case Integer: + return doInt(access.getInt(it)); + case Double: + return doDouble(access.getDouble(it)); + case Raw: + return RRuntime.raw2logical(access.getRaw(it)); + case Logical: + return doLogical(access.getLogical(it)); + case Character: + return doString(access.getString(it)); + case Complex: + return doComplex(access.getComplex(it)); + default: + throw error(RError.Message.ARGUMENT_NOT_INTERPRETABLE_LOGICAL); + } } - @Specialization - protected byte doRawVector(RList value) { - checkLength(value); - throw error(RError.Message.ARGUMENT_NOT_INTERPRETABLE_LOGICAL); + @Specialization(replaces = "doVector") + protected byte doVectorGeneric(RAbstractVector value) { + return doVector(value, value.slowPathAccess()); } @Specialization(guards = "isForeignObject(obj)") @@ -192,8 +186,7 @@ public abstract class ConvertBooleanNode extends RNode { if (node instanceof ConvertBooleanNode) { return (ConvertBooleanNode) node; } - ConvertBooleanNode result = ConvertBooleanNodeGen.create(node.asRNode()); - return result; + return ConvertBooleanNodeGen.create(node.asRNode()); } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java index 5a9c503079500a97603e9ffdb595104feaa5314e..e4360fc26b053139d0a36d9b630d819376b5d0e1 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java @@ -74,6 +74,7 @@ public enum FastROptions { // Miscellaneous + IgnoreGraphicsCalls("Silently ignore unimplemented functions from graphics package", false), StartupTiming("Records and prints various timestamps during initialization", false); private final String help; @@ -92,6 +93,10 @@ public enum FastROptions { this.value = defaultValue; } + public boolean isBoolean() { + return isBoolean; + } + public boolean getBooleanValue() { assert isBoolean; Object v = value; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RLocale.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RLocale.java index ca3c2f2891a3037cdfdce93a036c7815f916b491..649cb26fc0696879100374bbf4f87c3dafba0364 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RLocale.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RLocale.java @@ -26,6 +26,9 @@ import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.StandardCharsets; import java.nio.charset.UnsupportedCharsetException; +import java.text.Collator; +import java.text.ParseException; +import java.text.RuleBasedCollator; import java.util.EnumMap; import java.util.Locale; @@ -55,6 +58,22 @@ public enum RLocale { this.name = "LC_" + name(); } + /** + * Returns the collator that should be used in order builtin or any place that should sort + * elements like order. The {@code Locale} should be retrieved from {@link RContext}. + */ + public static Collator getOrderCollator(Locale locale) { + Collator baseCollator = Collator.getInstance(locale); + String rules = ((RuleBasedCollator) baseCollator).getRules(); + Collator collator; + try { + collator = new RuleBasedCollator(rules.replaceAll("<'\u005f'", "<' '<'\u005f'")); + } catch (ParseException e) { + throw RInternalError.shouldNotReachHere(e); + } + return collator; + } + public static final class ContextStateImpl implements RContext.ContextState { private final EnumMap<RLocale, Locale> locales = new EnumMap<>(RLocale.class); private final EnumMap<RLocale, Charset> charsets = new EnumMap<>(RLocale.class); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java index ef5fb88f7cb06c6a13dc38ee7dccb3fecb069b6f..6245346502eefc5ea5f4f06ac514c3bfb18b58f1 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java @@ -146,7 +146,21 @@ public final class RAttributesLayout { public static DynamicObject copy(DynamicObject attrs) { assert isRAttributes(attrs); - return attrs.copy(attrs.getShape()); + DynamicObject result = attrs.copy(attrs.getShape()); + Shape shape = result.getShape(); + Property prop = shape.getLastProperty(); + while (prop != null) { + Object value = result.get(prop.getKey()); + if (value instanceof RSharingAttributeStorage) { + // There is no simple way to determine the correct reference count here and since + // the value will end up in two attributes collections, it will end up being shared + // most likely anyway. + ((RSharingAttributeStorage) value).makeSharedPermanent(); + } + shape = shape.getParent(); + prop = shape.getLastProperty(); + } + return result; } @TruffleBoundary diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java index 74765b994d27f012599f7653a36f5f8db5e39810..feced1226c62318a28ca3a25b8aea4e7361ba6f7 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java @@ -31,6 +31,7 @@ import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.Utils; +import com.oracle.truffle.r.runtime.data.RDataFactory.BaseVectorFactory; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess; @@ -270,16 +271,22 @@ public final class RPairList extends RSharingAttributeStorage implements RAbstra } @Override - public RSharingAttributeStorage copy() { - RPairList result = new RPairList(); + public RPairList copy() { + BaseVectorFactory dataFactory = RDataFactory.getInstance(); + RPairList curr = dataFactory.createPairList(); + RPairList result = curr; Object original = this; - while (!isNull(original)) { + while (true) { RPairList origList = (RPairList) original; - result.car = origList.car; - result.tag = origList.tag; - result.cdr = new RPairList(); - result = (RPairList) result.cdr; + curr.car = origList.car; + curr.tag = origList.tag; original = origList.cdr; + if (isNull(original)) { + curr.cdr = RNull.instance; + break; + } + curr.cdr = dataFactory.createPairList(); + curr = (RPairList) curr.cdr; } if (getAttributes() != null) { result.initAttributes(RAttributesLayout.copy(getAttributes())); 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 71c091e5f81de87352a639664a550ccea7237616..d1fe132529d3ad8f8f3dc5aa0036a2c8d7fcb8a2 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 @@ -7912,6 +7912,18 @@ name #{ as.symbol(as.symbol(123)) } `123` +##com.oracle.truffle.r.test.builtins.TestBuiltin_asvector.testAsVector# +#as.pairlist(as.pairlist(c(1,2,3))) +[[1]] +[1] 1 + +[[2]] +[1] 2 + +[[3]] +[1] 3 + + ##com.oracle.truffle.r.test.builtins.TestBuiltin_asvector.testAsVector# #as.vector(NULL, mode='pairlist') NULL @@ -12542,6 +12554,10 @@ NA NA NA NA NA NA NA NA Hey Hey Goodbye ##com.oracle.truffle.r.test.builtins.TestBuiltin_cat.testCat# #{ cat(sep=" ", "hello") } hello +##com.oracle.truffle.r.test.builtins.TestBuiltin_cat.testCat#Output.IgnoreErrorMessage# +#{ foo <- function(a,b) cat(a,b); foo(42,); } +Error in cat(a, b) : argument "b" is missing, with no default + ##com.oracle.truffle.r.test.builtins.TestBuiltin_cat.testCat# #{ m <- matrix(as.character(1:6), nrow=2) ; cat(m) } 1 2 3 4 5 6 @@ -46306,6 +46322,9 @@ $width [1] 80 +##com.oracle.truffle.r.test.builtins.TestBuiltin_options.testOptions# +#{ options(options(digits = 5)) } + ##com.oracle.truffle.r.test.builtins.TestBuiltin_options.testPrompt# #{ options(prompt="abc"); identical(getOption("prompt"), "abc") } [1] TRUE diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asvector.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asvector.java index dc1cca11115c51a77cc2705486842ad5efe60d80..67ae5bdcae30836bcd3ca9d60de8b0551b7ad765 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asvector.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_asvector.java @@ -444,6 +444,7 @@ public class TestBuiltin_asvector extends TestBase { assertEval("as.vector(NULL, mode='pairlist')"); assertEval("{ as.vector.cls <- function(x, mode) 42; as.vector(structure(c(1,2), class='cls')); }"); + assertEval("as.pairlist(as.pairlist(c(1,2,3)))"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_cat.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_cat.java index 9ca7dc6899c8d805079160dfc513149610750423..660ef10f72aa2f2384b33fa6715cbdeb20b35515 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_cat.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_cat.java @@ -78,6 +78,7 @@ public class TestBuiltin_cat extends TestBase { assertEval("{ cat(c(\"a\", \"b\", \"c\"), \"d\", sep=c(\"-\", \"+\")) }"); assertEval("{ cat(paste(letters, 100* 1:26), fill = TRUE, labels = paste0(\"{\", 1:10, \"}:\"))}"); + assertEval(Output.IgnoreErrorMessage, "{ foo <- function(a,b) cat(a,b); foo(42,); }"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_options.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_options.java index 97b6fd5ca14a135fd97d82c11f6cbb9879929d9e..63411ea2a1c1617b0943cf10747ca73e969f2af1 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_options.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_options.java @@ -54,6 +54,7 @@ public class TestBuiltin_options extends TestBase { assertEval("{ getOption(NULL) }"); assertEval("{ getOption(character()) }"); assertEval("{ options(\"timeout\", \"width\") }"); + assertEval("{ options(options(digits = 5)) }"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/runtime/data/RPairListTests.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/runtime/data/RPairListTests.java index 04ecbe3bd7112ff3e75835fd90ad3820cbb48a41..0078010f55d99566a4efd72366ecf49df6a8b2bc 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/runtime/data/RPairListTests.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/runtime/data/RPairListTests.java @@ -24,6 +24,7 @@ package com.oracle.truffle.r.test.runtime.data; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; import java.util.Iterator; @@ -33,6 +34,7 @@ import com.oracle.truffle.r.runtime.data.RDataFactory; 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.RSharingAttributeStorage; public class RPairListTests { @Test @@ -52,4 +54,16 @@ public class RPairListTests { assertArrayEquals(new String[]{"name1", "name2"}, result.getNames().getReadonlyData()); assertArrayEquals(new Object[]{1, 2}, result.getDataWithoutCopying()); } + + @Test + public void testCopy() { + RPairList pairList = RDataFactory.createPairList(1, RDataFactory.createPairList(2, RNull.instance, "name2"), "name1"); + RPairList copy = pairList.copy(); + assertEquals(2, copy.getLength()); + assertEquals("name1", copy.getTag()); + assertEquals(1, copy.car()); + assertEquals("name2", ((RPairList) copy.cdr()).getTag()); + assertEquals(2, ((RPairList) copy.cdr()).car()); + assertSame(RNull.instance, ((RPairList) copy.cdr()).cdr()); + } }