Mercurial > hg > graal-jvmci-8
comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java @ 16130:6f7d3f3703d3
Truffle/Source:
- LineLocation and LineBreakpoint no longer implement Comparable
- TextMap now internal to the Source factory
author | Michael Van De Vanter <michael.van.de.vanter@oracle.com> |
---|---|
date | Mon, 16 Jun 2014 20:52:06 -0700 |
parents | 74e142bd2b12 |
children | 7109baa7b9eb |
comparison
equal
deleted
inserted
replaced
16113:a3a9d703c078 | 16130:6f7d3f3703d3 |
---|---|
192 } | 192 } |
193 | 193 |
194 return builder.toString(); | 194 return builder.toString(); |
195 } | 195 } |
196 | 196 |
197 protected Source() { | 197 Source() { |
198 } | 198 } |
199 | 199 |
200 protected TextMap textMap = null; | 200 private TextMap textMap = null; |
201 | 201 |
202 protected abstract void reset(); | 202 protected abstract void reset(); |
203 | 203 |
204 /** | 204 /** |
205 * Returns the name of this resource holding a guest language program. An example would be the | 205 * Returns the name of this resource holding a guest language program. An example would be the |
264 } | 264 } |
265 | 265 |
266 /** | 266 /** |
267 * Given a 0-based character offset, return the 1-based number of the line that includes the | 267 * Given a 0-based character offset, return the 1-based number of the line that includes the |
268 * position. | 268 * position. |
269 */ | 269 * |
270 public final int getLineNumber(int offset) { | 270 * @throws IllegalArgumentException if the offset is outside the text contents |
271 */ | |
272 public final int getLineNumber(int offset) throws IllegalArgumentException { | |
271 return checkTextMap().offsetToLine(offset); | 273 return checkTextMap().offsetToLine(offset); |
272 } | 274 } |
273 | 275 |
274 /** | 276 /** |
277 * Given a 0-based character offset, return the 1-based number of the column at the position. | |
278 * | |
279 * @throws IllegalArgumentException if the offset is outside the text contents | |
280 */ | |
281 public final int getColumnNumber(int offset) throws IllegalArgumentException { | |
282 return checkTextMap().offsetToCol(offset); | |
283 } | |
284 | |
285 /** | |
275 * Given a 1-based line number, return the 0-based offset of the first character in the line. | 286 * Given a 1-based line number, return the 0-based offset of the first character in the line. |
276 */ | 287 * |
277 public final int getLineStartOffset(int lineNumber) { | 288 * @throws IllegalArgumentException if there is no such line in the text |
289 */ | |
290 public final int getLineStartOffset(int lineNumber) throws IllegalArgumentException { | |
278 return checkTextMap().lineStartOffset(lineNumber); | 291 return checkTextMap().lineStartOffset(lineNumber); |
279 } | 292 } |
280 | 293 |
281 /** | 294 /** |
282 * The number of characters (not counting a possible terminating newline) in a (1-based) | 295 * The number of characters (not counting a possible terminating newline) in a (1-based) |
283 * numbered line. | 296 * numbered line. |
284 */ | 297 * |
285 public final int getLineLength(int lineNumber) { | 298 * @throws IllegalArgumentException if there is no such line in the text |
299 */ | |
300 public final int getLineLength(int lineNumber) throws IllegalArgumentException { | |
286 return checkTextMap().lineLength(lineNumber); | 301 return checkTextMap().lineLength(lineNumber); |
287 } | 302 } |
288 | 303 |
289 /** | 304 /** |
290 * Creates a representation of a contiguous region of text in the source. | 305 * Creates a representation of a contiguous region of text in the source. |
807 return false; | 822 return false; |
808 } | 823 } |
809 return source.equals(other.source); | 824 return source.equals(other.source); |
810 } | 825 } |
811 | 826 |
812 @Override | 827 } |
813 public int compareTo(Object o) { | 828 |
814 final LineLocationImpl other = (LineLocationImpl) o; | 829 /** |
815 final int nameOrder = source.getName().compareTo(other.source.getName()); | 830 * A utility for converting between coordinate systems in a string of text interspersed with |
816 if (nameOrder != 0) { | 831 * newline characters. The coordinate systems are: |
817 return nameOrder; | 832 * <ul> |
818 } | 833 * <li>0-based character offset from the beginning of the text, where newline characters count |
819 return Integer.compare(line, other.line); | 834 * as a single character and the first character in the text occupies position 0.</li> |
820 } | 835 * <li>1-based position in the 2D space of lines and columns, in which the first position in the |
821 | 836 * text is at (1,1).</li> |
822 } | 837 * </ul> |
838 * <p> | |
839 * This utility is based on positions occupied by characters, not text stream positions as in a | |
840 * text editor. The distinction shows up in editors where you can put the cursor just past the | |
841 * last character in a buffer; this is necessary, among other reasons, so that you can put the | |
842 * edit cursor in a new (empty) buffer. For the purposes of this utility, however, there are no | |
843 * character positions in an empty text string and there are no lines in an empty text string. | |
844 * <p> | |
845 * A newline character designates the end of a line and occupies a column position. | |
846 * <p> | |
847 * If the text ends with a character other than a newline, then the characters following the | |
848 * final newline character count as a line, even though not newline-terminated. | |
849 * <p> | |
850 * <strong>Limitations:</strong> | |
851 * <ul> | |
852 * <li>Does not handle multiple character encodings correctly.</li> | |
853 * <li>Treats tabs as occupying 1 column.</li> | |
854 * <li>Does not handle multiple-character line termination sequences correctly.</li> | |
855 * </ul> | |
856 */ | |
857 private static final class TextMap { | |
858 | |
859 // 0-based offsets of newline characters in the text, with sentinel | |
860 private final int[] nlOffsets; | |
861 | |
862 // The number of characters in the text, including newlines (which count as 1). | |
863 private final int textLength; | |
864 | |
865 // Is the final text character a newline? | |
866 final boolean finalNL; | |
867 | |
868 /** | |
869 * Constructs map permitting translation between 0-based character offsets and 1-based | |
870 * lines/columns. | |
871 */ | |
872 public TextMap(String text) { | |
873 this.textLength = text.length(); | |
874 final ArrayList<Integer> lines = new ArrayList<>(); | |
875 lines.add(0); | |
876 int offset = 0; | |
877 | |
878 while (offset < text.length()) { | |
879 final int nlIndex = text.indexOf('\n', offset); | |
880 if (nlIndex >= 0) { | |
881 offset = nlIndex + 1; | |
882 lines.add(offset); | |
883 } else { | |
884 break; | |
885 } | |
886 } | |
887 lines.add(Integer.MAX_VALUE); | |
888 | |
889 nlOffsets = new int[lines.size()]; | |
890 for (int line = 0; line < lines.size(); line++) { | |
891 nlOffsets[line] = lines.get(line); | |
892 } | |
893 | |
894 finalNL = textLength > 0 && (textLength == nlOffsets[nlOffsets.length - 2]); | |
895 } | |
896 | |
897 /** | |
898 * Converts 0-based character offset to 1-based number of the line containing the character. | |
899 * | |
900 * @throws IllegalArgumentException if the offset is outside the string. | |
901 */ | |
902 public int offsetToLine(int offset) throws IllegalArgumentException { | |
903 if (offset < 0 || offset >= textLength) { | |
904 throw new IllegalArgumentException("offset out of bounds"); | |
905 } | |
906 int line = 1; | |
907 while (offset >= nlOffsets[line]) { | |
908 line++; | |
909 } | |
910 return line; | |
911 } | |
912 | |
913 /** | |
914 * Converts 0-based character offset to 1-based number of the column occupied by the | |
915 * character. | |
916 * <p> | |
917 * Tabs are not expanded; they occupy 1 column. | |
918 * | |
919 * @throws IllegalArgumentException if the offset is outside the string. | |
920 */ | |
921 public int offsetToCol(int offset) throws IllegalArgumentException { | |
922 return 1 + offset - nlOffsets[offsetToLine(offset) - 1]; | |
923 } | |
924 | |
925 /** | |
926 * The number of lines in the text; if characters appear after the final newline, then they | |
927 * also count as a line, even though not newline-terminated. | |
928 */ | |
929 public int lineCount() { | |
930 if (textLength == 0) { | |
931 return 0; | |
932 } | |
933 return finalNL ? nlOffsets.length - 2 : nlOffsets.length - 1; | |
934 } | |
935 | |
936 /** | |
937 * Converts 1-based line number to the 0-based offset of the line's first character; this | |
938 * would be the offset of a newline if the line is empty. | |
939 * | |
940 * @throws IllegalArgumentException if there is no such line in the text. | |
941 */ | |
942 public int lineStartOffset(int line) throws IllegalArgumentException { | |
943 if (textLength == 0 || lineOutOfRange(line)) { | |
944 throw new IllegalArgumentException("line out of bounds"); | |
945 } | |
946 return nlOffsets[line - 1]; | |
947 } | |
948 | |
949 /** | |
950 * Gets the number of characters in a line, identified by 1-based line number; | |
951 * <em>does not</em> include the final newline, if any. | |
952 * | |
953 * @throws IllegalArgumentException if there is no such line in the text. | |
954 */ | |
955 public int lineLength(int line) throws IllegalArgumentException { | |
956 if (textLength == 0 || lineOutOfRange(line)) { | |
957 throw new IllegalArgumentException("line out of bounds"); | |
958 } | |
959 if (line == nlOffsets.length - 1 && !finalNL) { | |
960 return textLength - nlOffsets[line - 1]; | |
961 } | |
962 return (nlOffsets[line] - nlOffsets[line - 1]) - 1; | |
963 | |
964 } | |
965 | |
966 /** | |
967 * Is the line number out of range. | |
968 */ | |
969 private boolean lineOutOfRange(int line) { | |
970 return line <= 0 || line >= nlOffsets.length || (line == nlOffsets.length - 1 && finalNL); | |
971 } | |
972 | |
973 } | |
974 | |
823 } | 975 } |