BindDecls.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. package kawa.lang;
  2. import gnu.bytecode.*;
  3. import gnu.expr.*;
  4. import gnu.lists.*;
  5. import gnu.text.Char;
  6. import java.util.Stack;
  7. import java.util.Vector;
  8. import gnu.mapping.Environment;
  9. import gnu.mapping.Symbol;
  10. import gnu.kawa.functions.Convert;
  11. import gnu.kawa.lispexpr.SeqSizeType;
  12. import gnu.kawa.lispexpr.LangObjType;
  13. import gnu.kawa.lispexpr.LangPrimType;
  14. import gnu.kawa.lispexpr.LispLanguage;
  15. import gnu.kawa.reflect.MappedArrayType;
  16. import gnu.mapping.Procedure;
  17. import kawa.standard.Scheme;
  18. /** Methods for parsing patterns. */
  19. public class BindDecls {
  20. public static final BindDecls instance = new BindDecls();
  21. public boolean allowShadowing = false;
  22. public boolean makeConstant = true;
  23. public Object ifKeyword = Special.ifk;
  24. public Procedure compareEquals = kawa.standard.Scheme.isEqual;
  25. public Type booleanType = kawa.standard.Scheme.booleanType;
  26. static final Symbol underScoreSymbol = Symbol.valueOf("_");
  27. public Declaration define(Symbol name, TemplateScope templateScope,
  28. ScopeExp scope, Translator comp) {
  29. Declaration oldDecl = comp.lexical.lookup(name, false);
  30. Declaration decl = comp.define(name, templateScope, scope);
  31. if (! allowShadowing
  32. && oldDecl != null
  33. && oldDecl.context != scope
  34. && ! (oldDecl.context instanceof ModuleExp)) {
  35. comp.error('w', decl, "new declaration '", "' shadows old declaration");
  36. comp.error('w', oldDecl, "(this is the previous declaration of '", "')");
  37. }
  38. return decl;
  39. }
  40. public Object parsePatternNext(Pair patList, Translator comp) {
  41. Object next = patList.getCdr();
  42. if (next instanceof Pair) {
  43. Pair nextPair = (Pair) next;
  44. if (comp.matches(nextPair.getCar(), "::")) {
  45. Object nextCdr = nextPair.getCdr();
  46. if (nextCdr instanceof Pair) {
  47. next = ((Pair) nextCdr).getCdr();
  48. }
  49. else { // Error
  50. next = nextCdr;
  51. }
  52. }
  53. }
  54. return next;
  55. }
  56. /** Parse a declaration or more generally a pattern.
  57. * The actual pattern is an initial sublist (using just the initial
  58. * car) of the patList.
  59. * @return A 2-element array, where element 0 is the unused remainder
  60. * of patList, while element 1 is a Declaration for that pattern.
  61. */
  62. public Object[] parsePatternCar(Pair patList, int scanNesting,
  63. ScopeExp scope,
  64. Translator comp) {
  65. return parsePatternCar(patList, null, null, scanNesting, scope, comp);
  66. }
  67. public Object[] parsePatternCar(Pair patList, Expression init,
  68. TemplateScope templateScope,
  69. int scanNesting, ScopeExp scope,
  70. Translator comp) {
  71. Object next = patList.getCdr();
  72. Type type = null;
  73. if (next instanceof Pair) {
  74. Pair nextPair = (Pair) next;
  75. if (comp.matches(nextPair.getCar(), "::")) {
  76. Object nextCdr = nextPair.getCdr();
  77. if (nextCdr instanceof Pair) {
  78. Pair nextCdrPair = (Pair) nextCdr;
  79. type = comp.exp2Type(nextCdrPair);
  80. next = nextCdrPair.getCdr();
  81. }
  82. else {
  83. Object saveLoc = comp.pushPositionOf(nextPair);
  84. comp.error('e', "missing type after '::'");
  85. comp.popPositionOf(saveLoc);
  86. next = nextCdr;
  87. }
  88. }
  89. }
  90. Object pattern = patList.getCar();
  91. Object saveLoc = comp.pushPositionOf(patList);
  92. Object patval = pattern;
  93. while (patval instanceof SyntaxForm) {
  94. SyntaxForm patSyntax = (SyntaxForm) patval;
  95. templateScope = patSyntax.getScope();
  96. patval = patSyntax.getDatum();
  97. }
  98. patval = comp.namespaceResolve(patval);
  99. Declaration decl = null;
  100. QuoteExp literal = literalPattern(patval, comp);
  101. if (literal != null) {
  102. decl = scope.addDeclaration((Object) null);
  103. addCondition(scope, compareLiteral(decl, literal));
  104. } else if (patval instanceof Symbol) {
  105. if (patval == underScoreSymbol) {
  106. decl = scope.addDeclaration((Object) null);
  107. } else {
  108. decl = define((Symbol) patval, templateScope, scope, comp);
  109. Translator.setLine(decl, patList);
  110. }
  111. if (init != null)
  112. setInitializer(decl, init, scope, comp);
  113. if (scope instanceof ModuleExp
  114. && (patval == underScoreSymbol
  115. || ! scope.getFlag(ModuleExp.INTERACTIVE)))
  116. decl.setPrivate(true);
  117. if (makeConstant)
  118. decl.setFlag(Declaration.IS_CONSTANT);
  119. decl.setFlag(Declaration.IS_SINGLE_VALUE);
  120. } else if (patval == ifKeyword) {
  121. if (next instanceof Pair) {
  122. Pair nextPair = (Pair) next;
  123. decl = addCondition(scope, nextPair.getCar());
  124. next = nextPair.getCdr();
  125. } else {
  126. comp.error('e', "missing expression after "+ifKeyword);
  127. }
  128. } else if (pattern instanceof Pair) {
  129. Pair patpair = (Pair) pattern;
  130. Object patcar = patpair.getCar();
  131. if (patcar == LispLanguage.bracket_list_sym) {
  132. decl = scope.addDeclaration((Object) null);
  133. if (init != null)
  134. setInitializer(decl, init, scope, comp);
  135. if (type != null)
  136. ; // FIXME
  137. decl.setPrivate(true);
  138. decl.setFlag(Declaration.IS_CONSTANT
  139. |Declaration.SKIP_FOR_METHOD_PARAMETER
  140. |Declaration.IS_SINGLE_VALUE);
  141. // FIXME pass templateScope?
  142. parseBracketListPattern(patpair, scanNesting, scope, decl, comp);
  143. }
  144. /*else if (patcar == LispLanguage.bracket_quote_sym)
  145. ....
  146. */
  147. else if (patcar == LispLanguage.splice_sym
  148. || patcar == LispLanguage.splice_colon_sym) {
  149. Object patcdr = patpair.getCdr();
  150. if (Translator.listLength(patcdr) != 1)
  151. comp.syntaxError("bad syntax for splice pattern cdr:"+patcdr);
  152. else {
  153. Object[] r = parsePatternCar((Pair) patcdr, null,
  154. templateScope,
  155. scanNesting, scope, comp);
  156. decl = (Declaration) r[1];
  157. decl.setFlag(Declaration.IS_REST_PARAMETER);
  158. boolean keywordsOk =
  159. patcar == LispLanguage.splice_colon_sym;
  160. if (keywordsOk) {
  161. decl.setFlag(Declaration.KEYWORDS_OK);
  162. if (scope instanceof LambdaExp)
  163. scope.setFlag(LambdaExp.ALLOW_OTHER_KEYWORDS);
  164. }
  165. if (! decl.getFlag(Declaration.TYPE_SPECIFIED)) {
  166. decl.setType(keywordsOk ? LangObjType.argVectorType
  167. : ArrayType.make(Type.objectType));
  168. }
  169. }
  170. } else
  171. comp.syntaxError("unrecognized pattern operator "+patcar);
  172. }
  173. else
  174. comp.error('e', "unrecognized pattern "+pattern);
  175. if (decl != null) {
  176. decl.setScanNesting(scanNesting);
  177. if (type != null) {
  178. decl.setType(MappedArrayType.maybe(type, scanNesting));
  179. decl.setFlag(Declaration.TYPE_SPECIFIED);
  180. }
  181. }
  182. comp.popPositionOf(saveLoc);
  183. return new Object[]{next,decl};
  184. }
  185. /** Handle patterns of the form {@code [pat1 ... patN]}.
  186. */
  187. public void parseBracketListPattern
  188. (Pair patpair, int scanNesting, ScopeExp scope, Declaration decl, Translator comp) {
  189. ClassType listType = ClassType.make("java.util.List");
  190. decl.setFlag(Declaration.SKIP_FOR_METHOD_PARAMETER);
  191. if (decl.getTypeExpRaw() != null) {
  192. Declaration d = scope.addDeclaration((Object) null);
  193. d.setFlag(Declaration.PATTERN_NESTED|Declaration.SKIP_FOR_METHOD_PARAMETER);
  194. d.setScanNesting(scanNesting);
  195. setInitializer(d, new ReferenceExp(decl), scope, comp);
  196. decl = d;
  197. }
  198. int count = 0;
  199. Object cdr = patpair.getCdr();
  200. int ellipsisCount = 0;
  201. int spliceCount = 0;
  202. for (;; count++) {
  203. if (cdr == LList.Empty)
  204. break;
  205. if (! (cdr instanceof Pair))
  206. break; // FIXME ERROR - or handle "rest" pattern
  207. patpair = (Pair) cdr;
  208. boolean sawEllipsis = false;
  209. boolean sawSplice = false;
  210. int curScanNesting = scanNesting;
  211. cdr = parsePatternNext(patpair, comp);
  212. if (cdr instanceof Pair) {
  213. Object nextCar = ((Pair) cdr).getCar();
  214. Object ellipsis = SyntaxRule.dots3Symbol;
  215. if (SyntaxPattern.literalIdentifierEq(nextCar, null/*FIXME*/, ellipsis, null)) {
  216. sawEllipsis = true;
  217. curScanNesting++;
  218. ellipsisCount++;
  219. cdr = ((Pair) cdr).getCdr();
  220. }
  221. }
  222. Object curCar = patpair.getCar();
  223. if (Translator.listLength(curCar) == 2) {
  224. Object nextCaar = ((Pair) curCar).getCar();
  225. if (nextCaar == LispLanguage.splice_sym
  226. || nextCaar == LispLanguage.splice_colon_sym) {
  227. sawSplice = true;
  228. spliceCount++;
  229. patpair = (Pair) ((Pair) curCar).getCdr();
  230. }
  231. }
  232. Expression init;
  233. if (sawEllipsis || sawSplice) {
  234. // FIXME restCount mishandles 'ID :: TYPE', for example.
  235. int restCount = Translator.listLength(cdr);
  236. Method dropMethod = ClassType.make("gnu.lists.Sequences")
  237. .getDeclaredMethod("drop", restCount==0 ? 2 : 3);
  238. Expression[] args = new Expression[restCount==0 ? 2 : 3];
  239. args[0] = new ReferenceExp(decl);
  240. args[1] = new QuoteExp(count, Type.intType);
  241. if (restCount != 0)
  242. args[2] = new QuoteExp(restCount, Type.intType);
  243. init = new ApplyExp(dropMethod, args);
  244. } else {
  245. // FIXME Probably better to use an Iterator or "position indexes"
  246. Method indexMethod;
  247. int index;
  248. if (ellipsisCount + spliceCount > 0) {
  249. index = -1 - Translator.listLength(cdr);
  250. indexMethod = ConsumerTarget.typeSequences
  251. .getDeclaredMethod("getAt", 2);
  252. } else {
  253. index = count;
  254. indexMethod = listType
  255. .getMethod("get", new Type[] { Type.intType });
  256. }
  257. init = new ApplyExp(indexMethod, new Expression[] {
  258. new ReferenceExp(decl),
  259. new QuoteExp(index, Type.intType) });
  260. }
  261. if (scanNesting > 0)
  262. init = mapInit(init, decl);
  263. Object[] r = parsePatternCar(patpair, init, null, curScanNesting,
  264. scope, comp);
  265. //r[0] is ingnored, instead we use parsePatternNext
  266. Declaration d = (Declaration) r[1];
  267. d.setScanNesting(curScanNesting);
  268. d.setFlag(Declaration.PATTERN_NESTED);
  269. if (sawEllipsis)
  270. d.setFlag(Declaration.SCAN_OWNER);
  271. }
  272. if (ellipsisCount+spliceCount > 1)
  273. comp.error('e', "more than one '...' or '@' in a pattern not supported");
  274. Type seqType = new SeqSizeType(count-ellipsisCount-spliceCount,
  275. ellipsisCount+spliceCount==0);
  276. decl.setType(MappedArrayType.maybe(seqType, scanNesting));
  277. }
  278. public static void setInitializer(Declaration decl, Expression init, ScopeExp scope, Translator comp) {
  279. if ((scope instanceof ModuleExp)
  280. || (scope instanceof LetExp
  281. && scope.getFlag(LetExp.IS_BODY_SCOPE))) {
  282. SetExp sexp = new SetExp(decl, init);
  283. comp.pushForm(sexp);
  284. decl.noteValueFromSet(sexp);
  285. }
  286. else {
  287. decl.setInitValue(init);
  288. decl.noteValueFromLet(scope);
  289. }
  290. }
  291. static class ReplaceDecl extends ExpExpVisitor<Void> {
  292. Declaration oldDecl;
  293. Declaration newDecl;
  294. protected Expression visitReferenceExp(ReferenceExp exp, Void ignored) {
  295. if (exp.getBinding() == oldDecl)
  296. exp.setBinding(newDecl);
  297. return exp;
  298. }
  299. }
  300. static Expression mapInit(Expression init, Declaration decl) {
  301. LambdaExp lambda = new LambdaExp();
  302. Declaration param = lambda.addParameter(null);
  303. ReplaceDecl v = new ReplaceDecl();
  304. v.oldDecl = decl;
  305. v.newDecl = param;
  306. v.visit(init, null);
  307. lambda.body = init;
  308. return new ApplyExp(Scheme.map,
  309. lambda,
  310. new ReferenceExp(decl));
  311. }
  312. Declaration addCondition(ScopeExp scope, Object condition) {
  313. Declaration decl = scope.addDeclaration((Object) null);
  314. Expression cond;
  315. if (condition instanceof Expression)
  316. cond = Compilation.makeCoercion((Expression) condition, booleanType);
  317. else
  318. cond = new LangExp(LList.list3(new QuoteExp(Convert.cast),
  319. new QuoteExp(booleanType),
  320. condition));
  321. decl.setInitValue(cond);
  322. decl.setFlag(Declaration.PATTERN_NESTED|Declaration.SKIP_FOR_METHOD_PARAMETER);
  323. decl.setType(QuoteExp.isTrueTypeExp, LangPrimType.isTrueType);
  324. return decl;
  325. }
  326. public QuoteExp literalPattern(Object patval, Translator comp) {
  327. if (patval instanceof Number
  328. || patval == null
  329. || patval instanceof Character
  330. || patval instanceof Char
  331. || patval instanceof Boolean
  332. || patval instanceof CharSequence)
  333. return QuoteExp.getInstance(patval);
  334. if (patval instanceof Pair) {
  335. Pair p1 = (Pair) patval;
  336. Object p1cdr = p1.getCdr();
  337. if (comp.matches(p1.getCar(), "quote")
  338. && p1cdr instanceof Pair) {
  339. Pair p2 = (Pair) p1cdr;
  340. if (p2.getCdr() == LList.Empty)
  341. return QuoteExp.getInstance(p2.getCar());
  342. }
  343. }
  344. return null;
  345. }
  346. public Expression compareLiteral(Declaration param, QuoteExp literal) {
  347. return new ApplyExp(compareEquals,
  348. new ReferenceExp(param), literal);
  349. }
  350. }