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