Bug 701620 - Split up PNK_LC into PNK_STATEMENTLIST and PNK_XMLCURLYEXPR. r=jorendorff
authorJeff Walden <jwalden@mit.edu>
Fri, 11 Nov 2011 18:05:43 -0800
changeset 81685 db3280d6199df7f1d356c126efb3a1ea2faa2ac8
parent 81684 c7099e04ec39335acf8483b71fede74304b0d7d9
child 81686 ef50be56af0390878223a5b726cca6d6443f676e
push idunknown
push userunknown
push dateunknown
reviewersjorendorff
bugs701620
milestone11.0a1
Bug 701620 - Split up PNK_LC into PNK_STATEMENTLIST and PNK_XMLCURLYEXPR. r=jorendorff
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/FoldConstants.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/SemanticAnalysis.cpp
js/src/jsreflect.cpp
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -1449,17 +1449,18 @@ static ptrdiff_t
 EmitTraceOp(JSContext *cx, BytecodeEmitter *bce, ParseNode *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->isKind(PNK_LC) && nextpn->isArity(PN_LIST) && nextpn->pn_head)
+        JS_ASSERT_IF(nextpn->isKind(PNK_STATEMENTLIST), nextpn->isArity(PN_LIST));
+        if (nextpn->isKind(PNK_STATEMENTLIST) && nextpn->pn_head)
             nextpn = nextpn->pn_head;
         if (!UpdateLineNumberNotes(cx, bce, nextpn->pn_pos.begin.lineno))
             return -1;
     }
 
     uint32 index = bce->traceIndex;
     if (index < UINT16_MAX)
         bce->traceIndex++;
@@ -3340,17 +3341,17 @@ EmitSwitch(JSContext *cx, BytecodeEmitte
     if (!EmitTree(cx, bce, pn->pn_left))
         return JS_FALSE;
 
     /* Switch bytecodes run from here till end of final case. */
     top = bce->offset();
 #if !JS_HAS_BLOCK_SCOPE
     PushStatement(bce, &stmtInfo, STMT_SWITCH, top);
 #else
-    if (pn2->isKind(PNK_LC)) {
+    if (pn2->isKind(PNK_STATEMENTLIST)) {
         PushStatement(bce, &stmtInfo, STMT_SWITCH, top);
     } else {
         /* Re-push the switch's statement info record. */
         if (!tps.repushBlock(cx, bce))
             return JS_FALSE;
 
         /*
          * Set the statement info record's idea of top. Reset top too, since
@@ -5314,30 +5315,30 @@ EmitXMLTag(JSContext *cx, BytecodeEmitte
                           : cx->runtime->atomState.stagoAtom;
         if (!bce->makeAtomIndex(tagAtom, &index))
             return false;
         EMIT_INDEX_OP(JSOP_STRING, index);
     }
 
     JS_ASSERT(pn->pn_count != 0);
     ParseNode *pn2 = pn->pn_head;
-    if (pn2->isKind(PNK_LC) && Emit1(cx, bce, JSOP_STARTXMLEXPR) < 0)
+    if (pn2->isKind(PNK_XMLCURLYEXPR) && Emit1(cx, bce, JSOP_STARTXMLEXPR) < 0)
         return false;
     if (!EmitTree(cx, bce, pn2))
         return false;
     if (Emit1(cx, bce, JSOP_ADD) < 0)
         return false;
 
     uint32 i;
     for (pn2 = pn2->pn_next, i = 0; pn2; pn2 = pn2->pn_next, i++) {
-        if (pn2->isKind(PNK_LC) && Emit1(cx, bce, JSOP_STARTXMLEXPR) < 0)
+        if (pn2->isKind(PNK_XMLCURLYEXPR) && Emit1(cx, bce, JSOP_STARTXMLEXPR) < 0)
             return false;
         if (!EmitTree(cx, bce, pn2))
             return false;
-        if ((i & 1) && pn2->isKind(PNK_LC)) {
+        if ((i & 1) && pn2->isKind(PNK_XMLCURLYEXPR)) {
             if (Emit1(cx, bce, JSOP_TOATTRVAL) < 0)
                 return false;
         }
         if (Emit1(cx, bce, (i & 1) ? JSOP_ADDATTRVAL : JSOP_ADDATTRNAME) < 0)
             return false;
     }
 
     {
@@ -5783,17 +5784,17 @@ frontend::EmitTree(JSContext *cx, Byteco
 #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 PNK_LC case.
+             * comments in the PNK_STATEMENTLIST case.
              */
             JS_ASSERT(pn->isOp(JSOP_NOP));
             JS_ASSERT(bce->inFunction());
             if (!EmitFunctionDefNop(cx, bce, pn->pn_index))
                 return JS_FALSE;
             break;
         }
 
@@ -6171,28 +6172,28 @@ frontend::EmitTree(JSContext *cx, Byteco
         }
         if (pn->pn_hidden && NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
             return JS_FALSE;
         if (Emit1(cx, bce, JSOP_YIELD) < 0)
             return JS_FALSE;
         break;
 #endif
 
-      case PNK_LC:
+#if JS_HAS_XML_SUPPORT
+      case PNK_XMLCURLYEXPR:
+        JS_ASSERT(pn->isArity(PN_UNARY));
+        if (!EmitTree(cx, bce, pn->pn_kid))
+            return JS_FALSE;
+        if (Emit1(cx, bce, pn->getOp()) < 0)
+            return JS_FALSE;
+        break;
+#endif
+
+      case PNK_STATEMENTLIST:
       {
-#if JS_HAS_XML_SUPPORT
-        if (pn->isArity(PN_UNARY)) {
-            if (!EmitTree(cx, bce, pn->pn_kid))
-                return JS_FALSE;
-            if (Emit1(cx, bce, pn->getOp()) < 0)
-                return JS_FALSE;
-            break;
-        }
-#endif
-
         JS_ASSERT(pn->isArity(PN_LIST));
 
         noteIndex = -1;
         tmp = bce->offset();
         if (pn->pn_xflags & PNX_NEEDBRACES) {
             noteIndex = NewSrcNote2(cx, bce, SRC_BRACE, 0);
             if (noteIndex < 0 || Emit1(cx, bce, JSOP_NOP) < 0)
                 return JS_FALSE;
@@ -6350,19 +6351,19 @@ frontend::EmitTree(JSContext *cx, Byteco
          */
         atom = pn->pn_atom;
 
         jsatomid index;
         if (!bce->makeAtomIndex(atom, &index))
             return JS_FALSE;
 
         pn2 = pn->expr();
-        noteType = (pn2->isKind(PNK_LC) ||
+        noteType = (pn2->isKind(PNK_STATEMENTLIST) ||
                     (pn2->isKind(PNK_LEXICALSCOPE) &&
-                     pn2->expr()->isKind(PNK_LC)))
+                     pn2->expr()->isKind(PNK_STATEMENTLIST)))
                    ? SRC_LABELBRACE
                    : SRC_LABEL;
         noteIndex = NewSrcNote2(cx, bce, noteType, ptrdiff_t(index));
         if (noteIndex < 0)
             return JS_FALSE;
 
         top = EmitJump(cx, bce, JSOP_LABEL, 0);
         if (top < 0)
@@ -7286,17 +7287,17 @@ frontend::EmitTree(JSContext *cx, Byteco
           case PNK_XMLSTAGO:
             break;
           default:
             if (Emit1(cx, bce, JSOP_STARTXML) < 0)
                 return JS_FALSE;
         }
 
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
-            if (pn2->isKind(PNK_LC) && Emit1(cx, bce, JSOP_STARTXMLEXPR) < 0)
+            if (pn2->isKind(PNK_XMLCURLYEXPR) && Emit1(cx, bce, JSOP_STARTXMLEXPR) < 0)
                 return JS_FALSE;
             if (!EmitTree(cx, bce, pn2))
                 return JS_FALSE;
             if (pn2 != pn->pn_head && Emit1(cx, bce, JSOP_ADD) < 0)
                 return JS_FALSE;
         }
 
         if (pn->pn_xflags & PNX_XMLROOT) {
@@ -7325,17 +7326,17 @@ frontend::EmitTree(JSContext *cx, Byteco
         break;
 
       case PNK_XMLNAME:
         JS_ASSERT(!bce->inStrictMode());
 
         if (pn->isArity(PN_LIST)) {
             JS_ASSERT(pn->pn_count != 0);
             for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
-                if (pn2->isKind(PNK_LC) && Emit1(cx, bce, JSOP_STARTXMLEXPR) < 0)
+                if (pn2->isKind(PNK_XMLCURLYEXPR) && Emit1(cx, bce, JSOP_STARTXMLEXPR) < 0)
                     return JS_FALSE;
                 if (!EmitTree(cx, bce, pn2))
                     return JS_FALSE;
                 if (pn2 != pn->pn_head && Emit1(cx, bce, JSOP_ADD) < 0)
                     return JS_FALSE;
             }
         } else {
             JS_ASSERT(pn->isArity(PN_NULLARY));
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -589,17 +589,17 @@ js::FoldConstants(JSContext *cx, ParseNo
         if (!pn2 || (pn->isKind(PNK_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 PNK_IF as PNK_HOOK can never have a null kid
              * or an empty statement for a child.
              */
-            pn->setKind(PNK_LC);
+            pn->setKind(PNK_STATEMENTLIST);
             pn->setArity(PN_LIST);
             pn->makeEmpty();
         }
         tc->freeTree(pn2);
         if (pn3 && pn3 != pn2)
             tc->freeTree(pn3);
         break;
 
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -75,17 +75,18 @@ enum ParseNodeKind {
     PNK_STAR,
     PNK_DIV,
     PNK_MOD,
     PNK_INC,
     PNK_DEC,
     PNK_DOT,
     PNK_LB,
     PNK_RB,
-    PNK_LC,
+    PNK_STATEMENTLIST,
+    PNK_XMLCURLYEXPR,
     PNK_RC,
     PNK_LP,
     PNK_RP,
     PNK_NAME,
     PNK_NUMBER,
     PNK_STRING,
     PNK_REGEXP,
     PNK_TRUE,
@@ -200,50 +201,55 @@ enum ParseNodeKind {
  * Label        Variant     Members
  * -----        -------     -------
  * <Definitions>
  * PNK_FUNCTION name        pn_funbox: ptr to js::FunctionBox holding function
  *                            object containing arg and var properties.  We
  *                            create the function object at parse (not emit)
  *                            time to specialize arg and var bytecodes early.
  *                          pn_body: PNK_UPVARS if the function's source body
- *                                   depends on outer names, else PNK_ARGSBODY
- *                                   if formal parameters, else PNK_LC node for
- *                                   function body statements, else PNK_RETURN
- *                                   for expression closure, else PNK_SEQ for
- *                                   expression closure with destructured
- *                                   formal parameters
+ *                                     depends on outer names,
+ *                                   PNK_ARGSBODY if formal parameters,
+ *                                   PNK_STATEMENTLIST node for function body
+ *                                     statements,
+ *                                   PNK_RETURN for expression closure, or
+ *                                   PNK_SEQ for expression closure with
+ *                                     destructured formal parameters
  *                          pn_cookie: static level and var index for function
  *                          pn_dflags: PND_* definition/use flags (see below)
  *                          pn_blockid: block id number
- * PNK_ARGSBODY list        list of formal parameters followed by PNK_LC node
- *                            for function body statements as final element
+ * PNK_ARGSBODY list        list of formal parameters followed by
+ *                            PNK_STATEMENTLIST node for function body
+ *                            statements as final element
  *                          pn_count: 1 + number of formal parameters
  * PNK_UPVARS   nameset     pn_names: lexical dependencies (js::Definitions)
  *                            defined in enclosing scopes, or ultimately not
  *                            defined (free variables, either global property
  *                            references or reference errors).
- *                          pn_tree: PNK_ARGSBODY or PNK_LC node
+ *                          pn_tree: PNK_ARGSBODY or PNK_STATEMENTLIST node
  *
  * <Statements>
- * PNK_LC       list        pn_head: list of pn_count statements
+ * PNK_STATEMENTLIST list   pn_head: list of pn_count statements
  * PNK_IF       ternary     pn_kid1: cond, pn_kid2: then, pn_kid3: else or null.
  *                            In body of a comprehension or desugared generator
  *                            expression, pn_kid2 is PNK_YIELD, PNK_ARRAYPUSH,
- *                            or (if the push was optimized away) empty PNK_LC.
+ *                            or (if the push was optimized away) empty
+ *                            PNK_STATEMENTLIST.
  * PNK_SWITCH   binary      pn_left: discriminant
  *                          pn_right: list of PNK_CASE nodes, with at most one
  *                            PNK_DEFAULT node, or if there are let bindings
  *                            in the top level of the switch body's cases, a
  *                            PNK_LEXICALSCOPE node that contains the list of
  *                            PNK_CASE nodes.
  * PNK_CASE,    binary      pn_left: case expr
- *                          pn_right: PNK_LC node for this case's statements
+ *                          pn_right: PNK_STATEMENTLIST node for this case's
+ *                            statements
  * PNK_DEFAULT  binary      pn_left: null
- *                          pn_right: PNK_LC node for this default's statements
+ *                          pn_right: PNK_STATEMENTLIST node for this default's
+ *                            statements
  *                          pn_val: constant value if lookup or table switch
  * PNK_WHILE    binary      pn_left: cond, pn_right: body
  * PNK_DOWHILE  binary      pn_left: body, pn_right: cond
  * PNK_FOR      binary      pn_left: either PNK_FORIN (for-in statement) or
  *                            PNK_FORHEAD (for(;;) statement)
  *                          pn_right: body
  * PNK_FORIN    ternary     pn_kid1:  PNK_VAR to left of 'in', or NULL
  *                            its pn_xflags may have PNX_POPVAR
@@ -412,32 +418,32 @@ enum ParseNodeKind {
  * PNK_XMLNAME  nullary     pn_atom: XML name, with no {expr} embedded
  * PNK_XMLNAME  list        pn_head: tag name or {expr}, ... name or {expr}
  * PNK_XMLATTR, nullary     pn_atom: attribute value string; pn_op: JSOP_STRING
  * PNK_XMLCDATA,
  * PNK_XMLCOMMENT
  * PNK_XMLPI    nullary     pn_pitarget: XML processing instruction target
  *                          pn_pidata: XML PI data, or null if no data
  * PNK_XMLTEXT  nullary     pn_atom: marked-up text, or null if empty string
- * PNK_LC       unary       {expr} in XML tag or content; pn_kid is expr
+ * PNK_XMLCURLYEXPR unary   {expr} in XML tag or content; pn_kid is expr
  *
  * So an XML tag with no {expr} and three attributes is a list with the form:
  *
  *    (tagname attrname1 attrvalue1 attrname2 attrvalue2 attrname2 attrvalue3)
  *
  * An XML tag with embedded expressions like so:
  *
  *    <name1{expr1} name2{expr2}name3={expr3}>
  *
  * would have the form:
  *
  *    ((name1 {expr1}) (name2 {expr2} name3) {expr3})
  *
  * where () bracket a list with elements separated by spaces, and {expr} is a
- * PNK_LC unary node with expr as its kid.
+ * PNK_XMLCURLYEXPR unary node with expr as its kid.
  *
  * Thus, the attribute name/value pairs occupy successive odd and even list
  * locations, where pn_head is the PNK_XMLNAME node at list location 0.  The
  * parser builds the same sort of structures for elements:
  *
  *    <a x={x}>Hi there!<b y={y}>How are you?</b><answer>{x + y}</answer></a>
  *
  * translates to:
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -256,17 +256,17 @@ Parser::trace(JSTracer *trc)
         tc->trace(trc);
 }
 
 static bool
 GenerateBlockIdForStmtNode(ParseNode *pn, TreeContext *tc)
 {
     JS_ASSERT(tc->topStmt);
     JS_ASSERT(STMT_MAYBE_SCOPE(tc->topStmt));
-    JS_ASSERT(pn->isKind(PNK_LC) || pn->isKind(PNK_LEXICALSCOPE));
+    JS_ASSERT(pn->isKind(PNK_STATEMENTLIST) || pn->isKind(PNK_LEXICALSCOPE));
     if (!GenerateBlockId(tc, tc->topStmt->blockid))
         return false;
     pn->pn_blockid = tc->topStmt->blockid;
     return true;
 }
 
 /*
  * Parse a top-level JS script.
@@ -316,17 +316,17 @@ JS_STATIC_ASSERT(UpvarCookie::FREE_LEVEL
 
 static int
 HasFinalReturn(ParseNode *pn)
 {
     ParseNode *pn2, *pn3;
     uintN rv, rv2, hasDefault;
 
     switch (pn->getKind()) {
-      case PNK_LC:
+      case PNK_STATEMENTLIST:
         if (!pn->pn_head)
             return ENDS_IN_OTHER;
         return HasFinalReturn(pn->last());
 
       case PNK_IF:
         if (!pn->pn_kid3)
             return ENDS_IN_OTHER;
         return HasFinalReturn(pn->pn_kid2) & HasFinalReturn(pn->pn_kid3);
@@ -363,17 +363,17 @@ HasFinalReturn(ParseNode *pn)
         hasDefault = ENDS_IN_OTHER;
         pn2 = pn->pn_right;
         if (pn2->isKind(PNK_LEXICALSCOPE))
             pn2 = pn2->expr();
         for (pn2 = pn2->pn_head; rv && pn2; pn2 = pn2->pn_next) {
             if (pn2->isKind(PNK_DEFAULT))
                 hasDefault = ENDS_IN_RETURN;
             pn3 = pn2->pn_right;
-            JS_ASSERT(pn3->isKind(PNK_LC));
+            JS_ASSERT(pn3->isKind(PNK_STATEMENTLIST));
             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;
             }
         }
@@ -1766,17 +1766,17 @@ Parser::recognizeDirectivePrologue(Parse
 ParseNode *
 Parser::statements()
 {
     ParseNode *pn2, *saveBlock;
     TokenKind tt;
 
     JS_CHECK_RECURSION(context, return NULL);
 
-    ParseNode *pn = ListNode::create(PNK_LC, tc);
+    ParseNode *pn = ListNode::create(PNK_STATEMENTLIST, tc);
     if (!pn)
         return NULL;
     pn->makeEmpty();
     pn->pn_blockid = tc->blockid();
     saveBlock = tc->blockNode;
     tc->blockNode = pn;
 
     bool inDirectivePrologue = tc->atBodyLevel();
@@ -2946,17 +2946,17 @@ Parser::switchStatement()
     /*
      * NB: we must push stmtInfo before calling GenerateBlockIdForStmtNode
      * because that function states tc->topStmt->blockid.
      */
     StmtInfo stmtInfo;
     PushStatement(tc, &stmtInfo, STMT_SWITCH, -1);
 
     /* pn2 is a list of case nodes. The default case has pn_left == NULL */
-    ParseNode *pn2 = ListNode::create(PNK_LC, tc);
+    ParseNode *pn2 = ListNode::create(PNK_STATEMENTLIST, tc);
     if (!pn2)
         return NULL;
     pn2->makeEmpty();
     if (!GenerateBlockIdForStmtNode(pn2, tc))
         return NULL;
     ParseNode *saveBlock = tc->blockNode;
     tc->blockNode = pn2;
 
@@ -2998,17 +2998,17 @@ Parser::switchStatement()
         pn2->append(pn3);
         if (pn2->pn_count == JS_BIT(16)) {
             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_TOO_MANY_CASES);
             return NULL;
         }
 
         MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE);
 
-        ParseNode *pn4 = ListNode::create(PNK_LC, tc);
+        ParseNode *pn4 = ListNode::create(PNK_STATEMENTLIST, tc);
         if (!pn4)
             return NULL;
         pn4->makeEmpty();
         while ((tt = tokenStream.peekToken(TSF_OPERAND)) != TOK_RC &&
                tt != TOK_CASE && tt != TOK_DEFAULT) {
             if (tt == TOK_ERROR)
                 return NULL;
             ParseNode *pn5 = statement();
@@ -3752,17 +3752,17 @@ Parser::expressionStatement()
         PushStatement(tc, &stmtInfo, STMT_LABEL, -1);
         stmtInfo.label = label;
         ParseNode *pn = statement();
         if (!pn)
             return NULL;
 
         /* Normalize empty statement to empty block for the decompiler. */
         if (pn->isKind(PNK_SEMI) && !pn->pn_kid) {
-            pn->setKind(PNK_LC);
+            pn->setKind(PNK_STATEMENTLIST);
             pn->setArity(PN_LIST);
             pn->makeEmpty();
         }
 
         /* Pop the label, set pn_expr, and return early. */
         PopStatement(tc);
         pn2->setKind(PNK_COLON);
         pn2->pn_pos.end = pn->pn_pos.end;
@@ -6033,17 +6033,17 @@ Parser::attributeIdentifier()
  * Make a TOK_LC unary node whose pn_kid is an expression.
  */
 ParseNode *
 Parser::xmlExpr(JSBool inTag)
 {
     JS_ASSERT(!tc->inStrictMode());
 
     JS_ASSERT(tokenStream.currentToken().type == TOK_LC);
-    ParseNode *pn = UnaryNode::create(PNK_LC, tc);
+    ParseNode *pn = UnaryNode::create(PNK_XMLCURLYEXPR, tc);
     if (!pn)
         return NULL;
 
     /*
      * Turn off XML tag mode. We save the old value of the flag because it may
      * already be off: XMLExpr is called both from within a tag, and from
      * within text contained in an element, but outside of any start, end, or
      * point tag.
@@ -6078,17 +6078,17 @@ Parser::atomNode(ParseNodeKind kind, JSO
  *
  *      XMLNameExpr:
  *              XMLName XMLNameExpr?
  *              { Expr } XMLNameExpr?
  *
  * Return a PN_LIST, PN_UNARY, or PN_NULLARY according as XMLNameExpr produces
  * a list of names and/or expressions, a single expression, or a single name.
  * If PN_LIST or PN_NULLARY, getKind() will be PNK_XMLNAME.  Otherwise if
- * PN_UNARY, getKind() will be PNK_LC.
+ * PN_UNARY, getKind() will be PNK_XMLCURLYEXPR.
  */
 ParseNode *
 Parser::xmlNameExpr()
 {
     JS_ASSERT(!tc->inStrictMode());
 
     ParseNode *pn, *pn2, *list;
     TokenKind tt;
@@ -6130,34 +6130,34 @@ Parser::xmlNameExpr()
 }
 
 /*
  * Macro to test whether an XMLNameExpr or XMLTagContent node can be folded
  * at compile time into a JSXML tree.
  */
 #define XML_FOLDABLE(pn)        ((pn)->isArity(PN_LIST)                     \
                                  ? ((pn)->pn_xflags & PNX_CANTFOLD) == 0    \
-                                 : !(pn)->isKind(PNK_LC))
+                                 : !(pn)->isKind(PNK_XMLCURLYEXPR))
 
 /*
  * Parse the productions:
  *
  *      XMLTagContent:
  *              XMLNameExpr
  *              XMLTagContent S XMLNameExpr S? = S? XMLAttr
  *              XMLTagContent S XMLNameExpr S? = S? { Expr }
  *
  * Return a PN_LIST, PN_UNARY, or PN_NULLARY according to how XMLTagContent
  * produces a list of name and attribute values and/or braced expressions, a
  * single expression, or a single name.
  *
  * If PN_LIST or PN_NULLARY, getKind() will be PNK_XMLNAME for the case where
  * XMLTagContent: XMLNameExpr.  If getKind() is not PNK_XMLNAME but getArity()
  * is PN_LIST, getKind() will be tagkind.  If PN_UNARY, getKind() will be
- * PNK_LC and we parsed exactly one expression.
+ * PNK_XMLCURLYEXPR and we parsed exactly one expression.
  */
 ParseNode *
 Parser::xmlTagContent(ParseNodeKind tagkind, JSAtom **namep)
 {
     JS_ASSERT(!tc->inStrictMode());
 
     ParseNode *pn, *pn2, *list;
     TokenKind tt;
@@ -6328,17 +6328,17 @@ Parser::xmlElementOrList(JSBool allowLis
         tt = tokenStream.getToken();
         if (tt == TOK_XMLPTAGC) {
             /* Point tag (/>): recycle pn if pn2 is a list of tag contents. */
             if (pn2->isKind(PNK_XMLSTAGO)) {
                 pn->makeEmpty();
                 freeTree(pn);
                 pn = pn2;
             } else {
-                JS_ASSERT(pn2->isKind(PNK_XMLNAME) || pn2->isKind(PNK_LC));
+                JS_ASSERT(pn2->isKind(PNK_XMLNAME) || pn2->isKind(PNK_XMLCURLYEXPR));
                 pn->initList(pn2);
                 if (!XML_FOLDABLE(pn2))
                     pn->pn_xflags |= PNX_CANTFOLD;
             }
             pn->setKind(PNK_XMLPTAGC);
             pn->pn_xflags |= PNX_XMLROOT;
         } else {
             /* We had better have a tag-close (>) at this point. */
@@ -6390,17 +6390,17 @@ Parser::xmlElementOrList(JSBool allowLis
             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->isKind(PNK_XMLNAME) || pn2->isKind(PNK_LC));
+            JS_ASSERT(pn2->isKind(PNK_XMLNAME) || pn2->isKind(PNK_XMLCURLYEXPR));
             list = ListNode::create(PNK_XMLETAGO, tc);
             if (!list)
                 return NULL;
             list->initList(pn2);
             pn->append(list);
             if (!XML_FOLDABLE(pn2)) {
                 list->pn_xflags |= PNX_CANTFOLD;
                 pn->pn_xflags |= PNX_CANTFOLD;
--- a/js/src/frontend/SemanticAnalysis.cpp
+++ b/js/src/frontend/SemanticAnalysis.cpp
@@ -528,17 +528,17 @@ ConsiderUnbranding(FunctionBox *funbox)
     bool returnsExpr = !!(funbox->tcflags & TCF_RETURN_EXPR);
 #if JS_HAS_EXPR_CLOSURES
     {
         ParseNode *pn2 = funbox->node->pn_body;
         if (pn2->isKind(PNK_UPVARS))
             pn2 = pn2->pn_tree;
         if (pn2->isKind(PNK_ARGSBODY))
             pn2 = pn2->last();
-        if (!pn2->isKind(PNK_LC))
+        if (!pn2->isKind(PNK_STATEMENTLIST))
             returnsExpr = true;
     }
 #endif
     if (!returnsExpr) {
         uintN methodSets = 0, slowMethodSets = 0;
 
         for (ParseNode *method = funbox->methods; method; method = method->pn_link) {
             JS_ASSERT(method->isOp(JSOP_LAMBDA) || method->isOp(JSOP_LAMBDA_FC));
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -1805,17 +1805,18 @@ ASTSerializer::binop(ParseNodeKind kind,
       default:
         return BINOP_ERR;
     }
 }
 
 bool
 ASTSerializer::statements(ParseNode *pn, NodeVector &elts)
 {
-    JS_ASSERT(pn->isKind(PNK_LC) && pn->isArity(PN_LIST));
+    JS_ASSERT(pn->isKind(PNK_STATEMENTLIST));
+    JS_ASSERT(pn->isArity(PN_LIST));
 
     if (!elts.reserve(pn->pn_count))
         return false;
 
     for (ParseNode *next = pn->pn_head; next; next = next->pn_next) {
         Value elt;
         if (!sourceElement(next, &elt))
             return false;
@@ -1855,17 +1856,17 @@ ASTSerializer::xmls(ParseNode *pn, NodeV
     }
 
     return true;
 }
 
 bool
 ASTSerializer::blockStatement(ParseNode *pn, Value *dst)
 {
-    JS_ASSERT(pn->isKind(PNK_LC));
+    JS_ASSERT(pn->isKind(PNK_STATEMENTLIST));
 
     NodeVector stmts(cx);
     return statements(pn, stmts) &&
            builder.blockStatement(stmts, &pn->pn_pos, dst);
 }
 
 bool
 ASTSerializer::program(ParseNode *pn, Value *dst)
@@ -2106,21 +2107,21 @@ ASTSerializer::statement(ParseNode *pn, 
             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->isKind(PNK_LC))
+        if (!pn->isKind(PNK_STATEMENTLIST))
             return statement(pn, dst);
         /* FALL THROUGH */
 
-      case PNK_LC:
+      case PNK_STATEMENTLIST:
         return blockStatement(pn, dst);
 
       case PNK_IF:
       {
         Value test, cons, alt;
 
         return expression(pn->pn_kid1, &test) &&
                statement(pn->pn_kid2, &cons) &&
@@ -2332,17 +2333,17 @@ ASTSerializer::comprehension(ParseNode *
     }
 
     Value filter = MagicValue(JS_SERIALIZE_NO_NODE);
 
     if (next->isKind(PNK_IF)) {
         if (!optExpression(next->pn_kid1, &filter))
             return false;
         next = next->pn_kid2;
-    } else if (next->isKind(PNK_LC) && next->pn_count == 0) {
+    } else if (next->isKind(PNK_STATEMENTLIST) && next->pn_count == 0) {
         /* FoldConstants optimized away the push. */
         NodeVector empty(cx);
         return builder.arrayExpression(empty, &pn->pn_pos, dst);
     }
 
     LOCAL_ASSERT(next->isKind(PNK_ARRAYPUSH));
 
     Value body;
@@ -2709,17 +2710,17 @@ ASTSerializer::expression(ParseNode *pn,
 }
 
 bool
 ASTSerializer::xml(ParseNode *pn, Value *dst)
 {
     JS_CHECK_RECURSION(cx, return false);
     switch (pn->getKind()) {
 #ifdef JS_HAS_XML_SUPPORT
-      case PNK_LC:
+      case PNK_XMLCURLYEXPR:
       {
         Value expr;
         return expression(pn->pn_kid, &expr) &&
                builder.xmlEscapeExpression(expr, &pn->pn_pos, dst);
       }
 
       case PNK_XMLELEM:
       {
@@ -3044,17 +3045,17 @@ ASTSerializer::functionArgsAndBody(Parse
       {
         ParseNode *pnstart = pnbody->pn_head->pn_next;
         LOCAL_ASSERT(pnstart && pnstart->isKind(PNK_RETURN));
 
         return functionArgs(pn, pnargs, pndestruct, pnbody, args) &&
                expression(pnstart->pn_kid, body);
       }
 
-      case PNK_LC:     /* statement closure */
+      case PNK_STATEMENTLIST:     /* statement closure */
       {
         ParseNode *pnstart = (pnbody->pn_xflags & PNX_DESTRUCT)
                                ? pnbody->pn_head->pn_next
                                : pnbody->pn_head;
 
         return functionArgs(pn, pnargs, pndestruct, pnbody, args) &&
                functionBody(pnstart, &pnbody->pn_pos, body);
       }