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