Bumping manifests a=b2g-bump
[gecko.git] / js / src / jsreflect.cpp
blob9c38ad1458db1c25bef623c83adcc626d6e27e39
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 */
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 */
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 */
86 char const * const js::nodeTypeNames[] = {
87 #define ASTDEF(ast, str, method) str,
88 #include "jsast.tbl"
89 #undef ASTDEF
90 nullptr
93 static char const * const callbackNames[] = {
94 #define ASTDEF(ast, str, method) method,
95 #include "jsast.tbl"
96 #undef ASTDEF
97 nullptr
100 enum YieldKind { Delegating, NotDelegating };
102 typedef AutoValueVector NodeVector;
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.
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; \
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)
133 bool found;
134 if (!JSObject::hasProperty(cx, obj, id, &found))
135 return false;
136 if (!found) {
137 result.set(defaultValue);
138 return true;
140 return JSObject::getGeneric(cx, obj, obj, id, result);
144 * Builder class that constructs JavaScript AST node objects. See:
146 * https://developer.mozilla.org/en/SpiderMonkey/Parser_API
148 * Bug 569487: generalize builder interface
150 class NodeBuilder
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)
168 bool init(HandleObject userobj = js::NullPtr()) {
169 if (src) {
170 if (!atomValue(src, &srcval))
171 return false;
172 } else {
173 srcval.setNull();
176 if (!userobj) {
177 userv.setNull();
178 for (unsigned i = 0; i < AST_LIMIT; i++) {
179 callbacks[i].setNull();
181 return true;
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;
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;
208 callbacks[i].set(funv);
211 return true;
214 void setTokenStream(TokenStream *ts) {
215 tokenStream = ts;
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);
229 AutoValueArray<1> argv(cx);
230 argv[0].setNull(); /* no zero-length arrays allowed! */
231 return Invoke(cx, userv, fun, 0, argv.begin(), dst);
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);
245 AutoValueArray<1> argv(cx);
246 argv[0].set(v1);
247 return Invoke(cx, userv, fun, argv.length(), argv.begin(), dst);
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);
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);
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);
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);
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);
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);
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);
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);
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;
347 bool atomValue(const char *s, MutableHandleValue dst) {
349 * Bug 575416: instead of Atomize, lookup constant atoms in tbl file
351 RootedAtom atom(cx, Atomize(cx, s, strlen(s)));
352 if (!atom)
353 return false;
355 dst.setString(atom);
356 return true;
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;
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);
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);
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);
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);
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);
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);
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 MutableHandleValue dst) {
451 RootedObject node(cx);
452 return newNode(type, pos, &node) &&
453 setProperty(node, childName1, child1) &&
454 setProperty(node, childName2, child2) &&
455 setProperty(node, childName3, child3) &&
456 setProperty(node, childName4, child4) &&
457 setProperty(node, childName5, child5) &&
458 setProperty(node, childName6, child6) &&
459 setResult(node, dst);
462 bool newNode(ASTType type, TokenPos *pos,
463 const char *childName1, HandleValue child1,
464 const char *childName2, HandleValue child2,
465 const char *childName3, HandleValue child3,
466 const char *childName4, HandleValue child4,
467 const char *childName5, HandleValue child5,
468 const char *childName6, HandleValue child6,
469 const char *childName7, HandleValue child7,
470 MutableHandleValue dst) {
471 RootedObject node(cx);
472 return newNode(type, pos, &node) &&
473 setProperty(node, childName1, child1) &&
474 setProperty(node, childName2, child2) &&
475 setProperty(node, childName3, child3) &&
476 setProperty(node, childName4, child4) &&
477 setProperty(node, childName5, child5) &&
478 setProperty(node, childName6, child6) &&
479 setProperty(node, childName7, child7) &&
480 setResult(node, dst);
483 bool listNode(ASTType type, const char *propName, NodeVector &elts, TokenPos *pos,
484 MutableHandleValue dst) {
485 RootedValue array(cx);
486 if (!newArray(elts, &array))
487 return false;
489 RootedValue cb(cx, callbacks[type]);
490 if (!cb.isNull())
491 return callback(cb, array, pos, dst);
493 return newNode(type, pos, propName, array, dst);
496 bool setProperty(HandleObject obj, const char *name, HandleValue val) {
497 JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
500 * Bug 575416: instead of Atomize, lookup constant atoms in tbl file
502 RootedAtom atom(cx, Atomize(cx, name, strlen(name)));
503 if (!atom)
504 return false;
506 /* Represent "no node" as null and ensure users are not exposed to magic values. */
507 RootedValue optVal(cx, val.isMagic(JS_SERIALIZE_NO_NODE) ? NullValue() : val);
508 return JSObject::defineProperty(cx, obj, atom->asPropertyName(), optVal);
511 bool newNodeLoc(TokenPos *pos, MutableHandleValue dst);
513 bool setNodeLoc(HandleObject node, TokenPos *pos);
515 bool setResult(HandleObject obj, MutableHandleValue dst) {
516 JS_ASSERT(obj);
517 dst.setObject(*obj);
518 return true;
521 public:
523 * All of the public builder methods take as their last two
524 * arguments a nullable token position and a non-nullable, rooted
525 * outparam.
527 * Any Value arguments representing optional subnodes may be a
528 * JS_SERIALIZE_NO_NODE magic value.
532 * misc nodes
535 bool program(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
537 bool literal(HandleValue val, TokenPos *pos, MutableHandleValue dst);
539 bool identifier(HandleValue name, TokenPos *pos, MutableHandleValue dst);
541 bool function(ASTType type, TokenPos *pos,
542 HandleValue id, NodeVector &args, NodeVector &defaults,
543 HandleValue body, HandleValue rest, bool isGenerator, bool isExpression,
544 MutableHandleValue dst);
546 bool variableDeclarator(HandleValue id, HandleValue init, TokenPos *pos,
547 MutableHandleValue dst);
549 bool switchCase(HandleValue expr, NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
551 bool catchClause(HandleValue var, HandleValue guard, HandleValue body, TokenPos *pos,
552 MutableHandleValue dst);
554 bool propertyInitializer(HandleValue key, HandleValue val, PropKind kind, bool isShorthand,
555 bool isMethod, TokenPos *pos, MutableHandleValue dst);
559 * statements
562 bool blockStatement(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
564 bool expressionStatement(HandleValue expr, TokenPos *pos, MutableHandleValue dst);
566 bool emptyStatement(TokenPos *pos, MutableHandleValue dst);
568 bool ifStatement(HandleValue test, HandleValue cons, HandleValue alt, TokenPos *pos,
569 MutableHandleValue dst);
571 bool breakStatement(HandleValue label, TokenPos *pos, MutableHandleValue dst);
573 bool continueStatement(HandleValue label, TokenPos *pos, MutableHandleValue dst);
575 bool labeledStatement(HandleValue label, HandleValue stmt, TokenPos *pos,
576 MutableHandleValue dst);
578 bool throwStatement(HandleValue arg, TokenPos *pos, MutableHandleValue dst);
580 bool returnStatement(HandleValue arg, TokenPos *pos, MutableHandleValue dst);
582 bool forStatement(HandleValue init, HandleValue test, HandleValue update, HandleValue stmt,
583 TokenPos *pos, MutableHandleValue dst);
585 bool forInStatement(HandleValue var, HandleValue expr, HandleValue stmt,
586 bool isForEach, TokenPos *pos, MutableHandleValue dst);
588 bool forOfStatement(HandleValue var, HandleValue expr, HandleValue stmt, TokenPos *pos,
589 MutableHandleValue dst);
591 bool withStatement(HandleValue expr, HandleValue stmt, TokenPos *pos, MutableHandleValue dst);
593 bool whileStatement(HandleValue test, HandleValue stmt, TokenPos *pos, MutableHandleValue dst);
595 bool doWhileStatement(HandleValue stmt, HandleValue test, TokenPos *pos,
596 MutableHandleValue dst);
598 bool switchStatement(HandleValue disc, NodeVector &elts, bool lexical, TokenPos *pos,
599 MutableHandleValue dst);
601 bool tryStatement(HandleValue body, NodeVector &guarded, HandleValue unguarded,
602 HandleValue finally, TokenPos *pos, MutableHandleValue dst);
604 bool debuggerStatement(TokenPos *pos, MutableHandleValue dst);
606 bool letStatement(NodeVector &head, HandleValue stmt, TokenPos *pos, MutableHandleValue dst);
608 bool importDeclaration(NodeVector &elts, HandleValue moduleSpec, TokenPos *pos, MutableHandleValue dst);
610 bool importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos *pos, MutableHandleValue dst);
612 bool exportDeclaration(HandleValue decl, NodeVector &elts, HandleValue moduleSpec, TokenPos *pos, MutableHandleValue dst);
614 bool exportSpecifier(HandleValue bindingName, HandleValue exportName, TokenPos *pos, MutableHandleValue dst);
616 bool exportBatchSpecifier(TokenPos *pos, MutableHandleValue dst);
619 * expressions
622 bool binaryExpression(BinaryOperator op, HandleValue left, HandleValue right, TokenPos *pos,
623 MutableHandleValue dst);
625 bool unaryExpression(UnaryOperator op, HandleValue expr, TokenPos *pos, MutableHandleValue dst);
627 bool assignmentExpression(AssignmentOperator op, HandleValue lhs, HandleValue rhs,
628 TokenPos *pos, MutableHandleValue dst);
630 bool updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos *pos,
631 MutableHandleValue dst);
633 bool logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos *pos,
634 MutableHandleValue dst);
636 bool conditionalExpression(HandleValue test, HandleValue cons, HandleValue alt, TokenPos *pos,
637 MutableHandleValue dst);
639 bool sequenceExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
641 bool newExpression(HandleValue callee, NodeVector &args, TokenPos *pos, MutableHandleValue dst);
643 bool callExpression(HandleValue callee, NodeVector &args, TokenPos *pos,
644 MutableHandleValue dst);
646 bool memberExpression(bool computed, HandleValue expr, HandleValue member, TokenPos *pos,
647 MutableHandleValue dst);
649 bool arrayExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
651 bool templateLiteral(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
653 bool taggedTemplate(HandleValue callee, NodeVector &args, TokenPos *pos,
654 MutableHandleValue dst);
656 bool callSiteObj(NodeVector &raw, NodeVector &cooked, TokenPos *pos, MutableHandleValue dst);
658 bool spreadExpression(HandleValue expr, TokenPos *pos, MutableHandleValue dst);
660 bool computedName(HandleValue name, TokenPos *pos, MutableHandleValue dst);
662 bool objectExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
664 bool thisExpression(TokenPos *pos, MutableHandleValue dst);
666 bool yieldExpression(HandleValue arg, YieldKind kind, TokenPos *pos, MutableHandleValue dst);
668 bool comprehensionBlock(HandleValue patt, HandleValue src, bool isForEach, bool isForOf, TokenPos *pos,
669 MutableHandleValue dst);
671 bool comprehensionExpression(HandleValue body, NodeVector &blocks, HandleValue filter,
672 TokenPos *pos, MutableHandleValue dst);
674 bool generatorExpression(HandleValue body, NodeVector &blocks, HandleValue filter,
675 TokenPos *pos, MutableHandleValue dst);
677 bool letExpression(NodeVector &head, HandleValue expr, TokenPos *pos, MutableHandleValue dst);
680 * declarations
683 bool variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos,
684 MutableHandleValue dst);
687 * patterns
690 bool arrayPattern(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
692 bool objectPattern(NodeVector &elts, TokenPos *pos, MutableHandleValue dst);
694 bool propertyPattern(HandleValue key, HandleValue patt, bool isShorthand, TokenPos *pos,
695 MutableHandleValue dst);
698 } /* anonymous namespace */
700 bool
701 NodeBuilder::newNode(ASTType type, TokenPos *pos, MutableHandleObject dst)
703 JS_ASSERT(type > AST_ERROR && type < AST_LIMIT);
705 RootedValue tv(cx);
706 RootedObject node(cx, NewBuiltinClassInstance(cx, &JSObject::class_));
707 if (!node ||
708 !setNodeLoc(node, pos) ||
709 !atomValue(nodeTypeNames[type], &tv) ||
710 !setProperty(node, "type", tv)) {
711 return false;
714 dst.set(node);
715 return true;
718 bool
719 NodeBuilder::newArray(NodeVector &elts, MutableHandleValue dst)
721 const size_t len = elts.length();
722 if (len > UINT32_MAX) {
723 js_ReportAllocationOverflow(cx);
724 return false;
726 RootedObject array(cx, NewDenseAllocatedArray(cx, uint32_t(len)));
727 if (!array)
728 return false;
730 for (size_t i = 0; i < len; i++) {
731 RootedValue val(cx, elts[i]);
733 JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
735 /* Represent "no node" as an array hole by not adding the value. */
736 if (val.isMagic(JS_SERIALIZE_NO_NODE))
737 continue;
739 if (!JSObject::setElement(cx, array, array, i, &val, false))
740 return false;
743 dst.setObject(*array);
744 return true;
747 bool
748 NodeBuilder::newNodeLoc(TokenPos *pos, MutableHandleValue dst)
750 if (!pos) {
751 dst.setNull();
752 return true;
755 RootedObject loc(cx);
756 RootedObject to(cx);
757 RootedValue val(cx);
759 if (!newObject(&loc))
760 return false;
762 dst.setObject(*loc);
764 uint32_t startLineNum, startColumnIndex;
765 uint32_t endLineNum, endColumnIndex;
766 tokenStream->srcCoords.lineNumAndColumnIndex(pos->begin, &startLineNum, &startColumnIndex);
767 tokenStream->srcCoords.lineNumAndColumnIndex(pos->end, &endLineNum, &endColumnIndex);
769 if (!newObject(&to))
770 return false;
771 val.setObject(*to);
772 if (!setProperty(loc, "start", val))
773 return false;
774 val.setNumber(startLineNum);
775 if (!setProperty(to, "line", val))
776 return false;
777 val.setNumber(startColumnIndex);
778 if (!setProperty(to, "column", val))
779 return false;
781 if (!newObject(&to))
782 return false;
783 val.setObject(*to);
784 if (!setProperty(loc, "end", val))
785 return false;
786 val.setNumber(endLineNum);
787 if (!setProperty(to, "line", val))
788 return false;
789 val.setNumber(endColumnIndex);
790 if (!setProperty(to, "column", val))
791 return false;
793 if (!setProperty(loc, "source", srcval))
794 return false;
796 return true;
799 bool
800 NodeBuilder::setNodeLoc(HandleObject node, TokenPos *pos)
802 if (!saveLoc) {
803 RootedValue nullVal(cx, NullValue());
804 setProperty(node, "loc", nullVal);
805 return true;
808 RootedValue loc(cx);
809 return newNodeLoc(pos, &loc) &&
810 setProperty(node, "loc", loc);
813 bool
814 NodeBuilder::program(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
816 return listNode(AST_PROGRAM, "body", elts, pos, dst);
819 bool
820 NodeBuilder::blockStatement(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
822 return listNode(AST_BLOCK_STMT, "body", elts, pos, dst);
825 bool
826 NodeBuilder::expressionStatement(HandleValue expr, TokenPos *pos, MutableHandleValue dst)
828 RootedValue cb(cx, callbacks[AST_EXPR_STMT]);
829 if (!cb.isNull())
830 return callback(cb, expr, pos, dst);
832 return newNode(AST_EXPR_STMT, pos, "expression", expr, dst);
835 bool
836 NodeBuilder::emptyStatement(TokenPos *pos, MutableHandleValue dst)
838 RootedValue cb(cx, callbacks[AST_EMPTY_STMT]);
839 if (!cb.isNull())
840 return callback(cb, pos, dst);
842 return newNode(AST_EMPTY_STMT, pos, dst);
845 bool
846 NodeBuilder::ifStatement(HandleValue test, HandleValue cons, HandleValue alt, TokenPos *pos,
847 MutableHandleValue dst)
849 RootedValue cb(cx, callbacks[AST_IF_STMT]);
850 if (!cb.isNull())
851 return callback(cb, test, cons, opt(alt), pos, dst);
853 return newNode(AST_IF_STMT, pos,
854 "test", test,
855 "consequent", cons,
856 "alternate", alt,
857 dst);
860 bool
861 NodeBuilder::breakStatement(HandleValue label, TokenPos *pos, MutableHandleValue dst)
863 RootedValue cb(cx, callbacks[AST_BREAK_STMT]);
864 if (!cb.isNull())
865 return callback(cb, opt(label), pos, dst);
867 return newNode(AST_BREAK_STMT, pos, "label", label, dst);
870 bool
871 NodeBuilder::continueStatement(HandleValue label, TokenPos *pos, MutableHandleValue dst)
873 RootedValue cb(cx, callbacks[AST_CONTINUE_STMT]);
874 if (!cb.isNull())
875 return callback(cb, opt(label), pos, dst);
877 return newNode(AST_CONTINUE_STMT, pos, "label", label, dst);
880 bool
881 NodeBuilder::labeledStatement(HandleValue label, HandleValue stmt, TokenPos *pos,
882 MutableHandleValue dst)
884 RootedValue cb(cx, callbacks[AST_LAB_STMT]);
885 if (!cb.isNull())
886 return callback(cb, label, stmt, pos, dst);
888 return newNode(AST_LAB_STMT, pos,
889 "label", label,
890 "body", stmt,
891 dst);
894 bool
895 NodeBuilder::throwStatement(HandleValue arg, TokenPos *pos, MutableHandleValue dst)
897 RootedValue cb(cx, callbacks[AST_THROW_STMT]);
898 if (!cb.isNull())
899 return callback(cb, arg, pos, dst);
901 return newNode(AST_THROW_STMT, pos, "argument", arg, dst);
904 bool
905 NodeBuilder::returnStatement(HandleValue arg, TokenPos *pos, MutableHandleValue dst)
907 RootedValue cb(cx, callbacks[AST_RETURN_STMT]);
908 if (!cb.isNull())
909 return callback(cb, opt(arg), pos, dst);
911 return newNode(AST_RETURN_STMT, pos, "argument", arg, dst);
914 bool
915 NodeBuilder::forStatement(HandleValue init, HandleValue test, HandleValue update, HandleValue stmt,
916 TokenPos *pos, MutableHandleValue dst)
918 RootedValue cb(cx, callbacks[AST_FOR_STMT]);
919 if (!cb.isNull())
920 return callback(cb, opt(init), opt(test), opt(update), stmt, pos, dst);
922 return newNode(AST_FOR_STMT, pos,
923 "init", init,
924 "test", test,
925 "update", update,
926 "body", stmt,
927 dst);
930 bool
931 NodeBuilder::forInStatement(HandleValue var, HandleValue expr, HandleValue stmt, bool isForEach,
932 TokenPos *pos, MutableHandleValue dst)
934 RootedValue isForEachVal(cx, BooleanValue(isForEach));
936 RootedValue cb(cx, callbacks[AST_FOR_IN_STMT]);
937 if (!cb.isNull())
938 return callback(cb, var, expr, stmt, isForEachVal, pos, dst);
940 return newNode(AST_FOR_IN_STMT, pos,
941 "left", var,
942 "right", expr,
943 "body", stmt,
944 "each", isForEachVal,
945 dst);
948 bool
949 NodeBuilder::forOfStatement(HandleValue var, HandleValue expr, HandleValue stmt, TokenPos *pos,
950 MutableHandleValue dst)
952 RootedValue cb(cx, callbacks[AST_FOR_OF_STMT]);
953 if (!cb.isNull())
954 return callback(cb, var, expr, stmt, pos, dst);
956 return newNode(AST_FOR_OF_STMT, pos,
957 "left", var,
958 "right", expr,
959 "body", stmt,
960 dst);
963 bool
964 NodeBuilder::withStatement(HandleValue expr, HandleValue stmt, TokenPos *pos,
965 MutableHandleValue dst)
967 RootedValue cb(cx, callbacks[AST_WITH_STMT]);
968 if (!cb.isNull())
969 return callback(cb, expr, stmt, pos, dst);
971 return newNode(AST_WITH_STMT, pos,
972 "object", expr,
973 "body", stmt,
974 dst);
977 bool
978 NodeBuilder::whileStatement(HandleValue test, HandleValue stmt, TokenPos *pos,
979 MutableHandleValue dst)
981 RootedValue cb(cx, callbacks[AST_WHILE_STMT]);
982 if (!cb.isNull())
983 return callback(cb, test, stmt, pos, dst);
985 return newNode(AST_WHILE_STMT, pos,
986 "test", test,
987 "body", stmt,
988 dst);
991 bool
992 NodeBuilder::doWhileStatement(HandleValue stmt, HandleValue test, TokenPos *pos,
993 MutableHandleValue dst)
995 RootedValue cb(cx, callbacks[AST_DO_STMT]);
996 if (!cb.isNull())
997 return callback(cb, stmt, test, pos, dst);
999 return newNode(AST_DO_STMT, pos,
1000 "body", stmt,
1001 "test", test,
1002 dst);
1005 bool
1006 NodeBuilder::switchStatement(HandleValue disc, NodeVector &elts, bool lexical, TokenPos *pos,
1007 MutableHandleValue dst)
1009 RootedValue array(cx);
1010 if (!newArray(elts, &array))
1011 return false;
1013 RootedValue lexicalVal(cx, BooleanValue(lexical));
1015 RootedValue cb(cx, callbacks[AST_SWITCH_STMT]);
1016 if (!cb.isNull())
1017 return callback(cb, disc, array, lexicalVal, pos, dst);
1019 return newNode(AST_SWITCH_STMT, pos,
1020 "discriminant", disc,
1021 "cases", array,
1022 "lexical", lexicalVal,
1023 dst);
1026 bool
1027 NodeBuilder::tryStatement(HandleValue body, NodeVector &guarded, HandleValue unguarded,
1028 HandleValue finally, TokenPos *pos, MutableHandleValue dst)
1030 RootedValue guardedHandlers(cx);
1031 if (!newArray(guarded, &guardedHandlers))
1032 return false;
1034 RootedValue cb(cx, callbacks[AST_TRY_STMT]);
1035 if (!cb.isNull())
1036 return callback(cb, body, guardedHandlers, unguarded, opt(finally), pos, dst);
1038 return newNode(AST_TRY_STMT, pos,
1039 "block", body,
1040 "guardedHandlers", guardedHandlers,
1041 "handler", unguarded,
1042 "finalizer", finally,
1043 dst);
1046 bool
1047 NodeBuilder::debuggerStatement(TokenPos *pos, MutableHandleValue dst)
1049 RootedValue cb(cx, callbacks[AST_DEBUGGER_STMT]);
1050 if (!cb.isNull())
1051 return callback(cb, pos, dst);
1053 return newNode(AST_DEBUGGER_STMT, pos, dst);
1056 bool
1057 NodeBuilder::binaryExpression(BinaryOperator op, HandleValue left, HandleValue right, TokenPos *pos,
1058 MutableHandleValue dst)
1060 JS_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
1062 RootedValue opName(cx);
1063 if (!atomValue(binopNames[op], &opName))
1064 return false;
1066 RootedValue cb(cx, callbacks[AST_BINARY_EXPR]);
1067 if (!cb.isNull())
1068 return callback(cb, opName, left, right, pos, dst);
1070 return newNode(AST_BINARY_EXPR, pos,
1071 "operator", opName,
1072 "left", left,
1073 "right", right,
1074 dst);
1077 bool
1078 NodeBuilder::unaryExpression(UnaryOperator unop, HandleValue expr, TokenPos *pos,
1079 MutableHandleValue dst)
1081 JS_ASSERT(unop > UNOP_ERR && unop < UNOP_LIMIT);
1083 RootedValue opName(cx);
1084 if (!atomValue(unopNames[unop], &opName))
1085 return false;
1087 RootedValue cb(cx, callbacks[AST_UNARY_EXPR]);
1088 if (!cb.isNull())
1089 return callback(cb, opName, expr, pos, dst);
1091 RootedValue trueVal(cx, BooleanValue(true));
1092 return newNode(AST_UNARY_EXPR, pos,
1093 "operator", opName,
1094 "argument", expr,
1095 "prefix", trueVal,
1096 dst);
1099 bool
1100 NodeBuilder::assignmentExpression(AssignmentOperator aop, HandleValue lhs, HandleValue rhs,
1101 TokenPos *pos, MutableHandleValue dst)
1103 JS_ASSERT(aop > AOP_ERR && aop < AOP_LIMIT);
1105 RootedValue opName(cx);
1106 if (!atomValue(aopNames[aop], &opName))
1107 return false;
1109 RootedValue cb(cx, callbacks[AST_ASSIGN_EXPR]);
1110 if (!cb.isNull())
1111 return callback(cb, opName, lhs, rhs, pos, dst);
1113 return newNode(AST_ASSIGN_EXPR, pos,
1114 "operator", opName,
1115 "left", lhs,
1116 "right", rhs,
1117 dst);
1120 bool
1121 NodeBuilder::updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos *pos,
1122 MutableHandleValue dst)
1124 RootedValue opName(cx);
1125 if (!atomValue(incr ? "++" : "--", &opName))
1126 return false;
1128 RootedValue prefixVal(cx, BooleanValue(prefix));
1130 RootedValue cb(cx, callbacks[AST_UPDATE_EXPR]);
1131 if (!cb.isNull())
1132 return callback(cb, expr, opName, prefixVal, pos, dst);
1134 return newNode(AST_UPDATE_EXPR, pos,
1135 "operator", opName,
1136 "argument", expr,
1137 "prefix", prefixVal,
1138 dst);
1141 bool
1142 NodeBuilder::logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos *pos,
1143 MutableHandleValue dst)
1145 RootedValue opName(cx);
1146 if (!atomValue(lor ? "||" : "&&", &opName))
1147 return false;
1149 RootedValue cb(cx, callbacks[AST_LOGICAL_EXPR]);
1150 if (!cb.isNull())
1151 return callback(cb, opName, left, right, pos, dst);
1153 return newNode(AST_LOGICAL_EXPR, pos,
1154 "operator", opName,
1155 "left", left,
1156 "right", right,
1157 dst);
1160 bool
1161 NodeBuilder::conditionalExpression(HandleValue test, HandleValue cons, HandleValue alt,
1162 TokenPos *pos, MutableHandleValue dst)
1164 RootedValue cb(cx, callbacks[AST_COND_EXPR]);
1165 if (!cb.isNull())
1166 return callback(cb, test, cons, alt, pos, dst);
1168 return newNode(AST_COND_EXPR, pos,
1169 "test", test,
1170 "consequent", cons,
1171 "alternate", alt,
1172 dst);
1175 bool
1176 NodeBuilder::sequenceExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
1178 return listNode(AST_LIST_EXPR, "expressions", elts, pos, dst);
1181 bool
1182 NodeBuilder::callExpression(HandleValue callee, NodeVector &args, TokenPos *pos,
1183 MutableHandleValue dst)
1185 RootedValue array(cx);
1186 if (!newArray(args, &array))
1187 return false;
1189 RootedValue cb(cx, callbacks[AST_CALL_EXPR]);
1190 if (!cb.isNull())
1191 return callback(cb, callee, array, pos, dst);
1193 return newNode(AST_CALL_EXPR, pos,
1194 "callee", callee,
1195 "arguments", array,
1196 dst);
1199 bool
1200 NodeBuilder::newExpression(HandleValue callee, NodeVector &args, TokenPos *pos,
1201 MutableHandleValue dst)
1203 RootedValue array(cx);
1204 if (!newArray(args, &array))
1205 return false;
1207 RootedValue cb(cx, callbacks[AST_NEW_EXPR]);
1208 if (!cb.isNull())
1209 return callback(cb, callee, array, pos, dst);
1211 return newNode(AST_NEW_EXPR, pos,
1212 "callee", callee,
1213 "arguments", array,
1214 dst);
1217 bool
1218 NodeBuilder::memberExpression(bool computed, HandleValue expr, HandleValue member, TokenPos *pos,
1219 MutableHandleValue dst)
1221 RootedValue computedVal(cx, BooleanValue(computed));
1223 RootedValue cb(cx, callbacks[AST_MEMBER_EXPR]);
1224 if (!cb.isNull())
1225 return callback(cb, computedVal, expr, member, pos, dst);
1227 return newNode(AST_MEMBER_EXPR, pos,
1228 "object", expr,
1229 "property", member,
1230 "computed", computedVal,
1231 dst);
1234 bool
1235 NodeBuilder::arrayExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
1237 return listNode(AST_ARRAY_EXPR, "elements", elts, pos, dst);
1240 bool
1241 NodeBuilder::callSiteObj(NodeVector &raw, NodeVector &cooked, TokenPos *pos, MutableHandleValue dst)
1243 RootedValue rawVal(cx);
1244 if (!newArray(raw, &rawVal))
1245 return false;
1247 RootedValue cookedVal(cx);
1248 if (!newArray(cooked, &cookedVal))
1249 return false;
1251 return newNode(AST_CALL_SITE_OBJ, pos,
1252 "raw", rawVal,
1253 "cooked", cookedVal,
1254 dst);
1257 bool
1258 NodeBuilder::taggedTemplate(HandleValue callee, NodeVector &args, TokenPos *pos,
1259 MutableHandleValue dst)
1261 RootedValue array(cx);
1262 if (!newArray(args, &array))
1263 return false;
1265 return newNode(AST_TAGGED_TEMPLATE, pos,
1266 "callee", callee,
1267 "arguments", array,
1268 dst);
1271 bool
1272 NodeBuilder::templateLiteral(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
1274 return listNode(AST_TEMPLATE_LITERAL, "elements", elts, pos, dst);
1277 bool
1278 NodeBuilder::computedName(HandleValue name, TokenPos *pos, MutableHandleValue dst)
1280 return newNode(AST_COMPUTED_NAME, pos,
1281 "name", name,
1282 dst);
1285 bool
1286 NodeBuilder::spreadExpression(HandleValue expr, TokenPos *pos, MutableHandleValue dst)
1288 return newNode(AST_SPREAD_EXPR, pos,
1289 "expression", expr,
1290 dst);
1293 bool
1294 NodeBuilder::propertyPattern(HandleValue key, HandleValue patt, bool isShorthand, TokenPos *pos,
1295 MutableHandleValue dst)
1297 RootedValue kindName(cx);
1298 if (!atomValue("init", &kindName))
1299 return false;
1301 RootedValue isShorthandVal(cx, BooleanValue(isShorthand));
1303 RootedValue cb(cx, callbacks[AST_PROP_PATT]);
1304 if (!cb.isNull())
1305 return callback(cb, key, patt, pos, dst);
1307 return newNode(AST_PROP_PATT, pos,
1308 "key", key,
1309 "value", patt,
1310 "kind", kindName,
1311 "shorthand", isShorthandVal,
1312 dst);
1315 bool
1316 NodeBuilder::propertyInitializer(HandleValue key, HandleValue val, PropKind kind, bool isShorthand,
1317 bool isMethod, TokenPos *pos, MutableHandleValue dst)
1319 RootedValue kindName(cx);
1320 if (!atomValue(kind == PROP_INIT
1321 ? "init"
1322 : kind == PROP_GETTER
1323 ? "get"
1324 : "set", &kindName)) {
1325 return false;
1328 RootedValue isShorthandVal(cx, BooleanValue(isShorthand));
1329 RootedValue isMethodVal(cx, BooleanValue(isMethod));
1331 RootedValue cb(cx, callbacks[AST_PROPERTY]);
1332 if (!cb.isNull())
1333 return callback(cb, kindName, key, val, pos, dst);
1335 return newNode(AST_PROPERTY, pos,
1336 "key", key,
1337 "value", val,
1338 "kind", kindName,
1339 "method", isMethodVal,
1340 "shorthand", isShorthandVal,
1341 dst);
1344 bool
1345 NodeBuilder::objectExpression(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
1347 return listNode(AST_OBJECT_EXPR, "properties", elts, pos, dst);
1350 bool
1351 NodeBuilder::thisExpression(TokenPos *pos, MutableHandleValue dst)
1353 RootedValue cb(cx, callbacks[AST_THIS_EXPR]);
1354 if (!cb.isNull())
1355 return callback(cb, pos, dst);
1357 return newNode(AST_THIS_EXPR, pos, dst);
1360 bool
1361 NodeBuilder::yieldExpression(HandleValue arg, YieldKind kind, TokenPos *pos, MutableHandleValue dst)
1363 RootedValue cb(cx, callbacks[AST_YIELD_EXPR]);
1364 RootedValue delegateVal(cx);
1366 switch (kind) {
1367 case Delegating:
1368 delegateVal = BooleanValue(true);
1369 break;
1370 case NotDelegating:
1371 delegateVal = BooleanValue(false);
1372 break;
1375 if (!cb.isNull())
1376 return callback(cb, opt(arg), delegateVal, pos, dst);
1377 return newNode(AST_YIELD_EXPR, pos, "argument", arg, "delegate", delegateVal, dst);
1380 bool
1381 NodeBuilder::comprehensionBlock(HandleValue patt, HandleValue src, bool isForEach, bool isForOf, TokenPos *pos,
1382 MutableHandleValue dst)
1384 RootedValue isForEachVal(cx, BooleanValue(isForEach));
1385 RootedValue isForOfVal(cx, BooleanValue(isForOf));
1387 RootedValue cb(cx, callbacks[AST_COMP_BLOCK]);
1388 if (!cb.isNull())
1389 return callback(cb, patt, src, isForEachVal, isForOfVal, pos, dst);
1391 return newNode(AST_COMP_BLOCK, pos,
1392 "left", patt,
1393 "right", src,
1394 "each", isForEachVal,
1395 "of", isForOfVal,
1396 dst);
1399 bool
1400 NodeBuilder::comprehensionExpression(HandleValue body, NodeVector &blocks, HandleValue filter,
1401 TokenPos *pos, MutableHandleValue dst)
1403 RootedValue array(cx);
1404 if (!newArray(blocks, &array))
1405 return false;
1407 RootedValue cb(cx, callbacks[AST_COMP_EXPR]);
1408 if (!cb.isNull())
1409 return callback(cb, body, array, opt(filter), pos, dst);
1411 return newNode(AST_COMP_EXPR, pos,
1412 "body", body,
1413 "blocks", array,
1414 "filter", filter,
1415 dst);
1418 bool
1419 NodeBuilder::generatorExpression(HandleValue body, NodeVector &blocks, HandleValue filter,
1420 TokenPos *pos, MutableHandleValue dst)
1422 RootedValue array(cx);
1423 if (!newArray(blocks, &array))
1424 return false;
1426 RootedValue cb(cx, callbacks[AST_GENERATOR_EXPR]);
1427 if (!cb.isNull())
1428 return callback(cb, body, array, opt(filter), pos, dst);
1430 return newNode(AST_GENERATOR_EXPR, pos,
1431 "body", body,
1432 "blocks", array,
1433 "filter", filter,
1434 dst);
1437 bool
1438 NodeBuilder::letExpression(NodeVector &head, HandleValue expr, TokenPos *pos,
1439 MutableHandleValue dst)
1441 RootedValue array(cx);
1442 if (!newArray(head, &array))
1443 return false;
1445 RootedValue cb(cx, callbacks[AST_LET_EXPR]);
1446 if (!cb.isNull())
1447 return callback(cb, array, expr, pos, dst);
1449 return newNode(AST_LET_EXPR, pos,
1450 "head", array,
1451 "body", expr,
1452 dst);
1455 bool
1456 NodeBuilder::letStatement(NodeVector &head, HandleValue stmt, TokenPos *pos, MutableHandleValue dst)
1458 RootedValue array(cx);
1459 if (!newArray(head, &array))
1460 return false;
1462 RootedValue cb(cx, callbacks[AST_LET_STMT]);
1463 if (!cb.isNull())
1464 return callback(cb, array, stmt, pos, dst);
1466 return newNode(AST_LET_STMT, pos,
1467 "head", array,
1468 "body", stmt,
1469 dst);
1472 bool
1473 NodeBuilder::importDeclaration(NodeVector &elts, HandleValue moduleSpec, TokenPos *pos,
1474 MutableHandleValue dst)
1476 RootedValue array(cx);
1477 if (!newArray(elts, &array))
1478 return false;
1480 RootedValue cb(cx, callbacks[AST_IMPORT_DECL]);
1481 if (!cb.isNull())
1482 return callback(cb, array, moduleSpec, pos, dst);
1484 return newNode(AST_IMPORT_DECL, pos,
1485 "specifiers", array,
1486 "source", moduleSpec,
1487 dst);
1490 bool
1491 NodeBuilder::importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos *pos,
1492 MutableHandleValue dst)
1494 RootedValue cb(cx, callbacks[AST_IMPORT_SPEC]);
1495 if (!cb.isNull())
1496 return callback(cb, importName, bindingName, pos, dst);
1498 return newNode(AST_IMPORT_SPEC, pos,
1499 "id", importName,
1500 "name", bindingName,
1501 dst);
1504 bool
1505 NodeBuilder::exportDeclaration(HandleValue decl, NodeVector &elts, HandleValue moduleSpec,
1506 TokenPos *pos, MutableHandleValue dst)
1508 RootedValue array(cx, NullValue());
1509 if (decl.isNull() && !newArray(elts, &array))
1510 return false;
1512 RootedValue cb(cx, callbacks[AST_IMPORT_DECL]);
1514 if (!cb.isNull())
1515 return callback(cb, decl, array, moduleSpec, pos, dst);
1517 return newNode(AST_EXPORT_DECL, pos,
1518 "declaration", decl,
1519 "specifiers", array,
1520 "source", moduleSpec,
1521 dst);
1524 bool
1525 NodeBuilder::exportSpecifier(HandleValue bindingName, HandleValue exportName, TokenPos *pos,
1526 MutableHandleValue dst)
1528 RootedValue cb(cx, callbacks[AST_EXPORT_SPEC]);
1529 if (!cb.isNull())
1530 return callback(cb, bindingName, exportName, pos, dst);
1532 return newNode(AST_EXPORT_SPEC, pos,
1533 "id", bindingName,
1534 "name", exportName,
1535 dst);
1538 bool
1539 NodeBuilder::exportBatchSpecifier(TokenPos *pos, MutableHandleValue dst)
1541 RootedValue cb(cx, callbacks[AST_EXPORT_BATCH_SPEC]);
1542 if (!cb.isNull())
1543 return callback(cb, pos, dst);
1545 return newNode(AST_EXPORT_BATCH_SPEC, pos, dst);
1548 bool
1549 NodeBuilder::variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos,
1550 MutableHandleValue dst)
1552 JS_ASSERT(kind > VARDECL_ERR && kind < VARDECL_LIMIT);
1554 RootedValue array(cx), kindName(cx);
1555 if (!newArray(elts, &array) ||
1556 !atomValue(kind == VARDECL_CONST
1557 ? "const"
1558 : kind == VARDECL_LET
1559 ? "let"
1560 : "var", &kindName)) {
1561 return false;
1564 RootedValue cb(cx, callbacks[AST_VAR_DECL]);
1565 if (!cb.isNull())
1566 return callback(cb, kindName, array, pos, dst);
1568 return newNode(AST_VAR_DECL, pos,
1569 "kind", kindName,
1570 "declarations", array,
1571 dst);
1574 bool
1575 NodeBuilder::variableDeclarator(HandleValue id, HandleValue init, TokenPos *pos,
1576 MutableHandleValue dst)
1578 RootedValue cb(cx, callbacks[AST_VAR_DTOR]);
1579 if (!cb.isNull())
1580 return callback(cb, id, opt(init), pos, dst);
1582 return newNode(AST_VAR_DTOR, pos, "id", id, "init", init, dst);
1585 bool
1586 NodeBuilder::switchCase(HandleValue expr, NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
1588 RootedValue array(cx);
1589 if (!newArray(elts, &array))
1590 return false;
1592 RootedValue cb(cx, callbacks[AST_CASE]);
1593 if (!cb.isNull())
1594 return callback(cb, opt(expr), array, pos, dst);
1596 return newNode(AST_CASE, pos,
1597 "test", expr,
1598 "consequent", array,
1599 dst);
1602 bool
1603 NodeBuilder::catchClause(HandleValue var, HandleValue guard, HandleValue body, TokenPos *pos,
1604 MutableHandleValue dst)
1606 RootedValue cb(cx, callbacks[AST_CATCH]);
1607 if (!cb.isNull())
1608 return callback(cb, var, opt(guard), body, pos, dst);
1610 return newNode(AST_CATCH, pos,
1611 "param", var,
1612 "guard", guard,
1613 "body", body,
1614 dst);
1617 bool
1618 NodeBuilder::literal(HandleValue val, TokenPos *pos, MutableHandleValue dst)
1620 RootedValue cb(cx, callbacks[AST_LITERAL]);
1621 if (!cb.isNull())
1622 return callback(cb, val, pos, dst);
1624 return newNode(AST_LITERAL, pos, "value", val, dst);
1627 bool
1628 NodeBuilder::identifier(HandleValue name, TokenPos *pos, MutableHandleValue dst)
1630 RootedValue cb(cx, callbacks[AST_IDENTIFIER]);
1631 if (!cb.isNull())
1632 return callback(cb, name, pos, dst);
1634 return newNode(AST_IDENTIFIER, pos, "name", name, dst);
1637 bool
1638 NodeBuilder::objectPattern(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
1640 return listNode(AST_OBJECT_PATT, "properties", elts, pos, dst);
1643 bool
1644 NodeBuilder::arrayPattern(NodeVector &elts, TokenPos *pos, MutableHandleValue dst)
1646 return listNode(AST_ARRAY_PATT, "elements", elts, pos, dst);
1649 bool
1650 NodeBuilder::function(ASTType type, TokenPos *pos,
1651 HandleValue id, NodeVector &args, NodeVector &defaults,
1652 HandleValue body, HandleValue rest,
1653 bool isGenerator, bool isExpression,
1654 MutableHandleValue dst)
1656 RootedValue array(cx), defarray(cx);
1657 if (!newArray(args, &array))
1658 return false;
1659 if (!newArray(defaults, &defarray))
1660 return false;
1662 RootedValue isGeneratorVal(cx, BooleanValue(isGenerator));
1663 RootedValue isExpressionVal(cx, BooleanValue(isExpression));
1665 RootedValue cb(cx, callbacks[type]);
1666 if (!cb.isNull()) {
1667 return callback(cb, opt(id), array, body, isGeneratorVal, isExpressionVal, pos, dst);
1670 return newNode(type, pos,
1671 "id", id,
1672 "params", array,
1673 "defaults", defarray,
1674 "body", body,
1675 "rest", rest,
1676 "generator", isGeneratorVal,
1677 "expression", isExpressionVal,
1678 dst);
1681 namespace {
1684 * Serialization of parse nodes to JavaScript objects.
1686 * All serialization methods take a non-nullable ParseNode pointer.
1688 class ASTSerializer
1690 JSContext *cx;
1691 Parser<FullParseHandler> *parser;
1692 NodeBuilder builder;
1693 DebugOnly<uint32_t> lineno;
1695 Value unrootedAtomContents(JSAtom *atom) {
1696 return StringValue(atom ? atom : cx->names().empty);
1699 BinaryOperator binop(ParseNodeKind kind, JSOp op);
1700 UnaryOperator unop(ParseNodeKind kind, JSOp op);
1701 AssignmentOperator aop(JSOp op);
1703 bool statements(ParseNode *pn, NodeVector &elts);
1704 bool expressions(ParseNode *pn, NodeVector &elts);
1705 bool leftAssociate(ParseNode *pn, MutableHandleValue dst);
1706 bool functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestruct, ParseNode *pnbody,
1707 NodeVector &args, NodeVector &defaults, MutableHandleValue rest);
1709 bool sourceElement(ParseNode *pn, MutableHandleValue dst);
1711 bool declaration(ParseNode *pn, MutableHandleValue dst);
1712 bool variableDeclaration(ParseNode *pn, bool let, MutableHandleValue dst);
1713 bool variableDeclarator(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst);
1714 bool let(ParseNode *pn, bool expr, MutableHandleValue dst);
1715 bool importDeclaration(ParseNode *pn, MutableHandleValue dst);
1716 bool importSpecifier(ParseNode *pn, MutableHandleValue dst);
1717 bool exportDeclaration(ParseNode *pn, MutableHandleValue dst);
1718 bool exportSpecifier(ParseNode *pn, MutableHandleValue dst);
1720 bool optStatement(ParseNode *pn, MutableHandleValue dst) {
1721 if (!pn) {
1722 dst.setMagic(JS_SERIALIZE_NO_NODE);
1723 return true;
1725 return statement(pn, dst);
1728 bool forInit(ParseNode *pn, MutableHandleValue dst);
1729 bool forIn(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
1730 MutableHandleValue dst);
1731 bool forOf(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
1732 MutableHandleValue dst);
1733 bool statement(ParseNode *pn, MutableHandleValue dst);
1734 bool blockStatement(ParseNode *pn, MutableHandleValue dst);
1735 bool switchStatement(ParseNode *pn, MutableHandleValue dst);
1736 bool switchCase(ParseNode *pn, MutableHandleValue dst);
1737 bool tryStatement(ParseNode *pn, MutableHandleValue dst);
1738 bool catchClause(ParseNode *pn, bool *isGuarded, MutableHandleValue dst);
1740 bool optExpression(ParseNode *pn, MutableHandleValue dst) {
1741 if (!pn) {
1742 dst.setMagic(JS_SERIALIZE_NO_NODE);
1743 return true;
1745 return expression(pn, dst);
1748 bool expression(ParseNode *pn, MutableHandleValue dst);
1750 bool propertyName(ParseNode *pn, MutableHandleValue dst);
1751 bool property(ParseNode *pn, MutableHandleValue dst);
1753 bool optIdentifier(HandleAtom atom, TokenPos *pos, MutableHandleValue dst) {
1754 if (!atom) {
1755 dst.setMagic(JS_SERIALIZE_NO_NODE);
1756 return true;
1758 return identifier(atom, pos, dst);
1761 bool identifier(HandleAtom atom, TokenPos *pos, MutableHandleValue dst);
1762 bool identifier(ParseNode *pn, MutableHandleValue dst);
1763 bool literal(ParseNode *pn, MutableHandleValue dst);
1765 bool pattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst);
1766 bool arrayPattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst);
1767 bool objectPattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst);
1769 bool function(ParseNode *pn, ASTType type, MutableHandleValue dst);
1770 bool functionArgsAndBody(ParseNode *pn, NodeVector &args, NodeVector &defaults,
1771 MutableHandleValue body, MutableHandleValue rest);
1772 bool functionBody(ParseNode *pn, TokenPos *pos, MutableHandleValue dst);
1774 bool comprehensionBlock(ParseNode *pn, MutableHandleValue dst);
1775 bool comprehension(ParseNode *pn, MutableHandleValue dst);
1776 bool generatorExpression(ParseNode *pn, MutableHandleValue dst);
1778 public:
1779 ASTSerializer(JSContext *c, bool l, char const *src, uint32_t ln)
1780 : cx(c)
1781 , builder(c, l, src)
1782 #ifdef DEBUG
1783 , lineno(ln)
1784 #endif
1787 bool init(HandleObject userobj) {
1788 return builder.init(userobj);
1791 void setParser(Parser<FullParseHandler> *p) {
1792 parser = p;
1793 builder.setTokenStream(&p->tokenStream);
1796 bool program(ParseNode *pn, MutableHandleValue dst);
1799 } /* anonymous namespace */
1801 AssignmentOperator
1802 ASTSerializer::aop(JSOp op)
1804 switch (op) {
1805 case JSOP_NOP:
1806 return AOP_ASSIGN;
1807 case JSOP_ADD:
1808 return AOP_PLUS;
1809 case JSOP_SUB:
1810 return AOP_MINUS;
1811 case JSOP_MUL:
1812 return AOP_STAR;
1813 case JSOP_DIV:
1814 return AOP_DIV;
1815 case JSOP_MOD:
1816 return AOP_MOD;
1817 case JSOP_LSH:
1818 return AOP_LSH;
1819 case JSOP_RSH:
1820 return AOP_RSH;
1821 case JSOP_URSH:
1822 return AOP_URSH;
1823 case JSOP_BITOR:
1824 return AOP_BITOR;
1825 case JSOP_BITXOR:
1826 return AOP_BITXOR;
1827 case JSOP_BITAND:
1828 return AOP_BITAND;
1829 default:
1830 return AOP_ERR;
1834 UnaryOperator
1835 ASTSerializer::unop(ParseNodeKind kind, JSOp op)
1837 if (kind == PNK_DELETE)
1838 return UNOP_DELETE;
1840 switch (op) {
1841 case JSOP_NEG:
1842 return UNOP_NEG;
1843 case JSOP_POS:
1844 return UNOP_POS;
1845 case JSOP_NOT:
1846 return UNOP_NOT;
1847 case JSOP_BITNOT:
1848 return UNOP_BITNOT;
1849 case JSOP_TYPEOF:
1850 case JSOP_TYPEOFEXPR:
1851 return UNOP_TYPEOF;
1852 case JSOP_VOID:
1853 return UNOP_VOID;
1854 default:
1855 return UNOP_ERR;
1859 BinaryOperator
1860 ASTSerializer::binop(ParseNodeKind kind, JSOp op)
1862 switch (kind) {
1863 case PNK_LSH:
1864 return BINOP_LSH;
1865 case PNK_RSH:
1866 return BINOP_RSH;
1867 case PNK_URSH:
1868 return BINOP_URSH;
1869 case PNK_LT:
1870 return BINOP_LT;
1871 case PNK_LE:
1872 return BINOP_LE;
1873 case PNK_GT:
1874 return BINOP_GT;
1875 case PNK_GE:
1876 return BINOP_GE;
1877 case PNK_EQ:
1878 return BINOP_EQ;
1879 case PNK_NE:
1880 return BINOP_NE;
1881 case PNK_STRICTEQ:
1882 return BINOP_STRICTEQ;
1883 case PNK_STRICTNE:
1884 return BINOP_STRICTNE;
1885 case PNK_ADD:
1886 return BINOP_ADD;
1887 case PNK_SUB:
1888 return BINOP_SUB;
1889 case PNK_STAR:
1890 return BINOP_STAR;
1891 case PNK_DIV:
1892 return BINOP_DIV;
1893 case PNK_MOD:
1894 return BINOP_MOD;
1895 case PNK_BITOR:
1896 return BINOP_BITOR;
1897 case PNK_BITXOR:
1898 return BINOP_BITXOR;
1899 case PNK_BITAND:
1900 return BINOP_BITAND;
1901 case PNK_IN:
1902 return BINOP_IN;
1903 case PNK_INSTANCEOF:
1904 return BINOP_INSTANCEOF;
1905 default:
1906 return BINOP_ERR;
1910 bool
1911 ASTSerializer::statements(ParseNode *pn, NodeVector &elts)
1913 JS_ASSERT(pn->isKind(PNK_STATEMENTLIST));
1914 JS_ASSERT(pn->isArity(PN_LIST));
1916 if (!elts.reserve(pn->pn_count))
1917 return false;
1919 for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
1920 JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
1922 RootedValue elt(cx);
1923 if (!sourceElement(next, &elt))
1924 return false;
1925 elts.infallibleAppend(elt);
1928 return true;
1931 bool
1932 ASTSerializer::expressions(ParseNode *pn, NodeVector &elts)
1934 if (!elts.reserve(pn->pn_count))
1935 return false;
1937 for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
1938 JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
1940 RootedValue elt(cx);
1941 if (!expression(next, &elt))
1942 return false;
1943 elts.infallibleAppend(elt);
1946 return true;
1949 bool
1950 ASTSerializer::blockStatement(ParseNode *pn, MutableHandleValue dst)
1952 JS_ASSERT(pn->isKind(PNK_STATEMENTLIST));
1954 NodeVector stmts(cx);
1955 return statements(pn, stmts) &&
1956 builder.blockStatement(stmts, &pn->pn_pos, dst);
1959 bool
1960 ASTSerializer::program(ParseNode *pn, MutableHandleValue dst)
1962 JS_ASSERT(parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin) == lineno);
1964 NodeVector stmts(cx);
1965 return statements(pn, stmts) &&
1966 builder.program(stmts, &pn->pn_pos, dst);
1969 bool
1970 ASTSerializer::sourceElement(ParseNode *pn, MutableHandleValue dst)
1972 /* SpiderMonkey allows declarations even in pure statement contexts. */
1973 return statement(pn, dst);
1976 bool
1977 ASTSerializer::declaration(ParseNode *pn, MutableHandleValue dst)
1979 JS_ASSERT(pn->isKind(PNK_FUNCTION) ||
1980 pn->isKind(PNK_VAR) ||
1981 pn->isKind(PNK_LET) ||
1982 pn->isKind(PNK_CONST));
1984 switch (pn->getKind()) {
1985 case PNK_FUNCTION:
1986 return function(pn, AST_FUNC_DECL, dst);
1988 case PNK_VAR:
1989 case PNK_CONST:
1990 return variableDeclaration(pn, false, dst);
1992 default:
1993 JS_ASSERT(pn->isKind(PNK_LET));
1994 return variableDeclaration(pn, true, dst);
1998 bool
1999 ASTSerializer::variableDeclaration(ParseNode *pn, bool let, MutableHandleValue dst)
2001 JS_ASSERT(let ? pn->isKind(PNK_LET) : (pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST)));
2003 /* Later updated to VARDECL_CONST if we find a PND_CONST declarator. */
2004 VarDeclKind kind = let ? VARDECL_LET : VARDECL_VAR;
2006 NodeVector dtors(cx);
2007 if (!dtors.reserve(pn->pn_count))
2008 return false;
2009 for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
2010 RootedValue child(cx);
2011 if (!variableDeclarator(next, &kind, &child))
2012 return false;
2013 dtors.infallibleAppend(child);
2015 return builder.variableDeclaration(dtors, kind, &pn->pn_pos, dst);
2018 bool
2019 ASTSerializer::variableDeclarator(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst)
2021 ParseNode *pnleft;
2022 ParseNode *pnright;
2024 if (pn->isKind(PNK_NAME)) {
2025 pnleft = pn;
2026 pnright = pn->isUsed() ? nullptr : pn->pn_expr;
2027 JS_ASSERT_IF(pnright, pn->pn_pos.encloses(pnright->pn_pos));
2028 } else if (pn->isKind(PNK_ASSIGN)) {
2029 pnleft = pn->pn_left;
2030 pnright = pn->pn_right;
2031 JS_ASSERT(pn->pn_pos.encloses(pnleft->pn_pos));
2032 JS_ASSERT(pn->pn_pos.encloses(pnright->pn_pos));
2033 } else {
2034 /* This happens for a destructuring declarator in a for-in/of loop. */
2035 pnleft = pn;
2036 pnright = nullptr;
2039 RootedValue left(cx), right(cx);
2040 return pattern(pnleft, pkind, &left) &&
2041 optExpression(pnright, &right) &&
2042 builder.variableDeclarator(left, right, &pn->pn_pos, dst);
2045 bool
2046 ASTSerializer::let(ParseNode *pn, bool expr, MutableHandleValue dst)
2048 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2049 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2051 ParseNode *letHead = pn->pn_left;
2052 LOCAL_ASSERT(letHead->isArity(PN_LIST));
2054 ParseNode *letBody = pn->pn_right;
2055 LOCAL_ASSERT(letBody->isKind(PNK_LEXICALSCOPE));
2057 NodeVector dtors(cx);
2058 if (!dtors.reserve(letHead->pn_count))
2059 return false;
2061 VarDeclKind kind = VARDECL_LET_HEAD;
2063 for (ParseNode *next = letHead->pn_head; next; next = next->pn_next) {
2064 RootedValue child(cx);
2066 * Unlike in |variableDeclaration|, this does not update |kind|; since let-heads do
2067 * not contain const declarations, declarators should never have PND_CONST set.
2069 if (!variableDeclarator(next, &kind, &child))
2070 return false;
2071 dtors.infallibleAppend(child);
2074 RootedValue v(cx);
2075 return expr
2076 ? expression(letBody->pn_expr, &v) &&
2077 builder.letExpression(dtors, v, &pn->pn_pos, dst)
2078 : statement(letBody->pn_expr, &v) &&
2079 builder.letStatement(dtors, v, &pn->pn_pos, dst);
2082 bool
2083 ASTSerializer::importDeclaration(ParseNode *pn, MutableHandleValue dst)
2085 JS_ASSERT(pn->isKind(PNK_IMPORT));
2086 JS_ASSERT(pn->pn_left->isKind(PNK_IMPORT_SPEC_LIST));
2087 JS_ASSERT(pn->pn_right->isKind(PNK_STRING));
2089 NodeVector elts(cx);
2090 if (!elts.reserve(pn->pn_count))
2091 return false;
2093 for (ParseNode *next = pn->pn_left->pn_head; next; next = next->pn_next) {
2094 RootedValue elt(cx);
2095 if (!importSpecifier(next, &elt))
2096 return false;
2097 elts.infallibleAppend(elt);
2100 RootedValue moduleSpec(cx);
2101 return literal(pn->pn_right, &moduleSpec) &&
2102 builder.importDeclaration(elts, moduleSpec, &pn->pn_pos, dst);
2105 bool
2106 ASTSerializer::importSpecifier(ParseNode *pn, MutableHandleValue dst)
2108 JS_ASSERT(pn->isKind(PNK_IMPORT_SPEC));
2110 RootedValue importName(cx);
2111 RootedValue bindingName(cx);
2112 return identifier(pn->pn_left, &importName) &&
2113 identifier(pn->pn_right, &bindingName) &&
2114 builder.importSpecifier(importName, bindingName, &pn->pn_pos, dst);
2117 bool
2118 ASTSerializer::exportDeclaration(ParseNode *pn, MutableHandleValue dst)
2120 JS_ASSERT(pn->isKind(PNK_EXPORT) || pn->isKind(PNK_EXPORT_FROM));
2121 JS_ASSERT_IF(pn->isKind(PNK_EXPORT_FROM), pn->pn_right->isKind(PNK_STRING));
2123 RootedValue decl(cx, NullValue());
2124 NodeVector elts(cx);
2126 ParseNode *kid = pn->isKind(PNK_EXPORT) ? pn->pn_kid : pn->pn_left;
2127 switch (ParseNodeKind kind = kid->getKind()) {
2128 case PNK_EXPORT_SPEC_LIST:
2129 if (!elts.reserve(pn->pn_count))
2130 return false;
2132 for (ParseNode *next = pn->pn_left->pn_head; next; next = next->pn_next) {
2133 RootedValue elt(cx);
2134 if (next->isKind(PNK_EXPORT_SPEC)) {
2135 if (!exportSpecifier(next, &elt))
2136 return false;
2137 } else {
2138 if (!builder.exportBatchSpecifier(&pn->pn_pos, &elt))
2139 return false;
2141 elts.infallibleAppend(elt);
2143 break;
2145 case PNK_FUNCTION:
2146 if (!function(kid, AST_FUNC_DECL, &decl))
2147 return false;
2148 break;
2150 case PNK_VAR:
2151 case PNK_CONST:
2152 case PNK_LET:
2153 if (!variableDeclaration(kid, kind == PNK_LET, &decl))
2154 return false;
2155 break;
2157 default:
2158 LOCAL_NOT_REACHED("unexpected statement type");
2161 RootedValue moduleSpec(cx, NullValue());
2162 if (pn->isKind(PNK_EXPORT_FROM) && !literal(pn->pn_right, &moduleSpec))
2163 return false;
2165 return builder.exportDeclaration(decl, elts, moduleSpec, &pn->pn_pos, dst);
2168 bool
2169 ASTSerializer::exportSpecifier(ParseNode *pn, MutableHandleValue dst)
2171 JS_ASSERT(pn->isKind(PNK_EXPORT_SPEC));
2173 RootedValue bindingName(cx);
2174 RootedValue exportName(cx);
2175 return identifier(pn->pn_left, &bindingName) &&
2176 identifier(pn->pn_right, &exportName) &&
2177 builder.exportSpecifier(bindingName, exportName, &pn->pn_pos, dst);
2180 bool
2181 ASTSerializer::switchCase(ParseNode *pn, MutableHandleValue dst)
2183 JS_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos));
2184 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2186 NodeVector stmts(cx);
2188 RootedValue expr(cx);
2190 return optExpression(pn->pn_left, &expr) &&
2191 statements(pn->pn_right, stmts) &&
2192 builder.switchCase(expr, stmts, &pn->pn_pos, dst);
2195 bool
2196 ASTSerializer::switchStatement(ParseNode *pn, MutableHandleValue dst)
2198 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2199 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2201 RootedValue disc(cx);
2203 if (!expression(pn->pn_left, &disc))
2204 return false;
2206 ParseNode *listNode;
2207 bool lexical;
2209 if (pn->pn_right->isKind(PNK_LEXICALSCOPE)) {
2210 listNode = pn->pn_right->pn_expr;
2211 lexical = true;
2212 } else {
2213 listNode = pn->pn_right;
2214 lexical = false;
2217 NodeVector cases(cx);
2218 if (!cases.reserve(listNode->pn_count))
2219 return false;
2221 for (ParseNode *next = listNode->pn_head; next; next = next->pn_next) {
2222 RootedValue child(cx);
2223 if (!switchCase(next, &child))
2224 return false;
2225 cases.infallibleAppend(child);
2228 return builder.switchStatement(disc, cases, lexical, &pn->pn_pos, dst);
2231 bool
2232 ASTSerializer::catchClause(ParseNode *pn, bool *isGuarded, MutableHandleValue dst)
2234 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
2235 JS_ASSERT_IF(pn->pn_kid2, pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
2236 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
2238 RootedValue var(cx), guard(cx), body(cx);
2240 if (!pattern(pn->pn_kid1, nullptr, &var) ||
2241 !optExpression(pn->pn_kid2, &guard)) {
2242 return false;
2245 *isGuarded = !guard.isMagic(JS_SERIALIZE_NO_NODE);
2247 return statement(pn->pn_kid3, &body) &&
2248 builder.catchClause(var, guard, body, &pn->pn_pos, dst);
2251 bool
2252 ASTSerializer::tryStatement(ParseNode *pn, MutableHandleValue dst)
2254 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
2255 JS_ASSERT_IF(pn->pn_kid2, pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
2256 JS_ASSERT_IF(pn->pn_kid3, pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
2258 RootedValue body(cx);
2259 if (!statement(pn->pn_kid1, &body))
2260 return false;
2262 NodeVector guarded(cx);
2263 RootedValue unguarded(cx, NullValue());
2265 if (pn->pn_kid2) {
2266 if (!guarded.reserve(pn->pn_kid2->pn_count))
2267 return false;
2269 for (ParseNode *next = pn->pn_kid2->pn_head; next; next = next->pn_next) {
2270 RootedValue clause(cx);
2271 bool isGuarded;
2272 if (!catchClause(next->pn_expr, &isGuarded, &clause))
2273 return false;
2274 if (isGuarded)
2275 guarded.infallibleAppend(clause);
2276 else
2277 unguarded = clause;
2281 RootedValue finally(cx);
2282 return optStatement(pn->pn_kid3, &finally) &&
2283 builder.tryStatement(body, guarded, unguarded, finally, &pn->pn_pos, dst);
2286 bool
2287 ASTSerializer::forInit(ParseNode *pn, MutableHandleValue dst)
2289 if (!pn) {
2290 dst.setMagic(JS_SERIALIZE_NO_NODE);
2291 return true;
2294 return (pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST))
2295 ? variableDeclaration(pn, false, dst)
2296 : expression(pn, dst);
2299 bool
2300 ASTSerializer::forOf(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
2301 MutableHandleValue dst)
2303 RootedValue expr(cx);
2305 return expression(head->pn_kid3, &expr) &&
2306 builder.forOfStatement(var, expr, stmt, &loop->pn_pos, dst);
2309 bool
2310 ASTSerializer::forIn(ParseNode *loop, ParseNode *head, HandleValue var, HandleValue stmt,
2311 MutableHandleValue dst)
2313 RootedValue expr(cx);
2314 bool isForEach = loop->pn_iflags & JSITER_FOREACH;
2316 return expression(head->pn_kid3, &expr) &&
2317 builder.forInStatement(var, expr, stmt, isForEach, &loop->pn_pos, dst);
2320 bool
2321 ASTSerializer::statement(ParseNode *pn, MutableHandleValue dst)
2323 JS_CHECK_RECURSION(cx, return false);
2324 switch (pn->getKind()) {
2325 case PNK_FUNCTION:
2326 case PNK_VAR:
2327 case PNK_CONST:
2328 return declaration(pn, dst);
2330 case PNK_LET:
2331 return pn->isArity(PN_BINARY)
2332 ? let(pn, false, dst)
2333 : declaration(pn, dst);
2335 case PNK_IMPORT:
2336 return importDeclaration(pn, dst);
2338 case PNK_EXPORT:
2339 case PNK_EXPORT_FROM:
2340 return exportDeclaration(pn, dst);
2342 case PNK_NAME:
2343 LOCAL_ASSERT(pn->isUsed());
2344 return statement(pn->pn_lexdef, dst);
2346 case PNK_SEMI:
2347 if (pn->pn_kid) {
2348 RootedValue expr(cx);
2349 return expression(pn->pn_kid, &expr) &&
2350 builder.expressionStatement(expr, &pn->pn_pos, dst);
2352 return builder.emptyStatement(&pn->pn_pos, dst);
2354 case PNK_LEXICALSCOPE:
2355 pn = pn->pn_expr;
2356 if (!pn->isKind(PNK_STATEMENTLIST))
2357 return statement(pn, dst);
2358 /* FALL THROUGH */
2360 case PNK_STATEMENTLIST:
2361 return blockStatement(pn, dst);
2363 case PNK_IF:
2365 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
2366 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
2367 JS_ASSERT_IF(pn->pn_kid3, pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
2369 RootedValue test(cx), cons(cx), alt(cx);
2371 return expression(pn->pn_kid1, &test) &&
2372 statement(pn->pn_kid2, &cons) &&
2373 optStatement(pn->pn_kid3, &alt) &&
2374 builder.ifStatement(test, cons, alt, &pn->pn_pos, dst);
2377 case PNK_SWITCH:
2378 return switchStatement(pn, dst);
2380 case PNK_TRY:
2381 return tryStatement(pn, dst);
2383 case PNK_WITH:
2384 case PNK_WHILE:
2386 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2387 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2389 RootedValue expr(cx), stmt(cx);
2391 return expression(pn->pn_left, &expr) &&
2392 statement(pn->pn_right, &stmt) &&
2393 (pn->isKind(PNK_WITH)
2394 ? builder.withStatement(expr, stmt, &pn->pn_pos, dst)
2395 : builder.whileStatement(expr, stmt, &pn->pn_pos, dst));
2398 case PNK_DOWHILE:
2400 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2401 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2403 RootedValue stmt(cx), test(cx);
2405 return statement(pn->pn_left, &stmt) &&
2406 expression(pn->pn_right, &test) &&
2407 builder.doWhileStatement(stmt, test, &pn->pn_pos, dst);
2410 case PNK_FOR:
2412 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2413 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2415 ParseNode *head = pn->pn_left;
2417 JS_ASSERT_IF(head->pn_kid1, head->pn_pos.encloses(head->pn_kid1->pn_pos));
2418 JS_ASSERT_IF(head->pn_kid2, head->pn_pos.encloses(head->pn_kid2->pn_pos));
2419 JS_ASSERT_IF(head->pn_kid3, head->pn_pos.encloses(head->pn_kid3->pn_pos));
2421 RootedValue stmt(cx);
2422 if (!statement(pn->pn_right, &stmt))
2423 return false;
2425 if (head->isKind(PNK_FORIN)) {
2426 RootedValue var(cx);
2427 return (!head->pn_kid1
2428 ? pattern(head->pn_kid2, nullptr, &var)
2429 : head->pn_kid1->isKind(PNK_LEXICALSCOPE)
2430 ? variableDeclaration(head->pn_kid1->pn_expr, true, &var)
2431 : variableDeclaration(head->pn_kid1, false, &var)) &&
2432 forIn(pn, head, var, stmt, dst);
2435 if (head->isKind(PNK_FOROF)) {
2436 RootedValue var(cx);
2437 return (!head->pn_kid1
2438 ? pattern(head->pn_kid2, nullptr, &var)
2439 : head->pn_kid1->isKind(PNK_LEXICALSCOPE)
2440 ? variableDeclaration(head->pn_kid1->pn_expr, true, &var)
2441 : variableDeclaration(head->pn_kid1, false, &var)) &&
2442 forOf(pn, head, var, stmt, dst);
2445 RootedValue init(cx), test(cx), update(cx);
2447 return forInit(head->pn_kid1, &init) &&
2448 optExpression(head->pn_kid2, &test) &&
2449 optExpression(head->pn_kid3, &update) &&
2450 builder.forStatement(init, test, update, stmt, &pn->pn_pos, dst);
2453 /* Synthesized by the parser when a for-in loop contains a variable initializer. */
2454 case PNK_SEQ:
2456 LOCAL_ASSERT(pn->pn_count == 2);
2458 ParseNode *prelude = pn->pn_head;
2459 ParseNode *loop = prelude->pn_next;
2461 LOCAL_ASSERT(prelude->isKind(PNK_VAR) && loop->isKind(PNK_FOR));
2463 RootedValue var(cx);
2464 if (!variableDeclaration(prelude, false, &var))
2465 return false;
2467 ParseNode *head = loop->pn_left;
2468 JS_ASSERT(head->isKind(PNK_FORIN));
2470 RootedValue stmt(cx);
2472 return statement(loop->pn_right, &stmt) && forIn(loop, head, var, stmt, dst);
2475 case PNK_BREAK:
2476 case PNK_CONTINUE:
2478 RootedValue label(cx);
2479 RootedAtom pnAtom(cx, pn->pn_atom);
2480 return optIdentifier(pnAtom, nullptr, &label) &&
2481 (pn->isKind(PNK_BREAK)
2482 ? builder.breakStatement(label, &pn->pn_pos, dst)
2483 : builder.continueStatement(label, &pn->pn_pos, dst));
2486 case PNK_LABEL:
2488 JS_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos));
2490 RootedValue label(cx), stmt(cx);
2491 RootedAtom pnAtom(cx, pn->as<LabeledStatement>().label());
2492 return identifier(pnAtom, nullptr, &label) &&
2493 statement(pn->pn_expr, &stmt) &&
2494 builder.labeledStatement(label, stmt, &pn->pn_pos, dst);
2497 case PNK_THROW:
2498 case PNK_RETURN:
2500 JS_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2502 RootedValue arg(cx);
2504 return optExpression(pn->pn_kid, &arg) &&
2505 (pn->isKind(PNK_THROW)
2506 ? builder.throwStatement(arg, &pn->pn_pos, dst)
2507 : builder.returnStatement(arg, &pn->pn_pos, dst));
2510 case PNK_DEBUGGER:
2511 return builder.debuggerStatement(&pn->pn_pos, dst);
2513 case PNK_NOP:
2514 return builder.emptyStatement(&pn->pn_pos, dst);
2516 default:
2517 LOCAL_NOT_REACHED("unexpected statement type");
2521 bool
2522 ASTSerializer::leftAssociate(ParseNode *pn, MutableHandleValue dst)
2524 JS_ASSERT(pn->isArity(PN_LIST));
2525 JS_ASSERT(pn->pn_count >= 1);
2527 ParseNodeKind kind = pn->getKind();
2528 bool lor = kind == PNK_OR;
2529 bool logop = lor || (kind == PNK_AND);
2531 ParseNode *head = pn->pn_head;
2532 RootedValue left(cx);
2533 if (!expression(head, &left))
2534 return false;
2535 for (ParseNode *next = head->pn_next; next; next = next->pn_next) {
2536 RootedValue right(cx);
2537 if (!expression(next, &right))
2538 return false;
2540 TokenPos subpos(pn->pn_pos.begin, next->pn_pos.end);
2542 if (logop) {
2543 if (!builder.logicalExpression(lor, left, right, &subpos, &left))
2544 return false;
2545 } else {
2546 BinaryOperator op = binop(pn->getKind(), pn->getOp());
2547 LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
2549 if (!builder.binaryExpression(op, left, right, &subpos, &left))
2550 return false;
2554 dst.set(left);
2555 return true;
2558 bool
2559 ASTSerializer::comprehensionBlock(ParseNode *pn, MutableHandleValue dst)
2561 LOCAL_ASSERT(pn->isArity(PN_BINARY));
2563 ParseNode *in = pn->pn_left;
2565 LOCAL_ASSERT(in && (in->isKind(PNK_FORIN) || in->isKind(PNK_FOROF)));
2567 bool isForEach = pn->pn_iflags & JSITER_FOREACH;
2568 bool isForOf = in->isKind(PNK_FOROF);
2570 RootedValue patt(cx), src(cx);
2571 return pattern(in->pn_kid2, nullptr, &patt) &&
2572 expression(in->pn_kid3, &src) &&
2573 builder.comprehensionBlock(patt, src, isForEach, isForOf, &in->pn_pos, dst);
2576 bool
2577 ASTSerializer::comprehension(ParseNode *pn, MutableHandleValue dst)
2579 LOCAL_ASSERT(pn->isKind(PNK_FOR));
2581 NodeVector blocks(cx);
2583 ParseNode *next = pn;
2584 while (next->isKind(PNK_FOR)) {
2585 RootedValue block(cx);
2586 if (!comprehensionBlock(next, &block) || !blocks.append(block))
2587 return false;
2588 next = next->pn_right;
2591 RootedValue filter(cx, MagicValue(JS_SERIALIZE_NO_NODE));
2593 if (next->isKind(PNK_IF)) {
2594 if (!optExpression(next->pn_kid1, &filter))
2595 return false;
2596 next = next->pn_kid2;
2597 } else if (next->isKind(PNK_STATEMENTLIST) && next->pn_count == 0) {
2598 /* FoldConstants optimized away the push. */
2599 NodeVector empty(cx);
2600 return builder.arrayExpression(empty, &pn->pn_pos, dst);
2603 LOCAL_ASSERT(next->isKind(PNK_ARRAYPUSH));
2605 RootedValue body(cx);
2607 return expression(next->pn_kid, &body) &&
2608 builder.comprehensionExpression(body, blocks, filter, &pn->pn_pos, dst);
2611 bool
2612 ASTSerializer::generatorExpression(ParseNode *pn, MutableHandleValue dst)
2614 LOCAL_ASSERT(pn->isKind(PNK_FOR));
2616 NodeVector blocks(cx);
2618 ParseNode *next = pn;
2619 while (next->isKind(PNK_FOR)) {
2620 RootedValue block(cx);
2621 if (!comprehensionBlock(next, &block) || !blocks.append(block))
2622 return false;
2623 next = next->pn_right;
2626 RootedValue filter(cx, MagicValue(JS_SERIALIZE_NO_NODE));
2628 if (next->isKind(PNK_IF)) {
2629 if (!optExpression(next->pn_kid1, &filter))
2630 return false;
2631 next = next->pn_kid2;
2634 LOCAL_ASSERT(next->isKind(PNK_SEMI) &&
2635 next->pn_kid->isKind(PNK_YIELD) &&
2636 next->pn_kid->pn_kid);
2638 RootedValue body(cx);
2640 return expression(next->pn_kid->pn_kid, &body) &&
2641 builder.generatorExpression(body, blocks, filter, &pn->pn_pos, dst);
2644 bool
2645 ASTSerializer::expression(ParseNode *pn, MutableHandleValue dst)
2647 JS_CHECK_RECURSION(cx, return false);
2648 switch (pn->getKind()) {
2649 case PNK_FUNCTION:
2651 ASTType type = pn->pn_funbox->function()->isArrow() ? AST_ARROW_EXPR : AST_FUNC_EXPR;
2652 return function(pn, type, dst);
2655 case PNK_COMMA:
2657 NodeVector exprs(cx);
2658 return expressions(pn, exprs) &&
2659 builder.sequenceExpression(exprs, &pn->pn_pos, dst);
2662 case PNK_CONDITIONAL:
2664 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
2665 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
2666 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
2668 RootedValue test(cx), cons(cx), alt(cx);
2670 return expression(pn->pn_kid1, &test) &&
2671 expression(pn->pn_kid2, &cons) &&
2672 expression(pn->pn_kid3, &alt) &&
2673 builder.conditionalExpression(test, cons, alt, &pn->pn_pos, dst);
2676 case PNK_OR:
2677 case PNK_AND:
2679 if (pn->isArity(PN_BINARY)) {
2680 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2681 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2683 RootedValue left(cx), right(cx);
2684 return expression(pn->pn_left, &left) &&
2685 expression(pn->pn_right, &right) &&
2686 builder.logicalExpression(pn->isKind(PNK_OR), left, right, &pn->pn_pos, dst);
2688 return leftAssociate(pn, dst);
2691 case PNK_PREINCREMENT:
2692 case PNK_PREDECREMENT:
2694 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2696 bool inc = pn->isKind(PNK_PREINCREMENT);
2697 RootedValue expr(cx);
2698 return expression(pn->pn_kid, &expr) &&
2699 builder.updateExpression(expr, inc, true, &pn->pn_pos, dst);
2702 case PNK_POSTINCREMENT:
2703 case PNK_POSTDECREMENT:
2705 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2707 bool inc = pn->isKind(PNK_POSTINCREMENT);
2708 RootedValue expr(cx);
2709 return expression(pn->pn_kid, &expr) &&
2710 builder.updateExpression(expr, inc, false, &pn->pn_pos, dst);
2713 case PNK_ASSIGN:
2714 case PNK_ADDASSIGN:
2715 case PNK_SUBASSIGN:
2716 case PNK_BITORASSIGN:
2717 case PNK_BITXORASSIGN:
2718 case PNK_BITANDASSIGN:
2719 case PNK_LSHASSIGN:
2720 case PNK_RSHASSIGN:
2721 case PNK_URSHASSIGN:
2722 case PNK_MULASSIGN:
2723 case PNK_DIVASSIGN:
2724 case PNK_MODASSIGN:
2726 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2727 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2729 AssignmentOperator op = aop(pn->getOp());
2730 LOCAL_ASSERT(op > AOP_ERR && op < AOP_LIMIT);
2732 RootedValue lhs(cx), rhs(cx);
2733 return pattern(pn->pn_left, nullptr, &lhs) &&
2734 expression(pn->pn_right, &rhs) &&
2735 builder.assignmentExpression(op, lhs, rhs, &pn->pn_pos, dst);
2738 case PNK_ADD:
2739 case PNK_SUB:
2740 case PNK_STRICTEQ:
2741 case PNK_EQ:
2742 case PNK_STRICTNE:
2743 case PNK_NE:
2744 case PNK_LT:
2745 case PNK_LE:
2746 case PNK_GT:
2747 case PNK_GE:
2748 case PNK_LSH:
2749 case PNK_RSH:
2750 case PNK_URSH:
2751 case PNK_STAR:
2752 case PNK_DIV:
2753 case PNK_MOD:
2754 case PNK_BITOR:
2755 case PNK_BITXOR:
2756 case PNK_BITAND:
2757 case PNK_IN:
2758 case PNK_INSTANCEOF:
2759 if (pn->isArity(PN_BINARY)) {
2760 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2761 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2763 BinaryOperator op = binop(pn->getKind(), pn->getOp());
2764 LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
2766 RootedValue left(cx), right(cx);
2767 return expression(pn->pn_left, &left) &&
2768 expression(pn->pn_right, &right) &&
2769 builder.binaryExpression(op, left, right, &pn->pn_pos, dst);
2771 return leftAssociate(pn, dst);
2773 case PNK_DELETE:
2774 case PNK_TYPEOF:
2775 case PNK_VOID:
2776 case PNK_NOT:
2777 case PNK_BITNOT:
2778 case PNK_POS:
2779 case PNK_NEG: {
2780 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2782 UnaryOperator op = unop(pn->getKind(), pn->getOp());
2783 LOCAL_ASSERT(op > UNOP_ERR && op < UNOP_LIMIT);
2785 RootedValue expr(cx);
2786 return expression(pn->pn_kid, &expr) &&
2787 builder.unaryExpression(op, expr, &pn->pn_pos, dst);
2790 #if JS_HAS_GENERATOR_EXPRS
2791 case PNK_GENEXP:
2792 return generatorExpression(pn->generatorExpr(), dst);
2793 #endif
2795 case PNK_NEW:
2796 case PNK_TAGGED_TEMPLATE:
2797 case PNK_CALL:
2799 ParseNode *next = pn->pn_head;
2800 JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2802 RootedValue callee(cx);
2803 if (!expression(next, &callee))
2804 return false;
2806 NodeVector args(cx);
2807 if (!args.reserve(pn->pn_count - 1))
2808 return false;
2810 for (next = next->pn_next; next; next = next->pn_next) {
2811 JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2813 RootedValue arg(cx);
2814 if (!expression(next, &arg))
2815 return false;
2816 args.infallibleAppend(arg);
2819 if (pn->getKind() == PNK_TAGGED_TEMPLATE)
2820 return builder.taggedTemplate(callee, args, &pn->pn_pos, dst);
2822 return pn->isKind(PNK_NEW)
2823 ? builder.newExpression(callee, args, &pn->pn_pos, dst)
2825 : builder.callExpression(callee, args, &pn->pn_pos, dst);
2828 case PNK_DOT:
2830 JS_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos));
2832 RootedValue expr(cx), id(cx);
2833 RootedAtom pnAtom(cx, pn->pn_atom);
2834 return expression(pn->pn_expr, &expr) &&
2835 identifier(pnAtom, nullptr, &id) &&
2836 builder.memberExpression(false, expr, id, &pn->pn_pos, dst);
2839 case PNK_ELEM:
2841 JS_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2842 JS_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2844 RootedValue left(cx), right(cx);
2845 return expression(pn->pn_left, &left) &&
2846 expression(pn->pn_right, &right) &&
2847 builder.memberExpression(true, left, right, &pn->pn_pos, dst);
2850 case PNK_CALLSITEOBJ:
2852 NodeVector raw(cx);
2853 if (!raw.reserve(pn->pn_head->pn_count))
2854 return false;
2855 for (ParseNode *next = pn->pn_head->pn_head; next; next = next->pn_next) {
2856 JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2858 RootedValue expr(cx);
2859 expr.setString(next->pn_atom);
2860 raw.infallibleAppend(expr);
2863 NodeVector cooked(cx);
2864 if (!cooked.reserve(pn->pn_count - 1))
2865 return false;
2867 for (ParseNode *next = pn->pn_head->pn_next; next; next = next->pn_next) {
2868 JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2870 RootedValue expr(cx);
2871 expr.setString(next->pn_atom);
2872 cooked.infallibleAppend(expr);
2875 return builder.callSiteObj(raw, cooked, &pn->pn_pos, dst);
2878 case PNK_ARRAY:
2880 NodeVector elts(cx);
2881 if (!elts.reserve(pn->pn_count))
2882 return false;
2884 for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
2885 JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2887 if (next->isKind(PNK_ELISION)) {
2888 elts.infallibleAppend(NullValue());
2889 } else {
2890 RootedValue expr(cx);
2891 if (!expression(next, &expr))
2892 return false;
2893 elts.infallibleAppend(expr);
2897 return builder.arrayExpression(elts, &pn->pn_pos, dst);
2900 case PNK_SPREAD:
2902 RootedValue expr(cx);
2903 return expression(pn->pn_kid, &expr) &&
2904 builder.spreadExpression(expr, &pn->pn_pos, dst);
2907 case PNK_COMPUTED_NAME:
2909 RootedValue name(cx);
2910 return expression(pn->pn_kid, &name) &&
2911 builder.computedName(name, &pn->pn_pos, dst);
2914 case PNK_OBJECT:
2916 NodeVector elts(cx);
2917 if (!elts.reserve(pn->pn_count))
2918 return false;
2920 for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
2921 JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2923 RootedValue prop(cx);
2924 if (!property(next, &prop))
2925 return false;
2926 elts.infallibleAppend(prop);
2929 return builder.objectExpression(elts, &pn->pn_pos, dst);
2932 case PNK_NAME:
2933 return identifier(pn, dst);
2935 case PNK_THIS:
2936 return builder.thisExpression(&pn->pn_pos, dst);
2938 case PNK_TEMPLATE_STRING_LIST:
2940 NodeVector elts(cx);
2941 if (!elts.reserve(pn->pn_count))
2942 return false;
2944 for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
2945 JS_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2947 RootedValue expr(cx);
2948 if (!expression(next, &expr))
2949 return false;
2950 elts.infallibleAppend(expr);
2953 return builder.templateLiteral(elts, &pn->pn_pos, dst);
2956 case PNK_TEMPLATE_STRING:
2957 case PNK_STRING:
2958 case PNK_REGEXP:
2959 case PNK_NUMBER:
2960 case PNK_TRUE:
2961 case PNK_FALSE:
2962 case PNK_NULL:
2963 return literal(pn, dst);
2965 case PNK_YIELD_STAR:
2967 JS_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2969 RootedValue arg(cx);
2970 return expression(pn->pn_kid, &arg) &&
2971 builder.yieldExpression(arg, Delegating, &pn->pn_pos, dst);
2974 case PNK_YIELD:
2976 JS_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2978 RootedValue arg(cx);
2979 return optExpression(pn->pn_kid, &arg) &&
2980 builder.yieldExpression(arg, NotDelegating, &pn->pn_pos, dst);
2983 case PNK_ARRAYCOMP:
2984 JS_ASSERT(pn->pn_pos.encloses(pn->pn_head->pn_pos));
2986 /* NB: it's no longer the case that pn_count could be 2. */
2987 LOCAL_ASSERT(pn->pn_count == 1);
2988 LOCAL_ASSERT(pn->pn_head->isKind(PNK_LEXICALSCOPE));
2990 return comprehension(pn->pn_head->pn_expr, dst);
2992 case PNK_LET:
2993 return let(pn, true, dst);
2995 default:
2996 LOCAL_NOT_REACHED("unexpected expression type");
3000 bool
3001 ASTSerializer::propertyName(ParseNode *pn, MutableHandleValue dst)
3003 if (pn->isKind(PNK_COMPUTED_NAME))
3004 return expression(pn, dst);
3005 if (pn->isKind(PNK_NAME))
3006 return identifier(pn, dst);
3008 LOCAL_ASSERT(pn->isKind(PNK_STRING) || pn->isKind(PNK_NUMBER));
3010 return literal(pn, dst);
3013 bool
3014 ASTSerializer::property(ParseNode *pn, MutableHandleValue dst)
3016 PropKind kind;
3017 switch (pn->getOp()) {
3018 case JSOP_INITPROP:
3019 kind = PROP_INIT;
3020 break;
3022 case JSOP_INITPROP_GETTER:
3023 kind = PROP_GETTER;
3024 break;
3026 case JSOP_INITPROP_SETTER:
3027 kind = PROP_SETTER;
3028 break;
3030 default:
3031 LOCAL_NOT_REACHED("unexpected object-literal property");
3034 bool isShorthand = pn->isKind(PNK_SHORTHAND);
3035 bool isMethod = pn->pn_right->isKind(PNK_FUNCTION) && kind == PROP_INIT;
3036 RootedValue key(cx), val(cx);
3037 return propertyName(pn->pn_left, &key) &&
3038 expression(pn->pn_right, &val) &&
3039 builder.propertyInitializer(key, val, kind, isShorthand, isMethod, &pn->pn_pos, dst);
3042 bool
3043 ASTSerializer::literal(ParseNode *pn, MutableHandleValue dst)
3045 RootedValue val(cx);
3046 switch (pn->getKind()) {
3047 case PNK_TEMPLATE_STRING:
3048 case PNK_STRING:
3049 val.setString(pn->pn_atom);
3050 break;
3052 case PNK_REGEXP:
3054 RootedObject re1(cx, pn->as<RegExpLiteral>().objbox()->object);
3055 LOCAL_ASSERT(re1 && re1->is<RegExpObject>());
3057 RootedObject re2(cx, CloneRegExpObject(cx, re1));
3058 if (!re2)
3059 return false;
3061 val.setObject(*re2);
3062 break;
3065 case PNK_NUMBER:
3066 val.setNumber(pn->pn_dval);
3067 break;
3069 case PNK_NULL:
3070 val.setNull();
3071 break;
3073 case PNK_TRUE:
3074 val.setBoolean(true);
3075 break;
3077 case PNK_FALSE:
3078 val.setBoolean(false);
3079 break;
3081 default:
3082 LOCAL_NOT_REACHED("unexpected literal type");
3085 return builder.literal(val, &pn->pn_pos, dst);
3088 bool
3089 ASTSerializer::arrayPattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst)
3091 JS_ASSERT(pn->isKind(PNK_ARRAY));
3093 NodeVector elts(cx);
3094 if (!elts.reserve(pn->pn_count))
3095 return false;
3097 for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
3098 if (next->isKind(PNK_ELISION)) {
3099 elts.infallibleAppend(NullValue());
3100 } else if (next->isKind(PNK_SPREAD)) {
3101 RootedValue target(cx);
3102 RootedValue spread(cx);
3103 if (!pattern(next->pn_kid, pkind, &target))
3104 return false;
3105 if(!builder.spreadExpression(target, &next->pn_pos, &spread))
3106 return false;
3107 elts.infallibleAppend(spread);
3108 } else {
3109 RootedValue patt(cx);
3110 if (!pattern(next, pkind, &patt))
3111 return false;
3112 elts.infallibleAppend(patt);
3116 return builder.arrayPattern(elts, &pn->pn_pos, dst);
3119 bool
3120 ASTSerializer::objectPattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst)
3122 JS_ASSERT(pn->isKind(PNK_OBJECT));
3124 NodeVector elts(cx);
3125 if (!elts.reserve(pn->pn_count))
3126 return false;
3128 for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
3129 LOCAL_ASSERT(next->isOp(JSOP_INITPROP));
3131 RootedValue key(cx), patt(cx), prop(cx);
3132 if (!propertyName(next->pn_left, &key) ||
3133 !pattern(next->pn_right, pkind, &patt) ||
3134 !builder.propertyPattern(key, patt, next->isKind(PNK_SHORTHAND), &next->pn_pos,
3135 &prop)) {
3136 return false;
3139 elts.infallibleAppend(prop);
3142 return builder.objectPattern(elts, &pn->pn_pos, dst);
3145 bool
3146 ASTSerializer::pattern(ParseNode *pn, VarDeclKind *pkind, MutableHandleValue dst)
3148 JS_CHECK_RECURSION(cx, return false);
3149 switch (pn->getKind()) {
3150 case PNK_OBJECT:
3151 return objectPattern(pn, pkind, dst);
3153 case PNK_ARRAY:
3154 return arrayPattern(pn, pkind, dst);
3156 case PNK_NAME:
3157 if (pkind && (pn->pn_dflags & PND_CONST))
3158 *pkind = VARDECL_CONST;
3159 /* FALL THROUGH */
3161 default:
3162 return expression(pn, dst);
3166 bool
3167 ASTSerializer::identifier(HandleAtom atom, TokenPos *pos, MutableHandleValue dst)
3169 RootedValue atomContentsVal(cx, unrootedAtomContents(atom));
3170 return builder.identifier(atomContentsVal, pos, dst);
3173 bool
3174 ASTSerializer::identifier(ParseNode *pn, MutableHandleValue dst)
3176 LOCAL_ASSERT(pn->isArity(PN_NAME) || pn->isArity(PN_NULLARY));
3177 LOCAL_ASSERT(pn->pn_atom);
3179 RootedAtom pnAtom(cx, pn->pn_atom);
3180 return identifier(pnAtom, &pn->pn_pos, dst);
3183 bool
3184 ASTSerializer::function(ParseNode *pn, ASTType type, MutableHandleValue dst)
3186 RootedFunction func(cx, pn->pn_funbox->function());
3188 // FIXME: Provide more information (legacy generator vs star generator).
3189 bool isGenerator = pn->pn_funbox->isGenerator();
3191 bool isExpression =
3192 #if JS_HAS_EXPR_CLOSURES
3193 func->isExprClosure();
3194 #else
3195 false;
3196 #endif
3198 RootedValue id(cx);
3199 RootedAtom funcAtom(cx, func->atom());
3200 if (!optIdentifier(funcAtom, nullptr, &id))
3201 return false;
3203 NodeVector args(cx);
3204 NodeVector defaults(cx);
3206 RootedValue body(cx), rest(cx);
3207 if (func->hasRest())
3208 rest.setUndefined();
3209 else
3210 rest.setNull();
3211 return functionArgsAndBody(pn->pn_body, args, defaults, &body, &rest) &&
3212 builder.function(type, &pn->pn_pos, id, args, defaults, body,
3213 rest, isGenerator, isExpression, dst);
3216 bool
3217 ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args, NodeVector &defaults,
3218 MutableHandleValue body, MutableHandleValue rest)
3220 ParseNode *pnargs;
3221 ParseNode *pnbody;
3223 /* Extract the args and body separately. */
3224 if (pn->isKind(PNK_ARGSBODY)) {
3225 pnargs = pn;
3226 pnbody = pn->last();
3227 } else {
3228 pnargs = nullptr;
3229 pnbody = pn;
3232 ParseNode *pndestruct;
3234 /* Extract the destructuring assignments. */
3235 if (pnbody->isArity(PN_LIST) && (pnbody->pn_xflags & PNX_DESTRUCT)) {
3236 ParseNode *head = pnbody->pn_head;
3237 LOCAL_ASSERT(head && head->isKind(PNK_SEMI));
3239 pndestruct = head->pn_kid;
3240 LOCAL_ASSERT(pndestruct);
3241 LOCAL_ASSERT(pndestruct->isKind(PNK_VAR));
3242 } else {
3243 pndestruct = nullptr;
3246 /* Serialize the arguments and body. */
3247 switch (pnbody->getKind()) {
3248 case PNK_RETURN: /* expression closure, no destructured args */
3249 return functionArgs(pn, pnargs, nullptr, pnbody, args, defaults, rest) &&
3250 expression(pnbody->pn_kid, body);
3252 case PNK_SEQ: /* expression closure with destructured args */
3254 ParseNode *pnstart = pnbody->pn_head->pn_next;
3255 LOCAL_ASSERT(pnstart && pnstart->isKind(PNK_RETURN));
3257 return functionArgs(pn, pnargs, pndestruct, pnbody, args, defaults, rest) &&
3258 expression(pnstart->pn_kid, body);
3261 case PNK_STATEMENTLIST: /* statement closure */
3263 ParseNode *pnstart = (pnbody->pn_xflags & PNX_DESTRUCT)
3264 ? pnbody->pn_head->pn_next
3265 : pnbody->pn_head;
3267 return functionArgs(pn, pnargs, pndestruct, pnbody, args, defaults, rest) &&
3268 functionBody(pnstart, &pnbody->pn_pos, body);
3271 default:
3272 LOCAL_NOT_REACHED("unexpected function contents");
3276 bool
3277 ASTSerializer::functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestruct,
3278 ParseNode *pnbody, NodeVector &args, NodeVector &defaults,
3279 MutableHandleValue rest)
3281 uint32_t i = 0;
3282 ParseNode *arg = pnargs ? pnargs->pn_head : nullptr;
3283 ParseNode *destruct = pndestruct ? pndestruct->pn_head : nullptr;
3284 RootedValue node(cx);
3287 * Arguments are found in potentially two different places: 1) the
3288 * argsbody sequence (which ends with the body node), or 2) a
3289 * destructuring initialization at the beginning of the body. Loop
3290 * |arg| through the argsbody and |destruct| through the initial
3291 * destructuring assignments, stopping only when we've exhausted
3292 * both.
3294 while ((arg && arg != pnbody) || destruct) {
3295 if (destruct && destruct->pn_right->frameSlot() == i) {
3296 if (!pattern(destruct->pn_left, nullptr, &node) || !args.append(node))
3297 return false;
3298 destruct = destruct->pn_next;
3299 } else if (arg && arg != pnbody) {
3301 * We don't check that arg->frameSlot() == i since we
3302 * can't call that method if the arg def has been turned
3303 * into a use, e.g.:
3305 * function(a) { function a() { } }
3307 * There's no other way to ask a non-destructuring arg its
3308 * index in the formals list, so we rely on the ability to
3309 * ask destructuring args their index above.
3311 JS_ASSERT(arg->isKind(PNK_NAME) || arg->isKind(PNK_ASSIGN));
3312 ParseNode *argName = arg->isKind(PNK_NAME) ? arg : arg->pn_left;
3313 if (!identifier(argName, &node))
3314 return false;
3315 if (rest.isUndefined() && arg->pn_next == pnbody)
3316 rest.setObject(node.toObject());
3317 else if (!args.append(node))
3318 return false;
3319 if (arg->pn_dflags & PND_DEFAULT) {
3320 ParseNode *expr = arg->expr();
3321 RootedValue def(cx);
3322 if (!expression(expr, &def) || !defaults.append(def))
3323 return false;
3325 arg = arg->pn_next;
3326 } else {
3327 LOCAL_NOT_REACHED("missing function argument");
3329 ++i;
3331 JS_ASSERT(!rest.isUndefined());
3333 return true;
3336 bool
3337 ASTSerializer::functionBody(ParseNode *pn, TokenPos *pos, MutableHandleValue dst)
3339 NodeVector elts(cx);
3341 /* We aren't sure how many elements there are up front, so we'll check each append. */
3342 for (ParseNode *next = pn; next; next = next->pn_next) {
3343 RootedValue child(cx);
3344 if (!sourceElement(next, &child) || !elts.append(child))
3345 return false;
3348 return builder.blockStatement(elts, pos, dst);
3351 static bool
3352 reflect_parse(JSContext *cx, uint32_t argc, jsval *vp)
3354 CallArgs args = CallArgsFromVp(argc, vp);
3356 if (args.length() < 1) {
3357 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
3358 "Reflect.parse", "0", "s");
3359 return false;
3362 RootedString src(cx, ToString<CanGC>(cx, args[0]));
3363 if (!src)
3364 return false;
3366 ScopedJSFreePtr<char> filename;
3367 uint32_t lineno = 1;
3368 bool loc = true;
3370 RootedObject builder(cx);
3372 RootedValue arg(cx, args.get(1));
3374 if (!arg.isNullOrUndefined()) {
3375 if (!arg.isObject()) {
3376 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
3377 JSDVG_SEARCH_STACK, arg, js::NullPtr(),
3378 "not an object", nullptr);
3379 return false;
3382 RootedObject config(cx, &arg.toObject());
3384 RootedValue prop(cx);
3386 /* config.loc */
3387 RootedId locId(cx, NameToId(cx->names().loc));
3388 RootedValue trueVal(cx, BooleanValue(true));
3389 if (!GetPropertyDefault(cx, config, locId, trueVal, &prop))
3390 return false;
3392 loc = ToBoolean(prop);
3394 if (loc) {
3395 /* config.source */
3396 RootedId sourceId(cx, NameToId(cx->names().source));
3397 RootedValue nullVal(cx, NullValue());
3398 if (!GetPropertyDefault(cx, config, sourceId, nullVal, &prop))
3399 return false;
3401 if (!prop.isNullOrUndefined()) {
3402 RootedString str(cx, ToString<CanGC>(cx, prop));
3403 if (!str)
3404 return false;
3406 filename = JS_EncodeString(cx, str);
3407 if (!filename)
3408 return false;
3411 /* config.line */
3412 RootedId lineId(cx, NameToId(cx->names().line));
3413 RootedValue oneValue(cx, Int32Value(1));
3414 if (!GetPropertyDefault(cx, config, lineId, oneValue, &prop) ||
3415 !ToUint32(cx, prop, &lineno)) {
3416 return false;
3420 /* config.builder */
3421 RootedId builderId(cx, NameToId(cx->names().builder));
3422 RootedValue nullVal(cx, NullValue());
3423 if (!GetPropertyDefault(cx, config, builderId, nullVal, &prop))
3424 return false;
3426 if (!prop.isNullOrUndefined()) {
3427 if (!prop.isObject()) {
3428 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
3429 JSDVG_SEARCH_STACK, prop, js::NullPtr(),
3430 "not an object", nullptr);
3431 return false;
3433 builder = &prop.toObject();
3437 /* Extract the builder methods first to report errors before parsing. */
3438 ASTSerializer serialize(cx, loc, filename, lineno);
3439 if (!serialize.init(builder))
3440 return false;
3442 JSFlatString *flat = src->ensureFlat(cx);
3443 if (!flat)
3444 return false;
3446 AutoStableStringChars flatChars(cx);
3447 if (!flatChars.initTwoByte(cx, flat))
3448 return false;
3450 CompileOptions options(cx);
3451 options.setFileAndLine(filename, lineno);
3452 options.setCanLazilyParse(false);
3453 mozilla::Range<const jschar> chars = flatChars.twoByteRange();
3454 Parser<FullParseHandler> parser(cx, &cx->tempLifoAlloc(), options, chars.start().get(),
3455 chars.length(), /* foldConstants = */ false, nullptr, nullptr);
3457 serialize.setParser(&parser);
3459 ParseNode *pn = parser.parse(nullptr);
3460 if (!pn)
3461 return false;
3463 RootedValue val(cx);
3464 if (!serialize.program(pn, &val)) {
3465 args.rval().setNull();
3466 return false;
3469 args.rval().set(val);
3470 return true;
3473 JS_PUBLIC_API(JSObject *)
3474 JS_InitReflect(JSContext *cx, HandleObject obj)
3476 static const JSFunctionSpec static_methods[] = {
3477 JS_FN("parse", reflect_parse, 1, 0),
3478 JS_FS_END
3481 RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx));
3482 if (!proto)
3483 return nullptr;
3484 RootedObject Reflect(cx, NewObjectWithGivenProto(cx, &JSObject::class_, proto,
3485 obj, SingletonObject));
3486 if (!Reflect)
3487 return nullptr;
3489 if (!JS_DefineProperty(cx, obj, "Reflect", Reflect, 0,
3490 JS_PropertyStub, JS_StrictPropertyStub)) {
3491 return nullptr;
3494 if (!JS_DefineFunctions(cx, Reflect, static_methods))
3495 return nullptr;
3497 return Reflect;