trait.scm 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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))))