#ifndef BDL_COMPILER_H #define BDL_COMPILER_H #include "chunk.h" #include "lexer.h" typedef struct Visitor { Token *tokens; size_t current; } Visitor; // Mimics the functionality in the Scanner functions, but for entire tokens. Token next_token(Visitor *visitor); Token peek_token(const Visitor *visitor); bool has_next_token(const Visitor *visitor); Chunk * compile(Token *tokens); Token peek_token(const Visitor *visitor) { return visitor->tokens[visitor->current]; } Token next_token(Visitor *visitor) { return visitor->tokens[visitor->current++]; } bool has_next_token(const Visitor *visitor) { return visitor->current < array_size(visitor->tokens); } void emit_constant(Chunk *chunk, Token tok, Object obj) { // TODO: Should we deduplicate constants? For example why store a number // more than once instead of reusing the existing index? size_t num_idx = add_constant(chunk, obj); add_code(chunk, OP_CONSTANT, tok.line, tok.column); add_code(chunk, num_idx, tok.line, tok.column); } void parse_fixnum(Chunk *chunk, Token tok) { ssize_t num = 0; int sign = 1; for (size_t i = 0; i < tok.value.n; i++) { char c = tok.value.start[i]; if (c == '-') { sign = -1; continue; } num = num * 10 + (c - '0'); } emit_constant(chunk, tok, num); } void parse_tree(Chunk *chunk, Visitor *vs); void compile_list_primitive(Chunk *chunk, Visitor *vs, Token op_tok) { Ops op; switch (op_tok.type) { case TOKEN_ADD: { op = OP_SUM; } break; case TOKEN_SUB: { op = OP_SUB; } break; case TOKEN_MUL: { op = OP_MUL; } break; case TOKEN_DIV: { op = OP_DIV; } break; case TOKEN_MOD: { op = OP_MOD; } break; default: { } break; } size_t n = 0; while (has_next_token(vs)) { Token tok = peek_token(vs); if (tok.type == TOKEN_EOF) { error_push((Error){ .type = ERR_TYPE_COMPILER, .value = ERR_UNBALANCED_PAREN, .line = op_tok.line, .col = op_tok.column, }); return; } if (tok.type == TOKEN_RPAREN) { next_token(vs); break; } parse_tree(chunk, vs); n++; if (n > 1) { add_code(chunk, op, tok.line, tok.column); } } if (n == 0) { error_push((Error){ .type = ERR_TYPE_COMPILER, .value = ERR_NOT_ENOUGH_ARGS, .line = op_tok.line, .col = op_tok.column, }); } } void parse_list(Chunk *chunk, Visitor *vs) { if (has_next_token(vs)) { Token tok = next_token(vs); print_token(tok); // TODO: check if is function call. switch (tok.type) { case TOKEN_ADD: case TOKEN_SUB: case TOKEN_MUL: case TOKEN_DIV: case TOKEN_MOD:{ compile_list_primitive(chunk, vs, tok); } break; default: { error_push((Error){ .type = ERR_TYPE_COMPILER, .value = ERR_OBJ_NOT_CALLABLE, .line = tok.line, .line = tok.column, }); } break; } } } void parse_tree(Chunk *chunk, Visitor *vs) { Token tok = next_token(vs); switch (tok.type) { case TOKEN_FIXNUM: { parse_fixnum(chunk, tok); return ; } break; case TOKEN_TRUE: { // return obj_true; return; } break; case TOKEN_FALSE: { // return obj_false; return; } break; case TOKEN_RPAREN: { error_push((Error){ .type = ERR_TYPE_COMPILER, .value = ERR_UNBALANCED_PAREN, .line = tok.line, .col = tok.column, }); return; } break; case TOKEN_QUOTE: { // Object *base = make_pair(obj_quote, obj_nil); // base->cdr = make_pair(obj_nil, obj_nil); // push_root(base); // Object *next_obj = parse_tree(vs); // if (next_obj == obj_err) { // return obj_err; // } // base->cdr->car = next_obj; // return base; return; } break; case TOKEN_LPAREN: { parse_list(chunk, vs); // Object *obj = parse_list(vs); // if (obj == obj_err) { // error_push((Error){ // .type = ERR_TYPE_COMPILER, // .value = ERR_UNBALANCED_PAREN, // .line = tok.line, // .col = tok.column, // }); // } // return obj; return; } break; case TOKEN_STRING: { // Object *obj = make_string(); // push_root(obj); // append_string(obj, tok.value); // return obj; return; } break; case TOKEN_SYMBOL: { // Object *obj = make_symbol(tok.value); // push_root(obj); // return obj; return; } break; case TOKEN_NIL: { // return obj_nil; return; } break; default: { break; } break; } error_push((Error){ .type = ERR_TYPE_COMPILER, .value = ERR_EOF_REACHED, .line = tok.line, .col = tok.column, }); return; } Chunk * compile(Token *tokens) { Chunk *chunk = NULL; chunk = chunk_init(); Visitor visitor = (Visitor){ .tokens = tokens, .current = 0, }; while (has_next_token(&visitor) && peek_token(&visitor).type != TOKEN_EOF) { parse_tree(chunk, &visitor); } // error_push((Error){ // .type = ERR_TYPE_COMPILER, // .value = ERR_UNKNOWN, // }); // size_t const_a = add_constant(chunk, 7); // add_code(chunk, OP_CONSTANT, 1, 1); // add_code(chunk, const_a, 1, 1); // size_t const_b = add_constant(chunk, 2); // add_code(chunk, OP_CONSTANT, 1, 2); // add_code(chunk, const_b, 1, 2); // add_code(chunk, OP_MOD, 1, 3); add_code(chunk, OP_RETURN, 1, 1); return chunk; } #endif // BDL_COMPILER_H