diff --git a/build.bat b/build.bat index c46e53ab8e7..374977c7357 100644 --- a/build.bat +++ b/build.bat @@ -4,7 +4,7 @@ set exe_name=odin.exe :: Debug = 0, Release = 1 -set release_mode=0 +set release_mode=1 set compiler_flags= -nologo -Oi -TC -W4 -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR- @@ -48,8 +48,8 @@ rem pushd %build_dir% cl %compiler_settings% "src\main.c" ^ /link %linker_settings% -OUT:%exe_name% ^ - && odin build_dll code/example.odin ^ && odin run code/demo.odin + rem && odin build_dll code/example.odin ^ rem && odin run code/demo.odin diff --git a/code/demo.odin b/code/demo.odin index 8c2f7a90d15..41bf9b40b20 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,5 +1,6 @@ #import "win32.odin" #import "fmt.odin" +#import "sync.odin" Dll :: struct { Handle :: type rawptr @@ -50,6 +51,5 @@ main :: proc() { } some_thing := (proc_addr as proc()) - fmt.println(some_thing) some_thing() } diff --git a/core/win32.odin b/core/win32.odin index 21c77638c32..58d7bb2e866 100644 --- a/core/win32.odin +++ b/core/win32.odin @@ -205,6 +205,37 @@ GetProcessHeap :: proc() -> HANDLE #foreign #dll_import HEAP_ZERO_MEMORY :: 0x00000008 +// Synchronization + +SECURITY_ATTRIBUTES :: struct #ordered { + length: u32 + security_descriptor: rawptr + inherit_handle: BOOL +} + +INFINITE :: 0xffffffff + +CreateSemaphoreA :: proc(attributes: ^SECURITY_ATTRIBUTES, initial_count, maximum_count: i32, name: ^byte) -> HANDLE #foreign #dll_import +ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: i32, previous_count: ^i32) -> BOOL #foreign #dll_import +WaitForSingleObject :: proc(handle: HANDLE, milliseconds: u32) -> u32 #foreign #dll_import + + +InterlockedCompareExchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #foreign +InterlockedExchange :: proc(dst: ^i32, desired: i32) -> i32 #foreign +InterlockedExchangeAdd :: proc(dst: ^i32, desired: i32) -> i32 #foreign +InterlockedAnd :: proc(dst: ^i32, desired: i32) -> i32 #foreign +InterlockedOr :: proc(dst: ^i32, desired: i32) -> i32 #foreign + +InterlockedCompareExchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 #foreign +InterlockedExchange64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign +InterlockedExchangeAdd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign +InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign +InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign + +_mm_pause :: proc() #foreign +ReadWriteBarrier :: proc() #foreign +WriteBarrier :: proc() #foreign +ReadBarrier :: proc() #foreign // GDI diff --git a/src/build.c b/src/build.c index 7bf361b6870..ab892ecff24 100644 --- a/src/build.c +++ b/src/build.c @@ -149,7 +149,7 @@ String get_filepath_extension(String path) { void init_build_context(BuildContext *bc) { bc->ODIN_VENDOR = str_lit("odin"); - bc->ODIN_VERSION = str_lit("0.0.3d"); + bc->ODIN_VERSION = str_lit("0.0.4"); bc->ODIN_ROOT = odin_root_dir(); #if defined(GB_SYSTEM_WINDOWS) diff --git a/src/checker/checker.c b/src/checker/checker.c index fca1833e9b9..5bf066c1a30 100644 --- a/src/checker/checker.c +++ b/src/checker/checker.c @@ -1120,31 +1120,6 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As DelayedDecl di = {parent_scope, decl}; array_add(&c->delayed_foreign_libraries, di); case_end; - case_ast_node(cd, ConstDecl, decl); - for_array(i, cd->values) { - AstNode *name = cd->names.e[i]; - AstNode *value = cd->values.e[i]; - ExactValue v = {ExactValue_Invalid}; - if (name->kind != AstNode_Ident) { - error_node(name, "A declaration's name but be an identifier, got %.*s", LIT(ast_node_strings[name->kind])); - } - Entity *e = make_entity_constant(c->allocator, parent_scope, name->Ident, NULL, v); - e->identifier = name; - DeclInfo *di = make_declaration_info(c->allocator, parent_scope); - di->type_expr = cd->type; - di->init_expr = value; - add_entity_and_decl_info(c, name, e, di); - } - - isize lhs_count = cd->names.count; - isize rhs_count = cd->values.count; - - if (rhs_count == 0 && cd->type == NULL) { - error_node(decl, "Missing type or initial expression"); - } else if (lhs_count < rhs_count) { - error_node(decl, "Extra initial expression"); - } - case_end; case_ast_node(vd, VarDecl, decl); if (!parent_scope->is_file) { // NOTE(bill): Within a procedure, variables must be in order @@ -1171,7 +1146,8 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As value = vd->values.e[i]; } if (name->kind != AstNode_Ident) { - error_node(name, "A declaration's name but be an identifier, got %.*s", LIT(ast_node_strings[name->kind])); + error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind])); + continue; } Entity *e = make_entity_variable(c->allocator, parent_scope, name->Ident, NULL); e->identifier = name; @@ -1180,7 +1156,7 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As DeclInfo *d = di; if (d == NULL) { AstNode *init_expr = value; - d = make_declaration_info(heap_allocator(), parent_scope); + d = make_declaration_info(heap_allocator(), e->scope); d->type_expr = vd->type; d->init_expr = init_expr; d->var_decl_tags = vd->tags; @@ -1189,15 +1165,52 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As add_entity_and_decl_info(c, name, e, d); } case_end; + case_ast_node(cd, ConstDecl, decl); + for_array(i, cd->values) { + AstNode *name = cd->names.e[i]; + AstNode *value = unparen_expr(cd->values.e[i]); + if (name->kind != AstNode_Ident) { + error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind])); + continue; + } + + ExactValue v = {ExactValue_Invalid}; + Entity *e = make_entity_constant(c->allocator, parent_scope, name->Ident, NULL, v); + e->identifier = name; + DeclInfo *di = make_declaration_info(c->allocator, e->scope); + di->type_expr = cd->type; + di->init_expr = value; + add_entity_and_decl_info(c, name, e, di); + } + + isize lhs_count = cd->names.count; + isize rhs_count = cd->values.count; + + if (rhs_count == 0 && cd->type == NULL) { + error_node(decl, "Missing type or initial expression"); + } else if (lhs_count < rhs_count) { + error_node(decl, "Extra initial expression"); + } + case_end; case_ast_node(td, TypeDecl, decl); + if (td->name->kind != AstNode_Ident) { + error_node(td->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[td->name->kind])); + continue; + } ast_node(n, Ident, td->name); + Entity *e = make_entity_type_name(c->allocator, parent_scope, *n, NULL); e->identifier = td->name; DeclInfo *d = make_declaration_info(c->allocator, e->scope); d->type_expr = td->type; + d->init_expr = td->type; add_entity_and_decl_info(c, td->name, e, d); case_end; case_ast_node(pd, ProcDecl, decl); + if (pd->name->kind != AstNode_Ident) { + error_node(pd->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[pd->name->kind])); + continue; + } ast_node(n, Ident, pd->name); Token token = *n; Entity *e = make_entity_procedure(c->allocator, parent_scope, token, NULL, pd->tags); @@ -1275,9 +1288,6 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { if (e->scope == parent_scope) { continue; } - - - // NOTE(bill): Do not add other imported entities add_entity(c, parent_scope, NULL, e); if (!id->is_load) { // `#import`ed entities don't get exported diff --git a/src/checker/decl.c b/src/checker/decl.c index 134bfb87b55..abdeddc8a3c 100644 --- a/src/checker/decl.c +++ b/src/checker/decl.c @@ -211,8 +211,25 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) { e->Constant.value = operand->value; } +void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) { + GB_ASSERT(e->type == NULL); + Type *named = make_type_named(c->allocator, e->token.string, NULL, e); + named->Named.type_name = e; + if (def != NULL && def->kind == Type_Named) { + def->Named.base = named; + } + e->type = named; + + // gb_printf_err("%.*s %p\n", LIT(e->token.string), e); -void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr) { + Type *bt = check_type_extra(c, type_expr, named); + named->Named.base = base_type(bt); + if (named->Named.base == t_invalid) { + // gb_printf("check_type_decl: %s\n", type_to_string(named)); + } +} + +void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr, Type *named_type) { GB_ASSERT(e->type == NULL); if (e->flags & EntityFlag_Visited) { @@ -238,26 +255,10 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_e // check_expr_or_type(c, &operand, init_expr); check_expr(c, &operand, init_expr); } + check_init_constant(c, e, &operand); } -void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) { - GB_ASSERT(e->type == NULL); - Type *named = make_type_named(c->allocator, e->token.string, NULL, e); - named->Named.type_name = e; - if (def != NULL && def->kind == Type_Named) { - def->Named.base = named; - } - e->type = named; - - // gb_printf_err("%.*s %p\n", LIT(e->token.string), e); - - Type *bt = check_type_extra(c, type_expr, named); - named->Named.base = base_type(bt); - if (named->Named.base == t_invalid) { - // gb_printf("check_type_decl: %s\n", type_to_string(named)); - } -} bool are_signatures_similar_enough(Type *a_, Type *b_) { @@ -458,6 +459,7 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) { if (found) { d = *found; } else { + // TODO(bill): Err here? e->type = t_invalid; set_base_type(named_type, t_invalid); return; @@ -471,7 +473,7 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) { switch (e->kind) { case Entity_Constant: - check_const_decl(c, e, d->type_expr, d->init_expr); + check_const_decl(c, e, d->type_expr, d->init_expr, named_type); break; case Entity_Variable: check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr); diff --git a/src/checker/expr.c b/src/checker/expr.c index 3ed5236fa02..08d5ac3ff23 100644 --- a/src/checker/expr.c +++ b/src/checker/expr.c @@ -11,9 +11,11 @@ bool check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, void convert_to_typed (Checker *c, Operand *operand, Type *target_type, i32 level); gbString expr_to_string (AstNode *expression); void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type *named_type); +void check_const_decl (Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr, Type *named_type); void check_proc_body (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body); void update_expr_type (Checker *c, AstNode *e, Type *type, bool final); + gb_inline Type *check_type(Checker *c, AstNode *expression) { return check_type_extra(c, expression, NULL); } @@ -87,22 +89,20 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie for_array(i, cd->values) { AstNode *name = cd->names.e[i]; - AstNode *value = cd->values.e[i]; - ExactValue v = {ExactValue_Invalid}; - - if (!ast_node_expect(name, AstNode_Ident)) { + AstNode *value = unparen_expr(cd->values.e[i]); + if (name->kind != AstNode_Ident) { + error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind])); entities[entity_index++] = NULL; continue; } + ExactValue v = {ExactValue_Invalid}; Entity *e = make_entity_constant(c->allocator, c->context.scope, name->Ident, NULL, v); e->identifier = name; entities[entity_index++] = e; - DeclInfo *d = make_declaration_info(c->allocator, e->scope); d->type_expr = cd->type; d->init_expr = value; - add_entity_and_decl_info(c, name, e, d); DelayedEntity delay = {name, e, d}; @@ -171,6 +171,10 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie if (!ast_node_expect(td->name, AstNode_Ident)) { break; } + if (td->name->kind != AstNode_Ident) { + error_node(td->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[td->name->kind])); + continue; + } Token name_token = td->name->Ident; @@ -457,7 +461,6 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, MapEntity *en gb_string_free(str); } -void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr); void check_fields(Checker *c, AstNode *node, AstNodeArray decls, Entity **fields, isize field_count, @@ -1581,6 +1584,11 @@ bool check_is_vector_elem(Checker *c, AstNode *expr) { void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) { switch (op.kind) { case Token_Pointer: { // Pointer address + if (o->mode == Addressing_Type) { + o->type = make_type_pointer(c->allocator, o->type); + return; + } + if (o->mode != Addressing_Variable || check_is_expr_vector_index(c, o->expr) || check_is_vector_elem(c, o->expr)) { @@ -1600,6 +1608,12 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) { case Token_Maybe: { // Make maybe Type *t = default_type(o->type); + + if (o->mode == Addressing_Type) { + o->type = make_type_pointer(c->allocator, t); + return; + } + bool is_value = o->mode == Addressing_Variable || o->mode == Addressing_Value || diff --git a/src/checker/stmt.c b/src/checker/stmt.c index d39e6f29fc9..e3929efe93e 100644 --- a/src/checker/stmt.c +++ b/src/checker/stmt.c @@ -1095,6 +1095,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { #if 1 // NOTE(bill): This must be handled here so it has access to the parent scope stuff // e.g. using + if (pd->name->kind != AstNode_Ident) { + error_node(pd->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[pd->name->kind])); + break; + } + Entity *e = make_entity_procedure(c->allocator, c->context.scope, pd->name->Ident, NULL, pd->tags); e->identifier = pd->name; diff --git a/src/gb/gb.h b/src/gb/gb.h index 92d283242fb..4c7498aa7cc 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -4112,7 +4112,7 @@ gb_inline i64 gb_atomic64_fetch_and(gbAtomic64 volatile *a, i64 operand) { gb_inline i64 gb_atomic64_fetch_or(gbAtomic64 volatile *a, i64 operand) { #if defined(GB_ARCH_64_BIT) - return _InterlockedAnd64(cast(i64 volatile *)a, operand); + return _InterlockedOr64(cast(i64 volatile *)a, operand); #elif GB_CPU_X86 i64 expected = a->value; for (;;) { diff --git a/src/parser.c b/src/parser.c index 6b09b9da6e5..62c8902b0ec 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1936,6 +1936,7 @@ AstNode *parse_simple_stmt(AstFile *f) { f->curr_token.kind == Token_enum || f->curr_token.kind == Token_union || f->curr_token.kind == Token_raw_union) { + // if (f->curr_token.kind == Token_type) { Token token = f->curr_token; if (token.kind == Token_type) { next_token(f); diff --git a/src/tokenizer.c b/src/tokenizer.c index b82e5a7803a..5d1d63a1b81 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -109,7 +109,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ TOKEN_KIND(Token_using, "using"), \ TOKEN_KIND(Token_asm, "asm"), \ TOKEN_KIND(Token_volatile, "volatile"), \ - TOKEN_KIND(Token_atomic, "atomic"), \ +/* TOKEN_KIND(Token_atomic, "atomic"), */\ TOKEN_KIND(Token_push_allocator, "push_allocator"), \ TOKEN_KIND(Token_push_context, "push_context"), \ TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \