aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--examples/arithmetic.bdl60
-rw-r--r--examples/booleans.bdl82
-rw-r--r--examples/lists.bdl24
-rw-r--r--examples/rule110.bdl47
-rw-r--r--examples/types.bdl72
-rw-r--r--examples/variables.bdl84
-rw-r--r--src/main.c336
-rw-r--r--tests/arithmetic_expected.txt13
-rw-r--r--tests/booleans_expected.txt53
-rw-r--r--tests/constants/numbers.bdl41
-rw-r--r--tests/constants/strings.bdl5
-rw-r--r--tests/lists_expected.txt15
-rw-r--r--tests/types_expected.txt55
-rw-r--r--tests/variables.bad57
-rw-r--r--tests/variables_expected.txt23
16 files changed, 346 insertions, 623 deletions
diff --git a/Makefile b/Makefile
index 91c9b0e..843325a 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@
5SRC_DIR := src 5SRC_DIR := src
6BUILD_DIR := build 6BUILD_DIR := build
7SRC_MAIN := $(SRC_DIR)/main.c 7SRC_MAIN := $(SRC_DIR)/main.c
8SRC_BAD := tests/literals.bad 8SRC_BAD := tests/variables.bad
9WATCH_SRC := $(shell find $(SRC_DIR) -name "*.c" -or -name "*.s" -or -name "*.h") 9WATCH_SRC := $(shell find $(SRC_DIR) -name "*.c" -or -name "*.s" -or -name "*.h")
10INC_DIRS := $(shell find $(SRC_DIR) -type d) 10INC_DIRS := $(shell find $(SRC_DIR) -type d)
11INC_FLAGS := $(addprefix -I,$(INC_DIRS)) 11INC_FLAGS := $(addprefix -I,$(INC_DIRS))
diff --git a/examples/arithmetic.bdl b/examples/arithmetic.bdl
deleted file mode 100644
index c313dbb..0000000
--- a/examples/arithmetic.bdl
+++ /dev/null
@@ -1,60 +0,0 @@
1;;
2;; Basic arithmetic operations.
3;;
4
5;; Addition.
6(print "(+ 10 100) -> ")
7(display (+ 10 100))
8(newline)
9
10(print "(+ 1 -2 3 4) -> ")
11(display (+ 1 -2 3 4))
12(newline)
13
14;; Substraction.
15(print "(- 100 75) -> ")
16(display (- 100 75))
17(newline)
18
19(print "(- 10 20 30) -> ")
20(display (- 10 20 30))
21(newline)
22
23;; Multiplication.
24(print "(* 10 7) -> ")
25(display (* 10 7))
26(newline)
27
28(print "(* -1 66) -> ")
29(display (* -1 66))
30(newline)
31
32;; Division.
33(print "(/ 45 5) -> ")
34(display (/ 45 5))
35(newline)
36
37(print "(/ 10 5 2) -> ")
38(display (/ 10 5 2))
39(newline)
40
41;; Remainder/modulo.
42(print "(% 45 5) -> ")
43(display (% 45 5))
44(newline)
45
46(print "(% 45 7) -> ")
47(display (% 45 7))
48(newline)
49
50(print "(% 120 45) -> ")
51(display (% 120 45))
52(newline)
53
54(print "(% 120 45 8) -> ")
55(display (% 120 45 8))
56(newline)
57
58;; Nesting operations.
59(print "(* 20 (+ 100 (- 50 30) (/ 300 3)) 10) -> ")
60(display (* 20 (+ 100 (- 50 30) (/ 300 3)) 10))
diff --git a/examples/booleans.bdl b/examples/booleans.bdl
deleted file mode 100644
index 3d647a6..0000000
--- a/examples/booleans.bdl
+++ /dev/null
@@ -1,82 +0,0 @@
1;;
2;; Boolean primitives.
3;;
4
5;; Not.
6(print "(not true) -> ") (display (not true))(newline)
7(print "(not false) -> ") (display (not false))(newline)
8(print "(not (not true)) -> ") (display (not (not true)))(newline)
9(print "(not (not false)) -> ") (display (not (not false)))(newline)
10(print "(not 1) -> ") (display (not 1))(newline)
11(print "(not (not 1)) -> ") (display (not (not 1)))(newline)
12(print "(not \"string\") -> ") (display (not "string"))(newline)
13(print "(not (not \"string\")) -> ") (display (not (not "string")))(newline)
14
15;; And.
16(print "(and 1 \"string\" 4 true) -> ") (display (and 1 "string" 4 true))(newline)
17(print "(and true true true) -> ") (display (and true true true))(newline)
18; (print "(and (+ 1 2 3)) -> ") (display (and (+ 1 2 3)))(newline)
19(print "(and false false false) -> ") (display (and false false false))(newline)
20(print "(and true false false) -> ") (display (and true false false))(newline)
21(print "(and false true false) -> ") (display (and false true false))(newline)
22(print "(and false true true) -> ") (display (and false true true))(newline)
23(print "(and (not false) true true) -> ") (display (and (not false) true true))(newline)
24
25;; Or.
26(print "(or 1 \"string\" 4 true) -> ") (display (or 1 "string" 4 true))(newline)
27(print "(or false 1) -> ") (display (or false 1))(newline)
28(print "(or false \"string\") -> ") (display (or false "string"))(newline)
29; (print "(or false) -> ") (display (or false))(newline)
30(print "(or true true true) -> ") (display (or true true true))(newline)
31(print "(or false false false) -> ") (display (or false false false))(newline)
32(print "(or true false false) -> ") (display (or true false false))(newline)
33(print "(or false true false) -> ") (display (or false true false))(newline)
34(print "(or false true true) -> ") (display (or false true true))(newline)
35(print "(or (not false) true true) -> ") (display (or (not false) true true))(newline)
36(print "(or (not true) false) -> ") (display (or (not true) false))(newline)
37
38;; If.
39(print "(if true true false) -> ") (display (if true true false))(newline)
40(print "(if false true false) -> ") (display (if false true false))(newline)
41(print "(if true (+ 1 2 3) 0) -> ") (display (if true (+ 1 2 3) 0))(newline)
42(print "(if false (+ 1 2 3) 0) -> ") (display (if false (+ 1 2 3) 0))(newline)
43(print "(if (or true false) (+ 1 2 3) (+ 7 8 9)) -> ") (display (if (or true false) (+ 1 2 3) (+ 7 8 9)))(newline)
44(print "(if (or false false) (+ 1 2 3) (+ 7 8 9)) -> ") (display (if (or false false) (+ 1 2 3) (+ 7 8 9)))(newline)
45(print "(if (or (+ 1 2 3) false) (+ 1 2 3) (+ 7 8 9)) -> ") (display (if (or (+ 1 2 3) false) (+ 1 2 3) (+ 7 8 9)))(newline)
46(print "(if true 7) -> ") (display (if true 7))(newline)
47(print "(if false 7) -> ") (display (if false 7))(newline)
48
49; ; ;; Cond.
50; ; (print "(cond ((and true true true) 1) ((or true true false) 2) (else 3)) -> ")
51; ; (cond ((and true true true) 1)
52; ; ((or true true false) 2)
53; ; (else 3))
54; ; (print "(cond ((and true true false) 1) ((or true true false) 2) (else 3)) -> ")
55; ; (cond ((and true true false) 1)
56; ; ((or true true false) 2)
57; ; (else 3))
58; ; (print "(cond ((and true true false) 1) ((or false false false) 2) (else 3)) -> ")
59; ; (cond ((and true true false) 1)
60; ; ((or false false false) 2)
61; ; (else 3))
62; ; (print "(cond ((and true true true) 1) ((or true true false) 2)) -> ")
63; ; (cond ((and true true false) 1)
64; ; ((or false false false) 2)) (newline)
65; ; (print "(cond ((and true true true) (+ 1 2 3)) ((or true true false) 2) (else 3)) -> ")
66; ; (cond ((and true true true) (+ 1 2 3))
67; ; ((or true true false) 2)
68; ; (else 3))
69
70;; Numeric comparisons.
71(print "(< 1 2 3) -> ") (display (< 1 2 3))(newline)
72(print "(< 3 2 1) -> ") (display (< 3 2 1))(newline)
73(print "(> 1 2 3) -> ") (display (> 1 2 3))(newline)
74(print "(> 3 2 1) -> ") (display (> 3 2 1))(newline)
75(print "(= 1 2 3) -> ") (display (= 1 2 3))(newline)
76(print "(= 3 2 1) -> ") (display (= 3 2 1))(newline)
77(print "(= 3 3 3) -> ") (display (= 3 3 3))(newline)
78(print "(= (+ 1 2) 3 (- 6 3)) -> ") (display (= (+ 1 2) 3 (- 6 3)))(newline)
79(print "(< 1 1 3) -> ") (display (< 1 1 3))(newline)
80(print "(<= 1 1 3) -> ") (display (<= 1 1 3))(newline)
81(print "(> 3 3 1) -> ") (display (> 3 3 1))(newline)
82(print "(>= 3 3 1) -> ") (display (>= 3 3 1))(newline)
diff --git a/examples/lists.bdl b/examples/lists.bdl
deleted file mode 100644
index 36063d6..0000000
--- a/examples/lists.bdl
+++ /dev/null
@@ -1,24 +0,0 @@
1;;
2;; List operations.
3;;
4
5;; List function.
6(print "(list) -> ") (list) (newline)
7(print "(list 1) -> ") (list 1)
8(print "(list 1 2) -> ") (list 1 2)
9(print "(list 1 2 3) -> ") (list 1 2 3)
10(print "(list 4 5 (+ 1 2 3)) -> ") (list 4 5 (+ 1 2 3))
11
12;; Car/cdr.
13(print "(car (list 1 2 3)) -> ") (car (list 1 2 3))
14(print "(cdr (list 1 2 3)) -> ") (cdr (list 1 2 3))
15(print "(car (list (* 10 20) (+ 1 2 3) 50 60)) -> ") (car (list (* 10 20) (+ 1 2 3) 50 60))
16(print "(cdr (list (* 10 20) (+ 1 2 3) 50 60)) -> ") (cdr (list (* 10 20) (+ 1 2 3) 50 60))
17(print "(car (cdr (list (* 10 20) (+ 1 2 3) 50 60))) -> ") (car (cdr (list (* 10 20) (+ 1 2 3) 50 60)))
18
19;; Pairs construction.
20(print "(cons 1 2) -> ") (cons 1 2)
21(print "(cons \"a\" \"b\") -> ") (cons "a" "b")
22(print "(cons \"a\" (cons \"c\" ())) -> ") (cons "a" (cons "c" ()))
23(print "(cons 1 (cons 2 (cons (+ 1 2) ()))) -> ") (cons 1 (cons 2 (cons (+ 1 2) ())))
24(print "(cons 1 (cons 2 (cons (+ 1 2) 4))) -> ") (cons 1 (cons 2 (cons (+ 1 2) 4)))
diff --git a/examples/rule110.bdl b/examples/rule110.bdl
deleted file mode 100644
index abc89a9..0000000
--- a/examples/rule110.bdl
+++ /dev/null
@@ -1,47 +0,0 @@
1(def sequence (list 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1))
2
3(fun reverse (ls)
4 (fun rev-acc (ls acc)
5 (if (nil? ls)
6 acc
7 (rev-acc (cdr ls) (cons (car ls) acc))))
8 (rev-acc ls '()))
9
10(fun print-line (seq)
11 (if (or (nil? seq) (= 0 (car seq)))
12 (print " ")
13 (print "🖤"))
14 (if (not (nil? seq)) (print-line (cdr seq))))
15
16(fun rule-110 (seq n)
17 (print-line seq)
18 (newline)
19 (fun new-generation (lst seq)
20 (def a (if (nil? seq) 0 (car seq)))
21 (def b (if (or (nil? seq)
22 (nil? (cdr seq)))
23 0
24 (car (cdr seq))))
25 (def c (if (or (nil? seq)
26 (nil? (cdr seq))
27 (nil? (cdr (cdr seq))))
28 0
29 (car (cdr (cdr seq)))))
30 (def number (+ (* a 2 2) (* b 2) c))
31 (def cell (cond ((= number 0) 0)
32 ((= number 1) 1)
33 ((= number 2) 1)
34 ((= number 3) 1)
35 ((= number 4) 0)
36 ((= number 5) 1)
37 ((= number 6) 1)
38 ((= number 7) 0)))
39 (if (nil? (cdr seq))
40 lst
41 (new-generation (cons cell lst) (cdr seq))))
42 (def seq (cons 0 (reverse (new-generation '() seq))))
43 (if (= n 0)
44 ()
45 (rule-110 seq (- n 1))))
46
47(rule-110 sequence 25)
diff --git a/examples/types.bdl b/examples/types.bdl
deleted file mode 100644
index 22ffdce..0000000
--- a/examples/types.bdl
+++ /dev/null
@@ -1,72 +0,0 @@
1;;
2;; Type testing.
3;;
4
5;; Boolean.
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;; Empty list/null.
15(print "(nil? true) -> ") (nil? true)
16(print "(nil? false) -> ") (nil? false)
17(print "(nil? 1) -> ") (nil? 1)
18(print "(nil? 5) -> ") (nil? 5)
19(print "(nil? \"string\") -> ") (nil? "string")
20(print "(nil? (+ 1 2 3)) -> ") (nil? (+ 1 2 3))
21(print "(nil? (not 1)) -> ") (nil? (not 1))
22(print "(nil? ()) -> ") (nil? ())
23
24;; String.
25(print "(string? true) -> ") (string? true)
26(print "(string? false) -> ") (string? false)
27(print "(string? 1) -> ") (string? 1)
28(print "(string? 5) -> ") (string? 5)
29(print "(string? \"string\") -> ") (string? "string")
30(print "(string? (+ 1 2 3)) -> ") (string? (+ 1 2 3))
31(print "(string? (not 1)) -> ") (string? (not 1))
32
33;; Fixnum.
34(print "(fixnum? true) -> ") (fixnum? true)
35(print "(fixnum? false) -> ") (fixnum? false)
36(print "(fixnum? 1) -> ") (fixnum? 1)
37(print "(fixnum? 5) -> ") (fixnum? 5)
38(print "(fixnum? \"string\") -> ") (fixnum? "string")
39(print "(fixnum? (+ 1 2 3)) -> ") (fixnum? (+ 1 2 3))
40(print "(fixnum? (not 1)) -> ") (fixnum? (not 1))
41
42;; Symbol.
43(print "(symbol? true) -> ") (symbol? true)
44(print "(symbol? false) -> ") (symbol? false)
45(print "(symbol? 1) -> ") (symbol? 1)
46(print "(symbol? +) -> ") (symbol? +)
47(print "(symbol? \"string\") -> ") (symbol? "string")
48(print "(symbol? (+ 1 2 3)) -> ") (symbol? (+ 1 2 3))
49(print "(symbol? (not 1)) -> ") (symbol? (not 1))
50(print "(symbol? 'a) -> ") (symbol? 'a)
51(print "(symbol? 'c) -> ") (symbol? 'c)
52
53;; Pair.
54(print "(pair? false) -> ") (pair? false)
55(print "(pair? 1) -> ") (pair? 1)
56(print "(pair? 5) -> ") (pair? 5)
57(print "(pair? \"string\") -> ") (pair? "string")
58(print "(pair? (+ 1 2 3)) -> ") (pair? (+ 1 2 3))
59(print "(pair? (not 1)) -> ") (pair? (not 1))
60(print "(pair? (cons 1 2)) -> ") (pair? (cons 1 2))
61(print "(pair? (list 1 2 3)) -> ") (pair? (list 1 2 3))
62
63; ;; Procedure.
64(print "(procedure? false) -> ") (procedure? false)
65(print "(procedure? 1) -> ") (procedure? 1)
66(print "(procedure? 5) -> ") (procedure? 5)
67(print "(procedure? \"string\") -> ") (procedure? "string")
68(print "(procedure? (+ 1 2 3)) -> ") (procedure? (+ 1 2 3))
69(print "(procedure? (not 1)) -> ") (procedure? (not 1))
70(print "(procedure? +) -> ") (procedure? +)
71(print "(procedure? -) -> ") (procedure? -)
72(print "(procedure? procedure?) -> ") (procedure? procedure?)
diff --git a/examples/variables.bdl b/examples/variables.bdl
deleted file mode 100644
index a4dea0a..0000000
--- a/examples/variables.bdl
+++ /dev/null
@@ -1,84 +0,0 @@
1;;
2;; Variable declarations and updates
3;;
4
5(print "(def a 20)")
6(def a 20)
7(newline)
8
9(print "((lambda (a b) (+ 10 a b)) 1 2) -> ")
10(display ((lambda (a b) (+ 10 a b)) 1 2))
11(newline)
12
13(print "((lambda (a b) (+ 10 a b)) a 3) -> ")
14(display ((lambda (a b) (+ 10 a b)) a 3))
15(newline)
16
17(print "(def myfun (lambda (a b) (+ a b))) (myfun 6 9) -> ")
18(def myfun (lambda (a b) (+ a b)))
19(display (myfun 6 9))
20(newline)
21
22(print "(fun myfun (a b) (+ a b)) (myfun 6 9) -> ")
23(fun myfun (a b) (+ a b))
24(display (myfun 6 9))
25(newline)
26
27(print "(+ 1 (myfun 10 (myfun a a)) 30) -> ")
28(display (+ 1 (myfun 10 (myfun a a)) 30))
29(newline)
30
31(print "(myfun 10 (myfun 5 0)) -> ")
32(display (myfun 10 (myfun 5 0)))
33(newline)
34
35;; Closures.
36(print "(fun make-counter () (def value 0) (def counter (lambda () (set! value (+ value 1)) value)) counter)")
37(newline)
38(fun make-counter ()
39 (def value 0)
40 (def counter (lambda ()
41 (set! value (+ value 1))
42 value))
43 counter)
44
45(print "(def counter-a (make-counter))") (def counter-a (make-counter)) (newline)
46(print "(def counter-b (make-counter))") (def counter-b (make-counter)) (newline)
47(print "(counter-a) -> ") (display (counter-a))(newline)
48(print "(counter-b) -> ") (display (counter-b))(newline)
49(print "(counter-a) -> ") (display (counter-a))(newline)
50(print "(counter-a) -> ") (display (counter-a))(newline)
51(print "(counter-a) -> ") (display (counter-a))(newline)
52(print "(counter-b) -> ") (display (counter-b))(newline)
53(print "(counter-b) -> ") (display (counter-b))(newline)
54(print "(counter-b) -> ") (display (counter-b))(newline)
55
56;; Fibonacci.
57(print "(fun fib (n) (if (<= n 2) 1 (+ (fib (- n 1)) (fib (- n 2)))))") (newline)
58(fun fib (n)
59 (if (<= n 2)
60 1
61 (+ (fib (- n 1)) (fib (- n 2)))))
62
63(print "(fib 15) -> ")
64(display (fib 15))(newline)
65
66;; Lambda capture.
67(print "(fun b () (display a) (print \" --- \") (def a 42) (display a) (newline))") (newline)
68(fun b ()
69 (display a)
70 (print " --- ")
71 (def a 42)
72 (display a)
73 (newline))
74
75(print "(b) -> ") (b)
76(print "(b) -> ") (b)
77
78;; Infinite loop. (For teseting purposes)
79; (def test (lambda (n)
80; (print "ITER\n")
81; (if (<= n 2)
82; 1
83; (test (+ n 1)))))
84; (test 3)
diff --git a/src/main.c b/src/main.c
index 8dc645e..d456381 100644
--- a/src/main.c
+++ b/src/main.c
@@ -70,6 +70,13 @@ typedef enum NodeKind {
70 NODE_TRUE, 70 NODE_TRUE,
71 NODE_FALSE, 71 NODE_FALSE,
72 NODE_NIL, 72 NODE_NIL,
73 // Keywords.
74 NODE_LET,
75 NODE_SET,
76 NODE_STRUCT,
77 // Helpers.
78 NODE_NODE_LIST,
79 NODE_NODE_TYPE,
73} NodeKind; 80} NodeKind;
74 81
75Str node_str[] = { 82Str node_str[] = {
@@ -104,6 +111,12 @@ Str node_str[] = {
104 [NODE_TRUE] = cstr("TRUE"), 111 [NODE_TRUE] = cstr("TRUE"),
105 [NODE_FALSE] = cstr("FALSE"), 112 [NODE_FALSE] = cstr("FALSE"),
106 [NODE_NIL] = cstr("NIL"), 113 [NODE_NIL] = cstr("NIL"),
114 [NODE_LET] = cstr("LET"),
115 [NODE_SET] = cstr("SET"),
116 [NODE_STRUCT] = cstr("STRUCT"),
117 // Helpers.
118 [NODE_NODE_LIST] = cstr("..."),
119 [NODE_NODE_TYPE] = cstr("TYPE"),
107}; 120};
108 121
109typedef struct Node { 122typedef struct Node {
@@ -119,21 +132,17 @@ typedef struct Node {
119 Str str; 132 Str str;
120 Str sym; 133 Str sym;
121 } value; 134 } value;
122 struct Node *left; 135 union {
123 struct Node *right; 136 struct Node *left;
137 struct Node *varname;
138 };
139 union {
140 struct Node *right;
141 struct Node *vartype;
142 struct Node *varvalue;
143 };
124} Node; 144} Node;
125 145
126Node *
127node_alloc(NodeKind kind, Token tok, Arena *a) {
128 static sz id = 0;
129 Node *node = arena_calloc((sz)sizeof(Node), a);
130 node->id = id++;
131 node->kind = kind;
132 node->line = tok.line;
133 node->col = tok.col;
134 return node;
135}
136
137// 146//
138// Parsing. 147// Parsing.
139// 148//
@@ -179,6 +188,7 @@ typedef struct {
179 188
180void parse_expr(Parser *parser, ParsePrecedence precedence); 189void parse_expr(Parser *parser, ParsePrecedence precedence);
181void parse_advance(Parser *parser); 190void parse_advance(Parser *parser);
191bool parse_match(Parser *parser, TokenKind kind);
182 192
183void parse_grouping(Parser *parser); 193void parse_grouping(Parser *parser);
184void parse_unary(Parser *parser); 194void parse_unary(Parser *parser);
@@ -187,6 +197,11 @@ void parse_number(Parser *parser);
187void parse_literal(Parser *parser); 197void parse_literal(Parser *parser);
188void parse_string(Parser *parser); 198void parse_string(Parser *parser);
189void parse_symbol(Parser *parser); 199void parse_symbol(Parser *parser);
200void parse_symbol_chain(Parser *parser);
201void parse_keyword(Parser *parser);
202void parse_struct(Parser *parser);
203Node *parse_struct_field(Parser *parser);
204Node *parse_type(Parser *parser);
190 205
191ParseRule parse_rules[] = { 206ParseRule parse_rules[] = {
192 [TOK_LPAREN] = {parse_grouping, NULL, PREC_NONE}, 207 [TOK_LPAREN] = {parse_grouping, NULL, PREC_NONE},
@@ -196,6 +211,7 @@ ParseRule parse_rules[] = {
196 [TOK_DIV] = {NULL, parse_binary, PREC_FACTOR}, 211 [TOK_DIV] = {NULL, parse_binary, PREC_FACTOR},
197 [TOK_MUL] = {NULL, parse_binary, PREC_FACTOR}, 212 [TOK_MUL] = {NULL, parse_binary, PREC_FACTOR},
198 [TOK_MOD] = {NULL, parse_binary, PREC_FACTOR}, 213 [TOK_MOD] = {NULL, parse_binary, PREC_FACTOR},
214
199 // Logical. 215 // Logical.
200 [TOK_NOT] = {parse_unary, NULL, PREC_NONE}, 216 [TOK_NOT] = {parse_unary, NULL, PREC_NONE},
201 [TOK_AND] = {NULL, parse_binary, PREC_AND}, 217 [TOK_AND] = {NULL, parse_binary, PREC_AND},
@@ -206,23 +222,53 @@ ParseRule parse_rules[] = {
206 [TOK_GT] = {NULL, parse_binary, PREC_COMPARISON}, 222 [TOK_GT] = {NULL, parse_binary, PREC_COMPARISON},
207 [TOK_LE] = {NULL, parse_binary, PREC_COMPARISON}, 223 [TOK_LE] = {NULL, parse_binary, PREC_COMPARISON},
208 [TOK_GE] = {NULL, parse_binary, PREC_COMPARISON}, 224 [TOK_GE] = {NULL, parse_binary, PREC_COMPARISON},
225
209 // Bitwise ops. 226 // Bitwise ops.
210 [TOK_BITNOT] = {parse_unary, NULL, PREC_NONE}, 227 [TOK_BITNOT] = {parse_unary, NULL, PREC_NONE},
211 [TOK_BITAND] = {NULL, parse_binary, PREC_BITLOGIC}, 228 [TOK_BITAND] = {NULL, parse_binary, PREC_BITLOGIC},
212 [TOK_BITOR] = {NULL, parse_binary, PREC_BITLOGIC}, 229 [TOK_BITOR] = {NULL, parse_binary, PREC_BITLOGIC},
213 [TOK_BITLSHIFT] = {NULL, parse_binary, PREC_BITSHIFT}, 230 [TOK_BITLSHIFT] = {NULL, parse_binary, PREC_BITSHIFT},
214 [TOK_BITRSHIFT] = {NULL, parse_binary, PREC_BITSHIFT}, 231 [TOK_BITRSHIFT] = {NULL, parse_binary, PREC_BITSHIFT},
232
215 // Literals. 233 // Literals.
216 [TOK_STRING] = {parse_string, NULL, PREC_NONE}, 234 [TOK_STRING] = {parse_string, NULL, PREC_NONE},
217 [TOK_SYMBOL] = {parse_symbol, NULL, PREC_NONE}, 235 [TOK_SYMBOL] = {parse_symbol_chain, NULL, PREC_NONE},
218 [TOK_NUM_INT] = {parse_number, NULL, PREC_NONE}, 236 [TOK_NUM_INT] = {parse_number, NULL, PREC_NONE},
219 [TOK_NUM_FLOAT] = {parse_number, NULL, PREC_NONE}, 237 [TOK_NUM_FLOAT] = {parse_number, NULL, PREC_NONE},
220 [TOK_TRUE] = {parse_literal, NULL, PREC_NONE}, 238 [TOK_TRUE] = {parse_literal, NULL, PREC_NONE},
221 [TOK_FALSE] = {parse_literal, NULL, PREC_NONE}, 239 [TOK_FALSE] = {parse_literal, NULL, PREC_NONE},
222 [TOK_NIL] = {parse_literal, NULL, PREC_NONE}, 240 [TOK_NIL] = {parse_literal, NULL, PREC_NONE},
241
242 // Statements.
243 [TOK_LET] = {parse_keyword, NULL, PREC_NONE},
244 [TOK_SET] = {parse_keyword, NULL, PREC_NONE},
245 [TOK_STRUCT] = {parse_keyword, NULL, PREC_NONE},
246 [TOK_IF] = {parse_keyword, NULL, PREC_NONE},
247 [TOK_MATCH] = {parse_keyword, NULL, PREC_NONE},
248 [TOK_CASE] = {parse_keyword, NULL, PREC_NONE},
249 [TOK_WHILE] = {parse_keyword, NULL, PREC_NONE},
250 [TOK_CONTINUE] = {parse_keyword, NULL, PREC_NONE},
251 [TOK_BREAK] = {parse_keyword, NULL, PREC_NONE},
252 [TOK_FUN] = {parse_keyword, NULL, PREC_NONE},
253 [TOK_RETURN] = {parse_keyword, NULL, PREC_NONE},
254
223 [TOK_EOF] = {NULL, NULL, PREC_NONE}, 255 [TOK_EOF] = {NULL, NULL, PREC_NONE},
224}; 256};
225 257
258Node *
259node_alloc(NodeKind kind, Token tok, Parser *p) {
260 if (p->panic) {
261 return NULL;
262 }
263 static sz id = 0;
264 Node *node = arena_calloc((sz)sizeof(Node), p->storage);
265 node->id = id++;
266 node->kind = kind;
267 node->line = tok.line;
268 node->col = tok.col;
269 return node;
270}
271
226void 272void
227parse_emit_err(Parser *parser, Token token, Str msg) { 273parse_emit_err(Parser *parser, Token token, Str msg) {
228 if (parser->panic) { 274 if (parser->panic) {
@@ -243,9 +289,22 @@ void
243parse_advance(Parser *parser) { 289parse_advance(Parser *parser) {
244 assert(parser); 290 assert(parser);
245 parser->previous = parser->current; 291 parser->previous = parser->current;
292 if (parser->previous.kind == TOK_EOF) {
293 return;
294 }
246 parser->current = parser->tokens[parser->idx++]; 295 parser->current = parser->tokens[parser->idx++];
247} 296}
248 297
298bool
299parse_match(Parser *parser, TokenKind kind) {
300 assert(parser);
301 if (parser->current.kind != kind) {
302 return false;
303 }
304 parse_advance(parser);
305 return true;
306}
307
249static void 308static void
250parse_consume(Parser *parser, TokenKind kind, Str msg) { 309parse_consume(Parser *parser, TokenKind kind, Str msg) {
251 if (parser->current.kind == kind) { 310 if (parser->current.kind == kind) {
@@ -258,6 +317,10 @@ parse_consume(Parser *parser, TokenKind kind, Str msg) {
258void 317void
259parse_expr(Parser *parser, ParsePrecedence precedence) { 318parse_expr(Parser *parser, ParsePrecedence precedence) {
260 parse_advance(parser); 319 parse_advance(parser);
320 // TODO: synchronize panic mode on keywords.
321 if (parser->panic) {
322 return;
323 }
261 ParseFn prefix = parse_rules[parser->previous.kind].prefix; 324 ParseFn prefix = parse_rules[parser->previous.kind].prefix;
262 if (prefix == NULL) { 325 if (prefix == NULL) {
263 parse_emit_err(parser, parser->previous, cstr("expected expression")); 326 parse_emit_err(parser, parser->previous, cstr("expected expression"));
@@ -287,12 +350,13 @@ parse_unary(Parser *parser) {
287 parse_expr(parser, PREC_UNARY); 350 parse_expr(parser, PREC_UNARY);
288 Node *node = NULL; 351 Node *node = NULL;
289 switch (prev.kind) { 352 switch (prev.kind) {
290 case TOK_NOT: node = node_alloc(NODE_NOT, prev, parser->storage); break; 353 case TOK_NOT: node = node_alloc(NODE_NOT, prev, parser); break;
291 case TOK_BITNOT: { 354 case TOK_BITNOT: node = node_alloc(NODE_BITNOT, prev, parser); break;
292 node = node_alloc(NODE_BITNOT, prev, parser->storage);
293 } break;
294 default: break; // Unreachable. 355 default: break; // Unreachable.
295 } 356 }
357 if (!node) {
358 return;
359 }
296 node->left = array_pop(parser->nodes); 360 node->left = array_pop(parser->nodes);
297 array_push(parser->nodes, node, parser->storage); 361 array_push(parser->nodes, node, parser->storage);
298} 362}
@@ -307,13 +371,142 @@ parse_literal(Parser *parser) {
307 Node *node = NULL; 371 Node *node = NULL;
308 switch (prev.kind) { 372 switch (prev.kind) {
309 case TOK_TRUE: { 373 case TOK_TRUE: {
310 node = node_alloc(NODE_TRUE, prev, parser->storage); 374 node = node_alloc(NODE_TRUE, prev, parser);
311 } break; 375 } break;
312 case TOK_FALSE: { 376 case TOK_FALSE: {
313 node = node_alloc(NODE_FALSE, prev, parser->storage); 377 node = node_alloc(NODE_FALSE, prev, parser);
314 } break; 378 } break;
315 case TOK_NIL: { 379 case TOK_NIL: {
316 node = node_alloc(NODE_NIL, prev, parser->storage); 380 node = node_alloc(NODE_NIL, prev, parser);
381 } break;
382 default: return; // Unreachable.
383 }
384 array_push(parser->nodes, node, parser->storage);
385}
386
387Node *
388parse_type(Parser *parser) {
389 Token prev = parser->previous;
390#if DEBUG == 1
391 print("parsing type ");
392 print_token(prev);
393#endif
394 Node *node = node_alloc(NODE_NODE_TYPE, prev, parser);
395 if (parse_match(parser, TOK_LCURLY)) {
396 node->value.sym = cstr("...");
397 Node *l = parse_struct_field(parser);
398 if (!l) {
399 return NULL;
400 }
401 node->vartype = l;
402 while (!parse_match(parser, TOK_RCURLY) && !parser->panic) {
403 Node *tmp = parse_struct_field(parser);
404 if (!tmp) {
405 return NULL;
406 }
407 l->vartype = tmp;
408 l = tmp;
409 }
410 return node;
411 }
412 parse_consume(parser, TOK_SYMBOL, cstr("no type given for struct field"));
413 node->value.sym = parser->previous.val;
414 return node;
415}
416
417Node *
418parse_struct_field(Parser *parser) {
419#if DEBUG == 1
420 println("parsing struct field ");
421 print_token(parser->previous);
422#endif
423 parse_consume(parser, TOK_SYMBOL, cstr("expected struct field name"));
424 parse_symbol(parser);
425 Node *field = array_pop(parser->nodes);
426 parse_consume(parser, TOK_COLON,
427 cstr("invalid type name given for struct field"));
428 field->vartype = parse_type(parser);
429 if (parse_match(parser, TOK_ASSIGN)) {
430 parse_expr(parser, PREC_LOW);
431 field->varname = array_pop(parser->nodes);
432 }
433
434 Node *list = node_alloc(NODE_NODE_LIST, parser->previous, parser);
435 list->varname = field;
436 return list;
437}
438
439void
440parse_keyword(Parser *parser) {
441 Token prev = parser->previous;
442#if DEBUG == 1
443 print("parsing keyword ");
444 print_token(prev);
445#endif
446 Node *node = NULL;
447 switch (prev.kind) {
448 case TOK_LET: {
449 parse_consume(parser, TOK_SYMBOL,
450 cstr("expected symbol name on let expression"));
451 parse_symbol(parser);
452
453 // Optional type declaration.
454 Node *type = NULL;
455 if (parse_match(parser, TOK_COLON)) {
456 type = parse_type(parser);
457 }
458
459 node = node_alloc(NODE_LET, prev, parser);
460 if (!node) {
461 return;
462 }
463
464 // Optional assignment.
465 if (parse_match(parser, TOK_ASSIGN)) {
466 parse_expr(parser, PREC_LOW);
467 node->varvalue = array_pop(parser->nodes);
468 }
469 node->varname = array_pop(parser->nodes);
470 node->varname->vartype = type;
471 } break;
472 case TOK_SET: {
473 parse_consume(parser, TOK_SYMBOL,
474 cstr("expected symbol name on set expression"));
475 parse_symbol_chain(parser);
476 parse_consume(parser, TOK_ASSIGN,
477 cstr("expected assignment on set expression"));
478 parse_expr(parser, PREC_LOW);
479 node = node_alloc(NODE_SET, prev, parser);
480 if (!node) {
481 return;
482 }
483 node->varvalue = array_pop(parser->nodes);
484 node->varname = array_pop(parser->nodes);
485 } break;
486 case TOK_STRUCT: {
487 parse_consume(parser, TOK_SYMBOL,
488 cstr("expected symbol name on struct definition"));
489 parse_symbol(parser);
490 parse_consume(parser, TOK_LCURLY,
491 cstr("expected '{' on struct definition"));
492 node = node_alloc(NODE_STRUCT, prev, parser);
493 if (!node) {
494 return;
495 }
496 node->varname = array_pop(parser->nodes);
497 Node *l = parse_struct_field(parser);
498 if (!l) {
499 return;
500 }
501 node->vartype = l;
502 while (!parse_match(parser, TOK_RCURLY) && !parser->panic) {
503 Node *tmp = parse_struct_field(parser);
504 if (!tmp) {
505 return;
506 }
507 l->vartype = tmp;
508 l = tmp;
509 }
317 } break; 510 } break;
318 default: return; // Unreachable. 511 default: return; // Unreachable.
319 } 512 }
@@ -332,36 +525,39 @@ parse_binary(Parser *parser) {
332 525
333 Node *node; 526 Node *node;
334 switch (prev.kind) { 527 switch (prev.kind) {
335 case TOK_ADD: node = node_alloc(NODE_ADD, prev, parser->storage); break; 528 case TOK_ADD: node = node_alloc(NODE_ADD, prev, parser); break;
336 case TOK_SUB: node = node_alloc(NODE_SUB, prev, parser->storage); break; 529 case TOK_SUB: node = node_alloc(NODE_SUB, prev, parser); break;
337 case TOK_MUL: node = node_alloc(NODE_MUL, prev, parser->storage); break; 530 case TOK_MUL: node = node_alloc(NODE_MUL, prev, parser); break;
338 case TOK_DIV: node = node_alloc(NODE_DIV, prev, parser->storage); break; 531 case TOK_DIV: node = node_alloc(NODE_DIV, prev, parser); break;
339 case TOK_MOD: node = node_alloc(NODE_MOD, prev, parser->storage); break; 532 case TOK_MOD: node = node_alloc(NODE_MOD, prev, parser); break;
340 case TOK_AND: node = node_alloc(NODE_AND, prev, parser->storage); break; 533 case TOK_AND: node = node_alloc(NODE_AND, prev, parser); break;
341 case TOK_OR: node = node_alloc(NODE_OR, prev, parser->storage); break; 534 case TOK_OR: node = node_alloc(NODE_OR, prev, parser); break;
342 case TOK_EQ: node = node_alloc(NODE_EQ, prev, parser->storage); break; 535 case TOK_EQ: node = node_alloc(NODE_EQ, prev, parser); break;
343 case TOK_NEQ: node = node_alloc(NODE_NEQ, prev, parser->storage); break; 536 case TOK_NEQ: node = node_alloc(NODE_NEQ, prev, parser); break;
344 case TOK_LT: node = node_alloc(NODE_LT, prev, parser->storage); break; 537 case TOK_LT: node = node_alloc(NODE_LT, prev, parser); break;
345 case TOK_GT: node = node_alloc(NODE_GT, prev, parser->storage); break; 538 case TOK_GT: node = node_alloc(NODE_GT, prev, parser); break;
346 case TOK_LE: node = node_alloc(NODE_LE, prev, parser->storage); break; 539 case TOK_LE: node = node_alloc(NODE_LE, prev, parser); break;
347 case TOK_GE: node = node_alloc(NODE_GE, prev, parser->storage); break; 540 case TOK_GE: node = node_alloc(NODE_GE, prev, parser); break;
348 case TOK_BITAND: { 541 case TOK_BITAND: {
349 node = node_alloc(NODE_BITAND, prev, parser->storage); 542 node = node_alloc(NODE_BITAND, prev, parser);
350 } break; 543 } break;
351 case TOK_BITOR: { 544 case TOK_BITOR: {
352 node = node_alloc(NODE_BITOR, prev, parser->storage); 545 node = node_alloc(NODE_BITOR, prev, parser);
353 } break; 546 } break;
354 case TOK_BITLSHIFT: { 547 case TOK_BITLSHIFT: {
355 node = node_alloc(NODE_BITLSHIFT, prev, parser->storage); 548 node = node_alloc(NODE_BITLSHIFT, prev, parser);
356 } break; 549 } break;
357 case TOK_BITRSHIFT: { 550 case TOK_BITRSHIFT: {
358 node = node_alloc(NODE_BITRSHIFT, prev, parser->storage); 551 node = node_alloc(NODE_BITRSHIFT, prev, parser);
359 } break; 552 } break;
360 default: { 553 default: {
361 parse_emit_err(parser, prev, cstr("unreachable")); 554 parse_emit_err(parser, prev, cstr("unreachable"));
362 return; 555 return;
363 } 556 }
364 } 557 }
558 if (!node) {
559 return;
560 }
365 node->right = array_pop(parser->nodes); 561 node->right = array_pop(parser->nodes);
366 node->left = array_pop(parser->nodes); 562 node->left = array_pop(parser->nodes);
367 array_push(parser->nodes, node, parser->storage); 563 array_push(parser->nodes, node, parser->storage);
@@ -379,15 +575,24 @@ parse_number(Parser *parser) {
379 case TOK_NUM_INT: { 575 case TOK_NUM_INT: {
380 if (str_has_prefix(prev.val, cstr("0x")) || 576 if (str_has_prefix(prev.val, cstr("0x")) ||
381 str_has_prefix(prev.val, cstr("0b"))) { 577 str_has_prefix(prev.val, cstr("0b"))) {
382 node = node_alloc(NODE_NUM_UINT, prev, parser->storage); 578 node = node_alloc(NODE_NUM_UINT, prev, parser);
579 if (!node) {
580 return;
581 }
383 node->value.u = str_to_uint(prev.val); 582 node->value.u = str_to_uint(prev.val);
384 } else { 583 } else {
385 node = node_alloc(NODE_NUM_INT, prev, parser->storage); 584 node = node_alloc(NODE_NUM_INT, prev, parser);
585 if (!node) {
586 return;
587 }
386 node->value.i = str_to_int(prev.val); 588 node->value.i = str_to_int(prev.val);
387 } 589 }
388 } break; 590 } break;
389 case TOK_NUM_FLOAT: { 591 case TOK_NUM_FLOAT: {
390 node = node_alloc(NODE_NUM_FLOAT, prev, parser->storage); 592 node = node_alloc(NODE_NUM_FLOAT, prev, parser);
593 if (!node) {
594 return;
595 }
391 node->value.d = str_to_float(prev.val); 596 node->value.d = str_to_float(prev.val);
392 } break; 597 } break;
393 default: break; 598 default: break;
@@ -402,7 +607,10 @@ parse_string(Parser *parser) {
402 print("parsing string "); 607 print("parsing string ");
403 print_token(prev); 608 print_token(prev);
404#endif 609#endif
405 Node *node = node_alloc(NODE_STRING, prev, parser->storage); 610 Node *node = node_alloc(NODE_STRING, prev, parser);
611 if (!node) {
612 return;
613 }
406 node->value.str = str_remove_prefix(prev.val, cstr("\"")); 614 node->value.str = str_remove_prefix(prev.val, cstr("\""));
407 node->value.str = str_remove_suffix(node->value.str, cstr("\"")); 615 node->value.str = str_remove_suffix(node->value.str, cstr("\""));
408 array_push(parser->nodes, node, parser->storage); 616 array_push(parser->nodes, node, parser->storage);
@@ -412,15 +620,39 @@ void
412parse_symbol(Parser *parser) { 620parse_symbol(Parser *parser) {
413 Token prev = parser->previous; 621 Token prev = parser->previous;
414#if DEBUG == 1 622#if DEBUG == 1
415 print("parsing string "); 623 print("parsing symbol ");
416 print_token(prev); 624 print_token(prev);
417#endif 625#endif
418 Node *node = node_alloc(NODE_STRING, prev, parser->storage); 626 Node *node = node_alloc(NODE_SYMBOL, prev, parser);
627 if (!node) {
628 return;
629 }
419 node->value.sym = prev.val; 630 node->value.sym = prev.val;
420 array_push(parser->nodes, node, parser->storage); 631 array_push(parser->nodes, node, parser->storage);
421} 632}
422 633
423void 634void
635parse_symbol_chain(Parser *parser) {
636 Token prev = parser->previous;
637#if DEBUG == 1
638 print("parsing symbol ");
639 print_token(prev);
640#endif
641 Node *node = node_alloc(NODE_SYMBOL, prev, parser);
642 if (!node) {
643 return;
644 }
645 node->value.sym = prev.val;
646 if (parse_match(parser, TOK_DOT)) {
647 parse_consume(parser, TOK_SYMBOL,
648 cstr("expected symbol after '.' operator"));
649 parse_symbol_chain(parser);
650 node->varname = array_pop(parser->nodes);
651 }
652 array_push(parser->nodes, node, parser->storage);
653}
654
655void
424parse_grouping(Parser *parser) { 656parse_grouping(Parser *parser) {
425#if DEBUG == 1 657#if DEBUG == 1
426 print("parsing group "); 658 print("parsing group ");
@@ -436,23 +668,24 @@ graph_node(Node *node) {
436 return; 668 return;
437 } 669 }
438 print("%d [width=2.5,shape=Mrecord,label=\"", node->id); 670 print("%d [width=2.5,shape=Mrecord,label=\"", node->id);
439 print("<top> %s ", node_str[node->kind]); 671 print("{ %s | { L: %d | C: %d } } ", node_str[node->kind], node->line,
672 node->col);
440 switch (node->kind) { 673 switch (node->kind) {
441 case NODE_NUM_INT: print("| Value: %d", node->value.i); break; 674 case NODE_NUM_INT: print("| Value: %d", node->value.i); break;
442 case NODE_NUM_UINT: print("| Value: %x", node->value.u); break; 675 case NODE_NUM_UINT: print("| Value: %x", node->value.u); break;
443 case NODE_NUM_FLOAT: print("| Value: %f{2}", node->value.d); break; 676 case NODE_NUM_FLOAT: print("| Value: %f{2}", node->value.d); break;
444 case NODE_STRING: print("| Value: %s", node->value.str); break; 677 case NODE_STRING: print("| Value: %s", node->value.str); break;
445 case NODE_SYMBOL: print("| Value: %s", node->value.sym); break; 678 case NODE_SYMBOL: print("| Value: %s", node->value.sym); break;
679 case NODE_NODE_TYPE: print("| Value: %s", node->value.sym); break;
446 default: break; 680 default: break;
447 } 681 }
448 print("| Line: %d | Col: %d ", node->line, node->col);
449 println("\"];"); 682 println("\"];");
450 if (node->left) { 683 if (node->left) {
451 println("%d:top:e->%d:top:w;", node->id, node->left->id); 684 println("%d:e->%d:w;", node->id, node->left->id);
452 graph_node(node->left); 685 graph_node(node->left);
453 } 686 }
454 if (node->right) { 687 if (node->right) {
455 println("%d:top:e->%d:top:w;", node->id, node->right->id); 688 println("%d:e->%d:w;", node->id, node->right->id);
456 graph_node(node->right); 689 graph_node(node->right);
457 } 690 }
458} 691}
@@ -516,7 +749,14 @@ process_file(Str path) {
516 array_init(parser.nodes, 256, parser.storage); 749 array_init(parser.nodes, 256, parser.storage);
517 parse_advance(&parser); 750 parse_advance(&parser);
518 while (parser.current.kind != TOK_EOF) { 751 while (parser.current.kind != TOK_EOF) {
752#if DEBUG == 1
753 static sz ctr = 0;
754 println("parsing root: %d", ctr++);
755#endif
519 parse_expr(&parser, PREC_LOW); 756 parse_expr(&parser, PREC_LOW);
757 if (parser.panic) {
758 break;
759 }
520 } 760 }
521 if (parser.err) { 761 if (parser.err) {
522 goto stop; 762 goto stop;
diff --git a/tests/arithmetic_expected.txt b/tests/arithmetic_expected.txt
deleted file mode 100644
index a2a5a83..0000000
--- a/tests/arithmetic_expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
1(+ 10 100) -> 110
2(+ 1 -2 3 4) -> 6
3(- 100 75) -> 25
4(- 10 20 30) -> -40
5(* 10 7) -> 70
6(* -1 66) -> -66
7(/ 45 5) -> 9
8(/ 10 5 2) -> 1
9(% 45 5) -> 0
10(% 45 7) -> 3
11(% 120 45) -> 30
12(% 120 45 8) -> 6
13(* 20 (+ 100 (- 50 30) (/ 300 3)) 10) -> 44000
diff --git a/tests/booleans_expected.txt b/tests/booleans_expected.txt
deleted file mode 100644
index 43f67e5..0000000
--- a/tests/booleans_expected.txt
+++ /dev/null
@@ -1,53 +0,0 @@
1(not true) -> false
2(not false) -> true
3(not (not true)) -> true
4(not (not false)) -> false
5(not 1) -> false
6(not (not 1)) -> true
7(not "string") -> false
8(not (not "string")) -> true
9(and 1 "string" 4 true) -> true
10(and true true true) -> true
11(and (+ 1 2 3)) -> true
12(and false false false) -> false
13(and true false false) -> false
14(and false true false) -> false
15(and false true true) -> false
16(and (not false) true true) -> true
17(or 1 "string" 4 true) -> true
18(or false 1) -> true
19(or false "string") -> true
20(or false) -> false
21(or true true true) -> true
22(or false false false) -> false
23(or true false false) -> true
24(or false true false) -> true
25(or false true true) -> true
26(or (not false) true true) -> true
27(or (not true) false) -> false
28(if true true false) -> true
29(if false true false) -> false
30(if true (+ 1 2 3) 0) -> 6
31(if false (+ 1 2 3) 0) -> 0
32(if (or true false) (+ 1 2 3) (+ 7 8 9)) -> 6
33(if (or false false) (+ 1 2 3) (+ 7 8 9)) -> 24
34(if (or (+ 1 2 3) false) (+ 1 2 3) (+ 7 8 9)) -> 6
35(if true 7) -> 7
36(if false 7) ->
37(cond ((and true true true) 1) ((or true true false) 2) (else 3)) -> 1
38(cond ((and true true false) 1) ((or true true false) 2) (else 3)) -> 2
39(cond ((and true true false) 1) ((or false false false) 2) (else 3)) -> 3
40(cond ((and true true true) 1) ((or true true false) 2)) ->
41(cond ((and true true true) (+ 1 2 3)) ((or true true false) 2) (else 3)) -> 6
42(< 1 2 3) -> true
43(< 3 2 1) -> false
44(> 1 2 3) -> false
45(> 3 2 1) -> true
46(= 1 2 3) -> false
47(= 3 2 1) -> false
48(= 3 3 3) -> true
49(= (+ 1 2) 3 (- 6 3)) -> true
50(< 1 1 3) -> false
51(<= 1 1 3) -> true
52(> 3 3 1) -> false
53(>= 3 3 1) -> true
diff --git a/tests/constants/numbers.bdl b/tests/constants/numbers.bdl
deleted file mode 100644
index 136b5fb..0000000
--- a/tests/constants/numbers.bdl
+++ /dev/null
@@ -1,41 +0,0 @@
1; Signed integers.
2(print 1:s8)
3(print 52:s8)
4(print -1:s8)
5(print 0:s8)
6(print 1:s16)
7(print 52:s16)
8(print -1:s16)
9(print 0:s16)
10(print 1:s32)
11(print 52:s32)
12(print -1:s32)
13(print 0:s32)
14(print 1:s64)
15(print 52:s64)
16(print -1:s64)
17(print 0:s64)
18
19; Unsigned integers.
20(print 1:u8)
21(print 52:u8)
22(print -1:u8)
23(print 0:u8)
24(print 1:u16)
25(print 52:u16)
26(print -1:u16)
27(print 0:u16)
28(print 1:u32)
29(print 52:u32)
30(print -1:u32)
31(print 0:u32)
32(print 1:u64)
33(print 52:u64)
34(print -1:u64)
35(print 0:u64)
36
37; Type inference.
38(print 1)
39(print 52)
40(print -1)
41(print 0)
diff --git a/tests/constants/strings.bdl b/tests/constants/strings.bdl
deleted file mode 100644
index 9b1d687..0000000
--- a/tests/constants/strings.bdl
+++ /dev/null
@@ -1,5 +0,0 @@
1(print "abc")
2(print "test this longer string")
3(print "escape\na\nnewline")
4(print "escape\ttab\tcharacters")
5(print "with type :str":str)
diff --git a/tests/lists_expected.txt b/tests/lists_expected.txt
deleted file mode 100644
index 6ddb71b..0000000
--- a/tests/lists_expected.txt
+++ /dev/null
@@ -1,15 +0,0 @@
1(list) ->
2(list 1) -> (1)
3(list 1 2) -> (1 2)
4(list 1 2 3) -> (1 2 3)
5(list 4 5 (+ 1 2 3)) -> (4 5 6)
6(car (list 1 2 3)) -> 1
7(cdr (list 1 2 3)) -> (2 3)
8(car (list (* 10 20) (+ 1 2 3) 50 60)) -> 200
9(cdr (list (* 10 20) (+ 1 2 3) 50 60)) -> (6 50 60)
10(car (cdr (list (* 10 20) (+ 1 2 3) 50 60))) -> 6
11(cons 1 2) -> (1 . 2)
12(cons "a" "b") -> ("a" . "b")
13(cons "a" (cons "c" ())) -> ("a" "c")
14(cons 1 (cons 2 (cons (+ 1 2) ()))) -> (1 2 3)
15(cons 1 (cons 2 (cons (+ 1 2) 4))) -> (1 2 3 . 4)
diff --git a/tests/types_expected.txt b/tests/types_expected.txt
deleted file mode 100644
index 58eaa7f..0000000
--- a/tests/types_expected.txt
+++ /dev/null
@@ -1,55 +0,0 @@
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(nil? true) -> false
9(nil? false) -> false
10(nil? 1) -> false
11(nil? 5) -> false
12(nil? "string") -> false
13(nil? (+ 1 2 3)) -> false
14(nil? (not 1)) -> false
15(nil? ()) -> true
16(string? true) -> false
17(string? false) -> false
18(string? 1) -> false
19(string? 5) -> false
20(string? "string") -> true
21(string? (+ 1 2 3)) -> false
22(string? (not 1)) -> false
23(fixnum? true) -> false
24(fixnum? false) -> false
25(fixnum? 1) -> true
26(fixnum? 5) -> true
27(fixnum? "string") -> false
28(fixnum? (+ 1 2 3)) -> true
29(fixnum? (not 1)) -> false
30(symbol? true) -> false
31(symbol? false) -> false
32(symbol? 1) -> false
33(symbol? +) -> false
34(symbol? "string") -> false
35(symbol? (+ 1 2 3)) -> false
36(symbol? (not 1)) -> false
37(symbol? 'a) -> true
38(symbol? 'c) -> true
39(pair? false) -> false
40(pair? 1) -> false
41(pair? 5) -> false
42(pair? "string") -> false
43(pair? (+ 1 2 3)) -> false
44(pair? (not 1)) -> false
45(pair? (cons 1 2)) -> true
46(pair? (list 1 2 3)) -> true
47(procedure? false) -> false
48(procedure? 1) -> false
49(procedure? 5) -> false
50(procedure? "string") -> false
51(procedure? (+ 1 2 3)) -> false
52(procedure? (not 1)) -> false
53(procedure? +) -> true
54(procedure? -) -> true
55(procedure? procedure?) -> true
diff --git a/tests/variables.bad b/tests/variables.bad
new file mode 100644
index 0000000..a6f9900
--- /dev/null
+++ b/tests/variables.bad
@@ -0,0 +1,57 @@
1; Basic variable declaration with and without default values. The type could be
2; inferred, but can also be manually specified.
3let a
4let b: f64
5let c = 10
6let d:u64 = 20
7
8; No infix '=', instead we use `set` to bind values.
9set a = "hello"
10set b = 1.2
11set c = 30
12set d = (1 + 2 - 3)
13
14; Struct definitions.
15struct vec {
16 x: f32
17 y: f32
18 z: f32
19}
20
21; Default values are allowed, including const expressions.
22struct person {
23 name: str = "joe"
24 age: int = 18 * 2
25}
26
27; We can use the dot operator to access fields.
28let player_a: person
29set player_a.name = "alex"
30set player_a.age = 32
31let player_b = player_a
32
33; Anonymous structs can also be declared inline.
34let user: { id: u64 name: str }
35set user.id = 10
36set user.name = "haxor"
37
38; We can have anonymous struct fields.
39struct entity {
40 pos: vec
41 vel: vec
42 attr: {
43 id: u64
44 name: str
45 }
46}
47
48; Symbols followed by curly braces output struct literals.
49; let particle = entity {
50; ; Two ways of initializing inner fields.
51; pos = { 1 2 }
52; attr.id = 1
53; attr.name = "particle"
54
55; ; Missing initialization fields default to zero.
56; vel = { -3 }
57; }
diff --git a/tests/variables_expected.txt b/tests/variables_expected.txt
deleted file mode 100644
index 02a5f7a..0000000
--- a/tests/variables_expected.txt
+++ /dev/null
@@ -1,23 +0,0 @@
1(def a 20)
2((lambda (a b) (+ 10 a b)) 1 2) -> 13
3((lambda (a b) (+ 10 a b)) a 3) -> 33
4(def myfun (lambda (a b) (+ a b))) (myfun 6 9) -> 15
5(fun myfun (a b) (+ a b)) (myfun 6 9) -> 15
6(+ 1 (myfun 10 (myfun a a)) 30) -> 81
7(myfun 10 (myfun 5 0)) -> 15
8(fun make-counter () (def value 0) (def counter (lambda () (set! value (+ value 1)) value)) counter)
9(def counter-a (make-counter))
10(def counter-b (make-counter))
11(counter-a) -> 1
12(counter-b) -> 1
13(counter-a) -> 2
14(counter-a) -> 3
15(counter-a) -> 4
16(counter-b) -> 2
17(counter-b) -> 3
18(counter-b) -> 4
19(fun fib (n) (if (<= n 2) 1 (+ (fib (- n 1)) (fib (- n 2)))))
20(fib 15) -> 610
21(fun b () (display a) (print " --- ") (def a 42) (display a) (newline))
22(b) -> 20 --- 42
23(b) -> 20 --- 42