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

📄 mal_resolve.mx

📁 一个内存数据库的源代码这是服务器端还有客户端
💻 MX
📖 第 1 页 / 共 2 页
字号:
@= prepostProcess	if( findGDKtype(@1) == TYPE_bat){		setVarCleanup(mb,getArg(p,@2)) = TRUE;		getInstrPtr(@3,0)->gc |= GARBAGECONTROL;		p->gc|= QUICKCLEANUP;	}	else if( !isPolyType(@1)  && @1< TYPE_any && 			@1>=0 && ATOMstorage(@1)== TYPE_str){		getInstrPtr(@3,0)->gc |= GARBAGECONTROL;		setVarCleanup(mb,getArg(p,@2)) = TRUE;		p->gc|= QUICKCLEANUP;	} @c#ifdef DEBUG_MAL_RESOLVE	if(tracefcn) {		printInstruction(GDKout,mb,p,LIST_MAL_ALL);		stream_printf(GDKout,"Finished matching\n");	}#endif	return s1;	} /* while */@-We haven;t found the correct function.  To ease debugging, we may revealthat we found an instruction with the proper arguments, but that clasheswith one of the target variables.@c	if( foundbutwrong && !silent){		showScriptException(mb, getPC(mb, p), TYPE,			"type conflict in assignment");	}	return -3;}@- Type resolution algorithm.Every actual argument of a function call should be type compatiblewith the formal argument, and the function result type should becompatible with the destination variable.In both cases the 'receiving' variable may not be fully qualified,i.e. of type 'any'. The type resolution algorithm creates the concretetype for subsequent use.@hmal_export int resolveType(int dsttype, int srctype);@cint resolveType(int dsttype, int srctype){  #ifdef DEBUG_MAL_RESOLVE	if( tracefcn){		stream_printf(GDKout,"resolveType dst %s (%d) %s(%d)\n",			getTypeName(dsttype), dsttype,			getTypeName(srctype),srctype);	}#endif	if( dsttype == srctype) return dsttype;	if( dsttype == TYPE_any) return srctype;	if( srctype == TYPE_any) return dsttype;@-A bat reference can be coerced to bat type.@c	if(isaBatType(srctype) && dsttype == TYPE_bat) return srctype;	if(isaBatType(dsttype) && srctype == TYPE_bat) return dsttype;	if( isaBatType(dsttype) && isaBatType(srctype) ){		int h1,t1,h2,t2,h3,t3;		h1= getHeadType(dsttype);		h2= getHeadType(srctype);		if( h1 == h2) h3= h1; else		if( h1 == TYPE_any) h3= h2; else		if( h2 == TYPE_any) h3= h1; 		else {#ifdef DEBUG_MAL_RESOLVE			if(tracefcn) stream_printf(GDKout,"Can not be resolved \n");#endif			return -1;		}		t1= getTailType(dsttype);		t2= getTailType(srctype);		if( t1 == t2) t3= t1; else		if( t1 == TYPE_any) t3= t2; else		if( t2 == TYPE_any) t3= t1;		else {#ifdef DEBUG_MAL_RESOLVE			if(tracefcn) stream_printf(GDKout,"Can not be resolved \n");#endif			return -1;		}#ifdef DEBUG_MAL_RESOLVE		if( tracefcn){			int i1=getHeadIndex(dsttype);			int i2= getTailIndex(dsttype);		stream_printf(GDKout,"resolved to bat[:%s,:%s] bat[:%s,:%s]->bat[%s:%d,%s:%d]\n",			getTypeName(h1),getTypeName(t1),			getTypeName(h2),getTypeName(t2),			getTypeName(h3),i1,getTypeName(t3),i2			);		}#endif		return newBatType(h3,t3);	}#ifdef DEBUG_MAL_RESOLVE	if(tracefcn) stream_printf(GDKout,"Can not be resolved \n");#endif	return -1;}@-We try to clear the type check flag by looking up thefunctions. Errors are simply ignored at this point of the game,because they may be resolved as part of the calling sequence.@cvoid typeMismatch(MalBlkPtr mb, InstrPtr p, int lhs, int rhs, int silent){	str n1;	str n2;	if (!silent) {		n1 = getTypeName(lhs);		n2 = getTypeName(rhs);		showScriptException(mb, getPC(mb, p), TYPE, 				"type mismatch %s := %s", n1, n2);		GDKfree(n1);		GDKfree(n2);		mb->errors++;	}	p->typechk= TYPE_UNKNOWN;}@-A function search should inspect all modules unless a specific moduleis given. Preference is given to the lower scopes.The type check is set to TYPE_UNKNOWN first to enforce a properanalysis. This way it forms a cheap mechanism to resolvethe type after a change by an optimizer.If we can not find the function, the type check returns unsuccesfully.In this case we should issue an error message to the user.A re-check after the optimizer call should reset the tokento assignment.@cvoid typeChecker(Module scope, MalBlkPtr mb, InstrPtr p,int silent){	int s1= -1, i,k;	Module m=0;	p->typechk= TYPE_UNKNOWN;	if( p->fcn && p->token>= FCNcall && p->token<= PATcall){		p->token= ASSIGNsymbol;		p->fcn = NULL;		p->blk = NULL;	}	if( isaSignature(p) ) {		for(k=0;k<p->argc;k++)			setFixed(mb,getArg(p,k));		for(k=p->retc;k<p->argc;k++){			@:prepostProcess(getArgType(mb,p,k),k,mb)@		}		p->typechk= TYPE_RESOLVED;		for(k=0; k<p->retc;k++)			p->typechk = MIN(p->typechk,typeKind(mb,p,0));		return;	}	if( getFunctionId(p) && getModuleId(p)){#ifdef DEBUG_MAL_RESOLVE		tracefcn= idcmp(getFunctionId(p),traceFcnName)==0;#endif		m= findModule(scope,getModuleId(p));		s1= findFunctionType(m,mb,p,silent);		if( s1>= 0) return;@-Could not find a function that statisfies the constraints.If the instruction is just a function header we may continue.Likewise, the function and module may refer to string variablesknown only at runtime.In all other cases we should generate a message, but only if we knowthat the error was not caused by checking the definitionof a polymorphic function or the module or function name are variables,In those cases, the detailed analysis is performed upon an actual call.[ NOT ALLOWED ANYMORE		if( getModuleId(p) && (i=findVariable(mb,getModuleId(p))) != -1 &&					getVarType(mb,i) == TYPE_str){			for(i=0;i<p->retc;i++) setFixed(mb,getArg(p,i));			p->typechk= TYPE_UNKNOWN;			return;		} 		if( getFunctionId(p) && (i=findVariable(mb,getFunctionId(p))) != -1 &&					getVarType(mb,i) == TYPE_str){			for(i=0;i<p->retc;i++) setFixed(mb,getArg(p,i));			p->typechk= TYPE_UNKNOWN; 			return; 		}@c		if( ! isaSignature(p) && !getInstrPtr(mb,0)->polymorphic )  {			mb->errors++;			if( !silent) {				char errsig[BUFSIZ];				recognizedCall(mb,p,errsig);				showScriptException(mb,getPC(mb,p),TYPE,						"'%s%s%s' undefined in: %s", 						(getModuleId(p)?getModuleId(p):""),						(getModuleId(p)?".":""),						getFunctionId(p), errsig);			}			p->typechk= TYPE_UNKNOWN;		} else p->typechk= TYPE_RESOLVED;		return;	}@- Assignment When we arrive here the operator is an assignment.The language should also recognize (a,b):=(1,2);This is achieved by propagation of the rhs types to the lhsvariables.@c	if( getFunctionId(p) ) return;	if( p->retc > 1 && p->argc>p->retc && p->argc!= 2 * p->retc){		showScriptException( mb, getPC(mb,p), TYPE,			"Multiple assignment mismatch");		mb->errors++;	} else		p->typechk= TYPE_RESOLVED;	for(k=0,i= p->retc; k<p->retc && i<p->argc; i++,k++){		int rhs = getArgType(mb,p,i);		int lhs = getArgType(mb,p,k);		if( rhs != TYPE_void){			s1= resolveType(lhs,rhs);			if( s1== -1 ){				typeMismatch(mb,p,lhs,rhs,silent);				return;			}		} else @-The language permits assignment of 'nil' to any variable,using the target type.@c		if( lhs != TYPE_void && lhs != TYPE_any){			ValRecord cst;			cst.vtype= TYPE_void;			cst.val.oval= void_nil;						p->argv[i]= defConstant(mb, (isaBatType(lhs)?TYPE_bat:lhs), &cst);		} 		if( !isFixed(mb,getArg(p,k))) {			setVarType(mb,getArg(p,k),rhs);			setFixed(mb,getArg(p,k));		}		@:prepostProcess(s1,0,mb)@	}}@-Typechecking instructions can be delegated to runtime. In particular, MAL allows module and function names to be represented by string variables.The dynamic type checker uses these names and calls for a strong typecheck. Since the typechecker has side-effects on the symbol table, subsequent replacements can not produce differently typed results.This makes it possible to pass function names as arguments or tocollect them from a function table. The underlying signature remainsthe same.@cInstrPtr dynamicTypeChecker(Module scope, MalBlkPtr mb, MalStkPtr stk, InstrPtr p){	InstrPtr pci;	int i;	stream_printf(GDKout,"Start dynamic type check on:\n");	printInstruction(GDKout, mb, p,LIST_MAL_ALL);	pci = copyInstruction(p);	if( getFunctionId(pci) && (i=findVariable(mb,getFunctionId(pci))) != -1){		if( getVarType(mb,i) != TYPE_str)			setFunctionId(pci, 0);		else 			setFunctionId(pci,putName( stk->stk[i].val.sval,						strlen(stk->stk[i].val.sval)));	}	if( getModuleId(pci) && (i=findVariable(mb,getModuleId(pci))) != -1){		if( getVarType(mb,i) != TYPE_str)				setModuleId(pci, NULL);		else {				setModuleScope(pci, findModule(scope, stk->stk[i].val.sval));		}	}	typeChecker(scope, mb,pci,FALSE);#ifdef DEBUG_MAL_RESOLVE	stream_printf(GDKout,"type checked version:\n");	printInstruction(GDKout, mb, pci,LIST_MAL_ALL);#endif	return pci;}@- Function binderIn some cases the front-end may already assure type correctnessof the MAL instruction generated (e.g. the SQL front-end)In that case we merely have to locate the function address andfinalize the code for execution. Beware that we should be able todistinguish the function by module name, function name, andnumber of arguments only. Whether this is sufficient remainsto be seen.@cint fcnBinder(Module scope, MalBlkPtr mb, InstrPtr p){	Module m=0;	Symbol s;	if( p->token != ASSIGNsymbol) return 0;	if( getModuleId(p)== NULL || getFunctionId(p)== NULL) return 0;	for(m= findModule(scope,getModuleId(p)); m; m= m->outer)	if( m->name == getModuleId(p) ) {		s= m->subscope[(int)(getSubScope(getFunctionId(p)))];		for(; s; s= s->peer)		if( getFunctionId(p)==s->name &&			p->argc == getSignature(s)->argc ){			/* found it */			@:bindFunction@		}	}	return 0;}@-After the parser finishes, we have to look for semantic errors,such as flow of control problems and possible typeing conflicts.The nesting of BARRIER and CATCH statements with their associatedflow of control primitives LEAVE and RETRY should form a validhierarchy. Failure to comply is considered a structural errorand leads to flagging the function as erroneous.Also check general conformaty of the ML block structure.It should start with a signature and finish with and ENDsymbol@-Type checking a program is limited to those instructions that arenot resolved yet. Once the program is completely checked, further callsshould be ignored. This should be separately administered for the flowas well, because a dynamically typed instruction should later on notlead to a re-check when it was already fully analysed.@cvoid chkTypes(Module s, MalBlkPtr mb){	InstrPtr p=0;	int i, chk=0;	for(i=0;i<mb->stop;i++) {		p= getInstrPtr(mb,i);		if(p== NULL) continue;		if( p->typechk == TYPE_BIND) 			fcnBinder(s,mb,p);		else /*  not ready if( p->typechk != TYPE_RESOLVED)*/			typeChecker(s,mb,p,FALSE);		if( getFunctionId(p) ){			if(p->fcn != NULL && p->typechk== TYPE_RESOLVED) chk++;		} else		if( p->typechk== TYPE_RESOLVED) chk++;	}}@-Type checking an individual instruction is dangerous,because it ignores data flow and declarations issues.It is only to be used in isolated cases.@cvoid chkInstruction(Module s, MalBlkPtr mb, InstrPtr p){	typeChecker(s,mb,p, FALSE);}void chkProgram(Module s, MalBlkPtr mb){/* it is not ready yet, too fragile		mb->typefixed = mb->stop == chk; ignored END *//*	if( mb->flowfixed == 0)*/	chkTypes(s,mb);	chkFlow(mb);	chkDeclarations(mb,FALSE);}@- Polymorphic type analysisMAL provides for type variables of the form any$N. This featuresupports polymorphic types, but also complicates the subsequentanalysis. A variable typed with any$N not occuring in the functionheader leads to a dynamic typed statement. In principle we haveto type check the function upon each call.@cint typeKind(MalBlkPtr mb, InstrPtr p, int i){	malType t= getArgType(mb,p,i);	if(t == TYPE_any || isAnyExpression(t) ) {		return TYPE_DYNAMIC;	}	return TYPE_RESOLVED;}@-For a polymorphic commands we do not generate a cloned version.It suffices to determine the actual return value taking intoaccount the type variable constraints.@cmalType getPolyType(malType t,int *polytype){	int hi,ti;	int head, tail;	ti = getTailIndex(t);	tail= ti == 0? getTailType(t): polytype[ti];	if( isaBatType(t)){		hi = getHeadIndex(t);		head= hi == 0 ? getHeadType(t): polytype[hi];		return newBatType(head,tail);	}	return tail;}@-Each argument is checked for binding of polymorphic arguments.This routine assumes that the type index is indeed smaller than maxarg. (The parser currently enforces a single digit from 1-9 )The polymorphic type 'any', i.e. any$0, does never constraint an operationit can match with all polymorphic types.The routine returns the instanciated formal type for subsequenttype resolution.@cint updateTypeMap(int formal, int actual, int polytype[MAXTYPEVAR]){	int h,t,ret=0;	if( formal== TYPE_bat && isaBatType(actual) ) return 0;#ifdef DEBUG_MAL_RESOLVE	stream_printf(GDKout,"updateTypeMap:");	stream_printf(GDKout,"formal %s ", getTypeName(formal));	stream_printf(GDKout,"actual %s\n", getTypeName(actual));#endif	if( (h=getTailIndex(formal))  ){		t= getTailType(actual);		if( t != polytype[h]){			if( polytype[h]== TYPE_bat && isaBatType(actual))				ret= 0;			else			if( polytype[h] == TYPE_any ) polytype[h]=  t;			else {				ret= -1;				goto updLabel;			}		}	}	if( isaBatType(formal)){		if(!isaBatType(actual) && actual!= TYPE_bat) return -1;		if( (h=getHeadIndex(formal)) ){			t= actual == TYPE_bat? actual: getHeadType(actual);			if( t!= polytype[h]){				if( polytype[h] == TYPE_any) polytype[h]= t;				else {					ret= -1;					goto updLabel;				}			}		}	} updLabel:#ifdef DEBUG_MAL_RESOLVE	stream_printf(GDKout,"updateTypeMap returns: %d\n",ret);#endif	return ret;}@-A completely different mechanism would have been to hardcode some of the mostlyoccurring type checks. For example, the type checker for the instructionbat.insert(b:bat[:any$1,:any$2],h:any$1,t:any$2):bat[:any$1,:any$2].The disadvantage is an abundance of code and less efficient instructioncache hits.@}

⌨️ 快捷键说明

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