Skip to content

Commit

Permalink
[compiler] Cleanup before bigger stuff.
Browse files Browse the repository at this point in the history
  • Loading branch information
travisdoor committed Aug 26, 2024
1 parent f9620aa commit e16d40e
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 171 deletions.
3 changes: 2 additions & 1 deletion lib/bl/api/build/build.bl
Original file line number Diff line number Diff line change
Expand Up @@ -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;
__builder_set_options :: fn (opt: *BuilderOptions) #extern;

23 changes: 11 additions & 12 deletions src/assembly.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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", "");
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
23 changes: 11 additions & 12 deletions src/assembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 5 additions & 3 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
3 changes: 2 additions & 1 deletion src/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
99 changes: 0 additions & 99 deletions tests/test.bl
Original file line number Diff line number Diff line change
Expand Up @@ -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.

*/
74 changes: 32 additions & 42 deletions todo.txt
Original file line number Diff line number Diff line change
@@ -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:

0 comments on commit e16d40e

Please sign in to comment.