SyntaxForms.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. // Copyright (c) 2009, 2013 Per M.A. Bothner.
  2. // This is free software; for terms and warranty disclaimer see ../../COPYING.
  3. package kawa.lang;
  4. import gnu.expr.*;
  5. import gnu.mapping.Symbol;
  6. import gnu.lists.*;
  7. import gnu.text.SourceLocator;
  8. import java.io.*;
  9. /**
  10. * Helper method and implementation classes for SyntaxForm.
  11. * @author Per Bothner
  12. */
  13. public class SyntaxForms {
  14. public static Object makeForm (Object datum, TemplateScope scope) {
  15. if (datum instanceof SyntaxForm || datum == LList.Empty
  16. // Self-evaluating values don't need to be wrapped
  17. // This is an approximation - can be tweaked later.
  18. || datum instanceof Number || datum instanceof Keyword
  19. || scope == null)
  20. return datum;
  21. if (datum instanceof PairWithPosition)
  22. return new PairWithPositionSyntaxForm((PairWithPosition) datum,
  23. scope);
  24. if (datum instanceof Pair)
  25. return new PairSyntaxForm((Pair) datum, scope);
  26. /* FUTURE
  27. if (datum instanceof Symbol)
  28. return scope.getAliasSymbol((Symbol) datum);
  29. */
  30. return new SimpleSyntaxForm(datum, scope);
  31. }
  32. /** Create a syntax object with specified datum, and given syntatic context.
  33. * Used to implement {@code datum->syntax}.
  34. * @param template If this is a {@code SyntaxForm}, use its scope;
  35. * otherwise use the current {@code Compilation}'s current scope.
  36. * (This means just returning the datum as-is.)
  37. * @param datum The value (S-expression datum) to use.
  38. * @param srcloc Used to set source location (line number etc).
  39. * Ignored if null; otherwise should be a {@code SourceLocator}.
  40. */
  41. public static Object makeWithTemplate(Object template, Object datum,
  42. Object srcloc) {
  43. if (srcloc instanceof SourceLocator
  44. && datum instanceof Pair) {
  45. Pair pdatum = (Pair) datum;
  46. SourceLocator sloc = (SourceLocator) srcloc;
  47. if (template instanceof SyntaxForm)
  48. return new PairWithPositionSyntaxForm(pdatum, sloc,
  49. ((SyntaxForm) template).getScope());
  50. else
  51. return new PairWithPosition(sloc, pdatum.getCar(), pdatum.getCdr());
  52. }
  53. if (datum instanceof SyntaxForm)
  54. return (SyntaxForm) datum;
  55. if (template instanceof SyntaxForm) {
  56. SyntaxForm sdatum = (SyntaxForm) template;
  57. if (datum == sdatum.getDatum())
  58. return sdatum;
  59. return fromDatum(datum, sdatum);
  60. }
  61. return datum;
  62. }
  63. public static Object makeWithTemplate(Object template, Object form) {
  64. return makeWithTemplate(template, form, null);
  65. }
  66. /** Utility method to implement Scheme free-identifier=? and bound-identifier=?.
  67. * @param id1 An identifier - either a symbol or a SyntaxForm whose form is a symbol. We assume it satisfies the Scheme predicate identifier?.
  68. * @param id2 The other identifier to compare against.
  69. * @param checkBound true for bound-identifier=? and false for free-identifier=?.
  70. */
  71. public static boolean identifierEquals (Object id1, Object id2, boolean checkBound) {
  72. Compilation comp = (Translator) Compilation.getCurrent();
  73. Object s1, s2;
  74. TemplateScope sc1, sc2;
  75. if (id1 instanceof SyntaxForm) {
  76. SyntaxForm sf = (SyntaxForm) id1;
  77. s1 = sf.getDatum();
  78. sc1 = sf.getScope();
  79. }
  80. else {
  81. s1 = id1;
  82. sc1 = null;
  83. }
  84. if (id2 instanceof SyntaxForm) {
  85. SyntaxForm sf = (SyntaxForm) id2;
  86. s2 = sf.getDatum();
  87. sc2 = sf.getScope();
  88. }
  89. else {
  90. s2 = id2;
  91. sc2 = null;
  92. }
  93. if (s1 != s2)
  94. return false;
  95. if (sc1 == sc2)
  96. return true;
  97. if (checkBound) {
  98. // Note that SRFI-72 specifies:
  99. // (bound-identifier=? (syntax x) (syntax x)) => #f
  100. // but MzScheme/Racket and Chez Scheme return #t.
  101. // SRFI-72 says: "Two identifiers will also be bound-identifier=?
  102. // if they were produced from existing bound-identifier=?
  103. // identifiers during a single evaluation of the same syntax or
  104. // quasisyntax form ..."
  105. // but R6RS specifies bound-identifier=? in terms of "marks"
  106. // which are applied when a transformer is applied, thus two
  107. // syntax forms in the same transformer have the same marks.
  108. Object mark1 = sc1 != null ? sc1.macroMark : null;
  109. Object mark2 = sc2 != null ? sc2.macroMark : null;
  110. return mark1 == mark2;
  111. }
  112. ScopeExp savedScope = comp.currentScope();
  113. if (sc1 != null)
  114. comp.setCurrentScope(sc1);
  115. Declaration d1 = comp.lexical.lookup(s1, -1);
  116. comp.setCurrentScope(sc2 != null ? sc2 : savedScope);
  117. Declaration d2 = comp.lexical.lookup(s2, -1);
  118. if (sc2 != null)
  119. comp.setCurrentScope(savedScope);
  120. return d1 == d2;
  121. }
  122. public static boolean isIdentifier (SyntaxForm form)
  123. {
  124. return form.getDatum() instanceof Symbol;
  125. }
  126. /** Make a SyntaxForm object with the same contextual information as this.
  127. * @param datum which used for the new syntax value.
  128. * Corresponds to the <code>datum-&gt;syntax-object</code> function.
  129. */
  130. public static Object fromDatum (Object datum, SyntaxForm template)
  131. {
  132. return SyntaxForms.makeForm(datum, template.getScope());
  133. }
  134. public static Object fromDatumIfNeeded(Object datum, SyntaxForm template) {
  135. if (datum instanceof SyntaxForm || template == null)
  136. return datum;
  137. else if (datum == template.getDatum())
  138. return template;
  139. else
  140. return SyntaxForms.fromDatum(datum, template);
  141. }
  142. public static Expression rewrite (Object x)
  143. {
  144. Translator tr = (Translator) Compilation.getCurrent();
  145. return tr.rewrite(x);
  146. }
  147. public static Expression rewriteCar (Object x)
  148. {
  149. Translator tr = (Translator) Compilation.getCurrent();
  150. return tr.rewrite_car((Pair) x, false);
  151. }
  152. public static Expression rewriteBody (Object x)
  153. {
  154. Translator tr = (Translator) Compilation.getCurrent();
  155. return tr.rewrite_body(x);
  156. }
  157. public static final boolean DEBUGGING = true;
  158. public static String toString (SyntaxForm sform, String id)
  159. {
  160. StringBuilder sbuf = new StringBuilder("#<syntax");
  161. if (DEBUGGING && id != null)
  162. {
  163. sbuf.append('#');
  164. sbuf.append(id);
  165. }
  166. sbuf.append(' ');
  167. sbuf.append(sform.getDatum());
  168. if (DEBUGGING)
  169. {
  170. TemplateScope scope = sform.getScope();
  171. if (scope == null)
  172. {
  173. sbuf.append(" in null");
  174. }
  175. else
  176. {
  177. sbuf.append(" in #");
  178. sbuf.append(scope.id);
  179. }
  180. }
  181. sbuf.append(">");
  182. return sbuf.toString();
  183. }
  184. public static class SimpleSyntaxForm implements SyntaxForm, Externalizable {
  185. private Object datum;
  186. private TemplateScope scope;
  187. // DEBUGGING:
  188. static int counter;
  189. int id = ++counter;
  190. public SimpleSyntaxForm(Object datum, TemplateScope scope) {
  191. this.datum = datum;
  192. this.scope = scope;
  193. }
  194. public Object getDatum() {
  195. return datum;
  196. }
  197. public TemplateScope getScope() {
  198. return scope;
  199. }
  200. public String toString() {
  201. String sid = DEBUGGING ? Integer.toString(id) : null;
  202. return SyntaxForms.toString(this, sid);
  203. }
  204. public void writeExternal(ObjectOutput out) throws IOException {
  205. out.writeObject(datum);
  206. out.writeObject(scope);
  207. }
  208. public void readExternal(ObjectInput in)
  209. throws IOException, ClassNotFoundException {
  210. datum = in.readObject();
  211. scope = (TemplateScope) in.readObject();
  212. }
  213. }
  214. public static class PairSyntaxForm extends ImmutablePair
  215. implements SyntaxForm, Externalizable {
  216. private Pair datum;
  217. private TemplateScope scope;
  218. public PairSyntaxForm(Pair datum, TemplateScope scope) {
  219. this.datum = datum;
  220. this.scope = scope;
  221. }
  222. public Object getDatum() {
  223. return datum;
  224. }
  225. public TemplateScope getScope() {
  226. return scope;
  227. }
  228. public Object getCar() {
  229. if (car == null)
  230. car = SyntaxForms.makeForm(datum.getCar(), scope);
  231. return car;
  232. }
  233. public Object getCdr() {
  234. if (cdr == null)
  235. cdr = SyntaxForms.makeForm(datum.getCdr(), scope);
  236. return cdr;
  237. }
  238. public String toString() {
  239. //String sid = DEBUGGING ? Integer.toString(id) : null;
  240. return SyntaxForms.toString(this, null);
  241. }
  242. public void writeExternal(ObjectOutput out) throws IOException {
  243. out.writeObject(datum);
  244. out.writeObject(scope);
  245. }
  246. public void readExternal(ObjectInput in)
  247. throws IOException, ClassNotFoundException {
  248. datum = (Pair) in.readObject();
  249. scope = (TemplateScope) in.readObject();
  250. }
  251. }
  252. public static class PairWithPositionSyntaxForm extends PairWithPosition
  253. implements SyntaxForm, SourceLocator, Externalizable {
  254. private PairWithPosition datum;
  255. private TemplateScope scope;
  256. public PairWithPositionSyntaxForm(PairWithPosition datum,
  257. TemplateScope scope) {
  258. // The inherited car and cdr fields are initialized to null
  259. // because they're used as caches -
  260. // see the getCar and getCdr methods below
  261. super(datum, null, null);
  262. this.datum = datum;
  263. this.scope = scope;
  264. }
  265. public PairWithPositionSyntaxForm(Pair datum,
  266. SourceLocator where,
  267. TemplateScope scope) {
  268. this(new PairWithPosition(where, datum.getCar(), datum.getCdr()),
  269. scope);
  270. }
  271. public Object getDatum() {
  272. return datum;
  273. }
  274. public TemplateScope getScope() {
  275. return scope;
  276. }
  277. public Object getCar () {
  278. if (car == null)
  279. car = SyntaxForms.makeForm(datum.getCar(), scope);
  280. return car;
  281. }
  282. public Object getCdr () {
  283. if (cdr == null)
  284. cdr = SyntaxForms.makeForm(datum.getCdr(), scope);
  285. return cdr;
  286. }
  287. public String toString () {
  288. //String sid = DEBUGGING ? Integer.toString(id) : null;
  289. return SyntaxForms.toString(this, null);
  290. }
  291. public void writeExternal(ObjectOutput out) throws IOException {
  292. out.writeObject(datum);
  293. out.writeObject(scope);
  294. }
  295. public void readExternal(ObjectInput in)
  296. throws IOException, ClassNotFoundException {
  297. datum = (PairWithPosition) in.readObject();
  298. scope = (TemplateScope) in.readObject();
  299. }
  300. }
  301. // TODO: static class VectorSyntaxForm ...
  302. }