⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ejsparser.c

📁 samba最新软件
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *	Parse a function declaration */static int parseFunction(Ejs *ep, int state, int flags){	EjsInput	*endScript, *bodyScript;	EjsProperty	*pp;	EjsVar		*func, *funcProp, *currentObj, *vp, *baseClass;	char		*procName;	int			varFlags, len, tid, bodyFlags, innerState;	mprAssert(ep);	func = 0;	varFlags = 0;	/*		 *	method <name>(arg, arg, arg) { body };	 *	method name(arg, arg, arg) { body };	 */	tid = ejsLexGetToken(ep, state);	if (tid == EJS_TOK_GET) {		varFlags |= EJS_GET_ACCESSOR;		tid = ejsLexGetToken(ep, state);	} else if (tid == EJS_TOK_SET) {		varFlags |= EJS_SET_ACCESSOR;		tid = ejsLexGetToken(ep, state);	} 	if (tid == EJS_TOK_ID) {		if (varFlags & EJS_SET_ACCESSOR) {			if (mprAllocStrcat(MPR_LOC_ARGS(ep), &procName, EJS_MAX_ID + 5, 					0, "-set-", ep->token, 0) < 0) {				ejsError(ep, EJS_SYNTAX_ERROR, 					"Name %s is too long", ep->token);				return EJS_STATE_ERR;			}		} else {			procName = mprStrdup(ep, ep->token);		}		tid = ejsLexGetToken(ep, state);	}  else {		procName = 0;	}	if (tid != EJS_TOK_LPAREN) {		mprFree(procName);		ejsSyntaxError(ep, 0);		return EJS_STATE_ERR;	}	/* 	 *	Hand craft the method value structure.	 */	if (flags & EJS_FLAGS_EXE) {		func = ejsCreateMethodVar(ep, 0, 0, 0);		if (func == 0) {			mprFree(procName);			ejsMemoryError(ep);			return EJS_STATE_ERR;		}		func->flags = varFlags;	}	tid = ejsLexGetToken(ep, state);	while (tid == EJS_TOK_ID) {		if (flags & EJS_FLAGS_EXE) {			mprAddItem(func->method.args, 				mprStrdup(func->method.args, 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);		ejsFreeVar(ep, func);		ejsSyntaxError(ep, 0);		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);		ejsFreeVar(ep, func);		ejsSyntaxError(ep, 0);		return EJS_STATE_ERR;	}		/* 	 *	Register the method name early to allow for recursive	 *	method calls (see note in ECMA standard, page 71) 	 */	funcProp = 0;	if (flags & EJS_FLAGS_EXE && procName) {		currentObj = pickSpace(ep, 0, procName, flags | EJS_FLAGS_LOCAL);		pp = ejsSetProperty(ep, currentObj, procName, func);		if (pp == 0) {			ejsFreeVar(ep, func);			ejsMemoryError(ep);			return EJS_STATE_ERR;		}		funcProp = ejsGetVarPtr(pp);	}		bodyScript = getInputStruct(ep);	/*	 *	Parse the method body. Turn execute off.	 */	bodyFlags = flags & ~EJS_FLAGS_EXE;	ejsLexSaveInputState(ep, bodyScript);	do {		innerState = ejsParse(ep, EJS_STATE_STMT, bodyFlags);	} while (innerState == EJS_STATE_STMT_DONE);	tid = ejsLexGetToken(ep, state);	if (innerState != EJS_STATE_STMT_BLOCK_DONE || tid != EJS_TOK_RBRACE) {		mprFree(procName);		ejsFreeVar(ep, func);		ejsLexFreeInputState(ep, bodyScript);		if (innerState != EJS_STATE_ERR) {			ejsSyntaxError(ep, 0);		}		freeInputStruct(ep, bodyScript);		return EJS_STATE_ERR;	}	if (flags & EJS_FLAGS_EXE) {		endScript = getInputStruct(ep);		ejsLexSaveInputState(ep, endScript);		/*		 *	Save the method body between the starting and ending parse 		 *	positions. Overwrite the trailing '}' with a null.		 */		len = endScript->scriptServp - bodyScript->scriptServp;		func->method.body = mprAlloc(ep, len + 1);		memcpy(func->method.body, bodyScript->scriptServp, len);		if (len <= 0) {			func->method.body[0] = '\0';		} else {			func->method.body[len - 1] = '\0';		}		ejsLexFreeInputState(ep, bodyScript);		ejsLexFreeInputState(ep, endScript);		freeInputStruct(ep, endScript);		/*		 *	If we are in an assignment, don't register the method name, rather		 *	return the method structure in the parser result.		 */		if (procName) {			currentObj = pickSpace(ep, 0, procName, flags | EJS_FLAGS_LOCAL);			pp = ejsSetProperty(ep, currentObj, procName, func);			if (pp == 0) {				ejsFreeVar(ep, func);				ejsMemoryError(ep);				return EJS_STATE_ERR;			}			if (currentObj->objectState->className &&				strcmp(currentObj->objectState->className, procName) == 0) {				baseClass = currentObj->objectState->baseClass;				if (baseClass) {					if (strstr(func->method.body, "super(") != 0) {						funcProp->callsSuper = 1;						/*						 *	Define super() to point to the baseClass constructor						 */						vp = ejsGetPropertyAsVar(ep, baseClass, 							baseClass->objectState->className);						if (vp) {							mprAssert(vp);							if (ejsSetProperty(ep, currentObj, "super", 									vp) == 0) {								ejsFreeVar(ep, func);								ejsMemoryError(ep);								return EJS_STATE_ERR;							}						}					}				}			}		}		/*		 *	Always return the function. Try for all stmts to be expressions.		 */		/* MOB - rc */		ejsWriteVar(ep, ep->result, func, EJS_SHALLOW_COPY);	}	freeInputStruct(ep, bodyScript);	mprFree(procName);	ejsFreeVar(ep, func);	return state;}/******************************************************************************//* *	Local vars */typedef struct ParseMethod {	EjsProc		proc, *saveProc;	EjsVar		*saveObj, *newObj;	int			saveObjPerm, rc;} ParseMethod;/* *	Parse a method name and invoke the method. See parseFunction for  *	function declarations. */static int parseMethod(Ejs *ep, int state, int flags, char *id){	ParseMethod		*sp;	if ((sp = pushFrame(ep, sizeof(ParseMethod))) == 0) {		return EJS_STATE_ERR;	}	/*	 *	Must save any current ep->proc value for the current stack frame	 *	to allow for recursive method calls.	 */	sp->saveProc = (ep->proc) ? ep->proc: 0;	memset(&sp->proc, 0, sizeof(EjsProc));	sp->proc.procName = mprStrdup(ep, id);	sp->proc.fn = &ep->currentProperty->var;	sp->proc.args = mprCreateItemArray(ep, EJS_INC_ARGS, EJS_MAX_ARGS);	ep->proc = &sp->proc;#if BLD_DEBUG	if (strcmp(sp->proc.procName, "printv") == 0) {		flags |= EJS_FLAGS_TRACE_ARGS;	}#endif	if (flags & EJS_FLAGS_EXE) {		ejsClearVar(ep, ep->result);	}	if (! (flags & EJS_FLAGS_NO_ARGS)) {		sp->saveObj = ep->currentObj;		sp->saveObjPerm = ejsMakeObjPermanent(sp->saveObj, 1);		sp->rc = ejsParse(ep, EJS_STATE_ARG_LIST, flags);		ejsMakeObjPermanent(sp->saveObj, sp->saveObjPerm);		if (sp->rc < 0) {			goto err;		}		ep->currentObj = sp->saveObj;	}#if BLD_DEBUG	flags &= ~EJS_FLAGS_TRACE_ARGS;#endif	/*	 *	Evaluate the method if required	 */	if (flags & EJS_FLAGS_EXE) {		if (flags & EJS_FLAGS_NEW) {			sp->newObj = ejsCreateObjUsingArgv(ep, ep->currentObj, 				sp->proc.procName, sp->proc.args);			if (sp->newObj == 0) {				state = EJS_STATE_ERR;			} else {				mprAssert(! ejsObjIsCollectable(sp->newObj));				/*				 *	Return the newly created object as the result of the 				 *	command. NOTE: newObj may not be an object!				 */				/* MOB - rc */				ejsWriteVar(ep, ep->result, sp->newObj, EJS_SHALLOW_COPY);				if (ejsVarIsObject(sp->newObj)) {					ejsMakeObjLive(sp->newObj, 1);					mprAssert(ejsObjIsCollectable(sp->newObj));					mprAssert(ejsBlockInUse(sp->newObj));				}				ejsFreeVar(ep, sp->newObj);			}		} else {			if (evalMethod(ep, ep->currentObj, &sp->proc, flags) < 0) {				/* Methods must call ejsError to set exceptions */				state = EJS_STATE_ERR;			}		}	}	if (! (flags & EJS_FLAGS_NO_ARGS)) {		if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) {			if (state != EJS_STATE_ERR) {				ejsSyntaxError(ep, 0);			}			state = EJS_STATE_ERR;		}	}done:	freeProc(ep, &sp->proc);	ep->proc = sp->saveProc;	popFrame(ep, sizeof(ParseMethod));	return state;err:	state = EJS_STATE_ERR;	goto done;}/******************************************************************************//* *	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, int *done){	EjsVar	*null;	int		tid;	mprFree(*id);	*id = mprStrdup(ep, ep->token);	if (ep->currentObj == 0) {		/* First identifier segement */		ep->currentObj = pickSpace(ep, state, *id, flags);	}	tid = ejsLexGetToken(ep, state);	if (tid == EJS_TOK_ASSIGNMENT) {		flags |= EJS_FLAGS_LHS;	}	/*	 *	Find the referenced variable and store it in currentProperty.	  */	if (flags & EJS_FLAGS_EXE) {		ep->currentProperty = searchSpacesForProperty(ep, state, 			ep->currentObj, *id, flags);		/*		 *	Handle properties that have been deleted inside an enumeration		 */		if (ep->currentProperty && ep->currentProperty->delayedDelete) {			ep->currentProperty = 0;		}		if (ep->currentProperty && 				ejsVarIsMethod(&ep->currentProperty->var) && 				tid != EJS_TOK_LPAREN) {			if (ep->currentProperty->var.flags & EJS_GET_ACCESSOR) {				ejsLexPutbackToken(ep, tid, ep->token);				state = parseMethod(ep, state, flags | EJS_FLAGS_NO_ARGS, *id);				if (ep->flags & EJS_FLAGS_EXIT) {					state = EJS_STATE_RET;				}				if (state >= 0) {					ejsSetVarName(ep, ep->result, ep->currentProperty->name);				}				return state;			}		}		/*		 *	OPT. We should not have to do this always		 */		updateResult(ep, state, flags, ejsGetVarPtr(ep->currentProperty));	}	flags &= ~EJS_FLAGS_LHS;	if (tid == EJS_TOK_LPAREN) {		if (ep->currentProperty == 0 && (flags & EJS_FLAGS_EXE)) {			ejsError(ep, EJS_REFERENCE_ERROR,				"Method name not defined \"%s\"", *id);			return EJS_STATE_ERR;		}		ejsLexPutbackToken(ep, EJS_TOK_METHOD_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;	}	if (flags & EJS_FLAGS_CLASS_DEC) {		if (tid == EJS_TOK_LBRACE || tid == EJS_TOK_EXTENDS) {			ejsLexPutbackToken(ep, tid, ep->token);			return state;		}	}	if (flags & EJS_FLAGS_DELETE) {		if (tid == EJS_TOK_RBRACE) {			ejsLexPutbackToken(ep, tid, ep->token);		}	}	/*	 *	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, EJS_REFERENCE_ERROR,					"Variable already defined \"%s\"", *id);				return EJS_STATE_ERR;			}#endif			/*			 *	Create or overwrite if it already exists			 *	Set newly declared variables to the null value.			 */			null = ejsCreateNullVar(ep);			ep->currentProperty = ejsSetPropertyAndFree(ep, ep->currentObj, 				*id, null);			ejsClearVar(ep, ep->result);		} else if (flags & EJS_FLAGS_FORIN) {			/* 			 *	This allows "for (x" when x has not yet been defined			 */			if (ep->currentProperty == 0) {				/* MOB -- return code */				ep->currentProperty = ejsCreateProperty(ep, 					ep->currentObj, *id);			}		} else if (ep->currentProperty == 0) {			if (ep->currentObj && ((ep->currentObj == ep->global || 					(ep->currentObj == ep->local)))) {				/* 				 *	Test against currentObj and not currentObj->objectState				 *	as we must allow "i = global.x" and not allow 				 *	"i = x" where x does not exist.				 */				ejsError(ep, EJS_REFERENCE_ERROR,					"Undefined variable \"%s\"", *id);				return EJS_STATE_ERR;			}			if (flags & EJS_FLAGS_DELETE) {				ejsError(ep, EJS_REFERENCE_ERROR,					"Undefined variable \"%s\"", *id);				return EJS_STATE_ERR;			}		}	}	ejsLexPutbackToken(ep, tid, ep->token);	if (tid == EJS_TOK_RBRACKET || tid == EJS_TOK_COMMA || 			tid == EJS_TOK_IN) {		*done = 1;	}	return state;}/******************************************************************************//* *	Local vars  */typedef struct ParseIf {	int		ifResult, thenFlags, elseFlags, tid, rs;} ParseIf;/* *	Parse an "if" statement */static int parseIf(Ejs *ep, int state, int flags, int *done){	ParseIf		*sp;	if ((sp = pushFrame(ep, sizeof(ParseIf))) == 0) {		return EJS_STATE_ERR;	}	if (state != EJS_STATE_STMT) {		goto err;	}	if (ejsLexGetToken(ep, state) != EJS_TOK_LPAREN) {		goto err;	}	/*	 *	Evaluate the entire condition list "(condition)"	 */	if (ejsParse(ep, EJS_STATE_COND, flags) < 0) {		goto err;	}	if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) {		goto err;	}	/*	 *	This is the "then" case. We need to always parse both cases and	 *	execute only the relevant case.	 */	sp->ifResult = ejsVarToBoolean(ep->result);	if (sp->ifResult) {		sp->thenFlags = flags;		sp->elseFlags = flags & ~EJS_FLAGS_EXE;	} else {		sp->thenFlags = flags & ~EJS_FLAGS_EXE;		sp->elseFlags = flags;	}	/*	 *	Process the "then" case.	 */	if ((sp->rs = ejsParse(ep, EJS_STATE_STMT, sp->thenFlags)) < 0) {		if (! ep->gotException) {			state = sp->rs;			goto done;		}	}	/*	 *	Check to see if there is an "else" case	 */	removeNewlines(ep, state);	sp->tid = ejsLexGetToken(ep, state);	if (sp->tid != EJS_TOK_ELSE) {		ejsLexPutbackToken(ep, sp->tid, ep->token);		*done = 1;		if (ep->gotException) {			goto err;		}		goto done;	}	/*	 *	Process the "else" case.	 */	state = ejsParse(ep, EJS_STATE_STMT, sp

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -