trait.scm 5.1 KB

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