|
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 "frontend/ParseNode.h" |
|
11 #include "frontend/TokenStream.h" |
|
12 |
|
13 namespace js { |
|
14 namespace frontend { |
|
15 |
|
16 template <typename ParseHandler> |
|
17 class Parser; |
|
18 |
|
19 // Parse handler used when processing the syntax in a block of code, to generate |
|
20 // the minimal information which is required to detect syntax errors and allow |
|
21 // bytecode to be emitted for outer functions. |
|
22 // |
|
23 // When parsing, we start at the top level with a full parse, and when possible |
|
24 // only check the syntax for inner functions, so that they can be lazily parsed |
|
25 // into bytecode when/if they first run. Checking the syntax of a function is |
|
26 // several times faster than doing a full parse/emit, and lazy parsing improves |
|
27 // both performance and memory usage significantly when pages contain large |
|
28 // amounts of code that never executes (which happens often). |
|
29 class SyntaxParseHandler |
|
30 { |
|
31 // Remember the last encountered name or string literal during syntax parses. |
|
32 JSAtom *lastAtom; |
|
33 TokenPos lastStringPos; |
|
34 TokenStream &tokenStream; |
|
35 |
|
36 public: |
|
37 enum Node { |
|
38 NodeFailure = 0, |
|
39 NodeGeneric, |
|
40 NodeName, |
|
41 NodeGetProp, |
|
42 NodeString, |
|
43 NodeStringExprStatement, |
|
44 NodeLValue |
|
45 }; |
|
46 typedef Definition::Kind DefinitionNode; |
|
47 |
|
48 SyntaxParseHandler(ExclusiveContext *cx, LifoAlloc &alloc, |
|
49 TokenStream &tokenStream, bool foldConstants, |
|
50 Parser<SyntaxParseHandler> *syntaxParser, LazyScript *lazyOuterFunction) |
|
51 : lastAtom(nullptr), |
|
52 tokenStream(tokenStream) |
|
53 {} |
|
54 |
|
55 static Node null() { return NodeFailure; } |
|
56 |
|
57 void trace(JSTracer *trc) {} |
|
58 |
|
59 Node newName(PropertyName *name, uint32_t blockid, const TokenPos &pos) { |
|
60 lastAtom = name; |
|
61 return NodeName; |
|
62 } |
|
63 |
|
64 DefinitionNode newPlaceholder(JSAtom *atom, uint32_t blockid, const TokenPos &pos) { |
|
65 return Definition::PLACEHOLDER; |
|
66 } |
|
67 |
|
68 Node newIdentifier(JSAtom *atom, const TokenPos &pos) { return NodeString; } |
|
69 Node newNumber(double value, DecimalPoint decimalPoint, const TokenPos &pos) { return NodeGeneric; } |
|
70 Node newBooleanLiteral(bool cond, const TokenPos &pos) { return NodeGeneric; } |
|
71 |
|
72 Node newStringLiteral(JSAtom *atom, const TokenPos &pos) { |
|
73 lastAtom = atom; |
|
74 lastStringPos = pos; |
|
75 return NodeString; |
|
76 } |
|
77 |
|
78 Node newThisLiteral(const TokenPos &pos) { return NodeGeneric; } |
|
79 Node newNullLiteral(const TokenPos &pos) { return NodeGeneric; } |
|
80 |
|
81 template <class Boxer> |
|
82 Node newRegExp(JSObject *reobj, const TokenPos &pos, Boxer &boxer) { return NodeGeneric; } |
|
83 |
|
84 Node newConditional(Node cond, Node thenExpr, Node elseExpr) { return NodeGeneric; } |
|
85 |
|
86 Node newElision() { return NodeGeneric; } |
|
87 |
|
88 Node newDelete(uint32_t begin, Node expr) { return NodeGeneric; } |
|
89 |
|
90 Node newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, Node kid) { |
|
91 return NodeGeneric; |
|
92 } |
|
93 |
|
94 Node newBinary(ParseNodeKind kind, JSOp op = JSOP_NOP) { return NodeGeneric; } |
|
95 Node newBinary(ParseNodeKind kind, Node left, JSOp op = JSOP_NOP) { return NodeGeneric; } |
|
96 Node newBinary(ParseNodeKind kind, Node left, Node right, JSOp op = JSOP_NOP) { |
|
97 return NodeGeneric; |
|
98 } |
|
99 Node newBinaryOrAppend(ParseNodeKind kind, Node left, Node right, |
|
100 ParseContext<SyntaxParseHandler> *pc, JSOp op = JSOP_NOP) { |
|
101 return NodeGeneric; |
|
102 } |
|
103 |
|
104 Node newTernary(ParseNodeKind kind, Node first, Node second, Node third, JSOp op = JSOP_NOP) { |
|
105 return NodeGeneric; |
|
106 } |
|
107 |
|
108 // Expressions |
|
109 |
|
110 Node newArrayComprehension(Node body, unsigned blockid, const TokenPos &pos) { |
|
111 return NodeGeneric; |
|
112 } |
|
113 Node newArrayLiteral(uint32_t begin, unsigned blockid) { return NodeGeneric; } |
|
114 bool addElision(Node literal, const TokenPos &pos) { return true; } |
|
115 bool addSpreadElement(Node literal, uint32_t begin, Node inner) { return true; } |
|
116 bool addArrayElement(Node literal, Node element) { return true; } |
|
117 |
|
118 Node newObjectLiteral(uint32_t begin) { return NodeGeneric; } |
|
119 bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; } |
|
120 bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; } |
|
121 bool addShorthandPropertyDefinition(Node literal, Node name) { return true; } |
|
122 bool addAccessorPropertyDefinition(Node literal, Node name, Node fn, JSOp op) { return true; } |
|
123 |
|
124 // Statements |
|
125 |
|
126 Node newStatementList(unsigned blockid, const TokenPos &pos) { return NodeGeneric; } |
|
127 void addStatementToList(Node list, Node stmt, ParseContext<SyntaxParseHandler> *pc) {} |
|
128 Node newEmptyStatement(const TokenPos &pos) { return NodeGeneric; } |
|
129 |
|
130 Node newExprStatement(Node expr, uint32_t end) { |
|
131 return expr == NodeString ? NodeStringExprStatement : NodeGeneric; |
|
132 } |
|
133 |
|
134 Node newIfStatement(uint32_t begin, Node cond, Node then, Node else_) { return NodeGeneric; } |
|
135 Node newDoWhileStatement(Node body, Node cond, const TokenPos &pos) { return NodeGeneric; } |
|
136 Node newWhileStatement(uint32_t begin, Node cond, Node body) { return NodeGeneric; } |
|
137 Node newSwitchStatement(uint32_t begin, Node discriminant, Node caseList) { return NodeGeneric; } |
|
138 Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { return NodeGeneric; } |
|
139 Node newContinueStatement(PropertyName *label, const TokenPos &pos) { return NodeGeneric; } |
|
140 Node newBreakStatement(PropertyName *label, const TokenPos &pos) { return NodeGeneric; } |
|
141 Node newReturnStatement(Node expr, const TokenPos &pos) { return NodeGeneric; } |
|
142 |
|
143 Node newLabeledStatement(PropertyName *label, Node stmt, uint32_t begin) { |
|
144 return NodeGeneric; |
|
145 } |
|
146 |
|
147 Node newThrowStatement(Node expr, const TokenPos &pos) { return NodeGeneric; } |
|
148 Node newTryStatement(uint32_t begin, Node body, Node catchList, Node finallyBlock) { |
|
149 return NodeGeneric; |
|
150 } |
|
151 Node newDebuggerStatement(const TokenPos &pos) { return NodeGeneric; } |
|
152 |
|
153 Node newPropertyAccess(Node pn, PropertyName *name, uint32_t end) { |
|
154 lastAtom = name; |
|
155 return NodeGetProp; |
|
156 } |
|
157 |
|
158 Node newPropertyByValue(Node pn, Node kid, uint32_t end) { return NodeLValue; } |
|
159 |
|
160 bool addCatchBlock(Node catchList, Node letBlock, |
|
161 Node catchName, Node catchGuard, Node catchBody) { return true; } |
|
162 |
|
163 void setLastFunctionArgumentDefault(Node funcpn, Node pn) {} |
|
164 Node newFunctionDefinition() { return NodeGeneric; } |
|
165 void setFunctionBody(Node pn, Node kid) {} |
|
166 void setFunctionBox(Node pn, FunctionBox *funbox) {} |
|
167 void addFunctionArgument(Node pn, Node argpn) {} |
|
168 |
|
169 Node newForStatement(uint32_t begin, Node forHead, Node body, unsigned iflags) { |
|
170 return NodeGeneric; |
|
171 } |
|
172 |
|
173 Node newForHead(ParseNodeKind kind, Node decls, Node lhs, Node rhs, const TokenPos &pos) { |
|
174 return NodeGeneric; |
|
175 } |
|
176 |
|
177 Node newLexicalScope(ObjectBox *blockbox) { return NodeGeneric; } |
|
178 void setLexicalScopeBody(Node block, Node body) {} |
|
179 |
|
180 bool isOperationWithoutParens(Node pn, ParseNodeKind kind) { |
|
181 // It is OK to return false here, callers should only use this method |
|
182 // for reporting strict option warnings and parsing code which the |
|
183 // syntax parser does not handle. |
|
184 return false; |
|
185 } |
|
186 |
|
187 bool finishInitializerAssignment(Node pn, Node init, JSOp op) { return true; } |
|
188 |
|
189 void setBeginPosition(Node pn, Node oth) {} |
|
190 void setBeginPosition(Node pn, uint32_t begin) {} |
|
191 |
|
192 void setEndPosition(Node pn, Node oth) {} |
|
193 void setEndPosition(Node pn, uint32_t end) {} |
|
194 |
|
195 |
|
196 void setPosition(Node pn, const TokenPos &pos) {} |
|
197 TokenPos getPosition(Node pn) { |
|
198 return tokenStream.currentToken().pos; |
|
199 } |
|
200 |
|
201 Node newList(ParseNodeKind kind, Node kid = NodeGeneric, JSOp op = JSOP_NOP) { |
|
202 return NodeGeneric; |
|
203 } |
|
204 void addList(Node pn, Node kid) {} |
|
205 bool isUnparenthesizedYield(Node pn) { return false; } |
|
206 |
|
207 void setOp(Node pn, JSOp op) {} |
|
208 void setBlockId(Node pn, unsigned blockid) {} |
|
209 void setFlag(Node pn, unsigned flag) {} |
|
210 void setListFlag(Node pn, unsigned flag) {} |
|
211 Node setInParens(Node pn) { |
|
212 // String literals enclosed by parentheses are ignored during |
|
213 // strict mode parsing. |
|
214 return NodeGeneric; |
|
215 } |
|
216 void setPrologue(Node pn) {} |
|
217 |
|
218 bool isConstant(Node pn) { return false; } |
|
219 PropertyName *isName(Node pn) { |
|
220 return (pn == NodeName) ? lastAtom->asPropertyName() : nullptr; |
|
221 } |
|
222 PropertyName *isGetProp(Node pn) { |
|
223 return (pn == NodeGetProp) ? lastAtom->asPropertyName() : nullptr; |
|
224 } |
|
225 JSAtom *isStringExprStatement(Node pn, TokenPos *pos) { |
|
226 if (pn == NodeStringExprStatement) { |
|
227 *pos = lastStringPos; |
|
228 return lastAtom; |
|
229 } |
|
230 return nullptr; |
|
231 } |
|
232 |
|
233 Node makeAssignment(Node pn, Node rhs) { return NodeGeneric; } |
|
234 |
|
235 static Node getDefinitionNode(DefinitionNode dn) { return NodeGeneric; } |
|
236 static Definition::Kind getDefinitionKind(DefinitionNode dn) { return dn; } |
|
237 void linkUseToDef(Node pn, DefinitionNode dn) {} |
|
238 DefinitionNode resolve(DefinitionNode dn) { return dn; } |
|
239 void deoptimizeUsesWithin(DefinitionNode dn, const TokenPos &pos) {} |
|
240 bool dependencyCovered(Node pn, unsigned blockid, bool functionScope) { |
|
241 // Only resolve lexical dependencies in cases where a definition covers |
|
242 // the entire function. Not enough information is kept to compare the |
|
243 // dependency location with blockid. |
|
244 return functionScope; |
|
245 } |
|
246 |
|
247 static uintptr_t definitionToBits(DefinitionNode dn) { |
|
248 // Use a shift, as DefinitionList tags the lower bit of its associated union. |
|
249 return uintptr_t(dn << 1); |
|
250 } |
|
251 static DefinitionNode definitionFromBits(uintptr_t bits) { |
|
252 return (DefinitionNode) (bits >> 1); |
|
253 } |
|
254 static DefinitionNode nullDefinition() { |
|
255 return Definition::MISSING; |
|
256 } |
|
257 void disableSyntaxParser() { |
|
258 } |
|
259 }; |
|
260 |
|
261 } // namespace frontend |
|
262 } // namespace js |
|
263 |
|
264 #endif /* frontend_SyntaxParseHandler_h */ |