📄 ejsparser.c
字号:
/* * @file ejsParser.c * @brief EJS Parser and Execution *//********************************* Copyright **********************************//* * @copy default.g * * Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved. * Portions Copyright (c) GoAhead Software, 1995-2000. All Rights Reserved. * * This software is distributed under commercial and open source licenses. * You may use the GPL open source license described below or you may acquire * a commercial license from Mbedthis Software. You agree to be fully bound * by the terms of either license. Consult the LICENSE.TXT distributed with * this software for full details. * * This software is open source; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See the GNU General Public License for more * details at: http://www.mbedthis.com/downloads/gplLicense.html * * This program is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * This GPL license does NOT permit incorporating this software into * proprietary programs. If you are unable to comply with the GPL, you must * acquire a commercial license to use this software. Commercial licenses * for this software and support services are available from Mbedthis * Software at http://www.mbedthis.com * * @end *//********************************** Includes **********************************/#include "ejs.h"#if BLD_FEATURE_EJS/****************************** Forward Declarations **************************/static int createClass(Ejs *ep, EjsVar *parentClass, const char *className, EjsVar *baseClass);static int createProperty(Ejs *ep, EjsVar **obj, const char *id, int state);static int evalCond(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs);static int evalExpr(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs);#if BLD_FEATURE_FLOATING_POINTstatic int evalFloatExpr(Ejs *ep, double l, int rel, double r);#endif static int evalBoolExpr(Ejs *ep, int l, int rel, int r);static int evalNumericExpr(Ejs *ep, EjsNum l, int rel, EjsNum r);static int evalObjExpr(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs) ;static int evalStringExpr(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs);static int evalMethod(Ejs *ep, EjsVar *obj, EjsProc *proc, int flags);static EjsProperty *findProperty(Ejs *ep, EjsVar *op, const char *property, int flags);static EjsVar *pickSpace(Ejs *ep, int state, const char *property, int flags);static void freeProc(Ejs *ep, EjsProc *proc);static int parseArgs(Ejs *ep, int state, int flags);static int parseArrayLiteral(Ejs *ep, int state, int flags, char *id);static int parseAssignment(Ejs *ep, int state, int flags, char *id);static int parseClass(Ejs *ep, int state, int flags);static int parseForInner(Ejs *ep, int state, int flags, EjsInput *condScript, EjsInput *incrScript, EjsInput *bodyScript, EjsInput *endScript);static int parseCond(Ejs *ep, int state, int flags);static int parseDeclaration(Ejs *ep, int state, int flags);static int parseExpr(Ejs *ep, int state, int flags);static int parseFor(Ejs *ep, int state, int flags);static int parseRegFor(Ejs *ep, int state, int flags);static int parseForIn(Ejs *ep, int state, int flags, int each);static int parseId(Ejs *ep, int state, int flags, char **id, int *done);static int parseInc(Ejs *ep, int state, int flags);static int parseIf(Ejs *ep, int state, int flags, int *done);static int parseFunction(Ejs *ep, int state, int flags);static int parseMethod(Ejs *ep, int state, int flags, char *id);static int parseObjectLiteral(Ejs *ep, int state, int flags, char *id);static int parseStmt(Ejs *ep, int state, int flags);static int parseThrow(Ejs *ep, int state, int flags);static int parseTry(Ejs *ep, int state, int flags);static void removeNewlines(Ejs *ep, int state);static EjsProperty *searchSpacesForProperty(Ejs *ep, int state, EjsVar *obj, char *property, int flags);static int assignPropertyValue(Ejs *ep, char *id, int state, EjsVar *value, int flags);static int updateProperty(Ejs *ep, EjsVar *obj, const char *id, int state, EjsVar *value);static void updateResult(Ejs *ep, int state, int flags, EjsVar *vp);static int getNextNonSpaceToken(Ejs *ep, int state);static int callConstructor(Ejs *ep, EjsVar *thisObj, EjsVar *baseClass, MprArray *args);static int callCMethod(Ejs *ep, EjsVar *obj, EjsProc *proc, EjsVar *prototype);static int callStringCMethod(Ejs *ep, EjsVar *obj, EjsProc *proc, EjsVar *prototype);static int callMethod(Ejs *ep, EjsVar *obj, EjsProc *proc, EjsVar *prototype);static int runMethod(Ejs *ep, EjsVar *thisObj, EjsVar *method, const char *methodName, MprArray *args);static EjsInput *getInputStruct(Ejs *ep);static void freeInputStruct(Ejs *ep, EjsInput *input);static void *pushFrame(Ejs *ep, int size);static void *popFrame(Ejs *ep, int size);/************************************* Code ***********************************//* * Recursive descent parser for EJS */int ejsParse(Ejs *ep, int state, int flags){ mprAssert(ep);#if MOB if (mprStackCheck(ep)) { char *stack; stack = ejsFormatStack(ep); mprLog(ep, 0, "\nStack grew : MAX %d\n", mprStackSize(ep)); mprLog(ep, 0, "Stack\n %s\n", stack); mprFree(stack); }#endif if (ep->flags & EJS_FLAGS_EXIT) { return EJS_STATE_RET; } ep->inputMarker = ep->input->scriptServp; switch (state) { /* * Any statement, method arguments or conditional expressions */ case EJS_STATE_STMT: state = parseStmt(ep, state, flags); if (state != EJS_STATE_STMT_BLOCK_DONE && state != EJS_STATE_STMT_DONE){ goto err; } break; case EJS_STATE_DEC: state = parseStmt(ep, state, flags); if (state != EJS_STATE_DEC_DONE) { goto err; } break; case EJS_STATE_EXPR: state = parseStmt(ep, state, flags); if (state != EJS_STATE_EXPR_DONE) { goto err; } break; /* * Variable declaration list */ case EJS_STATE_DEC_LIST: state = parseDeclaration(ep, state, flags); if (state != EJS_STATE_DEC_LIST_DONE) { goto err; } break; /* * Method argument string */ case EJS_STATE_ARG_LIST: state = parseArgs(ep, state, flags); if (state != EJS_STATE_ARG_LIST_DONE) { goto err; } break; /* * Logical condition list (relational operations separated by &&, ||) */ case EJS_STATE_COND: state = parseCond(ep, state, flags); if (state != EJS_STATE_COND_DONE) { goto err; } break; /* * Expression list */ case EJS_STATE_RELEXP: state = parseExpr(ep, state, flags); if (state != EJS_STATE_RELEXP_DONE) { goto err; } break; } /* * Recursion protection */ if (ep->input->scriptServp == ep->inputMarker) { if (ep->recurseCount++ > 20) { ejsSyntaxError(ep, "Input syntax error"); state = EJS_STATE_ERR; } } else { ep->recurseCount = 0; } if (state == EJS_STATE_RET || state == EJS_STATE_EOF) { return state; }done: return state;err: if (state == EJS_STATE_RET || state == EJS_STATE_EOF) { goto done; } if (state != EJS_STATE_ERR) { ejsSyntaxError(ep, 0); } state = EJS_STATE_ERR; goto done;}/******************************************************************************//* * Local vars */typedef struct ParseStmt { EjsProc *saveProc; EjsProperty *pp; EjsVar *saveObj, *exception; char *str, *id; int done, tid, rs, saveObjPerm, expectEndOfStmt;} ParseStmt;/* * Parse expression (leftHandSide operator rightHandSide) */static int parseStmt(Ejs *ep, int state, int flags){ ParseStmt *sp; mprAssert(ep); if ((sp = pushFrame(ep, sizeof(ParseStmt))) == 0) { return EJS_STATE_ERR; } sp->id = 0; sp->expectEndOfStmt = 0; sp->saveProc = NULL; ep->currentObj = 0; ep->currentProperty = 0; for (sp->done = 0; !sp->done && state != EJS_STATE_ERR; ) { sp->tid = ejsLexGetToken(ep, state);#if (WIN || BREW_SIMULATOR) && BLD_DEBUG && DISABLED /* MOB -- make cross platform */ _CrtCheckMemory();#endif switch (sp->tid) { default: ejsLexPutbackToken(ep, sp->tid, ep->token); goto done; case EJS_TOK_EXPR: if (state == EJS_STATE_EXPR) { ejsLexPutbackToken(ep, EJS_TOK_EXPR, ep->token); } goto done; case EJS_TOK_LOGICAL: ejsLexPutbackToken(ep, sp->tid, ep->token); goto done; case EJS_TOK_ERR: if (state != EJS_STATE_ERR && !ep->gotException) { ejsSyntaxError(ep, 0); } state = EJS_STATE_ERR; goto done; case EJS_TOK_EOF: state = EJS_STATE_EOF; goto done; case EJS_TOK_NEWLINE: break; case EJS_TOK_SEMI: /* * This case is when we discover no statement and just a lone ';' */ if (state != EJS_STATE_STMT) { ejsLexPutbackToken(ep, sp->tid, ep->token); } goto done; case EJS_TOK_LBRACKET: if (flags & EJS_FLAGS_EXE) { ep->currentObj = &ep->currentProperty->var; if (ep->currentObj != 0 && ep->currentObj->type != EJS_TYPE_OBJECT) { ejsError(ep, EJS_REFERENCE_ERROR, "Property reference to a non-object type \"%s\"\n", sp->id); goto err; } } sp->saveObj = ep->currentObj; sp->saveObjPerm = ejsMakeObjPermanent(sp->saveObj, 1); sp->rs = ejsParse(ep, EJS_STATE_RELEXP, flags); ejsMakeObjPermanent(sp->saveObj, sp->saveObjPerm); ep->currentObj = sp->saveObj; if (sp->rs < 0) { state = sp->rs; goto done; } mprFree(sp->id); /* MOB rc */ sp->str = ejsVarToString(ep, ep->result); sp->id = mprStrdup(ep, sp->str); if (sp->id[0] == '\0') { if (flags & EJS_FLAGS_EXE) { ejsError(ep, EJS_RANGE_ERROR, "[] expression evaluates to the empty string\n"); goto err; } } else { sp->pp = searchSpacesForProperty(ep, state, ep->currentObj, sp->id, flags); ep->currentProperty = sp->pp; updateResult(ep, state, flags, ejsGetVarPtr(sp->pp)); } if ((sp->tid = ejsLexGetToken(ep, state)) != EJS_TOK_RBRACKET) { ejsSyntaxError(ep, "Missing ']'"); goto err; } break; case EJS_TOK_PERIOD: if (flags & EJS_FLAGS_EXE) { if (ep->currentProperty == 0) { ejsError(ep, EJS_REFERENCE_ERROR, "Undefined object \"%s\"", sp->id); goto err; } } ep->currentObj = &ep->currentProperty->var; if (flags & EJS_FLAGS_EXE) { if (ep->currentObj != 0 && ep->currentObj->type != EJS_TYPE_OBJECT) { ejsError(ep, EJS_REFERENCE_ERROR, "Property reference to a non-object type \"%s\"\n", sp->id); goto err; } } if ((sp->tid = ejsLexGetToken(ep, state)) != EJS_TOK_ID) { ejsError(ep, EJS_REFERENCE_ERROR, "Bad property after '.': %s", ep->token); goto err; } /* Fall through */ case EJS_TOK_ID: state = parseId(ep, state, flags, &sp->id, &sp->done); if (sp->done && state == EJS_STATE_STMT) { sp->expectEndOfStmt = 1; } break; case EJS_TOK_ASSIGNMENT: sp->tid = ejsLexGetToken(ep, state); if (sp->tid == EJS_TOK_LBRACE) { /* * var = { name: value, name: value, ... } */ if (parseObjectLiteral(ep, state, flags, sp->id) < 0) { ejsSyntaxError(ep, "Bad object literal"); goto err; } } else if (sp->tid == EJS_TOK_LBRACKET) { /* * var = [ array elements ] */ if (parseArrayLiteral(ep, state, flags, sp->id) < 0) { ejsSyntaxError(ep, "Bad array literal"); goto err; } } else if (sp->tid == EJS_TOK_EXPR && (int) *ep->token == EJS_EXPR_LESS) { /* * var = <xmlTag> .../</xmlTag> */ ejsSyntaxError(ep, "XML literals are not yet supported"); goto err; } else { /* * var = expression */ ejsLexPutbackToken(ep, sp->tid, ep->token); state = parseAssignment(ep, state, flags, sp->id); if (state == EJS_STATE_ERR) { if (ep->flags & EJS_FLAGS_EXIT) { state = EJS_STATE_RET; goto done; } if (!ep->gotException) { ejsSyntaxError(ep, 0); } goto err; } } if (flags & EJS_FLAGS_EXE) { if (assignPropertyValue(ep, sp->id, state, ep->result, flags) < 0) { if (ep->gotException == 0) { ejsError(ep, EJS_EVAL_ERROR, "Can't set property %s", sp->id); } goto err; } } if (state == EJS_STATE_STMT) { sp->expectEndOfStmt = 1; goto done; } break; case EJS_TOK_INC_DEC: state = parseInc(ep, state, flags); if (state == EJS_STATE_STMT) { sp->expectEndOfStmt = 1; } break; case EJS_TOK_NEW: /* MOB -- could we remove rs and just use state */ sp->rs = ejsParse(ep, EJS_STATE_EXPR, flags | EJS_FLAGS_NEW); if (sp->rs < 0) { state = sp->rs; goto done; } break; case EJS_TOK_DELETE: sp->rs = ejsParse(ep, EJS_STATE_EXPR, flags | EJS_FLAGS_DELETE); if (sp->rs < 0) { state = sp->rs; goto done; } if (flags & EJS_FLAGS_EXE) { /* Single place where properties are deleted */ if (ep->currentObj == 0 || ep->currentProperty == 0) { ejsError(ep, EJS_EVAL_ERROR, "Can't find property to delete"); goto err; } if (ep->currentObj->isArray) { ejsSetArrayLength(ep, ep->currentObj, 0, ep->currentProperty->name, 0); } ejsDeleteProperty(ep, ep->currentObj, ep->currentProperty->name); ep->currentProperty = 0; } goto done; case EJS_TOK_FUNCTION: /* * Parse a function declaration */ state = parseFunction(ep, state, flags); goto done; case EJS_TOK_THROW: state = parseThrow(ep, state, flags); goto done; case EJS_TOK_TRY: state = parseTry(ep, state, flags); goto done; case EJS_TOK_CLASS: case EJS_TOK_MODULE: state = parseClass(ep, state, flags); goto done; case EJS_TOK_LITERAL: /* * Set the result to the string literal */ if (flags & EJS_FLAGS_EXE) { ejsWriteVarAsString(ep, ep->result, ep->token); ejsSetVarName(ep, ep->result, ""); } if (state == EJS_STATE_STMT) { sp->expectEndOfStmt = 1; } goto done; case EJS_TOK_NUMBER: /* * Set the result to the parsed number */ if (flags & EJS_FLAGS_EXE) { ejsWriteVar(ep, ep->result, &ep->tokenNumber, 0); } if (state == EJS_STATE_STMT) { sp->expectEndOfStmt = 1; } goto done; case EJS_TOK_METHOD_NAME: /* * parse a method() invocation */ mprAssert(ep->currentObj); state = parseMethod(ep, state, flags, sp->id); if (state == EJS_STATE_STMT) { sp->expectEndOfStmt = 1; } if (ep->flags & EJS_FLAGS_EXIT) { state = EJS_STATE_RET; } goto done; case EJS_TOK_IF: state = parseIf(ep, state, flags, &sp->done); if (state < 0) { goto done; } break; case EJS_TOK_FOR: state = parseFor(ep, state, flags); goto done; case EJS_TOK_VAR: if ((sp->rs = ejsParse(ep, EJS_STATE_DEC_LIST, flags)) < 0) { state = sp->rs; goto done; } goto done;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -