ImportFromLibrary.java 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. // Copyright (C) 2009 Per M.A. Bothner.
  2. // This is free software; for terms and warranty disclaimer see ../../COPYING.
  3. package kawa.standard;
  4. import kawa.lang.*;
  5. import gnu.expr.*;
  6. import gnu.lists.*;
  7. import gnu.kawa.io.FilePath;
  8. import gnu.kawa.io.Path;
  9. import gnu.mapping.*;
  10. import java.io.File;
  11. import gnu.bytecode.ObjectType;
  12. import java.util.*;
  13. import kawa.lang.Translator.FormStack;
  14. /** Implement R6RS import form.
  15. * This actually only implements simplified import;
  16. * we assumes it has been simplified by import macro defined in syntax.scm.
  17. */
  18. public class ImportFromLibrary extends Syntax
  19. {
  20. public static final ImportFromLibrary instance = new ImportFromLibrary();
  21. public static String[] classPrefixPath = { "", "kawa.lib." };
  22. private static final String BUILTIN = "<builtin>";
  23. private static final String MISSING = null;
  24. static final String[][] SRFI97Map = {
  25. { "1", "lists", "gnu.kawa.slib.srfi1" },
  26. { "2", "and-let*", "gnu.kawa.slib.srfi2" },
  27. { "5", "let", MISSING },
  28. { "6", "basic-string-ports", BUILTIN },
  29. { "8", "receive", Mangling.mangleQualifiedName("kawa.lib.srfi.8") },
  30. { "9", "records", BUILTIN },
  31. { "11", "let-values", BUILTIN },
  32. { "13", "strings", "gnu.kawa.slib.srfi13" },
  33. { "14", "char-sets", "gnu.kawa.slib.srfi14" },
  34. { "16", "case-lambda", BUILTIN },
  35. { "17", "generalized-set!", BUILTIN },
  36. { "18", "multithreading", MISSING },
  37. { "19", "time", MISSING },
  38. { "21", "real-time-multithreading", MISSING },
  39. { "23", "error", BUILTIN },
  40. { "25", "multi-dimensional-arrays", BUILTIN },
  41. { "26", "cut", "kawa.lib.srfi.26" },
  42. { "27", "random-bits", MISSING },
  43. { "28", "basic-format-strings", BUILTIN },
  44. { "29", "localization", MISSING },
  45. { "31", "rec", MISSING },
  46. { "35", "conditions", "gnu.kawa.slib.conditions" },
  47. { "37", "args-fold", "gnu.kawa.slib.srfi37" },
  48. { "38", "with-shared-structure", MISSING },
  49. { "39", "parameters", BUILTIN },
  50. // Note the default for (srfi :41) should be "streams". We put that last,
  51. // since the lable is searched from high index to low index.
  52. { "41", "streams.primitive", "gnu.kawa.slib.StreamsPrimitive" },
  53. { "41", "streams.derived", "gnu.kawa.slib.StreamsDerived" },
  54. { "41", "streams", "gnu.kawa.slib.Streams" },
  55. { "42", "eager-comprehensions", MISSING },
  56. { "43", "vectors", MISSING },
  57. { "44", "collections", MISSING },
  58. { "45", "lazy", MISSING },
  59. { "46", "syntax-rules", MISSING },
  60. { "47", "arrays", MISSING },
  61. { "48", "intermediate-format-strings", MISSING },
  62. { "51", "rest-values", MISSING },
  63. { "54", "cat", MISSING },
  64. { "57", "records", MISSING },
  65. { "59", "vicinities", MISSING },
  66. { "60", "integer-bits", "gnu.kawa.slib.srfi60" },
  67. { "61", "cond", MISSING },
  68. { "63", "arrays", MISSING },
  69. { "64", "testing", "gnu.kawa.slib.testing" },
  70. { "66", "octet-vectors", MISSING },
  71. { "67", "compare-procedures", MISSING },
  72. { "69", "basic-hash-tables", "gnu.kawa.slib.srfi69" },
  73. { "71", "let", MISSING },
  74. { "74", "blobs", MISSING },
  75. { "78", "lightweight-testing", MISSING },
  76. { "86", "mu-and-nu", MISSING },
  77. { "87", "case", BUILTIN },
  78. { "95", "sorting-and-merging",
  79. Mangling.mangleQualifiedName("kawa.lib.srfi.95") },
  80. { "98", "os-environment-variables", BUILTIN },
  81. { "101", "random-access-lists", "gnu.kawa.slib.ralists" }
  82. };
  83. @Override
  84. public void scanForm(Pair st, ScopeExp defs, Translator tr) {
  85. Object obj = st.getCdr();
  86. while (obj instanceof Pair) {
  87. Pair pair = (Pair) obj;
  88. Object save1 = tr.pushPositionOf(pair);
  89. scanImportSet(pair.getCar(), defs, tr, null);
  90. tr.popPositionOf(save1);
  91. obj = pair.getCdr();
  92. }
  93. if (obj != LList.Empty) tr.error('e', "improper list");
  94. }
  95. public static String checkSrfi(String lname, Translator tr) {
  96. if (lname.startsWith("srfi.")) {
  97. String demangled =
  98. Mangling.demangleQualifiedName(lname.substring(5));
  99. int dot = demangled.indexOf('.');
  100. String srfiName;
  101. StringBuilder badNameBuffer = null;
  102. if (dot < 0) {
  103. srfiName = null;
  104. dot = demangled.length();
  105. } else
  106. srfiName = demangled.substring(dot+1);
  107. String srfiNumber = null;
  108. if (dot > 0) {
  109. int numStart = demangled.charAt(0) == ':' ? 1 : 0;
  110. for (int i = numStart; ; i++) {
  111. if (i == dot) {
  112. srfiNumber = demangled.substring(numStart, dot);
  113. break;
  114. }
  115. if (Character.digit(demangled.charAt(i), 10) < 0)
  116. break;
  117. }
  118. }
  119. if (srfiNumber == null) {
  120. tr.error('e', "SRFI library reference must have the form: (srfi NNN [name]) or (srfi :NNN [name])");
  121. return lname;
  122. }
  123. int srfiIndex = SRFI97Map.length;
  124. for (;;) {
  125. if (--srfiIndex < 0) {
  126. break;
  127. }
  128. if (!SRFI97Map[srfiIndex][0].equals(srfiNumber))
  129. continue;
  130. String srfiNameExpected = SRFI97Map[srfiIndex][1];
  131. String srfiClass = SRFI97Map[srfiIndex][2];
  132. if (srfiName == null || srfiName.equals(srfiNameExpected))
  133. return srfiClass != MISSING ? srfiClass : lname;
  134. if (badNameBuffer == null) {
  135. badNameBuffer = new StringBuilder("the name of SRFI ");
  136. badNameBuffer.append(srfiNumber);
  137. badNameBuffer.append(" should be '");
  138. }
  139. else
  140. badNameBuffer.append(" or '");
  141. badNameBuffer.append(srfiNameExpected);
  142. badNameBuffer.append('\'');
  143. }
  144. if (badNameBuffer != null) {
  145. tr.error('e', badNameBuffer.toString());
  146. return BUILTIN;
  147. }
  148. }
  149. return lname;
  150. }
  151. void scanImportSet(Object imports, ScopeExp defs, Translator tr, require.DeclSetMapper mapper) {
  152. if (imports instanceof SimpleSymbol) {
  153. String sname = imports.toString();
  154. handleImport(sname, null,
  155. Mangling.mangleQualifiedName(sname),
  156. defs, tr, mapper);
  157. return;
  158. }
  159. int specLength = Translator.listLength(imports);
  160. if (specLength <= 0) {
  161. Object save1 = tr.pushPositionOf(imports);
  162. tr.error('e', "import specifier is not a proper list");
  163. tr.popPositionOf(save1);
  164. return;
  165. }
  166. Pair pimport = (Pair) imports;
  167. Object first = pimport.getCar();
  168. Object rest = pimport.getCdr();
  169. Pair cdrPair = specLength >= 2 ? (Pair) rest : null;
  170. char kind = '\0';
  171. if (first == onlySymbol)
  172. kind = 'O';
  173. else if (first == exceptSymbol)
  174. kind = 'E';
  175. else if (first == renameSymbol)
  176. kind = 'R';
  177. else if (first == prefixSymbol)
  178. kind = 'P';
  179. else if (first == librarySymbol && specLength == 2
  180. && cdrPair.getCar() instanceof Pair)
  181. pimport = (Pair) cdrPair.getCar();
  182. else if (first == classSymbol && specLength >= 2
  183. && cdrPair.getCar() instanceof SimpleSymbol) {
  184. Map<Symbol, Expression> decls =
  185. new LinkedHashMap<Symbol, Expression>();
  186. SimpleSymbol name1 = (SimpleSymbol) cdrPair.getCar();
  187. String prefix = name1.getName();
  188. if (prefix.length() > 0)
  189. prefix = prefix + '.';
  190. rest = cdrPair.getCdr();
  191. if (rest == LList.Empty) {
  192. tr.error('e', "class-prefix must be followed by class-names");
  193. }
  194. while (rest != LList.Empty) {
  195. cdrPair = (Pair) rest;
  196. Object part2 = cdrPair.getCar();
  197. String cname = null;
  198. SimpleSymbol dname = null;
  199. if (part2 instanceof SimpleSymbol) {
  200. dname = (SimpleSymbol) part2;
  201. String str2 = dname.getName();
  202. cname = prefix+str2;
  203. } else if (part2 instanceof Pair
  204. && Translator.listLength(part2) == 2) {
  205. Pair rpair1 = (Pair) part2;
  206. Pair rpair2 = (Pair) rpair1.getCdr();
  207. Object rname1 = rpair1.getCar();
  208. Object rname2 = rpair2.getCar();
  209. if (rname1 instanceof SimpleSymbol
  210. && rname2 instanceof SimpleSymbol) {
  211. cname = prefix + ((SimpleSymbol) rname1).getName();
  212. dname = (SimpleSymbol) rname2;
  213. }
  214. }
  215. if (dname == null) {
  216. tr.error('e', "imported class-name must be NAME or (NAME NEW-NAME)");
  217. } else {
  218. try {
  219. Class clas = ObjectType.getContextClass(cname);
  220. decls.put(dname, tr.makeQuoteExp(clas));
  221. } catch (ClassNotFoundException ex) {
  222. Object savePos = tr.pushPositionOf(cdrPair);
  223. tr.error('e', "no class found named "+cname);
  224. tr.popPositionOf(savePos);
  225. }
  226. }
  227. rest = cdrPair.getCdr();
  228. }
  229. if (mapper != null)
  230. decls = mapper.map(decls, tr);
  231. for (Map.Entry<Symbol,Expression> entry : decls.entrySet()) {
  232. Symbol aname = entry.getKey();
  233. Declaration decl = tr.define(aname, defs);
  234. decl.setAlias(true);
  235. decl.setFlag(Declaration.IS_CONSTANT|Declaration.EARLY_INIT);
  236. SetExp sexp = new SetExp(decl, entry.getValue());
  237. tr.setLineOf(sexp);
  238. decl.noteValueFromSet(sexp);
  239. sexp.setDefining (true);
  240. tr.formStack.push(sexp);
  241. }
  242. return;
  243. }
  244. if (specLength >= 2 && kind != '\0') {
  245. ImportSetMapper nmapper
  246. = new ImportSetMapper(kind, cdrPair.getCdr(), specLength-2);
  247. nmapper.chain = mapper;
  248. scanImportSet(cdrPair.getCar(), defs, tr, nmapper);
  249. return;
  250. }
  251. scanImportSet1(pimport, defs, tr, mapper);
  252. }
  253. boolean scanImportSet1(Object libref, ScopeExp defs, Translator tr, require.DeclSetMapper mapper) {
  254. String explicitSource = null;
  255. Object versionSpec = null;
  256. StringBuilder cbuf = new StringBuilder(); // for class name
  257. StringBuilder sbuf = new StringBuilder(); // for source file name
  258. while (libref instanceof Pair) {
  259. Pair pair = (Pair) libref;
  260. Object car = pair.getCar();
  261. Object cdr = pair.getCdr();
  262. if (car instanceof Pair) {
  263. if (versionSpec != null) {
  264. tr.error('e', "duplicate version reference - was "+versionSpec);
  265. }
  266. versionSpec = car;
  267. } else if (car instanceof String) {
  268. if (cdr instanceof Pair)
  269. tr.error('e', "source specifier must be last element in library reference");
  270. explicitSource = (String) car;
  271. } else {
  272. if (cbuf.length() > 0)
  273. cbuf.append('.');
  274. if (sbuf.length() > 0)
  275. sbuf.append('/');
  276. String part = car.toString();
  277. cbuf.append(Mangling.mangleClassName(part));
  278. sbuf.append(part);
  279. }
  280. libref = cdr;
  281. }
  282. return handleImport(sbuf.toString(), explicitSource,
  283. cbuf.toString(),
  284. defs, tr, mapper);
  285. }
  286. /** Do the actual work of importing a module.
  287. * @param implicitSource Source name inferred from library name,
  288. * with '/' as separator. Does not include a file extension.
  289. * @param explicitSource If non-null, an exlicitly specified
  290. * source file name.
  291. */
  292. public static boolean handleImport(String implicitSource, String explicitSource, String requestedClass, ScopeExp defs, Translator tr, require.DeclSetMapper mapper) {
  293. boolean checkExistsOnly = defs == null;
  294. ModuleManager mmanager = ModuleManager.getInstance();
  295. ModuleInfo minfo = null;
  296. String lname = checkSrfi(requestedClass, tr);
  297. if (lname == BUILTIN)
  298. return true; // nothing to do
  299. boolean foundSrfi = lname != requestedClass;
  300. int classPrefixPathLength = classPrefixPath.length;
  301. Class existingClass = null;
  302. for (int i = 0; i < classPrefixPathLength; i++) {
  303. String tname = classPrefixPath[i] + lname;
  304. minfo = mmanager.searchWithClassName(tname);
  305. if (minfo != null)
  306. break;
  307. try {
  308. existingClass = ObjectType.getContextClass(tname);
  309. break;
  310. } catch (Exception ex) {
  311. } catch (NoClassDefFoundError ex) {
  312. }
  313. }
  314. ModuleInfo curinfo = tr.getMinfo();
  315. Path currentSource = curinfo.getSourceAbsPath();
  316. String currentExtension = currentSource == null ? null
  317. : currentSource.getExtension();
  318. if (currentExtension == null) {
  319. List<String> langExtensions = tr.getLanguage().getExtensions();
  320. if (! langExtensions.isEmpty())
  321. currentExtension = langExtensions.get(0);
  322. }
  323. boolean hasDot;
  324. boolean isAbsolute;
  325. if (explicitSource != null) {
  326. hasDot = explicitSource.indexOf("./") >= 0;
  327. isAbsolute = Path.valueOf(explicitSource).isAbsolute();
  328. } else {
  329. hasDot = false;
  330. isAbsolute = false;
  331. }
  332. String currentClassName = curinfo.getClassName();
  333. // Is the current module a file - as opposed to (say) a tty?
  334. boolean currentIsFile = currentSource != null
  335. && currentSource.isPlainFile();
  336. Path currentRoot = currentIsFile ? currentSource.getDirectory()
  337. : Path.currentPath();
  338. if (currentIsFile
  339. && ! (explicitSource != null && (hasDot || isAbsolute))) {
  340. int currentDots = 0;
  341. String prefix = currentClassName != null ? currentClassName
  342. : tr.classPrefix != null ? tr.classPrefix : "";
  343. for (int i = prefix.length(); --i >= 0; )
  344. if (prefix.charAt(i) == '.')
  345. currentDots++;
  346. if (currentDots > 0) {
  347. StringBuilder ups = new StringBuilder("..");
  348. for (int i = currentDots; -- i > 0; )
  349. ups.append("/..");
  350. currentRoot = currentRoot.resolve(ups.toString());
  351. }
  352. }
  353. List<CharSequence> srcSearchPath;
  354. boolean skipSourceSearch = minfo != null && explicitSource == null;
  355. if (isAbsolute || hasDot || skipSourceSearch) {
  356. srcSearchPath = new ArrayList<CharSequence>();
  357. if (! skipSourceSearch)
  358. srcSearchPath.add(currentRoot.toString());
  359. }
  360. else
  361. srcSearchPath = getImportSearchPath();
  362. String pathStr = null;
  363. for (CharSequence searchElement : srcSearchPath) {
  364. if (isAbsolute)
  365. pathStr = explicitSource;
  366. else {
  367. String pathElement = searchElement.toString();
  368. int selectorEnd;
  369. int star;
  370. int prefixLength = 0;
  371. StringBuilder pbuf = new StringBuilder();
  372. if (pathElement.length() >= 3
  373. && pathElement.charAt(0) == '<'
  374. && (selectorEnd = pathElement.indexOf('>')+1) > 0) {
  375. StringBuilder prefixBuf = new StringBuilder();
  376. boolean slashNeeded = false;
  377. for (int i = 1; i < selectorEnd-1; i++) {
  378. char ch = pathElement.charAt(i);
  379. if (ch == ' ') {
  380. if (prefixBuf.length() > 0)
  381. slashNeeded = true;
  382. } else {
  383. if (slashNeeded)
  384. prefixBuf.append('/');
  385. prefixBuf.append(ch);
  386. prefixLength += slashNeeded ? 2 : 1;
  387. slashNeeded = false;
  388. }
  389. }
  390. if (! implicitSource.startsWith(prefixBuf.toString()))
  391. continue;
  392. if (implicitSource.length() != prefixLength) {
  393. if (implicitSource.charAt(prefixLength) != '/')
  394. continue;
  395. prefixLength++;
  396. }
  397. star = pathElement.indexOf('*', selectorEnd);
  398. if (star < 0) {
  399. pathElement = pathElement.substring(selectorEnd);
  400. }
  401. } else { // No "<...>..." selector
  402. star = pathElement.indexOf('*');
  403. selectorEnd = 0;
  404. if (foundSrfi && explicitSource == null)
  405. continue;
  406. }
  407. if (star >= 0) {
  408. pbuf.append(pathElement.substring(selectorEnd, star));
  409. pbuf.append(implicitSource.substring(prefixLength));
  410. pbuf.append(pathElement.substring(star+1));
  411. } else {
  412. if (! ".".equals(pathElement)) {
  413. pbuf.append(pathElement);
  414. pbuf.append('/');
  415. }
  416. if (explicitSource != null)
  417. pbuf.append(explicitSource);
  418. else {
  419. pbuf.append(implicitSource);
  420. if (currentExtension != null) {
  421. pbuf.append('.');
  422. pbuf.append(currentExtension);
  423. }
  424. }
  425. }
  426. pathStr = pbuf.toString();
  427. }
  428. Path path = currentRoot.resolve(pathStr).getCanonical();
  429. // Might be more efficient to first check the ModuleManager,
  430. // before asking the file-system. FIXME
  431. long lastModifiedTime = path.getLastModified();
  432. if (lastModifiedTime != 0) {
  433. if (checkExistsOnly)
  434. return true;
  435. if (minfo != null) {
  436. String pstring = path.toString();
  437. Path infoPath = minfo.getSourceAbsPath();
  438. if (infoPath == null
  439. || ! (pstring.equals(infoPath.toString()))) {
  440. tr.error('w', "ignoring source file at "+pstring
  441. +" - instead using class "+minfo.getClassName()
  442. +(infoPath==null?""
  443. :(" from "+infoPath.toString())));
  444. }
  445. } else
  446. minfo = mmanager.findWithSourcePath(path, pathStr);
  447. // Should save lastModifiedTime in minfo FIXME
  448. if (foundSrfi)
  449. lname = requestedClass;
  450. break;
  451. }
  452. }
  453. if (checkExistsOnly)
  454. return existingClass != null || minfo != null;
  455. if (existingClass != null) {
  456. if (minfo == null)
  457. minfo = mmanager.findWithClass(existingClass);
  458. else
  459. minfo.setModuleClass(existingClass);
  460. }
  461. if (minfo == null)
  462. tr.error('e', "unknown library ("+implicitSource.replace('/', ' ')+")");
  463. else
  464. require.importDefinitions(lname, minfo, mapper,
  465. tr.formStack, defs, tr);
  466. return minfo != null;
  467. }
  468. public Expression rewriteForm(Pair form, Translator tr) {
  469. return tr.syntaxError(getName()+" is only allowed in a <body>");
  470. }
  471. static class ImportSetMapper implements require.DeclSetMapper {
  472. char kind;
  473. Object list;
  474. int listLength;
  475. require.DeclSetMapper chain;
  476. public ImportSetMapper(char kind, Object list, int listLength) {
  477. this.kind = kind;
  478. this.list = list;
  479. this.listLength = listLength;
  480. }
  481. public Map<Symbol, Expression> map(Map<Symbol, Expression> decls, Compilation comp) {
  482. Translator tr = (Translator) comp;
  483. Object lst = this.list;
  484. Map<Symbol,Expression> nmap = decls;
  485. switch (kind) {
  486. case 'E': // 'except; list has the form (name ...)
  487. case 'O': // 'only; list has the form (name ...)
  488. if (kind == 'O')
  489. nmap = new LinkedHashMap<Symbol,Expression>();
  490. while (lst instanceof Pair) {
  491. Pair pair = (Pair) lst;
  492. Object save1 = tr.pushPositionOf(pair);
  493. Object name = Translator.stripSyntax(pair.getCar());
  494. name = tr.namespaceResolve(name);
  495. Symbol oldsym = null;
  496. Symbol newsym = null;
  497. if (name instanceof Symbol) {
  498. oldsym = (Symbol) name;
  499. newsym = oldsym;
  500. } else if (kind == 'O' && name instanceof Pair
  501. && Translator.listLength(name) == 2) {
  502. Pair rpair1 = (Pair) name;
  503. Object rname1 = rpair1.getCar();
  504. Object rname2 = ((Pair) rpair1.getCdr()).getCar();
  505. rname1 = tr.namespaceResolve(rname1);
  506. rname2 = tr.namespaceResolve(rname2);
  507. if (rname1 instanceof Symbol
  508. && rname2 instanceof Symbol) {
  509. oldsym = (Symbol) rname1;
  510. newsym = (Symbol) rname2;
  511. }
  512. }
  513. if (oldsym == null)
  514. tr.error('e', "non-symbol in name list");
  515. else {
  516. Expression old = decls.get(oldsym);
  517. if (old == null)
  518. tr.error(kind == 'E' ? 'w' : 'e',
  519. "unknown symbol in import set: "+oldsym);
  520. else if (kind == 'E')
  521. nmap.remove(oldsym);
  522. else
  523. nmap.put(newsym, old);
  524. }
  525. tr.popPositionOf(save1);
  526. lst = pair.getCdr();
  527. }
  528. break;
  529. case 'R': // 'rename; list has the form: ((oldname newname) ...)
  530. Symbol[] pendingSymbols = new Symbol[listLength];
  531. Expression[] pendingDecls = new Expression[listLength];
  532. int npending = 0;
  533. while (lst instanceof Pair) {
  534. Pair pair = (Pair) lst;
  535. Object save1 = tr.pushPositionOf(pair);
  536. Object entry = pair.getCar();
  537. int entryLen = Translator.listLength(entry);
  538. if (entryLen == 2) {
  539. Pair p1 = (Pair) entry;
  540. Object oldname = p1.getCar();
  541. Object newname = ((Pair) p1.getCdr()).getCar();
  542. if (oldname instanceof Symbol
  543. && newname instanceof Symbol) {
  544. Symbol oldSymbol = (Symbol) oldname;
  545. Symbol newSymbol = (Symbol) newname;
  546. Expression oldValue = decls.remove(oldSymbol);
  547. if (oldValue == null)
  548. tr.error('e', "missing binding "+oldSymbol);
  549. else {
  550. pendingSymbols[npending] = newSymbol;
  551. pendingDecls[npending] = oldValue;
  552. npending++;
  553. }
  554. }
  555. else
  556. entryLen = -1;
  557. }
  558. if (entryLen != 2)
  559. tr.error('e', "entry is not a pair of names");
  560. tr.popPositionOf(save1);
  561. lst = pair.getCdr();
  562. }
  563. for (int i = 0; i < npending; i++) {
  564. Symbol newSymbol = pendingSymbols[i];
  565. Expression decl = pendingDecls[i];
  566. if (decls.put(newSymbol, decl) != null)
  567. tr.error('e', "duplicate binding for "+newSymbol);
  568. }
  569. break;
  570. case 'P': // 'prefix; list has the form: (name-prefix)
  571. nmap = new LinkedHashMap<Symbol,Expression>();
  572. if (listLength != 1
  573. || ! (((Pair) list).getCar() instanceof SimpleSymbol))
  574. tr.error('e', "bad syntax for prefix import specifier");
  575. else {
  576. String prefix
  577. = ((SimpleSymbol) ((Pair) list).getCar()).getName();
  578. for (Map.Entry<Symbol,Expression> entry : decls.entrySet()) {
  579. Symbol aname = entry.getKey();
  580. Expression old = entry.getValue();
  581. Symbol nname = Symbol.valueOf(prefix+aname);
  582. nmap.put(nname, old);
  583. }
  584. }
  585. break;
  586. }
  587. if (chain != null)
  588. nmap = chain.map(nmap, tr);
  589. return nmap;
  590. }
  591. }
  592. /** Check if library (in r7rs import syntax) exists.
  593. * @return if library exists: class name of (existing) library class,
  594. * or the special BUILTIN value; otherwise null.
  595. */
  596. public boolean libraryExists(Object list, Translator tr) {
  597. ModuleManager mmanager = ModuleManager.getInstance();
  598. return scanImportSet1(list, null, tr, null);
  599. }
  600. public static final ThreadLocal<List<CharSequence>> searchPath
  601. = new InheritableThreadLocal<List<CharSequence>>();
  602. public static List<CharSequence> getImportSearchPath() {
  603. return Include.getSearchPath(searchPath, "kawa.import.path", ".");
  604. }
  605. public static final SimpleSymbol classSymbol = Symbol.valueOf("class");
  606. public static final SimpleSymbol exceptSymbol = Symbol.valueOf("except");
  607. public static final SimpleSymbol librarySymbol = Symbol.valueOf("library");
  608. public static final SimpleSymbol onlySymbol = Symbol.valueOf("only");
  609. public static final SimpleSymbol prefixSymbol = Symbol.valueOf("prefix");
  610. public static final SimpleSymbol renameSymbol = Symbol.valueOf("rename");
  611. }