Bug 588735 - Mirror glass caption buttons for rtl windows. r=roc, a=blocking-betaN.
[mozilla-central.git] / js / src / jsreflect.cpp
blob03cb3f84549a4bd5f089d77f5e0cb14548a60a9e
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
15 * License.
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
18 * June 12, 2009.
20 * The Initial Developer of the Original Code is
21 * the Mozilla Corporation.
23 * Contributor(s):
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.
43 #include <stdlib.h>
44 #include <string.h> /* for jsparse.h */
45 #include "jspubtd.h"
46 #include "jsatom.h"
47 #include "jsobj.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 */
53 #include "jsparse.h"
54 #include "jsregexp.h"
55 #include "jsvector.h"
56 #include "jsemit.h"
57 #include "jsscan.h"
58 #include "jsprf.h"
59 #include "jsiter.h"
60 #include "jsbool.h"
61 #include "jsval.h"
62 #include "jsvalue.h"
63 #include "jsobjinlines.h"
64 #include "jsarray.h"
65 #include "jsnum.h"
67 using namespace js;
69 namespace js {
71 char const *aopNames[] = {
72 "=", /* AOP_ASSIGN */
73 "+=", /* AOP_PLUS */
74 "-=", /* AOP_MINUS */
75 "*=", /* AOP_STAR */
76 "/=", /* AOP_DIV */
77 "%=", /* AOP_MOD */
78 "<<=", /* AOP_LSH */
79 ">>=", /* AOP_RSH */
80 ">>>=", /* AOP_URSH */
81 "|=", /* AOP_BITOR */
82 "^=", /* AOP_BITXOR */
83 "&=" /* AOP_BITAND */
86 char const *binopNames[] = {
87 "==", /* BINOP_EQ */
88 "!=", /* BINOP_NE */
89 "===", /* BINOP_STRICTEQ */
90 "!==", /* BINOP_STRICTNE */
91 "<", /* BINOP_LT */
92 "<=", /* BINOP_LE */
93 ">", /* BINOP_GT */
94 ">=", /* BINOP_GE */
95 "<<", /* BINOP_LSH */
96 ">>", /* BINOP_RSH */
97 ">>>", /* BINOP_URSH */
98 "+", /* BINOP_PLUS */
99 "-", /* BINOP_MINUS */
100 "*", /* BINOP_STAR */
101 "/", /* BINOP_DIV */
102 "%", /* BINOP_MOD */
103 "|", /* BINOP_BITOR */
104 "^", /* BINOP_BITXOR */
105 "&", /* BINOP_BITAND */
106 "in", /* BINOP_IN */
107 "instanceof", /* BINOP_INSTANCEOF */
108 "..", /* BINOP_DBLDOT */
111 char const *unopNames[] = {
112 "delete", /* UNOP_DELETE */
113 "-", /* UNOP_NEG */
114 "+", /* UNOP_POS */
115 "!", /* UNOP_NOT */
116 "~", /* UNOP_BITNOT */
117 "typeof", /* UNOP_TYPEOF */
118 "void" /* UNOP_VOID */
121 char const *nodeTypeNames[] = {
122 #define ASTDEF(ast, str) str,
123 #include "jsast.tbl"
124 #undef ASTDEF
125 NULL
128 typedef Vector<Value, 8> NodeVector;
131 * JSParseNode is a somewhat intricate data structure, and its invariants have
132 * evolved, making it more likely that there could be a disconnect between the
133 * parser and the AST serializer. We use these macros to check invariants on a
134 * parse node and raise a dynamic error on failure.
136 #define LOCAL_ASSERT(expr) \
137 JS_BEGIN_MACRO \
138 JS_ASSERT(expr); \
139 if (!(expr)) { \
140 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PARSE_NODE); \
141 return false; \
143 JS_END_MACRO
145 #define LOCAL_NOT_REACHED(expr) \
146 JS_BEGIN_MACRO \
147 JS_NOT_REACHED(expr); \
148 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PARSE_NODE); \
149 return false; \
150 JS_END_MACRO
154 * Builder class that constructs JavaScript AST node objects. See:
156 * https://developer.mozilla.org/en/SpiderMonkey/Parser_API
158 * Bug 569487: generalize builder interface
160 class NodeBuilder
162 JSContext *cx;
163 char const *src; /* source filename or null */
164 Value srcval; /* source filename JS value or null */
166 public:
167 NodeBuilder(JSContext *c, char const *s)
168 : cx(c), src(s) {
171 bool init() {
172 if (src)
173 return atomValue(src, &srcval);
175 srcval.setNull();
176 return true;
179 private:
180 bool atomValue(const char *s, Value *dst) {
182 * Bug 575416: instead of js_Atomize, lookup constant atoms in tbl file
184 JSAtom *atom = js_Atomize(cx, s, strlen(s), 0);
185 if (!atom)
186 return false;
188 *dst = Valueify(ATOM_TO_JSVAL(atom));
189 return true;
192 bool newObject(JSObject **dst) {
193 JSObject *nobj = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, NULL, NULL);
194 if (!nobj)
195 return false;
197 *dst = nobj;
198 return true;
201 bool newArray(NodeVector &elts, Value *dst);
203 bool newNode(ASTType type, TokenPos *pos, JSObject **dst);
205 bool newNode(ASTType type, TokenPos *pos, Value *dst) {
206 JSObject *node;
207 return newNode(type, pos, &node) &&
208 setResult(node, dst);
211 bool newNode(ASTType type, TokenPos *pos, const char *childName, Value child, Value *dst) {
212 JSObject *node;
213 return newNode(type, pos, &node) &&
214 setProperty(node, childName, child) &&
215 setResult(node, dst);
218 bool newNode(ASTType type, TokenPos *pos,
219 const char *childName1, Value child1,
220 const char *childName2, Value child2,
221 Value *dst) {
222 JSObject *node;
223 return newNode(type, pos, &node) &&
224 setProperty(node, childName1, child1) &&
225 setProperty(node, childName2, child2) &&
226 setResult(node, dst);
229 bool newNode(ASTType type, TokenPos *pos,
230 const char *childName1, Value child1,
231 const char *childName2, Value child2,
232 const char *childName3, Value child3,
233 Value *dst) {
234 JSObject *node;
235 return newNode(type, pos, &node) &&
236 setProperty(node, childName1, child1) &&
237 setProperty(node, childName2, child2) &&
238 setProperty(node, childName3, child3) &&
239 setResult(node, dst);
242 bool newNode(ASTType type, TokenPos *pos,
243 const char *childName1, Value child1,
244 const char *childName2, Value child2,
245 const char *childName3, Value child3,
246 const char *childName4, Value child4,
247 Value *dst) {
248 JSObject *node;
249 return newNode(type, pos, &node) &&
250 setProperty(node, childName1, child1) &&
251 setProperty(node, childName2, child2) &&
252 setProperty(node, childName3, child3) &&
253 setProperty(node, childName4, child4) &&
254 setResult(node, dst);
257 bool newNode(ASTType type, TokenPos *pos,
258 const char *childName1, Value child1,
259 const char *childName2, Value child2,
260 const char *childName3, Value child3,
261 const char *childName4, Value child4,
262 const char *childName5, Value child5,
263 Value *dst) {
264 JSObject *node;
265 return newNode(type, pos, &node) &&
266 setProperty(node, childName1, child1) &&
267 setProperty(node, childName2, child2) &&
268 setProperty(node, childName3, child3) &&
269 setProperty(node, childName4, child4) &&
270 setProperty(node, childName5, child5) &&
271 setResult(node, dst);
274 bool newListNode(ASTType type, TokenPos *pos, const char *propName,
275 NodeVector &elts, Value *dst) {
276 Value array;
277 return newArray(elts, &array) &&
278 newNode(type, pos, propName, array, dst);
281 bool setProperty(JSObject *obj, const char *name, Value val) {
282 JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
284 /* Represent "no node" as null and ensure users are not exposed to magic values. */
285 if (val.isMagic(JS_SERIALIZE_NO_NODE))
286 val.setNull();
289 * Bug 575416: instead of js_Atomize, lookup constant atoms in tbl file
291 JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
292 if (!atom)
293 return false;
295 return obj->defineProperty(cx, ATOM_TO_JSID(atom), val);
298 bool setNodeLoc(JSObject *obj, TokenPos *pos);
300 bool setResult(JSObject *obj, Value *dst) {
301 JS_ASSERT(obj);
302 dst->setObject(*obj);
303 return true;
306 public:
308 * All of the public builder methods take as their last two
309 * arguments a nullable token position and a non-nullable, rooted
310 * outparam.
312 * All Value arguments are rooted. Any Value arguments representing
313 * optional subnodes may be a JS_SERIALIZE_NO_NODE magic value.
317 * misc nodes
320 bool program(NodeVector &elts, TokenPos *pos, Value *dst);
322 bool literal(Value val, TokenPos *pos, Value *dst);
324 bool identifier(Value name, TokenPos *pos, Value *dst);
326 bool function(ASTType type, TokenPos *pos,
327 Value id, NodeVector &args, Value body,
328 bool isGenerator, bool isExpression, Value *dst);
330 bool variableDeclarator(Value id, Value init, TokenPos *pos, Value *dst);
332 bool switchCase(Value expr, NodeVector &elts, TokenPos *pos, Value *dst);
334 bool catchClause(Value var, Value guard, Value body, TokenPos *pos, Value *dst);
336 bool propertyInitializer(Value key, Value val, PropKind kind, TokenPos *pos, Value *dst);
340 * statements
343 bool blockStatement(NodeVector &elts, TokenPos *pos, Value *dst);
345 bool expressionStatement(Value expr, TokenPos *pos, Value *dst);
347 bool emptyStatement(TokenPos *pos, Value *dst);
349 bool ifStatement(Value test, Value cons, Value alt, TokenPos *pos, Value *dst);
351 bool breakStatement(Value label, TokenPos *pos, Value *dst);
353 bool continueStatement(Value label, TokenPos *pos, Value *dst);
355 bool labeledStatement(Value label, Value stmt, TokenPos *pos, Value *dst);
357 bool throwStatement(Value arg, TokenPos *pos, Value *dst);
359 bool returnStatement(Value arg, TokenPos *pos, Value *dst);
361 bool forStatement(Value init, Value test, Value update, Value stmt,
362 TokenPos *pos, Value *dst);
364 bool forInStatement(Value var, Value expr, Value stmt,
365 bool isForEach, TokenPos *pos, Value *dst);
367 bool withStatement(Value expr, Value stmt, TokenPos *pos, Value *dst);
369 bool whileStatement(Value test, Value stmt, TokenPos *pos, Value *dst);
371 bool doWhileStatement(Value stmt, Value test, TokenPos *pos, Value *dst);
373 bool switchStatement(Value disc, NodeVector &elts, bool lexical, TokenPos *pos, Value *dst);
375 bool tryStatement(Value body, NodeVector &catches, Value finally, TokenPos *pos, Value *dst);
377 bool debuggerStatement(TokenPos *pos, Value *dst);
380 * expressions
383 bool binaryExpression(BinaryOperator op, Value left, Value right, TokenPos *pos, Value *dst);
385 bool unaryExpression(UnaryOperator op, Value expr, TokenPos *pos, Value *dst);
387 bool assignmentExpression(AssignmentOperator op, Value lhs, Value rhs,
388 TokenPos *pos, Value *dst);
390 bool updateExpression(Value expr, bool incr, bool prefix, TokenPos *pos, Value *dst);
392 bool logicalExpression(bool lor, Value left, Value right, TokenPos *pos, Value *dst);
394 bool conditionalExpression(Value test, Value cons, Value alt, TokenPos *pos, Value *dst);
396 bool sequenceExpression(NodeVector &elts, TokenPos *pos, Value *dst);
398 bool newExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst);
400 bool callExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst);
402 bool memberExpression(bool computed, Value expr, Value member, TokenPos *pos, Value *dst);
404 bool arrayExpression(NodeVector &elts, TokenPos *pos, Value *dst);
406 bool objectExpression(NodeVector &elts, TokenPos *pos, Value *dst);
408 bool thisExpression(TokenPos *pos, Value *dst);
410 bool yieldExpression(Value arg, TokenPos *pos, Value *dst);
412 bool comprehensionBlock(Value patt, Value src, bool isForEach, TokenPos *pos, Value *dst);
414 bool comprehensionExpression(Value body, NodeVector &blocks, Value filter,
415 TokenPos *pos, Value *dst);
417 bool generatorExpression(Value body, NodeVector &blocks, Value filter,
418 TokenPos *pos, Value *dst);
420 bool graphExpression(jsint idx, Value expr, TokenPos *pos, Value *dst);
422 bool graphIndexExpression(jsint idx, TokenPos *pos, Value *dst);
425 * declarations
428 bool variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos, Value *dst);
431 * patterns
434 bool arrayPattern(NodeVector &elts, TokenPos *pos, Value *dst);
436 bool objectPattern(NodeVector &elts, TokenPos *pos, Value *dst);
438 bool propertyPattern(Value key, Value patt, TokenPos *pos, Value *dst);
441 * xml
444 bool xmlAnyName(TokenPos *pos, Value *dst);
446 bool xmlEscapeExpression(Value expr, TokenPos *pos, Value *dst);
448 bool xmlDefaultNamespace(Value ns, TokenPos *pos, Value *dst);
450 bool xmlFilterExpression(Value left, Value right, TokenPos *pos, Value *dst);
452 bool xmlAttributeSelector(Value expr, TokenPos *pos, Value *dst);
454 bool xmlQualifiedIdentifier(Value left, Value right, bool computed, TokenPos *pos, Value *dst);
456 bool xmlElement(NodeVector &elts, TokenPos *pos, Value *dst);
458 bool xmlText(Value text, TokenPos *pos, Value *dst);
460 bool xmlList(NodeVector &elts, TokenPos *pos, Value *dst);
462 bool xmlStartTag(NodeVector &elts, TokenPos *pos, Value *dst);
464 bool xmlEndTag(NodeVector &elts, TokenPos *pos, Value *dst);
466 bool xmlPointTag(NodeVector &elts, TokenPos *pos, Value *dst);
468 bool xmlName(Value text, TokenPos *pos, Value *dst);
470 bool xmlName(NodeVector &elts, TokenPos *pos, Value *dst);
472 bool xmlAttribute(Value text, TokenPos *pos, Value *dst);
474 bool xmlCdata(Value text, TokenPos *pos, Value *dst);
476 bool xmlComment(Value text, TokenPos *pos, Value *dst);
478 bool xmlPI(Value target, TokenPos *pos, Value *dst);
480 bool xmlPI(Value target, Value content, TokenPos *pos, Value *dst);
483 bool
484 NodeBuilder::newNode(ASTType type, TokenPos *pos, JSObject **dst)
486 JS_ASSERT(type > AST_ERROR && type < AST_LIMIT);
488 Value tv;
490 JSObject *node = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, NULL, NULL);
491 if (!node ||
492 !setNodeLoc(node, pos) ||
493 !atomValue(nodeTypeNames[type], &tv) ||
494 !setProperty(node, "type", tv))
495 return false;
497 *dst = node;
498 return true;
501 bool
502 NodeBuilder::newArray(NodeVector &elts, Value *dst)
504 JSObject *array = js_NewArrayObject(cx, 0, NULL);
505 if (!array)
506 return false;
508 const size_t len = elts.length();
509 for (size_t i = 0; i < len; i++) {
510 Value val = elts[i];
512 JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
514 /* Represent "no node" as null and ensure users are not exposed to magic values. */
515 if (val.isMagic(JS_SERIALIZE_NO_NODE))
516 val.setNull();
518 if (!js_ArrayCompPush(cx, array, val))
519 return false;
522 dst->setObject(*array);
523 return true;
526 bool
527 NodeBuilder::setNodeLoc(JSObject *node, TokenPos *pos)
529 if (!pos)
530 return setProperty(node, "loc", NullValue());
532 JSObject *loc, *to;
533 Value tv;
535 return newObject(&loc) &&
536 setProperty(node, "loc", ObjectValue(*loc)) &&
537 setProperty(loc, "source", srcval) &&
539 newObject(&to) &&
540 setProperty(loc, "start", ObjectValue(*to)) &&
541 (tv.setNumber(pos->begin.lineno), true) &&
542 setProperty(to, "line", tv) &&
543 (tv.setNumber(pos->begin.index), true) &&
544 setProperty(to, "column", tv) &&
546 newObject(&to) &&
547 setProperty(loc, "end", ObjectValue(*to)) &&
548 (tv.setNumber(pos->end.lineno), true) &&
549 setProperty(to, "line", tv) &&
550 (tv.setNumber(pos->end.index), true) &&
551 setProperty(to, "column", tv);
554 bool
555 NodeBuilder::program(NodeVector &elts, TokenPos *pos, Value *dst)
557 Value array;
558 return newArray(elts, &array) &&
559 newNode(AST_PROGRAM, pos, "body", array, dst);
562 bool
563 NodeBuilder::blockStatement(NodeVector &elts, TokenPos *pos, Value *dst)
565 Value array;
566 return newArray(elts, &array) &&
567 newNode(AST_BLOCK_STMT, pos, "body", array, dst);
570 bool
571 NodeBuilder::expressionStatement(Value expr, TokenPos *pos, Value *dst)
573 return newNode(AST_EXPR_STMT, pos, "expression", expr, dst);
576 bool
577 NodeBuilder::emptyStatement(TokenPos *pos, Value *dst)
579 return newNode(AST_EMPTY_STMT, pos, dst);
582 bool
583 NodeBuilder::ifStatement(Value test, Value cons, Value alt, TokenPos *pos, Value *dst)
585 return newNode(AST_IF_STMT, pos,
586 "test", test,
587 "consequent", cons,
588 "alternate", alt,
589 dst);
592 bool
593 NodeBuilder::breakStatement(Value label, TokenPos *pos, Value *dst)
595 return newNode(AST_BREAK_STMT, pos, "label", label, dst);
598 bool
599 NodeBuilder::continueStatement(Value label, TokenPos *pos, Value *dst)
601 return newNode(AST_CONTINUE_STMT, pos, "label", label, dst);
604 bool
605 NodeBuilder::labeledStatement(Value label, Value stmt, TokenPos *pos, Value *dst)
607 return newNode(AST_LAB_STMT, pos,
608 "label", label,
609 "body", stmt,
610 dst);
613 bool
614 NodeBuilder::throwStatement(Value arg, TokenPos *pos, Value *dst)
616 return newNode(AST_THROW_STMT, pos, "argument", arg, dst);
619 bool
620 NodeBuilder::returnStatement(Value arg, TokenPos *pos, Value *dst)
622 return newNode(AST_RETURN_STMT, pos, "argument", arg, dst);
625 bool
626 NodeBuilder::forStatement(Value init, Value test, Value update, Value stmt,
627 TokenPos *pos, Value *dst)
629 return newNode(AST_FOR_STMT, pos,
630 "init", init,
631 "test", test,
632 "update", update,
633 "body", stmt,
634 dst);
637 bool
638 NodeBuilder::forInStatement(Value var, Value expr, Value stmt, bool isForEach,
639 TokenPos *pos, Value *dst)
641 return newNode(AST_FOR_IN_STMT, pos,
642 "left", var,
643 "right", expr,
644 "body", stmt,
645 "each", BooleanValue(isForEach),
646 dst);
649 bool
650 NodeBuilder::withStatement(Value expr, Value stmt, TokenPos *pos, Value *dst)
652 return newNode(AST_WITH_STMT, pos,
653 "object", expr,
654 "body", stmt,
655 dst);
658 bool
659 NodeBuilder::whileStatement(Value test, Value stmt, TokenPos *pos, Value *dst)
661 return newNode(AST_WHILE_STMT, pos,
662 "test", test,
663 "body", stmt,
664 dst);
667 bool
668 NodeBuilder::doWhileStatement(Value stmt, Value test, TokenPos *pos, Value *dst)
670 return newNode(AST_DO_STMT, pos,
671 "body", stmt,
672 "test", test,
673 dst);
676 bool
677 NodeBuilder::switchStatement(Value disc, NodeVector &elts, bool lexical, TokenPos *pos, Value *dst)
679 Value array;
680 return newArray(elts, &array) &&
681 newNode(AST_SWITCH_STMT, pos,
682 "discriminant", disc,
683 "cases", array,
684 "lexical", BooleanValue(lexical),
685 dst);
688 bool
689 NodeBuilder::tryStatement(Value body, NodeVector &catches, Value finally,
690 TokenPos *pos, Value *dst)
692 Value handler;
693 if (catches.empty())
694 handler.setNull();
695 else if (catches.length() == 1)
696 handler = catches[0];
697 else if (!newArray(catches, &handler))
698 return false;
700 return newNode(AST_TRY_STMT, pos,
701 "block", body,
702 "handler", handler,
703 "finalizer", finally,
704 dst);
707 bool
708 NodeBuilder::debuggerStatement(TokenPos *pos, Value *dst)
710 return newNode(AST_DEBUGGER_STMT, pos, dst);
713 bool
714 NodeBuilder::binaryExpression(BinaryOperator op, Value left, Value right, TokenPos *pos, Value *dst)
716 JS_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
718 Value opName;
720 return atomValue(binopNames[op], &opName) &&
721 newNode(AST_BINARY_EXPR, pos,
722 "operator", opName,
723 "left", left,
724 "right", right,
725 dst);
728 bool
729 NodeBuilder::unaryExpression(UnaryOperator unop, Value expr, TokenPos *pos, Value *dst)
731 JS_ASSERT(unop > UNOP_ERR && unop < UNOP_LIMIT);
733 Value opName;
735 return atomValue(unopNames[unop], &opName) &&
736 newNode(AST_UNARY_EXPR, pos,
737 "operator", opName,
738 "argument", expr,
739 "prefix", BooleanValue(true),
740 dst);
743 bool
744 NodeBuilder::assignmentExpression(AssignmentOperator aop, Value lhs, Value rhs,
745 TokenPos *pos, Value *dst)
747 JS_ASSERT(aop > AOP_ERR && aop < AOP_LIMIT);
749 Value opName;
751 return atomValue(aopNames[aop], &opName) &&
752 newNode(AST_ASSIGN_EXPR, pos,
753 "operator", opName,
754 "left", lhs,
755 "right", rhs,
756 dst);
759 bool
760 NodeBuilder::updateExpression(Value expr, bool incr, bool prefix, TokenPos *pos, Value *dst)
762 Value opName;
764 return atomValue(incr ? "++" : "--", &opName) &&
765 newNode(AST_UPDATE_EXPR, pos,
766 "operator", opName,
767 "argument", expr,
768 "prefix", BooleanValue(prefix),
769 dst);
772 bool
773 NodeBuilder::logicalExpression(bool lor, Value left, Value right, TokenPos *pos, Value *dst)
775 Value opName;
777 return atomValue(lor ? "||" : "&&", &opName) &&
778 newNode(AST_LOGICAL_EXPR, pos,
779 "operator", opName,
780 "left", left,
781 "right", right,
782 dst);
785 bool
786 NodeBuilder::conditionalExpression(Value test, Value cons, Value alt, TokenPos *pos, Value *dst)
788 return newNode(AST_COND_EXPR, pos,
789 "test", test,
790 "consequent", cons,
791 "alternate", alt,
792 dst);
795 bool
796 NodeBuilder::sequenceExpression(NodeVector &elts, TokenPos *pos, Value *dst)
798 return newListNode(AST_LIST_EXPR, pos,
799 "expressions", elts,
800 dst);
803 bool
804 NodeBuilder::callExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst)
806 Value array;
807 return newArray(args, &array) &&
808 newNode(AST_CALL_EXPR, pos,
809 "callee", callee,
810 "arguments", array,
811 dst);
814 bool
815 NodeBuilder::newExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst)
817 Value array;
818 return newArray(args, &array) &&
819 newNode(AST_NEW_EXPR, pos,
820 "callee", callee,
821 "arguments", array,
822 dst);
825 bool
826 NodeBuilder::memberExpression(bool computed, Value expr, Value member, TokenPos *pos, Value *dst)
828 return newNode(AST_MEMBER_EXPR, pos,
829 "object", expr,
830 "property", member,
831 "computed", BooleanValue(computed),
832 dst);
835 bool
836 NodeBuilder::arrayExpression(NodeVector &elts, TokenPos *pos, Value *dst)
838 return newListNode(AST_ARRAY_EXPR, pos,
839 "elements", elts,
840 dst);
843 bool
844 NodeBuilder::propertyPattern(Value key, Value patt, TokenPos *pos, Value *dst)
846 Value kindName;
848 return atomValue("init", &kindName) &&
849 newNode(AST_PROPERTY, pos,
850 "key", key,
851 "value", patt,
852 "kind", kindName,
853 dst);
856 bool
857 NodeBuilder::propertyInitializer(Value key, Value val, PropKind kind, TokenPos *pos, Value *dst)
859 Value kindName;
861 return atomValue(kind == PROP_INIT
862 ? "init"
863 : kind == PROP_GETTER
864 ? "get"
865 : "set", &kindName) &&
866 newNode(AST_PROPERTY, pos,
867 "key", key,
868 "value", val,
869 "kind", kindName,
870 dst);
873 bool
874 NodeBuilder::objectExpression(NodeVector &elts, TokenPos *pos, Value *dst)
876 return newListNode(AST_OBJECT_EXPR, pos, "properties", elts, dst);
879 bool
880 NodeBuilder::thisExpression(TokenPos *pos, Value *dst)
882 return newNode(AST_THIS_EXPR, pos, dst);
885 bool
886 NodeBuilder::yieldExpression(Value arg, TokenPos *pos, Value *dst)
888 return newNode(AST_YIELD_EXPR, pos, "argument", arg, dst);
891 bool
892 NodeBuilder::comprehensionBlock(Value patt, Value src, bool isForEach, TokenPos *pos, Value *dst)
894 return newNode(AST_COMP_BLOCK, pos,
895 "left", patt,
896 "right", src,
897 "each", BooleanValue(isForEach),
898 dst);
901 bool
902 NodeBuilder::comprehensionExpression(Value body, NodeVector &blocks, Value filter,
903 TokenPos *pos, Value *dst)
905 Value array;
907 return newArray(blocks, &array) &&
908 newNode(AST_COMP_EXPR, pos,
909 "body", body,
910 "blocks", array,
911 "filter", filter,
912 dst);
915 bool
916 NodeBuilder::generatorExpression(Value body, NodeVector &blocks, Value filter, TokenPos *pos, Value *dst)
918 Value array;
920 return newArray(blocks, &array) &&
921 newNode(AST_GENERATOR_EXPR, pos,
922 "body", body,
923 "blocks", array,
924 "filter", filter,
925 dst);
928 bool
929 NodeBuilder::graphExpression(jsint idx, Value expr, TokenPos *pos, Value *dst)
931 return newNode(AST_GRAPH_EXPR, pos,
932 "index", NumberValue(idx),
933 "expression", expr,
934 dst);
937 bool
938 NodeBuilder::graphIndexExpression(jsint idx, TokenPos *pos, Value *dst)
940 return newNode(AST_GRAPH_IDX_EXPR, pos, "index", NumberValue(idx), dst);
943 bool
944 NodeBuilder::variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos, Value *dst)
946 JS_ASSERT(kind > VARDECL_ERR && kind < VARDECL_LIMIT);
948 Value array, kindName;
950 return atomValue(kind == VARDECL_CONST
951 ? "const"
952 : kind == VARDECL_LET
953 ? "let"
954 : "var", &kindName) &&
955 newArray(elts, &array) &&
956 newNode(AST_VAR_DECL, pos,
957 "declarations", array,
958 "kind", kindName,
959 dst);
962 bool
963 NodeBuilder::variableDeclarator(Value id, Value init, TokenPos *pos, Value *dst)
965 return newNode(AST_VAR_DTOR, pos, "id", id, "init", init, dst);
968 bool
969 NodeBuilder::switchCase(Value expr, NodeVector &elts, TokenPos *pos, Value *dst)
971 Value array;
973 return newArray(elts, &array) &&
974 newNode(AST_CASE, pos,
975 "test", expr,
976 "consequent", array,
977 dst);
980 bool
981 NodeBuilder::catchClause(Value var, Value guard, Value body, TokenPos *pos, Value *dst)
983 return newNode(AST_CATCH, pos,
984 "param", var,
985 "guard", guard,
986 "body", body,
987 dst);
990 bool
991 NodeBuilder::literal(Value val, TokenPos *pos, Value *dst)
993 return newNode(AST_LITERAL, pos, "value", val, dst);
996 bool
997 NodeBuilder::identifier(Value name, TokenPos *pos, Value *dst)
999 return newNode(AST_IDENTIFIER, pos, "name", name, dst);
1002 bool
1003 NodeBuilder::objectPattern(NodeVector &elts, TokenPos *pos, Value *dst)
1005 return newListNode(AST_OBJECT_PATT, pos, "properties", elts, dst);
1008 bool
1009 NodeBuilder::arrayPattern(NodeVector &elts, TokenPos *pos, Value *dst)
1011 return newListNode(AST_ARRAY_PATT, pos, "elements", elts, dst);
1014 bool
1015 NodeBuilder::function(ASTType type, TokenPos *pos,
1016 Value id, NodeVector &args, Value body,
1017 bool isGenerator, bool isExpression,
1018 Value *dst)
1020 Value array;
1022 return newArray(args, &array) &&
1023 newNode(type, pos,
1024 "id", id,
1025 "params", array,
1026 "body", body,
1027 "generator", BooleanValue(isGenerator),
1028 "expression", BooleanValue(isExpression),
1029 dst);
1032 bool
1033 NodeBuilder::xmlAnyName(TokenPos *pos, Value *dst)
1035 return newNode(AST_XMLANYNAME, pos, dst);
1038 bool
1039 NodeBuilder::xmlEscapeExpression(Value expr, TokenPos *pos, Value *dst)
1041 return newNode(AST_XMLESCAPE, pos, "expression", expr, dst);
1044 bool
1045 NodeBuilder::xmlFilterExpression(Value left, Value right, TokenPos *pos, Value *dst)
1047 return newNode(AST_XMLFILTER, pos, "left", left, "right", right, dst);
1050 bool
1051 NodeBuilder::xmlDefaultNamespace(Value ns, TokenPos *pos, Value *dst)
1053 return newNode(AST_XMLDEFAULT, pos, "namespace", ns, dst);
1056 bool
1057 NodeBuilder::xmlAttributeSelector(Value expr, TokenPos *pos, Value *dst)
1059 return newNode(AST_XMLATTR_SEL, pos, "attribute", expr, dst);
1062 bool
1063 NodeBuilder::xmlQualifiedIdentifier(Value left, Value right, bool computed,
1064 TokenPos *pos, Value *dst)
1066 return newNode(AST_XMLQUAL, pos,
1067 "left", left,
1068 "right", right,
1069 "computed", BooleanValue(computed),
1070 dst);
1073 bool
1074 NodeBuilder::xmlElement(NodeVector &elts, TokenPos *pos, Value *dst)
1076 return newListNode(AST_XMLELEM, pos, "contents", elts, dst);
1079 bool
1080 NodeBuilder::xmlText(Value text, TokenPos *pos, Value *dst)
1082 return newNode(AST_XMLTEXT, pos, "text", text, dst);
1085 bool
1086 NodeBuilder::xmlList(NodeVector &elts, TokenPos *pos, Value *dst)
1088 return newListNode(AST_XMLLIST, pos, "contents", elts, dst);
1091 bool
1092 NodeBuilder::xmlStartTag(NodeVector &elts, TokenPos *pos, Value *dst)
1094 return newListNode(AST_XMLSTART, pos, "contents", elts, dst);
1097 bool
1098 NodeBuilder::xmlEndTag(NodeVector &elts, TokenPos *pos, Value *dst)
1100 return newListNode(AST_XMLEND, pos, "contents", elts, dst);
1103 bool
1104 NodeBuilder::xmlPointTag(NodeVector &elts, TokenPos *pos, Value *dst)
1106 return newListNode(AST_XMLPOINT, pos, "contents", elts, dst);
1109 bool
1110 NodeBuilder::xmlName(Value text, TokenPos *pos, Value *dst)
1112 return newNode(AST_XMLNAME, pos, "contents", text, dst);
1115 bool
1116 NodeBuilder::xmlName(NodeVector &elts, TokenPos *pos, Value *dst)
1118 return newListNode(AST_XMLNAME, pos, "contents", elts, dst);
1121 bool
1122 NodeBuilder::xmlAttribute(Value text, TokenPos *pos, Value *dst)
1124 return newNode(AST_XMLATTR, pos, "value", text, dst);
1127 bool
1128 NodeBuilder::xmlCdata(Value text, TokenPos *pos, Value *dst)
1130 return newNode(AST_XMLCDATA, pos, "contents", text, dst);
1133 bool
1134 NodeBuilder::xmlComment(Value text, TokenPos *pos, Value *dst)
1136 return newNode(AST_XMLCOMMENT, pos, "contents", text, dst);
1139 bool
1140 NodeBuilder::xmlPI(Value target, TokenPos *pos, Value *dst)
1142 return xmlPI(target, NullValue(), pos, dst);
1145 bool
1146 NodeBuilder::xmlPI(Value target, Value contents, TokenPos *pos, Value *dst)
1148 return newNode(AST_XMLPI, pos,
1149 "target", target,
1150 "contents", contents,
1151 dst);
1156 * Serialization of parse nodes to JavaScript objects.
1158 * All serialization methods take a non-nullable JSParseNode pointer.
1161 class ASTSerializer
1163 JSContext *cx;
1164 NodeBuilder builder;
1165 uintN lineno;
1167 Value atomContents(JSAtom *atom) {
1168 return Valueify(ATOM_TO_JSVAL(atom ? atom : cx->runtime->atomState.emptyAtom));
1171 BinaryOperator binop(TokenKind tk, JSOp op);
1172 UnaryOperator unop(TokenKind tk, JSOp op);
1173 AssignmentOperator aop(JSOp op);
1175 bool statements(JSParseNode *pn, NodeVector &elts);
1176 bool expressions(JSParseNode *pn, NodeVector &elts);
1177 bool xmls(JSParseNode *pn, NodeVector &elts);
1178 bool leftAssociate(JSParseNode *pn, Value *dst);
1179 bool binaryOperands(JSParseNode *pn, NodeVector &elts);
1180 bool functionArgs(JSParseNode *pn, JSParseNode *pnargs, JSParseNode *pndestruct,
1181 JSParseNode *pnbody, NodeVector &args);
1183 bool sourceElement(JSParseNode *pn, Value *dst);
1185 bool declaration(JSParseNode *pn, Value *dst);
1186 bool variableDeclaration(JSParseNode *pn, bool let, Value *dst);
1187 bool variableDeclarator(JSParseNode *pn, VarDeclKind *pkind, Value *dst);
1189 bool optStatement(JSParseNode *pn, Value *dst) {
1190 if (!pn) {
1191 dst->setMagic(JS_SERIALIZE_NO_NODE);
1192 return true;
1194 return statement(pn, dst);
1197 bool forInit(JSParseNode *pn, Value *dst);
1198 bool statement(JSParseNode *pn, Value *dst);
1199 bool blockStatement(JSParseNode *pn, Value *dst);
1200 bool switchStatement(JSParseNode *pn, Value *dst);
1201 bool switchCase(JSParseNode *pn, Value *dst);
1202 bool tryStatement(JSParseNode *pn, Value *dst);
1203 bool catchClause(JSParseNode *pn, Value *dst);
1205 bool optExpression(JSParseNode *pn, Value *dst) {
1206 if (!pn) {
1207 dst->setMagic(JS_SERIALIZE_NO_NODE);
1208 return true;
1210 return expression(pn, dst);
1213 bool expression(JSParseNode *pn, Value *dst);
1215 bool propertyName(JSParseNode *pn, Value *dst);
1216 bool property(JSParseNode *pn, Value *dst);
1218 bool optIdentifier(JSAtom *atom, TokenPos *pos, Value *dst) {
1219 if (!atom) {
1220 dst->setMagic(JS_SERIALIZE_NO_NODE);
1221 return true;
1223 return identifier(atom, pos, dst);
1226 bool identifier(JSAtom *atom, TokenPos *pos, Value *dst);
1227 bool identifier(JSParseNode *pn, Value *dst);
1228 bool literal(JSParseNode *pn, Value *dst);
1230 bool pattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst);
1231 bool arrayPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst);
1232 bool objectPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst);
1234 bool function(JSParseNode *pn, ASTType type, Value *dst);
1235 bool functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *body);
1236 bool functionBody(JSParseNode *pn, TokenPos *pos, Value *dst);
1238 bool comprehensionBlock(JSParseNode *pn, Value *dst);
1239 bool comprehension(JSParseNode *pn, Value *dst);
1240 bool generatorExpression(JSParseNode *pn, Value *dst);
1242 bool xml(JSParseNode *pn, Value *dst);
1244 public:
1245 ASTSerializer(JSContext *c, char const *src, uintN ln)
1246 : cx(c), builder(c, src), lineno(ln) {
1249 bool init() {
1250 return builder.init();
1253 bool program(JSParseNode *pn, Value *dst);
1256 AssignmentOperator
1257 ASTSerializer::aop(JSOp op)
1259 switch (op) {
1260 case JSOP_NOP:
1261 return AOP_ASSIGN;
1262 case JSOP_ADD:
1263 return AOP_PLUS;
1264 case JSOP_SUB:
1265 return AOP_MINUS;
1266 case JSOP_MUL:
1267 return AOP_STAR;
1268 case JSOP_DIV:
1269 return AOP_DIV;
1270 case JSOP_MOD:
1271 return AOP_MOD;
1272 case JSOP_LSH:
1273 return AOP_LSH;
1274 case JSOP_RSH:
1275 return AOP_RSH;
1276 case JSOP_URSH:
1277 return AOP_URSH;
1278 case JSOP_BITOR:
1279 return AOP_BITOR;
1280 case JSOP_BITXOR:
1281 return AOP_BITXOR;
1282 case JSOP_BITAND:
1283 return AOP_BITAND;
1284 default:
1285 return AOP_ERR;
1289 UnaryOperator
1290 ASTSerializer::unop(TokenKind tk, JSOp op)
1292 if (tk == TOK_DELETE)
1293 return UNOP_DELETE;
1295 switch (op) {
1296 case JSOP_NEG:
1297 return UNOP_NEG;
1298 case JSOP_POS:
1299 return UNOP_POS;
1300 case JSOP_NOT:
1301 return UNOP_NOT;
1302 case JSOP_BITNOT:
1303 return UNOP_BITNOT;
1304 case JSOP_TYPEOF:
1305 case JSOP_TYPEOFEXPR:
1306 return UNOP_TYPEOF;
1307 case JSOP_VOID:
1308 return UNOP_VOID;
1309 default:
1310 return UNOP_ERR;
1314 BinaryOperator
1315 ASTSerializer::binop(TokenKind tk, JSOp op)
1317 switch (tk) {
1318 case TOK_EQOP:
1319 switch (op) {
1320 case JSOP_EQ:
1321 return BINOP_EQ;
1322 case JSOP_NE:
1323 return BINOP_NE;
1324 case JSOP_STRICTEQ:
1325 return BINOP_STRICTEQ;
1326 case JSOP_STRICTNE:
1327 return BINOP_STRICTNE;
1328 default:
1329 return BINOP_ERR;
1332 case TOK_RELOP:
1333 switch (op) {
1334 case JSOP_LT:
1335 return BINOP_LT;
1336 case JSOP_LE:
1337 return BINOP_LE;
1338 case JSOP_GT:
1339 return BINOP_GT;
1340 case JSOP_GE:
1341 return BINOP_GE;
1342 default:
1343 return BINOP_ERR;
1346 case TOK_SHOP:
1347 switch (op) {
1348 case JSOP_LSH:
1349 return BINOP_LSH;
1350 case JSOP_RSH:
1351 return BINOP_RSH;
1352 case JSOP_URSH:
1353 return BINOP_URSH;
1354 default:
1355 return BINOP_ERR;
1358 case TOK_PLUS:
1359 return BINOP_PLUS;
1360 case TOK_MINUS:
1361 return BINOP_MINUS;
1362 case TOK_STAR:
1363 return BINOP_STAR;
1364 case TOK_DIVOP:
1365 return (op == JSOP_MOD) ? BINOP_MOD : BINOP_DIV;
1366 case TOK_BITOR:
1367 return BINOP_BITOR;
1368 case TOK_BITXOR:
1369 return BINOP_BITXOR;
1370 case TOK_BITAND:
1371 return BINOP_BITAND;
1372 case TOK_IN:
1373 return BINOP_IN;
1374 case TOK_INSTANCEOF:
1375 return BINOP_INSTANCEOF;
1376 case TOK_DBLDOT:
1377 return BINOP_DBLDOT;
1378 default:
1379 return BINOP_ERR;
1383 bool
1384 ASTSerializer::statements(JSParseNode *pn, NodeVector &elts)
1386 JS_ASSERT(PN_TYPE(pn) == TOK_LC && pn->pn_arity == PN_LIST);
1388 if (!elts.reserve(pn->pn_count))
1389 return false;
1391 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
1392 Value elt;
1393 if (!sourceElement(next, &elt))
1394 return false;
1395 (void)elts.append(elt); /* space check above */
1398 return true;
1401 bool
1402 ASTSerializer::expressions(JSParseNode *pn, NodeVector &elts)
1404 if (!elts.reserve(pn->pn_count))
1405 return false;
1407 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
1408 Value elt;
1409 if (!expression(next, &elt))
1410 return false;
1411 (void)elts.append(elt); /* space check above */
1414 return true;
1417 bool
1418 ASTSerializer::xmls(JSParseNode *pn, NodeVector &elts)
1420 if (!elts.reserve(pn->pn_count))
1421 return false;
1423 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
1424 Value elt;
1425 if (!xml(next, &elt))
1426 return false;
1427 (void)elts.append(elt); /* space check above */
1430 return true;
1433 bool
1434 ASTSerializer::blockStatement(JSParseNode *pn, Value *dst)
1436 JS_ASSERT(PN_TYPE(pn) == TOK_LC);
1438 NodeVector stmts(cx);
1439 return statements(pn, stmts) &&
1440 builder.blockStatement(stmts, &pn->pn_pos, dst);
1443 bool
1444 ASTSerializer::program(JSParseNode *pn, Value *dst)
1446 JS_ASSERT(pn);
1448 /* Workaround for bug 588061: parser's reported start position is always 0:0. */
1449 pn->pn_pos.begin.lineno = lineno;
1451 NodeVector stmts(cx);
1452 return statements(pn, stmts) &&
1453 builder.program(stmts, &pn->pn_pos, dst);
1456 bool
1457 ASTSerializer::sourceElement(JSParseNode *pn, Value *dst)
1459 /* SpiderMonkey allows declarations even in pure statement contexts. */
1460 return statement(pn, dst);
1463 bool
1464 ASTSerializer::declaration(JSParseNode *pn, Value *dst)
1466 JS_ASSERT(PN_TYPE(pn) == TOK_FUNCTION ||
1467 PN_TYPE(pn) == TOK_VAR ||
1468 PN_TYPE(pn) == TOK_LET);
1470 switch (PN_TYPE(pn)) {
1471 case TOK_FUNCTION:
1472 return function(pn, AST_FUNC_DECL, dst);
1474 case TOK_VAR:
1475 return variableDeclaration(pn, false, dst);
1477 default:
1478 JS_ASSERT(PN_TYPE(pn) == TOK_LET);
1479 return variableDeclaration(pn, true, dst);
1483 bool
1484 ASTSerializer::variableDeclaration(JSParseNode *pn, bool let, Value *dst)
1486 JS_ASSERT(let ? PN_TYPE(pn) == TOK_LET : PN_TYPE(pn) == TOK_VAR);
1488 /* Later updated to VARDECL_CONST if we find a PND_CONST declarator. */
1489 VarDeclKind kind = let ? VARDECL_LET : VARDECL_VAR;
1491 NodeVector dtors(cx);
1492 if (!dtors.reserve(pn->pn_count))
1493 return false;
1495 /* In a for-in context, variable declarations contain just a single pattern. */
1496 if (pn->pn_xflags & PNX_FORINVAR) {
1497 Value patt, child;
1498 return pattern(pn->pn_head, &kind, &patt) &&
1499 builder.variableDeclarator(patt, NullValue(), &pn->pn_head->pn_pos, &child) &&
1500 dtors.append(child) &&
1501 builder.variableDeclaration(dtors, kind, &pn->pn_pos, dst);
1504 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
1505 Value child;
1506 if (!variableDeclarator(next, &kind, &child))
1507 return false;
1508 (void)dtors.append(child); /* space check above */
1511 return builder.variableDeclaration(dtors, kind, &pn->pn_pos, dst);
1514 bool
1515 ASTSerializer::variableDeclarator(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
1517 /* A destructuring declarator is always a TOK_ASSIGN. */
1518 JS_ASSERT(PN_TYPE(pn) == TOK_NAME || PN_TYPE(pn) == TOK_ASSIGN);
1520 JSParseNode *pnleft;
1521 JSParseNode *pnright;
1523 if (PN_TYPE(pn) == TOK_NAME) {
1524 pnleft = pn;
1525 pnright = pn->pn_expr;
1526 } else {
1527 JS_ASSERT(PN_TYPE(pn) == TOK_ASSIGN);
1528 pnleft = pn->pn_left;
1529 pnright = pn->pn_right;
1532 Value left, right;
1533 return pattern(pnleft, pkind, &left) &&
1534 optExpression(pnright, &right) &&
1535 builder.variableDeclarator(left, right, &pn->pn_pos, dst);
1538 bool
1539 ASTSerializer::switchCase(JSParseNode *pn, Value *dst)
1541 NodeVector stmts(cx);
1543 Value expr;
1545 return optExpression(pn->pn_left, &expr) &&
1546 statements(pn->pn_right, stmts) &&
1547 builder.switchCase(expr, stmts, &pn->pn_pos, dst);
1550 bool
1551 ASTSerializer::switchStatement(JSParseNode *pn, Value *dst)
1553 Value disc;
1555 if (!expression(pn->pn_left, &disc))
1556 return false;
1558 JSParseNode *listNode;
1559 bool lexical;
1561 if (PN_TYPE(pn->pn_right) == TOK_LEXICALSCOPE) {
1562 listNode = pn->pn_right->pn_expr;
1563 lexical = true;
1564 } else {
1565 listNode = pn->pn_right;
1566 lexical = false;
1569 NodeVector cases(cx);
1570 if (!cases.reserve(listNode->pn_count))
1571 return false;
1573 for (JSParseNode *next = listNode->pn_head; next; next = next->pn_next) {
1574 Value child;
1575 if (!switchCase(next, &child))
1576 return false;
1577 (void)cases.append(child); /* space check above */
1580 return builder.switchStatement(disc, cases, lexical, &pn->pn_pos, dst);
1583 bool
1584 ASTSerializer::catchClause(JSParseNode *pn, Value *dst)
1586 Value var, guard, body;
1588 return pattern(pn->pn_kid1, NULL, &var) &&
1589 optExpression(pn->pn_kid2, &guard) &&
1590 statement(pn->pn_kid3, &body) &&
1591 builder.catchClause(var, guard, body, &pn->pn_pos, dst);
1594 bool
1595 ASTSerializer::tryStatement(JSParseNode *pn, Value *dst)
1597 Value body;
1598 if (!statement(pn->pn_kid1, &body))
1599 return false;
1601 NodeVector clauses(cx);
1602 if (pn->pn_kid2) {
1603 if (!clauses.reserve(pn->pn_kid2->pn_count))
1604 return false;
1606 for (JSParseNode *next = pn->pn_kid2->pn_head; next; next = next->pn_next) {
1607 Value clause;
1608 if (!catchClause(next->pn_expr, &clause))
1609 return false;
1610 (void)clauses.append(clause); /* space check above */
1614 Value finally;
1615 return optStatement(pn->pn_kid3, &finally) &&
1616 builder.tryStatement(body, clauses, finally, &pn->pn_pos, dst);
1619 bool
1620 ASTSerializer::forInit(JSParseNode *pn, Value *dst)
1622 if (!pn) {
1623 dst->setMagic(JS_SERIALIZE_NO_NODE);
1624 return true;
1627 return (PN_TYPE(pn) == TOK_VAR)
1628 ? variableDeclaration(pn, false, dst)
1629 : (PN_TYPE(pn) == TOK_LET)
1630 ? variableDeclaration(pn, true, dst)
1631 : expression(pn, dst);
1634 bool
1635 ASTSerializer::statement(JSParseNode *pn, Value *dst)
1637 switch (PN_TYPE(pn)) {
1638 case TOK_FUNCTION:
1639 case TOK_VAR:
1640 case TOK_LET:
1641 return declaration(pn, dst);
1643 case TOK_SEMI:
1644 if (pn->pn_kid) {
1645 Value expr;
1646 return expression(pn->pn_kid, &expr) &&
1647 builder.expressionStatement(expr, &pn->pn_pos, dst);
1649 return builder.emptyStatement(&pn->pn_pos, dst);
1651 case TOK_LEXICALSCOPE:
1652 pn = pn->pn_expr;
1653 if (PN_TYPE(pn) != TOK_LC)
1654 return statement(pn, dst);
1655 /* FALL THROUGH */
1657 case TOK_LC:
1658 return blockStatement(pn, dst);
1660 case TOK_IF:
1662 Value test, cons, alt;
1664 return expression(pn->pn_kid1, &test) &&
1665 statement(pn->pn_kid2, &cons) &&
1666 optStatement(pn->pn_kid3, &alt) &&
1667 builder.ifStatement(test, cons, alt, &pn->pn_pos, dst);
1670 case TOK_SWITCH:
1671 return switchStatement(pn, dst);
1673 case TOK_TRY:
1674 return tryStatement(pn, dst);
1676 case TOK_WITH:
1677 case TOK_WHILE:
1679 Value expr, stmt;
1681 return expression(pn->pn_left, &expr) &&
1682 statement(pn->pn_right, &stmt) &&
1683 (PN_TYPE(pn) == TOK_WITH)
1684 ? builder.withStatement(expr, stmt, &pn->pn_pos, dst)
1685 : builder.whileStatement(expr, stmt, &pn->pn_pos, dst);
1688 case TOK_DO:
1690 Value stmt, test;
1692 return statement(pn->pn_left, &stmt) &&
1693 expression(pn->pn_right, &test) &&
1694 builder.doWhileStatement(stmt, test, &pn->pn_pos, dst);
1697 case TOK_FOR:
1699 JSParseNode *head = pn->pn_left;
1701 Value stmt;
1702 if (!statement(pn->pn_right, &stmt))
1703 return false;
1705 bool isForEach = pn->pn_iflags & JSITER_FOREACH;
1707 if (PN_TYPE(head) == TOK_IN) {
1708 Value var, expr;
1710 return (PN_TYPE(head->pn_left) == TOK_VAR
1711 ? variableDeclaration(head->pn_left, false, &var)
1712 : PN_TYPE(head->pn_left) == TOK_LET
1713 ? variableDeclaration(head->pn_left, true, &var)
1714 : pattern(head->pn_left, NULL, &var)) &&
1715 expression(head->pn_right, &expr) &&
1716 builder.forInStatement(var, expr, stmt, isForEach, &pn->pn_pos, dst);
1719 Value init, test, update;
1721 return forInit(head->pn_kid1, &init) &&
1722 optExpression(head->pn_kid2, &test) &&
1723 optExpression(head->pn_kid3, &update) &&
1724 builder.forStatement(init, test, update, stmt, &pn->pn_pos, dst);
1727 case TOK_BREAK:
1728 case TOK_CONTINUE:
1730 Value label;
1732 return optIdentifier(pn->pn_atom, NULL, &label) &&
1733 (PN_TYPE(pn) == TOK_BREAK
1734 ? builder.breakStatement(label, &pn->pn_pos, dst)
1735 : builder.continueStatement(label, &pn->pn_pos, dst));
1738 case TOK_COLON:
1740 Value label, stmt;
1742 return identifier(pn->pn_atom, NULL, &label) &&
1743 statement(pn->pn_expr, &stmt) &&
1744 builder.labeledStatement(label, stmt, &pn->pn_pos, dst);
1747 case TOK_THROW:
1748 case TOK_RETURN:
1750 Value arg;
1752 return optExpression(pn->pn_kid, &arg) &&
1753 (PN_TYPE(pn) == TOK_THROW
1754 ? builder.throwStatement(arg, &pn->pn_pos, dst)
1755 : builder.returnStatement(arg, &pn->pn_pos, dst));
1758 case TOK_DEBUGGER:
1759 return builder.debuggerStatement(&pn->pn_pos, dst);
1761 #if JS_HAS_XML_SUPPORT
1762 case TOK_DEFAULT:
1764 LOCAL_ASSERT(pn->pn_arity == PN_UNARY && PN_TYPE(pn->pn_kid) == TOK_STRING);
1766 Value ns;
1768 return literal(pn->pn_kid, &ns) &&
1769 builder.xmlDefaultNamespace(ns, &pn->pn_pos, dst);
1771 #endif
1773 default:
1774 LOCAL_NOT_REACHED("unexpected statement type");
1778 bool
1779 ASTSerializer::leftAssociate(JSParseNode *pn, Value *dst)
1781 JS_ASSERT(pn->pn_arity == PN_LIST);
1783 const size_t len = pn->pn_count;
1784 JS_ASSERT(len >= 1);
1786 if (len == 1)
1787 return expression(pn->pn_head, dst);
1789 JS_ASSERT(len >= 2);
1791 Vector<JSParseNode *, 8> list(cx);
1792 if (!list.reserve(len))
1793 return false;
1795 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
1796 (void)list.append(next); /* space check above */
1799 TokenKind tk = PN_TYPE(pn);
1801 bool lor = tk == TOK_OR;
1802 bool logop = lor || (tk == TOK_AND);
1804 Value right;
1806 if (!expression(list[len - 1], &right))
1807 return false;
1809 size_t i = len - 2;
1811 do {
1812 JSParseNode *next = list[i];
1814 Value left;
1815 if (!expression(next, &left))
1816 return false;
1818 TokenPos subpos = { next->pn_pos.begin, pn->pn_pos.end };
1820 if (logop) {
1821 if (!builder.logicalExpression(lor, left, right, &subpos, &right))
1822 return false;
1823 } else {
1824 BinaryOperator op = binop(PN_TYPE(pn), PN_OP(pn));
1825 LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
1827 if (!builder.binaryExpression(op, left, right, &subpos, &right))
1828 return false;
1830 } while (i-- != 0);
1832 *dst = right;
1833 return true;
1836 bool
1837 ASTSerializer::binaryOperands(JSParseNode *pn, NodeVector &elts)
1839 if (pn->pn_arity == PN_BINARY) {
1840 Value left, right;
1842 return expression(pn->pn_left, &left) &&
1843 elts.append(left) &&
1844 expression(pn->pn_right, &right) &&
1845 elts.append(right);
1848 LOCAL_ASSERT(pn->pn_arity == PN_LIST);
1850 return expressions(pn, elts);
1853 bool
1854 ASTSerializer::comprehensionBlock(JSParseNode *pn, Value *dst)
1856 LOCAL_ASSERT(pn->pn_arity == PN_BINARY);
1858 JSParseNode *in = pn->pn_left;
1860 LOCAL_ASSERT(in && PN_TYPE(in) == TOK_IN);
1862 bool isForEach = pn->pn_iflags & JSITER_FOREACH;
1864 Value patt, src;
1865 return pattern(in->pn_left, NULL, &patt) &&
1866 expression(in->pn_right, &src) &&
1867 builder.comprehensionBlock(patt, src, isForEach, &in->pn_pos, dst);
1870 bool
1871 ASTSerializer::comprehension(JSParseNode *pn, Value *dst)
1873 LOCAL_ASSERT(PN_TYPE(pn) == TOK_FOR);
1875 NodeVector blocks(cx);
1877 JSParseNode *next = pn;
1878 while (PN_TYPE(next) == TOK_FOR) {
1879 Value block;
1880 if (!comprehensionBlock(next, &block) ||
1881 !blocks.append(block))
1882 return false;
1883 next = next->pn_right;
1886 Value filter = MagicValue(JS_SERIALIZE_NO_NODE);
1888 if (PN_TYPE(next) == TOK_IF) {
1889 if (!optExpression(next->pn_kid1, &filter))
1890 return false;
1891 next = next->pn_kid2;
1892 } else if (PN_TYPE(next) == TOK_LC && next->pn_count == 0) {
1893 /* js_FoldConstants optimized away the push. */
1894 NodeVector empty(cx);
1895 return builder.arrayExpression(empty, &pn->pn_pos, dst);
1898 LOCAL_ASSERT(PN_TYPE(next) == TOK_ARRAYPUSH);
1900 Value body;
1902 return expression(next->pn_kid, &body) &&
1903 builder.comprehensionExpression(body, blocks, filter, &pn->pn_pos, dst);
1906 bool
1907 ASTSerializer::generatorExpression(JSParseNode *pn, Value *dst)
1909 LOCAL_ASSERT(PN_TYPE(pn) == TOK_FOR);
1911 NodeVector blocks(cx);
1913 JSParseNode *next = pn;
1914 while (PN_TYPE(next) == TOK_FOR) {
1915 Value block;
1916 if (!comprehensionBlock(next, &block) ||
1917 !blocks.append(block))
1918 return false;
1919 next = next->pn_right;
1922 Value filter = MagicValue(JS_SERIALIZE_NO_NODE);
1924 if (PN_TYPE(next) == TOK_IF) {
1925 if (!optExpression(next->pn_kid1, &filter))
1926 return false;
1927 next = next->pn_kid2;
1930 LOCAL_ASSERT(PN_TYPE(next) == TOK_SEMI &&
1931 PN_TYPE(next->pn_kid) == TOK_YIELD &&
1932 next->pn_kid->pn_kid);
1934 Value body;
1936 return expression(next->pn_kid->pn_kid, &body) &&
1937 builder.generatorExpression(body, blocks, filter, &pn->pn_pos, dst);
1940 bool
1941 ASTSerializer::expression(JSParseNode *pn, Value *dst)
1943 switch (PN_TYPE(pn)) {
1944 case TOK_FUNCTION:
1945 return function(pn, AST_FUNC_EXPR, dst);
1947 case TOK_COMMA:
1949 NodeVector exprs(cx);
1950 return expressions(pn, exprs) &&
1951 builder.sequenceExpression(exprs, &pn->pn_pos, dst);
1954 case TOK_HOOK:
1956 Value test, cons, alt;
1958 return expression(pn->pn_kid1, &test) &&
1959 expression(pn->pn_kid2, &cons) &&
1960 expression(pn->pn_kid3, &alt) &&
1961 builder.conditionalExpression(test, cons, alt, &pn->pn_pos, dst);
1964 case TOK_OR:
1965 case TOK_AND:
1967 if (pn->pn_arity == PN_BINARY) {
1968 Value left, right;
1969 return expression(pn->pn_left, &left) &&
1970 expression(pn->pn_right, &right) &&
1971 builder.logicalExpression(PN_TYPE(pn) == TOK_OR, left, right, &pn->pn_pos, dst);
1973 return leftAssociate(pn, dst);
1976 case TOK_INC:
1977 case TOK_DEC:
1979 bool incr = PN_TYPE(pn) == TOK_INC;
1980 bool prefix = PN_OP(pn) >= JSOP_INCNAME && PN_OP(pn) <= JSOP_DECELEM;
1982 Value expr;
1983 return expression(pn->pn_kid, &expr) &&
1984 builder.updateExpression(expr, incr, prefix, &pn->pn_pos, dst);
1987 case TOK_ASSIGN:
1989 AssignmentOperator op = aop(PN_OP(pn));
1990 LOCAL_ASSERT(op > AOP_ERR && op < AOP_LIMIT);
1992 Value lhs, rhs;
1993 return pattern(pn->pn_left, NULL, &lhs) &&
1994 expression(pn->pn_right, &rhs) &&
1995 builder.assignmentExpression(op, lhs, rhs, &pn->pn_pos, dst);
1998 case TOK_EQOP:
1999 case TOK_RELOP:
2000 case TOK_SHOP:
2001 case TOK_PLUS:
2002 case TOK_MINUS:
2003 case TOK_STAR:
2004 case TOK_DIVOP:
2005 case TOK_BITOR:
2006 case TOK_BITXOR:
2007 case TOK_BITAND:
2008 case TOK_IN:
2009 case TOK_INSTANCEOF:
2010 case TOK_DBLDOT:
2011 if (pn->pn_arity == PN_BINARY) {
2012 BinaryOperator op = binop(PN_TYPE(pn), PN_OP(pn));
2013 LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
2015 Value left, right;
2016 return expression(pn->pn_left, &left) &&
2017 expression(pn->pn_right, &right) &&
2018 builder.binaryExpression(op, left, right, &pn->pn_pos, dst);
2020 return leftAssociate(pn, dst);
2022 case TOK_DELETE:
2023 case TOK_UNARYOP:
2024 #if JS_HAS_XML_SUPPORT
2025 if (PN_OP(pn) == JSOP_XMLNAME)
2026 return expression(pn->pn_kid, dst);
2027 #endif
2030 UnaryOperator op = unop(PN_TYPE(pn), PN_OP(pn));
2031 LOCAL_ASSERT(op > UNOP_ERR && op < UNOP_LIMIT);
2033 Value expr;
2034 return expression(pn->pn_kid, &expr) &&
2035 builder.unaryExpression(op, expr, &pn->pn_pos, dst);
2038 case TOK_NEW:
2039 case TOK_LP:
2041 #ifdef JS_HAS_GENERATOR_EXPRS
2042 if (pn->isGeneratorExpr())
2043 return generatorExpression(pn->generatorExpr(), dst);
2044 #endif
2046 JSParseNode *next = pn->pn_head;
2048 Value callee;
2049 if (!expression(next, &callee))
2050 return false;
2052 NodeVector args(cx);
2053 if (!args.reserve(pn->pn_count - 1))
2054 return false;
2056 for (next = next->pn_next; next; next = next->pn_next) {
2057 Value arg;
2058 if (!expression(next, &arg))
2059 return false;
2060 (void)args.append(arg); /* space check above */
2063 return PN_TYPE(pn) == TOK_NEW
2064 ? builder.newExpression(callee, args, &pn->pn_pos, dst)
2065 : builder.callExpression(callee, args, &pn->pn_pos, dst);
2068 case TOK_DOT:
2070 Value expr, id;
2071 return expression(pn->pn_expr, &expr) &&
2072 identifier(pn->pn_atom, NULL, &id) &&
2073 builder.memberExpression(false, expr, id, &pn->pn_pos, dst);
2076 case TOK_LB:
2078 Value left, right;
2079 return expression(pn->pn_left, &left) &&
2080 expression(pn->pn_right, &right) &&
2081 builder.memberExpression(true, left, right, &pn->pn_pos, dst);
2084 case TOK_RB:
2086 NodeVector elts(cx);
2087 if (!elts.reserve(pn->pn_count))
2088 return false;
2090 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
2091 if (PN_TYPE(next) == TOK_COMMA) {
2092 (void)elts.append(MagicValue(JS_SERIALIZE_NO_NODE)); /* space check above */
2093 } else {
2094 Value expr;
2095 if (!expression(next, &expr))
2096 return false;
2097 (void)elts.append(expr); /* space check above */
2101 return builder.arrayExpression(elts, &pn->pn_pos, dst);
2104 case TOK_RC:
2106 NodeVector elts(cx);
2107 if (!elts.reserve(pn->pn_count))
2108 return false;
2110 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
2111 Value prop;
2112 if (!property(next, &prop))
2113 return false;
2114 (void)elts.append(prop); /* space check above */
2117 return builder.objectExpression(elts, &pn->pn_pos, dst);
2120 case TOK_NAME:
2121 return identifier(pn, dst);
2123 case TOK_STRING:
2124 case TOK_REGEXP:
2125 case TOK_NUMBER:
2126 case TOK_PRIMARY:
2127 return PN_OP(pn) == JSOP_THIS ? builder.thisExpression(&pn->pn_pos, dst) : literal(pn, dst);
2129 case TOK_YIELD:
2131 Value arg;
2132 return optExpression(pn->pn_kid, &arg) &&
2133 builder.yieldExpression(arg, &pn->pn_pos, dst);
2136 case TOK_DEFSHARP:
2138 Value expr;
2139 return expression(pn->pn_kid, &expr) &&
2140 builder.graphExpression(pn->pn_num, expr, &pn->pn_pos, dst);
2143 case TOK_USESHARP:
2144 return builder.graphIndexExpression(pn->pn_num, &pn->pn_pos, dst);
2146 case TOK_ARRAYCOMP:
2147 /* NB: it's no longer the case that pn_count could be 2. */
2148 LOCAL_ASSERT(pn->pn_count == 1);
2149 LOCAL_ASSERT(PN_TYPE(pn->pn_head) == TOK_LEXICALSCOPE);
2151 return comprehension(pn->pn_head->pn_expr, dst);
2153 #ifdef JS_HAS_XML_SUPPORT
2154 case TOK_ANYNAME:
2155 return builder.xmlAnyName(&pn->pn_pos, dst);
2157 case TOK_DBLCOLON:
2159 Value left, right;
2161 LOCAL_ASSERT(pn->pn_arity == PN_NAME || pn->pn_arity == PN_BINARY);
2163 bool computed = pn->pn_arity == PN_BINARY;
2165 return (computed
2166 ? (expression(pn->pn_left, &left) &&
2167 expression(pn->pn_right, &right))
2168 : (expression(pn->pn_expr, &left) &&
2169 identifier(pn->pn_atom, NULL, &right))) &&
2170 builder.xmlQualifiedIdentifier(left, right, computed,
2171 &pn->pn_pos, dst);
2174 case TOK_AT:
2176 Value expr;
2177 return expression(pn->pn_kid, &expr) &&
2178 builder.xmlAttributeSelector(expr, &pn->pn_pos, dst);
2181 case TOK_FILTER:
2183 Value left, right;
2184 return expression(pn->pn_left, &left) &&
2185 expression(pn->pn_right, &right) &&
2186 builder.xmlFilterExpression(left, right, &pn->pn_pos, dst);
2189 default:
2190 return xml(pn, dst);
2192 #else
2193 default:
2194 LOCAL_NOT_REACHED("unexpected expression type");
2195 #endif
2199 bool
2200 ASTSerializer::xml(JSParseNode *pn, Value *dst)
2202 switch (PN_TYPE(pn)) {
2203 #ifdef JS_HAS_XML_SUPPORT
2204 case TOK_LC:
2206 Value expr;
2207 return expression(pn->pn_kid, &expr) &&
2208 builder.xmlEscapeExpression(expr, &pn->pn_pos, dst);
2211 case TOK_XMLELEM:
2213 NodeVector elts(cx);
2214 if (!xmls(pn, elts))
2215 return false;
2216 return builder.xmlElement(elts, &pn->pn_pos, dst);
2219 case TOK_XMLLIST:
2221 NodeVector elts(cx);
2222 if (!xmls(pn, elts))
2223 return false;
2224 return builder.xmlList(elts, &pn->pn_pos, dst);
2227 case TOK_XMLSTAGO:
2229 NodeVector elts(cx);
2230 if (!xmls(pn, elts))
2231 return false;
2232 return builder.xmlStartTag(elts, &pn->pn_pos, dst);
2235 case TOK_XMLETAGO:
2237 NodeVector elts(cx);
2238 if (!xmls(pn, elts))
2239 return false;
2240 return builder.xmlEndTag(elts, &pn->pn_pos, dst);
2243 case TOK_XMLPTAGC:
2245 NodeVector elts(cx);
2246 if (!xmls(pn, elts))
2247 return false;
2248 return builder.xmlPointTag(elts, &pn->pn_pos, dst);
2251 case TOK_XMLTEXT:
2252 return builder.xmlText(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2254 case TOK_XMLNAME:
2255 if (pn->pn_arity == PN_NULLARY)
2256 return builder.xmlName(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2258 LOCAL_ASSERT(pn->pn_arity == PN_LIST);
2261 NodeVector elts(cx);
2262 return xmls(pn, elts) &&
2263 builder.xmlName(elts, &pn->pn_pos, dst);
2266 case TOK_XMLATTR:
2267 return builder.xmlAttribute(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2269 case TOK_XMLCDATA:
2270 return builder.xmlCdata(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2272 case TOK_XMLCOMMENT:
2273 return builder.xmlComment(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2275 case TOK_XMLPI:
2276 if (!pn->pn_atom2)
2277 return builder.xmlPI(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2278 else
2279 return builder.xmlPI(atomContents(pn->pn_atom),
2280 atomContents(pn->pn_atom2),
2281 &pn->pn_pos,
2282 dst);
2283 #endif
2285 default:
2286 LOCAL_NOT_REACHED("unexpected XML node type");
2290 bool
2291 ASTSerializer::propertyName(JSParseNode *pn, Value *dst)
2293 if (PN_TYPE(pn) == TOK_NAME)
2294 return identifier(pn, dst);
2296 LOCAL_ASSERT(PN_TYPE(pn) == TOK_STRING || PN_TYPE(pn) == TOK_NUMBER);
2298 return literal(pn, dst);
2301 bool
2302 ASTSerializer::property(JSParseNode *pn, Value *dst)
2304 PropKind kind;
2305 switch (PN_OP(pn)) {
2306 case JSOP_INITPROP:
2307 kind = PROP_INIT;
2308 break;
2310 case JSOP_GETTER:
2311 kind = PROP_GETTER;
2312 break;
2314 case JSOP_SETTER:
2315 kind = PROP_SETTER;
2316 break;
2318 default:
2319 LOCAL_NOT_REACHED("unexpected object-literal property");
2322 Value key, val;
2323 return propertyName(pn->pn_left, &key) &&
2324 expression(pn->pn_right, &val) &&
2325 builder.propertyInitializer(key, val, kind, &pn->pn_pos, dst);
2328 bool
2329 ASTSerializer::literal(JSParseNode *pn, Value *dst)
2331 Value val;
2332 switch (PN_TYPE(pn)) {
2333 case TOK_STRING:
2334 val = Valueify(ATOM_TO_JSVAL(pn->pn_atom));
2335 break;
2337 case TOK_REGEXP:
2339 JSObject *re1 = pn->pn_objbox ? pn->pn_objbox->object : NULL;
2340 LOCAL_ASSERT(re1 && re1->isRegExp());
2342 JSObject *proto;
2343 if (!js_GetClassPrototype(cx, cx->fp()->getScopeChain(), JSProto_RegExp, &proto))
2344 return false;
2346 JSObject *re2 = js_CloneRegExpObject(cx, re1, proto);
2347 if (!re2)
2348 return false;
2350 val.setObject(*re2);
2351 break;
2354 case TOK_NUMBER:
2355 val.setNumber(pn->pn_dval);
2356 break;
2358 case TOK_PRIMARY:
2359 if (PN_OP(pn) == JSOP_NULL)
2360 val.setNull();
2361 else
2362 val.setBoolean(PN_OP(pn) == JSOP_TRUE);
2363 break;
2365 default:
2366 LOCAL_NOT_REACHED("unexpected literal type");
2369 return builder.literal(val, &pn->pn_pos, dst);
2372 bool
2373 ASTSerializer::arrayPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
2375 JS_ASSERT(PN_TYPE(pn) == TOK_RB);
2377 NodeVector elts(cx);
2378 if (!elts.reserve(pn->pn_count))
2379 return false;
2381 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
2382 if (PN_TYPE(next) == TOK_COMMA) {
2383 (void)elts.append(MagicValue(JS_SERIALIZE_NO_NODE)); /* space check above */
2384 } else {
2385 Value patt;
2386 if (!pattern(next, pkind, &patt))
2387 return false;
2388 (void)elts.append(patt); /* space check above */
2392 return builder.arrayPattern(elts, &pn->pn_pos, dst);
2395 bool
2396 ASTSerializer::objectPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
2398 JS_ASSERT(PN_TYPE(pn) == TOK_RC);
2400 NodeVector elts(cx);
2401 if (!elts.reserve(pn->pn_count))
2402 return false;
2404 for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
2405 LOCAL_ASSERT(PN_OP(next) == JSOP_INITPROP);
2407 Value key, patt, prop;
2408 if (!propertyName(next->pn_left, &key) ||
2409 !pattern(next->pn_right, pkind, &patt) ||
2410 !builder.propertyPattern(key, patt, &next->pn_pos, &prop))
2411 return false;
2413 (void)elts.append(prop); /* space check above */
2416 return builder.objectPattern(elts, &pn->pn_pos, dst);
2419 bool
2420 ASTSerializer::pattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
2422 switch (PN_TYPE(pn)) {
2423 case TOK_RC:
2424 return objectPattern(pn, pkind, dst);
2426 case TOK_RB:
2427 return arrayPattern(pn, pkind, dst);
2429 case TOK_NAME:
2430 if (pkind && (pn->pn_dflags & PND_CONST))
2431 *pkind = VARDECL_CONST;
2432 /* FALL THROUGH */
2434 default:
2435 return expression(pn, dst);
2439 bool
2440 ASTSerializer::identifier(JSAtom *atom, TokenPos *pos, Value *dst)
2442 return builder.identifier(atomContents(atom), pos, dst);
2445 bool
2446 ASTSerializer::identifier(JSParseNode *pn, Value *dst)
2448 LOCAL_ASSERT(pn->pn_arity == PN_NAME || pn->pn_arity == PN_NULLARY);
2449 LOCAL_ASSERT(pn->pn_atom);
2451 return identifier(pn->pn_atom, &pn->pn_pos, dst);
2454 bool
2455 ASTSerializer::function(JSParseNode *pn, ASTType type, Value *dst)
2457 JSFunction *func = (JSFunction *)pn->pn_funbox->object;
2459 bool isGenerator =
2460 #ifdef JS_HAS_GENERATORS
2461 pn->pn_funbox->tcflags & TCF_FUN_IS_GENERATOR;
2462 #else
2463 false;
2464 #endif
2466 bool isExpression =
2467 #ifdef JS_HAS_EXPR_CLOSURES
2468 func->flags & JSFUN_EXPR_CLOSURE;
2469 #else
2470 false;
2471 #endif
2473 Value id;
2474 if (!optIdentifier(func->atom, NULL, &id))
2475 return false;
2477 NodeVector args(cx);
2479 JSParseNode *argsAndBody = (PN_TYPE(pn->pn_body) == TOK_UPVARS)
2480 ? pn->pn_body->pn_tree
2481 : pn->pn_body;
2483 Value body;
2484 return functionArgsAndBody(argsAndBody, args, &body) &&
2485 builder.function(type, &pn->pn_pos, id, args, body, isGenerator, isExpression, dst);
2488 bool
2489 ASTSerializer::functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *body)
2491 JSParseNode *pnargs;
2492 JSParseNode *pnbody;
2494 /* Extract the args and body separately. */
2495 if (PN_TYPE(pn) == TOK_ARGSBODY) {
2496 pnargs = pn;
2497 pnbody = pn->last();
2498 } else {
2499 pnargs = NULL;
2500 pnbody = pn;
2503 JSParseNode *pndestruct;
2505 /* Extract the destructuring assignments. */
2506 if (pnbody->pn_arity == PN_LIST && (pnbody->pn_xflags & PNX_DESTRUCT)) {
2507 JSParseNode *head = pnbody->pn_head;
2508 LOCAL_ASSERT(head && PN_TYPE(head) == TOK_SEMI);
2510 pndestruct = head->pn_kid;
2511 LOCAL_ASSERT(pndestruct && PN_TYPE(pndestruct) == TOK_COMMA);
2512 } else {
2513 pndestruct = NULL;
2516 /* Serialize the arguments and body. */
2517 switch (PN_TYPE(pnbody)) {
2518 case TOK_RETURN: /* expression closure, no destructured args */
2519 return functionArgs(pn, pnargs, NULL, pnbody, args) &&
2520 expression(pnbody->pn_kid, body);
2522 case TOK_SEQ: /* expression closure with destructured args */
2524 JSParseNode *pnstart = pnbody->pn_head->pn_next;
2525 LOCAL_ASSERT(pnstart && PN_TYPE(pnstart) == TOK_RETURN);
2527 return functionArgs(pn, pnargs, pndestruct, pnbody, args) &&
2528 expression(pnstart->pn_kid, body);
2531 case TOK_LC: /* statement closure */
2533 JSParseNode *pnstart = (pnbody->pn_xflags & PNX_DESTRUCT)
2534 ? pnbody->pn_head->pn_next
2535 : pnbody->pn_head;
2537 return functionArgs(pn, pnargs, pndestruct, pnbody, args) &&
2538 functionBody(pnstart, &pnbody->pn_pos, body);
2541 default:
2542 LOCAL_NOT_REACHED("unexpected function contents");
2546 bool
2547 ASTSerializer::functionArgs(JSParseNode *pn, JSParseNode *pnargs, JSParseNode *pndestruct,
2548 JSParseNode *pnbody, NodeVector &args)
2550 uintN i = 0;
2551 JSParseNode *arg = pnargs ? pnargs->pn_head : NULL;
2552 JSParseNode *destruct = pndestruct ? pndestruct->pn_head : NULL;
2553 Value node;
2556 * Arguments are found in potentially two different places: 1) the
2557 * argsbody sequence (which ends with the body node), or 2) a
2558 * destructuring initialization at the beginning of the body. Loop
2559 * |arg| through the argsbody and |destruct| through the initial
2560 * destructuring assignments, stopping only when we've exhausted
2561 * both.
2563 while ((arg && arg != pnbody) || destruct) {
2564 if (arg && arg != pnbody && arg->frameSlot() == i) {
2565 if (!identifier(arg, &node) ||
2566 !args.append(node))
2567 return false;
2568 arg = arg->pn_next;
2569 } else if (destruct && destruct->pn_right->frameSlot() == i) {
2570 if (!pattern(destruct->pn_left, NULL, &node) ||
2571 !args.append(node))
2572 return false;
2573 destruct = destruct->pn_next;
2574 } else {
2575 LOCAL_NOT_REACHED("missing function argument");
2577 ++i;
2580 return true;
2583 bool
2584 ASTSerializer::functionBody(JSParseNode *pn, TokenPos *pos, Value *dst)
2586 NodeVector elts(cx);
2588 /* We aren't sure how many elements there are up front, so we'll check each append. */
2589 for (JSParseNode *next = pn; next; next = next->pn_next) {
2590 Value child;
2591 if (!sourceElement(next, &child) ||
2592 !elts.append(child))
2593 return false;
2596 return builder.blockStatement(elts, pos, dst);
2599 } /* namespace js */
2601 /* Reflect class */
2603 Class js_ReflectClass = {
2604 js_Reflect_str,
2605 JSCLASS_HAS_CACHED_PROTO(JSProto_Reflect),
2606 PropertyStub,
2607 PropertyStub,
2608 PropertyStub,
2609 PropertyStub,
2610 EnumerateStub,
2611 ResolveStub,
2612 ConvertStub
2615 static JSBool
2616 reflect_parse(JSContext *cx, uintN argc, jsval *vp)
2618 if (argc < 1) {
2619 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
2620 "Reflect.parse", "0", "s");
2621 return JS_FALSE;
2624 JSString *src = js_ValueToString(cx, Valueify(JS_ARGV(cx, vp)[0]));
2625 if (!src)
2626 return JS_FALSE;
2628 const char *filename = NULL;
2629 if (argc > 1) {
2630 JSString *str = js_ValueToString(cx, Valueify(JS_ARGV(cx, vp)[1]));
2631 if (!str)
2632 return JS_FALSE;
2633 filename = js_GetStringBytes(NULL, str);
2636 uintN lineno = 1;
2637 if (argc > 2) {
2638 if (!ValueToECMAUint32(cx, Valueify(JS_ARGV(cx, vp)[2]), &lineno))
2639 return JS_FALSE;
2642 const jschar *chars;
2643 size_t length;
2645 src->getCharsAndLength(chars, length);
2647 Parser parser(cx);
2649 if (!parser.init(chars, length, NULL, filename, lineno))
2650 return JS_FALSE;
2652 JSParseNode *pn = parser.parse(NULL);
2653 if (!pn)
2654 return JS_FALSE;
2656 ASTSerializer serialize(cx, filename, lineno);
2657 if (!serialize.init())
2658 return JS_FALSE;
2660 Value val;
2661 if (!serialize.program(pn, &val)) {
2662 JS_SET_RVAL(cx, vp, JSVAL_NULL);
2663 return JS_FALSE;
2666 JS_SET_RVAL(cx, vp, Jsvalify(val));
2667 return JS_TRUE;
2670 static JSFunctionSpec static_methods[] = {
2671 JS_FN("parse", reflect_parse, 1, 0),
2672 JS_FS_END
2676 JSObject *
2677 js_InitReflectClass(JSContext *cx, JSObject *obj)
2679 JSObject *Reflect = NewNonFunction<WithProto::Class>(cx, &js_ReflectClass, NULL, obj);
2680 if (!Reflect)
2681 return NULL;
2683 if (!JS_DefineProperty(cx, obj, js_Reflect_str, OBJECT_TO_JSVAL(Reflect),
2684 JS_PropertyStub, JS_PropertyStub, 0))
2685 return NULL;
2687 if (!JS_DefineFunctions(cx, Reflect, static_methods))
2688 return NULL;
2690 return Reflect;