1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=99 ft=cpp:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
20 * The Initial Developer of the Original Code is
21 * the Mozilla Corporation.
24 * Dave Herman <dherman@mozilla.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
41 * JS reflection package.
44 #include <string.h> /* for jsparse.h */
48 #include "jsreflect.h"
49 #include "jscntxt.h" /* for jsparse.h */
50 #include "jsbit.h" /* for jsparse.h */
51 #include "jsscript.h" /* for jsparse.h */
52 #include "jsinterp.h" /* for jsparse.h */
63 #include "jsobjinlines.h"
68 #include "jsscriptinlines.h"
74 char const *aopNames[] = {
83 ">>>=", /* AOP_URSH */
85 "^=", /* AOP_BITXOR */
89 char const *binopNames[] = {
92 "===", /* BINOP_STRICTEQ */
93 "!==", /* BINOP_STRICTNE */
100 ">>>", /* BINOP_URSH */
101 "+", /* BINOP_PLUS */
102 "-", /* BINOP_MINUS */
103 "*", /* BINOP_STAR */
106 "|", /* BINOP_BITOR */
107 "^", /* BINOP_BITXOR */
108 "&", /* BINOP_BITAND */
110 "instanceof", /* BINOP_INSTANCEOF */
111 "..", /* BINOP_DBLDOT */
114 char const *unopNames[] = {
115 "delete", /* UNOP_DELETE */
119 "~", /* UNOP_BITNOT */
120 "typeof", /* UNOP_TYPEOF */
121 "void" /* UNOP_VOID */
124 char const *nodeTypeNames[] = {
125 #define ASTDEF(ast, str, method) str,
131 char const *callbackNames[] = {
132 #define ASTDEF(ast, str, method) method,
138 typedef AutoValueVector NodeVector;
141 * JSParseNode is a somewhat intricate data structure, and its invariants have
142 * evolved, making it more likely that there could be a disconnect between the
143 * parser and the AST serializer. We use these macros to check invariants on a
144 * parse node and raise a dynamic error on failure.
146 #define LOCAL_ASSERT(expr) \
150 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PARSE_NODE); \
155 #define LOCAL_NOT_REACHED(expr) \
157 JS_NOT_REACHED(expr); \
158 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PARSE_NODE); \
164 * Builder class that constructs JavaScript AST node objects. See:
166 * https://developer.mozilla.org/en/SpiderMonkey/Parser_API
168 * Bug 569487: generalize builder interface
173 bool saveLoc; /* save source location information? */
174 char const *src; /* source filename or null */
175 Value srcval; /* source filename JS value or null */
176 Value callbacks[AST_LIMIT]; /* user-specified callbacks */
177 Value userv; /* user-specified builder object or null */
180 NodeBuilder(JSContext *c, bool l, char const *s)
181 : cx(c), saveLoc(l), src(s) {
184 bool init(JSObject *userobj = NULL) {
186 if (!atomValue(src, &srcval))
194 for (uintN i = 0; i < AST_LIMIT; i++) {
195 callbacks[i].setNull();
200 userv.setObject(*userobj);
202 for (uintN i = 0; i < AST_LIMIT; i++) {
205 const char *name = callbackNames[i];
206 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
207 if (!atom || !GetPropertyDefault(cx, userobj, ATOM_TO_JSID(atom), NullValue(), &funv))
210 if (funv.isNullOrUndefined()) {
211 callbacks[i].setNull();
215 if (!funv.isObject() || !funv.toObject().isFunction()) {
216 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NOT_FUNCTION,
217 JSDVG_SEARCH_STACK, funv, NULL, NULL, NULL);
228 bool callback(Value fun, TokenPos *pos, Value *dst) {
231 if (!newNodeLoc(pos, &loc))
233 Value argv[] = { loc };
234 return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
237 Value argv[] = { NullValue() }; /* no zero-length arrays allowed! */
238 return ExternalInvoke(cx, userv, fun, 0, argv, dst);
241 bool callback(Value fun, Value v1, TokenPos *pos, Value *dst) {
244 if (!newNodeLoc(pos, &loc))
246 Value argv[] = { v1, loc };
247 return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
250 Value argv[] = { v1 };
251 return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
254 bool callback(Value fun, Value v1, Value v2, TokenPos *pos, Value *dst) {
257 if (!newNodeLoc(pos, &loc))
259 Value argv[] = { v1, v2, loc };
260 return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
263 Value argv[] = { v1, v2 };
264 return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
267 bool callback(Value fun, Value v1, Value v2, Value v3, TokenPos *pos, Value *dst) {
270 if (!newNodeLoc(pos, &loc))
272 Value argv[] = { v1, v2, v3, loc };
273 return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
276 Value argv[] = { v1, v2, v3 };
277 return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
280 bool callback(Value fun, Value v1, Value v2, Value v3, Value v4, TokenPos *pos, Value *dst) {
283 if (!newNodeLoc(pos, &loc))
285 Value argv[] = { v1, v2, v3, v4, loc };
286 return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
289 Value argv[] = { v1, v2, v3, v4 };
290 return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
293 bool callback(Value fun, Value v1, Value v2, Value v3, Value v4, Value v5,
294 TokenPos *pos, Value *dst) {
297 if (!newNodeLoc(pos, &loc))
299 Value argv[] = { v1, v2, v3, v4, v5, loc };
300 return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
303 Value argv[] = { v1, v2, v3, v4, v5 };
304 return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
308 JS_ASSERT_IF(v.isMagic(), v.whyMagic() == JS_SERIALIZE_NO_NODE);
309 return v.isMagic(JS_SERIALIZE_NO_NODE) ? UndefinedValue() : v;
312 bool atomValue(const char *s, Value *dst) {
314 * Bug 575416: instead of js_Atomize, lookup constant atoms in tbl file
316 JSAtom *atom = js_Atomize(cx, s, strlen(s), 0);
320 *dst = Valueify(ATOM_TO_JSVAL(atom));
324 bool newObject(JSObject **dst) {
325 JSObject *nobj = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, NULL, NULL);
333 bool newArray(NodeVector &elts, Value *dst);
335 bool newNode(ASTType type, TokenPos *pos, JSObject **dst);
337 bool newNode(ASTType type, TokenPos *pos, Value *dst) {
339 return newNode(type, pos, &node) &&
340 setResult(node, dst);
343 bool newNode(ASTType type, TokenPos *pos, const char *childName, Value child, Value *dst) {
345 return newNode(type, pos, &node) &&
346 setProperty(node, childName, child) &&
347 setResult(node, dst);
350 bool newNode(ASTType type, TokenPos *pos,
351 const char *childName1, Value child1,
352 const char *childName2, Value child2,
355 return newNode(type, pos, &node) &&
356 setProperty(node, childName1, child1) &&
357 setProperty(node, childName2, child2) &&
358 setResult(node, dst);
361 bool newNode(ASTType type, TokenPos *pos,
362 const char *childName1, Value child1,
363 const char *childName2, Value child2,
364 const char *childName3, Value child3,
367 return newNode(type, pos, &node) &&
368 setProperty(node, childName1, child1) &&
369 setProperty(node, childName2, child2) &&
370 setProperty(node, childName3, child3) &&
371 setResult(node, dst);
374 bool newNode(ASTType type, TokenPos *pos,
375 const char *childName1, Value child1,
376 const char *childName2, Value child2,
377 const char *childName3, Value child3,
378 const char *childName4, Value child4,
381 return newNode(type, pos, &node) &&
382 setProperty(node, childName1, child1) &&
383 setProperty(node, childName2, child2) &&
384 setProperty(node, childName3, child3) &&
385 setProperty(node, childName4, child4) &&
386 setResult(node, dst);
389 bool newNode(ASTType type, TokenPos *pos,
390 const char *childName1, Value child1,
391 const char *childName2, Value child2,
392 const char *childName3, Value child3,
393 const char *childName4, Value child4,
394 const char *childName5, Value child5,
397 return newNode(type, pos, &node) &&
398 setProperty(node, childName1, child1) &&
399 setProperty(node, childName2, child2) &&
400 setProperty(node, childName3, child3) &&
401 setProperty(node, childName4, child4) &&
402 setProperty(node, childName5, child5) &&
403 setResult(node, dst);
406 bool listNode(ASTType type, const char *propName, NodeVector &elts, TokenPos *pos, Value *dst) {
408 if (!newArray(elts, &array))
411 Value cb = callbacks[type];
413 return callback(cb, array, pos, dst);
415 return newNode(type, pos, propName, array, dst);
418 bool setProperty(JSObject *obj, const char *name, Value val) {
419 JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
421 /* Represent "no node" as null and ensure users are not exposed to magic values. */
422 if (val.isMagic(JS_SERIALIZE_NO_NODE))
426 * Bug 575416: instead of js_Atomize, lookup constant atoms in tbl file
428 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
432 return obj->defineProperty(cx, ATOM_TO_JSID(atom), val);
435 bool newNodeLoc(TokenPos *pos, Value *dst);
437 bool setNodeLoc(JSObject *obj, TokenPos *pos);
439 bool setResult(JSObject *obj, Value *dst) {
441 dst->setObject(*obj);
447 * All of the public builder methods take as their last two
448 * arguments a nullable token position and a non-nullable, rooted
451 * All Value arguments are rooted. Any Value arguments representing
452 * optional subnodes may be a JS_SERIALIZE_NO_NODE magic value.
459 bool program(NodeVector &elts, TokenPos *pos, Value *dst);
461 bool literal(Value val, TokenPos *pos, Value *dst);
463 bool identifier(Value name, TokenPos *pos, Value *dst);
465 bool function(ASTType type, TokenPos *pos,
466 Value id, NodeVector &args, Value body,
467 bool isGenerator, bool isExpression, Value *dst);
469 bool variableDeclarator(Value id, Value init, TokenPos *pos, Value *dst);
471 bool switchCase(Value expr, NodeVector &elts, TokenPos *pos, Value *dst);
473 bool catchClause(Value var, Value guard, Value body, TokenPos *pos, Value *dst);
475 bool propertyInitializer(Value key, Value val, PropKind kind, TokenPos *pos, Value *dst);
482 bool blockStatement(NodeVector &elts, TokenPos *pos, Value *dst);
484 bool expressionStatement(Value expr, TokenPos *pos, Value *dst);
486 bool emptyStatement(TokenPos *pos, Value *dst);
488 bool ifStatement(Value test, Value cons, Value alt, TokenPos *pos, Value *dst);
490 bool breakStatement(Value label, TokenPos *pos, Value *dst);
492 bool continueStatement(Value label, TokenPos *pos, Value *dst);
494 bool labeledStatement(Value label, Value stmt, TokenPos *pos, Value *dst);
496 bool throwStatement(Value arg, TokenPos *pos, Value *dst);
498 bool returnStatement(Value arg, TokenPos *pos, Value *dst);
500 bool forStatement(Value init, Value test, Value update, Value stmt,
501 TokenPos *pos, Value *dst);
503 bool forInStatement(Value var, Value expr, Value stmt,
504 bool isForEach, TokenPos *pos, Value *dst);
506 bool withStatement(Value expr, Value stmt, TokenPos *pos, Value *dst);
508 bool whileStatement(Value test, Value stmt, TokenPos *pos, Value *dst);
510 bool doWhileStatement(Value stmt, Value test, TokenPos *pos, Value *dst);
512 bool switchStatement(Value disc, NodeVector &elts, bool lexical, TokenPos *pos, Value *dst);
514 bool tryStatement(Value body, NodeVector &catches, Value finally, TokenPos *pos, Value *dst);
516 bool debuggerStatement(TokenPos *pos, Value *dst);
518 bool letStatement(NodeVector &head, Value stmt, TokenPos *pos, Value *dst);
524 bool binaryExpression(BinaryOperator op, Value left, Value right, TokenPos *pos, Value *dst);
526 bool unaryExpression(UnaryOperator op, Value expr, TokenPos *pos, Value *dst);
528 bool assignmentExpression(AssignmentOperator op, Value lhs, Value rhs,
529 TokenPos *pos, Value *dst);
531 bool updateExpression(Value expr, bool incr, bool prefix, TokenPos *pos, Value *dst);
533 bool logicalExpression(bool lor, Value left, Value right, TokenPos *pos, Value *dst);
535 bool conditionalExpression(Value test, Value cons, Value alt, TokenPos *pos, Value *dst);
537 bool sequenceExpression(NodeVector &elts, TokenPos *pos, Value *dst);
539 bool newExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst);
541 bool callExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst);
543 bool memberExpression(bool computed, Value expr, Value member, TokenPos *pos, Value *dst);
545 bool arrayExpression(NodeVector &elts, TokenPos *pos, Value *dst);
547 bool objectExpression(NodeVector &elts, TokenPos *pos, Value *dst);
549 bool thisExpression(TokenPos *pos, Value *dst);
551 bool yieldExpression(Value arg, TokenPos *pos, Value *dst);
553 bool comprehensionBlock(Value patt, Value src, bool isForEach, TokenPos *pos, Value *dst);
555 bool comprehensionExpression(Value body, NodeVector &blocks, Value filter,
556 TokenPos *pos, Value *dst);
558 bool generatorExpression(Value body, NodeVector &blocks, Value filter,
559 TokenPos *pos, Value *dst);
561 bool graphExpression(jsint idx, Value expr, TokenPos *pos, Value *dst);
563 bool graphIndexExpression(jsint idx, TokenPos *pos, Value *dst);
565 bool letExpression(NodeVector &head, Value expr, TokenPos *pos, Value *dst);
571 bool variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos, Value *dst);
577 bool arrayPattern(NodeVector &elts, TokenPos *pos, Value *dst);
579 bool objectPattern(NodeVector &elts, TokenPos *pos, Value *dst);
581 bool propertyPattern(Value key, Value patt, TokenPos *pos, Value *dst);
587 bool xmlAnyName(TokenPos *pos, Value *dst);
589 bool xmlEscapeExpression(Value expr, TokenPos *pos, Value *dst);
591 bool xmlDefaultNamespace(Value ns, TokenPos *pos, Value *dst);
593 bool xmlFilterExpression(Value left, Value right, TokenPos *pos, Value *dst);
595 bool xmlAttributeSelector(Value expr, TokenPos *pos, Value *dst);
597 bool xmlQualifiedIdentifier(Value left, Value right, bool computed, TokenPos *pos, Value *dst);
599 bool xmlFunctionQualifiedIdentifier(Value right, bool computed, TokenPos *pos, Value *dst);
601 bool xmlElement(NodeVector &elts, TokenPos *pos, Value *dst);
603 bool xmlText(Value text, TokenPos *pos, Value *dst);
605 bool xmlList(NodeVector &elts, TokenPos *pos, Value *dst);
607 bool xmlStartTag(NodeVector &elts, TokenPos *pos, Value *dst);
609 bool xmlEndTag(NodeVector &elts, TokenPos *pos, Value *dst);
611 bool xmlPointTag(NodeVector &elts, TokenPos *pos, Value *dst);
613 bool xmlName(Value text, TokenPos *pos, Value *dst);
615 bool xmlName(NodeVector &elts, TokenPos *pos, Value *dst);
617 bool xmlAttribute(Value text, TokenPos *pos, Value *dst);
619 bool xmlCdata(Value text, TokenPos *pos, Value *dst);
621 bool xmlComment(Value text, TokenPos *pos, Value *dst);
623 bool xmlPI(Value target, TokenPos *pos, Value *dst);
625 bool xmlPI(Value target, Value content, TokenPos *pos, Value *dst);
629 NodeBuilder::newNode(ASTType type, TokenPos *pos, JSObject **dst)
631 JS_ASSERT(type > AST_ERROR && type < AST_LIMIT);
635 JSObject *node = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, NULL, NULL);
637 !setNodeLoc(node, pos) ||
638 !atomValue(nodeTypeNames[type], &tv) ||
639 !setProperty(node, "type", tv)) {
648 NodeBuilder::newArray(NodeVector &elts, Value *dst)
650 JSObject *array = NewDenseEmptyArray(cx);
654 const size_t len = elts.length();
655 for (size_t i = 0; i < len; i++) {
658 JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
660 /* Represent "no node" as an array hole by not adding the value. */
661 if (val.isMagic(JS_SERIALIZE_NO_NODE))
664 if (!array->setProperty(cx, INT_TO_JSID(i), &val, false))
668 dst->setObject(*array);
673 NodeBuilder::newNodeLoc(TokenPos *pos, Value *dst)
683 if (!newObject(&loc))
686 dst->setObject(*loc);
688 return newObject(&to) &&
689 setProperty(loc, "start", ObjectValue(*to)) &&
690 (tv.setNumber(pos->begin.lineno), true) &&
691 setProperty(to, "line", tv) &&
692 (tv.setNumber(pos->begin.index), true) &&
693 setProperty(to, "column", tv) &&
696 setProperty(loc, "end", ObjectValue(*to)) &&
697 (tv.setNumber(pos->end.lineno), true) &&
698 setProperty(to, "line", tv) &&
699 (tv.setNumber(pos->end.index), true) &&
700 setProperty(to, "column", tv) &&
702 setProperty(loc, "source", srcval);
706 NodeBuilder::setNodeLoc(JSObject *node, TokenPos *pos)
709 setProperty(node, "loc", NullValue());
714 return newNodeLoc(pos, &loc) &&
715 setProperty(node, "loc", loc);
719 NodeBuilder::program(NodeVector &elts, TokenPos *pos, Value *dst)
721 return listNode(AST_PROGRAM, "body", elts, pos, dst);
725 NodeBuilder::blockStatement(NodeVector &elts, TokenPos *pos, Value *dst)
727 return listNode(AST_BLOCK_STMT, "body", elts, pos, dst);
731 NodeBuilder::expressionStatement(Value expr, TokenPos *pos, Value *dst)
733 Value cb = callbacks[AST_EXPR_STMT];
735 return callback(cb, expr, pos, dst);
737 return newNode(AST_EXPR_STMT, pos, "expression", expr, dst);
741 NodeBuilder::emptyStatement(TokenPos *pos, Value *dst)
743 Value cb = callbacks[AST_EMPTY_STMT];
745 return callback(cb, pos, dst);
747 return newNode(AST_EMPTY_STMT, pos, dst);
751 NodeBuilder::ifStatement(Value test, Value cons, Value alt, TokenPos *pos, Value *dst)
753 Value cb = callbacks[AST_IF_STMT];
755 return callback(cb, test, cons, opt(alt), pos, dst);
757 return newNode(AST_IF_STMT, pos,
765 NodeBuilder::breakStatement(Value label, TokenPos *pos, Value *dst)
767 Value cb = callbacks[AST_BREAK_STMT];
769 return callback(cb, opt(label), pos, dst);
771 return newNode(AST_BREAK_STMT, pos, "label", label, dst);
775 NodeBuilder::continueStatement(Value label, TokenPos *pos, Value *dst)
777 Value cb = callbacks[AST_CONTINUE_STMT];
779 return callback(cb, opt(label), pos, dst);
781 return newNode(AST_CONTINUE_STMT, pos, "label", label, dst);
785 NodeBuilder::labeledStatement(Value label, Value stmt, TokenPos *pos, Value *dst)
787 Value cb = callbacks[AST_LAB_STMT];
789 return callback(cb, label, stmt, pos, dst);
791 return newNode(AST_LAB_STMT, pos,
798 NodeBuilder::throwStatement(Value arg, TokenPos *pos, Value *dst)
800 Value cb = callbacks[AST_THROW_STMT];
802 return callback(cb, arg, pos, dst);
804 return newNode(AST_THROW_STMT, pos, "argument", arg, dst);
808 NodeBuilder::returnStatement(Value arg, TokenPos *pos, Value *dst)
810 Value cb = callbacks[AST_RETURN_STMT];
812 return callback(cb, opt(arg), pos, dst);
814 return newNode(AST_RETURN_STMT, pos, "argument", arg, dst);
818 NodeBuilder::forStatement(Value init, Value test, Value update, Value stmt,
819 TokenPos *pos, Value *dst)
821 Value cb = callbacks[AST_FOR_STMT];
823 return callback(cb, opt(init), opt(test), opt(update), stmt, pos, dst);
825 return newNode(AST_FOR_STMT, pos,
834 NodeBuilder::forInStatement(Value var, Value expr, Value stmt, bool isForEach,
835 TokenPos *pos, Value *dst)
837 Value cb = callbacks[AST_FOR_IN_STMT];
839 return callback(cb, var, expr, stmt, BooleanValue(isForEach), pos, dst);
841 return newNode(AST_FOR_IN_STMT, pos,
845 "each", BooleanValue(isForEach),
850 NodeBuilder::withStatement(Value expr, Value stmt, TokenPos *pos, Value *dst)
852 Value cb = callbacks[AST_WITH_STMT];
854 return callback(cb, expr, stmt, pos, dst);
856 return newNode(AST_WITH_STMT, pos,
863 NodeBuilder::whileStatement(Value test, Value stmt, TokenPos *pos, Value *dst)
865 Value cb = callbacks[AST_WHILE_STMT];
867 return callback(cb, test, stmt, pos, dst);
869 return newNode(AST_WHILE_STMT, pos,
876 NodeBuilder::doWhileStatement(Value stmt, Value test, TokenPos *pos, Value *dst)
878 Value cb = callbacks[AST_DO_STMT];
880 return callback(cb, stmt, test, pos, dst);
882 return newNode(AST_DO_STMT, pos,
889 NodeBuilder::switchStatement(Value disc, NodeVector &elts, bool lexical, TokenPos *pos, Value *dst)
892 if (!newArray(elts, &array))
895 Value cb = callbacks[AST_SWITCH_STMT];
897 return callback(cb, disc, array, BooleanValue(lexical), pos, dst);
899 return newNode(AST_SWITCH_STMT, pos,
900 "discriminant", disc,
902 "lexical", BooleanValue(lexical),
907 NodeBuilder::tryStatement(Value body, NodeVector &catches, Value finally,
908 TokenPos *pos, Value *dst)
912 Value cb = callbacks[AST_TRY_STMT];
914 return newArray(catches, &handler) &&
915 callback(cb, body, handler, opt(finally), pos, dst);
918 switch (catches.length()) {
923 handler = catches[0];
926 if (!newArray(catches, &handler))
930 return newNode(AST_TRY_STMT, pos,
933 "finalizer", finally,
938 NodeBuilder::debuggerStatement(TokenPos *pos, Value *dst)
940 Value cb = callbacks[AST_DEBUGGER_STMT];
942 return callback(cb, pos, dst);
944 return newNode(AST_DEBUGGER_STMT, pos, dst);
948 NodeBuilder::binaryExpression(BinaryOperator op, Value left, Value right, TokenPos *pos, Value *dst)
950 JS_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
953 if (!atomValue(binopNames[op], &opName))
956 Value cb = callbacks[AST_BINARY_EXPR];
958 return callback(cb, opName, left, right, pos, dst);
960 return newNode(AST_BINARY_EXPR, pos,
968 NodeBuilder::unaryExpression(UnaryOperator unop, Value expr, TokenPos *pos, Value *dst)
970 JS_ASSERT(unop > UNOP_ERR && unop < UNOP_LIMIT);
973 if (!atomValue(unopNames[unop], &opName))
976 Value cb = callbacks[AST_UNARY_EXPR];
978 return callback(cb, opName, expr, pos, dst);
980 return newNode(AST_UNARY_EXPR, pos,
983 "prefix", BooleanValue(true),
988 NodeBuilder::assignmentExpression(AssignmentOperator aop, Value lhs, Value rhs,
989 TokenPos *pos, Value *dst)
991 JS_ASSERT(aop > AOP_ERR && aop < AOP_LIMIT);
994 if (!atomValue(aopNames[aop], &opName))
997 Value cb = callbacks[AST_ASSIGN_EXPR];
999 return callback(cb, opName, lhs, rhs, pos, dst);
1001 return newNode(AST_ASSIGN_EXPR, pos,
1009 NodeBuilder::updateExpression(Value expr, bool incr, bool prefix, TokenPos *pos, Value *dst)
1012 if (!atomValue(incr ? "++" : "--", &opName))
1015 Value cb = callbacks[AST_UPDATE_EXPR];
1017 return callback(cb, expr, opName, BooleanValue(prefix), pos, dst);
1019 return newNode(AST_UPDATE_EXPR, pos,
1022 "prefix", BooleanValue(prefix),
1027 NodeBuilder::logicalExpression(bool lor, Value left, Value right, TokenPos *pos, Value *dst)
1030 if (!atomValue(lor ? "||" : "&&", &opName))
1033 Value cb = callbacks[AST_LOGICAL_EXPR];
1035 return callback(cb, opName, left, right, pos, dst);
1037 return newNode(AST_LOGICAL_EXPR, pos,
1045 NodeBuilder::conditionalExpression(Value test, Value cons, Value alt, TokenPos *pos, Value *dst)
1047 Value cb = callbacks[AST_COND_EXPR];
1049 return callback(cb, test, cons, alt, pos, dst);
1051 return newNode(AST_COND_EXPR, pos,
1059 NodeBuilder::sequenceExpression(NodeVector &elts, TokenPos *pos, Value *dst)
1061 return listNode(AST_LIST_EXPR, "expressions", elts, pos, dst);
1065 NodeBuilder::callExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst)
1068 if (!newArray(args, &array))
1071 Value cb = callbacks[AST_CALL_EXPR];
1073 return callback(cb, callee, array, pos, dst);
1075 return newNode(AST_CALL_EXPR, pos,
1082 NodeBuilder::newExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst)
1085 if (!newArray(args, &array))
1088 Value cb = callbacks[AST_NEW_EXPR];
1090 return callback(cb, callee, array, pos, dst);
1092 return newNode(AST_NEW_EXPR, pos,
1099 NodeBuilder::memberExpression(bool computed, Value expr, Value member, TokenPos *pos, Value *dst)
1101 Value cb = callbacks[AST_MEMBER_EXPR];
1103 return callback(cb, BooleanValue(computed), expr, member, pos, dst);
1105 return newNode(AST_MEMBER_EXPR, pos,
1108 "computed", BooleanValue(computed),
1113 NodeBuilder::arrayExpression(NodeVector &elts, TokenPos *pos, Value *dst)
1115 return listNode(AST_ARRAY_EXPR, "elements", elts, pos, dst);
1119 NodeBuilder::propertyPattern(Value key, Value patt, TokenPos *pos, Value *dst)
1122 if (!atomValue("init", &kindName))
1125 Value cb = callbacks[AST_PROP_PATT];
1127 return callback(cb, key, patt, pos, dst);
1129 return newNode(AST_PROP_PATT, pos,
1137 NodeBuilder::propertyInitializer(Value key, Value val, PropKind kind, TokenPos *pos, Value *dst)
1140 if (!atomValue(kind == PROP_INIT
1142 : kind == PROP_GETTER
1144 : "set", &kindName)) {
1148 Value cb = callbacks[AST_PROPERTY];
1150 return callback(cb, kindName, key, val, pos, dst);
1152 return newNode(AST_PROPERTY, pos,
1160 NodeBuilder::objectExpression(NodeVector &elts, TokenPos *pos, Value *dst)
1162 return listNode(AST_OBJECT_EXPR, "properties", elts, pos, dst);
1166 NodeBuilder::thisExpression(TokenPos *pos, Value *dst)
1168 Value cb = callbacks[AST_THIS_EXPR];
1170 return callback(cb, pos, dst);
1172 return newNode(AST_THIS_EXPR, pos, dst);
1176 NodeBuilder::yieldExpression(Value arg, TokenPos *pos, Value *dst)
1178 Value cb = callbacks[AST_YIELD_EXPR];
1180 return callback(cb, opt(arg), pos, dst);
1182 return newNode(AST_YIELD_EXPR, pos, "argument", arg, dst);
1186 NodeBuilder::comprehensionBlock(Value patt, Value src, bool isForEach, TokenPos *pos, Value *dst)
1188 Value cb = callbacks[AST_COMP_BLOCK];
1190 return callback(cb, patt, src, BooleanValue(isForEach), pos, dst);
1192 return newNode(AST_COMP_BLOCK, pos,
1195 "each", BooleanValue(isForEach),
1200 NodeBuilder::comprehensionExpression(Value body, NodeVector &blocks, Value filter,
1201 TokenPos *pos, Value *dst)
1204 if (!newArray(blocks, &array))
1207 Value cb = callbacks[AST_COMP_EXPR];
1209 return callback(cb, body, array, opt(filter), pos, dst);
1211 return newNode(AST_COMP_EXPR, pos,
1219 NodeBuilder::generatorExpression(Value body, NodeVector &blocks, Value filter, TokenPos *pos, Value *dst)
1222 if (!newArray(blocks, &array))
1225 Value cb = callbacks[AST_GENERATOR_EXPR];
1227 return callback(cb, body, array, opt(filter), pos, dst);
1229 return newNode(AST_GENERATOR_EXPR, pos,
1237 NodeBuilder::graphExpression(jsint idx, Value expr, TokenPos *pos, Value *dst)
1239 Value cb = callbacks[AST_GRAPH_EXPR];
1241 return callback(cb, NumberValue(idx), pos, dst);
1243 return newNode(AST_GRAPH_EXPR, pos,
1244 "index", NumberValue(idx),
1250 NodeBuilder::graphIndexExpression(jsint idx, TokenPos *pos, Value *dst)
1252 Value cb = callbacks[AST_GRAPH_IDX_EXPR];
1254 return callback(cb, NumberValue(idx), pos, dst);
1256 return newNode(AST_GRAPH_IDX_EXPR, pos, "index", NumberValue(idx), dst);
1260 NodeBuilder::letExpression(NodeVector &head, Value expr, TokenPos *pos, Value *dst)
1263 if (!newArray(head, &array))
1266 Value cb = callbacks[AST_LET_EXPR];
1268 return callback(cb, array, expr, pos, dst);
1270 return newNode(AST_LET_EXPR, pos,
1277 NodeBuilder::letStatement(NodeVector &head, Value stmt, TokenPos *pos, Value *dst)
1280 if (!newArray(head, &array))
1283 Value cb = callbacks[AST_LET_STMT];
1285 return callback(cb, array, stmt, pos, dst);
1287 return newNode(AST_LET_STMT, pos,
1294 NodeBuilder::variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos, Value *dst)
1296 JS_ASSERT(kind > VARDECL_ERR && kind < VARDECL_LIMIT);
1298 Value array, kindName;
1299 if (!newArray(elts, &array) ||
1300 !atomValue(kind == VARDECL_CONST
1302 : kind == VARDECL_LET
1304 : "var", &kindName)) {
1308 Value cb = callbacks[AST_VAR_DECL];
1310 return callback(cb, kindName, array, pos, dst);
1312 return newNode(AST_VAR_DECL, pos,
1314 "declarations", array,
1319 NodeBuilder::variableDeclarator(Value id, Value init, TokenPos *pos, Value *dst)
1321 Value cb = callbacks[AST_VAR_DTOR];
1323 return callback(cb, id, opt(init), pos, dst);
1325 return newNode(AST_VAR_DTOR, pos, "id", id, "init", init, dst);
1329 NodeBuilder::switchCase(Value expr, NodeVector &elts, TokenPos *pos, Value *dst)
1332 if (!newArray(elts, &array))
1335 Value cb = callbacks[AST_CASE];
1337 return callback(cb, opt(expr), array, pos, dst);
1339 return newNode(AST_CASE, pos,
1341 "consequent", array,
1346 NodeBuilder::catchClause(Value var, Value guard, Value body, TokenPos *pos, Value *dst)
1348 Value cb = callbacks[AST_CATCH];
1350 return callback(cb, var, opt(guard), body, pos, dst);
1352 return newNode(AST_CATCH, pos,
1360 NodeBuilder::literal(Value val, TokenPos *pos, Value *dst)
1362 Value cb = callbacks[AST_LITERAL];
1364 return callback(cb, val, pos, dst);
1366 return newNode(AST_LITERAL, pos, "value", val, dst);
1370 NodeBuilder::identifier(Value name, TokenPos *pos, Value *dst)
1372 Value cb = callbacks[AST_IDENTIFIER];
1374 return callback(cb, name, pos, dst);
1376 return newNode(AST_IDENTIFIER, pos, "name", name, dst);
1380 NodeBuilder::objectPattern(NodeVector &elts, TokenPos *pos, Value *dst)
1382 return listNode(AST_OBJECT_PATT, "properties", elts, pos, dst);
1386 NodeBuilder::arrayPattern(NodeVector &elts, TokenPos *pos, Value *dst)
1388 return listNode(AST_ARRAY_PATT, "elements", elts, pos, dst);
1392 NodeBuilder::function(ASTType type, TokenPos *pos,
1393 Value id, NodeVector &args, Value body,
1394 bool isGenerator, bool isExpression,
1398 if (!newArray(args, &array))
1401 Value cb = callbacks[type];
1403 return callback(cb, opt(id), array, body, BooleanValue(isGenerator),
1404 BooleanValue(isExpression), pos, dst);
1407 return newNode(type, pos,
1411 "generator", BooleanValue(isGenerator),
1412 "expression", BooleanValue(isExpression),
1417 NodeBuilder::xmlAnyName(TokenPos *pos, Value *dst)
1419 Value cb = callbacks[AST_XMLANYNAME];
1421 return callback(cb, pos, dst);
1423 return newNode(AST_XMLANYNAME, pos, dst);
1427 NodeBuilder::xmlEscapeExpression(Value expr, TokenPos *pos, Value *dst)
1429 Value cb = callbacks[AST_XMLESCAPE];
1431 return callback(cb, expr, pos, dst);
1433 return newNode(AST_XMLESCAPE, pos, "expression", expr, dst);
1437 NodeBuilder::xmlFilterExpression(Value left, Value right, TokenPos *pos, Value *dst)
1439 Value cb = callbacks[AST_XMLFILTER];
1441 return callback(cb, left, right, pos, dst);
1443 return newNode(AST_XMLFILTER, pos, "left", left, "right", right, dst);
1447 NodeBuilder::xmlDefaultNamespace(Value ns, TokenPos *pos, Value *dst)
1449 Value cb = callbacks[AST_XMLDEFAULT];
1451 return callback(cb, ns, pos, dst);
1453 return newNode(AST_XMLDEFAULT, pos, "namespace", ns, dst);
1457 NodeBuilder::xmlAttributeSelector(Value expr, TokenPos *pos, Value *dst)
1459 Value cb = callbacks[AST_XMLATTR_SEL];
1461 return callback(cb, expr, pos, dst);
1463 return newNode(AST_XMLATTR_SEL, pos, "attribute", expr, dst);
1467 NodeBuilder::xmlFunctionQualifiedIdentifier(Value right, bool computed, TokenPos *pos, Value *dst)
1469 Value cb = callbacks[AST_XMLFUNCQUAL];
1471 return callback(cb, right, BooleanValue(computed), pos, dst);
1473 return newNode(AST_XMLFUNCQUAL, pos,
1475 "computed", BooleanValue(computed),
1480 NodeBuilder::xmlQualifiedIdentifier(Value left, Value right, bool computed,
1481 TokenPos *pos, Value *dst)
1483 Value cb = callbacks[AST_XMLQUAL];
1485 return callback(cb, left, right, BooleanValue(computed), pos, dst);
1487 return newNode(AST_XMLQUAL, pos,
1490 "computed", BooleanValue(computed),
1495 NodeBuilder::xmlElement(NodeVector &elts, TokenPos *pos, Value *dst)
1497 return listNode(AST_XMLELEM, "contents", elts, pos, dst);
1501 NodeBuilder::xmlText(Value text, TokenPos *pos, Value *dst)
1503 Value cb = callbacks[AST_XMLTEXT];
1505 return callback(cb, text, pos, dst);
1507 return newNode(AST_XMLTEXT, pos, "text", text, dst);
1511 NodeBuilder::xmlList(NodeVector &elts, TokenPos *pos, Value *dst)
1513 return listNode(AST_XMLLIST, "contents", elts, pos, dst);
1517 NodeBuilder::xmlStartTag(NodeVector &elts, TokenPos *pos, Value *dst)
1519 return listNode(AST_XMLSTART, "contents", elts, pos, dst);
1523 NodeBuilder::xmlEndTag(NodeVector &elts, TokenPos *pos, Value *dst)
1525 return listNode(AST_XMLEND, "contents", elts, pos, dst);
1529 NodeBuilder::xmlPointTag(NodeVector &elts, TokenPos *pos, Value *dst)
1531 return listNode(AST_XMLPOINT, "contents", elts, pos, dst);
1535 NodeBuilder::xmlName(Value text, TokenPos *pos, Value *dst)
1537 Value cb = callbacks[AST_XMLNAME];
1539 return callback(cb, text, pos, dst);
1541 return newNode(AST_XMLNAME, pos, "contents", text, dst);
1545 NodeBuilder::xmlName(NodeVector &elts, TokenPos *pos, Value *dst)
1547 return listNode(AST_XMLNAME, "contents", elts, pos ,dst);
1551 NodeBuilder::xmlAttribute(Value text, TokenPos *pos, Value *dst)
1553 Value cb = callbacks[AST_XMLATTR];
1555 return callback(cb, text, pos, dst);
1557 return newNode(AST_XMLATTR, pos, "value", text, dst);
1561 NodeBuilder::xmlCdata(Value text, TokenPos *pos, Value *dst)
1563 Value cb = callbacks[AST_XMLCDATA];
1565 return callback(cb, text, pos, dst);
1567 return newNode(AST_XMLCDATA, pos, "contents", text, dst);
1571 NodeBuilder::xmlComment(Value text, TokenPos *pos, Value *dst)
1573 Value cb = callbacks[AST_XMLCOMMENT];
1575 return callback(cb, text, pos, dst);
1577 return newNode(AST_XMLCOMMENT, pos, "contents", text, dst);
1581 NodeBuilder::xmlPI(Value target, TokenPos *pos, Value *dst)
1583 return xmlPI(target, NullValue(), pos, dst);
1587 NodeBuilder::xmlPI(Value target, Value contents, TokenPos *pos, Value *dst)
1589 Value cb = callbacks[AST_XMLPI];
1591 return callback(cb, target, contents, pos, dst);
1593 return newNode(AST_XMLPI, pos,
1595 "contents", contents,
1601 * Serialization of parse nodes to JavaScript objects.
1603 * All serialization methods take a non-nullable JSParseNode pointer.
1609 NodeBuilder builder;
1612 Value atomContents(JSAtom *atom) {
1613 return Valueify(ATOM_TO_JSVAL(atom ? atom : cx->runtime->atomState.emptyAtom));
1616 BinaryOperator binop(TokenKind tk, JSOp op);
1617 UnaryOperator unop(TokenKind tk, JSOp op);
1618 AssignmentOperator aop(JSOp op);
1620 bool statements(JSParseNode *pn, NodeVector &elts);
1621 bool expressions(JSParseNode *pn, NodeVector &elts);
1622 bool xmls(JSParseNode *pn, NodeVector &elts);
1623 bool leftAssociate(JSParseNode *pn, Value *dst);
1624 bool binaryOperands(JSParseNode *pn, NodeVector &elts);
1625 bool functionArgs(JSParseNode *pn, JSParseNode *pnargs, JSParseNode *pndestruct,
1626 JSParseNode *pnbody, NodeVector &args);
1628 bool sourceElement(JSParseNode *pn, Value *dst);
1630 bool declaration(JSParseNode *pn, Value *dst);
1631 bool variableDeclaration(JSParseNode *pn, bool let, Value *dst);
1632 bool variableDeclarator(JSParseNode *pn, VarDeclKind *pkind, Value *dst);
1633 bool letHead(JSParseNode *pn, NodeVector &dtors);
1635 bool optStatement(JSParseNode *pn, Value *dst) {
1637 dst->setMagic(JS_SERIALIZE_NO_NODE);
1640 return statement(pn, dst);
1643 bool forInit(JSParseNode *pn, Value *dst);
1644 bool statement(JSParseNode *pn, Value *dst);
1645 bool blockStatement(JSParseNode *pn, Value *dst);
1646 bool switchStatement(JSParseNode *pn, Value *dst);
1647 bool switchCase(JSParseNode *pn, Value *dst);
1648 bool tryStatement(JSParseNode *pn, Value *dst);
1649 bool catchClause(JSParseNode *pn, Value *dst);
1651 bool optExpression(JSParseNode *pn, Value *dst) {
1653 dst->setMagic(JS_SERIALIZE_NO_NODE);
1656 return expression(pn, dst);
1659 bool expression(JSParseNode *pn, Value *dst);
1661 bool propertyName(JSParseNode *pn, Value *dst);
1662 bool property(JSParseNode *pn, Value *dst);
1664 bool optIdentifier(JSAtom *atom, TokenPos *pos, Value *dst) {
1666 dst->setMagic(JS_SERIALIZE_NO_NODE);
1669 return identifier(atom, pos, dst);
1672 bool identifier(JSAtom *atom, TokenPos *pos, Value *dst);
1673 bool identifier(JSParseNode *pn, Value *dst);
1674 bool literal(JSParseNode *pn, Value *dst);
1676 bool pattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst);
1677 bool arrayPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst);
1678 bool objectPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst);
1680 bool function(JSParseNode *pn, ASTType type, Value *dst);
1681 bool functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *body);
1682 bool functionBody(JSParseNode *pn, TokenPos *pos, Value *dst);
1684 bool comprehensionBlock(JSParseNode *pn, Value *dst);
1685 bool comprehension(JSParseNode *pn, Value *dst);
1686 bool generatorExpression(JSParseNode *pn, Value *dst);
1688 bool xml(JSParseNode *pn, Value *dst);
1691 ASTSerializer(JSContext *c, bool l, char const *src, uint32 ln)
1692 : cx(c), builder(c, l, src), lineno(ln) {
1695 bool init(JSObject *userobj) {
1696 return builder.init(userobj);
1699 bool program(JSParseNode *pn, Value *dst);
1703 ASTSerializer::aop(JSOp op)
1736 ASTSerializer::unop(TokenKind tk, JSOp op)
1738 if (tk == TOK_DELETE)
1751 case JSOP_TYPEOFEXPR:
1761 ASTSerializer::binop(TokenKind tk, JSOp op)
1771 return BINOP_STRICTEQ;
1773 return BINOP_STRICTNE;
1811 return (op == JSOP_MOD) ? BINOP_MOD : BINOP_DIV;
1815 return BINOP_BITXOR;
1817 return BINOP_BITAND;
1820 case TOK_INSTANCEOF:
1821 return BINOP_INSTANCEOF;
1823 return BINOP_DBLDOT;
1830 ASTSerializer::statements(JSParseNode *pn, NodeVector &elts)
1832 JS_ASSERT(PN_TYPE(pn) == TOK_LC && pn->pn_arity == PN_LIST);
1834 if (!elts.reserve(pn->pn_count))
1837 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
1839 if (!sourceElement(next, &elt))
1841 JS_ALWAYS_TRUE(elts.append(elt)); /* space check above */
1848 ASTSerializer::expressions(JSParseNode *pn, NodeVector &elts)
1850 if (!elts.reserve(pn->pn_count))
1853 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
1855 if (!expression(next, &elt))
1857 JS_ALWAYS_TRUE(elts.append(elt)); /* space check above */
1864 ASTSerializer::xmls(JSParseNode *pn, NodeVector &elts)
1866 if (!elts.reserve(pn->pn_count))
1869 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
1871 if (!xml(next, &elt))
1873 JS_ALWAYS_TRUE(elts.append(elt)); /* space check above */
1880 ASTSerializer::blockStatement(JSParseNode *pn, Value *dst)
1882 JS_ASSERT(PN_TYPE(pn) == TOK_LC);
1884 NodeVector stmts(cx);
1885 return statements(pn, stmts) &&
1886 builder.blockStatement(stmts, &pn->pn_pos, dst);
1890 ASTSerializer::program(JSParseNode *pn, Value *dst)
1894 /* Workaround for bug 588061: parser's reported start position is always 0:0. */
1895 pn->pn_pos.begin.lineno = lineno;
1897 NodeVector stmts(cx);
1898 return statements(pn, stmts) &&
1899 builder.program(stmts, &pn->pn_pos, dst);
1903 ASTSerializer::sourceElement(JSParseNode *pn, Value *dst)
1905 /* SpiderMonkey allows declarations even in pure statement contexts. */
1906 return statement(pn, dst);
1910 ASTSerializer::declaration(JSParseNode *pn, Value *dst)
1912 JS_ASSERT(PN_TYPE(pn) == TOK_FUNCTION ||
1913 PN_TYPE(pn) == TOK_VAR ||
1914 PN_TYPE(pn) == TOK_LET);
1916 switch (PN_TYPE(pn)) {
1918 return function(pn, AST_FUNC_DECL, dst);
1921 return variableDeclaration(pn, false, dst);
1924 JS_ASSERT(PN_TYPE(pn) == TOK_LET);
1925 return variableDeclaration(pn, true, dst);
1930 ASTSerializer::variableDeclaration(JSParseNode *pn, bool let, Value *dst)
1932 JS_ASSERT(let ? PN_TYPE(pn) == TOK_LET : PN_TYPE(pn) == TOK_VAR);
1934 /* Later updated to VARDECL_CONST if we find a PND_CONST declarator. */
1935 VarDeclKind kind = let ? VARDECL_LET : VARDECL_VAR;
1937 NodeVector dtors(cx);
1938 if (!dtors.reserve(pn->pn_count))
1941 /* In a for-in context, variable declarations contain just a single pattern. */
1942 if (pn->pn_xflags & PNX_FORINVAR) {
1944 return pattern(pn->pn_head, &kind, &patt) &&
1945 builder.variableDeclarator(patt, NullValue(), &pn->pn_head->pn_pos, &child) &&
1946 dtors.append(child) &&
1947 builder.variableDeclaration(dtors, kind, &pn->pn_pos, dst);
1950 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
1952 if (!variableDeclarator(next, &kind, &child))
1954 JS_ALWAYS_TRUE(dtors.append(child)); /* space check above */
1957 return builder.variableDeclaration(dtors, kind, &pn->pn_pos, dst);
1961 ASTSerializer::variableDeclarator(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
1963 /* A destructuring declarator is always a TOK_ASSIGN. */
1964 JS_ASSERT(PN_TYPE(pn) == TOK_NAME || PN_TYPE(pn) == TOK_ASSIGN);
1966 JSParseNode *pnleft;
1967 JSParseNode *pnright;
1969 if (PN_TYPE(pn) == TOK_NAME) {
1971 pnright = pn->pn_expr;
1973 JS_ASSERT(PN_TYPE(pn) == TOK_ASSIGN);
1974 pnleft = pn->pn_left;
1975 pnright = pn->pn_right;
1979 return pattern(pnleft, pkind, &left) &&
1980 optExpression(pnright, &right) &&
1981 builder.variableDeclarator(left, right, &pn->pn_pos, dst);
1985 ASTSerializer::letHead(JSParseNode *pn, NodeVector &dtors)
1987 if (!dtors.reserve(pn->pn_count))
1990 VarDeclKind kind = VARDECL_LET_HEAD;
1992 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
1995 * Unlike in |variableDeclaration|, this does not update |kind|; since let-heads do
1996 * not contain const declarations, declarators should never have PND_CONST set.
1998 if (!variableDeclarator(next, &kind, &child))
2000 JS_ALWAYS_TRUE(dtors.append(child)); /* space check above */
2007 ASTSerializer::switchCase(JSParseNode *pn, Value *dst)
2009 NodeVector stmts(cx);
2013 return optExpression(pn->pn_left, &expr) &&
2014 statements(pn->pn_right, stmts) &&
2015 builder.switchCase(expr, stmts, &pn->pn_pos, dst);
2019 ASTSerializer::switchStatement(JSParseNode *pn, Value *dst)
2023 if (!expression(pn->pn_left, &disc))
2026 JSParseNode *listNode;
2029 if (PN_TYPE(pn->pn_right) == TOK_LEXICALSCOPE) {
2030 listNode = pn->pn_right->pn_expr;
2033 listNode = pn->pn_right;
2037 NodeVector cases(cx);
2038 if (!cases.reserve(listNode->pn_count))
2041 for (JSParseNode *next = listNode->pn_head; next; next = next->pn_next) {
2043 #ifdef __GNUC__ /* quell GCC overwarning */
2044 child = UndefinedValue();
2046 if (!switchCase(next, &child))
2048 JS_ALWAYS_TRUE(cases.append(child)); /* space check above */
2051 return builder.switchStatement(disc, cases, lexical, &pn->pn_pos, dst);
2055 ASTSerializer::catchClause(JSParseNode *pn, Value *dst)
2057 Value var, guard, body;
2059 return pattern(pn->pn_kid1, NULL, &var) &&
2060 optExpression(pn->pn_kid2, &guard) &&
2061 statement(pn->pn_kid3, &body) &&
2062 builder.catchClause(var, guard, body, &pn->pn_pos, dst);
2066 ASTSerializer::tryStatement(JSParseNode *pn, Value *dst)
2069 if (!statement(pn->pn_kid1, &body))
2072 NodeVector clauses(cx);
2074 if (!clauses.reserve(pn->pn_kid2->pn_count))
2077 for (JSParseNode *next = pn->pn_kid2->pn_head; next; next = next->pn_next) {
2079 if (!catchClause(next->pn_expr, &clause))
2081 JS_ALWAYS_TRUE(clauses.append(clause)); /* space check above */
2086 return optStatement(pn->pn_kid3, &finally) &&
2087 builder.tryStatement(body, clauses, finally, &pn->pn_pos, dst);
2091 ASTSerializer::forInit(JSParseNode *pn, Value *dst)
2094 dst->setMagic(JS_SERIALIZE_NO_NODE);
2098 return (PN_TYPE(pn) == TOK_VAR)
2099 ? variableDeclaration(pn, false, dst)
2100 : (PN_TYPE(pn) == TOK_LET)
2101 ? variableDeclaration(pn, true, dst)
2102 : expression(pn, dst);
2106 ASTSerializer::statement(JSParseNode *pn, Value *dst)
2108 switch (PN_TYPE(pn)) {
2112 return declaration(pn, dst);
2115 LOCAL_ASSERT(pn->pn_used);
2116 return statement(pn->pn_lexdef, dst);
2121 return expression(pn->pn_kid, &expr) &&
2122 builder.expressionStatement(expr, &pn->pn_pos, dst);
2124 return builder.emptyStatement(&pn->pn_pos, dst);
2126 case TOK_LEXICALSCOPE:
2128 if (PN_TYPE(pn) == TOK_LET) {
2129 NodeVector dtors(cx);
2132 return letHead(pn->pn_left, dtors) &&
2133 statement(pn->pn_right, &stmt) &&
2134 builder.letStatement(dtors, stmt, &pn->pn_pos, dst);
2137 if (PN_TYPE(pn) != TOK_LC)
2138 return statement(pn, dst);
2142 return blockStatement(pn, dst);
2146 Value test, cons, alt;
2148 return expression(pn->pn_kid1, &test) &&
2149 statement(pn->pn_kid2, &cons) &&
2150 optStatement(pn->pn_kid3, &alt) &&
2151 builder.ifStatement(test, cons, alt, &pn->pn_pos, dst);
2155 return switchStatement(pn, dst);
2158 return tryStatement(pn, dst);
2165 return expression(pn->pn_left, &expr) &&
2166 statement(pn->pn_right, &stmt) &&
2167 (PN_TYPE(pn) == TOK_WITH)
2168 ? builder.withStatement(expr, stmt, &pn->pn_pos, dst)
2169 : builder.whileStatement(expr, stmt, &pn->pn_pos, dst);
2176 return statement(pn->pn_left, &stmt) &&
2177 expression(pn->pn_right, &test) &&
2178 builder.doWhileStatement(stmt, test, &pn->pn_pos, dst);
2183 JSParseNode *head = pn->pn_left;
2186 if (!statement(pn->pn_right, &stmt))
2189 bool isForEach = pn->pn_iflags & JSITER_FOREACH;
2191 if (PN_TYPE(head) == TOK_IN) {
2194 return (PN_TYPE(head->pn_left) == TOK_VAR
2195 ? variableDeclaration(head->pn_left, false, &var)
2196 : PN_TYPE(head->pn_left) == TOK_LET
2197 ? variableDeclaration(head->pn_left, true, &var)
2198 : pattern(head->pn_left, NULL, &var)) &&
2199 expression(head->pn_right, &expr) &&
2200 builder.forInStatement(var, expr, stmt, isForEach, &pn->pn_pos, dst);
2203 Value init, test, update;
2205 return forInit(head->pn_kid1, &init) &&
2206 optExpression(head->pn_kid2, &test) &&
2207 optExpression(head->pn_kid3, &update) &&
2208 builder.forStatement(init, test, update, stmt, &pn->pn_pos, dst);
2211 /* Synthesized by the parser when a for-in loop contains a variable initializer. */
2214 LOCAL_ASSERT(pn->pn_count == 2);
2216 JSParseNode *prelude = pn->pn_head;
2217 JSParseNode *body = prelude->pn_next;
2219 LOCAL_ASSERT((PN_TYPE(prelude) == TOK_VAR && PN_TYPE(body) == TOK_FOR) ||
2220 (PN_TYPE(prelude) == TOK_SEMI && PN_TYPE(body) == TOK_LEXICALSCOPE));
2225 if (PN_TYPE(prelude) == TOK_VAR) {
2228 if (!variableDeclaration(prelude, false, &var))
2231 loop = body->pn_expr;
2233 LOCAL_ASSERT(PN_TYPE(loop->pn_left) == TOK_IN &&
2234 PN_TYPE(loop->pn_left->pn_left) == TOK_LET &&
2235 loop->pn_left->pn_left->pn_count == 1);
2237 JSParseNode *pnlet = loop->pn_left->pn_left;
2239 VarDeclKind kind = VARDECL_LET;
2240 NodeVector dtors(cx);
2241 Value patt, init, dtor;
2243 if (!pattern(pnlet->pn_head, &kind, &patt) ||
2244 !expression(prelude->pn_kid, &init) ||
2245 !builder.variableDeclarator(patt, init, &pnlet->pn_pos, &dtor) ||
2246 !dtors.append(dtor) ||
2247 !builder.variableDeclaration(dtors, kind, &pnlet->pn_pos, &var)) {
2252 JSParseNode *head = loop->pn_left;
2253 JS_ASSERT(PN_TYPE(head) == TOK_IN);
2255 bool isForEach = loop->pn_iflags & JSITER_FOREACH;
2259 return expression(head->pn_right, &expr) &&
2260 statement(loop->pn_right, &stmt) &&
2261 builder.forInStatement(var, expr, stmt, isForEach, &pn->pn_pos, dst);
2269 return optIdentifier(pn->pn_atom, NULL, &label) &&
2270 (PN_TYPE(pn) == TOK_BREAK
2271 ? builder.breakStatement(label, &pn->pn_pos, dst)
2272 : builder.continueStatement(label, &pn->pn_pos, dst));
2279 return identifier(pn->pn_atom, NULL, &label) &&
2280 statement(pn->pn_expr, &stmt) &&
2281 builder.labeledStatement(label, stmt, &pn->pn_pos, dst);
2289 return optExpression(pn->pn_kid, &arg) &&
2290 (PN_TYPE(pn) == TOK_THROW
2291 ? builder.throwStatement(arg, &pn->pn_pos, dst)
2292 : builder.returnStatement(arg, &pn->pn_pos, dst));
2296 return builder.debuggerStatement(&pn->pn_pos, dst);
2298 #if JS_HAS_XML_SUPPORT
2301 LOCAL_ASSERT(pn->pn_arity == PN_UNARY);
2305 return expression(pn->pn_kid, &ns) &&
2306 builder.xmlDefaultNamespace(ns, &pn->pn_pos, dst);
2311 LOCAL_NOT_REACHED("unexpected statement type");
2316 ASTSerializer::leftAssociate(JSParseNode *pn, Value *dst)
2318 JS_ASSERT(pn->pn_arity == PN_LIST);
2320 const size_t len = pn->pn_count;
2321 JS_ASSERT(len >= 1);
2324 return expression(pn->pn_head, dst);
2326 JS_ASSERT(len >= 2);
2328 Vector<JSParseNode *, 8> list(cx);
2329 if (!list.reserve(len))
2332 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
2333 JS_ALWAYS_TRUE(list.append(next)); /* space check above */
2336 TokenKind tk = PN_TYPE(pn);
2338 bool lor = tk == TOK_OR;
2339 bool logop = lor || (tk == TOK_AND);
2343 if (!expression(list[len - 1], &right))
2349 JSParseNode *next = list[i];
2352 if (!expression(next, &left))
2355 TokenPos subpos = { next->pn_pos.begin, pn->pn_pos.end };
2358 if (!builder.logicalExpression(lor, left, right, &subpos, &right))
2361 BinaryOperator op = binop(PN_TYPE(pn), PN_OP(pn));
2362 LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
2364 if (!builder.binaryExpression(op, left, right, &subpos, &right))
2374 ASTSerializer::binaryOperands(JSParseNode *pn, NodeVector &elts)
2376 if (pn->pn_arity == PN_BINARY) {
2379 return expression(pn->pn_left, &left) &&
2380 elts.append(left) &&
2381 expression(pn->pn_right, &right) &&
2385 LOCAL_ASSERT(pn->pn_arity == PN_LIST);
2387 return expressions(pn, elts);
2391 ASTSerializer::comprehensionBlock(JSParseNode *pn, Value *dst)
2393 LOCAL_ASSERT(pn->pn_arity == PN_BINARY);
2395 JSParseNode *in = pn->pn_left;
2397 LOCAL_ASSERT(in && PN_TYPE(in) == TOK_IN);
2399 bool isForEach = pn->pn_iflags & JSITER_FOREACH;
2402 return pattern(in->pn_left, NULL, &patt) &&
2403 expression(in->pn_right, &src) &&
2404 builder.comprehensionBlock(patt, src, isForEach, &in->pn_pos, dst);
2408 ASTSerializer::comprehension(JSParseNode *pn, Value *dst)
2410 LOCAL_ASSERT(PN_TYPE(pn) == TOK_FOR);
2412 NodeVector blocks(cx);
2414 JSParseNode *next = pn;
2415 while (PN_TYPE(next) == TOK_FOR) {
2417 if (!comprehensionBlock(next, &block) || !blocks.append(block))
2419 next = next->pn_right;
2422 Value filter = MagicValue(JS_SERIALIZE_NO_NODE);
2424 if (PN_TYPE(next) == TOK_IF) {
2425 if (!optExpression(next->pn_kid1, &filter))
2427 next = next->pn_kid2;
2428 } else if (PN_TYPE(next) == TOK_LC && next->pn_count == 0) {
2429 /* js_FoldConstants optimized away the push. */
2430 NodeVector empty(cx);
2431 return builder.arrayExpression(empty, &pn->pn_pos, dst);
2434 LOCAL_ASSERT(PN_TYPE(next) == TOK_ARRAYPUSH);
2438 return expression(next->pn_kid, &body) &&
2439 builder.comprehensionExpression(body, blocks, filter, &pn->pn_pos, dst);
2443 ASTSerializer::generatorExpression(JSParseNode *pn, Value *dst)
2445 LOCAL_ASSERT(PN_TYPE(pn) == TOK_FOR);
2447 NodeVector blocks(cx);
2449 JSParseNode *next = pn;
2450 while (PN_TYPE(next) == TOK_FOR) {
2452 if (!comprehensionBlock(next, &block) || !blocks.append(block))
2454 next = next->pn_right;
2457 Value filter = MagicValue(JS_SERIALIZE_NO_NODE);
2459 if (PN_TYPE(next) == TOK_IF) {
2460 if (!optExpression(next->pn_kid1, &filter))
2462 next = next->pn_kid2;
2465 LOCAL_ASSERT(PN_TYPE(next) == TOK_SEMI &&
2466 PN_TYPE(next->pn_kid) == TOK_YIELD &&
2467 next->pn_kid->pn_kid);
2471 return expression(next->pn_kid->pn_kid, &body) &&
2472 builder.generatorExpression(body, blocks, filter, &pn->pn_pos, dst);
2476 ASTSerializer::expression(JSParseNode *pn, Value *dst)
2478 switch (PN_TYPE(pn)) {
2480 return function(pn, AST_FUNC_EXPR, dst);
2484 NodeVector exprs(cx);
2485 return expressions(pn, exprs) &&
2486 builder.sequenceExpression(exprs, &pn->pn_pos, dst);
2491 Value test, cons, alt;
2493 return expression(pn->pn_kid1, &test) &&
2494 expression(pn->pn_kid2, &cons) &&
2495 expression(pn->pn_kid3, &alt) &&
2496 builder.conditionalExpression(test, cons, alt, &pn->pn_pos, dst);
2502 if (pn->pn_arity == PN_BINARY) {
2504 return expression(pn->pn_left, &left) &&
2505 expression(pn->pn_right, &right) &&
2506 builder.logicalExpression(PN_TYPE(pn) == TOK_OR, left, right, &pn->pn_pos, dst);
2508 return leftAssociate(pn, dst);
2514 bool incr = PN_TYPE(pn) == TOK_INC;
2515 bool prefix = PN_OP(pn) >= JSOP_INCNAME && PN_OP(pn) <= JSOP_DECELEM;
2518 return expression(pn->pn_kid, &expr) &&
2519 builder.updateExpression(expr, incr, prefix, &pn->pn_pos, dst);
2524 AssignmentOperator op = aop(PN_OP(pn));
2525 LOCAL_ASSERT(op > AOP_ERR && op < AOP_LIMIT);
2528 return pattern(pn->pn_left, NULL, &lhs) &&
2529 expression(pn->pn_right, &rhs) &&
2530 builder.assignmentExpression(op, lhs, rhs, &pn->pn_pos, dst);
2544 case TOK_INSTANCEOF:
2546 if (pn->pn_arity == PN_BINARY) {
2547 BinaryOperator op = binop(PN_TYPE(pn), PN_OP(pn));
2548 LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
2551 return expression(pn->pn_left, &left) &&
2552 expression(pn->pn_right, &right) &&
2553 builder.binaryExpression(op, left, right, &pn->pn_pos, dst);
2555 return leftAssociate(pn, dst);
2559 #if JS_HAS_XML_SUPPORT
2560 if (PN_OP(pn) == JSOP_XMLNAME ||
2561 PN_OP(pn) == JSOP_SETXMLNAME ||
2562 PN_OP(pn) == JSOP_BINDXMLNAME)
2563 return expression(pn->pn_kid, dst);
2567 UnaryOperator op = unop(PN_TYPE(pn), PN_OP(pn));
2568 LOCAL_ASSERT(op > UNOP_ERR && op < UNOP_LIMIT);
2571 return expression(pn->pn_kid, &expr) &&
2572 builder.unaryExpression(op, expr, &pn->pn_pos, dst);
2578 #ifdef JS_HAS_GENERATOR_EXPRS
2579 if (pn->isGeneratorExpr())
2580 return generatorExpression(pn->generatorExpr(), dst);
2583 JSParseNode *next = pn->pn_head;
2586 if (!expression(next, &callee))
2589 NodeVector args(cx);
2590 if (!args.reserve(pn->pn_count - 1))
2593 for (next = next->pn_next; next; next = next->pn_next) {
2595 if (!expression(next, &arg))
2597 JS_ALWAYS_TRUE(args.append(arg)); /* space check above */
2600 return PN_TYPE(pn) == TOK_NEW
2601 ? builder.newExpression(callee, args, &pn->pn_pos, dst)
2602 : builder.callExpression(callee, args, &pn->pn_pos, dst);
2608 return expression(pn->pn_expr, &expr) &&
2609 identifier(pn->pn_atom, NULL, &id) &&
2610 builder.memberExpression(false, expr, id, &pn->pn_pos, dst);
2616 return expression(pn->pn_left, &left) &&
2617 expression(pn->pn_right, &right) &&
2618 builder.memberExpression(true, left, right, &pn->pn_pos, dst);
2623 NodeVector elts(cx);
2624 if (!elts.reserve(pn->pn_count))
2627 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
2628 if (PN_TYPE(next) == TOK_COMMA) {
2629 JS_ALWAYS_TRUE(elts.append(MagicValue(JS_SERIALIZE_NO_NODE))); /* space check above */
2632 if (!expression(next, &expr))
2634 JS_ALWAYS_TRUE(elts.append(expr)); /* space check above */
2638 return builder.arrayExpression(elts, &pn->pn_pos, dst);
2643 NodeVector elts(cx);
2644 if (!elts.reserve(pn->pn_count))
2647 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
2649 if (!property(next, &prop))
2651 JS_ALWAYS_TRUE(elts.append(prop)); /* space check above */
2654 return builder.objectExpression(elts, &pn->pn_pos, dst);
2658 return identifier(pn, dst);
2664 return PN_OP(pn) == JSOP_THIS ? builder.thisExpression(&pn->pn_pos, dst) : literal(pn, dst);
2669 return optExpression(pn->pn_kid, &arg) &&
2670 builder.yieldExpression(arg, &pn->pn_pos, dst);
2676 return expression(pn->pn_kid, &expr) &&
2677 builder.graphExpression(pn->pn_num, expr, &pn->pn_pos, dst);
2681 return builder.graphIndexExpression(pn->pn_num, &pn->pn_pos, dst);
2684 /* NB: it's no longer the case that pn_count could be 2. */
2685 LOCAL_ASSERT(pn->pn_count == 1);
2686 LOCAL_ASSERT(PN_TYPE(pn->pn_head) == TOK_LEXICALSCOPE);
2688 return comprehension(pn->pn_head->pn_expr, dst);
2690 case TOK_LEXICALSCOPE:
2694 NodeVector dtors(cx);
2697 return letHead(pn->pn_left, dtors) &&
2698 expression(pn->pn_right, &expr) &&
2699 builder.letExpression(dtors, expr, &pn->pn_pos, dst);
2702 #ifdef JS_HAS_XML_SUPPORT
2704 return builder.xmlAnyName(&pn->pn_pos, dst);
2710 LOCAL_ASSERT(pn->pn_arity == PN_NAME || pn->pn_arity == PN_BINARY);
2712 JSParseNode *pnleft;
2715 if (pn->pn_arity == PN_BINARY) {
2717 pnleft = pn->pn_left;
2718 if (!expression(pn->pn_right, &right))
2721 JS_ASSERT(pn->pn_arity == PN_NAME);
2723 pnleft = pn->pn_expr;
2724 if (!identifier(pn->pn_atom, NULL, &right))
2728 if (PN_TYPE(pnleft) == TOK_FUNCTION)
2729 return builder.xmlFunctionQualifiedIdentifier(right, computed, &pn->pn_pos, dst);
2732 return expression(pnleft, &left) &&
2733 builder.xmlQualifiedIdentifier(left, right, computed, &pn->pn_pos, dst);
2739 return expression(pn->pn_kid, &expr) &&
2740 builder.xmlAttributeSelector(expr, &pn->pn_pos, dst);
2746 return expression(pn->pn_left, &left) &&
2747 expression(pn->pn_right, &right) &&
2748 builder.xmlFilterExpression(left, right, &pn->pn_pos, dst);
2752 return xml(pn, dst);
2756 LOCAL_NOT_REACHED("unexpected expression type");
2762 ASTSerializer::xml(JSParseNode *pn, Value *dst)
2764 switch (PN_TYPE(pn)) {
2765 #ifdef JS_HAS_XML_SUPPORT
2769 return expression(pn->pn_kid, &expr) &&
2770 builder.xmlEscapeExpression(expr, &pn->pn_pos, dst);
2775 NodeVector elts(cx);
2776 if (!xmls(pn, elts))
2778 return builder.xmlElement(elts, &pn->pn_pos, dst);
2783 NodeVector elts(cx);
2784 if (!xmls(pn, elts))
2786 return builder.xmlList(elts, &pn->pn_pos, dst);
2791 NodeVector elts(cx);
2792 if (!xmls(pn, elts))
2794 return builder.xmlStartTag(elts, &pn->pn_pos, dst);
2799 NodeVector elts(cx);
2800 if (!xmls(pn, elts))
2802 return builder.xmlEndTag(elts, &pn->pn_pos, dst);
2807 NodeVector elts(cx);
2808 if (!xmls(pn, elts))
2810 return builder.xmlPointTag(elts, &pn->pn_pos, dst);
2815 return builder.xmlText(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2818 if (pn->pn_arity == PN_NULLARY)
2819 return builder.xmlName(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2821 LOCAL_ASSERT(pn->pn_arity == PN_LIST);
2824 NodeVector elts(cx);
2825 return xmls(pn, elts) &&
2826 builder.xmlName(elts, &pn->pn_pos, dst);
2830 return builder.xmlAttribute(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2833 return builder.xmlCdata(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2835 case TOK_XMLCOMMENT:
2836 return builder.xmlComment(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2840 return builder.xmlPI(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2842 return builder.xmlPI(atomContents(pn->pn_atom),
2843 atomContents(pn->pn_atom2),
2849 LOCAL_NOT_REACHED("unexpected XML node type");
2854 ASTSerializer::propertyName(JSParseNode *pn, Value *dst)
2856 if (PN_TYPE(pn) == TOK_NAME)
2857 return identifier(pn, dst);
2859 LOCAL_ASSERT(PN_TYPE(pn) == TOK_STRING || PN_TYPE(pn) == TOK_NUMBER);
2861 return literal(pn, dst);
2865 ASTSerializer::property(JSParseNode *pn, Value *dst)
2868 switch (PN_OP(pn)) {
2882 LOCAL_NOT_REACHED("unexpected object-literal property");
2886 return propertyName(pn->pn_left, &key) &&
2887 expression(pn->pn_right, &val) &&
2888 builder.propertyInitializer(key, val, kind, &pn->pn_pos, dst);
2892 ASTSerializer::literal(JSParseNode *pn, Value *dst)
2895 switch (PN_TYPE(pn)) {
2897 val = Valueify(ATOM_TO_JSVAL(pn->pn_atom));
2902 JSObject *re1 = pn->pn_objbox ? pn->pn_objbox->object : NULL;
2903 LOCAL_ASSERT(re1 && re1->isRegExp());
2906 if (!js_GetClassPrototype(cx, &cx->fp()->scopeChain(), JSProto_RegExp, &proto))
2909 JSObject *re2 = js_CloneRegExpObject(cx, re1, proto);
2913 val.setObject(*re2);
2918 val.setNumber(pn->pn_dval);
2922 if (PN_OP(pn) == JSOP_NULL)
2925 val.setBoolean(PN_OP(pn) == JSOP_TRUE);
2929 LOCAL_NOT_REACHED("unexpected literal type");
2932 return builder.literal(val, &pn->pn_pos, dst);
2936 ASTSerializer::arrayPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
2938 JS_ASSERT(PN_TYPE(pn) == TOK_RB);
2940 NodeVector elts(cx);
2941 if (!elts.reserve(pn->pn_count))
2944 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
2945 if (PN_TYPE(next) == TOK_COMMA) {
2946 JS_ALWAYS_TRUE(elts.append(MagicValue(JS_SERIALIZE_NO_NODE))); /* space check above */
2949 if (!pattern(next, pkind, &patt))
2951 JS_ALWAYS_TRUE(elts.append(patt)); /* space check above */
2955 return builder.arrayPattern(elts, &pn->pn_pos, dst);
2959 ASTSerializer::objectPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
2961 JS_ASSERT(PN_TYPE(pn) == TOK_RC);
2963 NodeVector elts(cx);
2964 if (!elts.reserve(pn->pn_count))
2967 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
2968 LOCAL_ASSERT(PN_OP(next) == JSOP_INITPROP);
2970 Value key, patt, prop;
2971 if (!propertyName(next->pn_left, &key) ||
2972 !pattern(next->pn_right, pkind, &patt) ||
2973 !builder.propertyPattern(key, patt, &next->pn_pos, &prop)) {
2977 JS_ALWAYS_TRUE(elts.append(prop)); /* space check above */
2980 return builder.objectPattern(elts, &pn->pn_pos, dst);
2984 ASTSerializer::pattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
2986 switch (PN_TYPE(pn)) {
2988 return objectPattern(pn, pkind, dst);
2991 return arrayPattern(pn, pkind, dst);
2994 if (pkind && (pn->pn_dflags & PND_CONST))
2995 *pkind = VARDECL_CONST;
2999 return expression(pn, dst);
3004 ASTSerializer::identifier(JSAtom *atom, TokenPos *pos, Value *dst)
3006 return builder.identifier(atomContents(atom), pos, dst);
3010 ASTSerializer::identifier(JSParseNode *pn, Value *dst)
3012 LOCAL_ASSERT(pn->pn_arity == PN_NAME || pn->pn_arity == PN_NULLARY);
3013 LOCAL_ASSERT(pn->pn_atom);
3015 return identifier(pn->pn_atom, &pn->pn_pos, dst);
3019 ASTSerializer::function(JSParseNode *pn, ASTType type, Value *dst)
3021 JSFunction *func = (JSFunction *)pn->pn_funbox->object;
3024 #ifdef JS_HAS_GENERATORS
3025 pn->pn_funbox->tcflags & TCF_FUN_IS_GENERATOR;
3031 #ifdef JS_HAS_EXPR_CLOSURES
3032 func->flags & JSFUN_EXPR_CLOSURE;
3038 if (!optIdentifier(func->atom, NULL, &id))
3041 NodeVector args(cx);
3043 JSParseNode *argsAndBody = (PN_TYPE(pn->pn_body) == TOK_UPVARS)
3044 ? pn->pn_body->pn_tree
3048 return functionArgsAndBody(argsAndBody, args, &body) &&
3049 builder.function(type, &pn->pn_pos, id, args, body, isGenerator, isExpression, dst);
3053 ASTSerializer::functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *body)
3055 JSParseNode *pnargs;
3056 JSParseNode *pnbody;
3058 /* Extract the args and body separately. */
3059 if (PN_TYPE(pn) == TOK_ARGSBODY) {
3061 pnbody = pn->last();
3067 JSParseNode *pndestruct;
3069 /* Extract the destructuring assignments. */
3070 if (pnbody->pn_arity == PN_LIST && (pnbody->pn_xflags & PNX_DESTRUCT)) {
3071 JSParseNode *head = pnbody->pn_head;
3072 LOCAL_ASSERT(head && PN_TYPE(head) == TOK_SEMI);
3074 pndestruct = head->pn_kid;
3075 LOCAL_ASSERT(pndestruct && PN_TYPE(pndestruct) == TOK_VAR);
3080 /* Serialize the arguments and body. */
3081 switch (PN_TYPE(pnbody)) {
3082 case TOK_RETURN: /* expression closure, no destructured args */
3083 return functionArgs(pn, pnargs, NULL, pnbody, args) &&
3084 expression(pnbody->pn_kid, body);
3086 case TOK_SEQ: /* expression closure with destructured args */
3088 JSParseNode *pnstart = pnbody->pn_head->pn_next;
3089 LOCAL_ASSERT(pnstart && PN_TYPE(pnstart) == TOK_RETURN);
3091 return functionArgs(pn, pnargs, pndestruct, pnbody, args) &&
3092 expression(pnstart->pn_kid, body);
3095 case TOK_LC: /* statement closure */
3097 JSParseNode *pnstart = (pnbody->pn_xflags & PNX_DESTRUCT)
3098 ? pnbody->pn_head->pn_next
3101 return functionArgs(pn, pnargs, pndestruct, pnbody, args) &&
3102 functionBody(pnstart, &pnbody->pn_pos, body);
3106 LOCAL_NOT_REACHED("unexpected function contents");
3111 ASTSerializer::functionArgs(JSParseNode *pn, JSParseNode *pnargs, JSParseNode *pndestruct,
3112 JSParseNode *pnbody, NodeVector &args)
3115 JSParseNode *arg = pnargs ? pnargs->pn_head : NULL;
3116 JSParseNode *destruct = pndestruct ? pndestruct->pn_head : NULL;
3120 * Arguments are found in potentially two different places: 1) the
3121 * argsbody sequence (which ends with the body node), or 2) a
3122 * destructuring initialization at the beginning of the body. Loop
3123 * |arg| through the argsbody and |destruct| through the initial
3124 * destructuring assignments, stopping only when we've exhausted
3127 while ((arg && arg != pnbody) || destruct) {
3128 if (destruct && destruct->pn_right->frameSlot() == i) {
3129 if (!pattern(destruct->pn_left, NULL, &node) || !args.append(node))
3131 destruct = destruct->pn_next;
3132 } else if (arg && arg != pnbody) {
3134 * We don't check that arg->frameSlot() == i since we
3135 * can't call that method if the arg def has been turned
3138 * function(a) { function a() { } }
3140 * There's no other way to ask a non-destructuring arg its
3141 * index in the formals list, so we rely on the ability to
3142 * ask destructuring args their index above.
3144 if (!identifier(arg, &node) || !args.append(node))
3148 LOCAL_NOT_REACHED("missing function argument");
3157 ASTSerializer::functionBody(JSParseNode *pn, TokenPos *pos, Value *dst)
3159 NodeVector elts(cx);
3161 /* We aren't sure how many elements there are up front, so we'll check each append. */
3162 for (JSParseNode *next = pn; next; next = next->pn_next) {
3164 if (!sourceElement(next, &child) || !elts.append(child))
3168 return builder.blockStatement(elts, pos, dst);
3171 } /* namespace js */
3175 Class js_ReflectClass = {
3177 JSCLASS_HAS_CACHED_PROTO(JSProto_Reflect),
3188 reflect_parse(JSContext *cx, uint32 argc, jsval *vp)
3191 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
3192 "Reflect.parse", "0", "s");
3196 JSString *src = js_ValueToString(cx, Valueify(JS_ARGV(cx, vp)[0]));
3200 char *filename = NULL;
3201 AutoReleaseNullablePtr filenamep(cx, filename);
3205 JSObject *builder = NULL;
3207 Value arg = argc > 1 ? Valueify(JS_ARGV(cx, vp)[1]) : UndefinedValue();
3209 if (!arg.isNullOrUndefined()) {
3210 if (!arg.isObject()) {
3211 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
3212 JSDVG_SEARCH_STACK, arg, NULL, "not an object", NULL);
3216 JSObject *config = &arg.toObject();
3221 if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.locAtom),
3222 BooleanValue(true), &prop)) {
3226 loc = js_ValueToBoolean(prop);
3230 if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.sourceAtom),
3231 NullValue(), &prop)) {
3235 if (!prop.isNullOrUndefined()) {
3236 JSString *str = js_ValueToString(cx, prop);
3240 size_t length = str->length();
3241 const jschar *chars = str->getChars(cx);
3245 filename = js_DeflateString(cx, chars, length);
3248 filenamep.reset(filename);
3252 if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.lineAtom),
3253 Int32Value(1), &prop) ||
3254 !ValueToECMAUint32(cx, prop, &lineno)) {
3259 /* config.builder */
3260 if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.builderAtom),
3261 NullValue(), &prop)) {
3265 if (!prop.isNullOrUndefined()) {
3266 if (!prop.isObject()) {
3267 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
3268 JSDVG_SEARCH_STACK, prop, NULL, "not an object", NULL);
3271 builder = &prop.toObject();
3275 /* Extract the builder methods first to report errors before parsing. */
3276 ASTSerializer serialize(cx, loc, filename, lineno);
3277 if (!serialize.init(builder))
3280 size_t length = src->length();
3281 const jschar *chars = src->getChars(cx);
3287 if (!parser.init(chars, length, filename, lineno, cx->findVersion()))
3290 JSParseNode *pn = parser.parse(NULL);
3295 if (!serialize.program(pn, &val)) {
3296 JS_SET_RVAL(cx, vp, JSVAL_NULL);
3300 JS_SET_RVAL(cx, vp, Jsvalify(val));
3304 static JSFunctionSpec static_methods[] = {
3305 JS_FN("parse", reflect_parse, 1, 0),
3311 js_InitReflectClass(JSContext *cx, JSObject *obj)
3313 JSObject *Reflect = NewNonFunction<WithProto::Class>(cx, &js_ReflectClass, NULL, obj);
3317 if (!JS_DefineProperty(cx, obj, js_Reflect_str, OBJECT_TO_JSVAL(Reflect),
3318 JS_PropertyStub, JS_StrictPropertyStub, 0)) {
3322 if (!JS_DefineFunctions(cx, Reflect, static_methods))