diff options
Diffstat (limited to 'new/types.c')
-rw-r--r-- | new/types.c | 1613 |
1 files changed, 0 insertions, 1613 deletions
diff --git a/new/types.c b/new/types.c deleted file mode 100644 index f20627f..0000000 --- a/new/types.c +++ /dev/null @@ -1,1613 +0,0 @@ -/* MIRANDA TYPECHECKER */ - -/************************************************************************** - * Copyright (C) Research Software Limited 1985-90. All rights reserved. * - * The Miranda system is distributed as free software under the terms in * - * the file "COPYING" which is included in the distribution. * - *------------------------------------------------------------------------*/ - -#include "data.h" -#include "big.h" -word R=NIL; /* direct-and-indirect dependency graph */ -word TABSTRS=NIL; /* list of abstype declarations */ -word ND; /* undefined names used in script */ -word SBND; /* names specified but not defined (handled separately) */ -word FBS; /* list of bindings caused by parameterised %include's */ -word ATNAMES; /* global var set by abstr_check */ -word NT=NIL; /* undefined typenames used in script */ -word TYPERRS; -word bnf_t=0; -word current_id=0,lastloc=0,lineptr=0; /* used to locate type errors */ -word showchain=NIL; /* links together all occurrences of special forms (show) - encountered during typecheck */ -extern word rfl; - -#include <setjmp.h> -jmp_buf env1; /* for longjmp - see man (3) setjmp */ - -checktypes() /* outcome indicated by setting of flags SYNERR, TYPERRS, ND */ -{ word s; - extern word freeids,SYNERR,fnts; - ATNAMES=TYPERRS=0; - NT=R=SBND=ND=NIL; /* NT=R= added 4/6/88 */ - if(setjmp(env1)==1)goto L; - if(rfl!=NIL)readoption(); - for(s=reverse(fil_defs(hd[files]));s!=NIL;s=tl[s]) - comp_deps(hd[s]); /* for each identifier in current script, compute - dependencies to form R */ - R=tclos(sortrel(R)); - if(FBS!=NIL)mcheckfbs(); - abstr_mcheck(TABSTRS); -L:if(TYPERRS) - { /* badly formed types, so give up */ - TABSTRS=NT=R=NIL; - printf("typecheck cannot proceed - compilation abandoned\n"); - SYNERR=1; - return; } - if(freeids!=NIL)redtfr(freeids); - /* printgraph("dependency analysis:",R); /* for debugging */ - genshfns(); - if(fnts!=NIL)genbnft(); - R=msc(R); - /* printgraph("strong components:",R); /* for debugging */ - s=tsort(R); - /* printlist("topological sort:",s); /* for debugging */ - NT=R=NIL; /* must be invariant across the call */ - while(s!=NIL)infer_type(hd[s]),s=tl[s]; - checkfbs(); - while(TABSTRS!=NIL) - abstr_check(hd[TABSTRS]),TABSTRS=tl[TABSTRS]; - if(SBND!=NIL) - printlist("SPECIFIED BUT NOT DEFINED: ",alfasort(SBND)),SBND=NIL; - fixshows(); - lastloc=0; - return; -} - -/* NOTES - let element ::= id | list(id) - let graph1 ::= list(cons(id,list(id))) - let graph2 ::= list(cons(element,list(id))) - we define: - comp_deps(id)->builds R::graph1, direct dependencies - R=tclos(sortrel(R))::graph1, direct and indirect dependencies - msc(R)->collects maximal strong components in R, now R::graph2 - tsort(graph2)->list(element), topologically sorted - infer_type(element)->fills in the id_type field(s) of element -*/ -/* R occupies quadratic worst-case space - does anyone know a better way? */ - -comp_deps(n) /* adds to R an entry of the form cons(n,RHS) where n is an - identifier and RHS is a list of all the identifiers in the - current script upon which n directly depends */ -/* it also meta-typechecks type specifications, and puts them in reduced - form, as it goes */ -word n; -{ word rhs=NIL,r; - /* printf("comp_deps(%s)\n",get_id(n)); /* DEBUG */ - if(id_type(n)==type_t) - { if(t_class(n)==algebraic_t) - { r=t_info(n); - while(r!=NIL) /* meta type check constructors */ - { current_id=hd[r]; - id_type(hd[r])=redtvars(meta_tcheck(id_type(hd[r]))); - r=tl[r]; } - } - else if(t_class(n)==synonym_t) - current_id=n,t_info(n)=meta_tcheck(t_info(n)); - else if(t_class(n)==abstract_t) - if(t_info(n)==undef_t) - printf("error: script contains no binding for abstract typename\ - \"%s\"\n",get_id(n)),sayhere(id_who(n),1),TYPERRS++; - else current_id=n,t_info(n)=meta_tcheck(t_info(n)); - /* placeholder types - no action */ - current_id=0; - return; } - if(tag[id_val(n)]==CONSTRUCTOR)return; - /* primitive constructors require no type analysis */ - if(id_type(n)!=undef_t) /* meta typecheck spec, if present */ - { current_id=n; - if(tag[id_type(n)]==CONS) - { /* signature identifier */ - if(id_val(n)==UNDEF)SBND=add1(n,SBND); - id_type(n)=redtvars(meta_tcheck(hd[id_type(n)])); - current_id=0; - return; } /* typechecked separately, under TABSTRS */ - id_type(n)=redtvars(meta_tcheck(id_type(n))); - current_id=0; } - if(id_val(n)==FREE)return; /* no further analysis required */ - if(id_val(n)==UNDEF) /* name specified but not defined */ - { SBND=add1(n,SBND); /* change of policy (as for undefined sigid, above) */ - return; } /* now not added to ND, so script can be %included */ - r=deps(id_val(n)); - while(r!=NIL) - { if(id_val(hd[r])!=UNDEF&&id_type(hd[r])==undef_t) - /* only defined names without explicitly assigned types - cause dependency */ - rhs=add1(hd[r],rhs); - r=tl[r]; } - R=cons(cons(n,rhs),R); -} - -tsort(g) /* topological sort - returns a list of the elements in the domain - of relation g, in an order such that each element is preceded by everything - it depends on */ -word g; /* the structure of g is "graph2" see NOTES above */ -{ word NP=NIL; /* NP is set of elements with no predecessor */ - word g1=g, r=NIL; /* r is result */ - g=NIL; - while(g1!=NIL) - { if(tl[hd[g1]]==NIL)NP=cons(hd[hd[g1]],NP); - else g=cons(hd[g1],g); - g1=tl[g1]; } - while(NP!=NIL) - { word D=NIL; /* ids to be removed from range of g */ - while(NP!=NIL) - { r=cons(hd[NP],r); - if(tag[hd[NP]]==ID)D=add1(hd[NP],D); - else D=UNION(D,hd[NP]); - NP=tl[NP]; } - g1=g;g=NIL; - while(g1!=NIL) - { word rhs=setdiff(tl[hd[g1]],D); - if(rhs==NIL)NP=cons(hd[hd[g1]],NP); - else tl[hd[g1]]=rhs,g=cons(hd[g1],g); - g1=tl[g1]; } - } - if(g!=NIL)fprintf(stderr,"error: impossible event in tsort\n"); - return(reverse(r)); -} - -msc(R) /* collects maximal strong components in R, converting it from "graph1" - to "graph2" form - destructive in R */ -word R; -{ word R1=R; - while(R1!=NIL) - { word *r= &tl[hd[R1]],l=hd[hd[R1]]; - if(remove1(l,r)) - { hd[hd[R1]]=cons(l,NIL); - while(*r!=NIL) - { word n=hd[*r],*R2= &tl[R1]; - while(*R2!=NIL&&hd[hd[*R2]]!=n)R2= &tl[*R2]; /* find n-entry in R */ - if(*R2!=NIL&&member(tl[hd[*R2]],l)) - { *r=tl[*r]; /* remove n from r */ - *R2=tl[*R2]; /* remove n's entry from R */ - hd[hd[R1]]=add1(n,hd[hd[R1]]); - } - else r= &tl[*r]; - } - } - R1=tl[R1]; - } - return(R); -} - -word meta_pending=NIL; - -meta_tcheck(t) /* returns type t with synonyms substituted out and checks that - the result is well formed */ -word t; -{ word tn=t,i=0; - /* TO DO -- TIDY UP ERROR MESSAGES AND SET ERRLINE (ERRS) IF POSS */ - while(iscompound_t(tn)) - tl[tn]=meta_tcheck(tl[tn]),i++,tn=hd[tn]; - if(tag[tn]==STRCONS)goto L; /* patch to handle free type bindings */ - if(tag[tn]!=ID) - { if(i>0&&(isvar_t(tn)||tn==bool_t||tn==num_t||tn==char_t)) - { TYPERRS++; - if(tag[current_id]==DATAPAIR) - locate_inc(), - printf("badly formed type \""),out_type(t), - printf("\" in binding for \"%s\"\n",(char *)hd[current_id]), - printf("("),out_type(tn),printf(" has zero arity)\n"); - else - printf("badly formed type \""),out_type(t), - printf("\" in %s for \"%s\"\n", - id_type(current_id)==type_t?"== binding":"specification", - get_id(current_id)), - printf("("),out_type(tn),printf(" has zero arity)\n"), - sayhere(getspecloc(current_id),1); - sterilise(t); } - return(t); } - if(id_type(tn)==undef_t&&id_val(tn)==UNDEF) - { TYPERRS++; - if(!member(NT,tn)) - { if(tag[current_id]==DATAPAIR)locate_inc(); - printf("undeclared typename \"%s\" ",get_id(tn)); - if(tag[current_id]==DATAPAIR) - printf("in binding for %s\n",(char *)hd[current_id]); - else sayhere(getspecloc(current_id),1); - NT=add1(tn,NT); } - return(t); }else - if(id_type(tn)!=type_t||t_arity(tn)!=i) - { TYPERRS++; - if(tag[current_id]==DATAPAIR) - locate_inc(), - printf("badly formed type \""),out_type(t), - printf("\" in binding for \"%s\"\n",(char *)hd[current_id]); - else - printf("badly formed type \""),out_type(t), - printf("\" in %s for \"%s\"\n", - id_type(current_id)==type_t?"== binding":"specification", - get_id(current_id)); - if(id_type(tn)!=type_t) - printf("(%s not defined as typename)\n",get_id(tn)); - else printf("(typename %s has arity %d)\n",get_id(tn),t_arity(tn)); - if(tag[current_id]!=DATAPAIR) - sayhere(getspecloc(current_id),1); - sterilise(t); - return(t); } -L:if(t_class(tn)!=synonym_t)return(t); - if(member(meta_pending,tn)) - { TYPERRS++;/* report cycle */ - if(tag[current_id]==DATAPAIR)locate_inc(); - printf("error: cycle in type \"==\" definition%s ", - meta_pending==NIL?"":"s"); - printelement(meta_pending); putchar('\n'); - if(tag[current_id]!=DATAPAIR) - sayhere(id_who(tn),1); - longjmp(env1,1); /* fatal error - give up */ -/* t_class(tn)=algebraic_t;t_info(tn)=NIL; - /* to make sure we dont fall in here again! */ - return(t); } - meta_pending=cons(tn,meta_pending); - tn=NIL; - while(iscompound_t(t)) - tn=cons(tl[t],tn),t=hd[t]; - t=meta_tcheck(ap_subst(t_info(t),tn)); - meta_pending=tl[meta_pending]; - return(t); -} -/* needless inefficiency - we recheck the rhs of a synonym every time we - use it */ - -sterilise(t) /* to prevent multiple reporting of metatype errors from - namelist :: type */ -word t; -{ if(tag[t]==AP)hd[t]=list_t,tl[t]=num_t; -} - -word tvcount=1; -#define NTV mktvar(tvcount++) - /* brand new type variable */ -#define reset_SUBST (current_id=tvcount>=hashsize?clear_SUBST():0) - -infer_type(x) /* deduces the types of the identifiers in x - no result, - works by filling in id_type fields */ -word x; /* x is an "element" */ -{ if(tag[x]==ID) - { word t,oldte=TYPERRS; - current_id=x; - t = subst(etype(id_val(x),NIL,NIL)); - if(id_type(x)==undef_t)id_type(x)=redtvars(t); - else /* x already has assigned type */ - if(!subsumes(t,instantiate(id_type(x)))) - { TYPERRS++; - printf("incorrect declaration "); - sayhere(getspecloc(x),1); /* or: id_who(x) to locate defn */ - printf("specified, "); report_type(x); putchar('\n'); - printf("inferred, %s :: ",get_id(x)); out_type(redtvars(t)); - putchar('\n'); } - if(TYPERRS>oldte)id_type(x)=wrong_t, - id_val(x)=UNDEF, - ND=add1(x,ND); - reset_SUBST; } - else{ /* recursive group of names */ - word x1,oldte,ngt=NIL; - for(x1=x;x1!=NIL;x1=tl[x1]) - ngt=cons(NTV,ngt), - id_type(hd[x1])=ap(bind_t,hd[ngt]); - for(x1=x;x1!=NIL;x1=tl[x1]) - { oldte=TYPERRS, - current_id=hd[x1], - unify(tl[id_type(hd[x1])],etype(id_val(hd[x1]),NIL,ngt)); - if(TYPERRS>oldte) - id_type(hd[x1])=wrong_t, - id_val(hd[x1])=UNDEF,ND=add1(hd[x1],ND); } - for(x1=x;x1!=NIL;x1=tl[x1]) - if(id_type(hd[x1])!=wrong_t) - id_type(hd[x1])=redtvars(ult(tl[id_type(hd[x1])])); - reset_SUBST; - } -} - -word hereinc; /* location of currently-being-processed %include */ -word lasthereinc; - -mcheckfbs() -{ word ff,formals,n; - lasthereinc=0; - for(ff=FBS;ff!=NIL;ff=tl[ff]) - { hereinc=hd[hd[FBS]]; - for(formals=tl[hd[ff]];formals!=NIL;formals=tl[formals]) - { word t=tl[tl[hd[formals]]]; - if(t!=type_t)continue; - current_id=hd[tl[hd[formals]]]; /* nb datapair(orig,0) not id */ - t_info(hd[hd[formals]])=meta_tcheck(t_info(hd[hd[formals]])); - /*ATNAMES=cons(hd[hd[formals]],ATNAMES?ATNAMES:NIL); */ - current_id=0; - } - if(TYPERRS)return; /* to avoid misleading error messages */ - for(formals=tl[hd[ff]];formals!=NIL;formals=tl[formals]) - { word t=tl[tl[hd[formals]]]; - if(t==type_t)continue; - current_id=hd[tl[hd[formals]]]; /* nb datapair(orig,0) not id */ - tl[tl[hd[formals]]]=redtvars(meta_tcheck(t)); - current_id=0; - } - /* above double traverse is very inefficient way of doing types first - would be better to have bindings sorted in this order beforehand */ - } - /* all imported names must now have their types reduced to - canonical form wrt the parameter bindings */ - /* alternative method - put info in ATNAMES, see above and in abstr_check */ - /* a problem with this is that types do not print in canonical form */ - if(TYPERRS)return; - for(ff=tl[files];ff!=NIL;ff=tl[ff]) - for(formals=fil_defs(hd[ff]);formals!=NIL;formals=tl[formals]) - if(tag[n=hd[formals]]==ID) - if(id_type(n)==type_t) - { if(t_class(n)==synonym_t)t_info(n)=meta_tcheck(t_info(n)); } - else id_type(n)=redtvars(meta_tcheck(id_type(n))); -} /* wasteful if many includes */ - -redtfr(x) /* ensure types of freeids are in reduced form */ -word x; -{ for(;x!=NIL;x=tl[x]) - tl[tl[hd[x]]] = id_type(hd[hd[x]]); -} - -checkfbs() -/* FBS is list of entries of form cons(hereinfo,formals) where formals - has elements of form cons(id,cons(datapair(orig,0),type)) */ -{ word oldte=TYPERRS,formals; - lasthereinc=0; - for(;FBS!=NIL;FBS=tl[FBS]) - for(hereinc=hd[hd[FBS]],formals=tl[hd[FBS]]; - formals!=NIL;formals=tl[formals]) - { word t,t1=fix_type(tl[tl[hd[formals]]]); - if(t1==type_t)continue; - current_id=hd[tl[hd[formals]]]; /* nb datapair(orig,0) not id */ - t = subst(etype(the_val(hd[hd[formals]]),NIL,NIL)); - if(!subsumes(t,instantiate(t1))) - { TYPERRS++; - locate_inc(); - printf("binding for parameter `%s' has wrong type\n", - (char *)hd[current_id]); - printf( "required :: "); out_type(tl[tl[hd[formals]]]); - printf("\n actual :: "); out_type(redtvars(t)); - putchar('\n'); } - the_val(hd[hd[formals]])=codegen(the_val(hd[hd[formals]])); } - if(TYPERRS>oldte) - { /* badly typed parameter bindings, so give up */ - extern word SYNERR; - TABSTRS=NT=R=NIL; - printf("compilation abandoned\n"); - SYNERR=1; } - reset_SUBST; -} - -fix_type(t,x) /* substitute out any indirected typenames in t */ -word t,x; -{ switch(tag[t]) - { case AP: - case CONS: tl[t]=fixtype(tl[t],x); - hd[t]=fixtype(hd[t],x); - default: return(t); - case STRCONS: while(tag[pn_val(t)]!=CONS)t=pn_val(t);/*at most twice*/ - return(t); - } -} - -locate_inc() -{ if(lasthereinc==hereinc)return; - printf("incorrect %%include directive "); - sayhere(lasthereinc=hereinc,1); -} - -abstr_mcheck(tabstrs) /* meta-typecheck abstract type declarations */ -word tabstrs; -{ while(tabstrs!=NIL) - { word atnames=hd[hd[tabstrs]],sigids=tl[hd[tabstrs]],rtypes=NIL; - if(cyclic_abstr(atnames))return; - while(sigids!=NIL) /* compute representation types */ - { word rt=rep_t(id_type(hd[sigids]),atnames); - /*if(rt==id_type(hd[sigids])) - printf("abstype declaration error: \"%s\" has a type unrelated to \ -the abstraction\n",get_id(hd[sigids])), - sayhere(getspecloc(hd[sigids]),1), - TYPERRS++; /* suppressed June 89, see karen.m, secret.m */ - rtypes=cons(rt,rtypes); - sigids=tl[sigids]; } - rtypes=reverse(rtypes); - hd[hd[tabstrs]]=cons(hd[hd[tabstrs]],rtypes); - tabstrs=tl[tabstrs]; - } -} - -abstr_check(x) /* typecheck the implementation equations of a type abstraction - with the given signature */ -word x; -{ word rtypes=tl[hd[x]],sigids=tl[x]; -/*int holdat=ATNAMES; - ATNAMES=shunt(hd[hd[x]],ATNAMES); */ - ATNAMES=hd[hd[x]]; - txchange(sigids,rtypes); /* install representation types */ - /* report_types("concrete signature:\n",sigids); /* DEBUG */ - for(x=sigids;x!=NIL;x=tl[x]) - { word t,oldte=TYPERRS; - current_id=hd[x]; - t=subst(etype(id_val(hd[x]),NIL,NIL)); - if(!subsumes(t,instantiate(id_type(hd[x])))) - { TYPERRS++; - printf("abstype implementation error\n"); - printf("\"%s\" is bound to value of type: ",get_id(hd[x])); - out_type(redtvars(t)); - printf("\ntype expected: "); - out_type(id_type(hd[x])); - putchar('\n'); - sayhere(id_who(hd[x]),1); } - if(TYPERRS>oldte) - id_type(hd[x])=wrong_t,id_val(hd[x])=UNDEF,ND=add1(hd[x],ND); - reset_SUBST; } - /* restore the abstract types - for "finger" */ - for(x=sigids;x!=NIL;x=tl[x],rtypes=tl[rtypes]) - if(id_type(hd[x])!=wrong_t)id_type(hd[x])=hd[rtypes]; - ATNAMES= /* holdat */ 0; -} - -cyclic_abstr(atnames) /* immediately-cyclic acts of dta are illegal */ -word atnames; -{ word x,y=NIL; - for(x=atnames;x!=NIL;x=tl[x])y=ap(y,t_info(hd[x])); - for(x=atnames;x!=NIL;x=tl[x]) - if(occurs(hd[x],y)) - { printf("illegal type abstraction: cycle in \"==\" binding%s ", - tl[atnames]==NIL?"":"s"); - printelement(atnames); putchar('\n'); - sayhere(id_who(hd[x]),1); - TYPERRS++; return(1); } - return(0); -} - -txchange(ids,x) /* swap the id_type of each id with the corresponding type - in the list x */ -word ids,x; -{ while(ids!=NIL) - { word t=id_type(hd[ids]); - id_type(hd[ids])=hd[x],hd[x]=t; - ids=tl[ids],x=tl[x]; } -} - -report_type(x) -word x; -{ printf("%s",get_id(x)); - if(id_type(x)==type_t) - if(t_arity(x)>5)printf("(arity %d)",t_arity(x)); - else { word i,j; - for(i=1;i<=t_arity(x);i++) - { putchar(' '); - for(j=0;j<i;j++)putchar('*'); } - } - printf(" :: "); - out_type(id_type(x)); -} - -report_types(header,x) -char *header; -word x; -{ printf("%s",header); - while(x!=NIL) - report_type(hd[x]),putchar(';'),x=tl[x]; - putchar('\n'); -} - -typesfirst(x) /* rearrange list of ids to put types first */ -word x; -{ word *y= &x,z=NIL; - while(*y!=NIL) - if(id_type(hd[*y])==type_t) - z=cons(hd[*y],z),*y=tl[*y]; - else y= &tl[*y]; - return(shunt(z,x)); -} - -rep_t1(T,L) /* computes the representation type corresponding to T, wrt the - abstract typenames in L */ - /* will need to apply redtvars to result, see below */ - /* if no substitutions found, result is identically T */ -word T,L; -{ word args=NIL,t1,new=0; - for(t1=T;iscompound_t(t1);t1=hd[t1]) - { word a=rep_t1(tl[t1],L); - if(a!=tl[t1])new=1; - args=cons(a,args); } - if(member(L,t1))return(ap_subst(t_info(t1),args)); - /* call to redtvars removed 26/11/85 - leads to premature normalisation of subterms */ - if(!new)return(T); - while(args!=NIL) - t1=ap(t1,hd[args]),args=tl[args]; - return(t1); -} - -rep_t(T,L) /* see above */ -word T,L; -{ word t=rep_t1(T,L); - return(t==T?t:redtvars(t)); -} - -type_of(x) /* returns the type of expression x, in reduced form */ -word x; -{ word t; - TYPERRS=0; - t=redtvars(subst(etype(x,NIL,NIL))); - fixshows(); - if(TYPERRS>0)t=wrong_t; - return(t); -} - -checktype(x) /* is expression x well-typed ? */ - /* not currently used */ -word x; -{ TYPERRS=0; - etype(x,NIL,NIL); - reset_SUBST; - return(!TYPERRS); -} - -#define bound_t(t) (iscompound_t(t)&&hd[t]==bind_t) -#define tf(a,b) ap2(arrow_t,a,b) -#define tf2(a,b,c) tf(a,tf(b,c)) -#define tf3(a,b,c,d) tf(a,tf2(b,c,d)) -#define tf4(a,b,c,d,e) tf(a,tf3(b,c,d,e)) -#define lt(a) ap(list_t,a) -#define pair_t(x,y) ap2(comma_t,x,ap2(comma_t,y,void_t)) - -word tfnum,tfbool,tfbool2,tfnum2,tfstrstr,tfnumnum,ltchar, - tstep,tstepuntil; - -tsetup() -{ tfnum=tf(num_t,num_t); - tfbool=tf(bool_t,bool_t); - tfnum2=tf(num_t,tfnum); - tfbool2=tf(bool_t,tfbool); - ltchar=lt(char_t); - tfstrstr=tf(ltchar,ltchar); - tfnumnum=tf(num_t,num_t); - tstep=tf2(num_t,num_t,lt(num_t)); - tstepuntil=tf(num_t,tstep); -} - -word exec_t=0,read_t=0,filestat_t=0; /* set lazily, when used */ - -genlstat_t() /* type of %lex state */ -{ return(pair_t(num_t,num_t)); } - -genbnft() /* if %bnf used, find out input type of parsing fns */ -{ word bnftokenstate=findid("bnftokenstate"); - if(bnftokenstate!=NIL&&id_type(bnftokenstate)==type_t) - if(t_arity(bnftokenstate)==0) - bnf_t=t_class(bnftokenstate)==synonym_t? - t_info(bnftokenstate):bnftokenstate; - else printf("warning - bnftokenstate has arity>0 (ignored by parser)\n"), - bnf_t=void_t; - else bnf_t=void_t; /* now bnf_t holds the state type */ - bnf_t=ap2(comma_t,ltchar,ap2(comma_t,bnf_t,void_t)); -} /* the input type for parsers is lt(bnf_t) - note that tl[hd[tl[bnf_t]]] holds the state type */ - -extern word col_fn; - -checkcolfn() /* if offside rule used, check col_fn has right type */ -{ word t=id_type(col_fn),f=tf(tl[hd[tl[bnf_t]]],num_t); - if(t==undef_t||t==wrong_t - /* will be already reported - do not generate further typerrs - in both cases col_fn will behave as undefined name */ - ||subsumes(instantiate(t),f)) - { col_fn=0; return; } /* no further action required */ - printf("`bnftokenindentation' has wrong type for use in offside rule\n"); - printf("type required :: "); out_type(f); putchar('\n'); - printf(" actual type :: "); out_type(t); putchar('\n'); - sayhere(getspecloc(col_fn),1); - TYPERRS++; - col_fn= -1; /* error flag */ -} /* note that all parsing fns get type wrong_t if offside rule used - anywhere and col_fn has wrong type - strictly this is overkill */ - -etype(x,env,ngt) /* infer a type for an expression, by using unification */ -word x,env; /* env is list of local bindings of variables to types */ -word ngt; /* ngt is list of non-generic type variables */ -{ word a,b,c,d; /* initialise to 0 ? */ - switch(tag[x]) - { case AP: if(hd[x]==BADCASE||hd[x]==CONFERROR)return(NTV); - /* don't type check insides of error messages */ - { word ft=etype(hd[x],env,ngt),at=etype(tl[x],env,ngt),rt=NTV; - if(!unify1(ft,ap2(arrow_t,at,rt))) - { ft=subst(ft); - if(isarrow_t(ft)) - if(tag[hd[x]]==AP&&hd[hd[x]]==G_ERROR) - type_error8(at,tl[hd[ft]]); - else - type_error("unify","with",at,tl[hd[ft]]); - else type_error("apply","to",ft,at); - return(NTV); } - return(rt); } - case CONS: { word ht=etype(hd[x],env,ngt),rt=etype(tl[x],env,ngt); - if(!unify1(ap(list_t,ht),rt)) - { type_error("cons","to",ht,rt); - return(NTV); } - return(rt); } - case LEXER: { word hold=lineptr; - lineptr=hd[tl[tl[hd[x]]]]; - tl[tl[hd[x]]]=tl[tl[tl[hd[x]]]];/*discard label(hereinf,-)*/ - a=etype(tl[tl[hd[x]]],env,ngt); - while((x=tl[x])!=NIL) - { lineptr=hd[tl[tl[hd[x]]]]; - tl[tl[hd[x]]]=tl[tl[tl[hd[x]]]];/*discard label... */ - if(!unify1(a,b=etype(tl[tl[hd[x]]],env,ngt))) - { type_error7(a,b); - lineptr=hold; - return(NTV); } - } - lineptr=hold; - return(tf(ltchar,lt(a))); } - case TCONS: return(ap2(comma_t,etype(hd[x],env,ngt), - etype(tl[x],env,ngt))); - case PAIR: return(ap2(comma_t,etype(hd[x],env,ngt), - ap2(comma_t,etype(tl[x],env,ngt),void_t))); - case DOUBLE: - case INT: return(num_t); - case ID: a=env; - while(a!=NIL) /* take local binding, if present */ - if(hd[hd[a]]==x) - return(linst(tl[hd[a]]=subst(tl[hd[a]]),ngt)); - else a=tl[a]; - a=id_type(x); /* otherwise pick up global binding */ - if(bound_t(a))return(tl[a]); - if(a==type_t)type_error1(x); - if(a==undef_t) - { extern word commandmode; - if(commandmode)type_error2(x); - else - if(!member(ND,x)) /* report first occurrence only */ - { if(lineptr)sayhere(lineptr,0); - else if(tag[current_id]==DATAPAIR) /* see checkfbs */ - locate_inc(); - printf("undefined name \"%s\"\n",get_id(x)); - ND=add1(x,ND); } - return(NTV); } - if(a==wrong_t)return(NTV); - return(instantiate(ATNAMES?rep_t(a,ATNAMES):a)); - case LAMBDA: a=NTV; b=NTV; - d=cons(a,ngt); - c=conforms(hd[x],a,env,d); - if(c==-1||!unify(b,etype(tl[x],c,d)))return(NTV); - return(tf(a,b)); - case LET: { word e,def=hd[x]; - a=NTV,e=conforms(dlhs(def),a,env,cons(a,ngt)); - current_id=cons(dlhs(def),current_id); - c=lineptr; lineptr=dval(def); - b = unify(a,etype(dval(def),env,ngt)); - lineptr=c; - current_id=tl[current_id]; - if(e==-1||!b)return(NTV); - return(etype(tl[x],e,ngt)); } - case LETREC: { word e=env,s=NIL; - a=NIL; c=ngt; - for(d=hd[x];d!=NIL;d=tl[d]) - if(dtyp(hd[d])==undef_t) - a=cons(hd[d],a), /* unspecified defs */ - dtyp(hd[d])=(b=NTV), - c=cons(b,c), /* collect non-generic tvars */ - e=conforms(dlhs(hd[d]),b,e,c); - else dtyp(hd[d])=meta_tcheck(dtyp(hd[d])), - /* should do earlier, and locate errs properly*/ - s=cons(hd[d],s), /* specified defs */ - e=cons(cons(dlhs(hd[d]),dtyp(hd[d])),e); - if(e==-1)return(NTV); - b=1; - for(;a!=NIL;a=tl[a]) - { current_id=cons(dlhs(hd[a]),current_id); - d=lineptr; lineptr=dval(hd[a]); - b &= unify(dtyp(hd[a]),etype(dval(hd[a]),e,c)); - lineptr=d; current_id=tl[current_id]; } - for(;s!=NIL;s=tl[s]) - { current_id=cons(dlhs(hd[s]),current_id); - d=lineptr; lineptr=dval(hd[s]); - if(!subsumes(a=etype(dval(hd[s]),e,ngt), - linst(dtyp(hd[s]),ngt))) - /* would be better to set lineptr to spec here */ - b=0,type_error6(dlhs(hd[s]),dtyp(hd[s]),a); - lineptr=d; current_id=tl[current_id]; } - if(!b)return(NTV); - return(etype(tl[x],e,ngt)); } - case TRIES: { word hold=lineptr; - a=NTV; - x=tl[x]; - while(x!=NIL&&(lineptr=hd[hd[x]], - unify(a,etype(tl[hd[x]],env,ngt))) - )x=tl[x]; - lineptr=hold; - if(x!=NIL)return(NTV); - return(a); } - case LABEL: { word hold=lineptr,t; - lineptr=hd[x]; - t=etype(tl[x],env,ngt); - lineptr=hold; - return(t); } - case STARTREADVALS: if(tl[x]==0) - hd[x]=lineptr, /* insert here-info */ - tl[x]=NTV, - showchain=cons(x,showchain); - return(tf(ltchar,lt(tl[x]))); - case SHOW: hd[x]=lineptr; /* insert here-info */ - showchain=cons(x,showchain); - return(tf(tl[x]=NTV,ltchar)); - case SHARE: if(tl[x]==undef_t) - { word h=TYPERRS; - tl[x]=subst(etype(hd[x],env,ngt)); - if(TYPERRS>h)hd[x]=UNDEF,tl[x]=wrong_t; } - if(tl[x]==wrong_t) - { TYPERRS++; return(NTV); } - return(tl[x]); - case CONSTRUCTOR: a=id_type(tl[x]); - return(instantiate(ATNAMES?rep_t(a,ATNAMES):a)); - case UNICODE: return(char_t); - case ATOM: if(x<256)return(char_t); - switch(x) - { - case S:a=NTV,b=NTV,c=NTV; - d=tf3(tf2(a,b,c),tf(a,b),a,c); - return(d); - case K:a=NTV,b=NTV; - return(tf2(a,b,a)); - case Y:a=NTV; - return(tf(tf(a,a),a)); - case C:a=NTV,b=NTV,c=NTV; - return(tf3(tf2(a,b,c),b,a,c)); - case B:a=NTV,b=NTV,c=NTV; - return(tf3(tf(a,b),tf(c,a),c,b)); - case FORCE: - case G_UNIT: - case G_RULE: - case I:a=NTV; - return(tf(a,a)); - case G_ZERO:return(NTV); - case HD:a=NTV; - return(tf(lt(a),a)); - case TL:a=lt(NTV); - return(tf(a,a)); - case BODY:a=NTV,b=NTV; - return(tf(ap(a,b),a)); - case LAST:a=NTV,b=NTV; - return(tf(ap(a,b),b)); - case S_p:a=NTV,b=NTV; - c=lt(b); - return(tf3(tf(a,b),tf(a,c),a,c)); - case U: - case U_: a=NTV,b=NTV; - c=lt(a); - return(tf2(tf2(a,c,b),c,b)); - case Uf: a=NTV,b=NTV,c=NTV; - return(tf2(tf2(tf(a,b),a,c),b,c)); - case COND: a=NTV; - return(tf3(bool_t,a,a,a)); - case EQ:case GR:case GRE: - case NEQ: a=NTV; - return(tf2(a,a,bool_t)); - case NEG: return(tfnum); - case AND: - case OR: return(tfbool2); - case NOT: return(tfbool); - case MERGE: - case APPEND: a=lt(NTV); - return(tf2(a,a,a)); - case STEP: return(tstep); - case STEPUNTIL: return(tstepuntil); - case MAP: a=NTV; b=NTV; - return(tf2(tf(a,b),lt(a),lt(b))); - case FLATMAP: a=NTV,b=lt(NTV); - return(tf2(tf(a,b),lt(a),b)); - case FILTER: a=NTV; b=lt(a); - return(tf2(tf(a,bool_t),b,b)); - case ZIP: a=NTV; b=NTV; - return(tf2(lt(a),lt(b),lt(pair_t(a,b)))); - case FOLDL: a=NTV; b=NTV; - return(tf3(tf2(a,b,a),a,lt(b),a)); - case FOLDL1: a=NTV; - return(tf2(tf2(a,a,a),lt(a),a)); - case LIST_LAST: a=NTV; - return(tf(lt(a),a)); - case FOLDR: a=NTV; b=NTV; - return(tf3(tf2(a,b,b),b,lt(a),b)); - case MATCHINT: - case MATCH: a=NTV,b=NTV; - return(tf3(a,b,a,b)); - case TRY: a=NTV; - return(tf2(a,a,a)); - case DROP: - case TAKE: a=lt(NTV); - return(tf2(num_t,a,a)); - case SUBSCRIPT:a=NTV; - return(tf2(num_t,lt(a),a)); - case P: a=NTV; - b=lt(a); - return(tf2(a,b,b)); - case B_p: a=NTV,b=NTV; - c=lt(a); - return(tf3(a,tf(b,c),b,c)); - case C_p: a=NTV,b=NTV; - c=lt(b); - return(tf3(tf(a,b),c,a,c)); - case S1: a=NTV,b=NTV,c=NTV,d=NTV; - return(tf4(tf2(a,b,c),tf(d,a),tf(d,b),d,c)); - case B1: a=NTV,b=NTV,c=NTV,d=NTV; - return(tf4(tf(a,b),tf(c,a),tf(d,c),d,b)); - case C1: a=NTV,b=NTV,c=NTV,d=NTV; - return(tf4(tf2(a,b,c),tf(d,a),b,d,c)); - case SEQ: a=NTV,b=NTV; - return(tf2(a,b,b)); - case ITERATE1: - case ITERATE: a=NTV; - return(tf2(tf(a,a),a,lt(a))); - case EXEC: { if(!exec_t) - a=ap2(comma_t,ltchar,ap2(comma_t,num_t,void_t)), - exec_t=tf(ltchar,ap2(comma_t,ltchar,a)); - return(exec_t); } - case READBIN: - case READ: { if(!read_t) - read_t=tf(char_t,ltchar); - /* $- is ap(READ,0) */ - return(read_t); } - case FILESTAT: { if(!filestat_t) - filestat_t=tf(ltchar,pair_t(pair_t(num_t,num_t),num_t)); - return(filestat_t); } - case FILEMODE: - case GETENV: - case NB_STARTREAD: - case STARTREADBIN: - case STARTREAD: return(tfstrstr); - case GETARGS: return(tf(char_t,lt(ltchar))); - case SHOWHEX: - case SHOWOCT: - case SHOWNUM: return(tf(num_t,ltchar)); - case SHOWFLOAT: - case SHOWSCALED: return(tf2(num_t,num_t,ltchar)); - case NUMVAL: return(tf(ltchar,num_t)); - case INTEGER: return(tf(num_t,bool_t)); - case CODE: return(tf(char_t,num_t)); - case DECODE: return(tf(num_t,char_t)); - case LENGTH: return(tf(lt(NTV),num_t)); - case ENTIER_FN: case ARCTAN_FN: case EXP_FN: case SIN_FN: - case COS_FN: case SQRT_FN: case LOG_FN: case LOG10_FN: - return(tfnumnum); - case MINUS:case PLUS:case TIMES:case INTDIV:case FDIV: - case MOD:case POWER: return(tfnum2); - case True: case False: return(bool_t); - case NIL: a=lt(NTV); - return(a); - case NILS: return(ltchar); - case MKSTRICT: a=NTV; - return(tf(char_t,tf(a,a))); -/* the following are not the true types of the G_fns, which have the action - Ai->lt(bnf_t)->(B:lt(bnf_t)) - here represented by the type Ai->B. G_CLOSE interfaces the parser fns to - the outside world */ - case G_ALT: a=NTV; - return(tf2(a,a,a)); - case G_ERROR: a=NTV; - return(tf2(a,tf(lt(bnf_t),a),a)); - case G_OPT: - case G_STAR: a=NTV; - return(tf(a,lt(a))); - case G_FBSTAR: a=NTV; b=tf(a,a); - return(tf(b,b)); - case G_SYMB: return(tfstrstr); - case G_ANY: return(ltchar); - case G_SUCHTHAT: return(tf(tf(ltchar,bool_t),ltchar)); - case G_END: return(lt(bnf_t)); - case G_STATE: return(tl[hd[tl[bnf_t]]]); - case G_SEQ: a=NTV; b=NTV; - return(tf2(a,tf(a,b),b)); - /* G_RULE has same type as I */ - case G_CLOSE: a=NTV; - if(col_fn) /* offside rule used */ - if(col_fn== -1) /* arbitrary flag */ - TYPERRS++; /*overkill, see note on checkcolfn*/ - else checkcolfn(); - return(tf3(ltchar,a,lt(bnf_t),a)); - case OFFSIDE: return(ltchar); - /* pretend, used by indent, see prelude */ - case FAIL: /* compiled from last guard on rhs */ - case CONFERROR: - case BADCASE: - case UNDEF: return(NTV); - case ERROR: return(tf(ltchar,NTV)); - default: printf("do not know type of "); - out(stdout,x); - putchar('\n'); - return(wrong_t); - } - default: printf("unexpected tag in etype "); - out(stdout,tag[x]); - putchar('\n'); - return(wrong_t); - } -} - -rhs_here(r) -word r; -{ if(tag[r]==LABEL)return(hd[r]); - if(tag[r]==TRIES)return(hd[hd[lastlink(tl[r])]]); - return(0); /* something wrong */ -} /* efficiency hack, sometimes we set lineptr to rhs, can extract here_info - as above when needed */ - -conforms(p,t,e,ngt) /* returns new environment of local type bindings obtained - by conforming pattern p to type t; -1 means failure */ -word p,t,e,ngt; -{ if(e==-1)return(-1); - if(tag[p]==ID&&!isconstructor(p))return(cons(cons(p,t),e)); - if(hd[p]==CONST) - { unify(etype(tl[p],e,ngt),t); return(e); } - if(tag[p]==CONS) - { word at=NTV; - if(!unify(lt(at),t))return(-1); - return(conforms(tl[p],t,conforms(hd[p],at,e,ngt),ngt)); } - if(tag[p]==TCONS) - { word at=NTV,bt=NTV; - if(!unify(ap2(comma_t,at,bt),t))return(-1); - return(conforms(tl[p],bt,conforms(hd[p],at,e,ngt),ngt)); } - if(tag[p]==PAIR) - { word at=NTV,bt=NTV; - if(!unify(ap2(comma_t,at,ap2(comma_t,bt,void_t)),t))return(-1); - return(conforms(tl[p],bt,conforms(hd[p],at,e,ngt),ngt)); } - if(tag[p]==AP&&tag[hd[p]]==AP&&hd[hd[p]]==PLUS) /* n+k pattern */ - { if(!unify(num_t,t))return(1); - return(conforms(tl[p],num_t,e,ngt)); } -{ word p_args=NIL,pt; - while(tag[p]==AP)p_args=cons(tl[p],p_args),p=hd[p]; - if(!isconstructor(p)) - { type_error4(p); return(-1); } - if(id_type(p)==undef_t) - { type_error5(p); return(-1); } - pt= /*instantiate(id_type(p)); */ - instantiate(ATNAMES?rep_t(id_type(p),ATNAMES):id_type(p)); - while(p_args!=NIL&&isarrow_t(pt)) - { e=conforms(hd[p_args],tl[hd[pt]],e,ngt),pt=tl[pt],p_args=tl[p_args]; - if(e==-1)return(-1); } - if(p_args!=NIL||isarrow_t(pt)){ type_error3(p); return(-1); } - if(!unify(pt,t))return(-1); - return(e); -}} - -locate(s) /* for locating type errors */ -char *s; -{ TYPERRS++; - if(TYPERRS==1||lastloc!=current_id) /* avoid tedious repetition */ - if(current_id) - if(tag[current_id]==DATAPAIR) /* see checkfbs */ - { locate_inc(); - printf("%s in binding for %s\n",s,(char *)hd[current_id]); - return; } - else - { extern word fnts; - word x=current_id; - printf("%s in definition of ",s); - while(tag[x]==CONS) - if(tag[tl[x]]==ID&&member(fnts,tl[x])) - printf("nonterminal "),x=hd[x]; else /*note1*/ - out_formal1(stdout,hd[x]),printf(", subdef of "), - x=tl[x]; - printf("%s",get_id(x)); - putchar('\n'); } - else printf("%s in expression\n",s); - if(lineptr)sayhere(lineptr,0); else - if(current_id&&id_who(current_id)!=NIL)sayhere(id_who(current_id),0); - lastloc=current_id; -} -/* note1: this is hack to suppress extra `subdef of <fst start symb>' when - reporting error in defn of non-terminal in %bnf stuff */ - -sayhere(h,nl) /* h is hereinfo - reports location (in parens, newline if nl) - and sets errline/errs if not already set */ -word h,nl; -{ extern word errs,errline; - extern char *current_script; - if(tag[h]!=FILEINFO) - { h=rhs_here(h); - if(tag[h]!=FILEINFO) - { fprintf(stderr,"(impossible event in sayhere)\n"); return; }} - printf("(line %3d of %s\"%s\")",tl[h], - (char *)hd[h]==current_script?"":"%insert file ",(char *)hd[h]); - if(nl)putchar('\n'); else putchar(' '); - if((char *)hd[h]==current_script) - { if(!errline) /* tells editor where first error is */ - errline=tl[h]; } - else { if(!errs)errs=h; } -} - -type_error(a,b,t1,t2) -char *a,*b; -word t1,t2; -{ t1=redtvars(ap(subst(t1),subst(t2))); - t2=tl[t1];t1=hd[t1]; - locate("type error"); - printf("cannot %s ",a);out_type(t1); - printf(" %s ",b);out_type(t2);putchar('\n'); -} - -type_error1(x) /* typename in expression */ -word x; -{ locate("type error"); - printf("typename used as identifier (%s)\n",get_id(x)); -} - -type_error2(x) /* undefined name in expression */ -word x; -{ if(compiling)return; /* treat as type error only in $+ data */ - TYPERRS++; - printf("undefined name - %s\n",get_id(x)); -} - -type_error3(x) /* constructor used at wrong arity in formal */ -word x; -{ locate("error"); - printf("constructor \"%s\" used at wrong arity in formal\n", get_id(x)); -} - -type_error4(x) /* non-constructor as head of formal */ -word x; -{ locate("error"); - printf("illegal object \""); out_pattern(stdout,x); - printf("\" as head of formal\n"); -} - -type_error5(x) /* undeclared constructor in formal */ -word x; -{ locate("error"); - printf("undeclared constructor \""); out_pattern(stdout,x); - printf("\" in formal\n"); - ND=add1(x,ND); -} - -type_error6(x,f,a) -word x,f,a; -{ TYPERRS++; - printf("incorrect declaration "); sayhere(lineptr,1); - printf("specified, %s :: ",get_id(x)); out_type(f); putchar('\n'); - printf("inferred, %s :: ",get_id(x)); out_type(redtvars(subst(a))); - putchar('\n'); -} - -type_error7(t,args) -word t,args; -{ word i=1; - while((args=tl[args])!=NIL)i++; - locate("type error"); - printf(i==1?"1st":i==2?"2nd":i==3?"3rd":"%dth",i); - printf(" arg of zip has type :: "); - out_type(redtvars(subst(t))); - printf("\n - should be list\n"); -} - -type_error8(t1,t2) -word t1,t2; -{ word big; - t1=subst(t1); t2=subst(t2); - if(same(hd[t1],hd[t2])) - t1=tl[t1],t2=tl[t2]; /* discard `[bnf_t]->' */ - t1=redtvars(ap(t1,t2)); - t2=tl[t1];t1=hd[t1]; - big = size(t1)>=10 || size(t2)>=10; - locate("type error"); - printf("cannot unify%s ",big?"\n ":"");out_type(t1); - printf(big?"\nwith\n ":" with ");out_type(t2);putchar('\n'); -} - -unify(t1,t2) /* works by side-effecting SUBST, returns 1,0 as it succeeds - or fails */ -word t1,t2; -{ t1=subst(t1),t2=subst(t2); - if(t1==t2)return(1); - if(isvar_t(t1)&&!occurs(t1,t2)) - { addsubst(t1,t2); return(1); } - if(isvar_t(t2)&&!occurs(t2,t1)) - { addsubst(t2,t1); return(1); } - if(iscompound_t(t1)&&iscompound_t(t2)&& - unify1(hd[t1],hd[t2])&&unify1(tl[t1],tl[t2]))return(1); - type_error("unify","with",t1,t2); - return(0); -} - -unify1(t1,t2) /* inner call - exactly like unify, except error reporting is - done only by top level, see above */ - /* we do this to avoid printing inner parts of types */ -word t1,t2; -{ t1=subst(t1),t2=subst(t2); - if(t1==t2)return(1); - if(isvar_t(t1)&&!occurs(t1,t2)) - { addsubst(t1,t2); return(1); } - if(isvar_t(t2)&&!occurs(t2,t1)) - { addsubst(t2,t1); return(1); } - if(iscompound_t(t1)&&iscompound_t(t2)) - return(unify1(hd[t1],hd[t2])&&unify1(tl[t1],tl[t2])); - return(0); -} - -subsumes(t1,t2) /* like unify but lop-sided; returns 1,0 as t2 falls, doesnt - fall under t1 */ -word t1,t2; -{ if(t2==wrong_t)return(1); - /* special case, shows up only when compiling prelude (changetype etc) */ - return(subsu1(t1,t2,t2)); } - -subsu1(t1,t2,T2) -word t1,t2,T2; -{ t1=subst(t1); - if(t1==t2)return(1); - if(isvar_t(t1)&&!occurs(t1,T2)) - { addsubst(t1,t2); return(1); } - if(iscompound_t(t1)&&iscompound_t(t2)) - return(subsu1(hd[t1],hd[t2],T2)&&subsu1(tl[t1],tl[t2],T2)); - return(0); -} - -walktype(t,f) /* make a copy of t with f applied to its variables */ -word t; -word (*f)(); -{ if(isvar_t(t))return((*f)(t)); - if(iscompound_t(t)) - { word h1=walktype(hd[t],f); - word t1=walktype(tl[t],f); - return(h1==hd[t]&&t1==tl[t]?t:ap(h1,t1)); } - return(t); -} - -occurs(tv,t) /* does tv occur in type t? */ -word tv,t; -{ while(iscompound_t(t)) - { if(occurs(tv,tl[t]))return(1); - t=hd[t]; } - return(tv==t); -} - -ispoly(t) /* does t contain tvars? (should call subst first) */ -word t; -{ while(iscompound_t(t)) - { if(ispoly(tl[t]))return(1); - t=hd[t]; } - return(isvar_t(t)); -} - -word SUBST[hashsize]; /* hash table of substitutions */ - -clear_SUBST() -/* To save time and space we call this after a type inference to clear out - substitutions in extinct variables. Calling this too often can slow you - down - whence #define reset_SUBST, see above */ -{ word i; - fixshows(); - for(i=0;i<hashsize;i++)SUBST[i]=0; - /*printf("tvcount=%d\n",tvcount); /* probe */ - tvcount=1; - return(0); /* see defn of reset_SUBST */ -} -/* doubling hashsize from 512 to 1024 speeded typecheck by only 3% on - parser.m (=350 line block, used c. 5000 tvars) - may be worth increasing - for very large programs however. Guesstimate - further increase from - 512 would be worthwhile on blocks>2000 lines */ - -fixshows() -{ while(showchain!=NIL) - { tl[hd[showchain]]=subst(tl[hd[showchain]]); - showchain=tl[showchain]; } -} - -lookup(tv) /* find current substitution for type variable */ -word tv; -{ word h=SUBST[hashval(tv)]; - while(h) - { if(eqtvar(hd[hd[h]],tv))return(tl[hd[h]]); - h=tl[h]; } - return(tv); /* no substitution found, so answer is self */ -} - -addsubst(tv,t) /* add new substitution to SUBST */ -word tv,t; -{ word h=hashval(tv); - SUBST[h]=cons(cons(tv,t),SUBST[h]); -} - -ult(tv) /* fully substituted out value of a type var */ -word tv; -{ word s=lookup(tv); - return(s==tv?tv:subst(s)); -} - -subst(t) /* returns fully substituted out value of type expression */ -word t; -{ return(walktype(t,ult)); -} - -word localtvmap=NIL; -word NGT=0; - -lmap(tv) -word tv; -{ word l; - if(non_generic(tv))return(tv); - for(l=localtvmap;l!=NIL;l=tl[l]) - if(hd[hd[l]]==tv)return(tl[hd[l]]); - localtvmap=cons(cons(tv,l=NTV),localtvmap); - return(l); -} - -linst(t,ngt) /* local instantiate */ -word t; /* relevant tvars are those not in ngt */ -{ localtvmap=NIL; NGT=ngt; - return(walktype(t,lmap)); -} - -non_generic(tv) -word tv; -{ word x; - for(x=NGT;x!=NIL;x=tl[x]) - if(occurs(tv,subst(hd[x])))return(1); - return(0); -} /* note that when a non-generic tvar is unified against a texp, all tvars - in texp become non-generic; this is catered for by call to subst above - (obviating the need for unify to directly side-effect NGT) */ - -word tvmap=NIL; - -mapup(tv) -word tv; -{ word *m= &tvmap; - tv=gettvar(tv); - while(--tv)m= &tl[*m]; - if(*m==NIL)*m=cons(NTV,NIL); - return(hd[*m]); -} - -instantiate(t) /* make a copy of t with a new set of type variables */ -word t; /* t MUST be in reduced form - see redtvars */ -{ tvmap=NIL; - return(walktype(t,mapup)); -} - -ap_subst(t,args) /* similar, but with a list of substitions for the type - variables provided (args). Again, t must be in reduced form */ -word t,args; -{ word r; - tvmap=args; - r=walktype(t,mapup); - tvmap=NIL; /* ready for next use */ - return(r); -} - - -mapdown(tv) -word tv; -{ word *m= &tvmap; - word i=1; - while(*m!=NIL&&!eqtvar(hd[*m],tv))m= &tl[*m],i++; - if(*m==NIL)*m=cons(tv,NIL); - return(mktvar(i)); -} - -redtvars(t) /* renames the variables in t, in order of appearance to walktype, - using the numbers 1,2,3... */ -word t; -{ tvmap=NIL; - return(walktype(t,mapdown)); -} - - -remove1(e,ss) /* destructively remove e from set with address ss, returning - 1 if e was present, 0 otherwise */ -word e,*ss; -{ while(*ss!=NIL&&hd[*ss]<e)ss= &tl[*ss]; /* we assume set in address order */ - if(*ss==NIL||hd[*ss]!=e)return(0); - *ss=tl[*ss]; - return(1); -} - -setdiff(s1,s2) /* destructive on s1, returns set difference */ -word s1,s2; /* both are in ascending address order */ -{ word *ss1= &s1; - while(*ss1!=NIL&&s2!=NIL) - if(hd[*ss1]==hd[s2])*ss1=tl[*ss1]; else /* removes element */ - if(hd[*ss1]<hd[s2])ss1= &tl[*ss1]; - else s2=tl[s2]; - return(s1); -} - -add1(e,s) /* inserts e destructively into set s, kept in ascending address - order */ -word e,s; -{ word s1=s; - if(s==NIL||e<hd[s])return(cons(e,s)); - if(e==hd[s])return(s); /* no duplicates! */ - while(tl[s1]!=NIL&&e>hd[tl[s1]])s1=tl[s1]; - if(tl[s1]==NIL)tl[s1]=cons(e,NIL);else - if(e!=hd[tl[s1]])tl[s1]=cons(e,tl[s1]); - return(s); -} - -word NEW; /* nasty hack, see rules */ - -newadd1(e,s) /* as above, but with side-effect on NEW */ -word e,s; -{ word s1=s; - NEW=1; - if(s==NIL||e<hd[s])return(cons(e,s)); - if(e==hd[s]){ NEW=0; return(s); } /* no duplicates! */ - while(tl[s1]!=NIL&&e>hd[tl[s1]])s1=tl[s1]; - if(tl[s1]==NIL)tl[s1]=cons(e,NIL);else - if(e!=hd[tl[s1]])tl[s1]=cons(e,tl[s1]); - else NEW=0; - return(s); -} - -UNION(s1,s2) /* destructive on s1; s1, s2 both in address order */ -word s1,s2; -{ word *ss= &s1; - while(*ss!=NIL&&s2!=NIL) - if(hd[*ss]==hd[s2])ss= &tl[*ss],s2=tl[s2]; else - if(hd[*ss]<hd[s2])ss= &tl[*ss]; - else *ss=cons(hd[s2],*ss),ss= &tl[*ss],s2=tl[s2]; - if(*ss==NIL) - while(s2!=NIL)*ss=cons(hd[s2],*ss),ss= &tl[*ss],s2=tl[s2]; - /* must copy tail of s2, in case of later destructive operations on s1 */ - return(s1); -} - -intersection(s1,s2) /* s1, s2 and result all in address order */ -word s1,s2; -{ word r=NIL; - while(s1!=NIL&&s2!=NIL) - if(hd[s1]==hd[s2])r=cons(hd[s1],r),s1=tl[s1],s2=tl[s2]; else - if(hd[s1]<hd[s2])s1=tl[s1]; - else s2=tl[s2]; - return(reverse(r)); -} - -deps(x) /* returns list of the free identifiers in expression x */ -word x; -{ word d=NIL; -L:switch(tag[x]) -{ case AP: - case TCONS: - case PAIR: - case CONS: d=UNION(d,deps(hd[x])); - x=tl[x]; - goto L; - case ID: return(isconstructor(x)?d:add1(x,d)); - case LAMBDA: /* d=UNION(d,patdeps(hd[x])); - /* should add this - see sahbug3.m */ - return(rembvars(UNION(d,deps(tl[x])),hd[x])); - case LET: d=rembvars(UNION(d,deps(tl[x])),dlhs(hd[x])); - return(UNION(d,deps(dval(hd[x])))); - case LETREC: { word y; - d=UNION(d,deps(tl[x])); - for(y=hd[x];y!=NIL;y=tl[y]) - d=UNION(d,deps(dval(hd[y]))); - for(y=hd[x];y!=NIL;y=tl[y]) - d=rembvars(d,dlhs(hd[y])); - return(d); } - case LEXER: while(x!=NIL) - d=UNION(d,deps(tl[tl[hd[x]]])), - x=tl[x]; - return(d); - case TRIES: - case LABEL: x=tl[x]; goto L; - case SHARE: x=hd[x]; goto L; /* repeated analysis - fix later */ - default: return(d); -}} - -rembvars(x,p) /* x is list of ids in address order, remove bv's of pattern p - (destructive on x) */ -word x,p; -{ L: - switch(tag[p]) - { case ID: return(remove1(p,&x),x); - case CONS: if(hd[p]==CONST)return(x); - x=rembvars(x,hd[p]);p=tl[p];goto L; - case AP: if(tag[hd[p]]==AP&&hd[hd[p]]==PLUS) - p=tl[p]; /* for n+k patterns */ - else { x=rembvars(x,hd[p]);p=tl[p]; } - goto L; - case PAIR: - case TCONS: x=rembvars(x,hd[p]);p=tl[p];goto L; - default: fprintf(stderr, "impossible event in rembvars\n"); - return(x); -}} - -member(s,x) -word s,x; -{ while(s!=NIL&&x!=hd[s])s=tl[s]; - return(s!=NIL); -} - -printgraph(title,g) /* for debugging info */ -char *title; -word g; -{ printf("%s\n",title); - while(g!=NIL) - { printelement(hd[hd[g]]); putchar(':'); - printelement(tl[hd[g]]); printf(";\n"); - g=tl[g]; } -} - -printelement(x) -word x; -{ if(tag[x]!=CONS){ out(stdout,x); return; } - putchar('('); - while(x!=NIL) - { out(stdout,hd[x]); - x=tl[x]; - if(x!=NIL)putchar(' '); } - putchar(')'); -} - -printlist(title,l) /* for debugging */ -char *title; -word l; -{ printf("%s",title); - while(l!=NIL) - { printelement(hd[l]); - l=tl[l]; - if(l!=NIL)putchar(','); } - printf(";\n"); -} - -printob(title,x) /* for debugging */ -char *title; -word x; -{ printf("%s",title); out(stdout,x); putchar('\n'); - return(x); } - -print2obs(title,title2,x,y) /* for debugging */ -char *title,*title2; -word x,y; -{ printf("%s",title); out(stdout,x); printf("%s",title2); out(stdout,y); putchar('\n'); -} - -word allchars=0; /* flag used by tail */ - -out_formal1(f,x) -FILE *f; -word x; -{ extern word nill; - if(hd[x]==CONST)x=tl[x]; - if(x==NIL)fprintf(f,"[]"); else - if(tag[x]==CONS&&tail(x)==NIL) - if(allchars) - { fprintf(f,"\"");while(x!=NIL)fprintf(f,"%s",charname(hd[x])),x=tl[x]; - fprintf(f,"\""); } else - { fprintf(f,"["); - while(x!=nill&&x!=NIL) - { out_pattern(f,hd[x]); - x=tl[x]; - if(x!=nill&&x!=NIL)fprintf(f,","); } - fprintf(f,"]"); } else - if(tag[x]==AP||tag[x]==CONS) - { fprintf(f,"("); out_pattern(f,x); - fprintf(f,")"); } else - if(tag[x]==TCONS||tag[x]==PAIR) - { fprintf(f,"("); - while(tag[x]==TCONS) - { out_pattern(f,hd[x]); - x=tl[x]; fprintf(f,","); } - out_pattern(f,hd[x]); fprintf(f,","); out_pattern(f,tl[x]); - fprintf(f,")"); } else - if(tag[x]==INT&&neg(x)||tag[x]==DOUBLE&&get_dbl(x)<0) - { fprintf(f,"("); out(f,x); fprintf(f,")"); } /* -ve numbers */ - else - out(f,x); /* all other cases */ -} - -out_pattern(f,x) -FILE *f; -word x; -{ if(tag[x]==CONS) - if(hd[x]==CONST&&(tag[tl[x]]==INT||tag[tl[x]]==DOUBLE))out(f,tl[x]); else - if(hd[x]!=CONST&&tail(x)!=NIL) - { out_formal(f,hd[x]); fprintf(f,":"); out_pattern(f,tl[x]); } - else out_formal(f,x); - else out_formal(f,x); -} - -out_formal(f,x) -FILE *f; -word x; -{ if(tag[x]!=AP) - out_formal1(f,x); else - if(tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */ - { out_formal(f,tl[x]); fprintf(f,"+"); out(f,tl[hd[x]]); } - else - { out_formal(f,hd[x]); fprintf(f," "); out_formal1(f,tl[x]); } -} - -tail(x) -word x; -{ allchars=1; - while(tag[x]==CONS)allchars&=(is_char(hd[x])),x=tl[x]; - return(x); -} - -out_type(t) /* for printing external representation of types */ -word t; -{ while(isarrow_t(t)) - { out_type1(tl[hd[t]]); - printf("->"); - t=tl[t]; } - out_type1(t); -} - -out_type1(t) -word t; -{ if(iscompound_t(t)&&!iscomma_t(t)&&!islist_t(t)&&!isarrow_t(t)) - { out_type1(hd[t]); - putchar(' '); - t=tl[t]; } - out_type2(t); -} - -out_type2(t) -word t; -{ if(islist_t(t)) - { putchar('['); - out_type(tl[t]); /* could be out_typel, but absence of parentheses - might be confusing */ - putchar(']'); }else - if(iscompound_t(t)) - { putchar('('); - out_typel(t); - if(iscomma_t(t)&&tl[t]==void_t)putchar(','); - /* type of a one-tuple -- an anomaly that should never occur */ - putchar(')'); }else - switch(t) - { - case bool_t: printf("bool"); return; - case num_t: printf("num"); return; - case char_t: printf("char"); return; - case wrong_t: printf("WRONG"); return; - case undef_t: printf("UNKNOWN"); return; - case void_t: printf("()"); return; - case type_t: printf("type"); return; - default: if(tag[t]==ID)printf("%s",get_id(t));else - if(isvar_t(t)) - { word n=gettvar(t); - /*if(1)printf("t%d",n-1); else /* experiment, suppressed */ - /*if(n<=26)putchar('a'+n-1); else /* experiment */ - if(n>0&&n<7)while(n--)putchar('*'); /* 6 stars max */ - else printf("%d",n); }else - if(tag[t]==STRCONS) /* pname - see hack in privatise */ - { extern char *current_script; - if(tag[pn_val(t)]==ID)printf("%s",get_id(pn_val(t))); else - /* ?? one level of indirection sometimes present */ - if(strcmp((char *)hd[tl[t_info(t)]],current_script)==0) - printf("%s",(char *)hd[hd[t_info(t)]]); else /* elision */ - printf("`%s@%s'", - (char *)hd[hd[t_info(t)]], /* original typename */ - (char *)hd[tl[t_info(t)]]); /* sourcefile */ } - else printf("<BADLY FORMED TYPE:%d,%d,%d>",tag[t],hd[t],tl[t]); - } -} - -out_typel(t) -word t; -{ while(iscomma_t(t)) - { out_type(tl[hd[t]]); - t=tl[t]; - if(iscomma_t(t))putchar(','); - else if(t!=void_t)printf("<>"); } /* "tuple-cons", shouldn't occur free */ - if(t==void_t)return; - out_type(t); -} - -/* end of MIRANDA TYPECHECKER */ - |