Mercurial > hg > graal-jvmci-8
changeset 21271:1516d26e8f2b
Truffle/Source: add a new kind of Source (both indexed and non-indexed flavors) whose contents are unavailable at creation, but will be provided incrementally.
author | Michael Van De Vanter <michael.van.de.vanter@oracle.com> |
---|---|
date | Thu, 07 May 2015 20:14:23 -0700 |
parents | a43c7adc9d99 |
children | 090291af4230 |
files | graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java |
diffstat | 1 files changed, 153 insertions(+), 21 deletions(-) [+] |
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java Thu May 07 17:51:55 2015 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java Thu May 07 20:14:23 2015 -0700 @@ -60,6 +60,11 @@ * <li><strong>Reader:</strong> Contents are <em>read eagerly</em> and treated as an anonymous * (non-indexed) <em>Literal</em> . <br> * See {@link Source#fromReader(Reader, String)}</li> + * <p> + * <li><strong>AppendableSource:</strong> Literal contents are provided by the client, + * incrementally, after the instance is created.<br> + * See {@link Source#fromAppendableText(String)}<br> + * See {@link Source#fromNamedAppendableText(String)}</li> * </ul> * <p> * <strong>File cache:</strong> @@ -239,6 +244,19 @@ } /** + * Creates an anonymous source from literal text that is provided incrementally after creation: + * not named and not indexed. + * + * @param description a note about the origin, for error messages and debugging + * @return a newly created, non-indexed, initially empty, appendable source representation + */ + public static AppendableSource fromAppendableText(String description) { + final AppendableSource source = new AppendableLiteralSource(description); + notifyNewSource(source).tagAs(Tags.FROM_LITERAL); + return source; + } + + /** * Creates a source from literal text that can be retrieved by name, with no assumptions about * the structure or meaning of the name. If the name is already in the index, the new instance * will replace the previously existing instance in the index. @@ -255,6 +273,22 @@ } /** + * Creates a source from literal text that is provided incrementally after creation and which + * can be retrieved by name, with no assumptions about the structure or meaning of the name. If + * the name is already in the index, the new instance will replace the previously existing + * instance in the index. + * + * @param name string to use for indexing/lookup + * @return a newly created, indexed, initially empty, appendable source representation + */ + public static AppendableSource fromNamedAppendableText(String name) { + final Source source = new AppendableLiteralSource(name); + nameToSource.put(name, new WeakReference<>(source)); + notifyNewSource(source).tagAs(Tags.FROM_LITERAL); + return (AppendableSource) source; + } + + /** * Creates a source whose contents will be read immediately from a URL and cached. * * @param url @@ -384,9 +418,28 @@ return builder.toString(); } + public abstract static class AppendableSource extends Source { + + /** + * Sets the mark. + */ + public void setMark() { + } + + public abstract void appendCode(CharSequence chars); + + /** + * Gets the code from the mark to the end. + */ + public String getCodeFromMark() { + return getCode(); + } + + } + private final ArrayList<SourceTag> tags = new ArrayList<>(); - Source() { + private Source() { } private TextMap textMap = null; @@ -641,13 +694,25 @@ return new LineLocationImpl(this, lineNumber); } - private TextMap checkTextMap() { + /** + * An object suitable for using as a key into a hashtable that defines equivalence between + * different source types. + */ + protected Object getHashKey() { + return getName(); + } + + protected final TextMap checkTextMap() { if (textMap == null) { textMap = createTextMap(); } return textMap; } + protected final void clearTextMap() { + textMap = null; + } + protected TextMap createTextMap() { final String code = getCode(); if (code == null) { @@ -658,22 +723,22 @@ private static final class LiteralSource extends Source { - private final String name; // Name used originally to describe the source + private final String description; private final String code; - public LiteralSource(String name, String code) { - this.name = name; + public LiteralSource(String description, String code) { + this.description = description; this.code = code; } @Override public String getName() { - return name; + return description; } @Override public String getShortName() { - return name; + return description; } @Override @@ -683,7 +748,7 @@ @Override public String getPath() { - return name; + return description; } @Override @@ -702,11 +767,7 @@ @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + name.hashCode(); - result = prime * result + (code == null ? 0 : code.hashCode()); - return result; + return description.hashCode(); } @Override @@ -717,13 +778,81 @@ if (obj == null) { return false; } - if (!(obj instanceof LiteralSource)) { - return false; + if (obj instanceof LiteralSource) { + LiteralSource other = (LiteralSource) obj; + return description.equals(other.description); } - LiteralSource other = (LiteralSource) obj; - return name.equals(other.name) && code.equals(other.code); + return false; + } + } + + private static final class AppendableLiteralSource extends AppendableSource { + private String description; + private int mark = 0; + final List<CharSequence> codeList = new ArrayList<>(); + + public AppendableLiteralSource(String description) { + this.description = description; + } + + @Override + public String getName() { + return description; + } + + @Override + public String getShortName() { + return description; + } + + @Override + public String getCode() { + return getCodeFromIndex(0); + } + + @Override + public String getPath() { + return description; } + @Override + public URL getURL() { + return null; + } + + @Override + public Reader getReader() { + return new StringReader(getCode()); + } + + @Override + protected void reset() { + } + + private String getCodeFromIndex(int index) { + StringBuilder sb = new StringBuilder(); + for (int i = index; i < codeList.size(); i++) { + CharSequence s = codeList.get(i); + sb.append(s); + } + return sb.toString(); + } + + @Override + public String getCodeFromMark() { + return getCodeFromIndex(mark); + } + + @Override + public void appendCode(CharSequence chars) { + codeList.add(chars); + clearTextMap(); + } + + @Override + public void setMark() { + mark = codeList.size(); + } } private static final class FileSource extends Source { @@ -759,6 +888,11 @@ } @Override + protected Object getHashKey() { + return path; + } + + @Override public String getCode() { if (fileCacheEnabled) { if (code == null || timeStamp != file.lastModified()) { @@ -821,7 +955,6 @@ protected void reset() { this.code = null; } - } private static final class URLSource extends Source { @@ -881,7 +1014,6 @@ @Override protected void reset() { } - } private static final class BytesSource extends Source { @@ -1146,7 +1278,7 @@ final int prime = 31; int result = 1; result = prime * result + line; - result = prime * result + source.hashCode(); + result = prime * result + source.getHashKey().hashCode(); return result; } @@ -1165,7 +1297,7 @@ if (line != other.line) { return false; } - return source.equals(other.source); + return source.getHashKey().equals(other.source.getHashKey()); } }