From 2b12f779655fb1582255ec4077aa8592e7ad8f43 Mon Sep 17 00:00:00 2001 From: Zbynek Slajchrt <zbynek.slajchrt@oracle.com> Date: Thu, 25 Feb 2016 16:58:47 +0100 Subject: [PATCH] The new pretty-printer skeleton implementation integrated with the FastR. It supports the following data types: named and unnamed vectors, matrices, String and Double. --- .../truffle/r/nodes/builtin/base/Format.java | 8 +- .../r/nodes/builtin/base/Inherits.java | 2 +- .../truffle/r/nodes/builtin/base/IsS4.java | 2 + .../r/nodes/builtin/base/IsTypeFunctions.java | 6 + .../nodes/builtin/base/PrettyPrinterNode.java | 3 +- .../r/nodes/builtin/base/PrintFunctions.java | 44 +- .../base/printer/AbstractValuePrinter.java | 48 ++ .../base/printer/AttributesPrinter.java | 106 +++ .../builtin/base/printer/DoublePrinter.java | 216 ++++++ .../base/printer/DoubleVectorPrinter.java | 218 ++++++ .../builtin/base/printer/NullPrinter.java | 35 + .../builtin/base/printer/PrintContext.java | 54 ++ .../base/printer/PrintJustification.java | 30 + .../builtin/base/printer/PrintParameters.java | 237 +++++++ .../builtin/base/printer/RBufferedWriter.java | 54 ++ .../r/nodes/builtin/base/printer/RWriter.java | 45 ++ .../builtin/base/printer/StringPrinter.java | 100 +++ .../base/printer/StringVectorPrinter.java | 115 ++++ .../r/nodes/builtin/base/printer/Utils.java | 46 ++ .../builtin/base/printer/ValuePrinter.java | 30 + .../base/printer/ValuePrinterNode.java | 106 +++ .../builtin/base/printer/ValuePrinters.java | 69 ++ .../builtin/base/printer/VectorPrinter.java | 633 ++++++++++++++++++ .../oracle/truffle/r/runtime/RRuntime.java | 4 + .../truffle/r/test/ExpectedTestOutput.test | 4 + .../r/test/builtins/TestBuiltin_format.java | 13 +- .../library/base/TestSimpleArithmetic.java | 3 +- .../r/test/rpackages/TestRFFIPackage.java | 24 +- mx.fastr/copyrights/overrides | 7 + mx.fastr/mx_fastr.py | 3 + 30 files changed, 2249 insertions(+), 16 deletions(-) create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AbstractValuePrinter.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AttributesPrinter.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoublePrinter.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/NullPrinter.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintContext.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintJustification.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintParameters.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RBufferedWriter.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RWriter.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringPrinter.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringVectorPrinter.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/Utils.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinter.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinters.java create mode 100644 com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java 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 7c72e604d8..9d3bf751e0 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 @@ -31,6 +31,12 @@ public abstract class Format extends RBuiltinNode { protected final BranchProfile errorProfile = BranchProfile.create(); private final RAttributeProfiles attrProfiles = RAttributeProfiles.create(); + /** + * This is just a dummy object used to invoke getNames on RAbstractDoubleVector. The + * RAbstractDoubleVector has no method for obtaining the names associated with the values in the + * vector other than getNames(RAttributeProfiles). + */ + private static final RAttributeProfiles dummyAttrProfiles = RAttributeProfiles.create(); public static final int R_MAX_DIGITS_OPT = 22; public static final int R_MIN_DIGITS_OPT = 0; @@ -216,7 +222,7 @@ public abstract class Format extends RBuiltinNode { addSpaces(data, width); } // vector is complete because strings are created by string builder - return RDataFactory.createStringVector(data, complete); + return RDataFactory.createStringVector(data, complete, value.getNames(dummyAttrProfiles)); } @Specialization diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Inherits.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Inherits.java index 0f913c0a1f..5ae44f5d05 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Inherits.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Inherits.java @@ -28,7 +28,7 @@ public abstract class Inherits extends RBuiltinNode { protected final RAttributeProfiles attrProfiles = RAttributeProfiles.create(); - protected abstract Object execute(Object x, Object what, Object which); + public abstract Object execute(Object x, Object what, Object which); @Child private InheritsNode inheritsNode; @Child private Inherits recursiveInherits; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsS4.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsS4.java index 6e8406648d..ddd0b6e143 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsS4.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsS4.java @@ -39,6 +39,8 @@ import com.oracle.truffle.r.runtime.data.model.*; @RBuiltin(name = "isS4", kind = PRIMITIVE, parameterNames = {"object"}) public abstract class IsS4 extends RBuiltinNode { + public abstract byte execute(Object value); + @Specialization protected byte isS4(RNull object) { return RRuntime.asLogical(RContext.getInstance().isNullS4Object()); 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 939a829866..a5299f05f8 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 @@ -63,6 +63,8 @@ public class IsTypeFunctions { @RBuiltin(name = "is.array", kind = PRIMITIVE, parameterNames = {"x"}) public abstract static class IsArray extends MissingAdapter { + public abstract byte execute(Object value); + @Specialization protected byte isType(RAbstractVector vector) { controlVisibility(); @@ -302,6 +304,8 @@ public class IsTypeFunctions { private final ConditionProfile isListProfile = ConditionProfile.createBinaryProfile(); + public abstract byte execute(Object value); + @Specialization protected byte isType(RList value) { controlVisibility(); @@ -435,6 +439,8 @@ public class IsTypeFunctions { private final RAttributeProfiles attrProfiles = RAttributeProfiles.create(); + public abstract byte execute(Object value); + @Specialization protected byte isObject(RAttributable arg) { controlVisibility(); 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 50385f5b1a..697b37e0c2 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 @@ -1842,7 +1842,8 @@ public abstract class PrettyPrinterNode extends RNode { for (int dimInd = 0; dimInd < dimSize; dimInd++) { int newArrayBase = arrayBase + newAccDimensions * dimInd; String dimId = getDimId(vector, currentDimLevel, dimInd, attrProfiles); - String innerDims = printDimRecursive(vector, isListOrStringVector, isComplexOrRawVector, currentDimLevel - 1, newArrayBase, newAccDimensions, concat(dimId, ", ", header), isQuoted); + String innerDims = printDimRecursive(vector, isListOrStringVector, isComplexOrRawVector, currentDimLevel - 1, newArrayBase, newAccDimensions, concat(dimId, ", ", header), + isQuoted); if (innerDims == null) { return null; } else { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java index e10d120fcb..a0ff2ccd9a 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/PrintFunctions.java @@ -25,6 +25,8 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.runtime.RBuiltinKind.INTERNAL; import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.Truffle; @@ -33,11 +35,20 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; +import com.oracle.truffle.r.nodes.builtin.RBuiltinNode.CastBuilder; import com.oracle.truffle.r.nodes.builtin.RInvisibleBuiltinNode; +import com.oracle.truffle.r.nodes.builtin.base.printer.PrintContext; +import com.oracle.truffle.r.nodes.builtin.base.printer.PrintParameters; +import com.oracle.truffle.r.nodes.builtin.base.printer.RBufferedWriter; +import com.oracle.truffle.r.nodes.builtin.base.printer.RWriter; +import com.oracle.truffle.r.nodes.builtin.base.printer.ValuePrinterNode; +import com.oracle.truffle.r.nodes.builtin.base.printer.ValuePrinterNodeGen; +import com.oracle.truffle.r.nodes.builtin.base.printer.ValuePrinters; import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.Utils; +import com.oracle.truffle.r.runtime.conn.RConnection; import com.oracle.truffle.r.runtime.conn.StdConnections; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; @@ -49,6 +60,8 @@ import com.oracle.truffle.r.runtime.data.RTypedValue; public class PrintFunctions { public abstract static class PrintAdapter extends RInvisibleBuiltinNode { @Child protected PrettyPrinterNode prettyPrinter = PrettyPrinterNodeGen.create(null, null, null, null, false); + // The new pretty-printer + @Child protected ValuePrinterNode valuePrinter = ValuePrinterNodeGen.create(null, null, null, null, null, null, null, null, null); @TruffleBoundary protected void printHelper(String string) { @@ -66,13 +79,30 @@ public class PrintFunctions { private final RAttributeProfiles attrProfiles = RAttributeProfiles.create(); - @SuppressWarnings("unused") + @Override + protected void createCasts(CastBuilder casts) { + super.createCasts(casts); + casts.firstBoolean(2); + casts.firstBoolean(5); + casts.firstBoolean(7); + casts.firstBoolean(8); + } + + @SuppressWarnings({"unchecked"}) @Specialization(guards = "!isS4(o)") - protected Object printDefault(Object o, Object digits, byte quote, Object naPrint, Object printGap, byte right, Object max, Object useSource, Object noOpt) { - String s = (String) prettyPrinter.executeString(o, null, quote, right); - if (s != null && !s.isEmpty()) { - printHelper(s); + protected Object printDefault(Object o, Object digits, boolean quote, Object naPrint, Object printGap, boolean right, Object max, boolean useSource, boolean noOpt) { + try { + // Invoking the new pretty-printer. In contrast to the previous one, the new one + // does not return the output value and prints directly to the output. + valuePrinter.executeString(o, digits, quote, naPrint, printGap, right, max, useSource, noOpt); + } catch (UnsupportedOperationException e) { + // The original pretty printing code + String s = (String) prettyPrinter.executeString(o, null, RRuntime.asLogical(quote), RRuntime.asLogical(right)); + if (s != null && !s.isEmpty()) { + printHelper(s); + } } + controlVisibility(); return o; } @@ -92,14 +122,14 @@ public class PrintFunctions { @SuppressWarnings("unused") @TruffleBoundary @Specialization(guards = "isS4(o)") - protected Object printDefaultS4(RTypedValue o, Object digits, byte quote, Object naPrint, Object printGap, byte right, Object max, Object useSource, Object noOpt, + protected Object printDefaultS4(RTypedValue o, Object digits, boolean quote, Object naPrint, Object printGap, boolean right, Object max, boolean useSource, boolean noOpt, @Cached("createShowFind()") ReadVariableNode showFind, @Cached("createShowFunction(showFind)") RFunction showFunction) { RContext.getEngine().evalFunction(showFunction, null, o); return null; } protected boolean isS4(Object o) { - // chacking for class attribute is a bit of a hack but GNU R has a hack in place here as + // checking for class attribute is a bit of a hack but GNU R has a hack in place here as // well to avoid recursively calling show via print in showDefault (we just can't use // the same hack at this point - for details see definition of showDefault in show.R) return o instanceof RAttributable && ((RAttributable) o).isS4() && ((RAttributable) o).getClassAttr(attrProfiles) != null; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AbstractValuePrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AbstractValuePrinter.java new file mode 100644 index 0000000000..cee4b9608c --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AbstractValuePrinter.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import java.io.IOException; + +import com.oracle.truffle.r.runtime.data.RAttributeStorage; +import com.oracle.truffle.r.runtime.data.RAttributes; + +public abstract class AbstractValuePrinter<T> implements ValuePrinter<T> { + + public void print(T value, PrintContext printCtx) throws IOException { + printValue(value, printCtx); + printAttributes(value, printCtx); + } + + private void printAttributes(T value, PrintContext printCtx) throws IOException { + if (value instanceof RAttributeStorage) { + AttributesPrinter.INSTANCE.print((RAttributeStorage) value, printCtx); + } + } + + protected void printAttributes(T value, RAttributes attrs, PrintContext printCtx) throws IOException { + } + + protected abstract void printValue(T value, PrintContext printCtx) throws IOException; + +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AttributesPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AttributesPrinter.java new file mode 100644 index 0000000000..0a27ac8f00 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AttributesPrinter.java @@ -0,0 +1,106 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 1995, 1996 Robert Gentleman and Ross Ihaka + * Copyright (c) 1997-2013, The R Core Team + * Copyright (c) 2016, Oracle and/or its affiliates + * + * All rights reserved. + */ + +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import java.io.IOException; +import java.io.PrintWriter; + +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RAttributable; +import com.oracle.truffle.r.runtime.data.RAttributeStorage; +import com.oracle.truffle.r.runtime.data.RAttributes; +import com.oracle.truffle.r.runtime.data.RComplex; +import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute; +import com.oracle.truffle.r.runtime.data.RDataFrame; + +//Transcribed from GnuR, src/main/print.c + +public class AttributesPrinter implements ValuePrinter<RAttributable> { + + public static final AttributesPrinter INSTANCE = new AttributesPrinter(false); + + private final boolean useSlots; + + public AttributesPrinter(boolean useSlots) { + super(); + this.useSlots = useSlots; + } + + public void print(RAttributable value, PrintContext printCtx) throws IOException { + RAttributes attrs = value.getAttributes(); + if (attrs == null) { + return; + } + + for (RAttribute a : attrs) { + if (useSlots && RRuntime.CLASS_SYMBOL.equals(a.getName())) { + continue; + } + ValuePrinterNode utils = printCtx.printerNode(); + if (utils.isArray(value) || utils.isList(value)) { + if (RRuntime.DIM_ATTR_KEY.equals(a.getName()) || RRuntime.DIMNAMES_ATTR_KEY.equals(a.getName())) { + continue; + } + } + if (utils.inherits(value, "factor", RRuntime.LOGICAL_FALSE)) { + if (RRuntime.LEVELS_ATTR_KEY.equals(a.getName())) { + continue; + } + if (RRuntime.CLASS_ATTR_KEY.equals(a.getName())) { + continue; + } + } + if (value instanceof RDataFrame) { + if (RRuntime.ROWNAMES_ATTR_KEY.equals(a.getName())) { + continue; + } + } + if (!utils.isArray(value)) { + if (RRuntime.NAMES_ATTR_KEY.equals(a.getName())) { + continue; + } + } + if (RRuntime.R_COMMENT.equals(a.getName()) || RRuntime.R_SOURCE.equals(a.getName()) || + RRuntime.R_SRCREF.equals(a.getName()) || RRuntime.R_WHOLE_SRCREF.equals(a.getName()) || + RRuntime.R_SRCFILE.equals(a.getName())) { + continue; + } + + final PrintWriter out = printCtx.output(); + final String tag; + if (useSlots) { + tag = String.format("Slot \"%s\":", a.getName()); + } else { + tag = String.format("attr(,\"%s\")", a.getName()); + } + out.println(tag); + + if (RRuntime.ROWNAMES_ATTR_KEY.equals(a.getName())) { + /* need special handling AND protection */ + Object val = a.getValue(); + ValuePrinters.printValue(val, printCtx); + continue; + } + if (RContext.getInstance().isMethodTableDispatchOn() && utils.isS4(value)) { + throw new UnsupportedOperationException("TODO"); + } + if (utils.isObject(value)) { + throw new UnsupportedOperationException("TODO"); + } + + ValuePrinters.printValue(a.getValue(), printCtx); + } + } + +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoublePrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoublePrinter.java new file mode 100644 index 0000000000..0573958c7d --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoublePrinter.java @@ -0,0 +1,216 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 1995, 1996 Robert Gentleman and Ross Ihaka + * Copyright (c) 1997-2013, The R Core Team + * Copyright (c) 2016, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import static com.oracle.truffle.r.nodes.builtin.base.printer.Utils.snprintf; + +import java.io.IOException; +import java.io.PrintWriter; + +import com.oracle.truffle.r.nodes.builtin.base.printer.DoubleVectorPrinter.DoubleVectorMetrics; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.RDouble; + +//Transcribed from GnuR, src/main/printutils.c + +public final class DoublePrinter extends AbstractValuePrinter<Double> { + + public static final DoublePrinter INSTANCE = new DoublePrinter(); + + @Override + protected void printValue(Double value, PrintContext printCtx) throws IOException { + double x = value; + + PrintWriter out = printCtx.output(); + out.print("[1] "); + DoubleVectorMetrics dm = DoubleVectorPrinter.formatDoubleVector(RDouble.valueOf(x), 0, 1, 0, printCtx.parameters()); + out.println(encodeReal(x, dm.maxWidth, dm.d, dm.e, '.', printCtx.parameters())); + } + + private static final int DBL_DIG = 15; + + private static final double[] tbl = { + 1e-1, + 1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22 + }; + private static final int KP_MAX = 22; + private static final int R_dec_min_exponent = -308; + private static final int NB = 1000; + + public static class ScientificDouble { + public final int sgn; + public final int kpower; + public final int nsig; + public final boolean roundingwidens; + + public ScientificDouble(int sgn, int kpower, int nsig, boolean roundingwidens) { + super(); + this.sgn = sgn; + this.kpower = kpower; + this.nsig = nsig; + this.roundingwidens = roundingwidens; + } + + } + + public static ScientificDouble scientific(double x, PrintParameters pp) { + /* + * for a number x , determine sgn = 1_{x < 0} {0/1} kpower = Exponent of 10; nsig = + * min(R_print.digits, #{significant digits of alpha}) roundingwidens = 1 if rounding causes + * x to increase in width, 0 otherwise + * + * where |x| = alpha * 10^kpower and 1 <= alpha < 10 + */ + double alpha; + double r; + int kp; + int j; + + // output arguments + int sgn; + int kpower; + int nsig; + boolean roundingwidens; + + if (x == 0.0) { + kpower = 0; + nsig = 1; + sgn = 0; + roundingwidens = false; + r = 0.0; + } else { + if (x < 0.0) { + sgn = 1; + r = -x; + } else { + sgn = 0; + r = x; + } + + if (pp.getDigits() >= DBL_DIG + 1) { + // TODO: + // format_via_sprintf(r, pp.getDigits(), kpower, nsig); + roundingwidens = false; + // return; + throw new UnsupportedOperationException(); + } + + kp = (int) Math.floor(Math.log10(r)) - pp.getDigits() + 1; // r = |x|; + // 10^(kp + digits - 1) <= r + + double r_prec = r; + /* use exact scaling factor in double precision, if possible */ + if (Math.abs(kp) <= 22) { + if (kp >= 0) { + r_prec /= tbl[kp + 1]; + } else { + r_prec *= tbl[-kp + 1]; + } + } + /* + * on IEEE 1e-308 is not representable except by gradual underflow. Shifting by 303 + * allows for any potential denormalized numbers x, and makes the reasonable assumption + * that R_dec_min_exponent+303 is in range. Representation of 1e+303 has low error. + */ + + else if (kp <= R_dec_min_exponent) { + r_prec = (r_prec * 1e+303) / Math.pow(10, kp + 303); + } else { + r_prec /= Math.pow(10, kp); + } + if (r_prec < tbl[pp.getDigits()]) { + r_prec *= 10.0; + kp--; + } + /* round alpha to integer, 10^(digits-1) <= alpha <= 10^digits */ + /* + * accuracy limited by double rounding problem, alpha already rounded to 53 bits + */ + alpha = Math.round(r_prec); + + nsig = pp.getDigits(); + for (j = 1; j <= pp.getDigits(); j++) { + alpha /= 10.0; + if (alpha == Math.floor(alpha)) { + nsig--; + } else { + break; + } + } + if (nsig == 0 && pp.getDigits() > 0) { + nsig = 1; + kp += 1; + } + kpower = kp + pp.getDigits() - 1; + + /* + * Scientific format may do more rounding than fixed format, e.g. 9996 with 3 digits is + * 1e+04 in scientific, but 9996 in fixed. This happens when the true value r is less + * than 10^(kpower+1) and would not round up to it in fixed format. Here rgt is the + * decimal place that will be cut off by rounding + */ + + int rgt = pp.getDigits() - kpower; + /* bound rgt by 0 and KP_MAX */ + rgt = rgt < 0 ? 0 : rgt > KP_MAX ? KP_MAX : rgt; + double fuzz = 0.5 / tbl[1 + rgt]; + // kpower can be bigger than the table. + roundingwidens = kpower > 0 && kpower <= KP_MAX && r < tbl[kpower + 1] - fuzz; + + } + + return new ScientificDouble(sgn, kpower, nsig, roundingwidens); + } + + public static String encodeReal(double x, int w, int d, int e, char cdec, PrintParameters pp) { + final String buff; + String fmt; + + /* IEEE allows signed zeros (yuck!) */ + if (x == 0.0) { + x = 0.0; + } + if (!RRuntime.isFinite(x)) { + int numBlanks = Math.min(w, (NB - 1)); + String naFmt = "%" + numBlanks + "s"; + if (RRuntime.isNA(x)) { + buff = snprintf(NB, naFmt, pp.getNa_string()); + } else if (RRuntime.isNAorNaN(x)) { + buff = snprintf(NB, naFmt, "NaN"); + } else if (x > 0) { + buff = snprintf(NB, naFmt, "Inf"); + } else { + buff = snprintf(NB, naFmt, "-Inf"); + } + } else if (e != 0) { + if (d != 0) { + fmt = String.format("%%#%d.%de", Math.min(w, (NB - 1)), d); + buff = snprintf(NB, fmt, x); + } else { + fmt = String.format("%%%d.%de", Math.min(w, (NB - 1)), d); + buff = snprintf(NB, fmt, x); + } + } else { /* e = 0 */ + fmt = String.format("%%%d.%df", Math.min(w, (NB - 1)), d); + buff = snprintf(NB, fmt, x); + } + + if (cdec != '.') { + buff.replace('.', cdec); + } + + return buff; + } + +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java new file mode 100644 index 0000000000..603abc861f --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java @@ -0,0 +1,218 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 1995, 1996 Robert Gentleman and Ross Ihaka + * Copyright (c) 1997-2013, The R Core Team + * Copyright (c) 2016, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import java.io.IOException; + +import com.oracle.truffle.r.nodes.builtin.base.printer.DoublePrinter.ScientificDouble; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; + +//Transcribed from GnuR, src/main/format.c + +public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { + + public static final DoubleVectorPrinter INSTANCE = new DoubleVectorPrinter(); + + @Override + protected VectorPrinter<RAbstractDoubleVector>.VectorPrintJob createJob(RAbstractDoubleVector vector, int indx, boolean quote, PrintContext printCtx) { + return new DoubleVectorPrintJob(vector, indx, quote, printCtx); + } + + private class DoubleVectorPrintJob extends VectorPrintJob { + + protected DoubleVectorPrintJob(RAbstractDoubleVector vector, int indx, boolean quote, PrintContext printCtx) { + super(vector, indx, quote, printCtx); + } + + @Override + protected DoubleVectorMetrics formatVector(int offs, int len) { + return formatDoubleVector(vector, offs, len, 0, printCtx.parameters()); + } + + @Override + protected void printElement(int i, FormatMetrics fm) throws IOException { + DoubleVectorMetrics dfm = (DoubleVectorMetrics) fm; + String v = DoublePrinter.encodeReal(vector.getDataAt(i), dfm.maxWidth, dfm.d, dfm.e, '.', printCtx.parameters()); + out.print(v); + } + + @Override + protected void printCell(int i, FormatMetrics fm) throws IOException { + printElement(i, fm); + } + + @Override + protected void printEmptyVector() throws IOException { + out.println("numeric(0)"); + } + + } + + public static class DoubleVectorMetrics extends FormatMetrics { + public final int d; + public final int e; + + public DoubleVectorMetrics(int w, int d, int e) { + super(w); + this.d = d; + this.e = e; + } + + } + + public static DoubleVectorMetrics formatDoubleVector(RAbstractDoubleVector x, int offs, int n, int nsmall, PrintParameters pp) { + int left; + int right; + int sleft; + int mnl; + int mxl; + int rgt; + int mxsl; + int mxns; + int wF; + int neg; + int sgn; + int kpower; + int nsig; + boolean roundingwidens; + boolean naflag; + boolean nanflag; + boolean posinf; + boolean neginf; + + // output arguments + int w; + int d; + int e; + + nanflag = false; + naflag = false; + posinf = false; + neginf = false; + neg = 0; + rgt = mxl = mxsl = mxns = RRuntime.INT_MIN_VALUE; + mnl = RRuntime.INT_MAX_VALUE; + + for (int i = 0; i < n; i++) { + double xi = x.getDataAt(i + offs); + if (!RRuntime.isFinite(xi)) { + if (RRuntime.isNA(xi)) { + naflag = true; + } else if (RRuntime.isNAorNaN(xi)) { + nanflag = true; + } else if (xi > 0) { + posinf = true; + } else { + neginf = true; + } + } else { + ScientificDouble sd = DoublePrinter.scientific(xi, pp); + sgn = sd.sgn; + nsig = sd.nsig; + kpower = sd.kpower; + roundingwidens = sd.roundingwidens; + + left = kpower + 1; + if (roundingwidens) { + left--; + } + + sleft = sgn + ((left <= 0) ? 1 : left); /* >= 1 */ + right = nsig - left; /* #{digits} right of '.' ( > 0 often) */ + if (sgn > 0) { + neg = 1; /* if any < 0, need extra space for sign */ + } + + /* Infinite precision "F" Format : */ + if (right > rgt) { + rgt = right; /* max digits to right of . */ + } + if (left > mxl) { + mxl = left; /* max digits to left of . */ + } + if (left < mnl) { + mnl = left; /* min digits to left of . */ + } + if (sleft > mxsl) { + mxsl = sleft; /* + * max left includingimport static + * com.oracle.truffle.r.nodes.builtin.base.printer.Utils.*; + * sign(s) + */ + } + if (nsig > mxns) { + mxns = nsig; /* max sig digits */ + } + } + } + /* + * F Format: use "F" format WHENEVER we use not more space than 'E' and still satisfy + * 'R_print.digits' {but as if nsmall==0 !} + * + * E Format has the form [S]X[.XXX]E+XX[X] + * + * This is indicated by setting *e to non-zero (usually 1) If the additional exponent digit + * is required *e is set to 2 + */ + + /*-- These 'mxsl' & 'rgt' are used in F Format + * AND in the ____ if(.) "F" else "E" ___ below: */ + if (pp.getDigits() == 0) { + rgt = 0; + } + if (mxl < 0) { + mxsl = 1 + neg; /* we use %#w.dg, so have leading zero */ + } + + /* use nsmall only *after* comparing "F" vs "E": */ + if (rgt < 0) { + rgt = 0; + } + wF = mxsl + rgt + (rgt != 0 ? 1 : 0); /* width for F format */ + + /*-- 'see' how "E" Exponential format would be like : */ + e = (mxl > 100 || mnl <= -99) ? 2 /* 3 digit exponent */ : 1; + if (mxns != RRuntime.INT_MIN_VALUE) { + d = mxns - 1; + w = neg + (d != 0 ? 1 : 1) + d + 4 + e; /* width for E format */ + if (wF <= w + pp.getScipen()) { /* Fixpoint if it needs less space */ + e = 0; + if (nsmall > rgt) { + rgt = nsmall; + wF = mxsl + rgt + (rgt != 0 ? 1 : 0); + } + d = rgt; + w = wF; + } /* else : "E" Exponential format -- all done above */ + } else { /* when all x[i] are non-finite */ + w = 0; /* to be increased */ + d = 0; + e = 0; + } + if (naflag && w < pp.getNa_width()) { + w = pp.getNa_width(); + } + if (nanflag && w < 3) { + w = 3; + } + if (posinf && w < 3) { + w = 3; + } + if (neginf && w < 4) { + w = 4; + } + + return new DoubleVectorMetrics(w, d, e); + } + +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/NullPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/NullPrinter.java new file mode 100644 index 0000000000..e91de12c80 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/NullPrinter.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import com.oracle.truffle.r.runtime.RRuntime; + +public final class NullPrinter implements ValuePrinter<Object> { + + public static NullPrinter INSTANCE = new NullPrinter(); + + public void print(Object value, PrintContext printCtx) { + printCtx.output().println(RRuntime.NULL); + } + +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintContext.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintContext.java new file mode 100644 index 0000000000..404481be2a --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintContext.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import java.io.PrintWriter; + +public class PrintContext { + private final ValuePrinterNode pn; + private final PrintParameters params; + private final PrintWriter out; + + public PrintContext(ValuePrinterNode printerNode, PrintParameters parameters, PrintWriter output) { + this.pn = printerNode; + this.params = parameters; + this.out = output; + } + + public PrintParameters parameters() { + return params; + } + + public ValuePrinterNode printerNode() { + return pn; + } + + public PrintWriter output() { + return out; + } + + public PrintContext cloneContext() { + return new PrintContext(pn, params.cloneParameters(), out); + } + +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintJustification.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintJustification.java new file mode 100644 index 0000000000..f192492149 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintJustification.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +public enum PrintJustification { + left, + center, + right, + none +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintParameters.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintParameters.java new file mode 100644 index 0000000000..400901cb85 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintParameters.java @@ -0,0 +1,237 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 1995, 1996 Robert Gentleman and Ross Ihaka + * Copyright (c) 1997-2013, The R Core Team + * Copyright (c) 2016, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +//Transcribed from GnuR, src/include/Print.h + +import com.oracle.truffle.r.nodes.builtin.base.Format; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RString; + +public class PrintParameters { + private int width; + private int na_width; + private int na_width_noquote; + private int digits; + private int scipen; + private int gap; + private boolean quote; + private boolean right; + private int max; + private String na_string; + private String na_string_noquote; + private boolean useSource; + private int cutoff; // for deparsed language objects + + public PrintParameters() { + } + + public PrintParameters(Object digits, boolean quote, Object naPrint, + Object printGap, boolean right, Object max, boolean useSource, boolean noOpt) { + + setDefaults(); + + if (digits != RNull.instance) { + this.digits = RRuntime.asInteger(digits); + if (this.digits == RRuntime.INT_NA || + this.digits < Format.R_MIN_DIGITS_OPT || + this.digits > Format.R_MAX_DIGITS_OPT) { + throw new IllegalArgumentException(String.format("invalid '%s' argument", "digits")); + } + } + + this.quote = quote; + + if (naPrint != RNull.instance) { + // TODO: Although the original code in print.c at line 253 contains the following + // condition, the GnuR application ignores that condition. It was revealed when running + // test com.oracle.truffle.r.test.builtins.TestBuiltin_printdefault, which fails if the + // condition is present complaining about an invalid na.print specification. + // if (!(naPrint instanceof RString) || ((RString) naPrint).getValue().length() < 1) +// throw new IllegalArgumentException(String.format("invalid 'na.print' specification")); + String nav = naPrint.toString(); + if (!"".equals(nav)) { + this.na_string = this.na_string_noquote = ((RString) naPrint).getValue(); + this.na_width = this.na_width_noquote = this.na_string.length(); + } + } + + if (printGap != RNull.instance) { + this.gap = RRuntime.asInteger(printGap); + if (this.gap == RRuntime.INT_NA || this.gap < 0) { + throw new IllegalArgumentException(String.format("'gap' must be non-negative integer")); + } + } + + this.right = right; + + if (max != RNull.instance) { + this.max = RRuntime.asInteger(max); + if (this.max == RRuntime.INT_NA || this.max < 0) { + throw new IllegalArgumentException(String.format("invalid '%s' argument", "max")); + } else if (this.max == RRuntime.INT_MAX_VALUE) { + this.max--; // so we can add + } + } + + this.useSource = useSource; + } + + public PrintParameters cloneParameters() { + PrintParameters cloned = new PrintParameters(); + cloned.na_string = this.na_string; + cloned.na_string_noquote = this.na_string_noquote; + cloned.na_width = this.na_width; + cloned.na_width_noquote = this.na_string_noquote.length(); + cloned.quote = this.quote; + cloned.right = this.right; + cloned.digits = this.digits; + cloned.scipen = this.scipen; + cloned.max = this.max; + cloned.gap = this.gap; + cloned.width = this.width; + cloned.useSource = this.useSource; + cloned.cutoff = this.cutoff; + return cloned; + } + + private void setDefaults() { + this.na_string = RRuntime.STRING_NA; + this.na_string_noquote = "<NA>"; + this.na_width = this.na_string.length(); + this.na_width_noquote = this.na_string_noquote.length(); + this.quote = true; + this.right = false; + this.digits = RRuntime.asInteger(RContext.getInstance().stateROptions.getValue("digits")); + this.scipen = RRuntime.asInteger(RContext.getInstance().stateROptions.getValue("scipen")); + if (this.scipen == RRuntime.INT_NA) { + this.scipen = 0; + } + this.max = RRuntime.asInteger(RContext.getInstance().stateROptions.getValue("max.print")); + if (this.max == RRuntime.INT_NA || this.max < 0) { + this.max = 99999; + } else if (this.max == RRuntime.INT_NA) { + this.max--; // so we can add + } + this.gap = 1; + this.width = RRuntime.asInteger(RContext.getInstance().stateROptions.getValue("width")); + this.useSource = true; + this.cutoff = RRuntime.asInteger(RContext.getInstance().stateROptions.getValue("deparse.cutoff")); + } + + public int getWidth() { + return width; + } + + public void setWidth(int width) { + this.width = width; + } + + public int getNa_width() { + return na_width; + } + + public void setNa_width(int na_width) { + this.na_width = na_width; + } + + public int getNa_width_noquote() { + return na_width_noquote; + } + + public void setNa_width_noquote(int na_width_noquote) { + this.na_width_noquote = na_width_noquote; + } + + public int getDigits() { + return digits; + } + + public void setDigits(int digits) { + this.digits = digits; + } + + public int getScipen() { + return scipen; + } + + public void setScipen(int scipen) { + this.scipen = scipen; + } + + public int getGap() { + return gap; + } + + public void setGap(int gap) { + this.gap = gap; + } + + public boolean getQuote() { + return quote; + } + + public void setQuote(boolean quote) { + this.quote = quote; + } + + public boolean getRight() { + return right; + } + + public void setRight(boolean right) { + this.right = right; + } + + public int getMax() { + return max; + } + + public void setMax(int max) { + this.max = max; + } + + public String getNa_string() { + return na_string; + } + + public void setNa_string(String na_string) { + this.na_string = na_string; + } + + public String getNa_string_noquote() { + return na_string_noquote; + } + + public void setNa_string_noquote(String na_string_noquote) { + this.na_string_noquote = na_string_noquote; + } + + public boolean getUseSource() { + return useSource; + } + + public void setUseSource(boolean useSource) { + this.useSource = useSource; + } + + public int getCutoff() { + return cutoff; + } + + public void setCutoff(int cutoff) { + this.cutoff = cutoff; + } + +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RBufferedWriter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RBufferedWriter.java new file mode 100644 index 0000000000..460a44e314 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RBufferedWriter.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; + +import com.oracle.truffle.r.runtime.conn.StdConnections; + +public class RBufferedWriter extends Writer { + + private final StringWriter w = new StringWriter(); + + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + w.write(cbuf, off, len); + } + + @Override + public void flush() throws IOException { + w.flush(); + } + + public void commit() throws IOException { + StdConnections.getStdout().writeString(w.toString(), false); + } + + @Override + public void close() throws IOException { + w.close(); + } + +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RWriter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RWriter.java new file mode 100644 index 0000000000..a5da7f4618 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RWriter.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import java.io.IOException; +import java.io.Writer; + +import com.oracle.truffle.r.runtime.conn.StdConnections; + +public class RWriter extends Writer { + + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + StdConnections.getStdout().writeString(new String(cbuf, off, len), false); + } + + @Override + public void flush() throws IOException { + } + + @Override + public void close() throws IOException { + } + +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringPrinter.java new file mode 100644 index 0000000000..f64fb64023 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringPrinter.java @@ -0,0 +1,100 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 1995, 1996 Robert Gentleman and Ross Ihaka + * Copyright (c) 1997-2013, The R Core Team + * Copyright (c) 2016, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.util.Arrays; + +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.conn.RConnection; + +//Transcribed from GnuR, src/main/printutils.c + +public final class StringPrinter extends AbstractValuePrinter<String> { + + public static final StringPrinter INSTANCE = new StringPrinter(); + + public static String encode(String value, int w, PrintParameters pp) { + final boolean quote = pp.getQuote(); + final String s; + if (quote) { + if (RRuntime.isNA(value)) { + s = pp.getNa_string(); + } else { + s = RRuntime.quoteString(value); + } + } else { + if (RRuntime.isNA(value)) { + s = pp.getNa_string_noquote(); + } else { + s = value; + } + } + return encode(s, w, pp.getRight() ? PrintJustification.right : PrintJustification.left); + } + + public static String encode(String s, int w, PrintJustification justify) { + // justification + final int b = w - s.length(); // total amount of blanks + int bl = 0; // left blanks + int br = 0; // right blanks + + switch (justify) { + case left: + br = b; + break; + case center: + bl = b / 2; + br = b - bl; + break; + case right: + bl = b; + break; + case none: + break; + } + + StringBuilder sb = new StringBuilder(); + + if (bl > 0) { + char[] sp = new char[bl]; + Arrays.fill(sp, ' '); + sb.append(sp); + } + + sb.append(s); + + if (br > 0) { + char[] sp = new char[br]; + Arrays.fill(sp, ' '); + sb.append(sp); + } + + return sb.toString(); + } + + public static void printString(String s, int w, PrintContext printCtx) { + String outS = encode(s, w, printCtx.parameters()); + printCtx.output().print(outS); + } + + @Override + protected void printValue(String value, PrintContext printCtx) throws IOException { + PrintWriter out = printCtx.output(); + out.print("[1] "); + printString(value, value.length(), printCtx); + out.println(); + } + +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringVectorPrinter.java new file mode 100644 index 0000000000..2c8be4d92f --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringVectorPrinter.java @@ -0,0 +1,115 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 1995, 1996 Robert Gentleman and Ross Ihaka + * Copyright (c) 1997-2013, The R Core Team + * Copyright (c) 2016, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import java.io.IOException; + +import static com.oracle.truffle.r.nodes.builtin.base.printer.Utils.asBlankArg; + +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; + +//Transcribed from GnuR, src/main/format.c + +public final class StringVectorPrinter extends VectorPrinter<RAbstractStringVector> { + + public static final StringVectorPrinter INSTANCE = new StringVectorPrinter(); + + @Override + protected VectorPrinter<RAbstractStringVector>.VectorPrintJob createJob(RAbstractStringVector vector, int indx, boolean quote, PrintContext printCtx) { + return new StringVectorPrintJob(vector, indx, quote, printCtx); + } + + private class StringVectorPrintJob extends VectorPrintJob { + + protected StringVectorPrintJob(RAbstractStringVector vector, int indx, boolean quote, PrintContext printCtx) { + super(vector, indx, quote, printCtx); + } + + @Override + protected FormatMetrics formatVector(int offs, int len) { + int w = formatString(vector, offs, len, quote, printCtx.parameters()); + return new FormatMetrics(w); + } + + @Override + protected void printElement(int i, FormatMetrics fm) throws IOException { + String s = vector.getDataAt(i); + StringPrinter.printString(s, fm.maxWidth, printCtx); + } + + @Override + protected void printCell(int i, FormatMetrics fm) throws IOException { + String s = vector.getDataAt(i); + String outS = StringPrinter.encode(s, fm.maxWidth, printCtx.parameters()); + int g = printCtx.parameters().getGap(); + String fmt = "%" + asBlankArg(g) + "s%s"; + printCtx.output().printf(fmt, "", outS); + } + + @Override + protected void printEmptyVector() throws IOException { + out.println("character(0)"); + } + + @Override + protected void printMatrixColumnLabels(RAbstractStringVector cl, int jmin, int jmax, FormatMetrics[] w) { + if (printCtx.parameters().getRight()) { + for (int j = jmin; j < jmax; j++) { + rightMatrixColumnLabel(cl, j, w[j].maxWidth); + } + } else { + for (int j = jmin; j < jmax; j++) { + leftMatrixColumnLabel(cl, j, w[j].maxWidth); + } + } + } + + @Override + protected int matrixColumnWidthCorrection1() { + return 0; + } + + @Override + protected int matrixColumnWidthCorrection2() { + return printCtx.parameters().getGap(); + } + + } + + public static int formatString(RAbstractStringVector x, int offs, int n, boolean quote, PrintParameters pp) { + int xmax = 0; + int l; + + // output argument + int fieldwidth; + + for (int i = 0; i < n; i++) { + String s = x.getDataAt(offs + i); + String xi = quote ? RRuntime.quoteString(s) : s; + + if (xi == RRuntime.STRING_NA) { + l = quote ? pp.getNa_width() : pp.getNa_width_noquote(); + } else { + l = xi.length(); + } + if (l > xmax) { + xmax = l; + } + } + + fieldwidth = xmax; + + return fieldwidth; + } + +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/Utils.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/Utils.java new file mode 100644 index 0000000000..97f048a159 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/Utils.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import com.oracle.truffle.r.runtime.data.RNull; + +public class Utils { + + public static String snprintf(int size, String format, Object... args) { + String fs = String.format(format, args); + return fs.length() <= size ? fs : fs.substring(0, size); + } + + public static String asBlankArg(int blanks) { + return blanks == 0 ? "" : blanks + ""; + } + + @SuppressWarnings("unchecked") + public static <T> T castTo(Object x) { + if (x instanceof RNull) { + return null; + } else { + return (T) x; + } + } +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinter.java new file mode 100644 index 0000000000..a66b8cbf27 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinter.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import java.io.IOException; + +public interface ValuePrinter<T> { + + void print(T value, PrintContext printCtx) throws IOException; +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java new file mode 100644 index 0000000000..9d2abc010a --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinterNode.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import java.io.IOException; +import java.io.PrintWriter; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.NodeChild; +import com.oracle.truffle.api.dsl.NodeChildren; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.r.nodes.builtin.RBuiltinNode.CastBuilder; +import com.oracle.truffle.r.nodes.builtin.base.Inherits; +import com.oracle.truffle.r.nodes.builtin.base.InheritsNodeGen; +import com.oracle.truffle.r.nodes.builtin.base.IsS4; +import com.oracle.truffle.r.nodes.builtin.base.IsS4NodeGen; +import com.oracle.truffle.r.nodes.builtin.base.IsTypeFunctions.IsArray; +import com.oracle.truffle.r.nodes.builtin.base.IsTypeFunctions.IsList; +import com.oracle.truffle.r.nodes.builtin.base.IsTypeFunctions.IsObject; +import com.oracle.truffle.r.nodes.builtin.base.IsTypeFunctionsFactory.IsArrayNodeGen; +import com.oracle.truffle.r.nodes.builtin.base.IsTypeFunctionsFactory.IsListNodeGen; +import com.oracle.truffle.r.nodes.builtin.base.IsTypeFunctionsFactory.IsObjectNodeGen; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.nodes.RNode; + +@SuppressWarnings("unused") +@NodeChildren({@NodeChild(value = "operand", type = RNode.class), @NodeChild(value = "digits", type = RNode.class), @NodeChild(value = "quote", type = RNode.class), + @NodeChild(value = "naPrint", type = RNode.class), @NodeChild(value = "printGap", type = RNode.class), @NodeChild(value = "right", type = RNode.class), + @NodeChild(value = "max", type = RNode.class), @NodeChild(value = "useSource", type = RNode.class), @NodeChild(value = "noOpt", type = RNode.class), + @NodeChild(value = "max", type = RNode.class) +}) +public abstract class ValuePrinterNode extends RNode { + + @Child IsArray isArrayBuiltIn = IsArrayNodeGen.create(null, null, null); + @Child IsList isListBuiltIn = IsListNodeGen.create(null, null, null); + @Child Inherits inheritsBuiltIn = InheritsNodeGen.create(null, null, null); + @Child IsS4 isS4BuiltIn = IsS4NodeGen.create(null, null, null); + @Child IsObject isObjectBuiltIn = IsObjectNodeGen.create(null, null, null); + + public boolean isArray(Object o) { + return RRuntime.fromLogical(isArrayBuiltIn.execute(o)); + } + + public boolean isList(Object o) { + return RRuntime.fromLogical(isListBuiltIn.execute(o)); + } + + public boolean inherits(Object o, Object what, byte which) { + return RRuntime.fromLogical((Byte) inheritsBuiltIn.execute(o, what, which)); + } + + public boolean isS4(Object o) { + return RRuntime.fromLogical(isS4BuiltIn.execute(o)); + } + + public boolean isObject(Object o) { + return RRuntime.fromLogical(isObjectBuiltIn.execute(o)); + } + + public abstract Object executeString(Object o, Object digits, boolean quote, Object naPrint, Object printGap, boolean right, Object max, boolean useSource, boolean noOpt); + + // TODO: More specializations should be added + + @TruffleBoundary + @Specialization + protected String prettyPrint(Object o, Object digits, boolean quote, Object naPrint, Object printGap, boolean right, Object max, boolean useSource, boolean noOpt) { + // Until the new code is fully functional we have to use RBufferedWriter. In case + // an exception is thrown by the new code, the content accumulated in the + // RBufferedWriter is not printed and the old code is invoked to print the value. When + // the new code stabilizes the RBufferedWriter will be replaced by RWriter. + try (RBufferedWriter rw = new RBufferedWriter(); PrintWriter pw = new PrintWriter(rw)) { + // try (RWriter rw = new RWriter(); PrintWriter pw = new PrintWriter(rw)) { + PrintContext printCtx = new PrintContext(this, new PrintParameters(digits, quote, naPrint, printGap, + right, max, useSource, noOpt), pw); + ValuePrinters.printValue(o, printCtx); + pw.flush(); + rw.commit(); + return null; + } catch (IOException ex) { + throw RError.error(this, RError.Message.GENERIC, ex.getMessage()); + } + } + +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinters.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinters.java new file mode 100644 index 0000000000..67c643551b --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinters.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import com.oracle.truffle.r.runtime.data.RDoubleVector; +import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; + +public final class ValuePrinters implements ValuePrinter<Object> { + + private final Map<Class<?>, ValuePrinter<?>> printers = new HashMap<>(); + + private static final ValuePrinters INSTANCE = new ValuePrinters(); + + private ValuePrinters() { + printers.put(String.class, StringPrinter.INSTANCE); + printers.put(Double.class, DoublePrinter.INSTANCE); + } + + public static void printValue(Object x, PrintContext printCtx) throws IOException { + INSTANCE.print(x, printCtx); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public void print(Object x, PrintContext printCtx) throws IOException { + if (x == null) { + NullPrinter.INSTANCE.print(null, printCtx); + } else { + ValuePrinter printer = printers.get(x.getClass()); + if (printer == null) { + if (x instanceof RAbstractStringVector) { + printer = StringVectorPrinter.INSTANCE; + } else if (x instanceof RAbstractDoubleVector) { + printer = DoubleVectorPrinter.INSTANCE; + } else { + throw new UnsupportedOperationException("TODO"); + } + } + printer.print(x, printCtx); + } + } + +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java new file mode 100644 index 0000000000..9ccd9d671c --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java @@ -0,0 +1,633 @@ +/* + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html + * + * Copyright (c) 1995, 1996 Robert Gentleman and Ross Ihaka + * Copyright (c) 1997-2013, The R Core Team + * Copyright (c) 2016, Oracle and/or its affiliates + * + * All rights reserved. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import java.io.IOException; +import java.io.PrintWriter; + +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.RAttributeProfiles; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RString; +import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +import static com.oracle.truffle.r.nodes.builtin.base.printer.Utils.*; + +//Transcribed from GnuR, src/main/print.c, src/main/printarray.c, src/main/printvector.c + +public abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePrinter<T> { + + private static RAttributeProfiles dummyAttrProfiles = RAttributeProfiles.create(); + + @Override + protected void printValue(T vector, PrintContext printCtx) throws IOException { + printVector(vector, 1, printCtx.parameters().getQuote(), printCtx); + } + + public void printVector(T vector, int indx, boolean quote, PrintContext printCtx) throws IOException { + createJob(vector, indx, quote, printCtx).print(); + } + + protected abstract VectorPrintJob createJob(T vector, int indx, boolean quote, PrintContext printCtx); + + protected enum JobMode { + nonEmpty, + empty, + named, + namedEmpty, + matrix, + array + } + + protected static class FormatMetrics { + int maxWidth; + + public FormatMetrics(int maxWidth) { + super(); + this.maxWidth = maxWidth; + } + + } + + private static final int R_MIN_LBLOFF = 2; + + protected abstract class VectorPrintJob { + + protected final T vector; + protected final int n; + protected final int n_pr; + protected final int indx; + protected final int labwidth; + protected final boolean quote; + protected final PrintContext printCtx; + protected final PrintWriter out; + protected final JobMode jobMode; + protected final RAbstractStringVector names; + protected final String title; + protected final MatrixDimNames matrixDimNames; + protected final RAbstractIntVector dims; + + protected VectorPrintJob(T vector, int indx, boolean quote, PrintContext printCtx) { + this.vector = vector; + this.indx = indx; + this.quote = quote; + + MatrixDimNames mdn = null; + + Object dimAttr = vector.getAttr(dummyAttrProfiles, RRuntime.DIM_ATTR_KEY); + if (dimAttr instanceof RAbstractIntVector) { + dims = (RAbstractIntVector) dimAttr; + if (dims.getLength() == 1) { + RList t = Utils.<RList> castTo(vector.getAttr(dummyAttrProfiles, RRuntime.DIMNAMES_ATTR_KEY)); + if (t != null && t.getDataAt(0) != null) { + RAbstractStringVector nn = toStringVector(t.getAttr(dummyAttrProfiles, RRuntime.NAMES_ATTR_KEY)); + + if (nn != null) { + title = nn.getDataAt(0); + } else { + title = null; + } + + jobMode = vector.getLength() == 0 ? JobMode.namedEmpty : JobMode.named; + names = toStringVector(t.getDataAt(0)); + } else { + title = null; + names = null; + jobMode = vector.getLength() == 0 ? JobMode.empty : JobMode.nonEmpty; + } + } else if (dims.getLength() == 2) { + mdn = getMatrixDimnames(vector); + title = null; + names = null; + jobMode = JobMode.matrix; + } else { + title = null; + names = null; + jobMode = JobMode.array; +// SEXP dimnames; +// dimnames = GetArrayDimnames(s); +// printArray(s, t, R_print.quote, R_print.right, dimnames); + } + } else { + dims = null; + Object namesAttr = Utils.castTo(vector.getAttr(dummyAttrProfiles, RRuntime.NAMES_ATTR_KEY)); + if (namesAttr != null) { + if (vector.getLength() > 0) { + names = toStringVector(namesAttr); + jobMode = JobMode.named; + } else { + names = null; + jobMode = JobMode.namedEmpty; + } + } else if (vector.getLength() > 0) { + jobMode = JobMode.nonEmpty; + names = null; + } else { + jobMode = JobMode.empty; + names = null; + } + title = null; + } + + this.printCtx = printCtx.cloneContext(); + this.printCtx.parameters().setQuote(quote); + if (jobMode == JobMode.named) { + this.printCtx.parameters().setRight(true); + } + this.out = this.printCtx.output(); + this.n = vector.getLength(); + int max = printCtx.parameters().getMax(); + this.n_pr = (n <= max + 1) ? n : max; + this.labwidth = indexWidth(n) + 2; + this.matrixDimNames = mdn; + } + + public void print() throws IOException { + switch (jobMode) { + case empty: + printEmptyVector(); + break; + case nonEmpty: + printNonEmptyVector(); + break; + case named: + printNamedVector(); + break; + case namedEmpty: + printNamedEmptyVector(); + break; + case matrix: + printMatrix(); + break; + case array: + throw new UnsupportedOperationException("TODO"); + } + } + + private void printNamedEmptyVector() throws IOException { + out.print("named "); + printEmptyVector(); + } + + private void printNonEmptyVector() throws IOException { + final int gap = printCtx.parameters().getGap(); + final int totalWidth = printCtx.parameters().getWidth(); + + int width = 0; + + width = doLab(0); + + FormatMetrics fm = formatVector(0, n); + final int w = fm.maxWidth; + + for (int i = 0; i < n_pr; i++) { + if (i > 0 && width + w + gap > totalWidth) { + out.println(); + width = doLab(i); + } + out.printf("%" + asBlankArg(gap) + "s", ""); + printElement(i, fm); + width += w + gap; + } + out.println(); + if (n_pr < n) { + out.printf(" [ reached getOption(\"max.print\") -- omitted %d entries ]\n", n - n_pr); + } + } + + private void printNamedVector() throws IOException { + if (title != null) { + out.println(title); + } + + int i; + int j; + int k; + int nlines; + int nperline; + int wn; + + FormatMetrics fm = formatVector(0, n); + + PrintParameters pp = printCtx.parameters(); + + wn = StringVectorPrinter.formatString(names, 0, n, false, pp); + if (fm.maxWidth < wn) { + fm.maxWidth = wn; + } + + final int w = fm.maxWidth; + + nperline = pp.getWidth() / (w + pp.getGap()); + if (nperline <= 0) { + nperline = 1; + } + nlines = n / nperline; + if (n % nperline != 0) { + nlines += 1; + } + + int gap = pp.getGap(); + PrintContext namesPrintCtx = printCtx.cloneContext(); + namesPrintCtx.parameters().setQuote(false); + namesPrintCtx.parameters().setRight(true); + for (i = 0; i < nlines; i++) { + if (i > 0) { + out.println(); + } + for (j = 0; j < nperline && (k = i * nperline + j) < n; j++) { + StringPrinter.printString(names.getDataAt(k), w, namesPrintCtx); + out.printf("%" + asBlankArg(gap) + "s", ""); + } + out.println(); + for (j = 0; j < nperline && (k = i * nperline + j) < n; j++) { + printElement(k, fm); + out.printf("%" + asBlankArg(gap) + "s", ""); + } + } + out.println(); + } + + private void printMatrix() throws IOException { + printMatrix(0); + } + + private void printMatrix(int offset) throws IOException { + PrintParameters pp = printCtx.parameters(); + + RAbstractStringVector rl = matrixDimNames.rl; + RAbstractStringVector cl = matrixDimNames.cl; + String rn = matrixDimNames.rn; + String cn = matrixDimNames.cn; + int r = dims.getDataAt(0); + int c = dims.getDataAt(1); + int r_pr; + + /* PR#850 */ + if (rl != null && r > rl.getLength()) { + throw RError.error(printCtx.printerNode(), RError.Message.GENERIC, "too few row labels"); + } + if (cl != null && c > cl.getLength()) { + throw RError.error(printCtx.printerNode(), RError.Message.GENERIC, "too few column labels"); + } + if (r == 0 && c == 0) { // FIXME? names(dimnames(.)) : + out.println("<0 x 0 matrix>"); + return; + } + r_pr = r; + if (c > 0 && pp.getMax() / c < r) { + /* using floor(), not ceil(), since 'c' could be huge: */ + r_pr = pp.getMax() / c; + } + + printMatrix(offset, r_pr, r, c, rl, cl, rn, cn, true); + + if (r_pr < r) { + out.printf(" [ reached getOption(\"max.print\") -- omitted %d rows ]\n", r - r_pr); + } + + } + + private void printMatrix(int offset, int r_pr, int r, int c, + RAbstractStringVector rl, RAbstractStringVector cl, String rn, String cn, + boolean print_ij) throws IOException { + // _PRINT_INIT_rl_rn + + PrintParameters pp = printCtx.parameters(); + + FormatMetrics[] w = new FormatMetrics[c]; + int width; + int rlabw = -1; + int clabw = -1; + int i; + int j; + int jmin = 0; + int jmax = 0; + int lbloff = 0; + + if (rl != null) { + rlabw = StringVectorPrinter.formatString(rl, 0, r, false, pp); + } else { + rlabw = indexWidth(r + 1) + 3; + } + + if (rn != null) { + int rnw = rn.length(); + if (rnw < rlabw + R_MIN_LBLOFF) { + lbloff = R_MIN_LBLOFF; + } else { + lbloff = rnw - rlabw; + } + + rlabw += lbloff; + } + + // define _COMPUTE_W2_(_FORMAT_j_, _LAST_j_) + /* compute w[j] = column-width of j(+1)-th column : */ + for (j = 0; j < c; j++) { + if (print_ij) { + w[j] = formatVector(offset + j * r, r); + } else { + w[j] = formatVector(0, 0); + } + + if (cl != null) { + String clj = cl.getDataAt(j); + if (RRuntime.isNA(clj)) { + clabw = pp.getNa_width_noquote(); + } else { + clabw = clj.length(); + } + } else { + clabw = indexWidth(j + 1) + 3; + } + + if (w[j].maxWidth < clabw) { + w[j].maxWidth = clabw; + } + + w[j].maxWidth += matrixColumnWidthCorrection1(); + } + + // _PRINT_MATRIX_(_W_EXTRA_, DO_COLUMN_LABELS, ENCODE_I_J) + + int wExtra = matrixColumnWidthCorrection2(); + if (c == 0) { + printMatrixRowLab(cn, rn, rlabw); + for (i = 0; i < r; i++) { + matrixRowLabel(rl, i, rlabw, lbloff); + } + out.println(); + } else { + while (jmin < c) { + /* print columns jmin:(jmax-1) where jmax has to be determined first */ + + width = rlabw; + /* initially, jmax = jmin */ + do { + width += w[jmax].maxWidth + wExtra; + jmax++; + } while (jmax < c && width + w[jmax].maxWidth + wExtra < pp.getWidth()); + + printMatrixRowLab(cn, rn, rlabw); + + printMatrixColumnLabels(cl, jmin, jmax, w); + + for (i = 0; i < r_pr; i++) { + matrixRowLabel(rl, i, rlabw, lbloff); /* starting with an "\n" */ + if (print_ij) { + for (j = jmin; j < jmax; j++) { + printCell(i + j * r, w[j]); + } + } + } + out.println(); + jmin = jmax; + } + } + } + + protected void printMatrixColumnLabels(RAbstractStringVector cl, int jmin, int jmax, FormatMetrics[] w) { + // define STD_ColumnLabels + for (int j = jmin; j < jmax; j++) { + matrixColumnLabel(cl, j, w[j].maxWidth); + } + } + + private void printMatrixRowLab(String cn, String rn, int rlabw) { + // _PRINT_ROW_LAB + if (cn != null) { + String fmt = "%" + asBlankArg(rlabw) + "s%s\n"; + out.printf(fmt, "", cn); + } + if (rn != null) { + String fmt = "%" + asBlankArg(-rlabw) + "s"; + out.printf(fmt, rn); + } else { + String fmt = "%" + asBlankArg(rlabw) + "s"; + out.printf(fmt, ""); + } + } + + private void matrixColumnLabel(RAbstractStringVector cl, int j, int w) { + PrintParameters pp = printCtx.parameters(); + + if (cl != null) { + String tmp = cl.getDataAt(j); + int l = (RRuntime.isNA(tmp)) ? pp.getNa_width_noquote() : tmp.length(); + int gap = w - l; + String fmt = "%" + asBlankArg(gap) + "s%s"; + + PrintParameters pp2 = printCtx.parameters().cloneParameters(); + pp2.setQuote(false); + pp2.setRight(false); + out.printf(fmt, "", StringPrinter.encode(tmp, l, pp2)); + } else { + int gap = w - indexWidth(j + 1) - 3; + String fmt = "%" + asBlankArg(gap) + "s[,%d]"; + out.printf(fmt, "", j + 1); + } + } + + protected void rightMatrixColumnLabel(RAbstractStringVector cl, int j, int w) { + PrintParameters pp = printCtx.parameters(); + + if (cl != null) { + String tmp = cl.getDataAt(j); + int l = (RRuntime.isNA(tmp)) ? pp.getNa_width_noquote() : tmp.length(); + /* + * This does not work correctly at least on FC3 Rprintf("%*s", R_print.gap+w, + * EncodeString(tmp, l, 0, Rprt_adj_right)); + */ + int g = pp.getGap() + w - l; + String fmt = "%" + asBlankArg(g) + "s%s"; + + PrintParameters pp2 = printCtx.parameters().cloneParameters(); + pp2.setQuote(false); + pp2.setRight(true); + out.printf(fmt, "", StringPrinter.encode(tmp, l, pp2)); + } else { + String g1 = asBlankArg(pp.getGap()); + String g2 = asBlankArg(w - indexWidth(j + 1) - 3); + String fmt = "%" + g1 + "s[,%d]%" + g2 + "s"; + out.printf(fmt, "", j + 1, ""); + } + } + + protected void leftMatrixColumnLabel(RAbstractStringVector cl, int j, int w) { + PrintParameters pp = printCtx.parameters(); + + if (cl != null) { + String tmp = cl.getDataAt(j); + int l = (RRuntime.isNA(tmp)) ? pp.getNa_width_noquote() : tmp.length(); + String g1 = asBlankArg(pp.getGap()); + String g2 = asBlankArg(w - l); + String fmt = "%" + g1 + "s%s%" + g2 + "s"; + + PrintParameters pp2 = printCtx.parameters().cloneParameters(); + pp2.setQuote(false); + pp2.setRight(false); + out.printf(fmt, "", StringPrinter.encode(tmp, l, pp2), ""); + } else { + String g1 = asBlankArg(pp.getGap()); + String g2 = asBlankArg(w - indexWidth(j + 1) - 3); + String fmt = "%" + g1 + "s[,%d]%" + g2 + "s"; + out.printf(fmt, "", j + 1, ""); + } + } + + protected void matrixRowLabel(RAbstractStringVector rl, int i, int rlabw, int lbloff) { + PrintParameters pp = printCtx.parameters(); + + if (rl != null) { + String tmp = rl.getDataAt(i); + int l = (RRuntime.isNA(tmp)) ? pp.getNa_width_noquote() : tmp.length(); + String gap = asBlankArg(rlabw - l - lbloff); + String fmt = "\n%" + asBlankArg(lbloff) + "s%s%" + gap + "s"; + + PrintParameters pp2 = printCtx.parameters().cloneParameters(); + pp2.setQuote(false); + pp2.setRight(false); + String s = StringPrinter.encode(tmp, l, pp2); + out.printf(fmt, "", s, ""); + } else { + String gap = asBlankArg(rlabw - 3 - indexWidth(i + 1)); + String fmt = "\n%" + gap + "s[%d,]"; + out.printf(fmt, "", i + 1); + } + } + + /** + * @param offs the beginning offset in the internal store + * @param len the number of elements to involve in formatting + * @return the format metrics containing the width of the widest vector element and possibly + * other data type specific metrics + */ + protected abstract FormatMetrics formatVector(int offs, int len); + + /** + * Prints the i-th vector element. + * + * @param i the element index (zero-based) + * @param fm the format metrics produced by the corresponding <code>formatVector</code> + * invocation + * @throws IOException + */ + protected abstract void printElement(int i, FormatMetrics fm) throws IOException; + + /** + * Prints the matrix cell at position (i,j). + * + * @param i the index (zero-based) of the cell in the raw data store + * @param fm the format metrics produced by the corresponding <code>formatVector</code> + * invocation + * @throws IOException + */ + protected abstract void printCell(int i, FormatMetrics fm) throws IOException; + + protected int matrixIndividualCellColumnWidthCorrection() { + return 0; + } + + protected int matrixColumnWidthCorrection1() { + return printCtx.parameters().getGap(); + } + + protected int matrixColumnWidthCorrection2() { + return 0; + } + + private int doLab(int i) { + if (indx > 0) { + printVectorIndex(i + 1, labwidth, out); + return labwidth; + } else { + return 0; + } + } + + protected abstract void printEmptyVector() throws IOException; + + } + + private static void printVectorIndex(int i, int w, PrintWriter out) { + /* print index label "[`i']" , using total width `w' (left filling blanks) */ + // out.printf("%*s[%ld]", w - indexWidth(i) - 2, "", i); + String blanks = asBlankArg(w - indexWidth(i) - 2); + String fmt = "%" + blanks + "s[%d]"; + out.printf(fmt, "", i); + } + + private static int indexWidth(int n) { + return (int) (Math.log10(n + 0.5) + 1); + } + + private static final class MatrixDimNames { + final RAbstractStringVector rl; + final RAbstractStringVector cl; + final String rn; + final String cn; + + private MatrixDimNames(RAbstractStringVector rl, RAbstractStringVector cl, String rn, String cn) { + super(); + this.rl = rl; + this.cl = cl; + this.rn = rn; + this.cn = cn; + } + + } + + private static MatrixDimNames getMatrixDimnames(RAbstractVector x) { + // output parameters + RAbstractStringVector rl; + RAbstractStringVector cl; + String rn; + String cn; + + RList dimnames = Utils.<RList> castTo(x.getAttr(dummyAttrProfiles, RRuntime.DIMNAMES_ATTR_KEY)); + + if (dimnames == null) { + rl = null; + cl = null; + rn = null; + cn = null; + } else { + rl = getDimNamesAt(dimnames, 0); + cl = getDimNamesAt(dimnames, 1); + RAbstractStringVector nn = Utils.<RAbstractStringVector> castTo(dimnames.getAttr(dummyAttrProfiles, RRuntime.NAMES_ATTR_KEY)); + if (nn == null) { + rn = null; + cn = null; + } else { + rn = nn.getDataAt(0); + cn = nn.getDataAt(1); + } + } + + return new MatrixDimNames(rl, cl, rn, cn); + } + + private static RAbstractStringVector getDimNamesAt(RList dimNames, int dimLevel) { + return toStringVector(dimNames.getDataAt(dimLevel)); + } + + private static RAbstractStringVector toStringVector(Object o) { + if (o instanceof String) { + return RString.valueOf((String) o); + } + return Utils.<RAbstractStringVector> castTo(o); + } +} 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 ca7ae5588d..f3221276f6 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 @@ -154,6 +154,10 @@ public class RRuntime { public static final String R_LOAD_METHOD_NAME = "loadMethod"; public static final String R_DOT_METHODS = ".Methods"; public static final String R_SOURCE = "source"; + public static final String R_COMMENT = "comment"; + public static final String R_SRCREF = "srcref"; + public static final String R_WHOLE_SRCREF = "wholeSrcref"; + public static final String R_SRCFILE = "srcfile"; public static final String NULL = "NULL"; public static final String UNBOUND = "UNBOUND"; 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 f8a032a818..4b8a58d204 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 @@ -19018,6 +19018,10 @@ null.deviance deviance #argv <- structure(list(x = 0.04, digits = 3, nsmall = 3), .Names = c('x', 'digits', 'nsmall'));do.call('format', argv) [1] "0.040" +##com.oracle.truffle.r.test.builtins.TestBuiltin_format.testformat57 +#x <- c(1.0,2.0);names(x) <- c("x","y");argv <- list(x, FALSE, NULL, 0L, NULL, 0L, FALSE, FALSE);names(.Internal(format(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]], argv[[8]]))) +[1] "x" "y" + ##com.oracle.truffle.r.test.builtins.TestBuiltin_format.testformat6 #argv <- list(structure(c(47.97, 57.9, 74.76, 868.88), .Names = c('<none>', '- x4', '- x2', '- x1')), FALSE, 5L, 0L, NULL, 3L, TRUE, NA); .Internal(format(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]], argv[[8]])) <none> - x4 - x2 - x1 diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_format.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_format.java index e9c6197361..0cc0bf0c29 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_format.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_format.java @@ -13,6 +13,7 @@ package com.oracle.truffle.r.test.builtins; import org.junit.*; import com.oracle.truffle.r.test.*; +import com.sun.source.tree.AssertTree; // Checkstyle: stop line length check public class TestBuiltin_format extends TestBase { @@ -183,7 +184,8 @@ public class TestBuiltin_format extends TestBase { @Test public void testformat33() { - assertEval(Ignored.Unknown, "argv <- list(0+1i, TRUE, NULL, 0L, NULL, 3L, TRUE, NA); .Internal(format(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]], argv[[8]]))"); + assertEval(Ignored.Unknown, + "argv <- list(0+1i, TRUE, NULL, 0L, NULL, 3L, TRUE, NA); .Internal(format(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]], argv[[8]]))"); } @Test @@ -307,6 +309,15 @@ public class TestBuiltin_format extends TestBase { assertEval(Ignored.Unknown, "argv <- structure(list(x = 0.04, digits = 3, nsmall = 3), .Names = c('x', 'digits', 'nsmall'));do.call('format', argv)"); } + /** + * This test checks whether the names of double values in a vector are present in the formatted + * output. + */ + @Test + public void testformat57() { + assertEval("x <- c(1.0,2.0);names(x) <- c(\"x\",\"y\");argv <- list(x, FALSE, NULL, 0L, NULL, 0L, FALSE, FALSE);names(.Internal(format(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]], argv[[8]])))"); + } + public void testFormat() { assertEval("{ format(7) }"); assertEval("{ format(7.42) }"); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleArithmetic.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleArithmetic.java index 546d524198..f92fd6c506 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleArithmetic.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleArithmetic.java @@ -107,7 +107,8 @@ public class TestSimpleArithmetic extends TestBase { @Test /** - * FIXME These expressions evaluate correctly in the shell but produce 1+0i in unit test environment + * FIXME These expressions evaluate correctly in the shell but produce 1+0i in unit test + * environment */ public void testScalarsComplexIgnore() { assertEval("{ (1+2i)^(-2) }"); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRFFIPackage.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRFFIPackage.java index 46b61ff2fa..08fd9a2102 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRFFIPackage.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/rpackages/TestRFFIPackage.java @@ -23,6 +23,7 @@ package com.oracle.truffle.r.test.rpackages; import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -35,14 +36,28 @@ public class TestRFFIPackage extends TestRPackages { private static final String[] TEST_PACKAGES = new String[]{"testrffi"}; + @Override + public void beforeTest() { + // TODO Auto-generated method stub + super.beforeTest(); + setupInstallTestPackages(TEST_PACKAGES); + } + + @Override + public void afterTest() { + // TODO Auto-generated method stub + super.afterTest(); + tearDownUninstallTestPackages(TEST_PACKAGES); + } + @BeforeClass public static void setupInstallMyTestPackages() { - setupInstallTestPackages(TEST_PACKAGES); +// setupInstallTestPackages(TEST_PACKAGES); } @AfterClass public static void tearDownUninstallMyTestPackages() { - tearDownUninstallTestPackages(TEST_PACKAGES); +// tearDownUninstallTestPackages(TEST_PACKAGES); } @Test @@ -50,8 +65,9 @@ public class TestRFFIPackage extends TestRPackages { assertEval(TestBase.template("{ library(\"testrffi\", lib.loc = \"%0\"); r1 <- rffi.addInt(2L, 3L); detach(\"package:testrffi\"); list(r1) }", new String[]{packagePaths.rpackagesLibs.toString()})); assertEval(TestBase.template( - "{ library(\"testrffi\", lib.loc = \"%0\"); r1 <- rffi.addInt(2L, 3L); r2 <- rffi.addDouble(2, 3); v <- rffi.populateIntVector(5); v2 <- rffi.dotCModifiedArguments(c(0,1,2,3)); " - + "detach(\"package:testrffi\"); list(r1, r2, v, v2) }", new String[]{packagePaths.rpackagesLibs.toString()})); + "{ library(\"testrffi\", lib.loc = \"%0\"); r1 <- rffi.addInt(2L, 3L); r2 <- rffi.addDouble(2, 3); v <- rffi.populateIntVector(5); v2 <- rffi.dotCModifiedArguments(c(0,1,2,3)); " + + "detach(\"package:testrffi\"); list(r1, r2, v, v2) }", + new String[]{packagePaths.rpackagesLibs.toString()})); } @Test diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides index e914bfe324..79381b6535 100644 --- a/mx.fastr/copyrights/overrides +++ b/mx.fastr/copyrights/overrides @@ -688,3 +688,10 @@ com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleV com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/data/tree2/incx.r,no.copyright com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/simple/data/tree2/setx.r,no.copyright com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java,purdue.copyright +com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AttributesPrinter.java,gnu_r_gentleman_ihaka2.copyright +com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoublePrinter.java,gnu_r_gentleman_ihaka2.copyright +com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java,gnu_r_gentleman_ihaka2.copyright +com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrintParameters.java,gnu_r_gentleman_ihaka2.copyright +com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringPrinter.java,gnu_r_gentleman_ihaka2.copyright +com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringVectorPrinter.java,gnu_r_gentleman_ihaka2.copyright +com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java,gnu_r_gentleman_ihaka2.copyright \ No newline at end of file diff --git a/mx.fastr/mx_fastr.py b/mx.fastr/mx_fastr.py index 75b81ec0ea..cc027597e6 100644 --- a/mx.fastr/mx_fastr.py +++ b/mx.fastr/mx_fastr.py @@ -149,6 +149,9 @@ def setREnvironment(): if not os.environ.has_key('R_HOME'): os.environ['R_HOME'] = _fastr_suite.dir + # Make sure that native code formats numbers consistently + os.environ['LC_NUMERIC'] = 'C' + osname = platform.system() if osname != 'Darwin': lib_env = 'LD_LIBRARY_PATH' -- GitLab