diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java
index 4af701bbecf95d302ed5f309cfbdb55e46575df1..a6fa46db300fefca8accfefe8e70e6e628fbc7a6 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java
@@ -59,6 +59,7 @@ public final class EmbeddedConsoleHandler extends DelegatingConsoleHandler {
     private Context context;
     private Supplier<ConsoleHandler> delegateFactory;
     private ConsoleHandler delegate;
+    private int currentLine;
 
     private CallTarget readLineCallTarget;
     private CallTarget writeCallTarget;
@@ -78,7 +79,9 @@ public final class EmbeddedConsoleHandler extends DelegatingConsoleHandler {
     @Override
     public String readLine() {
         try (ContextClose ignored = inContext()) {
-            return isOverridden("R_ReadConsole") ? (String) getReadLineCallTarget().call("TODO prompt>") : getDelegate().readLine();
+            String l = isOverridden("R_ReadConsole") ? (String) getReadLineCallTarget().call("TODO prompt>") : getDelegate().readLine();
+            currentLine++;
+            return l;
         }
     }
 
@@ -239,4 +242,9 @@ public final class EmbeddedConsoleHandler extends DelegatingConsoleHandler {
             return null;
         }
     }
+
+    @Override
+    public int getCurrentLineIndex() {
+        return currentLine;
+    }
 }
diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/ConsoleHandler.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/ConsoleHandler.java
index f83c933b57f2d639383f736449e25ef3c6b50023..7043743d98d5f1e65606d8985b3419665122ac21 100644
--- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/ConsoleHandler.java
+++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/ConsoleHandler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -39,6 +39,11 @@ public abstract class ConsoleHandler {
      */
     public abstract String readLine();
 
+    /**
+     * Return the current 1-based line number.
+     */
+    public abstract int getCurrentLineIndex();
+
     /**
      * Set the R prompt.
      */
diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/DefaultConsoleHandler.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/DefaultConsoleHandler.java
index a395a0e613e5bfeac692cdc4491c79885c79f202..e7c14851ad99ec7def2e2c36e72471a086c29d28 100644
--- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/DefaultConsoleHandler.java
+++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/DefaultConsoleHandler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -35,6 +35,7 @@ public class DefaultConsoleHandler extends ConsoleHandler {
     private final BufferedReader in;
     private final PrintStream out;
     private String prompt;
+    private int currentLine;
 
     public DefaultConsoleHandler(InputStream in, OutputStream out, boolean interactive) {
         this.in = new BufferedReader(new InputStreamReader(in));
@@ -49,6 +50,7 @@ public class DefaultConsoleHandler extends ConsoleHandler {
                 out.print(prompt);
             }
             String line = in.readLine();
+            currentLine++;
             if ((line == null || "".equals(line.trim())) && prompt != null && !interactive) {
                 out.println();
             }
@@ -62,4 +64,9 @@ public class DefaultConsoleHandler extends ConsoleHandler {
     public void setPrompt(String prompt) {
         this.prompt = prompt;
     }
+
+    @Override
+    public int getCurrentLineIndex() {
+        return currentLine;
+    }
 }
diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/JLineConsoleHandler.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/JLineConsoleHandler.java
index e3c4cee27ef1c5139af1cdfa22552b540f4cf8ff..b3150e178f8e95c7ecdc84156e92688703bb7c4b 100644
--- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/JLineConsoleHandler.java
+++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/JLineConsoleHandler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -38,6 +38,7 @@ public class JLineConsoleHandler extends ConsoleHandler {
     private final ConsoleReader console;
     private final MemoryHistory history;
     private final boolean noPrompt;
+    private int currentLine;
 
     public JLineConsoleHandler(InputStream inStream, OutputStream outStream, boolean noPrompt) {
         this.noPrompt = noPrompt;
@@ -65,6 +66,7 @@ public class JLineConsoleHandler extends ConsoleHandler {
     public String readLine() {
         try {
             console.getTerminal().init();
+            currentLine++;
             return console.readLine();
         } catch (UserInterruptException e) {
             // interrupted by ctrl-c
@@ -94,4 +96,9 @@ public class JLineConsoleHandler extends ConsoleHandler {
         }
         return result;
     }
+
+    @Override
+    public int getCurrentLineIndex() {
+        return currentLine;
+    }
 }
diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java
index 136388102c545428d784ceba9356143cab167ae0..1e74ca7956ff2e573deed0ecdcfa6b1bb4cf74e2 100644
--- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java
+++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java
@@ -170,7 +170,14 @@ public class RCommand {
             consoleHandler.setContext(context);
             StartupTiming.timestamp("VM Created");
             StartupTiming.printSummary();
-            return readEvalPrint(context, consoleHandler);
+
+            File srcFile = null;
+            String fileOption = options.getString(RCmdOption.FILE);
+            if (fileOption != null) {
+                srcFile = new File(fileOption);
+            }
+
+            return readEvalPrint(context, consoleHandler, srcFile);
         }
     }
 
@@ -239,6 +246,10 @@ public class RCommand {
     private static final Source GET_PROMPT = Source.newBuilder("R", ".Internal(getOption('prompt'))", "<prompt>").internal(true).buildLiteral();
     private static final Source GET_CONTINUE_PROMPT = Source.newBuilder("R", ".Internal(getOption('continue'))", "<continue-prompt>").internal(true).buildLiteral();
 
+    public static int readEvalPrint(Context context, ConsoleHandler consoleHandler) {
+        return readEvalPrint(context, consoleHandler, null);
+    }
+
     /**
      * The read-eval-print loop, which can take input from a console, command line expression or a
      * file. There are two ways the repl can terminate:
@@ -249,7 +260,7 @@ public class RCommand {
      * In case 2, we must implicitly execute a {@code quit("default, 0L, TRUE} command before
      * exiting. So,in either case, we never return.
      */
-    public static int readEvalPrint(Context context, ConsoleHandler consoleHandler) {
+    public static int readEvalPrint(Context context, ConsoleHandler consoleHandler, File srcFile) {
         int lastStatus = 0;
         try {
             while (true) { // processing inputs
@@ -268,10 +279,18 @@ public class RCommand {
 
                     String continuePrompt = null;
                     StringBuilder sb = new StringBuilder(input);
+                    int startLine = consoleHandler.getCurrentLineIndex();
                     while (true) { // processing subsequent lines while input is incomplete
                         lastStatus = 0;
                         try {
-                            context.eval(Source.newBuilder("R", sb.toString(), "<REPL>").interactive(true).buildLiteral());
+                            Source src;
+                            if (srcFile != null) {
+                                int endLine = consoleHandler.getCurrentLineIndex();
+                                src = Source.newBuilder("R", sb.toString(), srcFile.toString() + "#" + startLine + "-" + endLine).interactive(true).uri(srcFile.toURI()).buildLiteral();
+                            } else {
+                                src = Source.newBuilder("R", sb.toString(), "<REPL>").interactive(true).buildLiteral();
+                            }
+                            context.eval(src);
                         } catch (PolyglotException e) {
                             if (continuePrompt == null) {
                                 continuePrompt = doEcho ? getContinuePrompt(context) : null;
diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RscriptCommand.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RscriptCommand.java
index e4ca8fa47dd8e44941047937ff8f9eea6d58b639..51fb18b43656c3e5451e6aa1c8c1087960b54521 100644
--- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RscriptCommand.java
+++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RscriptCommand.java
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.r.launcher;
 
+import java.io.File;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
@@ -140,7 +141,8 @@ public class RscriptCommand {
         try (Context context = Context.newBuilder().allowHostAccess(useJVM).options(polyglotOptions).arguments("R", arguments).in(consoleHandler.createInputStream()).out(outStream).err(
                         errStream).build()) {
             consoleHandler.setContext(context);
-            return RCommand.readEvalPrint(context, consoleHandler);
+            String fileOption = options.getString(RCmdOption.FILE);
+            return RCommand.readEvalPrint(context, consoleHandler, fileOption != null ? new File(fileOption) : null);
         }
     }
 }
diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/StringConsoleHandler.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/StringConsoleHandler.java
index 1327a8162997473ccaa032d9b4f27886e83d5f18..f5dd42526ad1f2de7df9fafd71bde76cc16485f2 100644
--- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/StringConsoleHandler.java
+++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/StringConsoleHandler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -54,4 +54,9 @@ class StringConsoleHandler extends ConsoleHandler {
     public void setPrompt(String prompt) {
         this.prompt = prompt;
     }
+
+    @Override
+    public int getCurrentLineIndex() {
+        return currentLine;
+    }
 }
diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/DefaultRParserFactory.java b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/DefaultRParserFactory.java
index df41e3d0d2c420bb88c6699133eb5e1dc2f0417c..f92d3697ba5833dfbe6f37da88c4e8f578bb0a56 100644
--- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/DefaultRParserFactory.java
+++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/DefaultRParserFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -34,6 +34,7 @@ import com.oracle.truffle.api.source.Source;
 import com.oracle.truffle.r.runtime.RParserFactory;
 import com.oracle.truffle.r.runtime.context.Engine.IncompleteSourceException;
 import com.oracle.truffle.r.runtime.context.Engine.ParseException;
+import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.context.TruffleRLanguage;
 import com.oracle.truffle.r.runtime.nodes.RCodeBuilder;
 
@@ -45,7 +46,8 @@ public class DefaultRParserFactory extends RParserFactory {
         public List<T> script(Source source, RCodeBuilder<T> builder, TruffleRLanguage language) throws ParseException {
             try {
                 try {
-                    RParser<T> parser = new RParser<>(source, builder, language);
+                    RContext context = language.getContextReference().get();
+                    RParser<T> parser = new RParser<>(source, builder, language, context.sourceCache);
                     return parser.script();
                 } catch (IllegalArgumentException e) {
                     // the lexer will wrap exceptions in IllegalArgumentExceptions
@@ -62,7 +64,8 @@ public class DefaultRParserFactory extends RParserFactory {
 
         @Override
         public RootCallTarget rootFunction(Source source, String name, RCodeBuilder<T> builder, TruffleRLanguage language) throws ParseException {
-            RParser<T> parser = new RParser<>(source, builder, language);
+            RContext context = language.getContextReference().get();
+            RParser<T> parser = new RParser<>(source, builder, language, context.sourceCache);
             try {
                 return parser.root_function(name);
             } catch (RecognitionException e) {
diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java
index 0aaa94d549b107e157a1d04c9c047294e43b7935..2d17f16cb44ee8dc2a0e892eab4b31168e17540a 100644
--- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java
+++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -96,6 +96,7 @@ public class ParserGeneration {
         "handle four and more dots as identifier",
         "allow greek characters in identifiers",
         "allow everything but newlines in %<ident>% operators",
-        "allow strings in :: and :::"
+        "allow strings in :: and :::",
+        "use file for interactive single-line source"
     };
 }
diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g
index 439c59319569283c6421c452f663bf39a5a9ca92..a86d1728d7e0fd16b916f60228ab2a974b939586 100644
--- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g
+++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g
@@ -4,7 +4,7 @@
  * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * Copyright (c) 2012-2014, Purdue University
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -26,17 +26,20 @@ options {
 //@formatter:off
 package com.oracle.truffle.r.parser;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.io.File;
 import java.io.IOException;
+import java.net.URISyntaxException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Paths;
-import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
 
 import com.oracle.truffle.api.RootCallTarget;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.source.Source.Builder;
 import com.oracle.truffle.api.source.SourceSection;
 
 import com.oracle.truffle.r.runtime.RError;
@@ -71,17 +74,94 @@ import com.oracle.truffle.r.runtime.RError;
     private RCodeBuilder<T> builder;
     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) {
+    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.source = source;
         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;
+        }
+    }
+    
+    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;
+	}
+        
+    private <T extends Throwable> boolean rethrow(T e) throws T {
+    	throw e;
     }
     
     /**
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
index 393a3df3fddce03701f21938395fb5cf51231754..14cbbbc8216169c4ca2e8770410c69787fec6a70 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
@@ -361,6 +361,7 @@ public final class RContext {
     public final List<String> libraryPaths = new ArrayList<>(1);
     public final Map<Integer, Thread> threads = new ConcurrentHashMap<>();
     public final LanguageClosureCache languageClosureCache = new LanguageClosureCache();
+    public final Map<String, Source> sourceCache = new ConcurrentHashMap<>();
 
     private final AllocationReporter allocationReporter;
 
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java
index d585d0de6206aa59094ed82bbaffe231a7aae8ce..90764cd79f7da521d4e450f076249047ed89c7eb 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/RNode.java
@@ -39,7 +39,7 @@ public abstract class RNode extends RBaseNode implements RInstrumentableNode {
 
     @Override
     public boolean isInstrumentable() {
-        return true;
+        return (this instanceof RSyntaxElement && ((RSyntaxElement) this).getLazySourceSection() != null) || getSourceSection() != null;
     }
 
     @Override