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 15:39:09 $
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;
126 /* --------------------------------------------------------------------------
128 * ------------------------------------------------------------------------*/
130 #ifndef NO_MAIN /* we omit main when building the "Hugs server" */
132 Main main ( Int, String [] ); /* now every func has a prototype */
137 #ifdef HAVE_CONSOLE_H /* Macintosh port */
139 _fcreator = 'R*ch'; /* // 'KAHL'; //'*TEX'; //'ttxt'; */
141 console_options.top = 50;
142 console_options.left = 20;
144 console_options.nrows = 32;
145 console_options.ncols = 80;
147 console_options.pause_atexit = 1;
148 console_options.title = "\pHugs";
150 console_options.procID = 5;
151 argc = ccommand(&argv);
154 CStackBase = &argc; /* Save stack base for use in gc */
158 checkBytecodeCount(); /* check for too many bytecodes */
162 /* If first arg is +Q or -Q, be entirely silent, and automatically run
163 main after loading scripts. Useful for running the nofib suite. */
164 if (argc > 1 && (strcmp(argv[1],"+Q") == 0 || strcmp(argv[1],"-Q")==0)) {
166 if (strcmp(argv[1],"-Q") == 0) {
171 Printf("__ __ __ __ ____ ___ _________________________________________\n");
172 Printf("|| || || || || || ||__ STGHugs: Based on the Haskell 98 standard\n");
173 Printf("||___|| ||__|| ||__|| __|| Copyright (c) 1994-1999\n");
174 Printf("||---|| ___|| World Wide Web: http://haskell.org/hugs\n");
175 Printf("|| || Report bugs to: hugs-bugs@haskell.org\n");
176 Printf("|| || Version: %s _________________________________________\n\n",HUGS_VERSION);
178 /* Get the absolute path to the directory containing the hugs
179 executable, so that we know where the Prelude and nHandle.so/.dll are.
180 We do this by reading env var STGHUGSDIR. This needs to succeed, so
181 setInstallDir won't return unless it succeeds.
183 setInstallDir ( argv[0] );
186 Printf(" Ported to Macintosh by Hans Aberg, compiled " __DATE__ ".\n\n");
189 interpreter(argc,argv);
190 Printf("[Leaving Hugs]\n");
201 /* --------------------------------------------------------------------------
202 * Initialization, interpret command line args and read prelude:
203 * ------------------------------------------------------------------------*/
205 static List /*CONID*/ initialize ( Int argc, String argv[] )
210 setLastEdit((String)0,0);
217 hugsEdit = strCopy(fromEnv("EDITOR",NULL));
219 hugsPath = strCopy(HUGSPATH);
220 readOptions("-p\"%s> \" -r$$");
221 readOptions(fromEnv("STGHUGSFLAGS",""));
225 char exe_name[N_INSTALLDIR + 6];
226 strcpy(exe_name, installDir);
227 strcat(exe_name, "hugs");
228 DEBUG_LoadSymbols(exe_name);
232 /* startupHaskell extracts args between +RTS ... -RTS, and sets
233 prog_argc/prog_argv to the rest. We want to further process
234 the rest, so we then get hold of them again.
236 startupHaskell ( argc, argv, NULL );
237 getProgArgv ( &argc, &argv );
239 /* Find out early on if we're in combined mode or not.
240 everybody(PREPREL) needs to know this. Also, establish the
243 for (i = 1; i < argc; ++i) {
244 if (strcmp(argv[i], "--")==0) break;
245 if (strcmp(argv[i], "-c")==0) combined = FALSE;
246 if (strcmp(argv[i], "+c")==0) combined = TRUE;
248 if (strncmp(argv[i],"+h",2)==0 || strncmp(argv[i],"-h",2)==0)
249 setHeapSize(&(argv[i][2]));
253 initialModules = NIL;
255 for (i = 1; i < argc; ++i) { /* process command line arguments */
256 if (strcmp(argv[i], "--")==0)
257 { argv[i] = NULL; break; }
258 if (argv[i] && argv[i][0]/* workaround for /bin/sh silliness*/) {
259 if (!processOption(argv[i]))
261 = cons ( mkCon(findText(argv[i])), initialModules );
267 Printf("Haskell 98 mode: Restart with command line option -98"
268 " to enable extensions\n");
270 Printf("Hugs mode: Restart with command line option +98 for"
271 " Haskell 98 mode\n");
275 Printf("Combined mode: Restart with command line -c for"
276 " standalone mode\n\n" );
278 Printf("Standalone mode: Restart with command line +c for"
279 " combined mode\n\n" );
282 /* slide args back over the deleted ones. */
284 for (i = 1; i < argc; i++)
290 setProgArgv ( argc, argv );
293 return initialModules;
296 /* --------------------------------------------------------------------------
297 * Command line options:
298 * ------------------------------------------------------------------------*/
300 struct options { /* command line option toggles */
301 char c; /* table defined in main app. */
306 extern struct options toggle[];
308 static Void local toggleSet(c,state) /* Set command line toggle */
312 for (i=0; toggle[i].c; ++i)
313 if (toggle[i].c == c) {
314 *toggle[i].flag = state;
318 ERRMSG(0) "Unknown toggle `%c'", c
322 static Void local togglesIn(state) /* Print current list of toggles in*/
323 Bool state; { /* given state */
326 for (i=0; toggle[i].c; ++i)
327 if (*toggle[i].flag == state && (!haskell98 || toggle[i].h98)) {
329 Putchar((char)(state ? '+' : '-'));
330 Putchar(toggle[i].c);
337 static Void local optionInfo() { /* Print information about command */
338 static String fmts = "%-5s%s\n"; /* line settings */
339 static String fmtc = "%-5c%s\n";
342 Printf("TOGGLES: groups begin with +/- to turn options on/off resp.\n");
343 for (i=0; toggle[i].c; ++i) {
344 if (!haskell98 || toggle[i].h98) {
345 Printf(fmtc,toggle[i].c,toggle[i].description);
349 Printf("\nOTHER OPTIONS: (leading + or - makes no difference)\n");
350 Printf(fmts,"hnum","Set heap size (cannot be changed within Hugs)");
351 Printf(fmts,"pstr","Set prompt string to str");
352 Printf(fmts,"rstr","Set repeat last expression string to str");
353 Printf(fmts,"Pstr","Set search path for modules to str");
354 Printf(fmts,"Estr","Use editor setting given by str");
355 Printf(fmts,"cnum","Set constraint cutoff limit");
356 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
357 Printf(fmts,"Fstr","Set preprocessor filter to str");
360 Printf("\nCurrent settings: ");
363 Printf("-h%d",heapSize);
367 printString(repeatStr);
368 Printf(" -c%d",cutoff);
369 Printf("\nSearch path : -P");
370 printString(hugsPath);
373 if (projectPath!=NULL) {
374 Printf("\nProject Path : %s",projectPath);
377 Printf("\nEditor setting : -E");
378 printString(hugsEdit);
379 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
380 Printf("\nPreprocessor : -F");
381 printString(preprocessor);
383 Printf("\nCompatibility : %s", haskell98 ? "Haskell 98 (+98)"
384 : "Hugs Extensions (-98)");
393 static Void local readOptions(options) /* read options from string */
397 stringInput(options);
398 while ((s=readFilename())!=0) {
399 if (*s && !processOption(s)) {
400 ERRMSG(0) "Option string must begin with `+' or `-'"
407 static Bool local processOption(s) /* process string s for options, */
408 String s; { /* return FALSE if none found. */
420 case 'Q' : break; /* already handled */
422 case 'p' : if (s[1]) {
423 if (prompt) free(prompt);
424 prompt = strCopy(s+1);
428 case 'r' : if (s[1]) {
429 if (repeatStr) free(repeatStr);
430 repeatStr = strCopy(s+1);
435 String p = substPath(s+1,hugsPath ? hugsPath : "");
436 if (hugsPath) free(hugsPath);
441 case 'E' : if (hugsEdit) free(hugsEdit);
442 hugsEdit = strCopy(s+1);
445 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
446 case 'F' : if (preprocessor) free(preprocessor);
447 preprocessor = strCopy(s+1);
451 case 'h' : /* don't do anything, since pre-scan of args
452 will have got it already */
455 case 'c' : /* don't do anything, since pre-scan of args
456 will have got it already */
459 case 'D' : /* hack */
461 extern void setRtsFlags( int x );
462 setRtsFlags(argToInt(s+1));
466 default : if (strcmp("98",s)==0) {
467 if (initDone && ((state && !haskell98) ||
468 (!state && haskell98))) {
470 "Haskell 98 compatibility cannot be changed"
471 " while the interpreter is running\n");
484 static Void local setHeapSize(s)
487 hpSize = argToInt(s);
488 if (hpSize < MINIMUMHEAP)
489 hpSize = MINIMUMHEAP;
490 else if (MAXIMUMHEAP && hpSize > MAXIMUMHEAP)
491 hpSize = MAXIMUMHEAP;
492 if (initDone && hpSize != heapSize) {
493 /* ToDo: should this use a message box in winhugs? */
494 FPrintf(stderr,"You cannot change heap size from inside Hugs\n");
501 static Int local argToInt(s) /* read integer from argument str */
506 if (*s=='\0' || !isascii((int)(*s)) || !isdigit((int)(*s))) {
507 ERRMSG(0) "Missing integer in option setting \"%s\"", t
512 Int d = (*s++) - '0';
513 if (n > ((MAXPOSINT - d)/10)) {
514 ERRMSG(0) "Option setting \"%s\" is too large", t
518 } while (isascii((int)(*s)) && isdigit((int)(*s)));
520 if (*s=='K' || *s=='k') {
521 if (n > (MAXPOSINT/1000)) {
522 ERRMSG(0) "Option setting \"%s\" is too large", t
529 #if MAXPOSINT > 1000000 /* waste of time on 16 bit systems */
530 if (*s=='M' || *s=='m') {
531 if (n > (MAXPOSINT/1000000)) {
532 ERRMSG(0) "Option setting \"%s\" is too large", t
540 #if MAXPOSINT > 1000000000
541 if (*s=='G' || *s=='g') {
542 if (n > (MAXPOSINT/1000000000)) {
543 ERRMSG(0) "Option setting \"%s\" is too large", t
552 ERRMSG(0) "Unwanted characters after option setting \"%s\"", t
559 /* --------------------------------------------------------------------------
560 * Print Menu of list of commands:
561 * ------------------------------------------------------------------------*/
563 static struct cmd cmds[] = {
564 {":?", HELP}, {":cd", CHGDIR}, {":also", ALSO},
565 {":type", TYPEOF}, {":!", SYSTEM}, {":load", LOAD},
566 {":reload", RELOAD}, {":gc", COLLECT}, {":edit", EDIT},
567 {":quit", QUIT}, {":set", SET}, {":find", FIND},
568 {":names", NAMES}, {":info", INFO}, {":project", PROJECT},
569 {":dump", DUMP}, {":ztats", STATS},
570 {":module",SETMODULE},
572 #if EXPLAIN_INSTANCE_RESOLUTION
575 {":version", PNTVER},
580 static Void local menu() {
581 Printf("LIST OF COMMANDS: Any command may be abbreviated to :c where\n");
582 Printf("c is the first character in the full name.\n\n");
583 Printf(":load <filenames> load modules from specified files\n");
584 Printf(":load clear all files except prelude\n");
585 Printf(":also <filenames> read additional modules\n");
586 Printf(":reload repeat last load command\n");
587 Printf(":project <filename> use project file\n");
588 Printf(":edit <filename> edit file\n");
589 Printf(":edit edit last module\n");
590 Printf(":module <module> set module for evaluating expressions\n");
591 Printf("<expr> evaluate expression\n");
592 Printf(":type <expr> print type of expression\n");
593 Printf(":? display this list of commands\n");
594 Printf(":set <options> set command line options\n");
595 Printf(":set help on command line options\n");
596 Printf(":names [pat] list names currently in scope\n");
597 Printf(":info <names> describe named objects\n");
598 Printf(":browse <modules> browse names defined in <modules>\n");
599 #if EXPLAIN_INSTANCE_RESOLUTION
600 Printf(":xplain <context> explain instance resolution for <context>\n");
602 Printf(":find <name> edit module containing definition of name\n");
603 Printf(":!command shell escape\n");
604 Printf(":cd dir change directory\n");
605 Printf(":gc force garbage collection\n");
606 Printf(":version print Hugs version\n");
607 Printf(":dump <name> print STG code for named fn\n");
608 #ifdef CRUDE_PROFILING
609 Printf(":ztats <name> print reduction stats\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 static void refreshActions ( ConId nextCurrMod, Bool cleanAfter )
1534 ConId tryFor = mkCon(module(currentModule).text);
1535 achieveTargetModules(FALSE);
1536 if (nonNull(nextCurrMod))
1537 tryFor = nextCurrMod;
1538 if (!elemMG(tryFor))
1539 tryFor = selectLatestMG();
1540 /* combined mode kludge, to get Prelude rather than PrelHugs */
1541 if (combined && textOf(tryFor)==findText("PrelHugs"))
1542 tryFor = mkCon(findText("Prelude"));
1545 /* delete any targetModules which didn't actually get loaded */
1547 targetModules = NIL;
1548 for (; nonNull(t); t=tl(t))
1550 targetModules = cons(hd(t),targetModules);
1553 setCurrModule ( findModule(textOf(tryFor)) );
1554 Printf("Hugs session for:\n");
1559 static void addActions ( List extraModules /* :: [CONID] */ )
1562 for (t = extraModules; nonNull(t); t=tl(t)) {
1563 ConId extra = hd(t);
1564 if (!varIsMember(textOf(extra),targetModules))
1565 targetModules = cons(extra,targetModules);
1567 refreshActions ( isNull(extraModules)
1569 : hd(reverse(extraModules)),
1575 static void loadActions ( List loadModules /* :: [CONID] */ )
1578 targetModules = dupList ( prelModules );
1580 for (t = loadModules; nonNull(t); t=tl(t)) {
1582 if (!varIsMember(textOf(load),targetModules))
1583 targetModules = cons(load,targetModules);
1585 refreshActions ( isNull(loadModules)
1587 : hd(reverse(loadModules)),
1593 /* --------------------------------------------------------------------------
1594 * Access to external editor:
1595 * ------------------------------------------------------------------------*/
1597 /* ToDo: All this editor stuff needs fixing. */
1599 static Void local editor() { /* interpreter-editor interface */
1601 String newFile = readFilename();
1603 setLastEdit(newFile,0);
1604 if (readFilename()) {
1605 ERRMSG(0) "Multiple filenames not permitted"
1613 static Void local find() { /* edit file containing definition */
1616 String nm = readFilename(); /* of specified name */
1618 ERRMSG(0) "No name specified"
1621 else if (readFilename()) {
1622 ERRMSG(0) "Multiple names not permitted"
1628 setCurrModule(findEvalModule());
1630 if (nonNull(c=findTycon(t=findText(nm)))) {
1631 if (startEdit(tycon(c).line,scriptName[scriptThisTycon(c)])) {
1632 readScripts(N_PRELUDE_SCRIPTS);
1634 } else if (nonNull(c=findName(t))) {
1635 if (startEdit(name(c).line,scriptName[scriptThisName(c)])) {
1636 readScripts(N_PRELUDE_SCRIPTS);
1639 ERRMSG(0) "No current definition for name \"%s\"", nm
1646 static Void local runEditor() { /* run editor on script lastEdit */
1648 if (startEdit(lastEdLine,lastEdit)) /* at line lastEdLine */
1649 readScripts(N_PRELUDE_SCRIPTS);
1653 static Void local setLastEdit(fname,line)/* keep name of last file to edit */
1659 lastEdit = strCopy(fname);
1664 /* --------------------------------------------------------------------------
1665 * Read and evaluate an expression:
1666 * ------------------------------------------------------------------------*/
1668 static Void setModule ( void ) {
1669 /*set module in which to evaluate expressions*/
1672 String s = readFilename();
1674 mc = selectLatestMG();
1675 if (combined && textOf(mc)==findText("PrelHugs"))
1676 mc = mkCon(findText("Prelude"));
1677 m = findModule(textOf(mc));
1680 m = findModule(findText(s));
1682 ERRMSG(0) "Cannot find module \"%s\"", s
1690 static Module allocEvalModule ( void )
1692 Module evalMod = newModule( findText("_Eval_Module_") );
1693 module(evalMod).names = module(currentModule).names;
1694 module(evalMod).tycons = module(currentModule).tycons;
1695 module(evalMod).classes = module(currentModule).classes;
1696 module(evalMod).qualImports
1697 = singleton(pair(mkCon(textPrelude),modulePrelude));
1701 static Void local evaluator() { /* evaluate expr and print value */
1704 volatile Kinds ks = NIL;
1705 volatile Module evalMod = allocEvalModule();
1706 volatile Module currMod = currentModule;
1707 setCurrModule(evalMod);
1710 defaultDefns = combined ? stdDefaults : evalDefaults;
1712 setBreakAction ( HugsLongjmpOnBreak );
1713 if (setjmp(catch_error)==0) {
1717 type = typeCheckExp(TRUE);
1719 /* if an exception happens, we arrive here */
1720 setBreakAction ( HugsIgnoreBreak );
1721 goto cleanup_and_return;
1724 setBreakAction ( HugsIgnoreBreak );
1725 if (isPolyType(type)) {
1726 ks = polySigOf(type);
1727 bd = monotypeOf(type);
1732 if (whatIs(bd)==QUAL) {
1734 ERRMSG(0) "Unresolved overloading" ETHEN
1735 ERRTEXT "\n*** Type : " ETHEN ERRTYPE(type);
1736 ERRTEXT "\n*** Expression : " ETHEN ERREXPR(inputExpr);
1739 goto cleanup_and_return;
1743 if (isProgType(ks,bd)) {
1744 inputExpr = ap(nameRunIO_toplevel,inputExpr);
1748 Cell d = provePred(ks,NIL,ap(classShow,bd));
1751 ERRMSG(0) "Cannot find \"show\" function for:" ETHEN
1752 ERRTEXT "\n*** expression : " ETHEN ERREXPR(inputExpr);
1753 ERRTEXT "\n*** of type : " ETHEN ERRTYPE(type);
1756 goto cleanup_and_return;
1758 inputExpr = ap2(nameShow, d,inputExpr);
1759 inputExpr = ap (namePutStr, inputExpr);
1760 inputExpr = ap (nameRunIO_toplevel, inputExpr);
1762 evalExp(); printf("\n");
1765 printType(stdout,type);
1772 printf ( "result type is " );
1773 printType ( stdout, type );
1781 setBreakAction ( HugsIgnoreBreak );
1782 nukeModule(evalMod);
1783 setCurrModule(currMod);
1784 setCurrentFile(currMod);
1789 /* --------------------------------------------------------------------------
1790 * Print type of input expression:
1791 * ------------------------------------------------------------------------*/
1793 static Void showtype ( void ) { /* print type of expression (if any)*/
1796 volatile Module evalMod = allocEvalModule();
1797 volatile Module currMod = currentModule;
1798 setCurrModule(evalMod);
1800 if (setjmp(catch_error)==0) {
1804 defaultDefns = evalDefaults;
1805 type = typeCheckExp(FALSE);
1806 printExp(stdout,inputExpr);
1808 printType(stdout,type);
1811 /* if an exception happens, we arrive here */
1814 nukeModule(evalMod);
1815 setCurrModule(currMod);
1819 static Void local browseit(mod,t,all)
1826 Printf("module %s where\n",textToStr(module(mod).text));
1827 for (cs = module(mod).names; nonNull(cs); cs=tl(cs)) {
1829 /* only look at things defined in this module,
1830 unless `all' flag is set */
1831 if (all || name(nm).mod == mod) {
1832 /* unwanted artifacts, like lambda lifted values,
1833 are in the list of names, but have no types */
1834 if (nonNull(name(nm).type)) {
1835 printExp(stdout,nm);
1837 printType(stdout,name(nm).type);
1839 Printf(" -- data constructor");
1840 } else if (isMfun(nm)) {
1841 Printf(" -- class member");
1842 } else if (isSfun(nm)) {
1843 Printf(" -- selector function");
1851 Printf("Unknown module %s\n",t);
1856 static Void local browse() { /* browse modules */
1857 Int count = 0; /* or give menu of commands */
1861 for (; (s=readFilename())!=0; count++)
1862 if (strcmp(s,"all") == 0) {
1866 browseit(findModule(findText(s)),s,all);
1868 browseit(currentModule,NULL,all);
1872 #if EXPLAIN_INSTANCE_RESOLUTION
1873 static Void local xplain() { /* print type of expression (if any)*/
1875 Bool sir = showInstRes;
1877 setCurrModule(findEvalModule());
1878 startNewScript(0); /* Enables recovery of storage */
1879 /* allocated during evaluation */
1883 d = provePred(NIL,NIL,hd(inputContext));
1885 fprintf(stdout, "not Sat\n");
1887 fprintf(stdout, "Sat\n");
1893 /* --------------------------------------------------------------------------
1894 * Enhanced help system: print current list of scripts or give information
1896 * ------------------------------------------------------------------------*/
1898 static String local objToStr(m,c)
1901 #if 1 || DISPLAY_QUANTIFIERS
1902 static char newVar[60];
1903 switch (whatIs(c)) {
1904 case NAME : if (m == name(c).mod) {
1905 sprintf(newVar,"%s", textToStr(name(c).text));
1907 sprintf(newVar,"%s.%s",
1908 textToStr(module(name(c).mod).text),
1909 textToStr(name(c).text));
1913 case TYCON : if (m == tycon(c).mod) {
1914 sprintf(newVar,"%s", textToStr(tycon(c).text));
1916 sprintf(newVar,"%s.%s",
1917 textToStr(module(tycon(c).mod).text),
1918 textToStr(tycon(c).text));
1922 case CLASS : if (m == cclass(c).mod) {
1923 sprintf(newVar,"%s", textToStr(cclass(c).text));
1925 sprintf(newVar,"%s.%s",
1926 textToStr(module(cclass(c).mod).text),
1927 textToStr(cclass(c).text));
1931 default : internal("objToStr");
1935 static char newVar[33];
1936 switch (whatIs(c)) {
1937 case NAME : sprintf(newVar,"%s", textToStr(name(c).text));
1940 case TYCON : sprintf(newVar,"%s", textToStr(tycon(c).text));
1943 case CLASS : sprintf(newVar,"%s", textToStr(cclass(c).text));
1946 default : internal("objToStr");
1954 static Void dumpStg ( void )
1960 setCurrModule(findEvalModule());
1965 /* request to locate a symbol by name */
1966 if (s && (*s == '?')) {
1967 Text t = findText(s+1);
1968 locateSymbolByName(t);
1972 /* request to dump a bit of the heap */
1973 if (s && (*s == '-' || isdigit(*s))) {
1980 /* request to dump a symbol table entry */
1982 || !(*s == 't' || *s == 'n' || *s == 'c' || *s == 'i')
1983 || !isdigit(s[1])) {
1984 fprintf(stderr, ":d -- bad request `%s'\n", s );
1989 case 't': dumpTycon(i); break;
1990 case 'n': dumpName(i); break;
1991 case 'c': dumpClass(i); break;
1992 case 'i': dumpInst(i); break;
1993 default: fprintf(stderr, ":d -- `%c' not implemented\n", *s );
1999 static Void local dumpStg( void ) { /* print STG stuff */
2004 Cell v; /* really StgVar */
2005 setCurrModule(findEvalModule());
2007 for (; (s=readFilename())!=0;) {
2010 /* find the name while ignoring module scopes */
2011 for (i=NAMEMIN; i<nameHw; i++)
2012 if (name(i).text == t) n = i;
2014 /* perhaps it's an "idNNNNNN" thing? */
2017 s[0]=='i' && s[1]=='d' && isdigit(s[2])) {
2020 while (isdigit(s[i])) {
2021 v = v * 10 + (s[i]-'0');
2025 n = nameFromStgVar(v);
2028 if (isNull(n) && whatIs(v)==STGVAR) {
2029 Printf ( "\n{- `%s' has no nametable entry -}\n", s );
2030 printStg(stderr, v );
2033 Printf ( "Unknown reference `%s'\n", s );
2036 Printf ( "Not a Name: `%s'\n", s );
2038 if (isNull(name(n).stgVar)) {
2039 Printf ( "Doesn't have a STG tree: %s\n", s );
2041 Printf ( "\n{- stgVar of `%s' is id%d -}\n", s, -name(n).stgVar);
2042 printStg(stderr, name(n).stgVar);
2048 static Void local info() { /* describe objects */
2049 Int count = 0; /* or give menu of commands */
2052 for (; (s=readFilename())!=0; count++) {
2053 describe(findText(s));
2056 /* whatScripts(); */
2061 static Void local describe(t) /* describe an object */
2063 Tycon tc = findTycon(t);
2064 Class cl = findClass(t);
2065 Name nm = findName(t);
2067 if (nonNull(tc)) { /* as a type constructor */
2071 for (i=0; i<tycon(tc).arity; ++i) {
2072 t = ap(t,mkOffset(i));
2074 Printf("-- type constructor");
2076 Printf(" with kind ");
2077 printKind(stdout,tycon(tc).kind);
2080 switch (tycon(tc).what) {
2081 case SYNONYM : Printf("type ");
2082 printType(stdout,t);
2084 printType(stdout,tycon(tc).defn);
2088 case DATATYPE : { List cs = tycon(tc).defn;
2089 if (tycon(tc).what==DATATYPE) {
2094 printType(stdout,t);
2096 mapProc(printSyntax,cs);
2098 Printf("\n-- constructors:");
2100 for (; hasCfun(cs); cs=tl(cs)) {
2102 printExp(stdout,hd(cs));
2104 printType(stdout,name(hd(cs)).type);
2107 Printf("\n-- selectors:");
2109 for (; nonNull(cs); cs=tl(cs)) {
2111 printExp(stdout,hd(cs));
2113 printType(stdout,name(hd(cs)).type);
2118 case RESTRICTSYN : Printf("type ");
2119 printType(stdout,t);
2120 Printf(" = <restricted>");
2124 if (nonNull(in=findFirstInst(tc))) {
2125 Printf("\n-- instances:\n");
2128 in = findNextInst(tc,in);
2129 } while (nonNull(in));
2134 if (nonNull(cl)) { /* as a class */
2135 List ins = cclass(cl).instances;
2136 Kinds ks = cclass(cl).kinds;
2137 if (nonNull(ks) && isNull(tl(ks)) && hd(ks)==STAR) {
2138 Printf("-- type class");
2140 Printf("-- constructor class");
2142 Printf(" with arity ");
2143 printKinds(stdout,ks);
2147 mapProc(printSyntax,cclass(cl).members);
2149 if (nonNull(cclass(cl).supers)) {
2150 printContext(stdout,cclass(cl).supers);
2153 printPred(stdout,cclass(cl).head);
2155 if (nonNull(cclass(cl).fds)) {
2156 List fds = cclass(cl).fds;
2158 for (; nonNull(fds); fds=tl(fds)) {
2160 printFD(stdout,hd(fds));
2165 if (nonNull(cclass(cl).members)) {
2166 List ms = cclass(cl).members;
2169 Type t = name(hd(ms)).type;
2170 if (isPolyType(t)) {
2174 printExp(stdout,hd(ms));
2176 if (isNull(tl(fst(snd(t))))) {
2179 t = ap(QUAL,pair(tl(fst(snd(t))),snd(snd(t))));
2181 printType(stdout,t);
2183 } while (nonNull(ms));
2187 Printf("\n-- instances:\n");
2191 } while (nonNull(ins));
2196 if (nonNull(nm)) { /* as a function/name */
2198 printExp(stdout,nm);
2200 if (nonNull(name(nm).type)) {
2201 printType(stdout,name(nm).type);
2203 Printf("<unknown type>");
2206 Printf(" -- data constructor");
2207 } else if (isMfun(nm)) {
2208 Printf(" -- class member");
2209 } else if (isSfun(nm)) {
2210 Printf(" -- selector function");
2216 if (isNull(tc) && isNull(cl) && isNull(nm)) {
2217 Printf("Unknown reference `%s'\n",textToStr(t));
2221 static Void local printSyntax(nm)
2223 Syntax sy = syntaxOf(nm);
2224 Text t = name(nm).text;
2225 String s = textToStr(t);
2226 if (sy != defaultSyntax(t)) {
2228 switch (assocOf(sy)) {
2229 case LEFT_ASS : Putchar('l'); break;
2230 case RIGHT_ASS : Putchar('r'); break;
2231 case NON_ASS : break;
2233 Printf(" %i ",precOf(sy));
2234 if (isascii((int)(*s)) && isalpha((int)(*s))) {
2243 static Void local showInst(in) /* Display instance decl header */
2245 Printf("instance ");
2246 if (nonNull(inst(in).specifics)) {
2247 printContext(stdout,inst(in).specifics);
2250 printPred(stdout,inst(in).head);
2254 /* --------------------------------------------------------------------------
2255 * List all names currently in scope:
2256 * ------------------------------------------------------------------------*/
2258 static Void local listNames() { /* list names matching optional pat*/
2259 String pat = readFilename();
2261 Int width = getTerminalWidth() - 1;
2264 Module mod = currentModule;
2266 if (pat) { /* First gather names to list */
2268 names = addNamesMatching(pat,names);
2269 } while ((pat=readFilename())!=0);
2271 names = addNamesMatching((String)0,names);
2273 if (isNull(names)) { /* Then print them out */
2275 ERRMSG(0) "No names selected"
2279 for (termPos=0; nonNull(names); names=tl(names)) {
2280 String s = objToStr(mod,hd(names));
2282 if (termPos+1+l>width) {
2285 } else if (termPos>0) {
2293 Printf("\n(%d names listed)\n", count);
2296 /* --------------------------------------------------------------------------
2297 * print a prompt and read a line of input:
2298 * ------------------------------------------------------------------------*/
2300 static Void local promptForInput(moduleName)
2301 String moduleName; {
2302 char promptBuffer[1000];
2304 /* This is portable but could overflow buffer */
2305 sprintf(promptBuffer,prompt,moduleName);
2307 /* Works on ANSI C - but pre-ANSI compilers return a pointer to
2308 * promptBuffer instead.
2310 if (sprintf(promptBuffer,prompt,moduleName) >= 1000) {
2311 /* Reset prompt to a safe default to avoid an infinite loop */
2313 prompt = strCopy("? ");
2314 internal("Combined prompt and evaluation module name too long");
2318 stringInput("main\0"); else
2319 consoleInput(promptBuffer);
2322 /* --------------------------------------------------------------------------
2323 * main read-eval-print loop, with error trapping:
2324 * ------------------------------------------------------------------------*/
2326 static Void local interpreter(argc,argv)/* main interpreter loop */
2330 List modConIds; /* :: [CONID] */
2334 setBreakAction ( HugsIgnoreBreak );
2335 modConIds = initialize(argc,argv); /* the initial modules to load */
2336 setBreakAction ( HugsIgnoreBreak );
2337 prelOK = loadThePrelude();
2341 fprintf(stderr, "hugs +Q: fatal error: can't load the Prelude.\n" );
2343 fprintf(stderr, "hugs: fatal error: can't load the Prelude.\n" );
2347 if (combined) everybody(POSTPREL);
2348 loadActions(modConIds);
2351 for (; nonNull(modConIds); modConIds=tl(modConIds))
2352 if (!elemMG(hd(modConIds))) {
2354 "hugs +Q: compilation failed -- can't run `main'\n" );
2361 /* initialize calls startupHaskell, which trashes our signal handlers */
2362 setBreakAction ( HugsIgnoreBreak );
2367 everybody(RESET); /* reset to sensible initial state */
2369 promptForInput(textToStr(module(currentModule).text));
2371 cmd = readCommand(cmds, (Char)':', (Char)'!');
2373 case EDIT : editor();
2377 case LOAD : modConIds = NIL;
2378 while ((s=readFilename())!=0)
2379 modConIds = cons(mkCon(findText(s)),modConIds);
2380 loadActions(modConIds);
2383 case ALSO : modConIds = NIL;
2384 while ((s=readFilename())!=0)
2385 modConIds = cons(mkCon(findText(s)),modConIds);
2386 addActions(modConIds);
2389 case RELOAD : refreshActions(NIL,FALSE);
2394 case EVAL : evaluator();
2396 case TYPEOF : showtype();
2398 case BROWSE : browse();
2400 #if EXPLAIN_INSTANCE_RESOLUTION
2401 case XPLAIN : xplain();
2404 case NAMES : listNames();
2408 case BADCMD : guidance();
2413 #ifdef CRUDE_PROFILING
2417 case SYSTEM : if (shellEsc(readLine()))
2418 Printf("Warning: Shell escape terminated abnormally\n");
2420 case CHGDIR : changeDir();
2424 case PNTVER: Printf("-- Hugs Version %s\n",
2427 case DUMP : dumpStg();
2430 case COLLECT: consGC = FALSE;
2433 Printf("Garbage collection recovered %d cells\n",
2439 if (autoMain) break;
2443 /* --------------------------------------------------------------------------
2444 * Display progress towards goal:
2445 * ------------------------------------------------------------------------*/
2447 static Target currTarget;
2448 static Bool aiming = FALSE;
2451 static Int charCount;
2453 Void setGoal(what, t) /* Set goal for what to be t */
2458 #if EXPLAIN_INSTANCE_RESOLUTION
2462 currTarget = (t?t:1);
2465 currPos = strlen(what);
2466 maxPos = getTerminalWidth() - 1;
2470 for (charCount=0; *what; charCount++)
2475 Void soFar(t) /* Indicate progress towards goal */
2476 Target t; { /* has now reached t */
2479 #if EXPLAIN_INSTANCE_RESOLUTION
2484 Int newPos = (Int)((maxPos * ((long)t))/currTarget);
2489 if (newPos>currPos) {
2492 while (newPos>++currPos);
2499 Void done() { /* Goal has now been achieved */
2502 #if EXPLAIN_INSTANCE_RESOLUTION
2507 while (maxPos>currPos++)
2512 for (; charCount>0; charCount--) {
2521 static Void local failed() { /* Goal cannot be reached due to */
2522 if (aiming) { /* errors */
2529 /* --------------------------------------------------------------------------
2531 * ------------------------------------------------------------------------*/
2533 static Void local stopAnyPrinting() { /* terminate printing of expression,*/
2534 if (printing) { /* after successful termination or */
2535 printing = FALSE; /* runtime error (e.g. interrupt) */
2538 #define plural(v) v, (v==1?"":"s")
2539 Printf("%lu cell%s",plural(numCells));
2541 Printf(", %u garbage collection%s",plural(numGcs));
2550 Cell errAssert(l) /* message to use when raising asserts, etc */
2554 str = mkStr(findText(currentFile));
2556 str = mkStr(findText(""));
2558 return (ap2(nameTangleMessage,str,mkInt(l)));
2561 Void errHead(l) /* print start of error message */
2563 failed(); /* failed to reach target ... */
2565 FPrintf(errorStream,"ERROR");
2568 FPrintf(errorStream," \"%s\"", currentFile);
2569 setLastEdit(currentFile,l);
2570 if (l) FPrintf(errorStream," (line %d)",l);
2573 FPrintf(errorStream,": ");
2574 FFlush(errorStream);
2577 Void errFail() { /* terminate error message and */
2578 Putc('\n',errorStream); /* produce exception to return to */
2579 FFlush(errorStream); /* main command loop */
2580 longjmp(catch_error,1);
2583 Void errFail_no_longjmp() { /* terminate error message but */
2584 Putc('\n',errorStream); /* don't produce an exception */
2585 FFlush(errorStream);
2588 Void errAbort() { /* altern. form of error handling */
2589 failed(); /* used when suitable error message*/
2590 stopAnyPrinting(); /* has already been printed */
2594 Void internal(msg) /* handle internal error */
2598 Printf("INTERNAL ERROR: %s\n",msg);
2601 longjmp(catch_error,1);
2604 Void fatal(msg) /* handle fatal error */
2607 Printf("\nFATAL ERROR: %s\n",msg);
2613 /* --------------------------------------------------------------------------
2614 * Read value from environment variable or registry:
2615 * ------------------------------------------------------------------------*/
2617 String fromEnv(var,def) /* return value of: */
2618 String var; /* environment variable named by var */
2619 String def; { /* or: default value given by def */
2620 String s = getenv(var);
2621 return (s ? s : def);
2624 /* --------------------------------------------------------------------------
2625 * String manipulation routines:
2626 * ------------------------------------------------------------------------*/
2628 static String local strCopy(s) /* make malloced copy of a string */
2632 if ((t=(char *)malloc(strlen(s)+1))==0) {
2633 ERRMSG(0) "String storage space exhausted"
2636 for (r=t; (*r++ = *s++)!=0; ) {
2644 /* --------------------------------------------------------------------------
2646 * We can redirect compiler output (prompts, error messages, etc) by
2647 * tweaking these functions.
2648 * ------------------------------------------------------------------------*/
2650 #ifdef HAVE_STDARG_H
2653 #include <varargs.h>
2656 Void hugsEnableOutput(f)
2661 #ifdef HAVE_STDARG_H
2662 Void hugsPrintf(const char *fmt, ...) {
2663 va_list ap; /* pointer into argument list */
2664 va_start(ap, fmt); /* make ap point to first arg after fmt */
2665 if (!disableOutput) {
2669 va_end(ap); /* clean up */
2672 Void hugsPrintf(fmt, va_alist)
2675 va_list ap; /* pointer into argument list */
2676 va_start(ap); /* make ap point to first arg after fmt */
2677 if (!disableOutput) {
2681 va_end(ap); /* clean up */
2687 if (!disableOutput) {
2693 Void hugsFlushStdout() {
2694 if (!disableOutput) {
2701 if (!disableOutput) {
2706 #ifdef HAVE_STDARG_H
2707 Void hugsFPrintf(FILE *fp, const char* fmt, ...) {
2710 if (!disableOutput) {
2711 vfprintf(fp, fmt, ap);
2717 Void hugsFPrintf(FILE *fp, const char* fmt, va_list)
2723 if (!disableOutput) {
2724 vfprintf(fp, fmt, ap);
2731 Void hugsPutc(c, fp)
2734 if (!disableOutput) {
2740 /* --------------------------------------------------------------------------
2741 * Send message to each component of system:
2742 * ------------------------------------------------------------------------*/
2744 Void everybody(what) /* send command `what' to each component of*/
2745 Int what; { /* system to respond as appropriate ... */
2747 fprintf ( stderr, "EVERYBODY %d\n", what );
2749 machdep(what); /* The order of calling each component is */
2750 storage(what); /* important for the PREPREL command */
2753 translateControl(what);
2755 staticAnalysis(what);
2756 deriveControl(what);
2763 mark(targetModules);
2767 /*-------------------------------------------------------------------------*/