syntax.scm 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. ; Copyright (c) 1993-2007 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; Rewrite-rule compiler (a.k.a. "extend-syntax")
  3. ; Example:
  4. ;
  5. ; (define-syntax or
  6. ; (syntax-rules ()
  7. ; ((or) #f)
  8. ; ((or e) e)
  9. ; ((or e1 e ...) (let ((temp e1))
  10. ; (if temp temp (or e ...))))))
  11. (define-syntax syntax-rules
  12. (let ()
  13. (define name? symbol?)
  14. (define (segment-pattern? pattern)
  15. (and (segment-template? pattern)
  16. (or (null? (cddr pattern))
  17. (syntax-error "segment matching not implemented" pattern))))
  18. (define (segment-template? pattern)
  19. (and (pair? pattern)
  20. (pair? (cdr pattern))
  21. (memq (cadr pattern) indicators-for-zero-or-more)))
  22. (define indicators-for-zero-or-more (list (string->symbol "...") '---))
  23. (lambda (exp r c)
  24. (define %input (r '%input)) ;Gensym these, if you like.
  25. (define %compare (r '%compare))
  26. (define %rename (r '%rename))
  27. (define %tail (r '%tail))
  28. (define %temp (r '%temp))
  29. (define rules (cddr exp))
  30. (define subkeywords (cadr exp))
  31. (define (make-transformer rules)
  32. `(lambda (,%input ,%rename ,%compare)
  33. (let ((,%tail (cdr ,%input)))
  34. (cond ,@(map process-rule rules)
  35. (else
  36. (syntax-error
  37. "use of macro doesn't match definition"
  38. ,%input))))))
  39. (define (process-rule rule)
  40. (if (and (pair? rule)
  41. (pair? (cdr rule))
  42. (null? (cddr rule)))
  43. (let ((pattern (cdar rule))
  44. (template (cadr rule)))
  45. `((and ,@(process-match %tail pattern))
  46. (let* ,(process-pattern pattern
  47. %tail
  48. (lambda (x) x))
  49. ,(process-template template
  50. 0
  51. (meta-variables pattern 0 '())))))
  52. (syntax-error "ill-formed syntax rule" rule)))
  53. ; Generate code to test whether input expression matches pattern
  54. (define (process-match input pattern)
  55. (cond ((name? pattern)
  56. (if (member pattern subkeywords)
  57. `((,%compare ,input (,%rename ',pattern)))
  58. `()))
  59. ((segment-pattern? pattern)
  60. (process-segment-match input (car pattern)))
  61. ((pair? pattern)
  62. `((let ((,%temp ,input))
  63. (and (pair? ,%temp)
  64. ,@(process-match `(car ,%temp) (car pattern))
  65. ,@(process-match `(cdr ,%temp) (cdr pattern))))))
  66. ((or (null? pattern) (boolean? pattern) (char? pattern))
  67. `((eq? ,input ',pattern)))
  68. (else
  69. `((equal? ,input ',pattern)))))
  70. (define (process-segment-match input pattern)
  71. (let ((conjuncts (process-match '(car l) pattern)))
  72. (if (null? conjuncts)
  73. `((list? ,input)) ;+++
  74. `((let loop ((l ,input))
  75. (or (null? l)
  76. (and (pair? l)
  77. ,@conjuncts
  78. (loop (cdr l)))))))))
  79. ; Generate code to take apart the input expression
  80. ; This is pretty bad, but it seems to work (can't say why).
  81. (define (process-pattern pattern path mapit)
  82. (cond ((name? pattern)
  83. (if (memq pattern subkeywords)
  84. '()
  85. (list (list pattern (mapit path)))))
  86. ((segment-pattern? pattern)
  87. (process-pattern (car pattern)
  88. %temp
  89. (lambda (x) ;temp is free in x
  90. (mapit (if (eq? %temp x)
  91. path ;+++
  92. `(map (lambda (,%temp) ,x)
  93. ,path))))))
  94. ((pair? pattern)
  95. (append (process-pattern (car pattern) `(car ,path) mapit)
  96. (process-pattern (cdr pattern) `(cdr ,path) mapit)))
  97. (else '())))
  98. ; Generate code to compose the output expression according to template
  99. (define (process-template template rank env)
  100. (cond ((name? template)
  101. (let ((probe (assq template env)))
  102. (if probe
  103. (if (<= (cdr probe) rank)
  104. template
  105. (syntax-error "template rank error (too few ...'s?)"
  106. template))
  107. `(,%rename ',template))))
  108. ((segment-template? template)
  109. (let ((vars
  110. (free-meta-variables (car template) (+ rank 1) env '())))
  111. (if (null? vars)
  112. (syntax-error "too many ...'s" template)
  113. (let* ((x (process-template (car template)
  114. (+ rank 1)
  115. env))
  116. (gen (if (equal? (list x) vars)
  117. x ;+++
  118. `(map (lambda ,vars ,x)
  119. ,@vars))))
  120. (if (null? (cddr template))
  121. gen ;+++
  122. `(append ,gen ,(process-template (cddr template)
  123. rank env)))))))
  124. ((pair? template)
  125. `(cons ,(process-template (car template) rank env)
  126. ,(process-template (cdr template) rank env)))
  127. (else `(quote ,template))))
  128. ; Return an association list of (var . rank)
  129. (define (meta-variables pattern rank vars)
  130. (cond ((name? pattern)
  131. (if (memq pattern subkeywords)
  132. vars
  133. (cons (cons pattern rank) vars)))
  134. ((segment-pattern? pattern)
  135. (meta-variables (car pattern) (+ rank 1) vars))
  136. ((pair? pattern)
  137. (meta-variables (car pattern) rank
  138. (meta-variables (cdr pattern) rank vars)))
  139. (else vars)))
  140. ; Return a list of meta-variables of given higher rank
  141. (define (free-meta-variables template rank env free)
  142. (cond ((name? template)
  143. (if (and (not (memq template free))
  144. (let ((probe (assq template env)))
  145. (and probe (>= (cdr probe) rank))))
  146. (cons template free)
  147. free))
  148. ((segment-template? template)
  149. (free-meta-variables (car template)
  150. rank env
  151. (free-meta-variables (cddr template)
  152. rank env free)))
  153. ((pair? template)
  154. (free-meta-variables (car template)
  155. rank env
  156. (free-meta-variables (cdr template)
  157. rank env free)))
  158. (else free)))
  159. c ;ignored
  160. ;; Kludge for Scheme 48 static linker.
  161. ;; `(cons ,(make-transformer rules)
  162. ;; ',(find-free-names-in-syntax-rules subkeywords rules))
  163. (make-transformer rules))))