Merge pull request #172 from dubek/issue_166_sharps_crystal_lua_perl
[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
d46927d0
DM
121function rest(a)
122 if a == Nil then
123 return List:new()
124 else
125 return List:new(a:slice(2))
126 end
127end
128
9d42904e
JM
129function apply(f, ...)
130 if types._malfunc_Q(f) then
131 f = f.fn
132 end
133 local args = concat(types.slice(arg, 1, #arg-1),
134 arg[#arg])
135 return f(unpack(args))
136end
137
138function map(f, lst)
139 if types._malfunc_Q(f) then
140 f = f.fn
141 end
142 return List:new(utils.map(f, lst))
143end
144
145-- metadata functions
146
147function meta(obj)
148 local m = getmetatable(obj)
149 if m == nil or m.meta == nil then return Nil end
150 return m.meta
151end
152
153function with_meta(obj, meta)
154 local new_obj = types.copy(obj)
155 getmetatable(new_obj).meta = meta
156 return new_obj
157end
158
159-- atom functions
160
161function swap_BANG(atm,f,...)
162 if types._malfunc_Q(f) then
163 f = f.fn
164 end
165 local args = List:new(arg)
166 table.insert(args, 1, atm.val)
167 atm.val = f(unpack(args))
168 return atm.val
169end
170
1ad8d501
MK
171local function conj(obj, ...)
172 local new_obj = types.copy(obj)
173 if types._list_Q(new_obj) then
174 for i, v in ipairs(arg) do
175 table.insert(new_obj, 1, v)
176 end
177 else
178 for i, v in ipairs(arg) do
179 table.insert(new_obj, v)
180 end
181 end
182 return new_obj
183end
184
5f7cbd77
DM
185local function seq(obj, ...)
186 if obj == Nil or #obj == 0 then
187 return Nil
188 elseif types._list_Q(obj) then
189 return obj
190 elseif types._vector_Q(obj) then
191 return List:new(obj)
192 elseif types._string_Q(obj) then
193 local chars = {}
194 for i = 1, #obj do
195 chars[#chars+1] = string.sub(obj,i,i)
196 end
197 return List:new(chars)
198 end
199 return Nil
200end
201
9d42904e
JM
202M.ns = {
203 ['='] = types._equal_Q,
204 throw = types.throw,
205
206 ['nil?'] = function(a) return a==Nil end,
207 ['true?'] = function(a) return a==true end,
208 ['false?'] = function(a) return a==false end,
209 symbol = function(a) return types.Symbol:new(a) end,
210 ['symbol?'] = function(a) return types._symbol_Q(a) end,
5f7cbd77 211 ['string?'] = function(a) return types._string_Q(a) and "\177" ~= string.sub(a,1,1) end,
9d42904e
JM
212 keyword = function(a) return "\177"..a end,
213 ['keyword?'] = function(a) return types._keyword_Q(a) end,
214
215 ['pr-str'] = pr_str,
216 str = str,
217 prn = prn,
218 println = println,
219 ['read-string'] = reader.read_str,
220 readline = do_readline,
221 slurp = slurp,
222
223 ['<'] = function(a,b) return a<b end,
224 ['<='] = function(a,b) return a<=b end,
225 ['>'] = function(a,b) return a>b end,
226 ['>='] = function(a,b) return a>=b end,
227 ['+'] = function(a,b) return a+b end,
228 ['-'] = function(a,b) return a-b end,
229 ['*'] = function(a,b) return a*b end,
230 ['/'] = function(a,b) return math.floor(a/b) end,
af8d51d1 231 ['time-ms'] = function() return math.floor(socket.gettime() * 1000) end,
9d42904e
JM
232
233 list = function(...) return List:new(arg) end,
234 ['list?'] = function(a) return types._list_Q(a) end,
235 vector = function(...) return types.Vector:new(arg) end,
236 ['vector?'] = types._vector_Q,
237 ['hash-map'] = types.hash_map,
238 ['map?'] = types._hash_map_Q,
239 assoc = assoc,
240 dissoc = dissoc,
241 get = get,
242 ['contains?'] = function(a,b) return a[b] ~= nil end,
243 keys = keys,
244 vals = vals,
245
246 ['sequential?'] = types._sequential_Q,
247 cons = cons,
248 concat = concat,
249 nth = nth,
250 first = first,
d46927d0 251 rest = rest,
9d42904e
JM
252 ['empty?'] = function(a) return a==Nil or #a == 0 end,
253 count = function(a) return #a end,
254 apply = apply,
255 map = map,
1ad8d501 256 conj = conj,
5f7cbd77 257 seq = seq,
9d42904e
JM
258
259 meta = meta,
260 ['with-meta'] = with_meta,
261 atom = function(a) return types.Atom:new(a) end,
262 ['atom?'] = types._atom_Q,
263 deref = function(a) return a.val end,
264 ['reset!'] = function(a,b) a.val = b; return b end,
265 ['swap!'] = swap_BANG,
266}
267
268return M
269