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/05 14:13:58 $
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 );
74 static String local optionsToStr ( Void );
76 static Void local readOptions ( String );
77 static Bool local processOption ( String );
78 static Void local setHeapSize ( String );
79 static Int local argToInt ( String );
81 static Void local setLastEdit ( String,Int );
82 static Void local failed ( Void );
83 static String local strCopy ( String );
84 static Void local browseit ( Module,String,Bool );
85 static Void local browse ( Void );
87 /* --------------------------------------------------------------------------
88 * Machine dependent code for Hugs interpreter:
89 * ------------------------------------------------------------------------*/
93 /* --------------------------------------------------------------------------
95 * ------------------------------------------------------------------------*/
97 static Bool printing = FALSE; /* TRUE => currently printing value*/
98 static Bool showStats = FALSE; /* TRUE => print stats after eval */
99 static Bool listScripts = TRUE; /* TRUE => list scripts after loading*/
100 static Bool addType = FALSE; /* TRUE => print type with value */
101 static Bool useDots = RISCOS; /* TRUE => use dots in progress */
102 static Bool quiet = FALSE; /* TRUE => don't show progress */
103 static Bool lastWasObject = FALSE;
105 Bool flagAssert = FALSE; /* TRUE => assert False <e> causes
106 an assertion failure */
107 Bool preludeLoaded = FALSE;
108 Bool debugSC = FALSE;
109 Bool combined = FALSE;
111 Module moduleBeingParsed; /* so the parser (topModule) knows */
112 static char* currentFile; /* Name of current file, or NULL */
113 static char currentFileName[1000]; /* name is stored here if it exists*/
115 static Bool autoMain = FALSE;
116 static String lastEdit = 0; /* Name of script to edit (if any) */
117 static Int lastEdLine = 0; /* Editor line number (if possible)*/
118 static String prompt = 0; /* Prompt string */
119 static Int hpSize = DEFAULTHEAP; /* Desired heap size */
120 static Bool disableOutput = FALSE; /* TRUE => quiet */
121 String hugsEdit = 0; /* String for editor command */
122 String hugsPath = 0; /* String for file search path */
124 List ifaces_outstanding = NIL;
127 /* --------------------------------------------------------------------------
129 * ------------------------------------------------------------------------*/
131 #ifndef NO_MAIN /* we omit main when building the "Hugs server" */
133 Main main ( Int, String [] ); /* now every func has a prototype */
138 #ifdef HAVE_CONSOLE_H /* Macintosh port */
140 _fcreator = 'R*ch'; /* // 'KAHL'; //'*TEX'; //'ttxt'; */
142 console_options.top = 50;
143 console_options.left = 20;
145 console_options.nrows = 32;
146 console_options.ncols = 80;
148 console_options.pause_atexit = 1;
149 console_options.title = "\pHugs";
151 console_options.procID = 5;
152 argc = ccommand(&argv);
155 CStackBase = &argc; /* Save stack base for use in gc */
159 checkBytecodeCount(); /* check for too many bytecodes */
163 /* If first arg is +Q or -Q, be entirely silent, and automatically run
164 main after loading scripts. Useful for running the nofib suite. */
165 if (argc > 1 && (strcmp(argv[1],"+Q") == 0 || strcmp(argv[1],"-Q")==0)) {
167 if (strcmp(argv[1],"-Q") == 0) {
172 Printf("__ __ __ __ ____ ___ _________________________________________\n");
173 Printf("|| || || || || || ||__ STGHugs: Based on the Haskell 98 standard\n");
174 Printf("||___|| ||__|| ||__|| __|| Copyright (c) 1994-1999\n");
175 Printf("||---|| ___|| World Wide Web: http://haskell.org/hugs\n");
176 Printf("|| || Report bugs to: hugs-bugs@haskell.org\n");
177 Printf("|| || Version: %s _________________________________________\n\n",HUGS_VERSION);
179 /* Get the absolute path to the directory containing the hugs
180 executable, so that we know where the Prelude and nHandle.so/.dll are.
181 We do this by reading env var STGHUGSDIR. This needs to succeed, so
182 setInstallDir won't return unless it succeeds.
184 setInstallDir ( argv[0] );
187 Printf(" Ported to Macintosh by Hans Aberg, compiled " __DATE__ ".\n\n");
190 interpreter(argc,argv);
191 Printf("[Leaving Hugs]\n");
202 /* --------------------------------------------------------------------------
203 * Initialization, interpret command line args and read prelude:
204 * ------------------------------------------------------------------------*/
206 static List /*CONID*/ initialize(argc,argv) /* Interpreter initialization */
210 char argv_0_orig[1000];
213 setLastEdit((String)0,0);
220 hugsEdit = strCopy(fromEnv("EDITOR",NULL));
222 hugsPath = strCopy(HUGSPATH);
223 readOptions("-p\"%s> \" -r$$");
225 projectPath = strCopy(readRegChildStrings(HKEY_LOCAL_MACHINE,ProjectRoot,
226 "HUGSPATH", PATHSEP, ""));
227 readOptions(readRegString(HKEY_LOCAL_MACHINE,HugsRoot,"Options",""));
228 readOptions(readRegString(HKEY_CURRENT_USER, HugsRoot,"Options",""));
229 #endif /* USE_REGISTRY */
230 readOptions(fromEnv("STGHUGSFLAGS",""));
232 strncpy(argv_0_orig,argv[0],1000); /* startupHaskell mangles argv[0] */
233 startupHaskell (argc,argv,NULL);
239 char exe_name[N_INSTALLDIR + 6];
240 strcpy(exe_name, installDir);
241 strcat(exe_name, "hugs");
242 DEBUG_LoadSymbols(exe_name);
246 /* Find out early on if we're in combined mode or not.
247 everybody(PREPREL) needs to know this.
249 for (i=1; i < argc; ++i) {
250 if (strcmp(argv[i], "--")==0) break;
251 if (strcmp(argv[i], "-c")==0) combined = FALSE;
252 if (strcmp(argv[i], "+c")==0) combined = TRUE;
256 initialModules = NIL;
258 for (i=1; i < argc; ++i) { /* process command line arguments */
259 if (strcmp(argv[i], "--")==0) break;
260 if (argv[i] && argv[i][0]/* workaround for /bin/sh silliness*/
261 && !processOption(argv[i])) {
263 = cons ( mkCon(findText(argv[i])), initialModules );
268 Printf("Haskell 98 mode: Restart with command line option -98"
269 " to enable extensions\n");
271 Printf("Hugs mode: Restart with command line option +98 for"
272 " Haskell 98 mode\n");
276 Printf("Combined mode: Restart with command line -c for"
277 " standalone mode\n\n" );
279 Printf("Standalone mode: Restart with command line +c for"
280 " combined mode\n\n" );
284 return initialModules;
287 /* --------------------------------------------------------------------------
288 * Command line options:
289 * ------------------------------------------------------------------------*/
291 struct options { /* command line option toggles */
292 char c; /* table defined in main app. */
297 extern struct options toggle[];
299 static Void local toggleSet(c,state) /* Set command line toggle */
303 for (i=0; toggle[i].c; ++i)
304 if (toggle[i].c == c) {
305 *toggle[i].flag = state;
308 ERRMSG(0) "Unknown toggle `%c'", c
312 static Void local togglesIn(state) /* Print current list of toggles in*/
313 Bool state; { /* given state */
316 for (i=0; toggle[i].c; ++i)
317 if (*toggle[i].flag == state && (!haskell98 || toggle[i].h98)) {
319 Putchar((char)(state ? '+' : '-'));
320 Putchar(toggle[i].c);
327 static Void local optionInfo() { /* Print information about command */
328 static String fmts = "%-5s%s\n"; /* line settings */
329 static String fmtc = "%-5c%s\n";
332 Printf("TOGGLES: groups begin with +/- to turn options on/off resp.\n");
333 for (i=0; toggle[i].c; ++i) {
334 if (!haskell98 || toggle[i].h98) {
335 Printf(fmtc,toggle[i].c,toggle[i].description);
339 Printf("\nOTHER OPTIONS: (leading + or - makes no difference)\n");
340 Printf(fmts,"hnum","Set heap size (cannot be changed within Hugs)");
341 Printf(fmts,"pstr","Set prompt string to str");
342 Printf(fmts,"rstr","Set repeat last expression string to str");
343 Printf(fmts,"Pstr","Set search path for modules to str");
344 Printf(fmts,"Estr","Use editor setting given by str");
345 Printf(fmts,"cnum","Set constraint cutoff limit");
346 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
347 Printf(fmts,"Fstr","Set preprocessor filter to str");
350 Printf("\nCurrent settings: ");
353 Printf("-h%d",heapSize);
357 printString(repeatStr);
358 Printf(" -c%d",cutoff);
359 Printf("\nSearch path : -P");
360 printString(hugsPath);
363 if (projectPath!=NULL) {
364 Printf("\nProject Path : %s",projectPath);
367 Printf("\nEditor setting : -E");
368 printString(hugsEdit);
369 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
370 Printf("\nPreprocessor : -F");
371 printString(preprocessor);
373 Printf("\nCompatibility : %s", haskell98 ? "Haskell 98 (+98)"
374 : "Hugs Extensions (-98)");
386 #define PUTInt(optc,i) \
387 sprintf(next,"-%c%d",optc,i); \
390 #define PUTStr(c,s) \
391 next=PUTStr_aux(next,c,s)
393 static String local PUTStr_aux ( String,Char, String));
395 static String local PUTStr_aux(next,c,s)
401 sprintf(next,"-%c\"",c);
404 PUTS(unlexChar(*t,'"'));
412 static String local optionsToStr() { /* convert options to string */
413 static char buffer[2000];
414 String next = buffer;
417 for (i=0; toggle[i].c; ++i) {
418 PUTC(*toggle[i].flag ? '+' : '-');
422 PUTS(haskell98 ? "+98 " : "-98 ");
423 PUTInt('h',hpSize); PUTC(' ');
425 PUTStr('r',repeatStr);
426 PUTStr('P',hugsPath);
427 PUTStr('E',hugsEdit);
428 PUTInt('c',cutoff); PUTC(' ');
429 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
430 PUTStr('F',preprocessor);
435 #endif /* USE_REGISTRY */
442 static Void local readOptions(options) /* read options from string */
446 stringInput(options);
447 while ((s=readFilename())!=0) {
448 if (*s && !processOption(s)) {
449 ERRMSG(0) "Option string must begin with `+' or `-'"
456 static Bool local processOption(s) /* process string s for options, */
457 String s; { /* return FALSE if none found. */
469 case 'Q' : break; /* already handled */
471 case 'p' : if (s[1]) {
472 if (prompt) free(prompt);
473 prompt = strCopy(s+1);
477 case 'r' : if (s[1]) {
478 if (repeatStr) free(repeatStr);
479 repeatStr = strCopy(s+1);
484 String p = substPath(s+1,hugsPath ? hugsPath : "");
485 if (hugsPath) free(hugsPath);
490 case 'E' : if (hugsEdit) free(hugsEdit);
491 hugsEdit = strCopy(s+1);
494 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
495 case 'F' : if (preprocessor) free(preprocessor);
496 preprocessor = strCopy(s+1);
500 case 'h' : setHeapSize(s+1);
503 case 'c' : /* don't do anything, since pre-scan of args
504 will have got it already */
507 case 'D' : /* hack */
509 extern void setRtsFlags( int x );
510 setRtsFlags(argToInt(s+1));
514 default : if (strcmp("98",s)==0) {
515 if (initDone && ((state && !haskell98) ||
516 (!state && haskell98))) {
518 "Haskell 98 compatibility cannot be changed"
519 " while the interpreter is running\n");
532 static Void local setHeapSize(s)
535 hpSize = argToInt(s);
536 if (hpSize < MINIMUMHEAP)
537 hpSize = MINIMUMHEAP;
538 else if (MAXIMUMHEAP && hpSize > MAXIMUMHEAP)
539 hpSize = MAXIMUMHEAP;
540 if (initDone && hpSize != heapSize) {
541 /* ToDo: should this use a message box in winhugs? */
543 FPrintf(stderr,"Change to heap size will not take effect until you rerun Hugs\n");
545 FPrintf(stderr,"You cannot change heap size from inside Hugs\n");
553 static Int local argToInt(s) /* read integer from argument str */
558 if (*s=='\0' || !isascii((int)(*s)) || !isdigit((int)(*s))) {
559 ERRMSG(0) "Missing integer in option setting \"%s\"", t
564 Int d = (*s++) - '0';
565 if (n > ((MAXPOSINT - d)/10)) {
566 ERRMSG(0) "Option setting \"%s\" is too large", t
570 } while (isascii((int)(*s)) && isdigit((int)(*s)));
572 if (*s=='K' || *s=='k') {
573 if (n > (MAXPOSINT/1000)) {
574 ERRMSG(0) "Option setting \"%s\" is too large", t
581 #if MAXPOSINT > 1000000 /* waste of time on 16 bit systems */
582 if (*s=='M' || *s=='m') {
583 if (n > (MAXPOSINT/1000000)) {
584 ERRMSG(0) "Option setting \"%s\" is too large", t
592 #if MAXPOSINT > 1000000000
593 if (*s=='G' || *s=='g') {
594 if (n > (MAXPOSINT/1000000000)) {
595 ERRMSG(0) "Option setting \"%s\" is too large", t
604 ERRMSG(0) "Unwanted characters after option setting \"%s\"", t
611 /* --------------------------------------------------------------------------
612 * Print Menu of list of commands:
613 * ------------------------------------------------------------------------*/
615 static struct cmd cmds[] = {
616 {":?", HELP}, {":cd", CHGDIR}, {":also", ALSO},
617 {":type", TYPEOF}, {":!", SYSTEM}, {":load", LOAD},
618 {":reload", RELOAD}, {":gc", COLLECT}, {":edit", EDIT},
619 {":quit", QUIT}, {":set", SET}, {":find", FIND},
620 {":names", NAMES}, {":info", INFO}, {":project", PROJECT},
621 {":dump", DUMP}, {":ztats", STATS},
622 {":module",SETMODULE},
624 #if EXPLAIN_INSTANCE_RESOLUTION
627 {":version", PNTVER},
632 static Void local menu() {
633 Printf("LIST OF COMMANDS: Any command may be abbreviated to :c where\n");
634 Printf("c is the first character in the full name.\n\n");
635 Printf(":load <filenames> load modules from specified files\n");
636 Printf(":load clear all files except prelude\n");
637 Printf(":also <filenames> read additional modules\n");
638 Printf(":reload repeat last load command\n");
639 Printf(":project <filename> use project file\n");
640 Printf(":edit <filename> edit file\n");
641 Printf(":edit edit last module\n");
642 Printf(":module <module> set module for evaluating expressions\n");
643 Printf("<expr> evaluate expression\n");
644 Printf(":type <expr> print type of expression\n");
645 Printf(":? display this list of commands\n");
646 Printf(":set <options> set command line options\n");
647 Printf(":set help on command line options\n");
648 Printf(":names [pat] list names currently in scope\n");
649 Printf(":info <names> describe named objects\n");
650 Printf(":browse <modules> browse names defined in <modules>\n");
651 #if EXPLAIN_INSTANCE_RESOLUTION
652 Printf(":xplain <context> explain instance resolution for <context>\n");
654 Printf(":find <name> edit module containing definition of name\n");
655 Printf(":!command shell escape\n");
656 Printf(":cd dir change directory\n");
657 Printf(":gc force garbage collection\n");
658 Printf(":version print Hugs version\n");
659 Printf(":dump <name> print STG code for named fn\n");
660 #ifdef CRUDE_PROFILING
661 Printf(":ztats <name> print reduction stats\n");
663 Printf(":quit exit Hugs interpreter\n");
666 static Void local guidance() {
667 Printf("Command not recognised. ");
671 static Void local forHelp() {
672 Printf("Type :? for help\n");
675 /* --------------------------------------------------------------------------
676 * Setting of command line options:
677 * ------------------------------------------------------------------------*/
679 struct options toggle[] = { /* List of command line toggles */
680 {'s', 1, "Print no. reductions/cells after eval", &showStats},
681 {'t', 1, "Print type after evaluation", &addType},
682 {'g', 1, "Print no. cells recovered after gc", &gcMessages},
683 {'l', 1, "Literate modules as default", &literateScripts},
684 {'e', 1, "Warn about errors in literate modules", &literateErrors},
685 {'.', 1, "Print dots to show progress", &useDots},
686 {'q', 1, "Print nothing to show progress", &quiet},
687 {'w', 1, "Always show which modules are loaded", &listScripts},
688 {'k', 1, "Show kind errors in full", &kindExpert},
689 {'o', 0, "Allow overlapping instances", &allowOverlap},
690 {'S', 1, "Debug: show generated SC code", &debugSC},
691 {'a', 1, "Raise exception on assert failure", &flagAssert},
692 #if EXPLAIN_INSTANCE_RESOLUTION
693 {'x', 1, "Explain instance resolution", &showInstRes},
696 {'m', 0, "Use multi instance resolution", &multiInstRes},
701 static Void local set() { /* change command line options from*/
702 String s; /* Hugs command line */
704 if ((s=readFilename())!=0) {
706 if (!processOption(s)) {
707 ERRMSG(0) "Option string must begin with `+' or `-'"
710 } while ((s=readFilename())!=0);
712 writeRegString("Options", optionsToStr());
719 /* --------------------------------------------------------------------------
720 * Change directory command:
721 * ------------------------------------------------------------------------*/
723 static Void local changeDir() { /* change directory */
724 String s = readFilename();
726 ERRMSG(0) "Unable to change to directory \"%s\"", s
732 /* --------------------------------------------------------------------------
734 * ------------------------------------------------------------------------*/
736 static jmp_buf catch_error; /* jump buffer for error trapping */
738 HugsBreakAction currentBreakAction = HugsIgnoreBreak;
740 static void handler_IgnoreBreak ( int sig )
742 setHandler ( handler_IgnoreBreak );
745 static void handler_LongjmpOnBreak ( int sig )
747 setHandler ( handler_LongjmpOnBreak );
748 Printf("{Interrupted!}\n");
749 longjmp(catch_error,1);
752 static void handler_RtsInterrupt ( int sig )
754 setHandler ( handler_RtsInterrupt );
758 HugsBreakAction setBreakAction ( HugsBreakAction newAction )
760 HugsBreakAction tmp = currentBreakAction;
761 currentBreakAction = newAction;
763 case HugsIgnoreBreak:
764 setHandler ( handler_IgnoreBreak ); break;
765 case HugsLongjmpOnBreak:
766 setHandler ( handler_LongjmpOnBreak ); break;
767 case HugsRtsInterrupt:
768 setHandler ( handler_RtsInterrupt ); break;
770 internal("setBreakAction");
776 /* --------------------------------------------------------------------------
777 * The new module chaser, loader, etc
778 * ------------------------------------------------------------------------*/
780 List moduleGraph = NIL;
781 List prelModules = NIL;
782 List targetModules = NIL;
784 static String modeToString ( Cell mode )
787 case FM_SOURCE: return "source";
788 case FM_OBJECT: return "object";
789 case FM_EITHER: return "source or object";
790 default: internal("modeToString");
794 static Cell childMode ( Cell modeMeRequest, Cell modeMeActual )
796 assert(modeMeActual == FM_SOURCE ||
797 modeMeActual == FM_OBJECT);
798 assert(modeMeRequest == FM_SOURCE ||
799 modeMeRequest == FM_OBJECT ||
800 modeMeRequest == FM_EITHER);
801 if (modeMeRequest == FM_SOURCE) return modeMeRequest;
802 if (modeMeRequest == FM_OBJECT) return modeMeRequest;
803 if (modeMeActual == FM_OBJECT) return FM_OBJECT;
804 if (modeMeActual == FM_SOURCE) return FM_EITHER;
805 internal("childMode");
808 static Bool compatibleNewMode ( Cell modeNew, Cell modeExisting )
810 if (modeNew == FM_OBJECT && modeExisting == FM_OBJECT) return TRUE;
811 if (modeNew == FM_SOURCE && modeExisting == FM_SOURCE) return TRUE;
812 if (modeNew == FM_EITHER && modeExisting == FM_OBJECT) return TRUE;
813 if (modeNew == FM_EITHER && modeExisting == FM_SOURCE) return TRUE;
817 static void setCurrentFile ( Module mod )
819 assert(isModule(mod));
820 strncpy(currentFileName, textToStr(module(mod).text), 990);
821 strcat(currentFileName, textToStr(module(mod).srcExt));
822 currentFile = currentFileName;
823 moduleBeingParsed = mod;
826 static void clearCurrentFile ( void )
829 moduleBeingParsed = NIL;
832 static void ppMG ( void )
835 for (t = moduleGraph; nonNull(t); t=tl(t)) {
839 FPrintf ( stderr, " %s\n", textToStr(textOf(snd(u))));
842 FPrintf ( stderr, " {" );
843 for (v = snd(u); nonNull(v); v=tl(v))
844 FPrintf ( stderr, "%s ", textToStr(textOf(hd(v))) );
845 FPrintf ( stderr, "}\n" );
854 static Bool elemMG ( ConId mod )
857 for (gs = moduleGraph; nonNull(gs); gs=tl(gs))
858 switch (whatIs(hd(gs))) {
860 if (textOf(mod)==textOf(snd(hd(gs)))) return TRUE;
863 if (varIsMember(textOf(mod),snd(hd(gs)))) return TRUE;
872 static ConId selectArbitrarilyFromGroup ( Cell group )
874 switch (whatIs(group)) {
875 case GRP_NONREC: return snd(group);
876 case GRP_REC: return hd(snd(group));
877 default: internal("selectArbitrarilyFromGroup");
881 static ConId selectLatestMG ( void )
883 List gs = moduleGraph;
884 if (isNull(gs)) internal("selectLatestMG(1)");
885 while (nonNull(gs) && nonNull(tl(gs))) gs = tl(gs);
886 return selectArbitrarilyFromGroup(hd(gs));
890 static List /* of CONID */ listFromSpecifiedMG ( List mg )
894 for (gs = mg; nonNull(gs); gs=tl(gs)) {
895 switch (whatIs(hd(gs))) {
896 case GRP_REC: cs = appendOnto(cs,snd(hd(gs))); break;
897 case GRP_NONREC: cs = cons(snd(hd(gs)),cs); break;
898 default: internal("listFromSpecifiedMG");
904 static List /* of CONID */ listFromMG ( void )
906 return listFromSpecifiedMG ( moduleGraph );
910 /* Calculate the strongly connected components of modgList
911 and assign them to moduleGraph. Uses the .uses field of
912 each of the modules to build the graph structure.
914 #define SCC modScc /* make scc algorithm for StgVars */
915 #define LOWLINK modLowlink
916 #define DEPENDS(t) snd(t)
917 #define SETDEPENDS(c,v) snd(c)=v
924 static void mgFromList ( List /* of CONID */ modgList )
930 List adjList; /* :: [ (Text, [Text]) ] */
936 for (t = modgList; nonNull(t); t=tl(t)) {
938 mod = findModule(mT);
939 assert(nonNull(mod));
941 for (u = module(mod).uses; nonNull(u); u=tl(u))
942 usesT = cons(textOf(hd(u)),usesT);
944 /* artificially give all modules a dependency on Prelude */
945 if (mT != textPrelude && mT != textPrimPrel)
946 usesT = cons(textPrelude,usesT);
948 adjList = cons(pair(mT,usesT),adjList);
951 /* adjList is now [ (module-text, [modules-which-i-import-text]) ].
952 Modify this so that the adjacency list is a list of pointers
953 back to bits of adjList -- that's what modScc needs.
955 for (t = adjList; nonNull(t); t=tl(t)) {
957 /* for each elem of the adjacency list ... */
958 for (u = snd(hd(t)); nonNull(u); u=tl(u)) {
961 /* find the element of adjList whose fst is a */
962 for (v = adjList; nonNull(v); v=tl(v)) {
964 assert(isText(fst(hd(v))));
965 if (fst(hd(v))==a) break;
967 if (isNull(v)) internal("mgFromList");
968 adj = cons(hd(v),adj);
973 adjList = modScc ( adjList );
974 /* adjList is now [ [(module-text, aux-info-field)] ] */
978 for (t = adjList; nonNull(t); t=tl(t)) {
981 /* scc :: [ (module-text, aux-info-field) ] */
982 for (u = scc; nonNull(u); u=tl(u))
983 hd(u) = mkCon(fst(hd(u)));
986 if (length(scc) > 1) {
989 /* singleton module in scc; does it import itself? */
990 mod = findModule ( textOf(hd(scc)) );
991 assert(nonNull(mod));
993 for (u = module(mod).uses; nonNull(u); u=tl(u))
994 if (textOf(hd(u))==textOf(hd(scc)))
999 moduleGraph = cons( ap(GRP_REC,scc), moduleGraph ); else
1000 moduleGraph = cons( ap(GRP_NONREC,hd(scc)), moduleGraph );
1002 moduleGraph = reverse(moduleGraph);
1006 static List /* of CONID */ getModuleImports ( Cell tree )
1012 for (tes = zthd3(unap(M_MODULE,tree)); nonNull(tes); tes=tl(tes)) {
1014 switch(whatIs(te)) {
1016 use = zfst(unap(M_IMPORT_Q,te));
1018 if (!varIsMember(textOf(use),uses)) uses = cons ( use, uses );
1021 use = zfst(unap(M_IMPORT_UNQ,te));
1023 if (!varIsMember(textOf(use),uses)) uses = cons ( use, uses );
1033 static void processModule ( Module m )
1049 unqualImports = NIL;
1050 foreignImports = NIL;
1051 foreignExports = NIL;
1058 tree = unap(M_MODULE,module(m).tree);
1059 modNm = zfst3(tree);
1061 if (textOf(modNm) != module(m).text) {
1062 ERRMSG(0) "Module name \"%s\" does not match file name \"%s%s\"",
1063 textToStr(textOf(modNm)),
1064 textToStr(module(m).text),
1065 textToStr(module(m).srcExt)
1069 setExportList(zsnd3(tree));
1070 topEnts = zthd3(tree);
1072 for (tes = topEnts; nonNull(tes); tes=tl(tes)) {
1074 assert(isGenPair(te));
1076 switch(whatIs(te)) {
1078 addQualImport(zfst(te2),zsnd(te2));
1081 addUnqualImport(zfst(te2),zsnd(te2));
1084 tyconDefn(zsel14(te2),zsel24(te2),zsel34(te2),zsel44(te2));
1087 classDefn(zsel14(te2),zsel24(te2),zsel34(te2),zsel44(te2));
1090 instDefn(zfst3(te2),zsnd3(te2),zthd3(te2));
1093 defaultDefn(zfst(te2),zsnd(te2));
1096 foreignImport(zsel15(te2),zsel25(te2),zsel35(te2),
1097 zsel45(te2),zsel55(te2));
1100 foreignExport(zsel15(te2),zsel25(te2),zsel35(te2),
1101 zsel45(te2),zsel55(te2));
1103 valDefns = cons(te2,valDefns);
1106 internal("processModule");
1115 static Module parseModuleOrInterface ( ConId mc, Cell modeRequest )
1117 /* Allocate a module-table entry. */
1118 /* Parse the entity and fill in the .tree and .uses entries. */
1121 Bool sAvail; Time sTime; Long sSize;
1122 Bool oiAvail; Time oiTime; Long oSize; Long iSize;
1127 Text mt = textOf(mc);
1128 Module mod = findModule ( mt );
1130 /* fprintf ( stderr, "parseModuleOrInterface `%s' == %d\n",
1131 textToStr(mt),mod); */
1132 if (nonNull(mod) && !module(mod).fake)
1133 internal("parseModuleOrInterface");
1135 module(mod).fake = FALSE;
1138 mod = newModule(mt);
1140 /* This call malloc-ates path; we should deallocate it. */
1141 ok = findFilesForModule (
1142 textToStr(module(mod).text),
1145 &sAvail, &sTime, &sSize,
1146 &oiAvail, &oiTime, &oSize, &iSize
1149 if (!ok) goto cant_find;
1150 if (!sAvail && !oiAvail) goto cant_find;
1152 /* Find out whether to use source or object. */
1153 switch (modeRequest) {
1155 if (!sAvail) goto cant_find;
1159 if (!oiAvail) goto cant_find;
1163 if ( sAvail && !oiAvail) { useSource = TRUE; break; }
1164 if (!sAvail && oiAvail) { useSource = FALSE; break; }
1165 useSource = firstTimeIsLater ( sTime, oiTime ) ? TRUE : FALSE;
1168 internal("parseModuleOrInterface");
1172 /* Actually do the parsing. */
1174 module(mod).srcExt = findText(sExt);
1175 setCurrentFile(mod);
1177 strcat(name, textToStr(mt));
1179 module(mod).tree = parseModule(name,sSize);
1180 module(mod).uses = getModuleImports(module(mod).tree);
1181 module(mod).mode = FM_SOURCE;
1182 module(mod).lastStamp = sTime;
1184 module(mod).srcExt = findText(HI_ENDING);
1185 setCurrentFile(mod);
1187 strcat(name, textToStr(mt));
1188 strcat(name, DLL_ENDING);
1189 module(mod).objName = findText(name);
1190 module(mod).objSize = oSize;
1192 strcat(name, textToStr(mt));
1193 strcat(name, ".u_hi");
1194 module(mod).tree = parseInterface(name,iSize);
1195 module(mod).uses = getInterfaceImports(module(mod).tree);
1196 module(mod).mode = FM_OBJECT;
1197 module(mod).lastStamp = oiTime;
1200 if (path) free(path);
1204 if (path) free(path);
1207 "Can't find %s for module \"%s\"",
1208 modeToString(modeRequest), textToStr(mt)
1213 static void tryLoadGroup ( Cell grp )
1217 switch (whatIs(grp)) {
1219 m = findModule(textOf(snd(grp)));
1221 if (module(m).mode == FM_SOURCE) {
1222 processModule ( m );
1224 processInterfaces ( singleton(snd(grp)) );
1228 for (t = snd(grp); nonNull(t); t=tl(t)) {
1229 m = findModule(textOf(hd(t)));
1231 if (module(m).mode == FM_SOURCE) {
1232 ERRMSG(0) "Source module \"%s\" imports itself recursively",
1233 textToStr(textOf(hd(t)))
1237 processInterfaces ( snd(grp) );
1240 internal("tryLoadGroup");
1245 static void fallBackToPrelModules ( void )
1248 for (m = MODULE_BASE_ADDR;
1249 m < MODULE_BASE_ADDR+tabModuleSz; m++)
1251 && !varIsMember(module(m).text, prelModules))
1256 /* This function catches exceptions in most of the system.
1257 So it's only ok for procedures called from this one
1258 to do EENDs (ie, write error messages). Others should use
1261 static void achieveTargetModules ( Bool loadingThePrelude )
1264 volatile List modgList;
1266 volatile Module mod;
1271 Bool sAvail; Time sTime; Long sSize;
1272 Bool oiAvail; Time oiTime; Long oSize; Long iSize;
1274 volatile Time oisTime;
1275 volatile Bool out_of_date;
1276 volatile List ood_new;
1278 volatile List modgList_new;
1279 volatile List parsedButNotLoaded;
1280 volatile List toChase;
1281 volatile List trans_cl;
1282 volatile List trans_cl_new;
1287 volatile List badMods;
1289 setBreakAction ( HugsIgnoreBreak );
1291 /* First, examine timestamps to find out which modules are
1292 out of date with respect to the source/interface/object files.
1295 modgList = listFromMG();
1297 for (t = modgList; nonNull(t); t=tl(t)) {
1299 if (varIsMember(textOf(hd(t)),prelModules))
1302 mod = findModule(textOf(hd(t)));
1303 if (isNull(mod)) internal("achieveTargetSet(1)");
1305 /* In standalone mode, only succeeds for source modules. */
1306 ok = findFilesForModule (
1307 textToStr(module(mod).text),
1310 &sAvail, &sTime, &sSize,
1311 &oiAvail, &oiTime, &oSize, &iSize
1314 if (!combined && !sAvail) ok = FALSE;
1316 fallBackToPrelModules();
1318 "Can't find source or object+interface for module \"%s\"",
1319 textToStr(module(mod).text)
1321 if (path) free(path);
1325 if (sAvail && oiAvail) {
1326 oisTime = whicheverIsLater(sTime,oiTime);
1328 else if (sAvail && !oiAvail) {
1331 else if (!sAvail && oiAvail) {
1335 internal("achieveTargetSet(2)");
1338 out_of_date = firstTimeIsLater(oisTime,module(mod).lastStamp);
1340 assert(!varIsMember(textOf(hd(t)),ood));
1341 ood = cons(hd(t),ood);
1344 if (path) { free(path); path = NULL; };
1347 /* Second, form a simplistic transitive closure of the out-of-date
1348 modules: a module is out of date if it imports an out-of-date
1353 for (t = modgList; nonNull(t); t=tl(t)) {
1354 mod = findModule(textOf(hd(t)));
1355 assert(nonNull(mod));
1356 for (us = module(mod).uses; nonNull(us); us=tl(us))
1357 if (varIsMember(textOf(hd(us)),ood))
1360 if (varIsMember(textOf(hd(t)),prelModules))
1361 Printf ( "warning: prelude module \"%s\" is out-of-date\n",
1362 textToStr(textOf(hd(t))) );
1364 if (!varIsMember(textOf(hd(t)),ood_new) &&
1365 !varIsMember(textOf(hd(t)),ood))
1366 ood_new = cons(hd(t),ood_new);
1369 if (isNull(ood_new)) break;
1370 ood = appendOnto(ood_new,ood);
1373 /* Now ood holds the entire set of modules which are out-of-date.
1374 Throw them out of the system, yielding a "reduced system",
1375 in which the remaining modules are in-date.
1377 for (t = ood; nonNull(t); t=tl(t)) {
1378 mod = findModule(textOf(hd(t)));
1379 assert(nonNull(mod));
1383 for (t = modgList; nonNull(t); t=tl(t))
1384 if (!varIsMember(textOf(hd(t)),ood))
1385 modgList_new = cons(hd(t),modgList_new);
1386 modgList = modgList_new;
1388 /* Update the module group list to reflect the reduced system.
1389 We do this so that if the following parsing phases fail, we can
1390 safely fall back to the reduced system.
1392 mgFromList ( modgList );
1394 /* Parse modules/interfaces, collecting parse trees and chasing
1395 imports, starting from the target set.
1397 toChase = dupList(targetModules);
1398 for (t = toChase; nonNull(t); t=tl(t)) {
1399 Cell mode = (!combined)
1401 : ( (loadingThePrelude && combined)
1404 hd(t) = zpair(hd(t), mode);
1407 /* toChase :: [ ((ConId, {FM_SOURCE|FM_OBJECT|FM_EITHER} )) ] */
1409 parsedButNotLoaded = NIL;
1412 while (nonNull(toChase)) {
1413 ConId mc = zfst(hd(toChase));
1414 Cell mode = zsnd(hd(toChase));
1415 toChase = tl(toChase);
1416 if (varIsMember(textOf(mc),modgList)
1417 || varIsMember(textOf(mc),parsedButNotLoaded)) {
1418 /* either exists fully, or is at least parsed */
1419 mod = findModule(textOf(mc));
1420 assert(nonNull(mod));
1421 if (!compatibleNewMode(mode,module(mod).mode)) {
1424 "module %s: %s required, but %s is more recent",
1425 textToStr(textOf(mc)), modeToString(mode),
1426 modeToString(module(mod).mode)
1428 goto parseException;
1432 setBreakAction ( HugsLongjmpOnBreak );
1433 if (setjmp(catch_error)==0) {
1434 /* try this; it may throw an exception */
1435 mod = parseModuleOrInterface ( mc, mode );
1437 /* here's the exception handler, if parsing fails */
1438 /* A parse error (or similar). Clean up and abort. */
1440 setBreakAction ( HugsIgnoreBreak );
1441 mod = findModule(textOf(mc));
1442 if (nonNull(mod)) nukeModule(mod);
1443 for (t = parsedButNotLoaded; nonNull(t); t=tl(t)) {
1444 mod = findModule(textOf(hd(t)));
1445 assert(nonNull(mod));
1446 if (nonNull(mod)) nukeModule(mod);
1449 /* end of the exception handler */
1451 setBreakAction ( HugsIgnoreBreak );
1453 parsedButNotLoaded = cons(mc, parsedButNotLoaded);
1454 for (t = module(mod).uses; nonNull(t); t=tl(t))
1456 zpair( hd(t), childMode(mode,module(mod).mode) ),
1461 modgList = dupOnto(parsedButNotLoaded, modgList);
1463 /* We successfully parsed all modules reachable from the target
1464 set which were not part of the reduced system. However, there
1465 may be modules in the reduced system which are not reachable from
1466 the target set. We detect these now by building the transitive
1467 closure of the target set, and nuking modules in the reduced
1468 system which are not part of that closure.
1470 trans_cl = dupList(targetModules);
1473 for (t = trans_cl; nonNull(t); t=tl(t)) {
1474 mod = findModule(textOf(hd(t)));
1475 assert(nonNull(mod));
1476 for (u = module(mod).uses; nonNull(u); u=tl(u))
1477 if (!varIsMember(textOf(hd(u)),trans_cl)
1478 && !varIsMember(textOf(hd(u)),trans_cl_new)
1479 && !varIsMember(textOf(hd(u)),prelModules))
1480 trans_cl_new = cons(hd(u),trans_cl_new);
1482 if (isNull(trans_cl_new)) break;
1483 trans_cl = appendOnto(trans_cl_new,trans_cl);
1486 for (t = modgList; nonNull(t); t=tl(t)) {
1487 if (varIsMember(textOf(hd(t)),trans_cl)) {
1488 modgList_new = cons(hd(t),modgList_new);
1490 mod = findModule(textOf(hd(t)));
1491 assert(nonNull(mod));
1495 modgList = modgList_new;
1497 /* Now, the module symbol tables hold exactly the set of
1498 modules reachable from the target set, and modgList holds
1499 their names. Calculate the scc-ified module graph,
1500 since we need that to guide the next stage, that of
1501 Actually Loading the modules.
1503 If no errors occur, moduleGraph will reflect the final graph
1504 loaded. If an error occurs loading a group, we nuke
1505 that group, truncate the moduleGraph just prior to that
1506 group, and exit. That leaves the system having successfully
1507 loaded all groups prior to the one which failed.
1509 mgFromList ( modgList );
1511 for (mg = moduleGraph; nonNull(mg); mg=tl(mg)) {
1514 if (!varIsMember(textOf(selectArbitrarilyFromGroup(grp)),
1515 parsedButNotLoaded)) continue;
1517 setBreakAction ( HugsLongjmpOnBreak );
1518 if (setjmp(catch_error)==0) {
1519 /* try this; it may throw an exception */
1522 /* here's the exception handler, if static/typecheck etc fails */
1523 /* nuke the entire rest (ie, the unloaded part)
1524 of the module graph */
1525 setBreakAction ( HugsIgnoreBreak );
1526 badMods = listFromSpecifiedMG ( mg );
1527 for (t = badMods; nonNull(t); t=tl(t)) {
1528 mod = findModule(textOf(hd(t)));
1529 if (nonNull(mod)) nukeModule(mod);
1531 /* truncate the module graph just prior to this group. */
1535 if (isNull(mg)) break;
1536 if (hd(mg) == grp) break;
1537 mg2 = cons ( hd(mg), mg2 );
1540 moduleGraph = reverse(mg2);
1542 /* end of the exception handler */
1544 setBreakAction ( HugsIgnoreBreak );
1547 /* Err .. I think that's it. If we get here, we've successfully
1548 achieved the target set. Phew!
1550 setBreakAction ( HugsIgnoreBreak );
1554 static Bool loadThePrelude ( void )
1559 moduleGraph = prelModules = NIL;
1562 conPrelude = mkCon(findText("Prelude"));
1563 conPrelHugs = mkCon(findText("PrelHugs"));
1564 targetModules = doubleton(conPrelude,conPrelHugs);
1565 achieveTargetModules(TRUE);
1566 ok = elemMG(conPrelude) && elemMG(conPrelHugs);
1568 conPrelude = mkCon(findText("Prelude"));
1569 targetModules = singleton(conPrelude);
1570 achieveTargetModules(TRUE);
1571 ok = elemMG(conPrelude);
1574 if (ok) prelModules = listFromMG();
1579 static void refreshActions ( ConId nextCurrMod, Bool cleanAfter )
1582 ConId tryFor = mkCon(module(currentModule).text);
1583 achieveTargetModules(FALSE);
1584 if (nonNull(nextCurrMod))
1585 tryFor = nextCurrMod;
1586 if (!elemMG(tryFor))
1587 tryFor = selectLatestMG();
1588 /* combined mode kludge, to get Prelude rather than PrelHugs */
1589 if (combined && textOf(tryFor)==findText("PrelHugs"))
1590 tryFor = mkCon(findText("Prelude"));
1593 /* delete any targetModules which didn't actually get loaded */
1595 targetModules = NIL;
1596 for (; nonNull(t); t=tl(t))
1598 targetModules = cons(hd(t),targetModules);
1601 setCurrModule ( findModule(textOf(tryFor)) );
1602 Printf("Hugs session for:\n");
1607 static void addActions ( List extraModules /* :: [CONID] */ )
1610 for (t = extraModules; nonNull(t); t=tl(t)) {
1611 ConId extra = hd(t);
1612 if (!varIsMember(textOf(extra),targetModules))
1613 targetModules = cons(extra,targetModules);
1615 refreshActions ( isNull(extraModules)
1617 : hd(reverse(extraModules)),
1623 static void loadActions ( List loadModules /* :: [CONID] */ )
1626 targetModules = dupList ( prelModules );
1628 for (t = loadModules; nonNull(t); t=tl(t)) {
1630 if (!varIsMember(textOf(load),targetModules))
1631 targetModules = cons(load,targetModules);
1633 refreshActions ( isNull(loadModules)
1635 : hd(reverse(loadModules)),
1641 /* --------------------------------------------------------------------------
1642 * Access to external editor:
1643 * ------------------------------------------------------------------------*/
1645 /* ToDo: All this editor stuff needs fixing. */
1647 static Void local editor() { /* interpreter-editor interface */
1649 String newFile = readFilename();
1651 setLastEdit(newFile,0);
1652 if (readFilename()) {
1653 ERRMSG(0) "Multiple filenames not permitted"
1661 static Void local find() { /* edit file containing definition */
1664 String nm = readFilename(); /* of specified name */
1666 ERRMSG(0) "No name specified"
1669 else if (readFilename()) {
1670 ERRMSG(0) "Multiple names not permitted"
1676 setCurrModule(findEvalModule());
1678 if (nonNull(c=findTycon(t=findText(nm)))) {
1679 if (startEdit(tycon(c).line,scriptName[scriptThisTycon(c)])) {
1680 readScripts(N_PRELUDE_SCRIPTS);
1682 } else if (nonNull(c=findName(t))) {
1683 if (startEdit(name(c).line,scriptName[scriptThisName(c)])) {
1684 readScripts(N_PRELUDE_SCRIPTS);
1687 ERRMSG(0) "No current definition for name \"%s\"", nm
1694 static Void local runEditor() { /* run editor on script lastEdit */
1696 if (startEdit(lastEdLine,lastEdit)) /* at line lastEdLine */
1697 readScripts(N_PRELUDE_SCRIPTS);
1701 static Void local setLastEdit(fname,line)/* keep name of last file to edit */
1707 lastEdit = strCopy(fname);
1712 /* --------------------------------------------------------------------------
1713 * Read and evaluate an expression:
1714 * ------------------------------------------------------------------------*/
1716 static Void setModule ( void ) {
1717 /*set module in which to evaluate expressions*/
1720 String s = readFilename();
1722 mc = selectLatestMG();
1723 if (combined && textOf(mc)==findText("PrelHugs"))
1724 mc = mkCon(findText("Prelude"));
1725 m = findModule(textOf(mc));
1728 m = findModule(findText(s));
1730 ERRMSG(0) "Cannot find module \"%s\"", s
1738 static Module allocEvalModule ( void )
1740 Module evalMod = newModule( findText("_Eval_Module_") );
1741 module(evalMod).names = module(currentModule).names;
1742 module(evalMod).tycons = module(currentModule).tycons;
1743 module(evalMod).classes = module(currentModule).classes;
1744 module(evalMod).qualImports
1745 = singleton(pair(mkCon(textPrelude),modulePrelude));
1749 static Void local evaluator() { /* evaluate expr and print value */
1752 volatile Kinds ks = NIL;
1753 volatile Module evalMod = allocEvalModule();
1754 volatile Module currMod = currentModule;
1755 setCurrModule(evalMod);
1758 defaultDefns = combined ? stdDefaults : evalDefaults;
1760 setBreakAction ( HugsLongjmpOnBreak );
1761 if (setjmp(catch_error)==0) {
1765 type = typeCheckExp(TRUE);
1767 /* if an exception happens, we arrive here */
1768 setBreakAction ( HugsIgnoreBreak );
1769 goto cleanup_and_return;
1772 setBreakAction ( HugsIgnoreBreak );
1773 if (isPolyType(type)) {
1774 ks = polySigOf(type);
1775 bd = monotypeOf(type);
1780 if (whatIs(bd)==QUAL) {
1781 ERRMSG(0) "Unresolved overloading" ETHEN
1782 ERRTEXT "\n*** Type : " ETHEN ERRTYPE(type);
1783 ERRTEXT "\n*** Expression : " ETHEN ERREXPR(inputExpr);
1786 goto cleanup_and_return;
1790 if (isProgType(ks,bd)) {
1791 inputExpr = ap(nameRunIO_toplevel,inputExpr);
1795 Cell d = provePred(ks,NIL,ap(classShow,bd));
1797 ERRMSG(0) "Cannot find \"show\" function for:" ETHEN
1798 ERRTEXT "\n*** expression : " ETHEN ERREXPR(inputExpr);
1799 ERRTEXT "\n*** of type : " ETHEN ERRTYPE(type);
1802 goto cleanup_and_return;
1804 inputExpr = ap2(nameShow, d,inputExpr);
1805 inputExpr = ap (namePutStr, inputExpr);
1806 inputExpr = ap (nameRunIO_toplevel, inputExpr);
1808 evalExp(); printf("\n");
1811 printType(stdout,type);
1818 printf ( "result type is " );
1819 printType ( stdout, type );
1827 setBreakAction ( HugsIgnoreBreak );
1828 nukeModule(evalMod);
1829 setCurrModule(currMod);
1830 setCurrentFile(currMod);
1835 /* --------------------------------------------------------------------------
1836 * Print type of input expression:
1837 * ------------------------------------------------------------------------*/
1839 static Void showtype ( void ) { /* print type of expression (if any)*/
1842 volatile Module evalMod = allocEvalModule();
1843 volatile Module currMod = currentModule;
1844 setCurrModule(evalMod);
1846 if (setjmp(catch_error)==0) {
1850 defaultDefns = evalDefaults;
1851 type = typeCheckExp(FALSE);
1852 printExp(stdout,inputExpr);
1854 printType(stdout,type);
1857 /* if an exception happens, we arrive here */
1860 nukeModule(evalMod);
1861 setCurrModule(currMod);
1865 static Void local browseit(mod,t,all)
1872 Printf("module %s where\n",textToStr(module(mod).text));
1873 for (cs = module(mod).names; nonNull(cs); cs=tl(cs)) {
1875 /* only look at things defined in this module,
1876 unless `all' flag is set */
1877 if (all || name(nm).mod == mod) {
1878 /* unwanted artifacts, like lambda lifted values,
1879 are in the list of names, but have no types */
1880 if (nonNull(name(nm).type)) {
1881 printExp(stdout,nm);
1883 printType(stdout,name(nm).type);
1885 Printf(" -- data constructor");
1886 } else if (isMfun(nm)) {
1887 Printf(" -- class member");
1888 } else if (isSfun(nm)) {
1889 Printf(" -- selector function");
1897 Printf("Unknown module %s\n",t);
1902 static Void local browse() { /* browse modules */
1903 Int count = 0; /* or give menu of commands */
1907 for (; (s=readFilename())!=0; count++)
1908 if (strcmp(s,"all") == 0) {
1912 browseit(findModule(findText(s)),s,all);
1914 browseit(currentModule,NULL,all);
1918 #if EXPLAIN_INSTANCE_RESOLUTION
1919 static Void local xplain() { /* print type of expression (if any)*/
1921 Bool sir = showInstRes;
1923 setCurrModule(findEvalModule());
1924 startNewScript(0); /* Enables recovery of storage */
1925 /* allocated during evaluation */
1929 d = provePred(NIL,NIL,hd(inputContext));
1931 fprintf(stdout, "not Sat\n");
1933 fprintf(stdout, "Sat\n");
1939 /* --------------------------------------------------------------------------
1940 * Enhanced help system: print current list of scripts or give information
1942 * ------------------------------------------------------------------------*/
1944 static String local objToStr(m,c)
1947 #if 1 || DISPLAY_QUANTIFIERS
1948 static char newVar[60];
1949 switch (whatIs(c)) {
1950 case NAME : if (m == name(c).mod) {
1951 sprintf(newVar,"%s", textToStr(name(c).text));
1953 sprintf(newVar,"%s.%s",
1954 textToStr(module(name(c).mod).text),
1955 textToStr(name(c).text));
1959 case TYCON : if (m == tycon(c).mod) {
1960 sprintf(newVar,"%s", textToStr(tycon(c).text));
1962 sprintf(newVar,"%s.%s",
1963 textToStr(module(tycon(c).mod).text),
1964 textToStr(tycon(c).text));
1968 case CLASS : if (m == cclass(c).mod) {
1969 sprintf(newVar,"%s", textToStr(cclass(c).text));
1971 sprintf(newVar,"%s.%s",
1972 textToStr(module(cclass(c).mod).text),
1973 textToStr(cclass(c).text));
1977 default : internal("objToStr");
1981 static char newVar[33];
1982 switch (whatIs(c)) {
1983 case NAME : sprintf(newVar,"%s", textToStr(name(c).text));
1986 case TYCON : sprintf(newVar,"%s", textToStr(tycon(c).text));
1989 case CLASS : sprintf(newVar,"%s", textToStr(cclass(c).text));
1992 default : internal("objToStr");
2000 static Void dumpStg ( void )
2006 setCurrModule(findEvalModule());
2011 /* request to locate a symbol by name */
2012 if (s && (*s == '?')) {
2013 Text t = findText(s+1);
2014 locateSymbolByName(t);
2018 /* request to dump a bit of the heap */
2019 if (s && (*s == '-' || isdigit(*s))) {
2026 /* request to dump a symbol table entry */
2028 || !(*s == 't' || *s == 'n' || *s == 'c' || *s == 'i')
2029 || !isdigit(s[1])) {
2030 fprintf(stderr, ":d -- bad request `%s'\n", s );
2035 case 't': dumpTycon(i); break;
2036 case 'n': dumpName(i); break;
2037 case 'c': dumpClass(i); break;
2038 case 'i': dumpInst(i); break;
2039 default: fprintf(stderr, ":d -- `%c' not implemented\n", *s );
2045 static Void local dumpStg( void ) { /* print STG stuff */
2050 Cell v; /* really StgVar */
2051 setCurrModule(findEvalModule());
2053 for (; (s=readFilename())!=0;) {
2056 /* find the name while ignoring module scopes */
2057 for (i=NAMEMIN; i<nameHw; i++)
2058 if (name(i).text == t) n = i;
2060 /* perhaps it's an "idNNNNNN" thing? */
2063 s[0]=='i' && s[1]=='d' && isdigit(s[2])) {
2066 while (isdigit(s[i])) {
2067 v = v * 10 + (s[i]-'0');
2071 n = nameFromStgVar(v);
2074 if (isNull(n) && whatIs(v)==STGVAR) {
2075 Printf ( "\n{- `%s' has no nametable entry -}\n", s );
2076 printStg(stderr, v );
2079 Printf ( "Unknown reference `%s'\n", s );
2082 Printf ( "Not a Name: `%s'\n", s );
2084 if (isNull(name(n).stgVar)) {
2085 Printf ( "Doesn't have a STG tree: %s\n", s );
2087 Printf ( "\n{- stgVar of `%s' is id%d -}\n", s, -name(n).stgVar);
2088 printStg(stderr, name(n).stgVar);
2094 static Void local info() { /* describe objects */
2095 Int count = 0; /* or give menu of commands */
2098 for (; (s=readFilename())!=0; count++) {
2099 describe(findText(s));
2102 /* whatScripts(); */
2107 static Void local describe(t) /* describe an object */
2109 Tycon tc = findTycon(t);
2110 Class cl = findClass(t);
2111 Name nm = findName(t);
2113 if (nonNull(tc)) { /* as a type constructor */
2117 for (i=0; i<tycon(tc).arity; ++i) {
2118 t = ap(t,mkOffset(i));
2120 Printf("-- type constructor");
2122 Printf(" with kind ");
2123 printKind(stdout,tycon(tc).kind);
2126 switch (tycon(tc).what) {
2127 case SYNONYM : Printf("type ");
2128 printType(stdout,t);
2130 printType(stdout,tycon(tc).defn);
2134 case DATATYPE : { List cs = tycon(tc).defn;
2135 if (tycon(tc).what==DATATYPE) {
2140 printType(stdout,t);
2142 mapProc(printSyntax,cs);
2144 Printf("\n-- constructors:");
2146 for (; hasCfun(cs); cs=tl(cs)) {
2148 printExp(stdout,hd(cs));
2150 printType(stdout,name(hd(cs)).type);
2153 Printf("\n-- selectors:");
2155 for (; nonNull(cs); cs=tl(cs)) {
2157 printExp(stdout,hd(cs));
2159 printType(stdout,name(hd(cs)).type);
2164 case RESTRICTSYN : Printf("type ");
2165 printType(stdout,t);
2166 Printf(" = <restricted>");
2170 if (nonNull(in=findFirstInst(tc))) {
2171 Printf("\n-- instances:\n");
2174 in = findNextInst(tc,in);
2175 } while (nonNull(in));
2180 if (nonNull(cl)) { /* as a class */
2181 List ins = cclass(cl).instances;
2182 Kinds ks = cclass(cl).kinds;
2183 if (nonNull(ks) && isNull(tl(ks)) && hd(ks)==STAR) {
2184 Printf("-- type class");
2186 Printf("-- constructor class");
2188 Printf(" with arity ");
2189 printKinds(stdout,ks);
2193 mapProc(printSyntax,cclass(cl).members);
2195 if (nonNull(cclass(cl).supers)) {
2196 printContext(stdout,cclass(cl).supers);
2199 printPred(stdout,cclass(cl).head);
2201 if (nonNull(cclass(cl).fds)) {
2202 List fds = cclass(cl).fds;
2204 for (; nonNull(fds); fds=tl(fds)) {
2206 printFD(stdout,hd(fds));
2211 if (nonNull(cclass(cl).members)) {
2212 List ms = cclass(cl).members;
2215 Type t = name(hd(ms)).type;
2216 if (isPolyType(t)) {
2220 printExp(stdout,hd(ms));
2222 if (isNull(tl(fst(snd(t))))) {
2225 t = ap(QUAL,pair(tl(fst(snd(t))),snd(snd(t))));
2227 printType(stdout,t);
2229 } while (nonNull(ms));
2233 Printf("\n-- instances:\n");
2237 } while (nonNull(ins));
2242 if (nonNull(nm)) { /* as a function/name */
2244 printExp(stdout,nm);
2246 if (nonNull(name(nm).type)) {
2247 printType(stdout,name(nm).type);
2249 Printf("<unknown type>");
2252 Printf(" -- data constructor");
2253 } else if (isMfun(nm)) {
2254 Printf(" -- class member");
2255 } else if (isSfun(nm)) {
2256 Printf(" -- selector function");
2262 if (isNull(tc) && isNull(cl) && isNull(nm)) {
2263 Printf("Unknown reference `%s'\n",textToStr(t));
2267 static Void local printSyntax(nm)
2269 Syntax sy = syntaxOf(nm);
2270 Text t = name(nm).text;
2271 String s = textToStr(t);
2272 if (sy != defaultSyntax(t)) {
2274 switch (assocOf(sy)) {
2275 case LEFT_ASS : Putchar('l'); break;
2276 case RIGHT_ASS : Putchar('r'); break;
2277 case NON_ASS : break;
2279 Printf(" %i ",precOf(sy));
2280 if (isascii((int)(*s)) && isalpha((int)(*s))) {
2289 static Void local showInst(in) /* Display instance decl header */
2291 Printf("instance ");
2292 if (nonNull(inst(in).specifics)) {
2293 printContext(stdout,inst(in).specifics);
2296 printPred(stdout,inst(in).head);
2300 /* --------------------------------------------------------------------------
2301 * List all names currently in scope:
2302 * ------------------------------------------------------------------------*/
2304 static Void local listNames() { /* list names matching optional pat*/
2305 String pat = readFilename();
2307 Int width = getTerminalWidth() - 1;
2310 Module mod = currentModule;
2312 if (pat) { /* First gather names to list */
2314 names = addNamesMatching(pat,names);
2315 } while ((pat=readFilename())!=0);
2317 names = addNamesMatching((String)0,names);
2319 if (isNull(names)) { /* Then print them out */
2320 ERRMSG(0) "No names selected"
2324 for (termPos=0; nonNull(names); names=tl(names)) {
2325 String s = objToStr(mod,hd(names));
2327 if (termPos+1+l>width) {
2330 } else if (termPos>0) {
2338 Printf("\n(%d names listed)\n", count);
2341 /* --------------------------------------------------------------------------
2342 * print a prompt and read a line of input:
2343 * ------------------------------------------------------------------------*/
2345 static Void local promptForInput(moduleName)
2346 String moduleName; {
2347 char promptBuffer[1000];
2349 /* This is portable but could overflow buffer */
2350 sprintf(promptBuffer,prompt,moduleName);
2352 /* Works on ANSI C - but pre-ANSI compilers return a pointer to
2353 * promptBuffer instead.
2355 if (sprintf(promptBuffer,prompt,moduleName) >= 1000) {
2356 /* Reset prompt to a safe default to avoid an infinite loop */
2358 prompt = strCopy("? ");
2359 internal("Combined prompt and evaluation module name too long");
2363 stringInput("main\0"); else
2364 consoleInput(promptBuffer);
2367 /* --------------------------------------------------------------------------
2368 * main read-eval-print loop, with error trapping:
2369 * ------------------------------------------------------------------------*/
2371 static Void local interpreter(argc,argv)/* main interpreter loop */
2375 List modConIds; /* :: [CONID] */
2379 setBreakAction ( HugsIgnoreBreak );
2380 modConIds = initialize(argc,argv); /* the initial modules to load */
2381 setBreakAction ( HugsIgnoreBreak );
2382 prelOK = loadThePrelude();
2383 if (combined) everybody(POSTPREL);
2387 fprintf(stderr, "hugs +Q: fatal error: can't load the Prelude.\n" );
2389 fprintf(stderr, "hugs: fatal error: can't load the Prelude.\n" );
2393 loadActions(modConIds);
2396 for (; nonNull(modConIds); modConIds=tl(modConIds))
2397 if (!elemMG(hd(modConIds))) {
2399 "hugs +Q: compilation failed -- can't run `main'\n" );
2406 /* initialize calls startupHaskell, which trashes our signal handlers */
2407 setBreakAction ( HugsIgnoreBreak );
2412 everybody(RESET); /* reset to sensible initial state */
2414 promptForInput(textToStr(module(currentModule).text));
2416 cmd = readCommand(cmds, (Char)':', (Char)'!');
2418 case EDIT : editor();
2422 case LOAD : modConIds = NIL;
2423 while ((s=readFilename())!=0)
2424 modConIds = cons(mkCon(findText(s)),modConIds);
2425 loadActions(modConIds);
2428 case ALSO : modConIds = NIL;
2429 while ((s=readFilename())!=0)
2430 modConIds = cons(mkCon(findText(s)),modConIds);
2431 addActions(modConIds);
2434 case RELOAD : refreshActions(NIL,FALSE);
2439 case EVAL : evaluator();
2441 case TYPEOF : showtype();
2443 case BROWSE : browse();
2445 #if EXPLAIN_INSTANCE_RESOLUTION
2446 case XPLAIN : xplain();
2449 case NAMES : listNames();
2453 case BADCMD : guidance();
2458 #ifdef CRUDE_PROFILING
2462 case SYSTEM : if (shellEsc(readLine()))
2463 Printf("Warning: Shell escape terminated abnormally\n");
2465 case CHGDIR : changeDir();
2469 case PNTVER: Printf("-- Hugs Version %s\n",
2472 case DUMP : dumpStg();
2475 case COLLECT: consGC = FALSE;
2478 Printf("Garbage collection recovered %d cells\n",
2484 if (autoMain) break;
2488 /* --------------------------------------------------------------------------
2489 * Display progress towards goal:
2490 * ------------------------------------------------------------------------*/
2492 static Target currTarget;
2493 static Bool aiming = FALSE;
2496 static Int charCount;
2498 Void setGoal(what, t) /* Set goal for what to be t */
2503 #if EXPLAIN_INSTANCE_RESOLUTION
2507 currTarget = (t?t:1);
2510 currPos = strlen(what);
2511 maxPos = getTerminalWidth() - 1;
2515 for (charCount=0; *what; charCount++)
2520 Void soFar(t) /* Indicate progress towards goal */
2521 Target t; { /* has now reached t */
2524 #if EXPLAIN_INSTANCE_RESOLUTION
2529 Int newPos = (Int)((maxPos * ((long)t))/currTarget);
2534 if (newPos>currPos) {
2537 while (newPos>++currPos);
2544 Void done() { /* Goal has now been achieved */
2547 #if EXPLAIN_INSTANCE_RESOLUTION
2552 while (maxPos>currPos++)
2557 for (; charCount>0; charCount--) {
2566 static Void local failed() { /* Goal cannot be reached due to */
2567 if (aiming) { /* errors */
2574 /* --------------------------------------------------------------------------
2576 * ------------------------------------------------------------------------*/
2578 static Void local stopAnyPrinting() { /* terminate printing of expression,*/
2579 if (printing) { /* after successful termination or */
2580 printing = FALSE; /* runtime error (e.g. interrupt) */
2583 #define plural(v) v, (v==1?"":"s")
2584 Printf("%lu cell%s",plural(numCells));
2586 Printf(", %u garbage collection%s",plural(numGcs));
2595 Cell errAssert(l) /* message to use when raising asserts, etc */
2599 str = mkStr(findText(currentFile));
2601 str = mkStr(findText(""));
2603 return (ap2(nameTangleMessage,str,mkInt(l)));
2606 Void errHead(l) /* print start of error message */
2608 failed(); /* failed to reach target ... */
2610 FPrintf(errorStream,"ERROR");
2613 FPrintf(errorStream," \"%s\"", currentFile);
2614 setLastEdit(currentFile,l);
2615 if (l) FPrintf(errorStream," (line %d)",l);
2618 FPrintf(errorStream,": ");
2619 FFlush(errorStream);
2622 Void errFail() { /* terminate error message and */
2623 Putc('\n',errorStream); /* produce exception to return to */
2624 FFlush(errorStream); /* main command loop */
2625 longjmp(catch_error,1);
2628 Void errFail_no_longjmp() { /* terminate error message but */
2629 Putc('\n',errorStream); /* don't produce an exception */
2630 FFlush(errorStream);
2633 Void errAbort() { /* altern. form of error handling */
2634 failed(); /* used when suitable error message*/
2635 stopAnyPrinting(); /* has already been printed */
2639 Void internal(msg) /* handle internal error */
2643 Printf("INTERNAL ERROR: %s\n",msg);
2646 longjmp(catch_error,1);
2649 Void fatal(msg) /* handle fatal error */
2652 Printf("\nFATAL ERROR: %s\n",msg);
2658 /* --------------------------------------------------------------------------
2659 * Read value from environment variable or registry:
2660 * ------------------------------------------------------------------------*/
2662 String fromEnv(var,def) /* return value of: */
2663 String var; /* environment variable named by var */
2664 String def; { /* or: default value given by def */
2665 String s = getenv(var);
2666 return (s ? s : def);
2669 /* --------------------------------------------------------------------------
2670 * String manipulation routines:
2671 * ------------------------------------------------------------------------*/
2673 static String local strCopy(s) /* make malloced copy of a string */
2677 if ((t=(char *)malloc(strlen(s)+1))==0) {
2678 ERRMSG(0) "String storage space exhausted"
2681 for (r=t; (*r++ = *s++)!=0; ) {
2689 /* --------------------------------------------------------------------------
2691 * We can redirect compiler output (prompts, error messages, etc) by
2692 * tweaking these functions.
2693 * ------------------------------------------------------------------------*/
2695 #ifdef HAVE_STDARG_H
2698 #include <varargs.h>
2701 Void hugsEnableOutput(f)
2706 #ifdef HAVE_STDARG_H
2707 Void hugsPrintf(const char *fmt, ...) {
2708 va_list ap; /* pointer into argument list */
2709 va_start(ap, fmt); /* make ap point to first arg after fmt */
2710 if (!disableOutput) {
2714 va_end(ap); /* clean up */
2717 Void hugsPrintf(fmt, va_alist)
2720 va_list ap; /* pointer into argument list */
2721 va_start(ap); /* make ap point to first arg after fmt */
2722 if (!disableOutput) {
2726 va_end(ap); /* clean up */
2732 if (!disableOutput) {
2738 Void hugsFlushStdout() {
2739 if (!disableOutput) {
2746 if (!disableOutput) {
2751 #ifdef HAVE_STDARG_H
2752 Void hugsFPrintf(FILE *fp, const char* fmt, ...) {
2755 if (!disableOutput) {
2756 vfprintf(fp, fmt, ap);
2762 Void hugsFPrintf(FILE *fp, const char* fmt, va_list)
2768 if (!disableOutput) {
2769 vfprintf(fp, fmt, ap);
2776 Void hugsPutc(c, fp)
2779 if (!disableOutput) {
2785 /* --------------------------------------------------------------------------
2786 * Send message to each component of system:
2787 * ------------------------------------------------------------------------*/
2789 Void everybody(what) /* send command `what' to each component of*/
2790 Int what; { /* system to respond as appropriate ... */
2792 fprintf ( stderr, "EVERYBODY %d\n", what );
2794 machdep(what); /* The order of calling each component is */
2795 storage(what); /* important for the PREPREL command */
2798 translateControl(what);
2800 staticAnalysis(what);
2801 deriveControl(what);
2808 mark(targetModules);
2812 /*-------------------------------------------------------------------------*/