1 ///////////////////////////////////////////////////////////////////////////////
3 // Module to generate law abbreviations.
5 ///////////////////////////////////////////////////////////////////////////////
13 ///////////////////////////////////////////////////////////////////////////////
17 ///////////////////////////////////////////////////////////////////////////////
18 HashTable DatatypeCompiler::law_env(string_hash,string_equal);
20 ///////////////////////////////////////////////////////////////////////////////
22 // Method to lookup a pattern law.
24 ///////////////////////////////////////////////////////////////////////////////
25 Pat DatatypeCompiler::lookup_pat (Id id)
26 { HashTable::Entry * e = law_env.lookup(id);
27 return e ? (Pat)e->v : NOpat;
30 ///////////////////////////////////////////////////////////////////////////////
32 // Method to enter a new pattern
34 ///////////////////////////////////////////////////////////////////////////////
35 void DatatypeCompiler::add_law(LawDef law_def)
37 { LAWdef { id, args, pat, guard, invert ... }:
38 { if (lookup_pat(id) != NOpat) {
39 error ("%Lduplicated definition of pattern constructor '%s'\n",id);
42 Pat p = guard != NOexp ? GUARDpat(p,guard) : pat;
43 law_env.insert(id, POLYpat(id, length(args), args, p, guard,
50 ///////////////////////////////////////////////////////////////////////////////
52 // Function 'invertible' checks whether a pattern is invertible into
53 // a pseudo constructor.
55 ///////////////////////////////////////////////////////////////////////////////
56 fun invertible NOpat || IDpat _ || LITERALpat _ || INDpat _
57 || CONSpat _ : Bool: { return true; }
58 | invertible WILDpat _ || APPENDpat _ || LOGICALpat _ || ARRAYpat _:
60 | invertible APPpat(CONSpat _,p): { return invertible(p); }
61 | invertible TYPEDpat(p,_): { return invertible(p); }
62 | invertible ASpat(_,p,_,_): { return invertible(p); }
63 | invertible CONTEXTpat(_,p): { return invertible(p); }
64 | invertible TUPLEpat ps: { return invertible(ps); }
65 | invertible EXTUPLEpat ps: { return invertible(ps); }
66 | invertible RECORDpat(ps,flex): { return ! flex && invertible(ps); }
67 | invertible GUARDpat(p,_): { return invertible(p); }
68 | invertible MARKEDpat(_,p): { return invertible(p); }
69 | invertible LISTpat { head, tail ... }:
70 { return invertible(head) && invertible(tail); }
71 | invertible VECTORpat { len, array, elements, head_flex, tail_flex ... }:
72 { return ! head_flex && ! tail_flex &&
73 invertible(len) && invertible(array) && invertible(elements);
75 | invertible p: { bug("invertible: %p", p); return false; }
77 and invertible (#[] : Pats): Bool: { return true; }
78 | invertible #[a ... b]: { return invertible(a) && invertible(b); }
80 and invertible (#[] : LabPats): Bool: { return true; }
81 | invertible #[a ... b]: { return invertible(a.pat) && invertible(b); }
84 ///////////////////////////////////////////////////////////////////////////////
86 // Function to convert a pattern into a variable creation expression.
88 ///////////////////////////////////////////////////////////////////////////////
89 Exp mkvariable (Pat p)
90 { match (deref_all(p->ty))
91 { DATATYPEty({ qualifiers, terms, unit ... },_)
92 | qualifiers & QUALunifiable:
93 { return APPexp(IDexp(terms[unit]->name),TUPLEexp(#[])); }
94 | _: { error("%L%p with type %T is not unifiable\n", p, p->ty);
100 ///////////////////////////////////////////////////////////////////////////////
102 // Function 'pat2exp' converts an invertible pattern into a
103 // constructor expression. Also extracts the bound variable bindings
106 ///////////////////////////////////////////////////////////////////////////////
107 static List<.[Id,Ty]> boundvars = #[];
108 static Exps actual_args = #[];
109 static Bool application_error = false;
110 Bool write_mode = false;
112 fun pat2exp NOpat: Exp: { return NOexp; }
113 | pat2exp p as IDpat(id,_,_):
114 { return write_mode ? mkvariable(p) : IDexp(id); }
115 | pat2exp INDpat(id,i,_) | actual_args != #[]:
117 for_each(Exp, e, actual_args)
118 { if (k == i) return e;
121 error("%LMissing argument %i in law variable %s\n",i,id);
122 application_error = true;
125 | pat2exp INDpat(id,_,ty):
126 { boundvars = #[.(id,ty) ... boundvars];
129 | pat2exp LITERALpat l: { return LITERALexp(l); }
130 | pat2exp TYPEDpat(p,_): { return pat2exp(p); }
131 | pat2exp ASpat(_,p,_,_): { return pat2exp(p); }
132 | pat2exp CONTEXTpat(_,p): { return pat2exp(p); }
133 | pat2exp TUPLEpat ps: { return TUPLEexp(pat2exp(ps)); }
134 | pat2exp EXTUPLEpat ps: { return EXTUPLEexp(pat2exp(ps)); }
135 | pat2exp RECORDpat(ps,_): { return RECORDexp(pat2exp(ps)); }
136 | pat2exp GUARDpat(p,e): { return pat2exp(p); }
137 | pat2exp MARKEDpat(_,p): { return pat2exp(p); }
138 | pat2exp CONSpat(ONEcons{name...}): { return IDexp(name); }
139 | pat2exp APPpat(CONSpat c,e): { return CONSexp(c,#[],pat2exp(e)); }
140 | pat2exp LISTpat { cons, nil, head, tail ... }:
141 { return LISTexp(cons,nil,pat2exp(head),pat2exp(tail)); }
142 | pat2exp VECTORpat { cons, elements ... }:
143 { return VECTORexp(cons,pat2exp(elements)); }
144 | pat2exp p as WILDpat _ | write_mode:
145 { return mkvariable(p); }
146 | pat2exp p: { bug("pat2exp: %p", p); return NOexp; }
148 and pat2exp (#[]: Pats): Exps: { return #[]; }
149 | pat2exp #[a ... b]: { return #[pat2exp(a) ... pat2exp(b)]; }
151 and pat2exp (#[] : LabPats): LabExps: { return #[]; }
152 | pat2exp #[a ... b]: { LabExp labexp;
153 labexp.label = a.label;
154 labexp.exp = pat2exp(a.pat);
155 return #[ labexp ... pat2exp(b) ];
158 and pat2constructor (p : Pat) : Exp:
159 { Bool mode_save = write_mode;
162 write_mode = mode_save;
166 and pat2unifier (p : Pat) : Exp:
167 { Bool mode_save = write_mode;
170 write_mode = mode_save;
175 ///////////////////////////////////////////////////////////////////////////////
177 // Method to lookup a pattern law.
179 ///////////////////////////////////////////////////////////////////////////////
180 Exp DatatypeCompiler::lookup_law (Id id, Exps args)
181 { Pat pat = lookup_pat(id);
183 { POLYpat(id,arity,_,pat,guard,invert) | invert == true:
184 { { if (invertible(pat) && guard == NOexp)
185 { actual_args = args;
186 application_error = false;
187 if (arity != length(args))
188 { error("%Larity mismatch between law %p and arguments %f\n",
189 pat, TUPLEexp(args));
192 Exp exp = pat2exp(pat);
194 if (application_error)
195 error("%Lcannot apply law %p with arguments %f\n",
196 pat, TUPLEexp(args));
199 { error ("%Llaw %s(...) = %p is not invertible\n",id,pat);
208 ///////////////////////////////////////////////////////////////////////////////
210 // Method to generate pattern law definitions
212 ///////////////////////////////////////////////////////////////////////////////
213 void DatatypeCompiler::gen_law_defs (LawDefs law_defs)
215 for_each (LawDef, l, law_defs)
217 { LAWdef{id,args,guard,pat,ty,invert}:
220 // infer the type of the pattern.
223 // If the law is invertible, generate
226 { if (invertible(pat) && guard == NOexp)
228 gen_law_inverse(l->loc(),id,args,pat2constructor(pat),ty);
231 { error ("%Llaw %s(...) = %p is not invertible\n",id,pat);
239 ///////////////////////////////////////////////////////////////////////////////
241 // Check if type can be a C++ parameter
243 ///////////////////////////////////////////////////////////////////////////////
244 Bool is_parameter_type (Ty ty)
246 { TYCONty(RECORDtycon _ || TUPLEtycon || ARRAYtycon _,_): return false;
252 ///////////////////////////////////////////////////////////////////////////////
254 // Method to generate an inverse for a law definition
256 ///////////////////////////////////////////////////////////////////////////////
257 void DatatypeCompiler::gen_law_inverse
258 (const Loc * location, Id id, Ids args, Exp exp, Ty ty)
259 { // Generate the header name
261 "%^// Definition of law %s"
265 id, location->begin_line, location->file_name, ty, id);
267 // Generate the parameters
271 { if (comma) pr(", ");
272 List<.[Id,Ty]> bvs = boundvars;
274 Bool mode_save = write_mode;
277 { #[.(v,ty) ... others]:
279 { if (! is_parameter_type(ty))
280 { error("%Llaw '%s': type %T cannot be used in parameter %s\n",
283 found = true; pr("%t",ty,v);
290 error("%Llaw '%s': bound variable '%s' is absent in body %e\n",
294 write_mode = mode_save;
299 pr(")%^{ return %e; }\n\n", exp);