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