From 01bfe05f661461f8c8ca04d1898fc31893f97c37 Mon Sep 17 00:00:00 2001 From: Adam Welc <adam.welc@oracle.com> Date: Mon, 10 Nov 2014 17:19:06 +0100 Subject: [PATCH] Further enhancements to factor and data frame support. --- .../r/nodes/builtin/base/AnyDuplicated.java | 20 ++-- .../r/nodes/builtin/base/AsDouble.java | 6 ++ .../r/nodes/builtin/base/AsInteger.java | 3 +- .../r/nodes/builtin/base/AsLogical.java | 4 +- .../truffle/r/nodes/builtin/base/Format.java | 14 ++- .../truffle/r/nodes/builtin/base/IsNA.java | 6 ++ .../r/nodes/builtin/base/IsTypeFunctions.java | 6 ++ .../nodes/builtin/base/PrettyPrinterNode.java | 36 +++++++- .../r/nodes/builtin/base/Structure.java | 7 +- .../r/nodes/builtin/base/TypeConvert.java | 3 +- .../nodes/builtin/base/UpdateAttributes.java | 15 +-- .../nodes/builtin/base/UpdateStorageMode.java | 2 +- .../access/array/read/AccessArrayNode.java | 3 +- .../array/write/UpdateArrayHelperNode.java | 2 +- .../r/nodes/binary/BinaryBooleanNode.java | 92 +++++++++---------- .../truffle/r/nodes/binary/CastTypeNode.java | 16 ++++ .../r/nodes/unary/CastLogicalNode.java | 14 +++ .../oracle/truffle/r/runtime/RRuntime.java | 2 + .../oracle/truffle/r/runtime/RSerialize.java | 2 +- .../truffle/r/runtime/data/RAttributable.java | 7 +- .../truffle/r/runtime/data/RDataFactory.java | 4 +- .../truffle/r/runtime/data/RFactor.java | 11 ++- .../truffle/r/runtime/data/RVector.java | 19 +++- .../RFactorToStringVectorClosure.java | 15 ++- .../truffle/r/test/ExpectedTestOutput.test | 53 +++++++++++ .../oracle/truffle/r/test/all/AllTests.java | 60 ++++++++++++ .../r/test/simple/TestSimpleBuiltins.java | 12 +++ .../r/test/simple/TestSimpleDataFrames.java | 5 + 28 files changed, 342 insertions(+), 97 deletions(-) diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java index 6a090aa209..9f26ab728d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyDuplicated.java @@ -69,24 +69,24 @@ public abstract class AnyDuplicated extends RBuiltinNode { } @Specialization(guards = {"!empty"}) - protected int anyDuplicatedFromStart(VirtualFrame frame, RAbstractVector x, RAbstractVector incomparables, byte fromLast) { + protected int anyDuplicatedFromStart(VirtualFrame frame, RAbstractContainer x, RAbstractContainer incomparables, byte fromLast) { initChildren(); RType xType = typeof.execute(frame, x); if (fromLastProfile.profile(fromLast == RRuntime.LOGICAL_TRUE)) { - return getIndexFromLast(x, (RAbstractVector) (castTypeNode.execute(frame, incomparables, xType))); + return getIndexFromLast(x, (RAbstractContainer) (castTypeNode.execute(frame, incomparables, xType))); } else { - return getIndexFromStart(x, (RAbstractVector) (castTypeNode.execute(frame, incomparables, xType))); + return getIndexFromStart(x, (RAbstractContainer) (castTypeNode.execute(frame, incomparables, xType))); } } @SuppressWarnings("unused") @Specialization(guards = "empty") - protected int anyDuplicatedEmpty(RAbstractVector x, RAbstractVector incomparables, byte fromLast) { + protected int anyDuplicatedEmpty(RAbstractContainer x, RAbstractContainer incomparables, byte fromLast) { return 0; } @TruffleBoundary - private static int getIndexFromStart(RAbstractVector x, RAbstractVector incomparables) { + private static int getIndexFromStart(RAbstractContainer x, RAbstractContainer incomparables) { HashSet<Object> incompContents = new HashSet<>(); HashSet<Object> vectorContents = new HashSet<>(); for (int i = 0; i < incomparables.getLength(); i++) { @@ -106,7 +106,7 @@ public abstract class AnyDuplicated extends RBuiltinNode { } @TruffleBoundary - private static int getIndexFromStart(RAbstractVector x) { + private static int getIndexFromStart(RAbstractContainer x) { HashSet<Object> vectorContents = new HashSet<>(); vectorContents.add(x.getDataAtAsObject(0)); for (int i = 1; i < x.getLength(); i++) { @@ -120,7 +120,7 @@ public abstract class AnyDuplicated extends RBuiltinNode { } @TruffleBoundary - public static int getIndexFromLast(RAbstractVector x, RAbstractVector incomparables) { + public static int getIndexFromLast(RAbstractContainer x, RAbstractContainer incomparables) { HashSet<Object> incompContents = new HashSet<>(); HashSet<Object> vectorContents = new HashSet<>(); for (int i = 0; i < incomparables.getLength(); i++) { @@ -140,7 +140,7 @@ public abstract class AnyDuplicated extends RBuiltinNode { } @TruffleBoundary - private static int getIndexFromLast(RAbstractVector x) { + private static int getIndexFromLast(RAbstractContainer x) { HashSet<Object> vectorContents = new HashSet<>(); vectorContents.add(x.getDataAtAsObject(x.getLength() - 1)); for (int i = x.getLength() - 2; i >= 0; i--) { @@ -154,11 +154,11 @@ public abstract class AnyDuplicated extends RBuiltinNode { } @SuppressWarnings("unused") - protected boolean isIncomparable(RAbstractVector x, byte incomparables, byte fromLast) { + protected boolean isIncomparable(RAbstractContainer x, byte incomparables, byte fromLast) { return incomparables == RRuntime.LOGICAL_TRUE; } - protected boolean empty(RAbstractVector x) { + protected boolean empty(RAbstractContainer x) { return x.getLength() == 0; } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java index 096951c0d0..d60ee33042 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsDouble.java @@ -137,4 +137,10 @@ public abstract class AsDouble extends RBuiltinNode { controlVisibility(); return castDoubleVector(frame, vector); } + + @Specialization + protected RDoubleVector asDouble(VirtualFrame frame, RFactor vector) { + return asDouble(frame, vector.getVector()); + } + } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java index ff874767f2..547ba5daa6 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsInteger.java @@ -133,8 +133,7 @@ public abstract class AsInteger extends RBuiltinNode { @Specialization protected RIntVector asInteger(RFactor factor) { - controlVisibility(); - return factor.getVector(); + return asInteger(factor.getVector()); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java index 2a18bb988b..b50cb5243b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsLogical.java @@ -101,8 +101,8 @@ public abstract class AsLogical extends RBuiltinNode { } @Specialization - protected RLogicalVector asLogical(VirtualFrame frame, RAbstractVector vector) { + protected RLogicalVector asLogical(VirtualFrame frame, RAbstractContainer container) { controlVisibility(); - return castLogicalVector(frame, vector); + return castLogicalVector(frame, container); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java index 4e0c8e5e25..47f8b92b2b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Format.java @@ -167,7 +167,7 @@ public abstract class Format extends RBuiltinNode { @SuppressWarnings("unused") @Specialization(guards = "!wrongArgs") - protected RStringVector format(VirtualFrame frame, RAbstractIntVector value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, + protected RStringVector format(RAbstractIntVector value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, RLogicalVector naEncodeVec, RAbstractVector sciVec) { if (value.getLength() == 0) { return RDataFactory.createEmptyStringVector(); @@ -248,12 +248,18 @@ public abstract class Format extends RBuiltinNode { @SuppressWarnings("unused") @Specialization(guards = "!wrongArgs") - protected RStringVector format(VirtualFrame frame, RStringVector value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, - RLogicalVector naEncodeVec, RAbstractVector sciVec) { + protected RStringVector format(RStringVector value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, RLogicalVector naEncodeVec, + RAbstractVector sciVec) { // TODO: implement full semantics return value; } + @Specialization(guards = "!wrongArgs") + protected RStringVector format(RFactor value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, RLogicalVector naEncodeVec, + RAbstractVector sciVec) { + return format(value.getVector(), trimVec, digitsVec, nsmallVec, widthVec, justifyVec, naEncodeVec, sciVec); + } + // TruffleDSL bug - should not need multiple guards here protected boolean wrongArgsObject(@SuppressWarnings("unused") Object value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, RLogicalVector naEncodeVec, RAbstractVector sciVec) { @@ -288,7 +294,7 @@ public abstract class Format extends RBuiltinNode { return false; } - protected boolean wrongArgs(RAbstractVector value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, RLogicalVector naEncodeVec, + protected boolean wrongArgs(RAbstractContainer value, RLogicalVector trimVec, RIntVector digitsVec, RIntVector nsmallVec, RIntVector widthVec, RIntVector justifyVec, RLogicalVector naEncodeVec, RAbstractVector sciVec) { return wrongArgsObject(value, trimVec, digitsVec, nsmallVec, widthVec, justifyVec, naEncodeVec, sciVec); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java index c330411359..da6df56c0b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java @@ -146,4 +146,10 @@ public abstract class IsNA extends RBuiltinNode { controlVisibility(); return RRuntime.LOGICAL_FALSE; } + + @Specialization + protected RLogicalVector isNA(RFactor value) { + return isNA(value.getVector()); + } + } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java index 89570da0f4..4af928c4d3 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java @@ -103,6 +103,12 @@ public class IsTypeFunctions { return arg.getElementClass() == Object.class; } + @Specialization + protected byte isAtomic(RFactor arg) { + controlVisibility(); + return RRuntime.LOGICAL_TRUE; + } + } @RBuiltin(name = "is.call", kind = PRIMITIVE, parameterNames = {"x"}) diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java index 96e572bfb2..cd3c4edb71 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrettyPrinterNode.java @@ -28,6 +28,7 @@ import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.frame.FrameInstance.FrameAccess; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.Node.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.r.nodes.*; import com.oracle.truffle.r.nodes.access.ConstantNode; @@ -41,8 +42,10 @@ import com.oracle.truffle.r.nodes.function.*; import com.oracle.truffle.r.runtime.*; import com.oracle.truffle.r.runtime.data.*; import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute; +import com.oracle.truffle.r.runtime.data.closures.*; import com.oracle.truffle.r.runtime.data.model.*; import com.oracle.truffle.r.runtime.env.*; +import com.oracle.truffle.r.runtime.ops.na.*; @SuppressWarnings("unused") @NodeChildren({@NodeChild(value = "operand", type = RNode.class), @NodeChild(value = "listElementName", type = RNode.class), @NodeChild(value = "quote", type = RNode.class), @@ -518,9 +521,13 @@ public abstract class PrettyPrinterNode extends RNode { resultBuilder.append(vector.getLength() - maxPrint); resultBuilder.append(" entries ]"); } - RAttributes attributes = vector.getAttributes(); - if (attributes != null) { - resultBuilder.append(printAttributes(vector, attributes)); + if (!(vector instanceof RFactorToStringVectorClosure)) { + // it's a bit of a hack, but factors are meant to be printed using the S3 function + // anyway - the idea is to suppress attribute printing for factors nested in lists + RAttributes attributes = vector.getAttributes(); + if (attributes != null) { + resultBuilder.append(printAttributes(vector, attributes)); + } } return builderToString(resultBuilder); } @@ -1014,6 +1021,8 @@ public abstract class PrettyPrinterNode extends RNode { @Child private PrettyPrinterNode prettyPrinter; + private final NACheck naCheck = NACheck.create(); + private void initCast(Object listElementName) { if (prettyPrinter == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -1121,6 +1130,27 @@ public abstract class PrettyPrinterNode extends RNode { return prettyPrintSingleElement(operand, listElementName, quote, right); } + // TODO: this should be handled by an S3 function + @TruffleBoundary + @Specialization + protected String prettyPrintListElement(RFactor operand, Object listElementName, byte quote, byte right) { + StringBuilder sb = new StringBuilder(prettyPrintSingleElement(RClosures.createFactorToStringVector(operand, naCheck), listElementName, RRuntime.LOGICAL_FALSE, right)); + sb.append("\nLevels:"); + Object attr = operand.getVector().getAttr(RRuntime.LEVELS_ATTR_KEY); + if (attr != null) { + if (attr instanceof String) { + sb.append(" "); + sb.append(attr.toString()); + } else { + RAbstractStringVector vec = (RAbstractStringVector) attr; + for (int i = 0; i < vec.getLength(); i++) { + sb.append(" "); + sb.append(vec.getDataAt(i)); + } + } + } + return sb.toString(); + } } @NodeChildren({@NodeChild(value = "operand", type = RNode.class), @NodeChild(value = "isQuoted", type = RNode.class)}) diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Structure.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Structure.java index 5b4deb5475..4ffba92c5d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Structure.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Structure.java @@ -75,16 +75,17 @@ public abstract class Structure extends RBuiltinNode { Object[] values = args.getValues(); String[] argNames = getSuppliedArgsNames(); validateArgNames(argNames); + RAbstractContainer res = obj; for (int i = 0; i < values.length; i++) { Object value = fixupValue(values[i]); String attrName = fixupAttrName(argNames[i + 1]); if (value == RNull.instance) { - obj.removeAttr(attrName); + res.removeAttr(attrName); } else { - obj.setAttr(attrName, value); + res = (RAbstractContainer) res.setAttr(attrName, value); } } - return obj; + return res; } private Object fixupValue(Object value) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TypeConvert.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TypeConvert.java index 0c2b3c7a78..b00fa7944d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TypeConvert.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/TypeConvert.java @@ -164,8 +164,7 @@ public abstract class TypeConvert extends RBuiltinNode { } RIntVector res = RDataFactory.createIntVector(data, complete); res.setLevels(RDataFactory.createStringVector(levelsArray, RDataFactory.COMPLETE_VECTOR)); - RVector.setClassAttr(res, RDataFactory.createStringVector("factor"), null, null); - return RDataFactory.createFactor(res); + return RVector.setClassAttr(res, RDataFactory.createStringVector("factor"), null, null); } } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java index e057dd8e85..196a22df5b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java @@ -89,7 +89,7 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode { } @Specialization - protected RAbstractVector updateAttributes(VirtualFrame frame, RAbstractContainer container, RList list) { + protected RAbstractContainer updateAttributes(VirtualFrame frame, RAbstractContainer container, RList list) { controlVisibility(); Object listNamesObject = list.getNames(); if (listNamesObject == null || listNamesObject == RNull.instance) { @@ -97,6 +97,7 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode { } RStringVector listNames = (RStringVector) listNamesObject; RVector resultVector = container.materializeNonSharedVector(); + RAbstractContainer res = resultVector; if (numAttributesProfile.profile(list.getLength() == 0)) { resultVector.resetAllAttributes(true); } else { @@ -113,9 +114,9 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode { // set the dim attribute first setDimAttribute(frame, resultVector, list); // set the remaining attributes in order - setRemainingAttributes(frame, container, resultVector, list); + res = setRemainingAttributes(frame, container, resultVector, list); } - return resultVector; + return res; } @TruffleBoundary @@ -155,10 +156,11 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode { } @ExplodeLoop - private void setRemainingAttributes(VirtualFrame virtualFrame, RAbstractContainer container, RVector resultVector, RList sourceList) { + private RAbstractContainer setRemainingAttributes(VirtualFrame virtualFrame, RAbstractContainer container, RVector resultVector, RList sourceList) { RStringVector listNames = (RStringVector) sourceList.getNames(); int length = sourceList.getLength(); assert length > 0 : "Length should be > 0 for ExplodeLoop"; + RAbstractContainer res = resultVector; for (int i = 0; i < sourceList.getLength(); i++) { Object value = sourceList.getDataAt(i); String attrName = listNames.getDataAt(i); @@ -174,9 +176,9 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode { } } else if (attrName.equals(RRuntime.CLASS_ATTR_KEY)) { if (value == RNull.instance) { - RVector.setClassAttr(resultVector, null, container.getElementClass() == RDataFrame.class ? container : null, container.getElementClass() == RFactor.class ? container : null); + res = RVector.setClassAttr(resultVector, null, container.getElementClass() == RDataFrame.class ? container : null, container.getElementClass() == RFactor.class ? container : null); } else { - UpdateAttr.setClassAttrFromObject(resultVector, container, value, getEncapsulatingSourceSection()); + res = UpdateAttr.setClassAttrFromObject(resultVector, container, value, getEncapsulatingSourceSection()); } } else if (attrName.equals(RRuntime.ROWNAMES_ATTR_KEY)) { resultVector.setRowNames(castVector(virtualFrame, value)); @@ -190,6 +192,7 @@ public abstract class UpdateAttributes extends RInvisibleBuiltinNode { } } } + return res; } @Fallback diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java index 200ede3e97..9203dd89db 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateStorageMode.java @@ -64,7 +64,7 @@ public abstract class UpdateStorageMode extends RBuiltinNode { if (attrs != null) { RAttributable rresult = (RAttributable) result; for (RAttribute attr : attrs) { - rresult.setAttr(attr.getName(), attr.getValue()); + rresult = rresult.setAttr(attr.getName(), attr.getValue()); } } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/AccessArrayNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/AccessArrayNode.java index 16c744e70c..623bd07b9d 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/AccessArrayNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/read/AccessArrayNode.java @@ -189,8 +189,7 @@ public abstract class AccessArrayNode extends RNode { protected Object accessFactor(VirtualFrame frame, RFactor factor, int recLevel, Object position, RAbstractLogicalVector dropDim) { RIntVector res = (RIntVector) castVector(frame, accessRecursive(frame, factor.getVector(), position, recLevel, dropDim)); res.setLevels(factor.getVector().getAttr(RRuntime.LEVELS_ATTR_KEY)); - RVector.setClassAttr(res, RDataFactory.createStringVector("factor"), null, null); - return RDataFactory.createFactor(res); + return RVector.setClassAttr(res, RDataFactory.createStringVector("factor"), null, null); } @SuppressWarnings("unused") diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/UpdateArrayHelperNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/UpdateArrayHelperNode.java index 1b3c4aeb31..5892d9d534 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/UpdateArrayHelperNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/array/write/UpdateArrayHelperNode.java @@ -203,7 +203,7 @@ public abstract class UpdateArrayHelperNode extends RNode { } } - @Specialization + @Specialization(guards = "isSubset") protected Object update(VirtualFrame frame, Object v, RFactor value, int recLevel, Object positions, Object vector) { return updateRecursive(frame, v, value.getVector(), vector, positions, recLevel); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java index d8c732f9d6..d1a4c5b129 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java @@ -703,72 +703,72 @@ public abstract class BinaryBooleanNode extends RBuiltinNode { // factor and scalar - @Specialization(guards = "!isEq") + @Specialization(guards = "!meaningfulOp") protected RLogicalVector doFactorOp(RFactor left, Object right) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName()); } - @Specialization(guards = "!isEq") + @Specialization(guards = "!meaningfulOp") protected RLogicalVector doFactorOp(Object left, RFactor right) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.NOT_MEANINGFUL_FOR_FACTORS, logic.opName()); } - @Specialization(guards = "isEq") + @Specialization(guards = "meaningfulOp") protected RLogicalVector doFactorOp(RFactor left, int right) { return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.intToString(right, false), false); } - @Specialization(guards = "isEq") + @Specialization(guards = "meaningfulOp") protected RLogicalVector doFactorOp(int left, RFactor right) { return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), RRuntime.intToString(left, false), true); } - @Specialization(guards = "isEq") + @Specialization(guards = "meaningfulOp") protected RLogicalVector doFactorOp(RFactor left, double right) { return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.doubleToString(right), false); } - @Specialization(guards = "isEq") + @Specialization(guards = "meaningfulOp") protected RLogicalVector doFactorOp(double left, RFactor right) { return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), RRuntime.doubleToString(left), true); } - @Specialization(guards = "isEq") + @Specialization(guards = "meaningfulOp") protected RLogicalVector doFactorOp(RFactor left, byte right) { return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.logicalToString(right), false); } - @Specialization(guards = "isEq") + @Specialization(guards = "meaningfulOp") protected RLogicalVector doFactorOp(byte left, RFactor right) { return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), RRuntime.logicalToString(left), false); } - @Specialization(guards = "isEq") + @Specialization(guards = "meaningfulOp") protected RLogicalVector doFactorOp(RFactor left, String right) { return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), right, false); } - @Specialization(guards = "isEq") + @Specialization(guards = "meaningfulOp") protected RLogicalVector doFactorOp(String left, RFactor right) { return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), left, true); } - @Specialization(guards = "isEq") + @Specialization(guards = "meaningfulOp") protected RLogicalVector doFactorOp(RFactor left, RComplex right) { return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.complexToString(right), false); } - @Specialization(guards = "isEq") + @Specialization(guards = "meaningfulOp") protected RLogicalVector doFactorOp(RComplex left, RFactor right) { return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), RRuntime.complexToString(left), true); } - @Specialization(guards = "isEq") + @Specialization(guards = "meaningfulOp") protected RLogicalVector doFactorOp(RFactor left, RRaw right) { return performStringVectorOp(RClosures.createFactorToStringVector(left, leftNACheck), RRuntime.rawToString(right), false); } - @Specialization(guards = "isEq") + @Specialization(guards = "meaningfulOp") protected RLogicalVector doFactorOp(RRaw left, RFactor right) { return performStringVectorOp(RClosures.createFactorToStringVector(right, leftNACheck), RRuntime.rawToString(left), true); } @@ -863,22 +863,22 @@ public abstract class BinaryBooleanNode extends RBuiltinNode { return performStringVectorOpSameLength(left, RClosures.createIntToStringVector(right, rightNACheck)); } - @Specialization(guards = {"!areSameLength", "isEq"}) + @Specialization(guards = {"!areSameLength", "meaningfulOp"}) protected RLogicalVector doIntVectorDifferentLength(RAbstractIntVector left, RFactor right) { return performStringVectorOpDifferentLength(RClosures.createIntToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck)); } - @Specialization(guards = {"areSameLength", "isEq"}) + @Specialization(guards = {"areSameLength", "meaningfulOp"}) protected RLogicalVector doIntVectorSameLength(RAbstractIntVector left, RFactor right) { return performStringVectorOpSameLength(RClosures.createIntToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck)); } - @Specialization(guards = {"!areSameLength", "isEq"}) + @Specialization(guards = {"!areSameLength", "meaningfulOp"}) protected RLogicalVector doIntVectorDifferentLength(RFactor left, RAbstractIntVector right) { return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createIntToStringVector(right, rightNACheck)); } - @Specialization(guards = {"areSameLength", "isEq"}) + @Specialization(guards = {"areSameLength", "meaningfulOp"}) protected RLogicalVector doIntVectorSameLength(RFactor left, RAbstractIntVector right) { return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createIntToStringVector(right, rightNACheck)); } @@ -975,22 +975,22 @@ public abstract class BinaryBooleanNode extends RBuiltinNode { return performStringVectorOpSameLength(left, RClosures.createDoubleToStringVector(right, rightNACheck)); } - @Specialization(guards = {"!areSameLength", "isEq"}) + @Specialization(guards = {"!areSameLength", "meaningfulOp"}) protected RLogicalVector doDoubleVectorDifferentLength(RAbstractDoubleVector left, RFactor right) { return performStringVectorOpDifferentLength(RClosures.createDoubleToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck)); } - @Specialization(guards = {"areSameLength", "isEq"}) + @Specialization(guards = {"areSameLength", "meaningfulOp"}) protected RLogicalVector doDoubleVectorSameLength(RAbstractDoubleVector left, RFactor right) { return performStringVectorOpSameLength(RClosures.createDoubleToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck)); } - @Specialization(guards = {"!areSameLength", "isEq"}) + @Specialization(guards = {"!areSameLength", "meaningfulOp"}) protected RLogicalVector doDoubleVectorDifferentLength(RFactor left, RAbstractDoubleVector right) { return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createDoubleToStringVector(right, rightNACheck)); } - @Specialization(guards = {"areSameLength", "isEq"}) + @Specialization(guards = {"areSameLength", "meaningfulOp"}) protected RLogicalVector doDoubleVectorSameLength(RFactor left, RAbstractDoubleVector right) { return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createDoubleToStringVector(right, rightNACheck)); } @@ -1067,22 +1067,22 @@ public abstract class BinaryBooleanNode extends RBuiltinNode { return performStringVectorOpSameLength(left, RClosures.createLogicalToStringVector(right, rightNACheck)); } - @Specialization(guards = {"!areSameLength", "isEq"}) + @Specialization(guards = {"!areSameLength", "meaningfulOp"}) protected RLogicalVector doLogicalVectorDifferentLength(RAbstractLogicalVector left, RFactor right) { return performStringVectorOpDifferentLength(RClosures.createLogicalToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck)); } - @Specialization(guards = {"areSameLength", "isEq"}) + @Specialization(guards = {"areSameLength", "meaningfulOp"}) protected RLogicalVector doLogicalVectorSameLength(RAbstractLogicalVector left, RFactor right) { return performStringVectorOpSameLength(RClosures.createLogicalToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, leftNACheck)); } - @Specialization(guards = {"!areSameLength", "isEq"}) + @Specialization(guards = {"!areSameLength", "meaningfulOp"}) protected RLogicalVector doLogicalVectorDifferentLength(RFactor left, RAbstractLogicalVector right) { return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createLogicalToStringVector(right, rightNACheck)); } - @Specialization(guards = {"areSameLength", "isEq"}) + @Specialization(guards = {"areSameLength", "meaningfulOp"}) protected RLogicalVector doLogicalVectorSameLength(RFactor left, RAbstractLogicalVector right) { return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, leftNACheck), RClosures.createLogicalToStringVector(right, rightNACheck)); } @@ -1139,22 +1139,22 @@ public abstract class BinaryBooleanNode extends RBuiltinNode { return performStringVectorOpSameLength(left, right); } - @Specialization(guards = {"!areSameLength", "isEq"}) + @Specialization(guards = {"!areSameLength", "meaningfulOp"}) protected RLogicalVector doStringVectorDifferentLength(RStringVector left, RFactor right) { return performStringVectorOpDifferentLength(left, RClosures.createFactorToStringVector(right, rightNACheck)); } - @Specialization(guards = {"areSameLength", "isEq"}) + @Specialization(guards = {"areSameLength", "meaningfulOp"}) protected RLogicalVector doStringVectorSameLength(RStringVector left, RFactor right) { return performStringVectorOpSameLength(left, RClosures.createFactorToStringVector(right, rightNACheck)); } - @Specialization(guards = {"!areSameLength", "isEq"}) + @Specialization(guards = {"!areSameLength", "meaningfulOp"}) protected RLogicalVector doStringVectorDifferentLength(RFactor left, RStringVector right) { return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, rightNACheck), right); } - @Specialization(guards = {"areSameLength", "isEq"}) + @Specialization(guards = {"areSameLength", "meaningfulOp"}) protected RLogicalVector doStringVectorSameLength(RFactor left, RStringVector right) { return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, rightNACheck), right); } @@ -1201,52 +1201,52 @@ public abstract class BinaryBooleanNode extends RBuiltinNode { // factor and vectors - @Specialization(guards = {"!areSameLength", "isEq"}) + @Specialization(guards = {"!areSameLength", "meaningfulOp"}) protected RLogicalVector doStringVectorDifferentLength(RFactor left, RFactor right) { return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createFactorToStringVector(right, rightNACheck)); } - @Specialization(guards = {"areSameLength", "isEq"}) + @Specialization(guards = {"areSameLength", "meaningfulOp"}) protected RLogicalVector doStringVectorSameLength(RFactor left, RFactor right) { return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createFactorToStringVector(right, rightNACheck)); } - @Specialization(guards = {"!areSameLength", "isEq"}) + @Specialization(guards = {"!areSameLength", "meaningfulOp"}) protected RLogicalVector doStringVectorDifferentLength(RFactor left, RAbstractComplexVector right) { return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createComplexToStringVector(right, rightNACheck)); } - @Specialization(guards = {"areSameLength", "isEq"}) + @Specialization(guards = {"areSameLength", "meaningfulOp"}) protected RLogicalVector doStringVectorSameLength(RFactor left, RAbstractComplexVector right) { return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createComplexToStringVector(right, rightNACheck)); } - @Specialization(guards = {"!areSameLength", "isEq"}) + @Specialization(guards = {"!areSameLength", "meaningfulOp"}) protected RLogicalVector doStringVectorDifferentLength(RAbstractComplexVector left, RFactor right) { return performStringVectorOpDifferentLength(RClosures.createComplexToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, rightNACheck)); } - @Specialization(guards = {"areSameLength", "isEq"}) + @Specialization(guards = {"areSameLength", "meaningfulOp"}) protected RLogicalVector doStringVectorSameLength(RAbstractComplexVector left, RFactor right) { return performStringVectorOpSameLength(RClosures.createComplexToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, rightNACheck)); } - @Specialization(guards = {"!areSameLength", "isEq"}) + @Specialization(guards = {"!areSameLength", "meaningfulOp"}) protected RLogicalVector doStringVectorDifferentLength(RFactor left, RRawVector right) { return performStringVectorOpDifferentLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createRawToStringVector(right, rightNACheck)); } - @Specialization(guards = {"areSameLength", "isEq"}) + @Specialization(guards = {"areSameLength", "meaningfulOp"}) protected RLogicalVector doStringVectorSameLength(RFactor left, RRawVector right) { return performStringVectorOpSameLength(RClosures.createFactorToStringVector(left, rightNACheck), RClosures.createRawToStringVector(right, rightNACheck)); } - @Specialization(guards = {"!areSameLength", "isEq"}) + @Specialization(guards = {"!areSameLength", "meaningfulOp"}) protected RLogicalVector doStringVectorDifferentLengthRRawVector(RRawVector left, RFactor right) { return performStringVectorOpDifferentLength(RClosures.createRawToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, rightNACheck)); } - @Specialization(guards = {"areSameLength", "isEq"}) + @Specialization(guards = {"areSameLength", "meaningfulOp"}) protected RLogicalVector doStringVectorSameLengthRRawVector(RRawVector left, RFactor right) { return performStringVectorOpSameLength(RClosures.createRawToStringVector(left, leftNACheck), RClosures.createFactorToStringVector(right, rightNACheck)); } @@ -1338,16 +1338,16 @@ public abstract class BinaryBooleanNode extends RBuiltinNode { // guards - public boolean isEq(RFactor left, RFactor right) { - return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual; + public boolean meaningfulOp(RFactor left, RFactor right) { + return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || (left.isOrdered() && right.isOrdered()); } - public boolean isEq(RFactor left, Object right) { - return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual; + public boolean meaningfulOp(RFactor left, Object right) { + return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || left.isOrdered(); } - public boolean isEq(Object left, RFactor right) { - return !(logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual); + public boolean meaningfulOp(Object left, RFactor right) { + return logic instanceof BinaryCompare.Equal || logic instanceof BinaryCompare.NotEqual || right.isOrdered(); } private boolean isVectorizedLogicalOp() { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java index facf67fe88..20559f41ad 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java @@ -31,6 +31,8 @@ public abstract class CastTypeNode extends BinaryNode { @Child private CastToVectorNode castToVectorNode; @Child private TypeofNode typeof; + @Child private CastTypeNode castRecursive; + public abstract Object execute(VirtualFrame frame, Object value, RType type); @SuppressWarnings("unused") @@ -94,6 +96,12 @@ public abstract class CastTypeNode extends BinaryNode { return null; } + @Specialization + protected Object doCastDataFrame(VirtualFrame frame, RDataFrame value, RType type) { + initCastRecursive(); + return castRecursive.execute(frame, value.getVector(), type); + } + @SuppressWarnings("unused") protected static boolean isString(RAbstractVector value, RType type) { return type == RType.Character; @@ -190,4 +198,12 @@ public abstract class CastTypeNode extends BinaryNode { castListNode = insert(CastListNodeFactory.create(null, false, false, false)); } } + + private void initCastRecursive() { + if (castRecursive == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + castRecursive = insert(CastTypeNodeFactory.create(null, null)); + } + } + } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java index 0a6857b8a7..10268ef185 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastLogicalNode.java @@ -22,6 +22,8 @@ */ package com.oracle.truffle.r.nodes.unary; +import java.util.*; + import com.oracle.truffle.api.*; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.*; @@ -179,6 +181,18 @@ public abstract class CastLogicalNode extends CastNode { return missing; } + @Specialization + protected Object asLogical(VirtualFrame frame, RDataFrame dataFrame) { + return castLogicalRecursive(frame, dataFrame.getVector()); + } + + @Specialization + protected RLogicalVector asLogical(RFactor factor) { + byte[] data = new byte[factor.getLength()]; + Arrays.fill(data, RRuntime.LOGICAL_NA); + return RDataFactory.createLogicalVector(data, RDataFactory.INCOMPLETE_VECTOR); + } + @Fallback @TruffleBoundary public int doOther(Object operand) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java index 69f26f12cc..38bebb8777 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java @@ -100,6 +100,8 @@ public class RRuntime { public static final String[] CLASS_INTEGER = new String[]{"integer", "numeric"}; public static final String[] CLASS_DOUBLE = new String[]{"double", "numeric"}; + public static final String CLASS_ORDERED = "ordered"; + public static final String WHICH = "which"; public static final String WHAT = "what"; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java index 290652e0f5..30a6913553 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java @@ -362,7 +362,7 @@ public class RSerialize { } else if (tag.equals(RRuntime.ROWNAMES_ATTR_KEY)) { vec.setRowNames(car); } else if (tag.equals(RRuntime.CLASS_ATTR_KEY)) { - RVector.setClassAttr(vec, (RStringVector) car, null, null); + result = RVector.setClassAttr(vec, (RStringVector) car, null, null); } else { vec.setAttr(tag, car); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java index 2746fdb5ea..3c51b93d1b 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributable.java @@ -46,19 +46,20 @@ public interface RAttributable { /** * Set the attribute {@code name} to {@code value}, overwriting any existing value. This is - * generic; a class may need to override this to handle certain attributes specially, + * generic; a class may need to override this to handle certain attributes specially. */ - default void setAttr(String name, Object value) { + default RAttributable setAttr(String name, Object value) { RAttributes attributes = getAttributes(); if (attributes == null) { attributes = initAttributes(); } attributes.put(name, value); + return this; } /** * Remove the attribute {@code name}. No error if {@code name} is not an attribute. This is - * generic; a class may need to override this to handle certain attributes specially, + * generic; a class may need to override this to handle certain attributes specially. */ default void removeAttr(String name) { RAttributes attributes = getAttributes(); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java index d7ae5ec067..1d19b5ae62 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java @@ -304,8 +304,8 @@ public final class RDataFactory { return traceDataCreated(new RExpression(list)); } - public static RFactor createFactor(RIntVector vector) { - return traceDataCreated(new RFactor(vector)); + public static RFactor createFactor(RIntVector vector, boolean ordered) { + return traceDataCreated(new RFactor(vector, ordered)); } public static RVector createObjectVector(Object[] data, boolean completeVector) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java index 2d4d8aa74e..600a7da4ee 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java @@ -28,14 +28,21 @@ public final class RFactor implements RShareable, RAbstractContainer { private RIntVector vector; - public RFactor(RIntVector vector) { + private final boolean ordered; + + public RFactor(RIntVector vector, boolean ordered) { this.vector = vector; + this.ordered = ordered; } public RIntVector getVector() { return vector; } + public boolean isOrdered() { + return ordered; + } + @Override public int getLength() { return vector.getLength(); @@ -63,7 +70,7 @@ public final class RFactor implements RShareable, RAbstractContainer { @Override public RFactor copy() { - return RDataFactory.createFactor((RIntVector) vector.copy()); + return RDataFactory.createFactor((RIntVector) vector.copy(), ordered); } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java index 3db2391caf..2b3a6961a4 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java @@ -163,10 +163,11 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV } @TruffleBoundary - public final void setAttr(String name, Object value) { + public final RAbstractContainer setAttr(String name, Object value) { if (attributes == null) { initAttributes(); } + RAbstractContainer res = this; if (name.equals(RRuntime.NAMES_ATTR_KEY)) { setNames(value); } else if (name.equals(RRuntime.DIM_ATTR_KEY)) { @@ -180,10 +181,11 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV } else if (name.equals(RRuntime.ROWNAMES_ATTR_KEY)) { setRowNames(value); } else if (name.equals(RRuntime.CLASS_ATTR_KEY)) { - setClassAttr(this, (RStringVector) value, null, null); + res = setClassAttr(this, (RStringVector) value, null, null); } else { attributes.put(name, value); } + return res; } public final Object getAttr(String name) { @@ -405,8 +407,15 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV // class attribute removed - no longer a data frame (even if it was before) return vector; } else if (classAttr != null && classAttr.getLength() != 0) { + boolean ordered = false; for (int i = 0; i < classAttr.getLength(); i++) { - if (RType.DataFrame.getName().equals(classAttr.getDataAt(i))) { + String attr = classAttr.getDataAt(i); + if (RRuntime.CLASS_ORDERED.equals(attr)) { + // "ordered" must be specified before "factor" - hence it's enough to do the + // check only before encountering the "factor" + ordered = true; + } + if (RType.DataFrame.getName().equals(attr)) { vector.putAttribute(RRuntime.CLASS_ATTR_KEY, classAttr); if (enclosingDataFrame != null) { // was a frame and still is a frame @@ -415,7 +424,7 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV // it's a data frame now return RDataFactory.createDataFrame(vector); } - } else if (RType.Factor.getName().equals(classAttr.getDataAt(i))) { + } else if (RType.Factor.getName().equals(attr)) { if (vector.getElementClass() != RInt.class) { // TODO: add source section throw RError.error(null, RError.Message.ADDING_INVALID_CLASS, "factor"); @@ -426,7 +435,7 @@ public abstract class RVector extends RBounded implements RShareable, RAbstractV return enclosingFactor; } else { // it's a factor now - return RDataFactory.createFactor((RIntVector) vector); + return RDataFactory.createFactor((RIntVector) vector, ordered); } } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RFactorToStringVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RFactorToStringVectorClosure.java index cb2c3ca812..e437f164d4 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RFactorToStringVectorClosure.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RFactorToStringVectorClosure.java @@ -42,13 +42,24 @@ public class RFactorToStringVectorClosure extends RToStringVectorClosure impleme if (this.levels == null) { RError.warning(RError.Message.IS_NA_TO_NON_VECTOR, "NULL"); } + naCheck.enable(this.vector); } public String getDataAt(int index) { - if (levels == null) { + if (levels == null || levels.getLength() == 0) { return RRuntime.STRING_NA; } else { - return this.levels.getDataAt(vector.getDataAt(index) - 1); + int val = vector.getDataAt(index); + if (naCheck.check(val)) { + return RRuntime.STRING_NA; + } else { + String l = levels.getDataAt(val - 1); + if (naCheck.check(l)) { + return "NA"; // for comparison + } else { + return l; + } + } } } } 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 605937e8f3..558be5cd61 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 @@ -8310,6 +8310,14 @@ x [1,] 10+0i -4+0i [2,] -2+0i 0+0i +##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor +#{ as.logical(factor(c("a", "b", "a"))) } +[1] NA NA NA + +##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor +#{ as.logical(factor(integer())) } +logical(0) + ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor #{ x<-c("1","2","3"); class(x)<-"factor"; x } Error in class(x) <- "factor" : @@ -8320,6 +8328,16 @@ Error in class(x) <- "factor" : Error in class(x) <- "factor" : adding class "factor" to an invalid object +##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor +#{ x<-c(1L, 2L, 1L); class(x)<-c("factor", "ordered"); levels(x)<-c("a", "b"); x > "a" } +[1] NA NA NA +Warning message: +In Ops.factor(x, "a") : > not meaningful for factors + +##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor +#{ x<-c(1L, 2L, 1L); class(x)<-c("ordered", "factor"); levels(x)<-c("a", "b"); x > "a" } +[1] FALSE TRUE FALSE + ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor #{ x<-c(1L,2L,3L); class(x)<-"factor"; x } Error in print.factor(1:3) : replacement has length zero @@ -8332,6 +8350,10 @@ NULL #{ x<-factor(c("a", "b", "a")); attr(x, "levels")<-character(); as.character(x) } [1] NA NA NA +##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor +#{ x<-factor(c("a", "b", "a")); is.atomic(x) } +[1] TRUE + ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor #{ x<-factor(c("a", "b", "a")); x == "a" } [1] TRUE FALSE TRUE @@ -8387,6 +8409,14 @@ Levels: a b [1] a b a <NA> Levels: a b +##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor +#{ x<-factor(c("a", "b", "a"), ordered=TRUE); is.atomic(x) } +[1] TRUE + +##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor +#{ x<-factor(c("a", "b", "a"), ordered=TRUE); x > "a" } +[1] FALSE TRUE FALSE + ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor #{ x<-factor(c("a", "b", "a", "c")); x == c("a", "b") } [1] TRUE TRUE TRUE FALSE @@ -8398,6 +8428,10 @@ Warning message: In y[1] <- x : number of items to replace is not a multiple of replacement length +##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor +#{ x<-factor(c("c", "b", "a", "c")); y<-c(1); y[[1]]<-x; y } +Error in y[[1]] <- x : more elements supplied than there are to replace + ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor #{ x<-factor(c("c", "b", "a", "c")); y<-list(1); y[1]<-x; y } [[1]] @@ -8407,6 +8441,13 @@ Warning message: In y[1] <- x : number of items to replace is not a multiple of replacement length +##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor +#{ x<-factor(c("c", "b", "a", "c")); y<-list(1); y[[1]]<-x; y } +[[1]] +[1] c b a c +Levels: a b c + + ##com.oracle.truffle.r.test.simple.TestSimpleBuiltins.testFactor #{data = c(1,2,2,3,1,2,3,3,1,2,3,3,1);fdata<-factor(data);levels(fdata) = c('I','II','III');print(fdata);} [1] I II II III I II III III I II III III I @@ -16277,6 +16318,18 @@ $x 2 33 bb 3 55 cc +##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testMisc +#{ y<-data.frame(7); as.logical(y) } +[1] TRUE + +##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testMisc +#{ y<-data.frame(c(1,2,3)); as.logical(y) } +Error: (list) object cannot be coerced to type 'logical' + +##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testMisc +#{ y<-data.frame(integer()); as.logical(y) } +[1] NA + ##com.oracle.truffle.r.test.simple.TestSimpleDataFrames.testPrint #{ n = c(2, 3, 5); s = c(TRUE, FALSE, TRUE); df = data.frame(n, s); df } n s diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java index 7bd93077b9..fb90a257aa 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/all/AllTests.java @@ -8123,6 +8123,21 @@ public class AllTests extends TestBase { assertEval("{ x<-factor(c(\"a\", \"b\", \"a\", \"c\")); x == c(\"a\", \"b\") }"); } + @Test + public void TestSimpleBuiltins_testFactor_c6b2929aec56f236a9015269d6d5e6f0() { + assertEval("{ x<-factor(c(\"a\", \"b\", \"a\"), ordered=TRUE); x > \"a\" }"); + } + + @Test + public void TestSimpleBuiltins_testFactor_e759d4fccb890277ccc9ddb8fcb0dec3() { + assertEval("{ x<-c(1L, 2L, 1L); class(x)<-c(\"ordered\", \"factor\"); levels(x)<-c(\"a\", \"b\"); x > \"a\" }"); + } + + @Test + public void TestSimpleBuiltins_testFactor_9383599e2b32f549f5e46351c2e6bd9b() { + assertEval("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-list(1); y[[1]]<-x; y }"); + } + @Test public void TestSimpleBuiltins_testFactor_ef37cc56e92b1c4a3742f47b97df2525() { assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[1] }"); @@ -8153,6 +8168,26 @@ public class AllTests extends TestBase { assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[c(1,2,3,4)] }"); } + @Test + public void TestSimpleBuiltins_testFactor_fdae08cc3544f4e5c971d2303a796eeb() { + assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); is.atomic(x) }"); + } + + @Test + public void TestSimpleBuiltins_testFactor_5302c7a50fda26503b5d1f681cec279c() { + assertEval("{ x<-factor(c(\"a\", \"b\", \"a\"), ordered=TRUE); is.atomic(x) }"); + } + + @Test + public void TestSimpleBuiltins_testFactor_a8153cc5be539920818caa4f7d546190() { + assertEval("{ as.logical(factor(c(\"a\", \"b\", \"a\"))) }"); + } + + @Test + public void TestSimpleBuiltins_testFactor_19ca5910d2b0103d936cfdd499387aa2() { + assertEval("{ as.logical(factor(integer())) }"); + } + @Test public void TestSimpleBuiltins_testFactor_2ef7de52def309425a9b70965111f004() { assertEvalError("{ x<-c(1,2,3); class(x)<-\"factor\"; x }"); @@ -8178,6 +8213,16 @@ public class AllTests extends TestBase { assertEvalError("{ x<-factor(c(\"a\", \"b\", \"a\")); x > c(\"a\", \"b\") }"); } + @Test + public void TestSimpleBuiltins_testFactor_e1f4890b0e585468d589f92e64e8fe43() { + assertEvalError("{ x<-c(1L, 2L, 1L); class(x)<-c(\"factor\", \"ordered\"); levels(x)<-c(\"a\", \"b\"); x > \"a\" }"); + } + + @Test + public void TestSimpleBuiltins_testFactor_778d87ada7ac057126f8a27cfe882a81() { + assertEvalError("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-c(1); y[[1]]<-x; y }"); + } + @Test public void TestSimpleBuiltins_testFactor_61bfd366e4db68e9bda18fe2c3cc87f2() { assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x == c(\"a\", \"b\") }"); @@ -17093,6 +17138,21 @@ public class AllTests extends TestBase { assertEval("{ n = c(2, 3, 5); s = c(\"aa\", \"bb\", \"cc\"); df = data.frame(n, s); df[[1]] <- c(22,33,55); df }"); } + @Test + public void TestSimpleDataFrames_testMisc_e52a62b09e6557563b89aed7622a090f() { + assertEval("{ y<-data.frame(7); as.logical(y) }"); + } + + @Test + public void TestSimpleDataFrames_testMisc_41c31f4873ee11a67409c7646ea787b9() { + assertEval("{ y<-data.frame(integer()); as.logical(y) }"); + } + + @Test + public void TestSimpleDataFrames_testMisc_526983ed080a1f64591401d75eba5c80() { + assertEvalError("{ y<-data.frame(c(1,2,3)); as.logical(y) }"); + } + @Test public void TestSimpleDataFrames_testPrint_da9c92f6582f469a3303b14bf936c77e() { assertEval("{x<-c(1,2); class(x)<-\"data.frame\"; x}"); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java index d66c062c8b..ac3cfff7ea 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleBuiltins.java @@ -3907,9 +3907,15 @@ public class TestSimpleBuiltins extends TestBase { assertEvalWarning("{ x<-factor(c(\"a\", \"b\", \"a\")); x == c(\"a\", \"b\") }"); assertEvalError("{ x<-factor(c(\"a\", \"b\", \"a\")); x > c(\"a\", \"b\") }"); assertEval("{ x<-factor(c(\"a\", \"b\", \"a\", \"c\")); x == c(\"a\", \"b\") }"); + assertEval("{ x<-factor(c(\"a\", \"b\", \"a\"), ordered=TRUE); x > \"a\" }"); + + assertEval("{ x<-c(1L, 2L, 1L); class(x)<-c(\"ordered\", \"factor\"); levels(x)<-c(\"a\", \"b\"); x > \"a\" }"); + assertEvalError("{ x<-c(1L, 2L, 1L); class(x)<-c(\"factor\", \"ordered\"); levels(x)<-c(\"a\", \"b\"); x > \"a\" }"); assertEvalWarning("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-list(1); y[1]<-x; y }"); assertEvalWarning("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-c(1); y[1]<-x; y }"); + assertEval("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-list(1); y[[1]]<-x; y }"); + assertEvalError("{ x<-factor(c(\"c\", \"b\", \"a\", \"c\")); y<-c(1); y[[1]]<-x; y }"); assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[1] }"); assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[[1]] }"); @@ -3917,6 +3923,12 @@ public class TestSimpleBuiltins extends TestBase { assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[[2]] }"); assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[c(1,2)] }"); assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); x[c(1,2,3,4)] }"); + + assertEval("{ x<-factor(c(\"a\", \"b\", \"a\")); is.atomic(x) }"); + assertEval("{ x<-factor(c(\"a\", \"b\", \"a\"), ordered=TRUE); is.atomic(x) }"); + + assertEval("{ as.logical(factor(c(\"a\", \"b\", \"a\"))) }"); + assertEval("{ as.logical(factor(integer())) }"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleDataFrames.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleDataFrames.java index 8a9644e161..feb33af1ad 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleDataFrames.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/TestSimpleDataFrames.java @@ -141,6 +141,11 @@ public class TestSimpleDataFrames extends TestBase { @Test public void testMisc() { assertEval("{ n = c(2, 3, 5); s = c(\"aa\", \"bb\", \"cc\"); df = data.frame(n, s); df[[1]] <- c(22,33,55); df }"); + + assertEval("{ y<-data.frame(7); as.logical(y) }"); + assertEval("{ y<-data.frame(integer()); as.logical(y) }"); + assertEvalError("{ y<-data.frame(c(1,2,3)); as.logical(y) }"); + } } -- GitLab