aboutsummaryrefslogtreecommitdiffstats
path: root/src/bytecode/compiler.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/bytecode/compiler.h')
-rwxr-xr-xsrc/bytecode/compiler.h109
1 files changed, 85 insertions, 24 deletions
diff --git a/src/bytecode/compiler.h b/src/bytecode/compiler.h
index 7497ea7..f9e1da1 100755
--- a/src/bytecode/compiler.h
+++ b/src/bytecode/compiler.h
@@ -4,16 +4,49 @@
4#include "chunk.h" 4#include "chunk.h"
5#include "lexer.h" 5#include "lexer.h"
6 6
7#define MAX_DEPTH 1024
8
9typedef struct Scope {
10 StringView *params;
11 StringView *locals;
12} Scope;
13
7typedef struct Compiler { 14typedef struct Compiler {
8 Token *tokens; 15 Token *tokens;
9 size_t current; 16 size_t current;
17 size_t scope_depth;
18 Scope scopes[MAX_DEPTH];
10} Compiler; 19} Compiler;
11 20
21
12// Mimics the functionality in the Scanner functions, but for entire tokens. 22// Mimics the functionality in the Scanner functions, but for entire tokens.
13Token next_token(Compiler *compiler); 23Token next_token(Compiler *compiler);
14Token peek_token(const Compiler *compiler); 24Token peek_token(const Compiler *compiler);
15bool has_next_token(const Compiler *compiler); 25bool has_next_token(const Compiler *compiler);
16 26
27// Scope initialization/exit.
28void enter_scope(Compiler *compiler);
29void exit_scope(Compiler *compiler);
30
31void
32enter_scope(Compiler *compiler) {
33 Scope *scope = &compiler->scopes[compiler->scope_depth++];
34 array_init(scope->params, 0);
35 array_init(scope->locals, 0);
36}
37
38void
39exit_scope(Compiler *compiler) {
40 Scope *scope = &compiler->scopes[--compiler->scope_depth];
41 array_free(scope->params);
42 array_free(scope->locals);
43}
44
45Scope *
46get_current_scope(Compiler *compiler) {
47 return &compiler->scopes[compiler->scope_depth - 1];
48}
49
17Chunk * compile(Token *tokens); 50Chunk * compile(Token *tokens);
18 51
19Token 52Token
@@ -32,10 +65,9 @@ has_next_token(const Compiler *compiler) {
32} 65}
33 66
34ssize_t 67ssize_t
35find_local_index(Chunk *chunk, Token tok) { 68find_local_index(Scope *scope, Token tok) {
36 // NOTE: This is dumb and potentially slow. 69 for (size_t i = 0; i < array_size(scope->locals); i++) {
37 for (size_t i = 0; i < array_size(chunk->locals); i++) { 70 if (sv_equal(&tok.value, &scope->locals[i])) {
38 if (sv_equal(&tok.value, &chunk->locals[i])) {
39 return i; 71 return i;
40 } 72 }
41 } 73 }
@@ -217,29 +249,49 @@ compile_declare_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) {
217 }); 249 });
218 return; 250 return;
219 } 251 }
220 // TODO: If we are inside a function and we are using OP_DEF, we just 252
221 // declare the local variable directly in the stack. No need for symbols! 253 if (compiler->scope_depth <= 1) {
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); 254 Object obj = make_symbol(name.value);
227 emit_constant(chunk, name, obj); 255 emit_constant(chunk, name, obj);
228 } else { 256 } 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) { 257 if (op == OP_DEF) {
237 op = OP_DEF_LOCAL; 258 op = OP_DEF_LOCAL;
259 // Check if the local is already registered.
260 Scope *scope = get_current_scope(compiler);
261 ssize_t idx = find_local_index(scope, name);
262 if (idx < 0) {
263 array_push(scope->locals, name.value);
264 idx = chunk->n_locals++;
265 }
266 emit_constant(chunk, name, FIXNUM_VAL(idx));
238 } else if (op == OP_SET) { 267 } else if (op == OP_SET) {
239 op = OP_SET_LOCAL; 268 size_t depth = compiler->scope_depth - 1;
269 ssize_t idx = -1;
270 // Check if name is local in this or any previous scope.
271 do {
272 Scope *scope = &compiler->scopes[depth];
273 idx = find_local_index(scope, name);
274 if (idx >= 0) {
275 break;
276 }
277 depth--;
278 } while (depth > 0);
279
280 if (idx >= 0) {
281 // If the value is found emit OP_SET_LOCAL with tree parameters:
282 // The new value, the scope depth, and the scope index.
283 op = OP_SET_LOCAL;
284 emit_constant(chunk, name, FIXNUM_VAL(depth));
285 emit_constant(chunk, name, FIXNUM_VAL(idx));
286 } else {
287 // If not found at all, emit set for the global scope.
288 Object obj = make_symbol(name.value);
289 emit_constant(chunk, name, obj);
290 }
240 } 291 }
241 emit_constant(chunk, name, FIXNUM_VAL(idx));
242 } 292 }
293 // NOTE: We can have compiler support for preemptively finding if globals
294 // exist or not.
243 295
244 Token tok = peek_token(compiler); 296 Token tok = peek_token(compiler);
245 if (name.type == TOKEN_EOF || tok.type == TOKEN_EOF) { 297 if (name.type == TOKEN_EOF || tok.type == TOKEN_EOF) {
@@ -276,6 +328,7 @@ compile_declare_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) {
276 328
277void 329void
278compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) { 330compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) {
331 enter_scope(compiler);
279 Object fun = make_lambda(name); 332 Object fun = make_lambda(name);
280 333
281 // Prepeare parameters. 334 // Prepeare parameters.
@@ -305,7 +358,8 @@ compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) {
305 return; 358 return;
306 } 359 }
307 // Check if parameters name already exists. 360 // Check if parameters name already exists.
308 ssize_t idx = find_local_index(fun.chunk, tok); 361 Scope *scope = get_current_scope(compiler);
362 ssize_t idx = find_local_index(scope, tok);
309 if (idx >= 0) { 363 if (idx >= 0) {
310 error_push((Error){ 364 error_push((Error){
311 .type = ERR_TYPE_COMPILER, 365 .type = ERR_TYPE_COMPILER,
@@ -315,8 +369,10 @@ compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) {
315 }); 369 });
316 return; 370 return;
317 } 371 }
318 array_push(fun.chunk->params, tok.value); 372 array_push(scope->params, tok.value);
319 array_push(fun.chunk->locals, tok.value); 373 array_push(scope->locals, tok.value);
374 fun.chunk->n_params++;
375 fun.chunk->n_locals++;
320 } 376 }
321 } else if (tok.type != TOKEN_NIL) { 377 } else if (tok.type != TOKEN_NIL) {
322 error_push((Error){ 378 error_push((Error){
@@ -348,6 +404,7 @@ compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) {
348 } 404 }
349 add_code(fun.chunk, OP_RETURN, start.line, start.column); 405 add_code(fun.chunk, OP_RETURN, start.line, start.column);
350 emit_constant(chunk, start, fun); 406 emit_constant(chunk, start, fun);
407 exit_scope(compiler);
351} 408}
352 409
353void 410void
@@ -551,7 +608,8 @@ parse_tree(Chunk *chunk, Compiler *compiler) {
551 return; 608 return;
552 } break; 609 } break;
553 case TOKEN_SYMBOL: { 610 case TOKEN_SYMBOL: {
554 ssize_t idx = find_local_index(chunk, tok); 611 Scope *scope = get_current_scope(compiler);
612 ssize_t idx = find_local_index(scope, tok);
555 if (idx < 0) { 613 if (idx < 0) {
556 Object obj = make_symbol(tok.value); 614 Object obj = make_symbol(tok.value);
557 emit_constant(chunk, tok, obj); 615 emit_constant(chunk, tok, obj);
@@ -583,11 +641,13 @@ parse_tree(Chunk *chunk, Compiler *compiler) {
583Chunk * 641Chunk *
584compile(Token *tokens) { 642compile(Token *tokens) {
585 Chunk *chunk = NULL; 643 Chunk *chunk = NULL;
586 chunk = NEW_CHUNK(""); 644 chunk = NEW_CHUNK("main");
587 Compiler compiler = (Compiler){ 645 Compiler compiler = (Compiler){
588 .tokens = tokens, 646 .tokens = tokens,
589 .current = 0, 647 .current = 0,
648 .scope_depth = 0,
590 }; 649 };
650 enter_scope(&compiler);
591 Token main_start = peek_token(&compiler); 651 Token main_start = peek_token(&compiler);
592 while (has_next_token(&compiler)) { 652 while (has_next_token(&compiler)) {
593 Token start = peek_token(&compiler); 653 Token start = peek_token(&compiler);
@@ -598,6 +658,7 @@ compile(Token *tokens) {
598 add_code(chunk, OP_DROP, start.line, start.column); 658 add_code(chunk, OP_DROP, start.line, start.column);
599 } 659 }
600 add_code(chunk, OP_RETURN, main_start.line, main_start.column); 660 add_code(chunk, OP_RETURN, main_start.line, main_start.column);
661 exit_scope(&compiler);
601 return chunk; 662 return chunk;
602} 663}
603 664