aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMistivia <i@mistivia.com>2025-06-17 09:12:35 +0800
committerMistivia <i@mistivia.com>2025-06-17 09:12:35 +0800
commit6f1cfbda4a519ad8a232d126539a2732ab43c671 (patch)
treefe33602e4dd8419b216ca755ea91c63c72ffa65b
init
-rw-r--r--.gitignore6
-rw-r--r--.gitmodules3
m---------3rdparty/algds0
-rw-r--r--Makefile48
-rw-r--r--src/bamboo.c22
-rw-r--r--src/bamboo.h32
-rw-r--r--src/main.c3
-rw-r--r--src/parser.c38
-rw-r--r--src/parser.h35
-rw-r--r--src/sexp.c8
-rw-r--r--src/sexp.h80
11 files changed, 275 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5e89843
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+*.o
+*.d
+*.a
+bamboo-lisp
+compile_commands.json
+.cache
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..26eaac4
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "3rdparty/algds"]
+ path = 3rdparty/algds
+ url = https://github.com/mistivia/algds.git
diff --git a/3rdparty/algds b/3rdparty/algds
new file mode 160000
+Subproject b8e8f46f58136464c4fdd0aa37578f2313f0bd9
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..89195e4
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,48 @@
+mode ?= debug
+cc = gcc
+includes = -I3rdparty/algds/build/include/
+ldflags = -L3rdparty/algds/build/lib/ -lalgds
+ifeq ($(mode), debug)
+ cflags = $(includes) \
+ -g \
+ -fsanitize=address
+else
+ cflags = $(includes) -flto -O2
+endif
+
+src = $(shell find src/ -name '*.c' -not -name 'main.c')
+obj = $(src:.c=.o)
+
+tests=$(shell ls tests/*.c)
+tests_bin=$(tests:.c=.bin)
+
+all: bamboo-lisp
+
+bamboo-lisp: 3rdparty/algds/build/lib/libalgds.a $(obj) src/main.c
+ gcc $(ldflags) $(cflags) -o $@ $(obj) src/main.c
+
+3rdparty/algds/build/lib/libalgds.a:
+ cd 3rdparty/algds && \
+ make profile=$(mode)
+
+test: $(tests_bin)
+ @echo
+ @echo "Run tests:"
+ @scripts/runall.sh $^
+
+$(obj):%.o:%.c
+ $(cc) -c $(cflags) $< -MD -MF $@.d -o $@
+
+$(tests_bin):%.bin:%.c $(obj)
+ $(cc) $(ldflags) $(cflags) -Isrc/ $< $(obj) -MD -MF $@.d -o $@
+
+clean:
+ -rm $(shell find tests/ -name '*.bin')
+ -rm $(shell find . -name '*.o' -or -name '*.a' -or -name '*.d')
+ -rm bamboo-lisp
+ -cd 3rdparty/algds && make clean
+
+DEPS := $(shell find . -name *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
diff --git a/src/bamboo.c b/src/bamboo.c
new file mode 100644
index 0000000..70a84f5
--- /dev/null
+++ b/src/bamboo.c
@@ -0,0 +1,22 @@
+#include "bamboo.h"
+
+SExpRef new_list1(Bamboo *ctx, SExpRef e1) {
+ return cons(ctx, e1, nil(ctx));
+}
+
+SExpRef new_list2(Bamboo *ctx, SExpRef e1, SExpRef e2) {
+ return cons(ctx, e1, new_list1(ctx, e2));
+}
+
+SExpRef new_list3(Bamboo *ctx, SExpRef e1, SExpRef e2, SExpRef e3) {
+ return cons(ctx, e1, new_list2(ctx, e2, e3));
+}
+
+SExpRef new_list4(Bamboo *ctx, SExpRef e1, SExpRef e2, SExpRef e3, SExpRef e4) {
+ return cons(ctx, e1, new_list3(ctx, e2, e3, e4));
+}
+
+SExpRef new_list5(Bamboo *ctx, SExpRef e1, SExpRef e2, SExpRef e3, SExpRef e4, SExpRef e5) {
+ return cons(ctx, e1, new_list4(ctx, e2, e3, e4, e5));
+}
+
diff --git a/src/bamboo.h b/src/bamboo.h
new file mode 100644
index 0000000..a424be6
--- /dev/null
+++ b/src/bamboo.h
@@ -0,0 +1,32 @@
+#ifndef BAMBOO_LISP_BAMBOO_H_
+#define BAMBOO_LISP_BAMBOO_H_
+
+#include <algds/hash_table.h>
+
+#include "sexp.h"
+
+typedef struct {
+ SExpVector objs;
+ String2IntHashTable symbols;
+} Bamboo;
+
+void Bamboo_init(Bamboo *self);
+SExp* Bamboo_ref(Bamboo *self, SExpRef ref);
+// TODO: Heap_gc()
+
+SExpRef new_integer(Bamboo *ctx, int64_t val);
+SExpRef new_real(Bamboo *ctx, double val);
+SExpRef new_string(Bamboo *ctx, const char *val);
+SExpRef new_symbol(Bamboo *ctx, const char *val);
+SExpRef cons(Bamboo *ctx, SExpRef car, SExpRef cdr);
+SExpRef nil(Bamboo *ctx);
+SExpRef new_list1(Bamboo *ctx, SExpRef e1);
+SExpRef new_list2(Bamboo *ctx, SExpRef e1, SExpRef e2);
+SExpRef new_list3(Bamboo *ctx, SExpRef e1, SExpRef e2, SExpRef e3);
+SExpRef new_list4(Bamboo *ctx, SExpRef e1, SExpRef e2, SExpRef e3, SExpRef e4);
+SExpRef new_list5(Bamboo *ctx, SExpRef e1, SExpRef e2, SExpRef e3, SExpRef e4, SExpRef e5);
+SExpRef new_list6(Bamboo *ctx, SExpRef e1, SExpRef e2, SExpRef e3, SExpRef e4, SExpRef e5, SExpRef e6);
+SExpRef new_list7(Bamboo *ctx, SExpRef e1, SExpRef e2, SExpRef e3, SExpRef e4, SExpRef e5, SExpRef e6, SExpRef e7);
+
+#endif
+
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..33c14ce
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,3 @@
+int main() {
+ return 0;
+}
diff --git a/src/parser.c b/src/parser.c
new file mode 100644
index 0000000..d164186
--- /dev/null
+++ b/src/parser.c
@@ -0,0 +1,38 @@
+#include "parser.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+
+static void skip_spaces(Parser *ctx) {
+ while (isspace(parser_peek(ctx))) {
+ parser_getchar(ctx);
+ }
+}
+
+ParseResult ParseOk(SExpRef ref) {
+ return (ParseResult){ .val = ref, .errmsg = NULL };
+}
+
+ParseResult ParseErr(const char *msg) {
+ return (ParseResult){ .val = {-1}, .errmsg = msg };
+}
+
+ParseResult parse_sexp(Parser *ctx) {
+ skip_spaces(ctx);
+ int next = parser_peek(ctx);
+ if (next == '(') {
+ return parse_list(ctx);
+ } else if (next == ',') {
+ parser_getchar(ctx);
+ if (parser_peek(ctx) == '@') {
+ return parse_slicing_unquote(ctx);
+ }
+ return parse_unquote(ctx);
+ } else if (next == '`') {
+ return parse_quasi(ctx);
+ } else if (next == '\'') {
+ return parse_quote(ctx);
+ }
+ return parse_atom(ctx);
+}
+
diff --git a/src/parser.h b/src/parser.h
new file mode 100644
index 0000000..3f159b8
--- /dev/null
+++ b/src/parser.h
@@ -0,0 +1,35 @@
+#ifndef BAMBOO_LISP_PARSER_H_
+#define BAMBOO_LISP_PARSER_H_
+
+#include <stdbool.h>
+
+#include "sexp.h"
+
+typedef struct {
+
+} Parser;
+
+typedef struct {
+ SExpRef val;
+ const char *errmsg;
+} ParseResult;
+
+int parser_getchar(Parser *ctx);
+int parser_peek(Parser *ctx);
+
+ParseResult parse_sexp(Parser *ctx);
+ParseResult parse_list(Parser *ctx);
+ParseResult parse_quote(Parser *ctx);
+ParseResult parse_unquote(Parser *ctx);
+ParseResult parse_slicing_unquote(Parser *ctx);
+ParseResult parse_quasi(Parser *ctx);
+ParseResult parse_atom(Parser *ctx);
+ParseResult parse_number(Parser *ctx);
+ParseResult parse_integer(Parser *ctx);
+ParseResult parse_real(Parser *ctx);
+ParseResult parse_symbol(Parser *ctx);
+ParseResult parse_string(Parser *ctx);
+ParseResult parse_char(Parser *ctx);
+
+#endif
+
diff --git a/src/sexp.c b/src/sexp.c
new file mode 100644
index 0000000..b268414
--- /dev/null
+++ b/src/sexp.c
@@ -0,0 +1,8 @@
+#include "sexp.h"
+#include "algds/vec.h"
+
+void SExp_show(SExp self, FILE* fp) {
+ fprintf(fp, "{SEXP}");
+}
+
+VECTOR_IMPL(SExp);
diff --git a/src/sexp.h b/src/sexp.h
new file mode 100644
index 0000000..dfbc4d9
--- /dev/null
+++ b/src/sexp.h
@@ -0,0 +1,80 @@
+#ifndef BAMBOO_LISP_SEXP_H_
+#define BAMBOO_LISP_SEXP_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <algds/vec.h>
+
+struct sexp;
+typedef struct sexp SExp;
+
+typedef struct {
+ int idx;
+} SExpRef;
+
+typedef struct {
+ SExpRef car;
+ SExpRef cdr;
+} SExpPair;
+
+typedef struct {
+ SExpRef args;
+ SExpRef body;
+} SExpFunc;
+
+typedef struct {
+ SExpRef args;
+ SExpRef body;
+} SExpMacro;
+
+typedef struct {
+ SExpRef parent;
+ SExpRef child;
+ SExpRef bindings;
+} SExpEnv;
+
+typedef struct {
+ SExpRef name;
+ SExpRef value;
+ SExpRef func;
+ SExpRef next;
+} SExpBinding;
+
+typedef enum {
+ kIntegerSExp,
+ kRealSExp,
+ kBooleanSExp,
+ kNumberSExp,
+ kCharSExp,
+ kStringSExp,
+ kSymbolSExp,
+ kUserDataSExp,
+ kPairSExp,
+ kFuncSExp,
+ kEnvSExp,
+ kBindingSExp,
+ kMacroSExp,
+} SExpType;
+
+struct sexp {
+ SExpType type;
+ union {
+ int64_t integer;
+ double real;
+ bool boolean;
+ char character;
+ const char *str;
+ const void *userdata;
+ SExpPair pair;
+ SExpFunc func;
+ SExpEnv env;
+ };
+};
+
+void SExp_show(SExp self, FILE* fp);
+
+VECTOR_DEF(SExp);
+
+#endif
+