aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-10-27 10:43:30 +0200
committerBad Diode <bd@badd10de.dev>2021-10-27 10:43:30 +0200
commitf0cd7a3cab56a6f8d7b4520aaa168a271a94d6d4 (patch)
tree70a5e81b14f0fe65c959d675909ee3aa471f8354
parent6eed0aa02c657ae97e18280a6dd9d74c84fd91d4 (diff)
downloadbdl-f0cd7a3cab56a6f8d7b4520aaa168a271a94d6d4.tar.gz
bdl-f0cd7a3cab56a6f8d7b4520aaa168a271a94d6d4.zip
Add initial implementation of locals
-rw-r--r--src/bytecode/chunk.c2
-rwxr-xr-xsrc/bytecode/chunk.h4
-rwxr-xr-xsrc/bytecode/compiler.h48
-rwxr-xr-xsrc/bytecode/debug.h8
-rwxr-xr-xsrc/bytecode/errors.c1
-rwxr-xr-xsrc/bytecode/errors.h1
-rw-r--r--src/bytecode/hashtable.h1
-rwxr-xr-xsrc/bytecode/ops.h2
-rwxr-xr-xsrc/bytecode/string_view.h2
-rwxr-xr-xsrc/bytecode/vm.h24
10 files changed, 77 insertions, 16 deletions
diff --git a/src/bytecode/chunk.c b/src/bytecode/chunk.c
index e566e78..71562fa 100644
--- a/src/bytecode/chunk.c
+++ b/src/bytecode/chunk.c
@@ -10,6 +10,7 @@ chunk_init(StringView name) {
10 array_init(chunk->name, name.n); 10 array_init(chunk->name, name.n);
11 array_insert(chunk->name, name.start, name.n); 11 array_insert(chunk->name, name.start, name.n);
12 array_init(chunk->params, 0); 12 array_init(chunk->params, 0);
13 array_init(chunk->locals, 0);
13 return chunk; 14 return chunk;
14} 15}
15 16
@@ -24,6 +25,7 @@ chunk_free(Chunk *chunk) {
24 array_free(chunk->lines); 25 array_free(chunk->lines);
25 array_free(chunk->name); 26 array_free(chunk->name);
26 array_free(chunk->params); 27 array_free(chunk->params);
28 array_free(chunk->locals);
27 free(chunk); 29 free(chunk);
28} 30}
29 31
diff --git a/src/bytecode/chunk.h b/src/bytecode/chunk.h
index a3e02d1..c584d4a 100755
--- a/src/bytecode/chunk.h
+++ b/src/bytecode/chunk.h
@@ -22,9 +22,11 @@ typedef struct Chunk {
22 char *name; 22 char *name;
23 // Parameters 23 // Parameters
24 StringView *params; 24 StringView *params;
25 // Locals.
26 StringView *locals;
25} Chunk; 27} Chunk;
26 28
27#define NEW_CHUNK(NAME) chunk_init((StringView){(NAME), sizeof(NAME)}) 29#define NEW_CHUNK(NAME) chunk_init((StringView){(NAME), sizeof(NAME) - 1})
28 30
29Chunk * chunk_init(StringView name); 31Chunk * chunk_init(StringView name);
30void add_code(Chunk *chunk, u8 byte, size_t line, size_t col); 32void add_code(Chunk *chunk, u8 byte, size_t line, size_t col);
diff --git a/src/bytecode/compiler.h b/src/bytecode/compiler.h
index 6a17beb..7497ea7 100755
--- a/src/bytecode/compiler.h
+++ b/src/bytecode/compiler.h
@@ -34,8 +34,8 @@ has_next_token(const Compiler *compiler) {
34ssize_t 34ssize_t
35find_local_index(Chunk *chunk, Token tok) { 35find_local_index(Chunk *chunk, Token tok) {
36 // NOTE: This is dumb and potentially slow. 36 // NOTE: This is dumb and potentially slow.
37 for (size_t i = 0; i < array_size(chunk->params); i++) { 37 for (size_t i = 0; i < array_size(chunk->locals); i++) {
38 if (sv_equal(&tok.value, &chunk->params[i])) { 38 if (sv_equal(&tok.value, &chunk->locals[i])) {
39 return i; 39 return i;
40 } 40 }
41 } 41 }
@@ -203,9 +203,11 @@ compile_list_simple_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) {
203 }); 203 });
204} 204}
205 205
206#define STR_ARRAY(ARR) (StringView){(ARR), array_size(ARR)}
207
206void 208void
207compile_declare_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) { 209compile_declare_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) {
208 Token name = peek_token(compiler); 210 Token name = next_token(compiler);
209 if (name.type != TOKEN_SYMBOL) { 211 if (name.type != TOKEN_SYMBOL) {
210 error_push((Error){ 212 error_push((Error){
211 .type = ERR_TYPE_COMPILER, 213 .type = ERR_TYPE_COMPILER,
@@ -215,9 +217,29 @@ compile_declare_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) {
215 }); 217 });
216 return; 218 return;
217 } 219 }
218 Object obj = make_symbol(name.value); 220 // TODO: If we are inside a function and we are using OP_DEF, we just
219 emit_constant(chunk, name, obj); 221 // declare the local variable directly in the stack. No need for symbols!
220 next_token(compiler); 222 // TODO: If we are inside a function and we are using OP_SET, check if the
223 // local variable has been defined before, if not try to read from the
224 // globals for setting.
225 if (sv_equal(&STRING(""), &STR_ARRAY(chunk->name))) {
226 Object obj = make_symbol(name.value);
227 emit_constant(chunk, name, obj);
228 } else {
229 // TODO: only do this if we are defining! not setting.
230 // Check if we already have the local
231 ssize_t idx = find_local_index(chunk, name);
232 if (idx < 0) {
233 array_push(chunk->locals, name.value);
234 idx = array_size(chunk->locals) - 1;
235 }
236 if (op == OP_DEF) {
237 op = OP_DEF_LOCAL;
238 } else if (op == OP_SET) {
239 op = OP_SET_LOCAL;
240 }
241 emit_constant(chunk, name, FIXNUM_VAL(idx));
242 }
221 243
222 Token tok = peek_token(compiler); 244 Token tok = peek_token(compiler);
223 if (name.type == TOKEN_EOF || tok.type == TOKEN_EOF) { 245 if (name.type == TOKEN_EOF || tok.type == TOKEN_EOF) {
@@ -282,7 +304,19 @@ compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) {
282 }); 304 });
283 return; 305 return;
284 } 306 }
307 // Check if parameters name already exists.
308 ssize_t idx = find_local_index(fun.chunk, tok);
309 if (idx >= 0) {
310 error_push((Error){
311 .type = ERR_TYPE_COMPILER,
312 .value = ERR_AMBIGUOUS_PARAMS,
313 .line = tok.line,
314 .col = tok.column,
315 });
316 return;
317 }
285 array_push(fun.chunk->params, tok.value); 318 array_push(fun.chunk->params, tok.value);
319 array_push(fun.chunk->locals, tok.value);
286 } 320 }
287 } else if (tok.type != TOKEN_NIL) { 321 } else if (tok.type != TOKEN_NIL) {
288 error_push((Error){ 322 error_push((Error){
@@ -549,7 +583,7 @@ parse_tree(Chunk *chunk, Compiler *compiler) {
549Chunk * 583Chunk *
550compile(Token *tokens) { 584compile(Token *tokens) {
551 Chunk *chunk = NULL; 585 Chunk *chunk = NULL;
552 chunk = NEW_CHUNK("main"); 586 chunk = NEW_CHUNK("");
553 Compiler compiler = (Compiler){ 587 Compiler compiler = (Compiler){
554 .tokens = tokens, 588 .tokens = tokens,
555 .current = 0, 589 .current = 0,
diff --git a/src/bytecode/debug.h b/src/bytecode/debug.h
index 06d48b0..54d2cdb 100755
--- a/src/bytecode/debug.h
+++ b/src/bytecode/debug.h
@@ -11,6 +11,8 @@ static const char* ops_str[] = {
11 // Load/store ops. 11 // Load/store ops.
12 [OP_CONSTANT] = "OP_CONSTANT", 12 [OP_CONSTANT] = "OP_CONSTANT",
13 [OP_LOCAL] = "OP_LOCAL", 13 [OP_LOCAL] = "OP_LOCAL",
14 [OP_DEF_LOCAL] = "OP_DEF_LOCAL",
15 [OP_SET_LOCAL] = "OP_SET_LOCAL",
14 [OP_DEF] = "OP_DEF", 16 [OP_DEF] = "OP_DEF",
15 [OP_SET] = "OP_SET", 17 [OP_SET] = "OP_SET",
16 [OP_GET] = "OP_GET", 18 [OP_GET] = "OP_GET",
@@ -46,7 +48,11 @@ static const char* ops_str[] = {
46 48
47void 49void
48disassemble_chunk(Chunk *chunk) { 50disassemble_chunk(Chunk *chunk) {
49 printf("===== %.*s =====\n", (int)array_size(chunk->name), chunk->name); 51 if (array_size(chunk->name) < 1) {
52 printf("===== main =====\n");
53 } else {
54 printf("===== %.*s =====\n", (int)array_size(chunk->name), chunk->name);
55 }
50 printf("code:\n"); 56 printf("code:\n");
51 size_t offset = 0; 57 size_t offset = 0;
52 while (offset < array_size(chunk->code)) { 58 while (offset < array_size(chunk->code)) {
diff --git a/src/bytecode/errors.c b/src/bytecode/errors.c
index b4595a1..b2aab93 100755
--- a/src/bytecode/errors.c
+++ b/src/bytecode/errors.c
@@ -17,6 +17,7 @@ static const char* error_msgs[] = {
17 [ERR_DIVISION_BY_ZERO] = "error: division by zero", 17 [ERR_DIVISION_BY_ZERO] = "error: division by zero",
18 [ERR_PC_OOB] = "error: pc out of bounds", 18 [ERR_PC_OOB] = "error: pc out of bounds",
19 [ERR_EMPTY_CHUNK] = "error: empty chunk", 19 [ERR_EMPTY_CHUNK] = "error: empty chunk",
20 [ERR_AMBIGUOUS_PARAMS] = "error: ambiguous parameter names",
20}; 21};
21 22
22static Error errors[ERR_MAX_NUMBER]; 23static Error errors[ERR_MAX_NUMBER];
diff --git a/src/bytecode/errors.h b/src/bytecode/errors.h
index 425c768..8f4386e 100755
--- a/src/bytecode/errors.h
+++ b/src/bytecode/errors.h
@@ -24,6 +24,7 @@ typedef enum ErrorValue {
24 ERR_TOO_MANY_ARGS, 24 ERR_TOO_MANY_ARGS,
25 ERR_WRONG_ARG_TYPE, 25 ERR_WRONG_ARG_TYPE,
26 ERR_DIVISION_BY_ZERO, 26 ERR_DIVISION_BY_ZERO,
27 ERR_AMBIGUOUS_PARAMS,
27 28
28 // Bytecode interpreter. 29 // Bytecode interpreter.
29 ERR_PC_OOB, 30 ERR_PC_OOB,
diff --git a/src/bytecode/hashtable.h b/src/bytecode/hashtable.h
index 81c841e..1f55048 100644
--- a/src/bytecode/hashtable.h
+++ b/src/bytecode/hashtable.h
@@ -116,7 +116,6 @@ _ht_insert(HashTable *table, Object key, Object value) {
116 pairs[probe_position].key = &table->keys[array_size(table->keys) - 1]; 116 pairs[probe_position].key = &table->keys[array_size(table->keys) - 1];
117 pairs[probe_position].value = &table->values[array_size(table->values) - 1]; 117 pairs[probe_position].value = &table->values[array_size(table->values) - 1];
118 } else { 118 } else {
119 object_free(*pairs[probe_position].value);
120 *pairs[probe_position].value = value; 119 *pairs[probe_position].value = value;
121 } 120 }
122} 121}
diff --git a/src/bytecode/ops.h b/src/bytecode/ops.h
index 501a37f..52c774a 100755
--- a/src/bytecode/ops.h
+++ b/src/bytecode/ops.h
@@ -5,6 +5,8 @@ typedef enum Ops {
5 // Load/store ops. 5 // Load/store ops.
6 OP_CONSTANT, 6 OP_CONSTANT,
7 OP_LOCAL, 7 OP_LOCAL,
8 OP_DEF_LOCAL,
9 OP_SET_LOCAL,
8 OP_DEF, 10 OP_DEF,
9 OP_SET, 11 OP_SET,
10 OP_GET, 12 OP_GET,
diff --git a/src/bytecode/string_view.h b/src/bytecode/string_view.h
index 79d8305..5977ea9 100755
--- a/src/bytecode/string_view.h
+++ b/src/bytecode/string_view.h
@@ -18,6 +18,6 @@ bool sv_equal(const StringView *a, const StringView *b);
18// Write a character to the given output stream. 18// Write a character to the given output stream.
19void sv_write(const StringView *sv); 19void sv_write(const StringView *sv);
20 20
21#define STRING(STR) (StringView){(STR), sizeof(STR)} 21#define STRING(STR) (StringView){(STR), sizeof(STR) - 1}
22 22
23#endif // BDL_STRINGVIEW_H 23#endif // BDL_STRINGVIEW_H
diff --git a/src/bytecode/vm.h b/src/bytecode/vm.h
index 3f59aff..84d2432 100755
--- a/src/bytecode/vm.h
+++ b/src/bytecode/vm.h
@@ -183,6 +183,11 @@ vm_interpret(VM *vm) {
183 Object obj = frame->chunk->constants[constant]; 183 Object obj = frame->chunk->constants[constant];
184 array_push(vm->stack, obj); 184 array_push(vm->stack, obj);
185 } break; 185 } break;
186 case OP_DEF_LOCAL: {
187 Object value = array_pop(vm->stack);
188 ssize_t idx = AS_FIXNUM(array_pop(vm->stack));
189 vm->stack[frame->stack_offset + idx] = value;
190 } break;
186 case OP_DEF: { 191 case OP_DEF: {
187 Object value = array_pop(vm->stack); 192 Object value = array_pop(vm->stack);
188 Object name = array_pop(vm->stack); 193 Object name = array_pop(vm->stack);
@@ -281,12 +286,15 @@ vm_interpret(VM *vm) {
281 } else if (n_args > n_params) { 286 } else if (n_args > n_params) {
282 RUNTIME_ERROR(ERR_TOO_MANY_ARGS); 287 RUNTIME_ERROR(ERR_TOO_MANY_ARGS);
283 } 288 }
289 ssize_t n_locals = array_size(proc.chunk->locals) - n_params;
284 290
285 // DEBUG:... 291#ifdef DEBUG
286 // disassemble_chunk(proc.chunk); 292 disassemble_chunk(proc.chunk);
293#endif
287 294
288 // Tail-call optimization. 295 // Tail-call optimization.
289 if (proc.chunk != frame->chunk || *vm->pc != OP_RETURN) { 296 if (proc.chunk != frame->chunk || *vm->pc != OP_RETURN) {
297 // Prepare new call frame.
290 CallFrame new_frame = (CallFrame){ 298 CallFrame new_frame = (CallFrame){
291 .chunk = proc.chunk, 299 .chunk = proc.chunk,
292 .rp = vm->pc, 300 .rp = vm->pc,
@@ -294,14 +302,20 @@ vm_interpret(VM *vm) {
294 }; 302 };
295 array_push(vm->frames, new_frame); 303 array_push(vm->frames, new_frame);
296 frame = &vm->frames[array_size(vm->frames) - 1]; 304 frame = &vm->frames[array_size(vm->frames) - 1];
305
306 // Prepare local slots.
307 for (ssize_t i = 0; i < n_locals; i++) {
308 array_push(vm->stack, NIL_VAL);
309 }
297 } else { 310 } else {
298 // Bind tail-call parameters. 311 // Bind tail-call parameters.
299 for (size_t i = 0; i < (size_t)n_params; i++) { 312 for (ssize_t i = 0; i < n_params; i++) {
300 Object obj = array_peek(vm->stack, n_params - 1 - i); 313 Object obj = array_peek(vm->stack, n_locals + n_params - 1 - i);
301 vm->stack[frame->stack_offset + i] = obj; 314 vm->stack[frame->stack_offset + i] = obj;
302 } 315 }
316
303 // Reset stack size. 317 // Reset stack size.
304 array_head(vm->stack)->size = frame->stack_offset + n_params; 318 array_head(vm->stack)->size = frame->stack_offset + n_params + n_locals;
305 } 319 }
306 vm->pc = frame->chunk->code; 320 vm->pc = frame->chunk->code;
307 } break; 321 } break;