Bug 670049 - JSParseNode accessors. (r=dherman)
authorChris Leary <cdleary@mozilla.com>
Tue, 13 Sep 2011 22:32:14 -0700
changeset 76983 4b5ceed325396fd03f3cd31a44fee0c7551e6050
parent 76982 ff19f221eecaa8b8f8017fa025e67e00cfbeeb36
child 76984 b2c01d6dbd4afadc9a23df5abad2465c01c5025d
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersdherman
bugs670049
milestone9.0a1
Bug 670049 - JSParseNode accessors. (r=dherman)
js/src/jsemit.cpp
js/src/jsparse.cpp
js/src/jsparse.h
js/src/jsreflect.cpp
js/src/jsxml.cpp
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -1440,17 +1440,17 @@ static ptrdiff_t
 EmitTraceOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *nextpn)
 {
     if (nextpn) {
         /*
          * Try to give the JSOP_TRACE the same line number as the next
          * instruction. nextpn is often a block, in which case the next
          * instruction typically comes from the first statement inside.
          */
-        if (nextpn->pn_type == TOK_LC && nextpn->pn_arity == PN_LIST && nextpn->pn_head)
+        if (nextpn->isKind(TOK_LC) && nextpn->isArity(PN_LIST) && nextpn->pn_head)
             nextpn = nextpn->pn_head;
         if (!UpdateLineNumberNotes(cx, cg, nextpn->pn_pos.begin.lineno))
             return -1;
     }
 
     uint32 index = cg->traceIndex;
     if (index < UINT16_MAX)
         cg->traceIndex++;
@@ -1690,17 +1690,17 @@ js_PopStatementCG(JSContext *cx, JSCodeG
     return JS_TRUE;
 }
 
 JSBool
 js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
                              JSParseNode *pn)
 {
     /* XXX just do numbers for now */
-    if (pn->pn_type == TOK_NUMBER) {
+    if (pn->isKind(TOK_NUMBER)) {
         if (!cg->constMap.put(atom, NumberValue(pn->pn_dval)))
             return JS_FALSE;
     }
     return JS_TRUE;
 }
 
 JSStmtInfo *
 js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, JSStmtInfo *stmt)
@@ -1950,17 +1950,17 @@ EmitSlotIndexOp(JSContext *cx, JSOp op, 
     pc += 2;
     SET_INDEX(pc, index);
     return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, bigSuffix) >= 0;
 }
 
 bool
 JSCodeGenerator::shouldNoteClosedName(JSParseNode *pn)
 {
-    return !callsEval() && pn->pn_defn && pn->isClosed();
+    return !callsEval() && pn->isDefn() && pn->isClosed();
 }
 
 /*
  * Adjust the slot for a block local to account for the number of variables
  * that share the same index space with locals. Due to the incremental code
  * generation for top-level script, we do the adjustment via code patching in
  * Compiler::compileScript; see comments there.
  *
@@ -1978,17 +1978,17 @@ AdjustBlockSlot(JSContext *cx, JSCodeGen
         }
     }
     return slot;
 }
 
 static bool
 EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg)
 {
-    JS_ASSERT(PN_TYPE(pn) == TOK_LEXICALSCOPE);
+    JS_ASSERT(pn->isKind(TOK_LEXICALSCOPE));
     if (!EmitObjectOp(cx, pn->pn_objbox, JSOP_ENTERBLOCK, cg))
         return false;
 
     JSObject *blockObj = pn->pn_objbox->object;
     jsint depth = AdjustBlockSlot(cx, cg, OBJ_BLOCK_DEPTH(cx, blockObj));
     if (depth < 0)
         return false;
 
@@ -1998,17 +1998,17 @@ EmitEnterBlock(JSContext *cx, JSParseNod
 
         /* Beware the empty destructuring dummy. */
         if (v.isUndefined()) {
             JS_ASSERT(slot + 1 <= limit);
             continue;
         }
 
         JSDefinition *dn = (JSDefinition *) v.toPrivate();
-        JS_ASSERT(dn->pn_defn);
+        JS_ASSERT(dn->isDefn());
         JS_ASSERT(uintN(dn->frameSlot() + depth) < JS_BIT(16));
         dn->pn_cookie.set(dn->pn_cookie.level(), uint16(dn->frameSlot() + depth));
 #ifdef DEBUG
         for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
             JS_ASSERT(pnu->pn_lexdef == dn);
             JS_ASSERT(!(pnu->pn_dflags & PND_BOUND));
             JS_ASSERT(pnu->pn_cookie.isFree());
         }
@@ -2145,20 +2145,20 @@ BindKnownGlobal(JSContext *cx, JSCodeGen
 
 // See BindKnownGlobal()'s comment.
 static bool
 BindGlobal(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, JSAtom *atom)
 {
     pn->pn_cookie.makeFree();
 
     JSDefinition *dn;
-    if (pn->pn_used) {
+    if (pn->isUsed()) {
         dn = pn->pn_lexdef;
     } else {
-        if (!pn->pn_defn)
+        if (!pn->isDefn())
             return true;
         dn = (JSDefinition *)pn;
     }
 
     // Only optimize for defined globals.
     if (!dn->isGlobal())
         return true;
 
@@ -2185,43 +2185,43 @@ BindGlobal(JSContext *cx, JSCodeGenerato
 static JSBool
 BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
 {
     JSDefinition *dn;
     JSOp op;
     JSAtom *atom;
     JSDefinition::Kind dn_kind;
 
-    JS_ASSERT(pn->pn_type == TOK_NAME);
+    JS_ASSERT(pn->isKind(TOK_NAME));
 
     /* Idempotency tests come first, since we may be called more than once. */
     if (pn->pn_dflags & PND_BOUND)
         return JS_TRUE;
 
     /* No cookie initialized for these two, they're pre-bound by definition. */
-    JS_ASSERT(pn->pn_op != JSOP_ARGUMENTS && pn->pn_op != JSOP_CALLEE);
+    JS_ASSERT(!pn->isOp(JSOP_ARGUMENTS) && !pn->isOp(JSOP_CALLEE));
 
     /*
      * The parser linked all uses (including forward references) to their
      * definitions, unless a with statement or direct eval intervened.
      */
-    if (pn->pn_used) {
+    if (pn->isUsed()) {
         JS_ASSERT(pn->pn_cookie.isFree());
         dn = pn->pn_lexdef;
-        JS_ASSERT(dn->pn_defn);
+        JS_ASSERT(dn->isDefn());
         if (pn->isDeoptimized())
             return JS_TRUE;
         pn->pn_dflags |= (dn->pn_dflags & PND_CONST);
     } else {
-        if (!pn->pn_defn)
+        if (!pn->isDefn())
             return JS_TRUE;
         dn = (JSDefinition *) pn;
     }
 
-    op = PN_OP(pn);
+    op = pn->getOp();
     if (op == JSOP_NOP)
         return JS_TRUE;
 
     JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
     atom = pn->pn_atom;
     UpvarCookie cookie = dn->pn_cookie;
     dn_kind = dn->kind();
 
@@ -2238,45 +2238,45 @@ BindNameToSlot(JSContext *cx, JSCodeGene
       case JSOP_NAME:
       case JSOP_SETCONST:
         break;
       case JSOP_DELNAME:
         if (dn_kind != JSDefinition::UNKNOWN) {
             if (cg->parser->callerFrame && dn->isTopLevel())
                 JS_ASSERT(cg->compileAndGo());
             else
-                pn->pn_op = JSOP_FALSE;
+                pn->setOp(JSOP_FALSE);
             pn->pn_dflags |= PND_BOUND;
             return JS_TRUE;
         }
         break;
       default:
         if (pn->isConst()) {
             if (cg->needStrictChecks()) {
                 JSAutoByteString name;
                 if (!js_AtomToPrintableString(cx, atom, &name) ||
                     !ReportStrictModeError(cx, CG_TS(cg), cg, pn, JSMSG_READ_ONLY, name.ptr())) {
                     return JS_FALSE;
                 }
             }
-            pn->pn_op = op = JSOP_NAME;
+            pn->setOp(op = JSOP_NAME);
         }
     }
 
     if (dn->isGlobal()) {
         if (op == JSOP_NAME) {
             /*
              * If the definition is a defined global, not potentially aliased
              * by a local variable, and not mutating the variable, try and
              * optimize to a fast, unguarded global access.
              */
             if (!BindKnownGlobal(cx, cg, dn, pn, atom))
                 return JS_FALSE;
             if (!pn->pn_cookie.isFree()) {
-                pn->pn_op = JSOP_GETGLOBAL;
+                pn->setOp(JSOP_GETGLOBAL);
                 return JS_TRUE;
             }
         }
 
         /*
          * The locally stored cookie here should really come from |pn|, not
          * |dn|. For example, we could have a SETGNAME op's lexdef be a
          * GETGLOBAL op, and their cookies have very different meanings. As
@@ -2303,17 +2303,17 @@ BindNameToSlot(JSContext *cx, JSCodeGene
              * If this is an eval in the global scope, then unbound variables
              * must be globals, so try to use GNAME ops.
              */
             if (caller->isGlobalFrame() && TryConvertToGname(cg, pn, &op)) {
                 jsatomid _;
                 if (!cg->makeAtomIndex(atom, &_))
                     return JS_FALSE;
 
-                pn->pn_op = op;
+                pn->setOp(op);
                 pn->pn_dflags |= PND_BOUND;
                 return JS_TRUE;
             }
 
             /*
              * Out of tricks, so we must rely on PICs to optimize named
              * accesses from direct eval called from function code.
              */
@@ -2323,17 +2323,17 @@ BindNameToSlot(JSContext *cx, JSCodeGene
         /* Optimize accesses to undeclared globals. */
         if (!cg->mightAliasLocals() && !TryConvertToGname(cg, pn, &op))
             return JS_TRUE;
 
         jsatomid _;
         if (!cg->makeAtomIndex(atom, &_))
             return JS_FALSE;
 
-        pn->pn_op = op;
+        pn->setOp(op);
         pn->pn_dflags |= PND_BOUND;
 
         return JS_TRUE;
     }
 
     uint16 level = cookie.level();
     JS_ASSERT(cg->staticLevel >= level);
 
@@ -2401,17 +2401,17 @@ BindNameToSlot(JSContext *cx, JSCodeGene
                 if (tc->inFunction())
                     slot += tc->fun()->nargs;
             }
 
             JS_ASSERT(index < upvarMap.length());
             upvarMap[index].set(skip, slot);
         }
 
-        pn->pn_op = JSOP_GETFCSLOT;
+        pn->setOp(JSOP_GETFCSLOT);
         JS_ASSERT((index & JS_BITMASK(16)) == index);
         pn->pn_cookie.set(0, index);
         pn->pn_dflags |= PND_BOUND;
         return JS_TRUE;
     }
 
     /*
      * We are compiling a function body and may be able to optimize name
@@ -2443,22 +2443,22 @@ BindNameToSlot(JSContext *cx, JSCodeGene
           case JSOP_DECNAME:  op = JSOP_DECARG; break;
           case JSOP_NAMEDEC:  op = JSOP_ARGDEC; break;
           default: JS_NOT_REACHED("arg");
         }
         JS_ASSERT(!pn->isConst());
         break;
 
       case JSDefinition::VAR:
-        if (PN_OP(dn) == JSOP_CALLEE) {
+        if (dn->isOp(JSOP_CALLEE)) {
             JS_ASSERT(op != JSOP_CALLEE);
             JS_ASSERT((cg->fun()->flags & JSFUN_LAMBDA) && atom == cg->fun()->atom);
 
             /*
-             * Leave pn->pn_op == JSOP_NAME if cg->fun is heavyweight to
+             * Leave pn->isOp(JSOP_NAME) if cg->fun is heavyweight to
              * address two cases: a new binding introduced by eval, and
              * assignment to the name in strict mode.
              *
              *   var fun = (function f(s) { eval(s); return f; });
              *   assertEq(fun("var f = 42"), 42);
              *
              * ECMAScript specifies that a function expression's name is bound
              * in a lexical environment distinct from that used to bind its
@@ -2477,17 +2477,17 @@ BindNameToSlot(JSContext *cx, JSCodeGene
              * the scope chain so that assignment will throw a TypeError.
              */
             JS_ASSERT(op != JSOP_DELNAME);
             if (!(cg->flags & TCF_FUN_HEAVYWEIGHT)) {
                 op = JSOP_CALLEE;
                 pn->pn_dflags |= PND_CONST;
             }
 
-            pn->pn_op = op;
+            pn->setOp(op);
             pn->pn_dflags |= PND_BOUND;
             return JS_TRUE;
         }
         /* FALL THROUGH */
 
       default:
         JS_ASSERT_IF(dn_kind != JSDefinition::FUNCTION,
                      dn_kind == JSDefinition::VAR ||
@@ -2501,18 +2501,18 @@ BindNameToSlot(JSContext *cx, JSCodeGene
           case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;
           case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;
           default: JS_NOT_REACHED("local");
         }
         JS_ASSERT_IF(dn_kind == JSDefinition::CONST, pn->pn_dflags & PND_CONST);
         break;
     }
 
-    JS_ASSERT(op != PN_OP(pn));
-    pn->pn_op = op;
+    JS_ASSERT(!pn->isOp(op));
+    pn->setOp(op);
     pn->pn_cookie.set(0, cookie.slot());
     pn->pn_dflags |= PND_BOUND;
     return JS_TRUE;
 }
 
 bool
 JSCodeGenerator::addGlobalUse(JSAtom *atom, uint32 slot, UpvarCookie *cookie)
 {
@@ -2565,32 +2565,31 @@ CheckSideEffects(JSContext *cx, JSCodeGe
 {
     JSBool ok;
     JSParseNode *pn2;
 
     ok = JS_TRUE;
     if (!pn || *answer)
         return ok;
 
-    switch (pn->pn_arity) {
+    switch (pn->getArity()) {
       case PN_FUNC:
         /*
          * A named function, contrary to ES3, is no longer useful, because we
          * bind its name lexically (using JSOP_CALLEE) instead of creating an
          * Object instance and binding a readonly, permanent property in it
          * (the object and binding can be detected and hijacked or captured).
          * This is a bug fix to ES3; it is fixed in ES3.1 drafts.
          */
         *answer = JS_FALSE;
         break;
 
       case PN_LIST:
-        if (pn->pn_op == JSOP_NOP ||
-            pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND ||
-            pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) {
+        if (pn->isOp(JSOP_NOP) || pn->isOp(JSOP_OR) || pn->isOp(JSOP_AND) ||
+            pn->isOp(JSOP_STRICTEQ) || pn->isOp(JSOP_STRICTNE)) {
             /*
              * Non-operators along with ||, &&, ===, and !== never invoke
              * toString or valueOf.
              */
             for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)
                 ok &= CheckSideEffects(cx, cg, pn2, answer);
         } else {
             /*
@@ -2615,40 +2614,40 @@ CheckSideEffects(JSContext *cx, JSCodeGe
 
       case PN_TERNARY:
         ok = CheckSideEffects(cx, cg, pn->pn_kid1, answer) &&
              CheckSideEffects(cx, cg, pn->pn_kid2, answer) &&
              CheckSideEffects(cx, cg, pn->pn_kid3, answer);
         break;
 
       case PN_BINARY:
-        if (pn->pn_type == TOK_ASSIGN) {
+        if (pn->isKind(TOK_ASSIGN)) {
             /*
              * Assignment is presumed to be useful, even if the next operation
              * is another assignment overwriting this one's ostensible effect,
              * because the left operand may be a property with a setter that
              * has side effects.
              *
              * The only exception is assignment of a useless value to a const
              * declared in the function currently being compiled.
              */
             pn2 = pn->pn_left;
-            if (pn2->pn_type != TOK_NAME) {
+            if (!pn2->isKind(TOK_NAME)) {
                 *answer = JS_TRUE;
             } else {
                 if (!BindNameToSlot(cx, cg, pn2))
                     return JS_FALSE;
                 if (!CheckSideEffects(cx, cg, pn->pn_right, answer))
                     return JS_FALSE;
-                if (!*answer && (pn->pn_op != JSOP_NOP || !pn2->isConst()))
+                if (!*answer && (!pn->isOp(JSOP_NOP) || !pn2->isConst()))
                     *answer = JS_TRUE;
             }
         } else {
-            if (pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND ||
-                pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) {
+            if (pn->isOp(JSOP_OR) || pn->isOp(JSOP_AND) || pn->isOp(JSOP_STRICTEQ) ||
+                pn->isOp(JSOP_STRICTNE)) {
                 /*
                  * ||, &&, ===, and !== do not convert their operands via
                  * toString or valueOf method calls.
                  */
                 ok = CheckSideEffects(cx, cg, pn->pn_left, answer) &&
                      CheckSideEffects(cx, cg, pn->pn_right, answer);
             } else {
                 /*
@@ -2656,20 +2655,20 @@ CheckSideEffects(JSContext *cx, JSCodeGe
                  * object with a toString or valueOf method.
                  */
                 *answer = JS_TRUE;
             }
         }
         break;
 
       case PN_UNARY:
-        switch (pn->pn_type) {
+        switch (pn->getKind()) {
           case TOK_DELETE:
             pn2 = pn->pn_kid;
-            switch (pn2->pn_type) {
+            switch (pn2->getKind()) {
               case TOK_NAME:
                 if (!BindNameToSlot(cx, cg, pn2))
                     return JS_FALSE;
                 if (pn2->isConst()) {
                     *answer = JS_FALSE;
                     break;
                 }
                 /* FALL THROUGH */
@@ -2684,17 +2683,17 @@ CheckSideEffects(JSContext *cx, JSCodeGe
                 break;
               default:
                 ok = CheckSideEffects(cx, cg, pn2, answer);
                 break;
             }
             break;
 
           case TOK_UNARYOP:
-            if (pn->pn_op == JSOP_NOT) {
+            if (pn->isOp(JSOP_NOT)) {
                 /* ! does not convert its operand via toString or valueOf. */
                 ok = CheckSideEffects(cx, cg, pn->pn_kid, answer);
                 break;
             }
             /* FALL THROUGH */
 
           default:
             /*
@@ -2709,66 +2708,66 @@ CheckSideEffects(JSContext *cx, JSCodeGe
         break;
 
       case PN_NAME:
         /*
          * Take care to avoid trying to bind a label name (labels, both for
          * statements and property values in object initialisers, have pn_op
          * defaulted to JSOP_NOP).
          */
-        if (pn->pn_type == TOK_NAME && pn->pn_op != JSOP_NOP) {
+        if (pn->isKind(TOK_NAME) && !pn->isOp(JSOP_NOP)) {
             if (!BindNameToSlot(cx, cg, pn))
                 return JS_FALSE;
-            if (pn->pn_op != JSOP_ARGUMENTS && pn->pn_op != JSOP_CALLEE &&
+            if (!pn->isOp(JSOP_ARGUMENTS) && !pn->isOp(JSOP_CALLEE) &&
                 pn->pn_cookie.isFree()) {
                 /*
                  * Not an argument or local variable use, and not a use of a
                  * unshadowed named function expression's given name, so this
                  * expression could invoke a getter that has side effects.
                  */
                 *answer = JS_TRUE;
             }
         }
         pn2 = pn->maybeExpr();
-        if (pn->pn_type == TOK_DOT) {
-            if (pn2->pn_type == TOK_NAME && !BindNameToSlot(cx, cg, pn2))
-                return JS_FALSE;
-            if (!(pn2->pn_op == JSOP_ARGUMENTS &&
+        if (pn->isKind(TOK_DOT)) {
+            if (pn2->isKind(TOK_NAME) && !BindNameToSlot(cx, cg, pn2))
+                return JS_FALSE;
+            if (!(pn2->isOp(JSOP_ARGUMENTS) &&
                   pn->pn_atom == cx->runtime->atomState.lengthAtom)) {
                 /*
                  * Any dotted property reference could call a getter, except
                  * for arguments.length where arguments is unambiguous.
                  */
                 *answer = JS_TRUE;
             }
         }
         ok = CheckSideEffects(cx, cg, pn2, answer);
         break;
 
       case PN_NAMESET:
         ok = CheckSideEffects(cx, cg, pn->pn_tree, answer);
         break;
 
       case PN_NULLARY:
-        if (pn->pn_type == TOK_DEBUGGER)
+        if (pn->isKind(TOK_DEBUGGER))
             *answer = JS_TRUE;
         break;
     }
     return ok;
 }
 
 static JSBool
 EmitNameOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
            JSBool callContext)
 {
     JSOp op;
 
     if (!BindNameToSlot(cx, cg, pn))
         return JS_FALSE;
-    op = PN_OP(pn);
+    op = pn->getOp();
 
     if (callContext) {
         switch (op) {
           case JSOP_NAME:
             op = JSOP_CALLNAME;
             break;
           case JSOP_GETGNAME:
             op = JSOP_CALLGNAME;
@@ -2810,18 +2809,18 @@ EmitNameOp(JSContext *cx, JSCodeGenerato
 
 #if JS_HAS_XML_SUPPORT
 static JSBool
 EmitXMLName(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
 {
     JSParseNode *pn2;
     uintN oldflags;
 
-    JS_ASSERT(pn->pn_type == TOK_UNARYOP);
-    JS_ASSERT(pn->pn_op == JSOP_XMLNAME);
+    JS_ASSERT(pn->isKind(TOK_UNARYOP));
+    JS_ASSERT(pn->isOp(JSOP_XMLNAME));
     JS_ASSERT(op == JSOP_XMLNAME || op == JSOP_CALLXMLNAME);
 
     pn2 = pn->pn_kid;
     oldflags = cg->flags;
     cg->flags &= ~TCF_IN_FOR_INIT;
     if (!js_EmitTree(cx, cg, pn2))
         return JS_FALSE;
     cg->flags |= oldflags & TCF_IN_FOR_INIT;
@@ -2861,63 +2860,63 @@ EmitSpecialPropOp(JSContext *cx, JSParse
 
 static JSBool
 EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,
            JSBool callContext, JSOp *psuffix = NULL)
 {
     JSParseNode *pn2, *pndot, *pnup, *pndown;
     ptrdiff_t top;
 
-    JS_ASSERT(pn->pn_arity == PN_NAME);
+    JS_ASSERT(pn->isArity(PN_NAME));
     pn2 = pn->maybeExpr();
 
     /* Special case deoptimization for __proto__. */
     if ((op == JSOP_GETPROP || op == JSOP_CALLPROP) &&
         pn->pn_atom == cx->runtime->atomState.protoAtom) {
         if (pn2 && !js_EmitTree(cx, cg, pn2))
             return JS_FALSE;
         return EmitSpecialPropOp(cx, pn, callContext ? JSOP_CALLELEM : JSOP_GETELEM, cg);
     }
 
     if (callContext) {
-        JS_ASSERT(pn->pn_type == TOK_DOT);
+        JS_ASSERT(pn->isKind(TOK_DOT));
         JS_ASSERT(op == JSOP_GETPROP);
         op = JSOP_CALLPROP;
-    } else if (op == JSOP_GETPROP && pn->pn_type == TOK_DOT) {
-        if (pn2->pn_type == TOK_NAME) {
+    } else if (op == JSOP_GETPROP && pn->isKind(TOK_DOT)) {
+        if (pn2->isKind(TOK_NAME)) {
             /*
              * Try to optimize arguments.length into JSOP_ARGCNT. If type
              * inference is enabled this is optimized separately.
              */
             if (!BindNameToSlot(cx, cg, pn2))
                 return JS_FALSE;
             if (!cx->typeInferenceEnabled() &&
                 pn->pn_atom == cx->runtime->atomState.lengthAtom) {
-                if (pn2->pn_op == JSOP_ARGUMENTS)
+                if (pn2->isOp(JSOP_ARGUMENTS))
                     return js_Emit1(cx, cg, JSOP_ARGCNT) >= 0;
             }
         }
     }
 
     /*
      * If the object operand is also a dotted property reference, reverse the
      * list linked via pn_expr temporarily so we can iterate over it from the
      * bottom up (reversing again as we go), to avoid excessive recursion.
      */
-    if (pn2->pn_type == TOK_DOT) {
+    if (pn2->isKind(TOK_DOT)) {
         pndot = pn2;
         pnup = NULL;
         top = CG_OFFSET(cg);
         for (;;) {
             /* Reverse pndot->pn_expr to point up, not down. */
             pndot->pn_offset = top;
-            JS_ASSERT(!pndot->pn_used);
+            JS_ASSERT(!pndot->isUsed());
             pndown = pndot->pn_expr;
             pndot->pn_expr = pnup;
-            if (pndown->pn_type != TOK_DOT)
+            if (!pndown->isKind(TOK_DOT))
                 break;
             pnup = pndot;
             pndot = pndown;
         }
 
         /* pndown is a primary expression, not a dotted property reference. */
         if (!js_EmitTree(cx, cg, pndown))
             return JS_FALSE;
@@ -2925,20 +2924,20 @@ EmitPropOp(JSContext *cx, JSParseNode *p
         do {
             /* Walk back up the list, emitting annotated name ops. */
             if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
                                CG_OFFSET(cg) - pndown->pn_offset) < 0) {
                 return JS_FALSE;
             }
 
             /* Special case deoptimization on __proto__, as above. */
-            if (pndot->pn_arity == PN_NAME && pndot->pn_atom == cx->runtime->atomState.protoAtom) {
+            if (pndot->isArity(PN_NAME) && pndot->pn_atom == cx->runtime->atomState.protoAtom) {
                 if (!EmitSpecialPropOp(cx, pndot, JSOP_GETELEM, cg))
                     return JS_FALSE;
-            } else if (!EmitAtomOp(cx, pndot, PN_OP(pndot), cg)) {
+            } else if (!EmitAtomOp(cx, pndot, pndot->getOp(), cg)) {
                 return JS_FALSE;
             }
 
             /* Reverse the pn_expr link again. */
             pnup = pndot->pn_expr;
             pndot->pn_expr = pndown;
             pndown = pndot;
         } while ((pndot = pnup) != NULL);
@@ -3075,34 +3074,34 @@ EmitNameIncDec(JSContext *cx, JSParseNod
 static JSBool
 EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
 {
     ptrdiff_t top;
     JSParseNode *left, *right, *next, ltmp, rtmp;
     int32_t slot;
 
     top = CG_OFFSET(cg);
-    if (pn->pn_arity == PN_LIST) {
+    if (pn->isArity(PN_LIST)) {
         /* Left-associative operator chain to avoid too much recursion. */
-        JS_ASSERT(pn->pn_op == JSOP_GETELEM);
+        JS_ASSERT(pn->isOp(JSOP_GETELEM));
         JS_ASSERT(pn->pn_count >= 3);
         left = pn->pn_head;
         right = pn->last();
         next = left->pn_next;
         JS_ASSERT(next != right);
 
         /*
          * Try to optimize arguments[0][j]... into JSOP_ARGSUB<0> followed by
          * one or more index expression and JSOP_GETELEM op pairs. If type
          * inference is enabled this is optimized separately.
          */
-        if (left->pn_type == TOK_NAME && next->pn_type == TOK_NUMBER) {
+        if (left->isKind(TOK_NAME) && next->isKind(TOK_NUMBER)) {
             if (!BindNameToSlot(cx, cg, left))
                 return JS_FALSE;
-            if (left->pn_op == JSOP_ARGUMENTS &&
+            if (left->isOp(JSOP_ARGUMENTS) &&
                 JSDOUBLE_IS_INT32(next->pn_dval, &slot) &&
                 jsuint(slot) < JS_BIT(16) &&
                 !cx->typeInferenceEnabled() &&
                 (!cg->inStrictMode() ||
                  (!cg->mutatesParameter() && !cg->callsEval()))) {
                 /*
                  * arguments[i]() requires arguments object as "this".
                  * Check that we never generates list for that usage.
@@ -3132,75 +3131,73 @@ EmitElemOp(JSContext *cx, JSParseNode *p
                 return JS_FALSE;
             if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
                 return JS_FALSE;
             if (!EmitElemOpBase(cx, cg, JSOP_GETELEM))
                 return JS_FALSE;
             next = next->pn_next;
         }
     } else {
-        if (pn->pn_arity == PN_NAME) {
+        if (pn->isArity(PN_NAME)) {
             /*
              * Set left and right so pn appears to be a TOK_LB node, instead
              * of a TOK_DOT node.  See the TOK_FOR/IN case in js_EmitTree, and
              * EmitDestructuringOps nearer below.  In the destructuring case,
              * the base expression (pn_expr) of the name may be null, which
              * means we have to emit a JSOP_BINDNAME.
              */
             left = pn->maybeExpr();
             if (!left) {
                 left = &ltmp;
-                left->pn_type = TOK_STRING;
-                left->pn_op = JSOP_BINDNAME;
-                left->pn_arity = PN_NULLARY;
+                left->setKind(TOK_STRING);
+                left->setOp(JSOP_BINDNAME);
+                left->setArity(PN_NULLARY);
                 left->pn_pos = pn->pn_pos;
                 left->pn_atom = pn->pn_atom;
             }
             right = &rtmp;
-            right->pn_type = TOK_STRING;
-            right->pn_op = js_IsIdentifier(pn->pn_atom)
-                           ? JSOP_QNAMEPART
-                           : JSOP_STRING;
-            right->pn_arity = PN_NULLARY;
+            right->setKind(TOK_STRING);
+            right->setOp(js_IsIdentifier(pn->pn_atom) ? JSOP_QNAMEPART : JSOP_STRING);
+            right->setArity(PN_NULLARY);
             right->pn_pos = pn->pn_pos;
             right->pn_atom = pn->pn_atom;
         } else {
-            JS_ASSERT(pn->pn_arity == PN_BINARY);
+            JS_ASSERT(pn->isArity(PN_BINARY));
             left = pn->pn_left;
             right = pn->pn_right;
         }
 
         /*
          * Try to optimize arguments[0] (e.g.) into JSOP_ARGSUB<0>. If type
          * inference is enabled this is optimized separately.
          */
         if (op == JSOP_GETELEM &&
-            left->pn_type == TOK_NAME &&
-            right->pn_type == TOK_NUMBER) {
+            left->isKind(TOK_NAME) &&
+            right->isKind(TOK_NUMBER)) {
             if (!BindNameToSlot(cx, cg, left))
                 return JS_FALSE;
-            if (left->pn_op == JSOP_ARGUMENTS &&
+            if (left->isOp(JSOP_ARGUMENTS) &&
                 JSDOUBLE_IS_INT32(right->pn_dval, &slot) &&
                 jsuint(slot) < JS_BIT(16) &&
                 !cx->typeInferenceEnabled() &&
                 (!cg->inStrictMode() ||
                  (!cg->mutatesParameter() && !cg->callsEval()))) {
                 left->pn_offset = right->pn_offset = top;
                 EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot);
                 return JS_TRUE;
             }
         }
 
         if (!js_EmitTree(cx, cg, left))
             return JS_FALSE;
     }
 
     /* The right side of the descendant operator is implicitly quoted. */
-    JS_ASSERT(op != JSOP_DESCENDANTS || right->pn_type != TOK_STRING ||
-              right->pn_op == JSOP_QNAMEPART);
+    JS_ASSERT(op != JSOP_DESCENDANTS || !right->isKind(TOK_STRING) ||
+              right->isOp(JSOP_QNAMEPART));
     if (!js_EmitTree(cx, cg, right))
         return JS_FALSE;
     if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
         return JS_FALSE;
     return EmitElemOpBase(cx, cg, op);
 }
 
 static bool
@@ -3402,17 +3399,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
      * If the switch contains let variables scoped by its body, model the
      * resulting block on the stack first, before emitting the discriminant's
      * bytecode (in case the discriminant contains a stack-model dependency
      * such as a let expression).
      */
     pn2 = pn->pn_right;
 #if JS_HAS_BLOCK_SCOPE
     TempPopScope tps;
-    if (pn2->pn_type == TOK_LEXICALSCOPE) {
+    if (pn2->isKind(TOK_LEXICALSCOPE)) {
         /*
          * Push the body's block scope before discriminant code-gen to reflect
          * the order of slots on the stack. The block's locals must lie under
          * the discriminant on the stack so that case-dispatch bytecodes can
          * find the discriminant on top of stack.
          */
         box = pn2->pn_objbox;
         js_PushBlockScope(cg, stmtInfo, box, -1);
@@ -3443,17 +3440,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
     if (!js_EmitTree(cx, cg, pn->pn_left))
         return JS_FALSE;
 
     /* Switch bytecodes run from here till end of final case. */
     top = CG_OFFSET(cg);
 #if !JS_HAS_BLOCK_SCOPE
     js_PushStatement(cg, stmtInfo, STMT_SWITCH, top);
 #else
-    if (pn2->pn_type == TOK_LC) {
+    if (pn2->isKind(TOK_LC)) {
         js_PushStatement(cg, stmtInfo, STMT_SWITCH, top);
     } else {
         /* Re-push the switch's statement info record. */
         if (!tps.repushBlock(cx, cg))
             return JS_FALSE;
 
         /*
          * Set the statement info record's idea of top. Reset top too, since
@@ -3467,46 +3464,46 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
 #endif
 
     caseCount = pn2->pn_count;
     tableLength = 0;
     table = NULL;
 
     if (caseCount == 0 ||
         (caseCount == 1 &&
-         (hasDefault = (pn2->pn_head->pn_type == TOK_DEFAULT)))) {
+         (hasDefault = (pn2->pn_head->isKind(TOK_DEFAULT))))) {
         caseCount = 0;
         low = 0;
         high = -1;
     } else {
 #define INTMAP_LENGTH   256
         jsbitmap intmap_space[INTMAP_LENGTH];
         jsbitmap *intmap = NULL;
         int32 intmap_bitlen = 0;
 
         low  = JSVAL_INT_MAX;
         high = JSVAL_INT_MIN;
 
         for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
-            if (pn3->pn_type == TOK_DEFAULT) {
+            if (pn3->isKind(TOK_DEFAULT)) {
                 hasDefault = JS_TRUE;
                 caseCount--;    /* one of the "cases" was the default */
                 continue;
             }
 
-            JS_ASSERT(pn3->pn_type == TOK_CASE);
+            JS_ASSERT(pn3->isKind(TOK_CASE));
             if (switchOp == JSOP_CONDSWITCH)
                 continue;
 
             pn4 = pn3->pn_left;
-            while (pn4->pn_type == TOK_RP)
+            while (pn4->isKind(TOK_RP))
                 pn4 = pn4->pn_kid;
 
             Value constVal;
-            switch (pn4->pn_type) {
+            switch (pn4->getKind()) {
               case TOK_NUMBER:
                 constVal.setNumber(pn4->pn_dval);
                 break;
               case TOK_STRING:
                 constVal.setString(pn4->pn_atom);
                 break;
               case TOK_NAME:
                 if (!pn4->maybeExpr()) {
@@ -3523,25 +3520,25 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
                             continue;
                         }
                         constPropagated = JS_TRUE;
                         break;
                     }
                 }
                 /* FALL THROUGH */
               case TOK_PRIMARY:
-                if (pn4->pn_op == JSOP_TRUE) {
+                if (pn4->isOp(JSOP_TRUE)) {
                     constVal.setBoolean(true);
                     break;
                 }
-                if (pn4->pn_op == JSOP_FALSE) {
+                if (pn4->isOp(JSOP_FALSE)) {
                     constVal.setBoolean(false);
                     break;
                 }
-                if (pn4->pn_op == JSOP_NULL) {
+                if (pn4->isOp(JSOP_NULL)) {
                     constVal.setNull();
                     break;
                 }
                 /* FALL THROUGH */
               default:
                 switchOp = JSOP_CONDSWITCH;
                 continue;
             }
@@ -3684,17 +3681,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
             if (caseNoteIndex >= 0) {
                 /* off is the previous JSOP_CASE's bytecode offset. */
                 if (!js_SetSrcNoteOffset(cx, cg, (uintN)caseNoteIndex, 0,
                                          CG_OFFSET(cg) - off)) {
                     return JS_FALSE;
                 }
             }
             if (!pn4) {
-                JS_ASSERT(pn3->pn_type == TOK_DEFAULT);
+                JS_ASSERT(pn3->isKind(TOK_DEFAULT));
                 continue;
             }
             caseNoteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);
             if (caseNoteIndex < 0)
                 return JS_FALSE;
             off = EmitJump(cx, cg, JSOP_CASE, 0);
             if (off < 0)
                 return JS_FALSE;
@@ -3748,17 +3745,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
              */
             if (tableLength != 0) {
                 tableSize = (size_t)tableLength * sizeof *table;
                 table = (JSParseNode **) cx->malloc_(tableSize);
                 if (!table)
                     return JS_FALSE;
                 memset(table, 0, tableSize);
                 for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
-                    if (pn3->pn_type == TOK_DEFAULT)
+                    if (pn3->isKind(TOK_DEFAULT))
                         continue;
                     i = pn3->pn_pval->toInt32();
                     i -= low;
                     JS_ASSERT((uint32)i < tableLength);
                     table[i] = pn3;
                 }
             }
         } else {
@@ -3794,32 +3791,32 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
              */
             savepc = CG_NEXT(cg);
             CG_NEXT(cg) = pc + 1;
             if (switchOp == JSOP_TABLESWITCH) {
                 for (i = 0; i < (jsint)tableLength; i++) {
                     pn3 = table[i];
                     if (pn3 &&
                         (pn4 = pn3->pn_left) != NULL &&
-                        pn4->pn_type == TOK_NAME) {
+                        pn4->isKind(TOK_NAME)) {
                         /* Note a propagated constant with the const's name. */
                         JS_ASSERT(!pn4->maybeExpr());
                         jsatomid index;
                         if (!cg->makeAtomIndex(pn4->pn_atom, &index))
                             goto bad;
                         CG_NEXT(cg) = pc;
                         if (js_NewSrcNote2(cx, cg, SRC_LABEL, ptrdiff_t(index)) < 0)
                             goto bad;
                     }
                     pc += JUMP_OFFSET_LEN;
                 }
             } else {
                 for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
                     pn4 = pn3->pn_left;
-                    if (pn4 && pn4->pn_type == TOK_NAME) {
+                    if (pn4 && pn4->isKind(TOK_NAME)) {
                         /* Note a propagated constant with the const's name. */
                         JS_ASSERT(!pn4->maybeExpr());
                         jsatomid index;
                         if (!cg->makeAtomIndex(pn4->pn_atom, &index))
                             goto bad;
                         CG_NEXT(cg) = pc;
                         if (js_NewSrcNote2(cx, cg, SRC_LABEL, ptrdiff_t(index)) < 0)
                             goto bad;
@@ -3828,24 +3825,24 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
                 }
             }
             CG_NEXT(cg) = savepc;
         }
     }
 
     /* Emit code for each case's statements, copying pn_offset up to pn3. */
     for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
-        if (switchOp == JSOP_CONDSWITCH && pn3->pn_type != TOK_DEFAULT)
+        if (switchOp == JSOP_CONDSWITCH && !pn3->isKind(TOK_DEFAULT))
             CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx, cg, pn3->pn_offset, goto bad);
         pn4 = pn3->pn_right;
         ok = js_EmitTree(cx, cg, pn4);
         if (!ok)
             goto out;
         pn3->pn_offset = pn4->pn_offset;
-        if (pn3->pn_type == TOK_DEFAULT)
+        if (pn3->isKind(TOK_DEFAULT))
             off = pn3->pn_offset - top;
     }
 
     if (!hasDefault) {
         /* If no default case, offset for default is to end of switch. */
         off = CG_OFFSET(cg) - top;
     }
 
@@ -3887,17 +3884,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
                 goto out;
             pc += JUMP_OFFSET_LEN;
         }
     } else if (switchOp == JSOP_LOOKUPSWITCH) {
         /* Skip over the already-initialized number of cases. */
         pc += INDEX_LEN;
 
         for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
-            if (pn3->pn_type == TOK_DEFAULT)
+            if (pn3->isKind(TOK_DEFAULT))
                 continue;
             if (!cg->constList.append(*pn3->pn_pval))
                 goto bad;
             SET_INDEX(pc, cg->constList.length() - 1);
             pc += INDEX_LEN;
 
             off = pn3->pn_offset - top;
             ok = js_SetJumpOffset(cx, cg, pc, off);
@@ -3909,17 +3906,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
 
 out:
     if (table)
         cx->free_(table);
     if (ok) {
         ok = js_PopStatementCG(cx, cg);
 
 #if JS_HAS_BLOCK_SCOPE
-        if (ok && pn->pn_right->pn_type == TOK_LEXICALSCOPE)
+        if (ok && pn->pn_right->isKind(TOK_LEXICALSCOPE))
             ok = EmitLeaveBlock(cx, cg, JSOP_LEAVEBLOCK, box);
 #endif
     }
     return ok;
 
 bad:
     ok = JS_FALSE;
     goto out;
@@ -3978,29 +3975,29 @@ MaybeEmitVarDecl(JSContext *cx, JSCodeGe
 
     if (!pn->pn_cookie.isFree()) {
         atomIndex = pn->pn_cookie.slot();
     } else {
         if (!cg->makeAtomIndex(pn->pn_atom, &atomIndex))
             return false;
     }
 
-    if (JOF_OPTYPE(pn->pn_op) == JOF_ATOM &&
+    if (JOF_OPTYPE(pn->getOp()) == JOF_ATOM &&
         (!cg->inFunction() || (cg->flags & TCF_FUN_HEAVYWEIGHT)) &&
         !(pn->pn_dflags & PND_GVAR))
     {
         CG_SWITCH_TO_PROLOG(cg);
         if (!UpdateLineNumberNotes(cx, cg, pn->pn_pos.begin.lineno))
             return false;
         EMIT_INDEX_OP(prologOp, atomIndex);
         CG_SWITCH_TO_MAIN(cg);
     }
 
     if (cg->inFunction() &&
-        JOF_OPTYPE(pn->pn_op) == JOF_LOCAL &&
+        JOF_OPTYPE(pn->getOp()) == JOF_LOCAL &&
         pn->pn_cookie.slot() < cg->bindings.countVars() &&
         cg->shouldNoteClosedName(pn))
     {
         if (!cg->closedVars.append(pn->pn_cookie.slot()))
             return false;
     }
 
     if (result)
@@ -4013,48 +4010,46 @@ MaybeEmitVarDecl(JSContext *cx, JSCodeGe
 typedef JSBool
 (*DestructuringDeclEmitter)(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
                             JSParseNode *pn);
 
 static JSBool
 EmitDestructuringDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
                       JSParseNode *pn)
 {
-    JS_ASSERT(pn->pn_type == TOK_NAME);
+    JS_ASSERT(pn->isKind(TOK_NAME));
     if (!BindNameToSlot(cx, cg, pn))
         return JS_FALSE;
 
-    JS_ASSERT(PN_OP(pn) != JSOP_ARGUMENTS && PN_OP(pn) != JSOP_CALLEE);
+    JS_ASSERT(!pn->isOp(JSOP_ARGUMENTS) && !pn->isOp(JSOP_CALLEE));
     return MaybeEmitVarDecl(cx, cg, prologOp, pn, NULL);
 }
 
 static JSBool
 EmitDestructuringDecls(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
                        JSParseNode *pn)
 {
     JSParseNode *pn2, *pn3;
     DestructuringDeclEmitter emitter;
 
-    if (pn->pn_type == TOK_RB) {
+    if (pn->isKind(TOK_RB)) {
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
-            if (pn2->pn_type == TOK_COMMA)
+            if (pn2->isKind(TOK_COMMA))
                 continue;
-            emitter = (pn2->pn_type == TOK_NAME)
+            emitter = (pn2->isKind(TOK_NAME))
                       ? EmitDestructuringDecl
                       : EmitDestructuringDecls;
             if (!emitter(cx, cg, prologOp, pn2))
                 return JS_FALSE;
         }
     } else {
-        JS_ASSERT(pn->pn_type == TOK_RC);
+        JS_ASSERT(pn->isKind(TOK_RC));
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             pn3 = pn2->pn_right;
-            emitter = (pn3->pn_type == TOK_NAME)
-                      ? EmitDestructuringDecl
-                      : EmitDestructuringDecls;
+            emitter = pn3->isKind(TOK_NAME) ? EmitDestructuringDecl : EmitDestructuringDecls;
             if (!emitter(cx, cg, prologOp, pn3))
                 return JS_FALSE;
         }
     }
     return JS_TRUE;
 }
 
 static JSBool
@@ -4064,30 +4059,30 @@ static JSBool
 EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
 {
     /*
      * Now emit the lvalue opcode sequence.  If the lvalue is a nested
      * destructuring initialiser-form, call ourselves to handle it, then
      * pop the matched value.  Otherwise emit an lvalue bytecode sequence
      * ending with a JSOP_ENUMELEM or equivalent op.
      */
-    if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC) {
+    if (pn->isKind(TOK_RB) || pn->isKind(TOK_RC)) {
         if (!EmitDestructuringOpsHelper(cx, cg, pn))
             return JS_FALSE;
         if (js_Emit1(cx, cg, JSOP_POP) < 0)
             return JS_FALSE;
     } else {
-        if (pn->pn_type == TOK_NAME) {
+        if (pn->isKind(TOK_NAME)) {
             if (!BindNameToSlot(cx, cg, pn))
                 return JS_FALSE;
             if (pn->isConst() && !pn->isInitialized())
                 return js_Emit1(cx, cg, JSOP_POP) >= 0;
         }
 
-        switch (pn->pn_op) {
+        switch (pn->getOp()) {
           case JSOP_SETNAME:
           case JSOP_SETGNAME:
             /*
              * NB: pn is a PN_NAME node, not a PN_BINARY.  Nevertheless,
              * we want to emit JSOP_ENUMELEM, which has format JOF_ELEM.
              * So here and for JSOP_ENUMCONSTELEM, we use EmitElemOp.
              */
             if (!EmitElemOp(cx, pn, JSOP_ENUMELEM, cg))
@@ -4104,17 +4099,17 @@ EmitDestructuringLHS(JSContext *cx, JSCo
             jsuint slot = pn->pn_cookie.asInteger();
             EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, slot);
             break;
           }
 
           case JSOP_SETARG:
           {
             jsuint slot = pn->pn_cookie.asInteger();
-            EMIT_UINT16_IMM_OP(PN_OP(pn), slot);
+            EMIT_UINT16_IMM_OP(pn->getOp(), slot);
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return JS_FALSE;
             break;
           }
 
           default:
           {
             ptrdiff_t top;
@@ -4149,18 +4144,18 @@ EmitDestructuringOpsHelper(JSContext *cx
 {
     jsuint index;
     JSParseNode *pn2, *pn3;
     JSBool doElemOp;
 
 #ifdef DEBUG
     intN stackDepth = cg->stackDepth;
     JS_ASSERT(stackDepth != 0);
-    JS_ASSERT(pn->pn_arity == PN_LIST);
-    JS_ASSERT(pn->pn_type == TOK_RB || pn->pn_type == TOK_RC);
+    JS_ASSERT(pn->isArity(PN_LIST));
+    JS_ASSERT(pn->isKind(TOK_RB) || pn->isKind(TOK_RC));
 #endif
 
     if (pn->pn_count == 0) {
         /* Emit a DUP;POP sequence for the decompiler. */
         return js_Emit1(cx, cg, JSOP_DUP) >= 0 &&
                js_Emit1(cx, cg, JSOP_POP) >= 0;
     }
 
@@ -4177,37 +4172,36 @@ EmitDestructuringOpsHelper(JSContext *cx
 
         /*
          * Now push the property name currently being matched, which is either
          * the array initialiser's current index, or the current property name
          * "label" on the left of a colon in the object initialiser.  Set pn3
          * to the lvalue node, which is in the value-initializing position.
          */
         doElemOp = JS_TRUE;
-        if (pn->pn_type == TOK_RB) {
+        if (pn->isKind(TOK_RB)) {
             if (!EmitNumberOp(cx, index, cg))
                 return JS_FALSE;
             pn3 = pn2;
         } else {
-            JS_ASSERT(pn->pn_type == TOK_RC);
-            JS_ASSERT(pn2->pn_type == TOK_COLON);
+            JS_ASSERT(pn->isKind(TOK_RC));
+            JS_ASSERT(pn2->isKind(TOK_COLON));
             pn3 = pn2->pn_left;
-            if (pn3->pn_type == TOK_NUMBER) {
+            if (pn3->isKind(TOK_NUMBER)) {
                 /*
                  * If we are emitting an object destructuring initialiser,
                  * annotate the index op with SRC_INITPROP so we know we are
                  * not decompiling an array initialiser.
                  */
                 if (js_NewSrcNote(cx, cg, SRC_INITPROP) < 0)
                     return JS_FALSE;
                 if (!EmitNumberOp(cx, pn3->pn_dval, cg))
                     return JS_FALSE;
             } else {
-                JS_ASSERT(pn3->pn_type == TOK_STRING ||
-                          pn3->pn_type == TOK_NAME);
+                JS_ASSERT(pn3->isKind(TOK_STRING) || pn3->isKind(TOK_NAME));
                 if (!EmitAtomOp(cx, pn3, JSOP_GETPROP, cg))
                     return JS_FALSE;
                 doElemOp = JS_FALSE;
             }
             pn3 = pn2->pn_right;
         }
 
         if (doElemOp) {
@@ -4217,18 +4211,18 @@ EmitDestructuringOpsHelper(JSContext *cx
              * is one deeper than when we started.
              */
             if (!EmitElemOpBase(cx, cg, JSOP_GETELEM))
                 return JS_FALSE;
             JS_ASSERT(cg->stackDepth == stackDepth + 1);
         }
 
         /* Nullary comma node makes a hole in the array destructurer. */
-        if (pn3->pn_type == TOK_COMMA && pn3->pn_arity == PN_NULLARY) {
-            JS_ASSERT(pn->pn_type == TOK_RB);
+        if (pn3->isKind(TOK_COMMA) && pn3->isArity(PN_NULLARY)) {
+            JS_ASSERT(pn->isKind(TOK_RB));
             JS_ASSERT(pn2 == pn3);
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return JS_FALSE;
         } else {
             if (!EmitDestructuringLHS(cx, cg, pn3))
                 return JS_FALSE;
         }
 
@@ -4284,17 +4278,17 @@ EmitGroupAssignment(JSContext *cx, JSCod
     depth = limit = (uintN) cg->stackDepth;
     for (pn = rhs->pn_head; pn; pn = pn->pn_next) {
         if (limit == JS_BIT(16)) {
             ReportCompileErrorNumber(cx, CG_TS(cg), rhs, JSREPORT_ERROR, JSMSG_ARRAY_INIT_TOO_BIG);
             return JS_FALSE;
         }
 
         /* MaybeEmitGroupAssignment won't call us if rhs is holey. */
-        JS_ASSERT(!(pn->pn_type == TOK_COMMA && pn->pn_arity == PN_NULLARY));
+        JS_ASSERT(!(pn->isKind(TOK_COMMA) && pn->isArity(PN_NULLARY)));
         if (!js_EmitTree(cx, cg, pn))
             return JS_FALSE;
         ++limit;
     }
 
     if (js_NewSrcNote2(cx, cg, SRC_GROUPASSIGN, OpToDeclType(prologOp)) < 0)
         return JS_FALSE;
 
@@ -4302,17 +4296,17 @@ EmitGroupAssignment(JSContext *cx, JSCod
     for (pn = lhs->pn_head; pn; pn = pn->pn_next, ++i) {
         /* MaybeEmitGroupAssignment requires lhs->pn_count <= rhs->pn_count. */
         JS_ASSERT(i < limit);
         jsint slot = AdjustBlockSlot(cx, cg, i);
         if (slot < 0)
             return JS_FALSE;
         EMIT_UINT16_IMM_OP(JSOP_GETLOCAL, slot);
 
-        if (pn->pn_type == TOK_COMMA && pn->pn_arity == PN_NULLARY) {
+        if (pn->isKind(TOK_COMMA) && pn->isArity(PN_NULLARY)) {
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return JS_FALSE;
         } else {
             if (!EmitDestructuringLHS(cx, cg, pn))
                 return JS_FALSE;
         }
     }
 
@@ -4328,21 +4322,21 @@ EmitGroupAssignment(JSContext *cx, JSCod
  * we set *pop to JSOP_NOP so callers can veto emitting pn followed by a pop.
  */
 static JSBool
 MaybeEmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
                          JSParseNode *pn, JSOp *pop)
 {
     JSParseNode *lhs, *rhs;
 
-    JS_ASSERT(pn->pn_type == TOK_ASSIGN);
+    JS_ASSERT(pn->isKind(TOK_ASSIGN));
     JS_ASSERT(*pop == JSOP_POP || *pop == JSOP_POPV);
     lhs = pn->pn_left;
     rhs = pn->pn_right;
-    if (lhs->pn_type == TOK_RB && rhs->pn_type == TOK_RB &&
+    if (lhs->isKind(TOK_RB) && rhs->isKind(TOK_RB) &&
         !(rhs->pn_xflags & PNX_HOLEY) &&
         lhs->pn_count <= rhs->pn_count) {
         if (!EmitGroupAssignment(cx, cg, prologOp, lhs, rhs))
             return JS_FALSE;
         *pop = JSOP_NOP;
     }
     return JS_TRUE;
 }
@@ -4370,61 +4364,61 @@ EmitVariables(JSContext *cx, JSCodeGener
      * block from any calls to BindNameToSlot hiding in pn2->pn_expr so that
      * it won't find any names in the new let block.
      *
      * The same goes for let declarations in the head of any kind of for loop.
      * Unlike a let declaration 'let x = i' within a block, where x is hoisted
      * to the start of the block, a 'for (let x = i...) ...' loop evaluates i
      * in the containing scope, and puts x in the loop body's scope.
      */
-    DebugOnly<bool> let = (pn->pn_op == JSOP_NOP);
+    DebugOnly<bool> let = (pn->isOp(JSOP_NOP));
     forInVar = (pn->pn_xflags & PNX_FORINVAR) != 0;
 
     off = noteIndex = -1;
     for (pn2 = pn->pn_head; ; pn2 = next) {
         first = pn2 == pn->pn_head;
         next = pn2->pn_next;
 
-        if (pn2->pn_type != TOK_NAME) {
+        if (!pn2->isKind(TOK_NAME)) {
 #if JS_HAS_DESTRUCTURING
-            if (pn2->pn_type == TOK_RB || pn2->pn_type == TOK_RC) {
+            if (pn2->isKind(TOK_RB) || pn2->isKind(TOK_RC)) {
                 /*
                  * Emit variable binding ops, but not destructuring ops.
                  * The parser (see Variables, jsparse.c) has ensured that
                  * our caller will be the TOK_FOR/TOK_IN case in js_EmitTree,
                  * and that case will emit the destructuring code only after
                  * emitting an enumerating opcode and a branch that tests
                  * whether the enumeration ended.
                  */
                 JS_ASSERT(forInVar);
                 JS_ASSERT(pn->pn_count == 1);
-                if (!EmitDestructuringDecls(cx, cg, PN_OP(pn), pn2))
+                if (!EmitDestructuringDecls(cx, cg, pn->getOp(), pn2))
                     return JS_FALSE;
                 break;
             }
 #endif
 
             /*
              * A destructuring initialiser assignment preceded by var will
              * never occur to the left of 'in' in a for-in loop.  As with 'for
              * (var x = i in o)...', this will cause the entire 'var [a, b] =
              * i' to be hoisted out of the loop.
              */
-            JS_ASSERT(pn2->pn_type == TOK_ASSIGN);
+            JS_ASSERT(pn2->isKind(TOK_ASSIGN));
             JS_ASSERT(!forInVar);
 
             /*
              * To allow the front end to rewrite var f = x; as f = x; when a
              * function f(){} precedes the var, detect simple name assignment
              * here and initialize the name.
              */
 #if !JS_HAS_DESTRUCTURING
-            JS_ASSERT(pn2->pn_left->pn_type == TOK_NAME);
+            JS_ASSERT(pn2->pn_left->isKind(TOK_NAME));
 #else
-            if (pn2->pn_left->pn_type == TOK_NAME)
+            if (pn2->pn_left->isKind(TOK_NAME))
 #endif
             {
                 pn3 = pn2->pn_right;
                 pn2 = pn2->pn_left;
                 goto do_name;
             }
 
 #if JS_HAS_DESTRUCTURING
@@ -4433,40 +4427,40 @@ EmitVariables(JSContext *cx, JSCodeGener
                  * If this is the only destructuring assignment in the list,
                  * try to optimize to a group assignment.  If we're in a let
                  * head, pass JSOP_POP rather than the pseudo-prolog JSOP_NOP
                  * in pn->pn_op, to suppress a second (and misplaced) 'let'.
                  */
                 JS_ASSERT(noteIndex < 0 && !pn2->pn_next);
                 op = JSOP_POP;
                 if (!MaybeEmitGroupAssignment(cx, cg,
-                                              inLetHead ? JSOP_POP : PN_OP(pn),
+                                              inLetHead ? JSOP_POP : pn->getOp(),
                                               pn2, &op)) {
                     return JS_FALSE;
                 }
                 if (op == JSOP_NOP) {
                     pn->pn_xflags = (pn->pn_xflags & ~PNX_POPVAR) | PNX_GROUPINIT;
                     break;
                 }
             }
 
             pn3 = pn2->pn_left;
-            if (!EmitDestructuringDecls(cx, cg, PN_OP(pn), pn3))
+            if (!EmitDestructuringDecls(cx, cg, pn->getOp(), pn3))
                 return JS_FALSE;
 
             if (!js_EmitTree(cx, cg, pn2->pn_right))
                 return JS_FALSE;
 
             /*
              * Veto pn->pn_op if inLetHead to avoid emitting a SRC_DESTRUCT
              * that's redundant with respect to the SRC_DECL/SRC_DECL_LET that
              * we will emit at the bottom of this function.
              */
             if (!EmitDestructuringOps(cx, cg,
-                                      inLetHead ? JSOP_POP : PN_OP(pn),
+                                      inLetHead ? JSOP_POP : pn->getOp(),
                                       pn3)) {
                 return JS_FALSE;
             }
             goto emit_note_pop;
 #endif
         }
 
         /*
@@ -4476,40 +4470,40 @@ EmitVariables(JSContext *cx, JSCodeGener
          * pn_lexdef.
          */
         pn3 = pn2->maybeExpr();
 
      do_name:
         if (!BindNameToSlot(cx, cg, pn2))
             return JS_FALSE;
 
-        op = PN_OP(pn2);
+        op = pn2->getOp();
         if (op == JSOP_ARGUMENTS) {
             /* JSOP_ARGUMENTS => no initializer */
             JS_ASSERT(!pn3 && !let);
             pn3 = NULL;
 #ifdef __GNUC__
             atomIndex = 0;            /* quell GCC overwarning */
 #endif
         } else {
             JS_ASSERT(op != JSOP_CALLEE);
             JS_ASSERT(!pn2->pn_cookie.isFree() || !let);
-            if (!MaybeEmitVarDecl(cx, cg, PN_OP(pn), pn2, &atomIndex))
+            if (!MaybeEmitVarDecl(cx, cg, pn->getOp(), pn2, &atomIndex))
                 return JS_FALSE;
 
             if (pn3) {
                 JS_ASSERT(!forInVar);
                 if (op == JSOP_SETNAME) {
                     JS_ASSERT(!let);
                     EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex);
                 } else if (op == JSOP_SETGNAME) {
                     JS_ASSERT(!let);
                     EMIT_INDEX_OP(JSOP_BINDGNAME, atomIndex);
                 }
-                if (pn->pn_op == JSOP_DEFCONST &&
+                if (pn->isOp(JSOP_DEFCONST) &&
                     !js_DefineCompileTimeConstant(cx, cg, pn2->pn_atom, pn3)) {
                     return JS_FALSE;
                 }
 
                 oldflags = cg->flags;
                 cg->flags &= ~TCF_IN_FOR_INIT;
                 if (!js_EmitTree(cx, cg, pn3))
                     return JS_FALSE;
@@ -4520,29 +4514,29 @@ EmitVariables(JSContext *cx, JSCodeGener
         /*
          * The parser rewrites 'for (var x = i in o)' to hoist 'var x = i' --
          * likewise 'for (let x = i in o)' becomes 'i; for (let x in o)' using
          * a TOK_SEQ node to make the two statements appear as one. Therefore
          * if this declaration is part of a for-in loop head, we do not need to
          * emit op or any source note. Our caller, the TOK_FOR/TOK_IN case in
          * js_EmitTree, will annotate appropriately.
          */
-        JS_ASSERT_IF(pn2->pn_defn, pn3 == pn2->pn_expr);
+        JS_ASSERT_IF(pn2->isDefn(), pn3 == pn2->pn_expr);
         if (forInVar) {
             JS_ASSERT(pn->pn_count == 1);
             JS_ASSERT(!pn3);
             break;
         }
 
         if (first &&
             !inLetHead &&
             js_NewSrcNote2(cx, cg, SRC_DECL,
-                           (pn->pn_op == JSOP_DEFCONST)
+                           (pn->isOp(JSOP_DEFCONST))
                            ? SRC_DECL_CONST
-                           : (pn->pn_op == JSOP_DEFVAR)
+                           : (pn->isOp(JSOP_DEFVAR))
                            ? SRC_DECL_VAR
                            : SRC_DECL_LET) < 0) {
             return JS_FALSE;
         }
         if (op == JSOP_ARGUMENTS) {
             if (js_Emit1(cx, cg, op) < 0)
                 return JS_FALSE;
         } else if (!pn2->pn_cookie.isFree()) {
@@ -4587,41 +4581,41 @@ EmitAssignment(JSContext *cx, JSCodeGene
     /*
      * Check left operand type and generate specialized code for it.
      * Specialize to avoid ECMA "reference type" values on the operand
      * stack, which impose pervasive runtime "GetValue" costs.
      */
     jsatomid atomIndex = (jsatomid) -1;              /* quell GCC overwarning */
     jsbytecode offset = 1;
 
-    switch (PN_TYPE(lhs)) {
+    switch (lhs->getKind()) {
       case TOK_NAME:
         if (!BindNameToSlot(cx, cg, lhs))
             return false;
         if (!lhs->pn_cookie.isFree()) {
             atomIndex = lhs->pn_cookie.asInteger();
         } else {
             if (!cg->makeAtomIndex(lhs->pn_atom, &atomIndex))
                 return false;
             if (!lhs->isConst()) {
-                JSOp op = PN_OP(lhs) == JSOP_SETGNAME ? JSOP_BINDGNAME : JSOP_BINDNAME;
+                JSOp op = lhs->isOp(JSOP_SETGNAME) ? JSOP_BINDGNAME : JSOP_BINDNAME;
                 EMIT_INDEX_OP(op, atomIndex);
                 offset++;
             }
         }
         break;
       case TOK_DOT:
         if (!js_EmitTree(cx, cg, lhs->expr()))
             return false;
         offset++;
         if (!cg->makeAtomIndex(lhs->pn_atom, &atomIndex))
             return false;
         break;
       case TOK_LB:
-        JS_ASSERT(lhs->pn_arity == PN_BINARY);
+        JS_ASSERT(lhs->isArity(PN_BINARY));
         if (!js_EmitTree(cx, cg, lhs->pn_left))
             return false;
         if (!js_EmitTree(cx, cg, lhs->pn_right))
             return false;
         offset += 2;
         break;
 #if JS_HAS_DESTRUCTURING
       case TOK_RB:
@@ -4630,55 +4624,52 @@ EmitAssignment(JSContext *cx, JSCodeGene
 #endif
       case TOK_LP:
         if (!js_EmitTree(cx, cg, lhs))
             return false;
         offset++;
         break;
 #if JS_HAS_XML_SUPPORT
       case TOK_UNARYOP:
-        JS_ASSERT(lhs->pn_op == JSOP_SETXMLNAME);
+        JS_ASSERT(lhs->isOp(JSOP_SETXMLNAME));
         if (!js_EmitTree(cx, cg, lhs->pn_kid))
             return false;
         if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0)
             return false;
         offset++;
         break;
 #endif
       default:
         JS_ASSERT(0);
     }
 
     if (op != JSOP_NOP) {
         JS_ASSERT(rhs);
-        switch (lhs->pn_type) {
+        switch (lhs->getKind()) {
           case TOK_NAME:
             if (lhs->isConst()) {
-                if (PN_OP(lhs) == JSOP_CALLEE) {
+                if (lhs->isOp(JSOP_CALLEE)) {
                     if (js_Emit1(cx, cg, JSOP_CALLEE) < 0)
                         return false;
                 } else {
-                    EMIT_INDEX_OP(PN_OP(lhs), atomIndex);
+                    EMIT_INDEX_OP(lhs->getOp(), atomIndex);
                 }
-            } else if (PN_OP(lhs) == JSOP_SETNAME) {
+            } else if (lhs->isOp(JSOP_SETNAME)) {
                 if (js_Emit1(cx, cg, JSOP_DUP) < 0)
                     return false;
                 EMIT_INDEX_OP(JSOP_GETXPROP, atomIndex);
-            } else if (PN_OP(lhs) == JSOP_SETGNAME) {
+            } else if (lhs->isOp(JSOP_SETGNAME)) {
                 if (!BindGlobal(cx, cg, lhs, lhs->pn_atom))
                     return false;
                 if (lhs->pn_cookie.isFree())
                     EmitAtomOp(cx, lhs, JSOP_GETGNAME, cg);
                 else
                     EMIT_UINT16_IMM_OP(JSOP_GETGLOBAL, lhs->pn_cookie.asInteger());
             } else {
-                EMIT_UINT16_IMM_OP((PN_OP(lhs) == JSOP_SETARG)
-                                   ? JSOP_GETARG
-                                   : JSOP_GETLOCAL,
-                                   atomIndex);
+                EMIT_UINT16_IMM_OP(lhs->isOp(JSOP_SETARG) ? JSOP_GETARG : JSOP_GETLOCAL, atomIndex);
             }
             break;
           case TOK_DOT:
             if (js_Emit1(cx, cg, JSOP_DUP) < 0)
                 return false;
             if (lhs->pn_atom == cx->runtime->atomState.protoAtom) {
                 if (!EmitIndexOp(cx, JSOP_QNAMEPART, atomIndex, cg))
                     return false;
@@ -4715,48 +4706,48 @@ EmitAssignment(JSContext *cx, JSCodeGene
 
     /* If += etc., emit the binary operator with a decompiler note. */
     if (op != JSOP_NOP) {
         /*
          * Take care to avoid SRC_ASSIGNOP if the left-hand side is a const
          * declared in the current compilation unit, as in this case (just
          * a bit further below) we will avoid emitting the assignment op.
          */
-        if (lhs->pn_type != TOK_NAME || !lhs->isConst()) {
+        if (!lhs->isKind(TOK_NAME) || !lhs->isConst()) {
             if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0)
                 return false;
         }
         if (js_Emit1(cx, cg, op) < 0)
             return false;
     }
 
     /* Left parts such as a.b.c and a[b].c need a decompiler note. */
-    if (lhs->pn_type != TOK_NAME &&
+    if (!lhs->isKind(TOK_NAME) &&
 #if JS_HAS_DESTRUCTURING
-        lhs->pn_type != TOK_RB &&
-        lhs->pn_type != TOK_RC &&
+        !lhs->isKind(TOK_RB) &&
+        !lhs->isKind(TOK_RC) &&
 #endif
         js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) {
         return false;
     }
 
     /* Finally, emit the specialized assignment bytecode. */
-    switch (lhs->pn_type) {
+    switch (lhs->getKind()) {
       case TOK_NAME:
         if (lhs->isConst()) {
             if (!rhs) {
                 ReportCompileErrorNumber(cx, CG_TS(cg), lhs, JSREPORT_ERROR,
                                          JSMSG_BAD_FOR_LEFTSIDE);
                 return false;
             }
             break;
         }
         /* FALL THROUGH */
       case TOK_DOT:
-        EMIT_INDEX_OP(PN_OP(lhs), atomIndex);
+        EMIT_INDEX_OP(lhs->getOp(), atomIndex);
         break;
       case TOK_LB:
       case TOK_LP:
         if (js_Emit1(cx, cg, JSOP_SETELEM) < 0)
             return false;
         break;
 #if JS_HAS_DESTRUCTURING
       case TOK_RB:
@@ -4831,40 +4822,40 @@ EmitEndInit(JSContext *cx, JSCodeGenerat
         EMIT_UINT16_IMM_OP(JSOP_SHARPINIT, cg->sharpSlotBase);
 #endif
     return js_Emit1(cx, cg, JSOP_ENDINIT) >= 0;
 }
 
 bool
 JSParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp)
 {
-    switch (pn_type) {
+    switch (getKind()) {
       case TOK_NUMBER:
         vp->setNumber(pn_dval);
         return true;
       case TOK_STRING:
         vp->setString(pn_atom);
         return true;
       case TOK_PRIMARY:
-        switch (pn_op) {
+        switch (getOp()) {
           case JSOP_NULL:
             vp->setNull();
             return true;
           case JSOP_FALSE:
             vp->setBoolean(false);
             return true;
           case JSOP_TRUE:
             vp->setBoolean(true);
             return true;
           default:
             JS_NOT_REACHED("Unexpected node");
             return false;
         }
       case TOK_RB: {
-        JS_ASSERT((pn_op == JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
+        JS_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
  
         JSObject *obj = NewDenseAllocatedArray(cx, pn_count);
         if (!obj)
             return false;
 
         unsigned idx = 0;
         for (JSParseNode *pn = pn_head; pn; idx++, pn = pn->pn_next) {
             Value value;
@@ -4875,41 +4866,41 @@ JSParseNode::getConstantValue(JSContext 
         }
         JS_ASSERT(idx == pn_count);
 
         types::FixArrayType(cx, obj);
         vp->setObject(*obj);
         return true;
       }
       case TOK_RC: {
-        JS_ASSERT((pn_op == JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
+        JS_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
 
         gc::AllocKind kind = GuessObjectGCKind(pn_count, false);
         JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
         if (!obj)
             return false;
 
         for (JSParseNode *pn = pn_head; pn; pn = pn->pn_next) {
             Value value;
             if (!pn->pn_right->getConstantValue(cx, strictChecks, &value))
                 return false;
 
             JSParseNode *pnid = pn->pn_left;
-            if (pnid->pn_type == TOK_NUMBER) {
+            if (pnid->isKind(TOK_NUMBER)) {
                 Value idvalue = NumberValue(pnid->pn_dval);
                 jsid id;
                 if (idvalue.isInt32() && INT_FITS_IN_JSID(idvalue.toInt32()))
                     id = INT_TO_JSID(idvalue.toInt32());
                 else if (!js_InternNonIntElementId(cx, obj, idvalue, &id))
                     return false;
                 if (!obj->defineProperty(cx, id, value, NULL, NULL, JSPROP_ENUMERATE))
                     return false;
             } else {
-                JS_ASSERT(pnid->pn_type == TOK_NAME ||
-                          pnid->pn_type == TOK_STRING);
+                JS_ASSERT(pnid->isKind(TOK_NAME) ||
+                          pnid->isKind(TOK_STRING));
                 JS_ASSERT(pnid->pn_atom != cx->runtime->atomState.protoAtom);
                 jsid id = ATOM_TO_JSID(pnid->pn_atom);
                 if (!DefineNativeProperty(cx, obj, id, value, NULL, NULL,
                                           JSPROP_ENUMERATE, 0, 0)) {
                     return false;
                 }
             }
         }
@@ -4978,39 +4969,39 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
     JS_CHECK_RECURSION(cx, return JS_FALSE);
 
     ok = JS_TRUE;
     pn->pn_offset = top = CG_OFFSET(cg);
 
     /* Emit notes to tell the current bytecode's source line number. */
     UPDATE_LINE_NUMBER_NOTES(cx, cg, pn->pn_pos.begin.lineno);
 
-    switch (pn->pn_type) {
+    switch (pn->getKind()) {
       case TOK_FUNCTION:
       {
         JSFunction *fun;
         uintN slot;
 
 #if JS_HAS_XML_SUPPORT
-        if (pn->pn_arity == PN_NULLARY) {
+        if (pn->isArity(PN_NULLARY)) {
             if (js_Emit1(cx, cg, JSOP_GETFUNNS) < 0)
                 return JS_FALSE;
             break;
         }
 #endif
 
         fun = pn->pn_funbox->function();
         JS_ASSERT(fun->isInterpreted());
         if (fun->script()) {
             /*
              * This second pass is needed to emit JSOP_NOP with a source note
              * for the already-emitted function definition prolog opcode. See
              * comments in the TOK_LC case.
              */
-            JS_ASSERT(pn->pn_op == JSOP_NOP);
+            JS_ASSERT(pn->isOp(JSOP_NOP));
             JS_ASSERT(cg->inFunction());
             if (!EmitFunctionDefNop(cx, cg, pn->pn_index))
                 return JS_FALSE;
             break;
         }
 
         JS_ASSERT_IF(pn->pn_funbox->tcflags & TCF_FUN_HEAVYWEIGHT,
                      fun->kind() == JSFUN_INTERPRETED);
@@ -5054,17 +5045,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         cg2 = NULL;
         if (!pn)
             return JS_FALSE;
 
         /* Make the function object a literal in the outer script's pool. */
         index = cg->objectList.index(pn->pn_funbox);
 
         /* Emit a bytecode pointing to the closure object in its immediate. */
-        op = PN_OP(pn);
+        op = pn->getOp();
         if (op != JSOP_NOP) {
             if ((pn->pn_funbox->tcflags & TCF_GENEXP_LAMBDA) &&
                 js_NewSrcNote(cx, cg, SRC_GENEXP) < 0) {
                 return JS_FALSE;
             }
             EMIT_INDEX_OP(op, index);
 
             /* Make blockChain determination quicker. */
@@ -5120,21 +5111,21 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         }
         break;
       }
 
       case TOK_ARGSBODY:
       {
         JSParseNode *pnlast = pn->last();
         for (JSParseNode *pn2 = pn->pn_head; pn2 != pnlast; pn2 = pn2->pn_next) {
-            if (!pn2->pn_defn)
+            if (!pn2->isDefn())
                 continue;
             if (!BindNameToSlot(cx, cg, pn2))
                 return JS_FALSE;
-            if (JOF_OPTYPE(pn2->pn_op) == JOF_QARG && cg->shouldNoteClosedName(pn2)) {
+            if (JOF_OPTYPE(pn2->getOp()) == JOF_QARG && cg->shouldNoteClosedName(pn2)) {
                 if (!cg->closedArgs.append(pn2->pn_cookie.slot()))
                     return JS_FALSE;
             }
         }
         ok = js_EmitTree(cx, cg, pnlast);
         break;
       }
 
@@ -5201,17 +5192,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
              * stmtInfo.breaks.
              */
             jmp = EmitGoto(cx, cg, &stmtInfo, &stmtInfo.breaks);
             if (jmp < 0)
                 return JS_FALSE;
 
             /* Ensure the branch-if-false comes here, then emit the else. */
             CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
-            if (pn3->pn_type == TOK_IF) {
+            if (pn3->isKind(TOK_IF)) {
                 pn = pn3;
                 goto if_again;
             }
 
             if (!js_EmitTree(cx, cg, pn3))
                 return JS_FALSE;
 
             /*
@@ -5337,31 +5328,31 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         break;
 
       case TOK_FOR:
         beq = 0;                /* suppress gcc warnings */
         jmp = -1;
         pn2 = pn->pn_left;
         js_PushStatement(cg, &stmtInfo, STMT_FOR_LOOP, top);
 
-        if (pn2->pn_type == TOK_IN) {
+        if (pn2->isKind(TOK_IN)) {
             /* Set stmtInfo type for later testing. */
             stmtInfo.type = STMT_FOR_IN_LOOP;
 
             /*
              * If the left part is 'var x', emit code to define x if necessary
              * using a prolog opcode, but do not emit a pop. If the left part
              * was originally 'var x = i', the parser will have rewritten it;
              * see Parser::forStatement. 'for (let x = i in o)' is mercifully
              * banned.
              */
             bool forLet = false;
             if (JSParseNode *decl = pn2->pn_kid1) {
-                JS_ASSERT(TokenKindIsDecl(PN_TYPE(decl)));
-                forLet = PN_TYPE(decl) == TOK_LET;
+                JS_ASSERT(TokenKindIsDecl(decl->getKind()));
+                forLet = decl->isKind(TOK_LET);
                 cg->flags |= TCF_IN_FOR_INIT;
                 if (!js_EmitTree(cx, cg, decl))
                     return JS_FALSE;
                 cg->flags &= ~TCF_IN_FOR_INIT;
             }
 
             /* Compile the object expression to the right of 'in'. */
             {
@@ -5374,17 +5365,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                     return JS_FALSE;
             }
 
             /*
              * Emit a bytecode to convert top of stack value to the iterator
              * object depending on the loop variant (for-in, for-each-in, or
              * destructuring for-in).
              */
-            JS_ASSERT(pn->pn_op == JSOP_ITER);
+            JS_ASSERT(pn->isOp(JSOP_ITER));
             if (js_Emit2(cx, cg, JSOP_ITER, (uint8) pn->pn_iflags) < 0)
                 return JS_FALSE;
 
             /* Annotate so the decompiler can find the loop-closing jump. */
             noteIndex = js_NewSrcNote(cx, cg, SRC_FOR_IN);
             if (noteIndex < 0)
                 return JS_FALSE;
 
@@ -5414,17 +5405,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
              * left hand side. The JSOP_POP after this assignment is annotated
              * so that the decompiler can distinguish 'for (x in y)' from
              * 'for (var x in y)'.
              */
             if (!EmitAssignment(cx, cg, pn2->pn_kid2, JSOP_NOP, NULL))
                 return false;
             tmp2 = CG_OFFSET(cg);
             if (pn2->pn_kid1 && js_NewSrcNote2(cx, cg, SRC_DECL,
-                                               (pn2->pn_kid1->pn_op == JSOP_DEFVAR)
+                                               (pn2->pn_kid1->isOp(JSOP_DEFVAR))
                                                ? SRC_DECL_VAR
                                                : SRC_DECL_LET) < 0) {
                 return false;
             }
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return false;
 
             /* The stack should be balanced around the assignment opcode sequence. */
@@ -5467,32 +5458,32 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             op = JSOP_POP;
             pn3 = pn2->pn_kid1;
             if (!pn3) {
                 /* No initializer: emit an annotated nop for the decompiler. */
                 op = JSOP_NOP;
             } else {
                 cg->flags |= TCF_IN_FOR_INIT;
 #if JS_HAS_DESTRUCTURING
-                if (pn3->pn_type == TOK_ASSIGN &&
+                if (pn3->isKind(TOK_ASSIGN) &&
                     !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
                     return JS_FALSE;
                 }
 #endif
                 if (op == JSOP_POP) {
                     if (!js_EmitTree(cx, cg, pn3))
                         return JS_FALSE;
-                    if (TokenKindIsDecl(PN_TYPE(pn3))) {
+                    if (TokenKindIsDecl(pn3->getKind())) {
                         /*
                          * Check whether a destructuring-initialized var decl
                          * was optimized to a group assignment.  If so, we do
                          * not need to emit a pop below, so switch to a nop,
                          * just for the decompiler.
                          */
-                        JS_ASSERT(pn3->pn_arity == PN_LIST);
+                        JS_ASSERT(pn3->isArity(PN_LIST));
                         if (pn3->pn_xflags & PNX_GROUPINIT)
                             op = JSOP_NOP;
                     }
                 }
                 cg->flags &= ~TCF_IN_FOR_INIT;
             }
 
             /*
@@ -5536,17 +5527,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                 stmt->update = CG_OFFSET(cg);
             } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
 
             /* Check for update code to do before the condition (if any). */
             pn3 = pn2->pn_kid3;
             if (pn3) {
                 op = JSOP_POP;
 #if JS_HAS_DESTRUCTURING
-                if (pn3->pn_type == TOK_ASSIGN &&
+                if (pn3->isKind(TOK_ASSIGN) &&
                     !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
                     return JS_FALSE;
                 }
 #endif
                 if (op == JSOP_POP && !js_EmitTree(cx, cg, pn3))
                     return JS_FALSE;
 
                 /* Always emit the POP or NOP, to help the decompiler. */
@@ -5607,17 +5598,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                     return JS_FALSE;
             }
         }
 
         /* Now fixup all breaks and continues (before for/in's JSOP_ENDITER). */
         if (!js_PopStatementCG(cx, cg))
             return JS_FALSE;
 
-        if (pn2->pn_type == TOK_IN) {
+        if (pn2->isKind(TOK_IN)) {
             if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top, CG_OFFSET(cg)) ||
                 js_Emit1(cx, cg, JSOP_ENDITER) < 0) {
                 return JS_FALSE;
             }
         }
         break;
 
       case TOK_BREAK: {
@@ -5826,17 +5817,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                     return JS_FALSE;
                 CATCHNOTE(stmtInfo) = catchNote;
 
                 /*
                  * Emit the lexical scope and catch body.  Save the catch's
                  * block object population via count, for use when targeting
                  * guardJump at the next catch (the guard mismatch case).
                  */
-                JS_ASSERT(pn3->pn_type == TOK_LEXICALSCOPE);
+                JS_ASSERT(pn3->isKind(TOK_LEXICALSCOPE));
                 count = OBJ_BLOCK_COUNT(cx, pn3->pn_objbox->object);
                 prevBox = pn3->pn_objbox;
                 if (!js_EmitTree(cx, cg, pn3))
                     return JS_FALSE;
 
                 /* gosub <finally>, if required */
                 if (pn->pn_kid3) {
                     jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH,
@@ -5975,17 +5966,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         /*
          * Dup the exception object if there is a guard for rethrowing to use
          * it later when rethrowing or in other catches.
          */
         if (pn->pn_kid2 && js_Emit1(cx, cg, JSOP_DUP) < 0)
             return JS_FALSE;
 
         pn2 = pn->pn_kid1;
-        switch (pn2->pn_type) {
+        switch (pn2->getKind()) {
 #if JS_HAS_DESTRUCTURING
           case TOK_RB:
           case TOK_RC:
             if (!EmitDestructuringOps(cx, cg, JSOP_NOP, pn2))
                 return JS_FALSE;
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return JS_FALSE;
             break;
@@ -6090,26 +6081,26 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         if (js_Emit1(cx, cg, JSOP_YIELD) < 0)
             return JS_FALSE;
         break;
 #endif
 
       case TOK_LC:
       {
 #if JS_HAS_XML_SUPPORT
-        if (pn->pn_arity == PN_UNARY) {
+        if (pn->isArity(PN_UNARY)) {
             if (!js_EmitTree(cx, cg, pn->pn_kid))
                 return JS_FALSE;
-            if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
+            if (js_Emit1(cx, cg, pn->getOp()) < 0)
                 return JS_FALSE;
             break;
         }
 #endif
 
-        JS_ASSERT(pn->pn_arity == PN_LIST);
+        JS_ASSERT(pn->isArity(PN_LIST));
 
         noteIndex = -1;
         tmp = CG_OFFSET(cg);
         if (pn->pn_xflags & PNX_NEEDBRACES) {
             noteIndex = js_NewSrcNote2(cx, cg, SRC_BRACE, 0);
             if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0)
                 return JS_FALSE;
         }
@@ -6130,36 +6121,36 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
              * mode for scripts does not allow separate emitter passes.
              */
             JS_ASSERT(cg->inFunction());
             if (pn->pn_xflags & PNX_DESTRUCT) {
                 /*
                  * Assign the destructuring arguments before defining any
                  * functions, see bug 419662.
                  */
-                JS_ASSERT(pnchild->pn_type == TOK_SEMI);
-                JS_ASSERT(pnchild->pn_kid->pn_type == TOK_VAR);
+                JS_ASSERT(pnchild->isKind(TOK_SEMI));
+                JS_ASSERT(pnchild->pn_kid->isKind(TOK_VAR));
                 if (!js_EmitTree(cx, cg, pnchild))
                     return JS_FALSE;
                 pnchild = pnchild->pn_next;
             }
 
             for (pn2 = pnchild; pn2; pn2 = pn2->pn_next) {
-                if (pn2->pn_type == TOK_FUNCTION) {
-                    if (pn2->pn_op == JSOP_NOP) {
+                if (pn2->isKind(TOK_FUNCTION)) {
+                    if (pn2->isOp(JSOP_NOP)) {
                         if (!js_EmitTree(cx, cg, pn2))
                             return JS_FALSE;
                     } else {
                         /*
                          * JSOP_DEFFUN in a top-level block with function
                          * definitions appears, for example, when "if (true)"
                          * is optimized away from "if (true) function x() {}".
                          * See bug 428424.
                          */
-                        JS_ASSERT(pn2->pn_op == JSOP_DEFFUN);
+                        JS_ASSERT(pn2->isOp(JSOP_DEFFUN));
                     }
                 }
             }
         }
         for (pn2 = pnchild; pn2; pn2 = pn2->pn_next) {
             if (!js_EmitTree(cx, cg, pn2))
                 return JS_FALSE;
         }
@@ -6170,17 +6161,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             return JS_FALSE;
         }
 
         ok = js_PopStatementCG(cx, cg);
         break;
       }
 
       case TOK_SEQ:
-        JS_ASSERT(pn->pn_arity == PN_LIST);
+        JS_ASSERT(pn->isArity(PN_LIST));
         js_PushStatement(cg, &stmtInfo, STMT_SEQ, top);
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             if (!js_EmitTree(cx, cg, pn2))
                 return JS_FALSE;
         }
         ok = js_PopStatementCG(cx, cg);
         break;
 
@@ -6226,36 +6217,36 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                                                   JSMSG_USELESS_EXPR)) {
                         return JS_FALSE;
                     }
                 }
             } else {
                 op = wantval ? JSOP_POPV : JSOP_POP;
 #if JS_HAS_DESTRUCTURING
                 if (!wantval &&
-                    pn2->pn_type == TOK_ASSIGN &&
+                    pn2->isKind(TOK_ASSIGN) &&
                     !MaybeEmitGroupAssignment(cx, cg, op, pn2, &op)) {
                     return JS_FALSE;
                 }
 #endif
                 if (op != JSOP_NOP) {
                     /*
                      * Specialize JSOP_SETPROP to JSOP_SETMETHOD to defer or
                      * avoid null closure cloning. Do this only for assignment
                      * statements that are not completion values wanted by a
                      * script evaluator, to ensure that the joined function
                      * can't escape directly.
                      */
                     if (!wantval &&
-                        PN_TYPE(pn2) == TOK_ASSIGN &&
-                        PN_OP(pn2) == JSOP_NOP &&
-                        PN_OP(pn2->pn_left) == JSOP_SETPROP &&
-                        PN_OP(pn2->pn_right) == JSOP_LAMBDA &&
+                        pn2->isKind(TOK_ASSIGN) &&
+                        pn2->isOp(JSOP_NOP) &&
+                        pn2->pn_left->isOp(JSOP_SETPROP) &&
+                        pn2->pn_right->isOp(JSOP_LAMBDA) &&
                         pn2->pn_right->pn_funbox->joinable()) {
-                        pn2->pn_left->pn_op = JSOP_SETMETHOD;
+                        pn2->pn_left->setOp(JSOP_SETMETHOD);
                     }
                     if (!js_EmitTree(cx, cg, pn2))
                         return JS_FALSE;
                     if (js_Emit1(cx, cg, op) < 0)
                         return JS_FALSE;
                 }
             }
         }
@@ -6265,19 +6256,19 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         /* Emit an annotated nop so we know to decompile a label. */
         atom = pn->pn_atom;
 
         jsatomid index;
         if (!cg->makeAtomIndex(atom, &index))
             return JS_FALSE;
 
         pn2 = pn->expr();
-        noteType = (pn2->pn_type == TOK_LC ||
-                    (pn2->pn_type == TOK_LEXICALSCOPE &&
-                     pn2->expr()->pn_type == TOK_LC))
+        noteType = (pn2->isKind(TOK_LC) ||
+                    (pn2->isKind(TOK_LEXICALSCOPE) &&
+                     pn2->expr()->isKind(TOK_LC)))
                    ? SRC_LABELBRACE
                    : SRC_LABEL;
         noteIndex = js_NewSrcNote2(cx, cg, noteType, ptrdiff_t(index));
         if (noteIndex < 0 ||
             js_Emit1(cx, cg, JSOP_NOP) < 0) {
             return JS_FALSE;
         }
 
@@ -6320,17 +6311,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             if (noteIndex < 0 ||
                 js_Emit1(cx, cg, JSOP_POP) < 0) {
                 return JS_FALSE;
             }
         }
         break;
 
       case TOK_ASSIGN:
-        if (!EmitAssignment(cx, cg, pn->pn_left, PN_OP(pn), pn->pn_right))
+        if (!EmitAssignment(cx, cg, pn->pn_left, pn->getOp(), pn->pn_right))
             return false;
         break;
 
       case TOK_HOOK:
         /* Emit the condition, then branch if false to the else part. */
         if (!js_EmitTree(cx, cg, pn->pn_kid1))
             return JS_FALSE;
         noteIndex = js_NewSrcNote(cx, cg, SRC_COND);
@@ -6374,30 +6365,30 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          * leaves the original operand value on the stack and jumps; otherwise
          * it pops and falls into the next bytecode, which evaluates the right
          * operand.  The jump goes around the right operand evaluation.
          *
          * JSOP_AND converts the operand on the stack to boolean, and if false,
          * leaves the original operand value on the stack and jumps; otherwise
          * it pops and falls into the right operand's bytecode.
          */
-        if (pn->pn_arity == PN_BINARY) {
+        if (pn->isArity(PN_BINARY)) {
             if (!js_EmitTree(cx, cg, pn->pn_left))
                 return JS_FALSE;
             top = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0);
             if (top < 0)
                 return JS_FALSE;
             if (!js_EmitTree(cx, cg, pn->pn_right))
                 return JS_FALSE;
             off = CG_OFFSET(cg);
             pc = CG_CODE(cg, top);
             CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, off - top);
-            *pc = pn->pn_op;
+            *pc = pn->getOp();
         } else {
-            JS_ASSERT(pn->pn_arity == PN_LIST);
+            JS_ASSERT(pn->isArity(PN_LIST));
             JS_ASSERT(pn->pn_head->pn_next->pn_next);
 
             /* Left-associative operator chain: avoid too much recursion. */
             pn2 = pn->pn_head;
             if (!js_EmitTree(cx, cg, pn2))
                 return JS_FALSE;
             top = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0);
             if (top < 0)
@@ -6420,17 +6411,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                 return JS_FALSE;
 
             pn2 = pn->pn_head;
             off = CG_OFFSET(cg);
             do {
                 pc = CG_CODE(cg, top);
                 tmp = GetJumpOffset(cg, pc);
                 CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, off - top);
-                *pc = pn->pn_op;
+                *pc = pn->getOp();
                 top += tmp;
             } while ((pn2 = pn2->pn_next)->pn_next);
         }
         break;
 
       case TOK_PLUS:
       case TOK_BITOR:
       case TOK_BITXOR:
@@ -6438,37 +6429,37 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
       case TOK_EQOP:
       case TOK_RELOP:
       case TOK_IN:
       case TOK_INSTANCEOF:
       case TOK_SHOP:
       case TOK_MINUS:
       case TOK_STAR:
       case TOK_DIVOP:
-        if (pn->pn_arity == PN_LIST) {
+        if (pn->isArity(PN_LIST)) {
             /* Left-associative operator chain: avoid too much recursion. */
             pn2 = pn->pn_head;
             if (!js_EmitTree(cx, cg, pn2))
                 return JS_FALSE;
-            op = PN_OP(pn);
+            op = pn->getOp();
             while ((pn2 = pn2->pn_next) != NULL) {
                 if (!js_EmitTree(cx, cg, pn2))
                     return JS_FALSE;
                 if (js_Emit1(cx, cg, op) < 0)
                     return JS_FALSE;
             }
         } else {
 #if JS_HAS_XML_SUPPORT
             uintN oldflags;
 
       case TOK_DBLCOLON:
-            if (pn->pn_arity == PN_NAME) {
+            if (pn->isArity(PN_NAME)) {
                 if (!js_EmitTree(cx, cg, pn->expr()))
                     return JS_FALSE;
-                if (!EmitAtomOp(cx, pn, PN_OP(pn), cg))
+                if (!EmitAtomOp(cx, pn, pn->getOp(), cg))
                     return JS_FALSE;
                 break;
             }
 
             /*
              * Binary :: has a right operand that brackets arbitrary code,
              * possibly including a let (a = b) ... expression.  We must clear
              * TCF_IN_FOR_INIT to avoid mis-compiling such beasts.
@@ -6480,69 +6471,69 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             /* Binary operators that evaluate both operands unconditionally. */
             if (!js_EmitTree(cx, cg, pn->pn_left))
                 return JS_FALSE;
             if (!js_EmitTree(cx, cg, pn->pn_right))
                 return JS_FALSE;
 #if JS_HAS_XML_SUPPORT
             cg->flags |= oldflags & TCF_IN_FOR_INIT;
 #endif
-            if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
+            if (js_Emit1(cx, cg, pn->getOp()) < 0)
                 return JS_FALSE;
         }
         break;
 
       case TOK_THROW:
 #if JS_HAS_XML_SUPPORT
       case TOK_AT:
       case TOK_DEFAULT:
-        JS_ASSERT(pn->pn_arity == PN_UNARY);
+        JS_ASSERT(pn->isArity(PN_UNARY));
         /* FALL THROUGH */
 #endif
       case TOK_UNARYOP:
       {
         uintN oldflags;
 
         /* Unary op, including unary +/-. */
-        op = PN_OP(pn);
+        op = pn->getOp();
 #if JS_HAS_XML_SUPPORT
         if (op == JSOP_XMLNAME) {
             if (!EmitXMLName(cx, pn, op, cg))
                 return JS_FALSE;
             break;
         }
 #endif
         pn2 = pn->pn_kid;
 
-        if (op == JSOP_TYPEOF && pn2->pn_type != TOK_NAME)
+        if (op == JSOP_TYPEOF && !pn2->isKind(TOK_NAME))
             op = JSOP_TYPEOFEXPR;
 
         oldflags = cg->flags;
         cg->flags &= ~TCF_IN_FOR_INIT;
         if (!js_EmitTree(cx, cg, pn2))
             return JS_FALSE;
         cg->flags |= oldflags & TCF_IN_FOR_INIT;
         if (js_Emit1(cx, cg, op) < 0)
             return JS_FALSE;
         break;
       }
 
       case TOK_INC:
       case TOK_DEC:
         /* Emit lvalue-specialized code for ++/-- operators. */
         pn2 = pn->pn_kid;
-        JS_ASSERT(pn2->pn_type != TOK_RP);
-        op = PN_OP(pn);
-        switch (pn2->pn_type) {
+        JS_ASSERT(!pn2->isKind(TOK_RP));
+        op = pn->getOp();
+        switch (pn2->getKind()) {
           default:
-            JS_ASSERT(pn2->pn_type == TOK_NAME);
-            pn2->pn_op = op;
+            JS_ASSERT(pn2->isKind(TOK_NAME));
+            pn2->setOp(op);
             if (!BindNameToSlot(cx, cg, pn2))
                 return JS_FALSE;
-            op = PN_OP(pn2);
+            op = pn2->getOp();
             if (op == JSOP_CALLEE) {
                 if (js_Emit1(cx, cg, op) < 0)
                     return JS_FALSE;
             } else if (!pn2->pn_cookie.isFree()) {
                 atomIndex = pn2->pn_cookie.asInteger();
                 EMIT_UINT16_IMM_OP(op, atomIndex);
             } else {
                 JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
@@ -6553,17 +6544,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                     if (!EmitAtomOp(cx, pn2, op, cg))
                         return JS_FALSE;
                 }
                 break;
             }
             if (pn2->isConst()) {
                 if (js_Emit1(cx, cg, JSOP_POS) < 0)
                     return JS_FALSE;
-                op = PN_OP(pn);
+                op = pn->getOp();
                 if (!(js_CodeSpec[op].format & JOF_POST)) {
                     if (js_Emit1(cx, cg, JSOP_ONE) < 0)
                         return JS_FALSE;
                     op = (js_CodeSpec[op].format & JOF_INC) ? JSOP_ADD : JSOP_SUB;
                     if (js_Emit1(cx, cg, op) < 0)
                         return JS_FALSE;
                 }
             }
@@ -6594,17 +6585,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             JS_ASSERT(js_CodeSpec[op].format & JOF_ELEM);
             if (js_Emit1(cx, cg, (JSOp)1) < 0)
                 return JS_FALSE;
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return JS_FALSE;
             break;
 #if JS_HAS_XML_SUPPORT
           case TOK_UNARYOP:
-            JS_ASSERT(pn2->pn_op == JSOP_SETXMLNAME);
+            JS_ASSERT(pn2->isOp(JSOP_SETXMLNAME));
             if (!js_EmitTree(cx, cg, pn2->pn_kid))
                 return JS_FALSE;
             if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0)
                 return JS_FALSE;
             if (!EmitElemIncDec(cx, NULL, op, cg))
                 return JS_FALSE;
             break;
 #endif
@@ -6612,21 +6603,21 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         break;
 
       case TOK_DELETE:
         /*
          * Under ECMA 3, deleting a non-reference returns true -- but alas we
          * must evaluate the operand if it appears it might have side effects.
          */
         pn2 = pn->pn_kid;
-        switch (pn2->pn_type) {
+        switch (pn2->getKind()) {
           case TOK_NAME:
             if (!BindNameToSlot(cx, cg, pn2))
                 return JS_FALSE;
-            op = PN_OP(pn2);
+            op = pn2->getOp();
             if (op == JSOP_FALSE) {
                 if (js_Emit1(cx, cg, op) < 0)
                     return JS_FALSE;
             } else {
                 if (!EmitAtomOp(cx, pn2, op, cg))
                     return JS_FALSE;
             }
             break;
@@ -6650,17 +6641,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
              * to foo(), true (a comma expression, requiring SRC_PCDELTA).
              */
             useful = JS_FALSE;
             if (!CheckSideEffects(cx, cg, pn2, &useful))
                 return JS_FALSE;
             if (!useful) {
                 off = noteIndex = -1;
             } else {
-                JS_ASSERT_IF(pn2->pn_type == TOK_LP, !(pn2->pn_xflags & PNX_SETCALL));
+                JS_ASSERT_IF(pn2->isKind(TOK_LP), !(pn2->pn_xflags & PNX_SETCALL));
                 if (!js_EmitTree(cx, cg, pn2))
                     return JS_FALSE;
                 off = CG_OFFSET(cg);
                 noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);
                 if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_POP) < 0)
                     return JS_FALSE;
             }
             if (js_Emit1(cx, cg, JSOP_TRUE) < 0)
@@ -6696,36 +6687,36 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 #endif
 
       case TOK_DOT:
         /*
          * Pop a stack operand, convert it to object, get a property named by
          * this bytecode's immediate-indexed atom operand, and push its value
          * (not a reference to it).
          */
-        ok = EmitPropOp(cx, pn, PN_OP(pn), cg, JS_FALSE);
+        ok = EmitPropOp(cx, pn, pn->getOp(), cg, JS_FALSE);
         break;
 
       case TOK_LB:
 #if JS_HAS_XML_SUPPORT
       case TOK_DBLDOT:
 #endif
         /*
          * Pop two operands, convert the left one to object and the right one
          * to property name (atom or tagged int), get the named property, and
          * push its value.  Set the "obj" register to the result of ToObject
          * on the left operand.
          */
-        ok = EmitElemOp(cx, pn, PN_OP(pn), cg);
+        ok = EmitElemOp(cx, pn, pn->getOp(), cg);
         break;
 
       case TOK_NEW:
       case TOK_LP:
       {
-        bool callop = (PN_TYPE(pn) == TOK_LP);
+        bool callop = pn->isKind(TOK_LP);
 
         /*
          * Emit callable invocation or operator new (constructor call) code.
          * First, emit code for the left operand to evaluate the callable or
          * constructable object expression.
          *
          * For operator new applied to other expressions than E4X ones, we emit
          * JSOP_GETPROP instead of JSOP_CALLPROP, etc. This is necessary to
@@ -6733,33 +6724,33 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          * in jsinterp.cpp for JSOP_LAMBDA followed by JSOP_{SET,INIT}PROP.
          *
          * Then (or in a call case that has no explicit reference-base
          * object) we emit JSOP_PUSH to produce the |this| slot required
          * for calls (which non-strict mode functions will box into the
          * global object).
          */
         pn2 = pn->pn_head;
-        switch (pn2->pn_type) {
+        switch (pn2->getKind()) {
           case TOK_NAME:
             if (!EmitNameOp(cx, cg, pn2, callop))
                 return JS_FALSE;
             break;
           case TOK_DOT:
-            if (!EmitPropOp(cx, pn2, PN_OP(pn2), cg, callop))
+            if (!EmitPropOp(cx, pn2, pn2->getOp(), cg, callop))
                 return JS_FALSE;
             break;
           case TOK_LB:
-            JS_ASSERT(pn2->pn_op == JSOP_GETELEM);
+            JS_ASSERT(pn2->isOp(JSOP_GETELEM));
             if (!EmitElemOp(cx, pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM, cg))
                 return JS_FALSE;
             break;
           case TOK_UNARYOP:
 #if JS_HAS_XML_SUPPORT
-            if (pn2->pn_op == JSOP_XMLNAME) {
+            if (pn2->isOp(JSOP_XMLNAME)) {
                 if (!EmitXMLName(cx, pn2, JSOP_CALLXMLNAME, cg))
                     return JS_FALSE;
                 callop = true;          /* suppress JSOP_PUSH after */
                 break;
             }
 #endif
             /* FALL THROUGH */
           default:
@@ -6785,20 +6776,20 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             if (!js_EmitTree(cx, cg, pn3))
                 return JS_FALSE;
         }
         cg->flags |= oldflags & TCF_IN_FOR_INIT;
         if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - off) < 0)
             return JS_FALSE;
 
         argc = pn->pn_count - 1;
-        if (js_Emit3(cx, cg, PN_OP(pn), ARGC_HI(argc), ARGC_LO(argc)) < 0)
-            return JS_FALSE;
-        CheckTypeSet(cx, cg, PN_OP(pn));
-        if (PN_OP(pn) == JSOP_EVAL) {
+        if (js_Emit3(cx, cg, pn->getOp(), ARGC_HI(argc), ARGC_LO(argc)) < 0)
+            return JS_FALSE;
+        CheckTypeSet(cx, cg, pn->getOp());
+        if (pn->isOp(JSOP_EVAL)) {
             EMIT_UINT16_IMM_OP(JSOP_LINENO, pn->pn_pos.begin.lineno);
             if (EmitBlockChain(cx, cg) < 0)
                 return JS_FALSE;
         }
         if (pn->pn_xflags & PNX_SETCALL) {
             if (js_Emit1(cx, cg, JSOP_SETCALL) < 0)
                 return JS_FALSE;
         }
@@ -6816,17 +6807,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          * If this lexical scope is not for a catch block, let block or let
          * expression, or any kind of for loop (where the scope starts in the
          * head after the first part if for (;;), else in the body if for-in);
          * and if our container is top-level but not a function body, or else
          * a block statement; then emit a SRC_BRACE note.  All other container
          * statements get braces by default from the decompiler.
          */
         noteIndex = -1;
-        type = PN_TYPE(pn->expr());
+        type = pn->expr()->getKind();
         if (type != TOK_CATCH && type != TOK_LET && type != TOK_FOR &&
             (!(stmt = stmtInfo.down)
              ? !cg->inFunction()
              : stmt->type == STMT_BLOCK)) {
 #if defined DEBUG_brendan || defined DEBUG_mrbkap
             /* There must be no source note already output for the next op. */
             JS_ASSERT(CG_NOTE_COUNT(cg) == 0 ||
                       CG_LAST_NOTE_OFFSET(cg) != CG_OFFSET(cg) ||
@@ -6839,17 +6830,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 
         JS_ASSERT(CG_OFFSET(cg) == top);
         if (!EmitEnterBlock(cx, pn, cg))
             return JS_FALSE;
 
         if (!js_EmitTree(cx, cg, pn->pn_expr))
             return JS_FALSE;
 
-        op = PN_OP(pn);
+        op = pn->getOp();
         if (op == JSOP_LEAVEBLOCKEXPR) {
             if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
                 return JS_FALSE;
         } else {
             if (noteIndex >= 0 &&
                 !js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0,
                                      CG_OFFSET(cg) - top)) {
                 return JS_FALSE;
@@ -6872,33 +6863,33 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          *   let-statement:                         let (x = y) { ... }
          *   let-declaration in statement context:  let x = y;
          *   let-declaration in for-loop head:      for (let ...) ...
          *
          * Let-expressions and let-statements are represented as binary nodes
          * with their variable declarations on the left and the body on the
          * right.
          */
-        if (pn->pn_arity == PN_BINARY) {
+        if (pn->isArity(PN_BINARY)) {
             pn2 = pn->pn_right;
             pn = pn->pn_left;
         } else {
             pn2 = NULL;
         }
 
         /*
          * Non-null pn2 means that pn is the variable list from a let head.
          *
          * Use TempPopScope to evaluate the expressions in the enclosing scope.
          * This also causes the initializing assignments to be emitted in the
          * enclosing scope, but the assignment opcodes emitted here
          * (essentially just setlocal, though destructuring assignment uses
          * other additional opcodes) do not care about the block chain.
          */
-        JS_ASSERT(pn->pn_arity == PN_LIST);
+        JS_ASSERT(pn->isArity(PN_LIST));
         TempPopScope tps;
         bool popScope = pn2 || (cg->flags & TCF_IN_FOR_INIT);
         if (popScope && !tps.popBlock(cx, cg))
             return JS_FALSE;
         if (!EmitVariables(cx, cg, pn, pn2 != NULL, &noteIndex))
             return JS_FALSE;
         tmp = CG_OFFSET(cg);
         if (popScope && !tps.repushBlock(cx, cg))
@@ -6926,17 +6917,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          * under the array initialiser code generator for array comprehension
          * special casing.
          */
         if (!js_EmitTree(cx, cg, pn->pn_kid))
             return JS_FALSE;
         slot = AdjustBlockSlot(cx, cg, cg->arrayCompDepth);
         if (slot < 0)
             return JS_FALSE;
-        EMIT_UINT16_IMM_OP(PN_OP(pn), slot);
+        EMIT_UINT16_IMM_OP(pn->getOp(), slot);
         break;
       }
 #endif
 
       case TOK_RB:
 #if JS_HAS_GENERATORS
       case TOK_ARRAYCOMP:
 #endif
@@ -6949,17 +6940,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          * JSOP_SETELEM/JSOP_SETPROP would do.
          */
 #if JS_HAS_SHARP_VARS
         sharpnum = -1;
       do_emit_array:
 #endif
 
 #if JS_HAS_GENERATORS
-        if (pn->pn_type == TOK_ARRAYCOMP) {
+        if (pn->isKind(TOK_ARRAYCOMP)) {
             uintN saveDepth;
 
             if (!EmitNewInit(cx, cg, JSProto_Array, pn, sharpnum))
                 return JS_FALSE;
 
             /*
              * Pass the new array's stack index to the TOK_ARRAYPUSH case via
              * cg->arrayCompDepth, then simply traverse the TOK_FOR node and
@@ -6997,17 +6988,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             pc = CG_CODE(cg, off);
             SET_UINT24(pc, pn->pn_count);
         }
 
         pn2 = pn->pn_head;
         for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) {
             if (!EmitNumberOp(cx, atomIndex, cg))
                 return JS_FALSE;
-            if (pn2->pn_type == TOK_COMMA && pn2->pn_arity == PN_NULLARY) {
+            if (pn2->isKind(TOK_COMMA) && pn2->isArity(PN_NULLARY)) {
                 if (js_Emit1(cx, cg, JSOP_HOLE) < 0)
                     return JS_FALSE;
             } else {
                 if (!js_EmitTree(cx, cg, pn2))
                     return JS_FALSE;
             }
             if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
                 return JS_FALSE;
@@ -7070,55 +7061,55 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             if (!obj)
                 return JS_FALSE;
         }
 
         uintN methodInits = 0, slowMethodInits = 0;
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
             pn3 = pn2->pn_left;
-            if (pn3->pn_type == TOK_NUMBER) {
+            if (pn3->isKind(TOK_NUMBER)) {
                 if (!EmitNumberOp(cx, pn3->pn_dval, cg))
                     return JS_FALSE;
             }
 
             /* Emit code for the property initializer. */
             if (!js_EmitTree(cx, cg, pn2->pn_right))
                 return JS_FALSE;
 
-            op = PN_OP(pn2);
+            op = pn2->getOp();
             if (op == JSOP_GETTER || op == JSOP_SETTER) {
                 obj = NULL;
                 if (js_Emit1(cx, cg, op) < 0)
                     return JS_FALSE;
             }
 
             /* Annotate JSOP_INITELEM so we decompile 2:c and not just c. */
-            if (pn3->pn_type == TOK_NUMBER) {
+            if (pn3->isKind(TOK_NUMBER)) {
                 obj = NULL;
                 if (js_NewSrcNote(cx, cg, SRC_INITPROP) < 0)
                     return JS_FALSE;
                 if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
                     return JS_FALSE;
             } else {
-                JS_ASSERT(pn3->pn_type == TOK_NAME ||
-                          pn3->pn_type == TOK_STRING);
+                JS_ASSERT(pn3->isKind(TOK_NAME) ||
+                          pn3->isKind(TOK_STRING));
                 jsatomid index;
                 if (!cg->makeAtomIndex(pn3->pn_atom, &index))
                     return JS_FALSE;
 
                 /* Check whether we can optimize to JSOP_INITMETHOD. */
                 JSParseNode *init = pn2->pn_right;
-                bool lambda = PN_OP(init) == JSOP_LAMBDA;
+                bool lambda = init->isOp(JSOP_LAMBDA);
                 if (lambda)
                     ++methodInits;
                 if (op == JSOP_INITPROP && lambda && init->pn_funbox->joinable()) {
                     obj = NULL;
                     op = JSOP_INITMETHOD;
-                    pn2->pn_op = uint8(op);
+                    pn2->setOp(op);
                 } else {
                     /*
                      * Disable NEWOBJECT on initializers that set __proto__, which has
                      * a non-standard setter on objects.
                      */
                     if (pn3->pn_atom == cx->runtime->atomState.protoAtom)
                         obj = NULL;
                     op = JSOP_INITPROP;
@@ -7165,23 +7156,23 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         break;
       }
 
 #if JS_HAS_SHARP_VARS
       case TOK_DEFSHARP:
         JS_ASSERT(cg->hasSharps());
         sharpnum = pn->pn_num;
         pn = pn->pn_kid;
-        if (pn->pn_type == TOK_RB)
+        if (pn->isKind(TOK_RB))
             goto do_emit_array;
 # if JS_HAS_GENERATORS
-        if (pn->pn_type == TOK_ARRAYCOMP)
+        if (pn->isKind(TOK_ARRAYCOMP))
             goto do_emit_array;
 # endif
-        if (pn->pn_type == TOK_RC)
+        if (pn->isKind(TOK_RC))
             goto do_emit_object;
 
         if (!js_EmitTree(cx, cg, pn))
             return JS_FALSE;
         EMIT_UINT16PAIR_IMM_OP(JSOP_DEFSHARP, cg->sharpSlotBase, (jsatomid) sharpnum);
         break;
 
       case TOK_USESHARP:
@@ -7191,95 +7182,95 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 #endif /* JS_HAS_SHARP_VARS */
 
       case TOK_NAME:
         /*
          * Cope with a left-over function definition that was replaced by a use
          * of a later function definition of the same name. See FunctionDef and
          * MakeDefIntoUse in jsparse.cpp.
          */
-        if (pn->pn_op == JSOP_NOP)
+        if (pn->isOp(JSOP_NOP))
             break;
         if (!EmitNameOp(cx, cg, pn, JS_FALSE))
             return JS_FALSE;
         break;
 
 #if JS_HAS_XML_SUPPORT
       case TOK_XMLATTR:
       case TOK_XMLSPACE:
       case TOK_XMLTEXT:
       case TOK_XMLCDATA:
       case TOK_XMLCOMMENT:
 #endif
       case TOK_STRING:
-        ok = EmitAtomOp(cx, pn, PN_OP(pn), cg);
+        ok = EmitAtomOp(cx, pn, pn->getOp(), cg);
         break;
 
       case TOK_NUMBER:
         ok = EmitNumberOp(cx, pn->pn_dval, cg);
         break;
 
       case TOK_REGEXP: {
-        JS_ASSERT(pn->pn_op == JSOP_REGEXP);
+        JS_ASSERT(pn->isOp(JSOP_REGEXP));
         ok = EmitIndexOp(cx, JSOP_REGEXP,
                          cg->regexpList.index(pn->pn_objbox),
                          cg);
         break;
       }
 
 #if JS_HAS_XML_SUPPORT
       case TOK_ANYNAME:
 #endif
       case TOK_PRIMARY:
-        if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
+        if (js_Emit1(cx, cg, pn->getOp()) < 0)
             return JS_FALSE;
         break;
 
       case TOK_DEBUGGER:
         if (js_Emit1(cx, cg, JSOP_DEBUGGER) < 0)
             return JS_FALSE;
         break;
 
 #if JS_HAS_XML_SUPPORT
       case TOK_XMLELEM:
       case TOK_XMLLIST:
-        JS_ASSERT(PN_TYPE(pn) == TOK_XMLLIST || pn->pn_count != 0);
-        switch (pn->pn_head ? PN_TYPE(pn->pn_head) : TOK_XMLLIST) {
+        JS_ASSERT(pn->isKind(TOK_XMLLIST) || pn->pn_count != 0);
+        switch (pn->pn_head ? pn->pn_head->getKind() : TOK_XMLLIST) {
           case TOK_XMLETAGO:
             JS_ASSERT(0);
             /* FALL THROUGH */
           case TOK_XMLPTAGC:
           case TOK_XMLSTAGO:
             break;
           default:
             if (js_Emit1(cx, cg, JSOP_STARTXML) < 0)
                 return JS_FALSE;
         }
 
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
-            if (pn2->pn_type == TOK_LC &&
+            if (pn2->isKind(TOK_LC) &&
                 js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) {
                 return JS_FALSE;
             }
             if (!js_EmitTree(cx, cg, pn2))
                 return JS_FALSE;
             if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0)
                 return JS_FALSE;
         }
 
         if (pn->pn_xflags & PNX_XMLROOT) {
             if (pn->pn_count == 0) {
-                JS_ASSERT(pn->pn_type == TOK_XMLLIST);
+                JS_ASSERT(pn->isKind(TOK_XMLLIST));
                 atom = cx->runtime->atomState.emptyAtom;
                 jsatomid index;
                 if (!cg->makeAtomIndex(atom, &index))
                     return JS_FALSE;
                 EMIT_INDEX_OP(JSOP_STRING, index);
             }
-            if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
+            if (js_Emit1(cx, cg, pn->getOp()) < 0)
                 return JS_FALSE;
         }
 #ifdef DEBUG
         else
             JS_ASSERT(pn->pn_count != 0);
 #endif
         break;
 
@@ -7289,83 +7280,83 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
       {
         uint32 i;
 
         if (js_Emit1(cx, cg, JSOP_STARTXML) < 0)
             return JS_FALSE;
 
         {
             jsatomid index;
-            JSAtom *tmp = (pn->pn_type == TOK_XMLETAGO) ? cx->runtime->atomState.etagoAtom
-                                                        : cx->runtime->atomState.stagoAtom;
+            JSAtom *tmp = (pn->isKind(TOK_XMLETAGO)) ? cx->runtime->atomState.etagoAtom
+                                                     : cx->runtime->atomState.stagoAtom;
             if (!cg->makeAtomIndex(tmp, &index))
                 return JS_FALSE;
             EMIT_INDEX_OP(JSOP_STRING, index);
         }
 
         JS_ASSERT(pn->pn_count != 0);
         pn2 = pn->pn_head;
-        if (pn2->pn_type == TOK_LC && js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0)
+        if (pn2->isKind(TOK_LC) && js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0)
             return JS_FALSE;
         if (!js_EmitTree(cx, cg, pn2))
             return JS_FALSE;
         if (js_Emit1(cx, cg, JSOP_ADD) < 0)
             return JS_FALSE;
 
         for (pn2 = pn2->pn_next, i = 0; pn2; pn2 = pn2->pn_next, i++) {
-            if (pn2->pn_type == TOK_LC &&
+            if (pn2->isKind(TOK_LC) &&
                 js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) {
                 return JS_FALSE;
             }
             if (!js_EmitTree(cx, cg, pn2))
                 return JS_FALSE;
-            if ((i & 1) && pn2->pn_type == TOK_LC) {
+            if ((i & 1) && pn2->isKind(TOK_LC)) {
                 if (js_Emit1(cx, cg, JSOP_TOATTRVAL) < 0)
                     return JS_FALSE;
             }
             if (js_Emit1(cx, cg,
                          (i & 1) ? JSOP_ADDATTRVAL : JSOP_ADDATTRNAME) < 0) {
                 return JS_FALSE;
             }
         }
 
         {
             jsatomid index;
-            JSAtom *tmp = (pn->pn_type == TOK_XMLPTAGC) ? cx->runtime->atomState.ptagcAtom
-                                                        : cx->runtime->atomState.tagcAtom;
+            JSAtom *tmp = (pn->isKind(TOK_XMLPTAGC)) ? cx->runtime->atomState.ptagcAtom
+                                                     : cx->runtime->atomState.tagcAtom;
             if (!cg->makeAtomIndex(tmp, &index))
                 return JS_FALSE;
             EMIT_INDEX_OP(JSOP_STRING, index);
         }
         if (js_Emit1(cx, cg, JSOP_ADD) < 0)
             return JS_FALSE;
 
-        if ((pn->pn_xflags & PNX_XMLROOT) && js_Emit1(cx, cg, PN_OP(pn)) < 0)
+        if ((pn->pn_xflags & PNX_XMLROOT) && js_Emit1(cx, cg, pn->getOp()) < 0)
             return JS_FALSE;
         break;
       }
 
       case TOK_XMLNAME:
-        if (pn->pn_arity == PN_LIST) {
+        if (pn->isArity(PN_LIST)) {
             JS_ASSERT(pn->pn_count != 0);
             for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
-                if (pn2->pn_type == TOK_LC &&
+                if (pn2->isKind(TOK_LC) &&
                     js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) {
                     return JS_FALSE;
                 }
                 if (!js_EmitTree(cx, cg, pn2))
                     return JS_FALSE;
                 if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0)
                     return JS_FALSE;
             }
         } else {
-            JS_ASSERT(pn->pn_arity == PN_NULLARY);
-            ok = (pn->pn_op == JSOP_OBJECT)
-                 ? EmitObjectOp(cx, pn->pn_objbox, PN_OP(pn), cg)
-                 : EmitAtomOp(cx, pn, PN_OP(pn), cg);
+            JS_ASSERT(pn->isArity(PN_NULLARY));
+            ok = pn->isOp(JSOP_OBJECT)
+                 ? EmitObjectOp(cx, pn->pn_objbox, pn->getOp(), cg)
+                 : EmitAtomOp(cx, pn, pn->getOp(), cg);
         }
         break;
 
       case TOK_XMLPI: {
         jsatomid index;
         if (!cg->makeAtomIndex(pn->pn_atom2, &index))
             return false;
         if (!EmitIndexOp(cx, JSOP_QNAMEPART, index, cg))
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -129,20 +129,20 @@ JS_STATIC_ASSERT(pn_offsetof(pn_u.name.a
         }                                                                                   \
     JS_END_MACRO
 #define MUST_MATCH_TOKEN(tt, errno) MUST_MATCH_TOKEN_WITH_FLAGS(tt, errno, 0)
 
 void
 JSParseNode::become(JSParseNode *pn2)
 {
     JS_ASSERT(!pn_defn);
-    JS_ASSERT(!pn2->pn_defn);
+    JS_ASSERT(!pn2->isDefn());
 
     JS_ASSERT(!pn_used);
-    if (pn2->pn_used) {
+    if (pn2->isUsed()) {
         JSParseNode **pnup = &pn2->pn_lexdef->dn_uses;
         while (*pnup != pn2)
             pnup = &(*pnup)->pn_link;
         *pnup = this;
         pn_link = pn2->pn_link;
         pn_used = true;
         pn2->pn_link = NULL;
         pn2->pn_used = false;
@@ -153,17 +153,17 @@ JSParseNode::become(JSParseNode *pn2)
     pn_arity = pn2->pn_arity;
     pn_parens = pn2->pn_parens;
     pn_u = pn2->pn_u;
 
     /*
      * If any pointers are pointing to pn2, change them to point to this
      * instead, since pn2 will be cleared and probably recycled.
      */
-    if (PN_TYPE(this) == TOK_FUNCTION && pn_arity == PN_FUNC) {
+    if (this->isKind(TOK_FUNCTION) && isArity(PN_FUNC)) {
         /* Function node: fix up the pn_funbox->node back-pointer. */
         JS_ASSERT(pn_funbox->node == pn2);
         pn_funbox->node = this;
     } else if (pn_arity == PN_LIST && !pn_head) {
         /* Empty list: fix up the pn_tail pointer. */
         JS_ASSERT(pn_count == 0);
         JS_ASSERT(pn_tail == &pn2->pn_head);
         pn_tail = &pn_head;
@@ -171,17 +171,17 @@ JSParseNode::become(JSParseNode *pn2)
 
     pn2->clear();
 }
 
 void
 JSParseNode::clear()
 {
     pn_type = TOK_EOF;
-    pn_op = JSOP_NOP;
+    setOp(JSOP_NOP);
     pn_used = pn_defn = false;
     pn_arity = PN_NULLARY;
     pn_parens = false;
 }
 
 Parser::Parser(JSContext *cx, JSPrincipals *prin, StackFrame *cfp, bool foldConstants)
   : js::AutoGCRooter(cx, PARSER),
     context(cx),
@@ -369,20 +369,20 @@ AddNodeToFreeList(JSParseNode *pn, js::P
     JS_ASSERT(pn != parser->nodeList);
 
     /* 
      * It's too hard to clear these nodes from the AtomDefnMaps, etc. that
      * hold references to them, so we never free them. It's our caller's job to
      * recognize and process these, since their children do need to be dealt
      * with.
      */
-    JS_ASSERT(!pn->pn_used);
-    JS_ASSERT(!pn->pn_defn);
-
-    if (pn->pn_arity == PN_NAMESET && pn->pn_names.hasMap())
+    JS_ASSERT(!pn->isUsed());
+    JS_ASSERT(!pn->isDefn());
+
+    if (pn->isArity(PN_NAMESET) && pn->pn_names.hasMap())
         pn->pn_names.releaseMap(parser->context);
 
 #ifdef DEBUG
     /* Poison the node, to catch attempts to use it without initializing it. */
     memset(pn, 0xab, sizeof(*pn));
 #endif
 
     pn->pn_next = parser->nodeList;
@@ -446,17 +446,17 @@ Parser::cleanFunctionList(JSFunctionBox 
         } else {
             /* The function is still live. */
 
             /* First, remove nodes for deleted functions from our methods list. */
             {
                 JSParseNode **methodLink = &box->methods;
                 while (JSParseNode *method = *methodLink) {
                     /* Method nodes are never rewritten in place to be other kinds of nodes. */
-                    JS_ASSERT(method->pn_arity == PN_FUNC);
+                    JS_ASSERT(method->isArity(PN_FUNC));
                     if (!method->pn_funbox) {
                         /* Deleted: drop the node, and stay on this link. */
                         *methodLink = method->pn_link;
                     } else {
                         /* Live: keep the node, and move to the next link. */
                         methodLink = &method->pn_link;
                     }
                 }
@@ -515,17 +515,17 @@ class NodeStack {
  * nodes, and all function nodes; see comments for
  * js::Parser::cleanFunctionList). Some callers want to free |pn|; others
  * (PrepareNodeForMutation) don't care about |pn|, and just need to take care of
  * its children.
  */
 static bool
 PushNodeChildren(JSParseNode *pn, NodeStack *stack)
 {
-    switch (pn->pn_arity) {
+    switch (pn->getArity()) {
       case PN_FUNC:
         /*
          * Function nodes are linked into the function box tree, and may
          * appear on method lists. Both of those lists are singly-linked,
          * so trying to update them now could result in quadratic behavior
          * when recycling trees containing many functions; and the lists
          * can be very long. So we put off cleaning the lists up until just
          * before function analysis, when we call
@@ -553,21 +553,21 @@ PushNodeChildren(JSParseNode *pn, NodeSt
          * them, so clean up the pointers to avoid dangling references. The
          * top-level decls table carries references to them that later
          * iterations through the compileScript loop may find, so they need
          * to be neat.
          *
          * pn_expr and pn_lexdef share storage; the latter isn't an owning
          * reference.
          */
-        if (!pn->pn_used) {
+        if (!pn->isUsed()) {
             stack->pushUnlessNull(pn->pn_expr);
             pn->pn_expr = NULL;
         }
-        return !pn->pn_used && !pn->pn_defn;
+        return !pn->isUsed() && !pn->isDefn();
 
       case PN_LIST:
         stack->pushList(pn);
         break;
       case PN_TERNARY:
         stack->pushUnlessNull(pn->pn_kid1);
         stack->pushUnlessNull(pn->pn_kid2);
         stack->pushUnlessNull(pn->pn_kid3);
@@ -580,32 +580,34 @@ PushNodeChildren(JSParseNode *pn, NodeSt
       case PN_UNARY:
         stack->pushUnlessNull(pn->pn_kid);
         break;
       case PN_NULLARY:
         /* 
          * E4X function namespace nodes are PN_NULLARY, but can appear on use
          * lists.
          */
-        return !pn->pn_used && !pn->pn_defn;
+        return !pn->isUsed() && !pn->isDefn();
+      default:
+        ;
     }
 
     return true;
 }
 
 /*
  * Prepare |pn| to be mutated in place into a new kind of node. Recycle all
  * |pn|'s recyclable children (but not |pn| itself!), and disconnect it from
  * metadata structures (the function box tree).
  */
 static void
 PrepareNodeForMutation(JSParseNode *pn, JSTreeContext *tc)
 {
-    if (pn->pn_arity != PN_NULLARY) {
-        if (pn->pn_arity == PN_FUNC) {
+    if (!pn->isArity(PN_NULLARY)) {
+        if (pn->isArity(PN_FUNC)) {
             /*
              * Since this node could be turned into anything, we can't
              * ensure it won't be subsequently recycled, so we must
              * disconnect it from the funbox tree entirely.
              *
              * Note that pn_funbox may legitimately be NULL. functionDef
              * applies MakeDefIntoUse to definition nodes, which can come
              * from prior iterations of the big loop in compileScript. In
@@ -679,17 +681,18 @@ NewOrRecycledNode(JSTreeContext *tc)
         JS_ARENA_ALLOCATE_TYPE(pn, JSParseNode, &cx->tempPool);
         if (!pn)
             js_ReportOutOfMemory(cx);
     } else {
         tc->parser->nodeList = pn->pn_next;
     }
 
     if (pn) {
-        pn->pn_used = pn->pn_defn = false;
+        pn->setUsed(false);
+        pn->setDefn(false);
         memset(&pn->pn_u, 0, sizeof pn->pn_u);
         pn->pn_next = NULL;
     }
     return pn;
 }
 
 /* used only by static create methods of subclasses */
 
@@ -720,57 +723,57 @@ JSParseNode::newBinaryOrAppend(TokenKind
 
     if (!left || !right)
         return NULL;
 
     /*
      * Flatten a left-associative (left-heavy) tree of a given operator into
      * a list, to reduce js_FoldConstants and js_EmitTree recursion.
      */
-    if (PN_TYPE(left) == tt &&
-        PN_OP(left) == op &&
+    if (left->isKind(tt) &&
+        left->isOp(op) &&
         (js_CodeSpec[op].format & JOF_LEFTASSOC)) {
         if (left->pn_arity != PN_LIST) {
             pn1 = left->pn_left, pn2 = left->pn_right;
-            left->pn_arity = PN_LIST;
+            left->setArity(PN_LIST);
             left->pn_parens = false;
             left->initList(pn1);
             left->append(pn2);
             if (tt == TOK_PLUS) {
-                if (pn1->pn_type == TOK_STRING)
+                if (pn1->isKind(TOK_STRING))
                     left->pn_xflags |= PNX_STRCAT;
-                else if (pn1->pn_type != TOK_NUMBER)
+                else if (!pn1->isKind(TOK_NUMBER))
                     left->pn_xflags |= PNX_CANTFOLD;
-                if (pn2->pn_type == TOK_STRING)
+                if (pn2->isKind(TOK_STRING))
                     left->pn_xflags |= PNX_STRCAT;
-                else if (pn2->pn_type != TOK_NUMBER)
+                else if (!pn2->isKind(TOK_NUMBER))
                     left->pn_xflags |= PNX_CANTFOLD;
             }
         }
         left->append(right);
         left->pn_pos.end = right->pn_pos.end;
         if (tt == TOK_PLUS) {
-            if (right->pn_type == TOK_STRING)
+            if (right->isKind(TOK_STRING))
                 left->pn_xflags |= PNX_STRCAT;
-            else if (right->pn_type != TOK_NUMBER)
+            else if (!right->isKind(TOK_NUMBER))
                 left->pn_xflags |= PNX_CANTFOLD;
         }
         return left;
     }
 
     /*
      * Fold constant addition immediately, to conserve node space and, what's
      * more, so js_FoldConstants never sees mixed addition and concatenation
      * operations with more than one leading non-string operand in a PN_LIST
      * generated for expressions such as 1 + 2 + "pt" (which should evaluate
      * to "3pt", not "12pt").
      */
     if (tt == TOK_PLUS &&
-        left->pn_type == TOK_NUMBER &&
-        right->pn_type == TOK_NUMBER &&
+        left->isKind(TOK_NUMBER) &&
+        right->isKind(TOK_NUMBER) &&
         tc->parser->foldConstants) {
         left->pn_dval += right->pn_dval;
         left->pn_pos.end = right->pn_pos.end;
         RecycleTree(right, tc);
         return left;
     }
 
     pn = NewOrRecycledNode(tc);
@@ -824,17 +827,17 @@ GenerateBlockId(JSTreeContext *tc, uint3
     return true;
 }
 
 static bool
 GenerateBlockIdForStmtNode(JSParseNode *pn, JSTreeContext *tc)
 {
     JS_ASSERT(tc->topStmt);
     JS_ASSERT(STMT_MAYBE_SCOPE(tc->topStmt));
-    JS_ASSERT(pn->pn_type == TOK_LC || pn->pn_type == TOK_LEXICALSCOPE);
+    JS_ASSERT(pn->isKind(TOK_LC) || pn->isKind(TOK_LEXICALSCOPE));
     if (!GenerateBlockId(tc, tc->topStmt->blockid))
         return false;
     pn->pn_blockid = tc->topStmt->blockid;
     return true;
 }
 
 /*
  * Parse a top-level JS script.
@@ -1034,21 +1037,18 @@ Compiler::compileScript(JSContext *cx, J
         if (!parser.analyzeFunctions(&cg))
             goto out;
         cg.functionList = NULL;
 
         if (!js_EmitTree(cx, &cg, pn))
             goto out;
 
 #if JS_HAS_XML_SUPPORT
-        if (PN_TYPE(pn) != TOK_SEMI ||
-            !pn->pn_kid ||
-            !TreeTypeIsXML(PN_TYPE(pn->pn_kid))) {
+        if (!pn->isKind(TOK_SEMI) || !pn->pn_kid || !TreeTypeIsXML(pn->pn_kid->getKind()))
             onlyXML = false;
-        }
 #endif
         RecycleTree(pn, &cg);
     }
 
 #if JS_HAS_XML_SUPPORT
     /*
      * Prevent XML data theft via <script src="http://victim.com/foo.xml">.
      * For background, see:
@@ -1236,67 +1236,67 @@ Compiler::defineGlobals(JSContext *cx, G
 #define ENDS_IN_BREAK   2
 
 static int
 HasFinalReturn(JSParseNode *pn)
 {
     JSParseNode *pn2, *pn3;
     uintN rv, rv2, hasDefault;
 
-    switch (pn->pn_type) {
+    switch (pn->getKind()) {
       case TOK_LC:
         if (!pn->pn_head)
             return ENDS_IN_OTHER;
         return HasFinalReturn(pn->last());
 
       case TOK_IF:
         if (!pn->pn_kid3)
             return ENDS_IN_OTHER;
         return HasFinalReturn(pn->pn_kid2) & HasFinalReturn(pn->pn_kid3);
 
       case TOK_WHILE:
         pn2 = pn->pn_left;
-        if (pn2->pn_type == TOK_PRIMARY && pn2->pn_op == JSOP_TRUE)
+        if (pn2->isKind(TOK_PRIMARY) && pn2->isOp(JSOP_TRUE))
             return ENDS_IN_RETURN;
-        if (pn2->pn_type == TOK_NUMBER && pn2->pn_dval)
+        if (pn2->isKind(TOK_NUMBER) && pn2->pn_dval)
             return ENDS_IN_RETURN;
         return ENDS_IN_OTHER;
 
       case TOK_DO:
         pn2 = pn->pn_right;
-        if (pn2->pn_type == TOK_PRIMARY) {
-            if (pn2->pn_op == JSOP_FALSE)
+        if (pn2->isKind(TOK_PRIMARY)) {
+            if (pn2->isOp(JSOP_FALSE))
                 return HasFinalReturn(pn->pn_left);
-            if (pn2->pn_op == JSOP_TRUE)
+            if (pn2->isOp(JSOP_TRUE))
                 return ENDS_IN_RETURN;
         }
-        if (pn2->pn_type == TOK_NUMBER) {
+        if (pn2->isKind(TOK_NUMBER)) {
             if (pn2->pn_dval == 0)
                 return HasFinalReturn(pn->pn_left);
             return ENDS_IN_RETURN;
         }
         return ENDS_IN_OTHER;
 
       case TOK_FOR:
         pn2 = pn->pn_left;
-        if (pn2->pn_arity == PN_TERNARY && !pn2->pn_kid2)
+        if (pn2->isArity(PN_TERNARY) && !pn2->pn_kid2)
             return ENDS_IN_RETURN;
         return ENDS_IN_OTHER;
 
       case TOK_SWITCH:
         rv = ENDS_IN_RETURN;
         hasDefault = ENDS_IN_OTHER;
         pn2 = pn->pn_right;
-        if (pn2->pn_type == TOK_LEXICALSCOPE)
+        if (pn2->isKind(TOK_LEXICALSCOPE))
             pn2 = pn2->expr();
         for (pn2 = pn2->pn_head; rv && pn2; pn2 = pn2->pn_next) {
-            if (pn2->pn_type == TOK_DEFAULT)
+            if (pn2->isKind(TOK_DEFAULT))
                 hasDefault = ENDS_IN_RETURN;
             pn3 = pn2->pn_right;
-            JS_ASSERT(pn3->pn_type == TOK_LC);
+            JS_ASSERT(pn3->isKind(TOK_LC));
             if (pn3->pn_head) {
                 rv2 = HasFinalReturn(pn3->last());
                 if (rv2 == ENDS_IN_OTHER && pn2->pn_next)
                     /* Falling through to next case or default. */;
                 else
                     rv &= rv2;
             }
         }
@@ -1326,29 +1326,29 @@ HasFinalReturn(JSParseNode *pn)
             rv = HasFinalReturn(pn->pn_kid3);
             if (rv == ENDS_IN_RETURN)
                 return rv;
         }
 
         /* Else check the try block and any and all catch statements. */
         rv = HasFinalReturn(pn->pn_kid1);
         if (pn->pn_kid2) {
-            JS_ASSERT(pn->pn_kid2->pn_arity == PN_LIST);
+            JS_ASSERT(pn->pn_kid2->isArity(PN_LIST));
             for (pn2 = pn->pn_kid2->pn_head; pn2; pn2 = pn2->pn_next)
                 rv &= HasFinalReturn(pn2);
         }
         return rv;
 
       case TOK_CATCH:
         /* Check this catch block's body. */
         return HasFinalReturn(pn->pn_kid3);
 
       case TOK_LET:
         /* Non-binary let statements are let declarations. */
-        if (pn->pn_arity != PN_BINARY)
+        if (!pn->isArity(PN_BINARY))
             return ENDS_IN_OTHER;
         return HasFinalReturn(pn->pn_right);
 
       default:
         return ENDS_IN_OTHER;
     }
 }
 
@@ -1377,17 +1377,17 @@ CheckFinalReturn(JSContext *cx, JSTreeCo
 
 /*
  * Check that it is permitted to assign to lhs.  Strict mode code may not
  * assign to 'eval' or 'arguments'.
  */
 bool
 CheckStrictAssignment(JSContext *cx, JSTreeContext *tc, JSParseNode *lhs)
 {
-    if (tc->needStrictChecks() && lhs->pn_type == TOK_NAME) {
+    if (tc->needStrictChecks() && lhs->isKind(TOK_NAME)) {
         JSAtom *atom = lhs->pn_atom;
         JSAtomState *atomState = &cx->runtime->atomState;
         if (atom == atomState->evalAtom || atom == atomState->argumentsAtom) {
             JSAutoByteString name;
             if (!js_AtomToPrintableString(cx, atom, &name) ||
                 !ReportStrictModeError(cx, TS(tc->parser), tc, lhs, JSMSG_DEPRECATED_ASSIGN,
                                        name.ptr())) {
                 return false;
@@ -1517,18 +1517,18 @@ Parser::functionBody()
                 pn = NULL;
             } else {
                 if (tc->flags & TCF_FUN_IS_GENERATOR) {
                     ReportBadReturn(context, tc, pn, JSREPORT_ERROR,
                                     JSMSG_BAD_GENERATOR_RETURN,
                                     JSMSG_BAD_ANON_GENERATOR_RETURN);
                     pn = NULL;
                 } else {
-                    pn->pn_type = TOK_RETURN;
-                    pn->pn_op = JSOP_RETURN;
+                    pn->setKind(TOK_RETURN);
+                    pn->setOp(JSOP_RETURN);
                     pn->pn_pos.end = pn->pn_kid->pn_pos.end;
                 }
             }
         }
     }
 #else
     pn = statements();
 #endif
@@ -1551,28 +1551,28 @@ Parser::functionBody()
 /* Create a placeholder JSDefinition node for |atom|. */
 static JSDefinition *
 MakePlaceholder(JSParseNode *pn, JSTreeContext *tc)
 {
     JSDefinition *dn = (JSDefinition *) NameNode::create(pn->pn_atom, tc);
     if (!dn)
         return NULL;
 
-    dn->pn_type = TOK_NAME;
-    dn->pn_op = JSOP_NOP;
-    dn->pn_defn = true;
+    dn->setKind(TOK_NAME);
+    dn->setOp(JSOP_NOP);
+    dn->setDefn(true);
     dn->pn_dflags |= PND_PLACEHOLDER;
     return dn;
 }
 
 static bool
 Define(JSParseNode *pn, JSAtom *atom, JSTreeContext *tc, bool let = false)
 {
-    JS_ASSERT(!pn->pn_used);
-    JS_ASSERT_IF(pn->pn_defn, pn->isPlaceholder());
+    JS_ASSERT(!pn->isUsed());
+    JS_ASSERT_IF(pn->isDefn(), pn->isPlaceholder());
 
     bool foundLexdep = false;
     JSDefinition *dn = NULL;
 
     if (let)
         dn = tc->decls.lookupFirst(atom);
 
     if (!dn) {
@@ -1581,17 +1581,17 @@ Define(JSParseNode *pn, JSAtom *atom, JS
     }
 
     if (dn && dn != pn) {
         JSParseNode **pnup = &dn->dn_uses;
         JSParseNode *pnu;
         uintN start = let ? pn->pn_blockid : tc->bodyid;
 
         while ((pnu = *pnup) != NULL && pnu->pn_blockid >= start) {
-            JS_ASSERT(pnu->pn_used);
+            JS_ASSERT(pnu->isUsed());
             pnu->pn_lexdef = (JSDefinition *) pn;
             pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
             pnup = &pnu->pn_link;
         }
 
         if (pnu != dn->dn_uses) {
             *pnup = pn->dn_uses;
             pn->dn_uses = dn->dn_uses;
@@ -1601,76 +1601,77 @@ Define(JSParseNode *pn, JSAtom *atom, JS
                 tc->lexdeps->remove(atom);
         }
     }
 
     JSDefinition *toAdd = (JSDefinition *) pn;
     bool ok = let ? tc->decls.addShadow(atom, toAdd) : tc->decls.addUnique(atom, toAdd);
     if (!ok)
         return false;
-    pn->pn_defn = true;
+    pn->setDefn(true);
     pn->pn_dflags &= ~PND_PLACEHOLDER;
     if (!tc->parent)
         pn->pn_dflags |= PND_TOPLEVEL;
     return true;
 }
 
 static void
 LinkUseToDef(JSParseNode *pn, JSDefinition *dn, JSTreeContext *tc)
 {
-    JS_ASSERT(!pn->pn_used);
-    JS_ASSERT(!pn->pn_defn);
+    JS_ASSERT(!pn->isUsed());
+    JS_ASSERT(!pn->isDefn());
     JS_ASSERT(pn != dn->dn_uses);
     pn->pn_link = dn->dn_uses;
     dn->dn_uses = pn;
     dn->pn_dflags |= pn->pn_dflags & PND_USE2DEF_FLAGS;
-    pn->pn_used = true;
+    pn->setUsed(true);
     pn->pn_lexdef = dn;
 }
 
 static void
 ForgetUse(JSParseNode *pn)
 {
-    if (!pn->pn_used) {
-        JS_ASSERT(!pn->pn_defn);
+    if (!pn->isUsed()) {
+        JS_ASSERT(!pn->isDefn());
         return;
     }
 
     JSParseNode **pnup = &pn->lexdef()->dn_uses;
     JSParseNode *pnu;
     while ((pnu = *pnup) != pn)
         pnup = &pnu->pn_link;
     *pnup = pn->pn_link;
-    pn->pn_used = false;
+    pn->setUsed(false);
 }
 
 static JSParseNode *
 MakeAssignment(JSParseNode *pn, JSParseNode *rhs, JSTreeContext *tc)
 {
     JSParseNode *lhs = NewOrRecycledNode(tc);
     if (!lhs)
         return NULL;
     *lhs = *pn;
 
-    if (pn->pn_used) {
+    if (pn->isUsed()) {
         JSDefinition *dn = pn->pn_lexdef;
         JSParseNode **pnup = &dn->dn_uses;
 
         while (*pnup != pn)
             pnup = &(*pnup)->pn_link;
         *pnup = lhs;
         lhs->pn_link = pn->pn_link;
         pn->pn_link = NULL;
     }
 
-    pn->pn_type = TOK_ASSIGN;
-    pn->pn_op = JSOP_NOP;
-    pn->pn_arity = PN_BINARY;
-    pn->pn_parens = false;
-    pn->pn_used = pn->pn_defn = false;
+    pn->setKind(TOK_ASSIGN);
+    pn->setOp(JSOP_NOP);
+    pn->setArity(PN_BINARY);
+    pn->setInParens(false);
+    pn->setUsed(false);
+    pn->setDefn(false);
     pn->pn_left = lhs;
     pn->pn_right = rhs;
     return lhs;
 }
 
 static JSParseNode *
 MakeDefIntoUse(JSDefinition *dn, JSParseNode *pn, JSAtom *atom, JSTreeContext *tc)
 {
@@ -1684,41 +1685,41 @@ MakeDefIntoUse(JSDefinition *dn, JSParse
         if (rhs) {
             JSParseNode *lhs = MakeAssignment(dn, rhs, tc);
             if (!lhs)
                 return NULL;
             //pn->dn_uses = lhs;
             dn = (JSDefinition *) lhs;
         }
 
-        dn->pn_op = (js_CodeSpec[dn->pn_op].format & JOF_SET) ? JSOP_SETNAME : JSOP_NAME;
+        dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETNAME : JSOP_NAME);
     } else if (dn->kind() == JSDefinition::FUNCTION) {
-        JS_ASSERT(dn->pn_op == JSOP_NOP);
+        JS_ASSERT(dn->isOp(JSOP_NOP));
         PrepareNodeForMutation(dn, tc);
-        dn->pn_type = TOK_NAME;
-        dn->pn_arity = PN_NAME;
+        dn->setKind(TOK_NAME);
+        dn->setArity(PN_NAME);
         dn->pn_atom = atom;
     }
 
     /* Now make dn no longer a definition, rather a use of pn. */
-    JS_ASSERT(dn->pn_type == TOK_NAME);
-    JS_ASSERT(dn->pn_arity == PN_NAME);
+    JS_ASSERT(dn->isKind(TOK_NAME));
+    JS_ASSERT(dn->isArity(PN_NAME));
     JS_ASSERT(dn->pn_atom == atom);
 
     for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
-        JS_ASSERT(pnu->pn_used);
-        JS_ASSERT(!pnu->pn_defn);
+        JS_ASSERT(pnu->isUsed());
+        JS_ASSERT(!pnu->isDefn());
         pnu->pn_lexdef = (JSDefinition *) pn;
         pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
     }
     pn->pn_dflags |= dn->pn_dflags & PND_USE2DEF_FLAGS;
     pn->dn_uses = dn;
 
-    dn->pn_defn = false;
-    dn->pn_used = true;
+    dn->setDefn(false);
+    dn->setUsed(true);
     dn->pn_lexdef = (JSDefinition *) pn;
     dn->pn_cookie.makeFree();
     dn->pn_dflags &= ~PND_BOUND;
     return dn;
 }
 
 static bool
 DefineArg(JSParseNode *pn, JSAtom *atom, uintN i, JSTreeContext *tc)
@@ -1732,36 +1733,36 @@ DefineArg(JSParseNode *pn, JSAtom *atom,
     /*
      * Make an argument definition node, distinguished by being in tc->decls
      * but having TOK_NAME type and JSOP_NOP op. Insert it in a TOK_ARGSBODY
      * list node returned via pn->pn_body.
      */
     argpn = NameNode::create(atom, tc);
     if (!argpn)
         return false;
-    JS_ASSERT(PN_TYPE(argpn) == TOK_NAME && PN_OP(argpn) == JSOP_NOP);
+    JS_ASSERT(argpn->isKind(TOK_NAME) && argpn->isOp(JSOP_NOP));
 
     /* Arguments are initialized by definition. */
     argpn->pn_dflags |= PND_INITIALIZED;
     if (!Define(argpn, atom, tc))
         return false;
 
     argsbody = pn->pn_body;
     if (!argsbody) {
         argsbody = ListNode::create(tc);
         if (!argsbody)
             return false;
-        argsbody->pn_type = TOK_ARGSBODY;
-        argsbody->pn_op = JSOP_NOP;
+        argsbody->setKind(TOK_ARGSBODY);
+        argsbody->setOp(JSOP_NOP);
         argsbody->makeEmpty();
         pn->pn_body = argsbody;
     }
     argsbody->append(argpn);
 
-    argpn->pn_op = JSOP_GETARG;
+    argpn->setOp(JSOP_GETARG);
     argpn->pn_cookie.set(tc->staticLevel, i);
     argpn->pn_dflags |= PND_BOUND;
     return true;
 }
 
 /*
  * Compile a JS function body, which might appear as the value of an event
  * handler attribute in an HTML <INPUT> tag.
@@ -1833,17 +1834,17 @@ Compiler::compileFunctionBody(JSContext 
             pn = NULL;
         } else if (!js_FoldConstants(cx, pn, &funcg)) {
             /* js_FoldConstants reported the error already. */
             pn = NULL;
         } else if (!parser.analyzeFunctions(&funcg)) {
             pn = NULL;
         } else {
             if (fn->pn_body) {
-                JS_ASSERT(PN_TYPE(fn->pn_body) == TOK_ARGSBODY);
+                JS_ASSERT(fn->pn_body->isKind(TOK_ARGSBODY));
                 fn->pn_body->append(pn);
                 fn->pn_body->pn_pos = pn->pn_pos;
                 pn = fn->pn_body;
             }
 
             if (!js_EmitFunctionScript(cx, &funcg, pn))
                 pn = NULL;
         }
@@ -1931,17 +1932,17 @@ BindDestructuringArg(JSContext *cx, Bind
      *
      * Thus a destructuring formal parameter binds an ARG (as in arguments[i]
      * element) with a null atom name for the object or array passed in to be
      * destructured, and zero or more VARs (as in named local variables) for
      * the destructured-to identifiers in the property value positions within
      * the object or array destructuring pattern, and all ARGs for the formal
      * parameter list bound as locals before any VAR for a destructured name.
      */
-    pn->pn_op = JSOP_SETLOCAL;
+    pn->setOp(JSOP_SETLOCAL);
     pn->pn_dflags |= PND_BOUND;
 
     return Define(pn, atom, tc);
 }
 #endif /* JS_HAS_DESTRUCTURING */
 
 JSFunction *
 Parser::newFunction(JSTreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind)
@@ -2030,17 +2031,17 @@ Parser::analyzeFunctions(JSTreeContext *
  */
 static uintN
 FindFunArgs(JSFunctionBox *funbox, int level, JSFunctionBoxQueue *queue)
 {
     uintN allskipmin = UpvarCookie::FREE_LEVEL;
 
     do {
         JSParseNode *fn = funbox->node;
-        JS_ASSERT(fn->pn_arity == PN_FUNC);
+        JS_ASSERT(fn->isArity(PN_FUNC));
         JSFunction *fun = funbox->function();
         int fnlevel = level;
 
         /*
          * An eval can leak funbox, functions along its ancestor line, and its
          * immediate kids. Since FindFunArgs uses DFS and the parser propagates
          * TCF_FUN_HEAVYWEIGHT bottom up, funbox's ancestor function nodes have
          * already been marked as funargs by this point. Therefore we have to
@@ -2062,17 +2063,17 @@ FindFunArgs(JSFunctionBox *funbox, int l
         /*
          * Compute in skipmin the least distance from fun's static level up to
          * an upvar, whether used directly by fun, or indirectly by a function
          * nested in fun.
          */
         uintN skipmin = UpvarCookie::FREE_LEVEL;
         JSParseNode *pn = fn->pn_body;
 
-        if (pn->pn_type == TOK_UPVARS) {
+        if (pn->isKind(TOK_UPVARS)) {
             AtomDefnMapPtr &upvars = pn->pn_names;
             JS_ASSERT(upvars->count() != 0);
 
             for (AtomDefnRange r = upvars->all(); !r.empty(); r.popFront()) {
                 JSDefinition *defn = r.front().value();
                 JSDefinition *lexdep = defn->resolve();
 
                 if (!lexdep->isFreeVar()) {
@@ -2141,41 +2142,41 @@ Parser::markFunArgs(JSFunctionBox *funbo
     }
 
     FindFunArgs(funbox, -1, &queue);
     while ((funbox = queue.pull()) != NULL) {
         JSParseNode *fn = funbox->node;
         JS_ASSERT(fn->isFunArg());
 
         JSParseNode *pn = fn->pn_body;
-        if (pn->pn_type == TOK_UPVARS) {
+        if (pn->isKind(TOK_UPVARS)) {
             AtomDefnMapPtr upvars = pn->pn_names;
             JS_ASSERT(!upvars->empty());
 
             for (AtomDefnRange r = upvars->all(); !r.empty(); r.popFront()) {
                 JSDefinition *defn = r.front().value();
                 JSDefinition *lexdep = defn->resolve();
 
                 if (!lexdep->isFreeVar() &&
                     !lexdep->isFunArg() &&
                     (lexdep->kind() == JSDefinition::FUNCTION ||
-                     PN_OP(lexdep) == JSOP_CALLEE)) {
+                     lexdep->isOp(JSOP_CALLEE))) {
                     /*
                      * Mark this formerly-Algol-like function as an escaping
                      * function (i.e., as a funarg), because it is used from
                      * another funarg.
                      *
                      * Progress is guaranteed because we set the funarg flag
                      * here, which suppresses revisiting this function (thanks
                      * to the !lexdep->isFunArg() test just above).
                      */
                     lexdep->setFunArg();
 
                     JSFunctionBox *afunbox;
-                    if (PN_OP(lexdep) == JSOP_CALLEE) {
+                    if (lexdep->isOp(JSOP_CALLEE)) {
                         /*
                          * A named function expression will not appear to be a
                          * funarg if it is immediately applied. However, if its
                          * name is used in an escaping function nested within
                          * it, then it must become flagged as a funarg again.
                          * See bug 545980.
                          */
                         afunbox = funbox;
@@ -2206,17 +2207,17 @@ Parser::markFunArgs(JSFunctionBox *funbo
     return true;
 }
 
 static uint32
 MinBlockId(JSParseNode *fn, uint32 id)
 {
     if (fn->pn_blockid < id)
         return false;
-    if (fn->pn_defn) {
+    if (fn->isDefn()) {
         for (JSParseNode *pn = fn->dn_uses; pn; pn = pn->pn_link) {
             if (pn->pn_blockid < id)
                 return false;
         }
     }
     return true;
 }
 
@@ -2385,18 +2386,18 @@ FlagHeavyweights(JSDefinition *dn, JSFun
 }
 
 static bool
 DeoptimizeUsesWithin(JSDefinition *dn, const TokenPos &pos)
 {
     uintN ndeoptimized = 0;
 
     for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
-        JS_ASSERT(pnu->pn_used);
-        JS_ASSERT(!pnu->pn_defn);
+        JS_ASSERT(pnu->isUsed());
+        JS_ASSERT(!pnu->isDefn());
         if (pnu->pn_pos.begin >= pos.begin && pnu->pn_pos.end <= pos.end) {
             pnu->pn_dflags |= PND_DEOPTIMIZED;
             ++ndeoptimized;
         }
     }
 
     return ndeoptimized != 0;
 }
@@ -2413,29 +2414,29 @@ ConsiderUnbranding(JSFunctionBox *funbox
      * slot-based shape if this function smells like a constructor and too many
      * of its methods are *not* joinable null closures (i.e., they have one or
      * more upvars fetched via the display).
      */
     bool returnsExpr = !!(funbox->tcflags & TCF_RETURN_EXPR);
 #if JS_HAS_EXPR_CLOSURES
     {
         JSParseNode *pn2 = funbox->node->pn_body;
-        if (PN_TYPE(pn2) == TOK_UPVARS)
+        if (pn2->isKind(TOK_UPVARS))
             pn2 = pn2->pn_tree;
-        if (PN_TYPE(pn2) == TOK_ARGSBODY)
+        if (pn2->isKind(TOK_ARGSBODY))
             pn2 = pn2->last();
-        if (PN_TYPE(pn2) != TOK_LC)
+        if (!pn2->isKind(TOK_LC))
             returnsExpr = true;
     }
 #endif
     if (!returnsExpr) {
         uintN methodSets = 0, slowMethodSets = 0;
 
         for (JSParseNode *method = funbox->methods; method; method = method->pn_link) {
-            JS_ASSERT(PN_OP(method) == JSOP_LAMBDA || PN_OP(method) == JSOP_LAMBDA_FC);
+            JS_ASSERT(method->isOp(JSOP_LAMBDA) || method->isOp(JSOP_LAMBDA_FC));
             ++methodSets;
             if (!method->pn_funbox->joinable())
                 ++slowMethodSets;
         }
 
         if (funbox->shouldUnbrand(methodSets, slowMethodSets))
             funbox->tcflags |= TCF_FUN_UNBRAND_THIS;
     }
@@ -2460,17 +2461,17 @@ Parser::setFunctionKinds(JSFunctionBox *
         if (funbox->tcflags & TCF_FUN_HEAVYWEIGHT) {
             /* nothing to do */
         } else if (funbox->inAnyDynamicScope()) {
             JS_ASSERT(!fun->isNullClosure());
         } else {
             bool hasUpvars = false;
             bool canFlatten = true;
 
-            if (pn->pn_type == TOK_UPVARS) {
+            if (pn->isKind(TOK_UPVARS)) {
                 AtomDefnMapPtr upvars = pn->pn_names;
                 JS_ASSERT(!upvars->empty());
 
                 /*
                  * For each lexical dependency from this closure to an outer
                  * binding, analyze whether it is safe to copy the binding's
                  * value into a flat closure slot when the closure is formed.
                  */
@@ -2494,34 +2495,34 @@ Parser::setFunctionKinds(JSFunctionBox *
                 }
             }
 
             if (!hasUpvars) {
                 /* No lexical dependencies => null closure, for best performance. */
                 fun->setKind(JSFUN_NULL_CLOSURE);
             } else if (canFlatten) {
                 fun->setKind(JSFUN_FLAT_CLOSURE);
-                switch (PN_OP(fn)) {
-                case JSOP_DEFFUN:
-                    fn->pn_op = JSOP_DEFFUN_FC;
+                switch (fn->getOp()) {
+                  case JSOP_DEFFUN:
+                    fn->setOp(JSOP_DEFFUN_FC);
                     break;
-                case JSOP_DEFLOCALFUN:
-                    fn->pn_op = JSOP_DEFLOCALFUN_FC;
+                  case JSOP_DEFLOCALFUN:
+                    fn->setOp(JSOP_DEFLOCALFUN_FC);
                     break;
-                case JSOP_LAMBDA:
-                    fn->pn_op = JSOP_LAMBDA_FC;
+                  case JSOP_LAMBDA:
+                    fn->setOp(JSOP_LAMBDA_FC);
                     break;
-                default:
+                  default:
                     /* js_EmitTree's case TOK_FUNCTION: will select op. */
-                    JS_ASSERT(PN_OP(fn) == JSOP_NOP);
+                    JS_ASSERT(fn->isOp(JSOP_NOP));
                 }
             }
         }
 
-        if (fun->kind() == JSFUN_INTERPRETED && pn->pn_type == TOK_UPVARS) {
+        if (fun->kind() == JSFUN_INTERPRETED && pn->isKind(TOK_UPVARS)) {
             /*
              * One or more upvars cannot be safely snapshot into a flat
              * closure's non-reserved slot (see JSOP_GETFCSLOT), so we loop
              * again over all upvars, and for each non-free upvar, ensure that
              * its containing function has been flagged as heavyweight.
              *
              * The emitter must see TCF_FUN_HEAVYWEIGHT accurately before
              * generating any code for a tree of nested functions.
@@ -2642,17 +2643,17 @@ LeaveFunction(JSParseNode *fn, JSTreeCon
         int foundCallee = 0;
 
         for (AtomDefnRange r = funtc->lexdeps->all(); !r.empty(); r.popFront()) {
             JSAtom *atom = r.front().key();
             JSDefinition *dn = r.front().value();
             JS_ASSERT(dn->isPlaceholder());
 
             if (atom == funAtom && kind == Expression) {
-                dn->pn_op = JSOP_CALLEE;
+                dn->setOp(JSOP_CALLEE);
                 dn->pn_cookie.set(funtc->staticLevel, UpvarCookie::CALLEE_SLOT);
                 dn->pn_dflags |= PND_BOUND;
 
                 /*
                  * If this named function expression uses its own name other
                  * than to call itself, flag this function specially.
                  */
                 if (dn->isFunArg())
@@ -2747,33 +2748,33 @@ LeaveFunction(JSParseNode *fn, JSTreeCon
                  * Make dn be a use that redirects to outer_dn, because we
                  * can't replace dn with outer_dn in all the pn_namesets in
                  * the AST where it may be. Instead we make it forward to
                  * outer_dn. See JSDefinition::resolve.
                  */
                 *pnup = outer_dn->dn_uses;
                 outer_dn->dn_uses = dn;
                 outer_dn->pn_dflags |= dn->pn_dflags & ~PND_PLACEHOLDER;
-                dn->pn_defn = false;
-                dn->pn_used = true;
+                dn->setDefn(false);
+                dn->setUsed(true);
                 dn->pn_lexdef = outer_dn;
             }
 
             /* Mark the outer dn as escaping. */
             outer_dn->pn_dflags |= PND_CLOSED;
         }
 
         if (funtc->lexdeps->count() - foundCallee != 0) {
             JSParseNode *body = fn->pn_body;
 
             fn->pn_body = NameSetNode::create(tc);
             if (!fn->pn_body)
                 return false;
 
-            fn->pn_body->pn_type = TOK_UPVARS;
+            fn->pn_body->setKind(TOK_UPVARS);
             fn->pn_body->pn_pos = body->pn_pos;
             if (foundCallee)
                 funtc->lexdeps->remove(funAtom);
             /* Transfer ownership of the lexdep map to the parse node. */
             fn->pn_body->pn_names = funtc->lexdeps;
             funtc->lexdeps.clearMap();
             fn->pn_body->pn_tree = body;
         } else {
@@ -2866,30 +2867,30 @@ Parser::functionArguments(JSTreeContext 
                 /*
                  * Synthesize a destructuring assignment from the single
                  * anonymous positional parameter into the destructuring
                  * left-hand-side expression and accumulate it in list.
                  */
                 JSParseNode *rhs = NameNode::create(context->runtime->atomState.emptyAtom, &funtc);
                 if (!rhs)
                     return false;
-                rhs->pn_type = TOK_NAME;
-                rhs->pn_op = JSOP_GETARG;
+                rhs->setKind(TOK_NAME);
+                rhs->setOp(JSOP_GETARG);
                 rhs->pn_cookie.set(funtc.staticLevel, slot);
                 rhs->pn_dflags |= PND_BOUND;
 
                 JSParseNode *item =
                     JSParseNode::newBinaryOrAppend(TOK_ASSIGN, JSOP_NOP, lhs, rhs, &funtc);
                 if (!item)
                     return false;
                 if (!list) {
                     list = ListNode::create(&funtc);
                     if (!list)
                         return false;
-                    list->pn_type = TOK_VAR;
+                    list->setKind(TOK_VAR);
                     list->makeEmpty();
                     *listp = list;
                 }
                 list->append(item);
                 break;
               }
 #endif /* JS_HAS_DESTRUCTURING */
 
@@ -2981,18 +2982,18 @@ Parser::functionDef(JSAtom *funAtom, Fun
     /*
      * Record names for function statements in tc->decls so we know when to
      * avoid optimizing variable references that might name a function.
      */
     if (kind == Statement) {
         if (JSDefinition *dn = tc->decls.lookupFirst(funAtom)) {
             JSDefinition::Kind dn_kind = dn->kind();
 
-            JS_ASSERT(!dn->pn_used);
-            JS_ASSERT(dn->pn_defn);
+            JS_ASSERT(!dn->isUsed());
+            JS_ASSERT(dn->isDefn());
 
             if (context->hasStrictOption() || dn_kind == JSDefinition::CONST) {
                 JSAutoByteString name;
                 if (!js_AtomToPrintableString(context, funAtom, &name) ||
                     !reportErrorNumber(NULL,
                                        (dn_kind != JSDefinition::CONST)
                                        ? JSREPORT_WARNING | JSREPORT_STRICT
                                        : JSREPORT_ERROR,
@@ -3000,33 +3001,33 @@ Parser::functionDef(JSAtom *funAtom, Fun
                                        JSDefinition::kindString(dn_kind),
                                        name.ptr())) {
                     return NULL;
                 }
             }
 
             if (bodyLevel) {
                 tc->decls.updateFirst(funAtom, (JSDefinition *) pn);
-                pn->pn_defn = true;
+                pn->setDefn(true);
                 pn->dn_uses = dn; /* dn->dn_uses is now pn_link */
 
                 if (!MakeDefIntoUse(dn, pn, funAtom, tc))
                     return NULL;
             }
         } else if (bodyLevel) {
             /*
              * If this function was used before it was defined, claim the
              * pre-created definition node for this function that primaryExpr
              * put in tc->lexdeps on first forward reference, and recycle pn.
              */
 
             if (JSDefinition *fn = tc->lexdeps.lookupDefn(funAtom)) {
-                JS_ASSERT(fn->pn_defn);
-                fn->pn_type = TOK_FUNCTION;
-                fn->pn_arity = PN_FUNC;
+                JS_ASSERT(fn->isDefn());
+                fn->setKind(TOK_FUNCTION);
+                fn->setArity(PN_FUNC);
                 fn->pn_pos.begin = pn->pn_pos.begin;
 
                 /*
                  * Set fn->pn_pos.end too, in case of error before we parse the
                  * closing brace.  See bug 640075.
                  */
                 fn->pn_pos.end = pn->pn_pos.end;
 
@@ -3106,17 +3107,17 @@ Parser::functionDef(JSAtom *funAtom, Fun
      * we can't bind vars induced by formal parameter destructuring until after
      * Parser::functionArguments has returned.
      */
     if (prelude) {
         AtomDeclsIter iter(&funtc.decls);
 
         while (JSDefinition *apn = iter()) {
             /* Filter based on pn_op -- see BindDestructuringArg, above. */
-            if (apn->pn_op != JSOP_SETLOCAL)
+            if (!apn->isOp(JSOP_SETLOCAL))
                 continue;
 
             if (!BindLocalVariable(context, &funtc, apn, VARIABLE))
                 return NULL;
         }
     }
 #endif
 
@@ -3180,34 +3181,34 @@ Parser::functionDef(JSAtom *funAtom, Fun
 #if JS_HAS_DESTRUCTURING
     /*
      * If there were destructuring formal parameters, prepend the initializing
      * comma expression that we synthesized to body. If the body is a return
      * node, we must make a special TOK_SEQ node, to prepend the destructuring
      * code without bracing the decompilation of the function body.
      */
     if (prelude) {
-        if (body->pn_arity != PN_LIST) {
+        if (!body->isArity(PN_LIST)) {
             JSParseNode *block;
 
             block = ListNode::create(outertc);
             if (!block)
                 return NULL;
-            block->pn_type = TOK_SEQ;
+            block->setKind(TOK_SEQ);
             block->pn_pos = body->pn_pos;
             block->initList(body);
 
             body = block;
         }
 
         JSParseNode *item = UnaryNode::create(outertc);
         if (!item)
             return NULL;
 
-        item->pn_type = TOK_SEMI;
+        item->setKind(TOK_SEMI);
         item->pn_pos.begin = item->pn_pos.end = body->pn_pos.begin;
         item->pn_kid = prelude;
         item->pn_next = body->pn_head;
         body->pn_head = item;
         if (body->pn_tail == &body->pn_head)
             body->pn_tail = &item->pn_next;
         ++body->pn_count;
         body->pn_xflags |= PNX_DESTRUCT;
@@ -3249,17 +3250,17 @@ Parser::functionDef(JSAtom *funAtom, Fun
             op = JSOP_DEFFUN;
             outertc->noteMightAliasLocals();
         }
     }
 
     funbox->kids = funtc.functionList;
 
     pn->pn_funbox = funbox;
-    pn->pn_op = op;
+    pn->setOp(op);
     if (pn->pn_body) {
         pn->pn_body->append(body);
         pn->pn_body->pn_pos = body->pn_pos;
     } else {
         pn->pn_body = body;
     }
 
     if (!outertc->inFunction() && bodyLevel && kind == Statement && outertc->compiling()) {
@@ -3393,17 +3394,17 @@ Parser::statements()
     JSParseNode *pn, *pn2, *saveBlock;
     TokenKind tt;
 
     JS_CHECK_RECURSION(context, return NULL);
 
     pn = ListNode::create(tc);
     if (!pn)
         return NULL;
-    pn->pn_type = TOK_LC;
+    pn->setKind(TOK_LC);
     pn->makeEmpty();
     pn->pn_blockid = tc->blockid();
     saveBlock = tc->blockNode;
     tc->blockNode = pn;
 
     bool inDirectivePrologue = tc->atBodyLevel();
     tokenStream.setOctalCharacterEscape(false);
     for (;;) {
@@ -3421,17 +3422,17 @@ Parser::statements()
             if (tokenStream.isEOF())
                 tokenStream.setUnexpectedEOF();
             return NULL;
         }
 
         if (inDirectivePrologue && !recognizeDirectivePrologue(pn2, &inDirectivePrologue))
             return NULL;
 
-        if (pn2->pn_type == TOK_FUNCTION) {
+        if (pn2->isKind(TOK_FUNCTION)) {
             /*
              * PNX_FUNCDEFS notifies the emitter that the block contains body-
              * level function definitions that should be processed before the
              * rest of nodes.
              *
              * TCF_HAS_FUNCTION_STMT is for the TOK_LC case in Statement. It
              * is relevant only for function definitions not at body-level,
              * which we call function statements.
@@ -3467,19 +3468,19 @@ Parser::condition()
 
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
     pn = parenExpr();
     if (!pn)
         return NULL;
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
 
     /* Check for (a = b) and warn about possible (a == b) mistype. */
-    if (pn->pn_type == TOK_ASSIGN &&
-        pn->pn_op == JSOP_NOP &&
-        !pn->pn_parens &&
+    if (pn->isKind(TOK_ASSIGN) &&
+        pn->isOp(JSOP_NOP) &&
+        !pn->isInParens() &&
         !reportErrorNumber(NULL, JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_EQUAL_AS_ASSIGN, "")) {
         return NULL;
     }
     return pn;
 }
 
 static JSBool
 MatchLabel(JSContext *cx, TokenStream *ts, JSParseNode *pn)
@@ -3555,17 +3556,17 @@ BindLet(JSContext *cx, BindData *data, J
 
     /*
      * Assign block-local index to pn->pn_cookie right away, encoding it as an
      * upvar cookie whose skip tells the current static level. The emitter will
      * adjust the node's slot based on its stack depth model -- and, for global
      * and eval code, Compiler::compileScript will adjust the slot again to
      * include script->nfixed.
      */
-    pn->pn_op = JSOP_GETLOCAL;
+    pn->setOp(JSOP_GETLOCAL);
     pn->pn_cookie.set(tc->staticLevel, uint16(n));
     pn->pn_dflags |= PND_LET | PND_BOUND;
 
     /*
      * Define the let binding's property before storing pn in the the binding's
      * slot indexed by n off the class-reserved slot base.
      */
     const Shape *shape = blockObj->defineBlockVariable(cx, ATOM_TO_JSID(atom), n);
@@ -3645,17 +3646,17 @@ DefineGlobal(JSParseNode *pn, JSCodeGene
     if (!p) {
         JSContext *cx = cg->parser->context;
 
         JSObject *holder;
         JSProperty *prop;
         if (!globalObj->lookupProperty(cx, ATOM_TO_JSID(atom), &holder, &prop))
             return false;
 
-        JSFunctionBox *funbox = (pn->pn_type == TOK_FUNCTION) ? pn->pn_funbox : NULL;
+        JSFunctionBox *funbox = pn->isKind(TOK_FUNCTION) ? pn->pn_funbox : NULL;
 
         GlobalScope::GlobalDef def;
         if (prop) {
             /*
              * A few cases where we don't bother aggressively caching:
              *   1) Function value changes.
              *   2) Configurable properties.
              *   3) Properties without slots, or with getters/setters.
@@ -3692,32 +3693,32 @@ DefineGlobal(JSParseNode *pn, JSCodeGene
          * example:
          *   var c = []
          *   function c() { }
          *
          * This rewrite is allowed because the function will be statically
          * hoisted to the top of the script, and the |c = []| will just
          * overwrite it at runtime.
          */
-        if (pn->pn_type == TOK_FUNCTION) {
-            JS_ASSERT(pn->pn_arity = PN_FUNC);
+        if (pn->isKind(TOK_FUNCTION)) {
+            JS_ASSERT(pn->isArity(PN_FUNC));
             jsatomid index = p.value();
             globalScope->defs[index].funbox = pn->pn_funbox;
         }
     }
 
     pn->pn_dflags |= PND_GVAR;
 
     return true;
 }
 
 static bool
 BindTopLevelVar(JSContext *cx, BindData *data, JSParseNode *pn, JSTreeContext *tc)
 {
-    JS_ASSERT(pn->pn_op == JSOP_NAME);
+    JS_ASSERT(pn->isOp(JSOP_NAME));
     JS_ASSERT(!tc->inFunction());
 
     /* There's no need to optimize bindings if we're not compiling code. */
     if (!tc->compiling())
         return true;
 
     /*
      * Bindings at top level in eval code aren't like bindings at top level in
@@ -3772,17 +3773,17 @@ BindFunctionLocal(JSContext *cx, BindDat
 
     /*
      * Don't create a local variable with the name 'arguments', per ECMA-262.
      * Instead, 'var arguments' always restates that predefined binding of the
      * lexical environment for function activations. Assignments to arguments
      * must be handled specially -- see NoteLValue.
      */
     if (name == cx->runtime->atomState.argumentsAtom) {
-        pn->pn_op = JSOP_ARGUMENTS;
+        pn->setOp(JSOP_ARGUMENTS);
         pn->pn_dflags |= PND_BOUND;
         return true;
     }
 
     BindingKind kind = tc->bindings.lookup(cx, name, NULL);
     if (kind == NONE) {
         /*
          * Property not found in current variable scope: we have not seen this
@@ -3790,17 +3791,17 @@ BindFunctionLocal(JSContext *cx, BindDat
          * declared in a with statement body are handled at runtime, by script
          * prolog JSOP_DEFVAR opcodes generated for global and heavyweight-
          * function-local vars.
          */
         kind = (data->op == JSOP_DEFCONST) ? CONSTANT : VARIABLE;
 
         if (!BindLocalVariable(cx, tc, pn, kind))
             return false;
-        pn->pn_op = JSOP_GETLOCAL;
+        pn->setOp(JSOP_GETLOCAL);
         return true;
     }
 
     if (kind == ARGUMENT) {
         JS_ASSERT(tc->inFunction());
         JS_ASSERT(!mdl.empty() && mdl.front()->kind() == JSDefinition::ARG);
     } else {
         JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
@@ -3810,17 +3811,17 @@ BindFunctionLocal(JSContext *cx, BindDat
 }
 
 static JSBool
 BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
 {
     JSParseNode *pn = data->pn;
 
     /* Default best op for pn is JSOP_NAME; we'll try to improve below. */
-    pn->pn_op = JSOP_NAME;
+    pn->setOp(JSOP_NAME);
 
     if (!CheckStrictBinding(cx, tc, atom, pn))
         return false;
 
     JSStmtInfo *stmt = js_LexicalLookup(tc, atom, NULL);
 
     if (stmt && stmt->type == STMT_WITH) {
         data->fresh = false;
@@ -3890,28 +3891,28 @@ BindVarOrConst(JSContext *cx, BindData *
          * A case such as let (x = 1) { var x = 2; print(x); } is even harder.
          * There the x definition is hoisted but the x = 2 assignment mutates
          * the block-local binding of x.
          */
         JSDefinition *dn = mdl.front();
 
         data->fresh = false;
 
-        if (!pn->pn_used) {
+        if (!pn->isUsed()) {
             /* Make pnu be a fresh name node that uses dn. */
             JSParseNode *pnu = pn;
 
-            if (pn->pn_defn) {
+            if (pn->isDefn()) {
                 pnu = NameNode::create(atom, tc);
                 if (!pnu)
                     return JS_FALSE;
             }
 
             LinkUseToDef(pnu, dn, tc);
-            pnu->pn_op = JSOP_NAME;
+            pnu->setOp(JSOP_NAME);
         }
 
         /* Find the first non-let binding of this atom. */
         while (dn->kind() == JSDefinition::LET) {
             mdl.popFront();
             if (mdl.empty())
                 break;
             dn = mdl.front();
@@ -3923,69 +3924,69 @@ BindVarOrConst(JSContext *cx, BindData *
             return JS_TRUE;
         }
 
         /*
          * A var or const that is shadowed by one or more let bindings of the
          * same name, but that has not been declared until this point, must be
          * hoisted above the let bindings.
          */
-        if (!pn->pn_defn) {
+        if (!pn->isDefn()) {
             if (tc->lexdeps->lookup(atom)) {
                 tc->lexdeps->remove(atom);
             } else {
                 JSParseNode *pn2 = NameNode::create(atom, tc);
                 if (!pn2)
                     return JS_FALSE;
 
                 /* The token stream may be past the location for pn. */
-                pn2->pn_type = TOK_NAME;
+                pn2->setKind(TOK_NAME);
                 pn2->pn_pos = pn->pn_pos;
                 pn = pn2;
             }
-            pn->pn_op = JSOP_NAME;
+            pn->setOp(JSOP_NAME);
         }
 
         if (!tc->decls.addHoist(atom, (JSDefinition *) pn))
             return JS_FALSE;
-        pn->pn_defn = true;
+        pn->setDefn(true);
         pn->pn_dflags &= ~PND_PLACEHOLDER;
     }
 
     if (data->op == JSOP_DEFCONST)
         pn->pn_dflags |= PND_CONST;
 
     if (tc->inFunction())
         return BindFunctionLocal(cx, data, mdl, tc);
 
     return BindTopLevelVar(cx, data, pn, tc);
 }
 
 static bool
 MakeSetCall(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN msg)
 {
-    JS_ASSERT(pn->pn_arity == PN_LIST);
-    JS_ASSERT(pn->pn_op == JSOP_CALL || pn->pn_op == JSOP_EVAL ||
-              pn->pn_op == JSOP_FUNCALL || pn->pn_op == JSOP_FUNAPPLY);
+    JS_ASSERT(pn->isArity(PN_LIST));
+    JS_ASSERT(pn->isOp(JSOP_CALL) || pn->isOp(JSOP_EVAL) ||
+              pn->isOp(JSOP_FUNCALL) || pn->isOp(JSOP_FUNAPPLY));
     if (!ReportStrictModeError(cx, TS(tc->parser), tc, pn, msg))
         return false;
 
     JSParseNode *pn2 = pn->pn_head;
-    if (pn2->pn_type == TOK_FUNCTION && (pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA)) {
+    if (pn2->isKind(TOK_FUNCTION) && (pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA)) {
         ReportCompileErrorNumber(cx, TS(tc->parser), pn, JSREPORT_ERROR, msg);
         return false;
     }
     pn->pn_xflags |= PNX_SETCALL;
     return true;
 }
 
 static void
 NoteLValue(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN dflag = PND_ASSIGNED)
 {
-    if (pn->pn_used) {
+    if (pn->isUsed()) {
         JSDefinition *dn = pn->pn_lexdef;
 
         /*
          * Save the win of PND_INITIALIZED if we can prove 'var x;' and 'x = y'
          * occur as direct kids of the same block with no forward refs to x.
          */
         if (!(dn->pn_dflags & (PND_INITIALIZED | PND_CONST | PND_PLACEHOLDER)) &&
             dn->isBlockChild() &&
@@ -4030,38 +4031,34 @@ BindDestructuringVar(JSContext *cx, Bind
 {
     JSAtom *atom;
 
     /*
      * Destructuring is a form of assignment, so just as for an initialized
      * simple variable, we must check for assignment to 'arguments' and flag
      * the enclosing function (if any) as heavyweight.
      */
-    JS_ASSERT(pn->pn_type == TOK_NAME);
+    JS_ASSERT(pn->isKind(TOK_NAME));
     atom = pn->pn_atom;
     if (atom == cx->runtime->atomState.argumentsAtom)
         tc->flags |= TCF_FUN_HEAVYWEIGHT;
 
     data->pn = pn;
     if (!data->binder(cx, data, atom, tc))
         return JS_FALSE;
 
     /*
      * Select the appropriate name-setting opcode, respecting eager selection
      * done by the data->binder function.
      */
     if (pn->pn_dflags & PND_BOUND) {
         JS_ASSERT(!(pn->pn_dflags & PND_GVAR));
-        pn->pn_op = (pn->pn_op == JSOP_ARGUMENTS)
-                    ? JSOP_SETNAME
-                    : JSOP_SETLOCAL;
+        pn->setOp(pn->isOp(JSOP_ARGUMENTS) ? JSOP_SETNAME : JSOP_SETLOCAL);
     } else {
-        pn->pn_op = (data->op == JSOP_DEFCONST)
-                    ? JSOP_SETCONST
-                    : JSOP_SETNAME;
+        pn->setOp((data->op == JSOP_DEFCONST) ? JSOP_SETCONST : JSOP_SETNAME);
     }
 
     if (data->op == JSOP_DEFCONST)
         pn->pn_dflags |= PND_CONST;
 
     NoteLValue(cx, pn, tc, PND_INITIALIZED);
     return JS_TRUE;
 }
@@ -4082,41 +4079,41 @@ BindDestructuringVar(JSContext *cx, Bind
  *
  * and pops all three values, setting lval[xval] = rval.  But we cannot select
  * JSOP_ENUMELEM yet, because the LHS may turn out to be an arg or local var,
  * which can be optimized further.  So we select JSOP_SETNAME.
  */
 static JSBool
 BindDestructuringLHS(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
 {
-    switch (pn->pn_type) {
+    switch (pn->getKind()) {
       case TOK_NAME:
         NoteLValue(cx, pn, tc);
         /* FALL THROUGH */
 
       case TOK_DOT:
       case TOK_LB:
         /*
          * We may be called on a name node that has already been specialized,
          * in the very weird and ECMA-262-required "for (var [x] = i in o) ..."
          * case. See bug 558633.
          */
-        if (!(js_CodeSpec[pn->pn_op].format & JOF_SET))
-            pn->pn_op = JSOP_SETNAME;
+        if (!(js_CodeSpec[pn->getOp()].format & JOF_SET))
+            pn->setOp(JSOP_SETNAME);
         break;
 
       case TOK_LP:
         if (!MakeSetCall(cx, pn, tc, JSMSG_BAD_LEFTSIDE_OF_ASS))
             return JS_FALSE;
         break;
 
 #if JS_HAS_XML_SUPPORT
       case TOK_UNARYOP:
-        if (pn->pn_op == JSOP_XMLNAME) {
-            pn->pn_op = JSOP_BINDXMLNAME;
+        if (pn->isOp(JSOP_XMLNAME)) {
+            pn->setOp(JSOP_BINDXMLNAME);
             break;
         }
         /* FALL THROUGH */
 #endif
 
       default:
         ReportCompileErrorNumber(cx, TS(tc->parser), pn,
                                  JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS);
@@ -4166,54 +4163,54 @@ BindDestructuringLHS(JSContext *cx, JSPa
  * either of these functions, you might have to change the other to
  * match.
  */
 static bool
 CheckDestructuring(JSContext *cx, BindData *data, JSParseNode *left, JSTreeContext *tc)
 {
     bool ok;
 
-    if (left->pn_type == TOK_ARRAYCOMP) {
+    if (left->isKind(TOK_ARRAYCOMP)) {
         ReportCompileErrorNumber(cx, TS(tc->parser), left, JSREPORT_ERROR,
                                  JSMSG_ARRAY_COMP_LEFTSIDE);
         return false;
     }
 
-    if (left->pn_type == TOK_RB) {
+    if (left->isKind(TOK_RB)) {
         for (JSParseNode *pn = left->pn_head; pn; pn = pn->pn_next) {
             /* Nullary comma is an elision; binary comma is an expression.*/
-            if (pn->pn_type != TOK_COMMA || pn->pn_arity != PN_NULLARY) {
-                if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC) {
+            if (!pn->isKind(TOK_COMMA) || !pn->isArity(PN_NULLARY)) {
+                if (pn->isKind(TOK_RB) || pn->isKind(TOK_RC)) {
                     ok = CheckDestructuring(cx, data, pn, tc);
                 } else {
                     if (data) {
-                        if (pn->pn_type != TOK_NAME) {
+                        if (!pn->isKind(TOK_NAME)) {
                             ReportCompileErrorNumber(cx, TS(tc->parser), pn, JSREPORT_ERROR,
                                                      JSMSG_NO_VARIABLE_NAME);
                             return false;
                         }
                         ok = BindDestructuringVar(cx, data, pn, tc);
                     } else {
                         ok = BindDestructuringLHS(cx, pn, tc);
                     }
                 }
                 if (!ok)
                     return false;
             }
         }
     } else {
-        JS_ASSERT(left->pn_type == TOK_RC);
+        JS_ASSERT(left->isKind(TOK_RC));
         for (JSParseNode *pair = left->pn_head; pair; pair = pair->pn_next) {
-            JS_ASSERT(pair->pn_type == TOK_COLON);
+            JS_ASSERT(pair->isKind(TOK_COLON));
             JSParseNode *pn = pair->pn_right;
 
-            if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC) {
+            if (pn->isKind(TOK_RB) || pn->isKind(TOK_RC)) {
                 ok = CheckDestructuring(cx, data, pn, tc);
             } else if (data) {
-                if (pn->pn_type != TOK_NAME) {
+                if (!pn->isKind(TOK_NAME)) {
                     ReportCompileErrorNumber(cx, TS(tc->parser), pn, JSREPORT_ERROR,
                                              JSMSG_NO_VARIABLE_NAME);
                     return false;
                 }
                 ok = BindDestructuringVar(cx, data, pn, tc);
             } else {
                 ok = BindDestructuringLHS(cx, pn, tc);
             }
@@ -4269,33 +4266,33 @@ CheckDestructuring(JSContext *cx, BindDa
  * Languages", Brandis and Mössenböck), we could do much better.
  *
  * See CheckDestructuring, immediately above. If you change either of these
  * functions, you might have to change the other to match.
  */
 static void
 UndominateInitializers(JSParseNode *left, const TokenPtr &end, JSTreeContext *tc)
 {
-    if (left->pn_type == TOK_RB) {
+    if (left->isKind(TOK_RB)) {
         for (JSParseNode *pn = left->pn_head; pn; pn = pn->pn_next) {
             /* Nullary comma is an elision; binary comma is an expression.*/
-            if (pn->pn_type != TOK_COMMA || pn->pn_arity != PN_NULLARY) {
-                if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC)
+            if (!pn->isKind(TOK_COMMA) || !pn->isArity(PN_NULLARY)) {
+                if (pn->isKind(TOK_RB) || pn->isKind(TOK_RC))
                     UndominateInitializers(pn, end, tc);
                 else
                     pn->pn_pos.end = end;
             }
         }
     } else {
-        JS_ASSERT(left->pn_type == TOK_RC);
+        JS_ASSERT(left->isKind(TOK_RC));
 
         for (JSParseNode *pair = left->pn_head; pair; pair = pair->pn_next) {
-            JS_ASSERT(pair->pn_type == TOK_COLON);
+            JS_ASSERT(pair->isKind(TOK_COLON));
             JSParseNode *pn = pair->pn_right;
-            if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC)
+            if (pn->isKind(TOK_RB) || pn->isKind(TOK_RC))
                 UndominateInitializers(pn, end, tc);
             else
                 pn->pn_pos.end = end;
         }
     }
 }
 
 JSParseNode *
@@ -4323,25 +4320,25 @@ CloneParseTree(JSParseNode *opn, JSTreeC
 {
     JS_CHECK_RECURSION(tc->parser->context, return NULL);
 
     JSParseNode *pn, *pn2, *opn2;
 
     pn = NewOrRecycledNode(tc);
     if (!pn)
         return NULL;
-    pn->pn_type = opn->pn_type;
+    pn->setKind(opn->getKind());
+    pn->setOp(opn->getOp());
+    pn->setUsed(opn->isUsed());
+    pn->setDefn(opn->isDefn());
+    pn->setArity(opn->getArity());
+    pn->setInParens(opn->isInParens());
     pn->pn_pos = opn->pn_pos;
-    pn->pn_op = opn->pn_op;
-    pn->pn_used = opn->pn_used;
-    pn->pn_defn = opn->pn_defn;
-    pn->pn_arity = opn->pn_arity;
-    pn->pn_parens = opn->pn_parens;
-
-    switch (pn->pn_arity) {
+
+    switch (pn->getArity()) {
 #define NULLCHECK(e)    JS_BEGIN_MACRO if (!(e)) return NULL; JS_END_MACRO
 
       case PN_FUNC:
         NULLCHECK(pn->pn_funbox =
                   tc->parser->newFunctionBox(opn->pn_funbox->object, pn, tc));
         NULLCHECK(pn->pn_body = CloneParseTree(opn->pn_body, tc));
         pn->pn_cookie = opn->pn_cookie;
         pn->pn_dflags = opn->pn_dflags;
@@ -4377,34 +4374,34 @@ CloneParseTree(JSParseNode *opn, JSTreeC
         NULLCHECK(pn->pn_kid = CloneParseTree(opn->pn_kid, tc));
         pn->pn_num = opn->pn_num;
         pn->pn_hidden = opn->pn_hidden;
         break;
 
       case PN_NAME:
         // PN_NAME could mean several arms in pn_u, so copy the whole thing.
         pn->pn_u = opn->pn_u;
-        if (opn->pn_used) {
+        if (opn->isUsed()) {
             /*
              * The old name is a use of its pn_lexdef. Make the clone also be a
              * use of that definition.
              */
             JSDefinition *dn = pn->pn_lexdef;
 
             pn->pn_link = dn->dn_uses;
             dn->dn_uses = pn;
         } else if (opn->pn_expr) {
             NULLCHECK(pn->pn_expr = CloneParseTree(opn->pn_expr, tc));
 
             /*
              * If the old name is a definition, the new one has pn_defn set.
              * Make the old name a use of the new node.
              */
-            if (opn->pn_defn) {
-                opn->pn_defn = false;
+            if (opn->isDefn()) {
+                opn->setDefn(false);
                 LinkUseToDef(opn, (JSDefinition *) pn, tc);
             }
         }
         break;
 
       case PN_NAMESET:
         pn->pn_names = opn->pn_names;
         NULLCHECK(pn->pn_tree = CloneParseTree(opn->pn_tree, tc));
@@ -4424,19 +4421,19 @@ CloneParseTree(JSParseNode *opn, JSTreeC
 
 static JSParseNode *
 ContainsStmt(JSParseNode *pn, TokenKind tt)
 {
     JSParseNode *pn2, *pnt;
 
     if (!pn)
         return NULL;
-    if (PN_TYPE(pn) == tt)
+    if (pn->isKind(tt))
         return pn;
-    switch (pn->pn_arity) {
+    switch (pn->getArity()) {
       case PN_LIST:
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             pnt = ContainsStmt(pn2, tt);
             if (pnt)
                 return pnt;
         }
         break;
       case PN_TERNARY:
@@ -4447,24 +4444,24 @@ ContainsStmt(JSParseNode *pn, TokenKind 
         if (pnt)
             return pnt;
         return ContainsStmt(pn->pn_kid3, tt);
       case PN_BINARY:
         /*
          * Limit recursion if pn is a binary expression, which can't contain a
          * var statement.
          */
-        if (pn->pn_op != JSOP_NOP)
+        if (!pn->isOp(JSOP_NOP))
             return NULL;
         pnt = ContainsStmt(pn->pn_left, tt);
         if (pnt)
             return pnt;
         return ContainsStmt(pn->pn_right, tt);
       case PN_UNARY:
-        if (pn->pn_op != JSOP_NOP)
+        if (!pn->isOp(JSOP_NOP))
             return NULL;
         return ContainsStmt(pn->pn_kid, tt);
       case PN_NAME:
         return ContainsStmt(pn->maybeExpr(), tt);
       case PN_NAMESET:
         return ContainsStmt(pn->pn_tree, tt);
       default:;
     }
@@ -4566,18 +4563,18 @@ PushLexicalScope(JSContext *cx, TokenStr
     if (!obj)
         return NULL;
 
     blockbox = tc->parser->newObjectBox(obj);
     if (!blockbox)
         return NULL;
 
     js_PushBlockScope(tc, stmt, blockbox, -1);
-    pn->pn_type = TOK_LEXICALSCOPE;
-    pn->pn_op = JSOP_LEAVEBLOCK;
+    pn->setKind(TOK_LEXICALSCOPE);
+    pn->setOp(JSOP_LEAVEBLOCK);
     pn->pn_objbox = blockbox;
     pn->pn_cookie.makeFree();
     pn->pn_dflags = 0;
     if (!GenerateBlockId(tc, stmt->blockid))
         return NULL;
     pn->pn_blockid = stmt->blockid;
     return pn;
 }
@@ -4630,34 +4627,34 @@ Parser::letBlock(JSBool statement)
         /*
          * If this is really an expression in let statement guise, then we
          * need to wrap the TOK_LET node in a TOK_SEMI node so that we pop
          * the return value of the expression.
          */
         pn = UnaryNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_type = TOK_SEMI;
+        pn->setKind(TOK_SEMI);
         pn->pn_num = -1;
         pn->pn_kid = pnblock;
 
         statement = JS_FALSE;
     }
 
     if (statement) {
         pnlet->pn_right = statements();
         if (!pnlet->pn_right)
             return NULL;
         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LET);
     } else {
         /*
          * Change pnblock's opcode to the variant that propagates the last
          * result down after popping the block, and clear statement.
          */
-        pnblock->pn_op = JSOP_LEAVEBLOCKEXPR;
+        pnblock->setOp(JSOP_LEAVEBLOCKEXPR);
         pnlet->pn_right = assignExpr();
         if (!pnlet->pn_right)
             return NULL;
     }
 
     PopStatement(tc);
     return pn;
 }
@@ -4681,17 +4678,17 @@ NewBindingNode(JSAtom *atom, JSTreeConte
         JS_ASSERT(!pn->isPlaceholder());
     } else {
         removal = tc->lexdeps->lookup(atom);
         pn = removal ? removal.value() : NULL;
         JS_ASSERT_IF(pn, pn->isPlaceholder());
     }
 
     if (pn) {
-        JS_ASSERT(pn->pn_defn);
+        JS_ASSERT(pn->isDefn());
 
         /*
          * A let binding at top level becomes a var before we get here, so if
          * pn and tc have the same blockid then that id must not be the bodyid.
          * If pn is a forward placeholder definition from the same or a higher
          * block then we claim it.
          */
         JS_ASSERT_IF(let && pn->pn_blockid == tc->blockid(),
@@ -4790,17 +4787,17 @@ Parser::switchStatement()
             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_SWITCH);
             return NULL;
         }
         MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE);
 
         JSParseNode *pn4 = ListNode::create(tc);
         if (!pn4)
             return NULL;
-        pn4->pn_type = TOK_LC;
+        pn4->setKind(TOK_LC);
         pn4->makeEmpty();
         while ((tt = tokenStream.peekToken(TSF_OPERAND)) != TOK_RC &&
                tt != TOK_CASE && tt != TOK_DEFAULT) {
             if (tt == TOK_ERROR)
                 return NULL;
             pn5 = statement();
             if (!pn5)
                 return NULL;
@@ -4843,75 +4840,75 @@ Parser::switchStatement()
  * the original tree.
  */
 static JSParseNode *
 CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc)
 {
     JSParseNode *pn = NewOrRecycledNode(tc);
     if (!pn)
         return NULL;
-    pn->pn_type = opn->pn_type;
+    pn->setKind(opn->getKind());
+    pn->setOp(opn->getOp());
+    pn->setUsed(opn->isUsed());
+    pn->setDefn(opn->isDefn());
+    pn->setArity(opn->getArity());
+    pn->setInParens(opn->isInParens());
     pn->pn_pos = opn->pn_pos;
-    pn->pn_op = opn->pn_op;
-    pn->pn_used = opn->pn_used;
-    pn->pn_defn = opn->pn_defn;
-    pn->pn_arity = opn->pn_arity;
-    pn->pn_parens = opn->pn_parens;
 
 #if JS_HAS_DESTRUCTURING
-    if (opn->pn_arity == PN_LIST) {
-        JS_ASSERT(opn->pn_type == TOK_RB || opn->pn_type == TOK_RC);
+    if (opn->isArity(PN_LIST)) {
+        JS_ASSERT(opn->isKind(TOK_RB) || opn->isKind(TOK_RC));
         pn->makeEmpty();
         for (JSParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) {
             JSParseNode *pn2;
-            if (opn->pn_type == TOK_RC) {
-                JS_ASSERT(opn2->pn_arity == PN_BINARY);
-                JS_ASSERT(opn2->pn_type == TOK_COLON);
+            if (opn->isKind(TOK_RC)) {
+                JS_ASSERT(opn2->isArity(PN_BINARY));
+                JS_ASSERT(opn2->isKind(TOK_COLON));
 
                 JSParseNode *tag = CloneParseTree(opn2->pn_left, tc);
                 if (!tag)
                     return NULL;
                 JSParseNode *target = CloneLeftHandSide(opn2->pn_right, tc);
                 if (!target)
                     return NULL;
                 pn2 = BinaryNode::create(TOK_COLON, JSOP_INITPROP, opn2->pn_pos, tag, target, tc);
-            } else if (opn2->pn_arity == PN_NULLARY) {
-                JS_ASSERT(opn2->pn_type == TOK_COMMA);
+            } else if (opn2->isArity(PN_NULLARY)) {
+                JS_ASSERT(opn2->isKind(TOK_COMMA));
                 pn2 = CloneParseTree(opn2, tc);
             } else {
                 pn2 = CloneLeftHandSide(opn2, tc);
             }
 
             if (!pn2)
                 return NULL;
             pn->append(pn2);
         }
         pn->pn_xflags = opn->pn_xflags;
         return pn;
     }
 #endif
 
-    JS_ASSERT(opn->pn_arity == PN_NAME);
-    JS_ASSERT(opn->pn_type == TOK_NAME);
+    JS_ASSERT(opn->isArity(PN_NAME));
+    JS_ASSERT(opn->isKind(TOK_NAME));
 
     /* If opn is a definition or use, make pn a use. */
     pn->pn_u.name = opn->pn_u.name;
-    pn->pn_op = JSOP_SETNAME;
-    if (opn->pn_used) {
+    pn->setOp(JSOP_SETNAME);
+    if (opn->isUsed()) {
         JSDefinition *dn = pn->pn_lexdef;
 
         pn->pn_link = dn->dn_uses;
         dn->dn_uses = pn;
     } else {
         pn->pn_expr = NULL;
-        if (opn->pn_defn) {
+        if (opn->isDefn()) {
             /* We copied some definition-specific state into pn. Clear it out. */
             pn->pn_cookie.makeFree();
             pn->pn_dflags &= ~PND_BOUND;
-            pn->pn_defn = false;
+            pn->setDefn(false);
 
             LinkUseToDef(pn, (JSDefinition *) opn, tc);
         }
     }
     return pn;
 }
 
 JSParseNode *
@@ -4925,17 +4922,17 @@ Parser::forStatement()
 
     /* A FOR node is binary, left is loop control and right is the body. */
     JSParseNode *pn = BinaryNode::create(tc);
     if (!pn)
         return NULL;
     JSStmtInfo stmtInfo;
     js_PushStatement(tc, &stmtInfo, STMT_FOR_LOOP, -1);
 
-    pn->pn_op = JSOP_ITER;
+    pn->setOp(JSOP_ITER);
     pn->pn_iflags = 0;
     if (tokenStream.matchToken(TOK_NAME)) {
         if (tokenStream.currentToken().t_atom == context->runtime->atomState.eachAtom)
             pn->pn_iflags = JSITER_FOREACH;
         else
             tokenStream.ungetToken();
     }
 
@@ -5013,46 +5010,46 @@ Parser::forStatement()
          * Here pn1 is everything to the left of 'in'. At the end of this block,
          * pn1 is a decl or NULL, pn2 is the assignment target that receives the
          * enumeration value each iteration, and pn3 is the rhs of 'in'.
          */
         pn->pn_iflags |= JSITER_ENUMERATE;
         stmtInfo.type = STMT_FOR_IN_LOOP;
 
         /* Check that the left side of the 'in' is valid. */
-        JS_ASSERT(!TokenKindIsDecl(tt) || PN_TYPE(pn1) == tt);
+        JS_ASSERT(!TokenKindIsDecl(tt) || pn1->isKind(tt));
         if (TokenKindIsDecl(tt)
-            ? (pn1->pn_count > 1 || pn1->pn_op == JSOP_DEFCONST
+            ? (pn1->pn_count > 1 || pn1->isOp(JSOP_DEFCONST)
 #if JS_HAS_DESTRUCTURING
                || (versionNumber() == JSVERSION_1_7 &&
-                   pn->pn_op == JSOP_ITER &&
+                   pn->isOp(JSOP_ITER) &&
                    !(pn->pn_iflags & JSITER_FOREACH) &&
-                   (pn1->pn_head->pn_type == TOK_RC ||
-                    (pn1->pn_head->pn_type == TOK_RB &&
+                   (pn1->pn_head->isKind(TOK_RC) ||
+                    (pn1->pn_head->isKind(TOK_RB) &&
                      pn1->pn_head->pn_count != 2) ||
-                    (pn1->pn_head->pn_type == TOK_ASSIGN &&
-                     (pn1->pn_head->pn_left->pn_type != TOK_RB ||
+                    (pn1->pn_head->isKind(TOK_ASSIGN) &&
+                     (!pn1->pn_head->pn_left->isKind(TOK_RB) ||
                       pn1->pn_head->pn_left->pn_count != 2))))
 #endif
               )
-            : (pn1->pn_type != TOK_NAME &&
-               pn1->pn_type != TOK_DOT &&
+            : (!pn1->isKind(TOK_NAME) &&
+               !pn1->isKind(TOK_DOT) &&
 #if JS_HAS_DESTRUCTURING
                ((versionNumber() == JSVERSION_1_7 &&
-                 pn->pn_op == JSOP_ITER &&
+                 pn->isOp(JSOP_ITER) &&
                  !(pn->pn_iflags & JSITER_FOREACH))
-                ? (pn1->pn_type != TOK_RB || pn1->pn_count != 2)
-                : (pn1->pn_type != TOK_RB && pn1->pn_type != TOK_RC)) &&
+                ? (!pn1->isKind(TOK_RB) || pn1->pn_count != 2)
+                : (!pn1->isKind(TOK_RB) && !pn1->isKind(TOK_RC))) &&
 #endif
-               pn1->pn_type != TOK_LP &&
+               !pn1->isKind(TOK_LP) &&
 #if JS_HAS_XML_SUPPORT
-               (pn1->pn_type != TOK_UNARYOP ||
-                pn1->pn_op != JSOP_XMLNAME) &&
+               (!pn1->isKind(TOK_UNARYOP) ||
+                !pn1->isOp(JSOP_XMLNAME)) &&
 #endif
-               pn1->pn_type != TOK_LB)) {
+               !pn1->isKind(TOK_LB))) {
             reportErrorNumber(pn1, JSREPORT_ERROR, JSMSG_BAD_FOR_LEFTSIDE);
             return NULL;
         }
 
         /*
          * After the following if-else, pn2 will point to the name or
          * destructuring pattern on in's left. pn1 will point to the decl, if
          * any, else NULL. Note that the "declaration with initializer" case
@@ -5060,19 +5057,19 @@ Parser::forStatement()
          */
         pn2 = NULL;
         uintN dflag = PND_ASSIGNED;
         if (TokenKindIsDecl(tt)) {
             /* Tell EmitVariables that pn1 is part of a for/in. */
             pn1->pn_xflags |= PNX_FORINVAR;
 
             pn2 = pn1->pn_head;
-            if ((pn2->pn_type == TOK_NAME && pn2->maybeExpr())
+            if ((pn2->isKind(TOK_NAME) && pn2->maybeExpr())
 #if JS_HAS_DESTRUCTURING
-                || pn2->pn_type == TOK_ASSIGN
+                || pn2->isKind(TOK_ASSIGN)
 #endif
                 ) {
                 /*
                  * Declaration with initializer.
                  *
                  * Rewrite 'for (<decl> x = i in o)' where <decl> is 'var' or
                  * 'const' to hoist the initializer or the entire decl out of
                  * the loop head. TOK_VAR is the type for both 'var' and 'const'.
@@ -5082,17 +5079,17 @@ Parser::forStatement()
                     reportErrorNumber(pn2, JSREPORT_ERROR, JSMSG_INVALID_FOR_IN_INIT);
                     return NULL;
                 }
 #endif /* JS_HAS_BLOCK_SCOPE */
 
                 pnseq = ListNode::create(tc);
                 if (!pnseq)
                     return NULL;
-                pnseq->pn_type = TOK_SEQ;
+                pnseq->setKind(TOK_SEQ);
                 pnseq->pn_pos.begin = pn->pn_pos.begin;
 
                 dflag = PND_INITIALIZED;
 
                 /*
                  * All of 'var x = i' is hoisted above 'for (x in o)',
                  * so clear PNX_FORINVAR.
                  *
@@ -5100,20 +5097,20 @@ Parser::forStatement()
                  * name (it is not a destructuring binding's left-hand
                  * side) and it has an initializer.
                  */
                 pn1->pn_xflags &= ~PNX_FORINVAR;
                 pn1->pn_xflags |= PNX_POPVAR;
                 pnseq->initList(pn1);
 
 #if JS_HAS_DESTRUCTURING
-                if (pn2->pn_type == TOK_ASSIGN) {
+                if (pn2->isKind(TOK_ASSIGN)) {
                     pn2 = pn2->pn_left;
-                    JS_ASSERT(pn2->pn_type == TOK_RB || pn2->pn_type == TOK_RC ||
-                              pn2->pn_type == TOK_NAME);
+                    JS_ASSERT(pn2->isKind(TOK_RB) || pn2->isKind(TOK_RC) ||
+                              pn2->isKind(TOK_NAME));
                 }
 #endif
                 pn1 = NULL;
             }
 
             /*
              * pn2 is part of a declaration. Make a copy that can be passed to
              * EmitAssignment.
@@ -5125,17 +5122,17 @@ Parser::forStatement()
             /* Not a declaration. */
             pn2 = pn1;
             pn1 = NULL;
 
             if (!setAssignmentLhsOps(pn2, JSOP_NOP))
                 return NULL;
         }
 
-        switch (pn2->pn_type) {
+        switch (pn2->getKind()) {
           case TOK_NAME:
             /* Beware 'for (arguments in ...)' with or without a 'var'. */
             NoteLValue(context, pn2, tc, dflag);
             break;
 
 #if JS_HAS_DESTRUCTURING
           case TOK_ASSIGN:
             JS_NOT_REACHED("forStatement TOK_ASSIGN");
@@ -5143,17 +5140,17 @@ Parser::forStatement()
 
           case TOK_RB:
           case TOK_RC:
             if (versionNumber() == JSVERSION_1_7) {
                 /*
                  * Destructuring for-in requires [key, value] enumeration
                  * in JS1.7.
                  */
-                JS_ASSERT(pn->pn_op == JSOP_ITER);
+                JS_ASSERT(pn->isOp(JSOP_ITER));
                 if (!(pn->pn_iflags & JSITER_FOREACH))
                     pn->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
             }
             break;
 #endif
 
           default:;
         }
@@ -5171,23 +5168,23 @@ Parser::forStatement()
         pn3 = expr();
         if (!pn3)
             return NULL;
 #if JS_HAS_BLOCK_SCOPE
         if (let)
             tc->topStmt = save;
 #endif
 
-        pn4->pn_type = TOK_IN;
+        pn4->setKind(TOK_IN);
     } else {
         if (pn->pn_iflags & JSITER_FOREACH) {
             reportErrorNumber(pn, JSREPORT_ERROR, JSMSG_BAD_FOR_EACH_LOOP);
             return NULL;
         }
-        pn->pn_op = JSOP_NOP;
+        pn->setOp(JSOP_NOP);
 
         /* Parse the loop condition or null into pn2. */
         MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT);
         tt = tokenStream.peekToken(TSF_OPERAND);
         if (tt == TOK_SEMI) {
             pn2 = NULL;
         } else {
             pn2 = expr();
@@ -5201,19 +5198,19 @@ Parser::forStatement()
         if (tt == TOK_RP) {
             pn3 = NULL;
         } else {
             pn3 = expr();
             if (!pn3)
                 return NULL;
         }
 
-        pn4->pn_type = TOK_FORHEAD;
-    }
-    pn4->pn_op = JSOP_NOP;
+        pn4->setKind(TOK_FORHEAD);
+    }
+    pn4->setOp(JSOP_NOP);
     pn4->pn_kid1 = pn1;
     pn4->pn_kid2 = pn2;
     pn4->pn_kid3 = pn3;
     pn->pn_left = pn4;
 
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
 
     /* Parse the loop body into pn->pn_right. */
@@ -5261,17 +5258,17 @@ Parser::tryStatement()
      *   TOK_NAME for a single identifier
      *   TOK_RB or TOK_RC for a destructuring left-hand side
      *
      * finally nodes are TOK_LC statement lists.
      */
     JSParseNode *pn = TernaryNode::create(tc);
     if (!pn)
         return NULL;
-    pn->pn_op = JSOP_NOP;
+    pn->setOp(JSOP_NOP);
 
     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
     JSStmtInfo stmtInfo;
     if (!PushBlocklikeStatement(&stmtInfo, STMT_TRY, tc))
         return NULL;
     pn->pn_kid1 = statements();
     if (!pn->pn_kid1)
         return NULL;
@@ -5279,17 +5276,17 @@ Parser::tryStatement()
     PopStatement(tc);
 
     catchList = NULL;
     TokenKind tt = tokenStream.getToken();
     if (tt == TOK_CATCH) {
         catchList = ListNode::create(tc);
         if (!catchList)
             return NULL;
-        catchList->pn_type = TOK_RESERVED;
+        catchList->setKind(TOK_RESERVED);
         catchList->makeEmpty();
         lastCatch = NULL;
 
         do {
             JSParseNode *pnblock;
             BindData data;
 
             /* Check for another catch after unconditional catch. */
@@ -5467,22 +5464,21 @@ Parser::letStatement()
 {
     JSObjectBox *blockbox;
 
     JSParseNode *pn;
     do {
         /* Check for a let statement or let expression. */
         if (tokenStream.peekToken() == TOK_LP) {
             pn = letBlock(JS_TRUE);
-            if (!pn || pn->pn_op == JSOP_LEAVEBLOCK)
+            if (!pn || pn->isOp(JSOP_LEAVEBLOCK))
                 return pn;
 
             /* Let expressions require automatic semicolon insertion. */
-            JS_ASSERT(pn->pn_type == TOK_SEMI ||
-                      pn->pn_op == JSOP_LEAVEBLOCKEXPR);
+            JS_ASSERT(pn->isKind(TOK_SEMI) || pn->isOp(JSOP_LEAVEBLOCKEXPR));
             break;
         }
 
         /*
          * This is a let declaration. We must be directly under a block per
          * the proposed ES4 specs, but not an implicit block created due to
          * 'for (let ...)'. If we pass this error test, make the enclosing
          * JSStmtInfo be our scope. Further let declarations in this block
@@ -5550,26 +5546,26 @@ Parser::letStatement()
 
             obj->setParent(tc->blockChain());
             blockbox->parent = tc->blockChainBox;
             tc->blockChainBox = blockbox;
             stmt->blockBox = blockbox;
 
 #ifdef DEBUG
             JSParseNode *tmp = tc->blockNode;
-            JS_ASSERT(!tmp || tmp->pn_type != TOK_LEXICALSCOPE);
+            JS_ASSERT(!tmp || !tmp->isKind(TOK_LEXICALSCOPE));
 #endif
 
             /* Create a new lexical scope node for these statements. */
             JSParseNode *pn1 = LexicalScopeNode::create(tc);
             if (!pn1)
                 return NULL;
 
-            pn1->pn_type = TOK_LEXICALSCOPE;
-            pn1->pn_op = JSOP_LEAVEBLOCK;
+            pn1->setKind(TOK_LEXICALSCOPE);
+            pn1->setOp(JSOP_LEAVEBLOCK);
             pn1->pn_pos = tc->blockNode->pn_pos;
             pn1->pn_objbox = blockbox;
             pn1->pn_expr = tc->blockNode;
             pn1->pn_blockid = tc->blockNode->pn_blockid;
             tc->blockNode = pn1;
         }
 
         pn = variables(false);
@@ -5587,17 +5583,17 @@ JSParseNode *
 Parser::expressionStatement()
 {
     tokenStream.ungetToken();
     JSParseNode *pn2 = expr();
     if (!pn2)
         return NULL;
 
     if (tokenStream.peekToken() == TOK_COLON) {
-        if (pn2->pn_type != TOK_NAME) {
+        if (!pn2->isKind(TOK_NAME)) {
             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_LABEL);
             return NULL;
         }
         JSAtom *label = pn2->pn_atom;
         for (JSStmtInfo *stmt = tc->topStmt; stmt; stmt = stmt->down) {
             if (stmt->type == STMT_LABEL && stmt->label == label) {
                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_DUPLICATE_LABEL);
                 return NULL;
@@ -5611,61 +5607,61 @@ Parser::expressionStatement()
         JSStmtInfo stmtInfo;
         js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1);
         stmtInfo.label = label;
         JSParseNode *pn = statement();
         if (!pn)
             return NULL;
 
         /* Normalize empty statement to empty block for the decompiler. */
-        if (pn->pn_type == TOK_SEMI && !pn->pn_kid) {
-            pn->pn_type = TOK_LC;
-            pn->pn_arity = PN_LIST;
+        if (pn->isKind(TOK_SEMI) && !pn->pn_kid) {
+            pn->setKind(TOK_LC);
+            pn->setArity(PN_LIST);
             pn->makeEmpty();
         }
 
         /* Pop the label, set pn_expr, and return early. */
         PopStatement(tc);
-        pn2->pn_type = TOK_COLON;
+        pn2->setKind(TOK_COLON);
         pn2->pn_pos.end = pn->pn_pos.end;
         pn2->pn_expr = pn;
         return pn2;
     }
 
     JSParseNode *pn = UnaryNode::create(tc);
     if (!pn)
         return NULL;
-    pn->pn_type = TOK_SEMI;
+    pn->setKind(TOK_SEMI);
     pn->pn_pos = pn2->pn_pos;
     pn->pn_kid = pn2;
 
-    switch (PN_TYPE(pn2)) {
+    switch (pn2->getKind()) {
       case TOK_LP:
         /*
          * Flag lambdas immediately applied as statements as instances of
          * the JS "module pattern". See CheckForImmediatelyAppliedLambda.
          */
-        if (PN_TYPE(pn2->pn_head) == TOK_FUNCTION &&
+        if (pn2->pn_head->isKind(TOK_FUNCTION) &&
             !pn2->pn_head->pn_funbox->node->isFunArg()) {
             pn2->pn_head->pn_funbox->tcflags |= TCF_FUN_MODULE_PATTERN;
         }
         break;
       case TOK_ASSIGN:
         /*
          * Keep track of all apparent methods created by assignments such
          * as this.foo = function (...) {...} in a function that could end
          * up a constructor function. See Parser::setFunctionKinds.
          */
         if (tc->funbox &&
-            PN_OP(pn2) == JSOP_NOP &&
-            PN_OP(pn2->pn_left) == JSOP_SETPROP &&
-            PN_OP(pn2->pn_left->pn_expr) == JSOP_THIS &&
-            PN_OP(pn2->pn_right) == JSOP_LAMBDA) {
-            JS_ASSERT(!pn2->pn_defn);
-            JS_ASSERT(!pn2->pn_used);
+            pn2->isOp(JSOP_NOP) &&
+            pn2->pn_left->isOp(JSOP_SETPROP) &&
+            pn2->pn_left->pn_expr->isOp(JSOP_THIS) &&
+            pn2->pn_right->isOp(JSOP_LAMBDA)) {
+            JS_ASSERT(!pn2->isDefn());
+            JS_ASSERT(!pn2->isUsed());
             pn2->pn_right->pn_link = tc->funbox->methods;
             tc->funbox->methods = pn2->pn_right;
         }
         break;
       default:;
     }
 
     /* Check termination of this primitive statement. */
@@ -5795,17 +5791,17 @@ Parser::statement()
             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
             return NULL;
         }
 
         JSParseNode *pn2 = expr();
         if (!pn2)
             return NULL;
         pn->pn_pos.end = pn2->pn_pos.end;
-        pn->pn_op = JSOP_THROW;
+        pn->setOp(JSOP_THROW);
         pn->pn_kid = pn2;
         break;
       }
 
       /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */
       case TOK_CATCH:
         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_CATCH_WITHOUT_TRY);
         return NULL;
@@ -5939,24 +5935,24 @@ Parser::statement()
         tc->flags = oldflags | (tc->flags & (TCF_FUN_FLAGS | TCF_RETURN_FLAGS));
         return pn;
       }
 
       case TOK_SEMI:
         pn = UnaryNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_type = TOK_SEMI;
+        pn->setKind(TOK_SEMI);
         return pn;
 
       case TOK_DEBUGGER:
         pn = NullaryNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_type = TOK_DEBUGGER;
+        pn->setKind(TOK_DEBUGGER);
         tc->flags |= TCF_FUN_HEAVYWEIGHT;
         break;
 
 #if JS_HAS_XML_SUPPORT
       case TOK_DEFAULT:
       {
         pn = UnaryNode::create(tc);
         if (!pn)
@@ -5971,17 +5967,17 @@ Parser::statement()
             return NULL;
         }
 
         /* Is this an E4X dagger I see before me? */
         tc->flags |= TCF_FUN_HEAVYWEIGHT;
         JSParseNode *pn2 = expr();
         if (!pn2)
             return NULL;
-        pn->pn_op = JSOP_DEFXMLNS;
+        pn->setOp(JSOP_DEFXMLNS);
         pn->pn_pos.end = pn2->pn_pos.end;
         pn->pn_kid = pn2;
         break;
       }
 #endif
 
       case TOK_ERROR:
         return NULL;
@@ -6031,17 +6027,17 @@ Parser::variables(bool inLetHead)
         }
         JS_ASSERT(scopeStmt);
     }
 
     data.op = let ? JSOP_NOP : tokenStream.currentToken().t_op;
     pn = ListNode::create(tc);
     if (!pn)
         return NULL;
-    pn->pn_op = data.op;
+    pn->setOp(data.op);
     pn->makeEmpty();
 
     /*
      * SpiderMonkey const is really "write once per initialization evaluation"
      * var, whereas let is block scoped. ES-Harmony wants block-scoped const so
      * this code will change soon.
      */
     if (let) {
@@ -6131,33 +6127,33 @@ Parser::variables(bool inLetHead)
             if (popScope) {
                 tc->topStmt = save;
                 tc->topScopeStmt = saveScope;
             }
 #endif
             if (!init)
                 return NULL;
 
-            if (pn2->pn_used) {
+            if (pn2->isUsed()) {
                 pn2 = MakeAssignment(pn2, init, tc);
                 if (!pn2)
                     return NULL;
             } else {
                 pn2->pn_expr = init;
             }
 
             JS_ASSERT_IF(pn2->pn_dflags & PND_GVAR, !(pn2->pn_dflags & PND_BOUND));
 
-            pn2->pn_op = (PN_OP(pn2) == JSOP_ARGUMENTS)
-                         ? JSOP_SETNAME
-                         : (pn2->pn_dflags & PND_BOUND)
-                         ? JSOP_SETLOCAL
-                         : (data.op == JSOP_DEFCONST)
-                         ? JSOP_SETCONST
-                         : JSOP_SETNAME;
+            pn2->setOp(pn2->isOp(JSOP_ARGUMENTS)
+                       ? JSOP_SETNAME
+                       : (pn2->pn_dflags & PND_BOUND)
+                       ? JSOP_SETLOCAL
+                       : (data.op == JSOP_DEFCONST)
+                       ? JSOP_SETCONST
+                       : JSOP_SETNAME);
 
             NoteLValue(context, pn2, tc, data.fresh ? PND_INITIALIZED : PND_ASSIGNED);
 
             /* The declarator's position must include the initializer. */
             pn2->pn_pos.end = init->pn_pos.end;
 
             if (tc->inFunction() &&
                 atom == context->runtime->atomState.argumentsAtom) {
@@ -6185,17 +6181,17 @@ Parser::expr()
         if (!pn2)
             return NULL;
         pn2->pn_pos.begin = pn->pn_pos.begin;
         pn2->initList(pn);
         pn = pn2;
         do {
 #if JS_HAS_GENERATORS
             pn2 = pn->last();
-            if (pn2->pn_type == TOK_YIELD && !pn2->pn_parens) {
+            if (pn2->isKind(TOK_YIELD) && !pn2->isInParens()) {
                 reportErrorNumber(pn2, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
                 return NULL;
             }
 #endif
             pn2 = assignExpr();
             if (!pn2)
                 return NULL;
             pn->append(pn2);
@@ -6383,28 +6379,28 @@ Parser::condExpr1()
         tokenStream.getToken();     /* need to read one token past the end */
     }
     return pn;
 }
 
 bool
 Parser::setAssignmentLhsOps(JSParseNode *pn, JSOp op)
 {
-    switch (pn->pn_type) {
+    switch (pn->getKind()) {
       case TOK_NAME:
         if (!CheckStrictAssignment(context, tc, pn))
             return false;
-        pn->pn_op = (pn->pn_op == JSOP_GETLOCAL) ? JSOP_SETLOCAL : JSOP_SETNAME;
+        pn->setOp(pn->isOp(JSOP_GETLOCAL) ? JSOP_SETLOCAL : JSOP_SETNAME);
         NoteLValue(context, pn, tc);
         break;
       case TOK_DOT:
-        pn->pn_op = JSOP_SETPROP;
+        pn->setOp(JSOP_SETPROP);
         break;
       case TOK_LB:
-        pn->pn_op = JSOP_SETELEM;
+        pn->setOp(JSOP_SETELEM);
         break;
 #if JS_HAS_DESTRUCTURING
       case TOK_RB:
       case TOK_RC:
         if (op != JSOP_NOP) {
             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_DESTRUCT_ASS);
             return false;
         }
@@ -6413,18 +6409,18 @@ Parser::setAssignmentLhsOps(JSParseNode 
         break;
 #endif
       case TOK_LP:
         if (!MakeSetCall(context, pn, tc, JSMSG_BAD_LEFTSIDE_OF_ASS))
             return false;
         break;
 #if JS_HAS_XML_SUPPORT
       case TOK_UNARYOP:
-        if (pn->pn_op == JSOP_XMLNAME) {
-            pn->pn_op = JSOP_SETXMLNAME;
+        if (pn->isOp(JSOP_XMLNAME)) {
+            pn->setOp(JSOP_SETXMLNAME);
             break;
         }
         /* FALL THROUGH */
 #endif
       default:
         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS);
         return false;
     }
@@ -6452,17 +6448,17 @@ Parser::assignExpr()
 
     JSOp op = tokenStream.currentToken().t_op;
     if (!setAssignmentLhsOps(pn, op))
         return NULL;
 
     JSParseNode *rhs = assignExpr();
     if (!rhs)
         return NULL;
-    if (PN_TYPE(pn) == TOK_NAME && pn->pn_used) {
+    if (pn->isKind(TOK_NAME) && pn->isUsed()) {
         JSDefinition *dn = pn->pn_lexdef;
 
         /*
          * If the definition is not flagged as assigned, we must have imputed
          * the initialized flag to it, to optimize for flat closures. But that
          * optimization uses source coordinates to check dominance relations,
          * so we must extend the end of the definition to cover the right-hand
          * side of this assignment, i.e., the initializer.
@@ -6475,25 +6471,25 @@ Parser::assignExpr()
 
     return JSParseNode::newBinaryOrAppend(TOK_ASSIGN, op, pn, rhs, tc);
 }
 
 static JSParseNode *
 SetLvalKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc,
            JSParseNode *pn, JSParseNode *kid, const char *name)
 {
-    if (kid->pn_type != TOK_NAME &&
-        kid->pn_type != TOK_DOT &&
-        (kid->pn_type != TOK_LP ||
-         (kid->pn_op != JSOP_CALL && kid->pn_op != JSOP_EVAL &&
-          kid->pn_op != JSOP_FUNCALL && kid->pn_op != JSOP_FUNAPPLY)) &&
+    if (!kid->isKind(TOK_NAME) &&
+        !kid->isKind(TOK_DOT) &&
+        (!kid->isKind(TOK_LP) ||
+         (!kid->isOp(JSOP_CALL) && !kid->isOp(JSOP_EVAL) &&
+          !kid->isOp(JSOP_FUNCALL) && !kid->isOp(JSOP_FUNAPPLY))) &&
 #if JS_HAS_XML_SUPPORT
-        (kid->pn_type != TOK_UNARYOP || kid->pn_op != JSOP_XMLNAME) &&
+        (!kid->isKind(TOK_UNARYOP) || !kid->isOp(JSOP_XMLNAME)) &&
 #endif
-        kid->pn_type != TOK_LB) {
+        !kid->isKind(TOK_LB)) {
         ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_OPERAND, name);
         return NULL;
     }
     if (!CheckStrictAssignment(cx, tc, kid))
         return NULL;
     pn->pn_kid = kid;
     return kid;
 }
@@ -6505,17 +6501,17 @@ SetIncOpKid(JSContext *cx, TokenStream *
             JSParseNode *pn, JSParseNode *kid,
             TokenKind tt, JSBool preorder)
 {
     JSOp op;
 
     kid = SetLvalKid(cx, ts, tc, pn, kid, incop_name_str[tt == TOK_DEC]);
     if (!kid)
         return JS_FALSE;
-    switch (kid->pn_type) {
+    switch (kid->getKind()) {
       case TOK_NAME:
         op = (tt == TOK_INC)
              ? (preorder ? JSOP_INCNAME : JSOP_NAMEINC)
              : (preorder ? JSOP_DECNAME : JSOP_NAMEDEC);
         NoteLValue(cx, kid, tc);
         break;
 
       case TOK_DOT:
@@ -6525,31 +6521,31 @@ SetIncOpKid(JSContext *cx, TokenStream *
         break;
 
       case TOK_LP:
         if (!MakeSetCall(cx, kid, tc, JSMSG_BAD_INCOP_OPERAND))
             return JS_FALSE;
         /* FALL THROUGH */
 #if JS_HAS_XML_SUPPORT
       case TOK_UNARYOP:
-        if (kid->pn_op == JSOP_XMLNAME)
-            kid->pn_op = JSOP_SETXMLNAME;
+        if (kid->isOp(JSOP_XMLNAME))
+            kid->setOp(JSOP_SETXMLNAME);
         /* FALL THROUGH */
 #endif
       case TOK_LB:
         op = (tt == TOK_INC)
              ? (preorder ? JSOP_INCELEM : JSOP_ELEMINC)
              : (preorder ? JSOP_DECELEM : JSOP_ELEMDEC);
         break;
 
       default:
         JS_ASSERT(0);
         op = JSOP_NOP;
     }
-    pn->pn_op = op;
+    pn->setOp(op);
     return JS_TRUE;
 }
 
 JSParseNode *
 Parser::unaryExpr()
 {
     JSParseNode *pn, *pn2;
 
@@ -6558,18 +6554,18 @@ Parser::unaryExpr()
     TokenKind tt = tokenStream.getToken(TSF_OPERAND);
     switch (tt) {
       case TOK_UNARYOP:
       case TOK_PLUS:
       case TOK_MINUS:
         pn = UnaryNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_type = TOK_UNARYOP;      /* PLUS and MINUS are binary */
-        pn->pn_op = tokenStream.currentToken().t_op;
+        pn->setKind(TOK_UNARYOP);      /* PLUS and MINUS are binary */
+        pn->setOp(tokenStream.currentToken().t_op);
         pn2 = unaryExpr();
         if (!pn2)
             return NULL;
         pn->pn_pos.end = pn2->pn_pos.end;
         pn->pn_kid = pn2;
         break;
 
       case TOK_INC:
@@ -6597,34 +6593,34 @@ Parser::unaryExpr()
 
         /*
          * Under ECMA3, deleting any unary expression is valid -- it simply
          * returns true. Here we fold constants before checking for a call
          * expression, in order to rule out delete of a generator expression.
          */
         if (foldConstants && !js_FoldConstants(context, pn2, tc))
             return NULL;
-        switch (pn2->pn_type) {
+        switch (pn2->getKind()) {
           case TOK_LP:
             if (!(pn2->pn_xflags & PNX_SETCALL)) {
                 /*
                  * Call MakeSetCall to check for errors, but clear PNX_SETCALL
                  * because the optimizer will eliminate the useless delete.
                  */
                 if (!MakeSetCall(context, pn2, tc, JSMSG_BAD_DELETE_OPERAND))
                     return NULL;
                 pn2->pn_xflags &= ~PNX_SETCALL;
             }
             break;
           case TOK_NAME:
             if (!ReportStrictModeError(context, &tokenStream, tc, pn,
                                        JSMSG_DEPRECATED_DELETE_OPERAND)) {
                 return NULL;
             }
-            pn2->pn_op = JSOP_DELNAME;
+            pn2->setOp(JSOP_DELNAME);
             if (pn2->pn_atom == context->runtime->atomState.argumentsAtom) {
                 tc->flags |= TCF_FUN_HEAVYWEIGHT;
                 tc->countArgumentsUse(pn2);
             }
             break;
           default:;
         }
         pn->pn_kid = pn2;
@@ -6821,29 +6817,29 @@ BumpStaticLevel(JSParseNode *pn, JSTreeC
         pn->pn_cookie.set(level, pn->pn_cookie.slot());
     }
     return true;
 }
 
 static void
 AdjustBlockId(JSParseNode *pn, uintN adjust, JSTreeContext *tc)
 {
-    JS_ASSERT(pn->pn_arity == PN_LIST || pn->pn_arity == PN_FUNC || pn->pn_arity == PN_NAME);
+    JS_ASSERT(pn->isArity(PN_LIST) || pn->isArity(PN_FUNC) || pn->isArity(PN_NAME));
     pn->pn_blockid += adjust;
     if (pn->pn_blockid >= tc->blockidGen)
         tc->blockidGen = pn->pn_blockid + 1;
 }
 
 bool
 CompExprTransplanter::transplant(JSParseNode *pn)
 {
     if (!pn)
         return true;
 
-    switch (pn->pn_arity) {
+    switch (pn->getArity()) {
       case PN_LIST:
         for (JSParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             if (!transplant(pn2))
                 return false;
         }
         if (pn->pn_pos >= root->pn_pos)
             AdjustBlockId(pn, adjust, tc);
         break;
@@ -6900,28 +6896,28 @@ CompExprTransplanter::transplant(JSParse
             funbox->level = tc->staticLevel;
         }
         /* FALL THROUGH */
       }
 
       case PN_NAME:
         if (!transplant(pn->maybeExpr()))
             return false;
-        if (pn->pn_arity == PN_FUNC)
+        if (pn->isArity(PN_FUNC))
             --funcLevel;
 
-        if (pn->pn_defn) {
+        if (pn->isDefn()) {
             if (genexp && !BumpStaticLevel(pn, tc))
                 return false;
-        } else if (pn->pn_used) {
-            JS_ASSERT(pn->pn_op != JSOP_NOP);
+        } else if (pn->isUsed()) {
+            JS_ASSERT(!pn->isOp(JSOP_NOP));
             JS_ASSERT(pn->pn_cookie.isFree());
 
             JSDefinition *dn = pn->pn_lexdef;
-            JS_ASSERT(dn->pn_defn);
+            JS_ASSERT(dn->isDefn());
 
             /*
              * Adjust the definition's block id only if it is a placeholder not
              * to the left of the root node, and if pn is the last use visited
              * in the comprehension expression (to avoid adjusting the blockid
              * multiple times).
              *
              * Non-placeholder definitions within the comprehension expression
@@ -6933,17 +6929,17 @@ CompExprTransplanter::transplant(JSParse
                 AdjustBlockId(dn, adjust, tc);
             }
 
             JSAtom *atom = pn->pn_atom;
 #ifdef DEBUG
             JSStmtInfo *stmt = js_LexicalLookup(tc, atom, NULL);
             JS_ASSERT(!stmt || stmt != tc->topStmt);
 #endif
-            if (genexp && PN_OP(dn) != JSOP_CALLEE) {
+            if (genexp && !dn->isOp(JSOP_CALLEE)) {
                 JS_ASSERT(!tc->decls.lookupFirst(atom));
 
                 if (dn->pn_pos < root->pn_pos) {
                     /*
                      * The variable originally appeared to be a use of a
                      * definition or placeholder outside the generator, but now
                      * we know it is scoped within the comprehension tail's
                      * clauses. Make it (along with any other uses within the
@@ -7071,17 +7067,17 @@ Parser::comprehensionTail(JSParseNode *k
          * FOR node is binary, left is loop control and right is body.  Use
          * index to count each block-local let-variable on the left-hand side
          * of the IN.
          */
         pn2 = BinaryNode::create(tc);
         if (!pn2)
             return NULL;
 
-        pn2->pn_op = JSOP_ITER;
+        pn2->setOp(JSOP_ITER);
         pn2->pn_iflags = JSITER_ENUMERATE;
         if (tokenStream.matchToken(TOK_NAME)) {
             if (tokenStream.currentToken().t_atom == context->runtime->atomState.eachAtom)
                 pn2->pn_iflags |= JSITER_FOREACH;
             else
                 tokenStream.ungetToken();
         }
         MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
@@ -7144,22 +7140,22 @@ Parser::comprehensionTail(JSParseNode *k
 #if JS_HAS_DESTRUCTURING
           case TOK_LB:
           case TOK_LC:
             if (!CheckDestructuring(context, &data, pn3, tc))
                 return NULL;
 
             if (versionNumber() == JSVERSION_1_7) {
                 /* Destructuring requires [key, value] enumeration in JS1.7. */
-                if (pn3->pn_type != TOK_RB || pn3->pn_count != 2) {
+                if (!pn3->isKind(TOK_RB) || pn3->pn_count != 2) {
                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_FOR_LEFTSIDE);
                     return NULL;
                 }
 
-                JS_ASSERT(pn2->pn_op == JSOP_ITER);
+                JS_ASSERT(pn2->isOp(JSOP_ITER));
                 JS_ASSERT(pn2->pn_iflags & JSITER_ENUMERATE);
                 if (!(pn2->pn_iflags & JSITER_FOREACH))
                     pn2->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
             }
             break;
 #endif
 
           case TOK_NAME:
@@ -7173,18 +7169,18 @@ Parser::comprehensionTail(JSParseNode *k
 
         /*
          * Synthesize a declaration. Every definition must appear in the parse
          * tree in order for ComprehensionTranslator to work.
          */
         JSParseNode *vars = ListNode::create(tc);
         if (!vars)
             return NULL;
-        vars->pn_op = JSOP_NOP;
-        vars->pn_type = TOK_VAR;
+        vars->setOp(JSOP_NOP);
+        vars->setKind(TOK_VAR);
         vars->pn_pos = pn3->pn_pos;
         vars->makeEmpty();
         vars->append(pn3);
         vars->pn_xflags |= PNX_FORINVAR;
 
         /* Definitions can't be passed directly to EmitAssignment as lhs. */
         pn3 = CloneLeftHandSide(pn3, tc);
         if (!pn3)
@@ -7206,18 +7202,18 @@ Parser::comprehensionTail(JSParseNode *k
             return NULL;
         *pnp = pn2;
         pnp = &pn2->pn_kid2;
     }
 
     pn2 = UnaryNode::create(tc);
     if (!pn2)
         return NULL;
-    pn2->pn_type = type;
-    pn2->pn_op = op;
+    pn2->setKind(type);
+    pn2->setOp(op);
     pn2->pn_kid = kid;
     *pnp = pn2;
 
     PopStatement(tc);
     return pn;
 }
 
 #if JS_HAS_GENERATOR_EXPRS
@@ -7239,29 +7235,29 @@ Parser::comprehensionTail(JSParseNode *k
  */
 JSParseNode *
 Parser::generatorExpr(JSParseNode *kid)
 {
     /* Create a |yield| node for |kid|. */
     JSParseNode *pn = UnaryNode::create(tc);
     if (!pn)
         return NULL;
-    pn->pn_type = TOK_YIELD;
-    pn->pn_op = JSOP_YIELD;
-    pn->pn_parens = true;
+    pn->setKind(TOK_YIELD);
+    pn->setOp(JSOP_YIELD);
+    pn->setInParens(true);
     pn->pn_pos = kid->pn_pos;
     pn->pn_kid = kid;
     pn->pn_hidden = true;
 
     /* Make a new node for the desugared generator function. */
     JSParseNode *genfn = FunctionNode::create(tc);
     if (!genfn)
         return NULL;
-    genfn->pn_type = TOK_FUNCTION;
-    genfn->pn_op = JSOP_LAMBDA;
+    genfn->setKind(TOK_FUNCTION);
+    genfn->setOp(JSOP_LAMBDA);
     JS_ASSERT(!genfn->pn_body);
     genfn->pn_dflags = PND_FUNARG;
 
     {
         JSTreeContext *outertc = tc;
         JSTreeContext gentc(tc->parser);
         if (!gentc.init(context))
             return NULL;
@@ -7310,18 +7306,18 @@ Parser::generatorExpr(JSParseNode *kid)
 
     /*
      * Our result is a call expression that invokes the anonymous generator
      * function object.
      */
     JSParseNode *result = ListNode::create(tc);
     if (!result)
         return NULL;
-    result->pn_type = TOK_LP;
-    result->pn_op = JSOP_CALL;
+    result->setKind(TOK_LP);
+    result->setOp(JSOP_CALL);
     result->pn_pos.begin = genfn->pn_pos.begin;
     result->initList(genfn);
     return result;
 }
 
 static const char js_generator_str[] = "generator";
 
 #endif /* JS_HAS_GENERATOR_EXPRS */
@@ -7339,18 +7335,18 @@ Parser::argumentList(JSParseNode *listNo
     do {
         JSParseNode *argNode = assignExpr();
         if (!argNode)
             return JS_FALSE;
         if (arg0)
             guard.endBody();
 
 #if JS_HAS_GENERATORS
-        if (argNode->pn_type == TOK_YIELD &&
-            !argNode->pn_parens &&
+        if (argNode->isKind(TOK_YIELD) &&
+            !argNode->isInParens() &&
             tokenStream.peekToken() == TOK_COMMA) {
             reportErrorNumber(argNode, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
             return JS_FALSE;
         }
 #endif
 #if JS_HAS_GENERATOR_EXPRS
         if (tokenStream.matchToken(TOK_FOR)) {
             if (!guard.checkValidBody(argNode))
@@ -7380,18 +7376,18 @@ Parser::argumentList(JSParseNode *listNo
     }
     return JS_TRUE;
 }
 
 /* Check for an immediately-applied (new'ed) lambda and clear PND_FUNARG. */
 static JSParseNode *
 CheckForImmediatelyAppliedLambda(JSParseNode *pn)
 {
-    if (pn->pn_type == TOK_FUNCTION) {
-        JS_ASSERT(pn->pn_arity == PN_FUNC);
+    if (pn->isKind(TOK_FUNCTION)) {
+        JS_ASSERT(pn->isArity(PN_FUNC));
 
         JSFunctionBox *funbox = pn->pn_funbox;
         JS_ASSERT((funbox->function())->flags & JSFUN_LAMBDA);
         if (!(funbox->tcflags & (TCF_FUN_USES_ARGUMENTS | TCF_FUN_USES_OWN_NAME)))
             pn->pn_dflags &= ~PND_FUNARG;
     }
     return pn;
 }
@@ -7408,44 +7404,42 @@ Parser::memberExpr(JSBool allowCallSynta
     if (tt == TOK_NEW) {
         pn = ListNode::create(tc);
         if (!pn)
             return NULL;
         pn2 = memberExpr(JS_FALSE);
         if (!pn2)
             return NULL;
         pn2 = CheckForImmediatelyAppliedLambda(pn2);
-        pn->pn_op = JSOP_NEW;
+        pn->setOp(JSOP_NEW);
         pn->initList(pn2);
         pn->pn_pos.begin = pn2->pn_pos.begin;
 
         if (tokenStream.matchToken(TOK_LP) && !argumentList(pn))
             return NULL;
         if (pn->pn_count > ARGC_LIMIT) {
             JS_ReportErrorNumber(context, js_GetErrorMessage, NULL,
                                  JSMSG_TOO_MANY_CON_ARGS);
             return NULL;
         }
         pn->pn_pos.end = pn->last()->pn_pos.end;
     } else {
         pn = primaryExpr(tt, JS_FALSE);
         if (!pn)
             return NULL;
 
-        if (pn->pn_type == TOK_ANYNAME ||
-            pn->pn_type == TOK_AT ||
-            pn->pn_type == TOK_DBLCOLON) {
+        if (pn->isKind(TOK_ANYNAME) || pn->isKind(TOK_AT) || pn->isKind(TOK_DBLCOLON)) {
             pn2 = NewOrRecycledNode(tc);
             if (!pn2)
                 return NULL;
-            pn2->pn_type = TOK_UNARYOP;
+            pn2->setKind(TOK_UNARYOP);
             pn2->pn_pos = pn->pn_pos;
-            pn2->pn_op = JSOP_XMLNAME;
-            pn2->pn_arity = PN_UNARY;
-            pn2->pn_parens = false;
+            pn2->setOp(JSOP_XMLNAME);
+            pn2->setArity(PN_UNARY);
+            pn2->setInParens(false);
             pn2->pn_kid = pn;
             pn = pn2;
         }
     }
 
     while ((tt = tokenStream.getToken()) > TOK_EOF) {
         if (tt == TOK_DOT) {
             pn2 = NameNode::create(NULL, tc);
@@ -7467,66 +7461,66 @@ Parser::memberExpr(JSBool allowCallSynta
                 return NULL;
 
             if (tt == TOK_LP) {
                 tc->innermostWith = oldWith;
                 PopStatement(tc);
             }
 
             /* Check both tt and pn_type, to distinguish |x.(y)| and |x.y::z| from |x.y|. */
-            if (tt == TOK_NAME && pn3->pn_type == TOK_NAME) {
-                pn2->pn_op = JSOP_GETPROP;
+            if (tt == TOK_NAME && pn3->isKind(TOK_NAME)) {
+                pn2->setOp(JSOP_GETPROP);
                 pn2->pn_expr = pn;
                 pn2->pn_atom = pn3->pn_atom;
                 RecycleTree(pn3, tc);
             } else {
                 if (tt == TOK_LP) {
-                    pn2->pn_type = TOK_FILTER;
-                    pn2->pn_op = JSOP_FILTER;
+                    pn2->setKind(TOK_FILTER);
+                    pn2->setOp(JSOP_FILTER);
 
                     /* A filtering predicate is like a with statement. */
                     tc->flags |= TCF_FUN_HEAVYWEIGHT;
-                } else if (TokenKindIsXML(PN_TYPE(pn3))) {
-                    pn2->pn_type = TOK_LB;
-                    pn2->pn_op = JSOP_GETELEM;
+                } else if (TokenKindIsXML(pn3->getKind())) {
+                    pn2->setKind(TOK_LB);
+                    pn2->setOp(JSOP_GETELEM);
                 } else {
                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT);
                     return NULL;
                 }
-                pn2->pn_arity = PN_BINARY;
+                pn2->setArity(PN_BINARY);
                 pn2->pn_left = pn;
                 pn2->pn_right = pn3;
             }
 #else
             MUST_MATCH_TOKEN_WITH_FLAGS(TOK_NAME, JSMSG_NAME_AFTER_DOT, TSF_KEYWORD_IS_NAME);
-            pn2->pn_op = JSOP_GETPROP;
+            pn2->setOp(JSOP_GETPROP);
             pn2->pn_expr = pn;
             pn2->pn_atom = tokenStream.currentToken().t_atom;
 #endif
             pn2->pn_pos.begin = pn->pn_pos.begin;
             pn2->pn_pos.end = tokenStream.currentToken().pos.end;
 #if JS_HAS_XML_SUPPORT
         } else if (tt == TOK_DBLDOT) {
             pn2 = BinaryNode::create(tc);
             if (!pn2)
                 return NULL;
             tt = tokenStream.getToken(TSF_OPERAND | TSF_KEYWORD_IS_NAME);
             pn3 = primaryExpr(tt, JS_TRUE);
             if (!pn3)
                 return NULL;
-            tt = PN_TYPE(pn3);
-            if (tt == TOK_NAME && !pn3->pn_parens) {
-                pn3->pn_type = TOK_STRING;
-                pn3->pn_arity = PN_NULLARY;
-                pn3->pn_op = JSOP_QNAMEPART;
+            tt = pn3->getKind();
+            if (tt == TOK_NAME && !pn3->isInParens()) {
+                pn3->setKind(TOK_STRING);
+                pn3->setArity(PN_NULLARY);
+                pn3->setOp(JSOP_QNAMEPART);
             } else if (!TokenKindIsXML(tt)) {
                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT);
                 return NULL;
             }
-            pn2->pn_op = JSOP_DESCENDANTS;
+            pn2->setOp(JSOP_DESCENDANTS);
             pn2->pn_left = pn;
             pn2->pn_right = pn3;
             pn2->pn_pos.begin = pn->pn_pos.begin;
             pn2->pn_pos.end = tokenStream.currentToken().pos.end;
 #endif
         } else if (tt == TOK_LB) {
             pn2 = BinaryNode::create(tc);
             if (!pn2)
@@ -7542,61 +7536,61 @@ Parser::memberExpr(JSBool allowCallSynta
             /*
              * Optimize o['p'] to o.p by rewriting pn2, but avoid rewriting
              * o['0'] to use JSOP_GETPROP, to keep fast indexing disjoint in
              * the interpreter from fast property access. However, if the
              * bracketed string is a uint32, we rewrite pn3 to be a number
              * instead of a string.
              */
             do {
-                if (pn3->pn_type == TOK_STRING) {
+                if (pn3->isKind(TOK_STRING)) {
                     jsuint index;
 
                     if (!js_IdIsIndex(ATOM_TO_JSID(pn3->pn_atom), &index)) {
-                        pn2->pn_type = TOK_DOT;
-                        pn2->pn_op = JSOP_GETPROP;
-                        pn2->pn_arity = PN_NAME;
+                        pn2->setKind(TOK_DOT);
+                        pn2->setOp(JSOP_GETPROP);
+                        pn2->setArity(PN_NAME);
                         pn2->pn_expr = pn;
                         pn2->pn_atom = pn3->pn_atom;
                         break;
                     }
-                    pn3->pn_type = TOK_NUMBER;
-                    pn3->pn_op = JSOP_DOUBLE;
+                    pn3->setKind(TOK_NUMBER);
+                    pn3->setOp(JSOP_DOUBLE);
                     pn3->pn_dval = index;
                 }
-                pn2->pn_op = JSOP_GETELEM;
+                pn2->setOp(JSOP_GETELEM);
                 pn2->pn_left = pn;
                 pn2->pn_right = pn3;
             } while (0);
         } else if (allowCallSyntax && tt == TOK_LP) {
             pn2 = ListNode::create(tc);
             if (!pn2)
                 return NULL;
-            pn2->pn_op = JSOP_CALL;
+            pn2->setOp(JSOP_CALL);
 
             pn = CheckForImmediatelyAppliedLambda(pn);
-            if (pn->pn_op == JSOP_NAME) {
+            if (pn->isOp(JSOP_NAME)) {
                 if (pn->pn_atom == context->runtime->atomState.evalAtom) {
                     /* Select JSOP_EVAL and flag tc as heavyweight. */
-                    pn2->pn_op = JSOP_EVAL;
+                    pn2->setOp(JSOP_EVAL);
                     tc->noteCallsEval();
                     tc->flags |= TCF_FUN_HEAVYWEIGHT;
                     /*
                      * In non-strict mode code, direct calls to eval can add
                      * variables to the call object.
                      */
                     if (!tc->inStrictMode())
                         tc->noteHasExtensibleScope();
                 }
-            } else if (pn->pn_op == JSOP_GETPROP) {
+            } else if (pn->isOp(JSOP_GETPROP)) {
                 /* Select JSOP_FUNAPPLY given foo.apply(...). */
                 if (pn->pn_atom == context->runtime->atomState.applyAtom)
-                    pn2->pn_op = JSOP_FUNAPPLY;
+                    pn2->setOp(JSOP_FUNAPPLY);
                 else if (pn->pn_atom == context->runtime->atomState.callAtom)
-                    pn2->pn_op = JSOP_FUNCALL;
+                    pn2->setOp(JSOP_FUNCALL);
             }
 
             pn2->initList(pn);
             pn2->pn_pos.begin = pn->pn_pos.begin;
 
             if (!argumentList(pn2))
                 return NULL;
             if (pn2->pn_count > ARGC_LIMIT) {
@@ -7704,24 +7698,24 @@ Parser::endBracketedExpr()
 JSParseNode *
 Parser::propertySelector()
 {
     JSParseNode *pn;
 
     pn = NullaryNode::create(tc);
     if (!pn)
         return NULL;
-    if (pn->pn_type == TOK_STAR) {
-        pn->pn_type = TOK_ANYNAME;
-        pn->pn_op = JSOP_ANYNAME;
+    if (pn->isKind(TOK_STAR)) {
+        pn->setKind(TOK_ANYNAME);
+        pn->setOp(JSOP_ANYNAME);
         pn->pn_atom = context->runtime->atomState.starAtom;
     } else {
-        JS_ASSERT(pn->pn_type == TOK_NAME);
-        pn->pn_op = JSOP_QNAMEPART;
-        pn->pn_arity = PN_NAME;
+        JS_ASSERT(pn->isKind(TOK_NAME));
+        pn->setOp(JSOP_QNAMEPART);
+        pn->setArity(PN_NAME);
         pn->pn_atom = tokenStream.currentToken().t_atom;
         pn->pn_cookie.makeFree();
     }
     return pn;
 }
 
 JSParseNode *
 Parser::qualifiedSuffix(JSParseNode *pn)
@@ -7730,23 +7724,23 @@ Parser::qualifiedSuffix(JSParseNode *pn)
     TokenKind tt;
 
     JS_ASSERT(tokenStream.currentToken().type == TOK_DBLCOLON);
     pn2 = NameNode::create(NULL, tc);
     if (!pn2)
         return NULL;
 
     /* Left operand of :: must be evaluated if it is an identifier. */
-    if (pn->pn_op == JSOP_QNAMEPART)
-        pn->pn_op = JSOP_NAME;
+    if (pn->isOp(JSOP_QNAMEPART))
+        pn->setOp(JSOP_NAME);
 
     tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
     if (tt == TOK_STAR || tt == TOK_NAME) {
         /* Inline and specialize propertySelector for JSOP_QNAMECONST. */
-        pn2->pn_op = JSOP_QNAMECONST;
+        pn2->setOp(JSOP_QNAMECONST);
         pn2->pn_pos.begin = pn->pn_pos.begin;
         pn2->pn_atom = (tt == TOK_STAR)
                        ? context->runtime->atomState.starAtom
                        : tokenStream.currentToken().t_atom;
         pn2->pn_expr = pn;
         pn2->pn_cookie.makeFree();
         return pn2;
     }
@@ -7754,18 +7748,18 @@ Parser::qualifiedSuffix(JSParseNode *pn)
     if (tt != TOK_LB) {
         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
         return NULL;
     }
     pn3 = endBracketedExpr();
     if (!pn3)
         return NULL;
 
-    pn2->pn_op = JSOP_QNAME;
-    pn2->pn_arity = PN_BINARY;
+    pn2->setOp(JSOP_QNAME);
+    pn2->setArity(PN_BINARY);
     pn2->pn_pos.begin = pn->pn_pos.begin;
     pn2->pn_pos.end = pn3->pn_pos.end;
     pn2->pn_left = pn;
     pn2->pn_right = pn3;
     return pn2;
 }
 
 JSParseNode *
@@ -7789,17 +7783,17 @@ Parser::attributeIdentifier()
 {
     JSParseNode *pn, *pn2;
     TokenKind tt;
 
     JS_ASSERT(tokenStream.currentToken().type == TOK_AT);
     pn = UnaryNode::create(tc);
     if (!pn)
         return NULL;
-    pn->pn_op = JSOP_TOATTRNAME;
+    pn->setOp(JSOP_TOATTRNAME);
     tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
     if (tt == TOK_STAR || tt == TOK_NAME) {
         pn2 = qualifiedIdentifier();
     } else if (tt == TOK_LB) {
         pn2 = endBracketedExpr();
     } else {
         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
         return NULL;
@@ -7833,34 +7827,34 @@ Parser::xmlExpr(JSBool inTag)
     tokenStream.setXMLTagMode(false);
     pn2 = expr();
     if (!pn2)
         return NULL;
 
     MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_XML_EXPR);
     tokenStream.setXMLTagMode(oldflag);
     pn->pn_kid = pn2;
-    pn->pn_op = inTag ? JSOP_XMLTAGEXPR : JSOP_XMLELTEXPR;
+    pn->setOp(inTag ? JSOP_XMLTAGEXPR : JSOP_XMLELTEXPR);
     return pn;
 }
 
 /*
  * Make a terminal node for one of TOK_XMLNAME, TOK_XMLATTR, TOK_XMLSPACE,
  * TOK_XMLTEXT, TOK_XMLCDATA, TOK_XMLCOMMENT, or TOK_XMLPI.  When converting
  * parse tree to XML, we preserve a TOK_XMLSPACE node only if it's the sole
  * child of a container tag.
  */
 JSParseNode *
 Parser::xmlAtomNode()
 {
     JSParseNode *pn = NullaryNode::create(tc);
     if (!pn)
         return NULL;
     const Token &tok = tokenStream.currentToken();
-    pn->pn_op = tok.t_op;
+    pn->setOp(tok.t_op);
     pn->pn_atom = tok.t_atom;
     if (tok.type == TOK_XMLPI)
         pn->pn_atom2 = tok.t_atom2;
     return pn;
 }
 
 /*
  * Parse the productions:
@@ -7896,17 +7890,17 @@ Parser::xmlNameExpr()
 
         if (!pn) {
             pn = pn2;
         } else {
             if (!list) {
                 list = ListNode::create(tc);
                 if (!list)
                     return NULL;
-                list->pn_type = TOK_XMLNAME;
+                list->setKind(TOK_XMLNAME);
                 list->pn_pos.begin = pn->pn_pos.begin;
                 list->initList(pn);
                 list->pn_xflags = PNX_CANTFOLD;
                 pn = list;
             }
             pn->pn_pos.end = pn2->pn_pos.end;
             pn->append(pn2);
         }
@@ -7915,19 +7909,19 @@ Parser::xmlNameExpr()
     tokenStream.ungetToken();
     return pn;
 }
 
 /*
  * Macro to test whether an XMLNameExpr or XMLTagContent node can be folded
  * at compile time into a JSXML tree.
  */
-#define XML_FOLDABLE(pn)        ((pn)->pn_arity == PN_LIST                    \
-                                 ? ((pn)->pn_xflags & PNX_CANTFOLD) == 0      \
-                                 : (pn)->pn_type != TOK_LC)
+#define XML_FOLDABLE(pn)        ((pn)->isArity(PN_LIST)                     \
+                                 ? ((pn)->pn_xflags & PNX_CANTFOLD) == 0    \
+                                 : !(pn)->isKind(TOK_LC))
 
 /*
  * Parse the productions:
  *
  *      XMLTagContent:
  *              XMLNameExpr
  *              XMLTagContent S XMLNameExpr S? = S? XMLAttr
  *              XMLTagContent S XMLNameExpr S? = S? { Expr }
@@ -7945,34 +7939,34 @@ JSParseNode *
 Parser::xmlTagContent(TokenKind tagtype, JSAtom **namep)
 {
     JSParseNode *pn, *pn2, *list;
     TokenKind tt;
 
     pn = xmlNameExpr();
     if (!pn)
         return NULL;
-    *namep = (pn->pn_arity == PN_NULLARY) ? pn->pn_atom : NULL;
+    *namep = (pn->isArity(PN_NULLARY)) ? pn->pn_atom : NULL;
     list = NULL;
 
     while (tokenStream.matchToken(TOK_XMLSPACE)) {
         tt = tokenStream.getToken();
         if (tt != TOK_XMLNAME && tt != TOK_LC) {
             tokenStream.ungetToken();
             break;
         }
 
         pn2 = xmlNameExpr();
         if (!pn2)
             return NULL;
         if (!list) {
             list = ListNode::create(tc);
             if (!list)
                 return NULL;
-            list->pn_type = tagtype;
+            list->setKind(tagtype);
             list->pn_pos.begin = pn->pn_pos.begin;
             list->initList(pn);
             pn = list;
         }
         pn->append(pn2);
         if (!XML_FOLDABLE(pn2))
             pn->pn_xflags |= PNX_CANTFOLD;
 
@@ -8092,50 +8086,50 @@ Parser::xmlElementOrList(JSBool allowLis
         pn2 = xmlTagContent(TOK_XMLSTAGO, &startAtom);
         if (!pn2)
             return NULL;
         tokenStream.matchToken(TOK_XMLSPACE);
 
         tt = tokenStream.getToken();
         if (tt == TOK_XMLPTAGC) {
             /* Point tag (/>): recycle pn if pn2 is a list of tag contents. */
-            if (pn2->pn_type == TOK_XMLSTAGO) {
+            if (pn2->isKind(TOK_XMLSTAGO)) {
                 pn->makeEmpty();
                 RecycleTree(pn, tc);
                 pn = pn2;
             } else {
-                JS_ASSERT(pn2->pn_type == TOK_XMLNAME ||
-                          pn2->pn_type == TOK_LC);
+                JS_ASSERT(pn2->isKind(TOK_XMLNAME) ||
+                          pn2->isKind(TOK_LC));
                 pn->initList(pn2);
                 if (!XML_FOLDABLE(pn2))
                     pn->pn_xflags |= PNX_CANTFOLD;
             }
-            pn->pn_type = TOK_XMLPTAGC;
+            pn->setKind(TOK_XMLPTAGC);
             pn->pn_xflags |= PNX_XMLROOT;
         } else {
             /* We had better have a tag-close (>) at this point. */
             if (tt != TOK_XMLTAGC) {
                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_TAG_SYNTAX);
                 return NULL;
             }
             pn2->pn_pos.end = tokenStream.currentToken().pos.end;
 
             /* Make sure pn2 is a TOK_XMLSTAGO list containing tag contents. */
-            if (pn2->pn_type != TOK_XMLSTAGO) {
+            if (!pn2->isKind(TOK_XMLSTAGO)) {
                 pn->initList(pn2);
                 if (!XML_FOLDABLE(pn2))
                     pn->pn_xflags |= PNX_CANTFOLD;
                 pn2 = pn;
                 pn = ListNode::create(tc);
                 if (!pn)
                     return NULL;
             }
 
             /* Now make pn a nominal-root TOK_XMLELEM list containing pn2. */
-            pn->pn_type = TOK_XMLELEM;
+            pn->setKind(TOK_XMLELEM);
             pn->pn_pos.begin = pn2->pn_pos.begin;
             pn->initList(pn2);
             if (!XML_FOLDABLE(pn2))
                 pn->pn_xflags |= PNX_CANTFOLD;
             pn->pn_xflags |= PNX_XMLROOT;
 
             /* Get element contents and delimiting end-tag-open sequence. */
             if (!xmlElementContent(pn))
@@ -8147,51 +8141,51 @@ Parser::xmlElementOrList(JSBool allowLis
                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_TAG_SYNTAX);
                 return NULL;
             }
 
             /* Parse end tag; check mismatch at compile-time if we can. */
             pn2 = xmlTagContent(TOK_XMLETAGO, &endAtom);
             if (!pn2)
                 return NULL;
-            if (pn2->pn_type == TOK_XMLETAGO) {
+            if (pn2->isKind(TOK_XMLETAGO)) {
                 /* Oops, end tag has attributes! */
                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_TAG_SYNTAX);
                 return NULL;
             }
             if (endAtom && startAtom && endAtom != startAtom) {
                 /* End vs. start tag name mismatch: point to the tag name. */
                 reportErrorNumber(pn2, JSREPORT_UC | JSREPORT_ERROR, JSMSG_XML_TAG_NAME_MISMATCH,
                                   startAtom->chars());
                 return NULL;
             }
 
             /* Make a TOK_XMLETAGO list with pn2 as its single child. */
-            JS_ASSERT(pn2->pn_type == TOK_XMLNAME || pn2->pn_type == TOK_LC);
+            JS_ASSERT(pn2->isKind(TOK_XMLNAME) || pn2->isKind(TOK_LC));
             list = ListNode::create(tc);
             if (!list)
                 return NULL;
-            list->pn_type = TOK_XMLETAGO;
+            list->setKind(TOK_XMLETAGO);
             list->initList(pn2);
             pn->append(list);
             if (!XML_FOLDABLE(pn2)) {
                 list->pn_xflags |= PNX_CANTFOLD;
                 pn->pn_xflags |= PNX_CANTFOLD;
             }
 
             tokenStream.matchToken(TOK_XMLSPACE);
             MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_TAG_SYNTAX);
         }
 
         /* Set pn_op now that pn has been updated to its final value. */
-        pn->pn_op = JSOP_TOXML;
+        pn->setOp(JSOP_TOXML);
     } else if (allowList && tt == TOK_XMLTAGC) {
         /* XMLList Initialiser. */
-        pn->pn_type = TOK_XMLLIST;
-        pn->pn_op = JSOP_TOXMLLIST;
+        pn->setKind(TOK_XMLLIST);
+        pn->setOp(JSOP_TOXMLLIST);
         pn->makeEmpty();
         pn->pn_xflags |= PNX_XMLROOT;
         if (!xmlElementContent(pn))
             return NULL;
 
         MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_LIST_SYNTAX);
     } else {
         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_NAME_SYNTAX);
@@ -8297,17 +8291,17 @@ JSParseNode::isConstant()
           case JSOP_FALSE:
           case JSOP_TRUE:
             return true;
           default:
             return false;
         }
       case TOK_RB:
       case TOK_RC:
-        return (pn_op == JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST);
+        return isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST);
       default:
         return false;
     }
 }
 
 JSParseNode *
 Parser::primaryExpr(TokenKind tt, JSBool afterDot)
 {
@@ -8318,17 +8312,17 @@ Parser::primaryExpr(TokenKind tt, JSBool
 
     switch (tt) {
       case TOK_FUNCTION:
 #if JS_HAS_XML_SUPPORT
         if (tokenStream.matchToken(TOK_DBLCOLON, TSF_KEYWORD_IS_NAME)) {
             pn2 = NullaryNode::create(tc);
             if (!pn2)
                 return NULL;
-            pn2->pn_type = TOK_FUNCTION;
+            pn2->setKind(TOK_FUNCTION);
             pn = qualifiedSuffix(pn2);
             if (!pn)
                 return NULL;
             break;
         }
 #endif
         pn = functionExpr();
         if (!pn)
@@ -8338,18 +8332,18 @@ Parser::primaryExpr(TokenKind tt, JSBool
       case TOK_LB:
       {
         JSBool matched;
         jsuint index;
 
         pn = ListNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_type = TOK_RB;
-        pn->pn_op = JSOP_NEWINIT;
+        pn->setKind(TOK_RB);
+        pn->setOp(JSOP_NEWINIT);
         pn->makeEmpty();
 
 #if JS_HAS_GENERATORS
         pn->pn_blockid = tc->blockidGen;
 #endif
 
         matched = tokenStream.matchToken(TOK_RB, TSF_OPERAND);
         if (!matched) {
@@ -8427,17 +8421,17 @@ Parser::primaryExpr(TokenKind tt, JSBool
              * The array comprehension iteration step, array.push(i * j) in
              * the example above, is done by <i * j>; JSOP_ARRAYCOMP <array>,
              * where <array> is the index of array's stack slot.
              */
             if (index == 0 && pn->pn_count != 0 && tokenStream.matchToken(TOK_FOR)) {
                 JSParseNode *pnexp, *pntop;
 
                 /* Relabel pn as an array comprehension node. */
-                pn->pn_type = TOK_ARRAYCOMP;
+                pn->setKind(TOK_ARRAYCOMP);
 
                 /*
                  * Remove the comprehension expression from pn's linked list
                  * and save it via pnexp.  We'll re-install it underneath the
                  * ARRAYPUSH node after we parse the rest of the comprehension.
                  */
                 pnexp = pn->last();
                 JS_ASSERT(pn->pn_count == 1);
@@ -8473,18 +8467,18 @@ Parser::primaryExpr(TokenKind tt, JSBool
             GET     = 0x1,
             SET     = 0x2,
             VALUE   = 0x4 | GET | SET
         };
 
         pn = ListNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_type = TOK_RC;
-        pn->pn_op = JSOP_NEWINIT;
+        pn->setKind(TOK_RC);
+        pn->setOp(JSOP_NEWINIT);
         pn->makeEmpty();
 
         for (;;) {
             JSAtom *atom;
             tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
             switch (tt) {
               case TOK_NUMBER:
                 pn3 = NullaryNode::create(tc);
@@ -8569,18 +8563,18 @@ Parser::primaryExpr(TokenKind tt, JSBool
 
                 /*
                  * Support, e.g., |var {x, y} = o| as destructuring shorthand
                  * for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8.
                  */
                 tokenStream.ungetToken();
                 pn->pn_xflags |= PNX_DESTRUCT | PNX_NONCONST;
                 pnval = pn3;
-                if (pnval->pn_type == TOK_NAME) {
-                    pnval->pn_arity = PN_NAME;
+                if (pnval->isKind(TOK_NAME)) {
+                    pnval->setArity(PN_NAME);
                     ((NameNode *)pnval)->initCommon(tc);
                 }
 #endif
             }
 
             pn2 = JSParseNode::newBinaryOrAppend(TOK_COLON, op, pn3, pnval, tc);
           skip:
             if (!pn2)
@@ -8660,21 +8654,21 @@ Parser::primaryExpr(TokenKind tt, JSBool
         pn = UnaryNode::create(tc);
         if (!pn)
             return NULL;
         pn->pn_num = (jsint) tokenStream.currentToken().t_dval;
         tt = tokenStream.getToken(TSF_OPERAND);
         pn->pn_kid = primaryExpr(tt, JS_FALSE);
         if (!pn->pn_kid)
             return NULL;
-        if (PN_TYPE(pn->pn_kid) == TOK_USESHARP ||
-            PN_TYPE(pn->pn_kid) == TOK_DEFSHARP ||
-            PN_TYPE(pn->pn_kid) == TOK_STRING ||
-            PN_TYPE(pn->pn_kid) == TOK_NUMBER ||
-            PN_TYPE(pn->pn_kid) == TOK_PRIMARY) {
+        if (pn->pn_kid->isKind(TOK_USESHARP) ||
+            pn->pn_kid->isKind(TOK_DEFSHARP) ||
+            pn->pn_kid->isKind(TOK_STRING) ||
+            pn->pn_kid->isKind(TOK_NUMBER) ||
+            pn->pn_kid->isKind(TOK_PRIMARY)) {
             reportErrorNumber(pn->pn_kid, JSREPORT_ERROR, JSMSG_BAD_SHARP_VAR_DEF);
             return NULL;
         }
         if (!tc->ensureSharpSlots())
             return NULL;
         break;
 
       case TOK_USESHARP:
@@ -8690,17 +8684,17 @@ Parser::primaryExpr(TokenKind tt, JSBool
 
       case TOK_LP:
       {
         JSBool genexp;
 
         pn = parenExpr(&genexp);
         if (!pn)
             return NULL;
-        pn->pn_parens = true;
+        pn->setInParens(true);
         if (!genexp)
             MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
         break;
       }
 
 #if JS_HAS_XML_SUPPORT
       case TOK_STAR:
         pn = qualifiedIdentifier();
@@ -8735,25 +8729,25 @@ Parser::primaryExpr(TokenKind tt, JSBool
         if (!pn)
             return NULL;
         pn->pn_atom = tokenStream.currentToken().t_atom;
 #if JS_HAS_XML_SUPPORT
         if (tt == TOK_XMLPI)
             pn->pn_atom2 = tokenStream.currentToken().t_atom2;
         else
 #endif
-            pn->pn_op = tokenStream.currentToken().t_op;
+            pn->setOp(tokenStream.currentToken().t_op);
         break;
 
       case TOK_NAME:
         pn = NameNode::create(tokenStream.currentToken().t_atom, tc);
         if (!pn)
             return NULL;
         JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NAME);
-        pn->pn_op = JSOP_NAME;
+        pn->setOp(JSOP_NAME);
 
         if ((tc->flags & (TCF_IN_FUNCTION | TCF_FUN_PARAM_ARGUMENTS)) == TCF_IN_FUNCTION &&
             pn->pn_atom == context->runtime->atomState.argumentsAtom) {
             /*
              * Flag arguments usage so we can avoid unsafe optimizations such
              * as formal parameter assignment analysis (because of the hated
              * feature whereby arguments alias formals). We do this even for
              * a reference of the form foo.arguments, which ancient code may
@@ -8762,17 +8756,17 @@ Parser::primaryExpr(TokenKind tt, JSBool
             tc->noteArgumentsUse(pn);
 
             /*
              * Bind early to JSOP_ARGUMENTS to relieve later code from having
              * to do this work (new rule for the emitter to count on).
              */
             if (!afterDot && !(tc->flags & TCF_DECL_DESTRUCTURING)
                 && !tc->inStatement(STMT_WITH)) {
-                pn->pn_op = JSOP_ARGUMENTS;
+                pn->setOp(JSOP_ARGUMENTS);
                 pn->pn_dflags |= PND_BOUND;
             }
         } else if ((!afterDot
 #if JS_HAS_XML_SUPPORT
                     || tokenStream.peekToken() == TOK_DBLCOLON
 #endif
                    ) && !(tc->flags & TCF_DECL_DESTRUCTURING)) {
             /* In case this is a generator expression outside of any function. */
@@ -8834,17 +8828,17 @@ Parser::primaryExpr(TokenKind tt, JSBool
                      * necessary for safe context->display-based optimiza-
                      * tion of the closure's static link.
                      */
                     if (tokenStream.peekToken() != TOK_LP)
                         dn->pn_dflags |= PND_FUNARG;
                 }
             }
 
-            JS_ASSERT(dn->pn_defn);
+            JS_ASSERT(dn->isDefn());
             LinkUseToDef(pn, dn, tc);
 
             /* Here we handle the backward function reference case. */
             if (tokenStream.peekToken() != TOK_LP)
                 dn->pn_dflags |= PND_FUNARG;
 
             pn->pn_dflags |= (dn->pn_dflags & PND_FUNARG);
             if (stmt && stmt->type == STMT_WITH)
@@ -8861,18 +8855,18 @@ Parser::primaryExpr(TokenKind tt, JSBool
                  */
                 const KeywordInfo *ki = FindKeyword(pn->pn_atom->charsZ(), pn->pn_atom->length());
                 if (ki) {
                     if (ki->tokentype != TOK_FUNCTION) {
                         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_KEYWORD_NOT_NS);
                         return NULL;
                     }
 
-                    pn->pn_arity = PN_NULLARY;
-                    pn->pn_type = TOK_FUNCTION;
+                    pn->setArity(PN_NULLARY);
+                    pn->setKind(TOK_FUNCTION);
                 }
             }
             pn = qualifiedSuffix(pn);
             if (!pn)
                 return NULL;
         }
 #endif
         break;
@@ -8904,33 +8898,33 @@ Parser::primaryExpr(TokenKind tt, JSBool
             obj->clearParent();
             obj->clearType();
         }
 
         pn->pn_objbox = tc->parser->newObjectBox(obj);
         if (!pn->pn_objbox)
             return NULL;
 
-        pn->pn_op = JSOP_REGEXP;
+        pn->setOp(JSOP_REGEXP);
         break;
       }
 
       case TOK_NUMBER:
         pn = NullaryNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_op = JSOP_DOUBLE;
+        pn->setOp(JSOP_DOUBLE);
         pn->pn_dval = tokenStream.currentToken().t_dval;
         break;
 
       case TOK_PRIMARY:
         pn = NullaryNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_op = tokenStream.currentToken().t_op;
+        pn->setOp(tokenStream.currentToken().t_op);
         break;
 
       case TOK_ERROR:
         /* The scanner or one of its subroutines reported the error. */
         return NULL;
 
       default:
         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
@@ -8957,18 +8951,18 @@ Parser::parenExpr(JSBool *genexp)
     if (!pn)
         return NULL;
     guard.endBody();
 
 #if JS_HAS_GENERATOR_EXPRS
     if (tokenStream.matchToken(TOK_FOR)) {
         if (!guard.checkValidBody(pn))
             return NULL;
-        JS_ASSERT(pn->pn_type != TOK_YIELD);
-        if (pn->pn_type == TOK_COMMA && !pn->pn_parens) {
+        JS_ASSERT(!pn->isKind(TOK_YIELD));
+        if (pn->isKind(TOK_COMMA) && !pn->isInParens()) {
             reportErrorNumber(pn->last(), JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX,
                               js_generator_str);
             return NULL;
         }
         pn = generatorExpr(pn);
         if (!pn)
             return NULL;
         pn->pn_pos.begin = begin;
@@ -8992,39 +8986,39 @@ Parser::parenExpr(JSBool *genexp)
 
 /*
  * Fold from one constant type to another.
  * XXX handles only strings and numbers for now
  */
 static JSBool
 FoldType(JSContext *cx, JSParseNode *pn, TokenKind type)
 {
-    if (PN_TYPE(pn) != type) {
+    if (!pn->isKind(type)) {
         switch (type) {
           case TOK_NUMBER:
-            if (pn->pn_type == TOK_STRING) {
+            if (pn->isKind(TOK_STRING)) {
                 jsdouble d;
                 if (!ToNumber(cx, StringValue(pn->pn_atom), &d))
                     return JS_FALSE;
                 pn->pn_dval = d;
-                pn->pn_type = TOK_NUMBER;
-                pn->pn_op = JSOP_DOUBLE;
+                pn->setKind(TOK_NUMBER);
+                pn->setOp(JSOP_DOUBLE);
             }
             break;
 
           case TOK_STRING:
-            if (pn->pn_type == TOK_NUMBER) {
+            if (pn->isKind(TOK_NUMBER)) {
                 JSString *str = js_NumberToString(cx, pn->pn_dval);
                 if (!str)
                     return JS_FALSE;
                 pn->pn_atom = js_AtomizeString(cx, str);
                 if (!pn->pn_atom)
                     return JS_FALSE;
-                pn->pn_type = TOK_STRING;
-                pn->pn_op = JSOP_STRING;
+                pn->setKind(TOK_STRING);
+                pn->setOp(JSOP_STRING);
             }
             break;
 
           default:;
         }
     }
     return JS_TRUE;
 }
@@ -9036,17 +9030,17 @@ FoldType(JSContext *cx, JSParseNode *pn,
  */
 static JSBool
 FoldBinaryNumeric(JSContext *cx, JSOp op, JSParseNode *pn1, JSParseNode *pn2,
                   JSParseNode *pn, JSTreeContext *tc)
 {
     jsdouble d, d2;
     int32 i, j;
 
-    JS_ASSERT(pn1->pn_type == TOK_NUMBER && pn2->pn_type == TOK_NUMBER);
+    JS_ASSERT(pn1->isKind(TOK_NUMBER) && pn2->isKind(TOK_NUMBER));
     d = pn1->pn_dval;
     d2 = pn2->pn_dval;
     switch (op) {
       case JSOP_LSH:
       case JSOP_RSH:
         i = js_DoubleToECMAInt32(d);
         j = js_DoubleToECMAInt32(d2);
         j &= 31;
@@ -9101,35 +9095,35 @@ FoldBinaryNumeric(JSContext *cx, JSOp op
       default:;
     }
 
     /* Take care to allow pn1 or pn2 to alias pn. */
     if (pn1 != pn)
         RecycleTree(pn1, tc);
     if (pn2 != pn)
         RecycleTree(pn2, tc);
-    pn->pn_type = TOK_NUMBER;
-    pn->pn_op = JSOP_DOUBLE;
-    pn->pn_arity = PN_NULLARY;
+    pn->setKind(TOK_NUMBER);
+    pn->setOp(JSOP_DOUBLE);
+    pn->setArity(PN_NULLARY);
     pn->pn_dval = d;
     return JS_TRUE;
 }
 
 #if JS_HAS_XML_SUPPORT
 
 static JSBool
 FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
 {
     TokenKind tt;
     JSParseNode **pnp, *pn1, *pn2;
     JSString *accum, *str;
     uint32 i, j;
 
-    JS_ASSERT(pn->pn_arity == PN_LIST);
-    tt = PN_TYPE(pn);
+    JS_ASSERT(pn->isArity(PN_LIST));
+    tt = pn->getKind();
     pnp = &pn->pn_head;
     pn1 = *pnp;
     accum = NULL;
     str = NULL;
     if ((pn->pn_xflags & PNX_CANTFOLD) == 0) {
         if (tt == TOK_XMLETAGO)
             accum = cx->runtime->atomState.etagoAtom;
         else if (tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC)
@@ -9141,26 +9135,26 @@ FoldXMLConstants(JSContext *cx, JSParseN
      * the newborn string root. However, when |pn2->pn_type| is TOK_XMLCDATA,
      * TOK_XMLCOMMENT, or TOK_XMLPI it is knocked out of the newborn root.
      * Therefore, we have to add additonal protection from GC nesting under
      * js_ConcatStrings.
      */
     for (pn2 = pn1, i = j = 0; pn2; pn2 = pn2->pn_next, i++) {
         /* The parser already rejected end-tags with attributes. */
         JS_ASSERT(tt != TOK_XMLETAGO || i == 0);
-        switch (pn2->pn_type) {
+        switch (pn2->getKind()) {
           case TOK_XMLATTR:
             if (!accum)
                 goto cantfold;
             /* FALL THROUGH */
           case TOK_XMLNAME:
           case TOK_XMLSPACE:
           case TOK_XMLTEXT:
           case TOK_STRING:
-            if (pn2->pn_arity == PN_LIST)
+            if (pn2->isArity(PN_LIST))
                 goto cantfold;
             str = pn2->pn_atom;
             break;
 
           case TOK_XMLCDATA:
             str = js_MakeXMLCDATAString(cx, pn2->pn_atom);
             if (!str)
                 return JS_FALSE;
@@ -9191,19 +9185,19 @@ FoldXMLConstants(JSContext *cx, JSParseN
                     fputs("NULL", stdout);
                 fputc('\n', stdout);
 #endif
             } else if (accum && pn1 != pn2) {
                 while (pn1->pn_next != pn2) {
                     pn1 = RecycleTree(pn1, tc);
                     --pn->pn_count;
                 }
-                pn1->pn_type = TOK_XMLTEXT;
-                pn1->pn_op = JSOP_STRING;
-                pn1->pn_arity = PN_NULLARY;
+                pn1->setKind(TOK_XMLTEXT);
+                pn1->setOp(JSOP_STRING);
+                pn1->setArity(PN_NULLARY);
                 pn1->pn_atom = js_AtomizeString(cx, accum);
                 if (!pn1->pn_atom)
                     return JS_FALSE;
                 JS_ASSERT(pnp != &pn1->pn_next);
                 *pnp = pn1;
             }
             pnp = &pn2->pn_next;
             pn1 = *pnp;
@@ -9244,19 +9238,19 @@ FoldXMLConstants(JSContext *cx, JSParseN
                 return JS_FALSE;
         }
 
         JS_ASSERT(*pnp == pn1);
         while (pn1->pn_next) {
             pn1 = RecycleTree(pn1, tc);
             --pn->pn_count;
         }
-        pn1->pn_type = TOK_XMLTEXT;
-        pn1->pn_op = JSOP_STRING;
-        pn1->pn_arity = PN_NULLARY;
+        pn1->setKind(TOK_XMLTEXT);
+        pn1->setOp(JSOP_STRING);
+        pn1->setArity(PN_NULLARY);
         pn1->pn_atom = js_AtomizeString(cx, accum);
         if (!pn1->pn_atom)
             return JS_FALSE;
         JS_ASSERT(pnp != &pn1->pn_next);
         *pnp = pn1;
     }
 
     if (pn1 && pn->pn_count == 1) {
@@ -9265,29 +9259,29 @@ FoldXMLConstants(JSContext *cx, JSParseN
          * unless pn is an XML root (in which case we need it to tell the code
          * generator to emit a JSOP_TOXML or JSOP_TOXMLLIST op).  If pn is an
          * XML root *and* it's a point-tag, rewrite it to TOK_XMLELEM to avoid
          * extra "<" and "/>" bracketing at runtime.
          */
         if (!(pn->pn_xflags & PNX_XMLROOT)) {
             pn->become(pn1);
         } else if (tt == TOK_XMLPTAGC) {
-            pn->pn_type = TOK_XMLELEM;
-            pn->pn_op = JSOP_TOXML;
+            pn->setKind(TOK_XMLELEM);
+            pn->setOp(JSOP_TOXML);
         }
     }
     return JS_TRUE;
 }
 
 #endif /* JS_HAS_XML_SUPPORT */
 
 static int
 Boolish(JSParseNode *pn)
 {
-    switch (pn->pn_op) {
+    switch (pn->getOp()) {
       case JSOP_DOUBLE:
         return pn->pn_dval != 0 && !JSDOUBLE_IS_NaN(pn->pn_dval);
 
       case JSOP_STRING:
         return pn->pn_atom->length() != 0;
 
 #if JS_HAS_GENERATOR_EXPRS
       case JSOP_CALL:
@@ -9295,17 +9289,17 @@ Boolish(JSParseNode *pn)
         /*
          * A generator expression as an if or loop condition has no effects, it
          * simply results in a truthy object reference. This condition folding
          * is needed for the decompiler. See bug 442342 and bug 443074.
          */
         if (pn->pn_count != 1)
             break;
         JSParseNode *pn2 = pn->pn_head;
-        if (pn2->pn_type != TOK_FUNCTION)
+        if (!pn2->isKind(TOK_FUNCTION))
             break;
         if (!(pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA))
             break;
         /* FALL THROUGH */
       }
 #endif
 
       case JSOP_DEFFUN:
@@ -9324,17 +9318,17 @@ Boolish(JSParseNode *pn)
 
 JSBool
 js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
 {
     JSParseNode *pn1 = NULL, *pn2 = NULL, *pn3 = NULL;
 
     JS_CHECK_RECURSION(cx, return JS_FALSE);
 
-    switch (pn->pn_arity) {
+    switch (pn->getArity()) {
       case PN_FUNC:
       {
         uint32 oldflags = tc->flags;
         JSFunctionBox *oldlist = tc->functionList;
 
         tc->flags = pn->pn_funbox->tcflags;
         tc->functionList = pn->pn_funbox->kids;
         if (!js_FoldConstants(cx, pn->pn_body, tc))
@@ -9343,241 +9337,241 @@ js_FoldConstants(JSContext *cx, JSParseN
         tc->flags = oldflags;
         tc->functionList = oldlist;
         break;
       }
 
       case PN_LIST:
       {
         /* Propagate inCond through logical connectives. */
-        bool cond = inCond && (pn->pn_type == TOK_OR || pn->pn_type == TOK_AND);
+        bool cond = inCond && (pn->isKind(TOK_OR) || pn->isKind(TOK_AND));
 
         /* Don't fold a parenthesized call expression. See bug 537673. */
         pn1 = pn2 = pn->pn_head;
-        if ((pn->pn_type == TOK_LP || pn->pn_type == TOK_NEW) && pn2->pn_parens)
+        if ((pn->isKind(TOK_LP) || pn->isKind(TOK_NEW)) && pn2->isInParens())
             pn2 = pn2->pn_next;
 
         /* Save the list head in pn1 for later use. */
         for (; pn2; pn2 = pn2->pn_next) {
             if (!js_FoldConstants(cx, pn2, tc, cond))
                 return JS_FALSE;
         }
         break;
       }
 
       case PN_TERNARY:
         /* Any kid may be null (e.g. for (;;)). */
         pn1 = pn->pn_kid1;
         pn2 = pn->pn_kid2;
         pn3 = pn->pn_kid3;
-        if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->pn_type == TOK_IF))
+        if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->isKind(TOK_IF)))
             return JS_FALSE;
         if (pn2) {
-            if (!js_FoldConstants(cx, pn2, tc, pn->pn_type == TOK_FORHEAD))
+            if (!js_FoldConstants(cx, pn2, tc, pn->isKind(TOK_FORHEAD)))
                 return JS_FALSE;
-            if (pn->pn_type == TOK_FORHEAD && pn2->pn_op == JSOP_TRUE) {
+            if (pn->isKind(TOK_FORHEAD) && pn2->isOp(JSOP_TRUE)) {
                 RecycleTree(pn2, tc);
                 pn->pn_kid2 = NULL;
             }
         }
         if (pn3 && !js_FoldConstants(cx, pn3, tc))
             return JS_FALSE;
         break;
 
       case PN_BINARY:
         pn1 = pn->pn_left;
         pn2 = pn->pn_right;
 
         /* Propagate inCond through logical connectives. */
-        if (pn->pn_type == TOK_OR || pn->pn_type == TOK_AND) {
+        if (pn->isKind(TOK_OR) || pn->isKind(TOK_AND)) {
             if (!js_FoldConstants(cx, pn1, tc, inCond))
                 return JS_FALSE;
             if (!js_FoldConstants(cx, pn2, tc, inCond))
                 return JS_FALSE;
             break;
         }
 
         /* First kid may be null (for default case in switch). */
-        if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->pn_type == TOK_WHILE))
+        if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->isKind(TOK_WHILE)))
             return JS_FALSE;
-        if (!js_FoldConstants(cx, pn2, tc, pn->pn_type == TOK_DO))
+        if (!js_FoldConstants(cx, pn2, tc, pn->isKind(TOK_DO)))
             return JS_FALSE;
         break;
 
       case PN_UNARY:
         pn1 = pn->pn_kid;
 
         /*
          * Kludge to deal with typeof expressions: because constant folding
          * can turn an expression into a name node, we have to check here,
          * before folding, to see if we should throw undefined name errors.
          *
          * NB: We know that if pn->pn_op is JSOP_TYPEOF, pn1 will not be
          * null. This assumption does not hold true for other unary
          * expressions.
          */
-        if (pn->pn_op == JSOP_TYPEOF && pn1->pn_type != TOK_NAME)
-            pn->pn_op = JSOP_TYPEOFEXPR;
-
-        if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->pn_op == JSOP_NOT))
+        if (pn->isOp(JSOP_TYPEOF) && !pn1->isKind(TOK_NAME))
+            pn->setOp(JSOP_TYPEOFEXPR);
+
+        if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->isOp(JSOP_NOT)))
             return JS_FALSE;
         break;
 
       case PN_NAME:
         /*
          * Skip pn1 down along a chain of dotted member expressions to avoid
          * excessive recursion.  Our only goal here is to fold constants (if
          * any) in the primary expression operand to the left of the first
          * dot in the chain.
          */
-        if (!pn->pn_used) {
+        if (!pn->isUsed()) {
             pn1 = pn->pn_expr;
-            while (pn1 && pn1->pn_arity == PN_NAME && !pn1->pn_used)
+            while (pn1 && pn1->isArity(PN_NAME) && !pn1->isUsed())
                 pn1 = pn1->pn_expr;
             if (pn1 && !js_FoldConstants(cx, pn1, tc))
                 return JS_FALSE;
         }
         break;
 
       case PN_NAMESET:
         pn1 = pn->pn_tree;
         if (!js_FoldConstants(cx, pn1, tc))
             return JS_FALSE;
         break;
 
       case PN_NULLARY:
         break;
     }
 
-    switch (pn->pn_type) {
+    switch (pn->getKind()) {
       case TOK_IF:
         if (ContainsStmt(pn2, TOK_VAR) || ContainsStmt(pn3, TOK_VAR))
             break;
         /* FALL THROUGH */
 
       case TOK_HOOK:
         /* Reduce 'if (C) T; else E' into T for true C, E for false. */
-        switch (pn1->pn_type) {
+        switch (pn1->getKind()) {
           case TOK_NUMBER:
             if (pn1->pn_dval == 0 || JSDOUBLE_IS_NaN(pn1->pn_dval))
                 pn2 = pn3;
             break;
           case TOK_STRING:
             if (pn1->pn_atom->length() == 0)
                 pn2 = pn3;
             break;
           case TOK_PRIMARY:
-            if (pn1->pn_op == JSOP_TRUE)
+            if (pn1->isOp(JSOP_TRUE))
                 break;
-            if (pn1->pn_op == JSOP_FALSE || pn1->pn_op == JSOP_NULL) {
+            if (pn1->isOp(JSOP_FALSE) || pn1->isOp(JSOP_NULL)) {
                 pn2 = pn3;
                 break;
             }
             /* FALL THROUGH */
           default:
             /* Early return to dodge common code that copies pn2 to pn. */
             return JS_TRUE;
         }
 
 #if JS_HAS_GENERATOR_EXPRS
         /* Don't fold a trailing |if (0)| in a generator expression. */
         if (!pn2 && (tc->flags & TCF_GENEXP_LAMBDA))
             break;
 #endif
 
-        if (pn2 && !pn2->pn_defn)
+        if (pn2 && !pn2->isDefn())
             pn->become(pn2);
-        if (!pn2 || (pn->pn_type == TOK_SEMI && !pn->pn_kid)) {
+        if (!pn2 || (pn->isKind(TOK_SEMI) && !pn->pn_kid)) {
             /*
              * False condition and no else, or an empty then-statement was
              * moved up over pn.  Either way, make pn an empty block (not an
              * empty statement, which does not decompile, even when labeled).
              * NB: pn must be a TOK_IF as TOK_HOOK can never have a null kid
              * or an empty statement for a child.
              */
-            pn->pn_type = TOK_LC;
-            pn->pn_arity = PN_LIST;
+            pn->setKind(TOK_LC);
+            pn->setArity(PN_LIST);
             pn->makeEmpty();
         }
         RecycleTree(pn2, tc);
         if (pn3 && pn3 != pn2)
             RecycleTree(pn3, tc);
         break;
 
       case TOK_OR:
       case TOK_AND:
         if (inCond) {
-            if (pn->pn_arity == PN_LIST) {
+            if (pn->isArity(PN_LIST)) {
                 JSParseNode **pnp = &pn->pn_head;
                 JS_ASSERT(*pnp == pn1);
                 do {
                     int cond = Boolish(pn1);
-                    if (cond == (pn->pn_type == TOK_OR)) {
+                    if (cond == pn->isKind(TOK_OR)) {
                         for (pn2 = pn1->pn_next; pn2; pn2 = pn3) {
                             pn3 = pn2->pn_next;
                             RecycleTree(pn2, tc);
                             --pn->pn_count;
                         }
                         pn1->pn_next = NULL;
                         break;
                     }
                     if (cond != -1) {
-                        JS_ASSERT(cond == (pn->pn_type == TOK_AND));
+                        JS_ASSERT(cond == pn->isKind(TOK_AND));
                         if (pn->pn_count == 1)
                             break;
                         *pnp = pn1->pn_next;
                         RecycleTree(pn1, tc);
                         --pn->pn_count;
                     } else {
                         pnp = &pn1->pn_next;
                     }
                 } while ((pn1 = *pnp) != NULL);
 
                 // We may have to change arity from LIST to BINARY.
                 pn1 = pn->pn_head;
                 if (pn->pn_count == 2) {
                     pn2 = pn1->pn_next;
                     pn1->pn_next = NULL;
                     JS_ASSERT(!pn2->pn_next);
-                    pn->pn_arity = PN_BINARY;
+                    pn->setArity(PN_BINARY);
                     pn->pn_left = pn1;
                     pn->pn_right = pn2;
                 } else if (pn->pn_count == 1) {
                     pn->become(pn1);
                     RecycleTree(pn1, tc);
                 }
             } else {
                 int cond = Boolish(pn1);
-                if (cond == (pn->pn_type == TOK_OR)) {
+                if (cond == pn->isKind(TOK_OR)) {
                     RecycleTree(pn2, tc);
                     pn->become(pn1);
                 } else if (cond != -1) {
-                    JS_ASSERT(cond == (pn->pn_type == TOK_AND));
+                    JS_ASSERT(cond == pn->isKind(TOK_AND));
                     RecycleTree(pn1, tc);
                     pn->become(pn2);
                 }
             }
         }
         break;
 
       case TOK_ASSIGN:
         /*
          * Compound operators such as *= should be subject to folding, in case
          * the left-hand side is constant, and so that the decompiler produces
          * the same string that you get from decompiling a script or function
          * compiled from that same string.  As with +, += is special.
          */
-        if (pn->pn_op == JSOP_NOP)
+        if (pn->isOp(JSOP_NOP))
             break;
-        if (pn->pn_op != JSOP_ADD)
+        if (!pn->isOp(JSOP_ADD))
             goto do_binary_op;
         /* FALL THROUGH */
 
       case TOK_PLUS:
-        if (pn->pn_arity == PN_LIST) {
+        if (pn->isArity(PN_LIST)) {
             /*
              * Any string literal term with all others number or string means
              * this is a concatenation.  If any term is not a string or number
              * literal, we can't fold.
              */
             JS_ASSERT(pn->pn_count > 2);
             if (pn->pn_xflags & PNX_CANTFOLD)
                 return JS_TRUE;
@@ -9585,17 +9579,17 @@ js_FoldConstants(JSContext *cx, JSParseN
                 goto do_binary_op;
 
             /* Ok, we're concatenating: convert non-string constant operands. */
             size_t length = 0;
             for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
                 if (!FoldType(cx, pn2, TOK_STRING))
                     return JS_FALSE;
                 /* XXX fold only if all operands convert to string */
-                if (pn2->pn_type != TOK_STRING)
+                if (!pn2->isKind(TOK_STRING))
                     return JS_TRUE;
                 length += pn2->pn_atom->length();
             }
 
             /* Allocate a new buffer and string descriptor for the result. */
             jschar *chars = (jschar *) cx->malloc_((length + 1) * sizeof(jschar));
             if (!chars)
                 return JS_FALSE;
@@ -9614,168 +9608,164 @@ js_FoldConstants(JSContext *cx, JSParseN
                 chars += length2;
             }
             JS_ASSERT(*chars == 0);
 
             /* Atomize the result string and mutate pn to refer to it. */
             pn->pn_atom = js_AtomizeString(cx, str);
             if (!pn->pn_atom)
                 return JS_FALSE;
-            pn->pn_type = TOK_STRING;
-            pn->pn_op = JSOP_STRING;
-            pn->pn_arity = PN_NULLARY;
+            pn->setKind(TOK_STRING);
+            pn->setOp(JSOP_STRING);
+            pn->setArity(PN_NULLARY);
             break;
         }
 
         /* Handle a binary string concatenation. */
-        JS_ASSERT(pn->pn_arity == PN_BINARY);
-        if (pn1->pn_type == TOK_STRING || pn2->pn_type == TOK_STRING) {
+        JS_ASSERT(pn->isArity(PN_BINARY));
+        if (pn1->isKind(TOK_STRING) || pn2->isKind(TOK_STRING)) {
             JSString *left, *right, *str;
 
-            if (!FoldType(cx, (pn1->pn_type != TOK_STRING) ? pn1 : pn2,
-                          TOK_STRING)) {
+            if (!FoldType(cx, !pn1->isKind(TOK_STRING) ? pn1 : pn2, TOK_STRING))
                 return JS_FALSE;
-            }
-            if (pn1->pn_type != TOK_STRING || pn2->pn_type != TOK_STRING)
+            if (!pn1->isKind(TOK_STRING) || !pn2->isKind(TOK_STRING))
                 return JS_TRUE;
             left = pn1->pn_atom;
             right = pn2->pn_atom;
             str = js_ConcatStrings(cx, left, right);
             if (!str)
                 return JS_FALSE;
             pn->pn_atom = js_AtomizeString(cx, str);
             if (!pn->pn_atom)
                 return JS_FALSE;
-            pn->pn_type = TOK_STRING;
-            pn->pn_op = JSOP_STRING;
-            pn->pn_arity = PN_NULLARY;
+            pn->setKind(TOK_STRING);
+            pn->setOp(JSOP_STRING);
+            pn->setArity(PN_NULLARY);
             RecycleTree(pn1, tc);
             RecycleTree(pn2, tc);
             break;
         }
 
         /* Can't concatenate string literals, let's try numbers. */
         goto do_binary_op;
 
       case TOK_STAR:
       case TOK_SHOP:
       case TOK_MINUS:
       case TOK_DIVOP:
       do_binary_op:
-        if (pn->pn_arity == PN_LIST) {
+        if (pn->isArity(PN_LIST)) {
             JS_ASSERT(pn->pn_count > 2);
             for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
                 if (!FoldType(cx, pn2, TOK_NUMBER))
                     return JS_FALSE;
             }
             for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
                 /* XXX fold only if all operands convert to number */
-                if (pn2->pn_type != TOK_NUMBER)
+                if (!pn2->isKind(TOK_NUMBER))
                     break;
             }
             if (!pn2) {
-                JSOp op = PN_OP(pn);
+                JSOp op = pn->getOp();
 
                 pn2 = pn1->pn_next;
                 pn3 = pn2->pn_next;
                 if (!FoldBinaryNumeric(cx, op, pn1, pn2, pn, tc))
                     return JS_FALSE;
                 while ((pn2 = pn3) != NULL) {
                     pn3 = pn2->pn_next;
                     if (!FoldBinaryNumeric(cx, op, pn, pn2, pn, tc))
                         return JS_FALSE;
                 }
             }
         } else {
-            JS_ASSERT(pn->pn_arity == PN_BINARY);
+            JS_ASSERT(pn->isArity(PN_BINARY));
             if (!FoldType(cx, pn1, TOK_NUMBER) ||
                 !FoldType(cx, pn2, TOK_NUMBER)) {
                 return JS_FALSE;
             }
-            if (pn1->pn_type == TOK_NUMBER && pn2->pn_type == TOK_NUMBER) {
-                if (!FoldBinaryNumeric(cx, PN_OP(pn), pn1, pn2, pn, tc))
+            if (pn1->isKind(TOK_NUMBER) && pn2->isKind(TOK_NUMBER)) {
+                if (!FoldBinaryNumeric(cx, pn->getOp(), pn1, pn2, pn, tc))
                     return JS_FALSE;
             }
         }
         break;
 
       case TOK_UNARYOP:
-        if (pn1->pn_type == TOK_NUMBER) {
+        if (pn1->isKind(TOK_NUMBER)) {
             jsdouble d;
 
             /* Operate on one numeric constant. */
             d = pn1->pn_dval;
-            switch (pn->pn_op) {
+            switch (pn->getOp()) {
               case JSOP_BITNOT:
                 d = ~js_DoubleToECMAInt32(d);
                 break;
 
               case JSOP_NEG:
                 d = -d;
                 break;
 
               case JSOP_POS:
                 break;
 
               case JSOP_NOT:
-                pn->pn_type = TOK_PRIMARY;
-                pn->pn_op = (d == 0 || JSDOUBLE_IS_NaN(d)) ? JSOP_TRUE : JSOP_FALSE;
-                pn->pn_arity = PN_NULLARY;
+                pn->setKind(TOK_PRIMARY);
+                pn->setOp((d == 0 || JSDOUBLE_IS_NaN(d)) ? JSOP_TRUE : JSOP_FALSE);
+                pn->setArity(PN_NULLARY);
                 /* FALL THROUGH */
 
               default:
                 /* Return early to dodge the common TOK_NUMBER code. */
                 return JS_TRUE;
             }
-            pn->pn_type = TOK_NUMBER;
-            pn->pn_op = JSOP_DOUBLE;
-            pn->pn_arity = PN_NULLARY;
+            pn->setKind(TOK_NUMBER);
+            pn->setOp(JSOP_DOUBLE);
+            pn->setArity(PN_NULLARY);
             pn->pn_dval = d;
             RecycleTree(pn1, tc);
-        } else if (pn1->pn_type == TOK_PRIMARY) {
-            if (pn->pn_op == JSOP_NOT &&
-                (pn1->pn_op == JSOP_TRUE ||
-                 pn1->pn_op == JSOP_FALSE)) {
+        } else if (pn1->isKind(TOK_PRIMARY)) {
+            if (pn->isOp(JSOP_NOT) && (pn1->isOp(JSOP_TRUE) || pn1->isOp(JSOP_FALSE))) {
                 pn->become(pn1);
-                pn->pn_op = (pn->pn_op == JSOP_TRUE) ? JSOP_FALSE : JSOP_TRUE;
+                pn->setOp(pn->isOp(JSOP_TRUE) ? JSOP_FALSE : JSOP_TRUE);
                 RecycleTree(pn1, tc);
             }
         }
         break;
 
 #if JS_HAS_XML_SUPPORT
       case TOK_XMLELEM:
       case TOK_XMLLIST:
       case TOK_XMLPTAGC:
       case TOK_XMLSTAGO:
       case TOK_XMLETAGO:
       case TOK_XMLNAME:
-        if (pn->pn_arity == PN_LIST) {
-            JS_ASSERT(pn->pn_type == TOK_XMLLIST || pn->pn_count != 0);
+        if (pn->isArity(PN_LIST)) {
+            JS_ASSERT(pn->isKind(TOK_XMLLIST) || pn->pn_count != 0);
             if (!FoldXMLConstants(cx, pn, tc))
                 return JS_FALSE;
         }
         break;
 
       case TOK_AT:
-        if (pn1->pn_type == TOK_XMLNAME) {
+        if (pn1->isKind(TOK_XMLNAME)) {
             JSObjectBox *xmlbox;
 
             Value v = StringValue(pn1->pn_atom);
             if (!js_ToAttributeName(cx, &v))
                 return JS_FALSE;
             JS_ASSERT(v.isObject());
 
             xmlbox = tc->parser->newObjectBox(&v.toObject());
             if (!xmlbox)
                 return JS_FALSE;
 
-            pn->pn_type = TOK_XMLNAME;
-            pn->pn_op = JSOP_OBJECT;
-            pn->pn_arity = PN_NULLARY;
+            pn->setKind(TOK_XMLNAME);
+            pn->setOp(JSOP_OBJECT);
+            pn->setArity(PN_NULLARY);
             pn->pn_objbox = xmlbox;
             RecycleTree(pn1, tc);
         }
         break;
 #endif /* JS_HAS_XML_SUPPORT */
 
       default:;
     }
@@ -9785,16 +9775,16 @@ js_FoldConstants(JSContext *cx, JSParseN
         if (cond >= 0) {
             /*
              * We can turn function nodes into constant nodes here, but mutating function
              * nodes is tricky --- in particular, mutating a function node that appears on
              * a method list corrupts the method list. However, methods are M's in
              * statements of the form 'this.foo = M;', which we never fold, so we're okay.
              */
             PrepareNodeForMutation(pn, tc);
-            pn->pn_type = TOK_PRIMARY;
-            pn->pn_op = cond ? JSOP_TRUE : JSOP_FALSE;
-            pn->pn_arity = PN_NULLARY;
+            pn->setKind(TOK_PRIMARY);
+            pn->setOp(cond ? JSOP_TRUE : JSOP_FALSE);
+            pn->setArity(PN_NULLARY);
         }
     }
 
     return JS_TRUE;
 }
--- a/js/src/jsparse.h
+++ b/js/src/jsparse.h
@@ -43,16 +43,17 @@
 /*
  * JS parser definitions.
  */
 #include "jsversion.h"
 #include "jsprvtd.h"
 #include "jspubtd.h"
 #include "jsatom.h"
 #include "jsscan.h"
+#include "jswin.h"
 
 #include "frontend/ParseMaps.h"
 
 JS_BEGIN_EXTERN_C
 
 /*
  * Parsing builds a tree of nodes that directs code generation.  This tree is
  * not a concrete syntax tree in all respects (for example, || and && are left
@@ -345,25 +346,41 @@ struct GlobalScope {
      */
     Vector<GlobalDef, 16> defs;
     AtomIndexMap      names;
 };
 
 } /* namespace js */
 
 struct JSParseNode {
-    uint32              pn_type:16,     /* TOK_* type, see jsscan.h */
-                        pn_op:8,        /* see JSOp enum and jsopcode.tbl */
-                        pn_arity:5,     /* see JSParseNodeArity enum */
-                        pn_parens:1,    /* this expr was enclosed in parens */
-                        pn_used:1,      /* name node is on a use-chain */
-                        pn_defn:1;      /* this node is a JSDefinition */
+  private:
+    uint32              pn_type   : 16, /* TOK_* type, see jsscan.h */
+                        pn_op     : 8,  /* see JSOp enum and jsopcode.tbl */
+                        pn_arity  : 5,  /* see JSParseNodeArity enum */
+                        pn_parens : 1,  /* this expr was enclosed in parens */
+                        pn_used   : 1,  /* name node is on a use-chain */
+                        pn_defn   : 1;  /* this node is a JSDefinition */
 
-#define PN_OP(pn)    ((JSOp)(pn)->pn_op)
-#define PN_TYPE(pn)  ((js::TokenKind)(pn)->pn_type)
+  public:
+    JSOp getOp() const                     { return JSOp(pn_op); }
+    void setOp(JSOp op)                    { pn_op = op; }
+    bool isOp(JSOp op) const               { return getOp() == op; }
+    js::TokenKind getKind() const          { return js::TokenKind(pn_type); }
+    void setKind(js::TokenKind kind)       { pn_type = kind; }
+    bool isKind(js::TokenKind kind) const  { return getKind() == kind; }
+    JSParseNodeArity getArity() const      { return JSParseNodeArity(pn_arity); }
+    bool isArity(JSParseNodeArity a) const { return getArity() == a; }
+    void setArity(JSParseNodeArity a)      { pn_arity = a; }
+    /* Boolean attributes. */
+    bool isInParens() const                { return pn_parens; }
+    void setInParens(bool enabled)         { pn_parens = enabled; }
+    bool isDefn() const                    { return pn_defn; }
+    void setDefn(bool enabled)             { pn_defn = enabled; }
+    bool isUsed() const                    { return pn_used; }
+    void setUsed(bool enabled)             { pn_used = enabled; }
 
     js::TokenPos        pn_pos;         /* two 16-bit pairs here, for 64 bits */
     int32               pn_offset;      /* first generated bytecode offset */
     JSParseNode         *pn_next;       /* intrinsic link in parent PN_LIST */
     JSParseNode         *pn_link;       /* def/use link (alignment freebie);
                                            also links JSFunctionBox::methods
                                            lists of would-be |this| methods */
     union {
@@ -575,19 +592,19 @@ public:
     /* Defined below, see after struct JSDefinition. */
     void setFunArg();
 
     void become(JSParseNode *pn2);
     void clear();
 
     /* True if pn is a parsenode representing a literal constant. */
     bool isLiteral() const {
-        return PN_TYPE(this) == js::TOK_NUMBER ||
-               PN_TYPE(this) == js::TOK_STRING ||
-               (PN_TYPE(this) == js::TOK_PRIMARY && PN_OP(this) != JSOP_THIS);
+        return isKind(js::TOK_NUMBER) ||
+               isKind(js::TOK_STRING) ||
+               (isKind(js::TOK_PRIMARY) && !isOp(JSOP_THIS));
     }
 
     /*
      * True if this statement node could be a member of a Directive Prologue: an
      * expression statement consisting of a single string literal.
      *
      * This considers only the node and its children, not its context. After
      * parsing, check the node's pn_prologue flag to see if it is indeed part of
@@ -596,20 +613,20 @@ public:
      * Note that a Directive Prologue can contain statements that cannot
      * themselves be directives (string literals that include escape sequences
      * or escaped newlines, say). This member function returns true for such
      * nodes; we use it to determine the extent of the prologue.
      * isEscapeFreeStringLiteral, below, checks whether the node itself could be
      * a directive.
      */
     bool isStringExprStatement() const {
-        if (PN_TYPE(this) == js::TOK_SEMI) {
+        if (getKind() == js::TOK_SEMI) {
             JS_ASSERT(pn_arity == PN_UNARY);
             JSParseNode *kid = pn_kid;
-            return kid && PN_TYPE(kid) == js::TOK_STRING && !kid->pn_parens;
+            return kid && kid->getKind() == js::TOK_STRING && !kid->pn_parens;
         }
         return false;
     }
 
     /*
      * Return true if this node, known to be a string literal, could be the
      * string of a directive in a Directive Prologue. Directive strings never
      * contain escape sequences or line continuations.
@@ -630,36 +647,36 @@ public:
     /* Return true if this node appears in a Directive Prologue. */
     bool isDirectivePrologueMember() const { return pn_prologue; }
 
 #ifdef JS_HAS_GENERATOR_EXPRS
     /*
      * True if this node is a desugared generator expression.
      */
     bool isGeneratorExpr() const {
-        if (PN_TYPE(this) == js::TOK_LP) {
+        if (getKind() == js::TOK_LP) {
             JSParseNode *callee = this->pn_head;
-            if (PN_TYPE(callee) == js::TOK_FUNCTION) {
-                JSParseNode *body = (PN_TYPE(callee->pn_body) == js::TOK_UPVARS)
+            if (callee->getKind() == js::TOK_FUNCTION) {
+                JSParseNode *body = (callee->pn_body->getKind() == js::TOK_UPVARS)
                                     ? callee->pn_body->pn_tree
                                     : callee->pn_body;
-                if (PN_TYPE(body) == js::TOK_LEXICALSCOPE)
+                if (body->getKind() == js::TOK_LEXICALSCOPE)
                     return true;
             }
         }
         return false;
     }
 
     JSParseNode *generatorExpr() const {
         JS_ASSERT(isGeneratorExpr());
         JSParseNode *callee = this->pn_head;
-        JSParseNode *body = PN_TYPE(callee->pn_body) == js::TOK_UPVARS
+        JSParseNode *body = callee->pn_body->getKind() == js::TOK_UPVARS
             ? callee->pn_body->pn_tree
             : callee->pn_body;
-        JS_ASSERT(PN_TYPE(body) == js::TOK_LEXICALSCOPE);
+        JS_ASSERT(body->getKind() == js::TOK_LEXICALSCOPE);
         return body->pn_expr;
     }
 #endif
 
     /*
      * Compute a pointer to the last element in a singly-linked list. NB: list
      * must be non-empty for correct PN_LAST usage -- this is asserted!
      */
@@ -907,53 +924,49 @@ struct JSDefinition : public JSParseNode
      * definitions.  This is unusual, so we simply chase the pn_lexdef link to
      * find the final definition node. See methods called from
      * Parser::analyzeFunctions.
      *
      * FIXME: MakeAssignment mutates for want of a parent link...
      */
     JSDefinition *resolve() {
         JSParseNode *pn = this;
-        while (!pn->pn_defn) {
-            if (pn->pn_type == js::TOK_ASSIGN) {
+        while (!pn->isDefn()) {
+            if (pn->getKind() == js::TOK_ASSIGN) {
                 pn = pn->pn_left;
                 continue;
             }
             pn = pn->lexdef();
         }
         return (JSDefinition *) pn;
     }
 
     bool isFreeVar() const {
-        JS_ASSERT(pn_defn);
+        JS_ASSERT(isDefn());
         return pn_cookie.isFree() || test(PND_GVAR);
     }
 
     bool isGlobal() const {
-        JS_ASSERT(pn_defn);
+        JS_ASSERT(isDefn());
         return test(PND_GVAR);
     }
 
-    // Grr, windows.h or something under it #defines CONST...
-#ifdef CONST
-# undef CONST
-#endif
     enum Kind { VAR, CONST, LET, FUNCTION, ARG, UNKNOWN };
 
     bool isBindingForm() { return int(kind()) <= int(LET); }
 
     static const char *kindString(Kind kind);
 
     Kind kind() {
-        if (PN_TYPE(this) == js::TOK_FUNCTION)
+        if (getKind() == js::TOK_FUNCTION)
             return FUNCTION;
-        JS_ASSERT(PN_TYPE(this) == js::TOK_NAME);
-        if (PN_OP(this) == JSOP_NOP)
+        JS_ASSERT(getKind() == js::TOK_NAME);
+        if (isOp(JSOP_NOP))
             return UNKNOWN;
-        if (PN_OP(this) == JSOP_GETARG)
+        if (isOp(JSOP_GETARG))
             return ARG;
         if (isConst())
             return CONST;
         if (isLet())
             return LET;
         return VAR;
     }
 };
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -1818,17 +1818,17 @@ ASTSerializer::binop(TokenKind tk, JSOp 
       default:
         return BINOP_ERR;
     }
 }
 
 bool
 ASTSerializer::statements(JSParseNode *pn, NodeVector &elts)
 {
-    JS_ASSERT(PN_TYPE(pn) == TOK_LC && pn->pn_arity == PN_LIST);
+    JS_ASSERT(pn->isKind(TOK_LC) && pn->isArity(PN_LIST));
 
     if (!elts.reserve(pn->pn_count))
         return false;
 
     for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
         Value elt;
         if (!sourceElement(next, &elt))
             return false;
@@ -1868,17 +1868,17 @@ ASTSerializer::xmls(JSParseNode *pn, Nod
     }
 
     return true;
 }
 
 bool
 ASTSerializer::blockStatement(JSParseNode *pn, Value *dst)
 {
-    JS_ASSERT(PN_TYPE(pn) == TOK_LC);
+    JS_ASSERT(pn->isKind(TOK_LC));
 
     NodeVector stmts(cx);
     return statements(pn, stmts) &&
            builder.blockStatement(stmts, &pn->pn_pos, dst);
 }
 
 bool
 ASTSerializer::program(JSParseNode *pn, Value *dst)
@@ -1895,37 +1895,35 @@ ASTSerializer::sourceElement(JSParseNode
 {
     /* SpiderMonkey allows declarations even in pure statement contexts. */
     return statement(pn, dst);
 }
 
 bool
 ASTSerializer::declaration(JSParseNode *pn, Value *dst)
 {
-    JS_ASSERT(PN_TYPE(pn) == TOK_FUNCTION ||
-              PN_TYPE(pn) == TOK_VAR ||
-              PN_TYPE(pn) == TOK_LET);
-
-    switch (PN_TYPE(pn)) {
+    JS_ASSERT(pn->isKind(TOK_FUNCTION) || pn->isKind(TOK_VAR) || pn->isKind(TOK_LET));
+
+    switch (pn->getKind()) {
       case TOK_FUNCTION:
         return function(pn, AST_FUNC_DECL, dst);
 
       case TOK_VAR:
         return variableDeclaration(pn, false, dst);
 
       default:
-        JS_ASSERT(PN_TYPE(pn) == TOK_LET);
+        JS_ASSERT(pn->isKind(TOK_LET));
         return variableDeclaration(pn, true, dst);
     }
 }
 
 bool
 ASTSerializer::variableDeclaration(JSParseNode *pn, bool let, Value *dst)
 {
-    JS_ASSERT(let ? PN_TYPE(pn) == TOK_LET : PN_TYPE(pn) == TOK_VAR);
+    JS_ASSERT(let ? pn->isKind(TOK_LET) : pn->isKind(TOK_VAR));
 
     /* Later updated to VARDECL_CONST if we find a PND_CONST declarator. */
     VarDeclKind kind = let ? VARDECL_LET : VARDECL_VAR;
 
     NodeVector dtors(cx);
 
     /* In a for-in context, variable declarations contain just a single pattern. */
     if (pn->pn_xflags & PNX_FORINVAR) {
@@ -1947,26 +1945,26 @@ ASTSerializer::variableDeclaration(JSPar
 
     return builder.variableDeclaration(dtors, kind, &pn->pn_pos, dst);
 }
 
 bool
 ASTSerializer::variableDeclarator(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
 {
     /* A destructuring declarator is always a TOK_ASSIGN. */
-    JS_ASSERT(PN_TYPE(pn) == TOK_NAME || PN_TYPE(pn) == TOK_ASSIGN);
+    JS_ASSERT(pn->isKind(TOK_NAME) || pn->isKind(TOK_ASSIGN));
 
     JSParseNode *pnleft;
     JSParseNode *pnright;
 
-    if (PN_TYPE(pn) == TOK_NAME) {
+    if (pn->isKind(TOK_NAME)) {
         pnleft = pn;
-        pnright = pn->pn_used ? NULL : pn->pn_expr;
+        pnright = pn->isUsed() ? NULL : pn->pn_expr;
     } else {
-        JS_ASSERT(PN_TYPE(pn) == TOK_ASSIGN);
+        JS_ASSERT(pn->isKind(TOK_ASSIGN));
         pnleft = pn->pn_left;
         pnright = pn->pn_right;
     }
 
     Value left, right;
     return pattern(pnleft, pkind, &left) &&
            optExpression(pnright, &right) &&
            builder.variableDeclarator(left, right, &pn->pn_pos, dst);
@@ -2012,17 +2010,17 @@ ASTSerializer::switchStatement(JSParseNo
     Value disc;
 
     if (!expression(pn->pn_left, &disc))
         return false;
 
     JSParseNode *listNode;
     bool lexical;
 
-    if (PN_TYPE(pn->pn_right) == TOK_LEXICALSCOPE) {
+    if (pn->pn_right->isKind(TOK_LEXICALSCOPE)) {
         listNode = pn->pn_right->pn_expr;
         lexical = true;
     } else {
         listNode = pn->pn_right;
         lexical = false;
     }
 
     NodeVector cases(cx);
@@ -2081,57 +2079,57 @@ ASTSerializer::tryStatement(JSParseNode 
 bool
 ASTSerializer::forInit(JSParseNode *pn, Value *dst)
 {
     if (!pn) {
         dst->setMagic(JS_SERIALIZE_NO_NODE);
         return true;
     }
 
-    return (PN_TYPE(pn) == TOK_VAR)
+    return pn->isKind(TOK_VAR)
            ? variableDeclaration(pn, false, dst)
-           : (PN_TYPE(pn) == TOK_LET)
+           : pn->isKind(TOK_LET)
            ? variableDeclaration(pn, true, dst)
            : expression(pn, dst);
 }
 
 bool
 ASTSerializer::statement(JSParseNode *pn, Value *dst)
 {
     JS_CHECK_RECURSION(cx, return false);
-    switch (PN_TYPE(pn)) {
+    switch (pn->getKind()) {
       case TOK_FUNCTION:
       case TOK_VAR:
       case TOK_LET:
         return declaration(pn, dst);
 
       case TOK_NAME:
-        LOCAL_ASSERT(pn->pn_used);
+        LOCAL_ASSERT(pn->isUsed());
         return statement(pn->pn_lexdef, dst);
 
       case TOK_SEMI:
         if (pn->pn_kid) {
             Value expr;
             return expression(pn->pn_kid, &expr) &&
                    builder.expressionStatement(expr, &pn->pn_pos, dst);
         }
         return builder.emptyStatement(&pn->pn_pos, dst);
 
       case TOK_LEXICALSCOPE:
         pn = pn->pn_expr;
-        if (PN_TYPE(pn) == TOK_LET) {
+        if (pn->isKind(TOK_LET)) {
             NodeVector dtors(cx);
             Value stmt;
 
             return letHead(pn->pn_left, dtors) &&
                    statement(pn->pn_right, &stmt) &&
                    builder.letStatement(dtors, stmt, &pn->pn_pos, dst);
         }
 
-        if (PN_TYPE(pn) != TOK_LC)
+        if (!pn->isKind(TOK_LC))
             return statement(pn, dst);
         /* FALL THROUGH */
 
       case TOK_LC:
         return blockStatement(pn, dst);
 
       case TOK_IF:
       {
@@ -2151,17 +2149,17 @@ ASTSerializer::statement(JSParseNode *pn
 
       case TOK_WITH:
       case TOK_WHILE:
       {
         Value expr, stmt;
 
         return expression(pn->pn_left, &expr) &&
                statement(pn->pn_right, &stmt) &&
-               (PN_TYPE(pn) == TOK_WITH)
+               pn->isKind(TOK_WITH)
                ? builder.withStatement(expr, stmt, &pn->pn_pos, dst)
                : builder.whileStatement(expr, stmt, &pn->pn_pos, dst);
       }
 
       case TOK_DO:
       {
         Value stmt, test;
 
@@ -2175,23 +2173,23 @@ ASTSerializer::statement(JSParseNode *pn
         JSParseNode *head = pn->pn_left;
 
         Value stmt;
         if (!statement(pn->pn_right, &stmt))
             return false;
 
         bool isForEach = pn->pn_iflags & JSITER_FOREACH;
 
-        if (PN_TYPE(head) == TOK_IN) {
+        if (head->isKind(TOK_IN)) {
             Value var, expr;
 
             return (!head->pn_kid1
                     ? pattern(head->pn_kid2, NULL, &var)
                     : variableDeclaration(head->pn_kid1,
-                                          PN_TYPE(head->pn_kid1) == TOK_LET,
+                                          head->pn_kid1->isKind(TOK_LET),
                                           &var)) &&
                    expression(head->pn_kid3, &expr) &&
                    builder.forInStatement(var, expr, stmt, isForEach, &pn->pn_pos, dst);
         }
 
         Value init, test, update;
 
         return forInit(head->pn_kid1, &init) &&
@@ -2203,41 +2201,41 @@ ASTSerializer::statement(JSParseNode *pn
       /* Synthesized by the parser when a for-in loop contains a variable initializer. */
       case TOK_SEQ:
       {
         LOCAL_ASSERT(pn->pn_count == 2);
 
         JSParseNode *prelude = pn->pn_head;
         JSParseNode *loop = prelude->pn_next;
 
-        LOCAL_ASSERT(PN_TYPE(prelude) == TOK_VAR && PN_TYPE(loop) == TOK_FOR);
+        LOCAL_ASSERT(prelude->isKind(TOK_VAR) && loop->isKind(TOK_FOR));
 
         Value var;
         if (!variableDeclaration(prelude, false, &var))
             return false;
 
         JSParseNode *head = loop->pn_left;
-        JS_ASSERT(PN_TYPE(head) == TOK_IN);
+        JS_ASSERT(head->isKind(TOK_IN));
 
         bool isForEach = loop->pn_iflags & JSITER_FOREACH;
 
         Value expr, stmt;
 
         return expression(head->pn_kid3, &expr) &&
                statement(loop->pn_right, &stmt) &&
                builder.forInStatement(var, expr, stmt, isForEach, &pn->pn_pos, dst);
       }
 
       case TOK_BREAK:
       case TOK_CONTINUE:
       {
         Value label;
 
         return optIdentifier(pn->pn_atom, NULL, &label) &&
-               (PN_TYPE(pn) == TOK_BREAK
+               (pn->isKind(TOK_BREAK)
                 ? builder.breakStatement(label, &pn->pn_pos, dst)
                 : builder.continueStatement(label, &pn->pn_pos, dst));
       }
 
       case TOK_COLON:
       {
         Value label, stmt;
 
@@ -2247,48 +2245,48 @@ ASTSerializer::statement(JSParseNode *pn
       }
 
       case TOK_THROW:
       case TOK_RETURN:
       {
         Value arg;
 
         return optExpression(pn->pn_kid, &arg) &&
-               (PN_TYPE(pn) == TOK_THROW
+               (pn->isKind(TOK_THROW)
                 ? builder.throwStatement(arg, &pn->pn_pos, dst)
                 : builder.returnStatement(arg, &pn->pn_pos, dst));
       }
 
       case TOK_DEBUGGER:
         return builder.debuggerStatement(&pn->pn_pos, dst);
 
 #if JS_HAS_XML_SUPPORT
       case TOK_DEFAULT:
       {
-        LOCAL_ASSERT(pn->pn_arity == PN_UNARY);
+        LOCAL_ASSERT(pn->isArity(PN_UNARY));
 
         Value ns;
 
         return expression(pn->pn_kid, &ns) &&
                builder.xmlDefaultNamespace(ns, &pn->pn_pos, dst);
       }
 #endif
 
       default:
         LOCAL_NOT_REACHED("unexpected statement type");
     }
 }
 
 bool
 ASTSerializer::leftAssociate(JSParseNode *pn, Value *dst)
 {
-    JS_ASSERT(pn->pn_arity == PN_LIST);
+    JS_ASSERT(pn->isArity(PN_LIST));
     JS_ASSERT(pn->pn_count >= 1);
 
-    TokenKind tk = PN_TYPE(pn);
+    TokenKind tk = pn->getKind();
     bool lor = tk == TOK_OR;
     bool logop = lor || (tk == TOK_AND);
 
     JSParseNode *head = pn->pn_head;
     Value left;
     if (!expression(head, &left))
         return false;
     for (JSParseNode *next = head->pn_next; next; next = next->pn_next) {
@@ -2297,118 +2295,118 @@ ASTSerializer::leftAssociate(JSParseNode
             return false;
 
         TokenPos subpos = { pn->pn_pos.begin, next->pn_pos.end };
 
         if (logop) {
             if (!builder.logicalExpression(lor, left, right, &subpos, &left))
                 return false;
         } else {
-            BinaryOperator op = binop(PN_TYPE(pn), PN_OP(pn));
+            BinaryOperator op = binop(pn->getKind(), pn->getOp());
             LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
 
             if (!builder.binaryExpression(op, left, right, &subpos, &left))
                 return false;
         }
     }
 
     *dst = left;
     return true;
 }
 
 bool
 ASTSerializer::comprehensionBlock(JSParseNode *pn, Value *dst)
 {
-    LOCAL_ASSERT(pn->pn_arity == PN_BINARY);
+    LOCAL_ASSERT(pn->isArity(PN_BINARY));
 
     JSParseNode *in = pn->pn_left;
 
-    LOCAL_ASSERT(in && PN_TYPE(in) == TOK_IN);
+    LOCAL_ASSERT(in && in->isKind(TOK_IN));
 
     bool isForEach = pn->pn_iflags & JSITER_FOREACH;
 
     Value patt, src;
     return pattern(in->pn_kid2, NULL, &patt) &&
            expression(in->pn_kid3, &src) &&
            builder.comprehensionBlock(patt, src, isForEach, &in->pn_pos, dst);
 }
 
 bool
 ASTSerializer::comprehension(JSParseNode *pn, Value *dst)
 {
-    LOCAL_ASSERT(PN_TYPE(pn) == TOK_FOR);
+    LOCAL_ASSERT(pn->isKind(TOK_FOR));
 
     NodeVector blocks(cx);
 
     JSParseNode *next = pn;
-    while (PN_TYPE(next) == TOK_FOR) {
+    while (next->isKind(TOK_FOR)) {
         Value block;
         if (!comprehensionBlock(next, &block) || !blocks.append(block))
             return false;
         next = next->pn_right;
     }
 
     Value filter = MagicValue(JS_SERIALIZE_NO_NODE);
 
-    if (PN_TYPE(next) == TOK_IF) {
+    if (next->isKind(TOK_IF)) {
         if (!optExpression(next->pn_kid1, &filter))
             return false;
         next = next->pn_kid2;
-    } else if (PN_TYPE(next) == TOK_LC && next->pn_count == 0) {
+    } else if (next->isKind(TOK_LC) && next->pn_count == 0) {
         /* js_FoldConstants optimized away the push. */
         NodeVector empty(cx);
         return builder.arrayExpression(empty, &pn->pn_pos, dst);
     }
 
-    LOCAL_ASSERT(PN_TYPE(next) == TOK_ARRAYPUSH);
+    LOCAL_ASSERT(next->isKind(TOK_ARRAYPUSH));
 
     Value body;
 
     return expression(next->pn_kid, &body) &&
            builder.comprehensionExpression(body, blocks, filter, &pn->pn_pos, dst);
 }
 
 bool
 ASTSerializer::generatorExpression(JSParseNode *pn, Value *dst)
 {
-    LOCAL_ASSERT(PN_TYPE(pn) == TOK_FOR);
+    LOCAL_ASSERT(pn->isKind(TOK_FOR));
 
     NodeVector blocks(cx);
 
     JSParseNode *next = pn;
-    while (PN_TYPE(next) == TOK_FOR) {
+    while (next->isKind(TOK_FOR)) {
         Value block;
         if (!comprehensionBlock(next, &block) || !blocks.append(block))
             return false;
         next = next->pn_right;
     }
 
     Value filter = MagicValue(JS_SERIALIZE_NO_NODE);
 
-    if (PN_TYPE(next) == TOK_IF) {
+    if (next->isKind(TOK_IF)) {
         if (!optExpression(next->pn_kid1, &filter))
             return false;
         next = next->pn_kid2;
     }
 
-    LOCAL_ASSERT(PN_TYPE(next) == TOK_SEMI &&
-                 PN_TYPE(next->pn_kid) == TOK_YIELD &&
+    LOCAL_ASSERT(next->isKind(TOK_SEMI) &&
+                 next->pn_kid->isKind(TOK_YIELD) &&
                  next->pn_kid->pn_kid);
 
     Value body;
 
     return expression(next->pn_kid->pn_kid, &body) &&
            builder.generatorExpression(body, blocks, filter, &pn->pn_pos, dst);
 }
 
 bool
 ASTSerializer::expression(JSParseNode *pn, Value *dst)
 {
     JS_CHECK_RECURSION(cx, return false);
-    switch (PN_TYPE(pn)) {
+    switch (pn->getKind()) {
       case TOK_FUNCTION:
         return function(pn, AST_FUNC_EXPR, dst);
 
       case TOK_COMMA:
       {
         NodeVector exprs(cx);
         return expressions(pn, exprs) &&
                builder.sequenceExpression(exprs, &pn->pn_pos, dst);
@@ -2422,39 +2420,39 @@ ASTSerializer::expression(JSParseNode *p
                expression(pn->pn_kid2, &cons) &&
                expression(pn->pn_kid3, &alt) &&
                builder.conditionalExpression(test, cons, alt, &pn->pn_pos, dst);
       }
 
       case TOK_OR:
       case TOK_AND:
       {
-        if (pn->pn_arity == PN_BINARY) {
+        if (pn->isArity(PN_BINARY)) {
             Value left, right;
             return expression(pn->pn_left, &left) &&
                    expression(pn->pn_right, &right) &&
-                   builder.logicalExpression(PN_TYPE(pn) == TOK_OR, left, right, &pn->pn_pos, dst);
+                   builder.logicalExpression(pn->isKind(TOK_OR), left, right, &pn->pn_pos, dst);
         }
         return leftAssociate(pn, dst);
       }
 
       case TOK_INC:
       case TOK_DEC:
       {
-        bool incr = PN_TYPE(pn) == TOK_INC;
-        bool prefix = PN_OP(pn) >= JSOP_INCNAME && PN_OP(pn) <= JSOP_DECELEM;
+        bool incr = pn->isKind(TOK_INC);
+        bool prefix = pn->getOp() >= JSOP_INCNAME && pn->getOp() <= JSOP_DECELEM;
 
         Value expr;
         return expression(pn->pn_kid, &expr) &&
                builder.updateExpression(expr, incr, prefix, &pn->pn_pos, dst);
       }
 
       case TOK_ASSIGN:
       {
-        AssignmentOperator op = aop(PN_OP(pn));
+        AssignmentOperator op = aop(pn->getOp());
         LOCAL_ASSERT(op > AOP_ERR && op < AOP_LIMIT);
 
         Value lhs, rhs;
         return pattern(pn->pn_left, NULL, &lhs) &&
                expression(pn->pn_right, &rhs) &&
                builder.assignmentExpression(op, lhs, rhs, &pn->pn_pos, dst);
       }
 
@@ -2466,38 +2464,38 @@ ASTSerializer::expression(JSParseNode *p
       case TOK_STAR:
       case TOK_DIVOP:
       case TOK_BITOR:
       case TOK_BITXOR:
       case TOK_BITAND:
       case TOK_IN:
       case TOK_INSTANCEOF:
       case TOK_DBLDOT:
-        if (pn->pn_arity == PN_BINARY) {
-            BinaryOperator op = binop(PN_TYPE(pn), PN_OP(pn));
+        if (pn->isArity(PN_BINARY)) {
+            BinaryOperator op = binop(pn->getKind(), pn->getOp());
             LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
 
             Value left, right;
             return expression(pn->pn_left, &left) &&
                    expression(pn->pn_right, &right) &&
                    builder.binaryExpression(op, left, right, &pn->pn_pos, dst);
         }
         return leftAssociate(pn, dst);
 
       case TOK_DELETE:
       case TOK_UNARYOP:
 #if JS_HAS_XML_SUPPORT
-        if (PN_OP(pn) == JSOP_XMLNAME ||
-            PN_OP(pn) == JSOP_SETXMLNAME ||
-            PN_OP(pn) == JSOP_BINDXMLNAME)
+        if (pn->isOp(JSOP_XMLNAME) ||
+            pn->isOp(JSOP_SETXMLNAME) ||
+            pn->isOp(JSOP_BINDXMLNAME))
             return expression(pn->pn_kid, dst);
 #endif
 
       {
-        UnaryOperator op = unop(PN_TYPE(pn), PN_OP(pn));
+        UnaryOperator op = unop(pn->getKind(), pn->getOp());
         LOCAL_ASSERT(op > UNOP_ERR && op < UNOP_LIMIT);
 
         Value expr;
         return expression(pn->pn_kid, &expr) &&
                builder.unaryExpression(op, expr, &pn->pn_pos, dst);
       }
 
       case TOK_NEW:
@@ -2520,17 +2518,17 @@ ASTSerializer::expression(JSParseNode *p
 
         for (next = next->pn_next; next; next = next->pn_next) {
             Value arg;
             if (!expression(next, &arg))
                 return false;
             args.infallibleAppend(arg);
         }
 
-        return PN_TYPE(pn) == TOK_NEW
+        return pn->isKind(TOK_NEW)
                ? builder.newExpression(callee, args, &pn->pn_pos, dst)
                : builder.callExpression(callee, args, &pn->pn_pos, dst);
       }
 
       case TOK_DOT:
       {
         Value expr, id;
         return expression(pn->pn_expr, &expr) &&
@@ -2538,33 +2536,33 @@ ASTSerializer::expression(JSParseNode *p
                builder.memberExpression(false, expr, id, &pn->pn_pos, dst);
       }
 
       case TOK_LB:
       {
         Value left, right;
         bool computed = true;
 #ifdef JS_HAS_XML_SUPPORT
-        computed = (PN_TYPE(pn->pn_right) != TOK_DBLCOLON &&
-                    PN_TYPE(pn->pn_right) != TOK_ANYNAME &&
-                    PN_TYPE(pn->pn_right) != TOK_AT);
+        computed = (!pn->pn_right->isKind(TOK_DBLCOLON) &&
+                    !pn->pn_right->isKind(TOK_ANYNAME) &&
+                    !pn->pn_right->isKind(TOK_AT));
 #endif
         return expression(pn->pn_left, &left) &&
                expression(pn->pn_right, &right) &&
                builder.memberExpression(computed, left, right, &pn->pn_pos, dst);
       }
 
       case TOK_RB:
       {
         NodeVector elts(cx);
         if (!elts.reserve(pn->pn_count))
             return false;
 
         for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
-            if (PN_TYPE(next) == TOK_COMMA) {
+            if (next->isKind(TOK_COMMA)) {
                 elts.infallibleAppend(MagicValue(JS_SERIALIZE_NO_NODE));
             } else {
                 Value expr;
                 if (!expression(next, &expr))
                     return false;
                 elts.infallibleAppend(expr);
             }
         }
@@ -2590,17 +2588,17 @@ ASTSerializer::expression(JSParseNode *p
 
       case TOK_NAME:
         return identifier(pn, dst);
 
       case TOK_STRING:
       case TOK_REGEXP:
       case TOK_NUMBER:
       case TOK_PRIMARY:
-        return PN_OP(pn) == JSOP_THIS ? builder.thisExpression(&pn->pn_pos, dst) : literal(pn, dst);
+        return pn->isOp(JSOP_THIS) ? builder.thisExpression(&pn->pn_pos, dst) : literal(pn, dst);
 
       case TOK_YIELD:
       {
         Value arg;
         return optExpression(pn->pn_kid, &arg) &&
                builder.yieldExpression(arg, &pn->pn_pos, dst);
       }
 
@@ -2612,17 +2610,17 @@ ASTSerializer::expression(JSParseNode *p
       }
 
       case TOK_USESHARP:
         return builder.graphIndexExpression(pn->pn_num, &pn->pn_pos, dst);
 
       case TOK_ARRAYCOMP:
         /* NB: it's no longer the case that pn_count could be 2. */
         LOCAL_ASSERT(pn->pn_count == 1);
-        LOCAL_ASSERT(PN_TYPE(pn->pn_head) == TOK_LEXICALSCOPE);
+        LOCAL_ASSERT(pn->pn_head->isKind(TOK_LEXICALSCOPE));
 
         return comprehension(pn->pn_head->pn_expr, dst);
 
       case TOK_LEXICALSCOPE:
       {
         pn = pn->pn_expr;
 
         NodeVector dtors(cx);
@@ -2636,49 +2634,49 @@ ASTSerializer::expression(JSParseNode *p
 #ifdef JS_HAS_XML_SUPPORT
       case TOK_ANYNAME:
         return builder.xmlAnyName(&pn->pn_pos, dst);
 
       case TOK_DBLCOLON:
       {
         Value right;
 
-        LOCAL_ASSERT(pn->pn_arity == PN_NAME || pn->pn_arity == PN_BINARY);
+        LOCAL_ASSERT(pn->isArity(PN_NAME) || pn->isArity(PN_BINARY));
 
         JSParseNode *pnleft;
         bool computed;
 
-        if (pn->pn_arity == PN_BINARY) {
+        if (pn->isArity(PN_BINARY)) {
             computed = true;
             pnleft = pn->pn_left;
             if (!expression(pn->pn_right, &right))
                 return false;
         } else {
-            JS_ASSERT(pn->pn_arity == PN_NAME);
+            JS_ASSERT(pn->isArity(PN_NAME));
             computed = false;
             pnleft = pn->pn_expr;
             if (!identifier(pn->pn_atom, NULL, &right))
                 return false;
         }
 
-        if (PN_TYPE(pnleft) == TOK_FUNCTION)
+        if (pnleft->isKind(TOK_FUNCTION))
             return builder.xmlFunctionQualifiedIdentifier(right, computed, &pn->pn_pos, dst);
 
         Value left;
         return expression(pnleft, &left) &&
                builder.xmlQualifiedIdentifier(left, right, computed, &pn->pn_pos, dst);
       }
 
       case TOK_AT:
       {
         Value expr;
         JSParseNode *kid = pn->pn_kid;
-        bool computed = ((PN_TYPE(kid) != TOK_NAME || PN_OP(kid) != JSOP_QNAMEPART) &&
-                         PN_TYPE(kid) != TOK_DBLCOLON &&
-                         PN_TYPE(kid) != TOK_ANYNAME);
+        bool computed = ((!kid->isKind(TOK_NAME) || !kid->isOp(JSOP_QNAMEPART)) &&
+                         !kid->isKind(TOK_DBLCOLON) &&
+                         !kid->isKind(TOK_ANYNAME));
         return expression(kid, &expr) &&
             builder.xmlAttributeSelector(expr, computed, &pn->pn_pos, dst);
       }
 
       case TOK_FILTER:
       {
         Value left, right;
         return expression(pn->pn_left, &left) &&
@@ -2695,17 +2693,17 @@ ASTSerializer::expression(JSParseNode *p
 #endif
     }
 }
 
 bool
 ASTSerializer::xml(JSParseNode *pn, Value *dst)
 {
     JS_CHECK_RECURSION(cx, return false);
-    switch (PN_TYPE(pn)) {
+    switch (pn->getKind()) {
 #ifdef JS_HAS_XML_SUPPORT
       case TOK_LC:
       {
         Value expr;
         return expression(pn->pn_kid, &expr) &&
                builder.xmlEscapeExpression(expr, &pn->pn_pos, dst);
       }
 
@@ -2749,20 +2747,20 @@ ASTSerializer::xml(JSParseNode *pn, Valu
         return builder.xmlPointTag(elts, &pn->pn_pos, dst);
       }
 
       case TOK_XMLTEXT:
       case TOK_XMLSPACE:
         return builder.xmlText(atomContents(pn->pn_atom), &pn->pn_pos, dst);
 
       case TOK_XMLNAME:
-        if (pn->pn_arity == PN_NULLARY)
+        if (pn->isArity(PN_NULLARY))
             return builder.xmlName(atomContents(pn->pn_atom), &pn->pn_pos, dst);
 
-        LOCAL_ASSERT(pn->pn_arity == PN_LIST);
+        LOCAL_ASSERT(pn->isArity(PN_LIST));
 
         {
             NodeVector elts(cx);
             return xmls(pn, elts) &&
                    builder.xmlName(elts, &pn->pn_pos, dst);
         }
 
       case TOK_XMLATTR:
@@ -2787,29 +2785,29 @@ ASTSerializer::xml(JSParseNode *pn, Valu
       default:
         LOCAL_NOT_REACHED("unexpected XML node type");
     }
 }
 
 bool
 ASTSerializer::propertyName(JSParseNode *pn, Value *dst)
 {
-    if (PN_TYPE(pn) == TOK_NAME)
+    if (pn->isKind(TOK_NAME))
         return identifier(pn, dst);
 
-    LOCAL_ASSERT(PN_TYPE(pn) == TOK_STRING || PN_TYPE(pn) == TOK_NUMBER);
+    LOCAL_ASSERT(pn->isKind(TOK_STRING) || pn->isKind(TOK_NUMBER));
 
     return literal(pn, dst);
 }
 
 bool
 ASTSerializer::property(JSParseNode *pn, Value *dst)
 {
     PropKind kind;
-    switch (PN_OP(pn)) {
+    switch (pn->getOp()) {
       case JSOP_INITPROP:
         kind = PROP_INIT;
         break;
 
       case JSOP_GETTER:
         kind = PROP_GETTER;
         break;
 
@@ -2826,17 +2824,17 @@ ASTSerializer::property(JSParseNode *pn,
            expression(pn->pn_right, &val) &&
            builder.propertyInitializer(key, val, kind, &pn->pn_pos, dst);
 }
 
 bool
 ASTSerializer::literal(JSParseNode *pn, Value *dst)
 {
     Value val;
-    switch (PN_TYPE(pn)) {
+    switch (pn->getKind()) {
       case TOK_STRING:
         val.setString(pn->pn_atom);
         break;
 
       case TOK_REGEXP:
       {
         JSObject *re1 = pn->pn_objbox ? pn->pn_objbox->object : NULL;
         LOCAL_ASSERT(re1 && re1->isRegExp());
@@ -2853,63 +2851,63 @@ ASTSerializer::literal(JSParseNode *pn, 
         break;
       }
 
       case TOK_NUMBER:
         val.setNumber(pn->pn_dval);
         break;
 
       case TOK_PRIMARY:
-        if (PN_OP(pn) == JSOP_NULL)
+        if (pn->isOp(JSOP_NULL))
             val.setNull();
         else
-            val.setBoolean(PN_OP(pn) == JSOP_TRUE);
+            val.setBoolean(pn->isOp(JSOP_TRUE));
         break;
 
       default:
         LOCAL_NOT_REACHED("unexpected literal type");
     }
 
     return builder.literal(val, &pn->pn_pos, dst);
 }
 
 bool
 ASTSerializer::arrayPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
 {
-    JS_ASSERT(PN_TYPE(pn) == TOK_RB);
+    JS_ASSERT(pn->isKind(TOK_RB));
 
     NodeVector elts(cx);
     if (!elts.reserve(pn->pn_count))
         return false;
 
     for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
-        if (PN_TYPE(next) == TOK_COMMA) {
+        if (next->isKind(TOK_COMMA)) {
             elts.infallibleAppend(MagicValue(JS_SERIALIZE_NO_NODE));
         } else {
             Value patt;
             if (!pattern(next, pkind, &patt))
                 return false;
             elts.infallibleAppend(patt);
         }
     }
 
     return builder.arrayPattern(elts, &pn->pn_pos, dst);
 }
 
 bool
 ASTSerializer::objectPattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
 {
-    JS_ASSERT(PN_TYPE(pn) == TOK_RC);
+    JS_ASSERT(pn->isKind(TOK_RC));
 
     NodeVector elts(cx);
     if (!elts.reserve(pn->pn_count))
         return false;
 
     for (JSParseNode *next = pn->pn_head; next; next = next->pn_next) {
-        LOCAL_ASSERT(PN_OP(next) == JSOP_INITPROP);
+        LOCAL_ASSERT(next->isOp(JSOP_INITPROP));
 
         Value key, patt, prop;
         if (!propertyName(next->pn_left, &key) ||
             !pattern(next->pn_right, pkind, &patt) ||
             !builder.propertyPattern(key, patt, &next->pn_pos, &prop)) {
             return false;
         }
 
@@ -2918,17 +2916,17 @@ ASTSerializer::objectPattern(JSParseNode
 
     return builder.objectPattern(elts, &pn->pn_pos, dst);
 }
 
 bool
 ASTSerializer::pattern(JSParseNode *pn, VarDeclKind *pkind, Value *dst)
 {
     JS_CHECK_RECURSION(cx, return false);
-    switch (PN_TYPE(pn)) {
+    switch (pn->getKind()) {
       case TOK_RC:
         return objectPattern(pn, pkind, dst);
 
       case TOK_RB:
         return arrayPattern(pn, pkind, dst);
 
       case TOK_NAME:
         if (pkind && (pn->pn_dflags & PND_CONST))
@@ -2944,17 +2942,17 @@ bool
 ASTSerializer::identifier(JSAtom *atom, TokenPos *pos, Value *dst)
 {
     return builder.identifier(atomContents(atom), pos, dst);
 }
 
 bool
 ASTSerializer::identifier(JSParseNode *pn, Value *dst)
 {
-    LOCAL_ASSERT(pn->pn_arity == PN_NAME || pn->pn_arity == PN_NULLARY);
+    LOCAL_ASSERT(pn->isArity(PN_NAME) || pn->isArity(PN_NULLARY));
     LOCAL_ASSERT(pn->pn_atom);
 
     return identifier(pn->pn_atom, &pn->pn_pos, dst);
 }
 
 bool
 ASTSerializer::function(JSParseNode *pn, ASTType type, Value *dst)
 {
@@ -2975,63 +2973,63 @@ ASTSerializer::function(JSParseNode *pn,
 #endif
 
     Value id;
     if (!optIdentifier(func->atom, NULL, &id))
         return false;
 
     NodeVector args(cx);
 
-    JSParseNode *argsAndBody = (PN_TYPE(pn->pn_body) == TOK_UPVARS)
+    JSParseNode *argsAndBody = pn->pn_body->isKind(TOK_UPVARS)
                                ? pn->pn_body->pn_tree
                                : pn->pn_body;
 
     Value body;
     return functionArgsAndBody(argsAndBody, args, &body) &&
            builder.function(type, &pn->pn_pos, id, args, body, isGenerator, isExpression, dst);
 }
 
 bool
 ASTSerializer::functionArgsAndBody(JSParseNode *pn, NodeVector &args, Value *body)
 {
     JSParseNode *pnargs;
     JSParseNode *pnbody;
 
     /* Extract the args and body separately. */
-    if (PN_TYPE(pn) == TOK_ARGSBODY) {
+    if (pn->isKind(TOK_ARGSBODY)) {
         pnargs = pn;
         pnbody = pn->last();
     } else {
         pnargs = NULL;
         pnbody = pn;
     }
 
     JSParseNode *pndestruct;
 
     /* Extract the destructuring assignments. */
-    if (pnbody->pn_arity == PN_LIST && (pnbody->pn_xflags & PNX_DESTRUCT)) {
+    if (pnbody->isArity(PN_LIST) && (pnbody->pn_xflags & PNX_DESTRUCT)) {
         JSParseNode *head = pnbody->pn_head;
-        LOCAL_ASSERT(head && PN_TYPE(head) == TOK_SEMI);
+        LOCAL_ASSERT(head && head->isKind(TOK_SEMI));
 
         pndestruct = head->pn_kid;
-        LOCAL_ASSERT(pndestruct && PN_TYPE(pndestruct) == TOK_VAR);
+        LOCAL_ASSERT(pndestruct && pndestruct->isKind(TOK_VAR));
     } else {
         pndestruct = NULL;
     }
 
     /* Serialize the arguments and body. */
-    switch (PN_TYPE(pnbody)) {
+    switch (pnbody->getKind()) {
       case TOK_RETURN: /* expression closure, no destructured args */
         return functionArgs(pn, pnargs, NULL, pnbody, args) &&
                expression(pnbody->pn_kid, body);
 
       case TOK_SEQ:    /* expression closure with destructured args */
       {
         JSParseNode *pnstart = pnbody->pn_head->pn_next;
-        LOCAL_ASSERT(pnstart && PN_TYPE(pnstart) == TOK_RETURN);
+        LOCAL_ASSERT(pnstart && pnstart->isKind(TOK_RETURN));
 
         return functionArgs(pn, pnargs, pndestruct, pnbody, args) &&
                expression(pnstart->pn_kid, body);
       }
 
       case TOK_LC:     /* statement closure */
       {
         JSParseNode *pnstart = (pnbody->pn_xflags & PNX_DESTRUCT)
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -1166,17 +1166,17 @@ ParseNodeToQName(Parser *parser, JSParse
     JSContext *cx = parser->context;
     JSLinearString *uri, *prefix;
     size_t length, offset;
     const jschar *start, *limit, *colon;
     uint32 n;
     JSObject *ns;
     JSLinearString *nsprefix;
 
-    JS_ASSERT(pn->pn_arity == PN_NULLARY);
+    JS_ASSERT(pn->isArity(PN_NULLARY));
     JSAtom *str = pn->pn_atom;
     start = str->chars();
     length = str->length();
     JS_ASSERT(length != 0 && *start != '@');
     JS_ASSERT(length != 1 || *start != '*');
 
     JSAtom *localName;
 
@@ -1313,17 +1313,17 @@ ParseNodeToXML(Parser *parser, JSParseNo
     /*
      * Cases return early to avoid common code that gets an outermost xml's
      * object, which protects GC-things owned by xml and its descendants from
      * garbage collection.
      */
     xml = NULL;
     if (!js_EnterLocalRootScope(cx))
         return NULL;
-    switch (pn->pn_type) {
+    switch (pn->getKind()) {
       case TOK_XMLELEM:
         length = inScopeNSes->length;
         pn2 = pn->pn_head;
         xml = ParseNodeToXML(parser, pn2, inScopeNSes, flags);
         if (!xml)
             goto fail;
 
         n = pn->pn_count;
@@ -1331,22 +1331,22 @@ ParseNodeToXML(Parser *parser, JSParseNo
         n -= 2;
         if (!xml->xml_kids.setCapacity(cx, n))
             goto fail;
 
         i = 0;
         while ((pn2 = pn2->pn_next) != NULL) {
             if (!pn2->pn_next) {
                 /* Don't append the end tag! */
-                JS_ASSERT(pn2->pn_type == TOK_XMLETAGO);
+                JS_ASSERT(pn2->isKind(TOK_XMLETAGO));
                 break;
             }
 
             if ((flags & XSF_IGNORE_WHITESPACE) &&
-                n > 1 && pn2->pn_type == TOK_XMLSPACE) {
+                n > 1 && pn2->isKind(TOK_XMLSPACE)) {
                 --n;
                 continue;
             }
 
             kid = ParseNodeToXML(parser, pn2, inScopeNSes, flags);
             if (kid == PN2X_SKIP_CHILD) {
                 --n;
                 continue;
@@ -1387,17 +1387,17 @@ ParseNodeToXML(Parser *parser, JSParseNo
 
         i = 0;
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             /*
              * Always ignore insignificant whitespace in lists -- we shouldn't
              * condition this on an XML.ignoreWhitespace setting when the list
              * constructor is XMLList (note XML/XMLList unification hazard).
              */
-            if (pn2->pn_type == TOK_XMLSPACE) {
+            if (pn2->isKind(TOK_XMLSPACE)) {
                 --n;
                 continue;
             }
 
             kid = ParseNodeToXML(parser, pn2, inScopeNSes, flags);
             if (kid == PN2X_SKIP_CHILD) {
                 --n;
                 continue;
@@ -1413,34 +1413,34 @@ ParseNodeToXML(Parser *parser, JSParseNo
         if (n < pn->pn_count)
             xml->xml_kids.trim();
         break;
 
       case TOK_XMLSTAGO:
       case TOK_XMLPTAGC:
         length = inScopeNSes->length;
         pn2 = pn->pn_head;
-        JS_ASSERT(pn2->pn_type == TOK_XMLNAME);
-        if (pn2->pn_arity == PN_LIST)
+        JS_ASSERT(pn2->isKind(TOK_XMLNAME));
+        if (pn2->isArity(PN_LIST))
             goto syntax;
 
         xml = js_NewXML(cx, JSXML_CLASS_ELEMENT);
         if (!xml)
             goto fail;
 
         /* First pass: check syntax and process namespace declarations. */
         JS_ASSERT(pn->pn_count >= 1);
         n = pn->pn_count - 1;
         pnp = &pn2->pn_next;
         head = *pnp;
         while ((pn2 = *pnp) != NULL) {
             size_t length;
             const jschar *chars;
 
-            if (pn2->pn_type != TOK_XMLNAME || pn2->pn_arity != PN_NULLARY)
+            if (!pn2->isKind(TOK_XMLNAME) || !pn2->isArity(PN_NULLARY))
                 goto syntax;
 
             /* Enforce "Well-formedness constraint: Unique Att Spec". */
             for (pn3 = head; pn3 != pn2; pn3 = pn3->pn_next->pn_next) {
                 if (pn3->pn_atom == pn2->pn_atom) {
                     Value v = StringValue(pn2->pn_atom);
                     JSAutoByteString bytes;
                     if (js_ValueToPrintable(cx, v, &bytes)) {
@@ -1450,17 +1450,17 @@ ParseNodeToXML(Parser *parser, JSParseNo
                     }
                     goto fail;
                 }
             }
 
             JSAtom *atom = pn2->pn_atom;
             pn2 = pn2->pn_next;
             JS_ASSERT(pn2);
-            if (pn2->pn_type != TOK_XMLATTR)
+            if (!pn2->isKind(TOK_XMLATTR))
                 goto syntax;
 
             chars = atom->chars();
             length = atom->length();
             if (length >= 5 &&
                 IS_XMLNS_CHARS(chars) &&
                 (length == 5 || chars[5] == ':')) {
                 JSLinearString *uri, *prefix;
@@ -1547,45 +1547,45 @@ ParseNodeToXML(Parser *parser, JSParseNo
                                                  bytes.ptr());
                     }
                     goto fail;
                 }
             }
 
             pn2 = pn2->pn_next;
             JS_ASSERT(pn2);
-            JS_ASSERT(pn2->pn_type == TOK_XMLATTR);
+            JS_ASSERT(pn2->isKind(TOK_XMLATTR));
 
             attr = js_NewXML(cx, JSXML_CLASS_ATTRIBUTE);
             if (!attr)
                 goto fail;
 
             XMLARRAY_SET_MEMBER(&xml->xml_attrs, i, attr);
             attr->parent = xml;
             attr->name = qn;
             attr->xml_value = pn2->pn_atom;
         }
 
         /* Point tag closes its own namespace scope. */
-        if (pn->pn_type == TOK_XMLPTAGC)
+        if (pn->isKind(TOK_XMLPTAGC))
             XMLARRAY_TRUNCATE(cx, inScopeNSes, length);
         break;
 
       case TOK_XMLSPACE:
       case TOK_XMLTEXT:
       case TOK_XMLCDATA:
       case TOK_XMLCOMMENT:
       case TOK_XMLPI:
         str = pn->pn_atom;
         qn = NULL;
-        if (pn->pn_type == TOK_XMLCOMMENT) {
+        if (pn->isKind(TOK_XMLCOMMENT)) {
             if (flags & XSF_IGNORE_COMMENTS)
                 goto skip_child;
             xml_class = JSXML_CLASS_COMMENT;
-        } else if (pn->pn_type == TOK_XMLPI) {
+        } else if (pn->isKind(TOK_XMLPI)) {
             if (IS_XML(str)) {
                 Value v = StringValue(str);
                 JSAutoByteString bytes;
                 if (js_ValueToPrintable(cx, v, &bytes)) {
                     ReportCompileErrorNumber(cx, &parser->tokenStream, pn,
                                              JSREPORT_ERROR, JSMSG_RESERVED_ID, bytes.ptr());
                 }
                 goto fail;
@@ -1604,17 +1604,17 @@ ParseNodeToXML(Parser *parser, JSParseNo
             /* CDATA section content, or element text. */
             xml_class = JSXML_CLASS_TEXT;
         }
 
         xml = js_NewXML(cx, xml_class);
         if (!xml)
             goto fail;
         xml->name = qn;
-        if (pn->pn_type == TOK_XMLSPACE)
+        if (pn->isKind(TOK_XMLSPACE))
             xml->xml_flags |= XMLF_WHITESPACE_TEXT;
         xml->xml_value = str;
         break;
 
       default:
         goto syntax;
     }