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