/collects/deinprogramm/signature/signature-syntax.rkt

http://github.com/gmarceau/PLT · Racket · 286 lines · 257 code · 19 blank · 10 comment · 11 complexity · 34f7237036f058ea15ec1f159d8f48ec MD5 · raw file

  1. #lang scheme/base
  2. (provide :
  3. signature signature/arbitrary
  4. define-contract contract ; legacy
  5. define/signature define-values/signature
  6. -> mixed one-of predicate combined property list-of)
  7. (require deinprogramm/signature/signature
  8. deinprogramm/signature/signature-german
  9. scheme/promise
  10. (for-syntax scheme/base)
  11. (for-syntax syntax/stx)
  12. (for-syntax stepper/private/shared))
  13. (define-for-syntax (phase-lift stx)
  14. (with-syntax ((?stx stx))
  15. (with-syntax ((?stx1 (syntax/loc stx #'?stx))) ; attach the occurrence position to the syntax object
  16. #'?stx1)))
  17. (define-for-syntax (parse-signature name stx)
  18. (syntax-case* stx
  19. (mixed one-of predicate list -> combined property reference at signature list-of)
  20. module-or-top-identifier=?
  21. ((mixed ?signature ...)
  22. (with-syntax ((?stx (phase-lift stx))
  23. (?name name)
  24. ((?signature-expr ...) (map (lambda (sig)
  25. (parse-signature #f sig))
  26. (syntax->list #'(?signature ...)))))
  27. #'(make-mixed-signature '?name
  28. (list ?signature-expr ...)
  29. ?stx)))
  30. ((one-of ?exp ...)
  31. (with-syntax ((((?temp ?exp) ...)
  32. (map list
  33. (generate-temporaries #'(?exp ...)) (syntax->list #'(?exp ...))))
  34. (?stx (phase-lift stx))
  35. (?name name))
  36. (with-syntax (((?check ...)
  37. (map (lambda (lis)
  38. (with-syntax (((?temp ?exp) lis))
  39. (with-syntax ((?raise
  40. (syntax/loc
  41. #'?exp
  42. (error 'signatures "hier keine Signatur zulässig, nur normaler Wert"))))
  43. #'(when (signature? ?temp)
  44. ?raise))))
  45. (syntax->list #'((?temp ?exp) ...)))))
  46. #'(let ((?temp ?exp) ...)
  47. ?check ...
  48. (make-case-signature '?name (list ?temp ...) equal? ?stx)))))
  49. ((predicate ?exp)
  50. (with-syntax ((?stx (phase-lift stx))
  51. (?name name))
  52. #'(make-predicate-signature '?name (delay ?exp) ?stx)))
  53. ((list ?signature)
  54. (with-syntax ((?stx (phase-lift stx))
  55. (?name name)
  56. (?signature-expr (parse-signature #f #'?signature)))
  57. #'(make-list-signature '?name ?signature-expr ?stx)))
  58. ((list ?signature1 ?rest ...)
  59. (raise-syntax-error #f
  60. "list-Signatur darf nur einen Operanden haben."
  61. (syntax ?signature1)))
  62. ((list-of ?signature)
  63. (with-syntax ((?stx (phase-lift stx))
  64. (?name name)
  65. (?signature-expr (parse-signature #f #'?signature)))
  66. #'(make-list-signature '?name ?signature-expr ?stx)))
  67. ((list-of ?signature)
  68. (raise-syntax-error #f
  69. "list-of-Signatur darf nur einen Operanden haben."
  70. (syntax ?signature1)))
  71. ((?arg-signature ... -> ?return-signature)
  72. (with-syntax ((?stx (phase-lift stx))
  73. (?name name)
  74. ((?arg-signature-exprs ...) (map (lambda (sig)
  75. (parse-signature #f sig))
  76. (syntax->list #'(?arg-signature ...))))
  77. (?return-signature-expr (parse-signature #f #'?return-signature)))
  78. #'(make-procedure-signature '?name (list ?arg-signature-exprs ...) ?return-signature-expr ?stx)))
  79. ((?arg-signature ... -> ?return-signature1 ?return-signature2 . ?_)
  80. (raise-syntax-error #f
  81. "Nach dem -> darf nur eine Signatur stehen."
  82. (syntax ?return-signature2)))
  83. ((at ?loc ?sig)
  84. (with-syntax ((?sig-expr (parse-signature #f #'?sig)))
  85. #'(signature-update-syntax ?sig-expr #'?loc)))
  86. (signature
  87. (with-syntax ((?stx (phase-lift stx)))
  88. #'(signature-update-syntax signature/signature #'?loc)))
  89. (?id
  90. (identifier? #'?id)
  91. (with-syntax ((?stx (phase-lift stx))
  92. (?name (or name (syntax->datum #'?id))))
  93. (let ((name (symbol->string (syntax->datum #'?id))))
  94. (if (char=? #\% (string-ref name 0))
  95. #'(make-type-variable-signature '?name ?stx)
  96. (with-syntax
  97. ((?raise
  98. (syntax/loc #'?stx
  99. (error 'signatures "expected a signature, found ~e" ?id))))
  100. (with-syntax
  101. ((?sig
  102. #'(make-delayed-signature '?name
  103. (delay
  104. (begin
  105. (when (not (signature? ?id))
  106. ?raise)
  107. ?id)))))
  108. ;; for local variables (parameters, most probably),
  109. ;; we want the value to determine the blame location
  110. (if (eq? (identifier-binding #'?id) 'lexical)
  111. #'?sig
  112. #'(signature-update-syntax ?sig #'?stx))))))))
  113. ((combined ?signature ...)
  114. (with-syntax ((?stx (phase-lift stx))
  115. (?name name)
  116. ((?signature-expr ...) (map (lambda (sig)
  117. (parse-signature #f sig))
  118. (syntax->list #'(?signature ...)))))
  119. #'(make-combined-signature '?name
  120. (list ?signature-expr ...)
  121. ?stx)))
  122. ((property ?access ?signature)
  123. (with-syntax ((?stx (phase-lift stx))
  124. (?name name)
  125. (?signature-expr (parse-signature #f #'?signature)))
  126. #'(make-property-signature '?name
  127. ?access
  128. ?signature-expr
  129. ?stx)))
  130. ((signature ?stuff ...)
  131. (raise-syntax-error #f
  132. "`signature' als Operator ergibt keinen Sinn"
  133. stx))
  134. ((?signature-abstr ?signature ...)
  135. (identifier? #'?signature-abstr)
  136. (with-syntax ((?stx (phase-lift stx))
  137. (?name name)
  138. ((?signature-expr ...) (map (lambda (sig)
  139. (parse-signature #f sig))
  140. (syntax->list #'(?signature ...)))))
  141. (with-syntax
  142. ((?call (syntax/loc stx (?signature-abstr ?signature-expr ...))))
  143. #'(make-call-signature '?name
  144. (delay ?call)
  145. (delay ?signature-abstr) (delay (list ?signature-expr ...))
  146. ?stx))))
  147. (else
  148. (raise-syntax-error #f
  149. "ungĂźltige Signatur" stx))))
  150. ; regrettable
  151. (define signature/signature
  152. (make-predicate-signature 'signature
  153. (delay signature?)
  154. #f))
  155. (define-syntax signature
  156. (lambda (stx)
  157. (syntax-case stx ()
  158. ((_ ?sig)
  159. #'(signature #f ?sig))
  160. ((_ ?name ?sig)
  161. (stepper-syntax-property
  162. (parse-signature (syntax->datum #'?name) #'?sig)
  163. 'stepper-skip-completely #t)))))
  164. (define-syntax contract
  165. (lambda (stx)
  166. (syntax-case stx ()
  167. ((_ ?sig)
  168. #'(signature #f ?sig))
  169. ((_ ?name ?sig)
  170. (stepper-syntax-property
  171. (parse-signature (syntax->datum #'?name) #'?sig)
  172. 'stepper-skip-completely #t)))))
  173. (define-syntax signature/arbitrary
  174. (lambda (stx)
  175. (syntax-case stx ()
  176. ((_ ?arb ?sig . ?rest)
  177. #'(let ((sig (signature ?sig . ?rest)))
  178. (set-signature-arbitrary! sig ?arb)
  179. sig)))))
  180. ; legacy
  181. (define-syntax define-contract
  182. (lambda (stx)
  183. (syntax-case stx ()
  184. ((_ ?name ?sig)
  185. (identifier? #'?name)
  186. (stepper-syntax-property #'(define ?name (signature ?name ?sig))
  187. 'stepper-skip-completely
  188. #t))
  189. ((_ (?name ?param ...) ?sig)
  190. (and (identifier? #'?name)
  191. (andmap identifier? (syntax->list #'(?param ...))))
  192. (stepper-syntax-property #'(define (?name ?param ...) (signature ?name ?sig))
  193. 'stepper-skip-completely
  194. #t)))))
  195. (define-syntax define/signature
  196. (lambda (stx)
  197. (syntax-case stx ()
  198. ((_ ?name ?cnt ?expr)
  199. (with-syntax ((?enforced
  200. (stepper-syntax-property #'(attach-name '?name (apply-signature/blame ?cnt ?expr))
  201. 'stepper-skipto/discard
  202. ;; apply-signature/blame takes care of itself
  203. ;; remember there's an implicit #%app
  204. '(syntax-e cdr syntax-e cdr cdr car))))
  205. #'(define ?name ?enforced))))))
  206. (define-syntax define-values/signature
  207. (lambda (stx)
  208. (syntax-case stx ()
  209. ((_ (?id ...) ?expr)
  210. (andmap identifier? (syntax->list #'(?id ...)))
  211. (syntax-track-origin
  212. #'(define-values (?id ...) ?expr)
  213. stx
  214. (car (syntax-e stx))))
  215. ((_ ((?id ?cnt)) ?expr)
  216. (identifier? #'?id)
  217. #'(define/signature ?id ?cnt ?expr)) ; works with stepper
  218. ((_ (?bind ...) ?expr)
  219. (let ((ids+enforced
  220. (map (lambda (bind)
  221. (syntax-case bind ()
  222. (?id
  223. (identifier? #'?id)
  224. (cons #'?id #'?id))
  225. ((?id ?cnt)
  226. (identifier? #'?id)
  227. (cons #'?id
  228. #'(attach-name '?id (apply-signature/blame ?cnt ?id))))))
  229. (syntax->list #'(?bind ...)))))
  230. (with-syntax (((?id ...) (map car ids+enforced))
  231. ((?enforced ...) (map cdr ids+enforced)))
  232. (stepper-syntax-property
  233. #'(define-values (?id ...)
  234. (call-with-values
  235. (lambda () ?expr)
  236. (lambda (?id ...)
  237. (values ?enforced ...))))
  238. 'stepper-skip-completely #t)))))))
  239. ;; Matthew has promised a better way of doing this in the future.
  240. (define (attach-name name thing)
  241. (if (procedure? thing)
  242. (procedure-rename thing name)
  243. thing))
  244. (define-syntax :
  245. (syntax-rules ()
  246. ((: ?id ?sig) (begin)))) ; probably never used, we're only interested in the binding for :
  247. (define-for-syntax (within-signature-syntax-error stx name)
  248. (raise-syntax-error #f
  249. "darf nur in Signaturen vorkommen"
  250. name))
  251. ;; Expression -> Expression
  252. ;; Transforms unfinished code (... and the like) to code
  253. ;; raising an appropriate error.
  254. (define-for-syntax within-signature-syntax-transformer
  255. (make-set!-transformer
  256. (lambda (stx)
  257. (syntax-case stx (set!)
  258. [(set! form expr) (within-signature-syntax-error stx (syntax form))]
  259. [(form . rest) (within-signature-syntax-error stx (syntax form))]
  260. [form (within-signature-syntax-error stx stx)]))))
  261. (define-syntax -> within-signature-syntax-transformer)
  262. (define-syntax mixed within-signature-syntax-transformer)
  263. (define-syntax one-of within-signature-syntax-transformer)
  264. (define-syntax predicate within-signature-syntax-transformer)
  265. (define-syntax combined within-signature-syntax-transformer)
  266. (define-syntax property within-signature-syntax-transformer)
  267. (define-syntax list-of within-signature-syntax-transformer)