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/04/10 14:28:14 $
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 );
84 /* --------------------------------------------------------------------------
85 * Machine dependent code for Hugs interpreter:
86 * ------------------------------------------------------------------------*/
90 /* --------------------------------------------------------------------------
92 * ------------------------------------------------------------------------*/
94 static Bool printing = FALSE; /* TRUE => currently printing value*/
95 static Bool showStats = FALSE; /* TRUE => print stats after eval */
96 static Bool listScripts = TRUE; /* TRUE => list scripts after loading*/
97 static Bool addType = FALSE; /* TRUE => print type with value */
98 static Bool useDots = RISCOS; /* TRUE => use dots in progress */
99 static Bool quiet = FALSE; /* TRUE => don't show progress */
100 static Bool lastWasObject = FALSE;
102 Bool flagAssert = FALSE; /* TRUE => assert False <e> causes
103 an assertion failure */
104 Bool preludeLoaded = FALSE;
105 Bool debugSC = FALSE;
106 Bool combined = FALSE;
108 Module moduleBeingParsed; /* so the parser (topModule) knows */
109 static char* currentFile; /* Name of current file, or NULL */
110 static char currentFileName[1000]; /* name is stored here if it exists*/
112 static Bool autoMain = FALSE;
113 static String lastEdit = 0; /* Name of script to edit (if any) */
114 static Int lastEdLine = 0; /* Editor line number (if possible)*/
115 static String prompt = 0; /* Prompt string */
116 static Int hpSize = DEFAULTHEAP; /* Desired heap size */
117 static Bool disableOutput = FALSE; /* TRUE => quiet */
118 String hugsEdit = 0; /* String for editor command */
119 String hugsPath = 0; /* String for file search path */
121 List ifaces_outstanding = NIL;
124 /* --------------------------------------------------------------------------
126 * ------------------------------------------------------------------------*/
128 #ifndef NO_MAIN /* we omit main when building the "Hugs server" */
130 Main main ( Int, String [] ); /* now every func has a prototype */
135 #ifdef HAVE_CONSOLE_H /* Macintosh port */
137 _fcreator = 'R*ch'; /* // 'KAHL'; //'*TEX'; //'ttxt'; */
139 console_options.top = 50;
140 console_options.left = 20;
142 console_options.nrows = 32;
143 console_options.ncols = 80;
145 console_options.pause_atexit = 1;
146 console_options.title = "\pHugs";
148 console_options.procID = 5;
149 argc = ccommand(&argv);
152 CStackBase = &argc; /* Save stack base for use in gc */
156 checkBytecodeCount(); /* check for too many bytecodes */
160 /* If first arg is +Q or -Q, be entirely silent, and automatically run
161 main after loading scripts. Useful for running the nofib suite. */
162 if (argc > 1 && (strcmp(argv[1],"+Q") == 0 || strcmp(argv[1],"-Q")==0)) {
164 if (strcmp(argv[1],"-Q") == 0) {
169 Printf("__ __ __ __ ____ ___ _________________________________________\n");
170 Printf("|| || || || || || ||__ STGHugs: Based on the Haskell 98 standard\n");
171 Printf("||___|| ||__|| ||__|| __|| Copyright (c) 1994-1999\n");
172 Printf("||---|| ___|| World Wide Web: http://haskell.org/hugs\n");
173 Printf("|| || Report bugs to: hugs-bugs@haskell.org\n");
174 Printf("|| || Version: %s _________________________________________\n\n",HUGS_VERSION);
176 /* Get the absolute path to the directory containing the hugs
177 executable, so that we know where the Prelude and nHandle.so/.dll are.
178 We do this by reading env var STGHUGSDIR. This needs to succeed, so
179 setInstallDir won't return unless it succeeds.
181 setInstallDir ( argv[0] );
184 Printf(" Ported to Macintosh by Hans Aberg, compiled " __DATE__ ".\n\n");
187 interpreter(argc,argv);
188 Printf("[Leaving Hugs]\n");
199 /* --------------------------------------------------------------------------
200 * Initialization, interpret command line args and read prelude:
201 * ------------------------------------------------------------------------*/
203 static List /*CONID*/ initialize ( Int argc, String argv[] )
208 setLastEdit((String)0,0);
215 hugsEdit = strCopy(fromEnv("EDITOR",NULL));
217 hugsPath = strCopy(HUGSPATH);
218 readOptions("-p\"%s> \" -r$$");
219 readOptions(fromEnv("STGHUGSFLAGS",""));
223 char exe_name[N_INSTALLDIR + 6];
224 strcpy(exe_name, installDir);
225 strcat(exe_name, "hugs");
226 DEBUG_LoadSymbols(exe_name);
230 /* startupHaskell extracts args between +RTS ... -RTS, and sets
231 prog_argc/prog_argv to the rest. We want to further process
232 the rest, so we then get hold of them again.
234 startupHaskell ( argc, argv, NULL );
235 getProgArgv ( &argc, &argv );
237 /* Find out early on if we're in combined mode or not.
238 everybody(PREPREL) needs to know this. Also, establish the
241 for (i = 1; i < argc; ++i) {
242 if (strcmp(argv[i], "--")==0) break;
243 if (strcmp(argv[i], "-c")==0) combined = FALSE;
244 if (strcmp(argv[i], "+c")==0) combined = TRUE;
246 if (strncmp(argv[i],"+h",2)==0 || strncmp(argv[i],"-h",2)==0)
247 setHeapSize(&(argv[i][2]));
251 initialModules = NIL;
253 for (i = 1; i < argc; ++i) { /* process command line arguments */
254 if (strcmp(argv[i], "--")==0)
255 { argv[i] = NULL; break; }
256 if (argv[i] && argv[i][0]/* workaround for /bin/sh silliness*/) {
257 if (!processOption(argv[i]))
259 = cons ( mkCon(findText(argv[i])), initialModules );
265 Printf("Haskell 98 mode: Restart with command line option -98"
266 " to enable extensions\n");
268 Printf("Hugs mode: Restart with command line option +98 for"
269 " Haskell 98 mode\n");
273 Printf("Combined mode: Restart with command line -c for"
274 " standalone mode\n\n" );
276 Printf("Standalone mode: Restart with command line +c for"
277 " combined mode\n\n" );
280 /* slide args back over the deleted ones. */
282 for (i = 1; i < argc; i++)
288 setProgArgv ( argc, argv );
291 return initialModules;
294 /* --------------------------------------------------------------------------
295 * Command line options:
296 * ------------------------------------------------------------------------*/
298 struct options { /* command line option toggles */
299 char c; /* table defined in main app. */
304 extern struct options toggle[];
306 static Void local toggleSet(c,state) /* Set command line toggle */
310 for (i=0; toggle[i].c; ++i)
311 if (toggle[i].c == c) {
312 *toggle[i].flag = state;
315 ERRMSG(0) "Unknown toggle `%c'", c
319 static Void local togglesIn(state) /* Print current list of toggles in*/
320 Bool state; { /* given state */
323 for (i=0; toggle[i].c; ++i)
324 if (*toggle[i].flag == state && (!haskell98 || toggle[i].h98)) {
326 Putchar((char)(state ? '+' : '-'));
327 Putchar(toggle[i].c);
334 static Void local optionInfo() { /* Print information about command */
335 static String fmts = "%-5s%s\n"; /* line settings */
336 static String fmtc = "%-5c%s\n";
339 Printf("TOGGLES: groups begin with +/- to turn options on/off resp.\n");
340 for (i=0; toggle[i].c; ++i) {
341 if (!haskell98 || toggle[i].h98) {
342 Printf(fmtc,toggle[i].c,toggle[i].description);
346 Printf("\nOTHER OPTIONS: (leading + or - makes no difference)\n");
347 Printf(fmts,"hnum","Set heap size (cannot be changed within Hugs)");
348 Printf(fmts,"pstr","Set prompt string to str");
349 Printf(fmts,"rstr","Set repeat last expression string to str");
350 Printf(fmts,"Pstr","Set search path for modules to str");
351 Printf(fmts,"Estr","Use editor setting given by str");
352 Printf(fmts,"cnum","Set constraint cutoff limit");
353 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
354 Printf(fmts,"Fstr","Set preprocessor filter to str");
357 Printf("\nCurrent settings: ");
360 Printf("-h%d",heapSize);
364 printString(repeatStr);
365 Printf(" -c%d",cutoff);
366 Printf("\nSearch path : -P");
367 printString(hugsPath);
370 if (projectPath!=NULL) {
371 Printf("\nProject Path : %s",projectPath);
374 Printf("\nEditor setting : -E");
375 printString(hugsEdit);
376 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
377 Printf("\nPreprocessor : -F");
378 printString(preprocessor);
380 Printf("\nCompatibility : %s", haskell98 ? "Haskell 98 (+98)"
381 : "Hugs Extensions (-98)");
390 static Void local readOptions(options) /* read options from string */
394 stringInput(options);
395 while ((s=readFilename())!=0) {
396 if (*s && !processOption(s)) {
397 ERRMSG(0) "Option string must begin with `+' or `-'"
404 static Bool local processOption(s) /* process string s for options, */
405 String s; { /* return FALSE if none found. */
417 case 'Q' : break; /* already handled */
419 case 'p' : if (s[1]) {
420 if (prompt) free(prompt);
421 prompt = strCopy(s+1);
425 case 'r' : if (s[1]) {
426 if (repeatStr) free(repeatStr);
427 repeatStr = strCopy(s+1);
432 String p = substPath(s+1,hugsPath ? hugsPath : "");
433 if (hugsPath) free(hugsPath);
438 case 'E' : if (hugsEdit) free(hugsEdit);
439 hugsEdit = strCopy(s+1);
442 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
443 case 'F' : if (preprocessor) free(preprocessor);
444 preprocessor = strCopy(s+1);
448 case 'h' : /* don't do anything, since pre-scan of args
449 will have got it already */
452 case 'c' : /* don't do anything, since pre-scan of args
453 will have got it already */
456 case 'D' : /* hack */
458 extern void setRtsFlags( int x );
459 setRtsFlags(argToInt(s+1));
463 default : if (strcmp("98",s)==0) {
464 if (initDone && ((state && !haskell98) ||
465 (!state && haskell98))) {
467 "Haskell 98 compatibility cannot be changed"
468 " while the interpreter is running\n");
481 static Void local setHeapSize(s)
484 hpSize = argToInt(s);
485 if (hpSize < MINIMUMHEAP)
486 hpSize = MINIMUMHEAP;
487 else if (MAXIMUMHEAP && hpSize > MAXIMUMHEAP)
488 hpSize = MAXIMUMHEAP;
489 if (initDone && hpSize != heapSize) {
490 /* ToDo: should this use a message box in winhugs? */
491 FPrintf(stderr,"You cannot change heap size from inside Hugs\n");
498 static Int local argToInt(s) /* read integer from argument str */
503 if (*s=='\0' || !isascii((int)(*s)) || !isdigit((int)(*s))) {
504 ERRMSG(0) "Missing integer in option setting \"%s\"", t
509 Int d = (*s++) - '0';
510 if (n > ((MAXPOSINT - d)/10)) {
511 ERRMSG(0) "Option setting \"%s\" is too large", t
515 } while (isascii((int)(*s)) && isdigit((int)(*s)));
517 if (*s=='K' || *s=='k') {
518 if (n > (MAXPOSINT/1000)) {
519 ERRMSG(0) "Option setting \"%s\" is too large", t
526 #if MAXPOSINT > 1000000 /* waste of time on 16 bit systems */
527 if (*s=='M' || *s=='m') {
528 if (n > (MAXPOSINT/1000000)) {
529 ERRMSG(0) "Option setting \"%s\" is too large", t
537 #if MAXPOSINT > 1000000000
538 if (*s=='G' || *s=='g') {
539 if (n > (MAXPOSINT/1000000000)) {
540 ERRMSG(0) "Option setting \"%s\" is too large", t
549 ERRMSG(0) "Unwanted characters after option setting \"%s\"", t
556 /* --------------------------------------------------------------------------
557 * Print Menu of list of commands:
558 * ------------------------------------------------------------------------*/
560 static struct cmd cmds[] = {
561 {":?", HELP}, {":cd", CHGDIR}, {":also", ALSO},
562 {":type", TYPEOF}, {":!", SYSTEM}, {":load", LOAD},
563 {":reload", RELOAD}, {":gc", COLLECT}, {":edit", EDIT},
564 {":quit", QUIT}, {":set", SET}, {":find", FIND},
565 {":names", NAMES}, {":info", INFO}, {":project", PROJECT},
566 {":dump", DUMP}, {":ztats", STATS},
567 {":module",SETMODULE},
569 #if EXPLAIN_INSTANCE_RESOLUTION
572 {":version", PNTVER},
577 static Void local menu() {
578 Printf("LIST OF COMMANDS: Any command may be abbreviated to :c where\n");
579 Printf("c is the first character in the full name.\n\n");
580 Printf(":load <filenames> load modules from specified files\n");
581 Printf(":load clear all files except prelude\n");
582 Printf(":also <filenames> read additional modules\n");
583 Printf(":reload repeat last load command\n");
584 Printf(":project <filename> use project file\n");
585 Printf(":edit <filename> edit file\n");
586 Printf(":edit edit last module\n");
587 Printf(":module <module> set module for evaluating expressions\n");
588 Printf("<expr> evaluate expression\n");
589 Printf(":type <expr> print type of expression\n");
590 Printf(":? display this list of commands\n");
591 Printf(":set <options> set command line options\n");
592 Printf(":set help on command line options\n");
593 Printf(":names [pat] list names currently in scope\n");
594 Printf(":info <names> describe named objects\n");
595 Printf(":browse <modules> browse names defined in <modules>\n");
596 #if EXPLAIN_INSTANCE_RESOLUTION
597 Printf(":xplain <context> explain instance resolution for <context>\n");
599 Printf(":find <name> edit module containing definition of name\n");
600 Printf(":!command shell escape\n");
601 Printf(":cd dir change directory\n");
602 Printf(":gc force garbage collection\n");
603 Printf(":version print Hugs version\n");
604 Printf(":dump <name> print STG code for named fn\n");
605 #ifdef CRUDE_PROFILING
606 Printf(":ztats <name> print reduction stats\n");
608 Printf(":quit exit Hugs interpreter\n");
611 static Void local guidance() {
612 Printf("Command not recognised. ");
616 static Void local forHelp() {
617 Printf("Type :? for help\n");
620 /* --------------------------------------------------------------------------
621 * Setting of command line options:
622 * ------------------------------------------------------------------------*/
624 struct options toggle[] = { /* List of command line toggles */
625 {'s', 1, "Print no. reductions/cells after eval", &showStats},
626 {'t', 1, "Print type after evaluation", &addType},
627 {'g', 1, "Print no. cells recovered after gc", &gcMessages},
628 {'l', 1, "Literate modules as default", &literateScripts},
629 {'e', 1, "Warn about errors in literate modules", &literateErrors},
630 {'.', 1, "Print dots to show progress", &useDots},
631 {'q', 1, "Print nothing to show progress", &quiet},
632 {'w', 1, "Always show which modules are loaded", &listScripts},
633 {'k', 1, "Show kind errors in full", &kindExpert},
634 {'o', 0, "Allow overlapping instances", &allowOverlap},
635 {'S', 1, "Debug: show generated SC code", &debugSC},
636 {'a', 1, "Raise exception on assert failure", &flagAssert},
637 #if EXPLAIN_INSTANCE_RESOLUTION
638 {'x', 1, "Explain instance resolution", &showInstRes},
641 {'m', 0, "Use multi instance resolution", &multiInstRes},
646 static Void local set() { /* change command line options from*/
647 String s; /* Hugs command line */
649 if ((s=readFilename())!=0) {
651 if (!processOption(s)) {
652 ERRMSG(0) "Option string must begin with `+' or `-'"
655 } while ((s=readFilename())!=0);
661 /* --------------------------------------------------------------------------
662 * Change directory command:
663 * ------------------------------------------------------------------------*/
665 static Void local changeDir() { /* change directory */
666 String s = readFilename();
668 ERRMSG(0) "Unable to change to directory \"%s\"", s
674 /* --------------------------------------------------------------------------
676 * ------------------------------------------------------------------------*/
678 static jmp_buf catch_error; /* jump buffer for error trapping */
680 HugsBreakAction currentBreakAction = HugsIgnoreBreak;
682 static void handler_IgnoreBreak ( int sig )
684 setHandler ( handler_IgnoreBreak );
687 static void handler_LongjmpOnBreak ( int sig )
689 setHandler ( handler_LongjmpOnBreak );
690 Printf("{Interrupted!}\n");
691 longjmp(catch_error,1);
694 static void handler_RtsInterrupt ( int sig )
696 setHandler ( handler_RtsInterrupt );
700 HugsBreakAction setBreakAction ( HugsBreakAction newAction )
702 HugsBreakAction tmp = currentBreakAction;
703 currentBreakAction = newAction;
705 case HugsIgnoreBreak:
706 setHandler ( handler_IgnoreBreak ); break;
707 case HugsLongjmpOnBreak:
708 setHandler ( handler_LongjmpOnBreak ); break;
709 case HugsRtsInterrupt:
710 setHandler ( handler_RtsInterrupt ); break;
712 internal("setBreakAction");
718 /* --------------------------------------------------------------------------
719 * The new module chaser, loader, etc
720 * ------------------------------------------------------------------------*/
722 List moduleGraph = NIL;
723 List prelModules = NIL;
724 List targetModules = NIL;
726 static String modeToString ( Cell mode )
729 case FM_SOURCE: return "source";
730 case FM_OBJECT: return "object";
731 case FM_EITHER: return "source or object";
732 default: internal("modeToString");
736 static Cell childMode ( Cell modeMeRequest, Cell modeMeActual )
738 assert(modeMeActual == FM_SOURCE ||
739 modeMeActual == FM_OBJECT);
740 assert(modeMeRequest == FM_SOURCE ||
741 modeMeRequest == FM_OBJECT ||
742 modeMeRequest == FM_EITHER);
743 if (modeMeRequest == FM_SOURCE) return modeMeRequest;
744 if (modeMeRequest == FM_OBJECT) return modeMeRequest;
745 if (modeMeActual == FM_OBJECT) return FM_OBJECT;
746 if (modeMeActual == FM_SOURCE) return FM_EITHER;
747 internal("childMode");
750 static Bool compatibleNewMode ( Cell modeNew, Cell modeExisting )
752 if (modeNew == FM_OBJECT && modeExisting == FM_OBJECT) return TRUE;
753 if (modeNew == FM_SOURCE && modeExisting == FM_SOURCE) return TRUE;
754 if (modeNew == FM_EITHER && modeExisting == FM_OBJECT) return TRUE;
755 if (modeNew == FM_EITHER && modeExisting == FM_SOURCE) return TRUE;
759 static void setCurrentFile ( Module mod )
761 assert(isModule(mod));
762 strncpy(currentFileName, textToStr(module(mod).text), 990);
763 strcat(currentFileName, textToStr(module(mod).srcExt));
764 currentFile = currentFileName;
765 moduleBeingParsed = mod;
768 static void clearCurrentFile ( void )
771 moduleBeingParsed = NIL;
774 static void ppMG ( void )
777 for (t = moduleGraph; nonNull(t); t=tl(t)) {
781 FPrintf ( stderr, " %s\n", textToStr(textOf(snd(u))));
784 FPrintf ( stderr, " {" );
785 for (v = snd(u); nonNull(v); v=tl(v))
786 FPrintf ( stderr, "%s ", textToStr(textOf(hd(v))) );
787 FPrintf ( stderr, "}\n" );
796 static Bool elemMG ( ConId mod )
799 for (gs = moduleGraph; nonNull(gs); gs=tl(gs))
800 switch (whatIs(hd(gs))) {
802 if (textOf(mod)==textOf(snd(hd(gs)))) return TRUE;
805 if (varIsMember(textOf(mod),snd(hd(gs)))) return TRUE;
814 static ConId selectArbitrarilyFromGroup ( Cell group )
816 switch (whatIs(group)) {
817 case GRP_NONREC: return snd(group);
818 case GRP_REC: return hd(snd(group));
819 default: internal("selectArbitrarilyFromGroup");
823 static ConId selectLatestMG ( void )
825 List gs = moduleGraph;
826 if (isNull(gs)) internal("selectLatestMG(1)");
827 while (nonNull(gs) && nonNull(tl(gs))) gs = tl(gs);
828 return selectArbitrarilyFromGroup(hd(gs));
832 static List /* of CONID */ listFromSpecifiedMG ( List mg )
836 for (gs = mg; nonNull(gs); gs=tl(gs)) {
837 switch (whatIs(hd(gs))) {
838 case GRP_REC: cs = appendOnto(cs,snd(hd(gs))); break;
839 case GRP_NONREC: cs = cons(snd(hd(gs)),cs); break;
840 default: internal("listFromSpecifiedMG");
846 static List /* of CONID */ listFromMG ( void )
848 return listFromSpecifiedMG ( moduleGraph );
852 /* Calculate the strongly connected components of modgList
853 and assign them to moduleGraph. Uses the .uses field of
854 each of the modules to build the graph structure.
856 #define SCC modScc /* make scc algorithm for StgVars */
857 #define LOWLINK modLowlink
858 #define DEPENDS(t) snd(t)
859 #define SETDEPENDS(c,v) snd(c)=v
866 static void mgFromList ( List /* of CONID */ modgList )
872 List adjList; /* :: [ (Text, [Text]) ] */
878 for (t = modgList; nonNull(t); t=tl(t)) {
880 mod = findModule(mT);
881 assert(nonNull(mod));
883 for (u = module(mod).uses; nonNull(u); u=tl(u))
884 usesT = cons(textOf(hd(u)),usesT);
886 /* artificially give all modules a dependency on Prelude */
887 if (mT != textPrelude && mT != textPrelPrim)
888 usesT = cons(textPrelude,usesT);
889 adjList = cons(pair(mT,usesT),adjList);
892 /* adjList is now [ (module-text, [modules-which-i-import-text]) ].
893 Modify this so that the adjacency list is a list of pointers
894 back to bits of adjList -- that's what modScc needs.
896 for (t = adjList; nonNull(t); t=tl(t)) {
898 /* for each elem of the adjacency list ... */
899 for (u = snd(hd(t)); nonNull(u); u=tl(u)) {
902 /* find the element of adjList whose fst is a */
903 for (v = adjList; nonNull(v); v=tl(v)) {
905 assert(isText(fst(hd(v))));
906 if (fst(hd(v))==a) break;
908 if (isNull(v)) internal("mgFromList");
909 adj = cons(hd(v),adj);
914 adjList = modScc ( adjList );
915 /* adjList is now [ [(module-text, aux-info-field)] ] */
919 for (t = adjList; nonNull(t); t=tl(t)) {
922 /* scc :: [ (module-text, aux-info-field) ] */
923 for (u = scc; nonNull(u); u=tl(u))
924 hd(u) = mkCon(fst(hd(u)));
927 if (length(scc) > 1) {
930 /* singleton module in scc; does it import itself? */
931 mod = findModule ( textOf(hd(scc)) );
932 assert(nonNull(mod));
934 for (u = module(mod).uses; nonNull(u); u=tl(u))
935 if (textOf(hd(u))==textOf(hd(scc)))
940 moduleGraph = cons( ap(GRP_REC,scc), moduleGraph ); else
941 moduleGraph = cons( ap(GRP_NONREC,hd(scc)), moduleGraph );
943 moduleGraph = reverse(moduleGraph);
947 static List /* of CONID */ getModuleImports ( Cell tree )
953 for (tes = zthd3(unap(M_MODULE,tree)); nonNull(tes); tes=tl(tes)) {
957 use = zfst(unap(M_IMPORT_Q,te));
959 if (!varIsMember(textOf(use),uses)) uses = cons ( use, uses );
962 use = zfst(unap(M_IMPORT_UNQ,te));
964 if (!varIsMember(textOf(use),uses)) uses = cons ( use, uses );
974 static void processModule ( Module m )
991 foreignImports = NIL;
992 foreignExports = NIL;
999 tree = unap(M_MODULE,module(m).tree);
1000 modNm = zfst3(tree);
1002 if (textOf(modNm) != module(m).text) {
1003 ERRMSG(0) "Module name \"%s\" does not match file name \"%s%s\"",
1004 textToStr(textOf(modNm)),
1005 textToStr(module(m).text),
1006 textToStr(module(m).srcExt)
1010 setExportList(zsnd3(tree));
1011 topEnts = zthd3(tree);
1013 for (tes = topEnts; nonNull(tes); tes=tl(tes)) {
1015 assert(isGenPair(te));
1017 switch(whatIs(te)) {
1019 addQualImport(zfst(te2),zsnd(te2));
1022 addUnqualImport(zfst(te2),zsnd(te2));
1025 tyconDefn(intOf(zsel14(te2)),zsel24(te2),zsel34(te2),zsel44(te2));
1028 classDefn(intOf(zsel14(te2)),zsel24(te2),zsel34(te2),zsel44(te2));
1031 instDefn(intOf(zfst3(te2)),zsnd3(te2),zthd3(te2));
1034 defaultDefn(intOf(zfst(te2)),zsnd(te2));
1037 foreignImport(intOf(zsel15(te2)),zsel25(te2),zsel35(te2),
1038 zsel45(te2),zsel55(te2));
1041 foreignExport(intOf(zsel15(te2)),zsel25(te2),zsel35(te2),
1042 zsel45(te2),zsel55(te2));
1044 valDefns = cons(te2,valDefns);
1047 internal("processModule");
1056 static Module parseModuleOrInterface ( ConId mc, Cell modeRequest )
1058 /* Allocate a module-table entry. */
1059 /* Parse the entity and fill in the .tree and .uses entries. */
1062 Bool sAvail; Time sTime; Long sSize;
1063 Bool oiAvail; Time oiTime; Long oSize; Long iSize;
1068 Text mt = textOf(mc);
1069 Module mod = findModule ( mt );
1071 /* fprintf ( stderr, "parseModuleOrInterface `%s' == %d\n",
1072 textToStr(mt),mod); */
1073 if (nonNull(mod) && !module(mod).fake)
1074 internal("parseModuleOrInterface");
1076 module(mod).fake = FALSE;
1079 mod = newModule(mt);
1081 /* This call malloc-ates path; we should deallocate it. */
1082 ok = findFilesForModule (
1083 textToStr(module(mod).text),
1086 &sAvail, &sTime, &sSize,
1087 &oiAvail, &oiTime, &oSize, &iSize
1090 if (!ok) goto cant_find;
1091 if (!sAvail && !oiAvail) goto cant_find;
1093 /* Find out whether to use source or object. */
1094 switch (modeRequest) {
1096 if (!sAvail) goto cant_find;
1100 if (!oiAvail) goto cant_find;
1104 if ( sAvail && !oiAvail) { useSource = TRUE; break; }
1105 if (!sAvail && oiAvail) { useSource = FALSE; break; }
1106 useSource = firstTimeIsLater ( sTime, oiTime ) ? TRUE : FALSE;
1109 internal("parseModuleOrInterface");
1112 /* Actually do the parsing. */
1114 module(mod).srcExt = findText(sExt);
1115 setCurrentFile(mod);
1117 strcat(name, textToStr(mt));
1119 module(mod).tree = parseModule(name,sSize);
1120 module(mod).uses = getModuleImports(module(mod).tree);
1121 module(mod).mode = FM_SOURCE;
1122 module(mod).lastStamp = sTime;
1124 module(mod).srcExt = findText(HI_ENDING);
1125 setCurrentFile(mod);
1127 strcat(name, textToStr(mt));
1128 strcat(name, DLL_ENDING);
1129 module(mod).objName = findText(name);
1130 module(mod).objSize = oSize;
1132 strcat(name, textToStr(mt));
1133 strcat(name, ".u_hi");
1134 module(mod).tree = parseInterface(name,iSize);
1135 module(mod).uses = getInterfaceImports(module(mod).tree);
1136 module(mod).mode = FM_OBJECT;
1137 module(mod).lastStamp = oiTime;
1140 if (path) free(path);
1144 if (path) free(path);
1147 "Can't find %s for module \"%s\"",
1148 modeToString(modeRequest), textToStr(mt)
1153 static void tryLoadGroup ( Cell grp )
1157 switch (whatIs(grp)) {
1159 m = findModule(textOf(snd(grp)));
1161 if (module(m).mode == FM_SOURCE) {
1162 processModule ( m );
1163 module(m).tree = NIL;
1165 processInterfaces ( singleton(snd(grp)) );
1166 m = findModule(textOf(snd(grp)));
1168 module(m).tree = NIL;
1172 for (t = snd(grp); nonNull(t); t=tl(t)) {
1173 m = findModule(textOf(hd(t)));
1175 if (module(m).mode == FM_SOURCE) {
1176 ERRMSG(0) "Source module \"%s\" imports itself recursively",
1177 textToStr(textOf(hd(t)))
1181 processInterfaces ( snd(grp) );
1182 for (t = snd(grp); nonNull(t); t=tl(t)) {
1183 m = findModule(textOf(hd(t)));
1185 module(m).tree = NIL;
1189 internal("tryLoadGroup");
1194 static void fallBackToPrelModules ( void )
1197 for (m = MODULE_BASE_ADDR;
1198 m < MODULE_BASE_ADDR+tabModuleSz; m++)
1200 && !varIsMember(module(m).text, prelModules))
1205 /* This function catches exceptions in most of the system.
1206 So it's only ok for procedures called from this one
1207 to do EENDs (ie, write error messages). Others should use
1210 static void achieveTargetModules ( Bool loadingThePrelude )
1213 volatile List modgList;
1215 volatile Module mod;
1220 Bool sAvail; Time sTime; Long sSize;
1221 Bool oiAvail; Time oiTime; Long oSize; Long iSize;
1223 volatile Time oisTime;
1224 volatile Bool out_of_date;
1225 volatile List ood_new;
1227 volatile List modgList_new;
1228 volatile List parsedButNotLoaded;
1229 volatile List toChase;
1230 volatile List trans_cl;
1231 volatile List trans_cl_new;
1236 volatile List badMods;
1238 setBreakAction ( HugsIgnoreBreak );
1240 /* First, examine timestamps to find out which modules are
1241 out of date with respect to the source/interface/object files.
1244 modgList = listFromMG();
1246 for (t = modgList; nonNull(t); t=tl(t)) {
1248 if (varIsMember(textOf(hd(t)),prelModules))
1251 mod = findModule(textOf(hd(t)));
1252 if (isNull(mod)) internal("achieveTargetSet(1)");
1254 /* In standalone mode, only succeeds for source modules. */
1255 ok = findFilesForModule (
1256 textToStr(module(mod).text),
1259 &sAvail, &sTime, &sSize,
1260 &oiAvail, &oiTime, &oSize, &iSize
1263 if (!combined && !sAvail) ok = FALSE;
1265 fallBackToPrelModules();
1267 "Can't find source or object+interface for module \"%s\"",
1268 textToStr(module(mod).text)
1270 if (path) free(path);
1274 if (sAvail && oiAvail) {
1275 oisTime = whicheverIsLater(sTime,oiTime);
1277 else if (sAvail && !oiAvail) {
1280 else if (!sAvail && oiAvail) {
1284 internal("achieveTargetSet(2)");
1287 out_of_date = firstTimeIsLater(oisTime,module(mod).lastStamp);
1289 assert(!varIsMember(textOf(hd(t)),ood));
1290 ood = cons(hd(t),ood);
1293 if (path) { free(path); path = NULL; };
1296 /* Second, form a simplistic transitive closure of the out-of-date
1297 modules: a module is out of date if it imports an out-of-date
1302 for (t = modgList; nonNull(t); t=tl(t)) {
1303 mod = findModule(textOf(hd(t)));
1304 assert(nonNull(mod));
1305 for (us = module(mod).uses; nonNull(us); us=tl(us))
1306 if (varIsMember(textOf(hd(us)),ood))
1309 if (varIsMember(textOf(hd(t)),prelModules))
1310 Printf ( "warning: prelude module \"%s\" is out-of-date\n",
1311 textToStr(textOf(hd(t))) );
1313 if (!varIsMember(textOf(hd(t)),ood_new) &&
1314 !varIsMember(textOf(hd(t)),ood))
1315 ood_new = cons(hd(t),ood_new);
1318 if (isNull(ood_new)) break;
1319 ood = appendOnto(ood_new,ood);
1322 /* Now ood holds the entire set of modules which are out-of-date.
1323 Throw them out of the system, yielding a "reduced system",
1324 in which the remaining modules are in-date.
1326 for (t = ood; nonNull(t); t=tl(t)) {
1327 mod = findModule(textOf(hd(t)));
1328 assert(nonNull(mod));
1332 for (t = modgList; nonNull(t); t=tl(t))
1333 if (!varIsMember(textOf(hd(t)),ood))
1334 modgList_new = cons(hd(t),modgList_new);
1335 modgList = modgList_new;
1337 /* Update the module group list to reflect the reduced system.
1338 We do this so that if the following parsing phases fail, we can
1339 safely fall back to the reduced system.
1341 mgFromList ( modgList );
1343 /* Parse modules/interfaces, collecting parse trees and chasing
1344 imports, starting from the target set.
1346 toChase = dupList(targetModules);
1347 for (t = toChase; nonNull(t); t=tl(t)) {
1348 Cell mode = (!combined)
1350 : ( (loadingThePrelude && combined)
1353 hd(t) = zpair(hd(t), mode);
1356 /* toChase :: [ ((ConId, {FM_SOURCE|FM_OBJECT|FM_EITHER} )) ] */
1358 parsedButNotLoaded = NIL;
1361 while (nonNull(toChase)) {
1362 ConId mc = zfst(hd(toChase));
1363 Cell mode = zsnd(hd(toChase));
1364 toChase = tl(toChase);
1365 if (varIsMember(textOf(mc),modgList)
1366 || varIsMember(textOf(mc),parsedButNotLoaded)) {
1367 /* either exists fully, or is at least parsed */
1368 mod = findModule(textOf(mc));
1369 assert(nonNull(mod));
1370 if (!compatibleNewMode(mode,module(mod).mode)) {
1373 "module %s: %s required, but %s is more recent",
1374 textToStr(textOf(mc)), modeToString(mode),
1375 modeToString(module(mod).mode)
1377 goto parseException;
1381 setBreakAction ( HugsLongjmpOnBreak );
1382 if (setjmp(catch_error)==0) {
1383 /* try this; it may throw an exception */
1384 mod = parseModuleOrInterface ( mc, mode );
1386 /* here's the exception handler, if parsing fails */
1387 /* A parse error (or similar). Clean up and abort. */
1389 setBreakAction ( HugsIgnoreBreak );
1390 mod = findModule(textOf(mc));
1391 if (nonNull(mod)) nukeModule(mod);
1392 for (t = parsedButNotLoaded; nonNull(t); t=tl(t)) {
1393 mod = findModule(textOf(hd(t)));
1394 assert(nonNull(mod));
1395 if (nonNull(mod)) nukeModule(mod);
1398 /* end of the exception handler */
1400 setBreakAction ( HugsIgnoreBreak );
1402 parsedButNotLoaded = cons(mc, parsedButNotLoaded);
1403 for (t = module(mod).uses; nonNull(t); t=tl(t))
1405 zpair( hd(t), childMode(mode,module(mod).mode) ),
1410 modgList = dupOnto(parsedButNotLoaded, modgList);
1412 /* We successfully parsed all modules reachable from the target
1413 set which were not part of the reduced system. However, there
1414 may be modules in the reduced system which are not reachable from
1415 the target set. We detect these now by building the transitive
1416 closure of the target set, and nuking modules in the reduced
1417 system which are not part of that closure.
1419 trans_cl = dupList(targetModules);
1422 for (t = trans_cl; nonNull(t); t=tl(t)) {
1423 mod = findModule(textOf(hd(t)));
1424 assert(nonNull(mod));
1425 for (u = module(mod).uses; nonNull(u); u=tl(u))
1426 if (!varIsMember(textOf(hd(u)),trans_cl)
1427 && !varIsMember(textOf(hd(u)),trans_cl_new)
1428 && !varIsMember(textOf(hd(u)),prelModules))
1429 trans_cl_new = cons(hd(u),trans_cl_new);
1431 if (isNull(trans_cl_new)) break;
1432 trans_cl = appendOnto(trans_cl_new,trans_cl);
1435 for (t = modgList; nonNull(t); t=tl(t)) {
1436 if (varIsMember(textOf(hd(t)),trans_cl)) {
1437 modgList_new = cons(hd(t),modgList_new);
1439 mod = findModule(textOf(hd(t)));
1440 assert(nonNull(mod));
1444 modgList = modgList_new;
1446 /* Now, the module symbol tables hold exactly the set of
1447 modules reachable from the target set, and modgList holds
1448 their names. Calculate the scc-ified module graph,
1449 since we need that to guide the next stage, that of
1450 Actually Loading the modules.
1452 If no errors occur, moduleGraph will reflect the final graph
1453 loaded. If an error occurs loading a group, we nuke
1454 that group, truncate the moduleGraph just prior to that
1455 group, and exit. That leaves the system having successfully
1456 loaded all groups prior to the one which failed.
1458 mgFromList ( modgList );
1460 for (mg = moduleGraph; nonNull(mg); mg=tl(mg)) {
1463 if (!varIsMember(textOf(selectArbitrarilyFromGroup(grp)),
1464 parsedButNotLoaded)) continue;
1466 setBreakAction ( HugsLongjmpOnBreak );
1467 if (setjmp(catch_error)==0) {
1468 /* try this; it may throw an exception */
1471 /* here's the exception handler, if static/typecheck etc fails */
1472 /* nuke the entire rest (ie, the unloaded part)
1473 of the module graph */
1474 setBreakAction ( HugsIgnoreBreak );
1475 badMods = listFromSpecifiedMG ( mg );
1476 for (t = badMods; nonNull(t); t=tl(t)) {
1477 mod = findModule(textOf(hd(t)));
1478 if (nonNull(mod)) nukeModule(mod);
1480 /* truncate the module graph just prior to this group. */
1484 if (isNull(mg)) break;
1485 if (hd(mg) == grp) break;
1486 mg2 = cons ( hd(mg), mg2 );
1489 moduleGraph = reverse(mg2);
1491 /* end of the exception handler */
1493 setBreakAction ( HugsIgnoreBreak );
1496 /* Err .. I think that's it. If we get here, we've successfully
1497 achieved the target set. Phew!
1499 setBreakAction ( HugsIgnoreBreak );
1503 static Bool loadThePrelude ( void )
1508 moduleGraph = prelModules = NIL;
1511 conPrelude = mkCon(findText("Prelude"));
1512 conPrelHugs = mkCon(findText("PrelHugs"));
1513 targetModules = doubleton(conPrelude,conPrelHugs);
1514 achieveTargetModules(TRUE);
1515 ok = elemMG(conPrelude) && elemMG(conPrelHugs);
1517 conPrelude = mkCon(findText("Prelude"));
1518 targetModules = singleton(conPrelude);
1519 achieveTargetModules(TRUE);
1520 ok = elemMG(conPrelude);
1523 if (ok) prelModules = listFromMG();
1528 static void refreshActions ( ConId nextCurrMod, Bool cleanAfter )
1531 ConId tryFor = mkCon(module(currentModule).text);
1532 achieveTargetModules(FALSE);
1533 if (nonNull(nextCurrMod))
1534 tryFor = nextCurrMod;
1535 if (!elemMG(tryFor))
1536 tryFor = selectLatestMG();
1537 /* combined mode kludge, to get Prelude rather than PrelHugs */
1538 if (combined && textOf(tryFor)==findText("PrelHugs"))
1539 tryFor = mkCon(findText("Prelude"));
1542 /* delete any targetModules which didn't actually get loaded */
1544 targetModules = NIL;
1545 for (; nonNull(t); t=tl(t))
1547 targetModules = cons(hd(t),targetModules);
1550 setCurrModule ( findModule(textOf(tryFor)) );
1551 Printf("Hugs session for:\n");
1556 static void addActions ( List extraModules /* :: [CONID] */ )
1559 for (t = extraModules; nonNull(t); t=tl(t)) {
1560 ConId extra = hd(t);
1561 if (!varIsMember(textOf(extra),targetModules))
1562 targetModules = cons(extra,targetModules);
1564 refreshActions ( isNull(extraModules)
1566 : hd(reverse(extraModules)),
1572 static void loadActions ( List loadModules /* :: [CONID] */ )
1575 targetModules = dupList ( prelModules );
1577 for (t = loadModules; nonNull(t); t=tl(t)) {
1579 if (!varIsMember(textOf(load),targetModules))
1580 targetModules = cons(load,targetModules);
1582 refreshActions ( isNull(loadModules)
1584 : hd(reverse(loadModules)),
1590 /* --------------------------------------------------------------------------
1591 * Access to external editor:
1592 * ------------------------------------------------------------------------*/
1594 /* ToDo: All this editor stuff needs fixing. */
1596 static Void local editor() { /* interpreter-editor interface */
1598 String newFile = readFilename();
1600 setLastEdit(newFile,0);
1601 if (readFilename()) {
1602 ERRMSG(0) "Multiple filenames not permitted"
1610 static Void local find() { /* edit file containing definition */
1613 String nm = readFilename(); /* of specified name */
1615 ERRMSG(0) "No name specified"
1618 else if (readFilename()) {
1619 ERRMSG(0) "Multiple names not permitted"
1625 setCurrModule(findEvalModule());
1627 if (nonNull(c=findTycon(t=findText(nm)))) {
1628 if (startEdit(tycon(c).line,scriptName[scriptThisTycon(c)])) {
1629 readScripts(N_PRELUDE_SCRIPTS);
1631 } else if (nonNull(c=findName(t))) {
1632 if (startEdit(name(c).line,scriptName[scriptThisName(c)])) {
1633 readScripts(N_PRELUDE_SCRIPTS);
1636 ERRMSG(0) "No current definition for name \"%s\"", nm
1643 static Void local runEditor() { /* run editor on script lastEdit */
1645 if (startEdit(lastEdLine,lastEdit)) /* at line lastEdLine */
1646 readScripts(N_PRELUDE_SCRIPTS);
1650 static Void local setLastEdit(fname,line)/* keep name of last file to edit */
1656 lastEdit = strCopy(fname);
1661 /* --------------------------------------------------------------------------
1662 * Read and evaluate an expression:
1663 * ------------------------------------------------------------------------*/
1665 static Void setModule ( void ) {
1666 /*set module in which to evaluate expressions*/
1669 String s = readFilename();
1671 mc = selectLatestMG();
1672 if (combined && textOf(mc)==findText("PrelHugs"))
1673 mc = mkCon(findText("Prelude"));
1674 m = findModule(textOf(mc));
1677 m = findModule(findText(s));
1679 ERRMSG(0) "Cannot find module \"%s\"", s
1687 static Module allocEvalModule ( void )
1689 Module evalMod = newModule( findText("_Eval_Module_") );
1690 module(evalMod).names = module(currentModule).names;
1691 module(evalMod).tycons = module(currentModule).tycons;
1692 module(evalMod).classes = module(currentModule).classes;
1693 module(evalMod).qualImports
1694 = singleton(pair(mkCon(textPrelude),modulePrelude));
1698 static Void local evaluator() { /* evaluate expr and print value */
1701 volatile Kinds ks = NIL;
1702 volatile Module evalMod = allocEvalModule();
1703 volatile Module currMod = currentModule;
1704 setCurrModule(evalMod);
1707 defaultDefns = combined ? stdDefaults : evalDefaults;
1709 setBreakAction ( HugsLongjmpOnBreak );
1710 if (setjmp(catch_error)==0) {
1714 type = typeCheckExp(TRUE);
1716 /* if an exception happens, we arrive here */
1717 setBreakAction ( HugsIgnoreBreak );
1718 goto cleanup_and_return;
1721 setBreakAction ( HugsIgnoreBreak );
1722 if (isPolyType(type)) {
1723 ks = polySigOf(type);
1724 bd = monotypeOf(type);
1729 if (whatIs(bd)==QUAL) {
1730 ERRMSG(0) "Unresolved overloading" ETHEN
1731 ERRTEXT "\n*** Type : " ETHEN ERRTYPE(type);
1732 ERRTEXT "\n*** Expression : " ETHEN ERREXPR(inputExpr);
1735 goto cleanup_and_return;
1739 if (isProgType(ks,bd)) {
1740 inputExpr = ap(nameRunIO_toplevel,inputExpr);
1744 Cell d = provePred(ks,NIL,ap(classShow,bd));
1746 ERRMSG(0) "Cannot find \"show\" function for:" ETHEN
1747 ERRTEXT "\n*** expression : " ETHEN ERREXPR(inputExpr);
1748 ERRTEXT "\n*** of type : " ETHEN ERRTYPE(type);
1751 goto cleanup_and_return;
1753 inputExpr = ap2(nameShow, d,inputExpr);
1754 inputExpr = ap (namePutStr, inputExpr);
1755 inputExpr = ap (nameRunIO_toplevel, inputExpr);
1757 evalExp(); printf("\n");
1760 printType(stdout,type);
1767 printf ( "result type is " );
1768 printType ( stdout, type );
1776 setBreakAction ( HugsIgnoreBreak );
1777 nukeModule(evalMod);
1778 setCurrModule(currMod);
1779 setCurrentFile(currMod);
1784 /* --------------------------------------------------------------------------
1785 * Print type of input expression:
1786 * ------------------------------------------------------------------------*/
1788 static Void showtype ( void ) { /* print type of expression (if any)*/
1791 volatile Module evalMod = allocEvalModule();
1792 volatile Module currMod = currentModule;
1793 setCurrModule(evalMod);
1795 if (setjmp(catch_error)==0) {
1799 defaultDefns = evalDefaults;
1800 type = typeCheckExp(FALSE);
1801 printExp(stdout,inputExpr);
1803 printType(stdout,type);
1806 /* if an exception happens, we arrive here */
1809 nukeModule(evalMod);
1810 setCurrModule(currMod);
1814 static Void local browseit(mod,t,all)
1821 Printf("module %s where\n",textToStr(module(mod).text));
1822 for (cs = module(mod).names; nonNull(cs); cs=tl(cs)) {
1824 /* only look at things defined in this module,
1825 unless `all' flag is set */
1826 if (all || name(nm).mod == mod) {
1827 /* unwanted artifacts, like lambda lifted values,
1828 are in the list of names, but have no types */
1829 if (nonNull(name(nm).type)) {
1830 printExp(stdout,nm);
1832 printType(stdout,name(nm).type);
1834 Printf(" -- data constructor");
1835 } else if (isMfun(nm)) {
1836 Printf(" -- class member");
1837 } else if (isSfun(nm)) {
1838 Printf(" -- selector function");
1846 Printf("Unknown module %s\n",t);
1851 static Void local browse() { /* browse modules */
1852 Int count = 0; /* or give menu of commands */
1856 for (; (s=readFilename())!=0; count++)
1857 if (strcmp(s,"all") == 0) {
1861 browseit(findModule(findText(s)),s,all);
1863 browseit(currentModule,NULL,all);
1867 #if EXPLAIN_INSTANCE_RESOLUTION
1868 static Void local xplain() { /* print type of expression (if any)*/
1870 Bool sir = showInstRes;
1872 setCurrModule(findEvalModule());
1873 startNewScript(0); /* Enables recovery of storage */
1874 /* allocated during evaluation */
1878 d = provePred(NIL,NIL,hd(inputContext));
1880 fprintf(stdout, "not Sat\n");
1882 fprintf(stdout, "Sat\n");
1888 /* --------------------------------------------------------------------------
1889 * Enhanced help system: print current list of scripts or give information
1891 * ------------------------------------------------------------------------*/
1893 static String local objToStr(m,c)
1896 #if 1 || DISPLAY_QUANTIFIERS
1897 static char newVar[60];
1898 switch (whatIs(c)) {
1899 case NAME : if (m == name(c).mod) {
1900 sprintf(newVar,"%s", textToStr(name(c).text));
1902 sprintf(newVar,"%s.%s",
1903 textToStr(module(name(c).mod).text),
1904 textToStr(name(c).text));
1908 case TYCON : if (m == tycon(c).mod) {
1909 sprintf(newVar,"%s", textToStr(tycon(c).text));
1911 sprintf(newVar,"%s.%s",
1912 textToStr(module(tycon(c).mod).text),
1913 textToStr(tycon(c).text));
1917 case CLASS : if (m == cclass(c).mod) {
1918 sprintf(newVar,"%s", textToStr(cclass(c).text));
1920 sprintf(newVar,"%s.%s",
1921 textToStr(module(cclass(c).mod).text),
1922 textToStr(cclass(c).text));
1926 default : internal("objToStr");
1930 static char newVar[33];
1931 switch (whatIs(c)) {
1932 case NAME : sprintf(newVar,"%s", textToStr(name(c).text));
1935 case TYCON : sprintf(newVar,"%s", textToStr(tycon(c).text));
1938 case CLASS : sprintf(newVar,"%s", textToStr(cclass(c).text));
1941 default : internal("objToStr");
1949 static Void dumpStg ( void )
1955 setCurrModule(findEvalModule());
1960 /* request to locate a symbol by name */
1961 if (s && (*s == '?')) {
1962 Text t = findText(s+1);
1963 locateSymbolByName(t);
1967 /* request to dump a bit of the heap */
1968 if (s && (*s == '-' || isdigit(*s))) {
1975 /* request to dump a symbol table entry */
1977 || !(*s == 't' || *s == 'n' || *s == 'c' || *s == 'i')
1978 || !isdigit(s[1])) {
1979 fprintf(stderr, ":d -- bad request `%s'\n", s );
1984 case 't': dumpTycon(i); break;
1985 case 'n': dumpName(i); break;
1986 case 'c': dumpClass(i); break;
1987 case 'i': dumpInst(i); break;
1988 default: fprintf(stderr, ":d -- `%c' not implemented\n", *s );
1994 static Void local dumpStg( void ) { /* print STG stuff */
1999 Cell v; /* really StgVar */
2000 setCurrModule(findEvalModule());
2002 for (; (s=readFilename())!=0;) {
2005 /* find the name while ignoring module scopes */
2006 for (i=NAMEMIN; i<nameHw; i++)
2007 if (name(i).text == t) n = i;
2009 /* perhaps it's an "idNNNNNN" thing? */
2012 s[0]=='i' && s[1]=='d' && isdigit(s[2])) {
2015 while (isdigit(s[i])) {
2016 v = v * 10 + (s[i]-'0');
2020 n = nameFromStgVar(v);
2023 if (isNull(n) && whatIs(v)==STGVAR) {
2024 Printf ( "\n{- `%s' has no nametable entry -}\n", s );
2025 printStg(stderr, v );
2028 Printf ( "Unknown reference `%s'\n", s );
2031 Printf ( "Not a Name: `%s'\n", s );
2033 if (isNull(name(n).stgVar)) {
2034 Printf ( "Doesn't have a STG tree: %s\n", s );
2036 Printf ( "\n{- stgVar of `%s' is id%d -}\n", s, -name(n).stgVar);
2037 printStg(stderr, name(n).stgVar);
2043 static Void local info() { /* describe objects */
2044 Int count = 0; /* or give menu of commands */
2047 for (; (s=readFilename())!=0; count++) {
2048 describe(findText(s));
2051 /* whatScripts(); */
2056 static Void local describe(t) /* describe an object */
2058 Tycon tc = findTycon(t);
2059 Class cl = findClass(t);
2060 Name nm = findName(t);
2062 if (nonNull(tc)) { /* as a type constructor */
2066 for (i=0; i<tycon(tc).arity; ++i) {
2067 t = ap(t,mkOffset(i));
2069 Printf("-- type constructor");
2071 Printf(" with kind ");
2072 printKind(stdout,tycon(tc).kind);
2075 switch (tycon(tc).what) {
2076 case SYNONYM : Printf("type ");
2077 printType(stdout,t);
2079 printType(stdout,tycon(tc).defn);
2083 case DATATYPE : { List cs = tycon(tc).defn;
2084 if (tycon(tc).what==DATATYPE) {
2089 printType(stdout,t);
2091 mapProc(printSyntax,cs);
2093 Printf("\n-- constructors:");
2095 for (; hasCfun(cs); cs=tl(cs)) {
2097 printExp(stdout,hd(cs));
2099 printType(stdout,name(hd(cs)).type);
2102 Printf("\n-- selectors:");
2104 for (; nonNull(cs); cs=tl(cs)) {
2106 printExp(stdout,hd(cs));
2108 printType(stdout,name(hd(cs)).type);
2113 case RESTRICTSYN : Printf("type ");
2114 printType(stdout,t);
2115 Printf(" = <restricted>");
2119 if (nonNull(in=findFirstInst(tc))) {
2120 Printf("\n-- instances:\n");
2123 in = findNextInst(tc,in);
2124 } while (nonNull(in));
2129 if (nonNull(cl)) { /* as a class */
2130 List ins = cclass(cl).instances;
2131 Kinds ks = cclass(cl).kinds;
2132 if (nonNull(ks) && isNull(tl(ks)) && hd(ks)==STAR) {
2133 Printf("-- type class");
2135 Printf("-- constructor class");
2137 Printf(" with arity ");
2138 printKinds(stdout,ks);
2142 mapProc(printSyntax,cclass(cl).members);
2144 if (nonNull(cclass(cl).supers)) {
2145 printContext(stdout,cclass(cl).supers);
2148 printPred(stdout,cclass(cl).head);
2150 if (nonNull(cclass(cl).fds)) {
2151 List fds = cclass(cl).fds;
2153 for (; nonNull(fds); fds=tl(fds)) {
2155 printFD(stdout,hd(fds));
2160 if (nonNull(cclass(cl).members)) {
2161 List ms = cclass(cl).members;
2164 Type t = name(hd(ms)).type;
2165 if (isPolyType(t)) {
2169 printExp(stdout,hd(ms));
2171 if (isNull(tl(fst(snd(t))))) {
2174 t = ap(QUAL,pair(tl(fst(snd(t))),snd(snd(t))));
2176 printType(stdout,t);
2178 } while (nonNull(ms));
2182 Printf("\n-- instances:\n");
2186 } while (nonNull(ins));
2191 if (nonNull(nm)) { /* as a function/name */
2193 printExp(stdout,nm);
2195 if (nonNull(name(nm).type)) {
2196 printType(stdout,name(nm).type);
2198 Printf("<unknown type>");
2201 Printf(" -- data constructor");
2202 } else if (isMfun(nm)) {
2203 Printf(" -- class member");
2204 } else if (isSfun(nm)) {
2205 Printf(" -- selector function");
2211 if (isNull(tc) && isNull(cl) && isNull(nm)) {
2212 Printf("Unknown reference `%s'\n",textToStr(t));
2216 static Void local printSyntax(nm)
2218 Syntax sy = syntaxOf(nm);
2219 Text t = name(nm).text;
2220 String s = textToStr(t);
2221 if (sy != defaultSyntax(t)) {
2223 switch (assocOf(sy)) {
2224 case LEFT_ASS : Putchar('l'); break;
2225 case RIGHT_ASS : Putchar('r'); break;
2226 case NON_ASS : break;
2228 Printf(" %i ",precOf(sy));
2229 if (isascii((int)(*s)) && isalpha((int)(*s))) {
2238 static Void local showInst(in) /* Display instance decl header */
2240 Printf("instance ");
2241 if (nonNull(inst(in).specifics)) {
2242 printContext(stdout,inst(in).specifics);
2245 printPred(stdout,inst(in).head);
2249 /* --------------------------------------------------------------------------
2250 * List all names currently in scope:
2251 * ------------------------------------------------------------------------*/
2253 static Void local listNames() { /* list names matching optional pat*/
2254 String pat = readFilename();
2256 Int width = getTerminalWidth() - 1;
2259 Module mod = currentModule;
2261 if (pat) { /* First gather names to list */
2263 names = addNamesMatching(pat,names);
2264 } while ((pat=readFilename())!=0);
2266 names = addNamesMatching((String)0,names);
2268 if (isNull(names)) { /* Then print them out */
2269 ERRMSG(0) "No names selected"
2273 for (termPos=0; nonNull(names); names=tl(names)) {
2274 String s = objToStr(mod,hd(names));
2276 if (termPos+1+l>width) {
2279 } else if (termPos>0) {
2287 Printf("\n(%d names listed)\n", count);
2290 /* --------------------------------------------------------------------------
2291 * print a prompt and read a line of input:
2292 * ------------------------------------------------------------------------*/
2294 static Void local promptForInput(moduleName)
2295 String moduleName; {
2296 char promptBuffer[1000];
2298 /* This is portable but could overflow buffer */
2299 sprintf(promptBuffer,prompt,moduleName);
2301 /* Works on ANSI C - but pre-ANSI compilers return a pointer to
2302 * promptBuffer instead.
2304 if (sprintf(promptBuffer,prompt,moduleName) >= 1000) {
2305 /* Reset prompt to a safe default to avoid an infinite loop */
2307 prompt = strCopy("? ");
2308 internal("Combined prompt and evaluation module name too long");
2312 stringInput("main\0"); else
2313 consoleInput(promptBuffer);
2316 /* --------------------------------------------------------------------------
2317 * main read-eval-print loop, with error trapping:
2318 * ------------------------------------------------------------------------*/
2320 static Void local interpreter(argc,argv)/* main interpreter loop */
2324 List modConIds; /* :: [CONID] */
2328 setBreakAction ( HugsIgnoreBreak );
2329 modConIds = initialize(argc,argv); /* the initial modules to load */
2330 setBreakAction ( HugsIgnoreBreak );
2331 prelOK = loadThePrelude();
2332 if (combined) everybody(POSTPREL);
2336 fprintf(stderr, "hugs +Q: fatal error: can't load the Prelude.\n" );
2338 fprintf(stderr, "hugs: fatal error: can't load the Prelude.\n" );
2342 loadActions(modConIds);
2345 for (; nonNull(modConIds); modConIds=tl(modConIds))
2346 if (!elemMG(hd(modConIds))) {
2348 "hugs +Q: compilation failed -- can't run `main'\n" );
2355 /* initialize calls startupHaskell, which trashes our signal handlers */
2356 setBreakAction ( HugsIgnoreBreak );
2361 everybody(RESET); /* reset to sensible initial state */
2363 promptForInput(textToStr(module(currentModule).text));
2365 cmd = readCommand(cmds, (Char)':', (Char)'!');
2367 case EDIT : editor();
2371 case LOAD : modConIds = NIL;
2372 while ((s=readFilename())!=0)
2373 modConIds = cons(mkCon(findText(s)),modConIds);
2374 loadActions(modConIds);
2377 case ALSO : modConIds = NIL;
2378 while ((s=readFilename())!=0)
2379 modConIds = cons(mkCon(findText(s)),modConIds);
2380 addActions(modConIds);
2383 case RELOAD : refreshActions(NIL,FALSE);
2388 case EVAL : evaluator();
2390 case TYPEOF : showtype();
2392 case BROWSE : browse();
2394 #if EXPLAIN_INSTANCE_RESOLUTION
2395 case XPLAIN : xplain();
2398 case NAMES : listNames();
2402 case BADCMD : guidance();
2407 #ifdef CRUDE_PROFILING
2411 case SYSTEM : if (shellEsc(readLine()))
2412 Printf("Warning: Shell escape terminated abnormally\n");
2414 case CHGDIR : changeDir();
2418 case PNTVER: Printf("-- Hugs Version %s\n",
2421 case DUMP : dumpStg();
2424 case COLLECT: consGC = FALSE;
2427 Printf("Garbage collection recovered %d cells\n",
2433 if (autoMain) break;
2437 /* --------------------------------------------------------------------------
2438 * Display progress towards goal:
2439 * ------------------------------------------------------------------------*/
2441 static Target currTarget;
2442 static Bool aiming = FALSE;
2445 static Int charCount;
2447 Void setGoal(what, t) /* Set goal for what to be t */
2452 #if EXPLAIN_INSTANCE_RESOLUTION
2456 currTarget = (t?t:1);
2459 currPos = strlen(what);
2460 maxPos = getTerminalWidth() - 1;
2464 for (charCount=0; *what; charCount++)
2469 Void soFar(t) /* Indicate progress towards goal */
2470 Target t; { /* has now reached t */
2473 #if EXPLAIN_INSTANCE_RESOLUTION
2478 Int newPos = (Int)((maxPos * ((long)t))/currTarget);
2483 if (newPos>currPos) {
2486 while (newPos>++currPos);
2493 Void done() { /* Goal has now been achieved */
2496 #if EXPLAIN_INSTANCE_RESOLUTION
2501 while (maxPos>currPos++)
2506 for (; charCount>0; charCount--) {
2515 static Void local failed() { /* Goal cannot be reached due to */
2516 if (aiming) { /* errors */
2523 /* --------------------------------------------------------------------------
2525 * ------------------------------------------------------------------------*/
2527 static Void local stopAnyPrinting() { /* terminate printing of expression,*/
2528 if (printing) { /* after successful termination or */
2529 printing = FALSE; /* runtime error (e.g. interrupt) */
2532 #define plural(v) v, (v==1?"":"s")
2533 Printf("%lu cell%s",plural(numCells));
2535 Printf(", %u garbage collection%s",plural(numGcs));
2544 Cell errAssert(l) /* message to use when raising asserts, etc */
2548 str = mkStr(findText(currentFile));
2550 str = mkStr(findText(""));
2552 return (ap2(nameTangleMessage,str,mkInt(l)));
2555 Void errHead(l) /* print start of error message */
2557 failed(); /* failed to reach target ... */
2559 FPrintf(errorStream,"ERROR");
2562 FPrintf(errorStream," \"%s\"", currentFile);
2563 setLastEdit(currentFile,l);
2564 if (l) FPrintf(errorStream," (line %d)",l);
2567 FPrintf(errorStream,": ");
2568 FFlush(errorStream);
2571 Void errFail() { /* terminate error message and */
2572 Putc('\n',errorStream); /* produce exception to return to */
2573 FFlush(errorStream); /* main command loop */
2574 longjmp(catch_error,1);
2577 Void errFail_no_longjmp() { /* terminate error message but */
2578 Putc('\n',errorStream); /* don't produce an exception */
2579 FFlush(errorStream);
2582 Void errAbort() { /* altern. form of error handling */
2583 failed(); /* used when suitable error message*/
2584 stopAnyPrinting(); /* has already been printed */
2588 Void internal(msg) /* handle internal error */
2592 Printf("INTERNAL ERROR: %s\n",msg);
2595 longjmp(catch_error,1);
2598 Void fatal(msg) /* handle fatal error */
2601 Printf("\nFATAL ERROR: %s\n",msg);
2607 /* --------------------------------------------------------------------------
2608 * Read value from environment variable or registry:
2609 * ------------------------------------------------------------------------*/
2611 String fromEnv(var,def) /* return value of: */
2612 String var; /* environment variable named by var */
2613 String def; { /* or: default value given by def */
2614 String s = getenv(var);
2615 return (s ? s : def);
2618 /* --------------------------------------------------------------------------
2619 * String manipulation routines:
2620 * ------------------------------------------------------------------------*/
2622 static String local strCopy(s) /* make malloced copy of a string */
2626 if ((t=(char *)malloc(strlen(s)+1))==0) {
2627 ERRMSG(0) "String storage space exhausted"
2630 for (r=t; (*r++ = *s++)!=0; ) {
2638 /* --------------------------------------------------------------------------
2640 * We can redirect compiler output (prompts, error messages, etc) by
2641 * tweaking these functions.
2642 * ------------------------------------------------------------------------*/
2644 #ifdef HAVE_STDARG_H
2647 #include <varargs.h>
2650 Void hugsEnableOutput(f)
2655 #ifdef HAVE_STDARG_H
2656 Void hugsPrintf(const char *fmt, ...) {
2657 va_list ap; /* pointer into argument list */
2658 va_start(ap, fmt); /* make ap point to first arg after fmt */
2659 if (!disableOutput) {
2663 va_end(ap); /* clean up */
2666 Void hugsPrintf(fmt, va_alist)
2669 va_list ap; /* pointer into argument list */
2670 va_start(ap); /* make ap point to first arg after fmt */
2671 if (!disableOutput) {
2675 va_end(ap); /* clean up */
2681 if (!disableOutput) {
2687 Void hugsFlushStdout() {
2688 if (!disableOutput) {
2695 if (!disableOutput) {
2700 #ifdef HAVE_STDARG_H
2701 Void hugsFPrintf(FILE *fp, const char* fmt, ...) {
2704 if (!disableOutput) {
2705 vfprintf(fp, fmt, ap);
2711 Void hugsFPrintf(FILE *fp, const char* fmt, va_list)
2717 if (!disableOutput) {
2718 vfprintf(fp, fmt, ap);
2725 Void hugsPutc(c, fp)
2728 if (!disableOutput) {
2734 /* --------------------------------------------------------------------------
2735 * Send message to each component of system:
2736 * ------------------------------------------------------------------------*/
2738 Void everybody(what) /* send command `what' to each component of*/
2739 Int what; { /* system to respond as appropriate ... */
2741 fprintf ( stderr, "EVERYBODY %d\n", what );
2743 machdep(what); /* The order of calling each component is */
2744 storage(what); /* important for the PREPREL command */
2747 translateControl(what);
2749 staticAnalysis(what);
2750 deriveControl(what);
2757 mark(targetModules);
2761 /*-------------------------------------------------------------------------*/