define_syntax.java 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // Copyright (C) 2005 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.bytecode.ClassType;
  7. import gnu.mapping.*;
  8. import gnu.lists.*;
  9. public class define_syntax extends Syntax
  10. {
  11. int flags;
  12. public static final define_syntax define_macro
  13. = new define_syntax("%define-macro", false);
  14. public static final define_syntax define_syntax
  15. = new define_syntax("%define-syntax", true);
  16. public static final define_syntax define_rewrite_syntax
  17. = new define_syntax("define-rewrite-syntax", Macro.HYGIENIC|Macro.SKIP_SCAN_FORM);
  18. public define_syntax() {
  19. flags = Macro.HYGIENIC;
  20. }
  21. public define_syntax(Object name, int flags) {
  22. super(name);
  23. this.flags = flags;
  24. }
  25. public define_syntax(Object name, boolean hygienic) {
  26. this(name, hygienic ? Macro.HYGIENIC : 0);
  27. }
  28. static ClassType typeMacro = ClassType.make("kawa.lang.Macro");
  29. static PrimProcedure makeHygienic
  30. = new PrimProcedure(typeMacro.getDeclaredMethod("make", 3));
  31. static PrimProcedure makeNonHygienic
  32. = new PrimProcedure(typeMacro.getDeclaredMethod("makeNonHygienic", 3));
  33. static PrimProcedure makeSkipScanForm
  34. = new PrimProcedure(typeMacro.getDeclaredMethod("makeSkipScanForm", 3));
  35. static PrimProcedure setCapturedScope
  36. = new PrimProcedure(typeMacro.getDeclaredMethod("setCapturedScope", 1));
  37. static {
  38. makeHygienic.setSideEffectFree();
  39. makeNonHygienic.setSideEffectFree();
  40. makeSkipScanForm.setSideEffectFree();
  41. }
  42. public void scanForm(Pair st, ScopeExp defs, Translator tr) {
  43. SyntaxForm syntax = null;
  44. Object st_cdr = st.getCdr();
  45. while (st_cdr instanceof SyntaxForm) {
  46. syntax = (SyntaxForm) st_cdr;
  47. st_cdr = syntax.getDatum();
  48. }
  49. Object p = st_cdr;
  50. Object name;
  51. if (p instanceof Pair) {
  52. Pair pp = (Pair) p;
  53. name = pp.getCar();
  54. p = pp.getCdr();
  55. }
  56. else
  57. name = null;
  58. SyntaxForm nameSyntax = syntax;
  59. while (name instanceof SyntaxForm) {
  60. nameSyntax = (SyntaxForm) name;
  61. name = nameSyntax.getDatum();
  62. }
  63. name = tr.namespaceResolve(name);
  64. if (! (name instanceof Symbol)) {
  65. tr.pushForm(tr.syntaxError("missing macro name for "+Translator.safeCar(st)));
  66. return;
  67. }
  68. if (p == null || Translator.safeCdr(p) != LList.Empty) {
  69. tr.pushForm(tr.syntaxError("invalid syntax for "+getName()));
  70. return;
  71. }
  72. Declaration decl = tr.define(name, nameSyntax, defs);
  73. decl.setType(typeMacro);
  74. tr.push(decl);
  75. Macro savedMacro = tr.currentMacroDefinition;
  76. Macro macro = Macro.make(decl);
  77. macro.setFlags(flags);
  78. Expression rule;
  79. ScopeExp scope = syntax != null ? syntax.getScope() : tr.currentScope();
  80. rule = new LangExp(new Object[]{ p, tr, scope });
  81. macro.expander = rule;
  82. // A top-level macro needs (in general) to be compiled into the
  83. // class-file, but for a non-top-level macro it is better to use
  84. // the quoted macro directly to get the right nesting, as we
  85. // do for letrec-syntax.
  86. rule = new QuoteExp(macro);
  87. decl.noteValue(rule);
  88. decl.setProcedureDecl(true);
  89. if (decl.context instanceof ModuleExp) {
  90. SetExp result = new SetExp (decl, rule);
  91. result.setDefining (true);
  92. if (tr.getLanguage().hasSeparateFunctionNamespace())
  93. result.setFuncDef(true);
  94. Object ret = Translator.makePair(st, this,
  95. Translator.makePair(st, result, LList.Empty));
  96. tr.pushForm(ret);
  97. if (tr.immediate) {
  98. Expression[] args =
  99. { new ReferenceExp(decl), new QuoteExp(defs) };
  100. tr.pushForm(new ApplyExp(setCapturedScope, args));
  101. }
  102. } else {
  103. macro.rewriteIfNeeded();
  104. }
  105. }
  106. public Expression rewriteForm(Pair form, Translator tr) {
  107. if (form instanceof Pair) {
  108. Pair p1 = (Pair) form.getCdr();
  109. Object x1 = p1.getCar();
  110. if (x1 instanceof SetExp) {
  111. SetExp sexp = (SetExp) x1;
  112. Object val = sexp.getNewValue().valueIfConstant();
  113. Declaration decl = sexp.getBinding();
  114. Object name = decl.getSymbol();
  115. ScopeExp defs = decl.getContext();
  116. if (val instanceof Macro) {
  117. Macro macro = (Macro) val;
  118. macro.rewriteIfNeeded();
  119. Expression rule = (Expression) macro.expander;
  120. Procedure makeMacroProc =
  121. (flags & Macro.SKIP_SCAN_FORM) != 0 ? makeSkipScanForm
  122. : (flags & Macro.HYGIENIC) != 0 ? makeHygienic
  123. : makeNonHygienic;
  124. if (defs instanceof ModuleExp)
  125. rule = new ApplyExp(makeMacroProc,
  126. new QuoteExp(name),
  127. rule,
  128. ThisExp.makeGivingContext(defs));
  129. sexp.setNewValue(rule);
  130. decl.setValue(rule);
  131. }
  132. return (SetExp) x1;
  133. }
  134. }
  135. return tr.syntaxError("define-syntax not in a body");
  136. }
  137. }