📄 ejsparser.c
字号:
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;}/******************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -