TypeScript: setup initial environment
[jackhill/mal.git] / julia / step5_tco.jl
CommitLineData
421cdb5d
JM
1#!/usr/bin/env julia
2
82484631 3push!(LOAD_PATH, pwd(), "/usr/share/julia/base")
85110962 4import readline_mod
421cdb5d
JM
5import reader
6import printer
7using env
8import core
9using types
10
11# READ
12function READ(str)
13 reader.read_str(str)
14end
15
16# EVAL
17function 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
27end
28
29function 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
79end
80
81# PRINT
82function PRINT(exp)
83 printer.pr_str(exp)
84end
85
86# REPL
87repl_env = nothing
88function REP(str)
89 return PRINT(EVAL(READ(str), repl_env))
90end
91
92# core.jl: defined using Julia
93repl_env = Env(nothing, core.ns)
94
95# core.mal: defined using the language itself
96REP("(def! not (fn* (a) (if a false true)))")
97
98while 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
116end