12da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#!/usr/bin/env python 22da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 32da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Copyright 2010 The Closure Linter Authors. All Rights Reserved. 42da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 52da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Licensed under the Apache License, Version 2.0 (the "License"); 62da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# you may not use this file except in compliance with the License. 72da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# You may obtain a copy of the License at 82da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 92da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# http://www.apache.org/licenses/LICENSE-2.0 102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Unless required by applicable law or agreed to in writing, software 122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# distributed under the License is distributed on an "AS-IS" BASIS, 132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# See the License for the specific language governing permissions and 152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# limitations under the License. 162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis"""Metadata pass for annotating tokens in EcmaScript files.""" 182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis__author__ = ('robbyw@google.com (Robert Walker)') 202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 212da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom closure_linter import javascripttokens 222da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom closure_linter import tokenutil 232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 252da489cd246702bee5938545b18a6f710ed214bcJamie GennisTokenType = javascripttokens.JavaScriptTokenType 262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 282da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass ParseError(Exception): 292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Exception indicating a parse error at the given token. 302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Attributes: 322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token: The token where the parse error occurred. 332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __init__(self, token, message=None): 362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Initialize a parse error at the given token with an optional message. 372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token: The token where the parse error occurred. 402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis message: A message describing the parse error. 412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Exception.__init__(self, message) 432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.token = token 442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 462da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass EcmaContext(object): 472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Context object for EcmaScript languages. 482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Attributes: 502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis type: The context type. 512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis start_token: The token where this context starts. 522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis end_token: The token where this context ends. 532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis parent: The parent context. 542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # The root context. 572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis ROOT = 'root' 582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # A block of code. 602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis BLOCK = 'block' 612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # A pseudo-block of code for a given case or default section. 632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis CASE_BLOCK = 'case_block' 642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Block of statements in a for loop's parentheses. 662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis FOR_GROUP_BLOCK = 'for_block' 672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # An implied block of code for 1 line if, while, and for statements 692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis IMPLIED_BLOCK = 'implied_block' 702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # An index in to an array or object. 722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis INDEX = 'index' 732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # An array literal in []. 752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis ARRAY_LITERAL = 'array_literal' 762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # An object literal in {}. 782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis OBJECT_LITERAL = 'object_literal' 792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # An individual element in an array or object literal. 812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis LITERAL_ELEMENT = 'literal_element' 822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # The portion of a ternary statement between ? and : 842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis TERNARY_TRUE = 'ternary_true' 852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # The portion of a ternary statment after : 872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis TERNARY_FALSE = 'ternary_false' 882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # The entire switch statment. This will contain a GROUP with the variable 902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # and a BLOCK with the code. 912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Since that BLOCK is not a normal block, it can not contain statements except 932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # for case and default. 942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis SWITCH = 'switch' 952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # A normal comment. 972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis COMMENT = 'comment' 982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # A JsDoc comment. 1002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis DOC = 'doc' 1012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # An individual statement. 1032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis STATEMENT = 'statement' 1042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Code within parentheses. 1062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis GROUP = 'group' 1072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Parameter names in a function declaration. 1092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis PARAMETERS = 'parameters' 1102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # A set of variable declarations appearing after the 'var' keyword. 1122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis VAR = 'var' 1132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Context types that are blocks. 1152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis BLOCK_TYPES = frozenset([ 1162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis ROOT, BLOCK, CASE_BLOCK, FOR_GROUP_BLOCK, IMPLIED_BLOCK]) 1172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __init__(self, type, start_token, parent): 1192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Initializes the context object. 1202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 1222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis type: The context type. 1232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis start_token: The token where this context starts. 1242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis parent: The parent context. 1252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 1262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.type = type 1272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.start_token = start_token 1282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.end_token = None 1292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.parent = parent 1302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __repr__(self): 1322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns a string representation of the context object.""" 1332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis stack = [] 1342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis context = self 1352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis while context: 1362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis stack.append(context.type) 1372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis context = context.parent 1382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return 'Context(%s)' % ' > '.join(stack) 1392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1412da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass EcmaMetaData(object): 1422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Token metadata for EcmaScript languages. 1432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Attributes: 1452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis last_code: The last code token to appear before this one. 1462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis context: The context this token appears in. 1472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis operator_type: The operator type, will be one of the *_OPERATOR constants 1482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis defined below. 1492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 1502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis UNARY_OPERATOR = 'unary' 1522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis UNARY_POST_OPERATOR = 'unary_post' 1542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis BINARY_OPERATOR = 'binary' 1562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis TERNARY_OPERATOR = 'ternary' 1582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __init__(self): 1602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Initializes a token metadata object.""" 1612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.last_code = None 1622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.context = None 1632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.operator_type = None 1642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.is_implied_semicolon = False 1652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.is_implied_block = False 1662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.is_implied_block_close = False 1672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __repr__(self): 1692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns a string representation of the context object.""" 1702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis parts = ['%r' % self.context] 1712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self.operator_type: 1722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis parts.append('optype: %r' % self.operator_type) 1732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self.is_implied_semicolon: 1742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis parts.append('implied;') 1752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return 'MetaData(%s)' % ', '.join(parts) 1762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def IsUnaryOperator(self): 1782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self.operator_type in (EcmaMetaData.UNARY_OPERATOR, 1792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis EcmaMetaData.UNARY_POST_OPERATOR) 1802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def IsUnaryPostOperator(self): 1822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self.operator_type == EcmaMetaData.UNARY_POST_OPERATOR 1832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1852da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass EcmaMetaDataPass(object): 1862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """A pass that iterates over all tokens and builds metadata about them.""" 1872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __init__(self): 1892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Initialize the meta data pass object.""" 1902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.Reset() 1912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Reset(self): 1932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Resets the metadata pass to prepare for the next file.""" 1942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._token = None 1952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._context = None 1962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.ROOT) 1972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_code = None 1982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _CreateContext(self, type): 2002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Overridable by subclasses to create the appropriate context type.""" 2012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return EcmaContext(type, self._token, self._context) 2022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _CreateMetaData(self): 2042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Overridable by subclasses to create the appropriate metadata type.""" 2052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return EcmaMetaData() 2062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _AddContext(self, type): 2082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Adds a context of the given type to the context stack. 2092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 2112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis type: The type of context to create 2122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 2132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._context = self._CreateContext(type) 2142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _PopContext(self): 2162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Moves up one level in the context stack. 2172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 2192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis The former context. 2202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Raises: 2222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis ParseError: If the root context is popped. 2232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 2242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis top_context = self._context 2252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis top_context.end_token = self._token 2262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._context = top_context.parent 2272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self._context: 2282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return top_context 2292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 2302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis raise ParseError(self._token) 2312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _PopContextType(self, *stop_types): 2332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Pops the context stack until a context of the given type is popped. 2342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 2362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis stop_types: The types of context to pop to - stops at the first match. 2372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 2392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis The context object of the given type that was popped. 2402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 2412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis last = None 2422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis while not last or last.type not in stop_types: 2432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis last = self._PopContext() 2442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return last 2452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _EndStatement(self): 2472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Process the end of a statement.""" 2482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._PopContextType(EcmaContext.STATEMENT) 2492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self._context.type == EcmaContext.IMPLIED_BLOCK: 2502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._token.metadata.is_implied_block_close = True 2512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._PopContext() 2522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _ProcessContext(self): 2542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Process the context at the current token. 2552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 2572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis The context that should be assigned to the current token, or None if 2582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis the current context after this method should be used. 2592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Raises: 2612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis ParseError: When the token appears in an invalid context. 2622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 2632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token = self._token 2642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token_type = token.type 2652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self._context.type in EcmaContext.BLOCK_TYPES: 2672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Whenever we're in a block, we add a statement context. We make an 2682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # exception for switch statements since they can only contain case: and 2692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # default: and therefore don't directly contain statements. 2702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # The block we add here may be immediately removed in some cases, but 2712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # that causes no harm. 2722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis parent = self._context.parent 2732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not parent or parent.type != EcmaContext.SWITCH: 2742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.STATEMENT) 2752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif self._context.type == EcmaContext.ARRAY_LITERAL: 2772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.LITERAL_ELEMENT) 2782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if token_type == TokenType.START_PAREN: 2802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self._last_code and self._last_code.IsKeyword('for'): 2812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # for loops contain multiple statements in the group unlike while, 2822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # switch, if, etc. 2832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.FOR_GROUP_BLOCK) 2842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 2852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.GROUP) 2862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif token_type == TokenType.END_PAREN: 2882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis result = self._PopContextType(EcmaContext.GROUP, 2892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis EcmaContext.FOR_GROUP_BLOCK) 2902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis keyword_token = result.start_token.metadata.last_code 2912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # keyword_token will not exist if the open paren is the first line of the 2922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # file, for example if all code is wrapped in an immediately executed 2932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # annonymous function. 2942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if keyword_token and keyword_token.string in ('if', 'for', 'while'): 2952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis next_code = tokenutil.SearchExcept(token, TokenType.NON_CODE_TYPES) 2962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if next_code.type != TokenType.START_BLOCK: 2972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Check for do-while. 2982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis is_do_while = False 2992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis pre_keyword_token = keyword_token.metadata.last_code 3002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if (pre_keyword_token and 3012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis pre_keyword_token.type == TokenType.END_BLOCK): 3022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis start_block_token = pre_keyword_token.metadata.context.start_token 3032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis is_do_while = start_block_token.metadata.last_code.string == 'do' 3042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # If it's not do-while, it's an implied block. 3062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not is_do_while: 3072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.IMPLIED_BLOCK) 3082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token.metadata.is_implied_block = True 3092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return result 3112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # else (not else if) with no open brace after it should be considered the 3132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # start of an implied block, similar to the case with if, for, and while 3142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # above. 3152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif (token_type == TokenType.KEYWORD and 3162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token.string == 'else'): 3172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis next_code = tokenutil.SearchExcept(token, TokenType.NON_CODE_TYPES) 3182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if (next_code.type != TokenType.START_BLOCK and 3192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis (next_code.type != TokenType.KEYWORD or next_code.string != 'if')): 3202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.IMPLIED_BLOCK) 3212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token.metadata.is_implied_block = True 3222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif token_type == TokenType.START_PARAMETERS: 3242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.PARAMETERS) 3252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif token_type == TokenType.END_PARAMETERS: 3272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._PopContextType(EcmaContext.PARAMETERS) 3282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif token_type == TokenType.START_BRACKET: 3302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if (self._last_code and 3312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_code.type in TokenType.EXPRESSION_ENDER_TYPES): 3322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.INDEX) 3332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 3342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.ARRAY_LITERAL) 3352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif token_type == TokenType.END_BRACKET: 3372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._PopContextType(EcmaContext.INDEX, EcmaContext.ARRAY_LITERAL) 3382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif token_type == TokenType.START_BLOCK: 3402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if (self._last_code.type in (TokenType.END_PAREN, 3412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis TokenType.END_PARAMETERS) or 3422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_code.IsKeyword('else') or 3432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_code.IsKeyword('do') or 3442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_code.IsKeyword('try') or 3452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_code.IsKeyword('finally') or 3462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis (self._last_code.IsOperator(':') and 3472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_code.metadata.context.type == EcmaContext.CASE_BLOCK)): 3482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # else, do, try, and finally all might have no () before {. 3492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Also, handle the bizzare syntax case 10: {...}. 3502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.BLOCK) 3512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 3522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.OBJECT_LITERAL) 3532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif token_type == TokenType.END_BLOCK: 3552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis context = self._PopContextType(EcmaContext.BLOCK, 3562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis EcmaContext.OBJECT_LITERAL) 3572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self._context.type == EcmaContext.SWITCH: 3582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # The end of the block also means the end of the switch statement it 3592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # applies to. 3602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._PopContext() 3612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return context 3622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif token.IsKeyword('switch'): 3642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.SWITCH) 3652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif (token_type == TokenType.KEYWORD and 3672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token.string in ('case', 'default')): 3682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Pop up to but not including the switch block. 3692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis while self._context.parent.type != EcmaContext.SWITCH: 3702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._PopContext() 3712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif token.IsOperator('?'): 3732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.TERNARY_TRUE) 3742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif token.IsOperator(':'): 3762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self._context.type == EcmaContext.OBJECT_LITERAL: 3772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.LITERAL_ELEMENT) 3782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif self._context.type == EcmaContext.TERNARY_TRUE: 3802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._PopContext() 3812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.TERNARY_FALSE) 3822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Handle nested ternary statements like: 3842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # foo = bar ? baz ? 1 : 2 : 3 3852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # When we encounter the second ":" the context is 3862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # ternary_false > ternary_true > statement > root 3872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif (self._context.type == EcmaContext.TERNARY_FALSE and 3882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._context.parent.type == EcmaContext.TERNARY_TRUE): 3892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._PopContext() # Leave current ternary false context. 3902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._PopContext() # Leave current parent ternary true 3912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.TERNARY_FALSE) 3922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif self._context.parent.type == EcmaContext.SWITCH: 3942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.CASE_BLOCK) 3952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif token.IsKeyword('var'): 3972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._AddContext(EcmaContext.VAR) 3982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif token.IsOperator(','): 4002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis while self._context.type not in (EcmaContext.VAR, 4012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis EcmaContext.ARRAY_LITERAL, 4022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis EcmaContext.OBJECT_LITERAL, 4032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis EcmaContext.STATEMENT, 4042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis EcmaContext.PARAMETERS, 4052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis EcmaContext.GROUP): 4062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._PopContext() 4072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif token_type == TokenType.SEMICOLON: 4092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._EndStatement() 4102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Process(self, first_token): 4122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Processes the token stream starting with the given token.""" 4132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._token = first_token 4142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis while self._token: 4152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._ProcessToken() 4162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self._token.IsCode(): 4182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_code = self._token 4192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._token = self._token.next 4212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis try: 4232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._PopContextType(self, EcmaContext.ROOT) 4242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis except ParseError: 4252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Ignore the "popped to root" error. 4262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis pass 4272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _ProcessToken(self): 4292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Process the given token.""" 4302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token = self._token 4312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token.metadata = self._CreateMetaData() 4322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis context = (self._ProcessContext() or self._context) 4332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token.metadata.context = context 4342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token.metadata.last_code = self._last_code 4352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Determine the operator type of the token, if applicable. 4372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if token.type == TokenType.OPERATOR: 4382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token.metadata.operator_type = self._GetOperatorType(token) 4392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Determine if there is an implied semicolon after the token. 4412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if token.type != TokenType.SEMICOLON: 4422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis next_code = tokenutil.SearchExcept(token, TokenType.NON_CODE_TYPES) 4432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # A statement like if (x) does not need a semicolon after it 4442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis is_implied_block = self._context == EcmaContext.IMPLIED_BLOCK 4452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis is_last_code_in_line = token.IsCode() and ( 4462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis not next_code or next_code.line_number != token.line_number) 4472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis is_continued_identifier = (token.type == TokenType.IDENTIFIER and 4482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token.string.endswith('.')) 4492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis is_continued_operator = (token.type == TokenType.OPERATOR and 4502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis not token.metadata.IsUnaryPostOperator()) 4512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis is_continued_dot = token.string == '.' 4522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis next_code_is_operator = next_code and next_code.type == TokenType.OPERATOR 4532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis next_code_is_dot = next_code and next_code.string == '.' 4542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis is_end_of_block = (token.type == TokenType.END_BLOCK and 4552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token.metadata.context.type != EcmaContext.OBJECT_LITERAL) 4562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis is_multiline_string = token.type == TokenType.STRING_TEXT 4572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis next_code_is_block = next_code and next_code.type == TokenType.START_BLOCK 4582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if (is_last_code_in_line and 4592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._StatementCouldEndInContext() and 4602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis not is_multiline_string and 4612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis not is_end_of_block and 4622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis not is_continued_identifier and 4632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis not is_continued_operator and 4642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis not is_continued_dot and 4652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis not next_code_is_dot and 4662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis not next_code_is_operator and 4672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis not is_implied_block and 4682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis not next_code_is_block): 4692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token.metadata.is_implied_semicolon = True 4702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._EndStatement() 4712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _StatementCouldEndInContext(self): 4732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns whether the current statement (if any) may end in this context.""" 4742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # In the basic statement or variable declaration context, statement can 4752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # always end in this context. 4762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self._context.type in (EcmaContext.STATEMENT, EcmaContext.VAR): 4772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return True 4782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # End of a ternary false branch inside a statement can also be the 4802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # end of the statement, for example: 4812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # var x = foo ? foo.bar() : null 4822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # In this case the statement ends after the null, when the context stack 4832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # looks like ternary_false > var > statement > root. 4842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if (self._context.type == EcmaContext.TERNARY_FALSE and 4852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._context.parent.type in (EcmaContext.STATEMENT, EcmaContext.VAR)): 4862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return True 4872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # In all other contexts like object and array literals, ternary true, etc. 4892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # the statement can't yet end. 4902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return False 4912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _GetOperatorType(self, token): 4932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns the operator type of the given operator token. 4942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 4962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token: The token to get arity for. 4972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 4992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis The type of the operator. One of the *_OPERATOR constants defined in 5002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis EcmaMetaData. 5012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 5022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if token.string == '?': 5032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return EcmaMetaData.TERNARY_OPERATOR 5042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if token.string in TokenType.UNARY_OPERATORS: 5062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return EcmaMetaData.UNARY_OPERATOR 5072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis last_code = token.metadata.last_code 5092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not last_code or last_code.type == TokenType.END_BLOCK: 5102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return EcmaMetaData.UNARY_OPERATOR 5112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if (token.string in TokenType.UNARY_POST_OPERATORS and 5132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis last_code.type in TokenType.EXPRESSION_ENDER_TYPES): 5142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return EcmaMetaData.UNARY_POST_OPERATOR 5152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if (token.string in TokenType.UNARY_OK_OPERATORS and 5172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis last_code.type not in TokenType.EXPRESSION_ENDER_TYPES and 5182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis last_code.string not in TokenType.UNARY_POST_OPERATORS): 5192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return EcmaMetaData.UNARY_OPERATOR 5202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return EcmaMetaData.BINARY_OPERATOR 522