LispPackage.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. package gnu.kawa.lispexpr;
  2. import gnu.commonlisp.lang.CommonLisp;
  3. import gnu.mapping.*;
  4. import gnu.lists.*;
  5. import java.util.Iterator;
  6. import java.util.Stack;
  7. import gnu.expr.Keyword;
  8. /** Implement a Common Lisp "package" value.
  9. *
  10. * @author Per Bothner
  11. * @author Charles Turner
  12. */
  13. public class LispPackage extends Namespace
  14. {
  15. /** The set of exported symbols.
  16. * This is one of the packages in importing.
  17. */
  18. public Namespace exported = new Namespace();
  19. public void setExportedNamespace (Namespace exp)
  20. {
  21. this.exported = exp;
  22. }
  23. /** The nicknames for this package. */
  24. LList nicknames = LList.Empty;
  25. private static final Object masterLock = new Object();
  26. LList shadowingSymbols = LList.Empty;
  27. public LList getShadowingSymbols()
  28. {
  29. return shadowingSymbols;
  30. }
  31. public static final LispPackage CLNamespace =
  32. (LispPackage) valueOf("COMMON-LISP");
  33. /* Symbols in the KeywordNamespace have type gnu.expr.Keyword. */
  34. public static final LispPackage KeywordNamespace =
  35. (LispPackage) valueOf("KEYWORD");
  36. /* Symbols in the KawaNamespace have type SimpleSymbol. */
  37. public static final LispPackage KawaNamespace =
  38. (LispPackage) valueOf("KAWA");
  39. /* The class namespace is used to resolve Java class names in the context of
  40. types. The user would specific class::|java.lang.String| if she wanted to
  41. use java.lang.String as a type name. This avoids various ambiguities. */
  42. public static final LispPackage ClassNamespace = (LispPackage) valueOf("CLASS");
  43. /** Common Lisp {@code *package*} special. */
  44. public static ThreadLocation<LispPackage> currentPackage
  45. = new ThreadLocation<LispPackage>("*package*");
  46. static
  47. {
  48. nsTable.put("CL", CLNamespace);
  49. CLNamespace.nicknames = Pair.make("CL", CLNamespace.nicknames);
  50. /* Package CL inherits from this package to facilitate cross language
  51. * lookups */
  52. KawaNamespace.setExportedNamespace(EmptyNamespace);
  53. KeywordNamespace.setExportedNamespace(Keyword.keywordNamespace);
  54. LispPackage.use(CLNamespace, KawaNamespace); // FIXME: Should be used from CL-USER
  55. LispPackage.use(CLNamespace, ClassNamespace);
  56. currentPackage.setGlobal(CLNamespace);
  57. }
  58. /** Namespaces that this Namespace imports or uses.
  59. * These are the <code>imported</code> fields of the
  60. * <code>NamespaceUse</code>, chained using <code>nextImported</code> fields.
  61. * The CommonLisp "uses" list. */
  62. NamespaceUse imported;
  63. /** Namespaces that import/use this namespace.
  64. * The CommonLisp "used-by" list. */
  65. NamespaceUse importing;
  66. /** Used for the CL PACKAGE-USE-LIST function. */
  67. public static LList pkgUsesList(LispPackage lp)
  68. {
  69. LList uses = LList.Empty;
  70. NamespaceUse it = lp.imported;
  71. while (it != null) {
  72. uses = Pair.make(it.imported, uses);
  73. it = it.nextImported;
  74. }
  75. return uses;
  76. }
  77. /** Used for the CL PACKAGE-USED-BY-LIST function */
  78. public static LList pkgUsedByList(LispPackage lp)
  79. {
  80. LList usedby = LList.Empty;
  81. NamespaceUse it = lp.importing;
  82. while (it != null) {
  83. usedby = Pair.make(it.importing, usedby);
  84. it = it.nextImporting;
  85. }
  86. return usedby;
  87. }
  88. public static void addNickNames(LispPackage name, LList nicks)
  89. {
  90. synchronized (nsTable)
  91. {
  92. for (Object nick : nicks) {
  93. name.nicknames = Pair.make((String) nick, name.nicknames);
  94. nsTable.put((String) nick, name);
  95. }
  96. }
  97. }
  98. public static void usePackages (LList importees, LispPackage importer)
  99. {
  100. for (Object usePkg : importees)
  101. {
  102. LispPackage lp;
  103. if (usePkg instanceof Symbol)
  104. lp = (LispPackage) LispPackage.valueOfNoCreate(((Symbol) usePkg).getName());//uc
  105. else if (usePkg instanceof LispPackage)
  106. lp = (LispPackage) usePkg;
  107. else
  108. lp = (LispPackage) LispPackage.valueOfNoCreate((String) usePkg);
  109. if (lp != null)
  110. {
  111. use(importer, lp);
  112. }
  113. else
  114. {
  115. throw new RuntimeException("The name " + usePkg + " does not designate any package");
  116. }
  117. }
  118. }
  119. public static LispPackage makeLispPackage (Object name, LList nicks,
  120. LList used)
  121. {
  122. LispPackage newpack = (LispPackage) LispPackage.valueOf((String) name);
  123. addNickNames(newpack, nicks);
  124. usePackages(used, newpack);
  125. return newpack;
  126. }
  127. /** Look up a given package in the {@link Namespace} map.
  128. *
  129. * This method creates a new Lisp package in the namespace if it does not
  130. * already exist.
  131. *
  132. * @param name The name of the package to look up.
  133. *
  134. * @return The {@link LispPackage} named by {@code name} or {@code null} if a
  135. * {@link Namespace} is already named by {@code name} but is not a lisp
  136. * package.
  137. */
  138. public static LispPackage valueOf (String name)
  139. {
  140. if (name == null)
  141. name = "";
  142. synchronized (nsTable) {
  143. Namespace ns = (Namespace) nsTable.get(name);
  144. if (ns != null)
  145. return (LispPackage) ns;
  146. ns = new LispPackage();
  147. ns.setName(name.intern());
  148. Namespace.nsTable.put(name, ns);
  149. return (LispPackage) ns;
  150. }
  151. }
  152. public static Namespace valueOfNoCreate (String name)
  153. {
  154. return (LispPackage) Namespace.valueOfNoCreate(name);
  155. }
  156. public Values.Values2 findSymbol (Object name)
  157. {
  158. String sname = name.toString();
  159. Symbol sym = exported.lookup(sname);
  160. if (sym != null)
  161. {
  162. return Values.values2(sym, CommonLisp.externalKeyword);
  163. }
  164. sym = lookupInternal(sname, sname.hashCode());
  165. if (sym != null)
  166. {
  167. return Values.values2(sym, CommonLisp.internalKeyword);
  168. }
  169. // It's not an exported or an imported symbol, let's check the inheritance
  170. // chain.
  171. NamespaceUse U = imported;
  172. while (U != null)
  173. {
  174. if (U.imported == LispPackage.KawaNamespace)
  175. sym = U.imported.exported.lookup(sname.toLowerCase());
  176. else
  177. sym = U.imported.exported.lookup(sname);
  178. if (sym != null)
  179. {
  180. return Values.values2(sym, CommonLisp.inheritedKeyword);
  181. }
  182. U = U.nextImported;
  183. }
  184. return Values.values2(CommonLisp.FALSE, CommonLisp.FALSE);
  185. }
  186. /** Export a list of symbols from a package, checking for conflicts.
  187. *
  188. * @param syms The list of symbols to export.
  189. * @param pkg The package to export the symbols from.
  190. *
  191. */
  192. public static void exportPkg (LList syms, LispPackage pkg)
  193. {
  194. Stack<Symbol> validSyms = new Stack<Symbol>();
  195. Iterator symiter = syms.getIterator();
  196. Symbol s;
  197. Values v;
  198. while (symiter.hasNext())
  199. {
  200. s = (Symbol) symiter.next();
  201. v = pkg.findSymbol(s.getName());//uc
  202. if (v.get(1) != CommonLisp.FALSE
  203. && !validSyms.contains(s))
  204. {
  205. validSyms.push(s);
  206. }
  207. }
  208. NamespaceUse usedBy = pkg.imported;
  209. symiter = syms.getIterator();
  210. while (symiter.hasNext())
  211. {
  212. s = (Symbol) symiter.next();
  213. String sname = s.getName();//uc
  214. while (usedBy != null)
  215. {
  216. v = usedBy.imported.findSymbol(sname);
  217. if (v.get(1) != CommonLisp.FALSE
  218. && v.get(0) != s
  219. && !usedBy.imported.shadowingSymbols.contains(v.get(0)))
  220. {
  221. // name conflict in usedBy.imported! Correctable, ask user
  222. // which name to nuke.
  223. signal("Name conflict from package " + usedBy.imported + "on symbol"
  224. + s);
  225. }
  226. usedBy = usedBy.nextImported;
  227. }
  228. }
  229. // Check that all symbols are accessible. If not, ask to import them.
  230. Stack<Symbol> missing = new Stack<Symbol>();
  231. // syms accessible in the inheritance chain, but not in this package
  232. Stack<Symbol> imports = new Stack<Symbol>();
  233. symiter = syms.getIterator();
  234. while (symiter.hasNext())
  235. {
  236. s = (Symbol) symiter.next();
  237. v = pkg.findSymbol(s.getName());//uc
  238. if ((v.get(1) == CommonLisp.FALSE)
  239. && (!(v.get(0).hashCode() == s.hashCode())))
  240. {
  241. missing.push(s);
  242. }
  243. else if (v.get(1) == KeywordNamespace.valueOf("inherited"))
  244. {
  245. imports.push(s);
  246. }
  247. }
  248. if (!missing.isEmpty())
  249. {
  250. // correctable error, ask user if they want ot import these
  251. // missing symbols into the package
  252. signal("The following symbols are missing: " + missing.toString());
  253. }
  254. while (!imports.isEmpty())
  255. {
  256. Symbol sym = imports.pop();
  257. pkg.exported.add(sym, sym.hashCode());
  258. }
  259. while (!validSyms.isEmpty())
  260. {
  261. s = validSyms.pop();
  262. pkg.remove(s); // remove internal
  263. pkg.exported.add(s, s.hashCode()); // add to external
  264. }
  265. }
  266. /**
  267. * Import a list of symbols into the internal table of a package.
  268. *
  269. * This method checks for conflicts, and should in the future allow the user
  270. * to shadow import any conflicts.
  271. *
  272. * @param syms the list of symbols to import.
  273. * @param pkg the package to import into.
  274. */
  275. public static void importPkg (LList syms, LispPackage pkg)
  276. {
  277. Stack<Symbol> validSyms = new Stack<Symbol>();
  278. Iterator symiter = syms.getIterator();
  279. Symbol s;
  280. Values v;
  281. while (symiter.hasNext())
  282. {
  283. s = (Symbol) symiter.next();
  284. v = pkg.findSymbol(s.getName());
  285. if (v.get(1) == CommonLisp.FALSE)
  286. {
  287. Iterator symiter2 = syms.getIterator();
  288. boolean found = false;
  289. while (symiter2.hasNext())
  290. {
  291. Symbol s2 = (Symbol) symiter2.next();
  292. if (s.getName().equals(s2.getName()))
  293. {
  294. if (s != s2)
  295. {
  296. validSyms.remove(s2);
  297. // name conflict
  298. signal("Symbol " + s2 + " conflicts with this package.");
  299. }
  300. }
  301. }
  302. if (!found)
  303. {
  304. validSyms.push(s);
  305. }
  306. }
  307. else if (v.get(0) != s)
  308. {
  309. // name conflict
  310. signal("Symbol " + v.get(0) + " conflicts in this package");
  311. }
  312. else if (v.get(1) == KeywordNamespace.valueOf("inherited"))
  313. {
  314. validSyms.add(s);
  315. }
  316. }
  317. while (!validSyms.isEmpty())
  318. {
  319. Symbol sym = validSyms.pop();
  320. pkg.add(sym, sym.hashCode());
  321. }
  322. // make any uninterned symbols owned by PKG
  323. symiter = syms.getIterator();
  324. while (symiter.hasNext())
  325. {
  326. s = (Symbol) symiter.next();
  327. if (s.getNamespace() == null)
  328. {
  329. s.setNamespace(pkg);
  330. }
  331. }
  332. }
  333. /**
  334. * The list of symbols managed by a given namespace.
  335. *
  336. * @param ns The namespace whose symbol table we query
  337. * @return The list of symbols managed by the given namespace.
  338. */
  339. public LList allSymbols (Namespace ns)
  340. {
  341. LList res = LList.Empty;
  342. java.util.Iterator symNameIter = ns.entrySet().iterator();
  343. while (symNameIter.hasNext())
  344. {
  345. res = Pair.make(symNameIter.next(), res);
  346. }
  347. return res;
  348. }
  349. /**
  350. * The list of symbols exported from this package.
  351. *
  352. * @return A list of the the exported symbols from the current package.
  353. *
  354. */
  355. public LList allExternalSymbols ()
  356. {
  357. return allSymbols(this.exported);
  358. }
  359. /**
  360. * The list of symbols interned into this package.
  361. *
  362. * @return A list of the interned symbols in this package.
  363. */
  364. public LList allInternalSymbols ()
  365. {
  366. return allSymbols(this);
  367. }
  368. public static void use (LispPackage importing, LispPackage imported)
  369. {
  370. synchronized (masterLock)
  371. {
  372. // FIXME check conflicts.
  373. NamespaceUse use = new NamespaceUse();
  374. use.nextImporting = imported.importing;
  375. use.importing = importing;
  376. imported.importing = use;
  377. use.nextImported = importing.imported;
  378. use.imported = imported;
  379. importing.imported = use;
  380. }
  381. }
  382. @Override
  383. public Symbol lookup(String name, int hash, boolean create)
  384. {
  385. Symbol sym = exported.lookup(name, hash, false);
  386. if (sym != null)
  387. return sym;
  388. sym = lookupInternal(name, hash);
  389. if (sym != null)
  390. return sym;
  391. // Do we need to synchronize on masterLock as well? FIXME
  392. for (NamespaceUse used = imported; used != null;
  393. used = used.nextImported)
  394. {
  395. sym = used.imported.exported.lookup(name, hash, false);
  396. if (sym != null)
  397. return sym;
  398. }
  399. if (create)
  400. return createSymbol (name, hash); // Optimization
  401. else
  402. return null;
  403. }
  404. public Symbol lookupPresent (String name, int hash, boolean intern)
  405. {
  406. Symbol sym = exported.lookup(name, hash, false);
  407. if (sym == null)
  408. sym = super.lookup(name, hash, intern);
  409. return sym;
  410. }
  411. public boolean isPresent (String name)
  412. {
  413. return lookupPresent(name, name.hashCode(), false) != null;
  414. }
  415. public boolean unintern (Symbol symbol)
  416. {
  417. String name = symbol.getName();
  418. int hash = name.hashCode();
  419. if (exported.lookup(name, hash, false) == symbol)
  420. exported.remove(symbol);
  421. else if (super.lookup(name, hash, false) == symbol)
  422. super.remove(symbol);
  423. else
  424. return false;
  425. symbol.setNamespace(null);
  426. if (removeFromShadowingSymbols(symbol))
  427. {
  428. // FIXME check use list: If thee are two or more different symbols
  429. // named 'name' in used packages, then signal a conflict.
  430. }
  431. return true;
  432. }
  433. private void addToShadowingSymbols (Symbol sym)
  434. {
  435. for (Object s = shadowingSymbols; s != LList.Empty; )
  436. {
  437. Pair p = (Pair) s;
  438. if (p.getCar() == sym)
  439. return;
  440. s = p.getCdr();
  441. }
  442. shadowingSymbols = new Pair(sym, shadowingSymbols);
  443. }
  444. private boolean removeFromShadowingSymbols (Symbol sym)
  445. {
  446. Pair prev = null;
  447. for (Object s = shadowingSymbols; s != LList.Empty; )
  448. {
  449. Pair p = (Pair) s;
  450. s = p.getCdr();
  451. if (p.getCar() == sym)
  452. {
  453. if (prev == null)
  454. shadowingSymbols = (LList) s;
  455. else
  456. prev.setCdr(s);
  457. return true;
  458. }
  459. prev = p;
  460. }
  461. return false;
  462. }
  463. /** The core of the Common Lisp shadow function. */
  464. public void shadow (String name)
  465. {
  466. Symbol sym = lookupPresent(name, name.hashCode(), true);
  467. addToShadowingSymbols(sym);
  468. }
  469. public void shadowingImport (Symbol symbol)
  470. {
  471. String name = symbol.getName();
  472. int hash = name.hashCode();
  473. Symbol old = lookupPresent(name, name.hashCode(), false);
  474. if (old != null && old != symbol)
  475. unintern(old);
  476. addToShadowingSymbols(symbol);
  477. }
  478. private Symbol createSymbol(String name, int hash) {
  479. if (this == KeywordNamespace) return Keyword.make(name);
  480. if (this == KawaNamespace) return Symbol.valueOf(name);
  481. return add(Symbol.makeUninterned(name, this), hash);
  482. }
  483. public static boolean keywordp (Object x) {
  484. return x instanceof Keyword;
  485. }
  486. public static Object symbolPackage (Object x) {
  487. Object nil = CommonLisp.FALSE;
  488. if (x == nil) return CLNamespace;
  489. else if (x instanceof Symbol) {
  490. Namespace ns = ((Symbol)x).getNamespace();
  491. if (ns instanceof LispPackage) return (LispPackage)ns;
  492. else if (keywordp (x)) return KeywordNamespace;
  493. else if (x instanceof SimpleSymbol) return KawaNamespace;
  494. else return nil;
  495. }
  496. else throw new RuntimeException("argument not a symbol: " + x);
  497. }
  498. public static Object intern(String name, LispPackage pkg) {
  499. name = name.intern();
  500. if (name == "nil" && pkg == CLNamespace) return CommonLisp.FALSE;
  501. return pkg.lookup(name, name.hashCode(), true);
  502. }
  503. /** Returns null if no package exists. */
  504. public static LispPackage findPackage(String name) {
  505. Namespace ns = Namespace.valueOfNoCreate(name);
  506. if (ns instanceof LispPackage) return (LispPackage)ns;
  507. return null;
  508. }
  509. /**
  510. * Temporary stub until Kawa supports conditional restarts.
  511. */
  512. public static void signal (String msg)
  513. {
  514. throw new RuntimeException(msg);
  515. }
  516. }
  517. /**
  518. * This is used to implement two linked lists. For performance they're combined
  519. * into one object.
  520. */
  521. class NamespaceUse
  522. {
  523. LispPackage imported = new LispPackage();
  524. NamespaceUse nextImported;
  525. LispPackage importing = new LispPackage();
  526. NamespaceUse nextImporting;
  527. }