immutable.scm 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. ;;; Extensions to SRFI-9
  2. ;; Copyright (C) 2010, 2012 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. ;;; Commentary:
  18. ;; Extensions to SRFI-9. Fully documented in the Guile Reference Manual.
  19. ;;; Code:
  20. (module (arguile data immutable)
  21. #:export (set-record-type-printer!
  22. define-immutable-record-type
  23. set-field
  24. set-fields))
  25. (use (srfi srfi-1)
  26. (system base ck))
  27. (define (set-record-type-printer! type proc)
  28. "Set PROC as the custom printer for TYPE."
  29. (struct-set! type vtable-index-printer proc))
  30. (define-syntax-rule (define-immutable-record-type name ctor pred fields ...)
  31. ((@@ (arguile data records) %define-record-type)
  32. #t (define-immutable-record-type name ctor pred fields ...)
  33. name ctor pred fields ...))
  34. (define-syntax-rule (set-field s (getter ...) expr)
  35. (%set-fields #t (set-field s (getter ...) expr) ()
  36. s ((getter ...) expr)))
  37. (define-syntax-rule (set-fields s . rest)
  38. (%set-fields #t (set-fields s . rest) ()
  39. s . rest))
  40. ;;
  41. ;; collate-set-field-specs is a helper for %set-fields
  42. ;; thats combines all specs with the same head together.
  43. ;;
  44. ;; For example:
  45. ;;
  46. ;; SPECS: (((a b c) expr1)
  47. ;; ((a d) expr2)
  48. ;; ((b c) expr3)
  49. ;; ((c) expr4))
  50. ;;
  51. ;; RESULT: ((a ((b c) expr1)
  52. ;; ((d) expr2))
  53. ;; (b ((c) expr3))
  54. ;; (c (() expr4)))
  55. ;;
  56. (define (collate-set-field-specs specs)
  57. (define (insert head tail expr result)
  58. (cond ((find (lambda (tree)
  59. (free-identifier=? head (car tree)))
  60. result)
  61. => (lambda (tree)
  62. `((,head (,tail ,expr)
  63. ,@(cdr tree))
  64. ,@(delq tree result))))
  65. (else `((,head (,tail ,expr))
  66. ,@result))))
  67. (with-syntax (((((head . tail) expr) ...) specs))
  68. (fold insert '() #'(head ...) #'(tail ...) #'(expr ...))))
  69. (define-syntax unknown-getter
  70. (lambda (x)
  71. (syntax-case x ()
  72. ((_ orig-form getter)
  73. (syntax-violation 'set-fields "unknown getter" #'orig-form #'getter)))))
  74. (define-syntax c-list
  75. (lambda (x)
  76. (syntax-case x (quote)
  77. ((_ s 'v ...)
  78. #'(ck s '(v ...))))))
  79. (define-syntax c-same-type-check
  80. (lambda (x)
  81. (syntax-case x (quote)
  82. ((_ s 'orig-form '(path ...)
  83. '(getter0 getter ...)
  84. '(type0 type ...)
  85. 'on-success)
  86. (every (lambda (t g)
  87. (or (free-identifier=? t #'type0)
  88. (syntax-violation
  89. 'set-fields
  90. (format #f
  91. "\
  92. field paths ~a and ~a require one object to belong to two different record types (~a and ~a)"
  93. (syntax->datum #`(path ... #,g))
  94. (syntax->datum #'(path ... getter0))
  95. (syntax->datum t)
  96. (syntax->datum #'type0))
  97. #'orig-form)))
  98. #'(type ...)
  99. #'(getter ...))
  100. #'(ck s 'on-success)))))
  101. (define-syntax %set-fields
  102. (lambda (x)
  103. (with-syntax ((getter-type #'(@@ (arguile data records) getter-type))
  104. (getter-index #'(@@ (arguile data records) getter-index))
  105. (getter-copier #'(@@ (arguile data records) getter-copier)))
  106. (syntax-case x ()
  107. ((_ check? orig-form (path-so-far ...)
  108. s)
  109. #'s)
  110. ((_ check? orig-form (path-so-far ...)
  111. s (() e))
  112. #'e)
  113. ((_ check? orig-form (path-so-far ...)
  114. struct-expr ((head . tail) expr) ...)
  115. (let ((collated-specs (collate-set-field-specs
  116. #'(((head . tail) expr) ...))))
  117. (with-syntax (((getter0 getter ...)
  118. (map car collated-specs)))
  119. (with-syntax ((err #'(unknown-getter
  120. orig-form getter0)))
  121. #`(ck
  122. ()
  123. (c-same-type-check
  124. 'orig-form
  125. '(path-so-far ...)
  126. '(getter0 getter ...)
  127. (c-list (getter-type 'getter0 'err)
  128. (getter-type 'getter 'err) ...)
  129. '(let ((s struct-expr))
  130. ((ck () (getter-copier 'getter0 'err))
  131. check?
  132. s
  133. #,@(map (lambda (spec)
  134. (with-syntax (((head (tail expr) ...) spec))
  135. (with-syntax ((err #'(unknown-getter
  136. orig-form head)))
  137. #'(head (%set-fields
  138. check?
  139. orig-form
  140. (path-so-far ... head)
  141. (struct-ref s (ck () (getter-index
  142. 'head 'err)))
  143. (tail expr) ...)))))
  144. collated-specs)))))))))
  145. ((_ check? orig-form (path-so-far ...)
  146. s (() e) (() e*) ...)
  147. (syntax-violation 'set-fields "duplicate field path"
  148. #'orig-form #'(path-so-far ...)))
  149. ((_ check? orig-form (path-so-far ...)
  150. s ((getter ...) expr) ...)
  151. (syntax-violation 'set-fields "one field path is a prefix of another"
  152. #'orig-form #'(path-so-far ...)))
  153. ((_ check? orig-form . rest)
  154. (syntax-violation 'set-fields "invalid syntax" #'orig-form))))))