Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(79)

Unified Diff: editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/ui/internal/text/functions/FastDartPartitionScanner.java

Issue 9704033: Fix two bugs in syntax highlighting (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/ui/internal/text/functions/FastDartPartitionScanner.java
===================================================================
--- editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/ui/internal/text/functions/FastDartPartitionScanner.java (revision 5470)
+++ editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/ui/internal/text/functions/FastDartPartitionScanner.java (working copy)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, the Dart project authors.
+ * Copyright (c) 2012, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@@ -26,6 +26,10 @@
* multi-line strings, in addition to the default.
*/
public class FastDartPartitionScanner implements IPartitionTokenScanner, DartPartitions {
+ /**
+ * Values of the enumeration <code>ScannerState</code> represent the states that the scanner can
+ * be in. The scanner is essentially a state machine with these states.
+ */
private enum ScannerState {
//
// Final states corresponding to partitions.
@@ -115,6 +119,64 @@
}
}
+ /**
+ * Instances of the class <code>TokenData</code> represent a single token that was scanned. The
+ * scanner scans all of the tokens, creating a linked list of tokens to be returned by
+ * {@link FastDartPartitionScanner#nextToken()}.
+ */
+ private static class TokenData {
+ /**
+ * Create a new token that comes after the given token in the linked list with the given
+ * information.
+ *
+ * @param previous the token before the new token in the linked list
+ * @param token the token being added to the list
+ * @param tokenOffset the offset of the token in the source
+ * @param tokenLength the length of the token
+ * @return the token that was created
+ */
+ public static TokenData following(TokenData previous, IToken token, int tokenOffset,
+ int tokenLength) {
+ TokenData data = new TokenData(token, tokenOffset, tokenLength);
+ previous.next = data;
+ return data;
+ }
+
+ /**
+ * The token value being represented.
+ */
+ private IToken token;
+
+ /**
+ * The offset of the token in the source.
+ */
+ private int tokenOffset;
+
+ /**
+ * The length of the token.
+ */
+ private int tokenLength;
+
+ /**
+ * The data for the token following this token.
+ */
+ private TokenData next;
+
+ /**
+ * Initialize a newly created node in the linked list of token data to store the information
+ * associated with the given token.
+ *
+ * @param token the token being represented by this node
+ * @param tokenOffset the offset of the token in the source
+ * @param tokenLength the length of the token
+ */
+ public TokenData(IToken token, int tokenOffset, int tokenLength) {
+ this.token = token;
+ this.tokenOffset = tokenOffset;
+ this.tokenLength = tokenLength;
+ }
+ }
+
private static IToken CODE_TOKEN = new Token(null);
private static IToken SINGLE_LINE_COMMENT_TOKEN = new Token(DART_SINGLE_LINE_COMMENT);
private static IToken MULTI_LINE_COMMENT_TOKEN = new Token(DART_MULTI_LINE_COMMENT);
@@ -183,30 +245,161 @@
*/
private int commentDepth = 0;
+ /**
+ * The head of the linked list, which always points to the data for the token that was last
+ * returned.
+ */
+ private TokenData currentToken;
+
+ /**
+ * A flag used to determine whether debugging output should be produced.
+ */
+ private static final boolean DEBUG = false;
+
+ /**
+ * Initialize a newly created scanner.
+ */
public FastDartPartitionScanner() {
- // create the scanner
+ super();
}
@Override
public int getTokenLength() {
- return tokenLength;
+ return currentToken.tokenLength;
}
@Override
public int getTokenOffset() {
- return tokenOffset;
+ return currentToken.tokenOffset;
}
@Override
public IToken nextToken() {
- // Uncomment the code below for debugging output.
-// IToken result = nextToken_internal();
-// System.out.println(tokenOffset + " - " + (tokenOffset + tokenLength - 1) + " (" + tokenLength
-// + ") : " + result.getData());
-// return result;
-// }
-//
-// public IToken nextToken_internal() {
+ currentToken = currentToken.next;
+ if (DEBUG) {
+ System.out.println(" " + currentToken.tokenOffset + " - "
+ + (currentToken.tokenOffset + currentToken.tokenLength - 1) + " ("
+ + currentToken.tokenLength + ") : " + currentToken.token.getData());
+ }
+ return currentToken.token;
+ }
+
+ @Override
+ public void setPartialRange(IDocument document, int offset, int length, String contentType,
+ int partitionOffset) {
+ if (DEBUG) {
+ System.out.println("setPartialRange(?, " + offset + ", " + length + ", " + contentType + ", "
+ + partitionOffset + ")");
+ }
+ // Scan a multi-line string from the beginning, so that the active string delimiter gets set.
+ if (contentType != null && contentType.equals(DART_MULTI_LINE_STRING)) {
+ length += offset - partitionOffset;
+ offset = partitionOffset;
+ }
+ setRange(document, offset, length);
+ }
+
+ @Override
+ public void setRange(IDocument document, int offset, int length) {
+ commentDepth = 0;
+ scanner.setRange(document, 0, document.getLength());
+ tokenOffset = 0;
+ tokenLength = 0;
+ prefixLength = 0;
+ scannerState = ScannerState.CODE;
+ stringState = null;
+ currentToken = buildData();
+ trimTokenData(offset, length);
+ }
+
+ /**
+ * Advance to the next character in the input.
+ */
+ private void advance() {
+ tokenLength++;
+ scanner.read();
+ }
+
+ /**
+ * Build the linked list of tokens representing the content of the entire document.
+ *
+ * @return a fake token that is logically the last token returned before any tokens have actually
+ * been returned
+ */
+ private TokenData buildData() {
+ if (DEBUG) {
+ System.out.println(" buildData()");
+ }
+ //
+ // Create a fake token so that the first invocation of nextToken() will return the real first
+ // token.
+ //
+ TokenData head = new TokenData(Token.UNDEFINED, 0, 0);
+ TokenData current = head;
+ while (current.token != Token.EOF) {
+ current = TokenData.following(current, parseToken(), tokenOffset, tokenLength);
+ }
+ current.next = current;
+ return head;
+ }
+
+ /**
+ * Return the code-like scanner state to which the scanner should return at the end of the current
+ * state. This can either be {@link ScannerState#CODE} or {@link ScannerState#BLOCK_INTERPOLATION}
+ * , depending on whether the scanner is currently within a multi-line string.
+ *
+ * @return the code-like scanner state to which the scanner should return
+ */
+ private ScannerState getCodeLikeState() {
+ if (stringState == null) {
+ return ScannerState.CODE;
+ } else {
+ return ScannerState.BLOCK_INTERPOLATION;
+ }
+ }
+
+ /**
+ * Return <code>true</code> if the given character is an end-of-line character.
+ *
+ * @param character the character being tested
+ * @return <code>true</code> if the given character is an end-of-line character
+ */
+ private boolean isEol(int character) {
+ return character == '\r' || character == '\n' || character == '\u2028' || character == '\u2029';
+ }
+
+ /**
+ * Return <code>true</code> if the given character is a valid character within an identifier.
+ *
+ * @param character the character being tested
+ * @return <code>true</code> if the given character is a valid character within an identifier
+ */
+ private boolean isIdentifierChar(int character) {
+ return (character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z')
+ || (character >= '0' && character <= '9') || character == '_';
+ }
+
+ /**
+ * Parse a single token from the input.
+ *
+ * @return the token that was parsed
+ */
+ private IToken parseToken() {
+ IToken result = parseToken_internal();
+ if (DEBUG) {
+ System.out.println(" " + tokenOffset + " - " + (tokenOffset + tokenLength - 1) + " ("
+ + tokenLength + ") : " + result.getData());
+ }
+ return result;
+ }
+
+ /**
+ * Parse a single token from the input. This helper method exists so that debugging output can be
+ * produced in a single location.
+ *
+ * @return the token that was parsed
+ */
+ private IToken parseToken_internal() {
tokenOffset += tokenLength;
tokenLength = prefixLength;
prefixLength = 0;
@@ -297,7 +490,7 @@
stringState = stringState.previous;
scannerState = getCodeLikeState();
return ScannerState.STRING.token;
- } else if (currentChar == '\\') {
+ } else if (!stringState.raw && currentChar == '\\') {
advance();
advance();
} else if (!stringState.raw && currentChar == '$') {
@@ -451,70 +644,46 @@
return Token.EOF;
}
- @Override
- public void setPartialRange(IDocument document, int offset, int length, String contentType,
- int partitionOffset) {
- // Scan a multi-line string from the beginning, so that the active string delimiter gets set.
- if (contentType != null && contentType.equals(DART_MULTI_LINE_STRING)) {
- length += offset - partitionOffset;
- offset = partitionOffset;
- }
- commentDepth = 0;
- scanner.setRange(document, offset, length);
- tokenOffset = partitionOffset;
- tokenLength = 0;
- prefixLength = offset - partitionOffset;
-
- if (offset == partitionOffset) {
- // restart at beginning of partition
- scannerState = ScannerState.CODE;
- } else {
- scannerState = getState(contentType);
- if (scannerState == ScannerState.MULTI_LINE_COMMENT
- || scannerState == ScannerState.DOC_COMMENT) {
- commentDepth++;
- }
- }
- stringState = null;
- }
-
- @Override
- public void setRange(IDocument document, int offset, int length) {
- commentDepth = 0;
- scanner.setRange(document, offset, length);
- tokenOffset = offset;
- tokenLength = 0;
- prefixLength = 0;
- scannerState = ScannerState.CODE;
- stringState = null;
- }
-
- private void advance() {
- tokenLength++;
- scanner.read();
- }
-
/**
- * Return the code-like scanner state to which the scanner should return at the end of the current
- * state. This can either be {@link ScannerState#CODE} or {@link ScannerState#BLOCK_INTERPOLATION}
- * , depending on whether the scanner is currently within a multi-line string.
+ * Adjust the linked list of tokens so that only those that encompass the given range of
+ * characters will be returned.
*
- * @return the code-like scanner state to which the scanner should return
+ * @param offset the offset of the first character to be included in a token
+ * @param length the number of characters to be included in tokens
*/
- private ScannerState getCodeLikeState() {
- if (stringState == null) {
- return ScannerState.CODE;
- } else {
- return ScannerState.BLOCK_INTERPOLATION;
+ private void trimTokenData(int offset, int length) {
+ //
+ // Skip over any tokens that should not be returned. currentToken is assumed to be the fake
+ // token created before the first real token.
+ //
+ TokenData nextToken = currentToken.next;
+ while (nextToken != nextToken.next && nextToken.next.tokenOffset <= offset) {
+ nextToken = nextToken.next;
}
+ currentToken.next = nextToken;
+ //
+ // Fix the token offset of the first token to match the requested offset.
+ //
+ TokenData firstToken = currentToken.next;
+ if (firstToken.tokenOffset < offset) {
+ firstToken.tokenLength = firstToken.tokenLength - (offset - firstToken.tokenOffset);
+ firstToken.tokenOffset = offset;
+ }
+ //
+ // Trim the tail of the list to cover only the requested length.
+ //
+ int totalLength = nextToken.tokenLength;
+ while (nextToken != nextToken.next && totalLength < length) {
+ nextToken = nextToken.next;
+ totalLength += nextToken.tokenLength;
+ }
+ if (totalLength > length) {
+ nextToken.tokenLength = nextToken.tokenLength - (tokenLength - length);
+ TokenData lastToken = nextToken.next;
+ while (lastToken != lastToken.next) {
+ lastToken = lastToken.next;
+ }
+ nextToken.next = lastToken;
+ }
}
-
- private boolean isEol(int character) {
- return character == '\r' || character == '\n' || character == '\u2028' || character == '\u2029';
- }
-
- private boolean isIdentifierChar(int character) {
- return (character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z')
- || (character >= '0' && character <= '9') || character == '_';
- }
}
« no previous file with comments | « no previous file | editor/tools/plugins/com.google.dart.tools.ui_test/src/com/google/dart/tools/ui/internal/text/functions/FastDartPartitionScannerTest.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698