i9.scm 4.0 KB

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