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

Unified Diff: third_party/closure_linter/closure_linter/ecmametadatapass.py

Issue 2592193002: Remove closure_linter from Chrome (Closed)
Patch Set: Created 4 years 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: third_party/closure_linter/closure_linter/ecmametadatapass.py
diff --git a/third_party/closure_linter/closure_linter/ecmametadatapass.py b/third_party/closure_linter/closure_linter/ecmametadatapass.py
deleted file mode 100755
index 2036aa2824e64eaf32669a1d4a37a3f1ffb9c93e..0000000000000000000000000000000000000000
--- a/third_party/closure_linter/closure_linter/ecmametadatapass.py
+++ /dev/null
@@ -1,575 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2010 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.
-
-"""Metadata pass for annotating tokens in EcmaScript files."""
-
-__author__ = ('robbyw@google.com (Robert Walker)')
-
-from closure_linter import javascripttokens
-from closure_linter import tokenutil
-
-
-TokenType = javascripttokens.JavaScriptTokenType
-
-
-class ParseError(Exception):
- """Exception indicating a parse error at the given token.
-
- Attributes:
- token: The token where the parse error occurred.
- """
-
- def __init__(self, token, message=None):
- """Initialize a parse error at the given token with an optional message.
-
- Args:
- token: The token where the parse error occurred.
- message: A message describing the parse error.
- """
- Exception.__init__(self, message)
- self.token = token
-
-
-class EcmaContext(object):
- """Context object for EcmaScript languages.
-
- Attributes:
- type: The context type.
- start_token: The token where this context starts.
- end_token: The token where this context ends.
- parent: The parent context.
- """
-
- # The root context.
- ROOT = 'root'
-
- # A block of code.
- BLOCK = 'block'
-
- # A pseudo-block of code for a given case or default section.
- CASE_BLOCK = 'case_block'
-
- # Block of statements in a for loop's parentheses.
- FOR_GROUP_BLOCK = 'for_block'
-
- # An implied block of code for 1 line if, while, and for statements
- IMPLIED_BLOCK = 'implied_block'
-
- # An index in to an array or object.
- INDEX = 'index'
-
- # An array literal in [].
- ARRAY_LITERAL = 'array_literal'
-
- # An object literal in {}.
- OBJECT_LITERAL = 'object_literal'
-
- # An individual element in an array or object literal.
- LITERAL_ELEMENT = 'literal_element'
-
- # The portion of a ternary statement between ? and :
- TERNARY_TRUE = 'ternary_true'
-
- # The portion of a ternary statment after :
- TERNARY_FALSE = 'ternary_false'
-
- # The entire switch statment. This will contain a GROUP with the variable
- # and a BLOCK with the code.
-
- # Since that BLOCK is not a normal block, it can not contain statements except
- # for case and default.
- SWITCH = 'switch'
-
- # A normal comment.
- COMMENT = 'comment'
-
- # A JsDoc comment.
- DOC = 'doc'
-
- # An individual statement.
- STATEMENT = 'statement'
-
- # Code within parentheses.
- GROUP = 'group'
-
- # Parameter names in a function declaration.
- PARAMETERS = 'parameters'
-
- # A set of variable declarations appearing after the 'var' keyword.
- VAR = 'var'
-
- # Context types that are blocks.
- BLOCK_TYPES = frozenset([
- ROOT, BLOCK, CASE_BLOCK, FOR_GROUP_BLOCK, IMPLIED_BLOCK])
-
- def __init__(self, context_type, start_token, parent=None):
- """Initializes the context object.
-
- Args:
- context_type: The context type.
- start_token: The token where this context starts.
- parent: The parent context.
-
- Attributes:
- type: The context type.
- start_token: The token where this context starts.
- end_token: The token where this context ends.
- parent: The parent context.
- children: The child contexts of this context, in order.
- """
- self.type = context_type
- self.start_token = start_token
- self.end_token = None
-
- self.parent = None
- self.children = []
-
- if parent:
- parent.AddChild(self)
-
- def __repr__(self):
- """Returns a string representation of the context object."""
- stack = []
- context = self
- while context:
- stack.append(context.type)
- context = context.parent
- return 'Context(%s)' % ' > '.join(stack)
-
- def AddChild(self, child):
- """Adds a child to this context and sets child's parent to this context.
-
- Args:
- child: A child EcmaContext. The child's parent will be set to this
- context.
- """
-
- child.parent = self
-
- self.children.append(child)
- self.children.sort(EcmaContext._CompareContexts)
-
- def GetRoot(self):
- """Get the root context that contains this context, if any."""
- context = self
- while context:
- if context.type is EcmaContext.ROOT:
- return context
- context = context.parent
-
- @staticmethod
- def _CompareContexts(context1, context2):
- """Sorts contexts 1 and 2 by start token document position."""
- return tokenutil.Compare(context1.start_token, context2.start_token)
-
-
-class EcmaMetaData(object):
- """Token metadata for EcmaScript languages.
-
- Attributes:
- last_code: The last code token to appear before this one.
- context: The context this token appears in.
- operator_type: The operator type, will be one of the *_OPERATOR constants
- defined below.
- aliased_symbol: The full symbol being identified, as a string (e.g. an
- 'XhrIo' alias for 'goog.net.XhrIo'). Only applicable to identifier
- tokens. This is set in aliaspass.py and is a best guess.
- is_alias_definition: True if the symbol is part of an alias definition.
- If so, these symbols won't be counted towards goog.requires/provides.
- """
-
- UNARY_OPERATOR = 'unary'
-
- UNARY_POST_OPERATOR = 'unary_post'
-
- BINARY_OPERATOR = 'binary'
-
- TERNARY_OPERATOR = 'ternary'
-
- def __init__(self):
- """Initializes a token metadata object."""
- self.last_code = None
- self.context = None
- self.operator_type = None
- self.is_implied_semicolon = False
- self.is_implied_block = False
- self.is_implied_block_close = False
- self.aliased_symbol = None
- self.is_alias_definition = False
-
- def __repr__(self):
- """Returns a string representation of the context object."""
- parts = ['%r' % self.context]
- if self.operator_type:
- parts.append('optype: %r' % self.operator_type)
- if self.is_implied_semicolon:
- parts.append('implied;')
- if self.aliased_symbol:
- parts.append('alias for: %s' % self.aliased_symbol)
- return 'MetaData(%s)' % ', '.join(parts)
-
- def IsUnaryOperator(self):
- return self.operator_type in (EcmaMetaData.UNARY_OPERATOR,
- EcmaMetaData.UNARY_POST_OPERATOR)
-
- def IsUnaryPostOperator(self):
- return self.operator_type == EcmaMetaData.UNARY_POST_OPERATOR
-
-
-class EcmaMetaDataPass(object):
- """A pass that iterates over all tokens and builds metadata about them."""
-
- def __init__(self):
- """Initialize the meta data pass object."""
- self.Reset()
-
- def Reset(self):
- """Resets the metadata pass to prepare for the next file."""
- self._token = None
- self._context = None
- self._AddContext(EcmaContext.ROOT)
- self._last_code = None
-
- def _CreateContext(self, context_type):
- """Overridable by subclasses to create the appropriate context type."""
- return EcmaContext(context_type, self._token, self._context)
-
- def _CreateMetaData(self):
- """Overridable by subclasses to create the appropriate metadata type."""
- return EcmaMetaData()
-
- def _AddContext(self, context_type):
- """Adds a context of the given type to the context stack.
-
- Args:
- context_type: The type of context to create
- """
- self._context = self._CreateContext(context_type)
-
- def _PopContext(self):
- """Moves up one level in the context stack.
-
- Returns:
- The former context.
-
- Raises:
- ParseError: If the root context is popped.
- """
- top_context = self._context
- top_context.end_token = self._token
- self._context = top_context.parent
- if self._context:
- return top_context
- else:
- raise ParseError(self._token)
-
- def _PopContextType(self, *stop_types):
- """Pops the context stack until a context of the given type is popped.
-
- Args:
- *stop_types: The types of context to pop to - stops at the first match.
-
- Returns:
- The context object of the given type that was popped.
- """
- last = None
- while not last or last.type not in stop_types:
- last = self._PopContext()
- return last
-
- def _EndStatement(self):
- """Process the end of a statement."""
- self._PopContextType(EcmaContext.STATEMENT)
- if self._context.type == EcmaContext.IMPLIED_BLOCK:
- self._token.metadata.is_implied_block_close = True
- self._PopContext()
-
- def _ProcessContext(self):
- """Process the context at the current token.
-
- Returns:
- The context that should be assigned to the current token, or None if
- the current context after this method should be used.
-
- Raises:
- ParseError: When the token appears in an invalid context.
- """
- token = self._token
- token_type = token.type
-
- if self._context.type in EcmaContext.BLOCK_TYPES:
- # Whenever we're in a block, we add a statement context. We make an
- # exception for switch statements since they can only contain case: and
- # default: and therefore don't directly contain statements.
- # The block we add here may be immediately removed in some cases, but
- # that causes no harm.
- parent = self._context.parent
- if not parent or parent.type != EcmaContext.SWITCH:
- self._AddContext(EcmaContext.STATEMENT)
-
- elif self._context.type == EcmaContext.ARRAY_LITERAL:
- self._AddContext(EcmaContext.LITERAL_ELEMENT)
-
- if token_type == TokenType.START_PAREN:
- if self._last_code and self._last_code.IsKeyword('for'):
- # for loops contain multiple statements in the group unlike while,
- # switch, if, etc.
- self._AddContext(EcmaContext.FOR_GROUP_BLOCK)
- else:
- self._AddContext(EcmaContext.GROUP)
-
- elif token_type == TokenType.END_PAREN:
- result = self._PopContextType(EcmaContext.GROUP,
- EcmaContext.FOR_GROUP_BLOCK)
- keyword_token = result.start_token.metadata.last_code
- # keyword_token will not exist if the open paren is the first line of the
- # file, for example if all code is wrapped in an immediately executed
- # annonymous function.
- if keyword_token and keyword_token.string in ('if', 'for', 'while'):
- next_code = tokenutil.SearchExcept(token, TokenType.NON_CODE_TYPES)
- if next_code.type != TokenType.START_BLOCK:
- # Check for do-while.
- is_do_while = False
- pre_keyword_token = keyword_token.metadata.last_code
- if (pre_keyword_token and
- pre_keyword_token.type == TokenType.END_BLOCK):
- start_block_token = pre_keyword_token.metadata.context.start_token
- is_do_while = start_block_token.metadata.last_code.string == 'do'
-
- # If it's not do-while, it's an implied block.
- if not is_do_while:
- self._AddContext(EcmaContext.IMPLIED_BLOCK)
- token.metadata.is_implied_block = True
-
- return result
-
- # else (not else if) with no open brace after it should be considered the
- # start of an implied block, similar to the case with if, for, and while
- # above.
- elif (token_type == TokenType.KEYWORD and
- token.string == 'else'):
- next_code = tokenutil.SearchExcept(token, TokenType.NON_CODE_TYPES)
- if (next_code.type != TokenType.START_BLOCK and
- (next_code.type != TokenType.KEYWORD or next_code.string != 'if')):
- self._AddContext(EcmaContext.IMPLIED_BLOCK)
- token.metadata.is_implied_block = True
-
- elif token_type == TokenType.START_PARAMETERS:
- self._AddContext(EcmaContext.PARAMETERS)
-
- elif token_type == TokenType.END_PARAMETERS:
- return self._PopContextType(EcmaContext.PARAMETERS)
-
- elif token_type == TokenType.START_BRACKET:
- if (self._last_code and
- self._last_code.type in TokenType.EXPRESSION_ENDER_TYPES):
- self._AddContext(EcmaContext.INDEX)
- else:
- self._AddContext(EcmaContext.ARRAY_LITERAL)
-
- elif token_type == TokenType.END_BRACKET:
- return self._PopContextType(EcmaContext.INDEX, EcmaContext.ARRAY_LITERAL)
-
- elif token_type == TokenType.START_BLOCK:
- if (self._last_code.type in (TokenType.END_PAREN,
- TokenType.END_PARAMETERS) or
- self._last_code.IsKeyword('else') or
- self._last_code.IsKeyword('do') or
- self._last_code.IsKeyword('try') or
- self._last_code.IsKeyword('finally') or
- (self._last_code.IsOperator(':') and
- self._last_code.metadata.context.type == EcmaContext.CASE_BLOCK)):
- # else, do, try, and finally all might have no () before {.
- # Also, handle the bizzare syntax case 10: {...}.
- self._AddContext(EcmaContext.BLOCK)
- else:
- self._AddContext(EcmaContext.OBJECT_LITERAL)
-
- elif token_type == TokenType.END_BLOCK:
- context = self._PopContextType(EcmaContext.BLOCK,
- EcmaContext.OBJECT_LITERAL)
- if self._context.type == EcmaContext.SWITCH:
- # The end of the block also means the end of the switch statement it
- # applies to.
- return self._PopContext()
- return context
-
- elif token.IsKeyword('switch'):
- self._AddContext(EcmaContext.SWITCH)
-
- elif (token_type == TokenType.KEYWORD and
- token.string in ('case', 'default') and
- self._context.type != EcmaContext.OBJECT_LITERAL):
- # Pop up to but not including the switch block.
- while self._context.parent.type != EcmaContext.SWITCH:
- self._PopContext()
- if self._context.parent is None:
- raise ParseError(token, 'Encountered case/default statement '
- 'without switch statement')
-
- elif token.IsOperator('?'):
- self._AddContext(EcmaContext.TERNARY_TRUE)
-
- elif token.IsOperator(':'):
- if self._context.type == EcmaContext.OBJECT_LITERAL:
- self._AddContext(EcmaContext.LITERAL_ELEMENT)
-
- elif self._context.type == EcmaContext.TERNARY_TRUE:
- self._PopContext()
- self._AddContext(EcmaContext.TERNARY_FALSE)
-
- # Handle nested ternary statements like:
- # foo = bar ? baz ? 1 : 2 : 3
- # When we encounter the second ":" the context is
- # ternary_false > ternary_true > statement > root
- elif (self._context.type == EcmaContext.TERNARY_FALSE and
- self._context.parent.type == EcmaContext.TERNARY_TRUE):
- self._PopContext() # Leave current ternary false context.
- self._PopContext() # Leave current parent ternary true
- self._AddContext(EcmaContext.TERNARY_FALSE)
-
- elif self._context.parent.type == EcmaContext.SWITCH:
- self._AddContext(EcmaContext.CASE_BLOCK)
-
- elif token.IsKeyword('var'):
- self._AddContext(EcmaContext.VAR)
-
- elif token.IsOperator(','):
- while self._context.type not in (EcmaContext.VAR,
- EcmaContext.ARRAY_LITERAL,
- EcmaContext.OBJECT_LITERAL,
- EcmaContext.STATEMENT,
- EcmaContext.PARAMETERS,
- EcmaContext.GROUP):
- self._PopContext()
-
- elif token_type == TokenType.SEMICOLON:
- self._EndStatement()
-
- def Process(self, first_token):
- """Processes the token stream starting with the given token."""
- self._token = first_token
- while self._token:
- self._ProcessToken()
-
- if self._token.IsCode():
- self._last_code = self._token
-
- self._token = self._token.next
-
- try:
- self._PopContextType(self, EcmaContext.ROOT)
- except ParseError:
- # Ignore the "popped to root" error.
- pass
-
- def _ProcessToken(self):
- """Process the given token."""
- token = self._token
- token.metadata = self._CreateMetaData()
- context = (self._ProcessContext() or self._context)
- token.metadata.context = context
- token.metadata.last_code = self._last_code
-
- # Determine the operator type of the token, if applicable.
- if token.type == TokenType.OPERATOR:
- token.metadata.operator_type = self._GetOperatorType(token)
-
- # Determine if there is an implied semicolon after the token.
- if token.type != TokenType.SEMICOLON:
- next_code = tokenutil.SearchExcept(token, TokenType.NON_CODE_TYPES)
- # A statement like if (x) does not need a semicolon after it
- is_implied_block = self._context == EcmaContext.IMPLIED_BLOCK
- is_last_code_in_line = token.IsCode() and (
- not next_code or next_code.line_number != token.line_number)
- is_continued_operator = (token.type == TokenType.OPERATOR and
- not token.metadata.IsUnaryPostOperator())
- is_continued_dot = token.string == '.'
- next_code_is_operator = next_code and next_code.type == TokenType.OPERATOR
- is_end_of_block = (
- token.type == TokenType.END_BLOCK and
- token.metadata.context.type != EcmaContext.OBJECT_LITERAL)
- is_multiline_string = (token.type == TokenType.STRING_TEXT or
- token.type == TokenType.TEMPLATE_STRING_START)
- is_continued_var_decl = (token.IsKeyword('var') and
- next_code and
- (next_code.type in [TokenType.IDENTIFIER,
- TokenType.SIMPLE_LVALUE]) and
- token.line_number < next_code.line_number)
- next_code_is_block = next_code and next_code.type == TokenType.START_BLOCK
- if (is_last_code_in_line and
- self._StatementCouldEndInContext() and
- not is_multiline_string and
- not is_end_of_block and
- not is_continued_var_decl and
- not is_continued_operator and
- not is_continued_dot and
- not next_code_is_operator and
- not is_implied_block and
- not next_code_is_block):
- token.metadata.is_implied_semicolon = True
- self._EndStatement()
-
- def _StatementCouldEndInContext(self):
- """Returns if the current statement (if any) may end in this context."""
- # In the basic statement or variable declaration context, statement can
- # always end in this context.
- if self._context.type in (EcmaContext.STATEMENT, EcmaContext.VAR):
- return True
-
- # End of a ternary false branch inside a statement can also be the
- # end of the statement, for example:
- # var x = foo ? foo.bar() : null
- # In this case the statement ends after the null, when the context stack
- # looks like ternary_false > var > statement > root.
- if (self._context.type == EcmaContext.TERNARY_FALSE and
- self._context.parent.type in (EcmaContext.STATEMENT, EcmaContext.VAR)):
- return True
-
- # In all other contexts like object and array literals, ternary true, etc.
- # the statement can't yet end.
- return False
-
- def _GetOperatorType(self, token):
- """Returns the operator type of the given operator token.
-
- Args:
- token: The token to get arity for.
-
- Returns:
- The type of the operator. One of the *_OPERATOR constants defined in
- EcmaMetaData.
- """
- if token.string == '?':
- return EcmaMetaData.TERNARY_OPERATOR
-
- if token.string in TokenType.UNARY_OPERATORS:
- return EcmaMetaData.UNARY_OPERATOR
-
- last_code = token.metadata.last_code
- if not last_code or last_code.type == TokenType.END_BLOCK:
- return EcmaMetaData.UNARY_OPERATOR
-
- if (token.string in TokenType.UNARY_POST_OPERATORS and
- last_code.type in TokenType.EXPRESSION_ENDER_TYPES):
- return EcmaMetaData.UNARY_POST_OPERATOR
-
- if (token.string in TokenType.UNARY_OK_OPERATORS and
- last_code.type not in TokenType.EXPRESSION_ENDER_TYPES and
- last_code.string not in TokenType.UNARY_POST_OPERATORS):
- return EcmaMetaData.UNARY_OPERATOR
-
- return EcmaMetaData.BINARY_OPERATOR
« no previous file with comments | « third_party/closure_linter/closure_linter/ecmalintrules.py ('k') | third_party/closure_linter/closure_linter/error_check.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698