Bumping gaia.json for 1 gaia revision(s) a=gaia-bump
[gecko.git] / js / src / jsreflect.cpp
blob8135b436826351b789845b334c3c57f2a1210224
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 MOZ_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 MOZ_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 RootedPlainObject nobj(cx, NewBuiltinClassInstance<PlainObject>(cx));
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 MOZ_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 MOZ_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 prototypeMutation(HandleValue val, TokenPos* pos, MutableHandleValue dst);
555 bool propertyInitializer(HandleValue key, HandleValue val, PropKind kind, bool isShorthand,
556 bool isMethod, TokenPos* pos, MutableHandleValue dst);
560 * statements
563 bool blockStatement(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
565 bool expressionStatement(HandleValue expr, TokenPos* pos, MutableHandleValue dst);
567 bool emptyStatement(TokenPos* pos, MutableHandleValue dst);
569 bool ifStatement(HandleValue test, HandleValue cons, HandleValue alt, TokenPos* pos,
570 MutableHandleValue dst);
572 bool breakStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst);
574 bool continueStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst);
576 bool labeledStatement(HandleValue label, HandleValue stmt, TokenPos* pos,
577 MutableHandleValue dst);
579 bool throwStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst);
581 bool returnStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst);
583 bool forStatement(HandleValue init, HandleValue test, HandleValue update, HandleValue stmt,
584 TokenPos* pos, MutableHandleValue dst);
586 bool forInStatement(HandleValue var, HandleValue expr, HandleValue stmt,
587 bool isForEach, TokenPos* pos, MutableHandleValue dst);
589 bool forOfStatement(HandleValue var, HandleValue expr, HandleValue stmt, TokenPos* pos,
590 MutableHandleValue dst);
592 bool withStatement(HandleValue expr, HandleValue stmt, TokenPos* pos, MutableHandleValue dst);
594 bool whileStatement(HandleValue test, HandleValue stmt, TokenPos* pos, MutableHandleValue dst);
596 bool doWhileStatement(HandleValue stmt, HandleValue test, TokenPos* pos,
597 MutableHandleValue dst);
599 bool switchStatement(HandleValue disc, NodeVector& elts, bool lexical, TokenPos* pos,
600 MutableHandleValue dst);
602 bool tryStatement(HandleValue body, NodeVector& guarded, HandleValue unguarded,
603 HandleValue finally, TokenPos* pos, MutableHandleValue dst);
605 bool debuggerStatement(TokenPos* pos, MutableHandleValue dst);
607 bool letStatement(NodeVector& head, HandleValue stmt, TokenPos* pos, MutableHandleValue dst);
609 bool importDeclaration(NodeVector& elts, HandleValue moduleSpec, TokenPos* pos, MutableHandleValue dst);
611 bool importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos* pos, MutableHandleValue dst);
613 bool exportDeclaration(HandleValue decl, NodeVector& elts, HandleValue moduleSpec, TokenPos* pos, MutableHandleValue dst);
615 bool exportSpecifier(HandleValue bindingName, HandleValue exportName, TokenPos* pos, MutableHandleValue dst);
617 bool exportBatchSpecifier(TokenPos* pos, MutableHandleValue dst);
620 * expressions
623 bool binaryExpression(BinaryOperator op, HandleValue left, HandleValue right, TokenPos* pos,
624 MutableHandleValue dst);
626 bool unaryExpression(UnaryOperator op, HandleValue expr, TokenPos* pos, MutableHandleValue dst);
628 bool assignmentExpression(AssignmentOperator op, HandleValue lhs, HandleValue rhs,
629 TokenPos* pos, MutableHandleValue dst);
631 bool updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos* pos,
632 MutableHandleValue dst);
634 bool logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos* pos,
635 MutableHandleValue dst);
637 bool conditionalExpression(HandleValue test, HandleValue cons, HandleValue alt, TokenPos* pos,
638 MutableHandleValue dst);
640 bool sequenceExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
642 bool newExpression(HandleValue callee, NodeVector& args, TokenPos* pos, MutableHandleValue dst);
644 bool callExpression(HandleValue callee, NodeVector& args, TokenPos* pos,
645 MutableHandleValue dst);
647 bool memberExpression(bool computed, HandleValue expr, HandleValue member, TokenPos* pos,
648 MutableHandleValue dst);
650 bool arrayExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
652 bool templateLiteral(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
654 bool taggedTemplate(HandleValue callee, NodeVector& args, TokenPos* pos,
655 MutableHandleValue dst);
657 bool callSiteObj(NodeVector& raw, NodeVector& cooked, TokenPos* pos, MutableHandleValue dst);
659 bool spreadExpression(HandleValue expr, TokenPos* pos, MutableHandleValue dst);
661 bool computedName(HandleValue name, TokenPos* pos, MutableHandleValue dst);
663 bool objectExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
665 bool thisExpression(TokenPos* pos, MutableHandleValue dst);
667 bool yieldExpression(HandleValue arg, YieldKind kind, TokenPos* pos, MutableHandleValue dst);
669 bool comprehensionBlock(HandleValue patt, HandleValue src, bool isForEach, bool isForOf, TokenPos* pos,
670 MutableHandleValue dst);
672 bool comprehensionExpression(HandleValue body, NodeVector& blocks, HandleValue filter,
673 bool isLegacy, TokenPos* pos, MutableHandleValue dst);
675 bool generatorExpression(HandleValue body, NodeVector& blocks, HandleValue filter,
676 bool isLegacy, TokenPos* pos, MutableHandleValue dst);
678 bool letExpression(NodeVector& head, HandleValue expr, TokenPos* pos, MutableHandleValue dst);
681 * declarations
684 bool variableDeclaration(NodeVector& elts, VarDeclKind kind, TokenPos* pos,
685 MutableHandleValue dst);
688 * patterns
691 bool arrayPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
693 bool objectPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst);
695 bool propertyPattern(HandleValue key, HandleValue patt, bool isShorthand, TokenPos* pos,
696 MutableHandleValue dst);
699 } /* anonymous namespace */
701 bool
702 NodeBuilder::newNode(ASTType type, TokenPos* pos, MutableHandleObject dst)
704 MOZ_ASSERT(type > AST_ERROR && type < AST_LIMIT);
706 RootedValue tv(cx);
707 RootedPlainObject node(cx, NewBuiltinClassInstance<PlainObject>(cx));
708 if (!node ||
709 !setNodeLoc(node, pos) ||
710 !atomValue(nodeTypeNames[type], &tv) ||
711 !setProperty(node, "type", tv)) {
712 return false;
715 dst.set(node);
716 return true;
719 bool
720 NodeBuilder::newArray(NodeVector& elts, MutableHandleValue dst)
722 const size_t len = elts.length();
723 if (len > UINT32_MAX) {
724 js_ReportAllocationOverflow(cx);
725 return false;
727 RootedObject array(cx, NewDenseFullyAllocatedArray(cx, uint32_t(len)));
728 if (!array)
729 return false;
731 for (size_t i = 0; i < len; i++) {
732 RootedValue val(cx, elts[i]);
734 MOZ_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
736 /* Represent "no node" as an array hole by not adding the value. */
737 if (val.isMagic(JS_SERIALIZE_NO_NODE))
738 continue;
740 if (!JSObject::setElement(cx, array, array, i, &val, false))
741 return false;
744 dst.setObject(*array);
745 return true;
748 bool
749 NodeBuilder::newNodeLoc(TokenPos* pos, MutableHandleValue dst)
751 if (!pos) {
752 dst.setNull();
753 return true;
756 RootedObject loc(cx);
757 RootedObject to(cx);
758 RootedValue val(cx);
760 if (!newObject(&loc))
761 return false;
763 dst.setObject(*loc);
765 uint32_t startLineNum, startColumnIndex;
766 uint32_t endLineNum, endColumnIndex;
767 tokenStream->srcCoords.lineNumAndColumnIndex(pos->begin, &startLineNum, &startColumnIndex);
768 tokenStream->srcCoords.lineNumAndColumnIndex(pos->end, &endLineNum, &endColumnIndex);
770 if (!newObject(&to))
771 return false;
772 val.setObject(*to);
773 if (!setProperty(loc, "start", val))
774 return false;
775 val.setNumber(startLineNum);
776 if (!setProperty(to, "line", val))
777 return false;
778 val.setNumber(startColumnIndex);
779 if (!setProperty(to, "column", val))
780 return false;
782 if (!newObject(&to))
783 return false;
784 val.setObject(*to);
785 if (!setProperty(loc, "end", val))
786 return false;
787 val.setNumber(endLineNum);
788 if (!setProperty(to, "line", val))
789 return false;
790 val.setNumber(endColumnIndex);
791 if (!setProperty(to, "column", val))
792 return false;
794 if (!setProperty(loc, "source", srcval))
795 return false;
797 return true;
800 bool
801 NodeBuilder::setNodeLoc(HandleObject node, TokenPos* pos)
803 if (!saveLoc) {
804 RootedValue nullVal(cx, NullValue());
805 setProperty(node, "loc", nullVal);
806 return true;
809 RootedValue loc(cx);
810 return newNodeLoc(pos, &loc) &&
811 setProperty(node, "loc", loc);
814 bool
815 NodeBuilder::program(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
817 return listNode(AST_PROGRAM, "body", elts, pos, dst);
820 bool
821 NodeBuilder::blockStatement(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
823 return listNode(AST_BLOCK_STMT, "body", elts, pos, dst);
826 bool
827 NodeBuilder::expressionStatement(HandleValue expr, TokenPos* pos, MutableHandleValue dst)
829 RootedValue cb(cx, callbacks[AST_EXPR_STMT]);
830 if (!cb.isNull())
831 return callback(cb, expr, pos, dst);
833 return newNode(AST_EXPR_STMT, pos, "expression", expr, dst);
836 bool
837 NodeBuilder::emptyStatement(TokenPos* pos, MutableHandleValue dst)
839 RootedValue cb(cx, callbacks[AST_EMPTY_STMT]);
840 if (!cb.isNull())
841 return callback(cb, pos, dst);
843 return newNode(AST_EMPTY_STMT, pos, dst);
846 bool
847 NodeBuilder::ifStatement(HandleValue test, HandleValue cons, HandleValue alt, TokenPos* pos,
848 MutableHandleValue dst)
850 RootedValue cb(cx, callbacks[AST_IF_STMT]);
851 if (!cb.isNull())
852 return callback(cb, test, cons, opt(alt), pos, dst);
854 return newNode(AST_IF_STMT, pos,
855 "test", test,
856 "consequent", cons,
857 "alternate", alt,
858 dst);
861 bool
862 NodeBuilder::breakStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst)
864 RootedValue cb(cx, callbacks[AST_BREAK_STMT]);
865 if (!cb.isNull())
866 return callback(cb, opt(label), pos, dst);
868 return newNode(AST_BREAK_STMT, pos, "label", label, dst);
871 bool
872 NodeBuilder::continueStatement(HandleValue label, TokenPos* pos, MutableHandleValue dst)
874 RootedValue cb(cx, callbacks[AST_CONTINUE_STMT]);
875 if (!cb.isNull())
876 return callback(cb, opt(label), pos, dst);
878 return newNode(AST_CONTINUE_STMT, pos, "label", label, dst);
881 bool
882 NodeBuilder::labeledStatement(HandleValue label, HandleValue stmt, TokenPos* pos,
883 MutableHandleValue dst)
885 RootedValue cb(cx, callbacks[AST_LAB_STMT]);
886 if (!cb.isNull())
887 return callback(cb, label, stmt, pos, dst);
889 return newNode(AST_LAB_STMT, pos,
890 "label", label,
891 "body", stmt,
892 dst);
895 bool
896 NodeBuilder::throwStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst)
898 RootedValue cb(cx, callbacks[AST_THROW_STMT]);
899 if (!cb.isNull())
900 return callback(cb, arg, pos, dst);
902 return newNode(AST_THROW_STMT, pos, "argument", arg, dst);
905 bool
906 NodeBuilder::returnStatement(HandleValue arg, TokenPos* pos, MutableHandleValue dst)
908 RootedValue cb(cx, callbacks[AST_RETURN_STMT]);
909 if (!cb.isNull())
910 return callback(cb, opt(arg), pos, dst);
912 return newNode(AST_RETURN_STMT, pos, "argument", arg, dst);
915 bool
916 NodeBuilder::forStatement(HandleValue init, HandleValue test, HandleValue update, HandleValue stmt,
917 TokenPos* pos, MutableHandleValue dst)
919 RootedValue cb(cx, callbacks[AST_FOR_STMT]);
920 if (!cb.isNull())
921 return callback(cb, opt(init), opt(test), opt(update), stmt, pos, dst);
923 return newNode(AST_FOR_STMT, pos,
924 "init", init,
925 "test", test,
926 "update", update,
927 "body", stmt,
928 dst);
931 bool
932 NodeBuilder::forInStatement(HandleValue var, HandleValue expr, HandleValue stmt, bool isForEach,
933 TokenPos* pos, MutableHandleValue dst)
935 RootedValue isForEachVal(cx, BooleanValue(isForEach));
937 RootedValue cb(cx, callbacks[AST_FOR_IN_STMT]);
938 if (!cb.isNull())
939 return callback(cb, var, expr, stmt, isForEachVal, pos, dst);
941 return newNode(AST_FOR_IN_STMT, pos,
942 "left", var,
943 "right", expr,
944 "body", stmt,
945 "each", isForEachVal,
946 dst);
949 bool
950 NodeBuilder::forOfStatement(HandleValue var, HandleValue expr, HandleValue stmt, TokenPos* pos,
951 MutableHandleValue dst)
953 RootedValue cb(cx, callbacks[AST_FOR_OF_STMT]);
954 if (!cb.isNull())
955 return callback(cb, var, expr, stmt, pos, dst);
957 return newNode(AST_FOR_OF_STMT, pos,
958 "left", var,
959 "right", expr,
960 "body", stmt,
961 dst);
964 bool
965 NodeBuilder::withStatement(HandleValue expr, HandleValue stmt, TokenPos* pos,
966 MutableHandleValue dst)
968 RootedValue cb(cx, callbacks[AST_WITH_STMT]);
969 if (!cb.isNull())
970 return callback(cb, expr, stmt, pos, dst);
972 return newNode(AST_WITH_STMT, pos,
973 "object", expr,
974 "body", stmt,
975 dst);
978 bool
979 NodeBuilder::whileStatement(HandleValue test, HandleValue stmt, TokenPos* pos,
980 MutableHandleValue dst)
982 RootedValue cb(cx, callbacks[AST_WHILE_STMT]);
983 if (!cb.isNull())
984 return callback(cb, test, stmt, pos, dst);
986 return newNode(AST_WHILE_STMT, pos,
987 "test", test,
988 "body", stmt,
989 dst);
992 bool
993 NodeBuilder::doWhileStatement(HandleValue stmt, HandleValue test, TokenPos* pos,
994 MutableHandleValue dst)
996 RootedValue cb(cx, callbacks[AST_DO_STMT]);
997 if (!cb.isNull())
998 return callback(cb, stmt, test, pos, dst);
1000 return newNode(AST_DO_STMT, pos,
1001 "body", stmt,
1002 "test", test,
1003 dst);
1006 bool
1007 NodeBuilder::switchStatement(HandleValue disc, NodeVector& elts, bool lexical, TokenPos* pos,
1008 MutableHandleValue dst)
1010 RootedValue array(cx);
1011 if (!newArray(elts, &array))
1012 return false;
1014 RootedValue lexicalVal(cx, BooleanValue(lexical));
1016 RootedValue cb(cx, callbacks[AST_SWITCH_STMT]);
1017 if (!cb.isNull())
1018 return callback(cb, disc, array, lexicalVal, pos, dst);
1020 return newNode(AST_SWITCH_STMT, pos,
1021 "discriminant", disc,
1022 "cases", array,
1023 "lexical", lexicalVal,
1024 dst);
1027 bool
1028 NodeBuilder::tryStatement(HandleValue body, NodeVector& guarded, HandleValue unguarded,
1029 HandleValue finally, TokenPos* pos, MutableHandleValue dst)
1031 RootedValue guardedHandlers(cx);
1032 if (!newArray(guarded, &guardedHandlers))
1033 return false;
1035 RootedValue cb(cx, callbacks[AST_TRY_STMT]);
1036 if (!cb.isNull())
1037 return callback(cb, body, guardedHandlers, unguarded, opt(finally), pos, dst);
1039 return newNode(AST_TRY_STMT, pos,
1040 "block", body,
1041 "guardedHandlers", guardedHandlers,
1042 "handler", unguarded,
1043 "finalizer", finally,
1044 dst);
1047 bool
1048 NodeBuilder::debuggerStatement(TokenPos* pos, MutableHandleValue dst)
1050 RootedValue cb(cx, callbacks[AST_DEBUGGER_STMT]);
1051 if (!cb.isNull())
1052 return callback(cb, pos, dst);
1054 return newNode(AST_DEBUGGER_STMT, pos, dst);
1057 bool
1058 NodeBuilder::binaryExpression(BinaryOperator op, HandleValue left, HandleValue right, TokenPos* pos,
1059 MutableHandleValue dst)
1061 MOZ_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
1063 RootedValue opName(cx);
1064 if (!atomValue(binopNames[op], &opName))
1065 return false;
1067 RootedValue cb(cx, callbacks[AST_BINARY_EXPR]);
1068 if (!cb.isNull())
1069 return callback(cb, opName, left, right, pos, dst);
1071 return newNode(AST_BINARY_EXPR, pos,
1072 "operator", opName,
1073 "left", left,
1074 "right", right,
1075 dst);
1078 bool
1079 NodeBuilder::unaryExpression(UnaryOperator unop, HandleValue expr, TokenPos* pos,
1080 MutableHandleValue dst)
1082 MOZ_ASSERT(unop > UNOP_ERR && unop < UNOP_LIMIT);
1084 RootedValue opName(cx);
1085 if (!atomValue(unopNames[unop], &opName))
1086 return false;
1088 RootedValue cb(cx, callbacks[AST_UNARY_EXPR]);
1089 if (!cb.isNull())
1090 return callback(cb, opName, expr, pos, dst);
1092 RootedValue trueVal(cx, BooleanValue(true));
1093 return newNode(AST_UNARY_EXPR, pos,
1094 "operator", opName,
1095 "argument", expr,
1096 "prefix", trueVal,
1097 dst);
1100 bool
1101 NodeBuilder::assignmentExpression(AssignmentOperator aop, HandleValue lhs, HandleValue rhs,
1102 TokenPos* pos, MutableHandleValue dst)
1104 MOZ_ASSERT(aop > AOP_ERR && aop < AOP_LIMIT);
1106 RootedValue opName(cx);
1107 if (!atomValue(aopNames[aop], &opName))
1108 return false;
1110 RootedValue cb(cx, callbacks[AST_ASSIGN_EXPR]);
1111 if (!cb.isNull())
1112 return callback(cb, opName, lhs, rhs, pos, dst);
1114 return newNode(AST_ASSIGN_EXPR, pos,
1115 "operator", opName,
1116 "left", lhs,
1117 "right", rhs,
1118 dst);
1121 bool
1122 NodeBuilder::updateExpression(HandleValue expr, bool incr, bool prefix, TokenPos* pos,
1123 MutableHandleValue dst)
1125 RootedValue opName(cx);
1126 if (!atomValue(incr ? "++" : "--", &opName))
1127 return false;
1129 RootedValue prefixVal(cx, BooleanValue(prefix));
1131 RootedValue cb(cx, callbacks[AST_UPDATE_EXPR]);
1132 if (!cb.isNull())
1133 return callback(cb, expr, opName, prefixVal, pos, dst);
1135 return newNode(AST_UPDATE_EXPR, pos,
1136 "operator", opName,
1137 "argument", expr,
1138 "prefix", prefixVal,
1139 dst);
1142 bool
1143 NodeBuilder::logicalExpression(bool lor, HandleValue left, HandleValue right, TokenPos* pos,
1144 MutableHandleValue dst)
1146 RootedValue opName(cx);
1147 if (!atomValue(lor ? "||" : "&&", &opName))
1148 return false;
1150 RootedValue cb(cx, callbacks[AST_LOGICAL_EXPR]);
1151 if (!cb.isNull())
1152 return callback(cb, opName, left, right, pos, dst);
1154 return newNode(AST_LOGICAL_EXPR, pos,
1155 "operator", opName,
1156 "left", left,
1157 "right", right,
1158 dst);
1161 bool
1162 NodeBuilder::conditionalExpression(HandleValue test, HandleValue cons, HandleValue alt,
1163 TokenPos* pos, MutableHandleValue dst)
1165 RootedValue cb(cx, callbacks[AST_COND_EXPR]);
1166 if (!cb.isNull())
1167 return callback(cb, test, cons, alt, pos, dst);
1169 return newNode(AST_COND_EXPR, pos,
1170 "test", test,
1171 "consequent", cons,
1172 "alternate", alt,
1173 dst);
1176 bool
1177 NodeBuilder::sequenceExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
1179 return listNode(AST_LIST_EXPR, "expressions", elts, pos, dst);
1182 bool
1183 NodeBuilder::callExpression(HandleValue callee, NodeVector& args, TokenPos* pos,
1184 MutableHandleValue dst)
1186 RootedValue array(cx);
1187 if (!newArray(args, &array))
1188 return false;
1190 RootedValue cb(cx, callbacks[AST_CALL_EXPR]);
1191 if (!cb.isNull())
1192 return callback(cb, callee, array, pos, dst);
1194 return newNode(AST_CALL_EXPR, pos,
1195 "callee", callee,
1196 "arguments", array,
1197 dst);
1200 bool
1201 NodeBuilder::newExpression(HandleValue callee, NodeVector& args, TokenPos* pos,
1202 MutableHandleValue dst)
1204 RootedValue array(cx);
1205 if (!newArray(args, &array))
1206 return false;
1208 RootedValue cb(cx, callbacks[AST_NEW_EXPR]);
1209 if (!cb.isNull())
1210 return callback(cb, callee, array, pos, dst);
1212 return newNode(AST_NEW_EXPR, pos,
1213 "callee", callee,
1214 "arguments", array,
1215 dst);
1218 bool
1219 NodeBuilder::memberExpression(bool computed, HandleValue expr, HandleValue member, TokenPos* pos,
1220 MutableHandleValue dst)
1222 RootedValue computedVal(cx, BooleanValue(computed));
1224 RootedValue cb(cx, callbacks[AST_MEMBER_EXPR]);
1225 if (!cb.isNull())
1226 return callback(cb, computedVal, expr, member, pos, dst);
1228 return newNode(AST_MEMBER_EXPR, pos,
1229 "object", expr,
1230 "property", member,
1231 "computed", computedVal,
1232 dst);
1235 bool
1236 NodeBuilder::arrayExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
1238 return listNode(AST_ARRAY_EXPR, "elements", elts, pos, dst);
1241 bool
1242 NodeBuilder::callSiteObj(NodeVector& raw, NodeVector& cooked, TokenPos* pos, MutableHandleValue dst)
1244 RootedValue rawVal(cx);
1245 if (!newArray(raw, &rawVal))
1246 return false;
1248 RootedValue cookedVal(cx);
1249 if (!newArray(cooked, &cookedVal))
1250 return false;
1252 return newNode(AST_CALL_SITE_OBJ, pos,
1253 "raw", rawVal,
1254 "cooked", cookedVal,
1255 dst);
1258 bool
1259 NodeBuilder::taggedTemplate(HandleValue callee, NodeVector& args, TokenPos* pos,
1260 MutableHandleValue dst)
1262 RootedValue array(cx);
1263 if (!newArray(args, &array))
1264 return false;
1266 return newNode(AST_TAGGED_TEMPLATE, pos,
1267 "callee", callee,
1268 "arguments", array,
1269 dst);
1272 bool
1273 NodeBuilder::templateLiteral(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
1275 return listNode(AST_TEMPLATE_LITERAL, "elements", elts, pos, dst);
1278 bool
1279 NodeBuilder::computedName(HandleValue name, TokenPos* pos, MutableHandleValue dst)
1281 return newNode(AST_COMPUTED_NAME, pos,
1282 "name", name,
1283 dst);
1286 bool
1287 NodeBuilder::spreadExpression(HandleValue expr, TokenPos* pos, MutableHandleValue dst)
1289 return newNode(AST_SPREAD_EXPR, pos,
1290 "expression", expr,
1291 dst);
1294 bool
1295 NodeBuilder::propertyPattern(HandleValue key, HandleValue patt, bool isShorthand, TokenPos* pos,
1296 MutableHandleValue dst)
1298 RootedValue kindName(cx);
1299 if (!atomValue("init", &kindName))
1300 return false;
1302 RootedValue isShorthandVal(cx, BooleanValue(isShorthand));
1304 RootedValue cb(cx, callbacks[AST_PROP_PATT]);
1305 if (!cb.isNull())
1306 return callback(cb, key, patt, pos, dst);
1308 return newNode(AST_PROP_PATT, pos,
1309 "key", key,
1310 "value", patt,
1311 "kind", kindName,
1312 "shorthand", isShorthandVal,
1313 dst);
1316 bool
1317 NodeBuilder::prototypeMutation(HandleValue val, TokenPos* pos, MutableHandleValue dst)
1319 RootedValue cb(cx, callbacks[AST_PROTOTYPEMUTATION]);
1320 if (!cb.isNull())
1321 return callback(cb, val, pos, dst);
1323 return newNode(AST_PROTOTYPEMUTATION, pos,
1324 "value", val,
1325 dst);
1328 bool
1329 NodeBuilder::propertyInitializer(HandleValue key, HandleValue val, PropKind kind, bool isShorthand,
1330 bool isMethod, TokenPos* pos, MutableHandleValue dst)
1332 RootedValue kindName(cx);
1333 if (!atomValue(kind == PROP_INIT
1334 ? "init"
1335 : kind == PROP_GETTER
1336 ? "get"
1337 : "set", &kindName)) {
1338 return false;
1341 RootedValue isShorthandVal(cx, BooleanValue(isShorthand));
1342 RootedValue isMethodVal(cx, BooleanValue(isMethod));
1344 RootedValue cb(cx, callbacks[AST_PROPERTY]);
1345 if (!cb.isNull())
1346 return callback(cb, kindName, key, val, pos, dst);
1348 return newNode(AST_PROPERTY, pos,
1349 "key", key,
1350 "value", val,
1351 "kind", kindName,
1352 "method", isMethodVal,
1353 "shorthand", isShorthandVal,
1354 dst);
1357 bool
1358 NodeBuilder::objectExpression(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
1360 return listNode(AST_OBJECT_EXPR, "properties", elts, pos, dst);
1363 bool
1364 NodeBuilder::thisExpression(TokenPos* pos, MutableHandleValue dst)
1366 RootedValue cb(cx, callbacks[AST_THIS_EXPR]);
1367 if (!cb.isNull())
1368 return callback(cb, pos, dst);
1370 return newNode(AST_THIS_EXPR, pos, dst);
1373 bool
1374 NodeBuilder::yieldExpression(HandleValue arg, YieldKind kind, TokenPos* pos, MutableHandleValue dst)
1376 RootedValue cb(cx, callbacks[AST_YIELD_EXPR]);
1377 RootedValue delegateVal(cx);
1379 switch (kind) {
1380 case Delegating:
1381 delegateVal = BooleanValue(true);
1382 break;
1383 case NotDelegating:
1384 delegateVal = BooleanValue(false);
1385 break;
1388 if (!cb.isNull())
1389 return callback(cb, opt(arg), delegateVal, pos, dst);
1390 return newNode(AST_YIELD_EXPR, pos, "argument", arg, "delegate", delegateVal, dst);
1393 bool
1394 NodeBuilder::comprehensionBlock(HandleValue patt, HandleValue src, bool isForEach, bool isForOf, TokenPos* pos,
1395 MutableHandleValue dst)
1397 RootedValue isForEachVal(cx, BooleanValue(isForEach));
1398 RootedValue isForOfVal(cx, BooleanValue(isForOf));
1400 RootedValue cb(cx, callbacks[AST_COMP_BLOCK]);
1401 if (!cb.isNull())
1402 return callback(cb, patt, src, isForEachVal, isForOfVal, pos, dst);
1404 return newNode(AST_COMP_BLOCK, pos,
1405 "left", patt,
1406 "right", src,
1407 "each", isForEachVal,
1408 "of", isForOfVal,
1409 dst);
1412 bool
1413 NodeBuilder::comprehensionExpression(HandleValue body, NodeVector& blocks, HandleValue filter,
1414 bool isLegacy, TokenPos* pos, MutableHandleValue dst)
1416 RootedValue array(cx);
1417 if (!newArray(blocks, &array))
1418 return false;
1420 RootedValue style(cx);
1421 if (!atomValue(isLegacy ? "legacy" : "modern", &style))
1422 return false;
1424 RootedValue cb(cx, callbacks[AST_COMP_EXPR]);
1425 if (!cb.isNull())
1426 return callback(cb, body, array, opt(filter), style, pos, dst);
1428 return newNode(AST_COMP_EXPR, pos,
1429 "body", body,
1430 "blocks", array,
1431 "filter", filter,
1432 "style", style,
1433 dst);
1436 bool
1437 NodeBuilder::generatorExpression(HandleValue body, NodeVector& blocks, HandleValue filter,
1438 bool isLegacy, TokenPos* pos, MutableHandleValue dst)
1440 RootedValue array(cx);
1441 if (!newArray(blocks, &array))
1442 return false;
1444 RootedValue style(cx);
1445 if (!atomValue(isLegacy ? "legacy" : "modern", &style))
1446 return false;
1448 RootedValue cb(cx, callbacks[AST_GENERATOR_EXPR]);
1449 if (!cb.isNull())
1450 return callback(cb, body, array, opt(filter), style, pos, dst);
1452 return newNode(AST_GENERATOR_EXPR, pos,
1453 "body", body,
1454 "blocks", array,
1455 "filter", filter,
1456 "style", style,
1457 dst);
1460 bool
1461 NodeBuilder::letExpression(NodeVector& head, HandleValue expr, TokenPos* pos,
1462 MutableHandleValue dst)
1464 RootedValue array(cx);
1465 if (!newArray(head, &array))
1466 return false;
1468 RootedValue cb(cx, callbacks[AST_LET_EXPR]);
1469 if (!cb.isNull())
1470 return callback(cb, array, expr, pos, dst);
1472 return newNode(AST_LET_EXPR, pos,
1473 "head", array,
1474 "body", expr,
1475 dst);
1478 bool
1479 NodeBuilder::letStatement(NodeVector& head, HandleValue stmt, TokenPos* pos, MutableHandleValue dst)
1481 RootedValue array(cx);
1482 if (!newArray(head, &array))
1483 return false;
1485 RootedValue cb(cx, callbacks[AST_LET_STMT]);
1486 if (!cb.isNull())
1487 return callback(cb, array, stmt, pos, dst);
1489 return newNode(AST_LET_STMT, pos,
1490 "head", array,
1491 "body", stmt,
1492 dst);
1495 bool
1496 NodeBuilder::importDeclaration(NodeVector& elts, HandleValue moduleSpec, TokenPos* pos,
1497 MutableHandleValue dst)
1499 RootedValue array(cx);
1500 if (!newArray(elts, &array))
1501 return false;
1503 RootedValue cb(cx, callbacks[AST_IMPORT_DECL]);
1504 if (!cb.isNull())
1505 return callback(cb, array, moduleSpec, pos, dst);
1507 return newNode(AST_IMPORT_DECL, pos,
1508 "specifiers", array,
1509 "source", moduleSpec,
1510 dst);
1513 bool
1514 NodeBuilder::importSpecifier(HandleValue importName, HandleValue bindingName, TokenPos* pos,
1515 MutableHandleValue dst)
1517 RootedValue cb(cx, callbacks[AST_IMPORT_SPEC]);
1518 if (!cb.isNull())
1519 return callback(cb, importName, bindingName, pos, dst);
1521 return newNode(AST_IMPORT_SPEC, pos,
1522 "id", importName,
1523 "name", bindingName,
1524 dst);
1527 bool
1528 NodeBuilder::exportDeclaration(HandleValue decl, NodeVector& elts, HandleValue moduleSpec,
1529 TokenPos* pos, MutableHandleValue dst)
1531 RootedValue array(cx, NullValue());
1532 if (decl.isNull() && !newArray(elts, &array))
1533 return false;
1535 RootedValue cb(cx, callbacks[AST_IMPORT_DECL]);
1537 if (!cb.isNull())
1538 return callback(cb, decl, array, moduleSpec, pos, dst);
1540 return newNode(AST_EXPORT_DECL, pos,
1541 "declaration", decl,
1542 "specifiers", array,
1543 "source", moduleSpec,
1544 dst);
1547 bool
1548 NodeBuilder::exportSpecifier(HandleValue bindingName, HandleValue exportName, TokenPos* pos,
1549 MutableHandleValue dst)
1551 RootedValue cb(cx, callbacks[AST_EXPORT_SPEC]);
1552 if (!cb.isNull())
1553 return callback(cb, bindingName, exportName, pos, dst);
1555 return newNode(AST_EXPORT_SPEC, pos,
1556 "id", bindingName,
1557 "name", exportName,
1558 dst);
1561 bool
1562 NodeBuilder::exportBatchSpecifier(TokenPos* pos, MutableHandleValue dst)
1564 RootedValue cb(cx, callbacks[AST_EXPORT_BATCH_SPEC]);
1565 if (!cb.isNull())
1566 return callback(cb, pos, dst);
1568 return newNode(AST_EXPORT_BATCH_SPEC, pos, dst);
1571 bool
1572 NodeBuilder::variableDeclaration(NodeVector& elts, VarDeclKind kind, TokenPos* pos,
1573 MutableHandleValue dst)
1575 MOZ_ASSERT(kind > VARDECL_ERR && kind < VARDECL_LIMIT);
1577 RootedValue array(cx), kindName(cx);
1578 if (!newArray(elts, &array) ||
1579 !atomValue(kind == VARDECL_CONST
1580 ? "const"
1581 : kind == VARDECL_LET
1582 ? "let"
1583 : "var", &kindName)) {
1584 return false;
1587 RootedValue cb(cx, callbacks[AST_VAR_DECL]);
1588 if (!cb.isNull())
1589 return callback(cb, kindName, array, pos, dst);
1591 return newNode(AST_VAR_DECL, pos,
1592 "kind", kindName,
1593 "declarations", array,
1594 dst);
1597 bool
1598 NodeBuilder::variableDeclarator(HandleValue id, HandleValue init, TokenPos* pos,
1599 MutableHandleValue dst)
1601 RootedValue cb(cx, callbacks[AST_VAR_DTOR]);
1602 if (!cb.isNull())
1603 return callback(cb, id, opt(init), pos, dst);
1605 return newNode(AST_VAR_DTOR, pos, "id", id, "init", init, dst);
1608 bool
1609 NodeBuilder::switchCase(HandleValue expr, NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
1611 RootedValue array(cx);
1612 if (!newArray(elts, &array))
1613 return false;
1615 RootedValue cb(cx, callbacks[AST_CASE]);
1616 if (!cb.isNull())
1617 return callback(cb, opt(expr), array, pos, dst);
1619 return newNode(AST_CASE, pos,
1620 "test", expr,
1621 "consequent", array,
1622 dst);
1625 bool
1626 NodeBuilder::catchClause(HandleValue var, HandleValue guard, HandleValue body, TokenPos* pos,
1627 MutableHandleValue dst)
1629 RootedValue cb(cx, callbacks[AST_CATCH]);
1630 if (!cb.isNull())
1631 return callback(cb, var, opt(guard), body, pos, dst);
1633 return newNode(AST_CATCH, pos,
1634 "param", var,
1635 "guard", guard,
1636 "body", body,
1637 dst);
1640 bool
1641 NodeBuilder::literal(HandleValue val, TokenPos* pos, MutableHandleValue dst)
1643 RootedValue cb(cx, callbacks[AST_LITERAL]);
1644 if (!cb.isNull())
1645 return callback(cb, val, pos, dst);
1647 return newNode(AST_LITERAL, pos, "value", val, dst);
1650 bool
1651 NodeBuilder::identifier(HandleValue name, TokenPos* pos, MutableHandleValue dst)
1653 RootedValue cb(cx, callbacks[AST_IDENTIFIER]);
1654 if (!cb.isNull())
1655 return callback(cb, name, pos, dst);
1657 return newNode(AST_IDENTIFIER, pos, "name", name, dst);
1660 bool
1661 NodeBuilder::objectPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
1663 return listNode(AST_OBJECT_PATT, "properties", elts, pos, dst);
1666 bool
1667 NodeBuilder::arrayPattern(NodeVector& elts, TokenPos* pos, MutableHandleValue dst)
1669 return listNode(AST_ARRAY_PATT, "elements", elts, pos, dst);
1672 bool
1673 NodeBuilder::function(ASTType type, TokenPos* pos,
1674 HandleValue id, NodeVector& args, NodeVector& defaults,
1675 HandleValue body, HandleValue rest,
1676 bool isGenerator, bool isExpression,
1677 MutableHandleValue dst)
1679 RootedValue array(cx), defarray(cx);
1680 if (!newArray(args, &array))
1681 return false;
1682 if (!newArray(defaults, &defarray))
1683 return false;
1685 RootedValue isGeneratorVal(cx, BooleanValue(isGenerator));
1686 RootedValue isExpressionVal(cx, BooleanValue(isExpression));
1688 RootedValue cb(cx, callbacks[type]);
1689 if (!cb.isNull()) {
1690 return callback(cb, opt(id), array, body, isGeneratorVal, isExpressionVal, pos, dst);
1693 return newNode(type, pos,
1694 "id", id,
1695 "params", array,
1696 "defaults", defarray,
1697 "body", body,
1698 "rest", rest,
1699 "generator", isGeneratorVal,
1700 "expression", isExpressionVal,
1701 dst);
1704 namespace {
1707 * Serialization of parse nodes to JavaScript objects.
1709 * All serialization methods take a non-nullable ParseNode pointer.
1711 class ASTSerializer
1713 JSContext* cx;
1714 Parser<FullParseHandler>* parser;
1715 NodeBuilder builder;
1716 DebugOnly<uint32_t> lineno;
1718 Value unrootedAtomContents(JSAtom* atom) {
1719 return StringValue(atom ? atom : cx->names().empty);
1722 BinaryOperator binop(ParseNodeKind kind, JSOp op);
1723 UnaryOperator unop(ParseNodeKind kind, JSOp op);
1724 AssignmentOperator aop(JSOp op);
1726 bool statements(ParseNode* pn, NodeVector& elts);
1727 bool expressions(ParseNode* pn, NodeVector& elts);
1728 bool leftAssociate(ParseNode* pn, MutableHandleValue dst);
1729 bool functionArgs(ParseNode* pn, ParseNode* pnargs, ParseNode* pndestruct, ParseNode* pnbody,
1730 NodeVector& args, NodeVector& defaults, MutableHandleValue rest);
1732 bool sourceElement(ParseNode* pn, MutableHandleValue dst);
1734 bool declaration(ParseNode* pn, MutableHandleValue dst);
1735 bool variableDeclaration(ParseNode* pn, bool lexical, MutableHandleValue dst);
1736 bool variableDeclarator(ParseNode* pn, MutableHandleValue dst);
1737 bool let(ParseNode* pn, bool expr, MutableHandleValue dst);
1738 bool importDeclaration(ParseNode* pn, MutableHandleValue dst);
1739 bool importSpecifier(ParseNode* pn, MutableHandleValue dst);
1740 bool exportDeclaration(ParseNode* pn, MutableHandleValue dst);
1741 bool exportSpecifier(ParseNode* pn, MutableHandleValue dst);
1743 bool optStatement(ParseNode* pn, MutableHandleValue dst) {
1744 if (!pn) {
1745 dst.setMagic(JS_SERIALIZE_NO_NODE);
1746 return true;
1748 return statement(pn, dst);
1751 bool forInit(ParseNode* pn, MutableHandleValue dst);
1752 bool forIn(ParseNode* loop, ParseNode* head, HandleValue var, HandleValue stmt,
1753 MutableHandleValue dst);
1754 bool forOf(ParseNode* loop, ParseNode* head, HandleValue var, HandleValue stmt,
1755 MutableHandleValue dst);
1756 bool statement(ParseNode* pn, MutableHandleValue dst);
1757 bool blockStatement(ParseNode* pn, MutableHandleValue dst);
1758 bool switchStatement(ParseNode* pn, MutableHandleValue dst);
1759 bool switchCase(ParseNode* pn, MutableHandleValue dst);
1760 bool tryStatement(ParseNode* pn, MutableHandleValue dst);
1761 bool catchClause(ParseNode* pn, bool* isGuarded, MutableHandleValue dst);
1763 bool optExpression(ParseNode* pn, MutableHandleValue dst) {
1764 if (!pn) {
1765 dst.setMagic(JS_SERIALIZE_NO_NODE);
1766 return true;
1768 return expression(pn, dst);
1771 bool expression(ParseNode* pn, MutableHandleValue dst);
1773 bool propertyName(ParseNode* pn, MutableHandleValue dst);
1774 bool property(ParseNode* pn, MutableHandleValue dst);
1776 bool optIdentifier(HandleAtom atom, TokenPos* pos, MutableHandleValue dst) {
1777 if (!atom) {
1778 dst.setMagic(JS_SERIALIZE_NO_NODE);
1779 return true;
1781 return identifier(atom, pos, dst);
1784 bool identifier(HandleAtom atom, TokenPos* pos, MutableHandleValue dst);
1785 bool identifier(ParseNode* pn, MutableHandleValue dst);
1786 bool literal(ParseNode* pn, MutableHandleValue dst);
1788 bool pattern(ParseNode* pn, MutableHandleValue dst);
1789 bool arrayPattern(ParseNode* pn, MutableHandleValue dst);
1790 bool objectPattern(ParseNode* pn, MutableHandleValue dst);
1792 bool function(ParseNode* pn, ASTType type, MutableHandleValue dst);
1793 bool functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector& defaults,
1794 MutableHandleValue body, MutableHandleValue rest);
1795 bool functionBody(ParseNode* pn, TokenPos* pos, MutableHandleValue dst);
1797 bool comprehensionBlock(ParseNode* pn, MutableHandleValue dst);
1798 bool comprehension(ParseNode* pn, MutableHandleValue dst);
1799 bool generatorExpression(ParseNode* pn, MutableHandleValue dst);
1801 public:
1802 ASTSerializer(JSContext* c, bool l, char const* src, uint32_t ln)
1803 : cx(c)
1804 , builder(c, l, src)
1805 #ifdef DEBUG
1806 , lineno(ln)
1807 #endif
1810 bool init(HandleObject userobj) {
1811 return builder.init(userobj);
1814 void setParser(Parser<FullParseHandler>* p) {
1815 parser = p;
1816 builder.setTokenStream(&p->tokenStream);
1819 bool program(ParseNode* pn, MutableHandleValue dst);
1822 } /* anonymous namespace */
1824 AssignmentOperator
1825 ASTSerializer::aop(JSOp op)
1827 switch (op) {
1828 case JSOP_NOP:
1829 return AOP_ASSIGN;
1830 case JSOP_ADD:
1831 return AOP_PLUS;
1832 case JSOP_SUB:
1833 return AOP_MINUS;
1834 case JSOP_MUL:
1835 return AOP_STAR;
1836 case JSOP_DIV:
1837 return AOP_DIV;
1838 case JSOP_MOD:
1839 return AOP_MOD;
1840 case JSOP_LSH:
1841 return AOP_LSH;
1842 case JSOP_RSH:
1843 return AOP_RSH;
1844 case JSOP_URSH:
1845 return AOP_URSH;
1846 case JSOP_BITOR:
1847 return AOP_BITOR;
1848 case JSOP_BITXOR:
1849 return AOP_BITXOR;
1850 case JSOP_BITAND:
1851 return AOP_BITAND;
1852 default:
1853 return AOP_ERR;
1857 UnaryOperator
1858 ASTSerializer::unop(ParseNodeKind kind, JSOp op)
1860 if (kind == PNK_DELETE)
1861 return UNOP_DELETE;
1863 switch (op) {
1864 case JSOP_NEG:
1865 return UNOP_NEG;
1866 case JSOP_POS:
1867 return UNOP_POS;
1868 case JSOP_NOT:
1869 return UNOP_NOT;
1870 case JSOP_BITNOT:
1871 return UNOP_BITNOT;
1872 case JSOP_TYPEOF:
1873 case JSOP_TYPEOFEXPR:
1874 return UNOP_TYPEOF;
1875 case JSOP_VOID:
1876 return UNOP_VOID;
1877 default:
1878 return UNOP_ERR;
1882 BinaryOperator
1883 ASTSerializer::binop(ParseNodeKind kind, JSOp op)
1885 switch (kind) {
1886 case PNK_LSH:
1887 return BINOP_LSH;
1888 case PNK_RSH:
1889 return BINOP_RSH;
1890 case PNK_URSH:
1891 return BINOP_URSH;
1892 case PNK_LT:
1893 return BINOP_LT;
1894 case PNK_LE:
1895 return BINOP_LE;
1896 case PNK_GT:
1897 return BINOP_GT;
1898 case PNK_GE:
1899 return BINOP_GE;
1900 case PNK_EQ:
1901 return BINOP_EQ;
1902 case PNK_NE:
1903 return BINOP_NE;
1904 case PNK_STRICTEQ:
1905 return BINOP_STRICTEQ;
1906 case PNK_STRICTNE:
1907 return BINOP_STRICTNE;
1908 case PNK_ADD:
1909 return BINOP_ADD;
1910 case PNK_SUB:
1911 return BINOP_SUB;
1912 case PNK_STAR:
1913 return BINOP_STAR;
1914 case PNK_DIV:
1915 return BINOP_DIV;
1916 case PNK_MOD:
1917 return BINOP_MOD;
1918 case PNK_BITOR:
1919 return BINOP_BITOR;
1920 case PNK_BITXOR:
1921 return BINOP_BITXOR;
1922 case PNK_BITAND:
1923 return BINOP_BITAND;
1924 case PNK_IN:
1925 return BINOP_IN;
1926 case PNK_INSTANCEOF:
1927 return BINOP_INSTANCEOF;
1928 default:
1929 return BINOP_ERR;
1933 bool
1934 ASTSerializer::statements(ParseNode* pn, NodeVector& elts)
1936 MOZ_ASSERT(pn->isKind(PNK_STATEMENTLIST));
1937 MOZ_ASSERT(pn->isArity(PN_LIST));
1939 if (!elts.reserve(pn->pn_count))
1940 return false;
1942 for (ParseNode* next = pn->pn_head; next; next = next->pn_next) {
1943 MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
1945 RootedValue elt(cx);
1946 if (!sourceElement(next, &elt))
1947 return false;
1948 elts.infallibleAppend(elt);
1951 return true;
1954 bool
1955 ASTSerializer::expressions(ParseNode* pn, NodeVector& elts)
1957 if (!elts.reserve(pn->pn_count))
1958 return false;
1960 for (ParseNode* next = pn->pn_head; next; next = next->pn_next) {
1961 MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
1963 RootedValue elt(cx);
1964 if (!expression(next, &elt))
1965 return false;
1966 elts.infallibleAppend(elt);
1969 return true;
1972 bool
1973 ASTSerializer::blockStatement(ParseNode* pn, MutableHandleValue dst)
1975 MOZ_ASSERT(pn->isKind(PNK_STATEMENTLIST));
1977 NodeVector stmts(cx);
1978 return statements(pn, stmts) &&
1979 builder.blockStatement(stmts, &pn->pn_pos, dst);
1982 bool
1983 ASTSerializer::program(ParseNode* pn, MutableHandleValue dst)
1985 MOZ_ASSERT(parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin) == lineno);
1987 NodeVector stmts(cx);
1988 return statements(pn, stmts) &&
1989 builder.program(stmts, &pn->pn_pos, dst);
1992 bool
1993 ASTSerializer::sourceElement(ParseNode* pn, MutableHandleValue dst)
1995 /* SpiderMonkey allows declarations even in pure statement contexts. */
1996 return statement(pn, dst);
1999 bool
2000 ASTSerializer::declaration(ParseNode* pn, MutableHandleValue dst)
2002 MOZ_ASSERT(pn->isKind(PNK_FUNCTION) ||
2003 pn->isKind(PNK_VAR) ||
2004 pn->isKind(PNK_GLOBALCONST) ||
2005 pn->isKind(PNK_LET) ||
2006 pn->isKind(PNK_CONST));
2008 switch (pn->getKind()) {
2009 case PNK_FUNCTION:
2010 return function(pn, AST_FUNC_DECL, dst);
2012 case PNK_VAR:
2013 case PNK_GLOBALCONST:
2014 return variableDeclaration(pn, false, dst);
2016 default:
2017 MOZ_ASSERT(pn->isKind(PNK_LET) || pn->isKind(PNK_CONST));
2018 return variableDeclaration(pn, true, dst);
2022 bool
2023 ASTSerializer::variableDeclaration(ParseNode* pn, bool lexical, MutableHandleValue dst)
2025 MOZ_ASSERT_IF(lexical, pn->isKind(PNK_LET) || pn->isKind(PNK_CONST));
2026 MOZ_ASSERT_IF(!lexical, pn->isKind(PNK_VAR) || pn->isKind(PNK_GLOBALCONST));
2028 VarDeclKind kind = VARDECL_ERR;
2029 // Treat both the toplevel const binding (secretly var-like) and the lexical const
2030 // the same way
2031 if (lexical)
2032 kind = pn->isKind(PNK_LET) ? VARDECL_LET : VARDECL_CONST;
2033 else
2034 kind = pn->isKind(PNK_VAR) ? VARDECL_VAR : VARDECL_CONST;
2036 NodeVector dtors(cx);
2037 if (!dtors.reserve(pn->pn_count))
2038 return false;
2039 for (ParseNode* next = pn->pn_head; next; next = next->pn_next) {
2040 RootedValue child(cx);
2041 if (!variableDeclarator(next, &child))
2042 return false;
2043 dtors.infallibleAppend(child);
2045 return builder.variableDeclaration(dtors, kind, &pn->pn_pos, dst);
2048 bool
2049 ASTSerializer::variableDeclarator(ParseNode* pn, MutableHandleValue dst)
2051 ParseNode* pnleft;
2052 ParseNode* pnright;
2054 if (pn->isKind(PNK_NAME)) {
2055 pnleft = pn;
2056 pnright = pn->isUsed() ? nullptr : pn->pn_expr;
2057 MOZ_ASSERT_IF(pnright, pn->pn_pos.encloses(pnright->pn_pos));
2058 } else if (pn->isKind(PNK_ASSIGN)) {
2059 pnleft = pn->pn_left;
2060 pnright = pn->pn_right;
2061 MOZ_ASSERT(pn->pn_pos.encloses(pnleft->pn_pos));
2062 MOZ_ASSERT(pn->pn_pos.encloses(pnright->pn_pos));
2063 } else {
2064 /* This happens for a destructuring declarator in a for-in/of loop. */
2065 pnleft = pn;
2066 pnright = nullptr;
2069 RootedValue left(cx), right(cx);
2070 return pattern(pnleft, &left) &&
2071 optExpression(pnright, &right) &&
2072 builder.variableDeclarator(left, right, &pn->pn_pos, dst);
2075 bool
2076 ASTSerializer::let(ParseNode* pn, bool expr, MutableHandleValue dst)
2078 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2079 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2081 ParseNode* letHead = pn->pn_left;
2082 LOCAL_ASSERT(letHead->isArity(PN_LIST));
2084 ParseNode* letBody = pn->pn_right;
2085 LOCAL_ASSERT(letBody->isKind(PNK_LEXICALSCOPE));
2087 NodeVector dtors(cx);
2088 if (!dtors.reserve(letHead->pn_count))
2089 return false;
2091 for (ParseNode* next = letHead->pn_head; next; next = next->pn_next) {
2092 RootedValue child(cx);
2094 if (!variableDeclarator(next, &child))
2095 return false;
2096 dtors.infallibleAppend(child);
2099 RootedValue v(cx);
2100 return expr
2101 ? expression(letBody->pn_expr, &v) &&
2102 builder.letExpression(dtors, v, &pn->pn_pos, dst)
2103 : statement(letBody->pn_expr, &v) &&
2104 builder.letStatement(dtors, v, &pn->pn_pos, dst);
2107 bool
2108 ASTSerializer::importDeclaration(ParseNode* pn, MutableHandleValue dst)
2110 MOZ_ASSERT(pn->isKind(PNK_IMPORT));
2111 MOZ_ASSERT(pn->pn_left->isKind(PNK_IMPORT_SPEC_LIST));
2112 MOZ_ASSERT(pn->pn_right->isKind(PNK_STRING));
2114 NodeVector elts(cx);
2115 if (!elts.reserve(pn->pn_left->pn_count))
2116 return false;
2118 for (ParseNode* next = pn->pn_left->pn_head; next; next = next->pn_next) {
2119 RootedValue elt(cx);
2120 if (!importSpecifier(next, &elt))
2121 return false;
2122 elts.infallibleAppend(elt);
2125 RootedValue moduleSpec(cx);
2126 return literal(pn->pn_right, &moduleSpec) &&
2127 builder.importDeclaration(elts, moduleSpec, &pn->pn_pos, dst);
2130 bool
2131 ASTSerializer::importSpecifier(ParseNode* pn, MutableHandleValue dst)
2133 MOZ_ASSERT(pn->isKind(PNK_IMPORT_SPEC));
2135 RootedValue importName(cx);
2136 RootedValue bindingName(cx);
2137 return identifier(pn->pn_left, &importName) &&
2138 identifier(pn->pn_right, &bindingName) &&
2139 builder.importSpecifier(importName, bindingName, &pn->pn_pos, dst);
2142 bool
2143 ASTSerializer::exportDeclaration(ParseNode* pn, MutableHandleValue dst)
2145 MOZ_ASSERT(pn->isKind(PNK_EXPORT) || pn->isKind(PNK_EXPORT_FROM));
2146 MOZ_ASSERT_IF(pn->isKind(PNK_EXPORT_FROM), pn->pn_right->isKind(PNK_STRING));
2148 RootedValue decl(cx, NullValue());
2149 NodeVector elts(cx);
2151 ParseNode* kid = pn->isKind(PNK_EXPORT) ? pn->pn_kid : pn->pn_left;
2152 switch (ParseNodeKind kind = kid->getKind()) {
2153 case PNK_EXPORT_SPEC_LIST:
2154 if (!elts.reserve(pn->pn_left->pn_count))
2155 return false;
2157 for (ParseNode* next = pn->pn_left->pn_head; next; next = next->pn_next) {
2158 RootedValue elt(cx);
2159 if (next->isKind(PNK_EXPORT_SPEC)) {
2160 if (!exportSpecifier(next, &elt))
2161 return false;
2162 } else {
2163 if (!builder.exportBatchSpecifier(&pn->pn_pos, &elt))
2164 return false;
2166 elts.infallibleAppend(elt);
2168 break;
2170 case PNK_FUNCTION:
2171 if (!function(kid, AST_FUNC_DECL, &decl))
2172 return false;
2173 break;
2175 case PNK_VAR:
2176 case PNK_CONST:
2177 case PNK_GLOBALCONST:
2178 case PNK_LET:
2179 if (!variableDeclaration(kid, kind == PNK_LET, &decl))
2180 return false;
2181 break;
2183 default:
2184 LOCAL_NOT_REACHED("unexpected statement type");
2187 RootedValue moduleSpec(cx, NullValue());
2188 if (pn->isKind(PNK_EXPORT_FROM) && !literal(pn->pn_right, &moduleSpec))
2189 return false;
2191 return builder.exportDeclaration(decl, elts, moduleSpec, &pn->pn_pos, dst);
2194 bool
2195 ASTSerializer::exportSpecifier(ParseNode* pn, MutableHandleValue dst)
2197 MOZ_ASSERT(pn->isKind(PNK_EXPORT_SPEC));
2199 RootedValue bindingName(cx);
2200 RootedValue exportName(cx);
2201 return identifier(pn->pn_left, &bindingName) &&
2202 identifier(pn->pn_right, &exportName) &&
2203 builder.exportSpecifier(bindingName, exportName, &pn->pn_pos, dst);
2206 bool
2207 ASTSerializer::switchCase(ParseNode* pn, MutableHandleValue dst)
2209 MOZ_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos));
2210 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2212 NodeVector stmts(cx);
2214 RootedValue expr(cx);
2216 return optExpression(pn->pn_left, &expr) &&
2217 statements(pn->pn_right, stmts) &&
2218 builder.switchCase(expr, stmts, &pn->pn_pos, dst);
2221 bool
2222 ASTSerializer::switchStatement(ParseNode* pn, MutableHandleValue dst)
2224 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2225 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2227 RootedValue disc(cx);
2229 if (!expression(pn->pn_left, &disc))
2230 return false;
2232 ParseNode* listNode;
2233 bool lexical;
2235 if (pn->pn_right->isKind(PNK_LEXICALSCOPE)) {
2236 listNode = pn->pn_right->pn_expr;
2237 lexical = true;
2238 } else {
2239 listNode = pn->pn_right;
2240 lexical = false;
2243 NodeVector cases(cx);
2244 if (!cases.reserve(listNode->pn_count))
2245 return false;
2247 for (ParseNode* next = listNode->pn_head; next; next = next->pn_next) {
2248 RootedValue child(cx);
2249 if (!switchCase(next, &child))
2250 return false;
2251 cases.infallibleAppend(child);
2254 return builder.switchStatement(disc, cases, lexical, &pn->pn_pos, dst);
2257 bool
2258 ASTSerializer::catchClause(ParseNode* pn, bool* isGuarded, MutableHandleValue dst)
2260 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
2261 MOZ_ASSERT_IF(pn->pn_kid2, pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
2262 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
2264 RootedValue var(cx), guard(cx), body(cx);
2266 if (!pattern(pn->pn_kid1, &var) ||
2267 !optExpression(pn->pn_kid2, &guard)) {
2268 return false;
2271 *isGuarded = !guard.isMagic(JS_SERIALIZE_NO_NODE);
2273 return statement(pn->pn_kid3, &body) &&
2274 builder.catchClause(var, guard, body, &pn->pn_pos, dst);
2277 bool
2278 ASTSerializer::tryStatement(ParseNode* pn, MutableHandleValue dst)
2280 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
2281 MOZ_ASSERT_IF(pn->pn_kid2, pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
2282 MOZ_ASSERT_IF(pn->pn_kid3, pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
2284 RootedValue body(cx);
2285 if (!statement(pn->pn_kid1, &body))
2286 return false;
2288 NodeVector guarded(cx);
2289 RootedValue unguarded(cx, NullValue());
2291 if (pn->pn_kid2) {
2292 if (!guarded.reserve(pn->pn_kid2->pn_count))
2293 return false;
2295 for (ParseNode* next = pn->pn_kid2->pn_head; next; next = next->pn_next) {
2296 RootedValue clause(cx);
2297 bool isGuarded;
2298 if (!catchClause(next->pn_expr, &isGuarded, &clause))
2299 return false;
2300 if (isGuarded)
2301 guarded.infallibleAppend(clause);
2302 else
2303 unguarded = clause;
2307 RootedValue finally(cx);
2308 return optStatement(pn->pn_kid3, &finally) &&
2309 builder.tryStatement(body, guarded, unguarded, finally, &pn->pn_pos, dst);
2312 bool
2313 ASTSerializer::forInit(ParseNode* pn, MutableHandleValue dst)
2315 if (!pn) {
2316 dst.setMagic(JS_SERIALIZE_NO_NODE);
2317 return true;
2320 return (pn->isKind(PNK_VAR) || pn->isKind(PNK_GLOBALCONST))
2321 ? variableDeclaration(pn, false, dst)
2322 : expression(pn, dst);
2325 bool
2326 ASTSerializer::forOf(ParseNode* loop, ParseNode* head, HandleValue var, HandleValue stmt,
2327 MutableHandleValue dst)
2329 RootedValue expr(cx);
2331 return expression(head->pn_kid3, &expr) &&
2332 builder.forOfStatement(var, expr, stmt, &loop->pn_pos, dst);
2335 bool
2336 ASTSerializer::forIn(ParseNode* loop, ParseNode* head, HandleValue var, HandleValue stmt,
2337 MutableHandleValue dst)
2339 RootedValue expr(cx);
2340 bool isForEach = loop->pn_iflags & JSITER_FOREACH;
2342 return expression(head->pn_kid3, &expr) &&
2343 builder.forInStatement(var, expr, stmt, isForEach, &loop->pn_pos, dst);
2346 bool
2347 ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst)
2349 JS_CHECK_RECURSION(cx, return false);
2350 switch (pn->getKind()) {
2351 case PNK_FUNCTION:
2352 case PNK_VAR:
2353 case PNK_GLOBALCONST:
2354 return declaration(pn, dst);
2356 case PNK_LET:
2357 case PNK_CONST:
2358 return pn->isArity(PN_BINARY)
2359 ? let(pn, false, dst)
2360 : declaration(pn, dst);
2362 case PNK_IMPORT:
2363 return importDeclaration(pn, dst);
2365 case PNK_EXPORT:
2366 case PNK_EXPORT_FROM:
2367 return exportDeclaration(pn, dst);
2369 case PNK_NAME:
2370 LOCAL_ASSERT(pn->isUsed());
2371 return statement(pn->pn_lexdef, dst);
2373 case PNK_SEMI:
2374 if (pn->pn_kid) {
2375 RootedValue expr(cx);
2376 return expression(pn->pn_kid, &expr) &&
2377 builder.expressionStatement(expr, &pn->pn_pos, dst);
2379 return builder.emptyStatement(&pn->pn_pos, dst);
2381 case PNK_LEXICALSCOPE:
2382 pn = pn->pn_expr;
2383 if (!pn->isKind(PNK_STATEMENTLIST))
2384 return statement(pn, dst);
2385 /* FALL THROUGH */
2387 case PNK_STATEMENTLIST:
2388 return blockStatement(pn, dst);
2390 case PNK_IF:
2392 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
2393 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
2394 MOZ_ASSERT_IF(pn->pn_kid3, pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
2396 RootedValue test(cx), cons(cx), alt(cx);
2398 return expression(pn->pn_kid1, &test) &&
2399 statement(pn->pn_kid2, &cons) &&
2400 optStatement(pn->pn_kid3, &alt) &&
2401 builder.ifStatement(test, cons, alt, &pn->pn_pos, dst);
2404 case PNK_SWITCH:
2405 return switchStatement(pn, dst);
2407 case PNK_TRY:
2408 return tryStatement(pn, dst);
2410 case PNK_WITH:
2411 case PNK_WHILE:
2413 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2414 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2416 RootedValue expr(cx), stmt(cx);
2418 return expression(pn->pn_left, &expr) &&
2419 statement(pn->pn_right, &stmt) &&
2420 (pn->isKind(PNK_WITH)
2421 ? builder.withStatement(expr, stmt, &pn->pn_pos, dst)
2422 : builder.whileStatement(expr, stmt, &pn->pn_pos, dst));
2425 case PNK_DOWHILE:
2427 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2428 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2430 RootedValue stmt(cx), test(cx);
2432 return statement(pn->pn_left, &stmt) &&
2433 expression(pn->pn_right, &test) &&
2434 builder.doWhileStatement(stmt, test, &pn->pn_pos, dst);
2437 case PNK_FOR:
2439 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2440 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2442 ParseNode* head = pn->pn_left;
2444 MOZ_ASSERT_IF(head->pn_kid1, head->pn_pos.encloses(head->pn_kid1->pn_pos));
2445 MOZ_ASSERT_IF(head->pn_kid2, head->pn_pos.encloses(head->pn_kid2->pn_pos));
2446 MOZ_ASSERT_IF(head->pn_kid3, head->pn_pos.encloses(head->pn_kid3->pn_pos));
2448 RootedValue stmt(cx);
2449 if (!statement(pn->pn_right, &stmt))
2450 return false;
2452 if (head->isKind(PNK_FORIN)) {
2453 RootedValue var(cx);
2454 return (!head->pn_kid1
2455 ? pattern(head->pn_kid2, &var)
2456 : head->pn_kid1->isKind(PNK_LEXICALSCOPE)
2457 ? variableDeclaration(head->pn_kid1->pn_expr, true, &var)
2458 : variableDeclaration(head->pn_kid1, false, &var)) &&
2459 forIn(pn, head, var, stmt, dst);
2462 if (head->isKind(PNK_FOROF)) {
2463 RootedValue var(cx);
2464 return (!head->pn_kid1
2465 ? pattern(head->pn_kid2, &var)
2466 : head->pn_kid1->isKind(PNK_LEXICALSCOPE)
2467 ? variableDeclaration(head->pn_kid1->pn_expr, true, &var)
2468 : variableDeclaration(head->pn_kid1, false, &var)) &&
2469 forOf(pn, head, var, stmt, dst);
2472 RootedValue init(cx), test(cx), update(cx);
2474 return forInit(head->pn_kid1, &init) &&
2475 optExpression(head->pn_kid2, &test) &&
2476 optExpression(head->pn_kid3, &update) &&
2477 builder.forStatement(init, test, update, stmt, &pn->pn_pos, dst);
2480 /* Synthesized by the parser when a for-in loop contains a variable initializer. */
2481 case PNK_SEQ:
2483 LOCAL_ASSERT(pn->pn_count == 2);
2485 ParseNode* prelude = pn->pn_head;
2486 ParseNode* loop = prelude->pn_next;
2488 LOCAL_ASSERT(prelude->isKind(PNK_VAR) && loop->isKind(PNK_FOR));
2490 RootedValue var(cx);
2491 if (!variableDeclaration(prelude, false, &var))
2492 return false;
2494 ParseNode* head = loop->pn_left;
2495 MOZ_ASSERT(head->isKind(PNK_FORIN));
2497 RootedValue stmt(cx);
2499 return statement(loop->pn_right, &stmt) && forIn(loop, head, var, stmt, dst);
2502 case PNK_BREAK:
2503 case PNK_CONTINUE:
2505 RootedValue label(cx);
2506 RootedAtom pnAtom(cx, pn->pn_atom);
2507 return optIdentifier(pnAtom, nullptr, &label) &&
2508 (pn->isKind(PNK_BREAK)
2509 ? builder.breakStatement(label, &pn->pn_pos, dst)
2510 : builder.continueStatement(label, &pn->pn_pos, dst));
2513 case PNK_LABEL:
2515 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos));
2517 RootedValue label(cx), stmt(cx);
2518 RootedAtom pnAtom(cx, pn->as<LabeledStatement>().label());
2519 return identifier(pnAtom, nullptr, &label) &&
2520 statement(pn->pn_expr, &stmt) &&
2521 builder.labeledStatement(label, stmt, &pn->pn_pos, dst);
2524 case PNK_THROW:
2526 MOZ_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2528 RootedValue arg(cx);
2530 return optExpression(pn->pn_kid, &arg) &&
2531 builder.throwStatement(arg, &pn->pn_pos, dst);
2534 case PNK_RETURN:
2536 MOZ_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos));
2538 RootedValue arg(cx);
2540 return optExpression(pn->pn_left, &arg) &&
2541 builder.returnStatement(arg, &pn->pn_pos, dst);
2544 case PNK_DEBUGGER:
2545 return builder.debuggerStatement(&pn->pn_pos, dst);
2547 case PNK_NOP:
2548 return builder.emptyStatement(&pn->pn_pos, dst);
2550 default:
2551 LOCAL_NOT_REACHED("unexpected statement type");
2555 bool
2556 ASTSerializer::leftAssociate(ParseNode* pn, MutableHandleValue dst)
2558 MOZ_ASSERT(pn->isArity(PN_LIST));
2559 MOZ_ASSERT(pn->pn_count >= 1);
2561 ParseNodeKind kind = pn->getKind();
2562 bool lor = kind == PNK_OR;
2563 bool logop = lor || (kind == PNK_AND);
2565 ParseNode* head = pn->pn_head;
2566 RootedValue left(cx);
2567 if (!expression(head, &left))
2568 return false;
2569 for (ParseNode* next = head->pn_next; next; next = next->pn_next) {
2570 RootedValue right(cx);
2571 if (!expression(next, &right))
2572 return false;
2574 TokenPos subpos(pn->pn_pos.begin, next->pn_pos.end);
2576 if (logop) {
2577 if (!builder.logicalExpression(lor, left, right, &subpos, &left))
2578 return false;
2579 } else {
2580 BinaryOperator op = binop(pn->getKind(), pn->getOp());
2581 LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
2583 if (!builder.binaryExpression(op, left, right, &subpos, &left))
2584 return false;
2588 dst.set(left);
2589 return true;
2592 bool
2593 ASTSerializer::comprehensionBlock(ParseNode* pn, MutableHandleValue dst)
2595 LOCAL_ASSERT(pn->isArity(PN_BINARY));
2597 ParseNode* in = pn->pn_left;
2599 LOCAL_ASSERT(in && (in->isKind(PNK_FORIN) || in->isKind(PNK_FOROF)));
2601 bool isForEach = in->isKind(PNK_FORIN) && (pn->pn_iflags & JSITER_FOREACH);
2602 bool isForOf = in->isKind(PNK_FOROF);
2604 RootedValue patt(cx), src(cx);
2605 return pattern(in->pn_kid2, &patt) &&
2606 expression(in->pn_kid3, &src) &&
2607 builder.comprehensionBlock(patt, src, isForEach, isForOf, &in->pn_pos, dst);
2610 bool
2611 ASTSerializer::comprehension(ParseNode* pn, MutableHandleValue dst)
2613 // There are two array comprehension flavors.
2614 // 1. The kind that was in ES4 for a while: [z for (x in y)]
2615 // 2. The kind that was in ES6 for a while: [for (x of y) z]
2616 // They have slightly different parse trees and scoping.
2617 bool isLegacy = pn->isKind(PNK_LEXICALSCOPE);
2618 ParseNode* next = isLegacy ? pn->pn_expr : pn;
2619 LOCAL_ASSERT(next->isKind(PNK_FOR));
2621 NodeVector blocks(cx);
2623 while (next->isKind(PNK_FOR)) {
2624 RootedValue block(cx);
2625 if (!comprehensionBlock(next, &block) || !blocks.append(block))
2626 return false;
2627 next = next->pn_right;
2630 RootedValue filter(cx, MagicValue(JS_SERIALIZE_NO_NODE));
2632 if (next->isKind(PNK_IF)) {
2633 if (!optExpression(next->pn_kid1, &filter))
2634 return false;
2635 next = next->pn_kid2;
2636 } else if (next->isKind(PNK_STATEMENTLIST) && next->pn_count == 0) {
2637 /* FoldConstants optimized away the push. */
2638 NodeVector empty(cx);
2639 return builder.arrayExpression(empty, &pn->pn_pos, dst);
2642 LOCAL_ASSERT(next->isKind(PNK_ARRAYPUSH));
2644 RootedValue body(cx);
2646 return expression(next->pn_kid, &body) &&
2647 builder.comprehensionExpression(body, blocks, filter, isLegacy, &pn->pn_pos, dst);
2650 bool
2651 ASTSerializer::generatorExpression(ParseNode* pn, MutableHandleValue dst)
2653 // Just as there are two kinds of array comprehension (see
2654 // ASTSerializer::comprehension), there are legacy and modern generator
2655 // expression.
2656 bool isLegacy = pn->isKind(PNK_LEXICALSCOPE);
2657 ParseNode* next = isLegacy ? pn->pn_expr : pn;
2658 LOCAL_ASSERT(next->isKind(PNK_FOR));
2660 NodeVector blocks(cx);
2662 while (next->isKind(PNK_FOR)) {
2663 RootedValue block(cx);
2664 if (!comprehensionBlock(next, &block) || !blocks.append(block))
2665 return false;
2666 next = next->pn_right;
2669 RootedValue filter(cx, MagicValue(JS_SERIALIZE_NO_NODE));
2671 if (next->isKind(PNK_IF)) {
2672 if (!optExpression(next->pn_kid1, &filter))
2673 return false;
2674 next = next->pn_kid2;
2677 LOCAL_ASSERT(next->isKind(PNK_SEMI) &&
2678 next->pn_kid->isKind(PNK_YIELD) &&
2679 next->pn_kid->pn_left);
2681 RootedValue body(cx);
2683 return expression(next->pn_kid->pn_left, &body) &&
2684 builder.generatorExpression(body, blocks, filter, isLegacy, &pn->pn_pos, dst);
2687 bool
2688 ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
2690 JS_CHECK_RECURSION(cx, return false);
2691 switch (pn->getKind()) {
2692 case PNK_FUNCTION:
2694 ASTType type = pn->pn_funbox->function()->isArrow() ? AST_ARROW_EXPR : AST_FUNC_EXPR;
2695 return function(pn, type, dst);
2698 case PNK_COMMA:
2700 NodeVector exprs(cx);
2701 return expressions(pn, exprs) &&
2702 builder.sequenceExpression(exprs, &pn->pn_pos, dst);
2705 case PNK_CONDITIONAL:
2707 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
2708 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
2709 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid3->pn_pos));
2711 RootedValue test(cx), cons(cx), alt(cx);
2713 return expression(pn->pn_kid1, &test) &&
2714 expression(pn->pn_kid2, &cons) &&
2715 expression(pn->pn_kid3, &alt) &&
2716 builder.conditionalExpression(test, cons, alt, &pn->pn_pos, dst);
2719 case PNK_OR:
2720 case PNK_AND:
2722 if (pn->isArity(PN_BINARY)) {
2723 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2724 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2726 RootedValue left(cx), right(cx);
2727 return expression(pn->pn_left, &left) &&
2728 expression(pn->pn_right, &right) &&
2729 builder.logicalExpression(pn->isKind(PNK_OR), left, right, &pn->pn_pos, dst);
2731 return leftAssociate(pn, dst);
2734 case PNK_PREINCREMENT:
2735 case PNK_PREDECREMENT:
2737 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2739 bool inc = pn->isKind(PNK_PREINCREMENT);
2740 RootedValue expr(cx);
2741 return expression(pn->pn_kid, &expr) &&
2742 builder.updateExpression(expr, inc, true, &pn->pn_pos, dst);
2745 case PNK_POSTINCREMENT:
2746 case PNK_POSTDECREMENT:
2748 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2750 bool inc = pn->isKind(PNK_POSTINCREMENT);
2751 RootedValue expr(cx);
2752 return expression(pn->pn_kid, &expr) &&
2753 builder.updateExpression(expr, inc, false, &pn->pn_pos, dst);
2756 case PNK_ASSIGN:
2757 case PNK_ADDASSIGN:
2758 case PNK_SUBASSIGN:
2759 case PNK_BITORASSIGN:
2760 case PNK_BITXORASSIGN:
2761 case PNK_BITANDASSIGN:
2762 case PNK_LSHASSIGN:
2763 case PNK_RSHASSIGN:
2764 case PNK_URSHASSIGN:
2765 case PNK_MULASSIGN:
2766 case PNK_DIVASSIGN:
2767 case PNK_MODASSIGN:
2769 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2770 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2772 AssignmentOperator op = aop(pn->getOp());
2773 LOCAL_ASSERT(op > AOP_ERR && op < AOP_LIMIT);
2775 RootedValue lhs(cx), rhs(cx);
2776 return pattern(pn->pn_left, &lhs) &&
2777 expression(pn->pn_right, &rhs) &&
2778 builder.assignmentExpression(op, lhs, rhs, &pn->pn_pos, dst);
2781 case PNK_ADD:
2782 case PNK_SUB:
2783 case PNK_STRICTEQ:
2784 case PNK_EQ:
2785 case PNK_STRICTNE:
2786 case PNK_NE:
2787 case PNK_LT:
2788 case PNK_LE:
2789 case PNK_GT:
2790 case PNK_GE:
2791 case PNK_LSH:
2792 case PNK_RSH:
2793 case PNK_URSH:
2794 case PNK_STAR:
2795 case PNK_DIV:
2796 case PNK_MOD:
2797 case PNK_BITOR:
2798 case PNK_BITXOR:
2799 case PNK_BITAND:
2800 case PNK_IN:
2801 case PNK_INSTANCEOF:
2802 if (pn->isArity(PN_BINARY)) {
2803 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2804 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2806 BinaryOperator op = binop(pn->getKind(), pn->getOp());
2807 LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
2809 RootedValue left(cx), right(cx);
2810 return expression(pn->pn_left, &left) &&
2811 expression(pn->pn_right, &right) &&
2812 builder.binaryExpression(op, left, right, &pn->pn_pos, dst);
2814 return leftAssociate(pn, dst);
2816 case PNK_DELETE:
2817 case PNK_TYPEOF:
2818 case PNK_VOID:
2819 case PNK_NOT:
2820 case PNK_BITNOT:
2821 case PNK_POS:
2822 case PNK_NEG: {
2823 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
2825 UnaryOperator op = unop(pn->getKind(), pn->getOp());
2826 LOCAL_ASSERT(op > UNOP_ERR && op < UNOP_LIMIT);
2828 RootedValue expr(cx);
2829 return expression(pn->pn_kid, &expr) &&
2830 builder.unaryExpression(op, expr, &pn->pn_pos, dst);
2833 #if JS_HAS_GENERATOR_EXPRS
2834 case PNK_GENEXP:
2835 return generatorExpression(pn->generatorExpr(), dst);
2836 #endif
2838 case PNK_NEW:
2839 case PNK_TAGGED_TEMPLATE:
2840 case PNK_CALL:
2842 ParseNode* next = pn->pn_head;
2843 MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2845 RootedValue callee(cx);
2846 if (!expression(next, &callee))
2847 return false;
2849 NodeVector args(cx);
2850 if (!args.reserve(pn->pn_count - 1))
2851 return false;
2853 for (next = next->pn_next; next; next = next->pn_next) {
2854 MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2856 RootedValue arg(cx);
2857 if (!expression(next, &arg))
2858 return false;
2859 args.infallibleAppend(arg);
2862 if (pn->getKind() == PNK_TAGGED_TEMPLATE)
2863 return builder.taggedTemplate(callee, args, &pn->pn_pos, dst);
2865 return pn->isKind(PNK_NEW)
2866 ? builder.newExpression(callee, args, &pn->pn_pos, dst)
2868 : builder.callExpression(callee, args, &pn->pn_pos, dst);
2871 case PNK_DOT:
2873 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos));
2875 RootedValue expr(cx), id(cx);
2876 RootedAtom pnAtom(cx, pn->pn_atom);
2877 return expression(pn->pn_expr, &expr) &&
2878 identifier(pnAtom, nullptr, &id) &&
2879 builder.memberExpression(false, expr, id, &pn->pn_pos, dst);
2882 case PNK_ELEM:
2884 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
2885 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
2887 RootedValue left(cx), right(cx);
2888 return expression(pn->pn_left, &left) &&
2889 expression(pn->pn_right, &right) &&
2890 builder.memberExpression(true, left, right, &pn->pn_pos, dst);
2893 case PNK_CALLSITEOBJ:
2895 NodeVector raw(cx);
2896 if (!raw.reserve(pn->pn_head->pn_count))
2897 return false;
2898 for (ParseNode* next = pn->pn_head->pn_head; next; next = next->pn_next) {
2899 MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2901 RootedValue expr(cx);
2902 expr.setString(next->pn_atom);
2903 raw.infallibleAppend(expr);
2906 NodeVector cooked(cx);
2907 if (!cooked.reserve(pn->pn_count - 1))
2908 return false;
2910 for (ParseNode* next = pn->pn_head->pn_next; next; next = next->pn_next) {
2911 MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2913 RootedValue expr(cx);
2914 expr.setString(next->pn_atom);
2915 cooked.infallibleAppend(expr);
2918 return builder.callSiteObj(raw, cooked, &pn->pn_pos, dst);
2921 case PNK_ARRAY:
2923 NodeVector elts(cx);
2924 if (!elts.reserve(pn->pn_count))
2925 return false;
2927 for (ParseNode* next = pn->pn_head; next; next = next->pn_next) {
2928 MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2930 if (next->isKind(PNK_ELISION)) {
2931 elts.infallibleAppend(NullValue());
2932 } else {
2933 RootedValue expr(cx);
2934 if (!expression(next, &expr))
2935 return false;
2936 elts.infallibleAppend(expr);
2940 return builder.arrayExpression(elts, &pn->pn_pos, dst);
2943 case PNK_SPREAD:
2945 RootedValue expr(cx);
2946 return expression(pn->pn_kid, &expr) &&
2947 builder.spreadExpression(expr, &pn->pn_pos, dst);
2950 case PNK_COMPUTED_NAME:
2952 RootedValue name(cx);
2953 return expression(pn->pn_kid, &name) &&
2954 builder.computedName(name, &pn->pn_pos, dst);
2957 case PNK_OBJECT:
2959 NodeVector elts(cx);
2960 if (!elts.reserve(pn->pn_count))
2961 return false;
2963 for (ParseNode* next = pn->pn_head; next; next = next->pn_next) {
2964 MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2966 RootedValue prop(cx);
2967 if (!property(next, &prop))
2968 return false;
2969 elts.infallibleAppend(prop);
2972 return builder.objectExpression(elts, &pn->pn_pos, dst);
2975 case PNK_NAME:
2976 return identifier(pn, dst);
2978 case PNK_THIS:
2979 return builder.thisExpression(&pn->pn_pos, dst);
2981 case PNK_TEMPLATE_STRING_LIST:
2983 NodeVector elts(cx);
2984 if (!elts.reserve(pn->pn_count))
2985 return false;
2987 for (ParseNode* next = pn->pn_head; next; next = next->pn_next) {
2988 MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
2990 RootedValue expr(cx);
2991 if (!expression(next, &expr))
2992 return false;
2993 elts.infallibleAppend(expr);
2996 return builder.templateLiteral(elts, &pn->pn_pos, dst);
2999 case PNK_TEMPLATE_STRING:
3000 case PNK_STRING:
3001 case PNK_REGEXP:
3002 case PNK_NUMBER:
3003 case PNK_TRUE:
3004 case PNK_FALSE:
3005 case PNK_NULL:
3006 return literal(pn, dst);
3008 case PNK_YIELD_STAR:
3010 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
3012 RootedValue arg(cx);
3013 return expression(pn->pn_left, &arg) &&
3014 builder.yieldExpression(arg, Delegating, &pn->pn_pos, dst);
3017 case PNK_YIELD:
3019 MOZ_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos));
3021 RootedValue arg(cx);
3022 return optExpression(pn->pn_left, &arg) &&
3023 builder.yieldExpression(arg, NotDelegating, &pn->pn_pos, dst);
3026 case PNK_ARRAYCOMP:
3027 MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_head->pn_pos));
3029 /* NB: it's no longer the case that pn_count could be 2. */
3030 LOCAL_ASSERT(pn->pn_count == 1);
3031 return comprehension(pn->pn_head, dst);
3033 case PNK_LET:
3034 return let(pn, true, dst);
3036 default:
3037 LOCAL_NOT_REACHED("unexpected expression type");
3041 bool
3042 ASTSerializer::propertyName(ParseNode* pn, MutableHandleValue dst)
3044 if (pn->isKind(PNK_COMPUTED_NAME))
3045 return expression(pn, dst);
3046 if (pn->isKind(PNK_NAME))
3047 return identifier(pn, dst);
3049 LOCAL_ASSERT(pn->isKind(PNK_STRING) || pn->isKind(PNK_NUMBER));
3051 return literal(pn, dst);
3054 bool
3055 ASTSerializer::property(ParseNode* pn, MutableHandleValue dst)
3057 if (pn->isKind(PNK_MUTATEPROTO)) {
3058 RootedValue val(cx);
3059 return expression(pn->pn_kid, &val) &&
3060 builder.prototypeMutation(val, &pn->pn_pos, dst);
3063 PropKind kind;
3064 switch (pn->getOp()) {
3065 case JSOP_INITPROP:
3066 kind = PROP_INIT;
3067 break;
3069 case JSOP_INITPROP_GETTER:
3070 kind = PROP_GETTER;
3071 break;
3073 case JSOP_INITPROP_SETTER:
3074 kind = PROP_SETTER;
3075 break;
3077 default:
3078 LOCAL_NOT_REACHED("unexpected object-literal property");
3081 bool isShorthand = pn->isKind(PNK_SHORTHAND);
3082 bool isMethod = pn->pn_right->isKind(PNK_FUNCTION) && kind == PROP_INIT;
3083 RootedValue key(cx), val(cx);
3084 return propertyName(pn->pn_left, &key) &&
3085 expression(pn->pn_right, &val) &&
3086 builder.propertyInitializer(key, val, kind, isShorthand, isMethod, &pn->pn_pos, dst);
3089 bool
3090 ASTSerializer::literal(ParseNode* pn, MutableHandleValue dst)
3092 RootedValue val(cx);
3093 switch (pn->getKind()) {
3094 case PNK_TEMPLATE_STRING:
3095 case PNK_STRING:
3096 val.setString(pn->pn_atom);
3097 break;
3099 case PNK_REGEXP:
3101 RootedObject re1(cx, pn->as<RegExpLiteral>().objbox()->object);
3102 LOCAL_ASSERT(re1 && re1->is<RegExpObject>());
3104 RootedObject re2(cx, CloneRegExpObject(cx, re1));
3105 if (!re2)
3106 return false;
3108 val.setObject(*re2);
3109 break;
3112 case PNK_NUMBER:
3113 val.setNumber(pn->pn_dval);
3114 break;
3116 case PNK_NULL:
3117 val.setNull();
3118 break;
3120 case PNK_TRUE:
3121 val.setBoolean(true);
3122 break;
3124 case PNK_FALSE:
3125 val.setBoolean(false);
3126 break;
3128 default:
3129 LOCAL_NOT_REACHED("unexpected literal type");
3132 return builder.literal(val, &pn->pn_pos, dst);
3135 bool
3136 ASTSerializer::arrayPattern(ParseNode* pn, MutableHandleValue dst)
3138 MOZ_ASSERT(pn->isKind(PNK_ARRAY));
3140 NodeVector elts(cx);
3141 if (!elts.reserve(pn->pn_count))
3142 return false;
3144 for (ParseNode* next = pn->pn_head; next; next = next->pn_next) {
3145 if (next->isKind(PNK_ELISION)) {
3146 elts.infallibleAppend(NullValue());
3147 } else if (next->isKind(PNK_SPREAD)) {
3148 RootedValue target(cx);
3149 RootedValue spread(cx);
3150 if (!pattern(next->pn_kid, &target))
3151 return false;
3152 if(!builder.spreadExpression(target, &next->pn_pos, &spread))
3153 return false;
3154 elts.infallibleAppend(spread);
3155 } else {
3156 RootedValue patt(cx);
3157 if (!pattern(next, &patt))
3158 return false;
3159 elts.infallibleAppend(patt);
3163 return builder.arrayPattern(elts, &pn->pn_pos, dst);
3166 bool
3167 ASTSerializer::objectPattern(ParseNode* pn, MutableHandleValue dst)
3169 MOZ_ASSERT(pn->isKind(PNK_OBJECT));
3171 NodeVector elts(cx);
3172 if (!elts.reserve(pn->pn_count))
3173 return false;
3175 for (ParseNode* propdef = pn->pn_head; propdef; propdef = propdef->pn_next) {
3176 LOCAL_ASSERT(propdef->isKind(PNK_MUTATEPROTO) != propdef->isOp(JSOP_INITPROP));
3178 RootedValue key(cx);
3179 ParseNode* target;
3180 if (propdef->isKind(PNK_MUTATEPROTO)) {
3181 RootedValue pname(cx, StringValue(cx->names().proto));
3182 if (!builder.literal(pname, &propdef->pn_pos, &key))
3183 return false;
3184 target = propdef->pn_kid;
3185 } else {
3186 if (!propertyName(propdef->pn_left, &key))
3187 return false;
3188 target = propdef->pn_right;
3191 RootedValue patt(cx), prop(cx);
3192 if (!pattern(target, &patt) ||
3193 !builder.propertyPattern(key, patt, propdef->isKind(PNK_SHORTHAND), &propdef->pn_pos,
3194 &prop))
3196 return false;
3199 elts.infallibleAppend(prop);
3202 return builder.objectPattern(elts, &pn->pn_pos, dst);
3205 bool
3206 ASTSerializer::pattern(ParseNode* pn, MutableHandleValue dst)
3208 JS_CHECK_RECURSION(cx, return false);
3209 switch (pn->getKind()) {
3210 case PNK_OBJECT:
3211 return objectPattern(pn, dst);
3213 case PNK_ARRAY:
3214 return arrayPattern(pn, dst);
3216 default:
3217 return expression(pn, dst);
3221 bool
3222 ASTSerializer::identifier(HandleAtom atom, TokenPos* pos, MutableHandleValue dst)
3224 RootedValue atomContentsVal(cx, unrootedAtomContents(atom));
3225 return builder.identifier(atomContentsVal, pos, dst);
3228 bool
3229 ASTSerializer::identifier(ParseNode* pn, MutableHandleValue dst)
3231 LOCAL_ASSERT(pn->isArity(PN_NAME) || pn->isArity(PN_NULLARY));
3232 LOCAL_ASSERT(pn->pn_atom);
3234 RootedAtom pnAtom(cx, pn->pn_atom);
3235 return identifier(pnAtom, &pn->pn_pos, dst);
3238 bool
3239 ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst)
3241 RootedFunction func(cx, pn->pn_funbox->function());
3243 // FIXME: Provide more information (legacy generator vs star generator).
3244 bool isGenerator = pn->pn_funbox->isGenerator();
3246 bool isExpression =
3247 #if JS_HAS_EXPR_CLOSURES
3248 func->isExprClosure();
3249 #else
3250 false;
3251 #endif
3253 RootedValue id(cx);
3254 RootedAtom funcAtom(cx, func->atom());
3255 if (!optIdentifier(funcAtom, nullptr, &id))
3256 return false;
3258 NodeVector args(cx);
3259 NodeVector defaults(cx);
3261 RootedValue body(cx), rest(cx);
3262 if (func->hasRest())
3263 rest.setUndefined();
3264 else
3265 rest.setNull();
3266 return functionArgsAndBody(pn->pn_body, args, defaults, &body, &rest) &&
3267 builder.function(type, &pn->pn_pos, id, args, defaults, body,
3268 rest, isGenerator, isExpression, dst);
3271 bool
3272 ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector& defaults,
3273 MutableHandleValue body, MutableHandleValue rest)
3275 ParseNode* pnargs;
3276 ParseNode* pnbody;
3278 /* Extract the args and body separately. */
3279 if (pn->isKind(PNK_ARGSBODY)) {
3280 pnargs = pn;
3281 pnbody = pn->last();
3282 } else {
3283 pnargs = nullptr;
3284 pnbody = pn;
3287 ParseNode* pndestruct;
3289 /* Extract the destructuring assignments. */
3290 if (pnbody->isArity(PN_LIST) && (pnbody->pn_xflags & PNX_DESTRUCT)) {
3291 ParseNode* head = pnbody->pn_head;
3292 LOCAL_ASSERT(head && head->isKind(PNK_SEMI));
3294 pndestruct = head->pn_kid;
3295 LOCAL_ASSERT(pndestruct);
3296 LOCAL_ASSERT(pndestruct->isKind(PNK_VAR));
3297 } else {
3298 pndestruct = nullptr;
3301 /* Serialize the arguments and body. */
3302 switch (pnbody->getKind()) {
3303 case PNK_RETURN: /* expression closure, no destructured args */
3304 return functionArgs(pn, pnargs, nullptr, pnbody, args, defaults, rest) &&
3305 expression(pnbody->pn_left, body);
3307 case PNK_SEQ: /* expression closure with destructured args */
3309 ParseNode* pnstart = pnbody->pn_head->pn_next;
3310 LOCAL_ASSERT(pnstart && pnstart->isKind(PNK_RETURN));
3312 return functionArgs(pn, pnargs, pndestruct, pnbody, args, defaults, rest) &&
3313 expression(pnstart->pn_left, body);
3316 case PNK_STATEMENTLIST: /* statement closure */
3318 ParseNode* pnstart = (pnbody->pn_xflags & PNX_DESTRUCT)
3319 ? pnbody->pn_head->pn_next
3320 : pnbody->pn_head;
3322 // Skip over initial yield in generator.
3323 if (pnstart && pnstart->isKind(PNK_YIELD)) {
3324 MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD);
3325 pnstart = pnstart->pn_next;
3328 return functionArgs(pn, pnargs, pndestruct, pnbody, args, defaults, rest) &&
3329 functionBody(pnstart, &pnbody->pn_pos, body);
3332 default:
3333 LOCAL_NOT_REACHED("unexpected function contents");
3337 bool
3338 ASTSerializer::functionArgs(ParseNode* pn, ParseNode* pnargs, ParseNode* pndestruct,
3339 ParseNode* pnbody, NodeVector& args, NodeVector& defaults,
3340 MutableHandleValue rest)
3342 uint32_t i = 0;
3343 ParseNode* arg = pnargs ? pnargs->pn_head : nullptr;
3344 ParseNode* destruct = pndestruct ? pndestruct->pn_head : nullptr;
3345 RootedValue node(cx);
3348 * Arguments are found in potentially two different places: 1) the
3349 * argsbody sequence (which ends with the body node), or 2) a
3350 * destructuring initialization at the beginning of the body. Loop
3351 * |arg| through the argsbody and |destruct| through the initial
3352 * destructuring assignments, stopping only when we've exhausted
3353 * both.
3355 while ((arg && arg != pnbody) || destruct) {
3356 if (destruct && destruct->pn_right->frameSlot() == i) {
3357 if (!pattern(destruct->pn_left, &node) || !args.append(node))
3358 return false;
3359 destruct = destruct->pn_next;
3360 } else if (arg && arg != pnbody) {
3362 * We don't check that arg->frameSlot() == i since we
3363 * can't call that method if the arg def has been turned
3364 * into a use, e.g.:
3366 * function(a) { function a() { } }
3368 * There's no other way to ask a non-destructuring arg its
3369 * index in the formals list, so we rely on the ability to
3370 * ask destructuring args their index above.
3372 MOZ_ASSERT(arg->isKind(PNK_NAME) || arg->isKind(PNK_ASSIGN));
3373 ParseNode* argName = arg->isKind(PNK_NAME) ? arg : arg->pn_left;
3374 if (!identifier(argName, &node))
3375 return false;
3376 if (rest.isUndefined() && arg->pn_next == pnbody)
3377 rest.setObject(node.toObject());
3378 else if (!args.append(node))
3379 return false;
3380 if (arg->pn_dflags & PND_DEFAULT) {
3381 ParseNode* expr = arg->expr();
3382 RootedValue def(cx);
3383 if (!expression(expr, &def) || !defaults.append(def))
3384 return false;
3386 arg = arg->pn_next;
3387 } else {
3388 LOCAL_NOT_REACHED("missing function argument");
3390 ++i;
3392 MOZ_ASSERT(!rest.isUndefined());
3394 return true;
3397 bool
3398 ASTSerializer::functionBody(ParseNode* pn, TokenPos* pos, MutableHandleValue dst)
3400 NodeVector elts(cx);
3402 /* We aren't sure how many elements there are up front, so we'll check each append. */
3403 for (ParseNode* next = pn; next; next = next->pn_next) {
3404 RootedValue child(cx);
3405 if (!sourceElement(next, &child) || !elts.append(child))
3406 return false;
3409 return builder.blockStatement(elts, pos, dst);
3412 static bool
3413 reflect_parse(JSContext* cx, uint32_t argc, jsval* vp)
3415 CallArgs args = CallArgsFromVp(argc, vp);
3417 if (args.length() < 1) {
3418 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
3419 "Reflect.parse", "0", "s");
3420 return false;
3423 RootedString src(cx, ToString<CanGC>(cx, args[0]));
3424 if (!src)
3425 return false;
3427 ScopedJSFreePtr<char> filename;
3428 uint32_t lineno = 1;
3429 bool loc = true;
3431 RootedObject builder(cx);
3433 RootedValue arg(cx, args.get(1));
3435 if (!arg.isNullOrUndefined()) {
3436 if (!arg.isObject()) {
3437 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
3438 JSDVG_SEARCH_STACK, arg, js::NullPtr(),
3439 "not an object", nullptr);
3440 return false;
3443 RootedObject config(cx, &arg.toObject());
3445 RootedValue prop(cx);
3447 /* config.loc */
3448 RootedId locId(cx, NameToId(cx->names().loc));
3449 RootedValue trueVal(cx, BooleanValue(true));
3450 if (!GetPropertyDefault(cx, config, locId, trueVal, &prop))
3451 return false;
3453 loc = ToBoolean(prop);
3455 if (loc) {
3456 /* config.source */
3457 RootedId sourceId(cx, NameToId(cx->names().source));
3458 RootedValue nullVal(cx, NullValue());
3459 if (!GetPropertyDefault(cx, config, sourceId, nullVal, &prop))
3460 return false;
3462 if (!prop.isNullOrUndefined()) {
3463 RootedString str(cx, ToString<CanGC>(cx, prop));
3464 if (!str)
3465 return false;
3467 filename = JS_EncodeString(cx, str);
3468 if (!filename)
3469 return false;
3472 /* config.line */
3473 RootedId lineId(cx, NameToId(cx->names().line));
3474 RootedValue oneValue(cx, Int32Value(1));
3475 if (!GetPropertyDefault(cx, config, lineId, oneValue, &prop) ||
3476 !ToUint32(cx, prop, &lineno)) {
3477 return false;
3481 /* config.builder */
3482 RootedId builderId(cx, NameToId(cx->names().builder));
3483 RootedValue nullVal(cx, NullValue());
3484 if (!GetPropertyDefault(cx, config, builderId, nullVal, &prop))
3485 return false;
3487 if (!prop.isNullOrUndefined()) {
3488 if (!prop.isObject()) {
3489 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
3490 JSDVG_SEARCH_STACK, prop, js::NullPtr(),
3491 "not an object", nullptr);
3492 return false;
3494 builder = &prop.toObject();
3498 /* Extract the builder methods first to report errors before parsing. */
3499 ASTSerializer serialize(cx, loc, filename, lineno);
3500 if (!serialize.init(builder))
3501 return false;
3503 JSFlatString* flat = src->ensureFlat(cx);
3504 if (!flat)
3505 return false;
3507 AutoStableStringChars flatChars(cx);
3508 if (!flatChars.initTwoByte(cx, flat))
3509 return false;
3511 CompileOptions options(cx);
3512 options.setFileAndLine(filename, lineno);
3513 options.setCanLazilyParse(false);
3514 mozilla::Range<const char16_t> chars = flatChars.twoByteRange();
3515 Parser<FullParseHandler> parser(cx, &cx->tempLifoAlloc(), options, chars.start().get(),
3516 chars.length(), /* foldConstants = */ false, nullptr, nullptr);
3517 if (!parser.checkOptions())
3518 return false;
3520 serialize.setParser(&parser);
3522 ParseNode* pn = parser.parse(nullptr);
3523 if (!pn)
3524 return false;
3526 RootedValue val(cx);
3527 if (!serialize.program(pn, &val)) {
3528 args.rval().setNull();
3529 return false;
3532 args.rval().set(val);
3533 return true;
3536 JS_PUBLIC_API(JSObject*)
3537 JS_InitReflect(JSContext* cx, HandleObject obj)
3539 static const JSFunctionSpec static_methods[] = {
3540 JS_FN("parse", reflect_parse, 1, 0),
3541 JS_FS_END
3544 RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx));
3545 if (!proto)
3546 return nullptr;
3547 RootedPlainObject Reflect(cx, NewObjectWithGivenProto<PlainObject>(cx, proto, obj,
3548 SingletonObject));
3549 if (!Reflect)
3550 return nullptr;
3552 if (!JS_DefineProperty(cx, obj, "Reflect", Reflect, 0,
3553 JS_STUBGETTER, JS_STUBSETTER)) {
3554 return nullptr;
3557 if (!JS_DefineFunctions(cx, Reflect, static_methods))
3558 return nullptr;
3560 return Reflect;