diff truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java @ 22266:0d36601f233e

Merge revised Instrumentation framework into the Polyglot API - Required language implementation support now in TruffleLanguage - Instrumentation services provided by the new Instrumenter class - Reduced public API exposure; communication with other components via Accessor - Several methods removed from the Node class - Many test rewritten or using a new "test mode" because of limited access to Engine services Merge with c66f520ad8562b906a878e9b3293aaf54270db90
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Wed, 30 Sep 2015 16:33:56 -0700
parents 09d91119929f b73205fe7cf3
children b56fe0d3b560
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java	Tue Sep 29 18:04:11 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java	Wed Sep 30 16:33:56 2015 -0700
@@ -24,12 +24,6 @@
  */
 package com.oracle.truffle.api;
 
-import com.oracle.truffle.api.debug.DebugSupportProvider;
-import com.oracle.truffle.api.impl.Accessor;
-import com.oracle.truffle.api.impl.FindContextNode;
-import com.oracle.truffle.api.instrument.ToolSupportProvider;
-import com.oracle.truffle.api.nodes.Node;
-import com.oracle.truffle.api.source.Source;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -45,6 +39,21 @@
 import java.util.Map;
 import java.util.WeakHashMap;
 
+import com.oracle.truffle.api.debug.Debugger;
+import com.oracle.truffle.api.frame.MaterializedFrame;
+import com.oracle.truffle.api.impl.Accessor;
+import com.oracle.truffle.api.impl.FindContextNode;
+import com.oracle.truffle.api.instrument.ASTProber;
+import com.oracle.truffle.api.instrument.AdvancedInstrumentResultListener;
+import com.oracle.truffle.api.instrument.AdvancedInstrumentRoot;
+import com.oracle.truffle.api.instrument.AdvancedInstrumentRootFactory;
+import com.oracle.truffle.api.instrument.Instrumenter;
+import com.oracle.truffle.api.instrument.SyntaxTag;
+import com.oracle.truffle.api.instrument.Visualizer;
+import com.oracle.truffle.api.instrument.WrapperNode;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.source.Source;
+
 /**
  * An entry point for everyone who wants to implement a Truffle based language. By providing an
  * implementation of this type and registering it using {@link Registration} annotation, your
@@ -52,6 +61,13 @@
  * polyglot execution engine} - all they will need to do is to include your JAR into their
  * application and all the Truffle goodies (multi-language support, multitenant hosting, debugging,
  * etc.) will be made available to them.
+ * <p>
+ * The use of {@linkplain Instrumenter Instrument-based services} requires that the language
+ * {@linkplain Instrumenter#registerASTProber(com.oracle.truffle.api.instrument.ASTProber) register}
+ * an instance of {@link ASTProber} suitable for the language implementation that can be applied to
+ * "mark up" each newly created AST with {@link SyntaxTag "tags"} that identify standard syntactic
+ * constructs in order to configure tool behavior. See also {@linkplain #createContext(Env)
+ * createContext(Env)}.
  *
  * @param <C> internal state of the language associated with every thread that is executing program
  *            {@link #parse(com.oracle.truffle.api.source.Source, com.oracle.truffle.api.nodes.Node, java.lang.String...)
@@ -67,18 +83,18 @@
 
     /**
      * The annotation to use to register your language to the
-     * {@link com.oracle.truffle.api.vm.TruffleVM Truffle} system. By annotating your implementation
-     * of {@link TruffleLanguage} by this annotation you are just a
+     * {@link com.oracle.truffle.api.vm.PolyglotEngine Truffle} system. By annotating your
+     * implementation of {@link TruffleLanguage} by this annotation you are just a
      * <em>one JAR drop to the class path</em> away from your users. Once they include your JAR in
      * their application, your language will be available to the
-     * {@link com.oracle.truffle.api.vm.TruffleVM Truffle virtual machine}.
+     * {@link com.oracle.truffle.api.vm.PolyglotEngine Truffle virtual machine}.
      */
     @Retention(RetentionPolicy.SOURCE)
     @Target(ElementType.TYPE)
     public @interface Registration {
         /**
          * Unique name of your language. This name will be exposed to users via the
-         * {@link com.oracle.truffle.api.vm.TruffleVM.Language#getName()} getter.
+         * {@link com.oracle.truffle.api.vm.PolyglotEngine.Language#getName()} getter.
          *
          * @return identifier of your language
          */
@@ -86,7 +102,7 @@
 
         /**
          * Unique string identifying the language version. This name will be exposed to users via
-         * the {@link com.oracle.truffle.api.vm.TruffleVM.Language#getVersion()} getter.
+         * the {@link com.oracle.truffle.api.vm.PolyglotEngine.Language#getVersion()} getter.
          *
          * @return version of your language
          */
@@ -95,7 +111,7 @@
         /**
          * List of MIME types associated with your language. Users will use them (directly or
          * indirectly) when
-         * {@link com.oracle.truffle.api.vm.TruffleVM#eval(com.oracle.truffle.api.source.Source)
+         * {@link com.oracle.truffle.api.vm.PolyglotEngine#eval(com.oracle.truffle.api.source.Source)
          * executing} their code snippets or their {@link Source files}.
          *
          * @return array of MIME types assigned to your language files
@@ -117,6 +133,15 @@
      * {@link Node findNode} and later {@link #findContext(com.oracle.truffle.api.nodes.Node)
      * findContext(findNode)} to get back your language context.
      *
+     * If it is expected that any {@linkplain Instrumenter Instrumentation Services} or tools that
+     * depend on those services (e.g. the {@link Debugger}, then part of the preparation in the new
+     * context is to
+     * {@linkplain Instrumenter#registerASTProber(com.oracle.truffle.api.instrument.ASTProber)
+     * register} a "default" {@link ASTProber} for the language implementation. Instrumentation
+     * requires that this be available to "mark up" each newly created AST with
+     * {@linkplain SyntaxTag "tags"} that identify standard syntactic constructs in order to
+     * configure tool behavior.
+     *
      * @param env the environment the language is supposed to operate in
      * @return internal data of the language in given environment
      */
@@ -152,7 +177,7 @@
      *         just parsed <code>code</code>
      * @throws IOException thrown when I/O or parsing goes wrong. Here-in thrown exception is
      *             propagate to the user who called one of <code>eval</code> methods of
-     *             {@link com.oracle.truffle.api.vm.TruffleVM}
+     *             {@link com.oracle.truffle.api.vm.PolyglotEngine}
      */
     protected abstract CallTarget parse(Source code, Node context, String... argumentNames) throws IOException;
 
@@ -201,9 +226,59 @@
      */
     protected abstract boolean isObjectOfLanguage(Object object);
 
-    protected abstract ToolSupportProvider getToolSupport();
+    /**
+     * Gets visualization services for language-specific information.
+     */
+    protected abstract Visualizer getVisualizer();
+
+    /**
+     * Returns {@code true} for a node can be "instrumented" by
+     * {@linkplain Instrumenter#probe(Node) probing}.
+     * <p>
+     * <b>Note:</b> instrumentation requires a appropriate {@link WrapperNode}
+     *
+     * @see WrapperNode
+     */
+    protected abstract boolean isInstrumentable(Node node);
 
-    protected abstract DebugSupportProvider getDebugSupport();
+    /**
+     * For nodes in this language that are <em>instrumentable</em>, this method returns an
+     * {@linkplain Node AST node} that:
+     * <ol>
+     * <li>implements {@link WrapperNode};</li>
+     * <li>has the node argument as it's child; and</li>
+     * <li>whose type is safe for replacement of the node in the parent.</li>
+     * </ol>
+     *
+     * @return an appropriately typed {@link WrapperNode}
+     */
+    protected abstract WrapperNode createWrapperNode(Node node);
+
+    /**
+     * Runs source code in a halted execution context, or at top level.
+     *
+     * @param source the code to run
+     * @param node node where execution halted, {@code null} if no execution context
+     * @param mFrame frame where execution halted, {@code null} if no execution context
+     * @return result of running the code in the context, or at top level if no execution context.
+     * @throws IOException if the evaluation cannot be performed
+     */
+    protected abstract Object evalInContext(Source source, Node node, MaterializedFrame mFrame) throws IOException;
+
+    /**
+     * Creates a language-specific factory to produce instances of {@link AdvancedInstrumentRoot}
+     * that, when executed, computes the result of a textual expression in the language; used to
+     * create an
+     * {@linkplain Instrumenter#attach(com.oracle.truffle.api.instrument.Probe, AdvancedInstrumentResultListener, AdvancedInstrumentRootFactory, Class, String)}
+     * .
+     *
+     * @param expr a guest language expression
+     * @param resultListener optional listener for the result of each evaluation.
+     * @return a new factory
+     * @throws IOException if the factory cannot be created, for example if the expression is badly
+     *             formed.
+     */
+    protected abstract AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(String expr, AdvancedInstrumentResultListener resultListener) throws IOException;
 
     /**
      * Allows a language implementor to create a node that can effectively lookup up the context
@@ -278,13 +353,15 @@
         private final InputStream in;
         private final OutputStream err;
         private final OutputStream out;
+        private final Instrumenter instrumenter;
 
-        Env(Object vm, TruffleLanguage<?> lang, OutputStream out, OutputStream err, InputStream in) {
+        Env(Object vm, TruffleLanguage<?> lang, OutputStream out, OutputStream err, InputStream in, Instrumenter instrumenter) {
             this.vm = vm;
             this.in = in;
             this.err = err;
             this.out = out;
             this.lang = lang;
+            this.instrumenter = instrumenter;
             this.langCtx = new LangCtx<>(lang, this);
         }
 
@@ -302,8 +379,8 @@
         }
 
         /**
-         * Input associated with {@link com.oracle.truffle.api.vm.TruffleVM} this language is being
-         * executed in.
+         * Input associated with {@link com.oracle.truffle.api.vm.PolyglotEngine} this language is
+         * being executed in.
          *
          * @return reader, never <code>null</code>
          */
@@ -317,8 +394,8 @@
         }
 
         /**
-         * Standard output writer for {@link com.oracle.truffle.api.vm.TruffleVM} this language is
-         * being executed in.
+         * Standard output writer for {@link com.oracle.truffle.api.vm.PolyglotEngine} this language
+         * is being executed in.
          *
          * @return writer, never <code>null</code>
          */
@@ -332,8 +409,8 @@
         }
 
         /**
-         * Standard error writer for {@link com.oracle.truffle.api.vm.TruffleVM} this language is
-         * being executed in.
+         * Standard error writer for {@link com.oracle.truffle.api.vm.PolyglotEngine} this language
+         * is being executed in.
          *
          * @return writer, never <code>null</code>
          */
@@ -345,6 +422,10 @@
         public Writer stdErr() {
             return new OutputStreamWriter(err);
         }
+
+        public Instrumenter instrumenter() {
+            return instrumenter;
+        }
     }
 
     private static final AccessAPI API = new AccessAPI();
@@ -352,8 +433,8 @@
     @SuppressWarnings("rawtypes")
     private static final class AccessAPI extends Accessor {
         @Override
-        protected Env attachEnv(Object vm, TruffleLanguage<?> language, OutputStream stdOut, OutputStream stdErr, InputStream stdIn) {
-            Env env = new Env(vm, language, stdOut, stdErr, stdIn);
+        protected Env attachEnv(Object vm, TruffleLanguage<?> language, OutputStream stdOut, OutputStream stdErr, InputStream stdIn, Instrumenter instrumenter) {
+            Env env = new Env(vm, language, stdOut, stdErr, stdIn, instrumenter);
             return env;
         }
 
@@ -382,6 +463,14 @@
         }
 
         @Override
+        protected AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(Object vm, Class<? extends TruffleLanguage> languageClass, String expr,
+                        AdvancedInstrumentResultListener resultListener) throws IOException {
+
+            final TruffleLanguage language = findLanguageImpl(vm, languageClass);
+            return language.createAdvancedInstrumentRootFactory(expr, resultListener);
+        }
+
+        @Override
         protected Object findExportedSymbol(TruffleLanguage.Env env, String globalName, boolean onlyExplicit) {
             return env.langCtx.findExportedSymbol(globalName, onlyExplicit);
         }
@@ -407,13 +496,13 @@
         }
 
         @Override
-        protected ToolSupportProvider getToolSupport(TruffleLanguage<?> l) {
-            return l.getToolSupport();
+        protected boolean isInstrumentable(Node node, TruffleLanguage language) {
+            return language.isInstrumentable(node);
         }
 
         @Override
-        protected DebugSupportProvider getDebugSupport(TruffleLanguage<?> l) {
-            return l.getDebugSupport();
+        protected WrapperNode createWrapperNode(Node node, TruffleLanguage language) {
+            return language.createWrapperNode(node);
         }
 
         @Override