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 + -
显示快捷键?