1151 lines
26 KiB
C
1151 lines
26 KiB
C
#include "compiler.h"
|
|
#include "common.h"
|
|
#include "emit.h"
|
|
#include "lexer.h"
|
|
#include "libc.h"
|
|
#include "list.h"
|
|
|
|
Parser *parser;
|
|
Emitter *emitter;
|
|
Arena *arena;
|
|
List *code;
|
|
List *memory;
|
|
|
|
/****************************************************
|
|
* Scope
|
|
***************************************************/
|
|
void
|
|
scopes_init(void)
|
|
{
|
|
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(void)
|
|
{
|
|
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(void)
|
|
{
|
|
if(parser->current_scope) {
|
|
parser->current_scope = parser->current_scope->parent;
|
|
parser->depth--;
|
|
}
|
|
}
|
|
|
|
void
|
|
scope_push(void)
|
|
{
|
|
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(void)
|
|
{
|
|
return parser->current_scope != nil && parser->current_scope->parent == nil;
|
|
}
|
|
|
|
bool
|
|
is_type(void)
|
|
{
|
|
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(void)
|
|
{
|
|
parser->before = parser->previous;
|
|
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_is_type(void)
|
|
{
|
|
if(is_type()) {
|
|
advance();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
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)
|
|
{
|
|
}
|
|
|
|
void
|
|
define_trait(void)
|
|
{
|
|
}
|
|
|
|
void
|
|
define_function(void)
|
|
{
|
|
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(!match(TOKEN_RPAREN)) {
|
|
size += variable_declaration(fn);
|
|
if(match(TOKEN_RPAREN)) break;
|
|
}
|
|
|
|
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, ¤t_stride, sizeof(u32));
|
|
return;
|
|
}
|
|
|
|
for(i = num_dims - 1; i > 0; i--) {
|
|
List_push(arena, strides, ¤t_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(void)
|
|
{
|
|
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
|
|
define_string(void)
|
|
{
|
|
scope_add_symbol(parser->current.start, parser->current.length, SYMBOL_STR,
|
|
0);
|
|
}
|
|
|
|
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->previous.type != TOKEN_KEYWORD_AS &&
|
|
match(TOKEN_TYPE_STR)) {
|
|
define_string();
|
|
} 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);
|
|
void statement(void);
|
|
void declaration(void);
|
|
ParseRule *get_rule(TokenType type);
|
|
void parse_precedence(Precedence precedence);
|
|
|
|
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(tt == TOKEN_TYPE_STR) {
|
|
variable = scope_get_symbol(parser->current_scope, parser->current.start,
|
|
parser->current.length);
|
|
if(!variable) {
|
|
emitter->error("cannot find str symbol", 23, parser->current.line);
|
|
return 0;
|
|
}
|
|
advance();
|
|
|
|
if(match(TOKEN_EQ)) {
|
|
expect(TOKEN_LITERAL_STR);
|
|
variable->size = parser->previous.length - 2;
|
|
emitter->emit_str(arena, memory, variable, parser->previous.start,
|
|
parser->previous.length);
|
|
expect(TOKEN_SEMICOLON);
|
|
}
|
|
|
|
parser->current_type = st;
|
|
return emitter->get_size(st);
|
|
}
|
|
|
|
if(parser->current.type == TOKEN_LBRACKET) {
|
|
while(!check(TOKEN_RBRACKET)) advance();
|
|
advance();
|
|
|
|
variable = scope_get_symbol(parser->current_scope, parser->current.start,
|
|
parser->current.length);
|
|
if(!variable) {
|
|
emitter->error("cannot find array symbol", 25, parser->current.line);
|
|
return 0;
|
|
}
|
|
advance();
|
|
|
|
if(match(TOKEN_EQ)) {
|
|
expect(TOKEN_LBRACKET);
|
|
array_literal = List_init(arena);
|
|
|
|
while(!match(TOKEN_RBRACKET)) {
|
|
StrBuf_append_exactly(arena, array_literal,
|
|
(char *)parser->current.start,
|
|
parser->current.length);
|
|
advance();
|
|
if(match(TOKEN_RBRACKET)) break;
|
|
expect(TOKEN_COMMA);
|
|
}
|
|
|
|
expect(TOKEN_SEMICOLON);
|
|
emitter->emit_array(arena, memory, variable, array_literal);
|
|
} else {
|
|
expect(TOKEN_SEMICOLON);
|
|
|
|
emitter->emit_array(arena, memory, variable, nil);
|
|
emitter->emit_zero_block(arena, memory,
|
|
variable->size *
|
|
emitter->get_size(variable->secondary_type));
|
|
}
|
|
|
|
parser->current_type = st;
|
|
return emitter->get_size(st);
|
|
}
|
|
|
|
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(void)
|
|
{
|
|
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, emitter->get_size(parser->current_type));
|
|
break;
|
|
case TOKEN_EQ_EQ:
|
|
emitter->emit_eq(arena, code, emitter->get_size(parser->current_type));
|
|
break;
|
|
case TOKEN_GT:
|
|
emitter->emit_gt(arena, code, emitter->get_size(parser->current_type));
|
|
break;
|
|
case TOKEN_GTE:
|
|
emitter->emit_ge(arena, code, emitter->get_size(parser->current_type));
|
|
break;
|
|
case TOKEN_LT:
|
|
emitter->emit_lt(arena, code, emitter->get_size(parser->current_type));
|
|
break;
|
|
case TOKEN_LTE:
|
|
emitter->emit_le(arena, code, emitter->get_size(parser->current_type));
|
|
break;
|
|
case TOKEN_PLUS:
|
|
emitter->emit_add(arena, code, emitter->get_size(parser->current_type));
|
|
break;
|
|
case TOKEN_MINUS:
|
|
emitter->emit_sub(arena, code, emitter->get_size(parser->current_type));
|
|
break;
|
|
case TOKEN_STAR:
|
|
emitter->emit_mul(arena, code, emitter->get_size(parser->current_type));
|
|
break;
|
|
case TOKEN_SLASH:
|
|
emitter->emit_div(arena, code, emitter->get_size(parser->current_type));
|
|
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(void)
|
|
{
|
|
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(void)
|
|
{
|
|
parse_precedence(PREC_ASSIGNMENT);
|
|
}
|
|
|
|
void
|
|
dot(void)
|
|
{
|
|
Symbol *sym = scope_get_symbol(parser->current_scope, parser->before.start,
|
|
parser->before.length);
|
|
if(sym == nil) {
|
|
emitter->error(parser->current.start, parser->current.length,
|
|
parser->current.line);
|
|
}
|
|
}
|
|
|
|
void
|
|
variable(void)
|
|
{
|
|
Symbol *sym = scope_get_symbol(parser->current_scope, parser->previous.start,
|
|
parser->previous.length);
|
|
if(sym == nil) {
|
|
return;
|
|
emitter->error(parser->previous.start, parser->previous.length,
|
|
parser->previous.line);
|
|
}
|
|
|
|
if(sym->type == SYMBOL_FUNCTION) {
|
|
parser->call_fn = sym;
|
|
return;
|
|
}
|
|
|
|
if(sym->type == SYMBOL_STR) {
|
|
emitter->emit_deref_prolog(arena, code, sym);
|
|
|
|
if(match(TOKEN_LBRACKET)) {
|
|
/* add offset of "length"*/
|
|
emitter->emit_nat(arena, code, "2", 1);
|
|
emitter->emit_add(arena, code, 2);
|
|
expression();
|
|
emitter->emit_add(arena, code, 2);
|
|
while(!match(TOKEN_RBRACKET)) {
|
|
}
|
|
|
|
if(match(TOKEN_EQ)) {
|
|
expression();
|
|
|
|
emitter->emit_stack_rot(arena, code, 1);
|
|
emitter->emit_stack_rot(arena, code, 1);
|
|
emitter->emit_ref_store(arena, code, 1);
|
|
} else {
|
|
emitter->emit_deref(arena, code, 1);
|
|
}
|
|
|
|
parser->current_type = SYMBOL_BYTE;
|
|
} else if(match(TOKEN_DOT)) {
|
|
if(sleq("length", parser->current.start, parser->current.length)) {
|
|
emitter->emit_deref(arena, code, 2);
|
|
} else {
|
|
emitter->error("arrays currently can only get their length, don't do "
|
|
"anything fancy yet...",
|
|
75, parser->current.line);
|
|
}
|
|
parser->current_type = SYMBOL_NAT;
|
|
advance();
|
|
} else {
|
|
emitter->emit_nat(arena, code, "2", 1);
|
|
emitter->emit_add(arena, code, 2);
|
|
/* emitter->emit_deref(arena, code); */
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if(sym->type == SYMBOL_ARRAY) {
|
|
u32 size = emitter->get_size(sym->secondary_type);
|
|
|
|
if(match(TOKEN_LBRACKET)) {
|
|
emitter->emit_deref_prolog(arena, code, sym);
|
|
expression();
|
|
emitter->emit_address(arena, code, 2);
|
|
emitter->emit_mul(arena, code, 2);
|
|
emitter->emit_add(arena, code, 2);
|
|
/* add offset of "length"*/
|
|
emitter->emit_nat(arena, code, "2", 1);
|
|
emitter->emit_add(arena, code, 2);
|
|
|
|
while(!match(TOKEN_RBRACKET)) {
|
|
/* eventually do something with multidimensional arrays */
|
|
}
|
|
|
|
if(match(TOKEN_EQ)) {
|
|
expression();
|
|
if(size == 1) {
|
|
emitter->emit_stack_rot(arena, code, 1);
|
|
emitter->emit_stack_rot(arena, code, 1);
|
|
} else {
|
|
emitter->emit_stack_swap(arena, code, 2);
|
|
}
|
|
emitter->emit_ref_store(arena, code, size);
|
|
} else {
|
|
emitter->emit_deref(arena, code, size);
|
|
}
|
|
parser->current_type = sym->secondary_type;
|
|
|
|
} else if(match(TOKEN_DOT)) {
|
|
emitter->emit_deref_prolog(arena, code, sym);
|
|
if(sleq("length", parser->current.start, parser->current.length)) {
|
|
emitter->emit_deref(arena, code, size);
|
|
} else {
|
|
emitter->error("arrays currently can only get their length, don't do "
|
|
"anything fancy yet...",
|
|
75, parser->current.line);
|
|
}
|
|
parser->current_type = SYMBOL_NAT;
|
|
advance();
|
|
}
|
|
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(void)
|
|
{
|
|
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(void)
|
|
{
|
|
if(is_type() && (parser->current.type == TOKEN_IDENTIFIER ||
|
|
parser->current.type == TOKEN_LBRACKET))
|
|
variable_declaration(nil);
|
|
else
|
|
statement();
|
|
}
|
|
|
|
void
|
|
print_statement(void)
|
|
{
|
|
expression();
|
|
consume(TOKEN_SEMICOLON);
|
|
emitter->emit_print(arena, code);
|
|
emitter->emit_end_statement(arena, code);
|
|
}
|
|
|
|
void
|
|
if_statement(void)
|
|
{
|
|
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(void)
|
|
{
|
|
u32 this_while = emitter->loops++;
|
|
emitter->emit_while(arena, code, this_while);
|
|
consume(TOKEN_LPAREN);
|
|
expression();
|
|
consume(TOKEN_RPAREN);
|
|
emitter->emit_while_postfix(arena, code);
|
|
statement();
|
|
emitter->emit_patch_while(arena, code, this_while);
|
|
}
|
|
|
|
void
|
|
block(void)
|
|
{
|
|
while(!check(TOKEN_RBRACE) && !check(TOKEN_EOF)) declaration();
|
|
|
|
consume(TOKEN_RBRACE);
|
|
}
|
|
|
|
void
|
|
function(void)
|
|
{
|
|
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(void)
|
|
{
|
|
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(void)
|
|
{
|
|
if(match(TOKEN_SEMICOLON)) {
|
|
emitter->emit_early_return(arena, code);
|
|
} else {
|
|
expression();
|
|
consume(TOKEN_SEMICOLON);
|
|
emitter->emit_early_return(arena, code);
|
|
}
|
|
}
|
|
|
|
void
|
|
statement(void)
|
|
{
|
|
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(void)
|
|
{
|
|
emitter->emit_open_paren(arena, code);
|
|
|
|
expression();
|
|
|
|
emitter->emit_close_paren(arena, code);
|
|
consume(TOKEN_RPAREN);
|
|
}
|
|
|
|
void
|
|
number(void)
|
|
{
|
|
switch(parser->current_type) {
|
|
case SYMBOL_BOOL:
|
|
case SYMBOL_BYTE:
|
|
case SYMBOL_U8:
|
|
case SYMBOL_I8:
|
|
emitter->emit_char(arena, code, parser->previous.start,
|
|
parser->previous.length);
|
|
break;
|
|
default:
|
|
emitter->emit_nat(arena, code, parser->previous.start,
|
|
parser->previous.length);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
string(void)
|
|
{
|
|
emitter->emit_inline_str(arena, code, parser->previous.start,
|
|
parser->previous.length);
|
|
}
|
|
|
|
void
|
|
character(void)
|
|
{
|
|
emitter->emit_char(arena, code, parser->previous.start,
|
|
parser->previous.length);
|
|
}
|
|
|
|
void
|
|
unary(void)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
void
|
|
read(void)
|
|
{
|
|
emitter->emit_read(arena, code);
|
|
}
|
|
|
|
void
|
|
write(void)
|
|
{
|
|
consume(TOKEN_EQ);
|
|
expression();
|
|
emitter->emit_write(arena, code);
|
|
}
|
|
|
|
void
|
|
semicolon(void)
|
|
{
|
|
emitter->emit_end_statement(arena, code);
|
|
}
|
|
|
|
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_DOT */ {nil, dot, PREC_CALL},
|
|
/* 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 */ {read, nil, PREC_NONE},
|
|
/* TOKEN_KEYWORD_WRITE */ {write, 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_COMMA */ {nil, nil, PREC_NONE},
|
|
/* TOKEN_COLON */ {nil, nil, PREC_NONE},
|
|
/* TOKEN_CARET */ {nil, nil, PREC_NONE},
|
|
/* TOKEN_SEMICOLON */ {semicolon, 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},
|
|
/* TOKEN_KEYWORD_TRAIT*/ {nil, nil, PREC_NONE},
|
|
/* TOKEN_KEYWORD_HALT*/ {nil, nil, PREC_NONE},
|
|
/* TOKEN_KEYWORD_DEVMAP*/ {nil, nil, PREC_NONE},
|
|
/* TOKEN_KEYWORD_BYTE*/ {nil, nil, PREC_NONE},
|
|
/* TOKEN_KEYWORD_CHAR*/ {character, nil, 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);
|
|
|
|
while(!match(TOKEN_EOF)) declaration();
|
|
|
|
/*emitter->epilogue(arena, code);*/
|
|
}
|
|
|
|
bool
|
|
compile(Arena *a, List *c, List *m, Emitter *e, char *source)
|
|
{
|
|
Parser p = {0};
|
|
arena = a;
|
|
emitter = e;
|
|
code = c;
|
|
memory = m;
|
|
parser = &p;
|
|
parser->scopes = List_init(arena);
|
|
|
|
build_symbol_table(source);
|
|
parser->pass++;
|
|
parser->depth = 0;
|
|
parser->scope_idx = 0;
|
|
emit_program(source);
|
|
|
|
return true;
|
|
}
|