15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright 2010 The Closure Linter Authors. All Rights Reserved.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Licensed under the Apache License, Version 2.0 (the "License");
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# you may not use this file except in compliance with the License.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# You may obtain a copy of the License at
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#      http://www.apache.org/licenses/LICENSE-2.0
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Unless required by applicable law or agreed to in writing, software
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# distributed under the License is distributed on an "AS-IS" BASIS,
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# See the License for the specific language governing permissions and
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# limitations under the License.
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Metadata pass for annotating tokens in EcmaScript files."""
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)__author__ = ('robbyw@google.com (Robert Walker)')
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from closure_linter import javascripttokens
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from closure_linter import tokenutil
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TokenType = javascripttokens.JavaScriptTokenType
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ParseError(Exception):
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Exception indicating a parse error at the given token.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Attributes:
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token: The token where the parse error occurred.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, token, message=None):
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Initialize a parse error at the given token with an optional message.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token: The token where the parse error occurred.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      message: A message describing the parse error.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Exception.__init__(self, message)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.token = token
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class EcmaContext(object):
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Context object for EcmaScript languages.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Attributes:
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    type: The context type.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    start_token: The token where this context starts.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    end_token: The token where this context ends.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parent: The parent context.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # The root context.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ROOT = 'root'
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # A block of code.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BLOCK = 'block'
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # A pseudo-block of code for a given case or default section.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CASE_BLOCK = 'case_block'
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Block of statements in a for loop's parentheses.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_GROUP_BLOCK = 'for_block'
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # An implied block of code for 1 line if, while, and for statements
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IMPLIED_BLOCK = 'implied_block'
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # An index in to an array or object.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  INDEX = 'index'
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # An array literal in [].
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ARRAY_LITERAL = 'array_literal'
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # An object literal in {}.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OBJECT_LITERAL = 'object_literal'
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # An individual element in an array or object literal.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LITERAL_ELEMENT = 'literal_element'
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # The portion of a ternary statement between ? and :
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TERNARY_TRUE = 'ternary_true'
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # The portion of a ternary statment after :
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TERNARY_FALSE = 'ternary_false'
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # The entire switch statment.  This will contain a GROUP with the variable
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # and a BLOCK with the code.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Since that BLOCK is not a normal block, it can not contain statements except
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # for case and default.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SWITCH = 'switch'
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # A normal comment.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  COMMENT = 'comment'
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # A JsDoc comment.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DOC = 'doc'
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # An individual statement.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STATEMENT = 'statement'
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Code within parentheses.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GROUP = 'group'
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Parameter names in a function declaration.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PARAMETERS = 'parameters'
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # A set of variable declarations appearing after the 'var' keyword.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VAR = 'var'
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Context types that are blocks.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BLOCK_TYPES = frozenset([
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ROOT, BLOCK, CASE_BLOCK, FOR_GROUP_BLOCK, IMPLIED_BLOCK])
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def __init__(self, context_type, start_token, parent=None):
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Initializes the context object.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      context_type: The context type.
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      start_token: The token where this context starts.
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      parent: The parent context.
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Attributes:
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      type: The context type.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      start_token: The token where this context starts.
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      end_token: The token where this context ends.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent: The parent context.
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      children: The child contexts of this context, in order.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self.type = context_type
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.start_token = start_token
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.end_token = None
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self.parent = None
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self.children = []
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if parent:
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      parent.AddChild(self)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __repr__(self):
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns a string representation of the context object."""
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stack = []
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context = self
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while context:
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stack.append(context.type)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      context = context.parent
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'Context(%s)' % ' > '.join(stack)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def AddChild(self, child):
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """Adds a child to this context and sets child's parent to this context.
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Args:
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      child: A child EcmaContext.  The child's parent will be set to this
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          context.
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    child.parent = self
1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self.children.append(child)
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self.children.sort(EcmaContext._CompareContexts)
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def GetRoot(self):
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """Get the root context that contains this context, if any."""
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    context = self
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    while context:
1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if context.type is EcmaContext.ROOT:
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return context
1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      context = context.parent
1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  @staticmethod
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def _CompareContexts(context1, context2):
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """Sorts contexts 1 and 2 by start token document position."""
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return tokenutil.Compare(context1.start_token, context2.start_token)
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class EcmaMetaData(object):
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Token metadata for EcmaScript languages.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Attributes:
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_code: The last code token to appear before this one.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context: The context this token appears in.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    operator_type: The operator type, will be one of the *_OPERATOR constants
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        defined below.
1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    aliased_symbol: The full symbol being identified, as a string (e.g. an
1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        'XhrIo' alias for 'goog.net.XhrIo'). Only applicable to identifier
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        tokens. This is set in aliaspass.py and is a best guess.
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    is_alias_definition: True if the symbol is part of an alias definition.
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        If so, these symbols won't be counted towards goog.requires/provides.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNARY_OPERATOR = 'unary'
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNARY_POST_OPERATOR = 'unary_post'
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BINARY_OPERATOR = 'binary'
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TERNARY_OPERATOR = 'ternary'
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Initializes a token metadata object."""
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.last_code = None
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.context = None
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.operator_type = None
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.is_implied_semicolon = False
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.is_implied_block = False
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.is_implied_block_close = False
2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self.aliased_symbol = None
2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self.is_alias_definition = False
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __repr__(self):
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns a string representation of the context object."""
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parts = ['%r' % self.context]
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.operator_type:
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parts.append('optype: %r' % self.operator_type)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.is_implied_semicolon:
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parts.append('implied;')
2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if self.aliased_symbol:
2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      parts.append('alias for: %s' % self.aliased_symbol)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'MetaData(%s)' % ', '.join(parts)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsUnaryOperator(self):
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.operator_type in (EcmaMetaData.UNARY_OPERATOR,
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  EcmaMetaData.UNARY_POST_OPERATOR)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsUnaryPostOperator(self):
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.operator_type == EcmaMetaData.UNARY_POST_OPERATOR
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class EcmaMetaDataPass(object):
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """A pass that iterates over all tokens and builds metadata about them."""
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Initialize the meta data pass object."""
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.Reset()
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Reset(self):
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Resets the metadata pass to prepare for the next file."""
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._token = None
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._context = None
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._AddContext(EcmaContext.ROOT)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._last_code = None
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def _CreateContext(self, context_type):
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Overridable by subclasses to create the appropriate context type."""
2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return EcmaContext(context_type, self._token, self._context)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _CreateMetaData(self):
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Overridable by subclasses to create the appropriate metadata type."""
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return EcmaMetaData()
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def _AddContext(self, context_type):
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Adds a context of the given type to the context stack.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      context_type: The type of context to create
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self._context = self._CreateContext(context_type)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _PopContext(self):
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Moves up one level in the context stack.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The former context.
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ParseError: If the root context is popped.
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    top_context = self._context
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    top_context.end_token = self._token
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._context = top_context.parent
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._context:
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return top_context
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise ParseError(self._token)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _PopContextType(self, *stop_types):
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Pops the context stack until a context of the given type is popped.
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      *stop_types: The types of context to pop to - stops at the first match.
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The context object of the given type that was popped.
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last = None
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while not last or last.type not in stop_types:
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last = self._PopContext()
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return last
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _EndStatement(self):
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Process the end of a statement."""
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._PopContextType(EcmaContext.STATEMENT)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._context.type == EcmaContext.IMPLIED_BLOCK:
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._token.metadata.is_implied_block_close = True
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._PopContext()
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _ProcessContext(self):
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Process the context at the current token.
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The context that should be assigned to the current token, or None if
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      the current context after this method should be used.
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ParseError: When the token appears in an invalid context.
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token = self._token
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token_type = token.type
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._context.type in EcmaContext.BLOCK_TYPES:
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Whenever we're in a block, we add a statement context.  We make an
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # exception for switch statements since they can only contain case: and
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # default: and therefore don't directly contain statements.
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # The block we add here may be immediately removed in some cases, but
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # that causes no harm.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent = self._context.parent
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not parent or parent.type != EcmaContext.SWITCH:
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.STATEMENT)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif self._context.type == EcmaContext.ARRAY_LITERAL:
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._AddContext(EcmaContext.LITERAL_ELEMENT)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if token_type == TokenType.START_PAREN:
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self._last_code and self._last_code.IsKeyword('for'):
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # for loops contain multiple statements in the group unlike while,
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # switch, if, etc.
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.FOR_GROUP_BLOCK)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.GROUP)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.END_PAREN:
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result = self._PopContextType(EcmaContext.GROUP,
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    EcmaContext.FOR_GROUP_BLOCK)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      keyword_token = result.start_token.metadata.last_code
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # keyword_token will not exist if the open paren is the first line of the
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # file, for example if all code is wrapped in an immediately executed
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # annonymous function.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if keyword_token and keyword_token.string in ('if', 'for', 'while'):
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        next_code = tokenutil.SearchExcept(token, TokenType.NON_CODE_TYPES)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if next_code.type != TokenType.START_BLOCK:
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          # Check for do-while.
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          is_do_while = False
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          pre_keyword_token = keyword_token.metadata.last_code
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (pre_keyword_token and
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              pre_keyword_token.type == TokenType.END_BLOCK):
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            start_block_token = pre_keyword_token.metadata.context.start_token
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            is_do_while = start_block_token.metadata.last_code.string == 'do'
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          # If it's not do-while, it's an implied block.
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if not is_do_while:
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            self._AddContext(EcmaContext.IMPLIED_BLOCK)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            token.metadata.is_implied_block = True
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return result
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # else (not else if) with no open brace after it should be considered the
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # start of an implied block, similar to the case with if, for, and while
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # above.
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif (token_type == TokenType.KEYWORD and
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          token.string == 'else'):
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_code = tokenutil.SearchExcept(token, TokenType.NON_CODE_TYPES)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (next_code.type != TokenType.START_BLOCK and
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (next_code.type != TokenType.KEYWORD or next_code.string != 'if')):
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.IMPLIED_BLOCK)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        token.metadata.is_implied_block = True
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.START_PARAMETERS:
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._AddContext(EcmaContext.PARAMETERS)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.END_PARAMETERS:
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return self._PopContextType(EcmaContext.PARAMETERS)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.START_BRACKET:
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (self._last_code and
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self._last_code.type in TokenType.EXPRESSION_ENDER_TYPES):
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.INDEX)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.ARRAY_LITERAL)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.END_BRACKET:
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return self._PopContextType(EcmaContext.INDEX, EcmaContext.ARRAY_LITERAL)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.START_BLOCK:
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (self._last_code.type in (TokenType.END_PAREN,
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   TokenType.END_PARAMETERS) or
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self._last_code.IsKeyword('else') or
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self._last_code.IsKeyword('do') or
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self._last_code.IsKeyword('try') or
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self._last_code.IsKeyword('finally') or
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (self._last_code.IsOperator(':') and
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           self._last_code.metadata.context.type == EcmaContext.CASE_BLOCK)):
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # else, do, try, and finally all might have no () before {.
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Also, handle the bizzare syntax case 10: {...}.
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.BLOCK)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.OBJECT_LITERAL)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.END_BLOCK:
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      context = self._PopContextType(EcmaContext.BLOCK,
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     EcmaContext.OBJECT_LITERAL)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self._context.type == EcmaContext.SWITCH:
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # The end of the block also means the end of the switch statement it
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # applies to.
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return self._PopContext()
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return context
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token.IsKeyword('switch'):
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._AddContext(EcmaContext.SWITCH)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif (token_type == TokenType.KEYWORD and
4145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          token.string in ('case', 'default') and
4155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          self._context.type != EcmaContext.OBJECT_LITERAL):
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Pop up to but not including the switch block.
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while self._context.parent.type != EcmaContext.SWITCH:
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._PopContext()
4195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if self._context.parent is None:
4205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          raise ParseError(token, 'Encountered case/default statement '
4215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                           'without switch statement')
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token.IsOperator('?'):
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._AddContext(EcmaContext.TERNARY_TRUE)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token.IsOperator(':'):
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self._context.type == EcmaContext.OBJECT_LITERAL:
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.LITERAL_ELEMENT)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif self._context.type == EcmaContext.TERNARY_TRUE:
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._PopContext()
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.TERNARY_FALSE)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Handle nested ternary statements like:
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # foo = bar ? baz ? 1 : 2 : 3
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # When we encounter the second ":" the context is
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # ternary_false > ternary_true > statement > root
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif (self._context.type == EcmaContext.TERNARY_FALSE and
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            self._context.parent.type == EcmaContext.TERNARY_TRUE):
4405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._PopContext()  # Leave current ternary false context.
4415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._PopContext()  # Leave current parent ternary true
4425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._AddContext(EcmaContext.TERNARY_FALSE)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif self._context.parent.type == EcmaContext.SWITCH:
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.CASE_BLOCK)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token.IsKeyword('var'):
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._AddContext(EcmaContext.VAR)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token.IsOperator(','):
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while self._context.type not in (EcmaContext.VAR,
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       EcmaContext.ARRAY_LITERAL,
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       EcmaContext.OBJECT_LITERAL,
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       EcmaContext.STATEMENT,
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       EcmaContext.PARAMETERS,
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       EcmaContext.GROUP):
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._PopContext()
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.SEMICOLON:
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._EndStatement()
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Process(self, first_token):
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Processes the token stream starting with the given token."""
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._token = first_token
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while self._token:
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._ProcessToken()
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self._token.IsCode():
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._last_code = self._token
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._token = self._token.next
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._PopContextType(self, EcmaContext.ROOT)
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except ParseError:
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Ignore the "popped to root" error.
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pass
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _ProcessToken(self):
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Process the given token."""
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token = self._token
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token.metadata = self._CreateMetaData()
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context = (self._ProcessContext() or self._context)
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token.metadata.context = context
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token.metadata.last_code = self._last_code
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Determine the operator type of the token, if applicable.
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if token.type == TokenType.OPERATOR:
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token.metadata.operator_type = self._GetOperatorType(token)
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Determine if there is an implied semicolon after the token.
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if token.type != TokenType.SEMICOLON:
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_code = tokenutil.SearchExcept(token, TokenType.NON_CODE_TYPES)
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # A statement like if (x) does not need a semicolon after it
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_implied_block = self._context == EcmaContext.IMPLIED_BLOCK
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_last_code_in_line = token.IsCode() and (
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not next_code or next_code.line_number != token.line_number)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_continued_identifier = (token.type == TokenType.IDENTIFIER and
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 token.string.endswith('.'))
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_continued_operator = (token.type == TokenType.OPERATOR and
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               not token.metadata.IsUnaryPostOperator())
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_continued_dot = token.string == '.'
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_code_is_operator = next_code and next_code.type == TokenType.OPERATOR
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_code_is_dot = next_code and next_code.string == '.'
5055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      is_end_of_block = (
5065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          token.type == TokenType.END_BLOCK and
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          token.metadata.context.type != EcmaContext.OBJECT_LITERAL)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_multiline_string = token.type == TokenType.STRING_TEXT
5095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      is_continued_var_decl = (token.IsKeyword('var') and
5105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               next_code and
5115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               (next_code.type in [TokenType.IDENTIFIER,
5125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                   TokenType.SIMPLE_LVALUE]) and
5135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               token.line_number < next_code.line_number)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_code_is_block = next_code and next_code.type == TokenType.START_BLOCK
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (is_last_code_in_line and
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self._StatementCouldEndInContext() and
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not is_multiline_string and
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not is_end_of_block and
5195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          not is_continued_var_decl and
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not is_continued_identifier and
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not is_continued_operator and
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not is_continued_dot and
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not next_code_is_dot and
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not next_code_is_operator and
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not is_implied_block and
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not next_code_is_block):
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        token.metadata.is_implied_semicolon = True
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._EndStatement()
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _StatementCouldEndInContext(self):
5315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """Returns if the current statement (if any) may end in this context."""
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # In the basic statement or variable declaration context, statement can
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # always end in this context.
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._context.type in (EcmaContext.STATEMENT, EcmaContext.VAR):
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return True
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # End of a ternary false branch inside a statement can also be the
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # end of the statement, for example:
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # var x = foo ? foo.bar() : null
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # In this case the statement ends after the null, when the context stack
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # looks like ternary_false > var > statement > root.
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (self._context.type == EcmaContext.TERNARY_FALSE and
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._context.parent.type in (EcmaContext.STATEMENT, EcmaContext.VAR)):
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return True
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # In all other contexts like object and array literals, ternary true, etc.
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # the statement can't yet end.
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return False
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetOperatorType(self, token):
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the operator type of the given operator token.
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token: The token to get arity for.
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The type of the operator.  One of the *_OPERATOR constants defined in
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EcmaMetaData.
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if token.string == '?':
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return EcmaMetaData.TERNARY_OPERATOR
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if token.string in TokenType.UNARY_OPERATORS:
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return EcmaMetaData.UNARY_OPERATOR
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_code = token.metadata.last_code
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not last_code or last_code.type == TokenType.END_BLOCK:
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return EcmaMetaData.UNARY_OPERATOR
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (token.string in TokenType.UNARY_POST_OPERATORS and
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        last_code.type in TokenType.EXPRESSION_ENDER_TYPES):
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return EcmaMetaData.UNARY_POST_OPERATOR
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (token.string in TokenType.UNARY_OK_OPERATORS and
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        last_code.type not in TokenType.EXPRESSION_ENDER_TYPES and
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        last_code.string not in TokenType.UNARY_POST_OPERATORS):
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return EcmaMetaData.UNARY_OPERATOR
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return EcmaMetaData.BINARY_OPERATOR
580