vb: add seq and string?
[jackhill/mal.git] / julia / step7_quote.jl
CommitLineData
e6fd6af2
JM
1#!/usr/bin/env julia
2
82484631 3push!(LOAD_PATH, pwd(), "/usr/share/julia/base")
85110962 4import readline_mod
e6fd6af2
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 ispair(ast)
18 (isa(ast, Array) || isa(ast, Tuple)) && length(ast) > 0
19end
20
21function quasiquote(ast)
22 if !ispair(ast)
82484631 23 [[:quote]; Any[ast]]
e6fd6af2
JM
24 elseif ast[1] == :unquote
25 ast[2]
26 elseif ispair(ast[1]) && ast[1][1] == symbol("splice-unquote")
82484631 27 [[:concat]; Any[ast[1][2]]; Any[quasiquote(ast[2:end])]]
e6fd6af2 28 else
82484631 29 [[:cons]; Any[quasiquote(ast[1])]; Any[quasiquote(ast[2:end])]]
e6fd6af2
JM
30 end
31end
32
33function eval_ast(ast, env)
34 if typeof(ast) == Symbol
82484631 35 env_get(env,ast)
e6fd6af2
JM
36 elseif isa(ast, Array) || isa(ast, Tuple)
37 map((x) -> EVAL(x,env), ast)
7e0bb668
JM
38 elseif isa(ast, Dict)
39 [EVAL(x[1],env) => EVAL(x[2], env) for x=ast]
e6fd6af2
JM
40 else
41 ast
42 end
43end
44
45function EVAL(ast, env)
46 while true
82484631 47 #println("EVAL: $(printer.pr_str(ast,true))")
2aa39ccd 48 if !isa(ast, Array) return eval_ast(ast, env) end
e6fd6af2
JM
49
50 # apply
51 if :def! == ast[1]
82484631 52 return env_set(env, ast[2], EVAL(ast[3], env))
e6fd6af2
JM
53 elseif symbol("let*") == ast[1]
54 let_env = Env(env)
55 for i = 1:2:length(ast[2])
82484631 56 env_set(let_env, ast[2][i], EVAL(ast[2][i+1], let_env))
e6fd6af2
JM
57 end
58 env = let_env
59 ast = ast[3]
60 # TCO loop
61 elseif :quote == ast[1]
62 return ast[2]
63 elseif :quasiquote == ast[1]
64 ast = quasiquote(ast[2])
65 # TCO loop
66 elseif :do == ast[1]
67 eval_ast(ast[2:end-1], env)
68 ast = ast[end]
69 # TCO loop
70 elseif :if == ast[1]
71 cond = EVAL(ast[2], env)
72 if cond === nothing || cond === false
73 if length(ast) >= 4
74 ast = ast[4]
75 # TCO loop
76 else
77 return nothing
78 end
79 else
80 ast = ast[3]
81 # TCO loop
82 end
83 elseif symbol("fn*") == ast[1]
84 return MalFunc(
f98e3ea9 85 (args...) -> EVAL(ast[3], Env(env, ast[2], Any[args...])),
e6fd6af2
JM
86 ast[3], env, ast[2])
87 else
88 el = eval_ast(ast, env)
89 f, args = el[1], el[2:end]
90 if isa(f, MalFunc)
91 ast = f.ast
92 env = Env(f.env, f.params, args)
93 # TCO loop
94 else
95 return f(args...)
96 end
97 end
98 end
99end
100
101# PRINT
102function PRINT(exp)
103 printer.pr_str(exp)
104end
105
106# REPL
107repl_env = nothing
108function REP(str)
109 return PRINT(EVAL(READ(str), repl_env))
110end
111
112# core.jl: defined using Julia
113repl_env = Env(nothing, core.ns)
82484631
JM
114env_set(repl_env, :eval, (ast) -> EVAL(ast, repl_env))
115env_set(repl_env, symbol("*ARGV*"), ARGS[2:end])
e6fd6af2
JM
116
117# core.mal: defined using the language itself
118REP("(def! not (fn* (a) (if a false true)))")
119REP("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))")
120
121if length(ARGS) > 0
122 REP("(load-file \"$(ARGS[1])\")")
123 exit(0)
124end
125
126while true
85110962
JM
127 line = readline_mod.do_readline("user> ")
128 if line === nothing break end
e6fd6af2
JM
129 try
130 println(REP(line))
131 catch e
132 if isa(e, ErrorException)
133 println("Error: $(e.msg)")
134 else
135 println("Error: $(string(e))")
136 end
82484631
JM
137 # TODO: show at least part of stack
138 if !isa(e, StackOverflowError)
139 bt = catch_backtrace()
140 Base.show_backtrace(STDERR, bt)
141 end
e6fd6af2
JM
142 println()
143 end
144end