From c7a7b4ee6228d12663c326c2986de30fb3594fdd Mon Sep 17 00:00:00 2001 From: stepan <stepan.sindelar@oracle.com> Date: Thu, 19 Apr 2018 14:49:44 +0200 Subject: [PATCH] Do not allow empty in '...' for most builtins This adds mustBeValidVarArgs method to the cast pipeline --- .../truffle/r/nodes/builtin/base/Combine.java | 1 + .../r/nodes/builtin/base/ListBuiltin.java | 3 +- .../truffle/r/nodes/builtin/base/Order.java | 3 +- .../truffle/r/nodes/builtin/base/Repeat.java | 2 + .../truffle/r/nodes/casts/MarkLookup.java | 6 ++ .../r/nodes/casts/ResultTypesAnalyser.java | 8 ++ .../r/nodes/casts/SamplesCollector.java | 8 ++ .../truffle/r/nodes/builtin/CastBuilder.java | 11 +++ .../truffle/r/nodes/builtin/casts/Filter.java | 11 +++ .../builtin/casts/PipelineToCastNode.java | 11 +++ .../analysis/ForwardedValuesAnalyser.java | 6 ++ .../casts/fluent/InitialPhaseBuilder.java | 10 +++ .../truffle/r/nodes/unary/CastNode.java | 3 +- .../r/nodes/unary/RVarArgsFilterNode.java | 77 +++++++++++++++++++ .../truffle/r/test/ExpectedTestOutput.test | 16 ++++ .../r/test/builtins/TestBuiltin_c.java | 2 + .../r/test/builtins/TestBuiltin_list.java | 4 +- .../r/test/builtins/TestBuiltin_rep.java | 5 +- .../r/test/builtins/TestBuiltin_switch.java | 4 +- 19 files changed, 185 insertions(+), 6 deletions(-) create mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/RVarArgsFilterNode.java 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 7d0f07f953..d46dfb479d 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/ListBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java index dc2095ae87..aa1452b747 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 c188ea4ce0..21a515a379 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 c94d04d820..5cee144e27 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 85f025e652..863eb2ddad 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 e383c823b2..b4a80787b4 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 7b664e03c0..ab5c7b59ec 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 195f31226a..a28127dffd 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 81f2bd6d2e..e5f12c84aa 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 7c93ac2ac8..97f0d2b7d2 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 631c6d8685..5d06fa101b 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 d5c603ad89..49514f0a33 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 76a270746e..5f3ea354eb 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 0000000000..8f495e7951 --- /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.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index a589460550..5ef348d3f9 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]] @@ -53097,6 +53105,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 @@ -74707,6 +74719,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" 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 974a0d5f7b..b28588066d 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 7b5ffe64de..2183c7b39e 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 01f86871e8..a6aaf4e375 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 823c928e5a..299276200c 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 -- GitLab