diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java index 351de044af320e907df5f8260c5f0d94467fd47c..368c1913cb7cb8e7d524faba46b323aff1a80cba 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java @@ -146,7 +146,10 @@ public class MethodsListDispatch { @Cached("create()") GetFromEnvironment get, @Cached("createPckgAttrAccess()") GetFixedAttributeNode klassPckgAttrAccess, @Cached("createPckgAttrAccess()") GetFixedAttributeNode valPckgAttrAccess) { - String klassString = klass.getLength() == 0 ? RRuntime.STRING_NA : klass.getDataAt(0); + if (klass.getLength() == 0) { + return RNull.instance; + } + String klassString = klass.getDataAt(0); if (klassString.length() == 0) { throw error(RError.Message.ZERO_LENGTH_VARIABLE); @@ -175,6 +178,11 @@ public class MethodsListDispatch { protected RS4Object callGetClassFromCache(RS4Object klass, @SuppressWarnings("unused") REnvironment table) { return klass; } + + @Fallback + protected RS4Object callGetClassFromCache(@SuppressWarnings("unused") Object klass, @SuppressWarnings("unused") Object table) { + throw error(Message.GENERIC, "class should be either a character-string name or a class definition"); + } } public abstract static class R_set_method_dispatch extends RExternalBuiltinNode.Arg1 { diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/model.R b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/model.R index 861b58860338027a5e7f74cd9a069e81e87df93d..ccd97715e87943174ac560ac2b5e9b987887d9bd 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/model.R +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/model.R @@ -782,7 +782,7 @@ modelframe <- function(formula, rownames, variables, varnames, dots, dotnames, s } data[[j]] <- dots[[i]] - dataNames[[j]] <- paste("(", ss, ")") + dataNames[[j]] <- paste0("(", ss, ")") j <- j + 1L } } else { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java index 7d0f07f953e86d59cd84247b1ea38ecead885c08..d46dfb479ddc830fb0ab8417566968223d741f11 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Combine.java @@ -110,6 +110,7 @@ public abstract class Combine extends RBuiltinNode.Arg2 { static { Casts casts = new Casts(Combine.class); + casts.arg("...").mustBeValidVarArgs(); casts.arg("recursive").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(toBoolean()); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConditionFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConditionFunctions.java index 1f8bda07e41d5cdd96cf3d8a5afe52ad97307196..11cd9e372a10f85a97942c1217b7f3bc8540f890 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConditionFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConditionFunctions.java @@ -177,8 +177,15 @@ public class ConditionFunctions { } @Specialization - protected RNull signalCondition(RList condition, RAbstractStringVector msg, Object call) { - RErrorHandling.signalCondition(condition, msg.getDataAt(0), call); + protected RNull signalCondition(RList condition, Object msg, Object call) { + String msgStr = ""; + if (msg instanceof RAbstractStringVector) { + RAbstractStringVector msgVec = (RAbstractStringVector) msg; + if (msgVec.getLength() > 0) { + msgStr = ((RAbstractStringVector) msg).getDataAt(0); + } + } + RErrorHandling.signalCondition(condition, msgStr, call); return RNull.instance; } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java index dc2095ae8794313b5fc148758e190c29d890c622..aa1452b747501d5c5961cb34dc6525f40fb54ba4 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java @@ -56,7 +56,8 @@ public abstract class ListBuiltin extends RBuiltinNode.Arg1 { @CompilationFinal private RStringVector suppliedSignatureArgNames; static { - Casts.noCasts(ListBuiltin.class); + Casts casts = new Casts(ListBuiltin.class); + casts.arg("...").allowMissing().mustBeValidVarArgs(); } /** 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 c188ea4ce08a296a3bf0c5e8b7750583ecf8c6ea..21a515a3797c1dd614bac7faf3256b3d77142395 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 @@ -6,7 +6,7 @@ * Copyright (c) 1995, 1996, 1997 Robert Gentleman and Ross Ihaka * Copyright (c) 1995-2014, The R Core Team * Copyright (c) 2002-2008, The R Foundation - * Copyright (c) 2016, 2017, Oracle and/or its affiliates + * Copyright (c) 2016, 2018, Oracle and/or its affiliates * * All rights reserved. */ @@ -157,6 +157,7 @@ public abstract class Order extends RPrecedenceBuiltinNode { static { Casts casts = new Casts(Order.class); + casts.arg("...").mustBeValidVarArgs(); casts.arg("na.last").mustBe(numericValue(), INVALID_LOGICAL, "na.last").asLogicalVector().findFirst(); casts.arg("decreasing").defaultError(INVALID_LOGICAL, "decreasing").mustBe(numericValue()).asLogicalVector().findFirst().mustNotBeNA().map(toBoolean()); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java index c94d04d8208eb7b9d3e1ba38d17804c14935d6a8..5cee144e27517e118dbfadbaca305c550240a80f 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Repeat.java @@ -122,6 +122,8 @@ public abstract class Repeat extends RBuiltinNode.Arg2 { ARG_IDX_LENGHT_OUT = 1; ARG_IDX_EACH = 2; FORMALS = FormalArguments.createForBuiltin(new Object[]{1, RRuntime.INT_NA, 1}, signature); + + // Note: repeat is happy with empty arguments in varagrs } @Child private FastRInternalRepeat internalNode = FastRInternalRepeatNodeGen.create(); diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/MarkLookup.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/MarkLookup.java index 85f025e652bc82946a92f93e8ca7b8e8e0c62a5a..863eb2ddad35a9a697280c3434e4ac0059bbb546 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/MarkLookup.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/MarkLookup.java @@ -39,6 +39,7 @@ import com.oracle.truffle.r.nodes.builtin.casts.Filter.NotFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.NullFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.OrFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.RTypeFilter; +import com.oracle.truffle.r.nodes.builtin.casts.Filter.RVarArgsFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.TypeFilter; import com.oracle.truffle.r.nodes.builtin.casts.Mapper; import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapByteToBoolean; @@ -205,6 +206,11 @@ public final class MarkLookup implements PipelineStepVisitor<Map<String, Object> return visitFilter(filter, foundMarks); } + @Override + public Map<String, Object> visit(RVarArgsFilter filter, Map<String, Object> foundMarks) { + return visitFilter(filter, foundMarks); + } + // Mapper visitor public Map<String, Object> visitMapper(Mapper<?, ?> mapper, Map<String, Object> foundMarks) { diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/ResultTypesAnalyser.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/ResultTypesAnalyser.java index e383c823b2c2f056f42658fe55ae472b60c1a536..b4a80787b4de0bd7e86206e226cb173e74469f5b 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/ResultTypesAnalyser.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/ResultTypesAnalyser.java @@ -48,6 +48,7 @@ import com.oracle.truffle.r.nodes.builtin.casts.Filter.NotFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.NullFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.OrFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.RTypeFilter; +import com.oracle.truffle.r.nodes.builtin.casts.Filter.RVarArgsFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.TypeFilter; import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapByteToBoolean; import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapDoubleToInt; @@ -78,6 +79,7 @@ import com.oracle.truffle.r.nodes.unary.CastToAttributableNode; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.Utils; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RDouble; import com.oracle.truffle.r.runtime.data.RFunction; @@ -347,6 +349,12 @@ public class ResultTypesAnalyser extends ExecutionPathVisitor<TypeExpr> implemen return previous.lower(filter).and(NOT_NULL_NOT_MISSING); } + @Override + public TypeExpr visit(RVarArgsFilter filter, TypeExpr previous) { + TypeExpr res = atom(RArgsValuesAndNames.class); + return res; + } + @Override public TypeExpr visit(DoubleFilter filter, TypeExpr previous) { return previous.lower(filter); diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/SamplesCollector.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/SamplesCollector.java index 7b664e03c08569eabf3e5069026111d1162cd34c..ab5c7b59ec9fde261f505317cfa1dd62974ca82d 100644 --- a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/SamplesCollector.java +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/casts/SamplesCollector.java @@ -45,6 +45,7 @@ import com.oracle.truffle.r.nodes.builtin.casts.Filter.NotFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.NullFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.OrFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.RTypeFilter; +import com.oracle.truffle.r.nodes.builtin.casts.Filter.RVarArgsFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.TypeFilter; import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapByteToBoolean; import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapDoubleToInt; @@ -298,6 +299,13 @@ public class SamplesCollector extends ExecutionPathVisitor<Consumer<Object>> }; } + @Override + public Consumer<Object> visit(RVarArgsFilter filter, Consumer<Object> previous) { + return s -> { + previous.accept(s); + }; + } + @Override public Consumer<Object> visit(DoubleFilter filter, Consumer<Object> previous) { return s -> { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java index 195f31226ac25bb7f429413c86b00862be56b414..a28127dffde0e5a5f6f652e39468847c5cb5990e 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/CastBuilder.java @@ -63,6 +63,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.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RComplexVector; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -697,6 +698,16 @@ public final class CastBuilder { return new TypeFilter<>(Object.class); } + /** + * Valid {@link RArgsValuesAndNames} do not contain + * {@link com.oracle.truffle.r.runtime.data.REmpty} values. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static Filter<Object, RArgsValuesAndNames> validVarArgs() { + Filter f = integerValue().or(doubleValue()).or(logicalValue()); + return f; + } + @SuppressWarnings({"rawtypes", "unchecked"}) public static Filter<Object, RAbstractVector> numericValue() { Filter f = integerValue().or(doubleValue()).or(logicalValue()); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/Filter.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/Filter.java index 81f2bd6d2e554e5cc96182df66fa62d137fc023c..e5f12c84aa9774b0a543921ceedcac9befc727d1 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/Filter.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/Filter.java @@ -28,6 +28,7 @@ import com.oracle.truffle.r.nodes.builtin.ArgumentFilter; import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.FilterStep; import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep.MapStep; import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; @@ -82,6 +83,8 @@ public abstract class Filter<T, R extends T> { D visit(NullFilter filter, D previous); D visit(MissingFilter filter, D previous); + + D visit(RVarArgsFilter filter, D previous); } /** @@ -434,6 +437,14 @@ public abstract class Filter<T, R extends T> { } } + public static final class RVarArgsFilter extends Filter<Object, RArgsValuesAndNames> { + + @Override + public <D> D accept(FilterVisitor<D> visitor, D previous) { + return visitor.visit(this, previous); + } + } + public abstract static class DoubleFilter extends Filter<Double, Double> { public static final DoubleFilter IS_FINITE = new DoubleFilter() { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java index 7c93ac2ac850933505b1314c2293dc7129b0c3ae..97f0d2b7d220e4d3df638a8275558a07616b813a 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java @@ -46,6 +46,7 @@ import com.oracle.truffle.r.nodes.builtin.casts.Filter.NotFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.NullFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.OrFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.RTypeFilter; +import com.oracle.truffle.r.nodes.builtin.casts.Filter.RVarArgsFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.ResultForArg; import com.oracle.truffle.r.nodes.builtin.casts.Filter.TypeFilter; import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapByteToBoolean; @@ -82,6 +83,7 @@ import com.oracle.truffle.r.nodes.unary.FilterNode; import com.oracle.truffle.r.nodes.unary.FindFirstNodeGen; import com.oracle.truffle.r.nodes.unary.MapNode; import com.oracle.truffle.r.nodes.unary.NonNANodeGen; +import com.oracle.truffle.r.nodes.unary.RVarArgsFilterNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; @@ -197,6 +199,9 @@ public final class PipelineToCastNode { @Override public CastNode visit(FilterStep<?, ?> step, CastNode previous) { + if (step.getFilter() instanceof RVarArgsFilter) { + return RVarArgsFilterNode.create(); + } @SuppressWarnings("unchecked") ArgumentFilter<Object, Object> filter = (ArgumentFilter<Object, Object>) ArgumentFilterFactoryImpl.INSTANCE.createFilter(step.getFilter()); MessageData msg = getDefaultIfNull(step.getMessage(), step.isWarning()); @@ -260,6 +265,7 @@ public final class PipelineToCastNode { @Override public CastNode visit(MapIfStep<?, ?> step, CastNode previous) { + assert !(step.getFilter() instanceof RVarArgsFilter) : "mapIf not yet implemented for RVarArgsFilter"; @SuppressWarnings("unchecked") ArgumentFilter<Object, Object> condition = (ArgumentFilter<Object, Object>) ArgumentFilterFactoryImpl.INSTANCE.createFilter(step.getFilter()); CastNode trueCastNode = PipelineToCastNode.convert(null, step.getTrueBranch(), this); @@ -410,6 +416,11 @@ public final class PipelineToCastNode { return filter.acceptOperation(this, null); } + @Override + public ArgumentFilter<?, ?> visit(RVarArgsFilter filter, ArgumentFilter<?, ?> previous) { + throw RInternalError.shouldNotReachHere("This filter should be handled separately as it has its own node."); + } + @Override public ArgumentFilter<?, ?> visit(DoubleFilter filter, ArgumentFilter<?, ?> previous) { return filter.acceptOperation(this, null); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardedValuesAnalyser.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardedValuesAnalyser.java index 631c6d86853121b2f68338f4823e972b139dccee..5d06fa101bf260572e30b52370c5506118466bec 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardedValuesAnalyser.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/analysis/ForwardedValuesAnalyser.java @@ -42,6 +42,7 @@ import com.oracle.truffle.r.nodes.builtin.casts.Filter.NotFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.NullFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.OrFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.RTypeFilter; +import com.oracle.truffle.r.nodes.builtin.casts.Filter.RVarArgsFilter; import com.oracle.truffle.r.nodes.builtin.casts.Filter.TypeFilter; import com.oracle.truffle.r.nodes.builtin.casts.Mapper; import com.oracle.truffle.r.nodes.builtin.casts.Mapper.MapByteToBoolean; @@ -263,6 +264,11 @@ public final class ForwardedValuesAnalyser implements PipelineStepVisitor<Forwar return new ForwardingAnalysisResult().blockAll(); } + @Override + public ForwardingAnalysisResult visit(RVarArgsFilter filter, ForwardingAnalysisResult previous) { + return new ForwardingAnalysisResult().blockAll(); + } + @Override public ForwardingAnalysisResult visit(DoubleFilter filter, @SuppressWarnings("hiding") ForwardingAnalysisResult previous) { return new ForwardingAnalysisResult().blockAll().setForwardedType(RType.Double, UNKNOWN); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java index d5c603ad89d8981e1a9310b0f4714cb151bc8246..49514f0a333d6b05f66b2b17e9fa4d6f6a54b7d3 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/fluent/InitialPhaseBuilder.java @@ -24,9 +24,11 @@ package com.oracle.truffle.r.nodes.builtin.casts.fluent; import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; import com.oracle.truffle.r.nodes.builtin.casts.Filter; +import com.oracle.truffle.r.nodes.builtin.casts.Filter.RVarArgsFilter; import com.oracle.truffle.r.nodes.builtin.casts.Mapper; import com.oracle.truffle.r.nodes.builtin.casts.PipelineStep; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RComplex; @@ -65,6 +67,14 @@ public class InitialPhaseBuilder<T> extends ArgCastBuilder<T, InitialPhaseBuilde return (InitialPhaseBuilder<S>) this; } + /** + * Valid {@link com.oracle.truffle.r.runtime.data.RArgsValuesAndNames} does not contain any + * {@link com.oracle.truffle.r.runtime.data.REmpty} values. + */ + public void mustBeValidVarArgs() { + pipelineBuilder().appendMustBeStep(new RVarArgsFilter(), Message.INVALID_ARG_TYPE, new Object[0]); + } + public <S extends T> InitialPhaseBuilder<S> mustBe(Class<S> cls) { mustBe(Predef.instanceOf(cls)); return (InitialPhaseBuilder<S>) this; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastNode.java index 76a270746e54b48134ce30be078ebb595813960e..5f3ea354eb9d346c8cf74d39aaa81e0b0d1abfc2 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastNode.java @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.function.Function; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.r.nodes.builtin.casts.MessageData; import com.oracle.truffle.r.runtime.RError; @@ -36,7 +37,7 @@ import com.oracle.truffle.r.runtime.RError; */ public abstract class CastNode extends UnaryNode { - private static boolean isTesting = false; + @CompilationFinal private static boolean isTesting = false; private static String lastWarning; private final ValueProfile classProfile = ValueProfile.createClassProfile(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/RVarArgsFilterNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/RVarArgsFilterNode.java new file mode 100644 index 0000000000000000000000000000000000000000..8f495e7951be73dee8581395a14c72fda55e62e2 --- /dev/null +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/RVarArgsFilterNode.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018, 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 3 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 3 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 + * 3 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.unary; + +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.nodes.ExplodeLoop; +import com.oracle.truffle.api.profiles.BranchProfile; +import com.oracle.truffle.r.nodes.builtin.casts.MessageData; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.data.REmpty; + +public abstract class RVarArgsFilterNode extends CastNode { + + public static RVarArgsFilterNode create() { + return RVarArgsFilterNodeGen.create(); + } + + @ExplodeLoop + @Specialization(guards = "args.getLength() == cachedLen") + protected Object cached(RArgsValuesAndNames args, + @Cached("create()") BranchProfile errorProfile, + @Cached("args.getLength()") int cachedLen) { + Object[] vals = args.getArguments(); + for (int i = 0; i < cachedLen; i++) { + if (vals[i] == REmpty.instance) { + errorProfile.enter(); + throw handleArgumentError(args, new MessageData(Message.ARGUMENT_EMPTY, i + 1)); + } + } + return args; + } + + @Specialization(replaces = "cached") + protected Object generic(RArgsValuesAndNames args, + @Cached("create()") BranchProfile errorProfile) { + Object[] vals = args.getArguments(); + for (int i = 0; i < vals.length; i++) { + if (vals[i] == REmpty.instance) { + errorProfile.enter(); + throw handleArgumentError(args, new MessageData(Message.ARGUMENT_EMPTY, i)); + } + } + return args; + } + + @Fallback + @TruffleBoundary + protected Object others(Object obj) { + String actualCls = obj == null ? "null" : obj.getClass().getSimpleName(); + throw RInternalError.shouldNotReachHere(String.format("RVarArgsFilter should be used only for %s, but used for %s", RArgsValuesAndNames.class.getSimpleName(), actualCls)); + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java index 4fdacb4c39c6451897273f9e551a897343fcc8a7..429472214591b80b8cc19ba5bb3dd7fc886a749e 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java @@ -42,8 +42,10 @@ public final class ArgumentsSignature implements Iterable<String> { * argument can be provided with a name or without a name, or it may have default value, but * without any actual value provided by the caller. This is the case for {@code UNMATCHED}. Use * {@link #isUnmatched(int)} for checking if argument is unmatched. + * + * Note we intentionally use invalid argument name. */ - public static final String UNMATCHED = new String(); + public static final String UNMATCHED = "^"; public static final String VARARG_NAME = "..."; public static final int[] EMPTY_VARARGS_INDEXES = new int[0]; public static final int NO_VARARG = -1; 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 3b74920c86137021bfc26201ea47fd478b68b21a..afbded810c429dad201df72fa835da7e3f736857 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 @@ -753,6 +753,9 @@ public class RDeparse { } needsParens = mainOp.prec > arginfo.prec || (mainOp.prec == arginfo.prec && isLeft == mainOp.rightassoc); break; + case FUNCTION: + needsParens = true; + break; default: break; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java index 3544f269c745fdd94f4727cde5c57a5533e51eb1..9762df621c5343f76c61707e1d479458f11752de 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java @@ -692,12 +692,17 @@ public final class RContext { // methods information assert contextKind != ContextKind.SHARE_NOTHING; assert parentContext != null; - return parentContext.getPrimitiveMethodsInfo(); + return parentContext.getPrimitiveMethodsInfoWithBoundary(); } else { return primitiveMethodsInfo; } } + @TruffleBoundary + private PrimitiveMethodsInfo getPrimitiveMethodsInfoWithBoundary() { + return getPrimitiveMethodsInfo(); + } + /** * This is a static property of the implementation and not context-specific. */ 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 b681e69d54a7af40945aaa50974256249e95ef7e..6f8d2fad0edd23d27debb3ae8259021f7fe3cf02 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 @@ -718,7 +718,11 @@ public final class RPairList extends RSharingAttributeStorage implements RAbstra } else { String[] signature = new String[length - 1]; for (int i = 0; i < names.getLength() && i < (length - 1); i++) { - signature[i] = names.getDataAt(i + 1); + String name = names.getDataAt(i + 1); + if (name != null && !name.isEmpty()) { + // in signatures, null is designated for unnamed arguments + signature[i] = name; + } } return ArgumentsSignature.get(signature); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/EvaluatedArgumentsVisitor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/EvaluatedArgumentsVisitor.java index 84bc84d1a51b2cc55060a755c005508300f37c84..890ffe858a553c17f8763fc1b65fd9810da06304 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/EvaluatedArgumentsVisitor.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/EvaluatedArgumentsVisitor.java @@ -80,7 +80,8 @@ public final class EvaluatedArgumentsVisitor extends RSyntaxVisitor<Info> { "print", "length", "rep", "inherits", "min", "max", "matrix", "table", "is.array", "is.element", "is.character", "exp", "all", "pmin", "pmax", "as.numeric", "proc.time", "as.integer", "as.character", "as.matrix", ".Call", "sum", "order", "rev", "integer", "double", "as.numeric", "as.list", "as.integer", ".Call", ".FastR", "unname", "log", "lgamma", "sin", "cos", "tan", "exp", "log", "expm1", "sinh", "sinpi", "cosh", "cospi", "tanh", "tanpi", "asin", "asinh", "acos", "acosh", "atan", "atanh", "+", "-", - "*", "/", "%%", "^", ":", ">=", ">", "<=", "<", "==", "!=", "||", "|", "&&", "&", "!", "%o%", "%*%", "%/%", "%in%", "{", "for", "while", "repeat", "if", "attributes", "attr")); + "*", "/", "%%", "^", ":", ">=", ">", "<=", "<", "==", "!=", "||", "|", "&&", "&", "!", "%o%", "%*%", "%/%", "%in%", "{", "for", "while", "repeat", "if", "attributes", "attr", + "nchar")); private EvaluatedArgumentsVisitor() { // private constructor 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 c0d15c5eb83077efeb6892b339c0b28dbaee9538..b3c2f7f7449a8729438da5e84dc78c9b66529d7e 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 @@ -11726,6 +11726,10 @@ NULL Warning message: In body(argv[[1]]) : argument is not a function +##com.oracle.truffle.r.test.builtins.TestBuiltin_c.testCombine# +#c(1,2,) +Error in c(1, 2, ) : argument 3 is empty + ##com.oracle.truffle.r.test.builtins.TestBuiltin_c.testCombine# #c(as.expression(1)) expression(1) @@ -35570,6 +35574,10 @@ numeric(0) Warning message: In do.call("lgamma", argv) : value out of range in 'lgamma' +##com.oracle.truffle.r.test.builtins.TestBuiltin_list.testList# +#list(1,2,3,) +Error in list(1, 2, 3, ) : argument 4 is empty + ##com.oracle.truffle.r.test.builtins.TestBuiltin_list.testList# #{ list(1, b=2) } [[1]] @@ -53109,6 +53117,10 @@ attr(,"useBytes") [1] " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " [20] " " +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep#Output.IgnoreWarningMessage# +#rep(3, 4,) +[1] 3 3 3 3 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep.testRep# #rep(x<-42) [1] 42 @@ -74719,6 +74731,10 @@ In matrix(7:1, nrow = 5) : [4,] [5,] +##com.oracle.truffle.r.test.builtins.TestBuiltin_switch.testSwitch#Ignored.Unimplemented# +#switch('q', a=42,) +Error: argument is missing, with no default + ##com.oracle.truffle.r.test.builtins.TestBuiltin_switch.testSwitch# #{ a <- NULL ; switch(mode(a), NULL="naught") } [1] "naught" @@ -163464,6 +163480,14 @@ data frame with 0 columns and 0 rows 9 m 8 c 10 f 9 c +##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelFrameWithWeights# +#model.frame(formula = cyl ~ disp, data = mtcars[1:4,], weights = seq_len(nrow(mtcars[1:4,]))) + cyl disp (weights) +Mazda RX4 6 160 1 +Mazda RX4 Wag 6 160 2 +Datsun 710 4 108 3 +Hornet 4 Drive 6 258 4 + ##com.oracle.truffle.r.test.library.stats.TestFormulae.testModelMatrix# #{y<-0:9;z<-1:10;k<-2:11;w<-3:12;m<-4:13;u<-5:14;v<-6:15;; model.matrix(model.frame(terms.formula(u~z*k+w*m))) } (Intercept) z k w m z:k w:m diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java index 974a0d5f7ba803258b3236f09f5c6ecdfc3a8532..b28588066de848ba0f5d48c68fdd6c2e6f50070c 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java @@ -554,6 +554,8 @@ public class TestBuiltin_c extends TestBase { assertEval("c(as.symbol(1), as.symbol(1))"); assertEval("{ setClass('foo', representation(bar = 'ANY')); c(new('foo', bar=1)) }"); assertEval("{ setClass('foo', representation(bar = 'ANY')); c(new('foo', bar=1), new('foo', bar=1)) }"); + + assertEval("c(1,2,)"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java index 7b5ffe64deb8b49683d103d3d20bccf3a60bdb27..2183c7b39eac0156e4fbef7c2207e408f3831ffa 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.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. */ @@ -366,5 +366,7 @@ public class TestBuiltin_list extends TestBase { assertEval("{ x<-list(y=1, 2); c(42, a=x) }"); assertEval("{ x<-list(y=1, 2); c(a=x, c(z=7,42)) }"); assertEval("{ x<-list(y=1, 2); c(a=x, c(y=7,z=42)) }"); + + assertEval("list(1,2,3,)"); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep.java index 01f86871e8cad4e923c8c993ea1f46017d932923..a6aaf4e37581c2dbc96e97f65b52c3146241e47f 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep.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. */ @@ -241,5 +241,8 @@ public class TestBuiltin_rep extends TestBase { assertEval("{ rep(paste0('hello', 1:10), 1:10) }"); assertEval("rep(' ', 20L, collapse = ' ')"); + + // FIXME: should not print the warnings if empty args occur in '...' + assertEval(Output.IgnoreWarningMessage, "rep(3, 4,)"); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_switch.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_switch.java index 823c928e5a0ef05c74cdd9e18ff79237265b29bd..299276200c202ffe514b31de21a42da355c484f3 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_switch.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_switch.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. */ @@ -49,6 +49,8 @@ public class TestBuiltin_switch extends TestBase { assertEval("{ a <- NULL ; switch(mode(a), NULL=) }"); assertEval(Output.IgnoreErrorContext, "{ x <- \"!\"; v <- switch(x, v77, \"<=\" =, \"<\" =, \">\" = 99, v55)}"); assertEval("{ x <- \"!\"; v <- switch(x, \"\"=v77, \"<=\" =, \"<\" =, \">\" = 99, v55)}"); + // FIXME: swicth does not check for REmpty + assertEval(Ignored.Unimplemented, "switch('q', a=42,)"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestFormulae.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestFormulae.java index f2d4ab6beb53ac8fca8e9ce86e6c3355877b0ecb..d3a56d60ae5847319716f77e6f77ae564a4bae7d 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestFormulae.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestFormulae.java @@ -115,4 +115,9 @@ public class TestFormulae extends TestBase { public void testDotWithNoFramenames() { assertEval(Output.IgnoreErrorContext, "terms.formula(x ~ .^4)"); } + + @Test + public void testModelFrameWithWeights() { + assertEval("model.frame(formula = cyl ~ disp, data = mtcars[1:4,], weights = seq_len(nrow(mtcars[1:4,])))"); + } }