Remove remaining embedded JavaScript support.
[bbaumbach/samba-autobuild/.git] / source4 / lib / appweb / ejs-2.0 / ejs / ejsParser.c
diff --git a/source4/lib/appweb/ejs-2.0/ejs/ejsParser.c b/source4/lib/appweb/ejs-2.0/ejs/ejsParser.c
deleted file mode 100644 (file)
index 9fce6d2..0000000
+++ /dev/null
@@ -1,4514 +0,0 @@
-/*
- *     @file   ejsParser.c
- *     @brief  EJS Parser and Execution 
- */
-/********************************* Copyright **********************************/
-/*
- *     @copy   default.g
- *     
- *     Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
- *     Portions Copyright (c) GoAhead Software, 1995-2000. All Rights Reserved.
- *     
- *     This software is distributed under commercial and open source licenses.
- *     You may use the GPL open source license described below or you may acquire 
- *     a commercial license from Mbedthis Software. You agree to be fully bound 
- *     by the terms of either license. Consult the LICENSE.TXT distributed with 
- *     this software for full details.
- *     
- *     This software is open source; you can redistribute it and/or modify it 
- *     under the terms of the GNU General Public License as published by the 
- *     Free Software Foundation; either version 2 of the License, or (at your 
- *     option) any later version. See the GNU General Public License for more 
- *     details at: http://www.mbedthis.com/downloads/gplLicense.html
- *     
- *     This program is distributed WITHOUT ANY WARRANTY; without even the 
- *     implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
- *     
- *     This GPL license does NOT permit incorporating this software into 
- *     proprietary programs. If you are unable to comply with the GPL, you must
- *     acquire a commercial license to use this software. Commercial licenses 
- *     for this software and support services are available from Mbedthis 
- *     Software at http://www.mbedthis.com 
- *     
- *     @end
- */
-
-/********************************** Includes **********************************/
-
-#include       "ejs.h"
-
-#if BLD_FEATURE_EJS
-
-/****************************** Forward Declarations **************************/
-
-static int             createClass(Ejs *ep, EjsVar *parentClass, 
-                                       const char *className, EjsVar *baseClass);
-static int             createProperty(Ejs *ep, EjsVar **obj, const char *id, 
-                                       int state);
-static int             evalCond(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs);
-static int             evalExpr(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs);
-#if BLD_FEATURE_FLOATING_POINT
-static int             evalFloatExpr(Ejs *ep, double l, int rel, double r);
-#endif 
-static int             evalBoolExpr(Ejs *ep, int l, int rel, int r);
-static int             evalNumericExpr(Ejs *ep, EjsNum l, int rel, EjsNum r);
-static int             evalObjExpr(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs) ;
-static int             evalStringExpr(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs);
-static int             evalMethod(Ejs *ep, EjsVar *obj, EjsProc *proc, int flags);
-static EjsProperty *findProperty(Ejs *ep, EjsVar *op, const char *property, 
-                                       int flags);
-static EjsVar  *pickSpace(Ejs *ep, int state, const char *property, int flags);
-static void            freeProc(Ejs *ep, EjsProc *proc);
-static int             parseArgs(Ejs *ep, int state, int flags);
-static int             parseArrayLiteral(Ejs *ep, int state, int flags, char *id);
-static int             parseAssignment(Ejs *ep, int state, int flags, char *id);
-static int             parseClass(Ejs *ep, int state, int flags);
-static int             parseForInner(Ejs *ep, int state, int flags, 
-                                       EjsInput *condScript, EjsInput *incrScript, 
-                                       EjsInput *bodyScript, EjsInput *endScript);
-static int             parseCond(Ejs *ep, int state, int flags);
-static int             parseDeclaration(Ejs *ep, int state, int flags);
-static int             parseExpr(Ejs *ep, int state, int flags);
-static int             parseFor(Ejs *ep, int state, int flags);
-static int             parseRegFor(Ejs *ep, int state, int flags);
-static int             parseForIn(Ejs *ep, int state, int flags, int each);
-static int             parseId(Ejs *ep, int state, int flags, char **id, int *done);
-static int             parseInc(Ejs *ep, int state, int flags);
-static int             parseIf(Ejs *ep, int state, int flags, int *done);
-static int             parseFunction(Ejs *ep, int state, int flags);
-static int             parseMethod(Ejs *ep, int state, int flags, char *id);
-static int             parseObjectLiteral(Ejs *ep, int state, int flags, char *id);
-static int             parseStmt(Ejs *ep, int state, int flags);
-static int             parseThrow(Ejs *ep, int state, int flags);
-static int             parseTry(Ejs *ep, int state, int flags);
-static void    removeNewlines(Ejs *ep, int state);
-static EjsProperty *searchSpacesForProperty(Ejs *ep, int state, EjsVar *obj, 
-                                       char *property, int flags);
-static int             assignPropertyValue(Ejs *ep, char *id, int state, EjsVar *value,
-                                       int flags);
-static int             updateProperty(Ejs *ep, EjsVar *obj, const char *id, int state,
-                                       EjsVar *value);
-static void    updateResult(Ejs *ep, int state, int flags, EjsVar *vp);
-static int             getNextNonSpaceToken(Ejs *ep, int state);
-
-static int             callConstructor(Ejs *ep, EjsVar *thisObj, EjsVar *baseClass, 
-                                       MprArray *args);
-static int             callCMethod(Ejs *ep, EjsVar *obj, EjsProc *proc,
-                                       EjsVar *prototype);
-static int             callStringCMethod(Ejs *ep, EjsVar *obj, EjsProc *proc,
-                                       EjsVar *prototype);
-static int             callMethod(Ejs *ep, EjsVar *obj, EjsProc *proc,
-                                       EjsVar *prototype);
-static int             runMethod(Ejs *ep, EjsVar *thisObj, EjsVar *method, 
-                                       const char *methodName, MprArray *args);
-
-static EjsInput *getInputStruct(Ejs *ep);
-static void    freeInputStruct(Ejs *ep, EjsInput *input);
-
-static void    *pushFrame(Ejs *ep, int size);
-static void    *popFrame(Ejs *ep, int size);
-
-/************************************* Code ***********************************/
-/*
- *     Recursive descent parser for EJS
- */
-
-int ejsParse(Ejs *ep, int state, int flags)
-{
-       mprAssert(ep);
-
-#if MOB
-       if (mprStackCheck(ep)) {
-               char    *stack;
-               stack = ejsFormatStack(ep);
-               mprLog(ep, 0, "\nStack grew : MAX %d\n", mprStackSize(ep));
-               mprLog(ep, 0, "Stack\n %s\n", stack);
-               mprFree(stack);
-       }
-#endif
-
-       if (ep->flags & EJS_FLAGS_EXIT) {
-               return EJS_STATE_RET;
-       }
-
-       ep->inputMarker = ep->input->scriptServp;
-
-       switch (state) {
-       /*
-        *      Any statement, method arguments or conditional expressions
-        */
-       case EJS_STATE_STMT:
-               state = parseStmt(ep, state, flags);
-               if (state != EJS_STATE_STMT_BLOCK_DONE && state != EJS_STATE_STMT_DONE){
-                       goto err;
-               }
-               break;
-
-       case EJS_STATE_DEC:
-               state = parseStmt(ep, state, flags);
-               if (state != EJS_STATE_DEC_DONE) {
-                       goto err;
-               }
-               break;
-
-       case EJS_STATE_EXPR:
-               state = parseStmt(ep, state, flags);
-               if (state != EJS_STATE_EXPR_DONE) {
-                       goto err;
-               }
-               break;
-
-       /*
-        *      Variable declaration list
-        */
-       case EJS_STATE_DEC_LIST:
-               state = parseDeclaration(ep, state, flags);
-               if (state != EJS_STATE_DEC_LIST_DONE) {
-                       goto err;
-               }
-               break;
-
-       /*
-        *      Method argument string
-        */
-       case EJS_STATE_ARG_LIST:
-               state = parseArgs(ep, state, flags);
-               if (state != EJS_STATE_ARG_LIST_DONE) {
-                       goto err;
-               }
-               break;
-
-       /*
-        *      Logical condition list (relational operations separated by &&, ||)
-        */
-       case EJS_STATE_COND:
-               state = parseCond(ep, state, flags);
-               if (state != EJS_STATE_COND_DONE) {
-                       goto err;
-               }
-               break;
-
-       /*
-        *      Expression list
-        */
-       case EJS_STATE_RELEXP:
-               state = parseExpr(ep, state, flags);
-               if (state != EJS_STATE_RELEXP_DONE) {
-                       goto err;
-               }
-               break;
-       }
-
-       /*
-        *      Recursion protection
-        */
-       if (ep->input->scriptServp == ep->inputMarker) {
-               if (ep->recurseCount++ > 20) {
-                       ejsSyntaxError(ep, "Input syntax error");
-                       state = EJS_STATE_ERR;
-               }
-       } else {
-               ep->recurseCount = 0;
-       }
-
-       if (state == EJS_STATE_RET || state == EJS_STATE_EOF) {
-               return state;
-       }
-
-done:
-       return state;
-
-err:
-       if (state == EJS_STATE_RET || state == EJS_STATE_EOF) {
-               goto done;
-       }
-       if (state != EJS_STATE_ERR) {
-               ejsSyntaxError(ep, 0);
-       }
-       state = EJS_STATE_ERR;
-       goto done;
-}
-
-/******************************************************************************/
-/*
- *     Local vars 
- */
-
-typedef struct ParseStmt {
-       EjsProc         *saveProc;
-       EjsProperty     *pp;
-       EjsVar          *saveObj, *exception;
-       char            *str, *id;
-       int                     done, tid, rs, saveObjPerm, expectEndOfStmt;
-} ParseStmt;
-
-/*
- *     Parse expression (leftHandSide operator rightHandSide)
- */
-
-
-static int parseStmt(Ejs *ep, int state, int flags)
-{
-       ParseStmt               *sp;
-
-       mprAssert(ep);
-
-       if ((sp = pushFrame(ep, sizeof(ParseStmt))) == 0) {
-               return EJS_STATE_ERR;
-       }
-
-       sp->id = 0;
-       sp->expectEndOfStmt = 0;
-       sp->saveProc = NULL;
-
-       ep->currentObj = 0;
-       ep->currentProperty = 0;
-
-       for (sp->done = 0; !sp->done && state != EJS_STATE_ERR; ) {
-               sp->tid = ejsLexGetToken(ep, state);
-
-#if (WIN || BREW_SIMULATOR) && BLD_DEBUG && DISABLED
-               /* MOB -- make cross platform */
-               _CrtCheckMemory();
-#endif
-
-               switch (sp->tid) {
-               default:
-                       ejsLexPutbackToken(ep, sp->tid, ep->token);
-                       goto done;
-
-               case EJS_TOK_EXPR:
-                       if (state == EJS_STATE_EXPR) {
-                               ejsLexPutbackToken(ep, EJS_TOK_EXPR, ep->token);
-                       }
-                       goto done;
-
-               case EJS_TOK_LOGICAL:
-                       ejsLexPutbackToken(ep, sp->tid, ep->token);
-                       goto done;
-
-               case EJS_TOK_ERR:
-                       if (state != EJS_STATE_ERR && !ep->gotException) {
-                               ejsSyntaxError(ep, 0);
-                       }
-                       state = EJS_STATE_ERR;
-                       goto done;
-
-               case EJS_TOK_EOF:
-                       state = EJS_STATE_EOF;
-                       goto done;
-
-               case EJS_TOK_NEWLINE:
-                       break;
-
-               case EJS_TOK_SEMI:
-                       /*
-                        *      This case is when we discover no statement and just a lone ';'
-                        */
-                       if (state != EJS_STATE_STMT) {
-                               ejsLexPutbackToken(ep, sp->tid, ep->token);
-                       }
-                       goto done;
-
-               case EJS_TOK_LBRACKET:
-                       if (flags & EJS_FLAGS_EXE) {
-                               ep->currentObj = &ep->currentProperty->var;
-                               if (ep->currentObj != 0 && ep->currentObj->type != 
-                                               EJS_TYPE_OBJECT) {
-                                       ejsError(ep, EJS_REFERENCE_ERROR,
-                                               "Property reference to a non-object type \"%s\"\n", 
-                                               sp->id);
-                                       goto err;
-                               }
-                       }
-
-                       sp->saveObj = ep->currentObj;
-                       sp->saveObjPerm = ejsMakeObjPermanent(sp->saveObj, 1);
-
-                       sp->rs = ejsParse(ep, EJS_STATE_RELEXP, flags);
-
-                       ejsMakeObjPermanent(sp->saveObj, sp->saveObjPerm);
-                       ep->currentObj = sp->saveObj;
-
-                       if (sp->rs < 0) {
-                               state = sp->rs;
-                               goto done;
-                       }
-
-                       mprFree(sp->id);
-                       /* MOB rc */
-                       sp->str = ejsVarToString(ep, ep->result);
-                       sp->id = mprStrdup(ep, sp->str);
-
-                       if (sp->id[0] == '\0') {
-                               if (flags & EJS_FLAGS_EXE) {
-                                       ejsError(ep, EJS_RANGE_ERROR,
-                                               "[] expression evaluates to the empty string\n");
-                                       goto err;
-                               }
-                       } else {
-                               sp->pp = searchSpacesForProperty(ep, state, ep->currentObj, 
-                                       sp->id, flags);
-                               ep->currentProperty = sp->pp;
-                               updateResult(ep, state, flags, ejsGetVarPtr(sp->pp));
-                       }
-
-                       if ((sp->tid = ejsLexGetToken(ep, state)) != EJS_TOK_RBRACKET) {
-                               ejsSyntaxError(ep, "Missing ']'");
-                               goto err;
-                       }
-                       break;
-
-               case EJS_TOK_PERIOD:
-                       if (flags & EJS_FLAGS_EXE) {
-                               if (ep->currentProperty == 0) {
-                                       ejsError(ep, EJS_REFERENCE_ERROR,
-                                               "Undefined object \"%s\"", sp->id);
-                                       goto err;
-                               }
-                       }
-                       ep->currentObj = &ep->currentProperty->var;
-                       if (flags & EJS_FLAGS_EXE) {
-                               if (ep->currentObj != 0 && ep->currentObj->type != 
-                                               EJS_TYPE_OBJECT) {
-                                       ejsError(ep, EJS_REFERENCE_ERROR,
-                                               "Property reference to a non-object type \"%s\"\n",
-                                               sp->id);
-                                       goto err;
-                               }
-                       }
-                       if ((sp->tid = ejsLexGetToken(ep, state)) != EJS_TOK_ID) {
-                               ejsError(ep, EJS_REFERENCE_ERROR, "Bad property after '.': %s", 
-                                       ep->token);
-                               goto err;
-                       }
-                       /* Fall through */
-
-               case EJS_TOK_ID:
-                       state = parseId(ep, state, flags, &sp->id, &sp->done);
-                       if (sp->done && state == EJS_STATE_STMT) {
-                               sp->expectEndOfStmt = 1;
-                       }
-                       break;
-
-               case EJS_TOK_ASSIGNMENT:
-                       sp->tid = ejsLexGetToken(ep, state);
-                       if (sp->tid == EJS_TOK_LBRACE) {
-                               /* 
-                                *      var = { name: value, name: value, ... } 
-                                */
-                               if (parseObjectLiteral(ep, state, flags, sp->id) < 0) {
-                                       ejsSyntaxError(ep, "Bad object literal");
-                                       goto err;
-                               }
-
-                       } else if (sp->tid == EJS_TOK_LBRACKET) {
-                               /* 
-                                *      var = [ array elements ] 
-                                */
-                               if (parseArrayLiteral(ep, state, flags, sp->id) < 0) {
-                                       ejsSyntaxError(ep, "Bad array literal");
-                                       goto err;
-                               }
-
-                       } else if (sp->tid == EJS_TOK_EXPR && 
-                                       (int) *ep->token == EJS_EXPR_LESS) {
-                               /* 
-                                *      var = <xmlTag> .../</xmlTag>
-                                */
-                               ejsSyntaxError(ep, "XML literals are not yet supported");
-                               goto err;
-
-                       } else {
-                               /* 
-                                *      var = expression
-                                */
-                               ejsLexPutbackToken(ep, sp->tid, ep->token);
-                               state = parseAssignment(ep, state, flags, sp->id);
-                               if (state == EJS_STATE_ERR) {
-                                       if (ep->flags & EJS_FLAGS_EXIT) {
-                                               state = EJS_STATE_RET;
-                                               goto done;
-                                       }
-                                       if (!ep->gotException) {
-                                               ejsSyntaxError(ep, 0);
-                                       }
-                                       goto err;
-                               }
-                       }
-
-                       if (flags & EJS_FLAGS_EXE) {
-                               if (assignPropertyValue(ep, sp->id, state, ep->result, 
-                                                       flags) < 0) {
-                                       if (ep->gotException == 0) {
-                                               ejsError(ep, EJS_EVAL_ERROR, "Can't set property %s", 
-                                                       sp->id);
-                                       }
-                                       goto err;
-                               }
-                       }
-
-                       if (state == EJS_STATE_STMT) {
-                               sp->expectEndOfStmt = 1;
-                               goto done;
-                       }
-                       break;
-
-               case EJS_TOK_INC_DEC:
-                       state = parseInc(ep, state, flags);
-                       if (state == EJS_STATE_STMT) {
-                               sp->expectEndOfStmt = 1;
-                       }
-                       break;
-
-               case EJS_TOK_NEW:
-                       /* MOB -- could we remove rs and just use state */
-                       sp->rs = ejsParse(ep, EJS_STATE_EXPR, flags | EJS_FLAGS_NEW);
-                       if (sp->rs < 0) {
-                               state = sp->rs;
-                               goto done;
-                       }
-                       break;
-
-               case EJS_TOK_DELETE:
-                       sp->rs = ejsParse(ep, EJS_STATE_EXPR, flags | EJS_FLAGS_DELETE);
-                       if (sp->rs < 0) {
-                               state = sp->rs;
-                               goto done;
-                       }
-                       if (flags & EJS_FLAGS_EXE) {
-                               /* Single place where properties are deleted */
-                               if (ep->currentObj == 0 || ep->currentProperty == 0) {
-                                       ejsError(ep, EJS_EVAL_ERROR, 
-                                               "Can't find property to delete"); 
-                                       goto err;
-                               }
-                               if (ep->currentObj->isArray) {
-                                       ejsSetArrayLength(ep, ep->currentObj, 0, 
-                                               ep->currentProperty->name, 0);
-                               }
-                               ejsDeleteProperty(ep, ep->currentObj, 
-                                       ep->currentProperty->name);
-                               ep->currentProperty = 0;
-                       }
-                       goto done;
-
-               case EJS_TOK_FUNCTION:
-                       /*
-                        *      Parse a function declaration 
-                        */
-                       state = parseFunction(ep, state, flags);
-                       goto done;
-
-               case EJS_TOK_THROW:
-                       state = parseThrow(ep, state, flags);
-                       goto done;
-
-               case EJS_TOK_TRY:
-                       state = parseTry(ep, state, flags);
-                       goto done;
-
-               case EJS_TOK_CLASS:
-               case EJS_TOK_MODULE:
-                       state = parseClass(ep, state, flags);
-                       goto done;
-
-               case EJS_TOK_LITERAL:
-                       /*
-                        *      Set the result to the string literal 
-                        */
-                       if (flags & EJS_FLAGS_EXE) {
-                               ejsWriteVarAsString(ep, ep->result, ep->token);
-                               ejsSetVarName(ep, ep->result, "");
-                       }
-                       if (state == EJS_STATE_STMT) {
-                               sp->expectEndOfStmt = 1;
-                       }
-                       goto done;
-
-               case EJS_TOK_NUMBER:
-                       /*
-                        *      Set the result to the parsed number
-                        */
-                       if (flags & EJS_FLAGS_EXE) {
-                               ejsWriteVar(ep, ep->result, &ep->tokenNumber, 0);
-                       }
-                       if (state == EJS_STATE_STMT) {
-                               sp->expectEndOfStmt = 1;
-                       }
-                       goto done;
-
-               case EJS_TOK_METHOD_NAME:
-                       /*
-                        *      parse a method() invocation
-                        */
-                       mprAssert(ep->currentObj);
-                       state = parseMethod(ep, state, flags, sp->id);
-                       if (state == EJS_STATE_STMT) {
-                               sp->expectEndOfStmt = 1;
-                       }
-                       if (ep->flags & EJS_FLAGS_EXIT) {
-                               state = EJS_STATE_RET;
-                       }
-                       goto done;
-
-               case EJS_TOK_IF:
-                       state = parseIf(ep, state, flags, &sp->done);
-                       if (state < 0) {
-                               goto done;
-                       }
-                       break;
-
-               case EJS_TOK_FOR:
-                       state = parseFor(ep, state, flags);
-                       goto done;
-
-               case EJS_TOK_VAR:
-                       if ((sp->rs = ejsParse(ep, EJS_STATE_DEC_LIST, flags)) < 0) {
-                               state = sp->rs;
-                               goto done;
-                       }
-                       goto done;
-
-               case EJS_TOK_COMMA:
-                       ejsLexPutbackToken(ep, sp->tid, ep->token);
-                       goto done;
-
-               case EJS_TOK_LPAREN:
-                       if (state == EJS_STATE_EXPR) {
-                               if ((sp->rs = ejsParse(ep, EJS_STATE_RELEXP, flags)) < 0) {
-                                       state = sp->rs;
-                                       goto done;
-                               }
-                               if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) {
-                                       ejsSyntaxError(ep, 0);
-                                       goto err;
-                               }
-                               goto done;
-
-                       } else if (state == EJS_STATE_STMT) {
-                               ejsLexPutbackToken(ep, EJS_TOK_METHOD_NAME, ep->token);
-                       }
-                       break;
-
-               case EJS_TOK_RPAREN:
-                       ejsLexPutbackToken(ep, sp->tid, ep->token);
-                       goto done;
-
-               case EJS_TOK_EXTENDS:
-                       if (! (flags & EJS_FLAGS_CLASS_DEC)) {
-                               ejsSyntaxError(ep, 0);
-                               goto err;
-                       }
-                       sp->saveObj = ep->currentObj;
-                       sp->saveObjPerm = ejsMakeObjPermanent(sp->saveObj, 1);
-                       
-                       sp->rs = ejsParse(ep, EJS_STATE_STMT, flags);
-                       ejsMakeObjPermanent(sp->saveObj, sp->saveObjPerm);
-
-                       if (sp->rs < 0) {
-                               state = sp->rs;
-                               goto done;
-                       }
-
-                       if (flags & EJS_FLAGS_EXE) {
-                               if (createClass(ep, sp->saveObj, sp->id, 
-                                               ejsGetVarPtr(ep->currentProperty)) < 0) {
-                                       goto err;
-                               }
-                       }
-                       if (ejsLexGetToken(ep, state) != EJS_TOK_LBRACE) {
-                               ejsSyntaxError(ep, 0);
-                               goto err;
-                       }
-                       ejsLexPutbackToken(ep, ep->tid, ep->token);
-                       goto done;
-
-               case EJS_TOK_LBRACE:
-                       if (flags & EJS_FLAGS_CLASS_DEC) {
-                               if (state == EJS_STATE_DEC) {
-                                       if (flags & EJS_FLAGS_EXE) {
-                                               if (createClass(ep, ep->currentObj, sp->id, 0) < 0) {
-                                                       goto err;
-                                               }
-                                       }
-                                       ejsLexPutbackToken(ep, sp->tid, ep->token);
-
-                               } else if (state == EJS_STATE_STMT) {
-                                       ejsLexPutbackToken(ep, sp->tid, ep->token);
-                               }
-                               goto done;
-                       }
-
-                       /*
-                        *      This handles any code in braces except "if () {} else {}"
-                        */
-                       if (state != EJS_STATE_STMT) {
-                               ejsSyntaxError(ep, 0);
-                               goto err;
-                       }
-
-                       /*
-                        *      Parse will return EJS_STATE_STMT_BLOCK_DONE when the RBRACE 
-                        *      is seen.
-                        */
-                       sp->exception = 0;
-                       do {
-                               state = ejsParse(ep, EJS_STATE_STMT, flags);
-                               if (state == EJS_STATE_ERR) {
-                                       /*
-                                        *      We need to keep parsing to get to the end of the block
-                                        */
-                                       if (sp->exception == 0) {
-                                               sp->exception = ejsDupVar(ep, ep->result, 
-                                                               EJS_SHALLOW_COPY);
-                                               if (sp->exception == 0) {
-                                                       ejsMemoryError(ep);
-                                                       goto err;
-                                               }
-                                               if (sp->exception->type == EJS_TYPE_OBJECT) {
-                                                       ejsMakeObjLive(sp->exception, 0);
-                                                       mprAssert(sp->exception->objectState->alive == 0);
-                                               }
-
-                                               /*
-                                                *      If we're in a try block, we need to keep parsing
-                                                *      so we can find the end of the block and the start
-                                                *      of the catch block. Otherwise, we are done.
-                                                */
-                                               if (!(flags & EJS_FLAGS_TRY)) {
-                                                       break;
-                                               }
-                                       }
-                                       flags &= ~EJS_FLAGS_EXE;
-                                       if (ep->recurseCount > 20) {
-                                               break;
-                                       }
-                                       state = EJS_STATE_STMT_DONE;
-                                       ep->gotException = 0;
-                               }
-
-                       } while (state == EJS_STATE_STMT_DONE);
-
-                       if (sp->exception) {
-                               ep->gotException = 1;
-                               ejsWriteVar(ep, ep->result, sp->exception, EJS_SHALLOW_COPY);
-
-                               /* Eat the closing brace */
-                               ejsLexGetToken(ep, state);
-                               ejsFreeVar(ep, sp->exception);
-
-                               goto err;
-                       }
-                       ejsFreeVar(ep, sp->exception);
-
-                       if (state < 0) {
-                               goto done;
-                       }
-
-                       if (ejsLexGetToken(ep, state) != EJS_TOK_RBRACE) {
-                               ejsSyntaxError(ep, 0);
-                               goto err;
-                       }
-                       state = EJS_STATE_STMT_DONE;
-                       goto done;
-
-               case EJS_TOK_RBRACE:
-                       if (state == EJS_STATE_STMT) {
-                               ejsLexPutbackToken(ep, sp->tid, ep->token);
-                               state = EJS_STATE_STMT_BLOCK_DONE;
-                               
-                       } else if (state == EJS_STATE_EXPR) {
-                               ejsLexPutbackToken(ep, sp->tid, ep->token);
-                               state = EJS_STATE_EXPR;
-
-                       } else {
-                               ejsSyntaxError(ep, 0);
-                               state = EJS_STATE_ERR;
-                       }
-                       goto done;
-
-               case EJS_TOK_RETURN:
-                       if ((sp->rs = ejsParse(ep, EJS_STATE_RELEXP, flags)) < 0) {
-                               state = sp->rs;
-                               goto done;
-                       }
-                       if (flags & EJS_FLAGS_EXE) {
-                               state = EJS_STATE_RET;
-                               goto done;
-                       }
-                       break;
-               }
-       }
-done:
-       mprFree(sp->id);
-
-       if (sp->expectEndOfStmt && state >= 0) {
-               sp->tid = ejsLexGetToken(ep, state);
-               if (sp->tid == EJS_TOK_RBRACE) {
-                       ejsLexPutbackToken(ep, EJS_TOK_RBRACE, ep->token);
-
-               } else if (sp->tid != EJS_TOK_SEMI && sp->tid != EJS_TOK_NEWLINE && 
-                               sp->tid != EJS_TOK_EOF) {
-                       ejsSyntaxError(ep, 0);
-                       state = EJS_STATE_ERR;
-
-               } else {
-                       /*
-                        *      Skip newlines after semi-colon
-                        */
-                       removeNewlines(ep, state);
-               }
-       }
-
-       /*
-        *      Advance the state
-        */
-       switch (state) {
-       case EJS_STATE_STMT:
-       case EJS_STATE_STMT_DONE:
-               state = EJS_STATE_STMT_DONE;
-               break;
-
-       case EJS_STATE_DEC:
-       case EJS_STATE_DEC_DONE:
-               state = EJS_STATE_DEC_DONE;
-               break;
-
-       case EJS_STATE_EXPR:
-       case EJS_STATE_EXPR_DONE:
-               state = EJS_STATE_EXPR_DONE;
-               break;
-
-       case EJS_STATE_STMT_BLOCK_DONE:
-       case EJS_STATE_EOF:
-       case EJS_STATE_RET:
-               break;
-
-       default:
-               if (state != EJS_STATE_ERR) {
-                       ejsSyntaxError(ep, 0);
-               }
-               state = EJS_STATE_ERR;
-       }
-       popFrame(ep, sizeof(ParseStmt));
-       return state;
-
-err:
-       state = EJS_STATE_ERR;
-       goto done;
-}
-
-/******************************************************************************/
-/*
- *     Local vars 
- */
-
-typedef struct ParseFor {
-       char            *initToken;
-       int             tid, foundVar, initId, each;
-} ParseFor;
-
-/*
- *     Parse method arguments
- */
-
-static int parseFor(Ejs *ep, int state, int flags)
-{
-       ParseFor                *sp;
-
-       if ((sp = pushFrame(ep, sizeof(ParseFor))) == 0) {
-               return EJS_STATE_ERR;
-       }
-
-       mprAssert(ep);
-
-       if (state != EJS_STATE_STMT) {
-               ejsSyntaxError(ep, 0);
-               goto err;
-       }
-
-       if ((sp->tid = ejsLexGetToken(ep, state)) == EJS_TOK_EACH) {
-               sp->each = 1;
-               sp->tid = ejsLexGetToken(ep, state);
-
-       } else {
-               sp->each = 0;
-       }
-
-       if (sp->tid != EJS_TOK_LPAREN) {
-               ejsSyntaxError(ep, 0);
-               goto err;
-       }
-
-       /*
-        *      Need to peek 2-3 tokens ahead and see if this is a 
-        *              for [each] ([var] x in set) 
-        *      or
-        *              for (init ; whileCond; incr)
-        */
-       sp->initId = ejsLexGetToken(ep, EJS_STATE_EXPR);
-       sp->foundVar = 0;
-       if (sp->initId == EJS_TOK_ID && strcmp(ep->token, "var") == 0) {
-               sp->foundVar = 1;
-               sp->initId = ejsLexGetToken(ep, EJS_STATE_EXPR);
-       }
-       sp->initToken = mprStrdup(ep, ep->token);
-
-       sp->tid = ejsLexGetToken(ep, EJS_STATE_EXPR);
-
-       ejsLexPutbackToken(ep, sp->tid, ep->token);
-       ejsLexPutbackToken(ep, sp->initId, sp->initToken);
-       mprFree(sp->initToken);
-
-       if (sp->foundVar) {
-               ejsLexPutbackToken(ep, EJS_TOK_ID, "var");
-       }
-
-       if (sp->tid == EJS_TOK_IN) {
-               state = parseForIn(ep, state, flags, sp->each);
-
-       } else {
-               state = parseRegFor(ep, state, flags);
-       }
-
-done:
-       popFrame(ep, sizeof(ParseFor));
-       return state;
-
-err:
-       state = EJS_STATE_ERR;
-       goto done;
-}
-
-/******************************************************************************/
-/*
- *     Parse method arguments
- */
-
-static int parseArgs(Ejs *ep, int state, int flags)
-{
-       EjsVar          *vp;
-       int                     tid;
-
-       mprAssert(ep);
-
-       do {
-               /*
-                *      Peek and see if there are no args
-                */
-               tid = ejsLexGetToken(ep, state);
-               ejsLexPutbackToken(ep, tid, ep->token);
-               if (tid == EJS_TOK_RPAREN) {
-                       break;
-               }
-
-               /*
-                *      If this is part of a constructor, must run methods in args normally 
-                */
-               flags &= ~EJS_FLAGS_NEW;
-
-               state = ejsParse(ep, EJS_STATE_RELEXP, flags);
-               if (state < 0) {
-                       return state;
-               }
-               if (flags & EJS_FLAGS_EXE) {
-                       mprAssert(ep->proc->args);
-                       vp = ejsDupVar(ep, ep->result, EJS_SHALLOW_COPY);
-                       if (vp == 0) {
-                               ejsMemoryError(ep);
-                               return EJS_STATE_ERR;
-                       }
-                       /* MOB */
-                       if (vp->type == EJS_TYPE_OBJECT) {
-                               ejsMakeObjLive(vp, 0);
-                               mprAssert(vp->objectState->alive == 0);
-                       }
-
-                       /*
-                        *      Propagate the name
-                        */
-                       ejsSetVarName(ep, vp, ep->result->propertyName);
-
-                       mprAddItem(ep->proc->args, vp);
-
-               }
-               /*
-                *      Peek at the next token, continue if more args (ie. comma seen)
-                */
-               tid = ejsLexGetToken(ep, state);
-               if (tid != EJS_TOK_COMMA) {
-                       ejsLexPutbackToken(ep, tid, ep->token);
-               }
-       } while (tid == EJS_TOK_COMMA);
-
-       if (tid != EJS_TOK_RPAREN && state != EJS_STATE_RELEXP_DONE) {
-               ejsSyntaxError(ep, 0);
-               return EJS_STATE_ERR;
-       }
-       return EJS_STATE_ARG_LIST_DONE;
-}
-
-/******************************************************************************/
-/*
- *     Local vars 
- */
-
-typedef struct ParseAssign {
-       EjsProperty             *saveProperty;
-       EjsVar                  *saveObj;
-       int                             saveObjPerm, savePropPerm, rc;
-} ParseAssign;
-
-/*
- *     Parse an assignment statement
- */
-
-static int parseAssignment(Ejs *ep, int state, int flags, char *id)
-{
-       ParseAssign             *sp;
-
-
-       if (id == 0) {
-               if (!ep->gotException) {
-                       ejsSyntaxError(ep, 0);
-               }
-               return EJS_STATE_ERR;
-       }
-
-       if ((sp = pushFrame(ep, sizeof(ParseAssign))) == 0) {
-               return EJS_STATE_ERR;
-       }
-
-       mprAssert(ep->currentObj);
-
-       /*
-        *      Parse the right hand side of the "="
-        */
-       sp->saveObj = ep->currentObj;
-       sp->saveProperty = ep->currentProperty;
-
-       sp->saveObjPerm = ejsMakeObjPermanent(sp->saveObj, 1);
-       sp->savePropPerm = ejsMakeObjPermanent(ejsGetVarPtr(sp->saveProperty), 1);
-
-       sp->rc = ejsParse(ep, EJS_STATE_RELEXP, flags | EJS_FLAGS_ASSIGNMENT);
-       
-       ejsMakeObjPermanent(sp->saveObj, sp->saveObjPerm);
-       ejsMakeObjPermanent(ejsGetVarPtr(sp->saveProperty), sp->savePropPerm);
-
-       if (sp->rc < 0) {
-               state = EJS_STATE_ERR;
-       }
-
-       ep->currentObj = sp->saveObj;
-       ep->currentProperty = sp->saveProperty;
-
-       popFrame(ep, sizeof(ParseAssign));
-
-       if (! (flags & EJS_FLAGS_EXE)) {
-               return state;
-       }
-
-       return state;
-}
-
-/******************************************************************************/
-
-static int assignPropertyValue(Ejs *ep, char *id, int state, EjsVar *value, 
-       int flags)
-{
-       EjsProperty             *saveProperty;
-       EjsVar                  *saveObj, *obj, *vp;
-       char                    *procName;
-       int                             saveObjPerm, savePropPerm, rc;
-
-       mprAssert(flags & EJS_FLAGS_EXE);
-
-       if (ep->currentProperty && 
-                       !ep->currentProperty->var.flags & EJS_GET_ACCESSOR) {
-               obj = ep->currentObj;
-
-       } else {
-               /*
-                *      Handle any set accessors.
-                *      FUTURE OPT -- could be faster
-                *      FUTURE OPT -- coming here even when doing just a set "x = value";
-                */
-               procName = 0;
-               if (mprAllocStrcat(MPR_LOC_ARGS(ep), &procName, EJS_MAX_ID + 5, 0, 
-                               "-set-", id, 0) > 0) {
-
-                       MprArray        *args;
-
-                       ep->currentProperty = searchSpacesForProperty(ep, state, 
-                               ep->currentObj, procName, flags);
-
-                       if (ep->currentProperty) {
-                               args = mprCreateItemArray(ep, EJS_INC_ARGS, EJS_MAX_ARGS);
-
-                               vp = ejsDupVar(ep, value, EJS_SHALLOW_COPY);
-                               mprAddItem(args, vp);
-                               mprAssert(! ejsObjIsCollectable(vp));
-
-                               saveObj = ep->currentObj;
-                               saveProperty = ep->currentProperty;
-
-                               saveObjPerm = ejsMakeObjPermanent(saveObj, 1);
-                               savePropPerm = ejsMakeObjPermanent(ejsGetVarPtr(saveProperty), 
-                                       1);
-
-                               /*
-                                *      Invoke the set accessor
-                                */
-                               rc = ejsRunMethod(ep, ep->currentObj, procName, args);
-                               mprFree(procName);
-                               ejsFreeMethodArgs(ep, args);
-
-                               ejsMakeObjPermanent(saveObj, saveObjPerm);
-                               ejsMakeObjPermanent(ejsGetVarPtr(saveProperty), savePropPerm);
-
-                               ep->currentObj = saveObj;
-                               ep->currentProperty = saveProperty;
-
-                               if (rc < 0) {
-                                       return EJS_STATE_ERR;
-                               }
-                               return state;
-                       }
-                       mprFree(procName);
-               }
-
-               if (ep->currentProperty == 0) {
-                       /*
-                        *      MOB -- can we omit this as updateProperty below will create
-                        */
-                       if (createProperty(ep, &obj, id, state) < 0) {
-                               return EJS_STATE_ERR;
-                       }
-               }
-       }
-
-       if (updateProperty(ep, obj, id, state, value) < 0) {
-               return EJS_STATE_ERR;
-       }
-
-       vp = ejsGetVarPtr(ep->currentProperty);
-       if (vp->type == EJS_TYPE_OBJECT) {
-               ejsMakeObjLive(vp, 1);
-       }
-
-       return state;
-}
-
-/******************************************************************************/
-
-static int parseObjectLiteral(Ejs *ep, int state, int flags, char *id)
-{
-       EjsProperty             *saveProperty;
-       EjsVar                  *saveObj;
-       EjsVar                  *obj;
-       char                    *name;
-       int                             saveObjPerm, savePropPerm, tid;
-
-       name = 0;
-
-       saveObj = ep->currentObj;
-       saveProperty = ep->currentProperty;
-
-       saveObjPerm = ejsMakeObjPermanent(saveObj, 1);
-       savePropPerm = ejsMakeObjPermanent(ejsGetVarPtr(saveProperty), 1);
-
-       if (flags & EJS_FLAGS_EXE) {
-               obj = ejsCreateSimpleObj(ep, "Object");
-               if (obj == 0) {
-                       ejsMemoryError(ep);
-                       goto err;
-               }
-               mprAssert(! ejsObjIsCollectable(obj));
-
-       } else {
-               obj = 0;
-       }
-
-       do {
-               tid = getNextNonSpaceToken(ep, state);
-               if (tid != EJS_TOK_ID) {
-                       ejsSyntaxError(ep, 0);
-                       goto err;
-               }
-               name = mprStrdup(ep, ep->token);
-
-               tid = getNextNonSpaceToken(ep, state);
-               if (tid != EJS_TOK_COLON) {
-                       ejsSyntaxError(ep, 0);
-                       goto err;
-               }
-
-               if (flags & EJS_FLAGS_EXE) {
-                       /* FUTURE OPT -- can we optimize this. We are double accessing id 
-                               with the Put below. Should we be using this or ejsSetProperty
-                        */
-                       if (ejsCreatePropertyMethod(ep, obj, name) == 0) {
-                               ejsMemoryError(ep);
-                               goto err;
-                       }
-               }
-
-               if (ejsParse(ep, EJS_STATE_RELEXP, flags) < 0) {
-                       goto err;
-               }
-               if (flags & EJS_FLAGS_EXE) {
-                       if (ejsSetPropertyMethod(ep, obj, name, ep->result) == 0) {
-                               ejsMemoryError(ep);
-                               goto err;
-                       }
-               }
-               mprFree(name);
-               name = 0;
-
-               tid = getNextNonSpaceToken(ep, state);
-
-       } while (tid == EJS_TOK_COMMA);
-
-       if (tid != EJS_TOK_RBRACE) {
-               ejsSyntaxError(ep, 0);
-               goto err;
-       }
-
-       if (flags & EJS_FLAGS_EXE) {
-               ejsMakeObjLive(obj, 1);
-               ejsWriteVar(ep, ep->result, obj, EJS_SHALLOW_COPY);
-       }
-
-done:
-       ejsMakeObjPermanent(saveObj, saveObjPerm);
-       ejsMakeObjPermanent(ejsGetVarPtr(saveProperty), savePropPerm);
-
-       ep->currentObj = saveObj;
-       ep->currentProperty = saveProperty;
-
-       if (obj) {
-               ejsFreeVar(ep, obj);
-       }
-       return state;
-
-err:
-       mprFree(name);
-       state = EJS_STATE_ERR;
-       goto done;
-}
-
-/******************************************************************************/
-
-static int parseArrayLiteral(Ejs *ep, int state, int flags, char *id)
-{
-       EjsProperty             *saveProperty;
-       EjsVar                  *saveObj;
-       EjsVar                  *obj;
-       int                             saveObjPerm, savePropPerm, tid;
-
-       saveObj = ep->currentObj;
-       saveProperty = ep->currentProperty;
-
-       saveObjPerm = ejsMakeObjPermanent(saveObj, 1);
-       savePropPerm = ejsMakeObjPermanent(ejsGetVarPtr(saveProperty), 1);
-
-       if (flags & EJS_FLAGS_EXE) {
-               obj = ejsCreateArray(ep, 0);
-               if (obj == 0) {
-                       ejsMemoryError(ep);
-                       goto err;
-               }
-               mprAssert(! ejsObjIsCollectable(obj));
-
-       } else {
-               obj = 0;
-       }
-
-       do {
-               if (ejsParse(ep, EJS_STATE_RELEXP, flags) < 0) {
-                       goto err;
-               }
-               if (flags & EJS_FLAGS_EXE) {
-                       /* MOB _- should this be put[array.length] */
-                       if (ejsAddArrayElt(ep, obj, ep->result, EJS_SHALLOW_COPY) == 0) {
-                               goto err;
-                       }
-               }
-
-               tid = getNextNonSpaceToken(ep, state);
-
-       } while (tid == EJS_TOK_COMMA);
-
-       if (tid != EJS_TOK_RBRACKET) {
-               ejsSyntaxError(ep, "Missing right bracket");
-               goto err;
-       }
-
-       if (flags & EJS_FLAGS_EXE) {
-               ejsMakeObjLive(obj, 1);
-               ejsWriteVar(ep, ep->result, obj, EJS_SHALLOW_COPY);
-       }
-
-done:
-       ejsMakeObjPermanent(saveObj, saveObjPerm);
-       ejsMakeObjPermanent(ejsGetVarPtr(saveProperty), savePropPerm);
-
-       ep->currentObj = saveObj;
-       ep->currentProperty = saveProperty;
-
-       ejsFreeVar(ep, obj);
-       return state;
-
-err:
-       state = EJS_STATE_ERR;
-       goto done;
-}
-
-/******************************************************************************/
-/*
- *     Create a property. 
- */
-
-/*
-MOB -- simplify this. Enforce ep->currentObj to be always set.
-Then we can delete this and just call 
-
-       ejsCreatePropertyMethod(ep->currentObj, id);
-*/
-//XX
-static int createProperty(Ejs *ep, EjsVar **objp, const char *id, int state)
-{
-       EjsVar  *obj, *vp;
-
-       mprAssert(id && *id);
-       mprAssert(objp);
-
-       /*
-        *      Determine the variable scope to use for the property.
-        *      Standard says: "var x" means declare locally.
-        *      "x = 2" means declare globally if x is undefined.
-        */
-       if (ep->currentObj) {
-               if (ep->currentObj->type != EJS_TYPE_OBJECT) {
-                       ejsSyntaxError(ep, "Reference is not an object");
-                       return EJS_STATE_ERR;
-               }
-               obj = ep->currentObj;
-
-       } else {
-               /* MOB -- we should never be doing this here. ep->currentObj should
-                       always be set already */
-               obj = (state == EJS_STATE_DEC) ? ep->local : ep->global;
-       }
-       mprAssert(obj);
-
-       vp = ejsCreatePropertyMethod(ep, obj, id);
-       if (vp == 0) {
-               if (!ep->gotException) {
-                       ejsMemoryError(ep);
-               }
-               return EJS_STATE_ERR;
-       }
-
-       *objp = obj;
-       return state;
-}
-
-/******************************************************************************/
-/*
- *     Update a property. 
- *
- *     Return with ep->currentProperty updated to point to the property.
- */
-
-static int updateProperty(Ejs *ep, EjsVar *obj, const char *id, int state,
-       EjsVar *value)
-{
-       EjsVar  *vp;
-
-       /* 
-        *      MOB -- do ready-only check here
-        */
-       vp = ejsSetPropertyMethod(ep, obj, id, value);
-       if (vp == 0) {
-               ejsMemoryError(ep);
-               return EJS_STATE_ERR;
-       }
-       ep->currentProperty = ejsGetPropertyPtr(vp);
-
-       obj->objectState->dirty = 1;
-
-       return state;
-}
-
-/******************************************************************************/
-/*
- *     Local vars 
- */
-
-typedef struct ParseCond {
-       EjsVar          lhs, rhs;
-       int                     tid, operator;
-} ParseCond;
-
-/*
- *     Parse conditional expression (relational ops separated by ||, &&)
- */
-
-static int parseCond(Ejs *ep, int state, int flags)
-{
-       ParseCond               *sp;
-
-       if ((sp = pushFrame(ep, sizeof(ParseCond))) == 0) {
-               return EJS_STATE_ERR;
-       }
-
-       mprAssert(ep);
-
-       if (flags & EJS_FLAGS_EXE) {
-               ejsClearVar(ep, ep->result);
-       }
-
-       sp->lhs.type = sp->rhs.type = EJS_TYPE_UNDEFINED;
-       sp->lhs.objectState = sp->rhs.objectState = 0;
-       sp->lhs.allocatedData = sp->rhs.allocatedData = 0;
-
-       ejsSetVarName(ep, &sp->lhs, "lhs");
-       ejsSetVarName(ep, &sp->rhs, "rhs");
-
-       sp->operator = 0;
-
-       do {
-               /*
-                *      Recurse to handle one side of a conditional. Accumulate the
-                *      left hand side and the final result in ep->result.
-                */
-               state = ejsParse(ep, EJS_STATE_RELEXP, flags);
-               if (state < 0) {
-                       break;
-               }
-
-               if (flags & EJS_FLAGS_EXE) {
-                       if (sp->operator > 0) {
-                               /*
-                                *      FUTURE -- does not do precedence
-                                */ 
-                               ejsWriteVar(ep, &sp->rhs, ep->result, EJS_SHALLOW_COPY);
-                               if (evalCond(ep, &sp->lhs, sp->operator, &sp->rhs) < 0) {
-                                       state = EJS_STATE_ERR;
-                                       break;
-                               }
-                               /* Result left in ep->result */
-                               /* MOB */
-                               if (sp->lhs.type == EJS_TYPE_OBJECT) {
-                                       mprAssert(sp->lhs.objectState->alive == 0);
-                               }
-                               if (sp->rhs.type == EJS_TYPE_OBJECT) {
-                                       mprAssert(sp->rhs.objectState->alive == 0);
-                               }
-                       }
-               }
-
-               sp->tid = ejsLexGetToken(ep, state);
-               if (sp->tid == EJS_TOK_LOGICAL) {
-                       sp->operator = (int) *ep->token;
-
-               } else if (sp->tid == EJS_TOK_RPAREN || sp->tid == EJS_TOK_SEMI) {
-                       ejsLexPutbackToken(ep, sp->tid, ep->token);
-                       state = EJS_STATE_COND_DONE;
-                       break;
-
-               } else {
-                       ejsLexPutbackToken(ep, sp->tid, ep->token);
-               }
-
-               if (flags & EJS_FLAGS_EXE) {
-                       ejsWriteVar(ep, &sp->lhs, ep->result, EJS_SHALLOW_COPY);
-               }
-
-       } while (state == EJS_STATE_RELEXP_DONE);
-
-       ejsClearVar(ep, &sp->lhs);
-       ejsClearVar(ep, &sp->rhs);
-
-       popFrame(ep, sizeof(ParseCond));
-
-       return state;
-}
-
-/******************************************************************************/
-/*
- *     Parse variable declaration list. Declarations can be of the following forms:
- *             var x;
- *             var x, y, z;
- *             var x = 1 + 2 / 3, y = 2 + 4;
- *             var x = { property: value, property: value ... };
- *             var x = [ property: value, property: value ... ];
- *
- *     We set the variable to NULL if there is no associated assignment.
- */
-
-static int parseDeclaration(Ejs *ep, int state, int flags)
-{
-       int             tid;
-
-       mprAssert(ep);
-
-       do {
-               if ((tid = ejsLexGetToken(ep, state)) != EJS_TOK_ID) {
-                       ejsSyntaxError(ep, 0);
-                       return EJS_STATE_ERR;
-               }
-               ejsLexPutbackToken(ep, tid, ep->token);
-
-               /*
-                *      Parse the entire assignment or simple identifier declaration
-                */
-               if (ejsParse(ep, EJS_STATE_DEC, flags) != EJS_STATE_DEC_DONE) {
-                       return EJS_STATE_ERR;
-               }
-
-               /*
-                *      Peek at the next token, continue if comma seen
-                *      Stop on ";" or "in" which is used in a "for (var x in ..."
-                */
-               tid = ejsLexGetToken(ep, state);
-
-               if (tid == EJS_TOK_SEMI) {
-                       return EJS_STATE_DEC_LIST_DONE;
-
-               } else if (tid == EJS_TOK_IN) {
-                       ejsLexPutbackToken(ep, tid, ep->token);
-                       return EJS_STATE_DEC_LIST_DONE;
-
-               } else if (flags & EJS_FLAGS_CLASS_DEC && 
-                               (tid == EJS_TOK_LBRACE || tid == EJS_TOK_EXTENDS)) {
-                       ejsLexPutbackToken(ep, tid, ep->token);
-                       return EJS_STATE_DEC_LIST_DONE;
-
-               } else if (tid == EJS_TOK_RPAREN && flags & EJS_FLAGS_CATCH) {
-                       ejsLexPutbackToken(ep, tid, ep->token);
-                       return EJS_STATE_DEC_LIST_DONE;
-
-               } else if (tid != EJS_TOK_COMMA) {
-                       ejsSyntaxError(ep, 0);
-                       return EJS_STATE_ERR;
-               }
-
-       } while (tid == EJS_TOK_COMMA);
-
-       if (tid != EJS_TOK_SEMI) {
-               ejsSyntaxError(ep, 0);
-               return EJS_STATE_ERR;
-       }
-       return EJS_STATE_DEC_LIST_DONE;
-}
-
-/******************************************************************************/
-/*
- *     Local vars 
- */
-
-typedef struct ParseExpr {
-       EjsVar          lhs, rhs;
-       int                     rel, tid, unaryMinus;
-} ParseExpr;
-
-/*
- *     Parse expression (leftHandSide operator rightHandSide)
- */
-
-static int parseExpr(Ejs *ep, int state, int flags)
-{
-       ParseExpr               *sp;
-
-       mprAssert(ep);
-
-       if ((sp = pushFrame(ep, sizeof(ParseExpr))) == 0) {
-               return EJS_STATE_ERR;
-       }
-
-       if (flags & EJS_FLAGS_EXE) {
-               ejsClearVar(ep, ep->result);
-       }
-
-       sp->lhs.type = sp->rhs.type = EJS_TYPE_UNDEFINED;
-       sp->lhs.objectState = sp->rhs.objectState = 0;
-       sp->lhs.allocatedData = sp->rhs.allocatedData = 0;
-
-       ejsSetVarName(ep, &sp->lhs, "lhs");
-       ejsSetVarName(ep, &sp->rhs, "rhs");
-
-       sp->rel = 0;
-       sp->tid = 0;
-       sp->unaryMinus = 0;
-
-       do {
-               /*
-                *      This loop will handle an entire expression list. We call parse
-                *      to evalutate each term which returns the result in ep->result.
-                */
-               if (sp->tid == EJS_TOK_LOGICAL) {
-                       state = ejsParse(ep, EJS_STATE_RELEXP, flags);
-                       if (state < 0) {
-                               break;
-                       }
-               } else {
-                       sp->tid = ejsLexGetToken(ep, state);
-                       if (sp->tid == EJS_TOK_EXPR && (int) *ep->token == EJS_EXPR_MINUS) {
-                               sp->unaryMinus = 1;
-
-                       } else {
-                               ejsLexPutbackToken(ep, sp->tid, ep->token);
-                       }
-
-                       state = ejsParse(ep, EJS_STATE_EXPR, flags);
-                       if (state < 0) {
-                               break;
-                       }
-               }
-
-               if (flags & EJS_FLAGS_EXE) {
-                       if (sp->unaryMinus) {
-                               switch (ep->result->type) {
-                               default:
-                               case EJS_TYPE_UNDEFINED:
-                               case EJS_TYPE_NULL:
-                               case EJS_TYPE_STRING_CMETHOD:
-                               case EJS_TYPE_CMETHOD:
-                               case EJS_TYPE_METHOD:
-                               case EJS_TYPE_PTR:
-                               case EJS_TYPE_OBJECT:
-                               case EJS_TYPE_STRING:
-                               case EJS_TYPE_BOOL:
-                                       ejsError(ep, EJS_SYNTAX_ERROR, "Invalid unary minus");
-                                       state = EJS_STATE_ERR;
-                                       break;
-
-#if BLD_FEATURE_FLOATING_POINT
-                               case EJS_TYPE_FLOAT:
-                                       ep->result->floating = - ep->result->floating;
-                                       break;
-#endif
-
-                               case EJS_TYPE_INT:
-                                       ep->result->integer = - ep->result->integer;
-                                       break;
-
-#if BLD_FEATURE_INT64
-                               case EJS_TYPE_INT64:
-                                       ep->result->integer64 = - ep->result->integer64;
-                                       break;
-#endif
-                               }
-                       }
-                       sp->unaryMinus = 0;
-
-                       if (sp->rel > 0) {
-                               ejsWriteVar(ep, &sp->rhs, ep->result, EJS_SHALLOW_COPY);
-                               if (sp->tid == EJS_TOK_LOGICAL) {
-                                       if (evalCond(ep, &sp->lhs, sp->rel, &sp->rhs) < 0) {
-                                               state = EJS_STATE_ERR;
-                                               break;
-                                       }
-                               } else {
-                                       if (evalExpr(ep, &sp->lhs, sp->rel, &sp->rhs) < 0) {
-                                               state = EJS_STATE_ERR;
-                                               break;
-                                       }
-                               }
-                       }
-                       /* MOB */
-                       if (sp->lhs.type == EJS_TYPE_OBJECT) {
-                               ejsMakeObjLive(&sp->lhs, 0);
-                               mprAssert(sp->lhs.objectState->alive == 0);
-                       }
-                       if (sp->rhs.type == EJS_TYPE_OBJECT) {
-                               ejsMakeObjLive(&sp->rhs, 0);
-                               mprAssert(sp->rhs.objectState->alive == 0);
-                       }
-               }
-
-               if ((sp->tid = ejsLexGetToken(ep, state)) == EJS_TOK_EXPR ||
-                        sp->tid == EJS_TOK_INC_DEC || sp->tid == EJS_TOK_LOGICAL) {
-                       sp->rel = (int) *ep->token;
-                       ejsWriteVar(ep, &sp->lhs, ep->result, EJS_SHALLOW_COPY);
-
-               } else {
-                       ejsLexPutbackToken(ep, sp->tid, ep->token);
-                       state = EJS_STATE_RELEXP_DONE;
-               }
-
-       } while (state == EJS_STATE_EXPR_DONE);
-
-       ejsClearVar(ep, &sp->lhs);
-       ejsClearVar(ep, &sp->rhs);
-
-       popFrame(ep, sizeof(ParseExpr));
-
-       return state;
-}
-
-/******************************************************************************/
-/*
- *     Local vars
- */
-
-typedef struct ParseForIn {
-       EjsInput                *endScript, *bodyScript;
-       EjsProperty             *pp, *nextp;
-       EjsVar                  *iteratorVar, *setVar, *vp;
-       int                             forFlags, tid;
-} ParseForIn;
-
-/*
- *     Parse the "for ... in" statement. Format for the statement is:
- *
- *             for [each] (var varName in expression) {
- *                     body;
- *             }
- */
-
-static int parseForIn(Ejs *ep, int state, int flags, int each)
-{
-       ParseForIn              *sp;
-
-       mprAssert(ep);
-
-       if ((sp = pushFrame(ep, sizeof(ParseForIn))) == 0) {
-               return EJS_STATE_ERR;
-       }
-
-       sp->setVar = 0;
-       sp->iteratorVar = 0;
-       sp->bodyScript = 0;
-       sp->endScript = 0;
-
-       sp->tid = ejsLexGetToken(ep, state);
-       if (sp->tid != EJS_TOK_ID && sp->tid != EJS_TOK_VAR) {
-               ejsSyntaxError(ep, 0);
-               goto err;
-       }
-       ejsLexPutbackToken(ep, sp->tid, ep->token);
-
-       state = ejsParse(ep, EJS_STATE_EXPR, EJS_FLAGS_FORIN | flags);
-       if (state < 0) {
-               goto done;
-       }
-       if (flags & EJS_FLAGS_EXE) {
-               if (ep->currentProperty == 0) {
-                       ejsSyntaxError(ep, 0);
-                       goto err;
-               }
-               sp->iteratorVar = &ep->currentProperty->var;
-       } else {
-               sp->iteratorVar = 0;
-       }
-       
-       if (ejsLexGetToken(ep, state) != EJS_TOK_IN) {
-               ejsSyntaxError(ep, 0);
-               goto err;
-       }
-
-       /*
-        *      Get the set
-        */
-       sp->tid = ejsLexGetToken(ep, state);
-       if (sp->tid != EJS_TOK_ID) {
-               ejsSyntaxError(ep, 0);
-               goto err;
-       }
-       ejsLexPutbackToken(ep, sp->tid, ep->token);
-
-       state = ejsParse(ep, EJS_STATE_EXPR, flags);
-       if (state < 0) {
-               goto done;
-       }
-
-       if ((flags & EJS_FLAGS_EXE) && 
-                       (ep->result == 0 || ep->result->type == EJS_TYPE_UNDEFINED)) {
-               ejsError(ep, EJS_REFERENCE_ERROR, "Can't access array or object");
-               goto err;
-       }
-       
-       if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) {
-               ejsSyntaxError(ep, 0);
-               goto err;
-       }
-
-       sp->setVar = ejsDupVar(ep, ep->result, EJS_SHALLOW_COPY);
-
-       sp->bodyScript = getInputStruct(ep);
-
-       /*
-        *      Parse the body and remember the end of the body script
-        */
-       sp->forFlags = flags & ~EJS_FLAGS_EXE;
-       ejsLexSaveInputState(ep, sp->bodyScript);
-
-       state = ejsParse(ep, EJS_STATE_STMT, sp->forFlags);
-       if (state < 0) {
-               goto done;
-       }
-
-       sp->endScript = getInputStruct(ep);
-       ejsInitInputState(sp->endScript);
-       ejsLexSaveInputState(ep, sp->endScript);
-
-       /*
-        *      Enumerate the properties
-        */
-       if (flags & EJS_FLAGS_EXE) {
-               if (sp->setVar->type == EJS_TYPE_OBJECT) {
-
-                       sp->setVar->objectState->preventDeleteProp = 1;
-
-                       sp->pp = ejsGetFirstProperty(sp->setVar, 0);
-                       while (sp->pp) {
-                               sp->nextp = ejsGetNextProperty(sp->pp, 0);
-                               if (! sp->pp->dontEnumerate && !sp->pp->delayedDelete) {
-                                       if (each) {
-                                               sp->vp = ejsWriteVar(ep, sp->iteratorVar,
-                                                       ejsGetVarPtr(sp->pp), EJS_SHALLOW_COPY);
-                                       } else {
-                                               sp->vp = ejsWriteVarAsString(ep, sp->iteratorVar, 
-                                                       sp->pp->name);
-                                       }
-                                       if (sp->vp == 0) {
-                                               ejsError(ep, EJS_MEMORY_ERROR, 
-                                                       "Can't write to variable");
-                                               goto err;
-                                       }
-
-                                       ejsLexRestoreInputState(ep, sp->bodyScript);
-
-                                       state = ejsParse(ep, EJS_STATE_STMT, flags);
-
-                                       if (state < 0) {
-                                               if (sp->setVar->objectState) {
-                                                       sp->setVar->objectState->preventDeleteProp = 0;
-                                               }
-                                               goto done;
-                                       }
-                               }
-                               sp->pp = sp->nextp;
-                       }
-
-                       /*
-                    *  Process delayed deletes
-                        */
-                       if (sp->setVar->objectState) {
-                               sp->setVar->objectState->preventDeleteProp = 0;
-                               if (sp->setVar->objectState->delayedDeleteProp) {
-                                       sp->pp = ejsGetFirstProperty(sp->setVar, 0);
-                                       while (sp->pp) {
-                                               sp->nextp = ejsGetNextProperty(sp->pp, 0);
-                                               if (sp->pp->delayedDelete) {
-                                                       ejsDeleteProperty(ep, sp->setVar, sp->pp->name);
-                                               }
-                                               sp->pp = sp->nextp;
-                                       }
-                                       sp->setVar->objectState->delayedDeleteProp = 0;
-                               }
-                       }
-
-               } else {
-                       ejsError(ep, EJS_REFERENCE_ERROR,
-                               "Variable to iterate over is not an array or object");
-                       goto err;
-               }
-       }
-
-       ejsLexRestoreInputState(ep, sp->endScript);
-
-done:
-       if (sp->endScript) {
-               ejsLexFreeInputState(ep, sp->endScript);
-               ejsLexFreeInputState(ep, sp->bodyScript);
-       }
-
-       if (sp->bodyScript) {
-               freeInputStruct(ep, sp->bodyScript);
-       }
-       if (sp->endScript) {
-               freeInputStruct(ep, sp->endScript);
-       }
-
-       if (sp->setVar) {
-               ejsFreeVar(ep, sp->setVar);
-       }
-
-       popFrame(ep, sizeof(ParseForIn));
-
-       return state;
-
-err:
-       state = EJS_STATE_ERR;
-       goto done;
-}
-
-/******************************************************************************/
-/*
- *     Parse the for statement. Format for the expression is:
- *
- *             for (initial; condition; incr) {
- *                     body;
- *             }
- */
-
-static int parseRegFor(Ejs *ep, int state, int flags)
-{
-       EjsInput        *condScript, *endScript, *bodyScript, *incrScript;
-
-       endScript = getInputStruct(ep);
-       bodyScript = getInputStruct(ep);
-       incrScript = getInputStruct(ep);
-       condScript = getInputStruct(ep);
-
-       ejsInitInputState(endScript);
-       ejsInitInputState(bodyScript);
-       ejsInitInputState(incrScript);
-       ejsInitInputState(condScript);
-
-       state = parseForInner(ep, state, flags, 
-               condScript, incrScript, bodyScript, endScript);
-
-       ejsLexFreeInputState(ep, condScript);
-       ejsLexFreeInputState(ep, incrScript);
-       ejsLexFreeInputState(ep, endScript);
-       ejsLexFreeInputState(ep, bodyScript);
-
-       freeInputStruct(ep, condScript);
-       freeInputStruct(ep, incrScript);
-       freeInputStruct(ep, endScript);
-       freeInputStruct(ep, bodyScript);
-
-       return state;
-}
-
-/******************************************************************************/
-
-static int parseForInner(Ejs *ep, int state, int flags, EjsInput *condScript,
-       EjsInput *incrScript, EjsInput *bodyScript, EjsInput *endScript)
-{
-       int                     forFlags, cond, rs;
-
-       mprAssert(ep);
-
-       /*
-        *      Evaluate the for loop initialization statement
-        */
-       if ((state = ejsParse(ep, EJS_STATE_STMT, flags)) < 0) {
-               return state;
-       }
-
-       /*
-        *      The first time through, we save the current input context just prior
-        *      to each step: prior to the conditional, the loop increment and 
-        *      the loop body.
-        */
-       ejsLexSaveInputState(ep, condScript);
-       if ((rs = ejsParse(ep, EJS_STATE_COND, flags)) < 0) {
-               return rs;
-       }
-
-       cond = (ep->result->boolean != 0);
-
-       if (ejsLexGetToken(ep, state) != EJS_TOK_SEMI) {
-               ejsSyntaxError(ep, 0);
-               return EJS_STATE_ERR;
-       }
-
-       /*
-        *      Don't execute the loop increment statement or the body 
-        *      first time.
-        */
-       forFlags = flags & ~EJS_FLAGS_EXE;
-       ejsLexSaveInputState(ep, incrScript);
-       if ((rs = ejsParse(ep, EJS_STATE_EXPR, forFlags)) < 0) {
-               return rs;
-       }
-
-       if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) {
-               ejsSyntaxError(ep, 0);
-               return EJS_STATE_ERR;
-       }
-
-       /*
-        *      Parse the body and remember the end of the body script
-        */
-       ejsLexSaveInputState(ep, bodyScript);
-       if ((rs = ejsParse(ep, EJS_STATE_STMT, forFlags)) < 0) {
-               return rs;
-       }
-       ejsLexSaveInputState(ep, endScript);
-
-       /*
-        *      Now actually do the for loop. Note loop has been rotated
-        */
-       while (cond && (flags & EJS_FLAGS_EXE)) {
-               /*
-                *      Evaluate the body
-                */
-               ejsLexRestoreInputState(ep, bodyScript);
-
-               if ((rs = ejsParse(ep, EJS_STATE_STMT, flags)) < 0) {
-                       return rs;
-               }
-
-               /*
-                *      Evaluate the increment script
-                */
-               ejsLexRestoreInputState(ep, incrScript);
-               if ((rs = ejsParse(ep, EJS_STATE_EXPR, flags)) < 0) {
-                       return rs;
-               }
-               /*
-                *      Evaluate the condition
-                */
-               ejsLexRestoreInputState(ep, condScript);
-               if ((rs = ejsParse(ep, EJS_STATE_COND, flags)) < 0) {
-                       return 0;
-               }
-               mprAssert(ep->result->type == EJS_TYPE_BOOL);
-               cond = (ep->result->boolean != 0);
-       }
-
-       ejsLexRestoreInputState(ep, endScript);
-
-       return state;
-}
-
-/******************************************************************************/
-/*
- *     Create the bare class object
- */
-
-static int createClass(Ejs *ep, EjsVar *obj, const char *className, 
-       EjsVar *baseClass)
-{
-       EjsVar  *classObj, *existingClass;
-
-       existingClass = ejsGetClass(ep, obj, className);
-       if (existingClass) {
-               /*
-                *      We allow partial clases and method redefinition
-                *      FUTURE -- should prevent this if the class is sealed.
-                *      DISABLED Error message and return OK.
-                */
-               /* ejsError(ep, EJS_EVAL_ERROR, "Can't create class %s", className); */
-               return 0;
-       }
-
-       if (baseClass == 0) {
-               baseClass = ejsGetClass(ep, ep->service->globalClass, "Object");
-               mprAssert(baseClass);
-       }
-
-       classObj = ejsCreateSimpleClass(ep, baseClass, className);
-       if (classObj == 0) {
-               ejsMemoryError(ep);
-               return -1;
-       }
-       mprAssert(! ejsObjIsCollectable(classObj));
-
-       ep->currentProperty = ejsSetPropertyAndFree(ep, obj, className, classObj);
-       mprAssert(ep->currentProperty);
-
-       if (ep->currentProperty == 0) {
-               return -1;
-       }
-
-       return 0;
-}
-
-/******************************************************************************/
-/*
- *     Local vars for parseTry
- */
-
-typedef struct ParseTry {
-       EjsVar          *exception;
-       int                     tid, caught, rs, catchFlags;
-} ParseTry;
-
-/*
- *     Parse try block
- *
- *             try {}
- */
-
-static int parseTry(Ejs *ep, int state, int flags)
-{
-       ParseTry                *sp;
-
-       if ((sp = pushFrame(ep, sizeof(ParseTry))) == 0) {
-               return EJS_STATE_ERR;
-       }
-
-       mprAssert(ep);
-
-       sp->caught = 0;
-       sp->exception = 0;
-       sp->catchFlags = flags;
-
-       /*
-        *      Execute the code in the try block
-        */
-       sp->rs = ejsParse(ep, EJS_STATE_STMT, flags | EJS_FLAGS_TRY);
-       if (sp->rs < 0) {
-               if (sp->rs == EJS_STATE_ERR) {
-                       sp->exception = ejsDupVar(ep, ep->result, EJS_SHALLOW_COPY);
-                       if (sp->exception == 0) {
-                               ejsMemoryError(ep);
-                               goto err;
-                       }
-               } else {
-                       state = sp->rs;
-                       goto done;
-               }
-
-       } else {
-               sp->catchFlags = flags & ~EJS_FLAGS_EXE;
-       }
-
-       /*
-        *      On success path or when an exception is caught, we must parse all
-        *      catch and finally blocks.
-        */
-       sp->tid = getNextNonSpaceToken(ep, state);
-
-       if (sp->tid == EJS_TOK_CATCH) {
-
-               ep->gotException = 0;
-
-               sp->tid = getNextNonSpaceToken(ep, state);
-
-               if (sp->tid == EJS_TOK_LBRACE) {
-                       /*
-                        *      Unqualified "catch "
-                        */
-                       ejsLexPutbackToken(ep, sp->tid, ep->token);
-                       if (ejsParse(ep, EJS_STATE_STMT, sp->catchFlags) >= 0) {
-                               sp->caught++;
-                       }
-
-               } else if (sp->tid == EJS_TOK_LPAREN) {
-
-                       /*
-                        *      Qualified "catch (variable) "
-                        */
-                       if ((sp->rs = ejsParse(ep, EJS_STATE_DEC_LIST, 
-                                       sp->catchFlags | EJS_FLAGS_CATCH)) < 0) {
-                               ejsSyntaxError(ep, "Bad catch statement");
-                               state = sp->rs;
-                               goto done;
-                       }
-
-                       sp->tid = getNextNonSpaceToken(ep, state);
-                       if (sp->tid != EJS_TOK_RPAREN) {
-                               ejsSyntaxError(ep, 0);
-                               goto err;
-                       }
-
-                       if (sp->catchFlags & EJS_FLAGS_EXE) {
-                               if (ep->currentProperty == 0) {
-                                       ejsError(ep, EJS_EVAL_ERROR, "Can't define catch variable");
-                                       goto err;
-                               }
-
-                               /*
-                                *      Set the catch variable
-                                */
-                               if (ejsWriteVar(ep, 
-                                               ejsGetVarPtr(ep->currentProperty), sp->exception, 
-                                               EJS_SHALLOW_COPY) == 0) {
-                                       ejsError(ep, EJS_EVAL_ERROR, "Can't update catch variable");
-                                       goto err;
-                               }
-                       }
-
-                       /*
-                        *      Parse the catch block
-                        */
-                       if ((sp->rs = ejsParse(ep, EJS_STATE_STMT, sp->catchFlags)) < 0) {
-                               state = sp->rs;
-                               goto done;
-                       }
-                       sp->caught++;
-                       ep->gotException = 0;
-               }
-               sp->tid = getNextNonSpaceToken(ep, state);
-       }
-
-       /*
-        *      Parse the finally block
-        */
-       if (sp->tid == EJS_TOK_FINALLY) {
-               if (ejsParse(ep, EJS_STATE_STMT, flags) < 0) {
-                       goto err;
-               }
-       } else {
-               ejsLexPutbackToken(ep, sp->tid, ep->token);
-       }
-
-       /*
-        *      Set the exception value
-        */
-       if (sp->exception && !sp->caught) {
-               ejsWriteVar(ep, ep->result, sp->exception, EJS_SHALLOW_COPY);
-               goto err;
-       }
-       
-       state = EJS_STATE_STMT_DONE;
-
-done:
-       if (sp->exception) {
-               ejsFreeVar(ep, sp->exception);
-       }
-
-       popFrame(ep, sizeof(ParseTry));
-       return state;
-
-
-err:
-       state = EJS_STATE_ERR;
-       goto done;
-}
-
-/******************************************************************************/
-/*
- *     Parse throw statement
- *
- *             throw expression
- */
-
-static int parseThrow(Ejs *ep, int state, int flags)
-{
-       int             rc;
-
-       mprAssert(ep);
-
-       if ((rc = ejsParse(ep, EJS_STATE_EXPR, flags)) < 0) {
-               return rc;
-       }
-
-
-       if (flags & EJS_FLAGS_EXE) {
-               /*
-                *      We have thrown the exception so set the state to ERR
-                */
-               ep->gotException = 1;
-               return EJS_STATE_ERR;
-       }
-       return state;
-}
-
-/******************************************************************************/
-/*
- *     Parse a class and module declaration
- *
- *             class <name> [extends baseClass] {
- *                     [public | private | ... ] var declarations ...
- *                     [constructor] function declarations ...
- *             }
- *
- *             Modules are identical except declared with a "module" instead of
- *             "class". Modules cannot be instantiated and are used for mixins.
- *     
- */
-
-static int parseClass(Ejs *ep, int state, int flags)
-{
-       int                     originalToken, tid, fid;
-
-       mprAssert(ep);
-
-       originalToken = ep->tid;
-
-       /*
-        *      Parse "class Name [extends BaseClass]"
-        */
-       if (ejsParse(ep, EJS_STATE_DEC_LIST, flags | EJS_FLAGS_CLASS_DEC) < 0) {
-               return EJS_STATE_ERR;
-       }
-
-       tid = getNextNonSpaceToken(ep, state);
-
-       if (tid != EJS_TOK_LBRACE) {
-               return EJS_STATE_ERR;
-       }
-
-       /*
-        *      After parsing the class body, ep->local will contain the actual 
-        *      class/module object. So, we save ep->local by creating a new block.
-        */
-       if (flags & EJS_FLAGS_EXE) {
-               fid = ejsSetBlock(ep, ejsGetVarPtr(ep->currentProperty));
-               ejsSetVarName(ep, ep->local, ep->currentProperty->name);
-
-       } else {
-               fid = -1;
-       }
-
-       /* FUTURE -- should prevent modules from being instantiated */
-
-       /*
-        *      Parse class body
-        */
-       do {
-               state = ejsParse(ep, EJS_STATE_STMT, flags);
-               if (state < 0) {
-                       if (fid >= 0) {
-                               ejsCloseBlock(ep, fid);
-                       }
-                       return state;
-               }
-               tid = getNextNonSpaceToken(ep, state);
-               if (tid == EJS_TOK_RBRACE) {
-                       break;
-               }
-               ejsLexPutbackToken(ep, tid, ep->token);
-
-       } while (state >= 0);
-
-       if (fid >= 0) {
-               ejsCloseBlock(ep, fid);
-       }
-
-       if (tid != EJS_TOK_RBRACE) {
-               ejsSyntaxError(ep, 0);
-               state = EJS_STATE_ERR;
-       }
-
-       return state;
-}
-
-/******************************************************************************/
-/*
- *     Parse a function declaration
- */
-
-static int parseFunction(Ejs *ep, int state, int flags)
-{
-       EjsInput        *endScript, *bodyScript;
-       EjsProperty     *pp;
-       EjsVar          *func, *funcProp, *currentObj, *vp, *baseClass;
-       char            *procName;
-       int                     varFlags, len, tid, bodyFlags, innerState;
-
-       mprAssert(ep);
-
-       func = 0;
-       varFlags = 0;
-
-       /*      
-        *      method <name>(arg, arg, arg) { body };
-        *      method name(arg, arg, arg) { body };
-        */
-
-       tid = ejsLexGetToken(ep, state);
-
-       if (tid == EJS_TOK_GET) {
-               varFlags |= EJS_GET_ACCESSOR;
-               tid = ejsLexGetToken(ep, state);
-
-       } else if (tid == EJS_TOK_SET) {
-               varFlags |= EJS_SET_ACCESSOR;
-               tid = ejsLexGetToken(ep, state);
-       } 
-
-       if (tid == EJS_TOK_ID) {
-               if (varFlags & EJS_SET_ACCESSOR) {
-
-                       if (mprAllocStrcat(MPR_LOC_ARGS(ep), &procName, EJS_MAX_ID + 5, 
-                                       0, "-set-", ep->token, 0) < 0) {
-                               ejsError(ep, EJS_SYNTAX_ERROR, 
-                                       "Name %s is too long", ep->token);
-                               return EJS_STATE_ERR;
-                       }
-
-               } else {
-                       procName = mprStrdup(ep, ep->token);
-               }
-
-               tid = ejsLexGetToken(ep, state);
-
-       }  else {
-               procName = 0;
-       }
-
-       if (tid != EJS_TOK_LPAREN) {
-               mprFree(procName);
-               ejsSyntaxError(ep, 0);
-               return EJS_STATE_ERR;
-       }
-
-       /*
-        *      Hand craft the method value structure.
-        */
-       if (flags & EJS_FLAGS_EXE) {
-               func = ejsCreateMethodVar(ep, 0, 0, 0);
-               if (func == 0) {
-                       mprFree(procName);
-                       ejsMemoryError(ep);
-                       return EJS_STATE_ERR;
-               }
-               func->flags = varFlags;
-       }
-
-       tid = ejsLexGetToken(ep, state);
-       while (tid == EJS_TOK_ID) {
-               if (flags & EJS_FLAGS_EXE) {
-                       mprAddItem(func->method.args, 
-                               mprStrdup(func->method.args, ep->token));
-               }
-               tid = ejsLexGetToken(ep, state);
-               if (tid == EJS_TOK_RPAREN || tid != EJS_TOK_COMMA) {
-                       break;
-               }
-               tid = ejsLexGetToken(ep, state);
-       }
-       if (tid != EJS_TOK_RPAREN) {
-               mprFree(procName);
-               ejsFreeVar(ep, func);
-               ejsSyntaxError(ep, 0);
-               return EJS_STATE_ERR;
-       }
-
-       /* Allow new lines before opening brace */
-       do {
-               tid = ejsLexGetToken(ep, state);
-       } while (tid == EJS_TOK_NEWLINE);
-
-       if (tid != EJS_TOK_LBRACE) {
-               mprFree(procName);
-               ejsFreeVar(ep, func);
-               ejsSyntaxError(ep, 0);
-               return EJS_STATE_ERR;
-       }
-       
-       /* 
-        *      Register the method name early to allow for recursive
-        *      method calls (see note in ECMA standard, page 71) 
-        */
-       funcProp = 0;
-       if (flags & EJS_FLAGS_EXE && procName) {
-               currentObj = pickSpace(ep, 0, procName, flags | EJS_FLAGS_LOCAL);
-               pp = ejsSetProperty(ep, currentObj, procName, func);
-               if (pp == 0) {
-                       ejsFreeVar(ep, func);
-                       ejsMemoryError(ep);
-                       return EJS_STATE_ERR;
-               }
-               funcProp = ejsGetVarPtr(pp);
-       }
-       
-
-       bodyScript = getInputStruct(ep);
-
-       /*
-        *      Parse the method body. Turn execute off.
-        */
-       bodyFlags = flags & ~EJS_FLAGS_EXE;
-       ejsLexSaveInputState(ep, bodyScript);
-
-       do {
-               innerState = ejsParse(ep, EJS_STATE_STMT, bodyFlags);
-       } while (innerState == EJS_STATE_STMT_DONE);
-
-       tid = ejsLexGetToken(ep, state);
-
-       if (innerState != EJS_STATE_STMT_BLOCK_DONE || tid != EJS_TOK_RBRACE) {
-               mprFree(procName);
-               ejsFreeVar(ep, func);
-               ejsLexFreeInputState(ep, bodyScript);
-               if (innerState != EJS_STATE_ERR) {
-                       ejsSyntaxError(ep, 0);
-               }
-               freeInputStruct(ep, bodyScript);
-               return EJS_STATE_ERR;
-       }
-
-       if (flags & EJS_FLAGS_EXE) {
-               endScript = getInputStruct(ep);
-               ejsLexSaveInputState(ep, endScript);
-
-               /*
-                *      Save the method body between the starting and ending parse 
-                *      positions. Overwrite the trailing '}' with a null.
-                */
-               len = endScript->scriptServp - bodyScript->scriptServp;
-               func->method.body = mprAlloc(ep, len + 1);
-               memcpy(func->method.body, bodyScript->scriptServp, len);
-
-               if (len <= 0) {
-                       func->method.body[0] = '\0';
-               } else {
-                       func->method.body[len - 1] = '\0';
-               }
-               ejsLexFreeInputState(ep, bodyScript);
-               ejsLexFreeInputState(ep, endScript);
-               freeInputStruct(ep, endScript);
-
-               /*
-                *      If we are in an assignment, don't register the method name, rather
-                *      return the method structure in the parser result.
-                */
-               if (procName) {
-                       currentObj = pickSpace(ep, 0, procName, flags | EJS_FLAGS_LOCAL);
-                       pp = ejsSetProperty(ep, currentObj, procName, func);
-                       if (pp == 0) {
-                               ejsFreeVar(ep, func);
-                               ejsMemoryError(ep);
-                               return EJS_STATE_ERR;
-                       }
-
-                       if (currentObj->objectState->className &&
-                               strcmp(currentObj->objectState->className, procName) == 0) {
-                               baseClass = currentObj->objectState->baseClass;
-                               if (baseClass) {
-                                       if (strstr(func->method.body, "super(") != 0) {
-                                               funcProp->callsSuper = 1;
-                                               /*
-                                                *      Define super() to point to the baseClass constructor
-                                                */
-                                               vp = ejsGetPropertyAsVar(ep, baseClass, 
-                                                       baseClass->objectState->className);
-                                               if (vp) {
-                                                       mprAssert(vp);
-                                                       if (ejsSetProperty(ep, currentObj, "super", 
-                                                                       vp) == 0) {
-                                                               ejsFreeVar(ep, func);
-                                                               ejsMemoryError(ep);
-                                                               return EJS_STATE_ERR;
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               }
-               /*
-                *      Always return the function. Try for all stmts to be expressions.
-                */
-               /* MOB - rc */
-               ejsWriteVar(ep, ep->result, func, EJS_SHALLOW_COPY);
-       }
-       freeInputStruct(ep, bodyScript);
-
-       mprFree(procName);
-       ejsFreeVar(ep, func);
-
-       return state;
-}
-
-/******************************************************************************/
-/*
- *     Local vars
- */
-
-typedef struct ParseMethod {
-       EjsProc         proc, *saveProc;
-       EjsVar          *saveObj, *newObj;
-       int                     saveObjPerm, rc;
-
-} ParseMethod;
-
-/*
- *     Parse a method name and invoke the method. See parseFunction for 
- *     function declarations.
- */
-
-static int parseMethod(Ejs *ep, int state, int flags, char *id)
-{
-       ParseMethod             *sp;
-
-       if ((sp = pushFrame(ep, sizeof(ParseMethod))) == 0) {
-               return EJS_STATE_ERR;
-       }
-
-       /*
-        *      Must save any current ep->proc value for the current stack frame
-        *      to allow for recursive method calls.
-        */
-       sp->saveProc = (ep->proc) ? ep->proc: 0;
-
-       memset(&sp->proc, 0, sizeof(EjsProc));
-       sp->proc.procName = mprStrdup(ep, id);
-       sp->proc.fn = &ep->currentProperty->var;
-       sp->proc.args = mprCreateItemArray(ep, EJS_INC_ARGS, EJS_MAX_ARGS);
-       ep->proc = &sp->proc;
-
-#if BLD_DEBUG
-       if (strcmp(sp->proc.procName, "printv") == 0) {
-               flags |= EJS_FLAGS_TRACE_ARGS;
-       }
-#endif
-
-       if (flags & EJS_FLAGS_EXE) {
-               ejsClearVar(ep, ep->result);
-       }
-
-       if (! (flags & EJS_FLAGS_NO_ARGS)) {
-               sp->saveObj = ep->currentObj;
-               sp->saveObjPerm = ejsMakeObjPermanent(sp->saveObj, 1);
-               sp->rc = ejsParse(ep, EJS_STATE_ARG_LIST, flags);
-               ejsMakeObjPermanent(sp->saveObj, sp->saveObjPerm);
-               if (sp->rc < 0) {
-                       goto err;
-               }
-               ep->currentObj = sp->saveObj;
-       }
-
-#if BLD_DEBUG
-       flags &= ~EJS_FLAGS_TRACE_ARGS;
-#endif
-
-       /*
-        *      Evaluate the method if required
-        */
-       if (flags & EJS_FLAGS_EXE) {
-               if (flags & EJS_FLAGS_NEW) {
-                       sp->newObj = ejsCreateObjUsingArgv(ep, ep->currentObj, 
-                               sp->proc.procName, sp->proc.args);
-
-                       if (sp->newObj == 0) {
-                               state = EJS_STATE_ERR;
-
-                       } else {
-                               mprAssert(! ejsObjIsCollectable(sp->newObj));
-
-                               /*
-                                *      Return the newly created object as the result of the 
-                                *      command. NOTE: newObj may not be an object!
-                                */
-                               /* MOB - rc */
-                               ejsWriteVar(ep, ep->result, sp->newObj, EJS_SHALLOW_COPY);
-                               if (ejsVarIsObject(sp->newObj)) {
-                                       ejsMakeObjLive(sp->newObj, 1);
-                                       mprAssert(ejsObjIsCollectable(sp->newObj));
-                                       mprAssert(ejsBlockInUse(sp->newObj));
-                               }
-                               ejsFreeVar(ep, sp->newObj);
-                       }
-
-               } else {
-
-                       if (evalMethod(ep, ep->currentObj, &sp->proc, flags) < 0) {
-                               /* Methods must call ejsError to set exceptions */
-                               state = EJS_STATE_ERR;
-                       }
-               }
-       }
-
-       if (! (flags & EJS_FLAGS_NO_ARGS)) {
-               if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) {
-                       if (state != EJS_STATE_ERR) {
-                               ejsSyntaxError(ep, 0);
-                       }
-                       state = EJS_STATE_ERR;
-               }
-       }
-
-done:
-       freeProc(ep, &sp->proc);
-       ep->proc = sp->saveProc;
-
-       popFrame(ep, sizeof(ParseMethod));
-       return state;
-
-err:
-       state = EJS_STATE_ERR;
-       goto done;
-}
-
-/******************************************************************************/
-/*
- *     Parse an identifier. This is a segment of a fully qualified variable.
- *     May come here for an initial identifier or for property names
- *     after a "." or "[...]".
- */
-
-static int parseId(Ejs *ep, int state, int flags, char **id, int *done)
-{
-       EjsVar  *null;
-       int             tid;
-
-       mprFree(*id);
-       *id = mprStrdup(ep, ep->token);
-
-       if (ep->currentObj == 0) {
-               /* First identifier segement */
-               ep->currentObj = pickSpace(ep, state, *id, flags);
-       }
-
-       tid = ejsLexGetToken(ep, state);
-       if (tid == EJS_TOK_ASSIGNMENT) {
-               flags |= EJS_FLAGS_LHS;
-       }
-
-       /*
-        *      Find the referenced variable and store it in currentProperty.
-         */
-       if (flags & EJS_FLAGS_EXE) {
-               ep->currentProperty = searchSpacesForProperty(ep, state, 
-                       ep->currentObj, *id, flags);
-
-               /*
-                *      Handle properties that have been deleted inside an enumeration
-                */
-               if (ep->currentProperty && ep->currentProperty->delayedDelete) {
-                       ep->currentProperty = 0;
-               }
-
-               if (ep->currentProperty && 
-                               ejsVarIsMethod(&ep->currentProperty->var) && 
-                               tid != EJS_TOK_LPAREN) {
-                       if (ep->currentProperty->var.flags & EJS_GET_ACCESSOR) {
-                               ejsLexPutbackToken(ep, tid, ep->token);
-                               state = parseMethod(ep, state, flags | EJS_FLAGS_NO_ARGS, *id);
-                               if (ep->flags & EJS_FLAGS_EXIT) {
-                                       state = EJS_STATE_RET;
-                               }
-                               if (state >= 0) {
-                                       ejsSetVarName(ep, ep->result, ep->currentProperty->name);
-                               }
-                               return state;
-                       }
-               }
-               /*
-                *      OPT. We should not have to do this always
-                */
-               updateResult(ep, state, flags, ejsGetVarPtr(ep->currentProperty));
-       }
-
-       flags &= ~EJS_FLAGS_LHS;
-
-       if (tid == EJS_TOK_LPAREN) {
-               if (ep->currentProperty == 0 && (flags & EJS_FLAGS_EXE)) {
-                       ejsError(ep, EJS_REFERENCE_ERROR,
-                               "Method name not defined \"%s\"", *id);
-                       return EJS_STATE_ERR;
-               }
-               ejsLexPutbackToken(ep, EJS_TOK_METHOD_NAME, ep->token);
-               return state;
-       }
-
-       if (tid == EJS_TOK_PERIOD || tid == EJS_TOK_LBRACKET || 
-                       tid == EJS_TOK_ASSIGNMENT || tid == EJS_TOK_INC_DEC) {
-               ejsLexPutbackToken(ep, tid, ep->token);
-               return state;
-       }
-
-       if (flags & EJS_FLAGS_CLASS_DEC) {
-               if (tid == EJS_TOK_LBRACE || tid == EJS_TOK_EXTENDS) {
-                       ejsLexPutbackToken(ep, tid, ep->token);
-                       return state;
-               }
-       }
-
-       if (flags & EJS_FLAGS_DELETE) {
-               if (tid == EJS_TOK_RBRACE) {
-                       ejsLexPutbackToken(ep, tid, ep->token);
-               }
-       }
-
-       /*
-        *      Only come here for variable access and declarations.
-        *      Assignment handled elsewhere.
-        */
-       if (flags & EJS_FLAGS_EXE) {
-               if (state == EJS_STATE_DEC) {
-                       /*
-                        *      Declare a variable. Standard allows: var x ; var x ;
-                        */
-#if DISABLED
-                       if (ep->currentProperty != 0) {
-                               ejsError(ep, EJS_REFERENCE_ERROR,
-                                       "Variable already defined \"%s\"", *id);
-                               return EJS_STATE_ERR;
-                       }
-#endif
-                       /*
-                        *      Create or overwrite if it already exists
-                        *      Set newly declared variables to the null value.
-                        */
-                       null = ejsCreateNullVar(ep);
-                       ep->currentProperty = ejsSetPropertyAndFree(ep, ep->currentObj, 
-                               *id, null);
-                       ejsClearVar(ep, ep->result);
-
-               } else if (flags & EJS_FLAGS_FORIN) {
-                       /*
-                        *      This allows "for (x" when x has not yet been defined
-                        */
-                       if (ep->currentProperty == 0) {
-                               /* MOB -- return code */
-                               ep->currentProperty = ejsCreateProperty(ep, 
-                                       ep->currentObj, *id);
-                       }
-
-               } else if (ep->currentProperty == 0) {
-
-                       if (ep->currentObj && ((ep->currentObj == ep->global || 
-                                       (ep->currentObj == ep->local)))) {
-                               /* 
-                                *      Test against currentObj and not currentObj->objectState
-                                *      as we must allow "i = global.x" and not allow 
-                                *      "i = x" where x does not exist.
-                                */
-                               ejsError(ep, EJS_REFERENCE_ERROR,
-                                       "Undefined variable \"%s\"", *id);
-                               return EJS_STATE_ERR;
-                       }
-
-                       if (flags & EJS_FLAGS_DELETE) {
-                               ejsError(ep, EJS_REFERENCE_ERROR,
-                                       "Undefined variable \"%s\"", *id);
-                               return EJS_STATE_ERR;
-                       }
-               }
-       }
-       ejsLexPutbackToken(ep, tid, ep->token);
-       if (tid == EJS_TOK_RBRACKET || tid == EJS_TOK_COMMA || 
-                       tid == EJS_TOK_IN) {
-               *done = 1;
-       }
-       return state;
-}
-
-/******************************************************************************/
-/*
- *     Local vars 
- */
-
-typedef struct ParseIf {
-       int             ifResult, thenFlags, elseFlags, tid, rs;
-} ParseIf;
-
-/*
- *     Parse an "if" statement
- */
-
-static int parseIf(Ejs *ep, int state, int flags, int *done)
-{
-       ParseIf         *sp;
-
-       if ((sp = pushFrame(ep, sizeof(ParseIf))) == 0) {
-               return EJS_STATE_ERR;
-       }
-
-       if (state != EJS_STATE_STMT) {
-               goto err;
-       }
-       if (ejsLexGetToken(ep, state) != EJS_TOK_LPAREN) {
-               goto err;
-       }
-
-       /*
-        *      Evaluate the entire condition list "(condition)"
-        */
-       if (ejsParse(ep, EJS_STATE_COND, flags) < 0) {
-               goto err;
-       }
-       if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) {
-               goto err;
-       }
-
-       /*
-        *      This is the "then" case. We need to always parse both cases and
-        *      execute only the relevant case.
-        */
-       sp->ifResult = ejsVarToBoolean(ep->result);
-       if (sp->ifResult) {
-               sp->thenFlags = flags;
-               sp->elseFlags = flags & ~EJS_FLAGS_EXE;
-       } else {
-               sp->thenFlags = flags & ~EJS_FLAGS_EXE;
-               sp->elseFlags = flags;
-       }
-
-       /*
-        *      Process the "then" case.
-        */
-       if ((sp->rs = ejsParse(ep, EJS_STATE_STMT, sp->thenFlags)) < 0) {
-               if (! ep->gotException) {
-                       state = sp->rs;
-                       goto done;
-               }
-       }
-
-       /*
-        *      Check to see if there is an "else" case
-        */
-       removeNewlines(ep, state);
-       sp->tid = ejsLexGetToken(ep, state);
-       if (sp->tid != EJS_TOK_ELSE) {
-               ejsLexPutbackToken(ep, sp->tid, ep->token);
-               *done = 1;
-               if (ep->gotException) {
-                       goto err;
-               }
-               goto done;
-       }
-
-       /*
-        *      Process the "else" case.
-        */
-       state = ejsParse(ep, EJS_STATE_STMT, sp->elseFlags);
-
-done:
-       *done = 1;
-       if (ep->gotException) {
-               state = EJS_STATE_ERR;
-       }
-       popFrame(ep, sizeof(ParseIf));
-       return state;
-
-
-err:
-       state = EJS_STATE_ERR;
-       goto done;
-}
-
-/******************************************************************************/
-/*
- *     Parse a postix "++" or "--" statement
- */
-
-static int parseInc(Ejs *ep, int state, int flags)
-{
-       EjsVar  *one;
-
-       if (! (flags & EJS_FLAGS_EXE)) {
-               return state;
-       }
-
-       if (ep->currentProperty == 0) {
-               ejsError(ep, EJS_REFERENCE_ERROR,
-                                               "Undefined variable \"%s\"", ep->token);
-               return EJS_STATE_ERR;
-       }
-       one = ejsCreateIntegerVar(ep, 1);
-       if (evalExpr(ep, &ep->currentProperty->var, (int) *ep->token, one) < 0) {
-               ejsFreeVar(ep, one);
-               return EJS_STATE_ERR;
-       }
-       if (ejsWriteVar(ep, &ep->currentProperty->var, ep->result, 
-                       EJS_SHALLOW_COPY) < 0) {
-               ejsError(ep, EJS_IO_ERROR, "Can't write to variable");
-               ejsFreeVar(ep, one);
-               return EJS_STATE_ERR;
-       }
-       ejsFreeVar(ep, one);
-       return state;
-}
-
-/******************************************************************************/
-/*
- *     Evaluate a condition. Implements &&, ||, !. Returns with a boolean result
- *     in ep->result. Returns EJS_STATE_ERR on errors, zero if successful.
- */
-
-static int evalCond(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs)
-{
-       int             l, r, lval;
-
-       mprAssert(rel > 0);
-
-       l = ejsVarToBoolean(lhs);
-       r = ejsVarToBoolean(rhs);
-
-       switch (rel) {
-       case EJS_COND_AND:
-               lval = l && r;
-               break;
-       case EJS_COND_OR:
-               lval = l || r;
-               break;
-       default:
-               ejsError(ep, EJS_SYNTAX_ERROR, "Bad operator %d", rel);
-               return -1;
-       }
-
-       /* MOB - rc */
-       ejsWriteVarAsBoolean(ep, ep->result, lval);
-       return 0;
-}
-
-
-/******************************************************************************/
-/*
- *     return true if this string is a valid number
- */
-
-static int stringIsNumber(const char *s)
-{
-       char *endptr = NULL;
-
-       if (s == NULL || *s == 0) {
-               return 0;
-       }
-       /* MOB -- not ideal */
-#if BREW
-       /* MOB this should check all digits and not just the first. */
-       /* Does not support floating point - easy */
-
-       if (isdigit(*s) || (*s == '-' && isdigit(s[1]))) {
-               return 1;
-       }
-#else
-       strtod(s, &endptr);
-#endif
-       if (endptr != NULL && *endptr == 0) {
-               return 1;
-       }
-       return 0;
-}
-
-/******************************************************************************/
-/*
- *     Evaluate an operation. Returns with the result in ep->result. Returns -1
- *     on errors, otherwise zero is returned.
- */
-
-static int evalExpr(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs)
-{
-       EjsNum          lval;
-       char            *str;
-       int                     rc;
-
-       mprAssert(rel > 0);
-       str = 0;
-       lval = 0;
-
-       /*
-        *      Type conversion. This is tricky and must be according to the standard.
-        *      Only numbers (including floats) and strings can be compared. All other
-        *      types are first converted to numbers by preference and if that fails,
-        *      to strings.
-        *
-        *      MOB -- should we do "valueOf" here also.
-        */
-       if (lhs->type == EJS_TYPE_OBJECT && 
-               (rhs->type != EJS_TYPE_OBJECT && 
-                       (rhs->type != EJS_TYPE_UNDEFINED && rhs->type != EJS_TYPE_NULL))) {
-               if (ejsVarIsNumber(rhs)) {
-                       if (ejsRunMethod(ep, lhs, "toValue", 0) == 0) {
-                               /* MOB - rc */
-                               ejsWriteVar(ep, lhs, ep->result, EJS_SHALLOW_COPY);
-                       } else {
-                               if (ejsRunMethod(ep, lhs, "toString", 0) == 0) {
-                                       /* MOB - rc */
-                                       ejsWriteVar(ep, lhs, ep->result, EJS_SHALLOW_COPY);
-                               }
-                       }
-
-               } else {
-                       if (ejsRunMethod(ep, lhs, "toString", 0) == 0) {
-                               /* MOB - rc */
-                               ejsWriteVar(ep, lhs, ep->result, EJS_SHALLOW_COPY);
-                       } else {
-                               if (ejsRunMethod(ep, lhs, "toValue", 0) == 0) {
-                                       /* MOB - rc */
-                                       ejsWriteVar(ep, lhs, ep->result, EJS_SHALLOW_COPY);
-                               }
-                       }
-               }
-               /* Nothing more can be done */
-       }
-
-       if (rhs->type == EJS_TYPE_OBJECT && 
-               (lhs->type != EJS_TYPE_OBJECT && 
-                       (lhs->type != EJS_TYPE_UNDEFINED && lhs->type != EJS_TYPE_NULL))) {
-               if (ejsVarIsNumber(lhs)) {
-                       /* If LHS is number, then convert to a value first */
-                       if (ejsRunMethod(ep, rhs, "toValue", 0) == 0) {
-                               /* MOB - rc */
-                               ejsWriteVar(ep, rhs, ep->result, EJS_SHALLOW_COPY);
-                       } else {
-                               if (ejsRunMethod(ep, rhs, "toString", 0) == 0) {
-                                       /* MOB - rc */
-                                       ejsWriteVar(ep, rhs, ep->result, EJS_SHALLOW_COPY);
-                               }
-                       }
-
-               } else {
-                       /* If LHS is not a number, then convert to a string first */
-                       if (ejsRunMethod(ep, rhs, "toString", 0) == 0) {
-                               /* MOB - rc */
-                               ejsWriteVar(ep, rhs, ep->result, EJS_SHALLOW_COPY);
-
-                       } else {
-                               if (ejsRunMethod(ep, rhs, "toValue", 0) == 0) {
-                                       /* MOB - rc */
-                                       ejsWriteVar(ep, rhs, ep->result, EJS_SHALLOW_COPY);
-                               }
-                       }
-               }
-               /* Nothing more can be done */
-       }
-
-       /* 
-        *      undefined and null are special, in that they don't get promoted when
-        *      comparing.
-        */
-       if (rel == EJS_EXPR_EQ || rel == EJS_EXPR_NOTEQ) {
-               if (lhs->type == EJS_TYPE_UNDEFINED || 
-                               rhs->type == EJS_TYPE_UNDEFINED) {
-                       return evalBoolExpr(ep, 
-                                                               lhs->type == EJS_TYPE_UNDEFINED, 
-                                                               rel, 
-                                                               rhs->type == EJS_TYPE_UNDEFINED);
-               }
-
-               if (lhs->type == EJS_TYPE_NULL || rhs->type == EJS_TYPE_NULL) {
-                       return evalBoolExpr(ep, 
-                                                               lhs->type == EJS_TYPE_NULL, 
-                                                               rel, 
-                                                               rhs->type == EJS_TYPE_NULL);
-               }
-       }
-
-       /*
-        *      From here on, lhs and rhs may contain allocated data (strings), so 
-        *      we must always destroy before overwriting.
-        */
-       
-       /*
-        *      Only allow a few bool operations. Otherwise convert to number.
-        */
-       if (lhs->type == EJS_TYPE_BOOL && rhs->type == EJS_TYPE_BOOL &&
-                       (rel != EJS_EXPR_EQ && rel != EJS_EXPR_NOTEQ &&
-                       rel != EJS_EXPR_BOOL_COMP)) {
-               ejsWriteVarAsNumber(ep, lhs, ejsVarToNumber(lhs));
-       }
-
-       /*
-        *      Types do not match, so try to coerce the right operand to match the left
-        *      But first, try to convert a left operand that is a numeric stored as a
-        *      string, into a numeric.
-        */
-       if (lhs->type != rhs->type) {
-               if (lhs->type == EJS_TYPE_STRING) {
-                       if (stringIsNumber(lhs->string)) {
-                               ejsWriteVarAsNumber(ep, lhs, ejsVarToNumber(lhs));
-                               
-                               /* Examine further below */
-
-                       } else {
-                               /*
-                                *      Convert the RHS to a string
-                                *      MOB rc
-                                */
-                               str = ejsVarToString(ep, rhs);
-                               ejsWriteVarAsString(ep, rhs, str);
-                       }
-
-#if BLD_FEATURE_FLOATING_POINT
-               } else if (lhs->type == EJS_TYPE_FLOAT) {
-                       /*
-                        *      Convert rhs to floating
-                        */
-                       ejsWriteVarAsFloat(ep, rhs, ejsVarToFloat(rhs));
-
-#endif
-#if BLD_FEATURE_INT64
-               } else if (lhs->type == EJS_TYPE_INT64) {
-                       /*
-                        *      Convert the rhs to 64 bit
-                        */
-                       ejsWriteVarAsInteger64(ep, rhs, ejsVarToInteger64(rhs));
-#endif
-               } else if (lhs->type == EJS_TYPE_BOOL || lhs->type == EJS_TYPE_INT) {
-
-                       if (rhs->type == EJS_TYPE_STRING) {
-                               if (stringIsNumber(rhs->string)) {
-                                       ejsWriteVarAsNumber(ep, rhs, ejsVarToNumber(rhs));
-                               } else {
-                                       /*
-                                        *      Convert to lhs to a string
-                                        */
-                                       str = ejsVarToString(ep, lhs);
-                                       /* MOB -- rc */
-                                       if (str) {
-                                               ejsWriteVarAsString(ep, lhs, str);
-                                       }
-                               }
-
-#if BLD_FEATURE_FLOATING_POINT
-                       } else if (rhs->type == EJS_TYPE_FLOAT) {
-                               /*
-                                *      Convert lhs to floating
-                                */
-                               ejsWriteVarAsFloat(ep, lhs, ejsVarToFloat(lhs));
-#endif
-
-                       } else {
-                               /*
-                                *      Forcibly convert both operands to numbers
-                                */
-                               ejsWriteVarAsNumber(ep, lhs, ejsVarToNumber(lhs));
-                               ejsWriteVarAsNumber(ep, rhs, ejsVarToNumber(rhs));
-                       }
-               }
-       }
-
-       /*
-        *      We have failed to coerce the types to be the same. Special case here
-        *      for undefined and null. We need to allow comparisions against these
-        *      special values.
-        */
-       if (lhs->type == EJS_TYPE_UNDEFINED || lhs->type == EJS_TYPE_NULL) {
-               switch (rel) {
-               case EJS_EXPR_EQ:
-                       lval = lhs->type == rhs->type;
-                       break;
-               case EJS_EXPR_NOTEQ:
-                       lval = lhs->type != rhs->type;
-                       break;
-               case EJS_EXPR_BOOL_COMP:
-                       lval = ! ejsVarToBoolean(rhs);
-                       break;
-               default:
-                       ejsWriteVar(ep, ep->result, rhs, EJS_SHALLOW_COPY);
-                       return 0;
-               }
-               ejsWriteVarAsBoolean(ep, ep->result, lval);
-               return 0;
-       }
-
-       /*
-        *      Types are the same here
-        */
-       switch (lhs->type) {
-       default:
-       case EJS_TYPE_UNDEFINED:
-       case EJS_TYPE_NULL:
-               /* Should be handled above */
-               mprAssert(0);
-               return 0;
-
-       case EJS_TYPE_STRING_CMETHOD:
-       case EJS_TYPE_CMETHOD:
-       case EJS_TYPE_METHOD:
-       case EJS_TYPE_PTR:
-               ejsWriteVarAsBoolean(ep, ep->result, 0);
-               return 0;
-
-       case EJS_TYPE_OBJECT:
-               rc = evalObjExpr(ep, lhs, rel, rhs);
-               break;
-
-       case EJS_TYPE_BOOL:
-               rc = evalBoolExpr(ep, lhs->boolean, rel, rhs->boolean);
-               break;
-
-#if BLD_FEATURE_FLOATING_POINT
-       case EJS_TYPE_FLOAT:
-               rc = evalFloatExpr(ep, lhs->floating, rel, rhs->floating);
-               break;
-#endif
-
-       case EJS_TYPE_INT:
-               rc = evalNumericExpr(ep, (EjsNum) lhs->integer, rel, 
-                       (EjsNum) rhs->integer);
-               break;
-
-#if BLD_FEATURE_INT64
-       case EJS_TYPE_INT64:
-               rc = evalNumericExpr(ep, (EjsNum) lhs->integer64, rel, 
-                       (EjsNum) rhs->integer64);
-               break;
-#endif
-
-       case EJS_TYPE_STRING:
-               rc = evalStringExpr(ep, lhs, rel, rhs);
-       }
-
-       /* MOB */
-       if (lhs->type == EJS_TYPE_OBJECT) {
-               ejsMakeObjLive(lhs, 0);
-               mprAssert(lhs->objectState->alive == 0);
-       }
-       if (rhs->type == EJS_TYPE_OBJECT) {
-               ejsMakeObjLive(rhs, 0);
-               mprAssert(rhs->objectState->alive == 0);
-       }
-
-       return rc;
-}
-
-/******************************************************************************/
-#if BLD_FEATURE_FLOATING_POINT
-/*
- *     Expressions with floating operands
- */
-
-static int evalFloatExpr(Ejs *ep, double l, int rel, double r) 
-{
-       double  lval;
-       int             logical;
-
-       lval = 0;
-       logical = 0;
-
-       switch (rel) {
-       case EJS_EXPR_PLUS:
-               lval = l + r;
-               break;
-       case EJS_EXPR_INC:
-               lval = l + 1;
-               break;
-       case EJS_EXPR_MINUS:
-               lval = l - r;
-               break;
-       case EJS_EXPR_DEC:
-               lval = l - 1;
-               break;
-       case EJS_EXPR_MUL:
-               lval = l * r;
-               break;
-       case EJS_EXPR_DIV:
-               lval = l / r;
-               break;
-       default:
-               logical++;
-               break;
-       }
-
-       /*
-        *      Logical operators
-        */
-       if (logical) {
-
-               switch (rel) {
-               case EJS_EXPR_EQ:
-                       lval = l == r;
-                       break;
-               case EJS_EXPR_NOTEQ:
-                       lval = l != r;
-                       break;
-               case EJS_EXPR_LESS:
-                       lval = (l < r) ? 1 : 0;
-                       break;
-               case EJS_EXPR_LESSEQ:
-                       lval = (l <= r) ? 1 : 0;
-                       break;
-               case EJS_EXPR_GREATER:
-                       lval = (l > r) ? 1 : 0;
-                       break;
-               case EJS_EXPR_GREATEREQ:
-                       lval = (l >= r) ? 1 : 0;
-                       break;
-               case EJS_EXPR_BOOL_COMP:
-                       lval = (r == 0) ? 1 : 0;
-                       break;
-               default:
-                       ejsError(ep, EJS_SYNTAX_ERROR, "Bad operator %d", rel);
-                       return -1;
-               }
-               ejsWriteVarAsBoolean(ep, ep->result, lval != 0);
-
-       } else {
-               ejsWriteVarAsFloat(ep, ep->result, lval);
-       }
-       return 0;
-}
-
-#endif /* BLD_FEATURE_FLOATING_POINT */
-/******************************************************************************/
-/*
- *     Expressions with object operands
- */
-
-static int evalObjExpr(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs) 
-{
-       int             lval;
-
-       switch (rel) {
-       case EJS_EXPR_EQ:
-               lval = lhs->objectState == rhs->objectState;
-               break;
-       case EJS_EXPR_NOTEQ:
-               lval = lhs->objectState != rhs->objectState;
-               break;
-       default:
-               ejsError(ep, EJS_SYNTAX_ERROR, "Bad operator %d", rel);
-               return -1;
-       }
-       ejsWriteVarAsBoolean(ep, ep->result, lval);
-       return 0;
-}
-
-/******************************************************************************/
-/*
- *     Expressions with boolean operands
- */
-
-static int evalBoolExpr(Ejs *ep, int l, int rel, int r) 
-{
-       int             lval;
-
-       switch (rel) {
-       case EJS_EXPR_EQ:
-               lval = l == r;
-               break;
-       case EJS_EXPR_NOTEQ:
-               lval = l != r;
-               break;
-       case EJS_EXPR_BOOL_COMP:
-               lval = (r == 0) ? 1 : 0;
-               break;
-       default:
-               ejsError(ep, EJS_SYNTAX_ERROR, "Bad operator %d", rel);
-               return -1;
-       }
-       ejsWriteVarAsBoolean(ep, ep->result, lval);
-       return 0;
-}
-
-/******************************************************************************/
-/*
- *     Expressions with numeric operands
- */
-
-static int evalNumericExpr(Ejs *ep, EjsNum l, int rel, EjsNum r) 
-{
-       EjsNum  lval;
-       int             logical;
-
-       lval = 0;
-       logical = 0;
-
-       switch (rel) {
-       case EJS_EXPR_PLUS:
-               lval = l + r;
-               break;
-       case EJS_EXPR_INC:
-               lval = l + 1;
-               break;
-       case EJS_EXPR_MINUS:
-               lval = l - r;
-               break;
-       case EJS_EXPR_DEC:
-               lval = l - 1;
-               break;
-       case EJS_EXPR_MUL:
-               lval = l * r;
-               break;
-       case EJS_EXPR_DIV:
-               if (r != 0) {
-                       lval = l / r;
-               } else {
-                       ejsError(ep, EJS_RANGE_ERROR, "Divide by zero");
-                       return -1;
-               }
-               break;
-       case EJS_EXPR_MOD:
-               if (r != 0) {
-                       lval = l % r;
-               } else {
-                       ejsError(ep, EJS_RANGE_ERROR, "Modulo zero");
-                       return -1;
-               }
-               break;
-       case EJS_EXPR_LSHIFT:
-               lval = l << r;
-               break;
-       case EJS_EXPR_RSHIFT:
-               lval = l >> r;
-               break;
-
-       default:
-               logical++;
-               break;
-       }
-
-       /*
-        *      Logical operators
-        */
-       if (logical) {
-
-               switch (rel) {
-               case EJS_EXPR_EQ:
-                       lval = l == r;
-                       break;
-               case EJS_EXPR_NOTEQ:
-                       lval = l != r;
-                       break;
-               case EJS_EXPR_LESS:
-                       lval = (l < r) ? 1 : 0;
-                       break;
-               case EJS_EXPR_LESSEQ:
-                       lval = (l <= r) ? 1 : 0;
-                       break;
-               case EJS_EXPR_GREATER:
-                       lval = (l > r) ? 1 : 0;
-                       break;
-               case EJS_EXPR_GREATEREQ:
-                       lval = (l >= r) ? 1 : 0;
-                       break;
-               case EJS_EXPR_BOOL_COMP:
-                       lval = (r == 0) ? 1 : 0;
-                       break;
-               default:
-                       ejsError(ep, EJS_SYNTAX_ERROR, "Bad operator %d", rel);
-                       return -1;
-               }
-               ejsWriteVarAsBoolean(ep, ep->result, lval != 0);
-
-       } else {
-               ejsWriteVarAsNumber(ep, ep->result, lval);
-       }
-       return 0;
-}
-
-/******************************************************************************/
-/*
- *     Expressions with string operands
- */
-
-static int evalStringExpr(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs)
-{
-       int             lval;
-
-       mprAssert(ep);
-       mprAssert(lhs);
-       mprAssert(rhs);
-
-       switch (rel) {
-       case EJS_EXPR_LESS:
-               lval = strcmp(lhs->string, rhs->string) < 0;
-               break;
-       case EJS_EXPR_LESSEQ:
-               lval = strcmp(lhs->string, rhs->string) <= 0;
-               break;
-       case EJS_EXPR_GREATER:
-               lval = strcmp(lhs->string, rhs->string) > 0;
-               break;
-       case EJS_EXPR_GREATEREQ:
-               lval = strcmp(lhs->string, rhs->string) >= 0;
-               break;
-       case EJS_EXPR_EQ:
-               lval = strcmp(lhs->string, rhs->string) == 0;
-               break;
-       case EJS_EXPR_NOTEQ:
-               lval = strcmp(lhs->string, rhs->string) != 0;
-               break;
-       case EJS_EXPR_PLUS:
-               /*
-                *      This differs from all the above operations. We append rhs to lhs.
-                */
-               ejsClearVar(ep, ep->result);
-               ejsStrcat(ep, ep->result, lhs);
-               ejsStrcat(ep, ep->result, rhs);
-               return 0;
-
-       case EJS_EXPR_INC:
-       case EJS_EXPR_DEC:
-       case EJS_EXPR_MINUS:
-       case EJS_EXPR_DIV:
-       case EJS_EXPR_MOD:
-       case EJS_EXPR_LSHIFT:
-       case EJS_EXPR_RSHIFT:
-       default:
-               ejsSyntaxError(ep, "Bad operator");
-               return -1;
-       }
-
-       ejsWriteVarAsBoolean(ep, ep->result, lval);
-       return 0;
-}
-
-/******************************************************************************/
-/*
- *     Evaluate a method. obj is set to the current object if a method is being
- *     run.
- */
-
-static int evalMethod(Ejs *ep, EjsVar *obj, EjsProc *proc, int flags)
-{
-       EjsProperty             *pp;
-       EjsVar                  *saveThis, *prototype;
-       int                             saveThisPerm, rc, fid;
-
-       mprAssert(ep); 
-
-       rc = 0;
-       fid = -1;
-       saveThis = 0;
-       saveThisPerm = 0;
-       prototype = proc->fn;
-
-       if (prototype == 0) {
-               ejsError(ep, EJS_EVAL_ERROR, "Undefined method");
-               return EJS_STATE_ERR;
-       }
-
-       if (prototype->type == EJS_TYPE_OBJECT) {
-               prototype = ejsGetPropertyAsVar(ep, prototype, proc->procName);
-       }
-
-       if (prototype) {
-               /*
-                *      Create a new variable stack frame. ie. new local variables.
-                *      Some C methods (eg. include) don't create a new local context.
-                */
-               if (! (prototype->flags & EJS_NO_LOCAL)) {
-                       fid = ejsOpenBlock(ep);
-                       if (fid < 0) {
-                               return EJS_STATE_ERR;
-                       }
-                       mprAssert(ejsBlockInUse(ep->local));
-
-                       pp = ejsSetProperty(ep, ep->local, "this", obj);
-                       ejsMakePropertyEnumerable(pp, 0);
-
-                       /*
-                        *      Optimization. Save "this" during this block.
-                        */
-                       saveThis = ep->thisObject;
-                       ep->thisObject = ejsGetVarPtr(pp);
-                       saveThisPerm = ejsMakeObjPermanent(saveThis, 1);
-               }
-
-               switch (prototype->type) {
-               default:
-                       mprAssert(0);
-                       break;
-
-               case EJS_TYPE_STRING_CMETHOD:
-                       rc = callStringCMethod(ep, obj, proc, prototype);
-                       break;
-
-               case EJS_TYPE_CMETHOD:
-                       rc = callCMethod(ep, obj, proc, prototype);
-                       break;
-
-               case EJS_TYPE_METHOD:
-                       rc = callMethod(ep, obj, proc, prototype);
-                       break;
-               }
-
-               if (fid >= 0) {
-                       ejsMakeObjPermanent(saveThis, saveThisPerm);
-                       ep->thisObject = saveThis;
-                       mprAssert(ejsBlockInUse(ep->local));
-                       mprAssert(ejsBlockInUse(ep->thisObject));
-                       ejsCloseBlock(ep, fid);
-               }
-       }
-
-       return rc;
-}
-
-/******************************************************************************/
-/*
- *     Create a new object and call all required constructors.
- *     obj may be null in which case we look globally for className.
- */
-
-EjsVar *ejsCreateObjUsingArgvInternal(EJS_LOC_DEC(ep, loc), EjsVar *obj, 
-       const char *className, MprArray *args)
-{
-       EjsVar          *baseClass, *objectClass, *thisObj;
-       int                     rc;
-
-       mprAssert(className && *className);
-
-       /*
-        *      Create a new object of the required class and pass it into the 
-        *      constructor as the "this" local variable. 
-        */
-       baseClass = ejsGetClass(ep, obj, className);
-       if (baseClass == 0) {
-
-               if (obj && obj->objectState->className &&
-                       strcmp(obj->objectState->className, className) == 0) {
-                       /*
-                        *      Handle case where we are calling the constructor inside
-                        *      the class. In this case, obj == baseClass.
-                        */
-                       thisObj = ejsCreateSimpleObjUsingClassInt(EJS_LOC_PASS(ep, loc), 
-                               obj);
-
-               } else {
-
-                       /*
-                        *      If the baseClass does not exist, try to create an Object
-                        *      We do this for compatibility with JS 1.5 style new Function.
-                        *      MOB -- but this masks an error if we really need className.
-                        */
-                       objectClass = ejsGetClass(ep, 0, "Object");
-                       thisObj = ejsCreateSimpleObjUsingClassInt(EJS_LOC_PASS(ep, loc), 
-                               objectClass);
-               }
-
-       } else {
-               thisObj = ejsCreateSimpleObjUsingClassInt(EJS_LOC_PASS(ep, loc), 
-                       baseClass);
-       }
-
-       if (thisObj == 0) {
-               ejsMemoryError(ep);
-               return 0;
-       }
-
-       /*
-        *      Make the object permanent. While currently not alive, the constructor 
-        *      below may make the object alive.
-        */
-       ejsMakeObjPermanent(thisObj, 1);
-       mprAssert(! ejsObjIsCollectable(thisObj));
-
-       rc = 0;
-       if (baseClass) {
-               if (! baseClass->objectState->noConstructor) {
-                       rc = callConstructor(ep, thisObj, baseClass, args);
-               }
-       } else {
-               /*
-                *      className is the function name when calling new on functions
-                */
-               rc = ejsRunMethod(ep, thisObj, className, args); 
-       }
-
-       /*
-        *      Constructor may change the type to a non-object. 
-        *      Function() does this. Ensure object is not collectable yet.
-        */
-       if (ejsVarIsObject(thisObj)) {
-               ejsMakeObjPermanent(thisObj, 0);
-               ejsMakeObjLive(thisObj, 0);
-       }
-
-       if (rc < 0) {
-               if (rc == MPR_ERR_NOT_FOUND) {
-                       /* No constructor (default) */
-                       return thisObj;
-               }
-               if (! (ep->flags & EJS_FLAGS_EXIT)) {
-                       if (! ep->gotException) {
-                               ejsMemoryError(ep);
-                       }
-               }
-               ejsFreeVar(ep, thisObj);
-               return 0;
-       }
-
-       mprAssert(ejsBlockInUse(thisObj));
-
-       return thisObj;
-}
-
-/******************************************************************************/
-/*
- *     Local vars 
- */
-
-typedef struct CallCons {
-       EjsVar          *subClassConstructor, *subClass, *method;
-} CallCons;
-
-/*
- *     Create a new object and call all required constructors.
- */
-
-static int callConstructor(Ejs *ep, EjsVar *thisObj, EjsVar *baseClass, 
-       MprArray *args)
-{
-       CallCons                *sp;
-       int                             state;
-
-       if ((sp = pushFrame(ep, sizeof(CallCons))) == 0) {
-               return EJS_STATE_ERR;
-       }
-
-       mprAssert(baseClass);
-       mprAssert(baseClass->objectState);
-
-       state = 0;
-
-       /*
-        *      method will be null if there is no constructor for this class
-        */
-       sp->method = ejsGetPropertyAsVar(ep, baseClass, 
-               baseClass->objectState->className);
-
-       if (sp->method == 0 || !ejsVarIsMethod(sp->method) || 
-                       !sp->method->callsSuper) {
-               /*
-                *      Invoke base class constructors in reverse order (RECURSIVE)
-                */
-               sp->subClass = baseClass->objectState->baseClass;
-               if (sp->subClass) {
-
-                       /*
-                        *      Note that the Object class does not have a constructor for 
-                        *      speed. Construction for the base Object is done via 
-                        *      ejsCreateObj above. The code below will invoke constructors 
-                        *      in the right order (bottom up) via recursion. MOB -- need to 
-                        *      scan for super() MOB -- Bug. Fails poorly if no constructor. 
-                        *      Should allows this and invoke a default constructor.
-                        */
-                       sp->subClassConstructor = ejsGetPropertyAsVar(ep, sp->subClass, 
-                               sp->subClass->objectState->className);
-
-                       if (sp->subClassConstructor) {
-
-                               if (callConstructor(ep, thisObj, sp->subClass, 0) < 0) {
-                                       if (! ep->gotException) {
-                                               ejsMemoryError(ep);
-                                       }
-                                       goto err;
-                               }
-                       }
-               }
-       }
-
-       if (sp->method) {
-               /*
-                *      Finally, invoke the constructor for this class itself.
-                */
-               state = runMethod(ep, thisObj, sp->method, 
-                       baseClass->objectState->className, args); 
-       }
-
-done:
-       popFrame(ep, sizeof(CallCons));
-       return state;
-
-err:
-       state = EJS_STATE_ERR;
-       goto done;
-}
-
-/******************************************************************************/
-/*
- *     Create a new object and call all required constructors using string args.
- *     MOB -- would be good to parse constructorArgs for "," and break into
- *     separate args.
- *     Returned object is not yet collectable. Will have alive bit cleared.
- */
-
-EjsVar *ejsCreateObj(Ejs *ep, EjsVar *obj, const char *className,
-        const char *constructorArgs)
-{
-       MprArray        *args;
-       EjsVar          *newp, *vp;
-
-       args = mprCreateItemArray(ep, 0, 0);
-       if (args == 0) {
-               return 0;
-       }
-
-       if (constructorArgs && *constructorArgs) {
-               vp = ejsCreateStringVarInternal(EJS_LOC_ARGS(ep), constructorArgs);
-
-               if (mprAddItem(args, vp) < 0) {
-                       mprFree(args);
-                       return 0;
-               }
-       }
-
-       newp = ejsCreateObjUsingArgv(ep, obj, className, args);
-
-       ejsFreeMethodArgs(ep, args);
-
-       mprAssert(! ejsObjIsCollectable(newp));
-       mprAssert(ejsBlockInUse(newp));
-
-       return newp;
-}
-
-/******************************************************************************/
-
-static int callStringCMethod(Ejs *ep, EjsVar *obj, EjsProc *proc,
-       EjsVar *prototype)
-{
-       EjsVar          **argValues;
-       MprArray        *actualArgs;
-       char            **argBuf, *str;
-       int                     i, rc;
-
-       actualArgs = proc->args;
-       argValues = (EjsVar**) actualArgs->items;
-
-       if (actualArgs->length > 0) {
-               argBuf = mprAlloc(ep, actualArgs->length * sizeof(char*));
-               for (i = 0; i < actualArgs->length; i++) {
-                       str = ejsVarToString(ep, argValues[i]);
-                       /* MOB rc */
-                       argBuf[i] = mprStrdup(ep, str);
-               }
-       } else {
-               argBuf = 0;
-       }
-
-       /*
-        *      Call the method depending on the various handle flags
-        */
-       ep->userData = prototype->cMethodWithStrings.userData;
-       if (prototype->flags & EJS_ALT_HANDLE) {
-               /* 
-                *      Used by the AppWeb GaCompat module. The alt handle is set to the
-                *      web server request struct
-                */
-               rc = ((EjsAltStringCMethod) 
-                       prototype->cMethodWithStrings.fn)
-                       (ep, ep->altHandle, obj, actualArgs->length, argBuf);
-
-       } else if (prototype->flags & EJS_PRIMARY_HANDLE) {
-               /* 
-                *      Used by ESP. The primary handle is set to the esp struct 
-                */
-               rc = (prototype->cMethodWithStrings.fn)(ep->primaryHandle, 
-                       obj, actualArgs->length, argBuf);
-
-       } else {
-               /* 
-                *      Used EJS for the standard procs 
-                */
-               rc = (prototype->cMethodWithStrings.fn)(ep, obj, actualArgs->length, 
-                       argBuf);
-       }
-
-       if (actualArgs->length > 0) {
-               for (i = 0; i < actualArgs->length; i++) {
-                       mprFree(argBuf[i]);
-               }
-               mprFree(argBuf);
-       }
-       ep->userData = 0;
-
-       return rc;
-}
-
-/******************************************************************************/
-
-static int callCMethod(Ejs *ep, EjsVar *obj, EjsProc *proc, EjsVar *prototype)
-{
-       EjsVar          **argValues;
-       MprArray        *actualArgs;
-       int                     rc;
-
-       actualArgs = proc->args;
-       argValues = (EjsVar**) actualArgs->items;
-
-       ep->userData = prototype->cMethod.userData;
-
-       /*
-        *      Call the method depending on the various handle flags
-        *      Sometimes cMethod.fn is NULL if there is no constructor for
-        *      an object.
-        */
-       if (prototype->flags & EJS_ALT_HANDLE) {
-               /* 
-                *      Use by the GaCompat module. The alt handle is set to the
-                *      web server request struct
-                */
-               rc = ((EjsAltCMethod) prototype->cMethod.fn)
-                       (ep, ep->altHandle, obj, actualArgs->length, argValues);
-
-       } else if (prototype->flags & EJS_PRIMARY_HANDLE) {
-               /* 
-                *      Used by ESP. The primary handle is set to the esp struct 
-                */
-               rc = (prototype->cMethod.fn)
-                       (ep->primaryHandle, obj, actualArgs->length, argValues);
-
-       } else {
-               /* 
-                *      Used EJS for the standard procs 
-                */
-               rc = (prototype->cMethod.fn)(ep, obj, actualArgs->length, argValues);
-       }
-
-       ep->userData = 0;
-
-       return rc;
-}
-
-/******************************************************************************/
-/*
- *     Local vars 
- */
-
-typedef struct CallMethod {
-       MprArray        *formalArgs, *actualArgs;
-       EjsVar          *arguments, *callee, **argValues;
-       char            **argNames, buf[16];
-       int                     i, argumentsObj;
-} CallMethod;
-
-
-static int callMethod(Ejs *ep, EjsVar *obj, EjsProc *proc, EjsVar *prototype)
-{
-       CallMethod              *sp;
-       int                             i;
-
-       if ((sp = pushFrame(ep, sizeof(CallMethod))) == 0) {
-               return EJS_STATE_ERR;
-       }
-
-       sp->arguments = 0;
-       sp->callee = 0;
-
-       sp->actualArgs = proc->args;
-       sp->argValues = (EjsVar**) sp->actualArgs->items;
-       sp->formalArgs = prototype->method.args;
-       sp->argNames = (char**) sp->formalArgs->items;
-
-       /*
-        *      Only create arguments and callee if the function actually uses them
-        */
-       sp->argumentsObj = 0;
-       if (strstr(prototype->method.body, "arguments") != 0) {
-               sp->argumentsObj++;
-
-               /*
-                *      Create the arguments and callee variables
-                *      MOB -- should we make real arrays here ? YES
-                */
-               sp->arguments = ejsCreateSimpleObj(ep, "Object");
-               ejsSetVarName(ep, sp->arguments, "arguments");
-               mprAssert(! ejsObjIsCollectable(sp->arguments));
-
-               sp->callee = ejsCreateSimpleObj(ep, "Object");
-               ejsSetVarName(ep, sp->callee, "callee");
-               mprAssert(! ejsObjIsCollectable(sp->callee));
-
-               /*
-                *      Overwrite the length property
-                */
-               ejsSetPropertyToInteger(ep, sp->arguments, "length", 
-                       sp->actualArgs->length);
-               ejsSetPropertyToInteger(ep, sp->callee, "length", 
-                       sp->formalArgs->length);
-       }
-
-       /*
-        *      Define all the agruments to be set to the actual parameters
-        */
-       for (i = 0; i < sp->formalArgs->length; i++) {
-               if (i >= sp->actualArgs->length) {
-                       /* MOB -- return code */
-                       ejsCreateProperty(ep, ep->local, sp->argNames[i]);
-
-               } else {
-                       /* MOB -- return code */
-                       ejsSetProperty(ep, ep->local, sp->argNames[i], sp->argValues[i]);
-               }
-       }
-
-       if (sp->argumentsObj) {
-               for (i = 0; i < sp->actualArgs->length; i++) {
-                       mprItoa(sp->buf, sizeof(sp->buf), i);
-                       ejsSetProperty(ep, sp->arguments, sp->buf, sp->argValues[i]);
-               }
-
-               ejsSetPropertyAndFree(ep, sp->arguments, "callee", sp->callee);
-               ejsSetPropertyAndFree(ep, ep->local, "arguments", sp->arguments);
-       }
-
-       /*
-        *      Actually run the method
-        */
-
-       i = ejsEvalScript(ep, prototype->method.body, 0);
-
-       popFrame(ep, sizeof(CallMethod));
-       return i;
-}
-
-/******************************************************************************/
-/*
- *     Run a method. Obj is set to "this" object. MethodName must exist in it
- *     or in a sub class.
- */
-
-int ejsRunMethod(Ejs *ep, EjsVar *obj, const char *methodName, MprArray *args)
-{
-       EjsProperty     *pp;
-       EjsProc         proc, *saveProc;
-       int                     rc;
-
-       mprAssert(obj);
-       mprAssert(methodName && *methodName);
-
-       pp = ejsGetProperty(ep, obj, methodName);
-       if (pp == 0) {
-               /* MOB -- this should be all in some common accessor routine */
-               pp = ejsGetProperty(ep, ep->local, methodName);
-               if (pp == 0) {
-                       pp = ejsGetProperty(ep, ep->global, methodName);
-                       if (pp == 0) {
-                               ejsError(ep, EJS_REFERENCE_ERROR,
-                                       "Undefined method \"%s\"", methodName);
-                               return MPR_ERR_NOT_FOUND;
-                       }
-               }
-       }
-
-       saveProc = ep->proc;
-       ep->proc = &proc;
-
-       memset(&proc, 0, sizeof(EjsProc));
-
-       ejsClearVar(ep, ep->result);
-
-       /* MOB -- if closures are going to work, we need to have proc be an 
-               Object and let the GC look after it */
-
-       proc.fn = &pp->var;
-       if (proc.fn == 0 || proc.fn->type == EJS_TYPE_UNDEFINED) {
-               ep->proc = saveProc;
-               return MPR_ERR_NOT_FOUND;
-       }
-
-       proc.procName = mprStrdup(ep, methodName);
-       if (args == 0) {
-               proc.args = mprCreateItemArray(ep, EJS_INC_ARGS, EJS_MAX_ARGS);
-       } else {
-               proc.args = args;
-       }
-
-       rc = evalMethod(ep, obj, &proc, 0);
-
-       if (args) {
-               proc.args = 0;
-       }
-       freeProc(ep, &proc);
-
-       ep->proc = saveProc;
-
-       return rc;
-}
-
-/******************************************************************************/
-/*
- *     Run a method. Obj is set to "this" object. MethodName must exist in it
- *     or in a sub class.
- */
-
-int ejsRunMethodCmd(Ejs *ep, EjsVar *obj, const char *methodName, 
-       const char *cmdFmt, ...)
-{
-       MprArray        *args;
-       va_list         cmdArgs;
-       char            *buf, *arg, *cp;
-       int                     rc;
-
-       mprAssert(methodName && *methodName);
-       mprAssert(cmdFmt && *cmdFmt);
-
-       va_start(cmdArgs, cmdFmt);
-       mprAllocVsprintf(MPR_LOC_ARGS(ep), &buf, 0, cmdFmt, cmdArgs);
-       va_end(cmdArgs);
-
-       args = mprCreateItemArray(ep, EJS_INC_ARGS, EJS_MAX_ARGS);
-
-       for (arg = cp = buf; cp && *cp; cp++) {
-               if (*cp == ',') {
-                       *cp = 0;
-                       mprAddItem(args, ejsParseVar(ep, arg, 0));
-                       arg = cp + 1;
-               }
-       }
-       if (cp > arg) {
-               mprAddItem(args, ejsParseVar(ep, arg, 0));
-       }
-
-       rc = ejsRunMethod(ep, obj, methodName, args);
-
-       ejsFreeMethodArgs(ep, args);
-       mprFree(buf);
-
-       return rc;
-}
-
-/******************************************************************************/
-/*
- *     Run a method. Obj is set to "this" object. 
- */
-
-static int runMethod(Ejs *ep, EjsVar *thisObj, EjsVar *method, 
-       const char *methodName, MprArray *args)
-{
-       EjsProc         proc, *saveProc;
-       int                     rc;
-
-       mprAssert(thisObj);
-       mprAssert(method);
-
-       saveProc = ep->proc;
-       ep->proc = &proc;
-
-       memset(&proc, 0, sizeof(EjsProc));
-
-       ejsClearVar(ep, ep->result);
-
-       /* MOB -- if closures are going to work, we need to have proc be an 
-               Object and let the GC look after it */
-
-       proc.fn = method;
-       if (proc.fn == 0 || proc.fn->type == EJS_TYPE_UNDEFINED) {
-               ep->proc = saveProc;
-               return MPR_ERR_NOT_FOUND;
-       }
-
-       proc.procName = mprStrdup(ep, methodName);
-       if (args == 0) {
-               proc.args = mprCreateItemArray(ep, EJS_INC_ARGS, EJS_MAX_ARGS);
-       } else {
-               proc.args = args;
-       }
-
-       rc = evalMethod(ep, thisObj, &proc, 0);
-
-       if (args) {
-               proc.args = 0;
-       }
-       freeProc(ep, &proc);
-
-       ep->proc = saveProc;
-
-       return rc;
-}
-
-/******************************************************************************/
-/*
- *     Find which object contains the property given the current context.
- *     We call this when there is no explicit object and the object must be
- *     determined by the context.
- */
-
-static EjsVar *pickSpace(Ejs *ep, int state, const char *property, int flags)
-{
-       EjsVar          *obj;
-
-       mprAssert(ep);
-       mprAssert(property && *property);
-
-       /* MOB - this is ugly and the logic is confused */
-
-       if (flags & EJS_FLAGS_GLOBAL) {
-               obj = ep->global;
-
-       } else if (state == EJS_STATE_DEC || flags & EJS_FLAGS_LOCAL) {
-               obj = ep->local;
-
-       } else {
-               /* First look local, then this and finally global */
-
-               if (ejsGetSimpleProperty(ep, ep->local, property)) {
-                       obj = ep->local;
-
-               } else if (ep->thisObject && 
-                               findProperty(ep, ep->thisObject, property, flags)) {
-                       obj = ep->thisObject;
-
-               } else {
-#if EJS_ECMA_STND
-                       obj = ep->global;
-#else
-                       if (flags & EJS_FLAGS_EXE && 
-                                       !findProperty(ep, ep->global, property, flags)) {
-                               obj = ep->local;
-                       } else {
-                               obj = ep->global;
-                       }
-#endif
-               }
-       }
-       return obj;
-}
-
-/******************************************************************************/
-/*
- *     Find an object property given a object and a property name. We
- *     intelligently look in the local and global namespaces depending on
- *     our state. If not found in local or global, try base classes for method
- *     names only. Returns the property or NULL.
- *     MOB -- need to rework this API.
- */
-
-static EjsProperty *searchSpacesForProperty(Ejs *ep, int state, EjsVar *obj, 
-       char *property, int flags)
-{
-       EjsProperty             *pp;
-
-       if (obj) {
-               return findProperty(ep, obj, property, flags);
-       }
-
-       /* MOB -- really should have a search stack */
-
-       pp = findProperty(ep, ep->local, property, flags);
-       if (pp == 0 && state != EJS_STATE_DEC) {
-
-               if (ep->thisObject) {
-                       pp = findProperty(ep, ep->thisObject, property, flags);
-               }
-               if (pp == 0) {
-                       pp = findProperty(ep, ep->global, property, flags);
-               }
-       }
-       return pp;
-}
-
-/******************************************************************************/
-/*
- *     Search an object and its base classes to find an object given an object
- *     an a property name. If not an assignment (LHS), then follow base classes. 
- *     Otherwise, just look in the specified object.
- */
-
-static EjsProperty *findProperty(Ejs *ep, EjsVar *op, const char *property, 
-       int flags)
-{
-       /*      MOB -- NEW. Remove when EXE fixes are in. */
-       if (! (flags & EJS_FLAGS_EXE) && op->type == EJS_TYPE_UNDEFINED) {
-               return 0;
-       }
-
-       if (flags & EJS_FLAGS_LHS) {
-               return ejsGetPropertyPtr(ejsGetSimpleProperty(ep, op, property));
-
-       } else {
-               /*
-                *      Follow base classes
-                */
-               return ejsGetPropertyPtr(ejsGetProperty(ep, op, property));
-       }
-}
-
-/******************************************************************************/
-/*
- *     Update result
- */
-
-static void updateResult(Ejs *ep, int state, int flags, EjsVar *vp)
-{
-       if (flags & EJS_FLAGS_EXE && state != EJS_STATE_DEC) {
-               ejsClearVar(ep, ep->result);
-               if (vp) {
-                       ejsWriteVar(ep, ep->result, vp, EJS_SHALLOW_COPY);
-                       ejsSetVarName(ep, ep->result, vp->propertyName);
-               }
-       }
-}
-
-/******************************************************************************/
-/*
- *     Append to the pointer value
- */
-
-int ejsStrcat(Ejs *ep, EjsVar *dest, EjsVar *src)
-{
-       char    *oldBuf, *buf, *str;
-       int             oldLen, newLen, len;
-
-       mprAssert(dest);
-       mprAssert(ejsVarIsString(src));
-
-       if (ejsVarIsValid(dest)) {
-
-               if (! ejsVarIsString(dest)) {
-                       /* Bad type for dest */
-                       return -1;
-               }
-
-               if (! ejsVarIsString(src)) {
-                       str = ejsVarToString(ep, src);
-                       if (str == 0) {
-                               return -1;
-                       }
-                       len = strlen(str);
-
-               } else {
-                       str = src->string;
-                       len = src->length;
-               }
-
-               oldBuf = dest->string;
-               oldLen = dest->length;
-               newLen = oldLen + len + 1;
-
-               if (newLen < MPR_SLAB_STR_MAX) {
-                       buf = oldBuf;
-               } else {
-                       buf = mprRealloc(ep, oldBuf, newLen);
-                       if (buf == 0) {
-                               return -1;
-                       }
-                       dest->string = buf;
-               }
-               memcpy(&buf[oldLen], str, len);
-               dest->length += len;
-
-       } else {
-               ejsWriteVarAsString(ep, dest, src->string);
-       }
-       return 0;
-}
-
-/******************************************************************************/
-/*
- *     Exit the script
- */
-
-void ejsExit(Ejs *ep, int status)
-{
-       ep->scriptStatus = status;
-       ep->flags |= EJS_FLAGS_EXIT;
-}
-
-/******************************************************************************/
-/*
- *     Free an argument list
- */
-
-static void freeProc(Ejs *ep, EjsProc *proc)
-{
-       if (proc->args) {
-               ejsFreeMethodArgs(ep, proc->args);
-       }
-
-       if (proc->procName) {
-               mprFree(proc->procName);
-               proc->procName = NULL;
-       }
-}
-
-/******************************************************************************/
-
-void ejsFreeMethodArgs(Ejs *ep, MprArray *args)
-{
-       int             i;
-
-       for (i = args->length - 1; i >= 0; i--) {
-               ejsFreeVar(ep, args->items[i]);
-               mprRemoveItemByIndex(args, i);
-       }
-       mprFree(args);
-}
-
-/******************************************************************************/
-/*
- *     This method removes any new lines.  Used for else       cases, etc.
- */
-
-static void removeNewlines(Ejs *ep, int state)
-{
-       int tid;
-
-       do {
-               tid = ejsLexGetToken(ep, state);
-       } while (tid == EJS_TOK_NEWLINE);
-
-       ejsLexPutbackToken(ep, tid, ep->token);
-}
-
-/******************************************************************************/
-
-static int getNextNonSpaceToken(Ejs *ep, int state)
-{
-       int             tid;
-
-       do {
-               tid = ejsLexGetToken(ep, state);
-       } while (tid == EJS_TOK_NEWLINE);
-       return tid;
-}
-
-/******************************************************************************/
-
-int ejsGetFlags(Ejs *ep)
-{
-       return ep->flags;
-}
-
-/******************************************************************************/
-
-bool ejsIsExiting(Ejs *ep)
-{
-       return (ep->flags & EJS_FLAGS_EXIT) ? 1: 0;
-}
-
-/******************************************************************************/
-
-void ejsClearExiting(Ejs *ep)
-{
-       ep->flags &= ~EJS_FLAGS_EXIT;
-}
-
-/******************************************************************************/
-
-static EjsInput *getInputStruct(Ejs *ep)
-{
-       EjsInput        *input;
-
-       if (ep->inputList) {
-               input = ep->inputList;
-               ep->inputList = input->nextInput;
-
-       } else {
-               input = mprAlloc(ep, sizeof(EjsInput));
-       }
-       return input;
-}
-
-/******************************************************************************/
-
-static void freeInputStruct(Ejs *ep, EjsInput *input)
-{
-       input->nextInput = ep->inputList;
-       ep->inputList = input;
-}
-
-/******************************************************************************/
-
-static void *pushFrame(Ejs *ep, int size)
-{
-       /*
-        *      Grow down stack
-        */
-       ep->stkPtr -= size;
-       if (ep->stkPtr < ep->stack) {
-               mprError(ep, MPR_LOC, "Exceeded parse stack");
-               return 0;
-       }
-       return ep->stkPtr;
-}
-
-/******************************************************************************/
-
-static void *popFrame(Ejs *ep, int size)
-{
-       ep->stkPtr += size;
-       if (ep->stkPtr > &ep->stack[EJS_MAX_STACK]) {
-               mprError(ep, MPR_LOC, "Over poped parse stack");
-               return 0;
-       }
-       return ep->stkPtr;
-}
-
-/******************************************************************************/
-#else
-void ejsParserDummy() {}
-
-/******************************************************************************/
-#endif /* BLD_FEATURE_EJS */
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim:tw=78
- * vim600: sw=4 ts=4 fdm=marker
- * vim<600: sw=4 ts=4
- */