~brenns10/funlisp

9c51536fa5cdb830f35d8690418a75a9945dc7dd — Stephen Brennan 1 year, 4 months ago 8ed8f2e
Allow importing other lisp files
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);