changeset 22378:06bdf4a43126

Adding parse with argument names into the API and TCK
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Wed, 18 Nov 2015 11:53:28 +0100
parents a765d165e7ec
children fdf6ad720cdc
files truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TckLanguage.java truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java
diffstat 3 files changed, 106 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java	Mon Nov 16 15:58:03 2015 +0100
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java	Wed Nov 18 11:53:28 2015 +0100
@@ -387,16 +387,20 @@
         /**
          * Evaluates source of (potentially different) language. The {@link Source#getMimeType()
          * MIME type) is used to identify the {@link TruffleLanguage} to use to perform the
-         * {@link #parse(com.oracle.truffle.api.source.Source, com.oracle.truffle.api.nodes.Node, java.lang.String...)}
-         * .
+         * {@link #parse(com.oracle.truffle.api.source.Source, com.oracle.truffle.api.nodes.Node, java.lang.String...)}.
+         * The names of arguments are parameters for the resulting
+         * {#link CallTarget} that allow the <code>source</code> to reference
+         * the actual parameters passed to {@link CallTarget#call(java.lang.Object...)}.
          * 
          * @param source the source to evaluate
+         * @param argumentNames the names of {@link CallTarget#call(java.lang.Object...)}
+         *   arguments that can be referenced from the source
          * @return the call target representing the parsed result
          * @throws IOException if the parsing or evaluation fails for some reason
          */
-        public CallTarget parse(Source source) throws IOException {
+        public CallTarget parse(Source source, String... argumentNames) throws IOException {
             TruffleLanguage<?> language = API.findLanguageImpl(vm, null, source.getMimeType());
-            return language.parse(source, null);
+            return language.parse(source, null, argumentNames);
         }
 
         /**
--- a/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TckLanguage.java	Mon Nov 16 15:58:03 2015 +0100
+++ b/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TckLanguage.java	Wed Nov 18 11:53:28 2015 +0100
@@ -29,14 +29,18 @@
 import com.oracle.truffle.api.TruffleLanguage;
 import com.oracle.truffle.api.TruffleLanguage.Env;
 import com.oracle.truffle.api.frame.MaterializedFrame;
+import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.instrument.Visualizer;
 import com.oracle.truffle.api.instrument.WrapperNode;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.api.source.Source;
 import java.io.IOException;
 
-@TruffleLanguage.Registration(mimeType = "x-application/tck", name = "TCK", version = "1.0")
+@TruffleLanguage.Registration(mimeType = "application/x-tck", name = "TCK", version = "1.0")
 public final class TckLanguage extends TruffleLanguage<Env> {
     public static final TckLanguage INSTANCE = new TckLanguage();
 
@@ -47,8 +51,18 @@
 
     @Override
     protected CallTarget parse(Source code, Node context, String... argumentNames) throws IOException {
-        final double value = Double.parseDouble(code.getCode());
-        return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(value));
+        final RootNode root;
+        final String txt = code.getCode();
+        if (txt.startsWith("TCK42:")) {
+            int nextColon = txt.indexOf(":", 6);
+            String mimeType = txt.substring(6, nextColon);
+            Source toParse = Source.fromText(txt.substring(nextColon + 1), "").withMimeType(mimeType);
+            root = new MultiplyNode(toParse);
+        } else {
+            final double value = Double.parseDouble(txt);
+            root = RootNode.createConstantNode(value);
+        }
+        return Truffle.getRuntime().createCallTarget(root);
     }
 
     @Override
@@ -85,4 +99,49 @@
     protected Object evalInContext(Source source, Node node, MaterializedFrame mFrame) throws IOException {
         throw new IOException();
     }
+
+    private static final class MultiplyNode extends RootNode implements TruffleObject, ForeignAccess.Factory {
+        private final Source code;
+
+        public MultiplyNode(Source toParse) {
+            super(TckLanguage.class, null, null);
+            this.code = toParse;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            Env env = TckLanguage.INSTANCE.findContext(TckLanguage.INSTANCE.createFindContextNode());
+            if (frame.getArguments().length == 0) {
+                return this;
+            }
+            try {
+                CallTarget call = env.parse(code, (String)frame.getArguments()[1], (String)frame.getArguments()[2]);
+                return call.call(6, 7);
+            } catch (IOException ex) {
+                throw new AssertionError("Cannot parse " + code, ex);
+            }
+        }
+
+        @Override
+        public ForeignAccess getForeignAccess() {
+            return ForeignAccess.create(this);
+        }
+
+        @Override
+        public boolean canHandle(TruffleObject obj) {
+            return obj instanceof MultiplyNode;
+        }
+
+        @Override
+        public CallTarget accessMessage(Message tree) {
+            if (tree == Message.IS_EXECUTABLE) {
+                return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(Boolean.TRUE));
+            } else if (Message.createExecute(2).equals(tree)) {
+                return Truffle.getRuntime().createCallTarget(this);
+            } else {
+                throw new IllegalArgumentException("" + tree);
+            }
+        }
+
+    }
 }
--- a/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java	Mon Nov 16 15:58:03 2015 +0100
+++ b/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java	Wed Nov 18 11:53:28 2015 +0100
@@ -41,6 +41,13 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 /**
  * A collection of tests that can certify language implementation to be compliant with most recent
@@ -170,6 +177,19 @@
     }
 
     /**
+     * Code snippet to multiplyCode two two variables. The test uses the snippet
+     * as a parameter to your language's {@link TruffleLanguage#parse(com.oracle.truffle.api.source.Source, com.oracle.truffle.api.nodes.Node, java.lang.String...)}
+     * method.
+     *
+     * @param firstName name of the first variable to multiplyCode
+     * @param secondName name of the second variable to multiplyCode
+     * @return code snippet that multiplies the two variables in your language
+     */
+    protected String multiplyCode(String firstName, String secondName) {
+        throw new UnsupportedOperationException("multiply(String,String) method not implemeted!");
+    }
+
+    /**
      * Name of a function that counts number of its invocations in current {@link PolyglotEngine}
      * context. Your function should somehow keep a counter to remember number of its invocations
      * and always increment it. The first invocation should return <code>1</code>, the second
@@ -615,14 +635,27 @@
         PolyglotEngine.Value function = vm().findGlobalSymbol(evaluateSource());
         assertNotNull(evaluateSource() + " found", function);
 
-        Random r = new Random();
-        double expect = Math.floor(r.nextDouble() * 100000.0) / 10.0;
-        Object parsed = function.invoke(null, "x-application/tck", "" + expect).get();
+        double expect = Math.floor(RANDOM.nextDouble() * 100000.0) / 10.0;
+        Object parsed = function.invoke(null, "application/x-tck", "" + expect).get();
         assertTrue("Expecting numeric result, was:" + expect, parsed instanceof Number);
         double value = ((Number)parsed).doubleValue();
         assertEquals("Gets the double", expect, value, 0.01);
     }
 
+    @Test
+    public void multiplyTwoVariables() throws Exception {
+        final String firstVar = "var" + (char)('A' + RANDOM.nextInt(24));
+        final String secondVar = "var" + (char)('0' + RANDOM.nextInt(10));
+        String mulCode = multiplyCode(firstVar, secondVar);
+        Source source = Source.fromText("TCK42:" + mimeType() + ":" + mulCode, "evaluate " + firstVar + " * " + secondVar)
+            .withMimeType("application/x-tck");
+        final PolyglotEngine.Value evalSource = vm().eval(source);
+        final PolyglotEngine.Value invokeMul = evalSource.invoke(null, firstVar, secondVar);
+        Object result = invokeMul.get();
+        assertTrue("Expecting numeric result, was:" + result, result instanceof Number);
+        assertEquals("Right value", 42, ((Number)result).intValue());
+    }
+
     private PolyglotEngine.Value findGlobalSymbol(String name) throws Exception {
         PolyglotEngine.Value s = vm().findGlobalSymbol(name);
         assert s != null : "Symbol " + name + " is not found!";