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)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, type, start_token, parent):
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Initializes the context object.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      type: The context type.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      start_token: The token where this context starts.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent: The parent context.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.type = type
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.start_token = start_token
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.end_token = None
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.parent = parent
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __repr__(self):
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns a string representation of the context object."""
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stack = []
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context = self
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while context:
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stack.append(context.type)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      context = context.parent
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'Context(%s)' % ' > '.join(stack)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class EcmaMetaData(object):
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Token metadata for EcmaScript languages.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Attributes:
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_code: The last code token to appear before this one.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context: The context this token appears in.
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    operator_type: The operator type, will be one of the *_OPERATOR constants
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        defined below.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNARY_OPERATOR = 'unary'
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNARY_POST_OPERATOR = 'unary_post'
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BINARY_OPERATOR = 'binary'
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TERNARY_OPERATOR = 'ternary'
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Initializes a token metadata object."""
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.last_code = None
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.context = None
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.operator_type = None
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.is_implied_semicolon = False
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.is_implied_block = False
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.is_implied_block_close = False
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __repr__(self):
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns a string representation of the context object."""
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parts = ['%r' % self.context]
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.operator_type:
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parts.append('optype: %r' % self.operator_type)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.is_implied_semicolon:
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parts.append('implied;')
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'MetaData(%s)' % ', '.join(parts)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsUnaryOperator(self):
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.operator_type in (EcmaMetaData.UNARY_OPERATOR,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  EcmaMetaData.UNARY_POST_OPERATOR)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsUnaryPostOperator(self):
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.operator_type == EcmaMetaData.UNARY_POST_OPERATOR
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class EcmaMetaDataPass(object):
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """A pass that iterates over all tokens and builds metadata about them."""
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Initialize the meta data pass object."""
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.Reset()
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Reset(self):
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Resets the metadata pass to prepare for the next file."""
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._token = None
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._context = None
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._AddContext(EcmaContext.ROOT)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._last_code = None
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _CreateContext(self, type):
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Overridable by subclasses to create the appropriate context type."""
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return EcmaContext(type, self._token, self._context)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _CreateMetaData(self):
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Overridable by subclasses to create the appropriate metadata type."""
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return EcmaMetaData()
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _AddContext(self, type):
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Adds a context of the given type to the context stack.
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      type: The type of context to create
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._context  = self._CreateContext(type)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _PopContext(self):
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Moves up one level in the context stack.
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The former context.
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ParseError: If the root context is popped.
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    top_context = self._context
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    top_context.end_token = self._token
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._context = top_context.parent
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._context:
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return top_context
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise ParseError(self._token)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _PopContextType(self, *stop_types):
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Pops the context stack until a context of the given type is popped.
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stop_types: The types of context to pop to - stops at the first match.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The context object of the given type that was popped.
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last = None
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while not last or last.type not in stop_types:
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last = self._PopContext()
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return last
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _EndStatement(self):
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Process the end of a statement."""
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._PopContextType(EcmaContext.STATEMENT)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._context.type == EcmaContext.IMPLIED_BLOCK:
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._token.metadata.is_implied_block_close = True
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._PopContext()
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _ProcessContext(self):
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Process the context at the current token.
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The context that should be assigned to the current token, or None if
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      the current context after this method should be used.
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Raises:
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ParseError: When the token appears in an invalid context.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token = self._token
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token_type = token.type
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._context.type in EcmaContext.BLOCK_TYPES:
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Whenever we're in a block, we add a statement context.  We make an
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # exception for switch statements since they can only contain case: and
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # default: and therefore don't directly contain statements.
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # The block we add here may be immediately removed in some cases, but
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # that causes no harm.
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent = self._context.parent
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not parent or parent.type != EcmaContext.SWITCH:
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.STATEMENT)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif self._context.type == EcmaContext.ARRAY_LITERAL:
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._AddContext(EcmaContext.LITERAL_ELEMENT)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if token_type == TokenType.START_PAREN:
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self._last_code and self._last_code.IsKeyword('for'):
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # for loops contain multiple statements in the group unlike while,
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # switch, if, etc.
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.FOR_GROUP_BLOCK)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.GROUP)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.END_PAREN:
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result = self._PopContextType(EcmaContext.GROUP,
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    EcmaContext.FOR_GROUP_BLOCK)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      keyword_token = result.start_token.metadata.last_code
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # keyword_token will not exist if the open paren is the first line of the
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # file, for example if all code is wrapped in an immediately executed
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # annonymous function.
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if keyword_token and keyword_token.string in ('if', 'for', 'while'):
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        next_code = tokenutil.SearchExcept(token, TokenType.NON_CODE_TYPES)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if next_code.type != TokenType.START_BLOCK:
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          # Check for do-while.
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          is_do_while = False
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          pre_keyword_token = keyword_token.metadata.last_code
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (pre_keyword_token and
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              pre_keyword_token.type == TokenType.END_BLOCK):
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            start_block_token = pre_keyword_token.metadata.context.start_token
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            is_do_while = start_block_token.metadata.last_code.string == 'do'
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          # If it's not do-while, it's an implied block.
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if not is_do_while:
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            self._AddContext(EcmaContext.IMPLIED_BLOCK)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            token.metadata.is_implied_block = True
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return result
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # else (not else if) with no open brace after it should be considered the
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # start of an implied block, similar to the case with if, for, and while
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # above.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif (token_type == TokenType.KEYWORD and
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          token.string == 'else'):
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_code = tokenutil.SearchExcept(token, TokenType.NON_CODE_TYPES)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (next_code.type != TokenType.START_BLOCK and
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (next_code.type != TokenType.KEYWORD or next_code.string != 'if')):
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.IMPLIED_BLOCK)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        token.metadata.is_implied_block = True
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.START_PARAMETERS:
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._AddContext(EcmaContext.PARAMETERS)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.END_PARAMETERS:
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return self._PopContextType(EcmaContext.PARAMETERS)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.START_BRACKET:
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (self._last_code and
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self._last_code.type in TokenType.EXPRESSION_ENDER_TYPES):
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.INDEX)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.ARRAY_LITERAL)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.END_BRACKET:
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return self._PopContextType(EcmaContext.INDEX, EcmaContext.ARRAY_LITERAL)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.START_BLOCK:
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (self._last_code.type in (TokenType.END_PAREN,
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   TokenType.END_PARAMETERS) or
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self._last_code.IsKeyword('else') or
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self._last_code.IsKeyword('do') or
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self._last_code.IsKeyword('try') or
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self._last_code.IsKeyword('finally') or
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (self._last_code.IsOperator(':') and
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           self._last_code.metadata.context.type == EcmaContext.CASE_BLOCK)):
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # else, do, try, and finally all might have no () before {.
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # Also, handle the bizzare syntax case 10: {...}.
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.BLOCK)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.OBJECT_LITERAL)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.END_BLOCK:
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      context = self._PopContextType(EcmaContext.BLOCK,
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     EcmaContext.OBJECT_LITERAL)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self._context.type == EcmaContext.SWITCH:
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # The end of the block also means the end of the switch statement it
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # applies to.
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return self._PopContext()
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return context
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token.IsKeyword('switch'):
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._AddContext(EcmaContext.SWITCH)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif (token_type == TokenType.KEYWORD and
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          token.string in ('case', 'default')):
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Pop up to but not including the switch block.
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while self._context.parent.type != EcmaContext.SWITCH:
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._PopContext()
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token.IsOperator('?'):
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._AddContext(EcmaContext.TERNARY_TRUE)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token.IsOperator(':'):
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self._context.type == EcmaContext.OBJECT_LITERAL:
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.LITERAL_ELEMENT)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif self._context.type == EcmaContext.TERNARY_TRUE:
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._PopContext()
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.TERNARY_FALSE)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Handle nested ternary statements like:
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # foo = bar ? baz ? 1 : 2 : 3
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # When we encounter the second ":" the context is
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # ternary_false > ternary_true > statement > root
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif (self._context.type == EcmaContext.TERNARY_FALSE and
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            self._context.parent.type == EcmaContext.TERNARY_TRUE):
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           self._PopContext() # Leave current ternary false context.
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           self._PopContext() # Leave current parent ternary true
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           self._AddContext(EcmaContext.TERNARY_FALSE)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif self._context.parent.type == EcmaContext.SWITCH:
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._AddContext(EcmaContext.CASE_BLOCK)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token.IsKeyword('var'):
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._AddContext(EcmaContext.VAR)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token.IsOperator(','):
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while self._context.type not in (EcmaContext.VAR,
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       EcmaContext.ARRAY_LITERAL,
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       EcmaContext.OBJECT_LITERAL,
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       EcmaContext.STATEMENT,
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       EcmaContext.PARAMETERS,
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       EcmaContext.GROUP):
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._PopContext()
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif token_type == TokenType.SEMICOLON:
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._EndStatement()
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Process(self, first_token):
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Processes the token stream starting with the given token."""
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._token = first_token
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while self._token:
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._ProcessToken()
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self._token.IsCode():
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._last_code = self._token
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._token = self._token.next
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._PopContextType(self, EcmaContext.ROOT)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except ParseError:
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Ignore the "popped to root" error.
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pass
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _ProcessToken(self):
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Process the given token."""
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token = self._token
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token.metadata = self._CreateMetaData()
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context = (self._ProcessContext() or self._context)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token.metadata.context = context
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    token.metadata.last_code = self._last_code
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Determine the operator type of the token, if applicable.
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if token.type == TokenType.OPERATOR:
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token.metadata.operator_type = self._GetOperatorType(token)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Determine if there is an implied semicolon after the token.
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if token.type != TokenType.SEMICOLON:
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_code = tokenutil.SearchExcept(token, TokenType.NON_CODE_TYPES)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # A statement like if (x) does not need a semicolon after it
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_implied_block = self._context == EcmaContext.IMPLIED_BLOCK
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_last_code_in_line = token.IsCode() and (
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not next_code or next_code.line_number != token.line_number)
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_continued_identifier = (token.type == TokenType.IDENTIFIER and
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 token.string.endswith('.'))
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_continued_operator = (token.type == TokenType.OPERATOR and
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               not token.metadata.IsUnaryPostOperator())
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_continued_dot = token.string == '.'
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_code_is_operator = next_code and next_code.type == TokenType.OPERATOR
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_code_is_dot = next_code and next_code.string == '.'
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_end_of_block = (token.type == TokenType.END_BLOCK and
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          token.metadata.context.type != EcmaContext.OBJECT_LITERAL)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_multiline_string = token.type == TokenType.STRING_TEXT
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_code_is_block = next_code and next_code.type == TokenType.START_BLOCK
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (is_last_code_in_line and
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          self._StatementCouldEndInContext() and
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not is_multiline_string and
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not is_end_of_block and
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not is_continued_identifier and
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not is_continued_operator and
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not is_continued_dot and
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not next_code_is_dot and
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not next_code_is_operator and
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not is_implied_block and
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          not next_code_is_block):
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        token.metadata.is_implied_semicolon = True
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._EndStatement()
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _StatementCouldEndInContext(self):
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns whether the current statement (if any) may end in this context."""
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # In the basic statement or variable declaration context, statement can
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # always end in this context.
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._context.type in (EcmaContext.STATEMENT, EcmaContext.VAR):
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return True
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # End of a ternary false branch inside a statement can also be the
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # end of the statement, for example:
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # var x = foo ? foo.bar() : null
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # In this case the statement ends after the null, when the context stack
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # looks like ternary_false > var > statement > root.
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (self._context.type == EcmaContext.TERNARY_FALSE and
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._context.parent.type in (EcmaContext.STATEMENT, EcmaContext.VAR)):
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return True
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # In all other contexts like object and array literals, ternary true, etc.
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # the statement can't yet end.
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return False
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _GetOperatorType(self, token):
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the operator type of the given operator token.
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      token: The token to get arity for.
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      The type of the operator.  One of the *_OPERATOR constants defined in
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EcmaMetaData.
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if token.string == '?':
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return EcmaMetaData.TERNARY_OPERATOR
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if token.string in TokenType.UNARY_OPERATORS:
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return EcmaMetaData.UNARY_OPERATOR
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_code = token.metadata.last_code
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not last_code or last_code.type == TokenType.END_BLOCK:
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return EcmaMetaData.UNARY_OPERATOR
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (token.string in TokenType.UNARY_POST_OPERATORS and
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        last_code.type in TokenType.EXPRESSION_ENDER_TYPES):
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return EcmaMetaData.UNARY_POST_OPERATOR
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (token.string in TokenType.UNARY_OK_OPERATORS and
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        last_code.type not in TokenType.EXPRESSION_ENDER_TYPES and
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        last_code.string not in TokenType.UNARY_POST_OPERATORS):
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return EcmaMetaData.UNARY_OPERATOR
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return EcmaMetaData.BINARY_OPERATOR
522