diff --git a/lib/bl/api/build/build.bl b/lib/bl/api/build/build.bl index 989ea436..7afcb226 100644 --- a/lib/bl/api/build/build.bl +++ b/lib/bl/api/build/build.bl @@ -493,4 +493,5 @@ __get_module_import_policy :: fn (target: *Target) C.int #extern; __get_default_triple :: fn (triple: *TargetTriple) #extern; __triple_to_string :: fn (triple: *TargetTriple, buf: *C.char, buf_len: C.int) C.int #extern; __builder_get_options :: fn (opt: *BuilderOptions) #extern; -__builder_set_options :: fn (opt: *BuilderOptions) #extern; \ No newline at end of file +__builder_set_options :: fn (opt: *BuilderOptions) #extern; + diff --git a/src/assembly.c b/src/assembly.c index e1ee91eb..69deb011 100644 --- a/src/assembly.c +++ b/src/assembly.c @@ -307,7 +307,7 @@ static void import_source(import_elem_context_t *ctx, const char *srcfile) { str_buf_t path = get_tmp_str(); str_buf_append_fmt(&path, "{s}/{s}", ctx->modulepath, srcfile); // @Cleanup: should we pass the import_from token here? - assembly_add_unit_safe(ctx->assembly, str_to_c(path), NULL); + assembly_add_unit(ctx->assembly, str_to_c(path), NULL); put_tmp_str(path); } @@ -607,7 +607,7 @@ struct assembly *assembly_new(const struct target *target) { // Add units from target for (usize i = 0; i < arrlenu(target->files); ++i) { - assembly_add_unit_safe(assembly, target->files[i], NULL); + assembly_add_unit(assembly, target->files[i], NULL); } const char *preload_file = read_config(builder.config, assembly->target, "preload_file", ""); @@ -616,19 +616,19 @@ struct assembly *assembly_new(const struct target *target) { switch (assembly->target->kind) { case ASSEMBLY_EXECUTABLE: if (assembly->target->no_api) break; - assembly_add_unit_safe(assembly, BUILTIN_FILE, NULL); - assembly_add_unit_safe(assembly, preload_file, NULL); + assembly_add_unit(assembly, BUILTIN_FILE, NULL); + assembly_add_unit(assembly, preload_file, NULL); break; case ASSEMBLY_SHARED_LIB: if (assembly->target->no_api) break; - assembly_add_unit_safe(assembly, BUILTIN_FILE, NULL); - assembly_add_unit_safe(assembly, preload_file, NULL); + assembly_add_unit(assembly, BUILTIN_FILE, NULL); + assembly_add_unit(assembly, preload_file, NULL); break; case ASSEMBLY_BUILD_PIPELINE: - assembly_add_unit_safe(assembly, BUILTIN_FILE, NULL); - assembly_add_unit_safe(assembly, preload_file, NULL); - assembly_add_unit_safe(assembly, BUILD_API_FILE, NULL); - assembly_add_unit_safe(assembly, BUILD_SCRIPT_FILE, NULL); + assembly_add_unit(assembly, BUILTIN_FILE, NULL); + assembly_add_unit(assembly, preload_file, NULL); + assembly_add_unit(assembly, BUILD_API_FILE, NULL); + assembly_add_unit(assembly, BUILD_SCRIPT_FILE, NULL); break; case ASSEMBLY_DOCS: break; @@ -705,8 +705,7 @@ static inline bool assembly_has_unit(struct assembly *assembly, const hash_t has return false; } -struct unit * -assembly_add_unit_safe(struct assembly *assembly, const char *filepath, struct token *load_from) { +struct unit *assembly_add_unit(struct assembly *assembly, const char *filepath, struct token *load_from) { zone(); if (!is_str_valid_nonempty(filepath)) return_zone(NULL); struct unit *unit = NULL; diff --git a/src/assembly.h b/src/assembly.h index b7ffed7e..3a5fae2e 100644 --- a/src/assembly.h +++ b/src/assembly.h @@ -300,18 +300,17 @@ s32 target_triple_to_string(const struct target_triple *triple, char struct assembly *assembly_new(const struct target *target); void assembly_delete(struct assembly *assembly); -struct unit * -assembly_add_unit_safe(struct assembly *assembly, const char *filepath, struct token *load_from); -void assembly_add_lib_path_safe(struct assembly *assembly, const char *path); -void assembly_append_linker_options_safe(struct assembly *assembly, const char *opt); -void assembly_add_native_lib_safe(struct assembly *assembly, - const char *lib_name, - struct token *link_token, - bool runtime_only); -bool assembly_import_module(struct assembly *assembly, - const char *modulepath, - struct token *import_from); -DCpointer assembly_find_extern(struct assembly *assembly, const str_t symbol); +struct unit *assembly_add_unit(struct assembly *assembly, const char *filepath, struct token *load_from); +void assembly_add_lib_path_safe(struct assembly *assembly, const char *path); +void assembly_append_linker_options_safe(struct assembly *assembly, const char *opt); +void assembly_add_native_lib_safe(struct assembly *assembly, + const char *lib_name, + struct token *link_token, + bool runtime_only); +bool assembly_import_module(struct assembly *assembly, + const char *modulepath, + struct token *import_from); +DCpointer assembly_find_extern(struct assembly *assembly, const str_t symbol); struct mir_var *assembly_get_rtti(struct assembly *assembly, hash_t type_hash); void assembly_add_rtti(struct assembly *assembly, hash_t type_hash, struct mir_var *rtti_var); diff --git a/src/common.h b/src/common.h index 4b23f6c0..9daa80cc 100644 --- a/src/common.h +++ b/src/common.h @@ -151,9 +151,9 @@ enum { BL_RED, // terminated. This way we can avoid calling strlen() every time and ew can reduce amount of string // copying and allocations (e.g. identificators can point directly to the loaded file data). typedef struct { + s32 len; + s32 _; // Gap to make this ABI compatible with BL strings. Note that we also use this gap in str_buf. char *ptr; - // Might be s64 but it cause warning in range-prints. - s32 len; } str_t; static_assert(sizeof(str_t) == 16, "Invalid size of string view type."); @@ -170,9 +170,11 @@ s32 levenshtein(const str_t s1, const str_t s2); // String dynamic array buffer. // // Note it's guaranteed to be zero terminated, however use 'str_to_c' macro for safety! +// Keep layout ABI compatible with str_t! struct str_buf { + s32 len; + s32 cap; char *ptr; - s32 len, cap; }; typedef struct str_buf str_buf_t; diff --git a/src/parser.c b/src/parser.c index b4204129..c65a1168 100644 --- a/src/parser.c +++ b/src/parser.c @@ -409,7 +409,7 @@ parse_hash_directive(struct context *ctx, s32 expected_mask, enum hash_directive struct ast *load = ast_create_node(ctx->ast_arena, AST_LOAD, tok_directive, scope_get(ctx)); load->data.load.filepath = tok_path->value.str.ptr; if (ctx->assembly->target->kind != ASSEMBLY_DOCS) { - assembly_add_unit_safe(ctx->assembly, load->data.load.filepath, tok_path); + assembly_add_unit(ctx->assembly, load->data.load.filepath, tok_path); } return_zone(load); } diff --git a/src/vm.c b/src/vm.c index 3463caa3..72cbb595 100644 --- a/src/vm.c +++ b/src/vm.c @@ -694,8 +694,9 @@ void dyncall_cb_read_arg(struct virtual_machine UNUSED(*vm), memset(dest, 0, sizeof(*dest_value->_tmp)); switch (type->kind) { + case MIR_TYPE_ENUM: case MIR_TYPE_INT: { - const usize bitcount = (usize)type->data.integer.bitcount; + const usize bitcount = (usize)(type->kind == MIR_TYPE_INT ? type->data.integer.bitcount : type->data.enm.base_type->size_bits); u64 v = 0; switch (bitcount) { case 8: diff --git a/tests/test.bl b/tests/test.bl index 3893317a..3605a176 100644 --- a/tests/test.bl +++ b/tests/test.bl @@ -909,103 +909,4 @@ main :: fn() s32 { return 0; } - -TODO: - -- Infer type name of constant array initializers: - FOO :: [2]Bar.{ .{ 10, 20 }, .{ 30, 40 } }; - -- !array => array.len == 0 -- #comptime - automatically comptime evaluated in case all the arguments are compile-time known. -What about functions returning types? -- Invalid - operator precedence! -- Add blc --init="My Project" command. -- Nested functions ignore previous using statement in some cases. -- Consider application context vs thread context (i.e. temporary allocator is by default thread -local but application_context is not). -- Consider #import and #load to be limited only to the file scope. -- Allow creation of scoped constants in structure bodies: - - foo :: struct { - THIS_IS_CONSTANT :: 10; - - number: s32; - } - -- Macros - - bar :: macro (v: s32) s32 { - return v + 1; - } - -- Introduce calling conventions. -- Change syntax of default argument value assignment to ':'. -- Properly handle fail of ast_expr_lit_fn while generating recipe implementation. - -- loop - else ? - - loop i := 0; i < arr.len; i += 1 { - ... - } else {} - -ENUM FLAGS: -- Allow direct | (or) composition of flags. -- Builtin support for checking if the flag is set? -- Replace all functionality of flags-related helper functions. - -STATIC IF: - -- Static if in other scopes. -- Fix static ifs. -- No scopes introduced by static ifs? But what about {}? Maybe C style is better? -- Struct declaration? -- Global scope? - - - -COMPILE TIME EXECUTION: - -- Use #run to mark function to be executed in compile time on the call side: '#run foo()'. -- Use #run to mark function executed only in compile time on the declaration side: 'foo :: fn () -#run {}'. - - -POLYMORPH: - -- Polymorp types cannot be easily identified; i.e. 'table_insert' should be something like this -'table_insert :: fn (tbl: *Table)' where 'Table' can be any polymorph type. However this is a bit -problematic due to the way how polymorph types are generated by compile-time funcitons... - - - -NEW FEATURES - -- Anonymous structs/unions? - -- Module versions: - - dir: module@2.9.16 - dir: module@3.2.0 - - #import "module" // the latest one - #import "module@2 // newest version 2.x.x - #import "module@2.9 // newest version 2.9.x - #import "module@3.2.0 // exact version - #import "module@2+ // any >= 2.0.0 - #import "module@2.1+ // any 2.1.0, 2.1.1, 2.2.0 ... - #import "module@2.9.0+ // any 2.9.0, 2.9.1, 2.9.2 ... - - -// To memory.bl??? -bytes_to_value :: fn (TValue: type #comptime, bytes: []u8) TValue { - tmp: TValue; - assert(bytes.ptr); - memcpy(auto &tmp, bytes.ptr, std.min(sizeof(TValue), auto bytes.len)); - return tmp; -} - -BIG STUFF: - -- Implement custom multithreaded linker for windows, lld is slow same as link.exe. - */ diff --git a/todo.txt b/todo.txt index b5dcc84c..86042221 100644 --- a/todo.txt +++ b/todo.txt @@ -1,48 +1,38 @@ -Static if -[ ] Static if in other scopes. -[ ] Fix static ifs. -[ ] No scopes introduced by static ifs? But what about {}? Maybe C style is better? -[ ] Struct declaration? -[ ] Global scope? - -Compile time execution -[x] Allow comptime artuments (mixed function signature). -[ ] Use #run to mark function to be executed in compile time on the call side: '#run foo()'. -[ ] Use #run to mark function executed only in compile time on the declaration side: 'foo :: fn () #run {}'. -[x] Not all compile time functions must be generated every time; use regular call in case it's not polymorp or mixed. -[x] Finish incremental execution and re-evaluate stack saving? - -Polymorph -[ ] Polymorp types cannot be easily identified; i.e. 'table_insert' should be something like this 'table_insert :: fn (tbl: *Table)' where 'Table' can be any polymorph type. However this is a bit problematic due to the way how polymorph types are generated by compile-time funcitons... - - -Application context. -[ ] Should be implicitly passed into all functions. -[ ] Accessible via #context directive. - -MISC -[ ] Use custom string implementation str_t. -[ ] ID should be passed by value (make sure it's 16B) -[ ] Refer to original file data since we'll have strings with len. -[ ] Remove scope bookmarks. -[ ] Finalize type cache. -[ ] -[ ] Add blc --init="My Project" command. -[x] Add support of #maybe_unused for function arguments. -[ ] Nested functions ignore previous using statement in some cases. -[x] Create new(s32) somehow. -[x] Change function arguments mutability. -[x] Redesign mutability propagation (now immutable struct cannot have its members modified). -[ ] Consider application context vs thread context (i.e. temporary allocator is by default thread local but application_context is not). -[ ] Consider #import and #load to be limited only to the file scope. -[ ] Allow creation of scoped constants in structure bodies: +TODO: + +- Use #run to mark function to be executed in compile time on the call side: '#run foo()'. +- Use #run to mark function executed only in compile time on the declaration side: 'foo :: fn () #run {}'. +- Consider #import and #load to be limited only to the file scope. +- Polymorp types cannot be easily identified; i.e. 'table_insert' should be something like + this 'table_insert :: fn (tbl: *Table)' where 'Table' can be any polymorph type. However this is a + bit problematic due to the way how polymorph types are generated by compile-time funcitons... +- Static if in other than local scopes. +- No scopes introduced by static ifs? But what about {}? Maybe C style is better? +- Allow creation of scoped constants in structure bodies: + foo :: struct { THIS_IS_CONSTANT :: 10; number: s32; } -Macros - bar :: macro (v: s32) s32 { - return v + 1; - } +- !array => array.len == 0 +- Introduce calling conventions. +- Change syntax of default argument value assignment to ':'. +- loop - else ? + + loop i := 0; i < arr.len; i += 1 { + ... + } else {} + +- Anonymous structs/unions? + +TODO BIG STUFF: + +- Implement custom multithreaded linker for windows, lld is slow same as link.exe. +- Factor-out mir generation into separate pass executed per unit. This might be the fisrt step to + support proper conditional #load and #import. +- Allow code generation from build script pipelines probably using compiler hooks. +- Implement code browsing from build script to allow custom usage checks. + +DONE: \ No newline at end of file