diff --git a/README.md b/README.md index 1567cb2..145c72a 100644 --- a/README.md +++ b/README.md @@ -65,28 +65,28 @@ Release :: (m: *Memory) ## What's missing ? -- [x] Constant evaluation and constant folding - Folding and precomputing every expression that can be calculated at compile time. Which allows to check if a given constant expression is actually something that can be computed at compile time. - - [ ] Constant expressions with types specified by the user. +- [x] Constant evaluation and constant folding - Folding and precomputing every expression that can be calculated at compile time. Which allows to check if a given constant expression is actually something that can be computed at compile time + - [ ] Constant expressions with concrete types -- [x] Untyped types - Context dependent type assignment of constant expressions, this is a feature I really loved in Go, it makes constants work very well with a very strict type system and it makes errors like overflow of constants in C due to bad size specifier impossible. - - [x] Infinite precision integers in constants. - - [x] Resolution of all untyped types in the typechecking stage. - - [x] Special case of booleans and their type propagation. +- [x] Untyped types - Context dependent type assignment of constant expressions, this is a feature I really loved in Go, it makes constants work very well with a very strict type system and it makes errors like overflow of constants in C due to bad size specifier impossible + - [x] Infinite precision integers in constants + - [x] Resolution of all untyped types in the typechecking stage + - [x] Special case of booleans and their type propagation - [x] Module system - [x] Lazy evaluation of modules (unused code is not compiled or typechecked) - [x] Import module, load project file distinction -- [x] Order independent declarations - The ordering of functions in code files or modules does not matter, compiler figures all that stuff out for you. "main" can be wherever you want it to be and all functions should be available without problems. +- [x] Order independent declarations - The ordering of functions in code files or modules does not matter, compiler figures all that stuff out for you. "main" can be wherever you want it to be and all functions should be available without problems -- [x] Synchronize generated C code with original source using line directives so that debuggers work. +- [x] Synchronize generated C code with original source using line directives so that debuggers work - [ ] Expressions - [x] Compounds with named fields and numbered fields - [x] Functions calls with named arguments - [x] All the standard binary, unary expressions - [x] Pointer arithmetic and pointer as array - - [ ] Dot access expression needs a redesign + - [ ] Dot access expression needs a redesign because it doesn't handle expressions after the dot it requires names instead - [ ] Casting might need a redesign not sure - [x] Runtime reflection diff --git a/core_compiler.cpp b/core_compiler.cpp index 8a83e88..e77789d 100644 --- a/core_compiler.cpp +++ b/core_compiler.cpp @@ -23,45 +23,6 @@ destroy_compiler(){ exp_destroy(&pctx->stage_arena); } -function void -parse_file(Ast_File *file){ - assert(file); - - Scratch scratch; - file->filecontent = os_read_file(pctx->perm, file->absolute_file_path); - if(file->filecontent.len == 0){ - compiler_error(file->pos, "Failed to open file \"%Q\"", file->absolute_file_path); - } - - - pctx->currently_parsed_file = file; - pctx->currently_parsed_scope = file; - lex_restream(pctx, file->filecontent, file->absolute_file_path); - while(token_expect(SAME_SCOPE)){ - if(token_match_pound(pctx->intern("load"_s))){ - parse_load(true); - continue; - } else if(token_match_pound(pctx->intern("import"_s))){ - parse_import(true); - continue; - } - - Ast_Decl *decl = parse_decl(true); - if(!decl) break; - - set_flag(decl->flags, AST_GLOBAL); - if(decl->kind == AST_STRUCT){ - decl->type = type_type; - decl->type_val = type_incomplete(decl); - decl->state = DECL_RESOLVED; - } - - insert_into_scope(file, decl); - } - pctx->currently_parsed_scope = 0; - pctx->currently_parsed_file = 0; -} - function void insert_builtin_into_scope(Ast_Scope *p, String name, Ast_Type *type){ Intern_String string = pctx->intern(name); diff --git a/core_main.cpp b/core_main.cpp index f2f3287..84b13cb 100644 --- a/core_main.cpp +++ b/core_main.cpp @@ -1,6 +1,9 @@ /* - [ ] Basic + - [ ] Idea to fix overshoot when debugging and it goes to the + close bracket and there is not enough line directives. + - Store the last outputed line and propagate it on the close brace etc. - [ ] Detecting if return was called - [ ] Fix . operator lookups - [ ] Combining casts with . operator diff --git a/core_parsing.cpp b/core_parsing.cpp index 7c1d7da..cfceb62 100644 --- a/core_parsing.cpp +++ b/core_parsing.cpp @@ -736,8 +736,7 @@ register_ast_file(Token *pos, String absolute_file_path, Ast_Module *module, B32 break; } - print_token_context(it->pos); - compiler_error(pos, "This file is already loaded by module: %Q, try importing that module to get access to it", module->absolute_file_path); + compiler_error(it->pos, pos, "This file is already loaded by module: %Q, try importing that module to get access to it", module->absolute_file_path); } } @@ -866,3 +865,44 @@ parse_decl(B32 is_global){ return result; } + +function void insert_into_scope(Ast_Scope *scope, Ast_Decl *decl); +function Ast_Type *type_incomplete(Ast *ast); + +function void +parse_file(Ast_File *file){ + assert(file); + + Scratch scratch; + file->filecontent = os_read_file(pctx->perm, file->absolute_file_path); + if(file->filecontent.len == 0){ + compiler_error(file->pos, "Failed to open file \"%Q\"", file->absolute_file_path); + } + + pctx->currently_parsed_file = file; + pctx->currently_parsed_scope = file; + lex_restream(pctx, file->filecontent, file->absolute_file_path); + while(token_expect(SAME_SCOPE)){ + if(token_match_pound(pctx->intern("load"_s))){ + parse_load(true); + continue; + } else if(token_match_pound(pctx->intern("import"_s))){ + parse_import(true); + continue; + } + + Ast_Decl *decl = parse_decl(true); + if(!decl) break; + + set_flag(decl->flags, AST_GLOBAL); + if(decl->kind == AST_STRUCT){ + decl->type = type_type; + decl->type_val = type_incomplete(decl); + decl->state = DECL_RESOLVED; + } + + insert_into_scope(file, decl); + } + pctx->currently_parsed_scope = 0; + pctx->currently_parsed_file = 0; +} diff --git a/core_typechecking.cpp b/core_typechecking.cpp index 1a5d54f..f5177d8 100644 --- a/core_typechecking.cpp +++ b/core_typechecking.cpp @@ -445,19 +445,26 @@ search_for_decl(Ast_Scope *scope, Intern_String name, Search_Flag flags = 0){ function Ast_Decl * resolve_name(Ast_Scope *scope, Token *pos, Intern_String name, Search_Flag search_flags){ Ast_Decl *decl = search_for_decl(scope, name, search_flags); - if(!decl) compiler_error(pos, "Unidentified name [%s]", name.str); + if(!decl) { + compiler_error(pos, "Unidentified name [%s]", name.str); + } + resolve_decl(decl); return decl; } function void insert_into_scope(Ast_Scope *scope, Ast_Decl *decl){ + // This function is called when resolving statements + // inside code blocks, inserting lambda arguments into scope + // + // It's also called when scanning top level declarations of a module + // as such we probably don't want to call any resolve stuff here Ast_Decl *find = search_for_decl(scope, decl->name); if(find){ - print_token_context(find->pos); - compiler_error(decl->pos, "[%s] is already defined", decl->name.str); + // if(find->kind != AST_LAMBDA) + compiler_error(find->pos, decl->pos, "[%s] is already defined", decl->name.str); } - scope->decls.add(decl); } diff --git a/core_typechecking.h b/core_typechecking.h index dacf0f0..b0ab1ab 100644 --- a/core_typechecking.h +++ b/core_typechecking.h @@ -224,8 +224,9 @@ type_array(Ast_Type *base, S64 size){ function Ast_Type * type_lambda(Ast *ast, Array return_vals, Array args){ Ast_Type *ret = type_try_tupling(return_vals, ast); - U64 hash = hash_ptr(ret); - For(args) hash = hash_mix(hash, hash_ptr(it)); + U64 hash_without_ret = 13; // @function_overloading scrap this if we changed course + For(args) hash_without_ret = hash_mix(hash_without_ret, hash_ptr(it)); + U64 hash = hash_mix(hash_ptr(ret), hash_without_ret); Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash); if(result){ @@ -238,6 +239,7 @@ type_lambda(Ast *ast, Array return_vals, Array args){ result->ast = ast; result->func.ret = ret; result->func.args = args.tight_copy(pctx->perm); + result->func.hash_without_ret = hash_without_ret; // @function_overloading scrap this if we changed course map_insert(&pctx->type_map, hash, result); return result; diff --git a/core_types.h b/core_types.h index 3106ce0..2a82923 100644 --- a/core_types.h +++ b/core_types.h @@ -101,6 +101,7 @@ struct Ast_Type{ struct{ Ast_Type * ret; Array args; + U64 hash_without_ret; // @function_overloading scrap this if we changed course }func; }; }; diff --git a/modules/math.kl b/modules/math.kl index da81c21..3716ccd 100644 --- a/modules/math.kl +++ b/modules/math.kl @@ -50,6 +50,20 @@ Vec3_Add :: (a: Vec3, b: Vec3): Vec3 ;; return Vec3{a.x+b.x, a.y+b.y, a.z+b. Vec3_Div :: (a: Vec3, b: Vec3): Vec3 ;; return Vec3{a.x/b.x, a.y/b.y, a.z/b.z} Vec3_Sub :: (a: Vec3, b: Vec3): Vec3 ;; return Vec3{a.x-b.x, a.y-b.y, a.z-b.z} +/* +@todo: Add function overloading +Current plan: + * allow insert_into_scope to insert multiple lambdas + * change resolve_name and search_for_decl to something + that can seek multiple lambda declarations + resolve them and return a match to hash or type + * change the order of lambda call resolution, probably would have to + hash the arguments first to match the lambda call + +*/ +// Add :: (a: Vec3, b: Vec3): Vec3 ;; return Vec3{a.x+b.x, a.y+b.y, a.z+b.z} +// Add :: (a: Vec2, b: Vec2): Vec2 ;; return Vec2{a.x+b.x, a.y+b.y} + F32_Clamp :: (min: F32, value: F32, max: F32): F32 if value > max;; return max if value < min;; return min