Commit | Line | Data |
---|---|---|
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) |