union.scm 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey
  3. ; Unions
  4. ; Todo:
  5. ; - finish the code below
  6. ; - add this file to the packages
  7. ; - add a separate field and member resolution phase.
  8. ; - figure out how union literals are going to work
  9. ; - to-cps method for type-case
  10. ; - C generation methods for unions, union literals, type-case, and
  11. ; x->type (which is a cast).
  12. ; Plan - datatypes with the initial restriction that a datatype
  13. ; cannot be polymorphic (does this matter?) and cannot have more than one
  14. ; non-nullary constructor. What is needed is a new expander and a couple
  15. ; of primitives:
  16. ;
  17. ; (x->union value 'union-type 'variant)
  18. ; (type-case value 'union-type '(variant ...) . conts)
  19. ;
  20. ; X->UNION does type checking and is a no-op in C.
  21. ; TYPE-CASE does type checking (VALUE must have type UNION-TYPE and the
  22. ; continuations receive arguments of the type of the corresponding variant).
  23. ; The C code does a switch for the nullary constructors and a second switch
  24. ; using the type field of the non-nullary constructors. Not every type
  25. ; needs both switches.
  26. ; Representation of union types.
  27. (define-record-type union-type :union-type
  28. (really-make-union-type name)
  29. union-type?
  30. (name union-type-name)
  31. ; MEMBERS are filled in later because of circularity
  32. (members union-type-members set-union-type-members))
  33. (define-union-discloser :union-type
  34. (lambda (rtype)
  35. (list 'union-type (union-type-name rtype))))
  36. ; Members of union types.
  37. (define-record-type union-member :union-member
  38. (make-union-member union-type name type)
  39. union-member?
  40. (union-type union-member-union-type)
  41. (name union-member-name)
  42. (type union-member-type))
  43. ; Global table of union types. Since we compile to a single C file the
  44. ; union types used within a single computation must have distinct names.
  45. ; (This should really be a fluid.)
  46. (define *union-type-table* (make-symbol-table))
  47. (define (reset-union-data!)
  48. (set! *union-type-table* (make-symbol-table)))
  49. (define (get-union-type id)
  50. (cond ((table-ref *union-type-table* id)
  51. => identity)
  52. (else
  53. (error "no union type ~S" id))))
  54. (define (lookup-union-type id)
  55. (table-ref *union-type-table* id))
  56. (define (all-union-types)
  57. (table->entry-list *union-type-table*))
  58. ; Construction a union type. This gets the name and the member specifications.
  59. ; Each member specification consists of a name and a type.
  60. ; Aargh. What to do? The simplest thing might be to expand define-data-type
  61. ; into define-record-types and and a define-union-type. Except that we hit
  62. ; the circularity problem again. We need to create record field type after
  63. ; all macro expansion has been completed.
  64. (define (make-union-type id specs)
  65. (let ((ut (really-make-union-type id)))
  66. (if (table-ref *union-type-table* id)
  67. (user-error "multiple definitions of union type ~S" id))
  68. (table-set! *union-type-table* id ut)
  69. (set-union-type-members! ut (map (lambda (spec)
  70. (make-union-member
  71. ut
  72. (car spec)
  73. (expand-type-spec (cadr spec))))
  74. specs))
  75. (set-union-type-constructor-args! ut
  76. (map (lambda (name)
  77. (get-union-type-member id name))
  78. constructor-args))
  79. ut))
  80. ; Return the member record for MEMBER-ID in union-type TYPE-ID.
  81. (define (get-union-type-member type-id member-id)
  82. (let ((utype (get-union-type type-id)))
  83. (cond ((any (lambda (member)
  84. (eq? member-id (union-member-name member)))
  85. (union-type-members utype))
  86. => identity)
  87. (else
  88. (user-error "~S is not a member of ~S" member-id utype)))))
  89. ; Returns a list of the expected continuation types (each of which returns
  90. ; UVAR) as its result.
  91. (define (get-union-deconstruction-types type-id uvar)
  92. ...)
  93. ;(define-data-type list delistifier
  94. ; (pair :pair pair->list
  95. ; (make-pair car cdr)
  96. ; (car integer car set-car!)
  97. ; (cdr list cdr set-cdr!))
  98. ; (null))
  99. ;
  100. ; ->
  101. ;
  102. ; (define-record-type pair :pair
  103. ; (make-pair car cdr)
  104. ; (car integer car set-car!)
  105. ; (cdr list cdr set-cdr!))
  106. ; (define-union-type list delistifier
  107. ; (pair :pair pair->list) ; must be a record type
  108. ; (null)) ; implied unit type
  109. ; (define-union-type list delistifier
  110. ; (pair :pair)
  111. ; null) ; implied unit type
  112. ; ->
  113. ; (define (pair->list x) (x->union x 'list 'pair))
  114. ; (define null (x->union 0 'list 'null)) ; needs compile-time objects
  115. ; (define (delistifier x pair-cont null-cont)
  116. ; (type-case x 'list '(pair null) pair-cont null-cont))
  117. (define (expand-union-type exp r c)
  118. (let ((id (cadr exp))
  119. (deconstructor (caddr exp))
  120. (members (cdddr exp)))
  121. (let* ((ut (make-union-type id members))
  122. (conts (make-names members r)))
  123. `(,(r 'begin)
  124. (,(r 'define) (,deconstructor ,(r 'x) . ,conts)
  125. (,(r 'type-case) ,(r 'x) ',id . ,conts))
  126. . ,(apply append
  127. (do ((members members (cdr members))
  128. (i 0 (+ i 1))
  129. (res '() (cons (expand-member (car members) i id r)
  130. res)))
  131. ((null? members)
  132. (apply append (reverse res)))))))))
  133. ; MEMBER is either (tag-name type injector-name) or just the tag-name.
  134. (define (expand-member member i type-id r)
  135. (if (pair? member)
  136. `((,(r 'define) (,(caddr member) ,(r 'x))
  137. (,(r 'x->union) ,(r 'x) ',type-id ',(car member))))
  138. `((,(r 'define) ,member
  139. (,(r 'x->union) ,i ',type-id ',member)))))
  140. (define (make-names things r)
  141. (do ((i 0 (+ i 1))
  142. (things things (cdr things))
  143. (names '() (cons (r (build-symbol 'c i))
  144. names)))
  145. (reverse names)))
  146. (define (build-symbol . args)
  147. (string->symbol
  148. (string-append (map (lambda (x)
  149. (cond ((string? x)
  150. x)
  151. ((symbol? x)
  152. (symbol->string x))
  153. ((number? x)
  154. (number->string x))
  155. (else
  156. (error "can't coerce to string" x))))
  157. args))))
  158. ;(define (expand-define-data-type exp r c)
  159. ; (let ((id (cadr exp))
  160. ; (deconstructor (caddr exp))
  161. ; (options (cdddr exp)))
  162. ; (let* ((specs (map (lambda (option)
  163. ; (if (null? (cdr option))
  164. ; option
  165. ; (cons (car option)
  166. ; (map car (cddddr option)))))
  167. ; options))
  168. ; (dt (make-union-type id specs))
  169. ; (conts (make-names specs r)))
  170. ; `(,(r 'begin)
  171. ; (,(r 'define) (,deconstructor ,(r 'x) . ,conts)
  172. ; (,(r 'type-case) ,(r 'x) ',id . ,conts))
  173. ; . ,(apply append
  174. ; (do ((options options (cdr options))
  175. ; (i 0 (+ i 1))
  176. ; (res '() (cons (expand-option (car options) i id r)
  177. ; res)))
  178. ; ((null? options)
  179. ; (apply append (reverse res)))))))))
  180. ;
  181. ;(define (expand-option option i type-id r)
  182. ; (if (null? (cdr option))
  183. ; `((,(r 'define) (,(car option))
  184. ; (,(r 'x->union) ,i ',type-id ',(car option))))
  185. ; `((,(r 'define-record-type) ,(car option)
  186. ; ,(cadr option)
  187. ; . ,(cdddr option))
  188. ; (,(r 'define) (,(caddr option) ,(r 'x))
  189. ; (,(r 'x->union) ,(r 'x) ',type-id ',(car option))))))
  190. ; I'll live without this for now.
  191. ;
  192. ;(define-syntax delistify
  193. ; (syntax-rules ()
  194. ; ((delistify value . clauses)
  195. ; (really-delistify value clauses #f match-error #f match-error))))
  196. ;
  197. ;(define-syntax really-delistify
  198. ; (syntax-rules ()
  199. ; ((really-delistify value () pair? pair-cont null? null-cont)
  200. ; (delistifier value pair-cont null-cont))
  201. ; ((really-delistify value
  202. ; (((pair car-var cdr-var) code . more-code)
  203. ; . more-clauses)
  204. ; #f pair-cont null? null-cont)
  205. ; (really-delistify value
  206. ; more-clauses
  207. ; #t
  208. ; (lambda (a-pair)
  209. ; (let ((car-var (car a-pair)) ; could check for #F
  210. ; (cdr-var (cdr a-pair)))
  211. ; code . more-code))
  212. ; null?
  213. ; null-cont))
  214. ; ((really-delistify value
  215. ; (((pair . pair-var) code . more-code)
  216. ; . more-clauses)
  217. ; #f pair-cont null? null-cont)
  218. ; (really-delistify value
  219. ; more-clauses
  220. ; #t
  221. ; (lambda (pair-var)
  222. ; code . more-code)
  223. ; null?
  224. ; null-cont))
  225. ; ((really-delistify value
  226. ; (((null) code . more-code)
  227. ; . more-clauses)
  228. ; pair? pair-cont #f null-cont)
  229. ; (really-delistify value
  230. ; more-clauses
  231. ; pair?
  232. ; pair-cont
  233. ; #t
  234. ; (lambda ()
  235. ; code . more-code)))
  236. ; (error)))