Thu, 15 Jan 2015 15:55:04 +0100
Back out 97036ab72558 which inappropriately compared turds to third parties.
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/. */
7 /* JS reflection package. */
9 #include "jsreflect.h"
11 #include "mozilla/ArrayUtils.h"
12 #include "mozilla/DebugOnly.h"
14 #include <stdlib.h>
16 #include "jsarray.h"
17 #include "jsatom.h"
18 #include "jsobj.h"
19 #include "jspubtd.h"
21 #include "frontend/Parser.h"
22 #include "frontend/TokenStream.h"
23 #include "js/CharacterEncoding.h"
24 #include "vm/RegExpObject.h"
26 #include "jsobjinlines.h"
28 #include "frontend/ParseNode-inl.h"
30 using namespace js;
31 using namespace js::frontend;
33 using JS::AutoValueArray;
34 using mozilla::ArrayLength;
35 using mozilla::DebugOnly;
37 char const * const js::aopNames[] = {
38 "=", /* AOP_ASSIGN */
39 "+=", /* AOP_PLUS */
40 "-=", /* AOP_MINUS */
41 "*=", /* AOP_STAR */
42 "/=", /* AOP_DIV */
43 "%=", /* AOP_MOD */
44 "<<=", /* AOP_LSH */
45 ">>=", /* AOP_RSH */
46 ">>>=", /* AOP_URSH */
47 "|=", /* AOP_BITOR */
48 "^=", /* AOP_BITXOR */
49 "&=" /* AOP_BITAND */
50 };
52 char const * const js::binopNames[] = {
53 "==", /* BINOP_EQ */
54 "!=", /* BINOP_NE */
55 "===", /* BINOP_STRICTEQ */
56 "!==", /* BINOP_STRICTNE */
57 "<", /* BINOP_LT */
58 "<=", /* BINOP_LE */
59 ">", /* BINOP_GT */
60 ">=", /* BINOP_GE */
61 "<<", /* BINOP_LSH */
62 ">>", /* BINOP_RSH */
63 ">>>", /* BINOP_URSH */
64 "+", /* BINOP_PLUS */
65 "-", /* BINOP_MINUS */
66 "*", /* BINOP_STAR */
67 "/", /* BINOP_DIV */
68 "%", /* BINOP_MOD */
69 "|", /* BINOP_BITOR */
70 "^", /* BINOP_BITXOR */
71 "&", /* BINOP_BITAND */
72 "in", /* BINOP_IN */
73 "instanceof", /* BINOP_INSTANCEOF */
74 };
76 char const * const js::unopNames[] = {
77 "delete", /* UNOP_DELETE */
78 "-", /* UNOP_NEG */
79 "+", /* UNOP_POS */
80 "!", /* UNOP_NOT */
81 "~", /* UNOP_BITNOT */
82 "typeof", /* UNOP_TYPEOF */
83 "void" /* UNOP_VOID */
84 };
86 char const * const js::nodeTypeNames[] = {
87 #define ASTDEF(ast, str, method) str,
88 #include "jsast.tbl"
89 #undef ASTDEF
90 nullptr
91 };
93 static char const * const callbackNames[] = {
94 #define ASTDEF(ast, str, method) method,
95 #include "jsast.tbl"
96 #undef ASTDEF
97 nullptr
98 };
100 enum YieldKind { Delegating, NotDelegating };
102 typedef AutoValueVector NodeVector;
104 /*
105 * ParseNode is a somewhat intricate data structure, and its invariants have
106 * evolved, making it more likely that there could be a disconnect between the
107 * parser and the AST serializer. We use these macros to check invariants on a
108 * parse node and raise a dynamic error on failure.
109 */
110 #define LOCAL_ASSERT(expr) \
111 JS_BEGIN_MACRO \
112 JS_ASSERT(expr); \
113 if (!(expr)) { \
114 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_PARSE_NODE); \
115 return false; \
116 } \
117 JS_END_MACRO
119 #define LOCAL_NOT_REACHED(expr) \
120 JS_BEGIN_MACRO \
121 MOZ_ASSERT(false); \
122 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_PARSE_NODE); \
123 return false; \
124 JS_END_MACRO
126 namespace {
128 /* Set 'result' to obj[id] if any such property exists, else defaultValue. */
129 static bool
130 GetPropertyDefault(JSContext *cx, HandleObject obj, HandleId id, HandleValue defaultValue,
131 MutableHandleValue result)
132 {
133 bool found;
134 if (!JSObject::hasProperty(cx, obj, id, &found))
135 return false;
136 if (!found) {
137 result.set(defaultValue);
138 return true;
139 }
140 return JSObject::getGeneric(cx, obj, obj, id, result);
141 }
143 /*
144 * Builder class that constructs JavaScript AST node objects. See:
145 *
146 * https://developer.mozilla.org/en/SpiderMonkey/Parser_API
147 *
148 * Bug 569487: generalize builder interface
149 */
150 class NodeBuilder
151 {
152 typedef AutoValueArray<AST_LIMIT> CallbackArray;
154 JSContext *cx;
155 TokenStream *tokenStream;
156 bool saveLoc; /* save source location information? */
157 char const *src; /* source filename or null */
158 RootedValue srcval; /* source filename JS value or null */
159 CallbackArray callbacks; /* user-specified callbacks */
160 RootedValue userv; /* user-specified builder object or null */
162 public:
163 NodeBuilder(JSContext *c, bool l, char const *s)
164 : cx(c), tokenStream(nullptr), saveLoc(l), src(s), srcval(c), callbacks(cx),
165 userv(c)
166 {}
168 bool init(HandleObject userobj = js::NullPtr()) {
169 if (src) {
170 if (!atomValue(src, &srcval))
171 return false;
172 } else {
173 srcval.setNull();
174 }
176 if (!userobj) {
177 userv.setNull();
178 for (unsigned i = 0; i < AST_LIMIT; i++) {
179 callbacks[i].setNull();
180 }
181 return true;
182 }
184 userv.setObject(*userobj);
186 RootedValue nullVal(cx, NullValue());
187 RootedValue funv(cx);
188 for (unsigned i = 0; i < AST_LIMIT; i++) {
189 const char *name = callbackNames[i];
190 RootedAtom atom(cx, Atomize(cx, name, strlen(name)));
191 if (!atom)
192 return false;
193 RootedId id(cx, AtomToId(atom));
194 if (!GetPropertyDefault(cx, userobj, id, nullVal, &funv))
195 return false;
197 if (funv.isNullOrUndefined()) {
198 callbacks[i].setNull();
199 continue;
200 }
202 if (!funv.isObject() || !funv.toObject().is<JSFunction>()) {
203 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NOT_FUNCTION,
204 JSDVG_SEARCH_STACK, funv, js::NullPtr(), nullptr, nullptr);
205 return false;
206 }
208 callbacks[i].set(funv);
209 }
211 return true;
212 }
214 void setTokenStream(TokenStream *ts) {
215 tokenStream = ts;
216 }
218 private:
219 bool callback(HandleValue fun, TokenPos *pos, MutableHandleValue dst) {
220 if (saveLoc) {
221 RootedValue loc(cx);
222 if (!newNodeLoc(pos, &loc))
223 return false;
224 AutoValueArray<1> argv(cx);
225 argv[0].set(loc);
226 return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
227 }
229 AutoValueArray<1> argv(cx);
230 argv[0].setNull(); /* no zero-length arrays allowed! */
231 return Invoke(cx, userv, fun, 0, argv.begin(), dst);
232 }
234 bool callback(HandleValue fun, HandleValue v1, TokenPos *pos, MutableHandleValue dst) {
235 if (saveLoc) {
236 RootedValue loc(cx);
237 if (!newNodeLoc(pos, &loc))
238 return false;
239 AutoValueArray<2> argv(cx);
240 argv[0].set(v1);
241 argv[1].set(loc);
242 return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
243 }
245 AutoValueArray<1> argv(cx);
246 argv[0].set(v1);
247 return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
248 }
250 bool callback(HandleValue fun, HandleValue v1, HandleValue v2, TokenPos *pos,
251 MutableHandleValue dst) {
252 if (saveLoc) {
253 RootedValue loc(cx);
254 if (!newNodeLoc(pos, &loc))
255 return false;
256 AutoValueArray<3> argv(cx);
257 argv[0].set(v1);
258 argv[1].set(v2);
259 argv[2].set(loc);
260 return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
261 }
263 AutoValueArray<2> argv(cx);
264 argv[0].set(v1);
265 argv[1].set(v2);
266 return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
267 }
269 bool callback(HandleValue fun, HandleValue v1, HandleValue v2, HandleValue v3, TokenPos *pos,
270 MutableHandleValue dst) {
271 if (saveLoc) {
272 RootedValue loc(cx);
273 if (!newNodeLoc(pos, &loc))
274 return false;
275 AutoValueArray<4> argv(cx);
276 argv[0].set(v1);
277 argv[1].set(v2);
278 argv[2].set(v3);
279 argv[3].set(loc);
280 return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
281 }
283 AutoValueArray<3> argv(cx);
284 argv[0].set(v1);
285 argv[1].set(v2);
286 argv[2].set(v3);
287 return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
288 }
290 bool callback(HandleValue fun, HandleValue v1, HandleValue v2, HandleValue v3, HandleValue v4,
291 TokenPos *pos, MutableHandleValue dst) {
292 if (saveLoc) {
293 RootedValue loc(cx);
294 if (!newNodeLoc(pos, &loc))
295 return false;
296 AutoValueArray<5> argv(cx);
297 argv[0].set(v1);
298 argv[1].set(v2);
299 argv[2].set(v3);
300 argv[3].set(v4);
301 argv[4].set(loc);
302 return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
303 }
305 AutoValueArray<4> argv(cx);
306 argv[0].set(v1);
307 argv[1].set(v2);
308 argv[2].set(v3);
309 argv[3].set(v4);
310 return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
311 }
313 bool callback(HandleValue fun, HandleValue v1, HandleValue v2, HandleValue v3, HandleValue v4,
314 HandleValue v5, TokenPos *pos, MutableHandleValue dst) {
315 if (saveLoc) {
316 RootedValue loc(cx);
317 if (!newNodeLoc(pos, &loc))
318 return false;
319 AutoValueArray<6> argv(cx);
320 argv[0].set(v1);
321 argv[1].set(v2);
322 argv[2].set(v3);
323 argv[3].set(v4);
324 argv[4].set(v5);
325 argv[5].set(loc);
326 return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
327 }
329 AutoValueArray<5> argv(cx);
330 argv[0].set(v1);
331 argv[1].set(v2);
332 argv[2].set(v3);
333 argv[3].set(v4);
334 argv[4].set(v5);
335 return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
336 }
338 // WARNING: Returning a Handle is non-standard, but it works in this case
339 // because both |v| and |UndefinedHandleValue| are definitely rooted on a
340 // previous stack frame (i.e. we're just choosing between two
341 // already-rooted values).
342 HandleValue opt(HandleValue v) {
343 JS_ASSERT_IF(v.isMagic(), v.whyMagic() == JS_SERIALIZE_NO_NODE);
344 return v.isMagic(JS_SERIALIZE_NO_NODE) ? JS::UndefinedHandleValue : v;
345 }
347 bool atomValue(const char *s, MutableHandleValue dst) {
348 /*
349 * Bug 575416: instead of Atomize, lookup constant atoms in tbl file
350 */
351 RootedAtom atom(cx, Atomize(cx, s, strlen(s)));
352 if (!atom)
353 return false;
355 dst.setString(atom);
356 return true;
357 }
359 bool newObject(MutableHandleObject dst) {
360 RootedObject nobj(cx, NewBuiltinClassInstance(cx, &JSObject::class_));
361 if (!nobj)
362 return false;
364 dst.set(nobj);
365 return true;
366 }
368 bool newArray(NodeVector &elts, MutableHandleValue dst);
370 bool newNode(ASTType type, TokenPos *pos, MutableHandleObject dst);
372 bool newNode(ASTType type, TokenPos *pos, MutableHandleValue dst) {
373 RootedObject node(cx);
374 return newNode(type, pos, &node) &&
375 setResult(node, dst);
376 }
378 bool newNode(ASTType type, TokenPos *pos,
379 const char *childName, HandleValue child,
380 MutableHandleValue dst) {
381 RootedObject node(cx);
382 return newNode(type, pos, &node) &&
383 setProperty(node, childName, child) &&
384 setResult(node, dst);
385 }
387 bool newNode(ASTType type, TokenPos *pos,
388 const char *childName1, HandleValue child1,
389 const char *childName2, HandleValue child2,
390 MutableHandleValue dst) {
391 RootedObject node(cx);
392 return newNode(type, pos, &node) &&
393 setProperty(node, childName1, child1) &&
394 setProperty(node, childName2, child2) &&
395 setResult(node, dst);
396 }
398 bool newNode(ASTType type, TokenPos *pos,
399 const char *childName1, HandleValue child1,
400 const char *childName2, HandleValue child2,
401 const char *childName3, HandleValue child3,
402 MutableHandleValue dst) {
403 RootedObject node(cx);
404 return newNode(type, pos, &node) &&
405 setProperty(node, childName1, child1) &&
406 setProperty(node, childName2, child2) &&
407 setProperty(node, childName3, child3) &&
408 setResult(node, dst);
409 }
411 bool newNode(ASTType type, TokenPos *pos,
412 const char *childName1, HandleValue child1,
413 const char *childName2, HandleValue child2,
414 const char *childName3, HandleValue child3,
415 const char *childName4, HandleValue child4,
416 MutableHandleValue dst) {
417 RootedObject node(cx);
418 return newNode(type, pos, &node) &&
419 setProperty(node, childName1, child1) &&
420 setProperty(node, childName2, child2) &&
421 setProperty(node, childName3, child3) &&
422 setProperty(node, childName4, child4) &&
423 setResult(node, dst);
424 }
426 bool newNode(ASTType type, TokenPos *pos,
427 const char *childName1, HandleValue child1,
428 const char *childName2, HandleValue child2,
429 const char *childName3, HandleValue child3,
430 const char *childName4, HandleValue child4,
431 const char *childName5, HandleValue child5,
432 MutableHandleValue dst) {
433 RootedObject node(cx);
434 return newNode(type, pos, &node) &&
435 setProperty(node, childName1, child1) &&
436 setProperty(node, childName2, child2) &&
437 setProperty(node, childName3, child3) &&
438 setProperty(node, childName4, child4) &&
439 setProperty(node, childName5, child5) &&
440 setResult(node, dst);
441 }
443 bool newNode(ASTType type, TokenPos *pos,
444 const char *childName1, HandleValue child1,
445 const char *childName2, HandleValue child2,
446 const char *childName3, HandleValue child3,
447 const char *childName4, HandleValue child4,
448 const char *childName5, HandleValue child5,
449 const char *childName6, HandleValue child6,
450 const char *childName7, HandleValue child7,
451 MutableHandleValue dst) {
452 RootedObject node(cx);
453 return newNode(type, pos, &node) &&
454 setProperty(node, childName1, child1) &&
455 setProperty(node, childName2, child2) &&
456 setProperty(node, childName3, child3) &&
457 setProperty(node, childName4, child4) &&
458 setProperty(node, childName5, child5) &&
459 setProperty(node, childName6, child6) &&
460 setProperty(node, childName7, child7) &&
461 setResult(node, dst);
462 }
464 bool listNode(ASTType type, const char *propName, NodeVector &elts, TokenPos *pos,
465 MutableHandleValue dst) {
466 RootedValue array(cx);
467 if (!newArray(elts, &array))
468 return false;
470 RootedValue cb(cx, callbacks[type]);
471 if (!cb.isNull())
472 return callback(cb, array, pos, dst);
474 return newNode(type, pos, propName, array, dst);
475 }
477 bool setProperty(HandleObject obj, const char *name, HandleValue val) {
478 JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
480 /*
481 * Bug 575416: instead of Atomize, lookup constant atoms in tbl file
482 */
483 RootedAtom atom(cx, Atomize(cx, name, strlen(name)));
484 if (!atom)
485 return false;
487 /* Represent "no node" as null and ensure users are not exposed to magic values. */
488 RootedValue optVal(cx, val.isMagic(JS_SERIALIZE_NO_NODE) ? NullValue() : val);
489 return JSObject::defineProperty(cx, obj, atom->asPropertyName(), optVal);
490 }
492 bool newNodeLoc(TokenPos *pos, MutableHandleValue dst);
494 bool setNodeLoc(HandleObject node, TokenPos *pos);
496 bool setResult(HandleObject obj, MutableHandleValue dst) {
497 JS_ASSERT(obj);
498 dst.setObject(*obj);
499 return true;
500 }
502 public:
503 /*
504 * All of the public builder methods take as their last two
505 * arguments a nullable token position and a non-nullable, rooted
506 * outparam.
507 *
508 * Any Value arguments representing optional subnodes may be a
509 * JS_SERIALIZE_NO_NODE magic value.
510 */
512 /*
513 * misc nodes
514 */
516 bool program(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
518 bool literal(HandleValue val, TokenPos *pos, MutableHandleValue dst);
520 bool identifier(HandleValue name, TokenPos *pos, MutableHandleValue dst);
522 bool function(ASTType type, TokenPos *pos,
523 HandleValue id, NodeVector &args, NodeVector &defaults,
524 HandleValue body, HandleValue rest, bool isGenerator, bool isExpression,
525 MutableHandleValue dst);
527 bool variableDeclarator(HandleValue id, HandleValue init, TokenPos *pos,
528 MutableHandleValue dst);
530 bool switchCase(HandleValue expr, NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
532 bool catchClause(HandleValue var, HandleValue guard, HandleValue body, TokenPos *pos,
533 MutableHandleValue dst);
535 bool propertyInitializer(HandleValue key, HandleValue val, PropKind kind, TokenPos *pos,
536 MutableHandleValue dst);
539 /*
540 * statements
541 */
543 bool blockStatement(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
545 bool expressionStatement(HandleValue expr, TokenPos *pos, MutableHandleValue dst);
547 bool emptyStatement(TokenPos *pos, MutableHandleValue dst);
549 bool ifStatement(HandleValue test, HandleValue cons, HandleValue alt, TokenPos *pos,
550 MutableHandleValue dst);
552 bool breakStatement(HandleValue label, TokenPos *pos, MutableHandleValue dst);
554 bool continueStatement(HandleValue label, TokenPos *pos, MutableHandleValue dst);
556 bool labeledStatement(HandleValue label, HandleValue stmt, TokenPos *pos,
557 MutableHandleValue dst);
559 bool throwStatement(HandleValue arg, TokenPos *pos, MutableHandleValue dst);
561 bool returnStatement(HandleValue arg, TokenPos *pos, MutableHandleValue dst);
563 bool forStatement(HandleValue init, HandleValue test, HandleValue update, HandleValue stmt,
564 TokenPos *pos, MutableHandleValue dst);
566 bool forInStatement(HandleValue var, HandleValue expr, HandleValue stmt,
567 bool isForEach, TokenPos *pos, MutableHandleValue dst);
569 bool forOfStatement(HandleValue var, HandleValue expr, HandleValue stmt, TokenPos *pos,
570 MutableHandleValue dst);
572 bool withStatement(HandleValue expr, HandleValue stmt, TokenPos *pos, MutableHandleValue dst);
574 bool whileStatement(HandleValue test, HandleValue stmt, TokenPos *pos, MutableHandleValue dst);
576 bool doWhileStatement(HandleValue stmt, HandleValue test, TokenPos *pos,
577 MutableHandleValue dst);
579 bool switchStatement(HandleValue disc, NodeVector &elts, bool lexical, TokenPos *pos,
580 MutableHandleValue dst);
582 bool tryStatement(HandleValue body, NodeVector &guarded, HandleValue unguarded,
583 HandleValue finally, TokenPos *pos, MutableHandleValue dst);
585 bool debuggerStatement(TokenPos *pos, MutableHandleValue dst);
587 bool letStatement(NodeVector &head, HandleValue stmt, TokenPos *pos, MutableHandleValue dst);
589 bool importDeclaration(NodeVector &elts, HandleValue moduleSpec, TokenPos *pos, MutableHandleValue dst);
591 bool importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos *pos, MutableHandleValue dst);
593 bool exportDeclaration(HandleValue decl, NodeVector &elts, HandleValue moduleSpec, TokenPos *pos, MutableHandleValue dst);
595 bool exportSpecifier(HandleValue bindingName, HandleValue exportName, TokenPos *pos, MutableHandleValue dst);
597 bool exportBatchSpecifier(TokenPos *pos, MutableHandleValue dst);
599 /*
600 * expressions
601 */
603 bool binaryExpression(BinaryOperator op, HandleValue left, HandleValue right, TokenPos *pos,
604 MutableHandleValue dst);
606 bool unaryExpression(UnaryOperator op, HandleValue expr, TokenPos *pos, MutableHandleValue dst);
608 bool assignmentExpression(AssignmentOperator op, HandleValue lhs, HandleValue rhs,
609 TokenPos *pos, MutableHandleValue dst);
611 bool updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos *pos,
612 MutableHandleValue dst);
614 bool logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos *pos,
615 MutableHandleValue dst);
617 bool conditionalExpression(HandleValue test, HandleValue cons, HandleValue alt, TokenPos *pos,
618 MutableHandleValue dst);
620 bool sequenceExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
622 bool newExpression(HandleValue callee, NodeVector &args, TokenPos *pos, MutableHandleValue dst);
624 bool callExpression(HandleValue callee, NodeVector &args, TokenPos *pos,
625 MutableHandleValue dst);
627 bool memberExpression(bool computed, HandleValue expr, HandleValue member, TokenPos *pos,
628 MutableHandleValue dst);
630 bool arrayExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
632 bool spreadExpression(HandleValue expr, TokenPos *pos, MutableHandleValue dst);
634 bool objectExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
636 bool thisExpression(TokenPos *pos, MutableHandleValue dst);
638 bool yieldExpression(HandleValue arg, YieldKind kind, TokenPos *pos, MutableHandleValue dst);
640 bool comprehensionBlock(HandleValue patt, HandleValue src, bool isForEach, bool isForOf, TokenPos *pos,
641 MutableHandleValue dst);
643 bool comprehensionExpression(HandleValue body, NodeVector &blocks, HandleValue filter,
644 TokenPos *pos, MutableHandleValue dst);
646 bool generatorExpression(HandleValue body, NodeVector &blocks, HandleValue filter,
647 TokenPos *pos, MutableHandleValue dst);
649 bool letExpression(NodeVector &head, HandleValue expr, TokenPos *pos, MutableHandleValue dst);
651 /*
652 * declarations
653 */
655 bool variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos,
656 MutableHandleValue dst);
658 /*
659 * patterns
660 */
662 bool arrayPattern(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
664 bool objectPattern(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
666 bool propertyPattern(HandleValue key, HandleValue patt, TokenPos *pos, MutableHandleValue dst);
667 };
669 } /* anonymous namespace */
671 bool
672 NodeBuilder::newNode(ASTType type, TokenPos *pos, MutableHandleObject dst)
673 {
674 JS_ASSERT(type > AST_ERROR && type < AST_LIMIT);
676 RootedValue tv(cx);
677 RootedObject node(cx, NewBuiltinClassInstance(cx, &JSObject::class_));
678 if (!node ||
679 !setNodeLoc(node, pos) ||
680 !atomValue(nodeTypeNames[type], &tv) ||
681 !setProperty(node, "type", tv)) {
682 return false;
683 }
685 dst.set(node);
686 return true;
687 }
689 bool
690 NodeBuilder::newArray(NodeVector &elts, MutableHandleValue dst)
691 {
692 const size_t len = elts.length();
693 if (len > UINT32_MAX) {
694 js_ReportAllocationOverflow(cx);
695 return false;
696 }
697 RootedObject array(cx, NewDenseAllocatedArray(cx, uint32_t(len)));
698 if (!array)
699 return false;
701 for (size_t i = 0; i < len; i++) {
702 RootedValue val(cx, elts[i]);
704 JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
706 /* Represent "no node" as an array hole by not adding the value. */
707 if (val.isMagic(JS_SERIALIZE_NO_NODE))
708 continue;
710 if (!JSObject::setElement(cx, array, array, i, &val, false))
711 return false;
712 }
714 dst.setObject(*array);
715 return true;
716 }
718 bool
719 NodeBuilder::newNodeLoc(TokenPos *pos, MutableHandleValue dst)
720 {
721 if (!pos) {
722 dst.setNull();
723 return true;
724 }
726 RootedObject loc(cx);
727 RootedObject to(cx);
728 RootedValue val(cx);
730 if (!newObject(&loc))
731 return false;
733 dst.setObject(*loc);
735 uint32_t startLineNum, startColumnIndex;
736 uint32_t endLineNum, endColumnIndex;
737 tokenStream->srcCoords.lineNumAndColumnIndex(pos->begin, &startLineNum, &startColumnIndex);
738 tokenStream->srcCoords.lineNumAndColumnIndex(pos->end, &endLineNum, &endColumnIndex);
740 if (!newObject(&to))
741 return false;
742 val.setObject(*to);
743 if (!setProperty(loc, "start", val))
744 return false;
745 val.setNumber(startLineNum);
746 if (!setProperty(to, "line", val))
747 return false;
748 val.setNumber(startColumnIndex);
749 if (!setProperty(to, "column", val))
750 return false;
752 if (!newObject(&to))
753 return false;
754 val.setObject(*to);
755 if (!setProperty(loc, "end", val))
756 return false;
757 val.setNumber(endLineNum);
758 if (!setProperty(to, "line", val))
759 return false;
760 val.setNumber(endColumnIndex);
761 if (!setProperty(to, "column", val))
762 return false;
764 if (!setProperty(loc, "source", srcval))
765 return false;
767 return true;
768 }
770 bool
771 NodeBuilder::setNodeLoc(HandleObject node, TokenPos *pos)
772 {
773 if (!saveLoc) {
774 RootedValue nullVal(cx, NullValue());
775 setProperty(node, "loc", nullVal);
776 return true;
777 }
779 RootedValue loc(cx);
780 return newNodeLoc(pos, &loc) &&
781 setProperty(node, "loc", loc);
782 }
784 bool
785 NodeBuilder::program(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
786 {
787 return listNode(AST_PROGRAM, "body", elts, pos, dst);
788 }
790 bool
791 NodeBuilder::blockStatement(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
792 {
793 return listNode(AST_BLOCK_STMT, "body", elts, pos, dst);
794 }
796 bool
797 NodeBuilder::expressionStatement(HandleValue expr, TokenPos *pos, MutableHandleValue dst)
798 {
799 RootedValue cb(cx, callbacks[AST_EXPR_STMT]);
800 if (!cb.isNull())
801 return callback(cb, expr, pos, dst);
803 return newNode(AST_EXPR_STMT, pos, "expression", expr, dst);
804 }
806 bool
807 NodeBuilder::emptyStatement(TokenPos *pos, MutableHandleValue dst)
808 {
809 RootedValue cb(cx, callbacks[AST_EMPTY_STMT]);
810 if (!cb.isNull())
811 return callback(cb, pos, dst);
813 return newNode(AST_EMPTY_STMT, pos, dst);
814 }
816 bool
817 NodeBuilder::ifStatement(HandleValue test, HandleValue cons, HandleValue alt, TokenPos *pos,
818 MutableHandleValue dst)
819 {
820 RootedValue cb(cx, callbacks[AST_IF_STMT]);
821 if (!cb.isNull())
822 return callback(cb, test, cons, opt(alt), pos, dst);
824 return newNode(AST_IF_STMT, pos,
825 "test", test,
826 "consequent", cons,
827 "alternate", alt,
828 dst);
829 }
831 bool
832 NodeBuilder::breakStatement(HandleValue label, TokenPos *pos, MutableHandleValue dst)
833 {
834 RootedValue cb(cx, callbacks[AST_BREAK_STMT]);
835 if (!cb.isNull())
836 return callback(cb, opt(label), pos, dst);
838 return newNode(AST_BREAK_STMT, pos, "label", label, dst);
839 }
841 bool
842 NodeBuilder::continueStatement(HandleValue label, TokenPos *pos, MutableHandleValue dst)
843 {
844 RootedValue cb(cx, callbacks[AST_CONTINUE_STMT]);
845 if (!cb.isNull())
846 return callback(cb, opt(label), pos, dst);
848 return newNode(AST_CONTINUE_STMT, pos, "label", label, dst);
849 }
851 bool
852 NodeBuilder::labeledStatement(HandleValue label, HandleValue stmt, TokenPos *pos,
853 MutableHandleValue dst)
854 {
855 RootedValue cb(cx, callbacks[AST_LAB_STMT]);
856 if (!cb.isNull())
857 return callback(cb, label, stmt, pos, dst);
859 return newNode(AST_LAB_STMT, pos,
860 "label", label,
861 "body", stmt,
862 dst);
863 }
865 bool
866 NodeBuilder::throwStatement(HandleValue arg, TokenPos *pos, MutableHandleValue dst)
867 {
868 RootedValue cb(cx, callbacks[AST_THROW_STMT]);
869 if (!cb.isNull())
870 return callback(cb, arg, pos, dst);
872 return newNode(AST_THROW_STMT, pos, "argument", arg, dst);
873 }
875 bool
876 NodeBuilder::returnStatement(HandleValue arg, TokenPos *pos, MutableHandleValue dst)
877 {
878 RootedValue cb(cx, callbacks[AST_RETURN_STMT]);
879 if (!cb.isNull())
880 return callback(cb, opt(arg), pos, dst);
882 return newNode(AST_RETURN_STMT, pos, "argument", arg, dst);
883 }
885 bool
886 NodeBuilder::forStatement(HandleValue init, HandleValue test, HandleValue update, HandleValue stmt,
887 TokenPos *pos, MutableHandleValue dst)
888 {
889 RootedValue cb(cx, callbacks[AST_FOR_STMT]);
890 if (!cb.isNull())
891 return callback(cb, opt(init), opt(test), opt(update), stmt, pos, dst);
893 return newNode(AST_FOR_STMT, pos,
894 "init", init,
895 "test", test,
896 "update", update,
897 "body", stmt,
898 dst);
899 }
901 bool
902 NodeBuilder::forInStatement(HandleValue var, HandleValue expr, HandleValue stmt, bool isForEach,
903 TokenPos *pos, MutableHandleValue dst)
904 {
905 RootedValue isForEachVal(cx, BooleanValue(isForEach));
907 RootedValue cb(cx, callbacks[AST_FOR_IN_STMT]);
908 if (!cb.isNull())
909 return callback(cb, var, expr, stmt, isForEachVal, pos, dst);
911 return newNode(AST_FOR_IN_STMT, pos,
912 "left", var,
913 "right", expr,
914 "body", stmt,
915 "each", isForEachVal,
916 dst);
917 }
919 bool
920 NodeBuilder::forOfStatement(HandleValue var, HandleValue expr, HandleValue stmt, TokenPos *pos,
921 MutableHandleValue dst)
922 {
923 RootedValue cb(cx, callbacks[AST_FOR_OF_STMT]);
924 if (!cb.isNull())
925 return callback(cb, var, expr, stmt, pos, dst);
927 return newNode(AST_FOR_OF_STMT, pos,
928 "left", var,
929 "right", expr,
930 "body", stmt,
931 dst);
932 }
934 bool
935 NodeBuilder::withStatement(HandleValue expr, HandleValue stmt, TokenPos *pos,
936 MutableHandleValue dst)
937 {
938 RootedValue cb(cx, callbacks[AST_WITH_STMT]);
939 if (!cb.isNull())
940 return callback(cb, expr, stmt, pos, dst);
942 return newNode(AST_WITH_STMT, pos,
943 "object", expr,
944 "body", stmt,
945 dst);
946 }
948 bool
949 NodeBuilder::whileStatement(HandleValue test, HandleValue stmt, TokenPos *pos,
950 MutableHandleValue dst)
951 {
952 RootedValue cb(cx, callbacks[AST_WHILE_STMT]);
953 if (!cb.isNull())
954 return callback(cb, test, stmt, pos, dst);
956 return newNode(AST_WHILE_STMT, pos,
957 "test", test,
958 "body", stmt,
959 dst);
960 }
962 bool
963 NodeBuilder::doWhileStatement(HandleValue stmt, HandleValue test, TokenPos *pos,
964 MutableHandleValue dst)
965 {
966 RootedValue cb(cx, callbacks[AST_DO_STMT]);
967 if (!cb.isNull())
968 return callback(cb, stmt, test, pos, dst);
970 return newNode(AST_DO_STMT, pos,
971 "body", stmt,
972 "test", test,
973 dst);
974 }
976 bool
977 NodeBuilder::switchStatement(HandleValue disc, NodeVector &elts, bool lexical, TokenPos *pos,
978 MutableHandleValue dst)
979 {
980 RootedValue array(cx);
981 if (!newArray(elts, &array))
982 return false;
984 RootedValue lexicalVal(cx, BooleanValue(lexical));
986 RootedValue cb(cx, callbacks[AST_SWITCH_STMT]);
987 if (!cb.isNull())
988 return callback(cb, disc, array, lexicalVal, pos, dst);
990 return newNode(AST_SWITCH_STMT, pos,
991 "discriminant", disc,
992 "cases", array,
993 "lexical", lexicalVal,
994 dst);
995 }
997 bool
998 NodeBuilder::tryStatement(HandleValue body, NodeVector &guarded, HandleValue unguarded,
999 HandleValue finally, TokenPos *pos, MutableHandleValue dst)
1000 {
1001 RootedValue guardedHandlers(cx);
1002 if (!newArray(guarded, &guardedHandlers))
1003 return false;
1005 RootedValue cb(cx, callbacks[AST_TRY_STMT]);
1006 if (!cb.isNull())
1007 return callback(cb, body, guardedHandlers, unguarded, opt(finally), pos, dst);
1009 return newNode(AST_TRY_STMT, pos,
1010 "block", body,
1011 "guardedHandlers", guardedHandlers,
1012 "handler", unguarded,
1013 "finalizer", finally,
1014 dst);
1015 }
1017 bool
1018 NodeBuilder::debuggerStatement(TokenPos *pos, MutableHandleValue dst)
1019 {
1020 RootedValue cb(cx, callbacks[AST_DEBUGGER_STMT]);
1021 if (!cb.isNull())
1022 return callback(cb, pos, dst);
1024 return newNode(AST_DEBUGGER_STMT, pos, dst);
1025 }
1027 bool
1028 NodeBuilder::binaryExpression(BinaryOperator op, HandleValue left, HandleValue right, TokenPos *pos,
1029 MutableHandleValue dst)
1030 {
1031 JS_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
1033 RootedValue opName(cx);
1034 if (!atomValue(binopNames[op], &opName))
1035 return false;
1037 RootedValue cb(cx, callbacks[AST_BINARY_EXPR]);
1038 if (!cb.isNull())
1039 return callback(cb, opName, left, right, pos, dst);
1041 return newNode(AST_BINARY_EXPR, pos,
1042 "operator", opName,
1043 "left", left,
1044 "right", right,
1045 dst);
1046 }
1048 bool
1049 NodeBuilder::unaryExpression(UnaryOperator unop, HandleValue expr, TokenPos *pos,
1050 MutableHandleValue dst)
1051 {
1052 JS_ASSERT(unop > UNOP_ERR && unop < UNOP_LIMIT);
1054 RootedValue opName(cx);
1055 if (!atomValue(unopNames[unop], &opName))
1056 return false;
1058 RootedValue cb(cx, callbacks[AST_UNARY_EXPR]);
1059 if (!cb.isNull())
1060 return callback(cb, opName, expr, pos, dst);
1062 RootedValue trueVal(cx, BooleanValue(true));
1063 return newNode(AST_UNARY_EXPR, pos,
1064 "operator", opName,
1065 "argument", expr,
1066 "prefix", trueVal,
1067 dst);
1068 }
1070 bool
1071 NodeBuilder::assignmentExpression(AssignmentOperator aop, HandleValue lhs, HandleValue rhs,
1072 TokenPos *pos, MutableHandleValue dst)
1073 {
1074 JS_ASSERT(aop > AOP_ERR && aop < AOP_LIMIT);
1076 RootedValue opName(cx);
1077 if (!atomValue(aopNames[aop], &opName))
1078 return false;
1080 RootedValue cb(cx, callbacks[AST_ASSIGN_EXPR]);
1081 if (!cb.isNull())
1082 return callback(cb, opName, lhs, rhs, pos, dst);
1084 return newNode(AST_ASSIGN_EXPR, pos,
1085 "operator", opName,
1086 "left", lhs,
1087 "right", rhs,
1088 dst);
1089 }
1091 bool
1092 NodeBuilder::updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos *pos,
1093 MutableHandleValue dst)
1094 {
1095 RootedValue opName(cx);
1096 if (!atomValue(incr ? "++" : "--", &opName))
1097 return false;
1099 RootedValue prefixVal(cx, BooleanValue(prefix));
1101 RootedValue cb(cx, callbacks[AST_UPDATE_EXPR]);
1102 if (!cb.isNull())
1103 return callback(cb, expr, opName, prefixVal, pos, dst);
1105 return newNode(AST_UPDATE_EXPR, pos,
1106 "operator", opName,
1107 "argument", expr,
1108 "prefix", prefixVal,
1109 dst);
1110 }
1112 bool
1113 NodeBuilder::logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos *pos,
1114 MutableHandleValue dst)
1115 {
1116 RootedValue opName(cx);
1117 if (!atomValue(lor ? "||" : "&&", &opName))
1118 return false;
1120 RootedValue cb(cx, callbacks[AST_LOGICAL_EXPR]);
1121 if (!cb.isNull())
1122 return callback(cb, opName, left, right, pos, dst);
1124 return newNode(AST_LOGICAL_EXPR, pos,
1125 "operator", opName,
1126 "left", left,
1127 "right", right,
1128 dst);
1129 }
1131 bool
1132 NodeBuilder::conditionalExpression(HandleValue test, HandleValue cons, HandleValue alt,
1133 TokenPos *pos, MutableHandleValue dst)
1134 {
1135 RootedValue cb(cx, callbacks[AST_COND_EXPR]);
1136 if (!cb.isNull())
1137 return callback(cb, test, cons, alt, pos, dst);
1139 return newNode(AST_COND_EXPR, pos,
1140 "test", test,
1141 "consequent", cons,
1142 "alternate", alt,
1143 dst);
1144 }
1146 bool
1147 NodeBuilder::sequenceExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
1148 {
1149 return listNode(AST_LIST_EXPR, "expressions", elts, pos, dst);
1150 }
1152 bool
1153 NodeBuilder::callExpression(HandleValue callee, NodeVector &args, TokenPos *pos,
1154 MutableHandleValue dst)
1155 {
1156 RootedValue array(cx);
1157 if (!newArray(args, &array))
1158 return false;
1160 RootedValue cb(cx, callbacks[AST_CALL_EXPR]);
1161 if (!cb.isNull())
1162 return callback(cb, callee, array, pos, dst);
1164 return newNode(AST_CALL_EXPR, pos,
1165 "callee", callee,
1166 "arguments", array,
1167 dst);
1168 }
1170 bool
1171 NodeBuilder::newExpression(HandleValue callee, NodeVector &args, TokenPos *pos,
1172 MutableHandleValue dst)
1173 {
1174 RootedValue array(cx);
1175 if (!newArray(args, &array))
1176 return false;
1178 RootedValue cb(cx, callbacks[AST_NEW_EXPR]);
1179 if (!cb.isNull())
1180 return callback(cb, callee, array, pos, dst);
1182 return newNode(AST_NEW_EXPR, pos,
1183 "callee", callee,
1184 "arguments", array,
1185 dst);
1186 }
1188 bool
1189 NodeBuilder::memberExpression(bool computed, HandleValue expr, HandleValue member, TokenPos *pos,
1190 MutableHandleValue dst)
1191 {
1192 RootedValue computedVal(cx, BooleanValue(computed));
1194 RootedValue cb(cx, callbacks[AST_MEMBER_EXPR]);
1195 if (!cb.isNull())
1196 return callback(cb, computedVal, expr, member, pos, dst);
1198 return newNode(AST_MEMBER_EXPR, pos,
1199 "object", expr,
1200 "property", member,
1201 "computed", computedVal,
1202 dst);
1203 }
1205 bool
1206 NodeBuilder::arrayExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
1207 {
1208 return listNode(AST_ARRAY_EXPR, "elements", elts, pos, dst);
1209 }
1211 bool
1212 NodeBuilder::spreadExpression(HandleValue expr, TokenPos *pos, MutableHandleValue dst)
1213 {
1214 return newNode(AST_SPREAD_EXPR, pos,
1215 "expression", expr,
1216 dst);
1217 }
1219 bool
1220 NodeBuilder::propertyPattern(HandleValue key, HandleValue patt, TokenPos *pos,
1221 MutableHandleValue dst)
1222 {
1223 RootedValue kindName(cx);
1224 if (!atomValue("init", &kindName))
1225 return false;
1227 RootedValue cb(cx, callbacks[AST_PROP_PATT]);
1228 if (!cb.isNull())
1229 return callback(cb, key, patt, pos, dst);
1231 return newNode(AST_PROP_PATT, pos,
1232 "key", key,
1233 "value", patt,
1234 "kind", kindName,
1235 dst);
1236 }
1238 bool
1239 NodeBuilder::propertyInitializer(HandleValue key, HandleValue val, PropKind kind, TokenPos *pos,
1240 MutableHandleValue dst)
1241 {
1242 RootedValue kindName(cx);
1243 if (!atomValue(kind == PROP_INIT
1244 ? "init"
1245 : kind == PROP_GETTER
1246 ? "get"
1247 : "set", &kindName)) {
1248 return false;
1249 }
1251 RootedValue cb(cx, callbacks[AST_PROPERTY]);
1252 if (!cb.isNull())
1253 return callback(cb, kindName, key, val, pos, dst);
1255 return newNode(AST_PROPERTY, pos,
1256 "key", key,
1257 "value", val,
1258 "kind", kindName,
1259 dst);
1260 }
1262 bool
1263 NodeBuilder::objectExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
1264 {
1265 return listNode(AST_OBJECT_EXPR, "properties", elts, pos, dst);
1266 }
1268 bool
1269 NodeBuilder::thisExpression(TokenPos *pos, MutableHandleValue dst)
1270 {
1271 RootedValue cb(cx, callbacks[AST_THIS_EXPR]);
1272 if (!cb.isNull())
1273 return callback(cb, pos, dst);
1275 return newNode(AST_THIS_EXPR, pos, dst);
1276 }
1278 bool
1279 NodeBuilder::yieldExpression(HandleValue arg, YieldKind kind, TokenPos *pos, MutableHandleValue dst)
1280 {
1281 RootedValue cb(cx, callbacks[AST_YIELD_EXPR]);
1282 RootedValue delegateVal(cx);
1284 switch (kind) {
1285 case Delegating:
1286 delegateVal = BooleanValue(true);
1287 break;
1288 case NotDelegating:
1289 delegateVal = BooleanValue(false);
1290 break;
1291 }
1293 if (!cb.isNull())
1294 return callback(cb, opt(arg), delegateVal, pos, dst);
1295 return newNode(AST_YIELD_EXPR, pos, "argument", arg, "delegate", delegateVal, dst);
1296 }
1298 bool
1299 NodeBuilder::comprehensionBlock(HandleValue patt, HandleValue src, bool isForEach, bool isForOf, TokenPos *pos,
1300 MutableHandleValue dst)
1301 {
1302 RootedValue isForEachVal(cx, BooleanValue(isForEach));
1303 RootedValue isForOfVal(cx, BooleanValue(isForOf));
1305 RootedValue cb(cx, callbacks[AST_COMP_BLOCK]);
1306 if (!cb.isNull())
1307 return callback(cb, patt, src, isForEachVal, isForOfVal, pos, dst);
1309 return newNode(AST_COMP_BLOCK, pos,
1310 "left", patt,
1311 "right", src,
1312 "each", isForEachVal,
1313 "of", isForOfVal,
1314 dst);
1315 }
1317 bool
1318 NodeBuilder::comprehensionExpression(HandleValue body, NodeVector &blocks, HandleValue filter,
1319 TokenPos *pos, MutableHandleValue dst)
1320 {
1321 RootedValue array(cx);
1322 if (!newArray(blocks, &array))
1323 return false;
1325 RootedValue cb(cx, callbacks[AST_COMP_EXPR]);
1326 if (!cb.isNull())
1327 return callback(cb, body, array, opt(filter), pos, dst);
1329 return newNode(AST_COMP_EXPR, pos,
1330 "body", body,
1331 "blocks", array,
1332 "filter", filter,
1333 dst);
1334 }
1336 bool
1337 NodeBuilder::generatorExpression(HandleValue body, NodeVector &blocks, HandleValue filter,
1338 TokenPos *pos, MutableHandleValue dst)
1339 {
1340 RootedValue array(cx);
1341 if (!newArray(blocks, &array))
1342 return false;
1344 RootedValue cb(cx, callbacks[AST_GENERATOR_EXPR]);
1345 if (!cb.isNull())
1346 return callback(cb, body, array, opt(filter), pos, dst);
1348 return newNode(AST_GENERATOR_EXPR, pos,
1349 "body", body,
1350 "blocks", array,
1351 "filter", filter,
1352 dst);
1353 }
1355 bool
1356 NodeBuilder::letExpression(NodeVector &head, HandleValue expr, TokenPos *pos,
1357 MutableHandleValue dst)
1358 {
1359 RootedValue array(cx);
1360 if (!newArray(head, &array))
1361 return false;
1363 RootedValue cb(cx, callbacks[AST_LET_EXPR]);
1364 if (!cb.isNull())
1365 return callback(cb, array, expr, pos, dst);
1367 return newNode(AST_LET_EXPR, pos,
1368 "head", array,
1369 "body", expr,
1370 dst);
1371 }
1373 bool
1374 NodeBuilder::letStatement(NodeVector &head, HandleValue stmt, TokenPos *pos, MutableHandleValue dst)
1375 {
1376 RootedValue array(cx);
1377 if (!newArray(head, &array))
1378 return false;
1380 RootedValue cb(cx, callbacks[AST_LET_STMT]);
1381 if (!cb.isNull())
1382 return callback(cb, array, stmt, pos, dst);
1384 return newNode(AST_LET_STMT, pos,
1385 "head", array,
1386 "body", stmt,
1387 dst);
1388 }
1390 bool
1391 NodeBuilder::importDeclaration(NodeVector &elts, HandleValue moduleSpec, TokenPos *pos,
1392 MutableHandleValue dst)
1393 {
1394 RootedValue array(cx);
1395 if (!newArray(elts, &array))
1396 return false;
1398 RootedValue cb(cx, callbacks[AST_IMPORT_DECL]);
1399 if (!cb.isNull())
1400 return callback(cb, array, moduleSpec, pos, dst);
1402 return newNode(AST_IMPORT_DECL, pos,
1403 "specifiers", array,
1404 "source", moduleSpec,
1405 dst);
1406 }
1408 bool
1409 NodeBuilder::importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos *pos,
1410 MutableHandleValue dst)
1411 {
1412 RootedValue cb(cx, callbacks[AST_IMPORT_SPEC]);
1413 if (!cb.isNull())
1414 return callback(cb, importName, bindingName, pos, dst);
1416 return newNode(AST_IMPORT_SPEC, pos,
1417 "id", importName,
1418 "name", bindingName,
1419 dst);
1420 }
1422 bool
1423 NodeBuilder::exportDeclaration(HandleValue decl, NodeVector &elts, HandleValue moduleSpec,
1424 TokenPos *pos, MutableHandleValue dst)
1425 {
1426 RootedValue array(cx, NullValue());
1427 if (decl.isNull() && !newArray(elts, &array))
1428 return false;
1430 RootedValue cb(cx, callbacks[AST_IMPORT_DECL]);
1432 if (!cb.isNull())
1433 return callback(cb, decl, array, moduleSpec, pos, dst);
1435 return newNode(AST_EXPORT_DECL, pos,
1436 "declaration", decl,
1437 "specifiers", array,
1438 "source", moduleSpec,
1439 dst);
1440 }
1442 bool
1443 NodeBuilder::exportSpecifier(HandleValue bindingName, HandleValue exportName, TokenPos *pos,
1444 MutableHandleValue dst)
1445 {
1446 RootedValue cb(cx, callbacks[AST_EXPORT_SPEC]);
1447 if (!cb.isNull())
1448 return callback(cb, bindingName, exportName, pos, dst);
1450 return newNode(AST_EXPORT_SPEC, pos,
1451 "id", bindingName,
1452 "name", exportName,
1453 dst);
1454 }
1456 bool
1457 NodeBuilder::exportBatchSpecifier(TokenPos *pos, MutableHandleValue dst)
1458 {
1459 RootedValue cb(cx, callbacks[AST_EXPORT_BATCH_SPEC]);
1460 if (!cb.isNull())
1461 return callback(cb, pos, dst);
1463 return newNode(AST_EXPORT_BATCH_SPEC, pos, dst);
1464 }
1466 bool
1467 NodeBuilder::variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos,
1468 MutableHandleValue dst)
1469 {
1470 JS_ASSERT(kind > VARDECL_ERR && kind < VARDECL_LIMIT);
1472 RootedValue array(cx), kindName(cx);
1473 if (!newArray(elts, &array) ||
1474 !atomValue(kind == VARDECL_CONST
1475 ? "const"
1476 : kind == VARDECL_LET
1477 ? "let"
1478 : "var", &kindName)) {
1479 return false;
1480 }
1482 RootedValue cb(cx, callbacks[AST_VAR_DECL]);
1483 if (!cb.isNull())
1484 return callback(cb, kindName, array, pos, dst);
1486 return newNode(AST_VAR_DECL, pos,
1487 "kind", kindName,
1488 "declarations", array,
1489 dst);
1490 }
1492 bool
1493 NodeBuilder::variableDeclarator(HandleValue id, HandleValue init, TokenPos *pos,
1494 MutableHandleValue dst)
1495 {
1496 RootedValue cb(cx, callbacks[AST_VAR_DTOR]);
1497 if (!cb.isNull())
1498 return callback(cb, id, opt(init), pos, dst);
1500 return newNode(AST_VAR_DTOR, pos, "id", id, "init", init, dst);
1501 }
1503 bool
1504 NodeBuilder::switchCase(HandleValue expr, NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
1505 {
1506 RootedValue array(cx);
1507 if (!newArray(elts, &array))
1508 return false;
1510 RootedValue cb(cx, callbacks[AST_CASE]);
1511 if (!cb.isNull())
1512 return callback(cb, opt(expr), array, pos, dst);
1514 return newNode(AST_CASE, pos,
1515 "test", expr,
1516 "consequent", array,
1517 dst);
1518 }
1520 bool
1521 NodeBuilder::catchClause(HandleValue var, HandleValue guard, HandleValue body, TokenPos *pos,
1522 MutableHandleValue dst)
1523 {
1524 RootedValue cb(cx, callbacks[AST_CATCH]);
1525 if (!cb.isNull())
1526 return callback(cb, var, opt(guard), body, pos, dst);
1528 return newNode(AST_CATCH, pos,
1529 "param", var,
1530 "guard", guard,
1531 "body", body,
1532 dst);
1533 }
1535 bool
1536 NodeBuilder::literal(HandleValue val, TokenPos *pos, MutableHandleValue dst)
1537 {
1538 RootedValue cb(cx, callbacks[AST_LITERAL]);
1539 if (!cb.isNull())
1540 return callback(cb, val, pos, dst);
1542 return newNode(AST_LITERAL, pos, "value", val, dst);
1543 }
1545 bool
1546 NodeBuilder::identifier(HandleValue name, TokenPos *pos, MutableHandleValue dst)
1547 {
1548 RootedValue cb(cx, callbacks[AST_IDENTIFIER]);
1549 if (!cb.isNull())
1550 return callback(cb, name, pos, dst);
1552 return newNode(AST_IDENTIFIER, pos, "name", name, dst);
1553 }
1555 bool
1556 NodeBuilder::objectPattern(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
1557 {
1558 return listNode(AST_OBJECT_PATT, "properties", elts, pos, dst);
1559 }
1561 bool
1562 NodeBuilder::arrayPattern(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
1563 {
1564 return listNode(AST_ARRAY_PATT, "elements", elts, pos, dst);
1565 }
1567 bool
1568 NodeBuilder::function(ASTType type, TokenPos *pos,
1569 HandleValue id, NodeVector &args, NodeVector &defaults,
1570 HandleValue body, HandleValue rest,
1571 bool isGenerator, bool isExpression,
1572 MutableHandleValue dst)
1573 {
1574 RootedValue array(cx), defarray(cx);
1575 if (!newArray(args, &array))
1576 return false;
1577 if (!newArray(defaults, &defarray))
1578 return false;
1580 RootedValue isGeneratorVal(cx, BooleanValue(isGenerator));
1581 RootedValue isExpressionVal(cx, BooleanValue(isExpression));
1583 RootedValue cb(cx, callbacks[type]);
1584 if (!cb.isNull()) {
1585 return callback(cb, opt(id), array, body, isGeneratorVal, isExpressionVal, pos, dst);
1586 }
1588 return newNode(type, pos,
1589 "id", id,
1590 "params", array,
1591 "defaults", defarray,
1592 "body", body,
1593 "rest", rest,
1594 "generator", isGeneratorVal,
1595 "expression", isExpressionVal,
1596 dst);
1597 }
1599 namespace {
1601 /*
1602 * Serialization of parse nodes to JavaScript objects.
1603 *
1604 * All serialization methods take a non-nullable ParseNode pointer.
1605 */
1606 class ASTSerializer
1607 {
1608 JSContext *cx;
1609 Parser<FullParseHandler> *parser;
1610 NodeBuilder builder;
1611 DebugOnly<uint32_t> lineno;
1613 Value unrootedAtomContents(JSAtom *atom) {
1614 return StringValue(atom ? atom : cx->names().empty);
1615 }
1617 BinaryOperator binop(ParseNodeKind kind, JSOp op);
1618 UnaryOperator unop(ParseNodeKind kind, JSOp op);
1619 AssignmentOperator aop(JSOp op);
1621 bool statements(ParseNode *pn, NodeVector &elts);
1622 bool expressions(ParseNode *pn, NodeVector &elts);
1623 bool leftAssociate(ParseNode *pn, MutableHandleValue dst);
1624 bool functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestruct, ParseNode *pnbody,
1625 NodeVector &args, NodeVector &defaults, MutableHandleValue rest);
1627 bool sourceElement(ParseNode *pn, MutableHandleValue dst);
1629 bool declaration(ParseNode *pn, MutableHandleValue dst);
1630 bool variableDeclaration(ParseNode *pn, bool let, MutableHandleValue dst);
1631 bool variableDeclarator(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst);
1632 bool let(ParseNode *pn, bool expr, MutableHandleValue dst);
1633 bool importDeclaration(ParseNode *pn, MutableHandleValue dst);
1634 bool importSpecifier(ParseNode *pn, MutableHandleValue dst);
1635 bool exportDeclaration(ParseNode *pn, MutableHandleValue dst);
1636 bool exportSpecifier(ParseNode *pn, MutableHandleValue dst);
1638 bool optStatement(ParseNode *pn, MutableHandleValue dst) {
1639 if (!pn) {
1640 dst.setMagic(JS_SERIALIZE_NO_NODE);
1641 return true;
1642 }
1643 return statement(pn, dst);
1644 }
1646 bool forInit(ParseNode *pn, MutableHandleValue dst);
1647 bool forIn(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
1648 MutableHandleValue dst);
1649 bool forOf(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
1650 MutableHandleValue dst);
1651 bool statement(ParseNode *pn, MutableHandleValue dst);
1652 bool blockStatement(ParseNode *pn, MutableHandleValue dst);
1653 bool switchStatement(ParseNode *pn, MutableHandleValue dst);
1654 bool switchCase(ParseNode *pn, MutableHandleValue dst);
1655 bool tryStatement(ParseNode *pn, MutableHandleValue dst);
1656 bool catchClause(ParseNode *pn, bool *isGuarded, MutableHandleValue dst);
1658 bool optExpression(ParseNode *pn, MutableHandleValue dst) {
1659 if (!pn) {
1660 dst.setMagic(JS_SERIALIZE_NO_NODE);
1661 return true;
1662 }
1663 return expression(pn, dst);
1664 }
1666 bool expression(ParseNode *pn, MutableHandleValue dst);
1668 bool propertyName(ParseNode *pn, MutableHandleValue dst);
1669 bool property(ParseNode *pn, MutableHandleValue dst);
1671 bool optIdentifier(HandleAtom atom, TokenPos *pos, MutableHandleValue dst) {
1672 if (!atom) {
1673 dst.setMagic(JS_SERIALIZE_NO_NODE);
1674 return true;
1675 }
1676 return identifier(atom, pos, dst);
1677 }
1679 bool identifier(HandleAtom atom, TokenPos *pos, MutableHandleValue dst);
1680 bool identifier(ParseNode *pn, MutableHandleValue dst);
1681 bool literal(ParseNode *pn, MutableHandleValue dst);
1683 bool pattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst);
1684 bool arrayPattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst);
1685 bool objectPattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst);
1687 bool function(ParseNode *pn, ASTType type, MutableHandleValue dst);
1688 bool functionArgsAndBody(ParseNode *pn, NodeVector &args, NodeVector &defaults,
1689 MutableHandleValue body, MutableHandleValue rest);
1690 bool functionBody(ParseNode *pn, TokenPos *pos, MutableHandleValue dst);
1692 bool comprehensionBlock(ParseNode *pn, MutableHandleValue dst);
1693 bool comprehension(ParseNode *pn, MutableHandleValue dst);
1694 bool generatorExpression(ParseNode *pn, MutableHandleValue dst);
1696 public:
1697 ASTSerializer(JSContext *c, bool l, char const *src, uint32_t ln)
1698 : cx(c)
1699 , builder(c, l, src)
1700 #ifdef DEBUG
1701 , lineno(ln)
1702 #endif
1703 {}
1705 bool init(HandleObject userobj) {
1706 return builder.init(userobj);
1707 }
1709 void setParser(Parser<FullParseHandler> *p) {
1710 parser = p;
1711 builder.setTokenStream(&p->tokenStream);
1712 }
1714 bool program(ParseNode *pn, MutableHandleValue dst);
1715 };
1717 } /* anonymous namespace */
1719 AssignmentOperator
1720 ASTSerializer::aop(JSOp op)
1721 {
1722 switch (op) {
1723 case JSOP_NOP:
1724 return AOP_ASSIGN;
1725 case JSOP_ADD:
1726 return AOP_PLUS;
1727 case JSOP_SUB:
1728 return AOP_MINUS;
1729 case JSOP_MUL:
1730 return AOP_STAR;
1731 case JSOP_DIV:
1732 return AOP_DIV;
1733 case JSOP_MOD:
1734 return AOP_MOD;
1735 case JSOP_LSH:
1736 return AOP_LSH;
1737 case JSOP_RSH:
1738 return AOP_RSH;
1739 case JSOP_URSH:
1740 return AOP_URSH;
1741 case JSOP_BITOR:
1742 return AOP_BITOR;
1743 case JSOP_BITXOR:
1744 return AOP_BITXOR;
1745 case JSOP_BITAND:
1746 return AOP_BITAND;
1747 default:
1748 return AOP_ERR;
1749 }
1750 }
1752 UnaryOperator
1753 ASTSerializer::unop(ParseNodeKind kind, JSOp op)
1754 {
1755 if (kind == PNK_DELETE)
1756 return UNOP_DELETE;
1758 switch (op) {
1759 case JSOP_NEG:
1760 return UNOP_NEG;
1761 case JSOP_POS:
1762 return UNOP_POS;
1763 case JSOP_NOT:
1764 return UNOP_NOT;
1765 case JSOP_BITNOT:
1766 return UNOP_BITNOT;
1767 case JSOP_TYPEOF:
1768 case JSOP_TYPEOFEXPR:
1769 return UNOP_TYPEOF;
1770 case JSOP_VOID:
1771 return UNOP_VOID;
1772 default:
1773 return UNOP_ERR;
1774 }
1775 }
1777 BinaryOperator
1778 ASTSerializer::binop(ParseNodeKind kind, JSOp op)
1779 {
1780 switch (kind) {
1781 case PNK_LSH:
1782 return BINOP_LSH;
1783 case PNK_RSH:
1784 return BINOP_RSH;
1785 case PNK_URSH:
1786 return BINOP_URSH;
1787 case PNK_LT:
1788 return BINOP_LT;
1789 case PNK_LE:
1790 return BINOP_LE;
1791 case PNK_GT:
1792 return BINOP_GT;
1793 case PNK_GE:
1794 return BINOP_GE;
1795 case PNK_EQ:
1796 return BINOP_EQ;
1797 case PNK_NE:
1798 return BINOP_NE;
1799 case PNK_STRICTEQ:
1800 return BINOP_STRICTEQ;
1801 case PNK_STRICTNE:
1802 return BINOP_STRICTNE;
1803 case PNK_ADD:
1804 return BINOP_ADD;
1805 case PNK_SUB:
1806 return BINOP_SUB;
1807 case PNK_STAR:
1808 return BINOP_STAR;
1809 case PNK_DIV:
1810 return BINOP_DIV;
1811 case PNK_MOD:
1812 return BINOP_MOD;
1813 case PNK_BITOR:
1814 return BINOP_BITOR;
1815 case PNK_BITXOR:
1816 return BINOP_BITXOR;
1817 case PNK_BITAND:
1818 return BINOP_BITAND;
1819 case PNK_IN:
1820 return BINOP_IN;
1821 case PNK_INSTANCEOF:
1822 return BINOP_INSTANCEOF;
1823 default:
1824 return BINOP_ERR;
1825 }
1826 }
1828 bool
1829 ASTSerializer::statements(ParseNode *pn, NodeVector &elts)
1830 {
1831 JS_ASSERT(pn->isKind(PNK_STATEMENTLIST));
1832 JS_ASSERT(pn->isArity(PN_LIST));
1834 if (!elts.reserve(pn->pn_count))
1835 return false;
1837 for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
1838 JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
1840 RootedValue elt(cx);
1841 if (!sourceElement(next, &elt))
1842 return false;
1843 elts.infallibleAppend(elt);
1844 }
1846 return true;
1847 }
1849 bool
1850 ASTSerializer::expressions(ParseNode *pn, NodeVector &elts)
1851 {
1852 if (!elts.reserve(pn->pn_count))
1853 return false;
1855 for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
1856 JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
1858 RootedValue elt(cx);
1859 if (!expression(next, &elt))
1860 return false;
1861 elts.infallibleAppend(elt);
1862 }
1864 return true;
1865 }
1867 bool
1868 ASTSerializer::blockStatement(ParseNode *pn, MutableHandleValue dst)
1869 {
1870 JS_ASSERT(pn->isKind(PNK_STATEMENTLIST));
1872 NodeVector stmts(cx);
1873 return statements(pn, stmts) &&
1874 builder.blockStatement(stmts, &pn->pn_pos, dst);
1875 }
1877 bool
1878 ASTSerializer::program(ParseNode *pn, MutableHandleValue dst)
1879 {
1880 JS_ASSERT(parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin) == lineno);
1882 NodeVector stmts(cx);
1883 return statements(pn, stmts) &&
1884 builder.program(stmts, &pn->pn_pos, dst);
1885 }
1887 bool
1888 ASTSerializer::sourceElement(ParseNode *pn, MutableHandleValue dst)
1889 {
1890 /* SpiderMonkey allows declarations even in pure statement contexts. */
1891 return statement(pn, dst);
1892 }
1894 bool
1895 ASTSerializer::declaration(ParseNode *pn, MutableHandleValue dst)
1896 {
1897 JS_ASSERT(pn->isKind(PNK_FUNCTION) ||
1898 pn->isKind(PNK_VAR) ||
1899 pn->isKind(PNK_LET) ||
1900 pn->isKind(PNK_CONST));
1902 switch (pn->getKind()) {
1903 case PNK_FUNCTION:
1904 return function(pn, AST_FUNC_DECL, dst);
1906 case PNK_VAR:
1907 case PNK_CONST:
1908 return variableDeclaration(pn, false, dst);
1910 default:
1911 JS_ASSERT(pn->isKind(PNK_LET));
1912 return variableDeclaration(pn, true, dst);
1913 }
1914 }
1916 bool
1917 ASTSerializer::variableDeclaration(ParseNode *pn, bool let, MutableHandleValue dst)
1918 {
1919 JS_ASSERT(let ? pn->isKind(PNK_LET) : (pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST)));
1921 /* Later updated to VARDECL_CONST if we find a PND_CONST declarator. */
1922 VarDeclKind kind = let ? VARDECL_LET : VARDECL_VAR;
1924 NodeVector dtors(cx);
1925 if (!dtors.reserve(pn->pn_count))
1926 return false;
1927 for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
1928 RootedValue child(cx);
1929 if (!variableDeclarator(next, &kind, &child))
1930 return false;
1931 dtors.infallibleAppend(child);
1932 }
1933 return builder.variableDeclaration(dtors, kind, &pn->pn_pos, dst);
1934 }
1936 bool
1937 ASTSerializer::variableDeclarator(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst)
1938 {
1939 ParseNode *pnleft;
1940 ParseNode *pnright;
1942 if (pn->isKind(PNK_NAME)) {
1943 pnleft = pn;
1944 pnright = pn->isUsed() ? nullptr : pn->pn_expr;
1945 JS_ASSERT_IF(pnright, pn->pn_pos.encloses(pnright->pn_pos));
1946 } else if (pn->isKind(PNK_ASSIGN)) {
1947 pnleft = pn->pn_left;
1948 pnright = pn->pn_right;
1949 JS_ASSERT(pn->pn_pos.encloses(pnleft->pn_pos));
1950 JS_ASSERT(pn->pn_pos.encloses(pnright->pn_pos));
1951 } else {
1952 /* This happens for a destructuring declarator in a for-in/of loop. */
1953 pnleft = pn;
1954 pnright = nullptr;
1955 }
1957 RootedValue left(cx), right(cx);
1958 return pattern(pnleft, pkind, &left) &&
1959 optExpression(pnright, &right) &&
1960 builder.variableDeclarator(left, right, &pn->pn_pos, dst);
1961 }
1963 bool
1964 ASTSerializer::let(ParseNode *pn, bool expr, MutableHandleValue dst)
1965 {
1966 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
1967 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
1969 ParseNode *letHead = pn->pn_left;
1970 LOCAL_ASSERT(letHead->isArity(PN_LIST));
1972 ParseNode *letBody = pn->pn_right;
1973 LOCAL_ASSERT(letBody->isKind(PNK_LEXICALSCOPE));
1975 NodeVector dtors(cx);
1976 if (!dtors.reserve(letHead->pn_count))
1977 return false;
1979 VarDeclKind kind = VARDECL_LET_HEAD;
1981 for (ParseNode *next = letHead->pn_head; next; next = next->pn_next) {
1982 RootedValue child(cx);
1983 /*
1984 * Unlike in |variableDeclaration|, this does not update |kind|; since let-heads do
1985 * not contain const declarations, declarators should never have PND_CONST set.
1986 */
1987 if (!variableDeclarator(next, &kind, &child))
1988 return false;
1989 dtors.infallibleAppend(child);
1990 }
1992 RootedValue v(cx);
1993 return expr
1994 ? expression(letBody->pn_expr, &v) &&
1995 builder.letExpression(dtors, v, &pn->pn_pos, dst)
1996 : statement(letBody->pn_expr, &v) &&
1997 builder.letStatement(dtors, v, &pn->pn_pos, dst);
1998 }
2000 bool
2001 ASTSerializer::importDeclaration(ParseNode *pn, MutableHandleValue dst)
2002 {
2003 JS_ASSERT(pn->isKind(PNK_IMPORT));
2004 JS_ASSERT(pn->pn_left->isKind(PNK_IMPORT_SPEC_LIST));
2005 JS_ASSERT(pn->pn_right->isKind(PNK_STRING));
2007 NodeVector elts(cx);
2008 if (!elts.reserve(pn->pn_count))
2009 return false;
2011 for (ParseNode *next = pn->pn_left->pn_head; next; next = next->pn_next) {
2012 RootedValue elt(cx);
2013 if (!importSpecifier(next, &elt))
2014 return false;
2015 elts.infallibleAppend(elt);
2016 }
2018 RootedValue moduleSpec(cx);
2019 return literal(pn->pn_right, &moduleSpec) &&
2020 builder.importDeclaration(elts, moduleSpec, &pn->pn_pos, dst);
2021 }
2023 bool
2024 ASTSerializer::importSpecifier(ParseNode *pn, MutableHandleValue dst)
2025 {
2026 JS_ASSERT(pn->isKind(PNK_IMPORT_SPEC));
2028 RootedValue importName(cx);
2029 RootedValue bindingName(cx);
2030 return identifier(pn->pn_left, &importName) &&
2031 identifier(pn->pn_right, &bindingName) &&
2032 builder.importSpecifier(importName, bindingName, &pn->pn_pos, dst);
2033 }
2035 bool
2036 ASTSerializer::exportDeclaration(ParseNode *pn, MutableHandleValue dst)
2037 {
2038 JS_ASSERT(pn->isKind(PNK_EXPORT) || pn->isKind(PNK_EXPORT_FROM));
2039 JS_ASSERT_IF(pn->isKind(PNK_EXPORT_FROM), pn->pn_right->isKind(PNK_STRING));
2041 RootedValue decl(cx, NullValue());
2042 NodeVector elts(cx);
2044 ParseNode *kid = pn->isKind(PNK_EXPORT) ? pn->pn_kid : pn->pn_left;
2045 switch (ParseNodeKind kind = kid->getKind()) {
2046 case PNK_EXPORT_SPEC_LIST:
2047 if (!elts.reserve(pn->pn_count))
2048 return false;
2050 for (ParseNode *next = pn->pn_left->pn_head; next; next = next->pn_next) {
2051 RootedValue elt(cx);
2052 if (next->isKind(PNK_EXPORT_SPEC)) {
2053 if (!exportSpecifier(next, &elt))
2054 return false;
2055 } else {
2056 if (!builder.exportBatchSpecifier(&pn->pn_pos, &elt))
2057 return false;
2058 }
2059 elts.infallibleAppend(elt);
2060 }
2061 break;
2063 case PNK_FUNCTION:
2064 if (!function(kid, AST_FUNC_DECL, &decl))
2065 return false;
2066 break;
2068 case PNK_VAR:
2069 case PNK_CONST:
2070 case PNK_LET:
2071 if (!variableDeclaration(kid, kind == PNK_LET, &decl))
2072 return false;
2073 break;
2075 default:
2076 LOCAL_NOT_REACHED("unexpected statement type");
2077 }
2079 RootedValue moduleSpec(cx, NullValue());
2080 if (pn->isKind(PNK_EXPORT_FROM) && !literal(pn->pn_right, &moduleSpec))
2081 return false;
2083 return builder.exportDeclaration(decl, elts, moduleSpec, &pn->pn_pos, dst);
2084 }
2086 bool
2087 ASTSerializer::exportSpecifier(ParseNode *pn, MutableHandleValue dst)
2088 {
2089 JS_ASSERT(pn->isKind(PNK_EXPORT_SPEC));
2091 RootedValue bindingName(cx);
2092 RootedValue exportName(cx);
2093 return identifier(pn->pn_left, &bindingName) &&
2094 identifier(pn->pn_right, &exportName) &&
2095 builder.exportSpecifier(bindingName, exportName, &pn->pn_pos, dst);
2096 }
2098 bool
2099 ASTSerializer::switchCase(ParseNode *pn, MutableHandleValue dst)
2100 {
2101 JS_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos));
2102 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2104 NodeVector stmts(cx);
2106 RootedValue expr(cx);
2108 return optExpression(pn->pn_left, &expr) &&
2109 statements(pn->pn_right, stmts) &&
2110 builder.switchCase(expr, stmts, &pn->pn_pos, dst);
2111 }
2113 bool
2114 ASTSerializer::switchStatement(ParseNode *pn, MutableHandleValue dst)
2115 {
2116 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2117 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2119 RootedValue disc(cx);
2121 if (!expression(pn->pn_left, &disc))
2122 return false;
2124 ParseNode *listNode;
2125 bool lexical;
2127 if (pn->pn_right->isKind(PNK_LEXICALSCOPE)) {
2128 listNode = pn->pn_right->pn_expr;
2129 lexical = true;
2130 } else {
2131 listNode = pn->pn_right;
2132 lexical = false;
2133 }
2135 NodeVector cases(cx);
2136 if (!cases.reserve(listNode->pn_count))
2137 return false;
2139 for (ParseNode *next = listNode->pn_head; next; next = next->pn_next) {
2140 RootedValue child(cx);
2141 if (!switchCase(next, &child))
2142 return false;
2143 cases.infallibleAppend(child);
2144 }
2146 return builder.switchStatement(disc, cases, lexical, &pn->pn_pos, dst);
2147 }
2149 bool
2150 ASTSerializer::catchClause(ParseNode *pn, bool *isGuarded, MutableHandleValue dst)
2151 {
2152 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
2153 JS_ASSERT_IF(pn->pn_kid2, pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
2154 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
2156 RootedValue var(cx), guard(cx), body(cx);
2158 if (!pattern(pn->pn_kid1, nullptr, &var) ||
2159 !optExpression(pn->pn_kid2, &guard)) {
2160 return false;
2161 }
2163 *isGuarded = !guard.isMagic(JS_SERIALIZE_NO_NODE);
2165 return statement(pn->pn_kid3, &body) &&
2166 builder.catchClause(var, guard, body, &pn->pn_pos, dst);
2167 }
2169 bool
2170 ASTSerializer::tryStatement(ParseNode *pn, MutableHandleValue dst)
2171 {
2172 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
2173 JS_ASSERT_IF(pn->pn_kid2, pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
2174 JS_ASSERT_IF(pn->pn_kid3, pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
2176 RootedValue body(cx);
2177 if (!statement(pn->pn_kid1, &body))
2178 return false;
2180 NodeVector guarded(cx);
2181 RootedValue unguarded(cx, NullValue());
2183 if (pn->pn_kid2) {
2184 if (!guarded.reserve(pn->pn_kid2->pn_count))
2185 return false;
2187 for (ParseNode *next = pn->pn_kid2->pn_head; next; next = next->pn_next) {
2188 RootedValue clause(cx);
2189 bool isGuarded;
2190 if (!catchClause(next->pn_expr, &isGuarded, &clause))
2191 return false;
2192 if (isGuarded)
2193 guarded.infallibleAppend(clause);
2194 else
2195 unguarded = clause;
2196 }
2197 }
2199 RootedValue finally(cx);
2200 return optStatement(pn->pn_kid3, &finally) &&
2201 builder.tryStatement(body, guarded, unguarded, finally, &pn->pn_pos, dst);
2202 }
2204 bool
2205 ASTSerializer::forInit(ParseNode *pn, MutableHandleValue dst)
2206 {
2207 if (!pn) {
2208 dst.setMagic(JS_SERIALIZE_NO_NODE);
2209 return true;
2210 }
2212 return (pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST))
2213 ? variableDeclaration(pn, false, dst)
2214 : expression(pn, dst);
2215 }
2217 bool
2218 ASTSerializer::forOf(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
2219 MutableHandleValue dst)
2220 {
2221 RootedValue expr(cx);
2223 return expression(head->pn_kid3, &expr) &&
2224 builder.forOfStatement(var, expr, stmt, &loop->pn_pos, dst);
2225 }
2227 bool
2228 ASTSerializer::forIn(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
2229 MutableHandleValue dst)
2230 {
2231 RootedValue expr(cx);
2232 bool isForEach = loop->pn_iflags & JSITER_FOREACH;
2234 return expression(head->pn_kid3, &expr) &&
2235 builder.forInStatement(var, expr, stmt, isForEach, &loop->pn_pos, dst);
2236 }
2238 bool
2239 ASTSerializer::statement(ParseNode *pn, MutableHandleValue dst)
2240 {
2241 JS_CHECK_RECURSION(cx, return false);
2242 switch (pn->getKind()) {
2243 case PNK_FUNCTION:
2244 case PNK_VAR:
2245 case PNK_CONST:
2246 return declaration(pn, dst);
2248 case PNK_LET:
2249 return pn->isArity(PN_BINARY)
2250 ? let(pn, false, dst)
2251 : declaration(pn, dst);
2253 case PNK_IMPORT:
2254 return importDeclaration(pn, dst);
2256 case PNK_EXPORT:
2257 case PNK_EXPORT_FROM:
2258 return exportDeclaration(pn, dst);
2260 case PNK_NAME:
2261 LOCAL_ASSERT(pn->isUsed());
2262 return statement(pn->pn_lexdef, dst);
2264 case PNK_SEMI:
2265 if (pn->pn_kid) {
2266 RootedValue expr(cx);
2267 return expression(pn->pn_kid, &expr) &&
2268 builder.expressionStatement(expr, &pn->pn_pos, dst);
2269 }
2270 return builder.emptyStatement(&pn->pn_pos, dst);
2272 case PNK_LEXICALSCOPE:
2273 pn = pn->pn_expr;
2274 if (!pn->isKind(PNK_STATEMENTLIST))
2275 return statement(pn, dst);
2276 /* FALL THROUGH */
2278 case PNK_STATEMENTLIST:
2279 return blockStatement(pn, dst);
2281 case PNK_IF:
2282 {
2283 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
2284 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
2285 JS_ASSERT_IF(pn->pn_kid3, pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
2287 RootedValue test(cx), cons(cx), alt(cx);
2289 return expression(pn->pn_kid1, &test) &&
2290 statement(pn->pn_kid2, &cons) &&
2291 optStatement(pn->pn_kid3, &alt) &&
2292 builder.ifStatement(test, cons, alt, &pn->pn_pos, dst);
2293 }
2295 case PNK_SWITCH:
2296 return switchStatement(pn, dst);
2298 case PNK_TRY:
2299 return tryStatement(pn, dst);
2301 case PNK_WITH:
2302 case PNK_WHILE:
2303 {
2304 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2305 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2307 RootedValue expr(cx), stmt(cx);
2309 return expression(pn->pn_left, &expr) &&
2310 statement(pn->pn_right, &stmt) &&
2311 (pn->isKind(PNK_WITH)
2312 ? builder.withStatement(expr, stmt, &pn->pn_pos, dst)
2313 : builder.whileStatement(expr, stmt, &pn->pn_pos, dst));
2314 }
2316 case PNK_DOWHILE:
2317 {
2318 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2319 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2321 RootedValue stmt(cx), test(cx);
2323 return statement(pn->pn_left, &stmt) &&
2324 expression(pn->pn_right, &test) &&
2325 builder.doWhileStatement(stmt, test, &pn->pn_pos, dst);
2326 }
2328 case PNK_FOR:
2329 {
2330 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2331 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2333 ParseNode *head = pn->pn_left;
2335 JS_ASSERT_IF(head->pn_kid1, head->pn_pos.encloses(head->pn_kid1->pn_pos));
2336 JS_ASSERT_IF(head->pn_kid2, head->pn_pos.encloses(head->pn_kid2->pn_pos));
2337 JS_ASSERT_IF(head->pn_kid3, head->pn_pos.encloses(head->pn_kid3->pn_pos));
2339 RootedValue stmt(cx);
2340 if (!statement(pn->pn_right, &stmt))
2341 return false;
2343 if (head->isKind(PNK_FORIN)) {
2344 RootedValue var(cx);
2345 return (!head->pn_kid1
2346 ? pattern(head->pn_kid2, nullptr, &var)
2347 : head->pn_kid1->isKind(PNK_LEXICALSCOPE)
2348 ? variableDeclaration(head->pn_kid1->pn_expr, true, &var)
2349 : variableDeclaration(head->pn_kid1, false, &var)) &&
2350 forIn(pn, head, var, stmt, dst);
2351 }
2353 if (head->isKind(PNK_FOROF)) {
2354 RootedValue var(cx);
2355 return (!head->pn_kid1
2356 ? pattern(head->pn_kid2, nullptr, &var)
2357 : head->pn_kid1->isKind(PNK_LEXICALSCOPE)
2358 ? variableDeclaration(head->pn_kid1->pn_expr, true, &var)
2359 : variableDeclaration(head->pn_kid1, false, &var)) &&
2360 forOf(pn, head, var, stmt, dst);
2361 }
2363 RootedValue init(cx), test(cx), update(cx);
2365 return forInit(head->pn_kid1, &init) &&
2366 optExpression(head->pn_kid2, &test) &&
2367 optExpression(head->pn_kid3, &update) &&
2368 builder.forStatement(init, test, update, stmt, &pn->pn_pos, dst);
2369 }
2371 /* Synthesized by the parser when a for-in loop contains a variable initializer. */
2372 case PNK_SEQ:
2373 {
2374 LOCAL_ASSERT(pn->pn_count == 2);
2376 ParseNode *prelude = pn->pn_head;
2377 ParseNode *loop = prelude->pn_next;
2379 LOCAL_ASSERT(prelude->isKind(PNK_VAR) && loop->isKind(PNK_FOR));
2381 RootedValue var(cx);
2382 if (!variableDeclaration(prelude, false, &var))
2383 return false;
2385 ParseNode *head = loop->pn_left;
2386 JS_ASSERT(head->isKind(PNK_FORIN));
2388 RootedValue stmt(cx);
2390 return statement(loop->pn_right, &stmt) && forIn(loop, head, var, stmt, dst);
2391 }
2393 case PNK_BREAK:
2394 case PNK_CONTINUE:
2395 {
2396 RootedValue label(cx);
2397 RootedAtom pnAtom(cx, pn->pn_atom);
2398 return optIdentifier(pnAtom, nullptr, &label) &&
2399 (pn->isKind(PNK_BREAK)
2400 ? builder.breakStatement(label, &pn->pn_pos, dst)
2401 : builder.continueStatement(label, &pn->pn_pos, dst));
2402 }
2404 case PNK_LABEL:
2405 {
2406 JS_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos));
2408 RootedValue label(cx), stmt(cx);
2409 RootedAtom pnAtom(cx, pn->as<LabeledStatement>().label());
2410 return identifier(pnAtom, nullptr, &label) &&
2411 statement(pn->pn_expr, &stmt) &&
2412 builder.labeledStatement(label, stmt, &pn->pn_pos, dst);
2413 }
2415 case PNK_THROW:
2416 case PNK_RETURN:
2417 {
2418 JS_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2420 RootedValue arg(cx);
2422 return optExpression(pn->pn_kid, &arg) &&
2423 (pn->isKind(PNK_THROW)
2424 ? builder.throwStatement(arg, &pn->pn_pos, dst)
2425 : builder.returnStatement(arg, &pn->pn_pos, dst));
2426 }
2428 case PNK_DEBUGGER:
2429 return builder.debuggerStatement(&pn->pn_pos, dst);
2431 case PNK_NOP:
2432 return builder.emptyStatement(&pn->pn_pos, dst);
2434 default:
2435 LOCAL_NOT_REACHED("unexpected statement type");
2436 }
2437 }
2439 bool
2440 ASTSerializer::leftAssociate(ParseNode *pn, MutableHandleValue dst)
2441 {
2442 JS_ASSERT(pn->isArity(PN_LIST));
2443 JS_ASSERT(pn->pn_count >= 1);
2445 ParseNodeKind kind = pn->getKind();
2446 bool lor = kind == PNK_OR;
2447 bool logop = lor || (kind == PNK_AND);
2449 ParseNode *head = pn->pn_head;
2450 RootedValue left(cx);
2451 if (!expression(head, &left))
2452 return false;
2453 for (ParseNode *next = head->pn_next; next; next = next->pn_next) {
2454 RootedValue right(cx);
2455 if (!expression(next, &right))
2456 return false;
2458 TokenPos subpos(pn->pn_pos.begin, next->pn_pos.end);
2460 if (logop) {
2461 if (!builder.logicalExpression(lor, left, right, &subpos, &left))
2462 return false;
2463 } else {
2464 BinaryOperator op = binop(pn->getKind(), pn->getOp());
2465 LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
2467 if (!builder.binaryExpression(op, left, right, &subpos, &left))
2468 return false;
2469 }
2470 }
2472 dst.set(left);
2473 return true;
2474 }
2476 bool
2477 ASTSerializer::comprehensionBlock(ParseNode *pn, MutableHandleValue dst)
2478 {
2479 LOCAL_ASSERT(pn->isArity(PN_BINARY));
2481 ParseNode *in = pn->pn_left;
2483 LOCAL_ASSERT(in && (in->isKind(PNK_FORIN) || in->isKind(PNK_FOROF)));
2485 bool isForEach = pn->pn_iflags & JSITER_FOREACH;
2486 bool isForOf = in->isKind(PNK_FOROF);
2488 RootedValue patt(cx), src(cx);
2489 return pattern(in->pn_kid2, nullptr, &patt) &&
2490 expression(in->pn_kid3, &src) &&
2491 builder.comprehensionBlock(patt, src, isForEach, isForOf, &in->pn_pos, dst);
2492 }
2494 bool
2495 ASTSerializer::comprehension(ParseNode *pn, MutableHandleValue dst)
2496 {
2497 LOCAL_ASSERT(pn->isKind(PNK_FOR));
2499 NodeVector blocks(cx);
2501 ParseNode *next = pn;
2502 while (next->isKind(PNK_FOR)) {
2503 RootedValue block(cx);
2504 if (!comprehensionBlock(next, &block) || !blocks.append(block))
2505 return false;
2506 next = next->pn_right;
2507 }
2509 RootedValue filter(cx, MagicValue(JS_SERIALIZE_NO_NODE));
2511 if (next->isKind(PNK_IF)) {
2512 if (!optExpression(next->pn_kid1, &filter))
2513 return false;
2514 next = next->pn_kid2;
2515 } else if (next->isKind(PNK_STATEMENTLIST) && next->pn_count == 0) {
2516 /* FoldConstants optimized away the push. */
2517 NodeVector empty(cx);
2518 return builder.arrayExpression(empty, &pn->pn_pos, dst);
2519 }
2521 LOCAL_ASSERT(next->isKind(PNK_ARRAYPUSH));
2523 RootedValue body(cx);
2525 return expression(next->pn_kid, &body) &&
2526 builder.comprehensionExpression(body, blocks, filter, &pn->pn_pos, dst);
2527 }
2529 bool
2530 ASTSerializer::generatorExpression(ParseNode *pn, MutableHandleValue dst)
2531 {
2532 LOCAL_ASSERT(pn->isKind(PNK_FOR));
2534 NodeVector blocks(cx);
2536 ParseNode *next = pn;
2537 while (next->isKind(PNK_FOR)) {
2538 RootedValue block(cx);
2539 if (!comprehensionBlock(next, &block) || !blocks.append(block))
2540 return false;
2541 next = next->pn_right;
2542 }
2544 RootedValue filter(cx, MagicValue(JS_SERIALIZE_NO_NODE));
2546 if (next->isKind(PNK_IF)) {
2547 if (!optExpression(next->pn_kid1, &filter))
2548 return false;
2549 next = next->pn_kid2;
2550 }
2552 LOCAL_ASSERT(next->isKind(PNK_SEMI) &&
2553 next->pn_kid->isKind(PNK_YIELD) &&
2554 next->pn_kid->pn_kid);
2556 RootedValue body(cx);
2558 return expression(next->pn_kid->pn_kid, &body) &&
2559 builder.generatorExpression(body, blocks, filter, &pn->pn_pos, dst);
2560 }
2562 bool
2563 ASTSerializer::expression(ParseNode *pn, MutableHandleValue dst)
2564 {
2565 JS_CHECK_RECURSION(cx, return false);
2566 switch (pn->getKind()) {
2567 case PNK_FUNCTION:
2568 {
2569 ASTType type = pn->pn_funbox->function()->isArrow() ? AST_ARROW_EXPR : AST_FUNC_EXPR;
2570 return function(pn, type, dst);
2571 }
2573 case PNK_COMMA:
2574 {
2575 NodeVector exprs(cx);
2576 return expressions(pn, exprs) &&
2577 builder.sequenceExpression(exprs, &pn->pn_pos, dst);
2578 }
2580 case PNK_CONDITIONAL:
2581 {
2582 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
2583 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
2584 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
2586 RootedValue test(cx), cons(cx), alt(cx);
2588 return expression(pn->pn_kid1, &test) &&
2589 expression(pn->pn_kid2, &cons) &&
2590 expression(pn->pn_kid3, &alt) &&
2591 builder.conditionalExpression(test, cons, alt, &pn->pn_pos, dst);
2592 }
2594 case PNK_OR:
2595 case PNK_AND:
2596 {
2597 if (pn->isArity(PN_BINARY)) {
2598 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2599 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2601 RootedValue left(cx), right(cx);
2602 return expression(pn->pn_left, &left) &&
2603 expression(pn->pn_right, &right) &&
2604 builder.logicalExpression(pn->isKind(PNK_OR), left, right, &pn->pn_pos, dst);
2605 }
2606 return leftAssociate(pn, dst);
2607 }
2609 case PNK_PREINCREMENT:
2610 case PNK_PREDECREMENT:
2611 {
2612 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2614 bool inc = pn->isKind(PNK_PREINCREMENT);
2615 RootedValue expr(cx);
2616 return expression(pn->pn_kid, &expr) &&
2617 builder.updateExpression(expr, inc, true, &pn->pn_pos, dst);
2618 }
2620 case PNK_POSTINCREMENT:
2621 case PNK_POSTDECREMENT:
2622 {
2623 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2625 bool inc = pn->isKind(PNK_POSTINCREMENT);
2626 RootedValue expr(cx);
2627 return expression(pn->pn_kid, &expr) &&
2628 builder.updateExpression(expr, inc, false, &pn->pn_pos, dst);
2629 }
2631 case PNK_ASSIGN:
2632 case PNK_ADDASSIGN:
2633 case PNK_SUBASSIGN:
2634 case PNK_BITORASSIGN:
2635 case PNK_BITXORASSIGN:
2636 case PNK_BITANDASSIGN:
2637 case PNK_LSHASSIGN:
2638 case PNK_RSHASSIGN:
2639 case PNK_URSHASSIGN:
2640 case PNK_MULASSIGN:
2641 case PNK_DIVASSIGN:
2642 case PNK_MODASSIGN:
2643 {
2644 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2645 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2647 AssignmentOperator op = aop(pn->getOp());
2648 LOCAL_ASSERT(op > AOP_ERR && op < AOP_LIMIT);
2650 RootedValue lhs(cx), rhs(cx);
2651 return pattern(pn->pn_left, nullptr, &lhs) &&
2652 expression(pn->pn_right, &rhs) &&
2653 builder.assignmentExpression(op, lhs, rhs, &pn->pn_pos, dst);
2654 }
2656 case PNK_ADD:
2657 case PNK_SUB:
2658 case PNK_STRICTEQ:
2659 case PNK_EQ:
2660 case PNK_STRICTNE:
2661 case PNK_NE:
2662 case PNK_LT:
2663 case PNK_LE:
2664 case PNK_GT:
2665 case PNK_GE:
2666 case PNK_LSH:
2667 case PNK_RSH:
2668 case PNK_URSH:
2669 case PNK_STAR:
2670 case PNK_DIV:
2671 case PNK_MOD:
2672 case PNK_BITOR:
2673 case PNK_BITXOR:
2674 case PNK_BITAND:
2675 case PNK_IN:
2676 case PNK_INSTANCEOF:
2677 if (pn->isArity(PN_BINARY)) {
2678 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2679 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2681 BinaryOperator op = binop(pn->getKind(), pn->getOp());
2682 LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
2684 RootedValue left(cx), right(cx);
2685 return expression(pn->pn_left, &left) &&
2686 expression(pn->pn_right, &right) &&
2687 builder.binaryExpression(op, left, right, &pn->pn_pos, dst);
2688 }
2689 return leftAssociate(pn, dst);
2691 case PNK_DELETE:
2692 case PNK_TYPEOF:
2693 case PNK_VOID:
2694 case PNK_NOT:
2695 case PNK_BITNOT:
2696 case PNK_POS:
2697 case PNK_NEG: {
2698 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2700 UnaryOperator op = unop(pn->getKind(), pn->getOp());
2701 LOCAL_ASSERT(op > UNOP_ERR && op < UNOP_LIMIT);
2703 RootedValue expr(cx);
2704 return expression(pn->pn_kid, &expr) &&
2705 builder.unaryExpression(op, expr, &pn->pn_pos, dst);
2706 }
2708 #if JS_HAS_GENERATOR_EXPRS
2709 case PNK_GENEXP:
2710 return generatorExpression(pn->generatorExpr(), dst);
2711 #endif
2713 case PNK_NEW:
2714 case PNK_CALL:
2715 {
2716 ParseNode *next = pn->pn_head;
2717 JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2719 RootedValue callee(cx);
2720 if (!expression(next, &callee))
2721 return false;
2723 NodeVector args(cx);
2724 if (!args.reserve(pn->pn_count - 1))
2725 return false;
2727 for (next = next->pn_next; next; next = next->pn_next) {
2728 JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2730 RootedValue arg(cx);
2731 if (!expression(next, &arg))
2732 return false;
2733 args.infallibleAppend(arg);
2734 }
2736 return pn->isKind(PNK_NEW)
2737 ? builder.newExpression(callee, args, &pn->pn_pos, dst)
2739 : builder.callExpression(callee, args, &pn->pn_pos, dst);
2740 }
2742 case PNK_DOT:
2743 {
2744 JS_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos));
2746 RootedValue expr(cx), id(cx);
2747 RootedAtom pnAtom(cx, pn->pn_atom);
2748 return expression(pn->pn_expr, &expr) &&
2749 identifier(pnAtom, nullptr, &id) &&
2750 builder.memberExpression(false, expr, id, &pn->pn_pos, dst);
2751 }
2753 case PNK_ELEM:
2754 {
2755 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2756 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2758 RootedValue left(cx), right(cx);
2759 return expression(pn->pn_left, &left) &&
2760 expression(pn->pn_right, &right) &&
2761 builder.memberExpression(true, left, right, &pn->pn_pos, dst);
2762 }
2764 case PNK_ARRAY:
2765 {
2766 NodeVector elts(cx);
2767 if (!elts.reserve(pn->pn_count))
2768 return false;
2770 for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
2771 JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2773 if (next->isKind(PNK_ELISION)) {
2774 elts.infallibleAppend(NullValue());
2775 } else {
2776 RootedValue expr(cx);
2777 if (!expression(next, &expr))
2778 return false;
2779 elts.infallibleAppend(expr);
2780 }
2781 }
2783 return builder.arrayExpression(elts, &pn->pn_pos, dst);
2784 }
2786 case PNK_SPREAD:
2787 {
2788 RootedValue expr(cx);
2789 return expression(pn->pn_kid, &expr) &&
2790 builder.spreadExpression(expr, &pn->pn_pos, dst);
2791 }
2793 case PNK_OBJECT:
2794 {
2795 /* The parser notes any uninitialized properties by setting the PNX_DESTRUCT flag. */
2796 if (pn->pn_xflags & PNX_DESTRUCT) {
2797 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_OBJECT_INIT);
2798 return false;
2799 }
2800 NodeVector elts(cx);
2801 if (!elts.reserve(pn->pn_count))
2802 return false;
2804 for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
2805 JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2807 RootedValue prop(cx);
2808 if (!property(next, &prop))
2809 return false;
2810 elts.infallibleAppend(prop);
2811 }
2813 return builder.objectExpression(elts, &pn->pn_pos, dst);
2814 }
2816 case PNK_NAME:
2817 return identifier(pn, dst);
2819 case PNK_THIS:
2820 return builder.thisExpression(&pn->pn_pos, dst);
2822 case PNK_STRING:
2823 case PNK_REGEXP:
2824 case PNK_NUMBER:
2825 case PNK_TRUE:
2826 case PNK_FALSE:
2827 case PNK_NULL:
2828 return literal(pn, dst);
2830 case PNK_YIELD_STAR:
2831 {
2832 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2834 RootedValue arg(cx);
2835 return expression(pn->pn_kid, &arg) &&
2836 builder.yieldExpression(arg, Delegating, &pn->pn_pos, dst);
2837 }
2839 case PNK_YIELD:
2840 {
2841 JS_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2843 RootedValue arg(cx);
2844 return optExpression(pn->pn_kid, &arg) &&
2845 builder.yieldExpression(arg, NotDelegating, &pn->pn_pos, dst);
2846 }
2848 case PNK_ARRAYCOMP:
2849 JS_ASSERT(pn->pn_pos.encloses(pn->pn_head->pn_pos));
2851 /* NB: it's no longer the case that pn_count could be 2. */
2852 LOCAL_ASSERT(pn->pn_count == 1);
2853 LOCAL_ASSERT(pn->pn_head->isKind(PNK_LEXICALSCOPE));
2855 return comprehension(pn->pn_head->pn_expr, dst);
2857 case PNK_LET:
2858 return let(pn, true, dst);
2860 default:
2861 LOCAL_NOT_REACHED("unexpected expression type");
2862 }
2863 }
2865 bool
2866 ASTSerializer::propertyName(ParseNode *pn, MutableHandleValue dst)
2867 {
2868 if (pn->isKind(PNK_NAME))
2869 return identifier(pn, dst);
2871 LOCAL_ASSERT(pn->isKind(PNK_STRING) || pn->isKind(PNK_NUMBER));
2873 return literal(pn, dst);
2874 }
2876 bool
2877 ASTSerializer::property(ParseNode *pn, MutableHandleValue dst)
2878 {
2879 PropKind kind;
2880 switch (pn->getOp()) {
2881 case JSOP_INITPROP:
2882 kind = PROP_INIT;
2883 break;
2885 case JSOP_INITPROP_GETTER:
2886 kind = PROP_GETTER;
2887 break;
2889 case JSOP_INITPROP_SETTER:
2890 kind = PROP_SETTER;
2891 break;
2893 default:
2894 LOCAL_NOT_REACHED("unexpected object-literal property");
2895 }
2897 RootedValue key(cx), val(cx);
2898 return propertyName(pn->pn_left, &key) &&
2899 expression(pn->pn_right, &val) &&
2900 builder.propertyInitializer(key, val, kind, &pn->pn_pos, dst);
2901 }
2903 bool
2904 ASTSerializer::literal(ParseNode *pn, MutableHandleValue dst)
2905 {
2906 RootedValue val(cx);
2907 switch (pn->getKind()) {
2908 case PNK_STRING:
2909 val.setString(pn->pn_atom);
2910 break;
2912 case PNK_REGEXP:
2913 {
2914 RootedObject re1(cx, pn->as<RegExpLiteral>().objbox()->object);
2915 LOCAL_ASSERT(re1 && re1->is<RegExpObject>());
2917 RootedObject re2(cx, CloneRegExpObject(cx, re1));
2918 if (!re2)
2919 return false;
2921 val.setObject(*re2);
2922 break;
2923 }
2925 case PNK_NUMBER:
2926 val.setNumber(pn->pn_dval);
2927 break;
2929 case PNK_NULL:
2930 val.setNull();
2931 break;
2933 case PNK_TRUE:
2934 val.setBoolean(true);
2935 break;
2937 case PNK_FALSE:
2938 val.setBoolean(false);
2939 break;
2941 default:
2942 LOCAL_NOT_REACHED("unexpected literal type");
2943 }
2945 return builder.literal(val, &pn->pn_pos, dst);
2946 }
2948 bool
2949 ASTSerializer::arrayPattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst)
2950 {
2951 JS_ASSERT(pn->isKind(PNK_ARRAY));
2953 NodeVector elts(cx);
2954 if (!elts.reserve(pn->pn_count))
2955 return false;
2957 for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
2958 if (next->isKind(PNK_ELISION)) {
2959 elts.infallibleAppend(NullValue());
2960 } else {
2961 RootedValue patt(cx);
2962 if (!pattern(next, pkind, &patt))
2963 return false;
2964 elts.infallibleAppend(patt);
2965 }
2966 }
2968 return builder.arrayPattern(elts, &pn->pn_pos, dst);
2969 }
2971 bool
2972 ASTSerializer::objectPattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst)
2973 {
2974 JS_ASSERT(pn->isKind(PNK_OBJECT));
2976 NodeVector elts(cx);
2977 if (!elts.reserve(pn->pn_count))
2978 return false;
2980 for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
2981 LOCAL_ASSERT(next->isOp(JSOP_INITPROP));
2983 RootedValue key(cx), patt(cx), prop(cx);
2984 if (!propertyName(next->pn_left, &key) ||
2985 !pattern(next->pn_right, pkind, &patt) ||
2986 !builder.propertyPattern(key, patt, &next->pn_pos, &prop)) {
2987 return false;
2988 }
2990 elts.infallibleAppend(prop);
2991 }
2993 return builder.objectPattern(elts, &pn->pn_pos, dst);
2994 }
2996 bool
2997 ASTSerializer::pattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst)
2998 {
2999 JS_CHECK_RECURSION(cx, return false);
3000 switch (pn->getKind()) {
3001 case PNK_OBJECT:
3002 return objectPattern(pn, pkind, dst);
3004 case PNK_ARRAY:
3005 return arrayPattern(pn, pkind, dst);
3007 case PNK_NAME:
3008 if (pkind && (pn->pn_dflags & PND_CONST))
3009 *pkind = VARDECL_CONST;
3010 /* FALL THROUGH */
3012 default:
3013 return expression(pn, dst);
3014 }
3015 }
3017 bool
3018 ASTSerializer::identifier(HandleAtom atom, TokenPos *pos, MutableHandleValue dst)
3019 {
3020 RootedValue atomContentsVal(cx, unrootedAtomContents(atom));
3021 return builder.identifier(atomContentsVal, pos, dst);
3022 }
3024 bool
3025 ASTSerializer::identifier(ParseNode *pn, MutableHandleValue dst)
3026 {
3027 LOCAL_ASSERT(pn->isArity(PN_NAME) || pn->isArity(PN_NULLARY));
3028 LOCAL_ASSERT(pn->pn_atom);
3030 RootedAtom pnAtom(cx, pn->pn_atom);
3031 return identifier(pnAtom, &pn->pn_pos, dst);
3032 }
3034 bool
3035 ASTSerializer::function(ParseNode *pn, ASTType type, MutableHandleValue dst)
3036 {
3037 RootedFunction func(cx, pn->pn_funbox->function());
3039 // FIXME: Provide more information (legacy generator vs star generator).
3040 bool isGenerator = pn->pn_funbox->isGenerator();
3042 bool isExpression =
3043 #if JS_HAS_EXPR_CLOSURES
3044 func->isExprClosure();
3045 #else
3046 false;
3047 #endif
3049 RootedValue id(cx);
3050 RootedAtom funcAtom(cx, func->atom());
3051 if (!optIdentifier(funcAtom, nullptr, &id))
3052 return false;
3054 NodeVector args(cx);
3055 NodeVector defaults(cx);
3057 RootedValue body(cx), rest(cx);
3058 if (func->hasRest())
3059 rest.setUndefined();
3060 else
3061 rest.setNull();
3062 return functionArgsAndBody(pn->pn_body, args, defaults, &body, &rest) &&
3063 builder.function(type, &pn->pn_pos, id, args, defaults, body,
3064 rest, isGenerator, isExpression, dst);
3065 }
3067 bool
3068 ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args, NodeVector &defaults,
3069 MutableHandleValue body, MutableHandleValue rest)
3070 {
3071 ParseNode *pnargs;
3072 ParseNode *pnbody;
3074 /* Extract the args and body separately. */
3075 if (pn->isKind(PNK_ARGSBODY)) {
3076 pnargs = pn;
3077 pnbody = pn->last();
3078 } else {
3079 pnargs = nullptr;
3080 pnbody = pn;
3081 }
3083 ParseNode *pndestruct;
3085 /* Extract the destructuring assignments. */
3086 if (pnbody->isArity(PN_LIST) && (pnbody->pn_xflags & PNX_DESTRUCT)) {
3087 ParseNode *head = pnbody->pn_head;
3088 LOCAL_ASSERT(head && head->isKind(PNK_SEMI));
3090 pndestruct = head->pn_kid;
3091 LOCAL_ASSERT(pndestruct);
3092 LOCAL_ASSERT(pndestruct->isKind(PNK_VAR));
3093 } else {
3094 pndestruct = nullptr;
3095 }
3097 /* Serialize the arguments and body. */
3098 switch (pnbody->getKind()) {
3099 case PNK_RETURN: /* expression closure, no destructured args */
3100 return functionArgs(pn, pnargs, nullptr, pnbody, args, defaults, rest) &&
3101 expression(pnbody->pn_kid, body);
3103 case PNK_SEQ: /* expression closure with destructured args */
3104 {
3105 ParseNode *pnstart = pnbody->pn_head->pn_next;
3106 LOCAL_ASSERT(pnstart && pnstart->isKind(PNK_RETURN));
3108 return functionArgs(pn, pnargs, pndestruct, pnbody, args, defaults, rest) &&
3109 expression(pnstart->pn_kid, body);
3110 }
3112 case PNK_STATEMENTLIST: /* statement closure */
3113 {
3114 ParseNode *pnstart = (pnbody->pn_xflags & PNX_DESTRUCT)
3115 ? pnbody->pn_head->pn_next
3116 : pnbody->pn_head;
3118 return functionArgs(pn, pnargs, pndestruct, pnbody, args, defaults, rest) &&
3119 functionBody(pnstart, &pnbody->pn_pos, body);
3120 }
3122 default:
3123 LOCAL_NOT_REACHED("unexpected function contents");
3124 }
3125 }
3127 bool
3128 ASTSerializer::functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestruct,
3129 ParseNode *pnbody, NodeVector &args, NodeVector &defaults,
3130 MutableHandleValue rest)
3131 {
3132 uint32_t i = 0;
3133 ParseNode *arg = pnargs ? pnargs->pn_head : nullptr;
3134 ParseNode *destruct = pndestruct ? pndestruct->pn_head : nullptr;
3135 RootedValue node(cx);
3137 /*
3138 * Arguments are found in potentially two different places: 1) the
3139 * argsbody sequence (which ends with the body node), or 2) a
3140 * destructuring initialization at the beginning of the body. Loop
3141 * |arg| through the argsbody and |destruct| through the initial
3142 * destructuring assignments, stopping only when we've exhausted
3143 * both.
3144 */
3145 while ((arg && arg != pnbody) || destruct) {
3146 if (destruct && destruct->pn_right->frameSlot() == i) {
3147 if (!pattern(destruct->pn_left, nullptr, &node) || !args.append(node))
3148 return false;
3149 destruct = destruct->pn_next;
3150 } else if (arg && arg != pnbody) {
3151 /*
3152 * We don't check that arg->frameSlot() == i since we
3153 * can't call that method if the arg def has been turned
3154 * into a use, e.g.:
3155 *
3156 * function(a) { function a() { } }
3157 *
3158 * There's no other way to ask a non-destructuring arg its
3159 * index in the formals list, so we rely on the ability to
3160 * ask destructuring args their index above.
3161 */
3162 JS_ASSERT(arg->isKind(PNK_NAME) || arg->isKind(PNK_ASSIGN));
3163 ParseNode *argName = arg->isKind(PNK_NAME) ? arg : arg->pn_left;
3164 if (!identifier(argName, &node))
3165 return false;
3166 if (rest.isUndefined() && arg->pn_next == pnbody)
3167 rest.setObject(node.toObject());
3168 else if (!args.append(node))
3169 return false;
3170 if (arg->pn_dflags & PND_DEFAULT) {
3171 ParseNode *expr = arg->isDefn() ? arg->expr() : arg->pn_kid->pn_right;
3172 RootedValue def(cx);
3173 if (!expression(expr, &def) || !defaults.append(def))
3174 return false;
3175 }
3176 arg = arg->pn_next;
3177 } else {
3178 LOCAL_NOT_REACHED("missing function argument");
3179 }
3180 ++i;
3181 }
3182 JS_ASSERT(!rest.isUndefined());
3184 return true;
3185 }
3187 bool
3188 ASTSerializer::functionBody(ParseNode *pn, TokenPos *pos, MutableHandleValue dst)
3189 {
3190 NodeVector elts(cx);
3192 /* We aren't sure how many elements there are up front, so we'll check each append. */
3193 for (ParseNode *next = pn; next; next = next->pn_next) {
3194 RootedValue child(cx);
3195 if (!sourceElement(next, &child) || !elts.append(child))
3196 return false;
3197 }
3199 return builder.blockStatement(elts, pos, dst);
3200 }
3202 static bool
3203 reflect_parse(JSContext *cx, uint32_t argc, jsval *vp)
3204 {
3205 CallArgs args = CallArgsFromVp(argc, vp);
3207 if (args.length() < 1) {
3208 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
3209 "Reflect.parse", "0", "s");
3210 return false;
3211 }
3213 RootedString src(cx, ToString<CanGC>(cx, args[0]));
3214 if (!src)
3215 return false;
3217 ScopedJSFreePtr<char> filename;
3218 uint32_t lineno = 1;
3219 bool loc = true;
3221 RootedObject builder(cx);
3223 RootedValue arg(cx, args.get(1));
3225 if (!arg.isNullOrUndefined()) {
3226 if (!arg.isObject()) {
3227 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
3228 JSDVG_SEARCH_STACK, arg, js::NullPtr(),
3229 "not an object", nullptr);
3230 return false;
3231 }
3233 RootedObject config(cx, &arg.toObject());
3235 RootedValue prop(cx);
3237 /* config.loc */
3238 RootedId locId(cx, NameToId(cx->names().loc));
3239 RootedValue trueVal(cx, BooleanValue(true));
3240 if (!GetPropertyDefault(cx, config, locId, trueVal, &prop))
3241 return false;
3243 loc = ToBoolean(prop);
3245 if (loc) {
3246 /* config.source */
3247 RootedId sourceId(cx, NameToId(cx->names().source));
3248 RootedValue nullVal(cx, NullValue());
3249 if (!GetPropertyDefault(cx, config, sourceId, nullVal, &prop))
3250 return false;
3252 if (!prop.isNullOrUndefined()) {
3253 RootedString str(cx, ToString<CanGC>(cx, prop));
3254 if (!str)
3255 return false;
3257 size_t length = str->length();
3258 const jschar *chars = str->getChars(cx);
3259 if (!chars)
3260 return false;
3262 TwoByteChars tbchars(chars, length);
3263 filename = LossyTwoByteCharsToNewLatin1CharsZ(cx, tbchars).c_str();
3264 if (!filename)
3265 return false;
3266 }
3268 /* config.line */
3269 RootedId lineId(cx, NameToId(cx->names().line));
3270 RootedValue oneValue(cx, Int32Value(1));
3271 if (!GetPropertyDefault(cx, config, lineId, oneValue, &prop) ||
3272 !ToUint32(cx, prop, &lineno)) {
3273 return false;
3274 }
3275 }
3277 /* config.builder */
3278 RootedId builderId(cx, NameToId(cx->names().builder));
3279 RootedValue nullVal(cx, NullValue());
3280 if (!GetPropertyDefault(cx, config, builderId, nullVal, &prop))
3281 return false;
3283 if (!prop.isNullOrUndefined()) {
3284 if (!prop.isObject()) {
3285 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
3286 JSDVG_SEARCH_STACK, prop, js::NullPtr(),
3287 "not an object", nullptr);
3288 return false;
3289 }
3290 builder = &prop.toObject();
3291 }
3292 }
3294 /* Extract the builder methods first to report errors before parsing. */
3295 ASTSerializer serialize(cx, loc, filename, lineno);
3296 if (!serialize.init(builder))
3297 return false;
3299 JSFlatString *flat = src->ensureFlat(cx);
3300 if (!flat)
3301 return false;
3303 CompileOptions options(cx);
3304 options.setFileAndLine(filename, lineno);
3305 options.setCanLazilyParse(false);
3306 Parser<FullParseHandler> parser(cx, &cx->tempLifoAlloc(), options, flat->chars(),
3307 flat->length(), /* foldConstants = */ false, nullptr, nullptr);
3309 serialize.setParser(&parser);
3311 ParseNode *pn = parser.parse(nullptr);
3312 if (!pn)
3313 return false;
3315 RootedValue val(cx);
3316 if (!serialize.program(pn, &val)) {
3317 args.rval().setNull();
3318 return false;
3319 }
3321 args.rval().set(val);
3322 return true;
3323 }
3325 JS_PUBLIC_API(JSObject *)
3326 JS_InitReflect(JSContext *cx, HandleObject obj)
3327 {
3328 static const JSFunctionSpec static_methods[] = {
3329 JS_FN("parse", reflect_parse, 1, 0),
3330 JS_FS_END
3331 };
3333 RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx));
3334 if (!proto)
3335 return nullptr;
3336 RootedObject Reflect(cx, NewObjectWithGivenProto(cx, &JSObject::class_, proto,
3337 obj, SingletonObject));
3338 if (!Reflect)
3339 return nullptr;
3341 if (!JS_DefineProperty(cx, obj, "Reflect", Reflect, 0,
3342 JS_PropertyStub, JS_StrictPropertyStub)) {
3343 return nullptr;
3344 }
3346 if (!JS_DefineFunctions(cx, Reflect, static_methods))
3347 return nullptr;
3349 return Reflect;
3350 }