define.java 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. package kawa.standard;
  2. import kawa.lang.*;
  3. import gnu.mapping.*;
  4. import gnu.bytecode.ClassType;
  5. import gnu.bytecode.Method;
  6. import gnu.expr.*;
  7. import gnu.lists.*;
  8. import gnu.kawa.reflect.Invoke;
  9. /**
  10. * The Syntax transformer that re-writes the "%define" internal form.
  11. * This is used to implement define, define-private, and define-constant.
  12. * Syntax: {@code (%define name code type value)}.
  13. * The {@code name} is an identifier ({@code String} or
  14. * {@code Symbol}) or {@code Declaration}.
  15. * The {@code code} is an integer mask,
  16. * where 1 means type specified, 2 means a function definition,
  17. * 4 means private, 8 means constant, 16 means an early constant.,
  18. * and 32 means a fluid variable (define-variable).
  19. * As a special case, define-procedure is 1+2+8+16=27
  20. * The {@code type} is the declarated type or{@code null}.
  21. * The {@code value} is the initializing value.
  22. * @author Per Bothner
  23. */
  24. public class define extends Syntax
  25. {
  26. public static final define defineRaw = new define(SchemeCompilation.lambda);
  27. Lambda lambda;
  28. String getName (int options)
  29. {
  30. if ((options & 4) != 0)
  31. return "define-private";
  32. else if ((options & 8) != 0)
  33. return "define-constant";
  34. else if ((options & 32) != 0)
  35. return "define-variable";
  36. else
  37. return "define";
  38. }
  39. public define(Lambda lambda)
  40. {
  41. this.lambda = lambda;
  42. }
  43. public void scanForm (Pair st, ScopeExp defs, Translator tr)
  44. {
  45. Pair p1 = (Pair) st.getCdr();
  46. Pair p2 = (Pair) p1.getCdr();
  47. Pair p3 = (Pair) p2.getCdr();
  48. TemplateScope templateScope = null;
  49. Object name = p1.getCar();
  50. while (name instanceof SyntaxForm)
  51. {
  52. SyntaxForm nameSyntax = (SyntaxForm) name;
  53. templateScope = nameSyntax.getScope();
  54. name = nameSyntax.getDatum();
  55. }
  56. int options = ((Number) Translator.stripSyntax(p2.getCar())).intValue();
  57. boolean makePrivate = (options & 4) != 0;
  58. boolean makeConstant = (options & 8) != 0;
  59. boolean makeFluid = (options & 32) != 0;
  60. boolean makeCompoundProcedure = options == 27;
  61. name = tr.namespaceResolve(name);
  62. if (! (name instanceof Symbol))
  63. {
  64. tr.error('e', "'"+name+"' is not a valid identifier");
  65. name = null;
  66. }
  67. Object savePos = tr.pushPositionOf(p1);
  68. Declaration decl = tr.define(name, templateScope, defs);
  69. tr.popPositionOf(savePos);
  70. name = decl.getSymbol();
  71. if (makePrivate)
  72. {
  73. if (defs instanceof ModuleExp && defs.getFlag(ModuleExp.INTERACTIVE))
  74. tr.error('w', "'define-private' should not be used in interactive mode");
  75. else {
  76. decl.setFlag(Declaration.PRIVATE_SPECIFIED);
  77. decl.setPrivate(true);
  78. }
  79. }
  80. if (makeConstant)
  81. decl.setFlag(Declaration.IS_CONSTANT);
  82. if ((options & 16) != 0)
  83. decl.setFlag(Declaration.EARLY_INIT);
  84. decl.setFlag(Declaration.IS_SINGLE_VALUE);
  85. Expression value;
  86. if ((options & 2) != 0 && ! makeCompoundProcedure)
  87. {
  88. LambdaExp lexp = new LambdaExp();
  89. lexp.setSymbol(name);
  90. if (Compilation.inlineOk)
  91. {
  92. decl.setProcedureDecl(true);
  93. decl.setType(Compilation.typeProcedure);
  94. lexp.nameDecl = decl;
  95. }
  96. Translator.setLine(lexp, p1);
  97. value = lexp;
  98. }
  99. else
  100. value = null;
  101. SetExp sexp = new SetExp(decl, value);
  102. if (defs instanceof ModuleExp && ! makePrivate && ! makeConstant
  103. && (! Compilation.inlineOk || tr.sharedModuleDefs()))
  104. decl.setCanWrite(true);
  105. if (makeFluid) {
  106. decl.setSimple(false);
  107. decl.setPrivate(true);
  108. decl.setFlag(Declaration.IS_DYNAMIC);
  109. decl.setCanRead(true);
  110. decl.setCanWrite(true);
  111. decl.setIndirectBinding(true);
  112. sexp.setSetIfUnbound(true);
  113. }
  114. if ((options & 1) != 0)
  115. {
  116. decl.setTypeExp(new LangExp(p3));
  117. decl.setFlag(Declaration.TYPE_SPECIFIED);
  118. }
  119. st = Translator.makePair(st, this,
  120. Translator.makePair(p1, sexp, p2));
  121. Translator.setLine(decl, p1);
  122. tr.pushForm(st);
  123. }
  124. public Expression rewriteForm (Pair form, Translator tr)
  125. {
  126. Pair p1 = (Pair) form.getCdr();
  127. Pair p2 = (Pair) p1.getCdr();
  128. Pair p3 = (Pair) p2.getCdr();
  129. Pair p4 = (Pair) p3.getCdr();
  130. Object name = p1.getCar();
  131. int options = ((Number) Translator.stripSyntax(p2.getCar())).intValue();
  132. boolean makePrivate = (options & 4) != 0;
  133. boolean makeFluid = (options & 32) != 0;
  134. boolean makeCompoundProcedure = options == 27;
  135. if (! (name instanceof SetExp))
  136. return tr.syntaxError(getName(options) + " is only allowed in a <body>");
  137. SetExp sexp = (SetExp) name;
  138. Declaration decl = sexp.getBinding();
  139. if (decl.getFlag(Declaration.TYPE_SPECIFIED))
  140. {
  141. Expression texp = decl.getTypeExp();
  142. if (texp instanceof LangExp)
  143. {
  144. Pair typeSpecPair = (Pair) ((LangExp) texp).getLangValue();
  145. decl.setType(tr.exp2Type(typeSpecPair));
  146. }
  147. }
  148. if (makeFluid
  149. && Translator.stripSyntax(p4.getCar())==Special.undefined)
  150. return QuoteExp.voidExp;
  151. BeginExp bexp2 = null;
  152. boolean unknownValue;
  153. if ((options & 2) != 0 && ! makeCompoundProcedure)
  154. {
  155. LambdaExp lexp = (LambdaExp) sexp.getNewValue();
  156. Object formals = p4.getCar();
  157. Object body = p4.getCdr();
  158. lambda.rewrite(lexp, formals, body, tr, null);
  159. unknownValue = ! Compilation.inlineOk;
  160. }
  161. else
  162. {
  163. unknownValue = decl.context instanceof ModuleExp && ! makePrivate && decl.getCanWrite();
  164. if (makeCompoundProcedure) {
  165. tr.letStart();
  166. ClassType classGenericProc = ClassType.make("gnu.expr.GenericProc");
  167. Declaration gproc =
  168. tr.letVariable(null,
  169. classGenericProc,
  170. new ApplyExp(Invoke.make,
  171. new Expression[] {
  172. QuoteExp.getInstance(classGenericProc),
  173. QuoteExp.getInstance(decl.getName()) }));
  174. gproc.setFlag(Declaration.ALLOCATE_ON_STACK);
  175. tr.letEnter();
  176. BeginExp bexp1 = new BeginExp(); // early-init-code goes here
  177. Method addMethod = classGenericProc.getDeclaredMethod("add", 1);
  178. Method setPropMethod =
  179. classGenericProc.getDeclaredMethod("setProperty", 2);
  180. for (;;) {
  181. Keyword key = null;
  182. Object car = Translator.stripSyntax(p4.getCar());
  183. if (car instanceof Keyword) {
  184. key = (Keyword) car;
  185. Object cdr = p4.getCdr();
  186. if (! (cdr instanceof Pair)
  187. || Translator.safeCar(cdr) instanceof Keyword) {
  188. tr.error('e', "missing value following keyword");
  189. break;
  190. }
  191. p4 = (Pair) cdr;
  192. }
  193. Expression arg = tr.rewrite_car(p4, false);
  194. if (key != null) {
  195. if (bexp2 == null)
  196. bexp2 = new BeginExp();
  197. bexp2.add(new ApplyExp(setPropMethod,
  198. new Expression[] {
  199. new ReferenceExp(decl),
  200. QuoteExp.getInstance(key),
  201. arg }));
  202. } else {
  203. Declaration gdecl = arg instanceof LambdaExp ? gproc : decl;
  204. Expression addCall =
  205. new ApplyExp(addMethod,
  206. new Expression[] {
  207. new ReferenceExp(gdecl),
  208. arg });
  209. if (arg instanceof LambdaExp) {
  210. LambdaExp larg = (LambdaExp) arg;
  211. String lname = larg.getName();
  212. String dname = decl.getName();
  213. if (lname == null || lname.equals(dname)) {
  214. // Needed so PrimProcedure.getMethodFor
  215. // can find this method.
  216. if (decl.isPublic())
  217. larg.setFlag(LambdaExp.PUBLIC_METHOD);
  218. // FIXME Maybe set larg.nameDecl to decl?
  219. // At least if we have a single LambdaExp?
  220. // FIXME set the name?
  221. // This "enables" ModuleMethod#resolveParameterTypes
  222. // to search for the most specific method, which
  223. // is expensive - and pull in Compilation and
  224. // related classes.
  225. // if (lname == null)
  226. // larg.setName(dname);
  227. }
  228. bexp1.add(addCall);
  229. } else {
  230. if (bexp2 == null)
  231. bexp2 = new BeginExp();
  232. bexp2.add(addCall);
  233. }
  234. }
  235. Object cdr = p4.getCdr();
  236. if (! (cdr instanceof Pair)) {
  237. if (cdr != LList.Empty)
  238. tr.error('e', "not a proper list");
  239. break;
  240. }
  241. p4 = (Pair) cdr;
  242. }
  243. ReferenceExp gref = new ReferenceExp(gproc);
  244. gref.setFlag(ReferenceExp.ALLOCATE_ON_STACK_LAST);
  245. bexp1.add(gref);
  246. sexp.setNewValue(tr.letDone(BeginExp.canonicalize(bexp1)));
  247. } else
  248. sexp.setNewValue(tr.rewrite_car(p4, false));
  249. }
  250. if (unknownValue)
  251. decl.noteValueUnknown();
  252. else
  253. decl.noteValueFromSet(sexp);
  254. sexp.setDefining (true);
  255. if (makePrivate && ! (decl.getContext() instanceof ModuleExp))
  256. tr.error('w', "define-private not at top level");
  257. if (bexp2 != null)
  258. return new BeginExp(sexp, bexp2);
  259. return sexp;
  260. }
  261. }