3 local table = require('table')
5 local readline
= require('readline')
6 local utils
= require('utils')
7 local types
= require('types')
8 local reader
= require('reader')
9 local printer
= require('printer')
10 local Env
= require('env')
11 local core
= require('core')
12 local List
, Vector
, HashMap
= types
.List
, types
.Vector
, types
.HashMap
16 return reader
.read_str(str
)
20 function eval_ast(ast
, env
)
21 if types
._symbol_Q(ast
) then
23 elseif types
._list_Q(ast
) then
24 return List
:new(utils
.map(function(x
) return EVAL(x
,env
) end,ast
))
25 elseif types
._vector_Q(ast
) then
26 return Vector
:new(utils
.map(function(x
) return EVAL(x
,env
) end,ast
))
27 elseif types
._hash_map_Q(ast
) then
29 for k
,v
in pairs(ast
) do
30 new_hm
[EVAL(k
, env
)] = EVAL(v
, env
)
32 return HashMap
:new(new_hm
)
38 function EVAL(ast
, env
)
40 --print("EVAL: "..printer._pr_str(ast,true))
41 if not types
._list_Q(ast
) then return eval_ast(ast
, env
) end
43 local a0
,a1
,a2
,a3
= ast
[1], ast
[2],ast
[3],ast
[4]
44 local a0sym
= types
._symbol_Q(a0
) and a0
.val
or ""
45 if 'def!' == a0sym
then
46 return env
:set(a1
, EVAL(a2
, env
))
47 elseif 'let*' == a0sym
then
48 local let_env
= Env
:new(env
)
50 let_env
:set(a1
[i
], EVAL(a1
[i
+1], let_env
))
54 elseif 'do' == a0sym
then
55 local el
= eval_ast(ast
:slice(2,#ast
-1), env
)
56 ast
= ast
[#ast
] -- TCO
57 elseif 'if' == a0sym
then
58 local cond
= EVAL(a1
, env
)
59 if cond
== types
.Nil
or cond
== false then
60 if a3
then ast
= a3
else return types
.Nil
end -- TCO
64 elseif 'fn*' == a0sym
then
65 return types
.MalFunc
:new(function(...)
66 return EVAL(a2
, Env
:new(env
, a1
, arg
))
69 local args
= eval_ast(ast
, env
)
70 local f
= table.remove(args
, 1)
71 if types
._malfunc_Q(f
) then
73 env
= Env
:new(f
.env
, f
.params
, args
) -- TCO
75 return f(unpack(args
))
83 return printer
._pr_str(exp, true)
87 local repl_env
= Env
:new()
89 return PRINT(EVAL(READ(str
),repl_env
))
92 -- core.lua: defined using Lua
93 for k
,v
in pairs(core
.ns
) do
94 repl_env
:set(types
.Symbol
:new(k
), v
)
97 -- core.mal: defined using mal
98 rep("(def! not (fn* (a) (if a false true)))")
101 line
= readline
.readline("user> ")
102 if not line
then break end
107 if types
._malexception_Q(exc
) then
108 exc
= printer
._pr_str(exc
.val
, true)
110 print("Error: " .. exc
)
111 print(debug
.traceback())