2 /* --------------------------------------------------------------------------
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.
11 * $RCSfile: hugs.c,v $
13 * $Date: 2000/05/10 09:00:20 $
14 * ------------------------------------------------------------------------*/
20 #include "hugsbasictypes.h"
29 #include "Assembler.h" /* DEBUG_LoadSymbols */
31 Bool haskell98 = TRUE; /* TRUE => Haskell 98 compatibility*/
32 Bool initDone = FALSE;
34 #if EXPLAIN_INSTANCE_RESOLUTION
35 Bool showInstRes = FALSE;
38 Bool multiInstRes = FALSE;
41 /* --------------------------------------------------------------------------
42 * Local function prototypes:
43 * ------------------------------------------------------------------------*/
45 static List local initialize ( Int,String [] );
46 static Void local promptForInput ( String );
47 static Void local interpreter ( Int,String [] );
48 static Void local menu ( Void );
49 static Void local guidance ( Void );
50 static Void local forHelp ( Void );
51 static Void local set ( Void );
52 static Void local changeDir ( Void );
53 static Void local load ( Void );
54 static Void local project ( Void );
55 static Void local editor ( Void );
56 static Void local find ( Void );
57 static Bool local startEdit ( Int,String );
58 static Void local runEditor ( Void );
59 static Void local setModule ( Void );
60 static Void local evaluator ( Void );
61 static Void local stopAnyPrinting ( Void );
62 static Void local showtype ( Void );
63 static String local objToStr ( Module, Cell );
64 static Void local info ( Void );
65 static Void local printSyntax ( Name );
66 static Void local showInst ( Inst );
67 static Void local describe ( Text );
68 static Void local listNames ( Void );
70 static Void local toggleSet ( Char,Bool );
71 static Void local togglesIn ( Bool );
72 static Void local optionInfo ( Void );
73 static Void local readOptions ( String );
74 static Bool local processOption ( String );
75 static Void local setHeapSize ( String );
76 static Int local argToInt ( String );
78 static Void local setLastEdit ( String,Int );
79 static Void local failed ( Void );
80 static String local strCopy ( String );
81 static Void local browseit ( Module,String,Bool );
82 static Void local browse ( Void );
83 static void local clearCurrentFile ( void );
86 /* --------------------------------------------------------------------------
87 * Machine dependent code for Hugs interpreter:
88 * ------------------------------------------------------------------------*/
92 /* --------------------------------------------------------------------------
94 * ------------------------------------------------------------------------*/
96 static Bool printing = FALSE; /* TRUE => currently printing value*/
97 static Bool showStats = FALSE; /* TRUE => print stats after eval */
98 static Bool listScripts = TRUE; /* TRUE => list scripts after loading*/
99 static Bool addType = FALSE; /* TRUE => print type with value */
100 static Bool useDots = RISCOS; /* TRUE => use dots in progress */
101 static Bool quiet = FALSE; /* TRUE => don't show progress */
102 static Bool lastWasObject = FALSE;
104 Bool flagAssert = FALSE; /* TRUE => assert False <e> causes
105 an assertion failure */
106 Bool preludeLoaded = FALSE;
107 Bool debugSC = FALSE;
108 Bool combined = FALSE;
110 Module moduleBeingParsed; /* so the parser (topModule) knows */
111 static char* currentFile; /* Name of current file, or NULL */
112 static char currentFileName[1000]; /* name is stored here if it exists*/
114 static Bool autoMain = FALSE;
115 static String lastEdit = 0; /* Name of script to edit (if any) */
116 static Int lastEdLine = 0; /* Editor line number (if possible)*/
117 static String prompt = 0; /* Prompt string */
118 static Int hpSize = DEFAULTHEAP; /* Desired heap size */
119 static Bool disableOutput = FALSE; /* TRUE => quiet */
120 String hugsEdit = 0; /* String for editor command */
121 String hugsPath = 0; /* String for file search path */
123 List ifaces_outstanding = NIL;
125 static ConId currentModule_failed = NIL; /* Remember failed module from :r */
129 /* --------------------------------------------------------------------------
131 * ------------------------------------------------------------------------*/
133 #ifndef NO_MAIN /* we omit main when building the "Hugs server" */
135 Main main ( Int, String [] ); /* now every func has a prototype */
140 #ifdef HAVE_CONSOLE_H /* Macintosh port */
142 _fcreator = 'R*ch'; /* // 'KAHL'; //'*TEX'; //'ttxt'; */
144 console_options.top = 50;
145 console_options.left = 20;
147 console_options.nrows = 32;
148 console_options.ncols = 80;
150 console_options.pause_atexit = 1;
151 console_options.title = "\pHugs";
153 console_options.procID = 5;
154 argc = ccommand(&argv);
157 CStackBase = &argc; /* Save stack base for use in gc */
161 checkBytecodeCount(); /* check for too many bytecodes */
165 /* If first arg is +Q or -Q, be entirely silent, and automatically run
166 main after loading scripts. Useful for running the nofib suite. */
167 if (argc > 1 && (strcmp(argv[1],"+Q") == 0 || strcmp(argv[1],"-Q")==0)) {
169 if (strcmp(argv[1],"-Q") == 0) {
174 Printf("__ __ __ __ ____ ___ _________________________________________\n");
175 Printf("|| || || || || || ||__ STGHugs: Based on the Haskell 98 standard\n");
176 Printf("||___|| ||__|| ||__|| __|| Copyright (c) 1994-2000\n");
177 Printf("||---|| ___|| World Wide Web: http://haskell.org/hugs\n");
178 Printf("|| || Report bugs to: hugs-bugs@haskell.org\n");
179 Printf("|| || Version: %s _________________________________________\n\n",HUGS_VERSION);
181 /* Get the absolute path to the directory containing the hugs
182 executable, so that we know where the Prelude and nHandle.so/.dll are.
183 We do this by reading env var STGHUGSDIR. This needs to succeed, so
184 setInstallDir won't return unless it succeeds.
186 setInstallDir ( argv[0] );
189 Printf(" Ported to Macintosh by Hans Aberg, compiled " __DATE__ ".\n\n");
192 interpreter(argc,argv);
193 Printf("[Leaving Hugs]\n");
204 /* --------------------------------------------------------------------------
205 * Initialization, interpret command line args and read prelude:
206 * ------------------------------------------------------------------------*/
208 static List /*CONID*/ initialize ( Int argc, String argv[] )
213 setLastEdit((String)0,0);
220 hugsEdit = strCopy(fromEnv("EDITOR",NULL));
222 hugsPath = strCopy(HUGSPATH);
223 readOptions("-p\"%s> \" -r$$");
224 readOptions(fromEnv("STGHUGSFLAGS",""));
228 char exe_name[N_INSTALLDIR + 6];
229 strcpy(exe_name, installDir);
230 strcat(exe_name, "hugs");
231 DEBUG_LoadSymbols(exe_name);
235 /* startupHaskell extracts args between +RTS ... -RTS, and sets
236 prog_argc/prog_argv to the rest. We want to further process
237 the rest, so we then get hold of them again.
239 startupHaskell ( argc, argv, NULL );
240 getProgArgv ( &argc, &argv );
242 /* Find out early on if we're in combined mode or not.
243 everybody(PREPREL) needs to know this. Also, establish the
246 for (i = 1; i < argc; ++i) {
247 if (strcmp(argv[i], "--")==0) break;
248 if (strcmp(argv[i], "-c")==0) combined = FALSE;
249 if (strcmp(argv[i], "+c")==0) combined = TRUE;
251 if (strncmp(argv[i],"+h",2)==0 || strncmp(argv[i],"-h",2)==0)
252 setHeapSize(&(argv[i][2]));
256 initialModules = NIL;
258 for (i = 1; i < argc; ++i) { /* process command line arguments */
259 if (strcmp(argv[i], "--")==0)
260 { argv[i] = NULL; break; }
261 if (argv[i] && argv[i][0]/* workaround for /bin/sh silliness*/) {
262 if (!processOption(argv[i]))
264 = cons ( mkCon(findText(argv[i])), initialModules );
270 Printf("Haskell 98 mode: Restart with command line option -98"
271 " to enable extensions\n");
273 Printf("Hugs mode: Restart with command line option +98 for"
274 " Haskell 98 mode\n");
278 Printf("Combined mode: Restart with command line -c for"
279 " standalone mode\n\n" );
281 Printf("Standalone mode: Restart with command line +c for"
282 " combined mode\n\n" );
285 /* slide args back over the deleted ones. */
287 for (i = 1; i < argc; i++)
293 setProgArgv ( argc, argv );
296 return initialModules;
299 /* --------------------------------------------------------------------------
300 * Command line options:
301 * ------------------------------------------------------------------------*/
303 struct options { /* command line option toggles */
304 char c; /* table defined in main app. */
309 extern struct options toggle[];
311 static Void local toggleSet(c,state) /* Set command line toggle */
315 for (i=0; toggle[i].c; ++i)
316 if (toggle[i].c == c) {
317 *toggle[i].flag = state;
321 ERRMSG(0) "Unknown toggle `%c'", c
325 static Void local togglesIn(state) /* Print current list of toggles in*/
326 Bool state; { /* given state */
329 for (i=0; toggle[i].c; ++i)
330 if (*toggle[i].flag == state && (!haskell98 || toggle[i].h98)) {
332 Putchar((char)(state ? '+' : '-'));
333 Putchar(toggle[i].c);
340 static Void local optionInfo() { /* Print information about command */
341 static String fmts = "%-5s%s\n"; /* line settings */
342 static String fmtc = "%-5c%s\n";
345 Printf("TOGGLES: groups begin with +/- to turn options on/off resp.\n");
346 for (i=0; toggle[i].c; ++i) {
347 if (!haskell98 || toggle[i].h98) {
348 Printf(fmtc,toggle[i].c,toggle[i].description);
352 Printf("\nOTHER OPTIONS: (leading + or - makes no difference)\n");
353 Printf(fmts,"hnum","Set heap size (cannot be changed within Hugs)");
354 Printf(fmts,"pstr","Set prompt string to str");
355 Printf(fmts,"rstr","Set repeat last expression string to str");
356 Printf(fmts,"Pstr","Set search path for modules to str");
357 Printf(fmts,"Estr","Use editor setting given by str");
358 Printf(fmts,"cnum","Set constraint cutoff limit");
359 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
360 Printf(fmts,"Fstr","Set preprocessor filter to str");
363 Printf("\nCurrent settings: ");
366 Printf("-h%d",heapSize);
370 printString(repeatStr);
371 Printf(" -c%d",cutoff);
372 Printf("\nSearch path : -P");
373 printString(hugsPath);
376 if (projectPath!=NULL) {
377 Printf("\nProject Path : %s",projectPath);
380 Printf("\nEditor setting : -E");
381 printString(hugsEdit);
382 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
383 Printf("\nPreprocessor : -F");
384 printString(preprocessor);
386 Printf("\nCompatibility : %s", haskell98 ? "Haskell 98 (+98)"
387 : "Hugs Extensions (-98)");
396 static Void local readOptions(options) /* read options from string */
400 stringInput(options);
401 while ((s=readFilename())!=0) {
402 if (*s && !processOption(s)) {
403 ERRMSG(0) "Option string must begin with `+' or `-'"
410 static Bool local processOption(s) /* process string s for options, */
411 String s; { /* return FALSE if none found. */
423 case 'Q' : break; /* already handled */
425 case 'p' : if (s[1]) {
426 if (prompt) free(prompt);
427 prompt = strCopy(s+1);
431 case 'r' : if (s[1]) {
432 if (repeatStr) free(repeatStr);
433 repeatStr = strCopy(s+1);
438 String p = substPath(s+1,hugsPath ? hugsPath : "");
439 if (hugsPath) free(hugsPath);
444 case 'E' : if (hugsEdit) free(hugsEdit);
445 hugsEdit = strCopy(s+1);
448 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
449 case 'F' : if (preprocessor) free(preprocessor);
450 preprocessor = strCopy(s+1);
454 case 'h' : /* don't do anything, since pre-scan of args
455 will have got it already */
458 case 'c' : /* don't do anything, since pre-scan of args
459 will have got it already */
462 case 'D' : /* hack */
464 extern void setRtsFlags( int x );
465 setRtsFlags(argToInt(s+1));
469 default : if (strcmp("98",s)==0) {
470 if (initDone && ((state && !haskell98) ||
471 (!state && haskell98))) {
473 "Haskell 98 compatibility cannot be changed"
474 " while the interpreter is running\n");
487 static Void local setHeapSize(s)
490 hpSize = argToInt(s);
491 if (hpSize < MINIMUMHEAP)
492 hpSize = MINIMUMHEAP;
493 else if (MAXIMUMHEAP && hpSize > MAXIMUMHEAP)
494 hpSize = MAXIMUMHEAP;
495 if (initDone && hpSize != heapSize) {
496 /* ToDo: should this use a message box in winhugs? */
497 FPrintf(stderr,"You cannot change heap size from inside Hugs\n");
504 static Int local argToInt(s) /* read integer from argument str */
509 if (*s=='\0' || !isascii((int)(*s)) || !isdigit((int)(*s))) {
510 ERRMSG(0) "Missing integer in option setting \"%s\"", t
515 Int d = (*s++) - '0';
516 if (n > ((MAXPOSINT - d)/10)) {
517 ERRMSG(0) "Option setting \"%s\" is too large", t
521 } while (isascii((int)(*s)) && isdigit((int)(*s)));
523 if (*s=='K' || *s=='k') {
524 if (n > (MAXPOSINT/1000)) {
525 ERRMSG(0) "Option setting \"%s\" is too large", t
532 #if MAXPOSINT > 1000000 /* waste of time on 16 bit systems */
533 if (*s=='M' || *s=='m') {
534 if (n > (MAXPOSINT/1000000)) {
535 ERRMSG(0) "Option setting \"%s\" is too large", t
543 #if MAXPOSINT > 1000000000
544 if (*s=='G' || *s=='g') {
545 if (n > (MAXPOSINT/1000000000)) {
546 ERRMSG(0) "Option setting \"%s\" is too large", t
555 ERRMSG(0) "Unwanted characters after option setting \"%s\"", t
562 /* --------------------------------------------------------------------------
563 * Print Menu of list of commands:
564 * ------------------------------------------------------------------------*/
566 static struct cmd cmds[] = {
567 {":?", HELP}, {":cd", CHGDIR}, {":also", ALSO},
568 {":type", TYPEOF}, {":!", SYSTEM}, {":load", LOAD},
569 {":reload", RELOAD}, {":gc", COLLECT}, {":edit", EDIT},
570 {":quit", QUIT}, {":set", SET}, {":find", FIND},
571 {":names", NAMES}, {":info", INFO}, {":project", PROJECT},
573 {":module", SETMODULE},
575 #if EXPLAIN_INSTANCE_RESOLUTION
578 {":version", PNTVER},
583 static Void local menu() {
584 Printf("LIST OF COMMANDS: Any command may be abbreviated to :c where\n");
585 Printf("c is the first character in the full name.\n\n");
586 Printf(":load <filenames> load modules from specified files\n");
587 Printf(":load clear all files except prelude\n");
588 Printf(":also <filenames> read additional modules\n");
589 Printf(":reload repeat last load command\n");
590 Printf(":project <filename> use project file\n");
591 Printf(":edit <filename> edit file\n");
592 Printf(":edit edit last module\n");
593 Printf(":module <module> set module for evaluating expressions\n");
594 Printf("<expr> evaluate expression\n");
595 Printf(":type <expr> print type of expression\n");
596 Printf(":? display this list of commands\n");
597 Printf(":set <options> set command line options\n");
598 Printf(":set help on command line options\n");
599 Printf(":names [pat] list names currently in scope\n");
600 Printf(":info <names> describe named objects\n");
601 Printf(":browse <modules> browse names defined in <modules>\n");
602 #if EXPLAIN_INSTANCE_RESOLUTION
603 Printf(":xplain <context> explain instance resolution for <context>\n");
605 Printf(":find <name> edit module containing definition of name\n");
606 Printf(":!command shell escape\n");
607 Printf(":cd dir change directory\n");
608 Printf(":gc force garbage collection\n");
609 Printf(":version print Hugs version\n");
610 Printf(":dump <name> print STG code for named fn\n");
611 Printf(":quit exit Hugs interpreter\n");
614 static Void local guidance() {
615 Printf("Command not recognised. ");
619 static Void local forHelp() {
620 Printf("Type :? for help\n");
623 /* --------------------------------------------------------------------------
624 * Setting of command line options:
625 * ------------------------------------------------------------------------*/
627 struct options toggle[] = { /* List of command line toggles */
628 {'s', 1, "Print no. reductions/cells after eval", &showStats},
629 {'t', 1, "Print type after evaluation", &addType},
630 {'g', 1, "Print no. cells recovered after gc", &gcMessages},
631 {'l', 1, "Literate modules as default", &literateScripts},
632 {'e', 1, "Warn about errors in literate modules", &literateErrors},
633 {'.', 1, "Print dots to show progress", &useDots},
634 {'q', 1, "Print nothing to show progress", &quiet},
635 {'w', 1, "Always show which modules are loaded", &listScripts},
636 {'k', 1, "Show kind errors in full", &kindExpert},
637 {'o', 0, "Allow overlapping instances", &allowOverlap},
638 {'S', 1, "Debug: show generated SC code", &debugSC},
639 {'a', 1, "Raise exception on assert failure", &flagAssert},
640 #if EXPLAIN_INSTANCE_RESOLUTION
641 {'x', 1, "Explain instance resolution", &showInstRes},
644 {'m', 0, "Use multi instance resolution", &multiInstRes},
649 static Void local set() { /* change command line options from*/
650 String s; /* Hugs command line */
652 if ((s=readFilename())!=0) {
654 if (!processOption(s)) {
655 ERRMSG(0) "Option string must begin with `+' or `-'"
658 } while ((s=readFilename())!=0);
664 /* --------------------------------------------------------------------------
665 * Change directory command:
666 * ------------------------------------------------------------------------*/
668 static Void local changeDir() { /* change directory */
669 String s = readFilename();
671 ERRMSG(0) "Unable to change to directory \"%s\"", s
677 /* --------------------------------------------------------------------------
679 * ------------------------------------------------------------------------*/
681 static jmp_buf catch_error; /* jump buffer for error trapping */
683 HugsBreakAction currentBreakAction = HugsIgnoreBreak;
685 static void handler_IgnoreBreak ( int sig )
687 setHandler ( handler_IgnoreBreak );
690 static void handler_LongjmpOnBreak ( int sig )
692 setHandler ( handler_LongjmpOnBreak );
693 Printf("{Interrupted!}\n");
694 longjmp(catch_error,1);
697 static void handler_RtsInterrupt ( int sig )
699 setHandler ( handler_RtsInterrupt );
703 HugsBreakAction setBreakAction ( HugsBreakAction newAction )
705 HugsBreakAction tmp = currentBreakAction;
706 currentBreakAction = newAction;
708 case HugsIgnoreBreak:
709 setHandler ( handler_IgnoreBreak ); break;
710 case HugsLongjmpOnBreak:
711 setHandler ( handler_LongjmpOnBreak ); break;
712 case HugsRtsInterrupt:
713 setHandler ( handler_RtsInterrupt ); break;
715 internal("setBreakAction");
721 /* --------------------------------------------------------------------------
722 * The new module chaser, loader, etc
723 * ------------------------------------------------------------------------*/
725 List moduleGraph = NIL;
726 List prelModules = NIL;
727 List targetModules = NIL;
729 static String modeToString ( Cell mode )
732 case FM_SOURCE: return "source";
733 case FM_OBJECT: return "object";
734 case FM_EITHER: return "source or object";
735 default: internal("modeToString");
739 static Cell childMode ( Cell modeMeRequest, Cell modeMeActual )
741 assert(modeMeActual == FM_SOURCE ||
742 modeMeActual == FM_OBJECT);
743 assert(modeMeRequest == FM_SOURCE ||
744 modeMeRequest == FM_OBJECT ||
745 modeMeRequest == FM_EITHER);
746 if (modeMeRequest == FM_SOURCE) return modeMeRequest;
747 if (modeMeRequest == FM_OBJECT) return modeMeRequest;
748 if (modeMeActual == FM_OBJECT) return FM_OBJECT;
749 if (modeMeActual == FM_SOURCE) return FM_EITHER;
750 internal("childMode");
753 static Bool compatibleNewMode ( Cell modeNew, Cell modeExisting )
755 if (modeNew == FM_OBJECT && modeExisting == FM_OBJECT) return TRUE;
756 if (modeNew == FM_SOURCE && modeExisting == FM_SOURCE) return TRUE;
757 if (modeNew == FM_EITHER && modeExisting == FM_OBJECT) return TRUE;
758 if (modeNew == FM_EITHER && modeExisting == FM_SOURCE) return TRUE;
762 static void setCurrentFile ( Module mod )
764 assert(isModule(mod));
765 strncpy(currentFileName, textToStr(module(mod).text), 990);
766 strcat(currentFileName, textToStr(module(mod).srcExt));
767 currentFile = currentFileName;
768 moduleBeingParsed = mod;
771 static void clearCurrentFile ( void )
774 moduleBeingParsed = NIL;
777 static void ppMG ( void )
780 for (t = moduleGraph; nonNull(t); t=tl(t)) {
784 FPrintf ( stderr, " %s\n", textToStr(textOf(snd(u))));
787 FPrintf ( stderr, " {" );
788 for (v = snd(u); nonNull(v); v=tl(v))
789 FPrintf ( stderr, "%s ", textToStr(textOf(hd(v))) );
790 FPrintf ( stderr, "}\n" );
799 static Bool elemMG ( ConId mod )
802 for (gs = moduleGraph; nonNull(gs); gs=tl(gs))
803 switch (whatIs(hd(gs))) {
805 if (textOf(mod)==textOf(snd(hd(gs)))) return TRUE;
808 if (varIsMember(textOf(mod),snd(hd(gs)))) return TRUE;
817 static ConId selectArbitrarilyFromGroup ( Cell group )
819 switch (whatIs(group)) {
820 case GRP_NONREC: return snd(group);
821 case GRP_REC: return hd(snd(group));
822 default: internal("selectArbitrarilyFromGroup");
826 static ConId selectLatestMG ( void )
828 List gs = moduleGraph;
829 if (isNull(gs)) internal("selectLatestMG(1)");
830 while (nonNull(gs) && nonNull(tl(gs))) gs = tl(gs);
831 return selectArbitrarilyFromGroup(hd(gs));
835 static List /* of CONID */ listFromSpecifiedMG ( List mg )
839 for (gs = mg; nonNull(gs); gs=tl(gs)) {
840 switch (whatIs(hd(gs))) {
841 case GRP_REC: cs = appendOnto(cs,snd(hd(gs))); break;
842 case GRP_NONREC: cs = cons(snd(hd(gs)),cs); break;
843 default: internal("listFromSpecifiedMG");
849 static List /* of CONID */ listFromMG ( void )
851 return listFromSpecifiedMG ( moduleGraph );
855 /* Calculate the strongly connected components of modgList
856 and assign them to moduleGraph. Uses the .uses field of
857 each of the modules to build the graph structure.
859 #define SCC modScc /* make scc algorithm for StgVars */
860 #define LOWLINK modLowlink
861 #define DEPENDS(t) snd(t)
862 #define SETDEPENDS(c,v) snd(c)=v
869 static void mgFromList ( List /* of CONID */ modgList )
875 List adjList; /* :: [ (Text, [Text]) ] */
881 for (t = modgList; nonNull(t); t=tl(t)) {
883 mod = findModule(mT);
884 assert(nonNull(mod));
886 for (u = module(mod).uses; nonNull(u); u=tl(u))
887 usesT = cons(textOf(hd(u)),usesT);
889 /* artificially give all modules a dependency on Prelude */
890 if (mT != textPrelude && mT != textPrelPrim)
891 usesT = cons(textPrelude,usesT);
892 adjList = cons(pair(mT,usesT),adjList);
895 /* adjList is now [ (module-text, [modules-which-i-import-text]) ].
896 Modify this so that the adjacency list is a list of pointers
897 back to bits of adjList -- that's what modScc needs.
899 for (t = adjList; nonNull(t); t=tl(t)) {
901 /* for each elem of the adjacency list ... */
902 for (u = snd(hd(t)); nonNull(u); u=tl(u)) {
905 /* find the element of adjList whose fst is a */
906 for (v = adjList; nonNull(v); v=tl(v)) {
908 assert(isText(fst(hd(v))));
909 if (fst(hd(v))==a) break;
911 if (isNull(v)) internal("mgFromList");
912 adj = cons(hd(v),adj);
917 adjList = modScc ( adjList );
918 /* adjList is now [ [(module-text, aux-info-field)] ] */
922 for (t = adjList; nonNull(t); t=tl(t)) {
925 /* scc :: [ (module-text, aux-info-field) ] */
926 for (u = scc; nonNull(u); u=tl(u))
927 hd(u) = mkCon(fst(hd(u)));
930 if (length(scc) > 1) {
933 /* singleton module in scc; does it import itself? */
934 mod = findModule ( textOf(hd(scc)) );
935 assert(nonNull(mod));
937 for (u = module(mod).uses; nonNull(u); u=tl(u))
938 if (textOf(hd(u))==textOf(hd(scc)))
943 moduleGraph = cons( ap(GRP_REC,scc), moduleGraph ); else
944 moduleGraph = cons( ap(GRP_NONREC,hd(scc)), moduleGraph );
946 moduleGraph = reverse(moduleGraph);
950 static List /* of CONID */ getModuleImports ( Cell tree )
956 for (tes = zthd3(unap(M_MODULE,tree)); nonNull(tes); tes=tl(tes)) {
960 use = zfst(unap(M_IMPORT_Q,te));
962 if (!varIsMember(textOf(use),uses)) uses = cons ( use, uses );
965 use = zfst(unap(M_IMPORT_UNQ,te));
967 if (!varIsMember(textOf(use),uses)) uses = cons ( use, uses );
977 static void processModule ( Module m )
994 foreignImports = NIL;
995 foreignExports = NIL;
1002 tree = unap(M_MODULE,module(m).tree);
1003 modNm = zfst3(tree);
1005 if (textOf(modNm) != module(m).text) {
1006 ERRMSG(0) "Module name \"%s\" does not match file name \"%s%s\"",
1007 textToStr(textOf(modNm)),
1008 textToStr(module(m).text),
1009 textToStr(module(m).srcExt)
1013 setExportList(zsnd3(tree));
1014 topEnts = zthd3(tree);
1016 for (tes = topEnts; nonNull(tes); tes=tl(tes)) {
1018 assert(isGenPair(te));
1020 switch(whatIs(te)) {
1022 addQualImport(zfst(te2),zsnd(te2));
1025 addUnqualImport(zfst(te2),zsnd(te2));
1028 tyconDefn(intOf(zsel14(te2)),zsel24(te2),zsel34(te2),zsel44(te2));
1031 classDefn(intOf(zsel14(te2)),zsel24(te2),zsel34(te2),zsel44(te2));
1034 instDefn(intOf(zfst3(te2)),zsnd3(te2),zthd3(te2));
1037 defaultDefn(intOf(zfst(te2)),zsnd(te2));
1040 foreignImport(intOf(zsel15(te2)),zsel25(te2),zsel35(te2),
1041 zsel45(te2),zsel55(te2));
1044 foreignExport(intOf(zsel15(te2)),zsel25(te2),zsel35(te2),
1045 zsel45(te2),zsel55(te2));
1047 valDefns = cons(te2,valDefns);
1050 internal("processModule");
1059 static Module parseModuleOrInterface ( ConId mc, Cell modeRequest )
1061 /* Allocate a module-table entry. */
1062 /* Parse the entity and fill in the .tree and .uses entries. */
1065 Bool sAvail; Time sTime; Long sSize;
1066 Bool oiAvail; Time oiTime; Long oSize; Long iSize;
1071 Text mt = textOf(mc);
1072 Module mod = findModule ( mt );
1074 /* fprintf ( stderr, "parseModuleOrInterface `%s' == %d\n",
1075 textToStr(mt),mod); */
1076 if (nonNull(mod) && !module(mod).fake)
1077 internal("parseModuleOrInterface");
1079 module(mod).fake = FALSE;
1082 mod = newModule(mt);
1084 /* This call malloc-ates path; we should deallocate it. */
1085 ok = findFilesForModule (
1086 textToStr(module(mod).text),
1089 &sAvail, &sTime, &sSize,
1090 &oiAvail, &oiTime, &oSize, &iSize
1093 if (!ok) goto cant_find;
1094 if (!sAvail && !oiAvail) goto cant_find;
1096 /* Find out whether to use source or object. */
1097 switch (modeRequest) {
1099 if (!sAvail) goto cant_find;
1103 if (!oiAvail) goto cant_find;
1107 if ( sAvail && !oiAvail) { useSource = TRUE; break; }
1108 if (!sAvail && oiAvail) { useSource = FALSE; break; }
1109 useSource = firstTimeIsLater ( sTime, oiTime ) ? TRUE : FALSE;
1112 internal("parseModuleOrInterface");
1115 /* Actually do the parsing. */
1117 module(mod).srcExt = findText(sExt);
1118 setCurrentFile(mod);
1120 strcat(name, textToStr(mt));
1122 module(mod).tree = parseModule(name,sSize);
1123 module(mod).uses = getModuleImports(module(mod).tree);
1124 module(mod).mode = FM_SOURCE;
1125 module(mod).lastStamp = sTime;
1127 module(mod).srcExt = findText(HI_ENDING);
1128 setCurrentFile(mod);
1130 strcat(name, textToStr(mt));
1131 strcat(name, DLL_ENDING);
1132 module(mod).objName = findText(name);
1133 module(mod).objSize = oSize;
1135 strcat(name, textToStr(mt));
1136 strcat(name, ".u_hi");
1137 module(mod).tree = parseInterface(name,iSize);
1138 module(mod).uses = getInterfaceImports(module(mod).tree);
1139 module(mod).mode = FM_OBJECT;
1140 module(mod).lastStamp = oiTime;
1143 if (path) free(path);
1147 if (path) free(path);
1150 "Can't find %s for module \"%s\"",
1151 modeToString(modeRequest), textToStr(mt)
1156 static void tryLoadGroup ( Cell grp )
1160 switch (whatIs(grp)) {
1162 m = findModule(textOf(snd(grp)));
1164 if (module(m).mode == FM_SOURCE) {
1165 processModule ( m );
1166 module(m).tree = NIL;
1168 processInterfaces ( singleton(snd(grp)) );
1169 m = findModule(textOf(snd(grp)));
1171 module(m).tree = NIL;
1175 for (t = snd(grp); nonNull(t); t=tl(t)) {
1176 m = findModule(textOf(hd(t)));
1178 if (module(m).mode == FM_SOURCE) {
1179 ERRMSG(0) "Source module \"%s\" imports itself recursively",
1180 textToStr(textOf(hd(t)))
1184 processInterfaces ( snd(grp) );
1185 for (t = snd(grp); nonNull(t); t=tl(t)) {
1186 m = findModule(textOf(hd(t)));
1188 module(m).tree = NIL;
1192 internal("tryLoadGroup");
1197 static void fallBackToPrelModules ( void )
1200 for (m = MODULE_BASE_ADDR;
1201 m < MODULE_BASE_ADDR+tabModuleSz; m++)
1203 && !varIsMember(module(m).text, prelModules))
1208 /* This function catches exceptions in most of the system.
1209 So it's only ok for procedures called from this one
1210 to do EENDs (ie, write error messages). Others should use
1213 static void achieveTargetModules ( Bool loadingThePrelude )
1216 volatile List modgList;
1218 volatile Module mod;
1223 Bool sAvail; Time sTime; Long sSize;
1224 Bool oiAvail; Time oiTime; Long oSize; Long iSize;
1226 volatile Time oisTime;
1227 volatile Bool out_of_date;
1228 volatile List ood_new;
1230 volatile List modgList_new;
1231 volatile List parsedButNotLoaded;
1232 volatile List toChase;
1233 volatile List trans_cl;
1234 volatile List trans_cl_new;
1239 volatile List badMods;
1241 setBreakAction ( HugsIgnoreBreak );
1243 /* First, examine timestamps to find out which modules are
1244 out of date with respect to the source/interface/object files.
1247 modgList = listFromMG();
1249 for (t = modgList; nonNull(t); t=tl(t)) {
1251 if (varIsMember(textOf(hd(t)),prelModules))
1254 mod = findModule(textOf(hd(t)));
1255 if (isNull(mod)) internal("achieveTargetSet(1)");
1257 /* In standalone mode, only succeeds for source modules. */
1258 ok = findFilesForModule (
1259 textToStr(module(mod).text),
1262 &sAvail, &sTime, &sSize,
1263 &oiAvail, &oiTime, &oSize, &iSize
1266 if (!combined && !sAvail) ok = FALSE;
1268 fallBackToPrelModules();
1270 "Can't find source or object+interface for module \"%s\"",
1271 textToStr(module(mod).text)
1273 if (path) free(path);
1277 if (sAvail && oiAvail) {
1278 oisTime = whicheverIsLater(sTime,oiTime);
1280 else if (sAvail && !oiAvail) {
1283 else if (!sAvail && oiAvail) {
1287 internal("achieveTargetSet(2)");
1290 out_of_date = firstTimeIsLater(oisTime,module(mod).lastStamp);
1292 assert(!varIsMember(textOf(hd(t)),ood));
1293 ood = cons(hd(t),ood);
1296 if (path) { free(path); path = NULL; };
1299 /* Second, form a simplistic transitive closure of the out-of-date
1300 modules: a module is out of date if it imports an out-of-date
1305 for (t = modgList; nonNull(t); t=tl(t)) {
1306 mod = findModule(textOf(hd(t)));
1307 assert(nonNull(mod));
1308 for (us = module(mod).uses; nonNull(us); us=tl(us))
1309 if (varIsMember(textOf(hd(us)),ood))
1312 if (varIsMember(textOf(hd(t)),prelModules))
1313 Printf ( "warning: prelude module \"%s\" is out-of-date\n",
1314 textToStr(textOf(hd(t))) );
1316 if (!varIsMember(textOf(hd(t)),ood_new) &&
1317 !varIsMember(textOf(hd(t)),ood))
1318 ood_new = cons(hd(t),ood_new);
1321 if (isNull(ood_new)) break;
1322 ood = appendOnto(ood_new,ood);
1325 /* Now ood holds the entire set of modules which are out-of-date.
1326 Throw them out of the system, yielding a "reduced system",
1327 in which the remaining modules are in-date.
1329 for (t = ood; nonNull(t); t=tl(t)) {
1330 mod = findModule(textOf(hd(t)));
1331 assert(nonNull(mod));
1335 for (t = modgList; nonNull(t); t=tl(t))
1336 if (!varIsMember(textOf(hd(t)),ood))
1337 modgList_new = cons(hd(t),modgList_new);
1338 modgList = modgList_new;
1340 /* Update the module group list to reflect the reduced system.
1341 We do this so that if the following parsing phases fail, we can
1342 safely fall back to the reduced system.
1344 mgFromList ( modgList );
1346 /* Parse modules/interfaces, collecting parse trees and chasing
1347 imports, starting from the target set.
1349 toChase = dupList(targetModules);
1350 for (t = toChase; nonNull(t); t=tl(t)) {
1351 Cell mode = (!combined)
1353 : ( (loadingThePrelude && combined)
1356 hd(t) = zpair(hd(t), mode);
1359 /* toChase :: [ ((ConId, {FM_SOURCE|FM_OBJECT|FM_EITHER} )) ] */
1361 parsedButNotLoaded = NIL;
1364 while (nonNull(toChase)) {
1365 ConId mc = zfst(hd(toChase));
1366 Cell mode = zsnd(hd(toChase));
1367 toChase = tl(toChase);
1368 if (varIsMember(textOf(mc),modgList)
1369 || varIsMember(textOf(mc),parsedButNotLoaded)) {
1370 /* either exists fully, or is at least parsed */
1371 mod = findModule(textOf(mc));
1372 assert(nonNull(mod));
1373 if (!compatibleNewMode(mode,module(mod).mode)) {
1376 "module %s: %s required, but %s is more recent",
1377 textToStr(textOf(mc)), modeToString(mode),
1378 modeToString(module(mod).mode)
1380 goto parseException;
1384 setBreakAction ( HugsLongjmpOnBreak );
1385 if (setjmp(catch_error)==0) {
1386 /* try this; it may throw an exception */
1387 mod = parseModuleOrInterface ( mc, mode );
1389 /* here's the exception handler, if parsing fails */
1390 /* A parse error (or similar). Clean up and abort. */
1392 setBreakAction ( HugsIgnoreBreak );
1393 mod = findModule(textOf(mc));
1394 if (nonNull(mod)) nukeModule(mod);
1395 for (t = parsedButNotLoaded; nonNull(t); t=tl(t)) {
1396 mod = findModule(textOf(hd(t)));
1397 assert(nonNull(mod));
1398 if (nonNull(mod)) nukeModule(mod);
1401 /* end of the exception handler */
1403 setBreakAction ( HugsIgnoreBreak );
1405 parsedButNotLoaded = cons(mc, parsedButNotLoaded);
1406 for (t = module(mod).uses; nonNull(t); t=tl(t))
1408 zpair( hd(t), childMode(mode,module(mod).mode) ),
1413 modgList = dupOnto(parsedButNotLoaded, modgList);
1415 /* We successfully parsed all modules reachable from the target
1416 set which were not part of the reduced system. However, there
1417 may be modules in the reduced system which are not reachable from
1418 the target set. We detect these now by building the transitive
1419 closure of the target set, and nuking modules in the reduced
1420 system which are not part of that closure.
1422 trans_cl = dupList(targetModules);
1425 for (t = trans_cl; nonNull(t); t=tl(t)) {
1426 mod = findModule(textOf(hd(t)));
1427 assert(nonNull(mod));
1428 for (u = module(mod).uses; nonNull(u); u=tl(u))
1429 if (!varIsMember(textOf(hd(u)),trans_cl)
1430 && !varIsMember(textOf(hd(u)),trans_cl_new)
1431 && !varIsMember(textOf(hd(u)),prelModules))
1432 trans_cl_new = cons(hd(u),trans_cl_new);
1434 if (isNull(trans_cl_new)) break;
1435 trans_cl = appendOnto(trans_cl_new,trans_cl);
1438 for (t = modgList; nonNull(t); t=tl(t)) {
1439 if (varIsMember(textOf(hd(t)),trans_cl)) {
1440 modgList_new = cons(hd(t),modgList_new);
1442 mod = findModule(textOf(hd(t)));
1443 assert(nonNull(mod));
1447 modgList = modgList_new;
1449 /* Now, the module symbol tables hold exactly the set of
1450 modules reachable from the target set, and modgList holds
1451 their names. Calculate the scc-ified module graph,
1452 since we need that to guide the next stage, that of
1453 Actually Loading the modules.
1455 If no errors occur, moduleGraph will reflect the final graph
1456 loaded. If an error occurs loading a group, we nuke
1457 that group, truncate the moduleGraph just prior to that
1458 group, and exit. That leaves the system having successfully
1459 loaded all groups prior to the one which failed.
1461 mgFromList ( modgList );
1463 for (mg = moduleGraph; nonNull(mg); mg=tl(mg)) {
1466 if (!varIsMember(textOf(selectArbitrarilyFromGroup(grp)),
1467 parsedButNotLoaded)) continue;
1469 setBreakAction ( HugsLongjmpOnBreak );
1470 if (setjmp(catch_error)==0) {
1471 /* try this; it may throw an exception */
1474 /* here's the exception handler, if static/typecheck etc fails */
1475 /* nuke the entire rest (ie, the unloaded part)
1476 of the module graph */
1477 setBreakAction ( HugsIgnoreBreak );
1478 badMods = listFromSpecifiedMG ( mg );
1479 for (t = badMods; nonNull(t); t=tl(t)) {
1480 mod = findModule(textOf(hd(t)));
1481 if (nonNull(mod)) nukeModule(mod);
1483 /* truncate the module graph just prior to this group. */
1487 if (isNull(mg)) break;
1488 if (hd(mg) == grp) break;
1489 mg2 = cons ( hd(mg), mg2 );
1492 moduleGraph = reverse(mg2);
1494 /* end of the exception handler */
1496 setBreakAction ( HugsIgnoreBreak );
1499 /* Err .. I think that's it. If we get here, we've successfully
1500 achieved the target set. Phew!
1502 setBreakAction ( HugsIgnoreBreak );
1506 static Bool loadThePrelude ( void )
1511 moduleGraph = prelModules = NIL;
1514 conPrelude = mkCon(findText("Prelude"));
1515 conPrelHugs = mkCon(findText("PrelHugs"));
1516 targetModules = doubleton(conPrelude,conPrelHugs);
1517 achieveTargetModules(TRUE);
1518 ok = elemMG(conPrelude) && elemMG(conPrelHugs);
1520 conPrelude = mkCon(findText("Prelude"));
1521 targetModules = singleton(conPrelude);
1522 achieveTargetModules(TRUE);
1523 ok = elemMG(conPrelude);
1526 if (ok) prelModules = listFromMG();
1531 /* Refresh the current target modules, and attempt to set the
1532 current module to what it was before (ie currentModule):
1533 if currentModule_failed is different from currentModule,
1535 if nextCurrMod is non null, try to set it to that instead
1536 if the one we're after insn't available, select a target
1537 from the end of the module group list.
1539 static void refreshActions ( ConId nextCurrMod, Bool cleanAfter )
1544 /* Remember what the old current module was. */
1545 tryFor = mkCon(module(currentModule).text);
1547 /* Do the Real Work. */
1548 achieveTargetModules(FALSE);
1550 /* Remember if the current module was invalidated by this
1551 refresh, so later refreshes can attempt to reload it. */
1552 if (!elemMG(tryFor))
1553 currentModule_failed = tryFor;
1555 /* If a previous refresh failed to get an old current module,
1556 try for that instead. */
1557 if (nonNull(currentModule_failed)
1558 && textOf(currentModule_failed) != textOf(tryFor)
1559 && elemMG(currentModule_failed))
1560 tryFor = currentModule_failed;
1561 /* If our caller specified a new current module, that overrides
1562 all historical settings. */
1563 if (nonNull(nextCurrMod))
1564 tryFor = nextCurrMod;
1565 /* Finally, if we can't actually get hold of whatever it was we
1566 were after, select something which is possible. */
1567 if (!elemMG(tryFor))
1568 tryFor = selectLatestMG();
1570 /* combined mode kludge, to get Prelude rather than PrelHugs */
1571 if (combined && textOf(tryFor)==findText("PrelHugs"))
1572 tryFor = mkCon(findText("Prelude"));
1575 /* delete any targetModules which didn't actually get loaded */
1577 targetModules = NIL;
1578 for (; nonNull(t); t=tl(t))
1580 targetModules = cons(hd(t),targetModules);
1583 setCurrModule ( findModule(textOf(tryFor)) );
1584 Printf("Hugs session for:\n");
1589 static void addActions ( List extraModules /* :: [CONID] */ )
1592 for (t = extraModules; nonNull(t); t=tl(t)) {
1593 ConId extra = hd(t);
1594 if (!varIsMember(textOf(extra),targetModules))
1595 targetModules = cons(extra,targetModules);
1597 refreshActions ( isNull(extraModules)
1599 : hd(reverse(extraModules)),
1605 static void loadActions ( List loadModules /* :: [CONID] */ )
1608 targetModules = dupList ( prelModules );
1610 for (t = loadModules; nonNull(t); t=tl(t)) {
1612 if (!varIsMember(textOf(load),targetModules))
1613 targetModules = cons(load,targetModules);
1615 refreshActions ( isNull(loadModules)
1617 : hd(reverse(loadModules)),
1623 /* --------------------------------------------------------------------------
1624 * Access to external editor:
1625 * ------------------------------------------------------------------------*/
1627 /* ToDo: All this editor stuff needs fixing. */
1629 static Void local editor() { /* interpreter-editor interface */
1631 String newFile = readFilename();
1633 setLastEdit(newFile,0);
1634 if (readFilename()) {
1635 ERRMSG(0) "Multiple filenames not permitted"
1643 static Void local find() { /* edit file containing definition */
1646 String nm = readFilename(); /* of specified name */
1648 ERRMSG(0) "No name specified"
1651 else if (readFilename()) {
1652 ERRMSG(0) "Multiple names not permitted"
1658 setCurrModule(findEvalModule());
1660 if (nonNull(c=findTycon(t=findText(nm)))) {
1661 if (startEdit(tycon(c).line,scriptName[scriptThisTycon(c)])) {
1662 readScripts(N_PRELUDE_SCRIPTS);
1664 } else if (nonNull(c=findName(t))) {
1665 if (startEdit(name(c).line,scriptName[scriptThisName(c)])) {
1666 readScripts(N_PRELUDE_SCRIPTS);
1669 ERRMSG(0) "No current definition for name \"%s\"", nm
1676 static Void local runEditor() { /* run editor on script lastEdit */
1678 if (startEdit(lastEdLine,lastEdit)) /* at line lastEdLine */
1679 readScripts(N_PRELUDE_SCRIPTS);
1683 static Void local setLastEdit(fname,line)/* keep name of last file to edit */
1689 lastEdit = strCopy(fname);
1694 /* --------------------------------------------------------------------------
1695 * Read and evaluate an expression:
1696 * ------------------------------------------------------------------------*/
1698 static Void setModule ( void ) {
1699 /*set module in which to evaluate expressions*/
1702 String s = readFilename();
1704 mc = selectLatestMG();
1705 if (combined && textOf(mc)==findText("PrelHugs"))
1706 mc = mkCon(findText("Prelude"));
1707 m = findModule(textOf(mc));
1710 m = findModule(findText(s));
1712 ERRMSG(0) "Cannot find module \"%s\"", s
1720 static Module allocEvalModule ( void )
1722 Module evalMod = newModule( findText("_Eval_Module_") );
1723 module(evalMod).names = module(currentModule).names;
1724 module(evalMod).tycons = module(currentModule).tycons;
1725 module(evalMod).classes = module(currentModule).classes;
1726 module(evalMod).qualImports
1727 = singleton(pair(mkCon(textPrelude),modulePrelude));
1731 static Void local evaluator() { /* evaluate expr and print value */
1734 volatile Kinds ks = NIL;
1735 volatile Module evalMod = allocEvalModule();
1736 volatile Module currMod = currentModule;
1737 setCurrModule(evalMod);
1740 defaultDefns = combined ? stdDefaults : evalDefaults;
1742 setBreakAction ( HugsLongjmpOnBreak );
1743 if (setjmp(catch_error)==0) {
1747 type = typeCheckExp(TRUE);
1749 /* if an exception happens, we arrive here */
1750 setBreakAction ( HugsIgnoreBreak );
1751 goto cleanup_and_return;
1754 setBreakAction ( HugsIgnoreBreak );
1755 if (isPolyType(type)) {
1756 ks = polySigOf(type);
1757 bd = monotypeOf(type);
1762 if (whatIs(bd)==QUAL) {
1765 ERRMSG(0) "Unresolved overloading" ETHEN
1766 ERRTEXT "\n*** Type : " ETHEN ERRTYPE(type);
1767 ERRTEXT "\n*** Expression : " ETHEN ERREXPR(inputExpr);
1770 goto cleanup_and_return;
1776 if (isProgType(ks,bd)) {
1777 inputExpr = ap(nameRunIO_toplevel,inputExpr);
1781 Cell d = provePred(ks,NIL,ap(classShow,bd));
1785 ERRMSG(0) "Cannot find \"show\" function for:" ETHEN
1786 ERRTEXT "\n*** expression : " ETHEN ERREXPR(inputExpr);
1787 ERRTEXT "\n*** of type : " ETHEN ERRTYPE(type);
1790 goto cleanup_and_return;
1792 inputExpr = ap2(nameShow, d,inputExpr);
1793 inputExpr = ap (namePutStr, inputExpr);
1794 inputExpr = ap (nameRunIO_toplevel, inputExpr);
1796 evalExp(); printf("\n");
1799 printType(stdout,type);
1806 printf ( "result type is " );
1807 printType ( stdout, type );
1815 setBreakAction ( HugsIgnoreBreak );
1816 nukeModule(evalMod);
1817 setCurrModule(currMod);
1818 setCurrentFile(currMod);
1824 /* --------------------------------------------------------------------------
1825 * Print type of input expression:
1826 * ------------------------------------------------------------------------*/
1828 static Void showtype ( void ) { /* print type of expression (if any)*/
1831 volatile Module evalMod = allocEvalModule();
1832 volatile Module currMod = currentModule;
1833 setCurrModule(evalMod);
1835 if (setjmp(catch_error)==0) {
1839 defaultDefns = evalDefaults;
1840 type = typeCheckExp(FALSE);
1841 printExp(stdout,inputExpr);
1843 printType(stdout,type);
1846 /* if an exception happens, we arrive here */
1849 nukeModule(evalMod);
1850 setCurrModule(currMod);
1854 static Void local browseit(mod,t,all)
1861 Printf("module %s where\n",textToStr(module(mod).text));
1862 for (cs = module(mod).names; nonNull(cs); cs=tl(cs)) {
1864 /* only look at things defined in this module,
1865 unless `all' flag is set */
1866 if (all || name(nm).mod == mod) {
1867 /* unwanted artifacts, like lambda lifted values,
1868 are in the list of names, but have no types */
1869 if (nonNull(name(nm).type)) {
1870 printExp(stdout,nm);
1872 printType(stdout,name(nm).type);
1874 Printf(" -- data constructor");
1875 } else if (isMfun(nm)) {
1876 Printf(" -- class member");
1877 } else if (isSfun(nm)) {
1878 Printf(" -- selector function");
1886 Printf("Unknown module %s\n",t);
1891 static Void local browse() { /* browse modules */
1892 Int count = 0; /* or give menu of commands */
1896 for (; (s=readFilename())!=0; count++)
1897 if (strcmp(s,"all") == 0) {
1901 browseit(findModule(findText(s)),s,all);
1903 browseit(currentModule,NULL,all);
1907 #if EXPLAIN_INSTANCE_RESOLUTION
1908 static Void local xplain() { /* print type of expression (if any)*/
1910 Bool sir = showInstRes;
1912 setCurrModule(findEvalModule());
1913 startNewScript(0); /* Enables recovery of storage */
1914 /* allocated during evaluation */
1918 d = provePred(NIL,NIL,hd(inputContext));
1920 fprintf(stdout, "not Sat\n");
1922 fprintf(stdout, "Sat\n");
1928 /* --------------------------------------------------------------------------
1929 * Enhanced help system: print current list of scripts or give information
1931 * ------------------------------------------------------------------------*/
1933 static String local objToStr(m,c)
1936 #if 1 || DISPLAY_QUANTIFIERS
1937 static char newVar[60];
1938 switch (whatIs(c)) {
1939 case NAME : if (m == name(c).mod) {
1940 sprintf(newVar,"%s", textToStr(name(c).text));
1942 sprintf(newVar,"%s.%s",
1943 textToStr(module(name(c).mod).text),
1944 textToStr(name(c).text));
1948 case TYCON : if (m == tycon(c).mod) {
1949 sprintf(newVar,"%s", textToStr(tycon(c).text));
1951 sprintf(newVar,"%s.%s",
1952 textToStr(module(tycon(c).mod).text),
1953 textToStr(tycon(c).text));
1957 case CLASS : if (m == cclass(c).mod) {
1958 sprintf(newVar,"%s", textToStr(cclass(c).text));
1960 sprintf(newVar,"%s.%s",
1961 textToStr(module(cclass(c).mod).text),
1962 textToStr(cclass(c).text));
1966 default : internal("objToStr");
1970 static char newVar[33];
1971 switch (whatIs(c)) {
1972 case NAME : sprintf(newVar,"%s", textToStr(name(c).text));
1975 case TYCON : sprintf(newVar,"%s", textToStr(tycon(c).text));
1978 case CLASS : sprintf(newVar,"%s", textToStr(cclass(c).text));
1981 default : internal("objToStr");
1989 static Void dumpStg ( void )
1995 setCurrModule(findEvalModule());
2000 /* request to locate a symbol by name */
2001 if (s && (*s == '?')) {
2002 Text t = findText(s+1);
2003 locateSymbolByName(t);
2007 /* request to dump a bit of the heap */
2008 if (s && (*s == '-' || isdigit(*s))) {
2015 /* request to dump a symbol table entry */
2017 || !(*s == 't' || *s == 'n' || *s == 'c' || *s == 'i')
2018 || !isdigit(s[1])) {
2019 fprintf(stderr, ":d -- bad request `%s'\n", s );
2024 case 't': dumpTycon(i); break;
2025 case 'n': dumpName(i); break;
2026 case 'c': dumpClass(i); break;
2027 case 'i': dumpInst(i); break;
2028 default: fprintf(stderr, ":d -- `%c' not implemented\n", *s );
2034 static Void local dumpStg( void ) { /* print STG stuff */
2039 Cell v; /* really StgVar */
2040 setCurrModule(findEvalModule());
2042 for (; (s=readFilename())!=0;) {
2045 /* find the name while ignoring module scopes */
2046 for (i=NAMEMIN; i<nameHw; i++)
2047 if (name(i).text == t) n = i;
2049 /* perhaps it's an "idNNNNNN" thing? */
2052 s[0]=='i' && s[1]=='d' && isdigit(s[2])) {
2055 while (isdigit(s[i])) {
2056 v = v * 10 + (s[i]-'0');
2060 n = nameFromStgVar(v);
2063 if (isNull(n) && whatIs(v)==STGVAR) {
2064 Printf ( "\n{- `%s' has no nametable entry -}\n", s );
2065 printStg(stderr, v );
2068 Printf ( "Unknown reference `%s'\n", s );
2071 Printf ( "Not a Name: `%s'\n", s );
2073 if (isNull(name(n).stgVar)) {
2074 Printf ( "Doesn't have a STG tree: %s\n", s );
2076 Printf ( "\n{- stgVar of `%s' is id%d -}\n", s, -name(n).stgVar);
2077 printStg(stderr, name(n).stgVar);
2083 static Void local info() { /* describe objects */
2084 Int count = 0; /* or give menu of commands */
2087 for (; (s=readFilename())!=0; count++) {
2088 describe(findText(s));
2091 /* whatScripts(); */
2096 static Void local describe(t) /* describe an object */
2098 Tycon tc = findTycon(t);
2099 Class cl = findClass(t);
2100 Name nm = findName(t);
2102 if (nonNull(tc)) { /* as a type constructor */
2106 for (i=0; i<tycon(tc).arity; ++i) {
2107 t = ap(t,mkOffset(i));
2109 Printf("-- type constructor");
2111 Printf(" with kind ");
2112 printKind(stdout,tycon(tc).kind);
2115 switch (tycon(tc).what) {
2116 case SYNONYM : Printf("type ");
2117 printType(stdout,t);
2119 printType(stdout,tycon(tc).defn);
2123 case DATATYPE : { List cs = tycon(tc).defn;
2124 if (tycon(tc).what==DATATYPE) {
2129 printType(stdout,t);
2131 mapProc(printSyntax,cs);
2133 Printf("\n-- constructors:");
2135 for (; hasCfun(cs); cs=tl(cs)) {
2137 printExp(stdout,hd(cs));
2139 printType(stdout,name(hd(cs)).type);
2142 Printf("\n-- selectors:");
2144 for (; nonNull(cs); cs=tl(cs)) {
2146 printExp(stdout,hd(cs));
2148 printType(stdout,name(hd(cs)).type);
2153 case RESTRICTSYN : Printf("type ");
2154 printType(stdout,t);
2155 Printf(" = <restricted>");
2159 if (nonNull(in=findFirstInst(tc))) {
2160 Printf("\n-- instances:\n");
2163 in = findNextInst(tc,in);
2164 } while (nonNull(in));
2169 if (nonNull(cl)) { /* as a class */
2170 List ins = cclass(cl).instances;
2171 Kinds ks = cclass(cl).kinds;
2172 if (nonNull(ks) && isNull(tl(ks)) && hd(ks)==STAR) {
2173 Printf("-- type class");
2175 Printf("-- constructor class");
2177 Printf(" with arity ");
2178 printKinds(stdout,ks);
2182 mapProc(printSyntax,cclass(cl).members);
2184 if (nonNull(cclass(cl).supers)) {
2185 printContext(stdout,cclass(cl).supers);
2188 printPred(stdout,cclass(cl).head);
2190 if (nonNull(cclass(cl).fds)) {
2191 List fds = cclass(cl).fds;
2193 for (; nonNull(fds); fds=tl(fds)) {
2195 printFD(stdout,hd(fds));
2200 if (nonNull(cclass(cl).members)) {
2201 List ms = cclass(cl).members;
2204 Type t = name(hd(ms)).type;
2205 if (isPolyType(t)) {
2209 printExp(stdout,hd(ms));
2211 if (isNull(tl(fst(snd(t))))) {
2214 t = ap(QUAL,pair(tl(fst(snd(t))),snd(snd(t))));
2216 printType(stdout,t);
2218 } while (nonNull(ms));
2222 Printf("\n-- instances:\n");
2226 } while (nonNull(ins));
2231 if (nonNull(nm)) { /* as a function/name */
2233 printExp(stdout,nm);
2235 if (nonNull(name(nm).type)) {
2236 printType(stdout,name(nm).type);
2238 Printf("<unknown type>");
2241 Printf(" -- data constructor");
2242 } else if (isMfun(nm)) {
2243 Printf(" -- class member");
2244 } else if (isSfun(nm)) {
2245 Printf(" -- selector function");
2251 if (isNull(tc) && isNull(cl) && isNull(nm)) {
2252 Printf("Unknown reference `%s'\n",textToStr(t));
2256 static Void local printSyntax(nm)
2258 Syntax sy = syntaxOf(nm);
2259 Text t = name(nm).text;
2260 String s = textToStr(t);
2261 if (sy != defaultSyntax(t)) {
2263 switch (assocOf(sy)) {
2264 case LEFT_ASS : Putchar('l'); break;
2265 case RIGHT_ASS : Putchar('r'); break;
2266 case NON_ASS : break;
2268 Printf(" %i ",precOf(sy));
2269 if (isascii((int)(*s)) && isalpha((int)(*s))) {
2278 static Void local showInst(in) /* Display instance decl header */
2280 Printf("instance ");
2281 if (nonNull(inst(in).specifics)) {
2282 printContext(stdout,inst(in).specifics);
2285 printPred(stdout,inst(in).head);
2289 /* --------------------------------------------------------------------------
2290 * List all names currently in scope:
2291 * ------------------------------------------------------------------------*/
2293 static Void local listNames() { /* list names matching optional pat*/
2294 String pat = readFilename();
2296 Int width = getTerminalWidth() - 1;
2299 Module mod = currentModule;
2301 if (pat) { /* First gather names to list */
2303 names = addNamesMatching(pat,names);
2304 } while ((pat=readFilename())!=0);
2306 names = addNamesMatching((String)0,names);
2308 if (isNull(names)) { /* Then print them out */
2310 ERRMSG(0) "No names selected"
2314 for (termPos=0; nonNull(names); names=tl(names)) {
2315 String s = objToStr(mod,hd(names));
2317 if (termPos+1+l>width) {
2320 } else if (termPos>0) {
2328 Printf("\n(%d names listed)\n", count);
2331 /* --------------------------------------------------------------------------
2332 * print a prompt and read a line of input:
2333 * ------------------------------------------------------------------------*/
2335 static Void local promptForInput(moduleName)
2336 String moduleName; {
2337 char promptBuffer[1000];
2339 /* This is portable but could overflow buffer */
2340 sprintf(promptBuffer,prompt,moduleName);
2342 /* Works on ANSI C - but pre-ANSI compilers return a pointer to
2343 * promptBuffer instead.
2345 if (sprintf(promptBuffer,prompt,moduleName) >= 1000) {
2346 /* Reset prompt to a safe default to avoid an infinite loop */
2348 prompt = strCopy("? ");
2349 internal("Combined prompt and evaluation module name too long");
2353 stringInput("main\0"); else
2354 consoleInput(promptBuffer);
2357 /* --------------------------------------------------------------------------
2358 * main read-eval-print loop, with error trapping:
2359 * ------------------------------------------------------------------------*/
2361 static Void local interpreter(argc,argv)/* main interpreter loop */
2365 List modConIds; /* :: [CONID] */
2369 setBreakAction ( HugsIgnoreBreak );
2370 modConIds = initialize(argc,argv); /* the initial modules to load */
2371 setBreakAction ( HugsIgnoreBreak );
2372 prelOK = loadThePrelude();
2376 fprintf(stderr, "hugs +Q: fatal error: can't load the Prelude.\n" );
2378 fprintf(stderr, "hugs: fatal error: can't load the Prelude.\n" );
2382 if (combined) everybody(POSTPREL);
2383 loadActions(modConIds);
2386 for (; nonNull(modConIds); modConIds=tl(modConIds))
2387 if (!elemMG(hd(modConIds))) {
2389 "hugs +Q: compilation failed -- can't run `main'\n" );
2396 /* initialize calls startupHaskell, which trashes our signal handlers */
2397 setBreakAction ( HugsIgnoreBreak );
2402 everybody(RESET); /* reset to sensible initial state */
2404 promptForInput(textToStr(module(currentModule).text));
2406 cmd = readCommand(cmds, (Char)':', (Char)'!');
2408 case EDIT : editor();
2412 case LOAD : modConIds = NIL;
2413 while ((s=readFilename())!=0) {
2414 modConIds = cons(mkCon(findText(s)),modConIds);
2417 loadActions(modConIds);
2420 case ALSO : modConIds = NIL;
2421 while ((s=readFilename())!=0)
2422 modConIds = cons(mkCon(findText(s)),modConIds);
2423 addActions(modConIds);
2426 case RELOAD : refreshActions(NIL,FALSE);
2431 case EVAL : evaluator();
2433 case TYPEOF : showtype();
2435 case BROWSE : browse();
2437 #if EXPLAIN_INSTANCE_RESOLUTION
2438 case XPLAIN : xplain();
2441 case NAMES : listNames();
2445 case BADCMD : guidance();
2449 case SYSTEM : if (shellEsc(readLine()))
2450 Printf("Warning: Shell escape terminated abnormally\n");
2452 case CHGDIR : changeDir();
2456 case PNTVER: Printf("-- Hugs Version %s\n",
2459 case DUMP : dumpStg();
2462 case COLLECT: consGC = FALSE;
2465 Printf("Garbage collection recovered %d cells\n",
2471 if (autoMain) break;
2475 /* --------------------------------------------------------------------------
2476 * Display progress towards goal:
2477 * ------------------------------------------------------------------------*/
2479 static Target currTarget;
2480 static Bool aiming = FALSE;
2483 static Int charCount;
2485 Void setGoal(what, t) /* Set goal for what to be t */
2490 #if EXPLAIN_INSTANCE_RESOLUTION
2494 currTarget = (t?t:1);
2497 currPos = strlen(what);
2498 maxPos = getTerminalWidth() - 1;
2502 for (charCount=0; *what; charCount++)
2507 Void soFar(t) /* Indicate progress towards goal */
2508 Target t; { /* has now reached t */
2511 #if EXPLAIN_INSTANCE_RESOLUTION
2516 Int newPos = (Int)((maxPos * ((long)t))/currTarget);
2521 if (newPos>currPos) {
2524 while (newPos>++currPos);
2531 Void done() { /* Goal has now been achieved */
2534 #if EXPLAIN_INSTANCE_RESOLUTION
2539 while (maxPos>currPos++)
2544 for (; charCount>0; charCount--) {
2553 static Void local failed() { /* Goal cannot be reached due to */
2554 if (aiming) { /* errors */
2561 /* --------------------------------------------------------------------------
2563 * ------------------------------------------------------------------------*/
2565 static Void local stopAnyPrinting() { /* terminate printing of expression,*/
2566 if (printing) { /* after successful termination or */
2567 printing = FALSE; /* runtime error (e.g. interrupt) */
2570 #define plural(v) v, (v==1?"":"s")
2571 Printf("(%lu enter%s)\n",plural(numEnters));
2579 Cell errAssert(l) /* message to use when raising asserts, etc */
2583 str = mkStr(findText(currentFile));
2585 str = mkStr(findText(""));
2587 return (ap2(nameTangleMessage,str,mkInt(l)));
2590 Void errHead(l) /* print start of error message */
2592 failed(); /* failed to reach target ... */
2594 FPrintf(errorStream,"ERROR");
2597 FPrintf(errorStream," \"%s\"", currentFile);
2598 setLastEdit(currentFile,l);
2599 if (l) FPrintf(errorStream," (line %d)",l);
2602 FPrintf(errorStream,": ");
2603 FFlush(errorStream);
2606 Void errFail() { /* terminate error message and */
2607 Putc('\n',errorStream); /* produce exception to return to */
2608 FFlush(errorStream); /* main command loop */
2609 longjmp(catch_error,1);
2612 Void errFail_no_longjmp() { /* terminate error message but */
2613 Putc('\n',errorStream); /* don't produce an exception */
2614 FFlush(errorStream);
2617 Void errAbort() { /* altern. form of error handling */
2618 failed(); /* used when suitable error message*/
2619 stopAnyPrinting(); /* has already been printed */
2623 Void internal(msg) /* handle internal error */
2627 Printf("INTERNAL ERROR: %s\n",msg);
2630 longjmp(catch_error,1);
2633 Void fatal(msg) /* handle fatal error */
2636 Printf("\nFATAL ERROR: %s\n",msg);
2642 /* --------------------------------------------------------------------------
2643 * Read value from environment variable or registry:
2644 * ------------------------------------------------------------------------*/
2646 String fromEnv(var,def) /* return value of: */
2647 String var; /* environment variable named by var */
2648 String def; { /* or: default value given by def */
2649 String s = getenv(var);
2650 return (s ? s : def);
2653 /* --------------------------------------------------------------------------
2654 * String manipulation routines:
2655 * ------------------------------------------------------------------------*/
2657 static String local strCopy(s) /* make malloced copy of a string */
2661 if ((t=(char *)malloc(strlen(s)+1))==0) {
2662 ERRMSG(0) "String storage space exhausted"
2665 for (r=t; (*r++ = *s++)!=0; ) {
2673 /* --------------------------------------------------------------------------
2675 * We can redirect compiler output (prompts, error messages, etc) by
2676 * tweaking these functions.
2677 * ------------------------------------------------------------------------*/
2679 #ifdef HAVE_STDARG_H
2682 #include <varargs.h>
2685 Void hugsEnableOutput(f)
2690 #ifdef HAVE_STDARG_H
2691 Void hugsPrintf(const char *fmt, ...) {
2692 va_list ap; /* pointer into argument list */
2693 va_start(ap, fmt); /* make ap point to first arg after fmt */
2694 if (!disableOutput) {
2698 va_end(ap); /* clean up */
2701 Void hugsPrintf(fmt, va_alist)
2704 va_list ap; /* pointer into argument list */
2705 va_start(ap); /* make ap point to first arg after fmt */
2706 if (!disableOutput) {
2710 va_end(ap); /* clean up */
2716 if (!disableOutput) {
2722 Void hugsFlushStdout() {
2723 if (!disableOutput) {
2730 if (!disableOutput) {
2735 #ifdef HAVE_STDARG_H
2736 Void hugsFPrintf(FILE *fp, const char* fmt, ...) {
2739 if (!disableOutput) {
2740 vfprintf(fp, fmt, ap);
2746 Void hugsFPrintf(FILE *fp, const char* fmt, va_list)
2752 if (!disableOutput) {
2753 vfprintf(fp, fmt, ap);
2760 Void hugsPutc(c, fp)
2763 if (!disableOutput) {
2769 /* --------------------------------------------------------------------------
2770 * Send message to each component of system:
2771 * ------------------------------------------------------------------------*/
2773 Void everybody(what) /* send command `what' to each component of*/
2774 Int what; { /* system to respond as appropriate ... */
2776 fprintf ( stderr, "EVERYBODY %d\n", what );
2778 machdep(what); /* The order of calling each component is */
2779 storage(what); /* important for the PREPREL command */
2782 translateControl(what);
2784 staticAnalysis(what);
2785 deriveControl(what);
2793 mark(targetModules);
2795 mark(currentModule_failed);
2799 /*-------------------------------------------------------------------------*/