procedural.scm 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. ;;; procedural.scm --- Procedural interface to R6RS records
  2. ;; Copyright (C) 2010, 2017, 2019-2020 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. (rename (record-type? 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. (rnrs conditions (6))
  27. (rnrs exceptions (6))
  28. (only (rename (guile)
  29. (record-accessor guile:record-accessor))
  30. logbit?
  31. when
  32. unless
  33. struct-ref
  34. struct-set!
  35. make-record-type
  36. record-type?
  37. record-type-name
  38. record-type-fields
  39. record-type-constructor
  40. record-type-mutable-fields
  41. record-type-parent
  42. record-type-opaque?
  43. record-predicate
  44. guile:record-accessor
  45. record-modifier
  46. vector->list))
  47. (define (make-record-type-descriptor name parent uid sealed? opaque? fields)
  48. (make-record-type name (vector->list fields) #:parent parent #:uid uid
  49. #:extensible? (not sealed?)
  50. #:allow-duplicate-field-names? #t
  51. #:opaque? (or opaque?
  52. (and parent (record-type-opaque? parent)))))
  53. (define record-constructor-descriptor
  54. (make-record-type 'record-constructor-descriptor
  55. '((immutable rtd)
  56. (immutable parent)
  57. (immutable protocol))))
  58. (define rcd-rtd
  59. (guile:record-accessor record-constructor-descriptor 'rtd))
  60. (define rcd-parent
  61. (guile:record-accessor record-constructor-descriptor 'parent))
  62. (define rcd-protocol
  63. (guile:record-accessor record-constructor-descriptor 'protocol))
  64. (define (make-record-constructor-descriptor rtd parent-rcd protocol)
  65. (unless (record-type? rtd)
  66. (raise (make-assertion-violation)))
  67. (when protocol
  68. (unless (procedure? protocol)
  69. (raise (make-assertion-violation))))
  70. (when parent-rcd
  71. (unless (eq? (rcd-rtd parent-rcd)
  72. (record-type-parent rtd))
  73. (when protocol
  74. (raise (make-assertion-violation)))))
  75. ((record-type-constructor record-constructor-descriptor)
  76. rtd parent-rcd protocol))
  77. (define (record-constructor rcd)
  78. ;; The protocol facility allows users to define constructors whose
  79. ;; arguments don't directly correspond to the fields of the record
  80. ;; type; instead, the protocol managed a mapping from "args" to
  81. ;; "inits", where args are constructor args, and inits are the
  82. ;; resulting set of initial field values.
  83. (define-syntax if*
  84. (syntax-rules (=>)
  85. ((if* (exp => id) consequent alternate)
  86. (cond (exp => (lambda (id) consequent)) (else alternate)))))
  87. (define raw-constructor
  88. (record-type-constructor (rcd-rtd rcd)))
  89. (if* ((rcd-protocol rcd) => protocol)
  90. (protocol
  91. (if* ((rcd-parent rcd) => parent)
  92. (lambda parent-args
  93. (lambda inits
  94. (let collect-inits ((parent parent)
  95. (parent-args parent-args)
  96. (inits inits))
  97. (apply
  98. (if* ((and parent (rcd-protocol parent)) => protocol)
  99. (protocol
  100. (if* ((rcd-parent parent) => parent)
  101. ;; Parent has a protocol too; collect
  102. ;; inits from parent.
  103. (lambda parent-args
  104. (lambda parent-inits
  105. (collect-inits parent parent-args
  106. (append parent-inits
  107. inits))))
  108. ;; Default case: parent args correspond
  109. ;; to inits.
  110. (lambda parent-args
  111. (apply raw-constructor
  112. (append parent-args inits)))))
  113. ;; Default case: parent args correspond to inits.
  114. (lambda parent-args
  115. (apply raw-constructor
  116. (append parent-args inits))))
  117. parent-args))))
  118. raw-constructor))
  119. raw-constructor))
  120. (define (record-accessor rtd k)
  121. (define pred (record-predicate rtd))
  122. (let* ((parent (record-type-parent rtd))
  123. (parent-nfields (if parent
  124. (length (record-type-fields parent))
  125. 0))
  126. (k (+ k parent-nfields)))
  127. (unless (and (<= parent-nfields k)
  128. (< k (length (record-type-fields rtd))))
  129. (raise (make-assertion-violation)))
  130. (lambda (obj)
  131. (unless (pred obj)
  132. (raise (make-assertion-violation)))
  133. (struct-ref obj k))))
  134. (define (record-mutator rtd k)
  135. (define pred (record-predicate rtd))
  136. (let* ((parent (record-type-parent rtd))
  137. (parent-nfields (if parent
  138. (length (record-type-fields parent))
  139. 0))
  140. (k (+ k parent-nfields)))
  141. (unless (and (<= parent-nfields k)
  142. (< k (length (record-type-fields rtd))))
  143. (raise (make-assertion-violation)))
  144. (unless (logbit? k (record-type-mutable-fields rtd))
  145. (raise (make-assertion-violation)))
  146. (lambda (obj val)
  147. (unless (pred obj)
  148. (raise (make-assertion-violation)))
  149. (struct-set! obj k val))))
  150. )