Merge pull request #174 from dubek/issue_166_schemes
[jackhill/mal.git] / racket / stepA_mal.rkt
CommitLineData
f5223195
JM
1#!/usr/bin/env racket
2#lang racket
3
4(require "readline.rkt" "types.rkt" "reader.rkt" "printer.rkt"
5 "env.rkt" "core.rkt")
6
7;; read
8(define (READ str)
9 (read_str str))
10
11;; eval
12(define (is-pair x)
13 (and (_sequential? x) (> (_count x) 0)))
14
15(define (quasiquote ast)
16 (cond
17 [(not (is-pair ast))
18 (list 'quote ast)]
19
20 [(equal? 'unquote (_nth ast 0))
21 (_nth ast 1)]
22
23 [(and (is-pair (_nth ast 0))
24 (equal? 'splice-unquote (_nth (_nth ast 0) 0)))
25 (list 'concat (_nth (_nth ast 0) 1) (quasiquote (_rest ast)))]
26
27 [else
28 (list 'cons (quasiquote (_nth ast 0)) (quasiquote (_rest ast)))]))
29
30(define (macro? ast env)
31 (and (list? ast)
32 (symbol? (first ast))
33 (not (equal? null (send env find (first ast))))
34 (let ([fn (send env get (first ast))])
35 (and (malfunc? fn) (malfunc-macro? fn)))))
36
37(define (macroexpand ast env)
38 (if (macro? ast env)
39 (let ([mac (malfunc-fn (send env get (first ast)))])
40 (macroexpand (apply mac (rest ast)) env))
41 ast))
42
43(define (eval-ast ast env)
44 (cond
45 [(symbol? ast) (send env get ast)]
46 [(_sequential? ast) (_map (lambda (x) (EVAL x env)) ast)]
47 [(hash? ast) (make-hash
48 (dict-map ast (lambda (k v) (cons k (EVAL v env)))))]
49 [else ast]))
50
51(define (EVAL ast env)
52 ;(printf "~a~n" (pr_str ast true))
53 (if (not (list? ast))
54 (eval-ast ast env)
55
56 (let ([ast (macroexpand ast env)])
57 (if (not (list? ast))
0d629719 58 (eval-ast ast env)
f5223195
JM
59 (let ([a0 (_nth ast 0)])
60 (cond
61 [(eq? 'def! a0)
62 (send env set (_nth ast 1) (EVAL (_nth ast 2) env))]
63 [(eq? 'let* a0)
64 (let ([let-env (new Env% [outer env] [binds null] [exprs null])])
65 (_map (lambda (b_e)
66 (send let-env set (_first b_e)
67 (EVAL (_nth b_e 1) let-env)))
68 (_partition 2 (_to_list (_nth ast 1))))
69 (EVAL (_nth ast 2) let-env))]
70 [(eq? 'quote a0)
71 (_nth ast 1)]
72 [(eq? 'quasiquote a0)
73 (EVAL (quasiquote (_nth ast 1)) env)]
74 [(eq? 'defmacro! a0)
75 (let* ([func (EVAL (_nth ast 2) env)]
76 [mac (struct-copy malfunc func [macro? #t])])
77 (send env set (_nth ast 1) mac))]
78 [(eq? 'macroexpand a0)
79 (macroexpand (_nth ast 1) env)]
80 [(eq? 'try* a0)
81 (if (eq? 'catch* (_nth (_nth ast 2) 0))
82 (let ([efn (lambda (exc)
83 (EVAL (_nth (_nth ast 2) 2)
84 (new Env%
85 [outer env]
86 [binds (list (_nth (_nth ast 2) 1))]
87 [exprs (list exc)])))])
88 (with-handlers
89 ([mal-exn? (lambda (exc) (efn (mal-exn-val exc)))]
90 [string? (lambda (exc) (efn exc))]
91 [exn:fail? (lambda (exc) (efn (format "~a" exc)))])
92 (EVAL (_nth ast 1) env)))
93 (EVAL (_nth ast 1)))]
94 [(eq? 'do a0)
95 (eval-ast (drop (drop-right ast 1) 1) env)
96 (EVAL (last ast) env)]
97 [(eq? 'if a0)
98 (let ([cnd (EVAL (_nth ast 1) env)])
99 (if (or (eq? cnd nil) (eq? cnd #f))
100 (if (> (length ast) 3)
101 (EVAL (_nth ast 3) env)
102 nil)
103 (EVAL (_nth ast 2) env)))]
104 [(eq? 'fn* a0)
105 (malfunc
106 (lambda args (EVAL (_nth ast 2)
107 (new Env% [outer env]
108 [binds (_nth ast 1)]
109 [exprs args])))
110 (_nth ast 2) env (_nth ast 1) #f nil)]
111 [else (let* ([el (eval-ast ast env)]
112 [f (first el)]
113 [args (rest el)])
114 (if (malfunc? f)
115 (EVAL (malfunc-ast f)
116 (new Env%
117 [outer (malfunc-env f)]
118 [binds (malfunc-params f)]
119 [exprs args]))
120 (apply f args)))]))))))
121
122;; print
123(define (PRINT exp)
124 (pr_str exp true))
125
126;; repl
127(define repl-env
128 (new Env% [outer null] [binds null] [exprs null]))
129(define (rep str)
130 (PRINT (EVAL (READ str) repl-env)))
131
132(for () ;; ignore return values
133
134;; core.rkt: defined using Racket
135(hash-for-each core_ns (lambda (k v) (send repl-env set k v)))
136(send repl-env set 'eval (lambda [ast] (EVAL ast repl-env)))
137(send repl-env set '*ARGV* (list))
138
139;; core.mal: defined using the language itself
140(rep "(def! *host-language* \"racket\")")
141(rep "(def! not (fn* (a) (if a false true)))")
142(rep "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
143(rep "(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))")
48572759
DM
144(rep "(def! *gensym-counter* (atom 0))")
145(rep "(def! gensym (fn* [] (symbol (str \"G__\" (swap! *gensym-counter* (fn* [x] (+ 1 x)))))))")
146(rep "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) (let* (condvar (gensym)) `(let* (~condvar ~(first xs)) (if ~condvar ~condvar (or ~@(rest xs)))))))))")
f5223195
JM
147
148)
149
150(define (repl-loop)
151 (let ([line (readline "user> ")])
152 (when (not (eq? nil line))
153 (with-handlers
154 ([string? (lambda (exc) (printf "Error: ~a~n" exc))]
155 [mal-exn? (lambda (exc) (printf "Error: ~a~n"
156 (pr_str (mal-exn-val exc) true)))]
157 [blank-exn? (lambda (exc) null)])
158 (printf "~a~n" (rep line)))
159 (repl-loop))))
160(let ([args (current-command-line-arguments)])
161 (if (> (vector-length args) 0)
162 (for () (rep (string-append "(load-file \"" (vector-ref args 0) "\")")))
163 (begin
164 (rep "(println (str \"Mal [\" *host-language* \"]\"))")
165 (repl-loop))))