Mercurial > hg > truffle
diff truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java @ 22104:cf19259edf87
TruffleVM.eval and Source.withMimeType
author | Jaroslav Tulach <jaroslav.tulach@oracle.com> |
---|---|
date | Mon, 24 Aug 2015 08:46:21 +0200 |
parents | 04b13488da2a |
children | 7ee578004be7 |
line wrap: on
line diff
--- 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 @@ * <p> */ 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 <code>null</code> */ 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 <code>null</code>, 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<CharSequence> 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<URL, WeakReference<URLSource>> 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;