Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jsreflect.cpp
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:
3  *
4  * ***** BEGIN LICENSE BLOCK *****
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
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/
11  *
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.
16  *
17  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
18  * June 12, 2009.
19  *
20  * The Initial Developer of the Original Code is
21  *   the Mozilla Corporation.
22  *
23  * Contributor(s):
24  *   Dave Herman <dherman@mozilla.com>
25  *
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.
37  *
38  * ***** END LICENSE BLOCK ***** */
39
40 /*
41  * JS reflection package.
42  */
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 "jsobj.h"
65 #include "jsarray.h"
66 #include "jsnum.h"
67
68 #include "jsscriptinlines.h"
69
70 using namespace js;
71
72 namespace js {
73
74 char const *aopNames[] = {
75     "=",    /* AOP_ASSIGN */
76     "+=",   /* AOP_PLUS */
77     "-=",   /* AOP_MINUS */
78     "*=",   /* AOP_STAR */
79     "/=",   /* AOP_DIV */
80     "%=",   /* AOP_MOD */
81     "<<=",  /* AOP_LSH */
82     ">>=",  /* AOP_RSH */
83     ">>>=", /* AOP_URSH */
84     "|=",   /* AOP_BITOR */
85     "^=",   /* AOP_BITXOR */
86     "&="    /* AOP_BITAND */
87 };
88
89 char const *binopNames[] = {
90     "==",         /* BINOP_EQ */
91     "!=",         /* BINOP_NE */
92     "===",        /* BINOP_STRICTEQ */
93     "!==",        /* BINOP_STRICTNE */
94     "<",          /* BINOP_LT */
95     "<=",         /* BINOP_LE */
96     ">",          /* BINOP_GT */
97     ">=",         /* BINOP_GE */
98     "<<",         /* BINOP_LSH */
99     ">>",         /* BINOP_RSH */
100     ">>>",        /* BINOP_URSH */
101     "+",          /* BINOP_PLUS */
102     "-",          /* BINOP_MINUS */
103     "*",          /* BINOP_STAR */
104     "/",          /* BINOP_DIV */
105     "%",          /* BINOP_MOD */
106     "|",          /* BINOP_BITOR */
107     "^",          /* BINOP_BITXOR */
108     "&",          /* BINOP_BITAND */
109     "in",         /* BINOP_IN */
110     "instanceof", /* BINOP_INSTANCEOF */
111     "..",         /* BINOP_DBLDOT */
112 };
113
114 char const *unopNames[] = {
115     "delete",  /* UNOP_DELETE */
116     "-",       /* UNOP_NEG */
117     "+",       /* UNOP_POS */
118     "!",       /* UNOP_NOT */
119     "~",       /* UNOP_BITNOT */
120     "typeof",  /* UNOP_TYPEOF */
121     "void"     /* UNOP_VOID */
122 };
123
124 char const *nodeTypeNames[] = {
125 #define ASTDEF(ast, str, method) str,
126 #include "jsast.tbl"
127 #undef ASTDEF
128     NULL
129 };
130
131 char const *callbackNames[] = {
132 #define ASTDEF(ast, str, method) method,
133 #include "jsast.tbl"
134 #undef ASTDEF
135     NULL
136 };
137
138 typedef AutoValueVector NodeVector;
139
140 /*
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.
145  */
146 #define LOCAL_ASSERT(expr)                                                             \
147     JS_BEGIN_MACRO                                                                     \
148         JS_ASSERT(expr);                                                               \
149         if (!(expr)) {                                                                 \
150             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PARSE_NODE);  \
151             return false;                                                              \
152         }                                                                              \
153     JS_END_MACRO
154
155 #define LOCAL_NOT_REACHED(expr)                                                        \
156     JS_BEGIN_MACRO                                                                     \
157         JS_NOT_REACHED(expr);                                                          \
158         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PARSE_NODE);      \
159         return false;                                                                  \
160     JS_END_MACRO
161
162
163 /*
164  * Builder class that constructs JavaScript AST node objects. See:
165  *
166  *     https://developer.mozilla.org/en/SpiderMonkey/Parser_API
167  *
168  * Bug 569487: generalize builder interface
169  */
170 class NodeBuilder
171 {
172     JSContext   *cx;
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 */
178
179   public:
180     NodeBuilder(JSContext *c, bool l, char const *s)
181         : cx(c), saveLoc(l), src(s) {
182     }
183
184     bool init(JSObject *userobj = NULL) {
185         if (src) {
186             if (!atomValue(src, &srcval))
187                 return false;
188         } else {
189             srcval.setNull();
190         }
191
192         if (!userobj) {
193             userv.setNull();
194             for (uintN i = 0; i < AST_LIMIT; i++) {
195                 callbacks[i].setNull();
196             }
197             return true;
198         }
199
200         userv.setObject(*userobj);
201
202         for (uintN i = 0; i < AST_LIMIT; i++) {
203             Value funv;
204
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))
208                 return false;
209
210             if (funv.isNullOrUndefined()) {
211                 callbacks[i].setNull();
212                 continue;
213             }
214
215             if (!funv.isObject() || !funv.toObject().isFunction()) {
216                 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NOT_FUNCTION,
217                                          JSDVG_SEARCH_STACK, funv, NULL, NULL, NULL);
218                 return false;
219             }
220
221             callbacks[i] = funv;
222         }
223
224         return true;
225     }
226
227   private:
228     bool callback(Value fun, TokenPos *pos, Value *dst) {
229         if (saveLoc) {
230             Value loc;
231             if (!newNodeLoc(pos, &loc))
232                 return false;
233             Value argv[] = { loc };
234             return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
235         }
236
237         Value argv[] = { NullValue() }; /* no zero-length arrays allowed! */
238         return ExternalInvoke(cx, userv, fun, 0, argv, dst);
239     }
240
241     bool callback(Value fun, Value v1, TokenPos *pos, Value *dst) {
242         if (saveLoc) {
243             Value loc;
244             if (!newNodeLoc(pos, &loc))
245                 return false;
246             Value argv[] = { v1, loc };
247             return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
248         }
249
250         Value argv[] = { v1 };
251         return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
252     }
253
254     bool callback(Value fun, Value v1, Value v2, TokenPos *pos, Value *dst) {
255         if (saveLoc) {
256             Value loc;
257             if (!newNodeLoc(pos, &loc))
258                 return false;
259             Value argv[] = { v1, v2, loc };
260             return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
261         }
262
263         Value argv[] = { v1, v2 };
264         return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
265     }
266
267     bool callback(Value fun, Value v1, Value v2, Value v3, TokenPos *pos, Value *dst) {
268         if (saveLoc) {
269             Value loc;
270             if (!newNodeLoc(pos, &loc))
271                 return false;
272             Value argv[] = { v1, v2, v3, loc };
273             return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
274         }
275
276         Value argv[] = { v1, v2, v3 };
277         return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
278     }
279
280     bool callback(Value fun, Value v1, Value v2, Value v3, Value v4, TokenPos *pos, Value *dst) {
281         if (saveLoc) {
282             Value loc;
283             if (!newNodeLoc(pos, &loc))
284                 return false;
285             Value argv[] = { v1, v2, v3, v4, loc };
286             return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
287         }
288
289         Value argv[] = { v1, v2, v3, v4 };
290         return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
291     }
292
293     bool callback(Value fun, Value v1, Value v2, Value v3, Value v4, Value v5,
294                   TokenPos *pos, Value *dst) {
295         if (saveLoc) {
296             Value loc;
297             if (!newNodeLoc(pos, &loc))
298                 return false;
299             Value argv[] = { v1, v2, v3, v4, v5, loc };
300             return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
301         }
302
303         Value argv[] = { v1, v2, v3, v4, v5 };
304         return ExternalInvoke(cx, userv, fun, JS_ARRAY_LENGTH(argv), argv, dst);
305     }
306
307     Value opt(Value v) {
308         JS_ASSERT_IF(v.isMagic(), v.whyMagic() == JS_SERIALIZE_NO_NODE);
309         return v.isMagic(JS_SERIALIZE_NO_NODE) ? UndefinedValue() : v;
310     }
311
312     bool atomValue(const char *s, Value *dst) {
313         /*
314          * Bug 575416: instead of js_Atomize, lookup constant atoms in tbl file
315          */
316         JSAtom *atom = js_Atomize(cx, s, strlen(s), 0);
317         if (!atom)
318             return false;
319
320         *dst = Valueify(ATOM_TO_JSVAL(atom));
321         return true;
322     }
323
324     bool newObject(JSObject **dst) {
325         JSObject *nobj = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, NULL, NULL);
326         if (!nobj)
327             return false;
328
329         *dst = nobj;
330         return true;
331     }
332
333     bool newArray(NodeVector &elts, Value *dst);
334
335     bool newNode(ASTType type, TokenPos *pos, JSObject **dst);
336
337     bool newNode(ASTType type, TokenPos *pos, Value *dst) {
338         JSObject *node;
339         return newNode(type, pos, &node) &&
340                setResult(node, dst);
341     }
342
343     bool newNode(ASTType type, TokenPos *pos, const char *childName, Value child, Value *dst) {
344         JSObject *node;
345         return newNode(type, pos, &node) &&
346                setProperty(node, childName, child) &&
347                setResult(node, dst);
348     }
349
350     bool newNode(ASTType type, TokenPos *pos,
351                  const char *childName1, Value child1,
352                  const char *childName2, Value child2,
353                  Value *dst) {
354         JSObject *node;
355         return newNode(type, pos, &node) &&
356                setProperty(node, childName1, child1) &&
357                setProperty(node, childName2, child2) &&
358                setResult(node, dst);
359     }
360
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,
365                  Value *dst) {
366         JSObject *node;
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);
372     }
373
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,
379                  Value *dst) {
380         JSObject *node;
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);
387     }
388
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,
395                  Value *dst) {
396         JSObject *node;
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);
404     }
405
406     bool listNode(ASTType type, const char *propName, NodeVector &elts, TokenPos *pos, Value *dst) {
407         Value array;
408         if (!newArray(elts, &array))
409             return false;
410
411         Value cb = callbacks[type];
412         if (!cb.isNull())
413             return callback(cb, array, pos, dst);
414
415         return newNode(type, pos, propName, array, dst);
416     }
417
418     bool setProperty(JSObject *obj, const char *name, Value val) {
419         JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
420
421         /* Represent "no node" as null and ensure users are not exposed to magic values. */
422         if (val.isMagic(JS_SERIALIZE_NO_NODE))
423             val.setNull();
424
425         /*
426          * Bug 575416: instead of js_Atomize, lookup constant atoms in tbl file
427          */
428         JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
429         if (!atom)
430             return false;
431
432         return obj->defineProperty(cx, ATOM_TO_JSID(atom), val);
433     }
434
435     bool newNodeLoc(TokenPos *pos, Value *dst);
436
437     bool setNodeLoc(JSObject *obj, TokenPos *pos);
438
439     bool setResult(JSObject *obj, Value *dst) {
440         JS_ASSERT(obj);
441         dst->setObject(*obj);
442         return true;
443     }
444
445   public:
446     /*
447      * All of the public builder methods take as their last two
448      * arguments a nullable token position and a non-nullable, rooted
449      * outparam.
450      *
451      * All Value arguments are rooted. Any Value arguments representing
452      * optional subnodes may be a JS_SERIALIZE_NO_NODE magic value.
453      */
454
455     /*
456      * misc nodes
457      */
458
459     bool program(NodeVector &elts, TokenPos *pos, Value *dst);
460
461     bool literal(Value val, TokenPos *pos, Value *dst);
462
463     bool identifier(Value name, TokenPos *pos, Value *dst);
464
465     bool function(ASTType type, TokenPos *pos,
466                   Value id, NodeVector &args, Value body,
467                   bool isGenerator, bool isExpression, Value *dst);
468
469     bool variableDeclarator(Value id, Value init, TokenPos *pos, Value *dst);
470
471     bool switchCase(Value expr, NodeVector &elts, TokenPos *pos, Value *dst);
472
473     bool catchClause(Value var, Value guard, Value body, TokenPos *pos, Value *dst);
474
475     bool propertyInitializer(Value key, Value val, PropKind kind, TokenPos *pos, Value *dst);
476
477
478     /*
479      * statements
480      */
481
482     bool blockStatement(NodeVector &elts, TokenPos *pos, Value *dst);
483
484     bool expressionStatement(Value expr, TokenPos *pos, Value *dst);
485
486     bool emptyStatement(TokenPos *pos, Value *dst);
487
488     bool ifStatement(Value test, Value cons, Value alt, TokenPos *pos, Value *dst);
489
490     bool breakStatement(Value label, TokenPos *pos, Value *dst);
491
492     bool continueStatement(Value label, TokenPos *pos, Value *dst);
493
494     bool labeledStatement(Value label, Value stmt, TokenPos *pos, Value *dst);
495
496     bool throwStatement(Value arg, TokenPos *pos, Value *dst);
497
498     bool returnStatement(Value arg, TokenPos *pos, Value *dst);
499
500     bool forStatement(Value init, Value test, Value update, Value stmt,
501                       TokenPos *pos, Value *dst);
502
503     bool forInStatement(Value var, Value expr, Value stmt,
504                         bool isForEach, TokenPos *pos, Value *dst);
505
506     bool withStatement(Value expr, Value stmt, TokenPos *pos, Value *dst);
507
508     bool whileStatement(Value test, Value stmt, TokenPos *pos, Value *dst);
509
510     bool doWhileStatement(Value stmt, Value test, TokenPos *pos, Value *dst);
511
512     bool switchStatement(Value disc, NodeVector &elts, bool lexical, TokenPos *pos, Value *dst);
513
514     bool tryStatement(Value body, NodeVector &catches, Value finally, TokenPos *pos, Value *dst);
515
516     bool debuggerStatement(TokenPos *pos, Value *dst);
517
518     bool letStatement(NodeVector &head, Value stmt, TokenPos *pos, Value *dst);
519
520     /*
521      * expressions
522      */
523
524     bool binaryExpression(BinaryOperator op, Value left, Value right, TokenPos *pos, Value *dst);
525
526     bool unaryExpression(UnaryOperator op, Value expr, TokenPos *pos, Value *dst);
527
528     bool assignmentExpression(AssignmentOperator op, Value lhs, Value rhs,
529                               TokenPos *pos, Value *dst);
530
531     bool updateExpression(Value expr, bool incr, bool prefix, TokenPos *pos, Value *dst);
532
533     bool logicalExpression(bool lor, Value left, Value right, TokenPos *pos, Value *dst);
534
535     bool conditionalExpression(Value test, Value cons, Value alt, TokenPos *pos, Value *dst);
536
537     bool sequenceExpression(NodeVector &elts, TokenPos *pos, Value *dst);
538
539     bool newExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst);
540
541     bool callExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst);
542
543     bool memberExpression(bool computed, Value expr, Value member, TokenPos *pos, Value *dst);
544
545     bool arrayExpression(NodeVector &elts, TokenPos *pos, Value *dst);
546
547     bool objectExpression(NodeVector &elts, TokenPos *pos, Value *dst);
548
549     bool thisExpression(TokenPos *pos, Value *dst);
550
551     bool yieldExpression(Value arg, TokenPos *pos, Value *dst);
552
553     bool comprehensionBlock(Value patt, Value src, bool isForEach, TokenPos *pos, Value *dst);
554
555     bool comprehensionExpression(Value body, NodeVector &blocks, Value filter,
556                                  TokenPos *pos, Value *dst);
557
558     bool generatorExpression(Value body, NodeVector &blocks, Value filter,
559                              TokenPos *pos, Value *dst);
560
561     bool graphExpression(jsint idx, Value expr, TokenPos *pos, Value *dst);
562
563     bool graphIndexExpression(jsint idx, TokenPos *pos, Value *dst);
564
565     bool letExpression(NodeVector &head, Value expr, TokenPos *pos, Value *dst);
566
567     /*
568      * declarations
569      */
570
571     bool variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos, Value *dst);
572
573     /*
574      * patterns
575      */
576
577     bool arrayPattern(NodeVector &elts, TokenPos *pos, Value *dst);
578
579     bool objectPattern(NodeVector &elts, TokenPos *pos, Value *dst);
580
581     bool propertyPattern(Value key, Value patt, TokenPos *pos, Value *dst);
582
583     /*
584      * xml
585      */
586
587     bool xmlAnyName(TokenPos *pos, Value *dst);
588
589     bool xmlEscapeExpression(Value expr, TokenPos *pos, Value *dst);
590
591     bool xmlDefaultNamespace(Value ns, TokenPos *pos, Value *dst);
592
593     bool xmlFilterExpression(Value left, Value right, TokenPos *pos, Value *dst);
594
595     bool xmlAttributeSelector(Value expr, TokenPos *pos, Value *dst);
596
597     bool xmlQualifiedIdentifier(Value left, Value right, bool computed, TokenPos *pos, Value *dst);
598
599     bool xmlFunctionQualifiedIdentifier(Value right, bool computed, TokenPos *pos, Value *dst);
600
601     bool xmlElement(NodeVector &elts, TokenPos *pos, Value *dst);
602
603     bool xmlText(Value text, TokenPos *pos, Value *dst);
604
605     bool xmlList(NodeVector &elts, TokenPos *pos, Value *dst);
606
607     bool xmlStartTag(NodeVector &elts, TokenPos *pos, Value *dst);
608
609     bool xmlEndTag(NodeVector &elts, TokenPos *pos, Value *dst);
610
611     bool xmlPointTag(NodeVector &elts, TokenPos *pos, Value *dst);
612
613     bool xmlName(Value text, TokenPos *pos, Value *dst);
614
615     bool xmlName(NodeVector &elts, TokenPos *pos, Value *dst);
616
617     bool xmlAttribute(Value text, TokenPos *pos, Value *dst);
618
619     bool xmlCdata(Value text, TokenPos *pos, Value *dst);
620
621     bool xmlComment(Value text, TokenPos *pos, Value *dst);
622
623     bool xmlPI(Value target, TokenPos *pos, Value *dst);
624
625     bool xmlPI(Value target, Value content, TokenPos *pos, Value *dst);
626 };
627
628 bool
629 NodeBuilder::newNode(ASTType type, TokenPos *pos, JSObject **dst)
630 {
631     JS_ASSERT(type > AST_ERROR && type < AST_LIMIT);
632
633     Value tv;
634
635     JSObject *node = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, NULL, NULL);
636     if (!node ||
637         !setNodeLoc(node, pos) ||
638         !atomValue(nodeTypeNames[type], &tv) ||
639         !setProperty(node, "type", tv)) {
640         return false;
641     }
642
643     *dst = node;
644     return true;
645 }
646
647 bool
648 NodeBuilder::newArray(NodeVector &elts, Value *dst)
649 {
650     JSObject *array = NewDenseEmptyArray(cx);
651     if (!array)
652         return false;
653
654     const size_t len = elts.length();
655     for (size_t i = 0; i < len; i++) {
656         Value val = elts[i];
657
658         JS_ASSERT_IF(val.isMagic(), val.whyMagic() == JS_SERIALIZE_NO_NODE);
659
660         /* Represent "no node" as an array hole by not adding the value. */
661         if (val.isMagic(JS_SERIALIZE_NO_NODE))
662             continue;
663
664         if (!array->setProperty(cx, INT_TO_JSID(i), &val, false))
665             return false;
666     }
667
668     dst->setObject(*array);
669     return true;
670 }
671
672 bool
673 NodeBuilder::newNodeLoc(TokenPos *pos, Value *dst)
674 {
675     if (!pos) {
676         dst->setNull();
677         return true;
678     }
679  
680     JSObject *loc, *to;
681     Value tv;
682
683     if (!newObject(&loc))
684         return false;
685
686     dst->setObject(*loc);
687
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) &&
694
695            newObject(&to) &&
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) &&
701
702            setProperty(loc, "source", srcval);
703 }
704
705 bool
706 NodeBuilder::setNodeLoc(JSObject *node, TokenPos *pos)
707 {
708     if (!saveLoc) {
709         setProperty(node, "loc", NullValue());
710         return true;
711     }
712
713     Value loc;
714     return newNodeLoc(pos, &loc) &&
715            setProperty(node, "loc", loc);
716 }
717
718 bool
719 NodeBuilder::program(NodeVector &elts, TokenPos *pos, Value *dst)
720 {
721     return listNode(AST_PROGRAM, "body", elts, pos, dst);
722 }
723
724 bool
725 NodeBuilder::blockStatement(NodeVector &elts, TokenPos *pos, Value *dst)
726 {
727     return listNode(AST_BLOCK_STMT, "body", elts, pos, dst);
728 }
729
730 bool
731 NodeBuilder::expressionStatement(Value expr, TokenPos *pos, Value *dst)
732 {
733     Value cb = callbacks[AST_EXPR_STMT];
734     if (!cb.isNull())
735         return callback(cb, expr, pos, dst);
736
737     return newNode(AST_EXPR_STMT, pos, "expression", expr, dst);
738 }
739
740 bool
741 NodeBuilder::emptyStatement(TokenPos *pos, Value *dst)
742 {
743     Value cb = callbacks[AST_EMPTY_STMT];
744     if (!cb.isNull())
745         return callback(cb, pos, dst);
746
747     return newNode(AST_EMPTY_STMT, pos, dst);
748 }
749
750 bool
751 NodeBuilder::ifStatement(Value test, Value cons, Value alt, TokenPos *pos, Value *dst)
752 {
753     Value cb = callbacks[AST_IF_STMT];
754     if (!cb.isNull())
755         return callback(cb, test, cons, opt(alt), pos, dst);
756
757     return newNode(AST_IF_STMT, pos,
758                    "test", test,
759                    "consequent", cons,
760                    "alternate", alt,
761                    dst);
762 }
763
764 bool
765 NodeBuilder::breakStatement(Value label, TokenPos *pos, Value *dst)
766 {
767     Value cb = callbacks[AST_BREAK_STMT];
768     if (!cb.isNull())
769         return callback(cb, opt(label), pos, dst);
770
771     return newNode(AST_BREAK_STMT, pos, "label", label, dst);
772 }
773
774 bool
775 NodeBuilder::continueStatement(Value label, TokenPos *pos, Value *dst)
776 {
777     Value cb = callbacks[AST_CONTINUE_STMT];
778     if (!cb.isNull())
779         return callback(cb, opt(label), pos, dst);
780
781     return newNode(AST_CONTINUE_STMT, pos, "label", label, dst);
782 }
783
784 bool
785 NodeBuilder::labeledStatement(Value label, Value stmt, TokenPos *pos, Value *dst)
786 {
787     Value cb = callbacks[AST_LAB_STMT];
788     if (!cb.isNull())
789         return callback(cb, label, stmt, pos, dst);
790
791     return newNode(AST_LAB_STMT, pos,
792                    "label", label,
793                    "body", stmt,
794                    dst);
795 }
796
797 bool
798 NodeBuilder::throwStatement(Value arg, TokenPos *pos, Value *dst)
799 {
800     Value cb = callbacks[AST_THROW_STMT];
801     if (!cb.isNull())
802         return callback(cb, arg, pos, dst);
803
804     return newNode(AST_THROW_STMT, pos, "argument", arg, dst);
805 }
806
807 bool
808 NodeBuilder::returnStatement(Value arg, TokenPos *pos, Value *dst)
809 {
810     Value cb = callbacks[AST_RETURN_STMT];
811     if (!cb.isNull())
812         return callback(cb, opt(arg), pos, dst);
813
814     return newNode(AST_RETURN_STMT, pos, "argument", arg, dst);
815 }
816
817 bool
818 NodeBuilder::forStatement(Value init, Value test, Value update, Value stmt,
819                           TokenPos *pos, Value *dst)
820 {
821     Value cb = callbacks[AST_FOR_STMT];
822     if (!cb.isNull())
823         return callback(cb, opt(init), opt(test), opt(update), stmt, pos, dst);
824
825     return newNode(AST_FOR_STMT, pos,
826                    "init", init,
827                    "test", test,
828                    "update", update,
829                    "body", stmt,
830                    dst);
831 }
832
833 bool
834 NodeBuilder::forInStatement(Value var, Value expr, Value stmt, bool isForEach,
835                             TokenPos *pos, Value *dst)
836 {
837     Value cb = callbacks[AST_FOR_IN_STMT];
838     if (!cb.isNull())
839         return callback(cb, var, expr, stmt, BooleanValue(isForEach), pos, dst);
840
841     return newNode(AST_FOR_IN_STMT, pos,
842                    "left", var,
843                    "right", expr,
844                    "body", stmt,
845                    "each", BooleanValue(isForEach),
846                    dst);
847 }
848
849 bool
850 NodeBuilder::withStatement(Value expr, Value stmt, TokenPos *pos, Value *dst)
851 {
852     Value cb = callbacks[AST_WITH_STMT];
853     if (!cb.isNull())
854         return callback(cb, expr, stmt, pos, dst);
855
856     return newNode(AST_WITH_STMT, pos,
857                    "object", expr,
858                    "body", stmt,
859                    dst);
860 }
861
862 bool
863 NodeBuilder::whileStatement(Value test, Value stmt, TokenPos *pos, Value *dst)
864 {
865     Value cb = callbacks[AST_WHILE_STMT];
866     if (!cb.isNull())
867         return callback(cb, test, stmt, pos, dst);
868
869     return newNode(AST_WHILE_STMT, pos,
870                    "test", test,
871                    "body", stmt,
872                    dst);
873 }
874
875 bool
876 NodeBuilder::doWhileStatement(Value stmt, Value test, TokenPos *pos, Value *dst)
877 {
878     Value cb = callbacks[AST_DO_STMT];
879     if (!cb.isNull())
880         return callback(cb, stmt, test, pos, dst);
881
882     return newNode(AST_DO_STMT, pos,
883                    "body", stmt,
884                    "test", test,
885                    dst);
886 }
887
888 bool
889 NodeBuilder::switchStatement(Value disc, NodeVector &elts, bool lexical, TokenPos *pos, Value *dst)
890 {
891     Value array;
892     if (!newArray(elts, &array))
893         return false;
894
895     Value cb = callbacks[AST_SWITCH_STMT];
896     if (!cb.isNull())
897         return callback(cb, disc, array, BooleanValue(lexical), pos, dst);
898
899     return newNode(AST_SWITCH_STMT, pos,
900                    "discriminant", disc,
901                    "cases", array,
902                    "lexical", BooleanValue(lexical),
903                    dst);
904 }
905
906 bool
907 NodeBuilder::tryStatement(Value body, NodeVector &catches, Value finally,
908                           TokenPos *pos, Value *dst)
909 {
910     Value handler;
911
912     Value cb = callbacks[AST_TRY_STMT];
913     if (!cb.isNull()) {
914         return newArray(catches, &handler) &&
915                callback(cb, body, handler, opt(finally), pos, dst);
916     }
917
918     switch (catches.length()) {
919       case 0:
920         handler.setNull();
921         break;
922       case 1:
923         handler = catches[0];
924         break;
925       default:
926         if (!newArray(catches, &handler))
927             return false;
928     }
929
930     return newNode(AST_TRY_STMT, pos,
931                    "block", body,
932                    "handler", handler,
933                    "finalizer", finally,
934                    dst);
935 }
936
937 bool
938 NodeBuilder::debuggerStatement(TokenPos *pos, Value *dst)
939 {
940     Value cb = callbacks[AST_DEBUGGER_STMT];
941     if (!cb.isNull())
942         return callback(cb, pos, dst);
943
944     return newNode(AST_DEBUGGER_STMT, pos, dst);
945 }
946
947 bool
948 NodeBuilder::binaryExpression(BinaryOperator op, Value left, Value right, TokenPos *pos, Value *dst)
949 {
950     JS_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
951
952     Value opName;
953     if (!atomValue(binopNames[op], &opName))
954         return false;
955
956     Value cb = callbacks[AST_BINARY_EXPR];
957     if (!cb.isNull())
958         return callback(cb, opName, left, right, pos, dst);
959
960     return newNode(AST_BINARY_EXPR, pos,
961                    "operator", opName,
962                    "left", left,
963                    "right", right,
964                    dst);
965 }
966
967 bool
968 NodeBuilder::unaryExpression(UnaryOperator unop, Value expr, TokenPos *pos, Value *dst)
969 {
970     JS_ASSERT(unop > UNOP_ERR && unop < UNOP_LIMIT);
971
972     Value opName;
973     if (!atomValue(unopNames[unop], &opName))
974         return false;
975
976     Value cb = callbacks[AST_UNARY_EXPR];
977     if (!cb.isNull())
978         return callback(cb, opName, expr, pos, dst);
979
980     return newNode(AST_UNARY_EXPR, pos,
981                    "operator", opName,
982                    "argument", expr,
983                    "prefix", BooleanValue(true),
984                    dst);
985 }
986
987 bool
988 NodeBuilder::assignmentExpression(AssignmentOperator aop, Value lhs, Value rhs,
989                                   TokenPos *pos, Value *dst)
990 {
991     JS_ASSERT(aop > AOP_ERR && aop < AOP_LIMIT);
992
993     Value opName;
994     if (!atomValue(aopNames[aop], &opName))
995         return false;
996
997     Value cb = callbacks[AST_ASSIGN_EXPR];
998     if (!cb.isNull())
999         return callback(cb, opName, lhs, rhs, pos, dst);
1000
1001     return newNode(AST_ASSIGN_EXPR, pos,
1002                    "operator", opName,
1003                    "left", lhs,
1004                    "right", rhs,
1005                    dst);
1006 }
1007
1008 bool
1009 NodeBuilder::updateExpression(Value expr, bool incr, bool prefix, TokenPos *pos, Value *dst)
1010 {
1011     Value opName;
1012     if (!atomValue(incr ? "++" : "--", &opName))
1013         return false;
1014
1015     Value cb = callbacks[AST_UPDATE_EXPR];
1016     if (!cb.isNull())
1017         return callback(cb, expr, opName, BooleanValue(prefix), pos, dst);
1018
1019     return newNode(AST_UPDATE_EXPR, pos,
1020                    "operator", opName,
1021                    "argument", expr,
1022                    "prefix", BooleanValue(prefix),
1023                    dst);
1024 }
1025
1026 bool
1027 NodeBuilder::logicalExpression(bool lor, Value left, Value right, TokenPos *pos, Value *dst)
1028 {
1029     Value opName;
1030     if (!atomValue(lor ? "||" : "&&", &opName))
1031         return false;
1032
1033     Value cb = callbacks[AST_LOGICAL_EXPR];
1034     if (!cb.isNull())
1035         return callback(cb, opName, left, right, pos, dst);
1036
1037     return newNode(AST_LOGICAL_EXPR, pos,
1038                    "operator", opName,
1039                    "left", left,
1040                    "right", right,
1041                    dst);
1042 }
1043
1044 bool
1045 NodeBuilder::conditionalExpression(Value test, Value cons, Value alt, TokenPos *pos, Value *dst)
1046 {
1047     Value cb = callbacks[AST_COND_EXPR];
1048     if (!cb.isNull())
1049         return callback(cb, test, cons, alt, pos, dst);
1050
1051     return newNode(AST_COND_EXPR, pos,
1052                    "test", test,
1053                    "consequent", cons,
1054                    "alternate", alt,
1055                    dst);
1056 }
1057
1058 bool
1059 NodeBuilder::sequenceExpression(NodeVector &elts, TokenPos *pos, Value *dst)
1060 {
1061     return listNode(AST_LIST_EXPR, "expressions", elts, pos, dst);
1062 }
1063
1064 bool
1065 NodeBuilder::callExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst)
1066 {
1067     Value array;
1068     if (!newArray(args, &array))
1069         return false;
1070
1071     Value cb = callbacks[AST_CALL_EXPR];
1072     if (!cb.isNull())
1073         return callback(cb, callee, array, pos, dst);
1074
1075     return newNode(AST_CALL_EXPR, pos,
1076                    "callee", callee,
1077                    "arguments", array,
1078                    dst);
1079 }
1080
1081 bool
1082 NodeBuilder::newExpression(Value callee, NodeVector &args, TokenPos *pos, Value *dst)
1083 {
1084     Value array;
1085     if (!newArray(args, &array))
1086         return false;
1087
1088     Value cb = callbacks[AST_NEW_EXPR];
1089     if (!cb.isNull())
1090         return callback(cb, callee, array, pos, dst);
1091
1092     return newNode(AST_NEW_EXPR, pos,
1093                    "callee", callee,
1094                    "arguments", array,
1095                    dst);
1096 }
1097
1098 bool
1099 NodeBuilder::memberExpression(bool computed, Value expr, Value member, TokenPos *pos, Value *dst)
1100 {
1101     Value cb = callbacks[AST_MEMBER_EXPR];
1102     if (!cb.isNull())
1103         return callback(cb, BooleanValue(computed), expr, member, pos, dst);
1104
1105     return newNode(AST_MEMBER_EXPR, pos,
1106                    "object", expr,
1107                    "property", member,
1108                    "computed", BooleanValue(computed),
1109                    dst);
1110 }
1111
1112 bool
1113 NodeBuilder::arrayExpression(NodeVector &elts, TokenPos *pos, Value *dst)
1114 {
1115     return listNode(AST_ARRAY_EXPR, "elements", elts, pos, dst);
1116 }
1117
1118 bool
1119 NodeBuilder::propertyPattern(Value key, Value patt, TokenPos *pos, Value *dst)
1120 {
1121     Value kindName;
1122     if (!atomValue("init", &kindName))
1123         return false;
1124
1125     Value cb = callbacks[AST_PROP_PATT];
1126     if (!cb.isNull())
1127         return callback(cb, key, patt, pos, dst);
1128
1129     return newNode(AST_PROP_PATT, pos,
1130                    "key", key,
1131                    "value", patt,
1132                    "kind", kindName,
1133                    dst);
1134 }
1135
1136 bool
1137 NodeBuilder::propertyInitializer(Value key, Value val, PropKind kind, TokenPos *pos, Value *dst)
1138 {
1139     Value kindName;
1140     if (!atomValue(kind == PROP_INIT
1141                    ? "init"
1142                    : kind == PROP_GETTER
1143                    ? "get"
1144                    : "set", &kindName)) {
1145         return false;
1146     }
1147
1148     Value cb = callbacks[AST_PROPERTY];
1149     if (!cb.isNull())
1150         return callback(cb, kindName, key, val, pos, dst);
1151
1152     return newNode(AST_PROPERTY, pos,
1153                    "key", key,
1154                    "value", val,
1155                    "kind", kindName,
1156                    dst);
1157 }
1158
1159 bool
1160 NodeBuilder::objectExpression(NodeVector &elts, TokenPos *pos, Value *dst)
1161 {
1162     return listNode(AST_OBJECT_EXPR, "properties", elts, pos, dst);
1163 }
1164
1165 bool
1166 NodeBuilder::thisExpression(TokenPos *pos, Value *dst)
1167 {
1168     Value cb = callbacks[AST_THIS_EXPR];
1169     if (!cb.isNull())
1170         return callback(cb, pos, dst);
1171
1172     return newNode(AST_THIS_EXPR, pos, dst);
1173 }
1174
1175 bool
1176 NodeBuilder::yieldExpression(Value arg, TokenPos *pos, Value *dst)
1177 {
1178     Value cb = callbacks[AST_YIELD_EXPR];
1179     if (!cb.isNull())
1180         return callback(cb, opt(arg), pos, dst);
1181
1182     return newNode(AST_YIELD_EXPR, pos, "argument", arg, dst);
1183 }
1184
1185 bool
1186 NodeBuilder::comprehensionBlock(Value patt, Value src, bool isForEach, TokenPos *pos, Value *dst)
1187 {
1188     Value cb = callbacks[AST_COMP_BLOCK];
1189     if (!cb.isNull())
1190         return callback(cb, patt, src, BooleanValue(isForEach), pos, dst);
1191
1192     return newNode(AST_COMP_BLOCK, pos,
1193                    "left", patt,
1194                    "right", src,
1195                    "each", BooleanValue(isForEach),
1196                    dst);
1197 }
1198
1199 bool
1200 NodeBuilder::comprehensionExpression(Value body, NodeVector &blocks, Value filter,
1201                                      TokenPos *pos, Value *dst)
1202 {
1203     Value array;
1204     if (!newArray(blocks, &array))
1205         return false;
1206
1207     Value cb = callbacks[AST_COMP_EXPR];
1208     if (!cb.isNull())
1209         return callback(cb, body, array, opt(filter), pos, dst);
1210
1211     return newNode(AST_COMP_EXPR, pos,
1212                    "body", body,
1213                    "blocks", array,
1214                    "filter", filter,
1215                    dst);
1216 }
1217
1218 bool
1219 NodeBuilder::generatorExpression(Value body, NodeVector &blocks, Value filter, TokenPos *pos, Value *dst)
1220 {
1221     Value array;
1222     if (!newArray(blocks, &array))
1223         return false;
1224
1225     Value cb = callbacks[AST_GENERATOR_EXPR];
1226     if (!cb.isNull())
1227         return callback(cb, body, array, opt(filter), pos, dst);
1228
1229     return newNode(AST_GENERATOR_EXPR, pos,
1230                    "body", body,
1231                    "blocks", array,
1232                    "filter", filter,
1233                    dst);
1234 }
1235
1236 bool
1237 NodeBuilder::graphExpression(jsint idx, Value expr, TokenPos *pos, Value *dst)
1238 {
1239     Value cb = callbacks[AST_GRAPH_EXPR];
1240     if (!cb.isNull())
1241         return callback(cb, NumberValue(idx), pos, dst);
1242
1243     return newNode(AST_GRAPH_EXPR, pos,
1244                    "index", NumberValue(idx),
1245                    "expression", expr,
1246                    dst);
1247 }
1248
1249 bool
1250 NodeBuilder::graphIndexExpression(jsint idx, TokenPos *pos, Value *dst)
1251 {
1252     Value cb = callbacks[AST_GRAPH_IDX_EXPR];
1253     if (!cb.isNull())
1254         return callback(cb, NumberValue(idx), pos, dst);
1255
1256     return newNode(AST_GRAPH_IDX_EXPR, pos, "index", NumberValue(idx), dst);
1257 }
1258
1259 bool
1260 NodeBuilder::letExpression(NodeVector &head, Value expr, TokenPos *pos, Value *dst)
1261 {
1262     Value array;
1263     if (!newArray(head, &array))
1264         return false;
1265
1266     Value cb = callbacks[AST_LET_EXPR];
1267     if (!cb.isNull())
1268         return callback(cb, array, expr, pos, dst);
1269
1270     return newNode(AST_LET_EXPR, pos,
1271                    "head", array,
1272                    "body", expr,
1273                    dst);
1274 }
1275
1276 bool
1277 NodeBuilder::letStatement(NodeVector &head, Value stmt, TokenPos *pos, Value *dst)
1278 {
1279     Value array;
1280     if (!newArray(head, &array))
1281         return false;
1282
1283     Value cb = callbacks[AST_LET_STMT];
1284     if (!cb.isNull())
1285         return callback(cb, array, stmt, pos, dst);
1286
1287     return newNode(AST_LET_STMT, pos,
1288                    "head", array,
1289                    "body", stmt,
1290                    dst);
1291 }
1292
1293 bool
1294 NodeBuilder::variableDeclaration(NodeVector &elts, VarDeclKind kind, TokenPos *pos, Value *dst)
1295 {
1296     JS_ASSERT(kind > VARDECL_ERR && kind < VARDECL_LIMIT);
1297
1298     Value array, kindName;
1299     if (!newArray(elts, &array) ||
1300         !atomValue(kind == VARDECL_CONST
1301                    ? "const"
1302                    : kind == VARDECL_LET
1303                    ? "let"
1304                    : "var", &kindName)) {
1305         return false;
1306     }
1307
1308     Value cb = callbacks[AST_VAR_DECL];
1309     if (!cb.isNull())
1310         return callback(cb, kindName, array, pos, dst);
1311
1312     return newNode(AST_VAR_DECL, pos,
1313                    "kind", kindName,
1314                    "declarations", array,
1315                    dst);
1316 }
1317
1318 bool
1319 NodeBuilder::variableDeclarator(Value id, Value init, TokenPos *pos, Value *dst)
1320 {
1321     Value cb = callbacks[AST_VAR_DTOR];
1322     if (!cb.isNull())
1323         return callback(cb, id, opt(init), pos, dst);
1324
1325     return newNode(AST_VAR_DTOR, pos, "id", id, "init", init, dst);
1326 }
1327
1328 bool
1329 NodeBuilder::switchCase(Value expr, NodeVector &elts, TokenPos *pos, Value *dst)
1330 {
1331     Value array;
1332     if (!newArray(elts, &array))
1333         return false;
1334
1335     Value cb = callbacks[AST_CASE];
1336     if (!cb.isNull())
1337         return callback(cb, opt(expr), array, pos, dst);
1338
1339     return newNode(AST_CASE, pos,
1340                    "test", expr,
1341                    "consequent", array,
1342                    dst);
1343 }
1344
1345 bool
1346 NodeBuilder::catchClause(Value var, Value guard, Value body, TokenPos *pos, Value *dst)
1347 {
1348     Value cb = callbacks[AST_CATCH];
1349     if (!cb.isNull())
1350         return callback(cb, var, opt(guard), body, pos, dst);
1351
1352     return newNode(AST_CATCH, pos,
1353                    "param", var,
1354                    "guard", guard,
1355                    "body", body,
1356                    dst);
1357 }
1358
1359 bool
1360 NodeBuilder::literal(Value val, TokenPos *pos, Value *dst)
1361 {
1362     Value cb = callbacks[AST_LITERAL];
1363     if (!cb.isNull())
1364         return callback(cb, val, pos, dst);
1365
1366     return newNode(AST_LITERAL, pos, "value", val, dst);
1367 }
1368
1369 bool
1370 NodeBuilder::identifier(Value name, TokenPos *pos, Value *dst)
1371 {
1372     Value cb = callbacks[AST_IDENTIFIER];
1373     if (!cb.isNull())
1374         return callback(cb, name, pos, dst);
1375
1376     return newNode(AST_IDENTIFIER, pos, "name", name, dst);
1377 }
1378
1379 bool
1380 NodeBuilder::objectPattern(NodeVector &elts, TokenPos *pos, Value *dst)
1381 {
1382     return listNode(AST_OBJECT_PATT, "properties", elts, pos, dst);
1383 }
1384
1385 bool
1386 NodeBuilder::arrayPattern(NodeVector &elts, TokenPos *pos, Value *dst)
1387 {
1388     return listNode(AST_ARRAY_PATT, "elements", elts, pos, dst);
1389 }
1390
1391 bool
1392 NodeBuilder::function(ASTType type, TokenPos *pos,
1393                       Value id, NodeVector &args, Value body,
1394                       bool isGenerator, bool isExpression,
1395                       Value *dst)
1396 {
1397     Value array;
1398     if (!newArray(args, &array))
1399         return false;
1400
1401     Value cb = callbacks[type];
1402     if (!cb.isNull()) {
1403         return callback(cb, opt(id), array, body, BooleanValue(isGenerator),
1404                         BooleanValue(isExpression), pos, dst);
1405     }
1406
1407     return newNode(type, pos,
1408                    "id", id,
1409                    "params", array,
1410                    "body", body,
1411                    "generator", BooleanValue(isGenerator),
1412                    "expression", BooleanValue(isExpression),
1413                    dst);
1414 }
1415
1416 bool
1417 NodeBuilder::xmlAnyName(TokenPos *pos, Value *dst)
1418 {
1419     Value cb = callbacks[AST_XMLANYNAME];
1420     if (!cb.isNull())
1421         return callback(cb, pos, dst);
1422
1423     return newNode(AST_XMLANYNAME, pos, dst);
1424 }
1425
1426 bool
1427 NodeBuilder::xmlEscapeExpression(Value expr, TokenPos *pos, Value *dst)
1428 {
1429     Value cb = callbacks[AST_XMLESCAPE];
1430     if (!cb.isNull())
1431         return callback(cb, expr, pos, dst);
1432
1433     return newNode(AST_XMLESCAPE, pos, "expression", expr, dst);
1434 }
1435
1436 bool
1437 NodeBuilder::xmlFilterExpression(Value left, Value right, TokenPos *pos, Value *dst)
1438 {
1439     Value cb = callbacks[AST_XMLFILTER];
1440     if (!cb.isNull())
1441         return callback(cb, left, right, pos, dst);
1442
1443     return newNode(AST_XMLFILTER, pos, "left", left, "right", right, dst);
1444 }
1445
1446 bool
1447 NodeBuilder::xmlDefaultNamespace(Value ns, TokenPos *pos, Value *dst)
1448 {
1449     Value cb = callbacks[AST_XMLDEFAULT];
1450     if (!cb.isNull())
1451         return callback(cb, ns, pos, dst);
1452
1453     return newNode(AST_XMLDEFAULT, pos, "namespace", ns, dst);
1454 }
1455
1456 bool
1457 NodeBuilder::xmlAttributeSelector(Value expr, TokenPos *pos, Value *dst)
1458 {
1459     Value cb = callbacks[AST_XMLATTR_SEL];
1460     if (!cb.isNull())
1461         return callback(cb, expr, pos, dst);
1462
1463     return newNode(AST_XMLATTR_SEL, pos, "attribute", expr, dst);
1464 }
1465
1466 bool
1467 NodeBuilder::xmlFunctionQualifiedIdentifier(Value right, bool computed, TokenPos *pos, Value *dst)
1468 {
1469     Value cb = callbacks[AST_XMLFUNCQUAL];
1470     if (!cb.isNull())
1471         return callback(cb, right, BooleanValue(computed), pos, dst);
1472
1473     return newNode(AST_XMLFUNCQUAL, pos,
1474                    "right", right,
1475                    "computed", BooleanValue(computed),
1476                    dst);
1477 }
1478
1479 bool
1480 NodeBuilder::xmlQualifiedIdentifier(Value left, Value right, bool computed,
1481                                     TokenPos *pos, Value *dst)
1482 {
1483     Value cb = callbacks[AST_XMLQUAL];
1484     if (!cb.isNull())
1485         return callback(cb, left, right, BooleanValue(computed), pos, dst);
1486
1487     return newNode(AST_XMLQUAL, pos,
1488                    "left", left,
1489                    "right", right,
1490                    "computed", BooleanValue(computed),
1491                    dst);
1492 }
1493
1494 bool
1495 NodeBuilder::xmlElement(NodeVector &elts, TokenPos *pos, Value *dst)
1496 {
1497     return listNode(AST_XMLELEM, "contents", elts, pos, dst);
1498 }
1499
1500 bool
1501 NodeBuilder::xmlText(Value text, TokenPos *pos, Value *dst)
1502 {
1503     Value cb = callbacks[AST_XMLTEXT];
1504     if (!cb.isNull())
1505         return callback(cb, text, pos, dst);
1506
1507     return newNode(AST_XMLTEXT, pos, "text", text, dst);
1508 }
1509
1510 bool
1511 NodeBuilder::xmlList(NodeVector &elts, TokenPos *pos, Value *dst)
1512 {
1513     return listNode(AST_XMLLIST, "contents", elts, pos, dst);
1514 }
1515
1516 bool
1517 NodeBuilder::xmlStartTag(NodeVector &elts, TokenPos *pos, Value *dst)
1518 {
1519     return listNode(AST_XMLSTART, "contents", elts, pos, dst);
1520 }
1521
1522 bool
1523 NodeBuilder::xmlEndTag(NodeVector &elts, TokenPos *pos, Value *dst)
1524 {
1525     return listNode(AST_XMLEND, "contents", elts, pos, dst);
1526 }
1527
1528 bool
1529 NodeBuilder::xmlPointTag(NodeVector &elts, TokenPos *pos, Value *dst)
1530 {
1531     return listNode(AST_XMLPOINT, "contents", elts, pos, dst);
1532 }
1533
1534 bool
1535 NodeBuilder::xmlName(Value text, TokenPos *pos, Value *dst)
1536 {
1537     Value cb = callbacks[AST_XMLNAME];
1538     if (!cb.isNull())
1539         return callback(cb, text, pos, dst);
1540
1541     return newNode(AST_XMLNAME, pos, "contents", text, dst);
1542 }
1543
1544 bool
1545 NodeBuilder::xmlName(NodeVector &elts, TokenPos *pos, Value *dst)
1546 {
1547     return listNode(AST_XMLNAME, "contents", elts, pos ,dst);
1548 }
1549
1550 bool
1551 NodeBuilder::xmlAttribute(Value text, TokenPos *pos, Value *dst)
1552 {
1553     Value cb = callbacks[AST_XMLATTR];
1554     if (!cb.isNull())
1555         return callback(cb, text, pos, dst);
1556
1557     return newNode(AST_XMLATTR, pos, "value", text, dst);
1558 }
1559
1560 bool
1561 NodeBuilder::xmlCdata(Value text, TokenPos *pos, Value *dst)
1562 {
1563     Value cb = callbacks[AST_XMLCDATA];
1564     if (!cb.isNull())
1565         return callback(cb, text, pos, dst);
1566
1567     return newNode(AST_XMLCDATA, pos, "contents", text, dst);
1568 }
1569
1570 bool
1571 NodeBuilder::xmlComment(Value text, TokenPos *pos, Value *dst)
1572 {
1573     Value cb = callbacks[AST_XMLCOMMENT];
1574     if (!cb.isNull())
1575         return callback(cb, text, pos, dst);
1576
1577     return newNode(AST_XMLCOMMENT, pos, "contents", text, dst);
1578 }
1579
1580 bool
1581 NodeBuilder::xmlPI(Value target, TokenPos *pos, Value *dst)
1582 {
1583     return xmlPI(target, NullValue(), pos, dst);
1584 }
1585
1586 bool
1587 NodeBuilder::xmlPI(Value target, Value contents, TokenPos *pos, Value *dst)
1588 {
1589     Value cb = callbacks[AST_XMLPI];
1590     if (!cb.isNull())
1591         return callback(cb, target, contents, pos, dst);
1592
1593     return newNode(AST_XMLPI, pos,
1594                    "target", target,
1595                    "contents", contents,
1596                    dst);
1597 }
1598
1599
1600 /*
1601  * Serialization of parse nodes to JavaScript objects.
1602  *
1603  * All serialization methods take a non-nullable JSParseNode pointer.
1604  */
1605
1606 class ASTSerializer
1607 {
1608     JSContext     *cx;
1609     NodeBuilder   builder;
1610     uint32        lineno;
1611
1612     Value atomContents(JSAtom *atom) {
1613         return Valueify(ATOM_TO_JSVAL(atom ? atom : cx->runtime->atomState.emptyAtom));
1614     }
1615
1616     BinaryOperator binop(TokenKind tk, JSOp op);
1617     UnaryOperator unop(TokenKind tk, JSOp op);
1618     AssignmentOperator aop(JSOp op);
1619
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);
1627
1628     bool sourceElement(JSParseNode *pn, Value *dst);
1629
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);
1634
1635     bool optStatement(JSParseNode *pn, Value *dst) {
1636         if (!pn) {
1637             dst->setMagic(JS_SERIALIZE_NO_NODE);
1638             return true;
1639         }
1640         return statement(pn, dst);
1641     }
1642
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);
1650
1651     bool optExpression(JSParseNode *pn, Value *dst) {
1652         if (!pn) {
1653             dst->setMagic(JS_SERIALIZE_NO_NODE);
1654             return true;
1655         }
1656         return expression(pn, dst);
1657     }
1658
1659     bool expression(JSParseNode *pn, Value *dst);
1660
1661     bool propertyName(JSParseNode *pn, Value *dst);
1662     bool property(JSParseNode *pn, Value *dst);
1663
1664     bool optIdentifier(JSAtom *atom, TokenPos *pos, Value *dst) {
1665         if (!atom) {
1666             dst->setMagic(JS_SERIALIZE_NO_NODE);
1667             return true;
1668         }
1669         return identifier(atom, pos, dst);
1670     }
1671
1672     bool identifier(JSAtom *atom, TokenPos *pos, Value *dst);
1673     bool identifier(JSParseNode *pn, Value *dst);
1674     bool literal(JSParseNode *pn, Value *dst);
1675
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);
1679
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);
1683
1684     bool comprehensionBlock(JSParseNode *pn, Value *dst);
1685     bool comprehension(JSParseNode *pn, Value *dst);
1686     bool generatorExpression(JSParseNode *pn, Value *dst);
1687
1688     bool xml(JSParseNode *pn, Value *dst);
1689
1690   public:
1691     ASTSerializer(JSContext *c, bool l, char const *src, uint32 ln)
1692         : cx(c), builder(c, l, src), lineno(ln) {
1693     }
1694
1695     bool init(JSObject *userobj) {
1696         return builder.init(userobj);
1697     }
1698
1699     bool program(JSParseNode *pn, Value *dst);
1700 };
1701
1702 AssignmentOperator
1703 ASTSerializer::aop(JSOp op)
1704 {
1705     switch (op) {
1706       case JSOP_NOP:
1707         return AOP_ASSIGN;
1708       case JSOP_ADD:
1709         return AOP_PLUS;
1710       case JSOP_SUB:
1711         return AOP_MINUS;
1712       case JSOP_MUL:
1713         return AOP_STAR;
1714       case JSOP_DIV:
1715         return AOP_DIV;
1716       case JSOP_MOD:
1717         return AOP_MOD;
1718       case JSOP_LSH:
1719         return AOP_LSH;
1720       case JSOP_RSH:
1721         return AOP_RSH;
1722       case JSOP_URSH:
1723         return AOP_URSH;
1724       case JSOP_BITOR:
1725         return AOP_BITOR;
1726       case JSOP_BITXOR:
1727         return AOP_BITXOR;
1728       case JSOP_BITAND:
1729         return AOP_BITAND;
1730       default:
1731         return AOP_ERR;
1732     }
1733 }
1734
1735 UnaryOperator
1736 ASTSerializer::unop(TokenKind tk, JSOp op)
1737 {
1738     if (tk == TOK_DELETE)
1739         return UNOP_DELETE;
1740
1741     switch (op) {
1742       case JSOP_NEG:
1743         return UNOP_NEG;
1744       case JSOP_POS:
1745         return UNOP_POS;
1746       case JSOP_NOT:
1747         return UNOP_NOT;
1748       case JSOP_BITNOT:
1749         return UNOP_BITNOT;
1750       case JSOP_TYPEOF:
1751       case JSOP_TYPEOFEXPR:
1752         return UNOP_TYPEOF;
1753       case JSOP_VOID:
1754         return UNOP_VOID;
1755       default:
1756         return UNOP_ERR;
1757     }
1758 }
1759
1760 BinaryOperator
1761 ASTSerializer::binop(TokenKind tk, JSOp op)
1762 {
1763     switch (tk) {
1764       case TOK_EQOP:
1765         switch (op) {
1766           case JSOP_EQ:
1767             return BINOP_EQ;
1768           case JSOP_NE:
1769             return BINOP_NE;
1770           case JSOP_STRICTEQ:
1771             return BINOP_STRICTEQ;
1772           case JSOP_STRICTNE:
1773             return BINOP_STRICTNE;
1774           default:
1775             return BINOP_ERR;
1776         }
1777
1778       case TOK_RELOP:
1779         switch (op) {
1780           case JSOP_LT:
1781             return BINOP_LT;
1782           case JSOP_LE:
1783             return BINOP_LE;
1784           case JSOP_GT:
1785             return BINOP_GT;
1786           case JSOP_GE:
1787             return BINOP_GE;
1788           default:
1789             return BINOP_ERR;
1790         }
1791
1792       case TOK_SHOP:
1793         switch (op) {
1794           case JSOP_LSH:
1795             return BINOP_LSH;
1796           case JSOP_RSH:
1797             return BINOP_RSH;
1798           case JSOP_URSH:
1799             return BINOP_URSH;
1800           default:
1801             return BINOP_ERR;
1802         }
1803
1804       case TOK_PLUS:
1805         return BINOP_PLUS;
1806       case TOK_MINUS:
1807         return BINOP_MINUS;
1808       case TOK_STAR:
1809         return BINOP_STAR;
1810       case TOK_DIVOP:
1811         return (op == JSOP_MOD) ? BINOP_MOD : BINOP_DIV;
1812       case TOK_BITOR:
1813         return BINOP_BITOR;
1814       case TOK_BITXOR:
1815         return BINOP_BITXOR;
1816       case TOK_BITAND:
1817         return BINOP_BITAND;
1818       case TOK_IN:
1819         return BINOP_IN;
1820       case TOK_INSTANCEOF:
1821         return BINOP_INSTANCEOF;
1822       case TOK_DBLDOT:
1823         return BINOP_DBLDOT;
1824       default:
1825         return BINOP_ERR;
1826     }
1827 }
1828
1829 bool
1830 ASTSerializer::statements(JSParseNode *pn, NodeVector &elts)
1831 {
1832     JS_ASSERT(PN_TYPE(pn) == TOK_LC && pn->pn_arity == PN_LIST);
1833
1834     if (!elts.reserve(pn->pn_count))
1835         return false;
1836
1837     for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
1838         Value elt;
1839         if (!sourceElement(next, &elt))
1840             return false;
1841         JS_ALWAYS_TRUE(elts.append(elt)); /* space check above */
1842     }
1843
1844     return true;
1845 }
1846
1847 bool
1848 ASTSerializer::expressions(JSParseNode *pn, NodeVector &elts)
1849 {
1850     if (!elts.reserve(pn->pn_count))
1851         return false;
1852
1853     for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
1854         Value elt;
1855         if (!expression(next, &elt))
1856             return false;
1857         JS_ALWAYS_TRUE(elts.append(elt)); /* space check above */
1858     }
1859
1860     return true;
1861 }
1862
1863 bool
1864 ASTSerializer::xmls(JSParseNode *pn, NodeVector &elts)
1865 {
1866     if (!elts.reserve(pn->pn_count))
1867         return false;
1868
1869     for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
1870         Value elt;
1871         if (!xml(next, &elt))
1872             return false;
1873         JS_ALWAYS_TRUE(elts.append(elt)); /* space check above */
1874     }
1875
1876     return true;
1877 }
1878
1879 bool
1880 ASTSerializer::blockStatement(JSParseNode *pn, Value *dst)
1881 {
1882     JS_ASSERT(PN_TYPE(pn) == TOK_LC);
1883
1884     NodeVector stmts(cx);
1885     return statements(pn, stmts) &&
1886            builder.blockStatement(stmts, &pn->pn_pos, dst);
1887 }
1888
1889 bool
1890 ASTSerializer::program(JSParseNode *pn, Value *dst)
1891 {
1892     JS_ASSERT(pn);
1893
1894     /* Workaround for bug 588061: parser's reported start position is always 0:0. */
1895     pn->pn_pos.begin.lineno = lineno;
1896
1897     NodeVector stmts(cx);
1898     return statements(pn, stmts) &&
1899            builder.program(stmts, &pn->pn_pos, dst);
1900 }
1901
1902 bool
1903 ASTSerializer::sourceElement(JSParseNode *pn, Value *dst)
1904 {
1905     /* SpiderMonkey allows declarations even in pure statement contexts. */
1906     return statement(pn, dst);
1907 }
1908
1909 bool
1910 ASTSerializer::declaration(JSParseNode *pn, Value *dst)
1911 {
1912     JS_ASSERT(PN_TYPE(pn) == TOK_FUNCTION ||
1913               PN_TYPE(pn) == TOK_VAR ||
1914               PN_TYPE(pn) == TOK_LET);
1915
1916     switch (PN_TYPE(pn)) {
1917       case TOK_FUNCTION:
1918         return function(pn, AST_FUNC_DECL, dst);
1919
1920       case TOK_VAR:
1921         return variableDeclaration(pn, false, dst);
1922
1923       default:
1924         JS_ASSERT(PN_TYPE(pn) == TOK_LET);
1925         return variableDeclaration(pn, true, dst);
1926     }
1927 }
1928
1929 bool
1930 ASTSerializer::variableDeclaration(JSParseNode *pn, bool let, Value *dst)
1931 {
1932     JS_ASSERT(let ? PN_TYPE(pn) == TOK_LET : PN_TYPE(pn) == TOK_VAR);
1933
1934     /* Later updated to VARDECL_CONST if we find a PND_CONST declarator. */
1935     VarDeclKind kind = let ? VARDECL_LET : VARDECL_VAR;
1936
1937     NodeVector dtors(cx);
1938     if (!dtors.reserve(pn->pn_count))
1939         return false;
1940
1941     /* In a for-in context, variable declarations contain just a single pattern. */
1942     if (pn->pn_xflags & PNX_FORINVAR) {
1943         Value patt, child;
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);
1948     }
1949
1950     for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
1951         Value child;
1952         if (!variableDeclarator(next, &kind, &child))
1953             return false;
1954         JS_ALWAYS_TRUE(dtors.append(child)); /* space check above */
1955     }
1956
1957     return builder.variableDeclaration(dtors, kind, &pn->pn_pos, dst);
1958 }
1959
1960 bool
1961 ASTSerializer::variableDeclarator(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
1962 {
1963     /* A destructuring declarator is always a TOK_ASSIGN. */
1964     JS_ASSERT(PN_TYPE(pn) == TOK_NAME || PN_TYPE(pn) == TOK_ASSIGN);
1965
1966     JSParseNode *pnleft;
1967     JSParseNode *pnright;
1968
1969     if (PN_TYPE(pn) == TOK_NAME) {
1970         pnleft = pn;
1971         pnright = pn->pn_expr;
1972     } else {
1973         JS_ASSERT(PN_TYPE(pn) == TOK_ASSIGN);
1974         pnleft = pn->pn_left;
1975         pnright = pn->pn_right;
1976     }
1977
1978     Value left, right;
1979     return pattern(pnleft, pkind, &left) &&
1980            optExpression(pnright, &right) &&
1981            builder.variableDeclarator(left, right, &pn->pn_pos, dst);
1982 }
1983
1984 bool
1985 ASTSerializer::letHead(JSParseNode *pn, NodeVector &dtors)
1986 {
1987     if (!dtors.reserve(pn->pn_count))
1988         return false;
1989
1990     VarDeclKind kind = VARDECL_LET_HEAD;
1991
1992     for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
1993         Value child;
1994         /*
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.
1997          */
1998         if (!variableDeclarator(next, &kind, &child))
1999             return false;
2000         JS_ALWAYS_TRUE(dtors.append(child)); /* space check above */
2001     }
2002
2003     return true;
2004 }
2005
2006 bool
2007 ASTSerializer::switchCase(JSParseNode *pn, Value *dst)
2008 {
2009     NodeVector stmts(cx);
2010
2011     Value expr;
2012
2013     return optExpression(pn->pn_left, &expr) &&
2014            statements(pn->pn_right, stmts) &&
2015            builder.switchCase(expr, stmts, &pn->pn_pos, dst);
2016 }
2017
2018 bool
2019 ASTSerializer::switchStatement(JSParseNode *pn, Value *dst)
2020 {
2021     Value disc;
2022
2023     if (!expression(pn->pn_left, &disc))
2024         return false;
2025
2026     JSParseNode *listNode;
2027     bool lexical;
2028
2029     if (PN_TYPE(pn->pn_right) == TOK_LEXICALSCOPE) {
2030         listNode = pn->pn_right->pn_expr;
2031         lexical = true;
2032     } else {
2033         listNode = pn->pn_right;
2034         lexical = false;
2035     }
2036
2037     NodeVector cases(cx);
2038     if (!cases.reserve(listNode->pn_count))
2039         return false;
2040
2041     for (JSParseNode *next = listNode->pn_head; next; next = next->pn_next) {
2042         Value child;
2043 #ifdef __GNUC__ /* quell GCC overwarning */
2044         child = UndefinedValue();
2045 #endif
2046         if (!switchCase(next, &child))
2047             return false;
2048         JS_ALWAYS_TRUE(cases.append(child)); /* space check above */
2049     }
2050
2051     return builder.switchStatement(disc, cases, lexical, &pn->pn_pos, dst);
2052 }
2053
2054 bool
2055 ASTSerializer::catchClause(JSParseNode *pn, Value *dst)
2056 {
2057     Value var, guard, body;
2058
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);
2063 }
2064
2065 bool
2066 ASTSerializer::tryStatement(JSParseNode *pn, Value *dst)
2067 {
2068     Value body;
2069     if (!statement(pn->pn_kid1, &body))
2070         return false;
2071
2072     NodeVector clauses(cx);
2073     if (pn->pn_kid2) {
2074         if (!clauses.reserve(pn->pn_kid2->pn_count))
2075             return false;
2076
2077         for (JSParseNode *next = pn->pn_kid2->pn_head; next; next = next->pn_next) {
2078             Value clause;
2079             if (!catchClause(next->pn_expr, &clause))
2080                 return false;
2081             JS_ALWAYS_TRUE(clauses.append(clause)); /* space check above */
2082         }
2083     }
2084
2085     Value finally;
2086     return optStatement(pn->pn_kid3, &finally) &&
2087            builder.tryStatement(body, clauses, finally, &pn->pn_pos, dst);
2088 }
2089
2090 bool
2091 ASTSerializer::forInit(JSParseNode *pn, Value *dst)
2092 {
2093     if (!pn) {
2094         dst->setMagic(JS_SERIALIZE_NO_NODE);
2095         return true;
2096     }
2097
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);
2103 }
2104
2105 bool
2106 ASTSerializer::statement(JSParseNode *pn, Value *dst)
2107 {
2108     switch (PN_TYPE(pn)) {
2109       case TOK_FUNCTION:
2110       case TOK_VAR:
2111       case TOK_LET:
2112         return declaration(pn, dst);
2113
2114       case TOK_NAME:
2115         LOCAL_ASSERT(pn->pn_used);
2116         return statement(pn->pn_lexdef, dst);
2117
2118       case TOK_SEMI:
2119         if (pn->pn_kid) {
2120             Value expr;
2121             return expression(pn->pn_kid, &expr) &&
2122                    builder.expressionStatement(expr, &pn->pn_pos, dst);
2123         }
2124         return builder.emptyStatement(&pn->pn_pos, dst);
2125
2126       case TOK_LEXICALSCOPE:
2127         pn = pn->pn_expr;
2128         if (PN_TYPE(pn) == TOK_LET) {
2129             NodeVector dtors(cx);
2130             Value stmt;
2131
2132             return letHead(pn->pn_left, dtors) &&
2133                    statement(pn->pn_right, &stmt) &&
2134                    builder.letStatement(dtors, stmt, &pn->pn_pos, dst);
2135         }
2136
2137         if (PN_TYPE(pn) != TOK_LC)
2138             return statement(pn, dst);
2139         /* FALL THROUGH */
2140
2141       case TOK_LC:
2142         return blockStatement(pn, dst);
2143
2144       case TOK_IF:
2145       {
2146         Value test, cons, alt;
2147
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);
2152       }
2153
2154       case TOK_SWITCH:
2155         return switchStatement(pn, dst);
2156
2157       case TOK_TRY:
2158         return tryStatement(pn, dst);
2159
2160       case TOK_WITH:
2161       case TOK_WHILE:
2162       {
2163         Value expr, stmt;
2164
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);
2170       }
2171
2172       case TOK_DO:
2173       {
2174         Value stmt, test;
2175
2176         return statement(pn->pn_left, &stmt) &&
2177                expression(pn->pn_right, &test) &&
2178                builder.doWhileStatement(stmt, test, &pn->pn_pos, dst);
2179       }
2180
2181       case TOK_FOR:
2182       {
2183         JSParseNode *head = pn->pn_left;
2184
2185         Value stmt;
2186         if (!statement(pn->pn_right, &stmt))
2187             return false;
2188
2189         bool isForEach = pn->pn_iflags & JSITER_FOREACH;
2190
2191         if (PN_TYPE(head) == TOK_IN) {
2192             Value var, expr;
2193
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);
2201         }
2202
2203         Value init, test, update;
2204
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);
2209       }
2210
2211       /* Synthesized by the parser when a for-in loop contains a variable initializer. */
2212       case TOK_SEQ:
2213       {
2214         LOCAL_ASSERT(pn->pn_count == 2);
2215
2216         JSParseNode *prelude = pn->pn_head;
2217         JSParseNode *body = prelude->pn_next;
2218
2219         LOCAL_ASSERT((PN_TYPE(prelude) == TOK_VAR && PN_TYPE(body) == TOK_FOR) ||
2220                      (PN_TYPE(prelude) == TOK_SEMI && PN_TYPE(body) == TOK_LEXICALSCOPE));
2221
2222         JSParseNode *loop;
2223         Value var;
2224
2225         if (PN_TYPE(prelude) == TOK_VAR) {
2226             loop = body;
2227
2228             if (!variableDeclaration(prelude, false, &var))
2229                 return false;
2230         } else {
2231             loop = body->pn_expr;
2232
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);
2236
2237             JSParseNode *pnlet = loop->pn_left->pn_left;
2238
2239             VarDeclKind kind = VARDECL_LET;
2240             NodeVector dtors(cx);
2241             Value patt, init, dtor;
2242
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)) {
2248                 return false;
2249             }
2250         }
2251
2252         JSParseNode *head = loop->pn_left;
2253         JS_ASSERT(PN_TYPE(head) == TOK_IN);
2254
2255         bool isForEach = loop->pn_iflags & JSITER_FOREACH;
2256
2257         Value expr, stmt;
2258
2259         return expression(head->pn_right, &expr) &&
2260                statement(loop->pn_right, &stmt) &&
2261                builder.forInStatement(var, expr, stmt, isForEach, &pn->pn_pos, dst);
2262       }
2263
2264       case TOK_BREAK:
2265       case TOK_CONTINUE:
2266       {
2267         Value label;
2268
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));
2273       }
2274
2275       case TOK_COLON:
2276       {
2277         Value label, stmt;
2278
2279         return identifier(pn->pn_atom, NULL, &label) &&
2280                statement(pn->pn_expr, &stmt) &&
2281                builder.labeledStatement(label, stmt, &pn->pn_pos, dst);
2282       }
2283
2284       case TOK_THROW:
2285       case TOK_RETURN:
2286       {
2287         Value arg;
2288
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));
2293       }
2294
2295       case TOK_DEBUGGER:
2296         return builder.debuggerStatement(&pn->pn_pos, dst);
2297
2298 #if JS_HAS_XML_SUPPORT
2299       case TOK_DEFAULT:
2300       {
2301         LOCAL_ASSERT(pn->pn_arity == PN_UNARY);
2302
2303         Value ns;
2304
2305         return expression(pn->pn_kid, &ns) &&
2306                builder.xmlDefaultNamespace(ns, &pn->pn_pos, dst);
2307       }
2308 #endif
2309
2310       default:
2311         LOCAL_NOT_REACHED("unexpected statement type");
2312     }
2313 }
2314
2315 bool
2316 ASTSerializer::leftAssociate(JSParseNode *pn, Value *dst)
2317 {
2318     JS_ASSERT(pn->pn_arity == PN_LIST);
2319
2320     const size_t len = pn->pn_count;
2321     JS_ASSERT(len >= 1);
2322
2323     if (len == 1)
2324         return expression(pn->pn_head, dst);
2325
2326     JS_ASSERT(len >= 2);
2327
2328     Vector<JSParseNode *, 8> list(cx);
2329     if (!list.reserve(len))
2330         return false;
2331
2332     for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
2333         JS_ALWAYS_TRUE(list.append(next)); /* space check above */
2334     }
2335
2336     TokenKind tk = PN_TYPE(pn);
2337
2338     bool lor = tk == TOK_OR;
2339     bool logop = lor || (tk == TOK_AND);
2340
2341     Value right;
2342
2343     if (!expression(list[len - 1], &right))
2344         return false;
2345
2346     size_t i = len - 2;
2347
2348     do {
2349         JSParseNode *next = list[i];
2350
2351         Value left;
2352         if (!expression(next, &left))
2353             return false;
2354
2355         TokenPos subpos = { next->pn_pos.begin, pn->pn_pos.end };
2356
2357         if (logop) {
2358             if (!builder.logicalExpression(lor, left, right, &subpos, &right))
2359                 return false;
2360         } else {
2361             BinaryOperator op = binop(PN_TYPE(pn), PN_OP(pn));
2362             LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
2363
2364             if (!builder.binaryExpression(op, left, right, &subpos, &right))
2365                 return false;
2366         }
2367     } while (i-- != 0);
2368
2369     *dst = right;
2370     return true;
2371 }
2372
2373 bool
2374 ASTSerializer::binaryOperands(JSParseNode *pn, NodeVector &elts)
2375 {
2376     if (pn->pn_arity == PN_BINARY) {
2377         Value left, right;
2378
2379         return expression(pn->pn_left, &left) &&
2380                elts.append(left) &&
2381                expression(pn->pn_right, &right) &&
2382                elts.append(right);
2383     }
2384
2385     LOCAL_ASSERT(pn->pn_arity == PN_LIST);
2386
2387     return expressions(pn, elts);
2388 }
2389
2390 bool
2391 ASTSerializer::comprehensionBlock(JSParseNode *pn, Value *dst)
2392 {
2393     LOCAL_ASSERT(pn->pn_arity == PN_BINARY);
2394
2395     JSParseNode *in = pn->pn_left;
2396
2397     LOCAL_ASSERT(in && PN_TYPE(in) == TOK_IN);
2398
2399     bool isForEach = pn->pn_iflags & JSITER_FOREACH;
2400
2401     Value patt, src;
2402     return pattern(in->pn_left, NULL, &patt) &&
2403            expression(in->pn_right, &src) &&
2404            builder.comprehensionBlock(patt, src, isForEach, &in->pn_pos, dst);
2405 }
2406
2407 bool
2408 ASTSerializer::comprehension(JSParseNode *pn, Value *dst)
2409 {
2410     LOCAL_ASSERT(PN_TYPE(pn) == TOK_FOR);
2411
2412     NodeVector blocks(cx);
2413
2414     JSParseNode *next = pn;
2415     while (PN_TYPE(next) == TOK_FOR) {
2416         Value block;
2417         if (!comprehensionBlock(next, &block) || !blocks.append(block))
2418             return false;
2419         next = next->pn_right;
2420     }
2421
2422     Value filter = MagicValue(JS_SERIALIZE_NO_NODE);
2423
2424     if (PN_TYPE(next) == TOK_IF) {
2425         if (!optExpression(next->pn_kid1, &filter))
2426             return false;
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);
2432     }
2433
2434     LOCAL_ASSERT(PN_TYPE(next) == TOK_ARRAYPUSH);
2435
2436     Value body;
2437
2438     return expression(next->pn_kid, &body) &&
2439            builder.comprehensionExpression(body, blocks, filter, &pn->pn_pos, dst);
2440 }
2441
2442 bool
2443 ASTSerializer::generatorExpression(JSParseNode *pn, Value *dst)
2444 {
2445     LOCAL_ASSERT(PN_TYPE(pn) == TOK_FOR);
2446
2447     NodeVector blocks(cx);
2448
2449     JSParseNode *next = pn;
2450     while (PN_TYPE(next) == TOK_FOR) {
2451         Value block;
2452         if (!comprehensionBlock(next, &block) || !blocks.append(block))
2453             return false;
2454         next = next->pn_right;
2455     }
2456
2457     Value filter = MagicValue(JS_SERIALIZE_NO_NODE);
2458
2459     if (PN_TYPE(next) == TOK_IF) {
2460         if (!optExpression(next->pn_kid1, &filter))
2461             return false;
2462         next = next->pn_kid2;
2463     }
2464
2465     LOCAL_ASSERT(PN_TYPE(next) == TOK_SEMI &&
2466                  PN_TYPE(next->pn_kid) == TOK_YIELD &&
2467                  next->pn_kid->pn_kid);
2468
2469     Value body;
2470
2471     return expression(next->pn_kid->pn_kid, &body) &&
2472            builder.generatorExpression(body, blocks, filter, &pn->pn_pos, dst);
2473 }
2474
2475 bool
2476 ASTSerializer::expression(JSParseNode *pn, Value *dst)
2477 {
2478     switch (PN_TYPE(pn)) {
2479       case TOK_FUNCTION:
2480         return function(pn, AST_FUNC_EXPR, dst);
2481
2482       case TOK_COMMA:
2483       {
2484         NodeVector exprs(cx);
2485         return expressions(pn, exprs) &&
2486                builder.sequenceExpression(exprs, &pn->pn_pos, dst);
2487       }
2488
2489       case TOK_HOOK:
2490       {
2491         Value test, cons, alt;
2492
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);
2497       }
2498
2499       case TOK_OR:
2500       case TOK_AND:
2501       {
2502         if (pn->pn_arity == PN_BINARY) {
2503             Value left, right;
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);
2507         }
2508         return leftAssociate(pn, dst);
2509       }
2510
2511       case TOK_INC:
2512       case TOK_DEC:
2513       {
2514         bool incr = PN_TYPE(pn) == TOK_INC;
2515         bool prefix = PN_OP(pn) >= JSOP_INCNAME && PN_OP(pn) <= JSOP_DECELEM;
2516
2517         Value expr;
2518         return expression(pn->pn_kid, &expr) &&
2519                builder.updateExpression(expr, incr, prefix, &pn->pn_pos, dst);
2520       }
2521
2522       case TOK_ASSIGN:
2523       {
2524         AssignmentOperator op = aop(PN_OP(pn));
2525         LOCAL_ASSERT(op > AOP_ERR && op < AOP_LIMIT);
2526
2527         Value lhs, rhs;
2528         return pattern(pn->pn_left, NULL, &lhs) &&
2529                expression(pn->pn_right, &rhs) &&
2530                builder.assignmentExpression(op, lhs, rhs, &pn->pn_pos, dst);
2531       }
2532
2533       case TOK_EQOP:
2534       case TOK_RELOP:
2535       case TOK_SHOP:
2536       case TOK_PLUS:
2537       case TOK_MINUS:
2538       case TOK_STAR:
2539       case TOK_DIVOP:
2540       case TOK_BITOR:
2541       case TOK_BITXOR:
2542       case TOK_BITAND:
2543       case TOK_IN:
2544       case TOK_INSTANCEOF:
2545       case TOK_DBLDOT:
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);
2549
2550             Value left, right;
2551             return expression(pn->pn_left, &left) &&
2552                    expression(pn->pn_right, &right) &&
2553                    builder.binaryExpression(op, left, right, &pn->pn_pos, dst);
2554         }
2555         return leftAssociate(pn, dst);
2556
2557       case TOK_DELETE:
2558       case TOK_UNARYOP:
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);
2564 #endif
2565
2566       {
2567         UnaryOperator op = unop(PN_TYPE(pn), PN_OP(pn));
2568         LOCAL_ASSERT(op > UNOP_ERR && op < UNOP_LIMIT);
2569
2570         Value expr;
2571         return expression(pn->pn_kid, &expr) &&
2572                builder.unaryExpression(op, expr, &pn->pn_pos, dst);
2573       }
2574
2575       case TOK_NEW:
2576       case TOK_LP:
2577       {
2578 #ifdef JS_HAS_GENERATOR_EXPRS
2579         if (pn->isGeneratorExpr())
2580             return generatorExpression(pn->generatorExpr(), dst);
2581 #endif
2582
2583         JSParseNode *next = pn->pn_head;
2584
2585         Value callee;
2586         if (!expression(next, &callee))
2587             return false;
2588
2589         NodeVector args(cx);
2590         if (!args.reserve(pn->pn_count - 1))
2591             return false;
2592
2593         for (next = next->pn_next; next; next = next->pn_next) {
2594             Value arg;
2595             if (!expression(next, &arg))
2596                 return false;
2597             JS_ALWAYS_TRUE(args.append(arg)); /* space check above */
2598         }
2599
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);
2603       }
2604
2605       case TOK_DOT:
2606       {
2607         Value expr, id;
2608         return expression(pn->pn_expr, &expr) &&
2609                identifier(pn->pn_atom, NULL, &id) &&
2610                builder.memberExpression(false, expr, id, &pn->pn_pos, dst);
2611       }
2612
2613       case TOK_LB:
2614       {
2615         Value left, right;
2616         return expression(pn->pn_left, &left) &&
2617                expression(pn->pn_right, &right) &&
2618                builder.memberExpression(true, left, right, &pn->pn_pos, dst);
2619       }
2620
2621       case TOK_RB:
2622       {
2623         NodeVector elts(cx);
2624         if (!elts.reserve(pn->pn_count))
2625             return false;
2626
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 */
2630             } else {
2631                 Value expr;
2632                 if (!expression(next, &expr))
2633                     return false;
2634                 JS_ALWAYS_TRUE(elts.append(expr)); /* space check above */
2635             }
2636         }
2637
2638         return builder.arrayExpression(elts, &pn->pn_pos, dst);
2639       }
2640
2641       case TOK_RC:
2642       {
2643         NodeVector elts(cx);
2644         if (!elts.reserve(pn->pn_count))
2645             return false;
2646
2647         for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
2648             Value prop;
2649             if (!property(next, &prop))
2650                 return false;
2651             JS_ALWAYS_TRUE(elts.append(prop)); /* space check above */
2652         }
2653
2654         return builder.objectExpression(elts, &pn->pn_pos, dst);
2655       }
2656
2657       case TOK_NAME:
2658         return identifier(pn, dst);
2659
2660       case TOK_STRING:
2661       case TOK_REGEXP:
2662       case TOK_NUMBER:
2663       case TOK_PRIMARY:
2664         return PN_OP(pn) == JSOP_THIS ? builder.thisExpression(&pn->pn_pos, dst) : literal(pn, dst);
2665
2666       case TOK_YIELD:
2667       {
2668         Value arg;
2669         return optExpression(pn->pn_kid, &arg) &&
2670                builder.yieldExpression(arg, &pn->pn_pos, dst);
2671       }
2672
2673       case TOK_DEFSHARP:
2674       {
2675         Value expr;
2676         return expression(pn->pn_kid, &expr) &&
2677                builder.graphExpression(pn->pn_num, expr, &pn->pn_pos, dst);
2678       }
2679
2680       case TOK_USESHARP:
2681         return builder.graphIndexExpression(pn->pn_num, &pn->pn_pos, dst);
2682
2683       case TOK_ARRAYCOMP:
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);
2687
2688         return comprehension(pn->pn_head->pn_expr, dst);
2689
2690       case TOK_LEXICALSCOPE:
2691       {
2692         pn = pn->pn_expr;
2693
2694         NodeVector dtors(cx);
2695         Value expr;
2696
2697         return letHead(pn->pn_left, dtors) &&
2698                expression(pn->pn_right, &expr) &&
2699                builder.letExpression(dtors, expr, &pn->pn_pos, dst);
2700       }
2701
2702 #ifdef JS_HAS_XML_SUPPORT
2703       case TOK_ANYNAME:
2704         return builder.xmlAnyName(&pn->pn_pos, dst);
2705
2706       case TOK_DBLCOLON:
2707       {
2708         Value right;
2709
2710         LOCAL_ASSERT(pn->pn_arity == PN_NAME || pn->pn_arity == PN_BINARY);
2711
2712         JSParseNode *pnleft;
2713         bool computed;
2714
2715         if (pn->pn_arity == PN_BINARY) {
2716             computed = true;
2717             pnleft = pn->pn_left;
2718             if (!expression(pn->pn_right, &right))
2719                 return false;
2720         } else {
2721             JS_ASSERT(pn->pn_arity == PN_NAME);
2722             computed = false;
2723             pnleft = pn->pn_expr;
2724             if (!identifier(pn->pn_atom, NULL, &right))
2725                 return false;
2726         }
2727
2728         if (PN_TYPE(pnleft) == TOK_FUNCTION)
2729             return builder.xmlFunctionQualifiedIdentifier(right, computed, &pn->pn_pos, dst);
2730
2731         Value left;
2732         return expression(pnleft, &left) &&
2733                builder.xmlQualifiedIdentifier(left, right, computed, &pn->pn_pos, dst);
2734       }
2735
2736       case TOK_AT:
2737       {
2738         Value expr;
2739         return expression(pn->pn_kid, &expr) &&
2740                builder.xmlAttributeSelector(expr, &pn->pn_pos, dst);
2741       }
2742
2743       case TOK_FILTER:
2744       {
2745         Value left, right;
2746         return expression(pn->pn_left, &left) &&
2747                expression(pn->pn_right, &right) &&
2748                builder.xmlFilterExpression(left, right, &pn->pn_pos, dst);
2749       }
2750
2751       default:
2752         return xml(pn, dst);
2753
2754 #else
2755       default:
2756         LOCAL_NOT_REACHED("unexpected expression type");
2757 #endif
2758     }
2759 }
2760
2761 bool
2762 ASTSerializer::xml(JSParseNode *pn, Value *dst)
2763 {
2764     switch (PN_TYPE(pn)) {
2765 #ifdef JS_HAS_XML_SUPPORT
2766       case TOK_LC:
2767       {
2768         Value expr;
2769         return expression(pn->pn_kid, &expr) &&
2770                builder.xmlEscapeExpression(expr, &pn->pn_pos, dst);
2771       }
2772
2773       case TOK_XMLELEM:
2774       {
2775         NodeVector elts(cx);
2776         if (!xmls(pn, elts))
2777             return false;
2778         return builder.xmlElement(elts, &pn->pn_pos, dst);
2779       }
2780
2781       case TOK_XMLLIST:
2782       {
2783         NodeVector elts(cx);
2784         if (!xmls(pn, elts))
2785             return false;
2786         return builder.xmlList(elts, &pn->pn_pos, dst);
2787       }
2788
2789       case TOK_XMLSTAGO:
2790       {
2791         NodeVector elts(cx);
2792         if (!xmls(pn, elts))
2793             return false;
2794         return builder.xmlStartTag(elts, &pn->pn_pos, dst);
2795       }
2796
2797       case TOK_XMLETAGO:
2798       {
2799         NodeVector elts(cx);
2800         if (!xmls(pn, elts))
2801             return false;
2802         return builder.xmlEndTag(elts, &pn->pn_pos, dst);
2803       }
2804
2805       case TOK_XMLPTAGC:
2806       {
2807         NodeVector elts(cx);
2808         if (!xmls(pn, elts))
2809             return false;
2810         return builder.xmlPointTag(elts, &pn->pn_pos, dst);
2811       }
2812
2813       case TOK_XMLTEXT:
2814       case TOK_XMLSPACE:
2815         return builder.xmlText(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2816
2817       case TOK_XMLNAME:
2818         if (pn->pn_arity == PN_NULLARY)
2819             return builder.xmlName(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2820
2821         LOCAL_ASSERT(pn->pn_arity == PN_LIST);
2822
2823         {
2824             NodeVector elts(cx);
2825             return xmls(pn, elts) &&
2826                    builder.xmlName(elts, &pn->pn_pos, dst);
2827         }
2828
2829       case TOK_XMLATTR:
2830         return builder.xmlAttribute(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2831
2832       case TOK_XMLCDATA:
2833         return builder.xmlCdata(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2834
2835       case TOK_XMLCOMMENT:
2836         return builder.xmlComment(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2837
2838       case TOK_XMLPI:
2839         if (!pn->pn_atom2)
2840             return builder.xmlPI(atomContents(pn->pn_atom), &pn->pn_pos, dst);
2841         else
2842             return builder.xmlPI(atomContents(pn->pn_atom),
2843                                  atomContents(pn->pn_atom2),
2844                                  &pn->pn_pos,
2845                                  dst);
2846 #endif
2847
2848       default:
2849         LOCAL_NOT_REACHED("unexpected XML node type");
2850     }
2851 }
2852
2853 bool
2854 ASTSerializer::propertyName(JSParseNode *pn, Value *dst)
2855 {
2856     if (PN_TYPE(pn) == TOK_NAME)
2857         return identifier(pn, dst);
2858
2859     LOCAL_ASSERT(PN_TYPE(pn) == TOK_STRING || PN_TYPE(pn) == TOK_NUMBER);
2860
2861     return literal(pn, dst);
2862 }
2863
2864 bool
2865 ASTSerializer::property(JSParseNode *pn, Value *dst)
2866 {
2867     PropKind kind;
2868     switch (PN_OP(pn)) {
2869       case JSOP_INITPROP:
2870         kind = PROP_INIT;
2871         break;
2872
2873       case JSOP_GETTER:
2874         kind = PROP_GETTER;
2875         break;
2876
2877       case JSOP_SETTER:
2878         kind = PROP_SETTER;
2879         break;
2880
2881       default:
2882         LOCAL_NOT_REACHED("unexpected object-literal property");
2883     }
2884
2885     Value key, val;
2886     return propertyName(pn->pn_left, &key) &&
2887            expression(pn->pn_right, &val) &&
2888            builder.propertyInitializer(key, val, kind, &pn->pn_pos, dst);
2889 }
2890
2891 bool
2892 ASTSerializer::literal(JSParseNode *pn, Value *dst)
2893 {
2894     Value val;
2895     switch (PN_TYPE(pn)) {
2896       case TOK_STRING:
2897         val = Valueify(ATOM_TO_JSVAL(pn->pn_atom));
2898         break;
2899
2900       case TOK_REGEXP:
2901       {
2902         JSObject *re1 = pn->pn_objbox ? pn->pn_objbox->object : NULL;
2903         LOCAL_ASSERT(re1 && re1->isRegExp());
2904
2905         JSObject *proto;
2906         if (!js_GetClassPrototype(cx, &cx->fp()->scopeChain(), JSProto_RegExp, &proto))
2907             return false;
2908
2909         JSObject *re2 = js_CloneRegExpObject(cx, re1, proto);
2910         if (!re2)
2911             return false;
2912
2913         val.setObject(*re2);
2914         break;
2915       }
2916
2917       case TOK_NUMBER:
2918         val.setNumber(pn->pn_dval);
2919         break;
2920
2921       case TOK_PRIMARY:
2922         if (PN_OP(pn) == JSOP_NULL)
2923             val.setNull();
2924         else
2925             val.setBoolean(PN_OP(pn) == JSOP_TRUE);
2926         break;
2927
2928       default:
2929         LOCAL_NOT_REACHED("unexpected literal type");
2930     }
2931
2932     return builder.literal(val, &pn->pn_pos, dst);
2933 }
2934
2935 bool
2936 ASTSerializer::arrayPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
2937 {
2938     JS_ASSERT(PN_TYPE(pn) == TOK_RB);
2939
2940     NodeVector elts(cx);
2941     if (!elts.reserve(pn->pn_count))
2942         return false;
2943
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 */
2947         } else {
2948             Value patt;
2949             if (!pattern(next, pkind, &patt))
2950                 return false;
2951             JS_ALWAYS_TRUE(elts.append(patt)); /* space check above */
2952         }
2953     }
2954
2955     return builder.arrayPattern(elts, &pn->pn_pos, dst);
2956 }
2957
2958 bool
2959 ASTSerializer::objectPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
2960 {
2961     JS_ASSERT(PN_TYPE(pn) == TOK_RC);
2962
2963     NodeVector elts(cx);
2964     if (!elts.reserve(pn->pn_count))
2965         return false;
2966
2967     for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
2968         LOCAL_ASSERT(PN_OP(next) == JSOP_INITPROP);
2969
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)) {
2974             return false;
2975         }
2976
2977         JS_ALWAYS_TRUE(elts.append(prop)); /* space check above */
2978     }
2979
2980     return builder.objectPattern(elts, &pn->pn_pos, dst);
2981 }
2982
2983 bool
2984 ASTSerializer::pattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
2985 {
2986     switch (PN_TYPE(pn)) {
2987       case TOK_RC:
2988         return objectPattern(pn, pkind, dst);
2989
2990       case TOK_RB:
2991         return arrayPattern(pn, pkind, dst);
2992
2993       case TOK_NAME:
2994         if (pkind && (pn->pn_dflags & PND_CONST))
2995             *pkind = VARDECL_CONST;
2996         /* FALL THROUGH */
2997
2998       default:
2999         return expression(pn, dst);
3000     }
3001 }
3002
3003 bool
3004 ASTSerializer::identifier(JSAtom *atom, TokenPos *pos, Value *dst)
3005 {
3006     return builder.identifier(atomContents(atom), pos, dst);
3007 }
3008
3009 bool
3010 ASTSerializer::identifier(JSParseNode *pn, Value *dst)
3011 {
3012     LOCAL_ASSERT(pn->pn_arity == PN_NAME || pn->pn_arity == PN_NULLARY);
3013     LOCAL_ASSERT(pn->pn_atom);
3014
3015     return identifier(pn->pn_atom, &pn->pn_pos, dst);
3016 }
3017
3018 bool
3019 ASTSerializer::function(JSParseNode *pn, ASTType type, Value *dst)
3020 {
3021     JSFunction *func = (JSFunction *)pn->pn_funbox->object;
3022
3023     bool isGenerator =
3024 #ifdef JS_HAS_GENERATORS
3025         pn->pn_funbox->tcflags & TCF_FUN_IS_GENERATOR;
3026 #else
3027         false;
3028 #endif
3029
3030     bool isExpression =
3031 #ifdef JS_HAS_EXPR_CLOSURES
3032         func->flags & JSFUN_EXPR_CLOSURE;
3033 #else
3034         false;
3035 #endif
3036
3037     Value id;
3038     if (!optIdentifier(func->atom, NULL, &id))
3039         return false;
3040
3041     NodeVector args(cx);
3042
3043     JSParseNode *argsAndBody = (PN_TYPE(pn->pn_body) == TOK_UPVARS)
3044                                ? pn->pn_body->pn_tree
3045                                : pn->pn_body;
3046
3047     Value body;
3048     return functionArgsAndBody(argsAndBody, args, &body) &&
3049            builder.function(type, &pn->pn_pos, id, args, body, isGenerator, isExpression, dst);
3050 }
3051
3052 bool
3053 ASTSerializer::functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *body)
3054 {
3055     JSParseNode *pnargs;
3056     JSParseNode *pnbody;
3057
3058     /* Extract the args and body separately. */
3059     if (PN_TYPE(pn) == TOK_ARGSBODY) {
3060         pnargs = pn;
3061         pnbody = pn->last();
3062     } else {
3063         pnargs = NULL;
3064         pnbody = pn;
3065     }
3066
3067     JSParseNode *pndestruct;
3068
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);
3073
3074         pndestruct = head->pn_kid;
3075         LOCAL_ASSERT(pndestruct && PN_TYPE(pndestruct) == TOK_VAR);
3076     } else {
3077         pndestruct = NULL;
3078     }
3079
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);
3085
3086       case TOK_SEQ:    /* expression closure with destructured args */
3087       {
3088         JSParseNode *pnstart = pnbody->pn_head->pn_next;
3089         LOCAL_ASSERT(pnstart && PN_TYPE(pnstart) == TOK_RETURN);
3090
3091         return functionArgs(pn, pnargs, pndestruct, pnbody, args) &&
3092                expression(pnstart->pn_kid, body);
3093       }
3094
3095       case TOK_LC:     /* statement closure */
3096       {
3097         JSParseNode *pnstart = (pnbody->pn_xflags & PNX_DESTRUCT)
3098                                ? pnbody->pn_head->pn_next
3099                                : pnbody->pn_head;
3100
3101         return functionArgs(pn, pnargs, pndestruct, pnbody, args) &&
3102                functionBody(pnstart, &pnbody->pn_pos, body);
3103       }
3104
3105       default:
3106         LOCAL_NOT_REACHED("unexpected function contents");
3107     }
3108 }
3109
3110 bool
3111 ASTSerializer::functionArgs(JSParseNode *pn, JSParseNode *pnargs, JSParseNode *pndestruct,
3112                             JSParseNode *pnbody, NodeVector &args)
3113 {
3114     uint32 i = 0;
3115     JSParseNode *arg = pnargs ? pnargs->pn_head : NULL;
3116     JSParseNode *destruct = pndestruct ? pndestruct->pn_head : NULL;
3117     Value node;
3118
3119     /*
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
3125      * both.
3126      */
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))
3130                 return false;
3131             destruct = destruct->pn_next;
3132         } else if (arg && arg != pnbody) {
3133             /*
3134              * We don't check that arg->frameSlot() == i since we
3135              * can't call that method if the arg def has been turned
3136              * into a use, e.g.:
3137              *
3138              *     function(a) { function a() { } }
3139              *
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.
3143              */
3144             if (!identifier(arg, &node) || !args.append(node))
3145                 return false;
3146             arg = arg->pn_next;
3147         } else {
3148             LOCAL_NOT_REACHED("missing function argument");
3149         }
3150         ++i;
3151     }
3152
3153     return true;
3154 }
3155
3156 bool
3157 ASTSerializer::functionBody(JSParseNode *pn, TokenPos *pos, Value *dst)
3158 {
3159     NodeVector elts(cx);
3160
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) {
3163         Value child;
3164         if (!sourceElement(next, &child) || !elts.append(child))
3165             return false;
3166     }
3167
3168     return builder.blockStatement(elts, pos, dst);
3169 }
3170
3171 } /* namespace js */
3172
3173 /* Reflect class */
3174
3175 Class js_ReflectClass = {
3176     js_Reflect_str,
3177     JSCLASS_HAS_CACHED_PROTO(JSProto_Reflect),
3178     PropertyStub,
3179     PropertyStub,
3180     PropertyStub,
3181     StrictPropertyStub,
3182     EnumerateStub,
3183     ResolveStub,
3184     ConvertStub
3185 };
3186
3187 static JSBool
3188 reflect_parse(JSContext *cx, uint32 argc, jsval *vp)
3189 {
3190     if (argc < 1) {
3191         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
3192                              "Reflect.parse", "0", "s");
3193         return JS_FALSE;
3194     }
3195
3196     JSString *src = js_ValueToString(cx, Valueify(JS_ARGV(cx, vp)[0]));
3197     if (!src)
3198         return JS_FALSE;
3199
3200     char *filename = NULL;
3201     AutoReleaseNullablePtr filenamep(cx, filename);
3202     uint32 lineno = 1;
3203     bool loc = true;
3204
3205     JSObject *builder = NULL;
3206
3207     Value arg = argc > 1 ? Valueify(JS_ARGV(cx, vp)[1]) : UndefinedValue();
3208
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);
3213             return JS_FALSE;
3214         }
3215
3216         JSObject *config = &arg.toObject();
3217
3218         Value prop;
3219
3220         /* config.loc */
3221         if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.locAtom),
3222                                 BooleanValue(true), &prop)) {
3223             return JS_FALSE;
3224         }
3225
3226         loc = js_ValueToBoolean(prop);
3227
3228         if (loc) {
3229             /* config.source */
3230             if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.sourceAtom),
3231                                     NullValue(), &prop)) {
3232                 return JS_FALSE;
3233             }
3234
3235             if (!prop.isNullOrUndefined()) {
3236                 JSString *str = js_ValueToString(cx, prop);
3237                 if (!str)
3238                     return JS_FALSE;
3239
3240                 size_t length = str->length();
3241                 const jschar *chars = str->getChars(cx);
3242                 if (!chars)
3243                     return JS_FALSE;
3244
3245                 filename = js_DeflateString(cx, chars, length);
3246                 if (!filename)
3247                     return JS_FALSE;
3248                 filenamep.reset(filename);
3249             }
3250
3251             /* config.line */
3252             if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.lineAtom),
3253                                     Int32Value(1), &prop) ||
3254                 !ValueToECMAUint32(cx, prop, &lineno)) {
3255                 return JS_FALSE;
3256             }
3257         }
3258
3259         /* config.builder */
3260         if (!GetPropertyDefault(cx, config, ATOM_TO_JSID(cx->runtime->atomState.builderAtom),
3261                                 NullValue(), &prop)) {
3262             return JS_FALSE;
3263         }
3264
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);
3269                 return JS_FALSE;
3270             }
3271             builder = &prop.toObject();
3272         }
3273     }
3274
3275     /* Extract the builder methods first to report errors before parsing. */
3276     ASTSerializer serialize(cx, loc, filename, lineno);
3277     if (!serialize.init(builder))
3278         return JS_FALSE;
3279
3280     size_t length = src->length();
3281     const jschar *chars = src->getChars(cx);
3282     if (!chars)
3283         return JS_FALSE;
3284
3285     Parser parser(cx);
3286
3287     if (!parser.init(chars, length, filename, lineno, cx->findVersion()))
3288         return JS_FALSE;
3289
3290     JSParseNode *pn = parser.parse(NULL);
3291     if (!pn)
3292         return JS_FALSE;
3293
3294     Value val;
3295     if (!serialize.program(pn, &val)) {
3296         JS_SET_RVAL(cx, vp, JSVAL_NULL);
3297         return JS_FALSE;
3298     }
3299
3300     JS_SET_RVAL(cx, vp, Jsvalify(val));
3301     return JS_TRUE;
3302 }
3303
3304 static JSFunctionSpec static_methods[] = {
3305     JS_FN("parse", reflect_parse, 1, 0),
3306     JS_FS_END
3307 };
3308
3309
3310 JSObject *
3311 js_InitReflectClass(JSContext *cx, JSObject *obj)
3312 {
3313     JSObject *Reflect = NewNonFunction<WithProto::Class>(cx, &js_ReflectClass, NULL, obj);
3314     if (!Reflect)
3315         return NULL;
3316
3317     if (!JS_DefineProperty(cx, obj, js_Reflect_str, OBJECT_TO_JSVAL(Reflect),
3318                            JS_PropertyStub, JS_StrictPropertyStub, 0)) {
3319         return NULL;
3320     }
3321
3322     if (!JS_DefineFunctions(cx, Reflect, static_methods))
3323         return NULL;
3324
3325     return Reflect;
3326 }