aboutsummaryrefslogtreecommitdiff
path: root/exts
diff options
context:
space:
mode:
authorMistivia <i@mistivia.com>2025-12-14 05:15:01 +0800
committerMistivia <i@mistivia.com>2025-12-14 05:15:01 +0800
commit724718566c384d8be60f2803e5ecd6be43c6d74b (patch)
treead1190d7e2ebc1b609fa5feea8ee428abe4cd1dc /exts
parent995b45685a5d23e9bbf5667b2e9246ba385110cd (diff)
create ext project
Diffstat (limited to 'exts')
-rw-r--r--exts/Makefile0
-rw-r--r--exts/dict/Makefile0
-rw-r--r--exts/dict/main.c165
-rw-r--r--exts/dict/test.lisp0
-rw-r--r--exts/io/main.c0
-rw-r--r--exts/vector/Makefile0
-rw-r--r--exts/vector/main.c129
-rw-r--r--exts/vector/test.lisp0
8 files changed, 294 insertions, 0 deletions
diff --git a/exts/Makefile b/exts/Makefile
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/exts/Makefile
diff --git a/exts/dict/Makefile b/exts/dict/Makefile
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/exts/dict/Makefile
diff --git a/exts/dict/main.c b/exts/dict/main.c
new file mode 100644
index 0000000..30eceb6
--- /dev/null
+++ b/exts/dict/main.c
@@ -0,0 +1,165 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include <algds/tree_map.h>
+#include <algds/basic_traits.h>
+#include <bamboo_lisp/interp.h>
+#include <bamboo_lisp/sexp.h>
+
+TREE_MAP_DEF(String, SExpRef);
+TREE_MAP_IMPL(String, SExpRef);
+
+typedef String2SExpRefTreeMap DictMap;
+typedef String2SExpRefTreeMapIter DictIter;
+typedef String2SExpRefTreeMapNode DictNode;
+
+LispUserdataMeta bamboo_lisp_dict_meta;
+
+#define DICT_TYPEID "ext.core.dict"
+
+static bool is_dict_impl(Interp *interp, SExpRef obj) {
+ if (VALTYPE(obj) == kUserDataSExp && strcmp(DICT_TYPEID, REF(obj)->userdata_meta->type) == 0) {
+ return true;
+ }
+ return false;
+}
+
+static void dict_free(void *vself) {
+ DictMap *map = (DictMap *)vself;
+
+ DictIter it = String2SExpRefTreeMap_min(map);
+ while (it != NULL) {
+ if (it->key) {
+ free((void*)it->key);
+ it->key = NULL;
+ }
+ it = String2SExpRefTreeMap_next(map, it);
+ }
+
+ String2SExpRefTreeMap_free(map);
+
+ free(map);
+}
+
+
+static void dict_gcmark(Interp *interp, SExpPtrVector *gcstack, void *vself) {
+ DictMap *map = (DictMap *)vself;
+
+ DictIter it = String2SExpRefTreeMap_min(map);
+ while (it != NULL) {
+ SExpRef val = it->value;
+ SExpPtr ptr = REF(val);
+
+ if (ptr && !ptr->marked) {
+ SExpPtrVector_push_back(gcstack, ptr);
+ }
+
+ it = String2SExpRefTreeMap_next(map, it);
+ }
+}
+
+
+static SExpRef lisp_is_dict(Interp* interp, SExpRef args) {
+ if (LENGTH(args) != 1) return new_error(interp, "dict?: wrongs args num.\n");
+ return new_boolean(interp, is_dict_impl(interp, CAR(args)));
+}
+
+// (make-dict)
+static SExpRef lisp_make_dict(Interp* interp, SExpRef args) {
+ if (LENGTH(args) != 0) return new_error(interp, "make-dict: expects no args.\n");
+
+ SExpRef ret = new_sexp(interp);
+ REF(ret)->type = kUserDataSExp;
+ REF(ret)->userdata_meta = &bamboo_lisp_dict_meta;
+
+ DictMap *map = malloc(sizeof(DictMap));
+ if (!map) return new_error(interp, "make-dict: out of memory.\n");
+
+ String2SExpRefTreeMap_init(map);
+ REF(ret)->userdata = map;
+
+ return ret;
+}
+
+// (dict-set dict key value)
+static SExpRef lisp_dict_set(Interp* interp, SExpRef args) {
+ if (LENGTH(args) != 3) return new_error(interp, "dict-set: wrong args num.\n");
+
+ SExpRef r_dict = CAR(args);
+ SExpRef r_key = CADR(args);
+ SExpRef r_val = CADDR(args);
+
+ if (!is_dict_impl(interp, r_dict)) return new_error(interp, "dict-set: first arg not a dict.\n");
+ if (REF(r_key)->type != kStringSExp) return new_error(interp, "dict-set: key must be a string.\n");
+
+ DictMap *map = REF(r_dict)->userdata;
+ const char *key_str = REF(r_key)->str;
+
+ DictIter it = String2SExpRefTreeMap_find(map, key_str);
+ if (it != NULL) {
+ it->value = r_val;
+ } else {
+ char *key_dup = strdup(key_str);
+ String2SExpRefTreeMap_insert(map, key_dup, r_val);
+ }
+
+ return NIL;
+}
+
+// (dict-get dict key) -> value or nil
+static SExpRef lisp_dict_get(Interp* interp, SExpRef args) {
+ if (LENGTH(args) != 2) return new_error(interp, "dict-get: wrong args num.\n");
+
+ SExpRef r_dict = CAR(args);
+ SExpRef r_key = CADR(args);
+
+ if (!is_dict_impl(interp, r_dict)) return new_error(interp, "dict-get: first arg not a dict.\n");
+ if (REF(r_key)->type != kStringSExp) return new_error(interp, "dict-get: key must be a string.\n");
+
+ DictMap *map = REF(r_dict)->userdata;
+ const char *key_str = REF(r_key)->str;
+
+ SExpRef *val_ptr = String2SExpRefTreeMap_get(map, key_str);
+ if (val_ptr == NULL) {
+ return NIL;
+ }
+ return *val_ptr;
+}
+
+// (dict-remove dict key)
+static SExpRef lisp_dict_remove(Interp* interp, SExpRef args) {
+ if (LENGTH(args) != 2) return new_error(interp, "dict-remove: wrong args num.\n");
+
+ SExpRef r_dict = CAR(args);
+ SExpRef r_key = CADR(args);
+
+ if (!is_dict_impl(interp, r_dict)) return new_error(interp, "dict-remove: first arg not a dict.\n");
+ if (REF(r_key)->type != kStringSExp) return new_error(interp, "dict-remove: key must be a string.\n");
+
+ DictMap *map = REF(r_dict)->userdata;
+ const char *key_str = REF(r_key)->str;
+
+ DictIter it = String2SExpRefTreeMap_find(map, key_str);
+ if (it != NULL) {
+ const char *owned_key = it->key;
+ String2SExpRefTreeMap_remove(map, it);
+ if (owned_key) free((void*)owned_key);
+ free(it);
+ }
+
+ return NIL;
+}
+
+int bamboo_lisp_dict_ext_init(Interp *interp) {
+ bamboo_lisp_dict_meta.type = DICT_TYPEID;
+ bamboo_lisp_dict_meta.free = &dict_free;
+ bamboo_lisp_dict_meta.gcmark = &dict_gcmark;
+
+ Interp_add_userfunc(interp, "dict?", &lisp_is_dict);
+ Interp_add_userfunc(interp, "make-dict", &lisp_make_dict);
+ Interp_add_userfunc(interp, "dict-get", &lisp_dict_get);
+ Interp_add_userfunc(interp, "dict-set", &lisp_dict_set);
+ Interp_add_userfunc(interp, "dict-remove", &lisp_dict_remove);
+ // TODO dict-keys
+ return 1;
+} \ No newline at end of file
diff --git a/exts/dict/test.lisp b/exts/dict/test.lisp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/exts/dict/test.lisp
diff --git a/exts/io/main.c b/exts/io/main.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/exts/io/main.c
diff --git a/exts/vector/Makefile b/exts/vector/Makefile
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/exts/vector/Makefile
diff --git a/exts/vector/main.c b/exts/vector/main.c
new file mode 100644
index 0000000..3261fed
--- /dev/null
+++ b/exts/vector/main.c
@@ -0,0 +1,129 @@
+#include <bamboo_lisp/interp.h>
+#include <bamboo_lisp/sexp.h>
+
+#define VECTOR_TYPEID "ext.core.vector"
+
+LispUserdataMeta bamboo_lisp_array_meta;
+
+static bool is_vector_impl(Interp *interp, SExpRef vec) {
+ if (VALTYPE(vec) == kUserDataSExp && strcmp(VECTOR_TYPEID, REF(vec)->userdata_meta->type) == 0) {
+ return true;
+ }
+ return false;
+}
+
+static SExpRef is_vector(Interp* interp, SExpRef args) {
+ if (LENGTH(args) != 1) return new_error(interp, "vector?: wrongs args num.\n");
+ return new_boolean(interp, is_vector_impl(interp, CAR(args)));
+}
+
+static SExpRef make_vector(Interp* interp, SExpRef args) {
+ SExpRef ret = new_sexp(interp);
+ REF(ret)->type = kUserDataSExp;
+ REF(ret)->userdata_meta = &bamboo_lisp_array_meta;
+ SExpRefVector *data = malloc(sizeof(SExpRefVector));
+ SExpRefVector_init(data);
+ REF(ret)->userdata = data;
+ return ret;
+}
+
+static SExpRef vector_ref(Interp* interp, SExpRef args) {
+ if (LENGTH(args) != 2) return new_error(interp, "vector-ref: wrong args num.\n");
+ if (!is_vector_impl(interp, CAR(args))
+ || REF(CADR(args))->type != kIntegerSExp) {
+ return new_error(interp, "vector-ref: wrong type.\n");
+ }
+ int n = REF(CADR(args))->integer;
+ SExpRefVector *vec = REF(CAR(args))->userdata;
+ if (n >= SExpRefVector_len(vec)) return new_error(interp, "vector-ref: out of bound.\n");
+ SExpRef ret = new_sexp(interp);
+ return *SExpRefVector_ref(vec, n);
+}
+
+static SExpRef vector_append(Interp* interp, SExpRef args) {
+ if (LENGTH(args) != 2) return new_error(interp, "vector-append: wrong args num.\n");
+ if (!is_vector_impl(interp, CAR(args))) return new_error(interp, "vector-append: first arg not a vector.\n");
+
+ SExpRefVector *vec = REF(CAR(args))->userdata;
+ SExpRef elem = CADR(args);
+ SExpRefVector_push_back(vec, elem);
+ return NIL;
+}
+
+static SExpRef vector_insert(Interp* interp, SExpRef args) {
+ if (LENGTH(args) != 3) return new_error(interp, "vector-insert: wrong args num.\n");
+ if (!is_vector_impl(interp, CAR(args)) || REF(CADR(args))->type != kIntegerSExp)
+ return new_error(interp, "vector-insert: wrong types.\n");
+
+ int pos = REF(CADR(args))->integer;
+ SExpRefVector *vec = REF(CAR(args))->userdata;
+ SExpRef elem = CADDR(args);
+ SExpRefVector_insert_before(vec, pos, elem);
+ return NIL;
+}
+
+static SExpRef vector_delete(Interp* interp, SExpRef args) {
+ if (LENGTH(args) != 2) return new_error(interp, "vector-remove: wrong args num.\n");
+ if (!is_vector_impl(interp, CAR(args)) || REF(CADR(args))->type != kIntegerSExp)
+ return new_error(interp, "vector-remove: wrong types.\n");
+
+ int pos = REF(CADR(args))->integer;
+ SExpRefVector *vec = REF(CAR(args))->userdata;
+ if (pos >= SExpRefVector_len(vec)) return new_error(interp, "vector-remove: out of bound.\n");
+ SExpRefVector_remove(vec, pos);
+ return NIL;
+}
+
+static SExpRef vector_length(Interp* interp, SExpRef args) {
+ if (LENGTH(args) != 1) return new_error(interp, "vector-length: wrong args num.\n");
+ if (!is_vector_impl(interp, CAR(args))) return new_error(interp, "vector-length: not a vector.\n");
+
+ SExpRefVector *vec = REF(CAR(args))->userdata;
+ return new_integer(interp, SExpRefVector_len(vec));
+}
+
+static SExpRef vector_set(Interp* interp, SExpRef args) {
+ if (LENGTH(args) != 3) return new_error(interp, "vector-set: wrong args num.\n");
+ if (!is_vector_impl(interp, CAR(args)) || REF(CADR(args))->type != kIntegerSExp)
+ return new_error(interp, "vector-set: wrong types.\n");
+
+ int pos = REF(CADR(args))->integer;
+ SExpRefVector *vec = REF(CAR(args))->userdata;
+ if (pos >= SExpRefVector_len(vec)) return new_error(interp, "vector-set: out of bound.\n");
+
+ *SExpRefVector_ref(vec, pos) = CADDR(args);
+ return NIL;
+}
+
+static void vector_free(void *vself) {
+ SExpRefVector *self = vself;
+ SExpRefVector_free(self);
+ free(self);
+}
+
+static void vector_gcmark(Interp *interp, SExpPtrVector *gcstack, void *vself) {
+ SExpRefVector *vec = (SExpRefVector *)vself;
+ int vecsize = SExpRefVector_len(vec);
+ for (int i = 0; i < vecsize; ++i) {
+ SExpPtr child = REF(*SExpRefVector_ref(vec, i));
+ if (child && !child->marked) {
+ SExpPtrVector_push_back(gcstack, child);
+ }
+ }
+}
+
+int bamboo_lisp_ext_init(Interp *interp) {
+ bamboo_lisp_array_meta.type = VECTOR_TYPEID;
+ bamboo_lisp_array_meta.free = &vector_free;
+ bamboo_lisp_array_meta.gcmark = &vector_gcmark;
+
+ Interp_add_userfunc(interp, "vector?", &is_vector);
+ Interp_add_userfunc(interp, "make-vector", &make_vector);
+ Interp_add_userfunc(interp, "vector-ref", &vector_ref);
+ Interp_add_userfunc(interp, "vector-append", &vector_append);
+ Interp_add_userfunc(interp, "vector-insert", &vector_insert);
+ Interp_add_userfunc(interp, "vector-remove", &vector_delete);
+ Interp_add_userfunc(interp, "vector-length", &vector_length);
+ Interp_add_userfunc(interp, "vector-set", &vector_set);
+ return 1;
+}
diff --git a/exts/vector/test.lisp b/exts/vector/test.lisp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/exts/vector/test.lisp