556 lines
16 KiB
C++
556 lines
16 KiB
C++
#define Ast_Begin(kind,type) case kind: { type *node = (type *)ast;
|
|
#define Ast_End() } break
|
|
|
|
enum Sym_Kind{
|
|
SYM_NONE,
|
|
SYM_TYPE,
|
|
SYM_CONST,
|
|
SYM_VAR,
|
|
};
|
|
|
|
enum Sym_State{
|
|
SYM_NOT_RESOLVED,
|
|
SYM_RESOLVING,
|
|
SYM_RESOLVED,
|
|
};
|
|
|
|
struct Sym{
|
|
Intern_String name;
|
|
Sym_Kind kind;
|
|
Sym_State state;
|
|
Ast *ast;
|
|
|
|
Ast_Resolved_Type *type;
|
|
union{
|
|
S64 int_val;
|
|
Intern_String intern_val;
|
|
};
|
|
};
|
|
|
|
struct Operand{
|
|
Ast_Resolved_Type *type;
|
|
bool is_const;
|
|
union {
|
|
S64 int_val;
|
|
Intern_String intern_val;
|
|
};
|
|
};
|
|
|
|
global Ast_Named empty_decl = {};
|
|
|
|
function void
|
|
sym_insert(Sym *sym){
|
|
U64 hash = hash_string(sym->name.s);
|
|
Sym *is_sym = (Sym *)map_get(&pctx->syms, hash);
|
|
if(is_sym){
|
|
parsing_error(sym->ast->pos, "Symbol with name: [%s] defined multiple times", sym->name.s.str);
|
|
}
|
|
if(pctx->scope > 0){
|
|
pctx->local_syms.add(sym);
|
|
}
|
|
|
|
map_insert(&pctx->syms, hash, sym);
|
|
}
|
|
|
|
function Sym *
|
|
sym_get(Intern_String name){
|
|
Sym *result = (Sym *)map_get(&pctx->syms, hash_string(name.s));
|
|
return result;
|
|
}
|
|
|
|
function S64
|
|
scope_push(){
|
|
S64 local_sym_count = pctx->local_syms.len;
|
|
pctx->scope++;
|
|
return local_sym_count;
|
|
}
|
|
|
|
function void
|
|
scope_pop(S64 local_sym_count){
|
|
pctx->scope--;
|
|
assert(pctx->scope >= 0);
|
|
for(S64 i = local_sym_count; i < pctx->local_syms.len; i++){
|
|
void *removed = map_remove(&pctx->syms, hash_string(pctx->local_syms.data[i]->name.s));
|
|
assert(removed);
|
|
}
|
|
pctx->local_syms.len = local_sym_count;
|
|
}
|
|
|
|
function Sym *
|
|
sym_new(Sym_Kind kind, Intern_String name, Ast *ast){
|
|
Sym *result = exp_alloc_type(pctx->perm, Sym, AF_ZeroMemory);
|
|
result->name = name;
|
|
result->kind = kind;
|
|
result->ast = ast;
|
|
assert(ast);
|
|
map_insert(&pctx->resolved, ast, result);
|
|
return result;
|
|
}
|
|
|
|
function Sym *
|
|
sym_new_resolved(Sym_Kind kind, Intern_String name, Ast_Resolved_Type *type, Ast *ast){
|
|
Sym *result = sym_new(kind, name, ast);
|
|
result->type = type;
|
|
result->state = SYM_RESOLVED;
|
|
return result;
|
|
}
|
|
|
|
function Sym *
|
|
resolved_get(Ast *ast){
|
|
Sym *result = (Sym *)map_get(&pctx->resolved, ast);
|
|
assert(result);
|
|
return result;
|
|
}
|
|
|
|
function void
|
|
sym_insert_builtin_type(String name, Ast_Resolved_Type *type){
|
|
Intern_String string = intern_string(&pctx->interns, name);
|
|
Sym *sym = sym_new_resolved(SYM_TYPE, string, type, &empty_decl);
|
|
sym_insert(sym);
|
|
}
|
|
|
|
function void
|
|
sym_insert_builtins(){
|
|
sym_insert_builtin_type("void"_s, type_void);
|
|
sym_insert_builtin_type("bool"_s, type_bool);
|
|
sym_insert_builtin_type("int"_s, type_int);
|
|
sym_insert_builtin_type("String"_s, type_string);
|
|
|
|
{
|
|
Intern_String string = intern_string(&pctx->interns, "true"_s);
|
|
Sym *sym = sym_new_resolved(SYM_CONST, string, type_bool, &empty_decl);
|
|
sym_insert(sym);
|
|
}
|
|
|
|
{
|
|
Intern_String string = intern_string(&pctx->interns, "false"_s);
|
|
Sym *sym = sym_new_resolved(SYM_CONST, string, type_bool, &empty_decl);
|
|
sym_insert(sym);
|
|
}
|
|
|
|
{
|
|
Intern_String string = intern_string(&pctx->interns, "null"_s);
|
|
Sym *sym = sym_new_resolved(SYM_CONST, string, type_null, &empty_decl);
|
|
sym_insert(sym);
|
|
}
|
|
}
|
|
|
|
function Sym *resolve_name(Token *pos, Intern_String name);
|
|
function Operand eval_expr(Ast_Expr *ast, Ast_Resolved_Type *compound_required_type = 0);
|
|
function Ast_Resolved_Type *
|
|
eval_typespec(Ast_Typespec *ast){
|
|
if(!ast) return 0;
|
|
|
|
switch(ast->kind){
|
|
Ast_Begin(AST_TYPESPEC_IDENT, Ast_Typespec){
|
|
Sym *type_sym = sym_get(node->name);
|
|
if(!type_sym){
|
|
parsing_error(node->pos, "This type is not defined");
|
|
}
|
|
if(type_sym->kind != SYM_TYPE){
|
|
parsing_error(node->pos, "This identifier is not a type");
|
|
}
|
|
|
|
node->resolved_type = type_sym->type;
|
|
return node->resolved_type;
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_TYPESPEC_LAMBDA, Ast_Typespec){
|
|
Scratch scratch;
|
|
Ast_Resolved_Type *ret = eval_typespec(node->lambda->ret);
|
|
Array<Ast_Resolved_Type *> args = {scratch};
|
|
For(node->lambda->args) args.add(eval_typespec(it[0]->typespec));
|
|
node->resolved_type = type_lambda(ret, args);
|
|
return node->resolved_type;
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_TYPESPEC_POINTER, Ast_Typespec){
|
|
Ast_Resolved_Type *type = eval_typespec(node->base);
|
|
node->resolved_type = type_pointer(type);
|
|
return node->resolved_type;
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_TYPESPEC_ARRAY, Ast_Typespec){
|
|
Ast_Resolved_Type *type = eval_typespec(node->arr.base);
|
|
Operand expr = eval_expr(node->arr.expr);
|
|
if(!expr.is_const) parsing_error(node->pos, "Array size is not a constant");
|
|
if(expr.type != type_int) parsing_error(node->pos, "Array size is expected to be of type [Int] is instead of type %s", type_names[expr.type->kind]);
|
|
node->resolved_type = type_array(type, expr.int_val);
|
|
return node->resolved_type;
|
|
Ast_End();
|
|
}
|
|
invalid_default_case;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
function Ast_Resolved_Type *
|
|
resolve_type_pair(Token *pos, Ast_Resolved_Type *a, Ast_Resolved_Type *b){
|
|
Ast_Resolved_Type *result = 0;
|
|
if(!a && b) result = b;
|
|
else if(a && !b) result = a;
|
|
else if(!a && !b) parsing_error(pos, "Trying to resolve a type pair where both types are [Null]");
|
|
else{ // a && b
|
|
if(b->kind == TYPE_Null) result = a;
|
|
else if(a->kind == TYPE_Null) result = b;
|
|
else if(a != b) parsing_error(pos, "Expression and type specification are differing %s %s", type_names[a->kind], type_names[b->kind]);
|
|
else result = a; // Types are the same
|
|
}
|
|
|
|
if(result->kind == TYPE_Null) parsing_error(pos, "Couldn't infer type of null value");
|
|
|
|
return result;
|
|
}
|
|
|
|
function Operand eval_decl(Ast *ast);
|
|
function void
|
|
eval_stmt(Ast *ast, Ast_Resolved_Type *ret){
|
|
switch(ast->kind){
|
|
Ast_Begin(AST_RETURN, Ast_Return){ // @todo: need to check if all paths return a value
|
|
Operand op = {};
|
|
if(node->expr) op = eval_expr(node->expr);
|
|
if(!op.type && ret != type_void) parsing_error(node->pos, "Function expects a void return value but the returned value is [x]");
|
|
if(op.type && op.type != ret) parsing_error(node->pos, "Return statement has different type then returned value");
|
|
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_VAR, Ast_Var){
|
|
Operand op = eval_decl(node);
|
|
Sym *sym = sym_new_resolved(SYM_VAR, node->name, op.type, node);
|
|
sym_insert(sym);
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_CONST, Ast_Const){
|
|
Operand op = eval_decl(node);
|
|
Sym *sym = sym_new_resolved(SYM_CONST, node->name, op.type, node);
|
|
sym_insert(sym);
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_INIT, Ast_Init){
|
|
switch(node->op){
|
|
case TK_Comma:{
|
|
Operand op = eval_expr(node->expr);
|
|
Sym *sym = sym_new_resolved(SYM_VAR, node->ident->intern_val, op.type, node);
|
|
sym_insert(sym);
|
|
}break;
|
|
invalid_default_case;
|
|
}
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_IF, Ast_If){
|
|
For(node->ifs){
|
|
if(it[0]->init) eval_stmt(it[0]->init, ret);
|
|
if(it[0]->expr) eval_expr(it[0]->expr);
|
|
S64 scope_index = scope_push();
|
|
For_It(it[0]->block->stmts, jt){
|
|
eval_stmt(jt[0], ret);
|
|
}
|
|
scope_pop(scope_index);
|
|
}
|
|
Ast_End();
|
|
}
|
|
|
|
invalid_default_case;
|
|
}
|
|
}
|
|
|
|
function Operand
|
|
eval_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type){
|
|
switch(ast->kind){
|
|
Ast_Begin(AST_INT, Ast_Atom){
|
|
Operand result = {type_int, true};
|
|
result.int_val = node->int_val;
|
|
return result;
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_STR, Ast_Atom){
|
|
Operand result = {type_string, true};
|
|
result.intern_val = node->intern_val;
|
|
return result;
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_IDENT, Ast_Atom){
|
|
Sym *sym = resolve_name(node->pos, node->intern_val);
|
|
|
|
// @note: check if null and rewrite the expression to match the expected type
|
|
Operand result = {};
|
|
if(sym->type->kind == TYPE_Null){
|
|
if(!expected_type) parsing_error(node->pos, "Couldn't infer type of null");
|
|
result.type = expected_type;
|
|
result.is_const = true;
|
|
if(expected_type == type_int){
|
|
result.int_val = 0;
|
|
node->kind = AST_INT;
|
|
node->int_val = 0;
|
|
}
|
|
else if(expected_type->kind == TYPE_Pointer){
|
|
result.int_val = 0;
|
|
node->kind = AST_IDENT;
|
|
node->intern_val = pctx->intern("NULL_POINTER"_s);
|
|
}
|
|
else if(expected_type->kind == TYPE_Lambda){
|
|
result.int_val = 0;
|
|
node->kind = AST_IDENT;
|
|
node->intern_val = pctx->intern("NULL_LAMBDA"_s);
|
|
}
|
|
else if(expected_type == type_bool){
|
|
result.int_val = 0;
|
|
node->kind = AST_IDENT;
|
|
node->intern_val = pctx->intern("false"_s);
|
|
}
|
|
else if(expected_type == type_string){
|
|
result.intern_val = pctx->intern(""_s);
|
|
node->kind = AST_STR;
|
|
node->intern_val = result.intern_val;
|
|
}
|
|
|
|
}
|
|
else{
|
|
result.type = sym->type;
|
|
result.is_const = sym->kind == SYM_CONST ? true : false;
|
|
result.int_val = sym->int_val;
|
|
}
|
|
|
|
return result;
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_LAMBDA, Ast_Lambda){
|
|
Ast_Resolved_Type *type = eval_typespec(ast_typespec_lambda(0, node));
|
|
|
|
// @todo: We also need to make sure there is a return value when ret type is not void
|
|
if(node->block){
|
|
S64 scope_index = scope_push();
|
|
For(node->args){
|
|
Ast_Resolved_Type *type = eval_typespec(it[0]->typespec);
|
|
Sym *arg_sym = sym_new_resolved(SYM_VAR, it[0]->name, type, it[0]);
|
|
sym_insert(arg_sym);
|
|
}
|
|
For(node->block->stmts){
|
|
eval_stmt(it[0], node->ret->resolved_type);
|
|
}
|
|
scope_pop(scope_index);
|
|
}
|
|
|
|
return {type, true};
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_INDEX, Ast_Index){
|
|
Operand left = eval_expr(node->expr);
|
|
Operand index = eval_expr(node->index);
|
|
if(left.type->kind != TYPE_Array) parsing_error(node->pos, "Indexing variable that is not an array");
|
|
if(index.type != type_int) parsing_error(node->pos, "Trying to index the array with invalid type, expected int");
|
|
Operand result = {left.type->arr.base};
|
|
return result;
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_COMPOUND, Ast_Compound){
|
|
Ast_Resolved_Type *type = eval_typespec(node->typespec);
|
|
Ast_Resolved_Type *variable_type = expected_type;
|
|
if(!type && variable_type) type = variable_type;
|
|
else if(!variable_type && type);
|
|
else if(variable_type != type) parsing_error(node->pos, "Variable type different from explicit compound type");
|
|
node->type = type;
|
|
|
|
if(type->kind == TYPE_Array){
|
|
if(node->exprs.len > type->arr.size) parsing_error(node->pos, "compound statement has too many items for this type");
|
|
Ast_Resolved_Type *item_type = type->arr.base;
|
|
|
|
For(node->exprs){
|
|
assert(it[0]->kind == AST_COMPOUND_ITEM);
|
|
Ast_Compound_Item *i = (Ast_Compound_Item *)it[0];
|
|
assert(i->kind == AST_COMPOUND_ITEM);
|
|
if(i->name) parsing_error(i->pos, "Invalid indexing kind in a compound expression of type %s", type_names[type->kind]);
|
|
if(i->index){
|
|
Operand index_op = eval_expr(i->index);
|
|
if(!index_op.is_const) parsing_error(i->pos, "Index in a compound expression is not a constant");
|
|
if(index_op.type != type_int) parsing_error(i->pos, "Index should be of type int");
|
|
if(index_op.int_val > (type->arr.size - 1)) parsing_error(i->pos, "Invalid index in compound expression, larger then type can store");
|
|
}
|
|
Operand expr = eval_expr(i->item, item_type);
|
|
resolve_type_pair(i->pos, expr.type, item_type);
|
|
}
|
|
}
|
|
else parsing_error(node->pos, "Invalid compound expression type");
|
|
|
|
Operand result = {type, false};
|
|
return result;
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_CAST, Ast_Cast){
|
|
Operand expr = eval_expr(node->expr);
|
|
Ast_Resolved_Type *type = eval_typespec(node->typespec);
|
|
|
|
if(type == expr.type) return expr;
|
|
|
|
else if(expr.type == type_int && type == type_bool){
|
|
expr.type = type_bool;
|
|
return expr;
|
|
}
|
|
|
|
else if(expr.type == type_bool && type == type_int){
|
|
expr.type = type_int;
|
|
return expr;
|
|
}
|
|
|
|
else if(expr.type == type_null){
|
|
expr.type = type;
|
|
return expr;
|
|
}
|
|
|
|
else parsing_error(node->pos, "Failed to cast, incompatible types");
|
|
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_UNARY, Ast_Unary){
|
|
Operand value = eval_expr(node->expr);
|
|
switch(node->op){
|
|
case TK_Pointer:{
|
|
if(value.type->kind != TYPE_Pointer) parsing_error(node->pos, "Dereferencing a value that is not a pointer");
|
|
Operand result = {value.type->base};
|
|
return result;
|
|
}break;
|
|
case TK_Dereference:{
|
|
Operand result = {type_pointer(value.type)};
|
|
return result;
|
|
}break;
|
|
invalid_default_case; return {};
|
|
}
|
|
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_BINARY, Ast_Binary){
|
|
Operand left = eval_expr(node->left);
|
|
Operand right = eval_expr(node->right);
|
|
Operand result = {};
|
|
result.type = resolve_type_pair(node->pos, left.type, right.type);
|
|
if(left.is_const && right.is_const){
|
|
result.is_const = true;
|
|
if(result.type == type_int){
|
|
switch(node->op){
|
|
case TK_Add: result.int_val = left.int_val + right.int_val; break;
|
|
case TK_Sub: result.int_val = left.int_val - right.int_val; break;
|
|
case TK_Mul: result.int_val = left.int_val * right.int_val; break;
|
|
case TK_Div: result.int_val = left.int_val / right.int_val; break;
|
|
invalid_default_case;
|
|
}
|
|
}
|
|
else parsing_error(node->pos, "Arithmetic on type [%s] is not supported", type_names[result.type->kind]);
|
|
}
|
|
|
|
return result;
|
|
Ast_End();
|
|
}
|
|
|
|
invalid_default_case;
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
function Operand
|
|
eval_decl(Ast *ast){
|
|
switch(ast->kind){
|
|
|
|
Ast_Begin(AST_VAR, Ast_Var){
|
|
Ast_Resolved_Type *type = eval_typespec(node->typespec);
|
|
Operand expr = node->expr ? eval_expr(node->expr, type) : Operand{};
|
|
expr.type = resolve_type_pair(node->pos, type, expr.type);
|
|
return expr;
|
|
Ast_End();
|
|
}
|
|
|
|
Ast_Begin(AST_CONST, Ast_Const){
|
|
Operand expr = eval_expr(node->expr);
|
|
if(!expr.type) parsing_error(node->pos, "Constant value without expression");
|
|
if(!expr.is_const) parsing_error(node->pos, "Value of constant variable is not a constant expression");
|
|
return expr;
|
|
Ast_End();
|
|
}
|
|
|
|
invalid_default_case; return {};
|
|
}
|
|
}
|
|
|
|
function void
|
|
resolve_sym(Sym *sym){
|
|
if(sym->state == SYM_RESOLVED) return;
|
|
else if(sym->state == SYM_RESOLVING){ parsing_error(sym->ast->pos, "Cyclic dependency"); return; }
|
|
assert(sym->state == SYM_NOT_RESOLVED);
|
|
|
|
assert(sym->ast->kind == AST_VAR || sym->ast->kind == AST_CONST);
|
|
sym->state = SYM_RESOLVING;
|
|
Operand op = eval_decl(sym->ast);
|
|
sym->type = op.type;
|
|
if(sym->kind == SYM_CONST){
|
|
assert(op.is_const);
|
|
if(op.type == type_int) sym->int_val = op.int_val;
|
|
else if(op.type == type_string) sym->intern_val = op.intern_val;
|
|
}
|
|
|
|
sym->state = SYM_RESOLVED;
|
|
pctx->resolving_package->ordered.add((Ast_Named *)sym->ast);
|
|
}
|
|
|
|
function Sym *
|
|
resolve_name(Token *pos, Intern_String name){
|
|
Sym *sym = sym_get(name);
|
|
if(!sym) parsing_error(pos, "Unidentified name [%s]", name.str);
|
|
resolve_sym(sym);
|
|
return sym;
|
|
}
|
|
|
|
function void
|
|
resolve_package(Ast_Package *package){
|
|
For(package->decls){
|
|
resolve_name(it[0]->pos, it[0]->name);
|
|
}
|
|
}
|
|
|
|
function Ast_Package *
|
|
parse_file(){
|
|
Scratch scratch;
|
|
|
|
//
|
|
// @note: pop the first token with token_next() / token_expect()
|
|
// which always should be an indentation token,
|
|
// it updates the indent info on the parser,
|
|
// making sure that indentation on
|
|
// the first line is properly updated
|
|
//
|
|
Token *token = token_get();
|
|
Array<Ast_Named *>decls = {scratch};
|
|
while(!token_is(TK_End)){
|
|
token_expect(SAME_SCOPE);
|
|
Ast_Named *decl = parse_named(true);
|
|
if(!decl) break;
|
|
|
|
Sym_Kind kind = SYM_VAR;
|
|
if(decl->kind == AST_CONST) kind = SYM_CONST;
|
|
else if(decl->kind == AST_VAR) kind = SYM_VAR;
|
|
else invalid_codepath;
|
|
|
|
Sym *sym = sym_new(kind, decl->name, decl);
|
|
sym_insert(sym);
|
|
|
|
decls.add(decl);
|
|
}
|
|
Ast_Package *result = ast_package(token, token->file, decls);
|
|
return result;
|
|
}
|
|
|