[project @ 1999-10-19 23:51:57 by andy]
[ghc-hetmet.git] / ghc / interpreter / storage.c
1
2 /* --------------------------------------------------------------------------
3  * Primitives for manipulating global data structures
4  *
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.
10  *
11  * $RCSfile: storage.c,v $
12  * $Revision: 1.12 $
13  * $Date: 1999/10/19 23:51:58 $
14  * ------------------------------------------------------------------------*/
15
16 #include "prelude.h"
17 #include "storage.h"
18 #include "backend.h"
19 #include "connect.h"
20 #include "errors.h"
21 #include <setjmp.h>
22
23 /*#define DEBUG_SHOWUSE*/
24
25 /* --------------------------------------------------------------------------
26  * local function prototypes:
27  * ------------------------------------------------------------------------*/
28
29 static Int  local hash                  Args((String));
30 static Int  local saveText              Args((Text));
31 static Module local findQualifier       Args((Text));
32 static Void local hashTycon             Args((Tycon));
33 static List local insertTycon           Args((Tycon,List));
34 static Void local hashName              Args((Name));
35 static List local insertName            Args((Name,List));
36 static Void local patternError          Args((String));
37 static Bool local stringMatch           Args((String,String));
38 static Bool local typeInvolves          Args((Type,Type));
39 static Cell local markCell              Args((Cell));
40 static Void local markSnd               Args((Cell));
41 static Cell local lowLevelLastIn        Args((Cell));
42 static Cell local lowLevelLastOut       Args((Cell));
43        Module local moduleOfScript      Args((Script));
44        Script local scriptThisFile      Args((Text));
45
46 /* --------------------------------------------------------------------------
47  * Text storage:
48  *
49  * provides storage for the characters making up identifier and symbol
50  * names, string literals, character constants etc...
51  *
52  * All character strings are stored in a large character array, with textHw
53  * pointing to the next free position.  Lookup in the array is improved using
54  * a hash table.  Internally, text strings are represented by integer offsets
55  * from the beginning of the array to the string in question.
56  *
57  * Where memory permits, the use of multiple hashtables gives a significant
58  * increase in performance, particularly when large source files are used.
59  *
60  * Each string in the array is terminated by a zero byte.  No string is
61  * stored more than once, so that it is safe to test equality of strings by
62  * comparing the corresponding offsets.
63  *
64  * Special text values (beyond the range of the text array table) are used
65  * to generate unique `new variable names' as required.
66  *
67  * The same text storage is also used to hold text values stored in a saved
68  * expression.  This grows downwards from the top of the text table (and is
69  * not included in the hash table).
70  * ------------------------------------------------------------------------*/
71
72 #define TEXTHSZ 512                     /* Size of Text hash table         */
73 #define NOTEXT  ((Text)(~0))            /* Empty bucket in Text hash table */
74 static  Text    textHw;                 /* Next unused position            */
75 static  Text    savedText = NUM_TEXT;   /* Start of saved portion of text  */
76 static  Text    nextNewText;            /* Next new text value             */
77 static  Text    nextNewDText;           /* Next new dict text value        */
78 static  char    DEFTABLE(text,NUM_TEXT);/* Storage of character strings    */
79 static  Text    textHash[TEXTHSZ][NUM_TEXTH]; /* Hash table storage        */
80
81 String textToStr(t)                    /* find string corresp to given Text*/
82 Text t; {
83     static char newVar[16];
84
85     if (0<=t && t<NUM_TEXT)                     /* standard char string    */
86         return text + t;
87     if (t<0)
88         sprintf(newVar,"d%d",-t);               /* dictionary variable     */
89     else
90         sprintf(newVar,"v%d",t-NUM_TEXT);       /* normal variable         */
91     return newVar;
92 }
93
94 String identToStr(v) /*find string corresp to given ident or qualified name*/
95 Cell v; {
96     if (!isPair(v)) {
97         internal("identToStr");
98     }
99     switch (fst(v)) {
100         case VARIDCELL  :
101         case VAROPCELL  : 
102         case CONIDCELL  :
103         case CONOPCELL  : return text+textOf(v);
104
105         case QUALIDENT  : {   Text pos = textHw;
106                               Text t   = qmodOf(v);
107                               while (pos+1 < savedText && text[t]!=0) {
108                                   text[pos++] = text[t++];
109                               }
110                               if (pos+1 < savedText) {
111                                   text[pos++] = '.';
112                               }
113                               t = qtextOf(v);
114                               while (pos+1 < savedText && text[t]!=0) {
115                                   text[pos++] = text[t++];
116                               }
117                               text[pos] = '\0';
118                               return text+textHw;
119                           }
120     }
121     internal("identToStr2");
122     return 0; /* NOTREACHED */
123 }
124
125 Text inventText()     {                 /* return new unused variable name */
126     return nextNewText++;
127 }
128
129 Text inventDictText() {                 /* return new unused dictvar name  */
130     return nextNewDText--;
131 }
132
133 Bool inventedText(t)                    /* Signal TRUE if text has been    */
134 Text t; {                               /* generated internally            */
135     return (t<0 || t>=NUM_TEXT);
136 }
137
138 #define MAX_FIXLIT 100
139 Text fixLitText(t)                /* fix literal text that might include \ */
140 Text t; {
141     String   s = textToStr(t);
142     char     p[MAX_FIXLIT];
143     Int      i;
144     for(i = 0;i < MAX_FIXLIT-2 && *s;s++) {
145       p[i++] = *s;
146       if (*s == '\\') {
147         p[i++] = '\\';
148       } 
149     }
150     if (i < MAX_FIXLIT-2) {
151       p[i] = 0;
152     } else {
153         ERRMSG(0) "storage space exhausted for internal literal string"
154         EEND;
155     }
156     return (findText(p));
157 }
158 #undef MAX_FIXLIT
159
160 static Int local hash(s)                /* Simple hash function on strings */
161 String s; {
162     int v, j = 3;
163
164     for (v=((int)(*s))*8; *s; s++)
165         v += ((int)(*s))*(j++);
166     if (v<0)
167         v = (-v);
168     return(v%TEXTHSZ);
169 }
170
171 Text findText(s)                       /* Locate string in Text array      */
172 String s; {
173     int    h       = hash(s);
174     int    hashno  = 0;
175     Text   textPos = textHash[h][hashno];
176
177 #define TryMatch        {   Text   originalTextPos = textPos;              \
178                             String t;                                      \
179                             for (t=s; *t==text[textPos]; textPos++,t++)    \
180                                 if (*t=='\0')                              \
181                                     return originalTextPos;                \
182                         }
183 #define Skip            while (text[textPos++]) ;
184
185     while (textPos!=NOTEXT) {
186         TryMatch
187         if (++hashno<NUM_TEXTH)         /* look in next hashtable entry    */
188             textPos = textHash[h][hashno];
189         else {
190             Skip
191             while (textPos < textHw) {
192                 TryMatch
193                 Skip
194             }
195             break;
196         }
197     }
198
199 #undef TryMatch
200 #undef Skip
201
202     textPos = textHw;                  /* if not found, save in array      */
203     if (textHw + (Int)strlen(s) + 1 > savedText) {
204         ERRMSG(0) "Character string storage space exhausted"
205         EEND;
206     }
207     while ((text[textHw++] = *s++) != 0) {
208     }
209     if (hashno<NUM_TEXTH) {            /* updating hash table as necessary */
210         textHash[h][hashno] = textPos;
211         if (hashno<NUM_TEXTH-1)
212             textHash[h][hashno+1] = NOTEXT;
213     }
214
215     return textPos;
216 }
217
218 static Int local saveText(t)            /* Save text value in buffer       */
219 Text t; {                               /* at top of text table            */
220     String s = textToStr(t);
221     Int    l = strlen(s);
222
223     if (textHw + l + 1 > savedText) {
224         ERRMSG(0) "Character string storage space exhausted"
225         EEND;
226     }
227     savedText -= l+1;
228     strcpy(text+savedText,s);
229     return savedText;
230 }
231
232
233 /* --------------------------------------------------------------------------
234  * Ext storage:
235  *
236  * Currently, the only attributes that we store for each Ext value is the
237  * corresponding Text label.  At some later stage, we may decide to cache
238  * types, predicates, etc. here as a space saving gesture.  Given that Text
239  * comparison is cheap, and that this is an experimental implementation, we
240  * will use a straightforward linear search to locate Ext values from their
241  * corresponding Text labels; a hashing scheme can be introduced later if
242  * this turns out to be a problem.
243  * ------------------------------------------------------------------------*/
244
245 #if TREX
246 Text  DEFTABLE(tabExt,NUM_EXT);         /* Storage for Ext names           */
247 Ext   extHw;
248
249 Ext mkExt(t)                            /* Allocate or find an Ext value   */
250 Text t; {
251     Ext e = EXTMIN;
252     for (; e<extHw; e++)
253         if (t==extText(e))
254             return e;
255     if (extHw-EXTMIN >= NUM_EXT) {
256         ERRMSG(0) "Ext storage space exhausted"
257         EEND;
258     }
259     extText(extHw) = t;
260     return extHw++;
261 }
262 #endif
263
264 /* --------------------------------------------------------------------------
265  * Tycon storage:
266  *
267  * A Tycon represents a user defined type constructor.  Tycons are indexed
268  * by Text values ... a very simple hash function is used to improve lookup
269  * times.  Tycon entries with the same hash code are chained together, with
270  * the most recent entry at the front of the list.
271  * ------------------------------------------------------------------------*/
272
273 #define TYCONHSZ 256                            /* Size of Tycon hash table*/
274 #define tHash(x) ((x)%TYCONHSZ)                 /* Tycon hash function     */
275 static  Tycon    tyconHw;                       /* next unused Tycon       */
276 static  Tycon    DEFTABLE(tyconHash,TYCONHSZ);  /* Hash table storage      */
277 struct  strTycon DEFTABLE(tabTycon,NUM_TYCON);  /* Tycon storage           */
278
279 Tycon newTycon(t)                       /* add new tycon to tycon table    */
280 Text t; {
281     Int h = tHash(t);
282     if (tyconHw-TYCMIN >= NUM_TYCON) {
283         ERRMSG(0) "Type constructor storage space exhausted"
284         EEND;
285     }
286     tycon(tyconHw).text          = t;   /* clear new tycon record          */
287     tycon(tyconHw).kind          = NIL;
288     tycon(tyconHw).defn          = NIL;
289     tycon(tyconHw).what          = NIL;
290     tycon(tyconHw).conToTag      = NIL;
291     tycon(tyconHw).tagToCon      = NIL;
292     tycon(tyconHw).mod           = currentModule;
293     module(currentModule).tycons = cons(tyconHw,module(currentModule).tycons);
294     tycon(tyconHw).nextTyconHash = tyconHash[h];
295     tyconHash[h]                 = tyconHw;
296
297     return tyconHw++;
298 }
299
300 Tycon findTycon(t)                      /* locate Tycon in tycon table     */
301 Text t; {
302     Tycon tc = tyconHash[tHash(t)];
303
304     while (nonNull(tc) && tycon(tc).text!=t)
305         tc = tycon(tc).nextTyconHash;
306     return tc;
307 }
308
309 Tycon addTycon(tc)  /* Insert Tycon in tycon table - if no clash is caused */
310 Tycon tc; {
311     Tycon oldtc = findTycon(tycon(tc).text);
312     if (isNull(oldtc)) {
313         hashTycon(tc);
314         module(currentModule).tycons=cons(tc,module(currentModule).tycons);
315         return tc;
316     } else
317         return oldtc;
318 }
319
320 static Void local hashTycon(tc)         /* Insert Tycon into hash table    */
321 Tycon tc; {
322   assert(isTycon(tc));
323    if (1) {
324      Text  t = tycon(tc).text;
325      Int   h = tHash(t);
326      tycon(tc).nextTyconHash = tyconHash[h];
327      tyconHash[h]            = tc;
328    }
329 }
330
331 Tycon findQualTycon(id) /*locate (possibly qualified) Tycon in tycon table */
332 Cell id; {
333     if (!isPair(id)) internal("findQualTycon");
334     switch (fst(id)) {
335         case CONIDCELL :
336         case CONOPCELL :
337             return findTycon(textOf(id));
338         case QUALIDENT : {
339             Text   t  = qtextOf(id);
340             Module m  = findQualifier(qmodOf(id));
341             List   es = NIL;
342             if (isNull(m)) return NIL;
343             for(es=module(m).exports; nonNull(es); es=tl(es)) {
344                 Cell e = hd(es);
345                 if (isPair(e) && isTycon(fst(e)) && tycon(fst(e)).text==t) 
346                     return fst(e);
347             }
348             return NIL;
349         }
350         default : internal("findQualTycon2");
351     }
352     return 0; /* NOTREACHED */
353 }
354
355 Tycon addPrimTycon(t,kind,ar,what,defn) /* add new primitive type constr   */
356 Text t;
357 Kind kind;
358 Int  ar;
359 Cell what;
360 Cell defn; {
361     Tycon tc        = newTycon(t);
362     tycon(tc).line  = 0;
363     tycon(tc).kind  = kind;
364     tycon(tc).what  = what;
365     tycon(tc).defn  = defn;
366     tycon(tc).arity = ar;
367     return tc;
368 }
369
370 static List local insertTycon(tc,ts)    /* insert tycon tc into sorted list*/
371 Tycon tc;                               /* ts                              */
372 List  ts; {
373     Cell   prev = NIL;
374     Cell   curr = ts;
375     String s    = textToStr(tycon(tc).text);
376
377     while (nonNull(curr) && strCompare(s,textToStr(tycon(hd(curr)).text))>=0) {
378         if (hd(curr)==tc)               /* just in case we get duplicates! */
379             return ts;
380         prev = curr;
381         curr = tl(curr);
382     }
383     if (nonNull(prev)) {
384         tl(prev) = cons(tc,curr);
385         return ts;
386     }
387     else
388         return cons(tc,curr);
389 }
390
391 List addTyconsMatching(pat,ts)          /* Add tycons matching pattern pat */
392 String pat;                             /* to list of Tycons ts            */
393 List   ts; {                            /* Null pattern matches every tycon*/
394     Tycon tc;                           /* (Tycons with NIL kind excluded) */
395     for (tc=TYCMIN; tc<tyconHw; ++tc)
396         if (!pat || stringMatch(pat,textToStr(tycon(tc).text)))
397             if (nonNull(tycon(tc).kind))
398                 ts = insertTycon(tc,ts);
399     return ts;
400 }
401
402 /* --------------------------------------------------------------------------
403  * Name storage:
404  *
405  * A Name represents a top level binding of a value to an identifier.
406  * Such values may be a constructor function, a member function in a
407  * class, a user-defined or primitive value/function.
408  *
409  * Names are indexed by Text values ... a very simple hash functions speeds
410  * access to the table of Names and Name entries with the same hash value
411  * are chained together, with the most recent entry at the front of the
412  * list.
413  * ------------------------------------------------------------------------*/
414
415 #define NAMEHSZ  256                            /* Size of Name hash table */
416 #define nHash(x) ((x)%NAMEHSZ)                  /* hash fn :: Text->Int    */
417         Name     nameHw;                        /* next unused name        */
418 static  Name     DEFTABLE(nameHash,NAMEHSZ);    /* Hash table storage      */
419 struct  strName  DEFTABLE(tabName,NUM_NAME);    /* Name table storage      */
420
421 Name newName(t,parent)                  /* Add new name to name table      */
422 Text t; 
423 Cell parent; {
424     Int h = nHash(t);
425     if (nameHw-NAMEMIN >= NUM_NAME) {
426         ERRMSG(0) "Name storage space exhausted"
427         EEND;
428     }
429     name(nameHw).text         = t;      /* clear new name record           */
430     name(nameHw).line         = 0;
431     name(nameHw).syntax       = NO_SYNTAX;
432     name(nameHw).parent       = parent;
433     name(nameHw).arity        = 0;
434     name(nameHw).number       = EXECNAME;
435     name(nameHw).defn         = NIL;
436     name(nameHw).stgVar       = NIL;
437     name(nameHw).stgSize      = 0;
438     name(nameHw).inlineMe     = FALSE;
439     name(nameHw).simplified   = FALSE;
440     name(nameHw).isDBuilder   = FALSE;
441     name(nameHw).type         = NIL;
442     name(nameHw).primop       = 0;
443     name(nameHw).mod          = currentModule;
444     module(currentModule).names=cons(nameHw,module(currentModule).names);
445     name(nameHw).nextNameHash = nameHash[h];
446     nameHash[h]               = nameHw;
447     return nameHw++;
448 }
449
450 Name findName(t)                        /* Locate name in name table       */
451 Text t; {
452     Name n = nameHash[nHash(t)];
453
454     while (nonNull(n) && name(n).text!=t)
455         n = name(n).nextNameHash;
456     return n;
457 }
458
459 Name addName(nm)                        /* Insert Name in name table - if  */
460 Name nm; {                              /* no clash is caused              */
461     Name oldnm = findName(name(nm).text);
462     if (isNull(oldnm)) {
463         hashName(nm);
464         module(currentModule).names=cons(nm,module(currentModule).names);
465         return nm;
466     } else
467         return oldnm;
468 }
469
470 static Void local hashName(nm)          /* Insert Name into hash table     */
471 Name nm; {
472     Text t;
473     Int  h;
474     assert(isName(nm));
475     t = name(nm).text;
476     h = nHash(t);
477     name(nm).nextNameHash = nameHash[h];
478     nameHash[h]           = nm;
479 }
480
481 Name findQualName(id)              /* Locate (possibly qualified) name*/
482 Cell id; {                         /* in name table                   */
483     if (!isPair(id))
484         internal("findQualName");
485     switch (fst(id)) {
486         case VARIDCELL :
487         case VAROPCELL :
488         case CONIDCELL :
489         case CONOPCELL :
490             return findName(textOf(id));
491         case QUALIDENT : {
492             Text   t  = qtextOf(id);
493             Module m  = findQualifier(qmodOf(id));
494             List   es = NIL;
495             if (isNull(m)) return NIL;
496             for(es=module(m).exports; nonNull(es); es=tl(es)) {
497                 Cell e = hd(es);
498                 if (isName(e) && name(e).text==t) 
499                     return e;
500                 else if (isPair(e) && DOTDOT==snd(e)) {
501                     List subentities = NIL;
502                     Cell c = fst(e);
503                     if (isTycon(c)
504                         && (tycon(c).what==DATATYPE || tycon(c).what==NEWTYPE))
505                         subentities = tycon(c).defn;
506                     else if (isClass(c))
507                         subentities = cclass(c).members;
508                     for(; nonNull(subentities); subentities=tl(subentities)) {
509                        if (!isName(hd(subentities)))
510                             internal("findQualName3");
511                         if (name(hd(subentities)).text == t)
512                             return hd(subentities);
513                     }
514                 }
515             }
516             return NIL;
517         }
518         default : internal("findQualName2");
519     }
520     return 0; /* NOTREACHED */
521 }
522
523
524 Name nameFromStgVar ( StgVar v )
525 {
526    Int n;
527    for (n = NAMEMIN; n < nameHw; n++)
528       if (name(n).stgVar == v) return n;
529    return NIL;
530 }
531
532 void* getHugs_AsmObject_for ( char* s )
533 {
534    StgVar v;
535    Name   n = findName(findText(s));
536    if (isNull(n)) internal("getHugs_AsmObject_for(1)");
537    v = name(n).stgVar;
538    if (!isStgVar(v) || !isPtr(stgVarInfo(v)))
539       internal("getHugs_AsmObject_for(2)");
540    return ptrOf(stgVarInfo(v));
541 }
542
543 /* --------------------------------------------------------------------------
544  * Primitive functions:
545  * ------------------------------------------------------------------------*/
546
547 Name addPrimCfunREP(t,arity,no,rep)     /* add primitive constructor func  */
548 Text t;                                 /* sets rep, not type              */
549 Int  arity;
550 Int  no;
551 Int  rep; { /* Really AsmRep */
552     Name n          = newName(t,NIL);
553     name(n).arity   = arity;
554     name(n).number  = cfunNo(no);
555     name(n).type    = NIL;
556     name(n).primop  = (void*)rep;
557     return n;
558 }
559
560
561 Name addPrimCfun(t,arity,no,type)       /* add primitive constructor func  */
562 Text t;
563 Int  arity;
564 Int  no;
565 Cell type; {
566     Name n         = newName(t,NIL);
567     name(n).arity  = arity;
568     name(n).number = cfunNo(no);
569     name(n).type   = type;
570     return n;
571 }
572
573
574 Int sfunPos(s,c)                        /* Find position of field with     */
575 Name s;                                 /* selector s in constructor c.    */
576 Name c; {
577     List cns;
578     cns = name(s).defn;
579     for (; nonNull(cns); cns=tl(cns))
580         if (fst(hd(cns))==c)
581             return intOf(snd(hd(cns)));
582     internal("sfunPos");
583     return 0;/* NOTREACHED */
584 }
585
586 static List local insertName(nm,ns)     /* insert name nm into sorted list */
587 Name nm;                                /* ns                              */
588 List ns; {
589     Cell   prev = NIL;
590     Cell   curr = ns;
591     String s    = textToStr(name(nm).text);
592
593     while (nonNull(curr) && strCompare(s,textToStr(name(hd(curr)).text))>=0) {
594         if (hd(curr)==nm)               /* just in case we get duplicates! */
595             return ns;
596         prev = curr;
597         curr = tl(curr);
598     }
599     if (nonNull(prev)) {
600         tl(prev) = cons(nm,curr);
601         return ns;
602     }
603     else
604         return cons(nm,curr);
605 }
606
607 List addNamesMatching(pat,ns)           /* Add names matching pattern pat  */
608 String pat;                             /* to list of names ns             */
609 List   ns; {                            /* Null pattern matches every name */
610     Name nm;                            /* (Names with NIL type, or hidden */
611 #if 1
612     for (nm=NAMEMIN; nm<nameHw; ++nm)   /* or invented names are excluded) */
613         if (!inventedText(name(nm).text) && nonNull(name(nm).type)) {
614             String str = textToStr(name(nm).text);
615             if (str[0]!='_' && (!pat || stringMatch(pat,str)))
616                 ns = insertName(nm,ns);
617         }
618     return ns;
619 #else
620     List mns = module(currentModule).names;
621     for(; nonNull(mns); mns=tl(mns)) {
622         Name nm = hd(mns);
623         if (!inventedText(name(nm).text)) {
624             String str = textToStr(name(nm).text);
625             if (str[0]!='_' && (!pat || stringMatch(pat,str)))
626                 ns = insertName(nm,ns);
627         }
628     }
629     return ns;
630 #endif
631 }
632
633 /* --------------------------------------------------------------------------
634  * A simple string matching routine
635  *     `*'    matches any sequence of zero or more characters
636  *     `?'    matches any single character exactly 
637  *     `@str' matches the string str exactly (ignoring any special chars)
638  *     `\c'   matches the character c only (ignoring special chars)
639  *     c      matches the character c only
640  * ------------------------------------------------------------------------*/
641
642 static Void local patternError(s)       /* report error in pattern         */
643 String s; {
644     ERRMSG(0) "%s in pattern", s
645     EEND;
646 }
647
648 static Bool local stringMatch(pat,str)  /* match string against pattern    */
649 String pat;
650 String str; {
651
652     for (;;)
653         switch (*pat) {
654             case '\0' : return (*str=='\0');
655
656             case '*'  : do {
657                             if (stringMatch(pat+1,str))
658                                 return TRUE;
659                         } while (*str++);
660                         return FALSE;
661
662             case '?'  : if (*str++=='\0')
663                             return FALSE;
664                         pat++;
665                         break;
666
667             case '['  : {   Bool found = FALSE;
668                             while (*++pat!='\0' && *pat!=']')
669                                 if (!found && ( pat[0] == *str  ||
670                                                (pat[1] == '-'   &&
671                                                 pat[2] != ']'   &&
672                                                 pat[2] != '\0'  &&
673                                                 pat[0] <= *str  &&
674                                                 pat[2] >= *str)))
675
676                                     found = TRUE;
677                             if (*pat != ']')
678                                 patternError("missing `]'");
679                             if (!found)
680                                 return FALSE;
681                             pat++;
682                             str++;
683                         }
684                         break;
685
686             case '\\' : if (*++pat == '\0')
687                             patternError("extra trailing `\\'");
688                         /*fallthru!*/
689             default   : if (*pat++ != *str++)
690                             return FALSE;
691                         break;
692         }
693 }
694
695 /* --------------------------------------------------------------------------
696  * Storage of type classes, instances etc...:
697  * ------------------------------------------------------------------------*/
698
699 static Class classHw;                  /* next unused class                */
700 static List  classes;                  /* list of classes in current scope */
701 static Inst  instHw;                   /* next unused instance record      */
702
703 struct strClass DEFTABLE(tabClass,NUM_CLASSES); /* table of class records  */
704 struct strInst far *tabInst;           /* (pointer to) table of instances  */
705
706 Class newClass(t)                      /* add new class to class table     */
707 Text t; {
708     if (classHw-CLASSMIN >= NUM_CLASSES) {
709         ERRMSG(0) "Class storage space exhausted"
710         EEND;
711     }
712     cclass(classHw).text      = t;
713     cclass(classHw).arity     = 0;
714     cclass(classHw).kinds     = NIL;
715     cclass(classHw).head      = NIL;
716     cclass(classHw).dcon      = NIL;
717     cclass(classHw).supers    = NIL;
718     cclass(classHw).dsels     = NIL;
719     cclass(classHw).members   = NIL;
720     cclass(classHw).defaults  = NIL;
721     cclass(classHw).instances = NIL;
722     classes=cons(classHw,classes);
723     cclass(classHw).mod       = currentModule;
724     module(currentModule).classes=cons(classHw,module(currentModule).classes);
725     return classHw++;
726 }
727
728 Class classMax() {                      /* Return max Class in use ...     */
729     return classHw;                     /* This is a bit ugly, but it's not*/
730 }                                       /* worth a lot of effort right now */
731
732 Class findClass(t)                     /* look for named class in table    */
733 Text t; {
734     Class cl;
735     List cs;
736     for (cs=classes; nonNull(cs); cs=tl(cs)) {
737         cl=hd(cs);
738         if (cclass(cl).text==t)
739             return cl;
740     }
741     return NIL;
742 }
743
744 Class addClass(c)                       /* Insert Class in class list      */
745 Class c; {                              /*  - if no clash caused           */
746     Class oldc = findClass(cclass(c).text);
747     if (isNull(oldc)) {
748         classes=cons(c,classes);
749         module(currentModule).classes=cons(c,module(currentModule).classes);
750         return c;
751     }
752     else
753         return oldc;
754 }
755
756 Class findQualClass(c)                  /* Look for (possibly qualified)   */
757 Cell c; {                               /* class in class list             */
758     if (!isQualIdent(c)) {
759         return findClass(textOf(c));
760     } else {
761         Text   t  = qtextOf(c);
762         Module m  = findQualifier(qmodOf(c));
763         List   es = NIL;
764         if (isNull(m))
765             return NIL;
766         for (es=module(m).exports; nonNull(es); es=tl(es)) {
767             Cell e = hd(es);
768             if (isPair(e) && isClass(fst(e)) && cclass(fst(e)).text==t) 
769                 return fst(e);
770         }
771     }
772     return NIL;
773 }
774
775 Inst newInst() {                       /* Add new instance to table        */
776     if (instHw-INSTMIN >= NUM_INSTS) {
777         ERRMSG(0) "Instance storage space exhausted"
778         EEND;
779     }
780     inst(instHw).kinds      = NIL;
781     inst(instHw).head       = NIL;
782     inst(instHw).specifics  = NIL;
783     inst(instHw).implements = NIL;
784     inst(instHw).builder    = NIL;
785     inst(instHw).mod        = currentModule;
786
787     return instHw++;
788 }
789
790 #ifdef DEBUG_DICTS
791 extern Void printInst Args((Inst));
792
793 Void printInst(in)
794 Inst in; {
795     Class cl = inst(in).c;
796     Printf("%s-", textToStr(cclass(cl).text));
797     printType(stdout,inst(in).t);
798 }
799 #endif /* DEBUG_DICTS */
800
801 Inst findFirstInst(tc)                  /* look for 1st instance involving */
802 Tycon tc; {                             /* the type constructor tc         */
803     return findNextInst(tc,INSTMIN-1);
804 }
805
806 Inst findNextInst(tc,in)                /* look for next instance involving*/
807 Tycon tc;                               /* the type constructor tc         */
808 Inst  in; {                             /* starting after instance in      */
809     while (++in < instHw) {
810         Cell pi = inst(in).head;
811         for (; isAp(pi); pi=fun(pi))
812             if (typeInvolves(arg(pi),tc))
813                 return in;
814     }
815     return NIL;
816 }
817
818 static Bool local typeInvolves(ty,tc)   /* Test to see if type ty involves */
819 Type ty;                                /* type constructor/tuple tc.      */
820 Type tc; {
821     return (ty==tc)
822         || (isAp(ty) && (typeInvolves(fun(ty),tc)
823                          || typeInvolves(arg(ty),tc)));
824 }
825
826 /* --------------------------------------------------------------------------
827  * Control stack:
828  *
829  * Various parts of the system use a stack of cells.  Most of the stack
830  * operations are defined as macros, expanded inline.
831  * ------------------------------------------------------------------------*/
832
833 Cell DEFTABLE(cellStack,NUM_STACK); /* Storage for cells on stack          */
834 StackPtr sp;                        /* stack pointer                       */
835
836 #if GIMME_STACK_DUMPS
837
838 #define UPPER_DISP  5               /* # display entries on top of stack   */
839 #define LOWER_DISP  5               /* # display entries on bottom of stack*/
840
841 Void hugsStackOverflow() {          /* Report stack overflow               */
842     extern Int  rootsp;
843     extern Cell evalRoots[];
844
845     ERRMSG(0) "Control stack overflow" ETHEN
846     if (rootsp>=0) {
847         Int i;
848         if (rootsp>=UPPER_DISP+LOWER_DISP) {
849             for (i=0; i<UPPER_DISP; i++) {
850                 ERRTEXT "\nwhile evaluating: " ETHEN
851                 ERREXPR(evalRoots[rootsp-i]);
852             }
853             ERRTEXT "\n..." ETHEN
854             for (i=LOWER_DISP-1; i>=0; i--) {
855                 ERRTEXT "\nwhile evaluating: " ETHEN
856                 ERREXPR(evalRoots[i]);
857             }
858         }
859         else {
860             for (i=rootsp; i>=0; i--) {
861                 ERRTEXT "\nwhile evaluating: " ETHEN
862                 ERREXPR(evalRoots[i]);
863             }
864         }
865     }
866     ERRTEXT "\n"
867     EEND;
868 }
869
870 #else /* !GIMME_STACK_DUMPS */
871
872 Void hugsStackOverflow() {          /* Report stack overflow               */
873     ERRMSG(0) "Control stack overflow"
874     EEND;
875 }
876
877 #endif /* !GIMME_STACK_DUMPS */
878
879 /* --------------------------------------------------------------------------
880  * Module storage:
881  *
882  * A Module represents a user defined module.  
883  *
884  * Note: there are now two lookup mechanisms in the system:
885  *
886  * 1) The exports from a module are stored in a big list.
887  *    We resolve qualified names, and import lists by linearly scanning
888  *    through this list.
889  *
890  * 2) Unqualified imports and local definitions for the current module
891  *    are stored in hash tables (tyconHash and nameHash) or linear lists
892  *    (classes).
893  *
894  * ------------------------------------------------------------------------*/
895
896 static  Module   moduleHw;              /* next unused Module              */
897 struct  Module   DEFTABLE(tabModule,NUM_MODULE); /* Module storage         */
898 Module  currentModule;                  /* Module currently being processed*/
899
900 Bool isValidModule(m)                  /* is m a legitimate module id?     */
901 Module m; {
902     return (MODMIN <= m && m < moduleHw);
903 }
904
905 Module newModule(t)                     /* add new module to module table  */
906 Text t; {
907     if (moduleHw-MODMIN >= NUM_MODULE) {
908         ERRMSG(0) "Module storage space exhausted"
909         EEND;
910     }
911     module(moduleHw).text          = t; /* clear new module record         */
912     module(moduleHw).qualImports   = NIL;
913     module(moduleHw).exports       = NIL;
914     module(moduleHw).tycons        = NIL;
915     module(moduleHw).names         = NIL;
916     module(moduleHw).classes       = NIL;
917     module(moduleHw).oImage        = NULL;
918     module(moduleHw).oTab          = NULL;
919     module(moduleHw).sizeoTab      = 0;
920     module(moduleHw).usedoTab      = 0;
921     module(moduleHw).dlTab         = NULL;
922     module(moduleHw).sizedlTab     = 0;
923     module(moduleHw).useddlTab     = 0;
924     return moduleHw++;
925 }
926
927 void ppModules ( void )
928 {
929    Int i;
930    fflush(stderr); fflush(stdout);
931    printf ( "begin MODULES\n" );
932    for (i = moduleHw-1; i >= MODMIN; i--)
933       printf ( " %2d: %16s\n",
934                i-MODMIN, textToStr(module(i).text)
935              );
936    printf ( "end   MODULES\n" );
937    fflush(stderr); fflush(stdout);
938 }
939
940
941 Module findModule(t)                    /* locate Module in module table  */
942 Text t; {
943     Module m;
944     for(m=MODMIN; m<moduleHw; ++m) {
945         if (module(m).text==t)
946             return m;
947     }
948     return NIL;
949 }
950
951 Module findModid(c)                    /* Find module by name or filename  */
952 Cell c; {
953     switch (whatIs(c)) {
954         case STRCELL   : { Script s = scriptThisFile(snd(c));
955                            return (s==-1) ? NIL : moduleOfScript(s);
956                          }
957         case CONIDCELL : return findModule(textOf(c));
958         default        : internal("findModid");
959     }
960     assert(0); return 0; /* NOTREACHED */
961 }
962
963 static local Module findQualifier(t)    /* locate Module in import list   */
964 Text t; {
965     Module ms;
966 printf ( "findQualifier %s\n", textToStr(t));
967     for (ms=module(currentModule).qualImports; nonNull(ms); ms=tl(ms)) {
968         if (textOf(fst(hd(ms)))==t)
969             return snd(hd(ms));
970     }
971 #if 1 /* mpj */
972     if (module(currentModule).text==t)
973         return currentModule;
974 #endif
975     return NIL;
976 }
977
978 Void setCurrModule(m)              /* set lookup tables for current module */
979 Module m; {
980     Int i;
981     assert(isModule(m));
982     if (m!=currentModule) {
983         currentModule = m; /* This is the only assignment to currentModule */
984         for (i=0; i<TYCONHSZ; ++i)
985             tyconHash[i] = NIL;
986         mapProc(hashTycon,module(m).tycons);
987         for (i=0; i<NAMEHSZ; ++i)
988             nameHash[i] = NIL;
989         mapProc(hashName,module(m).names);
990         classes = module(m).classes;
991     }
992 }
993
994 Name jrsFindQualName ( Text mn, Text sn )
995 {
996    Module m;
997    List   ns;
998
999    for (m=MODMIN; m<moduleHw; m++)
1000       if (module(m).text == mn) break;
1001    if (m == moduleHw) return NIL;
1002    
1003    for (ns = module(m).names; nonNull(ns); ns=tl(ns)) 
1004       if (name(hd(ns)).text == sn) return hd(ns);
1005
1006    return NIL;
1007 }
1008
1009
1010 /* A bit tricky.  Assumes that if tab==NULL, then 
1011    currUsed and *currSize must be zero.
1012 */
1013 static
1014 void* genericExpand ( void* tab, 
1015                       int*  currSize, int  currUsed,
1016                       int   initSize, int  elemSize )
1017 {
1018    int   size2;
1019    void* tab2;
1020    if (currUsed < *currSize)
1021       return tab;
1022    size2 = (*currSize == 0) ? initSize : (2 * *currSize);
1023    tab2 = malloc ( size2 * elemSize );
1024    if (!tab2) {
1025       ERRMSG(0) "Can't allocate enough memory to resize a table"
1026       EEND;
1027    }
1028    if (*currSize > 0)
1029       memcpy ( tab2, tab, elemSize * *currSize );
1030    *currSize = size2;
1031    if (tab) free ( tab );
1032    return tab2;
1033 }
1034
1035 void addOTabName ( Module m, char* nm, void* ad )
1036 {
1037    module(m).oTab
1038       = genericExpand ( module(m).oTab, 
1039                         &module(m).sizeoTab,
1040                         module(m).usedoTab,
1041                         8, sizeof(OSym) );
1042
1043    module(m).oTab[ module(m).usedoTab ].nm = nm;
1044    module(m).oTab[ module(m).usedoTab ].ad = ad;
1045    module(m).usedoTab++;
1046 }
1047
1048
1049 void addDLSect ( Module m, void* start, void* end, DLSect sect )
1050 {
1051    module(m).dlTab
1052       = genericExpand ( module(m).dlTab,
1053                         &module(m).sizedlTab,
1054                         module(m).useddlTab,
1055                         4, sizeof(DLTabEnt) );
1056    module(m).dlTab[ module(m).useddlTab ].start = start;
1057    module(m).dlTab[ module(m).useddlTab ].end   = end;
1058    module(m).dlTab[ module(m).useddlTab ].sect  = sect;
1059    module(m).useddlTab++;
1060 }
1061
1062
1063 void* lookupOTabName ( Module m, char* nm )
1064 {
1065    int i;
1066    for (i = 0; i < module(m).usedoTab; i++)
1067       if (0==strcmp(nm,module(m).oTab[i].nm))
1068          return module(m).oTab[i].ad;
1069    return NULL;
1070 }
1071
1072
1073 char* nameFromOPtr ( void* p )
1074 {
1075    int i;
1076    Module m;
1077    for (m=MODMIN; m<moduleHw; m++)
1078       for (i = 0; i < module(m).usedoTab; i++)
1079          if (p == module(m).oTab[i].ad)
1080             return module(m).oTab[i].nm;
1081    return NULL;
1082 }
1083
1084
1085 DLSect lookupDLSect ( void* ad )
1086 {
1087    int i;
1088    Module m;
1089    for (m=MODMIN; m<moduleHw; m++)
1090       for (i = 0; i < module(m).useddlTab; i++)
1091          if (module(m).dlTab[i].start <= ad &&
1092              ad <= module(m).dlTab[i].end)
1093             return module(m).dlTab[i].sect;
1094    return HUGS_DL_SECTION_OTHER;
1095 }
1096
1097
1098 /* --------------------------------------------------------------------------
1099  * Script file storage:
1100  *
1101  * script files are read into the system one after another.  The state of
1102  * the stored data structures (except the garbage-collected heap) is recorded
1103  * before reading a new script.  In the event of being unable to read the
1104  * script, or if otherwise requested, the system can be restored to its
1105  * original state immediately before the file was read.
1106  * ------------------------------------------------------------------------*/
1107
1108 typedef struct {                       /* record of storage state prior to */
1109     Text  file;                        /* reading script/module            */
1110     Text  textHw;
1111     Text  nextNewText;
1112     Text  nextNewDText;
1113     Module moduleHw;
1114     Tycon tyconHw;
1115     Name  nameHw;
1116     Class classHw;
1117     Inst  instHw;
1118 #if TREX
1119     Ext   extHw;
1120 #endif
1121 } script;
1122
1123 #ifdef  DEBUG_SHOWUSE
1124 static Void local showUse(msg,val,mx)
1125 String msg;
1126 Int val, mx; {
1127     Printf("%6s : %5d of %5d (%2d%%)\n",msg,val,mx,(100*val)/mx);
1128 }
1129 #endif
1130
1131 static Script scriptHw;                 /* next unused script number       */
1132 static script scripts[NUM_SCRIPTS];     /* storage for script records      */
1133
1134
1135 void ppScripts ( void )
1136 {
1137    Int i;
1138    fflush(stderr); fflush(stdout);
1139    printf ( "begin SCRIPTS\n" );
1140    for (i = scriptHw-1; i >= 0; i--)
1141       printf ( " %2d: %16s  tH=%d  mH=%d  yH=%d  "
1142                "nH=%d  cH=%d  iH=%d  nnS=%d,%d\n",
1143                i, textToStr(scripts[i].file),
1144                scripts[i].textHw, scripts[i].moduleHw,
1145                scripts[i].tyconHw, scripts[i].nameHw, 
1146                scripts[i].classHw, scripts[i].instHw,
1147                scripts[i].nextNewText, scripts[i].nextNewDText 
1148              );
1149    printf ( "end   SCRIPTS\n" );
1150    fflush(stderr); fflush(stdout);
1151 }
1152
1153 Script startNewScript(f)                /* start new script, keeping record */
1154 String f; {                             /* of status for later restoration  */
1155     if (scriptHw >= NUM_SCRIPTS) {
1156         ERRMSG(0) "Too many script files in use"
1157         EEND;
1158     }
1159 #ifdef DEBUG_SHOWUSE
1160     showUse("Text",   textHw,           NUM_TEXT);
1161     showUse("Module", moduleHw-MODMIN,  NUM_MODULE);
1162     showUse("Tycon",  tyconHw-TYCMIN,   NUM_TYCON);
1163     showUse("Name",   nameHw-NAMEMIN,   NUM_NAME);
1164     showUse("Class",  classHw-CLASSMIN, NUM_CLASSES);
1165     showUse("Inst",   instHw-INSTMIN,   NUM_INSTS);
1166 #if TREX
1167     showUse("Ext",    extHw-EXTMIN,     NUM_EXT);
1168 #endif
1169 #endif
1170     scripts[scriptHw].file         = findText( f ? f : "<nofile>" );
1171     scripts[scriptHw].textHw       = textHw;
1172     scripts[scriptHw].nextNewText  = nextNewText;
1173     scripts[scriptHw].nextNewDText = nextNewDText;
1174     scripts[scriptHw].moduleHw     = moduleHw;
1175     scripts[scriptHw].tyconHw      = tyconHw;
1176     scripts[scriptHw].nameHw       = nameHw;
1177     scripts[scriptHw].classHw      = classHw;
1178     scripts[scriptHw].instHw       = instHw;
1179 #if TREX
1180     scripts[scriptHw].extHw        = extHw;
1181 #endif
1182     return scriptHw++;
1183 }
1184
1185 Bool isPreludeScript() {                /* Test whether this is the Prelude*/
1186     return (scriptHw==0);
1187 }
1188
1189 Bool moduleThisScript(m)                /* Test if given module is defined */
1190 Module m; {                             /* in current script file          */
1191     return scriptHw<1 || m>=scripts[scriptHw-1].moduleHw;
1192 }
1193
1194 Module lastModule() {              /* Return module in current script file */
1195     return (moduleHw>MODMIN ? moduleHw-1 : modulePrelude);
1196 }
1197
1198 #define scriptThis(nm,t,tag)            Script nm(x)                       \
1199                                         t x; {                             \
1200                                             Script s=0;                    \
1201                                             while (s<scriptHw              \
1202                                                    && x>=scripts[s].tag)   \
1203                                                 s++;                       \
1204                                             return s;                      \
1205                                         }
1206 scriptThis(scriptThisName,Name,nameHw)
1207 scriptThis(scriptThisTycon,Tycon,tyconHw)
1208 scriptThis(scriptThisInst,Inst,instHw)
1209 scriptThis(scriptThisClass,Class,classHw)
1210 #undef scriptThis
1211
1212 Module moduleOfScript(s)
1213 Script s; {
1214     return (s==0) ? modulePrelude : scripts[s-1].moduleHw;
1215 }
1216
1217 String fileOfModule(m)
1218 Module m; {
1219     Script s;
1220     if (m == modulePrelude) {
1221         return STD_PRELUDE;
1222     }
1223     for(s=0; s<scriptHw; ++s) {
1224         if (scripts[s].moduleHw == m) {
1225             return textToStr(scripts[s].file);
1226         }
1227     }
1228     return 0;
1229 }
1230
1231 Script scriptThisFile(f)
1232 Text f; {
1233     Script s;
1234     for (s=0; s < scriptHw; ++s) {
1235         if (scripts[s].file == f) {
1236             return s+1;
1237         }
1238     }
1239     if (f == findText(STD_PRELUDE)) {
1240         return 0;
1241     }
1242     return (-1);
1243 }
1244
1245 Void dropScriptsFrom(sno)               /* Restore storage to state prior  */
1246 Script sno; {                           /* to reading script sno           */
1247     if (sno<scriptHw) {                 /* is there anything to restore?   */
1248         int i;
1249         textHw       = scripts[sno].textHw;
1250         nextNewText  = scripts[sno].nextNewText;
1251         nextNewDText = scripts[sno].nextNewDText;
1252         moduleHw     = scripts[sno].moduleHw;
1253         tyconHw      = scripts[sno].tyconHw;
1254         nameHw       = scripts[sno].nameHw;
1255         classHw      = scripts[sno].classHw;
1256         instHw       = scripts[sno].instHw;
1257 #if USE_DICTHW
1258         dictHw       = scripts[sno].dictHw;
1259 #endif
1260 #if TREX
1261         extHw        = scripts[sno].extHw;
1262 #endif
1263
1264 #if 0
1265         for (i=moduleHw; i >= scripts[sno].moduleHw; --i) {
1266             if (module(i).objectFile) {
1267                 printf("[bogus] closing objectFile for module %d\n",i);
1268                 /*dlclose(module(i).objectFile);*/
1269             }
1270         }
1271         moduleHw = scripts[sno].moduleHw;
1272 #endif
1273         for (i=0; i<TEXTHSZ; ++i) {
1274             int j = 0;
1275             while (j<NUM_TEXTH && textHash[i][j]!=NOTEXT
1276                                && textHash[i][j]<textHw)
1277                 ++j;
1278             if (j<NUM_TEXTH)
1279                 textHash[i][j] = NOTEXT;
1280         }
1281
1282         currentModule=NIL;
1283         for (i=0; i<TYCONHSZ; ++i) {
1284             tyconHash[i] = NIL;
1285         }
1286         for (i=0; i<NAMEHSZ; ++i) {
1287             nameHash[i] = NIL;
1288         }
1289
1290         for (i=CLASSMIN; i<classHw; i++) {
1291             List ins = cclass(i).instances;
1292             List is  = NIL;
1293
1294             while (nonNull(ins)) {
1295                 List temp = tl(ins);
1296                 if (hd(ins)<instHw) {
1297                     tl(ins) = is;
1298                     is      = ins;
1299                 }
1300                 ins = temp;
1301             }
1302             cclass(i).instances = rev(is);
1303         }
1304
1305         scriptHw = sno;
1306     }
1307 }
1308
1309 /* --------------------------------------------------------------------------
1310  * Heap storage:
1311  *
1312  * Provides a garbage collectable heap for storage of expressions etc.
1313  *
1314  * Now incorporates a flat resource:  A two-space collected extension of
1315  * the heap that provides storage for contiguous arrays of Cell storage,
1316  * cooperating with the garbage collection mechanisms for the main heap.
1317  * ------------------------------------------------------------------------*/
1318
1319 Int     heapSize = DEFAULTHEAP;         /* number of cells in heap         */
1320 Heap    heapFst;                        /* array of fst component of pairs */
1321 Heap    heapSnd;                        /* array of snd component of pairs */
1322 #ifndef GLOBALfst
1323 Heap    heapTopFst;
1324 #endif
1325 #ifndef GLOBALsnd
1326 Heap    heapTopSnd;
1327 #endif
1328 Bool    consGC = TRUE;                  /* Set to FALSE to turn off gc from*/
1329                                         /* C stack; use with extreme care! */
1330 Long    numCells;
1331 Int     numGcs;                         /* number of garbage collections   */
1332 Int     cellsRecovered;                 /* number of cells recovered       */
1333
1334 static  Cell freeList;                  /* free list of unused cells       */
1335 static  Cell lsave, rsave;              /* save components of pair         */
1336
1337 #if GC_STATISTICS
1338
1339 static Int markCount, stackRoots;
1340
1341 #define initStackRoots() stackRoots = 0
1342 #define recordStackRoot() stackRoots++
1343
1344 #define startGC()       \
1345     if (gcMessages) {   \
1346         Printf("\n");   \
1347         fflush(stdout); \
1348     }
1349 #define endGC()         \
1350     if (gcMessages) {   \
1351         Printf("\n");   \
1352         fflush(stdout); \
1353     }
1354
1355 #define start()      markCount = 0
1356 #define end(thing,rs) \
1357     if (gcMessages) { \
1358         Printf("GC: %-18s: %4d cells, %4d roots.\n", thing, markCount, rs); \
1359         fflush(stdout); \
1360     }
1361 #define recordMark() markCount++
1362
1363 #else /* !GC_STATISTICS */
1364
1365 #define startGC()
1366 #define endGC()
1367
1368 #define initStackRoots()
1369 #define recordStackRoot()
1370
1371 #define start()   
1372 #define end(thing,root) 
1373 #define recordMark() 
1374
1375 #endif /* !GC_STATISTICS */
1376
1377 Cell pair(l,r)                          /* Allocate pair (l, r) from       */
1378 Cell l, r; {                            /* heap, garbage collecting first  */
1379     Cell c = freeList;                  /* if necessary ...                */
1380
1381     if (isNull(c)) {
1382         lsave = l;
1383         rsave = r;
1384         garbageCollect();
1385         l     = lsave;
1386         lsave = NIL;
1387         r     = rsave;
1388         rsave = NIL;
1389         c     = freeList;
1390     }
1391     freeList = snd(freeList);
1392     fst(c)   = l;
1393     snd(c)   = r;
1394     numCells++;
1395     return c;
1396 }
1397
1398 Void overwrite(dst,src)                 /* overwrite dst cell with src cell*/
1399 Cell dst, src; {                        /* both *MUST* be pairs            */
1400     if (isPair(dst) && isPair(src)) {
1401         fst(dst) = fst(src);
1402         snd(dst) = snd(src);
1403     }
1404     else
1405         internal("overwrite");
1406 }
1407
1408 static Int *marks;
1409 static Int marksSize;
1410
1411 Cell markExpr(c)                        /* External interface to markCell  */
1412 Cell c; {
1413     return isGenPair(c) ? markCell(c) : c;
1414 }
1415
1416 static Cell local markCell(c)           /* Traverse part of graph marking  */
1417 Cell c; {                               /* cells reachable from given root */
1418                                         /* markCell(c) is only called if c */
1419                                         /* is a pair                       */
1420     {   register int place = placeInSet(c);
1421         register int mask  = maskInSet(c);
1422         if (marks[place]&mask)
1423             return c;
1424         else {
1425             marks[place] |= mask;
1426             recordMark();
1427         }
1428     }
1429
1430     if (isGenPair(fst(c))) {
1431         fst(c) = markCell(fst(c));
1432         markSnd(c);
1433     }
1434     else if (isNull(fst(c)) || fst(c)>=BCSTAG) {
1435         markSnd(c);
1436     }
1437
1438     return c;
1439 }
1440
1441 static Void local markSnd(c)            /* Variant of markCell used to     */
1442 Cell c; {                               /* update snd component of cell    */
1443     Cell t;                             /* using tail recursion            */
1444
1445 ma: t = c;                              /* Keep pointer to original pair   */
1446     c = snd(c);
1447     if (!isPair(c))
1448         return;
1449
1450     {   register int place = placeInSet(c);
1451         register int mask  = maskInSet(c);
1452         if (marks[place]&mask)
1453             return;
1454         else {
1455             marks[place] |= mask;
1456             recordMark();
1457         }
1458     }
1459
1460     if (isGenPair(fst(c))) {
1461         fst(c) = markCell(fst(c));
1462         goto ma;
1463     }
1464     else if (isNull(fst(c)) || fst(c)>=BCSTAG)
1465         goto ma;
1466     return;
1467 }
1468
1469 Void markWithoutMove(n)                 /* Garbage collect cell at n, as if*/
1470 Cell n; {                               /* it was a cell ref, but don't    */
1471                                         /* move cell so we don't have      */
1472                                         /* to modify the stored value of n */
1473     if (isGenPair(n)) {
1474         recordStackRoot();
1475         markCell(n); 
1476     }
1477 }
1478
1479 Void garbageCollect()     {             /* Run garbage collector ...       */
1480     Bool breakStat = breakOn(FALSE);    /* disable break checking          */
1481     Int i,j;
1482     register Int mask;
1483     register Int place;
1484     Int      recovered;
1485
1486     jmp_buf  regs;                      /* save registers on stack         */
1487     setjmp(regs);
1488
1489     gcStarted();
1490     for (i=0; i<marksSize; ++i)         /* initialise mark set to empty    */
1491         marks[i] = 0;
1492
1493     everybody(MARK);                    /* Mark all components of system   */
1494
1495     gcScanning();                       /* scan mark set                   */
1496     mask      = 1;
1497     place     = 0;
1498     recovered = 0;
1499     j         = 0;
1500
1501     freeList = NIL;
1502     for (i=1; i<=heapSize; i++) {
1503         if ((marks[place] & mask) == 0) {
1504             snd(-i)  = freeList;
1505             fst(-i)  = FREECELL;
1506             freeList = -i;
1507             recovered++;
1508         }
1509         mask <<= 1;
1510         if (++j == bitsPerWord) {
1511             place++;
1512             mask = 1;
1513             j    = 0;
1514         }
1515     }
1516
1517     gcRecovered(recovered);
1518     breakOn(breakStat);                 /* restore break trapping if nec.  */
1519
1520     everybody(GCDONE);
1521
1522     /* can only return if freeList is nonempty on return. */
1523     if (recovered<minRecovery || isNull(freeList)) {
1524         ERRMSG(0) "Garbage collection fails to reclaim sufficient space"
1525         EEND;
1526     }
1527     cellsRecovered = recovered;
1528 }
1529
1530 /* --------------------------------------------------------------------------
1531  * Code for saving last expression entered:
1532  *
1533  * This is a little tricky because some text values (e.g. strings or variable
1534  * names) may not be defined or have the same value when the expression is
1535  * recalled.  These text values are therefore saved in the top portion of
1536  * the text table.
1537  * ------------------------------------------------------------------------*/
1538
1539 static Cell lastExprSaved;              /* last expression to be saved     */
1540
1541 Void setLastExpr(e)                     /* save expression for later recall*/
1542 Cell e; {
1543     lastExprSaved = NIL;                /* in case attempt to save fails   */
1544     savedText     = NUM_TEXT;
1545     lastExprSaved = lowLevelLastIn(e);
1546 }
1547
1548 static Cell local lowLevelLastIn(c)     /* Duplicate expression tree (i.e. */
1549 Cell c; {                               /* acyclic graph) for later recall */
1550     if (isPair(c)) {                    /* Duplicating any text strings    */
1551         if (isBoxTag(fst(c)))           /* in case these are lost at some  */
1552             switch (fst(c)) {           /* point before the expr is reused */
1553                 case VARIDCELL :
1554                 case VAROPCELL :
1555                 case DICTVAR   :
1556                 case CONIDCELL :
1557                 case CONOPCELL :
1558                 case STRCELL   : return pair(fst(c),saveText(textOf(c)));
1559                 default        : return pair(fst(c),snd(c));
1560             }
1561         else
1562             return pair(lowLevelLastIn(fst(c)),lowLevelLastIn(snd(c)));
1563     }
1564 #if TREX
1565     else if (isExt(c))
1566         return pair(EXTCOPY,saveText(extText(c)));
1567 #endif
1568     else
1569         return c;
1570 }
1571
1572 Cell getLastExpr() {                    /* recover previously saved expr   */
1573     return lowLevelLastOut(lastExprSaved);
1574 }
1575
1576 static Cell local lowLevelLastOut(c)    /* As with lowLevelLastIn() above  */
1577 Cell c; {                               /* except that Cells refering to   */
1578     if (isPair(c)) {                    /* Text values are restored to     */
1579         if (isBoxTag(fst(c)))           /* appropriate values              */
1580             switch (fst(c)) {
1581                 case VARIDCELL :
1582                 case VAROPCELL :
1583                 case DICTVAR   :
1584                 case CONIDCELL :
1585                 case CONOPCELL :
1586                 case STRCELL   : return pair(fst(c),
1587                                              findText(text+intValOf(c)));
1588 #if TREX
1589                 case EXTCOPY   : return mkExt(findText(text+intValOf(c)));
1590 #endif
1591                 default        : return pair(fst(c),snd(c));
1592             }
1593         else
1594             return pair(lowLevelLastOut(fst(c)),lowLevelLastOut(snd(c)));
1595     }
1596     else
1597         return c;
1598 }
1599
1600 /* --------------------------------------------------------------------------
1601  * Miscellaneous operations on heap cells:
1602  * ------------------------------------------------------------------------*/
1603
1604 /* Profiling suggests that the number of calls to whatIs() is typically    */
1605 /* rather high.  The recoded version below attempts to improve the average */
1606 /* performance for whatIs() using a binary search for part of the analysis */
1607
1608 Cell whatIs(c)                         /* identify type of cell            */
1609 register Cell c; {
1610     if (isPair(c)) {
1611         register Cell fstc = fst(c);
1612         return isTag(fstc) ? fstc : AP;
1613     }
1614     if (c<TUPMIN)    return c;
1615     if (c>=INTMIN)   return INTCELL;
1616
1617     if (c>=NAMEMIN){if (c>=CLASSMIN)   {if (c>=CHARMIN) return CHARCELL;
1618                                         else            return CLASS;}
1619                     else                if (c>=INSTMIN) return INSTANCE;
1620                                         else            return NAME;}
1621     else            if (c>=MODMIN)     {if (c>=TYCMIN)  return TYCON;
1622                                         else            return MODULE;}
1623                     else                if (c>=OFFMIN)  return OFFSET;
1624 #if TREX
1625                                         else            return (c>=EXTMIN) ?
1626                                                                 EXT : TUPLE;
1627 #else
1628                                         else            return TUPLE;
1629 #endif
1630
1631 /*  if (isPair(c)) {
1632         register Cell fstc = fst(c);
1633         return isTag(fstc) ? fstc : AP;
1634     }
1635     if (c>=INTMIN)   return INTCELL;
1636     if (c>=CHARMIN)  return CHARCELL;
1637     if (c>=CLASSMIN) return CLASS;
1638     if (c>=INSTMIN)  return INSTANCE;
1639     if (c>=NAMEMIN)  return NAME;
1640     if (c>=TYCMIN)   return TYCON;
1641     if (c>=MODMIN)   return MODULE;
1642     if (c>=OFFMIN)   return OFFSET;
1643 #if TREX
1644     if (c>=EXTMIN)   return EXT;
1645 #endif
1646     if (c>=TUPMIN)   return TUPLE;
1647     return c;*/
1648 }
1649
1650 #if DEBUG_PRINTER
1651 /* A very, very simple printer.
1652  * Output is uglier than from printExp - but the printer is more
1653  * robust and can be used on any data structure irrespective of
1654  * its type.
1655  */
1656 Void print Args((Cell, Int));
1657 Void print(c, depth)
1658 Cell c;
1659 Int  depth; {
1660     if (0 == depth) {
1661         Printf("...");
1662 #if 0 /* Not in this version of Hugs */
1663     } else if (isPair(c) && !isGenPair(c)) {
1664         extern Void printEvalCell Args((Cell, Int));
1665         printEvalCell(c,depth);
1666 #endif
1667     } else {
1668         Int tag = whatIs(c);
1669         switch (tag) {
1670         case AP: 
1671                 Putchar('(');
1672                 print(fst(c), depth-1);
1673                 Putchar(',');
1674                 print(snd(c), depth-1);
1675                 Putchar(')');
1676                 break;
1677         case FREECELL:
1678                 Printf("free(%d)", c);
1679                 break;
1680         case INTCELL:
1681                 Printf("int(%d)", intOf(c));
1682                 break;
1683         case BIGCELL:
1684                 Printf("bignum(%s)", bignumToString(c));
1685                 break;
1686         case CHARCELL:
1687                 Printf("char('%c')", charOf(c));
1688                 break;
1689         case PTRCELL: 
1690                 Printf("ptr(%p)",ptrOf(c));
1691                 break;
1692         case CLASS:
1693                 Printf("class(%d)", c-CLASSMIN);
1694                 if (CLASSMIN <= c && c < classHw) {
1695                     Printf("=\"%s\"", textToStr(cclass(c).text));
1696                 }
1697                 break;
1698         case INSTANCE:
1699                 Printf("instance(%d)", c - INSTMIN);
1700                 break;
1701         case NAME:
1702                 Printf("name(%d)", c-NAMEMIN);
1703                 if (NAMEMIN <= c && c < nameHw) {
1704                     Printf("=\"%s\"", textToStr(name(c).text));
1705                 }
1706                 break;
1707         case TYCON:
1708                 Printf("tycon(%d)", c-TYCMIN);
1709                 if (TYCMIN <= c && c < tyconHw)
1710                     Printf("=\"%s\"", textToStr(tycon(c).text));
1711                 break;
1712         case MODULE:
1713                 Printf("module(%d)", c - MODMIN);
1714                 break;
1715         case OFFSET:
1716                 Printf("Offset %d", offsetOf(c));
1717                 break;
1718         case TUPLE:
1719                 Printf("Tuple %d", tupleOf(c));
1720                 break;
1721         case POLYTYPE:
1722                 Printf("Polytype");
1723                 print(snd(c),depth-1);
1724                 break;
1725         case QUAL:
1726                 Printf("Qualtype");
1727                 print(snd(c),depth-1);
1728                 break;
1729         case RANK2:
1730                 Printf("Rank2(");
1731                 if (isPair(snd(c)) && isInt(fst(snd(c)))) {
1732                     Printf("%d ", intOf(fst(snd(c))));
1733                     print(snd(snd(c)),depth-1);
1734                 } else {
1735                     print(snd(c),depth-1);
1736                 }
1737                 Printf(")");
1738                 break;
1739         case NIL:
1740                 Printf("NIL");
1741                 break;
1742         case WILDCARD:
1743                 Printf("_");
1744                 break;
1745         case STAR:
1746                 Printf("STAR");
1747                 break;
1748         case DOTDOT:
1749                 Printf("DOTDOT");
1750                 break;
1751         case DICTVAR:
1752                 Printf("{dict %d}",textOf(c));
1753                 break;
1754         case VARIDCELL:
1755         case VAROPCELL:
1756         case CONIDCELL:
1757         case CONOPCELL:
1758                 Printf("{id %s}",textToStr(textOf(c)));
1759                 break;
1760         case QUALIDENT:
1761                 Printf("{qid %s.%s}",textToStr(qmodOf(c)),textToStr(qtextOf(c)));
1762                 break;
1763         case LETREC:
1764                 Printf("LetRec(");
1765                 print(fst(snd(c)),depth-1);
1766                 Putchar(',');
1767                 print(snd(snd(c)),depth-1);
1768                 Putchar(')');
1769                 break;
1770         case LAMBDA:
1771                 Printf("Lambda(");
1772                 print(snd(c),depth-1);
1773                 Putchar(')');
1774                 break;
1775         case FINLIST:
1776                 Printf("FinList(");
1777                 print(snd(c),depth-1);
1778                 Putchar(')');
1779                 break;
1780         case COMP:
1781                 Printf("Comp(");
1782                 print(fst(snd(c)),depth-1);
1783                 Putchar(',');
1784                 print(snd(snd(c)),depth-1);
1785                 Putchar(')');
1786                 break;
1787         case ASPAT:
1788                 Printf("AsPat(");
1789                 print(fst(snd(c)),depth-1);
1790                 Putchar(',');
1791                 print(snd(snd(c)),depth-1);
1792                 Putchar(')');
1793                 break;
1794         case FROMQUAL:
1795                 Printf("FromQual(");
1796                 print(fst(snd(c)),depth-1);
1797                 Putchar(',');
1798                 print(snd(snd(c)),depth-1);
1799                 Putchar(')');
1800                 break;
1801         case STGVAR:
1802                 Printf("StgVar%d=",-c);
1803                 print(snd(c), depth-1);
1804                 break;
1805         case STGAPP:
1806                 Printf("StgApp(");
1807                 print(fst(snd(c)),depth-1);
1808                 Putchar(',');
1809                 print(snd(snd(c)),depth-1);
1810                 Putchar(')');
1811                 break;
1812         case STGPRIM:
1813                 Printf("StgPrim(");
1814                 print(fst(snd(c)),depth-1);
1815                 Putchar(',');
1816                 print(snd(snd(c)),depth-1);
1817                 Putchar(')');
1818                 break;
1819         case STGCON:
1820                 Printf("StgCon(");
1821                 print(fst(snd(c)),depth-1);
1822                 Putchar(',');
1823                 print(snd(snd(c)),depth-1);
1824                 Putchar(')');
1825                 break;
1826         case PRIMCASE:
1827                 Printf("PrimCase(");
1828                 print(fst(snd(c)),depth-1);
1829                 Putchar(',');
1830                 print(snd(snd(c)),depth-1);
1831                 Putchar(')');
1832                 break;
1833         default:
1834                 if (isBoxTag(tag)) {
1835                     Printf("Tag(%d)=%d", c, tag);
1836                 } else if (isConTag(tag)) {
1837                     Printf("%d@(%d,",c,tag);
1838                     print(snd(c), depth-1);
1839                     Putchar(')');
1840                     break;
1841                 } else if (c == tag) {
1842                     Printf("Tag(%d)", c);
1843                 } else {
1844                     Printf("Tag(%d)=%d", c, tag);
1845                 }
1846                 break;
1847         }
1848     }
1849     FlushStdout();
1850 }
1851 #endif
1852
1853 Bool isVar(c)                           /* is cell a VARIDCELL/VAROPCELL ? */
1854 Cell c; {                               /* also recognises DICTVAR cells   */
1855     return isPair(c) &&
1856                (fst(c)==VARIDCELL || fst(c)==VAROPCELL || fst(c)==DICTVAR);
1857 }
1858
1859 Bool isCon(c)                          /* is cell a CONIDCELL/CONOPCELL ?  */
1860 Cell c; {
1861     return isPair(c) && (fst(c)==CONIDCELL || fst(c)==CONOPCELL);
1862 }
1863
1864 Bool isQVar(c)                        /* is cell a [un]qualified varop/id? */
1865 Cell c; {
1866     if (!isPair(c)) return FALSE;
1867     switch (fst(c)) {
1868         case VARIDCELL  :
1869         case VAROPCELL  : return TRUE;
1870
1871         case QUALIDENT  : return isVar(snd(snd(c)));
1872
1873         default         : return FALSE;
1874     }
1875 }
1876
1877 Bool isQCon(c)                         /*is cell a [un]qualified conop/id? */
1878 Cell c; {
1879     if (!isPair(c)) return FALSE;
1880     switch (fst(c)) {
1881         case CONIDCELL  :
1882         case CONOPCELL  : return TRUE;
1883
1884         case QUALIDENT  : return isCon(snd(snd(c)));
1885
1886         default         : return FALSE;
1887     }
1888 }
1889
1890 Bool isQualIdent(c)                    /* is cell a qualified identifier?  */
1891 Cell c; {
1892     return isPair(c) && (fst(c)==QUALIDENT);
1893 }
1894
1895 Bool isIdent(c)                        /* is cell an identifier?           */
1896 Cell c; {
1897     if (!isPair(c)) return FALSE;
1898     switch (fst(c)) {
1899         case VARIDCELL  :
1900         case VAROPCELL  :
1901         case CONIDCELL  :
1902         case CONOPCELL  : return TRUE;
1903
1904         case QUALIDENT  : return TRUE;
1905
1906         default         : return FALSE;
1907     }
1908 }
1909
1910 Bool isInt(c)                          /* cell holds integer value?        */
1911 Cell c; {
1912     return isSmall(c) || (isPair(c) && fst(c)==INTCELL);
1913 }
1914
1915 Int intOf(c)                           /* find integer value of cell?      */
1916 Cell c; {
1917   if (!isInt(c)) {
1918     assert(isInt(c)); }
1919     return isPair(c) ? (Int)(snd(c)) : (Int)(c-INTZERO);
1920 }
1921
1922 Cell mkInt(n)                          /* make cell representing integer   */
1923 Int n; {
1924     return (MINSMALLINT <= n && n <= MAXSMALLINT)
1925            ? INTZERO+n
1926            : pair(INTCELL,n);
1927 }
1928
1929 #if SIZEOF_INTP == SIZEOF_INT
1930 typedef union {Int i; Ptr p;} IntOrPtr;
1931 Cell mkPtr(p)
1932 Ptr p;
1933 {
1934     IntOrPtr x;
1935     x.p = p;
1936     return pair(PTRCELL,x.i);
1937 }
1938
1939 Ptr ptrOf(c)
1940 Cell c;
1941 {
1942     IntOrPtr x;
1943     assert(fst(c) == PTRCELL);
1944     x.i = snd(c);
1945     return x.p;
1946 }
1947 Cell mkCPtr(p)
1948 Ptr p;
1949 {
1950     IntOrPtr x;
1951     x.p = p;
1952     return pair(CPTRCELL,x.i);
1953 }
1954
1955 Ptr cptrOf(c)
1956 Cell c;
1957 {
1958     IntOrPtr x;
1959     assert(fst(c) == CPTRCELL);
1960     x.i = snd(c);
1961     return x.p;
1962 }
1963 #elif SIZEOF_INTP == 2*SIZEOF_INT
1964 typedef union {struct {Int i1; Int i2;} i; Ptr p;} IntOrPtr;
1965 Cell mkPtr(p)
1966 Ptr p;
1967 {
1968     IntOrPtr x;
1969     x.p = p;
1970     return pair(PTRCELL,pair(mkInt(x.i.i1),mkInt(x.i.i2)));
1971 }
1972
1973 Ptr ptrOf(c)
1974 Cell c;
1975 {
1976     IntOrPtr x;
1977     assert(fst(c) == PTRCELL);
1978     x.i.i1 = intOf(fst(snd(c)));
1979     x.i.i2 = intOf(snd(snd(c)));
1980     return x.p;
1981 }
1982 #else
1983 #warning "type Addr not supported on this architecture - don't use it"
1984 Cell mkPtr(p)
1985 Ptr p;
1986 {
1987     ERRMSG(0) "mkPtr: type Addr not supported on this architecture"
1988     EEND;
1989 }
1990
1991 Ptr ptrOf(c)
1992 Cell c;
1993 {
1994     ERRMSG(0) "ptrOf: type Addr not supported on this architecture"
1995     EEND;
1996 }
1997 #endif
1998
1999 String stringNegate( s )
2000 String s;
2001 {
2002     if (s[0] == '-') {
2003         return &s[1];
2004     } else {
2005         static char t[100];
2006         t[0] = '-';
2007         strcpy(&t[1],s);  /* ToDo: use strncpy instead */
2008         return t;
2009     }
2010 }
2011
2012 /* --------------------------------------------------------------------------
2013  * List operations:
2014  * ------------------------------------------------------------------------*/
2015
2016 Int length(xs)                         /* calculate length of list xs      */
2017 List xs; {
2018     Int n = 0;
2019     for (; nonNull(xs); ++n)
2020         xs = tl(xs);
2021     return n;
2022 }
2023
2024 List appendOnto(xs,ys)                 /* Destructively prepend xs onto    */
2025 List xs, ys; {                         /* ys by modifying xs ...           */
2026     if (isNull(xs))
2027         return ys;
2028     else {
2029         List zs = xs;
2030         while (nonNull(tl(zs)))
2031             zs = tl(zs);
2032         tl(zs) = ys;
2033         return xs;
2034     }
2035 }
2036
2037 List dupOnto(xs,ys)      /* non-destructively prepend xs backwards onto ys */
2038 List xs; 
2039 List ys; {
2040     for (; nonNull(xs); xs=tl(xs))
2041         ys = cons(hd(xs),ys);
2042     return ys;
2043 }
2044
2045 List dupListOnto(xs,ys)              /* Duplicate spine of list xs onto ys */
2046 List xs;
2047 List ys; {
2048     return revOnto(dupOnto(xs,NIL),ys);
2049 }
2050
2051 List dupList(xs)                       /* Duplicate spine of list xs       */
2052 List xs; {
2053     List ys = NIL;
2054     for (; nonNull(xs); xs=tl(xs))
2055         ys = cons(hd(xs),ys);
2056     return rev(ys);
2057 }
2058
2059 List revOnto(xs,ys)                    /* Destructively reverse elements of*/
2060 List xs, ys; {                         /* list xs onto list ys...          */
2061     Cell zs;
2062
2063     while (nonNull(xs)) {
2064         zs     = tl(xs);
2065         tl(xs) = ys;
2066         ys     = xs;
2067         xs     = zs;
2068     }
2069     return ys;
2070 }
2071
2072 Cell varIsMember(t,xs)                 /* Test if variable is a member of  */
2073 Text t;                                /* given list of variables          */
2074 List xs; {
2075     for (; nonNull(xs); xs=tl(xs))
2076         if (t==textOf(hd(xs)))
2077             return hd(xs);
2078     return NIL;
2079 }
2080
2081 Name nameIsMember(t,ns)                 /* Test if name with text t is a   */
2082 Text t;                                 /* member of list of names xs      */
2083 List ns; {
2084     for (; nonNull(ns); ns=tl(ns))
2085         if (t==name(hd(ns)).text)
2086             return hd(ns);
2087     return NIL;
2088 }
2089
2090 Cell intIsMember(n,xs)                 /* Test if integer n is member of   */
2091 Int  n;                                /* given list of integers           */
2092 List xs; {
2093     for (; nonNull(xs); xs=tl(xs))
2094         if (n==intOf(hd(xs)))
2095             return hd(xs);
2096     return NIL;
2097 }
2098
2099 Cell cellIsMember(x,xs)                /* Test for membership of specific  */
2100 Cell x;                                /* cell x in list xs                */
2101 List xs; {
2102     for (; nonNull(xs); xs=tl(xs))
2103         if (x==hd(xs))
2104             return hd(xs);
2105     return NIL;
2106 }
2107
2108 Cell cellAssoc(c,xs)                   /* Lookup cell in association list  */
2109 Cell c;         
2110 List xs; {
2111     for (; nonNull(xs); xs=tl(xs))
2112         if (c==fst(hd(xs)))
2113             return hd(xs);
2114     return NIL;
2115 }
2116
2117 Cell cellRevAssoc(c,xs)                /* Lookup cell in range of          */
2118 Cell c;                                /* association lists                */
2119 List xs; {
2120     for (; nonNull(xs); xs=tl(xs))
2121         if (c==snd(hd(xs)))
2122             return hd(xs);
2123     return NIL;
2124 }
2125
2126 List replicate(n,x)                     /* create list of n copies of x    */
2127 Int n;
2128 Cell x; {
2129     List xs=NIL;
2130     while (0<n--)
2131         xs = cons(x,xs);
2132     return xs;
2133 }
2134
2135 List diffList(from,take)               /* list difference: from\take       */
2136 List from, take; {                     /* result contains all elements of  */
2137     List result = NIL;                 /* `from' not appearing in `take'   */
2138
2139     while (nonNull(from)) {
2140         List next = tl(from);
2141         if (!cellIsMember(hd(from),take)) {
2142             tl(from) = result;
2143             result   = from;
2144         }
2145         from = next;
2146     }
2147     return rev(result);
2148 }
2149
2150 List deleteCell(xs, y)                  /* copy xs deleting pointers to y  */
2151 List xs;
2152 Cell y; {
2153     List result = NIL; 
2154     for(;nonNull(xs);xs=tl(xs)) {
2155         Cell x = hd(xs);
2156         if (x != y) {
2157             result=cons(x,result);
2158         }
2159     }
2160     return rev(result);
2161 }
2162
2163 List take(n,xs)                         /* destructively truncate list to  */
2164 Int  n;                                 /* specified length                */
2165 List xs; {
2166     List ys = xs;
2167
2168     if (n==0)
2169         return NIL;
2170     while (1<n-- && nonNull(xs))
2171         xs = tl(xs);
2172     if (nonNull(xs))
2173         tl(xs) = NIL;
2174     return ys;
2175 }
2176
2177 List splitAt(n,xs)                      /* drop n things from front of list*/
2178 Int  n;       
2179 List xs; {
2180     for(; n>0; --n) {
2181         xs = tl(xs);
2182     }
2183     return xs;
2184 }
2185
2186 Cell nth(n,xs)                          /* extract n'th element of list    */
2187 Int  n;
2188 List xs; {
2189     for(; n>0 && nonNull(xs); --n, xs=tl(xs)) {
2190     }
2191     if (isNull(xs))
2192         internal("nth");
2193     return hd(xs);
2194 }
2195
2196 List removeCell(x,xs)                   /* destructively remove cell from  */
2197 Cell x;                                 /* list                            */
2198 List xs; {
2199     if (nonNull(xs)) {
2200         if (hd(xs)==x)
2201             return tl(xs);              /* element at front of list        */
2202         else {
2203             List prev = xs;
2204             List curr = tl(xs);
2205             for (; nonNull(curr); prev=curr, curr=tl(prev))
2206                 if (hd(curr)==x) {
2207                     tl(prev) = tl(curr);
2208                     return xs;          /* element in middle of list       */
2209                 }
2210         }
2211     }
2212     return xs;                          /* here if element not found       */
2213 }
2214
2215 List nubList(xs)                        /* nuke dups in list               */
2216 List xs; {                              /* non destructive                 */
2217    List outs = NIL;
2218    for (; nonNull(xs); xs=tl(xs))
2219       if (isNull(cellIsMember(hd(xs),outs)))
2220          outs = cons(hd(xs),outs);
2221    outs = rev(outs);
2222    return outs;
2223 }
2224
2225 /* --------------------------------------------------------------------------
2226  * Operations on applications:
2227  * ------------------------------------------------------------------------*/
2228
2229 Int argCount;                          /* number of args in application    */
2230
2231 Cell getHead(e)                        /* get head cell of application     */
2232 Cell e; {                              /* set number of args in argCount   */
2233     for (argCount=0; isAp(e); e=fun(e))
2234         argCount++;
2235     return e;
2236 }
2237
2238 List getArgs(e)                        /* get list of arguments in function*/
2239 Cell e; {                              /* application:                     */
2240     List as;                           /* getArgs(f e1 .. en) = [e1,..,en] */
2241
2242     for (as=NIL; isAp(e); e=fun(e))
2243         as = cons(arg(e),as);
2244     return as;
2245 }
2246
2247 Cell nthArg(n,e)                       /* return nth arg in application    */
2248 Int  n;                                /* of function to m args (m>=n)     */
2249 Cell e; {                              /* nthArg n (f x0 x1 ... xm) = xn   */
2250     for (n=numArgs(e)-n-1; n>0; n--)
2251         e = fun(e);
2252     return arg(e);
2253 }
2254
2255 Int numArgs(e)                         /* find number of arguments to expr */
2256 Cell e; {
2257     Int n;
2258     for (n=0; isAp(e); e=fun(e))
2259         n++;
2260     return n;
2261 }
2262
2263 Cell applyToArgs(f,args)               /* destructively apply list of args */
2264 Cell f;                                /* to function f                    */
2265 List args; {
2266     while (nonNull(args)) {
2267         Cell temp = tl(args);
2268         tl(args)  = hd(args);
2269         hd(args)  = f;
2270         f         = args;
2271         args      = temp;
2272     }
2273     return f;
2274 }
2275
2276
2277 /* --------------------------------------------------------------------------
2278  * plugin support
2279  * ------------------------------------------------------------------------*/
2280
2281 /*---------------------------------------------------------------------------
2282  * GreenCard entry points
2283  *
2284  * GreenCard generated code accesses Hugs data structures and functions 
2285  * (only) via these functions (which are stored in the virtual function
2286  * table hugsAPI1.
2287  *-------------------------------------------------------------------------*/
2288
2289 #if GREENCARD
2290
2291 static Cell  makeTuple      Args((Int));
2292 static Cell  makeInt        Args((Int));
2293 static Cell  makeChar       Args((Char));
2294 static Char  CharOf         Args((Cell));
2295 static Cell  makeFloat      Args((FloatPro));
2296 static Void* derefMallocPtr Args((Cell));
2297 static Cell* Fst            Args((Cell));
2298 static Cell* Snd            Args((Cell));
2299
2300 static Cell  makeTuple(n)      Int      n; { return mkTuple(n); }
2301 static Cell  makeInt(n)        Int      n; { return mkInt(n); }
2302 static Cell  makeChar(n)       Char     n; { return mkChar(n); }
2303 static Char  CharOf(n)         Cell     n; { return charOf(n); }
2304 static Cell  makeFloat(n)      FloatPro n; { return mkFloat(n); }
2305 static Void* derefMallocPtr(n) Cell     n; { return derefMP(n); }
2306 static Cell* Fst(n)            Cell     n; { return (Cell*)&fst(n); }
2307 static Cell* Snd(n)            Cell     n; { return (Cell*)&snd(n); }
2308
2309 HugsAPI1* hugsAPI1() {
2310     static HugsAPI1 api;
2311     static Bool initialised = FALSE;
2312     if (!initialised) {
2313         api.nameTrue        = nameTrue;
2314         api.nameFalse       = nameFalse;
2315         api.nameNil         = nameNil;
2316         api.nameCons        = nameCons;
2317         api.nameJust        = nameJust;
2318         api.nameNothing     = nameNothing;
2319         api.nameLeft        = nameLeft;
2320         api.nameRight       = nameRight;
2321         api.nameUnit        = nameUnit;
2322         api.nameIORun       = nameIORun;
2323         api.makeInt         = makeInt;
2324         api.makeChar        = makeChar;
2325         api.CharOf          = CharOf;
2326         api.makeFloat       = makeFloat;
2327         api.makeTuple       = makeTuple;
2328         api.pair            = pair;
2329         api.mkMallocPtr     = mkMallocPtr;
2330         api.derefMallocPtr  = derefMallocPtr;
2331         api.mkStablePtr     = mkStablePtr;
2332         api.derefStablePtr  = derefStablePtr;
2333         api.freeStablePtr   = freeStablePtr;
2334         api.eval            = eval;
2335         api.evalWithNoError = evalWithNoError;
2336         api.evalFails       = evalFails;
2337         api.whnfArgs        = &whnfArgs;
2338         api.whnfHead        = &whnfHead;
2339         api.whnfInt         = &whnfInt;
2340         api.whnfFloat       = &whnfFloat;
2341         api.garbageCollect  = garbageCollect;
2342         api.stackOverflow   = hugsStackOverflow;
2343         api.internal        = internal;
2344         api.registerPrims   = registerPrims;
2345         api.addPrimCfun     = addPrimCfun;
2346         api.inventText      = inventText;
2347         api.Fst             = Fst;
2348         api.Snd             = Snd;
2349         api.cellStack       = cellStack;
2350         api.sp              = &sp;
2351     }
2352     return &api;
2353 }
2354
2355 #endif /* GREENCARD */
2356
2357
2358 /* --------------------------------------------------------------------------
2359  * storage control:
2360  * ------------------------------------------------------------------------*/
2361
2362 #if DYN_TABLES
2363 static void far* safeFarCalloc Args((Int,Int));
2364 static void far* safeFarCalloc(n,s)     /* allocate table storage and check*/
2365 Int n, s; {                             /* for non-null return             */
2366     void far* tab = farCalloc(n,s);
2367     if (tab==0) {
2368         ERRMSG(0) "Cannot allocate run-time tables"
2369         EEND;
2370     }
2371     return tab;
2372 }
2373 #define TABALLOC(v,t,n)                 v=(t far*)safeFarCalloc(n,sizeof(t));
2374 #else
2375 #define TABALLOC(v,t,n)
2376 #endif
2377
2378 Void storage(what)
2379 Int what; {
2380     Int i;
2381
2382     switch (what) {
2383         case RESET   : clearStack();
2384
2385                        /* the next 2 statements are particularly important
2386                         * if you are using GLOBALfst or GLOBALsnd since the
2387                         * corresponding registers may be reset to their
2388                         * uninitialised initial values by a longjump.
2389                         */
2390                        heapTopFst = heapFst + heapSize;
2391                        heapTopSnd = heapSnd + heapSize;
2392                        consGC = TRUE;
2393                        lsave  = NIL;
2394                        rsave  = NIL;
2395                        if (isNull(lastExprSaved))
2396                            savedText = NUM_TEXT;
2397                        break;
2398
2399         case MARK    : 
2400                        start();
2401                        for (i=NAMEMIN; i<nameHw; ++i) {
2402                            mark(name(i).parent);
2403                            mark(name(i).defn);
2404                            mark(name(i).stgVar);
2405                            mark(name(i).type);
2406                         }
2407                        end("Names", nameHw-NAMEMIN);
2408
2409                        start();
2410                        for (i=MODMIN; i<moduleHw; ++i) {
2411                            mark(module(i).tycons);
2412                            mark(module(i).names);
2413                            mark(module(i).classes);
2414                            mark(module(i).exports);
2415                            mark(module(i).qualImports);
2416                        }
2417                        end("Modules", moduleHw-MODMIN);
2418
2419                        start();
2420                        for (i=TYCMIN; i<tyconHw; ++i) {
2421                            mark(tycon(i).defn);
2422                            mark(tycon(i).kind);
2423                            mark(tycon(i).what);
2424                        }
2425                        end("Type constructors", tyconHw-TYCMIN);
2426
2427                        start();
2428                        for (i=CLASSMIN; i<classHw; ++i) {
2429                            mark(cclass(i).head);
2430                            mark(cclass(i).kinds);
2431                            mark(cclass(i).dsels);
2432                            mark(cclass(i).supers);
2433                            mark(cclass(i).members);
2434                            mark(cclass(i).defaults);
2435                            mark(cclass(i).instances);
2436                        }
2437                        mark(classes);
2438                        end("Classes", classHw-CLASSMIN);
2439
2440                        start();
2441                        for (i=INSTMIN; i<instHw; ++i) {
2442                            mark(inst(i).head);
2443                            mark(inst(i).kinds);
2444                            mark(inst(i).specifics);
2445                            mark(inst(i).implements);
2446                        }
2447                        end("Instances", instHw-INSTMIN);
2448
2449                        start();
2450                        for (i=0; i<=sp; ++i)
2451                            mark(stack(i));
2452                        end("Stack", sp+1);
2453
2454                        start();
2455                        mark(lastExprSaved);
2456                        mark(lsave);
2457                        mark(rsave);
2458                        end("Last expression", 3);
2459
2460                        if (consGC) {
2461                            start();
2462                            gcCStack();
2463                            end("C stack", stackRoots);
2464                        }
2465
2466                        break;
2467
2468         case INSTALL : heapFst = heapAlloc(heapSize);
2469                        heapSnd = heapAlloc(heapSize);
2470
2471                        if (heapFst==(Heap)0 || heapSnd==(Heap)0) {
2472                            ERRMSG(0) "Cannot allocate heap storage (%d cells)",
2473                                      heapSize
2474                            EEND;
2475                        }
2476
2477                        heapTopFst = heapFst + heapSize;
2478                        heapTopSnd = heapSnd + heapSize;
2479                        for (i=1; i<heapSize; ++i) {
2480                            fst(-i) = FREECELL;
2481                            snd(-i) = -(i+1);
2482                        }
2483                        snd(-heapSize) = NIL;
2484                        freeList  = -1;
2485                        numGcs    = 0;
2486                        consGC    = TRUE;
2487                        lsave     = NIL;
2488                        rsave     = NIL;
2489
2490                        marksSize  = bitArraySize(heapSize);
2491                        if ((marks=(Int *)calloc(marksSize, sizeof(Int)))==0) {
2492                            ERRMSG(0) "Unable to allocate gc markspace"
2493                            EEND;
2494                        }
2495
2496                        TABALLOC(text,      char,             NUM_TEXT)
2497                        TABALLOC(tyconHash, Tycon,            TYCONHSZ)
2498                        TABALLOC(tabTycon,  struct strTycon,  NUM_TYCON)
2499                        TABALLOC(nameHash,  Name,             NAMEHSZ)
2500                        TABALLOC(tabName,   struct strName,   NUM_NAME)
2501                        TABALLOC(tabClass,  struct strClass,  NUM_CLASSES)
2502                        TABALLOC(cellStack, Cell,             NUM_STACK)
2503                        TABALLOC(tabModule, struct Module,    NUM_SCRIPTS)
2504 #if TREX
2505                        TABALLOC(tabExt,    Text,             NUM_EXT)
2506 #endif
2507                        clearStack();
2508
2509                        textHw        = 0;
2510                        nextNewText   = NUM_TEXT;
2511                        nextNewDText  = (-1);
2512                        lastExprSaved = NIL;
2513                        savedText     = NUM_TEXT;
2514                        for (i=0; i<TEXTHSZ; ++i)
2515                            textHash[i][0] = NOTEXT;
2516
2517
2518                        moduleHw = MODMIN;
2519
2520                        tyconHw  = TYCMIN;
2521                        for (i=0; i<TYCONHSZ; ++i)
2522                            tyconHash[i] = NIL;
2523 #if TREX
2524                        extHw    = EXTMIN;
2525 #endif
2526
2527                        nameHw   = NAMEMIN;
2528                        for (i=0; i<NAMEHSZ; ++i)
2529                            nameHash[i] = NIL;
2530
2531                        classHw  = CLASSMIN;
2532
2533                        instHw   = INSTMIN;
2534
2535 #if USE_DICTHW
2536                        dictHw   = 0;
2537 #endif
2538
2539                        tabInst  = (struct strInst far *)
2540                                     farCalloc(NUM_INSTS,sizeof(struct strInst));
2541
2542                        if (tabInst==0) {
2543                            ERRMSG(0) "Cannot allocate instance tables"
2544                            EEND;
2545                        }
2546
2547                        scriptHw = 0;
2548
2549                        break;
2550     }
2551 }
2552
2553 /*-------------------------------------------------------------------------*/