#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, }; struct Sym{ Intern_String name; Sym_Kind kind; 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_Decl 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_Resolved_Type *type, Ast *ast){ Sym *result = exp_alloc_type(pctx->perm, Sym, AF_ZeroMemory); result->name = name; result->kind = kind; result->type = type; result->ast = ast; assert(ast); map_insert(&pctx->resolved, ast, result); 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(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(SYM_Const, string, type_bool, &empty_decl); sym_insert(sym); } { Intern_String string = intern_string(&pctx->interns, "false"_s); Sym *sym = sym_new(SYM_Const, string, type_bool, &empty_decl); sym_insert(sym); } { Intern_String string = intern_string(&pctx->interns, "null"_s); Sym *sym = sym_new(SYM_Const, string, type_null, &empty_decl); sym_insert(sym); } } 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 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 void 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_Decl){ eval_decl(node); Ast_End(); } Ast_Begin(AST_CONST, Ast_Decl){ eval_decl(node); Ast_End(); } Ast_Begin(AST_IF, Ast_If){ For(node->ifs){ if(it[0]->expr) eval_expr(it[0]->expr); For_It(it[0]->block->stmts, jt){ eval_stmt(jt[0], ret); } } 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 = sym_get(node->intern_val); if(!sym){ parsing_error(node->pos, "Identifier is undefined"); } // @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(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 void eval_decl(Ast *ast){ switch(ast->kind){ Ast_Begin(AST_PACKAGE, Ast_Package){ For(node->decls) eval_decl(*it); Ast_End(); } Ast_Begin(AST_VAR, Ast_Decl){ Ast_Resolved_Type *type = eval_typespec(node->var.typespec); Operand expr = node->var.expr ? eval_expr(node->var.expr, type) : Operand{}; Ast_Resolved_Type *resolved_type = resolve_type_pair(node->pos, type, expr.type); Sym *sym = sym_new(SYM_Var, node->name, resolved_type, node); sym_insert(sym); Ast_End(); } Ast_Begin(AST_CONST, Ast_Decl){ Ast_Resolved_Type *type = eval_typespec(node->var.typespec); if(type && type->kind == TYPE_Pointer) parsing_error(node->pos, "Const cant be a pointer"); Operand expr = eval_expr(node->var.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"); Ast_Resolved_Type *resolved_type = resolve_type_pair(node->pos, type, expr.type); Sym *sym = sym_new(SYM_Const, node->name, resolved_type, node); if(resolved_type == type_int) sym->int_val = expr.int_val; else if(resolved_type == type_string) sym->intern_val = expr.intern_val; sym_insert(sym); Ast_End(); } invalid_default_case; } }