/collects/deinprogramm/signature/module-begin.rkt

http://github.com/gmarceau/PLT · Racket · 209 lines · 176 code · 13 blank · 20 comment · 15 complexity · 74c842386bc7ac48cfc5633abb83e641 MD5 · raw file

  1. #lang scheme/base
  2. (provide module-begin)
  3. (require deinprogramm/define-record-procedures
  4. deinprogramm/signature/signature
  5. deinprogramm/signature/signature-syntax)
  6. (require (for-syntax scheme/base)
  7. (for-syntax racket/list)
  8. (for-syntax syntax/boundmap)
  9. (for-syntax syntax/kerncase))
  10. (define-syntax (print-results stx)
  11. (syntax-case stx ()
  12. ((_ expr)
  13. (not (or (syntax-property #'expr 'stepper-hide-completed)
  14. (syntax-property #'expr 'stepper-skip-completely)
  15. (syntax-property #'expr 'test-call)))
  16. (syntax-property
  17. (syntax-property
  18. #'(#%app call-with-values (lambda () expr)
  19. do-print-results)
  20. 'stepper-skipto
  21. '(syntax-e cdr cdr car syntax-e cdr cdr car))
  22. 'certify-mode
  23. 'transparent))
  24. ((_ expr) #'expr)))
  25. (define (do-print-results . vs)
  26. (for-each (current-print) vs)
  27. ;; Returning 0 values avoids any further result printing
  28. ;; (even if void values are printed)
  29. (values))
  30. (define-syntaxes (module-begin module-continue)
  31. (let ()
  32. ;; takes a list of syntax objects (the result of syntax-e) and returns all the syntax objects that correspond to
  33. ;; a signature declaration. Syntax: (: id signature)
  34. (define extract-signatures
  35. (lambda (lostx)
  36. (let* ((table (make-bound-identifier-mapping))
  37. (non-signatures
  38. (filter-map (lambda (maybe)
  39. (syntax-case maybe (:)
  40. ((: ?exp ?sig)
  41. (not (identifier? #'?exp))
  42. #'(apply-signature/blame (signature ?sig) ?exp))
  43. ((: ?id ?sig)
  44. (begin
  45. (cond
  46. ((bound-identifier-mapping-get table #'?id (lambda () #f))
  47. => (lambda (old-sig-stx)
  48. (unless (equal? (syntax->datum old-sig-stx)
  49. (syntax->datum #'?sig))
  50. (raise-syntax-error #f
  51. "Zweite Signaturdeklaration fĂźr denselben Namen."
  52. maybe))))
  53. (else
  54. (bound-identifier-mapping-put! table #'?id #'?sig)))
  55. #f))
  56. ((: ?id)
  57. (raise-syntax-error #f "Bei dieser Signaturdeklaration fehlt die Signatur" maybe))
  58. ((: ?id ?sig ?stuff0 ?stuff1 ...)
  59. (raise-syntax-error #f "In der :-Form werden ein Name und eine Signatur erwartet; da steht noch mehr"
  60. (syntax/loc #'?stuff0
  61. (?stuff0 ?stuff1 ...))))
  62. (_ maybe)))
  63. lostx)))
  64. (values table non-signatures))))
  65. (define local-expand-stop-list
  66. (append (list #': #'define-contract
  67. #'#%require #'#%provide)
  68. (kernel-form-identifier-list)))
  69. (define (expand-signature-expressions signature-table expressions)
  70. (let loop ((exprs expressions))
  71. (cond
  72. ((null? exprs)
  73. (bound-identifier-mapping-for-each signature-table
  74. (lambda (id thing)
  75. (when thing
  76. (if (identifier-binding id)
  77. (raise-syntax-error #f "Zu einer eingebauten Form kann keine Signatur deklariert werden" id)
  78. (raise-syntax-error #f "Zu dieser Signatur gibt es keine Definition" id)))))
  79. #'(begin))
  80. (else
  81. (let ((expanded (car exprs)))
  82. (syntax-case expanded (begin define-values)
  83. ((define-values (?id ...) ?e1)
  84. (with-syntax (((?enforced ...)
  85. (map (lambda (id)
  86. (cond
  87. ((bound-identifier-mapping-get signature-table id (lambda () #f))
  88. => (lambda (sig)
  89. (bound-identifier-mapping-put! signature-table id #f) ; check for orphaned signatures
  90. (with-syntax ((?id id)
  91. (?sig sig))
  92. #'(?id (signature ?sig)))))
  93. (else
  94. id)))
  95. (syntax->list #'(?id ...))))
  96. (?rest (loop (cdr exprs))))
  97. (with-syntax ((?defn
  98. (syntax-track-origin
  99. #'(define-values/signature (?enforced ...)
  100. ?e1)
  101. (car exprs)
  102. (car (syntax-e expanded)))))
  103. (syntax/loc (car exprs)
  104. (begin
  105. ?defn
  106. ?rest)))))
  107. ((begin e1 ...)
  108. (loop (append (syntax-e (syntax (e1 ...))) (cdr exprs))))
  109. (else
  110. (with-syntax ((?first expanded)
  111. (?rest (loop (cdr exprs))))
  112. (syntax/loc (car exprs)
  113. (begin
  114. ?first ?rest))))))))))
  115. (values
  116. ;; module-begin
  117. (lambda (stx)
  118. (syntax-case stx ()
  119. ((_ e1 ...)
  120. ;; module-begin-continue takes a sequence of expanded
  121. ;; exprs and a sequence of to-expand exprs; that way,
  122. ;; the module-expansion machinery can be used to handle
  123. ;; requires, etc.:
  124. #`(#%plain-module-begin
  125. (module-continue (e1 ...) () ())))))
  126. ;; module-continue
  127. (lambda (stx)
  128. (syntax-case stx ()
  129. ((_ () (e1 ...) (defined-id ...))
  130. ;; Local-expanded all body elements, lifted out requires, etc.
  131. ;; Now process the result.
  132. (begin
  133. ;; The expansion for signatures breaks the way that beginner-define, etc.,
  134. ;; check for duplicate definitions, so we have to re-check here.
  135. ;; A better strategy might be to turn every define into a define-syntax
  136. ;; to redirect the binding, and then the identifier-binding check in
  137. ;; beginner-define, etc. will work.
  138. (let ((defined-ids (make-bound-identifier-mapping)))
  139. (for-each (lambda (id)
  140. (when (bound-identifier-mapping-get defined-ids id (lambda () #f))
  141. (raise-syntax-error
  142. #f
  143. "FĂźr diesen Namen gibt es schon eine Definition."
  144. id))
  145. (bound-identifier-mapping-put! defined-ids id #t))
  146. (reverse (syntax->list #'(defined-id ...)))))
  147. ;; Now handle signatures:
  148. (let ((top-level (reverse (syntax->list (syntax (e1 ...))))))
  149. (let-values (((sig-table expr-list)
  150. (extract-signatures top-level)))
  151. (expand-signature-expressions sig-table expr-list)))))
  152. ((frm e3s e1s def-ids)
  153. (let loop ((e3s #'e3s)
  154. (e1s #'e1s)
  155. (def-ids #'def-ids))
  156. (syntax-case e3s ()
  157. (()
  158. #`(frm () #,e1s #,def-ids))
  159. ((e2 . e3s)
  160. (let ((e2 (local-expand #'e2 'module local-expand-stop-list)))
  161. ;; Lift out certain forms to make them visible to the module
  162. ;; expander:
  163. (syntax-case e2 (#%require #%provide
  164. define-syntaxes define-values-for-syntax define-values begin
  165. define-record-procedures define-record-procedures-2
  166. define-record-procedures-parametric define-record-procedures-parametric-2
  167. define-contract :)
  168. ((#%require . __)
  169. #`(begin #,e2 (frm e3s #,e1s #,def-ids)))
  170. ((#%provide . __)
  171. #`(begin #,e2 (frm e3s #,e1s #,def-ids)))
  172. ((define-syntaxes (id ...) . _)
  173. #`(begin #,e2 (frm e3s #,e1s (id ... . #,def-ids))))
  174. ((define-values-for-syntax . _)
  175. #`(begin #,e2 (frm e3s #,e1s #,def-ids)))
  176. ((begin b1 ...)
  177. (syntax-track-origin
  178. (loop (append (syntax->list #'(b1 ...)) #'e3s) e1s def-ids)
  179. e2
  180. (car (syntax-e e2))))
  181. ((define-values (id ...) . _)
  182. (loop #'e3s (cons e2 e1s) (append (syntax->list #'(id ...)) def-ids)))
  183. ((define-contract id sig)
  184. (loop #'e3s (cons e2 e1s) def-ids))
  185. ((define-record-procedures id cns prd (spec ...))
  186. (loop #'e3s (cons e2 e1s) def-ids))
  187. ((define-record-procedures-2 id cns prd (spec ...))
  188. (loop #'e3s (cons e2 e1s) def-ids))
  189. ((define-record-procedures-parametric id cns prd (spec ...))
  190. (loop #'e3s (cons e2 e1s) def-ids))
  191. ((define-record-procedures-parametric-2 id cns prd (spec ...))
  192. (loop #'e3s (cons e2 e1s) def-ids))
  193. ((: stuff ...)
  194. (loop #'e3s (cons e2 e1s) def-ids))
  195. (_
  196. (loop #'e3s (cons #`(print-results #,e2) e1s) def-ids)))))))))))))