home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / js / src / jsparse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  64.3 KB  |  2,456 lines

  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20.  * JS parser.
  21.  *
  22.  * This is a recursive-descent parser for the JavaScript language specified by
  23.  * "The JavaScript 1.2 Language Specification".  It uses lexical and semantic
  24.  * feedback to disambiguate non-LL(1) structures.  It generates bytecode as it
  25.  * parses, with backpatching and code rewriting limited to downward branches,
  26.  * for loops, and assignable "lvalue" expressions.
  27.  *
  28.  * This parser attempts no error recovery.  The dense JSTokenType enumeration
  29.  * was designed with error recovery built on 64-bit first and follow bitsets
  30.  * in mind, however.
  31.  */
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include "prtypes.h"
  35. #ifndef NSPR20
  36. #include "prarena.h"
  37. #else
  38. #include "plarena.h"
  39. #endif
  40. #include "prlog.h"
  41. #include "prprf.h"
  42. #include "jsapi.h"
  43. #include "jsatom.h"
  44. #include "jscntxt.h"
  45. #include "jsconfig.h"
  46. #include "jsemit.h"
  47. #include "jsfun.h"
  48. #include "jsinterp.h"
  49. #include "jslock.h"
  50. #include "jsnum.h"
  51. #include "jsobj.h"
  52. #include "jsopcode.h"
  53. #include "jsparse.h"
  54. #include "jsscan.h"
  55. #include "jsscope.h"
  56. #include "jsscript.h"
  57. #include "jsstr.h"
  58.  
  59. /*
  60.  * JS parsers, from lowest to highest precedence.
  61.  *
  62.  * Each parser takes a context and a token stream, and emits bytecode using
  63.  * a code generator.
  64.  */
  65. typedef JSBool
  66. JSParser(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg);
  67.  
  68. static JSParser FunctionStmt;
  69. #if JS_HAS_LEXICAL_CLOSURE
  70. static JSParser FunctionExpr;
  71. #endif
  72. static JSParser Statements;
  73. static JSParser Statement;
  74. static JSParser Variables;
  75. static JSParser Expr;
  76. static JSParser AssignExpr;
  77. static JSParser CondExpr;
  78. static JSParser OrExpr;
  79. static JSParser AndExpr;
  80. static JSParser BitOrExpr;
  81. static JSParser BitXorExpr;
  82. static JSParser BitAndExpr;
  83. static JSParser EqExpr;
  84. static JSParser RelExpr;
  85. static JSParser ShiftExpr;
  86. static JSParser AddExpr;
  87. static JSParser MulExpr;
  88. static JSParser UnaryExpr;
  89. static JSParser MemberExpr;
  90. static JSParser PrimaryExpr;
  91.  
  92. /*
  93.  * Insist that the next token be of type tt, or report err and return false.
  94.  * NB: this macro uses cx, ts, and cg from its lexical environment.
  95.  */
  96. #define MUST_MATCH_TOKEN_THROW(tt, err, throw)                                \
  97.     PR_BEGIN_MACRO                                                            \
  98.     if (js_GetToken(cx, ts, cg) != tt) {                                  \
  99.         js_ReportCompileError(cx, ts, err);                               \
  100.         throw;                                                            \
  101.     }                                                                     \
  102.     PR_END_MACRO
  103.  
  104. #define MUST_MATCH_TOKEN(tt, err)                                             \
  105.     MUST_MATCH_TOKEN_THROW(tt, err, return JS_FALSE)
  106.  
  107. /*
  108.  * Emit a bytecode and its 2-byte constant (atom) index immediate operand.
  109.  * NB: We use cx and cg from our caller's lexical environment, and return
  110.  * false on error.
  111.  */
  112. #define EMIT_CONST_ATOM_OP(op, atomIndex)                                     \
  113.     PR_BEGIN_MACRO                                                            \
  114.     if (js_Emit3(cx, cg, op, ATOM_INDEX_HI(atomIndex),                    \
  115.                  ATOM_INDEX_LO(atomIndex)) < 0) {             \
  116.         return JS_FALSE;                                                  \
  117.     }                                                                     \
  118.     PR_END_MACRO
  119.  
  120. /*
  121.  * Parse a top-level JS script.
  122.  */
  123. JS_FRIEND_API(JSBool)
  124. js_Parse(JSContext *cx, JSObject *chain, JSTokenStream *ts, JSCodeGenerator *cg)
  125. {
  126.     JSStackFrame *fp, frame;
  127.     JSTokenType stop, tt;
  128.     JSBool ok;
  129.  
  130.     PR_ASSERT(JS_IS_LOCKED(cx));
  131.     fp = cx->fp;
  132.     if (!fp || fp->scopeChain != chain) {
  133.     memset(&frame, 0, sizeof frame);
  134.     frame.scopeChain = chain;
  135.     frame.down = fp;
  136.     cx->fp = &frame;
  137.     }
  138.  
  139.     if (ts->flags & TSF_INTERACTIVE) {
  140.     SCAN_NEWLINES(ts);
  141.     stop = TOK_EOL;
  142.     } else {
  143.     stop = TOK_EOF;
  144.     }
  145.  
  146.     ok = JS_TRUE;
  147.     do {
  148.     ts->flags |= TSF_REGEXP;
  149.     tt = js_GetToken(cx, ts, cg);
  150.     ts->flags &= ~TSF_REGEXP;
  151.     if (tt == stop || tt <= TOK_EOF) {
  152.         if (tt == TOK_ERROR)
  153.         ok = JS_FALSE;
  154.         break;
  155.     }
  156.  
  157.     switch (tt) {
  158.       case TOK_FUNCTION:
  159.         if (!FunctionStmt(cx, ts, cg))
  160.         ok = JS_FALSE;
  161.         break;
  162.       default:
  163.         js_UngetToken(ts);
  164.         if (!Statement(cx, ts, cg))
  165.         ok = JS_FALSE;
  166.     }
  167.     } while (ok);
  168.  
  169.     cx->fp = fp;
  170.     if (ok)
  171.     ok = js_FlushNewlines(cx, ts, cg);
  172.     if (!ok) {
  173.     CLEAR_PUSHBACK(ts);
  174.     js_DropUnmappedAtoms(cx, &cg->atomList);
  175.     }
  176.     return ok;
  177. }
  178.  
  179. /*
  180.  * Parse a JS function body, which might appear as the value of an event
  181.  * handler attribute in a HTML <INPUT> tag.
  182.  */
  183. JSBool
  184. js_ParseFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,
  185.              JSSymbol *args)
  186. {
  187.     uintN lineno, oldflags;
  188.     JSCodeGenerator funcg;
  189.     JSStackFrame *fp, frame;
  190.     JSBool ok;
  191.     jsbytecode *pc;
  192.  
  193.     PR_ASSERT(JS_IS_LOCKED(cx));
  194.  
  195.     lineno = ts->lineno;
  196.     if (!js_InitCodeGenerator(cx, &funcg, &cx->codePool))
  197.     return JS_FALSE;
  198.  
  199.     fp = cx->fp;
  200.     if (!fp || fp->scopeChain != fun->object) {
  201.     memset(&frame, 0, sizeof frame);
  202.     frame.scopeChain = fun->object;
  203.     frame.down = fp;
  204.     cx->fp = &frame;
  205.     }
  206.  
  207.     oldflags = ts->flags;
  208.     ts->flags &= ~(TSF_RETURN_EXPR | TSF_RETURN_VOID);
  209.     ts->flags |= TSF_FUNCTION;
  210.     ok = Statements(cx, ts, &funcg);
  211.  
  212.     /* Check for falling off the end of a function that returns a value. */
  213.     if (ok && (ts->flags & TSF_RETURN_EXPR)) {
  214.     for (pc = CG_CODE(&funcg,funcg.lastCodeOffset);
  215.          *pc == JSOP_NOP || *pc == JSOP_LEAVEWITH;
  216.          pc--) {
  217.         /* nothing */;
  218.     }
  219.     if (*pc != JSOP_RETURN) {
  220.         js_ReportCompileError(cx, ts,
  221.                   "function does not always return a value");
  222.         ok = JS_FALSE;
  223.     }
  224.     }
  225.     ts->flags = oldflags;
  226.     cx->fp = fp;
  227.  
  228.     if (ok)
  229.     ok = js_FlushNewlines(cx, ts, &funcg);
  230.     if (!ok) {
  231.     CLEAR_PUSHBACK(ts);
  232.     js_DropUnmappedAtoms(cx, &funcg.atomList);
  233.     } else {
  234.     funcg.args = args;
  235.     fun->script = js_NewScript(cx, &funcg, ts->filename, lineno,
  236.                    ts->principals, fun);
  237.     if (!fun->script)
  238.         ok = JS_FALSE;
  239.     }
  240.     return ok;
  241. }
  242.  
  243. #if JS_HAS_LEXICAL_CLOSURE
  244. static JSBool
  245. InWithStatement(JSCodeGenerator *cg)
  246. {
  247.     StmtInfo *stmt;
  248.  
  249.     for (stmt = cg->stmtInfo; stmt; stmt = stmt->down) {
  250.     if (stmt->type == STMT_WITH)
  251.         return JS_TRUE;
  252.     }
  253.     return JS_FALSE;
  254. }
  255. #endif
  256.  
  257. static JSBool
  258. FunctionDef(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg, JSBool expr)
  259. {
  260.     JSAtomMap map;
  261.     JSAtom *funAtom, *argAtom;
  262.     JSObject *parent;
  263.     JSFunction *fun, *outerFun;
  264.     JSBool ok, named;
  265.     JSSymbol *arg, *args, **argp;
  266.     JSObject *pobj;
  267.     JSProperty *prop;
  268.     void *mark;
  269.     jsval junk;
  270.     uint32 i;
  271.  
  272.     /* Save atoms indexed but not mapped for the top-level script. */
  273.     if (!js_InitAtomMap(cx, &map, &cg->atomList))
  274.     return JS_FALSE;
  275.  
  276.     if (js_MatchToken(cx, ts, cg, TOK_NAME))
  277.     funAtom = js_HoldAtom(cx, ts->token.u.atom);
  278.     else
  279.     funAtom = NULL;
  280.  
  281.     /* Find the nearest variable-declaring scope and use it as our parent. */
  282.     parent = js_FindVariableScope(cx, &outerFun);
  283.     if (!parent) {
  284.     ok = JS_FALSE;
  285.     goto out;
  286.     }
  287.  
  288. #if JS_HAS_LEXICAL_CLOSURE
  289.     if (!funAtom || InWithStatement(cg) || cx->fp->scopeChain != parent) {
  290.     /* Don't name the function if enclosed by a with statement or equiv. */
  291.     fun = js_NewFunction(cx, NULL, 0, 0, cx->fp->scopeChain, funAtom);
  292.     named = JS_FALSE;
  293.     } else
  294. #endif
  295.     {
  296.     /* Override any previously defined property using js_DefineFunction. */
  297.     fun = js_DefineFunction(cx, parent, funAtom, NULL, 0, JSPROP_ENUMERATE);
  298.     named = (fun != NULL);
  299.     }
  300.     if (!fun) {
  301.     ok = JS_FALSE;
  302.     goto out;
  303.     }
  304.  
  305.     /* Now parse formal argument list and compute fun->nargs. */
  306.     args = NULL;
  307.     MUST_MATCH_TOKEN_THROW(TOK_LP, "missing ( before formal parameters",
  308.                ok = JS_FALSE; goto out);
  309.     /* balance) */
  310.     if (!js_MatchToken(cx, ts, cg, TOK_RP)) {
  311.     argp = &args;
  312.     do {
  313.         MUST_MATCH_TOKEN_THROW(TOK_NAME, "missing formal parameter",
  314.                    ok = JS_FALSE; goto out);
  315.         argAtom = js_HoldAtom(cx, ts->token.u.atom);
  316.         pobj = NULL;
  317.         ok = js_LookupProperty(cx, fun->object, (jsval)argAtom, &pobj,
  318.                    &prop);
  319.         if (!ok)
  320.         goto out;
  321.         if (prop && prop->object == fun->object) {
  322.         if (prop->getter == js_GetArgument) {
  323.             js_ReportCompileError(cx, ts,
  324.                       "duplicate formal argument %s",
  325.                       ATOM_BYTES(argAtom));
  326.             ok = JS_FALSE;
  327.             goto out;
  328.         }
  329.         prop->getter = js_GetArgument;
  330.         prop->setter = js_SetArgument;
  331.         prop->flags |= JSPROP_ENUMERATE | JSPROP_PERMANENT;
  332.         } else {
  333.         prop = js_DefineProperty(cx, fun->object,
  334.                      (jsval)argAtom, JSVAL_VOID,
  335.                      js_GetArgument, js_SetArgument,
  336.                      JSPROP_ENUMERATE | JSPROP_PERMANENT);
  337.         }
  338.         js_DropAtom(cx, argAtom);
  339.         if (!prop) {
  340.         ok = JS_FALSE;
  341.         goto out;
  342.         }
  343.         prop->id = INT_TO_JSVAL(fun->nargs++);
  344.         arg = prop->symbols;
  345.         *argp = arg;
  346.         argp = &arg->next;
  347.     } while (js_MatchToken(cx, ts, cg, TOK_COMMA));
  348.  
  349.     /* (balance: */
  350.     MUST_MATCH_TOKEN_THROW(TOK_RP, "missing ) after formal parameters",
  351.                    ok = JS_FALSE; goto out);
  352.     }
  353.  
  354.     MUST_MATCH_TOKEN_THROW(TOK_LC, "missing { before function body",
  355.                ok = JS_FALSE; goto out);
  356.     mark = PR_ARENA_MARK(&cx->codePool);
  357.     ok = js_ParseFunctionBody(cx, ts, fun, args);
  358.     if (ok) {
  359.     MUST_MATCH_TOKEN_THROW(TOK_RC, "missing } after function body",
  360.                    ok = JS_FALSE; goto out);
  361.     fun->script->depth += fun->nvars;
  362.  
  363.     /* Generate a setline note for script that follows this function. */
  364.     if (js_NewSrcNote2(cx, cg, SRC_SETLINE, (ptrdiff_t)TRUE_LINENO(ts)) < 0)
  365.         ok = JS_FALSE;
  366.     }
  367.     PR_ARENA_RELEASE(&cx->codePool, mark);
  368.  
  369. out:
  370.     if (!ok && named)
  371.     (void) js_DeleteProperty(cx, parent, (jsval)funAtom, &junk);
  372.     for (i = 0; i < map.length; i++) {
  373.     js_IndexAtom(cx, map.vector[i], &cg->atomList);
  374.     PR_ASSERT(map.vector[i]->index == i);
  375.     }
  376.     js_FreeAtomMap(cx, &map);
  377.     if (funAtom)
  378.     js_DropAtom(cx, funAtom);
  379.  
  380. #if JS_HAS_LEXICAL_CLOSURE
  381.     if (fun) {
  382.     JSBool closure = (outerFun ||
  383.               InWithStatement(cg) ||
  384.               cx->fp->scopeChain != parent);
  385.  
  386.     if (closure || expr) {
  387.         jsatomid atomIndex;
  388.  
  389.         /* Make the function object a literal in the outer script's pool. */
  390.         funAtom = js_AtomizeObject(cx, fun->object, ATOM_NOHOLD);
  391.         if (!funAtom)
  392.         return JS_FALSE;
  393.  
  394.         /* Emit a closure or push naming the literal in its immediate. */
  395.         atomIndex = js_IndexAtom(cx, funAtom, &cg->atomList);
  396.         EMIT_CONST_ATOM_OP(closure ? JSOP_CLOSURE : JSOP_OBJECT, atomIndex);
  397.     }
  398.     }
  399. #endif
  400.     return ok;
  401. }
  402.  
  403. static JSBool
  404. FunctionStmt(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  405. {
  406.     return FunctionDef(cx, ts, cg, JS_FALSE);
  407. }
  408.  
  409. #if JS_HAS_LEXICAL_CLOSURE
  410. static JSBool
  411. FunctionExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  412. {
  413.     return FunctionDef(cx, ts, cg, JS_TRUE);
  414. }
  415. #endif
  416.  
  417. static JSBool
  418. Statements(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  419. {
  420.     uintN newlines;
  421.     JSBool ok;
  422.     JSTokenType tt;
  423.  
  424.     newlines = ts->flags & TSF_NEWLINES;
  425.     if (newlines)
  426.     HIDE_NEWLINES(ts);
  427.  
  428.     ok = JS_TRUE;
  429.     while ((tt = js_PeekToken(cx, ts, cg)) > TOK_EOF && tt != TOK_RC) {
  430.     ok = Statement(cx, ts, cg);
  431.     if (!ok)
  432.         break;
  433.     }
  434.     if (tt == TOK_ERROR)
  435.     ok = JS_FALSE;
  436.     if (newlines)
  437.     SCAN_NEWLINES(ts);
  438.     return ok;
  439. }
  440.  
  441. static JSBool
  442. Condition(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  443. {
  444.     jsbytecode *pc;
  445.     JSOp lastop;
  446.     jsatomid atomIndex;
  447.  
  448.     MUST_MATCH_TOKEN(TOK_LP, "missing ( before condition");
  449.     if (!Expr(cx, ts, cg))
  450.     return JS_FALSE;
  451.     MUST_MATCH_TOKEN(TOK_RP, "missing ) after condition");
  452.  
  453.     /*
  454.      * Check for an AssignExpr (see below) and "correct" it to an EqExpr.
  455.      */
  456.     pc = CG_CODE(cg, cg->lastCodeOffset);
  457.     lastop = (JSOp) *pc;
  458.     if (lastop == JSOP_SETNAME &&
  459.     (cg->noteCount == 0 ||
  460.      cg->lastNoteOffset != cg->lastCodeOffset - 1 ||
  461.      SN_TYPE(&cg->notes[cg->saveNoteCount]) != SRC_ASSIGNOP)) {
  462.     js_ReportCompileError(cx, ts,
  463.         "test for equality (==) mistyped as assignment (=)?\n"
  464.         "Assuming equality test");
  465.     atomIndex = GET_ATOM_INDEX(pc);
  466.     js_CancelLastOpcode(cx, cg, &ts->newlines);
  467.     EMIT_CONST_ATOM_OP(JSOP_NAME, atomIndex);
  468.     if (js_Emit1(cx, cg, cx->jsop_eq) < 0)
  469.         return JS_FALSE;
  470.     }
  471.     return JS_TRUE;
  472. }
  473.  
  474. static JSBool
  475. WellTerminated(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg,
  476.            JSTokenType lastExprType)
  477. {
  478.     JSTokenType tt;
  479.  
  480.     tt = ts->pushback.type;
  481.     if (tt == TOK_ERROR)
  482.     return JS_FALSE;
  483.     if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {
  484. #if JS_HAS_LEXICAL_CLOSURE
  485.     if ((tt == TOK_FUNCTION || lastExprType == TOK_FUNCTION) &&
  486.         cx->version < JSVERSION_1_2) {
  487.         return JS_TRUE;
  488.     }
  489. #endif
  490.     js_ReportCompileError(cx, ts, "missing ; before statement");
  491.     return JS_FALSE;
  492.     }
  493.     return JS_TRUE;
  494. }
  495.  
  496. static JSBool
  497. MatchLabel(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg,
  498.        JSAtom **labelp)
  499. {
  500. #if JS_HAS_LABEL_STATEMENT
  501.     JSTokenType tt;
  502.  
  503.     tt = js_PeekTokenSameLine(cx, ts, cg);
  504.     if (tt == TOK_ERROR)
  505.     return JS_FALSE;
  506.     if (tt == TOK_NAME) {
  507.     if (js_GetToken(cx, ts, cg) == TOK_ERROR)
  508.         return JS_FALSE;
  509.     *labelp = ts->token.u.atom;
  510.     js_IndexAtom(cx, *labelp, &cg->atomList);
  511.     } else {
  512.     *labelp = NULL;
  513.     }
  514. #else
  515.     *labelp = NULL;
  516. #endif
  517.     return WellTerminated(cx, ts, cg, TOK_ERROR);
  518. }
  519.  
  520. #if JS_HAS_EXPORT_IMPORT
  521. static JSBool
  522. ImportExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  523. {
  524.     ptrdiff_t begin;
  525.     jsatomid atomIndex;
  526.     JSOp op;
  527.     JSTokenType tt;
  528.  
  529.     begin = CG_OFFSET(cg);
  530.     MUST_MATCH_TOKEN(TOK_NAME, "missing name in import statement");
  531.     atomIndex = js_IndexAtom(cx, ts->token.u.atom, &cg->atomList);
  532.     op = JSOP_NAME;
  533.  
  534.     ts->flags |= TSF_LOOKAHEAD;
  535.     while ((tt = js_GetToken(cx, ts, cg)) == TOK_DOT || tt == TOK_LB) {
  536.     ts->flags &= ~TSF_LOOKAHEAD;
  537.     switch (op) {
  538.       case JSOP_NAME:
  539.       case JSOP_GETPROP:
  540.         EMIT_CONST_ATOM_OP(op, atomIndex);
  541.         break;
  542.       case JSOP_GETELEM:
  543.         if (js_Emit1(cx, cg, op) < 0)
  544.         return JS_FALSE;
  545.         break;
  546.       case JSOP_IMPORTALL:
  547.         goto bad_import;
  548.       default:;
  549.     }
  550.     if (!js_FlushNewlines(cx, ts, cg))
  551.         return JS_FALSE;
  552.  
  553.     if (tt == TOK_DOT) {
  554.         /*
  555.          * Compile import-property opcode.
  556.          */
  557.         if (js_MatchToken(cx, ts, cg, TOK_STAR)) {
  558.         op = JSOP_IMPORTALL;
  559.         } else {
  560.         MUST_MATCH_TOKEN(TOK_NAME, "missing name after . operator");
  561.  
  562.         if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
  563.                    (ptrdiff_t)(CG_OFFSET(cg) - begin)) < 0) {
  564.             return JS_FALSE;
  565.         }
  566.         atomIndex = js_IndexAtom(cx, ts->token.u.atom, &cg->atomList);
  567.         op = JSOP_GETPROP;
  568.         }
  569.     } else {
  570.         /*
  571.          * Compile index expression and get-slot opcode.
  572.          */
  573.         if (!Expr(cx, ts, cg))
  574.         return JS_FALSE;
  575.         /* [balance: */
  576.         MUST_MATCH_TOKEN(TOK_RB, "missing ] in index expression");
  577.  
  578.         if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
  579.                    (ptrdiff_t)(CG_OFFSET(cg) - begin)) < 0) {
  580.         return JS_FALSE;
  581.         }
  582.         op = JSOP_GETELEM;
  583.     }
  584.  
  585.     ts->flags |= TSF_LOOKAHEAD;
  586.     }
  587.     ts->flags &= ~TSF_LOOKAHEAD;
  588.     if (tt == TOK_ERROR)
  589.     return JS_FALSE;
  590.     js_UngetToken(ts);
  591.  
  592.     switch (op) {
  593.       case JSOP_GETPROP:
  594.     EMIT_CONST_ATOM_OP(JSOP_IMPORTPROP, atomIndex);
  595.     break;
  596.       case JSOP_GETELEM:
  597.     op = JSOP_IMPORTELEM;
  598.     /* FALL THROUGH */
  599.       case JSOP_IMPORTALL:
  600.     if (js_Emit1(cx, cg, op) < 0)
  601.         return JS_FALSE;
  602.     break;
  603.       default:
  604.     goto bad_import;
  605.     }
  606.     return JS_TRUE;
  607.  
  608.   bad_import:
  609.     js_ReportCompileError(cx, ts, "invalid import expression");
  610.     return JS_FALSE;
  611. }
  612. #endif /* JS_HAS_EXPORT_IMPORT */
  613.  
  614. static JSBool
  615. Statement(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  616. {
  617.     StmtInfo stmtInfo, *stmt, *stmt2;
  618.     intN snindex;
  619.     uintN lineno, topNoteCount;
  620.     JSBool ok, isForInLoop, hasVarNote;
  621.     ptrdiff_t top, beq, jmp;
  622.     JSCodeGenerator cg2;
  623.     jsbytecode *pc;
  624.     JSOp lastop;
  625.     jsatomid atomIndex;
  626.     JSTokenType tt, lastExprType;
  627.     JSAtom *label;
  628.  
  629.     switch (js_GetToken(cx, ts, cg)) {
  630. #if JS_HAS_EXPORT_IMPORT
  631.       case TOK_EXPORT:
  632.     lineno = ts->lineno;
  633.     if (js_MatchToken(cx, ts, cg, TOK_STAR)) {
  634.         if (js_Emit1(cx, cg, JSOP_EXPORTALL) < 0)
  635.         return JS_FALSE;
  636.     } else {
  637.         do {
  638.         MUST_MATCH_TOKEN(TOK_NAME, "missing name in export statement");
  639.         atomIndex = js_IndexAtom(cx, ts->token.u.atom, &cg->atomList);
  640.         EMIT_CONST_ATOM_OP(JSOP_EXPORTNAME, atomIndex);
  641.         } while (js_MatchToken(cx, ts, cg, TOK_COMMA));
  642.     }
  643.     if (ts->lineno == lineno && !WellTerminated(cx, ts, cg, TOK_ERROR))
  644.         return JS_FALSE;
  645.     break;
  646.  
  647.       case TOK_IMPORT:
  648.     lineno = ts->lineno;
  649.     do {
  650.         if (!ImportExpr(cx, ts, cg))
  651.         return JS_FALSE;
  652.     } while (js_MatchToken(cx, ts, cg, TOK_COMMA));
  653.     if (ts->lineno == lineno && !WellTerminated(cx, ts, cg, TOK_ERROR))
  654.         return JS_FALSE;
  655.     break;
  656. #endif /* JS_HAS_EXPORT_IMPORT */
  657.  
  658.       case TOK_IF:
  659.     if (!Condition(cx, ts, cg))
  660.         return JS_FALSE;
  661.     js_PushStatement(cg, &stmtInfo, STMT_IF, CG_OFFSET(cg));
  662.     snindex = js_NewSrcNote(cx, cg, SRC_IF);
  663.     if (snindex < 0)
  664.         return JS_FALSE;
  665.     beq = js_Emit3(cx, cg, JSOP_IFEQ, 0, 0);
  666.     if (beq < 0)
  667.         return JS_FALSE;
  668.     if (!Statement(cx, ts, cg))
  669.         return JS_FALSE;
  670.     if (js_MatchToken(cx, ts, cg, TOK_ELSE)) {
  671.         stmtInfo.type = STMT_ELSE;
  672.         SN_SET_TYPE(&cg->notes[snindex], SRC_IF_ELSE);
  673.         jmp = js_Emit3(cx, cg, JSOP_GOTO, 0, 0);
  674.         if (jmp < 0)
  675.         return JS_FALSE;
  676.         CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
  677.         if (!Statement(cx, ts, cg))
  678.         return JS_FALSE;
  679.         CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
  680.     } else {
  681.         CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
  682.     }
  683.     return js_PopStatement(cx, cg);
  684.  
  685. #if JS_HAS_SWITCH_STATEMENT
  686.       case TOK_SWITCH:
  687.       {
  688.     JSOp switchop;
  689.     uintN newlines;
  690.     SwitchCase *caselist;   /* singly-linked case list */
  691.     SwitchCase **casetail;  /* pointer to pointer to last case */
  692.     SwitchCase *defaultsc;  /* default switch case or null */
  693.     uint32 ncases, tablen;
  694.     JSAtomMap map;
  695.     JSScript *script;
  696.     jsval value;
  697.     SwitchCase *sc;
  698.     jsint i, low, high;
  699.     size_t length;
  700.     ptrdiff_t offset;
  701.  
  702.     MUST_MATCH_TOKEN(TOK_LP, "missing ( before switch expression");
  703.     if (!Expr(cx, ts, cg))
  704.         return JS_FALSE;
  705.     MUST_MATCH_TOKEN(TOK_RP, "missing ) after switch expression");
  706.     MUST_MATCH_TOKEN(TOK_LC, "missing { before switch body");
  707.     /* balance} */
  708.  
  709.     top = CG_OFFSET(cg);
  710.     js_PushStatement(cg, &stmtInfo, STMT_SWITCH, top);
  711.  
  712.     snindex = js_NewSrcNote2(cx, cg, SRC_SWITCH, 0);
  713.     if (snindex < 0)
  714.         return JS_FALSE;
  715.     topNoteCount = cg->noteCount;
  716.  
  717.     switchop = JSOP_TABLESWITCH;
  718.     if (js_Emit1(cx, cg, switchop) < 0)
  719.         return JS_FALSE;
  720.  
  721.     ok = JS_TRUE;
  722.     cg2.base = NULL;
  723.     caselist = NULL;
  724.     casetail = &caselist;
  725.     defaultsc = NULL;
  726.     ncases = 0;
  727.  
  728.     newlines = ts->flags & TSF_NEWLINES;
  729.     if (newlines)
  730.         HIDE_NEWLINES(ts);
  731.  
  732.     while ((tt = js_GetToken(cx, ts, cg)) != TOK_RC) {
  733.         switch (tt) {
  734.           case TOK_CASE:
  735.         if (!cg2.base) {
  736.             ok = js_InitCodeGenerator(cx, &cg2, &cx->tempPool);
  737.             if (!ok)
  738.             goto end_switch;
  739.         } else {
  740.             CG_RESET(&cg2);
  741.         }
  742.         lineno = ts->lineno;
  743.  
  744.         /* Save atoms indexed but not mapped before compiling. */
  745.         ok = js_InitAtomMap(cx, &map, &cg->atomList);
  746.         if (!ok)
  747.             goto end_switch;
  748.         ok = Expr(cx, ts, &cg2) && js_Emit1(cx, &cg2, JSOP_POPV) >= 0;
  749.         if (ok) {
  750.             script = js_NewScript(cx, &cg2, ts->filename, lineno,
  751.                       ts->principals, NULL);
  752.             if (!script)
  753.             ok = JS_FALSE;
  754.         }
  755.         for (i = 0; i < (jsint)map.length; i++) {
  756.             js_IndexAtom(cx, map.vector[i], &cg->atomList);
  757.             PR_ASSERT((jsint)map.vector[i]->index == i);
  758.         }
  759.         js_FreeAtomMap(cx, &map);
  760.  
  761.         if (!ok)
  762.             goto end_switch;
  763.         ok = js_Execute(cx, cx->fp->scopeChain, script, cx->fp, &value);
  764.         js_DestroyScript(cx, script);
  765.         if (!ok)
  766.             goto end_switch;
  767.  
  768.         if (!JSVAL_IS_NUMBER(value) &&
  769.             !JSVAL_IS_STRING(value) &&
  770.             !JSVAL_IS_BOOLEAN(value)) {
  771.             js_ReportCompileError(cx, ts, "invalid case expression");
  772.             ok = JS_FALSE;
  773.             goto end_switch;
  774.         }
  775.         if (++ncases == PR_BIT(16)) {
  776.             js_ReportCompileError(cx, ts, "too many switch cases");
  777.             ok = JS_FALSE;
  778.             goto end_switch;
  779.         }
  780.         JSVAL_LOCK(cx, value);
  781.         break;
  782.  
  783.           case TOK_DEFAULT:
  784.         if (defaultsc) {
  785.             js_ReportCompileError(cx, ts,
  786.                       "more than one switch default");
  787.             ok = JS_FALSE;
  788.             goto end_switch;
  789.         }
  790.         value = JSVAL_VOID;
  791.         break;
  792.  
  793.           case TOK_ERROR:
  794.         ok = JS_FALSE;
  795.         goto end_switch;
  796.  
  797.           default:
  798.         js_ReportCompileError(cx, ts, "invalid switch statement");
  799.         ok = JS_FALSE;
  800.         goto end_switch;
  801.         }
  802.         MUST_MATCH_TOKEN_THROW(TOK_COLON, "missing : after case expression",
  803.                    ok = JS_FALSE; goto end_switch);
  804.  
  805.         PR_ARENA_ALLOCATE(sc, &cx->tempPool, sizeof(SwitchCase));
  806.         if (!sc) {
  807.         JSVAL_UNLOCK(cx, value);
  808.         JS_ReportOutOfMemory(cx);
  809.         ok = JS_FALSE;
  810.         goto end_switch;
  811.         }
  812.         sc->value = value;
  813.         sc->offset = CG_OFFSET(cg);
  814.         sc->next = NULL;
  815.         *casetail = sc;
  816.         casetail = &sc->next;
  817.  
  818.         if (tt == TOK_DEFAULT)
  819.         defaultsc = sc;
  820.  
  821.         while ((tt = js_PeekToken(cx, ts, cg)) != TOK_RC &&
  822.             tt != TOK_CASE && tt != TOK_DEFAULT) {
  823.         if (tt == TOK_ERROR) {
  824.             ok = JS_FALSE;
  825.             goto end_switch;
  826.         }
  827.         ok = Statement(cx, ts, cg);
  828.         if (!ok)
  829.             goto end_switch;
  830.         }
  831.     }
  832.  
  833.     if (!caselist) {
  834.         low = high = 0;
  835.         tablen = 0;
  836.     } else {
  837.         low  = JSVAL_INT_MAX;
  838.         high = JSVAL_INT_MIN;
  839.         for (sc = caselist; sc; sc = sc->next) {
  840.         if (sc == defaultsc)
  841.             continue;
  842.         if (!JSVAL_IS_INT(sc->value)) {
  843.             switchop = JSOP_LOOKUPSWITCH;
  844.             break;
  845.         }
  846.         i = JSVAL_TO_INT(sc->value);
  847.         if ((jsuint)(i + (jsint)PR_BIT(15)) >= (jsuint)PR_BIT(16)) {
  848.             switchop = JSOP_LOOKUPSWITCH;
  849.             break;
  850.         }
  851.         if (i < low)
  852.             low = i;
  853.         if (high < i)
  854.             high = i;
  855.         }
  856.         tablen = (uint32)(high - low + 1);
  857.         if (tablen >= PR_BIT(16) || tablen > 2 * ncases)
  858.         switchop = JSOP_LOOKUPSWITCH;
  859.     }
  860.  
  861.     if (switchop == JSOP_TABLESWITCH) {
  862.         length = (size_t)(6 + 2 * tablen);
  863.     } else {
  864.         length = (size_t)(4 + 4 * ncases);
  865.         *CG_CODE(cg, top) = switchop;
  866.     }
  867.  
  868.     /* Slide body code down to make room for the jump or lookup table. */
  869.     if (js_MoveCode(cx, cg, top + 1, cg, top + 1 + length) < 0) {
  870.         ok = JS_FALSE;
  871.         goto end_switch;
  872.     }
  873.     pc = CG_CODE(cg, top);
  874.  
  875.     /* Don't forget to adjust the case offsets. */
  876.     for (sc = caselist; sc; sc = sc->next)
  877.         sc->offset += length;
  878.  
  879.     /* If the body has source notes, bump the first one's delta. */
  880.     if (cg->noteCount > topNoteCount) {
  881.         ok = js_BumpSrcNoteDelta(cx, cg, topNoteCount, (ptrdiff_t)length);
  882.         if (!ok)
  883.         goto end_switch;
  884.     }
  885.  
  886.     /* Set the SRC_SWITCH note's offset operand to tell end of switch. */
  887.     offset = CG_OFFSET(cg) - top;
  888.     ok = js_SetSrcNoteOffset(cx, cg, snindex, 0, (ptrdiff_t)offset);
  889.     if (!ok)
  890.         goto end_switch;
  891.  
  892.     /* Fill in the default jump offset. */
  893.     if (defaultsc)
  894.         offset = defaultsc->offset - top;
  895.     else
  896.         offset = CG_OFFSET(cg) - top;
  897.     ok = js_SetJumpOffset(cx, cg, pc, offset);
  898.     if (!ok)
  899.         goto end_switch;
  900.     pc += 2;
  901.  
  902.     /* Fill in jump or lookup table. */
  903.     if (switchop == JSOP_TABLESWITCH) {
  904.         SET_JUMP_OFFSET(pc, low);
  905.         pc += 2;
  906.         SET_JUMP_OFFSET(pc, high);
  907.         pc += 2;
  908.         if (tablen) {
  909.         size_t tablesize;
  910.         SwitchCase **table;
  911.  
  912.         tablesize = (size_t)tablen * sizeof *table;
  913.         PR_ARENA_ALLOCATE(table, &cx->tempPool, tablesize);
  914.         if (!table) {
  915.             JS_ReportOutOfMemory(cx);
  916.             ok = JS_FALSE;
  917.             goto end_switch;
  918.         }
  919.         memset(table, 0, tablesize);
  920.         for (sc = caselist; sc; sc = sc->next) {
  921.             if (sc == defaultsc)
  922.             continue;
  923.             i = JSVAL_TO_INT(sc->value);
  924.             i -= low;
  925.             PR_ASSERT((uint32)i < tablen);
  926.             table[i] = sc;
  927.         }
  928.         for (i = 0; i < (jsint)tablen; i++) {
  929.             sc = table[i];
  930.             offset = sc ? sc->offset - top : 0;
  931.             ok = js_SetJumpOffset(cx, cg, pc, offset);
  932.             if (!ok)
  933.             goto end_switch;
  934.             pc += 2;
  935.         }
  936.         }
  937.     } else {
  938.         SET_ATOM_INDEX(pc, ncases);
  939.         pc += 2;
  940.  
  941.         for (sc = caselist; sc; sc = sc->next) {
  942.         JSAtom *atom;
  943.  
  944.         if (sc == defaultsc)
  945.             continue;
  946.         value = sc->value;
  947.         atom = js_AtomizeValue(cx, value, 0);
  948.         if (!atom) {
  949.             ok = JS_FALSE;
  950.             goto end_switch;
  951.         }
  952.         atomIndex = js_IndexAtom(cx, atom, &cg->atomList);
  953.         js_DropAtom(cx, atom);
  954.  
  955.         SET_ATOM_INDEX(pc, atomIndex);
  956.         pc += 2;
  957.  
  958.         offset = sc->offset - top;
  959.         ok = js_SetJumpOffset(cx, cg, pc, offset);
  960.         if (!ok)
  961.             goto end_switch;
  962.         pc += 2;
  963.         }
  964.     }
  965.  
  966.       end_switch:
  967.     for (sc = caselist; sc; sc = sc->next)
  968.         JSVAL_UNLOCK(cx, sc->value);
  969.     if (newlines)
  970.         SCAN_NEWLINES(ts);
  971.     return js_PopStatement(cx, cg);
  972.       }
  973. #endif /* JS_HAS_SWITCH_STATEMENT */
  974.  
  975.       case TOK_WHILE:
  976.     top = CG_OFFSET(cg);
  977.     js_PushStatement(cg, &stmtInfo, STMT_WHILE_LOOP, top);
  978.     if (!Condition(cx, ts, cg))
  979.         return JS_FALSE;
  980.     snindex = js_NewSrcNote(cx, cg, SRC_WHILE);
  981.     if (snindex < 0)
  982.         return JS_FALSE;
  983.     beq = js_Emit3(cx, cg, JSOP_IFEQ, 0, 0);
  984.     if (beq < 0)
  985.         return JS_FALSE;
  986.     if (!Statement(cx, ts, cg))
  987.         return JS_FALSE;
  988.     jmp = js_Emit3(cx, cg, JSOP_GOTO, 0, 0);
  989.     if (jmp < 0)
  990.         return JS_FALSE;
  991.     CHECK_AND_SET_JUMP_OFFSET(cx, cg, CG_CODE(cg,jmp), top - jmp);
  992.     CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
  993.     return js_PopStatement(cx, cg);
  994.  
  995. #if JS_HAS_DO_WHILE_LOOP
  996.       case TOK_DO:
  997.     /* Emit an annotated nop so we know to decompile a 'do' keyword. */
  998.     if (js_NewSrcNote(cx, cg, SRC_WHILE) < 0 ||
  999.         js_Emit1(cx, cg, JSOP_NOP) < 0) {
  1000.         return JS_FALSE;
  1001.     }
  1002.  
  1003.     /* Compile the loop body and condition. */
  1004.     top = CG_OFFSET(cg);
  1005.     js_PushStatement(cg, &stmtInfo, STMT_DO_LOOP, top);
  1006.     if (!Statement(cx, ts, cg))
  1007.         return JS_FALSE;
  1008.     MUST_MATCH_TOKEN(TOK_WHILE, "missing while after do-loop body");
  1009.     if (!Condition(cx, ts, cg))
  1010.         return JS_FALSE;
  1011.  
  1012.     /* Re-use the SRC_WHILE note, this time for the JSOP_IFNE opcode. */
  1013.     if (js_NewSrcNote(cx, cg, SRC_WHILE) < 0)
  1014.         return JS_FALSE;
  1015.     jmp = top - CG_OFFSET(cg);
  1016.     if (js_Emit3(cx, cg, JSOP_IFNE,
  1017.              JUMP_OFFSET_HI(jmp), JUMP_OFFSET_LO(jmp)) < 0) {
  1018.         return JS_FALSE;
  1019.     }
  1020.     return js_PopStatement(cx, cg);
  1021. #endif /* JS_HAS_DO_WHILE_LOOP */
  1022.  
  1023.       case TOK_FOR:
  1024.     top = CG_OFFSET(cg);
  1025.     js_PushStatement(cg, &stmtInfo, STMT_FOR_LOOP, top);
  1026.     snindex = -1;
  1027.     topNoteCount = cg->noteCount;
  1028.     cg2.base = NULL;
  1029.  
  1030.     MUST_MATCH_TOKEN(TOK_LP, "missing ( after for");    /* balance) */
  1031.     tt = js_PeekToken(cx, ts, cg);
  1032.     if (tt == TOK_SEMI) {
  1033.         /* No initializer -- emit an annotated nop for the decompiler. */
  1034.         snindex = js_NewSrcNote(cx, cg, SRC_FOR);
  1035.         if (snindex < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0)
  1036.         return JS_FALSE;
  1037.     } else {
  1038.         if (tt == TOK_VAR) {
  1039.         (void) js_GetToken(cx, ts, cg);
  1040.         if (!Variables(cx, ts, cg))
  1041.             return JS_FALSE;
  1042.         } else {
  1043.         if (!Expr(cx, ts, cg))
  1044.             return JS_FALSE;
  1045.         }
  1046.         if (js_PeekToken(cx, ts, cg) != TOK_IN) {
  1047.         snindex = js_NewSrcNote(cx, cg, SRC_FOR);
  1048.         if (snindex < 0 || js_Emit1(cx, cg, JSOP_POP) < 0)
  1049.             return JS_FALSE;
  1050.         }
  1051.     }
  1052.  
  1053.     isForInLoop = js_MatchToken(cx, ts, cg, TOK_IN);
  1054.     if (isForInLoop) {
  1055.         /* Insert a JSOP_PUSH to allocate an iterator before this loop. */
  1056.         stmtInfo.type = STMT_FOR_IN_LOOP;
  1057.         if (js_MoveCode(cx, cg, top, cg, top + 1) < 0)
  1058.         return JS_FALSE;
  1059.         *CG_CODE(cg, top) = JSOP_PUSH;
  1060.         js_UpdateDepth(cx, cg, top);
  1061.         top++;
  1062.         SET_STATEMENT_TOP(&stmtInfo, top);
  1063.  
  1064.         /* If the iterator has a SRC_VAR note, remember to emit it later. */
  1065.         hasVarNote = (cg->noteCount > topNoteCount);
  1066.         if (hasVarNote) {
  1067.         hasVarNote = (SN_TYPE(&cg->notes[topNoteCount]) == SRC_VAR);
  1068.         if (hasVarNote) {
  1069.             /* XXX blow away any ASSIGNOP notes in initializers */
  1070.             cg->noteCount = topNoteCount;
  1071.         } else {
  1072.             /* Otherwise bump the first notes's delta. */
  1073.             if (!js_BumpSrcNoteDelta(cx, cg, topNoteCount, 1))
  1074.             return JS_FALSE;
  1075.         }
  1076.         }
  1077.  
  1078.         /* Cancel the last bytecode, saving it for re-emission later. */
  1079.         pc = CG_CODE(cg, cg->lastCodeOffset);
  1080.         lastop = (JSOp) *pc;
  1081.         switch (lastop) {
  1082.           case JSOP_NAME:
  1083.           case JSOP_GETPROP:
  1084.         atomIndex = GET_ATOM_INDEX(pc);
  1085.         break;
  1086.           case JSOP_GETELEM:
  1087.         /* GETELEM and FORELEM have no immediate operand. */
  1088.         break;
  1089.           default:
  1090.         js_ReportCompileError(cx, ts, "invalid for/in left-hand side");
  1091.         return JS_FALSE;
  1092.         }
  1093.         js_CancelLastOpcode(cx, cg, &ts->newlines);
  1094.  
  1095.         /* Now compile the object expression over which we're iterating. */
  1096.         if (!Expr(cx, ts, cg))
  1097.         return JS_FALSE;
  1098.  
  1099.         if (lastop == JSOP_NAME) {
  1100.         if (hasVarNote && js_NewSrcNote(cx, cg, SRC_VAR) < 0)
  1101.             return JS_FALSE;
  1102.         } else {
  1103.         if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
  1104.                    (int16)(CG_OFFSET(cg) - top)) < 0) {
  1105.             return JS_FALSE;
  1106.         }
  1107.         }
  1108.  
  1109.         /* Re-emit the left-hand side's bytecode as a JSOP_FOR* variant. */
  1110.         switch (lastop) {
  1111.           case JSOP_NAME:
  1112.         EMIT_CONST_ATOM_OP(JSOP_FORNAME, atomIndex);
  1113.         break;
  1114.           case JSOP_GETPROP:
  1115.         EMIT_CONST_ATOM_OP(JSOP_FORPROP, atomIndex);
  1116.         break;
  1117.           case JSOP_GETELEM:
  1118.         if (js_Emit1(cx, cg, JSOP_FORELEM) < 0)
  1119.             return JS_FALSE;
  1120.         break;
  1121.           default:;
  1122.         }
  1123.  
  1124.         /* Pop and test the loop condition generated by JSOP_FOR*. */
  1125.         beq = js_Emit3(cx, cg, JSOP_IFEQ, 0, 0);
  1126.         if (beq < 0)
  1127.         return JS_FALSE;
  1128.     } else {
  1129.         MUST_MATCH_TOKEN(TOK_SEMI, "missing ; after for-loop initializer");
  1130.         top = CG_OFFSET(cg);
  1131.         SET_STATEMENT_TOP(&stmtInfo, top);
  1132.         if (js_PeekToken(cx, ts, cg) == TOK_SEMI) {
  1133.         /* No loop condition -- flag this fact in the source note. */
  1134.         if (!js_SetSrcNoteOffset(cx, cg, snindex, 0, 0))
  1135.             return JS_FALSE;
  1136.         beq = 0;
  1137.         } else {
  1138.         if (!Expr(cx, ts, cg))
  1139.             return JS_FALSE;
  1140.         if (!js_SetSrcNoteOffset(cx, cg, snindex, 0,
  1141.                      (ptrdiff_t)(CG_OFFSET(cg) - top))) {
  1142.             return JS_FALSE;
  1143.         }
  1144.         beq = js_Emit3(cx, cg, JSOP_IFEQ, 0, 0);
  1145.         if (beq < 0)
  1146.             return JS_FALSE;
  1147.         }
  1148.  
  1149.         MUST_MATCH_TOKEN(TOK_SEMI, "missing ; after for-loop condition");
  1150.         if (js_PeekToken(cx, ts, cg) != TOK_RP) {
  1151.         if (!js_InitCodeGenerator(cx, &cg2, &cx->tempPool))
  1152.             return JS_FALSE;
  1153.         CG_PUSH(cg, &cg2);
  1154.         if (js_NewSrcNote2(cx, &cg2, SRC_SETLINE,
  1155.                    (ptrdiff_t)TRUE_LINENO(ts)) < 0) {
  1156.             return JS_FALSE;
  1157.         }
  1158.         if (!Expr(cx, ts, &cg2))
  1159.             return JS_FALSE;
  1160.         if (js_Emit1(cx, &cg2, JSOP_POP) < 0)
  1161.             return JS_FALSE;
  1162.         CG_POP(cg, &cg2);
  1163.         }
  1164.     }
  1165.  
  1166.     /* (balance: */
  1167.     MUST_MATCH_TOKEN(TOK_RP, "missing ) after for-loop control");
  1168.     if (!Statement(cx, ts, cg))
  1169.         return JS_FALSE;
  1170.  
  1171.     if (snindex != -1 &&
  1172.         !js_SetSrcNoteOffset(cx, cg, snindex, 1,
  1173.                  (ptrdiff_t)(CG_OFFSET(cg) - top))) {
  1174.         return JS_FALSE;
  1175.     }
  1176.  
  1177.     if (cg2.base) {
  1178.         /* Set loop and enclosing "update" offsets, for continue. */
  1179.         stmt = &stmtInfo;
  1180.         stmt->update = CG_OFFSET(cg);
  1181.         while ((stmt = stmt->down) != 0 && stmt->type == STMT_LABEL)
  1182.         stmt->update = CG_OFFSET(cg);
  1183.  
  1184.         /* Copy the update code from its temporary pool into cg's pool. */
  1185.         if (!js_MoveSrcNotes(cx, &cg2, cg))
  1186.         return JS_FALSE;
  1187.         if (js_MoveCode(cx, &cg2, 0, cg, stmtInfo.update) < 0)
  1188.         return JS_FALSE;
  1189.  
  1190.         /* Restore the absolute line number for source note readers. */
  1191.         if (js_NewSrcNote2(cx, cg, SRC_SETLINE, (ptrdiff_t)TRUE_LINENO(ts))
  1192.         < 0) {
  1193.         return JS_FALSE;
  1194.         }
  1195.     }
  1196.  
  1197.     if (snindex != -1 &&
  1198.         !js_SetSrcNoteOffset(cx, cg, snindex, 2,
  1199.                  (ptrdiff_t)(CG_OFFSET(cg) - top))) {
  1200.         return JS_FALSE;
  1201.     }
  1202.  
  1203.     jmp = js_Emit3(cx, cg, JSOP_GOTO, 0, 0);
  1204.     if (jmp < 0)
  1205.         return JS_FALSE;
  1206.     CHECK_AND_SET_JUMP_OFFSET(cx, cg, CG_CODE(cg,jmp), top - jmp);
  1207.     if (beq > 0)
  1208.         CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
  1209.     if (!js_PopStatement(cx, cg))
  1210.         return JS_FALSE;
  1211.     if (isForInLoop) {
  1212.         /*
  1213.          * Generate the iterator pop after popping the stmtInfo stack, so
  1214.          * breaks will go to the pop bytecode.
  1215.          */
  1216.         if (js_Emit1(cx, cg, JSOP_POP) < 0)
  1217.         return JS_FALSE;
  1218.     }
  1219.     return JS_TRUE;
  1220.  
  1221.       case TOK_BREAK:
  1222.     if (!MatchLabel(cx, ts, cg, &label))
  1223.         return JS_FALSE;
  1224.     stmt = cg->stmtInfo;
  1225.     if (label) {
  1226.         for (; ; stmt = stmt->down) {
  1227.         if (!stmt) {
  1228.             js_ReportCompileError(cx, ts, "label not found");
  1229.             return JS_FALSE;
  1230.         }
  1231.         if (stmt->type == STMT_LABEL && stmt->label == label)
  1232.             break;
  1233.         }
  1234.     } else {
  1235.         for (; ; stmt = stmt->down) {
  1236.         if (!stmt) {
  1237.             js_ReportCompileError(cx, ts, "invalid break");
  1238.             return JS_FALSE;
  1239.         }
  1240.         if (STMT_IS_LOOP(stmt) || stmt->type == STMT_SWITCH)
  1241.             break;
  1242.         }
  1243.     }
  1244.     if (js_EmitBreak(cx, cg, stmt, label) < 0)
  1245.         return JS_FALSE;
  1246.     break;
  1247.  
  1248.       case TOK_CONTINUE:
  1249.     if (!MatchLabel(cx, ts, cg, &label))
  1250.         return JS_FALSE;
  1251.     stmt = cg->stmtInfo;
  1252.     if (label) {
  1253.         for (stmt2 = NULL; ; stmt = stmt->down) {
  1254.         if (!stmt) {
  1255.             js_ReportCompileError(cx, ts, "label not found");
  1256.             return JS_FALSE;
  1257.         }
  1258.         if (stmt->type == STMT_LABEL) {
  1259.             if (stmt->label == label) {
  1260.             if (!stmt2 || !STMT_IS_LOOP(stmt2)) {
  1261.                 js_ReportCompileError(cx, ts, "invalid continue");
  1262.                 return JS_FALSE;
  1263.             }
  1264.             break;
  1265.             }
  1266.         } else {
  1267.             stmt2 = stmt;
  1268.         }
  1269.         }
  1270.     } else {
  1271.         for (; ; stmt = stmt->down) {
  1272.         if (!stmt) {
  1273.             js_ReportCompileError(cx, ts, "invalid continue");
  1274.             return JS_FALSE;
  1275.         }
  1276.         if (STMT_IS_LOOP(stmt))
  1277.             break;
  1278.         }
  1279.         if (js_NewSrcNote(cx, cg, SRC_CONTINUE) < 0)
  1280.         return JS_FALSE;
  1281.     }
  1282.     if (js_EmitContinue(cx, cg, stmt, label) < 0)
  1283.         return JS_FALSE;
  1284.     break;
  1285.  
  1286.       case TOK_WITH:
  1287.     MUST_MATCH_TOKEN(TOK_LP, "missing ( before with-statement object");
  1288.     /* balance) */
  1289.     if (!Expr(cx, ts, cg))
  1290.         return JS_FALSE;
  1291.     /* (balance: */
  1292.     MUST_MATCH_TOKEN(TOK_RP, "missing ) after with-statement object");
  1293.  
  1294.     js_PushStatement(cg, &stmtInfo, STMT_WITH, CG_OFFSET(cg));
  1295.     if (js_Emit1(cx, cg, JSOP_ENTERWITH) < 0)
  1296.         return JS_FALSE;
  1297.     if (!Statement(cx, ts, cg))
  1298.         return JS_FALSE;
  1299.     if (js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0)
  1300.         return JS_FALSE;
  1301.     return js_PopStatement(cx, cg);
  1302.  
  1303.       case TOK_VAR:
  1304.     lineno = ts->lineno;
  1305.     if (!Variables(cx, ts, cg))
  1306.         return JS_FALSE;
  1307.     if (ts->lineno == lineno && !WellTerminated(cx, ts, cg, TOK_ERROR))
  1308.         return JS_FALSE;
  1309.     if (js_Emit1(cx, cg, JSOP_POP) < 0)
  1310.         return JS_FALSE;
  1311.     break;
  1312.  
  1313.       case TOK_RETURN:
  1314.     if (!(ts->flags & TSF_FUNCTION)) {
  1315.         js_ReportCompileError(cx, ts, "invalid return");
  1316.         return JS_FALSE;
  1317.     }
  1318.  
  1319.     /* This is ugly, but we don't want to require a semicolon. */
  1320.     ts->flags |= TSF_REGEXP;
  1321.     tt = js_PeekTokenSameLine(cx, ts, cg);
  1322.     ts->flags &= ~TSF_REGEXP;
  1323.     if (tt == TOK_ERROR)
  1324.         return JS_FALSE;
  1325.  
  1326.     if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {
  1327.         lineno = ts->lineno;
  1328.         if (!Expr(cx, ts, cg))
  1329.         return JS_FALSE;
  1330.         if (ts->lineno == lineno && !WellTerminated(cx, ts, cg, TOK_ERROR))
  1331.         return JS_FALSE;
  1332.         ts->flags |= TSF_RETURN_EXPR;
  1333.     } else {
  1334.         if (js_Emit1(cx, cg, JSOP_PUSH) < 0)
  1335.         return JS_FALSE;
  1336.         ts->flags |= TSF_RETURN_VOID;
  1337.     }
  1338.  
  1339.     if ((ts->flags & (TSF_RETURN_EXPR | TSF_RETURN_VOID)) ==
  1340.         (TSF_RETURN_EXPR | TSF_RETURN_VOID)) {
  1341.         js_ReportCompileError(cx, ts,
  1342.                   "function does not always return a value");
  1343.         return JS_FALSE;
  1344.     }
  1345.  
  1346.     if (js_Emit1(cx, cg, JSOP_RETURN) < 0)
  1347.         return JS_FALSE;
  1348.     break;
  1349.  
  1350.       case TOK_LC:
  1351.     js_PushStatement(cg, &stmtInfo, STMT_BLOCK, CG_OFFSET(cg));
  1352.     if (!Statements(cx, ts, cg))
  1353.         return JS_FALSE;
  1354.  
  1355.     /* {balance: */
  1356.     MUST_MATCH_TOKEN(TOK_RC, "missing } in compound statement");
  1357.     return js_PopStatement(cx, cg);
  1358.  
  1359.       case TOK_EOL:
  1360.       case TOK_SEMI:
  1361.     return JS_TRUE;
  1362.  
  1363.       case TOK_ERROR:
  1364.     return JS_FALSE;
  1365.  
  1366.       default:
  1367.     lastExprType = ts->token.type;
  1368.     js_UngetToken(ts);
  1369.     lineno = ts->lineno;
  1370.     top = CG_OFFSET(cg);
  1371.     if (!Expr(cx, ts, cg))
  1372.         return JS_FALSE;
  1373.  
  1374.     tt = ts->pushback.type;
  1375.     if (tt == TOK_COLON) {
  1376.         if (cg->lastCodeOffset != top || *CG_CODE(cg, top) != JSOP_NAME) {
  1377.         js_ReportCompileError(cx, ts, "invalid label");
  1378.         return JS_FALSE;
  1379.         }
  1380.         label = cg->atomList.list;
  1381.         for (stmt = cg->stmtInfo; stmt; stmt = stmt->down) {
  1382.         if (stmt->type == STMT_LABEL && stmt->label == label) {
  1383.             js_ReportCompileError(cx, ts, "duplicate label");
  1384.             return JS_FALSE;
  1385.         }
  1386.         }
  1387.         js_CancelLastOpcode(cx, cg, &ts->newlines);
  1388.         js_GetToken(cx, ts, cg);
  1389.  
  1390.         /* Emit an annotated nop so we know to decompile a label. */
  1391.         snindex = js_NewSrcNote(cx, cg,
  1392.                     (js_PeekToken(cx, ts, cg) == TOK_LC)
  1393.                     ? SRC_LABELBRACE
  1394.                     : SRC_LABEL);
  1395.         if (snindex < 0 ||
  1396.         !js_SetSrcNoteOffset(cx, cg, snindex, 0,
  1397.                      (ptrdiff_t)label->index) ||
  1398.         js_Emit1(cx, cg, JSOP_NOP) < 0) {
  1399.         return JS_FALSE;
  1400.         }
  1401.  
  1402.         /* Push a label struct and parse the statement. */
  1403.         js_PushStatement(cg, &stmtInfo, STMT_LABEL, CG_OFFSET(cg));
  1404.         stmtInfo.label = label;
  1405.         if (!Statement(cx, ts, cg))
  1406.         return JS_FALSE;
  1407.  
  1408.         /* If the statement was compound, emit a note for the end brace */
  1409.         if (SN_TYPE(&cg->notes[snindex]) == SRC_LABELBRACE) {
  1410.         if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 ||
  1411.             js_Emit1(cx, cg, JSOP_NOP) < 0) {
  1412.             return JS_FALSE;
  1413.         }
  1414.         }
  1415.  
  1416.         /* Finally, pop the label and return early. */
  1417.         return js_PopStatement(cx, cg);
  1418.     }
  1419.  
  1420.     if (ts->lineno == lineno && !WellTerminated(cx, ts, cg, lastExprType))
  1421.         return JS_FALSE;
  1422.     if (js_Emit1(cx, cg, JSOP_POPV) < 0)
  1423.         return JS_FALSE;
  1424.     break;
  1425.     }
  1426.  
  1427.     (void) js_MatchToken(cx, ts, cg, TOK_SEMI);
  1428.     return JS_TRUE;
  1429. }
  1430.  
  1431. static JSBool
  1432. Variables(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  1433. {
  1434.     JSObject *obj, *pobj;
  1435.     JSFunction *fun;
  1436.     JSClass *clasp;
  1437.     JSBool ok, first;
  1438.     JSPropertyOp getter, setter;
  1439.     intN snindex;
  1440.     ptrdiff_t offset, newoffset;
  1441.     JSAtom *atom;
  1442.     jsatomid atomIndex;
  1443.     JSProperty *prop;
  1444.     JSSymbol *var;
  1445.     JSOp op;
  1446.  
  1447.     obj = js_FindVariableScope(cx, &fun);
  1448.     if (!obj)
  1449.     return JS_FALSE;
  1450.  
  1451.     clasp = obj->map->clasp;
  1452.     if (fun && clasp != &js_CallClass) {
  1453.     getter = js_GetLocalVariable;
  1454.     setter = js_SetLocalVariable;
  1455.     } else {
  1456.     getter = clasp->getProperty;
  1457.     setter = clasp->setProperty;
  1458.     }
  1459.  
  1460.     ok = first = JS_TRUE;
  1461.     snindex = -1;
  1462.     for (;;) {
  1463.     MUST_MATCH_TOKEN(TOK_NAME, "missing variable name");
  1464.     atom = ts->token.u.atom;
  1465.     atomIndex = js_IndexAtom(cx, atom, &cg->atomList);
  1466.  
  1467.     pobj = NULL;
  1468.     if (!js_LookupProperty(cx, obj, (jsval)atom, &pobj, &prop))
  1469.         return JS_FALSE;
  1470.     if (prop && prop->object == obj) {
  1471.         if (prop->getter == js_GetArgument) {
  1472. #ifdef CHECK_ARGUMENT_HIDING
  1473.         js_ReportCompileError(cx, ts, "variable %s hides argument",
  1474.                       ATOM_BYTES(atom));
  1475.         ok = JS_FALSE;
  1476. #endif
  1477.         } else {
  1478.         if (fun) {
  1479.             /* Not an argument, must be a redeclared local var. */
  1480.             if (clasp != &js_CallClass) {
  1481.             PR_ASSERT(prop->getter == js_GetLocalVariable);
  1482.             PR_ASSERT(JSVAL_IS_INT(prop->id) &&
  1483.                   JSVAL_TO_INT(prop->id) < fun->nvars);
  1484.             }
  1485.         } else {
  1486.             /* Global var: (re-)set id a la js_DefineProperty. */
  1487.             prop->id = ATOM_KEY(atom);
  1488.         }
  1489.         prop->getter = getter;
  1490.         prop->setter = setter;
  1491.         prop->flags |= JSPROP_ENUMERATE | JSPROP_PERMANENT;
  1492.         prop->flags &= ~JSPROP_READONLY;
  1493.         }
  1494.     } else {
  1495.         prop = js_DefineProperty(cx, obj, (jsval)atom, JSVAL_VOID,
  1496.                      getter, setter,
  1497.                      JSPROP_ENUMERATE | JSPROP_PERMANENT);
  1498.         if (!prop)
  1499.         return JS_FALSE;
  1500.         if (getter == js_GetLocalVariable)
  1501.         prop->id = INT_TO_JSVAL(fun->nvars++);
  1502.         var = prop->symbols;
  1503.         var->next = cg->vars;
  1504.         cg->vars = var;
  1505.     }
  1506.  
  1507.     if (js_MatchToken(cx, ts, cg, TOK_ASSIGN)) {
  1508.         if (ts->token.u.op != JSOP_NOP) {
  1509.         js_ReportCompileError(cx, ts,
  1510.                       "invalid variable initialization");
  1511.         ok = JS_FALSE;
  1512.         }
  1513.         if (!AssignExpr(cx, ts, cg))
  1514.         return JS_FALSE;
  1515.         op = JSOP_SETNAME;
  1516.     } else {
  1517.         op = JSOP_NAME;
  1518.     }
  1519.     if (first && js_NewSrcNote(cx, cg, SRC_VAR) < 0)
  1520.         return JS_FALSE;
  1521.     EMIT_CONST_ATOM_OP(op, atomIndex);
  1522.     if (snindex >= 0) {
  1523.         newoffset = CG_OFFSET(cg);
  1524.         if (!js_SetSrcNoteOffset(cx, cg, snindex, 0, newoffset - offset))
  1525.         return JS_FALSE;
  1526.         offset = newoffset;
  1527.     }
  1528.     if (!js_MatchToken(cx, ts, cg, TOK_COMMA))
  1529.         break;
  1530.     offset = CG_OFFSET(cg);
  1531.     snindex = js_NewSrcNote2(cx, cg, SRC_COMMA, 0);
  1532.     if (snindex < 0 || js_Emit1(cx, cg, JSOP_POP) < 0)
  1533.         return JS_FALSE;
  1534.     first = JS_FALSE;
  1535.     }
  1536.     return ok;
  1537. }
  1538.  
  1539. static JSBool
  1540. Expr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  1541. {
  1542.     intN snindex;
  1543.     ptrdiff_t offset, newoffset;
  1544.  
  1545.     snindex = -1;
  1546.     for (;;) {
  1547.     if (!AssignExpr(cx, ts, cg))
  1548.         return JS_FALSE;
  1549.     if (snindex >= 0) {
  1550.         newoffset = CG_OFFSET(cg);
  1551.         if (!js_SetSrcNoteOffset(cx, cg, snindex, 0, newoffset - offset))
  1552.         return JS_FALSE;
  1553.         offset = newoffset;
  1554.     }
  1555.     if (!js_MatchToken(cx, ts, cg, TOK_COMMA))
  1556.         break;
  1557.     offset = CG_OFFSET(cg);
  1558.     snindex = js_NewSrcNote2(cx, cg, SRC_COMMA, 0);
  1559.     if (snindex < 0 || js_Emit1(cx, cg, JSOP_POP) < 0)
  1560.         return JS_FALSE;
  1561.     }
  1562.     return JS_TRUE;
  1563. }
  1564.  
  1565. /*
  1566.  * XXX Need to build abstract syntax tree for complete error checking:
  1567.  * XXX (true ? 3 : x) = 4 does not result in an error, it evaluates to 3.
  1568.  * XXX similarly for (true && x) = 5, etc.
  1569.  */
  1570. static JSBool
  1571. AssignExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  1572. {
  1573.     ptrdiff_t begin;
  1574.     jsbytecode *pc;
  1575.     JSOp lastop, op;
  1576.     jsatomid atomIndex;
  1577.  
  1578.     begin = CG_OFFSET(cg);
  1579.     if (!CondExpr(cx, ts, cg))
  1580.     return JS_FALSE;
  1581.     if (js_MatchToken(cx, ts, cg, TOK_ASSIGN)) {
  1582.     pc = CG_CODE(cg, cg->lastCodeOffset);
  1583.     lastop = (JSOp) *pc;
  1584.     switch (lastop) {
  1585.       case JSOP_NAME:
  1586.       case JSOP_GETPROP:
  1587.         atomIndex = GET_ATOM_INDEX(pc);
  1588.         break;
  1589.       case JSOP_GETELEM:
  1590.         /* GETELEM and SETELEM have no immediate operand. */
  1591.         break;
  1592.       default:
  1593.         js_ReportCompileError(cx, ts, "invalid assignment left-hand side");
  1594.         return JS_FALSE;
  1595.     }
  1596.     js_CancelLastOpcode(cx, cg, &ts->newlines);
  1597.  
  1598.     op = ts->token.u.op;
  1599.     if (op != JSOP_NOP) {
  1600.         switch (lastop) {
  1601.           case JSOP_NAME:
  1602.         EMIT_CONST_ATOM_OP(lastop, atomIndex);
  1603.         break;
  1604.           case JSOP_GETPROP:
  1605.         if (js_Emit1(cx, cg, JSOP_DUP) < 0)
  1606.             return JS_FALSE;
  1607.         EMIT_CONST_ATOM_OP(lastop, atomIndex);
  1608.         break;
  1609.           case JSOP_GETELEM:
  1610.         if (js_Emit1(cx, cg, JSOP_DUP2) < 0)
  1611.             return JS_FALSE;
  1612.         if (js_Emit1(cx, cg, JSOP_GETELEM) < 0)
  1613.             return JS_FALSE;
  1614.         break;
  1615.           default:;
  1616.         }
  1617.     }
  1618.     if (!AssignExpr(cx, ts, cg))
  1619.         return JS_FALSE;
  1620.     if (op != JSOP_NOP) {
  1621.         if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0 ||
  1622.         js_Emit1(cx, cg, op) < 0) {
  1623.         return JS_FALSE;
  1624.         }
  1625.     }
  1626.  
  1627.     if (lastop != JSOP_NAME) {
  1628.         if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
  1629.                    (ptrdiff_t)(CG_OFFSET(cg) - begin)) < 0) {
  1630.         return JS_FALSE;
  1631.         }
  1632.     }
  1633.  
  1634.     switch (lastop) {
  1635.       case JSOP_NAME:
  1636.         EMIT_CONST_ATOM_OP(JSOP_SETNAME, atomIndex);
  1637.         break;
  1638.       case JSOP_GETPROP:
  1639.         EMIT_CONST_ATOM_OP(JSOP_SETPROP, atomIndex);
  1640.         break;
  1641.       case JSOP_GETELEM:
  1642.         if (js_Emit1(cx, cg, JSOP_SETELEM) < 0)
  1643.         return JS_FALSE;
  1644.         break;
  1645.       default:;
  1646.     }
  1647.     }
  1648.     return JS_TRUE;
  1649. }
  1650.  
  1651. static JSBool
  1652. CondExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  1653. {
  1654.     ptrdiff_t beq, jmp;
  1655.  
  1656.     if (!OrExpr(cx, ts, cg))
  1657.     return JS_FALSE;
  1658.     if (js_MatchToken(cx, ts, cg, TOK_HOOK)) {
  1659.     if (js_NewSrcNote(cx, cg, SRC_COND) < 0)
  1660.         return JS_FALSE;
  1661.     beq = js_Emit3(cx, cg, JSOP_IFEQ, 0, 0);
  1662.     if (beq < 0 || !AssignExpr(cx, ts, cg))
  1663.         return JS_FALSE;
  1664.     MUST_MATCH_TOKEN(TOK_COLON, "missing : in conditional expression");
  1665.     jmp = js_Emit3(cx, cg, JSOP_GOTO, 0, 0);
  1666.     if (jmp < 0)
  1667.         return JS_FALSE;
  1668.     CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
  1669.     if (!AssignExpr(cx, ts, cg))
  1670.         return JS_FALSE;
  1671.     CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
  1672.     }
  1673.     return JS_TRUE;
  1674. }
  1675.  
  1676. static JSBool
  1677. OrExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  1678. {
  1679. #if JS_BUG_SHORT_CIRCUIT
  1680.     ptrdiff_t beq, tmp, jmp;
  1681. #else
  1682.     ptrdiff_t jmp;
  1683. #endif
  1684.  
  1685.     if (!AndExpr(cx, ts, cg))
  1686.     return JS_FALSE;
  1687.     if (js_MatchToken(cx, ts, cg, TOK_OR)) {
  1688. #if JS_BUG_SHORT_CIRCUIT
  1689.     beq = js_Emit3(cx, cg, JSOP_IFEQ, 0, 0);
  1690.     tmp = js_Emit1(cx, cg, JSOP_TRUE);
  1691.     jmp = js_Emit3(cx, cg, JSOP_GOTO, 0, 0);
  1692.     if (beq < 0 || tmp < 0 || jmp < 0)
  1693.         return JS_FALSE;
  1694.     CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
  1695. #else
  1696.     jmp = js_Emit3(cx, cg, JSOP_OR, 0, 0);
  1697.     if (jmp < 0)
  1698.         return JS_FALSE;
  1699. #endif
  1700.     if (!OrExpr(cx, ts, cg))
  1701.         return JS_FALSE;
  1702.     CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
  1703.     }
  1704.     return JS_TRUE;
  1705. }
  1706.  
  1707. static JSBool
  1708. AndExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  1709. {
  1710. #if JS_BUG_SHORT_CIRCUIT
  1711.     ptrdiff_t bne, tmp, jmp;
  1712. #else
  1713.     ptrdiff_t jmp;
  1714. #endif
  1715.  
  1716.     if (!BitOrExpr(cx, ts, cg))
  1717.     return JS_FALSE;
  1718.     if (js_MatchToken(cx, ts, cg, TOK_AND)) {
  1719. #if JS_BUG_SHORT_CIRCUIT
  1720.     bne = js_Emit3(cx, cg, JSOP_IFNE, 0, 0);
  1721.     tmp = js_Emit1(cx, cg, JSOP_FALSE);
  1722.     jmp = js_Emit3(cx, cg, JSOP_GOTO, 0, 0);
  1723.     if (bne < 0 || tmp < 0 || jmp < 0)
  1724.         return JS_FALSE;
  1725.     CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, bne);
  1726. #else
  1727.     jmp = js_Emit3(cx, cg, JSOP_AND, 0, 0);
  1728.     if (jmp < 0)
  1729.         return JS_FALSE;
  1730. #endif
  1731.     if (!AndExpr(cx, ts, cg))
  1732.         return JS_FALSE;
  1733.     CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
  1734.     }
  1735.     return JS_TRUE;
  1736. }
  1737.  
  1738. static JSBool
  1739. BitOrExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  1740. {
  1741.     if (!BitXorExpr(cx, ts, cg))
  1742.     return JS_FALSE;
  1743.     while (js_MatchToken(cx, ts, cg, TOK_BITOR)) {
  1744.     if (!BitXorExpr(cx, ts, cg) ||
  1745.         js_Emit1(cx, cg, JSOP_BITOR) < 0) {
  1746.         return JS_FALSE;
  1747.     }
  1748.     }
  1749.     return JS_TRUE;
  1750. }
  1751.  
  1752. static JSBool
  1753. BitXorExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  1754. {
  1755.     if (!BitAndExpr(cx, ts, cg))
  1756.     return JS_FALSE;
  1757.     while (js_MatchToken(cx, ts, cg, TOK_BITXOR)) {
  1758.     if (!BitAndExpr(cx, ts, cg) ||
  1759.         js_Emit1(cx, cg, JSOP_BITXOR) < 0) {
  1760.         return JS_FALSE;
  1761.     }
  1762.     }
  1763.     return JS_TRUE;
  1764. }
  1765.  
  1766. static JSBool
  1767. BitAndExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  1768. {
  1769.     if (!EqExpr(cx, ts, cg))
  1770.     return JS_FALSE;
  1771.     while (js_MatchToken(cx, ts, cg, TOK_BITAND)) {
  1772.     if (!EqExpr(cx, ts, cg) || js_Emit1(cx, cg, JSOP_BITAND) < 0)
  1773.         return JS_FALSE;
  1774.     }
  1775.     return JS_TRUE;
  1776. }
  1777.  
  1778. static JSBool
  1779. EqExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  1780. {
  1781.     JSOp op;
  1782.  
  1783.     if (!RelExpr(cx, ts, cg))
  1784.     return JS_FALSE;
  1785.     while (js_MatchToken(cx, ts, cg, TOK_EQOP)) {
  1786.     op = ts->token.u.op;
  1787.     if (!RelExpr(cx, ts, cg) || js_Emit1(cx, cg, op) < 0)
  1788.         return JS_FALSE;
  1789.     }
  1790.     return JS_TRUE;
  1791. }
  1792.  
  1793. static JSBool
  1794. RelExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  1795. {
  1796.     JSOp op;
  1797.  
  1798.     if (!ShiftExpr(cx, ts, cg))
  1799.     return JS_FALSE;
  1800.     while (js_MatchToken(cx, ts, cg, TOK_RELOP)) {
  1801.     op = ts->token.u.op;
  1802.     if (!ShiftExpr(cx, ts, cg) || js_Emit1(cx, cg, op) < 0)
  1803.         return JS_FALSE;
  1804.     }
  1805.     return JS_TRUE;
  1806. }
  1807.  
  1808. static JSBool
  1809. ShiftExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  1810. {
  1811.     JSOp op;
  1812.  
  1813.     if (!AddExpr(cx, ts, cg))
  1814.     return JS_FALSE;
  1815.     while (js_MatchToken(cx, ts, cg, TOK_SHOP)) {
  1816.     op = ts->token.u.op;
  1817.     if (!AddExpr(cx, ts, cg) || js_Emit1(cx, cg, op) < 0)
  1818.         return JS_FALSE;
  1819.     }
  1820.     return JS_TRUE;
  1821. }
  1822.  
  1823. static JSBool
  1824. AddExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  1825. {
  1826.     JSTokenType tt;
  1827.  
  1828.     if (!MulExpr(cx, ts, cg))
  1829.     return JS_FALSE;
  1830.     ts->flags |= TSF_LOOKAHEAD;
  1831.     while ((tt = js_GetToken(cx, ts, cg)) == TOK_PLUS || tt == TOK_MINUS) {
  1832.     ts->flags &= ~TSF_LOOKAHEAD;
  1833.     if (!js_FlushNewlines(cx, ts, cg) ||
  1834.         !MulExpr(cx, ts, cg) ||
  1835.         js_Emit1(cx, cg, (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB) < 0) {
  1836.         return JS_FALSE;
  1837.     }
  1838.     ts->flags |= TSF_LOOKAHEAD;
  1839.     }
  1840.     ts->flags &= ~TSF_LOOKAHEAD;
  1841.     js_UngetToken(ts);
  1842.     return JS_TRUE;
  1843. }
  1844.  
  1845. static JSBool
  1846. MulExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  1847. {
  1848.     JSOp op;
  1849.  
  1850.     if (!UnaryExpr(cx, ts, cg))
  1851.     return JS_FALSE;
  1852.     while (js_MatchToken(cx, ts, cg, TOK_STAR) ||
  1853.        js_MatchToken(cx, ts, cg, TOK_DIVOP)) {
  1854.     op = ts->token.u.op;
  1855.     if (!UnaryExpr(cx, ts, cg) || js_Emit1(cx, cg, op) < 0)
  1856.         return JS_FALSE;
  1857.     }
  1858.     return JS_TRUE;
  1859. }
  1860.  
  1861. static JSBool
  1862. EmitIncOp(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg,
  1863.       JSTokenType tt, JSBool preorder)
  1864. {
  1865.     jsbytecode *pc;
  1866.     JSOp op;
  1867.  
  1868.     pc = CG_CODE(cg, cg->lastCodeOffset);
  1869.     op = (JSOp) *pc;
  1870.     switch (op) {
  1871.       case JSOP_NAME:
  1872.     if (tt == TOK_INC)
  1873.         op = preorder ? JSOP_INCNAME : JSOP_NAMEINC;
  1874.     else
  1875.         op = preorder ? JSOP_DECNAME : JSOP_NAMEDEC;
  1876.     break;
  1877.       case JSOP_GETPROP:
  1878.     if (tt == TOK_INC)
  1879.         op = preorder ? JSOP_INCPROP : JSOP_PROPINC;
  1880.     else
  1881.         op = preorder ? JSOP_DECPROP : JSOP_PROPDEC;
  1882.     break;
  1883.       case JSOP_GETELEM:
  1884.     if (tt == TOK_INC)
  1885.         op = preorder ? JSOP_INCELEM : JSOP_ELEMINC;
  1886.     else
  1887.         op = preorder ? JSOP_DECELEM : JSOP_ELEMDEC;
  1888.     break;
  1889.       default:
  1890.     js_ReportCompileError(cx, ts, "invalid %screment expression",
  1891.                   (tt == TOK_INC) ? "in" : "de");
  1892.     return JS_FALSE;
  1893.     }
  1894.     *pc = op;
  1895.     return JS_TRUE;
  1896. }
  1897.  
  1898. static JSBool
  1899. UnaryExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  1900. {
  1901.     JSTokenType tt;
  1902.     JSOp op, lastop;
  1903.     ptrdiff_t begin;
  1904.     jsatomid atomIndex;
  1905.     uintN argc, lineno;
  1906.     jsbytecode *pc;
  1907.  
  1908.     ts->flags |= TSF_REGEXP;
  1909.     tt = js_GetToken(cx, ts, cg);
  1910.     ts->flags &= ~TSF_REGEXP;
  1911.  
  1912.     switch (tt) {
  1913.       case TOK_UNARYOP:
  1914.       case TOK_PLUS:
  1915.       case TOK_MINUS:
  1916.     op = ts->token.u.op;
  1917.     if (!UnaryExpr(cx, ts, cg) || js_Emit1(cx, cg, op) < 0)
  1918.         return JS_FALSE;
  1919.     break;
  1920.       case TOK_INC:
  1921.       case TOK_DEC:
  1922.     if (!MemberExpr(cx, ts, cg))
  1923.         return JS_FALSE;
  1924.     if (!EmitIncOp(cx, ts, cg, tt, JS_TRUE))
  1925.         return JS_FALSE;
  1926.     break;
  1927.       case TOK_NEW:
  1928.     /* Allow 'new this.ctor(...)' constructor expressions. */
  1929.     begin = CG_OFFSET(cg);
  1930.     tt = js_GetToken(cx, ts, cg);
  1931.     switch (tt) {
  1932.       case TOK_NAME:
  1933.         atomIndex = js_IndexAtom(cx, ts->token.u.atom, &cg->atomList);
  1934.         EMIT_CONST_ATOM_OP(JSOP_NAME, atomIndex);
  1935.         break;
  1936.       case TOK_PRIMARY:
  1937.         if (ts->token.u.op == JSOP_THIS) {
  1938.         if (js_Emit1(cx, cg, JSOP_THIS) < 0)
  1939.             return JS_FALSE;
  1940.         break;
  1941.         }
  1942.         /* FALL THROUGH */
  1943.       default:
  1944.         js_ReportCompileError(cx, ts, "missing name after new operator");
  1945.         return JS_FALSE;
  1946.     }
  1947.     while (js_MatchToken(cx, ts, cg, TOK_DOT)) {
  1948.         MUST_MATCH_TOKEN(TOK_NAME,
  1949.                  "missing name in constructor expression");
  1950.         if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
  1951.                    (ptrdiff_t)(CG_OFFSET(cg) - begin)) < 0) {
  1952.         return JS_FALSE;
  1953.         }
  1954.         atomIndex = js_IndexAtom(cx, ts->token.u.atom, &cg->atomList);
  1955.         EMIT_CONST_ATOM_OP(JSOP_GETPROP, atomIndex);
  1956.     }
  1957.     if (js_Emit1(cx, cg, JSOP_PUSHOBJ) < 0)
  1958.         return JS_FALSE;
  1959.     argc = 0;
  1960.     if (js_MatchToken(cx, ts, cg, TOK_LP) &&
  1961.         !js_MatchToken(cx, ts, cg, TOK_RP)) {
  1962.         do {
  1963.         if (!AssignExpr(cx, ts, cg))
  1964.             return JS_FALSE;
  1965.         argc++;
  1966.         } while (js_MatchToken(cx, ts, cg, TOK_COMMA));
  1967.  
  1968.         /* (balance: */
  1969.         MUST_MATCH_TOKEN(TOK_RP,
  1970.                  "missing ) after constructor argument list");
  1971.     }
  1972.     if (argc >= ARGC_LIMIT) {
  1973.         JS_ReportError(cx, "too many constructor arguments");
  1974.         return JS_FALSE;
  1975.     }
  1976.     if (js_Emit3(cx, cg, JSOP_NEW, ARGC_HI(argc), ARGC_LO(argc)) < 0)
  1977.         return JS_FALSE;
  1978.     break;
  1979.  
  1980.       case TOK_DELETE:
  1981.     /* Compile the operand expression. */
  1982.     begin = CG_OFFSET(cg);
  1983.     if (!MemberExpr(cx, ts, cg))
  1984.         return JS_FALSE;
  1985.  
  1986.     /* Cancel the last bytecode, saving it for re-emission later. */
  1987.     pc = CG_CODE(cg, cg->lastCodeOffset);
  1988.     lastop = (JSOp) *pc;
  1989.     switch (lastop) {
  1990.       case JSOP_NAME:
  1991.       case JSOP_GETPROP:
  1992.         atomIndex = GET_ATOM_INDEX(pc);
  1993.         break;
  1994.       case JSOP_GETELEM:
  1995.         /* GETELEM and DELELEM have no immediate operand. */
  1996.         break;
  1997.       default:
  1998.         js_ReportCompileError(cx, ts, "invalid %s operand", js_delete_str);
  1999.         return JS_FALSE;
  2000.     }
  2001.     js_CancelLastOpcode(cx, cg, &ts->newlines);
  2002.  
  2003.     if (lastop != JSOP_NAME) {
  2004.         if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
  2005.                    (int16)(CG_OFFSET(cg) - begin)) < 0) {
  2006.         return JS_FALSE;
  2007.         }
  2008.     }
  2009.  
  2010.     /* Re-emit the operand's last bytecode as a JSOP_DEL* variant. */
  2011.     switch (lastop) {
  2012.       case JSOP_NAME:
  2013.         EMIT_CONST_ATOM_OP(JSOP_DELNAME, atomIndex);
  2014.         break;
  2015.       case JSOP_GETPROP:
  2016.         EMIT_CONST_ATOM_OP(JSOP_DELPROP, atomIndex);
  2017.         break;
  2018.       case JSOP_GETELEM:
  2019.         if (js_Emit1(cx, cg, JSOP_DELELEM) < 0)
  2020.         return JS_FALSE;
  2021.         break;
  2022.       default:;
  2023.     }
  2024.     break;
  2025.  
  2026.       case TOK_ERROR:
  2027.     return JS_FALSE;
  2028.  
  2029.       default:
  2030.     js_UngetToken(ts);
  2031.     lineno = ts->lineno;
  2032.     if (!MemberExpr(cx, ts, cg))
  2033.         return JS_FALSE;
  2034.  
  2035.     /* Don't look across a newline boundary for a postfix incop. */
  2036.     if (ts->lineno == lineno &&
  2037.         (js_MatchToken(cx, ts, cg, TOK_INC) ||
  2038.          js_MatchToken(cx, ts, cg, TOK_DEC))) {
  2039.         if (!EmitIncOp(cx, ts, cg, ts->token.type, JS_FALSE))
  2040.         return JS_FALSE;
  2041.     }
  2042.     }
  2043.     return JS_TRUE;
  2044. }
  2045.  
  2046. static JSBool
  2047. MemberExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  2048. {
  2049.     ptrdiff_t begin;
  2050.     JSToken token;
  2051.     JSTokenType tt;
  2052.     jsatomid atomIndex;
  2053.     uintN argc;
  2054.     JSBool matched;
  2055.     JSObject *pobj;
  2056.     JSProperty *prop;
  2057.     jsval val;
  2058.     JSFunction *fun;
  2059.     char *option;
  2060.     JSAtom *atom;
  2061.  
  2062.     begin = CG_OFFSET(cg);
  2063.     if (!PrimaryExpr(cx, ts, cg))
  2064.     return JS_FALSE;
  2065.  
  2066.     token = ts->token;
  2067.     ts->flags |= TSF_LOOKAHEAD;
  2068.     while ((tt = js_GetToken(cx, ts, cg)) > TOK_EOF) {
  2069.     ts->flags &= ~TSF_LOOKAHEAD;
  2070.  
  2071.     if (tt == TOK_DOT) {
  2072.         /*
  2073.          * Compile get-property opcode.
  2074.          */
  2075.         if (!js_FlushNewlines(cx, ts, cg))
  2076.         return JS_FALSE;
  2077.         MUST_MATCH_TOKEN(TOK_NAME, "missing name after . operator");
  2078.  
  2079.         if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
  2080.                    (ptrdiff_t)(CG_OFFSET(cg) - begin)) < 0) {
  2081.         return JS_FALSE;
  2082.         }
  2083.         atomIndex = js_IndexAtom(cx, ts->token.u.atom, &cg->atomList);
  2084.         EMIT_CONST_ATOM_OP(JSOP_GETPROP, atomIndex);
  2085.     } else if (tt == TOK_LB) {
  2086.         /*
  2087.          * Compile index expression and get-slot opcode.
  2088.          */
  2089.         if (!js_FlushNewlines(cx, ts, cg))
  2090.         return JS_FALSE;
  2091.         if (!Expr(cx, ts, cg))
  2092.         return JS_FALSE;
  2093.         /* [balance: */
  2094.         MUST_MATCH_TOKEN(TOK_RB, "missing ] in index expression");
  2095.  
  2096.         if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
  2097.                    (ptrdiff_t)(CG_OFFSET(cg) - begin)) < 0) {
  2098.         return JS_FALSE;
  2099.         }
  2100.         if (js_Emit1(cx, cg, JSOP_GETELEM) < 0)
  2101.         return JS_FALSE;
  2102.     } else if (tt == TOK_LP) {
  2103.         /*
  2104.          * Compile 'this' and the actual args, followed by a call opcode.
  2105.          */
  2106.         if (js_Emit1(cx, cg, JSOP_PUSHOBJ) < 0)
  2107.         return JS_FALSE;
  2108.         if (!js_FlushNewlines(cx, ts, cg))
  2109.         return JS_FALSE;
  2110.         argc = 0;
  2111.         ts->flags |= TSF_REGEXP;
  2112.         matched = js_MatchToken(cx, ts, cg, TOK_RP);
  2113.         ts->flags &= ~TSF_REGEXP;
  2114.         if (!matched) {
  2115.         do {
  2116.             if (!AssignExpr(cx, ts, cg))
  2117.             return JS_FALSE;
  2118.             argc++;
  2119.         } while (js_MatchToken(cx, ts, cg, TOK_COMMA));
  2120.  
  2121.         /* (balance: */
  2122.         MUST_MATCH_TOKEN(TOK_RP, "missing ) after argument list");
  2123.         }
  2124.  
  2125.         if (argc >= ARGC_LIMIT) {
  2126.         JS_ReportError(cx, "too many function arguments");
  2127.         return JS_FALSE;
  2128.         }
  2129.         if (js_Emit3(cx, cg, JSOP_CALL, ARGC_HI(argc), ARGC_LO(argc)) < 0)
  2130.         return JS_FALSE;
  2131.     } else {
  2132.         js_UngetToken(ts);
  2133.  
  2134.         /*
  2135.          * Look for a name, number, or string immediately after a name.
  2136.          * Such a token juxtaposition is likely to be a "command-style"
  2137.          * function call.
  2138.          */
  2139.         if ((ts->flags & TSF_COMMAND) &&
  2140.         token.type == TOK_NAME &&
  2141.         *CG_CODE(cg, cg->lastCodeOffset) == JSOP_NAME &&
  2142.         (tt == TOK_EOL || tt == TOK_MINUS || IS_PRIMARY_TOKEN(tt))) {
  2143.         pobj = NULL;
  2144.         if (!js_LookupProperty(cx, cx->fp->scopeChain,
  2145.                        (jsval)token.u.atom, &pobj, &prop)) {
  2146.             return JS_FALSE;
  2147.         }
  2148.         if (prop &&
  2149.             (val = prop->object->slots[prop->slot]) &&
  2150.             JSVAL_IS_FUNCTION(val) &&
  2151.             (fun = js_ValueToFunction(cx, val)) &&
  2152.             (tt != TOK_EOL || fun->nargs == 0)) {
  2153.             if (js_Emit1(cx, cg, JSOP_PUSHOBJ) < 0)
  2154.             return JS_FALSE;
  2155.             if (!js_FlushNewlines(cx, ts, cg))
  2156.             return JS_FALSE;
  2157.             argc = 0;
  2158.             while (tt != TOK_EOL && tt != TOK_SEMI &&
  2159.                tt != TOK_RP && tt != TOK_RC) {
  2160.             if (tt == TOK_MINUS && JS7_ISLET(ts->token.ptr[1])) {
  2161.                 (void) js_GetToken(cx, ts, cg);
  2162.                 MUST_MATCH_TOKEN(TOK_NAME,
  2163.                 "missing option after - in command");
  2164.                 option = PR_smprintf("-%s",
  2165.                          ATOM_BYTES(ts->token.u.atom));
  2166.                 if (!option) {
  2167.                 JS_ReportOutOfMemory(cx);
  2168.                 return JS_FALSE;
  2169.                 }
  2170.                 atom = js_Atomize(cx, option, strlen(option), 0);
  2171.                 free(option);
  2172.                 if (!atom)
  2173.                 return JS_FALSE;
  2174.                 atomIndex = js_IndexAtom(cx, atom, &cg->atomList);
  2175.                 EMIT_CONST_ATOM_OP(JSOP_STRING, atomIndex);
  2176.                 js_DropAtom(cx, atom);
  2177.             } else {
  2178.                 if (!AssignExpr(cx, ts, cg))
  2179.                 return JS_FALSE;
  2180.             }
  2181.             argc++;
  2182.             js_MatchToken(cx, ts, cg, TOK_COMMA);
  2183.             tt = js_PeekToken(cx, ts, cg);
  2184.             }
  2185.             if (argc >= ARGC_LIMIT) {
  2186.             JS_ReportError(cx, "too many command arguments");
  2187.             return JS_FALSE;
  2188.             }
  2189.             if (js_Emit3(cx, cg, JSOP_CALL,
  2190.                  ARGC_HI(argc), ARGC_LO(argc)) < 0) {
  2191.             return JS_FALSE;
  2192.             }
  2193.         }
  2194.         }
  2195.         break;
  2196.     }
  2197.  
  2198.     token = ts->token;
  2199.     ts->flags |= TSF_LOOKAHEAD;
  2200.     }
  2201.     ts->flags &= ~TSF_LOOKAHEAD;
  2202.     return (tt != TOK_ERROR);
  2203. }
  2204.  
  2205. static JSBool
  2206. EmitNumberOp(JSContext *cx, jsdouble dval, JSCodeGenerator *cg)
  2207. {
  2208.     jsint ival;
  2209.     JSAtom *atom;
  2210.     jsatomid atomIndex;
  2211.  
  2212.     ival = (jsint)dval;
  2213.     if (JSDOUBLE_IS_INT(dval, ival) && INT_FITS_IN_JSVAL(ival)) {
  2214.     if (ival == 0)
  2215.         return js_Emit1(cx, cg, JSOP_ZERO) >= 0;
  2216.     if (ival == 1)
  2217.         return js_Emit1(cx, cg, JSOP_ONE) >= 0;
  2218.     if ((jsuint)ival < (jsuint)ATOM_INDEX_LIMIT) {
  2219.         atomIndex = (jsatomid)ival;
  2220.         EMIT_CONST_ATOM_OP(JSOP_UINT16, atomIndex);
  2221.         return JS_TRUE;
  2222.     }
  2223.     atom = js_AtomizeInt(cx, ival, ATOM_NOHOLD);
  2224.     } else {
  2225.     atom = js_AtomizeDouble(cx, dval, ATOM_NOHOLD);
  2226.     }
  2227.     if (!atom)
  2228.     return JS_FALSE;
  2229.     atomIndex = js_IndexAtom(cx, atom, &cg->atomList);
  2230.     EMIT_CONST_ATOM_OP(JSOP_NUMBER, atomIndex);
  2231.     return JS_TRUE;
  2232. }
  2233.  
  2234. static JSBool
  2235. PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSCodeGenerator *cg)
  2236. {
  2237.     JSTokenType tt;
  2238.     jsatomid atomIndex;
  2239.  
  2240. #if JS_HAS_SHARP_VARS
  2241.     JSBool defsharp = JS_FALSE;
  2242.     jsatomid sharpnum = 0;
  2243.   again:
  2244. #endif
  2245.  
  2246.     ts->flags |= TSF_REGEXP;
  2247.     tt = js_GetToken(cx, ts, cg);
  2248.     ts->flags &= ~TSF_REGEXP;
  2249.  
  2250.     switch (tt) {
  2251. #if JS_HAS_LEXICAL_CLOSURE
  2252.       case TOK_FUNCTION:
  2253.     return FunctionExpr(cx, ts, cg);
  2254. #endif
  2255.  
  2256. #if JS_HAS_OBJECT_LITERAL
  2257.       case TOK_LB:
  2258.       {
  2259.     JSBool matched;
  2260.     jsint index;
  2261.  
  2262.     atomIndex = js_IndexAtom(cx, cx->runtime->atomState.ArrayAtom,
  2263.                  &cg->atomList);
  2264.     EMIT_CONST_ATOM_OP(JSOP_NAME, atomIndex);
  2265.     if (js_Emit1(cx, cg, JSOP_PUSHOBJ) < 0)
  2266.         return JS_FALSE;
  2267.     if (js_Emit1(cx, cg, JSOP_NEWINIT) < 0)
  2268.         return JS_FALSE;
  2269.  
  2270. #if JS_HAS_SHARP_VARS
  2271.     if (defsharp)
  2272.         EMIT_CONST_ATOM_OP(JSOP_DEFSHARP, sharpnum);
  2273. #endif
  2274.  
  2275.     ts->flags |= TSF_REGEXP;
  2276.     matched = js_MatchToken(cx, ts, cg, TOK_RB);
  2277.     ts->flags &= ~TSF_REGEXP;
  2278.     if (!matched) {
  2279.         for (index = 0; index < ATOM_INDEX_LIMIT; index++) {
  2280.         ts->flags |= TSF_REGEXP;
  2281.         tt = js_PeekToken(cx, ts, cg);
  2282.         ts->flags &= ~TSF_REGEXP;
  2283.         if (tt == TOK_RB) {
  2284.             if (js_NewSrcNote(cx, cg, SRC_COMMA) < 0)
  2285.             return JS_FALSE;
  2286.             break;
  2287.         }
  2288.  
  2289.         if (index == 0) {
  2290.             if (js_Emit1(cx, cg, JSOP_ZERO) < 0)
  2291.             return JS_FALSE;
  2292.         } else if (index == 1) {
  2293.             if (js_Emit1(cx, cg, JSOP_ONE) < 0)
  2294.             return JS_FALSE;
  2295.         } else {
  2296.             atomIndex = (jsatomid) index;
  2297.             EMIT_CONST_ATOM_OP(JSOP_UINT16, atomIndex);
  2298.         }
  2299.  
  2300.         if (tt == TOK_COMMA) {
  2301.             if (js_Emit1(cx, cg, JSOP_PUSH) < 0)
  2302.             return JS_FALSE;
  2303.         } else {
  2304.             if (!AssignExpr(cx, ts, cg))
  2305.             return JS_FALSE;
  2306.         }
  2307.         if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
  2308.             return JS_FALSE;
  2309.  
  2310.         if (!js_MatchToken(cx, ts, cg, TOK_COMMA))
  2311.             break;
  2312.         }
  2313.  
  2314.         /* [balance: */
  2315.         MUST_MATCH_TOKEN(TOK_RB, "missing ] after element list");
  2316.     }
  2317.  
  2318.     /* Emit an annotated op for sharpArray cleanup and decompilation. */
  2319.     if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0)
  2320.         return JS_FALSE;
  2321.     break;
  2322.       }
  2323.  
  2324.       case TOK_LC:
  2325.       {
  2326.     atomIndex = js_IndexAtom(cx, cx->runtime->atomState.ObjectAtom,
  2327.                  &cg->atomList);
  2328.     EMIT_CONST_ATOM_OP(JSOP_NAME, atomIndex);
  2329.     if (js_Emit1(cx, cg, JSOP_PUSHOBJ) < 0)
  2330.         return JS_FALSE;
  2331.     if (js_Emit1(cx, cg, JSOP_NEWINIT) < 0)
  2332.         return JS_FALSE;
  2333.  
  2334. #if JS_HAS_SHARP_VARS
  2335.     if (defsharp)
  2336.         EMIT_CONST_ATOM_OP(JSOP_DEFSHARP, sharpnum);
  2337. #endif
  2338.  
  2339.     if (!js_MatchToken(cx, ts, cg, TOK_RC)) {
  2340.         do {
  2341.         tt = js_GetToken(cx, ts, cg);
  2342.         switch (tt) {
  2343.           case TOK_NUMBER:
  2344.             if (!EmitNumberOp(cx, ts->token.u.dval, cg))
  2345.             return JS_FALSE;
  2346.             break;
  2347.           case TOK_NAME:
  2348.           case TOK_STRING:
  2349.             atomIndex = js_IndexAtom(cx, ts->token.u.atom,
  2350.                          &cg->atomList);
  2351.             break;
  2352.           default:
  2353.             js_ReportCompileError(cx, ts, "invalid property id");
  2354.             return JS_FALSE;
  2355.         }
  2356.  
  2357.         MUST_MATCH_TOKEN(TOK_COLON, "missing : after property id");
  2358.         if (!AssignExpr(cx, ts, cg))
  2359.             return JS_FALSE;
  2360.  
  2361.         if (tt == TOK_NUMBER) {
  2362.             if (js_NewSrcNote(cx, cg, SRC_LABEL) < 0)
  2363.             return JS_FALSE;
  2364.             if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
  2365.             return JS_FALSE;
  2366.         } else {
  2367.             EMIT_CONST_ATOM_OP(JSOP_INITPROP, atomIndex);
  2368.         }
  2369.         } while (js_MatchToken(cx, ts, cg, TOK_COMMA));
  2370.  
  2371.         /* {balance: */
  2372.         MUST_MATCH_TOKEN(TOK_RC, "missing } after property list");
  2373.     }
  2374.  
  2375.     /* Emit an op for sharpArray cleanup and decompilation. */
  2376.     if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0)
  2377.         return JS_FALSE;
  2378.     break;
  2379.       }
  2380.  
  2381. #if JS_HAS_SHARP_VARS
  2382.       case TOK_DEFSHARP:
  2383.     defsharp = JS_TRUE;
  2384.     sharpnum = (jsatomid) ts->token.u.dval;
  2385.     ts->flags |= TSF_REGEXP;
  2386.     tt = js_PeekToken(cx, ts, cg);
  2387.     ts->flags &= ~TSF_REGEXP;
  2388.     if (tt != TOK_LB && tt != TOK_LC) {
  2389.         js_ReportCompileError(cx, ts, "invalid sharp variable definition");
  2390.         return JS_FALSE;
  2391.     }
  2392.     goto again;
  2393.  
  2394.       case TOK_USESHARP:
  2395.     /* Check for forward/dangling references at runtime, to allow eval. */
  2396.     sharpnum = (jsatomid) ts->token.u.dval;
  2397.     EMIT_CONST_ATOM_OP(JSOP_USESHARP, sharpnum);
  2398.     break;
  2399. #endif /* JS_HAS_SHARP_VARS */
  2400. #endif /* JS_HAS_OBJECT_LITERAL */
  2401.  
  2402.       case TOK_LP:
  2403.     if (!Expr(cx, ts, cg))
  2404.         return JS_FALSE;
  2405.     /* (balance: */
  2406.     MUST_MATCH_TOKEN(TOK_RP, "missing ) in parenthetical");
  2407.  
  2408.     /* Emit an annotated NOP so we can decompile user parens. */
  2409.     if (js_NewSrcNote(cx, cg, SRC_PAREN) < 0 ||
  2410.         js_Emit1(cx, cg, JSOP_NOP) < 0) {
  2411.         return JS_FALSE;
  2412.     }
  2413.     break;
  2414.  
  2415.       case TOK_NAME:
  2416.     atomIndex = js_IndexAtom(cx, ts->token.u.atom, &cg->atomList);
  2417.     EMIT_CONST_ATOM_OP(JSOP_NAME, atomIndex);
  2418.     break;
  2419.  
  2420.       case TOK_NUMBER:
  2421.     return EmitNumberOp(cx, ts->token.u.dval, cg);
  2422.  
  2423.       case TOK_STRING:
  2424.     atomIndex = js_IndexAtom(cx, ts->token.u.atom, &cg->atomList);
  2425.     EMIT_CONST_ATOM_OP(JSOP_STRING, atomIndex);
  2426.     break;
  2427.  
  2428.       case TOK_OBJECT:
  2429.     atomIndex = js_IndexAtom(cx, ts->token.u.atom, &cg->atomList);
  2430.     EMIT_CONST_ATOM_OP(JSOP_OBJECT, atomIndex);
  2431.     break;
  2432.  
  2433.       case TOK_PRIMARY:
  2434.     if (js_Emit1(cx, cg, ts->token.u.op) < 0)
  2435.         return JS_FALSE;
  2436.     break;
  2437.  
  2438. #if !JS_HAS_EXPORT_IMPORT
  2439.       case TOK_EXPORT:
  2440.       case TOK_IMPORT:
  2441. #endif
  2442.       case TOK_RESERVED:
  2443.     js_ReportCompileError(cx, ts, "identifier is a reserved word");
  2444.     return JS_FALSE;
  2445.  
  2446.       case TOK_ERROR:
  2447.     /* The scanner or one of its subroutines reported the error. */
  2448.     return JS_FALSE;
  2449.  
  2450.       default:
  2451.     js_ReportCompileError(cx, ts, "syntax error");
  2452.     return JS_FALSE;
  2453.     }
  2454.     return JS_TRUE;
  2455. }
  2456.