diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java index ed08560e6b131206d1d416026031cdf0a9c24215..7c242944350bfebdceda6e44619e119485e7d8c3 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java @@ -438,7 +438,7 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { // This checks for the specific structure of replacements RLanguage replacement = ReplacementDispatchNode.getRLanguage(rl); RLanguage elem = replacement == null ? rl : replacement; - String string = RDeparse.deparse(elem, RDeparse.DEFAULT_Cutoff, true, RDeparse.KEEPINTEGER, -1); + String string = RDeparse.deparse(elem, RDeparse.DEFAULT_CUTOFF, true, RDeparse.KEEPINTEGER, -1); return string.split("\n")[0]; } diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java index 7b91b6f22401363b844fb8316586e10d63202c20..321e133d8f18d7864f4caa78057a81c77231e6f1 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguage.java @@ -146,7 +146,7 @@ public final class TruffleRLanguage extends TruffleLanguage<RContext> implements return (String) unwrapped; } if (unwrapped instanceof RTypedValue) { - return RDeparse.deparse(unwrapped); + return RDeparse.deparse(unwrapped, RDeparse.MAX_CUTOFF, true, RDeparse.KEEPINTEGER, -1, 1024 * 1024); } return RRuntime.toString(unwrapped); } diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REmptyMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REmptyMR.java new file mode 100644 index 0000000000000000000000000000000000000000..99277bbbcfbee60a210c5d0eacf8c530faa4dae0 --- /dev/null +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REmptyMR.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.engine.interop; + +import com.oracle.truffle.api.interop.CanResolve; +import com.oracle.truffle.api.interop.MessageResolution; +import com.oracle.truffle.api.interop.Resolve; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.engine.TruffleRLanguage; +import com.oracle.truffle.r.runtime.data.REmpty; + +@MessageResolution(receiverType = REmpty.class, language = TruffleRLanguage.class) +public class REmptyMR { + + @Resolve(message = "IS_BOXED") + public abstract static class REmptyIsBoxedNode extends Node { + protected Object access(@SuppressWarnings("unused") REmpty receiver) { + return false; + } + } + + @Resolve(message = "HAS_SIZE") + public abstract static class REmptyHasSizeNode extends Node { + protected Object access(@SuppressWarnings("unused") REmpty receiver) { + return false; + } + } + + @Resolve(message = "IS_NULL") + public abstract static class REmptyIsNullNode extends Node { + protected Object access(@SuppressWarnings("unused") REmpty receiver) { + return false; + } + } + + @CanResolve + public abstract static class REmptyCheck extends Node { + + protected static boolean test(TruffleObject receiver) { + return receiver instanceof REmpty; + } + } +} diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java index 53949ae75dfacdee0e86c8c99d7777dd4d1c1589..fa203c367ab06940717e8f66f02b92fb8910150b 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RForeignAccessFactoryImpl.java @@ -35,16 +35,18 @@ import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.context.RForeignAccessFactory; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RDouble; +import com.oracle.truffle.r.runtime.data.REmpty; import com.oracle.truffle.r.runtime.data.RExternalPtr; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RInteger; import com.oracle.truffle.r.runtime.data.RInteropScalar; import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RPairList; -import com.oracle.truffle.r.runtime.data.RS4Object; import com.oracle.truffle.r.runtime.data.RPromise; +import com.oracle.truffle.r.runtime.data.RS4Object; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RTruffleObject; import com.oracle.truffle.r.runtime.data.RUnboundValue; @@ -127,6 +129,10 @@ public final class RForeignAccessFactoryImpl implements RForeignAccessFactory { return ActiveBindingMRForeign.ACCESS; } else if (obj instanceof RInteropScalar) { return RInteropScalarMRForeign.ACCESS; + } else if (obj instanceof RMissing) { + return RMissingMRForeign.ACCESS; + } else if (obj instanceof REmpty) { + return REmptyMRForeign.ACCESS; } else { if (obj instanceof RAbstractVector) { diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RMissingMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RMissingMR.java new file mode 100644 index 0000000000000000000000000000000000000000..656843ed0c421fa4281d00467a90ca850a28203d --- /dev/null +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RMissingMR.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.engine.interop; + +import com.oracle.truffle.api.interop.CanResolve; +import com.oracle.truffle.api.interop.MessageResolution; +import com.oracle.truffle.api.interop.Resolve; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.engine.TruffleRLanguage; +import com.oracle.truffle.r.runtime.data.RMissing; + +@MessageResolution(receiverType = RMissing.class, language = TruffleRLanguage.class) +public class RMissingMR { + + @Resolve(message = "IS_BOXED") + public abstract static class RMissingIsBoxedNode extends Node { + protected Object access(@SuppressWarnings("unused") RMissing receiver) { + return false; + } + } + + @Resolve(message = "HAS_SIZE") + public abstract static class RMissingHasSizeNode extends Node { + protected Object access(@SuppressWarnings("unused") RMissing receiver) { + return false; + } + } + + @Resolve(message = "IS_NULL") + public abstract static class RMissingIsNullNode extends Node { + protected Object access(@SuppressWarnings("unused") RMissing receiver) { + return false; + } + } + + @CanResolve + public abstract static class RMissingCheck extends Node { + + protected static boolean test(TruffleObject receiver) { + return receiver instanceof RMissing; + } + } +} diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java index f76be777345451de573b7888e29b873a5e3065d9..ece1e6e7b936fc80923e638d3442b69f5492dd5d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsCharacter.java @@ -74,7 +74,7 @@ public abstract class AsCharacter extends RBuiltinNode.Arg2 { } else if (elem instanceof RStringVector && ((RStringVector) elem).getLength() == 1) { data[i] = ((RStringVector) elem).getDataAt(0); } else { - data[i] = RDeparse.deparse(elem, RDeparse.MAX_Cutoff, true, RDeparse.SIMPLEDEPARSE, -1); + data[i] = RDeparse.deparse(elem, RDeparse.MAX_CUTOFF, true, RDeparse.SIMPLEDEPARSE, -1); } if (RRuntime.isNA(data[i])) { complete = RDataFactory.INCOMPLETE_VECTOR; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index eb9ccf0a2de6fad41246661226886de25129841d..2030c3ecb77f0d70debd5bc68b326daa7d802d3c 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -102,6 +102,8 @@ import com.oracle.truffle.r.nodes.builtin.fastr.FastRRefCountInfo; import com.oracle.truffle.r.nodes.builtin.fastr.FastRRefCountInfoNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastRSlotAssign; import com.oracle.truffle.r.nodes.builtin.fastr.FastRSlotAssignNodeGen; +import com.oracle.truffle.r.nodes.builtin.fastr.FastRSourceInfo; +import com.oracle.truffle.r.nodes.builtin.fastr.FastRSourceInfoNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastRStackTrace; import com.oracle.truffle.r.nodes.builtin.fastr.FastRStackTraceNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastRStats.FastRProfAttr; @@ -387,6 +389,7 @@ public class BasePackage extends RBuiltinPackage { add(FastRInterop.ToShort.class, FastRInteropFactory.ToShortNodeGen::create); add(FastRRefCountInfo.class, FastRRefCountInfoNodeGen::create); add(FastRPkgSource.class, FastRPkgSourceNodeGen::create); + add(FastRSourceInfo.class, FastRSourceInfoNodeGen::create); add(FastRStackTrace.class, FastRStackTraceNodeGen::create); add(FastRProfAttr.class, FastRStatsFactory.FastRProfAttrNodeGen::create); add(FastRProfTypecounts.class, FastRStatsFactory.FastRProfTypecountsNodeGen::create); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DPut.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DPut.java index d0361a493fd9fba3da09709a9e967e9334354574..13f43b742006fdade1fcc006389fc993d931ed34 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DPut.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DPut.java @@ -52,7 +52,7 @@ public abstract class DPut extends RBuiltinNode.Arg3 { @Specialization @TruffleBoundary protected Object dput(Object x, int file, int opts) { - String string = RDeparse.deparse(x, RDeparse.DEFAULT_Cutoff, true, opts, -1); + String string = RDeparse.deparse(x, RDeparse.DEFAULT_CUTOFF, true, opts, -1); try (RConnection openConn = RConnection.fromIndex(file).forceOpen("wt")) { openConn.writeString(string, true); } catch (IOException ex) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Deparse.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Deparse.java index fdd7a26615bc8c8b22a40276dca4f24dcdb20cc5..a258e75f8ed951e14f99225759e4f55a1e34de67 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Deparse.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Deparse.java @@ -42,9 +42,9 @@ public abstract class Deparse extends RBuiltinNode.Arg5 { @TruffleBoundary protected RStringVector deparse(Object expr, int widthCutoffArg, boolean backtick, int control, int nlines) { int widthCutoff = widthCutoffArg; - if (widthCutoff == RRuntime.INT_NA || widthCutoff < RDeparse.MIN_Cutoff || widthCutoff > RDeparse.MAX_Cutoff) { + if (widthCutoff == RRuntime.INT_NA || widthCutoff < RDeparse.MIN_CUTOFF || widthCutoff > RDeparse.MAX_CUTOFF) { warning(RError.Message.DEPARSE_INVALID_CUTOFF); - widthCutoff = RDeparse.DEFAULT_Cutoff; + widthCutoff = RDeparse.DEFAULT_CUTOFF; } String[] data = RDeparse.deparse(expr, widthCutoff, backtick, control, nlines).split("\n"); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LanguagePrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LanguagePrinter.java index 82ddd8f26ff0f5bda65d6705a7185f065090e358..bc050bed9d46661b295b32889e4b192304e8daa8 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LanguagePrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LanguagePrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,6 @@ final class LanguagePrinter extends AbstractValuePrinter<RLanguage> { @Override @TruffleBoundary protected void printValue(RLanguage language, PrintContext printCtx) throws IOException { - printCtx.output().print(RDeparse.deparse(language, RDeparse.DEFAULT_Cutoff, true, RDeparse.KEEPINTEGER, -1)); + printCtx.output().print(RDeparse.deparse(language, RDeparse.DEFAULT_CUTOFF, true, RDeparse.KEEPINTEGER, -1)); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/SymbolPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/SymbolPrinter.java index 19451dfcbf5e7dc936254d14ef4d57b7af44566e..0bf416f5573f48cfaec6cfc6e328d1531e4f90a1 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/SymbolPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/SymbolPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,6 @@ final class SymbolPrinter extends AbstractValuePrinter<RSymbol> { @Override @TruffleBoundary protected void printValue(RSymbol value, PrintContext printCtx) throws IOException { - printCtx.output().print(RDeparse.deparse(value, RDeparse.DEFAULT_Cutoff, true, RDeparse.SIMPLEDEPARSE, -1)); + printCtx.output().print(RDeparse.deparse(value, RDeparse.DEFAULT_CUTOFF, true, RDeparse.SIMPLEDEPARSE, -1)); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSourceInfo.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSourceInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..ed3430a7b325f4ad1d1f6abd39ecc8fb61e57102 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRSourceInfo.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.fastr; + +import static com.oracle.truffle.r.runtime.RVisibility.ON; +import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; + +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.runtime.builtins.RBehavior; +import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RNull; + +/** + * Allows to show the actual location of the source section of a provided function. + */ +@RBuiltin(name = ".fastr.srcinfo", visibility = ON, kind = PRIMITIVE, parameterNames = "fun", behavior = RBehavior.IO) +public abstract class FastRSourceInfo extends RBuiltinNode.Arg1 { + + static { + Casts.noCasts(FastRSourceInfo.class); + } + + @Specialization + public Object srcInfo(@SuppressWarnings("unused") RNull fun) { + return RNull.instance; + } + + @Specialization + public Object srcInfo(RFunction fun) { + SourceSection ss = fun.getRootNode().getSourceSection(); + if (ss != null) { + String path = ss.getSource().getPath(); + if (path != null) { + return path + "#" + ss.getStartLine(); + } else { + return ss.getSource().getName(); + } + } + return RNull.instance; + } +} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java index 1f317668577066be9db826c1ae0ee1dce1e65fa2..0a8d63ec7ed252318654e764ef1e79573fbcfcf3 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java @@ -150,7 +150,7 @@ public abstract class BinaryBooleanNode extends RBuiltinNode.Arg2 { } private static RString deparseSymbolOrLang(Object val) { - return RString.valueOf(RDeparse.deparse(val, RDeparse.MAX_Cutoff, false, RDeparse.KEEPINTEGER, -1)); + return RString.valueOf(RDeparse.deparse(val, RDeparse.MAX_CUTOFF, false, RDeparse.KEEPINTEGER, -1)); } protected BinaryBooleanNode createRecursive() { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java index 44d6c5ad366038c4e4388ca02728ea7d68941b77..272cc7314196453d4d6182ff083e8ee6f75bdb81 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java @@ -86,9 +86,9 @@ public class RDeparse { public static final int SIMPLEDEPARSE = 0; public static final int DEFAULTDEPARSE = 65; /* KEEPINTEGER | KEEPNA, used for calls */ - public static final int MIN_Cutoff = 20; - public static final int MAX_Cutoff = 500; - public static final int DEFAULT_Cutoff = 60; + public static final int MIN_CUTOFF = 20; + public static final int MAX_CUTOFF = 500; + public static final int DEFAULT_CUTOFF = 60; public static final char BACKTICK = '`'; public static final char DQUOTE = '"'; @@ -264,22 +264,29 @@ public class RDeparse { private final ArrayList<SourceSectionElement> sources; - private final int cutoff; + private final int listCutoff; + private final int debugCutoff; private final boolean backtick; private int opts; - @SuppressWarnings("unused") private final int nlines; + private final int nlines; private int inCurly = 0; private int inList = 0; private int indent = 0; private int lastLineStart = 0; + private int curLine = 1; DeparseVisitor(boolean storeSource, int cutoff, boolean backtick, int opts, int nlines) { - this.cutoff = cutoff; + this(storeSource, cutoff, backtick, opts, nlines, -1); + } + + DeparseVisitor(boolean storeSource, int cutoff, boolean backtick, int opts, int nlines, int debugCutoff) { + this.listCutoff = cutoff; this.backtick = backtick; this.opts = opts; this.nlines = nlines; this.sources = storeSource ? new ArrayList<>() : null; + this.debugCutoff = debugCutoff; } public String getContents() { @@ -304,13 +311,22 @@ public class RDeparse { return (opts & QUOTEEXPRESSIONS) != 0; } + private void checkLength(int nchar) { + if (debugCutoff >= 0 && sb.length() + nchar > debugCutoff) { + throw new MaxLengthReachedException(); + } + } + private DeparseVisitor append(char ch) { assert ch != '\n'; + checkLength(1); sb.append(ch); return this; } private DeparseVisitor append(String str) { + assert !str.contains("\n"); + checkLength(str.length()); sb.append(str); return this; } @@ -357,6 +373,7 @@ public class RDeparse { if (!Files.exists(path)) { try (BufferedWriter bw = Files.newBufferedWriter(path, CREATE_NEW, WRITE)) { bw.write(sb.toString()); + bw.newLine(); } } return path; @@ -408,13 +425,20 @@ public class RDeparse { public DeparseVisitor append(RSyntaxElement element) { try (C c = withContext(element)) { visitor.accept(element); + } catch (AbortDeparsingException e) { + // stop deparsing; indicate that there is something missing + sb.append("..."); } return this; } private void printline() { sb.append("\n"); + curLine++; lastLineStart = sb.length(); + if (nlines > 0 && curLine >= nlines) { + throw new MaxLinesReachedException(); + } for (int i = 0; i < indent; i++) { sb.append(i < 4 ? " " : " "); } @@ -438,9 +462,9 @@ public class RDeparse { return null; } - private boolean linebreak(boolean lbreak) { + private boolean listLinebreak(boolean lbreak) { boolean result = lbreak; - if ((sb.length() - lastLineStart) > cutoff) { + if ((sb.length() - lastLineStart) > listCutoff) { if (!lbreak) { result = true; indent++; @@ -721,7 +745,7 @@ public class RDeparse { if (i++ > 0) { append(", "); } - lbreak = linebreak(lbreak); + lbreak = listLinebreak(lbreak); if (arglist.getTag() != RNull.instance) { String argName = ((RSymbol) arglist.getTag()).getName(); if (!argName.isEmpty()) { @@ -786,7 +810,7 @@ public class RDeparse { if (i > start) { append(", "); } - lbreak = linebreak(lbreak); + lbreak = listLinebreak(lbreak); RSyntaxElement argument = args[i]; String name = signature.getName(i); @@ -823,22 +847,27 @@ public class RDeparse { Object value = RRuntime.asAbstractVector(v); assert value instanceof RTypedValue : v.getClass(); - RSyntaxElement element; - if (value instanceof RSymbol) { - element = RSyntaxLookup.createDummyLookup(RSyntaxNode.INTERNAL, ((RSymbol) value).getName(), false); - } else if (value instanceof RLanguage) { - element = ((RLanguage) value).getRep().asRSyntaxNode(); - } else if (value instanceof RMissing) { - element = RSyntaxLookup.createDummyLookup(null, "", false); - } else { - return appendConstant(value); - } - if (!quoteExpressions() || element instanceof RSyntaxConstant) { - append(element); - } else { - append("quote("); - append(element); - append(')'); + try { + RSyntaxElement element; + if (value instanceof RSymbol) { + element = RSyntaxLookup.createDummyLookup(RSyntaxNode.INTERNAL, ((RSymbol) value).getName(), false); + } else if (value instanceof RLanguage) { + element = ((RLanguage) value).getRep().asRSyntaxNode(); + } else if (value instanceof RMissing) { + element = RSyntaxLookup.createDummyLookup(null, "", false); + } else { + return appendConstant(value); + } + if (!quoteExpressions() || element instanceof RSyntaxConstant) { + append(element); + } else { + append("quote("); + append(element); + append(')'); + } + } catch (AbortDeparsingException e) { + // stop deparsing; indicate that there is something missing + sb.append("..."); } return this; } @@ -964,7 +993,7 @@ public class RDeparse { if (i > 0) { append(", "); } - lbreak = linebreak(lbreak); + lbreak = listLinebreak(lbreak); if (snames != null) { append(quotify(snames.getDataAt(i), '\"')); append(" = "); @@ -1044,12 +1073,12 @@ public class RDeparse { @TruffleBoundary public static String deparseSyntaxElement(RSyntaxElement element) { - return new DeparseVisitor(false, RDeparse.MAX_Cutoff, true, KEEPINTEGER, -1).append(element).getContents(); + return new DeparseVisitor(false, RDeparse.MAX_CUTOFF, true, KEEPINTEGER, -1).append(element).getContents(); } @TruffleBoundary public static String deparse(Object value) { - return new DeparseVisitor(false, RDeparse.MAX_Cutoff, true, KEEPINTEGER, -1).appendValue(value).getContents(); + return new DeparseVisitor(false, RDeparse.MAX_CUTOFF, true, KEEPINTEGER, -1).appendValue(value).getContents(); } @TruffleBoundary @@ -1057,6 +1086,11 @@ public class RDeparse { return new DeparseVisitor(false, cutoff, backtick, opts, nlines).appendValue(expr).getContents(); } + @TruffleBoundary + public static String deparse(Object expr, int cutoff, boolean backtick, int opts, int nlines, int debugCutoff) { + return new DeparseVisitor(false, cutoff, backtick, opts, nlines, debugCutoff).appendValue(expr).getContents(); + } + /** * Ensure that {@code node} has a {@link SourceSection} by deparsing if necessary. */ @@ -1072,11 +1106,11 @@ public class RDeparse { } } // try to generate the source from the root node and hopefully it includes this node - new DeparseVisitor(true, RDeparse.MAX_Cutoff, false, -1, 0).append(nodeToFixup).fixupSources(); + new DeparseVisitor(true, RDeparse.MAX_CUTOFF, false, -1, 0).append(nodeToFixup).fixupSources(); // if not, we have to deparse the node in isolation if (node.getLazySourceSection() == RSyntaxNode.LAZY_DEPARSE) { - new DeparseVisitor(true, RDeparse.MAX_Cutoff, false, -1, 0).append(node).fixupSources(); + new DeparseVisitor(true, RDeparse.MAX_CUTOFF, false, -1, 0).append(node).fixupSources(); } assert node.getLazySourceSection() != RSyntaxNode.LAZY_DEPARSE; } @@ -1136,4 +1170,16 @@ public class RDeparse { return 0; } } + + @SuppressWarnings("serial") + private static class AbortDeparsingException extends RuntimeException { + } + + @SuppressWarnings("serial") + private static final class MaxLinesReachedException extends AbortDeparsingException { + } + + @SuppressWarnings("serial") + private static final class MaxLengthReachedException extends AbortDeparsingException { + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java index d44fd73c8796a4725c679e55032c7030a1be91f6..f338a25c9ac534364d623a9b5a338e3256d0da13 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java @@ -31,6 +31,7 @@ import com.oracle.truffle.api.interop.Resolve; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.UnknownIdentifierException; import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.metadata.ScopeProvider.AbstractScope; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.r.runtime.ArgumentsSignature; @@ -39,6 +40,7 @@ import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.env.REnvironment.PutException; /** @@ -103,10 +105,9 @@ public final class RScope extends AbstractScope { @Override protected AbstractScope findParent() { - if (this.env == REnvironment.emptyEnv()) { + if (env == REnvironment.emptyEnv() || env.getParent() == REnvironment.emptyEnv()) { return null; } - return new RScope(env.getParent()); } @@ -167,11 +168,13 @@ public final class RScope extends AbstractScope { @TruffleBoundary public Object access(VariablesMapObject varMap) { + String[] names; if (varMap.argumentsOnly) { - return new ArgumentNamesObject(collectArgs(varMap.env)); + names = collectArgs(varMap.env); } else { - return new VariableNamesObject(varMap.env); + names = ls(varMap.env); } + return new ArgumentNamesObject(names); } } @@ -223,6 +226,9 @@ public final class RScope extends AbstractScope { if (varMap.env == null) { throw UnsupportedMessageException.raise(Message.WRITE); } + if (!(value instanceof RTypedValue)) { + throw UnsupportedTypeException.raise(new Object[]{value}); + } try { varMap.env.put(name, value); return value; @@ -235,60 +241,6 @@ public final class RScope extends AbstractScope { } } - static final class VariableNamesObject implements TruffleObject { - - private final REnvironment env; - - private VariableNamesObject(REnvironment env) { - this.env = env; - } - - @Override - public ForeignAccess getForeignAccess() { - return VariableNamesMessageResolutionForeign.ACCESS; - } - - public static boolean isInstance(TruffleObject obj) { - return obj instanceof VariableNamesObject; - } - - @MessageResolution(receiverType = VariableNamesObject.class) - static final class VariableNamesMessageResolution { - - @Resolve(message = "HAS_SIZE") - abstract static class VarNamesHasSizeNode extends Node { - - @SuppressWarnings("unused") - public Object access(VariableNamesObject varNames) { - return true; - } - } - - @Resolve(message = "GET_SIZE") - abstract static class VarNamesGetSizeNode extends Node { - - public Object access(VariableNamesObject varNames) { - return ls(varNames.env).length; - } - } - - @Resolve(message = "READ") - abstract static class VarNamesReadNode extends Node { - - @TruffleBoundary - public Object access(VariableNamesObject varNames, int index) { - String[] names = ls(varNames.env); - if (index >= 0 && index < names.length) { - return names[index]; - } else { - throw UnknownIdentifierException.raise(Integer.toString(index)); - } - } - } - - } - } - static final class ArgumentNamesObject implements TruffleObject { private final String[] names; @@ -331,8 +283,9 @@ public final class RScope extends AbstractScope { @TruffleBoundary public Object access(ArgumentNamesObject varNames, int index) { - if (index >= 0 && index < varNames.names.length) { - return varNames.names[index]; + String[] names = varNames.names; + if (index >= 0 && index < names.length) { + return names[index]; } else { throw UnknownIdentifierException.raise(Integer.toString(index)); }