Index: third_party/closure_linter/closure_linter/tokenutil.py |
diff --git a/third_party/closure_linter/closure_linter/tokenutil.py b/third_party/closure_linter/closure_linter/tokenutil.py |
deleted file mode 100755 |
index dedf5aaac4b32f6775cf338949ab2b0d30c52f85..0000000000000000000000000000000000000000 |
--- a/third_party/closure_linter/closure_linter/tokenutil.py |
+++ /dev/null |
@@ -1,698 +0,0 @@ |
-#!/usr/bin/env python |
-# |
-# Copyright 2007 The Closure Linter Authors. All Rights Reserved. |
-# |
-# Licensed under the Apache License, Version 2.0 (the "License"); |
-# you may not use this file except in compliance with the License. |
-# You may obtain a copy of the License at |
-# |
-# http://www.apache.org/licenses/LICENSE-2.0 |
-# |
-# Unless required by applicable law or agreed to in writing, software |
-# distributed under the License is distributed on an "AS-IS" BASIS, |
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
-# See the License for the specific language governing permissions and |
-# limitations under the License. |
- |
-"""Token utility functions.""" |
- |
-__author__ = ('robbyw@google.com (Robert Walker)', |
- 'ajp@google.com (Andy Perelson)') |
- |
-import copy |
-import StringIO |
- |
-from closure_linter.common import tokens |
-from closure_linter.javascripttokens import JavaScriptToken |
-from closure_linter.javascripttokens import JavaScriptTokenType |
- |
-# Shorthand |
-Type = tokens.TokenType |
- |
- |
-def GetFirstTokenInSameLine(token): |
- """Returns the first token in the same line as token. |
- |
- Args: |
- token: Any token in the line. |
- |
- Returns: |
- The first token in the same line as token. |
- """ |
- while not token.IsFirstInLine(): |
- token = token.previous |
- return token |
- |
- |
-def GetFirstTokenInPreviousLine(token): |
- """Returns the first token in the previous line as token. |
- |
- Args: |
- token: Any token in the line. |
- |
- Returns: |
- The first token in the previous line as token, or None if token is on the |
- first line. |
- """ |
- first_in_line = GetFirstTokenInSameLine(token) |
- if first_in_line.previous: |
- return GetFirstTokenInSameLine(first_in_line.previous) |
- |
- return None |
- |
- |
-def GetLastTokenInSameLine(token): |
- """Returns the last token in the same line as token. |
- |
- Args: |
- token: Any token in the line. |
- |
- Returns: |
- The last token in the same line as token. |
- """ |
- while not token.IsLastInLine(): |
- token = token.next |
- return token |
- |
- |
-def GetAllTokensInSameLine(token): |
- """Returns all tokens in the same line as the given token. |
- |
- Args: |
- token: Any token in the line. |
- |
- Returns: |
- All tokens on the same line as the given token. |
- """ |
- first_token = GetFirstTokenInSameLine(token) |
- last_token = GetLastTokenInSameLine(token) |
- |
- tokens_in_line = [] |
- while first_token != last_token: |
- tokens_in_line.append(first_token) |
- first_token = first_token.next |
- tokens_in_line.append(last_token) |
- |
- return tokens_in_line |
- |
- |
-def CustomSearch(start_token, func, end_func=None, distance=None, |
- reverse=False): |
- """Returns the first token where func is True within distance of this token. |
- |
- Args: |
- start_token: The token to start searching from |
- func: The function to call to test a token for applicability |
- end_func: The function to call to test a token to determine whether to abort |
- the search. |
- distance: The number of tokens to look through before failing search. Must |
- be positive. If unspecified, will search until the end of the token |
- chain |
- reverse: When true, search the tokens before this one instead of the tokens |
- after it |
- |
- Returns: |
- The first token matching func within distance of this token, or None if no |
- such token is found. |
- """ |
- token = start_token |
- if reverse: |
- while token and (distance is None or distance > 0): |
- previous = token.previous |
- if previous: |
- if func(previous): |
- return previous |
- if end_func and end_func(previous): |
- return None |
- |
- token = previous |
- if distance is not None: |
- distance -= 1 |
- |
- else: |
- while token and (distance is None or distance > 0): |
- next_token = token.next |
- if next_token: |
- if func(next_token): |
- return next_token |
- if end_func and end_func(next_token): |
- return None |
- |
- token = next_token |
- if distance is not None: |
- distance -= 1 |
- |
- return None |
- |
- |
-def Search(start_token, token_types, distance=None, reverse=False): |
- """Returns the first token of type in token_types within distance. |
- |
- Args: |
- start_token: The token to start searching from |
- token_types: The allowable types of the token being searched for |
- distance: The number of tokens to look through before failing search. Must |
- be positive. If unspecified, will search until the end of the token |
- chain |
- reverse: When true, search the tokens before this one instead of the tokens |
- after it |
- |
- Returns: |
- The first token of any type in token_types within distance of this token, or |
- None if no such token is found. |
- """ |
- return CustomSearch(start_token, lambda token: token.IsAnyType(token_types), |
- None, distance, reverse) |
- |
- |
-def SearchExcept(start_token, token_types, distance=None, reverse=False): |
- """Returns the first token not of any type in token_types within distance. |
- |
- Args: |
- start_token: The token to start searching from |
- token_types: The unallowable types of the token being searched for |
- distance: The number of tokens to look through before failing search. Must |
- be positive. If unspecified, will search until the end of the token |
- chain |
- reverse: When true, search the tokens before this one instead of the tokens |
- after it |
- |
- Returns: |
- The first token of any type in token_types within distance of this token, or |
- None if no such token is found. |
- """ |
- return CustomSearch(start_token, |
- lambda token: not token.IsAnyType(token_types), |
- None, distance, reverse) |
- |
- |
-def SearchUntil(start_token, token_types, end_types, distance=None, |
- reverse=False): |
- """Returns the first token of type in token_types before a token of end_type. |
- |
- Args: |
- start_token: The token to start searching from. |
- token_types: The allowable types of the token being searched for. |
- end_types: Types of tokens to abort search if we find. |
- distance: The number of tokens to look through before failing search. Must |
- be positive. If unspecified, will search until the end of the token |
- chain |
- reverse: When true, search the tokens before this one instead of the tokens |
- after it |
- |
- Returns: |
- The first token of any type in token_types within distance of this token |
- before any tokens of type in end_type, or None if no such token is found. |
- """ |
- return CustomSearch(start_token, lambda token: token.IsAnyType(token_types), |
- lambda token: token.IsAnyType(end_types), |
- distance, reverse) |
- |
- |
-def DeleteToken(token): |
- """Deletes the given token from the linked list. |
- |
- Args: |
- token: The token to delete |
- """ |
- # When deleting a token, we do not update the deleted token itself to make |
- # sure the previous and next pointers are still pointing to tokens which are |
- # not deleted. Also it is very hard to keep track of all previously deleted |
- # tokens to update them when their pointers become invalid. So we add this |
- # flag that any token linked list iteration logic can skip deleted node safely |
- # when its current token is deleted. |
- token.is_deleted = True |
- if token.previous: |
- token.previous.next = token.next |
- |
- if token.next: |
- token.next.previous = token.previous |
- |
- following_token = token.next |
- while following_token and following_token.metadata.last_code == token: |
- following_token.metadata.last_code = token.metadata.last_code |
- following_token = following_token.next |
- |
- |
-def DeleteTokens(token, token_count): |
- """Deletes the given number of tokens starting with the given token. |
- |
- Args: |
- token: The token to start deleting at. |
- token_count: The total number of tokens to delete. |
- """ |
- for i in xrange(1, token_count): |
- DeleteToken(token.next) |
- DeleteToken(token) |
- |
- |
-def InsertTokenBefore(new_token, token): |
- """Insert new_token before token. |
- |
- Args: |
- new_token: A token to be added to the stream |
- token: A token already in the stream |
- """ |
- new_token.next = token |
- new_token.previous = token.previous |
- |
- new_token.metadata = copy.copy(token.metadata) |
- |
- if new_token.IsCode(): |
- old_last_code = token.metadata.last_code |
- following_token = token |
- while (following_token and |
- following_token.metadata.last_code == old_last_code): |
- following_token.metadata.last_code = new_token |
- following_token = following_token.next |
- |
- token.previous = new_token |
- if new_token.previous: |
- new_token.previous.next = new_token |
- |
- if new_token.start_index is None: |
- if new_token.line_number == token.line_number: |
- new_token.start_index = token.start_index |
- else: |
- previous_token = new_token.previous |
- if previous_token: |
- new_token.start_index = (previous_token.start_index + |
- len(previous_token.string)) |
- else: |
- new_token.start_index = 0 |
- |
- iterator = new_token.next |
- while iterator and iterator.line_number == new_token.line_number: |
- iterator.start_index += len(new_token.string) |
- iterator = iterator.next |
- |
- |
-def InsertTokenAfter(new_token, token): |
- """Insert new_token after token. |
- |
- Args: |
- new_token: A token to be added to the stream |
- token: A token already in the stream |
- """ |
- new_token.previous = token |
- new_token.next = token.next |
- |
- new_token.metadata = copy.copy(token.metadata) |
- |
- if token.IsCode(): |
- new_token.metadata.last_code = token |
- |
- if new_token.IsCode(): |
- following_token = token.next |
- while following_token and following_token.metadata.last_code == token: |
- following_token.metadata.last_code = new_token |
- following_token = following_token.next |
- |
- token.next = new_token |
- if new_token.next: |
- new_token.next.previous = new_token |
- |
- if new_token.start_index is None: |
- if new_token.line_number == token.line_number: |
- new_token.start_index = token.start_index + len(token.string) |
- else: |
- new_token.start_index = 0 |
- |
- iterator = new_token.next |
- while iterator and iterator.line_number == new_token.line_number: |
- iterator.start_index += len(new_token.string) |
- iterator = iterator.next |
- |
- |
-def InsertTokensAfter(new_tokens, token): |
- """Insert multiple tokens after token. |
- |
- Args: |
- new_tokens: An array of tokens to be added to the stream |
- token: A token already in the stream |
- """ |
- # TODO(user): It would be nicer to have InsertTokenAfter defer to here |
- # instead of vice-versa. |
- current_token = token |
- for new_token in new_tokens: |
- InsertTokenAfter(new_token, current_token) |
- current_token = new_token |
- |
- |
-def InsertSpaceTokenAfter(token): |
- """Inserts a space token after the given token. |
- |
- Args: |
- token: The token to insert a space token after |
- |
- Returns: |
- A single space token |
- """ |
- space_token = JavaScriptToken(' ', Type.WHITESPACE, token.line, |
- token.line_number) |
- InsertTokenAfter(space_token, token) |
- |
- |
-def InsertBlankLineAfter(token): |
- """Inserts a blank line after the given token. |
- |
- Args: |
- token: The token to insert a blank line after |
- |
- Returns: |
- A single space token |
- """ |
- blank_token = JavaScriptToken('', Type.BLANK_LINE, '', |
- token.line_number + 1) |
- InsertLineAfter(token, [blank_token]) |
- |
- |
-def InsertLineAfter(token, new_tokens): |
- """Inserts a new line consisting of new_tokens after the given token. |
- |
- Args: |
- token: The token to insert after. |
- new_tokens: The tokens that will make up the new line. |
- """ |
- insert_location = token |
- for new_token in new_tokens: |
- InsertTokenAfter(new_token, insert_location) |
- insert_location = new_token |
- |
- # Update all subsequent line numbers. |
- next_token = new_tokens[-1].next |
- while next_token: |
- next_token.line_number += 1 |
- next_token = next_token.next |
- |
- |
-def SplitToken(token, position): |
- """Splits the token into two tokens at position. |
- |
- Args: |
- token: The token to split |
- position: The position to split at. Will be the beginning of second token. |
- |
- Returns: |
- The new second token. |
- """ |
- new_string = token.string[position:] |
- token.string = token.string[:position] |
- |
- new_token = JavaScriptToken(new_string, token.type, token.line, |
- token.line_number) |
- InsertTokenAfter(new_token, token) |
- |
- return new_token |
- |
- |
-def Compare(token1, token2): |
- """Compares two tokens and determines their relative order. |
- |
- Args: |
- token1: The first token to compare. |
- token2: The second token to compare. |
- |
- Returns: |
- A negative integer, zero, or a positive integer as the first token is |
- before, equal, or after the second in the token stream. |
- """ |
- if token2.line_number != token1.line_number: |
- return token1.line_number - token2.line_number |
- else: |
- return token1.start_index - token2.start_index |
- |
- |
-def GoogScopeOrNoneFromStartBlock(token): |
- """Determines if the given START_BLOCK is part of a goog.scope statement. |
- |
- Args: |
- token: A token of type START_BLOCK. |
- |
- Returns: |
- The goog.scope function call token, or None if such call doesn't exist. |
- """ |
- if token.type != JavaScriptTokenType.START_BLOCK: |
- return None |
- |
- # Search for a goog.scope statement, which will be 5 tokens before the |
- # block. Illustration of the tokens found prior to the start block: |
- # goog.scope(function() { |
- # 5 4 3 21 ^ |
- |
- maybe_goog_scope = token |
- for unused_i in xrange(5): |
- maybe_goog_scope = (maybe_goog_scope.previous if maybe_goog_scope and |
- maybe_goog_scope.previous else None) |
- if maybe_goog_scope and maybe_goog_scope.string == 'goog.scope': |
- return maybe_goog_scope |
- |
- |
-def GetTokenRange(start_token, end_token): |
- """Returns a list of tokens between the two given, inclusive. |
- |
- Args: |
- start_token: Start token in the range. |
- end_token: End token in the range. |
- |
- Returns: |
- A list of tokens, in order, from start_token to end_token (including start |
- and end). Returns none if the tokens do not describe a valid range. |
- """ |
- |
- token_range = [] |
- token = start_token |
- |
- while token: |
- token_range.append(token) |
- |
- if token == end_token: |
- return token_range |
- |
- token = token.next |
- |
- |
-def TokensToString(token_iterable): |
- """Convert a number of tokens into a string. |
- |
- Newlines will be inserted whenever the line_number of two neighboring |
- strings differ. |
- |
- Args: |
- token_iterable: The tokens to turn to a string. |
- |
- Returns: |
- A string representation of the given tokens. |
- """ |
- |
- buf = StringIO.StringIO() |
- token_list = list(token_iterable) |
- if not token_list: |
- return '' |
- |
- line_number = token_list[0].line_number |
- |
- for token in token_list: |
- |
- while line_number < token.line_number: |
- line_number += 1 |
- buf.write('\n') |
- |
- if line_number > token.line_number: |
- line_number = token.line_number |
- buf.write('\n') |
- |
- buf.write(token.string) |
- |
- return buf.getvalue() |
- |
- |
-def GetPreviousCodeToken(token): |
- """Returns the code token before the specified token. |
- |
- Args: |
- token: A token. |
- |
- Returns: |
- The code token before the specified token or None if no such token |
- exists. |
- """ |
- |
- return CustomSearch( |
- token, |
- lambda t: t and t.type not in JavaScriptTokenType.NON_CODE_TYPES, |
- reverse=True) |
- |
- |
-def GetNextCodeToken(token): |
- """Returns the next code token after the specified token. |
- |
- Args: |
- token: A token. |
- |
- Returns: |
- The next code token after the specified token or None if no such token |
- exists. |
- """ |
- |
- return CustomSearch( |
- token, |
- lambda t: t and t.type not in JavaScriptTokenType.NON_CODE_TYPES, |
- reverse=False) |
- |
- |
-def GetIdentifierStart(token): |
- """Returns the first token in an identifier. |
- |
- Given a token which is part of an identifier, returns the token at the start |
- of the identifier. |
- |
- Args: |
- token: A token which is part of an identifier. |
- |
- Returns: |
- The token at the start of the identifier or None if the identifier was not |
- of the form 'a.b.c' (e.g. "['a']['b'].c"). |
- """ |
- |
- start_token = token |
- previous_code_token = GetPreviousCodeToken(token) |
- |
- while (previous_code_token and ( |
- previous_code_token.IsType(JavaScriptTokenType.IDENTIFIER) or |
- IsDot(previous_code_token))): |
- start_token = previous_code_token |
- previous_code_token = GetPreviousCodeToken(previous_code_token) |
- |
- if IsDot(start_token): |
- return None |
- |
- return start_token |
- |
- |
-def GetIdentifierForToken(token): |
- """Get the symbol specified by a token. |
- |
- Given a token, this function additionally concatenates any parts of an |
- identifying symbol being identified that are split by whitespace or a |
- newline. |
- |
- The function will return None if the token is not the first token of an |
- identifier. |
- |
- Args: |
- token: The first token of a symbol. |
- |
- Returns: |
- The whole symbol, as a string. |
- """ |
- |
- # Search backward to determine if this token is the first token of the |
- # identifier. If it is not the first token, return None to signal that this |
- # token should be ignored. |
- prev_token = token.previous |
- while prev_token: |
- if (prev_token.IsType(JavaScriptTokenType.IDENTIFIER) or |
- IsDot(prev_token)): |
- return None |
- |
- if (prev_token.IsType(tokens.TokenType.WHITESPACE) or |
- prev_token.IsAnyType(JavaScriptTokenType.COMMENT_TYPES)): |
- prev_token = prev_token.previous |
- else: |
- break |
- |
- # A "function foo()" declaration. |
- if token.type is JavaScriptTokenType.FUNCTION_NAME: |
- return token.string |
- |
- # A "var foo" declaration (if the previous token is 'var') |
- previous_code_token = GetPreviousCodeToken(token) |
- |
- if previous_code_token and previous_code_token.IsKeyword('var'): |
- return token.string |
- |
- # Otherwise, this is potentially a namespaced (goog.foo.bar) identifier that |
- # could span multiple lines or be broken up by whitespace. We need |
- # to concatenate. |
- identifier_types = set([ |
- JavaScriptTokenType.IDENTIFIER, |
- JavaScriptTokenType.SIMPLE_LVALUE |
- ]) |
- |
- assert token.type in identifier_types |
- |
- # Start with the first token |
- symbol_tokens = [token] |
- |
- if token.next: |
- for t in token.next: |
- last_symbol_token = symbol_tokens[-1] |
- |
- # A dot is part of the previous symbol. |
- if IsDot(t): |
- symbol_tokens.append(t) |
- continue |
- |
- # An identifier is part of the previous symbol if the previous one was a |
- # dot. |
- if t.type in identifier_types: |
- if IsDot(last_symbol_token): |
- symbol_tokens.append(t) |
- continue |
- else: |
- break |
- |
- # Skip any whitespace |
- if t.type in JavaScriptTokenType.NON_CODE_TYPES: |
- continue |
- |
- # This is the end of the identifier. Stop iterating. |
- break |
- |
- if symbol_tokens: |
- return ''.join([t.string for t in symbol_tokens]) |
- |
- |
-def GetStringAfterToken(token): |
- """Get string after token. |
- |
- Args: |
- token: Search will be done after this token. |
- |
- Returns: |
- String if found after token else None (empty string will also |
- return None). |
- |
- Search until end of string as in case of empty string Type.STRING_TEXT is not |
- present/found and don't want to return next string. |
- E.g. |
- a = ''; |
- b = 'test'; |
- When searching for string after 'a' if search is not limited by end of string |
- then it will return 'test' which is not desirable as there is a empty string |
- before that. |
- |
- This will return None for cases where string is empty or no string found |
- as in both cases there is no Type.STRING_TEXT. |
- """ |
- string_token = SearchUntil(token, JavaScriptTokenType.STRING_TEXT, |
- [JavaScriptTokenType.SINGLE_QUOTE_STRING_END, |
- JavaScriptTokenType.DOUBLE_QUOTE_STRING_END, |
- JavaScriptTokenType.TEMPLATE_STRING_END]) |
- if string_token: |
- return string_token.string |
- else: |
- return None |
- |
- |
-def IsDot(token): |
- """Whether the token represents a "dot" operator (foo.bar).""" |
- return token.type is JavaScriptTokenType.OPERATOR and token.string == '.' |
- |
- |
-def IsIdentifierOrDot(token): |
- """Whether the token is either an identifier or a '.'.""" |
- return (token.type in [JavaScriptTokenType.IDENTIFIER, |
- JavaScriptTokenType.SIMPLE_LVALUE] or |
- IsDot(token)) |