i10.scm 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #lang racket
  2. (require racket/match)
  3. (require racket/include)
  4. (require "parser.scm")
  5. ;;; rubbish/time waste because immutable conses
  6. ;;
  7. (define (set-assoc-box! soc key value)
  8. ;; if it already exists mutate it
  9. ;; else cons it on
  10. (cond ((assoc key soc) =>
  11. (lambda (entry)
  12. (set-box-value! (cdr entry) value)
  13. soc))
  14. (else (cons (cons key (box value)) soc))))
  15. (define (assoc-box-ref soc key default)
  16. (cond ((assoc key soc) =>
  17. (lambda (entry)
  18. (box-value (cdr entry))))
  19. (else default)))
  20. ;;; data
  21. ;;
  22. (define (print s) (display s) (newline))
  23. (struct box ((value #:mutable)) #:transparent)
  24. (define-syntax define-builtins
  25. (syntax-rules ()
  26. ((define-builtins builtins^ builtins <name> ...)
  27. (begin
  28. (define builtins^
  29. `((<name> . <name>) ...))
  30. (define builtins
  31. `((<name> . ,(box <name>)) ...))))))
  32. (define-builtins builtins^ builtins
  33. cons car cdr
  34. box box-value set-box-value!
  35. = eq? equal? not
  36. + - * /
  37. display newline print
  38. ;; predicates from R5RS
  39. boolean?
  40. pair?
  41. symbol?
  42. number?
  43. char?
  44. string?
  45. vector?
  46. procedure?
  47. )
  48. (define specials '(lambda if begin quote
  49. let))
  50. ;;; resolve
  51. ;;
  52. (define (resolve-prg prg env^ spec)
  53. (if (null? prg)
  54. '()
  55. (match (car prg)
  56. (`(,(sid define meta) ,name ,source)
  57. ;; think about whether we should gensym here or not
  58. (let ((env^ (cons (cons (sid-id name) (sid-id name)) env^)))
  59. (cons `(,(sid define meta) ,name ,(resolve-exp source env^ spec))
  60. (resolve-prg (cdr prg)
  61. env^
  62. (remove (sid-id name) spec))))))))
  63. (define (resolve-exp exp env^ spec)
  64. (cond ((or (number? exp) (boolean? exp) (string? exp)) exp)
  65. ((sid? exp)
  66. ;;
  67. ;; we see a variable
  68. ;; ensure that it is bound
  69. ;; and freshen it with a gensym if so
  70. ;;
  71. (cond ((assoc (sid-id exp) env^) => (lambda (i) (sid (cdr i) (sid-metadata exp))))
  72. (else (error "unbound variable" exp))))
  73. ((list? exp)
  74. (if (and (sid? (car exp)) (member (sid-id (car exp)) spec))
  75. (resolve-special exp env^ spec)
  76. (map (lambda (i) (resolve-exp i env^ spec)) exp)))
  77. (else (error "syntax error" exp))))
  78. (define (resolve-special exp env^ spec)
  79. (match exp
  80. (`(,(sid 'lambda m1) ,args ,b)
  81. (let ((args^ (map gensym (map sid-id args))))
  82. `(,(special 'lambda m1)
  83. ,(map (lambda (a x) (sid x (sid-metadata a))) args args^)
  84. ,(resolve-exp b (append (map cons (map sid-id args) args^) env^)
  85. (remove* args spec)))))
  86. (`(,(sid 'if m1) ,t ,c ,a)
  87. `(,(special 'if m1)
  88. ,(resolve-exp t env^ spec)
  89. ,(resolve-exp c env^ spec)
  90. ,(resolve-exp a env^ spec)))
  91. (`(,(sid 'if m1) ,t ,c)
  92. (error "illegal: sussmans pirate at" m1))
  93. (`(,(sid 'begin m1) . ,stmts)
  94. (if (null? stmts)
  95. (error "bad begin at" m1)
  96. `(,(special 'begin m1)
  97. . ,(map (lambda (e) (resolve-exp e env^ spec)) stmts))))
  98. (`(,(sid 'quote m1) ,data)
  99. `(,(special 'quote m1)
  100. ,(syx->datum data)))
  101. (`(,(sid 'let m1) ,bindings ,body)
  102. (resolve-exp
  103. `((,(sid 'lambda m1) ,(map car bindings) ,body)
  104. . ,(map cadr bindings))
  105. env^ spec))
  106. (else (error "invalid syntax" exp (syx->datum exp)))))
  107. ;;; interpret
  108. ;;
  109. (define (interpret-prg prg env)
  110. (if (null? prg)
  111. #t
  112. (match (car prg)
  113. (`(,(sid define meta) ,name ,exp)
  114. (let ((value (interpret-exp exp env)))
  115. (set-assoc-box! env (sid-id name) value)
  116. (interpret-prg (cdr prg) env))))))
  117. (define (interpret-exp exp env)
  118. (cond ((or (number? exp) (boolean? exp) (string? exp)) exp)
  119. ((sid? exp) (assoc-box-ref env (sid-id exp) #f))
  120. ((list? exp)
  121. (if (special? (car exp))
  122. (interpret-special exp env)
  123. (let ((f (interpret-exp (car exp) env)))
  124. (unless (procedure? f)
  125. (error "can't apply non-procedure" (car exp)))
  126. (apply f
  127. (map (lambda (i) (interpret-exp i env)) (cdr exp))))))
  128. (else (error "?" exp))))
  129. (define (interpret-special exp env)
  130. (match exp
  131. (`(,(special 'lambda meta) ,args ,b)
  132. (lambda args^
  133. (let ((env (append (map (lambda (x x^)
  134. (cons (sid-id x) (box x^)))
  135. args args^) env)))
  136. (interpret-exp b env))))
  137. (`(,(special 'if meta) ,t ,c ,a)
  138. (if (interpret-exp t env)
  139. (interpret-exp c env)
  140. (interpret-exp a env)))
  141. (`(,(special 'begin meta) . ,stmts)
  142. (let loop ((stmts stmts))
  143. (if (null? (cdr stmts))
  144. (interpret-exp (car stmts) env) ;; tail position
  145. (begin (interpret-exp (car stmts) env)
  146. (loop (cdr stmts))))))
  147. (`(,(special 'quote meta) ,d)
  148. d)
  149. ))
  150. ;;; main
  151. ;;
  152. (define (check filename)
  153. (let ((r (resolve-prg (parse-file filename) builtins^ specials)))
  154. (print r)
  155. (print (syx->datum r))))
  156. (define (go filename)
  157. (let ((resolved (resolve-prg (parse-file filename) builtins^ specials)))
  158. (interpret-prg resolved builtins)))