ejsparser.c
来自「samba最新软件」· C语言 代码 · 共 2,437 行 · 第 1/4 页
C
2,437 行
if (ejsParse(ep, EJS_STATE_ARG_LIST, flags) != EJS_STATE_ARG_LIST_DONE) { freeProc(&proc); ep->proc = saveProc; return -1; } ep->currentObj = saveObj; /* * Evaluate the function if required */ if (flags & EJS_FLAGS_EXE) { if (evalFunction(ep, ep->currentObj, flags) < 0) { freeProc(&proc); ep->proc = saveProc; return -1; } } freeProc(&proc); ep->proc = saveProc; if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) { return -1; } return state;}/******************************************************************************//* * 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, char **fullName, int *fullNameLen, int *done){ int tid; mprFree(*id); *id = mprStrdup(ep->token);#if BLD_DEBUG *fullNameLen = mprReallocStrcat(fullName, MPR_MAX_VAR, *fullNameLen, 0, *id, NULL);#endif if (ep->currentObj == 0) { ep->currentObj = ejsFindObj(ep, state, *id, flags); } /* * Find the referenced variable and store it in currentProperty. */ ep->currentProperty = ejsFindProperty(ep, state, ep->currentObj, *id, flags); updateResult(ep, state, flags, ep->currentProperty);#if BLD_DEBUG if (ep->currentProperty && (ep->currentProperty->name == 0 || ep->currentProperty->name[0] == '\0')) { mprSetVarName(ep->currentProperty, *id); }#endif tid = ejsLexGetToken(ep, state); if (tid == EJS_TOK_LPAREN) { if (ep->currentProperty == 0 && (flags & EJS_FLAGS_EXE)) { ejsError(ep, "Function name not defined \"%s\"\n", *id); return -1; } ejsLexPutbackToken(ep, EJS_TOK_FUNCTION_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; } /* * 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, "Variable already defined \"%s\"\n", *id); return -1; }#endif /* * Create or overwrite if it already exists */ mprSetPropertyValue(ep->currentObj, *id, mprCreateUndefinedVar()); ep->currentProperty = 0; mprDestroyVar(&ep->result); } else if (flags & EJS_FLAGS_FOREACH) { if (ep->currentProperty == 0) { ep->currentProperty = mprCreatePropertyValue(ep->currentObj, *id, mprCreateUndefinedVar()); } } else { if (ep->currentProperty == 0) { if (ep->currentObj == ep->global || ep->currentObj == ep->local) { ejsError(ep, "Undefined variable \"%s\"\n", *id); return -1; } ep->currentProperty = mprCreatePropertyValue(ep->currentObj, *id, mprCreateUndefinedVar()); } } } ejsLexPutbackToken(ep, tid, ep->token); if (tid == EJS_TOK_RBRACKET || tid == EJS_TOK_COMMA || tid == EJS_TOK_IN) { *done = 1; } return state;}/******************************************************************************//* * Parse an "if" statement */static int parseIf(Ejs *ep, int state, int flags, int *done){ bool ifResult; int thenFlags, elseFlags, tid; if (state != EJS_STATE_STMT) { return -1; } if (ejsLexGetToken(ep, state) != EJS_TOK_LPAREN) { return -1; } /* * Evaluate the entire condition list "(condition)" */ if (ejsParse(ep, EJS_STATE_COND, flags) != EJS_STATE_COND_DONE) { return -1; } if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) { return -1; } /* * This is the "then" case. We need to always parse both cases and * execute only the relevant case. */ ifResult = mprVarToBool(&ep->result); if (ifResult) { thenFlags = flags; elseFlags = flags & ~EJS_FLAGS_EXE; } else { thenFlags = flags & ~EJS_FLAGS_EXE; elseFlags = flags; } /* * Process the "then" case. */ switch (ejsParse(ep, EJS_STATE_STMT, thenFlags)) { case EJS_STATE_RET: state = EJS_STATE_RET; return state; case EJS_STATE_STMT_DONE: break; default: return -1; } /* * Check to see if there is an "else" case */ removeNewlines(ep, state); tid = ejsLexGetToken(ep, state); if (tid != EJS_TOK_ELSE) { ejsLexPutbackToken(ep, tid, ep->token); *done = 1; return state; } /* * Process the "else" case. */ switch (ejsParse(ep, EJS_STATE_STMT, elseFlags)) { case EJS_STATE_RET: state = EJS_STATE_RET; return state; case EJS_STATE_STMT_DONE: break; default: return -1; } *done = 1; return state;}/******************************************************************************//* * Parse an "++" or "--" statement */static int parseInc(Ejs *ep, int state, int flags){ MprVar one; if (! (flags & EJS_FLAGS_EXE)) { return state; } if (ep->currentProperty == 0) { ejsError(ep, "Undefined variable \"%s\"\n", ep->token); return -1; } one = mprCreateIntegerVar(1); if (evalExpr(ep, ep->currentProperty, (int) *ep->token, &one) < 0) { return -1; } if (mprWriteProperty(ep->currentProperty, &ep->result) < 0) { ejsError(ep, "Can't write to variable\n"); return -1; } return state;}/******************************************************************************//* * Evaluate a condition. Implements &&, ||, !. Returns with a boolean result * in ep->result. Returns -1 on errors, zero if successful. */static int evalCond(Ejs *ep, MprVar *lhs, int rel, MprVar *rhs){ bool l, r, lval; mprAssert(rel > 0); l = mprVarToBool(lhs); r = mprVarToBool(rhs); switch (rel) { case EJS_COND_AND: lval = l && r; break; case EJS_COND_OR: lval = l || r; break; default: ejsError(ep, "Bad operator %d", rel); return -1; } mprCopyVarValue(&ep->result, mprCreateBoolVar(lval), 0); return 0;}/* return true if this string is a valid number*/static int string_is_number(const char *s){ char *endptr = NULL; if (s == NULL || *s == 0) { return 0; } strtod(s, &endptr); 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, MprVar *lhs, int rel, MprVar *rhs){ char *str; MprNum lval, num; 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. * * First convert objects to comparable types. The "===" operator will * test the sameness of object references. Here, we coerce to comparable * types first. */ if (lhs->type == MPR_TYPE_OBJECT) { if (ejsRunFunction(ep->eid, lhs, "toValue", 0) == 0) { mprCopyVar(lhs, &ep->result, MPR_SHALLOW_COPY); } else { if (ejsRunFunction(ep->eid, lhs, "toString", 0) == 0) { mprCopyVar(lhs, &ep->result, MPR_SHALLOW_COPY); } } /* Nothing more can be done */ } if (rhs->type == MPR_TYPE_OBJECT) { if (ejsRunFunction(ep->eid, rhs, "toValue", 0) == 0) { mprCopyVar(rhs, &ep->result, MPR_SHALLOW_COPY); } else { if (ejsRunFunction(ep->eid, rhs, "toString", 0) == 0) { mprCopyVar(rhs, &ep->result, MPR_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 == MPR_TYPE_UNDEFINED || rhs->type == MPR_TYPE_UNDEFINED) { return evalBoolExpr(ep, lhs->type == MPR_TYPE_UNDEFINED, rel, rhs->type == MPR_TYPE_UNDEFINED); } if (lhs->type == MPR_TYPE_NULL || rhs->type == MPR_TYPE_NULL) { return evalBoolExpr(ep, lhs->type == MPR_TYPE_NULL, rel, rhs->type == MPR_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 == MPR_TYPE_BOOL && rhs->type == MPR_TYPE_BOOL && (rel != EJS_EXPR_EQ && rel != EJS_EXPR_NOTEQ && rel != EJS_EXPR_BOOL_COMP)) { num = mprVarToNumber(lhs); mprDestroyVar(lhs); *lhs = mprCreateNumberVar(num); } /* * 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 == MPR_TYPE_STRING) { if (string_is_number(lhs->string)) { num = mprVarToNumber(lhs); lhs->allocatedVar = 0; mprDestroyVar(lhs); *lhs = mprCreateNumberVar(num); /* Examine further below */ } else { /* * Convert the RHS to a string */ mprVarToString(&str, MPR_MAX_STRING, 0, rhs); rhs->allocatedVar = 0; mprDestroyVar(rhs); *rhs = mprCreateStringVar(str, 1); mprFree(str); }#if BLD_FEATURE_FLOATING_POINT } else if (lhs->type == MPR_TYPE_FLOAT) { /* * Convert rhs to floating */ double f = mprVarToFloat(rhs); mprDestroyVar(rhs); *rhs = mprCreateFloatVar(f);#endif#if BLD_FEATURE_INT64 } else if (lhs->type == MPR_TYPE_INT64) { /* * Convert the rhs to 64 bit */ int64 n = mprVarToInteger64(rhs); mprDestroyVar(rhs); *rhs = mprCreateInteger64Var(n);#endif } else if (lhs->type == MPR_TYPE_BOOL || lhs->type == MPR_TYPE_INT) { if (rhs->type == MPR_TYPE_STRING) { /* * Convert to lhs to a string */ mprVarToString(&str, MPR_MAX_STRING, 0, lhs); mprDestroyVar(lhs); *lhs = mprCreateStringVar(str, 1); mprFree(str);#if BLD_FEATURE_FLOATING_POINT } else if (rhs->type == MPR_TYPE_FLOAT) { /* * Convert lhs to floating */ double f = mprVarToFloat(lhs); mprDestroyVar(lhs); *lhs = mprCreateFloatVar(f);#endif } else { /* * Convert both operands to numbers */ num = mprVarToNumber(lhs); mprDestroyVar(lhs); *lhs = mprCreateNumberVar(num); num = mprVarToNumber(rhs); mprDestroyVar(rhs); *rhs = mprCreateNumberVar(num); } } } /* * 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 == MPR_TYPE_UNDEFINED || lhs->type == MPR_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 = ! mprVarToBool(rhs); break; default: lval = 0; } mprCopyVarValue(&ep->result, mprCreateBoolVar((bool) lval), 0); return 0; } /* * Types are the same here */ switch (lhs->type) { default: case MPR_TYPE_UNDEFINED: case MPR_TYPE_NULL: /* Should be handled above */ mprAssert(0); return 0; case MPR_TYPE_STRING_CFUNCTION: case MPR_TYPE_CFUNCTION: case MPR_TYPE_FUNCTION: case MPR_TYPE_OBJECT: mprCopyVarValue(&ep->result, mprCreateBoolVar(0), 0); return 0; case MPR_TYPE_PTR: rc = evalPtrExpr(ep, lhs->ptr, rel, rhs->ptr); break; case MPR_TYPE_BOOL: rc = evalBoolExpr(ep, lhs->boolean, rel, rhs->boolean); break;#if BLD_FEATURE_FLOATING_POINT case MPR_TYPE_FLOAT: rc = evalFloatExpr(ep, lhs->floating, rel, rhs->floating); break;#endif case MPR_TYPE_INT: rc = evalNumericExpr(ep, (MprNum) lhs->integer, rel, (MprNum) rhs->integer); break;#if BLD_FEATURE_INT64 case MPR_TYPE_INT64: rc = evalNumericExpr(ep, (MprNum) lhs->integer64, rel, (MprNum) rhs->integer64); break;#endif case MPR_TYPE_STRING: rc = evalStringExpr(ep, lhs, rel, rhs); } return rc;}/******************************************************************************/#if BLD_FEATURE_FLOATING_POINT/* * Expressions with floating operands */static int evalFloatExpr(Ejs *ep, double l, int rel, double r) { double lval; bool 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, "Bad operator %d", rel); return -1; } mprCopyVarValue(&ep->result, mprCreateBoolVar(lval != 0), 0); } else { mprCopyVarValue(&ep->result, mprCreateFloatVar(lval), 0); } return 0;}#endif /* BLD_FEATURE_FLOATING_POINT *//******************************************************************************//* * Expressions with boolean operands */static int evalBoolExpr(Ejs *ep, bool l, int rel, bool r) { bool lval; switch (rel) { case EJS_EXPR_EQ:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?