resolve.scm 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #lang racket
  2. (require racket/match)
  3. (require (only-in srfi/1 every))
  4. (require "utilities.scm")
  5. (require "counter.scm")
  6. (require "box.scm")
  7. (require "sets.scm")
  8. (require "scope-set-env.scm")
  9. (require "syntax.scm")
  10. (provide resolve-program)
  11. ;;; resolve
  12. ;;
  13. ;; NOTE: Right now nothing actually adds to the 'set'
  14. ;; metadata of a syntax node
  15. ;;
  16. ;; once we have macros, they will need to do this
  17. (define specials
  18. '((lambda special)
  19. (begin special)
  20. (if special)
  21. (quote special)))
  22. (define (special? x)
  23. (and (pair? x) (eq? 'special (car x))))
  24. (define (resolve-program prg builtins)
  25. (let ((assoc-table
  26. (append (map (lambda (entry)
  27. (cons (car entry) (list 'variable (car entry))))
  28. builtins)
  29. specials)))
  30. (resolve-program^ prg assoc-table)))
  31. (define (resolve-program^ prg tbl)
  32. (if (null? prg)
  33. '()
  34. (let ((res (resolve-definition (car prg) tbl)))
  35. ;; TODO: need to add the new definition
  36. ;; the loop could move into resolve def to make that easy
  37. (cons res (resolve-program (cdr prg) tbl)))))
  38. (define (resolve-definition def builtins)
  39. ;; TODO: what if someone shadows DEFINE
  40. (let ((me-meta '((source . "resolve-definition"))))
  41. (match def
  42. ((list (syx 'id 'define meta-1) (syx 'id name meta-2) source)
  43. ;;
  44. ;; A simple definition (define <name> <single-form>)
  45. ;;
  46. ;; We make the definition as in scope before resolving it
  47. ;; this allows for recursive functions
  48. ;; TODO (update-env! env (make-dummy-binding name))
  49. (let ((ss-env (ss-env-make builtins)))
  50. (list (syx 'id 'define meta-1) (syx 'id name meta-2)
  51. (resolve-exp source ss-env))))
  52. ((list (syx 'id 'define meta-1) (list* header args) source)
  53. ;;
  54. ;; Handle implicit lambda definitions
  55. ;;
  56. ;; (define (f x y) y) ~> (define f (lambda (x y) y))
  57. ;;
  58. (resolve-definition
  59. (list (syx 'id 'define meta-1)
  60. header
  61. (list (syx 'id 'lambda me-meta) args source))
  62. builtins))
  63. ((list* (syx 'id 'define meta-1) header source source*)
  64. ;;
  65. ;; Handle implicit begin inside a definition
  66. ;;
  67. (resolve-definition
  68. (list (syx 'id 'define meta-1) header
  69. (list* (syx 'id 'begin me-meta) source source*))
  70. builtins))
  71. (else
  72. (error "resolve-definition: Bad definition!" def)))))
  73. (define (resolve-exp exp ss-env)
  74. (define (ss-lookup exp)
  75. (scope-set-lookup ss-env
  76. (syx-id exp)
  77. (union +
  78. (syx-set exp)
  79. (ss-env-current-scope-set ss-env))))
  80. (cond ((syx-atomic? exp) exp)
  81. ((syx-id? exp)
  82. (ss-lookup exp))
  83. ((null? exp)
  84. '())
  85. ((and (pair? exp)
  86. (syx-id? (car exp))
  87. (special? (ss-lookup (car exp))))
  88. ;; A special form or macro
  89. ;; TODO: do we have to actually do a resolution here?
  90. ;; I think we do because otherwise you could rename
  91. ;; one special as another and it'd get them mixed up
  92. ;; make sure to create a test for this
  93. (resolve-special exp ss-env))
  94. ((pair? exp)
  95. ;; A regular function application
  96. (cons (resolve-exp (car exp) ss-env)
  97. (resolve-exp (cdr exp) ss-env)))
  98. (else (error "resolve-exp: bad syntax!" exp))))
  99. ;; changes
  100. ;;
  101. ;; env stores a scope counter
  102. ;; env stores the current scope set (nested)
  103. ;; env stores a hash table mapping name * set --> value
  104. ;;
  105. ;; new function (add-scopeset-binding! env scop name value)
  106. ;; adds a scope set binding to the environment hash table
  107. ;; name * (current scope u {scop}) --> value
  108. ;;
  109. ;; changed function (extend-env env scop)
  110. ;; now this adds scop to the current scop set of our env
  111. (define (resolve-special exp env)
  112. (let ((me-meta '((source . "resolve-special"))))
  113. (match exp
  114. ((list (syx 'id 'lambda meta) params body)
  115. ;; We see a lambda special form
  116. ;; Validate that it is well formed
  117. (unless (every syx-id? params)
  118. (error "malformed lambda: parameters are not variables" exp))
  119. ;; create a new scope for this binder
  120. (let* ((sm ((ss-env-scope-counter env)))
  121. ;; making a mapping var,scope u {sm} -> gensym(var)
  122. (param-names (map syx-id params))
  123. (gen-params (map (lambda (p n)
  124. (syx (syx-type p)
  125. (gensym n)
  126. (syx-metadata p)))
  127. params
  128. param-names)))
  129. (for-each (lambda (nm gen)
  130. (add-scopeset-binding! env sm nm gen))
  131. param-names gen-params)
  132. (list (syx 'special 'lambda meta)
  133. gen-params
  134. (resolve-exp body (extend-env env sm)))))
  135. ((list* (syx 'id 'lambda meta) params body body*)
  136. ;; This case just handles the implicit begin of lambda
  137. (resolve-exp
  138. (list (syx 'id 'lambda meta) params
  139. (list* (syx 'id 'begin me-meta) body body*))
  140. env))
  141. ((list (syx 'id 'begin meta))
  142. (error "empty begin"))
  143. ((list* (syx 'id 'begin meta) exps)
  144. (list* (syx 'special 'begin meta) (map (lambda (exp) (resolve-exp exp env)) exps)))
  145. ((list (syx 'id 'if meta) t c a)
  146. (list (syx 'special 'if meta)
  147. (resolve-exp t env)
  148. (resolve-exp c env)
  149. (resolve-exp a env)))
  150. ((list (syx 'id 'if meta) t c)
  151. (error "illegal sussmans pirate" exp))
  152. ((list (syx 'id 'quote meta) m)
  153. (syx->datum m))
  154. (else (error "invalid special form syntax in resolve-special" exp)))))