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