/[jscoverage]/trunk/js/jsparse.cpp
ViewVC logotype

Diff of /trunk/js/jsparse.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 332 by siliconforks, Thu Oct 23 19:03:33 2008 UTC revision 399 by siliconforks, Tue Dec 9 03:37:47 2008 UTC
# Line 543  Line 543 
543      cg.treeContext.u.scopeChain = scopeChain;      cg.treeContext.u.scopeChain = scopeChain;
544      cg.staticDepth = TCF_GET_STATIC_DEPTH(tcflags);      cg.staticDepth = TCF_GET_STATIC_DEPTH(tcflags);
545    
546        if ((tcflags & TCF_COMPILE_N_GO) && callerFrame && callerFrame->fun) {
547            /*
548             * An eval script in a caller frame needs to have its enclosing function
549             * captured in case it uses an upvar reference, and someone wishes to
550             * decompile it while running.
551             */
552            JSParsedObjectBox *pob = js_NewParsedObjectBox(cx, &pc, callerFrame->callee);
553            pob->emitLink = cg.objectList.lastPob;
554            cg.objectList.lastPob = pob;
555            cg.objectList.length++;
556        }
557    
558      /* Inline Statements() to emit as we go to save space. */      /* Inline Statements() to emit as we go to save space. */
559      for (;;) {      for (;;) {
560          pc.tokenStream.flags |= TSF_OPERAND;          pc.tokenStream.flags |= TSF_OPERAND;
# Line 1298  Line 1310 
1310      /*      /*
1311       * If there were destructuring formal parameters, prepend the initializing       * If there were destructuring formal parameters, prepend the initializing
1312       * comma expression that we synthesized to body.  If the body is a lexical       * comma expression that we synthesized to body.  If the body is a lexical
1313       * scope node, we must make a special TOK_BODY node, to prepend the formal       * scope node, we must make a special TOK_SEQ node, to prepend the formal
1314       * parameter destructuring code without bracing the decompilation of the       * parameter destructuring code without bracing the decompilation of the
1315       * function body's lexical scope.       * function body's lexical scope.
1316       */       */
# Line 1309  Line 1321 
1321              block = NewParseNode(cx, ts, PN_LIST, tc);              block = NewParseNode(cx, ts, PN_LIST, tc);
1322              if (!block)              if (!block)
1323                  return NULL;                  return NULL;
1324              block->pn_type = TOK_BODY;              block->pn_type = TOK_SEQ;
1325              block->pn_pos = body->pn_pos;              block->pn_pos = body->pn_pos;
1326              PN_INIT_LIST_1(block, body);              PN_INIT_LIST_1(block, body);
1327    
# Line 1663  Line 1675 
1675      return JS_TRUE;      return JS_TRUE;
1676  }  }
1677    
1678    static JSBool
1679    MakeSetCall(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN msg)
1680    {
1681        JSParseNode *pn2;
1682    
1683        JS_ASSERT(pn->pn_arity == PN_LIST);
1684        JS_ASSERT(pn->pn_op == JSOP_CALL || pn->pn_op == JSOP_EVAL || pn->pn_op == JSOP_APPLY);
1685        pn2 = pn->pn_head;
1686        if (pn2->pn_type == TOK_FUNCTION && (pn2->pn_flags & TCF_GENEXP_LAMBDA)) {
1687            js_ReportCompileErrorNumber(cx, TS(tc->parseContext), pn,
1688                                        JSREPORT_ERROR, msg);
1689            return JS_FALSE;
1690        }
1691        pn->pn_op = JSOP_SETCALL;
1692        return JS_TRUE;
1693    }
1694    
1695  #if JS_HAS_DESTRUCTURING  #if JS_HAS_DESTRUCTURING
1696    
1697  static JSBool  static JSBool
# Line 1702  Line 1731 
1731      return JS_TRUE;      return JS_TRUE;
1732  }  }
1733    
 static JSBool  
 MakeSetCall(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN msg)  
 {  
     JSParseNode *pn2;  
   
     JS_ASSERT(pn->pn_arity == PN_LIST);  
     JS_ASSERT(pn->pn_op == JSOP_CALL || pn->pn_op == JSOP_EVAL);  
     pn2 = pn->pn_head;  
     if (pn2->pn_type == TOK_FUNCTION && (pn2->pn_flags & TCF_GENEXP_LAMBDA)) {  
         js_ReportCompileErrorNumber(cx, TS(tc->parseContext), pn,  
                                     JSREPORT_ERROR, msg);  
         return JS_FALSE;  
     }  
     pn->pn_op = JSOP_SETCALL;  
     return JS_TRUE;  
 }  
   
1734  /*  /*
1735   * Here, we are destructuring {... P: Q, ...} = R, where P is any id, Q is any   * Here, we are destructuring {... P: Q, ...} = R, where P is any id, Q is any
1736   * LHS expression except a destructuring initialiser, and R is on the stack.   * LHS expression except a destructuring initialiser, and R is on the stack.
# Line 2095  Line 2107 
2107      return pn;      return pn;
2108  }  }
2109    
2110    // Currently used only #if JS_HAS_DESTRUCTURING, in Statement's TOK_FOR case.
2111    static JSParseNode *
2112    CloneParseTree(JSContext *cx, JSParseNode *opn, JSTreeContext *tc)
2113    {
2114        JSParseNode *pn, *pn2, *opn2;
2115    
2116        pn = NewOrRecycledNode(cx, tc);
2117        if (!pn)
2118            return NULL;
2119        pn->pn_type = opn->pn_type;
2120        pn->pn_pos = opn->pn_pos;
2121        pn->pn_op = opn->pn_op;
2122        pn->pn_arity = opn->pn_arity;
2123    
2124        switch (pn->pn_arity) {
2125    #define NULLCHECK(e)    JS_BEGIN_MACRO if (!(e)) return NULL; JS_END_MACRO
2126    
2127          case PN_FUNC:
2128            NULLCHECK(pn->pn_funpob =
2129                      js_NewParsedObjectBox(cx, tc->parseContext, opn->pn_funpob->object));
2130            NULLCHECK(pn->pn_body = CloneParseTree(cx, opn->pn_body, tc));
2131            pn->pn_flags = opn->pn_flags;
2132            pn->pn_index = opn->pn_index;
2133            break;
2134    
2135          case PN_LIST:
2136            PN_INIT_LIST(pn);
2137            for (opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) {
2138                NULLCHECK(pn2 = CloneParseTree(cx, opn2, tc));
2139                PN_APPEND(pn, pn2);
2140            }
2141            pn->pn_extra = opn->pn_extra;
2142            break;
2143    
2144          case PN_TERNARY:
2145            NULLCHECK(pn->pn_kid1 = CloneParseTree(cx, opn->pn_kid1, tc));
2146            NULLCHECK(pn->pn_kid2 = CloneParseTree(cx, opn->pn_kid2, tc));
2147            NULLCHECK(pn->pn_kid3 = CloneParseTree(cx, opn->pn_kid3, tc));
2148            break;
2149    
2150          case PN_BINARY:
2151            NULLCHECK(pn->pn_left = CloneParseTree(cx, opn->pn_left, tc));
2152            if (opn->pn_right != opn->pn_left)
2153                NULLCHECK(pn->pn_right = CloneParseTree(cx, opn->pn_right, tc));
2154            else
2155                pn->pn_right = pn->pn_left;
2156            pn->pn_val = opn->pn_val;
2157            pn->pn_iflags = opn->pn_iflags;
2158            break;
2159    
2160          case PN_UNARY:
2161            NULLCHECK(pn->pn_kid = CloneParseTree(cx, opn->pn_kid, tc));
2162            pn->pn_num = opn->pn_num;
2163            pn->pn_hidden = opn->pn_hidden;
2164            break;
2165    
2166          case PN_NAME:
2167            // PN_NAME could mean several arms in pn_u, so copy the whole thing.
2168            pn->pn_u = opn->pn_u;
2169            if (opn->pn_expr)
2170                NULLCHECK(pn->pn_expr = CloneParseTree(cx, opn->pn_expr, tc));
2171            break;
2172    
2173          case PN_NULLARY:
2174            // Even PN_NULLARY may have data (apair for E4X -- what a botch).
2175            pn->pn_u = opn->pn_u;
2176            break;
2177    
2178    #undef NULLCHECK
2179        }
2180        return pn;
2181    }
2182    
2183  #endif /* JS_HAS_DESTRUCTURING */  #endif /* JS_HAS_DESTRUCTURING */
2184    
2185  extern const char js_with_statement_str[];  extern const char js_with_statement_str[];
# Line 2537  Line 2622 
2622    
2623        case TOK_FOR:        case TOK_FOR:
2624        {        {
2625            JSParseNode *pnseq = NULL;
2626  #if JS_HAS_BLOCK_SCOPE  #if JS_HAS_BLOCK_SCOPE
2627          JSParseNode *pnlet;          JSParseNode *pnlet = NULL;
2628          JSStmtInfo blockInfo;          JSStmtInfo blockInfo;
   
         pnlet = NULL;  
2629  #endif  #endif
2630    
2631          /* A FOR node is binary, left is loop control and right is the body. */          /* A FOR node is binary, left is loop control and right is the body. */
# Line 2661  Line 2745 
2745                  return NULL;                  return NULL;
2746              }              }
2747    
2748                /* pn2 points to the name or destructuring pattern on in's left. */
2749                pn2 = NULL;
2750    
2751              if (TOKEN_TYPE_IS_DECL(tt)) {              if (TOKEN_TYPE_IS_DECL(tt)) {
2752                  /* Tell js_EmitTree(TOK_VAR) that pn1 is part of a for/in. */                  /* Tell js_EmitTree(TOK_VAR) that pn1 is part of a for/in. */
2753                  pn1->pn_extra |= PNX_FORINVAR;                  pn1->pn_extra |= PNX_FORINVAR;
2754    
2755                  /*                  /*
2756                   * Generate a final POP only if the variable is a simple name                   * Rewrite 'for (<decl> x = i in o)' where <decl> is 'let',
2757                   * (which means it is not a destructuring left-hand side) and                   * 'var', or 'const' to hoist the initializer or the entire
2758                   * it has an initializer.                   * decl out of the loop head. TOK_VAR is the type for both
2759                     * 'var' and 'const'.
2760                   */                   */
2761                  pn2 = pn1->pn_head;                  pn2 = pn1->pn_head;
2762                  if (pn2->pn_type == TOK_NAME && pn2->pn_expr)                  if (pn2->pn_type == TOK_NAME && pn2->pn_expr
2763                      pn1->pn_extra |= PNX_POPVAR;  #if JS_HAS_DESTRUCTURING
2764              } else {                      || pn2->pn_type == TOK_ASSIGN
2765    #endif
2766                        ) {
2767                        pnseq = NewParseNode(cx, ts, PN_LIST, tc);
2768                        if (!pnseq)
2769                            return NULL;
2770                        pnseq->pn_type = TOK_SEQ;
2771                        pnseq->pn_pos.begin = pn->pn_pos.begin;
2772                        if (tt == TOK_LET) {
2773                            /*
2774                             * Hoist just the 'i' from 'for (let x = i in o)' to
2775                             * before the loop, glued together via pnseq.
2776                             */
2777                            pn3 = NewParseNode(cx, ts, PN_UNARY, tc);
2778                            if (!pn3)
2779                                return NULL;
2780                            pn3->pn_type = TOK_SEMI;
2781                            pn3->pn_op = JSOP_NOP;
2782    #if JS_HAS_DESTRUCTURING
2783                            if (pn2->pn_type == TOK_ASSIGN) {
2784                                pn4 = pn2->pn_right;
2785                                pn2 = pn1->pn_head = pn2->pn_left;
2786                            } else
2787    #endif
2788                            {
2789                                pn4 = pn2->pn_expr;
2790                                pn2->pn_expr = NULL;
2791                            }
2792                            pn3->pn_pos = pn4->pn_pos;
2793                            pn3->pn_kid = pn4;
2794                            PN_INIT_LIST_1(pnseq, pn3);
2795                        } else {
2796                            /*
2797                             * All of 'var x = i' is hoisted above 'for (x in o)',
2798                             * so clear PNX_FORINVAR.
2799                             *
2800                             * Request JSOP_POP here since the var is for a simple
2801                             * name (it is not a destructuring binding's left-hand
2802                             * side) and it has an initializer.
2803                             */
2804                            pn1->pn_extra &= ~PNX_FORINVAR;
2805                            pn1->pn_extra |= PNX_POPVAR;
2806                            PN_INIT_LIST_1(pnseq, pn1);
2807    
2808    #if JS_HAS_DESTRUCTURING
2809                            if (pn2->pn_type == TOK_ASSIGN) {
2810                                pn1 = CloneParseTree(cx, pn2->pn_left, tc);
2811                                if (!pn1)
2812                                    return NULL;
2813                            } else
2814    #endif
2815                            {
2816                                pn1 = NewParseNode(cx, ts, PN_NAME, tc);
2817                                if (!pn1)
2818                                    return NULL;
2819                                pn1->pn_type = TOK_NAME;
2820                                pn1->pn_op = JSOP_NAME;
2821                                pn1->pn_pos = pn2->pn_pos;
2822                                pn1->pn_atom = pn2->pn_atom;
2823                                pn1->pn_expr = NULL;
2824                                pn1->pn_slot = -1;
2825                                pn1->pn_const = pn2->pn_const;
2826                            }
2827                            pn2 = pn1;
2828                        }
2829                    }
2830                }
2831    
2832                if (!pn2) {
2833                  pn2 = pn1;                  pn2 = pn1;
2834  #if JS_HAS_LVALUE_RETURN  #if JS_HAS_LVALUE_RETURN
2835                  if (pn2->pn_type == TOK_LP &&                  if (pn2->pn_type == TOK_LP &&
# Line 2741  Line 2897 
2897                  pn2 = Expr(cx, ts, tc);                  pn2 = Expr(cx, ts, tc);
2898                  if (!pn2)                  if (!pn2)
2899                      return NULL;                      return NULL;
   
                 if (pn2->pn_type == TOK_LP &&  
                     pn2->pn_head->pn_type == TOK_FUNCTION &&  
                     (pn2->pn_head->pn_flags & TCF_GENEXP_LAMBDA)) {  
                     /*  
                      * A generator expression as loop condition is useless.  
                      * It won't be called, and as an object it evaluates to  
                      * true in boolean contexts without any conversion hook  
                      * being called.  
                      *  
                      * This useless condition elimination is mandatory, to  
                      * help the decompiler. See bug 442342.  
                      */  
                     RecycleTree(pn2, tc);  
                     pn2 = NULL;  
                 }  
2900              }              }
2901    
2902              /* Parse the update expression or null into pn3. */              /* Parse the update expression or null into pn3. */
# Line 2772  Line 2912 
2912                      return NULL;                      return NULL;
2913              }              }
2914    
2915              /* Build the RESERVED node to use as the left kid of pn. */              /* Build the FORHEAD node to use as the left kid of pn. */
2916              pn4 = NewParseNode(cx, ts, PN_TERNARY, tc);              pn4 = NewParseNode(cx, ts, PN_TERNARY, tc);
2917              if (!pn4)              if (!pn4)
2918                  return NULL;                  return NULL;
2919              pn4->pn_type = TOK_RESERVED;              pn4->pn_type = TOK_FORHEAD;
2920              pn4->pn_op = JSOP_NOP;              pn4->pn_op = JSOP_NOP;
2921              pn4->pn_kid1 = pn1;              pn4->pn_kid1 = pn1;
2922              pn4->pn_kid2 = pn2;              pn4->pn_kid2 = pn2;
# Line 2802  Line 2942 
2942              pn = pnlet;              pn = pnlet;
2943          }          }
2944  #endif  #endif
2945            if (pnseq) {
2946                pnseq->pn_pos.end = pn->pn_pos.end;
2947                PN_APPEND(pnseq, pn);
2948                pn = pnseq;
2949            }
2950          js_PopStatement(tc);          js_PopStatement(tc);
2951          return pn;          return pn;
2952    
# Line 3846  Line 3991 
3991          kid->pn_type != TOK_DOT &&          kid->pn_type != TOK_DOT &&
3992  #if JS_HAS_LVALUE_RETURN  #if JS_HAS_LVALUE_RETURN
3993          (kid->pn_type != TOK_LP ||          (kid->pn_type != TOK_LP ||
3994           (kid->pn_op != JSOP_CALL && kid->pn_op != JSOP_EVAL)) &&           (kid->pn_op != JSOP_CALL && kid->pn_op != JSOP_EVAL && kid->pn_op != JSOP_APPLY)) &&
3995  #endif  #endif
3996  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
3997          (kid->pn_type != TOK_UNARYOP || kid->pn_op != JSOP_XMLNAME) &&          (kid->pn_type != TOK_UNARYOP || kid->pn_op != JSOP_XMLNAME) &&
# Line 4383  Line 4528 
4528                  } else if (tt == TOK_RP) {                  } else if (tt == TOK_RP) {
4529                      JSParseNode *group = pn3;                      JSParseNode *group = pn3;
4530    
4531                      /* Recycle the useless TOK_RP/JSOP_GROUP node. */                      /* Recycle the useless TOK_RP node. */
4532                      pn3 = group->pn_kid;                      pn3 = group->pn_kid;
4533                      group->pn_kid = NULL;                      group->pn_kid = NULL;
4534                      RecycleTree(group, tc);                      RecycleTree(group, tc);
# Line 4470  Line 4615 
4615                          break;                          break;
4616                      }                      }
4617                      pn3->pn_type = TOK_NUMBER;                      pn3->pn_type = TOK_NUMBER;
4618                        pn3->pn_op = JSOP_DOUBLE;
4619                      pn3->pn_dval = index;                      pn3->pn_dval = index;
4620                  }                  }
4621                  pn2->pn_op = JSOP_GETELEM;                  pn2->pn_op = JSOP_GETELEM;
# Line 4481  Line 4627 
4627              if (!pn2)              if (!pn2)
4628                  return NULL;                  return NULL;
4629    
             /* Pick JSOP_EVAL and flag tc as heavyweight if eval(...). */  
4630              pn2->pn_op = JSOP_CALL;              pn2->pn_op = JSOP_CALL;
4631              if (pn->pn_op == JSOP_NAME &&              if (pn->pn_op == JSOP_NAME &&
4632                  pn->pn_atom == cx->runtime->atomState.evalAtom) {                  pn->pn_atom == cx->runtime->atomState.evalAtom) {
4633                    /* Pick JSOP_EVAL and flag tc as heavyweight if eval(...). */
4634                  pn2->pn_op = JSOP_EVAL;                  pn2->pn_op = JSOP_EVAL;
4635                  tc->flags |= TCF_FUN_HEAVYWEIGHT;                  tc->flags |= TCF_FUN_HEAVYWEIGHT;
4636              }              } else if (pn->pn_op == JSOP_GETPROP &&
4637                           (pn->pn_atom == cx->runtime->atomState.applyAtom ||
4638                            pn->pn_atom == cx->runtime->atomState.callAtom)) {
4639                    /* Pick JSOP_APPLY if apply(...). */
4640                    pn2->pn_op = JSOP_APPLY;
4641                }
4642    
4643              PN_INIT_LIST_1(pn2, pn);              PN_INIT_LIST_1(pn2, pn);
4644              pn2->pn_pos.begin = pn->pn_pos.begin;              pn2->pn_pos.begin = pn->pn_pos.begin;
# Line 5244  Line 5395 
5395          if (!pn)          if (!pn)
5396              return NULL;              return NULL;
5397          pn->pn_type = TOK_RB;          pn->pn_type = TOK_RB;
5398            pn->pn_op = JSOP_NEWINIT;
5399    
5400  #if JS_HAS_SHARP_VARS  #if JS_HAS_SHARP_VARS
5401          if (defsharp) {          if (defsharp) {
# Line 5377  Line 5529 
5529          if (!pn)          if (!pn)
5530              return NULL;              return NULL;
5531          pn->pn_type = TOK_RC;          pn->pn_type = TOK_RC;
5532            pn->pn_op = JSOP_NEWINIT;
5533    
5534  #if JS_HAS_SHARP_VARS  #if JS_HAS_SHARP_VARS
5535          if (defsharp) {          if (defsharp) {
# Line 5706  Line 5859 
5859          pn = NewParseNode(cx, ts, PN_NULLARY, tc);          pn = NewParseNode(cx, ts, PN_NULLARY, tc);
5860          if (!pn)          if (!pn)
5861              return NULL;              return NULL;
5862            pn->pn_op = JSOP_DOUBLE;
5863          pn->pn_dval = CURRENT_TOKEN(ts).t_dval;          pn->pn_dval = CURRENT_TOKEN(ts).t_dval;
5864  #if JS_HAS_SHARP_VARS  #if JS_HAS_SHARP_VARS
5865          notsharp = JS_TRUE;          notsharp = JS_TRUE;
# Line 6137  Line 6291 
6291  #undef TAIL_RECURSE  #undef TAIL_RECURSE
6292  }  }
6293    
6294    static int
6295    Boolish(JSParseNode *pn)
6296    {
6297        switch (pn->pn_op) {
6298          case JSOP_DOUBLE:
6299            return pn->pn_dval != 0 && !JSDOUBLE_IS_NaN(pn->pn_dval);
6300    
6301          case JSOP_STRING:
6302            return JSSTRING_LENGTH(ATOM_TO_STRING(pn->pn_atom)) != 0;
6303    
6304    #if JS_HAS_GENERATOR_EXPRS
6305          case JSOP_CALL:
6306          {
6307            /*
6308             * A generator expression as an if or loop condition has no effects, it
6309             * simply results in a truthy object reference. This condition folding
6310             * is needed for the decompiler. See bug 442342 and bug 443074.
6311             */
6312            if (pn->pn_count != 1)
6313                break;
6314            JSParseNode *pn2 = pn->pn_head;
6315            if (pn2->pn_type != TOK_FUNCTION)
6316                break;
6317            if (!(pn2->pn_flags & TCF_GENEXP_LAMBDA))
6318                break;
6319            /* FALL THROUGH */
6320          }
6321    #endif
6322    
6323          case JSOP_DEFFUN:
6324          case JSOP_NAMEDFUNOBJ:
6325          case JSOP_ANONFUNOBJ:
6326          case JSOP_THIS:
6327          case JSOP_TRUE:
6328            return 1;
6329    
6330          case JSOP_NULL:
6331          case JSOP_FALSE:
6332            return 0;
6333    
6334          default:;
6335        }
6336        return -1;
6337    }
6338    
6339  JSBool  JSBool
6340  js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)  js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
6341  {  {
6342      JSParseNode *pn1 = NULL, *pn2 = NULL, *pn3 = NULL;      JSParseNode *pn1 = NULL, *pn2 = NULL, *pn3 = NULL;
6343    
# Line 6157  Line 6356 
6356        }        }
6357    
6358        case PN_LIST:        case PN_LIST:
6359  #if 0 /* JS_HAS_XML_SUPPORT */        {
6360          switch (pn->pn_type) {          /* Propagate inCond through logical connectives. */
6361            case TOK_XMLELEM:          bool cond = inCond && (pn->pn_type == TOK_OR || pn->pn_type == TOK_AND);
           case TOK_XMLLIST:  
           case TOK_XMLPTAGC:  
             /*  
              * Try to fold this XML parse tree once, from the top down, into  
              * a JSXML tree with just one object wrapping the tree root.  
              *  
              * Certain subtrees could be folded similarly, but we'd have to  
              * ensure that none used namespace prefixes declared elsewhere in  
              * its super-tree, and we would have to convert each XML object  
              * created at runtime for such sub-trees back into a string, and  
              * concatenate and re-parse anyway.  
              */  
             if ((pn->pn_extra & (PNX_XMLROOT | PNX_CANTFOLD)) == PNX_XMLROOT &&  
                 !(tc->flags & TCF_HAS_DEFXMLNS)) {  
                 JSObject *obj;  
                 JSParsedObjectBox *xmlpob;  
   
                 obj = js_ParseNodeToXMLObject(cx, pn);  
                 if (!obj)  
                     return JS_FALSE;  
                 xmlpob = js_NewParsedObjectBox(cx, ts, obj);  
                 if (!xmlpob)  
                     return JS_FALSE;  
                 pn->pn_op = JSOP_XMLOBJECT;  
                 pn->pn_arity = PN_NULLARY;  
                 pn->pn_pob = xmlpob;  
                 return JS_TRUE;  
             }  
   
             /*  
              * Can't fold from parse node to XML tree -- try folding strings  
              * as much as possible, and folding XML sub-trees bottom up to  
              * minimize string concatenation and ToXML/ToXMLList operations  
              * at runtime.  
              */  
             break;  
   
           default:;  
         }  
 #endif  
6362    
6363          /* Save the list head in pn1 for later use. */          /* Save the list head in pn1 for later use. */
6364          for (pn1 = pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {          for (pn1 = pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
6365              if (!js_FoldConstants(cx, pn2, tc))              if (!js_FoldConstants(cx, pn2, tc, cond))
6366                  return JS_FALSE;                  return JS_FALSE;
6367          }          }
6368          break;          break;
6369          }
6370    
6371        case PN_TERNARY:        case PN_TERNARY:
6372          /* Any kid may be null (e.g. for (;;)). */          /* Any kid may be null (e.g. for (;;)). */
6373          pn1 = pn->pn_kid1;          pn1 = pn->pn_kid1;
6374          pn2 = pn->pn_kid2;          pn2 = pn->pn_kid2;
6375          pn3 = pn->pn_kid3;          pn3 = pn->pn_kid3;
6376          if (pn1 && !js_FoldConstants(cx, pn1, tc))          if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->pn_type == TOK_IF))
             return JS_FALSE;  
         if (pn2 && !js_FoldConstants(cx, pn2, tc))  
6377              return JS_FALSE;              return JS_FALSE;
6378            if (pn2) {
6379                if (!js_FoldConstants(cx, pn2, tc, pn->pn_type == TOK_FORHEAD))
6380                    return JS_FALSE;
6381                if (pn->pn_type == TOK_FORHEAD && pn2->pn_op == JSOP_TRUE) {
6382                    RecycleTree(pn2, tc);
6383                    pn->pn_kid2 = NULL;
6384                }
6385            }
6386          if (pn3 && !js_FoldConstants(cx, pn3, tc))          if (pn3 && !js_FoldConstants(cx, pn3, tc))
6387              return JS_FALSE;              return JS_FALSE;
6388          break;          break;
6389    
6390        case PN_BINARY:        case PN_BINARY:
         /* First kid may be null (for default case in switch). */  
6391          pn1 = pn->pn_left;          pn1 = pn->pn_left;
6392          pn2 = pn->pn_right;          pn2 = pn->pn_right;
6393          if (pn1 && !js_FoldConstants(cx, pn1, tc))  
6394            /* Propagate inCond through logical connectives. */
6395            if (pn->pn_type == TOK_OR || pn->pn_type == TOK_AND) {
6396                if (!js_FoldConstants(cx, pn1, tc, inCond))
6397                    return JS_FALSE;
6398                if (!js_FoldConstants(cx, pn2, tc, inCond))
6399                    return JS_FALSE;
6400                break;
6401            }
6402    
6403            /* First kid may be null (for default case in switch). */
6404            if (pn1 && !js_FoldConstants(cx, pn1, tc, pn->pn_type == TOK_WHILE))
6405              return JS_FALSE;              return JS_FALSE;
6406          if (!js_FoldConstants(cx, pn2, tc))          if (!js_FoldConstants(cx, pn2, tc, pn->pn_type == TOK_DO))
6407              return JS_FALSE;              return JS_FALSE;
6408          break;          break;
6409    
6410        case PN_UNARY:        case PN_UNARY:
6411          /* Our kid may be null (e.g. return; vs. return e;). */          /* Our kid may be null (e.g. return; vs. return e;). */
6412          pn1 = pn->pn_kid;          pn1 = pn->pn_kid;
6413          if (pn1 && !js_FoldConstants(cx, pn1, tc))          if (pn1 &&
6414                !js_FoldConstants(cx, pn1, tc,
6415                                  (inCond && pn->pn_type == TOK_RP) ||
6416                                  pn->pn_op == JSOP_NOT)) {
6417              return JS_FALSE;              return JS_FALSE;
6418            }
6419          break;          break;
6420    
6421        case PN_NAME:        case PN_NAME:
# Line 6328  Line 6508 
6508              RecycleTree(pn3, tc);              RecycleTree(pn3, tc);
6509          break;          break;
6510    
6511          case TOK_OR:
6512          case TOK_AND:
6513            if (inCond) {
6514                if (pn->pn_arity == PN_LIST) {
6515                    JSParseNode **pnp = &pn->pn_head;
6516                    JS_ASSERT(*pnp == pn1);
6517                    do {
6518                        int cond = Boolish(pn1);
6519                        if (cond == (pn->pn_type == TOK_OR)) {
6520                            for (pn2 = pn1->pn_next; pn2; pn2 = pn3) {
6521                                pn3 = pn2->pn_next;
6522                                RecycleTree(pn2, tc);
6523                                --pn->pn_count;
6524                            }
6525                            pn1->pn_next = NULL;
6526                            break;
6527                        }
6528                        if (cond != -1) {
6529                            JS_ASSERT(cond == (pn->pn_type == TOK_AND));
6530                            if (pn->pn_count == 1)
6531                                break;
6532                            *pnp = pn1->pn_next;
6533                            RecycleTree(pn1, tc);
6534                            --pn->pn_count;
6535                        } else {
6536                            pnp = &pn1->pn_next;
6537                        }
6538                    } while ((pn1 = *pnp) != NULL);
6539    
6540                    // We may have to change arity from LIST to BINARY.
6541                    pn1 = pn->pn_head;
6542                    if (pn->pn_count == 2) {
6543                        pn2 = pn1->pn_next;
6544                        pn1->pn_next = NULL;
6545                        JS_ASSERT(!pn2->pn_next);
6546                        pn->pn_arity = PN_BINARY;
6547                        pn->pn_left = pn1;
6548                        pn->pn_right = pn2;
6549                    } else if (pn->pn_count == 1) {
6550                        PN_MOVE_NODE(pn, pn1);
6551                        RecycleTree(pn1, tc);
6552                    }
6553                } else {
6554                    int cond = Boolish(pn1);
6555                    if (cond == (pn->pn_type == TOK_OR)) {
6556                        RecycleTree(pn2, tc);
6557                        PN_MOVE_NODE(pn, pn1);
6558                    } else if (cond != -1) {
6559                        JS_ASSERT(cond == (pn->pn_type == TOK_AND));
6560                        RecycleTree(pn1, tc);
6561                        PN_MOVE_NODE(pn, pn2);
6562                    }
6563                }
6564            }
6565            break;
6566    
6567        case TOK_ASSIGN:        case TOK_ASSIGN:
6568          /*          /*
6569           * Compound operators such as *= should be subject to folding, in case           * Compound operators such as *= should be subject to folding, in case
# Line 6514  Line 6750 
6750              pn->pn_arity = PN_NULLARY;              pn->pn_arity = PN_NULLARY;
6751              pn->pn_dval = d;              pn->pn_dval = d;
6752              RecycleTree(pn1, tc);              RecycleTree(pn1, tc);
6753            } else if (pn1->pn_type == TOK_PRIMARY) {
6754                if (pn->pn_op == JSOP_NOT &&
6755                    (pn1->pn_op == JSOP_TRUE ||
6756                     pn1->pn_op == JSOP_FALSE)) {
6757                    PN_MOVE_NODE(pn, pn1);
6758                    pn->pn_op = (pn->pn_op == JSOP_TRUE) ? JSOP_FALSE : JSOP_TRUE;
6759                    RecycleTree(pn1, tc);
6760                }
6761          }          }
6762          break;          break;
6763    
# Line 6558  Line 6802 
6802        default:;        default:;
6803      }      }
6804    
6805        if (inCond) {
6806            int cond = Boolish(pn);
6807            if (cond >= 0) {
6808                if (pn->pn_arity == PN_LIST) {
6809                    pn2 = pn->pn_head;
6810                    do {
6811                        pn3 = pn2->pn_next;
6812                        RecycleTree(pn2, tc);
6813                    } while ((pn2 = pn3) != NULL);
6814                }
6815                pn->pn_type = TOK_PRIMARY;
6816                pn->pn_op = cond ? JSOP_TRUE : JSOP_FALSE;
6817                pn->pn_arity = PN_NULLARY;
6818            }
6819        }
6820    
6821      return JS_TRUE;      return JS_TRUE;
6822  }  }

Legend:
Removed from v.332  
changed lines
  Added in v.399

  ViewVC Help
Powered by ViewVC 1.1.24