defrecord.scm 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. ; Copyright (c) 1993-2007 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; Syntax for defining record types
  3. ; This knows about the implementation of records and creates the various
  4. ; accessors, mutators, etc. directly instead of calling the procedures
  5. ; from the record structure. This is done to allow the optional auto-inlining
  6. ; optimizer to inline the accessors, mutators, etc.
  7. ; LOOPHOLE is used to get a little compile-time type checking (in addition to
  8. ; the usual complete run-time checking).
  9. ; (define-record-type name constructor-fields other-fields)
  10. ; Constructor-arguments fields are either <name> or (<name>), the second
  11. ; indicating a field whose value can be modified.
  12. ; Other-fields are one of:
  13. ; (<name> <expression>) = modifiable field with the given value.
  14. ; <name> = modifiable field with no initial value.
  15. ;(define-record-type job
  16. ; ((thunk)
  17. ; (dynamic-env)
  18. ; number
  19. ; inferior-lock
  20. ; )
  21. ; ((on-queue #f)
  22. ; (superior #f)
  23. ; (inferiors '())
  24. ; (condition #f)
  25. ; ))
  26. (define-syntax define-record-type
  27. (let ()
  28. (define s->s symbol->string)
  29. (define s-conc (lambda args (string->symbol (apply string-append args))))
  30. (define spec-name (lambda (s) (if (pair? s) (car s) s)))
  31. (define (filter pred lst)
  32. (if (null? lst)
  33. '()
  34. (if (pred (car lst))
  35. (cons (car lst) (filter pred (cdr lst)))
  36. (filter pred (cdr lst)))))
  37. (define (ass compare name list)
  38. (cond ((null? list) #f)
  39. ((and (pair? (car list))
  40. (compare name (caar list)))
  41. (car list))
  42. (else
  43. (ass compare name (cdr list)))))
  44. (lambda (form rename compare)
  45. (let* ((name (cadr form))
  46. (arg-fields (caddr form))
  47. (other-fields (cadddr form))
  48. (init-fields (filter pair? other-fields))
  49. (args (map spec-name arg-fields))
  50. (field-name (lambda (field-name)
  51. (s-conc (s->s name) "-" (s->s field-name))))
  52. (set-name (lambda (field-name)
  53. (s-conc "set-" (s->s name)
  54. "-" (s->s field-name) "!")))
  55. (pred-name (s-conc (s->s name) "?"))
  56. (maker-name (s-conc (s->s name) "-maker"))
  57. (type-name (s-conc "type/" (s->s name)))
  58. (thing (rename 'name))
  59. (%make-record-type (rename 'make-record-type))
  60. (%record (rename 'record))
  61. (%define-accessors (rename 'define-accessors))
  62. (%unspecific (rename 'unspecific))
  63. (%loophole (rename 'loophole))
  64. (%:value (rename ':value))
  65. (%proc (rename 'proc))
  66. (%define (rename 'define))
  67. (%let (rename 'let))
  68. (%lambda (rename 'lambda))
  69. (%begin (rename 'begin)))
  70. `(,%begin
  71. (,%define ,type-name
  72. (,%make-record-type ',name
  73. ',(map spec-name
  74. (append arg-fields other-fields))))
  75. (,%define ,maker-name
  76. (,%loophole (,%proc ,(map (lambda (x) %:value) args) ,type-name)
  77. (,%lambda ,args
  78. (,%record ,type-name
  79. ,@args
  80. . ,(map (lambda (field)
  81. (cond ((ass compare
  82. (spec-name field)
  83. other-fields)
  84. => cadr)
  85. (else
  86. `(,%unspecific))))
  87. other-fields)))))
  88. (,%define ,pred-name
  89. (,%lambda (,(rename 'x))
  90. (,(rename 'and)
  91. (,(rename 'record?) ,(rename 'x))
  92. (,(rename 'eq?) ,type-name
  93. (,(rename 'record-ref) ,(rename 'x) 0)))))
  94. (,%define-accessors ,type-name
  95. ,@(map (lambda (spec)
  96. (if (pair? spec)
  97. `(,(field-name (car spec))
  98. ,(set-name (car spec)))
  99. `(,(field-name spec))))
  100. arg-fields)
  101. ,@(map (lambda (spec)
  102. `(,(field-name (spec-name spec))
  103. ,(set-name (spec-name spec))))
  104. other-fields)))))))
  105. (define-syntax define-accessors
  106. (lambda (e r c)
  107. (let ((%define-accessor (r 'define-accessor))
  108. (%begin (r 'begin))
  109. (type (cadr e))
  110. (field-specs (cddr e)))
  111. (do ((i 1 (+ i 1))
  112. (field-specs field-specs (cdr field-specs))
  113. (ds '()
  114. (cons `(,%define-accessor ,type ,i ,@(car field-specs))
  115. ds)))
  116. ((null? field-specs)
  117. `(,%begin ,@ds)))))
  118. (define-accessor begin))
  119. (define-syntax define-accessor
  120. (syntax-rules ()
  121. ((define-accessor ?type ?index ?accessor)
  122. (define ?accessor
  123. (loophole (proc (?type) :value)
  124. (lambda (r)
  125. (checked-record-ref (loophole :record r) ?type ?index)))))
  126. ((define-accessor ?type ?index ?accessor ?modifier)
  127. (begin (define-accessor ?type ?index ?accessor)
  128. (define ?modifier
  129. (loophole (proc (?type :value) :unspecific)
  130. (lambda (r new)
  131. (checked-record-set! (loophole :record r) ?type ?index new))))))
  132. ((define-accessor ?type ?index)
  133. (begin))))