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