|
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_FullParseHandler_h |
|
8 #define frontend_FullParseHandler_h |
|
9 |
|
10 #include "mozilla/PodOperations.h" |
|
11 |
|
12 #include "frontend/ParseNode.h" |
|
13 #include "frontend/SharedContext.h" |
|
14 |
|
15 namespace js { |
|
16 namespace frontend { |
|
17 |
|
18 template <typename ParseHandler> |
|
19 class Parser; |
|
20 |
|
21 class SyntaxParseHandler; |
|
22 |
|
23 // Parse handler used when generating a full parse tree for all code which the |
|
24 // parser encounters. |
|
25 class FullParseHandler |
|
26 { |
|
27 ParseNodeAllocator allocator; |
|
28 TokenStream &tokenStream; |
|
29 bool foldConstants; |
|
30 |
|
31 ParseNode *allocParseNode(size_t size) { |
|
32 JS_ASSERT(size == sizeof(ParseNode)); |
|
33 return static_cast<ParseNode *>(allocator.allocNode()); |
|
34 } |
|
35 |
|
36 ParseNode *cloneNode(const ParseNode &other) { |
|
37 ParseNode *node = allocParseNode(sizeof(ParseNode)); |
|
38 if (!node) |
|
39 return nullptr; |
|
40 mozilla::PodAssign(node, &other); |
|
41 return node; |
|
42 } |
|
43 |
|
44 /* |
|
45 * If this is a full parse to construct the bytecode for a function that |
|
46 * was previously lazily parsed, that lazy function and the current index |
|
47 * into its inner functions. We do not want to reparse the inner functions. |
|
48 */ |
|
49 LazyScript * const lazyOuterFunction_; |
|
50 size_t lazyInnerFunctionIndex; |
|
51 |
|
52 const TokenPos &pos() { |
|
53 return tokenStream.currentToken().pos; |
|
54 } |
|
55 |
|
56 public: |
|
57 |
|
58 /* |
|
59 * If non-nullptr, points to a syntax parser which can be used for inner |
|
60 * functions. Cleared if language features not handled by the syntax parser |
|
61 * are encountered, in which case all future activity will use the full |
|
62 * parser. |
|
63 */ |
|
64 Parser<SyntaxParseHandler> *syntaxParser; |
|
65 |
|
66 /* new_ methods for creating parse nodes. These report OOM on context. */ |
|
67 JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline) |
|
68 |
|
69 typedef ParseNode *Node; |
|
70 typedef Definition *DefinitionNode; |
|
71 |
|
72 FullParseHandler(ExclusiveContext *cx, LifoAlloc &alloc, |
|
73 TokenStream &tokenStream, bool foldConstants, |
|
74 Parser<SyntaxParseHandler> *syntaxParser, LazyScript *lazyOuterFunction) |
|
75 : allocator(cx, alloc), |
|
76 tokenStream(tokenStream), |
|
77 foldConstants(foldConstants), |
|
78 lazyOuterFunction_(lazyOuterFunction), |
|
79 lazyInnerFunctionIndex(0), |
|
80 syntaxParser(syntaxParser) |
|
81 {} |
|
82 |
|
83 static ParseNode *null() { return nullptr; } |
|
84 |
|
85 ParseNode *freeTree(ParseNode *pn) { return allocator.freeTree(pn); } |
|
86 void prepareNodeForMutation(ParseNode *pn) { return allocator.prepareNodeForMutation(pn); } |
|
87 const Token ¤tToken() { return tokenStream.currentToken(); } |
|
88 |
|
89 ParseNode *newName(PropertyName *name, uint32_t blockid, const TokenPos &pos) { |
|
90 return new_<NameNode>(PNK_NAME, JSOP_NAME, name, blockid, pos); |
|
91 } |
|
92 |
|
93 Definition *newPlaceholder(JSAtom *atom, uint32_t blockid, const TokenPos &pos) { |
|
94 Definition *dn = |
|
95 (Definition *) new_<NameNode>(PNK_NAME, JSOP_NOP, atom, blockid, pos); |
|
96 if (!dn) |
|
97 return nullptr; |
|
98 dn->setDefn(true); |
|
99 dn->pn_dflags |= PND_PLACEHOLDER; |
|
100 return dn; |
|
101 } |
|
102 |
|
103 ParseNode *newIdentifier(JSAtom *atom, const TokenPos &pos) { |
|
104 return new_<NullaryNode>(PNK_NAME, JSOP_NOP, pos, atom); |
|
105 } |
|
106 |
|
107 ParseNode *newNumber(double value, DecimalPoint decimalPoint, const TokenPos &pos) { |
|
108 ParseNode *pn = new_<NullaryNode>(PNK_NUMBER, pos); |
|
109 if (!pn) |
|
110 return nullptr; |
|
111 pn->initNumber(value, decimalPoint); |
|
112 return pn; |
|
113 } |
|
114 |
|
115 ParseNode *newBooleanLiteral(bool cond, const TokenPos &pos) { |
|
116 return new_<BooleanLiteral>(cond, pos); |
|
117 } |
|
118 |
|
119 ParseNode *newStringLiteral(JSAtom *atom, const TokenPos &pos) { |
|
120 return new_<NullaryNode>(PNK_STRING, JSOP_STRING, pos, atom); |
|
121 } |
|
122 |
|
123 ParseNode *newThisLiteral(const TokenPos &pos) { |
|
124 return new_<ThisLiteral>(pos); |
|
125 } |
|
126 |
|
127 ParseNode *newNullLiteral(const TokenPos &pos) { |
|
128 return new_<NullLiteral>(pos); |
|
129 } |
|
130 |
|
131 // The Boxer object here is any object that can allocate ObjectBoxes. |
|
132 // Specifically, a Boxer has a .newObjectBox(T) method that accepts a |
|
133 // Rooted<RegExpObject*> argument and returns an ObjectBox*. |
|
134 template <class Boxer> |
|
135 ParseNode *newRegExp(HandleObject reobj, const TokenPos &pos, Boxer &boxer) { |
|
136 ObjectBox *objbox = boxer.newObjectBox(reobj); |
|
137 if (!objbox) |
|
138 return null(); |
|
139 return new_<RegExpLiteral>(objbox, pos); |
|
140 } |
|
141 |
|
142 ParseNode *newConditional(ParseNode *cond, ParseNode *thenExpr, ParseNode *elseExpr) { |
|
143 return new_<ConditionalExpression>(cond, thenExpr, elseExpr); |
|
144 } |
|
145 |
|
146 void markAsSetCall(ParseNode *pn) { |
|
147 pn->pn_xflags |= PNX_SETCALL; |
|
148 } |
|
149 |
|
150 ParseNode *newDelete(uint32_t begin, ParseNode *expr) { |
|
151 if (expr->getKind() == PNK_NAME) { |
|
152 expr->pn_dflags |= PND_DEOPTIMIZED; |
|
153 expr->setOp(JSOP_DELNAME); |
|
154 } |
|
155 return newUnary(PNK_DELETE, JSOP_NOP, begin, expr); |
|
156 } |
|
157 |
|
158 ParseNode *newNullary(ParseNodeKind kind, JSOp op, const TokenPos &pos) { |
|
159 return new_<NullaryNode>(kind, op, pos); |
|
160 } |
|
161 |
|
162 ParseNode *newUnary(ParseNodeKind kind, JSOp op, uint32_t begin, ParseNode *kid) { |
|
163 TokenPos pos(begin, kid ? kid->pn_pos.end : begin + 1); |
|
164 return new_<UnaryNode>(kind, op, pos, kid); |
|
165 } |
|
166 |
|
167 ParseNode *newBinary(ParseNodeKind kind, JSOp op = JSOP_NOP) { |
|
168 return new_<BinaryNode>(kind, op, pos(), (ParseNode *) nullptr, (ParseNode *) nullptr); |
|
169 } |
|
170 ParseNode *newBinary(ParseNodeKind kind, ParseNode *left, |
|
171 JSOp op = JSOP_NOP) { |
|
172 return new_<BinaryNode>(kind, op, left->pn_pos, left, (ParseNode *) nullptr); |
|
173 } |
|
174 ParseNode *newBinary(ParseNodeKind kind, ParseNode *left, ParseNode *right, |
|
175 JSOp op = JSOP_NOP) { |
|
176 TokenPos pos(left->pn_pos.begin, right->pn_pos.end); |
|
177 return new_<BinaryNode>(kind, op, pos, left, right); |
|
178 } |
|
179 ParseNode *newBinaryOrAppend(ParseNodeKind kind, ParseNode *left, ParseNode *right, |
|
180 ParseContext<FullParseHandler> *pc, JSOp op = JSOP_NOP) |
|
181 { |
|
182 return ParseNode::newBinaryOrAppend(kind, op, left, right, this, pc, foldConstants); |
|
183 } |
|
184 |
|
185 ParseNode *newTernary(ParseNodeKind kind, |
|
186 ParseNode *first, ParseNode *second, ParseNode *third, |
|
187 JSOp op = JSOP_NOP) |
|
188 { |
|
189 return new_<TernaryNode>(kind, op, first, second, third); |
|
190 } |
|
191 |
|
192 // Expressions |
|
193 |
|
194 ParseNode *newArrayComprehension(ParseNode *body, unsigned blockid, const TokenPos &pos) { |
|
195 JS_ASSERT(pos.begin <= body->pn_pos.begin); |
|
196 JS_ASSERT(body->pn_pos.end <= pos.end); |
|
197 ParseNode *pn = new_<ListNode>(PNK_ARRAYCOMP, pos); |
|
198 if (!pn) |
|
199 return nullptr; |
|
200 pn->pn_blockid = blockid; |
|
201 pn->append(body); |
|
202 return pn; |
|
203 } |
|
204 |
|
205 ParseNode *newArrayLiteral(uint32_t begin, unsigned blockid) { |
|
206 ParseNode *literal = new_<ListNode>(PNK_ARRAY, TokenPos(begin, begin + 1)); |
|
207 // Later in this stack: remove dependency on this opcode. |
|
208 if (literal) { |
|
209 literal->setOp(JSOP_NEWINIT); |
|
210 literal->pn_blockid = blockid; |
|
211 } |
|
212 return literal; |
|
213 } |
|
214 |
|
215 bool addElision(ParseNode *literal, const TokenPos &pos) { |
|
216 ParseNode *elision = new_<NullaryNode>(PNK_ELISION, pos); |
|
217 if (!elision) |
|
218 return false; |
|
219 literal->append(elision); |
|
220 literal->pn_xflags |= PNX_SPECIALARRAYINIT | PNX_NONCONST; |
|
221 return true; |
|
222 } |
|
223 |
|
224 bool addSpreadElement(ParseNode *literal, uint32_t begin, ParseNode *inner) { |
|
225 TokenPos pos(begin, inner->pn_pos.end); |
|
226 ParseNode *spread = new_<UnaryNode>(PNK_SPREAD, JSOP_NOP, pos, inner); |
|
227 if (!spread) |
|
228 return null(); |
|
229 literal->append(spread); |
|
230 literal->pn_xflags |= PNX_SPECIALARRAYINIT | PNX_NONCONST; |
|
231 return true; |
|
232 } |
|
233 |
|
234 bool addArrayElement(ParseNode *literal, ParseNode *element) { |
|
235 if (!element->isConstant()) |
|
236 literal->pn_xflags |= PNX_NONCONST; |
|
237 literal->append(element); |
|
238 return true; |
|
239 } |
|
240 |
|
241 ParseNode *newObjectLiteral(uint32_t begin) { |
|
242 ParseNode *literal = new_<ListNode>(PNK_OBJECT, TokenPos(begin, begin + 1)); |
|
243 // Later in this stack: remove dependency on this opcode. |
|
244 if (literal) |
|
245 literal->setOp(JSOP_NEWINIT); |
|
246 return literal; |
|
247 } |
|
248 |
|
249 bool addPropertyDefinition(ParseNode *literal, ParseNode *name, ParseNode *expr) { |
|
250 ParseNode *propdef = newBinary(PNK_COLON, name, expr, JSOP_INITPROP); |
|
251 if (!propdef) |
|
252 return false; |
|
253 literal->append(propdef); |
|
254 return true; |
|
255 } |
|
256 |
|
257 bool addShorthandPropertyDefinition(ParseNode *literal, ParseNode *name) { |
|
258 JS_ASSERT(literal->isArity(PN_LIST)); |
|
259 literal->pn_xflags |= PNX_DESTRUCT | PNX_NONCONST; // XXX why PNX_DESTRUCT? |
|
260 return addPropertyDefinition(literal, name, name); |
|
261 } |
|
262 |
|
263 bool addAccessorPropertyDefinition(ParseNode *literal, ParseNode *name, ParseNode *fn, JSOp op) |
|
264 { |
|
265 JS_ASSERT(literal->isArity(PN_LIST)); |
|
266 literal->pn_xflags |= PNX_NONCONST; |
|
267 |
|
268 ParseNode *propdef = newBinary(PNK_COLON, name, fn, op); |
|
269 if (!propdef) |
|
270 return false; |
|
271 literal->append(propdef); |
|
272 return true; |
|
273 } |
|
274 |
|
275 // Statements |
|
276 |
|
277 ParseNode *newStatementList(unsigned blockid, const TokenPos &pos) { |
|
278 ParseNode *pn = new_<ListNode>(PNK_STATEMENTLIST, pos); |
|
279 if (pn) |
|
280 pn->pn_blockid = blockid; |
|
281 return pn; |
|
282 } |
|
283 |
|
284 template <typename PC> |
|
285 void addStatementToList(ParseNode *list, ParseNode *stmt, PC *pc) { |
|
286 JS_ASSERT(list->isKind(PNK_STATEMENTLIST)); |
|
287 |
|
288 if (stmt->isKind(PNK_FUNCTION)) { |
|
289 if (pc->atBodyLevel()) { |
|
290 // PNX_FUNCDEFS notifies the emitter that the block contains |
|
291 // body-level function definitions that should be processed |
|
292 // before the rest of nodes. |
|
293 list->pn_xflags |= PNX_FUNCDEFS; |
|
294 } else { |
|
295 // General deoptimization was done in Parser::functionDef. |
|
296 JS_ASSERT_IF(pc->sc->isFunctionBox(), |
|
297 pc->sc->asFunctionBox()->hasExtensibleScope()); |
|
298 } |
|
299 } |
|
300 |
|
301 list->append(stmt); |
|
302 } |
|
303 |
|
304 ParseNode *newEmptyStatement(const TokenPos &pos) { |
|
305 return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, pos, (ParseNode *) nullptr); |
|
306 } |
|
307 |
|
308 ParseNode *newImportDeclaration(ParseNode *importSpecSet, |
|
309 ParseNode *moduleSpec, const TokenPos &pos) |
|
310 { |
|
311 ParseNode *pn = new_<BinaryNode>(PNK_IMPORT, JSOP_NOP, pos, |
|
312 importSpecSet, moduleSpec); |
|
313 if (!pn) |
|
314 return null(); |
|
315 return pn; |
|
316 } |
|
317 |
|
318 ParseNode *newExportDeclaration(ParseNode *kid, const TokenPos &pos) { |
|
319 return new_<UnaryNode>(PNK_EXPORT, JSOP_NOP, pos, kid); |
|
320 } |
|
321 |
|
322 ParseNode *newExportFromDeclaration(uint32_t begin, ParseNode *exportSpecSet, |
|
323 ParseNode *moduleSpec) |
|
324 { |
|
325 ParseNode *pn = new_<BinaryNode>(PNK_EXPORT_FROM, JSOP_NOP, exportSpecSet, moduleSpec); |
|
326 if (!pn) |
|
327 return null(); |
|
328 pn->pn_pos.begin = begin; |
|
329 return pn; |
|
330 } |
|
331 |
|
332 ParseNode *newExprStatement(ParseNode *expr, uint32_t end) { |
|
333 JS_ASSERT(expr->pn_pos.end <= end); |
|
334 return new_<UnaryNode>(PNK_SEMI, JSOP_NOP, TokenPos(expr->pn_pos.begin, end), expr); |
|
335 } |
|
336 |
|
337 ParseNode *newIfStatement(uint32_t begin, ParseNode *cond, ParseNode *thenBranch, |
|
338 ParseNode *elseBranch) |
|
339 { |
|
340 ParseNode *pn = new_<TernaryNode>(PNK_IF, JSOP_NOP, cond, thenBranch, elseBranch); |
|
341 if (!pn) |
|
342 return null(); |
|
343 pn->pn_pos.begin = begin; |
|
344 return pn; |
|
345 } |
|
346 |
|
347 ParseNode *newDoWhileStatement(ParseNode *body, ParseNode *cond, const TokenPos &pos) { |
|
348 return new_<BinaryNode>(PNK_DOWHILE, JSOP_NOP, pos, body, cond); |
|
349 } |
|
350 |
|
351 ParseNode *newWhileStatement(uint32_t begin, ParseNode *cond, ParseNode *body) { |
|
352 TokenPos pos(begin, body->pn_pos.end); |
|
353 return new_<BinaryNode>(PNK_WHILE, JSOP_NOP, pos, cond, body); |
|
354 } |
|
355 |
|
356 ParseNode *newForStatement(uint32_t begin, ParseNode *forHead, ParseNode *body, |
|
357 unsigned iflags) |
|
358 { |
|
359 /* A FOR node is binary, left is loop control and right is the body. */ |
|
360 JSOp op = forHead->isKind(PNK_FORIN) ? JSOP_ITER : JSOP_NOP; |
|
361 BinaryNode *pn = new_<BinaryNode>(PNK_FOR, op, TokenPos(begin, body->pn_pos.end), |
|
362 forHead, body); |
|
363 if (!pn) |
|
364 return null(); |
|
365 pn->pn_iflags = iflags; |
|
366 return pn; |
|
367 } |
|
368 |
|
369 ParseNode *newForHead(ParseNodeKind kind, ParseNode *pn1, ParseNode *pn2, ParseNode *pn3, |
|
370 const TokenPos &pos) |
|
371 { |
|
372 JS_ASSERT(kind == PNK_FORIN || kind == PNK_FOROF || kind == PNK_FORHEAD); |
|
373 return new_<TernaryNode>(kind, JSOP_NOP, pn1, pn2, pn3, pos); |
|
374 } |
|
375 |
|
376 ParseNode *newSwitchStatement(uint32_t begin, ParseNode *discriminant, ParseNode *caseList) { |
|
377 TokenPos pos(begin, caseList->pn_pos.end); |
|
378 return new_<BinaryNode>(PNK_SWITCH, JSOP_NOP, pos, discriminant, caseList); |
|
379 } |
|
380 |
|
381 ParseNode *newCaseOrDefault(uint32_t begin, ParseNode *expr, ParseNode *body) { |
|
382 TokenPos pos(begin, body->pn_pos.end); |
|
383 return new_<BinaryNode>(expr ? PNK_CASE : PNK_DEFAULT, JSOP_NOP, pos, expr, body); |
|
384 } |
|
385 |
|
386 ParseNode *newContinueStatement(PropertyName *label, const TokenPos &pos) { |
|
387 return new_<ContinueStatement>(label, pos); |
|
388 } |
|
389 |
|
390 ParseNode *newBreakStatement(PropertyName *label, const TokenPos &pos) { |
|
391 return new_<BreakStatement>(label, pos); |
|
392 } |
|
393 |
|
394 ParseNode *newReturnStatement(ParseNode *expr, const TokenPos &pos) { |
|
395 JS_ASSERT_IF(expr, pos.encloses(expr->pn_pos)); |
|
396 return new_<UnaryNode>(PNK_RETURN, JSOP_RETURN, pos, expr); |
|
397 } |
|
398 |
|
399 ParseNode *newWithStatement(uint32_t begin, ParseNode *expr, ParseNode *body, |
|
400 ObjectBox *staticWith) { |
|
401 return new_<BinaryObjNode>(PNK_WITH, JSOP_NOP, TokenPos(begin, body->pn_pos.end), |
|
402 expr, body, staticWith); |
|
403 } |
|
404 |
|
405 ParseNode *newLabeledStatement(PropertyName *label, ParseNode *stmt, uint32_t begin) { |
|
406 return new_<LabeledStatement>(label, stmt, begin); |
|
407 } |
|
408 |
|
409 ParseNode *newThrowStatement(ParseNode *expr, const TokenPos &pos) { |
|
410 JS_ASSERT(pos.encloses(expr->pn_pos)); |
|
411 return new_<UnaryNode>(PNK_THROW, JSOP_THROW, pos, expr); |
|
412 } |
|
413 |
|
414 ParseNode *newTryStatement(uint32_t begin, ParseNode *body, ParseNode *catchList, |
|
415 ParseNode *finallyBlock) { |
|
416 TokenPos pos(begin, (finallyBlock ? finallyBlock : catchList)->pn_pos.end); |
|
417 return new_<TernaryNode>(PNK_TRY, JSOP_NOP, body, catchList, finallyBlock, pos); |
|
418 } |
|
419 |
|
420 ParseNode *newDebuggerStatement(const TokenPos &pos) { |
|
421 return new_<DebuggerStatement>(pos); |
|
422 } |
|
423 |
|
424 ParseNode *newPropertyAccess(ParseNode *pn, PropertyName *name, uint32_t end) { |
|
425 return new_<PropertyAccess>(pn, name, pn->pn_pos.begin, end); |
|
426 } |
|
427 |
|
428 ParseNode *newPropertyByValue(ParseNode *lhs, ParseNode *index, uint32_t end) { |
|
429 return new_<PropertyByValue>(lhs, index, lhs->pn_pos.begin, end); |
|
430 } |
|
431 |
|
432 inline bool addCatchBlock(ParseNode *catchList, ParseNode *letBlock, |
|
433 ParseNode *catchName, ParseNode *catchGuard, ParseNode *catchBody); |
|
434 |
|
435 inline void setLastFunctionArgumentDefault(ParseNode *funcpn, ParseNode *pn); |
|
436 inline ParseNode *newFunctionDefinition(); |
|
437 void setFunctionBody(ParseNode *pn, ParseNode *kid) { |
|
438 pn->pn_body = kid; |
|
439 } |
|
440 void setFunctionBox(ParseNode *pn, FunctionBox *funbox) { |
|
441 JS_ASSERT(pn->isKind(PNK_FUNCTION)); |
|
442 pn->pn_funbox = funbox; |
|
443 } |
|
444 void addFunctionArgument(ParseNode *pn, ParseNode *argpn) { |
|
445 pn->pn_body->append(argpn); |
|
446 } |
|
447 |
|
448 inline ParseNode *newLexicalScope(ObjectBox *blockbox); |
|
449 inline void setLexicalScopeBody(ParseNode *block, ParseNode *body); |
|
450 |
|
451 bool isOperationWithoutParens(ParseNode *pn, ParseNodeKind kind) { |
|
452 return pn->isKind(kind) && !pn->isInParens(); |
|
453 } |
|
454 |
|
455 inline bool finishInitializerAssignment(ParseNode *pn, ParseNode *init, JSOp op); |
|
456 |
|
457 void setBeginPosition(ParseNode *pn, ParseNode *oth) { |
|
458 setBeginPosition(pn, oth->pn_pos.begin); |
|
459 } |
|
460 void setBeginPosition(ParseNode *pn, uint32_t begin) { |
|
461 pn->pn_pos.begin = begin; |
|
462 JS_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end); |
|
463 } |
|
464 |
|
465 void setEndPosition(ParseNode *pn, ParseNode *oth) { |
|
466 setEndPosition(pn, oth->pn_pos.end); |
|
467 } |
|
468 void setEndPosition(ParseNode *pn, uint32_t end) { |
|
469 pn->pn_pos.end = end; |
|
470 JS_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end); |
|
471 } |
|
472 |
|
473 void setPosition(ParseNode *pn, const TokenPos &pos) { |
|
474 pn->pn_pos = pos; |
|
475 } |
|
476 TokenPos getPosition(ParseNode *pn) { |
|
477 return pn->pn_pos; |
|
478 } |
|
479 |
|
480 ParseNode *newList(ParseNodeKind kind, ParseNode *kid = nullptr, JSOp op = JSOP_NOP) { |
|
481 ParseNode *pn = ListNode::create(kind, this); |
|
482 if (!pn) |
|
483 return nullptr; |
|
484 pn->setOp(op); |
|
485 pn->makeEmpty(); |
|
486 if (kid) { |
|
487 pn->pn_pos.begin = kid->pn_pos.begin; |
|
488 pn->append(kid); |
|
489 } |
|
490 return pn; |
|
491 } |
|
492 void addList(ParseNode *pn, ParseNode *kid) { |
|
493 pn->append(kid); |
|
494 } |
|
495 |
|
496 bool isUnparenthesizedYield(ParseNode *pn) { |
|
497 return pn->isKind(PNK_YIELD) && !pn->isInParens(); |
|
498 } |
|
499 |
|
500 void setOp(ParseNode *pn, JSOp op) { |
|
501 pn->setOp(op); |
|
502 } |
|
503 void setBlockId(ParseNode *pn, unsigned blockid) { |
|
504 pn->pn_blockid = blockid; |
|
505 } |
|
506 void setFlag(ParseNode *pn, unsigned flag) { |
|
507 pn->pn_dflags |= flag; |
|
508 } |
|
509 void setListFlag(ParseNode *pn, unsigned flag) { |
|
510 JS_ASSERT(pn->isArity(PN_LIST)); |
|
511 pn->pn_xflags |= flag; |
|
512 } |
|
513 ParseNode *setInParens(ParseNode *pn) { |
|
514 pn->setInParens(true); |
|
515 return pn; |
|
516 } |
|
517 void setPrologue(ParseNode *pn) { |
|
518 pn->pn_prologue = true; |
|
519 } |
|
520 |
|
521 bool isConstant(ParseNode *pn) { |
|
522 return pn->isConstant(); |
|
523 } |
|
524 PropertyName *isName(ParseNode *pn) { |
|
525 return pn->isKind(PNK_NAME) ? pn->pn_atom->asPropertyName() : nullptr; |
|
526 } |
|
527 bool isCall(ParseNode *pn) { |
|
528 return pn->isKind(PNK_CALL); |
|
529 } |
|
530 PropertyName *isGetProp(ParseNode *pn) { |
|
531 return pn->is<PropertyAccess>() ? &pn->as<PropertyAccess>().name() : nullptr; |
|
532 } |
|
533 JSAtom *isStringExprStatement(ParseNode *pn, TokenPos *pos) { |
|
534 if (JSAtom *atom = pn->isStringExprStatement()) { |
|
535 *pos = pn->pn_kid->pn_pos; |
|
536 return atom; |
|
537 } |
|
538 return nullptr; |
|
539 } |
|
540 |
|
541 inline ParseNode *makeAssignment(ParseNode *pn, ParseNode *rhs); |
|
542 |
|
543 static Definition *getDefinitionNode(Definition *dn) { |
|
544 return dn; |
|
545 } |
|
546 static Definition::Kind getDefinitionKind(Definition *dn) { |
|
547 return dn->kind(); |
|
548 } |
|
549 void linkUseToDef(ParseNode *pn, Definition *dn) |
|
550 { |
|
551 JS_ASSERT(!pn->isUsed()); |
|
552 JS_ASSERT(!pn->isDefn()); |
|
553 JS_ASSERT(pn != dn->dn_uses); |
|
554 JS_ASSERT(dn->isDefn()); |
|
555 pn->pn_link = dn->dn_uses; |
|
556 dn->dn_uses = pn; |
|
557 dn->pn_dflags |= pn->pn_dflags & PND_USE2DEF_FLAGS; |
|
558 pn->setUsed(true); |
|
559 pn->pn_lexdef = dn; |
|
560 } |
|
561 Definition *resolve(Definition *dn) { |
|
562 return dn->resolve(); |
|
563 } |
|
564 void deoptimizeUsesWithin(Definition *dn, const TokenPos &pos) |
|
565 { |
|
566 for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) { |
|
567 JS_ASSERT(pnu->isUsed()); |
|
568 JS_ASSERT(!pnu->isDefn()); |
|
569 if (pnu->pn_pos.begin >= pos.begin && pnu->pn_pos.end <= pos.end) |
|
570 pnu->pn_dflags |= PND_DEOPTIMIZED; |
|
571 } |
|
572 } |
|
573 bool dependencyCovered(ParseNode *pn, unsigned blockid, bool functionScope) { |
|
574 return pn->pn_blockid >= blockid; |
|
575 } |
|
576 |
|
577 static uintptr_t definitionToBits(Definition *dn) { |
|
578 return uintptr_t(dn); |
|
579 } |
|
580 static Definition *definitionFromBits(uintptr_t bits) { |
|
581 return (Definition *) bits; |
|
582 } |
|
583 static Definition *nullDefinition() { |
|
584 return nullptr; |
|
585 } |
|
586 void disableSyntaxParser() { |
|
587 syntaxParser = nullptr; |
|
588 } |
|
589 |
|
590 LazyScript *lazyOuterFunction() { |
|
591 return lazyOuterFunction_; |
|
592 } |
|
593 JSFunction *nextLazyInnerFunction() { |
|
594 JS_ASSERT(lazyInnerFunctionIndex < lazyOuterFunction()->numInnerFunctions()); |
|
595 return lazyOuterFunction()->innerFunctions()[lazyInnerFunctionIndex++]; |
|
596 } |
|
597 }; |
|
598 |
|
599 inline bool |
|
600 FullParseHandler::addCatchBlock(ParseNode *catchList, ParseNode *letBlock, |
|
601 ParseNode *catchName, ParseNode *catchGuard, ParseNode *catchBody) |
|
602 { |
|
603 ParseNode *catchpn = newTernary(PNK_CATCH, catchName, catchGuard, catchBody); |
|
604 if (!catchpn) |
|
605 return false; |
|
606 |
|
607 catchList->append(letBlock); |
|
608 letBlock->pn_expr = catchpn; |
|
609 return true; |
|
610 } |
|
611 |
|
612 inline void |
|
613 FullParseHandler::setLastFunctionArgumentDefault(ParseNode *funcpn, ParseNode *defaultValue) |
|
614 { |
|
615 ParseNode *arg = funcpn->pn_body->last(); |
|
616 arg->pn_dflags |= PND_DEFAULT; |
|
617 arg->pn_expr = defaultValue; |
|
618 } |
|
619 |
|
620 inline ParseNode * |
|
621 FullParseHandler::newFunctionDefinition() |
|
622 { |
|
623 ParseNode *pn = CodeNode::create(PNK_FUNCTION, this); |
|
624 if (!pn) |
|
625 return nullptr; |
|
626 pn->pn_body = nullptr; |
|
627 pn->pn_funbox = nullptr; |
|
628 pn->pn_cookie.makeFree(); |
|
629 pn->pn_dflags = 0; |
|
630 return pn; |
|
631 } |
|
632 |
|
633 inline ParseNode * |
|
634 FullParseHandler::newLexicalScope(ObjectBox *blockbox) |
|
635 { |
|
636 ParseNode *pn = LexicalScopeNode::create(PNK_LEXICALSCOPE, this); |
|
637 if (!pn) |
|
638 return nullptr; |
|
639 |
|
640 pn->pn_objbox = blockbox; |
|
641 pn->pn_cookie.makeFree(); |
|
642 pn->pn_dflags = 0; |
|
643 return pn; |
|
644 } |
|
645 |
|
646 inline void |
|
647 FullParseHandler::setLexicalScopeBody(ParseNode *block, ParseNode *kid) |
|
648 { |
|
649 block->pn_expr = kid; |
|
650 } |
|
651 |
|
652 inline bool |
|
653 FullParseHandler::finishInitializerAssignment(ParseNode *pn, ParseNode *init, JSOp op) |
|
654 { |
|
655 if (pn->isUsed()) { |
|
656 pn = makeAssignment(pn, init); |
|
657 if (!pn) |
|
658 return false; |
|
659 } else { |
|
660 pn->pn_expr = init; |
|
661 } |
|
662 |
|
663 pn->setOp((pn->pn_dflags & PND_BOUND) |
|
664 ? JSOP_SETLOCAL |
|
665 : (op == JSOP_DEFCONST) |
|
666 ? JSOP_SETCONST |
|
667 : JSOP_SETNAME); |
|
668 |
|
669 pn->markAsAssigned(); |
|
670 |
|
671 /* The declarator's position must include the initializer. */ |
|
672 pn->pn_pos.end = init->pn_pos.end; |
|
673 return true; |
|
674 } |
|
675 |
|
676 inline ParseNode * |
|
677 FullParseHandler::makeAssignment(ParseNode *pn, ParseNode *rhs) |
|
678 { |
|
679 ParseNode *lhs = cloneNode(*pn); |
|
680 if (!lhs) |
|
681 return nullptr; |
|
682 |
|
683 if (pn->isUsed()) { |
|
684 Definition *dn = pn->pn_lexdef; |
|
685 ParseNode **pnup = &dn->dn_uses; |
|
686 |
|
687 while (*pnup != pn) |
|
688 pnup = &(*pnup)->pn_link; |
|
689 *pnup = lhs; |
|
690 lhs->pn_link = pn->pn_link; |
|
691 pn->pn_link = nullptr; |
|
692 } |
|
693 |
|
694 pn->setKind(PNK_ASSIGN); |
|
695 pn->setOp(JSOP_NOP); |
|
696 pn->setArity(PN_BINARY); |
|
697 pn->setInParens(false); |
|
698 pn->setUsed(false); |
|
699 pn->setDefn(false); |
|
700 pn->pn_left = lhs; |
|
701 pn->pn_right = rhs; |
|
702 pn->pn_pos.end = rhs->pn_pos.end; |
|
703 return lhs; |
|
704 } |
|
705 |
|
706 } // frontend |
|
707 } // js |
|
708 |
|
709 #endif /* frontend_FullParseHandler_h */ |