[project @ 1999-05-11 16:37:29 by keithw]
[ghc-hetmet.git] / ghc / interpreter / output.c
1
2 /* --------------------------------------------------------------------------
3  * Unparse expressions and types - for use in error messages, type checker
4  * and for debugging.
5  *
6  * Hugs 98 is Copyright (c) Mark P Jones, Alastair Reid and the Yale
7  * Haskell Group 1994-99, and is distributed as Open Source software
8  * under the Artistic License; see the file "Artistic" that is included
9  * in the distribution for details.
10  *
11  * $RCSfile: output.c,v $
12  * $Revision: 1.5 $
13  * $Date: 1999/04/27 10:06:57 $
14  * ------------------------------------------------------------------------*/
15
16 #include "prelude.h"
17 #include "storage.h"
18 #include "connect.h"
19 #include "errors.h"
20 #include <ctype.h>
21
22 #define DEPTH_LIMIT     15
23
24 /* --------------------------------------------------------------------------
25  * Local function prototypes:
26  * ------------------------------------------------------------------------*/
27
28 static Void local put            Args((Int,Cell));
29 static Void local putFlds        Args((Cell,List));
30 static Void local putComp        Args((Cell,List));
31 static Void local putQual        Args((Cell));
32 static Bool local isDictVal      Args((Cell));
33 static Cell local maySkipDict    Args((Cell));
34 static Void local putAp          Args((Int,Cell));
35 static Void local putOverInfix   Args((Int,Text,Syntax,Cell));
36 static Void local putInfix       Args((Int,Text,Syntax,Cell,Cell));
37 static Void local putSimpleAp    Args((Cell,Int));
38 static Void local putTuple       Args((Int,Cell));
39 static Int  local unusedTups     Args((Int,Cell));
40 static Void local unlexOp        Args((Text));
41
42 static Void local putSigType     Args((Cell));
43 static Void local putContext     Args((List,List,Int));
44 static Void local putPred        Args((Cell,Int));
45 static Void local putType        Args((Cell,Int,Int));
46 static Void local putTyVar       Args((Int));
47 static Bool local putTupleType   Args((Cell,Int));
48 static Void local putApType      Args((Type,Int,Int));
49
50 static Void local putKind        Args((Kind));
51 static Void local putKinds       Args((Kinds));
52
53 /* --------------------------------------------------------------------------
54  * Basic output routines:
55  * ------------------------------------------------------------------------*/
56
57 FILE *outputStream;                    /* current output stream            */
58 Int  outColumn = 0;                    /* current output column number     */
59                                                                        
60 #define OPEN(b)    if (b) putChr('(');                                 
61 #define CLOSE(b)   if (b) putChr(')');                                 
62                                                                        
63 Void putChr(c)                         /* print single character           */
64 Int c; {                                                               
65     Putc(c,outputStream);                                              
66     outColumn++;                                                       
67 }                                                                      
68                                                                        
69 Void putStr(s)                        /* print string                     */
70 String s; {                                                            
71     for (; *s; s++) {                                                  
72         Putc(*s,outputStream);                                         
73         outColumn++;                                                   
74     }                                                                  
75 }                                                                      
76                                                                        
77 Void putInt(n)                        /* print integer                    */
78 Int n; {
79     static char intBuf[16];
80     sprintf(intBuf,"%d",n);
81     putStr(intBuf);
82 }
83
84 Void putPtr(p)                        /* print pointer                    */
85 Ptr p; {
86     static char intBuf[16];
87     sprintf(intBuf,"%p",p);
88     putStr(intBuf);
89 }
90
91 /* --------------------------------------------------------------------------
92  * Precedence values (See Haskell 1.3 report, p.12):
93  * ------------------------------------------------------------------------*/
94
95 #define ALWAYS      FUN_PREC           /* Always use parens (unless atomic)*/
96                                        /* User defined operators have prec */
97                                        /* in the range MIN_PREC..MAX_PREC  */
98 #define ARROW_PREC  MAX_PREC           /* for printing -> in type exprs    */
99 #define COCO_PREC   (MIN_PREC-1)       /* :: is left assoc, low precedence */
100 #define COND_PREC   (MIN_PREC-2)       /* conditional expressions          */
101 #define WHERE_PREC  (MIN_PREC-3)       /* where expressions                */
102 #define LAM_PREC    (MIN_PREC-4)       /* lambda abstraction               */
103 #define NEVER       LAM_PREC           /* Never use parentheses            */
104
105
106 /* --------------------------------------------------------------------------
107  * Print an expression (used to display context of type errors):
108  * ------------------------------------------------------------------------*/
109
110 static Int putDepth = 0;               /* limits depth of printing DBG     */
111
112 static Void local put(d,e)             /* print expression e in context of */
113 Int  d;                                /* operator of precedence d         */
114 Cell e; {
115     List xs;
116
117     if (putDepth>DEPTH_LIMIT) {
118         putStr("...");
119         return;
120     }
121     else
122         putDepth++;
123
124     switch (whatIs(e)) {
125         case FINLIST    : putChr('[');
126                           xs = snd(e);
127                           if (nonNull(xs)) {
128                               put(NEVER,hd(xs));
129                               while (nonNull(xs=tl(xs))) {
130                                   putChr(',');
131                                   put(NEVER,hd(xs));
132                               }
133                           }
134                           putChr(']');
135                           break;
136
137         case AP         : putAp(d,e);
138                           break;
139
140         case NAME       : unlexVar(name(e).text);
141                           break;
142
143         case VARIDCELL  :
144         case VAROPCELL  :
145         case DICTVAR    :
146         case CONIDCELL  :
147         case CONOPCELL  : unlexVar(textOf(e));
148                           break;
149
150 #if TREX
151         case RECSEL     : putChr('#');
152                           unlexVar(extText(snd(e)));
153                           break;
154 #endif
155
156         case FREECELL   : putStr("{free!}");
157                           break;
158
159         case TUPLE      : putTuple(tupleOf(e),e);
160                           break;
161
162         case WILDCARD   : putChr('_');
163                           break;
164
165         case ASPAT      : put(NEVER,fst(snd(e)));
166                           putChr('@');
167                           put(ALWAYS,snd(snd(e)));
168                           break;
169
170         case LAZYPAT    : putChr('~');
171                           put(ALWAYS,snd(e));
172                           break;
173
174         case DOCOMP     : putStr("do {...}");
175                           break;
176
177         case COMP       : putComp(fst(snd(e)),snd(snd(e)));
178                           break;
179
180         case MONADCOMP  : putComp(fst(snd(snd(e))),snd(snd(snd(e))));
181                           break;
182
183         case CHARCELL   : unlexCharConst(charOf(e));
184                           break;
185
186         case INTCELL    : {   Int i = intOf(e);
187                               if (i<0 && d>=UMINUS_PREC) putChr('(');
188                               putInt(i);
189                               if (i<0 && d>=UMINUS_PREC) putChr(')');
190                           }
191                           break;
192
193         case FLOATCELL  : {   Float f = floatOf(e);
194                               if (f<0 && d>=UMINUS_PREC) putChr('(');
195                               putStr(floatToString(f));
196                               if (f<0 && d>=UMINUS_PREC) putChr(')');
197                           }
198                           break;
199
200         case STRCELL    : unlexStrConst(textOf(e));
201                           break;
202
203         case LETREC     : OPEN(d>WHERE_PREC);
204 #if DEBUG_CODE
205                           putStr("let {");
206                           put(NEVER,fst(snd(e)));
207                           putStr("} in ");
208 #else
209                           putStr("let {...} in ");
210 #endif
211                           put(WHERE_PREC+1,snd(snd(e)));
212                           CLOSE(d>WHERE_PREC);
213                           break;
214
215         case COND       : OPEN(d>COND_PREC);
216                           putStr("if ");
217                           put(COND_PREC+1,fst3(snd(e)));
218                           putStr(" then ");
219                           put(COND_PREC+1,snd3(snd(e)));
220                           putStr(" else ");
221                           put(COND_PREC+1,thd3(snd(e)));
222                           CLOSE(d>COND_PREC);
223                           break;
224
225         case LAMBDA     : xs = fst(snd(e));
226                           if (whatIs(xs)==BIGLAM)
227                               xs = snd(snd(xs));
228                           while (nonNull(xs) && isDictVal(hd(xs)))
229                               xs = tl(xs);
230                           if (isNull(xs)) {
231                               put(d,snd(snd(snd(e))));
232                               break;
233                           }
234                           OPEN(d>LAM_PREC);
235                           putChr('\\');
236                           if (nonNull(xs)) {
237                               put(ALWAYS,hd(xs));
238                               while (nonNull(xs=tl(xs))) {
239                                   putChr(' ');
240                                   put(ALWAYS,hd(xs));
241                               }
242                           }
243                           putStr(" -> ");
244                           put(LAM_PREC,snd(snd(snd(e))));
245                           CLOSE(d>LAM_PREC);
246                           break;
247
248         case ESIGN      : OPEN(d>COCO_PREC);
249                           put(COCO_PREC,fst(snd(e)));
250                           putStr(" :: ");
251                           putSigType(snd(snd(e)));
252                           CLOSE(d>COCO_PREC);
253                           break;
254
255         case BIGLAM     : put(d,snd(snd(e)));
256                           break;
257
258         case CASE       : putStr("case ");
259                           put(NEVER,fst(snd(e)));
260 #if DEBUG_CODE
261                           putStr(" of {");
262                           put(NEVER,snd(snd(e)));
263                           putChr('}');
264 #else
265                           putStr(" of {...}");
266 #endif
267                           break;
268
269         case CONFLDS    : putFlds(fst(snd(e)),snd(snd(e)));
270                           break;
271
272         case UPDFLDS    : putFlds(fst3(snd(e)),thd3(snd(e)));
273                           break;
274
275         default         : /*internal("put");*/
276                           putChr('$');
277                           putInt(e);
278                           break;
279     }
280     putDepth--;
281 }
282
283 static Void local putFlds(exp,fs)       /* Output exp using labelled fields*/
284 Cell exp;
285 List fs; {
286     put(ALWAYS,exp);
287     putChr('{');
288     for (; nonNull(fs); fs=tl(fs)) {
289         Cell v = hd(fs);
290         if (isVar(v))
291             put(NEVER,v);
292         else {
293             Cell f = fst(v);
294             Cell e = snd(v);
295             Text t = isName(f) ? name(f).text :
296                      isVar(f)  ? textOf(f)    : inventText();
297             Text s = isName(e) ? name(e).text :
298                      isVar(e)  ? textOf(e)    : inventText();
299
300             put(NEVER,f);
301             if (haskell98 || s!=t) {
302                 putStr(" = ");
303                 put(NEVER,e);
304             }
305         }
306         if (nonNull(tl(fs)))
307             putStr(", ");
308     }
309     putChr('}');
310 }
311
312 static Void local putComp(e,qs)         /* print comprehension             */
313 Cell e;
314 List qs; {
315     putStr("[ ");
316     put(NEVER,e);
317     if (nonNull(qs)) {
318         putStr(" | ");
319         putQual(hd(qs));
320         while (nonNull(qs=tl(qs))) {
321             putStr(", ");
322             putQual(hd(qs));
323         }
324     }
325     putStr(" ]");
326 }
327
328 static Void local putQual(q)            /* print list comp qualifier       */
329 Cell q; {
330     switch (whatIs(q)) {
331         case BOOLQUAL : put(NEVER,snd(q));
332                         return;
333
334         case QWHERE   : putStr("let {...}");
335                         return;
336
337         case FROMQUAL : put(ALWAYS,fst(snd(q)));
338                         putStr("<-");
339                         put(NEVER,snd(snd(q)));
340                         return;
341     }
342 }
343
344 static Bool local isDictVal(e)          /* Look for dictionary value       */
345 Cell e; {
346 #if !DEBUG_CODE
347     Cell h = getHead(e);
348     switch (whatIs(h)) {
349         case DICTVAR : return TRUE;
350         case NAME    : return isDfun(h);
351     }
352 #endif
353     return FALSE;
354 }
355
356 static Cell local maySkipDict(e)        /* descend function application,   */
357 Cell e; {                               /* ignoring dict aps               */
358     while (isAp(e) && isDictVal(arg(e)))
359         e = fun(e);
360     return e;
361 }
362
363 static Void local putAp(d,e)            /* print application (args>=1)     */
364 Int  d;
365 Cell e; {
366     Cell   h;
367     Text   t;
368     Syntax sy;
369     Int    args = 0;
370
371     for (h=e; isAp(h); h=fun(h))        /* find head of expression, looking*/
372         if (!isDictVal(arg(h)))         /* for dictionary arguments        */
373             args++;
374
375     if (args==0) {                      /* Special case when *all* args    */
376         put(d,h);                       /* are dictionary values           */
377         return;
378     }
379
380     switch (whatIs(h)) {
381 #if NPLUSK
382         case ADDPAT     : if (args==1)
383                               putInfix(d,textPlus,syntaxOf(namePlus),
384                                          arg(e),mkInt(intValOf(fun(e))));
385                           else
386                               putStr("ADDPAT");
387                           return;
388 #endif
389
390         case TUPLE      : OPEN(args>tupleOf(h) && d>=FUN_PREC);
391                           putTuple(tupleOf(h),e);
392                           CLOSE(args>tupleOf(h) && d>=FUN_PREC);
393                           return;
394
395         case NAME       : if (args==1 &&
396                               ((h==nameFromInt     && isInt(arg(e)))    ||
397                                (h==nameFromDouble  && isFloat(arg(e))))) {
398                               put(d,arg(e));
399                               return;
400                           }
401                           t  = name(h).text;
402                           sy = syntaxOf(h);
403                           break;
404
405         case VARIDCELL  :
406         case VAROPCELL  :
407         case DICTVAR    :
408         case CONIDCELL  :
409         case CONOPCELL  : sy = defaultSyntax(t = textOf(h));
410                           break;
411
412 #if TREX
413         case EXT        : if (args==2) {
414                               String punc = "(";
415                               do {
416                                   putStr(punc);
417                                   punc = ", ";
418                                   putStr(textToStr(extText(h)));
419                                   putStr("=");
420                                   put(NEVER,extField(e));
421                                   args = 0;
422                                   e    = extRow(e);
423                                   for (h=e; isAp(h); h=fun(h))
424                                       if (!isDictVal(arg(h)))
425                                           args++;
426                               } while (isExt(h) && args==2);
427                               if (e!=nameNoRec) {
428                                   putStr(" | ");
429                                   put(NEVER,e);
430                               }
431                               putChr(')');
432                               return;
433                           }
434                           else if (args<2)
435                               internal("putExt");
436                           else
437                               args-=2;
438                           break;
439 #endif
440
441         default         : sy = APPLIC;
442                           break;
443     }
444
445     e = maySkipDict(e);
446
447     if (sy==APPLIC) {                   /* print simple application        */
448         OPEN(d>=FUN_PREC);
449         putSimpleAp(e,args);
450         CLOSE(d>=FUN_PREC);
451         return;
452     }
453     else if (args==1) {                 /* print section of the form (e+)  */
454         putChr('(');
455         put(FUN_PREC-1,arg(e));
456         putChr(' ');
457         unlexOp(t);
458         putChr(')');
459     }
460     else if (args==2)                  /* infix expr of the form e1 + e2   */
461         putInfix(d,t,sy,arg(maySkipDict(fun(e))),arg(e));
462     else {                             /* o/w (e1 + e2) e3 ... en   (n>=3) */
463         OPEN(d>=FUN_PREC);
464         putOverInfix(args,t,sy,e);
465         CLOSE(d>=FUN_PREC);
466     }
467 }
468
469 static Void local putOverInfix(args,t,sy,e)
470 Int    args;                           /* infix applied to >= 3 arguments  */
471 Text   t;
472 Syntax sy;
473 Cell   e; {
474     if (args>2) {
475         putOverInfix(args-1,t,sy,maySkipDict(fun(e)));
476         putChr(' ');
477         put(FUN_PREC,arg(e));
478     }
479     else
480         putInfix(ALWAYS,t,sy,arg(maySkipDict(fun(e))),arg(e));
481 }
482
483 static Void local putInfix(d,t,sy,e,f)  /* print infix expression          */
484 Int    d;
485 Text   t;                               /* Infix operator symbol           */
486 Syntax sy;                              /* with name t, syntax s           */
487 Cell   e, f; {                          /* Left and right operands         */
488     Syntax a = assocOf(sy);
489     Int    p = precOf(sy);
490
491     OPEN(d>p);
492     put((a==LEFT_ASS ? p : 1+p), e);
493     putChr(' ');
494     unlexOp(t);
495     putChr(' ');
496     put((a==RIGHT_ASS ? p : 1+p), f);
497     CLOSE(d>p);
498 }
499
500 static Void local putSimpleAp(e,n)      /* print application e0 e1 ... en  */
501 Cell e; 
502 Int  n; {
503     if (n>0) {
504         putSimpleAp(maySkipDict(fun(e)),n-1);
505         putChr(' ');
506         put(FUN_PREC,arg(e));
507     }
508     else
509         put(FUN_PREC,e);
510 }
511
512 static Void local putTuple(ts,e)        /* Print tuple expression, allowing*/
513 Int  ts;                                /* for possibility of either too   */
514 Cell e; {                               /* few or too many args to constr  */
515     Int i;
516     putChr('(');
517     if ((i=unusedTups(ts,e))>0) {
518         while (--i>0)
519             putChr(',');
520         putChr(')');
521     }
522 }
523
524 static Int local unusedTups(ts,e)       /* print first part of tuple expr  */
525 Int  ts;                                /* returning number of constructor */
526 Cell e; {                               /* args not yet printed ...        */
527     if (isAp(e)) {
528         if ((ts=unusedTups(ts,fun(e))-1)>=0) {
529             put(NEVER,arg(e));
530             putChr(ts>0?',':')');
531         }
532         else {
533             putChr(' ');
534             put(FUN_PREC,arg(e));
535         }
536     }
537     return ts;
538 }
539
540 Void unlexVar(t)                       /* print text as a variable name    */
541 Text t; {                              /* operator symbols must be enclosed*/
542     String s = textToStr(t);           /* in parentheses... except [] ...  */
543
544     if ((isascii((int)(s[0])) && isalpha((int)(s[0]))) 
545        || s[0]=='_' || s[0]=='[' || s[0]=='(')
546         putStr(s);
547     else {
548         putChr('(');
549         putStr(s);
550         putChr(')');
551     }
552 }
553
554 static Void local unlexOp(t)           /* print text as operator name      */
555 Text t; {                              /* alpha numeric symbols must be    */
556     String s = textToStr(t);           /* enclosed by backquotes           */
557
558     if (isascii((int)(s[0])) && isalpha((int)(s[0]))) {
559         putChr('`');
560         putStr(s);
561         putChr('`');
562     }
563     else
564         putStr(s);
565 }
566
567 Void unlexCharConst(c)
568 Cell c; {
569     putChr('\'');
570     putStr(unlexChar(c,'\''));
571     putChr('\'');
572 }
573
574 Void unlexStrConst(t)
575 Text t; {
576     String s            = textToStr(t);
577     static Char SO      = 14;          /* ASCII code for '\SO'             */
578     Bool   lastWasSO    = FALSE;
579     Bool   lastWasDigit = FALSE;
580     Bool   lastWasEsc   = FALSE;
581
582     putChr('\"');
583     for (; *s; s++) {
584         String ch = unlexChar(*s,'\"');
585         Char   c  = ' ';
586
587         if ((lastWasSO && *ch=='H') ||
588                 (lastWasEsc && lastWasDigit 
589                  && isascii((int)(*ch)) && isdigit((int)(*ch))))
590             putStr("\\&");
591
592         lastWasEsc   = (*ch=='\\');
593         lastWasSO    = (*s==SO);
594         for (; *ch; c = *ch++)
595             putChr(*ch);
596         lastWasDigit = (isascii(c) && isdigit(c));
597     }
598     putChr('\"');
599 }
600
601 /* --------------------------------------------------------------------------
602  * Print type expression:
603  * ------------------------------------------------------------------------*/
604
605 static Void local putSigType(t)         /* print (possibly) generic type   */
606 Cell t; {
607     Int fr = 0;
608     if (isPolyType(t)) {
609         Kinds ks = polySigOf(t);
610         for (; isAp(ks); ks=tl(ks))
611             fr++;
612         t = monotypeOf(t);
613     }
614
615     putType(t,NEVER,fr);                /* Finally, print rest of type ... */
616 }
617
618 static Void local putContext(ps,qs,fr)  /* print context list              */
619 List ps;
620 List qs;
621 Int  fr; {
622     Int len = length(ps) + length(qs);
623     Int c   = len;
624     if (len!=1) {
625         putChr('(');
626     }
627     for (; nonNull(ps); ps=tl(ps)) {
628         putPred(hd(ps),fr);
629         if (--c > 0) {
630             putStr(", ");
631         }
632     }
633     for (; nonNull(qs); qs=tl(qs)) {
634         putPred(hd(qs),fr);
635         if (--c > 0) {
636             putStr(", ");
637         }
638     }
639     if (len!=1) {
640         putChr(')');
641     }
642 }
643
644 static Void local putPred(pi,fr)        /* Output predicate                */
645 Cell pi;
646 Int  fr; {
647     if (isAp(pi)) {
648 #if TREX
649         if (isExt(fun(pi))) {
650             putType(arg(pi),ALWAYS,fr);
651             putChr('\\');
652             putStr(textToStr(extText(fun(pi))));
653             return;
654         }
655 #endif
656         putPred(fun(pi),fr);
657         putChr(' ');
658         putType(arg(pi),ALWAYS,fr);
659     }
660     else if (isClass(pi))
661         putStr(textToStr(cclass(pi).text));
662     else if (isCon(pi))
663         putStr(textToStr(textOf(pi)));
664     else
665         putStr("<unknownPredicate>");
666 }
667
668 static Void local putType(t,prec,fr)    /* print nongeneric type expression*/
669 Cell t;
670 Int  prec;
671 Int  fr; {
672     switch(whatIs(t)) {
673         case TYCON     : putStr(textToStr(tycon(t).text));
674                          break;
675
676         case TUPLE     : {   Int n = tupleOf(t);
677                              putChr('(');
678                              while (--n > 0)
679                                  putChr(',');
680                              putChr(')');
681                          }
682                          break;
683
684         case POLYTYPE  : {   Kinds ks = polySigOf(t);
685                              OPEN(prec>=ARROW_PREC);
686                              putStr("forall ");
687                              for (; isAp(ks); ks=tl(ks)) {
688                                  putTyVar(fr++);
689                                  if (isAp(tl(ks)))
690                                      putChr(',');
691                              }
692                              putStr(". ");
693                              putType(monotypeOf(t),NEVER,fr);
694                              CLOSE(prec>=ARROW_PREC);
695                          }
696                          break;
697
698         case CDICTS    :
699         case QUAL      : OPEN(prec>=ARROW_PREC);
700                          if (whatIs(snd(snd(t)))==CDICTS) {
701                              putContext(fst(snd(t)),fst(snd(snd(snd(t)))),fr);
702                              putStr(" => ");
703                              putType(snd(snd(snd(snd(t)))),NEVER,fr);
704                          } else {
705                              putContext(fst(snd(t)),NIL,fr);
706                              putStr(" => ");
707                              putType(snd(snd(t)),NEVER,fr);
708                          }
709                          CLOSE(prec>=ARROW_PREC);
710                          break;
711
712         case EXIST     :
713         case RANK2     : putType(snd(snd(t)),prec,fr);
714                          break;
715
716         case OFFSET    : putTyVar(offsetOf(t));
717                          break;
718
719         case VARIDCELL :
720         case VAROPCELL : putChr('_');
721                          unlexVar(textOf(t));
722                          break;
723
724         case INTCELL   : putChr('_');
725                          putInt(intOf(t));
726                          break;
727
728         case AP       : {   Cell typeHead = getHead(t);
729                             Bool brackets = (argCount!=0 && prec>=ALWAYS);
730                             Int  args    = argCount;
731
732                             if (typeHead==typeList) {
733                                 if (argCount==1) {
734                                     putChr('[');
735                                     putType(arg(t),NEVER,fr);
736                                     putChr(']');
737                                     return;
738                                 }
739                             }
740                             else if (typeHead==typeArrow) {
741                                 if (argCount==2) {
742                                     OPEN(prec>=ARROW_PREC);
743                                     putType(arg(fun(t)),ARROW_PREC,fr);
744                                     putStr(" -> ");
745                                     putType(arg(t),NEVER,fr);
746                                     CLOSE(prec>=ARROW_PREC);
747                                     return;
748                                 }
749                                 else if (argCount==1) {
750                                     putChr('(');
751                                     putType(arg(t),ARROW_PREC,fr);
752                                     putStr("->)");
753                                     return;
754                                 }
755                             }
756                             else if (isTuple(typeHead)) {
757                                 if (argCount==tupleOf(typeHead)) {
758                                     putChr('(');
759                                     putTupleType(t,fr);
760                                     putChr(')');
761                                     return;
762                                 }
763                             }
764 #if TREX
765                             else if (isExt(typeHead)) {
766                                 if (args==2) {
767                                     String punc = "(";
768                                     do {
769                                         putStr(punc);
770                                         punc = ", ";
771                                         putStr(textToStr(extText(typeHead)));
772                                         putStr("::");
773                                         putType(extField(t),NEVER,fr);
774                                         t        = extRow(t);
775                                         typeHead = getHead(t);
776                                     } while (isExt(typeHead) && argCount==2);
777                                     if (t!=typeNoRow) {
778                                         putStr(" | ");
779                                         putType(t,NEVER,fr);
780                                     }
781                                     putChr(')');
782                                     return;
783                                 }
784                                 else if (args<2)
785                                     internal("putExt");
786                                 else
787                                     args-=2;
788                             }
789 #endif
790                             OPEN(brackets);
791                             putApType(t,args,fr);
792                             CLOSE(brackets);
793                         }
794                         break;
795
796         default       : putStr("(bad type)");
797     }
798 }
799
800 static Void local putTyVar(n)           /* print type variable             */
801 Int n; {
802     static String alphabet              /* for the benefit of EBCDIC :-)   */
803                 ="abcdefghijklmnopqrstuvwxyz";
804     putChr(alphabet[n%26]);
805     if (n /= 26)                        /* just in case there are > 26 vars*/
806         putInt(n);
807 }
808
809 static Bool local putTupleType(e,fr)    /* print tuple of types, returning */
810 Cell e;                                 /* TRUE if something was printed,  */
811 Int  fr; {                              /* FALSE otherwise; used to control*/
812     if (isAp(e)) {                      /* printing of intermed. commas    */
813         if (putTupleType(fun(e),fr))
814             putChr(',');
815         putType(arg(e),NEVER,fr);
816         return TRUE;
817     }
818     return FALSE;
819 }
820
821 static Void local putApType(t,n,fr)     /* print type application          */
822 Cell t;
823 Int  n;
824 Int  fr; {
825     if (n>0) {
826         putApType(fun(t),n-1,fr);
827         putChr(' ');
828         putType(arg(t),ALWAYS,fr);
829     }
830     else
831         putType(t,ALWAYS,fr);
832 }
833
834 /* --------------------------------------------------------------------------
835  * Print kind expression:
836  * ------------------------------------------------------------------------*/
837
838 static Void local putKind(k)            /* print kind expression           */
839 Kind k; {
840     switch (whatIs(k)) {
841         case AP      : if (isAp(fst(k))) {
842                            putChr('(');
843                            putKind(fst(k));
844                            putChr(')');
845                        }
846                        else
847                            putKind(fst(k));
848                        putStr(" -> ");
849                        putKind(snd(k));
850                        break;
851
852 #if TREX
853         case ROW     : putStr("row");
854                        break;
855 #endif
856
857         case STAR    : putChr('*');
858                        break;
859
860         case OFFSET  : putTyVar(offsetOf(k));
861                        break;
862
863         case INTCELL : putChr('_');
864                        putInt(intOf(k));
865                        break;
866
867         default      : putStr("(bad kind)");
868     }
869 }
870
871 static Void local putKinds(ks)          /* Print list of kinds             */
872 Kinds ks; {
873     if (isNull(ks))
874         putStr("()");
875     else if (nonNull(tl(ks))) {
876         putChr('(');
877         putKind(hd(ks));
878         while (nonNull(ks=tl(ks))) {
879             putChr(',');
880             putKind(hd(ks));
881         }
882         putChr(')');
883     }
884     else
885         putKind(hd(ks));
886 }
887
888 /* --------------------------------------------------------------------------
889  * Main drivers:
890  * ------------------------------------------------------------------------*/
891
892 Void printExp(fp,e)                     /* print expr on specified stream  */
893 FILE *fp;
894 Cell e; {
895     outputStream = fp;
896     putDepth     = 0;
897     put(NEVER,e);
898 }
899
900 Void printType(fp,t)                    /* print type on specified stream  */
901 FILE *fp;
902 Cell t; {
903     outputStream = fp;
904     putSigType(t);
905 }
906
907 Void printContext(fp,qs)                /* print context on spec. stream   */
908 FILE *fp;
909 List qs; {
910     outputStream = fp;
911     putContext(qs,NIL,0);
912 }
913
914 Void printPred(fp,pi)                   /* print predicate pi on stream    */
915 FILE *fp;
916 Cell pi; {
917     outputStream = fp;
918     putPred(pi,0);
919 }
920
921 Void printKind(fp,k)                    /* print kind k on stream          */
922 FILE *fp;
923 Kind k; {
924     outputStream = fp;
925     putKind(k);
926 }
927
928 Void printKinds(fp,ks)                  /* print list of kinds on stream   */
929 FILE  *fp;
930 Kinds ks; {
931     outputStream = fp;
932     putKinds(ks);
933 }
934
935 /*-------------------------------------------------------------------------*/