#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){ type_complete(sym->type); 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 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(COMPOUND, Compound){ Ast_Resolved_Type *type = resolve_typespec(node->typespec, AST_CAN_BE_NULL); if(!type && expected_type) type = expected_type; else if(!expected_type && type); else if(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){ 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 = 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 parsing_error(node->pos, "Invalid compound expression 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 prepass? expecting only structs, exprs, lambdas CASE(STRUCT, Struct){ assert(const_sym); Scratch scratch; Array 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); 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(); Arraydecls = {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; }