let.java 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. package kawa.standard;
  2. import kawa.lang.*;
  3. import gnu.lists.*;
  4. import gnu.mapping.*;
  5. import gnu.expr.*;
  6. import gnu.bytecode.*;
  7. import java.util.ArrayList;
  8. import java.util.Stack;
  9. /**
  10. * The Syntax transformer that re-writes the Scheme "let" primitive.
  11. * This only handles standard "unnamed" let.
  12. * The let macro in ../lib/let.scm handles named let as well.
  13. * @author Per Bothner
  14. */
  15. public class let extends Syntax {
  16. public static final let let = new let("let", false);
  17. /**
  18. * Used for constructs such as FLET, where we intend to set a
  19. * function binding rather than an ordinary binding.
  20. */
  21. protected boolean settingProcedures;
  22. public let(String name, boolean settingProcedures) {
  23. this.setName(name);
  24. this.settingProcedures = settingProcedures;
  25. }
  26. @Override
  27. public Expression rewrite (Object obj, final Translator tr) {
  28. final ArrayList<Declaration> decls = new ArrayList<Declaration>();
  29. final Stack<Declaration> renamedAliases = new Stack<Declaration>();
  30. // Used to check for duplicate definitions.
  31. final SimpleEnvironment dupenv = new SimpleEnvironment();
  32. final LetExp let = new LetExp();
  33. BindDecls bindDecls =
  34. new BindDecls() {
  35. @Override
  36. public Declaration define(Symbol name,
  37. TemplateScope templateScope,
  38. ScopeExp defs, Translator comp) {
  39. Declaration decl = new Declaration(name);
  40. Object old = dupenv.get(name, templateScope, null);
  41. if (old != null)
  42. ScopeExp.duplicateDeclarationError((Declaration) old,
  43. decl, tr);
  44. dupenv.put(name, templateScope, decl);
  45. let.add(decl);
  46. decl.setFlag(Declaration.IS_SINGLE_VALUE);
  47. if (templateScope != null) {
  48. renamedAliases.push
  49. (tr.makeRenamedAlias(decl, templateScope));
  50. }
  51. return decl;
  52. }
  53. };
  54. bindDecls.allowShadowing = true;
  55. bindDecls.makeConstant = false;
  56. if (! (obj instanceof Pair))
  57. return tr.syntaxError ("missing " + getName() + " arguments");
  58. Pair pair = (Pair) obj;
  59. Object bindings = pair.getCar();
  60. Object body = pair.getCdr();
  61. for (;;) {
  62. if (bindings == LList.Empty)
  63. break;
  64. if (! (bindings instanceof Pair))
  65. return tr.syntaxError("bindings not a proper list");
  66. Pair bind_pair = (Pair) bindings;
  67. Object bind_pair_car = bind_pair.getCar();
  68. if (! (bind_pair_car instanceof Pair))
  69. return tr.syntaxError (getName() +
  70. " binding is not a pair:"+bind_pair_car);
  71. Pair binding = (Pair) bind_pair_car;
  72. Object saveLoc1 = tr.pushPositionOf(binding);
  73. Object[] r = bindDecls.parsePatternCar(binding, 0, let, tr);
  74. Object binding_cdr = r[0];
  75. Declaration decl = (Declaration) r[1];
  76. maybeSetProcedure(decl);
  77. if (binding_cdr instanceof Pair) {
  78. Pair init = (Pair) binding_cdr;
  79. binding_cdr = init.getCdr();
  80. Expression initExp = tr.rewrite_car(init, false);
  81. if (decl != null) { // paranoia
  82. decl.setInitValue(initExp);
  83. if (initExp != QuoteExp.undefined_exp)
  84. decl.noteValueFromLet(let);
  85. }
  86. if (init.getCdr() != LList.Empty) {
  87. Object saveLoc2 = tr.pushPositionOf(init.getCdr());
  88. tr.error('e', "junk after initializer");
  89. tr.popPositionOf(saveLoc2);
  90. }
  91. } else {
  92. tr.error('e', "let has no initializer");
  93. }
  94. tr.popPositionOf(saveLoc1);
  95. bindings = bind_pair.getCdr();
  96. }
  97. int renamedAliasesCount = renamedAliases.size();
  98. for (int i = renamedAliasesCount; --i >= 0; )
  99. tr.pushRenamedAlias(renamedAliases.pop());
  100. tr.push(let);
  101. try {
  102. let.setBody(tr.rewrite_body(body));
  103. } finally {
  104. tr.pop(let);
  105. tr.popRenamedAlias(renamedAliasesCount);
  106. }
  107. return let;
  108. }
  109. /**
  110. * Set the procedure flag of a declaration if binding a function property.
  111. *
  112. * This is used for FLET .vs. LET distinction, where {@code settingProcedures}
  113. * is true for FLET, and false for LET.
  114. *
  115. * @param decl The declaration to possibly set the {@code PROCEDURE} flag.
  116. */
  117. protected void maybeSetProcedure (Declaration decl)
  118. {
  119. if (settingProcedures)
  120. decl.setProcedureDecl(true);
  121. }
  122. }