diff options
-rwxr-xr-x | src/bytecode/compiler.h | 88 | ||||
-rwxr-xr-x | src/bytecode/lexer.c | 16 | ||||
-rwxr-xr-x | src/bytecode/lexer.h | 8 | ||||
-rwxr-xr-x | src/bytecode/ops.h | 8 | ||||
-rwxr-xr-x | src/bytecode/vm.h | 43 |
5 files changed, 137 insertions, 26 deletions
diff --git a/src/bytecode/compiler.h b/src/bytecode/compiler.h index fd5cdbc..6f43416 100755 --- a/src/bytecode/compiler.h +++ b/src/bytecode/compiler.h | |||
@@ -58,7 +58,7 @@ parse_fixnum(Chunk *chunk, Token tok) { | |||
58 | void parse_tree(Chunk *chunk, Visitor *vs); | 58 | void parse_tree(Chunk *chunk, Visitor *vs); |
59 | 59 | ||
60 | void | 60 | void |
61 | compile_list_op(Chunk *chunk, Visitor *vs, Token list_start, Ops op) { | 61 | compile_list_binary_op(Chunk *chunk, Visitor *vs, Token list_start, Ops op) { |
62 | size_t n = 0; | 62 | size_t n = 0; |
63 | while (has_next_token(vs)) { | 63 | while (has_next_token(vs)) { |
64 | Token tok = peek_token(vs); | 64 | Token tok = peek_token(vs); |
@@ -73,7 +73,15 @@ compile_list_op(Chunk *chunk, Visitor *vs, Token list_start, Ops op) { | |||
73 | } | 73 | } |
74 | if (tok.type == TOKEN_RPAREN) { | 74 | if (tok.type == TOKEN_RPAREN) { |
75 | next_token(vs); | 75 | next_token(vs); |
76 | break; | 76 | if (n <= 1) { |
77 | error_push((Error){ | ||
78 | .type = ERR_TYPE_COMPILER, | ||
79 | .value = ERR_NOT_ENOUGH_ARGS, | ||
80 | .line = list_start.line, | ||
81 | .col = list_start.column, | ||
82 | }); | ||
83 | } | ||
84 | return; | ||
77 | } | 85 | } |
78 | parse_tree(chunk, vs); | 86 | parse_tree(chunk, vs); |
79 | n++; | 87 | n++; |
@@ -81,14 +89,58 @@ compile_list_op(Chunk *chunk, Visitor *vs, Token list_start, Ops op) { | |||
81 | add_code(chunk, op, list_start.line, list_start.column); | 89 | add_code(chunk, op, list_start.line, list_start.column); |
82 | } | 90 | } |
83 | } | 91 | } |
84 | if (n == 0) { | 92 | error_push((Error){ |
85 | error_push((Error){ | 93 | .type = ERR_TYPE_COMPILER, |
86 | .type = ERR_TYPE_COMPILER, | 94 | .value = ERR_NOT_ENOUGH_ARGS, |
87 | .value = ERR_NOT_ENOUGH_ARGS, | 95 | .line = list_start.line, |
88 | .line = list_start.line, | 96 | .col = list_start.column, |
89 | .col = list_start.column, | 97 | }); |
90 | }); | 98 | } |
99 | |||
100 | void | ||
101 | compile_list_unary_op(Chunk *chunk, Visitor *vs, Token list_start, Ops op) { | ||
102 | size_t n = 0; | ||
103 | while (has_next_token(vs)) { | ||
104 | Token tok = peek_token(vs); | ||
105 | if (tok.type == TOKEN_EOF) { | ||
106 | error_push((Error){ | ||
107 | .type = ERR_TYPE_COMPILER, | ||
108 | .value = ERR_UNBALANCED_PAREN, | ||
109 | .line = list_start.line, | ||
110 | .col = list_start.column, | ||
111 | }); | ||
112 | return; | ||
113 | } | ||
114 | if (tok.type == TOKEN_RPAREN) { | ||
115 | next_token(vs); | ||
116 | if (n == 0) { | ||
117 | error_push((Error){ | ||
118 | .type = ERR_TYPE_COMPILER, | ||
119 | .value = ERR_NOT_ENOUGH_ARGS, | ||
120 | .line = list_start.line, | ||
121 | .col = list_start.column, | ||
122 | }); | ||
123 | } | ||
124 | return; | ||
125 | } | ||
126 | parse_tree(chunk, vs); | ||
127 | add_code(chunk, op, list_start.line, list_start.column); | ||
128 | n++; | ||
129 | if (n > 1) { | ||
130 | error_push((Error){ | ||
131 | .type = ERR_TYPE_COMPILER, | ||
132 | .value = ERR_TOO_MANY_ARGS, | ||
133 | .line = list_start.line, | ||
134 | .col = list_start.column, | ||
135 | }); | ||
136 | } | ||
91 | } | 137 | } |
138 | error_push((Error){ | ||
139 | .type = ERR_TYPE_COMPILER, | ||
140 | .value = ERR_UNBALANCED_PAREN, | ||
141 | .line = list_start.line, | ||
142 | .col = list_start.column, | ||
143 | }); | ||
92 | } | 144 | } |
93 | 145 | ||
94 | void | 146 | void |
@@ -103,11 +155,19 @@ parse_list(Chunk *chunk, Visitor *vs, Token list_start) { | |||
103 | } | 155 | } |
104 | Token tok = next_token(vs); | 156 | Token tok = next_token(vs); |
105 | switch (tok.type) { | 157 | switch (tok.type) { |
106 | case TOKEN_ADD: { compile_list_op(chunk, vs, list_start, OP_SUM); } break; | 158 | case TOKEN_ADD: { compile_list_binary_op(chunk, vs, list_start, OP_SUM); } break; |
107 | case TOKEN_SUB: { compile_list_op(chunk, vs, list_start, OP_SUB); } break; | 159 | case TOKEN_SUB: { compile_list_binary_op(chunk, vs, list_start, OP_SUB); } break; |
108 | case TOKEN_MUL: { compile_list_op(chunk, vs, list_start, OP_MUL); } break; | 160 | case TOKEN_MUL: { compile_list_binary_op(chunk, vs, list_start, OP_MUL); } break; |
109 | case TOKEN_DIV: { compile_list_op(chunk, vs, list_start, OP_DIV); } break; | 161 | case TOKEN_DIV: { compile_list_binary_op(chunk, vs, list_start, OP_DIV); } break; |
110 | case TOKEN_MOD: { compile_list_op(chunk, vs, list_start, OP_MOD); } break; | 162 | case TOKEN_MOD: { compile_list_binary_op(chunk, vs, list_start, OP_MOD); } break; |
163 | case TOKEN_NOT: { compile_list_unary_op(chunk, vs, list_start, OP_NOT); } break; | ||
164 | case TOKEN_AND: { compile_list_binary_op(chunk, vs, list_start, OP_AND); } break; | ||
165 | case TOKEN_OR: { compile_list_binary_op(chunk, vs, list_start, OP_OR); } break; | ||
166 | case TOKEN_EQUAL: { compile_list_binary_op(chunk, vs, list_start, OP_EQUAL); } break; | ||
167 | case TOKEN_LESS: { compile_list_binary_op(chunk, vs, list_start, OP_LESS); } break; | ||
168 | case TOKEN_GREATER: { compile_list_binary_op(chunk, vs, list_start, OP_GREATER); } break; | ||
169 | case TOKEN_LESS_EQUAL: { compile_list_binary_op(chunk, vs, list_start, OP_LESS_EQUAL); } break; | ||
170 | case TOKEN_GREATER_EQUAL: { compile_list_binary_op(chunk, vs, list_start, OP_GREATER_EQUAL); } break; | ||
111 | default: { | 171 | default: { |
112 | error_push((Error){ | 172 | error_push((Error){ |
113 | .type = ERR_TYPE_COMPILER, | 173 | .type = ERR_TYPE_COMPILER, |
diff --git a/src/bytecode/lexer.c b/src/bytecode/lexer.c index bc2dd9d..207cebb 100755 --- a/src/bytecode/lexer.c +++ b/src/bytecode/lexer.c | |||
@@ -25,10 +25,10 @@ static const char* token_str[] = { | |||
25 | [TOKEN_AND] = "TOKEN_AND", | 25 | [TOKEN_AND] = "TOKEN_AND", |
26 | [TOKEN_OR] = "TOKEN_OR", | 26 | [TOKEN_OR] = "TOKEN_OR", |
27 | [TOKEN_EQUAL] = "TOKEN_EQUAL", | 27 | [TOKEN_EQUAL] = "TOKEN_EQUAL", |
28 | [TOKEN_LESS_THAN] = "TOKEN_LESS_THAN", | 28 | [TOKEN_LESS] = "TOKEN_LESS", |
29 | [TOKEN_GREATER_THAN] = "TOKEN_GREATER_THAN", | 29 | [TOKEN_GREATER] = "TOKEN_GREATER", |
30 | [TOKEN_LESS_EQUAL_THAN] = "TOKEN_LESS_EQUAL_THAN", | 30 | [TOKEN_LESS_EQUAL] = "TOKEN_LESS_EQUAL", |
31 | [TOKEN_GREATER_EQUAL_THAN] = "TOKEN_GREATER_EQUAL_THAN", | 31 | [TOKEN_GREATER_EQUAL] = "TOKEN_GREATER_EQUAL", |
32 | [TOKEN_EOF] = "TOKEN_EOF", | 32 | [TOKEN_EOF] = "TOKEN_EOF", |
33 | }; | 33 | }; |
34 | 34 | ||
@@ -155,10 +155,10 @@ find_primitive_type(const StringView value) { | |||
155 | if (TOKEN_IS_KEYWORD(value, "and")) { return TOKEN_AND; } | 155 | if (TOKEN_IS_KEYWORD(value, "and")) { return TOKEN_AND; } |
156 | if (TOKEN_IS_KEYWORD(value, "or")) { return TOKEN_OR; } | 156 | if (TOKEN_IS_KEYWORD(value, "or")) { return TOKEN_OR; } |
157 | if (TOKEN_IS_KEYWORD(value, "=")) { return TOKEN_EQUAL; } | 157 | if (TOKEN_IS_KEYWORD(value, "=")) { return TOKEN_EQUAL; } |
158 | if (TOKEN_IS_KEYWORD(value, "<")) { return TOKEN_LESS_THAN; } | 158 | if (TOKEN_IS_KEYWORD(value, "<")) { return TOKEN_LESS; } |
159 | if (TOKEN_IS_KEYWORD(value, ">")) { return TOKEN_GREATER_THAN; } | 159 | if (TOKEN_IS_KEYWORD(value, ">")) { return TOKEN_GREATER; } |
160 | if (TOKEN_IS_KEYWORD(value, "<=")) { return TOKEN_LESS_EQUAL_THAN; } | 160 | if (TOKEN_IS_KEYWORD(value, "<=")) { return TOKEN_LESS_EQUAL; } |
161 | if (TOKEN_IS_KEYWORD(value, ">=")) { return TOKEN_GREATER_EQUAL_THAN; } | 161 | if (TOKEN_IS_KEYWORD(value, ">=")) { return TOKEN_GREATER_EQUAL; } |
162 | 162 | ||
163 | return TOKEN_SYMBOL; | 163 | return TOKEN_SYMBOL; |
164 | } | 164 | } |
diff --git a/src/bytecode/lexer.h b/src/bytecode/lexer.h index 47fd384..cee2915 100755 --- a/src/bytecode/lexer.h +++ b/src/bytecode/lexer.h | |||
@@ -38,10 +38,10 @@ typedef enum TokenType { | |||
38 | TOKEN_AND, | 38 | TOKEN_AND, |
39 | TOKEN_OR, | 39 | TOKEN_OR, |
40 | TOKEN_EQUAL, | 40 | TOKEN_EQUAL, |
41 | TOKEN_LESS_THAN, | 41 | TOKEN_LESS, |
42 | TOKEN_GREATER_THAN, | 42 | TOKEN_GREATER, |
43 | TOKEN_LESS_EQUAL_THAN, | 43 | TOKEN_LESS_EQUAL, |
44 | TOKEN_GREATER_EQUAL_THAN, | 44 | TOKEN_GREATER_EQUAL, |
45 | 45 | ||
46 | TOKEN_EOF, | 46 | TOKEN_EOF, |
47 | } TokenType; | 47 | } TokenType; |
diff --git a/src/bytecode/ops.h b/src/bytecode/ops.h index b58631f..b59d65a 100755 --- a/src/bytecode/ops.h +++ b/src/bytecode/ops.h | |||
@@ -8,6 +8,14 @@ typedef enum Ops { | |||
8 | OP_MUL, | 8 | OP_MUL, |
9 | OP_DIV, | 9 | OP_DIV, |
10 | OP_MOD, | 10 | OP_MOD, |
11 | OP_NOT, | ||
12 | OP_AND, | ||
13 | OP_OR, | ||
14 | OP_EQUAL, | ||
15 | OP_LESS, | ||
16 | OP_GREATER, | ||
17 | OP_LESS_EQUAL, | ||
18 | OP_GREATER_EQUAL, | ||
11 | OP_RETURN, | 19 | OP_RETURN, |
12 | } Ops; | 20 | } Ops; |
13 | 21 | ||
diff --git a/src/bytecode/vm.h b/src/bytecode/vm.h index 9b68fc1..c94e22b 100755 --- a/src/bytecode/vm.h +++ b/src/bytecode/vm.h | |||
@@ -59,6 +59,35 @@ vm_reset(VM *vm) { | |||
59 | array_push(vm->stack, FIXNUM_VAL(y OP x)); \ | 59 | array_push(vm->stack, FIXNUM_VAL(y OP x)); \ |
60 | } while (false) | 60 | } while (false) |
61 | 61 | ||
62 | #define FIXNUM_CMP_OP(OP) \ | ||
63 | do { \ | ||
64 | Object a = array_pop(vm->stack); \ | ||
65 | Object b = array_pop(vm->stack); \ | ||
66 | if (!IS_FIXNUM(a) || !IS_FIXNUM(b)) { \ | ||
67 | error_push((Error){ \ | ||
68 | .type = ERR_TYPE_RUNTIME, \ | ||
69 | .value = ERR_WRONG_ARG_TYPE, \ | ||
70 | .line = vm->chunk->lines[vm->pc - vm->chunk->code - 1].line, \ | ||
71 | .col = vm->chunk->lines[vm->pc - vm->chunk->code - 1].col, \ | ||
72 | }); \ | ||
73 | return; \ | ||
74 | } \ | ||
75 | ssize_t x = AS_FIXNUM(a); \ | ||
76 | ssize_t y = AS_FIXNUM(b); \ | ||
77 | Object result = y OP x ? TRUE_VAL : FALSE_VAL; \ | ||
78 | array_push(vm->stack, result); \ | ||
79 | } while (false) | ||
80 | |||
81 | #define LOGIC_OP(OP) \ | ||
82 | do { \ | ||
83 | Object a = array_pop(vm->stack); \ | ||
84 | Object b = array_pop(vm->stack); \ | ||
85 | bool x = IS_TRUE(a); \ | ||
86 | bool y = IS_TRUE(b); \ | ||
87 | Object result = y OP x ? TRUE_VAL : FALSE_VAL; \ | ||
88 | array_push(vm->stack, result); \ | ||
89 | } while (false) | ||
90 | |||
62 | void | 91 | void |
63 | vm_interpret(VM *vm, Chunk *chunk) { | 92 | vm_interpret(VM *vm, Chunk *chunk) { |
64 | vm->chunk = chunk; | 93 | vm->chunk = chunk; |
@@ -97,6 +126,18 @@ vm_interpret(VM *vm, Chunk *chunk) { | |||
97 | case OP_MUL: { FIXNUM_BINARY_OP(*); } break; | 126 | case OP_MUL: { FIXNUM_BINARY_OP(*); } break; |
98 | case OP_DIV: { FIXNUM_BINARY_OP(/); } break; | 127 | case OP_DIV: { FIXNUM_BINARY_OP(/); } break; |
99 | case OP_MOD: { FIXNUM_BINARY_OP(%); } break; | 128 | case OP_MOD: { FIXNUM_BINARY_OP(%); } break; |
129 | case OP_NOT: { | ||
130 | Object prev = array_pop(vm->stack); | ||
131 | Object new = IS_TRUE(prev) ? FALSE_VAL : TRUE_VAL; | ||
132 | array_push(vm->stack, new); | ||
133 | } break; | ||
134 | case OP_AND: { LOGIC_OP(&&); } break; | ||
135 | case OP_OR: { LOGIC_OP(||); } break; | ||
136 | case OP_EQUAL: { FIXNUM_CMP_OP(==); } break; | ||
137 | case OP_LESS: { FIXNUM_CMP_OP(<); } break; | ||
138 | case OP_GREATER: { FIXNUM_CMP_OP(>); } break; | ||
139 | case OP_LESS_EQUAL: { FIXNUM_CMP_OP(<=); } break; | ||
140 | case OP_GREATER_EQUAL: { FIXNUM_CMP_OP(>=); } break; | ||
100 | case OP_RETURN: { | 141 | case OP_RETURN: { |
101 | display(array_pop(vm->stack)); | 142 | display(array_pop(vm->stack)); |
102 | printf("\n"); | 143 | printf("\n"); |
@@ -123,5 +164,7 @@ vm_interpret(VM *vm, Chunk *chunk) { | |||
123 | } | 164 | } |
124 | 165 | ||
125 | #undef FIXNUM_BINARY_OP | 166 | #undef FIXNUM_BINARY_OP |
167 | #undef FIXNUM_CMP_OP | ||
168 | #undef LOGIC_OP | ||
126 | 169 | ||
127 | #endif // BDL_VM_H | 170 | #endif // BDL_VM_H |