Merge branch 'Haxe'
[jackhill/mal.git] / lua / core.lua
CommitLineData
9d42904e
JM
1local utils = require('utils')
2local types = require('types')
3local reader = require('reader')
4local printer = require('printer')
5local readline = require('readline')
af8d51d1 6local socket = require('socket')
9d42904e
JM
7
8local Nil, List, _pr_str = types.Nil, types.List, printer._pr_str
9
10local M = {}
11
12-- string functions
13
14function pr_str(...)
15 return table.concat(
16 utils.map(function(e) return _pr_str(e, true) end, arg), " ")
17end
18
19function str(...)
20 return table.concat(
21 utils.map(function(e) return _pr_str(e, false) end, arg), "")
22end
23
24function prn(...)
25 print(table.concat(
26 utils.map(function(e) return _pr_str(e, true) end, arg), " "))
3e0b36dc 27 io.flush()
9d42904e
JM
28 return Nil
29end
30
31function println(...)
32 print(table.concat(
33 utils.map(function(e) return _pr_str(e, false) end, arg), " "))
3e0b36dc 34 io.flush()
9d42904e
JM
35 return Nil
36end
37
38function slurp(file)
39 local lines = {}
40 for line in io.lines(file) do
41 lines[#lines+1] = line
42 end
43 return table.concat(lines, "\n") .. "\n"
44end
45
46function do_readline(prompt)
47 local line = readline.readline(prompt)
48 if line == nil then
49 return Nil
50 else
51 return line
52 end
53end
54
55-- hash map functions
56
57function assoc(hm, ...)
58 return types._assoc_BANG(types.copy(hm), unpack(arg))
59end
60
61function dissoc(hm, ...)
62 return types._dissoc_BANG(types.copy(hm), unpack(arg))
63end
64
65function get(hm, key)
66 local res = hm[key]
67 if res == nil then return Nil end
68 return res
69end
70
71function keys(hm)
72 local res = {}
73 for k,v in pairs(hm) do
74 res[#res+1] = k
75 end
76 return List:new(res)
77end
78
79function vals(hm)
80 local res = {}
81 for k,v in pairs(hm) do
82 res[#res+1] = v
83 end
84 return List:new(res)
85end
86
87-- sequential functions
88
89function cons(a,lst)
90 local new_lst = lst:slice(1)
91 table.insert(new_lst, 1, a)
92 return List:new(new_lst)
93end
94
95function concat(...)
96 local new_lst = {}
97 for i = 1, #arg do
98 for j = 1, #arg[i] do
99 table.insert(new_lst, arg[i][j])
100 end
101 end
102 return List:new(new_lst)
103end
104
105function nth(seq, idx)
106 if idx+1 <= #seq then
107 return seq[idx+1]
108 else
109 types.throw("nth: index out of range")
110 end
111end
112
113function first(a)
114 if #a == 0 then
115 return Nil
116 else
117 return a[1]
118 end
119end
120
121function apply(f, ...)
122 if types._malfunc_Q(f) then
123 f = f.fn
124 end
125 local args = concat(types.slice(arg, 1, #arg-1),
126 arg[#arg])
127 return f(unpack(args))
128end
129
130function map(f, lst)
131 if types._malfunc_Q(f) then
132 f = f.fn
133 end
134 return List:new(utils.map(f, lst))
135end
136
137-- metadata functions
138
139function meta(obj)
140 local m = getmetatable(obj)
141 if m == nil or m.meta == nil then return Nil end
142 return m.meta
143end
144
145function with_meta(obj, meta)
146 local new_obj = types.copy(obj)
147 getmetatable(new_obj).meta = meta
148 return new_obj
149end
150
151-- atom functions
152
153function swap_BANG(atm,f,...)
154 if types._malfunc_Q(f) then
155 f = f.fn
156 end
157 local args = List:new(arg)
158 table.insert(args, 1, atm.val)
159 atm.val = f(unpack(args))
160 return atm.val
161end
162
1ad8d501
MK
163local function conj(obj, ...)
164 local new_obj = types.copy(obj)
165 if types._list_Q(new_obj) then
166 for i, v in ipairs(arg) do
167 table.insert(new_obj, 1, v)
168 end
169 else
170 for i, v in ipairs(arg) do
171 table.insert(new_obj, v)
172 end
173 end
174 return new_obj
175end
176
9d42904e
JM
177M.ns = {
178 ['='] = types._equal_Q,
179 throw = types.throw,
180
181 ['nil?'] = function(a) return a==Nil end,
182 ['true?'] = function(a) return a==true end,
183 ['false?'] = function(a) return a==false end,
184 symbol = function(a) return types.Symbol:new(a) end,
185 ['symbol?'] = function(a) return types._symbol_Q(a) end,
186 keyword = function(a) return "\177"..a end,
187 ['keyword?'] = function(a) return types._keyword_Q(a) end,
188
189 ['pr-str'] = pr_str,
190 str = str,
191 prn = prn,
192 println = println,
193 ['read-string'] = reader.read_str,
194 readline = do_readline,
195 slurp = slurp,
196
197 ['<'] = function(a,b) return a<b end,
198 ['<='] = function(a,b) return a<=b end,
199 ['>'] = function(a,b) return a>b end,
200 ['>='] = function(a,b) return a>=b end,
201 ['+'] = function(a,b) return a+b end,
202 ['-'] = function(a,b) return a-b end,
203 ['*'] = function(a,b) return a*b end,
204 ['/'] = function(a,b) return math.floor(a/b) end,
af8d51d1 205 ['time-ms'] = function() return math.floor(socket.gettime() * 1000) end,
9d42904e
JM
206
207 list = function(...) return List:new(arg) end,
208 ['list?'] = function(a) return types._list_Q(a) end,
209 vector = function(...) return types.Vector:new(arg) end,
210 ['vector?'] = types._vector_Q,
211 ['hash-map'] = types.hash_map,
212 ['map?'] = types._hash_map_Q,
213 assoc = assoc,
214 dissoc = dissoc,
215 get = get,
216 ['contains?'] = function(a,b) return a[b] ~= nil end,
217 keys = keys,
218 vals = vals,
219
220 ['sequential?'] = types._sequential_Q,
221 cons = cons,
222 concat = concat,
223 nth = nth,
224 first = first,
225 rest = function(a) return List:new(a:slice(2)) end,
226 ['empty?'] = function(a) return a==Nil or #a == 0 end,
227 count = function(a) return #a end,
228 apply = apply,
229 map = map,
1ad8d501 230 conj = conj,
9d42904e
JM
231
232 meta = meta,
233 ['with-meta'] = with_meta,
234 atom = function(a) return types.Atom:new(a) end,
235 ['atom?'] = types._atom_Q,
236 deref = function(a) return a.val end,
237 ['reset!'] = function(a,b) a.val = b; return b end,
238 ['swap!'] = swap_BANG,
239}
240
241return M
242