initial
[prop.git] / prop-src / printgen.pcc
blob73f0b5d4ff3394b80c601ef356c5e771f6b8ea92
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 //  This file implements the pretty printer generator.
4 //
5 ///////////////////////////////////////////////////////////////////////////////
6 #include <ctype.h>
7 #include <string.h>
8 #include <AD/strings/quark.h>
9 #include <AD/strings/charesc.h>
10 #include "ir.ph"
11 #include "ast.ph"
12 #include "datatype.ph"
13 #include "type.h"
14 #include "matchcom.h"
15 #include "list.h"
16 #include "codegen.h"
18 ///////////////////////////////////////////////////////////////////////////////
20 //  Method to generate the interface definition for the pretty printers
22 ///////////////////////////////////////////////////////////////////////////////
23 void DatatypeClass::generate_print_interface(CodeGen& C)
27 void DatatypeHierarchy::generate_print_interface(CodeGen& C)
29    C.pr("%^%/"
30         "%^//"
31         "%^//  Pretty printing methods for %s%V"
32         "%^//"
33         "%^%/"
34         "%^class PrettyOStream;"
35         "%^%Hextern ostream& operator<<(ostream&, %s%v);"
36         "%^%Hextern PrettyOStream& operator<<(PrettyOStream&, %s%v);",
37         datatype_name, parameters,
38         parameters, datatype_name, parameters,
39         parameters, datatype_name, parameters
40        );
43 ///////////////////////////////////////////////////////////////////////////////
45 //  Method to generate the pretty printer implementation.
47 ///////////////////////////////////////////////////////////////////////////////
48 void DatatypeClass::generate_print_implementation(CodeGen&, Tys, DefKind)
52 void DatatypeHierarchy::generate_print_implementation
53    (CodeGen& C, Tys tys, DefKind k)
55    Ty ty = NOty;
56    match (datatype_ty)
57    {  DATATYPEty ({ polyty ... },_): { ty =  apply_ty(polyty,tys); }
58    |  _: // skip
59    }
61    C.pr("%^%/"
62         "%^//"
63         "%^// Pretty printing methods for %s%P"
64         "%^//"
65         "%^%/",
66         datatype_name, tys);
68    //
69    // Generate the ostream based method
70    //
71    C.pr("%^ostream& operator << (ostream& strm__, %t obj__)", ty, "");
73    if (k == EXTERNAL_INSTANTIATION)
74       C.pr("%^{  PrettyOStream S(strm__); S << obj__; return strm__; }\n\n");
75    else
76       C.pr(";");
78    //
79    // Generate the PrettyOStream based method
80    //
81    C.pr("%^PrettyOStream& operator << (PrettyOStream& strm__, %t obj__)",
82         ty,"");
84    if (k == EXTERNAL_INSTANTIATION)
85       C.pr("%^{%+");
86    else
87       C.pr(";");
89    if (k != EXTERNAL_INSTANTIATION) return;
91    if (arity > 1) C.pr("%^switch (%U)%^{%+", IDexp(#"obj__"), ty);
93    for (int i = 0; i < arity; i++)
94    {  Cons term = constructor_terms[i];
95       if (arity > 1) C.pr("%^case %*: %+", term, true);
96       generate_printer(C,tys,k,ty,term);
97       if (arity > 1) C.pr("%^break;%-");
98    }
100    if (arity > 1) C.pr("%-%^}");
101    C.pr("%^return strm__;"
102         "%-%^}");
104    C.pr("\n\n");
108 ///////////////////////////////////////////////////////////////////////////////
110 //  Pretty printer for one single variant
112 ///////////////////////////////////////////////////////////////////////////////
113 void DatatypeHierarchy::generate_printer
114    (CodeGen& C, Tys tys, DefKind k, Ty mono_ty, Cons cons)
115 {  match (cons)
116    {  ONEcons { ty, cons_ty, print_formats ... }:
117       {  cons_arg_ty = ty == NOty ? NOty : apply_ty(cons_ty,tys);
118          if (print_formats == #[])
119          {  generate_default_printer(C,tys,k,mono_ty,cons,cons_arg_ty);
120          } else
121          {  generate_formatted_printer(C,tys,k,mono_ty,
122                                        cons,cons_arg_ty,print_formats);
123          }
124       }
125    |  _: // skip
126    }
129 ///////////////////////////////////////////////////////////////////////////////
131 //  Method to generate a default pretty printer
133 ///////////////////////////////////////////////////////////////////////////////
134 void DatatypeHierarchy::generate_default_printer
135    (CodeGen& C, Tys tys, DefKind k, Ty mono_ty, Cons cons, Ty ty)
136 {  PrintFormats fmt = #[];
137    match (cons) and (deref_all(ty))
138    {  ONEcons { name ... }, NOty | is_list_constructor(name):
139         { fmt = #[SPECIALsym('['),SPECIALsym(']')]; }
140    |  ONEcons { name ... }, NOty:     
141         { fmt = #[TERMSTRINGsym(name)]; } 
142    |  ONEcons { name ... }, TUPLEty #[a,b] | is_list_constructor(name):
143         { fmt = #[SPECIALsym('['), SPECIALsym('L'), SPECIALsym(']')]; }
144    |  ONEcons { name ... }, TUPLEty Ts:
145         { Tys ts;
146           fmt = #[ TERMsym(')') ];
147           Bool comma = false;
148           for(ts = Ts; ts; ts = ts->#2)
149           {  if (comma) fmt = #[ TERMsym(',') ... fmt ];
150              fmt = #[ SPECIALsym('_') ... fmt ]; 
151              comma = true;
152           }
153           fmt = #[TERMSTRINGsym(name), TERMsym('(') ... fmt ];
154         }
155    |  ONEcons { name ... }, EXTUPLEty Ts:
156         { Tys ts;
157           fmt = #[ TERMsym(')') ];
158           Bool comma = false;
159           for(ts = Ts; ts; ts = ts->#2)
160           {  if (comma) fmt = #[ TERMsym(',') ... fmt ];
161              fmt = #[ SPECIALsym('_') ... fmt ]; 
162              comma = true;
163           }
164           fmt = #[TERMSTRINGsym(name), TERMsym('(') ... fmt ];
165         }
166    |  ONEcons { name ... }, RECORDty(Ls,_,Ts):
167         { Ids ls; Tys ts;
168           fmt = #[TERMsym('{'), TERMSTRINGsym(name) ];
169           Bool comma = false;
170           for(ls = Ls, ts = Ts; ls && ts; ls = ls->#2, ts = ts->#2)
171           {  if (comma) fmt = #[ TERMsym(',') ... fmt ];
172              fmt = #[ SPECIALsym('_'),TERMsym('='),TERMSTRINGsym(ls->#1) ... fmt ]; 
173              comma = true;
174           }
175           fmt = #[ TERMsym('}') ... fmt ];
176           fmt = rev(fmt);
177         }
178    |  ONEcons { name ... }, ty:
179         { fmt = #[TERMSTRINGsym(name), TERMsym('('), SPECIALsym('_'),TERMsym(')')];
180         }
181    |  _: // skip
182    }  
183    generate_formatted_printer(C,tys,k,mono_ty,cons,ty,fmt);
186 ///////////////////////////////////////////////////////////////////////////////
188 //  Method to generate a formatted pretty printer
190 ///////////////////////////////////////////////////////////////////////////////
191 void DatatypeHierarchy::generate_formatted_printer
192    (CodeGen& C, Tys tys, DefKind k, Ty mono_ty,
193     Cons cons, Ty ty, PrintFormats fmt)
194 {  Tys tyl  = #[];
195    Ids label_list = #[];
197    match (deref_all(ty))
198    {  NOty:             { tyl = #[]; }
199    |  TUPLEty tys:      { tyl = tys; }
200    |  RECORDty(l,_,t):  { tyl = t; label_list = l; } 
201    |  ty:               { tyl = #[ty]; }
202    }
204    int N = length(tyl);
205    int index = 1;
207    Exp exp = select(IDexp("obj__"),cons,mono_ty);
209    for_each (ProductionSymbol, f, fmt)
210    {  match (f)
211       {  NONTERMsym l: { gen_print_field(C,DOTexp(exp,l),component_ty(ty,l)); }
212       |  POSNONTERMsym i:   
213             { gen_print_field(C,DOTexp(exp,index_of(i)),component_ty(ty,i)); }
214       |  TERMsym c:    
215          {  C.pr("%^strm__ << '%s';", print_char(c)); }
216       |  TERMSTRINGsym s:    
217          {  int len = strlen(s);
218             if (len == 1) 
219             {  C.pr("%^strm__ << '%s';",s);
220             } else if (len == 3 && s[0] == '"' && s[2] == '"' && 
221                        ! isalnum(s[1]))
222             {  C.pr("%^strm__ << '%s';",print_char(s[1]));
223             } else
224             {  Id quote = s[0] == '"' ? "" : "\"";
225                C.pr("%^strm__ << %s%s%s;",quote,s,quote); 
226             }
227          }
228       |  SPECIALsym '[': // Print lists
229          {  C.pr("%^strm__ << '%c';", (int)cons->name[1]); }
230       |  SPECIALsym ']': // Print lists
231          {  char c = cons->name[strlen(cons->name)-1];
232             C.pr("%^strm__ << '%c';", (int)c);
233          }
234       |  SPECIALsym 'L': // Print lists
235          {  char nil_name[4];
236             nil_name[0] = '#'; nil_name[1] = cons->name[1];
237             nil_name[2] = cons->name[5]; nil_name[3] = '\0';
238             Cons nil = lookup_cons(nil_name);
239             C.pr("%^{%+"
240                  "%^int comma__ = 0;"
241                  "%^for (%S%P * l__ = obj__; l__ != %S; l__ = %e)"
242                  "%^{%+" 
243                  "%^if (comma__) strm__ << ',';"
244                  "%^strm__ << %e;"
245                  "%^comma__ = 1;"
246                  "%-%^}"
247                  "%-%^}",
248                  class_name, tys, nil->name,
249                  DOTexp(select(IDexp("l__"),cons,mono_ty),"_2"),
250                  DOTexp(select(IDexp("l__"),cons,mono_ty),"_1")
251                 );
252          }
253       |  SPECIALsym '{': { C.pr("%^strm__.indent().newline().tab();"); }
254       |  SPECIALsym '}': { C.pr("%^strm__.unindent().newline().tab();"); }
255       |  SPECIALsym '/': { C.pr("%^strm__.newline().tab();"); }
256       |  SPECIALsym '_' | tyl != #[]: 
257          {  
258             if (N == 1)
259             {  gen_print_field(C, exp, ty); }
260             else if (label_list == #[])
261             {  gen_print_field(C,DOTexp(exp,index_of(index)),tyl->#1); }
262             else
263             {  gen_print_field(C,DOTexp(exp,label_list->#1),tyl->#1); }
264             C.pr(" // %T", tyl->#1);
265             if (tyl != #[])  tyl = tyl->#2;
266             if (label_list != #[]) label_list = label_list->#2;
267             index++;
268          }
269       |  SPECIALsym c: 
270          {  error ("%!illegal print format '%c' in constructor %s %T\n",
271                    cons->location, (int)c, cons->name, ty);
272          }
273       |  _:
274          {  bug ("%!illegal print format in constructor %s %T\n", 
275                  cons->location, cons->name, ty); 
276          }
277       }
278    }
281 ///////////////////////////////////////////////////////////////////////////////
283 //  Method to generate a formatted pretty printer for a field
285 ///////////////////////////////////////////////////////////////////////////////
286 void DatatypeHierarchy::gen_print_field(CodeGen& C, Exp exp, Ty ty)
288    Id stream = (ty_equal(ty,integer_ty) ||
289                 ty_equal(ty,character_ty) ||
290                 ty_equal(ty,string_ty) ||
291                 ty_equal(ty,bool_ty) ||
292                 ty_equal(ty,real_ty) ||
293                 ty_equal(ty,quark_ty) ||
294                 has_qual(QUALprintable,ty) ||
295                 has_qual(QUALprintable,deref_all(ty))) ? "" : ".stream()";
296    C.pr("%^strm__%s << %e;", stream, exp);