[project @ 1999-10-20 02:15:56 by andy]
[ghc-hetmet.git] / ghc / interpreter / hugs.c
1
2 /* --------------------------------------------------------------------------
3  * Command interpreter
4  *
5  * The Hugs 98 system is Copyright (c) Mark P Jones, Alastair Reid, the
6  * Yale Haskell Group, and the Oregon Graduate Institute of Science and
7  * Technology, 1994-1999, All rights reserved.  It is distributed as
8  * free software under the license in the file "License", which is
9  * included in the distribution.
10  *
11  * $RCSfile: hugs.c,v $
12  * $Revision: 1.15 $
13  * $Date: 1999/10/20 02:15:59 $
14  * ------------------------------------------------------------------------*/
15
16 #include <setjmp.h>
17 #include <ctype.h>
18 #include <stdio.h>
19
20 #include "prelude.h"
21 #include "storage.h"
22 #include "command.h"
23 #include "backend.h"
24 #include "connect.h"
25 #include "errors.h"
26 #include "version.h"
27 #include "link.h"
28
29 #include "Rts.h"
30 #include "RtsAPI.h"
31 #include "Schedule.h"
32
33
34 Bool haskell98 = TRUE;                  /* TRUE => Haskell 98 compatibility*/
35
36 #if EXPLAIN_INSTANCE_RESOLUTION
37 Bool showInstRes = FALSE;
38 #endif
39 #if MULTI_INST
40 Bool multiInstRes = FALSE;
41 #endif
42
43 /* --------------------------------------------------------------------------
44  * Local function prototypes:
45  * ------------------------------------------------------------------------*/
46
47 static Void   local initialize        Args((Int,String []));
48 static Void   local promptForInput    Args((String));
49 static Void   local interpreter       Args((Int,String []));
50 static Void   local menu              Args((Void));
51 static Void   local guidance          Args((Void));
52 static Void   local forHelp           Args((Void));
53 static Void   local set               Args((Void));
54 static Void   local changeDir         Args((Void));
55 static Void   local load              Args((Void));
56 static Void   local project           Args((Void));
57 static Void   local readScripts       Args((Int));
58 static Void   local whatScripts       Args((Void));
59 static Void   local editor            Args((Void));
60 static Void   local find              Args((Void));
61 static Bool   local startEdit         Args((Int,String));
62 static Void   local runEditor         Args((Void));
63 static Void   local setModule         Args((Void));
64 static Module local findEvalModule    Args((Void));
65 static Void   local evaluator         Args((Void));
66 static Void   local stopAnyPrinting   Args((Void));
67 static Void   local showtype          Args((Void));
68 static String local objToStr          Args((Module, Cell));
69 static Void   local info              Args((Void));
70 static Void   local printSyntax       Args((Name));
71 static Void   local showInst          Args((Inst));
72 static Void   local describe          Args((Text));
73 static Void   local listNames         Args((Void));
74
75 static Void   local toggleSet         Args((Char,Bool));
76 static Void   local togglesIn         Args((Bool));
77 static Void   local optionInfo        Args((Void));
78 #if USE_REGISTRY || HUGS_FOR_WINDOWS
79 static String local optionsToStr      Args((Void));
80 #endif
81 static Void   local readOptions       Args((String));
82 static Bool   local processOption     Args((String));
83 static Void   local setHeapSize       Args((String));
84 static Int    local argToInt          Args((String));
85
86 static Void   local loadProject       Args((String));
87 static Void   local clearProject      Args((Void));
88 static Bool   local addScript         Args((Int));
89 static Void   local forgetScriptsFrom Args((Script));
90 static Void   local setLastEdit       Args((String,Int));
91 static Void   local failed            Args((Void));
92 static String local strCopy           Args((String));
93 static Void   local browseit          Args((Module,String));
94 static Void   local browse            Args((Void));
95
96 /* --------------------------------------------------------------------------
97  * Machine dependent code for Hugs interpreter:
98  * ------------------------------------------------------------------------*/
99
100 #include "machdep.c"
101 #ifdef WANT_TIMER
102 #include "timer.c"
103 #endif
104
105 /* --------------------------------------------------------------------------
106  * Local data areas:
107  * ------------------------------------------------------------------------*/
108
109 static Bool   printing     = FALSE;     /* TRUE => currently printing value*/
110 static Bool   showStats    = FALSE;     /* TRUE => print stats after eval  */
111 static Bool   listScripts  = TRUE;      /* TRUE => list scripts after loading*/
112 static Bool   addType      = FALSE;     /* TRUE => print type with value   */
113 static Bool   useDots      = RISCOS;    /* TRUE => use dots in progress    */
114 static Bool   quiet        = FALSE;     /* TRUE => don't show progress     */
115 static Bool   lastWasObject = FALSE;
116        Bool   preludeLoaded = FALSE;
117        Bool   optimise      = FALSE;
118
119 typedef 
120    struct { 
121       String modName;                   /* Module name                     */
122       Bool   details;             /* FALSE => remaining fields are invalid */
123       String path;                      /* Path to module                  */
124       String srcExt;                    /* ".hs" or ".lhs" if fromSource   */
125       Time   lastChange;                /* Time of last change to script   */
126       Bool   fromSource;                /* FALSE => load object code       */
127       Bool   postponed;                 /* Indicates postponed load        */
128       Bool   objLoaded;
129       Long   size;
130       Long   oSize;
131    }
132    ScriptInfo;
133
134 static Void   local makeStackEntry    Args((ScriptInfo*,String));
135 static Void   local addStackEntry     Args((String));
136
137 static ScriptInfo scriptInfo[NUM_SCRIPTS];
138
139 static Int    numScripts;               /* Number of scripts loaded        */
140 static Int    nextNumScripts;
141 static Int    namesUpto;                /* Number of script names set      */
142 static Bool   needsImports;             /* set to TRUE if imports required */
143        String scriptFile;               /* Name of current script (if any) */
144
145
146
147 static Text   evalModule  = 0;          /* Name of module we eval exprs in */
148 static String currProject = 0;          /* Name of current project file    */
149 static Bool   projectLoaded = FALSE;    /* TRUE => project file loaded     */
150
151 static Bool   autoMain   = FALSE;
152 static String lastEdit   = 0;           /* Name of script to edit (if any) */
153 static Int    lastEdLine = 0;           /* Editor line number (if possible)*/
154 static String prompt     = 0;           /* Prompt string                   */
155 static Int    hpSize     = DEFAULTHEAP; /* Desired heap size               */
156        String hugsEdit   = 0;           /* String for editor command       */
157        String hugsPath   = 0;           /* String for file search path     */
158
159 #if REDIRECT_OUTPUT
160 static Bool disableOutput = FALSE;      /* redirect output to buffer?      */
161 #endif
162
163 String bool2str ( Bool b )
164 {
165    if (b) return "Yes"; else return "No ";
166 }
167
168 void ppSmStack ( String who )
169 {
170    int i, j;
171 return;
172    fflush(stdout);fflush(stderr);
173    printf ( "\n" );
174    printf ( "ppSmStack %s:  numScripts = %d   namesUpto = %d  needsImports = %s\n",
175             who, numScripts, namesUpto, bool2str(needsImports) );
176    assert (namesUpto >= numScripts);
177    printf ( "     Det FrS Pst ObL           Module Ext   Size ModTime  Path\n" );
178    for (i = namesUpto-1; i >= 0; i--) {
179       printf ( "%c%2d: %3s %3s %3s %3s %16s %-4s %5ld %8lx %s\n",
180                (i==numScripts ? '*' : ' '),
181                i, bool2str(scriptInfo[i].details), 
182                   bool2str(scriptInfo[i].fromSource),
183                   bool2str(scriptInfo[i].postponed), 
184                   bool2str(scriptInfo[i].objLoaded),
185                   scriptInfo[i].modName, 
186                   scriptInfo[i].fromSource ? scriptInfo[i].srcExt : "",
187                   scriptInfo[i].size, 
188                   scriptInfo[i].lastChange,
189                   scriptInfo[i].path
190              );
191    }
192    //   printf ( "\n" );
193    fflush(stdout);fflush(stderr);
194 ppScripts();
195 ppModules();
196    printf ( "\n" );
197 }
198
199 /* --------------------------------------------------------------------------
200  * Hugs entry point:
201  * ------------------------------------------------------------------------*/
202
203 #ifndef NO_MAIN /* we omit main when building the "Hugs server" */
204  
205 Main main Args((Int, String []));       /* now every func has a prototype  */
206
207 Main main(argc,argv)
208 int  argc;
209 char *argv[]; {
210 #ifdef HAVE_CONSOLE_H /* Macintosh port */
211     _ftype = 'TEXT';
212     _fcreator = 'R*ch';       /*  // 'KAHL';      //'*TEX';       //'ttxt'; */
213
214     console_options.top = 50;
215     console_options.left = 20;
216
217     console_options.nrows = 32;
218     console_options.ncols = 80;
219
220     console_options.pause_atexit = 1;
221     console_options.title = "\pHugs";
222
223     console_options.procID = 5;
224     argc = ccommand(&argv);
225 #endif
226
227     CStackBase = &argc;                 /* Save stack base for use in gc   */
228
229     /* Try and figure out an absolute path to the executable, so
230        we can make a reasonable guess about where the default
231        libraries (Prelude etc) are.
232     */
233     setDefaultLibDir ( argv[0] );
234
235     /* If first arg is +Q or -Q, be entirely silent, and automatically run
236        main after loading scripts.  Useful for running the nofib suite.    */
237     if (argc > 1 && (strcmp(argv[1],"+Q") == 0 || strcmp(argv[1],"-Q")==0)) {
238        autoMain = TRUE;
239        hugsEnableOutput(0);
240     }
241
242     Printf("__   __ __  __  ____   ___      _________________________________________\n");
243     Printf("||   || ||  || ||  || ||__      Hugs 98: Based on the Haskell 98 standard\n");
244     Printf("||___|| ||__|| ||__||  __||     Copyright (c) 1994-1999\n");
245     Printf("||---||         ___||           World Wide Web: http://haskell.org/hugs\n");
246     Printf("||   ||                         Report bugs to: hugs-bugs@haskell.org\n");
247     Printf("||   || Version: %s _________________________________________\n\n",HUGS_VERSION);
248
249 #if SYMANTEC_C
250     Printf("   Ported to Macintosh by Hans Aberg, compiled " __DATE__ ".\n\n");
251 #endif
252     FlushStdout();
253     interpreter(argc,argv);
254     Printf("[Leaving Hugs]\n");
255     everybody(EXIT);
256     shutdownHaskell();
257     FlushStdout();
258     fflush(stderr);
259     exit(0);
260     MainDone();
261 }
262
263 #endif
264
265 /* --------------------------------------------------------------------------
266  * Initialization, interpret command line args and read prelude:
267  * ------------------------------------------------------------------------*/
268
269 static Void local initialize(argc,argv)/* Interpreter initialization       */
270 Int    argc;
271 String argv[]; {
272     Script i;
273     String proj        = 0;
274     char argv_0_orig[1000];
275
276     setLastEdit((String)0,0);
277     lastEdit      = 0;
278     scriptFile    = 0;
279     numScripts    = 0;
280     namesUpto     = 1;
281
282 #if HUGS_FOR_WINDOWS
283     hugsEdit      = strCopy(fromEnv("EDITOR","c:\\windows\\notepad.exe"));
284 #elif SYMANTEC_C
285     hugsEdit      = "";
286 #else
287     hugsEdit      = strCopy(fromEnv("EDITOR",NULL));
288 #endif
289     hugsPath      = strCopy(HUGSPATH);
290     readOptions("-p\"%s> \" -r$$");
291 #if USE_REGISTRY
292     projectPath   = strCopy(readRegChildStrings(HKEY_LOCAL_MACHINE,ProjectRoot,
293                                                 "HUGSPATH", PATHSEP, ""));
294     readOptions(readRegString(HKEY_LOCAL_MACHINE,HugsRoot,"Options",""));
295     readOptions(readRegString(HKEY_CURRENT_USER, HugsRoot,"Options",""));
296 #endif /* USE_REGISTRY */
297     readOptions(fromEnv("STGHUGSFLAGS",""));
298
299    strncpy(argv_0_orig,argv[0],1000);   /* startupHaskell mangles argv[0] */
300    startupHaskell (argc,argv);
301    argc = prog_argc; argv = prog_argv;
302
303     namesUpto = numScripts = 0;
304     addStackEntry("Prelude");
305
306    for (i=1; i<argc; ++i) {            /* process command line arguments  */
307         if (strcmp(argv[i], "--")==0) break;
308         if (strcmp(argv[i],"+")==0 && i+1<argc) {
309             if (proj) {
310                 ERRMSG(0) "Multiple project filenames on command line"
311                 EEND;
312             } else {
313                 proj = argv[++i];
314             }
315         } else if (argv[i] && argv[i][0]/* workaround for /bin/sh silliness*/
316                  && !processOption(argv[i])) {
317             addStackEntry(argv[i]);
318         }
319     }
320
321 #ifdef DEBUG
322     DEBUG_LoadSymbols(argv_0_orig);
323 #endif
324
325
326
327 #if 0
328     if (!scriptName[0]) {
329         Printf("Prelude not found on current path: \"%s\"\n",
330                hugsPath ? hugsPath : "");
331         fatal("Unable to load prelude");
332     }
333 #endif
334
335     if (haskell98) {
336         Printf("Haskell 98 mode: Restart with command line option -98 to enable extensions\n\n");
337     } else {
338         Printf("Hugs mode: Restart with command line option +98 for Haskell 98 mode\n\n");
339     }
340  
341     everybody(INSTALL);
342     evalModule = findText("");      /* evaluate wrt last module by default */
343     if (proj) {
344         if (namesUpto>1) {
345             fprintf(stderr,
346                     "\nUsing project file, ignoring additional filenames\n");
347         }
348         loadProject(strCopy(proj));
349     }
350     readScripts(0);
351 }
352
353 /* --------------------------------------------------------------------------
354  * Command line options:
355  * ------------------------------------------------------------------------*/
356
357 struct options {                        /* command line option toggles     */
358     char   c;                           /* table defined in main app.      */
359     int    h98;
360     String description;
361     Bool   *flag;
362 };
363 extern struct options toggle[];
364
365 static Void local toggleSet(c,state)    /* Set command line toggle         */
366 Char c;
367 Bool state; {
368     Int i;
369     for (i=0; toggle[i].c; ++i)
370         if (toggle[i].c == c) {
371             *toggle[i].flag = state;
372             return;
373         }
374     ERRMSG(0) "Unknown toggle `%c'", c
375     EEND;
376 }
377
378 static Void local togglesIn(state)      /* Print current list of toggles in*/
379 Bool state; {                           /* given state                     */
380     Int count = 0;
381     Int i;
382     for (i=0; toggle[i].c; ++i)
383         if (*toggle[i].flag == state && (!haskell98 || toggle[i].h98)) {
384             if (count==0)
385                 Putchar((char)(state ? '+' : '-'));
386             Putchar(toggle[i].c);
387             count++;
388         }
389     if (count>0)
390         Putchar(' ');
391 }
392
393 static Void local optionInfo() {        /* Print information about command */
394     static String fmts = "%-5s%s\n";    /* line settings                   */
395     static String fmtc = "%-5c%s\n";
396     Int    i;
397
398     Printf("TOGGLES: groups begin with +/- to turn options on/off resp.\n");
399     for (i=0; toggle[i].c; ++i) {
400         if (!haskell98 || toggle[i].h98) {
401             Printf(fmtc,toggle[i].c,toggle[i].description);
402         }
403     }
404
405     Printf("\nOTHER OPTIONS: (leading + or - makes no difference)\n");
406     Printf(fmts,"hnum","Set heap size (cannot be changed within Hugs)");
407     Printf(fmts,"pstr","Set prompt string to str");
408     Printf(fmts,"rstr","Set repeat last expression string to str");
409     Printf(fmts,"Pstr","Set search path for modules to str");
410     Printf(fmts,"Estr","Use editor setting given by str");
411     Printf(fmts,"cnum","Set constraint cutoff limit");
412 #if USE_PREPROCESSOR  && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
413     Printf(fmts,"Fstr","Set preprocessor filter to str");
414 #endif
415
416     Printf("\nCurrent settings: ");
417     togglesIn(TRUE);
418     togglesIn(FALSE);
419     Printf("-h%d",heapSize);
420     Printf(" -p");
421     printString(prompt);
422     Printf(" -r");
423     printString(repeatStr);
424     Printf(" -c%d",cutoff);
425     Printf("\nSearch path     : -P");
426     printString(hugsPath);
427 #if 0
428 ToDo
429     if (projectPath!=NULL) {
430         Printf("\nProject Path    : %s",projectPath);
431     }
432 #endif
433     Printf("\nEditor setting  : -E");
434     printString(hugsEdit);
435 #if USE_PREPROCESSOR  && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
436     Printf("\nPreprocessor    : -F");
437     printString(preprocessor);
438 #endif
439     Printf("\nCompatibility   : %s", haskell98 ? "Haskell 98 (+98)"
440                                                : "Hugs Extensions (-98)");
441     Putchar('\n');
442 }
443
444 #if USE_REGISTRY || HUGS_FOR_WINDOWS
445 #define PUTC(c)                         \
446     *next++=(c)
447
448 #define PUTS(s)                         \
449     strcpy(next,s);                     \
450     next+=strlen(next)
451
452 #define PUTInt(optc,i)                  \
453     sprintf(next,"-%c%d",optc,i);       \
454     next+=strlen(next)
455
456 #define PUTStr(c,s)                     \
457     next=PUTStr_aux(next,c,s)
458
459 static String local PUTStr_aux Args((String,Char, String));
460
461 static String local PUTStr_aux(next,c,s)
462 String next;
463 Char   c;
464 String s; {
465     if (s) { 
466         String t = 0;
467         sprintf(next,"-%c\"",c); 
468         next+=strlen(next);      
469         for(t=s; *t; ++t) {
470             PUTS(unlexChar(*t,'"'));
471         }
472         next+=strlen(next);      
473         PUTS("\" ");
474     }
475     return next;
476 }
477
478 static String local optionsToStr() {          /* convert options to string */
479     static char buffer[2000];
480     String next = buffer;
481
482     Int i;
483     for (i=0; toggle[i].c; ++i) {
484         PUTC(*toggle[i].flag ? '+' : '-');
485         PUTC(toggle[i].c);
486         PUTC(' ');
487     }
488     PUTS(haskell98 ? "+98 " : "-98 ");
489     PUTInt('h',hpSize);  PUTC(' ');
490     PUTStr('p',prompt);
491     PUTStr('r',repeatStr);
492     PUTStr('P',hugsPath);
493     PUTStr('E',hugsEdit);
494     PUTInt('c',cutoff);  PUTC(' ');
495 #if USE_PREPROCESSOR  && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
496     PUTStr('F',preprocessor);
497 #endif
498     PUTC('\0');
499     return buffer;
500 }
501 #endif /* USE_REGISTRY */
502
503 #undef PUTC
504 #undef PUTS
505 #undef PUTInt
506 #undef PUTStr
507
508 static Void local readOptions(options)         /* read options from string */
509 String options; {
510     String s;
511     if (options) {
512         stringInput(options);
513         while ((s=readFilename())!=0) {
514             if (*s && !processOption(s)) {
515                 ERRMSG(0) "Option string must begin with `+' or `-'"
516                 EEND;
517             }
518         }
519     }
520 }
521
522 static Bool local processOption(s)      /* process string s for options,   */
523 String s; {                             /* return FALSE if none found.     */
524     Bool state;
525
526     if (s[0]=='-')
527         state = FALSE;
528     else if (s[0]=='+')
529         state = TRUE;
530     else
531         return FALSE;
532
533     while (*++s)
534         switch (*s) {
535             case 'Q' : break;                           /* already handled */
536
537             case 'p' : if (s[1]) {
538                            if (prompt) free(prompt);
539                            prompt = strCopy(s+1);
540                        }
541                        return TRUE;
542
543             case 'r' : if (s[1]) {
544                            if (repeatStr) free(repeatStr);
545                            repeatStr = strCopy(s+1);
546                        }
547                        return TRUE;
548
549             case 'P' : {
550                            String p = substPath(s+1,hugsPath ? hugsPath : "");
551                            if (hugsPath) free(hugsPath);
552                            hugsPath = p;
553                            return TRUE;
554                        }
555
556             case 'E' : if (hugsEdit) free(hugsEdit);
557                        hugsEdit = strCopy(s+1);
558                        return TRUE;
559
560 #if USE_PREPROCESSOR  && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
561             case 'F' : if (preprocessor) free(preprocessor);
562                        preprocessor = strCopy(s+1);
563                        return TRUE;
564 #endif
565
566             case 'h' : setHeapSize(s+1);
567                        return TRUE;
568
569             case 'D' : /* hack */
570                 {
571                     extern void setRtsFlags( int x );
572                     setRtsFlags(argToInt(s+1));
573                     return TRUE;
574                 }
575
576             default  : if (strcmp("98",s)==0) {
577                            if (heapBuilt() && ((state && !haskell98) ||
578                                                (!state && haskell98))) {
579                                FPrintf(stderr,"Haskell 98 compatibility cannot be changed while the interpreter is running\n");
580                            } else {
581                                haskell98 = state;
582                            }
583                            return TRUE;
584                        } else {
585                            toggleSet(*s,state);
586                        }
587                        break;
588         }
589     return TRUE;
590 }
591
592 static Void local setHeapSize(s) 
593 String s; {
594     if (s) {
595         hpSize = argToInt(s);
596         if (hpSize < MINIMUMHEAP)
597             hpSize = MINIMUMHEAP;
598         else if (MAXIMUMHEAP && hpSize > MAXIMUMHEAP)
599             hpSize = MAXIMUMHEAP;
600         if (heapBuilt() && hpSize != heapSize) {
601             /* ToDo: should this use a message box in winhugs? */
602 #if USE_REGISTRY
603             FPrintf(stderr,"Change to heap size will not take effect until you rerun Hugs\n");
604 #else
605             FPrintf(stderr,"Cannot change heap size\n");
606 #endif
607         } else {
608             heapSize = hpSize;
609         }
610     }
611 }
612
613 static Int local argToInt(s)            /* read integer from argument str  */
614 String s; {
615     Int    n = 0;
616     String t = s;
617
618     if (*s=='\0' || !isascii((int)(*s)) || !isdigit((int)(*s))) {
619         ERRMSG(0) "Missing integer in option setting \"%s\"", t
620         EEND;
621     }
622
623     do {
624         Int d = (*s++) - '0';
625         if (n > ((MAXPOSINT - d)/10)) {
626             ERRMSG(0) "Option setting \"%s\" is too large", t
627             EEND;
628         }
629         n     = 10*n + d;
630     } while (isascii((int)(*s)) && isdigit((int)(*s)));
631
632     if (*s=='K' || *s=='k') {
633         if (n > (MAXPOSINT/1000)) {
634             ERRMSG(0) "Option setting \"%s\" is too large", t
635             EEND;
636         }
637         n *= 1000;
638         s++;
639     }
640
641 #if MAXPOSINT > 1000000                 /* waste of time on 16 bit systems */
642     if (*s=='M' || *s=='m') {
643         if (n > (MAXPOSINT/1000000)) {
644             ERRMSG(0) "Option setting \"%s\" is too large", t
645             EEND;
646         }
647         n *= 1000000;
648         s++;
649     }
650 #endif
651
652 #if MAXPOSINT > 1000000000
653     if (*s=='G' || *s=='g') {
654         if (n > (MAXPOSINT/1000000000)) {
655             ERRMSG(0) "Option setting \"%s\" is too large", t
656             EEND;
657         }
658         n *= 1000000000;
659         s++;
660     }
661 #endif
662
663     if (*s!='\0') {
664         ERRMSG(0) "Unwanted characters after option setting \"%s\"", t
665         EEND;
666     }
667
668     return n;
669 }
670
671 /* --------------------------------------------------------------------------
672  * Print Menu of list of commands:
673  * ------------------------------------------------------------------------*/
674
675 static struct cmd cmds[] = {
676  {":?",      HELP},   {":cd",   CHGDIR},  {":also",    ALSO},
677  {":type",   TYPEOF}, {":!",    SYSTEM},  {":load",    LOAD},
678  {":reload", RELOAD}, {":gc",   COLLECT}, {":edit",    EDIT},
679  {":quit",   QUIT},   {":set",  SET},     {":find",    FIND},
680  {":names",  NAMES},  {":info", INFO},    {":project", PROJECT},
681  {":dump",   DUMP},   {":ztats", STATS},
682  {":module",SETMODULE}, 
683  {":browse", BROWSE},
684 #if EXPLAIN_INSTANCE_RESOLUTION
685  {":xplain", XPLAIN},
686 #endif
687  {":version", PNTVER},
688  {"",      EVAL},
689  {0,0}
690 };
691
692 static Void local menu() {
693     Printf("LIST OF COMMANDS:  Any command may be abbreviated to :c where\n");
694     Printf("c is the first character in the full name.\n\n");
695     Printf(":load <filenames>   load modules from specified files\n");
696     Printf(":load               clear all files except prelude\n");
697     Printf(":also <filenames>   read additional modules\n");
698     Printf(":reload             repeat last load command\n");
699     Printf(":project <filename> use project file\n");
700     Printf(":edit <filename>    edit file\n");
701     Printf(":edit               edit last module\n");
702     Printf(":module <module>    set module for evaluating expressions\n");
703     Printf("<expr>              evaluate expression\n");
704     Printf(":type <expr>        print type of expression\n");
705     Printf(":?                  display this list of commands\n");
706     Printf(":set <options>      set command line options\n");
707     Printf(":set                help on command line options\n");
708     Printf(":names [pat]        list names currently in scope\n");
709     Printf(":info <names>       describe named objects\n");
710     Printf(":browse <modules>   browse names defined in <modules>\n");
711 #if EXPLAIN_INSTANCE_RESOLUTION
712     Printf(":xplain <context>   explain instance resolution for <context>\n");
713 #endif
714     Printf(":find <name>        edit module containing definition of name\n");
715     Printf(":!command           shell escape\n");
716     Printf(":cd dir             change directory\n");
717     Printf(":gc                 force garbage collection\n");
718     Printf(":version            print Hugs version\n");
719     Printf(":dump <name>        print STG code for named fn\n");
720 #ifdef CRUDE_PROFILING
721     Printf(":ztats <name>       print reduction stats\n");
722 #endif
723     Printf(":quit               exit Hugs interpreter\n");
724 }
725
726 static Void local guidance() {
727     Printf("Command not recognised.  ");
728     forHelp();
729 }
730
731 static Void local forHelp() {
732     Printf("Type :? for help\n");
733 }
734
735 /* --------------------------------------------------------------------------
736  * Setting of command line options:
737  * ------------------------------------------------------------------------*/
738
739 struct options toggle[] = {             /* List of command line toggles    */
740     {'s', 1, "Print no. reductions/cells after eval", &showStats},
741     {'t', 1, "Print type after evaluation",           &addType},
742     {'g', 1, "Print no. cells recovered after gc",    &gcMessages},
743     {'l', 1, "Literate modules as default",           &literateScripts},
744     {'e', 1, "Warn about errors in literate modules", &literateErrors},
745     {'.', 1, "Print dots to show progress",           &useDots},
746     {'q', 1, "Print nothing to show progress",        &quiet},
747     {'w', 1, "Always show which modules are loaded",  &listScripts},
748     {'k', 1, "Show kind errors in full",              &kindExpert},
749     {'o', 0, "Allow overlapping instances",           &allowOverlap},
750     {'O', 1, "Optimise (improve?) generated code",    &optimise},
751
752
753 #if DEBUG_CODE
754     {'D', 1, "Debug: show generated code",            &debugCode},
755 #endif
756 #if EXPLAIN_INSTANCE_RESOLUTION
757     {'x', 1, "Explain instance resolution",           &showInstRes},
758 #endif
759 #if MULTI_INST
760     {'m', 0, "Use multi instance resolution",         &multiInstRes},
761 #endif
762 #if DEBUG_CODE
763     {'D', 1, "Debug: show generated G code",          &debugCode},
764 #endif
765 #if DEBUG_SHOWSC
766     {'S', 1, "Debug: show generated SC code",         &debugSC},
767 #endif
768 #if 0
769     {'f', 1, "Terminate evaluation on first error",   &failOnError},
770     {'u', 1, "Use \"show\" to display results",       &useShow},
771     {'i', 1, "Chase imports while loading modules",   &chaseImports}, 
772 #endif
773     {0,   0, 0,                                       0}
774 };
775
776 static Void local set() {               /* change command line options from*/
777     String s;                           /* Hugs command line               */
778
779     if ((s=readFilename())!=0) {
780         do {
781             if (!processOption(s)) {
782                 ERRMSG(0) "Option string must begin with `+' or `-'"
783                 EEND;
784             }
785         } while ((s=readFilename())!=0);
786 #if USE_REGISTRY
787         writeRegString("Options", optionsToStr());
788 #endif
789     }
790     else
791         optionInfo();
792 }
793
794 /* --------------------------------------------------------------------------
795  * Change directory command:
796  * ------------------------------------------------------------------------*/
797
798 static Void local changeDir() {         /* change directory                */
799     String s = readFilename();
800     if (s && chdir(s)) {
801         ERRMSG(0) "Unable to change to directory \"%s\"", s
802         EEND;
803     }
804 }
805
806 /* --------------------------------------------------------------------------
807  * Loading project and script files:
808  * ------------------------------------------------------------------------*/
809
810 static Void local loadProject(s)        /* Load project file               */
811 String s; {
812     clearProject();
813     currProject = s;
814     projInput(currProject);
815     scriptFile = currProject;
816     forgetScriptsFrom(1);
817     while ((s=readFilename())!=0)
818         addStackEntry(s);
819     if (namesUpto<=1) {
820         ERRMSG(0) "Empty project file"
821         EEND;
822     }
823     scriptFile    = 0;
824     projectLoaded = TRUE;
825 }
826
827 static Void local clearProject() {      /* clear name for current project  */
828     if (currProject)
829         free(currProject);
830     currProject   = 0;
831     projectLoaded = FALSE;
832 #if HUGS_FOR_WINDOWS
833     setLastEdit((String)0,0);
834 #endif
835 }
836
837
838
839 static Void local makeStackEntry ( ScriptInfo* ent, String iname )
840 {
841    Bool   ok, fromObj;
842    Bool   sAvail, iAvail, oAvail;
843    Time   sTime,  iTime,  oTime;
844    Long   sSize,  iSize,  oSize;
845    String path,   sExt;
846
847    ok = findFilesForModule (
848            iname,
849            &path,
850            &sExt,
851            &sAvail, &sTime, &sSize,
852            &iAvail, &iTime, &iSize,
853            &oAvail, &oTime, &oSize
854         );
855    if (!ok) {
856       ERRMSG(0) 
857         /* "Can't file source or object+interface for module \"%s\"", */
858          "Can't file source for module \"%s\"",
859          iname
860       EEND;
861    }
862    /* findFilesForModule should enforce this */
863    if (!(sAvail || (oAvail && iAvail))) 
864       internal("chase");
865    /* Load objects in preference to sources if both are available */
866    /* 11 Oct 99: disable object loading in the interim.
867       Will probably only reinstate when HEP becomes available.
868    fromObj = sAvail
869                 ? (oAvail && iAvail && timeEarlier(sTime,oTime))
870                 : TRUE;
871    */
872    fromObj = FALSE;
873
874    /* ToDo: namesUpto overflow */
875    ent->modName     = strCopy(iname);
876    ent->details     = TRUE;
877    ent->path        = path;
878    ent->fromSource  = !fromObj;
879    ent->srcExt      = sExt;
880    ent->postponed   = FALSE;
881    ent->lastChange  = sTime; /* ToDo: is this right? */
882    ent->size        = fromObj ? iSize : sSize;
883    ent->oSize       = fromObj ? oSize : 0;
884    ent->objLoaded   = FALSE;
885 }
886
887
888
889 static Void nukeEnding( String s )
890 {
891     Int l = strlen(s);
892     if (l > 2 && strncmp(s+l-2,".o"  ,3)==0) s[l-2] = 0; else
893     if (l > 3 && strncmp(s+l-3,".hi" ,3)==0) s[l-3] = 0; else
894     if (l > 3 && strncmp(s+l-3,".hs" ,3)==0) s[l-3] = 0; else
895     if (l > 4 && strncmp(s+l-4,".lhs",4)==0) s[l-4] = 0; else
896     if (l > 4 && strncmp(s+l-4,".dll",4)==0) s[l-4] = 0; else
897     if (l > 4 && strncmp(s+l-4,".DLL",4)==0) s[l-4] = 0;
898 }
899
900 static Void local addStackEntry(s)     /* Add script to list of scripts    */
901 String s; {                            /* to be read in ...                */
902     String s2;
903     Bool   found;
904     Int    i;
905
906     if (namesUpto>=NUM_SCRIPTS) {
907         ERRMSG(0) "Too many module files (maximum of %d allowed)",
908                   NUM_SCRIPTS
909         EEND;
910     }
911
912     s = strCopy(s);
913     nukeEnding(s);
914     for (s2 = s; *s2; s2++)
915        if (*s2 == SLASH && *(s2+1)) s = s2+1;
916
917     found = FALSE;
918     for (i = 0; i < namesUpto; i++)
919        if (strcmp(scriptInfo[i].modName,s)==0)
920           found = TRUE;
921
922     if (!found) {
923        makeStackEntry ( &scriptInfo[namesUpto], strCopy(s) );
924        namesUpto++;
925     }
926     free(s);
927 }
928
929 /* Return TRUE if no imports were needed; FALSE otherwise. */
930 static Bool local addScript(stacknum)   /* read single file                */
931 Int stacknum; {
932    static char name[FILENAME_MAX+1];
933    Int len = scriptInfo[stacknum].size;
934
935 #if HUGS_FOR_WINDOWS                    /* Set clock cursor while loading  */
936     allowBreak();
937     SetCursor(LoadCursor(NULL, IDC_WAIT));
938 #endif
939
940     //   setLastEdit(name,0);
941
942    nameObj[0] = 0;
943    strcpy(name, scriptInfo[stacknum].path);
944    strcat(name, scriptInfo[stacknum].modName);
945    if (scriptInfo[stacknum].fromSource)
946       strcat(name, scriptInfo[stacknum].srcExt); else
947       strcat(name, ".hi");
948
949    scriptFile = name;
950
951    if (scriptInfo[stacknum].fromSource) {
952       if (lastWasObject) finishInterfaces();
953       lastWasObject = FALSE;
954       Printf("Reading script \"%s\":\n",name);
955       needsImports = FALSE;
956       parseScript(name,len);
957       if (needsImports) return FALSE;
958       checkDefns();
959       typeCheckDefns();
960       compileDefns();
961    } else {
962       Printf("Reading  iface \"%s\":\n", name);
963       scriptFile = name;
964       needsImports = FALSE;
965
966       // set nameObj for the benefit of openGHCIface
967       strcpy(nameObj, scriptInfo[stacknum].path);
968       strcat(nameObj, scriptInfo[stacknum].modName);
969       strcat(nameObj, DLL_ENDING);
970       sizeObj = scriptInfo[stacknum].oSize;
971
972       loadInterface(name,len);
973       scriptFile = 0;
974       lastWasObject = TRUE;
975       if (needsImports) return FALSE;
976    }
977  
978    scriptFile = 0;
979    preludeLoaded = TRUE;
980    return TRUE;
981 }
982
983
984 Bool chase(imps)                        /* Process list of import requests */
985 List imps; {
986     Int    dstPosn;
987     ScriptInfo tmp;
988     Int    origPos  = numScripts;       /* keep track of original position */
989     String origName = scriptInfo[origPos].modName;
990     for (; nonNull(imps); imps=tl(imps)) {
991         String iname = textToStr(textOf(hd(imps)));
992         Int    i     = 0;
993         for (; i<namesUpto; i++)
994             if (strcmp(scriptInfo[i].modName,iname)==0)
995                 break;
996         //fprintf(stderr, "import name = %s   num = %d\n", iname, i );
997
998         if (i<namesUpto) {
999            /* We should have filled in the details of each module
1000               the first time we hear about it.
1001            */
1002            assert(scriptInfo[i].details);
1003         }
1004
1005         if (i>=origPos) {               /* Neither loaded or queued        */
1006             String theName;
1007             Time   theTime;
1008             Bool   thePost;
1009             Bool   theFS;
1010
1011             needsImports = TRUE;
1012             if (scriptInfo[origPos].fromSource)
1013                scriptInfo[origPos].postponed  = TRUE;
1014
1015             if (i==namesUpto) {         /* Name not found (i==namesUpto)   */
1016                  /* Find out where it lives, whether source or object, etc */
1017                makeStackEntry ( &scriptInfo[i], iname );
1018                namesUpto++;
1019             }
1020             else 
1021             if (scriptInfo[i].postponed && scriptInfo[i].fromSource) {
1022                                         /* Check for recursive dependency  */
1023                 ERRMSG(0)
1024                   "Recursive import dependency between \"%s\" and \"%s\"",
1025                   scriptInfo[origPos].modName, iname
1026                 EEND;
1027             }
1028             /* Move stack entry i to somewhere below origPos.  If i denotes 
1029              * an object, destination is immediately below origPos.  
1030              * Otherwise, it's underneath the queue of objects below origPos.
1031              */
1032             dstPosn = origPos-1;
1033             if (scriptInfo[i].fromSource)
1034                while (!scriptInfo[dstPosn].fromSource && dstPosn > 0)
1035                   dstPosn--;
1036
1037             dstPosn++;
1038             tmp = scriptInfo[i];
1039             for (; i > dstPosn; i--) scriptInfo[i] = scriptInfo[i-1];
1040             scriptInfo[dstPosn] = tmp;
1041             if (dstPosn < nextNumScripts) nextNumScripts = dstPosn;
1042             origPos++;
1043         }
1044     }
1045     return needsImports;
1046 }
1047
1048 static Void local forgetScriptsFrom(scno)/* remove scripts from system     */
1049 Script scno; {
1050     Script i;
1051 #if 0
1052     for (i=scno; i<namesUpto; ++i)
1053         if (scriptName[i])
1054             free(scriptName[i]);
1055 #endif
1056     dropScriptsFrom(scno-1);
1057     namesUpto = scno;
1058     if (numScripts>namesUpto)
1059         numScripts = scno;
1060 }
1061
1062 /* --------------------------------------------------------------------------
1063  * Commands for loading and removing script files:
1064  * ------------------------------------------------------------------------*/
1065
1066 static Void local load() {           /* read filenames from command line   */
1067     String s;                        /* and add to list of scripts waiting */
1068                                      /* to be read                         */
1069     while ((s=readFilename())!=0)
1070         addStackEntry(s);
1071     readScripts(1);
1072 }
1073
1074 static Void local project() {          /* read list of script names from   */
1075     String s;                          /* project file                     */
1076
1077     if ((s=readFilename()) || currProject) {
1078         if (!s)
1079             s = strCopy(currProject);
1080         else if (readFilename()) {
1081             ERRMSG(0) "Too many project files"
1082             EEND;
1083         }
1084         else
1085             s = strCopy(s);
1086     }
1087     else {
1088         ERRMSG(0) "No project filename specified"
1089         EEND;
1090     }
1091     loadProject(s);
1092     readScripts(1);
1093 }
1094
1095 static Void local readScripts(n)        /* Reread current list of scripts, */
1096 Int n; {                                /* loading everything after and    */
1097     Time timeStamp;                     /* including the first script which*/
1098     Long fileSize;                      /* has been either changed or added*/
1099     static char name[FILENAME_MAX+1];
1100
1101     lastWasObject = FALSE;
1102     ppSmStack("readscripts-begin");
1103 #if HUGS_FOR_WINDOWS
1104     SetCursor(LoadCursor(NULL, IDC_WAIT));
1105 #endif
1106
1107 #if 0
1108     for (; n<numScripts; n++) {         /* Scan previously loaded scripts  */
1109         ppSmStack("readscripts-loop1");
1110         getFileInfo(scriptName[n], &timeStamp, &fileSize);
1111         if (timeChanged(timeStamp,lastChange[n])) {
1112             dropScriptsFrom(n-1);
1113             numScripts = n;
1114             break;
1115         }
1116     }
1117     for (; n<NUM_SCRIPTS; n++)          /* No scripts have been postponed  */
1118         postponed[n] = FALSE;           /* at this stage                   */
1119     numScripts = 0;
1120
1121     while (numScripts<namesUpto) {      /* Process any remaining scripts   */
1122         ppSmStack("readscripts-loop2");
1123         getFileInfo(scriptName[numScripts], &timeStamp, &fileSize);
1124         timeSet(lastChange[numScripts],timeStamp);
1125         if (numScripts>0)               /* no new script for prelude       */
1126             startNewScript(scriptName[numScripts]);
1127         if (addScript(scriptName[numScripts],fileSize))
1128             numScripts++;
1129         else
1130             dropScriptsFrom(numScripts-1);
1131     }
1132 #endif
1133
1134     interface(RESET);
1135
1136     for (; n<numScripts; n++) {
1137         ppSmStack("readscripts-loop2");
1138         strcpy(name, scriptInfo[n].path);
1139         strcat(name, scriptInfo[n].modName);
1140         if (scriptInfo[n].fromSource)
1141            strcat(name, scriptInfo[n].srcExt); else
1142            strcat(name, ".hi");  //ToDo: should be .o
1143         getFileInfo(name,&timeStamp, &fileSize);
1144         if (timeChanged(timeStamp,scriptInfo[n].lastChange)) {
1145            dropScriptsFrom(n-1);
1146            numScripts = n;
1147            break;
1148         }
1149     }
1150     for (; n<NUM_SCRIPTS; n++)
1151         scriptInfo[n].postponed = FALSE;
1152
1153     //numScripts = 0;
1154
1155     while (numScripts < namesUpto) {
1156 ppSmStack ( "readscripts-loop2" );
1157
1158        if (scriptInfo[numScripts].fromSource) {
1159
1160           if (numScripts>0)
1161               startNewScript(scriptInfo[numScripts].modName);
1162           nextNumScripts = NUM_SCRIPTS; //bogus initialisation
1163           if (addScript(numScripts)) {
1164              numScripts++;
1165 assert(nextNumScripts==NUM_SCRIPTS);
1166           }
1167           else
1168              dropScriptsFrom(numScripts-1);
1169
1170        } else {
1171       
1172           if (scriptInfo[numScripts].objLoaded) {
1173              numScripts++;
1174           } else {
1175              scriptInfo[numScripts].objLoaded = TRUE;
1176              /* new */
1177              if (numScripts>0)
1178                  startNewScript(scriptInfo[numScripts].modName);
1179              /* end */
1180              nextNumScripts = NUM_SCRIPTS;
1181              if (addScript(numScripts)) {
1182                 numScripts++;
1183 assert(nextNumScripts==NUM_SCRIPTS);
1184              } else {
1185                 //while (!scriptInfo[numScripts].fromSource && numScripts > 0)
1186                 //   numScripts--;
1187                 //if (scriptInfo[numScripts].fromSource)
1188                 //   numScripts++;
1189                 numScripts = nextNumScripts;
1190 assert(nextNumScripts<NUM_SCRIPTS);
1191              }
1192           }
1193        }
1194 if (numScripts==namesUpto) ppSmStack( "readscripts-final") ;
1195     }
1196
1197     finishInterfaces();
1198
1199     { Int  m     = namesUpto-1;
1200       Text mtext = findText(scriptInfo[m].modName);
1201       /* Commented out till we understand what
1202        * this is trying to do.
1203        * Problem, you cant find a module till later.
1204        */
1205 #if 0
1206        setCurrModule(findModule(mtext)); 
1207 #endif
1208       evalModule = mtext;
1209     }
1210
1211     
1212
1213     if (listScripts)
1214         whatScripts();
1215     if (numScripts<=1)
1216         setLastEdit((String)0, 0);
1217     ppSmStack("readscripts-end  ");
1218 }
1219
1220 static Void local whatScripts() {       /* list scripts in current session */
1221     int i;
1222     Printf("\nHugs session for:");
1223     if (projectLoaded)
1224         Printf(" (project: %s)",currProject);
1225     for (i=0; i<numScripts; ++i)
1226       Printf("\n%s%s",scriptInfo[i].path, scriptInfo[i].modName);
1227     Putchar('\n');
1228 }
1229
1230 /* --------------------------------------------------------------------------
1231  * Access to external editor:
1232  * ------------------------------------------------------------------------*/
1233
1234 static Void local editor() {            /* interpreter-editor interface    */
1235     String newFile  = readFilename();
1236     if (newFile) {
1237         setLastEdit(newFile,0);
1238         if (readFilename()) {
1239             ERRMSG(0) "Multiple filenames not permitted"
1240             EEND;
1241         }
1242     }
1243     runEditor();
1244 }
1245
1246 static Void local find() {              /* edit file containing definition */
1247 #if 0
1248 This just plain wont work no more.
1249 ToDo: Fix!
1250     String nm = readFilename();         /* of specified name               */
1251     if (!nm) {
1252         ERRMSG(0) "No name specified"
1253         EEND;
1254     }
1255     else if (readFilename()) {
1256         ERRMSG(0) "Multiple names not permitted"
1257         EEND;
1258     }
1259     else {
1260         Text t;
1261         Cell c;
1262         setCurrModule(findEvalModule());
1263         startNewScript(0);
1264         if (nonNull(c=findTycon(t=findText(nm)))) {
1265             if (startEdit(tycon(c).line,scriptName[scriptThisTycon(c)])) {
1266                 readScripts(1);
1267             }
1268         } else if (nonNull(c=findName(t))) {
1269             if (startEdit(name(c).line,scriptName[scriptThisName(c)])) {
1270                 readScripts(1);
1271             }
1272         } else {
1273             ERRMSG(0) "No current definition for name \"%s\"", nm
1274             EEND;
1275         }
1276     }
1277 #endif
1278 }
1279
1280 static Void local runEditor() {         /* run editor on script lastEdit   */
1281     if (startEdit(lastEdLine,lastEdit)) /* at line lastEdLine              */
1282         readScripts(1);
1283 }
1284
1285 static Void local setLastEdit(fname,line)/* keep name of last file to edit */
1286 String fname;
1287 Int    line; {
1288     if (lastEdit)
1289         free(lastEdit);
1290     lastEdit = strCopy(fname);
1291     lastEdLine = line;
1292 #if HUGS_FOR_WINDOWS
1293     DrawStatusLine(hWndMain);           /* Redo status line                */
1294 #endif
1295 }
1296
1297 /* --------------------------------------------------------------------------
1298  * Read and evaluate an expression:
1299  * ------------------------------------------------------------------------*/
1300
1301 static Void local setModule(){/*set module in which to evaluate expressions*/
1302     String s = readFilename();
1303     if (!s) s = "";              /* :m clears the current module selection */
1304     evalModule = findText(s);
1305     setLastEdit(fileOfModule(findEvalModule()),0);
1306 }
1307
1308 static Module local findEvalModule() { /*Module in which to eval expressions*/
1309     Module m = findModule(evalModule); 
1310     if (isNull(m))
1311         m = lastModule();
1312     return m;
1313 }
1314
1315 static Void local evaluator() {        /* evaluate expr and print value    */
1316     Type  type, bd;
1317     Kinds ks   = NIL;
1318
1319     setCurrModule(findEvalModule());
1320     scriptFile = 0;
1321     startNewScript(0);                 /* Enables recovery of storage      */
1322                                        /* allocated during evaluation      */
1323     parseExp();
1324     checkExp();
1325     defaultDefns = evalDefaults;
1326     type         = typeCheckExp(TRUE);
1327     if (isPolyType(type)) {
1328         ks = polySigOf(type);
1329         bd = monotypeOf(type);
1330     }
1331     else
1332         bd = type;
1333
1334     if (whatIs(bd)==QUAL) {
1335         ERRMSG(0) "Unresolved overloading" ETHEN
1336         ERRTEXT   "\n*** Type       : "    ETHEN ERRTYPE(type);
1337         ERRTEXT   "\n*** Expression : "    ETHEN ERREXPR(inputExpr);
1338         ERRTEXT   "\n"
1339         EEND;
1340     }
1341   
1342 #ifdef WANT_TIMER
1343     updateTimers();
1344 #endif
1345
1346 #if 1
1347     if (typeMatches(type,ap(typeIO,typeUnit))) {
1348         inputExpr = ap(nameRunIO,inputExpr);
1349         evalExp();
1350         Putchar('\n');
1351     } else {
1352         Cell d = provePred(ks,NIL,ap(classShow,bd));
1353         if (isNull(d)) {
1354             ERRMSG(0) "Cannot find \"show\" function for:" ETHEN
1355             ERRTEXT   "\n*** expression : "   ETHEN ERREXPR(inputExpr);
1356             ERRTEXT   "\n*** of type    : "   ETHEN ERRTYPE(type);
1357             ERRTEXT   "\n"
1358             EEND;
1359         }
1360         inputExpr = ap2(findName(findText("show")),d,inputExpr);
1361         inputExpr = ap(findName(findText("putStr")), inputExpr);
1362         inputExpr = ap(nameRunIO, inputExpr);
1363
1364         evalExp(); printf("\n");
1365         if (addType) {
1366             printf(" :: ");
1367             printType(stdout,type);
1368             Putchar('\n');
1369         }
1370     }
1371
1372 #else
1373
1374    printf ( "result type is " );
1375    printType ( stdout, type );
1376    printf ( "\n" );
1377    evalExp();
1378    printf ( "\n" );
1379
1380 #endif
1381
1382 }
1383
1384 static Void local stopAnyPrinting() {  /* terminate printing of expression,*/
1385     if (printing) {                    /* after successful termination or  */
1386         printing = FALSE;              /* runtime error (e.g. interrupt)   */
1387         Putchar('\n');
1388         if (showStats) {
1389 #define plural(v)   v, (v==1?"":"s")
1390             Printf("%lu cell%s",plural(numCells));
1391             if (numGcs>0)
1392                 Printf(", %u garbage collection%s",plural(numGcs));
1393             Printf(")\n");
1394 #undef plural
1395         }
1396         FlushStdout();
1397         garbageCollect();
1398     }
1399 }
1400
1401 /* --------------------------------------------------------------------------
1402  * Print type of input expression:
1403  * ------------------------------------------------------------------------*/
1404
1405 static Void local showtype() {         /* print type of expression (if any)*/
1406     Cell type;
1407
1408     setCurrModule(findEvalModule());
1409     startNewScript(0);                 /* Enables recovery of storage      */
1410                                        /* allocated during evaluation      */
1411     parseExp();
1412     checkExp();
1413     defaultDefns = evalDefaults;
1414     type = typeCheckExp(FALSE);
1415     printExp(stdout,inputExpr);
1416     Printf(" :: ");
1417     printType(stdout,type);
1418     Putchar('\n');
1419 }
1420
1421
1422 static Void local browseit(mod,t)
1423 Module mod; 
1424 String t; {
1425     if (nonNull(mod)) {
1426         Cell cs;
1427         Printf("module %s where\n",textToStr(module(mod).text));
1428         for (cs = module(mod).names; nonNull(cs); cs=tl(cs)) {
1429             Name nm = hd(cs);
1430             /* only look at things defined in this module */
1431             if (name(nm).mod == mod) {
1432                 /* unwanted artifacts, like lambda lifted values,
1433                    are in the list of names, but have no types */
1434                 if (nonNull(name(nm).type)) {
1435                     printExp(stdout,nm);
1436                     Printf(" :: ");
1437                     printType(stdout,name(nm).type);
1438                     if (isCfun(nm)) {
1439                         Printf("  -- data constructor");
1440                     } else if (isMfun(nm)) {
1441                         Printf("  -- class member");
1442                     } else if (isSfun(nm)) {
1443                         Printf("  -- selector function");
1444                     }
1445                     Printf("\n");
1446                 }
1447             }
1448         }
1449     } else {
1450       if (isNull(mod)) {
1451         Printf("Unknown module %s\n",t);
1452       }
1453     }
1454 }
1455
1456 static Void local browse() {            /* browse modules                  */
1457     Int    count = 0;                   /* or give menu of commands        */
1458     String s;
1459
1460     setCurrModule(findEvalModule());
1461     startNewScript(0);                  /* for recovery of storage         */
1462     for (; (s=readFilename())!=0; count++) {
1463         browseit(findModule(findText(s)),s);
1464     }
1465     if (count == 0) {
1466         whatScripts();
1467     }
1468 }
1469
1470 #if EXPLAIN_INSTANCE_RESOLUTION
1471 static Void local xplain() {         /* print type of expression (if any)*/
1472     Cell type;
1473     Cell d;
1474     Bool sir = showInstRes;
1475
1476     setCurrModule(findEvalModule());
1477     startNewScript(0);                 /* Enables recovery of storage      */
1478                                        /* allocated during evaluation      */
1479     parseContext();
1480     checkContext();
1481     showInstRes = TRUE;
1482     d = provePred(NIL,NIL,hd(inputContext));
1483     if (isNull(d)) {
1484         fprintf(stdout, "not Sat\n");
1485     } else {
1486         fprintf(stdout, "Sat\n");
1487     }
1488     showInstRes = sir;
1489 }
1490 #endif
1491
1492 /* --------------------------------------------------------------------------
1493  * Enhanced help system:  print current list of scripts or give information
1494  * about an object.
1495  * ------------------------------------------------------------------------*/
1496
1497 static String local objToStr(m,c)
1498 Module m;
1499 Cell   c; {
1500 #if 1 || DISPLAY_QUANTIFIERS
1501     static char newVar[60];
1502     switch (whatIs(c)) {
1503         case NAME  : if (m == name(c).mod) {
1504                          sprintf(newVar,"%s", textToStr(name(c).text));
1505                      } else {
1506                          sprintf(newVar,"%s.%s",
1507                                         textToStr(module(name(c).mod).text),
1508                                         textToStr(name(c).text));
1509                      }
1510                      break;
1511
1512         case TYCON : if (m == tycon(c).mod) {
1513                          sprintf(newVar,"%s", textToStr(tycon(c).text));
1514                      } else {
1515                          sprintf(newVar,"%s.%s",
1516                                         textToStr(module(tycon(c).mod).text),
1517                                         textToStr(tycon(c).text));
1518                      }
1519                      break;
1520
1521         case CLASS : if (m == cclass(c).mod) {
1522                          sprintf(newVar,"%s", textToStr(cclass(c).text));
1523                      } else {
1524                          sprintf(newVar,"%s.%s",
1525                                         textToStr(module(cclass(c).mod).text),
1526                                         textToStr(cclass(c).text));
1527                      }
1528                      break;
1529
1530         default    : internal("objToStr");
1531     }
1532     return newVar;
1533 #else
1534     static char newVar[33];
1535     switch (whatIs(c)) {
1536         case NAME  : sprintf(newVar,"%s", textToStr(name(c).text));
1537                      break;
1538
1539         case TYCON : sprintf(newVar,"%s", textToStr(tycon(c).text));
1540                      break;
1541
1542         case CLASS : sprintf(newVar,"%s", textToStr(cclass(c).text));
1543                      break;
1544
1545         default    : internal("objToStr");
1546     }
1547     return newVar;
1548 #endif
1549 }
1550
1551 extern Name nameHw;
1552
1553 static Void local dumpStg( void ) {       /* print STG stuff                 */
1554     String s;
1555     Text   t;
1556     Name   n;
1557     Int    i;
1558     Cell   v;                           /* really StgVar */
1559     setCurrModule(findEvalModule());
1560     startNewScript(0);
1561     for (; (s=readFilename())!=0;) {
1562         t = findText(s);
1563         v = n = NIL;
1564         /* find the name while ignoring module scopes */
1565         for (i=NAMEMIN; i<nameHw; i++)
1566            if (name(i).text == t) n = i;
1567
1568         /* perhaps it's an "idNNNNNN" thing? */
1569         if (isNull(n) &&
1570             strlen(s) >= 3 && 
1571             s[0]=='i' && s[1]=='d' && isdigit(s[2])) {
1572            v = 0;
1573            i = 2;
1574            while (isdigit(s[i])) {
1575               v = v * 10 + (s[i]-'0');
1576               i++;
1577            }
1578            v = -v;
1579            n = nameFromStgVar(v);
1580         }
1581
1582         if (isNull(n) && whatIs(v)==STGVAR) {
1583            Printf ( "\n{- `%s' has no nametable entry -}\n", s );
1584            Printf ( "{- stgSize of body is %d -}\n\n", stgSize(stgVarBody(v)));
1585            printStg(stderr, v );
1586         } else
1587         if (isNull(n)) {
1588            Printf ( "Unknown reference `%s'\n", s );
1589         } else
1590         if (!isName(n)) {
1591            Printf ( "Not a Name: `%s'\n", s );
1592         } else
1593         if (isNull(name(n).stgVar)) {
1594            Printf ( "Doesn't have a STG tree: %s\n", s );
1595         } else {
1596            Printf ( "\n{- stgVar of `%s' is id%d -}\n", s, -name(n).stgVar);
1597            Printf ( "{- stgSize of body is %d -}\n\n", 
1598                     stgSize(stgVarBody(name(n).stgVar)));
1599            printStg(stderr, name(n).stgVar);
1600         }
1601     }
1602 }
1603
1604 static Void local info() {              /* describe objects                */
1605     Int    count = 0;                   /* or give menu of commands        */
1606     String s;
1607
1608     setCurrModule(findEvalModule());
1609     startNewScript(0);                  /* for recovery of storage         */
1610     for (; (s=readFilename())!=0; count++) {
1611         describe(findText(s));
1612     }
1613     if (count == 0) {
1614         whatScripts();
1615     }
1616 }
1617
1618
1619 static Void local describe(t)           /* describe an object              */
1620 Text t; {
1621     Tycon  tc  = findTycon(t);
1622     Class  cl  = findClass(t);
1623     Name   nm  = findName(t);
1624
1625     if (nonNull(tc)) {                  /* as a type constructor           */
1626         Type t = tc;
1627         Int  i;
1628         Inst in;
1629         for (i=0; i<tycon(tc).arity; ++i) {
1630             t = ap(t,mkOffset(i));
1631         }
1632         Printf("-- type constructor");
1633         if (kindExpert) {
1634             Printf(" with kind ");
1635             printKind(stdout,tycon(tc).kind);
1636         }
1637         Putchar('\n');
1638         switch (tycon(tc).what) {
1639             case SYNONYM      : Printf("type ");
1640                                 printType(stdout,t);
1641                                 Printf(" = ");
1642                                 printType(stdout,tycon(tc).defn);
1643                                 break;
1644
1645             case NEWTYPE      :
1646             case DATATYPE     : {   List cs = tycon(tc).defn;
1647                                     if (tycon(tc).what==DATATYPE) {
1648                                         Printf("data ");
1649                                     } else {
1650                                         Printf("newtype ");
1651                                     }
1652                                     printType(stdout,t);
1653                                     Putchar('\n');
1654                                     mapProc(printSyntax,cs);
1655                                     if (hasCfun(cs)) {
1656                                         Printf("\n-- constructors:");
1657                                     }
1658                                     for (; hasCfun(cs); cs=tl(cs)) {
1659                                         Putchar('\n');
1660                                         printExp(stdout,hd(cs));
1661                                         Printf(" :: ");
1662                                         printType(stdout,name(hd(cs)).type);
1663                                     }
1664                                     if (nonNull(cs)) {
1665                                         Printf("\n-- selectors:");
1666                                     }
1667                                     for (; nonNull(cs); cs=tl(cs)) {
1668                                         Putchar('\n');
1669                                         printExp(stdout,hd(cs));
1670                                         Printf(" :: ");
1671                                         printType(stdout,name(hd(cs)).type);
1672                                     }
1673                                 }
1674                                 break;
1675
1676             case RESTRICTSYN  : Printf("type ");
1677                                 printType(stdout,t);
1678                                 Printf(" = <restricted>");
1679                                 break;
1680         }
1681         Putchar('\n');
1682         if (nonNull(in=findFirstInst(tc))) {
1683             Printf("\n-- instances:\n");
1684             do {
1685                 showInst(in);
1686                 in = findNextInst(tc,in);
1687             } while (nonNull(in));
1688         }
1689         Putchar('\n');
1690     }
1691
1692     if (nonNull(cl)) {                  /* as a class                      */
1693         List  ins = cclass(cl).instances;
1694         Kinds ks  = cclass(cl).kinds;
1695         if (nonNull(ks) && isNull(tl(ks)) && hd(ks)==STAR) {
1696             Printf("-- type class");
1697         } else {
1698             Printf("-- constructor class");
1699             if (kindExpert) {
1700                 Printf(" with arity ");
1701                 printKinds(stdout,ks);
1702             }
1703         }
1704         Putchar('\n');
1705         mapProc(printSyntax,cclass(cl).members);
1706         Printf("class ");
1707         if (nonNull(cclass(cl).supers)) {
1708             printContext(stdout,cclass(cl).supers);
1709             Printf(" => ");
1710         }
1711         printPred(stdout,cclass(cl).head);
1712
1713         if (nonNull(cclass(cl).fds)) {
1714             List   fds = cclass(cl).fds;
1715             String pre = " | ";
1716             for (; nonNull(fds); fds=tl(fds)) {
1717                 Printf(pre);
1718                 printFD(stdout,hd(fds));
1719                 pre = ", ";
1720             }
1721         }
1722
1723         if (nonNull(cclass(cl).members)) {
1724             List ms = cclass(cl).members;
1725             Printf(" where");
1726             do {
1727                 Type t = monotypeOf(name(hd(ms)).type);
1728                 Printf("\n  ");
1729                 printExp(stdout,hd(ms));
1730                 Printf(" :: ");
1731                 if (isNull(tl(fst(snd(t))))) {
1732                     t = snd(snd(t));
1733                 } else {
1734                     t = ap(QUAL,pair(tl(fst(snd(t))),snd(snd(t))));
1735                 }
1736                 printType(stdout,t);
1737                 ms = tl(ms);
1738             } while (nonNull(ms));
1739         }
1740         Putchar('\n');
1741         if (nonNull(ins)) {
1742             Printf("\n-- instances:\n");
1743             do {
1744                 showInst(hd(ins));
1745                 ins = tl(ins);
1746             } while (nonNull(ins));
1747         }
1748         Putchar('\n');
1749     }
1750
1751     if (nonNull(nm)) {                  /* as a function/name              */
1752         printSyntax(nm);
1753         printExp(stdout,nm);
1754         Printf(" :: ");
1755         if (nonNull(name(nm).type)) {
1756             printType(stdout,name(nm).type);
1757         } else {
1758             Printf("<unknown type>");
1759         }
1760
1761         if (isCfun(nm)) {
1762             Printf("  -- data constructor");
1763         } else if (isMfun(nm)) {
1764             Printf("  -- class member");
1765         } else if (isSfun(nm)) {
1766             Printf("  -- selector function");
1767         }
1768         Printf("\n\n");
1769     }
1770
1771
1772     if (isNull(tc) && isNull(cl) && isNull(nm)) {
1773         Printf("Unknown reference `%s'\n",textToStr(t));
1774     }
1775 }
1776
1777 static Void local printSyntax(nm)
1778 Name nm; {
1779     Syntax sy = syntaxOf(nm);
1780     Text   t  = name(nm).text;
1781     String s  = textToStr(t);
1782     if (sy != defaultSyntax(t)) {
1783         Printf("infix");
1784         switch (assocOf(sy)) {
1785             case LEFT_ASS  : Putchar('l'); break;
1786             case RIGHT_ASS : Putchar('r'); break;
1787             case NON_ASS   : break;
1788         }
1789         Printf(" %i ",precOf(sy));
1790         if (isascii((int)(*s)) && isalpha((int)(*s))) {
1791             Printf("`%s`",s);
1792         } else {
1793             Printf("%s",s);
1794         }
1795         Putchar('\n');
1796     }
1797 }
1798
1799 static Void local showInst(in)          /* Display instance decl header    */
1800 Inst in; {
1801     Printf("instance ");
1802     if (nonNull(inst(in).specifics)) {
1803         printContext(stdout,inst(in).specifics);
1804         Printf(" => ");
1805     }
1806     printPred(stdout,inst(in).head);
1807     Putchar('\n');
1808 }
1809
1810 /* --------------------------------------------------------------------------
1811  * List all names currently in scope:
1812  * ------------------------------------------------------------------------*/
1813
1814 static Void local listNames() {         /* list names matching optional pat*/
1815     String pat   = readFilename();
1816     List   names = NIL;
1817     Int    width = getTerminalWidth() - 1;
1818     Int    count = 0;
1819     Int    termPos;
1820     Module mod   = findEvalModule();
1821
1822     if (pat) {                          /* First gather names to list      */
1823         do {
1824             names = addNamesMatching(pat,names);
1825         } while ((pat=readFilename())!=0);
1826     } else {
1827         names = addNamesMatching((String)0,names);
1828     }
1829     if (isNull(names)) {                /* Then print them out             */
1830         ERRMSG(0) "No names selected"
1831         EEND;
1832     }
1833     for (termPos=0; nonNull(names); names=tl(names)) {
1834         String s = objToStr(mod,hd(names));
1835         Int    l = strlen(s);
1836         if (termPos+1+l>width) { 
1837             Putchar('\n');       
1838             termPos = 0;         
1839         } else if (termPos>0) {  
1840             Putchar(' ');        
1841             termPos++;           
1842         }
1843         Printf("%s",s);
1844         termPos += l;
1845         count++;
1846     }
1847     Printf("\n(%d names listed)\n", count);
1848 }
1849
1850 /* --------------------------------------------------------------------------
1851  * print a prompt and read a line of input:
1852  * ------------------------------------------------------------------------*/
1853
1854 static Void local promptForInput(moduleName)
1855 String moduleName; {
1856     char promptBuffer[1000];
1857 #if 1
1858     /* This is portable but could overflow buffer */
1859     sprintf(promptBuffer,prompt,moduleName);
1860 #else
1861     /* Works on ANSI C - but pre-ANSI compilers return a pointer to
1862      * promptBuffer instead.
1863      */
1864     if (sprintf(promptBuffer,prompt,moduleName) >= 1000) {
1865         /* Reset prompt to a safe default to avoid an infinite loop */
1866         free(prompt);
1867         prompt = strCopy("? ");
1868         internal("Combined prompt and evaluation module name too long");
1869     }
1870 #endif
1871     if (autoMain)
1872        stringInput("main\0"); else
1873        consoleInput(promptBuffer);
1874 }
1875
1876 /* --------------------------------------------------------------------------
1877  * main read-eval-print loop, with error trapping:
1878  * ------------------------------------------------------------------------*/
1879
1880 static jmp_buf catch_error;             /* jump buffer for error trapping  */
1881
1882 static Void local interpreter(argc,argv)/* main interpreter loop           */
1883 Int    argc;
1884 String argv[]; {
1885     Int errorNumber = setjmp(catch_error);
1886
1887     if (errorNumber && autoMain) {
1888        fprintf(stderr, "hugs +Q: compilation failed -- can't run `main'\n" );
1889        exit(1);
1890     }
1891
1892     breakOn(TRUE);                      /* enable break trapping           */
1893     if (numScripts==0) {                /* only succeeds on first time,    */
1894         if (errorNumber)                /* before prelude has been loaded  */
1895             fatal("Unable to load prelude");
1896         initialize(argc,argv);
1897         forHelp();
1898     }
1899
1900     for (;;) {
1901         Command cmd;
1902         everybody(RESET);               /* reset to sensible initial state */
1903         dropScriptsFrom(numScripts-1);  /* remove partially loaded scripts */
1904                                         /* not counting prelude as a script*/
1905
1906         promptForInput(textToStr(module(findEvalModule()).text));
1907
1908         cmd = readCommand(cmds, (Char)':', (Char)'!');
1909 #ifdef WANT_TIMER
1910         updateTimers();
1911 #endif
1912         switch (cmd) {
1913             case EDIT   : editor();
1914                           break;
1915             case FIND   : find();
1916                           break;
1917             case LOAD   : clearProject();
1918                           forgetScriptsFrom(1);
1919                           load();
1920                           break;
1921             case ALSO   : clearProject();
1922                           forgetScriptsFrom(numScripts);
1923                           load();
1924                           break;
1925             case RELOAD : readScripts(1);
1926                           break;
1927             case PROJECT: project();
1928                           break;
1929             case SETMODULE :
1930                           setModule();
1931                           break;
1932             case EVAL   : evaluator();
1933                           break;
1934             case TYPEOF : showtype();
1935                           break;
1936             case BROWSE : browse();
1937                           break;
1938 #if EXPLAIN_INSTANCE_RESOLUTION
1939             case XPLAIN : xplain();
1940                           break;
1941 #endif
1942             case NAMES  : listNames();
1943                           break;
1944             case HELP   : menu();
1945                           break;
1946             case BADCMD : guidance();
1947                           break;
1948             case SET    : set();
1949                           break;
1950             case STATS:
1951 #ifdef CRUDE_PROFILING
1952                           cp_show();
1953 #endif
1954                           break;
1955             case SYSTEM : if (shellEsc(readLine()))
1956                               Printf("Warning: Shell escape terminated abnormally\n");
1957                           break;
1958             case CHGDIR : changeDir();
1959                           break;
1960             case INFO   : info();
1961                           break;
1962             case PNTVER: Printf("-- Hugs Version %s\n",
1963                                  HUGS_VERSION);
1964                           break;
1965             case DUMP   : dumpStg();
1966                           break;
1967             case QUIT   : return;
1968             case COLLECT: consGC = FALSE;
1969                           garbageCollect();
1970                           consGC = TRUE;
1971                           Printf("Garbage collection recovered %d cells\n",
1972                                  cellsRecovered);
1973                           break;
1974             case NOCMD  : break;
1975         }
1976 #ifdef WANT_TIMER
1977         updateTimers();
1978         Printf("Elapsed time (ms): %ld (user), %ld (system)\n",
1979                millisecs(userElapsed), millisecs(systElapsed));
1980 #endif
1981         if (autoMain) break;
1982     }
1983     breakOn(FALSE);
1984 }
1985
1986 /* --------------------------------------------------------------------------
1987  * Display progress towards goal:
1988  * ------------------------------------------------------------------------*/
1989
1990 static Target currTarget;
1991 static Bool   aiming = FALSE;
1992 static Int    currPos;
1993 static Int    maxPos;
1994 static Int    charCount;
1995
1996 Void setGoal(what, t)                  /* Set goal for what to be t        */
1997 String what;
1998 Target t; {
1999     if (quiet) return;
2000     currTarget = (t?t:1);
2001     aiming     = TRUE;
2002     if (useDots) {
2003         currPos = strlen(what);
2004         maxPos  = getTerminalWidth() - 1;
2005         Printf("%s",what);
2006     }
2007     else
2008         for (charCount=0; *what; charCount++)
2009             Putchar(*what++);
2010     FlushStdout();
2011 }
2012
2013 Void soFar(t)                          /* Indicate progress towards goal   */
2014 Target t; {                            /* has now reached t                */
2015     if (quiet) return;
2016     if (useDots) {
2017         Int newPos = (Int)((maxPos * ((long)t))/currTarget);
2018
2019         if (newPos>maxPos)
2020             newPos = maxPos;
2021
2022         if (newPos>currPos) {
2023             do
2024                 Putchar('.');
2025             while (newPos>++currPos);
2026             FlushStdout();
2027         }
2028         FlushStdout();
2029     }
2030 }
2031
2032 Void done() {                          /* Goal has now been achieved       */
2033     if (quiet) return;
2034     if (useDots) {
2035         while (maxPos>currPos++)
2036             Putchar('.');
2037         Putchar('\n');
2038     }
2039     else
2040         for (; charCount>0; charCount--) {
2041             Putchar('\b');
2042             Putchar(' ');
2043             Putchar('\b');
2044         }
2045     aiming = FALSE;
2046     FlushStdout();
2047 }
2048
2049 static Void local failed() {           /* Goal cannot be reached due to    */
2050     if (aiming) {                      /* errors                           */
2051         aiming = FALSE;
2052         Putchar('\n');
2053         FlushStdout();
2054     }
2055 }
2056
2057 /* --------------------------------------------------------------------------
2058  * Error handling:
2059  * ------------------------------------------------------------------------*/
2060
2061 Void errHead(l)                        /* print start of error message     */
2062 Int l; {
2063     failed();                          /* failed to reach target ...       */
2064     stopAnyPrinting();
2065     FPrintf(errorStream,"ERROR");
2066
2067     if (scriptFile) {
2068         FPrintf(errorStream," \"%s\"", scriptFile);
2069         setLastEdit(scriptFile,l);
2070         if (l) FPrintf(errorStream," (line %d)",l);
2071         scriptFile = 0;
2072     }
2073     FPrintf(errorStream,": ");
2074     FFlush(errorStream);
2075 }
2076
2077 Void errFail() {                        /* terminate error message and     */
2078     Putc('\n',errorStream);             /* produce exception to return to  */
2079     FFlush(errorStream);                /* main command loop               */
2080     longjmp(catch_error,1);
2081 }
2082
2083 Void errAbort() {                       /* altern. form of error handling  */
2084     failed();                           /* used when suitable error message*/
2085     stopAnyPrinting();                  /* has already been printed        */
2086     errFail();
2087 }
2088
2089 Void internal(msg)                      /* handle internal error           */
2090 String msg; {
2091 #if HUGS_FOR_WINDOWS
2092     char buf[300];
2093     wsprintf(buf,"INTERNAL ERROR: %s",msg);
2094     MessageBox(hWndMain, buf, appName, MB_ICONHAND | MB_OK);
2095 #endif
2096     failed();
2097     stopAnyPrinting();
2098     Printf("INTERNAL ERROR: %s\n",msg);
2099     FlushStdout();
2100     longjmp(catch_error,1);
2101 }
2102
2103 Void fatal(msg)                         /* handle fatal error              */
2104 String msg; {
2105 #if HUGS_FOR_WINDOWS
2106     char buf[300];
2107     wsprintf(buf,"FATAL ERROR: %s",msg);
2108     MessageBox(hWndMain, buf, appName, MB_ICONHAND | MB_OK);
2109 #endif
2110     FlushStdout();
2111     Printf("\nFATAL ERROR: %s\n",msg);
2112     everybody(EXIT);
2113     exit(1);
2114 }
2115
2116 sigHandler(breakHandler) {              /* respond to break interrupt      */
2117 #if HUGS_FOR_WINDOWS
2118     MessageBox(GetFocus(), "Interrupted!", appName, MB_ICONSTOP | MB_OK);
2119 #endif
2120     Hilite();
2121     Printf("{Interrupted!}\n");
2122     Lolite();
2123     breakOn(TRUE);  /* reinstall signal handler - redundant on BSD systems */
2124                     /* but essential on POSIX (and other?) systems         */
2125     everybody(BREAK);
2126     failed();
2127     stopAnyPrinting();
2128     FlushStdout();
2129     clearerr(stdin);
2130     longjmp(catch_error,1);
2131     sigResume;/*NOTREACHED*/
2132 }
2133
2134 /* --------------------------------------------------------------------------
2135  * Read value from environment variable or registry:
2136  * ------------------------------------------------------------------------*/
2137
2138 String fromEnv(var,def)         /* return value of:                        */
2139 String var;                     /*     environment variable named by var   */
2140 String def; {                   /* or: default value given by def          */
2141     String s = getenv(var);     
2142     return (s ? s : def);
2143 }
2144
2145 /* --------------------------------------------------------------------------
2146  * String manipulation routines:
2147  * ------------------------------------------------------------------------*/
2148
2149 static String local strCopy(s)         /* make malloced copy of a string   */
2150 String s; {
2151     if (s && *s) {
2152         char *t, *r;
2153         if ((t=(char *)malloc(strlen(s)+1))==0) {
2154             ERRMSG(0) "String storage space exhausted"
2155             EEND;
2156         }
2157         for (r=t; (*r++ = *s++)!=0; ) {
2158         }
2159         return t;
2160     }
2161     return NULL;
2162 }
2163
2164 /* --------------------------------------------------------------------------
2165  * Compiler output
2166  * We can redirect compiler output (prompts, error messages, etc) by
2167  * tweaking these functions.
2168  * ------------------------------------------------------------------------*/
2169
2170 #if REDIRECT_OUTPUT && !HUGS_FOR_WINDOWS
2171
2172 #ifdef HAVE_STDARG_H
2173 #include <stdarg.h>
2174 #else
2175 #include <varargs.h>
2176 #endif
2177
2178 /* ----------------------------------------------------------------------- */
2179
2180 #define BufferSize 10000              /* size of redirected output buffer  */
2181
2182 typedef struct _HugsStream {
2183     char buffer[BufferSize];          /* buffer for redirected output      */
2184     Int  next;                        /* next space in buffer              */
2185 } HugsStream;
2186
2187 static Void   local vBufferedPrintf  Args((HugsStream*, const char*, va_list));
2188 static Void   local bufferedPutchar  Args((HugsStream*, Char));
2189 static String local bufferClear      Args((HugsStream *stream));
2190
2191 static Void local vBufferedPrintf(stream, fmt, ap)
2192 HugsStream* stream;
2193 const char* fmt;
2194 va_list     ap; {
2195     Int spaceLeft = BufferSize - stream->next;
2196     char* p = &stream->buffer[stream->next];
2197     Int charsAdded = vsnprintf(p, spaceLeft, fmt, ap);
2198     if (0 <= charsAdded && charsAdded < spaceLeft) 
2199         stream->next += charsAdded;
2200 #if 1 /* we can either buffer the first n chars or buffer the last n chars */
2201     else
2202         stream->next = 0;
2203 #endif
2204 }
2205
2206 static Void local bufferedPutchar(stream, c)
2207 HugsStream *stream;
2208 Char        c; {
2209     if (BufferSize - stream->next >= 2) {
2210         stream->buffer[stream->next++] = c;
2211         stream->buffer[stream->next] = '\0';
2212     }
2213 }    
2214
2215 static String local bufferClear(stream)
2216 HugsStream *stream; {
2217     if (stream->next == 0) {
2218         return "";
2219     } else {
2220         stream->next = 0;
2221         return stream->buffer;
2222     }
2223 }
2224
2225 /* ----------------------------------------------------------------------- */
2226
2227 static HugsStream outputStreamH;
2228 /* ADR note: 
2229  * We rely on standard C semantics to initialise outputStreamH.next to 0.
2230  */
2231
2232 Void hugsEnableOutput(f) 
2233 Bool f; {
2234     disableOutput = !f;
2235 }
2236
2237 String hugsClearOutputBuffer() {
2238     return bufferClear(&outputStreamH);
2239 }
2240
2241 #ifdef HAVE_STDARG_H
2242 Void hugsPrintf(const char *fmt, ...) {
2243     va_list ap;                    /* pointer into argument list           */
2244     va_start(ap, fmt);             /* make ap point to first arg after fmt */
2245     if (!disableOutput) {
2246         vprintf(fmt, ap);
2247     } else {
2248         vBufferedPrintf(&outputStreamH, fmt, ap);
2249     }
2250     va_end(ap);                    /* clean up                             */
2251 }
2252 #else
2253 Void hugsPrintf(fmt, va_alist) 
2254 const char *fmt;
2255 va_dcl {
2256     va_list ap;                    /* pointer into argument list           */
2257     va_start(ap);                  /* make ap point to first arg after fmt */
2258     if (!disableOutput) {
2259         vprintf(fmt, ap);
2260     } else {
2261         vBufferedPrintf(&outputStreamH, fmt, ap);
2262     }
2263     va_end(ap);                    /* clean up                             */
2264 }
2265 #endif
2266
2267 Void hugsPutchar(c)
2268 int c; {
2269     if (!disableOutput) {
2270         putchar(c);
2271     } else {
2272         bufferedPutchar(&outputStreamH, c);
2273     }
2274 }
2275
2276 Void hugsFlushStdout() {
2277     if (!disableOutput) {
2278         fflush(stdout);
2279     }
2280 }
2281
2282 Void hugsFFlush(fp)
2283 FILE* fp; {
2284     if (!disableOutput) {
2285         fflush(fp);
2286     }
2287 }
2288
2289 #ifdef HAVE_STDARG_H
2290 Void hugsFPrintf(FILE *fp, const char* fmt, ...) {
2291     va_list ap;             
2292     va_start(ap, fmt);      
2293     if (!disableOutput) {
2294         vfprintf(fp, fmt, ap);
2295     } else {
2296         vBufferedPrintf(&outputStreamH, fmt, ap);
2297     }
2298     va_end(ap);             
2299 }
2300 #else
2301 Void hugsFPrintf(FILE *fp, const char* fmt, va_list)
2302 FILE* fp;
2303 const char* fmt;
2304 va_dcl {
2305     va_list ap;             
2306     va_start(ap);      
2307     if (!disableOutput) {
2308         vfprintf(fp, fmt, ap);
2309     } else {
2310         vBufferedPrintf(&outputStreamH, fmt, ap);
2311     }
2312     va_end(ap);             
2313 }
2314 #endif
2315
2316 Void hugsPutc(c, fp)
2317 int   c;
2318 FILE* fp; {
2319     if (!disableOutput) {
2320         putc(c,fp);
2321     } else {
2322         bufferedPutchar(&outputStreamH, c);
2323     }
2324 }
2325     
2326 #endif /* REDIRECT_OUTPUT && !HUGS_FOR_WINDOWS */
2327 /* --------------------------------------------------------------------------
2328  * Send message to each component of system:
2329  * ------------------------------------------------------------------------*/
2330
2331 Void everybody(what)            /* send command `what' to each component of*/
2332 Int what; {                     /* system to respond as appropriate ...    */
2333     machdep(what);              /* The order of calling each component is  */
2334     storage(what);              /* important for the INSTALL command       */
2335     substitution(what);
2336     input(what);
2337     translateControl(what);
2338     linkControl(what);
2339     staticAnalysis(what);
2340     deriveControl(what);
2341     typeChecker(what);
2342     compiler(what);   
2343     codegen(what);
2344     optimiser(what);
2345 }
2346
2347 /* --------------------------------------------------------------------------
2348  * Hugs for Windows code (WinMain and related functions)
2349  * ------------------------------------------------------------------------*/
2350
2351 #if HUGS_FOR_WINDOWS
2352 #include "winhugs.c"
2353 #endif