Merge pull request #406 from chr15m/lib-alias-hacks
[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 if not a0 then return ast end
43 local a0sym = types._symbol_Q(a0) and a0.val or ""
44 if 'def!' == a0sym then
45 return env:set(a1, EVAL(a2, env))
46 elseif 'let*' == a0sym then
47 local let_env = Env:new(env)
48 for i = 1,#a1,2 do
49 let_env:set(a1[i], EVAL(a1[i+1], let_env))
50 end
51 return EVAL(a2, let_env)
52 else
53 local args = eval_ast(ast, env)
54 local f = table.remove(args, 1)
55 return f(table.unpack(args))
56 end
57 end
58
59 -- print
60 function PRINT(exp)
61 return printer._pr_str(exp, true)
62 end
63
64 -- repl
65 local repl_env = Env:new()
66 function rep(str)
67 return PRINT(EVAL(READ(str),repl_env))
68 end
69
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 a*b end)
73 repl_env:set(types.Symbol:new('/'), function(a,b) return math.floor(a/b) end)
74
75 if #arg > 0 and arg[1] == "--raw" then
76 readline.raw = true
77 end
78
79 while true do
80 line = readline.readline("user> ")
81 if not line then break end
82 xpcall(function()
83 print(rep(line))
84 end, function(exc)
85 if exc then
86 if types._malexception_Q(exc) then
87 exc = printer._pr_str(exc.val, true)
88 end
89 print("Error: " .. exc)
90 print(debug.traceback())
91 end
92 end)
93 end