ReaderDispatchSyntaxQuote.java 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. // Copyright (c) 2012 Per M.A. Bothner
  2. // This is free software; for terms and warranty disclaimer see ./COPYING.
  3. package gnu.kawa.lispexpr;
  4. import gnu.kawa.io.InPort;
  5. import gnu.text.*;
  6. import gnu.mapping.*;
  7. import gnu.lists.*;
  8. import gnu.bytecode.Type;
  9. /** Handle special Scheme forms {@code #`}, {@code #'}, and {@code #,}.
  10. * This is because {@code #,} has two meanings:
  11. * (1) equivalent to unsyntax when in the context of a quasisyntax form;
  12. * (2) otherwise a SRFI10 named constructor.
  13. */
  14. public class ReaderDispatchSyntaxQuote extends ReadTableEntry {
  15. static Symbol makeSymbol(String name) {
  16. return Namespace.EmptyNamespace.getSymbol(name);
  17. }
  18. static Symbol syntaxSymbol = makeSymbol("syntax");
  19. static Symbol quasisyntaxSymbol = makeSymbol("quasisyntax");
  20. static Symbol unsyntaxSymbol = makeSymbol("unsyntax");
  21. static Symbol unsyntaxSplicingSymbol = makeSymbol("unsyntax-splicing");
  22. public Object read (Lexer in, int ch, int count)
  23. throws java.io.IOException, SyntaxException {
  24. LispReader reader = (LispReader) in;
  25. switch (ch) {
  26. case ',':
  27. if (reader.inQuasiSyntax) {
  28. return ReaderQuote.read(reader, unsyntaxSymbol,
  29. '@', unsyntaxSplicingSymbol);
  30. } else {
  31. return readNamedConstructor(reader);
  32. }
  33. case '\'':
  34. return ReaderQuote.read(reader, syntaxSymbol, '\0', null);
  35. case '`':
  36. boolean save = reader.inQuasiSyntax;
  37. reader.inQuasiSyntax = true;
  38. try {
  39. return ReaderQuote.read(reader, quasisyntaxSymbol, '\0', null);
  40. } finally {
  41. reader.inQuasiSyntax = save;
  42. }
  43. default:
  44. return null;
  45. }
  46. }
  47. public static Object readNamedConstructor(LispReader reader)
  48. throws java.io.IOException, SyntaxException {
  49. InPort port = reader.getPort();
  50. int length;
  51. String name;
  52. Object list;
  53. if (port.peek() == '('
  54. && ((length
  55. = LList.listLength(list = reader.readObject(), false))
  56. > 0)
  57. && ((Pair) list).getCar() instanceof Symbol) {
  58. name = ((Pair) list).getCar().toString();
  59. Object proc = ReadTable.getCurrent().getReaderCtor(name);
  60. if (proc == null)
  61. reader.error("unknown reader constructor "+name);
  62. else if (! (proc instanceof Procedure || proc instanceof Type))
  63. reader.error("reader constructor must be procedure or type name");
  64. else {
  65. length--; // Subtract 1 for the constructor name.
  66. int parg = proc instanceof Type ? 1 : 0;
  67. Object[] args = new Object[parg+length];
  68. Object argList = ((Pair) list).getCdr();
  69. for (int i = 0; i < length; i++) {
  70. Pair pair = (Pair) argList;
  71. args[parg+i] = pair.getCar();
  72. argList = pair.getCdr();
  73. }
  74. try {
  75. if (parg > 0) {
  76. args[0] = proc;
  77. return gnu.kawa.reflect.Invoke.make.applyN(args);
  78. }
  79. return ((Procedure) proc).applyN(args);
  80. }
  81. catch (Error ex) {
  82. throw ex;
  83. }
  84. catch (Throwable ex) {
  85. reader.error("caught "+ex+" applying reader constructor "+name);
  86. }
  87. }
  88. }
  89. else
  90. reader.error("a non-empty list starting with a symbol must follow #,");
  91. return Boolean.FALSE;
  92. }
  93. }