defrecord.scm 4.6 KB

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