Files
corelang/new_resolve.cpp

606 lines
18 KiB
C++

#define CASE(kind,type) case AST_##kind: { Ast_##type *node = (Ast_##type *)ast;
#define BREAK() } break
enum Sym_Kind{
SYM_NONE,
SYM_CONST,
SYM_VAR,
};
enum Sym_State{
SYM_NOT_RESOLVED,
SYM_RESOLVING,
SYM_RESOLVED,
};
#define VALUE_FIELDS \
S64 int_val; \
Intern_String intern_val; \
Ast_Resolved_Type *type_val;
#define INLINE_VALUE_FIELDS union{Value value; union{VALUE_FIELDS};}
union Value{VALUE_FIELDS};
struct Sym{
Intern_String name;
Sym_Kind kind;
Sym_State state;
Ast *ast;
Ast_Resolved_Type *type;
INLINE_VALUE_FIELDS;
};
struct Operand{
Ast_Resolved_Type *type;
bool is_const;
INLINE_VALUE_FIELDS;
};
enum{
AST_CANT_BE_NULL = 0,
AST_CAN_BE_NULL = 1
};
function Sym *resolve_name(Token *pos, Intern_String name);
function Operand resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *compound_required_type = 0, Sym *const_sym = 0);
function Operand resolve_binding(Ast *ast, Sym *sym = 0);
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_open(){
S64 local_sym_count = pctx->local_syms.len;
pctx->scope++;
return local_sym_count;
}
function void
scope_close(S64 local_sym_count){
pctx->scope--;
assert(pctx->scope >= 0);
for(S64 i = local_sym_count; i < pctx->local_syms.len; i++){
Sym *it = pctx->local_syms.data[i];
void *removed = map_remove(&pctx->syms, hash_string(it->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, Value value, Ast *ast){
Sym *result = sym_new(kind, name, ast);
result->type = type;
result->state = SYM_RESOLVED;
result->value = value;
return result;
}
function Sym *
resolved_get(Ast *ast){
Sym *result = (Sym *)map_get(&pctx->resolved, ast);
assert(result);
return result;
}
#include "new_type.cpp"
function Ast_Resolved_Type *
resolved_type_get(Ast_Expr *ast){
Sym *result = resolved_get(ast);
assert(result->type == type_type);
assert(result->type);
return result->type_val;
}
function void
sym_insert_builtin_type(String name, Ast_Resolved_Type *type){
Intern_String string = intern_string(&pctx->interns, name);
Value val; val.type_val = type;
Sym *sym = sym_new_resolved(SYM_CONST, string, type_type, val, &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);
Value val; val.int_val = 1;
Sym *sym = sym_new_resolved(SYM_CONST, string, type_bool, val, &empty_decl);
sym_insert(sym);
}
{
Intern_String string = intern_string(&pctx->interns, "false"_s);
Value val; val.int_val = 0;
Sym *sym = sym_new_resolved(SYM_CONST, string, type_bool, val, &empty_decl);
sym_insert(sym);
}
{
Intern_String string = intern_string(&pctx->interns, "null"_s);
Value val; val.int_val = 0;
Sym *sym = sym_new_resolved(SYM_CONST, string, type_null, val, &empty_decl);
sym_insert(sym);
}
}
function Ast_Resolved_Type *
resolve_typespec(Ast_Expr *ast, B32 ast_can_be_null = AST_CANT_BE_NULL){
if(ast_can_be_null && ast == 0) return 0;
Operand resolved = resolve_expr(ast);
if(resolved.type != type_type) parsing_error(ast->pos, "Expected [Type] got instead %s", resolved.type->kind);
return resolved.type_val;
}
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 void
resolve_stmt(Ast *ast, Ast_Resolved_Type *ret){
switch(ast->kind){
CASE(RETURN, Return){ // @todo: need to check if all paths return a value
Operand op = {};
if(node->expr) op = resolve_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");
BREAK();
}
CASE(VAR, Var){
Operand op = resolve_binding(node);
Sym *sym = sym_new_resolved(SYM_VAR, node->name, op.type, op.value, node);
sym_insert(sym);
BREAK();
}
CASE(CONST, Const){
Operand op = resolve_binding(node);
Sym *sym = sym_new_resolved(SYM_CONST, node->name, op.type, op.value, node);
sym_insert(sym);
BREAK();
}
CASE(INIT, Init){
switch(node->op){
case TK_Comma:{
Operand op = resolve_expr(node->expr);
Sym *sym = sym_new_resolved(SYM_VAR, node->ident->intern_val, op.type, op.value, node);
sym_insert(sym);
}break;
invalid_default_case;
}
BREAK();
}
CASE(IF, If){
For(node->ifs){
if(it[0]->init) resolve_stmt(it[0]->init, ret);
if(it[0]->expr) resolve_expr(it[0]->expr);
S64 scope_index = scope_open();
For_It(it[0]->block->stmts, jt){
resolve_stmt(jt[0], ret);
}
scope_close(scope_index);
}
BREAK();
}
invalid_default_case;
}
}
function Operand
resolve_expr(Ast_Expr *ast, Ast_Resolved_Type *expected_type, Sym *const_sym){
switch(ast->kind){
CASE(INT, Atom){
Operand result = {type_int, true};
result.int_val = node->int_val;
return result;
BREAK();
}
CASE(STR, Atom){
Operand result = {type_string, true};
result.intern_val = node->intern_val;
return result;
BREAK();
}
CASE(IDENT, Atom){
Sym *sym = resolve_name(node->pos, node->intern_val);
// @cleanup: due to Value being a union this portion probably can get cleaned
// @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;
}
else if(sym->kind == SYM_CONST || sym->kind == SYM_VAR){
// if(sym->type == type_type) type_complete(sym->type_val);
result.type = sym->type;
result.is_const = sym->kind == SYM_CONST ? true : false;
result.value = sym->value;
sym_new_resolved(SYM_CONST, sym->name, sym->type, sym->value, node);
}
else invalid_codepath;
return result;
BREAK();
}
CASE(ARRAY, Array){
Operand type = resolve_expr(node->base);
if(type.type != type_type) parsing_error(node->pos, "Prefix array operator is only allowed on types");
Operand expr = resolve_expr(node->expr);
if(!expr.is_const) parsing_error(node->pos, "Array operator requires a constant value");
if(expr.type != type_int) parsing_error(node->pos, "Array index requires type [Int]");
type.type_val = type_array(type.type_val, expr.int_val);
sym_new_resolved(SYM_CONST, {}, type_type, type.value, node);
return type;
BREAK();
}
CASE(LAMBDA, Lambda){
// @note: first resolve type of lambda
Scratch scratch;
Ast_Resolved_Type *lambda_type = 0;
Ast_Resolved_Type *ret_type = resolve_typespec(node->ret);
Array<Ast_Resolved_Type *> args = {scratch};
For(node->args){
Operand type = resolve_expr(it[0]->typespec);
if(type.type != type_type) parsing_error(it[0]->pos, "Required expression of kind [type]");
args.add(type.type_val);
}
lambda_type = type_lambda(ret_type, args);
{
assert(lambda_type);
Value val; val.type_val = lambda_type;
sym_new_resolved(SYM_CONST, {}, type_type, val, node);
if(const_sym){
const_sym->type = lambda_type;
const_sym->state = SYM_RESOLVED;
}
}
Operand result = {type_type, true};
result.type_val = lambda_type;
// @todo: We also need to make sure there is a return value when ret type is not void
// @note: then try resolving the block of lambda
if(node->block){
S64 scope_index = scope_open();
For(node->args){
S64 i = node->args.get_index(it);
Ast_Resolved_Type *type = args[i];
Sym *arg_sym = sym_new_resolved(SYM_VAR, it[0]->name, type, {}, it[0]);
sym_insert(arg_sym);
}
For(node->block->stmts){
resolve_stmt(it[0], ret_type);
}
scope_close(scope_index);
result.type = lambda_type;
}
return result;
BREAK();
}
CASE(INDEX, Index){
Operand left = resolve_expr(node->expr);
Operand index = resolve_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;
BREAK();
}
CASE(CALL, Call){
Operand name = resolve_expr(node->name);
Ast_Resolved_Type *type = name.type;
if(name.type == type_type){
type = name.type_val;
if(expected_type && expected_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){
Ast_Call_Item *i = (Ast_Call_Item *)it[0];
assert(i->kind == AST_CALL_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 = resolve_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 = resolve_expr(i->item, item_type);
resolve_type_pair(i->pos, expr.type, item_type);
}
}
else if(type->kind == TYPE_LAMBDA){
if(type->func.args.len != node->exprs.len) parsing_error(node->pos, "Invalid number of arguments");
For(node->exprs){
Ast_Call_Item *i = (Ast_Call_Item *)it[0];
assert(i->kind == AST_CALL_ITEM);
S64 index = node->exprs.get_index(it);
Operand expr = resolve_expr(i->item);
if(expr.type != type->func.args[index]) parsing_error(i->pos, "Type is not matching function definition");
}
type = type->func.ret;
}
else parsing_error(node->pos, "Invalid function call type");
Operand result = {type, false};
return result;
BREAK();
}
CASE(CAST, Cast){
Operand expr = resolve_expr(node->expr);
Ast_Resolved_Type *type = resolve_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");
BREAK();
}
CASE(UNARY, Unary){
Operand value = resolve_expr(node->expr);
switch(node->op){
case TK_Pointer:{
if(value.type->kind == TYPE_POINTER){
Operand result = {value.type->base};
return result;
}
else if(value.type->kind == TYPE_TYPE){
Operand result = {type_type, true};
result.type_val = type_pointer(value.type_val);
return result;
}
else{ parsing_error(node->pos, "Dereferencing expression %s that is not a [Pointer] or [Type]", type_names[value.type->kind]); return {}; }
}break;
case TK_Dereference:{
Operand result = {type_pointer(value.type)};
return result;
}break;
invalid_default_case; return {};
}
BREAK();
}
CASE(BINARY, Binary){
Operand left = resolve_expr(node->left);
Operand right = resolve_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;
BREAK();
}
// @todo: add const first level function? expecting only structs, exprs, lambdas
CASE(STRUCT, Struct){
assert(const_sym);
Scratch scratch;
Array<Ast_Resolved_Member> members = {scratch};
For(node->members){
Operand op = resolve_binding(it[0]);
Intern_String name = {};
if(is_flag_set(it[0]->flags, AST_BINDING)){
Ast_Named *named = (Ast_Named *)it[0];
name = named->name;
}
sym_new_resolved(SYM_VAR, name, op.type, {}, it[0]);
members.add({op.type, name});
}
Ast_Resolved_Type *resolved = type_struct(const_sym, members);
Operand result = {type_type, true}; result.type_val = resolved;
return result;
BREAK();
}
invalid_default_case;
}
return {};
}
function Operand
resolve_binding(Ast *ast, Sym *sym){
switch(ast->kind){
CASE(VAR, Var){
Ast_Resolved_Type *type = resolve_typespec(node->typespec, AST_CAN_BE_NULL);
Operand expr = node->expr ? resolve_expr(node->expr, type) : Operand{};
expr.type = resolve_type_pair(node->pos, type, expr.type);
type_complete(expr.type);
return expr;
BREAK();
}
CASE(CONST, Const){
Operand expr = resolve_expr((Ast_Expr *)node->value, 0, sym);
if(!expr.is_const) parsing_error(node->pos, "Value of constant variable is not a constant expression");
assert(expr.type);
return expr;
BREAK();
}
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 = resolve_binding(sym->ast, sym);
sym->type = op.type;
sym->value = op.value;
}
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);
if(ast_is_struct(it[0])){
type_complete(const_get_struct(it[0])->type);
}
}
}
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 *sym = sym_new(SYM_VAR, decl->name, decl);
if(decl->kind == AST_CONST) {
sym->kind = SYM_CONST;
Ast_Struct *s = const_try_getting_struct(decl);
if(s){
s->type = type_incomplete(sym);
sym->type_val = s->type;
sym->type = type_type;
sym->state = SYM_RESOLVED;
}
}
else assert(decl->kind == AST_VAR);
sym_insert(sym);
decls.add(decl);
}
Ast_Package *result = ast_package(token, token->file, decls);
return result;
}