undar-lang/compiler.c

958 lines
21 KiB
C

#include "compiler.h"
#include "common.h"
#include "emit.h"
#include "lexer.h"
#include "libc.h"
#include "list.h"
Emitter emitter = {0};
Parser parser = {0};
Arena *arena;
List *code;
List *memory;
/****************************************************
* Scope
***************************************************/
void
scopes_init()
{
Scope *current;
Scope child = {0};
child.symbols = List_init(arena);
child.locals_offset = 0;
current = (Scope *)List_push(arena, parser.scopes, &child, sizeof(Scope));
parser.current_scope = current;
}
Scope *
scope_new()
{
Scope *current;
Scope child = {0};
child.symbols = List_init(arena);
child.parent = parser.current_scope;
child.locals_offset = 0;
current = (Scope *)List_push(arena, parser.scopes, &child, sizeof(Scope));
parser.current_scope = current;
parser.scope_idx++;
parser.depth++;
return current;
}
void
scope_pop()
{
if(parser.current_scope) {
parser.current_scope = parser.current_scope->parent;
parser.depth--;
}
}
void
scope_push()
{
Scope *scope = List_get(parser.scopes, parser.scope_idx);
parser.current_scope = scope;
parser.depth++;
parser.scope_idx++;
}
Symbol *
scope_get_symbol(Scope *scope, const char *name, u32 name_length)
{
u32 count, i;
if(!scope) return nil;
count = scope->symbols->count;
for(i = 0; i < count; i++) {
Symbol *sym = List_get(scope->symbols, i);
if(sym->name_length == name_length && sleq(sym->name, name, name_length))
return sym;
}
return scope_get_symbol(scope->parent, name, name_length);
}
Symbol *
scope_add_symbol(const char *name, u32 name_length, SymbolType type, u32 size)
{
Symbol new_sym = {0};
Symbol *sym = scope_get_symbol(parser.current_scope, name, name_length);
if(sym != nil) {
if(parser.pass)
return sym;
else
emitter.error("duplicate found", 14, parser.previous.line);
}
scpy(new_sym.name, name, name_length);
new_sym.name_length = name_length;
new_sym.type = type;
new_sym.secondary_type = SYMBOL_VOID;
new_sym.size = size;
new_sym.ref = parser.current_scope->locals_offset;
new_sym.scope = parser.scope_idx;
parser.current_scope->locals_offset += size;
if(type == SYMBOL_PLEX || type == SYMBOL_METHOD || type == SYMBOL_TRAIT ||
type == SYMBOL_FUNCTION) {
new_sym.args = List_init(arena);
}
if(type == SYMBOL_PLEX || type == SYMBOL_METHOD || type == SYMBOL_TRAIT)
new_sym.fields = List_init(arena);
return List_push(arena, parser.current_scope->symbols, &new_sym,
sizeof(Symbol));
}
bool
is_global()
{
return parser.current_scope != nil && parser.current_scope->parent == nil;
}
bool
is_type()
{
return parser.previous.type >= TOKEN_TYPE_I8 &&
parser.previous.type <= TOKEN_TYPE_PTR;
}
SymbolType
token_type_to_sym_type(TokenType t)
{
switch(t) {
case TOKEN_TYPE_BOOL:
return SYMBOL_BOOL;
case TOKEN_TYPE_BYTE:
return SYMBOL_BYTE;
case TOKEN_TYPE_INT:
return SYMBOL_INT;
case TOKEN_TYPE_NAT:
return SYMBOL_NAT;
case TOKEN_TYPE_REAL:
return SYMBOL_REAL;
case TOKEN_TYPE_STR:
return SYMBOL_STR;
case TOKEN_TYPE_U8:
return SYMBOL_U8;
case TOKEN_TYPE_I8:
return SYMBOL_I8;
case TOKEN_TYPE_I16:
return SYMBOL_I16;
case TOKEN_TYPE_U16:
return SYMBOL_U16;
default:
break;
}
return SYMBOL_UNDEFINED;
}
/****************************************************
* Parser
***************************************************/
bool
advance()
{
parser.previous = parser.current;
for(;;) {
parser.current = next_token();
if(parser.current.type != TOKEN_ERROR) return true;
return false;
}
}
bool
check(TokenType type)
{
return parser.current.type == type;
}
bool
consume(TokenType type)
{
if(check(type)) {
advance();
return true;
}
return false;
}
bool
match(TokenType type)
{
if(!check(type)) return false;
advance();
return true;
}
void
expect(TokenType type)
{
if(!consume(type)) {
emitter.error(parser.previous.start, parser.previous.length,
parser.previous.line);
}
}
u32 variable_declaration(Symbol *def);
void
define_plex()
{
}
void
define_trait()
{
}
void
define_function()
{
Symbol *fn;
u32 size = 0;
advance();
fn = scope_add_symbol(parser.previous.start, parser.previous.length,
SYMBOL_FUNCTION, 0);
/* need to push scope early because the variables need to be a part of the fn
* scope */
scope_new();
expect(TOKEN_LPAREN);
advance();
/* parse the args */
while(!check(TOKEN_LBRACE)) {
size += variable_declaration(fn);
advance();
if(check(TOKEN_LBRACE)) break;
advance();
}
if(is_type()) {
/* get return slot */
fn->secondary_type = token_type_to_sym_type(parser.previous.type);
/* now parse the fn body */
}
expect(TOKEN_LBRACE);
/* get the size of all the locals for the function in the body */
while(parser.depth > 0) {
if(match(TOKEN_LBRACE)) {
scope_new();
continue;
} else if(match(TOKEN_RBRACE)) {
scope_pop();
continue;
} else if(is_type() && parser.current.type == TOKEN_IDENTIFIER)
size += variable_declaration(nil);
advance();
}
fn->size = size;
}
void
calculate_strides(List *dims, List *strides)
{
u32 *num;
u32 i;
u32 num_dims = dims->count;
u32 current_stride = 1;
if (num_dims == 1) {
List_push(arena, strides, &current_stride, sizeof(u32));
return;
}
for(i = num_dims - 1; i > 0; i--) {
List_push(arena, strides, &current_stride, sizeof(u32));
/* this is very slow but for small numbers of dimensions its fine */
num = (u32*)List_get(dims, i);
if (num){
current_stride *= (*num);
} else {
emitter.error("Tried to get a dimension that did not exist", 43, parser.previous.line);
}
}
}
void
define_array()
{
i32 size = 0, n = 0, flat_array_length = 1;
TokenType tt = parser.previous.type;
SymbolType st = token_type_to_sym_type(tt);
Symbol *array;
List *dims = List_init(arena);
List *strides = List_init(arena);
advance();
while(!match(TOKEN_RBRACKET)) {
if(parser.current.type == TOKEN_LITERAL_INT) {
n = ston(parser.current.start, parser.current.length);
flat_array_length *= n;
List_push(arena, dims, &n, sizeof(u32));
}
advance();
if(check(TOKEN_LBRACKET)) break;
if(check(TOKEN_COMMA)) {
/* it is a multidimensional array */
}
}
size = emitter.get_size(st) * flat_array_length;
array = scope_add_symbol(parser.current.start, parser.current.length,
SYMBOL_ARRAY, size);
array->secondary_type = st;
calculate_strides(dims, strides);
array->args = dims;
array->fields = strides;
}
void
build_symbol_table(char *source)
{
init_lexer(source);
advance();
scopes_init();
while(!match(TOKEN_EOF)) {
if(match(TOKEN_LBRACE)) {
scope_new();
} else if(match(TOKEN_RBRACE)) {
scope_pop();
} else if(match(TOKEN_KEYWORD_FN)) {
define_function();
} else if(match(TOKEN_KEYWORD_PLEX)) {
define_plex();
} else if(match(TOKEN_KEYWORD_TRAIT)) {
define_trait();
} else if (parser.current.type >= TOKEN_TYPE_I8 &&
parser.current.type <= TOKEN_TYPE_PTR) {
advance();
if (check(TOKEN_LBRACKET)) {
define_array();
}
} else {
/* in binary bytecode output mode we need to count the bytes here */
/* otherwise ignore everything */
advance();
}
}
}
void expression();
void statement();
void declaration();
ParseRule *get_rule(TokenType type);
void parse_precedence(Precedence precedence);
/**
FIXME: we need to move the string to be on the heap instead of the stack
so we need special handling in variable_dec
During the first pass we need to append the string label @variable
and then the hexed out literal.
every time we reference the string we should reference the global ptr.
If the string gets appended then we should copy and use the local varaiable
but for string conts or array conts we should use the global ref '@'
*/
u32
variable_declaration(Symbol *def)
{
i32 size = 0;
TokenType tt = parser.previous.type;
SymbolType st = token_type_to_sym_type(tt);
Symbol *variable;
List *array_literal;
if (parser.current.type == TOKEN_LBRACE) {
while(!check(TOKEN_RBRACKET)) {
advance();
}
variable = scope_get_symbol(parser.current_scope,
parser.previous.start,
parser.previous.length);
if (match(TOKEN_EQ)) {
expect(TOKEN_LBRACKET);
while (!match(TOKEN_RBRACKET)) {
StrBuf_append_exactly(arena, array_literal,
(char*)parser.previous.start,
parser.previous.length);
if(match(TOKEN_RBRACKET)) break;
expect(TOKEN_COMMA);
}
}
expect(TOKEN_SEMICOLON);
emitter.emit_array(arena, memory, variable, array_literal);
return variable->size;
}
if(st != SYMBOL_UNDEFINED) {
size = emitter.get_size(st);
variable = scope_add_symbol(parser.current.start, parser.current.length, st, size);
if(!def && (parser.pass == 0)) return size;
if(def) {
List_push(arena, def->args, variable, sizeof(Symbol));
} else {
emitter.emit_type(arena, code, variable, parser.depth);
parser.current_type = st;
}
} else {
/* we need to look up the type */
emitter.error("Not implemented", 16, parser.previous.line);
}
advance();
if(def && (check(TOKEN_COMMA) || check(TOKEN_RPAREN))) return size;
if(def)
emitter.error(parser.previous.start, parser.previous.length,
parser.previous.line);
if(parser.pass == 0) return size;
if(match(TOKEN_EQ)) {
emitter.emit_set_value(arena, code);
expression();
emitter.emit_constant(arena, code, variable, parser.depth);
}
consume(TOKEN_SEMICOLON);
emitter.emit_end_statement(arena, code);
parser.current_type = SYMBOL_UNDEFINED;
return size;
}
void
binary()
{
TokenType operatorType = parser.previous.type;
ParseRule *rule = get_rule(operatorType);
parse_precedence((Precedence)(rule->precedence + 1));
switch(operatorType) {
case TOKEN_BANG_EQ:
emitter.emit_ne(arena, code);
break;
case TOKEN_EQ_EQ:
emitter.emit_eq(arena, code);
break;
case TOKEN_GT:
emitter.emit_gt(arena, code);
break;
case TOKEN_GTE:
emitter.emit_ge(arena, code);
break;
case TOKEN_LT:
emitter.emit_lt(arena, code);
break;
case TOKEN_LTE:
emitter.emit_le(arena, code);
break;
case TOKEN_PLUS:
emitter.emit_add(arena, code);
break;
case TOKEN_MINUS:
emitter.emit_sub(arena, code);
break;
case TOKEN_STAR:
emitter.emit_mul(arena, code);
break;
case TOKEN_SLASH:
emitter.emit_div(arena, code);
break;
case TOKEN_OPERATOR_AND:
emitter.emit_and(arena, code);
break;
case TOKEN_OPERATOR_OR:
emitter.emit_or(arena, code);
break;
case TOKEN_OPERATOR_XOR:
emitter.emit_xor(arena, code);
break;
case TOKEN_OPERATOR_MOD:
emitter.emit_mod(arena, code);
break;
case TOKEN_SLL:
emitter.emit_sll(arena, code);
break;
case TOKEN_SRL:
emitter.emit_srl(arena, code);
break;
default:
return;
}
}
void
literal()
{
switch(parser.previous.type) {
case TOKEN_KEYWORD_FALSE:
emitter.emit_false(arena, code);
break;
case TOKEN_KEYWORD_TRUE:
emitter.emit_true(arena, code);
break;
case TOKEN_KEYWORD_NIL:
emitter.emit_nil(arena, code);
break;
default:
return;
}
}
void
expression()
{
parse_precedence(PREC_ASSIGNMENT);
}
void
variable()
{
Symbol *sym = scope_get_symbol(parser.current_scope, parser.previous.start,
parser.previous.length);
if(sym == nil) {
emitter.error(parser.previous.start, parser.previous.length,
parser.previous.line);
}
if(sym->type == SYMBOL_FUNCTION) {
parser.call_fn = sym;
return;
}
parser.current_type = sym->type;
if(match(TOKEN_EQ)) {
expression();
emitter.emit_set_variable(arena, code, sym, sym->scope);
} else {
emitter.emit_variable(arena, code, sym, sym->scope);
}
}
void
cast_type()
{
SymbolType st = parser.current_type;
TokenType cast_type;
if(!(parser.current.type >= TOKEN_TYPE_I8 &&
parser.current.type <= TOKEN_TYPE_PTR)) {
emitter.error("Expect type name after 'as'.", 26, parser.current.line);
return;
}
cast_type = parser.current.type;
advance();
switch(st) {
case SYMBOL_INT: {
switch(cast_type) {
case TOKEN_TYPE_NAT: {
emitter.emit_cast_int_to_nat(arena, code);
break;
}
case TOKEN_TYPE_REAL: {
emitter.emit_cast_int_to_real(arena, code);
break;
}
case TOKEN_TYPE_STR: {
emitter.emit_cast_int_to_str(arena, code);
break;
}
default:
emitter.error("Not castable to int", 19, parser.previous.line);
}
break;
}
case SYMBOL_NAT: {
switch(cast_type) {
case TOKEN_TYPE_INT: {
emitter.emit_cast_nat_to_int(arena, code);
break;
}
case TOKEN_TYPE_REAL: {
emitter.emit_cast_nat_to_real(arena, code);
break;
}
case TOKEN_TYPE_STR: {
emitter.emit_cast_nat_to_str(arena, code);
break;
}
default:
emitter.error("Not castable to nat", 19, parser.previous.line);
}
break;
}
case SYMBOL_REAL: {
switch(cast_type) {
case TOKEN_TYPE_NAT: {
emitter.emit_cast_real_to_nat(arena, code);
break;
}
case TOKEN_TYPE_INT: {
emitter.emit_cast_real_to_int(arena, code);
break;
}
case TOKEN_TYPE_STR: {
emitter.emit_cast_real_to_str(arena, code);
break;
}
default:
emitter.error("Not castable to real", 20, parser.previous.line);
}
break;
}
case SYMBOL_STR: {
switch(cast_type) {
case TOKEN_TYPE_NAT: {
emitter.emit_cast_str_to_nat(arena, code);
break;
}
case TOKEN_TYPE_REAL: {
emitter.emit_cast_str_to_real(arena, code);
break;
}
case TOKEN_TYPE_INT: {
emitter.emit_cast_str_to_int(arena, code);
break;
}
default:
emitter.error("Not castable to str", 19, parser.previous.line);
}
break;
}
default:
emitter.error("Type cast not implemented for this type (oops)", 46, parser.previous.line);
}
}
void
declaration()
{
if(is_type() && parser.current.type == TOKEN_IDENTIFIER)
variable_declaration(nil);
else
statement();
}
void
print_statement()
{
expression();
consume(TOKEN_SEMICOLON);
emitter.emit_print(arena, code);
emitter.emit_end_statement(arena, code);
}
void
if_statement()
{
consume(TOKEN_LPAREN);
expression();
consume(TOKEN_RPAREN);
emitter.emit_if(arena, code);
statement();
emitter.emit_patch_if(arena, code, emitter.ifs);
if(match(TOKEN_KEYWORD_ELSE)) {
emitter.else_if_depth++;
statement();
emitter.else_if_depth--;
}
if(emitter.else_if_depth == 0) emitter.emit_patch_if_done(arena, code, emitter.ifs++);
}
void
while_statement()
{
emitter.emit_while(arena, code, emitter.loops);
consume(TOKEN_LPAREN);
expression();
consume(TOKEN_RPAREN);
emitter.emit_while_postfix(arena, code);
statement();
emitter.emit_patch_while(arena, code, emitter.loops++);
}
void
block()
{
while(!check(TOKEN_RBRACE) && !check(TOKEN_EOF)) declaration();
consume(TOKEN_RBRACE);
}
void
function()
{
Symbol *sym = scope_get_symbol(parser.current_scope, parser.previous.start,
parser.previous.length);
emitter.emit_function(arena, code, sym);
scope_push();
while(!check(TOKEN_RPAREN)) advance();
consume(TOKEN_RPAREN);
consume(TOKEN_LBRACE);
block();
emitter.emit_arena_fn_return(arena, code);
}
void
call()
{
if(!check(TOKEN_RPAREN)) {
do {
expression();
} while(match(TOKEN_COMMA));
}
consume(TOKEN_RPAREN);
emitter.emit_arena_fn_call(arena, code, parser.call_fn);
parser.current_type = parser.call_fn->secondary_type;
return;
}
void
return_statement()
{
if(match(TOKEN_SEMICOLON)) {
emitter.emit_early_return(arena, code);
} else {
expression();
consume(TOKEN_SEMICOLON);
emitter.emit_early_return(arena, code);
}
}
void
statement()
{
if(match(TOKEN_LBRACE)) {
scope_push();
block();
scope_pop();
} else if(match(TOKEN_KEYWORD_FN)) {
advance();
function();
} else if(match(TOKEN_KEYWORD_RETURN)) {
return_statement();
} else if(match(TOKEN_KEYWORD_IF)) {
if_statement();
} else if(match(TOKEN_KEYWORD_WHILE)) {
while_statement();
} else if(match(TOKEN_KEYWORD_PRINT)) {
print_statement();
} else if(match(TOKEN_KEYWORD_HALT)) {
emitter.emit_halt(arena, code);
} else {
expression();
}
}
void
grouping()
{
emitter.emit_open_paren(arena, code);
expression();
emitter.emit_close_paren(arena, code);
consume(TOKEN_RPAREN);
}
void
number()
{
emitter.emit_int(arena, code, parser.previous.start, parser.previous.length);
}
void
string()
{
emitter.emit_str(arena, code, parser.previous.start, parser.previous.length);
}
void
unary()
{
TokenType operatorType = parser.previous.type;
parse_precedence(PREC_UNARY);
switch(operatorType) {
case TOKEN_MINUS:
emitter.emit_neg(arena, code);
break;
case TOKEN_BANG:
emitter.emit_not(arena, code);
break;
default:
return;
}
}
ParseRule rules[] = {
/* TOKEN_ERROR */ {nil, nil, PREC_NONE},
/* TOKEN_EOF */ {nil, nil, PREC_NONE},
/* TOKEN_LPAREN */ {grouping, call, PREC_CALL},
/* TOKEN_RPAREN */ {nil, nil, PREC_NONE},
/* TOKEN_LBRACE */ {nil, nil, PREC_NONE},
/* TOKEN_RBRACE */ {nil, nil, PREC_NONE},
/* TOKEN_LBRACKET */ {nil, nil, PREC_NONE},
/* TOKEN_RBRACKET */ {nil, nil, PREC_NONE},
/* TOKEN_IDENTIFIER */ {variable, nil, PREC_NONE},
/* TOKEN_LITERAL_INT */ {number, nil, PREC_NONE},
/* TOKEN_LITERAL_NAT */ {number, nil, PREC_NONE},
/* TOKEN_LITERAL_REAL */ {number, nil, PREC_NONE},
/* TOKEN_LITERAL_STR */ {string, nil, PREC_NONE},
/* TOKEN_TYPE_I8 */ {nil, nil, PREC_NONE},
/* TOKEN_TYPE_I16 */ {nil, nil, PREC_NONE},
/* TOKEN_TYPE_INT */ {nil, nil, PREC_NONE},
/* TOKEN_TYPE_U8 */ {nil, nil, PREC_NONE},
/* TOKEN_TYPE_U16 */ {nil, nil, PREC_NONE},
/* TOKEN_TYPE_NAT */ {nil, nil, PREC_NONE},
/* TOKEN_TYPE_REAL */ {nil, nil, PREC_NONE},
/* TOKEN_TYPE_STR */ {nil, nil, PREC_NONE},
/* TOKEN_TYPE_BOOL */ {nil, nil, PREC_NONE},
/* TOKEN_TYPE_BYTE */ {nil, nil, PREC_NONE},
/* TOKEN_TYPE_VOID */ {nil, nil, PREC_NONE},
/* TOKEN_TYPE_PTR */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_PLEX */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_FN */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_CONST */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_IF */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_IS */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_AS */ {nil, cast_type, PREC_CAST},
/* TOKEN_KEYWORD_ELSE */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_WHILE */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_FOR */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_RETURN */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_USE */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_INIT */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_THIS */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_OPEN */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_READ */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_WRITE */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_STAT */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_CLOSE */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_LOOP */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_DO */ {nil, nil, PREC_NONE},
/* TOKEN_KEYWORD_NIL */ {literal, nil, PREC_NONE},
/* TOKEN_KEYWORD_TRUE */ {literal, nil, PREC_NONE},
/* TOKEN_KEYWORD_FALSE */ {literal, nil, PREC_NONE},
/* TOKEN_OPERATOR_AND */ {nil, binary, PREC_NONE},
/* TOKEN_OPERATOR_OR */ {nil, binary, PREC_NONE},
/* TOKEN_OPERATOR_XOR */ {nil, binary, PREC_NONE},
/* TOKEN_OPERATOR_MOD */ {nil, binary, PREC_NONE},
/* TOKEN_BANG */ {unary, nil, PREC_NONE},
/* TOKEN_BANG_EQ */ {nil, binary, PREC_EQUALITY},
/* TOKEN_EQ */ {nil, nil, PREC_NONE},
/* TOKEN_EQ_EQ */ {nil, binary, PREC_EQUALITY},
/* TOKEN_AND */ {nil, nil, PREC_NONE},
/* TOKEN_AND_AND */ {nil, nil, PREC_NONE},
/* TOKEN_PIPE */ {nil, nil, PREC_NONE},
/* TOKEN_PIPE_PIPE */ {nil, nil, PREC_NONE},
/* TOKEN_QUESTION */ {nil, nil, PREC_NONE},
/* TOKEN_QUESTION_DOT */ {nil, nil, PREC_NONE},
/* TOKEN_PLUS */ {nil, binary, PREC_TERM},
/* TOKEN_MINUS */ {unary, binary, PREC_TERM},
/* TOKEN_STAR */ {nil, binary, PREC_FACTOR},
/* TOKEN_SLASH */ {nil, binary, PREC_FACTOR},
/* TOKEN_MESH */ {nil, nil, PREC_NONE},
/* TOKEN_BIG_MONEY */ {nil, nil, PREC_NONE},
/* TOKEN_GT */ {nil, binary, PREC_COMPARISON},
/* TOKEN_LT */ {nil, binary, PREC_COMPARISON},
/* TOKEN_GTE */ {nil, binary, PREC_COMPARISON},
/* TOKEN_LTE */ {nil, binary, PREC_COMPARISON},
/* TOKEN_DOT */ {nil, nil, PREC_NONE},
/* TOKEN_COMMA */ {nil, nil, PREC_NONE},
/* TOKEN_COLON */ {nil, nil, PREC_NONE},
/* TOKEN_CARET */ {nil, nil, PREC_NONE},
/* TOKEN_SEMICOLON */ {nil, nil, PREC_NONE},
/* TOKEN_ARROW_RIGHT */ {nil, nil, PREC_NONE},
/* TOKEN_SLL */ {nil, binary, PREC_NONE},
/* TOKEN_SRL */ {nil, binary, PREC_NONE},
/* TOKEN_KEYWORD_PRINT*/ {nil, binary, PREC_NONE}};
void
parse_precedence(Precedence precedence)
{
ParseFn prefixRule;
ParseFn infixRule;
advance();
prefixRule = get_rule(parser.previous.type)->prefix;
if(prefixRule == nil) return;
prefixRule();
while(precedence <= get_rule(parser.current.type)->precedence) {
advance();
infixRule = get_rule(parser.previous.type)->infix;
infixRule();
}
}
ParseRule *
get_rule(TokenType type)
{
return &rules[type];
}
void
emit_program(char *source)
{
init_lexer(source);
advance();
emitter.prolog(arena, code);
emitter.epilogue(arena, memory);
while(!match(TOKEN_EOF)) declaration();
}
bool
compile(Arena *a, List *c, List* m, Emitter e, char *source)
{
arena = a;
emitter = e;
code = c;
memory = m;
parser.scopes = List_init(arena);
build_symbol_table(source);
parser.pass++;
parser.scope_idx = 0;
emit_program(source);
return true;
}