blob: 0acafe86c8883c30f0b78b799777e9d39137cc5d [file] [log] [blame]
swissChilib3ca4fb2021-04-20 10:33:00 -07001#include "std.h"
swissChili8b5ec7a2022-08-05 22:26:17 -07002#include "classes.h"
swissChilia890aed2022-07-30 17:13:07 -07003#include "../gc.h"
swissChili04d94162022-07-30 21:46:49 -07004#include "../compiler.h"
swissChilif68671f2021-07-05 14:14:44 -07005#include "../plat/plat.h"
swissChilif3e7f182021-04-20 13:57:22 -07006#include <stdlib.h>
swissChilif68671f2021-07-05 14:14:44 -07007#include <string.h>
swissChilib3ca4fb2021-04-20 10:33:00 -07008
swissChili53472e82021-05-08 16:06:32 -07009value_t l_plus(value_t a, value_t b)
swissChilib3ca4fb2021-04-20 10:33:00 -070010{
swissChili53472e82021-05-08 16:06:32 -070011 if (!integerp(a) || !integerp(b))
swissChilib3ca4fb2021-04-20 10:33:00 -070012 return nil;
13
14 return (((a >> 2) + (b >> 2)) << 2) | INT_TAG;
15}
16
swissChili53472e82021-05-08 16:06:32 -070017value_t l_minus(value_t a, value_t b)
swissChili6aff2bb2021-04-20 15:02:53 -070018{
swissChili53472e82021-05-08 16:06:32 -070019 if (!integerp(a) || !integerp(b))
swissChili6aff2bb2021-04-20 15:02:53 -070020 return nil;
21
22 return (((a >> 2) - (b >> 2)) << 2) | INT_TAG;
23}
24
swissChili53472e82021-05-08 16:06:32 -070025value_t l_times(value_t a, value_t b)
swissChili6aff2bb2021-04-20 15:02:53 -070026{
swissChili53472e82021-05-08 16:06:32 -070027 if (!integerp(a) || !integerp(b))
swissChili6aff2bb2021-04-20 15:02:53 -070028 return nil;
29
30 return (((a >> 2) * (b >> 2)) << 2) | INT_TAG;
31}
32
swissChili53472e82021-05-08 16:06:32 -070033value_t l_divide(value_t a, value_t b)
swissChili6aff2bb2021-04-20 15:02:53 -070034{
swissChili53472e82021-05-08 16:06:32 -070035 if (!integerp(a) || !integerp(b))
swissChili6aff2bb2021-04-20 15:02:53 -070036 return nil;
37
38 return (((a >> 2) / (b >> 2)) << 2) | INT_TAG;
39}
40
swissChili53472e82021-05-08 16:06:32 -070041value_t l_printval(value_t val)
swissChili8fc5e2f2021-04-22 13:45:10 -070042{
swissChili53472e82021-05-08 16:06:32 -070043 printval(val, 0);
swissChili8fc5e2f2021-04-22 13:45:10 -070044 return nil;
45}
46
swissChiliddc97542021-07-04 11:47:42 -070047value_t l_apply(value_t func, value_t args)
48{
49 if (!closurep(func))
50 return nil;
51
52 if (!listp(args))
53 return nil;
54
55 return call_list_closure((struct closure *)(func ^ CLOSURE_TAG), args);
56}
57
swissChili15f1cae2021-07-05 19:08:47 -070058value_t l_nilp(value_t val)
59{
60 return nilp(val) ? t : nil;
61}
62
63void add_function(struct environment *env, char *name, void *func, struct args *args, enum namespace ns)
swissChilib3ca4fb2021-04-20 10:33:00 -070064{
swissChili53472e82021-05-08 16:06:32 -070065 struct function *last, *new = malloc(sizeof(struct function));
swissChilib3ca4fb2021-04-20 10:33:00 -070066
67 last = env->first;
68 new->prev = last;
69 new->name = name;
swissChili15f1cae2021-07-05 19:08:47 -070070 new->args = args;
swissChilib3ca4fb2021-04-20 10:33:00 -070071 new->code_ptr = func;
swissChili2999dd12021-07-02 14:19:53 -070072 new->namespace = ns;
swissChilib3ca4fb2021-04-20 10:33:00 -070073
swissChilif3e7f182021-04-20 13:57:22 -070074 env->first = new;
swissChilib3ca4fb2021-04-20 10:33:00 -070075}
76
swissChili1e8b7562021-12-22 21:22:57 -080077void add_c_varargs(struct environment *env, char *name, void *func, int nargs)
78{
79 struct args *args = new_args();
80 args->num_required = nargs;
81 args->variadic = true;
82
83 add_function(env, name, func, args, NS_FUNCTION);
84}
85
swissChili15f1cae2021-07-05 19:08:47 -070086void add_c_function(struct environment *env, char *name, void *func, int nargs)
87{
88 struct args *args = new_args();
89 args->num_required = nargs;
90
91 add_function(env, name, func, args, NS_FUNCTION);
92}
93
94value_t l_elt(value_t seq, value_t i)
95{
96 if (!listp(seq) || !integerp(i))
97 return nil;
98
99 return elt(seq, i >> 2);
100}
101
swissChili7e1393c2021-07-07 12:59:12 -0700102value_t l_read_stdin()
103{
104 char *string = read_input_line("lisp> ");
105 if (!string)
106 return nil;
107
108 struct istream *is = new_stristream_nt(string);
109
110 value_t val = nil;
swissChili36f2c692021-08-08 14:31:44 -0700111 struct error err = { 0 };
swissChili6d02af42021-08-05 19:49:01 -0700112
113 if (!IS_OKAY((err = read1(is, &val))))
114 {
115 ereport(err);
116
117 del_stristream(is);
118 free(string);
119 // tail recursion, yay!
120 return l_read_stdin();
121 }
swissChili7e1393c2021-07-07 12:59:12 -0700122
123 del_stristream(is);
124 free(string);
125
126 return val;
127}
128
swissChili53e7cd12021-08-02 21:55:53 -0700129value_t l_num_eq(value_t a, value_t b)
130{
131 if (!integerp(a) || !integerp(b))
132 {
133 return nil;
134 }
135
swissChili1e8b7562021-12-22 21:22:57 -0800136 return (a >> 2) == (b >> 2) ? t : nil;
137}
138
139value_t l_num_gt(value_t a, value_t b)
140{
141 if (!integerp(a) || !integerp(b))
142 return nil;
143
144 return (a >> 2) > (b >> 2) ? t : nil;
145}
146
147value_t l_num_lt(value_t a, value_t b)
148{
149 if (!integerp(a) || !integerp(b))
150 return nil;
151
152 return (a >> 2) < (b >> 2) ? t : nil;
153}
154
155value_t l_append(value_t l)
156{
157 if (nilp(l))
158 return l;
159
160 value_t first = nil;
161 value_t *last = NULL;
162
163 for (value_t item = l; !nilp(item); item = cdr(item))
164 {
165 value_t a = car(item);
166
167 if (!listp(a))
168 {
169 value_t new = cons(a, nil);
170 *last = new;
171 last = cdrref(new);
172 continue;
173 }
174
175 for (value_t i = a; !nilp(i); i = cdr(i))
176 {
177 value_t b = car(i);
178
179 if (!last)
180 {
181 first = cons(b, nil);
182 last = cdrref(first);
183 }
184 else
185 {
186 value_t new = cons(b, nil);
187 *last = new;
188 last = cdrref(new);
189 }
190 }
191 }
192
193 return first;
swissChili53e7cd12021-08-02 21:55:53 -0700194}
195
swissChilia890aed2022-07-30 17:13:07 -0700196value_t l_gc_stats()
197{
198 struct gc_stats stats = gc_get_stats();
199
200 return cons(intval(stats.total_allocs),
201 cons(intval(stats.gc_runs),
202 nil));
203}
204
swissChili04d94162022-07-30 21:46:49 -0700205value_t l_list_functions(value_t env)
206{
207 if (!integerp(env))
208 return nil;
209
210 struct environment *e = (void *)env;
211 value_t list = nil;
212
213 for (struct function *fun = e->first; fun; fun = fun->prev)
214 {
215 list = cons(symval(fun->name), list);
216 }
217
218 return list;
219}
220
swissChili8b5ec7a2022-08-05 22:26:17 -0700221value_t l_string_to_symbol(value_t string)
222{
223 if (!stringp(string))
224 return nil;
225
226 return symval((char *)(string ^ STRING_TAG));
227}
228
229value_t l_symbol_to_string(value_t string)
230{
231 if (!symbolp(string))
232 return nil;
233
234 return strval((char *)(string ^ SYMBOL_TAG));
235}
236
237value_t l_string_length(value_t string)
238{
239 if (!stringp(string))
240 return intval(0);
241
242 return intval(strlen((char *)(string ^ STRING_TAG)));
243}
244
245value_t l_concat(value_t strings)
246{
247 struct alloc *string_alloc = malloc_aligned(sizeof(struct alloc));
248 int lengths = 0;
249
250 for (value_t str = strings; !nilp(str); str = cdr(str))
251 {
252 if (!stringp(car(str)))
253 continue;
254
255 int len = strlen((char *)(car(str) ^ STRING_TAG));
256 string_alloc = realloc_aligned(string_alloc,
257 sizeof(struct alloc) + lengths + len);
258
259 memcpy((void *)string_alloc + sizeof(struct alloc) + lengths,
260 (char *)(car(str) ^ STRING_TAG),
261 len);
262
263 lengths += len;
264 }
265
266 add_this_alloc(string_alloc, STRING_TAG);
267
268 return (value_t)(string_alloc + 1) | STRING_TAG;
269}
270
271value_t l_gensym()
272{
273 static int symcnt = 0;
274 char buffer[32] = {0};
275 snprintf(buffer, 32, "-sym-%d", symcnt++);
276 return symval(buffer);
277}
278
swissChilifc5c9412021-08-08 19:08:26 -0700279#define LISP_PREDICATE(name) value_t l_##name(value_t v) { return name(v) ? t : nil; }
280
281LISP_PREDICATE(listp)
282LISP_PREDICATE(integerp)
283LISP_PREDICATE(symbolp)
284LISP_PREDICATE(closurep)
285LISP_PREDICATE(consp)
swissChili8b5ec7a2022-08-05 22:26:17 -0700286LISP_PREDICATE(classp)
swissChilifc5c9412021-08-08 19:08:26 -0700287
288#undef LISP_PREDICATE
289
swissChili6d02af42021-08-05 19:49:01 -0700290struct error load_std(struct environment *env)
swissChilib3ca4fb2021-04-20 10:33:00 -0700291{
swissChili6d02af42021-08-05 19:49:01 -0700292 E_INIT();
293
swissChili15f1cae2021-07-05 19:08:47 -0700294 add_c_function(env, "+", l_plus, 2);
295 add_c_function(env, "-", l_minus, 2);
296 add_c_function(env, "*", l_times, 2);
297 add_c_function(env, "/", l_divide, 2);
swissChili53e7cd12021-08-02 21:55:53 -0700298 add_c_function(env, "=", l_num_eq, 2);
swissChili1e8b7562021-12-22 21:22:57 -0800299 add_c_function(env, "<", l_num_lt, 2);
300 add_c_function(env, ">", l_num_gt, 2);
swissChili8fc5e2f2021-04-22 13:45:10 -0700301
swissChili15f1cae2021-07-05 19:08:47 -0700302 add_c_function(env, "car", car, 1);
303 add_c_function(env, "cdr", cdr, 1);
304 add_c_function(env, "cons", cons, 2);
swissChili8fc5e2f2021-04-22 13:45:10 -0700305
swissChili15f1cae2021-07-05 19:08:47 -0700306 add_c_function(env, "print", l_printval, 1);
swissChili7e1393c2021-07-07 12:59:12 -0700307 add_c_function(env, "read-stdin", l_read_stdin, 0);
swissChili15f1cae2021-07-05 19:08:47 -0700308 add_c_function(env, "apply", l_apply, 2);
swissChili1e8b7562021-12-22 21:22:57 -0800309 add_c_varargs(env, "append", l_append, 0);
swissChiliddc97542021-07-04 11:47:42 -0700310
swissChili15f1cae2021-07-05 19:08:47 -0700311 add_c_function(env, "nilp", l_nilp, 1);
swissChilifc5c9412021-08-08 19:08:26 -0700312 add_c_function(env, "listp", l_listp, 1);
313 add_c_function(env, "integerp", l_integerp, 1);
314 add_c_function(env, "symbolp", l_symbolp, 1);
315 add_c_function(env, "closurep", l_closurep, 1);
316 add_c_function(env, "functionp", l_closurep, 1);
317 add_c_function(env, "consp", l_consp, 1);
318
swissChili15f1cae2021-07-05 19:08:47 -0700319 add_c_function(env, "elt", l_elt, 2);
swissChilif68671f2021-07-05 14:14:44 -0700320
swissChilia890aed2022-07-30 17:13:07 -0700321 add_c_function(env, "gc-stats", l_gc_stats, 0);
swissChili04d94162022-07-30 21:46:49 -0700322 add_c_function(env, "env-functions", l_list_functions, 1);
323
swissChili8b5ec7a2022-08-05 22:26:17 -0700324 add_c_varargs(env, "concat", l_concat, 0);
325 add_c_function(env, "string-length", l_string_length, 1);
326 add_c_function(env, "string->symbol", l_string_to_symbol, 1);
327 add_c_function(env, "symbol->string", l_symbol_to_string, 1);
328 add_c_function(env, "gensym", l_gensym, 0);
329
330 load_classes(env);
331
swissChilif68671f2021-07-05 14:14:44 -0700332 if (!load_library(env, "std"))
333 {
swissChili1e8b7562021-12-22 21:22:57 -0800334 fprintf(stderr, "Not found std\n");
swissChili6d02af42021-08-05 19:49:01 -0700335 THROW(ENOTFOUND, "Could not load library `std`, make sure your $LISP_LIBRARY_PATH is correct.");
swissChilif68671f2021-07-05 14:14:44 -0700336 }
swissChili6d02af42021-08-05 19:49:01 -0700337
338 OKAY();
swissChilif68671f2021-07-05 14:14:44 -0700339}
340
341bool load_library(struct environment *env, char *name)
342{
343 char *lib_paths = getenv("LISP_LIBRARY_PATH");
344
345 if (!lib_paths)
346 lib_paths = "/lib/lisp";
347
348 for (char *p = strtok(lib_paths, ":"); p; p = strtok(NULL, ":"))
349 {
350 static char path[512];
351 snprintf(path, 512, "%s/%s.lisp", p, name);
352
353 if (file_exists(path))
354 {
swissChili1e8b7562021-12-22 21:22:57 -0800355 // fprintf(stderr, "loading path: %s\n", path);
swissChilif68671f2021-07-05 14:14:44 -0700356 return load(env, path);
357 }
358
359 snprintf(path, 512, "%s/%s/%s.lisp", p, name, name);
360
361 if (file_exists(path))
362 {
swissChili1e8b7562021-12-22 21:22:57 -0800363 // fprintf(stderr, "loading path: %s\n", path);
swissChilif68671f2021-07-05 14:14:44 -0700364 return load(env, path);
365 }
366 }
367
368 return false;
swissChilib3ca4fb2021-04-20 10:33:00 -0700369}