procedural.scm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. ;;; procedural.scm --- Procedural interface to R6RS records
  2. ;; Copyright (C) 2010 Free Software Foundation, Inc.
  3. ;;
  4. ;; This library is free software; you can redistribute it and/or
  5. ;; modify it under the terms of the GNU Lesser General Public
  6. ;; License as published by the Free Software Foundation; either
  7. ;; version 3 of the License, or (at your option) any later version.
  8. ;;
  9. ;; This library is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;; Lesser General Public License for more details.
  13. ;;
  14. ;; You should have received a copy of the GNU Lesser General Public
  15. ;; License along with this library; if not, write to the Free Software
  16. ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. (library (rnrs records procedural (6))
  18. (export make-record-type-descriptor
  19. record-type-descriptor?
  20. make-record-constructor-descriptor
  21. record-constructor
  22. record-predicate
  23. record-accessor
  24. record-mutator)
  25. (import (rnrs base (6))
  26. (only (guile) cons*
  27. logand
  28. logior
  29. ash
  30. and=>
  31. throw
  32. display
  33. make-struct
  34. make-vtable
  35. map
  36. simple-format
  37. string-append
  38. symbol-append
  39. struct?
  40. struct-layout
  41. struct-ref
  42. struct-set!
  43. struct-vtable
  44. vtable-index-layout
  45. make-hash-table
  46. hashq-ref
  47. hashq-set!
  48. vector->list)
  49. (ice-9 receive)
  50. (only (srfi :1) fold split-at take))
  51. (define (record-internal? obj)
  52. (and (struct? obj) (record-type-descriptor? (struct-vtable obj))))
  53. (define rtd-index-name 8)
  54. (define rtd-index-uid 9)
  55. (define rtd-index-parent 10)
  56. (define rtd-index-sealed? 11)
  57. (define rtd-index-opaque? 12)
  58. (define rtd-index-predicate 13)
  59. (define rtd-index-field-names 14)
  60. (define rtd-index-field-bit-field 15)
  61. (define rtd-index-field-binder 16)
  62. (define rctd-index-rtd 0)
  63. (define rctd-index-parent 1)
  64. (define rctd-index-protocol 2)
  65. (define vtable-base-layout (symbol->string (struct-layout (make-vtable ""))))
  66. (define record-type-vtable
  67. (make-vtable (string-append vtable-base-layout "prprprprprprprprprpr")
  68. (lambda (obj port)
  69. (simple-format port "#<r6rs:record-type:~A>"
  70. (struct-ref obj rtd-index-name)))))
  71. (define record-constructor-vtable
  72. (make-vtable "prprpr"
  73. (lambda (obj port)
  74. (simple-format port "#<r6rs:record-constructor:~A>"
  75. (struct-ref (struct-ref obj rctd-index-rtd)
  76. rtd-index-name)))))
  77. (define uid-table (make-hash-table))
  78. (define (make-record-type-descriptor name parent uid sealed? opaque? fields)
  79. (define fields-pair
  80. (let loop ((field-list (vector->list fields))
  81. (layout-sym 'pr)
  82. (layout-bit-field 0)
  83. (counter 0))
  84. (if (null? field-list)
  85. (cons layout-sym layout-bit-field)
  86. (case (caar field-list)
  87. ((immutable)
  88. (loop (cdr field-list)
  89. (symbol-append layout-sym 'pr)
  90. layout-bit-field
  91. (+ counter 1)))
  92. ((mutable)
  93. (loop (cdr field-list)
  94. (symbol-append layout-sym 'pw)
  95. (logior layout-bit-field (ash 1 counter))
  96. (+ counter 1)))
  97. (else (r6rs-raise (make-assertion-violation)))))))
  98. (define fields-layout (car fields-pair))
  99. (define fields-bit-field (cdr fields-pair))
  100. (define field-names (list->vector (map cadr (vector->list fields))))
  101. (define late-rtd #f)
  102. (define (private-record-predicate obj)
  103. (and (record-internal? obj)
  104. (or (eq? (struct-vtable obj) late-rtd)
  105. (and=> (struct-ref obj 0) private-record-predicate))))
  106. (define (field-binder parent-struct . args)
  107. (apply make-struct (cons* late-rtd 0 parent-struct args)))
  108. (if (and parent (struct-ref parent rtd-index-sealed?))
  109. (r6rs-raise (make-assertion-violation)))
  110. (let ((matching-rtd (and uid (hashq-ref uid-table uid)))
  111. (opaque? (or opaque? (and parent (struct-ref
  112. parent rtd-index-opaque?)))))
  113. (if matching-rtd
  114. (if (equal? (list name
  115. parent
  116. sealed?
  117. opaque?
  118. field-names
  119. fields-bit-field)
  120. (list (struct-ref matching-rtd rtd-index-name)
  121. (struct-ref matching-rtd rtd-index-parent)
  122. (struct-ref matching-rtd rtd-index-sealed?)
  123. (struct-ref matching-rtd rtd-index-opaque?)
  124. (struct-ref matching-rtd rtd-index-field-names)
  125. (struct-ref matching-rtd
  126. rtd-index-field-bit-field)))
  127. matching-rtd
  128. (r6rs-raise (make-assertion-violation)))
  129. (let ((rtd (make-struct record-type-vtable 0
  130. fields-layout
  131. (lambda (obj port)
  132. (simple-format
  133. port "#<r6rs:record:~A>" name))
  134. name
  135. uid
  136. parent
  137. sealed?
  138. opaque?
  139. private-record-predicate
  140. field-names
  141. fields-bit-field
  142. field-binder)))
  143. (set! late-rtd rtd)
  144. (if uid (hashq-set! uid-table uid rtd))
  145. rtd))))
  146. (define (record-type-descriptor? obj)
  147. (and (struct? obj) (eq? (struct-vtable obj) record-type-vtable)))
  148. (define (make-record-constructor-descriptor rtd
  149. parent-constructor-descriptor
  150. protocol)
  151. (define rtd-arity (vector-length (struct-ref rtd rtd-index-field-names)))
  152. (define (default-inherited-protocol n)
  153. (lambda args
  154. (receive
  155. (n-args p-args)
  156. (split-at args (- (length args) rtd-arity))
  157. (let ((p (apply n n-args)))
  158. (apply p p-args)))))
  159. (define (default-protocol p) p)
  160. (let* ((prtd (struct-ref rtd rtd-index-parent))
  161. (pcd (or parent-constructor-descriptor
  162. (and=> prtd (lambda (d) (make-record-constructor-descriptor
  163. prtd #f #f)))))
  164. (prot (or protocol (if pcd
  165. default-inherited-protocol
  166. default-protocol))))
  167. (make-struct record-constructor-vtable 0 rtd pcd prot)))
  168. (define (record-constructor rctd)
  169. (let* ((rtd (struct-ref rctd rctd-index-rtd))
  170. (parent-rctd (struct-ref rctd rctd-index-parent))
  171. (protocol (struct-ref rctd rctd-index-protocol)))
  172. (protocol
  173. (if parent-rctd
  174. (let ((parent-record-constructor (record-constructor parent-rctd))
  175. (parent-rtd (struct-ref parent-rctd rctd-index-rtd)))
  176. (lambda args
  177. (let ((struct (apply parent-record-constructor args)))
  178. (lambda args
  179. (apply (struct-ref rtd rtd-index-field-binder)
  180. (cons struct args))))))
  181. (lambda args (apply (struct-ref rtd rtd-index-field-binder)
  182. (cons #f args)))))))
  183. (define (record-predicate rtd) (struct-ref rtd rtd-index-predicate))
  184. (define (record-accessor rtd k)
  185. (define (record-accessor-inner obj)
  186. (if (eq? (struct-vtable obj) rtd)
  187. (struct-ref obj (+ k 1))
  188. (and=> (struct-ref obj 0) record-accessor-inner)))
  189. (lambda (obj)
  190. (if (not (record-internal? obj))
  191. (r6rs-raise (make-assertion-violation)))
  192. (record-accessor-inner obj)))
  193. (define (record-mutator rtd k)
  194. (define (record-mutator-inner obj val)
  195. (and obj (or (and (eq? (struct-vtable obj) rtd)
  196. (struct-set! obj (+ k 1) val))
  197. (record-mutator-inner (struct-ref obj 0) val))))
  198. (let ((bit-field (struct-ref rtd rtd-index-field-bit-field)))
  199. (if (zero? (logand bit-field (ash 1 k)))
  200. (r6rs-raise (make-assertion-violation))))
  201. (lambda (obj val) (record-mutator-inner obj val)))
  202. ;; Condition types that are used in the current library. These are defined
  203. ;; here and not in (rnrs conditions) to avoid a circular dependency.
  204. (define &condition (make-record-type-descriptor '&condition #f #f #f #f '#()))
  205. (define &condition-constructor-descriptor
  206. (make-record-constructor-descriptor &condition #f #f))
  207. (define &serious (make-record-type-descriptor
  208. '&serious &condition #f #f #f '#()))
  209. (define &serious-constructor-descriptor
  210. (make-record-constructor-descriptor
  211. &serious &condition-constructor-descriptor #f))
  212. (define make-serious-condition
  213. (record-constructor &serious-constructor-descriptor))
  214. (define &violation (make-record-type-descriptor
  215. '&violation &serious #f #f #f '#()))
  216. (define &violation-constructor-descriptor
  217. (make-record-constructor-descriptor
  218. &violation &serious-constructor-descriptor #f))
  219. (define make-violation (record-constructor &violation-constructor-descriptor))
  220. (define &assertion (make-record-type-descriptor
  221. '&assertion &violation #f #f #f '#()))
  222. (define make-assertion-violation
  223. (record-constructor
  224. (make-record-constructor-descriptor
  225. &assertion &violation-constructor-descriptor #f)))
  226. ;; Exception wrapper type, along with a wrapping `throw' implementation.
  227. ;; These are used in the current library, and so they are defined here and not
  228. ;; in (rnrs exceptions) to avoid a circular dependency.
  229. (define &raise-object-wrapper
  230. (make-record-type-descriptor '&raise-object-wrapper #f #f #f #f
  231. '#((immutable obj) (immutable continuation))))
  232. (define make-raise-object-wrapper
  233. (record-constructor (make-record-constructor-descriptor
  234. &raise-object-wrapper #f #f)))
  235. (define raise-object-wrapper? (record-predicate &raise-object-wrapper))
  236. (define raise-object-wrapper-obj (record-accessor &raise-object-wrapper 0))
  237. (define raise-object-wrapper-continuation
  238. (record-accessor &raise-object-wrapper 1))
  239. (define (r6rs-raise obj)
  240. (throw 'r6rs:exception (make-raise-object-wrapper obj #f)))
  241. (define (r6rs-raise-continuable obj)
  242. (define (r6rs-raise-continuable-internal continuation)
  243. (throw 'r6rs:exception (make-raise-object-wrapper obj continuation)))
  244. (call/cc r6rs-raise-continuable-internal))
  245. )