Macro.java 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. package kawa.lang;
  2. import gnu.expr.*;
  3. import gnu.mapping.*;
  4. import gnu.lists.*;
  5. import java.io.*;
  6. import gnu.kawa.format.Printable;
  7. public class Macro extends Syntax implements Printable, Externalizable
  8. {
  9. public Object expander;
  10. Object instance;
  11. public static final int HYGIENIC = 1;
  12. /** If this flag is set, then don't expand during the scan-body phase. */
  13. public static final int SKIP_SCAN_FORM = 2;
  14. private int flags = HYGIENIC;
  15. public final void setFlags(int flags) { this.flags = flags; }
  16. public final boolean isHygienic() { return (flags & HYGIENIC) != 0; }
  17. public final void setHygienic(boolean hygienic) {
  18. if (hygienic)
  19. flags |= HYGIENIC;
  20. else
  21. flags &= ~HYGIENIC;
  22. }
  23. ScopeExp capturedScope;
  24. public ScopeExp getCapturedScope() {
  25. if (capturedScope == null) {
  26. if (instance instanceof ModuleExp) // possibly if immediate.
  27. capturedScope = (ModuleExp) instance;
  28. else if (instance instanceof Class)
  29. capturedScope = ModuleManager.findWithClass((Class) instance).getModuleExp();
  30. else if (instance != null)
  31. capturedScope = ModuleInfo.findFromInstance(instance).getModuleExp();
  32. }
  33. return capturedScope;
  34. }
  35. public void setCapturedScope(ScopeExp scope) {
  36. capturedScope = scope;
  37. }
  38. public static Macro make(Declaration decl) {
  39. Macro mac = new Macro(decl.getSymbol());
  40. decl.setSyntax();
  41. mac.capturedScope = decl.context;
  42. return mac;
  43. }
  44. public static Macro makeNonHygienic(Object name, Procedure expander) {
  45. Macro mac = new Macro(name, expander);
  46. mac.setHygienic(false);
  47. return mac;
  48. }
  49. public static Macro makeNonHygienic(Object name, Procedure expander,
  50. Object instance) {
  51. Macro mac = new Macro(name, expander);
  52. mac.setHygienic(false);
  53. mac.instance = instance;
  54. return mac;
  55. }
  56. public static Macro makeSkipScanForm(Object name, Procedure expander,
  57. Object instance) {
  58. Macro mac = new Macro(name, expander);
  59. mac.flags = HYGIENIC|SKIP_SCAN_FORM;
  60. mac.instance = instance;
  61. return mac;
  62. }
  63. public static Macro make(Object name, Procedure expander) {
  64. return new Macro(name, expander);
  65. }
  66. public static Macro make(Object name, Procedure expander,
  67. Object instance) {
  68. Macro mac = new Macro(name, expander);
  69. mac.instance = instance;
  70. return mac;
  71. }
  72. public Macro() {
  73. }
  74. /** Copy constructor. */
  75. public Macro(Macro old) {
  76. name = old.name;
  77. expander = old.expander;
  78. flags = old.flags;
  79. }
  80. public Macro(Object name, Procedure expander) {
  81. super(name);
  82. this.expander = expander instanceof Expression ? expander
  83. : new QuoteExp(expander);
  84. }
  85. public Macro(Object name) {
  86. super(name);
  87. }
  88. public gnu.expr.Expression rewriteForm(Pair form, Translator tr) {
  89. return tr.rewrite(expand(form, tr), 'N');
  90. }
  91. public String toString() {
  92. return "#<macro "+getName()+'>';
  93. }
  94. public void print(Consumer out) {
  95. out.write("#<macro ");
  96. out.write(getName());
  97. out.write ('>');
  98. }
  99. public Object rewriteIfNeeded() {
  100. Object exp = expander;
  101. if (exp instanceof LangExp) {
  102. Object[] lval = (Object[]) ((LangExp) exp).getLangValue();
  103. Object p = lval[0];
  104. Translator xtr = (Translator) lval[1];
  105. ScopeExp scope = (ScopeExp) lval[2];
  106. Macro savedMacro = xtr.currentMacroDefinition;
  107. Compilation savedComp = Compilation.getCurrent();
  108. xtr.currentMacroDefinition = this;
  109. Compilation.setCurrent(xtr);
  110. Expression rule;
  111. ScopeExp savedScope = xtr.setPushCurrentScope(scope);
  112. try {
  113. rule = xtr.rewrite_car((Pair) p, false);
  114. } finally {
  115. xtr.setPopCurrentScope(savedScope);
  116. xtr.currentMacroDefinition = savedMacro;
  117. Compilation.setCurrent(savedComp);
  118. }
  119. if (rule instanceof LambdaExp)
  120. ((LambdaExp) rule).setFlag(LambdaExp.NO_FIELD);
  121. expander = exp = rule;
  122. }
  123. return exp;
  124. }
  125. public Object expand(Object form, Translator tr) {
  126. Object savedMacroMark = tr.currentMacroMark;
  127. tr.currentMacroMark = new Object();
  128. try {
  129. Procedure pr;
  130. Object exp = expander;
  131. if (exp instanceof Procedure && ! (exp instanceof Expression))
  132. pr = (Procedure) exp;
  133. else {
  134. exp = rewriteIfNeeded();
  135. if (! (exp instanceof Expression)) {
  136. Macro savedMacro = tr.currentMacroDefinition;
  137. tr.currentMacroDefinition = this;
  138. try {
  139. exp = tr.rewrite(exp);
  140. expander = exp;
  141. } finally {
  142. tr.currentMacroDefinition = savedMacro;
  143. }
  144. }
  145. /* DEBUGGING:
  146. if (exp instanceof LambdaExp) {
  147. System.err.println("expand "+this+" expander:"+exp);
  148. System.err.flush();
  149. gnu.kawa.io.OutPort dout = gnu.kawa.io.OutPort.errDefault();
  150. dout.flush();
  151. ((Expression) exp).print(dout);
  152. dout.println(']');
  153. dout.flush();
  154. }
  155. */
  156. pr = (Procedure)
  157. ((Expression) exp).eval(tr.getGlobalEnvironment());
  158. }
  159. Object result;
  160. if (! isHygienic()) {
  161. form = Quote.quote(form, tr);
  162. int nargs = Translator.listLength(form) - 1;
  163. if (nargs < 0)
  164. return tr.syntaxError("invalid macro argument list to "+this);
  165. CallContext ctx = CallContext.getInstance();
  166. ctx.setupApply(pr);
  167. form = ((Pair) form).getCdr();
  168. for (int i = 0; i < nargs; i++) {
  169. Pair pair = (Pair) form;
  170. Object arg = pair.getCar();
  171. if (arg instanceof Keyword && i + 1 < nargs) {
  172. String key = ((Keyword) arg).getName();
  173. pair = (Pair) pair.getCdr();
  174. ctx.addKey(key, pair.getCar());
  175. i++;
  176. } else
  177. ctx.add(arg);
  178. form = pair.getCdr();
  179. }
  180. result = ctx.runUntilValue();
  181. }
  182. else
  183. result = pr.apply1(form);
  184. return result;
  185. } catch (Throwable ex) {
  186. String msg = "evaluating syntax transformer '"
  187. + getName() + "' threw " + ex;
  188. tr.getMessages().error('e', msg, ex);
  189. return new ErrorExp(msg);
  190. } finally {
  191. tr.currentMacroMark = savedMacroMark;
  192. }
  193. }
  194. public void scanForm(Pair st, ScopeExp defs, Translator tr) {
  195. if ((flags & SKIP_SCAN_FORM) != 0) {
  196. super.scanForm(st, defs, tr);
  197. return;
  198. }
  199. Syntax saveSyntax = tr.currentSyntax;
  200. try {
  201. tr.currentSyntax = this;
  202. Object x = expand(st, tr);
  203. tr.scanForm(x, defs);
  204. } finally {
  205. tr.currentSyntax = saveSyntax;
  206. }
  207. }
  208. /**
  209. * @serialData Write the name followed by the expansion procedure,
  210. * both using writeObject.
  211. */
  212. public void writeExternal(ObjectOutput out) throws IOException {
  213. out.writeObject(getName());
  214. out.writeObject(((QuoteExp) expander).getValue());
  215. }
  216. public void readExternal(ObjectInput in)
  217. throws IOException, ClassNotFoundException {
  218. setName((String) in.readObject());
  219. expander = new QuoteExp(in.readObject());
  220. }
  221. }