# HG changeset patch # User Michael Van De Vanter # Date 1400030913 25200 # Node ID 2d63ce48d22267ca37e68a82fa89706c379520ac # Parent 357e7202de5b24648acf0f767713ddf06a59ecc8 Truffle/Source Attribution: Replace direct creation of SourceSection objects with factory methods on Source; two of these greatly simplify source attribution by automatically computing either the row/column start location from a character offset or vice versa, depending on what?s made available from the parser. Minor API change on Visualizer. diff -r 357e7202de5b -r 2d63ce48d222 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java Mon May 12 21:29:29 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Source.java Tue May 13 18:28:33 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -26,6 +26,8 @@ import java.io.*; +import com.oracle.truffle.api.source.*; + /** * Represents a unit (typically a file) of guest language source code. */ @@ -97,4 +99,61 @@ */ int getLineLength(int lineNumber); + /** + * Creates a representation of a contiguous region of text in the source. Computes the + * {@code (startLine, startColumn)} values by building a {@linkplain TextMap map} of lines in + * the source. + *

+ * Checks the position arguments for consistency with the source. + *

+ * The resulting representation defines hash/equality around equivalent location, presuming that + * {@link Source} representations are cannonical. + * + * + * @param identifier terse description of the region + * @param charIndex 0-based position of the first character in the section + * @param length the number of characters in the section + * @return newly created object representing the specified region + * @throws IllegalArgumentException if either of the arguments are outside the text of the + * source + * @throws IllegalStateException if the source is one of the "null" instances + */ + SourceSection createSection(String identifier, int charIndex, int length) throws IllegalArgumentException, IllegalStateException; + + /** + * Creates a representation of a contiguous region of text in the source. Computes the + * {@code charIndex} value by building a {@linkplain TextMap map} of lines in the source. + *

+ * Checks the position arguments for consistency with the source. + *

+ * The resulting representation defines hash/equality around equivalent location, presuming that + * {@link Source} representations are cannonical. + * + * @param identifier terse description of the region + * @param startLine 1-based line number of the first character in the section + * @param startColumn 1-based column number of the first character in the section + * @param length the number of characters in the section + * @return newly created object representing the specified region + * @throws IllegalArgumentException if arguments are outside the text of the source + * @throws IllegalStateException if the source is one of the "null" instances + */ + SourceSection createSection(String identifier, int startLine, int startColumn, int length); + + /** + * Creates a representation of a contiguous region of text in the source. + *

+ * This method performs no checks on the validity of the arguments. + *

+ * The resulting representation defines hash/equality around equivalent location, presuming that + * {@link Source} representations are cannonical. + * + * @param identifier terse description of the region + * @param startLine 1-based line number of the first character in the section + * @param startColumn 1-based column number of the first character in the section + * @param charIndex the 0-based index of the first character of the section + * @param length the number of characters in the section + * @return newly created object representing the specified region + */ + SourceSection createSection(String identifier, int startLine, int startColumn, int charIndex, int length); + } diff -r 357e7202de5b -r 2d63ce48d222 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java Mon May 12 21:29:29 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/SourceSection.java Tue May 13 18:28:33 2014 -0700 @@ -25,46 +25,62 @@ package com.oracle.truffle.api; /** - * Description of contiguous text section within the source code of a guest language program. + * Description of contiguous section of text within a {@link Source} of program code. + * + * The starting location of the section can be described using two different coordinates: + *

+ * The {@code Newline} that terminates each line counts as a single character for the purpose of a + * character index and when counting the length of text. The {@code (line,column)} coordinates of a + * {@code Newline} should never appear in a text section. + *

+ * If the final character of source is not a {@code Newline}, the final characters of the text are + * still considered to be a line ("unterminated"). + *

+ * + * @see Source#createSection(String, int, int, int, int) + * @see Source#createSection(String, int, int, int) + * @see Source#createSection(String, int, int) */ public interface SourceSection { + // TODO support alternate text representations/encodings + /** - * Returns the object representing the source program that contains this section. + * Representation of the source program that contains this section. * * @return the source object */ Source getSource(); /** - * Returns 1-based line number of the first character in this source section (inclusive). + * Returns 1-based line number of the first character in this section (inclusive). * * @return the starting line number */ int getStartLine(); /** - * Returns the 1-based column number of the first character in this source section (inclusive). + * Returns the 1-based column number of the first character in this section (inclusive). * * @return the starting column number */ int getStartColumn(); /** - * Returns the 0-based index of the first character in this source section. - *

- * The complete text of the source that contains this section can be retrieved via - * {@link Source#getCode()}. + * Returns the 0-based index of the first character in this section. * * @return the starting character index */ int getCharIndex(); /** - * Returns the length of this source section in characters. - *

- * The complete text of the source that contains this section can be retrieved via - * {@link Source#getCode()}. + * Returns the length of this section in characters. * * @return the number of characters in the section */ @@ -79,14 +95,14 @@ int getCharEndIndex(); /** - * Returns the identifier of this source section that is used for printing the section. + * Returns terse text describing this source section, typically used for printing the section. * * @return the identifier of the section */ String getIdentifier(); /** - * Returns text of the code represented by this source section. + * Returns text described by this section. * * @return the code as a String object */ diff -r 357e7202de5b -r 2d63ce48d222 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultSourceSection.java Mon May 12 21:29:29 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2013, 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.impl; - -import com.oracle.truffle.api.*; - -/** - * Represents a contiguous text section within the source code of a guest language program. - */ -public class DefaultSourceSection implements SourceSection { - - private final Source source; - private final String identifier; - private final int startLine; - private final int startColumn; - private final int charIndex; - private final int charLength; - - /** - * Creates a new object representing a contiguous text section within the source code of a guest - * language program's text. - *

- * The starting location of the section is specified using two different coordinate: - *

- * The newline that terminates each line counts as a single character for the purpose of - * a character index. The (row,column) coordinates of a newline character should never appear in - * a text section. - *

- * - * @param source object representing the complete source program that contains this section - * @param identifier an identifier used when printing the section - * @param startLine the 1-based number of the start line of the section - * @param startColumn the 1-based number of the start column of the section - * @param charIndex the 0-based index of the first character of the section - * @param charLength the length of the section in number of characters - */ - public DefaultSourceSection(Source source, String identifier, int startLine, int startColumn, int charIndex, int charLength) { - this.source = source; - this.identifier = identifier; - this.startLine = startLine; - this.startColumn = startColumn; - this.charIndex = charIndex; - this.charLength = charLength; - } - - public final Source getSource() { - return source; - } - - public final int getStartLine() { - return startLine; - } - - public final int getStartColumn() { - return startColumn; - } - - public final int getCharIndex() { - return charIndex; - } - - public final int getCharLength() { - return charLength; - } - - public final int getCharEndIndex() { - return charIndex + charLength; - } - - public final String getIdentifier() { - return identifier; - } - - public final String getCode() { - return getSource().getCode().substring(charIndex, charIndex + charLength); - } - - public final String getShortDescription() { - return String.format("%s:%d", source.getShortName(), startLine); - } - - @Override - public String toString() { - return String.format("%s:%d", source.getName(), startLine); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + charIndex; - result = prime * result + charLength; - result = prime * result + ((identifier == null) ? 0 : identifier.hashCode()); - result = prime * result + ((source == null) ? 0 : source.hashCode()); - result = prime * result + startColumn; - result = prime * result + startLine; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof DefaultSourceSection)) { - return false; - } - DefaultSourceSection other = (DefaultSourceSection) obj; - if (charIndex != other.charIndex) { - return false; - } - if (charLength != other.charLength) { - return false; - } - if (identifier == null) { - if (other.identifier != null) { - return false; - } - } else if (!identifier.equals(other.identifier)) { - return false; - } - if (source == null) { - if (other.source != null) { - return false; - } - } else if (!source.equals(other.source)) { - return false; - } - if (startColumn != other.startColumn) { - return false; - } - if (startLine != other.startLine) { - return false; - } - return true; - } - -} diff -r 357e7202de5b -r 2d63ce48d222 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java Mon May 12 21:29:29 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java Tue May 13 18:28:33 2014 -0700 @@ -61,7 +61,7 @@ /** * Converts a value in the guest language to a display string. */ - String displayValue(Object value); + String displayValue(ExecutionContext context, Object value); /** * Converts a slot identifier in the guest language to a display string. diff -r 357e7202de5b -r 2d63ce48d222 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java Mon May 12 21:29:29 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java Tue May 13 18:28:33 2014 -0700 @@ -69,7 +69,7 @@ return callTarget.toString(); } - public String displayValue(Object value) { + public String displayValue(ExecutionContext context, Object value) { return value.toString(); } diff -r 357e7202de5b -r 2d63ce48d222 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java Mon May 12 21:29:29 2014 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java Tue May 13 18:28:33 2014 -0700 @@ -199,6 +199,32 @@ return checkTextMap().lineLength(lineNumber); } + public final SourceSection createSection(String identifier, int startOffset, int sectionLength) throws IllegalArgumentException { + final int codeLength = getCode().length(); + if (!(startOffset >= 0 && sectionLength >= 0 && startOffset + sectionLength <= codeLength)) { + throw new IllegalArgumentException("text positions out of range"); + } + checkTextMap(); + final int startLine = getLineNumber(startOffset); + final int startColumn = startOffset - getLineStartOffset(startLine) + 1; + + return new SourceSectionImpl(this, identifier, startLine, startColumn, startOffset, sectionLength); + } + + public SourceSection createSection(String identifier, int startLine, int startColumn, int sectionLength) { + checkTextMap(); + final int lineStartOffset = textMap.lineStartOffset(startLine); + if (startColumn > textMap.lineLength(startLine)) { + throw new IllegalArgumentException("column out of range"); + } + final int startOffset = lineStartOffset + startColumn - 1; + return new SourceSectionImpl(this, identifier, startLine, startColumn, startOffset, sectionLength); + } + + public SourceSection createSection(String identifier, int startLine, int startColumn, int charIndex, int length) { + return new SourceSectionImpl(this, identifier, startLine, startColumn, charIndex, length); + } + private TextMap checkTextMap() { if (textMap == null) { final String code = getCode(); @@ -211,7 +237,7 @@ } } - public static class LiteralSourceImpl extends SourceImpl { + private static class LiteralSourceImpl extends SourceImpl { private final String name; // Name used originally to describe the source private final String code; @@ -337,4 +363,142 @@ } + private static class SourceSectionImpl implements SourceSection { + + private final Source source; + private final String identifier; + private final int startLine; + private final int startColumn; + private final int charIndex; + private final int charLength; + + /** + * Creates a new object representing a contiguous text section within the source code of a + * guest language program's text. + *

+ * The starting location of the section is specified using two different coordinate: + *

+ * The newline that terminates each line counts as a single character for the purpose + * of a character index. The (row,column) coordinates of a newline character should never + * appear in a text section. + *

+ * + * @param source object representing the complete source program that contains this section + * @param identifier an identifier used when printing the section + * @param startLine the 1-based number of the start line of the section + * @param startColumn the 1-based number of the start column of the section + * @param charIndex the 0-based index of the first character of the section + * @param charLength the length of the section in number of characters + */ + public SourceSectionImpl(Source source, String identifier, int startLine, int startColumn, int charIndex, int charLength) { + this.source = source; + this.identifier = identifier; + this.startLine = startLine; + this.startColumn = startColumn; + this.charIndex = charIndex; + this.charLength = charLength; + } + + public final Source getSource() { + return source; + } + + public final int getStartLine() { + return startLine; + } + + public final int getStartColumn() { + return startColumn; + } + + public final int getCharIndex() { + return charIndex; + } + + public final int getCharLength() { + return charLength; + } + + public final int getCharEndIndex() { + return charIndex + charLength; + } + + public final String getIdentifier() { + return identifier; + } + + public final String getCode() { + return getSource().getCode().substring(charIndex, charIndex + charLength); + } + + public final String getShortDescription() { + return String.format("%s:%d", source.getShortName(), startLine); + } + + @Override + public String toString() { + return String.format("%s:%d", source.getName(), startLine); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + charIndex; + result = prime * result + charLength; + result = prime * result + ((identifier == null) ? 0 : identifier.hashCode()); + result = prime * result + ((source == null) ? 0 : source.hashCode()); + result = prime * result + startColumn; + result = prime * result + startLine; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof SourceSectionImpl)) { + return false; + } + SourceSectionImpl other = (SourceSectionImpl) obj; + if (charIndex != other.charIndex) { + return false; + } + if (charLength != other.charLength) { + return false; + } + if (identifier == null) { + if (other.identifier != null) { + return false; + } + } else if (!identifier.equals(other.identifier)) { + return false; + } + if (source == null) { + if (other.source != null) { + return false; + } + } else if (!source.equals(other.source)) { + return false; + } + if (startColumn != other.startColumn) { + return false; + } + if (startLine != other.startLine) { + return false; + } + return true; + } + + } + }