trait.scm 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. (module trait (trait?
  2. define-trait
  3. define-trait-impl
  4. with-type-of
  5. define-overload
  6. ;; functions below used only in macros
  7. get-trait-func
  8. create-trait)
  9. (import scheme
  10. (chicken base)
  11. (chicken syntax)
  12. srfi-69)
  13. (define-syntax define-macro
  14. (er-macro-transformer
  15. (lambda (exp r c)
  16. (let ((def (cadr exp))
  17. (body (cddr exp)))
  18. `(define-syntax ,(car def)
  19. (er-macro-transformer
  20. (lambda (e2 r2 c2)
  21. (define (transform-func ,@(cdr def))
  22. ,@body)
  23. (apply transform-func (cdr e2)))))))))
  24. ;; body
  25. (define-record trait name func-names func-table pred parent)
  26. (define (create-trait name func-names funcs pred parent)
  27. (let ((table (make-hash-table)))
  28. (define cls (make-trait name func-names table pred parent))
  29. (define (init-table func-names funcs)
  30. (if (null? func-names)
  31. '()
  32. (let ()
  33. (hash-table-set! (trait-func-table cls)
  34. (car func-names)
  35. (car funcs))
  36. (init-table (cdr func-names) (cdr funcs)))))
  37. (init-table func-names funcs)
  38. cls))
  39. (define-macro (define-trait name . body)
  40. (let ()
  41. (define (func-def-tr entry)
  42. (define args (gensym))
  43. `(define ,(car entry)
  44. ,(if (null? (cdr entry))
  45. ''()
  46. (cadr entry))))
  47. (define (define-trait-tr name . body)
  48. `(begin
  49. (define ,name
  50. (create-trait (quote ,name)
  51. (quote ,(map car body))
  52. (list ,@(map (lambda (x)
  53. (if (null? (cdr x))
  54. ''()
  55. (cadr x)))
  56. body))
  57. '()
  58. '()))
  59. ,@(map func-def-tr body)))
  60. (define form (apply define-trait-tr (cons name body)))
  61. ;; (display form) (newline)
  62. form))
  63. (define-macro (define-trait-impl name . body)
  64. (let ()
  65. (define (define-trait-impl-tr name . body)
  66. (define old-cls (gensym))
  67. (define cls (car name))
  68. (define pred (cadr name))
  69. (define (func-def-tr entry)
  70. (define old-func (gensym))
  71. (define args (gensym))
  72. `(begin
  73. (define ,old-func ,(car entry))
  74. (define (,(car entry) . ,args)
  75. (if (,pred (car ,args))
  76. (apply ,(if (null? (cdr entry))
  77. '()
  78. (cadr entry))
  79. ,args)
  80. (apply ,old-func ,args)))))
  81. `(begin
  82. (define ,old-cls ,cls)
  83. (define ,cls
  84. (create-trait (quote ,cls)
  85. (quote ,(map car body))
  86. (list ,@(map (lambda (x)
  87. (if (null? (cdr x))
  88. ''()
  89. (cadr x)))
  90. body))
  91. ,pred
  92. ,old-cls))
  93. ,@(map func-def-tr body)))
  94. (define form (apply define-trait-impl-tr (cons name body)))
  95. ;; (display form) (newline)
  96. form))
  97. (define (get-trait-func trait obj func-name)
  98. (let loop ((cur trait))
  99. (cond ((null? (trait-parent cur))
  100. (hash-table-ref (trait-func-table cur) func-name))
  101. (((trait-pred cur) obj)
  102. (let ((func (hash-table-ref/default (trait-func-table cur) func-name #f)))
  103. (or func (loop (trait-parent cur)))))
  104. (else (loop (trait-parent cur))))))
  105. (define-macro (with-type-of obj trait func)
  106. `(get-trait-func ,trait ,obj (quote ,func)))
  107. (define-syntax define-overload
  108. (ir-macro-transformer
  109. (lambda (e i c)
  110. (define (impl def . body)
  111. (define name (car def))
  112. (define (get-param-names args)
  113. (let loop ((lst args) (ret '()))
  114. (if (null? lst)
  115. (reverse ret)
  116. (if (symbol? (car lst))
  117. (loop (cdr lst) (cons (car lst) ret))
  118. (loop (cdr lst) (cons (caar lst) ret))))))
  119. (define (get-preds args)
  120. (let loop ((lst args) (ret '()))
  121. (if (null? lst)
  122. (reverse ret)
  123. (if (list? (car lst))
  124. (loop (cdr lst) (cons (reverse (car lst)) ret))
  125. (loop (cdr lst) ret)))))
  126. (define param-names (get-param-names (cdr def)))
  127. (define preds (get-preds (cdr def)))
  128. (define old-func (gensym))
  129. `(begin
  130. (define ,old-func ,name)
  131. (define (,name ,@param-names)
  132. (if (and ,@preds)
  133. ((lambda (,@param-names) ,@body) ,@param-names)
  134. (,old-func ,@param-names)))))
  135. (define form (apply impl (cdr e)))
  136. ;; (display form) (newline)
  137. form))))