aboutsummaryrefslogtreecommitdiffstats
path: root/src/bytecode/compiler.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/bytecode/compiler.h')
-rwxr-xr-xsrc/bytecode/compiler.h748
1 files changed, 0 insertions, 748 deletions
diff --git a/src/bytecode/compiler.h b/src/bytecode/compiler.h
deleted file mode 100755
index 5f38216..0000000
--- a/src/bytecode/compiler.h
+++ /dev/null
@@ -1,748 +0,0 @@
1#ifndef BDL_COMPILER_H
2#define BDL_COMPILER_H
3
4#include "chunk.h"
5#include "lexer.h"
6
7#define MAX_DEPTH 1024
8
9typedef struct Scope {
10 StringView *params;
11 StringView *locals;
12 Token *captured;
13} Scope;
14
15typedef struct Compiler {
16 Token *tokens;
17 size_t current;
18 size_t scope_depth;
19 Scope scopes[MAX_DEPTH];
20} Compiler;
21
22
23// Mimics the functionality in the Scanner functions, but for entire tokens.
24Token next_token(Compiler *compiler);
25Token peek_token(const Compiler *compiler);
26bool has_next_token(const Compiler *compiler);
27
28// Scope initialization/exit.
29void enter_scope(Compiler *compiler);
30void exit_scope(Compiler *compiler);
31
32void
33enter_scope(Compiler *compiler) {
34 Scope *scope = &compiler->scopes[compiler->scope_depth++];
35 array_init(scope->params, 0);
36 array_init(scope->locals, 0);
37 array_init(scope->captured, 0);
38}
39
40void
41exit_scope(Compiler *compiler) {
42 Scope *scope = &compiler->scopes[--compiler->scope_depth];
43 array_free(scope->params);
44 array_free(scope->locals);
45 array_free(scope->captured);
46}
47
48Scope *
49get_current_scope(Compiler *compiler) {
50 return &compiler->scopes[compiler->scope_depth - 1];
51}
52
53Chunk * compile(Token *tokens);
54
55Token
56peek_token(const Compiler *compiler) {
57 return compiler->tokens[compiler->current];
58}
59
60Token
61next_token(Compiler *compiler) {
62 return compiler->tokens[compiler->current++];
63}
64
65bool
66has_next_token(const Compiler *compiler) {
67 return compiler->current < array_size(compiler->tokens);
68}
69
70ssize_t
71find_local_index(Scope *scope, Token tok) {
72 for (size_t i = 0; i < array_size(scope->locals); i++) {
73 if (sv_equal(&tok.value, &scope->locals[i])) {
74 return i;
75 }
76 }
77 return -1;
78}
79
80ssize_t
81find_captued_index(Scope *scope, Token tok) {
82 for (size_t i = 0; i < array_size(scope->captured); i++) {
83 if (sv_equal(&tok.value, &scope->captured[i].value)) {
84 return i;
85 }
86 }
87 return -1;
88}
89
90void
91emit_constant(Chunk *chunk, Token tok, Object obj) {
92 size_t prev_size = array_size(chunk->constants);
93 size_t num_idx = add_constant(chunk, obj);
94 add_code(chunk, OP_CONSTANT, tok.line, tok.column);
95 add_code(chunk, num_idx, tok.line, tok.column);
96
97 // If the non value constant was already present we need to properly free
98 // the memory from the object given to this function.
99 if (prev_size == array_size(chunk->constants)) {
100 object_free(&obj);
101 }
102}
103
104size_t
105emit_jump(Chunk *chunk, Token tok, Ops op, ssize_t offset) {
106 add_code(chunk, op, tok.line, tok.column);
107 add_code(chunk, ((u16)offset >> 8) & 0xFF, tok.line, tok.column);
108 add_code(chunk, ((u16)offset) & 0xFF, tok.line, tok.column);
109 return array_size(chunk->code) - 2;
110}
111
112void
113patch_jump(Chunk *chunk, ssize_t offset) {
114 ssize_t jump = array_size(chunk->code) - offset - 2;
115 assert((u16)jump <= UINT16_MAX && "error: jump is too long");
116 chunk->code[offset] = ((u16)jump >> 8) & 0xFF;
117 chunk->code[offset + 1] = ((u16)jump) & 0xFF;
118}
119
120void
121parse_fixnum(Chunk *chunk, Token tok) {
122 ssize_t num = 0;
123 int sign = 1;
124 for (size_t i = 0; i < tok.value.n; i++) {
125 char c = tok.value.start[i];
126 if (c == '-') {
127 sign = -1;
128 continue;
129 }
130 num = num * 10 + (c - '0');
131 }
132 emit_constant(chunk, tok, FIXNUM_VAL(num * sign));
133}
134
135void
136parse_symbol(Chunk *chunk, Compiler *compiler, Token tok) {
137 if (compiler->scope_depth > 1) {
138 Scope *current_scope = get_current_scope(compiler);
139 ssize_t idx = -1;
140 // Check if the variable was already captured.
141 idx = find_captued_index(current_scope, tok);
142 if (idx >= 0) {
143 emit_constant(chunk, tok, FIXNUM_VAL(idx));
144 add_code(chunk, OP_CAPTURED, tok.line, tok.column);
145 return;
146 }
147
148 // Check current scope locals. If we find it, emit OP_LOCAL.
149 idx = find_local_index(current_scope, tok);
150 if (idx >= 0) {
151 emit_constant(chunk, tok, FIXNUM_VAL(idx));
152 add_code(chunk, OP_LOCAL, tok.line, tok.column);
153 return;
154 }
155
156 // Descend scopes, if we find the symbol at a different depth,
157 // we need to capture the variable.
158 size_t depth = compiler->scope_depth - 2;
159 while (depth > 0) {
160 Scope *scope = &compiler->scopes[depth];
161 idx = find_local_index(scope, tok);
162 if (idx >= 0) {
163 // Put captured variable on stack.
164 ssize_t captured_idx = array_size(current_scope->captured);
165 emit_constant(chunk, tok, FIXNUM_VAL(captured_idx));
166 add_code(chunk, OP_CAPTURED, tok.line, tok.column);
167 array_push(current_scope->captured, tok);
168 return;
169 }
170 depth--;
171 }
172
173 // TODO: Capture globals?
174 }
175
176 Object obj = make_symbol(tok.value);
177 emit_constant(chunk, tok, obj);
178 add_code(chunk, OP_GET, tok.line, tok.column);
179}
180
181void parse_tree(Chunk *chunk, Compiler *compiler);
182
183void
184compile_list_binary_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) {
185 size_t n = 0;
186 while (has_next_token(compiler)) {
187 Token tok = peek_token(compiler);
188 if (tok.type == TOKEN_EOF) {
189 error_push((Error){
190 .type = ERR_TYPE_COMPILER,
191 .value = ERR_UNBALANCED_PAREN,
192 .line = start.line,
193 .col = start.column,
194 });
195 return;
196 }
197 if (tok.type == TOKEN_RPAREN) {
198 next_token(compiler);
199 if (n <= 1) {
200 error_push((Error){
201 .type = ERR_TYPE_COMPILER,
202 .value = ERR_NOT_ENOUGH_ARGS,
203 .line = start.line,
204 .col = start.column,
205 });
206 return;
207 }
208 break;
209 }
210 parse_tree(chunk, compiler);
211 n++;
212 }
213 emit_constant(chunk, start, FIXNUM_VAL(n));
214 add_code(chunk, op, start.line, start.column);
215}
216
217void
218compile_list_unary_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) {
219 size_t n = 0;
220 while (has_next_token(compiler)) {
221 Token tok = peek_token(compiler);
222 if (tok.type == TOKEN_EOF) {
223 error_push((Error){
224 .type = ERR_TYPE_COMPILER,
225 .value = ERR_UNBALANCED_PAREN,
226 .line = start.line,
227 .col = start.column,
228 });
229 return;
230 }
231 if (tok.type == TOKEN_RPAREN) {
232 next_token(compiler);
233 if (n == 0) {
234 error_push((Error){
235 .type = ERR_TYPE_COMPILER,
236 .value = ERR_NOT_ENOUGH_ARGS,
237 .line = start.line,
238 .col = start.column,
239 });
240 }
241 return;
242 }
243 parse_tree(chunk, compiler);
244 add_code(chunk, op, start.line, start.column);
245 n++;
246 if (n > 1) {
247 error_push((Error){
248 .type = ERR_TYPE_COMPILER,
249 .value = ERR_TOO_MANY_ARGS,
250 .line = start.line,
251 .col = start.column,
252 });
253 }
254 }
255 error_push((Error){
256 .type = ERR_TYPE_COMPILER,
257 .value = ERR_UNBALANCED_PAREN,
258 .line = start.line,
259 .col = start.column,
260 });
261}
262
263void
264compile_list_simple_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) {
265 if (has_next_token(compiler)) {
266 Token tok = peek_token(compiler);
267 if (tok.type == TOKEN_EOF) {
268 error_push((Error){
269 .type = ERR_TYPE_COMPILER,
270 .value = ERR_UNBALANCED_PAREN,
271 .line = start.line,
272 .col = start.column,
273 });
274 return;
275 }
276 if (tok.type != TOKEN_RPAREN) {
277 error_push((Error){
278 .type = ERR_TYPE_COMPILER,
279 .value = ERR_TOO_MANY_ARGS,
280 .line = start.line,
281 .col = start.column,
282 });
283 return;
284 }
285 next_token(compiler);
286 add_code(chunk, op, start.line, start.column);
287 return;
288 }
289 error_push((Error){
290 .type = ERR_TYPE_COMPILER,
291 .value = ERR_UNBALANCED_PAREN,
292 .line = start.line,
293 .col = start.column,
294 });
295}
296
297#define STR_ARRAY(ARR) (StringView){(ARR), array_size(ARR)}
298
299void
300compile_declare_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) {
301 Token name = next_token(compiler);
302 if (name.type != TOKEN_SYMBOL) {
303 error_push((Error){
304 .type = ERR_TYPE_COMPILER,
305 .value = ERR_WRONG_ARG_TYPE,
306 .line = start.line,
307 .col = start.column,
308 });
309 return;
310 }
311
312 if (compiler->scope_depth <= 1) {
313 Object obj = make_symbol(name.value);
314 emit_constant(chunk, name, obj);
315 } else {
316 if (op == OP_DEF) {
317 op = OP_DEF_LOCAL;
318 // Check if the local is already registered.
319 Scope *scope = get_current_scope(compiler);
320 ssize_t idx = find_local_index(scope, name);
321 if (idx < 0) {
322 array_push(scope->locals, name.value);
323 idx = chunk->n_locals++;
324 }
325 emit_constant(chunk, name, FIXNUM_VAL(idx));
326 } else if (op == OP_SET) {
327 // FIXME: This is fucking ugly.
328 Scope *current_scope = get_current_scope(compiler);
329 ssize_t idx = -1;
330 // Check if the variable was already captured.
331 idx = find_captued_index(current_scope, name);
332 if (idx >= 0) {
333 emit_constant(chunk, name, FIXNUM_VAL(idx));
334 op = OP_SET_CAPTURED;
335 } else {
336 idx = find_local_index(current_scope, name);
337 if (idx >= 0) {
338 emit_constant(chunk, name, FIXNUM_VAL(idx));
339 op = OP_SET_LOCAL;
340 } else {
341 size_t depth = compiler->scope_depth - 2;
342 while (depth > 0) {
343 Scope *scope = &compiler->scopes[depth];
344 idx = find_local_index(scope, name);
345 if (idx >= 0) {
346 op = OP_SET_CAPTURED;
347 ssize_t captured_idx = array_size(current_scope->captured);
348 emit_constant(chunk, name, FIXNUM_VAL(captured_idx));
349 array_push(current_scope->captured, name);
350 break;
351 }
352 depth--;
353 }
354 if (idx < 0) {
355 Object obj = make_symbol(name.value);
356 emit_constant(chunk, name, obj);
357 }
358 }
359 }
360 }
361 }
362 // NOTE: We can have compiler support for preemptively finding if globals
363 // exist or not.
364
365 Token tok = peek_token(compiler);
366 if (name.type == TOKEN_EOF || tok.type == TOKEN_EOF) {
367 error_push((Error){
368 .type = ERR_TYPE_COMPILER,
369 .value = ERR_UNBALANCED_PAREN,
370 .line = start.line,
371 .col = start.column,
372 });
373 return;
374 }
375 if (name.type == TOKEN_RPAREN || tok.type == TOKEN_RPAREN) {
376 error_push((Error){
377 .type = ERR_TYPE_COMPILER,
378 .value = ERR_NOT_ENOUGH_ARGS,
379 .line = start.line,
380 .col = start.column,
381 });
382 return;
383 }
384 parse_tree(chunk, compiler);
385 if (peek_token(compiler).type != TOKEN_RPAREN) {
386 error_push((Error){
387 .type = ERR_TYPE_COMPILER,
388 .value = ERR_TOO_MANY_ARGS,
389 .line = start.line,
390 .col = start.column,
391 });
392 return;
393 }
394 next_token(compiler);
395 add_code(chunk, op, start.line, start.column);
396}
397
398void
399compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) {
400 enter_scope(compiler);
401 Chunk *proc_chunk = chunk_init(name);
402 Object fun = make_lambda(proc_chunk);
403
404 // Prepeare parameters.
405 Token tok = next_token(compiler);
406 if (tok.type == TOKEN_LPAREN){
407 while (has_next_token(compiler)) {
408 Token tok = next_token(compiler);
409 if (tok.type == TOKEN_EOF) {
410 error_push((Error){
411 .type = ERR_TYPE_COMPILER,
412 .value = ERR_UNBALANCED_PAREN,
413 .line = start.line,
414 .col = start.column,
415 });
416 return;
417 }
418 if (tok.type == TOKEN_RPAREN) {
419 break;
420 }
421 if (tok.type != TOKEN_SYMBOL) {
422 error_push((Error){
423 .type = ERR_TYPE_COMPILER,
424 .value = ERR_WRONG_ARG_TYPE,
425 .line = tok.line,
426 .col = tok.column,
427 });
428 return;
429 }
430 // Check if parameters name already exists.
431 Scope *scope = get_current_scope(compiler);
432 ssize_t idx = find_local_index(scope, tok);
433 if (idx >= 0) {
434 error_push((Error){
435 .type = ERR_TYPE_COMPILER,
436 .value = ERR_AMBIGUOUS_PARAMS,
437 .line = tok.line,
438 .col = tok.column,
439 });
440 return;
441 }
442 array_push(scope->params, tok.value);
443 array_push(scope->locals, tok.value);
444 fun.closure->chunk->n_params++;
445 fun.closure->chunk->n_locals++;
446 }
447 } else if (tok.type != TOKEN_NIL) {
448 error_push((Error){
449 .type = ERR_TYPE_COMPILER,
450 .value = ERR_WRONG_ARG_TYPE,
451 .line = tok.line,
452 .col = tok.column,
453 });
454 return;
455 }
456
457 // Compile body.
458 while (has_next_token(compiler)) {
459 Token tok = peek_token(compiler);
460 if (tok.type == TOKEN_EOF) {
461 error_push((Error){
462 .type = ERR_TYPE_COMPILER,
463 .value = ERR_UNBALANCED_PAREN,
464 .line = start.line,
465 .col = start.column,
466 });
467 return;
468 }
469 if (tok.type == TOKEN_RPAREN) {
470 next_token(compiler);
471 break;
472 }
473 parse_tree(fun.closure->chunk, compiler);
474 }
475 add_code(fun.closure->chunk, OP_RETURN, start.line, start.column);
476
477 // Prepare closure value capture.
478 Scope *scope = get_current_scope(compiler);
479 size_t n_captured = array_size(scope->captured);
480 if (n_captured > 0) {
481 compiler->scope_depth--;
482 for (size_t i = 0; i < n_captured; i++) {
483 Token tok = scope->captured[i];
484 parse_symbol(chunk, compiler, tok);
485 }
486 // Number of captured values.
487 emit_constant(chunk, tok, FIXNUM_VAL(n_captured));
488
489 // Push created lambda to stack.
490 emit_constant(chunk, start, fun);
491
492 // Emit capture local instruction.
493 add_code(chunk, OP_CAPTURE_LOCAL, tok.line, tok.column);
494 compiler->scope_depth++;
495 } else {
496 emit_constant(chunk, start, fun);
497 }
498 exit_scope(compiler);
499}
500
501void
502compile_fun_op(Chunk *chunk, Compiler *compiler, Token start) {
503 Token name = peek_token(compiler);
504 if (name.type != TOKEN_SYMBOL) {
505 error_push((Error){
506 .type = ERR_TYPE_COMPILER,
507 .value = ERR_WRONG_ARG_TYPE,
508 .line = start.line,
509 .col = start.column,
510 });
511 return;
512 }
513 Object obj = make_symbol(name.value);
514 emit_constant(chunk, name, obj);
515 next_token(compiler);
516
517 compile_lambda(chunk, compiler, start, name.value);
518 add_code(chunk, OP_DEF, start.line, start.column);
519}
520
521void
522compile_call_op(Chunk *chunk, Compiler *compiler, Token start, Token name) {
523 if (name.type == TOKEN_SYMBOL) {
524 parse_symbol(chunk, compiler, name);
525 }
526
527 // Compile body.
528 size_t n = 0;
529 while (has_next_token(compiler)) {
530 Token tok = peek_token(compiler);
531 if (tok.type == TOKEN_EOF) {
532 error_push((Error){
533 .type = ERR_TYPE_COMPILER,
534 .value = ERR_UNBALANCED_PAREN,
535 .line = start.line,
536 .col = start.column,
537 });
538 return;
539 }
540 if (tok.type == TOKEN_RPAREN) {
541 next_token(compiler);
542 break;
543 }
544 parse_tree(chunk, compiler);
545 n++;
546 }
547 emit_constant(chunk, start, FIXNUM_VAL(n));
548 add_code(chunk, OP_CALL, start.line, start.column);
549}
550
551void
552compile_if_op(Chunk *chunk, Compiler *compiler, Token start) {
553 Token tok = peek_token(compiler);
554 if (tok.type == TOKEN_EOF) {
555 error_push((Error){
556 .type = ERR_TYPE_COMPILER,
557 .value = ERR_UNBALANCED_PAREN,
558 .line = start.line,
559 .col = start.column,
560 });
561 return;
562 }
563 if (tok.type == TOKEN_RPAREN) {
564 error_push((Error){
565 .type = ERR_TYPE_COMPILER,
566 .value = ERR_NOT_ENOUGH_ARGS,
567 .line = start.line,
568 .col = start.column,
569 });
570 return;
571 }
572
573 // Condition.
574 parse_tree(chunk, compiler);
575 size_t jmp_false = emit_jump(chunk, start, OP_JUMP_IF_FALSE, 0xFFFF);
576
577 // True expression.
578 parse_tree(chunk, compiler);
579
580 // No second expression.
581 if (peek_token(compiler).type == TOKEN_RPAREN) {
582 patch_jump(chunk, jmp_false);
583 next_token(compiler);
584 return;
585 }
586
587 // False expression.
588 size_t jmp_end = emit_jump(chunk, start, OP_JUMP, 0xFFFF);
589 patch_jump(chunk, jmp_false);
590 parse_tree(chunk, compiler);
591 patch_jump(chunk, jmp_end);
592
593 if (peek_token(compiler).type != TOKEN_RPAREN) {
594 error_push((Error){
595 .type = ERR_TYPE_COMPILER,
596 .value = ERR_TOO_MANY_ARGS,
597 .line = start.line,
598 .col = start.column,
599 });
600 return;
601 }
602 next_token(compiler);
603}
604
605void
606parse_list(Chunk *chunk, Compiler *compiler, Token start) {
607 if (!has_next_token(compiler)) {
608 error_push((Error){
609 .type = ERR_TYPE_COMPILER,
610 .value = ERR_UNBALANCED_PAREN,
611 .line = start.line,
612 .col = start.column,
613 });
614 return;
615 }
616 while (has_next_token(compiler)) {
617 Token tok = next_token(compiler);
618 if (tok.type == TOKEN_LPAREN) {
619 parse_list(chunk, compiler, tok);
620 }
621 switch (tok.type) {
622 case TOKEN_ADD: { compile_list_binary_op(chunk, compiler, start, OP_SUM); } break;
623 case TOKEN_SUB: { compile_list_binary_op(chunk, compiler, start, OP_SUB); } break;
624 case TOKEN_MUL: { compile_list_binary_op(chunk, compiler, start, OP_MUL); } break;
625 case TOKEN_DIV: { compile_list_binary_op(chunk, compiler, start, OP_DIV); } break;
626 case TOKEN_MOD: { compile_list_binary_op(chunk, compiler, start, OP_MOD); } break;
627 case TOKEN_NOT: { compile_list_unary_op(chunk, compiler, start, OP_NOT); } break;
628 case TOKEN_AND: { compile_list_binary_op(chunk, compiler, start, OP_AND); } break;
629 case TOKEN_OR: { compile_list_binary_op(chunk, compiler, start, OP_OR); } break;
630 case TOKEN_EQUAL: { compile_list_binary_op(chunk, compiler, start, OP_EQUAL); } break;
631 case TOKEN_LESS: { compile_list_binary_op(chunk, compiler, start, OP_LESS); } break;
632 case TOKEN_GREATER: { compile_list_binary_op(chunk, compiler, start, OP_GREATER); } break;
633 case TOKEN_LESS_EQUAL: { compile_list_binary_op(chunk, compiler, start, OP_LESS_EQUAL); } break;
634 case TOKEN_GREATER_EQUAL: { compile_list_binary_op(chunk, compiler, start, OP_GREATER_EQUAL); } break;
635 case TOKEN_PRINT: { compile_list_unary_op(chunk, compiler, start, OP_PRINT); } break;
636 case TOKEN_DISPLAY: { compile_list_unary_op(chunk, compiler, start, OP_DISPLAY); } break;
637 case TOKEN_NEWLINE: {
638 compile_list_simple_op(chunk, compiler, start, OP_NEWLINE);
639 emit_constant(chunk, start, NIL_VAL);
640 } break;
641 case TOKEN_DEF: { compile_declare_op(chunk, compiler, start, OP_DEF); } break;
642 case TOKEN_SET: { compile_declare_op(chunk, compiler, start, OP_SET); } break;
643 case TOKEN_FUN: { compile_fun_op(chunk, compiler, start); } break;
644 case TOKEN_LAMBDA: { compile_lambda(chunk, compiler, start, STRING("lambda")); } break;
645 case TOKEN_IF: { compile_if_op(chunk, compiler, start); } break;
646 default: {
647 compile_call_op(chunk, compiler, start, tok);
648 } break;
649 }
650 return;
651 }
652}
653
654void
655parse_tree(Chunk *chunk, Compiler *compiler) {
656 Token tok = next_token(compiler);
657 if (errors_n != 0) {
658 return;
659 }
660 switch (tok.type) {
661 case TOKEN_FIXNUM: {
662 parse_fixnum(chunk, tok);
663 return ;
664 } break;
665 case TOKEN_TRUE: {
666 emit_constant(chunk, tok, TRUE_VAL);
667 return;
668 } break;
669 case TOKEN_FALSE: {
670 emit_constant(chunk, tok, FALSE_VAL);
671 return;
672 } break;
673 case TOKEN_RPAREN: {
674 error_push((Error){
675 .type = ERR_TYPE_COMPILER,
676 .value = ERR_UNBALANCED_PAREN,
677 .line = tok.line,
678 .col = tok.column,
679 });
680 return;
681 } break;
682 case TOKEN_QUOTE: {
683 // Object *base = make_pair(obj_quote, obj_nil);
684 // base->cdr = make_pair(obj_nil, obj_nil);
685 // push_root(base);
686 // Object *next_obj = parse_tree(compiler);
687 // if (next_obj == obj_err) {
688 // return obj_err;
689 // }
690 // base->cdr->car = next_obj;
691 // return base;
692 return;
693 } break;
694 case TOKEN_LPAREN: {
695 parse_list(chunk, compiler, tok);
696 return;
697 } break;
698 case TOKEN_STRING: {
699 Object obj = make_string(tok.value);
700 emit_constant(chunk, tok, obj);
701 return;
702 } break;
703 case TOKEN_SYMBOL: {
704 parse_symbol(chunk, compiler, tok);
705 return;
706 } break;
707 case TOKEN_NIL: {
708 emit_constant(chunk, tok, NIL_VAL);
709 return;
710 } break;
711 default: {
712 break;
713 } break;
714 }
715 error_push((Error){
716 .type = ERR_TYPE_COMPILER,
717 .value = ERR_EOF_REACHED,
718 .line = tok.line,
719 .col = tok.column,
720 });
721 return;
722}
723
724Chunk *
725compile(Token *tokens) {
726 Chunk *chunk = NULL;
727 chunk = NEW_CHUNK("main");
728 Compiler compiler = (Compiler){
729 .tokens = tokens,
730 .current = 0,
731 .scope_depth = 0,
732 };
733 enter_scope(&compiler);
734 Token main_start = peek_token(&compiler);
735 while (has_next_token(&compiler)) {
736 Token start = peek_token(&compiler);
737 parse_tree(chunk, &compiler);
738 if (peek_token(&compiler).type == TOKEN_EOF) {
739 break;
740 }
741 add_code(chunk, OP_DROP, start.line, start.column);
742 }
743 add_code(chunk, OP_RETURN, main_start.line, main_start.column);
744 exit_scope(&compiler);
745 return chunk;
746}
747
748#endif // BDL_COMPILER_H