M Makefile => Makefile +2 -2
@@ 7,7 7,7 @@ include Makefile.conf
OBJS=src/builtins.o src/charbuf.o src/gc.o src/hashtable.o src/iter.o \
src/parse.o src/ringbuf.o src/types.o src/util.o src/textcache.o \
- src/module.o
+ src/module.o src/en.o
# https://semver.org
VERSION=1.1.0
@@ 83,7 83,7 @@ doc: FORCE
test: all FORCE
rm -f cov*.html src/*.gcda
- @python test.py scripts/tests
+ @cd scripts && python ../test.py tests -r ../bin/funlisp
gcovr -r src --html --html-details -o cov.html
clean_doc:
M Makefile.dep => Makefile.dep +1 -0
@@ 1,6 1,7 @@
builtins.o: src/builtins.c src/funlisp_internal.h inc/funlisp.h \
src/iter.h src/ringbuf.h src/hashtable.h
charbuf.o: src/charbuf.c src/charbuf.h
+en.o: src/en.c
gc.o: src/gc.c src/funlisp_internal.h inc/funlisp.h src/iter.h \
src/ringbuf.h src/hashtable.h
hashtable.o: src/hashtable.c src/iter.h src/hashtable.h
M inc/funlisp.h => inc/funlisp.h +1 -0
@@ 875,6 875,7 @@ enum lisp_errno {
LE_EXIT, /* exit the interpreter */
LE_ASSERT, /* assertion error */
LE_VALUE, /* invalid argument */
+ LE_ERRNO, /* used for C library errors, does perror() */
LE_MAX_ERR /* not a real error, don't use */
};
M scripts/tests/modules.lisp => scripts/tests/modules.lisp +6 -3
@@ 1,9 1,12 @@
(assert (equal? '(getattr a 'b) 'a.b))
(assert (equal? '(getattr (getattr one 'two) 'three) 'one.two.three))
-(import example)
+(import os)
-(assert (equal? (getattr example 'foo) "bar"))
-(assert (equal? example.foo "bar"))
+(import filter)
+
+(assert (equal?
+ (filter.filter (lambda (v) (< v 3)) '(1 2 3 4 5))
+ '(1 2)))
; OUTPUT(0)
M src/builtins.c => src/builtins.c +2 -3
@@ 758,9 758,8 @@ static lisp_value *lisp_builtin_import(
if (!lisp_get_args(rt, arglist, "s", &sym))
return NULL;
- mod = lisp_lookup_module(rt, sym);
- if (!mod)
- return lisp_error(rt, LE_NOTFOUND, "module not found");
+ mod = lisp_do_import(rt, sym);
+ lisp_error_check(mod);
lisp_scope_bind(scope, sym, (lisp_value*)mod);
return (lisp_value*)mod;
A src/en.c => src/en.c +6 -0
@@ 0,0 1,6 @@
+#include <errno.h>
+
+int get_errno(void)
+{
+ return errno;
+}
M src/funlisp_internal.h => src/funlisp_internal.h +6 -2
@@ 85,7 85,7 @@ struct lisp_runtime {
/* Maintain cache of lisp_string */
struct hashtable *strcache;
/* Maintain builtin module list */
- struct hashtable *modules;
+ lisp_scope *modules;
};
/* The below ARE lisp_values! */
@@ 196,8 196,12 @@ void lisp_textcache_remove(struct hashtable *cache, struct lisp_text *t);
int lisp_truthy(lisp_value *v);
-/* Module stuff */
+/* Module stuff, will become public eventually, but for now is private */
lisp_module *create_os_module(lisp_runtime *rt);
void lisp_register_module(lisp_runtime *rt, lisp_module *m);
lisp_module *lisp_lookup_module(lisp_runtime *rt, lisp_symbol *name);
+
+lisp_module *lisp_import_file(lisp_runtime *rt, lisp_string *name, lisp_string *file);
+lisp_module *lisp_do_import(lisp_runtime *rt, lisp_symbol *name);
+int get_errno(void);
#endif
M src/gc.c => src/gc.c +2 -3
@@ 24,8 24,7 @@ void lisp_init(lisp_runtime *rt)
rt->stack_depth = 0;
rt->symcache = NULL;
rt->strcache = NULL;
- rt->modules = ht_create(lisp_text_hash, lisp_text_compare,
- sizeof(struct lisp_text *), sizeof(struct lisp_module*));
+ rt->modules = lisp_new_empty_scope(rt);
lisp_register_module(rt, create_os_module(rt));
}
@@ 40,7 39,6 @@ void lisp_destroy(lisp_runtime *rt)
ht_delete(rt->symcache);
if (rt->strcache)
ht_delete(rt->strcache);
- ht_delete(rt->modules);
}
void lisp_mark(lisp_runtime *rt, lisp_value *v)
@@ 75,6 73,7 @@ static void lisp_mark_basics(lisp_runtime *rt)
if (rt->error_stack)
lisp_mark(rt, (lisp_value *) rt->error_stack);
lisp_mark(rt, (lisp_value *) rt->stack);
+ lisp_mark(rt, (lisp_value *) rt->modules);
}
void lisp_sweep(lisp_runtime *rt)
M src/module.c => src/module.c +55 -2
@@ 2,6 2,7 @@
* Module-related functionality. Includes builtin modules.
*/
#include <stdlib.h>
+#include <string.h>
#include "funlisp_internal.h"
@@ 43,10 44,62 @@ lisp_module *create_os_module(lisp_runtime *rt)
void lisp_register_module(lisp_runtime *rt, lisp_module *m)
{
- ht_insert_ptr(rt->modules, m->name, m);
+ /* TODO this depends on symbols and strings hashing to same value and
+ * comparing equal */
+ lisp_scope_bind(rt->modules, (lisp_symbol*)m->name, (lisp_value*) m);
}
lisp_module *lisp_lookup_module(lisp_runtime *rt, lisp_symbol *name)
{
- return ht_get_ptr(rt->modules, name);
+ lisp_module *m = (lisp_module*) lisp_scope_lookup(rt, rt->modules, name);
+
+ if (!m) /* not found is not necessarily an error */
+ lisp_clear_error(rt);
+
+ return m;
+}
+
+lisp_module *lisp_import_file(lisp_runtime *rt, lisp_string *name, lisp_string *file)
+{
+ FILE *f;
+ lisp_scope *builtins = lisp_new_default_scope(rt);
+ lisp_scope *modscope = lisp_new_empty_scope(rt);
+ lisp_module *module;
+ lisp_value *v;
+ modscope->up = builtins;
+
+ f = fopen(file->s, "r");
+ if (!f) {
+ return (lisp_module*) lisp_error(rt, LE_ERRNO, "error opening file for import");
+ }
+
+ v = lisp_load_file(rt, modscope, f);
+ lisp_error_check(v);
+
+ module = (lisp_module *)lisp_new(rt, type_module);
+ module->contents = modscope;
+ module->name = name;
+ module->file = file;
+ lisp_register_module(rt, module);
+ return module;
+}
+
+lisp_module *lisp_do_import(lisp_runtime *rt, lisp_symbol *name)
+{
+ lisp_module *m;
+ lisp_string *file, *namestr;
+ char *filestr;
+ int len;
+
+ m = lisp_lookup_module(rt, name);
+ if (m)
+ return m;
+
+ len = strlen(name->s);
+ len += 1 /*nul*/ + 7 /*./ .lisp */;
+ filestr = malloc(len);
+ sprintf(filestr, "./%s.lisp", name->s);
+ file = lisp_string_new(rt, filestr, LS_OWN);
+ namestr = lisp_symbol_new(rt, name->s, LS_OWN | LS_CPY);
+ return lisp_import_file(rt, namestr, file);
}
M src/types.c => src/types.c +1 -1
@@ 179,7 179,7 @@ static struct iterator scope_expand(lisp_value *v)
lisp_scope *scope = (lisp_scope *) v;
if (scope->up) {
return iterator_concat3(
- iterator_single_value(&scope->up),
+ iterator_single_value(scope->up),
ht_iter_keys_ptr(&scope->scope),
ht_iter_values_ptr(&scope->scope)
);
M src/util.c => src/util.c +9 -1
@@ 33,6 33,7 @@ const char *lisp_error_name[LE_MAX_ERR] = {
"LE_EXIT",
"LE_ASSERT",
"LE_VALUE",
+ "LE_ERRNO",
};
void lisp_scope_bind(lisp_scope *scope, lisp_symbol *symbol, lisp_value *value)
@@ 413,6 414,7 @@ void lisp_clear_error(lisp_runtime *rt)
void lisp_print_error(lisp_runtime *rt, FILE *file)
{
+ char *errmsg;
if (!rt->error) {
fprintf(stderr, "BUG: lisp_print_error() expects error, found none\n");
return;
@@ 421,7 423,13 @@ void lisp_print_error(lisp_runtime *rt, FILE *file)
if (rt->error_line)
fprintf(file, "at line %d: ", rt->error_line);
- fprintf(file, "Error %s: %s\n", lisp_error_name[rt->errno], rt->error);
+ if (rt->errno == LE_ERRNO) {
+ errmsg = strerror(get_errno());
+ fprintf(file, "Error %s: %s\nSystem error: %s\n",
+ lisp_error_name[rt->errno], rt->error, errmsg);
+ } else {
+ fprintf(file, "Error %s: %s\n", lisp_error_name[rt->errno], rt->error);
+ }
if (rt->error_stack)
lisp_dump_stack(rt, rt->error_stack, file);