Merge pull request #378 from asarhaddon/test-macro-not-changing-function
[jackhill/mal.git] / scheme / step5_tco.scm
CommitLineData
a9385e97
VS
1(import (scheme base))
2(import (scheme write))
3
4(import (lib util))
5(import (lib reader))
6(import (lib printer))
7(import (lib types))
8(import (lib env))
9(import (lib core))
10
11(define (READ input)
12 (read-str input))
13
14(define (eval-ast ast env)
15 (let ((type (and (mal-object? ast) (mal-type ast)))
16 (value (and (mal-object? ast) (mal-value ast))))
17 (case type
18 ((symbol) (env-get env value))
19 ((list) (mal-list (map (lambda (item) (EVAL item env)) value)))
20 ((vector) (mal-vector (vector-map (lambda (item) (EVAL item env)) value)))
21 ((map) (mal-map (alist-map (lambda (key value) (cons key (EVAL value env))) value)))
22 (else ast))))
23
24(define (EVAL ast env)
25 (let ((type (and (mal-object? ast) (mal-type ast))))
26 (if (not (eq? type 'list))
27 (eval-ast ast env)
28 (let ((items (mal-value ast)))
29 (if (null? items)
30 ast
31 (case (mal-value (car items))
32 ((def!)
33 (let ((symbol (mal-value (cadr items)))
34 (value (EVAL (list-ref items 2) env)))
35 (env-set env symbol value)
36 value))
37 ((let*)
38 (let ((env* (make-env env))
39 (binds (->list (mal-value (cadr items))))
40 (form (list-ref items 2)))
41 (let loop ((binds binds))
42 (when (pair? binds)
43 (let ((key (mal-value (car binds))))
44 (when (null? (cdr binds))
45 (error "unbalanced list"))
46 (let ((value (EVAL (cadr binds) env*)))
47 (env-set env* key value)
48 (loop (cddr binds))))))
49 (EVAL form env*))) ; TCO
50 ((do)
51 (let ((forms (cdr items)))
52 (if (null? forms)
53 mal-nil
54 ;; the evaluation order of map is unspecified
55 (let loop ((forms forms))
56 (let ((form (car forms))
57 (tail (cdr forms)))
58 (if (null? tail)
59 (EVAL form env) ; TCO
60 (begin
61 (EVAL form env)
62 (loop tail))))))))
63 ((if)
64 (let* ((condition (EVAL (cadr items) env))
65 (type (and (mal-object? condition)
66 (mal-type condition))))
67 (if (memq type '(false nil))
68 (if (< (length items) 4)
69 mal-nil
70 (EVAL (list-ref items 3) env)) ; TCO
71 (EVAL (list-ref items 2) env)))) ; TCO
72 ((fn*)
73 (let* ((binds (->list (mal-value (cadr items))))
74 (binds (map mal-value binds))
75 (body (list-ref items 2))
76 (fn (lambda args
77 (let ((env* (make-env env binds args)))
78 (EVAL body env*)))))
79 (make-func body binds env fn)))
80 (else
81 (let* ((items (mal-value (eval-ast ast env)))
82 (op (car items))
83 (ops (cdr items)))
84 (if (func? op)
85 (let* ((outer (func-env op))
86 (binds (func-params op))
87 (env* (make-env outer binds ops)))
88 (EVAL (func-ast op) env*)) ; TCO
89 (apply op ops))))))))))
90
91(define (PRINT ast)
92 (pr-str ast #t))
93
94(define repl-env (make-env #f))
95(for-each (lambda (kv) (env-set repl-env (car kv) (cdr kv))) ns)
96
97(define (rep input)
98 (PRINT (EVAL (READ input) repl-env)))
99
100(rep "(def! not (fn* (a) (if a false true)))")
101
a9385e97
VS
102(define (main)
103 (let loop ()
104 (let ((input (readline "user> ")))
105 (when input
106 (guard
107 (ex ((error-object? ex)
108 (when (not (memv 'empty-input (error-object-irritants ex)))
109 (display "[error] ")
110 (display (error-object-message ex))
dd7a4f55
JM
111 (newline)))
112 ((and (pair? ex) (eq? (car ex) 'user-error))
113 (display "[error] ")
114 (display (pr-str (cdr ex) #t))
115 (newline)))
a9385e97
VS
116 (display (rep input))
117 (newline))
118 (loop))))
119 (newline))
120
121(main)