changeset 19698:32b4b06b6fac

Merge with 5d2309d32463f4c857d55e3233e8366f7b4d6feb
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Wed, 04 Mar 2015 16:38:36 -0800
parents 191c55f08ed2 (diff) 5d2309d32463 (current diff)
children ef30b2318658 8f21e30a29c2
files
diffstat 10 files changed, 462 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceTest.java	Wed Mar 04 16:38:36 2015 -0800
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 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 static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.source.*;
+
+public class SourceTest {
+
+    @Test
+    public void sourceTagTest() {
+
+        // Private tag
+        final SourceTag testTag = new SourceTag() {
+
+            public String name() {
+                return null;
+            }
+
+            public String getDescription() {
+                return null;
+            }
+        };
+
+        // No sources exist with the private tag
+        assertEquals(Source.findSourcesTaggedAs(testTag).size(), 0);
+
+        // Create a new source
+        final Source source = Source.fromText("test1 source", "test1 source");
+
+        // Initially has only the default tag
+        assertEquals(source.getSourceTags().size(), 1);
+
+        assertTrue(source.getSourceTags().contains(StandardSourceTag.FROM_LITERAL));
+        assertTrue(source.isTaggedAs(StandardSourceTag.FROM_LITERAL));
+        assertTrue(Source.findSourcesTaggedAs(StandardSourceTag.FROM_LITERAL).contains(source));
+
+        assertFalse(source.isTaggedAs(testTag));
+        assertEquals(Source.findSourcesTaggedAs(testTag).size(), 0);
+
+        // Add a private tag
+        source.tagAs(testTag);
+
+        // Now there are exactly two tags
+        assertEquals(source.getSourceTags().size(), 2);
+
+        assertTrue(source.getSourceTags().contains(StandardSourceTag.FROM_LITERAL));
+        assertTrue(source.isTaggedAs(StandardSourceTag.FROM_LITERAL));
+        assertTrue(Source.findSourcesTaggedAs(StandardSourceTag.FROM_LITERAL).contains(source));
+
+        assertTrue(source.getSourceTags().contains(testTag));
+        assertTrue(source.isTaggedAs(testTag));
+        assertEquals(Source.findSourcesTaggedAs(testTag).size(), 1);
+        assertTrue(Source.findSourcesTaggedAs(testTag).contains(source));
+
+        // Add the private tag again
+        source.tagAs(testTag);
+
+        // Nothing has changed
+        assertEquals(source.getSourceTags().size(), 2);
+
+        assertTrue(source.getSourceTags().contains(StandardSourceTag.FROM_LITERAL));
+        assertTrue(source.isTaggedAs(StandardSourceTag.FROM_LITERAL));
+        assertTrue(Source.findSourcesTaggedAs(StandardSourceTag.FROM_LITERAL).contains(source));
+
+        assertTrue(source.getSourceTags().contains(testTag));
+        assertTrue(source.isTaggedAs(testTag));
+        assertEquals(Source.findSourcesTaggedAs(testTag).size(), 1);
+        assertTrue(Source.findSourcesTaggedAs(testTag).contains(source));
+    }
+
+    @Test
+    public void sourceListenerTest() {
+
+        // Private tag
+        final SourceTag testTag = new SourceTag() {
+
+            public String name() {
+                return null;
+            }
+
+            public String getDescription() {
+                return null;
+            }
+        };
+
+        final int[] newSourceEvents = {0};
+        final Source[] newSource = {null};
+
+        final int[] newTagEvents = {0};
+        final Source[] taggedSource = {null};
+        final SourceTag[] newTag = {null};
+
+        Source.addSourceListener(new SourceListener() {
+
+            public void sourceCreated(Source source) {
+                newSourceEvents[0] = newSourceEvents[0] + 1;
+                newSource[0] = source;
+            }
+
+            public void sourceTaggedAs(Source source, SourceTag tag) {
+                newTagEvents[0] = newTagEvents[0] + 1;
+                taggedSource[0] = source;
+                newTag[0] = tag;
+            }
+        });
+
+        // New source has a default tag applied.
+        // Get one event for the new source, another one when it gets tagged
+        final Source source = Source.fromText("testSource", "testSource");
+        assertEquals(newSourceEvents[0], 1);
+        assertEquals(newSource[0], source);
+        assertEquals(newTagEvents[0], 1);
+        assertEquals(taggedSource[0], source);
+        assertEquals(newTag[0], StandardSourceTag.FROM_LITERAL);
+
+        // reset
+        newSource[0] = null;
+        taggedSource[0] = null;
+        newTag[0] = null;
+
+        // Add a tag; only get one event (the new tag)
+        source.tagAs(testTag);
+        assertEquals(newSourceEvents[0], 1);
+        assertEquals(newSource[0], null);
+        assertEquals(newTagEvents[0], 2);
+        assertEquals(taggedSource[0], source);
+        assertEquals(newTag[0], testTag);
+
+        // Add the same tag; no events, and nothing changes.
+        source.tagAs(testTag);
+        assertEquals(newSourceEvents[0], 1);
+        assertEquals(newSource[0], null);
+        assertEquals(newTagEvents[0], 2);
+        assertEquals(taggedSource[0], source);
+        assertEquals(newTag[0], testTag);
+
+    }
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Wed Mar 04 12:17:46 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Wed Mar 04 16:38:36 2015 -0800
@@ -69,6 +69,7 @@
  * @see Instrument
  * @see ASTProber
  * @see ProbeListener
+ * @see SyntaxTag
  */
 public final class Probe implements SyntaxTagged {
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardSyntaxTag.java	Wed Mar 04 12:17:46 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardSyntaxTag.java	Wed Mar 04 16:38:36 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -30,8 +30,6 @@
  * <p>
  * The need for alternative sets of tags is likely to arise, perhaps for other families of languages
  * (for example for mostly expression-oriented languages) or even for specific languages.
- * <p>
- * <strong>Disclaimer:</strong> experimental interface under development.
  *
  * @see Probe
  */
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SyntaxTag.java	Wed Mar 04 12:17:46 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SyntaxTag.java	Wed Mar 04 16:38:36 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -34,8 +34,6 @@
  * and should not be visible to guest language programmers. Nodes may also have more than one tag,
  * for example a variable assignment that is also a statement. Finally, the assignment of tags to
  * nodes could depending on the use-case of whatever tool is using them.
- * <p>
- * <strong>Disclaimer:</strong> experimental interface under development.
  *
  * @see Probe
  * @see StandardSyntaxTag
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SyntaxTagTrap.java	Wed Mar 04 12:17:46 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SyntaxTagTrap.java	Wed Mar 04 16:38:36 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -29,6 +29,8 @@
 
 /**
  * A trap that can be set to interrupt execution at probed nodes carrying a specific tag.
+ *
+ * @see Probe
  */
 public abstract class SyntaxTagTrap {
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SyntaxTagged.java	Wed Mar 04 12:17:46 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SyntaxTagged.java	Wed Mar 04 16:38:36 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 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
@@ -29,8 +29,6 @@
 /**
  * Information about a guest language program element in a Truffle AST that can be marked as
  * belonging to 0 or more {@linkplain SyntaxTag tags}.
- * <p>
- * <strong>Disclaimer:</strong> experimental interface under development.
  */
 public interface SyntaxTagged {
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java	Wed Mar 04 12:17:46 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java	Wed Mar 04 16:38:36 2015 -0800
@@ -29,6 +29,8 @@
 import java.net.*;
 import java.util.*;
 
+import com.oracle.truffle.api.instrument.*;
+
 /**
  * Representation of a guest language source code unit and its contents. Sources originate in
  * several ways:
@@ -66,17 +68,28 @@
  * <li>Any access to file contents via the cache will result in a timestamp check and possible cache
  * reload.</li>
  * </ol>
+ * <p>
+ *
+ * @see SourceTag
+ * @see SourceListener
  */
 public abstract class Source {
 
     // TODO (mlvdv) consider canonicalizing and reusing SourceSection instances
     // TOOD (mlvdv) connect SourceSections into a spatial tree for fast geometric lookup
 
+    /**
+     * All Sources that have been created.
+     */
+    private static final List<WeakReference<Source>> allSources = new ArrayList<>();
+
     // Files and pseudo files are indexed.
     private static final Map<String, WeakReference<Source>> filePathToSource = new Hashtable<>();
 
     private static boolean fileCacheEnabled = true;
 
+    private static final List<SourceListener> sourceListeners = new ArrayList<>();
+
     /**
      * Gets the canonical representation of a source file, whose contents will be read lazily and
      * then cached.
@@ -106,6 +119,7 @@
         if (reset) {
             source.reset();
         }
+        notifyNewSource(source).tagAs(StandardSourceTag.FROM_FILE);
         return source;
     }
 
@@ -147,6 +161,7 @@
                 filePathToSource.put(path, new WeakReference<>(source));
             }
         }
+        notifyNewSource(source).tagAs(StandardSourceTag.FROM_FILE);
         return source;
     }
 
@@ -160,7 +175,9 @@
      */
     public static Source fromText(CharSequence chars, String description) {
         assert chars != null;
-        return new LiteralSource(description, chars.toString());
+        final LiteralSource source = new LiteralSource(description, chars.toString());
+        notifyNewSource(source).tagAs(StandardSourceTag.FROM_LITERAL);
+        return source;
     }
 
     /**
@@ -172,7 +189,9 @@
      * @throws IOException if reading fails
      */
     public static Source fromURL(URL url, String description) throws IOException {
-        return URLSource.get(url, description);
+        final URLSource source = URLSource.get(url, description);
+        notifyNewSource(source).tagAs(StandardSourceTag.FROM_URL);
+        return source;
     }
 
     /**
@@ -184,7 +203,9 @@
      * @throws IOException if reading fails
      */
     public static Source fromReader(Reader reader, String description) throws IOException {
-        return new LiteralSource(description, read(reader));
+        final LiteralSource source = new LiteralSource(description, read(reader));
+        notifyNewSource(source).tagAs(StandardSourceTag.FROM_READER);
+        return source;
     }
 
     /**
@@ -215,7 +236,9 @@
      * @return a newly created, non-indexed source representation
      */
     public static Source fromBytes(byte[] bytes, int byteIndex, int length, String description, BytesDecoder decoder) {
-        return new BytesSource(description, bytes, byteIndex, length, decoder);
+        final BytesSource source = new BytesSource(description, bytes, byteIndex, length, decoder);
+        notifyNewSource(source).tagAs(StandardSourceTag.FROM_BYTES);
+        return source;
     }
 
     /**
@@ -229,6 +252,7 @@
     public static Source asPseudoFile(CharSequence chars, String pseudoFileName) {
         final Source source = new LiteralSource(pseudoFileName, chars.toString());
         filePathToSource.put(pseudoFileName, new WeakReference<>(source));
+        notifyNewSource(source).tagAs(StandardSourceTag.FROM_LITERAL);
         return source;
     }
 
@@ -241,6 +265,48 @@
         fileCacheEnabled = enabled;
     }
 
+    /**
+     * Returns all {@link Source}s holding a particular {@link SyntaxTag}, or the whole collection
+     * of Sources if the specified tag is {@code null}.
+     *
+     * @return A collection of Sources containing the given tag.
+     */
+    public static Collection<Source> findSourcesTaggedAs(SourceTag tag) {
+        final List<Source> taggedSources = new ArrayList<>();
+        for (WeakReference<Source> ref : allSources) {
+            Source source = ref.get();
+            if (source != null) {
+                if (tag == null || source.isTaggedAs(tag)) {
+                    taggedSources.add(ref.get());
+                }
+            }
+        }
+        return taggedSources;
+    }
+
+    /**
+     * Adds a {@link SourceListener} to receive events.
+     */
+    public static void addSourceListener(SourceListener listener) {
+        assert listener != null;
+        sourceListeners.add(listener);
+    }
+
+    /**
+     * Removes a {@link SourceListener}. Ignored if listener not found.
+     */
+    public static void removeSourceListener(SourceListener listener) {
+        sourceListeners.remove(listener);
+    }
+
+    private static Source notifyNewSource(Source source) {
+        allSources.add(new WeakReference<>(source));
+        for (SourceListener listener : sourceListeners) {
+            listener.sourceCreated(source);
+        }
+        return source;
+    }
+
     private static String read(Reader reader) throws IOException {
         final BufferedReader bufferedReader = new BufferedReader(reader);
         final StringBuilder builder = new StringBuilder();
@@ -257,6 +323,8 @@
         return builder.toString();
     }
 
+    private final ArrayList<SourceTag> tags = new ArrayList<>();
+
     Source() {
     }
 
@@ -264,6 +332,32 @@
 
     protected abstract void reset();
 
+    public final boolean isTaggedAs(SourceTag tag) {
+        assert tag != null;
+        return tags.contains(tag);
+    }
+
+    public final Collection<SourceTag> getSourceTags() {
+        return Collections.unmodifiableCollection(tags);
+    }
+
+    /**
+     * Adds a {@linkplain SourceTag tag} to the set of tags associated with this {@link Source};
+     * {@code no-op} if already in the set.
+     *
+     * @return this
+     */
+    public final Source tagAs(SourceTag tag) {
+        assert tag != null;
+        if (!tags.contains(tag)) {
+            tags.add(tag);
+            for (SourceListener listener : sourceListeners) {
+                listener.sourceTaggedAs(this, tag);
+            }
+        }
+        return this;
+    }
+
     /**
      * Returns the name of this resource holding a guest language program. An example would be the
      * name of a guest language source code file.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceListener.java	Wed Mar 04 16:38:36 2015 -0800
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.source;
+
+/**
+ * An observer of events related to {@link Source}s: creating and tagging.
+ */
+public interface SourceListener {
+
+    /**
+     * Notifies that a new {@link Source} has just been created.
+     */
+    void sourceCreated(Source source);
+
+    /**
+     * Notifies that a {@link SourceTag} has been newly added to the set of tags associated with a
+     * {@link Source} via {@link Source#tagAs(SourceTag)}.
+     * <p>
+     * The {@linkplain SourceTag tags} at a {@link Source} are a <em>set</em>; this notification
+     * will only be delivered the first time a particular {@linkplain SourceTag tag} is added at a
+     * {@link Source}.
+     *
+     * @param source where a tag has been added
+     * @param tag the tag that has been newly added (subsequent additions of the tag are
+     *            unreported).
+     */
+    void sourceTaggedAs(Source source, SourceTag tag);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceTag.java	Wed Mar 04 16:38:36 2015 -0800
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.source;
+
+/**
+ * Categorical information (best implemented as enums} about particular sources of Guest Language
+ * code that can be useful to configure behavior of both the language runtime and external tools.
+ * These might include {@linkplain StandardSourceTag standard tags} noting, for example, whether the
+ * source was read from a file and whether it should be considered library code.
+ * <p>
+ * An untagged {@link Source} should by default be considered application code.
+ * <p>
+ * The need for additional tags is likely to arise, in some cases because of issue specific to a
+ * Guest Language, but also for help configuring the behavior of particular tools.
+ *
+ * @see Source
+ * @see StandardSourceTag
+ */
+public interface SourceTag {
+
+    /**
+     * Human-friendly name of a category of code sources, e.g. "file", or "library".
+     *
+     */
+    String name();
+
+    /**
+     * Criteria and example uses for the tag.
+     */
+    String getDescription();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/StandardSourceTag.java	Wed Mar 04 16:38:36 2015 -0800
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.source;
+
+/**
+ * A general set of "properties" or "categories" that might be usefully attached to a particular
+ * source of code, both for use by the language runtime and by external tools. This set of tags
+ * includes some intended to be applied by default by {@link Source} factory methods or other
+ * services built into the Truffle platform.
+ * <p>
+ * The need for additional tags is likely to arise, in some cases because of issue specific to a
+ * Guest Language, but also for help configuring the behavior of particular tools.
+ *
+ * @see Source
+ */
+public enum StandardSourceTag implements SourceTag {
+
+    /**
+     * Builtin.
+     */
+    BUILTIN("builtin", "implementation of language builtins"),
+
+    /**
+     * From bytes.
+     */
+    FROM_BYTES("bytes", "read from bytes"),
+
+    /**
+     * Read from a file.
+     */
+    FROM_FILE("file", "read from a file"),
+
+    /**
+     * From literal text.
+     */
+    FROM_LITERAL("literal", "from literal text"),
+
+    /**
+     * From a {@linkplain java.io.Reader Reader}.
+     */
+    FROM_READER("reader", "read from a Java Reader"),
+
+    /**
+     * Read from a URL.
+     */
+    FROM_URL("URL", "read from a URL"),
+
+    /**
+     * Treat as LIBRARY code.
+     */
+    LIBRARY("library", "library code");
+
+    private final String name;
+    private final String description;
+
+    private StandardSourceTag(String name, String description) {
+        this.name = name;
+        this.description = description;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+}