summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile15
-rw-r--r--lisp.c33
-rw-r--r--lisp.h1
-rw-r--r--lisp_api.h7
-rw-r--r--main.c2
-rw-r--r--modules/test_module.c19
7 files changed, 76 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index 632497d..0884e9e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
*.o
+*.so
lex.yy.*
lisp.tab.*
main
diff --git a/Makefile b/Makefile
index 6feb95e..d574b4e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,12 @@
LEX = flex
YACC = bison
CC = gcc -g
-CFLAGS = -DYYDEBUG=1
+CFLAGS = -DYYDEBUG=1 -fPIC
LIBS = -lreadline -lfl -lm
OBJS = lisp.o lisp.tab.o lex.yy.o
+
+MODULE_SRC = $(wildcard modules/*.c)
+MODULE_SO = $(MODULE_SRC:.c=.so)
.SUFFIXES:
main: main.c $(OBJS)
@@ -25,7 +28,7 @@ lex.yy.o: lex.yy.c
$(CC) $(CFLAGS) -c lex.yy.c
clean:
- rm -f *.o main test lisp.tab.c lisp.tab.h lex.yy.c lex.yy.h
+ rm -f *.o main test lisp.tab.c lisp.tab.h lex.yy.c lex.yy.h modules/*.so
test: test.o $(OBJS)
$(CC) $(CFLAGS) -o $@ test.o $(OBJS) $(LIBS)
@@ -40,4 +43,12 @@ run: main
run_std: main
./main lisp/standard_functions.lisp
+modules: $(MODULE_SO)
+ @echo "All modules built successfully."
+
+modules/%.so: modules/%.c lisp.o
+ gcc -fPIC -c $< -o $*.o
+ gcc -fPIC -shared $*.o lisp.o -o $@
+ rm $*.o
+
.PHONY: clean test run
diff --git a/lisp.c b/lisp.c
index d5f9600..1c80a74 100644
--- a/lisp.c
+++ b/lisp.c
@@ -3,6 +3,7 @@
#include <readline/readline.h>
#include <readline/history.h>
#include <math.h>
+#include <dlfcn.h>
#include "lisp_api.h"
#include "lisp.h"
#include "lex.yy.h"
@@ -488,6 +489,38 @@ value *builtin_lt(env *e, value *args) {
return make_int(1);
}
+value *builtin_load_module(env *e, value *args) {
+ value *fst_arg = eval(e, car(args));
+
+ if (fst_arg->type != VT_STRING) {
+ printf("error: not a string:");
+ print_value(fst_arg);
+ return make_nil(); //TODO: make_err
+ }
+
+ const char *path = fst_arg->as.str;
+
+ void *handle = dlopen(path, RTLD_LAZY);
+ if (!handle) {
+ printf("dlopen error: %s\n", dlerror());
+ return make_nil(); //TODO: make_err
+ }
+
+ module_export *(*init)(void) = dlsym(handle, "module_init");
+
+ if (!init) {
+ printf("not a valid module: %s\n", dlerror());
+ return make_nil(); //TODO: make_err
+ }
+
+ module_export *exports = init();
+ for (int i = 0; exports[i].name; i++) {
+ env_define(e, exports[i].name, exports[i].v);
+ }
+
+ return make_nil();
+}
+
int is_integer(double x) {
return floor(x) == x && isfinite(x);
}
diff --git a/lisp.h b/lisp.h
index a972ecc..df5835e 100644
--- a/lisp.h
+++ b/lisp.h
@@ -37,6 +37,7 @@ value *builtin_sub(env *e, value *args);
value *builtin_mul(env *e, value *args);
value *builtin_div(env *e, value *args);
value *builtin_lt(env *e, value *args);
+value *builtin_load_module(env *e, value *args);
int is_integer(double x);
diff --git a/lisp_api.h b/lisp_api.h
index 70d317b..6361031 100644
--- a/lisp_api.h
+++ b/lisp_api.h
@@ -49,4 +49,11 @@ value *car(value *cons);
value *cdr(value *cons);
value *reverse(value *list);
+typedef struct {
+ const char *name;
+ value *v;
+} module_export;
+
+module_export *module_init();
+
#endif
diff --git a/main.c b/main.c
index 73adf2d..5a8043b 100644
--- a/main.c
+++ b/main.c
@@ -106,6 +106,8 @@ int main(int argc, char **argv) {
env_define(global_env, "/", make_builtin(builtin_div));
env_define(global_env, "<", make_builtin(builtin_lt));
+ env_define(global_env, "load_module", make_builtin(builtin_load_module));
+
// evaluate files
for(int i = 1; i < argc; i++) {
eval_file(argv[i]);
diff --git a/modules/test_module.c b/modules/test_module.c
new file mode 100644
index 0000000..ead7b91
--- /dev/null
+++ b/modules/test_module.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include "../lisp_api.h"
+
+value *hello_fun(env *e, value *args) {
+ printf("Hello from dynamically loaded module!\n");
+ return make_nil();
+}
+
+module_export *module_init() {
+ static module_export exports[2];
+
+ exports[0].name = "hello";
+ exports[0].v = make_builtin(&hello_fun);
+
+ exports[1].name = NULL;
+ exports[1].v = NULL;
+
+ return exports;
+}