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