# HG changeset patch # User Jaroslav Tulach # Date 1440398781 -7200 # Node ID cf19259edf874ae291dea9aa6f590a9a456f2ddc # Parent 7646278cca8aafe582dff83c366f409b713089fc TruffleVM.eval and Source.withMimeType diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceTest.java Mon Aug 24 08:46:21 2015 +0200 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2013, 2015, 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.api.test.source; + +import com.oracle.truffle.api.source.Source; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class SourceTest { + @Test + public void assignMimeTypeAndIdentity() { + Source s1 = Source.fromText("// a comment\n", "Empty comment"); + assertNull("No mime type assigned", s1.getMimeType()); + Source s2 = s1.withMimeType("text/x-c"); + assertEquals("They have the same content", s1.getCode(), s2.getCode()); + assertNotEquals("But different type", s1.getMimeType(), s2.getMimeType()); + assertNotEquals("So they are different", s1, s2); + } + + @Test + public void assignMimeTypeAndIdentityForApppendable() { + Source s1 = Source.fromAppendableText(""); + assertNull("No mime type assigned", s1.getMimeType()); + s1.appendCode("// Hello"); + Source s2 = s1.withMimeType("text/x-c"); + assertEquals("They have the same content", s1.getCode(), s2.getCode()); + assertEquals("// Hello", s1.getCode()); + assertNotEquals("But different type", s1.getMimeType(), s2.getMimeType()); + assertNotEquals("So they are different", s1, s2); + } + + @Test + public void assignMimeTypeAndIdentityForBytes() { + String text = "// Hello"; + Source s1 = Source.fromBytes(text.getBytes(StandardCharsets.UTF_8), "Hello", StandardCharsets.UTF_8); + assertNull("No mime type assigned", s1.getMimeType()); + Source s2 = s1.withMimeType("text/x-c"); + assertEquals("They have the same content", s1.getCode(), s2.getCode()); + assertEquals("// Hello", s1.getCode()); + assertNotEquals("But different type", s1.getMimeType(), s2.getMimeType()); + assertNotEquals("So they are different", s1, s2); + } + + @Test + public void assignMimeTypeAndIdentityForReader() throws IOException { + String text = "// Hello"; + Source s1 = Source.fromReader(new StringReader(text), "Hello"); + assertNull("No mime type assigned", s1.getMimeType()); + Source s2 = s1.withMimeType("text/x-c"); + assertEquals("They have the same content", s1.getCode(), s2.getCode()); + assertEquals("// Hello", s1.getCode()); + assertNotEquals("But different type", s1.getMimeType(), s2.getMimeType()); + assertNotEquals("So they are different", s1, s2); + } + + @Test + public void assignMimeTypeAndIdentityForFile() throws IOException { + File file = File.createTempFile("Hello", ".java"); + file.deleteOnExit(); + + String text; + try (FileWriter w = new FileWriter(file)) { + text = "// Hello"; + w.write(text); + } + + Source s1 = Source.fromFileName(file.getPath()); + assertEquals("Recognized as Java", "text/x-java", s1.getMimeType()); + Source s2 = s1.withMimeType("text/x-c"); + assertEquals("They have the same content", s1.getCode(), s2.getCode()); + assertEquals("// Hello", s1.getCode()); + assertNotEquals("But different type", s1.getMimeType(), s2.getMimeType()); + assertNotEquals("So they are different", s1, s2); + } + + @Test + public void assignMimeTypeAndIdentityForVirtualFile() throws IOException { + File file = File.createTempFile("Hello", ".java"); + file.deleteOnExit(); + + String text = "// Hello"; + + Source s1 = Source.fromFileName(text, file.getPath()); + assertEquals("Recognized as Java", "text/x-java", s1.getMimeType()); + Source s2 = s1.withMimeType("text/x-c"); + assertEquals("They have the same content", s1.getCode(), s2.getCode()); + assertEquals("// Hello", s1.getCode()); + assertNotEquals("But different type", s1.getMimeType(), s2.getMimeType()); + assertNotEquals("So they are different", s1, s2); + } + + @Test + public void assignMimeTypeAndIdentityForURL() throws IOException { + File file = File.createTempFile("Hello", ".java"); + file.deleteOnExit(); + + String text; + try (FileWriter w = new FileWriter(file)) { + text = "// Hello"; + w.write(text); + } + + Source s1 = Source.fromURL(file.toURI().toURL(), "Hello.java"); + assertEquals("Threated as plain", "text/plain", s1.getMimeType()); + Source s2 = s1.withMimeType("text/x-c"); + assertEquals("They have the same content", s1.getCode(), s2.getCode()); + assertEquals("// Hello", s1.getCode()); + assertNotEquals("But different type", s1.getMimeType(), s2.getMimeType()); + assertNotEquals("So they are different", s1, s2); + } +} diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/AccessorTest.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/AccessorTest.java Mon Aug 24 08:25:31 2015 +0200 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/AccessorTest.java Mon Aug 24 08:46:21 2015 +0200 @@ -24,6 +24,7 @@ import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.impl.Accessor; +import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.test.vm.ImplicitExplicitExportTest.ExportImportLanguage1; import static com.oracle.truffle.api.test.vm.ImplicitExplicitExportTest.L1; import com.oracle.truffle.api.vm.TruffleVM; @@ -50,7 +51,8 @@ TruffleVM.Language language = vm.getLanguages().get(L1); assertNotNull("L1 language is defined", language); - Object ret = vm.eval(L1, "return nothing"); + Source s = Source.fromText("return nothing", "nothing").withMimeType(L1); + Object ret = vm.eval(s); assertNull("nothing is returned", ret); Object afterInitialization = findLanguageByClass(vm); diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ExceptionDuringParsingTest.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ExceptionDuringParsingTest.java Mon Aug 24 08:25:31 2015 +0200 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ExceptionDuringParsingTest.java Mon Aug 24 08:46:21 2015 +0200 @@ -23,6 +23,7 @@ package com.oracle.truffle.api.test.vm; import com.oracle.truffle.api.impl.Accessor; +import com.oracle.truffle.api.source.Source; import static com.oracle.truffle.api.test.vm.ImplicitExplicitExportTest.L1; import com.oracle.truffle.api.vm.TruffleVM; import java.io.IOException; @@ -39,7 +40,7 @@ assertNotNull("L1 language is defined", language); try { - vm.eval(L1, "parse=No, no, no!"); + vm.eval(Source.fromText("parse=No, no, no!", "Fail on parsing").withMimeType(L1)); fail("Exception thrown"); } catch (IOException ex) { assertEquals(ex.getMessage(), "No, no, no!"); diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/GlobalSymbolTest.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/GlobalSymbolTest.java Mon Aug 24 08:25:31 2015 +0200 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/GlobalSymbolTest.java Mon Aug 24 08:46:21 2015 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.truffle.api.test.vm; +import com.oracle.truffle.api.source.Source; import static org.junit.Assert.*; import java.io.*; @@ -36,8 +37,8 @@ public void globalSymbolFoundByLanguage() throws IOException { TruffleVM vm = TruffleVM.newVM().globalSymbol("ahoj", "42").build(); // @formatter:off - Object ret = vm.eval(L3, - "return=ahoj" + Object ret = vm.eval( + Source.fromText("return=ahoj", "Return").withMimeType(L3) ); // @formatter:on assertEquals("42", ret); diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java Mon Aug 24 08:25:31 2015 +0200 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java Mon Aug 24 08:46:21 2015 +0200 @@ -52,11 +52,9 @@ @Test public void explicitExportFound() throws IOException { // @formatter:off - vm.eval(L1, - "explicit.ahoj=42" - ); - Object ret = vm.eval(L3, - "return=ahoj" + vm.eval(Source.fromText("explicit.ahoj=42", "Fourty two").withMimeType(L1)); + Object ret = vm.eval( + Source.fromText("return=ahoj", "Return").withMimeType(L3) ); // @formatter:on assertEquals("42", ret); @@ -65,11 +63,11 @@ @Test public void implicitExportFound() throws IOException { // @formatter:off - vm.eval(L1, - "implicit.ahoj=42" + vm.eval( + Source.fromText("implicit.ahoj=42", "Fourty two").withMimeType(L1) ); - Object ret = vm.eval(L3, - "return=ahoj" + Object ret = vm.eval( + Source.fromText("return=ahoj", "Return").withMimeType(L3) ); // @formatter:on assertEquals("42", ret); @@ -78,14 +76,14 @@ @Test public void explicitExportPreferred2() throws IOException { // @formatter:off - vm.eval(L1, - "implicit.ahoj=42" + vm.eval( + Source.fromText("implicit.ahoj=42", "Fourty two").withMimeType(L1) ); - vm.eval(L2, - "explicit.ahoj=43" + vm.eval( + Source.fromText("explicit.ahoj=43", "Fourty three").withMimeType(L2) ); - Object ret = vm.eval(L3, - "return=ahoj" + Object ret = vm.eval( + Source.fromText("return=ahoj", "Return").withMimeType(L3) ); // @formatter:on assertEquals("Explicit import from L2 is used", "43", ret); @@ -95,14 +93,14 @@ @Test public void explicitExportPreferred1() throws IOException { // @formatter:off - vm.eval(L1, - "explicit.ahoj=43" + vm.eval( + Source.fromText("explicit.ahoj=43", "Fourty three").withMimeType(L1) ); - vm.eval(L2, - "implicit.ahoj=42" + vm.eval( + Source.fromText("implicit.ahoj=42", "Fourty two").withMimeType(L2) ); - Object ret = vm.eval(L3, - "return=ahoj" + Object ret = vm.eval( + Source.fromText("return=ahoj", "Return").withMimeType(L3) ); // @formatter:on assertEquals("Explicit import from L2 is used", "43", ret); diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java --- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java Mon Aug 24 08:25:31 2015 +0200 +++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java Mon Aug 24 08:46:21 2015 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.truffle.api.test.vm; +import com.oracle.truffle.api.source.Source; import java.io.*; import java.net.*; @@ -45,16 +46,19 @@ t.join(); } + @SuppressWarnings("deprecation") @Test(expected = IllegalStateException.class) public void evalURI() throws IOException, URISyntaxException { tvm.eval(new URI("http://unknown.js")); } + @SuppressWarnings("deprecation") @Test(expected = IllegalStateException.class) public void evalString() throws IOException { tvm.eval("text/javascript", "1 + 1"); } + @SuppressWarnings("deprecation") @Test(expected = IllegalStateException.class) public void evalReader() throws IOException { try (StringReader sr = new StringReader("1 + 1")) { @@ -63,6 +67,11 @@ } @Test(expected = IllegalStateException.class) + public void evalSource() throws IOException { + tvm.eval(Source.fromText("", "Empty")); + } + + @Test(expected = IllegalStateException.class) public void findGlobalSymbol() { tvm.findGlobalSymbol("doesNotExists"); } diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java Mon Aug 24 08:25:31 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java Mon Aug 24 08:46:21 2015 +0200 @@ -84,8 +84,8 @@ /** * List of MIME types associated with your language. Users will use them (directly or - * indirectly) when {@link TruffleVM#eval(java.lang.String, java.lang.String) executing} - * their code snippets or their {@link TruffleVM#eval(java.net.URI) files}. + * indirectly) when {@link TruffleVM#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 */ diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/package-info.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/package-info.java Mon Aug 24 08:25:31 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/package-info.java Mon Aug 24 08:46:21 2015 +0200 @@ -39,7 +39,7 @@ * {@link com.oracle.truffle.api.vm.TruffleVM.Builder#onEvent(com.oracle.truffle.api.vm.EventConsumer) onEvent}(new {@link com.oracle.truffle.api.vm.EventConsumer EventConsumer} * {@code <}{@link com.oracle.truffle.api.debug.ExecutionEvent}{@code >}() { * public void handle({@link com.oracle.truffle.api.debug.ExecutionEvent} ev) { - * // configure the virtual machine as {@link com.oracle.truffle.api.vm.TruffleVM#eval(java.net.URI) new execution} is starting + * // configure the virtual machine as {@link com.oracle.truffle.api.vm.TruffleVM#eval(com.oracle.truffle.api.source.Source) new execution} is starting * } * }). * {@link com.oracle.truffle.api.vm.TruffleVM.Builder#onEvent(com.oracle.truffle.api.vm.EventConsumer) onEvent}(new {@link com.oracle.truffle.api.vm.EventConsumer EventConsumer}{@code <} @@ -51,7 +51,7 @@ * * The debugging is controlled by events emitted by the Truffle virtual machine * at important moments. The {@link com.oracle.truffle.api.debug.ExecutionEvent} - * is sent when a call to {@link com.oracle.truffle.api.vm.TruffleVM#eval(java.net.URI) eval(...)} + * is sent when a call to {@link com.oracle.truffle.api.vm.TruffleVM#eval(com.oracle.truffle.api.source.Source)} * is made and allows one to configure {@link com.oracle.truffle.api.debug.Breakpoint breakpoints} and/or decide whether the * program should {@link com.oracle.truffle.api.debug.ExecutionEvent#prepareStepInto() step-into} or * {@link com.oracle.truffle.api.debug.ExecutionEvent#prepareContinue() just run}. Once the execution is suspended a diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java Mon Aug 24 08:25:31 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java Mon Aug 24 08:46:21 2015 +0200 @@ -32,6 +32,11 @@ import java.util.*; import com.oracle.truffle.api.*; +import com.oracle.truffle.api.TruffleLanguage.Registration; +import java.nio.file.Files; +import java.nio.file.spi.FileTypeDetector; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Representation of a guest language source code unit and its contents. Sources originate in @@ -87,6 +92,7 @@ *

*/ public abstract class Source { + private static final Logger LOG = Logger.getLogger(Source.class.getName()); // TODO (mlvdv) consider canonicalizing and reusing SourceSection instances // TOOD (mlvdv) connect SourceSections into a spatial tree for fast geometric lookup @@ -374,7 +380,8 @@ private Source() { } - private TextMap textMap = null; + private String mimeType; + private TextMap textMap; abstract void reset(); @@ -402,6 +409,8 @@ /** * The URL if the source is retrieved via URL. + * + * @return URL or null */ public abstract URL getURL(); @@ -632,7 +641,50 @@ return TextMap.fromString(code); } - private static final class LiteralSource extends Source { + /** + * Associates the source with specified MIME type. The mime type may be used to select the right + * {@link Registration Truffle language} to use to execute the returned source. The value of MIME + * type can be obtained via {@link #getMimeType()} method. + * + * @param mime mime type to use + * @return new (identical) source, just associated {@link #getMimeType()} + */ + public final Source withMimeType(String mime) { + try { + Source another = (Source) clone(); + another.mimeType = mime; + return another; + } catch (CloneNotSupportedException ex) { + throw new IllegalStateException(ex); + } + } + + /** + * MIME type that is associated with this source. By default file extensions known to the system + * are used to determine the MIME type (via registered {@link FileTypeDetector} classes), yet + * one can directly {@link #withMimeType(java.lang.String) provide a MIME type} to each source. + * + * @return MIME type of this source or null, if unknown + */ + public String getMimeType() { + if (mimeType == null) { + mimeType = findMimeType(); + } + return mimeType; + } + + String findMimeType() { + return null; + } + + final boolean equalMime(Source other) { + if (mimeType == null) { + return other.mimeType == null; + } + return mimeType.equals(other.mimeType); + } + + private static final class LiteralSource extends Source implements Cloneable { private final String description; private final String code; @@ -691,14 +743,14 @@ } if (obj instanceof LiteralSource) { LiteralSource other = (LiteralSource) obj; - return description.equals(other.description) && code.equals(other.code); + return description.equals(other.description) && code.equals(other.code) && equalMime(other); } return false; } } - private static final class AppendableLiteralSource extends Source { - private String description; + private static final class AppendableLiteralSource extends Source implements Cloneable { + private final String description; final List codeList = new ArrayList<>(); public AppendableLiteralSource(String description) { @@ -756,7 +808,7 @@ } - private static final class FileSource extends Source { + private static final class FileSource extends Source implements Cloneable { private final File file; private final String name; // Name used originally to describe the source @@ -836,13 +888,29 @@ } @Override + String findMimeType() { + if (file.getName().endsWith(".c")) { + return "text/x-c"; + } else if (file.getName().endsWith(".R") || file.getName().endsWith(".r")) { + return "application/x-r"; + } else { + try { + return Files.probeContentType(file.toPath()); + } catch (IOException ex) { + LOG.log(Level.SEVERE, null, ex); + } + } + return null; + } + + @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof FileSource) { FileSource other = (FileSource) obj; - return path.equals(other.path); + return path.equals(other.path) && equalMime(other); } return false; } @@ -854,7 +922,7 @@ } // TODO (mlvdv) if we keep this, hoist a superclass in common with FileSource. - private static final class ClientManagedFileSource extends Source { + private static final class ClientManagedFileSource extends Source implements Cloneable { private final File file; private final String name; // Name used originally to describe the source @@ -908,6 +976,22 @@ } @Override + String findMimeType() { + if (file.getName().endsWith(".c")) { + return "text/x-c"; + } else if (file.getName().endsWith(".R") || file.getName().endsWith(".r")) { + return "application/x-r"; + } else { + try { + return Files.probeContentType(file.toPath()); + } catch (IOException ex) { + LOG.log(Level.SEVERE, null, ex); + } + } + return null; + } + + @Override public int hashCode() { return path.hashCode(); } @@ -919,7 +1003,7 @@ } if (obj instanceof ClientManagedFileSource) { ClientManagedFileSource other = (ClientManagedFileSource) obj; - return path.equals(other.path); + return path.equals(other.path) && equalMime(other); } return false; } @@ -930,7 +1014,7 @@ } } - private static final class URLSource extends Source { + private static final class URLSource extends Source implements Cloneable { private static final Map> urlToSource = new HashMap<>(); @@ -946,12 +1030,16 @@ private final URL url; private final String name; - private String code = null; // A cache of the source contents + private String code; // A cache of the source contents public URLSource(URL url, String name) throws IOException { this.url = url; this.name = name; - code = read(new InputStreamReader(url.openStream())); + URLConnection c = url.openConnection(); + if (super.mimeType == null) { + super.mimeType = c.getContentType(); + } + code = read(new InputStreamReader(c.getInputStream())); } @Override @@ -989,7 +1077,7 @@ } } - private static final class SubSource extends Source { + private static final class SubSource extends Source implements Cloneable { private final Source base; private final int baseIndex; private final int subLength; @@ -1044,7 +1132,7 @@ } } - private static final class BytesSource extends Source { + private static final class BytesSource extends Source implements Cloneable { private final String name; private final byte[] bytes; diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java --- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java Mon Aug 24 08:25:31 2015 +0200 +++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java Mon Aug 24 08:46:21 2015 +0200 @@ -344,7 +344,9 @@ * @return result of a processing the file, possibly null * @throws IOException exception to signal I/O problems or problems with processing the file's * content + * @deprecated use {@link #eval(com.oracle.truffle.api.source.Source)} */ + @Deprecated public Object eval(URI location) throws IOException { checkThread(); Source s; @@ -382,7 +384,9 @@ * @param reader the source of code snippet to execute * @return result of an execution, possibly null * @throws IOException thrown to signal errors while processing the code + * @deprecated use {@link #eval(com.oracle.truffle.api.source.Source)} */ + @Deprecated public Object eval(String mimeType, Reader reader) throws IOException { checkThread(); TruffleLanguage l = getTruffleLang(mimeType); @@ -400,7 +404,9 @@ * @param code the code snippet to execute * @return result of an execution, possibly null * @throws IOException thrown to signal errors while processing the code + * @deprecated use {@link #eval(com.oracle.truffle.api.source.Source)} */ + @Deprecated public Object eval(String mimeType, String code) throws IOException { checkThread(); TruffleLanguage l = getTruffleLang(mimeType); @@ -410,6 +416,25 @@ return eval(l, Source.fromText(code, mimeType)); } + /** + * Evaluates provided source. Chooses language registered for a particular + * {@link Source#getMimeType() MIME type} (throws {@link IOException} if there is none). The + * language is then allowed to parse and execute the source. + * + * @param source code snippet to execute + * @return result of an execution, possibly null + * @throws IOException thrown to signal errors while processing the code + */ + public Object eval(Source source) throws IOException { + String mimeType = source.getMimeType(); + checkThread(); + TruffleLanguage l = getTruffleLang(mimeType); + if (l == null) { + throw new IOException("No language for MIME type " + mimeType + " found. Supported types: " + langs.keySet()); + } + return eval(l, source); + } + private Object eval(TruffleLanguage l, Source s) throws IOException { TruffleVM.findDebuggerSupport(l); Debugger[] fillIn = {debugger}; diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java --- a/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java Mon Aug 24 08:25:31 2015 +0200 +++ b/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java Mon Aug 24 08:46:21 2015 +0200 @@ -40,6 +40,7 @@ */ package com.oracle.truffle.sl.test; +import com.oracle.truffle.api.source.Source; import com.oracle.truffle.tck.TruffleTCK; import com.oracle.truffle.api.vm.TruffleVM; import static org.junit.Assert.*; @@ -60,26 +61,28 @@ protected TruffleVM prepareVM() throws Exception { TruffleVM vm = TruffleVM.newVM().build(); // @formatter:off - vm.eval("application/x-sl", - "function fourtyTwo() {\n" + - " return 42;\n" + // - "}\n" + - "function plus(a, b) {\n" + - " return a + b;\n" + - "}\n" + - "function apply(f) {\n" + - " return f(18, 32) + 10;\n" + - "}\n" + - "function cnt() {\n" + - " return 0;\n" + - "}\n" + - "function count() {\n" + - " n = cnt() + 1;\n" + - " defineFunction(\"function cnt() { return \" + n + \"; }\");\n" + - " return n;\n" + - "}\n" + - "function null() {\n" + - "}\n" + vm.eval( + Source.fromText( + "function fourtyTwo() {\n" + + " return 42;\n" + // + "}\n" + + "function plus(a, b) {\n" + + " return a + b;\n" + + "}\n" + + "function apply(f) {\n" + + " return f(18, 32) + 10;\n" + + "}\n" + + "function cnt() {\n" + + " return 0;\n" + + "}\n" + + "function count() {\n" + + " n = cnt() + 1;\n" + + " defineFunction(\"function cnt() { return \" + n + \"; }\");\n" + + " return n;\n" + + "}\n" + + "function null() {\n" + + "}\n", "SL TCK" + ).withMimeType("application/x-sl") ); // @formatter:on return vm; diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java --- a/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java Mon Aug 24 08:25:31 2015 +0200 +++ b/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java Mon Aug 24 08:46:21 2015 +0200 @@ -221,7 +221,7 @@ TruffleVM vm = TruffleVM.newVM().stdIn(new BufferedReader(new StringReader(repeat(testCase.testInput, repeats)))).stdOut(printer).build(); String script = readAllLines(testCase.path); - SLLanguage.run(vm, testCase.path.toUri(), null, printer, repeats, builtins); + SLLanguage.run(vm, testCase.path, null, printer, repeats, builtins); printer.flush(); String actualOutput = new String(out.toByteArray()); diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java --- a/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java Mon Aug 24 08:25:31 2015 +0200 +++ b/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java Mon Aug 24 08:46:21 2015 +0200 @@ -56,6 +56,7 @@ import com.oracle.truffle.api.instrument.*; import com.oracle.truffle.api.instrument.impl.*; +import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.vm.*; import com.oracle.truffle.sl.nodes.instrument.*; import com.oracle.truffle.sl.nodes.local.*; @@ -229,7 +230,7 @@ TruffleVM vm = TruffleVM.newVM().stdIn(new BufferedReader(new StringReader(testCase.testInput))).stdOut(printer).build(); final String src = readAllLines(testCase.path); - vm.eval("application/x-sl", src); + vm.eval(Source.fromText(src, testCase.path.toString()).withMimeType("application/x-sl")); // Attach an instrument to every probe tagged as an assignment for (Probe probe : Probe.findProbesTaggedAs(StandardSyntaxTag.ASSIGNMENT)) { diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.sl.tools/src/com/oracle/truffle/sl/tools/debug/SLREPLHandler.java --- a/truffle/com.oracle.truffle.sl.tools/src/com/oracle/truffle/sl/tools/debug/SLREPLHandler.java Mon Aug 24 08:25:31 2015 +0200 +++ b/truffle/com.oracle.truffle.sl.tools/src/com/oracle/truffle/sl/tools/debug/SLREPLHandler.java Mon Aug 24 08:46:21 2015 +0200 @@ -44,6 +44,7 @@ import java.util.*; import com.oracle.truffle.api.instrument.*; +import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.vm.*; import com.oracle.truffle.tools.debug.shell.*; import com.oracle.truffle.tools.debug.shell.client.*; @@ -127,7 +128,7 @@ return finishReplyFailed(reply, "can't find file \"" + fileName + "\""); } final TruffleVM vm = serverContext.vm(); - vm.eval(file.toURI()); + vm.eval(Source.fromFileName(file.getPath())); TruffleVM.Symbol main = vm.findGlobalSymbol("main"); if (main != null) { main.invoke(null); diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.sl/src/META-INF/services/java.nio.file.spi.FileTypeDetector --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.sl/src/META-INF/services/java.nio.file.spi.FileTypeDetector Mon Aug 24 08:46:21 2015 +0200 @@ -0,0 +1,1 @@ +com.oracle.truffle.sl.SLFileDetector diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLFileDetector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLFileDetector.java Mon Aug 24 08:46:21 2015 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.sl; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.spi.FileTypeDetector; + +public final class SLFileDetector extends FileTypeDetector { + @Override + public String probeContentType(Path path) throws IOException { + if (path.getFileName().toString().endsWith(".sl")) { + return "application/x-sl"; + } + return null; + } +} diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java --- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java Mon Aug 24 08:25:31 2015 +0200 +++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java Mon Aug 24 08:46:21 2015 +0200 @@ -65,6 +65,7 @@ import com.oracle.truffle.sl.parser.*; import com.oracle.truffle.sl.runtime.*; import com.oracle.truffle.tools.*; +import java.nio.file.Path; /** * SL is a simple language to demonstrate and showcase features of Truffle. The implementation is as @@ -200,11 +201,13 @@ repeats = Integer.parseInt(args[1]); } + Source source; if (args.length == 0) { - vm.eval("application/x-sl", new InputStreamReader(System.in)); + source = Source.fromReader(new InputStreamReader(System.in), "").withMimeType("application/x-sl"); } else { - vm.eval(new File(args[0]).toURI()); + source = Source.fromFileName(args[0]); } + vm.eval(source); Symbol main = vm.findGlobalSymbol("main"); if (main == null) { throw new SLException("No function main() defined in SL source file."); @@ -221,7 +224,7 @@ public static void run(Source source) throws IOException { TruffleVM vm = TruffleVM.newVM().build(); assert vm.getLanguages().containsKey("application/x-sl"); - vm.eval(new File(source.getPath()).toURI()); + vm.eval(source); Symbol main = vm.findGlobalSymbol("main"); if (main == null) { throw new SLException("No function main() defined in SL source file."); @@ -233,7 +236,7 @@ * Parse and run the specified SL source. Factored out in a separate method so that it can also * be used by the unit test harness. */ - public static long run(TruffleVM context, URI source, PrintWriter logOutput, PrintWriter out, int repeats, List> currentBuiltins) throws IOException { + public static long run(TruffleVM context, Path path, PrintWriter logOutput, PrintWriter out, int repeats, List> currentBuiltins) throws IOException { builtins = currentBuiltins; if (logOutput != null) { @@ -241,8 +244,9 @@ // logOutput.println("Source = " + source.getCode()); } + Source src = Source.fromFileName(path.toString()); /* Parse the SL source file. */ - Object result = context.eval(source); + Object result = context.eval(src.withMimeType("application/x-sl")); if (result != null) { out.println(result); } diff -r 7646278cca8a -r cf19259edf87 truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java --- a/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java Mon Aug 24 08:25:31 2015 +0200 +++ b/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java Mon Aug 24 08:46:21 2015 +0200 @@ -24,6 +24,7 @@ */ package com.oracle.truffle.tck; +import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.vm.TruffleVM; import java.io.IOException; import java.util.Random; @@ -44,8 +45,8 @@ /** * This methods is called before first test is executed. It's purpose is to set a TruffleVM with * your language up, so it is ready for testing. - * {@link TruffleVM#eval(java.lang.String, java.lang.String) Execute} any scripts you need, and - * prepare global symbols with proper names. The symbols will then be looked up by the + * {@link TruffleVM#eval(com.oracle.truffle.api.source.Source) Execute} any scripts you need, + * and prepare global symbols with proper names. The symbols will then be looked up by the * infrastructure (using the names provided by you from methods like {@link #plusInt()}) and * used for internal testing. * @@ -56,8 +57,8 @@ /** * Mimetype associated with your language. The mimetype will be passed to - * {@link TruffleVM#eval(java.lang.String, java.lang.String)} method of the {@link #prepareVM() - * created TruffleVM}. + * {@link TruffleVM#eval(com.oracle.truffle.api.source.Source)} method of the + * {@link #prepareVM() created TruffleVM}. * * @return mime type of the tested language */ @@ -116,7 +117,7 @@ /** * Return a code snippet that is invalid in your language. Its - * {@link TruffleVM#eval(java.lang.String, java.lang.String) evaluation} should fail and yield + * {@link TruffleVM#eval(com.oracle.truffle.api.source.Source) evaluation} should fail and yield * an exception. * * @return code snippet invalid in the tested language @@ -180,7 +181,7 @@ public void testInvalidTestMethod() throws Exception { String mime = mimeType(); String code = invalidCode(); - Object ret = vm().eval(mime, code); + Object ret = vm().eval(Source.fromText(code, "Invalid code").withMimeType(mime)); fail("Should yield IOException, but returned " + ret); }