aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-10-10 12:11:45 +0200
committerBad Diode <bd@badd10de.dev>2021-10-10 12:11:45 +0200
commit4673fde605090320fbab227e56bb085eec97362a (patch)
tree5d510484d5543b4b11fd62b42a4b1e14672ff2cd
parentc2bfb5368e603d686190fdc9f3ddbafbda075a9c (diff)
downloadbdl-4673fde605090320fbab227e56bb085eec97362a.tar.gz
bdl-4673fde605090320fbab227e56bb085eec97362a.zip
Add boolean primitives and more (better) tests
-rwxr-xr-xMakefile7
-rw-r--r--examples/arithmetic.bdl34
-rw-r--r--examples/booleans.bdl45
-rw-r--r--src/bootstrap/lexer.c2
-rwxr-xr-xsrc/bootstrap/main.c10
-rw-r--r--src/bootstrap/primitives.c95
-rw-r--r--src/bootstrap/readline.c2
-rw-r--r--src/bootstrap/string_view.c18
-rw-r--r--tests/arithmetic_expected.txt18
-rw-r--r--tests/booleans_expected.txt34
10 files changed, 222 insertions, 43 deletions
diff --git a/Makefile b/Makefile
index afcd918..1a3168b 100755
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,7 @@ LDLIBS :=
22RELEASE_CFLAGS := -DNDEBUG -O2 22RELEASE_CFLAGS := -DNDEBUG -O2
23DEBUG_CFLAGS := -DDEBUG -O2 -g 23DEBUG_CFLAGS := -DDEBUG -O2 -g
24 24
25.PHONY: tools clean run 25.PHONY: build tests run clean
26 26
27# Setup debug/release builds. 27# Setup debug/release builds.
28# make clean && make <target> DEBUG=0 28# make clean && make <target> DEBUG=0
@@ -40,14 +40,15 @@ $(BIN): $(SRC_MAIN) $(WATCH_SRC) $(BUILD_DIR)
40 $(CC) $(CFLAGS) $(LDFLAGS) -o $(BIN) $(SRC_MAIN) $(LDLIBS) 40 $(CC) $(CFLAGS) $(LDFLAGS) -o $(BIN) $(SRC_MAIN) $(LDLIBS)
41 41
42# Create build directory if needed. 42# Create build directory if needed.
43$(BUILD_DIR): tools 43$(BUILD_DIR):
44 mkdir -p $(BUILD_DIR) 44 mkdir -p $(BUILD_DIR)
45 45
46run: $(BIN) 46run: $(BIN)
47 ./$(BIN) -i 47 ./$(BIN) -i
48 48
49tests: $(BIN) 49tests: $(BIN)
50 ./$(BIN) examples/arithmetic.bdl | diff -q tests/arithmetic_expected.txt - 50 ./$(BIN) examples/arithmetic.bdl | diff tests/arithmetic_expected.txt -
51 ./$(BIN) examples/booleans.bdl | diff tests/booleans_expected.txt -
51 52
52# Remove build directory. 53# Remove build directory.
53clean: 54clean:
diff --git a/examples/arithmetic.bdl b/examples/arithmetic.bdl
index 5e102e9..83404e2 100644
--- a/examples/arithmetic.bdl
+++ b/examples/arithmetic.bdl
@@ -1,22 +1,22 @@
1; 1;;
2; Basic arithmetic operations 2;; Basic arithmetic operations.
3; 3;;
4 4
5; Addition 5;; Addition.
6(+ 10 100) 6(print "(+ 10 100) -> ") (+ 10 100)
7(+ 1 -2 3 4) 7(print "(+ 1 -2 3 4) -> ") (+ 1 -2 3 4)
8 8
9; Substraction 9;; Substraction.
10(- 100 75) 10(print "(- 100 75) -> ") (- 100 75)
11(- 10 20 30) 11(print "(- 10 20 30) -> ") (- 10 20 30)
12 12
13; Multiplication 13;; Multiplication.
14(* 10 7) 14(print "(* 10 7) -> ") (* 10 7)
15(* -1 66) 15(print "(* -1 66) -> ") (* -1 66)
16 16
17; Division 17;; Division.
18(/ 45 5) 18(print "(/ 45 5) -> ") (/ 45 5)
19(/ 10 5 2) 19(print "(/ 10 5 2) -> ") (/ 10 5 2)
20 20
21; Nesting operations. 21;; Nesting operations.
22(* 20 (+ 100 (- 50 30) (/ 300 3)) 10) 22(print "(* 20 (+ 100 (- 50 30) (/ 300 3)) 10) -> ") (* 20 (+ 100 (- 50 30) (/ 300 3)) 10)
diff --git a/examples/booleans.bdl b/examples/booleans.bdl
new file mode 100644
index 0000000..d248bf8
--- /dev/null
+++ b/examples/booleans.bdl
@@ -0,0 +1,45 @@
1;;
2;; Boolean primitives.
3;;
4
5;; Boolean test.
6(print "(boolean? true) -> ") (boolean? true)
7(print "(boolean? false) -> ") (boolean? false)
8(print "(boolean? 1) -> ") (boolean? 1)
9(print "(boolean? 5) -> ") (boolean? 5)
10(print "(boolean? \"string\") -> ") (boolean? "string")
11(print "(boolean? (+ 1 2 3)) -> ") (boolean? (+ 1 2 3))
12(print "(boolean? (not 1)) -> ") (boolean? (not 1))
13
14;; Not.
15(print "(not true) -> ") (not true)
16(print "(not false) -> ") (not false)
17(print "(not (not true)) -> ") (not (not true))
18(print "(not (not false)) -> ") (not (not false))
19(print "(not 1) -> ") (not 1)
20(print "(not (not 1)) -> ") (not (not 1))
21(print "(not \"string\") -> ") (not "string")
22(print "(not (not \"string\")) -> ") (not (not "string"))
23
24;; And.
25(print "(and 1 \"string\" 4 true) -> ") (and 1 "string" 4 true)
26(print "(and true true true) -> ") (and true true true)
27(print "(and (+ 1 2 3)) -> ") (and (+ 1 2 3))
28(print "(and false false false) -> ") (and false false false)
29(print "(and true false false) -> ") (and true false false)
30(print "(and false true false) -> ") (and false true false)
31(print "(and false true true) -> ") (and false true true)
32(print "(and (not false) true true) -> ") (and (not false) true true)
33
34;; Or.
35(print "(or 1 \"string\" 4 true) -> ") (or 1 "string" 4 true)
36(print "(or false 1) -> ") (or false 1)
37(print "(or false \"string\") -> ") (or false "string")
38(print "(or false) -> ") (or false)
39(print "(or true true true) -> ") (or true true true)
40(print "(or false false false) -> ") (or false false false)
41(print "(or true false false) -> ") (or true false false)
42(print "(or false true false) -> ") (or false true false)
43(print "(or false true true) -> ") (or false true true)
44(print "(or (not false) true true) -> ") (or (not false) true true)
45(print "(or (not true) false) -> ") (or (not true) false)
diff --git a/src/bootstrap/lexer.c b/src/bootstrap/lexer.c
index dd5c0f2..b03db77 100644
--- a/src/bootstrap/lexer.c
+++ b/src/bootstrap/lexer.c
@@ -51,7 +51,7 @@ Tokens
51tokenize(StringView sv) { 51tokenize(StringView sv) {
52 // NOTE: Not allocating any memory for now, but we are limited by a maximum 52 // NOTE: Not allocating any memory for now, but we are limited by a maximum
53 // number of tokens we can process. 53 // number of tokens we can process.
54 #define TOKENS_BUF_SIZE 1024 54 #define TOKENS_BUF_SIZE KB(64)
55 static Token tokens_buf[TOKENS_BUF_SIZE]; 55 static Token tokens_buf[TOKENS_BUF_SIZE];
56 56
57 // Clear buffer. 57 // Clear buffer.
diff --git a/src/bootstrap/main.c b/src/bootstrap/main.c
index 95b2e49..a8ba7bc 100755
--- a/src/bootstrap/main.c
+++ b/src/bootstrap/main.c
@@ -37,8 +37,11 @@ init(void) {
37 environment[env_n++] = (EnvSymbol){MAKE_SYM("*"), make_procedure(proc_mul)}; 37 environment[env_n++] = (EnvSymbol){MAKE_SYM("*"), make_procedure(proc_mul)};
38 environment[env_n++] = (EnvSymbol){MAKE_SYM("/"), make_procedure(proc_div)}; 38 environment[env_n++] = (EnvSymbol){MAKE_SYM("/"), make_procedure(proc_div)};
39 environment[env_n++] = (EnvSymbol){MAKE_SYM("boolean?"), make_procedure(proc_is_boolean)}; 39 environment[env_n++] = (EnvSymbol){MAKE_SYM("boolean?"), make_procedure(proc_is_boolean)};
40 environment[env_n++] = (EnvSymbol){MAKE_SYM("false?"), make_procedure(proc_is_false)}; 40 environment[env_n++] = (EnvSymbol){MAKE_SYM("not"), make_procedure(proc_not)};
41 environment[env_n++] = (EnvSymbol){MAKE_SYM("and"), make_procedure(proc_and)};
42 environment[env_n++] = (EnvSymbol){MAKE_SYM("or"), make_procedure(proc_or)};
41 environment[env_n++] = (EnvSymbol){MAKE_SYM("display"), make_procedure(proc_display)}; 43 environment[env_n++] = (EnvSymbol){MAKE_SYM("display"), make_procedure(proc_display)};
44 environment[env_n++] = (EnvSymbol){MAKE_SYM("print"), make_procedure(proc_print)};
42} 45}
43 46
44void 47void
@@ -64,8 +67,9 @@ eval_line(FILE *fd, char delimiter) {
64 printf("\n"); 67 printf("\n");
65 printf("EVAL: "); 68 printf("EVAL: ");
66#endif 69#endif
67 display(eval(ast)); 70 if (display(eval(ast))) {
68 printf("\n"); 71 printf("\n");
72 };
69 } 73 }
70 } 74 }
71} 75}
diff --git a/src/bootstrap/primitives.c b/src/bootstrap/primitives.c
index e4c18cd..97058f9 100644
--- a/src/bootstrap/primitives.c
+++ b/src/bootstrap/primitives.c
@@ -1,4 +1,4 @@
1void display(Object *root); 1bool display(Object *root);
2 2
3void 3void
4display_pair(Object *root) { 4display_pair(Object *root) {
@@ -6,7 +6,7 @@ display_pair(Object *root) {
6 if (root->cdr->type == OBJ_TYPE_PAIR) { 6 if (root->cdr->type == OBJ_TYPE_PAIR) {
7 printf(" "); 7 printf(" ");
8 display_pair(root->cdr); 8 display_pair(root->cdr);
9 } else if (root->cdr->type == OBJ_TYPE_NIL) { 9 } else if (root->cdr == obj_nil) {
10 return; 10 return;
11 } else { 11 } else {
12 printf(" . "); 12 printf(" . ");
@@ -14,10 +14,10 @@ display_pair(Object *root) {
14 } 14 }
15} 15}
16 16
17void 17bool
18display(Object *root) { 18display(Object *root) {
19 if (root == NULL) { 19 if (root == NULL) {
20 return; 20 return false;
21 } 21 }
22 22
23 switch (root->type) { 23 switch (root->type) {
@@ -49,6 +49,7 @@ display(Object *root) {
49 printf("#{procedure}"); 49 printf("#{procedure}");
50 } break; 50 } break;
51 } 51 }
52 return true;
52} 53}
53 54
54Object * 55Object *
@@ -223,14 +224,90 @@ proc_display(Object *args) {
223} 224}
224 225
225Object * 226Object *
227proc_print(Object *args) {
228 if (args == NULL) {
229 return NULL;
230 }
231 if (args->type == OBJ_TYPE_PAIR) {
232 Object *obj = args->car;
233 if (obj->type == OBJ_TYPE_STRING) {
234 StringView scanner = (StringView) {
235 .start = obj->string,
236 .n = obj->string_n,
237 };
238 while (scanner.n != 0) {
239 char c = sv_next(&scanner);
240 if (c == '\\' && sv_peek(&scanner) == 'n') {
241 putchar('\n');
242 sv_next(&scanner);
243 continue;
244 }
245 if (c == '\\' && sv_peek(&scanner) == '"') {
246 putchar('"');
247 sv_next(&scanner);
248 continue;
249 }
250 putchar(c);
251 }
252 } else {
253 fprintf(stderr, "error: print requires a string argument\n");
254 }
255 }
256 return NULL;
257}
258
259Object *
226proc_is_boolean(Object *args) { 260proc_is_boolean(Object *args) {
227 if (args->car == obj_true || args->car == obj_false) { 261 Object *obj = NULL;
228 return obj_true; 262 if (args->type == OBJ_TYPE_PAIR) {
263 obj = eval(args->car);
264 } else {
265 obj = eval(args);
229 } 266 }
230 return obj_false; 267 return (obj == obj_true || obj == obj_false) ? obj_true : obj_false;
268}
269
270Object *
271proc_not(Object *args) {
272 if (args->type == OBJ_TYPE_PAIR) {
273 return eval(args->car) == obj_false ? obj_true : obj_false;
274 }
275 return eval(args) == obj_false ? obj_true : obj_false;
276}
277
278Object *
279proc_and(Object *args) {
280 while (args != NULL && args != obj_nil) {
281 Object *obj = args->car;
282 if (args->car->type == OBJ_TYPE_PAIR) {
283 obj = eval(args->car);
284 }
285 if (proc_not(obj) == obj_true) {
286 return obj_false;
287 }
288 args = args->cdr;
289 }
290 return obj_true;
231} 291}
232 292
233Object * 293Object *
234proc_is_false(Object *args) { 294proc_or(Object *args) {
235 return args->car == obj_false ? obj_true : obj_false; 295 if (args->type != OBJ_TYPE_PAIR) {
296 return obj_false;
297 }
298
299 while (args != NULL && args != obj_nil) {
300 Object *obj = args->car;
301 if (args->car->type == OBJ_TYPE_PAIR) {
302 obj = eval(args->car);
303 }
304 if (proc_not(obj) == obj_false) {
305 return obj_true;
306 }
307 args = args->cdr;
308 }
309 return obj_false;
236} 310}
311
312// TODO: if/cond
313// TODO: fixnum left/right shift, mask, invert
diff --git a/src/bootstrap/readline.c b/src/bootstrap/readline.c
index dfd8285..ae03e4a 100644
--- a/src/bootstrap/readline.c
+++ b/src/bootstrap/readline.c
@@ -2,7 +2,7 @@
2 2
3StringView 3StringView
4read_line(FILE *fd, char delimiter) { 4read_line(FILE *fd, char delimiter) {
5 #define RL_BUF_SIZE 1024 5 #define RL_BUF_SIZE KB(64)
6 static char readline_buf[RL_BUF_SIZE]; 6 static char readline_buf[RL_BUF_SIZE];
7 7
8 // Clear buffer. 8 // Clear buffer.
diff --git a/src/bootstrap/string_view.c b/src/bootstrap/string_view.c
index 3cf275a..e958a46 100644
--- a/src/bootstrap/string_view.c
+++ b/src/bootstrap/string_view.c
@@ -23,3 +23,21 @@ sv_equal(StringView a, StringView b) {
23 return false; 23 return false;
24} 24}
25 25
26char
27sv_next(StringView *sv) {
28 if (sv->n == 0) {
29 return '\0';
30 }
31 char ret = sv->start[0];
32 sv->start++;
33 sv->n--;
34 return ret;
35}
36
37char
38sv_peek(const StringView *sv) {
39 if (sv->n == 0) {
40 return '\0';
41 }
42 return sv->start[0];
43}
diff --git a/tests/arithmetic_expected.txt b/tests/arithmetic_expected.txt
index 590166a..16445dc 100644
--- a/tests/arithmetic_expected.txt
+++ b/tests/arithmetic_expected.txt
@@ -1,9 +1,9 @@
1110 1(+ 10 100) -> 110
26 2(+ 1 -2 3 4) -> 6
325 3(- 100 75) -> 25
4-40 4(- 10 20 30) -> -40
570 5(* 10 7) -> 70
6-66 6(* -1 66) -> -66
79 7(/ 45 5) -> 9
81 8(/ 10 5 2) -> 1
944000 9(* 20 (+ 100 (- 50 30) (/ 300 3)) 10) -> 44000
diff --git a/tests/booleans_expected.txt b/tests/booleans_expected.txt
new file mode 100644
index 0000000..81f0313
--- /dev/null
+++ b/tests/booleans_expected.txt
@@ -0,0 +1,34 @@
1(boolean? true) -> true
2(boolean? false) -> true
3(boolean? 1) -> false
4(boolean? 5) -> false
5(boolean? "string") -> false
6(boolean? (+ 1 2 3)) -> false
7(boolean? (not 1)) -> true
8(not true) -> false
9(not false) -> true
10(not (not true)) -> true
11(not (not false)) -> false
12(not 1) -> false
13(not (not 1)) -> true
14(not "string") -> false
15(not (not "string")) -> true
16(and 1 "string" 4 true) -> true
17(and true true true) -> true
18(and (+ 1 2 3)) -> true
19(and false false false) -> false
20(and true false false) -> false
21(and false true false) -> false
22(and false true true) -> false
23(and (not false) true true) -> true
24(or 1 "string" 4 true) -> true
25(or false 1) -> true
26(or false "string") -> true
27(or false) -> false
28(or true true true) -> true
29(or false false false) -> false
30(or true false false) -> true
31(or false true false) -> true
32(or false true true) -> true
33(or (not false) true true) -> true
34(or (not true) false) -> false