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