Commit | Line | Data |
---|---|---|
421cdb5d JM |
1 | #!/usr/bin/env julia |
2 | ||
82484631 | 3 | push!(LOAD_PATH, pwd(), "/usr/share/julia/base") |
85110962 | 4 | import readline_mod |
421cdb5d JM |
5 | import reader |
6 | import printer | |
7 | using env | |
8 | import core | |
9 | using types | |
10 | ||
11 | # READ | |
12 | function READ(str) | |
13 | reader.read_str(str) | |
14 | end | |
15 | ||
16 | # EVAL | |
17 | function eval_ast(ast, env) | |
18 | if typeof(ast) == Symbol | |
82484631 | 19 | env_get(env,ast) |
421cdb5d JM |
20 | elseif isa(ast, Array) || isa(ast, Tuple) |
21 | map((x) -> EVAL(x,env), ast) | |
7e0bb668 JM |
22 | elseif isa(ast, Dict) |
23 | [EVAL(x[1],env) => EVAL(x[2], env) for x=ast] | |
421cdb5d JM |
24 | else |
25 | ast | |
26 | end | |
27 | end | |
28 | ||
29 | function EVAL(ast, env) | |
30 | while true | |
82484631 | 31 | #println("EVAL: $(printer.pr_str(ast,true))") |
7e0bb668 | 32 | if !isa(ast, Array) return eval_ast(ast, env) end |
6f8a5d05 | 33 | if isempty(ast) return ast end |
421cdb5d JM |
34 | |
35 | # apply | |
36 | if :def! == ast[1] | |
82484631 | 37 | return env_set(env, ast[2], EVAL(ast[3], env)) |
421cdb5d | 38 | elseif symbol("let*") == ast[1] |
7e0bb668 | 39 | let_env = Env(env) |
421cdb5d | 40 | for i = 1:2:length(ast[2]) |
82484631 | 41 | env_set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env)) |
421cdb5d JM |
42 | end |
43 | env = let_env | |
44 | ast = ast[3] | |
45 | # TCO loop | |
46 | elseif :do == ast[1] | |
47 | eval_ast(ast[2:end-1], env) | |
48 | ast = ast[end] | |
49 | # TCO loop | |
50 | elseif :if == ast[1] | |
51 | cond = EVAL(ast[2], env) | |
52 | if cond === nothing || cond === false | |
53 | if length(ast) >= 4 | |
54 | ast = ast[4] | |
55 | # TCO loop | |
56 | else | |
57 | return nothing | |
58 | end | |
59 | else | |
60 | ast = ast[3] | |
61 | # TCO loop | |
62 | end | |
63 | elseif symbol("fn*") == ast[1] | |
64 | return MalFunc( | |
f98e3ea9 | 65 | (args...) -> EVAL(ast[3], Env(env, ast[2], Any[args...])), |
421cdb5d JM |
66 | ast[3], env, ast[2]) |
67 | else | |
68 | el = eval_ast(ast, env) | |
69 | f, args = el[1], el[2:end] | |
70 | if isa(f, MalFunc) | |
71 | ast = f.ast | |
72 | env = Env(f.env, f.params, args) | |
73 | # TCO loop | |
74 | else | |
75 | return f(args...) | |
76 | end | |
77 | end | |
78 | end | |
79 | end | |
80 | ||
81 | ||
82 | function PRINT(exp) | |
83 | printer.pr_str(exp) | |
84 | end | |
85 | ||
86 | # REPL | |
87 | repl_env = nothing | |
88 | function REP(str) | |
89 | return PRINT(EVAL(READ(str), repl_env)) | |
90 | end | |
91 | ||
92 | # core.jl: defined using Julia | |
93 | repl_env = Env(nothing, core.ns) | |
94 | ||
95 | # core.mal: defined using the language itself | |
96 | REP("(def! not (fn* (a) (if a false true)))") | |
97 | ||
98 | while true | |
85110962 JM |
99 | line = readline_mod.do_readline("user> ") |
100 | if line === nothing break end | |
421cdb5d JM |
101 | try |
102 | println(REP(line)) | |
103 | catch e | |
104 | if isa(e, ErrorException) | |
105 | println("Error: $(e.msg)") | |
106 | else | |
107 | println("Error: $(string(e))") | |
108 | end | |
82484631 JM |
109 | # TODO: show at least part of stack |
110 | if !isa(e, StackOverflowError) | |
111 | bt = catch_backtrace() | |
112 | Base.show_backtrace(STDERR, bt) | |
113 | end | |
421cdb5d JM |
114 | println() |
115 | end | |
116 | end |