record-syntactic.scm 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. (define-syntax define-record-type
  3. (let ((uid-count 0))
  4. (lambda (e r c)
  5. ;; returns clause or #f
  6. (define (search-clause keyword clauses)
  7. (let loop ((clauses clauses))
  8. (cond
  9. ((null? clauses)
  10. #f)
  11. ((c keyword (caar clauses))
  12. (let ((clause (car clauses)))
  13. ;; rudimentary checks
  14. (cond
  15. ((not (list? clause))
  16. (syntax-violation 'define-record-type "invalid clause" e clause))
  17. ((search-clause keyword (cdr clauses))
  18. => (lambda (duplicate)
  19. (syntax-violation 'define-record-type "duplicate clause" e clause)))
  20. (else
  21. clause))))
  22. (else (loop (cdr clauses))))))
  23. (define (clause-value clause value-ok?)
  24. (cond
  25. ((not clause) #f)
  26. ((not (= (length clause) 2))
  27. (syntax-violation 'define-record-type "invalid clause" clause))
  28. ((not (value-ok? (cadr clause)))
  29. (syntax-violation 'define-record-type "invalid clause value" clause))
  30. (else
  31. (cadr clause))))
  32. (define s->s symbol->string)
  33. (define s-conc (lambda args (string->symbol (apply string-append args))))
  34. (define %mutable (r 'mutable))
  35. (define %immutable (r 'immutable))
  36. ;; returns a field desc; each desc is a three-element list:
  37. ;; field-name accessor-name (maybe mutator-name)
  38. (define (parse-field-spec record-name-string field-spec)
  39. (cond
  40. ((symbol? field-spec)
  41. (list field-spec
  42. (s-conc record-name-string "-" (s->s field-spec))
  43. #f))
  44. ((and (pair? field-spec)
  45. (pair? (cdr field-spec)))
  46. (let ((tag (car field-spec))
  47. (field (cadr field-spec))
  48. (size (length field-spec)))
  49. (cond
  50. ((c tag %immutable)
  51. (case size
  52. ((2)
  53. (list field
  54. (s-conc record-name-string "-" (s->s field))
  55. #f))
  56. ((3)
  57. (list field
  58. (caddr field-spec)
  59. #f))
  60. (else
  61. (syntax-violation 'define-record-type "invalid field spec" e field-spec))))
  62. ((c tag %mutable)
  63. (case size
  64. ((2)
  65. (list field
  66. (s-conc record-name-string "-" (s->s field))
  67. (s-conc record-name-string "-" (s->s field) "-set!")))
  68. ((4)
  69. (list field
  70. (caddr field-spec)
  71. (cadddr field-spec)))
  72. (else
  73. (syntax-violation 'define-record-type "invalid field spec" e field-spec))))
  74. (else
  75. (syntax-violation 'define-record-type "invalid field spec" e field-spec)))))
  76. (else
  77. (syntax-violation 'define-record-type "invalid field spec" e field-spec))))
  78. (let ((name-spec (cadr e))
  79. (clauses (cddr e)))
  80. (call-with-values
  81. (lambda ()
  82. (cond ((symbol? name-spec) ; probably barfs on generated name
  83. (values name-spec
  84. (s-conc "make-" (s->s name-spec))
  85. (s-conc (s->s name-spec) "?")))
  86. ((or (not (list? name-spec))
  87. (not (= 3 (length name-spec))))
  88. (syntax-violation 'define-record-type "invalid name spec" e name-spec))
  89. (else
  90. (apply values name-spec))))
  91. (lambda (record-name constructor-name predicate-name)
  92. (let ((record-name-string (s->s record-name))
  93. (field-specs
  94. (cond
  95. ((search-clause (r 'fields) clauses)
  96. => cdr)
  97. (else '())))
  98. (parent (clause-value (search-clause (r 'parent) clauses) symbol?)) ; probably barfs on generated names
  99. (protocol (clause-value (search-clause (r 'protocol) clauses) values))
  100. (sealed? (clause-value (search-clause (r 'sealed) clauses) boolean?))
  101. (opaque? (clause-value (search-clause (r 'opaque) clauses) boolean?))
  102. (nongenerative-clause (search-clause (r 'nongenerative) clauses))
  103. (parent-rtd-clause (search-clause (r 'parent-rtd) clauses)))
  104. (if (and parent parent-rtd-clause)
  105. (syntax-violation 'define-record-type "can't have both `parent' and `parent-rtd' clauses"
  106. e))
  107. (if (and parent-rtd-clause
  108. (or (not (list? parent-rtd-clause))
  109. (not (= 3 (length parent-rtd-clause)))))
  110. (syntax-violation 'define-record-type "invalid `parent-rtd' clause" e parent-rtd-clause))
  111. (let ((field-descs
  112. ;; cons field index onto descs
  113. (let loop ((i 0) (field-specs field-specs) (res '()))
  114. (if (null? field-specs)
  115. (reverse res)
  116. (loop (+ 1 i)
  117. (cdr field-specs)
  118. (cons (cons i (parse-field-spec record-name-string (car field-specs)))
  119. res)))))
  120. (nongenerative-uid
  121. (and nongenerative-clause
  122. (let ((size (length nongenerative-clause)))
  123. (cond
  124. ((= size 1)
  125. (set! uid-count (+ 1 uid-count)) ; #### not enough in the presence of separate compilation
  126. (s-conc "record-type-" (number->string uid-count)))
  127. ((= size 2)
  128. (cadr nongenerative-clause))
  129. (else
  130. (syntax-violation 'define-record-type "invalid `nongenerative' clause" e nongenerative-clause))))))
  131. (parent-rtd
  132. (cond
  133. (parent
  134. `(,(r 'record-type-descriptor) ,parent))
  135. (parent-rtd-clause => cadr)
  136. (else #f)))
  137. (parent-cd
  138. (cond
  139. (parent
  140. `(,(r 'record-constructor-descriptor) ,parent))
  141. (parent-rtd-clause => caddr)
  142. (else #f)))
  143. (rtd-name (r 'record-rtd))
  144. (cd-name (r 'cd))
  145. (%define (r 'define)))
  146. `(,(r 'begin)
  147. (,%define ,rtd-name
  148. (,(r 'make-record-type-descriptor)
  149. ',record-name
  150. ,parent-rtd
  151. ',nongenerative-uid
  152. ,sealed?
  153. ,opaque?
  154. ',(list->vector
  155. (map
  156. (lambda (desc)
  157. (apply (lambda (index name accessor mutator)
  158. (list (if mutator
  159. 'mutable
  160. 'immutable)
  161. name))
  162. desc))
  163. field-descs))))
  164. (,%define ,cd-name
  165. (,(r 'make-record-constructor-descriptor)
  166. ,rtd-name
  167. ,parent-cd
  168. ,protocol))
  169. ,(cond
  170. (parent
  171. `(,parent
  172. ,(r 'dispatch)
  173. (,record-name
  174. ,constructor-name ,predicate-name
  175. ,rtd-name ,cd-name
  176. ,parent ,protocol ,sealed? ,opaque? ,nongenerative-uid ,parent-rtd ,parent-cd
  177. ,field-descs)
  178. ,(r 'define-known-record-type-helper)
  179. ,(r 'define-unknown-record-type-helper)))
  180. (parent-rtd-clause
  181. `(,(r 'define-unknown-record-type-helper)
  182. ,record-name
  183. ,constructor-name ,predicate-name
  184. ,rtd-name ,cd-name
  185. ,parent ,protocol ,sealed? ,opaque? ,nongenerative-uid ,parent-rtd ,parent-cd
  186. ,field-descs))
  187. (else
  188. `(,(r 'define-known-record-type-helper)
  189. 0 #t
  190. ,record-name
  191. ,constructor-name ,predicate-name
  192. ,rtd-name ,cd-name
  193. ,parent ,protocol ,sealed? ,opaque? ,nongenerative-uid ,parent-rtd ,parent-cd
  194. ,field-descs))))))))))))
  195. ; fallback: the supertype isn't completely known statically
  196. (define-syntax define-unknown-record-type-helper
  197. (lambda (e r c)
  198. (define %begin (r 'begin))
  199. (define %define (r 'define))
  200. (define %record-accessor (r 'record-accessor))
  201. (define %record-mutator (r 'record-mutator))
  202. (define %loophole (r 'loophole))
  203. (define %:value (r ':value))
  204. (define %:unspecific (r ':value))
  205. (define %proc (r 'proc))
  206. (apply
  207. (lambda (_ record-name constructor-name predicate-name rtd-name cd-name
  208. parent protocol sealed? opaque? nongenerative-uid parent-rtd parent-cd
  209. field-descs)
  210. `(,%begin
  211. (,(r 'define-unknown-record-type-name) ,record-name ,rtd-name ,cd-name)
  212. (,%define ,constructor-name
  213. (,(r 'record-constructor) ,cd-name))
  214. (,%define ,predicate-name (,(r 'record-predicate) ,rtd-name))
  215. ,@(map (lambda (desc)
  216. (apply (lambda (index name accessor mutator)
  217. (let ((acc
  218. `(,%define ,accessor
  219. (,%loophole (,%proc (,rtd-name) ,%:value)
  220. (,%record-accessor ,rtd-name ,index)))))
  221. (if mutator
  222. `(,%begin
  223. ,acc
  224. (,%define ,mutator
  225. (,%loophole (,%proc (,rtd-name ,%:value) ,%:unspecific)
  226. (,%record-mutator ,rtd-name ,index))))
  227. acc)))
  228. desc))
  229. field-descs)))
  230. e)))
  231. ; This knows about the implementation of records and creates
  232. ; constructor, accessors, mutators, etc. directly instead of calling
  233. ; the procedures from r6rs-records-procedural. This is done to allow
  234. ; the optional auto-inlining optimizer to inline the accessors,
  235. ; mutators, etc.
  236. (define-syntax define-known-record-type-helper
  237. (lambda (e r c)
  238. (define %begin (r 'begin))
  239. (define %define (r 'define))
  240. (define %record (r 'record))
  241. (define %checked-record-ref (r 'checked-record-ref))
  242. (define %checked-record-set! (r 'checked-record-set!))
  243. (define %r (r 'r))
  244. (define %val (r 'val))
  245. (define %loophole (r 'loophole))
  246. (define %:value (r ':value))
  247. (define %:unspecific (r ':value))
  248. (define %proc (r 'proc))
  249. (define (build-args count)
  250. (let loop ((i count)
  251. (args '()))
  252. (if (zero? i)
  253. args
  254. (loop (- i 1)
  255. (cons (r (string->symbol (string-append "arg-" (number->string i))))
  256. args)))))
  257. (apply
  258. (lambda (_ parent-field-count parent-default-constructor?
  259. record-name constructor-name predicate-name rtd-name cd-name
  260. parent protocol sealed? opaque? nongenerative-uid parent-rtd parent-cd
  261. field-descs)
  262. (let ((field-count (+ parent-field-count (length field-descs)))
  263. (default-constructor? (and parent-default-constructor? (not protocol))))
  264. `(,%begin
  265. (,(r 'define-known-record-type-name) ,record-name ,rtd-name ,cd-name
  266. ,field-count ,default-constructor?)
  267. ,(if default-constructor?
  268. (let ((args (build-args field-count)))
  269. `(,%define (,constructor-name . ,args)
  270. (,%loophole (,%proc ,(map (lambda (_) %:value) args) ,rtd-name)
  271. (,%record ,rtd-name . ,args))))
  272. `(,%define ,constructor-name (,(r 'record-constructor) ,cd-name)))
  273. (,%define ,predicate-name (,(r 'record-predicate) ,rtd-name))
  274. ,@(map (lambda (desc)
  275. (apply (lambda (index name accessor mutator)
  276. (let* ((real-index (+ 1 parent-field-count index))
  277. (acc
  278. `(,%define (,accessor ,%r)
  279. (,%loophole (,%proc (,rtd-name) ,%:value)
  280. (,%checked-record-ref ,%r ,rtd-name
  281. ,real-index)))))
  282. (if mutator
  283. `(,%begin
  284. ,acc
  285. (,%define (,mutator ,%r ,%val)
  286. (,%loophole (,%proc (,rtd-name ,%:value) ,%:unspecific)
  287. (,%checked-record-set! ,%r ,rtd-name ,real-index ,%val))))
  288. acc)))
  289. desc))
  290. field-descs))))
  291. e)))
  292. (define-syntax define-known-record-type-name
  293. (syntax-rules ()
  294. ((define-known-record-type-name ?name ?rtd ?constructor-descriptor ?field-count ?default-constructor?)
  295. (define-syntax ?name
  296. (syntax-rules (descriptor constructor-descriptor dispatch)
  297. ((?name descriptor) ?rtd)
  298. ((?name constructor-descriptor) ?constructor-descriptor)
  299. ((?name dispatch ?args ?known ?unknown) (?known ?field-count ?default-constructor? . ?args)))))))
  300. (define-syntax define-unknown-record-type-name
  301. (syntax-rules ()
  302. ((define-unknown-record-type-name ?name ?rtd ?constructor-descriptor)
  303. (define-syntax ?name
  304. (syntax-rules (descriptor constructor-descriptor dispatch)
  305. ((?name descriptor) ?rtd)
  306. ((?name constructor-descriptor) ?constructor-descriptor)
  307. ((?name dispatch ?args ?known ?unknown) (?unknown . ?args)))))))
  308. ; Retrofitting RTS record types to R6RS record types.
  309. ; For now, we do default constructors only.
  310. ; (define-retrofitted-record-type r6rs-type rts-type (mutable field1) (immutable field2) ...)
  311. ; (define-retrofitted-record-type (r6rs-type r6rs-base-type) rts-type (mutable field1) ...)
  312. (define-syntax define-retrofitted-record-type
  313. (lambda (e r c)
  314. (cons (r 'define-retrofitted-record-type-helper)
  315. (cons (length (list-tail e 6))
  316. (cdr e)))))
  317. (define-syntax define-retrofitted-record-type-helper
  318. (syntax-rules ()
  319. ((define-retrofitted-record-type-helper ?field-count
  320. (?r6rs-type ?r6rs-parent-type) ?rts-type ?uid ?sealed? ?opaque? ?field-spec1 ...)
  321. (begin
  322. (retrofit-record-type! ?rts-type ?uid ?sealed? ?opaque? '#(?field-spec1 ...))
  323. (define cd (make-record-constructor-descriptor ?rts-type #f #f))
  324. (?r6rs-parent-type dispatch (?r6rs-type ?rts-type cd ?field-count)
  325. define-known-retrofitted-record-type-helper
  326. define-unknown-retrofitted-record-type-helper)))
  327. ((define-retrofitted-record-type-helper ?field-count
  328. ?r6rs-type ?rts-type ?uid ?sealed? ?opaque? ?field-spec1 ...)
  329. (begin
  330. (retrofit-record-type! ?rts-type ?uid ?sealed? ?opaque? '#(?field-spec1 ...))
  331. (define cd (make-record-constructor-descriptor ?rts-type #f #f))
  332. (define-known-record-type-name ?r6rs-type ?rts-type cd ?field-count #t)))))
  333. (define-syntax define-known-retrofitted-record-type-helper
  334. (lambda (e r c)
  335. (apply
  336. (lambda (_ parent-field-count parent-default-constructor? r6rs-type rts-type cd field-count)
  337. `(,(r 'define-known-record-type-name)
  338. ,r6rs-type ,rts-type ,cd ,(+ parent-field-count field-count) ,parent-default-constructor?))
  339. e)))
  340. (define-syntax define-unknown-retrofitted-record-type-helper
  341. (lambda (e r c)
  342. (apply
  343. (lambda (_ r6rs-type rts-type cd field-count)
  344. `(,(r 'define-unknown-record-type-name) ,r6rs-type ,rts-type ,cd))
  345. e)))
  346. (define-syntax record-type-descriptor
  347. (syntax-rules ()
  348. ((record-type-descriptor ?type)
  349. (?type descriptor))))
  350. (define-syntax record-constructor-descriptor
  351. (syntax-rules ()
  352. ((record-constructor-descriptor ?type)
  353. (?type constructor-descriptor))))