1 ///////////////////////////////////////////////////////////////////////////////
3 // This file implements the pretty printer generator.
5 ///////////////////////////////////////////////////////////////////////////////
8 #include <AD/strings/quark.h>
9 #include <AD/strings/charesc.h>
12 #include "datatype.ph"
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)
31 "%^// Pretty printing methods for %s%V"
34 "%^class PrettyOStream;"
35 "%^%Hextern std::ostream& operator<<(std::ostream&, %s%v);"
36 "%^%Hextern PrettyOStream& operator<<(PrettyOStream&, %s%v);",
37 datatype_name, parameters,
38 parameters, datatype_name, parameters,
39 parameters, datatype_name, parameters
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)
57 { DATATYPEty ({ polyty ... },_): { ty = apply_ty(polyty,tys); }
63 "%^// Pretty printing methods for %s%P"
69 // Generate the ostream based method
71 C.pr("%^std::ostream& operator << (std::ostream& strm__, %t obj__)", ty, "");
73 if (k == EXTERNAL_INSTANTIATION)
74 C.pr("%^{ PrettyOStream S(strm__); S << obj__; return strm__; }\n\n");
79 // Generate the PrettyOStream based method
81 C.pr("%^PrettyOStream& operator << (PrettyOStream& strm__, %t obj__)",
84 if (k == EXTERNAL_INSTANTIATION)
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;%-");
100 if (arity > 1) C.pr("%-%^}");
101 C.pr("%^return strm__;"
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)
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);
121 { generate_formatted_printer(C,tys,k,mono_ty,
122 cons,cons_arg_ty,print_formats);
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:
146 fmt = #[ TERMsym(')') ];
148 for(ts = Ts; ts; ts = ts->#2)
149 { if (comma) fmt = #[ TERMsym(',') ... fmt ];
150 fmt = #[ SPECIALsym('_') ... fmt ];
153 fmt = #[TERMSTRINGsym(name), TERMsym('(') ... fmt ];
155 | ONEcons { name ... }, EXTUPLEty Ts:
157 fmt = #[ TERMsym(')') ];
159 for(ts = Ts; ts; ts = ts->#2)
160 { if (comma) fmt = #[ TERMsym(',') ... fmt ];
161 fmt = #[ SPECIALsym('_') ... fmt ];
164 fmt = #[TERMSTRINGsym(name), TERMsym('(') ... fmt ];
166 | ONEcons { name ... }, RECORDty(Ls,_,Ts):
168 fmt = #[TERMsym('{'), TERMSTRINGsym(name) ];
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 ];
175 fmt = #[ TERMsym('}') ... fmt ];
178 | ONEcons { name ... }, ty:
179 { fmt = #[TERMSTRINGsym(name), TERMsym('('), SPECIALsym('_'),TERMsym(')')];
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)
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]; }
207 Exp exp = select(IDexp("obj__"),cons,mono_ty);
209 for_each (ProductionSymbol, f, fmt)
211 { NONTERMsym l: { gen_print_field(C,DOTexp(exp,l),component_ty(ty,l)); }
213 { gen_print_field(C,DOTexp(exp,index_of(i)),component_ty(ty,i)); }
215 { C.pr("%^strm__ << '%s';", print_char(c)); }
217 { int len = strlen(s);
219 { C.pr("%^strm__ << '%s';",s);
220 } else if (len == 3 && s[0] == '"' && s[2] == '"' &&
222 { C.pr("%^strm__ << '%s';",print_char(s[1]));
224 { Id quote = s[0] == '"' ? "" : "\"";
225 C.pr("%^strm__ << %s%s%s;",quote,s,quote);
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);
234 | SPECIALsym 'L': // Print lists
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);
241 "%^for (%S%P * l__ = obj__; l__ != %S; l__ = %e)"
243 "%^if (comma__) strm__ << ',';"
248 class_name, tys, nil->name,
249 DOTexp(select(IDexp("l__"),cons,mono_ty),"_2"),
250 DOTexp(select(IDexp("l__"),cons,mono_ty),"_1")
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 != #[]:
259 { gen_print_field(C, exp, ty); }
260 else if (label_list == #[])
261 { gen_print_field(C,DOTexp(exp,index_of(index)),tyl->#1); }
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;
270 { error ("%!illegal print format '%c' in constructor %s %T\n",
271 cons->location, (int)c, cons->name, ty);
274 { bug ("%!illegal print format in constructor %s %T\n",
275 cons->location, cons->name, ty);
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);