All: rename stepA_interop to stepA_mal
[jackhill/mal.git] / lua / step3_env.lua
1 #!/usr/bin/env lua
2
3 local table = require('table')
4
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 List, Vector, HashMap = types.List, types.Vector, types.HashMap
12
13 -- read
14 function READ(str)
15 return reader.read_str(str)
16 end
17
18 -- eval
19 function eval_ast(ast, env)
20 if types._symbol_Q(ast) then
21 return env:get(ast)
22 elseif types._list_Q(ast) then
23 return List:new(utils.map(function(x) return EVAL(x,env) end,ast))
24 elseif types._vector_Q(ast) then
25 return Vector:new(utils.map(function(x) return EVAL(x,env) end,ast))
26 elseif types._hash_map_Q(ast) then
27 local new_hm = {}
28 for k,v in pairs(ast) do
29 new_hm[EVAL(k, env)] = EVAL(v, env)
30 end
31 return HashMap:new(new_hm)
32 else
33 return ast
34 end
35 end
36
37 function EVAL(ast, env)
38 --print("EVAL: "..printer._pr_str(ast,true))
39 if not types._list_Q(ast) then return eval_ast(ast, env) end
40
41 local a0,a1,a2 = ast[1], ast[2],ast[3]
42 local a0sym = types._symbol_Q(a0) and a0.val or ""
43 if 'def!' == a0sym then
44 return env:set(a1, EVAL(a2, env))
45 elseif 'let*' == a0sym then
46 local let_env = Env:new(env)
47 for i = 1,#a1,2 do
48 let_env:set(a1[i], EVAL(a1[i+1], let_env))
49 end
50 return EVAL(a2, let_env)
51 else
52 local args = eval_ast(ast, env)
53 local f = table.remove(args, 1)
54 return f(unpack(args))
55 end
56 end
57
58 -- print
59 function PRINT(exp)
60 return printer._pr_str(exp, true)
61 end
62
63 -- repl
64 local repl_env = Env:new()
65 function rep(str)
66 return PRINT(EVAL(READ(str),repl_env))
67 end
68
69 repl_env:set(types.Symbol:new('+'), function(a,b) return a+b end)
70 repl_env:set(types.Symbol:new('-'), function(a,b) return a-b end)
71 repl_env:set(types.Symbol:new('*'), function(a,b) return a*b end)
72 repl_env:set(types.Symbol:new('/'), function(a,b) return math.floor(a/b) end)
73
74 while true do
75 line = readline.readline("user> ")
76 if not line then break end
77 xpcall(function()
78 print(rep(line))
79 end, function(exc)
80 if exc then
81 if types._malexception_Q(exc) then
82 exc = printer._pr_str(exc.val, true)
83 end
84 print("Error: " .. exc)
85 print(debug.traceback())
86 end
87 end)
88 end