1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * vim: set ts=8 sts=4 et sw=4 tw=99: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef frontend_SyntaxParseHandler_h 8 #define frontend_SyntaxParseHandler_h 9 10 #include "mozilla/Attributes.h" 11 12 #include "frontend/ParseNode.h" 13 #include "frontend/TokenStream.h" 14 15 namespace js { 16 namespace frontend { 17 18 template <typename ParseHandler> 19 class Parser; 20 21 // Parse handler used when processing the syntax in a block of code, to generate 22 // the minimal information which is required to detect syntax errors and allow 23 // bytecode to be emitted for outer functions. 24 // 25 // When parsing, we start at the top level with a full parse, and when possible 26 // only check the syntax for inner functions, so that they can be lazily parsed 27 // into bytecode when/if they first run. Checking the syntax of a function is 28 // several times faster than doing a full parse/emit, and lazy parsing improves 29 // both performance and memory usage significantly when pages contain large 30 // amounts of code that never executes (which happens often). 31 class SyntaxParseHandler 32 { 33 // Remember the last encountered name or string literal during syntax parses. 34 JSAtom* lastAtom; 35 TokenPos lastStringPos; 36 TokenStream& tokenStream; 37 38 public: 39 enum Node { 40 NodeFailure = 0, 41 NodeGeneric, 42 NodeGetProp, 43 NodeStringExprStatement, 44 NodeReturn, 45 NodeHoistableDeclaration, 46 NodeBreak, 47 NodeThrow, 48 NodeEmptyStatement, 49 50 // This is needed for proper assignment-target handling. ES6 formally 51 // requires function calls *not* pass IsValidSimpleAssignmentTarget, 52 // but at last check there were still sites with |f() = 5| and similar 53 // in code not actually executed (or at least not executed enough to be 54 // noticed). 55 NodeFunctionCall, 56 57 // Nodes representing *parenthesized* IsValidSimpleAssignmentTarget 58 // nodes. We can't simply treat all such parenthesized nodes 59 // identically, because in assignment and increment/decrement contexts 60 // ES6 says that parentheses constitute a syntax error. 61 // 62 // var obj = {}; 63 // var val; 64 // (val) = 3; (obj.prop) = 4; // okay per ES5's little mind 65 // [(a)] = [3]; [(obj.prop)] = [4]; // invalid ES6 syntax 66 // // ...and so on for the other IsValidSimpleAssignmentTarget nodes 67 // 68 // We don't know in advance in the current parser when we're parsing 69 // in a place where name parenthesization changes meaning, so we must 70 // have multiple node values for these cases. 71 NodeParenthesizedArgumentsName, 72 NodeParenthesizedEvalName, 73 NodeParenthesizedName, 74 75 NodeDottedProperty, 76 NodeElement, 77 78 // Destructuring target patterns can't be parenthesized: |([a]) = [3];| 79 // must be a syntax error. (We can't use NodeGeneric instead of these 80 // because that would trigger invalid-left-hand-side ReferenceError 81 // semantics when SyntaxError semantics are desired.) 82 NodeParenthesizedArray, 83 NodeParenthesizedObject, 84 85 // In rare cases a parenthesized |node| doesn't have the same semantics 86 // as |node|. Each such node has a special Node value, and we use a 87 // different Node value to represent the parenthesized form. See also 88 // is{Unp,P}arenthesized*(Node), parenthesize(Node), and the various 89 // functions that deal in NodeUnparenthesized* below. 90 91 // Nodes representing unparenthesized names. 92 NodeUnparenthesizedArgumentsName, 93 NodeUnparenthesizedEvalName, 94 NodeUnparenthesizedName, 95 96 // Valuable for recognizing potential destructuring patterns. 97 NodeUnparenthesizedArray, 98 NodeUnparenthesizedObject, 99 100 // The directive prologue at the start of a FunctionBody or ScriptBody 101 // is the longest sequence (possibly empty) of string literal 102 // expression statements at the start of a function. Thus we need this 103 // to treat |"use strict";| as a possible Use Strict Directive and 104 // |("use strict");| as a useless statement. 105 NodeUnparenthesizedString, 106 107 // Legacy generator expressions of the form |(expr for (...))| and 108 // array comprehensions of the form |[expr for (...)]|) don't permit 109 // |expr| to be a comma expression. Thus we need this to treat 110 // |(a(), b for (x in []))| as a syntax error and 111 // |((a(), b) for (x in []))| as a generator that calls |a| and then 112 // yields |b| each time it's resumed. 113 NodeUnparenthesizedCommaExpr, 114 115 // Yield expressions currently (but not in ES6 -- a SpiderMonkey bug to 116 // fix) must generally be parenthesized. (See the uses of 117 // isUnparenthesizedYieldExpression in Parser.cpp for the rare 118 // exceptions.) Thus we need this to treat |yield 1, 2;| as a syntax 119 // error and |(yield 1), 2;| as a comma expression that will yield 1, 120 // then evaluate to 2. 121 NodeUnparenthesizedYieldExpr, 122 123 // Assignment expressions in condition contexts could be typos for 124 // equality checks. (Think |if (x = y)| versus |if (x == y)|.) Thus 125 // we need this to treat |if (x = y)| as a possible typo and 126 // |if ((x = y))| as a deliberate assignment within a condition. 127 // 128 // (Technically this isn't needed, as these are *only* extraWarnings 129 // warnings, and parsing with that option disables syntax parsing. But 130 // it seems best to be consistent, and perhaps the syntax parser will 131 // eventually enforce extraWarnings and will require this then.) 132 NodeUnparenthesizedAssignment, 133 134 // This node is necessary to determine if the LHS of a property access is 135 // super related. 136 NodeSuperBase 137 }; 138 typedef Definition::Kind DefinitionNode; 139 isPropertyAccess(Node node)140 bool isPropertyAccess(Node node) { 141 return node == NodeDottedProperty || node == NodeElement; 142 } 143 isFunctionCall(Node node)144 bool isFunctionCall(Node node) { 145 // Note: super() is a special form, *not* a function call. 146 return node == NodeFunctionCall; 147 } 148 isUnparenthesizedDestructuringPattern(Node node)149 static bool isUnparenthesizedDestructuringPattern(Node node) { 150 return node == NodeUnparenthesizedArray || node == NodeUnparenthesizedObject; 151 } 152 isParenthesizedDestructuringPattern(Node node)153 static bool isParenthesizedDestructuringPattern(Node node) { 154 // Technically this isn't a destructuring target at all -- the grammar 155 // doesn't treat it as such. But we need to know when this happens to 156 // consider it a SyntaxError rather than an invalid-left-hand-side 157 // ReferenceError. 158 return node == NodeParenthesizedArray || node == NodeParenthesizedObject; 159 } 160 isDestructuringPatternAnyParentheses(Node node)161 static bool isDestructuringPatternAnyParentheses(Node node) { 162 return isUnparenthesizedDestructuringPattern(node) || 163 isParenthesizedDestructuringPattern(node); 164 } 165 166 public: SyntaxParseHandler(ExclusiveContext * cx,LifoAlloc & alloc,TokenStream & tokenStream,Parser<SyntaxParseHandler> * syntaxParser,LazyScript * lazyOuterFunction)167 SyntaxParseHandler(ExclusiveContext* cx, LifoAlloc& alloc, 168 TokenStream& tokenStream, Parser<SyntaxParseHandler>* syntaxParser, 169 LazyScript* lazyOuterFunction) 170 : lastAtom(nullptr), 171 tokenStream(tokenStream) 172 {} 173 null()174 static Node null() { return NodeFailure; } 175 prepareNodeForMutation(Node node)176 void prepareNodeForMutation(Node node) {} freeTree(Node node)177 void freeTree(Node node) {} 178 trace(JSTracer * trc)179 void trace(JSTracer* trc) {} 180 newName(PropertyName * name,uint32_t blockid,const TokenPos & pos,ExclusiveContext * cx)181 Node newName(PropertyName* name, uint32_t blockid, const TokenPos& pos, ExclusiveContext* cx) { 182 lastAtom = name; 183 if (name == cx->names().arguments) 184 return NodeUnparenthesizedArgumentsName; 185 if (name == cx->names().eval) 186 return NodeUnparenthesizedEvalName; 187 return NodeUnparenthesizedName; 188 } 189 newComputedName(Node expr,uint32_t start,uint32_t end)190 Node newComputedName(Node expr, uint32_t start, uint32_t end) { 191 return NodeGeneric; 192 } 193 newPlaceholder(JSAtom * atom,uint32_t blockid,const TokenPos & pos)194 DefinitionNode newPlaceholder(JSAtom* atom, uint32_t blockid, const TokenPos& pos) { 195 return Definition::PLACEHOLDER; 196 } 197 newObjectLiteralPropertyName(JSAtom * atom,const TokenPos & pos)198 Node newObjectLiteralPropertyName(JSAtom* atom, const TokenPos& pos) { 199 return NodeUnparenthesizedName; 200 } 201 newNumber(double value,DecimalPoint decimalPoint,const TokenPos & pos)202 Node newNumber(double value, DecimalPoint decimalPoint, const TokenPos& pos) { return NodeGeneric; } newBooleanLiteral(bool cond,const TokenPos & pos)203 Node newBooleanLiteral(bool cond, const TokenPos& pos) { return NodeGeneric; } 204 newStringLiteral(JSAtom * atom,const TokenPos & pos)205 Node newStringLiteral(JSAtom* atom, const TokenPos& pos) { 206 lastAtom = atom; 207 lastStringPos = pos; 208 return NodeUnparenthesizedString; 209 } 210 newTemplateStringLiteral(JSAtom * atom,const TokenPos & pos)211 Node newTemplateStringLiteral(JSAtom* atom, const TokenPos& pos) { 212 return NodeGeneric; 213 } 214 newCallSiteObject(uint32_t begin)215 Node newCallSiteObject(uint32_t begin) { 216 return NodeGeneric; 217 } 218 addToCallSiteObject(Node callSiteObj,Node rawNode,Node cookedNode)219 bool addToCallSiteObject(Node callSiteObj, Node rawNode, Node cookedNode) { 220 return true; 221 } 222 newThisLiteral(const TokenPos & pos,Node thisName)223 Node newThisLiteral(const TokenPos& pos, Node thisName) { return NodeGeneric; } newNullLiteral(const TokenPos & pos)224 Node newNullLiteral(const TokenPos& pos) { return NodeGeneric; } 225 226 template <class Boxer> newRegExp(RegExpObject * reobj,const TokenPos & pos,Boxer & boxer)227 Node newRegExp(RegExpObject* reobj, const TokenPos& pos, Boxer& boxer) { return NodeGeneric; } 228 newConditional(Node cond,Node thenExpr,Node elseExpr)229 Node newConditional(Node cond, Node thenExpr, Node elseExpr) { return NodeGeneric; } 230 newElision()231 Node newElision() { return NodeGeneric; } 232 markAsSetCall(Node node)233 void markAsSetCall(Node node) { 234 MOZ_ASSERT(node == NodeFunctionCall); 235 } 236 newDelete(uint32_t begin,Node expr)237 Node newDelete(uint32_t begin, Node expr) { 238 return NodeGeneric; 239 } 240 newTypeof(uint32_t begin,Node kid)241 Node newTypeof(uint32_t begin, Node kid) { 242 return NodeGeneric; 243 } 244 newUnary(ParseNodeKind kind,JSOp op,uint32_t begin,Node kid)245 Node newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, Node kid) { 246 return NodeGeneric; 247 } 248 249 Node newBinary(ParseNodeKind kind, JSOp op = JSOP_NOP) { return NodeGeneric; } 250 Node newBinary(ParseNodeKind kind, Node left, JSOp op = JSOP_NOP) { return NodeGeneric; } 251 Node newBinary(ParseNodeKind kind, Node left, Node right, JSOp op = JSOP_NOP) { 252 return NodeGeneric; 253 } 254 Node appendOrCreateList(ParseNodeKind kind, Node left, Node right, 255 ParseContext<SyntaxParseHandler>* pc, JSOp op = JSOP_NOP) { 256 return NodeGeneric; 257 } 258 259 Node newTernary(ParseNodeKind kind, Node first, Node second, Node third, JSOp op = JSOP_NOP) { 260 return NodeGeneric; 261 } 262 263 // Expressions 264 newArrayComprehension(Node body,const TokenPos & pos)265 Node newArrayComprehension(Node body, const TokenPos& pos) { return NodeGeneric; } newArrayLiteral(uint32_t begin)266 Node newArrayLiteral(uint32_t begin) { return NodeUnparenthesizedArray; } addElision(Node literal,const TokenPos & pos)267 bool addElision(Node literal, const TokenPos& pos) { return true; } addSpreadElement(Node literal,uint32_t begin,Node inner)268 bool addSpreadElement(Node literal, uint32_t begin, Node inner) { return true; } addArrayElement(Node literal,Node element)269 void addArrayElement(Node literal, Node element) { } 270 newCall()271 Node newCall() { return NodeFunctionCall; } newTaggedTemplate()272 Node newTaggedTemplate() { return NodeGeneric; } 273 newObjectLiteral(uint32_t begin)274 Node newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; } newClassMethodList(uint32_t begin)275 Node newClassMethodList(uint32_t begin) { return NodeGeneric; } 276 newNewTarget(Node newHolder,Node targetHolder)277 Node newNewTarget(Node newHolder, Node targetHolder) { return NodeGeneric; } newPosHolder(const TokenPos & pos)278 Node newPosHolder(const TokenPos& pos) { return NodeGeneric; } newSuperBase(Node thisName,const TokenPos & pos)279 Node newSuperBase(Node thisName, const TokenPos& pos) { return NodeSuperBase; } 280 addPrototypeMutation(Node literal,uint32_t begin,Node expr)281 bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; } addPropertyDefinition(Node literal,Node name,Node expr)282 bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; } addShorthand(Node literal,Node name,Node expr)283 bool addShorthand(Node literal, Node name, Node expr) { return true; } addObjectMethodDefinition(Node literal,Node name,Node fn,JSOp op)284 bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; } addClassMethodDefinition(Node literal,Node name,Node fn,JSOp op,bool isStatic)285 bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; } newYieldExpression(uint32_t begin,Node value,Node gen)286 Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeUnparenthesizedYieldExpr; } newYieldStarExpression(uint32_t begin,Node value,Node gen)287 Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; } 288 289 // Statements 290 newStatementList(unsigned blockid,const TokenPos & pos)291 Node newStatementList(unsigned blockid, const TokenPos& pos) { return NodeGeneric; } addStatementToList(Node list,Node stmt,ParseContext<SyntaxParseHandler> * pc)292 void addStatementToList(Node list, Node stmt, ParseContext<SyntaxParseHandler>* pc) {} prependInitialYield(Node stmtList,Node gen)293 bool prependInitialYield(Node stmtList, Node gen) { return true; } newEmptyStatement(const TokenPos & pos)294 Node newEmptyStatement(const TokenPos& pos) { return NodeEmptyStatement; } 295 newSetThis(Node thisName,Node value)296 Node newSetThis(Node thisName, Node value) { return value; } 297 newExprStatement(Node expr,uint32_t end)298 Node newExprStatement(Node expr, uint32_t end) { 299 return expr == NodeUnparenthesizedString ? NodeStringExprStatement : NodeGeneric; 300 } 301 newIfStatement(uint32_t begin,Node cond,Node then,Node else_)302 Node newIfStatement(uint32_t begin, Node cond, Node then, Node else_) { return NodeGeneric; } newDoWhileStatement(Node body,Node cond,const TokenPos & pos)303 Node newDoWhileStatement(Node body, Node cond, const TokenPos& pos) { return NodeGeneric; } newWhileStatement(uint32_t begin,Node cond,Node body)304 Node newWhileStatement(uint32_t begin, Node cond, Node body) { return NodeGeneric; } newSwitchStatement(uint32_t begin,Node discriminant,Node caseList)305 Node newSwitchStatement(uint32_t begin, Node discriminant, Node caseList) { return NodeGeneric; } newCaseOrDefault(uint32_t begin,Node expr,Node body)306 Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { return NodeGeneric; } newContinueStatement(PropertyName * label,const TokenPos & pos)307 Node newContinueStatement(PropertyName* label, const TokenPos& pos) { return NodeGeneric; } newBreakStatement(PropertyName * label,const TokenPos & pos)308 Node newBreakStatement(PropertyName* label, const TokenPos& pos) { return NodeBreak; } newReturnStatement(Node expr,const TokenPos & pos)309 Node newReturnStatement(Node expr, const TokenPos& pos) { return NodeReturn; } 310 newLabeledStatement(PropertyName * label,Node stmt,uint32_t begin)311 Node newLabeledStatement(PropertyName* label, Node stmt, uint32_t begin) { 312 return NodeGeneric; 313 } 314 newThrowStatement(Node expr,const TokenPos & pos)315 Node newThrowStatement(Node expr, const TokenPos& pos) { return NodeThrow; } newTryStatement(uint32_t begin,Node body,Node catchList,Node finallyBlock)316 Node newTryStatement(uint32_t begin, Node body, Node catchList, Node finallyBlock) { 317 return NodeGeneric; 318 } newDebuggerStatement(const TokenPos & pos)319 Node newDebuggerStatement(const TokenPos& pos) { return NodeGeneric; } 320 newPropertyAccess(Node pn,PropertyName * name,uint32_t end)321 Node newPropertyAccess(Node pn, PropertyName* name, uint32_t end) { 322 lastAtom = name; 323 return NodeDottedProperty; 324 } 325 newPropertyByValue(Node pn,Node kid,uint32_t end)326 Node newPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeElement; } 327 addCatchBlock(Node catchList,Node letBlock,Node catchName,Node catchGuard,Node catchBody)328 bool addCatchBlock(Node catchList, Node letBlock, 329 Node catchName, Node catchGuard, Node catchBody) { return true; } 330 setLastFunctionArgumentDefault(Node funcpn,Node pn)331 bool setLastFunctionArgumentDefault(Node funcpn, Node pn) { return true; } setLastFunctionArgumentDestructuring(Node funcpn,Node pn)332 void setLastFunctionArgumentDestructuring(Node funcpn, Node pn) {} newFunctionDefinition()333 Node newFunctionDefinition() { return NodeHoistableDeclaration; } setFunctionBody(Node pn,Node kid)334 void setFunctionBody(Node pn, Node kid) {} setFunctionBox(Node pn,FunctionBox * funbox)335 void setFunctionBox(Node pn, FunctionBox* funbox) {} addFunctionArgument(Node pn,Node argpn)336 void addFunctionArgument(Node pn, Node argpn) {} 337 newForStatement(uint32_t begin,Node forHead,Node body,unsigned iflags)338 Node newForStatement(uint32_t begin, Node forHead, Node body, unsigned iflags) { 339 return NodeGeneric; 340 } 341 newComprehensionFor(uint32_t begin,Node forHead,Node body)342 Node newComprehensionFor(uint32_t begin, Node forHead, Node body) { 343 return NodeGeneric; 344 } 345 newForHead(ParseNodeKind kind,Node decls,Node lhs,Node rhs,const TokenPos & pos)346 Node newForHead(ParseNodeKind kind, Node decls, Node lhs, Node rhs, const TokenPos& pos) { 347 return NodeGeneric; 348 } 349 newLexicalScope(ObjectBox * blockbox)350 Node newLexicalScope(ObjectBox* blockbox) { return NodeGeneric; } setLexicalScopeBody(Node block,Node body)351 void setLexicalScopeBody(Node block, Node body) {} 352 newLetBlock(Node vars,Node block,const TokenPos & pos)353 Node newLetBlock(Node vars, Node block, const TokenPos& pos) { 354 return NodeGeneric; 355 } 356 finishInitializerAssignment(Node pn,Node init,JSOp op)357 bool finishInitializerAssignment(Node pn, Node init, JSOp op) { return true; } setLexicalDeclarationOp(Node pn,JSOp op)358 void setLexicalDeclarationOp(Node pn, JSOp op) {} 359 setBeginPosition(Node pn,Node oth)360 void setBeginPosition(Node pn, Node oth) {} setBeginPosition(Node pn,uint32_t begin)361 void setBeginPosition(Node pn, uint32_t begin) {} 362 setEndPosition(Node pn,Node oth)363 void setEndPosition(Node pn, Node oth) {} setEndPosition(Node pn,uint32_t end)364 void setEndPosition(Node pn, uint32_t end) {} 365 setDerivedClassConstructor(Node pn)366 void setDerivedClassConstructor(Node pn) {} 367 setPosition(Node pn,const TokenPos & pos)368 void setPosition(Node pn, const TokenPos& pos) {} getPosition(Node pn)369 TokenPos getPosition(Node pn) { 370 return tokenStream.currentToken().pos; 371 } 372 373 Node newList(ParseNodeKind kind, JSOp op = JSOP_NOP) { 374 MOZ_ASSERT(kind != PNK_VAR); 375 return NodeGeneric; 376 } 377 Node newList(ParseNodeKind kind, uint32_t begin, JSOp op = JSOP_NOP) { 378 return NodeGeneric; 379 } 380 Node newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) { 381 MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET); 382 return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric; 383 } 384 Node newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) { 385 MOZ_ASSERT(kind != PNK_VAR); 386 return NodeGeneric; 387 } 388 Node newDeclarationList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) { 389 MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET); 390 return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric; 391 } 392 newCatchList()393 Node newCatchList() { 394 return newList(PNK_CATCHLIST, JSOP_NOP); 395 } 396 newCommaExpressionList(Node kid)397 Node newCommaExpressionList(Node kid) { 398 return NodeUnparenthesizedCommaExpr; 399 } 400 addList(Node list,Node kid)401 void addList(Node list, Node kid) { 402 MOZ_ASSERT(list == NodeGeneric || 403 list == NodeUnparenthesizedArray || 404 list == NodeUnparenthesizedObject || 405 list == NodeUnparenthesizedCommaExpr || 406 list == NodeHoistableDeclaration || 407 list == NodeFunctionCall); 408 } 409 newAssignment(ParseNodeKind kind,Node lhs,Node rhs,ParseContext<SyntaxParseHandler> * pc,JSOp op)410 Node newAssignment(ParseNodeKind kind, Node lhs, Node rhs, 411 ParseContext<SyntaxParseHandler>* pc, JSOp op) 412 { 413 if (kind == PNK_ASSIGN) 414 return NodeUnparenthesizedAssignment; 415 return newBinary(kind, lhs, rhs, op); 416 } 417 isUnparenthesizedYieldExpression(Node node)418 bool isUnparenthesizedYieldExpression(Node node) { 419 return node == NodeUnparenthesizedYieldExpr; 420 } 421 isUnparenthesizedCommaExpression(Node node)422 bool isUnparenthesizedCommaExpression(Node node) { 423 return node == NodeUnparenthesizedCommaExpr; 424 } 425 isUnparenthesizedAssignment(Node node)426 bool isUnparenthesizedAssignment(Node node) { 427 return node == NodeUnparenthesizedAssignment; 428 } 429 isReturnStatement(Node node)430 bool isReturnStatement(Node node) { 431 return node == NodeReturn; 432 } 433 isStatementPermittedAfterReturnStatement(Node pn)434 bool isStatementPermittedAfterReturnStatement(Node pn) { 435 return pn == NodeHoistableDeclaration || pn == NodeBreak || pn == NodeThrow || 436 pn == NodeEmptyStatement; 437 } 438 isSuperBase(Node pn)439 bool isSuperBase(Node pn) { 440 return pn == NodeSuperBase; 441 } 442 setOp(Node pn,JSOp op)443 void setOp(Node pn, JSOp op) {} setBlockId(Node pn,unsigned blockid)444 void setBlockId(Node pn, unsigned blockid) {} setFlag(Node pn,unsigned flag)445 void setFlag(Node pn, unsigned flag) {} setListFlag(Node pn,unsigned flag)446 void setListFlag(Node pn, unsigned flag) {} parenthesize(Node node)447 MOZ_WARN_UNUSED_RESULT Node parenthesize(Node node) { 448 // A number of nodes have different behavior upon parenthesization, but 449 // only in some circumstances. Convert these nodes to special 450 // parenthesized forms. 451 if (node == NodeUnparenthesizedArgumentsName) 452 return NodeParenthesizedArgumentsName; 453 if (node == NodeUnparenthesizedEvalName) 454 return NodeParenthesizedEvalName; 455 if (node == NodeUnparenthesizedName) 456 return NodeParenthesizedName; 457 458 if (node == NodeUnparenthesizedArray) 459 return NodeParenthesizedArray; 460 if (node == NodeUnparenthesizedObject) 461 return NodeParenthesizedObject; 462 463 // Other nodes need not be recognizable after parenthesization; convert 464 // them to a generic node. 465 if (node == NodeUnparenthesizedString || 466 node == NodeUnparenthesizedCommaExpr || 467 node == NodeUnparenthesizedYieldExpr || 468 node == NodeUnparenthesizedAssignment) 469 { 470 return NodeGeneric; 471 } 472 473 // In all other cases, the parenthesized form of |node| is equivalent 474 // to the unparenthesized form: return |node| unchanged. 475 return node; 476 } setLikelyIIFE(Node pn)477 MOZ_WARN_UNUSED_RESULT Node setLikelyIIFE(Node pn) { 478 return pn; // Remain in syntax-parse mode. 479 } setPrologue(Node pn)480 void setPrologue(Node pn) {} 481 isConstant(Node pn)482 bool isConstant(Node pn) { return false; } 483 maybeUnparenthesizedName(Node node)484 PropertyName* maybeUnparenthesizedName(Node node) { 485 if (node == NodeUnparenthesizedName || 486 node == NodeUnparenthesizedArgumentsName || 487 node == NodeUnparenthesizedEvalName) 488 { 489 return lastAtom->asPropertyName(); 490 } 491 return nullptr; 492 } 493 maybeParenthesizedName(Node node)494 PropertyName* maybeParenthesizedName(Node node) { 495 if (node == NodeParenthesizedName || 496 node == NodeParenthesizedArgumentsName || 497 node == NodeParenthesizedEvalName) 498 { 499 return lastAtom->asPropertyName(); 500 } 501 return nullptr; 502 } 503 maybeNameAnyParentheses(Node node)504 PropertyName* maybeNameAnyParentheses(Node node) { 505 if (PropertyName* name = maybeUnparenthesizedName(node)) 506 return name; 507 return maybeParenthesizedName(node); 508 } 509 maybeDottedProperty(Node node)510 PropertyName* maybeDottedProperty(Node node) { 511 // Note: |super.apply(...)| is a special form that calls an "apply" 512 // method retrieved from one value, but using a *different* value as 513 // |this|. It's not really eligible for the funapply/funcall 514 // optimizations as they're currently implemented (assuming a single 515 // value is used for both retrieval and |this|). 516 if (node != NodeDottedProperty) 517 return nullptr; 518 return lastAtom->asPropertyName(); 519 } 520 isStringExprStatement(Node pn,TokenPos * pos)521 JSAtom* isStringExprStatement(Node pn, TokenPos* pos) { 522 if (pn == NodeStringExprStatement) { 523 *pos = lastStringPos; 524 return lastAtom; 525 } 526 return nullptr; 527 } 528 markAsAssigned(Node node)529 void markAsAssigned(Node node) {} adjustGetToSet(Node node)530 void adjustGetToSet(Node node) {} maybeDespecializeSet(Node node)531 void maybeDespecializeSet(Node node) {} 532 makeAssignment(Node pn,Node rhs)533 Node makeAssignment(Node pn, Node rhs) { return NodeGeneric; } 534 getDefinitionNode(DefinitionNode dn)535 static Node getDefinitionNode(DefinitionNode dn) { return NodeGeneric; } getDefinitionKind(DefinitionNode dn)536 static Definition::Kind getDefinitionKind(DefinitionNode dn) { return dn; } isPlaceholderDefinition(DefinitionNode dn)537 static bool isPlaceholderDefinition(DefinitionNode dn) { return dn == Definition::PLACEHOLDER; } linkUseToDef(Node pn,DefinitionNode dn)538 void linkUseToDef(Node pn, DefinitionNode dn) {} resolve(DefinitionNode dn)539 DefinitionNode resolve(DefinitionNode dn) { return dn; } deoptimizeUsesWithin(DefinitionNode dn,const TokenPos & pos)540 void deoptimizeUsesWithin(DefinitionNode dn, const TokenPos& pos) {} dependencyCovered(Node pn,unsigned blockid,bool functionScope)541 bool dependencyCovered(Node pn, unsigned blockid, bool functionScope) { 542 // Only resolve lexical dependencies in cases where a definition covers 543 // the entire function. Not enough information is kept to compare the 544 // dependency location with blockid. 545 return functionScope; 546 } markMaybeUninitializedLexicalUseInSwitch(Node pn,DefinitionNode dn,uint16_t firstDominatingLexicalSlot)547 void markMaybeUninitializedLexicalUseInSwitch(Node pn, DefinitionNode dn, 548 uint16_t firstDominatingLexicalSlot) {} 549 definitionToBits(DefinitionNode dn)550 static uintptr_t definitionToBits(DefinitionNode dn) { 551 // Use a shift, as DefinitionList tags the lower bit of its associated union. 552 return uintptr_t(dn << 1); 553 } definitionFromBits(uintptr_t bits)554 static DefinitionNode definitionFromBits(uintptr_t bits) { 555 return (DefinitionNode) (bits >> 1); 556 } nullDefinition()557 static DefinitionNode nullDefinition() { 558 return Definition::MISSING; 559 } disableSyntaxParser()560 void disableSyntaxParser() { 561 } 562 }; 563 564 } // namespace frontend 565 } // namespace js 566 567 #endif /* frontend_SyntaxParseHandler_h */ 568