From 1724375c46144576f15b4d9a02e48fcf947175de Mon Sep 17 00:00:00 2001 From: Lukas Stadler <lukas.stadler@oracle.com> Date: Fri, 1 Apr 2016 17:34:20 +0200 Subject: [PATCH] deparsing refactoring --- .../r/engine/RRuntimeASTAccessImpl.java | 16 +- .../r/library/methods/SubstituteDirect.java | 4 +- .../truffle/r/nodes/builtin/base/Args.java | 4 +- .../r/nodes/builtin/base/AsCharacter.java | 2 +- .../r/nodes/builtin/base/AsFunction.java | 4 +- .../truffle/r/nodes/builtin/base/DPut.java | 2 +- .../truffle/r/nodes/builtin/base/Deparse.java | 2 +- .../builtin/base/HiddenInternalFunctions.java | 4 +- .../nodes/builtin/base/PrettyPrinterNode.java | 18 +- .../r/nodes/builtin/base/Substitute.java | 5 +- .../truffle/r/nodes/builtin/base/Switch.java | 9 +- .../builtin/base/printer/FunctionPrinter.java | 2 +- .../builtin/base/printer/LanguagePrinter.java | 16 +- .../builtin/base/printer/SymbolPrinter.java | 4 +- .../nodes/builtin/helpers/DebugHandling.java | 6 +- .../com/oracle/truffle/r/nodes/RASTUtils.java | 9 +- .../truffle/r/nodes/access/ConstantNode.java | 47 - .../access/ReadVariadicComponentNode.java | 8 - .../access/WriteCurrentVariableNode.java | 8 - .../nodes/access/WriteSuperVariableNode.java | 8 - .../access/WriteVariableNodeSyntaxHelper.java | 10 - .../access/variables/ReadVariableNode.java | 8 - .../truffle/r/nodes/control/BlockNode.java | 20 - .../truffle/r/nodes/control/BreakNode.java | 8 - .../truffle/r/nodes/control/ForNode.java | 13 - .../truffle/r/nodes/control/IfNode.java | 28 - .../truffle/r/nodes/control/NextNode.java | 8 - .../r/nodes/control/ReplacementNode.java | 15 +- .../truffle/r/nodes/control/WhileNode.java | 15 - .../function/FunctionDefinitionNode.java | 30 - .../function/FunctionExpressionNode.java | 8 - .../r/nodes/function/GroupDispatchNode.java | 17 - .../truffle/r/nodes/function/PromiseNode.java | 9 - .../truffle/r/nodes/function/RCallNode.java | 80 +- .../truffle/r/nodes/runtime/RASTDeparse.java | 225 -- .../truffle/r/nodes/unary/CastStringNode.java | 2 +- .../r/nodes/unary/GetNonSharedNode.java | 6 - .../oracle/truffle/r/runtime/RDeparse.java | 1935 +++++++---------- .../truffle/r/runtime/RRuntimeASTAccess.java | 11 +- .../oracle/truffle/r/runtime/RSerialize.java | 6 +- .../truffle/r/runtime/nodes/RBaseNode.java | 6 - .../truffle/r/runtime/nodes/RSyntaxNode.java | 6 +- .../r/runtime/nodes/RSyntaxNodeSPI.java | 8 +- mx.fastr/copyrights/overrides | 1 - 44 files changed, 793 insertions(+), 1860 deletions(-) delete mode 100644 com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/runtime/RASTDeparse.java 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 1ff20ee23e..0881ec1d11 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 @@ -51,12 +51,10 @@ import com.oracle.truffle.r.nodes.function.FunctionExpressionNode; import com.oracle.truffle.r.nodes.function.GroupDispatchNode; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.nodes.function.RCallNode; -import com.oracle.truffle.r.nodes.runtime.RASTDeparse; import com.oracle.truffle.r.runtime.Arguments; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; -import com.oracle.truffle.r.runtime.RDeparse.State; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RInternalSourceDescriptions; @@ -363,16 +361,6 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { } } - @Override - public void deparse(State state, RLanguage rl) { - RASTDeparse.deparse(state, rl); - } - - @Override - public void deparse(State state, RFunction f) { - RASTDeparse.deparse(state, f); - } - @Override public Object callback(RFunction f, Object[] args) { boolean gd = DebugHandling.globalDisable(true); @@ -545,6 +533,10 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { } } + public RSyntaxFunction getSyntaxFunction(RFunction f) { + return (FunctionDefinitionNode) f.getTarget().getRootNode(); + } + private static Object getCallerFromFrame(Frame frame) { if (frame == null) { // parser error diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/SubstituteDirect.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/SubstituteDirect.java index 4978cc5bcc..8082bff689 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/SubstituteDirect.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/SubstituteDirect.java @@ -29,7 +29,7 @@ import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; import com.oracle.truffle.r.nodes.builtin.RList2EnvNode; import com.oracle.truffle.r.nodes.builtin.RList2EnvNodeGen; -import com.oracle.truffle.r.nodes.runtime.RASTDeparse; +import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RLanguage; @@ -48,7 +48,7 @@ public abstract class SubstituteDirect extends RExternalBuiltinNode.Arg2 { RSyntaxNode snode = lang.getRep().asRSyntaxNode(); RSyntaxNode subRNode = snode.substituteImpl(env); // create source for entire tree - RASTDeparse.ensureSourceSection(subRNode); + RDeparse.ensureSourceSection(subRNode); return RASTUtils.createLanguageElement(subRNode.asRNode()); } else { return object; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java index 0a790ec670..65ff6a5714 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Args.java @@ -35,9 +35,9 @@ import com.oracle.truffle.r.nodes.builtin.base.GetFunctionsFactory.GetNodeGen; import com.oracle.truffle.r.nodes.function.FormalArguments; import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; import com.oracle.truffle.r.nodes.function.SaveArgumentsNode; -import com.oracle.truffle.r.nodes.runtime.RASTDeparse; import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RBuiltinKind; +import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -87,7 +87,7 @@ public abstract class Args extends RBuiltinNode { String newDesc = "args(" + rootNode.getDescription() + ")"; FunctionDefinitionNode newNode = FunctionDefinitionNode.create(RSyntaxNode.EAGER_DEPARSE, rootNode.getFrameDescriptor(), null, SaveArgumentsNode.NO_ARGS, ConstantNode.create(RSyntaxNode.EAGER_DEPARSE, RNull.instance), formals, newDesc, null); - RASTDeparse.ensureSourceSection(newNode); + RDeparse.ensureSourceSection(newNode); return RDataFactory.createFunction(newDesc, Truffle.getRuntime().createCallTarget(newNode), null, REnvironment.globalEnv().getFrame(), null, false); } 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 0aa2b5bd86..00ad207d38 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 @@ -141,7 +141,7 @@ public abstract class AsCharacter extends RBuiltinNode { } else if (elem instanceof RStringVector && ((RStringVector) elem).getLength() == 1) { data[i] = ((RStringVector) elem).getDataAt(0); } else { - data[i] = RDeparse.deparse1Line(elem, false); + data[i] = RDeparse.deparse(elem, RDeparse.MAX_Cutoff, true, 0, -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/AsFunction.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java index ed87bf4a51..73823c9215 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AsFunction.java @@ -36,10 +36,10 @@ import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.function.FormalArguments; import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode; import com.oracle.truffle.r.nodes.function.SaveArgumentsNode; -import com.oracle.truffle.r.nodes.runtime.RASTDeparse; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RBuiltinKind; +import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; @@ -135,7 +135,7 @@ public abstract class AsFunction extends RBuiltinNode { FrameSlotChangeMonitor.initializeFunctionFrameDescriptor("<as.function.default>", descriptor); FrameSlotChangeMonitor.initializeEnclosingFrame(descriptor, envir.getFrame()); FunctionDefinitionNode rootNode = FunctionDefinitionNode.create(RSyntaxNode.EAGER_DEPARSE, descriptor, null, saveArguments, (RSyntaxNode) body, formals, "from AsFunction", null); - RASTDeparse.ensureSourceSection(rootNode); + RDeparse.ensureSourceSection(rootNode); RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode); boolean containsDispatch = ((FunctionDefinitionNode) callTarget.getRootNode()).containsDispatch(); return RDataFactory.createFunction(RFunction.NO_NAME, callTarget, null, envir.getFrame(), null, containsDispatch); 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 825387ba53..89da1c8285 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 @@ -51,7 +51,7 @@ public abstract class DPut extends RInvisibleBuiltinNode { protected Object dput(Object x, RConnection file, int opts) { controlVisibility(); - String string = RDeparse.deparse1Line(x, false, RDeparse.DEFAULT_Cutoff, opts); + String string = RDeparse.deparse(x, RDeparse.DEFAULT_Cutoff, true, opts, -1); try (RConnection openConn = 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 dca97289df..d9914efa4c 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 @@ -47,7 +47,7 @@ public abstract class Deparse extends RBuiltinNode { widthCutoff = RDeparse.DEFAULT_Cutoff; } - String[] data = RDeparse.deparse(expr, widthCutoff, RRuntime.fromLogical(backtick.getDataAt(0)), control, nlines); + String[] data = RDeparse.deparse(expr, widthCutoff, RRuntime.fromLogical(backtick.getDataAt(0)), control, nlines).split("\n"); return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java index ae2c1e1935..e1eb81169e 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/HiddenInternalFunctions.java @@ -38,7 +38,6 @@ import com.oracle.truffle.r.nodes.builtin.base.EvalFunctions.Eval; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.nodes.function.RCallNode; import com.oracle.truffle.r.nodes.function.SubstituteVirtualFrame; -import com.oracle.truffle.r.nodes.runtime.RASTDeparse; import com.oracle.truffle.r.nodes.unary.CastIntegerNode; import com.oracle.truffle.r.nodes.unary.CastIntegerNodeGen; import com.oracle.truffle.r.runtime.ArgumentsSignature; @@ -47,6 +46,7 @@ import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RBuiltinKind; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RCompression; +import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RInternalError; @@ -115,7 +115,7 @@ public class HiddenInternalFunctions { RCallNode expr0 = RCallNode.createCloneReplacingArgs(callNode, vecNode); try { // We want this call to have a SourceSection - RASTDeparse.ensureSourceSection(expr0); + RDeparse.ensureSourceSection(expr0); aenv.put(name, RDataFactory.createPromise(expr0, eenv)); } catch (PutException ex) { /* 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 6b74a77c2f..931e2cf1a4 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 @@ -291,7 +291,7 @@ public abstract class PrettyPrinterNode extends RNode { } else { String source = ((RRootNode) operand.getTarget().getRootNode()).getSourceCode(); if (source == null || !useSource) { - source = RDeparse.deparseForPrint(operand); + source = RDeparse.deparse(operand); } REnvironment env = RArguments.getEnvironment(operand.getEnclosingFrame()); if (env != null && env.isNamespaceEnv()) { @@ -358,21 +358,7 @@ public abstract class PrettyPrinterNode extends RNode { } private static String prettyPrintLanguageInternal(RLanguage language) { - String[] lines = RDeparse.deparse(language, 60, false, 0, -1); - if (lines.length == 1) { - return lines[0]; - } else { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < lines.length; i++) { - sb.append(lines[i]); - if (i == lines.length - 1) { - continue; - } - sb.append('\n'); - } - return sb.toString(); - - } + return RDeparse.deparse(language, 60, false, 0, -1); } private static String prettyPrintPromise(RPromise promise) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substitute.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substitute.java index fb81a1b1a0..49c1914483 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substitute.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Substitute.java @@ -33,8 +33,8 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.control.IfNode; -import com.oracle.truffle.r.nodes.runtime.RASTDeparse; import com.oracle.truffle.r.runtime.RBuiltin; +import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.data.RAttributeProfiles; import com.oracle.truffle.r.runtime.data.RLanguage; @@ -126,7 +126,8 @@ public abstract class Substitute extends RBuiltinNode { RSyntaxNode rNode = (RSyntaxNode) RASTUtils.cloneNode(node); RSyntaxNode subRNode = rNode.substituteImpl(env); // create source for entire tree - RASTDeparse.ensureSourceSection(subRNode); + subRNode.setSourceSection(RSyntaxNode.EAGER_DEPARSE); + RDeparse.ensureSourceSection(subRNode); return RASTUtils.createLanguageElement(subRNode.asRNode()); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Switch.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Switch.java index 73ea368e25..a6f10226ce 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Switch.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Switch.java @@ -26,14 +26,12 @@ import com.oracle.truffle.r.nodes.unary.CastIntegerNodeGen; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RBuiltin; import com.oracle.truffle.r.runtime.RDeparse; -import com.oracle.truffle.r.runtime.RDeparse.State; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; -import com.oracle.truffle.r.runtime.nodes.RBaseNode; /** * The {@code switch} builtin. When called directly, the "..." arguments are not evaluated before @@ -123,12 +121,9 @@ public abstract class Switch extends RBuiltinNode { if (arg instanceof RPromise) { // We do not want to evaluate the promise,just display the rep RPromise p = (RPromise) arg; - RBaseNode node = p.getRep(); - State state = State.createPrintableState(); - node.deparse(state); - return state.toString(); + return RDeparse.deparseSyntaxElement(p.getRep().asRSyntaxNode()); } else { - return RDeparse.deparseForPrint(arg); + return RDeparse.deparse(arg); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/FunctionPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/FunctionPrinter.java index 493318dac7..e8c0bc6d2b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/FunctionPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/FunctionPrinter.java @@ -76,7 +76,7 @@ final class FunctionPrinter extends AbstractValuePrinter<RFunction> { final boolean useSource = printCtx.parameters().getUseSource(); String source = ((RRootNode) operand.getTarget().getRootNode()).getSourceCode(); if (source == null || !useSource) { - source = RDeparse.deparseForPrint(operand); + source = RDeparse.deparse(operand); } REnvironment env = RArguments.getEnvironment(operand.getEnclosingFrame()); if (env != null && env.isNamespaceEnv()) { 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 182aa7319f..f47b7a21b9 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 @@ -23,7 +23,6 @@ package com.oracle.truffle.r.nodes.builtin.base.printer; import java.io.IOException; -import java.io.PrintWriter; import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.data.RLanguage; @@ -38,19 +37,6 @@ final class LanguagePrinter extends AbstractValuePrinter<RLanguage> { @Override protected void printValue(RLanguage language, PrintContext printCtx) throws IOException { - final PrintWriter out = printCtx.output(); - - String[] lines = RDeparse.deparse(language, 60, false, 0, -1); - if (lines.length == 1) { - out.print(lines[0]); - } else { - for (int i = 0; i < lines.length; i++) { - out.print(lines[i]); - if (i == lines.length - 1) { - continue; - } - out.println(); - } - } + printCtx.output().print(RDeparse.deparse(language, RDeparse.DEFAULT_Cutoff, false, 0, -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 8b8b38c8e2..7f8080ae07 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 @@ -37,8 +37,6 @@ final class SymbolPrinter extends AbstractValuePrinter<RSymbol> { @Override protected void printValue(RSymbol value, PrintContext printCtx) throws IOException { - String[] dp = RDeparse.deparse(value, RDeparse.DEFAULT_Cutoff, false, - RDeparse.SIMPLEDEPARSE, -1); - printCtx.output().print(dp[0]); + 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/helpers/DebugHandling.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java index 09fcc78f79..ad0d6d9ee5 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/DebugHandling.java @@ -36,8 +36,8 @@ import com.oracle.truffle.api.instrumentation.Instrumenter; import com.oracle.truffle.api.instrumentation.SourceSectionFilter; import com.oracle.truffle.api.instrumentation.StandardTags; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.api.utilities.CyclicAssumption; import com.oracle.truffle.r.nodes.control.AbstractLoopNode; @@ -440,9 +440,7 @@ public class DebugHandling { * N.B. It would seem that GnuR does a deparse that because, e.g., a function that ends with * } without a preceding newline prints with one and indentation is standardized. */ - RDeparse.State state = RDeparse.State.createPrintableState(); RBaseNode rNode = (RBaseNode) node; - rNode.deparse(state); boolean curly = RSyntaxCall.isCallTo((RSyntaxElement) node, "{"); if (startFunction && !curly) { @@ -455,7 +453,7 @@ public class DebugHandling { } consoleHandler.print("debug at " + path + "#" + source.getStartLine() + ": "); } - consoleHandler.print(state.toString()); + consoleHandler.print(RDeparse.deparseSyntaxElement(rNode.asRSyntaxNode())); consoleHandler.print("\n"); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java index 24ed425eb6..86b18a11af 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTUtils.java @@ -44,7 +44,6 @@ import com.oracle.truffle.r.nodes.function.WrapArgumentNode; import com.oracle.truffle.r.runtime.Arguments; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RDeparse; -import com.oracle.truffle.r.runtime.RDeparse.State; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -278,9 +277,7 @@ public class RASTUtils { } else { // TODO This should really fail in some way as (clearly) this is not a "name" // some more complicated expression, just deparse it - RDeparse.State state = RDeparse.State.createPrintableState(); - child.deparse(state); - return RDataFactory.createSymbolInterned(state.toString()); + return RDataFactory.createSymbolInterned(RDeparse.deparse(child)); } } @@ -380,10 +377,6 @@ public class RASTUtils { * Marker class for special '...' handling. */ private abstract static class DotsNode extends RNode implements RSyntaxNode { - @Override - public void deparseImpl(State state) { - throw RInternalError.unimplemented(); - } @Override public RSyntaxNode substituteImpl(REnvironment env) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java index a62a976bf5..b71392f90e 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ConstantNode.java @@ -23,12 +23,8 @@ package com.oracle.truffle.r.nodes.access; import com.oracle.truffle.api.CompilerAsserts; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.source.SourceSection; -import com.oracle.truffle.r.nodes.RASTUtils; -import com.oracle.truffle.r.runtime.RDeparse; -import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RSerialize; import com.oracle.truffle.r.runtime.VisibilityController; @@ -75,14 +71,6 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax return getValue(); } - @Override - @TruffleBoundary - public void deparseImpl(RDeparse.State state) { - state.startNodeDeparse(this); - RDeparse.deparse2buff(state, getValue()); - state.endNodeDeparse(this); - } - @Override public RSyntaxNode substituteImpl(REnvironment env) { return this; @@ -201,41 +189,6 @@ public abstract class ConstantNode extends RSourceSectionNode implements RSyntax return value; } - @Override - @TruffleBoundary - public void deparseImpl(RDeparse.State state) { - if (value == RMissing.instance || value instanceof RArgsValuesAndNames) { - state.startNodeDeparse(this); - if (value == RMissing.instance) { - // nothing to do - } else if (value instanceof RArgsValuesAndNames) { - RArgsValuesAndNames args = (RArgsValuesAndNames) value; - Object[] values = args.getArguments(); - for (int i = 0; i < values.length; i++) { - String name = args.getSignature().getName(i); - if (name != null) { - state.append(name); - state.append(" = "); - } - Object argValue = values[i]; - if (argValue instanceof RSyntaxNode) { - ((RSyntaxNode) argValue).deparseImpl(state); - } else if (argValue instanceof RPromise) { - RASTUtils.unwrap(((RPromise) argValue).getRep()).deparse(state); - } else { - RInternalError.shouldNotReachHere(); - } - if (i < values.length - 1) { - state.append(", "); - } - } - } - state.endNodeDeparse(this); - } else { - super.deparseImpl(state); - } - } - @Override public void serializeImpl(RSerialize.State state) { if (value == RMissing.instance) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java index 28043f5fa1..3c16440037 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/ReadVariadicComponentNode.java @@ -29,7 +29,6 @@ import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RDeparse.State; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RType; @@ -98,13 +97,6 @@ public class ReadVariadicComponentNode extends RSourceSectionNode implements RSy return ".." + Integer.toString(index + 1); } - @Override - public void deparseImpl(State state) { - state.startNodeDeparse(this); - state.append(getPrintForm()); - state.endNodeDeparse(this); - } - @Override public RSyntaxNode substituteImpl(REnvironment env) { throw RInternalError.unimplemented(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteCurrentVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteCurrentVariableNode.java index 027986264b..e1cfa015e0 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteCurrentVariableNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteCurrentVariableNode.java @@ -28,7 +28,6 @@ import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RDeparse.State; import com.oracle.truffle.r.runtime.RSerialize; import com.oracle.truffle.r.runtime.VisibilityController; import com.oracle.truffle.r.runtime.env.REnvironment; @@ -77,13 +76,6 @@ public class WriteCurrentVariableNode extends WriteVariableNodeSyntaxHelper impl writeLocalFrameVariableNode.execute(frame, value); } - @Override - public void deparseImpl(State state) { - state.startNodeDeparse(this); - deparseHelper(state, " <- "); - state.endNodeDeparse(this); - } - @Override public void serializeImpl(RSerialize.State state) { serializeHelper(state, "<-"); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteSuperVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteSuperVariableNode.java index 249cdaf317..ae6f6b56e5 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteSuperVariableNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteSuperVariableNode.java @@ -27,7 +27,6 @@ import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RDeparse.State; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RSerialize; import com.oracle.truffle.r.runtime.VisibilityController; @@ -83,13 +82,6 @@ public class WriteSuperVariableNode extends WriteVariableNodeSyntaxHelper implem writeSuperFrameVariableNode.execute(frame, value); } - @Override - public void deparseImpl(State state) { - state.startNodeDeparse(this); - deparseHelper(state, " <<- "); - state.endNodeDeparse(this); - } - @Override public void serializeImpl(RSerialize.State state) { serializeHelper(state, "<<-"); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNodeSyntaxHelper.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNodeSyntaxHelper.java index ba559c9f03..27f7ff678e 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNodeSyntaxHelper.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/WriteVariableNodeSyntaxHelper.java @@ -24,7 +24,6 @@ package com.oracle.truffle.r.nodes.access; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.source.SourceSection; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RSerialize; import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; import com.oracle.truffle.r.runtime.nodes.RNode; @@ -37,15 +36,6 @@ abstract class WriteVariableNodeSyntaxHelper extends WriteVariableNode { this.sourceSectionR = sourceSection; } - protected void deparseHelper(RDeparse.State state, String op) { - state.append(getName().toString()); - RNode rhs = getRhs(); - if (rhs != null) { - state.append(op); - getRhs().deparse(state); - } - } - protected void serializeHelper(RSerialize.State state, String op) { RNode rhs = getRhs(); if (rhs == null) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java index 7ec2ccab2b..cdf8187d4b 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java @@ -52,7 +52,6 @@ import com.oracle.truffle.r.runtime.AnonymousFrameVariable; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RArguments; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; @@ -163,13 +162,6 @@ public final class ReadVariableNode extends RSourceSectionNode implements RSynta return mode; } - @Override - public void deparseImpl(RDeparse.State state) { - state.startNodeDeparse(this); - state.append(RDeparse.quotify(identifierAsString, state)); - state.endNodeDeparse(this); - } - @Override public void serializeImpl(RSerialize.State state) { state.setCarAsSymbol(identifierAsString); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java index 48e1397b39..a153a33b36 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BlockNode.java @@ -28,7 +28,6 @@ import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RSerialize; import com.oracle.truffle.r.runtime.VisibilityController; import com.oracle.truffle.r.runtime.data.RNull; @@ -70,25 +69,6 @@ public final class BlockNode extends RSourceSectionNode implements RSyntaxNode, return lastResult; } - @TruffleBoundary - @Override - public void deparseImpl(RDeparse.State state) { - state.startNodeDeparse(this); - // empty deparses as {} - state.writeOpenCurlyNLIncIndent(); - for (int i = 0; i < sequence.length; i++) { - state.mark(); - sequence[i].deparse(state); - if (state.changed()) { - // not all nodes will produce output - state.writeline(); - state.mark(); // in case last - } - } - state.decIndentWriteCloseCurly(); - state.endNodeDeparse(this); - } - @Override public void serializeImpl(RSerialize.State state) { state.setAsLangType(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BreakNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BreakNode.java index 5c0105bc3d..50bd80a94b 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BreakNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/BreakNode.java @@ -25,7 +25,6 @@ package com.oracle.truffle.r.nodes.control; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RSerialize; import com.oracle.truffle.r.runtime.VisibilityController; import com.oracle.truffle.r.runtime.env.REnvironment; @@ -41,13 +40,6 @@ public final class BreakNode extends RSourceSectionNode implements RSyntaxNode, super(src); } - @Override - public void deparseImpl(RDeparse.State state) { - state.startNodeDeparse(this); - state.append("break"); - state.endNodeDeparse(this); - } - @Override public void serializeImpl(RSerialize.State state) { state.setAsBuiltin("break"); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java index f01f41a695..b2f6ec6cba 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java @@ -38,7 +38,6 @@ import com.oracle.truffle.r.nodes.access.WriteVariableNode.Mode; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.runtime.AnonymousFrameVariable; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RSerialize; import com.oracle.truffle.r.runtime.VisibilityController; import com.oracle.truffle.r.runtime.data.RNull; @@ -97,18 +96,6 @@ public final class ForNode extends AbstractLoopNode implements VisibilityControl return getForRepeatingNode().body; } - @Override - public void deparseImpl(RDeparse.State state) { - state.startNodeDeparse(this); - state.append("for ("); - getCvar().deparse(state); - state.append(" in "); - getRange().deparse(state); - state.append(") "); - getBody().deparse(state); - state.endNodeDeparse(this); - } - @Override public void serializeImpl(RSerialize.State state) { state.setAsBuiltin("for"); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java index 92a14b0d2e..dd489256d7 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/IfNode.java @@ -26,10 +26,8 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.source.SourceSection; -import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.nodes.unary.ConvertBooleanNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RSerialize; @@ -108,32 +106,6 @@ public final class IfNode extends RSourceSectionNode implements RSyntaxNode, RSy return elsePart; } - @Override - public void deparseImpl(RDeparse.State state) { - state.startNodeDeparse(this); - state.append("if ("); - condition.deparse(state); - state.append(") "); - if (RASTUtils.unwrap(thenPart) instanceof BlockNode && ((BlockNode) RASTUtils.unwrap(thenPart)).getSequence().length > 1) { - thenPart.deparse(state); - if (elsePart != null) { - state.writeline(); - state.append("else "); - elsePart.deparse(state); - } - } else { - state.writeline(); - state.incIndent(); - thenPart.deparse(state); - state.decIndent(); - if (elsePart != null) { - state.append(" else "); - elsePart.deparse(state); - } - } - state.endNodeDeparse(this); - } - @Override public void serializeImpl(RSerialize.State state) { state.setAsBuiltin("if"); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/NextNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/NextNode.java index 5815f5d2a4..0fac8ccbed 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/NextNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/NextNode.java @@ -25,7 +25,6 @@ package com.oracle.truffle.r.nodes.control; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RSerialize; import com.oracle.truffle.r.runtime.VisibilityController; import com.oracle.truffle.r.runtime.env.REnvironment; @@ -47,13 +46,6 @@ public final class NextNode extends RSourceSectionNode implements RSyntaxNode, R throw NextException.instance; } - @Override - public void deparseImpl(RDeparse.State state) { - state.startNodeDeparse(this); - state.append("next"); - state.endNodeDeparse(this); - } - @Override public void serializeImpl(RSerialize.State state) { state.setAsBuiltin("next"); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java index 68eeaad4d8..2930f24e59 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ReplacementNode.java @@ -32,7 +32,6 @@ import com.oracle.truffle.r.nodes.access.RemoveAndAnswerNode; import com.oracle.truffle.r.nodes.access.WriteVariableNode; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RSerialize; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.env.REnvironment; @@ -54,7 +53,8 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; public final class ReplacementNode extends RSourceSectionNode implements RSyntaxNode, RSyntaxCall { /** - * This is just the left hand side of the assignment and only used for {@link #deparseImpl} etc. + * This is just the left hand side of the assignment and only used when looking at the original + * structure of this replacement. */ private final RSyntaxNode syntaxLhs; private final boolean isSuper; @@ -110,17 +110,6 @@ public final class ReplacementNode extends RSourceSectionNode implements RSyntax return removeRhs.execute(frame); } - @Override - public void deparseImpl(RDeparse.State state) { - state.startNodeDeparse(this); - syntaxLhs.deparseImpl(state); - state.append(' '); - state.append(getSymbol()); - state.append(' '); - storeRhs.getRhs().asRSyntaxNode().deparseImpl(state); - state.endNodeDeparse(this); - } - @Override public void serializeImpl(RSerialize.State state) { state.setAsLangType(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/WhileNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/WhileNode.java index afe163dda1..4a18e69fde 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/WhileNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/WhileNode.java @@ -33,7 +33,6 @@ import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.r.nodes.RRootNode; import com.oracle.truffle.r.nodes.unary.ConvertBooleanNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RSerialize; import com.oracle.truffle.r.runtime.VisibilityController; @@ -90,20 +89,6 @@ public final class WhileNode extends AbstractLoopNode implements RSyntaxNode, RS return isRepeat; } - @Override - public void deparseImpl(RDeparse.State state) { - state.startNodeDeparse(this); - if (isRepeat) { - state.append("repeat "); - } else { - state.append("while ("); - getCondition().deparse(state); - state.append(") "); - } - getBody().deparse(state); - state.endNodeDeparse(this); - } - @Override public void serializeImpl(RSerialize.State state) { state.setAsBuiltin(isRepeat ? "repeat" : "while"); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java index 0eaaa98be0..8c60007897 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionDefinitionNode.java @@ -53,7 +53,6 @@ import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RArguments.DispatchArgs; import com.oracle.truffle.r.runtime.RArguments.S3Args; import com.oracle.truffle.r.runtime.RArguments.S4Args; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RErrorHandling; import com.oracle.truffle.r.runtime.RInternalError; @@ -392,35 +391,6 @@ public final class FunctionDefinitionNode extends RRootNode implements RSyntaxNo return description == null ? "<no source>" : description; } - /* - * TODO Decide whether we really care about the braces/no-braces issue for deparse and - * serialize, since we do not distinguish them in other nodes at the present time. - */ - - @Override - public void deparseImpl(RDeparse.State state) { - // TODO linebreaks - state.startNodeDeparse(this); - state.append("function ("); - FormalArguments formals = getFormalArguments(); - int formalsLength = formals.getSignature().getLength(); - for (int i = 0; i < formalsLength; i++) { - RNode defaultArg = formals.getDefaultArgument(i); - state.append(formals.getSignature().getName(i)); - if (defaultArg != null) { - state.append(" = "); - defaultArg.deparse(state); - } - if (i != formalsLength - 1) { - state.append(", "); - } - } - state.append(") "); - state.writeline(); - body.deparse(state); - state.endNodeDeparse(this); - } - @Override public RSyntaxNode substituteImpl(REnvironment env) { FrameDescriptor frameDesc = new FrameDescriptor(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java index 0ca3806a47..d9258b2a3d 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java @@ -36,7 +36,6 @@ import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseDeoptimizeFr import com.oracle.truffle.r.nodes.function.opt.EagerEvalHelper; import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RSerialize; import com.oracle.truffle.r.runtime.data.FastPathFactory; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -102,13 +101,6 @@ public final class FunctionExpressionNode extends RSourceSectionNode implements return callTarget; } - @Override - public void deparseImpl(RDeparse.State state) { - state.startNodeDeparse(this); - ((FunctionDefinitionNode) callTarget.getRootNode()).deparseImpl(state); - state.endNodeDeparse(this); - } - @Override public void serializeImpl(RSerialize.State state) { state.setAsBuiltin("function"); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java index 93af4b7477..9493f0c100 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GroupDispatchNode.java @@ -22,11 +22,9 @@ import com.oracle.truffle.r.nodes.RASTUtils; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.NoGenericMethodException; import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.Result; -import com.oracle.truffle.r.nodes.runtime.RASTDeparse; import com.oracle.truffle.r.runtime.Arguments; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RArguments.S3Args; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RGroupGenerics; import com.oracle.truffle.r.runtime.RInternalError; @@ -95,21 +93,6 @@ public final class GroupDispatchNode extends RSourceSectionNode implements RSynt return getSourceSection(); } - @Override - public void deparseImpl(RDeparse.State state) { - String name = getGenericName(); - RDeparse.Func func = RDeparse.getFunc(name); - state.startNodeDeparse(this); - if (func != null) { - // infix operator - RASTDeparse.deparseInfixOperator(state, this, func); - } else { - state.append(name); - RCallNode.deparseArguments(state, callArgsNode.getSyntaxArguments(), callArgsNode.signature); - } - state.endNodeDeparse(this); - } - @Override public void serializeImpl(RSerialize.State state) { String name = getGenericName(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java index 7bf0554223..a7aa26bf1a 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseNode.java @@ -44,7 +44,6 @@ import com.oracle.truffle.r.nodes.function.opt.OptConstantPromiseNode; import com.oracle.truffle.r.nodes.function.opt.OptForcedEagerPromiseNode; import com.oracle.truffle.r.nodes.function.opt.OptVariablePromiseBaseNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RSerialize.State; import com.oracle.truffle.r.runtime.RType; @@ -326,14 +325,6 @@ public abstract class PromiseNode extends RNode { return index; } - @Override - public void deparseImpl(RDeparse.State state) { - int num = index + 1; - state.startNodeDeparse(this); - state.append((num < 10 ? ".." : ".") + num); - state.endNodeDeparse(this); - } - @Override public void serializeImpl(State state) { throw RInternalError.unimplemented(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java index 47e1711da4..596c3cf5ab 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java @@ -61,7 +61,6 @@ import com.oracle.truffle.r.nodes.builtin.RBuiltinRootNode; import com.oracle.truffle.r.nodes.function.MatchedArguments.MatchedArgumentsNode; import com.oracle.truffle.r.nodes.function.S3FunctionLookupNode.Result; import com.oracle.truffle.r.nodes.function.signature.RArgumentsNode; -import com.oracle.truffle.r.nodes.runtime.RASTDeparse; import com.oracle.truffle.r.runtime.Arguments; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RArguments; @@ -69,7 +68,6 @@ import com.oracle.truffle.r.runtime.RArguments.S3Args; import com.oracle.truffle.r.runtime.RBuiltinKind; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RDeparse; -import com.oracle.truffle.r.runtime.RDeparse.Func; import com.oracle.truffle.r.runtime.RDispatch; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; @@ -83,7 +81,6 @@ import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; @@ -425,81 +422,6 @@ public final class RCallNode extends RSourceSectionNode implements RSyntaxNode, return CallArgumentsNode.create(modeChange, modeChangeAppliesToAll, args, signature); } - @Override - public void deparseImpl(RDeparse.State state) { - Object fname = RASTUtils.findFunctionName(this); - Func func = RASTDeparse.isInfixOperator(fname); - try { - state.startNodeDeparse(this); - if (func != null && arguments.v.length > 0) { - RASTDeparse.deparseInfixOperator(state, this, func); - } else { - if (fname instanceof RSymbol) { - String sfname = ((RSymbol) fname).getName(); - if (sfname.equals(":::") || sfname.equals("::")) { - // special infix, could be a:::b() or a:::b - RNode fn = getFunctionNode().unwrap(); - RSyntaxNode[] argValues; - if (fn instanceof RCallNode) { - argValues = ((RCallNode) fn).arguments.v; - } else { - argValues = arguments.v; - } - argValues[0].deparseImpl(state); - state.append(sfname); - argValues[1].deparseImpl(state); - if (!(fn instanceof RCallNode)) { - return; - } - } else if (sfname.equals("[<-") || sfname.equals("[[<-")) { - boolean isSubset = sfname.equals("[<-"); - arguments.v[0].deparseImpl(state); - state.append(isSubset ? "[" : "[["); - for (int i = 1; i < arguments.v.length - 1; i++) { - if (signature.getName(i) != null && !signature.getName(i).isEmpty()) { - state.append(signature.getName(i)); - state.append('='); - } - arguments.v[i].deparseImpl(state); - if (i != arguments.v.length - 2) { - state.append(", "); - } - } - state.append(isSubset ? "]" : "]]"); - state.append(" <- "); - arguments.v[arguments.v.length - 1].deparseImpl(state); - return; - } - } - getFunctionNode().deparse(state); - - deparseArguments(state, arguments.v, signature); - } - } finally { - state.endNodeDeparse(this); - } - } - - public static void deparseArguments(RDeparse.State state, RSyntaxNode[] arguments, ArgumentsSignature signature) { - state.append('('); - for (int i = 0; i < arguments.length; i++) { - RSyntaxNode argument = arguments[i]; - String name = signature.getName(i); - if (name != null) { - state.append(RDeparse.quotify(name, state)); - state.append(" = "); - } - if (argument != null) { - // e.g. not f(, foo) - argument.deparseImpl(state); - } - if (i != arguments.length - 1) { - state.append(", "); - } - } - state.append(')'); - } - @Override public void serializeImpl(RSerialize.State state) { state.setAsLangType(); @@ -632,7 +554,7 @@ public final class RCallNode extends RSourceSectionNode implements RSyntaxNode, public static RCallNode createCall(SourceSection src, RNode function, ArgumentsSignature signature, RSyntaxNode... arguments) { RCallNode call = new RCallNode(src, function, arguments, signature); if (src == RSyntaxNode.EAGER_DEPARSE) { - RASTDeparse.ensureSourceSection(call); + RDeparse.ensureSourceSection(call); } return call; } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/runtime/RASTDeparse.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/runtime/RASTDeparse.java deleted file mode 100644 index f77037cb76..0000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/runtime/RASTDeparse.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * 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-2012, The R Core Team - * Copyright (c) 2003, The R Foundation - * Copyright (c) 2013, 2016, Oracle and/or its affiliates - * - * All rights reserved. - */ -package com.oracle.truffle.r.nodes.runtime; - -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.source.SourceSection; -import com.oracle.truffle.r.nodes.RASTUtils; -import com.oracle.truffle.r.nodes.access.ConstantNode; -import com.oracle.truffle.r.nodes.function.GroupDispatchNode; -import com.oracle.truffle.r.nodes.function.RCallNode; -import com.oracle.truffle.r.runtime.Arguments; -import com.oracle.truffle.r.runtime.ArgumentsSignature; -import com.oracle.truffle.r.runtime.RDeparse; -import com.oracle.truffle.r.runtime.RDeparse.Func; -import com.oracle.truffle.r.runtime.RDeparse.PP; -import com.oracle.truffle.r.runtime.RDeparse.PPInfo; -import com.oracle.truffle.r.runtime.RDeparse.State; -import com.oracle.truffle.r.runtime.data.RFunction; -import com.oracle.truffle.r.runtime.data.RLanguage; -import com.oracle.truffle.r.runtime.data.RSymbol; -import com.oracle.truffle.r.runtime.nodes.RBaseNode; -import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; - -/** - * Deparse support for AST instances. - * - * N.B. We ignore the {@link SourceSection} for GnuR compatibility. E.g. in <a - * href="https://stat.ethz.ch/R-manual/R-devel/library/base/html/deparse.html">deparse - * specification</a>: "To avoid the risk of a source attribute out of sync with the actual function - * definition, the source attribute of a function will never be deparsed as an attribute." - * - * Parts transcribed from GnuR deparse.c - */ -public class RASTDeparse { - - private static final String SQUARE = "["; - - /** - * Ensure that {@code node} has a {@link SourceSection} by deparsing if necessary. - */ - public static void ensureSourceSection(RSyntaxNode node) { - SourceSection ss = node.getSourceSection(); - if (ss == RSyntaxNode.EAGER_DEPARSE) { - RDeparse.State state = RDeparse.State.createPrintableStateWithSource(); - node.deparseImpl(state); - state.assignSourceSections(); - } - } - - public static void deparse(State state, RLanguage rl) { - RBaseNode node = rl.getRep(); - node.deparse(state); - } - - public static void deparse(State state, RFunction f) { - ((RSyntaxNode) f.getRootNode()).deparseImpl(state); - } - - public static Func isInfixOperator(Object fname) { - if (fname instanceof RSymbol) { - Func func = RDeparse.getFunc(((RSymbol) fname).getName()); - if (func == null) { - return null; - } else { - return func.info.kind == PP.RETURN ? null : func; - } - } - return null; - } - - private static Func isInfixOperatorNode(RBaseNode node) { - if (node instanceof RCallNode || node instanceof GroupDispatchNode) { - Object fname = RASTUtils.findFunctionName(node); - return isInfixOperator(fname); - } else { - return null; - } - } - - public static void deparseInfixOperator(RDeparse.State state, Node node, RDeparse.Func func) { - Arguments<RSyntaxNode> args = RASTUtils.findCallArguments(node); - RSyntaxNode[] argValues = args.getArguments(); - PP kind = func.info.kind; - if (kind == PP.BINARY && argValues.length == 1) { - kind = PP.UNARY; - } - switch (kind) { - case UNARY: - state.append(func.op); - argValues[0].deparseImpl(state); - break; - - case BINARY: - case BINARY2: { - // TODO lbreak - boolean parens = needsParens(func.info, argValues[0], true); - if (parens) { - state.append('('); - } - argValues[0].deparseImpl(state); - if (parens) { - state.append(')'); - } - if (kind == PP.BINARY) { - state.append(' '); - } - state.append(func.op); - if (kind == PP.BINARY) { - state.append(' '); - } - parens = needsParens(func.info, argValues[1], false); - if (parens) { - state.append('('); - } - argValues[1].deparseImpl(state); - if (parens) { - state.append(')'); - } - break; - } - case SUBSET: { - boolean parens = needsParens(func.info, argValues[0], true); - if (parens) { - state.append('('); - } - argValues[0].deparseImpl(state); - if (parens) { - state.append(')'); - } - state.append(func.op == SQUARE ? "[" : "[["); - ArgumentsSignature signature = args.getSignature(); - // similar to ArgumentsNode.deparse() - for (int i = 1; i < argValues.length; i++) { - RSyntaxNode argument = argValues[i]; - String name = signature.getName(i); - if (name != null) { - state.append(name); - state.append(" = "); - } - if (argument != null) { - // e.g. not f(, foo) - argument.deparseImpl(state); - } - if (i != argValues.length - 1) { - state.append(", "); - } - } - state.append(func.op == SQUARE ? "]" : "]]"); - break; - } - case DOLLAR: - /* - * Experimentally one cannot assume that the call is well formed, i.e arguments may - * be missing. - */ - if (argValues.length > 0) { - argValues[0].deparseImpl(state); - } else { - state.append("NULL"); - } - state.append(func.op); - if (argValues.length > 1) { - String fieldName = ConstantNode.getString(argValues[1]); - if (fieldName != null) { - state.append(fieldName); - } else { - // FIXME: this needs to be handled in RCallNode, not here - argValues[1].deparseImpl(state); - } - } else { - state.append("NULL"); - } - break; - default: - assert false; - } - } - - private static boolean needsParens(PPInfo mainop, RSyntaxNode arg, boolean isLeft) { - RBaseNode node = RASTUtils.unwrap(arg); - Func func = isInfixOperatorNode(node); - if (func != null) { - Arguments<RSyntaxNode> args = RASTUtils.findCallArguments(node); - PPInfo arginfo = func.info; - switch (arginfo.kind) { - case BINARY: - case BINARY2: - switch (args.getArguments().length) { - case 1: - if (!isLeft) { - return false; - } - if (arginfo.prec == RDeparse.PREC_SUM) { - arginfo = arginfo.changePrec(RDeparse.PREC_SIGN); - } - break; - case 2: - break; - default: - return false; - } - return RDeparse.checkPrec(mainop, arginfo, isLeft); - - // CheckStyle: stop case fall through check - case UNARY: - if (mainop.prec > arginfo.prec || (mainop.prec == arginfo.prec && isLeft == mainop.rightassoc)) { - return true; - } - // CheckStyle: resume case fall through check - } - } else { - // TODO complex - } - return false; - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java index 6e881b5d1c..1ec20856b7 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringNode.java @@ -68,7 +68,7 @@ public abstract class CastStringNode extends CastStringBaseNode { for (int i = 0; i < operand.getLength(); i++) { Object o = operand.getDataAtAsObject(i); if (o instanceof RLanguage) { - sdata[i] = RDeparse.deparseForPrint(o); + sdata[i] = RDeparse.deparse(o); } else { sdata[i] = toString(o); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/GetNonSharedNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/GetNonSharedNode.java index c2c87b42fe..6c0435a233 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/GetNonSharedNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/GetNonSharedNode.java @@ -27,7 +27,6 @@ import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.api.source.SourceSection; -import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RSerialize; import com.oracle.truffle.r.runtime.data.RShareable; @@ -51,11 +50,6 @@ public abstract class GetNonSharedNode extends RNode implements RSyntaxNode { return o; } - @Override - public void deparseImpl(RDeparse.State state) { - throw RInternalError.unimplemented("deparseImpl"); - } - @Override public RSyntaxNode substituteImpl(REnvironment env) { throw RInternalError.unimplemented("substituteImpl"); 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 7ea3de6394..adcbe3db22 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 @@ -14,9 +14,9 @@ package com.oracle.truffle.r.runtime; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Arrays; +import java.util.HashSet; import java.util.Iterator; -import java.util.Map; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -27,13 +27,14 @@ import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RAttributes; import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute; import com.oracle.truffle.r.runtime.data.RComplex; -import com.oracle.truffle.r.runtime.data.RComplexVector; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RDataFrame; +import com.oracle.truffle.r.runtime.data.REmpty; import com.oracle.truffle.r.runtime.data.RExpression; import com.oracle.truffle.r.runtime.data.RExternalPtr; import com.oracle.truffle.r.runtime.data.RFactor; import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RIntSequence; import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RMissing; @@ -42,11 +43,19 @@ import com.oracle.truffle.r.runtime.data.RPairList; import com.oracle.truffle.r.runtime.data.RS4Object; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; -import com.oracle.truffle.r.runtime.data.RVector; +import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; +import com.oracle.truffle.r.runtime.nodes.RSyntaxCall; +import com.oracle.truffle.r.runtime.nodes.RSyntaxConstant; +import com.oracle.truffle.r.runtime.nodes.RSyntaxElement; +import com.oracle.truffle.r.runtime.nodes.RSyntaxFunction; +import com.oracle.truffle.r.runtime.nodes.RSyntaxLookup; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; +import com.oracle.truffle.r.runtime.nodes.RSyntaxVisitor; /** * Deparsing R objects. @@ -122,12 +131,12 @@ public class RDeparse { public static final int PREC_NS = 16; public static final int PREC_SUBSET = 17; - public static class PPInfo { + private static class PPInfo { public final PP kind; public final int prec; public final boolean rightassoc; - public PPInfo(PP kind, int prec, boolean rightassoc) { + PPInfo(PP kind, int prec, boolean rightassoc) { this.kind = kind; this.prec = prec; this.rightassoc = rightassoc; @@ -138,65 +147,63 @@ public class RDeparse { } } - public static class Func { + private static class Func { public final String op; + public final String closeOp; public final PPInfo info; - Func(String op, PPInfo info) { + Func(String op, String closeOp, PPInfo info) { this.op = op; + this.closeOp = closeOp; this.info = info; } } - // TODO COMPLETE THIS! - // @formatter:off @CompilationFinal private static final Func[] FUNCTAB = new Func[]{ - new Func("+", new PPInfo(PP.BINARY, PREC_SUM, false)), - new Func("-", new PPInfo(PP.BINARY, PREC_SUM, false)), - new Func("*", new PPInfo(PP.BINARY, PREC_PROD, false)), - new Func("/", new PPInfo(PP.BINARY, PREC_PROD, false)), - new Func("^", new PPInfo(PP.BINARY2, PREC_POWER, false)), - new Func("%%", new PPInfo(PP.BINARY2, PREC_PERCENT, false)), - new Func("%/%", new PPInfo(PP.BINARY2, PREC_PERCENT, false)), - new Func("%*%", new PPInfo(PP.BINARY2, PREC_PERCENT, false)), - new Func("==", new PPInfo(PP.BINARY, PREC_COMPARE, false)), - new Func("!=", new PPInfo(PP.BINARY, PREC_COMPARE, false)), - new Func("<", new PPInfo(PP.BINARY, PREC_COMPARE, false)), - new Func("<=", new PPInfo(PP.BINARY, PREC_COMPARE, false)), - new Func(">=", new PPInfo(PP.BINARY, PREC_COMPARE, false)), - new Func(">", new PPInfo(PP.BINARY, PREC_COMPARE, false)), - new Func("&", new PPInfo(PP.BINARY, PREC_AND, false)), - new Func("|", new PPInfo(PP.BINARY, PREC_OR, false)), - new Func("!", new PPInfo(PP.BINARY, PREC_NOT, false)), - new Func("&&", new PPInfo(PP.BINARY, PREC_AND, false)), - new Func("||", new PPInfo(PP.BINARY, PREC_OR, false)), - new Func(":", new PPInfo(PP.BINARY2, PREC_COLON, false)), - new Func("~", new PPInfo(PP.BINARY, PREC_TILDE, false)), - - new Func("if", new PPInfo(PP.IF, PREC_FN, true)), - new Func("while", new PPInfo(PP.WHILE, PREC_FN, false)), - new Func("for", new PPInfo(PP.FOR, PREC_FN, false)), - new Func("repeat", new PPInfo(PP.REPEAT, PREC_FN, false)), - new Func("break", new PPInfo(PP.BREAK, PREC_FN, false)), - new Func("next", new PPInfo(PP.NEXT, PREC_FN, false)), - new Func("return", new PPInfo(PP.RETURN, PREC_FN, false)), - new Func("function", new PPInfo(PP.FUNCTION, PREC_FN, false)), - new Func("{", new PPInfo(PP.CURLY, PREC_FN, false)), - new Func("(", new PPInfo(PP.PAREN, PREC_FN, false)), - new Func("<-", new PPInfo(PP.ASSIGN, PREC_LEFT, true)), - new Func("=", new PPInfo(PP.ASSIGN, PREC_LEFT, true)), - new Func("<<-", new PPInfo(PP.ASSIGN, PREC_LEFT, true)), - new Func("[", new PPInfo(PP.SUBSET, PREC_SUBSET, false)), - new Func("[[", new PPInfo(PP.SUBSET, PREC_SUBSET, false)), - new Func("$", new PPInfo(PP.DOLLAR, PREC_DOLLAR, false)), - new Func("@", new PPInfo(PP.DOLLAR, PREC_DOLLAR, false)), + new Func("+", null, new PPInfo(PP.BINARY, PREC_SUM, false)), + new Func("-", null, new PPInfo(PP.BINARY, PREC_SUM, false)), + new Func("*", null, new PPInfo(PP.BINARY, PREC_PROD, false)), + new Func("/", null, new PPInfo(PP.BINARY, PREC_PROD, false)), + new Func("^", null, new PPInfo(PP.BINARY2, PREC_POWER, false)), + new Func("%%", null, new PPInfo(PP.BINARY2, PREC_PERCENT, false)), + new Func("%/%", null, new PPInfo(PP.BINARY2, PREC_PERCENT, false)), + new Func("%*%", null, new PPInfo(PP.BINARY2, PREC_PERCENT, false)), + new Func("==", null, new PPInfo(PP.BINARY, PREC_COMPARE, false)), + new Func("!=", null, new PPInfo(PP.BINARY, PREC_COMPARE, false)), + new Func("<", null, new PPInfo(PP.BINARY, PREC_COMPARE, false)), + new Func("<=", null, new PPInfo(PP.BINARY, PREC_COMPARE, false)), + new Func(">=", null, new PPInfo(PP.BINARY, PREC_COMPARE, false)), + new Func(">", null, new PPInfo(PP.BINARY, PREC_COMPARE, false)), + new Func("&", null, new PPInfo(PP.BINARY, PREC_AND, false)), + new Func("|", null, new PPInfo(PP.BINARY, PREC_OR, false)), + new Func("!", null, new PPInfo(PP.BINARY, PREC_NOT, false)), + new Func("&&", null, new PPInfo(PP.BINARY, PREC_AND, false)), + new Func("||", null, new PPInfo(PP.BINARY, PREC_OR, false)), + new Func(":", null, new PPInfo(PP.BINARY2, PREC_COLON, false)), + new Func("~", null, new PPInfo(PP.BINARY, PREC_TILDE, false)), + + new Func("if", null, new PPInfo(PP.IF, PREC_FN, true)), + new Func("while", null, new PPInfo(PP.WHILE, PREC_FN, false)), + new Func("for", null, new PPInfo(PP.FOR, PREC_FN, false)), + new Func("repeat", null, new PPInfo(PP.REPEAT, PREC_FN, false)), + new Func("break", null, new PPInfo(PP.BREAK, PREC_FN, false)), + new Func("next", null, new PPInfo(PP.NEXT, PREC_FN, false)), + new Func("return", null, new PPInfo(PP.RETURN, PREC_FN, false)), + new Func("function", null, new PPInfo(PP.FUNCTION, PREC_FN, false)), + new Func("{", "}", new PPInfo(PP.CURLY, PREC_FN, false)), + new Func("(", ")", new PPInfo(PP.PAREN, PREC_FN, false)), + new Func("<-", null, new PPInfo(PP.ASSIGN, PREC_LEFT, true)), + new Func("=", null, new PPInfo(PP.ASSIGN, PREC_LEFT, true)), + new Func("<<-", null, new PPInfo(PP.ASSIGN, PREC_LEFT, true)), + new Func("[", "]", new PPInfo(PP.SUBSET, PREC_SUBSET, false)), + new Func("[[", "]]", new PPInfo(PP.SUBSET, PREC_SUBSET, false)), + new Func("$", null, new PPInfo(PP.DOLLAR, PREC_DOLLAR, false)), + new Func("@", null, new PPInfo(PP.DOLLAR, PREC_DOLLAR, false)), }; - // @formatter:on - public static final PPInfo BUILTIN = new PPInfo(PP.FUNCALL, PREC_FN, false); private static final PPInfo USERBINOP = new PPInfo(PP.BINARY2, PREC_PERCENT, false); - public static Func getFunc(String op) { + private static Func getFunc(String op) { for (Func func : FUNCTAB) { if (func.op.equals(op)) { return func; @@ -204,185 +211,100 @@ public class RDeparse { } // user binary op? if (isUserBinop(op)) { - return new Func(op, USERBINOP); + return new Func(op, null, USERBINOP); } return null; } private static boolean isUserBinop(String op) { int len = op.length(); - return op.charAt(0) == '%' && op.charAt(len - 1) == '%'; + return len > 0 && op.charAt(0) == '%' && op.charAt(len - 1) == '%'; } - public static PPInfo ppInfo(String op) { - Func func = getFunc(op); - if (func == null) { - // must be a builtin that we don't have in FUNCTAB - return BUILTIN; - } else { - return func.info; + /** + * Ensure that {@code node} has a {@link SourceSection} by deparsing if necessary. + */ + public static void ensureSourceSection(RSyntaxElement node) { + SourceSection ss = node.getSourceSection(); + if (ss == RSyntaxNode.EAGER_DEPARSE) { + new DeparseVisitor(true, RDeparse.MAX_Cutoff, false, -1, 0).append(node).fixupSources(); } } - public static final class State { - private final StringBuilder sb = new StringBuilder(); - private final ArrayList<String> lines; - private int linenumber; - private int len; - private int incurly; - private int inlist; - private boolean startline; - private int indent; - private final int cutoff; - private final boolean backtick; - private int opts; - @SuppressWarnings("unused") private int sourceable; - @SuppressWarnings("unused") private int longstring; - private final int maxlines; - private boolean active = true; - @SuppressWarnings("unused") private int isS4; - private boolean changed; - - private static class NodeSourceInfo { - private final int startCharIndex; - private int endCharIndex; - - NodeSourceInfo(int startCharIndex) { - this.startCharIndex = startCharIndex; - } - } - - /** - * Used when generating {@link SourceSection}s during deparse. - */ - private HashMap<RSyntaxNode, NodeSourceInfo> nodeMap; - - private State(int widthCutOff, boolean backtick, int maxlines, int opts, boolean needVector) { - this.cutoff = widthCutOff; - this.backtick = backtick; - this.maxlines = maxlines == -1 ? Integer.MAX_VALUE : maxlines; - this.opts = opts; - lines = needVector ? new ArrayList<>() : null; - } - - public static State createPrintableState() { - return new RDeparse.State(RDeparse.MAX_Cutoff, false, -1, 0, false); - } - - public static State createPrintableStateWithSource() { - State result = new RDeparse.State(RDeparse.MAX_Cutoff, false, -1, 0, false); - result.nodeMap = new HashMap<>(); - return result; - } - - private void preAppend() { - if (startline) { - startline = false; - indent(); - } - } - - public void indent() { - for (int i = 1; i <= indent; i++) { - if (i <= 4) { - append(" "); + private static Func isInfixOperatorNode(RSyntaxElement element) { + if (element instanceof RSyntaxCall) { + RSyntaxElement lhs = ((RSyntaxCall) element).getSyntaxLHS(); + if (lhs instanceof RSyntaxLookup) { + String name = ((RSyntaxLookup) lhs).getIdentifier(); + Func func = RDeparse.getFunc(name); + if (func == null) { + return null; } else { - append(" "); + return func.info.kind == PP.RETURN ? null : func; } } } + return null; + } - public void mark() { - changed = false; - } - - public boolean changed() { - return changed; - } - - public void incIndent() { - indent++; - } + private interface C extends AutoCloseable { + // this interface is used to get a shorter name and remove the checked exception + void close(); + } - public void decIndent() { - indent--; - } + private static final class SourceSectionElement { + public final RSyntaxElement element; + public final int start; + public final int length; - public void append(String s) { - preAppend(); - sb.append(s); - len += s.length(); - changed = true; + SourceSectionElement(RSyntaxElement element, int start, int length) { + this.element = element; + this.start = start; + this.length = length; } + } - public void append(char ch) { - preAppend(); - sb.append(ch); - len++; - changed = true; - } + private static final class DeparseVisitor { - private boolean linebreak(boolean lbreak) { - boolean result = lbreak; - if (len > cutoff) { - if (!lbreak) { - result = true; - indent++; - } - writeline(); - } - return result; - } + private final Visitor visitor = new Visitor(); - public void writeline() { - if (lines == null) { - // nl for debugging really, we don't care about format, - // although line length could be an issues also. - sb.append('\n'); - } else { - lines.add(sb.toString()); - sb.delete(0, Integer.MAX_VALUE); - } - linenumber++; - if (linenumber >= maxlines) { - active = false; - } - /* reset */ - len = 0; - startline = true; - changed = true; - } + private final StringBuilder sb = new StringBuilder(); - public void writeOpenCurlyNLIncIndent() { - append('{'); - writeline(); - incIndent(); - } + private final ArrayList<SourceSectionElement> sources; - public void writeNLOpenCurlyIncIndent() { - writeline(); - append('{'); - incIndent(); - } + private final int cutoff; + private final boolean backtick; + private int opts; + private final int nlines; - public void writeNLDecIndentCloseCurly() { - writeline(); - decIndent(); - append('}'); - } + private int inCurly = 0; + private int inList = 0; + private int indent = 0; + private int lastLineStart = 0; - public void decIndentWriteCloseCurly() { - decIndent(); - append('}'); + DeparseVisitor(boolean storeSource, int cutoff, boolean backtick, int opts, int nlines) { + this.cutoff = cutoff; + this.backtick = backtick; + this.opts = opts; + this.nlines = nlines; + this.sources = storeSource ? new ArrayList<>() : null; } - @Override - public String toString() { - // assumes needVector == false + public String getContents() { + // strip surplus newlines + int length = sb.length(); + while (length > 0) { + char c = sb.charAt(length - 1); + if (c != '\n' && c != ' ') { + break; + } + length--; + } + sb.setLength(length); return sb.toString(); } - boolean showAttributes() { + private boolean showAttributes() { return (opts & SHOWATTRIBUTES) != 0; } @@ -390,1018 +312,740 @@ public class RDeparse { return (opts & QUOTEEXPRESSIONS) != 0; } - private int dIndent = 0; + private DeparseVisitor append(char ch) { + assert ch != '\n'; + sb.append(ch); + return this; + } - private void dIndent() { - for (int i = 0; i < dIndent; i++) { - System.out.print(' '); - } + private DeparseVisitor append(String str) { + assert !str.contains("\n"); + sb.append(str); + return this; } - @SuppressWarnings("unused") - private void trace(boolean enter, RSyntaxNode node) { - String ms; - if (enter) { - ms = "start"; - dIndent(); - dIndent += 2; + private C withContext(RSyntaxElement... context) { + if (sources == null) { + return () -> { + }; } else { - ms = "end"; - dIndent -= 2; - dIndent(); + int startIndex = sb.length(); + return () -> { + for (RSyntaxElement element : context) { + sources.add(new SourceSectionElement(element, startIndex, sb.length() - startIndex)); + } + }; } - System.out.printf("%sNodeDeparse (%d): %s%n", ms, +sb.length(), node); } - public void startNodeDeparse(RSyntaxNode node) { - if (nodeMap != null) { - // trace(true, node); - nodeMap.put(node, new NodeSourceInfo(sb.length())); + public void fixupSources() { + Source source = Source.fromText(sb, "deparse"); + for (SourceSectionElement s : sources) { + SourceSection original = s.element.getSourceSection(); + SourceSection newSource = source.createSection(null, s.start, s.length); + s.element.setSourceSection(newSource); } } - public void endNodeDeparse(RSyntaxNode node) { - if (nodeMap != null) { - // trace(false, node); - NodeSourceInfo nsi = nodeMap.get(node); - nsi.endCharIndex = sb.length(); + private DeparseVisitor append(String str, RSyntaxElement... context) { + try (C c = withContext(context)) { + append(str); } + return this; } - public void assignSourceSections() { - assert nodeMap != null; - String sourceString = toString(); - Source source = Source.fromText(sourceString, "deparse"); - for (Map.Entry<RSyntaxNode, NodeSourceInfo> entry : nodeMap.entrySet()) { - RSyntaxNode node = entry.getKey(); - NodeSourceInfo nsi = entry.getValue(); - node.setSourceSection(source.createSection("", nsi.startCharIndex, nsi.endCharIndex - nsi.startCharIndex)); + public DeparseVisitor append(RSyntaxElement element) { + try (C c = withContext(element)) { + visitor.accept(element); } + return this; } - } - - /** - * Version for use by {@code RSerialize} to convert a CLOSXP/LANGSXP/PROMSXP into a parseable - * string. - */ - @TruffleBoundary - public static String deparse(RPairList pl) { - State state = new State(80, true, -1, 0, false); - return deparse2buff(state, pl).sb.toString(); - } - - /** - * Version to generate a printable string for e.g., error messages. - */ - @TruffleBoundary - public static String deparseForPrint(Object expr) { - State state = State.createPrintableState(); - return deparse2buff(state, expr).sb.toString(); - } - private static String stateToString(boolean abbrev, State state) { - String result; - int len = state.lines.size(); - if (len > 1) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < len; i++) { - String line = state.lines.get(i); - sb.append(line); - if (i < len - 1) { - sb.append('\n'); - } + private void printline() { + sb.append("\n"); + lastLineStart = sb.length(); + for (int i = 0; i < indent; i++) { + sb.append(i < 4 ? " " : " "); } - result = sb.toString(); - } else { - result = state.lines.get(0); - } - if (abbrev && result.length() > 13) { - result = result.substring(0, 14); - } - return result; - } - - @TruffleBoundary - public static String deparse1Line(Object expr, boolean abbrev) { - State state = deparse1WithCutoff(expr, MAX_Cutoff, true, 0, -1); - return stateToString(abbrev, state); - } - - @TruffleBoundary - public static String deparse1Line(Object expr, boolean abbrev, int cutoff, int opts) { - State state = deparse1WithCutoff(expr, cutoff, true, opts, -1); - return stateToString(abbrev, state); - } - - /** - * Version for {@code deparse}. - */ - @TruffleBoundary - public static String[] deparse(Object expr, int cutoff, boolean backtick, int opts, int nlines) { - State state = deparse1WithCutoff(expr, cutoff, backtick, opts, nlines); - String[] data = new String[state.lines.size()]; - state.lines.toArray(data); - return data; - } - - private static State deparse1WithCutoff(Object expr, int cutoff, boolean backtick, int opts, int nlines) { - State state = new State(cutoff, backtick, nlines, opts, true); - deparse2buff(state, expr); - state.writeline(); - return state; - } - - @TruffleBoundary - public static State deparse2buff(State state, Object obj) { - boolean lbreak = false; - if (!state.active) { - return state; } - SEXPTYPE type = typeof(obj); - switch (type) { - case NILSXP: - state.append("NULL"); - break; - - case MISSINGARG_SXP: - case EMPTYARG_SXP: - break; - - case SYMSXP: { - if (state.quoteExpressions()) { - state.append("quote("); + private static boolean isSequence(RSyntaxElement element) { + if (element instanceof RSyntaxCall) { + RSyntaxElement lhs = ((RSyntaxCall) element).getSyntaxLHS(); + if (lhs instanceof RSyntaxLookup) { + RSyntaxLookup lookup = (RSyntaxLookup) lhs; + return "{".equals(lookup.getIdentifier()); } - String name = ((RSymbol) obj).getName(); - if (state.backtick) { - name = quotify(name, BACKTICK); - } - state.append(name); - if (state.quoteExpressions()) { - state.append(')'); - } - break; - } - - case CHARSXP: - state.append((String) obj); - break; - - case PROMSXP: { - RPairList f = (RPairList) obj; - deparse2buff(state, f.cdr()); - break; } + return false; + } - case CLOSXP: { - RPairList f = (RPairList) obj; - state.append("function ("); - if (f.car() instanceof RPairList) { - args2buff(state, f.car(), false, true); - } - state.append(") "); - state.writeline(); - deparse2buff(state, f.cdr()); - break; + private static String isConstantString(RSyntaxElement element) { + if (element instanceof RSyntaxConstant) { + return RRuntime.asStringLengthOne(((RSyntaxConstant) element).getValue()); } + return null; + } - case FUNSXP: { - RFunction f = (RFunction) obj; - if (f.isBuiltin()) { - state.append(".Primitive("); - state.append("\""); - state.append(f.getName()); - state.append("\")"); - } else { - RContext.getRRuntimeASTAccess().deparse(state, f); + private boolean linebreak(boolean lbreak) { + boolean result = lbreak; + if ((sb.length() - lastLineStart) > cutoff) { + if (!lbreak) { + result = true; + indent++; } - break; + printline(); } + return result; + } - case ENVSXP: - state.append("<environment>"); - break; - - case FASTR_FACTOR: - deparseList(state, ((RFactor) obj).getVector()); - break; - - case FASTR_DATAFRAME: - deparseList(state, ((RDataFrame) obj).getVector()); - break; - - case VECSXP: - deparseList(state, (RList) obj); - break; - - case EXPRSXP: - RExpression expr = (RExpression) obj; - state.append("expression("); - vec2buff(state, expr.getList()); - state.append(')'); - break; - - case LISTSXP: { - state.append("pairlist("); - RPairList s = (RPairList) obj; - RPairList t = s; - while (t != null && t.cdr() != RNull.instance) { - if (t.getTag() != null && !t.isNullTag()) { - deparse2buff(state, t.getTag()); - state.append(" = "); - } - deparse2buff(state, t.car()); - state.append(", "); - t = next(t); - } - if (t.getTag() != null && !t.isNullTag()) { - deparse2buff(state, t.getTag()); - state.append(" = "); + private C indent() { + indent++; + return new C() { + public void close() { + indent--; } - deparse2buff(state, t.car()); - state.append(')'); - break; - } + }; + } - case LANGSXP: { - if (obj instanceof RLanguage) { - RContext.getRRuntimeASTAccess().deparse(state, (RLanguage) obj); - break; + private C inCurly() { + inCurly++; + return new C() { + public void close() { + inCurly--; } - RPairList f = (RPairList) obj; - Object car = f.car(); - Object cdr = f.cdr(); - SEXPTYPE carType = typeof(car); - if (carType == SEXPTYPE.SYMSXP) { - RSymbol symbol = (RSymbol) car; // TODO could be a promise according to GnuR - String op = symbol.getName(); - boolean userBinop = false; - if (RContext.isPrimitiveBuiltin(op) || (userBinop = isUserBinop(op))) { - RPairList pl = cdr instanceof RPairList ? (RPairList) cdr : null; - PPInfo fop; - if (userBinop) { - // TODO check for named args and deparse as normal function - fop = USERBINOP; - } else { - fop = ppInfo(op); - } - if (fop.kind == PP.BINARY) { - switch (pl.getLength()) { - case 1: - fop = new PPInfo(PP.UNARY, fop.prec == PREC_SUM ? PREC_SIGN : fop.prec, fop.rightassoc); - break; - case 2: - break; - default: - assert false; - } - } else if (fop.kind == PP.BINARY2) { - if (pl.getLength() != 2) { - fop = new PPInfo(PP.FUNCALL, 0, false); - } else if (userBinop) { - fop = new PPInfo(PP.BINARY, fop.prec, fop.rightassoc); + }; + } + + private final class Visitor extends RSyntaxVisitor<Void> { + + @Override + protected Void visit(RSyntaxCall call) { + RSyntaxElement lhs = call.getSyntaxLHS(); + RSyntaxElement[] args = call.getSyntaxArguments(); + if (lhs instanceof RSyntaxLookup) { + String symbol = ((RSyntaxLookup) lhs).getIdentifier(); + RDeparse.Func func = RDeparse.getFunc(symbol); + if (func != null) { + PPInfo info = func.info; + if (args.length == 0) { + switch (info.kind) { + case BREAK: + case NEXT: + append(func.op, call, lhs); + return null; } - } - switch (fop.kind) { - case ASSIGN: { - Object left = pl.car(); - boolean parens = needsParens(fop, left, true); - if (parens) { - state.append('('); - } - deparse2buff(state, left); - state.append(' '); - state.append(op); - state.append(' '); - Object right = pl.cadr(); - parens = needsParens(fop, right, false); - deparse2buff(state, right); - if (parens) { - state.append(')'); - } - break; + } else if (args.length == 1) { + switch (info.kind) { + case BINARY: + case BINARY2: + append(func.op, lhs).append(args[0]); + return null; + case REPEAT: + append("repeat", lhs).append(' ').append(args[0]); + return null; + case PAREN: + append(func.op, lhs).append(args[0]).append(func.closeOp); + return null; } - - case IF: { - state.append("if ("); - deparse2buff(state, pl.car()); - state.append(')'); - boolean lookahead = false; - if (state.incurly > 0 && state.inlist == 0) { - lookahead = curlyahead(pl.cadr()); - if (!lookahead) { - state.writeline(); - state.indent++; + } else if (args.length == 2) { + switch (info.kind) { + case ASSIGN: + case BINARY: + case BINARY2: + appendWithParens(args[0], info, true); + if (info.kind != PP.BINARY2) { + append(' ').append(func.op, lhs).append(' '); + } else { + append(func.op); } - } - int lenpl = pl.getLength(); - if (lenpl > 2) { - deparse2buff(state, pl.cadr()); - if (state.incurly > 0 && state.inlist == 0) { - state.writeline(); - if (!lookahead) { - state.indent--; - } + appendWithParens(args[1], info, false); + return null; + case DOLLAR: + appendWithParens(args[0], info, true); + append(func.op, lhs); + String name = isConstantString(args[1]); + if (name != null && isValidName(name)) { + append(name, args[1]); } else { - state.append(' '); + appendWithParens(args[1], info, false); } - state.append("else "); - deparse2buff(state, pl.caddr()); - } else { - deparse2buff(state, pl.cadr()); - if (state.incurly > 0 && !lookahead && state.inlist == 0) { - state.indent--; + return null; + case IF: + append("if", lhs).append(" (").append(args[0]).append(") "); + if (inCurly > 0 && inList == 0 && !isSequence(args[1])) { + printline(); + try (C c = indent()) { + append(args[1]); + } + } else { + append(args[1]); } - } - break; - } - - case WHILE: { - state.append("while ("); - deparse2buff(state, pl.car()); - state.append(") "); - deparse2buff(state, pl.cadr()); - break; + return null; + case WHILE: + append("while", lhs).append(" (").append(args[0]).append(") ").append(args[1]); + return null; } - - case FOR: { - state.append("for ("); - deparse2buff(state, pl.car()); - state.append(" in "); - deparse2buff(state, pl.cadr()); - state.append(") "); - deparse2buff(state, ((RPairList) pl.cdr()).cadr()); - break; - } - - case REPEAT: - state.append("repeat "); - deparse2buff(state, pl.car()); - break; - - case BINARY: - case BINARY2: { - Object left = pl.car(); - boolean parens = needsParens(fop, left, true); - if (parens) { - state.append('('); - } - deparse2buff(state, pl.car()); - if (parens) { - state.append(')'); - } - if (fop.kind == PP.BINARY) { - state.append(' '); - } - state.append(op); - if (fop.kind == PP.BINARY) { - state.append(' '); - } - if (fop.kind == PP.BINARY) { - lbreak = state.linebreak(lbreak); - } - Object right = pl.cadr(); - parens = needsParens(fop, right, false); - if (parens) { - state.append('('); - } - deparse2buff(state, right); - if (parens) { - state.append(')'); - } - if (fop.kind == PP.BINARY) { - if (lbreak) { - state.indent--; - lbreak = false; + } else if (args.length == 3) { + switch (symbol) { + case "for": + append("for", lhs).append(" (").append(args[0]).append(" in ").append(args[1]).append(") ").append(args[2]); + return null; + case "if": + append("if", lhs).append(" (").append(args[0]).append(") "); + if (inCurly > 0 && inList == 0 && !isSequence(args[1])) { + printline(); + try (C c = indent()) { + append(args[1]).printline(); + } + } else { + append(args[1]); + if (inCurly > 0 && inList == 0) { + printline(); + } else { + append(' '); + } } - } - break; - } - - case UNARY: { - state.append(op); - Object left = pl.car(); - boolean parens = needsParens(fop, left, true); - if (parens) { - state.append('('); - } - deparse2buff(state, left); - if (parens) { - state.append(')'); - } - break; - } - - case CURLY: { - state.append(op); - state.incurly++; - state.indent++; - state.writeline(); - while (pl != null) { - deparse2buff(state, pl.car()); - state.writeline(); - pl = next(pl); - } - state.indent--; - state.append('}'); - state.incurly--; - break; - } - - case PAREN: - state.append('('); - deparse2buff(state, pl.car()); - state.append(')'); - break; - - case SUBSET: { - Object left = pl.car(); - boolean parens = needsParens(fop, left, true); - if (parens) { - state.append('('); - } - deparse2buff(state, left); - if (parens) { - state.append(')'); - } - state.append(op); - args2buff(state, pl.cdr(), false, false); - if (op.equals("[")) { - state.append(']'); - } else { - state.append("]]"); - } - break; + append("else ").append(args[2]); + return null; } - - case FUNCTION: - state.append(op); - state.append('('); - args2buff(state, pl.car(), false, true); - state.append(") "); - deparse2buff(state, pl.cadr()); - break; - - case DOLLAR: { - Object left = pl.car(); - boolean parens = needsParens(fop, left, true); - if (parens) { - state.append('('); - } - deparse2buff(state, left); - if (parens) { - state.append(')'); - } - state.append(op); - Object right = pl.cadr(); - if (right instanceof RSymbol) { - deparse2buff(state, right); - } else { - parens = needsParens(fop, right, true); - if (parens) { - state.append('('); - } - deparse2buff(state, right); - if (parens) { - state.append(')'); + } + switch (info.kind) { + case CURLY: + boolean braces = args.length != 1 || hasBraces(call); + if (braces) { + append("{", lhs); + try (C i = indent(); C c = inCurly()) { + for (RSyntaxElement statement : args) { + printline(); + append(statement); + } } - } - break; - } - - case FUNCALL: - case RETURN: { - if (state.backtick) { - state.append(quotify(op, BACKTICK)); + printline(); + append('}'); } else { - state.append(quotify(op, DQUOTE)); // quote? + append(args[0]); } - state.append('('); - state.inlist++; - args2buff(state, cdr, false, false); - state.inlist--; - state.append(')'); - break; - } - - case NEXT: - state.append("next"); - break; - - case BREAK: - state.append("break"); - break; - - default: - throw RInternalError.unimplemented(); + return null; + case SUBSET: + appendWithParens(args[0], info, true); + append(func.op, lhs).appendArgs(call.getSyntaxSignature(), args, 1, false).append(func.closeOp); + return null; } - } else { - // TODO promise? - if (op.equals("::") || op.equals(":::")) { - // special case - deparse2buff(state, f.cadr()); - state.append(op); - deparse2buff(state, f.caddr()); + } + if ("::".equals(symbol) || ":::".equals(symbol)) { + if (args.length == 0) { + append("NULL").append(symbol).append("NULL"); + } else if (args.length == 1) { + append(args[0]).append(symbol).append("NULL"); } else { - state.append(quotify(op, BACKTICK)); - state.append('('); - args2buff(state, cdr, false, false); - state.append(')'); + append(args[0]).append(symbol).append(args[1]); } + return null; } - } else if (carType == SEXPTYPE.CLOSXP || carType == SEXPTYPE.SPECIALSXP || carType == SEXPTYPE.BUILTINSXP) { - if (parenthesizeCaller(car)) { - state.append('('); - deparse2buff(state, car); - state.append(')'); - } else { - deparse2buff(state, car); - } - state.append('('); - args2buff(state, cdr, false, false); - state.append(')'); - } else { - // lambda - if (parenthesizeCaller(car)) { - state.append('('); - deparse2buff(state, car); - state.append(')'); - } else { - deparse2buff(state, car); - } - state.append('('); - args2buff(state, f.cdr(), false, false); - state.append(')'); } - break; - } - case STRSXP: - case LGLSXP: - case INTSXP: - case REALSXP: - case CPLXSXP: - case RAWSXP: - vector2buff(state, checkScalarVector(obj)); - break; - - case BCODESXP: { - /* - * This should only happen in a call from RSerialize when unserializing a CLOSXP. - * There is no value in following GnuR and appending <bytecode>, as we need the - * source., which is (we expect) in the RPairList cdr (which is an RList). - * Experimentally, only the first element of the list should be deparsed. - */ - // state.append("<bytecode>"); - RPairList pl = (RPairList) obj; - RList plcdr = (RList) pl.cdr(); - deparse2buff(state, plcdr.getDataAtAsObject(0)); - break; + PPInfo info = new PPInfo(PP.FUNCALL, PREC_FN, false); + appendWithParens(lhs, info, true); + append('(').appendArgs(call.getSyntaxSignature(), args, 0, false).append(')'); + return null; } - case FASTR_DOUBLE: - case FASTR_INT: - case FASTR_BYTE: - case FASTR_COMPLEX: - vecElement2buff(state, SEXPTYPE.convertFastRScalarType(type), obj); - break; - - case FASTR_CONNECTION: - // TODO GnuR deparses this as a structure - state.append("NULL"); - break; - - case S4SXP: { - RS4Object s4Obj = (RS4Object) obj; - state.append("new(\""); - Object clazz = s4Obj.getAttribute("class"); - state.append(clazz == null ? "S4" : RRuntime.toString(RRuntime.asStringLengthOne(clazz))); - state.append('\"'); - state.incIndent(); - state.writeline(); - if (s4Obj.getAttributes() != null) { - for (RAttribute att : s4Obj.getAttributes()) { - if (!"class".equals(att.getName())) { - state.append(", "); - state.append(att.getName()); - state.append(" = "); - deparse2buff(state, att.getValue()); - state.writeline(); - } - } + public boolean hasBraces(RSyntaxElement node) { + SourceSection ss = node.getSourceSection(); + if (ss == null || ss == RSyntaxNode.SOURCE_UNAVAILABLE) { + // this is statistical guess + return true; + } else { + return ss.getCode().startsWith("{"); } - state.decIndent(); - state.append(')'); - break; } - case EXTPTRSXP: { - RExternalPtr ext = (RExternalPtr) obj; - state.append("<pointer: 0x"); - state.append(Long.toHexString(ext.getAddr())); - state.append('>'); - break; - } - - default: - throw RInternalError.shouldNotReachHere("unexpected SEXPTYPE: " + type); - } - return state; - } - - private static SEXPTYPE typeof(Object obj) { - Class<?> klass = obj.getClass(); - if (klass == RPairList.class) { - return ((RPairList) obj).getType(); - } else { - return SEXPTYPE.typeForClass(klass); - } - } - - private static RAbstractVector checkScalarVector(Object obj) { - if (obj instanceof String) { - return RDataFactory.createStringVectorFromScalar((String) obj); - } else if (obj instanceof Byte) { - return RDataFactory.createLogicalVectorFromScalar((Byte) obj); - } else if (obj instanceof Integer) { - return RDataFactory.createIntVectorFromScalar((Integer) obj); - } else if (obj instanceof Double) { - return RDataFactory.createDoubleVectorFromScalar((Double) obj); - } else if (obj instanceof RComplex) { - return RDataFactory.createComplexVectorFromScalar((RComplex) obj); - } else { - return (RAbstractVector) obj; - } - } - @SuppressWarnings("unused") - private static boolean curlyahead(Object obj) { - return false; - } + @Override + protected Void visit(RSyntaxConstant constant) { + // coerce scalar values to vectors and unwrap data frames and factors: + Object value = RRuntime.asAbstractVector(constant.getValue()); + if (value instanceof RDataFrame) { + value = ((RDataFrame) value).getVector(); + } else if (value instanceof RFactor) { + value = ((RFactor) value).getVector(); + } - /** - * Check for whether we need to parenthesize a caller. The unevaluated ones are tricky: We want - * - * <pre> - * x$f(z) - * x[n](z) - * base::mean(x) - * </pre> - * - * but <pre< (f+g)(z) (function(x) 1)(x) </pre> etc. - */ - private static boolean parenthesizeCaller(Object s) { - if (s instanceof RPairList) { - RPairList pl = (RPairList) s; - if (pl.getType() == SEXPTYPE.CLOSXP) { - return true; - } else if (pl.getType() == SEXPTYPE.LANGSXP) { - Object car = pl.car(); - if (car instanceof RSymbol) { - String op = ((RSymbol) car).getName(); - if (isUserBinop(op)) { - return true; + if (value instanceof RExpression) { + append("expression(").appendListContents(((RExpression) value).getList()).append(')'); + } else if (value instanceof RAbstractListVector) { + RAbstractListVector obj = (RAbstractListVector) value; + try (C c = withAttributes(obj)) { + append("list(").appendListContents(obj).append(')'); + } + } else if (value instanceof RAbstractVector) { + appendVector((RAbstractVector) value); + } else if (value instanceof RNull) { + append("NULL"); + } else if (value instanceof RFunction) { + RFunction f = (RFunction) value; + if (f.isBuiltin()) { + append(".Primitive(\"").append(f.getName()).append("\")"); + } else { + append(RContext.getRRuntimeASTAccess().getSyntaxFunction(f)); } - if (RContext.isPrimitiveBuiltin(op)) { - PPInfo info = ppInfo(op); - if (info.prec >= PREC_DOLLAR || info.kind == PP.FUNCALL || info.kind == PP.PAREN || info.kind == PP.CURLY) { - return true; + } else if (value instanceof RPairList) { + RPairList pl = (RPairList) value; + assert pl.getType() == SEXPTYPE.LISTSXP; + append("pairlist("); + Arguments<RSyntaxElement> arguments = wrapArguments(pl); + appendArgs(arguments.getSignature(), arguments.getArguments(), 0, false); + append(')'); + } else if (value instanceof RS4Object) { + RS4Object s4Obj = (RS4Object) value; + Object clazz = s4Obj.getAttribute("class"); + String className = clazz == null ? "S4" : RRuntime.toString(RRuntime.asStringLengthOne(clazz)); + append("new(\"").append(className).append('\"'); + try (C c = indent()) { + printline(); + if (s4Obj.getAttributes() != null) { + for (RAttribute att : s4Obj.getAttributes()) { + if (!"class".equals(att.getName())) { + append(", ").append(att.getName()).append(" = ").process(att.getValue()).printline(); + } + } } } - return false; + append(')'); + } else if (value instanceof RExternalPtr) { + append("<pointer: 0x").append(Long.toHexString(((RExternalPtr) value).getAddr())).append('>'); + } else if (value instanceof REnvironment) { + append("<environment>"); } else { - return true; + throw RInternalError.shouldNotReachHere("unexpected: " + value); } + return null; + } + @Override + protected Void visit(RSyntaxLookup lookup) { + if (!backtick || isValidName(lookup.getIdentifier())) { + append(lookup.getIdentifier()); + } else { + append(quotify(lookup.getIdentifier(), BACKTICK)); + } + return null; } - } - return false; - } - private static RPairList next(RPairList pairlist) { - if (pairlist.cdr() == RNull.instance) { - return null; - } else { - return (RPairList) pairlist.cdr(); - } - } + @Override + protected Void visit(RSyntaxFunction function) { + append("function ("); + appendArgs(function.getSyntaxSignature(), function.getSyntaxArgumentDefaults(), 0, true); + append(") "); + RSyntaxElement body = function.getSyntaxBody(); + boolean newline = true; + if (body instanceof RSyntaxCall) { + RSyntaxCall c = (RSyntaxCall) body; + if (c.getSyntaxLHS() instanceof RSyntaxLookup) { + RSyntaxLookup l = (RSyntaxLookup) c.getSyntaxLHS(); + if ("{".equals(l.getIdentifier())) { + newline = c.getSyntaxArguments().length == 1 && !hasBraces(c); + } - /** - * Deparse list, dataframe, factor (different representation types in FastR). - */ - private static void deparseList(State state, RVector obj) { - if (state.showAttributes()) { - attr1(state, obj); - } - state.append("list("); - vec2buff(state, obj); - state.append(')'); - if (state.showAttributes()) { - attr2(state, obj); + } + } + if (newline) { + printline(); + } + append(body); + return null; + } } - } - /** - * Check for needing parentheses in expressions. needsparens looks at an arg to a unary or - * binary operator to determine if it needs to be parenthesized when deparsed.{@code mainop} is - * a unary or binary operator, {@code arg} is an argument to it, on the left if - * {@code left == true}. - */ - private static boolean needsParens(PPInfo mainop, Object arg, boolean left) { - if (arg instanceof RPairList) { - RPairList pl = (RPairList) arg; - if (pl.getType() == SEXPTYPE.LANGSXP) { - Object car = pl.car(); - if (car instanceof RSymbol) { - String op = ((RSymbol) car).getName(); - if (RContext.isPrimitiveBuiltin(op)) { - PPInfo arginfo = ppInfo(op); - switch (arginfo.kind) { - case BINARY: - case BINARY2: { - Object cdr = pl.cdr(); - int length = (cdr instanceof RPairList) ? ((RPairList) cdr).getLength() : 1; - switch (length) { - case 1: - if (!left) { - return false; - } - if (arginfo.prec == PREC_SUM) { - arginfo = arginfo.changePrec(PREC_SIGN); - } - break; - case 2: - break; - default: - return false; - } - return checkPrec(mainop, arginfo, left); + private void appendWithParens(RSyntaxElement arg, PPInfo mainOp, boolean isLeft) { + Func func = isInfixOperatorNode(arg); + boolean needsParens = false; + if (func != null) { + PPInfo arginfo = func.info; + switch (arginfo.kind) { + case BINARY: + case BINARY2: + RSyntaxElement[] subArgs = ((RSyntaxCall) arg).getSyntaxArguments(); + if (subArgs.length == 1) { + if (isLeft && arginfo.prec == RDeparse.PREC_SUM) { + arginfo = arginfo.changePrec(RDeparse.PREC_SIGN); } - - case ASSIGN: - case SUBSET: - case UNARY: - case DOLLAR: - return checkPrec(mainop, arginfo, left); - - case FOR: - case IF: - case WHILE: - case REPEAT: - return left; - default: - return false; - } - } else if (isUserBinop(op)) { - if (mainop.prec == PREC_PERCENT || (mainop.prec == PREC_PERCENT && left == mainop.rightassoc)) { - return true; + } else if (subArgs.length == 2) { + needsParens = checkPrec(mainOp, arginfo, isLeft); } - } + break; + case UNARY: + needsParens = mainOp.prec > arginfo.prec || (mainOp.prec == arginfo.prec && isLeft == mainOp.rightassoc); + break; + default: + break; } } - } else if (isComplexLengthOne(arg)) { - if (mainop.prec > PREC_SUM || (mainop.prec == PREC_SUM && left == mainop.rightassoc)) { - return true; + if (needsParens) { + append('('); + append(arg); + append(')'); + } else { + append(arg); } } - return false; - } - public static boolean checkPrec(PPInfo mainop, PPInfo arginfo, boolean left) { - return mainop.prec > arginfo.prec || (mainop.prec == arginfo.prec && left == mainop.rightassoc); - } + private static boolean checkPrec(PPInfo mainop, PPInfo arginfo, boolean left) { + return mainop.prec > arginfo.prec || (mainop.prec == arginfo.prec && left == mainop.rightassoc); + } - private static boolean isComplexLengthOne(Object arg) { - return ((arg instanceof RComplexVector && ((RComplexVector) arg).getLength() == 1) || arg instanceof RComplex); - } + private DeparseVisitor appendArgs(ArgumentsSignature signature, RSyntaxElement[] args, int start, boolean formals) { + for (int i = start; i < args.length; i++) { + RSyntaxElement argument = args[i]; + if (argument instanceof RSyntaxLookup && ((RSyntaxLookup) argument).getIdentifier().isEmpty()) { + argument = null; + } + if (argument instanceof RSyntaxConstant && ((RSyntaxConstant) argument).getValue() instanceof REmpty) { + argument = null; + } + String name = signature.getName(i); + if (name != null && name.isEmpty()) { + name = null; + } + if (name != null) { + if (isValidName(name)) { + append(name); + } else { + append(quotify(name, BACKTICK)); + } + if (!formals || argument != null) { + append(" = "); + } + } + if (argument != null) { + append(argument); + } + if (i != args.length - 1) { + append(", "); + } + } + return this; + } - @TruffleBoundary - /** Handles {@link RList}, (@link RExpression}, {@link RDataFrame} and {@link RFactor}. Method name same as GnuR. - */ - private static State vec2buff(State state, RVector v) { - int n = v.getLength(); - boolean lbreak = false; - Object names = v.getNames(); - RStringVector snames = names == RNull.instance ? null : (RStringVector) names; - for (int i = 0; i < n; i++) { - if (i > 0) { - state.append(", "); + private DeparseVisitor process(Object v) { + assert RRuntime.asAbstractVector(v) instanceof RTypedValue; + assert !(v instanceof RSyntaxElement); + + RSyntaxElement element = wrap(v, false); + if (!quoteExpressions() || element instanceof RSyntaxConstant) { + append(element); + } else { + append("quote("); + append(element); + append(')'); } - lbreak = state.linebreak(lbreak); - String sname = snames == null ? null : snames.getDataAt(i); - if (snames != null && ((sname = snames.getDataAt(i)) != null)) { - state.append(sname); - state.append(" = "); + return this; + } + + private static RSyntaxElement wrap(Object v, boolean isCallLHS) { + Object value = RRuntime.asAbstractVector(v); + if (value instanceof RSymbol) { + return RSyntaxLookup.createDummyLookup(null, ((RSymbol) value).getName(), isCallLHS); + } else if (value instanceof RLanguage) { + return ((RLanguage) value).getRep().asRSyntaxNode(); + } else if (value instanceof RPairList) { + RPairList pl = (RPairList) value; + switch (pl.getType()) { + case LANGSXP: + return wrapCall(pl); + case CLOSXP: + return wrapFunctionExpression(pl); + default: + throw RInternalError.shouldNotReachHere("sexptype: " + pl.getType()); + } + } else if (value instanceof RMissing) { + return RSyntaxLookup.createDummyLookup(null, "", false); + } else { + return RSyntaxConstant.createDummyConstant(null, value); } - deparse2buff(state, v.getDataAtAsObject(i)); - } - if (lbreak) { - state.decIndent(); } - return state; - } - @TruffleBoundary - private static State args2buff(State state, Object args, @SuppressWarnings("unused") boolean lineb, boolean formals) { - boolean lbreak = false; - RPairList arglist; - if (args instanceof RNull) { - arglist = null; - } else { - arglist = (RPairList) args; - } - while (arglist != null) { - Object argTag = arglist.getTag(); - if (argTag != null && argTag != RNull.instance) { - String rs = ((RSymbol) arglist.getTag()).getName(); - if (rs.equals("...")) { - state.append(rs); + private static RSyntaxElement wrapCall(RPairList pl) { + Object car = pl.car(); + if (car instanceof RSymbol && ((RSymbol) car).getName().equals("function")) { + RPairList fun = (RPairList) pl.cdr(); + return wrapFunctionExpression(fun); + } + RSyntaxElement lhs = wrap(car, true); + + Arguments<RSyntaxElement> args = wrapArguments(pl.cdr()); + return RSyntaxCall.createDummyCall(null, lhs, args.getSignature(), args.getArguments()); + } + + private static RSyntaxElement wrapFunctionExpression(RPairList fun) { + Arguments<RSyntaxElement> args = wrapArguments(fun.car()); + RSyntaxElement body; + Object cdr = fun.cdr(); + if (cdr instanceof RPairList) { + RPairList pl = (RPairList) cdr; + if (pl.getType() == SEXPTYPE.BCODESXP) { + RAbstractListVector list = (RAbstractListVector) fun.cddr(); + body = wrap(list.getDataAtAsObject(0), false); + } else if (pl.getType() == SEXPTYPE.LISTSXP) { + assert pl.cadr() == RNull.instance && pl.cddr() == RNull.instance; + body = wrap(pl.car(), false); } else { - state.append(quotify(rs, state.backtick ? BACKTICK : DQUOTE)); + assert pl.getType() == SEXPTYPE.LANGSXP; + body = wrap(pl, false); } + } else { + body = wrap(cdr, false); + } - if (formals) { - if (arglist.car() != RMissing.instance) { - state.append(" = "); - deparse2buff(state, arglist.car()); - } + return RSyntaxFunction.createDummyFunction(null, args.getSignature(), args.getArguments(), body); + } + + private static Arguments<RSyntaxElement> wrapArguments(Object args) { + RPairList arglist = args instanceof RNull ? null : (RPairList) args; + ArrayList<RSyntaxElement> argElements = new ArrayList<>(); + ArrayList<String> argNames = new ArrayList<>(); + while (arglist != null) { + Object argTag = arglist.getTag(); + if (argTag != null && argTag != RNull.instance) { + String rs = ((RSymbol) arglist.getTag()).getName(); + argNames.add(rs); } else { - state.append(" = "); - if (arglist.car() != RMissing.instance) { - deparse2buff(state, arglist.car()); - } + argNames.add(null); } + argElements.add(wrap(arglist.car(), false)); + arglist = next(arglist); + } + RSyntaxElement[] arguments = argElements.toArray(new RSyntaxElement[argElements.size()]); + ArgumentsSignature signature = ArgumentsSignature.get(argNames.toArray(new String[argNames.size()])); + Arguments<RSyntaxElement> arg = new Arguments<>(arguments, signature); + return arg; + } + + private static RPairList next(RPairList pairlist) { + if (pairlist.cdr() == RNull.instance) { + return null; } else { - deparse2buff(state, arglist.car()); + return (RPairList) pairlist.cdr(); } - arglist = next(arglist); - if (arglist != null) { - state.append(", "); - lbreak = state.linebreak(lbreak); + } + + private void appendVector(RAbstractVector vec) { + SEXPTYPE type = SEXPTYPE.typeForClass(vec.getClass()); + int len = vec.getLength(); + if (len == 0) { + append(vec.getRType().getClazz() + "(0)"); + } else if (len == 1) { + vecElement2buff(type, vec.getDataAtAsObject(0), true); + } else { + RIntSequence sequence = asIntSequence(vec); + if (sequence != null) { + append(RRuntime.intToStringNoCheck(sequence.getStart())).append(':').append(RRuntime.intToStringNoCheck(sequence.getEnd())); + return; + } else { + // TODO COMPAT? + append("c("); + for (int i = 0; i < len; i++) { + Object element = vec.getDataAtAsObject(i); + vecElement2buff(type, element, false); + if (i < len - 1) { + append(", "); + } + } + append(')'); + } } } - if (lbreak) { - state.indent--; + + private static RIntSequence asIntSequence(RAbstractVector vec) { + if (!(vec instanceof RAbstractIntVector)) { + return null; + } + RAbstractIntVector intVec = (RAbstractIntVector) vec; + if (vec instanceof RIntSequence) { + return (RIntSequence) vec; + } + assert vec.getLength() >= 2; + int start = intVec.getDataAt(0); + if (RRuntime.isNA(start)) { + return null; + } + for (int i = 1; i < vec.getLength(); i++) { + int next = intVec.getDataAt(i); + if (RRuntime.isNA(next) || next != start + i) { + return null; + } + } + return RDataFactory.createIntSequence(start, 1, intVec.getLength()); } - return state; - } - @TruffleBoundary - private static State vector2buff(State state, RAbstractVector vec) { - SEXPTYPE type = SEXPTYPE.typeForClass(vec.getClass()); - boolean surround = false; - int len = vec.getLength(); - if (len == 0) { + private DeparseVisitor vecElement2buff(SEXPTYPE type, Object element, boolean singleElement) { switch (type) { - case LGLSXP: - state.append("logical(0)"); + case STRSXP: + String s = (String) element; + append(RRuntime.isNA(s) ? (singleElement ? "NA_character_" : "NA") : RRuntime.quoteString((String) element, true)); break; - case INTSXP: - state.append("integer(0)"); + case LGLSXP: + append(RRuntime.logicalToString((byte) element)); break; case REALSXP: - state.append("numeric(0)"); + double d = (double) element; + append(RRuntime.isNA(d) ? (singleElement ? "NA_real_" : "NA") : encodeReal(d)); break; - case CPLXSXP: - state.append("complex(0)"); - break; - case STRSXP: - state.append("character(0)"); + case INTSXP: + int i = (int) element; + if (RRuntime.isNA(i)) { + append((singleElement ? "NA_integer_" : "NA")); + } else { + append(RRuntime.intToStringNoCheck(i)).append('L'); + } break; - case RAWSXP: - state.append("raw(0)"); + case CPLXSXP: + RComplex c = (RComplex) element; + if (RRuntime.isNA(c)) { + append((singleElement ? "NA_complex_" : "NA")); + } else { + append(encodeReal(c.getRealPart())); + if (c.getImaginaryPart() >= 0) { + append('+'); + } + append(encodeReal(c.getImaginaryPart())).append('i'); + } break; default: - assert false; - } - } else if (type == SEXPTYPE.INTSXP) { - // TODO seq detection and COMPAT? - if (len > 1) { - state.append("c("); - surround = true; + throw RInternalError.shouldNotReachHere("unexpected SEXPTYPE: " + type); } - RAbstractIntVector intVec = (RAbstractIntVector) vec; - for (int i = 0; i < len; i++) { - int val = intVec.getDataAt(i); - if (RRuntime.isNA(val)) { - state.append("NA_integer_"); - } else { - state.append(Integer.toString(val)); - state.append('L'); + return this; + } + + /** + * Handles {@link RList}, (@link RExpression}, {@link RDataFrame} and {@link RFactor}. + * Method name same as GnuR. + */ + private DeparseVisitor appendListContents(RAbstractListVector v) { + int n = v.getLength(); + boolean lbreak = false; + Object names = v.getNames(); + RStringVector snames = names == RNull.instance ? null : (RStringVector) names; + for (int i = 0; i < n; i++) { + if (i > 0) { + append(", "); } - if (i < len - 1) { - state.append(", "); + lbreak = linebreak(lbreak); + String sname = snames == null ? null : snames.getDataAt(i); + if (snames != null && ((sname = snames.getDataAt(i)) != null)) { + append(sname); + append(" = "); } + append(wrap(v.getDataAtAsObject(i), false)); } - } else { - // TODO NA checks - if (len > 1) { - state.append("c("); - surround = true; - } else if (len == 1 && type == SEXPTYPE.CPLXSXP) { - state.append('('); - surround = true; + if (lbreak) { + indent--; } - for (int i = 0; i < len; i++) { - Object element = vec.getDataAtAsObject(i); - if (type == SEXPTYPE.REALSXP && RRuntime.isNA((double) element)) { - state.append("NA_real_"); - } else if (type == SEXPTYPE.STRSXP && RRuntime.isNA((String) element)) { - state.append("NA_character_"); - } else if (type == SEXPTYPE.CPLXSXP && RRuntime.isNA((RComplex) element)) { - state.append("NA_complex_"); - } else { - vecElement2buff(state, type, element); - } + return this; + } - if (i < len - 1) { - state.append(", "); - } + private static boolean hasAttributes(Object obj) { + // TODO check (and ignore) function source attribute + if (obj instanceof RAttributable) { + RAttributes attrs = ((RAttributable) obj).getAttributes(); + return attrs != null && !attrs.isEmpty(); + } else { + return false; } } - if (surround) { - state.append(')'); - } - return state; - } - private static State vecElement2buff(State state, SEXPTYPE type, Object element) { - switch (type) { - case STRSXP: - // TODO encoding - state.append('"'); - String s = (String) element; - for (int i = 0; i < s.length(); i++) { - char ch = s.charAt(i); - int charInt = ch; - switch (ch) { - case '\n': - state.append("\\n"); - break; - case '\r': - state.append("\\r"); - break; - case '\t': - state.append("\\t"); - break; - case '\f': - state.append("\\f"); - break; - case '\\': - state.append("\\\\"); - break; - case '"': - state.append("\\\""); - break; - case 0x7: - state.append("\\a"); - break; - case 0x8: - state.append("\\b"); - break; - case 0xB: - state.append("\\v"); - break; - default: - if (Character.isISOControl(ch)) { - state.append("\\x" + Integer.toHexString(charInt)); - } else if (charInt > 0x7F) { - state.append("\\u" + Integer.toHexString(charInt)); - } else { - state.append(ch); + private C withAttributes(Object obj) { + if (showAttributes() && hasAttributes(obj)) { + append("structure("); + return () -> { + RAttributes attrs = ((RAttributable) obj).getAttributes(); + if (attrs != null) { + Iterator<RAttribute> iter = attrs.iterator(); + while (iter.hasNext()) { + RAttribute attr = iter.next(); + // TODO ignore function source attribute + String attrName = attr.getName(); + append(", "); + String dotName = null; + switch (attrName) { + case "dimnames": + dotName = ".Dimnames"; + break; + case "dim": + dotName = ".Dim"; + break; + case "names": + dotName = ".Names"; + break; + case "tsp": + dotName = ".Tsp"; + break; + case "levels": + dotName = ".Label"; + break; + + default: { + opts = SIMPLEDEPARSE; + if (attrName.contains(" ")) { + append('"'); + append(attrName); + append('"'); + } else { + append(attrName); + } + } + + } + if (dotName != null) { + append(dotName); } - break; + append(" = "); + process(attr.getValue()); + append(')'); + } } - } - state.append('"'); - break; - case LGLSXP: - byte lgl = (byte) element; - state.append(lgl == RRuntime.LOGICAL_TRUE ? "TRUE" : (lgl == RRuntime.LOGICAL_FALSE ? "FALSE" : "NA")); - break; - case REALSXP: - double d = (double) element; - state.append(encodeReal(d)); - break; - case INTSXP: - int i = (int) element; - state.append(Integer.toString(i)); - state.append('L'); - break; - case CPLXSXP: - RComplex c = (RComplex) element; - String reRep = encodeReal(c.getRealPart()); - String imRep = encodeReal(c.getImaginaryPart()); - state.append(reRep); - state.append('+'); - state.append(imRep); - state.append('i'); - break; - default: - assert false; + }; + } else { + return () -> { + }; + } + } + } + + /** + * Version for use by {@code RSerialize} to convert a CLOSXP/LANGSXP/PROMSXP into a parseable + * string. + */ + @TruffleBoundary + public static String deparseDeserialize(Object obj) { + Object root = obj; + if (root instanceof RPairList) { + RPairList pl = (RPairList) root; + if (pl.getType() == SEXPTYPE.BCODESXP) { + RAbstractListVector list = (RAbstractListVector) pl.cdr(); + root = list.getDataAtAsObject(0); + } } - return state; + return new DeparseVisitor(false, 80, true, 0, -1).process(root).getContents(); + } + + @TruffleBoundary + public static String deparseSyntaxElement(RSyntaxElement element) { + return new DeparseVisitor(false, RDeparse.MAX_Cutoff, true, 0, -1).append(element).getContents(); + } + + @TruffleBoundary + public static String deparse(Object expr) { + return new DeparseVisitor(false, RDeparse.MAX_Cutoff, true, 0, -1).process(expr).getContents(); + } + + @TruffleBoundary + public static String deparse(Object expr, int cutoff, boolean backtick, int opts, int nlines) { + return new DeparseVisitor(false, cutoff, backtick, opts, nlines).process(expr).getContents(); } + // TODO: this should use the DoubleVectorPrinter + private static final DecimalFormatSymbols decimalFormatSymbols; private static final DecimalFormat decimalFormat; private static final DecimalFormat simpleDecimalFormat; @@ -1415,7 +1059,8 @@ public class RDeparse { simpleDecimalFormat = new DecimalFormat("#.##################", decimalFormatSymbols); } - private static String encodeReal(double d) { + private static String encodeReal(double x) { + double d = RRuntime.normalizeZero(x); if (d == 0 || withinSimpleRealRange(d)) { return simpleDecimalFormat.format(d); } else { @@ -1432,11 +1077,7 @@ public class RDeparse { return (d > 0.0001 || d < -0.0001) && d < 100000 && d > -100000; } - public static String quotify(String name, State state) { - return quotify(name, state.backtick ? BACKTICK : DQUOTE); - } - - public static String quotify(String name, char qc) { + private static String quotify(String name, char qc) { if (isValidName(name) || name.length() == 0) { return name; } else { @@ -1454,16 +1095,11 @@ public class RDeparse { } } - private static final String[] keywords = {"NULL", "NA", "TRUE", "FALSE", "Inf", "NaN", "NA_integer_", "NA_real_", "NA_character_", "NA_complex_", "function", "while", "repeat", "for", "if", "in", - "else", "next", "break", "..."}; + private static final HashSet<String> keywords = new HashSet<>(Arrays.asList("NULL", "NA", "TRUE", "FALSE", "Inf", "NaN", "NA_integer_", "NA_real_", "NA_character_", "NA_complex_", "function", + "while", "repeat", "for", "if", "in", "else", "next", "break", "...")); - public static boolean isKeyword(String name) { - for (int i = 0; i < keywords.length; i++) { - if (name.equals(keywords[i])) { - return true; - } - } - return false; + private static boolean isKeyword(String name) { + return keywords.contains(name); } public static boolean isValidName(String name) { @@ -1499,71 +1135,4 @@ public class RDeparse { return 0; } } - - private static boolean hasAttributes(Object obj) { - // TODO check (and ignore) function source attribute - if (obj instanceof RAttributable) { - RAttributes attrs = ((RAttributable) obj).getAttributes(); - return attrs != null && !attrs.isEmpty(); - } else { - return false; - } - } - - private static void attr1(State state, Object obj) { - if (hasAttributes(obj)) { - state.append("structure("); - } - } - - private static void attr2(State state, Object obj) { - if (obj instanceof RAttributable) { - RAttributes attrs = ((RAttributable) obj).getAttributes(); - if (attrs != null) { - Iterator<RAttribute> iter = attrs.iterator(); - while (iter.hasNext()) { - RAttribute attr = iter.next(); - // TODO ignore function source attribute - String attrName = attr.getName(); - state.append(", "); - String dotName = null; - switch (attrName) { - case "dimnames": - dotName = ".Dimnames"; - break; - case "dim": - dotName = ".Dim"; - break; - case "names": - dotName = ".Names"; - break; - case "tsp": - dotName = ".Tsp"; - break; - case "levels": - dotName = ".Label"; - break; - - default: { - state.opts = SIMPLEDEPARSE; - if (attrName.contains(" ")) { - state.append('"'); - state.append(attrName); - state.append('"'); - } else { - state.append(attrName); - } - } - - } - if (dotName != null) { - state.append(dotName); - } - state.append(" = "); - deparse2buff(state, attr.getValue()); - state.append(')'); - } - } - } - } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java index aa6317c133..1273db4605 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntimeASTAccess.java @@ -33,6 +33,7 @@ import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.nodes.RBaseNode; +import com.oracle.truffle.r.runtime.nodes.RSyntaxFunction; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; /** @@ -79,15 +80,7 @@ public interface RRuntimeASTAccess { */ void setNames(RLanguage rl, RStringVector names); - /** - * Deparse {@code rl}. - */ - void deparse(RDeparse.State state, RLanguage rl); - - /** - * Deparse non-builtin function. - */ - void deparse(RDeparse.State state, RFunction f); + RSyntaxFunction getSyntaxFunction(RFunction f); /** * Serialize a runtime value that requires non-standard treatment. diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java index 19a3210627..c3c55b054a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java @@ -537,7 +537,7 @@ public class RSerialize { if (FastROptions.debugMatches("printUclosure")) { Debug.printClosure(rpl); } - String deparse = RDeparse.deparse(rpl); + String deparse = RDeparse.deparseDeserialize(rpl); try { /* * The tag of result is the enclosing environment (from NAMESPACESEXP) @@ -563,7 +563,7 @@ public class RSerialize { */ if (closureDepth == 0 && langDepth == 0) { RPairList pl = (RPairList) result; - String deparse = RDeparse.deparse(pl); + String deparse = RDeparse.deparseDeserialize(pl); RExpression expr = parse(deparse); assert expr.getLength() == 1; result = expr.getDataAt(0); @@ -576,7 +576,7 @@ public class RSerialize { * tag: environment for eval (or RNull if evaluated), car: value: * RUnboundValue if not evaluated, cdr: expression */ - String deparse = RDeparse.deparse(pl); + String deparse = RDeparse.deparseDeserialize(pl.cdr()); RExpression expr = parse(deparse); assert expr.getLength() == 1; RLanguage lang = (RLanguage) expr.getDataAt(0); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RBaseNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RBaseNode.java index 7b650615d0..2724e59029 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RBaseNode.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RBaseNode.java @@ -25,7 +25,6 @@ package com.oracle.truffle.r.runtime.nodes; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeVisitor; import com.oracle.truffle.api.source.SourceSection; -import com.oracle.truffle.r.runtime.RDeparse.State; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RSerialize; @@ -124,11 +123,6 @@ public abstract class RBaseNode extends Node { return null; } - public void deparse(State state) { - RSyntaxNode syntaxNode = getRSyntaxNode(); - syntaxNode.deparseImpl(state); - } - public RSyntaxNode substitute(REnvironment env) { RSyntaxNode syntaxNode = getRSyntaxNode(); return syntaxNode.substituteImpl(env); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxNode.java index 8ae220151a..d76292bd07 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxNode.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxNode.java @@ -53,9 +53,9 @@ import com.oracle.truffle.r.runtime.context.RContext; * One particular case is {@link #LAZY_DEPARSE} which indicates that a valid {@link SourceSection} * can be produced for the associated node, but it is computed lazily, when requested. * - * Every implementor of this interface must provide an implementation of the {@link #deparseImpl}, - * {@link #serializeImpl}, and {@link #substituteImpl} methods. These are invoked by the - * corresponding methods on {@link RBaseNode} after the correct {@link RSyntaxNode} is located. + * Every implementor of this interface must provide an implementation of the {@link #serializeImpl} + * and {@link #substituteImpl} methods. These are invoked by the corresponding methods on + * {@link RBaseNode} after the correct {@link RSyntaxNode} is located. */ public interface RSyntaxNode extends RSyntaxNodeSPI, RSyntaxElement { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxNodeSPI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxNodeSPI.java index 1b8c3ac146..47760daff1 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxNodeSPI.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RSyntaxNodeSPI.java @@ -22,9 +22,8 @@ */ package com.oracle.truffle.r.runtime.nodes; -import com.oracle.truffle.r.runtime.RDeparse; -import com.oracle.truffle.r.runtime.RDeparse.State; import com.oracle.truffle.r.runtime.RSerialize; +import com.oracle.truffle.r.runtime.RSerialize.State; import com.oracle.truffle.r.runtime.env.REnvironment; /** @@ -34,11 +33,6 @@ import com.oracle.truffle.r.runtime.env.REnvironment; * */ interface RSyntaxNodeSPI { - /** - * Support for the {@code deparse} builtin function. The source representation should be - * appended to the {@link State}. - */ - void deparseImpl(RDeparse.State state); /** * Support for the {@code substitute} builtin function. Assert: {this.isSyntax() == true}. N.B. diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides index 9f2dcdf304..7fff3ff75f 100644 --- a/mx.fastr/copyrights/overrides +++ b/mx.fastr/copyrights/overrides @@ -179,7 +179,6 @@ com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/ExecuteMethod. com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java,gnu_r_gentleman_ihaka.copyright com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java,gnu_r_gentleman_ihaka.copyright com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java,gnu_r_gentleman_ihaka.copyright -com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/runtime/RASTDeparse.java,gnu_r.copyright com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/InheritsNode.java,purdue.copyright com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/IsFactorNode.java,purdue.copyright com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g,purdue.copyright -- GitLab