js/src/jsreflect.cpp

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

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

mercurial