ejsparser.c
来自「samba最新软件」· C语言 代码 · 共 2,437 行 · 第 1/4 页
C
2,437 行
if (ep->currentProperty) { /* * Update the variable. Update the property name if not * yet defined. */ if (ep->currentProperty->name == 0 || ep->currentProperty->name[0] == '\0') { mprSetVarName(ep->currentProperty, id); } if (mprWriteProperty(ep->currentProperty, &ep->result) < 0){ ejsError(ep, "Can't write to variable\n"); return -1; } } else { /* * Create the variable */ if (ep->currentObj) { if (ep->currentObj->type != MPR_TYPE_OBJECT) { if (strcmp(ep->currentObj->name, "session") == 0) { ejsError(ep, "Variable \"%s\" is not an array or object." "If using ESP, you need useSession(); in your page.", ep->currentObj->name); } else { ejsError(ep, "Variable \"%s\" is not an array or object", ep->currentObj->name); } return -1; } vp = mprCreateProperty(ep->currentObj, id, &ep->result); } else { /* * Standard says: "var x" means declare locally. * "x = 2" means declare globally if x is undefined. */ if (state == EJS_STATE_DEC) { vp = mprCreateProperty(ep->local, id, &ep->result); } else { vp = mprCreateProperty(ep->global, id, &ep->result); } }#if BLD_DEBUG mprSetVarFullName(vp, fullName);#endif } return state;}/******************************************************************************//* * Parse conditional expression (relational ops separated by ||, &&) */static int parseCond(Ejs *ep, int state, int flags){ MprVar lhs, rhs; int tid, operator; mprAssert(ep); mprDestroyVar(&ep->result); rhs = lhs = mprCreateUndefinedVar(); 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 != EJS_STATE_RELEXP_DONE) { state = EJS_STATE_ERR; break; } if (operator > 0) { mprCopyVar(&rhs, &ep->result, MPR_SHALLOW_COPY); if (evalCond(ep, &lhs, operator, &rhs) < 0) { state = EJS_STATE_ERR; break; } } mprCopyVar(&lhs, &ep->result, MPR_SHALLOW_COPY); tid = ejsLexGetToken(ep, state); if (tid == EJS_TOK_LOGICAL) { operator = (int) *ep->token; } else if (tid == EJS_TOK_RPAREN || tid == EJS_TOK_SEMI) { ejsLexPutbackToken(ep, tid, ep->token); state = EJS_STATE_COND_DONE; break; } else { ejsLexPutbackToken(ep, tid, ep->token); } tid = (state == EJS_STATE_RELEXP_DONE); } while (state == EJS_STATE_RELEXP_DONE); mprDestroyVar(&lhs); mprDestroyVar(&rhs); 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; * * 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) { 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 */ tid = ejsLexGetToken(ep, state); if (tid == EJS_TOK_SEMI) { return EJS_STATE_DEC_LIST_DONE; } else if (tid != EJS_TOK_COMMA) { return EJS_STATE_ERR; } } while (tid == EJS_TOK_COMMA); if (tid != EJS_TOK_SEMI) { return EJS_STATE_ERR; } return EJS_STATE_DEC_LIST_DONE;}/******************************************************************************//* * Parse expression (leftHandSide operator rightHandSide) */static int parseExpr(Ejs *ep, int state, int flags){ MprVar lhs, rhs; int rel, tid; mprAssert(ep); mprDestroyVar(&ep->result); rhs = lhs = mprCreateUndefinedVar(); rel = 0; tid = 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 (tid == EJS_TOK_LOGICAL) { state = ejsParse(ep, EJS_STATE_RELEXP, flags); if (state != EJS_STATE_RELEXP_DONE) { state = EJS_STATE_ERR; break; } } else { tid = ejsLexGetToken(ep, state); if (tid == EJS_TOK_EXPR && (int) *ep->token == EJS_EXPR_MINUS) { lhs = mprCreateIntegerVar(0); rel = (int) *ep->token; } else { ejsLexPutbackToken(ep, tid, ep->token); } state = ejsParse(ep, EJS_STATE_EXPR, flags); if (state != EJS_STATE_EXPR_DONE) { state = EJS_STATE_ERR; break; } } if (rel > 0) { mprCopyVar(&rhs, &ep->result, MPR_SHALLOW_COPY); if (tid == EJS_TOK_LOGICAL) { if (evalCond(ep, &lhs, rel, &rhs) < 0) { state = EJS_STATE_ERR; break; } } else { if (evalExpr(ep, &lhs, rel, &rhs) < 0) { state = EJS_STATE_ERR; break; } } } mprCopyVar(&lhs, &ep->result, MPR_SHALLOW_COPY); if ((tid = ejsLexGetToken(ep, state)) == EJS_TOK_EXPR || tid == EJS_TOK_INC_DEC || tid == EJS_TOK_LOGICAL) { rel = (int) *ep->token; } else { ejsLexPutbackToken(ep, tid, ep->token); state = EJS_STATE_RELEXP_DONE; } } while (state == EJS_STATE_EXPR_DONE); mprDestroyVar(&lhs); mprDestroyVar(&rhs); return state;}/******************************************************************************//* * Parse the "for ... in" statement. Format for the statement is: * * for (var in expr) { * body; * } */static int parseForIn(Ejs *ep, int state, int flags){ EjsInput endScript, bodyScript; MprVar *iteratorVar, *setVar, *vp, v; int forFlags, tid; mprAssert(ep); tid = ejsLexGetToken(ep, state); if (tid != EJS_TOK_ID) { return -1; } ejsLexPutbackToken(ep, tid, ep->token); if (ejsParse(ep, EJS_STATE_EXPR, EJS_FLAGS_FOREACH | EJS_FLAGS_EXE) != EJS_STATE_EXPR_DONE) { return -1; } if (ep->currentProperty == 0) { return -1; } iteratorVar = ep->currentProperty; if (ejsLexGetToken(ep, state) != EJS_TOK_IN) { return -1; } /* * Get the set */ tid = ejsLexGetToken(ep, state); if (tid != EJS_TOK_ID) { return -1; } ejsLexPutbackToken(ep, tid, ep->token); if (ejsParse(ep, EJS_STATE_EXPR, flags) != EJS_STATE_EXPR_DONE) { return -1; } if (ep->currentProperty == 0 && flags & EJS_FLAGS_EXE) { return -1; } setVar = ep->currentProperty; if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) { return -1; } /* * Parse the body and remember the end of the body script */ forFlags = flags & ~EJS_FLAGS_EXE; ejsLexSaveInputState(ep, &bodyScript); if (ejsParse(ep, EJS_STATE_STMT, forFlags) != EJS_STATE_STMT_DONE) { ejsLexFreeInputState(ep, &bodyScript); return -1; } ejsInitInputState(&endScript); ejsLexSaveInputState(ep, &endScript); /* * Now actually do the for loop. */ if (flags & EJS_FLAGS_EXE) { if (setVar->type == MPR_TYPE_OBJECT) { vp = mprGetFirstProperty(setVar, MPR_ENUM_DATA); while (vp) { if (strcmp(vp->name, "length") != 0) { v = mprCreateStringVar(vp->name, 0); if (mprWriteProperty(iteratorVar, &v) < 0) { ejsError(ep, "Can't write to variable\n"); ejsLexFreeInputState(ep, &bodyScript); ejsLexFreeInputState(ep, &endScript); return -1; } ejsLexRestoreInputState(ep, &bodyScript); switch (ejsParse(ep, EJS_STATE_STMT, flags)) { case EJS_STATE_RET: return EJS_STATE_RET; case EJS_STATE_STMT_DONE: break; default: ejsLexFreeInputState(ep, &endScript); ejsLexFreeInputState(ep, &bodyScript); return -1; } } vp = mprGetNextProperty(setVar, vp, MPR_ENUM_DATA); } } else { ejsError(ep, "Variable \"%s\" is not an array or object", setVar->name); ejsLexFreeInputState(ep, &endScript); ejsLexFreeInputState(ep, &bodyScript); return -1; } } ejsLexRestoreInputState(ep, &endScript); ejsLexFreeInputState(ep, &endScript); ejsLexFreeInputState(ep, &bodyScript); return state;}/******************************************************************************//* * Parse the for statement. Format for the expression is: * * for (initial; condition; incr) { * body; * } */static int parseFor(Ejs *ep, int state, int flags){ EjsInput condScript, endScript, bodyScript, incrScript; int forFlags, cond; ejsInitInputState(&endScript); ejsInitInputState(&bodyScript); ejsInitInputState(&incrScript); ejsInitInputState(&condScript); mprAssert(ep); /* * Evaluate the for loop initialization statement */ if (ejsParse(ep, EJS_STATE_EXPR, flags) != EJS_STATE_EXPR_DONE) { return -1; } if (ejsLexGetToken(ep, state) != EJS_TOK_SEMI) { return -1; } /* * 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 (ejsParse(ep, EJS_STATE_COND, flags) != EJS_STATE_COND_DONE) { goto error; } cond = (ep->result.boolean != 0); if (ejsLexGetToken(ep, state) != EJS_TOK_SEMI) { goto error; } /* * Don't execute the loop increment statement or the body * first time. */ forFlags = flags & ~EJS_FLAGS_EXE; ejsLexSaveInputState(ep, &incrScript); if (ejsParse(ep, EJS_STATE_EXPR, forFlags) != EJS_STATE_EXPR_DONE) { goto error; } if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) { goto error; } /* * Parse the body and remember the end of the body script */ ejsLexSaveInputState(ep, &bodyScript); if (ejsParse(ep, EJS_STATE_STMT, forFlags) != EJS_STATE_STMT_DONE) { goto error; } 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); switch (ejsParse(ep, EJS_STATE_STMT, flags)) { case EJS_STATE_RET: return EJS_STATE_RET; case EJS_STATE_STMT_DONE: break; default: goto error; } /* * Evaluate the increment script */ ejsLexRestoreInputState(ep, &incrScript); if (ejsParse(ep, EJS_STATE_EXPR, flags) != EJS_STATE_EXPR_DONE){ goto error; } /* * Evaluate the condition */ ejsLexRestoreInputState(ep, &condScript); if (ejsParse(ep, EJS_STATE_COND, flags) != EJS_STATE_COND_DONE) { goto error; } mprAssert(ep->result.type == MPR_TYPE_BOOL); cond = (ep->result.boolean != 0); } ejsLexRestoreInputState(ep, &endScript);done: ejsLexFreeInputState(ep, &condScript); ejsLexFreeInputState(ep, &incrScript); ejsLexFreeInputState(ep, &endScript); ejsLexFreeInputState(ep, &bodyScript); return state;error: state = EJS_STATE_ERR; goto done;}/******************************************************************************//* * Parse a function declaration */static int parseFunctionDec(Ejs *ep, int state, int flags){ EjsInput endScript, bodyScript; MprVar v, *currentObj, *vp; char *procName; int len, tid, bodyFlags; mprAssert(ep); mprAssert(ejsPtr(ep->eid)); /* * function <name>(arg, arg, arg) { body }; * function name(arg, arg, arg) { body }; */ tid = ejsLexGetToken(ep, state); if (tid == EJS_TOK_ID) { procName = mprStrdup(ep->token); tid = ejsLexGetToken(ep, state); } else { procName = 0; } if (tid != EJS_TOK_LPAREN) { mprFree(procName); return EJS_STATE_ERR; } /* * Hand craft the function value structure. */ v = mprCreateFunctionVar(0, 0, 0); tid = ejsLexGetToken(ep, state); while (tid == EJS_TOK_ID) { mprAddToArray(v.function.args, mprStrdup(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); mprDestroyVar(&v); 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); mprDestroyVar(&v); return EJS_STATE_ERR; } /* * Register the function name early to allow for recursive * function calls (see note in ECMA standard, page 71) */ if (!(flags & EJS_FLAGS_ASSIGNMENT)) { currentObj = ejsFindObj(ep, 0, procName, flags); vp = mprSetProperty(currentObj, procName, &v); } /* * Parse the function body. Turn execute off. */ bodyFlags = flags & ~EJS_FLAGS_EXE; ejsLexSaveInputState(ep, &bodyScript); do { state = ejsParse(ep, EJS_STATE_STMT, bodyFlags); } while (state == EJS_STATE_STMT_DONE); tid = ejsLexGetToken(ep, state); if (state != EJS_STATE_STMT_BLOCK_DONE || tid != EJS_TOK_RBRACE) { mprFree(procName); mprDestroyVar(&v); ejsLexFreeInputState(ep, &bodyScript); return EJS_STATE_ERR; } ejsLexSaveInputState(ep, &endScript); /* * Save the function body between the starting and ending parse positions. * Overwrite the trailing '}' with a null. */ len = endScript.scriptServp - bodyScript.scriptServp; v.function.body = mprMalloc(len + 1); memcpy(v.function.body, bodyScript.scriptServp, len); if (len <= 0) { v.function.body[0] = '\0'; } else { v.function.body[len - 1] = '\0'; } ejsLexFreeInputState(ep, &bodyScript); ejsLexFreeInputState(ep, &endScript); /* * If we are in an assignment, don't register the function name, rather * return the function structure in the parser result. */ if (flags & EJS_FLAGS_ASSIGNMENT) { mprCopyVar(&ep->result, &v, MPR_SHALLOW_COPY); } else { currentObj = ejsFindObj(ep, 0, procName, flags); vp = mprSetProperty(currentObj, procName, &v); } mprFree(procName); mprDestroyVar(&v); return EJS_STATE_STMT;}/******************************************************************************//* * Parse a function name and invoke the function */static int parseFunction(Ejs *ep, int state, int flags, char *id){ EjsProc proc, *saveProc; MprVar *saveObj; /* * Must save any current ep->proc value for the current stack frame * to allow for recursive function calls. */ saveProc = (ep->proc) ? ep->proc: 0; memset(&proc, 0, sizeof(EjsProc)); proc.procName = mprStrdup(id); proc.fn = ep->currentProperty; proc.args = mprCreateArray(); ep->proc = &proc; mprDestroyVar(&ep->result); saveObj = ep->currentObj;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?