Skip to content
Snippets Groups Projects
Commit 85ab441c authored by stepan's avatar stepan
Browse files

Rscript parses the whole file before executing in order to be able to respond...

Rscript parses the whole file before executing in order to be able to respond to `materializeInstrumentableNodes`
parent ea784a2b
No related branches found
No related tags found
No related merge requests found
Showing
with 362 additions and 152 deletions
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.truffle.r.engine;
import java.util.List;
import java.util.Set;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.instrumentation.InstrumentableNode;
import com.oracle.truffle.api.instrumentation.ProbeNode;
import com.oracle.truffle.api.instrumentation.Tag;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.r.runtime.ExitException;
import com.oracle.truffle.r.runtime.JumpToTopLevelException;
import com.oracle.truffle.r.runtime.RError;
import com.oracle.truffle.r.runtime.RInternalError;
import com.oracle.truffle.r.runtime.RSource;
import com.oracle.truffle.r.runtime.ReturnException;
import com.oracle.truffle.r.runtime.Utils.DebugExitException;
import com.oracle.truffle.r.runtime.context.RContext;
import com.oracle.truffle.r.runtime.data.RNull;
import com.oracle.truffle.r.runtime.interop.R2Foreign;
import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen;
import com.oracle.truffle.r.runtime.nodes.RNode;
import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
class EngineRootNode extends RootNode {
private final SourceSection sourceSection;
private final MaterializedFrame executionFrame;
private final ContextReference<RContext> contextReference;
@Child private EngineBodyNode bodyNode;
@Child private R2Foreign r2Foreign = R2ForeignNodeGen.create();
EngineRootNode(EngineBodyNode bodyNode, RContext context, SourceSection sourceSection, MaterializedFrame executionFrame) {
super(context.getLanguage());
this.sourceSection = sourceSection;
this.bodyNode = bodyNode;
this.executionFrame = executionFrame;
this.contextReference = context.getLanguage().getContextReference();
}
public static EngineRootNode createEngineRoot(REngine engine, RContext context, List<RSyntaxNode> statements, SourceSection sourceSection, MaterializedFrame executionFrame) {
return new EngineRootNode(new EngineBodyNode(engine, statements, getPrintResult(sourceSection)), context, sourceSection, executionFrame);
}
/**
* The normal {@link REngine#doMakeCallTarget} happens first, then we actually run the call
* using the standard FastR machinery, saving and restoring the {@link RContext}, since we have
* no control over what that might be when the call is initiated.
*/
@Override
public Object execute(VirtualFrame frame) {
Object actualFrame = executionFrame != null ? executionFrame : contextReference.get().stateREnvironment.getGlobalFrame();
try {
return r2Foreign.execute(this.bodyNode.execute(actualFrame));
} catch (ReturnException ex) {
return ex.getResult();
} catch (DebugExitException | JumpToTopLevelException | ExitException | ThreadDeath e) {
CompilerDirectives.transferToInterpreter();
throw e;
} catch (RError e) {
CompilerDirectives.transferToInterpreter();
throw e;
} catch (Throwable t) {
CompilerDirectives.transferToInterpreter();
// other errors didn't produce an output yet
RInternalError.reportError(t);
throw t;
}
}
@Override
public SourceSection getSourceSection() {
return sourceSection;
}
public static boolean isEngineBody(Object node) {
return node instanceof EngineBodyNode;
}
private static boolean getPrintResult(SourceSection sourceSection) {
// can't print if initializing the system in embedded mode (no builtins yet)
return !sourceSection.getSource().getName().equals(RSource.Internal.INIT_EMBEDDED.string) && sourceSection.getSource().isInteractive();
}
private static final class EngineBodyNode extends Node implements InstrumentableNode {
private final REngine engine;
private final List<RSyntaxNode> statements;
@Children protected final DirectCallNode[] calls;
private final boolean printResult;
EngineBodyNode(REngine engine, List<RSyntaxNode> statements, boolean printResult) {
this.engine = engine;
this.statements = statements;
this.calls = new DirectCallNode[statements.size()];
this.printResult = printResult;
}
@ExplodeLoop
Object execute(Object actualFrame) {
Object lastValue = RNull.instance;
int lastStatus = 0;
for (int i = 0; i < calls.length; i++) {
materializeCall(i);
lastValue = calls[i].call(new Object[]{actualFrame});
}
return lastValue;
}
@Override
public boolean isInstrumentable() {
return false;
}
@Override
public WrapperNode createWrapper(ProbeNode probe) {
return null;
}
@Override
public boolean hasTag(Class<? extends Tag> tag) {
return false;
}
@Override
public InstrumentableNode materializeInstrumentableNodes(Set<Class<? extends Tag>> materializedTags) {
for (int i = 0; i < calls.length; i++) {
materializeCall(i);
}
return this;
}
protected void materializeCall(int i) {
if (calls[i] == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
RNode node = statements.get(i).asRNode();
calls[i] = insert(Truffle.getRuntime().createDirectCallNode(engine.doMakeCallTarget(node, RSource.Internal.REPL_WRAPPER.string, printResult, true)));
}
}
}
}
......@@ -22,6 +22,11 @@
*/
package com.oracle.truffle.r.engine;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
......@@ -33,16 +38,13 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.dsl.UnsupportedSpecializationException;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.java.JavaInterop;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.ExecutableNode;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.profiles.ValueProfile;
......@@ -99,7 +101,6 @@ import com.oracle.truffle.r.runtime.data.RTypedValue;
import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
import com.oracle.truffle.r.runtime.env.REnvironment;
import com.oracle.truffle.r.runtime.interop.R2Foreign;
import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen;
import com.oracle.truffle.r.runtime.nodes.RNode;
import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
......@@ -256,7 +257,7 @@ final class REngine implements Engine, Engine.Timings {
@Override
public Object parseAndEval(Source source, MaterializedFrame frame, boolean printResult) throws ParseException {
List<RSyntaxNode> list = parseImpl(source);
List<RSyntaxNode> list = parseSource(source);
try {
Object lastValue = RNull.instance;
for (RSyntaxNode node : list) {
......@@ -284,21 +285,23 @@ final class REngine implements Engine, Engine.Timings {
}
}
private List<RSyntaxNode> parseImpl(Source source) throws ParseException {
List<RSyntaxNode> parseSource(Source source) throws ParseException {
RParserFactory.Parser<RSyntaxNode> parser = RParserFactory.getParser();
return parser.script(source, new RASTBuilder(), context.getLanguage());
}
@Override
public RExpression parse(Source source) throws ParseException {
List<RSyntaxNode> list = parseImpl(source);
List<RSyntaxNode> list = parseSource(source);
Object[] data = list.stream().map(node -> RASTUtils.createLanguageElement(node)).toArray();
return RDataFactory.createExpression(data);
}
@Override
public CallTarget parseToCallTarget(Source source, MaterializedFrame executionFrame) throws ParseException {
if (source == Engine.GET_CONTEXT) {
if (source.getPath() != null && !source.isInteractive()) {
return Truffle.getRuntime().createCallTarget(createRScriptRoot(source, executionFrame));
} else if (source == Engine.GET_CONTEXT) {
/*
* The "get context" operations should be executed with as little influence on the
* actual engine as possible, therefore this special case takes care of it explicitly.
......@@ -315,14 +318,15 @@ final class REngine implements Engine, Engine.Timings {
}
});
} else {
List<RSyntaxNode> statements = parseImpl(source);
return Truffle.getRuntime().createCallTarget(new PolyglotEngineRootNode(statements, createSourceSection(source, statements), executionFrame));
List<RSyntaxNode> statements = parseSource(source);
EngineRootNode rootNode = EngineRootNode.createEngineRoot(this, context, statements, createSourceSection(source, statements), executionFrame);
return Truffle.getRuntime().createCallTarget(rootNode);
}
}
@Override
public ExecutableNode parseToExecutableNode(Source source) throws ParseException {
List<RSyntaxNode> list = parseImpl(source);
List<RSyntaxNode> list = parseSource(source);
RNode[] statements = new RNode[list.size()];
for (int i = 0; i < statements.length; i++) {
statements[i] = list.get(i).asRNode();
......@@ -355,68 +359,49 @@ final class REngine implements Engine, Engine.Timings {
}
}
private final class PolyglotEngineRootNode extends RootNode {
private final List<RSyntaxNode> statements;
private final MaterializedFrame executionFrame;
@Children private final DirectCallNode[] calls;
private final boolean printResult;
private final SourceSection sourceSection;
private final ContextReference<RContext> contextReference;
@Child private R2Foreign r2Foreign = R2ForeignNodeGen.create();
PolyglotEngineRootNode(List<RSyntaxNode> statements, SourceSection sourceSection, MaterializedFrame executionFrame) {
super(context.getLanguage());
this.sourceSection = sourceSection;
this.contextReference = context.getLanguage().getContextReference();
// can't print if initializing the system in embedded mode (no builtins yet)
this.printResult = !sourceSection.getSource().getName().equals(RSource.Internal.INIT_EMBEDDED.string) && sourceSection.getSource().isInteractive();
this.statements = statements;
this.executionFrame = executionFrame;
this.calls = new DirectCallNode[statements.size()];
}
@Override
public SourceSection getSourceSection() {
return sourceSection;
}
/**
* The normal {@link #doMakeCallTarget} happens first, then we actually run the call using
* the standard FastR machinery, saving and restoring the {@link RContext}, since we have no
* control over what that might be when the call is initiated.
*/
@Override
@ExplodeLoop
public Object execute(VirtualFrame frame) {
Object actualFrame = executionFrame != null ? executionFrame : contextReference.get().stateREnvironment.getGlobalFrame();
try {
Object lastValue = RNull.instance;
for (int i = 0; i < calls.length; i++) {
if (calls[i] == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
RSyntaxNode node = statements.get(i);
calls[i] = insert(Truffle.getRuntime().createDirectCallNode(doMakeCallTarget(node.asRNode(), RSource.Internal.REPL_WRAPPER.string, printResult, true)));
private EngineRootNode createRScriptRoot(Source fullSource, MaterializedFrame frame) {
URI uri = fullSource.getURI();
String file = fullSource.getPath();
ArrayList<RSyntaxNode> statements = new ArrayList<>(128);
try {
try (BufferedReader br = new BufferedReader(new InputStreamReader(fullSource.getInputStream()))) {
int lineIndex = 1;
int startLine = lineIndex;
StringBuilder sb = new StringBuilder();
while (true) {
String input = br.readLine();
if (input == null) {
if (sb.length() != 0) {
// end of file, but not end of statement => error
statements.add(new SyntaxErrorNode(null, fullSource.createSection(startLine, 1, sb.length())));
}
break;
}
sb.append(input);
Source src = Source.newBuilder(sb.toString()).mimeType(RRuntime.R_APP_MIME).name(file + "#" + startLine + "-" + lineIndex).uri(uri).build();
lineIndex++;
List<RSyntaxNode> currentStmts = null;
try {
RParserFactory.Parser<RSyntaxNode> parser = RParserFactory.getParser();
currentStmts = parser.statements(src, fullSource, startLine, new RASTBuilder(), context.getLanguage());
} catch (IncompleteSourceException e) {
sb.append('\n');
continue;
} catch (ParseException e) {
statements.add(new SyntaxErrorNode(e, fullSource.createSection(startLine, 1, sb.length())));
}
lastValue = calls[i].call(new Object[]{actualFrame});
if (currentStmts != null) {
statements.addAll(currentStmts);
}
// we did not continue on incomplete source exception
sb.setLength(0);
startLine = lineIndex;
}
return r2Foreign.execute(lastValue);
} catch (ReturnException ex) {
return ex.getResult();
} catch (DebugExitException | JumpToTopLevelException | ExitException | ThreadDeath e) {
CompilerDirectives.transferToInterpreter();
throw e;
} catch (RError e) {
CompilerDirectives.transferToInterpreter();
throw e;
} catch (Throwable t) {
CompilerDirectives.transferToInterpreter();
// other errors didn't produce an output yet
RInternalError.reportError(t);
throw t;
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return EngineRootNode.createEngineRoot(this, context, statements, createSourceSection(fullSource, statements), frame);
}
@Override
......@@ -510,7 +495,7 @@ final class REngine implements Engine, Engine.Timings {
* that the body should be executed in.
*/
@TruffleBoundary
private RootCallTarget doMakeCallTarget(RNode body, String description, boolean printResult, boolean topLevel) {
RootCallTarget doMakeCallTarget(RNode body, String description, boolean printResult, boolean topLevel) {
return Truffle.getRuntime().createCallTarget(new AnonymousRootNode(this, body, description, printResult, topLevel));
}
......
......@@ -308,7 +308,7 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess {
// single statement block: as function body, if/else body, loop body
// note: RepeatingNode is not a RSyntaxElement but the body of a loop is
// under the repeating node !
return parent instanceof RootBodyNode || parent instanceof IfNode || AbstractLoopNode.isLoopBody(node);
return parent instanceof RootBodyNode || parent instanceof IfNode || AbstractLoopNode.isLoopBody(node) || EngineRootNode.isEngineBody(parent);
}
}
// TODO: ExpressionTag: (!statement && !loop && !if && !call && !root)??
......
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.truffle.r.engine;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.r.runtime.RInternalError;
import com.oracle.truffle.r.runtime.context.Engine.ParseException;
import com.oracle.truffle.r.runtime.nodes.RInstrumentableNode;
import com.oracle.truffle.r.runtime.nodes.RNode;
import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
/**
* Node that represents piece of AST that would throw syntax error when parser. Used to delay
* parsing error to the point when they should be reported.
*/
final class SyntaxErrorNode extends RNode implements RSyntaxNode, RInstrumentableNode {
private final ParseException exception;
private final SourceSection sourceSection;
SyntaxErrorNode(ParseException exception, SourceSection sourceSection) {
this.exception = exception;
this.sourceSection = sourceSection;
}
@Override
public Object execute(VirtualFrame frame) {
throw exception.throwAsRError();
}
@Override
public SourceSection getSourceSection() {
return this.sourceSection;
}
@Override
public SourceSection getLazySourceSection() {
return this.sourceSection;
}
@Override
public void setSourceSection(SourceSection source) {
throw RInternalError.shouldNotReachHere(String.format("%s should not be serialized/deserialzed.", getClass().getSimpleName()));
}
}
......@@ -34,6 +34,7 @@ import com.oracle.truffle.api.instrumentation.ProvidedTags;
import com.oracle.truffle.api.instrumentation.StandardTags;
import com.oracle.truffle.api.nodes.ExecutableNode;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.r.engine.interop.RForeignAccessFactoryImpl;
import com.oracle.truffle.r.nodes.RASTBuilder;
......@@ -189,12 +190,13 @@ public final class TruffleRLanguageImpl extends TruffleRLanguage {
@Override
protected CallTarget parse(ParsingRequest request) throws Exception {
CompilerAsserts.neverPartOfCompilation();
Source source = request.getSource();
try {
return RContext.getEngine().parseToCallTarget(request.getSource(), null);
return RContext.getEngine().parseToCallTarget(source, null);
} catch (IncompleteSourceException e) {
throw e;
} catch (ParseException e) {
if (request.getSource().isInteractive()) {
if (source.isInteractive()) {
throw e.throwAsRError();
} else {
throw e;
......
......@@ -23,6 +23,7 @@
package com.oracle.truffle.r.launcher;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
......@@ -30,6 +31,9 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.graalvm.polyglot.PolyglotException;
import org.graalvm.polyglot.Source;
import com.oracle.truffle.r.launcher.RCmdOptions.Client;
import com.oracle.truffle.r.launcher.RCmdOptions.RCmdOption;
......@@ -67,12 +71,36 @@ public final class RscriptCommand extends RAbstractLauncher {
launch(args);
if (context != null) {
String fileOption = options.getString(RCmdOption.FILE);
return RCommand.readEvalPrint(context, consoleHandler, fileOption != null ? new File(fileOption) : null);
if (fileOption != null) {
return executeFile(fileOption);
} else {
return RCommand.readEvalPrint(context, consoleHandler, null);
}
} else {
return 0;
}
}
private int executeFile(String fileOption) {
Source src;
try {
src = Source.newBuilder("R", new File(fileOption)).interactive(false).build();
} catch (IOException ex) {
System.err.printf("IO error while reading the source file '%s'.\nDetails: '%s'.", fileOption, ex.getLocalizedMessage());
return 1;
}
try {
context.eval(src);
return 0;
} catch (Throwable ex) {
if (ex instanceof PolyglotException && ((PolyglotException) ex).isExit()) {
return ((PolyglotException) ex).getExitStatus();
}
// Internal exceptions are reported by the engine already
return 1;
}
}
// CheckStyle: stop system..print check
private static String[] preprocessRScriptOptions(RCmdOptions options) throws PrintHelp {
......
......@@ -62,6 +62,26 @@ public class DefaultRParserFactory extends RParserFactory {
}
}
@Override
public List<T> statements(Source source, Source fullSource, int startLine, RCodeBuilder<T> builder, TruffleRLanguage language) throws ParseException {
try {
try {
RContext context = language.getContextReference().get();
RParser<T> parser = new RParser<>(source, fullSource, startLine, builder, language, context.sourceCache);
return parser.script();
} catch (IllegalArgumentException e) {
// the lexer will wrap exceptions in IllegalArgumentExceptions
if (e.getCause() instanceof RecognitionException) {
throw (RecognitionException) e.getCause();
} else {
throw e;
}
}
} catch (RecognitionException e) {
throw handleRecognitionException(source, e);
}
}
@Override
public RootCallTarget rootFunction(Source source, String name, RCodeBuilder<T> builder, TruffleRLanguage language) throws ParseException {
RContext context = language.getContextReference().get();
......
......@@ -98,6 +98,7 @@ public class ParserGeneration {
"allow everything but newlines in %<ident>% operators",
"allow strings in :: and :::",
"use file for interactive single-line source",
":: and ::: do not set argument names"
":: and ::: do not set argument names",
"refactored: use file for interactive single-line source"
};
}
......@@ -75,90 +75,25 @@ import com.oracle.truffle.r.runtime.RError;
private TruffleRLanguage language;
private int fileStartOffset = 0;
private Map<String, Source> sourceCache;
/**
* Always use this constructor to initialize the R specific fields.
*/
public RParser(Source source, RCodeBuilder<T> builder, TruffleRLanguage language, Map<String, Source> sourceCache) {
super(new CommonTokenStream(new RLexer(new ANTLRStringStream(source.getCharacters().toString()))));
assert source != null && builder != null;
this.initialSource = source;
this.builder = builder;
this.language = language;
this.sourceCache = sourceCache;
if (source.getURI() != null && source.getName().contains("#")) {
this.source = createFullSource(source);
} else {
this.source = source;
}
this.source = source;
}
private Source createFullSource(Source original) {
String originalName = original.getName();
// check if source name is like 'path/to/source.R#45-54'
int hash_idx = originalName.lastIndexOf("#");
if (hash_idx == -1) {
return original;
}
String fileName = originalName.substring(0, hash_idx);
String lineRange = originalName.substring(hash_idx + 1);
try {
// check for line range, e.g. '45-54'
int startLine = -1;
int endLine = -1;
int dashIdx = lineRange.indexOf('-');
if (dashIdx != -1) {
startLine = Integer.parseInt(lineRange.substring(0, dashIdx));
endLine = Integer.parseInt(lineRange.substring(dashIdx + 1));
} else {
startLine = Integer.parseInt(lineRange);
endLine = startLine;
}
File f = new File(fileName);
Source fullSource;
String canonicalName;
try {
canonicalName = f.getAbsoluteFile().getCanonicalPath();
fullSource = sourceCache != null ? sourceCache.get(canonicalName) : null;
} catch(IOException e) {
// ignore an freshly load file
fullSource = null;
canonicalName = null;
}
if(fullSource == null) {
Builder<IOException, RuntimeException, RuntimeException> newBuilder = Source.newBuilder(f);
if (original.isInteractive()) {
newBuilder.interactive();
}
fullSource = newBuilder.build();
if (sourceCache != null && canonicalName != null) {
sourceCache.put(canonicalName, fullSource);
}
}
// verify to avoid accidentally matching file names
for (int i = 0; i < endLine - startLine + 1; i++) {
if (!original.getCharacters(i + 1).equals(fullSource.getCharacters(startLine + i))) {
return original;
}
}
fileStartOffset = -fullSource.getLineStartOffset(startLine);
return fullSource;
} catch (NumberFormatException e) {
// invalid line number
} catch (IllegalArgumentException e) {
// file name is accidentally named in the expected scheme
} catch (IOException e) {
} catch (RuntimeException e) {
assert rethrow(e);
}
return original;
}
public RParser(Source source, Source fullSource, int startLine, RCodeBuilder<T> builder, TruffleRLanguage language, Map<String, Source> sourceCache) {
super(new CommonTokenStream(new RLexer(new ANTLRStringStream(source.getCharacters().toString()))));
assert source != null && builder != null;
this.initialSource = source;
this.builder = builder;
this.language = language;
this.source = fullSource;
fileStartOffset = -fullSource.getLineStartOffset(startLine);
}
private <T extends Throwable> boolean rethrow(T e) throws T {
throw e;
......
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -37,6 +37,8 @@ public abstract class RParserFactory {
public interface Parser<T> {
List<T> script(Source source, RCodeBuilder<T> builder, TruffleRLanguage language) throws ParseException;
List<T> statements(Source source, Source fullSource, int startLine, RCodeBuilder<T> builder, TruffleRLanguage language) throws ParseException;
RootCallTarget rootFunction(Source source, String name, RCodeBuilder<T> builder, TruffleRLanguage language) throws ParseException;
boolean isRecognitionException(Throwable t);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment