# HG changeset patch # User Michael Van De Vanter # Date 1425515916 28800 # Node ID 32b4b06b6fac55939e943f621acbf954e66ce411 # Parent 191c55f08ed2d55e586f9a91b909dd28786a71f5# Parent 5d2309d32463f4c857d55e3233e8366f7b4d6feb Merge with 5d2309d32463f4c857d55e3233e8366f7b4d6feb diff -r 5d2309d32463 -r 32b4b06b6fac graal/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/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); + + } +} diff -r 5d2309d32463 -r 32b4b06b6fac graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java --- 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 { diff -r 5d2309d32463 -r 32b4b06b6fac graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardSyntaxTag.java --- 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 @@ *

* 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. - *

- * Disclaimer: experimental interface under development. * * @see Probe */ diff -r 5d2309d32463 -r 32b4b06b6fac graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SyntaxTag.java --- 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. - *

- * Disclaimer: experimental interface under development. * * @see Probe * @see StandardSyntaxTag diff -r 5d2309d32463 -r 32b4b06b6fac graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SyntaxTagTrap.java --- 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 { diff -r 5d2309d32463 -r 32b4b06b6fac graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/SyntaxTagged.java --- 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}. - *

- * Disclaimer: experimental interface under development. */ public interface SyntaxTagged { diff -r 5d2309d32463 -r 32b4b06b6fac graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java --- 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 @@ *

  • Any access to file contents via the cache will result in a timestamp check and possible cache * reload.
  • * + *

    + * + * @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> allSources = new ArrayList<>(); + // Files and pseudo files are indexed. private static final Map> filePathToSource = new Hashtable<>(); private static boolean fileCacheEnabled = true; + private static final List 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 findSourcesTaggedAs(SourceTag tag) { + final List taggedSources = new ArrayList<>(); + for (WeakReference 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 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 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. diff -r 5d2309d32463 -r 32b4b06b6fac graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceListener.java --- /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)}. + *

    + * The {@linkplain SourceTag tags} at a {@link Source} are a set; 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); + +} diff -r 5d2309d32463 -r 32b4b06b6fac graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceTag.java --- /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. + *

    + * An untagged {@link Source} should by default be considered application code. + *

    + * 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(); +} diff -r 5d2309d32463 -r 32b4b06b6fac graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/StandardSourceTag.java --- /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. + *

    + * 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; + } + +}