1260 lines · 37.3 KB · C
RawDownload
/* -------------------------------------------------------------------------- * Haskell 98 module system implementation for Hugs. * * The Hugs 98 system is Copyright (c) Mark P Jones, Alastair Reid, the * Yale Haskell Group, and the OGI School of Science & Engineering at OHSU, * 1994-2003, All rights reserved.  It is distributed as free software under * the license in the file "License", which is included in the distribution. * * -sof 2002. *  * ------------------------------------------------------------------------*/#include "prelude.h"#include "storage.h"#include "connect.h"#include "errors.h"#include "module.h"#include "output.h" /* -------------------------------------------------------------------------- * Static analysis of modules: * * The static checks of the import and export lists are invoked * via the entry points in module.h  (cf. static.c:checkDefns()). * * ------------------------------------------------------------------------*/ /* -------------------------------------------------------------------------- * local function prototypes: * ------------------------------------------------------------------------*/static Name   local lookupName		Args((Text,List));static Module local modOfEntity         Args((Cell));static Void   local reportAmbigEntity   Args((Text,Text,List));static List   local checkSubentities	Args((List,List,List,String,Text));static Void   local checkExportDistinct Args((List,Bool,Cell));static List   local checkExportTycon	Args((List,Text,Bool,Cell,Tycon));static List   local checkExportClass	Args((List,Text,Bool,Cell,Class));static List   local checkExportModule	Args((List,Text,Cell));static List   local checkExport		Args((List,Text,Cell));static List   local checkImportEntity	Args((List,Module,Bool,Cell));static List   local resolveImportList	Args((Module,Cell,Bool));static Cell   local entityIsMember      Args((Cell,List));static List   local augmentEntity       Args((Bool,Cell,Cell,List));static List   local addEntity           Args((Cell,Cell,List));static List   local addEntityPair       Args((Cell,List));static List   local mergeImportLists    Args((List,List));static List   local getIEOrphans        Args((List));static List   local fixupIEList         Args((List));static List   local allMethodsOrDCons   Args((List,Cell,Module,Bool)); static Cell   local importEntity	Args((Module,Cell));static Void   local importTycon		Args((Module,Tycon));static Void   local importClass		Args((Module,Class)); static Void   local browseName		Args((Name));static Void   local browseEntity	Args((Cell)); Void addQualImport(orig,new,entities) /* Add to qualified import list       */Cell orig;       /* Original name of module                                */Cell new;        /* Name module is called within this module (or NIL)      */List entities; { /* List of entity names */    /* Record the entities imported */    module(currentModule).qualImports =       addEntity(orig,entities,module(currentModule).qualImports);    /* Record the module --> alias mapping */    module(currentModule).modAliases =        cons(pair(isNull(new)?orig:new,orig), module(currentModule).modAliases);} Void addUnqualImport(mod,new,entities) /* An unqualified import            */Cell mod;         /* Name of module                                        */Cell new;         /* Local alias                                           */List entities;  { /* List of entity names                                  */    /* Add to unqualified import list */    unqualImports = addEntity(mod,entities,unqualImports);    /* Record the module --> alias mapping */    module(currentModule).modAliases =        cons(pair(isNull(new)?mod:new,mod), module(currentModule).modAliases);}  static Name local lookupName(t,nms)    /* find text t in list of Names     */Text t;List nms; { /* :: [Name] */    for(; nonNull(nms); nms=tl(nms)) {      if ( t == name(hd(nms)).text ) {	    return hd(nms);      }    }    return NIL;} static List local checkSubentities(imports,named,wanted,description,textParent)List   imports;List   named;       /* :: [ Q?(Var|Con)(Id|Op) ]                  */List   wanted;      /* :: [Name]                                  */String description; /* "<constructor>|<member> of <type>|<class>" */Text   textParent; {    for(; nonNull(named); named=tl(named)) {	Pair x = hd(named);	/* ToDo: ignores qualifier; doesn't check that entity is in scope */	Text t = isPair(snd(x)) ? qtextOf(x) : textOf(x);	Name n = lookupName(t,wanted);	if (isNull(n)) {	    ERRMSG(0) "Entity \"%s\" is not a %s \"%s\"",		      textToStr(t),		      description,		      textToStr(textParent)	    EEND;	}	imports = cons(n,imports);    }    return imports;} #if 0/* debugging code - dumping IE lists */static Void showIEEntity Args((Cell));static Void showIEList   Args((List,char)); static VoidshowIEEntity(e)Cell e; {  if (isName(e)) {    fprintf(stderr, "%s", textToStr(name(e).text));  } else if (isClass(e)) {    fprintf(stderr, "%s", textToStr(cclass(e).text));  } else if (isTycon(e)) {    fprintf(stderr, "%s", textToStr(tycon(e).text));  } else if (isPair(e)) {    showIEEntity(fst(e));    fprintf(stderr, "(");    showIEList(snd(e),' ');    fprintf(stderr, ")");  } else {    fprintf(stderr, "showIEEntity: unknown entity kind %d\n", whatIs(e));    fflush(stderr);  }} static VoidshowIEList(ieList,sep)List ieList;char sep; {  List xs = ieList;  for(;nonNull(xs);xs=tl(xs)) {    showIEEntity(hd(xs));    if (tl(xs) != NIL) {      fputc(sep, stderr);    }  }}#endif static List getIEOrphans(ieList) /* locate methods/dcons appearing on their */List ieList; {                   /* own in an import/export list.           */  List orphans = NIL;  List xs;    for(xs=ieList;nonNull(xs);xs=tl(xs)) {    Cell e = hd(xs);    if ( isName(e) ) {      if (isClass(name(e).parent)) {	/* a lone member */	orphans = cons(pair(name(e).parent, singleton(e)), orphans);      } else if (isCfun(e)) {	/* a lone data constructor (can only appear in a hiding list.) */	orphans = cons(pair(name(e).parent, singleton(e)), orphans);      } else if (isSfun(e)) {	/* a field name */	Cell p = name(e).parent;      /* the data constructor */	Cell t = name(p).parent;      /* the type constructor */	orphans = cons(pair(t,singleton(e)), orphans);      }    }  }  return orphans;} /* * fixupIEList() traverses an import/export list, adjusting * the list in the following ways: * *  1. 'orphan'/subordinate names are joined up with their *     parents. An orphan E is either a class member, field *     name or a data constructor (in 'hiding' lists *only*) *     that's imported/exported without referring to its *     parent P -- E appears in an import/export list rather *     than P(E). If P is appearing elsewhere in the *     import/export list, float E inside of P. * * ToDo: remove duplicates from the resulting list also; it's *       harmless for there to be any, but may lead to confusion *       later on. *  */static List fixupIEList(ieList)List ieList; {  List orphans = NIL;  List xs;   orphans = getIEOrphans(ieList);    if (nonNull(orphans)) {#if 0    /* Debugging - show the orphan list */    fprintf(stderr, "Orphan list{%s}:", textToStr(module(currentModule).text)); fflush(stderr);    showIEList(orphans,'\n'); fflush(stderr);#endif    /* Transformation 1 (we're actually being a bit sloppy here       and not removing the orphan from the IE list if it       can be floated inside its parent.) */    for(xs=orphans; nonNull(xs);xs=tl(xs)) {      ieList = augmentEntity(FALSE,fst(hd(xs)),snd(hd(xs)),ieList);    }  }  return ieList;}           Void fixupImportExports (ls)List ls; {    List xs;    for(xs=ls;nonNull(xs);xs=tl(xs)) {      if ( isPair(hd(xs)) && !fst(snd(hd(xs))) ) {        snd(snd(hd(xs))) = fixupIEList(snd(snd(hd(xs))));      }    }} static List local checkImportEntity(imports,exporter,isHidden,entity)List   imports; /* Accumulated list of things to import */Module exporter;Bool   isHidden;Cell   entity; { /* Entry from import/hiding list */    Bool impFound    = FALSE;    Bool isId        = isIdent(entity);    Cell subEntities = !isId ? snd(entity) : NIL;    Text t           = isId ? textOf(entity) : textOf(fst(entity));    List es          = module(exporter).exports;    Bool lookForVar  = isVar(entity);     /* In H98, a data con may be named in a 'hiding' list, so we     * have to grovel around inside each tycon looking for it.     */    Bool lookForDataCon =       isHidden &&      subEntities == NONE &&       isCon(isId ? entity : fst(entity));          /* The use of NONE heralds a dcon */    subEntities = ( (subEntities == NONE) ? NIL : subEntities);        for(; nonNull(es); es=tl(es)) {	Cell e = hd(es); /* :: Entity | (Entity, NIL|DOTDOT|[Entity]) */	if (isPair(e)) {	    Cell f = fst(e);	    if (isTycon(f)) {		if (tycon(f).text == t) {		    impFound = TRUE;		    if (!isId) {			switch (tycon(f).what) {			case NEWTYPE:			case DATATYPE:			    if (DOTDOT == subEntities) {				/* Want all dcons that are _exported_ by				   the importing module.				*/				Cell dcons;				if (snd(e) == DOTDOT) {				    dcons = tycon(f).defn;				} else {				    dcons = snd(e);				}				imports=addEntity(f,dcons,imports);			    } else if ( NIL == subEntities) {				imports=addEntity(f,NIL,imports);			    } else {				List xs = NIL;				xs = checkSubentities(xs, subEntities, tycon(f).defn,"constructor of type",t);				imports=addEntity(f,xs,imports);			    }			    break;			case SYNONYM:			case RESTRICTSYN:			    imports=addEntity(f,DOTDOT,imports);			    break;			default:;			  /* deliberate fall thru */			    }		    } else {			imports = addEntity(f,NIL,imports);		    }		    if (!lookForDataCon) break;		}		/* check the data constructors or field labels for match */		if (tycon(f).what != SYNONYM     && 		    tycon(f).what != RESTRICTSYN &&		    (lookForVar || lookForDataCon)) {		    /* The type's exported dcons/fields */		    Cell dcons;		    if (snd(e) == DOTDOT) {			dcons = tycon(f).defn;		    } else {			dcons = snd(e);		    }		    while(nonNull(dcons)) {			if (isName(hd(dcons)) && name(hd(dcons)).text == t) {			    impFound = TRUE;			    imports=addEntity(hd(dcons),NIL,imports);			    break;			}			dcons=tl(dcons);		    }		}	    } else if (isClass(f)) {		List sigs = NIL;		/* Want all members that are _exported_ by the importing module. */		if (isPair(e)) {		    if (snd(e) == DOTDOT) {			sigs = cclass(f).members;		    } else {			sigs = snd(e);		    }		}		if (cclass(f).text == t) {		    impFound = TRUE;		    if (!isId) {			if (DOTDOT == subEntities) {			    imports=addEntity(f,sigs,imports);			    return imports;			} else if ( NIL == subEntities) {			    imports=addEntity(f,NIL,imports);			} else {			    List xs = NIL;			    xs = checkSubentities(xs, subEntities, cclass(f).members,"member of class",t);			    imports=addEntity(f,xs,imports);			}		    }		    break;		}		if (!impFound && isId) {		    List xs = sigs;		    while(nonNull(xs)) {			if (isName(hd(xs)) && name(hd(xs)).text == t) {			    impFound = TRUE;			    imports=cons(hd(xs),imports);			    break;			}			xs=tl(xs);		    }		}	    } else {		internal("checkImportEntity2");	    }	} else if (isName(e)) {	    if (isId && name(e).text == t) {		impFound = TRUE;		imports=cons(e,imports);		if (!lookForDataCon) break;	    }	} else if (isTycon(e)) {	    if (isId && tycon(e).text == t) {		impFound = TRUE;		imports = addEntity(e,NIL,imports);		if (!lookForDataCon) break;	    }	} else {	    internal("checkImportEntity3");	}    }    if (!impFound) {	ERRMSG(0) "Unknown entity \"%s\" %s from module \"%s\"",                  textToStr(t), ((!isHidden) ? "imported" : "hidden"),		  textToStr(module(exporter ).text)	EEND;    }    return imports;} static List local resolveImportList(m,impList,isHidden)Module m;  /* exporting module */Cell   impList;Bool   isHidden; {    List imports = NIL;    if (DOTDOT == impList) {	List es = module(m).exports;	for(; nonNull(es); es=tl(es)) {	    Cell e = hd(es);	    if (isName(e)) {		imports = cons(e,imports);            } else {                Cell c = fst(e);                List subentities = NIL;                if ( isClass(c) ||                      (isTycon(c)                       && (tycon(c).what == DATATYPE ||                           tycon(c).what == NEWTYPE)) ) {                    if (snd(e) != DOTDOT) {                        List ys = snd(e);                        Name sub;                        while (nonNull(ys)) {                            if (isPair(hd(ys))) {                                if (nonNull(sub = findQualName(hd(ys)))) {                                  subentities = cons (sub,subentities);                                }                            } else {                                subentities = cons(hd(ys),subentities);                            }                            ys=tl(ys);                        }			subentities = rev(subentities);                    } else {                        if (isClass(c)) {                            subentities = cclass(c).members;                        } else {                            subentities = tycon(c).defn;                        }                    }                }                imports = addEntity(c,subentities,imports);            }        }	imports = rev(imports);    } else {        map2Accum(checkImportEntity,imports,m,isHidden,impList);    }    return imports;} Void checkQualImportList(importSpec)Pair importSpec; {  /* checkQualImport() has verified that the module has already been loaded;   * just locate the Module for it here & update the qualImports.   */  Module m = findModid(fst(importSpec));  fst(importSpec) = m;   checkImportList(TRUE,importSpec);} static List local addEntityPair(e,is) /* For pair (e,ls) add ls to the 'is' */                                      /* import/export list.                   */Cell e;List is; {  if (isPair(e)) {    return addEntity(fst(e),snd(e), is);  } else if (isName(e)) {      if (isClass(name(e).parent)) {        return addEntity(name(e).parent, singleton(e),is);      } else if (isTycon(name(e).parent) && isCfun(e)) {        return addEntity(name(e).parent, singleton(e),is);      } else if (isSfun(e)) {        /* a field name */        Cell p = name(e).parent;      /* the data constructor */        Cell t = name(p).parent;      /* the type constructor */        return addEntity(t, singleton(e), is);      }  }  return addEntity(e,NIL,is);} static List local augmentEntity(addNew,e,ls,is) Bool addNew;                      /* For entity e, add 'ls' to the 'is'   */Cell e;                           /* import/export list,combining it with */Cell ls;                          /* previous entries (if any.)           */List is; {     Cell ms = entityIsMember(e,is);        if (!ms) {      if (!addNew) {        return is;      } else {        if (isName(e) && (ls == NIL || ls == NONE)) {           return cons(e,is);        } else {            return cons(pair(e,ls),is);        }      }    } else {        /* concat the two lists; remove duplicates. */        if (!isPair(hd(ms)) && ls != NIL) {            hd(ms) = pair(e,ls);        } else if (ls == NIL || ls == NONE || snd(hd(ms)) == DOTDOT) {            ;        } else if (ls == DOTDOT || snd(hd(ms)) == NIL || snd(hd(ms)) == NONE) {            snd(hd(ms)) = ls;        } else {            snd(hd(ms)) = nubList(dupOnto(ls,snd(hd(ms))));        }        return is;    }} static List local addEntity(e,ls,is)Cell e;Cell ls;List is; {  return augmentEntity(TRUE,e,ls,is);} 

Lines 1–500 of 1260.