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