summaryrefslogtreecommitdiff
path: root/new/trans.c
diff options
context:
space:
mode:
Diffstat (limited to 'new/trans.c')
-rw-r--r--new/trans.c1026
1 files changed, 0 insertions, 1026 deletions
diff --git a/new/trans.c b/new/trans.c
deleted file mode 100644
index e50eb8a..0000000
--- a/new/trans.c
+++ /dev/null
@@ -1,1026 +0,0 @@
-/* MIRANDA TRANS */
-/* performs translation to combinatory logic */
-
-/**************************************************************************
- * 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"
-
- /* miscellaneous declarations */
-extern word nill,Void;
-extern word listdiff_fn,count_fn,from_fn;
-extern word diagonalise,concat;
-extern word lastname,initialising;
-extern word current_id,echoing;
-extern word errs;
-word newtyps=NIL; /* list of typenames declared in current script */
-word SGC=NIL; /* list of user defined sui-generis constructors */
-#define sui_generis(k) (/* k==Void|| */ member(SGC,k))
- /* 3/10/88 decision to treat `()' as lifted */
-
-abstract(x,e) /* abstraction of template x from compiled expression e */
-word x,e;
-{ switch(tag[x])
- { case ID:
- if(isconstructor(x))
- return(sui_generis(x)?ap(K,e):
- ap2(Ug,primconstr(x),e));
- else return(abstr(x,e));
- case CONS:
- if(hd[x]==CONST)
- if(tag[tl[x]]==INT)return(ap2(MATCHINT,tl[x],e));
- else return(ap2(MATCH,tl[x]==NILS?NIL:tl[x],e));
- else return(ap(U_,abstract(hd[x],abstract(tl[x],e))));
- case TCONS:
- case PAIR: /* tuples */
- return(ap(U,abstract(hd[x],abstract(tl[x],e))));
- case AP:
- if(sui_generis(head(x)))
- return(ap(Uf,abstract(hd[x],abstract(tl[x],e))));
- if(tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
- return(ap2(ATLEAST,tl[hd[x]],abstract(tl[x],e)));
- while(tag[x]==AP)
- { e= abstract(tl[x],e);
- x= hd[x]; }
- /* now x must be a constructor */
- default: ; }
- if(isconstructor(x))
- return(ap2(Ug,primconstr(x),e));
- printf("error in declaration of \"%s\", undeclared constructor in pattern: ",
- get_id(current_id)); /* something funny here - fix later */
- out(stdout,x);
- printf("\n");
- return(NIL);
-}
-
-primconstr(x)
-word x;
-{ x=id_val(x);
- while(tag[x]!=CONSTRUCTOR)x=tl[x];
- return(x);
- /* => constructor values are of the form TRY f k where k is the
- original constructor value, and ! constructors are of the form
- MKSTRICT i k */
-}
-
-memb(l,x) /* tests if x is a member of list "l" - used in testing for
- repeated names - see rule for "v2" in MIRANDA RULES */
-word l,x;
-{ if(tag[x]==TVAR) /* type variable! */
- while(l!=NIL&&!eqtvar(hd[l],x))l= tl[l];
- else while(l!=NIL&&hd[l]!=x)l= tl[l];
- return(l!=NIL); }
-
-abstr(x,e) /* "bracket abstraction" of variable x from code e */
-word x,e;
-{ switch(tag[e])
- { case TCONS:
- case PAIR:
- case CONS: return(liscomb(abstr(x,hd[e]),abstr(x,tl[e])));
- case AP: if(hd[e]==BADCASE||hd[e]==CONFERROR)
- return(ap(K,e)); /* don't go inside error info */
- return(combine(abstr(x,hd[e]),abstr(x,tl[e])));
- case LAMBDA:
- case LET:
- case LETREC:
- case TRIES:
- case LABEL:
- case SHOW:
- case LEXER:
- case SHARE: fprintf(stderr,"impossible event in abstr (tag=%d)\n",tag[e]),
- exit(1);
- default: if(x==e||isvar_t(x)&&isvar_t(e)&&eqtvar(x,e))
- return(I); /* see note */
- return(ap(K,e));
-}} /* note - we allow abstraction wrt tvars - see genshfns() */
-
-#define mkindex(i) ((i)<256?(i):make(INT,i,0))
- /* will fall over if i >= IBASE */
-
-abstrlist(x,e) /* abstraction of list of variables x from code e */
-word x,e;
-{ switch(tag[e])
- { case TCONS:
- case PAIR:
- case CONS: return(liscomb(abstrlist(x,hd[e]),abstrlist(x,tl[e])));
- case AP: if(hd[e]==BADCASE||hd[e]==CONFERROR)
- return(ap(K,e)); /* don't go inside error info */
- else return(combine(abstrlist(x,hd[e]),abstrlist(x,tl[e])));
- case LAMBDA: case LET: case LETREC: case TRIES: case LABEL: case SHOW:
- case LEXER:
- case SHARE: fprintf(stderr,
- "impossible event in abstrlist (tag=%d)\n",tag[e]),
- exit(1);
- default: { word i=0;
- while(x!=NIL&&hd[x]!=e)i++,x=tl[x];
- if(x==NIL)return(ap(K,e));
- return(ap(SUBSCRIPT,mkindex(i))); }
-}}
-
-word rv_script=0; /* flags readvals in use (for garbage collector) */
-
-codegen(x) /* returns expression x with abstractions performed */
-word x;
-{ extern word debug,commandmode,cook_stdin,common_stdin,common_stdinb,rv_expr;
- switch(tag[x])
- { case AP: if(commandmode /* beware of corrupting lastexp */
- &&x!=cook_stdin&&x!=common_stdin&&x!=common_stdinb) /* but share $+ $- */
- return(make(AP,codegen(hd[x]),codegen(tl[x])));
- if(tag[hd[x]]==AP&&hd[hd[x]]==APPEND&&tl[hd[x]]==NIL)
- return(codegen(tl[x])); /* post typecheck reversal of HR bug fix */
- hd[x]=codegen(hd[x]); tl[x]=codegen(tl[x]);
- /* otherwise do in situ */
- return(tag[hd[x]]==AP&&hd[hd[x]]==G_ALT?leftfactor(x):x);
- case TCONS:
- case PAIR: return(make(CONS,codegen(hd[x]),codegen(tl[x])));
- case CONS: if(commandmode)
- return(make(CONS,codegen(hd[x]),codegen(tl[x])));
- /* otherwise do in situ (see declare) */
- hd[x]=codegen(hd[x]); tl[x]=codegen(tl[x]);
- return(x);
- case LAMBDA: return(abstract(hd[x],codegen(tl[x])));
- case LET: return(translet(hd[x],tl[x]));
- case LETREC: return(transletrec(hd[x],tl[x]));
- case TRIES: return(transtries(hd[x],tl[x]));
- case LABEL: return(codegen(tl[x]));
- case SHOW: return(makeshow(hd[x],tl[x]));
- case LEXER:
- { word r=NIL,uses_state=0;;
- while(x!=NIL)
- { word rule=abstr(mklexvar(0),codegen(tl[tl[hd[x]]]));
- rule=abstr(mklexvar(1),rule);
- if(!(tag[rule]==AP&&hd[rule]==K))uses_state=1;
- r=cons(cons(hd[hd[x]], /* start condition stuff */
- cons(ap(hd[tl[hd[x]]],NIL), /* matcher [] */
- rule)),
- r);
- x=tl[x]; }
- if(!uses_state) /* strip off (K -) from each rule */
- { for(x=r;x!=NIL;x=tl[x])tl[tl[hd[x]]]=tl[tl[tl[hd[x]]]];
- r = ap(LEX_RPT,ap(LEX_TRY,r)); }
- else r = ap(LEX_RPT1,ap(LEX_TRY1,r));
- return(ap(r,0)); } /* 0 startcond */
- case STARTREADVALS:
- if(ispoly(tl[x]))
- { extern word cook_stdin,polyshowerror,ND;
- printf("type error - %s used at polymorphic type :: [",
- cook_stdin&&x==hd[cook_stdin]?"$+":"readvals or $+");
- out_type(redtvars(tl[x])),printf("]\n");
- polyshowerror=1;
- if(current_id)
- ND=add1(current_id,ND),
- id_type(current_id)=wrong_t,
- id_val(current_id)=UNDEF;
- if(hd[x])sayhere(hd[x],1); }
- if(commandmode)rv_expr=1; else rv_script=1;
- return(x);
- case SHARE: if(tl[x]!= -1) /* arbitrary flag for already visited */
- hd[x]=codegen(hd[x]),tl[x]= -1;
- return(hd[x]);
- default: if(x==NILS)return(NIL);
- return(x); /* identifier, private name, or constant */
-}}
-
-word lfrule=0;
-
-leftfactor(x)
-
-/* grammar optimisations - x is of the form ap2(G_ALT,...)
- G_ALT(G_SEQ a b) a => G_SEQ a (G_ALT b G_UNIT)
- G_ALT(G_SEQ a b)(G_SEQ a c) => G_SEQ a (G_ALT b c)
- G_ALT(G_SEQ a b)(G_ALT a d) => G_ALT(G_SEQ a (G_ALT b G_UNIT)) d
- G_ALT(G_SEQ a b)(G_ALT(G_SEQ a c) d) => G_ALT(G_SEQ a (G_ALT b c)) d
-*/
-word x;
-{ word a,b,c,d;
- if(tag[c=tl[hd[x]]]==AP&&tag[hd[c]]==AP&&hd[hd[c]]==G_SEQ)
- a=tl[hd[c]],b=tl[c]; else return(x);
- if(same(a,d=tl[x]))
- { hd[x]=ap(G_SEQ,a), tl[x]=ap2(G_ALT,b,G_UNIT); lfrule++;
- /* printob("rule1: ",x); */
- return(x); }
- if(tag[d]==AP&&tag[hd[d]]==AP)
- c=hd[hd[d]]; else return(x);
- if(c==G_SEQ&&same(a,tl[hd[d]]))
- { c=tl[d],
- hd[x]=ap(G_SEQ,a), tl[x]=leftfactor(ap2(G_ALT,b,c)); lfrule++;
- /* printob("rule2: ",x); */
- return(x); }
- if(c!=G_ALT)return(x);
- if(same(a,c=tl[hd[d]]))
- { d=tl[d];
- hd[x]=ap(G_ALT,ap2(G_SEQ,a,ap2(G_ALT,b,G_UNIT)));
- tl[x]=d; lfrule++;
- /* printob("rule3: ",x); */
- return(leftfactor(x)); }
- if(tag[c]==AP&&tag[hd[c]]==AP&&hd[hd[c]]==G_SEQ
- &&same(a,tl[hd[c]]))
- { c=tl[c],d=tl[d],
- hd[x]=ap(G_ALT,ap2(G_SEQ,a,leftfactor(ap2(G_ALT,b,c))));
- tl[x]=d; lfrule++;
- /* printob("rule4: ",x); */
- return(leftfactor(x)); }
- return(x);
-}
-
-same(x,y) /* structural equality */
-word x,y;
-{ if(x==y)return(1);
- if(tag[x]==ATOM||tag[y]==ATOM||tag[x]!=tag[y])return(0);
- if(tag[x]<INT)return(hd[x]==hd[y]&&tl[x]==tl[y]);
- if(tag[x]>STRCONS)return(same(hd[x],hd[y])&&same(tl[x],tl[y]));
- return(hd[x]==hd[y]&&same(tl[x],tl[y])); /* INT..STRCONS */
-}
-
-static word was_poly;
-word polyshowerror;
-
-makeshow(here,type)
-word here,type;
-{ word f;
- extern word ND;
- was_poly=0; f=mkshow(0,0,type);
- /* printob("showfn=",f); /* DEBUG */
- if(here&&was_poly)
- { extern char *current_script;
- printf("type error in definition of %s\n",get_id(current_id));
- sayhere(here,0);
- printf(" use of \"show\" at polymorphic type ");
- out_type(redtvars(type));
- putchar('\n');
- id_type(current_id)=wrong_t;
- id_val(current_id)=UNDEF;
- polyshowerror=1;
- ND=add1(current_id,ND);
- was_poly=0; }
- return(f);
-}
-
-mkshow(s,p,t) /* build a show function appropriate to type t */
-word s,p,t; /* p is precedence - 0 for top level, 1 for internal */
- /* s flags special case invoked from genshfns */
-{ extern word shownum1,showbool,showchar,showlist,showstring,showparen,
- showvoid,showpair,showfunction,showabstract,showwhat;
- word a=NIL;
- while(tag[t]==AP)a=cons(tl[t],a),t=hd[t];
- switch(t)
- { case num_t: return(p?shownum1:SHOWNUM);
- case bool_t: return(showbool);
- case char_t: return(showchar);
- case list_t: if(hd[a]==char_t)return(showstring);
- return(ap(showlist,mkshow(s,0,hd[a])));
- case comma_t: return(ap(showparen,ap2(showpair,mkshow(s,0,hd[a]),
- mkshowt(s,hd[tl[a]]))));
- case void_t: return(showvoid);
- case arrow_t:return(showfunction);
- default: if(tag[t]==ID)
- { word r=t_showfn(t);
- if(r==0) /* abstype without show function */
- return(showabstract);
- if(r==showwhat) /* dont apply to parameter showfns */
- return(r);
- while(a!=NIL)r=ap(r,mkshow(s,1,hd[a])),a=tl[a];
- if(t_class(t)==algebraic_t)r=ap(r,p);
- return(r);
- /* note that abstype-showfns have only one precedence
- and show their components (if any) at precedence 1
- - if the latter is a problem could do parenthesis
- stripping */
- }
- if(isvar_t(t)){ if(s)return(t); /* see genshfns */
- was_poly=1;
- return(showwhat); }
- /* arbitrary - could be any strict function */
- if(tag[t]==STRCONS) /* pname */ /* DEBUG */
- { printf("warning - mkshow applied to suppressed type\n");
- return(showwhat); }
- else { printf("impossible event in mkshow ("),
- out_type(t), printf(")\n");
- return(showwhat); }
- }
-}
-
-mkshowt(s,t) /* t is a (possibly singleton) tuple type */
-word s,t; /* flags special call from genshfns */
-{ extern word showpair;
- if(tl[t]==void_t)return(mkshow(s,0,tl[hd[t]]));
- return(ap2(showpair,mkshow(s,0,tl[hd[t]]),mkshowt(s,tl[t])));
-}
-
-word algshfns=NIL; /* list of showfunctions for all algebraic types in scope
- (list of pnames) - needed to make dumps */
-
-genshfns() /* called after meta type check - create show functions for
- algebraic types */
-{ word s;
- for(s=newtyps;s!=NIL;s=tl[s])
- if(t_class(hd[s])==algebraic_t)
- { word f=0,r=t_info(hd[s]); /* r is list of constructors */
- word ush= tl[r]==NIL&&member(SGC,hd[r])?Ush1:Ush;
- for(;r!=NIL;r=tl[r])
- { word t=id_type(hd[r]),k=id_val(hd[r]);
- while(tag[k]!=CONSTRUCTOR)k=tl[k];/* lawful and !'d constructors*/
- /* k now holds constructor(i,hd[r]) */
- /* k=constructor(hd[k],datapair(get_id(tl[k]),0));
- /* this `freezes' the name of the constructor */
- /* incorrect, makes showfns immune to aliasing, should be
- done at mkshow time, not genshfn time - FIX LATER */
- while(isarrow_t(t))
- k=ap(k,mkshow(1,1,tl[hd[t]])),t=tl[t]; /* NB 2nd arg */
- k=ap(ush,k);
- while(iscompound_t(t))k=abstr(tl[t],k),t=hd[t];
- /* see kahrs.bug.m (this is the fix) */
- if(f)f=ap2(TRY,k,f);
- else f=k;
- }
- /* f~=0, placeholder types dealt with in specify() */
- pn_val(t_showfn(hd[s]))=f;
- algshfns=cons(t_showfn(hd[s]),algshfns);
- }
- else
- if(t_class(hd[s])==abstract_t) /* if showfn present check type is ok */
- if(t_showfn(hd[s]))
- if(!abshfnck(hd[s],id_type(t_showfn(hd[s]))))
- printf("warning - \"%s\" has type inappropriate for a show-function\n",
- get_id(t_showfn(hd[s]))),t_showfn(hd[s])=0;
-}
-
-abshfnck(t,f) /* t is an abstype, is f right type for its showfn? */
-word t,f;
-{ word n=t_arity(t),i=1;
- while(i<=n)
- if(isarrow_t(f))
- { word h=tl[hd[f]];
- if(!(isarrow_t(h)&&isvar_t(tl[hd[h]])&&gettvar(tl[hd[h]])==i
- &&islist_t(tl[h])&&tl[tl[h]]==char_t))return(0);
- i++,f=tl[f];
- } else return(0);
- if(!(isarrow_t(f)&&islist_t(tl[f])&&tl[tl[f]]==char_t))return(0);
- f=tl[hd[f]];
- while(iscompound_t(f)&&isvar_t(tl[f])&&gettvar(tl[f])==n--)f=hd[f];
- return(f==t);
-}
-
-transtries(id,x)
-word id,x; /* x is a list of alternative values, in reverse order */
-{ word r,h=0,earliest;
- if(fallible(hd[x])) /* add default last case */
- { word oldn=tag[id]==ID?datapair(get_id(id),0):0;
- r=ap(BADCASE,h=cons(oldn,0));
- /* 0 is placeholder for here-info */
- /* oldn omitted if id is pattern - FIX LATER */ }
- else r=codegen(earliest=hd[x]), x = tl[x];
- while(x!=NIL)r=ap2(TRY,codegen(earliest=hd[x]),r), x=tl[x];
- if(h)tl[h]=hd[earliest]; /* first line-no is the best marker */
- return(r);
-}
-
-translet(d,e) /* compile block with body e and def d */
-word d,e;
-{ word x=mklazy(d);
- return(ap(abstract(dlhs(x),codegen(e)),codegen(dval(x))));
-}
-/* nasty bug, codegen(dval(x)) was interfering with abstract(dlhs(x)...
- to fix made codegen on tuples be NOT in situ 20/11/88 */
-
-transletrec(dd,e) /* better method, using list indexing - Jan 88 */
-word e,dd;
-{ word lhs=NIL,rhs=NIL,pn=1;
- /* list of defs (x=e) is combined to listwise def `xs=es' */
- for(;dd!=NIL;dd=tl[dd])
- { word x=hd[dd];
- if(tag[dlhs(x)]==ID) /* couldn't be constructor, by grammar */
- lhs=cons(dlhs(x),lhs),
- rhs=cons(codegen(dval(x)),rhs);
- else { word i=0,ids,p=mkgvar(pn++); /* see note 1 */
- x=new_mklazy(x); ids=dlhs(x);
- lhs=cons(p,lhs),rhs=cons(codegen(dval(x)),rhs);
- for(;ids!=NIL;ids=tl[ids],i++)
- lhs=cons(hd[ids],lhs),
- rhs=cons(ap2(SUBSCRIPT,mkindex(i),p),rhs);
- }
- }
- if(tl[lhs]==NIL) /* singleton */
- return(ap(abstr(hd[lhs],codegen(e)),ap(Y,abstr(hd[lhs],hd[rhs]))));
- return(ap(abstrlist(lhs,codegen(e)),ap(Y,abstrlist(lhs,rhs))));
-}
-/* note 1: we here use the alternative `mklazy' transformation
- pat = e => x1=p!0;...;xn=p!(n-1);p=(lambda(pat)[xs])e|conferror;
- where p is a private name (need be unique only within a given letrec)
-*/
-
-mklazy(d) /* transforms local p=e to ids=($p.ids)e|conferror */
-word d;
-{ if(irrefutable(dlhs(d)))return(d);
-{ word ids=mktuple(dlhs(d));
- if(ids==NIL){ printf("impossible event in mklazy\n"); return(d); }
- dval(d)=ap2(TRY,ap(lambda(dlhs(d),ids),dval(d)),
- ap(CONFERROR,cons(dlhs(d),here_inf(dval(d)))));
- dlhs(d)=ids;
- return(d);
-}}
-
-new_mklazy(d) /* transforms local p=e to ids=($p.ids)e|conferror
- with ids a LIST (not tuple as formerly) */
-word d;
-{ word ids=get_ids(dlhs(d));
- if(ids==NIL){ printf("impossible event in new_mklazy\n"); return(d); }
- dval(d)=ap2(TRY,ap(lambda(dlhs(d),ids),dval(d)),
- ap(CONFERROR,cons(dlhs(d),here_inf(dval(d)))));
- dlhs(d)=ids;
- return(d);
-}
-
-here_inf(rhs) /* rhs is of form tries(id,val_list) */
-word rhs;
-{ word x=tl[rhs];
- while(tl[x]!=NIL)x=tl[x]; /* find earliest alternative */
- return(hd[hd[x]]); /* hd[x] is of form label(here_info,value) */
-}
-
-irrefutable(x) /* x built from suigeneris constr's and (unrepeated) names */
-word x;
-{ if(tag[x]==CONS)return(0); /* includes constants */
- if(isconstructor(x))return(sui_generis(x));
- if(tag[x]==ID)return(1);
- if(tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
- return(0);
- return(irrefutable(hd[x])&&irrefutable(tl[x]));
-}
-
-combine(x,y)
-word x,y;
-{ word a,b,a1,b1;
- a= tag[x]==AP&&hd[x]==K;
- b= tag[y]==AP&&hd[y]==K;
- if(a&&b)return(ap(K,ap(tl[x],tl[y])));
- /* rule of K propagation */
- if(a&&y==I)return(tl[x]);
- /* rule 'eta */
- b1= tag[y]==AP&&tag[hd[y]]==AP&&hd[hd[y]]==B;
- if(a)if(b1)return(ap3(B1,tl[x],tl[hd[y]],tl[y])); else
- /* Mark Scheevel's new B1 introduction rule -- adopted Aug 83 */
- if(tag[tl[x]]==AP&&tag[hd[tl[x]]]==AP&&hd[hd[tl[x]]]==COND)
- return(ap3(COND,tl[hd[tl[x]]],ap(K,tl[tl[x]]),y));
- else return(ap2(B,tl[x],y));
- a1= tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==B;
- if(b)if(a1)if(tag[tl[hd[x]]]==AP&&hd[tl[hd[x]]]==COND)
- return(ap3(COND,tl[tl[hd[x]]],tl[x],y));
- else return(ap3(C1,tl[hd[x]],tl[x],tl[y]));
- else return(ap2(C,x,tl[y]));
- if(a1)if(tag[tl[hd[x]]]==AP&&hd[tl[hd[x]]]==COND)
- return(ap3(COND,tl[tl[hd[x]]],tl[x],y));
- else return(ap3(S1,tl[hd[x]],tl[x],y));
- else return(ap2(S,x,y)); }
-
-liscomb(x,y) /* the CONSy analogue of "combine" */
-word x,y;
-{ word a,b;
- a= tag[x]==AP&&hd[x]==K;
- b= tag[y]==AP&&hd[y]==K;
- if(a&&b)return(ap(K,cons(tl[x],tl[y])));
- /* K propagation again */
- if(a)if(y==I)return(ap(P,tl[x])); /* eta P - new rule added 20/11/88 */
- else return(ap2(B_p,tl[x],y));
- if(b)return(ap2(C_p,x,tl[y]));
- return(ap2(S_p,x,y)); }
-/* B_p,C_p,S_p are the CONSy analogues of B,C,S
- see MIRANDA REDUCE for their definitions */
-
-compzf(e,qq,diag) /* compile a zf expression with body e and qualifiers qq
- (listed in reverse order); diag is 0 for sequential
- and 1 for diagonalising zf expressions */
-word e,qq,diag;
-{ word hold=NIL,r=0,g1= -1; /* r is number of generators */
- while(qq!=NIL) /* unreverse qualifier list */
- { if(hd[hd[qq]]==REPEAT)qq=fixrepeats(qq);
- hold=cons(hd[qq],hold);
- if(hd[hd[qq]]==GUARD)r++; /* count filters */
- qq = tl[qq]; }
- for(qq=hold;qq!=NIL&&hd[hd[qq]]==GUARD;qq=tl[qq])r--; /* less leading filters */
- if(hd[hd[hold]]==GENERATOR)g1=tl[tl[hd[hold]]]; /* rhs of 1st generator */
- e=transzf(e,hold,diag?diagonalise:concat);
- /* diagonalise [ // ] comprehensions, but not [ | ] ones */
- if(diag)
- while(r--)e=ap(concat,e); /* see funny version of rule 3 below */
- return(e==g1?ap2(APPEND,NIL,e):e); /* test in g1 is to fix HR bug */
-}
-/* HR bug - if Rule 1 applied at outermost level, type info is lost
- eg [p|p<-3] ==> 3 (reported by Ham Richards, Nov 89)
-*/
-
-transzf(e,qq,conc) /* Bird and Wadler page 63 */
-word e,qq,conc;
-{ word q,q2;
- if(qq==NIL)return(cons(e,NIL));
- q=hd[qq];
- if(hd[q]==GUARD)
- return(ap3(COND,tl[q],transzf(e,tl[qq],conc),NIL));
- if(tl[qq]==NIL)
- if(hd[tl[q]]==e&&isvariable(e))return(tl[tl[q]]); /* Rule 1 */
- else if(irrefutable(hd[tl[q]]))
- return(ap2(MAP,lambda(hd[tl[q]],e),tl[tl[q]])); /* Rule 2 */
- else /* Rule 2 warped for refutable patterns */
- return(ap2(FLATMAP,lambda(hd[tl[q]],cons(e,NIL)),tl[tl[q]]));
- q2=hd[tl[qq]];
- if(hd[q2]==GUARD)
- if(conc==concat) /* Rule 3 */
- { tl[tl[q]]=ap2(FILTER,lambda(hd[tl[q]],tl[q2]),tl[tl[q]]);
- tl[qq]=tl[tl[qq]];
- return(transzf(e,qq,conc)); }
- else /* funny [//] version of Rule 3 to avoid creating weak lists */
- { e=ap3(COND,tl[q2],cons(e,NIL),NIL);
- tl[qq]=tl[tl[qq]];
- return(transzf(e,qq,conc)); } /* plus wrap result with concat */
- return(ap(conc,transzf(transzf(e,tl[qq],conc),cons(q,NIL),conc)));
- /* Rule 4 */
-}
-
-fixrepeats(qq) /* expands multi-lhs generators in zf expressions */
-word qq;
-{ word q = hd[qq];
- word rhs = q;
- qq = tl[qq];
- while(hd[rhs]==REPEAT)rhs = tl[tl[rhs]];
- rhs = tl[tl[rhs]]; /* rhs now contains the common right hand side */
- while(hd[q]==REPEAT)
- { qq = cons(cons(GENERATOR,cons(hd[tl[q]],rhs)),qq);
- q = tl[tl[q]];
- }
- return(cons(q,qq));
-} /* EFFICIENCY PROBLEM - rhs gets re-evaluated for each lhs, fix later */
- /* likewise re-typechecked, although this probably doesn't matter */
-
-lastlink(x) /* finds last link of a list -- needed with zf body elision */
-word x;
-{ while(tl[x]!=NIL)x=tl[x];
- return(x);
-}
-
-#define ischar(x) ((x)>=0&&(x)<=255)
-
-genlhs(x) /* x is an expression found on the lhs of <- and genlhs returns
- the corresponding pattern */
-word x;
-{ word hold;
- switch(tag[x])
- { case AP:
- if(tag[hd[x]]==AP&&hd[hd[x]]==PLUS&&isnat(tl[x]))
- return(ap2(PLUS,tl[x],genlhs(tl[hd[x]]))); /* n+k pattern */
- case CONS:
- case TCONS:
- case PAIR:
- hold=genlhs(hd[x]); return(make(tag[x],hold,genlhs(tl[x])));
- case ID:
- if(member(idsused,x))return(cons(CONST,x));
- if(!isconstructor(x))idsused=cons(x,idsused); return(x);
- case INT: return(cons(CONST,x));
- case DOUBLE: syntax("floating point literal in pattern\n");
- return(nill);
- case ATOM: if(x==True||x==False||x==NILS||x==NIL||ischar(x))
- return(cons(CONST,x));
- default: syntax("illegal form on left of <-\n");
- return(nill);
-}}
-
-#ifdef OBSOLETE
-genexp(x) /* undoes effect of genlhs - sorry about that! (see qualifiers1)*/
-word x;
-{ switch(tag[x])
- { case AP: return(ap(genexp(hd[x]),genexp(tl[x])));
- case TCONS: return(tcons(genexp(hd[x]),genexp(tl[x])));
- case PAIR: return(pair(genexp(hd[x]),genexp(tl[x])));
- case CONS: return(hd[x]==CONST?tl[x]
- :cons(genexp(hd[x]),genexp(tl[x])));
- default: return(x); /* must be ID or constant */
-}}
-#endif
-
-word speclocs=NIL; /* list of cons(id,hereinfo) giving location of spec for
- ids both defined and specified - needed to locate errs
- in meta_tcheck, abstr_mcheck */
-getspecloc(x)
-word x;
-{ word s=speclocs;
- while(s!=NIL&&hd[hd[s]]!=x)s=tl[s];
- return(s==NIL?id_who(x):tl[hd[s]]); }
-
-declare(x,e) /* translates <pattern> = <exp> at top level */
-word x,e;
-{ if(tag[x]==ID&&!isconstructor(x))decl1(x,e);else
- { word bindings=scanpattern(x,x,share(tries(x,cons(e,NIL)),undef_t),
- ap(CONFERROR,cons(x,hd[e])));
- /* hd[e] is here-info */
- /* note creation of share node to force sharing on code generation
- and typechecking */
- if(bindings==NIL){ errs=hd[e];
- syntax("illegal lhs for definition\n");
- return; }
- lastname=0;
- while(bindings!=NIL)
- { word h;
- if(id_val(h=hd[hd[bindings]])!=UNDEF)
- { errs=hd[e]; nameclash(h); return; }
- id_val(h)=tl[hd[bindings]];
- if(id_who(h)!=NIL)speclocs=cons(cons(h,id_who(h)),speclocs);
- id_who(h)=hd[e]; /* here-info */
- if(id_type(h)==undef_t)addtoenv(h);
- bindings = tl[bindings];
- }
-}}
-
-scanpattern(p,x,e,fail) /* declare ids in x as components of `p=e', each as
- n = ($p.n)e, result is list of bindings */
-word p,x,e,fail;
-{ if(hd[x]==CONST||isconstructor(x))return(NIL);
- if(tag[x]==ID){ word binding=
- cons(x,ap2(TRY,ap(lambda(p,x),e),fail));
- return(cons(binding,NIL)); }
- if(tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
- return(scanpattern(p,tl[x],e,fail));
- return(shunt(scanpattern(p,hd[x],e,fail),scanpattern(p,tl[x],e,fail)));
-}
-
-get_ids(x) /* return list of names in pattern x (without repetitions) */
-word x;
-{ if(hd[x]==CONST||isconstructor(x))return(NIL);
- if(tag[x]==ID)return(cons(x,NIL));
- if(tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
- return(get_ids(tl[x]));
- return(UNION(get_ids(hd[x]),get_ids(tl[x])));
-}
-
-mktuple(x) /* extract tuple-structure of names from pattern x */
-word x;
-{ if(hd[x]==CONST||isconstructor(x))return(NIL);
- if(tag[x]==ID)return(x);
- if(tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
- return(mktuple(tl[x]));
-{ word y=mktuple(tl[x]); x=mktuple(hd[x]);
- return(x==NIL?y:y==NIL?x:pair(x,y));
-}}
-
-decl1(x,e) /* declare name x to have the value denoted by e */
-word x,e;
-{ if(id_val(x)!=UNDEF&&lastname!=x)
- { errs=hd[e]; nameclash(x); return; }
- if(id_val(x)==UNDEF)
- { id_val(x)= tries(x,cons(e,NIL));
- if(id_who(x)!=NIL)speclocs=cons(cons(x,id_who(x)),speclocs);
- id_who(x)= hd[e]; /* here-info */
- if(id_type(x)==undef_t)addtoenv(x);
- } else
- if(!fallible(hd[tl[id_val(x)]]))
- errs=hd[e],
- printf("%ssyntax error: unreachable case in defn of \"%s\"\n",
- echoing?"\n":"",get_id(x)),
- acterror();
- else tl[id_val(x)]= cons(e,tl[id_val(x)]);
-/* multi-clause definitions are composed as tries(id,rhs_list)
- where id is included purely for diagnostic purposes
- note that rhs_list is reversed - put right by code generation */
-}
-
-fallible(e) /* e is "fallible" rhs - if not sure, says yes */
-word e;
-{ for(;;)
- { if(tag[e]==LABEL)e=tl[e];
- if(tag[e]==LETREC||tag[e]==LET)e=tl[e]; else
- if(tag[e]==LAMBDA)
- if(irrefutable(hd[e]))e=tl[e];
- else return(1); else
- if(tag[e]==AP&&tag[hd[e]]==AP&&tag[hd[hd[e]]]==AP&&hd[hd[hd[e]]]==COND)
- e=tl[e]; else
- return(e==FAIL); /* test for nested (COND a b FAIL) */
- }
-} /* NOTE
- When an rhs contains FAIL as a result of compiling an elseless guard set
- it is of the form
- XX ::= ap3(COND,a,b,FAIL) | let[rec](def[s],XX) | lambda(pat,XX)
- an rhs is fallible if
- 1) it is an XX, as above, or
- 2) it is of the form lambda(pat1,...,lambda(patn,e)...)
- where at least one of the patterns pati is refutable.
- */
-
-/* combinator to select i'th out of n args *//*
-k(i,n)
-int i,n;
-{ if(i==1)return(n==1?I:n==2?K:ap2(B,K,k(1,n-1)));
- if(i==2&&n==2)return(KI); /* redundant but saves space *//*
- return(ap(K,k(i-1,n-1)));
-} */
-
-#define arity_check if(t_arity(tf)!=arity)\
- printf("%ssyntax error: \
-wrong number of parameters for typename \"%s\" (%d expected)\n",\
- echoing?"\n":"",get_id(tf),t_arity(tf)),errs=here,acterror()
-
-decltype(tf,class,info,here) /* declare a user defined type */
-word tf,class,info,here;
-{ word arity=0;
- extern word errs;
- while(tag[tf]==AP)arity++,tf=hd[tf];
- if(class==synonym_t&&id_type(tf)==type_t&&t_class(tf)==abstract_t
- &&t_info(tf)==undef_t)
- { /* this is binding for declared but not yet bound abstract typename */
- arity_check;
- id_who(tf)=here;
- t_info(tf)=info;
- return; }
- if(class==abstract_t&&id_type(tf)==type_t&&t_class(tf)==synonym_t)
- { /* this is abstype declaration of already bound typename */
- arity_check;
- t_class(tf)=abstract_t;
- return; }
- if(id_val(tf)!=UNDEF)
- { errs=here; nameclash(tf); return; }
- if(class!=synonym_t)newtyps=add1(tf,newtyps);
- id_val(tf)=make_typ(arity,class==algebraic_t?make_pn(UNDEF):0,class,info);
- if(id_type(tf)!=undef_t){ errs=here; respec_error(tf); return; }
- else addtoenv(tf);
- id_who(tf)=here;
- id_type(tf)=type_t;
-}
-
-declconstr(x,n,t) /* declare x to be constructor number n of type t */
-word x,n,t; /* x must be an identifier */
-{ id_val(x)=constructor(n,x);
- if(n>>16)
- { syntax("algebraic type has too many constructors\n"); return; }
- if(id_type(x)!=undef_t){ errs=id_who(x); respec_error(x); return; }
- else addtoenv(x);
- id_type(x) = t;
-} /* the value of a constructor x is constructor(constr_tag,x)
- where constr_tag is a small natural number */
-
-/* #define DEPSDEBUG .
- /* switches on debugging printouts for dependency analysis in block() */
-#ifdef DEPSDEBUG
-pd(def)
-word def;
-{ out1(stdout,dlhs(def)); }
-
-pdlist(defs)
-word defs;
-{ putchar('(');
- for(;defs!=NIL;defs=tl[defs])
- pd(hd[defs]),printf(tl[defs]==NIL?"":",");
- putchar(')');
-}
-#endif
-
-block(defs,e,keep) /* semantics of "where" - performs dependency analysis */
-/* defs has form list(defn(pat,typ,val)), e is body of block */
-/* if `keep' hold together as single letrec */
-word defs,e,keep;
-{ word ids=NIL,deftoids=NIL,g=NIL,d;
- extern word SYNERR,detrop;
- /* return(letrec(defs,e)); /* release one semantics was just this */
- if(SYNERR)return(NIL); /* analysis falls over on empty patterns */
- for(d=defs;d!=NIL;d=tl[d]) /* first collect all ids defined in block */
- { word x = get_ids(dlhs(hd[d]));
- ids=UNION(ids,x);
- deftoids=cons(cons(hd[d],x),deftoids);
- }
- defs=sort(defs);
- for(d=defs;d!=NIL;d=tl[d]) /* now build dependency relation g */
- { word x=intersection(deps(dval(hd[d])),ids),y=NIL;
- for(;x!=NIL;x=tl[x]) /* replace each id by corresponding def */
- y=add1(invgetrel(deftoids,hd[x]),y);
- g=cons(cons(hd[d],add1(hd[d],y)),g);
- /* treat all defs as recursive for now */
- }
- g=reverse(g); /* keep in address order of first components */
-#ifdef DEPSDEBUG
- { word g1=g;
- printf("g=");
- for(;g1!=NIL;g1=tl[g1])
- pd(hd[hd[g1]]),putchar(':'),pdlist(tl[hd[g1]]),putchar(';');
- printf("\n"); }
-#endif
-/* g is list(cons(def,defs))
- where defs are all on which def immediately depends, plus self */
- g = tclos(g); /* now g is list(cons(def,ultdefs)) */
-#ifdef DEPSDEBUG
- { word g1=g;
- printf("tclos(g)=");
- for(;g1!=NIL;g1=tl[g1])
- pd(hd[hd[g1]]),putchar(':'),pdlist(tl[hd[g1]]),putchar(';');
- printf("\n"); }
-#endif
- { /* check for unused definitions */
- word x=intersection(deps(e),ids),y=NIL,*g1= &g;
- for(;x!=NIL;x=tl[x])
- { word d=invgetrel(deftoids,hd[x]);
- if(!member(y,d))y=UNION(y,getrel(g,d)); }
- defs=setdiff(defs,y); /* these are de trop */
- if(defs!=NIL)detrop=append1(detrop,defs);
- if(keep) /* if local polymorphism not required */
- return(letrec(y,e)); /* analysis was solely to find unwanted defs */
- /* remove redundant entries from g */
- /* no, leave in for typecheck - could remove afterwards
- while(*g1!=NIL&&defs!=NIL)
- if(hd[hd[*g1]]==hd[defs])*g1=tl[*g1]; else
- if(hd[hd[*g1]]<hd[defs])g1= &tl[*g1];
- else defs=tl[defs]; */
- }
- g = msc(g); /* g is list(defgroup,ultdefs) */
-#ifdef DEPSDEBUG
- { word g1=g;
- printf("msc(g)=");
- for(;g1!=NIL;g1=tl[g1])
- pdlist(hd[hd[g1]]),putchar(':'),pdlist(tl[hd[g1]]),putchar(';');
- printf("\n"); }
-#endif
- g = tsort(g); /* g is list(defgroup) in dependency order */
-#ifdef DEPSDEBUG
- { word g1=g;
- printf("tsort(g)=");
- for(;g1!=NIL;g1=tl[g1])
- pdlist(hd[g1]),putchar(';');
- printf("\n"); }
-#endif
- g = reverse(g); /* reconstruct block inside-first */
- while(g!=NIL)
- { if(tl[hd[g]]==NIL &&
- intersection(get_ids(dlhs(hd[hd[g]])),deps(dval(hd[hd[g]])))==NIL
- )e=let(hd[hd[g]],e); /* single non-recursive def */
- else e=letrec(hd[g],e);
- g=tl[g]; }
- return(e);
-}
-/* Implementation note:
- tsort will fall over if there is a non-list strong component because it
- was originally written on assumption that relation is over identifiers.
- Whence need to pretend all defs recursive until after tsort.
- Could do better - some defs may be subsidiary to others */
-
-tclos(r) /* fast transitive closure - destructive in r */
-word r; /* r is of form list(cons(x,xs)) */
-{ word r1;
- for(r1=r;r1!=NIL;r1=tl[r1])
- { word x= less1(tl[hd[r1]],hd[hd[r1]]);
- /* invariant x intersect tl[hd[r1]] = NIL */
- while(x!=NIL)
- { x=imageless(r,x,tl[hd[r1]]);
- tl[hd[r1]]=UNION(tl[hd[r1]],x); }
- }
- return(r);
-}
-
-getrel(r,x) /* r is list(cons(x,xs)) - return appropriate xs, else NIL */
-word r,x;
-{ while(r!=NIL&&hd[hd[r]]!=x)r=tl[r];
- return(r==NIL?NIL:tl[hd[r]]);
-}
-
-invgetrel(r,x) /* return first x1 such that `x1 r x' error if none found */
-word r,x;
-{ while(r!=NIL&&!member(tl[hd[r]],x))r=tl[r];
- if(r==NIL)fprintf(stderr,"impossible event in invgetrel\n"),exit(1);
- return(hd[hd[r]]);
-}
-
-
-imageless(r,y,z) /* image of set y in reln r, less set z */
-word r,y,z;
-{ word i=NIL;
- while(r!=NIL&&y!=NIL)
- if(hd[hd[r]]==hd[y])
- i=UNION(i,less(tl[hd[r]],z)),r=tl[r],y=tl[y]; else
- if(hd[hd[r]]<hd[y])r=tl[r];
- else y=tl[y];
- return(i);
-}
-
-less(x,y) /* non-destructive set difference x-y */
-word x,y;
-{ word r=NIL;
- while(x!=NIL&&y!=NIL)
- if(hd[x]==hd[y])x=tl[x],y=tl[y]; else
- if(hd[x]<hd[y])r=cons(hd[x],r),x=tl[x];
- else y=tl[y];
- return(shunt(r,x));
-}
-
-less1(x,a) /* non-destructive set difference x- {a} */
-word x,a;
-{ word r=NIL;
- while(x!=NIL&&hd[x]!=a)r=cons(hd[x],r),x=tl[x];
- return(shunt(r,x==NIL?NIL:tl[x]));
-}
-
-sort(x) /* into address order */
-word x;
-{ word a=NIL,b=NIL,hold=NIL;
- if(x==NIL||tl[x]==NIL)return(x);
- while(x!=NIL) /* split x */
- { hold=a,a=cons(hd[x],b),b=hold;
- x=tl[x]; }
- a=sort(a),b=sort(b);
- /* now merge two halves back together */
- while(a!=NIL&&b!=NIL)
- if(hd[a]<hd[b])x=cons(hd[a],x),a=tl[a];
- else x=cons(hd[b],x),b=tl[b];
- if(a==NIL)a=b;
- while(a!=NIL)x=cons(hd[a],x),a=tl[a];
- return(reverse(x));
-}
-
-sortrel(x) /* sort relation into address order of first components */
-word x; /* x is a list of cons(y,ys) */
-{ word a=NIL,b=NIL,hold=NIL;
- if(x==NIL||tl[x]==NIL)return(x);
- while(x!=NIL) /* split x */
- { hold=a,a=cons(hd[x],b),b=hold;
- x=tl[x]; }
- a=sortrel(a),b=sortrel(b);
- /* now merge two halves back together */
- while(a!=NIL&&b!=NIL)
- if(hd[hd[a]]<hd[hd[b]])x=cons(hd[a],x),a=tl[a];
- else x=cons(hd[b],x),b=tl[b];
- if(a==NIL)a=b;
- while(a!=NIL)x=cons(hd[a],x),a=tl[a];
- return(reverse(x));
-}
-
-specify(x,t,h) /* semantics of a "::" statement */
-word x,t,h; /* N.B. t not yet in reduced form */
-{ extern word showwhat;
- if(tag[x]!=ID&&t!=type_t){ errs=h;
- syntax("incorrect use of ::\n");
- return; }
- if(t==type_t)
- { word a=0;
- while(tag[x]==AP)a++,x=hd[x];
- if(!(id_val(x)==UNDEF&&id_type(x)==undef_t))
- { errs=h; nameclash(x); return; }
- id_type(x)=type_t;
- if(id_who(x)==NIL)id_who(x)=h; /* premise always true, see above */
- /* if specified and defined, locate by definition */
- id_val(x)=make_typ(a,showwhat,placeholder_t,NIL);/* placeholder type */
- addtoenv(x);
- newtyps=add1(x,newtyps);
- return; }
- if(id_type(x)!=undef_t){ errs=h; respec_error(x); return; }
- id_type(x)=t;
- if(id_who(x)==NIL)id_who(x)=h; /* as above */
- else speclocs=cons(cons(x,h),speclocs);
- if(id_val(x)==UNDEF)addtoenv(x);
-}
-
-respec_error(x) /* only one type spec per name allowed - IS THIS RIGHT? */
-word x;
-{ extern word primenv;
- if(echoing)putchar('\n');
- printf("syntax error: type of \"%s\" already declared%s\n",get_id(x),
- member(primenv,x)?" (in standard environment)":"");
- acterror();
-}
-
-nameclash(x) /* only one top level binding per name allowed */
-word x;
-{ extern word primenv;
- if(echoing)putchar('\n');
- printf("syntax error: nameclash, \"%s\" already defined%s\n",get_id(x),
- member(primenv,x)?" (in standard environment)":"");
- acterror();
-}
-
-nclashcheck(n,dd,hr) /* is n already bound in list of definitions dd */
-word n,dd,hr;
-{ while(dd!=NIL&&!nclchk(n,dlhs(hd[dd]),hr))dd=tl[dd];
-}
-
-nclchk(n,p,hr) /* is n already bound in pattern p */
-word n,p,hr;
-{ if(hd[p]==CONST)return(0);
- if(tag[p]==ID)
- { if(n!=p)return(0);
- if(echoing)putchar('\n');
- errs=hr,
- printf(
-"syntax error: conflicting definitions of \"%s\" in where clause\n",
- get_id(n)),
- acterror();
- return(1); }
- if(tag[p]==AP&&hd[p]==PLUS) /* hd of n+k pattern */
- return(0);
- return(nclchk(n,hd[p],hr)||nclchk(n,tl[p],hr));
-}
-
-transtypeid(x) /* recognises literal type constants - see RULES */
-word x;
-{ char *n=get_id(x);
- return(strcmp(n,"bool")==0?bool_t:
- strcmp(n,"num")==0?num_t:
- strcmp(n,"char")==0?char_t:
- x);
-}
-
-/* end of MIRANDA TRANS */
-