001: /*
002: * Package.java
003: *
004: * Copyright (C) 2002-2003 Peter Graves
005: * $Id: Package.java,v 1.6 2003/11/15 11:03:28 beedlem Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.lisp;
023:
024: import java.util.ArrayList;
025: import java.util.HashMap;
026: import java.util.Iterator;
027: import java.util.List;
028:
029: public final class Package extends LispObject {
030: private String name;
031:
032: private final HashMap internalSymbols = new HashMap();
033: private final HashMap externalSymbols = new HashMap();
034: private HashMap shadowingSymbols;
035: private ArrayList nicknames;
036: private final ArrayList useList = new ArrayList();
037: private ArrayList usedByList = null;
038:
039: public Package(String name) {
040: this .name = name;
041: }
042:
043: public Package(String name, int size) {
044: this .name = name;
045: }
046:
047: public LispObject typeOf() {
048: return Symbol.PACKAGE;
049: }
050:
051: public LispClass classOf() {
052: return BuiltInClass.PACKAGE;
053: }
054:
055: public LispObject typep(LispObject type) throws ConditionThrowable {
056: if (type == Symbol.PACKAGE)
057: return T;
058: if (type == BuiltInClass.PACKAGE)
059: return T;
060: return super .typep(type);
061: }
062:
063: public final String getName() {
064: return name;
065: }
066:
067: public final List getNicknames() {
068: return nicknames;
069: }
070:
071: public final synchronized boolean delete() {
072: if (name != null) {
073: Packages.deletePackage(this );
074: name = null;
075: nicknames = null;
076: return true;
077: }
078: return false;
079: }
080:
081: public final synchronized void rename(String newName,
082: LispObject newNicks) throws ConditionThrowable {
083: ArrayList arrayList = null;
084: while (newNicks != NIL) {
085: if (arrayList == null)
086: arrayList = new ArrayList();
087: arrayList.add(javaString(newNicks.car()));
088: newNicks = newNicks.cdr();
089: }
090:
091: // Remove old name and nicknames from Packages map.
092: Packages.deletePackage(this );
093:
094: // Now change the names...
095: name = newName;
096: nicknames = arrayList;
097:
098: // And add the package back.
099: Packages.addPackage(this );
100: }
101:
102: public synchronized Symbol findInternalSymbol(String name) {
103: return (Symbol) internalSymbols.get(name);
104: }
105:
106: public synchronized Symbol findExternalSymbol(String name) {
107: return (Symbol) externalSymbols.get(name);
108: }
109:
110: // Returns null if symbol is not accessible in this package.
111: public synchronized Symbol findAccessibleSymbol(String name) {
112: // Look in external and internal symbols of this package.
113: Symbol symbol = (Symbol) externalSymbols.get(name);
114: if (symbol != null)
115: return symbol;
116: symbol = (Symbol) internalSymbols.get(name);
117: if (symbol != null)
118: return symbol;
119: // Look in external symbols of used packages.
120: for (Iterator it = useList.iterator(); it.hasNext();) {
121: Package pkg = (Package) it.next();
122: symbol = pkg.findExternalSymbol(name);
123: if (symbol != null)
124: return symbol;
125: }
126: // Not found.
127: return null;
128: }
129:
130: public synchronized LispObject findSymbol(String name) {
131: final LispThread thread = LispThread.currentThread();
132: LispObject[] values = new LispObject[2];
133: // Look in external and internal symbols of this package.
134: Symbol symbol = (Symbol) externalSymbols.get(name);
135: if (symbol != null) {
136: values[0] = symbol;
137: values[1] = Keyword.EXTERNAL;
138: thread.setValues(values);
139: return symbol;
140: }
141: symbol = (Symbol) internalSymbols.get(name);
142: if (symbol != null) {
143: values[0] = symbol;
144: values[1] = Keyword.INTERNAL;
145: thread.setValues(values);
146: return symbol;
147: }
148: // Look in external symbols of used packages.
149: for (Iterator it = useList.iterator(); it.hasNext();) {
150: Package pkg = (Package) it.next();
151: symbol = pkg.findExternalSymbol(name);
152: if (symbol != null) {
153: values[0] = symbol;
154: values[1] = Keyword.INHERITED;
155: thread.setValues(values);
156: return symbol;
157: }
158: }
159: // Not found.
160: values[0] = NIL;
161: values[1] = NIL;
162: thread.setValues(values);
163: return NIL;
164: }
165:
166: // Helper function to add NIL to PACKAGE_CL.
167: public synchronized void addSymbol(Symbol symbol) {
168: Debug.assertTrue(symbol.getPackage() == this );
169: final String name = symbol.getName();
170: Debug.assertTrue(name.equals("NIL"));
171: externalSymbols.put(symbol.getName(), symbol);
172: }
173:
174: private synchronized Symbol addSymbol(String symbolName) {
175: Symbol symbol = new Symbol(symbolName, this );
176: if (this == PACKAGE_KEYWORD) {
177: symbol.setSymbolValue(symbol);
178: symbol.setConstant(true);
179: externalSymbols.put(symbolName, symbol);
180: } else
181: internalSymbols.put(symbolName, symbol);
182: return symbol;
183: }
184:
185: public synchronized Symbol addInternalSymbol(String symbolName) {
186: Symbol symbol = new Symbol(symbolName, this );
187: internalSymbols.put(symbolName, symbol);
188: return symbol;
189: }
190:
191: public synchronized Symbol addExternalSymbol(String symbolName) {
192: Symbol symbol = new Symbol(symbolName, this );
193: externalSymbols.put(symbolName, symbol);
194: return symbol;
195: }
196:
197: public synchronized void addInitialExports(String[] names) {
198: for (int i = names.length; i-- > 0;) {
199: String symbolName = names[i];
200: // There shouldn't be any internal symbols in the COMMON-LISP
201: // package.
202: Debug.assertTrue(internalSymbols.get(symbolName) == null);
203: // The symbol in question may have been exported already. If we
204: // replace an existing symbol, we'll lose any information that
205: // might be associated with it. So we check first...
206: if (externalSymbols.get(symbolName) == null)
207: externalSymbols.put(symbolName, new Symbol(symbolName,
208: this ));
209: }
210: }
211:
212: public synchronized Symbol intern(String symbolName) {
213: // Look in external and internal symbols of this package.
214: Symbol symbol = (Symbol) externalSymbols.get(symbolName);
215: if (symbol != null)
216: return symbol;
217: symbol = (Symbol) internalSymbols.get(symbolName);
218: if (symbol != null)
219: return symbol;
220: // Look in external symbols of used packages.
221: for (Iterator it = useList.iterator(); it.hasNext();) {
222: Package pkg = (Package) it.next();
223: symbol = pkg.findExternalSymbol(symbolName);
224: if (symbol != null)
225: return symbol;
226: }
227: // Not found.
228: return addSymbol(symbolName);
229: }
230:
231: public synchronized Symbol intern(String name, LispThread thread) {
232: LispObject[] values = new LispObject[2];
233: // Look in external and internal symbols of this package.
234: Symbol symbol = (Symbol) externalSymbols.get(name);
235: if (symbol != null) {
236: values[0] = symbol;
237: values[1] = Keyword.EXTERNAL;
238: thread.setValues(values);
239: return symbol;
240: }
241: symbol = (Symbol) internalSymbols.get(name);
242: if (symbol != null) {
243: values[0] = symbol;
244: values[1] = Keyword.INTERNAL;
245: thread.setValues(values);
246: return symbol;
247: }
248: // Look in external symbols of used packages.
249: for (Iterator it = useList.iterator(); it.hasNext();) {
250: Package pkg = (Package) it.next();
251: symbol = pkg.findExternalSymbol(name);
252: if (symbol != null) {
253: values[0] = symbol;
254: values[1] = Keyword.INHERITED;
255: thread.setValues(values);
256: return symbol;
257: }
258: }
259: // Not found.
260: symbol = addSymbol(name);
261: values[0] = symbol;
262: values[1] = NIL;
263: thread.setValues(values);
264: return symbol;
265: }
266:
267: public synchronized LispObject unintern(Symbol symbol)
268: throws ConditionThrowable {
269: final String symbolName = symbol.getName();
270: final boolean shadow;
271: if (shadowingSymbols != null
272: && shadowingSymbols.get(symbolName) == symbol)
273: shadow = true;
274: else
275: shadow = false;
276: if (shadow) {
277: // Check for conflicts that might be exposed in used package list
278: // if we remove the shadowing symbol.
279: Symbol sym = null;
280: for (Iterator it = useList.iterator(); it.hasNext();) {
281: Package pkg = (Package) it.next();
282: Symbol s = pkg.findExternalSymbol(symbolName);
283: if (s != null) {
284: if (sym == null)
285: sym = s;
286: else if (sym != s) {
287: StringBuffer sb = new StringBuffer(
288: "uninterning the symbol ");
289: sb.append(symbol.getQualifiedName());
290: sb.append(" causes a name conflict between ");
291: sb.append(sym.getQualifiedName());
292: sb.append(" and ");
293: sb.append(s.getQualifiedName());
294: throw new ConditionThrowable(new PackageError(
295: sb.toString()));
296: }
297: }
298: }
299: }
300: // Reaching here, it's OK to remove the symbol.
301: if (internalSymbols.get(symbolName) == symbol) {
302: internalSymbols.remove(symbolName);
303: } else if (externalSymbols.get(symbolName) == symbol) {
304: externalSymbols.remove(symbolName);
305: } else {
306: // Not found.
307: return NIL;
308: }
309: if (shadow) {
310: Debug.assertTrue(shadowingSymbols != null);
311: shadowingSymbols.remove(symbolName);
312: }
313: if (symbol.getPackage() == this )
314: symbol.setPackage(NIL);
315: return T;
316: }
317:
318: public synchronized void importSymbol(Symbol symbol)
319: throws ConditionThrowable {
320: if (symbol.getPackage() == this )
321: return; // Nothing to do.
322: Symbol sym = findAccessibleSymbol(symbol.getName());
323: if (sym != null && sym != symbol) {
324: StringBuffer sb = new StringBuffer("the symbol ");
325: sb.append(sym.getQualifiedName());
326: sb.append(" is already accessible in package ");
327: sb.append(name);
328: throw new ConditionThrowable(
329: new PackageError(sb.toString()));
330: }
331: internalSymbols.put(symbol.getName(), symbol);
332: }
333:
334: public synchronized void export(Symbol symbol)
335: throws ConditionThrowable {
336: final String symbolName = symbol.getName();
337: if (symbol.getPackage() != this ) {
338: Symbol sym = findAccessibleSymbol(symbolName);
339: if (sym == null) {
340: StringBuffer sb = new StringBuffer("the symbol ");
341: sb.append(symbol.getQualifiedName());
342: sb.append(" is not accessible in package ");
343: sb.append(name);
344: throw new ConditionThrowable(new PackageError(sb
345: .toString()));
346: }
347: if (sym != symbol) {
348: // Conflict.
349: StringBuffer sb = new StringBuffer("the symbol ");
350: sb.append(sym.getQualifiedName());
351: sb.append(" is already accessible in package ");
352: sb.append(name);
353: throw new ConditionThrowable(new PackageError(sb
354: .toString()));
355: }
356: internalSymbols.put(symbolName, symbol);
357: }
358: if (internalSymbols.get(symbolName) == symbol) {
359: // Found existing internal symbol in this package.
360: if (usedByList != null) {
361: for (Iterator it = usedByList.iterator(); it.hasNext();) {
362: Package pkg = (Package) it.next();
363: Symbol sym = pkg.findAccessibleSymbol(symbolName);
364: if (sym != null && sym != symbol) {
365: if (pkg.shadowingSymbols != null
366: && pkg.shadowingSymbols.get(symbolName) == sym) {
367: ; // OK.
368: } else {
369: StringBuffer sb = new StringBuffer(
370: "the symbol ");
371: sb.append(sym.getQualifiedName());
372: sb
373: .append(" is already accessible in package ");
374: sb.append(pkg.getName());
375: throw new ConditionThrowable(new LispError(
376: sb.toString()));
377: }
378: }
379: }
380: }
381: // No conflicts.
382: internalSymbols.remove(symbolName);
383: externalSymbols.put(symbolName, symbol);
384: return;
385: }
386: if (externalSymbols.get(symbolName) == symbol) {
387: // Symbol is already exported; there's nothing to do.
388: return;
389: }
390: StringBuffer sb = new StringBuffer("the symbol ");
391: sb.append(symbol.getQualifiedName());
392: sb.append(" is not accessible in package ");
393: sb.append(name);
394: throw new ConditionThrowable(new PackageError(sb.toString()));
395: }
396:
397: public synchronized void unexport(Symbol symbol)
398: throws ConditionThrowable {
399: final String symbolName = symbol.getName();
400: if (symbol.getPackage() == this ) {
401: if (externalSymbols.get(symbolName) == symbol) {
402: externalSymbols.remove(symbolName);
403: internalSymbols.put(symbolName, symbol);
404: }
405: } else {
406: // Signal an error if symbol is not accessible.
407: for (Iterator it = useList.iterator(); it.hasNext();) {
408: Package pkg = (Package) it.next();
409: if (pkg.findExternalSymbol(symbolName) == symbol)
410: return; // OK.
411: }
412: StringBuffer sb = new StringBuffer("the symbol ");
413: sb.append(symbol.getQualifiedName());
414: sb.append(" is not accessible in package ");
415: sb.append(name);
416: throw new ConditionThrowable(
417: new PackageError(sb.toString()));
418: }
419: }
420:
421: public synchronized void shadow(String symbolName)
422: throws ConditionThrowable {
423: Symbol symbol = (Symbol) externalSymbols.get(symbolName);
424: if (symbol != null)
425: return;
426: symbol = (Symbol) internalSymbols.get(symbolName);
427: if (symbol != null)
428: return;
429: if (shadowingSymbols != null) {
430: if (shadowingSymbols.get(symbolName) != null)
431: return;
432: } else
433: shadowingSymbols = new HashMap();
434:
435: symbol = new Symbol(symbolName, this );
436: internalSymbols.put(symbolName, symbol);
437: shadowingSymbols.put(symbolName, symbol);
438: }
439:
440: public synchronized void shadowingImport(Symbol symbol)
441: throws ConditionThrowable {
442: LispObject where = NIL;
443: final String symbolName = symbol.getName();
444: Symbol sym = (Symbol) externalSymbols.get(symbolName);
445: if (sym != null) {
446: where = Keyword.EXTERNAL;
447: } else {
448: sym = (Symbol) internalSymbols.get(symbolName);
449: if (sym != null) {
450: where = Keyword.INTERNAL;
451: } else {
452: // Look in external symbols of used packages.
453: for (Iterator it = useList.iterator(); it.hasNext();) {
454: Package pkg = (Package) it.next();
455: sym = pkg.findExternalSymbol(symbolName);
456: if (sym != null) {
457: where = Keyword.INHERITED;
458: break;
459: }
460: }
461: }
462: }
463: if (sym != null) {
464: if (where == Keyword.INTERNAL || where == Keyword.EXTERNAL) {
465: if (sym != symbol) {
466: if (shadowingSymbols != null)
467: shadowingSymbols.remove(symbolName);
468: unintern(sym);
469: }
470: }
471: }
472: internalSymbols.put(symbolName, symbol);
473: if (shadowingSymbols == null)
474: shadowingSymbols = new HashMap();
475: Debug.assertTrue(shadowingSymbols.get(symbolName) == null);
476: shadowingSymbols.put(symbolName, symbol);
477: }
478:
479: // Adds pkg to the use list of this package.
480: public void usePackage(Package pkg) {
481: if (!useList.contains(pkg)) {
482: useList.add(pkg);
483: // Add this package to the used-by list of pkg.
484: if (pkg.usedByList != null)
485: Debug.assertTrue(!pkg.usedByList.contains(this ));
486: if (pkg.usedByList == null)
487: pkg.usedByList = new ArrayList();
488: pkg.usedByList.add(this );
489: }
490: }
491:
492: public void unusePackage(Package pkg) {
493: if (useList.contains(pkg)) {
494: useList.remove(pkg);
495: Debug.assertTrue(pkg.usedByList != null);
496: Debug.assertTrue(pkg.usedByList.contains(this ));
497: pkg.usedByList.remove(this );
498: }
499: }
500:
501: public final void addNickname(String s) throws ConditionThrowable {
502: // This call will throw an error if there's a naming conflict.
503: Packages.addNickname(this , s);
504:
505: if (nicknames != null) {
506: if (nicknames.contains(s))
507: return; // Nothing to do.
508: } else
509: nicknames = new ArrayList();
510:
511: nicknames.add(s);
512: }
513:
514: public String getNickname() {
515: if (nicknames != null && nicknames.size() > 0)
516: return (String) nicknames.get(0);
517: return null;
518: }
519:
520: public LispObject packageNicknames() {
521: LispObject list = NIL;
522: if (nicknames != null) {
523: for (int i = nicknames.size(); i-- > 0;) {
524: String nickname = (String) nicknames.get(i);
525: list = new Cons(new LispString(nickname), list);
526: }
527: }
528: return list;
529: }
530:
531: public LispObject getUseList() {
532: LispObject list = NIL;
533: for (Iterator it = useList.iterator(); it.hasNext();) {
534: Package pkg = (Package) it.next();
535: list = new Cons(pkg, list);
536: }
537: return list;
538: }
539:
540: public boolean uses(LispObject pkg) {
541: return useList.contains(pkg);
542: }
543:
544: public LispObject getUsedByList() {
545: LispObject list = NIL;
546: if (usedByList != null) {
547: for (Iterator it = usedByList.iterator(); it.hasNext();) {
548: Package pkg = (Package) it.next();
549: list = new Cons(pkg, list);
550: }
551: }
552: return list;
553: }
554:
555: public LispObject getShadowingSymbols() {
556: LispObject list = NIL;
557: if (shadowingSymbols != null) {
558: for (Iterator it = shadowingSymbols.values().iterator(); it
559: .hasNext();) {
560: Symbol symbol = (Symbol) it.next();
561: list = new Cons(symbol, list);
562: }
563: }
564: return list;
565: }
566:
567: public synchronized List getExternalSymbols() {
568: ArrayList list = new ArrayList();
569: for (Iterator it = externalSymbols.values().iterator(); it
570: .hasNext();) {
571: Symbol symbol = (Symbol) it.next();
572: list.add(symbol);
573: }
574: return list;
575: }
576:
577: public synchronized List getAccessibleSymbols() {
578: ArrayList list = new ArrayList();
579: for (Iterator it = internalSymbols.values().iterator(); it
580: .hasNext();) {
581: Symbol symbol = (Symbol) it.next();
582: list.add(symbol);
583: }
584: for (Iterator it = externalSymbols.values().iterator(); it
585: .hasNext();) {
586: Symbol symbol = (Symbol) it.next();
587: list.add(symbol);
588: }
589: for (Iterator packageIter = useList.iterator(); packageIter
590: .hasNext();) {
591: Package pkg = (Package) packageIter.next();
592: for (Iterator it = pkg.externalSymbols.values().iterator(); it
593: .hasNext();) {
594: Symbol symbol = (Symbol) it.next();
595: if (shadowingSymbols == null
596: || shadowingSymbols.get(symbol.getName()) == null)
597: list.add(symbol);
598: }
599: }
600: return list;
601: }
602:
603: public synchronized LispObject PACKAGE_INTERNAL_SYMBOLS() {
604: LispObject list = NIL;
605: for (Iterator it = internalSymbols.values().iterator(); it
606: .hasNext();) {
607: Symbol symbol = (Symbol) it.next();
608: list = new Cons(symbol, list);
609: }
610: return list;
611: }
612:
613: public synchronized LispObject PACKAGE_EXTERNAL_SYMBOLS() {
614: LispObject list = NIL;
615: for (Iterator it = externalSymbols.values().iterator(); it
616: .hasNext();) {
617: Symbol symbol = (Symbol) it.next();
618: list = new Cons(symbol, list);
619: }
620: return list;
621: }
622:
623: public synchronized LispObject PACKAGE_INHERITED_SYMBOLS() {
624: LispObject list = NIL;
625: for (Iterator packageIter = useList.iterator(); packageIter
626: .hasNext();) {
627: Package pkg = (Package) packageIter.next();
628: for (Iterator it = pkg.externalSymbols.values().iterator(); it
629: .hasNext();) {
630: Symbol symbol = (Symbol) it.next();
631: if (shadowingSymbols != null
632: && shadowingSymbols.get(symbol.getName()) != null)
633: continue;
634: if (externalSymbols.get(symbol.getName()) == symbol)
635: continue;
636: list = new Cons(symbol, list);
637: }
638: }
639: return list;
640: }
641:
642: public synchronized LispObject getSymbols() {
643: LispObject list = NIL;
644: for (Iterator it = internalSymbols.values().iterator(); it
645: .hasNext();) {
646: Symbol symbol = (Symbol) it.next();
647: list = new Cons(symbol, list);
648: }
649: for (Iterator it = externalSymbols.values().iterator(); it
650: .hasNext();) {
651: Symbol symbol = (Symbol) it.next();
652: list = new Cons(symbol, list);
653: }
654: return list;
655: }
656:
657: public synchronized Symbol[] symbols() {
658: Symbol[] array = new Symbol[internalSymbols.size()
659: + externalSymbols.size()];
660: int i = 0;
661: for (Iterator it = internalSymbols.values().iterator(); it
662: .hasNext();) {
663: Symbol symbol = (Symbol) it.next();
664: array[i++] = symbol;
665: }
666: for (Iterator it = externalSymbols.values().iterator(); it
667: .hasNext();) {
668: Symbol symbol = (Symbol) it.next();
669: array[i++] = symbol;
670: }
671: return array;
672: }
673:
674: public String toString() {
675: StringBuffer sb = new StringBuffer("#<The ");
676: sb.append(name);
677: sb.append(" package>");
678: return sb.toString();
679: }
680: }
|