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 09:40:03 $
14 * ------------------------------------------------------------------------*/
20 #include "hugsbasictypes.h"
29 #include "Assembler.h" /* DEBUG_LoadSymbols */
31 Bool haskell98 = TRUE; /* TRUE => Haskell 98 compatibility*/
32 Bool initDone = FALSE;
34 #if EXPLAIN_INSTANCE_RESOLUTION
35 Bool showInstRes = FALSE;
38 Bool multiInstRes = FALSE;
41 /* --------------------------------------------------------------------------
42 * Local function prototypes:
43 * ------------------------------------------------------------------------*/
45 static List local initialize ( Int,String [] );
46 static Void local promptForInput ( String );
47 static Void local interpreter ( Int,String [] );
48 static Void local menu ( Void );
49 static Void local guidance ( Void );
50 static Void local forHelp ( Void );
51 static Void local set ( Void );
52 static Void local changeDir ( Void );
53 static Void local load ( Void );
54 static Void local project ( Void );
55 static Void local editor ( Void );
56 static Void local find ( Void );
57 static Bool local startEdit ( Int,String );
58 static Void local runEditor ( Void );
59 static Void local setModule ( Void );
60 static Void local evaluator ( Void );
61 static Void local stopAnyPrinting ( Void );
62 static Void local showtype ( Void );
63 static String local objToStr ( Module, Cell );
64 static Void local info ( Void );
65 static Void local printSyntax ( Name );
66 static Void local showInst ( Inst );
67 static Void local describe ( Text );
68 static Void local listNames ( Void );
70 static Void local toggleSet ( Char,Bool );
71 static Void local togglesIn ( Bool );
72 static Void local optionInfo ( Void );
73 static Void local readOptions ( String );
74 static Bool local processOption ( String );
75 static Void local setHeapSize ( String );
76 static Int local argToInt ( String );
78 static Void local setLastEdit ( String,Int );
79 static Void local failed ( Void );
80 static String local strCopy ( String );
81 static Void local browseit ( Module,String,Bool );
82 static Void local browse ( Void );
84 /* --------------------------------------------------------------------------
85 * Machine dependent code for Hugs interpreter:
86 * ------------------------------------------------------------------------*/
90 /* --------------------------------------------------------------------------
92 * ------------------------------------------------------------------------*/
94 static Bool printing = FALSE; /* TRUE => currently printing value*/
95 static Bool showStats = FALSE; /* TRUE => print stats after eval */
96 static Bool listScripts = TRUE; /* TRUE => list scripts after loading*/
97 static Bool addType = FALSE; /* TRUE => print type with value */
98 static Bool useDots = RISCOS; /* TRUE => use dots in progress */
99 static Bool quiet = FALSE; /* TRUE => don't show progress */
100 static Bool lastWasObject = FALSE;
102 Bool flagAssert = FALSE; /* TRUE => assert False <e> causes
103 an assertion failure */
104 Bool preludeLoaded = FALSE;
105 Bool debugSC = FALSE;
106 Bool combined = FALSE;
108 Module moduleBeingParsed; /* so the parser (topModule) knows */
109 static char* currentFile; /* Name of current file, or NULL */
110 static char currentFileName[1000]; /* name is stored here if it exists*/
112 static Bool autoMain = FALSE;
113 static String lastEdit = 0; /* Name of script to edit (if any) */
114 static Int lastEdLine = 0; /* Editor line number (if possible)*/
115 static String prompt = 0; /* Prompt string */
116 static Int hpSize = DEFAULTHEAP; /* Desired heap size */
117 static Bool disableOutput = FALSE; /* TRUE => quiet */
118 String hugsEdit = 0; /* String for editor command */
119 String hugsPath = 0; /* String for file search path */
121 List ifaces_outstanding = NIL;
124 /* --------------------------------------------------------------------------
126 * ------------------------------------------------------------------------*/
128 #ifndef NO_MAIN /* we omit main when building the "Hugs server" */
130 Main main ( Int, String [] ); /* now every func has a prototype */
135 #ifdef HAVE_CONSOLE_H /* Macintosh port */
137 _fcreator = 'R*ch'; /* // 'KAHL'; //'*TEX'; //'ttxt'; */
139 console_options.top = 50;
140 console_options.left = 20;
142 console_options.nrows = 32;
143 console_options.ncols = 80;
145 console_options.pause_atexit = 1;
146 console_options.title = "\pHugs";
148 console_options.procID = 5;
149 argc = ccommand(&argv);
152 CStackBase = &argc; /* Save stack base for use in gc */
156 checkBytecodeCount(); /* check for too many bytecodes */
160 /* If first arg is +Q or -Q, be entirely silent, and automatically run
161 main after loading scripts. Useful for running the nofib suite. */
162 if (argc > 1 && (strcmp(argv[1],"+Q") == 0 || strcmp(argv[1],"-Q")==0)) {
164 if (strcmp(argv[1],"-Q") == 0) {
169 Printf("__ __ __ __ ____ ___ _________________________________________\n");
170 Printf("|| || || || || || ||__ STGHugs: Based on the Haskell 98 standard\n");
171 Printf("||___|| ||__|| ||__|| __|| Copyright (c) 1994-1999\n");
172 Printf("||---|| ___|| World Wide Web: http://haskell.org/hugs\n");
173 Printf("|| || Report bugs to: hugs-bugs@haskell.org\n");
174 Printf("|| || Version: %s _________________________________________\n\n",HUGS_VERSION);
176 /* Get the absolute path to the directory containing the hugs
177 executable, so that we know where the Prelude and nHandle.so/.dll are.
178 We do this by reading env var STGHUGSDIR. This needs to succeed, so
179 setInstallDir won't return unless it succeeds.
181 setInstallDir ( argv[0] );
184 Printf(" Ported to Macintosh by Hans Aberg, compiled " __DATE__ ".\n\n");
187 interpreter(argc,argv);
188 Printf("[Leaving Hugs]\n");
199 /* --------------------------------------------------------------------------
200 * Initialization, interpret command line args and read prelude:
201 * ------------------------------------------------------------------------*/
203 static List /*CONID*/ initialize(argc,argv) /* Interpreter initialization */
207 char argv_0_orig[1000];
210 setLastEdit((String)0,0);
217 hugsEdit = strCopy(fromEnv("EDITOR",NULL));
219 hugsPath = strCopy(HUGSPATH);
220 readOptions("-p\"%s> \" -r$$");
221 readOptions(fromEnv("STGHUGSFLAGS",""));
223 strncpy(argv_0_orig,argv[0],1000); /* startupHaskell mangles argv[0] */
224 startupHaskell (argc,argv,NULL);
230 char exe_name[N_INSTALLDIR + 6];
231 strcpy(exe_name, installDir);
232 strcat(exe_name, "hugs");
233 DEBUG_LoadSymbols(exe_name);
237 /* Find out early on if we're in combined mode or not.
238 everybody(PREPREL) needs to know this. Also, establish the
241 for (i=1; i < argc; ++i) {
242 if (strcmp(argv[i], "--")==0) break;
243 if (strcmp(argv[i], "-c")==0) combined = FALSE;
244 if (strcmp(argv[i], "+c")==0) combined = TRUE;
246 if (strncmp(argv[i],"+h",2)==0 ||
247 strncmp(argv[i],"-h",2)==0)
248 setHeapSize(&(argv[i][2]));
252 initialModules = NIL;
254 for (i=1; i < argc; ++i) { /* process command line arguments */
255 if (strcmp(argv[i], "--")==0) break;
256 if (argv[i] && argv[i][0]/* workaround for /bin/sh silliness*/
257 && !processOption(argv[i])) {
259 = cons ( mkCon(findText(argv[i])), initialModules );
264 Printf("Haskell 98 mode: Restart with command line option -98"
265 " to enable extensions\n");
267 Printf("Hugs mode: Restart with command line option +98 for"
268 " Haskell 98 mode\n");
272 Printf("Combined mode: Restart with command line -c for"
273 " standalone mode\n\n" );
275 Printf("Standalone mode: Restart with command line +c for"
276 " combined mode\n\n" );
280 return initialModules;
283 /* --------------------------------------------------------------------------
284 * Command line options:
285 * ------------------------------------------------------------------------*/
287 struct options { /* command line option toggles */
288 char c; /* table defined in main app. */
293 extern struct options toggle[];
295 static Void local toggleSet(c,state) /* Set command line toggle */
299 for (i=0; toggle[i].c; ++i)
300 if (toggle[i].c == c) {
301 *toggle[i].flag = state;
304 ERRMSG(0) "Unknown toggle `%c'", c
308 static Void local togglesIn(state) /* Print current list of toggles in*/
309 Bool state; { /* given state */
312 for (i=0; toggle[i].c; ++i)
313 if (*toggle[i].flag == state && (!haskell98 || toggle[i].h98)) {
315 Putchar((char)(state ? '+' : '-'));
316 Putchar(toggle[i].c);
323 static Void local optionInfo() { /* Print information about command */
324 static String fmts = "%-5s%s\n"; /* line settings */
325 static String fmtc = "%-5c%s\n";
328 Printf("TOGGLES: groups begin with +/- to turn options on/off resp.\n");
329 for (i=0; toggle[i].c; ++i) {
330 if (!haskell98 || toggle[i].h98) {
331 Printf(fmtc,toggle[i].c,toggle[i].description);
335 Printf("\nOTHER OPTIONS: (leading + or - makes no difference)\n");
336 Printf(fmts,"hnum","Set heap size (cannot be changed within Hugs)");
337 Printf(fmts,"pstr","Set prompt string to str");
338 Printf(fmts,"rstr","Set repeat last expression string to str");
339 Printf(fmts,"Pstr","Set search path for modules to str");
340 Printf(fmts,"Estr","Use editor setting given by str");
341 Printf(fmts,"cnum","Set constraint cutoff limit");
342 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
343 Printf(fmts,"Fstr","Set preprocessor filter to str");
346 Printf("\nCurrent settings: ");
349 Printf("-h%d",heapSize);
353 printString(repeatStr);
354 Printf(" -c%d",cutoff);
355 Printf("\nSearch path : -P");
356 printString(hugsPath);
359 if (projectPath!=NULL) {
360 Printf("\nProject Path : %s",projectPath);
363 Printf("\nEditor setting : -E");
364 printString(hugsEdit);
365 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
366 Printf("\nPreprocessor : -F");
367 printString(preprocessor);
369 Printf("\nCompatibility : %s", haskell98 ? "Haskell 98 (+98)"
370 : "Hugs Extensions (-98)");
379 static Void local readOptions(options) /* read options from string */
383 stringInput(options);
384 while ((s=readFilename())!=0) {
385 if (*s && !processOption(s)) {
386 ERRMSG(0) "Option string must begin with `+' or `-'"
393 static Bool local processOption(s) /* process string s for options, */
394 String s; { /* return FALSE if none found. */
406 case 'Q' : break; /* already handled */
408 case 'p' : if (s[1]) {
409 if (prompt) free(prompt);
410 prompt = strCopy(s+1);
414 case 'r' : if (s[1]) {
415 if (repeatStr) free(repeatStr);
416 repeatStr = strCopy(s+1);
421 String p = substPath(s+1,hugsPath ? hugsPath : "");
422 if (hugsPath) free(hugsPath);
427 case 'E' : if (hugsEdit) free(hugsEdit);
428 hugsEdit = strCopy(s+1);
431 #if USE_PREPROCESSOR && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
432 case 'F' : if (preprocessor) free(preprocessor);
433 preprocessor = strCopy(s+1);
437 case 'h' : /* don't do anything, since pre-scan of args
438 will have got it already */
441 case 'c' : /* don't do anything, since pre-scan of args
442 will have got it already */
445 case 'D' : /* hack */
447 extern void setRtsFlags( int x );
448 setRtsFlags(argToInt(s+1));
452 default : if (strcmp("98",s)==0) {
453 if (initDone && ((state && !haskell98) ||
454 (!state && haskell98))) {
456 "Haskell 98 compatibility cannot be changed"
457 " while the interpreter is running\n");
470 static Void local setHeapSize(s)
473 hpSize = argToInt(s);
474 if (hpSize < MINIMUMHEAP)
475 hpSize = MINIMUMHEAP;
476 else if (MAXIMUMHEAP && hpSize > MAXIMUMHEAP)
477 hpSize = MAXIMUMHEAP;
478 if (initDone && hpSize != heapSize) {
479 /* ToDo: should this use a message box in winhugs? */
480 FPrintf(stderr,"You cannot change heap size from inside Hugs\n");
487 static Int local argToInt(s) /* read integer from argument str */
492 if (*s=='\0' || !isascii((int)(*s)) || !isdigit((int)(*s))) {
493 ERRMSG(0) "Missing integer in option setting \"%s\"", t
498 Int d = (*s++) - '0';
499 if (n > ((MAXPOSINT - d)/10)) {
500 ERRMSG(0) "Option setting \"%s\" is too large", t
504 } while (isascii((int)(*s)) && isdigit((int)(*s)));
506 if (*s=='K' || *s=='k') {
507 if (n > (MAXPOSINT/1000)) {
508 ERRMSG(0) "Option setting \"%s\" is too large", t
515 #if MAXPOSINT > 1000000 /* waste of time on 16 bit systems */
516 if (*s=='M' || *s=='m') {
517 if (n > (MAXPOSINT/1000000)) {
518 ERRMSG(0) "Option setting \"%s\" is too large", t
526 #if MAXPOSINT > 1000000000
527 if (*s=='G' || *s=='g') {
528 if (n > (MAXPOSINT/1000000000)) {
529 ERRMSG(0) "Option setting \"%s\" is too large", t
538 ERRMSG(0) "Unwanted characters after option setting \"%s\"", t
545 /* --------------------------------------------------------------------------
546 * Print Menu of list of commands:
547 * ------------------------------------------------------------------------*/
549 static struct cmd cmds[] = {
550 {":?", HELP}, {":cd", CHGDIR}, {":also", ALSO},
551 {":type", TYPEOF}, {":!", SYSTEM}, {":load", LOAD},
552 {":reload", RELOAD}, {":gc", COLLECT}, {":edit", EDIT},
553 {":quit", QUIT}, {":set", SET}, {":find", FIND},
554 {":names", NAMES}, {":info", INFO}, {":project", PROJECT},
555 {":dump", DUMP}, {":ztats", STATS},
556 {":module",SETMODULE},
558 #if EXPLAIN_INSTANCE_RESOLUTION
561 {":version", PNTVER},
566 static Void local menu() {
567 Printf("LIST OF COMMANDS: Any command may be abbreviated to :c where\n");
568 Printf("c is the first character in the full name.\n\n");
569 Printf(":load <filenames> load modules from specified files\n");
570 Printf(":load clear all files except prelude\n");
571 Printf(":also <filenames> read additional modules\n");
572 Printf(":reload repeat last load command\n");
573 Printf(":project <filename> use project file\n");
574 Printf(":edit <filename> edit file\n");
575 Printf(":edit edit last module\n");
576 Printf(":module <module> set module for evaluating expressions\n");
577 Printf("<expr> evaluate expression\n");
578 Printf(":type <expr> print type of expression\n");
579 Printf(":? display this list of commands\n");
580 Printf(":set <options> set command line options\n");
581 Printf(":set help on command line options\n");
582 Printf(":names [pat] list names currently in scope\n");
583 Printf(":info <names> describe named objects\n");
584 Printf(":browse <modules> browse names defined in <modules>\n");
585 #if EXPLAIN_INSTANCE_RESOLUTION
586 Printf(":xplain <context> explain instance resolution for <context>\n");
588 Printf(":find <name> edit module containing definition of name\n");
589 Printf(":!command shell escape\n");
590 Printf(":cd dir change directory\n");
591 Printf(":gc force garbage collection\n");
592 Printf(":version print Hugs version\n");
593 Printf(":dump <name> print STG code for named fn\n");
594 #ifdef CRUDE_PROFILING
595 Printf(":ztats <name> print reduction stats\n");
597 Printf(":quit exit Hugs interpreter\n");
600 static Void local guidance() {
601 Printf("Command not recognised. ");
605 static Void local forHelp() {
606 Printf("Type :? for help\n");
609 /* --------------------------------------------------------------------------
610 * Setting of command line options:
611 * ------------------------------------------------------------------------*/
613 struct options toggle[] = { /* List of command line toggles */
614 {'s', 1, "Print no. reductions/cells after eval", &showStats},
615 {'t', 1, "Print type after evaluation", &addType},
616 {'g', 1, "Print no. cells recovered after gc", &gcMessages},
617 {'l', 1, "Literate modules as default", &literateScripts},
618 {'e', 1, "Warn about errors in literate modules", &literateErrors},
619 {'.', 1, "Print dots to show progress", &useDots},
620 {'q', 1, "Print nothing to show progress", &quiet},
621 {'w', 1, "Always show which modules are loaded", &listScripts},
622 {'k', 1, "Show kind errors in full", &kindExpert},
623 {'o', 0, "Allow overlapping instances", &allowOverlap},
624 {'S', 1, "Debug: show generated SC code", &debugSC},
625 {'a', 1, "Raise exception on assert failure", &flagAssert},
626 #if EXPLAIN_INSTANCE_RESOLUTION
627 {'x', 1, "Explain instance resolution", &showInstRes},
630 {'m', 0, "Use multi instance resolution", &multiInstRes},
635 static Void local set() { /* change command line options from*/
636 String s; /* Hugs command line */
638 if ((s=readFilename())!=0) {
640 if (!processOption(s)) {
641 ERRMSG(0) "Option string must begin with `+' or `-'"
644 } while ((s=readFilename())!=0);
650 /* --------------------------------------------------------------------------
651 * Change directory command:
652 * ------------------------------------------------------------------------*/
654 static Void local changeDir() { /* change directory */
655 String s = readFilename();
657 ERRMSG(0) "Unable to change to directory \"%s\"", s
663 /* --------------------------------------------------------------------------
665 * ------------------------------------------------------------------------*/
667 static jmp_buf catch_error; /* jump buffer for error trapping */
669 HugsBreakAction currentBreakAction = HugsIgnoreBreak;
671 static void handler_IgnoreBreak ( int sig )
673 setHandler ( handler_IgnoreBreak );
676 static void handler_LongjmpOnBreak ( int sig )
678 setHandler ( handler_LongjmpOnBreak );
679 Printf("{Interrupted!}\n");
680 longjmp(catch_error,1);
683 static void handler_RtsInterrupt ( int sig )
685 setHandler ( handler_RtsInterrupt );
689 HugsBreakAction setBreakAction ( HugsBreakAction newAction )
691 HugsBreakAction tmp = currentBreakAction;
692 currentBreakAction = newAction;
694 case HugsIgnoreBreak:
695 setHandler ( handler_IgnoreBreak ); break;
696 case HugsLongjmpOnBreak:
697 setHandler ( handler_LongjmpOnBreak ); break;
698 case HugsRtsInterrupt:
699 setHandler ( handler_RtsInterrupt ); break;
701 internal("setBreakAction");
707 /* --------------------------------------------------------------------------
708 * The new module chaser, loader, etc
709 * ------------------------------------------------------------------------*/
711 List moduleGraph = NIL;
712 List prelModules = NIL;
713 List targetModules = NIL;
715 static String modeToString ( Cell mode )
718 case FM_SOURCE: return "source";
719 case FM_OBJECT: return "object";
720 case FM_EITHER: return "source or object";
721 default: internal("modeToString");
725 static Cell childMode ( Cell modeMeRequest, Cell modeMeActual )
727 assert(modeMeActual == FM_SOURCE ||
728 modeMeActual == FM_OBJECT);
729 assert(modeMeRequest == FM_SOURCE ||
730 modeMeRequest == FM_OBJECT ||
731 modeMeRequest == FM_EITHER);
732 if (modeMeRequest == FM_SOURCE) return modeMeRequest;
733 if (modeMeRequest == FM_OBJECT) return modeMeRequest;
734 if (modeMeActual == FM_OBJECT) return FM_OBJECT;
735 if (modeMeActual == FM_SOURCE) return FM_EITHER;
736 internal("childMode");
739 static Bool compatibleNewMode ( Cell modeNew, Cell modeExisting )
741 if (modeNew == FM_OBJECT && modeExisting == FM_OBJECT) return TRUE;
742 if (modeNew == FM_SOURCE && modeExisting == FM_SOURCE) return TRUE;
743 if (modeNew == FM_EITHER && modeExisting == FM_OBJECT) return TRUE;
744 if (modeNew == FM_EITHER && modeExisting == FM_SOURCE) return TRUE;
748 static void setCurrentFile ( Module mod )
750 assert(isModule(mod));
751 strncpy(currentFileName, textToStr(module(mod).text), 990);
752 strcat(currentFileName, textToStr(module(mod).srcExt));
753 currentFile = currentFileName;
754 moduleBeingParsed = mod;
757 static void clearCurrentFile ( void )
760 moduleBeingParsed = NIL;
763 static void ppMG ( void )
766 for (t = moduleGraph; nonNull(t); t=tl(t)) {
770 FPrintf ( stderr, " %s\n", textToStr(textOf(snd(u))));
773 FPrintf ( stderr, " {" );
774 for (v = snd(u); nonNull(v); v=tl(v))
775 FPrintf ( stderr, "%s ", textToStr(textOf(hd(v))) );
776 FPrintf ( stderr, "}\n" );
785 static Bool elemMG ( ConId mod )
788 for (gs = moduleGraph; nonNull(gs); gs=tl(gs))
789 switch (whatIs(hd(gs))) {
791 if (textOf(mod)==textOf(snd(hd(gs)))) return TRUE;
794 if (varIsMember(textOf(mod),snd(hd(gs)))) return TRUE;
803 static ConId selectArbitrarilyFromGroup ( Cell group )
805 switch (whatIs(group)) {
806 case GRP_NONREC: return snd(group);
807 case GRP_REC: return hd(snd(group));
808 default: internal("selectArbitrarilyFromGroup");
812 static ConId selectLatestMG ( void )
814 List gs = moduleGraph;
815 if (isNull(gs)) internal("selectLatestMG(1)");
816 while (nonNull(gs) && nonNull(tl(gs))) gs = tl(gs);
817 return selectArbitrarilyFromGroup(hd(gs));
821 static List /* of CONID */ listFromSpecifiedMG ( List mg )
825 for (gs = mg; nonNull(gs); gs=tl(gs)) {
826 switch (whatIs(hd(gs))) {
827 case GRP_REC: cs = appendOnto(cs,snd(hd(gs))); break;
828 case GRP_NONREC: cs = cons(snd(hd(gs)),cs); break;
829 default: internal("listFromSpecifiedMG");
835 static List /* of CONID */ listFromMG ( void )
837 return listFromSpecifiedMG ( moduleGraph );
841 /* Calculate the strongly connected components of modgList
842 and assign them to moduleGraph. Uses the .uses field of
843 each of the modules to build the graph structure.
845 #define SCC modScc /* make scc algorithm for StgVars */
846 #define LOWLINK modLowlink
847 #define DEPENDS(t) snd(t)
848 #define SETDEPENDS(c,v) snd(c)=v
855 static void mgFromList ( List /* of CONID */ modgList )
861 List adjList; /* :: [ (Text, [Text]) ] */
867 for (t = modgList; nonNull(t); t=tl(t)) {
869 mod = findModule(mT);
870 assert(nonNull(mod));
872 for (u = module(mod).uses; nonNull(u); u=tl(u))
873 usesT = cons(textOf(hd(u)),usesT);
875 /* artificially give all modules a dependency on Prelude */
876 if (mT != textPrelude && mT != textPrelPrim)
877 usesT = cons(textPrelude,usesT);
878 adjList = cons(pair(mT,usesT),adjList);
881 /* adjList is now [ (module-text, [modules-which-i-import-text]) ].
882 Modify this so that the adjacency list is a list of pointers
883 back to bits of adjList -- that's what modScc needs.
885 for (t = adjList; nonNull(t); t=tl(t)) {
887 /* for each elem of the adjacency list ... */
888 for (u = snd(hd(t)); nonNull(u); u=tl(u)) {
891 /* find the element of adjList whose fst is a */
892 for (v = adjList; nonNull(v); v=tl(v)) {
894 assert(isText(fst(hd(v))));
895 if (fst(hd(v))==a) break;
897 if (isNull(v)) internal("mgFromList");
898 adj = cons(hd(v),adj);
903 adjList = modScc ( adjList );
904 /* adjList is now [ [(module-text, aux-info-field)] ] */
908 for (t = adjList; nonNull(t); t=tl(t)) {
911 /* scc :: [ (module-text, aux-info-field) ] */
912 for (u = scc; nonNull(u); u=tl(u))
913 hd(u) = mkCon(fst(hd(u)));
916 if (length(scc) > 1) {
919 /* singleton module in scc; does it import itself? */
920 mod = findModule ( textOf(hd(scc)) );
921 assert(nonNull(mod));
923 for (u = module(mod).uses; nonNull(u); u=tl(u))
924 if (textOf(hd(u))==textOf(hd(scc)))
929 moduleGraph = cons( ap(GRP_REC,scc), moduleGraph ); else
930 moduleGraph = cons( ap(GRP_NONREC,hd(scc)), moduleGraph );
932 moduleGraph = reverse(moduleGraph);
936 static List /* of CONID */ getModuleImports ( Cell tree )
942 for (tes = zthd3(unap(M_MODULE,tree)); nonNull(tes); tes=tl(tes)) {
946 use = zfst(unap(M_IMPORT_Q,te));
948 if (!varIsMember(textOf(use),uses)) uses = cons ( use, uses );
951 use = zfst(unap(M_IMPORT_UNQ,te));
953 if (!varIsMember(textOf(use),uses)) uses = cons ( use, uses );
963 static void processModule ( Module m )
980 foreignImports = NIL;
981 foreignExports = NIL;
988 tree = unap(M_MODULE,module(m).tree);
991 if (textOf(modNm) != module(m).text) {
992 ERRMSG(0) "Module name \"%s\" does not match file name \"%s%s\"",
993 textToStr(textOf(modNm)),
994 textToStr(module(m).text),
995 textToStr(module(m).srcExt)
999 setExportList(zsnd3(tree));
1000 topEnts = zthd3(tree);
1002 for (tes = topEnts; nonNull(tes); tes=tl(tes)) {
1004 assert(isGenPair(te));
1006 switch(whatIs(te)) {
1008 addQualImport(zfst(te2),zsnd(te2));
1011 addUnqualImport(zfst(te2),zsnd(te2));
1014 tyconDefn(intOf(zsel14(te2)),zsel24(te2),zsel34(te2),zsel44(te2));
1017 classDefn(intOf(zsel14(te2)),zsel24(te2),zsel34(te2),zsel44(te2));
1020 instDefn(intOf(zfst3(te2)),zsnd3(te2),zthd3(te2));
1023 defaultDefn(intOf(zfst(te2)),zsnd(te2));
1026 foreignImport(intOf(zsel15(te2)),zsel25(te2),zsel35(te2),
1027 zsel45(te2),zsel55(te2));
1030 foreignExport(intOf(zsel15(te2)),zsel25(te2),zsel35(te2),
1031 zsel45(te2),zsel55(te2));
1033 valDefns = cons(te2,valDefns);
1036 internal("processModule");
1045 static Module parseModuleOrInterface ( ConId mc, Cell modeRequest )
1047 /* Allocate a module-table entry. */
1048 /* Parse the entity and fill in the .tree and .uses entries. */
1051 Bool sAvail; Time sTime; Long sSize;
1052 Bool oiAvail; Time oiTime; Long oSize; Long iSize;
1057 Text mt = textOf(mc);
1058 Module mod = findModule ( mt );
1060 /* fprintf ( stderr, "parseModuleOrInterface `%s' == %d\n",
1061 textToStr(mt),mod); */
1062 if (nonNull(mod) && !module(mod).fake)
1063 internal("parseModuleOrInterface");
1065 module(mod).fake = FALSE;
1068 mod = newModule(mt);
1070 /* This call malloc-ates path; we should deallocate it. */
1071 ok = findFilesForModule (
1072 textToStr(module(mod).text),
1075 &sAvail, &sTime, &sSize,
1076 &oiAvail, &oiTime, &oSize, &iSize
1079 if (!ok) goto cant_find;
1080 if (!sAvail && !oiAvail) goto cant_find;
1082 /* Find out whether to use source or object. */
1083 switch (modeRequest) {
1085 if (!sAvail) goto cant_find;
1089 if (!oiAvail) goto cant_find;
1093 if ( sAvail && !oiAvail) { useSource = TRUE; break; }
1094 if (!sAvail && oiAvail) { useSource = FALSE; break; }
1095 useSource = firstTimeIsLater ( sTime, oiTime ) ? TRUE : FALSE;
1098 internal("parseModuleOrInterface");
1101 /* Actually do the parsing. */
1103 module(mod).srcExt = findText(sExt);
1104 setCurrentFile(mod);
1106 strcat(name, textToStr(mt));
1108 module(mod).tree = parseModule(name,sSize);
1109 module(mod).uses = getModuleImports(module(mod).tree);
1110 module(mod).mode = FM_SOURCE;
1111 module(mod).lastStamp = sTime;
1113 module(mod).srcExt = findText(HI_ENDING);
1114 setCurrentFile(mod);
1116 strcat(name, textToStr(mt));
1117 strcat(name, DLL_ENDING);
1118 module(mod).objName = findText(name);
1119 module(mod).objSize = oSize;
1121 strcat(name, textToStr(mt));
1122 strcat(name, ".u_hi");
1123 module(mod).tree = parseInterface(name,iSize);
1124 module(mod).uses = getInterfaceImports(module(mod).tree);
1125 module(mod).mode = FM_OBJECT;
1126 module(mod).lastStamp = oiTime;
1129 if (path) free(path);
1133 if (path) free(path);
1136 "Can't find %s for module \"%s\"",
1137 modeToString(modeRequest), textToStr(mt)
1142 static void tryLoadGroup ( Cell grp )
1146 switch (whatIs(grp)) {
1148 m = findModule(textOf(snd(grp)));
1150 if (module(m).mode == FM_SOURCE) {
1151 processModule ( m );
1152 module(m).tree = NIL;
1154 processInterfaces ( singleton(snd(grp)) );
1155 m = findModule(textOf(snd(grp)));
1157 module(m).tree = NIL;
1161 for (t = snd(grp); nonNull(t); t=tl(t)) {
1162 m = findModule(textOf(hd(t)));
1164 if (module(m).mode == FM_SOURCE) {
1165 ERRMSG(0) "Source module \"%s\" imports itself recursively",
1166 textToStr(textOf(hd(t)))
1170 processInterfaces ( snd(grp) );
1171 for (t = snd(grp); nonNull(t); t=tl(t)) {
1172 m = findModule(textOf(hd(t)));
1174 module(m).tree = NIL;
1178 internal("tryLoadGroup");
1183 static void fallBackToPrelModules ( void )
1186 for (m = MODULE_BASE_ADDR;
1187 m < MODULE_BASE_ADDR+tabModuleSz; m++)
1189 && !varIsMember(module(m).text, prelModules))
1194 /* This function catches exceptions in most of the system.
1195 So it's only ok for procedures called from this one
1196 to do EENDs (ie, write error messages). Others should use
1199 static void achieveTargetModules ( Bool loadingThePrelude )
1202 volatile List modgList;
1204 volatile Module mod;
1209 Bool sAvail; Time sTime; Long sSize;
1210 Bool oiAvail; Time oiTime; Long oSize; Long iSize;
1212 volatile Time oisTime;
1213 volatile Bool out_of_date;
1214 volatile List ood_new;
1216 volatile List modgList_new;
1217 volatile List parsedButNotLoaded;
1218 volatile List toChase;
1219 volatile List trans_cl;
1220 volatile List trans_cl_new;
1225 volatile List badMods;
1227 setBreakAction ( HugsIgnoreBreak );
1229 /* First, examine timestamps to find out which modules are
1230 out of date with respect to the source/interface/object files.
1233 modgList = listFromMG();
1235 for (t = modgList; nonNull(t); t=tl(t)) {
1237 if (varIsMember(textOf(hd(t)),prelModules))
1240 mod = findModule(textOf(hd(t)));
1241 if (isNull(mod)) internal("achieveTargetSet(1)");
1243 /* In standalone mode, only succeeds for source modules. */
1244 ok = findFilesForModule (
1245 textToStr(module(mod).text),
1248 &sAvail, &sTime, &sSize,
1249 &oiAvail, &oiTime, &oSize, &iSize
1252 if (!combined && !sAvail) ok = FALSE;
1254 fallBackToPrelModules();
1256 "Can't find source or object+interface for module \"%s\"",
1257 textToStr(module(mod).text)
1259 if (path) free(path);
1263 if (sAvail && oiAvail) {
1264 oisTime = whicheverIsLater(sTime,oiTime);
1266 else if (sAvail && !oiAvail) {
1269 else if (!sAvail && oiAvail) {
1273 internal("achieveTargetSet(2)");
1276 out_of_date = firstTimeIsLater(oisTime,module(mod).lastStamp);
1278 assert(!varIsMember(textOf(hd(t)),ood));
1279 ood = cons(hd(t),ood);
1282 if (path) { free(path); path = NULL; };
1285 /* Second, form a simplistic transitive closure of the out-of-date
1286 modules: a module is out of date if it imports an out-of-date
1291 for (t = modgList; nonNull(t); t=tl(t)) {
1292 mod = findModule(textOf(hd(t)));
1293 assert(nonNull(mod));
1294 for (us = module(mod).uses; nonNull(us); us=tl(us))
1295 if (varIsMember(textOf(hd(us)),ood))
1298 if (varIsMember(textOf(hd(t)),prelModules))
1299 Printf ( "warning: prelude module \"%s\" is out-of-date\n",
1300 textToStr(textOf(hd(t))) );
1302 if (!varIsMember(textOf(hd(t)),ood_new) &&
1303 !varIsMember(textOf(hd(t)),ood))
1304 ood_new = cons(hd(t),ood_new);
1307 if (isNull(ood_new)) break;
1308 ood = appendOnto(ood_new,ood);
1311 /* Now ood holds the entire set of modules which are out-of-date.
1312 Throw them out of the system, yielding a "reduced system",
1313 in which the remaining modules are in-date.
1315 for (t = ood; nonNull(t); t=tl(t)) {
1316 mod = findModule(textOf(hd(t)));
1317 assert(nonNull(mod));
1321 for (t = modgList; nonNull(t); t=tl(t))
1322 if (!varIsMember(textOf(hd(t)),ood))
1323 modgList_new = cons(hd(t),modgList_new);
1324 modgList = modgList_new;
1326 /* Update the module group list to reflect the reduced system.
1327 We do this so that if the following parsing phases fail, we can
1328 safely fall back to the reduced system.
1330 mgFromList ( modgList );
1332 /* Parse modules/interfaces, collecting parse trees and chasing
1333 imports, starting from the target set.
1335 toChase = dupList(targetModules);
1336 for (t = toChase; nonNull(t); t=tl(t)) {
1337 Cell mode = (!combined)
1339 : ( (loadingThePrelude && combined)
1342 hd(t) = zpair(hd(t), mode);
1345 /* toChase :: [ ((ConId, {FM_SOURCE|FM_OBJECT|FM_EITHER} )) ] */
1347 parsedButNotLoaded = NIL;
1350 while (nonNull(toChase)) {
1351 ConId mc = zfst(hd(toChase));
1352 Cell mode = zsnd(hd(toChase));
1353 toChase = tl(toChase);
1354 if (varIsMember(textOf(mc),modgList)
1355 || varIsMember(textOf(mc),parsedButNotLoaded)) {
1356 /* either exists fully, or is at least parsed */
1357 mod = findModule(textOf(mc));
1358 assert(nonNull(mod));
1359 if (!compatibleNewMode(mode,module(mod).mode)) {
1362 "module %s: %s required, but %s is more recent",
1363 textToStr(textOf(mc)), modeToString(mode),
1364 modeToString(module(mod).mode)
1366 goto parseException;
1370 setBreakAction ( HugsLongjmpOnBreak );
1371 if (setjmp(catch_error)==0) {
1372 /* try this; it may throw an exception */
1373 mod = parseModuleOrInterface ( mc, mode );
1375 /* here's the exception handler, if parsing fails */
1376 /* A parse error (or similar). Clean up and abort. */
1378 setBreakAction ( HugsIgnoreBreak );
1379 mod = findModule(textOf(mc));
1380 if (nonNull(mod)) nukeModule(mod);
1381 for (t = parsedButNotLoaded; nonNull(t); t=tl(t)) {
1382 mod = findModule(textOf(hd(t)));
1383 assert(nonNull(mod));
1384 if (nonNull(mod)) nukeModule(mod);
1387 /* end of the exception handler */
1389 setBreakAction ( HugsIgnoreBreak );
1391 parsedButNotLoaded = cons(mc, parsedButNotLoaded);
1392 for (t = module(mod).uses; nonNull(t); t=tl(t))
1394 zpair( hd(t), childMode(mode,module(mod).mode) ),
1399 modgList = dupOnto(parsedButNotLoaded, modgList);
1401 /* We successfully parsed all modules reachable from the target
1402 set which were not part of the reduced system. However, there
1403 may be modules in the reduced system which are not reachable from
1404 the target set. We detect these now by building the transitive
1405 closure of the target set, and nuking modules in the reduced
1406 system which are not part of that closure.
1408 trans_cl = dupList(targetModules);
1411 for (t = trans_cl; nonNull(t); t=tl(t)) {
1412 mod = findModule(textOf(hd(t)));
1413 assert(nonNull(mod));
1414 for (u = module(mod).uses; nonNull(u); u=tl(u))
1415 if (!varIsMember(textOf(hd(u)),trans_cl)
1416 && !varIsMember(textOf(hd(u)),trans_cl_new)
1417 && !varIsMember(textOf(hd(u)),prelModules))
1418 trans_cl_new = cons(hd(u),trans_cl_new);
1420 if (isNull(trans_cl_new)) break;
1421 trans_cl = appendOnto(trans_cl_new,trans_cl);
1424 for (t = modgList; nonNull(t); t=tl(t)) {
1425 if (varIsMember(textOf(hd(t)),trans_cl)) {
1426 modgList_new = cons(hd(t),modgList_new);
1428 mod = findModule(textOf(hd(t)));
1429 assert(nonNull(mod));
1433 modgList = modgList_new;
1435 /* Now, the module symbol tables hold exactly the set of
1436 modules reachable from the target set, and modgList holds
1437 their names. Calculate the scc-ified module graph,
1438 since we need that to guide the next stage, that of
1439 Actually Loading the modules.
1441 If no errors occur, moduleGraph will reflect the final graph
1442 loaded. If an error occurs loading a group, we nuke
1443 that group, truncate the moduleGraph just prior to that
1444 group, and exit. That leaves the system having successfully
1445 loaded all groups prior to the one which failed.
1447 mgFromList ( modgList );
1449 for (mg = moduleGraph; nonNull(mg); mg=tl(mg)) {
1452 if (!varIsMember(textOf(selectArbitrarilyFromGroup(grp)),
1453 parsedButNotLoaded)) continue;
1455 setBreakAction ( HugsLongjmpOnBreak );
1456 if (setjmp(catch_error)==0) {
1457 /* try this; it may throw an exception */
1460 /* here's the exception handler, if static/typecheck etc fails */
1461 /* nuke the entire rest (ie, the unloaded part)
1462 of the module graph */
1463 setBreakAction ( HugsIgnoreBreak );
1464 badMods = listFromSpecifiedMG ( mg );
1465 for (t = badMods; nonNull(t); t=tl(t)) {
1466 mod = findModule(textOf(hd(t)));
1467 if (nonNull(mod)) nukeModule(mod);
1469 /* truncate the module graph just prior to this group. */
1473 if (isNull(mg)) break;
1474 if (hd(mg) == grp) break;
1475 mg2 = cons ( hd(mg), mg2 );
1478 moduleGraph = reverse(mg2);
1480 /* end of the exception handler */
1482 setBreakAction ( HugsIgnoreBreak );
1485 /* Err .. I think that's it. If we get here, we've successfully
1486 achieved the target set. Phew!
1488 setBreakAction ( HugsIgnoreBreak );
1492 static Bool loadThePrelude ( void )
1497 moduleGraph = prelModules = NIL;
1500 conPrelude = mkCon(findText("Prelude"));
1501 conPrelHugs = mkCon(findText("PrelHugs"));
1502 targetModules = doubleton(conPrelude,conPrelHugs);
1503 achieveTargetModules(TRUE);
1504 ok = elemMG(conPrelude) && elemMG(conPrelHugs);
1506 conPrelude = mkCon(findText("Prelude"));
1507 targetModules = singleton(conPrelude);
1508 achieveTargetModules(TRUE);
1509 ok = elemMG(conPrelude);
1512 if (ok) prelModules = listFromMG();
1517 static void refreshActions ( ConId nextCurrMod, Bool cleanAfter )
1520 ConId tryFor = mkCon(module(currentModule).text);
1521 achieveTargetModules(FALSE);
1522 if (nonNull(nextCurrMod))
1523 tryFor = nextCurrMod;
1524 if (!elemMG(tryFor))
1525 tryFor = selectLatestMG();
1526 /* combined mode kludge, to get Prelude rather than PrelHugs */
1527 if (combined && textOf(tryFor)==findText("PrelHugs"))
1528 tryFor = mkCon(findText("Prelude"));
1531 /* delete any targetModules which didn't actually get loaded */
1533 targetModules = NIL;
1534 for (; nonNull(t); t=tl(t))
1536 targetModules = cons(hd(t),targetModules);
1539 setCurrModule ( findModule(textOf(tryFor)) );
1540 Printf("Hugs session for:\n");
1545 static void addActions ( List extraModules /* :: [CONID] */ )
1548 for (t = extraModules; nonNull(t); t=tl(t)) {
1549 ConId extra = hd(t);
1550 if (!varIsMember(textOf(extra),targetModules))
1551 targetModules = cons(extra,targetModules);
1553 refreshActions ( isNull(extraModules)
1555 : hd(reverse(extraModules)),
1561 static void loadActions ( List loadModules /* :: [CONID] */ )
1564 targetModules = dupList ( prelModules );
1566 for (t = loadModules; nonNull(t); t=tl(t)) {
1568 if (!varIsMember(textOf(load),targetModules))
1569 targetModules = cons(load,targetModules);
1571 refreshActions ( isNull(loadModules)
1573 : hd(reverse(loadModules)),
1579 /* --------------------------------------------------------------------------
1580 * Access to external editor:
1581 * ------------------------------------------------------------------------*/
1583 /* ToDo: All this editor stuff needs fixing. */
1585 static Void local editor() { /* interpreter-editor interface */
1587 String newFile = readFilename();
1589 setLastEdit(newFile,0);
1590 if (readFilename()) {
1591 ERRMSG(0) "Multiple filenames not permitted"
1599 static Void local find() { /* edit file containing definition */
1602 String nm = readFilename(); /* of specified name */
1604 ERRMSG(0) "No name specified"
1607 else if (readFilename()) {
1608 ERRMSG(0) "Multiple names not permitted"
1614 setCurrModule(findEvalModule());
1616 if (nonNull(c=findTycon(t=findText(nm)))) {
1617 if (startEdit(tycon(c).line,scriptName[scriptThisTycon(c)])) {
1618 readScripts(N_PRELUDE_SCRIPTS);
1620 } else if (nonNull(c=findName(t))) {
1621 if (startEdit(name(c).line,scriptName[scriptThisName(c)])) {
1622 readScripts(N_PRELUDE_SCRIPTS);
1625 ERRMSG(0) "No current definition for name \"%s\"", nm
1632 static Void local runEditor() { /* run editor on script lastEdit */
1634 if (startEdit(lastEdLine,lastEdit)) /* at line lastEdLine */
1635 readScripts(N_PRELUDE_SCRIPTS);
1639 static Void local setLastEdit(fname,line)/* keep name of last file to edit */
1645 lastEdit = strCopy(fname);
1650 /* --------------------------------------------------------------------------
1651 * Read and evaluate an expression:
1652 * ------------------------------------------------------------------------*/
1654 static Void setModule ( void ) {
1655 /*set module in which to evaluate expressions*/
1658 String s = readFilename();
1660 mc = selectLatestMG();
1661 if (combined && textOf(mc)==findText("PrelHugs"))
1662 mc = mkCon(findText("Prelude"));
1663 m = findModule(textOf(mc));
1666 m = findModule(findText(s));
1668 ERRMSG(0) "Cannot find module \"%s\"", s
1676 static Module allocEvalModule ( void )
1678 Module evalMod = newModule( findText("_Eval_Module_") );
1679 module(evalMod).names = module(currentModule).names;
1680 module(evalMod).tycons = module(currentModule).tycons;
1681 module(evalMod).classes = module(currentModule).classes;
1682 module(evalMod).qualImports
1683 = singleton(pair(mkCon(textPrelude),modulePrelude));
1687 static Void local evaluator() { /* evaluate expr and print value */
1690 volatile Kinds ks = NIL;
1691 volatile Module evalMod = allocEvalModule();
1692 volatile Module currMod = currentModule;
1693 setCurrModule(evalMod);
1696 defaultDefns = combined ? stdDefaults : evalDefaults;
1698 setBreakAction ( HugsLongjmpOnBreak );
1699 if (setjmp(catch_error)==0) {
1703 type = typeCheckExp(TRUE);
1705 /* if an exception happens, we arrive here */
1706 setBreakAction ( HugsIgnoreBreak );
1707 goto cleanup_and_return;
1710 setBreakAction ( HugsIgnoreBreak );
1711 if (isPolyType(type)) {
1712 ks = polySigOf(type);
1713 bd = monotypeOf(type);
1718 if (whatIs(bd)==QUAL) {
1719 ERRMSG(0) "Unresolved overloading" ETHEN
1720 ERRTEXT "\n*** Type : " ETHEN ERRTYPE(type);
1721 ERRTEXT "\n*** Expression : " ETHEN ERREXPR(inputExpr);
1724 goto cleanup_and_return;
1728 if (isProgType(ks,bd)) {
1729 inputExpr = ap(nameRunIO_toplevel,inputExpr);
1733 Cell d = provePred(ks,NIL,ap(classShow,bd));
1735 ERRMSG(0) "Cannot find \"show\" function for:" ETHEN
1736 ERRTEXT "\n*** expression : " ETHEN ERREXPR(inputExpr);
1737 ERRTEXT "\n*** of type : " ETHEN ERRTYPE(type);
1740 goto cleanup_and_return;
1742 inputExpr = ap2(nameShow, d,inputExpr);
1743 inputExpr = ap (namePutStr, inputExpr);
1744 inputExpr = ap (nameRunIO_toplevel, inputExpr);
1746 evalExp(); printf("\n");
1749 printType(stdout,type);
1756 printf ( "result type is " );
1757 printType ( stdout, type );
1765 setBreakAction ( HugsIgnoreBreak );
1766 nukeModule(evalMod);
1767 setCurrModule(currMod);
1768 setCurrentFile(currMod);
1773 /* --------------------------------------------------------------------------
1774 * Print type of input expression:
1775 * ------------------------------------------------------------------------*/
1777 static Void showtype ( void ) { /* print type of expression (if any)*/
1780 volatile Module evalMod = allocEvalModule();
1781 volatile Module currMod = currentModule;
1782 setCurrModule(evalMod);
1784 if (setjmp(catch_error)==0) {
1788 defaultDefns = evalDefaults;
1789 type = typeCheckExp(FALSE);
1790 printExp(stdout,inputExpr);
1792 printType(stdout,type);
1795 /* if an exception happens, we arrive here */
1798 nukeModule(evalMod);
1799 setCurrModule(currMod);
1803 static Void local browseit(mod,t,all)
1810 Printf("module %s where\n",textToStr(module(mod).text));
1811 for (cs = module(mod).names; nonNull(cs); cs=tl(cs)) {
1813 /* only look at things defined in this module,
1814 unless `all' flag is set */
1815 if (all || name(nm).mod == mod) {
1816 /* unwanted artifacts, like lambda lifted values,
1817 are in the list of names, but have no types */
1818 if (nonNull(name(nm).type)) {
1819 printExp(stdout,nm);
1821 printType(stdout,name(nm).type);
1823 Printf(" -- data constructor");
1824 } else if (isMfun(nm)) {
1825 Printf(" -- class member");
1826 } else if (isSfun(nm)) {
1827 Printf(" -- selector function");
1835 Printf("Unknown module %s\n",t);
1840 static Void local browse() { /* browse modules */
1841 Int count = 0; /* or give menu of commands */
1845 for (; (s=readFilename())!=0; count++)
1846 if (strcmp(s,"all") == 0) {
1850 browseit(findModule(findText(s)),s,all);
1852 browseit(currentModule,NULL,all);
1856 #if EXPLAIN_INSTANCE_RESOLUTION
1857 static Void local xplain() { /* print type of expression (if any)*/
1859 Bool sir = showInstRes;
1861 setCurrModule(findEvalModule());
1862 startNewScript(0); /* Enables recovery of storage */
1863 /* allocated during evaluation */
1867 d = provePred(NIL,NIL,hd(inputContext));
1869 fprintf(stdout, "not Sat\n");
1871 fprintf(stdout, "Sat\n");
1877 /* --------------------------------------------------------------------------
1878 * Enhanced help system: print current list of scripts or give information
1880 * ------------------------------------------------------------------------*/
1882 static String local objToStr(m,c)
1885 #if 1 || DISPLAY_QUANTIFIERS
1886 static char newVar[60];
1887 switch (whatIs(c)) {
1888 case NAME : if (m == name(c).mod) {
1889 sprintf(newVar,"%s", textToStr(name(c).text));
1891 sprintf(newVar,"%s.%s",
1892 textToStr(module(name(c).mod).text),
1893 textToStr(name(c).text));
1897 case TYCON : if (m == tycon(c).mod) {
1898 sprintf(newVar,"%s", textToStr(tycon(c).text));
1900 sprintf(newVar,"%s.%s",
1901 textToStr(module(tycon(c).mod).text),
1902 textToStr(tycon(c).text));
1906 case CLASS : if (m == cclass(c).mod) {
1907 sprintf(newVar,"%s", textToStr(cclass(c).text));
1909 sprintf(newVar,"%s.%s",
1910 textToStr(module(cclass(c).mod).text),
1911 textToStr(cclass(c).text));
1915 default : internal("objToStr");
1919 static char newVar[33];
1920 switch (whatIs(c)) {
1921 case NAME : sprintf(newVar,"%s", textToStr(name(c).text));
1924 case TYCON : sprintf(newVar,"%s", textToStr(tycon(c).text));
1927 case CLASS : sprintf(newVar,"%s", textToStr(cclass(c).text));
1930 default : internal("objToStr");
1938 static Void dumpStg ( void )
1944 setCurrModule(findEvalModule());
1949 /* request to locate a symbol by name */
1950 if (s && (*s == '?')) {
1951 Text t = findText(s+1);
1952 locateSymbolByName(t);
1956 /* request to dump a bit of the heap */
1957 if (s && (*s == '-' || isdigit(*s))) {
1964 /* request to dump a symbol table entry */
1966 || !(*s == 't' || *s == 'n' || *s == 'c' || *s == 'i')
1967 || !isdigit(s[1])) {
1968 fprintf(stderr, ":d -- bad request `%s'\n", s );
1973 case 't': dumpTycon(i); break;
1974 case 'n': dumpName(i); break;
1975 case 'c': dumpClass(i); break;
1976 case 'i': dumpInst(i); break;
1977 default: fprintf(stderr, ":d -- `%c' not implemented\n", *s );
1983 static Void local dumpStg( void ) { /* print STG stuff */
1988 Cell v; /* really StgVar */
1989 setCurrModule(findEvalModule());
1991 for (; (s=readFilename())!=0;) {
1994 /* find the name while ignoring module scopes */
1995 for (i=NAMEMIN; i<nameHw; i++)
1996 if (name(i).text == t) n = i;
1998 /* perhaps it's an "idNNNNNN" thing? */
2001 s[0]=='i' && s[1]=='d' && isdigit(s[2])) {
2004 while (isdigit(s[i])) {
2005 v = v * 10 + (s[i]-'0');
2009 n = nameFromStgVar(v);
2012 if (isNull(n) && whatIs(v)==STGVAR) {
2013 Printf ( "\n{- `%s' has no nametable entry -}\n", s );
2014 printStg(stderr, v );
2017 Printf ( "Unknown reference `%s'\n", s );
2020 Printf ( "Not a Name: `%s'\n", s );
2022 if (isNull(name(n).stgVar)) {
2023 Printf ( "Doesn't have a STG tree: %s\n", s );
2025 Printf ( "\n{- stgVar of `%s' is id%d -}\n", s, -name(n).stgVar);
2026 printStg(stderr, name(n).stgVar);
2032 static Void local info() { /* describe objects */
2033 Int count = 0; /* or give menu of commands */
2036 for (; (s=readFilename())!=0; count++) {
2037 describe(findText(s));
2040 /* whatScripts(); */
2045 static Void local describe(t) /* describe an object */
2047 Tycon tc = findTycon(t);
2048 Class cl = findClass(t);
2049 Name nm = findName(t);
2051 if (nonNull(tc)) { /* as a type constructor */
2055 for (i=0; i<tycon(tc).arity; ++i) {
2056 t = ap(t,mkOffset(i));
2058 Printf("-- type constructor");
2060 Printf(" with kind ");
2061 printKind(stdout,tycon(tc).kind);
2064 switch (tycon(tc).what) {
2065 case SYNONYM : Printf("type ");
2066 printType(stdout,t);
2068 printType(stdout,tycon(tc).defn);
2072 case DATATYPE : { List cs = tycon(tc).defn;
2073 if (tycon(tc).what==DATATYPE) {
2078 printType(stdout,t);
2080 mapProc(printSyntax,cs);
2082 Printf("\n-- constructors:");
2084 for (; hasCfun(cs); cs=tl(cs)) {
2086 printExp(stdout,hd(cs));
2088 printType(stdout,name(hd(cs)).type);
2091 Printf("\n-- selectors:");
2093 for (; nonNull(cs); cs=tl(cs)) {
2095 printExp(stdout,hd(cs));
2097 printType(stdout,name(hd(cs)).type);
2102 case RESTRICTSYN : Printf("type ");
2103 printType(stdout,t);
2104 Printf(" = <restricted>");
2108 if (nonNull(in=findFirstInst(tc))) {
2109 Printf("\n-- instances:\n");
2112 in = findNextInst(tc,in);
2113 } while (nonNull(in));
2118 if (nonNull(cl)) { /* as a class */
2119 List ins = cclass(cl).instances;
2120 Kinds ks = cclass(cl).kinds;
2121 if (nonNull(ks) && isNull(tl(ks)) && hd(ks)==STAR) {
2122 Printf("-- type class");
2124 Printf("-- constructor class");
2126 Printf(" with arity ");
2127 printKinds(stdout,ks);
2131 mapProc(printSyntax,cclass(cl).members);
2133 if (nonNull(cclass(cl).supers)) {
2134 printContext(stdout,cclass(cl).supers);
2137 printPred(stdout,cclass(cl).head);
2139 if (nonNull(cclass(cl).fds)) {
2140 List fds = cclass(cl).fds;
2142 for (; nonNull(fds); fds=tl(fds)) {
2144 printFD(stdout,hd(fds));
2149 if (nonNull(cclass(cl).members)) {
2150 List ms = cclass(cl).members;
2153 Type t = name(hd(ms)).type;
2154 if (isPolyType(t)) {
2158 printExp(stdout,hd(ms));
2160 if (isNull(tl(fst(snd(t))))) {
2163 t = ap(QUAL,pair(tl(fst(snd(t))),snd(snd(t))));
2165 printType(stdout,t);
2167 } while (nonNull(ms));
2171 Printf("\n-- instances:\n");
2175 } while (nonNull(ins));
2180 if (nonNull(nm)) { /* as a function/name */
2182 printExp(stdout,nm);
2184 if (nonNull(name(nm).type)) {
2185 printType(stdout,name(nm).type);
2187 Printf("<unknown type>");
2190 Printf(" -- data constructor");
2191 } else if (isMfun(nm)) {
2192 Printf(" -- class member");
2193 } else if (isSfun(nm)) {
2194 Printf(" -- selector function");
2200 if (isNull(tc) && isNull(cl) && isNull(nm)) {
2201 Printf("Unknown reference `%s'\n",textToStr(t));
2205 static Void local printSyntax(nm)
2207 Syntax sy = syntaxOf(nm);
2208 Text t = name(nm).text;
2209 String s = textToStr(t);
2210 if (sy != defaultSyntax(t)) {
2212 switch (assocOf(sy)) {
2213 case LEFT_ASS : Putchar('l'); break;
2214 case RIGHT_ASS : Putchar('r'); break;
2215 case NON_ASS : break;
2217 Printf(" %i ",precOf(sy));
2218 if (isascii((int)(*s)) && isalpha((int)(*s))) {
2227 static Void local showInst(in) /* Display instance decl header */
2229 Printf("instance ");
2230 if (nonNull(inst(in).specifics)) {
2231 printContext(stdout,inst(in).specifics);
2234 printPred(stdout,inst(in).head);
2238 /* --------------------------------------------------------------------------
2239 * List all names currently in scope:
2240 * ------------------------------------------------------------------------*/
2242 static Void local listNames() { /* list names matching optional pat*/
2243 String pat = readFilename();
2245 Int width = getTerminalWidth() - 1;
2248 Module mod = currentModule;
2250 if (pat) { /* First gather names to list */
2252 names = addNamesMatching(pat,names);
2253 } while ((pat=readFilename())!=0);
2255 names = addNamesMatching((String)0,names);
2257 if (isNull(names)) { /* Then print them out */
2258 ERRMSG(0) "No names selected"
2262 for (termPos=0; nonNull(names); names=tl(names)) {
2263 String s = objToStr(mod,hd(names));
2265 if (termPos+1+l>width) {
2268 } else if (termPos>0) {
2276 Printf("\n(%d names listed)\n", count);
2279 /* --------------------------------------------------------------------------
2280 * print a prompt and read a line of input:
2281 * ------------------------------------------------------------------------*/
2283 static Void local promptForInput(moduleName)
2284 String moduleName; {
2285 char promptBuffer[1000];
2287 /* This is portable but could overflow buffer */
2288 sprintf(promptBuffer,prompt,moduleName);
2290 /* Works on ANSI C - but pre-ANSI compilers return a pointer to
2291 * promptBuffer instead.
2293 if (sprintf(promptBuffer,prompt,moduleName) >= 1000) {
2294 /* Reset prompt to a safe default to avoid an infinite loop */
2296 prompt = strCopy("? ");
2297 internal("Combined prompt and evaluation module name too long");
2301 stringInput("main\0"); else
2302 consoleInput(promptBuffer);
2305 /* --------------------------------------------------------------------------
2306 * main read-eval-print loop, with error trapping:
2307 * ------------------------------------------------------------------------*/
2309 static Void local interpreter(argc,argv)/* main interpreter loop */
2313 List modConIds; /* :: [CONID] */
2317 setBreakAction ( HugsIgnoreBreak );
2318 modConIds = initialize(argc,argv); /* the initial modules to load */
2319 setBreakAction ( HugsIgnoreBreak );
2320 prelOK = loadThePrelude();
2321 if (combined) everybody(POSTPREL);
2325 fprintf(stderr, "hugs +Q: fatal error: can't load the Prelude.\n" );
2327 fprintf(stderr, "hugs: fatal error: can't load the Prelude.\n" );
2331 loadActions(modConIds);
2334 for (; nonNull(modConIds); modConIds=tl(modConIds))
2335 if (!elemMG(hd(modConIds))) {
2337 "hugs +Q: compilation failed -- can't run `main'\n" );
2344 /* initialize calls startupHaskell, which trashes our signal handlers */
2345 setBreakAction ( HugsIgnoreBreak );
2350 everybody(RESET); /* reset to sensible initial state */
2352 promptForInput(textToStr(module(currentModule).text));
2354 cmd = readCommand(cmds, (Char)':', (Char)'!');
2356 case EDIT : editor();
2360 case LOAD : modConIds = NIL;
2361 while ((s=readFilename())!=0)
2362 modConIds = cons(mkCon(findText(s)),modConIds);
2363 loadActions(modConIds);
2366 case ALSO : modConIds = NIL;
2367 while ((s=readFilename())!=0)
2368 modConIds = cons(mkCon(findText(s)),modConIds);
2369 addActions(modConIds);
2372 case RELOAD : refreshActions(NIL,FALSE);
2377 case EVAL : evaluator();
2379 case TYPEOF : showtype();
2381 case BROWSE : browse();
2383 #if EXPLAIN_INSTANCE_RESOLUTION
2384 case XPLAIN : xplain();
2387 case NAMES : listNames();
2391 case BADCMD : guidance();
2396 #ifdef CRUDE_PROFILING
2400 case SYSTEM : if (shellEsc(readLine()))
2401 Printf("Warning: Shell escape terminated abnormally\n");
2403 case CHGDIR : changeDir();
2407 case PNTVER: Printf("-- Hugs Version %s\n",
2410 case DUMP : dumpStg();
2413 case COLLECT: consGC = FALSE;
2416 Printf("Garbage collection recovered %d cells\n",
2422 if (autoMain) break;
2426 /* --------------------------------------------------------------------------
2427 * Display progress towards goal:
2428 * ------------------------------------------------------------------------*/
2430 static Target currTarget;
2431 static Bool aiming = FALSE;
2434 static Int charCount;
2436 Void setGoal(what, t) /* Set goal for what to be t */
2441 #if EXPLAIN_INSTANCE_RESOLUTION
2445 currTarget = (t?t:1);
2448 currPos = strlen(what);
2449 maxPos = getTerminalWidth() - 1;
2453 for (charCount=0; *what; charCount++)
2458 Void soFar(t) /* Indicate progress towards goal */
2459 Target t; { /* has now reached t */
2462 #if EXPLAIN_INSTANCE_RESOLUTION
2467 Int newPos = (Int)((maxPos * ((long)t))/currTarget);
2472 if (newPos>currPos) {
2475 while (newPos>++currPos);
2482 Void done() { /* Goal has now been achieved */
2485 #if EXPLAIN_INSTANCE_RESOLUTION
2490 while (maxPos>currPos++)
2495 for (; charCount>0; charCount--) {
2504 static Void local failed() { /* Goal cannot be reached due to */
2505 if (aiming) { /* errors */
2512 /* --------------------------------------------------------------------------
2514 * ------------------------------------------------------------------------*/
2516 static Void local stopAnyPrinting() { /* terminate printing of expression,*/
2517 if (printing) { /* after successful termination or */
2518 printing = FALSE; /* runtime error (e.g. interrupt) */
2521 #define plural(v) v, (v==1?"":"s")
2522 Printf("%lu cell%s",plural(numCells));
2524 Printf(", %u garbage collection%s",plural(numGcs));
2533 Cell errAssert(l) /* message to use when raising asserts, etc */
2537 str = mkStr(findText(currentFile));
2539 str = mkStr(findText(""));
2541 return (ap2(nameTangleMessage,str,mkInt(l)));
2544 Void errHead(l) /* print start of error message */
2546 failed(); /* failed to reach target ... */
2548 FPrintf(errorStream,"ERROR");
2551 FPrintf(errorStream," \"%s\"", currentFile);
2552 setLastEdit(currentFile,l);
2553 if (l) FPrintf(errorStream," (line %d)",l);
2556 FPrintf(errorStream,": ");
2557 FFlush(errorStream);
2560 Void errFail() { /* terminate error message and */
2561 Putc('\n',errorStream); /* produce exception to return to */
2562 FFlush(errorStream); /* main command loop */
2563 longjmp(catch_error,1);
2566 Void errFail_no_longjmp() { /* terminate error message but */
2567 Putc('\n',errorStream); /* don't produce an exception */
2568 FFlush(errorStream);
2571 Void errAbort() { /* altern. form of error handling */
2572 failed(); /* used when suitable error message*/
2573 stopAnyPrinting(); /* has already been printed */
2577 Void internal(msg) /* handle internal error */
2581 Printf("INTERNAL ERROR: %s\n",msg);
2584 longjmp(catch_error,1);
2587 Void fatal(msg) /* handle fatal error */
2590 Printf("\nFATAL ERROR: %s\n",msg);
2596 /* --------------------------------------------------------------------------
2597 * Read value from environment variable or registry:
2598 * ------------------------------------------------------------------------*/
2600 String fromEnv(var,def) /* return value of: */
2601 String var; /* environment variable named by var */
2602 String def; { /* or: default value given by def */
2603 String s = getenv(var);
2604 return (s ? s : def);
2607 /* --------------------------------------------------------------------------
2608 * String manipulation routines:
2609 * ------------------------------------------------------------------------*/
2611 static String local strCopy(s) /* make malloced copy of a string */
2615 if ((t=(char *)malloc(strlen(s)+1))==0) {
2616 ERRMSG(0) "String storage space exhausted"
2619 for (r=t; (*r++ = *s++)!=0; ) {
2627 /* --------------------------------------------------------------------------
2629 * We can redirect compiler output (prompts, error messages, etc) by
2630 * tweaking these functions.
2631 * ------------------------------------------------------------------------*/
2633 #ifdef HAVE_STDARG_H
2636 #include <varargs.h>
2639 Void hugsEnableOutput(f)
2644 #ifdef HAVE_STDARG_H
2645 Void hugsPrintf(const char *fmt, ...) {
2646 va_list ap; /* pointer into argument list */
2647 va_start(ap, fmt); /* make ap point to first arg after fmt */
2648 if (!disableOutput) {
2652 va_end(ap); /* clean up */
2655 Void hugsPrintf(fmt, va_alist)
2658 va_list ap; /* pointer into argument list */
2659 va_start(ap); /* make ap point to first arg after fmt */
2660 if (!disableOutput) {
2664 va_end(ap); /* clean up */
2670 if (!disableOutput) {
2676 Void hugsFlushStdout() {
2677 if (!disableOutput) {
2684 if (!disableOutput) {
2689 #ifdef HAVE_STDARG_H
2690 Void hugsFPrintf(FILE *fp, const char* fmt, ...) {
2693 if (!disableOutput) {
2694 vfprintf(fp, fmt, ap);
2700 Void hugsFPrintf(FILE *fp, const char* fmt, va_list)
2706 if (!disableOutput) {
2707 vfprintf(fp, fmt, ap);
2714 Void hugsPutc(c, fp)
2717 if (!disableOutput) {
2723 /* --------------------------------------------------------------------------
2724 * Send message to each component of system:
2725 * ------------------------------------------------------------------------*/
2727 Void everybody(what) /* send command `what' to each component of*/
2728 Int what; { /* system to respond as appropriate ... */
2730 fprintf ( stderr, "EVERYBODY %d\n", what );
2732 machdep(what); /* The order of calling each component is */
2733 storage(what); /* important for the PREPREL command */
2736 translateControl(what);
2738 staticAnalysis(what);
2739 deriveControl(what);
2746 mark(targetModules);
2750 /*-------------------------------------------------------------------------*/