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