i8.scm 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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. (define specials '(lambda if begin quote))
  24. (struct special ((id #:mutable) (metadata #:mutable)) #:transparent)
  25. ;;; resolve
  26. ;;
  27. (define (resolve-prg prg env^ spec)
  28. (if (null? prg)
  29. '()
  30. (match (car prg)
  31. (`(,(sid define meta) ,name ,source)
  32. (cons `(,(sid define meta) ,name ,(resolve-exp source env^ spec))
  33. (resolve-prg (cdr prg)
  34. (cons (cons (sid-id name) (sid-id name)) env^)
  35. (remove (sid-id name) spec)))))))
  36. (define (resolve-exp exp env^ spec)
  37. (cond ((or (number? exp) (boolean? exp) (string? exp)) exp)
  38. ((sid? exp)
  39. ;;
  40. ;; we see a variable
  41. ;; ensure that it is bound
  42. ;; and freshen it with a gensym if so
  43. ;;
  44. (cond ((assoc (sid-id exp) env^) => (lambda (i) (sid (cdr i) (sid-metadata exp))))
  45. (else (error "unbound variable" exp))))
  46. ((list? exp)
  47. (if (and (sid? (car exp)) (member (sid-id (car exp)) spec))
  48. (resolve-special exp env^ spec)
  49. (map (lambda (i) (resolve-exp i env^ spec)) exp)))
  50. (else (error "syntax error" exp))))
  51. (define (resolve-special exp env^ spec)
  52. (match exp
  53. (`(,(sid 'lambda m1) (,(sid x m2)) ,b)
  54. (let ((x^ (gensym x)))
  55. `(,(special 'lambda m1)
  56. (,x^)
  57. ,(resolve-exp b (cons (cons x x^) env^)
  58. (remove x spec)))))
  59. (`(,(sid 'if m1) ,t ,c ,a)
  60. `(,(special 'if m1)
  61. ,(resolve-exp t env^ spec)
  62. ,(resolve-exp c env^ spec)
  63. ,(resolve-exp a env^ spec)))
  64. (`(,(sid 'if m1) ,t ,c)
  65. (error "illegal: sussmans pirate at" m1))
  66. (`(,(sid 'begin m1) . ,stmts)
  67. (if (null? stmts)
  68. (error "bad begin at" m1)
  69. `(,(special 'begin m1)
  70. . ,(map (lambda (e) (resolve-exp e env^ spec)) stmts))))
  71. (`(,(sid 'quote m1) ,data)
  72. `(,(special 'quote m1)
  73. ,(syx->datum data)))
  74. (else (error "invalid syntax" exp (syx->datum exp)))))
  75. ;;; interpret
  76. ;;
  77. (define (interpret-prg prg env)
  78. (if (null? prg)
  79. #t
  80. (match (car prg)
  81. (`(,(sid define meta) ,name ,exp)
  82. (let ((value (interpret-exp exp env)))
  83. (interpret-prg (cdr prg)
  84. (cons (cons (sid-id name) value) env)))))))
  85. (define (interpret-exp exp env)
  86. (cond ((or (number? exp) (boolean? exp) (string? exp)) exp)
  87. ((sid? exp)
  88. (cond ((assoc (sid-id exp) env) => cdr)
  89. (else (error "impossible unbound variable:" exp))))
  90. ((list? exp)
  91. (if (special? (car exp))
  92. (interpret-special exp env)
  93. (apply (interpret-exp (car exp) env)
  94. (map (lambda (i) (interpret-exp i env)) (cdr exp)))))
  95. (else (error "?" exp))))
  96. (define (interpret-special exp env)
  97. (match exp
  98. (`(,(special 'lambda meta) (,x) ,b)
  99. (lambda (x^)
  100. (interpret-exp b (cons (cons x x^) env))))
  101. (`(,(special 'if meta) ,t ,c ,a)
  102. (if (interpret-exp t env)
  103. (interpret-exp c env)
  104. (interpret-exp a env)))
  105. (`(,(special 'begin meta) . ,stmts)
  106. (let loop ((stmts stmts))
  107. (if (null? (cdr stmts))
  108. (interpret-exp (car stmts) env) ;; tail position
  109. (begin (interpret-exp (car stmts) env)
  110. (loop (cdr stmts))))))
  111. (`(,(special 'quote meta) ,d)
  112. d)
  113. ))
  114. ;;; main
  115. ;;
  116. (define (check filename)
  117. (resolve-prg (parse-file filename) builtins^ specials))
  118. (define (go filename)
  119. (interpret-prg
  120. (resolve-prg (parse-file filename) builtins^ specials)
  121. builtins))