diff options
| author | Mistivia <i@mistivia.com> | 2025-06-17 09:12:35 +0800 |
|---|---|---|
| committer | Mistivia <i@mistivia.com> | 2025-06-17 09:12:35 +0800 |
| commit | 6f1cfbda4a519ad8a232d126539a2732ab43c671 (patch) | |
| tree | fe33602e4dd8419b216ca755ea91c63c72ffa65b | |
init
| -rw-r--r-- | .gitignore | 6 | ||||
| -rw-r--r-- | .gitmodules | 3 | ||||
| m--------- | 3rdparty/algds | 0 | ||||
| -rw-r--r-- | Makefile | 48 | ||||
| -rw-r--r-- | src/bamboo.c | 22 | ||||
| -rw-r--r-- | src/bamboo.h | 32 | ||||
| -rw-r--r-- | src/main.c | 3 | ||||
| -rw-r--r-- | src/parser.c | 38 | ||||
| -rw-r--r-- | src/parser.h | 35 | ||||
| -rw-r--r-- | src/sexp.c | 8 | ||||
| -rw-r--r-- | src/sexp.h | 80 |
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 + |
