001: package gnu.kawa.lispexpr;
002:
003: import gnu.mapping.*;
004: import gnu.lists.*;
005:
006: /** Implementa A Common Lisp "package" value.
007: * Far from complete. */
008:
009: public class LispPackage extends Namespace {
010: /** The set of exported symbols.
011: * This is on of the packages in importing.
012: */
013: Namespace exported;
014:
015: LList shadowingSymbols = LList.Empty;
016:
017: /** Namespaces that this Namespace imports or uses.
018: * These are the <code>imported</code> fields of the
019: * <code>NamespaceUse</code>, chained using <code>nextImported</code> fields.
020: * The CommonLisp "uses" list. */
021: NamespaceUse imported;
022: /** Namespaces that import/use this namespace.
023: * The CommonLisp "used-by" list. */
024: NamespaceUse importing;
025:
026: /*
027: public static void use (Namespace importing, Namespace imported)
028: {
029: synchronized (masterLock)
030: {
031: // FIXME check conflicts.
032: NamespaceUse use = new NamespaceUse();
033: use.nextImporting = imported.importing;
034: imported.importing = use;
035: use.nextImported = importing.imported;
036: importing.imported = use;
037: }
038: }
039: */
040:
041: public Symbol lookup(String name, int hash, boolean create) {
042: Symbol sym = exported.lookup(name, hash, false);
043: if (sym != null)
044: return sym;
045: sym = lookupInternal(name, hash);
046: if (sym != null)
047: return sym;
048:
049: // Do we need to synchronize on masterLock as well? FIXME
050: for (NamespaceUse used = imported; used != null; used = used.nextImported) {
051: sym = lookup(name, hash, false);
052: if (sym != null)
053: return sym;
054: }
055:
056: if (create)
057: return add(new Symbol(this , name), hash);
058: else
059: return null;
060: }
061:
062: public Symbol lookupPresent(String name, int hash, boolean intern) {
063: Symbol sym = exported.lookup(name, hash, false);
064: if (sym == null)
065: sym = super .lookup(name, hash, intern);
066: return sym;
067: }
068:
069: public boolean isPresent(String name) {
070: return lookupPresent(name, name.hashCode(), false) != null;
071: }
072:
073: public boolean unintern(Symbol symbol) {
074: String name = symbol.getName();
075: int hash = name.hashCode();
076: if (exported.lookup(name, hash, false) == symbol)
077: exported.remove(symbol);
078: else if (super .lookup(name, hash, false) == symbol)
079: super .remove(symbol);
080: else
081: return false;
082: symbol.setNamespace(null);
083: if (removeFromShadowingSymbols(symbol)) {
084: // FIXME check use list: If thee are two or more different symbols
085: // named 'name' in used packages, then signal a conflict.
086: }
087: return true;
088: }
089:
090: private void addToShadowingSymbols(Symbol sym) {
091: for (Object s = shadowingSymbols; s != LList.Empty;) {
092: Pair p = (Pair) s;
093: if (p.car == sym)
094: return;
095: s = p.cdr;
096: }
097: shadowingSymbols = new Pair(sym, shadowingSymbols);
098: }
099:
100: private boolean removeFromShadowingSymbols(Symbol sym) {
101: Pair prev = null;
102: for (Object s = shadowingSymbols; s != LList.Empty;) {
103: Pair p = (Pair) s;
104: s = p.cdr;
105: if (p.car == sym) {
106: if (prev == null)
107: shadowingSymbols = (LList) s;
108: else
109: prev.cdr = s;
110: return true;
111: }
112: prev = p;
113: }
114: return false;
115: }
116:
117: /** The core of the Common Lisp shadow function. */
118: public void shadow(String name) {
119: Symbol sym = lookupPresent(name, name.hashCode(), true);
120: addToShadowingSymbols(sym);
121: }
122:
123: public void shadowingImport(Symbol symbol) {
124: String name = symbol.getName();
125: int hash = name.hashCode();
126: Symbol old = lookupPresent(name, name.hashCode(), false);
127: if (old != null && old != symbol)
128: unintern(old);
129: addToShadowingSymbols(symbol);
130: }
131:
132: }
133:
134: /** This is used to implement two linked lists.
135: * For performance they're combined into one object. */
136: class NamespaceUse {
137: Namespace imported;
138: NamespaceUse nextImported;
139:
140: Namespace importing;
141: NamespaceUse nextImporting;
142: }
|