From 96f0a08725cc8662e94f87ef9b637292b85a5ba4 Mon Sep 17 00:00:00 2001 From: Joshua Mark Manton Date: Sat, 20 Jul 2019 13:15:51 -0700 Subject: [PATCH 001/143] Fix `scale_f32` and `scale_vec3` from returning the wrong variable. --- core/math/math.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/math/math.odin b/core/math/math.odin index 016e8143a..ed04cbfbc 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -454,7 +454,7 @@ scale_vec3 :: proc(m: Mat4, v: Vec3) -> Mat4 { mm[0][0] *= v[0]; mm[1][1] *= v[1]; mm[2][2] *= v[2]; - return m; + return mm; } scale_f32 :: proc(m: Mat4, s: f32) -> Mat4 { @@ -462,7 +462,7 @@ scale_f32 :: proc(m: Mat4, s: f32) -> Mat4 { mm[0][0] *= s; mm[1][1] *= s; mm[2][2] *= s; - return m; + return mm; } scale :: proc{scale_vec3, scale_f32}; From 40f0e74b8c93f753479c6d0ed52d0b1a812f6acd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 27 Jul 2019 00:45:36 +0100 Subject: [PATCH 002/143] Change scoping rules to allow for shadowing of procedure parameters but not named return values --- src/check_decl.cpp | 4 ++-- src/checker.cpp | 45 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 1a6fad918..f3e0f70bc 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1141,7 +1141,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty } ast_node(bs, BlockStmt, body); - // check_open_scope(ctx, body); + check_open_scope(ctx, body); check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls); if (type->Proc.result_count > 0) { if (!check_is_terminating(body)) { @@ -1153,7 +1153,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty } } } - // check_close_scope(ctx); + check_close_scope(ctx); check_scope_usage(ctx->checker, ctx->scope); diff --git a/src/checker.cpp b/src/checker.cpp index 9abd8c499..f68e2ab15 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -400,6 +400,15 @@ Entity *scope_insert_with_name(Scope *s, String name, Entity *entity) { if (found) { return *found; } + if (s->parent != nullptr && (s->parent->flags & ScopeFlag_Proc) != 0) { + Entity **found = map_get(&s->parent->elements, key); + if (found) { + if ((*found)->flags & EntityFlag_Result) { + return *found; + } + } + } + map_set(&s->elements, key, entity); if (entity->scope == nullptr) { entity->scope = s; @@ -1044,21 +1053,37 @@ bool redeclaration_error(String name, Entity *prev, Entity *found) { // NOTE(bill): Error should have been handled already return false; } - error(prev->token, - "Redeclaration of '%.*s' in this scope through 'using'\n" - "\tat %.*s(%td:%td)", - LIT(name), - LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column); + if (found->flags & EntityFlag_Result) { + error(prev->token, + "Direct shadowing of the named return value '%.*s' in this scope through 'using'\n" + "\tat %.*s(%td:%td)", + LIT(name), + LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column); + } else { + error(prev->token, + "Redeclaration of '%.*s' in this scope through 'using'\n" + "\tat %.*s(%td:%td)", + LIT(name), + LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column); + } } else { if (pos == prev->token.pos) { // NOTE(bill): Error should have been handled already return false; } - error(prev->token, - "Redeclaration of '%.*s' in this scope\n" - "\tat %.*s(%td:%td)", - LIT(name), - LIT(pos.file), pos.line, pos.column); + if (found->flags & EntityFlag_Result) { + error(prev->token, + "Direct shadowing of the named return value '%.*s' in this scope\n" + "\tat %.*s(%td:%td)", + LIT(name), + LIT(pos.file), pos.line, pos.column); + } else { + error(prev->token, + "Redeclaration of '%.*s' in this scope\n" + "\tat %.*s(%td:%td)", + LIT(name), + LIT(pos.file), pos.line, pos.column); + } } return false; } From f3bffb98101e3a584c8a5e8a6389c608ffe64c40 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 27 Jul 2019 10:20:11 +0100 Subject: [PATCH 003/143] Improvement to the Odin calling conventions to pass certain things by "implicit reference" (`const &` in C++) --- src/check_type.cpp | 8 ++++++++ src/entity.cpp | 3 ++- src/ir.cpp | 3 +-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index f4e5b49d0..5b20a48fc 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2084,6 +2084,14 @@ void set_procedure_abi_types(CheckerContext *c, Type *type) { Type *original_type = e->type; Type *new_type = type_to_abi_compat_param_type(c->allocator, original_type, type->Proc.calling_convention); type->Proc.abi_compat_params[i] = new_type; + switch (type->Proc.calling_convention) { + case ProcCC_Odin: + case ProcCC_Contextless: + if (is_type_pointer(new_type) & !is_type_pointer(e->type)) { + e->flags |= EntityFlag_ImplicitReference; + } + break; + } } } diff --git a/src/entity.cpp b/src/entity.cpp index 3318eac24..0c05a9bf6 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -48,7 +48,8 @@ enum EntityFlag { EntityFlag_NotExported = 1<<14, EntityFlag_Static = 1<<16, - // EntityFlag_Reference = 1<<17, + + EntityFlag_ImplicitReference = 1<<17, // NOTE(bill): equivalent to `const &` in C++ EntityFlag_CVarArg = 1<<20, EntityFlag_AutoCast = 1<<21, diff --git a/src/ir.cpp b/src/ir.cpp index 82f9fa755..8c5dcb963 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3004,9 +3004,8 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro if (are_types_identical(arg_type, new_type)) { // NOTE(bill): Done } else if (!are_types_identical(original_type, new_type)) { - if (is_type_pointer(new_type) && !is_type_pointer(original_type)) { - if (e->flags&EntityFlag_Value) { + if (e->flags&EntityFlag_ImplicitReference) { args[i] = ir_address_from_load_or_generate_local(p, args[i]); } else if (!is_type_pointer(arg_type)) { args[i] = ir_copy_value_to_ptr(p, args[i], original_type, 16); From 14059583cdb3039a16979f97c4fd1907fc069662 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 27 Jul 2019 10:44:40 +0100 Subject: [PATCH 004/143] Fix array comparisons --- src/ir.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 8c5dcb963..973aa7476 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4111,14 +4111,17 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal if (inline_array_arith) { // inline + irValue *val = ir_add_local_generated(proc, t_bool, false); + ir_emit_store(proc, val, res); for (i32 i = 0; i < count; i++) { irValue *x = ir_emit_load(proc, ir_emit_array_epi(proc, lhs, i)); irValue *y = ir_emit_load(proc, ir_emit_array_epi(proc, rhs, i)); irValue *cmp = ir_emit_comp(proc, op_kind, x, y); - res = ir_emit_arith(proc, cmp_op, res, cmp, t_bool); + irValue *new_res = ir_emit_arith(proc, cmp_op, ir_emit_load(proc, val), cmp, t_bool); + ir_emit_store(proc, val, ir_emit_conv(proc, new_res, t_bool)); } - return ir_emit_conv(proc, res, t_bool); + return ir_emit_load(proc, val); } else { irValue *val = ir_add_local_generated(proc, t_bool, false); ir_emit_store(proc, val, res); @@ -4127,7 +4130,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, loop_data.idx)); irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, loop_data.idx)); irValue *cmp = ir_emit_comp(proc, op_kind, x, y); - irValue *new_res = ir_emit_arith(proc, cmp_op, res, cmp, t_bool); + irValue *new_res = ir_emit_arith(proc, cmp_op, res, ir_emit_load(proc, val), t_bool); ir_emit_store(proc, val, ir_emit_conv(proc, new_res, t_bool)); } ir_loop_end(proc, loop_data); From 912fc2890b1603ff8f6ffa09b15719322e852edf Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 27 Jul 2019 11:33:22 +0100 Subject: [PATCH 005/143] Fix array comparisons and fix f32 literal LLVM issue regarding accurate representation --- src/ir.cpp | 20 ++++++++++++-------- src/ir_print.cpp | 24 ++++++++++++++++++++---- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 973aa7476..9f95db524 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3652,12 +3652,12 @@ struct irLoopData { irBlock *loop; }; -irLoopData ir_loop_start(irProcedure *proc, isize count) { +irLoopData ir_loop_start(irProcedure *proc, isize count, Type *index_type=t_int) { irLoopData data = {}; irValue *max = ir_const_int(count); - data.idx_addr = ir_add_local_generated(proc, t_int, true); + data.idx_addr = ir_add_local_generated(proc, index_type, true); data.body = ir_new_block(proc, nullptr, "loop.body"); data.done = ir_new_block(proc, nullptr, "loop.done"); @@ -3727,7 +3727,7 @@ irValue *ir_emit_unary_arith(irProcedure *proc, TokenKind op, irValue *x, Type * ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z); } } else { - auto loop_data = ir_loop_start(proc, count); + auto loop_data = ir_loop_start(proc, count, t_i32); irValue *e = ir_emit_load(proc, ir_emit_array_ep(proc, val, loop_data.idx)); irValue *z = ir_emit_unary_arith(proc, op, e, elem_type); @@ -3786,7 +3786,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z); } } else { - auto loop_data = ir_loop_start(proc, count); + auto loop_data = ir_loop_start(proc, count, t_i32); irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, loop_data.idx)); irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, loop_data.idx)); @@ -4104,6 +4104,9 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal if (op_kind == Token_NotEq) { res = v_false; cmp_op = Token_Or; + } else if (op_kind == Token_CmpEq) { + res = v_true; + cmp_op = Token_And; } bool inline_array_arith = type_size_of(tl) <= build_context.max_align; @@ -4125,12 +4128,13 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal } else { irValue *val = ir_add_local_generated(proc, t_bool, false); ir_emit_store(proc, val, res); - auto loop_data = ir_loop_start(proc, count); + auto loop_data = ir_loop_start(proc, count, t_i32); { - irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, loop_data.idx)); - irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, loop_data.idx)); + irValue *i = loop_data.idx; + irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, i)); + irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, i)); irValue *cmp = ir_emit_comp(proc, op_kind, x, y); - irValue *new_res = ir_emit_arith(proc, cmp_op, res, ir_emit_load(proc, val), t_bool); + irValue *new_res = ir_emit_arith(proc, cmp_op, ir_emit_load(proc, val), cmp, t_bool); ir_emit_store(proc, val, ir_emit_conv(proc, new_res, t_bool)); } ir_loop_end(proc, loop_data); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index b008fa682..a64f454d0 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -767,15 +767,17 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * case ExactValue_Float: { GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type)); type = core_type(type); - u64 u = bit_cast(value.value_float); + u64 u_64 = bit_cast(value.value_float); + u32 u_32 = bit_cast(cast(f32)value.value_float); + #if 0 switch (type->Basic.kind) { case Basic_f32: // IMPORTANT NOTE(bill): LLVM requires all floating point constants to be // a 64 bit number if bits_of(float type) <= 64. // https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M - // 64 bit mantissa: 52 bits - // 32 bit mantissa: 23 bits - // 16 bit mantissa: 10 bits + // 64 bit mantissa: 52 bits ==> 52-52 == 0 + // 32 bit mantissa: 23 bits ==> 52-23 == 29 + // 16 bit mantissa: 10 bits ==> 52=10 == 42 // 29 == 52-23 u >>= 29; u <<= 29; @@ -792,6 +794,20 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * ir_fprintf(f, "0x%016llx", u); break; } + #else + switch (type->Basic.kind) { + case Basic_f32: { + ir_fprintf(f, "bitcast (i32 %u to float)", u_32); + break; + } + case Basic_f64: + ir_fprintf(f, "0x%016llx", u_64); + break; + default: + ir_fprintf(f, "0x%016llx", u_64); + break; + } + #endif break; } case ExactValue_Complex: { From 77734ea967d620541eadc770280477cf1550892e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 27 Jul 2019 11:59:50 +0100 Subject: [PATCH 006/143] Improve the performance of simple array comparisons --- core/runtime/internal.odin | 40 +++++++++++++++++++++++++++++++++++++- src/checker.cpp | 2 ++ src/ir.cpp | 37 ++++++++++++++++++++++------------- src/types.cpp | 23 ++++++++++++++++++++++ 4 files changed, 88 insertions(+), 14 deletions(-) diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index d4d7ab84d..90d653c71 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -243,6 +243,44 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) { } } +memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check { + x := uintptr(a); + y := uintptr(b); + n := uintptr(n); + + SU :: size_of(uintptr); + fast := uintptr(n/SU + 1); + offset := (fast-1)*SU; + curr_block := uintptr(0); + if n < SU { + fast = 0; + } + + for /**/; curr_block < fast; curr_block += 1 { + va := (^uintptr)(x + curr_block * size_of(uintptr))^; + vb := (^uintptr)(y + curr_block * size_of(uintptr))^; + if va ~ vb != 0 { + for pos := curr_block*SU; pos < n; pos += 1 { + a := (^byte)(x+pos)^; + b := (^byte)(y+pos)^; + if a ~ b != 0 { + return (int(a) - int(b)) < 0 ? -1 : +1; + } + } + } + } + + for /**/; offset < n; offset += 1 { + a := (^byte)(x+offset)^; + b := (^byte)(y+offset)^; + if a ~ b != 0 { + return (int(a) - int(b)) < 0 ? -1 : +1; + } + } + + return 0; +} + string_eq :: proc "contextless" (a, b: string) -> bool { switch { case len(a) != len(b): return false; @@ -253,7 +291,7 @@ string_eq :: proc "contextless" (a, b: string) -> bool { } string_cmp :: proc "contextless" (a, b: string) -> int { - return mem.compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b))); + return memory_compare(&a[0], &b[0], min(len(a), len(b))); } string_ne :: inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b); } diff --git a/src/checker.cpp b/src/checker.cpp index f68e2ab15..ba13b2237 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1613,6 +1613,8 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("umodti3"), str_lit("udivti3"), + + str_lit("memory_compare"), }; for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) { add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i])); diff --git a/src/ir.cpp b/src/ir.cpp index 9f95db524..1105eac29 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4126,20 +4126,31 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal return ir_emit_load(proc, val); } else { - irValue *val = ir_add_local_generated(proc, t_bool, false); - ir_emit_store(proc, val, res); - auto loop_data = ir_loop_start(proc, count, t_i32); - { - irValue *i = loop_data.idx; - irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, i)); - irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, i)); - irValue *cmp = ir_emit_comp(proc, op_kind, x, y); - irValue *new_res = ir_emit_arith(proc, cmp_op, ir_emit_load(proc, val), cmp, t_bool); - ir_emit_store(proc, val, ir_emit_conv(proc, new_res, t_bool)); - } - ir_loop_end(proc, loop_data); + if (is_type_simple_compare(tl) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) { + // TODO(bill): Test to see if this is actually faster!!!! + auto args = array_make(heap_allocator(), 3); + args[0] = ir_emit_conv(proc, lhs, t_rawptr); + args[1] = ir_emit_conv(proc, rhs, t_rawptr); + args[2] = ir_const_int(type_size_of(tl)); + irValue *val = ir_emit_runtime_call(proc, "memory_compare", args); + irValue *res = ir_emit_comp(proc, op_kind, val, v_zero); + return ir_emit_conv(proc, res, t_bool); + } else { + irValue *val = ir_add_local_generated(proc, t_bool, false); + ir_emit_store(proc, val, res); + auto loop_data = ir_loop_start(proc, count, t_i32); + { + irValue *i = loop_data.idx; + irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, i)); + irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, i)); + irValue *cmp = ir_emit_comp(proc, op_kind, x, y); + irValue *new_res = ir_emit_arith(proc, cmp_op, ir_emit_load(proc, val), cmp, t_bool); + ir_emit_store(proc, val, ir_emit_conv(proc, new_res, t_bool)); + } + ir_loop_end(proc, loop_data); - return ir_emit_load(proc, val); + return ir_emit_load(proc, val); + } } } diff --git a/src/types.cpp b/src/types.cpp index dc7ecb946..5cf86d6b6 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1037,6 +1037,29 @@ Type *core_array_type(Type *t) { return t; } +// NOTE(bill): type can be easily compared using memcmp +bool is_type_simple_compare(Type *t) { + t = core_type(t); + switch (t->kind) { + case Type_Array: + return is_type_simple_compare(t->Array.elem); + + case Type_Basic: + if (t->Basic.flags & (BasicFlag_Integer|BasicFlag_Float|BasicFlag_Complex|BasicFlag_Rune|BasicFlag_Pointer)) { + return true; + } + return false; + + case Type_Pointer: + case Type_Proc: + case Type_BitSet: + case Type_BitField: + return true; + } + + return false; +} + Type *base_complex_elem_type(Type *t) { t = core_type(t); if (is_type_complex(t)) { From 162c87b1b810770f75920a51682a8f6b63adeba4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 28 Jul 2019 18:44:50 +0100 Subject: [PATCH 007/143] Minor code clean-up --- core/log/log.odin | 67 +++++++++++++++++++++------------------- core/mem/allocators.odin | 2 -- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/core/log/log.odin b/core/log/log.odin index 13e370b91..76b8550e8 100644 --- a/core/log/log.odin +++ b/core/log/log.odin @@ -11,30 +11,30 @@ Level :: enum { } Option :: enum { - Level, - Date, - Time, - Short_File_Path, - Long_File_Path, - Line, - Procedure, - Terminal_Color + Level, + Date, + Time, + Short_File_Path, + Long_File_Path, + Line, + Procedure, + Terminal_Color } Options :: bit_set[Option]; Full_Timestamp_Opts :: Options{ - Option.Date, - Option.Time + .Date, + .Time }; Location_Header_Opts :: Options{ - Option.Short_File_Path, - Option.Long_File_Path, - Option.Line, - Option.Procedure, + .Short_File_Path, + .Long_File_Path, + .Line, + .Procedure, }; Location_File_Opts :: Options{ - Option.Short_File_Path, - Option.Long_File_Path + .Short_File_Path, + .Long_File_Path }; Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location); @@ -42,30 +42,34 @@ Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Opt Logger :: struct { procedure: Logger_Proc, data: rawptr, - options: Options, + options: Options, } Multi_Logger_Data :: struct { - loggers : []Logger, + loggers : []Logger, } create_multi_logger :: proc(logs: ..Logger) -> Logger { - data := new(Multi_Logger_Data); - data.loggers = make([]Logger, len(logs)); - copy(data.loggers, logs); - return Logger{multi_logger_proc, data, nil}; + data := new(Multi_Logger_Data); + data.loggers = make([]Logger, len(logs)); + copy(data.loggers, logs); + return Logger{multi_logger_proc, data, nil}; } -destroy_multi_logger ::proc(log : ^Logger) { - free(log.data); - log^ = nil_logger(); +destroy_multi_logger :: proc(log : ^Logger) { + free(log.data); + log^ = nil_logger(); } multi_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) { - data := cast(^Multi_Logger_Data)logger_data; - if data.loggers == nil || len(data.loggers) == 0 do return; - for log in data.loggers do log.procedure(log.data, level, text, log.options, location); + data := cast(^Multi_Logger_Data)logger_data; + if data.loggers == nil || len(data.loggers) == 0 { + return; + } + for log in data.loggers { + log.procedure(log.data, level, text, log.options, location); + } } nil_logger_proc :: proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location) { @@ -76,6 +80,7 @@ nil_logger :: proc() -> Logger { return Logger{nil_logger_proc, nil, nil}; } +// TODO(bill): Should these be redesigned so that they are do not rely upon `package fmt`? debug :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Debug, fmt_str=fmt_str, args=args, location=location); info :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Info, fmt_str=fmt_str, args=args, location=location); warn :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Warning, fmt_str=fmt_str, args=args, location=location); @@ -83,7 +88,7 @@ error :: proc(fmt_str : string, args : ..any, location := #caller_location) do l fatal :: proc(fmt_str : string, args : ..any, location := #caller_location) do logf(level=Level.Fatal, fmt_str=fmt_str, args=args, location=location); logf :: proc(level : Level, fmt_str : string, args : ..any, location := #caller_location) { - logger := context.logger; - str := len(args) > 0 ? fmt.tprintf(fmt_str, ..args) : fmt.tprint(fmt_str); //NOTE(Hoej): While tprint isn't thread-safe, no logging is. - logger.procedure(logger.data, level, str, logger.options, location); + logger := context.logger; + str := len(args) > 0 ? fmt.tprintf(fmt_str, ..args) : fmt.tprint(fmt_str); //NOTE(Hoej): While tprint isn't thread-safe, no logging is. + logger.procedure(logger.data, level, str, logger.options, location); } diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 04b0fd0b1..7ef094bc1 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -1,7 +1,5 @@ package mem - - nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr { From 2c5c8192f8fcb40fdef183c25a8d799f23f23439 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 28 Jul 2019 22:58:56 +0100 Subject: [PATCH 008/143] Fix parsing for procedure literals expression statements; improve assert performance; other minor fixes --- core/odin/parser/parser.odin | 1 + core/runtime/core.odin | 12 +++++++----- core/sys/win32/kernel32.odin | 2 +- core/sys/win32/user32.odin | 2 +- core/time/time_windows.odin | 2 +- src/ir.cpp | 2 +- src/parser.cpp | 1 + 7 files changed, 13 insertions(+), 9 deletions(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 077e04cc9..0c011e07e 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -955,6 +955,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { switch p.curr_tok.kind { // Operands case token.Context, // Also allows for 'context = ' + token.Proc, token.Inline, token.No_Inline, token.Ident, token.Integer, token.Float, token.Imag, diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 623f3725a..02578da3b 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -666,11 +666,13 @@ card :: proc(s: $S/bit_set[$E; $U]) -> int { @builtin assert :: proc(condition: bool, message := "", loc := #caller_location) -> bool { if !condition { - p := context.assertion_failure_proc; - if p == nil { - p = default_assertion_failure_proc; - } - p("Runtime assertion", message, loc); + proc(message: string, loc: Source_Code_Location) { + p := context.assertion_failure_proc; + if p == nil { + p = default_assertion_failure_proc; + } + p("Runtime assertion", message, loc); + }(message, loc); } return condition; } diff --git a/core/sys/win32/kernel32.odin b/core/sys/win32/kernel32.odin index 036fc016a..f647ab7e0 100644 --- a/core/sys/win32/kernel32.odin +++ b/core/sys/win32/kernel32.odin @@ -23,7 +23,7 @@ foreign kernel32 { @(link_name="GetModuleFileNameA") get_module_file_name_a :: proc(module: Hmodule, filename: cstring, size: u32) -> u32 ---; @(link_name="GetModuleFileNameW") get_module_file_name_w :: proc(module: Hmodule, filename: Wstring, size: u32) -> u32 ---; - @(link_name="Sleep") sleep :: proc(ms: i32) -> i32 ---; + @(link_name="Sleep") sleep :: proc(ms: u32) ---; @(link_name="QueryPerformanceFrequency") query_performance_frequency :: proc(result: ^i64) -> i32 ---; @(link_name="QueryPerformanceCounter") query_performance_counter :: proc(result: ^i64) -> i32 ---; @(link_name="OutputDebugStringA") output_debug_string_a :: proc(c_str: cstring) ---; diff --git a/core/sys/win32/user32.odin b/core/sys/win32/user32.odin index b8969faf3..5165d9389 100644 --- a/core/sys/win32/user32.odin +++ b/core/sys/win32/user32.odin @@ -182,7 +182,7 @@ foreign user32 { @(link_name="DestroyIcon") destroy_icon :: proc(icon: Hicon) -> Bool ---; @(link_name="LoadCursorA") load_cursor_a :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---; - @(link_name="LoadCursorW") load_cursor_w :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---; + @(link_name="LoadCursorW") load_cursor_w :: proc(instance: Hinstance, cursor_name: Wstring) -> Hcursor ---; @(link_name="GetCursor") get_cursor :: proc() -> Hcursor ---; @(link_name="SetCursor") set_cursor :: proc(cursor: Hcursor) -> Hcursor ---; diff --git a/core/time/time_windows.odin b/core/time/time_windows.odin index 31fbca769..f6bfdd678 100644 --- a/core/time/time_windows.odin +++ b/core/time/time_windows.odin @@ -20,5 +20,5 @@ now :: proc() -> Time { sleep :: proc(d: Duration) { - win32.sleep(i32(d/Millisecond)); + win32.sleep(u32(d/Millisecond)); } diff --git a/src/ir.cpp b/src/ir.cpp index 1105eac29..0a5dc7528 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3053,7 +3053,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro if (value->kind == irValue_Proc) { irProcedure *the_proc = &value->Proc; Entity *e = the_proc->entity; - if (entity_has_deferred_procedure(e)) { + if (e != nullptr && entity_has_deferred_procedure(e)) { DeferredProcedureKind kind = e->Procedure.deferred_procedure.kind; Entity *deferred_entity = e->Procedure.deferred_procedure.entity; irValue **deferred_found = map_get(&p->module->values, hash_entity(deferred_entity)); diff --git a/src/parser.cpp b/src/parser.cpp index a377b773c..d1fd94c1d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3759,6 +3759,7 @@ Ast *parse_stmt(AstFile *f) { switch (token.kind) { // Operands case Token_context: // Also allows for `context =` + case Token_proc: case Token_inline: case Token_no_inline: case Token_Ident: From f1631812049ae2c50b9ddb2f5c163327f15731c8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 29 Jul 2019 10:43:07 +0100 Subject: [PATCH 009/143] Add extra hints for LLVM for implicit reference parameters --- src/ir_print.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ir_print.cpp b/src/ir_print.cpp index a64f454d0..58e7b8b0d 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1904,6 +1904,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { if (e->flags&EntityFlag_NoAlias) { ir_write_str_lit(f, " noalias"); } + if (e->flags&EntityFlag_ImplicitReference) { + ir_write_str_lit(f, " nonnull dereferenceable"); + } ir_write_byte(f, ' '); irValue *arg = call->args[i]; if (is_type_boolean(t)) { From e7d3001dd1ef698304d5fcda2c564350d6a25fe8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 29 Jul 2019 18:33:06 +0100 Subject: [PATCH 010/143] Fix constant default value error #408 (typo) --- src/check_type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index 5b20a48fc..bcf0ed71c 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1538,7 +1538,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is } if (is_poly_name) { - if (type != nullptr && type_expr->kind == Ast_TypeidType) { + if (type_expr != nullptr && type_expr->kind == Ast_TypeidType) { is_type_param = true; } else { if (param_value.kind != ParameterValue_Invalid) { From 132fdf14b8c9dd717aea6ced64641030dd8adb47 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 3 Aug 2019 10:07:09 +0100 Subject: [PATCH 011/143] Fix `min`, `max`, `clamp` final type bug --- src/check_expr.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4c5ca2348..36304bf65 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3959,6 +3959,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 Type *bt = base_type(operands[0].type); if (are_types_identical(bt, t_f32)) add_package_dependency(c, "runtime", "min_f32"); if (are_types_identical(bt, t_f64)) add_package_dependency(c, "runtime", "min_f64"); + + operand->type = operands[0].type; } } break; @@ -4119,6 +4121,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 Type *bt = base_type(operands[0].type); if (are_types_identical(bt, t_f32)) add_package_dependency(c, "runtime", "max_f32"); if (are_types_identical(bt, t_f64)) add_package_dependency(c, "runtime", "max_f64"); + + operand->type = operands[0].type; } } break; @@ -4266,6 +4270,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 add_package_dependency(c, "runtime", "min_f64"); add_package_dependency(c, "runtime", "max_f64"); } + + operand->type = ops[0]->type; } } From 5877017d30999388c832f6467116336733b607e2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 3 Aug 2019 10:15:31 +0100 Subject: [PATCH 012/143] Add error message for non-constant polymorphic name parameters --- src/check_type.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/check_type.cpp b/src/check_type.cpp index bcf0ed71c..36d8cf0f8 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1622,6 +1622,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is if (op.mode == Addressing_Constant) { poly_const = op.value; } else { + error(op.expr, "Expected a constant value for this polymorphic name parameter"); success = false; } } From 37633c1d2a9cc2ab5ae659ffb359f7f56f0457a2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2019 11:02:00 +0100 Subject: [PATCH 013/143] `intrinsics.type_*` constant evaluation procedures --- src/check_expr.cpp | 412 +++++++++++++++++++++++++++++++++- src/checker.hpp | 212 +---------------- src/checker_builtin_procs.hpp | 312 +++++++++++++++++++++++++ src/exact_value.cpp | 10 +- src/types.cpp | 13 ++ 5 files changed, 739 insertions(+), 220 deletions(-) create mode 100644 src/checker_builtin_procs.hpp diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 36304bf65..6a789bc33 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3178,7 +3178,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 /*fallthrough*/ } default: - if (ce->args.count > 0) { + if (BuiltinProc__type_begin < id && id < BuiltinProc__type_end) { + check_expr_or_type(c, operand, ce->args[0]); + } else if (ce->args.count > 0) { check_multi_expr(c, operand, ce->args[0]); } break; @@ -4445,6 +4447,414 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } break; + + case BuiltinProc_type_base_type: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + } else { + operand->type = base_type(operand->type); + } + operand->mode = Addressing_Type; + break; + case BuiltinProc_type_core_type: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + } else { + operand->type = core_type(operand->type); + } + operand->mode = Addressing_Type; + break; + + case BuiltinProc_type_is_boolean: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_boolean(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_integer: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_integer(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_rune: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_rune(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_float: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + } else { + + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_complex: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_complex(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_string: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_string(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_typeid: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_typeid(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_any: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_any(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + + case BuiltinProc_type_is_endian_little: + operand->value = exact_value_bool(false); + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected an integer type for '%.*s'", LIT(builtin_name)); + } else if (!is_type_integer(operand->type)) { + error(operand->expr, "Expected an integer type for '%.*s'", LIT(builtin_name)); + } else { + operand->value = exact_value_bool(is_type_integer_endian_little(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_endian_big: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else if (!is_type_integer(operand->type)) { + error(operand->expr, "Expected an integer type for '%.*s'", LIT(builtin_name)); + } else { + operand->value = exact_value_bool(is_type_integer_endian_big(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_numeric: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_numeric(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_ordered: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_ordered(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_ordered_numeric: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_numeric(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_indexable: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_indexable(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_sliceable: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_sliceable(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_simple_compare: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_simple_compare(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_dereferenceable: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + if (is_type_rawptr(operand->type)) { + operand->value = exact_value_bool(false); + } else if (is_type_pointer(operand->type)) { + operand->value = exact_value_bool(true); + } else { + operand->value = exact_value_bool(false); + } + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + + case BuiltinProc_type_is_named: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_named(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_pointer: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_pointer(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_opaque: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_opaque(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_array: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_array(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_slice: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_slice(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_dynamic_array: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_dynamic_array(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_map: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_map(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_struct: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_struct(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_union: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_union(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_enum: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_enum(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_proc: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_proc(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_bit_field: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_bit_field(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_bit_field_value: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_bit_field_value(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_bit_set: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_bit_set(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_is_simd_vector: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->value = exact_value_bool(false); + } else { + operand->value = exact_value_bool(is_type_simd_vector(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + + case BuiltinProc_type_has_nil: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + } else { + operand->value = exact_value_bool(type_has_nil(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + + case BuiltinProc_type_elem_type: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + } else { + Type *bt = base_type(operand->type); + switch (bt->kind) { + case Type_Basic: + switch (bt->Basic.kind) { + case Basic_complex64: operand->type = t_f32; break; + case Basic_complex128: operand->type = t_f64; break; + } + break; + case Type_Pointer: operand->type = bt->Pointer.elem; break; + case Type_Opaque: operand->type = bt->Opaque.elem; break; + case Type_Array: operand->type = bt->Array.elem; break; + case Type_Slice: operand->type = bt->Slice.elem; break; + case Type_DynamicArray: operand->type = bt->DynamicArray.elem; break; + } + } + operand->mode = Addressing_Type; + break; + + case BuiltinProc_type_proc_parameter_count: + operand->value = exact_value_i64(0); + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a procedure type for '%.*s'", LIT(builtin_name)); + } else if (!is_type_proc(operand->type)) { + error(operand->expr, "Expected a procedure type for '%.*s'", LIT(builtin_name)); + } else { + Type *bt = base_type(operand->type); + operand->value = exact_value_i64(bt->Proc.param_count); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + break; + case BuiltinProc_type_proc_return_count: + operand->value = exact_value_i64(0); + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a procedure type for '%.*s'", LIT(builtin_name)); + } else if (!is_type_proc(operand->type)) { + error(operand->expr, "Expected a procedure type for '%.*s'", LIT(builtin_name)); + } else { + Type *bt = base_type(operand->type); + operand->value = exact_value_i64(bt->Proc.result_count); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + break; } return true; diff --git a/src/checker.hpp b/src/checker.hpp index 66b68c35c..4e4a8cfe1 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -59,218 +59,8 @@ struct BuiltinProc { BuiltinProcPkg pkg; }; -enum BuiltinProcId { - BuiltinProc_Invalid, - BuiltinProc_len, - BuiltinProc_cap, - - BuiltinProc_size_of, - BuiltinProc_align_of, - BuiltinProc_offset_of, - BuiltinProc_type_of, - BuiltinProc_type_info_of, - BuiltinProc_typeid_of, - - BuiltinProc_swizzle, - - BuiltinProc_complex, - BuiltinProc_real, - BuiltinProc_imag, - BuiltinProc_conj, - - BuiltinProc_expand_to_tuple, - - BuiltinProc_min, - BuiltinProc_max, - BuiltinProc_abs, - BuiltinProc_clamp, - - BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures - - // "Intrinsics" - BuiltinProc_vector, - - BuiltinProc_atomic_fence, - BuiltinProc_atomic_fence_acq, - BuiltinProc_atomic_fence_rel, - BuiltinProc_atomic_fence_acqrel, - - BuiltinProc_atomic_store, - BuiltinProc_atomic_store_rel, - BuiltinProc_atomic_store_relaxed, - BuiltinProc_atomic_store_unordered, - - BuiltinProc_atomic_load, - BuiltinProc_atomic_load_acq, - BuiltinProc_atomic_load_relaxed, - BuiltinProc_atomic_load_unordered, - - BuiltinProc_atomic_add, - BuiltinProc_atomic_add_acq, - BuiltinProc_atomic_add_rel, - BuiltinProc_atomic_add_acqrel, - BuiltinProc_atomic_add_relaxed, - BuiltinProc_atomic_sub, - BuiltinProc_atomic_sub_acq, - BuiltinProc_atomic_sub_rel, - BuiltinProc_atomic_sub_acqrel, - BuiltinProc_atomic_sub_relaxed, - BuiltinProc_atomic_and, - BuiltinProc_atomic_and_acq, - BuiltinProc_atomic_and_rel, - BuiltinProc_atomic_and_acqrel, - BuiltinProc_atomic_and_relaxed, - BuiltinProc_atomic_nand, - BuiltinProc_atomic_nand_acq, - BuiltinProc_atomic_nand_rel, - BuiltinProc_atomic_nand_acqrel, - BuiltinProc_atomic_nand_relaxed, - BuiltinProc_atomic_or, - BuiltinProc_atomic_or_acq, - BuiltinProc_atomic_or_rel, - BuiltinProc_atomic_or_acqrel, - BuiltinProc_atomic_or_relaxed, - BuiltinProc_atomic_xor, - BuiltinProc_atomic_xor_acq, - BuiltinProc_atomic_xor_rel, - BuiltinProc_atomic_xor_acqrel, - BuiltinProc_atomic_xor_relaxed, - - BuiltinProc_atomic_xchg, - BuiltinProc_atomic_xchg_acq, - BuiltinProc_atomic_xchg_rel, - BuiltinProc_atomic_xchg_acqrel, - BuiltinProc_atomic_xchg_relaxed, - - BuiltinProc_atomic_cxchg, - BuiltinProc_atomic_cxchg_acq, - BuiltinProc_atomic_cxchg_rel, - BuiltinProc_atomic_cxchg_acqrel, - BuiltinProc_atomic_cxchg_relaxed, - BuiltinProc_atomic_cxchg_failrelaxed, - BuiltinProc_atomic_cxchg_failacq, - BuiltinProc_atomic_cxchg_acq_failrelaxed, - BuiltinProc_atomic_cxchg_acqrel_failrelaxed, - - BuiltinProc_atomic_cxchgweak, - BuiltinProc_atomic_cxchgweak_acq, - BuiltinProc_atomic_cxchgweak_rel, - BuiltinProc_atomic_cxchgweak_acqrel, - BuiltinProc_atomic_cxchgweak_relaxed, - BuiltinProc_atomic_cxchgweak_failrelaxed, - BuiltinProc_atomic_cxchgweak_failacq, - BuiltinProc_atomic_cxchgweak_acq_failrelaxed, - BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed, - - BuiltinProc_COUNT, -}; -gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { - {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_builtin}, - - {STR_LIT("len"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("cap"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - - {STR_LIT("size_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("align_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("offset_of"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("type_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("type_info_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("typeid_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - - {STR_LIT("swizzle"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, - - {STR_LIT("complex"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("real"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("imag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - - {STR_LIT("expand_to_tuple"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - - {STR_LIT("min"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("max"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("abs"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("clamp"), 3, false, Expr_Expr, BuiltinProcPkg_builtin}, - - {STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE - - - // "Intrinsics" - {STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type - - - {STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_fence_rel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_fence_acqrel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_store"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_store_rel"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_store_relaxed"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_store_unordered"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_load"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_load_acq"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_load_relaxed"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_load_unordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_add_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_add_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_add_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_add_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_sub_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_sub_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_sub_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_sub_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_and"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_and_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_and_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_and_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_and_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_nand"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_nand_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_nand_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_nand_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_nand_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_or_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_or_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_or_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_or_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xor"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xor_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xor_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xor_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xor_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_xchg"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xchg_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xchg_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xchg_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_xchg_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_cxchg"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchg_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - - {STR_LIT("atomic_cxchgweak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("atomic_cxchgweak_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, -}; +#include "checker_builtin_procs.hpp" // Operand is used as an intermediate value whilst checking diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp new file mode 100644 index 000000000..f6e3aee7e --- /dev/null +++ b/src/checker_builtin_procs.hpp @@ -0,0 +1,312 @@ +// checker_builtin_procs.hpp + +enum BuiltinProcId { + BuiltinProc_Invalid, + + BuiltinProc_len, + BuiltinProc_cap, + + BuiltinProc_size_of, + BuiltinProc_align_of, + BuiltinProc_offset_of, + BuiltinProc_type_of, + BuiltinProc_type_info_of, + BuiltinProc_typeid_of, + + BuiltinProc_swizzle, + + BuiltinProc_complex, + BuiltinProc_real, + BuiltinProc_imag, + BuiltinProc_conj, + + BuiltinProc_expand_to_tuple, + + BuiltinProc_min, + BuiltinProc_max, + BuiltinProc_abs, + BuiltinProc_clamp, + + BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures + + // "Intrinsics" + BuiltinProc_vector, + + BuiltinProc_atomic_fence, + BuiltinProc_atomic_fence_acq, + BuiltinProc_atomic_fence_rel, + BuiltinProc_atomic_fence_acqrel, + + BuiltinProc_atomic_store, + BuiltinProc_atomic_store_rel, + BuiltinProc_atomic_store_relaxed, + BuiltinProc_atomic_store_unordered, + + BuiltinProc_atomic_load, + BuiltinProc_atomic_load_acq, + BuiltinProc_atomic_load_relaxed, + BuiltinProc_atomic_load_unordered, + + BuiltinProc_atomic_add, + BuiltinProc_atomic_add_acq, + BuiltinProc_atomic_add_rel, + BuiltinProc_atomic_add_acqrel, + BuiltinProc_atomic_add_relaxed, + BuiltinProc_atomic_sub, + BuiltinProc_atomic_sub_acq, + BuiltinProc_atomic_sub_rel, + BuiltinProc_atomic_sub_acqrel, + BuiltinProc_atomic_sub_relaxed, + BuiltinProc_atomic_and, + BuiltinProc_atomic_and_acq, + BuiltinProc_atomic_and_rel, + BuiltinProc_atomic_and_acqrel, + BuiltinProc_atomic_and_relaxed, + BuiltinProc_atomic_nand, + BuiltinProc_atomic_nand_acq, + BuiltinProc_atomic_nand_rel, + BuiltinProc_atomic_nand_acqrel, + BuiltinProc_atomic_nand_relaxed, + BuiltinProc_atomic_or, + BuiltinProc_atomic_or_acq, + BuiltinProc_atomic_or_rel, + BuiltinProc_atomic_or_acqrel, + BuiltinProc_atomic_or_relaxed, + BuiltinProc_atomic_xor, + BuiltinProc_atomic_xor_acq, + BuiltinProc_atomic_xor_rel, + BuiltinProc_atomic_xor_acqrel, + BuiltinProc_atomic_xor_relaxed, + + BuiltinProc_atomic_xchg, + BuiltinProc_atomic_xchg_acq, + BuiltinProc_atomic_xchg_rel, + BuiltinProc_atomic_xchg_acqrel, + BuiltinProc_atomic_xchg_relaxed, + + BuiltinProc_atomic_cxchg, + BuiltinProc_atomic_cxchg_acq, + BuiltinProc_atomic_cxchg_rel, + BuiltinProc_atomic_cxchg_acqrel, + BuiltinProc_atomic_cxchg_relaxed, + BuiltinProc_atomic_cxchg_failrelaxed, + BuiltinProc_atomic_cxchg_failacq, + BuiltinProc_atomic_cxchg_acq_failrelaxed, + BuiltinProc_atomic_cxchg_acqrel_failrelaxed, + + BuiltinProc_atomic_cxchgweak, + BuiltinProc_atomic_cxchgweak_acq, + BuiltinProc_atomic_cxchgweak_rel, + BuiltinProc_atomic_cxchgweak_acqrel, + BuiltinProc_atomic_cxchgweak_relaxed, + BuiltinProc_atomic_cxchgweak_failrelaxed, + BuiltinProc_atomic_cxchgweak_failacq, + BuiltinProc_atomic_cxchgweak_acq_failrelaxed, + BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed, + + + // Constant type tests +BuiltinProc__type_begin, + + BuiltinProc_type_base_type, + BuiltinProc_type_core_type, + + BuiltinProc_type_is_boolean, + BuiltinProc_type_is_integer, + BuiltinProc_type_is_rune, + BuiltinProc_type_is_float, + BuiltinProc_type_is_complex, + BuiltinProc_type_is_string, + BuiltinProc_type_is_typeid, + BuiltinProc_type_is_any, + + BuiltinProc_type_is_endian_little, + BuiltinProc_type_is_endian_big, + BuiltinProc_type_is_numeric, + BuiltinProc_type_is_ordered, + BuiltinProc_type_is_ordered_numeric, + BuiltinProc_type_is_indexable, + BuiltinProc_type_is_sliceable, + BuiltinProc_type_is_simple_compare, // easily compared using memcmp + BuiltinProc_type_is_dereferenceable, + + BuiltinProc_type_is_named, + BuiltinProc_type_is_pointer, + BuiltinProc_type_is_opaque, + BuiltinProc_type_is_array, + BuiltinProc_type_is_slice, + BuiltinProc_type_is_dynamic_array, + BuiltinProc_type_is_map, + BuiltinProc_type_is_struct, + BuiltinProc_type_is_union, + BuiltinProc_type_is_enum, + BuiltinProc_type_is_proc, + BuiltinProc_type_is_bit_field, + BuiltinProc_type_is_bit_field_value, + BuiltinProc_type_is_bit_set, + BuiltinProc_type_is_simd_vector, + + BuiltinProc_type_has_nil, + + BuiltinProc_type_elem_type, + + BuiltinProc_type_proc_parameter_count, + BuiltinProc_type_proc_return_count, + +BuiltinProc__type_end, + + BuiltinProc_COUNT, +}; +gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_builtin}, + + {STR_LIT("len"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("cap"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + + {STR_LIT("size_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("align_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("offset_of"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("type_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("type_info_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("typeid_of"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + + {STR_LIT("swizzle"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, + + {STR_LIT("complex"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("real"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("imag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + + {STR_LIT("expand_to_tuple"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + + {STR_LIT("min"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("max"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("abs"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("clamp"), 3, false, Expr_Expr, BuiltinProcPkg_builtin}, + + {STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE + + + // "Intrinsics" + {STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type + + {STR_LIT("atomic_fence"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_fence_acq"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_fence_rel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_fence_acqrel"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + + {STR_LIT("atomic_store"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_store_rel"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_store_relaxed"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_store_unordered"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + + {STR_LIT("atomic_load"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_load_acq"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_load_relaxed"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_load_unordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("atomic_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_add_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_add_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_add_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_add_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_sub_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_sub_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_sub_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_sub_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_and"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_and_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_and_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_and_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_and_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_nand"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_nand_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_nand_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_nand_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_nand_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_or_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_or_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_or_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_or_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xor"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xor_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xor_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xor_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xor_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("atomic_xchg"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xchg_acq"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xchg_rel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xchg_acqrel"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_xchg_relaxed"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("atomic_cxchg"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchg_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("atomic_cxchgweak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_acq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_rel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_acqrel"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_relaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_failacq"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_acq_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("atomic_cxchgweak_acqrel_failrelaxed"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_base_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_core_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_integer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_rune"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_float"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_complex"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_string"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_typeid"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_any"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("type_is_endian_little"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_endian_big"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_numeric"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_ordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_ordered_numeric"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_indexable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_sliceable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_simple_compare"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics,}, + {STR_LIT("type_is_dereferenceable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("type_is_named"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_pointer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_opaque"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_array"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_slice"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_dynamic_array"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_map"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_struct"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_union"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_enum"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_bit_field"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_bit_field_value"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_bit_set"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_simd_vector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("type_has_nil"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("type_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("type_proc_parameter_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_proc_return_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, +}; diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 428690291..7d822512b 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -53,14 +53,8 @@ HashKey hash_exact_value(ExactValue v) { return hash_integer(u64(v.value_bool)); case ExactValue_String: return hash_string(v.value_string); - case ExactValue_Integer: { - u64 *d = big_int_ptr(&v.value_integer); - u64 x = 0; - for (i32 i = 0; i < v.value_integer.len; i++) { - x |= d[i]; - } - return hash_integer(x); - } + case ExactValue_Integer: + return hashing_proc(big_int_ptr(&v.value_integer), v.value_integer.len * gb_size_of(u64)); case ExactValue_Float: return hash_f64(v.value_float); case ExactValue_Pointer: diff --git a/src/types.cpp b/src/types.cpp index 5cf86d6b6..76126f17f 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1307,6 +1307,19 @@ bool is_type_indexable(Type *t) { return false; } +bool is_type_sliceable(Type *t) { + Type *bt = base_type(t); + switch (bt->kind) { + case Type_Basic: + return bt->Basic.kind == Basic_string; + case Type_Array: + case Type_Slice: + case Type_DynamicArray: + return true; + } + return false; +} + bool is_type_polymorphic_record(Type *t) { t = base_type(t); From b04231dd95b6a80789b5e8762a51db4506948da1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2019 14:54:23 +0100 Subject: [PATCH 014/143] Improve implementation of `intrinsics.type_*` procedures --- src/check_expr.cpp | 445 ++++++++-------------------------- src/checker_builtin_procs.hpp | 6 +- src/types.cpp | 20 +- 3 files changed, 120 insertions(+), 351 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6a789bc33..99fe6695b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3131,6 +3131,55 @@ bool check_identifier_exists(Scope *s, Ast *node, bool nested = false, Scope **o return false; } +typedef bool (BuiltinTypeIsProc)(Type *t); + +BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_end - BuiltinProc__type_begin - 1] = { + nullptr, // BuiltinProc_type_base_type + nullptr, // BuiltinProc_type_core_type + nullptr, // BuiltinProc_type_elem_type + + is_type_boolean, + is_type_integer, + is_type_rune, + is_type_float, + is_type_complex, + is_type_string, + is_type_typeid, + is_type_any, + is_type_endian_little, + is_type_endian_big, + is_type_numeric, + is_type_ordered, + is_type_ordered_numeric, + is_type_indexable, + is_type_sliceable, + is_type_simple_compare, + is_type_dereferenceable, + + is_type_named, + is_type_pointer, + is_type_opaque, + is_type_array, + is_type_slice, + is_type_dynamic_array, + + is_type_map, + is_type_struct, + is_type_union, + is_type_enum, + is_type_proc, + is_type_bit_field, + is_type_bit_field_value, + is_type_bit_set, + is_type_simd_vector, + + type_has_nil, + + nullptr, // BuiltinProc_type_proc_parameter_count + nullptr, // BuiltinProc_type_proc_return_count +}; + + bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id) { ast_node(ce, CallExpr, call); @@ -4464,349 +4513,6 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } operand->mode = Addressing_Type; break; - - case BuiltinProc_type_is_boolean: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_boolean(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_integer: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_integer(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_rune: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_rune(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_float: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - } else { - - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_complex: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_complex(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_string: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_string(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_typeid: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_typeid(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_any: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_any(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - - case BuiltinProc_type_is_endian_little: - operand->value = exact_value_bool(false); - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected an integer type for '%.*s'", LIT(builtin_name)); - } else if (!is_type_integer(operand->type)) { - error(operand->expr, "Expected an integer type for '%.*s'", LIT(builtin_name)); - } else { - operand->value = exact_value_bool(is_type_integer_endian_little(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_endian_big: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else if (!is_type_integer(operand->type)) { - error(operand->expr, "Expected an integer type for '%.*s'", LIT(builtin_name)); - } else { - operand->value = exact_value_bool(is_type_integer_endian_big(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_numeric: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_numeric(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_ordered: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_ordered(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_ordered_numeric: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_numeric(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_indexable: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_indexable(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_sliceable: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_sliceable(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_simple_compare: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_simple_compare(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_dereferenceable: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - if (is_type_rawptr(operand->type)) { - operand->value = exact_value_bool(false); - } else if (is_type_pointer(operand->type)) { - operand->value = exact_value_bool(true); - } else { - operand->value = exact_value_bool(false); - } - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - - case BuiltinProc_type_is_named: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_named(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_pointer: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_pointer(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_opaque: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_opaque(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_array: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_array(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_slice: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_slice(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_dynamic_array: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_dynamic_array(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_map: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_map(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_struct: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_struct(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_union: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_union(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_enum: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_enum(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_proc: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_proc(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_bit_field: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_bit_field(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_bit_field_value: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_bit_field_value(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_bit_set: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_bit_set(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_is_simd_vector: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - operand->value = exact_value_bool(false); - } else { - operand->value = exact_value_bool(is_type_simd_vector(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - - case BuiltinProc_type_has_nil: - if (operand->mode != Addressing_Type) { - error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); - } else { - operand->value = exact_value_bool(type_has_nil(operand->type)); - } - operand->mode = Addressing_Constant; - operand->type = t_untyped_bool; - break; - case BuiltinProc_type_elem_type: if (operand->mode != Addressing_Type) { error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); @@ -4829,6 +4535,56 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 operand->mode = Addressing_Type; break; + + case BuiltinProc_type_is_boolean: + case BuiltinProc_type_is_integer: + case BuiltinProc_type_is_rune: + case BuiltinProc_type_is_float: + case BuiltinProc_type_is_complex: + case BuiltinProc_type_is_string: + case BuiltinProc_type_is_typeid: + case BuiltinProc_type_is_any: + case BuiltinProc_type_is_endian_little: + case BuiltinProc_type_is_endian_big: + case BuiltinProc_type_is_numeric: + case BuiltinProc_type_is_ordered: + case BuiltinProc_type_is_ordered_numeric: + case BuiltinProc_type_is_indexable: + case BuiltinProc_type_is_sliceable: + case BuiltinProc_type_is_simple_compare: + case BuiltinProc_type_is_dereferenceable: + case BuiltinProc_type_is_named: + case BuiltinProc_type_is_pointer: + case BuiltinProc_type_is_opaque: + case BuiltinProc_type_is_array: + case BuiltinProc_type_is_slice: + case BuiltinProc_type_is_dynamic_array: + case BuiltinProc_type_is_map: + case BuiltinProc_type_is_struct: + case BuiltinProc_type_is_union: + case BuiltinProc_type_is_enum: + case BuiltinProc_type_is_proc: + case BuiltinProc_type_is_bit_field: + case BuiltinProc_type_is_bit_field_value: + case BuiltinProc_type_is_bit_set: + case BuiltinProc_type_is_simd_vector: + case BuiltinProc_type_has_nil: + GB_ASSERT(BuiltinProc__type_begin < id && id < BuiltinProc__type_end); + operand->value = exact_value_bool(false); + if (operand->mode != Addressing_Type) { + gbString str = expr_to_string(ce->args[0]); + error(operand->expr, "Expected a type for '%.*s', got '%s'", LIT(builtin_name), str); + gb_string_free(str); + } else { + i32 i = id - (BuiltinProc__type_begin+1); + auto procedure = builtin_type_is_procs[i]; + GB_ASSERT_MSG(procedure != nullptr, "%.*s", LIT(builtin_name)); + operand->value = exact_value_bool(procedure(operand->type)); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + case BuiltinProc_type_proc_parameter_count: operand->value = exact_value_i64(0); if (operand->mode != Addressing_Type) { @@ -7527,6 +7283,9 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case Ast_UnionType: case Ast_EnumType: case Ast_MapType: + case Ast_OpaqueType: + case Ast_BitSetType: + case Ast_BitFieldType: o->mode = Addressing_Type; o->type = check_type(c, node); break; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index f6e3aee7e..536d47616 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -110,6 +110,7 @@ BuiltinProc__type_begin, BuiltinProc_type_base_type, BuiltinProc_type_core_type, + BuiltinProc_type_elem_type, BuiltinProc_type_is_boolean, BuiltinProc_type_is_integer, @@ -148,8 +149,6 @@ BuiltinProc__type_begin, BuiltinProc_type_has_nil, - BuiltinProc_type_elem_type, - BuiltinProc_type_proc_parameter_count, BuiltinProc_type_proc_return_count, @@ -266,6 +265,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("type_base_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_core_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_integer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -304,8 +304,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_has_nil"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_proc_parameter_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_proc_return_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, diff --git a/src/types.cpp b/src/types.cpp index 76126f17f..e5d2509e0 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1122,12 +1122,11 @@ bool is_type_integer_endian_big(Type *t) { return is_type_integer_endian_big(bit_set_to_int(t)); } else if (t->kind == Type_Pointer) { return is_type_integer_endian_big(&basic_types[Basic_uintptr]); - } else { - GB_PANIC("Unsupported type: %s", type_to_string(t)); } return build_context.endian_kind == TargetEndian_Big; } + bool is_type_integer_endian_little(Type *t) { t = core_type(t); if (t->kind == Type_Basic) { @@ -1141,11 +1140,24 @@ bool is_type_integer_endian_little(Type *t) { return is_type_integer_endian_little(bit_set_to_int(t)); } else if (t->kind == Type_Pointer) { return is_type_integer_endian_little(&basic_types[Basic_uintptr]); - } else { - GB_PANIC("Unsupported type: %s", type_to_string(t)); } return build_context.endian_kind == TargetEndian_Little; } +bool is_type_endian_big(Type *t) { + return is_type_integer_endian_big(t); +} +bool is_type_endian_little(Type *t) { + return is_type_integer_endian_little(t); +} + +bool is_type_dereferenceable(Type *t) { + if (is_type_rawptr(t)) { + return false; + } + return is_type_pointer(t); +} + + bool is_type_different_to_arch_endianness(Type *t) { switch (build_context.endian_kind) { From 65d41d4248b61e6ef79ed02c2ce4f3be305149a5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 9 Aug 2019 20:31:11 +0100 Subject: [PATCH 015/143] Fix bit_field comparison against nil #414 --- core/runtime/internal.odin | 34 ++++++++++++++++++++++++++++++++++ src/checker.cpp | 1 + src/ir.cpp | 9 +++++++++ 3 files changed, 44 insertions(+) diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 90d653c71..c33d5f62c 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -281,6 +281,40 @@ memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_ch return 0; } +memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_check { + x := uintptr(a); + n := uintptr(n); + + SU :: size_of(uintptr); + fast := uintptr(n/SU + 1); + offset := (fast-1)*SU; + curr_block := uintptr(0); + if n < SU { + fast = 0; + } + + for /**/; curr_block < fast; curr_block += 1 { + va := (^uintptr)(x + curr_block * size_of(uintptr))^; + if va ~ 0 != 0 { + for pos := curr_block*SU; pos < n; pos += 1 { + a := (^byte)(x+pos)^; + if a ~ 0 != 0 { + return int(a) < 0 ? -1 : +1; + } + } + } + } + + for /**/; offset < n; offset += 1 { + a := (^byte)(x+offset)^; + if a ~ 0 != 0 { + return int(a) < 0 ? -1 : +1; + } + } + + return 0; +} + string_eq :: proc "contextless" (a, b: string) -> bool { switch { case len(a) != len(b): return false; diff --git a/src/checker.cpp b/src/checker.cpp index ba13b2237..45b661a58 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1615,6 +1615,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("udivti3"), str_lit("memory_compare"), + str_lit("memory_compare_zero"), }; for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) { add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i])); diff --git a/src/ir.cpp b/src/ir.cpp index 0a5dc7528..ee67c0ea8 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4017,6 +4017,15 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue } else if (is_type_typeid(t)) { irValue *invalid_typeid = ir_value_constant(t_typeid, exact_value_i64(0)); return ir_emit_comp(proc, op_kind, x, invalid_typeid); + } else if (is_type_bit_field(t)) { + auto args = array_make(heap_allocator(), 2); + irValue *lhs = ir_address_from_load_or_generate_local(proc, x); + args[0] = ir_emit_conv(proc, lhs, t_rawptr); + args[1] = ir_const_int(type_size_of(t)); + irValue *val = ir_emit_runtime_call(proc, "memory_compare_zero", args); + irValue *res = ir_emit_comp(proc, op_kind, val, v_zero); + return ir_emit_conv(proc, res, t_bool); + } return nullptr; } From 9c632128245e9a51bb63273d0d4531ba28773629 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 9 Aug 2019 21:59:58 +0100 Subject: [PATCH 016/143] Struct field tags --- core/odin/ast/ast.odin | 20 +++++++++++-------- core/odin/parser/parser.odin | 24 ++++++++++++++++------- core/runtime/core.odin | 5 +++-- examples/demo/demo.odin | 25 ++++++++++++++++++++++++ src/check_type.cpp | 6 ++++-- src/ir.cpp | 37 ++++++++++++++++++++++++++++++++---- src/parser.cpp | 37 ++++++++++++++++++++++++++++-------- src/parser.hpp | 4 +++- src/types.cpp | 1 + 9 files changed, 127 insertions(+), 32 deletions(-) diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index c0d2948ee..3655a601d 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -435,7 +435,9 @@ Field_Flag :: enum { C_Vararg, Auto_Cast, In, + Results, + Tags, Default_Parameters, Typeid_Token, } @@ -443,18 +445,19 @@ Field_Flag :: enum { Field_Flags :: distinct bit_set[Field_Flag]; Field_Flags_Struct :: Field_Flags{ - Field_Flag.Using, + .Using, + .Tags, }; Field_Flags_Record_Poly_Params :: Field_Flags{ - Field_Flag.Typeid_Token, + .Typeid_Token, }; Field_Flags_Signature :: Field_Flags{ - Field_Flag.Ellipsis, - Field_Flag.Using, - Field_Flag.No_Alias, - Field_Flag.C_Vararg, - Field_Flag.Auto_Cast, - Field_Flag.Default_Parameters, + .Ellipsis, + .Using, + .No_Alias, + .C_Vararg, + .Auto_Cast, + .Default_Parameters, }; Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token}; @@ -483,6 +486,7 @@ Field :: struct { names: []^Expr, // Could be polymorphic type: ^Expr, default_value: ^Expr, + tag: token.Token, flags: Field_Flags, comment: ^Comment_Group, } diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 0c011e07e..2d8e42720 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1388,19 +1388,18 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se for flag in ast.Field_Flag { if flag notin allowed_flags && flag in flags { - using ast.Field_Flag; #complete switch flag { - case Using: + case .Using: error(p, p.curr_tok.pos, "'using' is not allowed within this field list"); - case No_Alias: + case .No_Alias: error(p, p.curr_tok.pos, "'#no_alias' is not allowed within this field list"); - case C_Vararg: + case .C_Vararg: error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list"); - case Auto_Cast: + case .Auto_Cast: error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list"); - case In: + case .In: error(p, p.curr_tok.pos, "'in' is not allowed within this field list"); - case Ellipsis, Results, Default_Parameters, Typeid_Token: + case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token: panic("Impossible prefixes"); } flags &~= {flag}; @@ -1540,6 +1539,7 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel type: ^ast.Expr; default_value: ^ast.Expr; + tag: token.Token; expect_token_after(p, token.Colon, "field list"); if p.curr_tok.kind != token.Eq { @@ -1579,9 +1579,19 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel error(p, p.curr_tok.pos, "extra parameter after ellipsis without a default value"); } + if type != nil && default_value == nil { + if p.curr_tok.kind == token.String { + tag = expect_token(p, token.String); + if .Tags notin allowed_flags { + error(p, tag.pos, "Field tags are only allowed within structures"); + } + } + } + ok := expect_field_separator(p, type); field := new_ast_field(names, type, default_value); + field.tag = tag; field.docs = docs; field.flags = flags; field.comment = p.line_comment; diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 02578da3b..28767cc2d 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -79,8 +79,9 @@ Type_Info_Tuple :: struct { // Only really used for procedures Type_Info_Struct :: struct { types: []^Type_Info, names: []string, - offsets: []uintptr, // offsets may not be used in tuples - usings: []bool, // usings may not be used in tuples + offsets: []uintptr, + usings: []bool, + tags: []string, is_packed: bool, is_raw_union: bool, custom_align: bool, diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 206fa4a2d..21f889746 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -3,6 +3,7 @@ package main import "core:fmt" import "core:mem" import "core:os" +import "core:runtime" when os.OS == "windows" { import "core:thread" @@ -945,6 +946,29 @@ deferred_procedure_associations :: proc() { } } +struct_field_tags :: proc() { + fmt.println("# struct_field_tags"); + + Foo :: struct { + x: int `tag1`, + y: string `tag2`, + z: bool, // no tag + } + + f: Foo; + ti := runtime.type_info_base(type_info_of(Foo)); + s := ti.variant.(runtime.Type_Info_Struct); + fmt.println("Foo :: struct {"); + for _, i in s.names { + if tag := s.tags[i]; tag != "" { + fmt.printf("\t%s: %T `%s`,\n", s.names[i], s.types[i], tag); + } else { + fmt.printf("\t%s: %T,\n", s.names[i], s.types[i]); + } + } + fmt.println("}"); +} + main :: proc() { when true { general_stuff(); @@ -963,5 +987,6 @@ main :: proc() { bit_set_type(); diverging_procedures(); deferred_procedure_associations(); + struct_field_tags(); } } diff --git a/src/check_type.cpp b/src/check_type.cpp index 36d8cf0f8..a9c1d3fe3 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -110,9 +110,10 @@ bool does_field_type_allow_using(Type *t) { return false; } -void check_struct_fields(CheckerContext *ctx, Ast *node, Array *fields, Array const ¶ms, +void check_struct_fields(CheckerContext *ctx, Ast *node, Array *fields, Array *tags, Array const ¶ms, isize init_field_capacity, Type *struct_type, String context) { *fields = array_make(heap_allocator(), 0, init_field_capacity); + *tags = array_make(heap_allocator(), 0, init_field_capacity); GB_ASSERT(node->kind == Ast_StructType); GB_ASSERT(struct_type->kind == Type_Struct); @@ -171,6 +172,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Array *fields Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index); add_entity(ctx->checker, ctx->scope, name, field); array_add(fields, field); + array_add(tags, p->tag.string); field_src_index += 1; } @@ -504,7 +506,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< if (!is_polymorphic) { - check_struct_fields(ctx, node, &struct_type->Struct.fields, st->fields, min_field_count, struct_type, context); + check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context); } if (st->align != nullptr) { diff --git a/src/ir.cpp b/src/ir.cpp index ee67c0ea8..2499b848f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -174,6 +174,7 @@ gbAllocator ir_allocator(void) { #define IR_TYPE_INFO_NAMES_NAME "__$type_info_names_data" #define IR_TYPE_INFO_OFFSETS_NAME "__$type_info_offsets_data" #define IR_TYPE_INFO_USINGS_NAME "__$type_info_usings_data" +#define IR_TYPE_INFO_TAGS_NAME "__$type_info_tags_data" #define IR_INSTR_KINDS \ @@ -5271,12 +5272,14 @@ gb_global irValue *ir_global_type_info_member_types = nullptr; gb_global irValue *ir_global_type_info_member_names = nullptr; gb_global irValue *ir_global_type_info_member_offsets = nullptr; gb_global irValue *ir_global_type_info_member_usings = nullptr; +gb_global irValue *ir_global_type_info_member_tags = nullptr; gb_global i32 ir_global_type_info_data_index = 0; gb_global i32 ir_global_type_info_member_types_index = 0; gb_global i32 ir_global_type_info_member_names_index = 0; gb_global i32 ir_global_type_info_member_offsets_index = 0; gb_global i32 ir_global_type_info_member_usings_index = 0; +gb_global i32 ir_global_type_info_member_tags_index = 0; isize ir_type_info_count(CheckerInfo *info) { return info->minimum_dependency_type_info_set.entries.count+1; @@ -9587,6 +9590,16 @@ void ir_init_module(irModule *m, Checker *c) { map_set(&m->members, hash_string(name), g); ir_global_type_info_member_usings = g; } + + { + String name = str_lit(IR_TYPE_INFO_TAGS_NAME); + Entity *e = alloc_entity_variable(nullptr, make_token_ident(name), + alloc_type_array(t_string, count), false); + irValue *g = ir_value_global(e, nullptr); + ir_module_add_value(m, e, g); + map_set(&m->members, hash_string(name), g); + ir_global_type_info_member_tags = g; + } } } } @@ -9720,6 +9733,11 @@ irValue *ir_type_info_member_usings_offset(irProcedure *proc, isize count) { ir_global_type_info_member_usings_index += cast(i32)count; return offset; } +irValue *ir_type_info_member_tags_offset(irProcedure *proc, isize count) { + irValue *offset = ir_emit_array_epi(proc, ir_global_type_info_member_tags, ir_global_type_info_member_tags_index); + ir_global_type_info_member_tags_index += cast(i32)count; + return offset; +} @@ -10065,9 +10083,9 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info irValue *is_packed = ir_const_bool(t->Struct.is_packed); irValue *is_raw_union = ir_const_bool(t->Struct.is_raw_union); irValue *is_custom_align = ir_const_bool(t->Struct.custom_align != 0); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), is_packed); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_raw_union); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_custom_align); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_packed); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_raw_union); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align); } isize count = t->Struct.fields.count; @@ -10076,6 +10094,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info irValue *memory_names = ir_type_info_member_names_offset (proc, count); irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, count); irValue *memory_usings = ir_type_info_member_usings_offset (proc, count); + irValue *memory_tags = ir_type_info_member_tags_offset (proc, count); type_set_offsets(t); // NOTE(bill): Just incase the offsets have not been set yet for (isize source_index = 0; source_index < count; source_index++) { @@ -10091,7 +10110,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info irValue *index = ir_const_int(source_index); irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index); irValue *offset = ir_emit_ptr_offset(proc, memory_offsets, index); - irValue *is_using = ir_emit_ptr_offset(proc, memory_usings, index); + irValue *is_using = ir_emit_ptr_offset(proc, memory_usings, index); ir_emit_store(proc, type_info, ir_type_info(proc, f->type)); if (f->token.string.len > 0) { @@ -10100,6 +10119,15 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info } ir_emit_store(proc, offset, ir_const_uintptr(foffset)); ir_emit_store(proc, is_using, ir_const_bool((f->flags&EntityFlag_Using) != 0)); + + if (t->Struct.tags.count > 0) { + String tag_string = t->Struct.tags[source_index]; + if (tag_string.len > 0) { + irValue *tag_ptr = ir_emit_ptr_offset(proc, memory_tags, index); + ir_emit_store(proc, tag_ptr, ir_const_string(tag_string)); + } + } + } irValue *cv = ir_const_int(count); @@ -10107,6 +10135,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, cv); ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, cv); ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 3), memory_usings, cv); + ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 4), memory_tags, cv); } break; } diff --git a/src/parser.cpp b/src/parser.cpp index d1fd94c1d..9aebc78d6 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -805,13 +805,14 @@ Ast *ast_bad_decl(AstFile *f, Token begin, Token end) { return result; } -Ast *ast_field(AstFile *f, Array names, Ast *type, Ast *default_value, u32 flags, - CommentGroup *docs, CommentGroup *comment) { +Ast *ast_field(AstFile *f, Array names, Ast *type, Ast *default_value, u32 flags, Token tag, + CommentGroup *docs, CommentGroup *comment) { Ast *result = alloc_ast_node(f, Ast_Field); result->Field.names = names; result->Field.type = type; result->Field.default_value = default_value; result->Field.flags = flags; + result->Field.tag = tag; result->Field.docs = docs; result->Field.comment = comment; return result; @@ -2740,7 +2741,8 @@ Ast *parse_results(AstFile *f, bool *diverging) { Array empty_names = {}; auto list = array_make(heap_allocator(), 0, 1); Ast *type = parse_type(f); - array_add(&list, ast_field(f, empty_names, type, nullptr, 0, nullptr, nullptr)); + Token tag = {}; + array_add(&list, ast_field(f, empty_names, type, nullptr, 0, tag, nullptr, nullptr)); return ast_field_list(f, begin_token, list); } @@ -3095,6 +3097,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi Ast *type = nullptr; Ast *default_value = nullptr; + Token tag = {}; expect_token_after(f, Token_Colon, "field list"); if (f->curr_token.kind != Token_Eq) { @@ -3132,16 +3135,25 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value"); } + if (type != nullptr && default_value == nullptr) { + if (f->curr_token.kind == Token_String) { + tag = expect_token(f, Token_String); + if ((allowed_flags & FieldFlag_Tags) == 0) { + syntax_error(tag, "Field tags are only allowed within structures"); + } + } + } + parse_expect_field_separator(f, type); - Ast *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment); + Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment); array_add(¶ms, param); while (f->curr_token.kind != follow && f->curr_token.kind != Token_EOF) { CommentGroup *docs = f->lead_comment; - u32 set_flags = parse_field_prefixes(f); + Token tag = {}; Array names = parse_ident_list(f, allow_poly_names); if (names.count == 0) { syntax_error(f->curr_token, "Empty field declaration"); @@ -3184,9 +3196,18 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value"); } + if (type != nullptr && default_value == nullptr) { + if (f->curr_token.kind == Token_String) { + tag = expect_token(f, Token_String); + if ((allowed_flags & FieldFlag_Tags) == 0) { + syntax_error(tag, "Field tags are only allowed within structures"); + } + } + } + bool ok = parse_expect_field_separator(f, param); - Ast *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment); + Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment); array_add(¶ms, param); if (!ok) { @@ -3210,8 +3231,8 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi token.pos = ast_token(type).pos; names[0] = ast_ident(f, token); u32 flags = check_field_prefixes(f, list.count, allowed_flags, list[i].flags); - - Ast *param = ast_field(f, names, list[i].node, nullptr, flags, docs, f->line_comment); + Token tag = {}; + Ast *param = ast_field(f, names, list[i].node, nullptr, flags, tag, docs, f->line_comment); array_add(¶ms, param); } diff --git a/src/parser.hpp b/src/parser.hpp index 9f4f68a7b..3489f1a9b 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -186,11 +186,12 @@ enum FieldFlag { FieldFlag_c_vararg = 1<<3, FieldFlag_auto_cast = 1<<4, + FieldFlag_Tags = 1<<10, FieldFlag_Results = 1<<16, FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast, - FieldFlag_Struct = FieldFlag_using, + FieldFlag_Struct = FieldFlag_using|FieldFlag_Tags, }; enum StmtAllowFlag { @@ -412,6 +413,7 @@ AST_KIND(_DeclEnd, "", bool) \ Array names; \ Ast * type; \ Ast * default_value; \ + Token tag; \ u32 flags; \ CommentGroup * docs; \ CommentGroup * comment; \ diff --git a/src/types.cpp b/src/types.cpp index e5d2509e0..1197ba974 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -107,6 +107,7 @@ struct BasicType { struct TypeStruct { Array fields; + Array tags; Ast *node; Scope * scope; From 27a3c5449ad8b09e54c70a494170fed8157eb6c3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 9 Aug 2019 22:35:48 +0100 Subject: [PATCH 017/143] Fix global variable initialization for certain types. --- src/ir_print.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 58e7b8b0d..684ae81cd 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2195,6 +2195,22 @@ void ir_print_type_name(irFileBuffer *f, irModule *m, irValue *v) { ir_write_byte(f, '\n'); } +bool ir_print_global_type_allowed(Type *t) { + if (t == nullptr) { + return true; + } + t = core_type(t); + switch (t->kind) { + case Type_DynamicArray: + case Type_Map: + case Type_Union: + case Type_BitField: + return false; + } + + return true; +} + void print_llvm_ir(irGen *ir) { irModule *m = &ir->module; @@ -2358,7 +2374,7 @@ void print_llvm_ir(irGen *ir) { ir_print_type(f, m, g->entity->type); ir_write_byte(f, ' '); if (!g->is_foreign) { - if (g->value != nullptr) { + if (g->value != nullptr && ir_print_global_type_allowed(g->entity->type)) { ir_print_value(f, m, g->value, g->entity->type); } else { ir_write_string(f, str_lit("zeroinitializer")); From 2d26278a658211a9ce6cf6c9d1a8be16ba0e23cb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 9 Aug 2019 22:52:19 +0100 Subject: [PATCH 018/143] Make structs with the same fields but with different tags distinct types --- examples/demo/demo.odin | 1 - src/types.cpp | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 21f889746..e07eea7c7 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -955,7 +955,6 @@ struct_field_tags :: proc() { z: bool, // no tag } - f: Foo; ti := runtime.type_info_base(type_info_of(Foo)); s := ti.variant.(runtime.Type_Info_Struct); fmt.println("Foo :: struct {"); diff --git a/src/types.cpp b/src/types.cpp index 1197ba974..4404882a9 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1712,6 +1712,12 @@ bool are_types_identical(Type *x, Type *y) { if (xf_is_using ^ yf_is_using) { return false; } + if (x->Struct.tags.count != y->Struct.tags.count) { + return false; + } + if (x->Struct.tags.count > 0 && x->Struct.tags[i] != y->Struct.tags[i]) { + return false; + } } return true; } From b08aa857b3c99c241e93ea3d0fbe36f712d96015 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 9 Aug 2019 23:01:22 +0100 Subject: [PATCH 019/143] Remove dead keywords in odin_token --- core/odin/token/token.odin | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/odin/token/token.odin b/core/odin/token/token.odin index 8ce98d1d9..d41fa6d05 100644 --- a/core/odin/token/token.odin +++ b/core/odin/token/token.odin @@ -154,9 +154,6 @@ using Kind :: enum u32 { Offset_Of, Type_Of, Const, - Asm, - Yield, - Await, B_Keyword_End, COUNT, @@ -291,9 +288,6 @@ tokens := [Kind.COUNT]string { "offset_of", "type_of", "const", - "asm", - "yield", - "await", "", }; From 04036aba9c1eec05fe143d939ef93e017502f015 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 11 Aug 2019 23:58:49 +0100 Subject: [PATCH 020/143] `package reflect`; fix substring type bug; fix scoping rules for `using` on procedure parameter --- core/reflect/reflect.odin | 285 ++++++++++++++++++++++++++++++++++++++ core/runtime/core.odin | 11 +- examples/demo/demo.odin | 34 +++-- src/check_decl.cpp | 118 ++++++++++------ src/check_expr.cpp | 2 +- 5 files changed, 392 insertions(+), 58 deletions(-) create mode 100644 core/reflect/reflect.odin diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin new file mode 100644 index 000000000..ecc2e7362 --- /dev/null +++ b/core/reflect/reflect.odin @@ -0,0 +1,285 @@ +package reflect + +import "core:runtime" +import "core:mem" + + +Type_Kind :: enum { + Invalid, + + Named, + Integer, + Rune, + Float, + Complex, + String, + Boolean, + Any, + Type_Id, + Pointer, + Procedure, + Array, + Dynamic_Array, + Slice, + Tuple, + Struct, + Union, + Enum, + Map, + Bit_Field, + Bit_Set, + Opaque, + Simd_Vector, +} + + +type_kind :: proc(T: typeid) -> Type_Kind { + ti := type_info_of(T); + if ti != nil { + #complete switch _ in ti.variant { + case runtime.Type_Info_Named: return .Named; + case runtime.Type_Info_Integer: return .Integer; + case runtime.Type_Info_Rune: return .Rune; + case runtime.Type_Info_Float: return .Float; + case runtime.Type_Info_Complex: return .Complex; + case runtime.Type_Info_String: return .String; + case runtime.Type_Info_Boolean: return .Boolean; + case runtime.Type_Info_Any: return .Any; + case runtime.Type_Info_Type_Id: return .Type_Id; + case runtime.Type_Info_Pointer: return .Pointer; + case runtime.Type_Info_Procedure: return .Procedure; + case runtime.Type_Info_Array: return .Array; + case runtime.Type_Info_Dynamic_Array: return .Dynamic_Array; + case runtime.Type_Info_Slice: return .Slice; + case runtime.Type_Info_Tuple: return .Tuple; + case runtime.Type_Info_Struct: return .Struct; + case runtime.Type_Info_Union: return .Union; + case runtime.Type_Info_Enum: return .Enum; + case runtime.Type_Info_Map: return .Map; + case runtime.Type_Info_Bit_Field: return .Bit_Field; + case runtime.Type_Info_Bit_Set: return .Bit_Set; + case runtime.Type_Info_Opaque: return .Opaque; + case runtime.Type_Info_Simd_Vector: return .Simd_Vector; + } + + } + return .Invalid; +} + +// TODO(bill): Better name +underlying_type_kind :: proc(T: typeid) -> Type_Kind { + return type_kind(runtime.typeid_base(T)); +} + +// TODO(bill): Better name +backing_type_kind :: proc(T: typeid) -> Type_Kind { + return type_kind(runtime.typeid_core(T)); +} + + + +size_of_typeid :: proc(T: typeid) -> int { + if ti := type_info_of(T); ti != nil { + return ti.size; + } + return 0; +} + +align_of_typeid :: proc(T: typeid) -> int { + if ti := type_info_of(T); ti != nil { + return ti.align; + } + return 1; +} + +to_bytes :: proc(v: any) -> []byte { + if v != nil { + sz := size_of_typeid(v.id); + return mem.slice_ptr((^byte)(v.data), sz); + } + return nil; +} + +any_data :: inline proc(v: any) -> (data: rawptr, id: typeid) { + return v.data, v.id; +} + +is_nil :: proc(v: any) -> bool { + data := to_bytes(v); + if data != nil { + return true; + } + for v in data do if v != 0 { + return false; + } + return true; +} + + +index :: proc(v: any, i: int, loc := #caller_location) -> any { + if v == nil do return nil; + + v := v; + v.id = runtime.typeid_base(v.id); + switch a in v { + case runtime.Type_Info_Array: + runtime.bounds_check_error_loc(loc, i, a.count); + offset := uintptr(a.elem.size * i); + data := rawptr(uintptr(v.data) + offset); + return any{data, a.elem.id}; + + case runtime.Type_Info_Slice: + raw := (^mem.Raw_Slice)(v.data); + runtime.bounds_check_error_loc(loc, i, raw.len); + offset := uintptr(a.elem.size * i); + data := rawptr(uintptr(raw.data) + offset); + return any{data, a.elem.id}; + + case runtime.Type_Info_Dynamic_Array: + raw := (^mem.Raw_Dynamic_Array)(v.data); + runtime.bounds_check_error_loc(loc, i, raw.len); + offset := uintptr(a.elem.size * i); + data := rawptr(uintptr(raw.data) + offset); + return any{data, a.elem.id}; + + case runtime.Type_Info_String: + if a.is_cstring do return nil; + + raw := (^mem.Raw_String)(v.data); + runtime.bounds_check_error_loc(loc, i, raw.len); + offset := uintptr(size_of(u8) * i); + data := rawptr(uintptr(raw.data) + offset); + return any{data, typeid_of(u8)}; + } + return nil; +} + + + + +Struct_Tag :: distinct string; + +Struct_Field :: struct { + name: string, + type: typeid, + tag: Struct_Tag, + offset: uintptr, +} + +struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) { + ti := runtime.type_info_base(type_info_of(T)); + if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { + if 0 <= i && i < len(s.names) { + field.name = s.names[i]; + field.type = s.types[i].id; + field.tag = Struct_Tag(s.tags[i]); + field.offset = s.offsets[i]; + } + } + return; +} + +struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) { + ti := runtime.type_info_base(type_info_of(T)); + if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { + for fname, i in s.names { + if fname == name { + field.name = s.names[i]; + field.type = s.types[i].id; + field.tag = Struct_Tag(s.tags[i]); + field.offset = s.offsets[i]; + break; + } + } + } + return; +} + + + +struct_field_names :: proc(T: typeid) -> []string { + ti := runtime.type_info_base(type_info_of(T)); + if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { + return s.names; + } + return nil; +} + +struct_field_types :: proc(T: typeid) -> []^runtime.Type_Info { + ti := runtime.type_info_base(type_info_of(T)); + if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { + return s.types; + } + return nil; +} + + +struct_field_tags :: proc(T: typeid) -> []Struct_Tag { + ti := runtime.type_info_base(type_info_of(T)); + if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { + return transmute([]Struct_Tag)s.tags; + } + return nil; +} + +struct_field_offsets :: proc(T: typeid) -> []uintptr { + ti := runtime.type_info_base(type_info_of(T)); + if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { + return s.offsets; + } + return nil; +} + + + +struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: string) { + value, _ = struct_tag_lookup(tag, key); + return; +} + +struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: string, ok: bool) { + for tag := tag; tag != ""; /**/ { + i := 0; + for i < len(tag) && tag[i] == ' ' { // Skip whitespace + i += 1; + } + tag = tag[i:]; + if len(tag) == 0 do break; + + i = 0; + loop: for i < len(tag) { + switch tag[i] { + case ':', '"': + break loop; + case 0x00 ..< ' ', 0x7f .. 0x9f: // break if control character is found + break loop; + } + i += 1; + } + + if i == 0 do break; + if i+1 >= len(tag) do break; + + if tag[i] != ':' || tag[i+1] != '"' { + break; + } + name := string(tag[:i]); + tag = tag[i+1:]; + + i = 1; + for i < len(tag) && tag[i] != '"' { // find closing quote + if tag[i] == '\\' do i += 1; // Skip escaped characters + i += 1; + } + + if i >= len(tag) do break; + + val := string(tag[:i+1]); + tag = tag[i+1:]; + + if key == name { + return val[1:i], true; + } + } + return; +} diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 28767cc2d..047281b10 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -283,19 +283,21 @@ type_info_base :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { } -type_info_base_without_enum :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { +type_info_core :: proc "contextless" (info: ^Type_Info) -> ^Type_Info { if info == nil do return nil; base := info; loop: for { switch i in base.variant { - case Type_Info_Named: base = i.base; - case Type_Info_Enum: base = i.base; + case Type_Info_Named: base = i.base; + case Type_Info_Enum: base = i.base; + case Type_Info_Opaque: base = i.elem; case: break loop; } } return base; } +type_info_base_without_enum :: type_info_core; __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info { data := transmute(Typeid_Bit_Field)id; @@ -311,10 +313,11 @@ typeid_base :: proc "contextless" (id: typeid) -> typeid { ti = type_info_base(ti); return ti.id; } -typeid_base_without_enum :: proc "contextless" (id: typeid) -> typeid { +typeid_core :: proc "contextless" (id: typeid) -> typeid { ti := type_info_base_without_enum(type_info_of(id)); return ti.id; } +typeid_base_without_enum :: typeid_core; diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index e07eea7c7..157ecb9bf 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -4,6 +4,7 @@ import "core:fmt" import "core:mem" import "core:os" import "core:runtime" +import "core:reflect" when os.OS == "windows" { import "core:thread" @@ -946,26 +947,39 @@ deferred_procedure_associations :: proc() { } } -struct_field_tags :: proc() { - fmt.println("# struct_field_tags"); +reflection :: proc() { + fmt.println("# reflection"); Foo :: struct { x: int `tag1`, - y: string `tag2`, + y: string `json:"y_field"`, z: bool, // no tag } - ti := runtime.type_info_base(type_info_of(Foo)); - s := ti.variant.(runtime.Type_Info_Struct); + id := typeid_of(Foo); + names := reflect.struct_field_names(id); + types := reflect.struct_field_types(id); + tags := reflect.struct_field_tags(id); + + assert(len(names) == len(types) && len(names) == len(tags)); + fmt.println("Foo :: struct {"); - for _, i in s.names { - if tag := s.tags[i]; tag != "" { - fmt.printf("\t%s: %T `%s`,\n", s.names[i], s.types[i], tag); + for tag, i in tags { + name, type := names[i], types[i]; + if tag != "" { + fmt.printf("\t%s: %T `%s`,\n", name, type, tag); } else { - fmt.printf("\t%s: %T,\n", s.names[i], s.types[i]); + fmt.printf("\t%s: %T,\n", name, type); } } fmt.println("}"); + + + for tag, i in tags { + if val, ok := reflect.struct_tag_lookup(tag, "json"); ok { + fmt.printf("json: %s -> %s\n", names[i], val); + } + } } main :: proc() { @@ -986,6 +1000,6 @@ main :: proc() { bit_set_type(); diverging_procedures(); deferred_procedure_associations(); - struct_field_tags(); + reflection(); } } diff --git a/src/check_decl.cpp b/src/check_decl.cpp index f3e0f70bc..cf3cb8e97 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1074,6 +1074,11 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_ } +struct ProcUsingVar { + Entity *e; + Entity *uvar; +}; + void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) { if (body == nullptr) { @@ -1098,58 +1103,85 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty ctx->curr_proc_decl = decl; ctx->curr_proc_sig = type; - GB_ASSERT(type->kind == Type_Proc); - if (type->Proc.param_count > 0) { - TypeTuple *params = &type->Proc.params->Tuple; - for_array(i, params->variables) { - Entity *e = params->variables[i]; - if (e->kind != Entity_Variable) { - continue; - } - if (!(e->flags & EntityFlag_Using)) { - continue; - } - bool is_immutable = e->Variable.is_immutable; - bool is_value = (e->flags & EntityFlag_Value) != 0 && !is_type_pointer(e->type); - String name = e->token.string; - Type *t = base_type(type_deref(e->type)); - if (t->kind == Type_Struct) { - Scope *scope = t->Struct.scope; - if (scope == nullptr) { - scope = scope_of_node(t->Struct.node); - } - GB_ASSERT(scope != nullptr); - for_array(i, scope->elements.entries) { - Entity *f = scope->elements.entries[i].value; - if (f->kind == Entity_Variable) { - Entity *uvar = alloc_entity_using_variable(e, f->token, f->type); - uvar->Variable.is_immutable = is_immutable; - if (is_value) uvar->flags |= EntityFlag_Value; + ast_node(bs, BlockStmt, body); + + Array using_entities = {}; + using_entities.allocator = heap_allocator(); + defer (array_free(&using_entities)); + + { + GB_ASSERT(type->kind == Type_Proc); + if (type->Proc.param_count > 0) { + TypeTuple *params = &type->Proc.params->Tuple; + for_array(i, params->variables) { + Entity *e = params->variables[i]; + if (e->kind != Entity_Variable) { + continue; + } + if (!(e->flags & EntityFlag_Using)) { + continue; + } + bool is_immutable = e->Variable.is_immutable; + bool is_value = (e->flags & EntityFlag_Value) != 0 && !is_type_pointer(e->type); + String name = e->token.string; + Type *t = base_type(type_deref(e->type)); + if (t->kind == Type_Struct) { + Scope *scope = t->Struct.scope; + if (scope == nullptr) { + scope = scope_of_node(t->Struct.node); + } + GB_ASSERT(scope != nullptr); + for_array(i, scope->elements.entries) { + Entity *f = scope->elements.entries[i].value; + if (f->kind == Entity_Variable) { + Entity *uvar = alloc_entity_using_variable(e, f->token, f->type); + uvar->Variable.is_immutable = is_immutable; + if (is_value) uvar->flags |= EntityFlag_Value; + + + ProcUsingVar puv = {e, uvar}; + array_add(&using_entities, puv); - Entity *prev = scope_insert(ctx->scope, uvar); - if (prev != nullptr) { - error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string)); - break; } } + } else { + error(e->token, "'using' can only be applied to variables of type struct"); + break; } - } else { - error(e->token, "'using' can only be applied to variables of type struct"); - break; } } } - ast_node(bs, BlockStmt, body); + + for_array(i, using_entities) { + Entity *e = using_entities[i].e; + Entity *uvar = using_entities[i].uvar; + Entity *prev = scope_insert(ctx->scope, uvar); + if (prev != nullptr) { + error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string)); + break; + } + } + check_open_scope(ctx, body); - check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls); - if (type->Proc.result_count > 0) { - if (!check_is_terminating(body)) { - if (token.kind == Token_Ident) { - error(bs->close, "Missing return statement at the end of the procedure '%.*s'", LIT(token.string)); - } else { - // NOTE(bill): Anonymous procedure (lambda) - error(bs->close, "Missing return statement at the end of the procedure"); + { + for_array(i, using_entities) { + Entity *e = using_entities[i].e; + Entity *uvar = using_entities[i].uvar; + Entity *prev = scope_insert(ctx->scope, uvar); + // NOTE(bill): Don't err here + } + + check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls); + + if (type->Proc.result_count > 0) { + if (!check_is_terminating(body)) { + if (token.kind == Token_Ident) { + error(bs->close, "Missing return statement at the end of the procedure '%.*s'", LIT(token.string)); + } else { + // NOTE(bill): Anonymous procedure (lambda) + error(bs->close, "Missing return statement at the end of the procedure"); + } } } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 99fe6695b..7a6e0f22d 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7164,7 +7164,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (o->mode == Addressing_Constant) { max_count = o->value.value_string.len; } - o->type = t_string; + o->type = type_deref(o->type); } break; From 4c065a7e99a97ee8c4f527503b0daad4dd5f2454 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 13 Aug 2019 22:27:52 +0100 Subject: [PATCH 021/143] Keep -vet happy --- core/reflect/reflect.odin | 36 ++++++++++++++++++------------------ examples/demo/demo.odin | 1 - 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index ecc2e7362..c49c62daf 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -116,10 +116,10 @@ is_nil :: proc(v: any) -> bool { } -index :: proc(v: any, i: int, loc := #caller_location) -> any { - if v == nil do return nil; +index :: proc(val: any, i: int, loc := #caller_location) -> any { + if val == nil do return nil; - v := v; + v := val; v.id = runtime.typeid_base(v.id); switch a in v { case runtime.Type_Info_Array: @@ -238,17 +238,17 @@ struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: string) { } struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: string, ok: bool) { - for tag := tag; tag != ""; /**/ { + for t := tag; t != ""; /**/ { i := 0; - for i < len(tag) && tag[i] == ' ' { // Skip whitespace + for i < len(t) && t[i] == ' ' { // Skip whitespace i += 1; } - tag = tag[i:]; - if len(tag) == 0 do break; + t = t[i:]; + if len(t) == 0 do break; i = 0; - loop: for i < len(tag) { - switch tag[i] { + loop: for i < len(t) { + switch t[i] { case ':', '"': break loop; case 0x00 ..< ' ', 0x7f .. 0x9f: // break if control character is found @@ -258,24 +258,24 @@ struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: string, ok: b } if i == 0 do break; - if i+1 >= len(tag) do break; + if i+1 >= len(t) do break; - if tag[i] != ':' || tag[i+1] != '"' { + if t[i] != ':' || t[i+1] != '"' { break; } - name := string(tag[:i]); - tag = tag[i+1:]; + name := string(t[:i]); + t = t[i+1:]; i = 1; - for i < len(tag) && tag[i] != '"' { // find closing quote - if tag[i] == '\\' do i += 1; // Skip escaped characters + for i < len(t) && t[i] != '"' { // find closing quote + if t[i] == '\\' do i += 1; // Skip escaped characters i += 1; } - if i >= len(tag) do break; + if i >= len(t) do break; - val := string(tag[:i+1]); - tag = tag[i+1:]; + val := string(t[:i+1]); + t = t[i+1:]; if key == name { return val[1:i], true; diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 157ecb9bf..343c50ff7 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -3,7 +3,6 @@ package main import "core:fmt" import "core:mem" import "core:os" -import "core:runtime" import "core:reflect" when os.OS == "windows" { From 0076a4df62c5f4e2fc827d6401ae4c8a93181fb9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 13 Aug 2019 22:33:05 +0100 Subject: [PATCH 022/143] Fix compound literal printing for structs with custom alignment requirements --- src/ir_print.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 684ae81cd..c1e41c4b0 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -943,7 +943,8 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * if (type->Struct.is_packed) ir_write_byte(f, '<'); ir_write_byte(f, '{'); if (type->Struct.custom_align > 0) { - ir_fprintf(f, "[0 x <%lld x i8>] zeroinitializer", cast(i64)type->Struct.custom_align); + ir_print_alignment_prefix_hack(f, cast(i64)type->Struct.custom_align); + ir_write_str_lit(f, " zeroinitializer"); if (value_count > 0) { ir_write_string(f, str_lit(", ")); } From 0a63690b399da06e7de887854b38d5e95c712431 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 13 Aug 2019 22:34:02 +0100 Subject: [PATCH 023/143] Fix typo in ? array lengths error --- src/check_type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index a9c1d3fe3..2fa8939c4 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2548,7 +2548,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t generic_type = o.type; } if (count < 0) { - error(at->count, "... can only be used in conjuction with compound literals"); + error(at->count, "? can only be used in conjuction with compound literals"); count = 0; } Type *elem = check_type_expr(ctx, at->elem, nullptr); From 980890ee8a5fdfd1dc0ae6412fcf004eb250bb08 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 13 Aug 2019 22:39:53 +0100 Subject: [PATCH 024/143] Make -vet happy on *nix --- core/os/os_linux.odin | 6 +++--- core/os/os_osx.odin | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 1587e2ad1..13eab5def 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -392,9 +392,9 @@ dlerror :: proc() -> string { _alloc_command_line_arguments :: proc() -> []string { - args := make([]string, len(runtime.args__)); + res := make([]string, len(runtime.args__)); for arg, i in runtime.args__ { - args[i] = string(arg); + res[i] = string(arg); } - return args; + return res; } diff --git a/core/os/os_osx.odin b/core/os/os_osx.odin index 302cba76a..3185fecc6 100644 --- a/core/os/os_osx.odin +++ b/core/os/os_osx.odin @@ -287,9 +287,9 @@ dlerror :: proc() -> string { _alloc_command_line_arguments :: proc() -> []string { - args := make([]string, len(runtime.args__)); + res := make([]string, len(runtime.args__)); for arg, i in runtime.args__ { - args[i] = string(arg); + res[i] = string(arg); } - return args; + return res; } From b86dfa7af79a1563b2f47622aeeaedb737eaafb8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 13 Aug 2019 22:51:04 +0100 Subject: [PATCH 025/143] Fix compiler crash with #defined #417 --- src/check_expr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7a6e0f22d..8da6816ac 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3368,8 +3368,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 return false; } Ast *arg = unparen_expr(ce->args[0]); - if (arg->kind != Ast_Ident && arg->kind != Ast_SelectorExpr) { - error(call, "'#defined' expects an identifier or selector expression, got %s", LIT(ast_strings[arg->kind])); + if (arg == nullptr || (arg->kind != Ast_Ident && arg->kind != Ast_SelectorExpr)) { + error(call, "'#defined' expects an identifier or selector expression, got %.*s", LIT(ast_strings[arg->kind])); return false; } From 3ad20a2d2d4769f9f60c34f836a0327d59768b23 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 13 Aug 2019 22:59:07 +0100 Subject: [PATCH 026/143] Remove `package types` and merge with `package reflect` --- core/encoding/json/marshal.odin | 4 +- core/fmt/fmt.odin | 241 ++-------------------------- core/reflect/reflect.odin | 212 ++++++++++++++++++++++++ core/types/types.odin | 274 -------------------------------- 4 files changed, 230 insertions(+), 501 deletions(-) delete mode 100644 core/types/types.odin diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index cd9aae169..52d75524a 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -5,7 +5,7 @@ import "core:math/bits" import "core:runtime" import "core:strconv" import "core:strings" -import "core:types" +import "core:reflect" Marshal_Error :: enum { None, @@ -194,7 +194,7 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error { data := uintptr(entries.data) + uintptr(i*entry_size); header := cast(^Map_Entry_Header)data; - if types.is_string(info.key) { + if reflect.is_string(info.key) { marshal_arg(b, header.key.str); } else { marshal_arg(b, any{rawptr(&header.key.hash), info.key.id}); diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 60b1fdcc1..5dbebf972 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -5,9 +5,9 @@ import "core:os" import "core:mem" import "core:math/bits" import "core:unicode/utf8" -import "core:types" import "core:strconv" import "core:strings" +import "core:reflect" @private @@ -143,7 +143,7 @@ panicf :: proc "contextless" (fmt: string, args: ..any, loc := #caller_location) fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) { data: [DEFAULT_BUFFER_SIZE]byte; buf := strings.builder_from_slice(data[:]); - write_type(&buf, info); + reflect.write_type(&buf, info); os.write_string(fd, strings.to_string(buf)); } @@ -156,7 +156,7 @@ sbprint :: proc(buf: ^strings.Builder, args: ..any) -> string { fi.buf = buf; for arg, i in args { - is_string := arg != nil && types.is_string(type_info_of(arg.id)); + is_string := arg != nil && reflect.is_string(type_info_of(arg.id)); if i > 0 && !is_string && !prev_string { strings.write_byte(buf, ' '); } @@ -399,7 +399,7 @@ fmt_bad_verb :: proc(using fi: ^Info, verb: rune) { strings.write_rune(buf, verb); strings.write_byte(buf, '('); if arg.id != nil { - write_typeid(buf, arg.id); + reflect.write_typeid(buf, arg.id); strings.write_byte(buf, '='); fmt_value(fi, arg, 'v'); } else { @@ -792,7 +792,7 @@ enum_value_to_string :: proc(val: any) -> (string, bool) { case: return "", false; case runtime.Type_Info_Enum: get_str :: proc(i: $T, e: runtime.Type_Info_Enum) -> (string, bool) { - if types.is_string(e.base) { + if reflect.is_string(e.base) { for val, idx in e.values { if v, ok := val.(T); ok && v == i { return e.names[idx], true; @@ -947,7 +947,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") { if name != "" { strings.write_string(fi.buf, name); } else { - write_type(fi.buf, type_info); + reflect.write_type(fi.buf, type_info); } strings.write_byte(fi.buf, '{'); defer strings.write_byte(fi.buf, '}'); @@ -1042,7 +1042,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) { if ot, ok := rt.type_info_base(type_info).variant.(rt.Type_Info_Opaque); ok { elem := rt.type_info_base(ot.elem); if elem == nil do return; - write_type(fi.buf, type_info); + reflect.write_type(fi.buf, type_info); strings.write_byte(fi.buf, '{'); defer strings.write_byte(fi.buf, '}'); @@ -1053,7 +1053,7 @@ fmt_opaque :: proc(fi: ^Info, v: any) { // Okay } } else { - write_type(fi.buf, type_info); + reflect.write_type(fi.buf, type_info); strings.write_byte(fi.buf, '{'); strings.write_byte(fi.buf, '}'); } @@ -1101,7 +1101,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { strings.write_string(fi.buf, name); strings.write_string(fi.buf, " = "); - if t := b.types[i]; types.is_any(t) { + if t := b.types[i]; reflect.is_any(t) { strings.write_string(fi.buf, "any{}"); } else { data := rawptr(uintptr(v.data) + b.offsets[i]); @@ -1133,7 +1133,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Pointer: if v.id == typeid_of(^runtime.Type_Info) { - write_type(fi.buf, (^^runtime.Type_Info)(v.data)^); + reflect.write_type(fi.buf, (^^runtime.Type_Info)(v.data)^); } else { ptr := (^rawptr)(v.data)^; if verb != 'p' && info.elem != nil { @@ -1256,7 +1256,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { data := uintptr(entries.data) + uintptr(i*entry_size); header := cast(^runtime.Map_Entry_Header)data; - if types.is_string(info.key) { + if reflect.is_string(info.key) { strings.write_string(fi.buf, header.key.str); } else { fi := Info{buf = fi.buf}; @@ -1297,7 +1297,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { strings.write_string(fi.buf, info.names[i]); strings.write_string(fi.buf, " = "); - if t := info.types[i]; types.is_any(t) { + if t := info.types[i]; reflect.is_any(t) { strings.write_string(fi.buf, "any{}"); } else { data := uintptr(v.data) + info.offsets[i]; @@ -1349,14 +1349,14 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { if ptr == nil { strings.write_string(fi.buf, "nil"); } else { - write_typeid(fi.buf, v.id); + reflect.write_typeid(fi.buf, v.id); strings.write_string(fi.buf, " @ "); fmt_pointer(fi, ptr, 'p'); } case runtime.Type_Info_Type_Id: id := (^typeid)(v.data)^; - write_typeid(fi.buf, id); + reflect.write_typeid(fi.buf, id); case runtime.Type_Info_Bit_Field: fmt_bit_field(fi, v); @@ -1398,7 +1398,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { switch a in arg { case ^runtime.Type_Info: ti = a; } - write_type(fi.buf, ti); + reflect.write_type(fi.buf, ti); return; } @@ -1449,7 +1449,7 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { case string: fmt_string(fi, a, verb); case cstring: fmt_cstring(fi, a, verb); - case typeid: write_typeid(fi.buf, a); + case typeid: reflect.write_typeid(fi.buf, a); case i16le: fmt_int(fi, u64(a), true, 16, verb); case u16le: fmt_int(fi, u64(a), false, 16, verb); @@ -1482,212 +1482,3 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { - -write_typeid :: proc(buf: ^strings.Builder, id: typeid) { - write_type(buf, type_info_of(id)); -} - -write_type :: proc(buf: ^strings.Builder, ti: ^runtime.Type_Info) { - using strings; - if ti == nil { - write_string(buf, "nil"); - return; - } - - switch info in ti.variant { - case runtime.Type_Info_Named: - write_string(buf, info.name); - case runtime.Type_Info_Integer: - switch ti.id { - case int: write_string(buf, "int"); - case uint: write_string(buf, "uint"); - case uintptr: write_string(buf, "uintptr"); - case: - write_byte(buf, info.signed ? 'i' : 'u'); - write_i64(buf, i64(8*ti.size), 10); - switch info.endianness { - case runtime.Type_Info_Endianness.Little: - write_string(buf, "le"); - case runtime.Type_Info_Endianness.Big: - write_string(buf, "be"); - } - } - case runtime.Type_Info_Rune: - write_string(buf, "rune"); - case runtime.Type_Info_Float: - write_byte(buf, 'f'); - write_i64(buf, i64(8*ti.size), 10); - case runtime.Type_Info_Complex: - write_string(buf, "complex"); - write_i64(buf, i64(8*ti.size), 10); - case runtime.Type_Info_String: - if info.is_cstring { - write_string(buf, "cstring"); - } else { - write_string(buf, "string"); - } - case runtime.Type_Info_Boolean: - switch ti.id { - case bool: write_string(buf, "bool"); - case: - write_byte(buf, 'b'); - write_i64(buf, i64(8*ti.size), 10); - } - case runtime.Type_Info_Any: - write_string(buf, "any"); - - case runtime.Type_Info_Type_Id: - write_string(buf, "typeid"); - - case runtime.Type_Info_Pointer: - if info.elem == nil { - write_string(buf, "rawptr"); - } else { - write_string(buf, "^"); - write_type(buf, info.elem); - } - case runtime.Type_Info_Procedure: - write_string(buf, "proc"); - if info.params == nil { - write_string(buf, "()"); - } else { - t := info.params.variant.(runtime.Type_Info_Tuple); - write_string(buf, "("); - for t, i in t.types { - if i > 0 do write_string(buf, ", "); - write_type(buf, t); - } - write_string(buf, ")"); - } - if info.results != nil { - write_string(buf, " -> "); - write_type(buf, info.results); - } - case runtime.Type_Info_Tuple: - count := len(info.names); - if count != 1 do write_string(buf, "("); - for name, i in info.names { - if i > 0 do write_string(buf, ", "); - - t := info.types[i]; - - if len(name) > 0 { - write_string(buf, name); - write_string(buf, ": "); - } - write_type(buf, t); - } - if count != 1 do write_string(buf, ")"); - - case runtime.Type_Info_Array: - write_string(buf, "["); - write_i64(buf, i64(info.count), 10); - write_string(buf, "]"); - write_type(buf, info.elem); - case runtime.Type_Info_Dynamic_Array: - write_string(buf, "[dynamic]"); - write_type(buf, info.elem); - case runtime.Type_Info_Slice: - write_string(buf, "[]"); - write_type(buf, info.elem); - - case runtime.Type_Info_Map: - write_string(buf, "map["); - write_type(buf, info.key); - write_byte(buf, ']'); - write_type(buf, info.value); - - case runtime.Type_Info_Struct: - write_string(buf, "struct "); - if info.is_packed do write_string(buf, "#packed "); - if info.is_raw_union do write_string(buf, "#raw_union "); - if info.custom_align { - write_string(buf, "#align "); - write_i64(buf, i64(ti.align), 10); - write_byte(buf, ' '); - } - write_byte(buf, '{'); - for name, i in info.names { - if i > 0 do write_string(buf, ", "); - write_string(buf, name); - write_string(buf, ": "); - write_type(buf, info.types[i]); - } - write_byte(buf, '}'); - - case runtime.Type_Info_Union: - write_string(buf, "union "); - if info.custom_align { - write_string(buf, "#align "); - write_i64(buf, i64(ti.align), 10); - write_byte(buf, ' '); - } - write_byte(buf, '{'); - for variant, i in info.variants { - if i > 0 do write_string(buf, ", "); - write_type(buf, variant); - } - write_byte(buf, '}'); - - case runtime.Type_Info_Enum: - write_string(buf, "enum "); - write_type(buf, info.base); - write_string(buf, " {"); - for name, i in info.names { - if i > 0 do write_string(buf, ", "); - write_string(buf, name); - } - write_byte(buf, '}'); - - case runtime.Type_Info_Bit_Field: - write_string(buf, "bit_field "); - if ti.align != 1 { - write_string(buf, "#align "); - write_i64(buf, i64(ti.align), 10); - write_byte(buf, ' '); - } - write_string(buf, " {"); - for name, i in info.names { - if i > 0 do write_string(buf, ", "); - write_string(buf, name); - write_string(buf, ": "); - write_i64(buf, i64(info.bits[i]), 10); - } - write_byte(buf, '}'); - - case runtime.Type_Info_Bit_Set: - write_string(buf, "bit_set["); - switch { - case types.is_enum(info.elem): - write_type(buf, info.elem); - case types.is_rune(info.elem): - write_encoded_rune(buf, rune(info.lower)); - write_string(buf, ".."); - write_encoded_rune(buf, rune(info.upper)); - case: - write_i64(buf, info.lower, 10); - write_string(buf, ".."); - write_i64(buf, info.upper, 10); - } - if info.underlying != nil { - write_string(buf, "; "); - write_type(buf, info.underlying); - } - write_byte(buf, ']'); - - case runtime.Type_Info_Opaque: - write_string(buf, "opaque "); - write_type(buf, info.elem); - - case runtime.Type_Info_Simd_Vector: - if info.is_x86_mmx { - write_string(buf, "intrinsics.x86_mmx"); - } else { - write_string(buf, "intrinsics.vector("); - write_i64(buf, i64(info.count)); - write_string(buf, ", "); - write_type(buf, info.elem); - write_byte(buf, ')'); - } - } -} diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index c49c62daf..2e917710b 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -2,6 +2,7 @@ package reflect import "core:runtime" import "core:mem" +import "core:strings" Type_Kind :: enum { @@ -283,3 +284,214 @@ struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: string, ok: b } return; } + + +write_typeid :: proc(buf: ^strings.Builder, id: typeid) { + write_type(buf, type_info_of(id)); +} + +write_type :: proc(buf: ^strings.Builder, ti: ^runtime.Type_Info) { + using strings; + if ti == nil { + write_string(buf, "nil"); + return; + } + + switch info in ti.variant { + case runtime.Type_Info_Named: + write_string(buf, info.name); + case runtime.Type_Info_Integer: + switch ti.id { + case int: write_string(buf, "int"); + case uint: write_string(buf, "uint"); + case uintptr: write_string(buf, "uintptr"); + case: + write_byte(buf, info.signed ? 'i' : 'u'); + write_i64(buf, i64(8*ti.size), 10); + switch info.endianness { + case runtime.Type_Info_Endianness.Little: + write_string(buf, "le"); + case runtime.Type_Info_Endianness.Big: + write_string(buf, "be"); + } + } + case runtime.Type_Info_Rune: + write_string(buf, "rune"); + case runtime.Type_Info_Float: + write_byte(buf, 'f'); + write_i64(buf, i64(8*ti.size), 10); + case runtime.Type_Info_Complex: + write_string(buf, "complex"); + write_i64(buf, i64(8*ti.size), 10); + case runtime.Type_Info_String: + if info.is_cstring { + write_string(buf, "cstring"); + } else { + write_string(buf, "string"); + } + case runtime.Type_Info_Boolean: + switch ti.id { + case bool: write_string(buf, "bool"); + case: + write_byte(buf, 'b'); + write_i64(buf, i64(8*ti.size), 10); + } + case runtime.Type_Info_Any: + write_string(buf, "any"); + + case runtime.Type_Info_Type_Id: + write_string(buf, "typeid"); + + case runtime.Type_Info_Pointer: + if info.elem == nil { + write_string(buf, "rawptr"); + } else { + write_string(buf, "^"); + write_type(buf, info.elem); + } + case runtime.Type_Info_Procedure: + write_string(buf, "proc"); + if info.params == nil { + write_string(buf, "()"); + } else { + t := info.params.variant.(runtime.Type_Info_Tuple); + write_string(buf, "("); + for t, i in t.types { + if i > 0 do write_string(buf, ", "); + write_type(buf, t); + } + write_string(buf, ")"); + } + if info.results != nil { + write_string(buf, " -> "); + write_type(buf, info.results); + } + case runtime.Type_Info_Tuple: + count := len(info.names); + if count != 1 do write_string(buf, "("); + for name, i in info.names { + if i > 0 do write_string(buf, ", "); + + t := info.types[i]; + + if len(name) > 0 { + write_string(buf, name); + write_string(buf, ": "); + } + write_type(buf, t); + } + if count != 1 do write_string(buf, ")"); + + case runtime.Type_Info_Array: + write_string(buf, "["); + write_i64(buf, i64(info.count), 10); + write_string(buf, "]"); + write_type(buf, info.elem); + case runtime.Type_Info_Dynamic_Array: + write_string(buf, "[dynamic]"); + write_type(buf, info.elem); + case runtime.Type_Info_Slice: + write_string(buf, "[]"); + write_type(buf, info.elem); + + case runtime.Type_Info_Map: + write_string(buf, "map["); + write_type(buf, info.key); + write_byte(buf, ']'); + write_type(buf, info.value); + + case runtime.Type_Info_Struct: + write_string(buf, "struct "); + if info.is_packed do write_string(buf, "#packed "); + if info.is_raw_union do write_string(buf, "#raw_union "); + if info.custom_align { + write_string(buf, "#align "); + write_i64(buf, i64(ti.align), 10); + write_byte(buf, ' '); + } + write_byte(buf, '{'); + for name, i in info.names { + if i > 0 do write_string(buf, ", "); + write_string(buf, name); + write_string(buf, ": "); + write_type(buf, info.types[i]); + } + write_byte(buf, '}'); + + case runtime.Type_Info_Union: + write_string(buf, "union "); + if info.custom_align { + write_string(buf, "#align "); + write_i64(buf, i64(ti.align), 10); + write_byte(buf, ' '); + } + write_byte(buf, '{'); + for variant, i in info.variants { + if i > 0 do write_string(buf, ", "); + write_type(buf, variant); + } + write_byte(buf, '}'); + + case runtime.Type_Info_Enum: + write_string(buf, "enum "); + write_type(buf, info.base); + write_string(buf, " {"); + for name, i in info.names { + if i > 0 do write_string(buf, ", "); + write_string(buf, name); + } + write_byte(buf, '}'); + + case runtime.Type_Info_Bit_Field: + write_string(buf, "bit_field "); + if ti.align != 1 { + write_string(buf, "#align "); + write_i64(buf, i64(ti.align), 10); + write_byte(buf, ' '); + } + write_string(buf, " {"); + for name, i in info.names { + if i > 0 do write_string(buf, ", "); + write_string(buf, name); + write_string(buf, ": "); + write_i64(buf, i64(info.bits[i]), 10); + } + write_byte(buf, '}'); + + case runtime.Type_Info_Bit_Set: + write_string(buf, "bit_set["); + switch { + case is_enum(info.elem): + write_type(buf, info.elem); + case is_rune(info.elem): + write_encoded_rune(buf, rune(info.lower)); + write_string(buf, ".."); + write_encoded_rune(buf, rune(info.upper)); + case: + write_i64(buf, info.lower, 10); + write_string(buf, ".."); + write_i64(buf, info.upper, 10); + } + if info.underlying != nil { + write_string(buf, "; "); + write_type(buf, info.underlying); + } + write_byte(buf, ']'); + + case runtime.Type_Info_Opaque: + write_string(buf, "opaque "); + write_type(buf, info.elem); + + case runtime.Type_Info_Simd_Vector: + if info.is_x86_mmx { + write_string(buf, "intrinsics.x86_mmx"); + } else { + write_string(buf, "intrinsics.vector("); + write_i64(buf, i64(info.count)); + write_string(buf, ", "); + write_type(buf, info.elem); + write_byte(buf, ')'); + } + } +} + diff --git a/core/types/types.odin b/core/types/types.odin deleted file mode 100644 index dc4db549f..000000000 --- a/core/types/types.odin +++ /dev/null @@ -1,274 +0,0 @@ -package types - -import rt "core:runtime" - -are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool { - if a == b do return true; - - if (a == nil && b != nil) || - (a != nil && b == nil) { - return false; - } - - - switch { - case a.size != b.size, a.align != b.align: - return false; - } - - switch x in a.variant { - case rt.Type_Info_Named: - y, ok := b.variant.(rt.Type_Info_Named); - if !ok do return false; - return x.base == y.base; - - case rt.Type_Info_Integer: - y, ok := b.variant.(rt.Type_Info_Integer); - if !ok do return false; - return x.signed == y.signed; - - case rt.Type_Info_Rune: - _, ok := b.variant.(rt.Type_Info_Rune); - return ok; - - case rt.Type_Info_Float: - _, ok := b.variant.(rt.Type_Info_Float); - return ok; - - case rt.Type_Info_Complex: - _, ok := b.variant.(rt.Type_Info_Complex); - return ok; - - case rt.Type_Info_String: - _, ok := b.variant.(rt.Type_Info_String); - return ok; - - case rt.Type_Info_Boolean: - _, ok := b.variant.(rt.Type_Info_Boolean); - return ok; - - case rt.Type_Info_Any: - _, ok := b.variant.(rt.Type_Info_Any); - return ok; - - case rt.Type_Info_Pointer: - y, ok := b.variant.(rt.Type_Info_Pointer); - if !ok do return false; - return are_types_identical(x.elem, y.elem); - - case rt.Type_Info_Procedure: - y, ok := b.variant.(rt.Type_Info_Procedure); - if !ok do return false; - switch { - case x.variadic != y.variadic, - x.convention != y.convention: - return false; - } - - return are_types_identical(x.params, y.params) && are_types_identical(x.results, y.results); - - case rt.Type_Info_Array: - y, ok := b.variant.(rt.Type_Info_Array); - if !ok do return false; - if x.count != y.count do return false; - return are_types_identical(x.elem, y.elem); - - case rt.Type_Info_Dynamic_Array: - y, ok := b.variant.(rt.Type_Info_Dynamic_Array); - if !ok do return false; - return are_types_identical(x.elem, y.elem); - - case rt.Type_Info_Slice: - y, ok := b.variant.(rt.Type_Info_Slice); - if !ok do return false; - return are_types_identical(x.elem, y.elem); - - case rt.Type_Info_Tuple: - y, ok := b.variant.(rt.Type_Info_Tuple); - if !ok do return false; - if len(x.types) != len(y.types) do return false; - for _, i in x.types { - xt, yt := x.types[i], y.types[i]; - if !are_types_identical(xt, yt) { - return false; - } - } - return true; - - case rt.Type_Info_Struct: - y, ok := b.variant.(rt.Type_Info_Struct); - if !ok do return false; - switch { - case len(x.types) != len(y.types), - x.is_packed != y.is_packed, - x.is_raw_union != y.is_raw_union, - x.custom_align != y.custom_align: - return false; - } - for _, i in x.types { - xn, yn := x.names[i], y.names[i]; - xt, yt := x.types[i], y.types[i]; - - if xn != yn do return false; - if !are_types_identical(xt, yt) do return false; - } - return true; - - case rt.Type_Info_Union: - y, ok := b.variant.(rt.Type_Info_Union); - if !ok do return false; - if len(x.variants) != len(y.variants) do return false; - - for _, i in x.variants { - xv, yv := x.variants[i], y.variants[i]; - if !are_types_identical(xv, yv) do return false; - } - return true; - - case rt.Type_Info_Enum: - // NOTE(bill): Should be handled above - return false; - - case rt.Type_Info_Map: - y, ok := b.variant.(rt.Type_Info_Map); - if !ok do return false; - return are_types_identical(x.key, y.key) && are_types_identical(x.value, y.value); - - case rt.Type_Info_Bit_Field: - y, ok := b.variant.(rt.Type_Info_Bit_Field); - if !ok do return false; - if len(x.names) != len(y.names) do return false; - - for _, i in x.names { - xb, yb := x.bits[i], y.bits[i]; - xo, yo := x.offsets[i], y.offsets[i]; - xn, yn := x.names[i], y.names[i]; - - if xb != yb do return false; - if xo != yo do return false; - if xn != yn do return false; - } - return true; - - case rt.Type_Info_Bit_Set: - y, ok := b.variant.(rt.Type_Info_Bit_Set); - if !ok do return false; - return x.elem == y.elem && x.lower == y.lower && x.upper == y.upper; - - case rt.Type_Info_Opaque: - y, ok := b.variant.(rt.Type_Info_Opaque); - if !ok do return false; - return x.elem == y.elem; - } - - return false; -} - -is_signed :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - switch i in rt.type_info_base(info).variant { - case rt.Type_Info_Integer: return i.signed; - case rt.Type_Info_Float: return true; - } - return false; -} -is_integer :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Integer); - return ok; -} -is_rune :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Rune); - return ok; -} -is_float :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Float); - return ok; -} -is_complex :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Complex); - return ok; -} -is_any :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Any); - return ok; -} -is_string :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_String); - return ok; -} -is_boolean :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Boolean); - return ok; -} -is_pointer :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Pointer); - return ok; -} -is_procedure :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Procedure); - return ok; -} -is_array :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Array); - return ok; -} -is_dynamic_array :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Dynamic_Array); - return ok; -} -is_dynamic_map :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Map); - return ok; -} -is_slice :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Slice); - return ok; -} -is_tuple :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Tuple); - return ok; -} -is_struct :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - s, ok := rt.type_info_base(info).variant.(rt.Type_Info_Struct); - return ok && !s.is_raw_union; -} -is_raw_union :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - s, ok := rt.type_info_base(info).variant.(rt.Type_Info_Struct); - return ok && s.is_raw_union; -} -is_union :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Union); - return ok; -} -is_enum :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Enum); - return ok; -} -is_opaque :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Opaque); - return ok; -} -is_simd_vector :: proc(info: ^rt.Type_Info) -> bool { - if info == nil do return false; - _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Simd_Vector); - return ok; -} From a58c29582ed355a38f0029b3000aa725c85abb3f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 13 Aug 2019 23:21:33 +0100 Subject: [PATCH 027/143] Add new stuff to package reflect; fix -vet for odin_parser --- core/odin/parser/parser.odin | 2 +- core/reflect/reflect.odin | 309 ++++++++++++----------------------- 2 files changed, 104 insertions(+), 207 deletions(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 2d8e42720..a9961fafd 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1741,7 +1741,7 @@ string_to_calling_convention :: proc(s: string) -> ast.Proc_Calling_Convention { parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) { for p.curr_tok.kind == token.Hash { - tok := expect_token(p, token.Hash); + _ = expect_token(p, token.Hash); ident := expect_token(p, token.Ident); switch ident.text { diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 2e917710b..a4450490f 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -2,7 +2,6 @@ package reflect import "core:runtime" import "core:mem" -import "core:strings" Type_Kind :: enum { @@ -116,6 +115,31 @@ is_nil :: proc(v: any) -> bool { return true; } +length :: proc(val: any) -> int { + if val == nil do return 0; + + v := val; + v.id = runtime.typeid_base(v.id); + switch a in v { + case runtime.Type_Info_Array: + return a.count; + + case runtime.Type_Info_Slice: + return (^mem.Raw_Slice)(v.data).len; + + case runtime.Type_Info_Dynamic_Array: + return (^mem.Raw_Dynamic_Array)(v.data).len; + + case runtime.Type_Info_String: + if a.is_cstring { + return len((^cstring)(v.data)^); + } else { + return (^mem.Raw_String)(v.data).len; + } + } + return 0; +} + index :: proc(val: any, i: int, loc := #caller_location) -> any { if val == nil do return nil; @@ -196,6 +220,35 @@ struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) { return; } +struct_field_value_by_name :: proc(a: any, field: string, recurse := false) -> any { + if a == nil do return nil; + + ti := runtime.type_info_base(type_info_of(a.id)); + + if s, ok := ti.variant.(runtime.Type_Info_Struct); ok { + for name, i in s.names { + if name == field { + return any{ + rawptr(uintptr(a.data) + s.offsets[i]), + s.types[i].id, + }; + } + + if recurse && s.usings[i] { + f := any{ + rawptr(uintptr(a.data) + s.offsets[i]), + s.types[i].id, + }; + + if res := struct_field_value_by_name(f, field, recurse); res != nil { + return res; + } + } + } + } + return nil; +} + struct_field_names :: proc(T: typeid) -> []string { @@ -286,212 +339,56 @@ struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: string, ok: b } -write_typeid :: proc(buf: ^strings.Builder, id: typeid) { - write_type(buf, type_info_of(id)); -} - -write_type :: proc(buf: ^strings.Builder, ti: ^runtime.Type_Info) { - using strings; - if ti == nil { - write_string(buf, "nil"); - return; +enum_string :: proc(a: any) -> string { + if a == nil do return ""; + ti := runtime.type_info_base(type_info_of(a.id)); + if e, ok := ti.variant.(runtime.Type_Info_Enum); ok { + for _, i in e.values { + value := &e.values[i]; + n := mem.compare_byte_ptrs((^byte)(a.data), (^byte)(value), ti.size); + if n == 0 { + return e.names[i]; + } + } + } else { + panic("expected an enum to reflect.enum_string"); } - switch info in ti.variant { - case runtime.Type_Info_Named: - write_string(buf, info.name); - case runtime.Type_Info_Integer: - switch ti.id { - case int: write_string(buf, "int"); - case uint: write_string(buf, "uint"); - case uintptr: write_string(buf, "uintptr"); - case: - write_byte(buf, info.signed ? 'i' : 'u'); - write_i64(buf, i64(8*ti.size), 10); - switch info.endianness { - case runtime.Type_Info_Endianness.Little: - write_string(buf, "le"); - case runtime.Type_Info_Endianness.Big: - write_string(buf, "be"); - } - } - case runtime.Type_Info_Rune: - write_string(buf, "rune"); - case runtime.Type_Info_Float: - write_byte(buf, 'f'); - write_i64(buf, i64(8*ti.size), 10); - case runtime.Type_Info_Complex: - write_string(buf, "complex"); - write_i64(buf, i64(8*ti.size), 10); - case runtime.Type_Info_String: - if info.is_cstring { - write_string(buf, "cstring"); - } else { - write_string(buf, "string"); - } - case runtime.Type_Info_Boolean: - switch ti.id { - case bool: write_string(buf, "bool"); - case: - write_byte(buf, 'b'); - write_i64(buf, i64(8*ti.size), 10); - } - case runtime.Type_Info_Any: - write_string(buf, "any"); - - case runtime.Type_Info_Type_Id: - write_string(buf, "typeid"); - - case runtime.Type_Info_Pointer: - if info.elem == nil { - write_string(buf, "rawptr"); - } else { - write_string(buf, "^"); - write_type(buf, info.elem); - } - case runtime.Type_Info_Procedure: - write_string(buf, "proc"); - if info.params == nil { - write_string(buf, "()"); - } else { - t := info.params.variant.(runtime.Type_Info_Tuple); - write_string(buf, "("); - for t, i in t.types { - if i > 0 do write_string(buf, ", "); - write_type(buf, t); - } - write_string(buf, ")"); - } - if info.results != nil { - write_string(buf, " -> "); - write_type(buf, info.results); - } - case runtime.Type_Info_Tuple: - count := len(info.names); - if count != 1 do write_string(buf, "("); - for name, i in info.names { - if i > 0 do write_string(buf, ", "); - - t := info.types[i]; - - if len(name) > 0 { - write_string(buf, name); - write_string(buf, ": "); - } - write_type(buf, t); - } - if count != 1 do write_string(buf, ")"); - - case runtime.Type_Info_Array: - write_string(buf, "["); - write_i64(buf, i64(info.count), 10); - write_string(buf, "]"); - write_type(buf, info.elem); - case runtime.Type_Info_Dynamic_Array: - write_string(buf, "[dynamic]"); - write_type(buf, info.elem); - case runtime.Type_Info_Slice: - write_string(buf, "[]"); - write_type(buf, info.elem); - - case runtime.Type_Info_Map: - write_string(buf, "map["); - write_type(buf, info.key); - write_byte(buf, ']'); - write_type(buf, info.value); - - case runtime.Type_Info_Struct: - write_string(buf, "struct "); - if info.is_packed do write_string(buf, "#packed "); - if info.is_raw_union do write_string(buf, "#raw_union "); - if info.custom_align { - write_string(buf, "#align "); - write_i64(buf, i64(ti.align), 10); - write_byte(buf, ' '); - } - write_byte(buf, '{'); - for name, i in info.names { - if i > 0 do write_string(buf, ", "); - write_string(buf, name); - write_string(buf, ": "); - write_type(buf, info.types[i]); - } - write_byte(buf, '}'); - - case runtime.Type_Info_Union: - write_string(buf, "union "); - if info.custom_align { - write_string(buf, "#align "); - write_i64(buf, i64(ti.align), 10); - write_byte(buf, ' '); - } - write_byte(buf, '{'); - for variant, i in info.variants { - if i > 0 do write_string(buf, ", "); - write_type(buf, variant); - } - write_byte(buf, '}'); - - case runtime.Type_Info_Enum: - write_string(buf, "enum "); - write_type(buf, info.base); - write_string(buf, " {"); - for name, i in info.names { - if i > 0 do write_string(buf, ", "); - write_string(buf, name); - } - write_byte(buf, '}'); - - case runtime.Type_Info_Bit_Field: - write_string(buf, "bit_field "); - if ti.align != 1 { - write_string(buf, "#align "); - write_i64(buf, i64(ti.align), 10); - write_byte(buf, ' '); - } - write_string(buf, " {"); - for name, i in info.names { - if i > 0 do write_string(buf, ", "); - write_string(buf, name); - write_string(buf, ": "); - write_i64(buf, i64(info.bits[i]), 10); - } - write_byte(buf, '}'); - - case runtime.Type_Info_Bit_Set: - write_string(buf, "bit_set["); - switch { - case is_enum(info.elem): - write_type(buf, info.elem); - case is_rune(info.elem): - write_encoded_rune(buf, rune(info.lower)); - write_string(buf, ".."); - write_encoded_rune(buf, rune(info.upper)); - case: - write_i64(buf, info.lower, 10); - write_string(buf, ".."); - write_i64(buf, info.upper, 10); - } - if info.underlying != nil { - write_string(buf, "; "); - write_type(buf, info.underlying); - } - write_byte(buf, ']'); - - case runtime.Type_Info_Opaque: - write_string(buf, "opaque "); - write_type(buf, info.elem); - - case runtime.Type_Info_Simd_Vector: - if info.is_x86_mmx { - write_string(buf, "intrinsics.x86_mmx"); - } else { - write_string(buf, "intrinsics.vector("); - write_i64(buf, i64(info.count)); - write_string(buf, ", "); - write_type(buf, info.elem); - write_byte(buf, ')'); - } - } + return ""; } +union_variant_type_info :: proc(a: any) -> ^runtime.Type_Info { + id := union_variant_typeid(a); + return type_info_of(id); +} + +union_variant_typeid :: proc(a: any) -> typeid { + if a == nil do return nil; + + ti := runtime.type_info_base(type_info_of(a.id)); + if info, ok := ti.variant.(runtime.Type_Info_Union); ok { + tag_ptr := uintptr(a.data) + info.tag_offset; + tag_any := any{rawptr(tag_ptr), info.tag_type.id}; + + tag: i64 = ---; + switch i in tag_any { + case u8: tag = i64(i); + case i8: tag = i64(i); + case u16: tag = i64(i); + case i16: tag = i64(i); + case u32: tag = i64(i); + case i32: tag = i64(i); + case u64: tag = i64(i); + case i64: tag = i64(i); + case: unimplemented(); + } + + if a.data != nil && tag != 0 { + return info.variants[tag-1].id; + } + } else { + panic("expected a union to reflect.union_variant_typeid"); + } + + return nil; +} From 4369298e9629fffa2bd86a1aa50bec13abd84180 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 13 Aug 2019 23:21:51 +0100 Subject: [PATCH 028/143] Add reflect/types.odin --- core/reflect/types.odin | 492 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 492 insertions(+) create mode 100644 core/reflect/types.odin diff --git a/core/reflect/types.odin b/core/reflect/types.odin new file mode 100644 index 000000000..8130668b3 --- /dev/null +++ b/core/reflect/types.odin @@ -0,0 +1,492 @@ +package reflect + +import rt "core:runtime" +import "core:strings" + +are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool { + if a == b do return true; + + if (a == nil && b != nil) || + (a != nil && b == nil) { + return false; + } + + + switch { + case a.size != b.size, a.align != b.align: + return false; + } + + switch x in a.variant { + case rt.Type_Info_Named: + y, ok := b.variant.(rt.Type_Info_Named); + if !ok do return false; + return x.base == y.base; + + case rt.Type_Info_Integer: + y, ok := b.variant.(rt.Type_Info_Integer); + if !ok do return false; + return x.signed == y.signed; + + case rt.Type_Info_Rune: + _, ok := b.variant.(rt.Type_Info_Rune); + return ok; + + case rt.Type_Info_Float: + _, ok := b.variant.(rt.Type_Info_Float); + return ok; + + case rt.Type_Info_Complex: + _, ok := b.variant.(rt.Type_Info_Complex); + return ok; + + case rt.Type_Info_String: + _, ok := b.variant.(rt.Type_Info_String); + return ok; + + case rt.Type_Info_Boolean: + _, ok := b.variant.(rt.Type_Info_Boolean); + return ok; + + case rt.Type_Info_Any: + _, ok := b.variant.(rt.Type_Info_Any); + return ok; + + case rt.Type_Info_Pointer: + y, ok := b.variant.(rt.Type_Info_Pointer); + if !ok do return false; + return are_types_identical(x.elem, y.elem); + + case rt.Type_Info_Procedure: + y, ok := b.variant.(rt.Type_Info_Procedure); + if !ok do return false; + switch { + case x.variadic != y.variadic, + x.convention != y.convention: + return false; + } + + return are_types_identical(x.params, y.params) && are_types_identical(x.results, y.results); + + case rt.Type_Info_Array: + y, ok := b.variant.(rt.Type_Info_Array); + if !ok do return false; + if x.count != y.count do return false; + return are_types_identical(x.elem, y.elem); + + case rt.Type_Info_Dynamic_Array: + y, ok := b.variant.(rt.Type_Info_Dynamic_Array); + if !ok do return false; + return are_types_identical(x.elem, y.elem); + + case rt.Type_Info_Slice: + y, ok := b.variant.(rt.Type_Info_Slice); + if !ok do return false; + return are_types_identical(x.elem, y.elem); + + case rt.Type_Info_Tuple: + y, ok := b.variant.(rt.Type_Info_Tuple); + if !ok do return false; + if len(x.types) != len(y.types) do return false; + for _, i in x.types { + xt, yt := x.types[i], y.types[i]; + if !are_types_identical(xt, yt) { + return false; + } + } + return true; + + case rt.Type_Info_Struct: + y, ok := b.variant.(rt.Type_Info_Struct); + if !ok do return false; + switch { + case len(x.types) != len(y.types), + x.is_packed != y.is_packed, + x.is_raw_union != y.is_raw_union, + x.custom_align != y.custom_align: + return false; + } + for _, i in x.types { + xn, yn := x.names[i], y.names[i]; + xt, yt := x.types[i], y.types[i]; + xl, yl := x.tags[i], y.tags[i]; + + if xn != yn do return false; + if !are_types_identical(xt, yt) do return false; + if xl != yl do return false; + } + return true; + + case rt.Type_Info_Union: + y, ok := b.variant.(rt.Type_Info_Union); + if !ok do return false; + if len(x.variants) != len(y.variants) do return false; + + for _, i in x.variants { + xv, yv := x.variants[i], y.variants[i]; + if !are_types_identical(xv, yv) do return false; + } + return true; + + case rt.Type_Info_Enum: + // NOTE(bill): Should be handled above + return false; + + case rt.Type_Info_Map: + y, ok := b.variant.(rt.Type_Info_Map); + if !ok do return false; + return are_types_identical(x.key, y.key) && are_types_identical(x.value, y.value); + + case rt.Type_Info_Bit_Field: + y, ok := b.variant.(rt.Type_Info_Bit_Field); + if !ok do return false; + if len(x.names) != len(y.names) do return false; + + for _, i in x.names { + xb, yb := x.bits[i], y.bits[i]; + xo, yo := x.offsets[i], y.offsets[i]; + xn, yn := x.names[i], y.names[i]; + + if xb != yb do return false; + if xo != yo do return false; + if xn != yn do return false; + } + return true; + + case rt.Type_Info_Bit_Set: + y, ok := b.variant.(rt.Type_Info_Bit_Set); + if !ok do return false; + return x.elem == y.elem && x.lower == y.lower && x.upper == y.upper; + + case rt.Type_Info_Opaque: + y, ok := b.variant.(rt.Type_Info_Opaque); + if !ok do return false; + return x.elem == y.elem; + } + + return false; +} + +is_signed :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + switch i in rt.type_info_base(info).variant { + case rt.Type_Info_Integer: return i.signed; + case rt.Type_Info_Float: return true; + } + return false; +} +is_integer :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Integer); + return ok; +} +is_rune :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Rune); + return ok; +} +is_float :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Float); + return ok; +} +is_complex :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Complex); + return ok; +} +is_any :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Any); + return ok; +} +is_string :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_String); + return ok; +} +is_boolean :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Boolean); + return ok; +} +is_pointer :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Pointer); + return ok; +} +is_procedure :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Procedure); + return ok; +} +is_array :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Array); + return ok; +} +is_dynamic_array :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Dynamic_Array); + return ok; +} +is_dynamic_map :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Map); + return ok; +} +is_slice :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Slice); + return ok; +} +is_tuple :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Tuple); + return ok; +} +is_struct :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + s, ok := rt.type_info_base(info).variant.(rt.Type_Info_Struct); + return ok && !s.is_raw_union; +} +is_raw_union :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + s, ok := rt.type_info_base(info).variant.(rt.Type_Info_Struct); + return ok && s.is_raw_union; +} +is_union :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Union); + return ok; +} +is_enum :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Enum); + return ok; +} +is_opaque :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Opaque); + return ok; +} +is_simd_vector :: proc(info: ^rt.Type_Info) -> bool { + if info == nil do return false; + _, ok := rt.type_info_base(info).variant.(rt.Type_Info_Simd_Vector); + return ok; +} + + + + + + +write_typeid :: proc(buf: ^strings.Builder, id: typeid) { + write_type(buf, type_info_of(id)); +} + +write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) { + using strings; + if ti == nil { + write_string(buf, "nil"); + return; + } + + switch info in ti.variant { + case rt.Type_Info_Named: + write_string(buf, info.name); + case rt.Type_Info_Integer: + switch ti.id { + case int: write_string(buf, "int"); + case uint: write_string(buf, "uint"); + case uintptr: write_string(buf, "uintptr"); + case: + write_byte(buf, info.signed ? 'i' : 'u'); + write_i64(buf, i64(8*ti.size), 10); + switch info.endianness { + case rt.Type_Info_Endianness.Little: + write_string(buf, "le"); + case rt.Type_Info_Endianness.Big: + write_string(buf, "be"); + } + } + case rt.Type_Info_Rune: + write_string(buf, "rune"); + case rt.Type_Info_Float: + write_byte(buf, 'f'); + write_i64(buf, i64(8*ti.size), 10); + case rt.Type_Info_Complex: + write_string(buf, "complex"); + write_i64(buf, i64(8*ti.size), 10); + case rt.Type_Info_String: + if info.is_cstring { + write_string(buf, "cstring"); + } else { + write_string(buf, "string"); + } + case rt.Type_Info_Boolean: + switch ti.id { + case bool: write_string(buf, "bool"); + case: + write_byte(buf, 'b'); + write_i64(buf, i64(8*ti.size), 10); + } + case rt.Type_Info_Any: + write_string(buf, "any"); + + case rt.Type_Info_Type_Id: + write_string(buf, "typeid"); + + case rt.Type_Info_Pointer: + if info.elem == nil { + write_string(buf, "rawptr"); + } else { + write_string(buf, "^"); + write_type(buf, info.elem); + } + case rt.Type_Info_Procedure: + write_string(buf, "proc"); + if info.params == nil { + write_string(buf, "()"); + } else { + t := info.params.variant.(rt.Type_Info_Tuple); + write_string(buf, "("); + for t, i in t.types { + if i > 0 do write_string(buf, ", "); + write_type(buf, t); + } + write_string(buf, ")"); + } + if info.results != nil { + write_string(buf, " -> "); + write_type(buf, info.results); + } + case rt.Type_Info_Tuple: + count := len(info.names); + if count != 1 do write_string(buf, "("); + for name, i in info.names { + if i > 0 do write_string(buf, ", "); + + t := info.types[i]; + + if len(name) > 0 { + write_string(buf, name); + write_string(buf, ": "); + } + write_type(buf, t); + } + if count != 1 do write_string(buf, ")"); + + case rt.Type_Info_Array: + write_string(buf, "["); + write_i64(buf, i64(info.count), 10); + write_string(buf, "]"); + write_type(buf, info.elem); + case rt.Type_Info_Dynamic_Array: + write_string(buf, "[dynamic]"); + write_type(buf, info.elem); + case rt.Type_Info_Slice: + write_string(buf, "[]"); + write_type(buf, info.elem); + + case rt.Type_Info_Map: + write_string(buf, "map["); + write_type(buf, info.key); + write_byte(buf, ']'); + write_type(buf, info.value); + + case rt.Type_Info_Struct: + write_string(buf, "struct "); + if info.is_packed do write_string(buf, "#packed "); + if info.is_raw_union do write_string(buf, "#raw_union "); + if info.custom_align { + write_string(buf, "#align "); + write_i64(buf, i64(ti.align), 10); + write_byte(buf, ' '); + } + write_byte(buf, '{'); + for name, i in info.names { + if i > 0 do write_string(buf, ", "); + write_string(buf, name); + write_string(buf, ": "); + write_type(buf, info.types[i]); + } + write_byte(buf, '}'); + + case rt.Type_Info_Union: + write_string(buf, "union "); + if info.custom_align { + write_string(buf, "#align "); + write_i64(buf, i64(ti.align), 10); + write_byte(buf, ' '); + } + write_byte(buf, '{'); + for variant, i in info.variants { + if i > 0 do write_string(buf, ", "); + write_type(buf, variant); + } + write_byte(buf, '}'); + + case rt.Type_Info_Enum: + write_string(buf, "enum "); + write_type(buf, info.base); + write_string(buf, " {"); + for name, i in info.names { + if i > 0 do write_string(buf, ", "); + write_string(buf, name); + } + write_byte(buf, '}'); + + case rt.Type_Info_Bit_Field: + write_string(buf, "bit_field "); + if ti.align != 1 { + write_string(buf, "#align "); + write_i64(buf, i64(ti.align), 10); + write_byte(buf, ' '); + } + write_string(buf, " {"); + for name, i in info.names { + if i > 0 do write_string(buf, ", "); + write_string(buf, name); + write_string(buf, ": "); + write_i64(buf, i64(info.bits[i]), 10); + } + write_byte(buf, '}'); + + case rt.Type_Info_Bit_Set: + write_string(buf, "bit_set["); + switch { + case is_enum(info.elem): + write_type(buf, info.elem); + case is_rune(info.elem): + write_encoded_rune(buf, rune(info.lower)); + write_string(buf, ".."); + write_encoded_rune(buf, rune(info.upper)); + case: + write_i64(buf, info.lower, 10); + write_string(buf, ".."); + write_i64(buf, info.upper, 10); + } + if info.underlying != nil { + write_string(buf, "; "); + write_type(buf, info.underlying); + } + write_byte(buf, ']'); + + case rt.Type_Info_Opaque: + write_string(buf, "opaque "); + write_type(buf, info.elem); + + case rt.Type_Info_Simd_Vector: + if info.is_x86_mmx { + write_string(buf, "intrinsics.x86_mmx"); + } else { + write_string(buf, "intrinsics.vector("); + write_i64(buf, i64(info.count)); + write_string(buf, ", "); + write_type(buf, info.elem); + write_byte(buf, ')'); + } + } +} + From a7676bff6ef105b8fbd84610c1a842beb5e40f2b Mon Sep 17 00:00:00 2001 From: zhibog Date: Thu, 15 Aug 2019 22:05:06 +0200 Subject: [PATCH 029/143] Added an implementation for Base64. Also provides the ability to supply your own alphabet and decoding table. --- core/encoding/base64/base64.odin | 93 ++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 core/encoding/base64/base64.odin diff --git a/core/encoding/base64/base64.odin b/core/encoding/base64/base64.odin new file mode 100644 index 000000000..0224e93e4 --- /dev/null +++ b/core/encoding/base64/base64.odin @@ -0,0 +1,93 @@ +package base64 + +// @note(zh): Encoding utility for Base64 +// A secondary param can be used to supply a custom alphabet to +// @link(encode) and a matching decoding table to @link(decode). +// If none is supplied it just uses the standard Base64 alphabet. +// Incase your specific version does not use padding, you may +// truncate it from the encoded output. + +ENC_TABLE := [64]byte { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' +}; + +PADDING :: '='; + +DEC_TABLE := [128]int { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, -1, -1, -1, -1, -1 +}; + +encode :: proc(data: []byte, ENC_TBL := ENC_TABLE, allocator := context.allocator) -> string #no_bounds_check { + length := len(data); + if length == 0 do return ""; + + out_length := ((4 * length / 3) + 3) &~ 3; + out := make([]byte, out_length, allocator); + + c0, c1, c2, block: int; + + for i, d := 0, 0; i < length; i, d = i + 3, d + 4 { + c0, c1, c2 = int(data[i]), 0, 0; + + if i + 1 < length do c1 = int(data[i + 1]); + if i + 2 < length do c2 = int(data[i + 2]); + + block = (c0 << 16) | (max(c1, 0) << 8) | max(c2, 0); + + out[d] = ENC_TBL[block >> 18 & 63]; + out[d + 1] = ENC_TBL[block >> 12 & 63]; + out[d + 2] = c1 == 0 ? PADDING : ENC_TBL[block >> 6 & 63]; + out[d + 3] = c2 == 0 ? PADDING : ENC_TBL[block & 63]; + } + return string(out); +} + +decode :: proc(data: string, DEC_TBL := DEC_TABLE, allocator := context.allocator) -> []byte #no_bounds_check{ + length := len(data); + if length == 0 do return []byte{}; + + pad_count := data[length - 1] == PADDING ? (data[length - 2] == PADDING ? 2 : 1) : 0; + out_length := ((length * 6) >> 3) - pad_count; + out := make([]byte, out_length, allocator); + + c0, c1, c2, c3: int; + b0, b1, b2: int; + + for i, j := 0, 0; i < length; i, j = i + 4, j + 3 { + c0 = DEC_TBL[data[i]]; + c1 = DEC_TBL[data[i + 1]]; + c2 = DEC_TBL[data[i + 2]]; + c3 = DEC_TBL[data[i + 3]]; + + b0 = (c0 << 2) | (c1 >> 4); + b1 = (c1 << 4) | (c2 >> 2); + b2 = (c2 << 6) | c3; + + out[j] = byte(b0); + out[j + 1] = byte(b1); + out[j + 2] = byte(b2); + } + return out; +} \ No newline at end of file From 150d4e343ddd99eef1d921cdd494c108ac2e9a12 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 23 Aug 2019 10:24:18 +0100 Subject: [PATCH 030/143] Fix `~(1 << x)` type inference bug --- src/check_expr.cpp | 17 ++++++++++------- src/check_stmt.cpp | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8da6816ac..6c252b9b6 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1767,7 +1767,7 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) { } -void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node) { +void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *type_hint) { GB_ASSERT(node->kind == Ast_BinaryExpr); ast_node(be, BinaryExpr, node); @@ -1845,6 +1845,9 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node) { info->is_lhs = true; } x->mode = Addressing_Value; + if (type_hint && is_type_integer(type_hint)) { + x->type = type_hint; + } // x->value = x_val; return; } @@ -2167,7 +2170,7 @@ bool check_binary_array_expr(CheckerContext *c, Token op, Operand *x, Operand *y } -void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, bool use_lhs_as_type_hint=false) { +void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint, bool use_lhs_as_type_hint=false) { GB_ASSERT(node->kind == Ast_BinaryExpr); Operand y_ = {}, *y = &y_; @@ -2178,7 +2181,7 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, bool use_lhs_as case Token_CmpEq: case Token_NotEq: { // NOTE(bill): Allow comparisons between types - check_expr_or_type(c, x, be->left); + check_expr_or_type(c, x, be->left, type_hint); check_expr_or_type(c, y, be->right, x->type); bool xt = x->mode == Addressing_Type; bool yt = y->mode == Addressing_Type; @@ -2278,11 +2281,11 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, bool use_lhs_as return; default: - check_expr(c, x, be->left); + check_expr_with_type_hint(c, x, be->left, type_hint); if (use_lhs_as_type_hint) { check_expr_with_type_hint(c, y, be->right, x->type); } else { - check_expr(c, y, be->right); + check_expr_with_type_hint(c, y, be->right, type_hint); } break; } @@ -2307,7 +2310,7 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, bool use_lhs_as } if (token_is_shift(op.kind)) { - check_shift(c, x, y, node); + check_shift(c, x, y, node, type_hint); return; } @@ -7000,7 +7003,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_ast_node(be, BinaryExpr, node); - check_binary_expr(c, o, node, true); + check_binary_expr(c, o, node, type_hint, true); if (o->mode == Addressing_Invalid) { o->expr = node; return kind; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index e2090688f..2787aa436 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1168,7 +1168,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { be->right = as->rhs[0]; check_expr(ctx, &lhs, as->lhs[0]); - check_binary_expr(ctx, &rhs, &binary_expr, true); + check_binary_expr(ctx, &rhs, &binary_expr, nullptr, true); if (rhs.mode == Addressing_Invalid) { return; } From d1cc6534cdb25c95f948a81e863f9348dfb5122e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 23 Aug 2019 10:32:05 +0100 Subject: [PATCH 031/143] Remove the rule that made any declaration prefixed with an underscore private to that package. --- src/entity.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/entity.cpp b/src/entity.cpp index 0c05a9bf6..78726171d 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -184,10 +184,11 @@ bool is_entity_exported(Entity *e, bool allow_builtin = false) { } String name = e->token.string; - if (name.len == 0) { - return false; + switch (name.len) { + case 0: return false; + case 1: return name[0] != '_'; } - return name[0] != '_'; + return true; } bool entity_has_deferred_procedure(Entity *e) { From cf23954297993b3e574c295f95f75b294fdca4ec Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 23 Aug 2019 11:51:04 +0100 Subject: [PATCH 032/143] Improve #assert to show the procedure and signature it was called with; Allow the ability to print ExactValue correct now. --- src/check_expr.cpp | 9 ++++- src/exact_value.cpp | 46 ++++++++++++++++++++++++ src/string.cpp | 88 +++++++++++++++++++++++++++++++++++++++++++-- src/types.cpp | 71 ++++++++++++++++++++++-------------- 4 files changed, 184 insertions(+), 30 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6c252b9b6..24a130d62 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3360,6 +3360,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (!operand->value.value_bool) { gbString arg = expr_to_string(ce->args[0]); error(call, "Compile time assertion: %s", arg); + if (c->proc_name != "") { + gbString str = type_to_string(c->curr_proc_sig); + error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); + gb_string_free(str); + } gb_string_free(arg); } @@ -3744,7 +3749,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } if (x.mode == Addressing_Constant && y.mode == Addressing_Constant) { - operand->value = exact_binary_operator_value(Token_Add, x.value, y.value); + f64 r = exact_value_to_float(x.value).value_float; + f64 i = exact_value_to_float(y.value).value_float; + operand->value = exact_value_complex(r, i); operand->mode = Addressing_Constant; } else { operand->mode = Addressing_Value; diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 7d822512b..be034ecc5 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -718,3 +718,49 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) { GB_PANIC("Invalid comparison"); return false; } + + +gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) { + switch (v.kind) { + case ExactValue_Invalid: + return str; + case ExactValue_Bool: + return gb_string_appendc(str, v.value_bool ? "true" : "false"); + case ExactValue_String: { + String s = quote_to_ascii(heap_allocator(), v.value_string); + string_limit = gb_max(string_limit, 36); + if (s.len <= string_limit) { + str = gb_string_append_length(str, s.text, s.len); + } else { + isize n = string_limit/5; + str = gb_string_append_length(str, s.text, n); + str = gb_string_append_fmt(str, "\"..%lld chars..\"", s.len-(2*n)); + str = gb_string_append_length(str, s.text+s.len-n, n); + } + gb_free(heap_allocator(), s.text); + return str; + } + case ExactValue_Integer: { + String s = big_int_to_string(heap_allocator(), &v.value_integer); + str = gb_string_append_length(str, s.text, s.len); + gb_free(heap_allocator(), s.text); + return str; + } + case ExactValue_Float: + return gb_string_append_fmt(str, "%f", v.value_float); + case ExactValue_Complex: + return gb_string_append_fmt(str, "%f+%fi", v.value_complex.real, v.value_complex.imag); + + case ExactValue_Pointer: + return str; + case ExactValue_Compound: + return str; + case ExactValue_Procedure: + return str; + } + return str; +}; + +gbString exact_value_to_string(ExactValue const &v, isize string_limit=35) { + return write_exact_value_to_string(gb_string_make(heap_allocator(), ""), v, string_limit); +} diff --git a/src/string.cpp b/src/string.cpp index 774061edf..a29f3bd77 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -440,12 +440,94 @@ String string16_to_string(gbAllocator a, String16 s) { +bool is_printable(Rune r) { + if (r <= 0xff) { + if (0x20 <= r && r <= 0x7e) { + return true; + } + if (0xa1 <= r && r <= 0xff) { + return r != 0xad; + } + return false; + } + return false; +} + +gb_global char const lower_hex[] = "0123456789abcdef"; + +String quote_to_ascii(gbAllocator a, String str, u8 quote='"') { + u8 *s = str.text; + isize n = str.len; + auto buf = array_make(a, 0, n); + array_add(&buf, quote); + for (isize width = 0; n > 0; s += width, n -= width) { + Rune r = cast(Rune)s[0]; + width = 1; + if (r >= 0x80) { + width = gb_utf8_decode(s, n, &r); + } + if (width == 1 && r == GB_RUNE_INVALID) { + array_add(&buf, cast(u8)'\\'); + array_add(&buf, cast(u8)'x'); + array_add(&buf, cast(u8)lower_hex[s[0]>>4]); + array_add(&buf, cast(u8)lower_hex[s[0]&0xf]); + continue; + } + + if (r == quote || r == '\\') { + array_add(&buf, cast(u8)'\\'); + array_add(&buf, u8(r)); + continue; + } + if (r < 0x80 && is_printable(r)) { + array_add(&buf, u8(r)); + continue; + } + switch (r) { + case '\a': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + default: + if (r < ' ') { + u8 b = cast(u8)r; + array_add(&buf, cast(u8)'\\'); + array_add(&buf, cast(u8)'x'); + array_add(&buf, cast(u8)lower_hex[b>>4]); + array_add(&buf, cast(u8)lower_hex[b&0xf]); + } + if (r > GB_RUNE_MAX) { + r = 0XFFFD; + } + if (r < 0x10000) { + u8 b = cast(u8)r; + array_add(&buf, cast(u8)'\\'); + array_add(&buf, cast(u8)'u'); + for (isize i = 12; i >= 0; i -= 4) { + array_add(&buf, cast(u8)lower_hex[(r>>i)&0xf]); + } + } else { + u8 b = cast(u8)r; + array_add(&buf, cast(u8)'\\'); + array_add(&buf, cast(u8)'U'); + for (isize i = 28; i >= 0; i -= 4) { + array_add(&buf, cast(u8)lower_hex[(r>>i)&0xf]); + } + } + } + } - - - + array_add(&buf, quote); + String res = {}; + res.text = buf.data; + res.len = buf.count; + return res; +} diff --git a/src/types.cpp b/src/types.cpp index 4404882a9..b5c9152b6 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2968,35 +2968,54 @@ gbString write_type_to_string(gbString str, Type *type) { isize comma_index = 0; for_array(i, type->Tuple.variables) { Entity *var = type->Tuple.variables[i]; - if (var != nullptr) { - if (var->kind == Entity_Constant) { - // Ignore - continue; - } - - if (comma_index++ > 0) { - str = gb_string_appendc(str, ", "); - } - - if (var->kind == Entity_Variable) { - if (var->flags&EntityFlag_CVarArg) { - str = gb_string_appendc(str, "#c_vararg "); - } - if (var->flags&EntityFlag_Ellipsis) { - Type *slice = base_type(var->type); - str = gb_string_appendc(str, ".."); - GB_ASSERT(var->type->kind == Type_Slice); - str = write_type_to_string(str, slice->Slice.elem); - } else { - str = write_type_to_string(str, var->type); - } + if (var == nullptr) { + continue; + } + String name = var->token.string; + if (var->kind == Entity_Constant) { + str = gb_string_appendc(str, "$"); + str = gb_string_append_length(str, name.text, name.len); + if (!is_type_untyped(var->type)) { + str = gb_string_appendc(str, ": "); + str = write_type_to_string(str, var->type); + str = gb_string_appendc(str, " = "); + str = write_exact_value_to_string(str, var->Constant.value); } else { - GB_ASSERT(var->kind == Entity_TypeName); - if (var->type->kind == Type_Generic) { - str = gb_string_appendc(str, "type/"); + str = gb_string_appendc(str, "="); + str = write_exact_value_to_string(str, var->Constant.value); + } + continue; + } + + if (comma_index++ > 0) { + str = gb_string_appendc(str, ", "); + } + + if (var->kind == Entity_Variable) { + if (var->flags&EntityFlag_CVarArg) { + str = gb_string_appendc(str, "#c_vararg "); + } + if (var->flags&EntityFlag_Ellipsis) { + Type *slice = base_type(var->type); + str = gb_string_appendc(str, ".."); + GB_ASSERT(var->type->kind == Type_Slice); + str = write_type_to_string(str, slice->Slice.elem); + } else { + str = write_type_to_string(str, var->type); + } + } else { + GB_ASSERT(var->kind == Entity_TypeName); + if (var->type->kind == Type_Generic) { + str = gb_string_appendc(str, "typeid/"); + str = write_type_to_string(str, var->type); + } else { + if (var->kind == Entity_TypeName) { + str = gb_string_appendc(str, "$"); + str = gb_string_append_length(str, name.text, name.len); + str = gb_string_appendc(str, "="); str = write_type_to_string(str, var->type); } else { - str = gb_string_appendc(str, "type"); + str = gb_string_appendc(str, "typeid"); } } } From 59ab51acecd22674a7cc8607cd3af8eaeb55068a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 23 Aug 2019 11:54:23 +0100 Subject: [PATCH 033/143] Fix typo --- src/exact_value.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/exact_value.cpp b/src/exact_value.cpp index be034ecc5..520812e44 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -761,6 +761,6 @@ gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize st return str; }; -gbString exact_value_to_string(ExactValue const &v, isize string_limit=35) { +gbString exact_value_to_string(ExactValue const &v, isize string_limit=36) { return write_exact_value_to_string(gb_string_make(heap_allocator(), ""), v, string_limit); } From 7bc146e6fde909298a7184fdf00cec91868ffc00 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 26 Aug 2019 11:33:05 +0100 Subject: [PATCH 034/143] Built-in Quaternions (Not just an April Fool's Joke any more) --- core/fmt/fmt.odin | 29 ++++ core/reflect/reflect.odin | 2 + core/runtime/core.odin | 23 ++-- core/runtime/internal.odin | 70 +++++++++- examples/demo/demo.odin | 60 +++++++-- src/check_expr.cpp | 242 ++++++++++++++++++++++++++++++++- src/checker.cpp | 6 + src/checker_builtin_procs.hpp | 6 + src/exact_value.cpp | 184 ++++++++++++++++++++++++- src/ir.cpp | 245 +++++++++++++++++++++++++++++++++- src/ir_print.cpp | 53 ++++++-- src/tokenizer.cpp | 5 +- src/types.cpp | 50 +++++-- 13 files changed, 909 insertions(+), 66 deletions(-) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 5dbebf972..a2f1166ac 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1129,6 +1129,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Rune: fmt_arg(fi, v, verb); case runtime.Type_Info_Float: fmt_arg(fi, v, verb); case runtime.Type_Info_Complex: fmt_arg(fi, v, verb); + case runtime.Type_Info_Quaternion: fmt_arg(fi, v, verb); case runtime.Type_Info_String: fmt_arg(fi, v, verb); case runtime.Type_Info_Pointer: @@ -1386,6 +1387,31 @@ fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) { } } +fmt_quaternion :: proc(fi: ^Info, q: quaternion256, bits: int, verb: rune) { + switch verb { + case 'f', 'F', 'v', 'h', 'H': + r, i, j, k := real(q), imag(q), jmag(q), kmag(q); + + fmt_float(fi, r, bits/4, verb); + + if !fi.plus && i >= 0 do strings.write_rune(fi.buf, '+'); + fmt_float(fi, i, bits/4, verb); + strings.write_rune(fi.buf, 'i'); + + if !fi.plus && j >= 0 do strings.write_rune(fi.buf, '+'); + fmt_float(fi, j, bits/4, verb); + strings.write_rune(fi.buf, 'j'); + + if !fi.plus && k >= 0 do strings.write_rune(fi.buf, '+'); + fmt_float(fi, k, bits/4, verb); + strings.write_rune(fi.buf, 'k'); + + case: + fmt_bad_verb(fi, verb); + return; + } +} + fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { if arg == nil { strings.write_string(fi.buf, ""); @@ -1434,6 +1460,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { case complex64: fmt_complex(fi, complex128(a), 64, verb); case complex128: fmt_complex(fi, a, 128, verb); + case quaternion128: fmt_quaternion(fi, quaternion256(a), 128, verb); + case quaternion256: fmt_quaternion(fi, a, 256, verb); + case i8: fmt_int(fi, u64(a), true, 8, verb); case u8: fmt_int(fi, u64(a), false, 8, verb); case i16: fmt_int(fi, u64(a), true, 16, verb); diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index a4450490f..4bc9a2225 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -12,6 +12,7 @@ Type_Kind :: enum { Rune, Float, Complex, + Quaternion, String, Boolean, Any, @@ -42,6 +43,7 @@ type_kind :: proc(T: typeid) -> Type_Kind { case runtime.Type_Info_Rune: return .Rune; case runtime.Type_Info_Float: return .Float; case runtime.Type_Info_Complex: return .Complex; + case runtime.Type_Info_Quaternion: return .Quaternion; case runtime.Type_Info_String: return .String; case runtime.Type_Info_Boolean: return .Boolean; case runtime.Type_Info_Any: return .Any; diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 047281b10..022a84e9e 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -47,16 +47,17 @@ Type_Info_Endianness :: enum u8 { } // Variant Types -Type_Info_Named :: struct {name: string, base: ^Type_Info}; -Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness}; -Type_Info_Rune :: struct {}; -Type_Info_Float :: struct {}; -Type_Info_Complex :: struct {}; -Type_Info_String :: struct {is_cstring: bool}; -Type_Info_Boolean :: struct {}; -Type_Info_Any :: struct {}; -Type_Info_Type_Id :: struct {}; -Type_Info_Pointer :: struct { +Type_Info_Named :: struct {name: string, base: ^Type_Info}; +Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness}; +Type_Info_Rune :: struct {}; +Type_Info_Float :: struct {}; +Type_Info_Complex :: struct {}; +Type_Info_Quaternion :: struct {}; +Type_Info_String :: struct {is_cstring: bool}; +Type_Info_Boolean :: struct {}; +Type_Info_Any :: struct {}; +Type_Info_Type_Id :: struct {}; +Type_Info_Pointer :: struct { elem: ^Type_Info // nil -> rawptr }; Type_Info_Procedure :: struct { @@ -135,6 +136,7 @@ Type_Info :: struct { Type_Info_Rune, Type_Info_Float, Type_Info_Complex, + Type_Info_Quaternion, Type_Info_String, Type_Info_Boolean, Type_Info_Any, @@ -163,6 +165,7 @@ Typeid_Kind :: enum u8 { Rune, Float, Complex, + Quaternion, String, Boolean, Any, diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index c33d5f62c..a5099944b 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -357,6 +357,11 @@ complex128_eq :: inline proc "contextless" (a, b: complex128) -> bool { return r complex128_ne :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); } +quaternion128_eq :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); } +quaternion128_ne :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); } + +quaternion256_eq :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); } +quaternion256_ne :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); } bounds_check_error :: proc "contextless" (file: string, line, column: int, index, count: int) { @@ -546,9 +551,16 @@ abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 { r, i := real(x), imag(x); return _sqrt_f64(r*r + i*i); } +abs_quaternion128 :: inline proc "contextless" (x: quaternion128) -> f32 { + r, i, j, k := real(x), imag(x), jmag(x), kmag(x); + return _sqrt_f32(r*r + i*i + j*j + k*k); +} +abs_quaternion256 :: inline proc "contextless" (x: quaternion256) -> f64 { + r, i, j, k := real(x), imag(x), jmag(x), kmag(x); + return _sqrt_f64(r*r + i*i + j*j + k*k); +} - -quo_complex64 :: proc(n, m: complex64) -> complex64 { +quo_complex64 :: proc "contextless" (n, m: complex64) -> complex64 { e, f: f32; if abs(real(m)) >= abs(imag(m)) { @@ -566,7 +578,7 @@ quo_complex64 :: proc(n, m: complex64) -> complex64 { return complex(e, f); } -quo_complex128 :: proc(n, m: complex128) -> complex128 { +quo_complex128 :: proc "contextless" (n, m: complex128) -> complex128 { e, f: f64; if abs(real(m)) >= abs(imag(m)) { @@ -583,3 +595,55 @@ quo_complex128 :: proc(n, m: complex128) -> complex128 { return complex(e, f); } + +mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { + q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q); + r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r); + + t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3; + t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2; + t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1; + t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0; + + return quaternion(t0, t1, t2, t3); +} + +mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { + q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q); + r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r); + + t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3; + t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2; + t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1; + t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0; + + return quaternion(t0, t1, t2, t3); +} + +quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { + q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q); + r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r); + + invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3); + + t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2; + t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2; + t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2; + t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2; + + return quaternion(t0, t1, t2, t3); +} + +quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { + q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q); + r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r); + + invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3); + + t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2; + t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2; + t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2; + t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2; + + return quaternion(t0, t1, t2, t3); +} diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 343c50ff7..a96056b61 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -326,7 +326,7 @@ union_type :: proc() { } parametric_polymorphism :: proc() { - fmt.println("# parametric_polymorphism"); + fmt.println("\n# parametric_polymorphism"); print_value :: proc(value: $T) { fmt.printf("print_value: %T %v\n", value, value); @@ -561,7 +561,7 @@ prefix_table := [?]string{ threading_example :: proc() { when os.OS == "windows" { - fmt.println("# threading_example"); + fmt.println("\n# threading_example"); worker_proc :: proc(t: ^thread.Thread) -> int { for iteration in 1..5 { @@ -601,7 +601,7 @@ threading_example :: proc() { } array_programming :: proc() { - fmt.println("# array_programming"); + fmt.println("\n# array_programming"); { a := [3]f32{1, 2, 3}; b := [3]f32{5, 6, 7}; @@ -646,7 +646,7 @@ array_programming :: proc() { } named_proc_return_parameters :: proc() { - fmt.println("# named proc return parameters"); + fmt.println("\n# named proc return parameters"); foo0 :: proc() -> int { return 123; @@ -668,7 +668,7 @@ named_proc_return_parameters :: proc() { using_enum :: proc() { - fmt.println("# using enum"); + fmt.println("\n# using enum"); using Foo :: enum {A, B, C}; @@ -680,7 +680,7 @@ using_enum :: proc() { } map_type :: proc() { - fmt.println("# map type"); + fmt.println("\n# map type"); // enums of type u16, u32, i16 & i32 also work Enum_u8 :: enum u8 { @@ -735,7 +735,7 @@ map_type :: proc() { } implicit_selector_expression :: proc() { - fmt.println("# implicit selector expression"); + fmt.println("\n# implicit selector expression"); Foo :: enum {A, B, C}; @@ -763,7 +763,7 @@ implicit_selector_expression :: proc() { } explicit_procedure_overloading :: proc() { - fmt.println("# explicit procedure overloading"); + fmt.println("\n# explicit procedure overloading"); add_ints :: proc(a, b: int) -> int { x := a + b; @@ -797,7 +797,7 @@ explicit_procedure_overloading :: proc() { } complete_switch :: proc() { - fmt.println("# complete_switch"); + fmt.println("\n# complete_switch"); { // enum using Foo :: enum { A, @@ -947,7 +947,7 @@ deferred_procedure_associations :: proc() { } reflection :: proc() { - fmt.println("# reflection"); + fmt.println("\n# reflection"); Foo :: struct { x: int `tag1`, @@ -981,6 +981,45 @@ reflection :: proc() { } } +quaternions :: proc() { + fmt.println("\n# quaternions"); + + { // Quaternion operations + q := 1 + 2i + 3j + 4k; + r := quaternion(5, 6, 7, 8); + t := q * r; + fmt.printf("(%v) * (%v) = %v\n", q, r, t); + v := q / r; + fmt.printf("(%v) / (%v) = %v\n", q, r, v); + u := q + r; + fmt.printf("(%v) + (%v) = %v\n", q, r, u); + s := q - r; + fmt.printf("(%v) - (%v) = %v\n", q, r, s); + } + { // The quaternion types + q128: quaternion128; // 4xf32 + q256: quaternion256; // 4xf64 + q128 = quaternion(1, 0, 0, 0); + q256 = 1; // quaternion(1, 0, 0, 0); + } + { // Built-in procedures + q := 1 + 2i + 3j + 4k; + fmt.println("q =", q); + fmt.println("real(q) =", real(q)); + fmt.println("imag(q) =", imag(q)); + fmt.println("jmag(q) =", jmag(q)); + fmt.println("kmag(q) =", kmag(q)); + fmt.println("conj(q) =", conj(q)); + fmt.println("abs(q) =", abs(q)); + } + { // Conversion of a complex type to a quaternion type + c := 1 + 2i; + q := quaternion256(c); + fmt.println(c); + fmt.println(q); + } +} + main :: proc() { when true { general_stuff(); @@ -1000,5 +1039,6 @@ main :: proc() { diverging_procedures(); deferred_procedure_associations(); reflection(); + quaternions(); } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 24a130d62..6a9a53275 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -497,6 +497,14 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type if (is_type_complex(dst)) { return 1; } + if (is_type_quaternion(dst)) { + return 2; + } + break; + case Basic_UntypedQuaternion: + if (is_type_quaternion(dst)) { + return 1; + } break; } } @@ -1438,7 +1446,7 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ ExactValue imag = exact_value_imag(v); if (real.kind != ExactValue_Invalid && imag.kind != ExactValue_Invalid) { - if (out_value) *out_value = exact_binary_operator_value(Token_Add, real, exact_value_make_imag(imag)); + if (out_value) *out_value = exact_value_complex(exact_value_to_f64(real), exact_value_to_f64(imag)); return true; } break; @@ -1449,6 +1457,36 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ default: GB_PANIC("Compiler error: Unknown complex type!"); break; } + return false; + } else if (is_type_quaternion(type)) { + ExactValue v = exact_value_to_quaternion(in_value); + if (v.kind != ExactValue_Quaternion) { + return false; + } + + switch (type->Basic.kind) { + case Basic_quaternion128: + case Basic_quaternion256: { + ExactValue real = exact_value_real(v); + ExactValue imag = exact_value_imag(v); + ExactValue jmag = exact_value_jmag(v); + ExactValue kmag = exact_value_kmag(v); + if (real.kind != ExactValue_Invalid && + imag.kind != ExactValue_Invalid) { + if (out_value) *out_value = exact_value_quaternion(exact_value_to_f64(real), exact_value_to_f64(imag), exact_value_to_f64(jmag), exact_value_to_f64(kmag)); + return true; + } + break; + } + case Basic_UntypedComplex: + if (out_value) *out_value = exact_value_to_quaternion(*out_value); + return true; + case Basic_UntypedQuaternion: + return true; + + default: GB_PANIC("Compiler error: Unknown complex type!"); break; + } + return false; } else if (is_type_pointer(type)) { if (in_value.kind == ExactValue_Pointer) { @@ -1481,10 +1519,14 @@ void check_is_expressible(CheckerContext *c, Operand *o, Type *type) { if (!is_type_integer(o->type) && is_type_integer(type)) { error(o->expr, "'%s' truncated to '%s'", a, b); } else { + #if 0 gbAllocator ha = heap_allocator(); String str = big_int_to_string(ha, &o->value.value_integer); defer (gb_free(ha, str.text)); error(o->expr, "'%s = %.*s' overflows '%s'", a, LIT(str), b); + #else + error(o->expr, "Cannot convert '%s' to '%s'", a, b); + #endif } } else { error(o->expr, "Cannot convert '%s' to '%s'", a, b); @@ -1759,6 +1801,21 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) { } break; } + } else if (is_type_quaternion(x->type) || is_type_quaternion(y->type)) { + switch (op) { + case Token_CmpEq: + switch (8*size) { + case 128: add_package_dependency(c, "runtime", "quaternion128_eq"); break; + case 256: add_package_dependency(c, "runtime", "quaternion256_eq"); break; + } + break; + case Token_NotEq: + switch (8*size) { + case 128: add_package_dependency(c, "runtime", "quaternion128_ne"); break; + case 256: add_package_dependency(c, "runtime", "quaternion256_ne"); break; + } + break; + } } } @@ -1978,6 +2035,14 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) { return true; } + if (is_type_complex(src) && is_type_quaternion(dst)) { + return true; + } + + if (is_type_quaternion(src) && is_type_quaternion(dst)) { + return true; + } + if (is_type_bit_field_value(src) && is_type_integer(dst)) { return true; } @@ -2557,6 +2622,8 @@ ExactValue convert_exact_value_for_type(ExactValue v, Type *type) { v = exact_value_to_integer(v); } else if (is_type_complex(t)) { v = exact_value_to_complex(v); + } else if (is_type_quaternion(t)) { + v = exact_value_to_quaternion(v); } return v; } @@ -2652,6 +2719,7 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { case Basic_UntypedInteger: case Basic_UntypedFloat: case Basic_UntypedComplex: + case Basic_UntypedQuaternion: case Basic_UntypedRune: if (!is_type_numeric(target_type)) { operand->mode = Addressing_Invalid; @@ -3769,10 +3837,98 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } + case BuiltinProc_quaternion: { + // quaternion :: proc(real, imag, jmag, kmag: float_type) -> complex_type + Operand x = *operand; + Operand y = {}; + Operand z = {}; + Operand w = {}; + + // NOTE(bill): Invalid will be the default till fixed + operand->type = t_invalid; + operand->mode = Addressing_Invalid; + + check_expr(c, &y, ce->args[1]); + if (y.mode == Addressing_Invalid) { + return false; + } + check_expr(c, &z, ce->args[2]); + if (y.mode == Addressing_Invalid) { + return false; + } + check_expr(c, &w, ce->args[3]); + if (y.mode == Addressing_Invalid) { + return false; + } + + convert_to_typed(c, &x, y.type); if (x.mode == Addressing_Invalid) return false; + convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false; + convert_to_typed(c, &z, x.type); if (z.mode == Addressing_Invalid) return false; + convert_to_typed(c, &w, x.type); if (w.mode == Addressing_Invalid) return false; + if (x.mode == Addressing_Constant && + y.mode == Addressing_Constant && + z.mode == Addressing_Constant && + w.mode == Addressing_Constant) { + if (is_type_numeric(x.type) && exact_value_imag(x.value).value_float == 0) { + x.type = t_untyped_float; + } + if (is_type_numeric(y.type) && exact_value_imag(y.value).value_float == 0) { + y.type = t_untyped_float; + } + if (is_type_numeric(z.type) && exact_value_imag(z.value).value_float == 0) { + z.type = t_untyped_float; + } + if (is_type_numeric(w.type) && exact_value_imag(w.value).value_float == 0) { + w.type = t_untyped_float; + } + } + + if (!(are_types_identical(x.type, y.type) && are_types_identical(x.type, z.type) && are_types_identical(x.type, w.type))) { + gbString tx = type_to_string(x.type); + gbString ty = type_to_string(y.type); + gbString tz = type_to_string(z.type); + gbString tw = type_to_string(w.type); + error(call, "Mismatched types to 'quaternion', '%s' vs '%s' vs '%s' vs '%s'", tx, ty, tz, tw); + gb_string_free(tw); + gb_string_free(tz); + gb_string_free(ty); + gb_string_free(tx); + return false; + } + + if (!is_type_float(x.type)) { + gbString s = type_to_string(x.type); + error(call, "Arguments have type '%s', expected a floating point", s); + gb_string_free(s); + return false; + } + + if (x.mode == Addressing_Constant && y.mode == Addressing_Constant && z.mode == Addressing_Constant && w.mode == Addressing_Constant) { + f64 r = exact_value_to_float(x.value).value_float; + f64 i = exact_value_to_float(y.value).value_float; + f64 j = exact_value_to_float(z.value).value_float; + f64 k = exact_value_to_float(w.value).value_float; + operand->value = exact_value_quaternion(r, i, j, k); + operand->mode = Addressing_Constant; + } else { + operand->mode = Addressing_Value; + } + + BasicKind kind = core_type(x.type)->Basic.kind; + switch (kind) { + case Basic_f32: operand->type = t_quaternion128; break; + case Basic_f64: operand->type = t_quaternion256; break; + case Basic_UntypedFloat: operand->type = t_untyped_quaternion; break; + default: GB_PANIC("Invalid type"); break; + } + + break; + } + case BuiltinProc_real: case BuiltinProc_imag: { // real :: proc(x: type) -> float_type - // proc imag(x: type) -> float_type + // imag :: proc(x: type) -> float_type Operand *x = operand; if (is_type_untyped(x->type)) { @@ -3780,7 +3936,12 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (is_type_numeric(x->type)) { x->type = t_untyped_complex; } - } else { + } else if (is_type_quaternion(x->type)) { + convert_to_typed(c, x, t_quaternion256); + if (x->mode == Addressing_Invalid) { + return false; + } + } else{ convert_to_typed(c, x, t_complex128); if (x->mode == Addressing_Invalid) { return false; @@ -3788,9 +3949,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } } - if (!is_type_complex(x->type)) { + if (!is_type_complex(x->type) && !is_type_quaternion(x->type)) { gbString s = type_to_string(x->type); - error(call, "Argument has type '%s', expected a complex type", s); + error(call, "Argument has type '%s', expected a complex or quaternion type", s); gb_string_free(s); return false; } @@ -3808,7 +3969,57 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 switch (kind) { case Basic_complex64: x->type = t_f32; break; case Basic_complex128: x->type = t_f64; break; + case Basic_quaternion128: x->type = t_f32; break; + case Basic_quaternion256: x->type = t_f64; break; case Basic_UntypedComplex: x->type = t_untyped_float; break; + case Basic_UntypedQuaternion: x->type = t_untyped_float; break; + default: GB_PANIC("Invalid type"); break; + } + + break; + } + + case BuiltinProc_jmag: + case BuiltinProc_kmag: { + // jmag :: proc(x: type) -> float_type + // kmag :: proc(x: type) -> float_type + + Operand *x = operand; + if (is_type_untyped(x->type)) { + if (x->mode == Addressing_Constant) { + if (is_type_numeric(x->type)) { + x->type = t_untyped_complex; + } + } else{ + convert_to_typed(c, x, t_quaternion256); + if (x->mode == Addressing_Invalid) { + return false; + } + } + } + + if (!is_type_quaternion(x->type)) { + gbString s = type_to_string(x->type); + error(call, "Argument has type '%s', expected a quaternion type", s); + gb_string_free(s); + return false; + } + + if (x->mode == Addressing_Constant) { + switch (id) { + case BuiltinProc_jmag: x->value = exact_value_jmag(x->value); break; + case BuiltinProc_kmag: x->value = exact_value_kmag(x->value); break; + } + } else { + x->mode = Addressing_Value; + } + + BasicKind kind = core_type(x->type)->Basic.kind; + switch (kind) { + case Basic_quaternion128: x->type = t_f32; break; + case Basic_quaternion256: x->type = t_f64; break; + case Basic_UntypedComplex: x->type = t_untyped_float; break; + case Basic_UntypedQuaternion: x->type = t_untyped_float; break; default: GB_PANIC("Invalid type"); break; } @@ -3822,12 +4033,24 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (x->mode == Addressing_Constant) { ExactValue v = exact_value_to_complex(x->value); f64 r = v.value_complex.real; - f64 i = v.value_complex.imag; + f64 i = -v.value_complex.imag; x->value = exact_value_complex(r, i); x->mode = Addressing_Constant; } else { x->mode = Addressing_Value; } + } else if (is_type_quaternion(x->type)) { + if (x->mode == Addressing_Constant) { + ExactValue v = exact_value_to_quaternion(x->value); + f64 r = v.value_quaternion.real; + f64 i = -v.value_quaternion.imag; + f64 j = -v.value_quaternion.jmag; + f64 k = -v.value_quaternion.kmag; + x->value = exact_value_quaternion(r, i, j, k); + x->mode = Addressing_Constant; + } else { + x->mode = Addressing_Value; + } } else { gbString s = type_to_string(x->type); error(call, "Expected a complex or quaternion, got '%s'", s); @@ -4226,6 +4449,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (are_types_identical(bt, t_f64)) add_package_dependency(c, "runtime", "abs_f64"); if (are_types_identical(bt, t_complex64)) add_package_dependency(c, "runtime", "abs_complex64"); if (are_types_identical(bt, t_complex128)) add_package_dependency(c, "runtime", "abs_complex128"); + if (are_types_identical(bt, t_quaternion128)) add_package_dependency(c, "runtime", "abs_quaternion128"); + if (are_types_identical(bt, t_quaternion256)) add_package_dependency(c, "runtime", "abs_quaternion256"); } } @@ -6232,8 +6457,11 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case Token_Imag: { String s = bl->token.string; Rune r = s[s.len-1]; + // NOTE(bill, 2019-08-25): Allow for quaternions by having j and k imaginary numbers switch (r) { - case 'i': t = t_untyped_complex; break; + case 'i': t = t_untyped_complex; break; + case 'j': t = t_untyped_quaternion; break; + case 'k': t = t_untyped_quaternion; break; } break; diff --git a/src/checker.cpp b/src/checker.cpp index 45b661a58..d6f5ad402 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1610,6 +1610,10 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("quo_complex64"), str_lit("quo_complex128"), + str_lit("mul_quaternion128"), + str_lit("mul_quaternion256"), + str_lit("quo_quaternion128"), + str_lit("quo_quaternion256"), str_lit("umodti3"), str_lit("udivti3"), @@ -1891,6 +1895,7 @@ void init_core_type_info(Checker *c) { t_type_info_integer = find_core_type(c, str_lit("Type_Info_Integer")); t_type_info_rune = find_core_type(c, str_lit("Type_Info_Rune")); t_type_info_float = find_core_type(c, str_lit("Type_Info_Float")); + t_type_info_quaternion = find_core_type(c, str_lit("Type_Info_Quaternion")); t_type_info_complex = find_core_type(c, str_lit("Type_Info_Complex")); t_type_info_string = find_core_type(c, str_lit("Type_Info_String")); t_type_info_boolean = find_core_type(c, str_lit("Type_Info_Boolean")); @@ -1915,6 +1920,7 @@ void init_core_type_info(Checker *c) { t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer); t_type_info_rune_ptr = alloc_type_pointer(t_type_info_rune); t_type_info_float_ptr = alloc_type_pointer(t_type_info_float); + t_type_info_quaternion_ptr = alloc_type_pointer(t_type_info_quaternion); t_type_info_complex_ptr = alloc_type_pointer(t_type_info_complex); t_type_info_string_ptr = alloc_type_pointer(t_type_info_string); t_type_info_boolean_ptr = alloc_type_pointer(t_type_info_boolean); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 536d47616..0135b3c50 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -16,8 +16,11 @@ enum BuiltinProcId { BuiltinProc_swizzle, BuiltinProc_complex, + BuiltinProc_quaternion, BuiltinProc_real, BuiltinProc_imag, + BuiltinProc_jmag, + BuiltinProc_kmag, BuiltinProc_conj, BuiltinProc_expand_to_tuple, @@ -172,8 +175,11 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("swizzle"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("complex"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("quaternion"), 4, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("real"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("imag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("jmag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("kmag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("expand_to_tuple"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 520812e44..54d4ef6f2 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -12,6 +12,19 @@ bool are_types_identical(Type *x, Type *y); struct Complex128 { f64 real, imag; }; +struct Quaternion256 { + f64 imag, jmag, kmag, real; +}; + +Quaternion256 quaternion256_inverse(Quaternion256 x) { + f64 invmag2 = 1.0 / (x.real*x.real + x.imag*x.imag + x.jmag*x.jmag + x.kmag*x.kmag); + x.real = +x.real * invmag2; + x.imag = -x.imag * invmag2; + x.jmag = -x.jmag * invmag2; + x.kmag = -x.kmag * invmag2; + return x; +} + enum ExactValueKind { ExactValue_Invalid, @@ -21,6 +34,7 @@ enum ExactValueKind { ExactValue_Integer, ExactValue_Float, ExactValue_Complex, + ExactValue_Quaternion, ExactValue_Pointer, ExactValue_Compound, // TODO(bill): Is this good enough? ExactValue_Procedure, // TODO(bill): Is this good enough? @@ -37,6 +51,7 @@ struct ExactValue { f64 value_float; i64 value_pointer; Complex128 value_complex; + Quaternion256 value_quaternion; Ast * value_compound; Ast * value_procedure; }; @@ -61,7 +76,8 @@ HashKey hash_exact_value(ExactValue v) { return hash_integer(v.value_pointer); case ExactValue_Complex: return hashing_proc(&v.value_complex, gb_size_of(Complex128)); - + case ExactValue_Quaternion: + return hashing_proc(&v.value_quaternion, gb_size_of(Quaternion256)); case ExactValue_Compound: return hash_pointer(v.value_compound); case ExactValue_Procedure: @@ -116,6 +132,15 @@ ExactValue exact_value_complex(f64 real, f64 imag) { return result; } +ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) { + ExactValue result = {ExactValue_Quaternion}; + result.value_quaternion.real = real; + result.value_quaternion.imag = imag; + result.value_quaternion.jmag = jmag; + result.value_quaternion.kmag = kmag; + return result; +} + ExactValue exact_value_pointer(i64 ptr) { ExactValue result = {ExactValue_Pointer}; result.value_pointer = ptr; @@ -253,8 +278,10 @@ ExactValue exact_value_from_basic_literal(Token token) { str.len--; // Ignore the 'i|j|k' f64 imag = float_from_string(str); - if (last_rune == 'i') { - return exact_value_complex(0, imag); + switch (last_rune) { + case 'i': return exact_value_complex(0, imag); + case 'j': return exact_value_quaternion(0, 0, imag, 0); + case 'k': return exact_value_quaternion(0, 0, 0, imag); } } case Token_Rune: { @@ -318,11 +345,26 @@ ExactValue exact_value_to_complex(ExactValue v) { return exact_value_complex(v.value_float, 0); case ExactValue_Complex: return v; + // case ExactValue_Quaternion: + // return exact_value_complex(v.value_quaternion.real, v.value_quaternion.imag); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} +ExactValue exact_value_to_quaternion(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + return exact_value_quaternion(big_int_to_f64(&v.value_integer), 0, 0, 0); + case ExactValue_Float: + return exact_value_quaternion(v.value_float, 0, 0, 0); + case ExactValue_Complex: + return exact_value_quaternion(v.value_complex.real, v.value_complex.imag, 0, 0); + case ExactValue_Quaternion: + return v; } ExactValue r = {ExactValue_Invalid}; return r; } - ExactValue exact_value_real(ExactValue v) { switch (v.kind) { @@ -331,6 +373,8 @@ ExactValue exact_value_real(ExactValue v) { return v; case ExactValue_Complex: return exact_value_float(v.value_complex.real); + case ExactValue_Quaternion: + return exact_value_float(v.value_quaternion.real); } ExactValue r = {ExactValue_Invalid}; return r; @@ -343,6 +387,34 @@ ExactValue exact_value_imag(ExactValue v) { return exact_value_i64(0); case ExactValue_Complex: return exact_value_float(v.value_complex.imag); + case ExactValue_Quaternion: + return exact_value_float(v.value_quaternion.imag); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} + +ExactValue exact_value_jmag(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + case ExactValue_Float: + case ExactValue_Complex: + return exact_value_i64(0); + case ExactValue_Quaternion: + return exact_value_float(v.value_quaternion.jmag); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} + +ExactValue exact_value_kmag(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + case ExactValue_Float: + case ExactValue_Complex: + return exact_value_i64(0); + case ExactValue_Quaternion: + return exact_value_float(v.value_quaternion.kmag); } ExactValue r = {ExactValue_Invalid}; return r; @@ -361,6 +433,32 @@ ExactValue exact_value_make_imag(ExactValue v) { return r; } +ExactValue exact_value_make_jmag(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0); + case ExactValue_Float: + return exact_value_quaternion(0, 0, v.value_float, 0); + default: + GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'"); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} + +ExactValue exact_value_make_kmag(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float); + case ExactValue_Float: + return exact_value_quaternion(0, 0, 0, v.value_float); + default: + GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'"); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} + i64 exact_value_to_i64(ExactValue v) { v = exact_value_to_integer(v); if (v.kind == ExactValue_Integer) { @@ -389,6 +487,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision, case ExactValue_Integer: case ExactValue_Float: case ExactValue_Complex: + case ExactValue_Quaternion: return v; } break; @@ -413,6 +512,13 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision, f64 imag = v.value_complex.imag; return exact_value_complex(-real, -imag); } + case ExactValue_Quaternion: { + f64 real = v.value_quaternion.real; + f64 imag = v.value_quaternion.imag; + f64 jmag = v.value_quaternion.jmag; + f64 kmag = v.value_quaternion.kmag; + return exact_value_quaternion(-real, -imag, -jmag, -kmag); + } } break; } @@ -463,8 +569,10 @@ i32 exact_value_order(ExactValue const &v) { return 3; case ExactValue_Complex: return 4; - case ExactValue_Pointer: + case ExactValue_Quaternion: return 5; + case ExactValue_Pointer: + return 6; default: GB_PANIC("How'd you get here? Invalid Value.kind"); @@ -485,7 +593,7 @@ void match_exact_values(ExactValue *x, ExactValue *y) { case ExactValue_Bool: case ExactValue_String: - case ExactValue_Complex: + case ExactValue_Quaternion: return; case ExactValue_Integer: @@ -499,6 +607,9 @@ void match_exact_values(ExactValue *x, ExactValue *y) { case ExactValue_Complex: *x = exact_value_complex(big_int_to_f64(&x->value_integer), 0); return; + case ExactValue_Quaternion: + *x = exact_value_quaternion(big_int_to_f64(&x->value_integer), 0, 0, 0); + return; } break; @@ -509,6 +620,17 @@ void match_exact_values(ExactValue *x, ExactValue *y) { case ExactValue_Complex: *x = exact_value_to_complex(*x); return; + case ExactValue_Quaternion: + *x = exact_value_to_quaternion(*x); + return; + } + break; + + case ExactValue_Complex: + switch (y->kind) { + case ExactValue_Quaternion: + *x = exact_value_to_quaternion(*x); + return; } break; } @@ -606,6 +728,56 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y) break; } + case ExactValue_Quaternion: { + y = exact_value_to_quaternion(y); + f64 xr = x.value_quaternion.real; + f64 xi = x.value_quaternion.imag; + f64 xj = x.value_quaternion.jmag; + f64 xk = x.value_quaternion.kmag; + f64 yr = y.value_quaternion.real; + f64 yi = y.value_quaternion.imag; + f64 yj = y.value_quaternion.jmag; + f64 yk = y.value_quaternion.kmag; + + + f64 real = 0; + f64 imag = 0; + f64 jmag = 0; + f64 kmag = 0; + + switch (op) { + case Token_Add: + real = xr + yr; + imag = xi + yi; + jmag = xj + yj; + kmag = xk + yk; + break; + case Token_Sub: + real = xr - yr; + imag = xi - yi; + jmag = xj - yj; + kmag = xk - yk; + break; + case Token_Mul: + imag = xr * yi + xi * yr + xj * yk - xk * yj; + jmag = xr * yj - xi * yk + xj * yr + xk * yi; + kmag = xr * yk + xi * yj - xj * yi + xk * yr; + real = xr * yr - xi * yi - xj * yj - xk * yk; + break; + case Token_Quo: { + f64 invmag2 = 1.0 / (yr*yr + yi*yi + yj*yj + yk*yk); + imag = (xr * -yi + xi * +yr + xj * -yk - xk * -yj) * invmag2; + jmag = (xr * -yj - xi * -yk + xj * +yr + xk * -yi) * invmag2; + kmag = (xr * -yk + xi * -yj - xj * -yi + xk * +yr) * invmag2; + real = (xr * +yr - xi * -yi - xj * -yj - xk * -yk) * invmag2; + break; + } + default: goto error; + } + return exact_value_quaternion(real, imag, jmag, kmag); + break; + } + case ExactValue_String: { if (op != Token_Add) goto error; diff --git a/src/ir.cpp b/src/ir.cpp index 2499b848f..2a4bb028b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3853,6 +3853,60 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * return ir_emit_load(proc, res); } + if (is_type_quaternion(t_left)) { + ir_emit_comment(proc, str_lit("complex.arith.begin")); + defer (ir_emit_comment(proc, str_lit("complex.arith.end"))); + + right = ir_emit_conv(proc, right, t_left); + + Type *ft = base_complex_elem_type(t_left); + + if (op == Token_Add || op == Token_Sub) { + irValue *res = ir_add_local_generated(proc, type, false); // NOTE: initialized in full later + irValue *x0 = ir_emit_struct_ev(proc, left, 0); + irValue *x1 = ir_emit_struct_ev(proc, left, 1); + irValue *x2 = ir_emit_struct_ev(proc, left, 2); + irValue *x3 = ir_emit_struct_ev(proc, left, 3); + + irValue *y0 = ir_emit_struct_ev(proc, right, 0); + irValue *y1 = ir_emit_struct_ev(proc, right, 1); + irValue *y2 = ir_emit_struct_ev(proc, right, 2); + irValue *y3 = ir_emit_struct_ev(proc, right, 3); + + irValue *z0 = ir_emit_arith(proc, op, x0, y0, ft); + irValue *z1 = ir_emit_arith(proc, op, x1, y1, ft); + irValue *z2 = ir_emit_arith(proc, op, x2, y2, ft); + irValue *z3 = ir_emit_arith(proc, op, x3, y3, ft); + + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), z0); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), z1); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 2), z2); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 3), z3); + + return ir_emit_load(proc, res); + } else if (op == Token_Mul) { + auto args = array_make(heap_allocator(), 2); + args[0] = left; + args[1] = right; + + switch (8*type_size_of(ft)) { + case 32: return ir_emit_runtime_call(proc, "mul_quaternion128", args); + case 64: return ir_emit_runtime_call(proc, "mul_quaternion256", args); + default: GB_PANIC("Unknown float type"); break; + } + } else if (op == Token_Quo) { + auto args = array_make(heap_allocator(), 2); + args[0] = left; + args[1] = right; + + switch (8*type_size_of(ft)) { + case 32: return ir_emit_runtime_call(proc, "quo_quaternion128", args); + case 64: return ir_emit_runtime_call(proc, "quo_quaternion256", args); + default: GB_PANIC("Unknown float type"); break; + } + } + } + #if 0 if (op == Token_Add) { @@ -4188,7 +4242,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal } if (is_type_complex(a)) { - char *runtime_proc = ""; + char const *runtime_proc = ""; i64 sz = 8*type_size_of(a); switch (sz) { case 64: @@ -4212,6 +4266,31 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal return ir_emit_runtime_call(proc, runtime_proc, args); } + if (is_type_quaternion(a)) { + char const *runtime_proc = ""; + i64 sz = 8*type_size_of(a); + switch (sz) { + case 128: + switch (op_kind) { + case Token_CmpEq: runtime_proc = "quaternion128_eq"; break; + case Token_NotEq: runtime_proc = "quaternion128_ne"; break; + } + break; + case 256: + switch (op_kind) { + case Token_CmpEq: runtime_proc = "quaternion256_eq"; break; + case Token_NotEq: runtime_proc = "quaternion256_ne"; break; + } + break; + } + GB_ASSERT(runtime_proc != nullptr); + + auto args = array_make(ir_allocator(), 2); + args[0] = left; + args[1] = right; + return ir_emit_runtime_call(proc, runtime_proc, args); + } + if (is_type_bit_set(a)) { switch (op_kind) { case Token_Lt: @@ -4295,11 +4374,18 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) { case 0: result_type = alloc_type_pointer(ft); break; case 1: result_type = alloc_type_pointer(ft); break; } + } else if (is_type_quaternion(t)) { + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = alloc_type_pointer(ft); break; + case 1: result_type = alloc_type_pointer(ft); break; + case 2: result_type = alloc_type_pointer(ft); break; + case 3: result_type = alloc_type_pointer(ft); break; + } } else if (is_type_slice(t)) { switch (index) { case 0: result_type = alloc_type_pointer(alloc_type_pointer(t->Slice.elem)); break; case 1: result_type = alloc_type_pointer(t_int); break; - case 2: result_type = alloc_type_pointer(t_int); break; } } else if (is_type_string(t)) { switch (index) { @@ -4370,6 +4456,17 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) { } break; } + case Basic_quaternion128: case Basic_quaternion256: + { + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = ft; break; + case 1: result_type = ft; break; + case 2: result_type = ft; break; + case 3: result_type = ft; break; + } + break; + } } break; case Type_Struct: @@ -4752,6 +4849,8 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { ev = exact_value_to_float(ev); } else if (is_type_complex(dst)) { ev = exact_value_to_complex(ev); + } else if (is_type_quaternion(dst)) { + ev = exact_value_to_quaternion(ev); } else if (is_type_string(dst)) { // Handled elsewhere GB_ASSERT_MSG(ev.kind == ExactValue_String, "%d", ev.kind); @@ -4875,6 +4974,49 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { return ir_emit_load(proc, gen); } + if (is_type_quaternion(src) && is_type_quaternion(dst)) { + // @QuaternionLayout + Type *ft = base_complex_elem_type(dst); + irValue *gen = ir_add_local_generated(proc, dst, false); + irValue *q0 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 0), ft); + irValue *q1 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 1), ft); + irValue *q2 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 2), ft); + irValue *q3 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 3), ft); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), q0); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 1), q1); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 2), q2); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), q3); + return ir_emit_load(proc, gen); + } + + if (is_type_float(src) && is_type_complex(dst)) { + Type *ft = base_complex_elem_type(dst); + irValue *gen = ir_add_local_generated(proc, dst, true); + irValue *real = ir_emit_conv(proc, value, ft); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), real); + return ir_emit_load(proc, gen); + } + if (is_type_float(src) && is_type_quaternion(dst)) { + Type *ft = base_complex_elem_type(dst); + irValue *gen = ir_add_local_generated(proc, dst, true); + irValue *real = ir_emit_conv(proc, value, ft); + // @QuaternionLayout + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), real); + return ir_emit_load(proc, gen); + } + if (is_type_complex(src) && is_type_quaternion(dst)) { + Type *ft = base_complex_elem_type(dst); + irValue *gen = ir_add_local_generated(proc, dst, true); + irValue *real = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 0), ft); + irValue *imag = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 1), ft); + // @QuaternionLayout + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), imag); + return ir_emit_load(proc, gen); + } + + + // float <-> integer if (is_type_float(src) && is_type_integer(dst)) { irConvKind kind = irConv_fptosi; @@ -5315,6 +5457,7 @@ enum Typeid_Kind : u8 { Typeid_Rune, Typeid_Float, Typeid_Complex, + Typeid_Quaternion, Typeid_String, Typeid_Boolean, Typeid_Any, @@ -6067,17 +6210,77 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu return ir_emit_load(proc, dst); } + case BuiltinProc_quaternion: { + ir_emit_comment(proc, str_lit("quaternion")); + irValue *real = ir_build_expr(proc, ce->args[0]); + irValue *imag = ir_build_expr(proc, ce->args[1]); + irValue *jmag = ir_build_expr(proc, ce->args[2]); + irValue *kmag = ir_build_expr(proc, ce->args[3]); + + // @QuaternionLayout + irValue *dst = ir_add_local_generated(proc, tv.type, false); + Type *ft = base_complex_elem_type(tv.type); + real = ir_emit_conv(proc, real, ft); + imag = ir_emit_conv(proc, imag, ft); + jmag = ir_emit_conv(proc, jmag, ft); + kmag = ir_emit_conv(proc, kmag, ft); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 3), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 0), imag); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 1), jmag); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 2), kmag); + + return ir_emit_load(proc, dst); + } + case BuiltinProc_real: { ir_emit_comment(proc, str_lit("real")); irValue *val = ir_build_expr(proc, ce->args[0]); - irValue *real = ir_emit_struct_ev(proc, val, 0); - return ir_emit_conv(proc, real, tv.type); + if (is_type_complex(ir_type(val))) { + irValue *real = ir_emit_struct_ev(proc, val, 0); + return ir_emit_conv(proc, real, tv.type); + } else if (is_type_quaternion(ir_type(val))) { + // @QuaternionLayout + irValue *real = ir_emit_struct_ev(proc, val, 3); + return ir_emit_conv(proc, real, tv.type); + } + GB_PANIC("invalid type for real"); + return nullptr; } case BuiltinProc_imag: { ir_emit_comment(proc, str_lit("imag")); irValue *val = ir_build_expr(proc, ce->args[0]); - irValue *imag = ir_emit_struct_ev(proc, val, 1); - return ir_emit_conv(proc, imag, tv.type); + if (is_type_complex(ir_type(val))) { + irValue *imag = ir_emit_struct_ev(proc, val, 1); + return ir_emit_conv(proc, imag, tv.type); + } else if (is_type_quaternion(ir_type(val))) { + // @QuaternionLayout + irValue *imag = ir_emit_struct_ev(proc, val, 0); + return ir_emit_conv(proc, imag, tv.type); + } + GB_PANIC("invalid type for imag"); + return nullptr; + } + case BuiltinProc_jmag: { + ir_emit_comment(proc, str_lit("jmag")); + irValue *val = ir_build_expr(proc, ce->args[0]); + if (is_type_quaternion(ir_type(val))) { + // @QuaternionLayout + irValue *imag = ir_emit_struct_ev(proc, val, 1); + return ir_emit_conv(proc, imag, tv.type); + } + GB_PANIC("invalid type for jmag"); + return nullptr; + } + case BuiltinProc_kmag: { + ir_emit_comment(proc, str_lit("kmag")); + irValue *val = ir_build_expr(proc, ce->args[0]); + if (is_type_quaternion(ir_type(val))) { + // @QuaternionLayout + irValue *imag = ir_emit_struct_ev(proc, val, 2); + return ir_emit_conv(proc, imag, tv.type); + } + GB_PANIC("invalid type for kmag"); + return nullptr; } case BuiltinProc_conj: { @@ -6092,6 +6295,20 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu imag = ir_emit_unary_arith(proc, Token_Sub, imag, ir_type(imag)); ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), real); ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), imag); + } else if (is_type_quaternion(t)) { + // @QuaternionLayout + res = ir_add_local_generated(proc, tv.type, false); + irValue *real = ir_emit_struct_ev(proc, val, 3); + irValue *imag = ir_emit_struct_ev(proc, val, 0); + irValue *jmag = ir_emit_struct_ev(proc, val, 1); + irValue *kmag = ir_emit_struct_ev(proc, val, 2); + imag = ir_emit_unary_arith(proc, Token_Sub, imag, ir_type(imag)); + jmag = ir_emit_unary_arith(proc, Token_Sub, jmag, ir_type(jmag)); + kmag = ir_emit_unary_arith(proc, Token_Sub, kmag, ir_type(kmag)); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 3), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), imag); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), jmag); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 2), kmag); } return ir_emit_load(proc, res); } @@ -6162,7 +6379,16 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu return x; } ir_emit_comment(proc, str_lit("abs")); - if (is_type_complex(t)) { + if (is_type_quaternion(t)) { + i64 sz = 8*type_size_of(t); + auto args = array_make(ir_allocator(), 1); + args[0] = x; + switch (sz) { + case 128: return ir_emit_runtime_call(proc, "abs_quaternion128", args); + case 256: return ir_emit_runtime_call(proc, "abs_quaternion256", args); + } + GB_PANIC("Unknown complex type"); + } else if (is_type_complex(t)) { i64 sz = 8*type_size_of(t); auto args = array_make(ir_allocator(), 1); args[0] = x; @@ -9876,6 +10102,11 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info tag = ir_emit_conv(proc, variant_ptr, t_type_info_complex_ptr); break; + case Basic_quaternion128: + case Basic_quaternion256: + tag = ir_emit_conv(proc, variant_ptr, t_type_info_quaternion_ptr); + break; + case Basic_rawptr: tag = ir_emit_conv(proc, variant_ptr, t_type_info_pointer_ptr); break; diff --git a/src/ir_print.cpp b/src/ir_print.cpp index c1e41c4b0..30ad914a9 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -418,20 +418,23 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) { } return; - // case Basic_f16: ir_write_str_lit(f, "half"); return; - case Basic_f32: ir_write_str_lit(f, "float"); return; - case Basic_f64: ir_write_str_lit(f, "double"); return; + // case Basic_f16: ir_write_str_lit(f, "half"); return; + case Basic_f32: ir_write_str_lit(f, "float"); return; + case Basic_f64: ir_write_str_lit(f, "double"); return; - // case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return; - case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return; - case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return; + // case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return; + case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return; + case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return; - case Basic_any: ir_write_str_lit(f, "%..any"); return; - case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return; - case Basic_string: ir_write_str_lit(f, "%..string"); return; - case Basic_cstring: ir_write_str_lit(f, "i8*"); return; + case Basic_quaternion128: ir_write_str_lit(f, "%..quaternion128"); return; + case Basic_quaternion256: ir_write_str_lit(f, "%..quaternion256"); return; - case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return; + case Basic_any: ir_write_str_lit(f, "%..any"); return; + case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return; + case Basic_string: ir_write_str_lit(f, "%..string"); return; + case Basic_cstring: ir_write_str_lit(f, "i8*"); return; + + case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return; } break; @@ -811,6 +814,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * break; } case ExactValue_Complex: { + // xy/ri format type = core_type(type); GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type)); Type *ft = base_complex_elem_type(type); @@ -823,6 +827,26 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * ir_write_byte(f, '}'); break; } + + case ExactValue_Quaternion: { + // xyzw/ijkr format + type = core_type(type); + GB_ASSERT_MSG(is_type_quaternion(type), "%s", type_to_string(type)); + Type *ft = base_complex_elem_type(type); + ir_write_byte(f, ' '); + ir_write_byte(f, '{'); + ir_print_type(f, m, ft); ir_write_byte(f, ' '); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.imag), ft); + ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' '); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.jmag), ft); + ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' '); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.kmag), ft); + ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' '); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.real), ft); + ir_write_byte(f, '}'); + break; + } + case ExactValue_Pointer: if (value.value_pointer == 0) { if (is_type_typeid(type)) { @@ -2246,6 +2270,13 @@ void print_llvm_ir(irGen *ir) { ir_print_encoded_local(f, str_lit("..complex128")); ir_write_str_lit(f, " = type {double, double} ; Basic_complex128\n"); + ir_print_encoded_local(f, str_lit("..quaternion64")); + ir_write_str_lit(f, " = type {half, half, half, half} ; Basic_quaternion64\n"); + ir_print_encoded_local(f, str_lit("..quaternion128")); + ir_write_str_lit(f, " = type {float, float, float, float} ; Basic_quaternion128\n"); + ir_print_encoded_local(f, str_lit("..quaternion256")); + ir_write_str_lit(f, " = type {double, double, double, double} ; Basic_quaternion256\n"); + ir_print_encoded_local(f, str_lit("..typeid")); ir_write_str_lit(f, " = type "); ir_print_type(f, m, t_uintptr); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index a551f0545..5ba402858 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -745,7 +745,10 @@ exponent: scan_mantissa(t, 10); } - if (t->curr_rune == 'i') { + switch (t->curr_rune) { + case 'i': + case 'j': + case 'k': token.kind = Token_Imag; advance_to_next_rune(t); } diff --git a/src/types.cpp b/src/types.cpp index b5c9152b6..94b89d8f5 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -32,6 +32,9 @@ enum BasicKind { Basic_complex64, Basic_complex128, + Basic_quaternion128, + Basic_quaternion256, + Basic_int, Basic_uint, Basic_uintptr, @@ -66,6 +69,7 @@ enum BasicKind { Basic_UntypedInteger, Basic_UntypedFloat, Basic_UntypedComplex, + Basic_UntypedQuaternion, Basic_UntypedString, Basic_UntypedRune, Basic_UntypedNil, @@ -82,17 +86,18 @@ enum BasicFlag { BasicFlag_Unsigned = GB_BIT(2), BasicFlag_Float = GB_BIT(3), BasicFlag_Complex = GB_BIT(4), - BasicFlag_Pointer = GB_BIT(5), - BasicFlag_String = GB_BIT(6), - BasicFlag_Rune = GB_BIT(7), - BasicFlag_Untyped = GB_BIT(8), + BasicFlag_Quaternion = GB_BIT(5), + BasicFlag_Pointer = GB_BIT(6), + BasicFlag_String = GB_BIT(7), + BasicFlag_Rune = GB_BIT(8), + BasicFlag_Untyped = GB_BIT(9), - BasicFlag_LLVM = GB_BIT(10), + BasicFlag_LLVM = GB_BIT(11), BasicFlag_EndianLittle = GB_BIT(13), BasicFlag_EndianBig = GB_BIT(14), - BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex, + BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex | BasicFlag_Quaternion, BasicFlag_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune, BasicFlag_OrderedNumeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Rune, BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune, @@ -342,6 +347,9 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}}, {Type_Basic, {Basic_complex128, BasicFlag_Complex, 16, STR_LIT("complex128")}}, + {Type_Basic, {Basic_quaternion128, BasicFlag_Quaternion, 16, STR_LIT("quaternion128")}}, + {Type_Basic, {Basic_quaternion256, BasicFlag_Quaternion, 32, STR_LIT("quaternion256")}}, + {Type_Basic, {Basic_int, BasicFlag_Integer, -1, STR_LIT("int")}}, {Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}}, {Type_Basic, {Basic_uintptr, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uintptr")}}, @@ -377,6 +385,7 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped integer")}}, {Type_Basic, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, 0, STR_LIT("untyped float")}}, {Type_Basic, {Basic_UntypedComplex, BasicFlag_Complex | BasicFlag_Untyped, 0, STR_LIT("untyped complex")}}, + {Type_Basic, {Basic_UntypedQuaternion, BasicFlag_Quaternion | BasicFlag_Untyped, 0, STR_LIT("untyped quaternion")}}, {Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}}, {Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}}, {Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}}, @@ -412,6 +421,9 @@ gb_global Type *t_f64 = &basic_types[Basic_f64]; gb_global Type *t_complex64 = &basic_types[Basic_complex64]; gb_global Type *t_complex128 = &basic_types[Basic_complex128]; +gb_global Type *t_quaternion128 = &basic_types[Basic_quaternion128]; +gb_global Type *t_quaternion256 = &basic_types[Basic_quaternion256]; + gb_global Type *t_int = &basic_types[Basic_int]; gb_global Type *t_uint = &basic_types[Basic_uint]; gb_global Type *t_uintptr = &basic_types[Basic_uintptr]; @@ -446,6 +458,7 @@ gb_global Type *t_untyped_bool = &basic_types[Basic_UntypedBool]; gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger]; gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat]; gb_global Type *t_untyped_complex = &basic_types[Basic_UntypedComplex]; +gb_global Type *t_untyped_quaternion = &basic_types[Basic_UntypedQuaternion]; gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString]; gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune]; gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil]; @@ -472,6 +485,7 @@ gb_global Type *t_type_info_integer = nullptr; gb_global Type *t_type_info_rune = nullptr; gb_global Type *t_type_info_float = nullptr; gb_global Type *t_type_info_complex = nullptr; +gb_global Type *t_type_info_quaternion = nullptr; gb_global Type *t_type_info_any = nullptr; gb_global Type *t_type_info_typeid = nullptr; gb_global Type *t_type_info_string = nullptr; @@ -496,6 +510,7 @@ gb_global Type *t_type_info_integer_ptr = nullptr; gb_global Type *t_type_info_rune_ptr = nullptr; gb_global Type *t_type_info_float_ptr = nullptr; gb_global Type *t_type_info_complex_ptr = nullptr; +gb_global Type *t_type_info_quaternion_ptr = nullptr; gb_global Type *t_type_info_any_ptr = nullptr; gb_global Type *t_type_info_typeid_ptr = nullptr; gb_global Type *t_type_info_string_ptr = nullptr; @@ -924,6 +939,13 @@ bool is_type_complex(Type *t) { } return false; } +bool is_type_quaternion(Type *t) { + t = core_type(t); + if (t->kind == Type_Basic) { + return (t->Basic.flags & BasicFlag_Quaternion) != 0; + } + return false; +} bool is_type_f32(Type *t) { t = core_type(t); if (t->kind == Type_Basic) { @@ -1063,12 +1085,15 @@ bool is_type_simple_compare(Type *t) { Type *base_complex_elem_type(Type *t) { t = core_type(t); - if (is_type_complex(t)) { + if (t->kind == Type_Basic) { switch (t->Basic.kind) { - // case Basic_complex32: return t_f16; - case Basic_complex64: return t_f32; - case Basic_complex128: return t_f64; - case Basic_UntypedComplex: return t_untyped_float; + // case Basic_complex32: return t_f16; + case Basic_complex64: return t_f32; + case Basic_complex128: return t_f64; + case Basic_quaternion128: return t_f32; + case Basic_quaternion256: return t_f64; + case Basic_UntypedComplex: return t_untyped_float; + case Basic_UntypedQuaternion: return t_untyped_float; } } GB_PANIC("Invalid complex type"); @@ -1818,6 +1843,7 @@ Type *default_type(Type *type) { case Basic_UntypedInteger: return t_int; case Basic_UntypedFloat: return t_f64; case Basic_UntypedComplex: return t_complex128; + case Basic_UntypedQuaternion: return t_quaternion256; case Basic_UntypedString: return t_string; case Basic_UntypedRune: return t_rune; } @@ -2358,6 +2384,8 @@ i64 type_align_of_internal(Type *t, TypePath *path) { case Basic_complex64: case Basic_complex128: return type_size_of_internal(t, path) / 2; + case Basic_quaternion128: case Basic_quaternion256: + return type_size_of_internal(t, path) / 4; } } break; From 4908d1ebdd00a8822d9ef59245f2456db4b6dbfc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 26 Aug 2019 11:56:04 +0100 Subject: [PATCH 035/143] Update odin_tokenizer to support quaternion literals --- core/odin/tokenizer/tokenizer.odin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/odin/tokenizer/tokenizer.odin b/core/odin/tokenizer/tokenizer.odin index 764fe6e34..b29ac700d 100644 --- a/core/odin/tokenizer/tokenizer.odin +++ b/core/odin/tokenizer/tokenizer.odin @@ -343,7 +343,8 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str } // NOTE(bill): This needs to be here for sanity's sake - if t.ch == 'i' { + switch t.ch { + case 'i', 'j', 'k': kind^ = token.Imag; advance_rune(t); } From 01c10aa9447d135bdda5dc25583a5e1f94cbda6d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 26 Aug 2019 13:54:35 +0100 Subject: [PATCH 036/143] `inline for` loops (only for 'in' based for loops) --- examples/demo/demo.odin | 39 ++++++ src/check_stmt.cpp | 272 +++++++++++++++++++++++++++++++++++++--- src/checker.hpp | 3 + src/exact_value.cpp | 4 + src/ir.cpp | 144 +++++++++++++++++++++ src/parser.cpp | 83 +++++++++++- src/parser.hpp | 9 ++ 7 files changed, 530 insertions(+), 24 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index a96056b61..cef814a56 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1018,6 +1018,44 @@ quaternions :: proc() { fmt.println(c); fmt.println(q); } + { // Memory layout of Quaternions + q := 1 + 2i + 3j + 4k; + a := transmute([4]f64)q; + fmt.println("Quaternion memory layout: xyzw/(ijkr)"); + fmt.println(q); // 1.000+2.000i+3.000j+4.000k + fmt.println(a); // [2.000, 3.000, 4.000, 1.000] + } +} + +inline_for_statement :: proc() { + fmt.println("\n#inline for statements"); + + fmt.println("Ranges"); + inline for x, i in 1..<4 { + fmt.println(x, i); + } + + fmt.println("Strings"); + inline for r, i in "Hello, 世界" { + fmt.println(r, i); + } + + fmt.println("Arrays"); + inline for elem, idx in ([4]int{1, 4, 9, 16}) { + fmt.println(elem, idx); + } + + + Foo_Enum :: enum { + A = 1, + B, + C = 6, + D, + } + fmt.println("Enum types"); + inline for elem, idx in Foo_Enum { + fmt.println(elem, idx); + } } main :: proc() { @@ -1040,5 +1078,6 @@ main :: proc() { deferred_procedure_associations(); reflection(); quaternions(); + inline_for_statement(); } } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 2787aa436..88661558d 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -132,6 +132,10 @@ bool check_is_terminating(Ast *node) { } case_end; + case_ast_node(rs, InlineRangeStmt, node); + return false; + case_end; + case_ast_node(rs, RangeStmt, node); return false; case_end; @@ -587,6 +591,236 @@ void add_constant_switch_case(CheckerContext *ctx, Map *seen, Oper multi_map_insert(seen, key, tap); } +void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { + ast_node(irs, InlineRangeStmt, node); + check_open_scope(ctx, node); + + Type *val0 = nullptr; + Type *val1 = nullptr; + Entity *entities[2] = {}; + isize entity_count = 0; + + Ast *expr = unparen_expr(irs->expr); + + ExactValue inline_for_depth = exact_value_i64(0); + + if (is_ast_range(expr)) { + ast_node(ie, BinaryExpr, expr); + Operand x = {Addressing_Invalid}; + Operand y = {Addressing_Invalid}; + + check_expr(ctx, &x, ie->left); + if (x.mode == Addressing_Invalid) { + goto skip_expr; + } + check_expr(ctx, &y, ie->right); + if (y.mode == Addressing_Invalid) { + goto skip_expr; + } + + convert_to_typed(ctx, &x, y.type); + if (x.mode == Addressing_Invalid) { + goto skip_expr; + } + convert_to_typed(ctx, &y, x.type); + if (y.mode == Addressing_Invalid) { + goto skip_expr; + } + + convert_to_typed(ctx, &x, default_type(y.type)); + if (x.mode == Addressing_Invalid) { + goto skip_expr; + } + convert_to_typed(ctx, &y, default_type(x.type)); + if (y.mode == Addressing_Invalid) { + goto skip_expr; + } + + if (!are_types_identical(x.type, y.type)) { + if (x.type != t_invalid && + y.type != t_invalid) { + gbString xt = type_to_string(x.type); + gbString yt = type_to_string(y.type); + gbString expr_str = expr_to_string(x.expr); + error(ie->op, "Mismatched types in interval expression '%s' : '%s' vs '%s'", expr_str, xt, yt); + gb_string_free(expr_str); + gb_string_free(yt); + gb_string_free(xt); + } + goto skip_expr; + } + + Type *type = x.type; + if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) { + error(ie->op, "Only numerical and pointer types are allowed within interval expressions"); + goto skip_expr; + } + + if (x.mode == Addressing_Constant && + y.mode == Addressing_Constant) { + ExactValue a = x.value; + ExactValue b = y.value; + + GB_ASSERT(are_types_identical(x.type, y.type)); + + TokenKind op = Token_Lt; + switch (ie->op.kind) { + case Token_Ellipsis: op = Token_LtEq; break; + case Token_RangeHalf: op = Token_Lt; break; + default: error(ie->op, "Invalid range operator"); break; + } + bool ok = compare_exact_values(op, a, b); + if (!ok) { + // TODO(bill): Better error message + error(ie->op, "Invalid interval range"); + goto skip_expr; + } + + inline_for_depth = exact_value_sub(b, a); + if (ie->op.kind == Token_Ellipsis) { + inline_for_depth = exact_value_increment_one(inline_for_depth); + } + + } else { + error(ie->op, "Interval expressions must be constant"); + goto skip_expr; + } + + add_type_and_value(&ctx->checker->info, ie->left, x.mode, x.type, x.value); + add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value); + val0 = type; + val1 = t_int; + } else { + Operand operand = {Addressing_Invalid}; + check_expr_or_type(ctx, &operand, irs->expr); + + if (operand.mode == Addressing_Type) { + if (!is_type_enum(operand.type)) { + gbString t = type_to_string(operand.type); + error(operand.expr, "Cannot iterate over the type '%s'", t); + gb_string_free(t); + goto skip_expr; + } else { + val0 = operand.type; + val1 = t_int; + add_type_info_type(ctx, operand.type); + + Type *bt = base_type(operand.type); + inline_for_depth = exact_value_i64(bt->Enum.fields.count); + goto skip_expr; + } + } else if (operand.mode != Addressing_Invalid) { + Type *t = base_type(operand.type); + switch (t->kind) { + case Type_Basic: + if (is_type_string(t) && t->Basic.kind != Basic_cstring) { + val0 = t_rune; + val1 = t_int; + inline_for_depth = exact_value_i64(operand.value.value_string.len); + } + break; + case Type_Array: + val0 = t->Array.elem; + val1 = t_int; + inline_for_depth = exact_value_i64(t->Array.count); + break; + } + } + + if (val0 == nullptr) { + gbString s = expr_to_string(operand.expr); + gbString t = type_to_string(operand.type); + error(operand.expr, "Cannot iterate over '%s' of type '%s' in an 'inline for' statement", s, t); + gb_string_free(t); + gb_string_free(s); + } else if (operand.mode != Addressing_Constant) { + error(operand.expr, "An 'inline for' expression must be known at compile time"); + } + } + + skip_expr:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird. + + Ast * lhs[2] = {irs->val0, irs->val1}; + Type *rhs[2] = {val0, val1}; + + for (isize i = 0; i < 2; i++) { + if (lhs[i] == nullptr) { + continue; + } + Ast * name = lhs[i]; + Type *type = rhs[i]; + + Entity *entity = nullptr; + if (name->kind == Ast_Ident) { + Token token = name->Ident.token; + String str = token.string; + Entity *found = nullptr; + + if (!is_blank_ident(str)) { + found = scope_lookup_current(ctx->scope, str); + } + if (found == nullptr) { + bool is_immutable = true; + entity = alloc_entity_variable(ctx->scope, token, type, is_immutable, EntityState_Resolved); + entity->flags |= EntityFlag_Value; + add_entity_definition(&ctx->checker->info, name, entity); + } else { + TokenPos pos = found->token.pos; + error(token, + "Redeclaration of '%.*s' in this scope\n" + "\tat %.*s(%td:%td)", + LIT(str), LIT(pos.file), pos.line, pos.column); + entity = found; + } + } else { + error(name, "A variable declaration must be an identifier"); + } + + if (entity == nullptr) { + entity = alloc_entity_dummy_variable(builtin_pkg->scope, ast_token(name)); + } + + entities[entity_count++] = entity; + + if (type == nullptr) { + entity->type = t_invalid; + entity->flags |= EntityFlag_Used; + } + } + + for (isize i = 0; i < entity_count; i++) { + add_entity(ctx->checker, ctx->scope, entities[i]->identifier, entities[i]); + } + + + // NOTE(bill): Minimize the amount of nesting of an 'inline for' + i64 prev_inline_for_depth = ctx->inline_for_depth; + defer (ctx->inline_for_depth = prev_inline_for_depth); + { + i64 v = exact_value_to_i64(inline_for_depth); + if (v <= 0) { + // Do nothing + } else { + ctx->inline_for_depth = gb_max(ctx->inline_for_depth, 1) * v; + } + + if (ctx->inline_for_depth >= MAX_INLINE_FOR_DEPTH && prev_inline_for_depth < MAX_INLINE_FOR_DEPTH) { + if (prev_inline_for_depth > 0) { + error(node, "Nested 'inline for' loop cannot be inlined as it exceeds the maximum inline for depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH); + } else { + error(node, "'inline for' loop cannot be inlined as it exceeds the maximum inline for depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH); + } + error_line("\tUse a normal 'for' loop instead by removing the 'inline' prefix\n"); + ctx->inline_for_depth = MAX_INLINE_FOR_DEPTH; + } + } + + check_stmt(ctx, irs->body, mod_flags); + + + check_close_scope(ctx); +} + void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { ast_node(ss, SwitchStmt, node); @@ -1298,6 +1532,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { check_close_scope(ctx); case_end; + case_ast_node(rs, RangeStmt, node); u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed; @@ -1320,29 +1555,29 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { check_expr(ctx, &x, ie->left); if (x.mode == Addressing_Invalid) { - goto skip_expr; + goto skip_expr_range_stmt; } check_expr(ctx, &y, ie->right); if (y.mode == Addressing_Invalid) { - goto skip_expr; + goto skip_expr_range_stmt; } convert_to_typed(ctx, &x, y.type); if (x.mode == Addressing_Invalid) { - goto skip_expr; + goto skip_expr_range_stmt; } convert_to_typed(ctx, &y, x.type); if (y.mode == Addressing_Invalid) { - goto skip_expr; + goto skip_expr_range_stmt; } convert_to_typed(ctx, &x, default_type(y.type)); if (x.mode == Addressing_Invalid) { - goto skip_expr; + goto skip_expr_range_stmt; } convert_to_typed(ctx, &y, default_type(x.type)); if (y.mode == Addressing_Invalid) { - goto skip_expr; + goto skip_expr_range_stmt; } if (!are_types_identical(x.type, y.type)) { @@ -1356,13 +1591,13 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { gb_string_free(yt); gb_string_free(xt); } - goto skip_expr; + goto skip_expr_range_stmt; } Type *type = x.type; if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) { error(ie->op, "Only numerical and pointer types are allowed within interval expressions"); - goto skip_expr; + goto skip_expr_range_stmt; } if (x.mode == Addressing_Constant && @@ -1382,18 +1617,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { if (!ok) { // TODO(bill): Better error message error(ie->op, "Invalid interval range"); - goto skip_expr; + goto skip_expr_range_stmt; } } - if (x.mode != Addressing_Constant) { - x.value = empty_exact_value; - } - if (y.mode != Addressing_Constant) { - y.value = empty_exact_value; - } - - add_type_and_value(&ctx->checker->info, ie->left, x.mode, x.type, x.value); add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value); val0 = type; @@ -1407,12 +1634,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { gbString t = type_to_string(operand.type); error(operand.expr, "Cannot iterate over the type '%s'", t); gb_string_free(t); - goto skip_expr; + goto skip_expr_range_stmt; } else { val0 = operand.type; val1 = t_int; add_type_info_type(ctx, operand.type); - goto skip_expr; + goto skip_expr_range_stmt; } } else if (operand.mode != Addressing_Invalid) { bool is_ptr = is_type_pointer(operand.type); @@ -1457,7 +1684,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { } } - skip_expr:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird. + skip_expr_range_stmt:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird. + Ast * lhs[2] = {rs->val0, rs->val1}; Type *rhs[2] = {val0, val1}; @@ -1515,6 +1743,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { check_close_scope(ctx); case_end; + case_ast_node(irs, InlineRangeStmt, node); + check_inline_range_stmt(ctx, node, mod_flags); + case_end; + case_ast_node(ss, SwitchStmt, node); check_switch_stmt(ctx, node, mod_flags); case_end; diff --git a/src/checker.hpp b/src/checker.hpp index 4e4a8cfe1..a37a87b87 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -276,6 +276,9 @@ struct CheckerContext { CheckerPolyPath *poly_path; isize poly_level; // TODO(bill): Actually handle correctly +#define MAX_INLINE_FOR_DEPTH 1024ll + i64 inline_for_depth; + bool in_enum_type; bool collect_delayed_decls; bool allow_polymorphic_types; diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 54d4ef6f2..fcc6f1973 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -813,6 +813,10 @@ gb_inline ExactValue exact_value_shift(TokenKind op, ExactValue const &x, ExactV return exact_binary_operator_value(op, x, y); } +gb_inline ExactValue exact_value_increment_one(ExactValue const &x) { + return exact_binary_operator_value(Token_Add, x, exact_value_i64(1)); +} + i32 cmp_f64(f64 a, f64 b) { return (a > b) - (a < b); diff --git a/src/ir.cpp b/src/ir.cpp index 2a4bb028b..7dc5988e3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9061,6 +9061,150 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) { ir_start_block(proc, done); case_end; + case_ast_node(rs, InlineRangeStmt, node); + ir_emit_comment(proc, str_lit("InlineRangeStmt")); + ir_open_scope(proc); // Open scope here + + Type *val0_type = nullptr; + Type *val1_type = nullptr; + if (rs->val0 != nullptr && !is_blank_ident(rs->val0)) { + val0_type = type_of_expr(rs->val0); + } + if (rs->val1 != nullptr && !is_blank_ident(rs->val1)) { + val1_type = type_of_expr(rs->val1); + } + + if (val0_type != nullptr) { + ir_add_local_for_identifier(proc, rs->val0, true); + } + if (val1_type != nullptr) { + ir_add_local_for_identifier(proc, rs->val1, true); + } + + irValue *val = nullptr; + irValue *key = nullptr; + irBlock *loop = nullptr; + irBlock *done = nullptr; + Ast *expr = unparen_expr(rs->expr); + + TypeAndValue tav = type_and_value_of_expr(expr); + + if (is_ast_range(expr)) { + + irAddr val0_addr = {}; + irAddr val1_addr = {}; + if (val0_type) val0_addr = ir_build_addr(proc, rs->val0); + if (val1_type) val1_addr = ir_build_addr(proc, rs->val1); + + TokenKind op = expr->BinaryExpr.op.kind; + Ast *start_expr = expr->BinaryExpr.left; + Ast *end_expr = expr->BinaryExpr.right; + GB_ASSERT(start_expr->tav.mode == Addressing_Constant); + GB_ASSERT(end_expr->tav.mode == Addressing_Constant); + + ExactValue start = start_expr->tav.value; + ExactValue end = end_expr->tav.value; + if (op == Token_Ellipsis) { // .. [start, end] + ExactValue index = exact_value_i64(0); + for (ExactValue val = start; + compare_exact_values(Token_LtEq, val, end); + val = exact_value_increment_one(val), index = exact_value_increment_one(index)) { + + if (val0_type) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, val)); + if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, index)); + + ir_build_stmt(proc, rs->body); + } + } else if (op == Token_RangeHalf) { // ..< [start, end) + ExactValue index = exact_value_i64(0); + for (ExactValue val = start; + compare_exact_values(Token_Lt, val, end); + val = exact_value_increment_one(val), index = exact_value_increment_one(index)) { + + if (val0_type) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, val)); + if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, index)); + + ir_build_stmt(proc, rs->body); + } + } + + + } else if (tav.mode == Addressing_Type) { + GB_ASSERT(is_type_enum(type_deref(tav.type))); + Type *et = type_deref(tav.type); + Type *bet = base_type(et); + + irAddr val0_addr = {}; + irAddr val1_addr = {}; + if (val0_type) val0_addr = ir_build_addr(proc, rs->val0); + if (val1_type) val1_addr = ir_build_addr(proc, rs->val1); + + for_array(i, bet->Enum.fields) { + Entity *field = bet->Enum.fields[i]; + GB_ASSERT(field->kind == Entity_Constant); + if (val0_type) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, field->Constant.value)); + if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, exact_value_i64(i))); + + ir_build_stmt(proc, rs->body); + } + } else { + irAddr val0_addr = {}; + irAddr val1_addr = {}; + if (val0_type) val0_addr = ir_build_addr(proc, rs->val0); + if (val1_type) val1_addr = ir_build_addr(proc, rs->val1); + + GB_ASSERT(expr->tav.mode == Addressing_Constant); + + Type *t = base_type(expr->tav.type); + + + switch (t->kind) { + case Type_Basic: + GB_ASSERT(is_type_string(t)); + { + ExactValue value = expr->tav.value; + GB_ASSERT(value.kind == ExactValue_String); + String str = value.value_string; + Rune codepoint = 0; + isize offset = 0; + do { + isize width = gb_utf8_decode(str.text+offset, str.len-offset, &codepoint); + if (val0_type) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, exact_value_i64(codepoint))); + if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, exact_value_i64(offset))); + ir_build_stmt(proc, rs->body); + + offset += width; + } while (offset < str.len); + } + break; + case Type_Array: + if (t->Array.count > 0) { + irValue *val = ir_build_expr(proc, expr); + irValue *val_addr = ir_address_from_load_or_generate_local(proc, val); + + for (i64 i = 0; i < t->Array.count; i++) { + if (val0_type) { + // NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32 + irValue *elem = ir_emit_array_epi(proc, val_addr, cast(i32)i); + ir_addr_store(proc, val0_addr, ir_emit_load(proc, elem)); + } + if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, exact_value_i64(i))); + + ir_build_stmt(proc, rs->body); + } + + } + break; + default: + GB_PANIC("Invalid inline for type"); + break; + } + } + + + ir_close_scope(proc, irDeferExit_Default, nullptr); + case_end; + case_ast_node(ss, SwitchStmt, node); ir_emit_comment(proc, str_lit("SwitchStmt")); if (ss->init != nullptr) { diff --git a/src/parser.cpp b/src/parser.cpp index 9aebc78d6..8c32f35ff 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -51,6 +51,7 @@ Token ast_token(Ast *node) { case Ast_ReturnStmt: return node->ReturnStmt.token; case Ast_ForStmt: return node->ForStmt.token; case Ast_RangeStmt: return node->RangeStmt.token; + case Ast_InlineRangeStmt: return node->InlineRangeStmt.inline_token; case Ast_CaseClause: return node->CaseClause.token; case Ast_SwitchStmt: return node->SwitchStmt.token; case Ast_TypeSwitchStmt: return node->TypeSwitchStmt.token; @@ -257,6 +258,12 @@ Ast *clone_ast(Ast *node) { n->RangeStmt.expr = clone_ast(n->RangeStmt.expr); n->RangeStmt.body = clone_ast(n->RangeStmt.body); break; + case Ast_InlineRangeStmt: + n->InlineRangeStmt.val0 = clone_ast(n->InlineRangeStmt.val0); + n->InlineRangeStmt.val1 = clone_ast(n->InlineRangeStmt.val1); + n->InlineRangeStmt.expr = clone_ast(n->InlineRangeStmt.expr); + n->InlineRangeStmt.body = clone_ast(n->InlineRangeStmt.body); + break; case Ast_CaseClause: n->CaseClause.list = clone_ast_array(n->CaseClause.list); n->CaseClause.stmts = clone_ast_array(n->CaseClause.stmts); @@ -748,6 +755,18 @@ Ast *ast_range_stmt(AstFile *f, Token token, Ast *val0, Ast *val1, Token in_toke return result; } +Ast *ast_inline_range_stmt(AstFile *f, Token inline_token, Token for_token, Ast *val0, Ast *val1, Token in_token, Ast *expr, Ast *body) { + Ast *result = alloc_ast_node(f, Ast_InlineRangeStmt); + result->InlineRangeStmt.inline_token = inline_token; + result->InlineRangeStmt.for_token = for_token; + result->InlineRangeStmt.val0 = val0; + result->InlineRangeStmt.val1 = val1; + result->InlineRangeStmt.in_token = in_token; + result->InlineRangeStmt.expr = expr; + result->InlineRangeStmt.body = body; + return result; +} + Ast *ast_switch_stmt(AstFile *f, Token token, Ast *init, Ast *tag, Ast *body) { Ast *result = alloc_ast_node(f, Ast_SwitchStmt); result->SwitchStmt.token = token; @@ -1119,6 +1138,17 @@ Token advance_token(AstFile *f) { return prev; } +bool peek_token_kind(AstFile *f, TokenKind kind) { + for (isize i = f->curr_token_index+1; i < f->tokens.count; i++) { + Token tok = f->tokens[i]; + if (kind != Token_Comment && tok.kind == Token_Comment) { + continue; + } + return tok.kind == kind; + } + return false; +} + Token expect_token(AstFile *f, TokenKind kind) { Token prev = f->curr_token; if (prev.kind != kind) { @@ -2092,7 +2122,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { bool prev_allow_range = f->allow_range; f->allow_range = true; - elem = parse_expr(f, false); + elem = parse_expr(f, true); f->allow_range = prev_allow_range; if (allow_token(f, Token_Semicolon)) { underlying = parse_type(f); @@ -2650,7 +2680,7 @@ Ast *parse_simple_stmt(AstFile *f, u32 flags) { allow_token(f, Token_in); bool prev_allow_range = f->allow_range; f->allow_range = true; - Ast *expr = parse_expr(f, false); + Ast *expr = parse_expr(f, true); f->allow_range = prev_allow_range; auto rhs = array_make(heap_allocator(), 0, 1); @@ -3779,10 +3809,55 @@ Ast *parse_stmt(AstFile *f) { Token token = f->curr_token; switch (token.kind) { // Operands + case Token_inline: + if (peek_token_kind(f, Token_for)) { + Token inline_token = expect_token(f, Token_inline); + Token for_token = expect_token(f, Token_for); + Ast *val0 = nullptr; + Ast *val1 = nullptr; + Token in_token = {}; + Ast *expr = nullptr; + Ast *body = nullptr; + + bool bad_stmt = false; + + if (f->curr_token.kind != Token_in) { + Array idents = parse_ident_list(f, false); + switch (idents.count) { + case 1: + val0 = idents[0]; + break; + case 2: + val0 = idents[0]; + val1 = idents[1]; + break; + default: + syntax_error(for_token, "Expected either 1 or 2 identifiers"); + bad_stmt = true; + break; + } + } + in_token = expect_token(f, Token_in); + + bool prev_allow_range = f->allow_range; + f->allow_range = true; + expr = parse_expr(f, true); + f->allow_range = prev_allow_range; + + if (allow_token(f, Token_do)) { + body = convert_stmt_to_body(f, parse_stmt(f)); + } else { + body = parse_block_stmt(f, false); + } + if (bad_stmt) { + return ast_bad_stmt(f, inline_token, f->curr_token); + } + return ast_inline_range_stmt(f, inline_token, for_token, val0, val1, in_token, expr, body); + } + /* fallthrough */ + case Token_no_inline: case Token_context: // Also allows for `context =` case Token_proc: - case Token_inline: - case Token_no_inline: case Token_Ident: case Token_Integer: case Token_Float: diff --git a/src/parser.hpp b/src/parser.hpp index 3489f1a9b..32398592e 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -326,6 +326,15 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ Ast *expr; \ Ast *body; \ }) \ + AST_KIND(InlineRangeStmt, "inline range statement", struct { \ + Token inline_token; \ + Token for_token; \ + Ast *val0; \ + Ast *val1; \ + Token in_token; \ + Ast *expr; \ + Ast *body; \ + }) \ AST_KIND(CaseClause, "case clause", struct { \ Token token; \ Array list; \ From 25dd00cd0bf84fedabb459bda098e07ba5e4e409 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 26 Aug 2019 14:40:04 +0100 Subject: [PATCH 037/143] Add complex/quaternion raw layouts to mem/raw.odin --- core/mem/raw.odin | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/mem/raw.odin b/core/mem/raw.odin index c7f4ee9db..97cd71e7a 100644 --- a/core/mem/raw.odin +++ b/core/mem/raw.odin @@ -31,6 +31,12 @@ Raw_Map :: struct { entries: Raw_Dynamic_Array, } +Raw_Complex64 :: struct {real, imag: f32}; +Raw_Complex128 :: struct {real, imag: f64}; +Raw_Quaternion128 :: struct {imag, jmag, kmag: f32, real: f32}; +Raw_Quaternion256 :: struct {imag, jmag, kmag: f64, real: f64}; +Raw_Quaternion128_Vector_Scalar :: struct {vector: [3]f32, scalar: f32}; +Raw_Quaternion256_Vector_Scalar :: struct {vector: [3]f64, scalar: f64}; make_any :: inline proc(data: rawptr, id: typeid) -> any { return transmute(any)Raw_Any{data, id}; From c44d25d14f2a8f800170daae4a1c9d08858978b6 Mon Sep 17 00:00:00 2001 From: thebirk Date: Mon, 26 Aug 2019 16:47:41 +0200 Subject: [PATCH 038/143] Fixed parser creating a new thread for each file. --- src/parser.cpp | 107 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 97 insertions(+), 10 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 9aebc78d6..0a2a3c1fc 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4679,7 +4679,47 @@ skip: return ParseFile_None; } +#if 1 +struct ParserWorkerThreadData { + Parser *parser; + gbSemaphore resume_work; //NOTE(thebirk): Use to signal that the worker thead has a new work to do + ParseFileError err; + + gbMutex lock; //NOTE(thebirk): All variables below are locked by this mutex + bool error_available; + bool should_exit; +}; + + +GB_THREAD_PROC(parse_worker_file_proc) { + GB_ASSERT(thread != nullptr); + + ParserWorkerThreadData* data = cast(ParserWorkerThreadData*) thread->user_data; + + for(;;) { + gb_semaphore_wait(&data->resume_work); + + gb_mutex_lock(&data->lock); + if (data->should_exit) { + gb_mutex_unlock(&data->lock); + return isize(0); + } + + Parser *p = data->parser; + isize index = thread->user_index; + gb_mutex_lock(&p->file_add_mutex); + auto file_to_process = p->files_to_process[index]; + gb_mutex_unlock(&p->file_add_mutex); + data->err = process_imported_file(p, file_to_process); + + data->error_available = true; + gb_mutex_unlock(&data->lock); + } + + //GB_PANIC("A worker thread should not be able to reach the end!!!"); +} +#else GB_THREAD_PROC(parse_worker_file_proc) { if (thread == nullptr) return 0; auto *p = cast(Parser *)thread->user_data; @@ -4690,6 +4730,7 @@ GB_THREAD_PROC(parse_worker_file_proc) { ParseFileError err = process_imported_file(p, file_to_process); return cast(isize)err; } +#endif ParseFileError parse_packages(Parser *p, String init_filename) { GB_ASSERT(init_filename.text[init_filename.len] == 0); @@ -4729,14 +4770,36 @@ ParseFileError parse_packages(Parser *p, String init_filename) { curr_import_index++; } + auto worker_threads_data = array_make(heap_allocator(), thread_count); + defer (array_free(&worker_threads_data)); + + for_array(i, worker_threads_data) { + ParserWorkerThreadData *data = &worker_threads_data[i]; + gb_mutex_init(&data->lock); + gb_semaphore_init(&data->resume_work); + data->parser = p; + data->err = ParseFile_None; + data->should_exit = false; + data->error_available = false; + } + defer(for_array(i, worker_threads_data) { + ParserWorkerThreadData *data = &worker_threads_data[i]; + gb_mutex_destroy(&data->lock); + gb_semaphore_destroy(&data->resume_work); + }); + auto worker_threads = array_make(heap_allocator(), thread_count); defer (array_free(&worker_threads)); for_array(i, worker_threads) { gbThread *t = &worker_threads[i]; gb_thread_init(t); + char buffer[64]; + gb_snprintf(buffer, 64, "Parser Worker #%lld", i); + gb_thread_set_name(t, buffer); + gb_thread_start(t, parse_worker_file_proc, &worker_threads_data[i]); } - defer (for_array(i, worker_threads) { + defer(for_array(i, worker_threads) { gb_thread_destroy(&worker_threads[i]); }); @@ -4744,27 +4807,51 @@ ParseFileError parse_packages(Parser *p, String init_filename) { for (;;) { bool are_any_alive = false; + for_array(i, worker_threads) { gbThread *t = &worker_threads[i]; - if (gb_thread_is_running(t)) { - are_any_alive = true; - } else if (curr_import_index < p->files_to_process.count) { - auto curr_err = cast(ParseFileError)t->return_value; - if (curr_err != ParseFile_None) { - array_add(&errors, curr_err); - } else { + ParserWorkerThreadData *data = &worker_threads_data[i]; + + if (gb_mutex_try_lock(&data->lock)) { + if (data->error_available) { + auto curr_err = data->err; + if (curr_err != ParseFile_None) { + array_add(&errors, curr_err); + } + + data->error_available = false; + } + + if (curr_import_index < p->files_to_process.count) { t->user_index = curr_import_index; curr_import_index++; - gb_thread_start(t, parse_worker_file_proc, p); are_any_alive = true; + + gb_semaphore_release(&data->resume_work); } + + gb_mutex_unlock(&data->lock); + } else { + //NOTE(thebirk): If we cant lock a thread it must be working + are_any_alive = true; } } - if (!are_any_alive && curr_import_index >= p->files_to_process.count) { + + //NOTE(thebirk): Everything collapses without this, but it really shouldn't! + gb_yield(); + + if ((!are_any_alive) && (curr_import_index >= p->files_to_process.count)) { break; } } + //NOTE(thebirk): Signal all workers to exit + for_array(i, worker_threads_data) { + ParserWorkerThreadData* data = &worker_threads_data[i]; + data->should_exit = true; + gb_semaphore_release(&data->resume_work); + } + if (errors.count > 0) { return errors[errors.count-1]; } From 6d3feb45312ff22a9be7c791e798bb64adbcb0a8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 26 Aug 2019 16:18:26 +0100 Subject: [PATCH 039/143] Fix typo in tokenizer (no actual bug) --- src/tokenizer.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 5ba402858..618de54b9 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -746,11 +746,10 @@ exponent: } switch (t->curr_rune) { - case 'i': - case 'j': - case 'k': + case 'i': case 'j': case 'k': token.kind = Token_Imag; advance_to_next_rune(t); + break; } end: From 97dfcffa761acdf22a12412db5610cc4beb2c4d6 Mon Sep 17 00:00:00 2001 From: thebirk Date: Mon, 26 Aug 2019 19:09:52 +0200 Subject: [PATCH 040/143] Fixed error where the parser would end early. --- src/parser.cpp | 34 +++++++++++++++++++++++++++------- src/parser.hpp | 1 + 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 0a2a3c1fc..d7e7f63b7 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4062,6 +4062,7 @@ bool init_parser(Parser *p) { array_init(&p->files_to_process, heap_allocator()); gb_mutex_init(&p->file_add_mutex); gb_mutex_init(&p->file_decl_mutex); + gb_semaphore_init(&p->worker_finished_semaphore); return true; } @@ -4087,6 +4088,7 @@ void destroy_parser(Parser *p) { map_destroy(&p->package_map); gb_mutex_destroy(&p->file_add_mutex); gb_mutex_destroy(&p->file_decl_mutex); + gb_semaphore_destroy(&p->worker_finished_semaphore); } @@ -4714,6 +4716,7 @@ GB_THREAD_PROC(parse_worker_file_proc) { data->err = process_imported_file(p, file_to_process); data->error_available = true; + gb_semaphore_release(&p->worker_finished_semaphore); gb_mutex_unlock(&data->lock); } @@ -4760,6 +4763,8 @@ ParseFileError parse_packages(Parser *p, String init_filename) { isize thread_count = gb_max(build_context.thread_count, 1); if (thread_count > 1) { isize volatile curr_import_index = 0; + +#if 0 isize initial_file_count = p->files_to_process.count; // NOTE(bill): Make sure that these are in parsed in this order for (isize i = 0; i < initial_file_count; i++) { @@ -4769,6 +4774,7 @@ ParseFileError parse_packages(Parser *p, String init_filename) { } curr_import_index++; } +#endif auto worker_threads_data = array_make(heap_allocator(), thread_count); defer (array_free(&worker_threads_data)); @@ -4795,7 +4801,7 @@ ParseFileError parse_packages(Parser *p, String init_filename) { gbThread *t = &worker_threads[i]; gb_thread_init(t); char buffer[64]; - gb_snprintf(buffer, 64, "Parser Worker #%lld", i); + gb_snprintf(buffer, 64, "Parser Worker #%ll", i); gb_thread_set_name(t, buffer); gb_thread_start(t, parse_worker_file_proc, &worker_threads_data[i]); } @@ -4806,7 +4812,7 @@ ParseFileError parse_packages(Parser *p, String init_filename) { auto errors = array_make(heap_allocator(), 0, 16); for (;;) { - bool are_any_alive = false; + int num_alive = 0; for_array(i, worker_threads) { gbThread *t = &worker_threads[i]; @@ -4825,7 +4831,7 @@ ParseFileError parse_packages(Parser *p, String init_filename) { if (curr_import_index < p->files_to_process.count) { t->user_index = curr_import_index; curr_import_index++; - are_any_alive = true; + num_alive += 1; gb_semaphore_release(&data->resume_work); } @@ -4833,14 +4839,28 @@ ParseFileError parse_packages(Parser *p, String init_filename) { gb_mutex_unlock(&data->lock); } else { //NOTE(thebirk): If we cant lock a thread it must be working - are_any_alive = true; + num_alive += 1; + } } - //NOTE(thebirk): Everything collapses without this, but it really shouldn't! - gb_yield(); + while (num_alive > 0) { + isize prev_files_to_process = p->files_to_process.count; + gb_semaphore_wait(&p->worker_finished_semaphore); + num_alive -= 1; - if ((!are_any_alive) && (curr_import_index >= p->files_to_process.count)) { + if (prev_files_to_process < p->files_to_process.count) { + if (num_alive > 0) { + //NOTE(thebirk): Recreate semaphore to avoid overflowing the counter. Only needs to happen when there are more threads alive + gb_semaphore_destroy(&p->worker_finished_semaphore); + gb_semaphore_init(&p->worker_finished_semaphore); + } + break; + } + } + + + if ((num_alive == 0) && (curr_import_index >= p->files_to_process.count)) { break; } } diff --git a/src/parser.hpp b/src/parser.hpp index 3489f1a9b..f1bbd8784 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -139,6 +139,7 @@ struct Parser { isize total_line_count; gbMutex file_add_mutex; gbMutex file_decl_mutex; + gbSemaphore worker_finished_semaphore; }; enum ProcInlining { From 4551521b2cc461d89d9d69ea441ae311a8607f94 Mon Sep 17 00:00:00 2001 From: thebirk Date: Mon, 26 Aug 2019 19:51:33 +0200 Subject: [PATCH 041/143] Im just trying things at this point, Bill should just squash this PR at merge time ;) --- src/parser.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index d7e7f63b7..97715b10e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4690,6 +4690,7 @@ struct ParserWorkerThreadData { gbMutex lock; //NOTE(thebirk): All variables below are locked by this mutex bool error_available; + bool is_working; bool should_exit; }; @@ -4716,8 +4717,9 @@ GB_THREAD_PROC(parse_worker_file_proc) { data->err = process_imported_file(p, file_to_process); data->error_available = true; - gb_semaphore_release(&p->worker_finished_semaphore); + data->is_working = false; gb_mutex_unlock(&data->lock); + gb_semaphore_release(&p->worker_finished_semaphore); } //GB_PANIC("A worker thread should not be able to reach the end!!!"); @@ -4818,7 +4820,7 @@ ParseFileError parse_packages(Parser *p, String init_filename) { gbThread *t = &worker_threads[i]; ParserWorkerThreadData *data = &worker_threads_data[i]; - if (gb_mutex_try_lock(&data->lock)) { + if (!data->is_working && gb_mutex_try_lock(&data->lock)) { if (data->error_available) { auto curr_err = data->err; if (curr_err != ParseFile_None) { @@ -4834,6 +4836,7 @@ ParseFileError parse_packages(Parser *p, String init_filename) { num_alive += 1; gb_semaphore_release(&data->resume_work); + data->is_working = true; } gb_mutex_unlock(&data->lock); @@ -4844,20 +4847,23 @@ ParseFileError parse_packages(Parser *p, String init_filename) { } } + /* while (num_alive > 0) { isize prev_files_to_process = p->files_to_process.count; gb_semaphore_wait(&p->worker_finished_semaphore); num_alive -= 1; - if (prev_files_to_process < p->files_to_process.count) { + if ((prev_files_to_process < p->files_to_process.count)) { if (num_alive > 0) { //NOTE(thebirk): Recreate semaphore to avoid overflowing the counter. Only needs to happen when there are more threads alive - gb_semaphore_destroy(&p->worker_finished_semaphore); - gb_semaphore_init(&p->worker_finished_semaphore); + //gb_semaphore_destroy(&p->worker_finished_semaphore); + //gb_semaphore_init(&p->worker_finished_semaphore); } + printf("Early out!\n"); break; } } + */ if ((num_alive == 0) && (curr_import_index >= p->files_to_process.count)) { From 6a8b3fee38b3bb05ffc599d619e78472ad8b56a0 Mon Sep 17 00:00:00 2001 From: thebirk Date: Mon, 26 Aug 2019 20:23:52 +0200 Subject: [PATCH 042/143] Removed gb_thread_set_name because it segfaults on linux. --- src/parser.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 97715b10e..70cc37433 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4789,6 +4789,7 @@ ParseFileError parse_packages(Parser *p, String init_filename) { data->err = ParseFile_None; data->should_exit = false; data->error_available = false; + data->is_working = false; } defer(for_array(i, worker_threads_data) { ParserWorkerThreadData *data = &worker_threads_data[i]; @@ -4802,9 +4803,9 @@ ParseFileError parse_packages(Parser *p, String init_filename) { for_array(i, worker_threads) { gbThread *t = &worker_threads[i]; gb_thread_init(t); - char buffer[64]; - gb_snprintf(buffer, 64, "Parser Worker #%ll", i); - gb_thread_set_name(t, buffer); + //char buffer[64]; + //gb_snprintf(buffer, 64, "Parser Worker #%ll", i); + //gb_thread_set_name(t, buffer); gb_thread_start(t, parse_worker_file_proc, &worker_threads_data[i]); } defer(for_array(i, worker_threads) { From f1a7b31209d68f71256ad524d6d1a6ed15cb7c12 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 28 Aug 2019 13:34:55 +0100 Subject: [PATCH 043/143] Fix nested raw_union with using #428 --- src/ir.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 7dc5988e3..7fa3f296a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1873,10 +1873,12 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) { case Basic_string: case Basic_any: case Basic_rawptr: + case Basic_quaternion128: + case Basic_quaternion256: break; // not a "DIBasicType" } - GB_PANIC("Unreachable"); + GB_PANIC("Unreachable %d", kind); return irDebugBasicEncoding_Invalid; } @@ -4525,13 +4527,14 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, irValue *e, Selection sel) { if (is_type_pointer(type)) { type = type_deref(type); e = ir_emit_load(proc, e); - e = ir_emit_ptr_offset(proc, e, v_zero); // TODO(bill): Do I need these copies? + // e = ir_emit_ptr_offset(proc, e, v_zero); // TODO(bill): Do I need these copies? } type = core_type(type); if (is_type_raw_union(type)) { type = type->Struct.fields[index]->type; - e = ir_emit_conv(proc, e, alloc_type_pointer(type)); + GB_ASSERT(is_type_pointer(ir_type(e))); + e = ir_emit_bitcast(proc, e, alloc_type_pointer(type)); } else if (is_type_struct(type)) { type = type->Struct.fields[index]->type; e = ir_emit_struct_ep(proc, e, index); From 614d209824f005aa11a399bbe1bbf2b3b9e76687 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 29 Aug 2019 10:39:03 +0100 Subject: [PATCH 044/143] Add debug information for quaternion types (fixes #428) --- src/ir.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 7fa3f296a..62519c259 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2224,14 +2224,7 @@ irDebugInfo *ir_add_debug_info_type_complex(irModule *module, Type *type) { di->CompositeType.tag = irDebugBasicEncoding_structure_type; di->CompositeType.size = ir_debug_size_bits(type); - Type *field_type = nullptr; - if (type->Basic.kind == Basic_complex64) { - field_type = t_f32; - } else if (type->Basic.kind == Basic_complex128) { - field_type = t_f64; - } else { - GB_PANIC("Unreachable"); - } + Type *field_type = base_complex_elem_type(type); // Field "real" irDebugInfo *real_di = ir_add_debug_info_field_internal(module, str_lit("real"), field_type, @@ -2256,6 +2249,40 @@ irDebugInfo *ir_add_debug_info_type_complex(irModule *module, Type *type) { return di; } +irDebugInfo *ir_add_debug_info_type_quaternion(irModule *module, Type *type) { + GB_ASSERT(type->kind == Type_Basic && is_type_quaternion(type)); + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + map_set(&module->debug_info, hash_type(type), di); + + di->CompositeType.name = type->Basic.name; + di->CompositeType.tag = irDebugBasicEncoding_structure_type; + di->CompositeType.size = ir_debug_size_bits(type); + + Type *field_type = base_complex_elem_type(type); + + // @QuaternionLayout + irDebugInfo *imag_di = ir_add_debug_info_field_internal(module, str_lit("imag"), field_type, 0*cast(i32)type_size_of(field_type), nullptr, di); + irDebugInfo *jmag_di = ir_add_debug_info_field_internal(module, str_lit("jmag"), field_type, 1*cast(i32)type_size_of(field_type), nullptr, di); + irDebugInfo *kmag_di = ir_add_debug_info_field_internal(module, str_lit("kmag"), field_type, 2*cast(i32)type_size_of(field_type), nullptr, di); + irDebugInfo *real_di = ir_add_debug_info_field_internal(module, str_lit("real"), field_type, 3*cast(i32)type_size_of(field_type), nullptr, di); + + map_set(&module->debug_info, hash_pointer(imag_di), imag_di); + map_set(&module->debug_info, hash_pointer(jmag_di), jmag_di); + map_set(&module->debug_info, hash_pointer(kmag_di), kmag_di); + map_set(&module->debug_info, hash_pointer(real_di), real_di); + + irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 4); + array_add(&elements_di->DebugInfoArray.elements, imag_di); + array_add(&elements_di->DebugInfoArray.elements, jmag_di); + array_add(&elements_di->DebugInfoArray.elements, kmag_di); + array_add(&elements_di->DebugInfoArray.elements, real_di); + di->CompositeType.elements = elements_di; + map_set(&module->debug_info, hash_pointer(elements_di), elements_di); + + return di; +} + irDebugInfo *ir_add_debug_info_proc_type(irModule *module, Type *type) { GB_ASSERT(type->kind == Type_Proc); @@ -2380,10 +2407,14 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD if (type->kind == Type_Basic) { switch (type->Basic.kind) { // Composite basic types - case Basic_complex64: - case Basic_complex128: return ir_add_debug_info_type_complex(module, type); - case Basic_string: return ir_add_debug_info_type_string(module, scope, e, type); - case Basic_any: return ir_add_debug_info_type_any(module); + case Basic_complex64: case Basic_complex128: + return ir_add_debug_info_type_complex(module, type); + case Basic_quaternion128: case Basic_quaternion256: + return ir_add_debug_info_type_quaternion(module, type); + case Basic_string: + return ir_add_debug_info_type_string(module, scope, e, type); + case Basic_any: + return ir_add_debug_info_type_any(module); // Derived basic types case Basic_cstring: From c89fc35e941275085332ba16b453432b5b7a5086 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 29 Aug 2019 14:36:42 +0100 Subject: [PATCH 045/143] Fix global variable initialization ordering (related to #427) --- src/check_decl.cpp | 5 ++-- src/check_stmt.cpp | 7 +++++- src/checker.cpp | 57 +++++++++++++++++++++++++----------------- src/ir.cpp | 13 ++-------- src/priority_queue.cpp | 4 +-- 5 files changed, 47 insertions(+), 39 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index cf3cb8e97..d87e6def0 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -791,7 +791,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { } } -void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) { +void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) { GB_ASSERT(e->type == nullptr); GB_ASSERT(e->kind == Entity_Variable); @@ -805,6 +805,7 @@ void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_ex ac.init_expr_list_count = init_expr != nullptr ? 1 : 0; DeclInfo *decl = decl_info_of_entity(e); + GB_ASSERT(decl == ctx->decl); if (decl != nullptr) { check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac); } @@ -1051,7 +1052,7 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_ switch (e->kind) { case Entity_Variable: - check_var_decl(&c, e, d->type_expr, d->init_expr); + check_global_variable_decl(&c, e, d->type_expr, d->init_expr); break; case Entity_Constant: check_const_decl(&c, e, d->type_expr, d->init_expr, named_type); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 88661558d..6945fb00e 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1735,7 +1735,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { } for (isize i = 0; i < entity_count; i++) { - add_entity(ctx->checker, ctx->scope, entities[i]->identifier, entities[i]); + Entity *e = entities[i]; + DeclInfo *d = decl_info_of_entity(e); + GB_ASSERT(d == nullptr); + add_entity(ctx->checker, ctx->scope, e->identifier, e); + d = make_decl_info(ctx->allocator, ctx->scope, ctx->decl); + add_entity_and_decl_info(ctx, e->identifier, e, d); } check_stmt(ctx, rs->body, new_flags); diff --git a/src/checker.cpp b/src/checker.cpp index d6f5ad402..fc8cb5c63 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -85,9 +85,13 @@ int entity_graph_node_cmp(EntityGraphNode **data, isize i, isize j) { EntityGraphNode *y = data[j]; isize a = x->entity->order_in_src; isize b = y->entity->order_in_src; - if (x->dep_count < y->dep_count) return -1; - if (x->dep_count > y->dep_count) return +1; - return a < b ? -1 : b > a; + if (x->dep_count < y->dep_count) { + return -1; + } + if (x->dep_count == y->dep_count) { + return a < b ? -1 : b > a; + } + return +1; } void entity_graph_node_swap(EntityGraphNode **data, isize i, isize j) { @@ -1164,6 +1168,7 @@ void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, Dec add_entity_definition(&c->checker->info, identifier, e); GB_ASSERT(e->decl_info == nullptr); e->decl_info = d; + d->entity = e; array_add(&c->checker->info.entities, e); e->order_in_src = c->checker->info.entities.count; e->pkg = c->pkg; @@ -1602,6 +1607,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("args__"), str_lit("type_table"), + str_lit("__type_info_of"), str_lit("global_scratch_allocator"), str_lit("Type_Info"), @@ -1688,9 +1694,10 @@ bool is_entity_a_dependency(Entity *e) { if (e == nullptr) return false; switch (e->kind) { case Entity_Procedure: - case Entity_Variable: - case Entity_Constant: return true; + case Entity_Constant: + case Entity_Variable: + return e->pkg != nullptr; } return false; } @@ -1717,18 +1724,17 @@ Array generate_entity_dependency_graph(CheckerInfo *info) { EntityGraphNode *n = M.entries[i].value; DeclInfo *decl = decl_info_of_entity(e); - if (decl != nullptr) { - for_array(j, decl->deps.entries) { - auto entry = decl->deps.entries[j]; - Entity *dep = entry.ptr; - if (dep && is_entity_a_dependency(dep)) { - EntityGraphNode **m_ = map_get(&M, hash_pointer(dep)); - if (m_ != nullptr) { - EntityGraphNode *m = *m_; - entity_graph_node_set_add(&n->succ, m); - entity_graph_node_set_add(&m->pred, n); - } - } + GB_ASSERT(decl != nullptr); + + for_array(j, decl->deps.entries) { + Entity *dep = decl->deps.entries[j].ptr; + GB_ASSERT(dep != nullptr); + if (is_entity_a_dependency(dep)) { + EntityGraphNode **m_ = map_get(&M, hash_pointer(dep)); + GB_ASSERT(m_ != nullptr); + EntityGraphNode *m = *m_; + entity_graph_node_set_add(&n->succ, m); + entity_graph_node_set_add(&m->pred, n); } } } @@ -2562,6 +2568,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { Ast *init_expr = value; DeclInfo *d = make_decl_info(heap_allocator(), c->scope, c->decl); + d->entity = e; d->type_expr = vd->type; d->init_expr = init_expr; d->attributes = vd->attributes; @@ -3576,7 +3583,6 @@ void calculate_global_init_order(Checker *c) { #define TIME_SECTION(str) #endif - CheckerInfo *info = &c->info; TIME_SECTION("generate entity dependency graph"); @@ -3618,21 +3624,26 @@ void calculate_global_init_order(Checker *c) { for_array(i, n->pred.entries) { EntityGraphNode *p = n->pred.entries[i].ptr; - p->dep_count -= gb_max(p->dep_count-1, 0); + p->dep_count -= 1; + p->dep_count = gb_max(p->dep_count, 0); priority_queue_fix(&pq, p->index); } - if (e == nullptr || e->kind != Entity_Variable) { + DeclInfo *d = decl_info_of_entity(e); + if (e->kind != Entity_Variable) { continue; } - DeclInfo *d = decl_info_of_entity(e); - + // IMPORTANT NOTE(bill, 2019-08-29): Just add it regardless of the ordering + // because it does not need any initialization other than zero + // if (!decl_info_has_init(d)) { + // continue; + // } if (ptr_set_exists(&emitted, d)) { continue; } ptr_set_add(&emitted, d); - d->entity = e; + array_add(&info->variable_init_order, d); } diff --git a/src/ir.cpp b/src/ir.cpp index 62519c259..26f787976 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2226,18 +2226,9 @@ irDebugInfo *ir_add_debug_info_type_complex(irModule *module, Type *type) { Type *field_type = base_complex_elem_type(type); - // Field "real" - irDebugInfo *real_di = ir_add_debug_info_field_internal(module, str_lit("real"), field_type, - 0, - nullptr, - di); + irDebugInfo *real_di = ir_add_debug_info_field_internal(module, str_lit("real"), field_type, 0*cast(i32)type_size_of(field_type), nullptr, di); + irDebugInfo *imag_di = ir_add_debug_info_field_internal(module, str_lit("imag"), field_type, 1*cast(i32)type_size_of(field_type), nullptr, di); map_set(&module->debug_info, hash_pointer(real_di), real_di); - - // Field "imag" - irDebugInfo *imag_di = ir_add_debug_info_field_internal(module, str_lit("imag"), field_type, - real_di->DerivedType.size, - nullptr, - di); map_set(&module->debug_info, hash_pointer(imag_di), imag_di); irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 2); diff --git a/src/priority_queue.cpp b/src/priority_queue.cpp index 7c36e6a22..aee2061b5 100644 --- a/src/priority_queue.cpp +++ b/src/priority_queue.cpp @@ -20,7 +20,7 @@ bool priority_queue_shift_down(PriorityQueue *pq, isize i0, isize n) { if (j2 < n && pq->cmp(&pq->queue[0], j2, j1) < 0) { j = j2; } - if (pq->cmp(&pq->queue[0], i, j) < 0) break; + if (pq->cmp(&pq->queue[0], j, i) >= 0) break; pq->swap(&pq->queue[0], i, j); i = j; @@ -32,7 +32,7 @@ template void priority_queue_shift_up(PriorityQueue *pq, isize j) { while (0 <= j && j < pq->queue.count) { isize i = (j-1)/2; - if (i == j || pq->cmp(&pq->queue[0], i, j) < 0) { + if (i == j || pq->cmp(&pq->queue[0], j, i) >= 0) { break; } pq->swap(&pq->queue[0], i, j); From 2dc39a5cbdd9c2654cfca4dee84018c2951b7f3f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 29 Aug 2019 15:25:46 +0100 Subject: [PATCH 046/143] Improve demo.odin --- examples/demo/demo.odin | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index cef814a56..fe390e5b0 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -544,6 +544,30 @@ parametric_polymorphism :: proc() { for v, i in array { assert(v == T(i*i)); } + + // Matrix multiplication + mul :: proc(a: [$M][$N]$T, b: [N][$P]T) -> (c: [M][P]T) { + for i in 0.. ! { fmt.println("I'm a diverging procedure"); @@ -931,6 +961,8 @@ diverging_procedures :: proc() { } deferred_procedure_associations :: proc() { + fmt.println("\n# deferred_procedure_associations"); + @(deferred_out=closure) open :: proc(s: string) -> bool { fmt.println(s); @@ -1030,6 +1062,10 @@ quaternions :: proc() { inline_for_statement :: proc() { fmt.println("\n#inline for statements"); + // 'inline for' works the same as if the 'inline' prefix did not + // exist but these ranged loops are explicitly unrolled which can + // be very very useful for certain optimizations + fmt.println("Ranges"); inline for x, i in 1..<4 { fmt.println(x, i); From d118fc569abed3338cf85c3ec2a0296340d9c04f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 29 Aug 2019 16:45:36 +0100 Subject: [PATCH 047/143] Add intrinsincs.type_is_quaternion --- src/check_expr.cpp | 2 ++ src/checker_builtin_procs.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6a9a53275..7c4c4e6e4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3214,6 +3214,7 @@ BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_end - BuiltinProc__ty is_type_rune, is_type_float, is_type_complex, + is_type_quaternion, is_type_string, is_type_typeid, is_type_any, @@ -4776,6 +4777,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_type_is_rune: case BuiltinProc_type_is_float: case BuiltinProc_type_is_complex: + case BuiltinProc_type_is_quaternion: case BuiltinProc_type_is_string: case BuiltinProc_type_is_typeid: case BuiltinProc_type_is_any: diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 0135b3c50..b119452d4 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -120,6 +120,7 @@ BuiltinProc__type_begin, BuiltinProc_type_is_rune, BuiltinProc_type_is_float, BuiltinProc_type_is_complex, + BuiltinProc_type_is_quaternion, BuiltinProc_type_is_string, BuiltinProc_type_is_typeid, BuiltinProc_type_is_any, @@ -278,6 +279,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_rune"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_float"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_complex"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_quaternion"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_string"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_typeid"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_any"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, From d76249d90b4d2812c2d8c2d25d854a3e9361b510 Mon Sep 17 00:00:00 2001 From: thebirk Date: Thu, 29 Aug 2019 20:27:38 +0200 Subject: [PATCH 048/143] Cleaned up parse_packages and the worker proc. --- src/parser.cpp | 50 ++++++++++++-------------------------------------- 1 file changed, 12 insertions(+), 38 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 70cc37433..3fc999a2c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4681,14 +4681,13 @@ skip: return ParseFile_None; } -#if 1 struct ParserWorkerThreadData { Parser *parser; - - gbSemaphore resume_work; //NOTE(thebirk): Use to signal that the worker thead has a new work to do ParseFileError err; - gbMutex lock; //NOTE(thebirk): All variables below are locked by this mutex + gbSemaphore resume_work; + gbMutex lock; + bool error_available; bool is_working; bool should_exit; @@ -4724,18 +4723,6 @@ GB_THREAD_PROC(parse_worker_file_proc) { //GB_PANIC("A worker thread should not be able to reach the end!!!"); } -#else -GB_THREAD_PROC(parse_worker_file_proc) { - if (thread == nullptr) return 0; - auto *p = cast(Parser *)thread->user_data; - isize index = thread->user_index; - gb_mutex_lock(&p->file_add_mutex); - auto file_to_process = p->files_to_process[index]; - gb_mutex_unlock(&p->file_add_mutex); - ParseFileError err = process_imported_file(p, file_to_process); - return cast(isize)err; -} -#endif ParseFileError parse_packages(Parser *p, String init_filename) { GB_ASSERT(init_filename.text[init_filename.len] == 0); @@ -4767,6 +4754,8 @@ ParseFileError parse_packages(Parser *p, String init_filename) { isize volatile curr_import_index = 0; #if 0 + //NOTE(thebirk): Leaving this piece of code behind if it turns out we need it, yes I know git exists + isize initial_file_count = p->files_to_process.count; // NOTE(bill): Make sure that these are in parsed in this order for (isize i = 0; i < initial_file_count; i++) { @@ -4803,8 +4792,11 @@ ParseFileError parse_packages(Parser *p, String init_filename) { for_array(i, worker_threads) { gbThread *t = &worker_threads[i]; gb_thread_init(t); - //char buffer[64]; - //gb_snprintf(buffer, 64, "Parser Worker #%ll", i); + //NOTE(thebirk): This crashes on linux. In addition to that the method used on windows does + // not get picked up by a lot of tools look into using SetThreadDescription + // when running on new enough windows 10 builds + //char buffer[32]; + //gb_snprintf(buffer, 32, "Parser Worker #%ll", i); //gb_thread_set_name(t, buffer); gb_thread_start(t, parse_worker_file_proc, &worker_threads_data[i]); } @@ -4844,32 +4836,14 @@ ParseFileError parse_packages(Parser *p, String init_filename) { } else { //NOTE(thebirk): If we cant lock a thread it must be working num_alive += 1; - } } - /* - while (num_alive > 0) { - isize prev_files_to_process = p->files_to_process.count; - gb_semaphore_wait(&p->worker_finished_semaphore); - num_alive -= 1; - - if ((prev_files_to_process < p->files_to_process.count)) { - if (num_alive > 0) { - //NOTE(thebirk): Recreate semaphore to avoid overflowing the counter. Only needs to happen when there are more threads alive - //gb_semaphore_destroy(&p->worker_finished_semaphore); - //gb_semaphore_init(&p->worker_finished_semaphore); - } - printf("Early out!\n"); - break; - } - } - */ - - if ((num_alive == 0) && (curr_import_index >= p->files_to_process.count)) { break; } + + gb_yield(); } //NOTE(thebirk): Signal all workers to exit From 4dade346033bc3d19879bee1823abf3d9e230281 Mon Sep 17 00:00:00 2001 From: thebirk Date: Thu, 29 Aug 2019 20:34:09 +0200 Subject: [PATCH 049/143] Removed unused semaphore on Parser. --- src/parser.cpp | 2 -- src/parser.hpp | 1 - 2 files changed, 3 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 3fc999a2c..f08688b5f 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4062,7 +4062,6 @@ bool init_parser(Parser *p) { array_init(&p->files_to_process, heap_allocator()); gb_mutex_init(&p->file_add_mutex); gb_mutex_init(&p->file_decl_mutex); - gb_semaphore_init(&p->worker_finished_semaphore); return true; } @@ -4088,7 +4087,6 @@ void destroy_parser(Parser *p) { map_destroy(&p->package_map); gb_mutex_destroy(&p->file_add_mutex); gb_mutex_destroy(&p->file_decl_mutex); - gb_semaphore_destroy(&p->worker_finished_semaphore); } diff --git a/src/parser.hpp b/src/parser.hpp index f1bbd8784..3489f1a9b 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -139,7 +139,6 @@ struct Parser { isize total_line_count; gbMutex file_add_mutex; gbMutex file_decl_mutex; - gbSemaphore worker_finished_semaphore; }; enum ProcInlining { From f921a91fc8a1e2674279e79c7357adfb0016b360 Mon Sep 17 00:00:00 2001 From: thebirk Date: Thu, 29 Aug 2019 20:35:12 +0200 Subject: [PATCH 050/143] Properly removed the semaphore. --- src/parser.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/parser.cpp b/src/parser.cpp index f08688b5f..31d21b737 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4716,7 +4716,6 @@ GB_THREAD_PROC(parse_worker_file_proc) { data->error_available = true; data->is_working = false; gb_mutex_unlock(&data->lock); - gb_semaphore_release(&p->worker_finished_semaphore); } //GB_PANIC("A worker thread should not be able to reach the end!!!"); From 07ced1cf0eed9c30813d49dad0c33f29f0c161ef Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 31 Aug 2019 11:12:41 +0100 Subject: [PATCH 051/143] Fix variable dependency ordering issues caused by procedure literals --- src/check_decl.cpp | 23 +++++++++++++++-------- src/check_expr.cpp | 3 ++- src/checker.cpp | 9 +++++++++ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index d87e6def0..b5b9dc61d 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1190,17 +1190,24 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty check_scope_usage(ctx->checker, ctx->scope); +#if 0 if (decl->parent != nullptr) { - // NOTE(bill): Add the dependencies from the procedure literal (lambda) - for_array(i, decl->deps.entries) { - Entity *e = decl->deps.entries[i].ptr; - ptr_set_add(&decl->parent->deps, e); - } - for_array(i, decl->type_info_deps.entries) { - Type *t = decl->type_info_deps.entries[i].ptr; - ptr_set_add(&decl->parent->type_info_deps, t); + Scope *ps = decl->parent->scope; + if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) { + return; + } else { + // NOTE(bill): Add the dependencies from the procedure literal (lambda) + for_array(i, decl->deps.entries) { + Entity *e = decl->deps.entries[i].ptr; + ptr_set_add(&decl->parent->deps, e); + } + for_array(i, decl->type_info_deps.entries) { + Type *t = decl->type_info_deps.entries[i].ptr; + ptr_set_add(&decl->parent->type_info_deps, t); + } } } +#endif } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7c4c4e6e4..86cba0f94 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4864,7 +4864,7 @@ isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lhs, isize lhs c->decl = decl; // will be reset by the 'defer' any way for_array(k, decl->deps.entries) { Entity *dep = decl->deps.entries[k].ptr; - add_declaration_dependency(c, dep); // TODO(bill): Should this be here? + add_declaration_dependency(c, dep); // TODO(bill): Should this be here? } } } @@ -6519,6 +6519,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type decl = make_decl_info(ctx.allocator, ctx.scope, ctx.decl); decl->proc_lit = node; ctx.decl = decl; + defer (ctx.decl = ctx.decl->parent); if (pl->tags != 0) { error(node, "A procedure literal cannot have tags"); diff --git a/src/checker.cpp b/src/checker.cpp index fc8cb5c63..9fa6d4555 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1445,6 +1445,14 @@ void add_min_dep_type_info(Checker *c, Type *t) { add_min_dep_type_info(c, t_type_info_float); add_min_dep_type_info(c, t_f64); break; + case Basic_quaternion128: + add_min_dep_type_info(c, t_type_info_float); + add_min_dep_type_info(c, t_f32); + break; + case Basic_quaternion256: + add_min_dep_type_info(c, t_type_info_float); + add_min_dep_type_info(c, t_f64); + break; } break; @@ -1779,6 +1787,7 @@ Array generate_entity_dependency_graph(CheckerInfo *info) { EntityGraphNode *n = G[i]; n->index = i; n->dep_count = n->succ.entries.count; + GB_ASSERT(n->dep_count >= 0); } From b311540b1672129e87a7249650a19cf11d2fccef Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 31 Aug 2019 14:48:56 +0100 Subject: [PATCH 052/143] Make `require_results` an attribute rather than a suffix tag for procedures --- core/odin/ast/ast.odin | 1 - core/odin/parser/parser.odin | 2 -- src/check_decl.cpp | 7 +++---- src/checker.cpp | 6 ++++++ src/checker.hpp | 1 + src/parser.cpp | 6 +++++- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 3655a601d..87893e0e4 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -5,7 +5,6 @@ import "core:odin/token" Proc_Tag :: enum { Bounds_Check, No_Bounds_Check, - Require_Results, } Proc_Tags :: distinct bit_set[Proc_Tag; u32]; diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index a9961fafd..1f5add69a 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1745,8 +1745,6 @@ parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) { ident := expect_token(p, token.Ident); switch ident.text { - case "require_results": - tags |= {.Require_Results}; case "bounds_check": tags |= {.Bounds_Check}; case "no_bounds_check": diff --git a/src/check_decl.cpp b/src/check_decl.cpp index b5b9dc61d..7e019d82b 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -654,7 +654,6 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { bool is_foreign = e->Procedure.is_foreign; bool is_export = e->Procedure.is_export; - bool is_require_results = (pl->tags & ProcTag_require_results) != 0; if (e->pkg != nullptr && e->token.string == "main") { if (pt->param_count != 0 || @@ -714,10 +713,10 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { } } - if (pt->result_count == 0 && is_require_results) { - error(pl->type, "'#require_results' is not needed on a procedure with no results"); + if (pt->result_count == 0 && ac.require_results) { + error(pl->type, "'require_results' is not needed on a procedure with no results"); } else { - pt->require_results = is_require_results; + pt->require_results = ac.require_results; } if (ac.link_name.len > 0) { diff --git a/src/checker.cpp b/src/checker.cpp index 9fa6d4555..b00b4bbac 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2187,6 +2187,12 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { error(elem, "Expected a string value for '%.*s'", LIT(name)); } return true; + } else if (name == "require_results") { + if (value != nullptr) { + error(elem, "Expected no value for '%.*s'", LIT(name)); + } + ac->require_results = true; + return true; } return false; } diff --git a/src/checker.hpp b/src/checker.hpp index a37a87b87..58cb01a82 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -97,6 +97,7 @@ struct DeferredProcedure { struct AttributeContext { bool is_export; bool is_static; + bool require_results; String link_name; String link_prefix; isize init_expr_list_count; diff --git a/src/parser.cpp b/src/parser.cpp index 34a42ba3d..e92489020 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1855,7 +1855,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { } if (tags != 0) { - syntax_error(token, "A procedure type cannot have tags"); + syntax_error(token, "A procedure type cannot have suffix tags"); } return type; @@ -2828,6 +2828,10 @@ Ast *parse_proc_type(AstFile *f, Token proc_token) { u64 tags = 0; parse_proc_tags(f, &tags); + if ((tags & ProcTag_require_results) != 0) { + syntax_error(f->curr_token, "#require_results has now been replaced as an attribute @(require_results) on the declaration"); + tags &= ~ProcTag_require_results; + } bool is_generic = false; From b9d3129fb3a4ba7ef49cea69d086a7f705819f2e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 31 Aug 2019 20:13:28 +0100 Subject: [PATCH 053/143] `where` clauses for procedure literals --- core/odin/ast/ast.odin | 2 + core/odin/parser/parser.odin | 18 ++++++ core/odin/token/token.odin | 2 + examples/demo/demo.odin | 65 ++++++++++++++++++++ src/check_decl.cpp | 33 +++++++--- src/check_expr.cpp | 115 +++++++++++++++++++++++++++++++++-- src/checker.cpp | 8 +++ src/parser.cpp | 50 +++++++++++---- src/parser.hpp | 2 + src/tokenizer.cpp | 1 + 10 files changed, 272 insertions(+), 24 deletions(-) diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 87893e0e4..f1ea79584 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -99,6 +99,8 @@ Proc_Lit :: struct { body: ^Stmt, tags: Proc_Tags, inlining: Proc_Inlining, + where_token: token.Token, + where_clauses: []^Expr, } Comp_Lit :: struct { diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 1f5add69a..a0d4d639e 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1985,13 +1985,29 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { type := parse_proc_type(p, tok); + where_token: token.Token; + where_clauses: []^ast.Expr; + if (p.curr_tok.kind == token.Where) { + where_token = expect_token(p, token.Where); + prev_level := p.expr_level; + p.expr_level = -1; + where_clauses = parse_rhs_expr_list(p); + p.expr_level = prev_level; + } + if p.allow_type && p.expr_level < 0 { + if where_token.kind != token.Invalid { + error(p, where_token.pos, "'where' clauses are not allowed on procedure types"); + } return type; } body: ^ast.Stmt; if allow_token(p, token.Undef) { // Okay + if where_token.kind != token.Invalid { + error(p, where_token.pos, "'where' clauses are not allowed on procedure literals without a defined body (replaced with ---"); + } } else if p.curr_tok.kind == token.Open_Brace { prev_proc := p.curr_proc; p.curr_proc = type; @@ -2009,6 +2025,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { pl := ast.new(ast.Proc_Lit, tok.pos, end_pos(p.prev_tok)); pl.type = type; pl.body = body; + pl.where_token = where_token; + pl.where_clauses = where_clauses; return pl; case token.Dollar: diff --git a/core/odin/token/token.odin b/core/odin/token/token.odin index d41fa6d05..737ff3586 100644 --- a/core/odin/token/token.odin +++ b/core/odin/token/token.odin @@ -118,6 +118,7 @@ using Kind :: enum u32 { Package, Typeid, When, + Where, If, Else, For, @@ -252,6 +253,7 @@ tokens := [Kind.COUNT]string { "package", "typeid", "when", + "where", "if", "else", "for", diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index fe390e5b0..92d1c17bd 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -4,6 +4,7 @@ import "core:fmt" import "core:mem" import "core:os" import "core:reflect" +import "intrinsics" when os.OS == "windows" { import "core:thread" @@ -1094,6 +1095,69 @@ inline_for_statement :: proc() { } } +procedure_where_clauses :: proc() { + fmt.println("\n#procedure 'where' clauses"); + + { // Sanity checks + simple_sanity_check :: proc(x: [2]int) + where len(x) > 1, + type_of(x) == [2]int { + fmt.println(x); + } + } + { // Parametric polymorphism checks + cross_2d :: proc(a, b: $T/[2]$E) -> E + where intrinsics.type_is_numeric(E) { + return a.x*b.y - a.y*b.x; + } + cross_3d :: proc(a, b: $T/[3]$E) -> T + where intrinsics.type_is_numeric(E) { + x := a.y*b.z - a.z*b.y; + y := a.z*b.x - a.x*b.z; + z := a.x*b.y - a.y*b.z; + return T{x, y, z}; + } + + a := [2]int{1, 2}; + b := [2]int{5, -3}; + fmt.println(cross_2d(a, b)); + + x := [3]f32{1, 4, 9}; + y := [3]f32{-5, 0, 3}; + fmt.println(cross_3d(x, y)); + + // Failure case + // i := [2]bool{true, false}; + // j := [2]bool{false, true}; + // fmt.println(cross_2d(i, j)); + + } + + { // Procedure groups usage + foo :: proc(x: [$N]int) -> bool + where N > 2 { + fmt.println(#procedure, "was called with the parameter", x); + return true; + } + + bar :: proc(x: [$N]int) -> bool + where 0 < N, + N <= 2 { + fmt.println(#procedure, "was called with the parameter", x); + return false; + } + + baz :: proc{foo, bar}; + + x := [3]int{1, 2, 3}; + y := [2]int{4, 9}; + ok_x := baz(x); + ok_y := baz(y); + assert(ok_x == true); + assert(ok_y == false); + } +} + main :: proc() { when true { general_stuff(); @@ -1115,5 +1179,6 @@ main :: proc() { reflection(); quaternions(); inline_for_statement(); + procedure_where_clauses(); } } diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 7e019d82b..156c874ce 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -936,7 +936,6 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d) ptr_set_destroy(&entity_set); - for_array(j, pge->entities) { Entity *p = pge->entities[j]; if (p->type == t_invalid) { @@ -962,27 +961,40 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d) defer (end_error_block()); ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type); - switch (kind) { + bool both_have_where_clauses = false; + if (p->decl_info->proc_lit != nullptr && q->decl_info->proc_lit != nullptr) { + GB_ASSERT(p->decl_info->proc_lit->kind == Ast_ProcLit); + GB_ASSERT(q->decl_info->proc_lit->kind == Ast_ProcLit); + auto pl = &p->decl_info->proc_lit->ProcLit; + auto ql = &q->decl_info->proc_lit->ProcLit; + + // Allow collisions if the procedures both have 'where' clauses and are both polymorphic + bool pw = pl->where_token.kind != Token_Invalid && is_type_polymorphic(p->type, true); + bool qw = ql->where_token.kind != Token_Invalid && is_type_polymorphic(q->type, true); + both_have_where_clauses = pw && qw; + } + + if (!both_have_where_clauses) switch (kind) { case ProcOverload_Identical: - error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name)); + error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name)); is_invalid = true; break; // case ProcOverload_CallingConvention: - // error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name)); + // error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name)); // is_invalid = true; // break; case ProcOverload_ParamVariadic: - error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in this scope", LIT(name)); + error(p->token, "Overloaded procedure '%.*s' as the same type as another procedure in the procedure group '%.*s'", LIT(name), LIT(proc_group_name)); is_invalid = true; break; case ProcOverload_ResultCount: case ProcOverload_ResultTypes: - error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in this scope", LIT(name)); + error(p->token, "Overloaded procedure '%.*s' as the same parameters but different results in the procedure group '%.*s'", LIT(name), LIT(proc_group_name)); is_invalid = true; break; case ProcOverload_Polymorphic: #if 0 - error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in this scope which is not allowed", LIT(name)); + error(p->token, "Overloaded procedure '%.*s' has a polymorphic counterpart in the procedure group '%.*s' which is not allowed", LIT(name), LIT(proc_group_name)); is_invalid = true; #endif break; @@ -1163,6 +1175,13 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty } } + + bool where_clause_ok = evaluate_where_clauses(ctx, decl, true); + if (!where_clause_ok) { + // NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed + return; + } + check_open_scope(ctx, body); { for_array(i, using_entities) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 86cba0f94..4c8cd61a7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5470,6 +5470,74 @@ Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize return lhs; } + +bool evaluate_where_clauses(CheckerContext *ctx, DeclInfo *decl, bool print_err) { + Ast *proc_lit = decl->proc_lit; + GB_ASSERT(proc_lit != nullptr); + GB_ASSERT(proc_lit->kind == Ast_ProcLit); + + if (proc_lit->ProcLit.where_token.kind != Token_Invalid) { + auto &clauses = proc_lit->ProcLit.where_clauses; + for_array(i, clauses) { + Ast *clause = clauses[i]; + Operand o = {}; + check_expr(ctx, &o, clause); + if (o.mode != Addressing_Constant) { + if (print_err) error(clause, "'where' clauses expect a constant boolean evaluation"); + return false; + } else if (o.value.kind != ExactValue_Bool) { + if (print_err) error(clause, "'where' clauses expect a constant boolean evaluation"); + return false; + } else if (!o.value.value_bool) { + if (print_err) { + gbString str = expr_to_string(clause); + error(clause, "'where' clause evaluated to false:\n\t%s", str); + gb_string_free(str); + + if (decl->scope != nullptr) { + isize print_count = 0; + for_array(j, decl->scope->elements.entries) { + Entity *e = decl->scope->elements.entries[j].value; + switch (e->kind) { + case Entity_TypeName: { + if (print_count == 0) error_line("\n\tWith the following definitions:\n"); + + gbString str = type_to_string(e->type); + error_line("\t\t%.*s :: %s;\n", LIT(e->token.string), str); + gb_string_free(str); + print_count += 1; + break; + } + case Entity_Constant: { + if (print_count == 0) error_line("\n\tWith the following definitions:\n"); + + gbString str = exact_value_to_string(e->Constant.value); + if (is_type_untyped(e->type)) { + error_line("\t\t%.*s :: %s;\n", LIT(e->token.string), str); + } else { + gbString t = type_to_string(e->type); + error_line("\t\t%.*s : %s : %s;\n", LIT(e->token.string), t, str); + gb_string_free(t); + } + gb_string_free(str); + + print_count += 1; + break; + } + } + } + } + + } + return false; + } + } + } + + return true; +} + + CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type *proc_type, Ast *call) { ast_node(ce, CallExpr, call); @@ -5710,11 +5778,26 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type err = call_checker(&ctx, call, pt, p, operands, CallArgumentMode_NoErrors, &data); - if (err == CallArgumentError_None) { - valids[valid_count].index = i; - valids[valid_count].score = data.score; - valid_count++; + if (err != CallArgumentError_None) { + continue; } + if (data.gen_entity != nullptr) { + Entity *e = data.gen_entity; + DeclInfo *decl = data.gen_entity->decl_info; + ctx.scope = decl->scope; + ctx.decl = decl; + ctx.proc_name = e->token.string; + ctx.curr_proc_decl = decl; + ctx.curr_proc_sig = e->type; + + if (!evaluate_where_clauses(&ctx, decl, false)) { + continue; + } + } + + valids[valid_count].index = i; + valids[valid_count].score = data.score; + valid_count++; } } @@ -5822,7 +5905,29 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type if (proc->kind == Entity_Variable) { sep = ":="; } - error_line("\t%.*s %s %s at %.*s(%td:%td)\n", LIT(name), sep, pt, LIT(pos.file), pos.line, pos.column); + error_line("\t%.*s %s %s ", LIT(name), sep, pt); + if (proc->decl_info->proc_lit != nullptr) { + GB_ASSERT(proc->decl_info->proc_lit->kind == Ast_ProcLit); + auto *pl = &proc->decl_info->proc_lit->ProcLit; + if (pl->where_token.kind != Token_Invalid) { + error_line("\n\t\twhere "); + for_array(j, pl->where_clauses) { + Ast *clause = pl->where_clauses[j]; + if (j != 0) { + error_line("\t\t "); + } + gbString str = expr_to_string(clause); + error_line("%s", str); + gb_string_free(str); + + if (j != pl->where_clauses.count-1) { + error_line(","); + } + } + error_line("\n\t"); + } + } + error_line("at %.*s(%td:%td)\n", LIT(pos.file), pos.line, pos.column); // error_line("\t%.*s %s %s at %.*s(%td:%td) %lld\n", LIT(name), sep, pt, LIT(pos.file), pos.line, pos.column, valids[i].score); } result_type = t_invalid; diff --git a/src/checker.cpp b/src/checker.cpp index b00b4bbac..8fe71b63c 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3697,6 +3697,14 @@ void check_proc_info(Checker *c, ProcInfo pi) { return; } + if (pt->is_polymorphic && pt->is_poly_specialized) { + Entity *e = pi.decl->entity; + if ((e->flags & EntityFlag_Used) == 0) { + // NOTE(bill, 2019-08-31): It was never used, don't check + return; + } + } + bool bounds_check = (pi.tags & ProcTag_bounds_check) != 0; bool no_bounds_check = (pi.tags & ProcTag_no_bounds_check) != 0; diff --git a/src/parser.cpp b/src/parser.cpp index e92489020..8490b0e00 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -144,6 +144,7 @@ Ast *clone_ast(Ast *node) { case Ast_ProcLit: n->ProcLit.type = clone_ast(n->ProcLit.type); n->ProcLit.body = clone_ast(n->ProcLit.body); + n->ProcLit.where_clauses = clone_ast_array(n->ProcLit.where_clauses); break; case Ast_CompoundLit: n->CompoundLit.type = clone_ast(n->CompoundLit.type); @@ -612,11 +613,13 @@ Ast *ast_proc_group(AstFile *f, Token token, Token open, Token close, Array const &where_clauses) { Ast *result = alloc_ast_node(f, Ast_ProcLit); result->ProcLit.type = type; result->ProcLit.body = body; result->ProcLit.tags = tags; + result->ProcLit.where_token = where_token; + result->ProcLit.where_clauses = where_clauses; return result; } @@ -1827,15 +1830,41 @@ Ast *parse_operand(AstFile *f, bool lhs) { } Ast *type = parse_proc_type(f, token); + Token where_token = {}; + Array where_clauses = {}; + u64 tags = 0; + + if (f->curr_token.kind == Token_where) { + where_token = expect_token(f, Token_where); + isize prev_level = f->expr_level; + f->expr_level = -1; + where_clauses = parse_rhs_expr_list(f); + f->expr_level = prev_level; + } + + parse_proc_tags(f, &tags); + if ((tags & ProcTag_require_results) != 0) { + syntax_error(f->curr_token, "#require_results has now been replaced as an attribute @(require_results) on the declaration"); + tags &= ~ProcTag_require_results; + } + GB_ASSERT(type->kind == Ast_ProcType); + type->ProcType.tags = tags; if (f->allow_type && f->expr_level < 0) { + if (tags != 0) { + syntax_error(token, "A procedure type cannot have suffix tags"); + } + if (where_token.kind != Token_Invalid) { + syntax_error(where_token, "'where' clauses are not allowed on procedure types"); + } return type; } - u64 tags = type->ProcType.tags; - if (allow_token(f, Token_Undef)) { - return ast_proc_lit(f, type, nullptr, tags); + if (where_token.kind != Token_Invalid) { + syntax_error(where_token, "'where' clauses are not allowed on procedure literals without a defined body (replaced with ---)"); + } + return ast_proc_lit(f, type, nullptr, tags, where_token, where_clauses); } else if (f->curr_token.kind == Token_OpenBrace) { Ast *curr_proc = f->curr_proc; Ast *body = nullptr; @@ -1843,7 +1872,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { body = parse_body(f); f->curr_proc = curr_proc; - return ast_proc_lit(f, type, body, tags); + return ast_proc_lit(f, type, body, tags, where_token, where_clauses); } else if (allow_token(f, Token_do)) { Ast *curr_proc = f->curr_proc; Ast *body = nullptr; @@ -1851,12 +1880,15 @@ Ast *parse_operand(AstFile *f, bool lhs) { body = convert_stmt_to_body(f, parse_stmt(f)); f->curr_proc = curr_proc; - return ast_proc_lit(f, type, body, tags); + return ast_proc_lit(f, type, body, tags, where_token, where_clauses); } if (tags != 0) { syntax_error(token, "A procedure type cannot have suffix tags"); } + if (where_token.kind != Token_Invalid) { + syntax_error(where_token, "'where' clauses are not allowed on procedure types"); + } return type; } @@ -2827,12 +2859,6 @@ Ast *parse_proc_type(AstFile *f, Token proc_token) { results = parse_results(f, &diverging); u64 tags = 0; - parse_proc_tags(f, &tags); - if ((tags & ProcTag_require_results) != 0) { - syntax_error(f->curr_token, "#require_results has now been replaced as an attribute @(require_results) on the declaration"); - tags &= ~ProcTag_require_results; - } - bool is_generic = false; for_array(i, params->FieldList.list) { diff --git a/src/parser.hpp b/src/parser.hpp index 32398592e..26536fe56 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -229,6 +229,8 @@ enum StmtAllowFlag { Ast *body; \ u64 tags; \ ProcInlining inlining; \ + Token where_token; \ + Array where_clauses; \ }) \ AST_KIND(CompoundLit, "compound literal", struct { \ Ast *type; \ diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 618de54b9..d5e04aa1e 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -86,6 +86,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \ TOKEN_KIND(Token_package, "package"), \ TOKEN_KIND(Token_typeid, "typeid"), \ TOKEN_KIND(Token_when, "when"), \ + TOKEN_KIND(Token_where, "where"), \ TOKEN_KIND(Token_if, "if"), \ TOKEN_KIND(Token_else, "else"), \ TOKEN_KIND(Token_for, "for"), \ From 657103c4cff8f63cfa617d8c4371fd29df7b41a2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 1 Sep 2019 20:02:39 +0100 Subject: [PATCH 054/143] ThreadPool for the parser --- core/log/file_console_logger.odin | 32 ++-- core/sort/sort.odin | 7 +- src/check_expr.cpp | 2 +- src/common.cpp | 5 +- src/gb/gb.h | 2 +- src/parser.cpp | 243 ++++++------------------------ src/parser.hpp | 13 ++ 7 files changed, 86 insertions(+), 218 deletions(-) diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin index 3778d3e53..6bddf7ffb 100644 --- a/core/log/file_console_logger.odin +++ b/core/log/file_console_logger.odin @@ -14,18 +14,18 @@ Level_Headers := []string{ }; Default_Console_Logger_Opts :: Options{ - Option.Level, - Option.Terminal_Color, - Option.Short_File_Path, - Option.Line, - Option.Procedure, + .Level, + .Terminal_Color, + .Short_File_Path, + .Line, + .Procedure, } | Full_Timestamp_Opts; Default_File_Logger_Opts :: Options{ - Option.Level, - Option.Short_File_Path, - Option.Line, - Option.Procedure, + .Level, + .Short_File_Path, + .Line, + .Procedure, } | Full_Timestamp_Opts; @@ -109,10 +109,10 @@ do_level_header :: proc(opts : Options, level : Level, str : ^strings.Builder) { case Level.Error, Level.Fatal : col = RED; } - if Option.Level in opts { - if Option.Terminal_Color in opts do fmt.sbprint(str, col); + if .Level in opts { + if .Terminal_Color in opts do fmt.sbprint(str, col); fmt.sbprint(str, Level_Headers[level]); - if Option.Terminal_Color in opts do fmt.sbprint(str, RESET); + if .Terminal_Color in opts do fmt.sbprint(str, RESET); } } @@ -120,7 +120,7 @@ do_location_header :: proc(opts : Options, buf : ^strings.Builder, location := # if Location_Header_Opts & opts != nil do fmt.sbprint(buf, "["); else do return; file := location.file_path; - if Option.Short_File_Path in opts { + if .Short_File_Path in opts { when os.OS == "windows" do delimiter := '\\'; else do delimiter := '/'; last := 0; for r, i in location.file_path do if r == delimiter do last = i+1; @@ -129,13 +129,13 @@ do_location_header :: proc(opts : Options, buf : ^strings.Builder, location := # if Location_File_Opts & opts != nil do fmt.sbprint(buf, file); - if Option.Procedure in opts { + if .Procedure in opts { if Location_File_Opts & opts != nil do fmt.sbprint(buf, "."); fmt.sbprintf(buf, "%s()", location.procedure); } - if Option.Line in opts { - if Location_File_Opts & opts != nil || Option.Procedure in opts do fmt.sbprint(buf, ":"); + if .Line in opts { + if Location_File_Opts & opts != nil || .Procedure in opts do fmt.sbprint(buf, ":"); fmt.sbprint(buf, location.line); } diff --git a/core/sort/sort.odin b/core/sort/sort.odin index 3c8366def..86953d7dd 100644 --- a/core/sort/sort.odin +++ b/core/sort/sort.odin @@ -1,6 +1,7 @@ package sort import "core:mem" +import "intrinsics" bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { assert(f != nil); @@ -26,7 +27,7 @@ bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { } } -bubble_sort :: proc(array: $A/[]$T) { +bubble_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) { count := len(array); init_j, last_j := 0, count-1; @@ -73,7 +74,7 @@ quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { quick_sort_proc(a[i:n], f); } -quick_sort :: proc(array: $A/[]$T) { +quick_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) { a := array; n := len(a); if n < 2 do return; @@ -146,7 +147,7 @@ merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { if M & 1 == 0 do copy(arr2, arr1); } -merge_sort :: proc(array: $A/[]$T) { +merge_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) { merge_slices :: proc(arr1, arr2, out: A) { N1, N2 := len(arr1), len(arr2); i, j := 0, 0; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4c8cd61a7..ca1aed970 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -159,7 +159,7 @@ isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0 src = base_type(src); if (!is_type_struct(src)) { - return false; + return 0; } for_array(i, src->Struct.fields) { diff --git a/src/common.cpp b/src/common.cpp index 8085e895c..db6505a36 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -10,13 +10,11 @@ #define GB_IMPLEMENTATION #include "gb/gb.h" - #include #include #include - template gb_inline U bit_cast(V &v) { return reinterpret_cast(v); } @@ -331,7 +329,7 @@ void mul_overflow_u64(u64 x, u64 y, u64 *lo, u64 *hi) { #include "ptr_set.cpp" #include "string_set.cpp" #include "priority_queue.cpp" - +#include "thread_pool.cpp" gb_global String global_module_path = {0}; @@ -873,7 +871,6 @@ ReadDirectoryError read_directory(String path, Array *fi) { info.size = size; info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; array_add(fi, info); - } while (FindNextFileW(find_file, &file_data)); if (fi->count == 0) { diff --git a/src/gb/gb.h b/src/gb/gb.h index adeb554b2..5e74ff2d8 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -4591,7 +4591,7 @@ gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); } gb_inline void gb_semaphore_init (gbSemaphore *s) { s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL); } gb_inline void gb_semaphore_destroy(gbSemaphore *s) { CloseHandle(s->win32_handle); } gb_inline void gb_semaphore_post (gbSemaphore *s, i32 count) { ReleaseSemaphore(s->win32_handle, count, NULL); } - gb_inline void gb_semaphore_wait (gbSemaphore *s) { WaitForSingleObject(s->win32_handle, INFINITE); } + gb_inline void gb_semaphore_wait (gbSemaphore *s) { WaitForSingleObjectEx(s->win32_handle, INFINITE, FALSE); } #elif defined(GB_SYSTEM_OSX) gb_inline void gb_semaphore_init (gbSemaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); } diff --git a/src/parser.cpp b/src/parser.cpp index 8490b0e00..a210eb661 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4207,16 +4207,30 @@ void parser_add_package(Parser *p, AstPackage *pkg) { error(f->package_token, "Non-unique package name '%.*s'", LIT(pkg->name)); GB_ASSERT((*found)->files.count > 0); TokenPos pos = (*found)->files[0]->package_token.pos; - gb_printf_err("\tpreviously declared at %.*s(%td:%td)", LIT(pos.file), pos.line, pos.column); + error_line("\tpreviously declared at %.*s(%td:%td)\n", LIT(pos.file), pos.line, pos.column); } else { map_set(&p->package_map, key, pkg); } } } +ParseFileError process_imported_file(Parser *p, ImportedFile const &imported_file); + +WORKER_TASK_PROC(parser_worker_proc) { + ParserWorkerData *wd = cast(ParserWorkerData *)data; + ParseFileError err = process_imported_file(wd->parser, wd->imported_file); + return cast(isize)err; +} + + void parser_add_file_to_process(Parser *p, AstPackage *pkg, FileInfo fi, TokenPos pos) { + // TODO(bill): Use a better allocator ImportedFile f = {pkg, fi, pos, p->files_to_process.count}; + auto wd = gb_alloc_item(heap_allocator(), ParserWorkerData); + wd->parser = p; + wd->imported_file = f; array_add(&p->files_to_process, f); + thread_pool_add_task(&parser_thread_pool, parser_worker_proc, wd); } @@ -4717,9 +4731,9 @@ bool parse_file(Parser *p, AstFile *f) { } -ParseFileError process_imported_file(Parser *p, ImportedFile imported_file) { +ParseFileError process_imported_file(Parser *p, ImportedFile const &imported_file) { AstPackage *pkg = imported_file.pkg; - FileInfo *fi = &imported_file.fi; + FileInfo const *fi = &imported_file.fi; TokenPos pos = imported_file.pos; AstFile *file = gb_alloc_item(heap_allocator(), AstFile); @@ -4737,35 +4751,32 @@ ParseFileError process_imported_file(Parser *p, ImportedFile imported_file) { error(pos, "Initial file is empty - %.*s\n", LIT(p->init_fullpath)); gb_exit(1); } - goto skip; - } + } else { + switch (err) { + case ParseFile_WrongExtension: + error(pos, "Failed to parse file: %.*s; invalid file extension: File must have the extension '.odin'", LIT(fi->name)); + break; + case ParseFile_InvalidFile: + error(pos, "Failed to parse file: %.*s; invalid file or cannot be found", LIT(fi->name)); + break; + case ParseFile_Permission: + error(pos, "Failed to parse file: %.*s; file permissions problem", LIT(fi->name)); + break; + case ParseFile_NotFound: + error(pos, "Failed to parse file: %.*s; file cannot be found ('%.*s')", LIT(fi->name), LIT(fi->fullpath)); + break; + case ParseFile_InvalidToken: + error(err_pos, "Failed to parse file: %.*s; invalid token found in file", LIT(fi->name)); + break; + case ParseFile_EmptyFile: + error(pos, "Failed to parse file: %.*s; file contains no tokens", LIT(fi->name)); + break; + } - switch (err) { - case ParseFile_WrongExtension: - error(pos, "Failed to parse file: %.*s; invalid file extension: File must have the extension '.odin'", LIT(fi->name)); - break; - case ParseFile_InvalidFile: - error(pos, "Failed to parse file: %.*s; invalid file or cannot be found", LIT(fi->name)); - break; - case ParseFile_Permission: - error(pos, "Failed to parse file: %.*s; file permissions problem", LIT(fi->name)); - break; - case ParseFile_NotFound: - error(pos, "Failed to parse file: %.*s; file cannot be found ('%.*s')", LIT(fi->name), LIT(fi->fullpath)); - break; - case ParseFile_InvalidToken: - error(err_pos, "Failed to parse file: %.*s; invalid token found in file", LIT(fi->name)); - break; - case ParseFile_EmptyFile: - error(pos, "Failed to parse file: %.*s; file contains no tokens", LIT(fi->name)); - break; + return err; } - - return err; } - -skip: if (parse_file(p, file)) { gb_mutex_lock(&p->file_add_mutex); defer (gb_mutex_unlock(&p->file_add_mutex)); @@ -4781,66 +4792,26 @@ skip: p->total_line_count += file->tokenizer.line_count; p->total_token_count += file->tokens.count; } + return ParseFile_None; } -struct ParserWorkerThreadData { - Parser *parser; - ParseFileError err; - - gbSemaphore resume_work; - gbMutex lock; - - bool error_available; - bool is_working; - bool should_exit; -}; - - -GB_THREAD_PROC(parse_worker_file_proc) { - GB_ASSERT(thread != nullptr); - - ParserWorkerThreadData* data = cast(ParserWorkerThreadData*) thread->user_data; - - for(;;) { - gb_semaphore_wait(&data->resume_work); - - gb_mutex_lock(&data->lock); - if (data->should_exit) { - gb_mutex_unlock(&data->lock); - return isize(0); - } - - Parser *p = data->parser; - isize index = thread->user_index; - gb_mutex_lock(&p->file_add_mutex); - auto file_to_process = p->files_to_process[index]; - gb_mutex_unlock(&p->file_add_mutex); - data->err = process_imported_file(p, file_to_process); - - data->error_available = true; - data->is_working = false; - gb_mutex_unlock(&data->lock); - } - - //GB_PANIC("A worker thread should not be able to reach the end!!!"); -} ParseFileError parse_packages(Parser *p, String init_filename) { GB_ASSERT(init_filename.text[init_filename.len] == 0); - // char *fullpath_str = gb_path_get_full_name(heap_allocator(), cast(char const *)&init_filename[0]); - // String init_fullpath = string_trim_whitespace(make_string_c(fullpath_str)); + isize thread_count = gb_max(build_context.thread_count, 1); + thread_pool_init(&parser_thread_pool, heap_allocator(), thread_count, "ParserWork"); + String init_fullpath = path_to_full_path(heap_allocator(), init_filename); if (!path_is_directory(init_fullpath)) { String const ext = str_lit(".odin"); if (!string_ends_with(init_fullpath, ext)) { - gb_printf_err("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename)); + error_line("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename)); return ParseFile_WrongExtension; } } - TokenPos init_pos = {}; if (!build_context.generate_docs) { String s = get_fullpath_core(heap_allocator(), str_lit("runtime")); @@ -4850,131 +4821,17 @@ ParseFileError parse_packages(Parser *p, String init_filename) { try_add_import_path(p, init_fullpath, init_fullpath, init_pos, Package_Init); p->init_fullpath = init_fullpath; -#if 1 - isize thread_count = gb_max(build_context.thread_count, 1); - if (thread_count > 1) { - isize volatile curr_import_index = 0; + thread_pool_start(&parser_thread_pool); + thread_pool_kick_and_wait(&parser_thread_pool); -#if 0 - //NOTE(thebirk): Leaving this piece of code behind if it turns out we need it, yes I know git exists - - isize initial_file_count = p->files_to_process.count; - // NOTE(bill): Make sure that these are in parsed in this order - for (isize i = 0; i < initial_file_count; i++) { - ParseFileError err = process_imported_file(p, p->files_to_process[i]); - if (err != ParseFile_None) { - return err; - } - curr_import_index++; - } -#endif - - auto worker_threads_data = array_make(heap_allocator(), thread_count); - defer (array_free(&worker_threads_data)); - - for_array(i, worker_threads_data) { - ParserWorkerThreadData *data = &worker_threads_data[i]; - gb_mutex_init(&data->lock); - gb_semaphore_init(&data->resume_work); - data->parser = p; - data->err = ParseFile_None; - data->should_exit = false; - data->error_available = false; - data->is_working = false; - } - defer(for_array(i, worker_threads_data) { - ParserWorkerThreadData *data = &worker_threads_data[i]; - gb_mutex_destroy(&data->lock); - gb_semaphore_destroy(&data->resume_work); - }); - - auto worker_threads = array_make(heap_allocator(), thread_count); - defer (array_free(&worker_threads)); - - for_array(i, worker_threads) { - gbThread *t = &worker_threads[i]; - gb_thread_init(t); - //NOTE(thebirk): This crashes on linux. In addition to that the method used on windows does - // not get picked up by a lot of tools look into using SetThreadDescription - // when running on new enough windows 10 builds - //char buffer[32]; - //gb_snprintf(buffer, 32, "Parser Worker #%ll", i); - //gb_thread_set_name(t, buffer); - gb_thread_start(t, parse_worker_file_proc, &worker_threads_data[i]); - } - defer(for_array(i, worker_threads) { - gb_thread_destroy(&worker_threads[i]); - }); - - auto errors = array_make(heap_allocator(), 0, 16); - - for (;;) { - int num_alive = 0; - - for_array(i, worker_threads) { - gbThread *t = &worker_threads[i]; - ParserWorkerThreadData *data = &worker_threads_data[i]; - - if (!data->is_working && gb_mutex_try_lock(&data->lock)) { - if (data->error_available) { - auto curr_err = data->err; - if (curr_err != ParseFile_None) { - array_add(&errors, curr_err); - } - - data->error_available = false; - } - - if (curr_import_index < p->files_to_process.count) { - t->user_index = curr_import_index; - curr_import_index++; - num_alive += 1; - - gb_semaphore_release(&data->resume_work); - data->is_working = true; - } - - gb_mutex_unlock(&data->lock); - } else { - //NOTE(thebirk): If we cant lock a thread it must be working - num_alive += 1; - } - } - - if ((num_alive == 0) && (curr_import_index >= p->files_to_process.count)) { - break; - } - - gb_yield(); - } - - //NOTE(thebirk): Signal all workers to exit - for_array(i, worker_threads_data) { - ParserWorkerThreadData* data = &worker_threads_data[i]; - data->should_exit = true; - gb_semaphore_release(&data->resume_work); - } - - if (errors.count > 0) { - return errors[errors.count-1]; - } - } else { - for_array(i, p->files_to_process) { - ParseFileError err = process_imported_file(p, p->files_to_process[i]); - if (err != ParseFile_None) { - return err; - } - } - } -#else - for_array(i, p->files_to_process) { - ImportedFile f = p->files_to_process[i]; - ParseFileError err = process_imported_file(p, f); + // NOTE(bill): Get the last error and use that + for (isize i = parser_thread_pool.threads.count-1; i >= 0; i--) { + gbThread *t = &parser_thread_pool.threads[i]; + ParseFileError err = cast(ParseFileError)t->return_value; if (err != ParseFile_None) { return err; } } -#endif return ParseFile_None; } diff --git a/src/parser.hpp b/src/parser.hpp index 26536fe56..56d9b74c7 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -141,6 +141,19 @@ struct Parser { gbMutex file_decl_mutex; }; + +gb_global ThreadPool parser_thread_pool = {}; + +struct ParserWorkerData { + Parser *parser; + ImportedFile imported_file; +}; + + + + + + enum ProcInlining { ProcInlining_none = 0, ProcInlining_inline = 1, From 97dece15d73a6c4830f5bf01d82014cb0eeff062 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 1 Sep 2019 22:18:55 +0100 Subject: [PATCH 055/143] Minor changes --- src/gb/gb.h | 31 ++++++++++++++++++++++++------- src/parser.cpp | 5 +---- src/parser.hpp | 2 +- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/gb/gb.h b/src/gb/gb.h index 5e74ff2d8..65b8b2ff6 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -918,7 +918,10 @@ GB_DEF void gb_lfence (void); #if defined(GB_SYSTEM_WINDOWS) -typedef struct gbSemaphore { void *win32_handle; } gbSemaphore; +typedef struct gbSemaphore { + void *win32_handle; + LONG count; +} gbSemaphore; #elif defined(GB_SYSTEM_OSX) typedef struct gbSemaphore { semaphore_t osx_handle; } gbSemaphore; #elif defined(GB_SYSTEM_UNIX) @@ -930,7 +933,7 @@ typedef struct gbSemaphore { sem_t unix_handle; } gbSemaphore; GB_DEF void gb_semaphore_init (gbSemaphore *s); GB_DEF void gb_semaphore_destroy(gbSemaphore *s); GB_DEF void gb_semaphore_post (gbSemaphore *s, i32 count); -GB_DEF void gb_semaphore_release(gbSemaphore *s); // NOTE(bill): gb_semaphore_post(s, 1) +GB_DEF void gb_semaphore_release(gbSemaphore *s); GB_DEF void gb_semaphore_wait (gbSemaphore *s); @@ -4588,10 +4591,24 @@ gb_inline void gb_lfence(void) { gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); } #if defined(GB_SYSTEM_WINDOWS) - gb_inline void gb_semaphore_init (gbSemaphore *s) { s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL); } - gb_inline void gb_semaphore_destroy(gbSemaphore *s) { CloseHandle(s->win32_handle); } - gb_inline void gb_semaphore_post (gbSemaphore *s, i32 count) { ReleaseSemaphore(s->win32_handle, count, NULL); } - gb_inline void gb_semaphore_wait (gbSemaphore *s) { WaitForSingleObjectEx(s->win32_handle, INFINITE, FALSE); } + gb_inline void gb_semaphore_init(gbSemaphore *s) { + s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL); + s->count = 0; + } + gb_inline void gb_semaphore_destroy(gbSemaphore *s) { + CloseHandle(s->win32_handle); + } + gb_inline void gb_semaphore_post(gbSemaphore *s, i32 count) { + _InterlockedIncrement(&s->count); + if (ReleaseSemaphore(s->win32_handle, count, NULL) == FALSE) { + _InterlockedDecrement(&s->count); + } + } + gb_inline void gb_semaphore_wait(gbSemaphore *s) { + if (WaitForSingleObjectEx(s->win32_handle, INFINITE, FALSE) == WAIT_OBJECT_0) { + _InterlockedDecrement(&s->count); + } + } #elif defined(GB_SYSTEM_OSX) gb_inline void gb_semaphore_init (gbSemaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); } @@ -8975,7 +8992,7 @@ gb_inline void gb_exit(u32 code) { exit(code); } gb_inline void gb_yield(void) { #if defined(GB_SYSTEM_WINDOWS) - Sleep(0); + YieldProcessor(); #else sched_yield(); #endif diff --git a/src/parser.cpp b/src/parser.cpp index a210eb661..e4d21e72a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4164,7 +4164,6 @@ bool init_parser(Parser *p) { map_init(&p->package_map, heap_allocator()); array_init(&p->packages, heap_allocator()); array_init(&p->package_imports, heap_allocator()); - array_init(&p->files_to_process, heap_allocator()); gb_mutex_init(&p->file_add_mutex); gb_mutex_init(&p->file_decl_mutex); return true; @@ -4187,7 +4186,6 @@ void destroy_parser(Parser *p) { #endif array_free(&p->packages); array_free(&p->package_imports); - array_free(&p->files_to_process); string_set_destroy(&p->imported_files); map_destroy(&p->package_map); gb_mutex_destroy(&p->file_add_mutex); @@ -4225,11 +4223,10 @@ WORKER_TASK_PROC(parser_worker_proc) { void parser_add_file_to_process(Parser *p, AstPackage *pkg, FileInfo fi, TokenPos pos) { // TODO(bill): Use a better allocator - ImportedFile f = {pkg, fi, pos, p->files_to_process.count}; + ImportedFile f = {pkg, fi, pos, p->file_to_process_count++}; auto wd = gb_alloc_item(heap_allocator(), ParserWorkerData); wd->parser = p; wd->imported_file = f; - array_add(&p->files_to_process, f); thread_pool_add_task(&parser_thread_pool, parser_worker_proc, wd); } diff --git a/src/parser.hpp b/src/parser.hpp index 56d9b74c7..3da2551f1 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -134,7 +134,7 @@ struct Parser { Map package_map; // Key: String (package name) Array packages; Array package_imports; - Array files_to_process; + isize file_to_process_count; isize total_token_count; isize total_line_count; gbMutex file_add_mutex; From c93872cc1371d60863e2dae6c08f556f32dd5a8a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 1 Sep 2019 22:57:53 +0100 Subject: [PATCH 056/143] Thread pool fixes --- build.bat | 13 ++-- src/thread_pool.cpp | 169 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+), 6 deletions(-) create mode 100644 src/thread_pool.cpp diff --git a/build.bat b/build.bat index 6e5450c2b..334102cf1 100644 --- a/build.bat +++ b/build.bat @@ -4,14 +4,14 @@ set exe_name=odin.exe :: Debug = 0, Release = 1 -set release_mode=0 +set release_mode=1 set compiler_flags= -nologo -Oi -TP -fp:precise -Gm- -MP -FC -GS- -EHsc- -GR- if %release_mode% EQU 0 ( rem Debug - set compiler_flags=%compiler_flags% -Od -MDd -Z7 + set compiler_flags=%compiler_flags% -Od -MDd -Zi rem -DDISPLAY_TIMING ) else ( rem Release - set compiler_flags=%compiler_flags% -O2 -MT -Z7 -DNO_ARRAY_BOUNDS_CHECK + set compiler_flags=%compiler_flags% -O2 -MT -Zi -DNO_ARRAY_BOUNDS_CHECK ) set compiler_warnings= ^ @@ -40,9 +40,10 @@ del *.pdb > NUL 2> NUL del *.ilk > NUL 2> NUL -cl %compiler_settings% "src\main.cpp" ^ - /link %linker_settings% -OUT:%exe_name% ^ - && odin run examples/demo/demo.odin +rem cl %compiler_settings% "src\main.cpp" ^ + rem /link %linker_settings% -OUT:%exe_name% ^ + rem && odin build examples/demo/demo.odin -show-timings +odin check examples/demo/demo.odin -show-timings del *.obj > NUL 2> NUL diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp new file mode 100644 index 000000000..67e698e5d --- /dev/null +++ b/src/thread_pool.cpp @@ -0,0 +1,169 @@ +// worker_queue.cpp + +#define WORKER_TASK_PROC(name) isize name(void *data) +typedef WORKER_TASK_PROC(WorkerTaskProc); + +struct WorkerTask { + WorkerTaskProc *do_work; + void *data; +}; + + +struct ThreadPool { + gbMutex task_mutex; + gbMutex mutex; + gbSemaphore semaphore; + gbAtomic32 processing_work_count; + bool is_running; + + Array tasks; + Array threads; + + gbAllocator original_allocator; + + char worker_prefix[10]; + i32 worker_prefix_len; +}; + + +GB_ALLOCATOR_PROC(thread_pool_allocator_proc) { + ThreadPool *pool = cast(ThreadPool *)allocator_data; + return pool->original_allocator.proc(pool->original_allocator.data, type, size, 256, old_memory, old_size, flags); +} + +gbAllocator thread_pool_allocator(ThreadPool *pool) { + gbAllocator a = {thread_pool_allocator_proc, pool}; + return a; +} + +void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count, char const *worker_prefix = nullptr); +void thread_pool_destroy(ThreadPool *pool); +void thread_pool_start(ThreadPool *pool); +void thread_pool_join(ThreadPool *pool); +void thread_pool_add_task(ThreadPool *pool, WorkerTaskProc *proc, void *data); +void thread_pool_kick(ThreadPool *pool); +void thread_pool_kick_and_wait(ThreadPool *pool); +GB_THREAD_PROC(worker_thread_internal); + +void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count, char const *worker_prefix) { + pool->original_allocator = a; + gbAllocator tpa = thread_pool_allocator(pool); + pool->tasks = array_make(tpa, 0, 1024); + pool->threads = array_make(tpa, thread_count); + gb_mutex_init(&pool->task_mutex); + gb_mutex_init(&pool->mutex); + gb_semaphore_init(&pool->semaphore); + pool->is_running = true; + + pool->worker_prefix_len = 0; + if (worker_prefix) { + i32 worker_prefix_len = cast(i32)gb_strlen(worker_prefix); + worker_prefix_len = gb_min(worker_prefix_len, 10); + gb_memmove(pool->worker_prefix, worker_prefix, worker_prefix_len); + pool->worker_prefix_len = worker_prefix_len; + } + + for_array(i, pool->threads) { + gbThread *t = &pool->threads[i]; + gb_thread_init(t); + t->user_index = i; + if (pool->worker_prefix_len > 0) { + char worker_name[16] = {}; + gb_snprintf(worker_name, gb_size_of(worker_name), "%.*s%u", pool->worker_prefix_len, pool->worker_prefix, cast(u16)i); + gb_thread_set_name(t, worker_name); + } + } +} + +void thread_pool_start(ThreadPool *pool) { + for_array(i, pool->threads) { + gbThread *t = &pool->threads[i]; + gb_thread_start(t, worker_thread_internal, pool); + } +} + +void thread_pool_join(ThreadPool *pool) { + pool->is_running = false; + + for_array(i, pool->threads) { + gb_semaphore_release(&pool->semaphore); + } + + for_array(i, pool->threads) { + gbThread *t = &pool->threads[i]; + gb_thread_join(t); + } +} + + +void thread_pool_destroy(ThreadPool *pool) { + thread_pool_join(pool); + + gb_semaphore_destroy(&pool->semaphore); + gb_mutex_destroy(&pool->mutex); + gb_mutex_destroy(&pool->task_mutex); + array_free(&pool->threads); + array_free(&pool->tasks); +} + + +void thread_pool_add_task(ThreadPool *pool, WorkerTaskProc *proc, void *data) { + gb_mutex_lock(&pool->task_mutex); + + WorkerTask task = {}; + task.do_work = proc; + task.data = data; + array_add(&pool->tasks, task); + + gb_mutex_unlock(&pool->task_mutex); + + gb_semaphore_post(&pool->semaphore, 1); +} + +void thread_pool_kick(ThreadPool *pool) { + if (pool->tasks.count > 0) { + isize count = gb_min(pool->tasks.count, pool->threads.count); + for (isize i = 0; i < count; i++) { + gb_semaphore_post(&pool->semaphore, 1); + } + } + +} +void thread_pool_kick_and_wait(ThreadPool *pool) { + thread_pool_kick(pool); + + isize return_value = 0; + while (pool->tasks.count > 0 || gb_atomic32_load(&pool->processing_work_count) != 0) { + gb_yield(); + } + + thread_pool_join(pool); +} + + +GB_THREAD_PROC(worker_thread_internal) { + ThreadPool *pool = cast(ThreadPool *)thread->user_data; + thread->return_value = 0; + while (pool->is_running) { + gb_semaphore_wait(&pool->semaphore); + + WorkerTask task = {}; + bool got_task = false; + + if (gb_mutex_try_lock(&pool->task_mutex)) { + if (pool->tasks.count > 0) { + gb_atomic32_fetch_add(&pool->processing_work_count, +1); + task = array_pop(&pool->tasks); + got_task = true; + } + gb_mutex_unlock(&pool->task_mutex); + } + + if (got_task) { + thread->return_value = task.do_work(task.data); + gb_atomic32_fetch_add(&pool->processing_work_count, -1); + } + } + return thread->return_value; +} + From 723f351a6d36193cb36c74c40b40befa3c4302f1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 1 Sep 2019 23:13:29 +0100 Subject: [PATCH 057/143] Remove custom allocator for thread pool --- src/thread_pool.cpp | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index 67e698e5d..32fe3b82f 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -19,23 +19,10 @@ struct ThreadPool { Array tasks; Array threads; - gbAllocator original_allocator; - char worker_prefix[10]; i32 worker_prefix_len; }; - -GB_ALLOCATOR_PROC(thread_pool_allocator_proc) { - ThreadPool *pool = cast(ThreadPool *)allocator_data; - return pool->original_allocator.proc(pool->original_allocator.data, type, size, 256, old_memory, old_size, flags); -} - -gbAllocator thread_pool_allocator(ThreadPool *pool) { - gbAllocator a = {thread_pool_allocator_proc, pool}; - return a; -} - void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count, char const *worker_prefix = nullptr); void thread_pool_destroy(ThreadPool *pool); void thread_pool_start(ThreadPool *pool); @@ -46,10 +33,8 @@ void thread_pool_kick_and_wait(ThreadPool *pool); GB_THREAD_PROC(worker_thread_internal); void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count, char const *worker_prefix) { - pool->original_allocator = a; - gbAllocator tpa = thread_pool_allocator(pool); - pool->tasks = array_make(tpa, 0, 1024); - pool->threads = array_make(tpa, thread_count); + pool->tasks = array_make(a, 0, 1024); + pool->threads = array_make(a, thread_count); gb_mutex_init(&pool->task_mutex); gb_mutex_init(&pool->mutex); gb_semaphore_init(&pool->semaphore); From 6d614ef07caf89939b1757bd225ebd0b8c88fa78 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 1 Sep 2019 23:16:01 +0100 Subject: [PATCH 058/143] Remove thread naming on thread pool --- src/thread_pool.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index 32fe3b82f..83178ea47 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -52,11 +52,13 @@ void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count gbThread *t = &pool->threads[i]; gb_thread_init(t); t->user_index = i; + #if 0 if (pool->worker_prefix_len > 0) { char worker_name[16] = {}; gb_snprintf(worker_name, gb_size_of(worker_name), "%.*s%u", pool->worker_prefix_len, pool->worker_prefix, cast(u16)i); gb_thread_set_name(t, worker_name); } + #endif } } From 22e982c8fbec797f2fb48a7df5ab28efc0ee16c9 Mon Sep 17 00:00:00 2001 From: nakst Date: Mon, 2 Sep 2019 16:46:50 +0100 Subject: [PATCH 059/143] New Essence OS layer; cross-compiling improvements --- core/os/os_essence.odin | 1498 ++++++++++++++++++++++--- core/sys/essence_linker_userland64.ld | 24 - core/time/time_essence.odin | 2 + src/build_settings.cpp | 40 +- src/ir.cpp | 2 + src/main.cpp | 92 +- 6 files changed, 1414 insertions(+), 244 deletions(-) delete mode 100644 core/sys/essence_linker_userland64.ld create mode 100644 core/time/time_essence.odin diff --git a/core/os/os_essence.odin b/core/os/os_essence.odin index 2fe62b873..e087a3de3 100644 --- a/core/os/os_essence.odin +++ b/core/os/os_essence.odin @@ -1,180 +1,1350 @@ -package os +package os; +EsData :: struct { _private : [4]rawptr, } +EsGeneric :: rawptr; +EsElement :: struct { _private : u8, }; +EsObject :: rawptr; +EsLongDouble :: struct { value : [10]u8, }; +EsNodeType :: u64; +EsError :: int; +EsHandle :: uint; +EsResponse :: i32; +EsFileOffset :: u64; +EsListViewIndex :: i32; +EsThreadEntryFunction :: distinct #type proc (EsGeneric); +EsComparisonCallbackFunction :: distinct #type proc (rawptr, rawptr, EsGeneric) -> i32; +EsSwapCallbackFunction :: distinct #type proc (rawptr, rawptr, EsGeneric); +EsCRTComparisonCallback :: distinct #type proc (rawptr, rawptr) -> i32; +EsMessageCallbackFunction :: distinct #type proc (EsObject, ^EsMessage, ^EsResponse); +EsUICallbackFunction :: distinct #type proc (^EsElement, ^EsMessage, ^EsResponse); +ES_SCANCODE_A :: (0x1C); +ES_SCANCODE_B :: (0x32); +ES_SCANCODE_C :: (0x21); +ES_SCANCODE_D :: (0x23); +ES_SCANCODE_E :: (0x24); +ES_SCANCODE_F :: (0x2B); +ES_SCANCODE_G :: (0x34); +ES_SCANCODE_H :: (0x33); +ES_SCANCODE_I :: (0x43); +ES_SCANCODE_J :: (0x3B); +ES_SCANCODE_K :: (0x42); +ES_SCANCODE_L :: (0x4B); +ES_SCANCODE_M :: (0x3A); +ES_SCANCODE_N :: (0x31); +ES_SCANCODE_O :: (0x44); +ES_SCANCODE_P :: (0x4D); +ES_SCANCODE_Q :: (0x15); +ES_SCANCODE_R :: (0x2D); +ES_SCANCODE_S :: (0x1B); +ES_SCANCODE_T :: (0x2C); +ES_SCANCODE_U :: (0x3C); +ES_SCANCODE_V :: (0x2A); +ES_SCANCODE_W :: (0x1D); +ES_SCANCODE_X :: (0x22); +ES_SCANCODE_Y :: (0x35); +ES_SCANCODE_Z :: (0x1A); +ES_SCANCODE_0 :: (0x45); +ES_SCANCODE_1 :: (0x16); +ES_SCANCODE_2 :: (0x1E); +ES_SCANCODE_3 :: (0x26); +ES_SCANCODE_4 :: (0x25); +ES_SCANCODE_5 :: (0x2E); +ES_SCANCODE_6 :: (0x36); +ES_SCANCODE_7 :: (0x3D); +ES_SCANCODE_8 :: (0x3E); +ES_SCANCODE_9 :: (0x46); +ES_SCANCODE_CAPS_LOCK :: (0x58); +ES_SCANCODE_SCROLL_LOCK :: (0x7E); +ES_SCANCODE_NUM_LOCK :: (0x77) ; +ES_SCANCODE_LEFT_SHIFT :: (0x12); +ES_SCANCODE_LEFT_CTRL :: (0x14); +ES_SCANCODE_LEFT_ALT :: (0x11); +ES_SCANCODE_LEFT_FLAG :: (0x11F); +ES_SCANCODE_RIGHT_SHIFT :: (0x59); +ES_SCANCODE_RIGHT_CTRL :: (0x114); +ES_SCANCODE_RIGHT_ALT :: (0x111); +ES_SCANCODE_PAUSE :: (0xE1); +ES_SCANCODE_CONTEXT_MENU :: (0x127); +ES_SCANCODE_BACKSPACE :: (0x66); +ES_SCANCODE_ESCAPE :: (0x76); +ES_SCANCODE_INSERT :: (0x170); +ES_SCANCODE_HOME :: (0x16C); +ES_SCANCODE_PAGE_UP :: (0x17D); +ES_SCANCODE_DELETE :: (0x171); +ES_SCANCODE_END :: (0x169); +ES_SCANCODE_PAGE_DOWN :: (0x17A); +ES_SCANCODE_UP_ARROW :: (0x175); +ES_SCANCODE_LEFT_ARROW :: (0x16B); +ES_SCANCODE_DOWN_ARROW :: (0x172); +ES_SCANCODE_RIGHT_ARROW :: (0x174); +ES_SCANCODE_SPACE :: (0x29); +ES_SCANCODE_TAB :: (0x0D); +ES_SCANCODE_ENTER :: (0x5A); +ES_SCANCODE_SLASH :: (0x4A); +ES_SCANCODE_BACKSLASH :: (0x5D); +ES_SCANCODE_LEFT_BRACE :: (0x54); +ES_SCANCODE_RIGHT_BRACE :: (0x5B); +ES_SCANCODE_EQUALS :: (0x55); +ES_SCANCODE_BACKTICK :: (0x0E); +ES_SCANCODE_HYPHEN :: (0x4E); +ES_SCANCODE_SEMICOLON :: (0x4C); +ES_SCANCODE_QUOTE :: (0x52); +ES_SCANCODE_COMMA :: (0x41); +ES_SCANCODE_PERIOD :: (0x49); +ES_SCANCODE_NUM_DIVIDE :: (0x14A); +ES_SCANCODE_NUM_MULTIPLY :: (0x7C); +ES_SCANCODE_NUM_SUBTRACT :: (0x7B); +ES_SCANCODE_NUM_ADD :: (0x79); +ES_SCANCODE_NUM_ENTER :: (0x15A); +ES_SCANCODE_NUM_POINT :: (0x71); +ES_SCANCODE_NUM_0 :: (0x70); +ES_SCANCODE_NUM_1 :: (0x69); +ES_SCANCODE_NUM_2 :: (0x72); +ES_SCANCODE_NUM_3 :: (0x7A); +ES_SCANCODE_NUM_4 :: (0x6B); +ES_SCANCODE_NUM_5 :: (0x73); +ES_SCANCODE_NUM_6 :: (0x74); +ES_SCANCODE_NUM_7 :: (0x6C); +ES_SCANCODE_NUM_8 :: (0x75); +ES_SCANCODE_NUM_9 :: (0x7D); +ES_SCANCODE_PRINT_SCREEN_1 :: (0x112) ; +ES_SCANCODE_PRINT_SCREEN_2 :: (0x17C); +ES_SCANCODE_F1 :: (0x05); +ES_SCANCODE_F2 :: (0x06); +ES_SCANCODE_F3 :: (0x04); +ES_SCANCODE_F4 :: (0x0C); +ES_SCANCODE_F5 :: (0x03); +ES_SCANCODE_F6 :: (0x0B); +ES_SCANCODE_F7 :: (0x83); +ES_SCANCODE_F8 :: (0x0A); +ES_SCANCODE_F9 :: (0x01); +ES_SCANCODE_F10 :: (0x09); +ES_SCANCODE_F11 :: (0x78); +ES_SCANCODE_F12 :: (0x07); +ES_SCANCODE_ACPI_POWER :: (0x137); +ES_SCANCODE_ACPI_SLEEP :: (0x13F); +ES_SCANCODE_ACPI_WAKE :: (0x15E); +ES_SCANCODE_MM_NEXT :: (0x14D); +ES_SCANCODE_MM_PREVIOUS :: (0x115); +ES_SCANCODE_MM_STOP :: (0x13B); +ES_SCANCODE_MM_PAUSE :: (0x134); +ES_SCANCODE_MM_MUTE :: (0x123); +ES_SCANCODE_MM_QUIETER :: (0x121); +ES_SCANCODE_MM_LOUDER :: (0x132); +ES_SCANCODE_MM_SELECT :: (0x150); +ES_SCANCODE_MM_EMAIL :: (0x148); +ES_SCANCODE_MM_CALC :: (0x12B); +ES_SCANCODE_MM_FILES :: (0x140); +ES_SCANCODE_WWW_SEARCH :: (0x110); +ES_SCANCODE_WWW_HOME :: (0x13A); +ES_SCANCODE_WWW_BACK :: (0x138); +ES_SCANCODE_WWW_FORWARD :: (0x130); +ES_SCANCODE_WWW_STOP :: (0x128); +ES_SCANCODE_WWW_REFRESH :: (0x120); +ES_SCANCODE_WWW_STARRED :: (0x118); +ES_PROCESS_STATE_ALL_THREADS_TERMINATED :: (1); +ES_PROCESS_STATE_TERMINATING :: (2); +ES_PROCESS_STATE_CRASHED :: (4); +ES_FLAGS_DEFAULT :: (0); +ES_SUCCESS :: (-1); +ES_ERROR_BUFFER_TOO_SMALL :: (-2); +ES_ERROR_UNKNOWN_OPERATION_FAILURE :: (-7); +ES_ERROR_NO_MESSAGES_AVAILABLE :: (-9); +ES_ERROR_MESSAGE_QUEUE_FULL :: (-10); +ES_ERROR_MESSAGE_NOT_HANDLED_BY_GUI :: (-13); +ES_ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME :: (-14); +ES_ERROR_PATH_NOT_TRAVERSABLE :: (-15); +ES_ERROR_FILE_ALREADY_EXISTS :: (-19); +ES_ERROR_FILE_DOES_NOT_EXIST :: (-20); +ES_ERROR_DRIVE_ERROR_FILE_DAMAGED :: (-21) ; +ES_ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS :: (-22) ; +ES_ERROR_FILE_PERMISSION_NOT_GRANTED :: (-23); +ES_ERROR_FILE_IN_EXCLUSIVE_USE :: (-24); +ES_ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE :: (-25); +ES_ERROR_INCORRECT_NODE_TYPE :: (-26); +ES_ERROR_EVENT_NOT_SET :: (-27); +ES_ERROR_TIMEOUT_REACHED :: (-29); +ES_ERROR_REQUEST_CLOSED_BEFORE_COMPLETE :: (-30); +ES_ERROR_NO_CHARACTER_AT_COORDINATE :: (-31); +ES_ERROR_FILE_ON_READ_ONLY_VOLUME :: (-32); +ES_ERROR_USER_CANCELED_IO :: (-33); +ES_ERROR_INVALID_DIMENSIONS :: (-34); +ES_ERROR_DRIVE_CONTROLLER_REPORTED :: (-35); +ES_ERROR_COULD_NOT_ISSUE_PACKET :: (-36); +ES_ERROR_HANDLE_TABLE_FULL :: (-37); +ES_ERROR_COULD_NOT_RESIZE_FILE :: (-38); +ES_ERROR_DIRECTORY_NOT_EMPTY :: (-39); +ES_ERROR_UNSUPPORTED_FILESYSTEM :: (-40); +ES_ERROR_NODE_ALREADY_DELETED :: (-41); +ES_ERROR_NODE_IS_ROOT :: (-42); +ES_ERROR_VOLUME_MISMATCH :: (-43); +ES_ERROR_TARGET_WITHIN_SOURCE :: (-44); +ES_ERROR_TARGET_INVALID_TYPE :: (-45); +ES_ERROR_NOTHING_TO_DRAW :: (-46); +ES_ERROR_MALFORMED_NODE_PATH :: (-47); +ES_ERROR_OUT_OF_CACHE_RESOURCES :: (-48); +ES_ERROR_TARGET_IS_SOURCE :: (-49); +ES_ERROR_INVALID_NAME :: (-50); +ES_ERROR_CORRUPT_DATA :: (-51); +ES_ERROR_INSUFFICIENT_RESOURCES :: (-52); +ES_ERROR_UNSUPPORTED_FEATURE :: (-53); +ES_ERROR_FILE_TOO_FRAGMENTED :: (-54); +ES_ERROR_DRIVE_FULL :: (-55); +ES_ERROR_COULD_NOT_RESOLVE_SYMBOL :: (-56); +ES_ERROR_ALREADY_EMBEDDED :: (-57); +ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND :: (0); +ES_SYSTEM_CONSTANT_NO_FANCY_GRAPHICS :: (2); +ES_SYSTEM_CONSTANT_REPORTED_PROBLEMS :: (3); +ES_INVALID_HANDLE :: ((EsHandle) (0)); +ES_CURRENT_THREAD :: ((EsHandle) (0x10)); +ES_CURRENT_PROCESS :: ((EsHandle) (0x11)); +ES_SURFACE_UI_SHEET :: ((EsHandle) (0x20)); +ES_SURFACE_WALLPAPER :: ((EsHandle) (0x21)); +ES_DRAW_ALPHA_OVERWRITE :: (0x100); +ES_DRAW_ALPHA_FULL :: (0x200) ; +ES_WAIT_NO_TIMEOUT :: (-1); +ES_MAX_WAIT_COUNT :: (16); +ES_MAX_DIRECTORY_CHILD_NAME_LENGTH :: (256); +ES_PROCESS_EXECUTABLE_NOT_LOADED :: 0; +ES_PROCESS_EXECUTABLE_FAILED_TO_LOAD :: 1; +ES_PROCESS_EXECUTABLE_LOADED :: 2; +ES_SNAPSHOT_MAX_PROCESS_NAME_LENGTH :: (80); +ES_SYSTEM_SNAPSHOT_PROCESSES :: (1); +ES_SYSTEM_SNAPSHOT_DRIVES :: (2); +ES_NOT_HANDLED :: (-1); +ES_HANDLED :: (0); +ES_REJECTED :: (-2); +ES_SHARED_MEMORY_MAXIMUM_SIZE :: ( (1024) * 1024 * 1024 * 1024); +ES_SHARED_MEMORY_NAME_MAX_LENGTH :: (32); +ES_MAP_OBJECT_ALL :: (0); +ES_DRAW_STRING_HALIGN_LEFT :: (1); +ES_DRAW_STRING_HALIGN_RIGHT :: (2); +ES_DRAW_STRING_HALIGN_CENTER :: (3); +ES_DRAW_STRING_VALIGN_TOP :: (4); +ES_DRAW_STRING_VALIGN_BOTTOM :: (8); +ES_DRAW_STRING_VALIGN_CENTER :: (12); +ES_DRAW_STRING_CLIP :: (0); +ES_DRAW_STRING_WORD_WRAP :: (16); +ES_DRAW_STRING_ELLIPSIS :: (32); +ES_NODE_READ_NONE :: (0x0); +ES_NODE_READ_BLOCK :: (0x1); +ES_NODE_READ_ACCESS :: (0x2); +ES_NODE_READ_EXCLUSIVE :: (0x3); +ES_NODE_WRITE_NONE :: (0x00); +ES_NODE_WRITE_BLOCK :: (0x10); +ES_NODE_WRITE_ACCESS :: (0x20); +ES_NODE_WRITE_EXCLUSIVE :: (0x30); +ES_NODE_RESIZE_NONE :: (0x000); +ES_NODE_RESIZE_BLOCK :: (0x100); +ES_NODE_RESIZE_ACCESS :: (0x200); +ES_NODE_RESIZE_EXCLUSIVE :: (0x300); +ES_NODE_FAIL_IF_FOUND :: (0x1000); +ES_NODE_FAIL_IF_NOT_FOUND :: (0x2000); +ES_NODE_CREATE_DIRECTORIES :: (0x8000) ; +ES_NODE_POSIX_NAMESPACE :: (0x10000) ; +ES_DIRECTORY_CHILDREN_UNKNOWN :: ( (-1)); +ES_MEMORY_OPEN_FAIL_IF_FOUND :: (0x1000); +ES_MEMORY_OPEN_FAIL_IF_NOT_FOUND :: (0x2000); +ES_MAP_OBJECT_READ_WRITE :: (0); +ES_MAP_OBJECT_READ_ONLY :: (1); +ES_MAP_OBJECT_COPY_ON_WRITE :: (2); +ES_BOX_STYLE_OUTWARDS :: (0x01) ; +ES_BOX_STYLE_INWARDS :: (0x02) ; +ES_BOX_STYLE_NEUTRAL :: (0x03) ; +ES_BOX_STYLE_FLAT :: (0x04) ; +ES_BOX_STYLE_NONE :: (0x05) ; +ES_BOX_STYLE_SELECTED :: (0x06) ; +ES_BOX_STYLE_PUSHED :: (0x07) ; +ES_BOX_STYLE_DOTTED :: (0x80); +ES_BOX_COLOR_GRAY :: (0xC0C0C0); +ES_BOX_COLOR_DARK_GRAY :: (0x808080); +ES_BOX_COLOR_WHITE :: (0xFFFFFF); +ES_BOX_COLOR_BLUE :: (0x000080); +ES_BOX_COLOR_TRANSPARENT :: (0xFF00FF); +ES_BOX_COLOR_BLACK :: (0x000000); +ES_STRING_FORMAT_ENOUGH_SPACE :: ( (-1)); +ES_POSIX_SYSCALL_GET_POSIX_FD_PATH :: (0x10000); +ES_SURFACE_FULL_ALPHA :: (1); +ES_PERMISSION_ACCESS_SYSTEM_FILES :: (1 << 0); +ES_PERMISSION_ACCESS_USER_FILES :: (1 << 1); +ES_PERMISSION_PROCESS_CREATE :: (1 << 2); +ES_PERMISSION_PROCESS_OPEN :: (1 << 3); +ES_PERMISSION_SCREEN_MODIFY :: (1 << 4) ; +ES_PERMISSION_SHUTDOWN :: (1 << 5); +ES_PERMISSION_TAKE_SYSTEM_SNAPSHOT :: (1 << 6); +ES_PERMISSION_WINDOW_OPEN :: (1 << 7); +ES_PERMISSION_ALL :: ( (-1)); +ES_PERMISSION_INHERIT :: ( (1 << 63)); +ES_PANEL_WRAP :: ( (0x0001) << 32); +ES_PANEL_H_LEFT :: ( (0x0010) << 32); +ES_PANEL_H_RIGHT :: ( (0x0020) << 32); +ES_PANEL_H_CENTER :: ( (0x0040) << 32); +ES_PANEL_H_JUSTIFY :: ( (0x0080) << 32); +ES_PANEL_V_TOP :: ( (0x0100) << 32); +ES_PANEL_V_BOTTOM :: ( (0x0200) << 32); +ES_PANEL_V_CENTER :: ( (0x0400) << 32); +ES_PANEL_V_JUSTIFY :: ( (0x0800) << 32); +ES_PANEL_H_SCROLL :: ( (0x1000) << 32); +ES_PANEL_V_SCROLL :: ( (0x2000) << 32); +ES_CELL_H_PUSH :: ( (0x0001) << 16); +ES_CELL_H_EXPAND :: ( (0x0002) << 16); +ES_CELL_H_LEFT :: ( (0x0004) << 16); +ES_CELL_H_RIGHT :: ( (0x0008) << 16); +ES_CELL_H_SHRINK :: ( (0x0010) << 16); +ES_CELL_V_PUSH :: ( (0x0100) << 16); +ES_CELL_V_EXPAND :: ( (0x0200) << 16); +ES_CELL_V_TOP :: ( (0x0400) << 16); +ES_CELL_V_BOTTOM :: ( (0x0800) << 16); +ES_CELL_V_SHRINK :: ( (0x1000) << 16); +ES_CELL_NEW_BAND :: ( (0x8000) << 16); +ES_CELL_HIDDEN :: ( (0xFFFF) << 16); +ES_ELEMENT_DO_NOT_FREE_STYLE_OVERRIDE :: (1 << 0); +ES_ELEMENT_RICH_TEXT :: (1 << 1); +ES_ELEMENT_FOCUSABLE :: (1 << 2); +ES_ELEMENT_Z_STACK :: (1 << 3) ; +ES_ELEMENT_HIDDEN :: (1 << 4); +ES_ELEMENT_USE_CHILD_AS_PARENT :: (1 << 5) ; +ES_TEXTBOX_MULTILINE :: (1 << 0); +ES_TEXTBOX_BORDERED :: (1 << 1); +ES_BUTTON_DEFAULT :: ( (1) << 32); +ES_BUTTON_DANGEROUS :: ( (1) << 33); +ES_SCROLLBAR_VERTICAL :: ( (0) << 32); +ES_SCROLLBAR_HORIZONTAL :: ( (1) << 32); +ES_LIST_VIEW_INDEX_GROUP_HEADER :: (-1); +ES_LIST_VIEW_ITEM_CONTENT_TEXT :: (1 << 0); +ES_LIST_VIEW_ITEM_CONTENT_ICON :: (1 << 1); +ES_LIST_VIEW_ITEM_CONTENT_INDENTATION :: (1 << 2); +ES_LIST_VIEW_ITEM_STATE_SELECTED :: (1 << 0); +ES_LIST_VIEW_ITEM_STATE_CHECKED :: (1 << 1); +ES_LIST_VIEW_ITEM_STATE_HIDDEN :: (1 << 2); +ES_LIST_VIEW_ITEM_STATE_EXPANDABLE :: (1 << 3); +ES_LIST_VIEW_ITEM_STATE_CHECKABLE :: (1 << 4); +ES_LIST_VIEW_ITEM_STATE_DROP_TARGET :: (1 << 5); +ES_LIST_VIEW_ITEM_STATE_COLLAPSABLE :: (1 << 6); +ES_LIST_VIEW_ITEM_STATE_PARTIAL_CHECK :: (1 << 7); +ES_LIST_VIEW_ITEM_STATE_DRAG_SOURCE :: (1 << 8); +ES_LIST_VIEW_ITEM_STATE_CUT :: (1 << 9); +ES_LIST_VIEW_FIND_ITEM_FROM_Y_POSITION :: (0); +ES_LIST_VIEW_FIND_ITEM_FROM_TEXT_PREFIX :: (1); +ES_LIST_VIEW_FIND_ITEM_NON_HIDDEN :: (2); +ES_LIST_VIEW_FIND_ITEM_PARENT :: (3); +ES_LIST_VIEW_COLUMN_DEFAULT_WIDTH_PRIMARY :: (300); +ES_LIST_VIEW_COLUMN_DEFAULT_WIDTH_SECONDARY :: (150); +ES_LIST_VIEW_COLUMN_PRIMARY :: (1); +ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED :: (2); +ES_LIST_VIEW_COLUMN_SORT_ASCENDING :: (8); +ES_LIST_VIEW_COLUMN_SORT_DESCENDING :: (16); +ES_LIST_VIEW_COLUMN_SORTABLE :: (32); +ES_LIST_VIEW_SINGLE_SELECT :: (1 << 0) ; +ES_LIST_VIEW_MULTI_SELECT :: (1 << 1) ; +ES_LIST_VIEW_HAS_COLUMNS :: (1 << 2) ; +ES_LIST_VIEW_HAS_GROUPS :: (1 << 3) ; +ES_LIST_VIEW_FIXED_HEIGHT :: (1 << 4) ; +ES_LIST_VIEW_VARIABLE_HEIGHT :: (1 << 5) ; +ES_LIST_VIEW_TREE :: (1 << 6) ; +ES_LIST_VIEW_TILED :: (1 << 7) ; +ES_LIST_VIEW_ALT_BACKGROUND :: (1 << 8) ; +ES_LIST_VIEW_BORDERED :: (1 << 9) ; +ES_LIST_VIEW_NO_BACKGROUND :: (1 << 10) ; +ES_LIST_VIEW_DROP_TARGET_ORDERED :: (1 << 11) ; +ES_LIST_VIEW_DROP_TARGET_UNORDERED :: (1 << 12) ; +ES_LIST_VIEW_ROW_DIVIDERS :: (1 << 13) ; +ES_LIST_VIEW_STATIC_GROUP_HEADERS :: (1 << 14) ; +ES_LIST_VIEW_COLLAPSABLE_GROUPS :: (1 << 15) ; +ES_LIST_VIEW_INTERNAL_SELECTION_STORAGE :: (1 << 16) ; +ES_LIST_VIEW_HAND_CURSOR :: (1 << 17) ; +ES_LIST_VIEW_NO_ITEM_BACKGROUNDS :: (1 << 18) ; +ES_LIST_VIEW_RICH_TEXT :: (1 << 20) ; +ES_LIST_VIEW_LABELS_BELOW :: (1 << 21) ; +ES_LIST_VIEW_MAXIMUM_ITEMS :: (10 * 1000 * 1000); +ES_LIST_VIEW_MAXIMUM_GROUPS :: (10 * 1000); +ES_LIST_VIEW_TRANSITION_BACKWARDS :: (1); +ES_LIST_VIEW_TRANSITION_DRAW_NEW_CONTENTS_ONCE :: (2) ; +EsFatalError :: enum { + ES_FATAL_ERROR_INVALID_BUFFER, + ES_FATAL_ERROR_UNKNOWN_SYSCALL, + ES_FATAL_ERROR_INVALID_MEMORY_REGION, + ES_FATAL_ERROR_MEMORY_REGION_LOCKED_BY_KERNEL, + ES_FATAL_ERROR_PATH_LENGTH_EXCEEDS_LIMIT, + ES_FATAL_ERROR_INVALID_HANDLE, + ES_FATAL_ERROR_MUTEX_NOT_ACQUIRED_BY_THREAD, + ES_FATAL_ERROR_MUTEX_ALREADY_ACQUIRED, + ES_FATAL_ERROR_BUFFER_NOT_ACCESSIBLE, + ES_FATAL_ERROR_SHARED_MEMORY_REGION_TOO_LARGE, + ES_FATAL_ERROR_SHARED_MEMORY_STILL_MAPPED, + ES_FATAL_ERROR_COULD_NOT_LOAD_FONT, + ES_FATAL_ERROR_COULD_NOT_DRAW_FONT, + ES_FATAL_ERROR_COULD_NOT_ALLOCATE_MEMORY, + ES_FATAL_ERROR_INCORRECT_FILE_ACCESS, + ES_FATAL_ERROR_TOO_MANY_WAIT_OBJECTS, + ES_FATAL_ERROR_INCORRECT_NODE_TYPE, + ES_FATAL_ERROR_PROCESSOR_EXCEPTION, + ES_FATAL_ERROR_UNKNOWN, + ES_FATAL_ERROR_RECURSIVE_BATCH, + ES_FATAL_ERROR_CORRUPT_HEAP, + ES_FATAL_ERROR_CORRUPT_LINKED_LIST, + ES_FATAL_ERROR_INDEX_OUT_OF_BOUNDS, + ES_FATAL_ERROR_INVALID_STRING_LENGTH, + ES_FATAL_ERROR_SPINLOCK_NOT_ACQUIRED, + ES_FATAL_ERROR_UNKNOWN_SNAPSHOT_TYPE, + ES_FATAL_ERROR_PROCESS_ALREADY_ATTACHED, + ES_FATAL_ERROR_INTERNAL, + ES_FATAL_ERROR_INSUFFICIENT_PERMISSIONS, + ES_FATAL_ERROR_ABORT, + ES_FATAL_ERROR_COUNT, +} -OS :: "essence"; +EsSyscallType :: enum { + ES_SYSCALL_ALLOCATE, + ES_SYSCALL_FREE, + ES_SYSCALL_SHARE_MEMORY, + ES_SYSCALL_MAP_OBJECT, + ES_SYSCALL_OPEN_SHARED_MEMORY, + ES_SYSCALL_CREATE_PROCESS, + ES_SYSCALL_GET_CREATION_ARGUMENT, + ES_SYSCALL_TERMINATE_THREAD, + ES_SYSCALL_CREATE_THREAD, + ES_SYSCALL_WAIT, + ES_SYSCALL_TERMINATE_PROCESS, + ES_SYSCALL_CREATE_EVENT, + ES_SYSCALL_SET_EVENT, + ES_SYSCALL_RESET_EVENT, + ES_SYSCALL_POLL_EVENT, + ES_SYSCALL_PAUSE_PROCESS, + ES_SYSCALL_CRASH_PROCESS, + ES_SYSCALL_GET_THREAD_ID, + ES_SYSCALL_GET_PROCESS_STATE, + ES_SYSCALL_YIELD_SCHEDULER, + ES_SYSCALL_SLEEP, + ES_SYSCALL_OPEN_PROCESS, + ES_SYSCALL_SET_TLS, + ES_SYSCALL_TIMER_SET, + ES_SYSCALL_TIMER_CREATE, + ES_SYSCALL_GET_PROCESS_STATUS, + ES_SYSCALL_CREATE_SURFACE, + ES_SYSCALL_GET_LINEAR_BUFFER, + ES_SYSCALL_INVALIDATE_RECTANGLE, + ES_SYSCALL_COPY_TO_SCREEN, + ES_SYSCALL_FORCE_SCREEN_UPDATE, + ES_SYSCALL_FILL_RECTANGLE, + ES_SYSCALL_COPY_SURFACE, + ES_SYSCALL_CLEAR_MODIFIED_REGION, + ES_SYSCALL_DRAW_SURFACE, + ES_SYSCALL_REDRAW_ALL, + ES_SYSCALL_DRAW_BOX, + ES_SYSCALL_DRAW_BITMAP, + ES_SYSCALL_SURFACE_RESET, + ES_SYSCALL_SURFACE_SHARE, + ES_SYSCALL_DRAW_STYLED_BOX, + ES_SYSCALL_SURFACE_SCROLL, + ES_SYSCALL_RESIZE_SURFACE, + ES_SYSCALL_GET_MESSAGE, + ES_SYSCALL_POST_MESSAGE, + ES_SYSCALL_POST_MESSAGE_REMOTE, + ES_SYSCALL_WAIT_MESSAGE, + ES_SYSCALL_CREATE_WINDOW, + ES_SYSCALL_UPDATE_WINDOW, + ES_SYSCALL_SET_CURSOR_STYLE, + ES_SYSCALL_MOVE_WINDOW, + ES_SYSCALL_GET_WINDOW_BOUNDS, + ES_SYSCALL_RESET_CLICK_CHAIN, + ES_SYSCALL_GET_CURSOR_POSITION, + ES_SYSCALL_SET_CURSOR_POSITION, + ES_SYSCALL_COPY, + ES_SYSCALL_GET_CLIPBOARD_HEADER, + ES_SYSCALL_PASTE_TEXT, + ES_SYSCALL_SET_FOCUSED_WINDOW, + ES_SYSCALL_SET_WINDOW_TITLE, + ES_SYSCALL_GET_SCREEN_BOUNDS, + ES_SYSCALL_WINDOW_OPEN, + ES_SYSCALL_WINDOW_SET_BLEND_BOUNDS, + ES_SYSCALL_WINDOW_GET_BLEND_BOUNDS, + ES_SYSCALL_WINDOW_GET_ID, + ES_SYSCALL_SET_WINDOW_ALPHA, + ES_SYSCALL_DOCKED_WINDOW_CREATE, + ES_SYSCALL_WINDOW_SHARE, + ES_SYSCALL_SET_EMBED_WINDOW, + ES_SYSCALL_OPEN_NODE, + ES_SYSCALL_READ_FILE_SYNC, + ES_SYSCALL_WRITE_FILE_SYNC, + ES_SYSCALL_RESIZE_FILE, + ES_SYSCALL_REFRESH_NODE_INFORMATION, + ES_SYSCALL_ENUMERATE_DIRECTORY_CHILDREN, + ES_SYSCALL_DELETE_NODE, + ES_SYSCALL_MOVE_NODE, + ES_SYSCALL_READ_CONSTANT_BUFFER, + ES_SYSCALL_SHARE_CONSTANT_BUFFER, + ES_SYSCALL_CREATE_CONSTANT_BUFFER, + ES_SYSCALL_EXECUTE, + ES_SYSCALL_INSTANCE_CREATE_REMOTE, + ES_SYSCALL_MAILSLOT_SEND_DATA, + ES_SYSCALL_MAILSLOT_SEND_MESSAGE, + ES_SYSCALL_MAILSLOT_SHARE, + ES_SYSCALL_PIPE_CREATE, + ES_SYSCALL_PIPE_WRITE, + ES_SYSCALL_PIPE_READ, + ES_SYSCALL_USER_GET_HOME_FOLDER, + ES_SYSCALL_USER_LOGIN, + ES_SYSCALL_GET_SYSTEM_CONSTANTS, + ES_SYSCALL_TAKE_SYSTEM_SNAPSHOT, + ES_SYSCALL_SET_SYSTEM_CONSTANT, + ES_SYSCALL_GET_SYSTEM_INFORMATION, + ES_SYSCALL_PRINT, + ES_SYSCALL_CLOSE_HANDLE, + ES_SYSCALL_BATCH, + ES_SYSCALL_SHUTDOWN, + ES_SYSCALL_POSIX, + ES_SYSCALL_COUNT, +} -foreign import api "system:api" +EsStandardFont :: enum { + ES_STANDARD_FONT_REGULAR, + ES_STANDARD_FONT_BOLD, + ES_STANDARD_FONT_MONOSPACED, +} -Handle :: distinct int; -Errno :: distinct int; +EsMessageType :: enum { + ES_MESSAGE_WM_START = 0x1000, + ES_MESSAGE_MOUSE_MOVED = 0x1001, + ES_MESSAGE_WINDOW_ACTIVATED = 0x1003, + ES_MESSAGE_WINDOW_DEACTIVATED = 0x1004, + ES_MESSAGE_WINDOW_DESTROYED = 0x1005, + ES_MESSAGE_MOUSE_EXIT = 0x1006 , + ES_MESSAGE_CLICK_REPEAT = 0x1009, + ES_MESSAGE_WINDOW_RESIZED = 0x100B, + ES_MESSAGE_MOUSE_LEFT_PRESSED = 0x100C , + ES_MESSAGE_MOUSE_LEFT_RELEASED = 0x100D, + ES_MESSAGE_MOUSE_RIGHT_PRESSED = 0x100E, + ES_MESSAGE_MOUSE_RIGHT_RELEASED = 0x100F, + ES_MESSAGE_MOUSE_MIDDLE_PRESSED = 0x1010, + ES_MESSAGE_MOUSE_MIDDLE_RELEASED = 0x1011 , + ES_MESSAGE_KEY_PRESSED = 0x1012, + ES_MESSAGE_KEY_RELEASED = 0x1013, + ES_MESSAGE_UPDATE_WINDOW = 0x1014, + ES_MESSAGE_WM_END = 0x13FF, + ES_MESSAGE_PAINT = 0x2000 , + ES_MESSAGE_DESTROY = 0x2001 , + ES_MESSAGE_MEASURE = 0x2002 , + ES_MESSAGE_SIZE = 0x2003 , + ES_MESSAGE_ADD_CHILD = 0x2004 , + ES_MESSAGE_REMOVE_CHILD = 0x2005 , + ES_MESSAGE_HIT_TEST = 0x2006 , + ES_MESSAGE_HOVERED_START = 0x2007 , + ES_MESSAGE_HOVERED_END = 0x2008 , + ES_MESSAGE_PRESSED_START = 0x2009 , + ES_MESSAGE_PRESSED_END = 0x200A , + ES_MESSAGE_FOCUSED_START = 0x200B , + ES_MESSAGE_FOCUSED_END = 0x200C , + ES_MESSAGE_FOCUS_WITHIN_START = 0x200D , + ES_MESSAGE_FOCUS_WITHIN_END = 0x200E , + ES_MESSAGE_Z_ORDER = 0x2010 , + ES_MESSAGE_ANIMATE = 0x2011 , + ES_MESSAGE_MOUSE_DRAGGED = 0x2012 , + ES_MESSAGE_KEY_TYPED = 0x2013 , + ES_MESSAGE_PAINT_BACKGROUND = 0x2014 , + ES_MESSAGE_PAINT_FOREGROUND = 0x2015 , + ES_MESSAGE_ENSURE_VISIBLE = 0x2016 , + ES_MESSAGE_GET_CURSOR = 0x2017 , + ES_MESSAGE_WINDOW_CREATED = 0x2018 , + ES_MESSAGE_CLICKED = 0x3000 , + ES_MESSAGE_SCROLLBAR_MOVED = 0x3001 , + ES_MESSAGE_RECALCULATE_CONTENT_SIZE = 0x3002 , + ES_MESSAGE_DESKTOP_EXECUTE = 0x4800, + ES_MESSAGE_POWER_BUTTON_PRESSED = 0x4801, + ES_MESSAGE_TASKBAR_WINDOW_ADD = 0x4804, + ES_MESSAGE_TASKBAR_WINDOW_REMOVE = 0x4805, + ES_MESSAGE_TASKBAR_WINDOW_ACTIVATE = 0x4806, + ES_MESSAGE_TASKBAR_WINDOW_SET_TITLE = 0x4807, + ES_MESSAGE_DOCKED_WINDOW_CREATE = 0x4808, + ES_MESSAGE_PROGRAM_CRASH = 0x4C00, + ES_MESSAGE_PROGRAM_FAILED_TO_START = 0x4C01, + ES_MESSAGE_RECEIVE_DATA = 0x5100, + ES_MESSAGE_MAILSLOT_CLOSED = 0x5101, + ES_MESSAGE_CLIPBOARD_UPDATED = 0x5001, + ES_MESSAGE_SYSTEM_CONSTANT_UPDATED = 0x5004, + ES_MESSAGE_TIMER = 0x5006, + ES_MESSAGE_OBJECT_DESTROY = 0x5007, + ES_MESSAGE_LIST_VIEW_GET_ITEM_CONTENT = 0x6000, + ES_MESSAGE_LIST_VIEW_SET_ITEM_STATE = 0x6001, + ES_MESSAGE_LIST_VIEW_GET_ITEM_STATE = 0x6002, + ES_MESSAGE_LIST_VIEW_PAINT_ITEM = 0x6003 , + ES_MESSAGE_LIST_VIEW_PAINT_CELL = 0x6004 , + ES_MESSAGE_LIST_VIEW_SORT_COLUMN = 0x6005, + ES_MESSAGE_LIST_VIEW_CHOOSE_ITEM = 0x6006, + ES_MESSAGE_LIST_VIEW_FIND_ITEM = 0x6007, + ES_MESSAGE_LIST_VIEW_TOGGLE_DISCLOSURE = 0x6008, + ES_MESSAGE_LIST_VIEW_MEASURE_ITEM_HEIGHT = 0x6009, + ES_MESSAGE_LIST_VIEW_LAYOUT_ITEM = 0x600A, + ES_MESSAGE_LIST_VIEW_SET_ITEM_VISIBILITY = 0x600B, + ES_MESSAGE_LIST_VIEW_RELAY_MESSAGE = 0x600C, + ES_MESSAGE_LIST_VIEW_SET_ITEM_POSITION = 0x600D, + ES_MESSAGE_USER_START = 0x8000, + ES_MESSAGE_USER_END = 0xBFFF, +} -O_RDONLY :: 0x00001; -O_WRONLY :: 0x00002; -O_RDWR :: 0x00003; +EsDrawMode :: enum { + ES_DRAW_MODE_REPEAT_FIRST = 1 , + ES_DRAW_MODE_STRECH, + ES_DRAW_MODE_REPEAT, + ES_DRAW_MODE_NONE, +} + +EsClipboardFormat :: enum { + ES_CLIPBOARD_FORMAT_EMPTY, + ES_CLIPBOARD_FORMAT_TEXT, + ES_CLIPBOARD_FORMAT_FILE_LIST, +} + +EsColorFormat :: enum { + ES_COLOR_FORMAT_32_XRGB, +} + +EsCursorStyle :: enum { + ES_CURSOR_NORMAL, + ES_CURSOR_TEXT, + ES_CURSOR_RESIZE_VERTICAL, + ES_CURSOR_RESIZE_HORIZONTAL, + ES_CURSOR_RESIZE_DIAGONAL_1, + ES_CURSOR_RESIZE_DIAGONAL_2, + ES_CURSOR_SPLIT_VERTICAL, + ES_CURSOR_SPLIT_HORIZONTAL, + ES_CURSOR_HAND_HOVER, + ES_CURSOR_HAND_DRAG, + ES_CURSOR_HAND_POINT, + ES_CURSOR_SCROLL_UP_LEFT, + ES_CURSOR_SCROLL_UP, + ES_CURSOR_SCROLL_UP_RIGHT, + ES_CURSOR_SCROLL_LEFT, + ES_CURSOR_SCROLL_CENTER, + ES_CURSOR_SCROLL_RIGHT, + ES_CURSOR_SCROLL_DOWN_LEFT, + ES_CURSOR_SCROLL_DOWN, + ES_CURSOR_SCROLL_DOWN_RIGHT, + ES_CURSOR_SELECT_LINES, + ES_CURSOR_DROP_TEXT, + ES_CURSOR_CROSS_HAIR_PICK, + ES_CURSOR_CROSS_HAIR_RESIZE, + ES_CURSOR_MOVE_HOVER, + ES_CURSOR_MOVE_DRAG, + ES_CURSOR_ROTATE_HOVER, + ES_CURSOR_ROTATE_DRAG, + ES_CURSOR_BLANK, +} + +EsWindowStyle :: enum { + ES_WINDOW_NORMAL, + ES_WINDOW_CONTAINER, + ES_WINDOW_MENU, +} + +ES_NODE_FILE :: (0); +ES_NODE_DIRECTORY :: (0x4000); +ES_NODE_INVALID :: (0x8000); +EsBatchCall :: struct { + index :EsSyscallType, + stopBatchIfError :bool, + using _ : struct #raw_union { + argument0 :uintptr, + returnValue :uintptr, + }, + + argument1 :uintptr, + argument2 :uintptr, + argument3 :uintptr, +} + +EsThreadInformation :: struct { + handle :EsHandle, + tid :uintptr, +} + +EsProcessInformation :: struct { + handle :EsHandle, + pid :uintptr, + mainThread :EsThreadInformation, +} + +EsUniqueIdentifier :: struct { + using _ : struct #raw_union { + d :[16]u8, + }, + +} + +EsNodeInformation :: struct { + handle :EsHandle, + type :EsNodeType, + using _ : struct #raw_union { + fileSize :EsFileOffset, + directoryChildren :EsFileOffset, + }, + +} + +EsDirectoryChild :: struct { + name :[ES_MAX_DIRECTORY_CHILD_NAME_LENGTH]i8, + nameBytes :uintptr, + information :EsNodeInformation, +} + +EsPoint :: struct { + x :i32, + y :i32, +} + +EsRectangle :: struct { + left :i32, + right :i32, + top :i32, + bottom :i32, +} + +EsRectangle16 :: struct { + left :i16, + right :i16, + top :i16, + bottom :i16, +} + +EsColor :: struct { + using _ : struct #raw_union { + using _ : struct { + blue :u8, + green :u8, + red :u8, + }, + + combined :u32, + }, + +} + +EsLinearBuffer :: struct { + width :uintptr, + height :uintptr, + stride :uintptr, + colorFormat :EsColorFormat, + handle :EsHandle, + flags :u32, +} + +_EsRectangleAndColor :: struct { + rectangle :EsRectangle, + color :EsColor, +} + +_EsStyledBoxData :: struct { + backgroundColor :u32, + borderColor :u32, + borderSize :u8, + cornerRadius :u8, + roundedCornersToExclude :u8, + ox :i32, + oy :i32, + width :i32, + height :i32, + clip :EsRectangle, +} + +_EsInstanceCreateRemoteArguments :: struct { + what :^i8, + argument :^i8, + whatBytes :uintptr, + argumentBytes :uintptr, + modalWindowParent :EsHandle, + apiInstance :^rawptr, +} + +_EsDrawSurfaceArguments :: struct { + source :EsRectangle, + destination :EsRectangle, + border :EsRectangle, + alpha :u16, +} + +EsSpinlock :: struct { + state :u8, +} + +EsMutex :: struct { + event :EsHandle, + spinlock :EsSpinlock, + state :u8, + queued :u32, +} + +EsCrashReason :: struct { + errorCode :EsError, +} + +EsProcessState :: struct { + crashReason :EsCrashReason, + creationArgument :EsGeneric, + id :uintptr, + executableState :uintptr, + flags :u8, +} + +EsIORequestProgress :: struct { + accessed :EsFileOffset, + progress :EsFileOffset, + completed :bool, + cancelled :bool, + error :EsError, +} + +EsClipboardHeader :: struct { + customBytes :uintptr, + format :EsClipboardFormat, + textBytes :uintptr, + unused :uintptr, +} + +EsPainter :: struct { + surface :EsHandle, + clip :EsRectangle, + offsetX :i32, + offsetY :i32, +} + +EsMessage :: struct { + type :EsMessageType, + _context :EsGeneric, + using _ : struct #raw_union { + _argument :^rawptr, + mouseMoved : struct { + oldPositionX :i32, + newPositionX :i32, + oldPositionY :i32, + newPositionY :i32, + newPositionXScreen :i32, + newPositionYScreen :i32, + }, + + mouseDragged : struct { + oldPositionX :i32, + newPositionX :i32, + oldPositionY :i32, + newPositionY :i32, + originalPositionX :i32, + originalPositionY :i32, + }, + + mousePressed : struct { + positionX :i32, + positionY :i32, + positionXScreen :i32, + positionYScreen :i32, + clickChainCount :u8, + activationClick :u8, + alt :u8, + ctrl :u8, + shift :u8, + }, + + keyboard : struct { + scancode :u32, + alt :u8, + ctrl :u8, + shift :u8, + numpad :u8, + notHandledBy :EsObject, + }, + + crash : struct { + reason :EsCrashReason, + process :EsHandle, + processNameBuffer :EsHandle, + processNameBytes :uintptr, + pid :uintptr, + }, + + clipboard :EsClipboardHeader, + receive : struct { + buffer :EsHandle, + bytes :uintptr, + }, + + animate : struct { + deltaMcs :i64, + waitMcs :i64, + complete :bool, + }, + + systemConstantUpdated : struct { + index :uintptr, + newValue :u64, + }, + + desktopExecute : struct { + whatBuffer :EsHandle, + argumentBuffer :EsHandle, + mailslot :EsHandle, + whatBytes :uintptr, + argumentBytes :uintptr, + modalWindowParent :u64, + }, + + dockedWindowCreate : struct { + pipe :EsHandle, + }, + + taskbar : struct { + id :u64, + buffer :EsHandle, + bytes :uintptr, + }, + + windowResized : struct { + content :EsRectangle, + }, + + painter :^EsPainter, + measure : struct { + width :i32, + height :i32, + }, + + child :EsObject, + size : struct { + width :i32, + height :i32, + }, + + hitTest : struct { + x :i32, + y :i32, + inside :bool, + }, + + zOrder : struct { + index :uintptr, + child :^EsElement, + }, + + scrollbarMoved : struct { + scroll :i32, + }, + + ensureVisible : struct { + child :^EsElement, + }, + + cursorStyle :EsCursorStyle, + getItemContent : struct { + mask :u32, + index :EsListViewIndex, + column :EsListViewIndex, + group :EsListViewIndex, + text :^i8, + textBytes :uintptr, + iconHash :u32, + iconWidth :u16, + iconHeight :u16, + indentation :u16, + spaceAfterIcon :u16, + }, + + accessItemState : struct { + mask :u32, + state :u32, + iIndexFrom :EsListViewIndex, + eIndexTo :EsListViewIndex, + group :EsListViewIndex, + }, + + measureItemHeight : struct { + iIndexFrom :EsListViewIndex, + eIndexTo :EsListViewIndex, + group :EsListViewIndex, + height :i32, + }, + + layoutItem : struct { + index :EsListViewIndex, + group :EsListViewIndex, + knownIndex :EsListViewIndex, + knownGroup :EsListViewIndex, + bounds :EsRectangle, + }, + + toggleItemDisclosure : struct { + index :EsListViewIndex, + group :EsListViewIndex, + }, + + findItem : struct { + type :u8, + backwards :u8, + inclusive :bool, + indexFrom :EsListViewIndex, + groupFrom :EsListViewIndex, + foundIndex :EsListViewIndex, + foundGroup :EsListViewIndex, + using _ : struct #raw_union { + using _ : struct { + prefix :^i8, + prefixBytes :uintptr, + }, + + using _ : struct { + yPosition :i32, + yPositionOfIndexFrom :i32, + offsetIntoItem :i32, + }, + + }, + + }, + + listViewColumn : struct { + index :EsListViewIndex, + descending :bool, + }, + + setItemVisibility : struct { + index :EsListViewIndex, + group :EsListViewIndex, + visible :bool, + }, + + setItemPosition : struct { + index :EsListViewIndex, + group :EsListViewIndex, + bounds :EsRectangle, + }, + + listViewPaint : struct { + surface :EsHandle, + bounds :EsRectangle, + clip :EsRectangle, + index :EsListViewIndex, + group :EsListViewIndex, + column :EsListViewIndex, + _internal :^rawptr, + }, + + }, + +} + +EsDebuggerMessage :: struct { + process :EsHandle, + reason :EsCrashReason, +} + +EsDriveInformation :: struct { + name :[64]i8, + nameBytes :uintptr, + mountpoint :[256]i8, + mountpointBytes :uintptr, +} + +EsSnapshotProcessesItem :: struct { + pid :i64, + memoryUsage :i64, + cpuTimeSlices :i64, + name :[ES_SNAPSHOT_MAX_PROCESS_NAME_LENGTH]i8, + nameLength :uintptr, + internal :u64, +} + +EsSystemInformation :: struct { + processCount :uintptr, + threadCount :uintptr, + handleCount :uintptr, + commitLimit :uintptr, + commit :uintptr, + countZeroedPages :uintptr, + countFreePages :uintptr, + countStandbyPages :uintptr, + countModifiedPages :uintptr, + countActivePages :uintptr, + coreHeapSize :uintptr, + coreHeapAllocations :uintptr, + fixedHeapSize :uintptr, + fixedHeapAllocations :uintptr, + coreRegions :uintptr, + kernelRegions :uintptr, +} + +EsSnapshotProcesses :: struct { + count :uintptr, + processes :[]EsSnapshotProcessesItem, +} + +_EsPOSIXSyscall :: struct { + index :int, + arguments :[7]int, +} + +EsProcessCreationArguments :: struct { + executablePath :^i8, + executablePathBytes :uintptr, + environmentBlock :^rawptr, + environmentBlockBytes :uintptr, + creationArgument :EsGeneric, + permissions :u64, +} + +_EsUserLoginArguments :: struct { + name :^i8, + nameBytes :uintptr, + home :^i8, + homeBytes :uintptr, +} + +EsInstance :: struct { + _private :^rawptr, +} + +EsListViewColumn :: struct { + title :^i8, + titleBytes :uintptr, + width :i32, + minimumWidth :i32, + flags :u32, +} + +EsListViewStyle :: struct { + flags :u32, + fixedWidth :i32, + fixedHeight :i32, + groupHeaderHeight :i32, + gapX :i32, + gapY :i32, + margin :EsRectangle16, + columns :^EsListViewColumn, + columnCount :uintptr, + emptyMessage :^i8, + emptyMessageBytes :uintptr, +} + +EsBatch :: inline proc (calls :^EsBatchCall, count :uintptr){ ((proc (^EsBatchCall, uintptr))(rawptr(uintptr(0x1000 + 0 * size_of(int)))))(calls, count); } +EsProcessCreate :: inline proc (executablePath :^i8, executablePathLength :uintptr, information :^EsProcessInformation, argument :EsGeneric) -> EsError{ return ((proc (^i8, uintptr, ^EsProcessInformation, EsGeneric) -> EsError)(rawptr(uintptr(0x1000 + 1 * size_of(int)))))(executablePath, executablePathLength, information, argument); } +EsThreadCreate :: inline proc (entryFunction :EsThreadEntryFunction, information :^EsThreadInformation, argument :EsGeneric) -> EsError{ return ((proc (EsThreadEntryFunction, ^EsThreadInformation, EsGeneric) -> EsError)(rawptr(uintptr(0x1000 + 2 * size_of(int)))))(entryFunction, information, argument); } +EsSurfaceCreate :: inline proc (width :uintptr, height :uintptr, flags :u32) -> EsHandle{ return ((proc (uintptr, uintptr, u32) -> EsHandle)(rawptr(uintptr(0x1000 + 3 * size_of(int)))))(width, height, flags); } +EsEventCreate :: inline proc (autoReset :bool) -> EsHandle{ return ((proc (bool) -> EsHandle)(rawptr(uintptr(0x1000 + 4 * size_of(int)))))(autoReset); } +EsThreadLocalStorageSetAddress :: inline proc (address :^rawptr){ ((proc (^rawptr))(rawptr(uintptr(0x1000 + 5 * size_of(int)))))(address); } +EsConstantBufferRead :: inline proc (constantBuffer :EsHandle, output :^rawptr){ ((proc (EsHandle, ^rawptr))(rawptr(uintptr(0x1000 + 6 * size_of(int)))))(constantBuffer, output); } +EsConstantBufferShare :: inline proc (constantBuffer :EsHandle, targetProcess :EsHandle) -> EsHandle{ return ((proc (EsHandle, EsHandle) -> EsHandle)(rawptr(uintptr(0x1000 + 7 * size_of(int)))))(constantBuffer, targetProcess); } +EsConstantBufferCreate :: inline proc (data :^rawptr, dataBytes :uintptr, targetProcess :EsHandle) -> EsHandle{ return ((proc (^rawptr, uintptr, EsHandle) -> EsHandle)(rawptr(uintptr(0x1000 + 8 * size_of(int)))))(data, dataBytes, targetProcess); } +EsProcessOpen :: inline proc (pid :u64) -> EsHandle{ return ((proc (u64) -> EsHandle)(rawptr(uintptr(0x1000 + 9 * size_of(int)))))(pid); } +EsHandleClose :: inline proc (handle :EsHandle) -> EsError{ return ((proc (EsHandle) -> EsError)(rawptr(uintptr(0x1000 + 10 * size_of(int)))))(handle); } +EsTakeSystemSnapshot :: inline proc (type :i32, bufferSize :^uintptr) -> EsHandle{ return ((proc (i32, ^uintptr) -> EsHandle)(rawptr(uintptr(0x1000 + 11 * size_of(int)))))(type, bufferSize); } +EsGetSystemInformation :: inline proc (systemInformation :^EsSystemInformation){ ((proc (^EsSystemInformation))(rawptr(uintptr(0x1000 + 12 * size_of(int)))))(systemInformation); } +EsNodeOpen :: inline proc (path :^i8, pathLength :uintptr, flags :u64, information :^EsNodeInformation) -> EsError{ return ((proc (^i8, uintptr, u64, ^EsNodeInformation) -> EsError)(rawptr(uintptr(0x1000 + 13 * size_of(int)))))(path, pathLength, flags, information); } +EsNodeFindUniqueName :: inline proc (buffer :^i8, originalBytes :uintptr, bufferBytes :uintptr) -> uintptr{ return ((proc (^i8, uintptr, uintptr) -> uintptr)(rawptr(uintptr(0x1000 + 14 * size_of(int)))))(buffer, originalBytes, bufferBytes); } +EsFileReadAll :: inline proc (filePath :^i8, filePathLength :uintptr, fileSize :^uintptr){ ((proc (^i8, uintptr, ^uintptr))(rawptr(uintptr(0x1000 + 15 * size_of(int)))))(filePath, filePathLength, fileSize); } +EsFileReadSync :: inline proc (file :EsHandle, offset :EsFileOffset, size :uintptr, buffer :^rawptr) -> uintptr{ return ((proc (EsHandle, EsFileOffset, uintptr, ^rawptr) -> uintptr)(rawptr(uintptr(0x1000 + 16 * size_of(int)))))(file, offset, size, buffer); } +EsFileWriteSync :: inline proc (file :EsHandle, offset :EsFileOffset, size :uintptr, buffer :^rawptr) -> uintptr{ return ((proc (EsHandle, EsFileOffset, uintptr, ^rawptr) -> uintptr)(rawptr(uintptr(0x1000 + 17 * size_of(int)))))(file, offset, size, buffer); } +EsFileResize :: inline proc (file :EsHandle, newSize :EsFileOffset) -> EsError{ return ((proc (EsHandle, EsFileOffset) -> EsError)(rawptr(uintptr(0x1000 + 18 * size_of(int)))))(file, newSize); } +EsNodeRefreshInformation :: inline proc (information :^EsNodeInformation){ ((proc (^EsNodeInformation))(rawptr(uintptr(0x1000 + 19 * size_of(int)))))(information); } +EsDirectoryEnumerateChildren :: inline proc (directory :EsHandle, buffer :^EsDirectoryChild, bufferCount :uintptr) -> int{ return ((proc (EsHandle, ^EsDirectoryChild, uintptr) -> int)(rawptr(uintptr(0x1000 + 20 * size_of(int)))))(directory, buffer, bufferCount); } +EsNodeDelete :: inline proc (node :EsHandle) -> EsError{ return ((proc (EsHandle) -> EsError)(rawptr(uintptr(0x1000 + 21 * size_of(int)))))(node); } +EsNodeMove :: inline proc (node :EsHandle, newDirectory :EsHandle, newName :^i8, newNameLength :uintptr) -> EsError{ return ((proc (EsHandle, EsHandle, ^i8, uintptr) -> EsError)(rawptr(uintptr(0x1000 + 22 * size_of(int)))))(node, newDirectory, newName, newNameLength); } +EsThreadTerminate :: inline proc (thread :EsHandle){ ((proc (EsHandle))(rawptr(uintptr(0x1000 + 23 * size_of(int)))))(thread); } +EsProcessTerminate :: inline proc (process :EsHandle, status :i32){ ((proc (EsHandle, i32))(rawptr(uintptr(0x1000 + 24 * size_of(int)))))(process, status); } +EsProcessTerminateCurrent :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 25 * size_of(int)))))(); } +EsProcessPause :: inline proc (process :EsHandle, resume :bool){ ((proc (EsHandle, bool))(rawptr(uintptr(0x1000 + 26 * size_of(int)))))(process, resume); } +EsProcessCrash :: inline proc (error :EsError, message :^i8, messageBytes :uintptr){ ((proc (EsError, ^i8, uintptr))(rawptr(uintptr(0x1000 + 27 * size_of(int)))))(error, message, messageBytes); } +EsThreadGetID :: inline proc (thread :EsHandle) -> uintptr{ return ((proc (EsHandle) -> uintptr)(rawptr(uintptr(0x1000 + 28 * size_of(int)))))(thread); } +EsProcessGetID :: inline proc (process :EsHandle) -> uintptr{ return ((proc (EsHandle) -> uintptr)(rawptr(uintptr(0x1000 + 29 * size_of(int)))))(process); } +EsSpinlockRelease :: inline proc (spinlock :^EsSpinlock){ ((proc (^EsSpinlock))(rawptr(uintptr(0x1000 + 30 * size_of(int)))))(spinlock); } +EsSpinlockAcquire :: inline proc (spinlock :^EsSpinlock){ ((proc (^EsSpinlock))(rawptr(uintptr(0x1000 + 31 * size_of(int)))))(spinlock); } +EsMutexRelease :: inline proc (mutex :^EsMutex){ ((proc (^EsMutex))(rawptr(uintptr(0x1000 + 32 * size_of(int)))))(mutex); } +EsMutexAcquire :: inline proc (mutex :^EsMutex){ ((proc (^EsMutex))(rawptr(uintptr(0x1000 + 33 * size_of(int)))))(mutex); } +EsMutexDestroy :: inline proc (mutex :^EsMutex){ ((proc (^EsMutex))(rawptr(uintptr(0x1000 + 34 * size_of(int)))))(mutex); } +EsSchedulerYield :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 35 * size_of(int)))))(); } +EsEventSet :: inline proc (event :EsHandle){ ((proc (EsHandle))(rawptr(uintptr(0x1000 + 36 * size_of(int)))))(event); } +EsEventReset :: inline proc (event :EsHandle){ ((proc (EsHandle))(rawptr(uintptr(0x1000 + 37 * size_of(int)))))(event); } +EsEventPoll :: inline proc (event :EsHandle) -> EsError{ return ((proc (EsHandle) -> EsError)(rawptr(uintptr(0x1000 + 38 * size_of(int)))))(event); } +EsWait :: inline proc (objects :^EsHandle, objectCount :uintptr, timeoutMs :uintptr) -> uintptr{ return ((proc (^EsHandle, uintptr, uintptr) -> uintptr)(rawptr(uintptr(0x1000 + 39 * size_of(int)))))(objects, objectCount, timeoutMs); } +EsSleep :: inline proc (milliseconds :u64){ ((proc (u64))(rawptr(uintptr(0x1000 + 40 * size_of(int)))))(milliseconds); } +EsMemoryOpen :: inline proc (size :uintptr, name :^i8, nameLength :uintptr, flags :u32) -> EsHandle{ return ((proc (uintptr, ^i8, uintptr, u32) -> EsHandle)(rawptr(uintptr(0x1000 + 41 * size_of(int)))))(size, name, nameLength, flags); } +EsMemoryShare :: inline proc (sharedMemoryRegion :EsHandle, targetProcess :EsHandle, readOnly :bool) -> EsHandle{ return ((proc (EsHandle, EsHandle, bool) -> EsHandle)(rawptr(uintptr(0x1000 + 42 * size_of(int)))))(sharedMemoryRegion, targetProcess, readOnly); } +EsObjectMap :: inline proc (object :EsHandle, offset :uintptr, size :uintptr, flags :u32){ ((proc (EsHandle, uintptr, uintptr, u32))(rawptr(uintptr(0x1000 + 43 * size_of(int)))))(object, offset, size, flags); } +EsMemoryAllocate :: inline proc (size :uintptr){ ((proc (uintptr))(rawptr(uintptr(0x1000 + 44 * size_of(int)))))(size); } +EsMemoryFree :: inline proc (address :^rawptr) -> EsError{ return ((proc (^rawptr) -> EsError)(rawptr(uintptr(0x1000 + 45 * size_of(int)))))(address); } +EsGetCreationArgument :: inline proc (object :EsHandle) -> EsGeneric{ return ((proc (EsHandle) -> EsGeneric)(rawptr(uintptr(0x1000 + 46 * size_of(int)))))(object); } +EsProcessGetState :: inline proc (process :EsHandle, state :^EsProcessState){ ((proc (EsHandle, ^EsProcessState))(rawptr(uintptr(0x1000 + 47 * size_of(int)))))(process, state); } +EsSurfaceGetLinearBuffer :: inline proc (surface :EsHandle, linearBuffer :^EsLinearBuffer){ ((proc (EsHandle, ^EsLinearBuffer))(rawptr(uintptr(0x1000 + 48 * size_of(int)))))(surface, linearBuffer); } +EsRectangleInvalidate :: inline proc (surface :EsHandle, rectangle :EsRectangle){ ((proc (EsHandle, EsRectangle))(rawptr(uintptr(0x1000 + 49 * size_of(int)))))(surface, rectangle); } +EsCopyToScreen :: inline proc (source :EsHandle, point :EsPoint, depth :u16){ ((proc (EsHandle, EsPoint, u16))(rawptr(uintptr(0x1000 + 50 * size_of(int)))))(source, point, depth); } +EsForceScreenUpdate :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 51 * size_of(int)))))(); } +EsDrawRectangle :: inline proc (surface :EsHandle, rectangle :EsRectangle, color :EsColor){ ((proc (EsHandle, EsRectangle, EsColor))(rawptr(uintptr(0x1000 + 52 * size_of(int)))))(surface, rectangle, color); } +EsDrawRectangleClipped :: inline proc (surface :EsHandle, rectangle :EsRectangle, color :EsColor, clipRegion :EsRectangle){ ((proc (EsHandle, EsRectangle, EsColor, EsRectangle))(rawptr(uintptr(0x1000 + 53 * size_of(int)))))(surface, rectangle, color, clipRegion); } +EsDrawSurfaceBlit :: inline proc (destination :EsHandle, source :EsHandle, destinationPoint :EsPoint){ ((proc (EsHandle, EsHandle, EsPoint))(rawptr(uintptr(0x1000 + 54 * size_of(int)))))(destination, source, destinationPoint); } +EsDrawSurface :: inline proc (destination :EsHandle, source :EsHandle, destinationRegion :EsRectangle, sourceRegion :EsRectangle, borderRegion :EsRectangle, mode :EsDrawMode, alpha :u16) -> EsError{ return ((proc (EsHandle, EsHandle, EsRectangle, EsRectangle, EsRectangle, EsDrawMode, u16) -> EsError)(rawptr(uintptr(0x1000 + 55 * size_of(int)))))(destination, source, destinationRegion, sourceRegion, borderRegion, mode, alpha); } +EsDrawSurfaceClipped :: inline proc (destination :EsHandle, source :EsHandle, destinationRegion :EsRectangle, sourceRegion :EsRectangle, borderRegion :EsRectangle, mode :EsDrawMode, alpha :u16, clipRegion :EsRectangle) -> EsError{ return ((proc (EsHandle, EsHandle, EsRectangle, EsRectangle, EsRectangle, EsDrawMode, u16, EsRectangle) -> EsError)(rawptr(uintptr(0x1000 + 56 * size_of(int)))))(destination, source, destinationRegion, sourceRegion, borderRegion, mode, alpha, clipRegion); } +EsDrawBitmap :: inline proc (destination :EsHandle, destinationPoint :EsPoint, bitmap :^rawptr, width :uintptr, height :uintptr, stride :uintptr, colorFormat :EsColorFormat){ ((proc (EsHandle, EsPoint, ^rawptr, uintptr, uintptr, uintptr, EsColorFormat))(rawptr(uintptr(0x1000 + 57 * size_of(int)))))(destination, destinationPoint, bitmap, width, height, stride, colorFormat); } +EsSurfaceClearInvalidatedRegion :: inline proc (surface :EsHandle){ ((proc (EsHandle))(rawptr(uintptr(0x1000 + 58 * size_of(int)))))(surface); } +EsRectangleClip :: inline proc (parent :EsRectangle, rectangle :EsRectangle, output :^EsRectangle) -> bool{ return ((proc (EsRectangle, EsRectangle, ^EsRectangle) -> bool)(rawptr(uintptr(0x1000 + 59 * size_of(int)))))(parent, rectangle, output); } +EsDrawBox :: inline proc (surface :EsHandle, rectangle :EsRectangle, style :u8, color :u32, clipRegion :EsRectangle){ ((proc (EsHandle, EsRectangle, u8, u32, EsRectangle))(rawptr(uintptr(0x1000 + 60 * size_of(int)))))(surface, rectangle, style, color, clipRegion); } +EsRedrawAll :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 61 * size_of(int)))))(); } +EsMessagePost :: inline proc (message :^EsMessage) -> EsError{ return ((proc (^EsMessage) -> EsError)(rawptr(uintptr(0x1000 + 62 * size_of(int)))))(message); } +EsMessagePostRemote :: inline proc (process :EsHandle, message :^EsMessage) -> EsError{ return ((proc (EsHandle, ^EsMessage) -> EsError)(rawptr(uintptr(0x1000 + 63 * size_of(int)))))(process, message); } +EsExtractArguments :: inline proc (string :^i8, bytes :uintptr, delimiterByte :u8, replacementDelimiter :u8, argvAllocated :uintptr, argv :^^i8, argc :^uintptr) -> bool{ return ((proc (^i8, uintptr, u8, u8, uintptr, ^^i8, ^uintptr) -> bool)(rawptr(uintptr(0x1000 + 64 * size_of(int)))))(string, bytes, delimiterByte, replacementDelimiter, argvAllocated, argv, argc); } +EsCStringLength :: inline proc (string :^i8) -> uintptr{ return ((proc (^i8) -> uintptr)(rawptr(uintptr(0x1000 + 65 * size_of(int)))))(string); } +EsStringLength :: inline proc (string :^i8, end :u8) -> uintptr{ return ((proc (^i8, u8) -> uintptr)(rawptr(uintptr(0x1000 + 66 * size_of(int)))))(string, end); } +EsMemoryCopy :: inline proc (destination :^rawptr, source :^rawptr, bytes :uintptr){ ((proc (^rawptr, ^rawptr, uintptr))(rawptr(uintptr(0x1000 + 67 * size_of(int)))))(destination, source, bytes); } +EsMemoryMove :: inline proc (_start :^rawptr, _end :^rawptr, amount :int, zeroEmptySpace :bool){ ((proc (^rawptr, ^rawptr, int, bool))(rawptr(uintptr(0x1000 + 68 * size_of(int)))))(_start, _end, amount, zeroEmptySpace); } +EsMemoryCopyReverse :: inline proc (_destination :^rawptr, _source :^rawptr, bytes :uintptr){ ((proc (^rawptr, ^rawptr, uintptr))(rawptr(uintptr(0x1000 + 69 * size_of(int)))))(_destination, _source, bytes); } +EsMemoryZero :: inline proc (destination :^rawptr, bytes :uintptr){ ((proc (^rawptr, uintptr))(rawptr(uintptr(0x1000 + 70 * size_of(int)))))(destination, bytes); } +EsMemoryCompare :: inline proc (a :^rawptr, b :^rawptr, bytes :uintptr) -> i32{ return ((proc (^rawptr, ^rawptr, uintptr) -> i32)(rawptr(uintptr(0x1000 + 71 * size_of(int)))))(a, b, bytes); } +EsMemorySumBytes :: inline proc (data :^u8, bytes :uintptr) -> u8{ return ((proc (^u8, uintptr) -> u8)(rawptr(uintptr(0x1000 + 72 * size_of(int)))))(data, bytes); } +EsPrintDirect :: inline proc (string :^i8, stringLength :uintptr){ ((proc (^i8, uintptr))(rawptr(uintptr(0x1000 + 73 * size_of(int)))))(string, stringLength); } +EsStringFormat :: inline proc (buffer :^i8, bufferLength :uintptr, format :^i8, args : ..any) -> uintptr{ return ((proc (^i8, uintptr, ^i8, ..any) -> uintptr)(rawptr(uintptr(0x1000 + 74 * size_of(int)))))(buffer, bufferLength, format, ); } +EsStringFormatAppend :: inline proc (buffer :^i8, bufferLength :uintptr, bufferPosition :^uintptr, format :^i8, args : ..any){ ((proc (^i8, uintptr, ^uintptr, ^i8, ..any))(rawptr(uintptr(0x1000 + 75 * size_of(int)))))(buffer, bufferLength, bufferPosition, format, ); } +EsPrintHelloWorld :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 76 * size_of(int)))))(); } +EsGetRandomByte :: inline proc () -> u8{ return ((proc () -> u8)(rawptr(uintptr(0x1000 + 77 * size_of(int)))))(); } +EsSort :: inline proc (_base :^rawptr, nmemb :uintptr, size :uintptr, compar :EsComparisonCallbackFunction, argument :EsGeneric){ ((proc (^rawptr, uintptr, uintptr, EsComparisonCallbackFunction, EsGeneric))(rawptr(uintptr(0x1000 + 78 * size_of(int)))))(_base, nmemb, size, compar, argument); } +EsSortWithSwapCallback :: inline proc (_base :^rawptr, nmemb :uintptr, size :uintptr, compar :EsComparisonCallbackFunction, argument :EsGeneric, swap :EsSwapCallbackFunction){ ((proc (^rawptr, uintptr, uintptr, EsComparisonCallbackFunction, EsGeneric, EsSwapCallbackFunction))(rawptr(uintptr(0x1000 + 79 * size_of(int)))))(_base, nmemb, size, compar, argument, swap); } +EsStringCompare :: inline proc (s1 :^i8, s2 :^i8, length1 :uintptr, length2 :uintptr) -> i32{ return ((proc (^i8, ^i8, uintptr, uintptr) -> i32)(rawptr(uintptr(0x1000 + 80 * size_of(int)))))(s1, s2, length1, length2); } +EsIntegerParse :: inline proc (text :^i8, bytes :uintptr) -> i64{ return ((proc (^i8, uintptr) -> i64)(rawptr(uintptr(0x1000 + 81 * size_of(int)))))(text, bytes); } +EsCRTmemset :: inline proc (s :^rawptr, c :i32, n :uintptr){ ((proc (^rawptr, i32, uintptr))(rawptr(uintptr(0x1000 + 82 * size_of(int)))))(s, c, n); } +EsCRTmemcpy :: inline proc (dest :^rawptr, src :^rawptr, n :uintptr){ ((proc (^rawptr, ^rawptr, uintptr))(rawptr(uintptr(0x1000 + 83 * size_of(int)))))(dest, src, n); } +EsCRTmemmove :: inline proc (dest :^rawptr, src :^rawptr, n :uintptr){ ((proc (^rawptr, ^rawptr, uintptr))(rawptr(uintptr(0x1000 + 84 * size_of(int)))))(dest, src, n); } +EsCRTstrlen :: inline proc (s :^i8) -> uintptr{ return ((proc (^i8) -> uintptr)(rawptr(uintptr(0x1000 + 85 * size_of(int)))))(s); } +EsCRTstrnlen :: inline proc (s :^i8, maxlen :uintptr) -> uintptr{ return ((proc (^i8, uintptr) -> uintptr)(rawptr(uintptr(0x1000 + 86 * size_of(int)))))(s, maxlen); } +EsCRTmalloc :: inline proc (size :uintptr){ ((proc (uintptr))(rawptr(uintptr(0x1000 + 87 * size_of(int)))))(size); } +EsCRTcalloc :: inline proc (num :uintptr, size :uintptr){ ((proc (uintptr, uintptr))(rawptr(uintptr(0x1000 + 88 * size_of(int)))))(num, size); } +EsCRTfree :: inline proc (ptr :^rawptr){ ((proc (^rawptr))(rawptr(uintptr(0x1000 + 89 * size_of(int)))))(ptr); } +EsCRTabs :: inline proc (n :i32) -> i32{ return ((proc (i32) -> i32)(rawptr(uintptr(0x1000 + 90 * size_of(int)))))(n); } +EsCRTrealloc :: inline proc (ptr :^rawptr, size :uintptr){ ((proc (^rawptr, uintptr))(rawptr(uintptr(0x1000 + 91 * size_of(int)))))(ptr, size); } +EsCRTgetenv :: inline proc (name :^i8) -> ^i8{ return ((proc (^i8) -> ^i8)(rawptr(uintptr(0x1000 + 92 * size_of(int)))))(name); } +EsCRTstrncmp :: inline proc (s1 :^i8, s2 :^i8, n :uintptr) -> i32{ return ((proc (^i8, ^i8, uintptr) -> i32)(rawptr(uintptr(0x1000 + 93 * size_of(int)))))(s1, s2, n); } +EsCRTmemcmp :: inline proc (s1 :^rawptr, s2 :^rawptr, n :uintptr) -> i32{ return ((proc (^rawptr, ^rawptr, uintptr) -> i32)(rawptr(uintptr(0x1000 + 94 * size_of(int)))))(s1, s2, n); } +EsCRTqsort :: inline proc (_base :^rawptr, nmemb :uintptr, size :uintptr, compar :EsCRTComparisonCallback){ ((proc (^rawptr, uintptr, uintptr, EsCRTComparisonCallback))(rawptr(uintptr(0x1000 + 95 * size_of(int)))))(_base, nmemb, size, compar); } +EsCRTstrcmp :: inline proc (s1 :^i8, s2 :^i8) -> i32{ return ((proc (^i8, ^i8) -> i32)(rawptr(uintptr(0x1000 + 96 * size_of(int)))))(s1, s2); } +EsCRTstrstr :: inline proc (haystack :^i8, needle :^i8) -> ^i8{ return ((proc (^i8, ^i8) -> ^i8)(rawptr(uintptr(0x1000 + 97 * size_of(int)))))(haystack, needle); } +EsCRTstrcpy :: inline proc (dest :^i8, src :^i8) -> ^i8{ return ((proc (^i8, ^i8) -> ^i8)(rawptr(uintptr(0x1000 + 98 * size_of(int)))))(dest, src); } +EsCRTisalpha :: inline proc (c :i32) -> i32{ return ((proc (i32) -> i32)(rawptr(uintptr(0x1000 + 99 * size_of(int)))))(c); } +EsCRTmemchr :: inline proc (_s :^rawptr, _c :i32, n :uintptr){ ((proc (^rawptr, i32, uintptr))(rawptr(uintptr(0x1000 + 100 * size_of(int)))))(_s, _c, n); } +EsCRTisdigit :: inline proc (c :i32) -> i32{ return ((proc (i32) -> i32)(rawptr(uintptr(0x1000 + 101 * size_of(int)))))(c); } +EsCRTstrcat :: inline proc (dest :^i8, src :^i8) -> ^i8{ return ((proc (^i8, ^i8) -> ^i8)(rawptr(uintptr(0x1000 + 102 * size_of(int)))))(dest, src); } +EsCRTtolower :: inline proc (c :i32) -> i32{ return ((proc (i32) -> i32)(rawptr(uintptr(0x1000 + 103 * size_of(int)))))(c); } +EsCRTstrncpy :: inline proc (dest :^i8, src :^i8, n :uintptr) -> ^i8{ return ((proc (^i8, ^i8, uintptr) -> ^i8)(rawptr(uintptr(0x1000 + 104 * size_of(int)))))(dest, src, n); } +EsCRTstrtoul :: inline proc (nptr :^i8, endptr :^^i8, base :i32) -> u64{ return ((proc (^i8, ^^i8, i32) -> u64)(rawptr(uintptr(0x1000 + 105 * size_of(int)))))(nptr, endptr, base); } +EsExecute :: inline proc (what :^i8, whatBytes :uintptr, argument :^i8, argumentBytes :uintptr){ ((proc (^i8, uintptr, ^i8, uintptr))(rawptr(uintptr(0x1000 + 106 * size_of(int)))))(what, whatBytes, argument, argumentBytes); } +EsAbort :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 107 * size_of(int)))))(); } +EsMailslotSendData :: inline proc (mailslot :EsHandle, data :^rawptr, bytes :uintptr) -> bool{ return ((proc (EsHandle, ^rawptr, uintptr) -> bool)(rawptr(uintptr(0x1000 + 108 * size_of(int)))))(mailslot, data, bytes); } +EsCRTfloorf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 109 * size_of(int)))))(x); } +EsCRTceilf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 110 * size_of(int)))))(x); } +EsCRTsinf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 111 * size_of(int)))))(x); } +EsCRTcosf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 112 * size_of(int)))))(x); } +EsCRTatan2f :: inline proc (y :f32, x :f32) -> f32{ return ((proc (f32, f32) -> f32)(rawptr(uintptr(0x1000 + 113 * size_of(int)))))(y, x); } +EsCRTfmodf :: inline proc (x :f32, y :f32) -> f32{ return ((proc (f32, f32) -> f32)(rawptr(uintptr(0x1000 + 114 * size_of(int)))))(x, y); } +EsCRTacosf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 115 * size_of(int)))))(x); } +EsCRTasinf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 116 * size_of(int)))))(x); } +EsCRTatanf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 117 * size_of(int)))))(x); } +EsRandomSeed :: inline proc (x :u64){ ((proc (u64))(rawptr(uintptr(0x1000 + 118 * size_of(int)))))(x); } +EsCRTsqrtf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 119 * size_of(int)))))(x); } +EsCRTsqrtl :: inline proc (x :EsLongDouble) -> EsLongDouble{ return ((proc (EsLongDouble) -> EsLongDouble)(rawptr(uintptr(0x1000 + 120 * size_of(int)))))(x); } +EsCRTfabsl :: inline proc (x :EsLongDouble) -> EsLongDouble{ return ((proc (EsLongDouble) -> EsLongDouble)(rawptr(uintptr(0x1000 + 121 * size_of(int)))))(x); } +_EsSyscall :: inline proc (a :uintptr, b :uintptr, c :uintptr, d :uintptr, e :uintptr, f :uintptr) -> uintptr{ return ((proc (uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) -> uintptr)(rawptr(uintptr(0x1000 + 122 * size_of(int)))))(a, b, c, d, e, f); } +EsProcessorReadTimeStamp :: inline proc () -> u64{ return ((proc () -> u64)(rawptr(uintptr(0x1000 + 123 * size_of(int)))))(); } +EsHeapAllocate :: inline proc (size :uintptr, zeroMemory :bool){ ((proc (uintptr, bool))(rawptr(uintptr(0x1000 + 124 * size_of(int)))))(size, zeroMemory); } +EsHeapFree :: inline proc (address :^rawptr){ ((proc (^rawptr))(rawptr(uintptr(0x1000 + 125 * size_of(int)))))(address); } +EsPrint :: inline proc (format :^i8, args : ..any){ ((proc (^i8, ..any))(rawptr(uintptr(0x1000 + 126 * size_of(int)))))(format, ); } +EsMemoryFill :: inline proc (from :^rawptr, to :^rawptr, byte :u8){ ((proc (^rawptr, ^rawptr, u8))(rawptr(uintptr(0x1000 + 127 * size_of(int)))))(from, to, byte); } +EsInitialiseCStandardLibrary :: inline proc (argc :^i32, argv :^^^i8){ ((proc (^i32, ^^^i8))(rawptr(uintptr(0x1000 + 128 * size_of(int)))))(argc, argv); } +EsMakeLinuxSystemCall2 :: inline proc (n :int, a1 :int, a2 :int, a3 :int, a4 :int, a5 :int, a6 :int) -> int{ return ((proc (int, int, int, int, int, int, int) -> int)(rawptr(uintptr(0x1000 + 129 * size_of(int)))))(n, a1, a2, a3, a4, a5, a6); } +EsProcessCreate2 :: inline proc (arguments :^EsProcessCreationArguments, information :^EsProcessInformation) -> EsError{ return ((proc (^EsProcessCreationArguments, ^EsProcessInformation) -> EsError)(rawptr(uintptr(0x1000 + 130 * size_of(int)))))(arguments, information); } +EsCRTatoi :: inline proc (string :^i8) -> i32{ return ((proc (^i8) -> i32)(rawptr(uintptr(0x1000 + 131 * size_of(int)))))(string); } +EsProcessGetExitStatus :: inline proc (process :EsHandle) -> i32{ return ((proc (EsHandle) -> i32)(rawptr(uintptr(0x1000 + 132 * size_of(int)))))(process); } +EsSurfaceReset :: inline proc (surface :EsHandle){ ((proc (EsHandle))(rawptr(uintptr(0x1000 + 133 * size_of(int)))))(surface); } +EsTimerCreate :: inline proc () -> EsHandle{ return ((proc () -> EsHandle)(rawptr(uintptr(0x1000 + 134 * size_of(int)))))(); } +EsTimerSet :: inline proc (handle :EsHandle, afterMs :u64, object :EsObject, argument :EsGeneric){ ((proc (EsHandle, u64, EsObject, EsGeneric))(rawptr(uintptr(0x1000 + 135 * size_of(int)))))(handle, afterMs, object, argument); } +EsFileWriteAll :: inline proc (filePath :^i8, filePathLength :uintptr, data :^rawptr, fileSize :uintptr) -> EsError{ return ((proc (^i8, uintptr, ^rawptr, uintptr) -> EsError)(rawptr(uintptr(0x1000 + 136 * size_of(int)))))(filePath, filePathLength, data, fileSize); } +EsUserGetHomeFolder :: inline proc (buffer :^i8, bufferBytes :uintptr) -> uintptr{ return ((proc (^i8, uintptr) -> uintptr)(rawptr(uintptr(0x1000 + 137 * size_of(int)))))(buffer, bufferBytes); } +EsAssert :: inline proc (expression :bool, failureMessage :^i8){ ((proc (bool, ^i8))(rawptr(uintptr(0x1000 + 138 * size_of(int)))))(expression, failureMessage); } +EsResizeArray :: inline proc (array :^^rawptr, allocated :^uintptr, needed :uintptr, itemSize :uintptr){ ((proc (^^rawptr, ^uintptr, uintptr, uintptr))(rawptr(uintptr(0x1000 + 139 * size_of(int)))))(array, allocated, needed, itemSize); } +EsMessageLoopEnter :: inline proc (callback :EsMessageCallbackFunction){ ((proc (EsMessageCallbackFunction))(rawptr(uintptr(0x1000 + 140 * size_of(int)))))(callback); } +_EsInstanceCreate :: inline proc (bytes :uintptr) -> ^EsInstance{ return ((proc (uintptr) -> ^EsInstance)(rawptr(uintptr(0x1000 + 141 * size_of(int)))))(bytes); } +EsMouseGetPosition :: inline proc (relativeWindow :^EsElement) -> EsPoint{ return ((proc (^EsElement) -> EsPoint)(rawptr(uintptr(0x1000 + 142 * size_of(int)))))(relativeWindow); } +EsMouseSetPosition :: inline proc (relativeWindow :^EsElement, x :i32, y :i32){ ((proc (^EsElement, i32, i32))(rawptr(uintptr(0x1000 + 143 * size_of(int)))))(relativeWindow, x, y); } +EsNewWindow :: inline proc (instance :^EsInstance, style :EsWindowStyle) -> ^EsElement{ return ((proc (^EsInstance, EsWindowStyle) -> ^EsElement)(rawptr(uintptr(0x1000 + 144 * size_of(int)))))(instance, style); } +EsNewPanel :: inline proc (parent :^EsElement, style :EsData, flags :u64) -> ^EsElement{ return ((proc (^EsElement, EsData, u64) -> ^EsElement)(rawptr(uintptr(0x1000 + 145 * size_of(int)))))(parent, style, flags); } +EsNewScrollbar :: inline proc (parent :^EsElement, flags :u64, userCallback :EsUICallbackFunction, _context :EsGeneric) -> ^EsElement{ return ((proc (^EsElement, u64, EsUICallbackFunction, EsGeneric) -> ^EsElement)(rawptr(uintptr(0x1000 + 146 * size_of(int)))))(parent, flags, userCallback, _context); } +EsNewButton :: inline proc (parent :^EsElement, label :^i8, labelBytes :int, flags :u64, userCallback :EsUICallbackFunction, _context :EsGeneric) -> ^EsElement{ return ((proc (^EsElement, ^i8, int, u64, EsUICallbackFunction, EsGeneric) -> ^EsElement)(rawptr(uintptr(0x1000 + 147 * size_of(int)))))(parent, label, labelBytes, flags, userCallback, _context); } +EsNewTextbox :: inline proc (parent :^EsElement, flags :u64, userCallback :EsUICallbackFunction, _context :EsGeneric) -> ^EsElement{ return ((proc (^EsElement, u64, EsUICallbackFunction, EsGeneric) -> ^EsElement)(rawptr(uintptr(0x1000 + 148 * size_of(int)))))(parent, flags, userCallback, _context); } +EsNewNumericEntry :: inline proc (parent :^EsElement, flags :u64, userCallback :EsUICallbackFunction, _context :EsGeneric) -> ^EsElement{ return ((proc (^EsElement, u64, EsUICallbackFunction, EsGeneric) -> ^EsElement)(rawptr(uintptr(0x1000 + 149 * size_of(int)))))(parent, flags, userCallback, _context); } +EsNewListView :: inline proc (parent :^EsElement, flags :u64, style :^EsListViewStyle, userCallback :EsUICallbackFunction, _context :EsGeneric) -> ^EsElement{ return ((proc (^EsElement, u64, ^EsListViewStyle, EsUICallbackFunction, EsGeneric) -> ^EsElement)(rawptr(uintptr(0x1000 + 150 * size_of(int)))))(parent, flags, style, userCallback, _context); } +EsElementGetInstance :: inline proc (element :^EsElement) -> ^EsInstance{ return ((proc (^EsElement) -> ^EsInstance)(rawptr(uintptr(0x1000 + 151 * size_of(int)))))(element); } +EsElementFocus :: inline proc (element :^EsElement, ensureVisible :bool){ ((proc (^EsElement, bool))(rawptr(uintptr(0x1000 + 152 * size_of(int)))))(element, ensureVisible); } +EsScrollbarSetMeasurements :: inline proc (scrollbar :^EsElement, viewportSize :i32, contentSize :i32){ ((proc (^EsElement, i32, i32))(rawptr(uintptr(0x1000 + 153 * size_of(int)))))(scrollbar, viewportSize, contentSize); } +EsScrollbarSetPosition :: inline proc (scrollbar :^EsElement, position :f32, sendMovedMessage :bool, smoothScroll :bool){ ((proc (^EsElement, f32, bool, bool))(rawptr(uintptr(0x1000 + 154 * size_of(int)))))(scrollbar, position, sendMovedMessage, smoothScroll); } +EsWindowGetBounds :: inline proc (window :^EsElement, bounds :^EsRectangle){ ((proc (^EsElement, ^EsRectangle))(rawptr(uintptr(0x1000 + 155 * size_of(int)))))(window, bounds); } +EsListViewInsert :: inline proc (listView :^EsElement, group :EsListViewIndex, index :EsListViewIndex, count :uintptr){ ((proc (^EsElement, EsListViewIndex, EsListViewIndex, uintptr))(rawptr(uintptr(0x1000 + 156 * size_of(int)))))(listView, group, index, count); } +EsListViewInsertGroup :: inline proc (listView :^EsElement, group :EsListViewIndex){ ((proc (^EsElement, EsListViewIndex))(rawptr(uintptr(0x1000 + 157 * size_of(int)))))(listView, group); } +EsListViewRemove :: inline proc (listView :^EsElement, group :EsListViewIndex, index :EsListViewIndex, count :int, removedHeight :i32){ ((proc (^EsElement, EsListViewIndex, EsListViewIndex, int, i32))(rawptr(uintptr(0x1000 + 158 * size_of(int)))))(listView, group, index, count, removedHeight); } +EsListViewRemoveGroup :: inline proc (listView :^EsElement, group :EsListViewIndex){ ((proc (^EsElement, EsListViewIndex))(rawptr(uintptr(0x1000 + 159 * size_of(int)))))(listView, group); } +EsListViewInvalidate :: inline proc (listView :^EsElement, deltaHeight :i32, recalculateHeight :bool){ ((proc (^EsElement, i32, bool))(rawptr(uintptr(0x1000 + 160 * size_of(int)))))(listView, deltaHeight, recalculateHeight); } +EsListViewEnsureVisible :: inline proc (listView :^EsElement, group :EsListViewIndex, index :EsListViewIndex){ ((proc (^EsElement, EsListViewIndex, EsListViewIndex))(rawptr(uintptr(0x1000 + 161 * size_of(int)))))(listView, group, index); } +EsListViewResetSearchBuffer :: inline proc (object :^EsElement){ ((proc (^EsElement))(rawptr(uintptr(0x1000 + 162 * size_of(int)))))(object); } +EsDataParse :: inline proc (cFormat :^i8, args : ..any) -> EsData{ return ((proc (^i8, ..any) -> EsData)(rawptr(uintptr(0x1000 + 163 * size_of(int)))))(cFormat, ); } +EsDataNone :: inline proc () -> EsData{ return ((proc () -> EsData)(rawptr(uintptr(0x1000 + 164 * size_of(int)))))(); } + +////////////////////////////////////////////////////// + +Handle :: distinct i32; +Errno :: distinct i32; + +INVALID_HANDLE :: ~Handle(0); + +stdin: Handle = 0; +stdout: Handle = 1; +stderr: Handle = 2; + +O_RDONLY :: 0x00000; +O_WRONLY :: 0x00001; +O_RDWR :: 0x00002; O_CREATE :: 0x00040; O_EXCL :: 0x00080; +O_NOCTTY :: 0x00100; O_TRUNC :: 0x00200; +O_NONBLOCK :: 0x00800; O_APPEND :: 0x00400; +O_SYNC :: 0x01000; +O_ASYNC :: 0x02000; +O_CLOEXEC :: 0x80000; -ERROR_NONE :: Errno(-1); -ERROR_UNKNOWN_OPERATION_FAILURE :: Errno(-7); -ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME :: Errno(-14); -ERROR_PATH_NOT_FOUND :: Errno(-15); -ERROR_FILE_EXISTS :: Errno(-19); -ERROR_FILE_NOT_FOUND :: Errno(-20); -ERROR_DRIVE_ERROR_FILE_DAMAGED :: Errno(-21); -ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS :: Errno(-22); -ERROR_ACCESS_DENIED :: Errno(-23); -ERROR_FILE_IN_EXCLUSIVE_USE :: Errno(-24); -ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE :: Errno(-25); -ERROR_INCORRECT_NODE_TYPE :: Errno(-26); -ERROR_EVENT_NOT_SET :: Errno(-27); -ERROR_TIMEOUT_REACHED :: Errno(-29); -ERROR_REQUEST_CLOSED_BEFORE_COMPLETE :: Errno(-30); -ERROR_NO_CHARACTER_AT_COORDINATE :: Errno(-31); -ERROR_FILE_ON_READ_ONLY_VOLUME :: Errno(-32); -ERROR_USER_CANCELED_IO :: Errno(-33); -ERROR_DRIVE_CONTROLLER_REPORTED :: Errno(-35); -ERROR_COULD_NOT_ISSUE_PACKET :: Errno(-36); +ERROR_UNSUPPORTED :: 1; -ERROR_NOT_IMPLEMENTED :: Errno(1); - -OS_Node_Type :: enum i32 { - File = 0, - Directory = 1, -} - -OS_Node_Information :: struct { - handle: Handle, - id: [16]byte, - ntype: OS_Node_Type, - size: i64, - - // Our additions.. - position: i64, -} - -foreign api { - @(link_name="OSPrintDirect") OSPrintDirect :: proc(str: ^u8, length: int) ---; - @(link_name="malloc") OSMalloc :: proc(bytes: int) -> rawptr ---; - @(link_name="free") OSFree :: proc(address: rawptr) ---; - @(link_name="OSOpenNode") OSOpenNode :: proc(path: ^u8, path_length: int, flags: u64, information: ^OS_Node_Information) -> Errno ---; - @(link_name="OSResizeFile") OSResizeFile :: proc(handle: Handle, new_size: u64) -> Errno ---; - @(link_name="OSCloseHandle") OSCloseHandle :: proc(handle: Handle) ---; - @(link_name="OSWriteFileSync") OSWriteFileSync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---; - @(link_name="OSReadFileSync") OSReadFileSync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---; - @(link_name="realloc") OSRealloc :: proc(address: rawptr, size: int) -> rawptr ---; - @(link_name="OSGetThreadID") OSGetThreadID :: proc(handle: Handle) -> int ---; - @(link_name="OSRefreshNodeInformation") OSRefreshNodeInformation :: proc(information: ^OS_Node_Information) ---; -} - -stdin := Handle(-1); // Not implemented -stdout := Handle(0); -stderr := Handle(0); - -is_path_separator :: proc(r: rune) -> bool { - return r == '/'; -} - -current_thread_id :: proc "contextless" () -> int { - return OSGetThreadID(Handle(0x1000)); -} - -heap_alloc :: proc(size: int) -> rawptr { - return OSMalloc(size); -} - -heap_free :: proc(address: rawptr) { - OSFree(address); -} - -heap_resize :: proc(address: rawptr, new_size: int) -> rawptr { - return OSRealloc(address, new_size); -} - -open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) { - flags : u64 = 0; - - if mode & O_CREATE == O_CREATE { - flags = flags | 0x9000; // Fail if found and create directories leading to the file if they don't exist - } else { - flags = flags | 0x2000; // Fail if not found - } - - if mode & O_EXCL == O_EXCL { - flags = flags | 0x111; // Block opening the node for any reason - } - - if mode & O_RDONLY == O_RDONLY { - flags = flags | 0x2; // Read access - } - - if mode & O_WRONLY == O_WRONLY { - flags = flags | 0x220; // Write and resize access - } - - if mode & O_TRUNC == O_TRUNC { - flags = flags | 0x200; // Resize access - } - - information := new(OS_Node_Information); - error := OSOpenNode(&path[0], len(path), flags, information); - - if error < ERROR_NONE { - free(information); - return 0, error; - } - - if mode & O_TRUNC == O_TRUNC { - error := OSResizeFile(information.handle, 0); - if error < ERROR_NONE do return 0, ERROR_UNKNOWN_OPERATION_FAILURE; - } - - if mode & O_APPEND == O_APPEND { - information.position = information.size; - } else { - information.position = 0; - } - - return Handle(uintptr(information)), ERROR_NONE; -} - -close :: proc(fd: Handle) { - information := (^OS_Node_Information)(uintptr(fd)); - OSCloseHandle(information.handle); - free(information); -} - -file_size :: proc(fd: Handle) -> (i64, Errno) { - x: OS_Node_Information; - OSRefreshNodeInformation(&x); - return x.size, ERROR_NONE; +read :: proc(fd: Handle, data: []byte) -> (int, Errno) { + return -1, ERROR_UNSUPPORTED; } write :: proc(fd: Handle, data: []byte) -> (int, Errno) { - if fd == 0 { - OSPrintDirect(&data[0], len(data)); - return len(data), ERROR_NONE; - } else if fd == 1 { - assert(false); - return 0, ERROR_NOT_IMPLEMENTED; - } - - information := (^OS_Node_Information)(uintptr(fd)); - count := OSWriteFileSync(information.handle, information.position, i64(len(data)), &data[0]); - if count < 0 do return 0, 1; - information.position += count; - return int(count), 0; + return -1, ERROR_UNSUPPORTED; } -read :: proc(fd: Handle, data: []byte) -> (int, Errno) { - if (fd == 0 || fd == 1) { - assert(false); - return 0, ERROR_NOT_IMPLEMENTED; - } - - information := (^OS_Node_Information)(uintptr(fd)); - count := OSReadFileSync(information.handle, information.position, i64(len(data)), &data[0]); - if count < 0 do return 0, ERROR_UNKNOWN_OPERATION_FAILURE; - information.position += count; - return int(count), ERROR_NONE; +open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { + return -1, ERROR_UNSUPPORTED; } + +close :: proc(fd: Handle) -> Errno { + return ERROR_UNSUPPORTED; +} + +file_size :: proc(fd: Handle) -> (i64, Errno) { + return 0, ERROR_UNSUPPORTED; +} + +heap_alloc :: proc(size: int) -> rawptr { + return nil; +} + +heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { + return nil; +} + +heap_free :: proc(ptr: rawptr) { +} + +current_thread_id :: proc "contextless" () -> int { + // return int(EsThreadGetID(ES_CURRENT_THREAD)); + return -1; +} + +OS :: "essence"; diff --git a/core/sys/essence_linker_userland64.ld b/core/sys/essence_linker_userland64.ld deleted file mode 100644 index 5f6d92791..000000000 --- a/core/sys/essence_linker_userland64.ld +++ /dev/null @@ -1,24 +0,0 @@ -ENTRY(_start) - -SECTIONS -{ - . = 0x100000; - .text BLOCK(4K) : ALIGN(4K) - { - *(.text) - } - .rodata BLOCK(4K) : ALIGN(4K) - { - *(.rodata) - } - .data BLOCK(4K) : ALIGN(4K) - { - *(.data) - } - - .bss BLOCK(4K) : ALIGN(4K) - { - *(COMMON) - *(.bss) - } -} diff --git a/core/time/time_essence.odin b/core/time/time_essence.odin new file mode 100644 index 000000000..11713d84b --- /dev/null +++ b/core/time/time_essence.odin @@ -0,0 +1,2 @@ +package time +IS_SUPPORTED :: false; diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 992443f7c..956ffe1ed 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -56,8 +56,6 @@ TargetEndianKind target_endians[TargetArch_COUNT] = { String const ODIN_VERSION = str_lit("0.10.1"); -String cross_compile_target = str_lit(""); -String cross_compile_lib_dir = str_lit(""); @@ -66,6 +64,7 @@ struct TargetMetrics { TargetArchKind arch; isize word_size; isize max_align; + String target_triplet; }; @@ -109,6 +108,7 @@ struct BuildContext { bool has_resource; String opt_flags; String llc_flags; + String target_triplet; String link_flags; bool is_dll; bool generate_docs; @@ -121,6 +121,7 @@ struct BuildContext { bool no_crt; bool use_lld; bool vet; + bool cross_compiling; QueryDataSetSettings query_data_set_settings; @@ -135,18 +136,19 @@ struct BuildContext { gb_global BuildContext build_context = {0}; - gb_global TargetMetrics target_windows_386 = { TargetOs_windows, TargetArch_386, 4, 8, + str_lit("i686-pc-windows"), }; gb_global TargetMetrics target_windows_amd64 = { TargetOs_windows, TargetArch_amd64, 8, 16, + str_lit("x86_64-pc-windows-gnu"), }; gb_global TargetMetrics target_linux_386 = { @@ -154,12 +156,14 @@ gb_global TargetMetrics target_linux_386 = { TargetArch_386, 4, 8, + str_lit("i686-pc-linux-gnu"), }; gb_global TargetMetrics target_linux_amd64 = { TargetOs_linux, TargetArch_amd64, 8, 16, + str_lit("x86_64-pc-linux-gnu"), }; gb_global TargetMetrics target_osx_amd64 = { @@ -167,10 +171,32 @@ gb_global TargetMetrics target_osx_amd64 = { TargetArch_amd64, 8, 16, + str_lit("x86_64-apple-darwin"), }; +gb_global TargetMetrics target_essence_amd64 = { + TargetOs_essence, + TargetArch_amd64, + 8, + 16, + str_lit("x86_64-pc-none-elf"), +}; +struct NamedTargetMetrics { + String name; + TargetMetrics *metrics; +}; +gb_global NamedTargetMetrics named_targets[] = { + { str_lit("essence_amd64"), &target_essence_amd64 }, + { str_lit("macos_amd64"), &target_osx_amd64 }, + { str_lit("linux_386"), &target_linux_386 }, + { str_lit("linux_amd64"), &target_linux_amd64 }, + { str_lit("windows_386"), &target_windows_386 }, + { str_lit("windows_amd64"), &target_windows_amd64 }, +}; + +NamedTargetMetrics *selected_target_metrics; TargetOsKind get_target_os_from_string(String str) { for (isize i = 0; i < TargetOs_COUNT; i++) { @@ -522,7 +548,7 @@ String get_fullpath_core(gbAllocator a, String path) { -void init_build_context(void) { +void init_build_context(TargetMetrics *cross_target) { BuildContext *bc = &build_context; gb_affinity_init(&bc->affinity); @@ -554,8 +580,9 @@ void init_build_context(void) { #endif #endif - if (cross_compile_target.len) { - bc->ODIN_OS = cross_compile_target; + if (cross_target) { + metrics = *cross_target; + bc->cross_compiling = true; } GB_ASSERT(metrics.os != TargetOs_Invalid); @@ -573,6 +600,7 @@ void init_build_context(void) { bc->max_align = metrics.max_align; bc->link_flags = str_lit(" "); bc->opt_flags = str_lit(" "); + bc->target_triplet = metrics.target_triplet; gbString llc_flags = gb_string_make_reserve(heap_allocator(), 64); diff --git a/src/ir.cpp b/src/ir.cpp index 26f787976..9e44b837f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10937,12 +10937,14 @@ void ir_gen_tree(irGen *s) { // main :: proc(argc: i32, argv: ^^u8) -> i32 String name = str_lit("main"); +#if 0 if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) { // This is a bit hacky, // because this makes this function the first function run in the executable // so it won't actually have the argc/argv arguments. name = str_lit("ProgramEntry"); } +#endif Type *proc_params = alloc_type_tuple(); Type *proc_results = alloc_type_tuple(); diff --git a/src/main.cpp b/src/main.cpp index 05fa6c366..539480bf4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -75,7 +75,7 @@ i32 system_exec_command_line_app(char *name, char *fmt, ...) { va_end(va); cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1); - //printf("do: %s\n", cmd_line); + // printf("do: %s\n", cmd_line); exit_code = system(&cmd_line[0]); // pid_t pid = fork(); @@ -210,9 +210,8 @@ enum BuildFlagKind { BuildFlag_Collection, BuildFlag_Define, BuildFlag_BuildMode, + BuildFlag_Target, BuildFlag_Debug, - BuildFlag_CrossCompile, - BuildFlag_CrossLibDir, BuildFlag_NoBoundsCheck, BuildFlag_NoCRT, BuildFlag_UseLLD, @@ -298,9 +297,8 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String); add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String); add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String); + add_flag(&build_flags, BuildFlag_Target, str_lit("target"), BuildFlagParam_String); add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None); - add_flag(&build_flags, BuildFlag_CrossCompile, str_lit("cross-compile"), BuildFlagParam_String); - add_flag(&build_flags, BuildFlag_CrossLibDir, str_lit("cross-lib-dir"), BuildFlagParam_String); add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None); @@ -478,33 +476,6 @@ bool parse_build_flags(Array args) { build_context.keep_temp_files = true; break; - case BuildFlag_CrossCompile: { - GB_ASSERT(value.kind == ExactValue_String); - cross_compile_target = value.value_string; - #if defined(GB_SYSTEM_UNIX) && defined(GB_ARCH_64_BIT) - if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) { - - } else - #endif - { - gb_printf_err("Unsupported cross compilation target '%.*s'\n", LIT(cross_compile_target)); - gb_printf_err("Currently supported targets: Essence (from 64-bit Unixes only)\n"); - bad_flags = true; - } - break; - } - - case BuildFlag_CrossLibDir: { - GB_ASSERT(value.kind == ExactValue_String); - if (cross_compile_lib_dir.len) { - gb_printf_err("Multiple cross compilation library directories\n"); - bad_flags = true; - } else { - cross_compile_lib_dir = concatenate_strings(heap_allocator(), str_lit("-L"), value.value_string); - } - break; - } - case BuildFlag_Collection: { GB_ASSERT(value.kind == ExactValue_String); String str = value.value_string; @@ -623,7 +594,25 @@ bool parse_build_flags(Array args) { break; } + case BuildFlag_Target: { + String str = value.value_string; + bool found = false; + for (int i = 0; i < sizeof(named_targets) / sizeof(named_targets[0]); i++) { + if (str_eq_ignore_case(str, named_targets[i].name)) { + found = true; + selected_target_metrics = named_targets + i; + break; + } + } + + if (!found) { + gb_printf_err("Unknown target '%.*s'\n", LIT(str)); + bad_flags = true; + } + + break; + } case BuildFlag_BuildMode: { GB_ASSERT(value.kind == ExactValue_String); @@ -889,8 +878,8 @@ i32 exec_llvm_opt(String output_base) { } i32 exec_llvm_llc(String output_base) { -#if defined(GB_SYSTEM_WINDOWS) // For more arguments: http://llvm.org/docs/CommandGuide/llc.html +#if defined(GB_SYSTEM_WINDOWS) return system_exec_command_line_app("llvm-llc", "\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d " "-o \"%.*s.obj\" " @@ -903,21 +892,19 @@ i32 exec_llvm_llc(String output_base) { LIT(build_context.llc_flags)); #else // NOTE(zangent): Linux / Unix is unfinished and not tested very well. - // For more arguments: http://llvm.org/docs/CommandGuide/llc.html return system_exec_command_line_app("llc", "llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d " "%.*s " - "%s" - "", + "%s%.*s", LIT(output_base), build_context.optimization_level, LIT(build_context.llc_flags), - str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-mtriple=x86_64-pc-none-elf" : ""); + build_context.cross_compiling ? "-mtriple=" : "", + (int) (build_context.cross_compiling ? build_context.target_triplet.len : 0), + build_context.target_triplet.text); #endif } - - int main(int arg_count, char **arg_ptr) { if (arg_count < 2) { usage(make_string_c(arg_ptr[0])); @@ -1026,7 +1013,7 @@ int main(int arg_count, char **arg_ptr) { } - init_build_context(); + init_build_context(selected_target_metrics ? selected_target_metrics->metrics : nullptr); if (build_context.word_size == 4) { print_usage_line(0, "%s 32-bit is not yet supported", args[0]); return 1; @@ -1121,6 +1108,17 @@ int main(int arg_count, char **arg_ptr) { return exit_code; } + if (build_context.cross_compiling) { + if (0) { +#ifdef GB_SYSTEM_UNIX + } else if (selected_target_metrics->metrics == &target_essence_amd64) { + system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s", + LIT(output_base), LIT(output_base), LIT(build_context.link_flags)); +#endif + } else { + gb_printf_err("Don't know how to cross compile to selected target.\n"); + } + } else { #if defined(GB_SYSTEM_WINDOWS) timings_start_section(&timings, str_lit("msvc-link")); @@ -1309,11 +1307,7 @@ int main(int arg_count, char **arg_ptr) { // It probably has to do with including the entire CRT, but // that's quite a complicated issue to solve while remaining distro-agnostic. // Clang can figure out linker flags for us, and that's good enough _for now_. - if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) { - linker = "x86_64-elf-gcc -T core/sys/essence_linker_userland64.ld -ffreestanding -nostdlib -lgcc -g -z max-page-size=0x1000 -Wno-unused-command-line-argument"; - } else { - linker = "clang -Wno-unused-command-line-argument"; - } + linker = "clang -Wno-unused-command-line-argument"; #endif exit_code = system_exec_command_line_app("ld-link", @@ -1321,7 +1315,6 @@ int main(int arg_count, char **arg_ptr) { " %s " " %.*s " " %s " - " %.*s " #if defined(GB_SYSTEM_OSX) // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. // NOTE: If you change this (although this minimum is as low as you can go with Odin working) @@ -1332,11 +1325,9 @@ int main(int arg_count, char **arg_ptr) { #endif , linker, LIT(output_base), LIT(output_base), LIT(output_ext), lib_str, - str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-lfreetype -lglue" : "-lc -lm", + "-lc -lm", LIT(build_context.link_flags), - link_settings, - LIT(cross_compile_lib_dir) - ); + link_settings); if (exit_code != 0) { return exit_code; } @@ -1369,6 +1360,7 @@ int main(int arg_count, char **arg_ptr) { system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); } #endif + } return 0; } From 495aaacb81b1b1a8175c9ad8aaa4448ab4085b6a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Sep 2019 18:35:00 +0100 Subject: [PATCH 060/143] Fix build.bat --- build.bat | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/build.bat b/build.bat index 334102cf1..61b3742a2 100644 --- a/build.bat +++ b/build.bat @@ -40,10 +40,9 @@ del *.pdb > NUL 2> NUL del *.ilk > NUL 2> NUL -rem cl %compiler_settings% "src\main.cpp" ^ - rem /link %linker_settings% -OUT:%exe_name% ^ - rem && odin build examples/demo/demo.odin -show-timings -odin check examples/demo/demo.odin -show-timings +cl %compiler_settings% "src\main.cpp" ^ + /link %linker_settings% -OUT:%exe_name% ^ + && odin run examples/demo/demo.odin del *.obj > NUL 2> NUL From 1348d8a8cdefcb02be6ad9346ecbf24a4635fe0c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Sep 2019 18:49:23 +0100 Subject: [PATCH 061/143] Improve thread pool (volatile hints, etc) --- src/gb/gb.h | 8 +++---- src/parser.cpp | 2 +- src/thread_pool.cpp | 57 +++++++++++++++++++++++++++++++-------------- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/gb/gb.h b/src/gb/gb.h index 65b8b2ff6..1b2bc5188 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -978,10 +978,10 @@ typedef struct gbThread { pthread_t posix_handle; #endif - gbThreadProc *proc; - void * user_data; - isize user_index; - isize return_value; + gbThreadProc * proc; + void * user_data; + isize user_index; + isize volatile return_value; gbSemaphore semaphore; isize stack_size; diff --git a/src/parser.cpp b/src/parser.cpp index e4d21e72a..a026e8ecd 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4822,7 +4822,7 @@ ParseFileError parse_packages(Parser *p, String init_filename) { thread_pool_kick_and_wait(&parser_thread_pool); // NOTE(bill): Get the last error and use that - for (isize i = parser_thread_pool.threads.count-1; i >= 0; i--) { + for (isize i = parser_thread_pool.thread_count-1; i >= 0; i--) { gbThread *t = &parser_thread_pool.threads[i]; ParseFileError err = cast(ParseFileError)t->return_value; if (err != ParseFile_None) { diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index 83178ea47..bbe9ccac6 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -16,8 +16,14 @@ struct ThreadPool { gbAtomic32 processing_work_count; bool is_running; - Array tasks; - Array threads; + gbAllocator allocator; + + WorkerTask *tasks; + isize volatile task_count; + isize volatile task_capacity; + + gbThread *threads; + isize thread_count; char worker_prefix[10]; i32 worker_prefix_len; @@ -33,8 +39,12 @@ void thread_pool_kick_and_wait(ThreadPool *pool); GB_THREAD_PROC(worker_thread_internal); void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count, char const *worker_prefix) { - pool->tasks = array_make(a, 0, 1024); - pool->threads = array_make(a, thread_count); + pool->allocator = a; + pool->task_count = 0; + pool->task_capacity = 1024; + pool->tasks = gb_alloc_array(a, WorkerTask, pool->task_capacity); + pool->threads = gb_alloc_array(a, gbThread, thread_count); + pool->thread_count = thread_count; gb_mutex_init(&pool->task_mutex); gb_mutex_init(&pool->mutex); gb_semaphore_init(&pool->semaphore); @@ -48,7 +58,7 @@ void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count pool->worker_prefix_len = worker_prefix_len; } - for_array(i, pool->threads) { + for (isize i = 0; i < pool->thread_count; i++) { gbThread *t = &pool->threads[i]; gb_thread_init(t); t->user_index = i; @@ -63,7 +73,7 @@ void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count } void thread_pool_start(ThreadPool *pool) { - for_array(i, pool->threads) { + for (isize i = 0; i < pool->thread_count; i++) { gbThread *t = &pool->threads[i]; gb_thread_start(t, worker_thread_internal, pool); } @@ -72,11 +82,11 @@ void thread_pool_start(ThreadPool *pool) { void thread_pool_join(ThreadPool *pool) { pool->is_running = false; - for_array(i, pool->threads) { + for (isize i = 0; i < pool->thread_count; i++) { gb_semaphore_release(&pool->semaphore); } - for_array(i, pool->threads) { + for (isize i = 0; i < pool->thread_count; i++) { gbThread *t = &pool->threads[i]; gb_thread_join(t); } @@ -89,18 +99,30 @@ void thread_pool_destroy(ThreadPool *pool) { gb_semaphore_destroy(&pool->semaphore); gb_mutex_destroy(&pool->mutex); gb_mutex_destroy(&pool->task_mutex); - array_free(&pool->threads); - array_free(&pool->tasks); + gb_free(pool->allocator, pool->threads); + pool->thread_count = 0; + gb_free(pool->allocator, pool->tasks); + pool->task_count = 0; + pool->task_capacity = 0; + } void thread_pool_add_task(ThreadPool *pool, WorkerTaskProc *proc, void *data) { gb_mutex_lock(&pool->task_mutex); + if (pool->task_count == pool->task_capacity) { + isize new_cap = 2*pool->task_capacity + 8; + WorkerTask *new_tasks = gb_alloc_array(pool->allocator, WorkerTask, new_cap); + gb_memmove(new_tasks, pool->tasks, pool->task_count*gb_size_of(WorkerTask)); + pool->tasks = new_tasks; + pool->task_capacity = new_cap; + } WorkerTask task = {}; task.do_work = proc; task.data = data; - array_add(&pool->tasks, task); + + pool->tasks[pool->task_count++] = task; gb_mutex_unlock(&pool->task_mutex); @@ -108,19 +130,20 @@ void thread_pool_add_task(ThreadPool *pool, WorkerTaskProc *proc, void *data) { } void thread_pool_kick(ThreadPool *pool) { - if (pool->tasks.count > 0) { - isize count = gb_min(pool->tasks.count, pool->threads.count); + gb_mutex_lock(&pool->task_mutex); + if (pool->task_count > 0) { + isize count = gb_max(pool->task_count, pool->thread_count); for (isize i = 0; i < count; i++) { gb_semaphore_post(&pool->semaphore, 1); } } - + gb_mutex_unlock(&pool->task_mutex); } void thread_pool_kick_and_wait(ThreadPool *pool) { thread_pool_kick(pool); isize return_value = 0; - while (pool->tasks.count > 0 || gb_atomic32_load(&pool->processing_work_count) != 0) { + while (pool->task_count > 0 || gb_atomic32_load(&pool->processing_work_count) != 0) { gb_yield(); } @@ -138,9 +161,9 @@ GB_THREAD_PROC(worker_thread_internal) { bool got_task = false; if (gb_mutex_try_lock(&pool->task_mutex)) { - if (pool->tasks.count > 0) { + if (pool->task_count > 0) { gb_atomic32_fetch_add(&pool->processing_work_count, +1); - task = array_pop(&pool->tasks); + task = pool->tasks[--pool->task_count]; got_task = true; } gb_mutex_unlock(&pool->task_mutex); From 1370c10d1b9012bd914cf35347f8f6d9ac1a0da0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Sep 2019 18:59:07 +0100 Subject: [PATCH 062/143] Fix Converting addresses to function pointers produces llvm-opt error #431 --- src/ir.cpp | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/ir.cpp b/src/ir.cpp index 26f787976..4d5a55814 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6967,7 +6967,34 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { } // NOTE(bill): Regular call - irValue *value = ir_build_expr(proc, ce->proc); + irValue *value = nullptr; + Ast *proc_expr = unparen_expr(ce->proc); + if (proc_expr->tav.mode == Addressing_Constant) { + ExactValue v = proc_expr->tav.value; + switch (v.kind) { + case ExactValue_Integer: + { + u64 u = big_int_to_u64(&v.value_integer); + irValue *x = ir_const_uintptr(u); + x = ir_emit_conv(proc, x, t_rawptr); + value = ir_emit_conv(proc, x, proc_expr->tav.type); + break; + } + case ExactValue_Pointer: + { + u64 u = cast(u64)v.value_pointer; + irValue *x = ir_const_uintptr(u); + x = ir_emit_conv(proc, x, t_rawptr); + value = ir_emit_conv(proc, x, proc_expr->tav.type); + break; + } + } + } + + if (value == nullptr) { + value = ir_build_expr(proc, proc_expr); + } + GB_ASSERT(value != nullptr); Type *proc_type_ = base_type(ir_type(value)); GB_ASSERT(proc_type_->kind == Type_Proc); From 1af143b7499fc035578a655ee4ca65ff164d9f04 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Sep 2019 21:16:17 +0100 Subject: [PATCH 063/143] Fix debug mode for build.bat --- build.bat | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.bat b/build.bat index 61b3742a2..6e5450c2b 100644 --- a/build.bat +++ b/build.bat @@ -4,14 +4,14 @@ set exe_name=odin.exe :: Debug = 0, Release = 1 -set release_mode=1 +set release_mode=0 set compiler_flags= -nologo -Oi -TP -fp:precise -Gm- -MP -FC -GS- -EHsc- -GR- if %release_mode% EQU 0 ( rem Debug - set compiler_flags=%compiler_flags% -Od -MDd -Zi + set compiler_flags=%compiler_flags% -Od -MDd -Z7 rem -DDISPLAY_TIMING ) else ( rem Release - set compiler_flags=%compiler_flags% -O2 -MT -Zi -DNO_ARRAY_BOUNDS_CHECK + set compiler_flags=%compiler_flags% -O2 -MT -Z7 -DNO_ARRAY_BOUNDS_CHECK ) set compiler_warnings= ^ From c92b2e961297b3bf0c37070c27bcba34e27a2b9b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 3 Sep 2019 21:17:46 +0100 Subject: [PATCH 064/143] Fix semaphore posting --- src/thread_pool.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index bbe9ccac6..8a32b7aca 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -124,15 +124,14 @@ void thread_pool_add_task(ThreadPool *pool, WorkerTaskProc *proc, void *data) { pool->tasks[pool->task_count++] = task; - gb_mutex_unlock(&pool->task_mutex); - gb_semaphore_post(&pool->semaphore, 1); + gb_mutex_unlock(&pool->task_mutex); } void thread_pool_kick(ThreadPool *pool) { gb_mutex_lock(&pool->task_mutex); if (pool->task_count > 0) { - isize count = gb_max(pool->task_count, pool->thread_count); + isize count = gb_min(pool->task_count, pool->thread_count); for (isize i = 0; i < count; i++) { gb_semaphore_post(&pool->semaphore, 1); } @@ -144,6 +143,14 @@ void thread_pool_kick_and_wait(ThreadPool *pool) { isize return_value = 0; while (pool->task_count > 0 || gb_atomic32_load(&pool->processing_work_count) != 0) { + + if (pool->task_count > 0 && gb_atomic32_load(&pool->processing_work_count) == 0) { + gb_mutex_lock(&pool->task_mutex); + for (isize i = 0; i < pool->task_count; i++) { + gb_semaphore_post(&pool->semaphore, 1); + } + gb_mutex_unlock(&pool->task_mutex); + } gb_yield(); } From 772c8779fa4ed38fcc53c1a7a5c4c93e8a13f05a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 3 Sep 2019 22:11:21 +0100 Subject: [PATCH 065/143] Clean up thread pool code --- src/gb/gb.h | 15 ++---- src/parser.cpp | 11 +++-- src/thread_pool.cpp | 112 ++++++++++++++++++++++---------------------- 3 files changed, 64 insertions(+), 74 deletions(-) diff --git a/src/gb/gb.h b/src/gb/gb.h index 1b2bc5188..60303729f 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -918,10 +918,7 @@ GB_DEF void gb_lfence (void); #if defined(GB_SYSTEM_WINDOWS) -typedef struct gbSemaphore { - void *win32_handle; - LONG count; -} gbSemaphore; +typedef struct gbSemaphore { void *win32_handle;} gbSemaphore; #elif defined(GB_SYSTEM_OSX) typedef struct gbSemaphore { semaphore_t osx_handle; } gbSemaphore; #elif defined(GB_SYSTEM_UNIX) @@ -4593,21 +4590,15 @@ gb_inline void gb_semaphore_release(gbSemaphore *s) { gb_semaphore_post(s, 1); } #if defined(GB_SYSTEM_WINDOWS) gb_inline void gb_semaphore_init(gbSemaphore *s) { s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL); - s->count = 0; } gb_inline void gb_semaphore_destroy(gbSemaphore *s) { CloseHandle(s->win32_handle); } gb_inline void gb_semaphore_post(gbSemaphore *s, i32 count) { - _InterlockedIncrement(&s->count); - if (ReleaseSemaphore(s->win32_handle, count, NULL) == FALSE) { - _InterlockedDecrement(&s->count); - } + ReleaseSemaphore(s->win32_handle, count, NULL); } gb_inline void gb_semaphore_wait(gbSemaphore *s) { - if (WaitForSingleObjectEx(s->win32_handle, INFINITE, FALSE) == WAIT_OBJECT_0) { - _InterlockedDecrement(&s->count); - } + WaitForSingleObjectEx(s->win32_handle, INFINITE, FALSE); } #elif defined(GB_SYSTEM_OSX) diff --git a/src/parser.cpp b/src/parser.cpp index a026e8ecd..b1d9a457f 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4798,7 +4798,8 @@ ParseFileError parse_packages(Parser *p, String init_filename) { GB_ASSERT(init_filename.text[init_filename.len] == 0); isize thread_count = gb_max(build_context.thread_count, 1); - thread_pool_init(&parser_thread_pool, heap_allocator(), thread_count, "ParserWork"); + isize worker_count = thread_count-1; // NOTE(bill): The main thread will also be used for work + thread_pool_init(&parser_thread_pool, heap_allocator(), worker_count, "ParserWork"); String init_fullpath = path_to_full_path(heap_allocator(), init_filename); if (!path_is_directory(init_fullpath)) { @@ -4819,12 +4820,12 @@ ParseFileError parse_packages(Parser *p, String init_filename) { p->init_fullpath = init_fullpath; thread_pool_start(&parser_thread_pool); - thread_pool_kick_and_wait(&parser_thread_pool); + thread_pool_wait_to_process(&parser_thread_pool); // NOTE(bill): Get the last error and use that - for (isize i = parser_thread_pool.thread_count-1; i >= 0; i--) { - gbThread *t = &parser_thread_pool.threads[i]; - ParseFileError err = cast(ParseFileError)t->return_value; + for (isize i = parser_thread_pool.task_tail-1; i >= 0; i--) { + WorkerTask *task = &parser_thread_pool.tasks[i]; + ParseFileError err = cast(ParseFileError)task->result; if (err != ParseFile_None) { return err; } diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index 8a32b7aca..2467ba609 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -6,20 +6,21 @@ typedef WORKER_TASK_PROC(WorkerTaskProc); struct WorkerTask { WorkerTaskProc *do_work; void *data; + isize result; }; struct ThreadPool { - gbMutex task_mutex; gbMutex mutex; - gbSemaphore semaphore; + gbSemaphore sem_available; gbAtomic32 processing_work_count; bool is_running; gbAllocator allocator; WorkerTask *tasks; - isize volatile task_count; + isize volatile task_head; + isize volatile task_tail; isize volatile task_capacity; gbThread *threads; @@ -40,14 +41,14 @@ GB_THREAD_PROC(worker_thread_internal); void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count, char const *worker_prefix) { pool->allocator = a; - pool->task_count = 0; + pool->task_head = 0; + pool->task_tail = 0; pool->task_capacity = 1024; pool->tasks = gb_alloc_array(a, WorkerTask, pool->task_capacity); - pool->threads = gb_alloc_array(a, gbThread, thread_count); - pool->thread_count = thread_count; - gb_mutex_init(&pool->task_mutex); + pool->thread_count = gb_max(thread_count, 0); + pool->threads = gb_alloc_array(a, gbThread, pool->thread_count); gb_mutex_init(&pool->mutex); - gb_semaphore_init(&pool->semaphore); + gb_semaphore_init(&pool->sem_available); pool->is_running = true; pool->worker_prefix_len = 0; @@ -63,6 +64,7 @@ void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count gb_thread_init(t); t->user_index = i; #if 0 + // TODO(bill): Fix this on Linux as it causes a seg-fault if (pool->worker_prefix_len > 0) { char worker_name[16] = {}; gb_snprintf(worker_name, gb_size_of(worker_name), "%.*s%u", pool->worker_prefix_len, pool->worker_prefix, cast(u16)i); @@ -82,9 +84,9 @@ void thread_pool_start(ThreadPool *pool) { void thread_pool_join(ThreadPool *pool) { pool->is_running = false; - for (isize i = 0; i < pool->thread_count; i++) { - gb_semaphore_release(&pool->semaphore); - } + gb_semaphore_post(&pool->sem_available, cast(i32)pool->thread_count); + + gb_yield(); for (isize i = 0; i < pool->thread_count; i++) { gbThread *t = &pool->threads[i]; @@ -96,25 +98,24 @@ void thread_pool_join(ThreadPool *pool) { void thread_pool_destroy(ThreadPool *pool) { thread_pool_join(pool); - gb_semaphore_destroy(&pool->semaphore); + gb_semaphore_destroy(&pool->sem_available); gb_mutex_destroy(&pool->mutex); - gb_mutex_destroy(&pool->task_mutex); gb_free(pool->allocator, pool->threads); pool->thread_count = 0; gb_free(pool->allocator, pool->tasks); - pool->task_count = 0; + pool->task_head = 0; + pool->task_tail = 0; pool->task_capacity = 0; - } void thread_pool_add_task(ThreadPool *pool, WorkerTaskProc *proc, void *data) { - gb_mutex_lock(&pool->task_mutex); + gb_mutex_lock(&pool->mutex); - if (pool->task_count == pool->task_capacity) { + if (pool->task_tail == pool->task_capacity) { isize new_cap = 2*pool->task_capacity + 8; WorkerTask *new_tasks = gb_alloc_array(pool->allocator, WorkerTask, new_cap); - gb_memmove(new_tasks, pool->tasks, pool->task_count*gb_size_of(WorkerTask)); + gb_memmove(new_tasks, pool->tasks, (pool->task_tail)*gb_size_of(WorkerTask)); pool->tasks = new_tasks; pool->task_capacity = new_cap; } @@ -122,35 +123,42 @@ void thread_pool_add_task(ThreadPool *pool, WorkerTaskProc *proc, void *data) { task.do_work = proc; task.data = data; - pool->tasks[pool->task_count++] = task; - - gb_semaphore_post(&pool->semaphore, 1); - gb_mutex_unlock(&pool->task_mutex); + pool->tasks[pool->task_tail++] = task; + gb_semaphore_post(&pool->sem_available, 1); + gb_mutex_unlock(&pool->mutex); } -void thread_pool_kick(ThreadPool *pool) { - gb_mutex_lock(&pool->task_mutex); - if (pool->task_count > 0) { - isize count = gb_min(pool->task_count, pool->thread_count); - for (isize i = 0; i < count; i++) { - gb_semaphore_post(&pool->semaphore, 1); +bool thread_pool_try_and_pop_task(ThreadPool *pool, WorkerTask *task) { + bool got_task = false; + if (gb_mutex_try_lock(&pool->mutex)) { + if (pool->task_tail > pool->task_head) { + gb_atomic32_fetch_add(&pool->processing_work_count, +1); + *task = pool->tasks[pool->task_head++]; + got_task = true; } + gb_mutex_unlock(&pool->mutex); } - gb_mutex_unlock(&pool->task_mutex); + return got_task; +} +void thread_pool_do_work(ThreadPool *pool, WorkerTask *task) { + task->result = task->do_work(task->data); + gb_atomic32_fetch_add(&pool->processing_work_count, -1); } -void thread_pool_kick_and_wait(ThreadPool *pool) { - thread_pool_kick(pool); - isize return_value = 0; - while (pool->task_count > 0 || gb_atomic32_load(&pool->processing_work_count) != 0) { - - if (pool->task_count > 0 && gb_atomic32_load(&pool->processing_work_count) == 0) { - gb_mutex_lock(&pool->task_mutex); - for (isize i = 0; i < pool->task_count; i++) { - gb_semaphore_post(&pool->semaphore, 1); - } - gb_mutex_unlock(&pool->task_mutex); +void thread_pool_wait_to_process(ThreadPool *pool) { + while (pool->task_tail > pool->task_head || gb_atomic32_load(&pool->processing_work_count) != 0) { + WorkerTask task = {}; + if (thread_pool_try_and_pop_task(pool, &task)) { + thread_pool_do_work(pool, &task); } + + // Safety-kick + if (pool->task_tail > pool->task_head && gb_atomic32_load(&pool->processing_work_count) == 0) { + gb_mutex_lock(&pool->mutex); + gb_semaphore_post(&pool->sem_available, cast(i32)(pool->task_tail-pool->task_head)); + gb_mutex_unlock(&pool->mutex); + } + gb_yield(); } @@ -160,27 +168,17 @@ void thread_pool_kick_and_wait(ThreadPool *pool) { GB_THREAD_PROC(worker_thread_internal) { ThreadPool *pool = cast(ThreadPool *)thread->user_data; - thread->return_value = 0; while (pool->is_running) { - gb_semaphore_wait(&pool->semaphore); + gb_semaphore_wait(&pool->sem_available); WorkerTask task = {}; - bool got_task = false; - - if (gb_mutex_try_lock(&pool->task_mutex)) { - if (pool->task_count > 0) { - gb_atomic32_fetch_add(&pool->processing_work_count, +1); - task = pool->tasks[--pool->task_count]; - got_task = true; - } - gb_mutex_unlock(&pool->task_mutex); - } - - if (got_task) { - thread->return_value = task.do_work(task.data); - gb_atomic32_fetch_add(&pool->processing_work_count, -1); + if (thread_pool_try_and_pop_task(pool, &task)) { + thread_pool_do_work(pool, &task); } } - return thread->return_value; + // Cascade + gb_semaphore_release(&pool->sem_available); + + return 0; } From d4914c3546b45ebca11d489481e58ecbd7f4e6a0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 4 Sep 2019 18:06:02 +0100 Subject: [PATCH 066/143] Fix Ir panic on using append() from within anonymous function #432 --- src/check_decl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 156c874ce..388b37864 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1208,13 +1208,14 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty check_scope_usage(ctx->checker, ctx->scope); -#if 0 +#if 1 if (decl->parent != nullptr) { Scope *ps = decl->parent->scope; if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) { return; } else { // NOTE(bill): Add the dependencies from the procedure literal (lambda) + // But only at the procedure level for_array(i, decl->deps.entries) { Entity *e = decl->deps.entries[i].ptr; ptr_set_add(&decl->parent->deps, e); From d54255505a1b7b2a460ce7f4a18ea30a92286aa1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 4 Sep 2019 18:10:02 +0100 Subject: [PATCH 067/143] Fix Compiler does not complain about missing semicolon #433 --- src/parser.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index b1d9a457f..123e1fcee 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1370,10 +1370,6 @@ void expect_semicolon(AstFile *f, Ast *s) { return; } - switch (f->curr_token.kind) { - case Token_EOF: - return; - } if (s != nullptr) { if (prev_token.pos.line != f->curr_token.pos.line) { @@ -1386,12 +1382,21 @@ void expect_semicolon(AstFile *f, Ast *s) { case Token_CloseParen: case Token_else: return; + case Token_EOF: + if (is_semicolon_optional_for_node(f, s)) { + return; + } + break; } } String node_string = ast_strings[s->kind]; syntax_error(prev_token, "Expected ';' after %.*s, got %.*s", - LIT(node_string), LIT(token_strings[prev_token.kind])); + LIT(node_string), LIT(token_strings[f->curr_token.kind])); } else { + switch (f->curr_token.kind) { + case Token_EOF: + return; + } syntax_error(prev_token, "Expected ';'"); } fix_advance_to_next_stmt(f); From 08dd8414c1f7c97e91f082cdace0bcea56603df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Hjortsh=C3=B8j?= Date: Sun, 8 Sep 2019 01:09:04 +0200 Subject: [PATCH 068/143] Make `odin run` return the process exit code --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 05fa6c366..00490bce7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1219,7 +1219,7 @@ int main(int arg_count, char **arg_ptr) { remove_temp_files(output_base); if (run_output) { - system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string)); + return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string)); } #else timings_start_section(&timings, str_lit("ld-link")); From bc34083c9c60397b88da0f594364791b5571ba61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Hjortsh=C3=B8j?= Date: Sun, 8 Sep 2019 01:10:54 +0200 Subject: [PATCH 069/143] Also return on unix --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 00490bce7..a75b711f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1366,7 +1366,7 @@ int main(int arg_count, char **arg_ptr) { //NOTE(thebirk): This whole thing is a little leaky String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext); complete_path = path_to_full_path(heap_allocator(), complete_path); - system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); + return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); } #endif From 4afc78efc682152a9b096781a1598fd1841ca938 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 8 Sep 2019 12:12:41 +0100 Subject: [PATCH 070/143] Add `where` clauses to `struct` and `union` --- core/odin/ast/ast.odin | 18 ++++++---- core/odin/parser/parser.odin | 42 +++++++++++++++++----- src/check_decl.cpp | 2 +- src/check_expr.cpp | 22 +++++------- src/check_type.cpp | 5 ++- src/checker.cpp | 2 +- src/parser.cpp | 67 +++++++++++++++++++++++++++--------- src/parser.hpp | 28 ++++++++------- 8 files changed, 125 insertions(+), 61 deletions(-) diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index f1ea79584..baad5f802 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -568,13 +568,15 @@ Dynamic_Array_Type :: struct { Struct_Type :: struct { using node: Expr, - tok_pos: token.Pos, - poly_params: ^Field_List, - align: ^Expr, - is_packed: bool, - is_raw_union: bool, - fields: ^Field_List, - name_count: int, + tok_pos: token.Pos, + poly_params: ^Field_List, + align: ^Expr, + fields: ^Field_List, + name_count: int, + where_token: token.Token, + where_clauses: []^Expr, + is_packed: bool, + is_raw_union: bool, } Union_Type :: struct { @@ -583,6 +585,8 @@ Union_Type :: struct { poly_params: ^Field_List, align: ^Expr, variants: []^Expr, + where_token: token.Token, + where_clauses: []^Expr, } Enum_Type :: struct { diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index a0d4d639e..f652e2c02 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2174,17 +2174,29 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { error(p, tok.pos, "'#raw_union' cannot also be '#packed"); } + where_token: token.Token; + where_clauses: []^ast.Expr; + if (p.curr_tok.kind == token.Where) { + where_token = expect_token(p, token.Where); + prev_level := p.expr_level; + p.expr_level = -1; + where_clauses = parse_rhs_expr_list(p); + p.expr_level = prev_level; + } + expect_token(p, token.Open_Brace); fields, name_count = parse_field_list(p, token.Close_Brace, ast.Field_Flags_Struct); close := expect_token(p, token.Close_Brace); st := ast.new(ast.Struct_Type, tok.pos, end_pos(close)); - st.poly_params = poly_params; - st.align = align; - st.is_packed = is_packed; - st.is_raw_union = is_raw_union; - st.fields = fields; - st.name_count = name_count; + st.poly_params = poly_params; + st.align = align; + st.is_packed = is_packed; + st.is_raw_union = is_raw_union; + st.fields = fields; + st.name_count = name_count; + st.where_token = where_token; + st.where_clauses = where_clauses; return st; case token.Union: @@ -2217,6 +2229,16 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { } p.expr_level = prev_level; + where_token: token.Token; + where_clauses: []^ast.Expr; + if (p.curr_tok.kind == token.Where) { + where_token = expect_token(p, token.Where); + prev_level := p.expr_level; + p.expr_level = -1; + where_clauses = parse_rhs_expr_list(p); + p.expr_level = prev_level; + } + variants: [dynamic]^ast.Expr; expect_token_after(p, token.Open_Brace, "union"); @@ -2234,9 +2256,11 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { close := expect_token(p, token.Close_Brace); ut := ast.new(ast.Union_Type, tok.pos, end_pos(close)); - ut.poly_params = poly_params; - ut.variants = variants[:]; - ut.align = align; + ut.poly_params = poly_params; + ut.variants = variants[:]; + ut.align = align; + ut.where_token = where_token; + ut.where_clauses = where_clauses; return ut; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 388b37864..173ba4a90 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1176,7 +1176,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty } - bool where_clause_ok = evaluate_where_clauses(ctx, decl, true); + bool where_clause_ok = evaluate_where_clauses(ctx, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true); if (!where_clause_ok) { // NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed return; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ca1aed970..8a5ed9c1c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5471,15 +5471,10 @@ Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize } -bool evaluate_where_clauses(CheckerContext *ctx, DeclInfo *decl, bool print_err) { - Ast *proc_lit = decl->proc_lit; - GB_ASSERT(proc_lit != nullptr); - GB_ASSERT(proc_lit->kind == Ast_ProcLit); - - if (proc_lit->ProcLit.where_token.kind != Token_Invalid) { - auto &clauses = proc_lit->ProcLit.where_clauses; - for_array(i, clauses) { - Ast *clause = clauses[i]; +bool evaluate_where_clauses(CheckerContext *ctx, Scope *scope, Array *clauses, bool print_err) { + if (clauses != nullptr) { + for_array(i, *clauses) { + Ast *clause = (*clauses)[i]; Operand o = {}; check_expr(ctx, &o, clause); if (o.mode != Addressing_Constant) { @@ -5494,10 +5489,10 @@ bool evaluate_where_clauses(CheckerContext *ctx, DeclInfo *decl, bool print_err) error(clause, "'where' clause evaluated to false:\n\t%s", str); gb_string_free(str); - if (decl->scope != nullptr) { + if (scope != nullptr) { isize print_count = 0; - for_array(j, decl->scope->elements.entries) { - Entity *e = decl->scope->elements.entries[j].value; + for_array(j, scope->elements.entries) { + Entity *e = scope->elements.entries[j].value; switch (e->kind) { case Entity_TypeName: { if (print_count == 0) error_line("\n\tWith the following definitions:\n"); @@ -5790,7 +5785,8 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type ctx.curr_proc_decl = decl; ctx.curr_proc_sig = e->type; - if (!evaluate_where_clauses(&ctx, decl, false)) { + GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); + if (!evaluate_where_clauses(&ctx, decl->scope, &decl->proc_lit->ProcLit.where_clauses, false)) { continue; } } diff --git a/src/check_type.cpp b/src/check_type.cpp index 2fa8939c4..e1602365a 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -504,8 +504,8 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< struct_type->Struct.polymorphic_params = polymorphic_params; struct_type->Struct.is_poly_specialized = is_poly_specialized; - if (!is_polymorphic) { + bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &st->where_clauses, true); check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context); } @@ -688,6 +688,9 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, ArrayUnion.is_polymorphic = is_polymorphic; union_type->Union.is_poly_specialized = is_poly_specialized; + bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &ut->where_clauses, true); + + for_array(i, ut->variants) { Ast *node = ut->variants[i]; Type *t = check_type_expr(ctx, node, nullptr); diff --git a/src/checker.cpp b/src/checker.cpp index 8fe71b63c..994e0776d 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3157,7 +3157,7 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) { Entity *e = scope->elements.entries[elem_index].value; if (e->scope == parent_scope) continue; - if (is_entity_exported(e)) { + if (is_entity_exported(e, true)) { Entity *found = scope_lookup_current(parent_scope, name); if (found != nullptr) { // NOTE(bill): diff --git a/src/parser.cpp b/src/parser.cpp index 123e1fcee..204ff3984 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -349,10 +349,12 @@ Ast *clone_ast(Ast *node) { n->StructType.fields = clone_ast_array(n->StructType.fields); n->StructType.polymorphic_params = clone_ast(n->StructType.polymorphic_params); n->StructType.align = clone_ast(n->StructType.align); + n->StructType.where_clauses = clone_ast_array(n->StructType.where_clauses); break; case Ast_UnionType: n->UnionType.variants = clone_ast_array(n->UnionType.variants); n->UnionType.polymorphic_params = clone_ast(n->UnionType.polymorphic_params); + n->UnionType.where_clauses = clone_ast_array(n->UnionType.where_clauses); break; case Ast_EnumType: n->EnumType.base_type = clone_ast(n->EnumType.base_type); @@ -921,7 +923,8 @@ Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) { Ast *ast_struct_type(AstFile *f, Token token, Array fields, isize field_count, Ast *polymorphic_params, bool is_packed, bool is_raw_union, - Ast *align) { + Ast *align, + Token where_token, Array const &where_clauses) { Ast *result = alloc_ast_node(f, Ast_StructType); result->StructType.token = token; result->StructType.fields = fields; @@ -930,17 +933,22 @@ Ast *ast_struct_type(AstFile *f, Token token, Array fields, isize field_c result->StructType.is_packed = is_packed; result->StructType.is_raw_union = is_raw_union; result->StructType.align = align; + result->StructType.where_token = where_token; + result->StructType.where_clauses = where_clauses; return result; } -Ast *ast_union_type(AstFile *f, Token token, Array variants, Ast *polymorphic_params, Ast *align, bool no_nil) { +Ast *ast_union_type(AstFile *f, Token token, Array variants, Ast *polymorphic_params, Ast *align, bool no_nil, + Token where_token, Array const &where_clauses) { Ast *result = alloc_ast_node(f, Ast_UnionType); result->UnionType.token = token; result->UnionType.variants = variants; result->UnionType.polymorphic_params = polymorphic_params; result->UnionType.align = align; result->UnionType.no_nil = no_nil; + result->UnionType.where_token = where_token; + result->UnionType.where_clauses = where_clauses; return result; } @@ -2020,6 +2028,18 @@ Ast *parse_operand(AstFile *f, bool lhs) { syntax_error(token, "'#raw_union' cannot also be '#packed'"); } + Token where_token = {}; + Array where_clauses = {}; + + if (f->curr_token.kind == Token_where) { + where_token = expect_token(f, Token_where); + isize prev_level = f->expr_level; + f->expr_level = -1; + where_clauses = parse_rhs_expr_list(f); + f->expr_level = prev_level; + } + + Token open = expect_token_after(f, Token_OpenBrace, "struct"); isize name_count = 0; @@ -2032,7 +2052,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { decls = fields->FieldList.list; } - return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, align); + return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, align, where_token, where_clauses); } break; case Token_union: { @@ -2073,6 +2093,18 @@ Ast *parse_operand(AstFile *f, bool lhs) { } } + Token where_token = {}; + Array where_clauses = {}; + + if (f->curr_token.kind == Token_where) { + where_token = expect_token(f, Token_where); + isize prev_level = f->expr_level; + f->expr_level = -1; + where_clauses = parse_rhs_expr_list(f); + f->expr_level = prev_level; + } + + Token open = expect_token_after(f, Token_OpenBrace, "union"); while (f->curr_token.kind != Token_CloseBrace && @@ -2088,7 +2120,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { Token close = expect_token(f, Token_CloseBrace); - return ast_union_type(f, token, variants, polymorphic_params, align, no_nil); + return ast_union_type(f, token, variants, polymorphic_params, align, no_nil, where_token, where_clauses); } break; case Token_enum: { @@ -4424,19 +4456,6 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir, } - if (is_package_name_reserved(file_str)) { - *path = file_str; - return true; - } - - if (file_mutex) gb_mutex_lock(file_mutex); - defer (if (file_mutex) gb_mutex_unlock(file_mutex)); - - - if (node->kind == Ast_ForeignImportDecl) { - node->ForeignImportDecl.collection_name = collection_name; - } - if (collection_name.len > 0) { if (collection_name == "system") { if (node->kind != Ast_ForeignImportDecl) { @@ -4467,6 +4486,20 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir, #endif } + + if (is_package_name_reserved(file_str)) { + *path = file_str; + return true; + } + + if (file_mutex) gb_mutex_lock(file_mutex); + defer (if (file_mutex) gb_mutex_unlock(file_mutex)); + + + if (node->kind == Ast_ForeignImportDecl) { + node->ForeignImportDecl.collection_name = collection_name; + } + if (has_windows_drive) { *path = file_str; } else { diff --git a/src/parser.hpp b/src/parser.hpp index 3da2551f1..419cf9da3 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -491,20 +491,24 @@ AST_KIND(_TypeBegin, "", bool) \ Ast *elem; \ }) \ AST_KIND(StructType, "struct type", struct { \ - Token token; \ - Array fields; \ - isize field_count; \ - Ast *polymorphic_params; \ - Ast *align; \ - bool is_packed; \ - bool is_raw_union; \ + Token token; \ + Array fields; \ + isize field_count; \ + Ast *polymorphic_params; \ + Ast *align; \ + Token where_token; \ + Array where_clauses; \ + bool is_packed; \ + bool is_raw_union; \ }) \ AST_KIND(UnionType, "union type", struct { \ - Token token; \ - Array variants; \ - Ast *polymorphic_params; \ - Ast * align; \ - bool no_nil; \ + Token token; \ + Array variants; \ + Ast *polymorphic_params; \ + Ast * align; \ + bool no_nil; \ + Token where_token; \ + Array where_clauses; \ }) \ AST_KIND(EnumType, "enum type", struct { \ Token token; \ From c7cc38b7d8894578e7158e8e092531c7ec71f815 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 8 Sep 2019 15:47:57 +0100 Subject: [PATCH 071/143] Remove assert --- src/check_type.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index e1602365a..fe9e6f817 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -441,8 +441,6 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< if (poly_operands != nullptr) { Operand operand = (*poly_operands)[entities.count]; if (is_type_param) { - GB_ASSERT(operand.mode == Addressing_Type || - operand.mode == Addressing_Invalid); if (is_type_polymorphic(base_type(operand.type))) { is_polymorphic = true; can_check_fields = false; From 42bbd31df143d49340f289326f949ad524a3a70e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 8 Sep 2019 19:03:57 +0100 Subject: [PATCH 072/143] Disallow `where` clauses on non-polymorphic records --- src/check_type.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index fe9e6f817..f2d42cfe1 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -503,7 +503,11 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< struct_type->Struct.is_poly_specialized = is_poly_specialized; if (!is_polymorphic) { - bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &st->where_clauses, true); + if (st->where_clauses.count > 0 && st->polymorphic_params != nullptr) { + error(st->where_clauses[0], "'where' clauses can only be used on structures with polymorphic parameters"); + } else { + bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &st->where_clauses, true); + } check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context); } @@ -686,7 +690,11 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, ArrayUnion.is_polymorphic = is_polymorphic; union_type->Union.is_poly_specialized = is_poly_specialized; - bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &ut->where_clauses, true); + if (ut->where_clauses.count > 0 && ut->polymorphic_params != nullptr) { + error(ut->where_clauses[0], "'where' clauses can only be used on unions with polymorphic parameters"); + } else { + bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &ut->where_clauses, true); + } for_array(i, ut->variants) { From 5fc42bf9c9e040be09a6dc976b357efb04a1efea Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 8 Sep 2019 19:15:12 +0100 Subject: [PATCH 073/143] Update demo.odin --- examples/demo/demo.odin | 18 ++++++++++++++++-- src/check_type.cpp | 4 ++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 92d1c17bd..9554eaa2e 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1095,7 +1095,7 @@ inline_for_statement :: proc() { } } -procedure_where_clauses :: proc() { +where_clauses :: proc() { fmt.println("\n#procedure 'where' clauses"); { // Sanity checks @@ -1156,6 +1156,20 @@ procedure_where_clauses :: proc() { assert(ok_x == true); assert(ok_y == false); } + + { // Record types + Foo :: struct(T: typeid, N: int) + where intrinsics.type_is_integer(T), + N > 2 { + x: [N]T, + y: [N-2]T, + } + + T :: i32; + N :: 5; + f: Foo(T, N); + #assert(size_of(f) == (N+N-2)*size_of(T)); + } } main :: proc() { @@ -1179,6 +1193,6 @@ main :: proc() { reflection(); quaternions(); inline_for_statement(); - procedure_where_clauses(); + where_clauses(); } } diff --git a/src/check_type.cpp b/src/check_type.cpp index f2d42cfe1..465c11731 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -503,7 +503,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< struct_type->Struct.is_poly_specialized = is_poly_specialized; if (!is_polymorphic) { - if (st->where_clauses.count > 0 && st->polymorphic_params != nullptr) { + if (st->where_clauses.count > 0 && st->polymorphic_params == nullptr) { error(st->where_clauses[0], "'where' clauses can only be used on structures with polymorphic parameters"); } else { bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &st->where_clauses, true); @@ -690,7 +690,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, ArrayUnion.is_polymorphic = is_polymorphic; union_type->Union.is_poly_specialized = is_poly_specialized; - if (ut->where_clauses.count > 0 && ut->polymorphic_params != nullptr) { + if (ut->where_clauses.count > 0 && ut->polymorphic_params == nullptr) { error(ut->where_clauses[0], "'where' clauses can only be used on unions with polymorphic parameters"); } else { bool where_clause_ok = evaluate_where_clauses(ctx, ctx->scope, &ut->where_clauses, true); From 68582c5ad1b2bf562242b9d2f40c89efad343b66 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 17 Sep 2019 19:47:04 +0100 Subject: [PATCH 074/143] Add suggestions to errors on casts and assignments. --- src/check_decl.cpp | 3 +- src/check_expr.cpp | 93 ++++++++++++++++++++++++++++++++++++++++------ src/check_stmt.cpp | 3 +- 3 files changed, 85 insertions(+), 14 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 173ba4a90..166b6e715 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -112,7 +112,8 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Ar isize rhs_count = operands.count; for_array(i, operands) { if (operands[i].mode == Addressing_Invalid) { - rhs_count--; + // TODO(bill): Should I ignore invalid parameters? + // rhs_count--; } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8a5ed9c1c..5ef42a3fc 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -90,7 +90,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCallingConvention cc); bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type *abi_return_type); void set_procedure_abi_types(CheckerContext *c, Type *type); - +void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type); Entity *entity_from_expr(Ast *expr) { expr = unparen_expr(expr); @@ -786,6 +786,7 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co op_type_str, type_str, LIT(context_name)); + check_assignment_error_suggestion(c, operand, type); break; } operand->mode = Addressing_Invalid; @@ -1509,32 +1510,98 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ return false; } + +void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type) { + gbString a = expr_to_string(o->expr); + gbString b = type_to_string(type); + defer( + gb_string_free(b); + gb_string_free(a); + ); + + Type *src = base_type(o->type); + Type *dst = base_type(type); + + if (is_type_array(src) && is_type_slice(dst)) { + Type *s = src->Array.elem; + Type *d = dst->Slice.elem; + if (are_types_identical(s, d)) { + error_line("\tSuggestion: the array expression may be sliced with %s[:]\n", a); + } + } else if (are_types_identical(src, dst)) { + error_line("\tSuggestion: the expression may be directly casted to type %s\n", b); + } else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) { + error_line("\tSuggestion: a string may be casted to %s\n", a, b); + } else if (is_type_u8_slice(src) && are_types_identical(dst, t_string)) { + error_line("\tSuggestion: the expression may be casted to %s\n", b); + } +} + +void check_cast_error_suggestion(CheckerContext *c, Operand *o, Type *type) { + gbString a = expr_to_string(o->expr); + gbString b = type_to_string(type); + defer( + gb_string_free(b); + gb_string_free(a); + ); + + Type *src = base_type(o->type); + Type *dst = base_type(type); + + if (is_type_array(src) && is_type_slice(dst)) { + Type *s = src->Array.elem; + Type *d = dst->Slice.elem; + if (are_types_identical(s, d)) { + error_line("\tSuggestion: the array expression may be sliced with %s[:]\n", a); + } + } else if (is_type_pointer(o->type) && is_type_integer(type)) { + if (is_type_uintptr(type)) { + error_line("\tSuggestion: a pointer may be directly casted to %s\n", b); + } else { + error_line("\tSuggestion: for a pointer to be casted to an integer, it must be converted to 'uintptr' first\n"); + i64 x = type_size_of(o->type); + i64 y = type_size_of(type); + if (x != y) { + error_line("\tNote: the type of expression and the type of the cast have a different size in bytes, %lld vs %lld\n", x, y); + } + } + } else if (is_type_integer(o->type) && is_type_pointer(type)) { + if (is_type_uintptr(o->type)) { + error_line("\tSuggestion: %a may be directly casted to %s\n", a, b); + } else { + error_line("\tSuggestion: for an integer to be casted to a pointer, it must be converted to 'uintptr' first\n"); + } + } else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) { + error_line("\tSuggestion: a string may be casted to %s\n", a, b); + } else if (is_type_u8_slice(src) && are_types_identical(dst, t_string)) { + error_line("\tSuggestion: the expression may be casted to %s\n", b); + } +} + + void check_is_expressible(CheckerContext *c, Operand *o, Type *type) { GB_ASSERT(is_type_constant_type(type)); GB_ASSERT(o->mode == Addressing_Constant); if (!check_representable_as_constant(c, o->value, type, &o->value)) { gbString a = expr_to_string(o->expr); gbString b = type_to_string(type); + defer( + gb_string_free(b); + gb_string_free(a); + o->mode = Addressing_Invalid; + ); + if (is_type_numeric(o->type) && is_type_numeric(type)) { if (!is_type_integer(o->type) && is_type_integer(type)) { error(o->expr, "'%s' truncated to '%s'", a, b); } else { - #if 0 - gbAllocator ha = heap_allocator(); - String str = big_int_to_string(ha, &o->value.value_integer); - defer (gb_free(ha, str.text)); - error(o->expr, "'%s = %.*s' overflows '%s'", a, LIT(str), b); - #else error(o->expr, "Cannot convert '%s' to '%s'", a, b); - #endif + check_assignment_error_suggestion(c, o, type); } } else { error(o->expr, "Cannot convert '%s' to '%s'", a, b); + check_assignment_error_suggestion(c, o, type); } - - gb_string_free(b); - gb_string_free(a); - o->mode = Addressing_Invalid; } } @@ -2165,6 +2232,8 @@ void check_cast(CheckerContext *c, Operand *x, Type *type) { gb_string_free(to_type); gb_string_free(expr_str); + check_cast_error_suggestion(c, x, type); + x->mode = Addressing_Invalid; return; } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 6945fb00e..9163fadc2 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1366,7 +1366,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { isize rhs_count = rhs_operands.count; for_array(i, rhs_operands) { if (rhs_operands[i].mode == Addressing_Invalid) { - rhs_count--; + // TODO(bill): Should I ignore invalid parameters? + // rhs_count--; } } From 1e53a6fa9635988a55071f0f05c6b29bd9320414 Mon Sep 17 00:00:00 2001 From: nakst Date: Wed, 18 Sep 2019 16:19:19 +0100 Subject: [PATCH 075/143] updated os_essence.odin --- core/os/os_essence.odin | 2936 +++++++++++++++++++++++++++------------ 1 file changed, 2013 insertions(+), 923 deletions(-) diff --git a/core/os/os_essence.odin b/core/os/os_essence.odin index e087a3de3..d11c0503b 100644 --- a/core/os/os_essence.odin +++ b/core/os/os_essence.odin @@ -1,646 +1,1721 @@ package os; -EsData :: struct { _private : [4]rawptr, } -EsGeneric :: rawptr; -EsElement :: struct { _private : u8, }; -EsObject :: rawptr; -EsLongDouble :: struct { value : [10]u8, }; -EsNodeType :: u64; -EsError :: int; -EsHandle :: uint; -EsResponse :: i32; -EsFileOffset :: u64; -EsListViewIndex :: i32; -EsThreadEntryFunction :: distinct #type proc (EsGeneric); -EsComparisonCallbackFunction :: distinct #type proc (rawptr, rawptr, EsGeneric) -> i32; -EsSwapCallbackFunction :: distinct #type proc (rawptr, rawptr, EsGeneric); -EsCRTComparisonCallback :: distinct #type proc (rawptr, rawptr) -> i32; -EsMessageCallbackFunction :: distinct #type proc (EsObject, ^EsMessage, ^EsResponse); -EsUICallbackFunction :: distinct #type proc (^EsElement, ^EsMessage, ^EsResponse); -ES_SCANCODE_A :: (0x1C); -ES_SCANCODE_B :: (0x32); -ES_SCANCODE_C :: (0x21); -ES_SCANCODE_D :: (0x23); -ES_SCANCODE_E :: (0x24); -ES_SCANCODE_F :: (0x2B); -ES_SCANCODE_G :: (0x34); -ES_SCANCODE_H :: (0x33); -ES_SCANCODE_I :: (0x43); -ES_SCANCODE_J :: (0x3B); -ES_SCANCODE_K :: (0x42); -ES_SCANCODE_L :: (0x4B); -ES_SCANCODE_M :: (0x3A); -ES_SCANCODE_N :: (0x31); -ES_SCANCODE_O :: (0x44); -ES_SCANCODE_P :: (0x4D); -ES_SCANCODE_Q :: (0x15); -ES_SCANCODE_R :: (0x2D); -ES_SCANCODE_S :: (0x1B); -ES_SCANCODE_T :: (0x2C); -ES_SCANCODE_U :: (0x3C); -ES_SCANCODE_V :: (0x2A); -ES_SCANCODE_W :: (0x1D); -ES_SCANCODE_X :: (0x22); -ES_SCANCODE_Y :: (0x35); -ES_SCANCODE_Z :: (0x1A); -ES_SCANCODE_0 :: (0x45); -ES_SCANCODE_1 :: (0x16); -ES_SCANCODE_2 :: (0x1E); -ES_SCANCODE_3 :: (0x26); -ES_SCANCODE_4 :: (0x25); -ES_SCANCODE_5 :: (0x2E); -ES_SCANCODE_6 :: (0x36); -ES_SCANCODE_7 :: (0x3D); -ES_SCANCODE_8 :: (0x3E); -ES_SCANCODE_9 :: (0x46); -ES_SCANCODE_CAPS_LOCK :: (0x58); -ES_SCANCODE_SCROLL_LOCK :: (0x7E); -ES_SCANCODE_NUM_LOCK :: (0x77) ; -ES_SCANCODE_LEFT_SHIFT :: (0x12); -ES_SCANCODE_LEFT_CTRL :: (0x14); -ES_SCANCODE_LEFT_ALT :: (0x11); -ES_SCANCODE_LEFT_FLAG :: (0x11F); -ES_SCANCODE_RIGHT_SHIFT :: (0x59); -ES_SCANCODE_RIGHT_CTRL :: (0x114); -ES_SCANCODE_RIGHT_ALT :: (0x111); -ES_SCANCODE_PAUSE :: (0xE1); -ES_SCANCODE_CONTEXT_MENU :: (0x127); -ES_SCANCODE_BACKSPACE :: (0x66); -ES_SCANCODE_ESCAPE :: (0x76); -ES_SCANCODE_INSERT :: (0x170); -ES_SCANCODE_HOME :: (0x16C); -ES_SCANCODE_PAGE_UP :: (0x17D); -ES_SCANCODE_DELETE :: (0x171); -ES_SCANCODE_END :: (0x169); -ES_SCANCODE_PAGE_DOWN :: (0x17A); -ES_SCANCODE_UP_ARROW :: (0x175); -ES_SCANCODE_LEFT_ARROW :: (0x16B); -ES_SCANCODE_DOWN_ARROW :: (0x172); -ES_SCANCODE_RIGHT_ARROW :: (0x174); -ES_SCANCODE_SPACE :: (0x29); -ES_SCANCODE_TAB :: (0x0D); -ES_SCANCODE_ENTER :: (0x5A); -ES_SCANCODE_SLASH :: (0x4A); -ES_SCANCODE_BACKSLASH :: (0x5D); -ES_SCANCODE_LEFT_BRACE :: (0x54); -ES_SCANCODE_RIGHT_BRACE :: (0x5B); -ES_SCANCODE_EQUALS :: (0x55); -ES_SCANCODE_BACKTICK :: (0x0E); -ES_SCANCODE_HYPHEN :: (0x4E); -ES_SCANCODE_SEMICOLON :: (0x4C); -ES_SCANCODE_QUOTE :: (0x52); -ES_SCANCODE_COMMA :: (0x41); -ES_SCANCODE_PERIOD :: (0x49); -ES_SCANCODE_NUM_DIVIDE :: (0x14A); -ES_SCANCODE_NUM_MULTIPLY :: (0x7C); -ES_SCANCODE_NUM_SUBTRACT :: (0x7B); -ES_SCANCODE_NUM_ADD :: (0x79); -ES_SCANCODE_NUM_ENTER :: (0x15A); -ES_SCANCODE_NUM_POINT :: (0x71); -ES_SCANCODE_NUM_0 :: (0x70); -ES_SCANCODE_NUM_1 :: (0x69); -ES_SCANCODE_NUM_2 :: (0x72); -ES_SCANCODE_NUM_3 :: (0x7A); -ES_SCANCODE_NUM_4 :: (0x6B); -ES_SCANCODE_NUM_5 :: (0x73); -ES_SCANCODE_NUM_6 :: (0x74); -ES_SCANCODE_NUM_7 :: (0x6C); -ES_SCANCODE_NUM_8 :: (0x75); -ES_SCANCODE_NUM_9 :: (0x7D); -ES_SCANCODE_PRINT_SCREEN_1 :: (0x112) ; -ES_SCANCODE_PRINT_SCREEN_2 :: (0x17C); -ES_SCANCODE_F1 :: (0x05); -ES_SCANCODE_F2 :: (0x06); -ES_SCANCODE_F3 :: (0x04); -ES_SCANCODE_F4 :: (0x0C); -ES_SCANCODE_F5 :: (0x03); -ES_SCANCODE_F6 :: (0x0B); -ES_SCANCODE_F7 :: (0x83); -ES_SCANCODE_F8 :: (0x0A); -ES_SCANCODE_F9 :: (0x01); -ES_SCANCODE_F10 :: (0x09); -ES_SCANCODE_F11 :: (0x78); -ES_SCANCODE_F12 :: (0x07); -ES_SCANCODE_ACPI_POWER :: (0x137); -ES_SCANCODE_ACPI_SLEEP :: (0x13F); -ES_SCANCODE_ACPI_WAKE :: (0x15E); -ES_SCANCODE_MM_NEXT :: (0x14D); -ES_SCANCODE_MM_PREVIOUS :: (0x115); -ES_SCANCODE_MM_STOP :: (0x13B); -ES_SCANCODE_MM_PAUSE :: (0x134); -ES_SCANCODE_MM_MUTE :: (0x123); -ES_SCANCODE_MM_QUIETER :: (0x121); -ES_SCANCODE_MM_LOUDER :: (0x132); -ES_SCANCODE_MM_SELECT :: (0x150); -ES_SCANCODE_MM_EMAIL :: (0x148); -ES_SCANCODE_MM_CALC :: (0x12B); -ES_SCANCODE_MM_FILES :: (0x140); -ES_SCANCODE_WWW_SEARCH :: (0x110); -ES_SCANCODE_WWW_HOME :: (0x13A); -ES_SCANCODE_WWW_BACK :: (0x138); -ES_SCANCODE_WWW_FORWARD :: (0x130); -ES_SCANCODE_WWW_STOP :: (0x128); -ES_SCANCODE_WWW_REFRESH :: (0x120); -ES_SCANCODE_WWW_STARRED :: (0x118); -ES_PROCESS_STATE_ALL_THREADS_TERMINATED :: (1); -ES_PROCESS_STATE_TERMINATING :: (2); -ES_PROCESS_STATE_CRASHED :: (4); -ES_FLAGS_DEFAULT :: (0); -ES_SUCCESS :: (-1); -ES_ERROR_BUFFER_TOO_SMALL :: (-2); -ES_ERROR_UNKNOWN_OPERATION_FAILURE :: (-7); -ES_ERROR_NO_MESSAGES_AVAILABLE :: (-9); -ES_ERROR_MESSAGE_QUEUE_FULL :: (-10); -ES_ERROR_MESSAGE_NOT_HANDLED_BY_GUI :: (-13); -ES_ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME :: (-14); -ES_ERROR_PATH_NOT_TRAVERSABLE :: (-15); -ES_ERROR_FILE_ALREADY_EXISTS :: (-19); -ES_ERROR_FILE_DOES_NOT_EXIST :: (-20); -ES_ERROR_DRIVE_ERROR_FILE_DAMAGED :: (-21) ; -ES_ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS :: (-22) ; -ES_ERROR_FILE_PERMISSION_NOT_GRANTED :: (-23); -ES_ERROR_FILE_IN_EXCLUSIVE_USE :: (-24); -ES_ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE :: (-25); -ES_ERROR_INCORRECT_NODE_TYPE :: (-26); -ES_ERROR_EVENT_NOT_SET :: (-27); -ES_ERROR_TIMEOUT_REACHED :: (-29); -ES_ERROR_REQUEST_CLOSED_BEFORE_COMPLETE :: (-30); -ES_ERROR_NO_CHARACTER_AT_COORDINATE :: (-31); -ES_ERROR_FILE_ON_READ_ONLY_VOLUME :: (-32); -ES_ERROR_USER_CANCELED_IO :: (-33); -ES_ERROR_INVALID_DIMENSIONS :: (-34); -ES_ERROR_DRIVE_CONTROLLER_REPORTED :: (-35); -ES_ERROR_COULD_NOT_ISSUE_PACKET :: (-36); -ES_ERROR_HANDLE_TABLE_FULL :: (-37); -ES_ERROR_COULD_NOT_RESIZE_FILE :: (-38); -ES_ERROR_DIRECTORY_NOT_EMPTY :: (-39); -ES_ERROR_UNSUPPORTED_FILESYSTEM :: (-40); -ES_ERROR_NODE_ALREADY_DELETED :: (-41); -ES_ERROR_NODE_IS_ROOT :: (-42); -ES_ERROR_VOLUME_MISMATCH :: (-43); -ES_ERROR_TARGET_WITHIN_SOURCE :: (-44); -ES_ERROR_TARGET_INVALID_TYPE :: (-45); -ES_ERROR_NOTHING_TO_DRAW :: (-46); -ES_ERROR_MALFORMED_NODE_PATH :: (-47); -ES_ERROR_OUT_OF_CACHE_RESOURCES :: (-48); -ES_ERROR_TARGET_IS_SOURCE :: (-49); -ES_ERROR_INVALID_NAME :: (-50); -ES_ERROR_CORRUPT_DATA :: (-51); -ES_ERROR_INSUFFICIENT_RESOURCES :: (-52); -ES_ERROR_UNSUPPORTED_FEATURE :: (-53); -ES_ERROR_FILE_TOO_FRAGMENTED :: (-54); -ES_ERROR_DRIVE_FULL :: (-55); -ES_ERROR_COULD_NOT_RESOLVE_SYMBOL :: (-56); -ES_ERROR_ALREADY_EMBEDDED :: (-57); -ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND :: (0); -ES_SYSTEM_CONSTANT_NO_FANCY_GRAPHICS :: (2); -ES_SYSTEM_CONSTANT_REPORTED_PROBLEMS :: (3); -ES_INVALID_HANDLE :: ((EsHandle) (0)); -ES_CURRENT_THREAD :: ((EsHandle) (0x10)); -ES_CURRENT_PROCESS :: ((EsHandle) (0x11)); -ES_SURFACE_UI_SHEET :: ((EsHandle) (0x20)); -ES_SURFACE_WALLPAPER :: ((EsHandle) (0x21)); -ES_DRAW_ALPHA_OVERWRITE :: (0x100); -ES_DRAW_ALPHA_FULL :: (0x200) ; -ES_WAIT_NO_TIMEOUT :: (-1); -ES_MAX_WAIT_COUNT :: (16); -ES_MAX_DIRECTORY_CHILD_NAME_LENGTH :: (256); -ES_PROCESS_EXECUTABLE_NOT_LOADED :: 0; -ES_PROCESS_EXECUTABLE_FAILED_TO_LOAD :: 1; -ES_PROCESS_EXECUTABLE_LOADED :: 2; -ES_SNAPSHOT_MAX_PROCESS_NAME_LENGTH :: (80); -ES_SYSTEM_SNAPSHOT_PROCESSES :: (1); -ES_SYSTEM_SNAPSHOT_DRIVES :: (2); -ES_NOT_HANDLED :: (-1); -ES_HANDLED :: (0); -ES_REJECTED :: (-2); -ES_SHARED_MEMORY_MAXIMUM_SIZE :: ( (1024) * 1024 * 1024 * 1024); -ES_SHARED_MEMORY_NAME_MAX_LENGTH :: (32); -ES_MAP_OBJECT_ALL :: (0); -ES_DRAW_STRING_HALIGN_LEFT :: (1); -ES_DRAW_STRING_HALIGN_RIGHT :: (2); -ES_DRAW_STRING_HALIGN_CENTER :: (3); -ES_DRAW_STRING_VALIGN_TOP :: (4); -ES_DRAW_STRING_VALIGN_BOTTOM :: (8); -ES_DRAW_STRING_VALIGN_CENTER :: (12); -ES_DRAW_STRING_CLIP :: (0); -ES_DRAW_STRING_WORD_WRAP :: (16); -ES_DRAW_STRING_ELLIPSIS :: (32); -ES_NODE_READ_NONE :: (0x0); -ES_NODE_READ_BLOCK :: (0x1); -ES_NODE_READ_ACCESS :: (0x2); -ES_NODE_READ_EXCLUSIVE :: (0x3); -ES_NODE_WRITE_NONE :: (0x00); -ES_NODE_WRITE_BLOCK :: (0x10); -ES_NODE_WRITE_ACCESS :: (0x20); -ES_NODE_WRITE_EXCLUSIVE :: (0x30); -ES_NODE_RESIZE_NONE :: (0x000); -ES_NODE_RESIZE_BLOCK :: (0x100); -ES_NODE_RESIZE_ACCESS :: (0x200); -ES_NODE_RESIZE_EXCLUSIVE :: (0x300); -ES_NODE_FAIL_IF_FOUND :: (0x1000); -ES_NODE_FAIL_IF_NOT_FOUND :: (0x2000); -ES_NODE_CREATE_DIRECTORIES :: (0x8000) ; -ES_NODE_POSIX_NAMESPACE :: (0x10000) ; -ES_DIRECTORY_CHILDREN_UNKNOWN :: ( (-1)); -ES_MEMORY_OPEN_FAIL_IF_FOUND :: (0x1000); -ES_MEMORY_OPEN_FAIL_IF_NOT_FOUND :: (0x2000); -ES_MAP_OBJECT_READ_WRITE :: (0); -ES_MAP_OBJECT_READ_ONLY :: (1); -ES_MAP_OBJECT_COPY_ON_WRITE :: (2); -ES_BOX_STYLE_OUTWARDS :: (0x01) ; -ES_BOX_STYLE_INWARDS :: (0x02) ; -ES_BOX_STYLE_NEUTRAL :: (0x03) ; -ES_BOX_STYLE_FLAT :: (0x04) ; -ES_BOX_STYLE_NONE :: (0x05) ; -ES_BOX_STYLE_SELECTED :: (0x06) ; -ES_BOX_STYLE_PUSHED :: (0x07) ; -ES_BOX_STYLE_DOTTED :: (0x80); -ES_BOX_COLOR_GRAY :: (0xC0C0C0); -ES_BOX_COLOR_DARK_GRAY :: (0x808080); -ES_BOX_COLOR_WHITE :: (0xFFFFFF); -ES_BOX_COLOR_BLUE :: (0x000080); -ES_BOX_COLOR_TRANSPARENT :: (0xFF00FF); -ES_BOX_COLOR_BLACK :: (0x000000); -ES_STRING_FORMAT_ENOUGH_SPACE :: ( (-1)); -ES_POSIX_SYSCALL_GET_POSIX_FD_PATH :: (0x10000); -ES_SURFACE_FULL_ALPHA :: (1); -ES_PERMISSION_ACCESS_SYSTEM_FILES :: (1 << 0); -ES_PERMISSION_ACCESS_USER_FILES :: (1 << 1); -ES_PERMISSION_PROCESS_CREATE :: (1 << 2); -ES_PERMISSION_PROCESS_OPEN :: (1 << 3); -ES_PERMISSION_SCREEN_MODIFY :: (1 << 4) ; -ES_PERMISSION_SHUTDOWN :: (1 << 5); -ES_PERMISSION_TAKE_SYSTEM_SNAPSHOT :: (1 << 6); -ES_PERMISSION_WINDOW_OPEN :: (1 << 7); -ES_PERMISSION_ALL :: ( (-1)); -ES_PERMISSION_INHERIT :: ( (1 << 63)); -ES_PANEL_WRAP :: ( (0x0001) << 32); -ES_PANEL_H_LEFT :: ( (0x0010) << 32); -ES_PANEL_H_RIGHT :: ( (0x0020) << 32); -ES_PANEL_H_CENTER :: ( (0x0040) << 32); -ES_PANEL_H_JUSTIFY :: ( (0x0080) << 32); -ES_PANEL_V_TOP :: ( (0x0100) << 32); -ES_PANEL_V_BOTTOM :: ( (0x0200) << 32); -ES_PANEL_V_CENTER :: ( (0x0400) << 32); -ES_PANEL_V_JUSTIFY :: ( (0x0800) << 32); -ES_PANEL_H_SCROLL :: ( (0x1000) << 32); -ES_PANEL_V_SCROLL :: ( (0x2000) << 32); -ES_CELL_H_PUSH :: ( (0x0001) << 16); -ES_CELL_H_EXPAND :: ( (0x0002) << 16); -ES_CELL_H_LEFT :: ( (0x0004) << 16); -ES_CELL_H_RIGHT :: ( (0x0008) << 16); -ES_CELL_H_SHRINK :: ( (0x0010) << 16); -ES_CELL_V_PUSH :: ( (0x0100) << 16); -ES_CELL_V_EXPAND :: ( (0x0200) << 16); -ES_CELL_V_TOP :: ( (0x0400) << 16); -ES_CELL_V_BOTTOM :: ( (0x0800) << 16); -ES_CELL_V_SHRINK :: ( (0x1000) << 16); -ES_CELL_NEW_BAND :: ( (0x8000) << 16); -ES_CELL_HIDDEN :: ( (0xFFFF) << 16); -ES_ELEMENT_DO_NOT_FREE_STYLE_OVERRIDE :: (1 << 0); -ES_ELEMENT_RICH_TEXT :: (1 << 1); -ES_ELEMENT_FOCUSABLE :: (1 << 2); -ES_ELEMENT_Z_STACK :: (1 << 3) ; -ES_ELEMENT_HIDDEN :: (1 << 4); -ES_ELEMENT_USE_CHILD_AS_PARENT :: (1 << 5) ; -ES_TEXTBOX_MULTILINE :: (1 << 0); -ES_TEXTBOX_BORDERED :: (1 << 1); -ES_BUTTON_DEFAULT :: ( (1) << 32); -ES_BUTTON_DANGEROUS :: ( (1) << 33); -ES_SCROLLBAR_VERTICAL :: ( (0) << 32); -ES_SCROLLBAR_HORIZONTAL :: ( (1) << 32); -ES_LIST_VIEW_INDEX_GROUP_HEADER :: (-1); -ES_LIST_VIEW_ITEM_CONTENT_TEXT :: (1 << 0); -ES_LIST_VIEW_ITEM_CONTENT_ICON :: (1 << 1); -ES_LIST_VIEW_ITEM_CONTENT_INDENTATION :: (1 << 2); -ES_LIST_VIEW_ITEM_STATE_SELECTED :: (1 << 0); -ES_LIST_VIEW_ITEM_STATE_CHECKED :: (1 << 1); -ES_LIST_VIEW_ITEM_STATE_HIDDEN :: (1 << 2); -ES_LIST_VIEW_ITEM_STATE_EXPANDABLE :: (1 << 3); -ES_LIST_VIEW_ITEM_STATE_CHECKABLE :: (1 << 4); -ES_LIST_VIEW_ITEM_STATE_DROP_TARGET :: (1 << 5); -ES_LIST_VIEW_ITEM_STATE_COLLAPSABLE :: (1 << 6); -ES_LIST_VIEW_ITEM_STATE_PARTIAL_CHECK :: (1 << 7); -ES_LIST_VIEW_ITEM_STATE_DRAG_SOURCE :: (1 << 8); -ES_LIST_VIEW_ITEM_STATE_CUT :: (1 << 9); -ES_LIST_VIEW_FIND_ITEM_FROM_Y_POSITION :: (0); -ES_LIST_VIEW_FIND_ITEM_FROM_TEXT_PREFIX :: (1); -ES_LIST_VIEW_FIND_ITEM_NON_HIDDEN :: (2); -ES_LIST_VIEW_FIND_ITEM_PARENT :: (3); -ES_LIST_VIEW_COLUMN_DEFAULT_WIDTH_PRIMARY :: (300); -ES_LIST_VIEW_COLUMN_DEFAULT_WIDTH_SECONDARY :: (150); -ES_LIST_VIEW_COLUMN_PRIMARY :: (1); -ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED :: (2); -ES_LIST_VIEW_COLUMN_SORT_ASCENDING :: (8); -ES_LIST_VIEW_COLUMN_SORT_DESCENDING :: (16); -ES_LIST_VIEW_COLUMN_SORTABLE :: (32); -ES_LIST_VIEW_SINGLE_SELECT :: (1 << 0) ; -ES_LIST_VIEW_MULTI_SELECT :: (1 << 1) ; -ES_LIST_VIEW_HAS_COLUMNS :: (1 << 2) ; -ES_LIST_VIEW_HAS_GROUPS :: (1 << 3) ; -ES_LIST_VIEW_FIXED_HEIGHT :: (1 << 4) ; -ES_LIST_VIEW_VARIABLE_HEIGHT :: (1 << 5) ; -ES_LIST_VIEW_TREE :: (1 << 6) ; -ES_LIST_VIEW_TILED :: (1 << 7) ; -ES_LIST_VIEW_ALT_BACKGROUND :: (1 << 8) ; -ES_LIST_VIEW_BORDERED :: (1 << 9) ; -ES_LIST_VIEW_NO_BACKGROUND :: (1 << 10) ; -ES_LIST_VIEW_DROP_TARGET_ORDERED :: (1 << 11) ; -ES_LIST_VIEW_DROP_TARGET_UNORDERED :: (1 << 12) ; -ES_LIST_VIEW_ROW_DIVIDERS :: (1 << 13) ; -ES_LIST_VIEW_STATIC_GROUP_HEADERS :: (1 << 14) ; -ES_LIST_VIEW_COLLAPSABLE_GROUPS :: (1 << 15) ; -ES_LIST_VIEW_INTERNAL_SELECTION_STORAGE :: (1 << 16) ; -ES_LIST_VIEW_HAND_CURSOR :: (1 << 17) ; -ES_LIST_VIEW_NO_ITEM_BACKGROUNDS :: (1 << 18) ; -ES_LIST_VIEW_RICH_TEXT :: (1 << 20) ; -ES_LIST_VIEW_LABELS_BELOW :: (1 << 21) ; -ES_LIST_VIEW_MAXIMUM_ITEMS :: (10 * 1000 * 1000); -ES_LIST_VIEW_MAXIMUM_GROUPS :: (10 * 1000); -ES_LIST_VIEW_TRANSITION_BACKWARDS :: (1); -ES_LIST_VIEW_TRANSITION_DRAW_NEW_CONTENTS_ONCE :: (2) ; -EsFatalError :: enum { - ES_FATAL_ERROR_INVALID_BUFFER, - ES_FATAL_ERROR_UNKNOWN_SYSCALL, - ES_FATAL_ERROR_INVALID_MEMORY_REGION, - ES_FATAL_ERROR_MEMORY_REGION_LOCKED_BY_KERNEL, - ES_FATAL_ERROR_PATH_LENGTH_EXCEEDS_LIMIT, - ES_FATAL_ERROR_INVALID_HANDLE, - ES_FATAL_ERROR_MUTEX_NOT_ACQUIRED_BY_THREAD, - ES_FATAL_ERROR_MUTEX_ALREADY_ACQUIRED, - ES_FATAL_ERROR_BUFFER_NOT_ACCESSIBLE, - ES_FATAL_ERROR_SHARED_MEMORY_REGION_TOO_LARGE, - ES_FATAL_ERROR_SHARED_MEMORY_STILL_MAPPED, - ES_FATAL_ERROR_COULD_NOT_LOAD_FONT, - ES_FATAL_ERROR_COULD_NOT_DRAW_FONT, - ES_FATAL_ERROR_COULD_NOT_ALLOCATE_MEMORY, - ES_FATAL_ERROR_INCORRECT_FILE_ACCESS, - ES_FATAL_ERROR_TOO_MANY_WAIT_OBJECTS, - ES_FATAL_ERROR_INCORRECT_NODE_TYPE, - ES_FATAL_ERROR_PROCESSOR_EXCEPTION, - ES_FATAL_ERROR_UNKNOWN, - ES_FATAL_ERROR_RECURSIVE_BATCH, - ES_FATAL_ERROR_CORRUPT_HEAP, - ES_FATAL_ERROR_CORRUPT_LINKED_LIST, - ES_FATAL_ERROR_INDEX_OUT_OF_BOUNDS, - ES_FATAL_ERROR_INVALID_STRING_LENGTH, - ES_FATAL_ERROR_SPINLOCK_NOT_ACQUIRED, - ES_FATAL_ERROR_UNKNOWN_SNAPSHOT_TYPE, - ES_FATAL_ERROR_PROCESS_ALREADY_ATTACHED, - ES_FATAL_ERROR_INTERNAL, - ES_FATAL_ERROR_INSUFFICIENT_PERMISSIONS, - ES_FATAL_ERROR_ABORT, - ES_FATAL_ERROR_COUNT, +Data :: struct { _private : [4]rawptr, } +Generic :: rawptr; +Element :: struct { _private : u8, }; +Object :: rawptr; +LongDouble :: struct { value : [10]u8, }; +NodeType :: u64; +Error :: int; +Handle :: uint; +Response :: i32; +FileOffset :: u64; +ListViewIndex :: i32; +ThreadEntryFunction :: distinct #type proc (Generic); +ComparisonCallbackFunction :: distinct #type proc (rawptr, rawptr, Generic) -> i32; +SwapCallbackFunction :: distinct #type proc (rawptr, rawptr, Generic); +CRTComparisonCallback :: distinct #type proc (rawptr, rawptr) -> i32; +MessageCallbackFunction :: distinct #type proc (Object, ^Message, ^Response); +UICallbackFunction :: distinct #type proc (^Element, ^Message, ^Response); +Window :: struct { using element : Element, }; +Panel :: struct { using element : Element, }; +Scrollbar :: struct { using element : Element, }; +Button :: struct { using element : Element, }; +Textbox :: struct { using element : Element, }; +ListView :: struct { using element : Element, }; +NumericEntry :: struct { using element : Element, }; +Menu :: struct { using element : Element, }; +MenuCallbackFunction :: distinct #type proc (^Element, Generic); +INSTANCE_TYPE :: Instance; +SCANCODE_A :: (0x1C); +SCANCODE_B :: (0x32); +SCANCODE_C :: (0x21); +SCANCODE_D :: (0x23); +SCANCODE_E :: (0x24); +SCANCODE_F :: (0x2B); +SCANCODE_G :: (0x34); +SCANCODE_H :: (0x33); +SCANCODE_I :: (0x43); +SCANCODE_J :: (0x3B); +SCANCODE_K :: (0x42); +SCANCODE_L :: (0x4B); +SCANCODE_M :: (0x3A); +SCANCODE_N :: (0x31); +SCANCODE_O :: (0x44); +SCANCODE_P :: (0x4D); +SCANCODE_Q :: (0x15); +SCANCODE_R :: (0x2D); +SCANCODE_S :: (0x1B); +SCANCODE_T :: (0x2C); +SCANCODE_U :: (0x3C); +SCANCODE_V :: (0x2A); +SCANCODE_W :: (0x1D); +SCANCODE_X :: (0x22); +SCANCODE_Y :: (0x35); +SCANCODE_Z :: (0x1A); +SCANCODE_0 :: (0x45); +SCANCODE_1 :: (0x16); +SCANCODE_2 :: (0x1E); +SCANCODE_3 :: (0x26); +SCANCODE_4 :: (0x25); +SCANCODE_5 :: (0x2E); +SCANCODE_6 :: (0x36); +SCANCODE_7 :: (0x3D); +SCANCODE_8 :: (0x3E); +SCANCODE_9 :: (0x46); +SCANCODE_CAPS_LOCK :: (0x58); +SCANCODE_SCROLL_LOCK :: (0x7E); +SCANCODE_NUM_LOCK :: (0x77) ; +SCANCODE_LEFT_SHIFT :: (0x12); +SCANCODE_LEFT_CTRL :: (0x14); +SCANCODE_LEFT_ALT :: (0x11); +SCANCODE_LEFT_FLAG :: (0x11F); +SCANCODE_RIGHT_SHIFT :: (0x59); +SCANCODE_RIGHT_CTRL :: (0x114); +SCANCODE_RIGHT_ALT :: (0x111); +SCANCODE_PAUSE :: (0xE1); +SCANCODE_CONTEXT_MENU :: (0x127); +SCANCODE_BACKSPACE :: (0x66); +SCANCODE_ESCAPE :: (0x76); +SCANCODE_INSERT :: (0x170); +SCANCODE_HOME :: (0x16C); +SCANCODE_PAGE_UP :: (0x17D); +SCANCODE_DELETE :: (0x171); +SCANCODE_END :: (0x169); +SCANCODE_PAGE_DOWN :: (0x17A); +SCANCODE_UP_ARROW :: (0x175); +SCANCODE_LEFT_ARROW :: (0x16B); +SCANCODE_DOWN_ARROW :: (0x172); +SCANCODE_RIGHT_ARROW :: (0x174); +SCANCODE_SPACE :: (0x29); +SCANCODE_TAB :: (0x0D); +SCANCODE_ENTER :: (0x5A); +SCANCODE_SLASH :: (0x4A); +SCANCODE_BACKSLASH :: (0x5D); +SCANCODE_LEFT_BRACE :: (0x54); +SCANCODE_RIGHT_BRACE :: (0x5B); +SCANCODE_EQUALS :: (0x55); +SCANCODE_BACKTICK :: (0x0E); +SCANCODE_HYPHEN :: (0x4E); +SCANCODE_SEMICOLON :: (0x4C); +SCANCODE_QUOTE :: (0x52); +SCANCODE_COMMA :: (0x41); +SCANCODE_PERIOD :: (0x49); +SCANCODE_NUM_DIVIDE :: (0x14A); +SCANCODE_NUM_MULTIPLY :: (0x7C); +SCANCODE_NUM_SUBTRACT :: (0x7B); +SCANCODE_NUM_ADD :: (0x79); +SCANCODE_NUM_ENTER :: (0x15A); +SCANCODE_NUM_POINT :: (0x71); +SCANCODE_NUM_0 :: (0x70); +SCANCODE_NUM_1 :: (0x69); +SCANCODE_NUM_2 :: (0x72); +SCANCODE_NUM_3 :: (0x7A); +SCANCODE_NUM_4 :: (0x6B); +SCANCODE_NUM_5 :: (0x73); +SCANCODE_NUM_6 :: (0x74); +SCANCODE_NUM_7 :: (0x6C); +SCANCODE_NUM_8 :: (0x75); +SCANCODE_NUM_9 :: (0x7D); +SCANCODE_PRINT_SCREEN_1 :: (0x112) ; +SCANCODE_PRINT_SCREEN_2 :: (0x17C); +SCANCODE_F1 :: (0x05); +SCANCODE_F2 :: (0x06); +SCANCODE_F3 :: (0x04); +SCANCODE_F4 :: (0x0C); +SCANCODE_F5 :: (0x03); +SCANCODE_F6 :: (0x0B); +SCANCODE_F7 :: (0x83); +SCANCODE_F8 :: (0x0A); +SCANCODE_F9 :: (0x01); +SCANCODE_F10 :: (0x09); +SCANCODE_F11 :: (0x78); +SCANCODE_F12 :: (0x07); +SCANCODE_ACPI_POWER :: (0x137); +SCANCODE_ACPI_SLEEP :: (0x13F); +SCANCODE_ACPI_WAKE :: (0x15E); +SCANCODE_MM_NEXT :: (0x14D); +SCANCODE_MM_PREVIOUS :: (0x115); +SCANCODE_MM_STOP :: (0x13B); +SCANCODE_MM_PAUSE :: (0x134); +SCANCODE_MM_MUTE :: (0x123); +SCANCODE_MM_QUIETER :: (0x121); +SCANCODE_MM_LOUDER :: (0x132); +SCANCODE_MM_SELECT :: (0x150); +SCANCODE_MM_EMAIL :: (0x148); +SCANCODE_MM_CALC :: (0x12B); +SCANCODE_MM_FILES :: (0x140); +SCANCODE_WWW_SEARCH :: (0x110); +SCANCODE_WWW_HOME :: (0x13A); +SCANCODE_WWW_BACK :: (0x138); +SCANCODE_WWW_FORWARD :: (0x130); +SCANCODE_WWW_STOP :: (0x128); +SCANCODE_WWW_REFRESH :: (0x120); +SCANCODE_WWW_STARRED :: (0x118); +PROCESS_STATE_ALL_THREADS_TERMINATED :: (1); +PROCESS_STATE_TERMINATING :: (2); +PROCESS_STATE_CRASHED :: (4); +FLAGS_DEFAULT :: (0); +SUCCESS :: (-1); +ERROR_BUFFER_TOO_SMALL :: (-2); +ERROR_UNKNOWN_OPERATION_FAILURE :: (-7); +ERROR_NO_MESSAGES_AVAILABLE :: (-9); +ERROR_MESSAGE_QUEUE_FULL :: (-10); +ERROR_MESSAGE_NOT_HANDLED_BY_GUI :: (-13); +ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME :: (-14); +ERROR_PATH_NOT_TRAVERSABLE :: (-15); +ERROR_FILE_ALREADY_EXISTS :: (-19); +ERROR_FILE_DOES_NOT_EXIST :: (-20); +ERROR_DRIVE_ERROR_FILE_DAMAGED :: (-21) ; +ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS :: (-22) ; +ERROR_FILE_PERMISSION_NOT_GRANTED :: (-23); +ERROR_FILE_IN_EXCLUSIVE_USE :: (-24); +ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE :: (-25); +ERROR_INCORRECT_NODE_TYPE :: (-26); +ERROR_EVENT_NOT_SET :: (-27); +ERROR_TIMEOUT_REACHED :: (-29); +ERROR_REQUEST_CLOSED_BEFORE_COMPLETE :: (-30); +ERROR_NO_CHARACTER_AT_COORDINATE :: (-31); +ERROR_FILE_ON_READ_ONLY_VOLUME :: (-32); +ERROR_USER_CANCELED_IO :: (-33); +ERROR_INVALID_DIMENSIONS :: (-34); +ERROR_DRIVE_CONTROLLER_REPORTED :: (-35); +ERROR_COULD_NOT_ISSUE_PACKET :: (-36); +ERROR_HANDLE_TABLE_FULL :: (-37); +ERROR_COULD_NOT_RESIZE_FILE :: (-38); +ERROR_DIRECTORY_NOT_EMPTY :: (-39); +ERROR_UNSUPPORTED_FILESYSTEM :: (-40); +ERROR_NODE_ALREADY_DELETED :: (-41); +ERROR_NODE_IS_ROOT :: (-42); +ERROR_VOLUME_MISMATCH :: (-43); +ERROR_TARGET_WITHIN_SOURCE :: (-44); +ERROR_TARGET_INVALID_TYPE :: (-45); +ERROR_NOTHING_TO_DRAW :: (-46); +ERROR_MALFORMED_NODE_PATH :: (-47); +ERROR_OUT_OF_CACHE_RESOURCES :: (-48); +ERROR_TARGET_IS_SOURCE :: (-49); +ERROR_INVALID_NAME :: (-50); +ERROR_CORRUPT_DATA :: (-51); +ERROR_INSUFFICIENT_RESOURCES :: (-52); +ERROR_UNSUPPORTED_FEATURE :: (-53); +ERROR_FILE_TOO_FRAGMENTED :: (-54); +ERROR_DRIVE_FULL :: (-55); +ERROR_COULD_NOT_RESOLVE_SYMBOL :: (-56); +ERROR_ALREADY_EMBEDDED :: (-57); +SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND :: (0); +SYSTEM_CONSTANT_NO_FANCY_GRAPHICS :: (2); +SYSTEM_CONSTANT_REPORTED_PROBLEMS :: (3); +SYSTEM_CONSTANT_RIGHT_TO_LEFT :: (4); +INVALID_HANDLE :: ((Handle) (0)); +CURRENT_THREAD :: ((Handle) (0x10)); +CURRENT_PROCESS :: ((Handle) (0x11)); +SURFACE_UI_SHEET :: ((Handle) (0x20)); +SURFACE_WALLPAPER :: ((Handle) (0x21)); +DRAW_ALPHA_OVERWRITE :: (0x100); +DRAW_ALPHA_FULL :: (0x200) ; +WAIT_NO_TIMEOUT :: (-1); +MAX_WAIT_COUNT :: (16); +MAX_DIRECTORY_CHILD_NAME_LENGTH :: (256); +PROCESS_EXECUTABLE_NOT_LOADED :: 0; +PROCESS_EXECUTABLE_FAILED_TO_LOAD :: 1; +PROCESS_EXECUTABLE_LOADED :: 2; +SNAPSHOT_MAX_PROCESS_NAME_LENGTH :: (80); +SYSTEM_SNAPSHOT_PROCESSES :: (1); +SYSTEM_SNAPSHOT_DRIVES :: (2); +NOT_HANDLED :: (-1); +HANDLED :: (0); +REJECTED :: (-2); +SHARED_MEMORY_MAXIMUM_SIZE :: ( (1024) * 1024 * 1024 * 1024); +SHARED_MEMORY_NAME_MAX_LENGTH :: (32); +MAP_OBJECT_ALL :: (0); +DRAW_STRING_HALIGN_LEFT :: (1); +DRAW_STRING_HALIGN_RIGHT :: (2); +DRAW_STRING_HALIGN_CENTER :: (3); +DRAW_STRING_VALIGN_TOP :: (4); +DRAW_STRING_VALIGN_BOTTOM :: (8); +DRAW_STRING_VALIGN_CENTER :: (12); +DRAW_STRING_CLIP :: (0); +DRAW_STRING_WORD_WRAP :: (16); +DRAW_STRING_ELLIPSIS :: (32); +NODE_READ_NONE :: (0x0); +NODE_READ_BLOCK :: (0x1); +NODE_READ_ACCESS :: (0x2); +NODE_READ_EXCLUSIVE :: (0x3); +NODE_WRITE_NONE :: (0x00); +NODE_WRITE_BLOCK :: (0x10); +NODE_WRITE_ACCESS :: (0x20); +NODE_WRITE_EXCLUSIVE :: (0x30); +NODE_RESIZE_NONE :: (0x000); +NODE_RESIZE_BLOCK :: (0x100); +NODE_RESIZE_ACCESS :: (0x200); +NODE_RESIZE_EXCLUSIVE :: (0x300); +NODE_FAIL_IF_FOUND :: (0x1000); +NODE_FAIL_IF_NOT_FOUND :: (0x2000); +NODE_CREATE_DIRECTORIES :: (0x8000) ; +NODE_POSIX_NAMESPACE :: (0x10000) ; +DIRECTORY_CHILDREN_UNKNOWN :: ( (-1)); +MEMORY_OPEN_FAIL_IF_FOUND :: (0x1000); +MEMORY_OPEN_FAIL_IF_NOT_FOUND :: (0x2000); +MAP_OBJECT_READ_WRITE :: (0); +MAP_OBJECT_READ_ONLY :: (1); +MAP_OBJECT_COPY_ON_WRITE :: (2); +BOX_STYLE_OUTWARDS :: (0x01) ; +BOX_STYLE_INWARDS :: (0x02) ; +BOX_STYLE_NEUTRAL :: (0x03) ; +BOX_STYLE_FLAT :: (0x04) ; +BOX_STYLE_NONE :: (0x05) ; +BOX_STYLE_SELECTED :: (0x06) ; +BOX_STYLE_PUSHED :: (0x07) ; +BOX_STYLE_DOTTED :: (0x80); +BOX_COLOR_GRAY :: (0xC0C0C0); +BOX_COLOR_DARK_GRAY :: (0x808080); +BOX_COLOR_WHITE :: (0xFFFFFF); +BOX_COLOR_BLUE :: (0x000080); +BOX_COLOR_TRANSPARENT :: (0xFF00FF); +BOX_COLOR_BLACK :: (0x000000); +STRING_FORMAT_ENOUGH_SPACE :: ( (-1)); +POSIX_SYSCALL_GET_POSIX_FD_PATH :: (0x10000); +PERMISSION_ACCESS_SYSTEM_FILES :: (1 << 0); +PERMISSION_ACCESS_USER_FILES :: (1 << 1); +PERMISSION_PROCESS_CREATE :: (1 << 2); +PERMISSION_PROCESS_OPEN :: (1 << 3); +PERMISSION_SCREEN_MODIFY :: (1 << 4) ; +PERMISSION_SHUTDOWN :: (1 << 5); +PERMISSION_TAKE_SYSTEM_SNAPSHOT :: (1 << 6); +PERMISSION_WINDOW_OPEN :: (1 << 7); +PERMISSION_ALL :: ( (-1)); +PERMISSION_INHERIT :: ( (1 << 63)); +PANEL_STYLE_DEFAULT :: "Panel.Default"; +PANEL_STYLE_MENU_COLUMN :: "Panel.Menu.Column"; +PANEL_WRAP :: ( (0x0001) << 32); +PANEL_H_LEFT :: ( (0x0010) << 32); +PANEL_H_RIGHT :: ( (0x0020) << 32); +PANEL_H_CENTER :: ( (0x0040) << 32); +PANEL_H_JUSTIFY :: ( (0x0080) << 32); +PANEL_V_TOP :: ( (0x0100) << 32); +PANEL_V_BOTTOM :: ( (0x0200) << 32); +PANEL_V_CENTER :: ( (0x0400) << 32); +PANEL_V_JUSTIFY :: ( (0x0800) << 32); +PANEL_H_SCROLL :: ( (0x1000) << 32); +PANEL_V_SCROLL :: ( (0x2000) << 32); +CELL_H_PUSH :: ( (0x0001) << 16); +CELL_H_EXPAND :: ( (0x0002) << 16); +CELL_H_LEFT :: ( (0x0004) << 16); +CELL_H_RIGHT :: ( (0x0008) << 16); +CELL_H_SHRINK :: ( (0x0010) << 16); +CELL_V_PUSH :: ( (0x0100) << 16); +CELL_V_EXPAND :: ( (0x0200) << 16); +CELL_V_TOP :: ( (0x0400) << 16); +CELL_V_BOTTOM :: ( (0x0800) << 16); +CELL_V_SHRINK :: ( (0x1000) << 16); +CELL_NEW_BAND :: ( (0x8000) << 16); +CELL_HIDDEN :: ( (0xFFFF) << 16); +ELEMENT_DO_NOT_FREE_STYLE_OVERRIDE :: (1 << 0); +ELEMENT_RICH_TEXT :: (1 << 1); +ELEMENT_FOCUSABLE :: (1 << 2); +ELEMENT_Z_STACK :: (1 << 3) ; +ELEMENT_HIDDEN :: (1 << 4); +ELEMENT_USE_CHILD_AS_PARENT :: (1 << 5) ; +ELEMENT_DISABLED :: (1 << 6); +ELEMENT_WINDOW_COORDS_FOR_MOUSE :: (1 << 7) ; +TEXTBOX_MULTILINE :: (1 << 0); +TEXTBOX_BORDERED :: (1 << 1); +BUTTON_DEFAULT :: ( (1) << 32); +BUTTON_DANGEROUS :: ( (1) << 33); +BUTTON_MENU_ITEM :: ( (1) << 34); +BUTTON_NOT_FOCUSABLE :: ( (1) << 35); +BUTTON_TOOLBAR :: ( (1) << 36); +SCROLLBAR_VERTICAL :: ( (0) << 32); +SCROLLBAR_HORIZONTAL :: ( (1) << 32); +LIST_VIEW_INDEX_GROUP_HEADER :: (-1); +LIST_VIEW_ITEM_CONTENT_TEXT :: (1 << 0); +LIST_VIEW_ITEM_CONTENT_ICON :: (1 << 1); +LIST_VIEW_ITEM_CONTENT_INDENTATION :: (1 << 2); +LIST_VIEW_ITEM_STATE_SELECTED :: (1 << 0); +LIST_VIEW_ITEM_STATE_CHECKED :: (1 << 1); +LIST_VIEW_ITEM_STATE_HIDDEN :: (1 << 2); +LIST_VIEW_ITEM_STATE_EXPANDABLE :: (1 << 3); +LIST_VIEW_ITEM_STATE_CHECKABLE :: (1 << 4); +LIST_VIEW_ITEM_STATE_DROP_TARGET :: (1 << 5); +LIST_VIEW_ITEM_STATE_COLLAPSABLE :: (1 << 6); +LIST_VIEW_ITEM_STATE_PARTIAL_CHECK :: (1 << 7); +LIST_VIEW_ITEM_STATE_DRAG_SOURCE :: (1 << 8); +LIST_VIEW_ITEM_STATE_CUT :: (1 << 9); +LIST_VIEW_FIND_ITEM_FROM_Y_POSITION :: (0); +LIST_VIEW_FIND_ITEM_FROM_TEXT_PREFIX :: (1); +LIST_VIEW_FIND_ITEM_NON_HIDDEN :: (2); +LIST_VIEW_FIND_ITEM_PARENT :: (3); +LIST_VIEW_COLUMN_DEFAULT_WIDTH_PRIMARY :: (270); +LIST_VIEW_COLUMN_DEFAULT_WIDTH_SECONDARY :: (130); +LIST_VIEW_COLUMN_PRIMARY :: (1); +LIST_VIEW_COLUMN_RIGHT_ALIGNED :: (2); +LIST_VIEW_COLUMN_SORT_ASCENDING :: (8); +LIST_VIEW_COLUMN_SORT_DESCENDING :: (16); +LIST_VIEW_COLUMN_SORTABLE :: (32); +LIST_VIEW_SINGLE_SELECT :: ( (1) << 32) ; +LIST_VIEW_MULTI_SELECT :: ( (1) << 33) ; +LIST_VIEW_HAS_COLUMNS :: ( (1) << 34) ; +LIST_VIEW_HAS_GROUPS :: ( (1) << 35) ; +LIST_VIEW_FIXED_HEIGHT :: ( (1) << 36) ; +LIST_VIEW_VARIABLE_HEIGHT :: ( (1) << 37) ; +LIST_VIEW_TREE :: ( (1) << 38) ; +LIST_VIEW_TILED :: ( (1) << 39) ; +LIST_VIEW_BORDERED :: ( (1) << 41) ; +LIST_VIEW_DROP_TARGET_ORDERED :: ( (1) << 43) ; +LIST_VIEW_DROP_TARGET_UNORDERED :: ( (1) << 44) ; +LIST_VIEW_ROW_DIVIDERS :: ( (1) << 45) ; +LIST_VIEW_STATIC_GROUP_HEADERS :: ( (1) << 46) ; +LIST_VIEW_COLLAPSABLE_GROUPS :: ( (1) << 47) ; +LIST_VIEW_INTERNAL_SELECTION_STORAGE :: ( (1) << 48) ; +LIST_VIEW_HAND_CURSOR :: ( (1) << 49) ; +LIST_VIEW_NO_ITEM_BACKGROUNDS :: ( (1) << 50) ; +LIST_VIEW_RICH_TEXT :: ( (1) << 52) ; +LIST_VIEW_LABELS_BELOW :: ( (1) << 53) ; +LIST_VIEW_MAXIMUM_ITEMS :: (10 * 1000 * 1000); +LIST_VIEW_MAXIMUM_GROUPS :: (10 * 1000); +LIST_VIEW_TRANSITION_BACKWARDS :: (1); +LIST_VIEW_TRANSITION_DRAW_NEW_CONTENTS_ONCE :: (2) ; +MENU_AT_CURSOR :: (1 << 0); +StandardIcon :: enum { + ICON_ACTION_UNAVAILABLE_SYMBOLIC, + ICON_ADDRESS_BOOK_NEW, + ICON_ADDRESS_BOOK_NEW_SYMBOLIC, + ICON_ALIGN_HORIZONTAL_CENTER, + ICON_ALIGN_HORIZONTAL_CENTER_SYMBOLIC, + ICON_ALIGN_HORIZONTAL_LEFT, + ICON_ALIGN_HORIZONTAL_LEFT_SYMBOLIC, + ICON_ALIGN_HORIZONTAL_LEFT_TO_ANCHOR, + ICON_ALIGN_HORIZONTAL_LEFT_TO_ANCHOR_SYMBOLIC, + ICON_ALIGN_HORIZONTAL_RIGHT, + ICON_ALIGN_HORIZONTAL_RIGHT_SYMBOLIC, + ICON_ALIGN_HORIZONTAL_RIGHT_TO_ANCHOR, + ICON_ALIGN_HORIZONTAL_RIGHT_TO_ANCHOR_SYMBOLIC, + ICON_ALIGN_VERTICAL_BOTTOM, + ICON_ALIGN_VERTICAL_BOTTOM_SYMBOLIC, + ICON_ALIGN_VERTICAL_BOTTOM_TO_ANCHOR, + ICON_ALIGN_VERTICAL_BOTTOM_TO_ANCHOR_SYMBOLIC, + ICON_ALIGN_VERTICAL_CENTER, + ICON_ALIGN_VERTICAL_CENTER_SYMBOLIC, + ICON_ALIGN_VERTICAL_TOP, + ICON_ALIGN_VERTICAL_TOP_SYMBOLIC, + ICON_ALIGN_VERTICAL_TOP_TO_ANCHOR, + ICON_ALIGN_VERTICAL_TOP_TO_ANCHOR_SYMBOLIC, + ICON_APPLICATION_ADD_SYMBOLIC, + ICON_APPOINTMENT_NEW, + ICON_APPOINTMENT_NEW_SYMBOLIC, + ICON_APPOINTMENT_SYMBOLIC, + ICON_BOOKMARK_NEW, + ICON_BOOKMARK_NEW_SYMBOLIC, + ICON_CALL_START, + ICON_CALL_START_SYMBOLIC, + ICON_CALL_STOP, + ICON_CALL_STOP_SYMBOLIC, + ICON_COLOR_FILL, + ICON_COLOR_GRADIENT, + ICON_COLOR_GRADIENT_MESH, + ICON_COLOR_SELECT_SYMBOLIC, + ICON_CONTACT_NEW, + ICON_CONTACT_NEW_SYMBOLIC, + ICON_DISTRIBUTE_HORIZONTAL_CENTER, + ICON_DISTRIBUTE_HORIZONTAL_GAPS, + ICON_DISTRIBUTE_HORIZONTAL_LEFT, + ICON_DISTRIBUTE_HORIZONTAL_RIGHT, + ICON_DISTRIBUTE_VERTICAL_BOTTOM, + ICON_DISTRIBUTE_VERTICAL_CENTER, + ICON_DISTRIBUTE_VERTICAL_GAPS, + ICON_DISTRIBUTE_VERTICAL_TOP, + ICON_DOCUMENT_EDIT, + ICON_DOCUMENT_EDIT_SYMBOLIC, + ICON_DOCUMENT_EXPORT, + ICON_DOCUMENT_EXPORT_SYMBOLIC, + ICON_DOCUMENT_IMPORT, + ICON_DOCUMENT_IMPORT_SYMBOLIC, + ICON_DOCUMENT_NEW, + ICON_DOCUMENT_NEW_SYMBOLIC, + ICON_DOCUMENT_OPEN_RECENT, + ICON_DOCUMENT_OPEN_RECENT_SYMBOLIC, + ICON_DOCUMENT_OPEN_SYMBOLIC, + ICON_DOCUMENT_PAGE_SETUP, + ICON_DOCUMENT_PAGE_SETUP_SYMBOLIC, + ICON_DOCUMENT_PRINT_PREVIEW, + ICON_DOCUMENT_PRINT_PREVIEW_SYMBOLIC, + ICON_DOCUMENT_PRINT_SYMBOLIC, + ICON_DOCUMENT_PROPERTIES, + ICON_DOCUMENT_PROPERTIES_SYMBOLIC, + ICON_DOCUMENT_REVERT, + ICON_DOCUMENT_REVERT_SYMBOLIC, + ICON_DOCUMENT_SAVE_AS, + ICON_DOCUMENT_SAVE_AS_SYMBOLIC, + ICON_DOCUMENT_SAVE_SYMBOLIC, + ICON_DOCUMENT_SEND, + ICON_DOCUMENT_SEND_SYMBOLIC, + ICON_DRAW_CUBOID, + ICON_DRAW_ELLIPSE, + ICON_DRAW_ERASER, + ICON_DRAW_FREEHAND, + ICON_DRAW_PATH, + ICON_DRAW_POLYGON_STAR, + ICON_DRAW_RECTANGLE, + ICON_DRAW_SPIRAL, + ICON_DRAW_TEXT, + ICON_EDIT_CLEAR, + ICON_EDIT_CLEAR_ALL_SYMBOLIC, + ICON_EDIT_CLEAR_SYMBOLIC, + ICON_EDIT_COPY, + ICON_EDIT_COPY_SYMBOLIC, + ICON_EDIT_CUT, + ICON_EDIT_CUT_SYMBOLIC, + ICON_EDIT_DELETE_SYMBOLIC, + ICON_EDIT_FIND, + ICON_EDIT_FIND_REPLACE, + ICON_EDIT_FIND_REPLACE_SYMBOLIC, + ICON_EDIT_FIND_SYMBOLIC, + ICON_EDIT_FLAG, + ICON_EDIT_FLAG_SYMBOLIC, + ICON_EDIT_MARK, + ICON_EDIT_PASTE, + ICON_EDIT_PASTE_SYMBOLIC, + ICON_EDIT_REDO, + ICON_EDIT_REDO_SYMBOLIC, + ICON_EDIT_SELECT_ALL, + ICON_EDIT_SELECT_ALL_SYMBOLIC, + ICON_EDIT_SELECT_SYMBOLIC, + ICON_EDIT_UNDO, + ICON_EDIT_UNDO_ARCHIVE, + ICON_EDIT_UNDO_SYMBOLIC, + ICON_ERROR_CORRECT_SYMBOLIC, + ICON_EVENT_NEW, + ICON_FIND_LOCATION, + ICON_FIND_LOCATION_SYMBOLIC, + ICON_FOLDER_COPY, + ICON_FOLDER_MOVE, + ICON_FOLDER_NEW, + ICON_FOLDER_NEW_SYMBOLIC, + ICON_FONT_SELECT_SYMBOLIC, + ICON_FORMAT_INDENT_LESS, + ICON_FORMAT_INDENT_LESS_SYMBOLIC, + ICON_FORMAT_INDENT_MORE, + ICON_FORMAT_INDENT_MORE_SYMBOLIC, + ICON_FORMAT_JUSTIFY_CENTER, + ICON_FORMAT_JUSTIFY_CENTER_SYMBOLIC, + ICON_FORMAT_JUSTIFY_FILL, + ICON_FORMAT_JUSTIFY_FILL_SYMBOLIC, + ICON_FORMAT_JUSTIFY_LEFT, + ICON_FORMAT_JUSTIFY_LEFT_SYMBOLIC, + ICON_FORMAT_JUSTIFY_RIGHT, + ICON_FORMAT_JUSTIFY_RIGHT_SYMBOLIC, + ICON_FORMAT_TEXT_BOLD, + ICON_FORMAT_TEXT_BOLD_ES_SYMBOLIC, + ICON_FORMAT_TEXT_BOLD_FR_SYMBOLIC, + ICON_FORMAT_TEXT_BOLD_SYMBOLIC, + ICON_FORMAT_TEXT_CLEAR_FORMATTING_SYMBOLIC, + ICON_FORMAT_TEXT_DIRECTION_LTR_SYMBOLIC, + ICON_FORMAT_TEXT_HIGHLIGHT, + ICON_FORMAT_TEXT_ITALIC, + ICON_FORMAT_TEXT_ITALIC_ES_SYMBOLIC, + ICON_FORMAT_TEXT_ITALIC_SYMBOLIC, + ICON_FORMAT_TEXT_LARGER_SYMBOLIC, + ICON_FORMAT_TEXT_NONE, + ICON_FORMAT_TEXT_SMALLER_SYMBOLIC, + ICON_FORMAT_TEXT_STRIKETHROUGH, + ICON_FORMAT_TEXT_STRIKETHROUGH_FR_SYMBOLIC, + ICON_FORMAT_TEXT_STRIKETHROUGH_SYMBOLIC, + ICON_FORMAT_TEXT_UNDERLINE, + ICON_FORMAT_TEXT_UNDERLINE_FR_SYMBOLIC, + ICON_FORMAT_TEXT_UNDERLINE_SYMBOLIC, + ICON_GO_BOTTOM, + ICON_GO_BOTTOM_SYMBOLIC, + ICON_GO_DOWN, + ICON_GO_DOWN_SYMBOLIC, + ICON_GO_FIRST, + ICON_GO_FIRST_SYMBOLIC, + ICON_GO_HOME_SYMBOLIC, + ICON_GO_JUMP, + ICON_GO_JUMP_SYMBOLIC, + ICON_GO_LAST, + ICON_GO_LAST_SYMBOLIC, + ICON_GO_NEXT, + ICON_GO_NEXT_SYMBOLIC, + ICON_GO_PREVIOUS, + ICON_GO_PREVIOUS_SYMBOLIC, + ICON_GO_TOP, + ICON_GO_TOP_SYMBOLIC, + ICON_GO_UP, + ICON_GO_UP_SYMBOLIC, + ICON_HELP_ABOUT, + ICON_HELP_ABOUT_SYMBOLIC, + ICON_HELP_CONTENTS, + ICON_HELP_CONTENTS_SYMBOLIC, + ICON_HELP_INFO_SYMBOLIC, + ICON_IMAGE_ADJUST, + ICON_IMAGE_AUTO_ADJUST, + ICON_IMAGE_CROP, + ICON_IMAGE_CROP_SYMBOLIC, + ICON_IMAGE_RED_EYE, + ICON_IMAGE_RED_EYE_SYMBOLIC, + ICON_INSERT_IMAGE, + ICON_INSERT_IMAGE_SYMBOLIC, + ICON_INSERT_LINK, + ICON_INSERT_LINK_SYMBOLIC, + ICON_INSERT_OBJECT, + ICON_INSERT_OBJECT_SYMBOLIC, + ICON_INSERT_TEXT_SYMBOLIC, + ICON_LIST_ADD, + ICON_LIST_ADD_SYMBOLIC, + ICON_LIST_REMOVE, + ICON_LIST_REMOVE_SYMBOLIC, + ICON_MAIL_ARCHIVE, + ICON_MAIL_FORWARD, + ICON_MAIL_FORWARD_SYMBOLIC, + ICON_MAIL_MARK_IMPORTANT, + ICON_MAIL_MARK_IMPORTANT_SYMBOLIC, + ICON_MAIL_MARK_JUNK, + ICON_MAIL_MARK_JUNK_SYMBOLIC, + ICON_MAIL_MARK_NOTJUNK, + ICON_MAIL_MARK_NOTJUNK_SYMBOLIC, + ICON_MAIL_MESSAGE_NEW, + ICON_MAIL_MESSAGE_NEW_SYMBOLIC, + ICON_MAIL_MOVE, + ICON_MAIL_MOVE_SYMBOLIC, + ICON_MAIL_REPLY_ALL, + ICON_MAIL_REPLY_ALL_SYMBOLIC, + ICON_MAIL_REPLY_SENDER, + ICON_MAIL_REPLY_SENDER_SYMBOLIC, + ICON_MAIL_SEND, + ICON_MAIL_SEND_RECEIVE_SYMBOLIC, + ICON_MAIL_SEND_SYMBOLIC, + ICON_MARK_LOCATION_SYMBOLIC, + ICON_MEDIA_EJECT, + ICON_MEDIA_EJECT_SYMBOLIC, + ICON_MEDIA_EQ_SYMBOLIC, + ICON_MEDIA_PLAYBACK_PAUSE, + ICON_MEDIA_PLAYBACK_PAUSE_SYMBOLIC, + ICON_MEDIA_PLAYBACK_START, + ICON_MEDIA_PLAYBACK_START_SYMBOLIC, + ICON_MEDIA_PLAYBACK_STOP, + ICON_MEDIA_PLAYBACK_STOP_SYMBOLIC, + ICON_MEDIA_RECORD, + ICON_MEDIA_RECORD_SYMBOLIC, + ICON_MEDIA_SEEK_BACKWARD, + ICON_MEDIA_SEEK_BACKWARD_SYMBOLIC, + ICON_MEDIA_SEEK_FORWARD, + ICON_MEDIA_SEEK_FORWARD_SYMBOLIC, + ICON_MEDIA_SKIP_BACKWARD, + ICON_MEDIA_SKIP_FORWARD, + ICON_MEDIA_VIEW_SUBTITLES_SYMBOLIC, + ICON_NODE_ADD, + ICON_NODE_ALIGN_HORIZONTAL, + ICON_NODE_ALIGN_VERTICAL, + ICON_NODE_BREAK, + ICON_NODE_CUSP, + ICON_NODE_DELETE, + ICON_NODE_DELETE_SEGMENT, + ICON_NODE_DISTRIBUTE_HORIZONTAL, + ICON_NODE_DISTRIBUTE_VERTICAL, + ICON_NODE_INSERT, + ICON_NODE_JOIN, + ICON_NODE_JOIN_SEGMENT, + ICON_NODE_SMOOTH, + ICON_NODE_SYMMETRIC, + ICON_OBJECT_FLIP_HORIZONTAL, + ICON_OBJECT_FLIP_HORIZONTAL_SYMBOLIC, + ICON_OBJECT_FLIP_VERTICAL, + ICON_OBJECT_FLIP_VERTICAL_SYMBOLIC, + ICON_OBJECT_GROUP, + ICON_OBJECT_GROUP_SYMBOLIC, + ICON_OBJECT_INVERSE, + ICON_OBJECT_INVERSE_SYMBOLIC, + ICON_OBJECT_MERGE, + ICON_OBJECT_ROTATE_LEFT, + ICON_OBJECT_ROTATE_LEFT_SYMBOLIC, + ICON_OBJECT_ROTATE_RIGHT, + ICON_OBJECT_ROTATE_RIGHT_SYMBOLIC, + ICON_OBJECT_SELECT_SYMBOLIC, + ICON_OBJECT_STRAIGHTEN, + ICON_OBJECT_TO_PATH, + ICON_OBJECT_UNGROUP, + ICON_OBJECT_UNGROUP_SYMBOLIC, + ICON_OPEN_MENU, + ICON_OPEN_MENU_SYMBOLIC, + ICON_PAN_DOWN_SYMBOLIC, + ICON_PAN_END_SYMBOLIC, + ICON_PAN_START_SYMBOLIC, + ICON_PAN_UP_SYMBOLIC, + ICON_PANE_HIDE_SYMBOLIC, + ICON_PANE_SHOW_SYMBOLIC, + ICON_PATH_BREAK_APART, + ICON_PATH_BREAK_APART_SYMBOLIC, + ICON_PATH_COMBINE, + ICON_PATH_COMBINE_SYMBOLIC, + ICON_PATH_DIFFERENCE, + ICON_PATH_DIFFERENCE_SYMBOLIC, + ICON_PATH_DIVISION, + ICON_PATH_DIVISION_SYMBOLIC, + ICON_PATH_EXCLUSION, + ICON_PATH_EXCLUSION_SYMBOLIC, + ICON_PATH_INTERSECTION, + ICON_PATH_INTERSECTION_SYMBOLIC, + ICON_PATH_UNION, + ICON_PATH_UNION_SYMBOLIC, + ICON_PROCESS_STOP, + ICON_PROCESS_STOP_SYMBOLIC, + ICON_SEGMENT_CURVE, + ICON_SEGMENT_LINE, + ICON_SELECTION_ADD, + ICON_SELECTION_BOTTOM, + ICON_SELECTION_BOTTOM_SYMBOLIC, + ICON_SELECTION_CHECKED, + ICON_SELECTION_END_SYMBOLIC, + ICON_SELECTION_LOWER, + ICON_SELECTION_LOWER_SYMBOLIC, + ICON_SELECTION_RAISE, + ICON_SELECTION_RAISE_SYMBOLIC, + ICON_SELECTION_REMOVE, + ICON_SELECTION_START_SYMBOLIC, + ICON_SELECTION_TOP, + ICON_SELECTION_TOP_SYMBOLIC, + ICON_SEND_TO, + ICON_SEND_TO_SYMBOLIC, + ICON_STAR_NEW_SYMBOLIC, + ICON_STROKE_TO_PATH, + ICON_SYSTEM_LOCK_SCREEN, + ICON_SYSTEM_LOCK_SCREEN_SYMBOLIC, + ICON_SYSTEM_LOG_OUT, + ICON_SYSTEM_REBOOT, + ICON_SYSTEM_RUN, + ICON_SYSTEM_RUN_SYMBOLIC, + ICON_SYSTEM_SHUTDOWN, + ICON_SYSTEM_SHUTDOWN_SYMBOLIC, + ICON_SYSTEM_SUSPEND, + ICON_TAB_NEW_SYMBOLIC, + ICON_TAG_NEW, + ICON_TAG_NEW_SYMBOLIC, + ICON_TOOL_MEASURE, + ICON_TOOL_NODE_EDITOR, + ICON_TOOLS_CHECK_SPELLING_SYMBOLIC, + ICON_TOOLS_TIMER_SYMBOLIC, + ICON_VIEW_COLUMN_SYMBOLIC, + ICON_VIEW_CONTINUOUS_SYMBOLIC, + ICON_VIEW_DUAL_SYMBOLIC, + ICON_VIEW_FILTER_SYMBOLIC, + ICON_VIEW_FULLSCREEN_SYMBOLIC, + ICON_VIEW_GRID_SYMBOLIC, + ICON_VIEW_LIST_COMPACT_SYMBOLIC, + ICON_VIEW_LIST_IMAGES_SYMBOLIC, + ICON_VIEW_LIST_SYMBOLIC, + ICON_VIEW_LIST_VIDEO_SYMBOLIC, + ICON_VIEW_MORE_HORIZONTAL_SYMBOLIC, + ICON_VIEW_MORE_SYMBOLIC, + ICON_VIEW_PAGED_SYMBOLIC, + ICON_VIEW_PIN_SYMBOLIC, + ICON_VIEW_REFRESH, + ICON_VIEW_REFRESH_SYMBOLIC, + ICON_VIEW_RESTORE_SYMBOLIC, + ICON_VIEW_SORT_ASCENDING_SYMBOLIC, + ICON_VIEW_SORT_DESCENDING_SYMBOLIC, + ICON_WINDOW_CLOSE, + ICON_WINDOW_CLOSE_SYMBOLIC, + ICON_WINDOW_MAXIMIZE_SYMBOLIC, + ICON_WINDOW_MINIMIZE_SYMBOLIC, + ICON_WINDOW_NEW, + ICON_WINDOW_NEW_SYMBOLIC, + ICON_WINDOW_POP_OUT_SYMBOLIC, + ICON_WINDOW_RESTORE_SYMBOLIC, + ICON_ZOOM_FIT_BEST, + ICON_ZOOM_FIT_BEST_SYMBOLIC, + ICON_ZOOM_IN, + ICON_ZOOM_IN_SYMBOLIC, + ICON_ZOOM_ORIGINAL, + ICON_ZOOM_ORIGINAL_SYMBOLIC, + ICON_ZOOM_OUT, + ICON_ZOOM_OUT_SYMBOLIC, + ICON_ACCESSORIES_CALCULATOR, + ICON_ACCESSORIES_CALCULATOR_SYMBOLIC, + ICON_ACCESSORIES_SCREENSHOT, + ICON_ACCESSORIES_TEXT_EDITOR, + ICON_ACCESSORIES_TEXT_EDITOR_SYMBOLIC, + ICON_APPLICATION_DEFAULT_ICON, + ICON_ARCHIVE_MANAGER, + ICON_INTERNET_CHAT, + ICON_INTERNET_CHAT_SYMBOLIC, + ICON_INTERNET_MAIL, + ICON_INTERNET_MAIL_SYMBOLIC, + ICON_INTERNET_NEWS_READER, + ICON_INTERNET_NEWS_READER_SYMBOLIC, + ICON_INTERNET_WEB_BROWSER, + ICON_INTERNET_WEB_BROWSER_SYMBOLIC, + ICON_MULTIMEDIA_AUDIO_PLAYER, + ICON_MULTIMEDIA_PHOTO_MANAGER, + ICON_MULTIMEDIA_VIDEO_PLAYER, + ICON_OFFICE_ADDRESS_BOOK, + ICON_OFFICE_CALENDAR, + ICON_OFFICE_CALENDAR_SYMBOLIC, + ICON_ONBOARD, + ICON_POSTSCRIPT_VIEWER, + ICON_PREFERENCES_DESKTOP, + ICON_PREFERENCES_DESKTOP_FONT, + ICON_SYSTEM_FILE_MANAGER, + ICON_SYSTEM_OS_INSTALLER, + ICON_SYSTEM_SOFTWARE_INSTALL, + ICON_SYSTEM_SOFTWARE_INSTALL_SYMBOLIC, + ICON_SYSTEM_SOFTWARE_UPDATE, + ICON_SYSTEM_USERS, + ICON_SYSTEM_USERS_SYMBOLIC, + ICON_UTILITIES_SYSTEM_MONITOR, + ICON_UTILITIES_TERMINAL, + ICON_UTILITIES_TERMINAL_SYMBOLIC, + ICON_APPLICATIONS_ACCESSORIES, + ICON_APPLICATIONS_AUDIO_SYMBOLIC, + ICON_APPLICATIONS_DEVELOPMENT, + ICON_APPLICATIONS_DEVELOPMENT_SYMBOLIC, + ICON_APPLICATIONS_EDUCATION, + ICON_APPLICATIONS_EDUCATION_SYMBOLIC, + ICON_APPLICATIONS_ENGINEERING_SYMBOLIC, + ICON_APPLICATIONS_FONTS, + ICON_APPLICATIONS_GAMES, + ICON_APPLICATIONS_GAMES_SYMBOLIC, + ICON_APPLICATIONS_GRAPHICS, + ICON_APPLICATIONS_GRAPHICS_SYMBOLIC, + ICON_APPLICATIONS_INTERFACEDESIGN, + ICON_APPLICATIONS_INTERNET_SYMBOLIC, + ICON_APPLICATIONS_MULTIMEDIA, + ICON_APPLICATIONS_MULTIMEDIA_SYMBOLIC, + ICON_APPLICATIONS_OFFICE, + ICON_APPLICATIONS_OFFICE_SYMBOLIC, + ICON_APPLICATIONS_OTHER, + ICON_APPLICATIONS_OTHER_SYMBOLIC, + ICON_APPLICATIONS_PHOTOGRAPHY, + ICON_APPLICATIONS_SCIENCE, + ICON_APPLICATIONS_SCIENCE_SYMBOLIC, + ICON_APPLICATIONS_UTILITIES, + ICON_APPLICATIONS_UTILITIES_SYMBOLIC, + ICON_APPLICATIONS_VIDEO_SYMBOLIC, + ICON_BUG, + ICON_BUG_SYMBOLIC, + ICON_EMOJI_ACTIVITY_SYMBOLIC, + ICON_EMOJI_BODY_SYMBOLIC, + ICON_EMOJI_FOOD_SYMBOLIC, + ICON_EMOJI_NATURE_SYMBOLIC, + ICON_EMOJI_OBJECTS_SYMBOLIC, + ICON_EMOJI_TRAVEL_SYMBOLIC, + ICON_EVENT_BIRTHDAY_SYMBOLIC, + ICON_PREFERENCES_BLUETOOTH_SYMBOLIC, + ICON_PREFERENCES_COLOR, + ICON_PREFERENCES_COLOR_SYMBOLIC, + ICON_PREFERENCES_DESKTOP_ACCESSIBILITY, + ICON_PREFERENCES_DESKTOP_ACCESSIBILITY_POINTING, + ICON_PREFERENCES_DESKTOP_ACCESSIBILITY_SYMBOLIC, + ICON_PREFERENCES_DESKTOP_ACCESSIBILITY_ZOOM, + ICON_PREFERENCES_DESKTOP_APPLICATIONS, + ICON_PREFERENCES_DESKTOP_DISPLAY, + ICON_PREFERENCES_DESKTOP_DISPLAY_SYMBOLIC, + ICON_PREFERENCES_DESKTOP_KEYBOARD, + ICON_PREFERENCES_DESKTOP_KEYBOARD_SYMBOLIC, + ICON_PREFERENCES_DESKTOP_LOCALE, + ICON_PREFERENCES_DESKTOP_LOCALE_SYMBOLIC, + ICON_PREFERENCES_DESKTOP_ONLINE_ACCOUNTS, + ICON_PREFERENCES_DESKTOP_ONLINE_ACCOUNTS_SYMBOLIC, + ICON_PREFERENCES_DESKTOP_PERIPHERALS, + ICON_PREFERENCES_DESKTOP_SOUND, + ICON_PREFERENCES_DESKTOP_WALLPAPER, + ICON_PREFERENCES_OTHER_SYMBOLIC, + ICON_PREFERENCES_SYSTEM, + ICON_PREFERENCES_SYSTEM_NETWORK, + ICON_PREFERENCES_SYSTEM_NETWORK_SYMBOLIC, + ICON_PREFERENCES_SYSTEM_NOTIFICATIONS, + ICON_PREFERENCES_SYSTEM_PARENTAL_CONTROL_SYMBOLIC, + ICON_PREFERENCES_SYSTEM_PARENTAL_CONTROLS, + ICON_PREFERENCES_SYSTEM_POWER, + ICON_PREFERENCES_SYSTEM_POWER_SYMBOLIC, + ICON_PREFERENCES_SYSTEM_PRIVACY_HOUSEKEEPING, + ICON_PREFERENCES_SYSTEM_SHARING, + ICON_PREFERENCES_SYSTEM_SHARING_SYMBOLIC, + ICON_PREFERENCES_SYSTEM_TIME, + ICON_PREFERENCES_SYSTEM_TIME_SYMBOLIC, + ICON_PREFERENCES_SYSTEM_WINDOWS, + ICON_AC_ADAPTER_SYMBOLIC, + ICON_AUDIO_CARD_SYMBOLIC, + ICON_AUDIO_HEADPHONES, + ICON_AUDIO_HEADPHONES_SYMBOLIC, + ICON_AUDIO_HEADSET_SYMBOLIC, + ICON_AUDIO_HEADSETS, + ICON_AUDIO_INPUT_MICROPHONE, + ICON_AUDIO_INPUT_MICROPHONE_SYMBOLIC, + ICON_AUDIO_SPEAKER_CENTER, + ICON_AUDIO_SPEAKER_CENTER_BACK, + ICON_AUDIO_SPEAKER_CENTER_BACK_TESTING, + ICON_AUDIO_SPEAKER_CENTER_TESTING, + ICON_AUDIO_SPEAKER_LEFT, + ICON_AUDIO_SPEAKER_LEFT_BACK, + ICON_AUDIO_SPEAKER_LEFT_BACK_TESTING, + ICON_AUDIO_SPEAKER_LEFT_SIDE, + ICON_AUDIO_SPEAKER_LEFT_SIDE_TESTING, + ICON_AUDIO_SPEAKER_LEFT_TESTING, + ICON_AUDIO_SPEAKER_RIGHT, + ICON_AUDIO_SPEAKER_RIGHT_BACK, + ICON_AUDIO_SPEAKER_RIGHT_BACK_TESTING, + ICON_AUDIO_SPEAKER_RIGHT_SIDE, + ICON_AUDIO_SPEAKER_RIGHT_SIDE_TESTING, + ICON_AUDIO_SPEAKER_RIGHT_TESTING, + ICON_AUDIO_SPEAKERS, + ICON_AUDIO_SPEAKERS_SYMBOLIC, + ICON_AUDIO_SUBWOOFER, + ICON_AUDIO_SUBWOOFER_TESTING, + ICON_BATTERY, + ICON_BATTERY_SYMBOLIC, + ICON_BLUETOOTH, + ICON_BLUETOOTH_SYMBOLIC, + ICON_CAMERA_PHOTO, + ICON_CAMERA_PHOTO_SYMBOLIC, + ICON_CAMERA_VIDEO, + ICON_CAMERA_VIDEO_SYMBOLIC, + ICON_CAMERA_WEB, + ICON_CAMERA_WEB_SYMBOLIC, + ICON_COLORIMETER_COLORHUG_SYMBOLIC, + ICON_COMPUTER_LAPTOP, + ICON_COMPUTER_LAPTOP_SYMBOLIC, + ICON_DISPLAY_PROJECTOR_SYMBOLIC, + ICON_DRIVE_HARDDISK, + ICON_DRIVE_HARDDISK_IEEE1394_SYMBOLIC, + ICON_DRIVE_HARDDISK_SOLIDSTATE, + ICON_DRIVE_HARDDISK_SOLIDSTATE_SYMBOLIC, + ICON_DRIVE_HARDDISK_SYMBOLIC, + ICON_DRIVE_MULTIDISK_SYMBOLIC, + ICON_DRIVE_OPTICAL_SYMBOLIC, + ICON_DRIVE_REMOVABLE_MEDIA, + ICON_DRIVE_REMOVABLE_MEDIA_SYMBOLIC, + ICON_DRIVE_REMOVABLE_MEDIA_USB, + ICON_FINGERPRINT, + ICON_FINGERPRINT_SYMBOLIC, + ICON_GNOME_DEV_PRINTER_NEW, + ICON_INPUT_DIALPAD_SYMBOLIC, + ICON_INPUT_GAMING, + ICON_INPUT_GAMING_SYMBOLIC, + ICON_INPUT_KEYBOARD, + ICON_INPUT_KEYBOARD_SYMBOLIC, + ICON_INPUT_MOUSE, + ICON_INPUT_MOUSE_SYMBOLIC, + ICON_INPUT_TABLET, + ICON_INPUT_TABLET_SYMBOLIC, + ICON_INPUT_TOUCHPAD, + ICON_INPUT_TOUCHPAD_SYMBOLIC, + ICON_MEDIA_FLASH_CF, + ICON_MEDIA_FLASH_MS, + ICON_MEDIA_FLASH_SYMBOLIC, + ICON_MEDIA_FLOPPY_SYMBOLIC, + ICON_MEDIA_MEMORY, + ICON_MEDIA_MEMORY_SD, + ICON_MEDIA_MEMORY_SEMBOLIC, + ICON_MEDIA_MEMORY_SM, + ICON_MEDIA_OPTICAL, + ICON_MEDIA_OPTICAL_SYMBOLIC, + ICON_MEDIA_REMOVABLE_SYMBOLIC, + ICON_MEDIA_TAPE_SYMBOLIC, + ICON_MEDIA_ZIP_SYMBOLIC, + ICON_MODEM, + ICON_MODEM_SYMBOLIC, + ICON_MULTIMEDIA_PLAYER, + ICON_MULTIMEDIA_PLAYER_SYMBOLIC, + ICON_NETWORK_CELLULAR, + ICON_NETWORK_FIREWALL, + ICON_NETWORK_VPN, + ICON_NETWORK_WIRED, + ICON_NETWORK_WIRELESS, + ICON_NETWORK_WIRELESS_HOTSPOT, + ICON_NM_DEVICE_WWAN, + ICON_PDA_SYMBOLIC, + ICON_PHONE, + ICON_PHONE_SYMBOLIC, + ICON_PRINTER, + ICON_PRINTER_NETWORK, + ICON_PRINTER_SYMBOLIC, + ICON_SCANNER, + ICON_SCANNER_SYMBOLIC, + ICON_TABLET, + ICON_TABLET_SYMBOLIC, + ICON_TV_SYMBOLIC, + ICON_UNINTERRUPTIBLE_POWER_SUPPLY, + ICON_UNINTERRUPTIBLE_POWER_SUPPLY_SYMBOLIC, + ICON_VIDEO_DISPLAY, + ICON_VIDEO_DISPLAY_SYMBOLIC, + ICON_EMBLEM_DEFAULT_SYMBOLIC, + ICON_EMBLEM_DOCUMENTS_SYMBOLIC, + ICON_EMBLEM_FAVORITE_SYMBOLIC, + ICON_EMBLEM_IMPORTANT_SYMBOLIC, + ICON_EMBLEM_MUSIC_SYMBOLIC, + ICON_EMBLEM_OK_SYMBOLIC, + ICON_EMBLEM_PHOTOS_SYMBOLIC, + ICON_EMBLEM_READONLY, + ICON_EMBLEM_SHARED_SYMBOLIC, + ICON_EMBLEM_SYMBOLIC_LINK, + ICON_EMBLEM_SYNCHRONIZED, + ICON_EMBLEM_SYNCHRONIZING_SYMBOLIC, + ICON_EMBLEM_UNREADABLE, + ICON_EMBLEM_VIDEOS_SYMBOLIC, + ICON_FACE_ANGEL, + ICON_FACE_ANGEL_SYMBOLIC, + ICON_FACE_ANGRY, + ICON_FACE_ANGRY_SYMBOLIC, + ICON_FACE_COOL, + ICON_FACE_COOL_SYMBOLIC, + ICON_FACE_CRYING, + ICON_FACE_CRYING_SYMBOLIC, + ICON_FACE_DEVILISH, + ICON_FACE_DEVILISH_SYMBOLIC, + ICON_FACE_EMBARRASSED, + ICON_FACE_EMBARRASSED_SYMBOLIC, + ICON_FACE_HEART, + ICON_FACE_HEART_BROKEN, + ICON_FACE_HEART_BROKEN_SYMBOLIC, + ICON_FACE_HEART_SYMBOLIC, + ICON_FACE_KISS, + ICON_FACE_KISS_SYMBOLIC, + ICON_FACE_LAUGH, + ICON_FACE_LAUGH_SYMBOLIC, + ICON_FACE_MONKEY_SYMBOLIC, + ICON_FACE_PLAIN, + ICON_FACE_PLAIN_SYMBOLIC, + ICON_FACE_RASPBERRY, + ICON_FACE_RASPBERRY_SYMBOLIC, + ICON_FACE_SAD, + ICON_FACE_SAD_SYMBOLIC, + ICON_FACE_SICK, + ICON_FACE_SICK_SYMBOLIC, + ICON_FACE_SMILE, + ICON_FACE_SMILE_BIG, + ICON_FACE_SMILE_BIG_SYMBOLIC, + ICON_FACE_SMILE_SYMBOLIC, + ICON_FACE_SMIRK, + ICON_FACE_SMIRK_SYMBOLIC, + ICON_FACE_SURPRISE, + ICON_FACE_SURPRISE_SYMBOLIC, + ICON_FACE_TIRED, + ICON_FACE_TIRED_SYMBOLIC, + ICON_FACE_UNCERTAIN, + ICON_FACE_UNCERTAIN_SYMBOLIC, + ICON_FACE_WINK, + ICON_FACE_WINK_SYMBOLIC, + ICON_FACE_WORRIED, + ICON_FACE_WORRIED_SYMBOLIC, + ICON_APPLICATION_CERTIFICATE_SYMBOLIC, + ICON_APPLICATION_EPUB_ZIP, + ICON_APPLICATION_ILLUSTRATOR, + ICON_APPLICATION_JAVASCRIPT, + ICON_APPLICATION_MSWORD, + ICON_APPLICATION_OCTET_STREAM, + ICON_APPLICATION_PDF, + ICON_APPLICATION_PGP, + ICON_APPLICATION_RSS_XML_SYMBOLIC, + ICON_APPLICATION_VND, + ICON_APPLICATION_X_APPLIANCE_SYMBOLIC, + ICON_APPLICATION_X_BITTORRENT, + ICON_APPLICATION_X_CD_IMAGE, + ICON_APPLICATION_X_DESKTOP, + ICON_APPLICATION_X_EXECUTABLE_SYMBOLIC, + ICON_APPLICATION_X_FICTIONBOOK_XML, + ICON_APPLICATION_X_FIRMWARE, + ICON_APPLICATION_X_FIRMWARE_SYMBOLIC, + ICON_APPLICATION_X_FLASH_VIDEO, + ICON_APPLICATION_X_MS_DOS_EXECUTABLE, + ICON_APPLICATION_X_PARTIAL_DOWNLOAD, + ICON_APPLICATION_X_PHP, + ICON_APPLICATION_X_RUBY, + ICON_AUDIO_X_GENERIC, + ICON_AUDIO_X_GENERIC_SYMBOLIC, + ICON_AUDIO_X_PLAYLIST, + ICON_EXTENSION, + ICON_FONT_X_GENERIC, + ICON_FONT_X_GENERIC_SYMBOLIC, + ICON_IMAGE_VND, + ICON_IMAGE_X_GENERIC, + ICON_IMAGE_X_GENERIC_SYMBOLIC, + ICON_IMAGE_X_XCF, + ICON_INTERNET_FEED, + ICON_MODEL, + ICON_OFFICE_CONTACT, + ICON_OFFICE_DATABASE, + ICON_PACKAGE_X_GENERIC, + ICON_PACKAGE_X_GENERIC_SYMBOLIC, + ICON_PAYMENT_CARD, + ICON_PAYMENT_CARD_AMEX, + ICON_PAYMENT_CARD_DINERS_CLUB, + ICON_PAYMENT_CARD_DISCOVER, + ICON_PAYMENT_CARD_JCB, + ICON_PAYMENT_CARD_MASTERCARD, + ICON_PAYMENT_CARD_SYMBOLIC, + ICON_PAYMENT_CARD_UNIONPAY, + ICON_PAYMENT_CARD_VISA, + ICON_TEXT, + ICON_TEXT_CSS, + ICON_TEXT_HTML, + ICON_TEXT_HTML_SYMBOLIC, + ICON_TEXT_MARKDOWN, + ICON_TEXT_X_BIBTEX, + ICON_TEXT_X_CHANGELOG, + ICON_TEXT_X_CHDR, + ICON_TEXT_X_COPYING, + ICON_TEXT_X_COPYING_SYMBOLIC, + ICON_TEXT_X_CSRC, + ICON_TEXT_X_GENERIC_SYMBOLIC, + ICON_TEXT_X_GENERIC_TEMPLATE, + ICON_TEXT_X_GETTEXT_TRANSLATION, + ICON_TEXT_X_GETTEXT_TRANSLATION_TEMPLATE, + ICON_TEXT_X_GO, + ICON_TEXT_X_INSTALL, + ICON_TEXT_X_MAKEFILE, + ICON_TEXT_X_PREVIEW, + ICON_TEXT_X_PYTHON, + ICON_TEXT_X_README, + ICON_TEXT_X_SASS, + ICON_TEXT_X_SCRIPT, + ICON_TEXT_X_SSA, + ICON_TEXT_X_TEX, + ICON_TEXT_X_VALA, + ICON_UNKNOWN, + ICON_VIDEO_X_GENERIC, + ICON_VIDEO_X_GENERIC_SYMBOLIC, + ICON_X_OFFICE_ADDRESS_BOOK_SYMBOLIC, + ICON_X_OFFICE_DOCUMENT, + ICON_X_OFFICE_DOCUMENT_SYMBOLIC, + ICON_X_OFFICE_DOCUMENT_TEMPLATE, + ICON_X_OFFICE_DRAWING, + ICON_X_OFFICE_DRAWING_SYMBOLIC, + ICON_X_OFFICE_DRAWING_TEMPLATE, + ICON_X_OFFICE_PRESENTATION, + ICON_X_OFFICE_PRESENTATION_SYMBOLIC, + ICON_X_OFFICE_PRESENTATION_TEMPLATE, + ICON_X_OFFICE_SPREADSHEET, + ICON_X_OFFICE_SPREADSHEET_SYMBOLIC, + ICON_X_OFFICE_SPREADSHEET_TEMPLATE, + ICON_BOOKMARK_MISSING, + ICON_DISTRIBUTOR_LOGO, + ICON_DISTRIBUTOR_LOGO_SYMBOLIC, + ICON_FOLDER, + ICON_FOLDER_DOCUMENTS, + ICON_FOLDER_DOCUMENTS_OPEN, + ICON_FOLDER_DOCUMENTS_SYMBOLIC, + ICON_FOLDER_DOWNLOAD, + ICON_FOLDER_DOWNLOAD_OPEN, + ICON_FOLDER_DOWNLOAD_SYMBOLIC, + ICON_FOLDER_MUSIC, + ICON_FOLDER_MUSIC_OPEN, + ICON_FOLDER_MUSIC_SYMBOLIC, + ICON_FOLDER_OPEN, + ICON_FOLDER_PICTURES, + ICON_FOLDER_PICTURES_OPEN, + ICON_FOLDER_PICTURES_SYMBOLIC, + ICON_FOLDER_PUBLICSHARE, + ICON_FOLDER_PUBLICSHARE_OPEN, + ICON_FOLDER_PUBLICSHARE_SYMBOLIC, + ICON_FOLDER_RECENT, + ICON_FOLDER_RECENT_SYMBOLIC, + ICON_FOLDER_REMOTE, + ICON_FOLDER_REMOTE_OPEN, + ICON_FOLDER_SAVED_SEARCH, + ICON_FOLDER_SYMBOLIC, + ICON_FOLDER_TAG, + ICON_FOLDER_TEMPLATES, + ICON_FOLDER_TEMPLATES_OPEN, + ICON_FOLDER_TEMPLATES_SYMBOLIC, + ICON_FOLDER_VIDEOS, + ICON_FOLDER_VIDEOS_OPEN, + ICON_FOLDER_VIDEOS_SYMBOLIC, + ICON_INTERNET_RADIO, + ICON_INTERNET_RADIO_SYMBOLIC, + ICON_LIBRARY_AUDIOBOOK, + ICON_LIBRARY_PLACES, + ICON_LIBRARY_PODCAST, + ICON_MAIL_INBOX, + ICON_MAIL_INBOX_SYMBOLIC, + ICON_MAIL_MAILBOX, + ICON_MAIL_MAILBOX_SYMBOLIC, + ICON_MAIL_OUTBOX, + ICON_MAIL_OUTBOX_SYMBOLIC, + ICON_NETWORK_SERVER_SYMBOLIC, + ICON_PLAYLIST, + ICON_PLAYLIST_AUTOMATIC, + ICON_PLAYLIST_QUEUE, + ICON_PLAYLIST_QUEUE_SYMBOLIC, + ICON_PLAYLIST_SIMILAR, + ICON_PLAYLIST_SYMBOLIC, + ICON_TAG_SYMBOLIC, + ICON_USER_BOOKMARKS_SYMBOLIC, + ICON_USER_HOME, + ICON_USER_HOME_OPEN, + ICON_USER_HOME_SYMBOLIC, + ICON_USER_TRASH, + ICON_USER_TRASH_FULL, + ICON_USER_TRASH_SYMBOLIC, + ICON_AIRPLANE_MODE, + ICON_AIRPLANE_MODE_SYMBOLIC, + ICON_ALARM_SYMBOLIC, + ICON_APPOINTMENT_MISSED, + ICON_APPOINTMENT_MISSED_SYMBOLIC, + ICON_APPOINTMENT_SOON, + ICON_APPOINTMENT_SOON_SYMBOLIC, + ICON_AUDIO_VOLUME_HIGH_SYMBOLIC, + ICON_AUDIO_VOLUME_LOW_SYMBOLIC, + ICON_AUDIO_VOLUME_MEDIUM_SYMBOLIC, + ICON_AUDIO_VOLUME_MUTED_BLOCKING_SYMBOLIC, + ICON_AUDIO_VOLUME_MUTED_SYMBOLIC, + ICON_AVATAR_DEFAULT, + ICON_AVATAR_DEFAULT_SYMBOLIC, + ICON_BATTERY_AC_ADAPTER, + ICON_BATTERY_AC_ADAPTER_SYMBOLIC, + ICON_BATTERY_CAUTION, + ICON_BATTERY_CAUTION_CHARGING, + ICON_BATTERY_CAUTION_CHARGING_SYMBOLIC, + ICON_BATTERY_CAUTION_SYMBOLIC, + ICON_BATTERY_EMPTY, + ICON_BATTERY_EMPTY_CHARGING, + ICON_BATTERY_EMPTY_CHARGING_SYMBOLIC, + ICON_BATTERY_EMPTY_SYMBOLIC, + ICON_BATTERY_FULL, + ICON_BATTERY_FULL_CHARGED, + ICON_BATTERY_FULL_CHARGED_SYMBOLIC, + ICON_BATTERY_FULL_CHARGING, + ICON_BATTERY_FULL_CHARGING_SYMBOLIC, + ICON_BATTERY_FULL_SYMBOLIC, + ICON_BATTERY_GOOD, + ICON_BATTERY_GOOD_CHARGING, + ICON_BATTERY_GOOD_CHARGING_SYMBOLIC, + ICON_BATTERY_GOOD_SYMBOLIC, + ICON_BATTERY_LOW, + ICON_BATTERY_LOW_CHARGING, + ICON_BATTERY_LOW_CHARGING_SYMBOLIC, + ICON_BATTERY_LOW_SYMBOLIC, + ICON_BATTERY_MISSING, + ICON_BATTERY_MISSING_SYMBOLIC, + ICON_BLUETOOTH_ACTIVE_SYMBOLIC, + ICON_BLUETOOTH_DISABLED, + ICON_BLUETOOTH_DISABLED_10_SYMBOLIC, + ICON_BLUETOOTH_DISABLED_20_SYMBOLIC, + ICON_BLUETOOTH_DISABLED_30_SYMBOLIC, + ICON_BLUETOOTH_DISABLED_40_SYMBOLIC, + ICON_BLUETOOTH_DISABLED_50_SYMBOLIC, + ICON_BLUETOOTH_DISABLED_60_SYMBOLIC, + ICON_BLUETOOTH_DISABLED_70_SYMBOLIC, + ICON_BLUETOOTH_DISABLED_80_SYMBOLIC, + ICON_BLUETOOTH_DISABLED_90_SYMBOLIC, + ICON_BLUETOOTH_DISABLED_SYMBOLIC, + ICON_BLUETOOTH_PAIRED_SYMBOLIC, + ICON_CALL_MISSED_SYMBOLIC, + ICON_CHANGES_ALLOW, + ICON_CHANGES_ALLOW_SYMBOLIC, + ICON_CHANGES_PREVENT_SYMBOLIC, + ICON_CHANNEL_INSECURE_SYMBOLIC, + ICON_CHANNEL_SECURE_SYMBOLIC, + ICON_CHECK_ACTIVE_SYMBOLIC, + ICON_CHECK_MIXED_SYMBOLIC, + ICON_CHECKBOX_CHECKED_SYMBOLIC, + ICON_CHECKBOX_MIXED_SYMBOLIC, + ICON_CHECKBOX_SYMBOLIC, + ICON_COMPUTER_FAIL_SYMBOLIC, + ICON_CONTENT_LOADING_SYMBOLIC, + ICON_DAYTIME_SUNRISE_SYMBOLIC, + ICON_DAYTIME_SUNSET_SYMBOLIC, + ICON_DIALOG_ERROR, + ICON_DIALOG_ERROR_SYMBOLIC, + ICON_DIALOG_INFORMATION, + ICON_DIALOG_INFORMATION_SYMBOLIC, + ICON_DIALOG_PASSWORD, + ICON_DIALOG_PASSWORD_SYMBOLIC, + ICON_DIALOG_WARNING, + ICON_DIALOG_WARNING_SYMBOLIC, + ICON_DISPLAY_BRIGHTNESS_SYMBOLIC, + ICON_FOLDER_OPEN_SYMBOLIC, + ICON_FOLDER_VISITING_SYMBOLIC, + ICON_IMAGE_LOADING, + ICON_IMAGE_MISSING, + ICON_INPUT_KEYBOARD_CAPSLOCK_SYMBOLIC, + ICON_INPUT_KEYBOARD_NUMLOCK_SYMBOLIC, + ICON_KEYBOARD_BRIGHTNESS_SYMBOLIC, + ICON_LOCATION_ACTIVE_SYMBOLIC, + ICON_LOCATION_DISABLED_SYMBOLIC, + ICON_LOCATION_INACTIVE_SYMBOLIC, + ICON_LOCKED, + ICON_MAIL_ATTACHMENT_SYMBOLIC, + ICON_MAIL_FORWARDED_SYMBOLIC, + ICON_MAIL_IMPORTANT_SYMBOLIC, + ICON_MAIL_READ_SYMBOLIC, + ICON_MAIL_REPLIED_SYMBOLIC, + ICON_MAIL_UNREAD, + ICON_MAIL_UNREAD_SYMBOLIC, + ICON_MEDIA_PLAYLIST_CONSECUTIVE_SYMBOLIC, + ICON_MEDIA_PLAYLIST_NO_REPEAT_SYMBOLIC, + ICON_MEDIA_PLAYLIST_REPEAT, + ICON_MEDIA_PLAYLIST_REPEAT_SONG_SYMBOLIC, + ICON_MEDIA_PLAYLIST_REPEAT_SYMBOLIC, + ICON_MEDIA_PLAYLIST_SHUFFLE_SYMBOLIC, + ICON_MICROPHONE_SENSITIVITY_HIGH_SYMBOLIC, + ICON_MICROPHONE_SENSITIVITY_LOW_SYMBOLIC, + ICON_MICROPHONE_SENSITIVITY_MEDIUM_SYMBOLIC, + ICON_MICROPHONE_SENSITIVITY_MUTED_10_SYMBOLIC, + ICON_MICROPHONE_SENSITIVITY_MUTED_20_SYMBOLIC, + ICON_MICROPHONE_SENSITIVITY_MUTED_30_SYMBOLIC, + ICON_MICROPHONE_SENSITIVITY_MUTED_40_SYMBOLIC, + ICON_MICROPHONE_SENSITIVITY_MUTED_50_SYMBOLIC, + ICON_MICROPHONE_SENSITIVITY_MUTED_60_SYMBOLIC, + ICON_MICROPHONE_SENSITIVITY_MUTED_70_SYMBOLIC, + ICON_MICROPHONE_SENSITIVITY_MUTED_80_SYMBOLIC, + ICON_MICROPHONE_SENSITIVITY_MUTED_90_SYMBOLIC, + ICON_MICROPHONE_SENSITIVITY_MUTED_SYMBOLIC, + ICON_NETWORK_CELLULAR_ACQUIRING_SYMBOLIC, + ICON_NETWORK_CELLULAR_CONNECTED_SYMBOLIC, + ICON_NETWORK_CELLULAR_NO_ROUTE_SYMBOLIC, + ICON_NETWORK_CELLULAR_OFFLINE_SYMBOLIC, + ICON_NETWORK_CELLULAR_SIGNAL_EXCELLENT_SECURE_SYMBOLIC, + ICON_NETWORK_CELLULAR_SIGNAL_EXCELLENT_SYMBOLIC, + ICON_NETWORK_CELLULAR_SIGNAL_GOOD_SECURE_SYMBOLIC, + ICON_NETWORK_CELLULAR_SIGNAL_GOOD_SYMBOLIC, + ICON_NETWORK_CELLULAR_SIGNAL_NONE_SECURE_SYMBOLIC, + ICON_NETWORK_CELLULAR_SIGNAL_NONE_SYMBOLIC, + ICON_NETWORK_CELLULAR_SIGNAL_OK_SECURE_SYMBOLIC, + ICON_NETWORK_CELLULAR_SIGNAL_OK_SYMBOLIC, + ICON_NETWORK_CELLULAR_SIGNAL_WEAK_SECURE_SYMBOLIC, + ICON_NETWORK_CELLULAR_SIGNAL_WEAK_SYMBOLIC, + ICON_NETWORK_ERROR, + ICON_NETWORK_ERROR_SYMBOLIC, + ICON_NETWORK_IDLE, + ICON_NETWORK_OFFLINE_SYMBOLIC, + ICON_NETWORK_VPN_ACQUIRING_SYMBOLIC, + ICON_NETWORK_VPN_LOCK_SYMBOLIC, + ICON_NETWORK_VPN_SYMBOLIC, + ICON_NETWORK_WIRED_ACQUIRING_SYMBOLIC, + ICON_NETWORK_WIRED_DISCONNECTED, + ICON_NETWORK_WIRED_NO_ROUTE_SYMBOLIC, + ICON_NETWORK_WIRED_OFFLINE_SYMBOLIC, + ICON_NETWORK_WIRED_SYMBOLIC, + ICON_NETWORK_WIRELESS_ACQUIRING_SYMBOLIC, + ICON_NETWORK_WIRELESS_CONNECTED_SYMBOLIC, + ICON_NETWORK_WIRELESS_ENCRYPTED_SYMBOLIC, + ICON_NETWORK_WIRELESS_HOTSPOT_SYMBOLIC, + ICON_NETWORK_WIRELESS_NO_ROUTE_SYMBOLIC, + ICON_NETWORK_WIRELESS_OFFLINE_SYMBOLIC, + ICON_NETWORK_WIRELESS_SIGNAL_EXCELLENT_SECURE_SYMBOLIC, + ICON_NETWORK_WIRELESS_SIGNAL_EXCELLENT_SYMBOLIC, + ICON_NETWORK_WIRELESS_SIGNAL_GOOD_SECURE_SYMBOLIC, + ICON_NETWORK_WIRELESS_SIGNAL_GOOD_SYMBOLIC, + ICON_NETWORK_WIRELESS_SIGNAL_NONE_SYMBOLIC, + ICON_NETWORK_WIRELESS_SIGNAL_OK_SECURE_SYMBOLIC, + ICON_NETWORK_WIRELESS_SIGNAL_OK_SYMBOLIC, + ICON_NETWORK_WIRELESS_SIGNAL_WEAK_SECURE_SYMBOLIC, + ICON_NETWORK_WIRELESS_SIGNAL_WEAK_SYMBOLIC, + ICON_NETWORK_WIRELESS_SYMBOLIC, + ICON_NIGHT_LIGHT, + ICON_NIGHT_LIGHT_DISABLED_10_SYMBOLIC, + ICON_NIGHT_LIGHT_DISABLED_20_SYMBOLIC, + ICON_NIGHT_LIGHT_DISABLED_30_SYMBOLIC, + ICON_NIGHT_LIGHT_DISABLED_40_SYMBOLIC, + ICON_NIGHT_LIGHT_DISABLED_50_SYMBOLIC, + ICON_NIGHT_LIGHT_DISABLED_60_SYMBOLIC, + ICON_NIGHT_LIGHT_DISABLED_70_SYMBOLIC, + ICON_NIGHT_LIGHT_DISABLED_80_SYMBOLIC, + ICON_NIGHT_LIGHT_DISABLED_90_SYMBOLIC, + ICON_NIGHT_LIGHT_DISABLED_SYMBOLIC, + ICON_NIGHT_LIGHT_SYMBOLIC, + ICON_NM_NO_CONNECTION, + ICON_NM_SIGNAL_0, + ICON_NM_SIGNAL_0_SECURE, + ICON_NM_SIGNAL_100, + ICON_NM_SIGNAL_100_SECURE, + ICON_NM_SIGNAL_25, + ICON_NM_SIGNAL_25_SECURE, + ICON_NM_SIGNAL_50, + ICON_NM_SIGNAL_50_SECURE, + ICON_NM_SIGNAL_75, + ICON_NM_SIGNAL_75_SECURE, + ICON_NM_VPN_ACTIVE_LOCK, + ICON_NM_VPN_LOCK, + ICON_NON_STARRED, + ICON_NON_STARRED_SYMBOLIC, + ICON_NOTIFICATION_AUDIO_VOLUME_HIGH, + ICON_NOTIFICATION_AUDIO_VOLUME_LOW, + ICON_NOTIFICATION_AUDIO_VOLUME_MEDIUM, + ICON_NOTIFICATION_AUDIO_VOLUME_MUTED, + ICON_NOTIFICATION_DEVICE_EJECT, + ICON_NOTIFICATION_DISABLED, + ICON_NOTIFICATION_DISABLED_10_SYMBOLIC, + ICON_NOTIFICATION_DISABLED_20_SYMBOLIC, + ICON_NOTIFICATION_DISABLED_30_SYMBOLIC, + ICON_NOTIFICATION_DISABLED_40_SYMBOLIC, + ICON_NOTIFICATION_DISABLED_50_SYMBOLIC, + ICON_NOTIFICATION_DISABLED_60_SYMBOLIC, + ICON_NOTIFICATION_DISABLED_70_SYMBOLIC, + ICON_NOTIFICATION_DISABLED_80_SYMBOLIC, + ICON_NOTIFICATION_DISABLED_90_SYMBOLIC, + ICON_NOTIFICATION_DISABLED_SYMBOLIC, + ICON_NOTIFICATION_DISPLAY_BRIGHTNESS, + ICON_NOTIFICATION_KEYBOARD_BRIGHTNESS, + ICON_NOTIFICATION_NETWORK_ETHERNET_DISCONNECTED, + ICON_NOTIFICATION_NETWORK_WIRED, + ICON_NOTIFICATION_NETWORK_WIRELESS, + ICON_NOTIFICATION_NETWORK_WIRELESS_DISCONNECTED, + ICON_NOTIFICATION_NETWORK_WIRELESS_DISCONNECTED_SYMBOLIC, + ICON_NOTIFICATION_NETWORK_WIRELESS_SYMBOLIC, + ICON_NOTIFICATION_NEW_10_SYMBOLIC, + ICON_NOTIFICATION_NEW_20_SYMBOLIC, + ICON_NOTIFICATION_NEW_30_SYMBOLIC, + ICON_NOTIFICATION_NEW_40_SYMBOLIC, + ICON_NOTIFICATION_NEW_50_SYMBOLIC, + ICON_NOTIFICATION_NEW_60_SYMBOLIC, + ICON_NOTIFICATION_NEW_70_SYMBOLIC, + ICON_NOTIFICATION_NEW_80_SYMBOLIC, + ICON_NOTIFICATION_NEW_90_SYMBOLIC, + ICON_NOTIFICATION_NEW_SYMBOLIC, + ICON_NOTIFICATION_SYMBOLIC, + ICON_PAGER_CHECKED_SYMBOLIC, + ICON_PRINTER_ERROR, + ICON_PRINTER_ERROR_SYMBOLIC, + ICON_PRINTER_PRINTING_SYMBOLIC, + ICON_PRINTER_WARNING_SYMBOLIC, + ICON_PROCESS_COMPLETED, + ICON_PROCESS_COMPLETED_SYMBOLIC, + ICON_PROCESS_ERROR_SYMBOLIC, + ICON_PROCESS_WORKING_SYMBOLIC, + ICON_RADIO_CHECKED_SYMBOLIC, + ICON_RADIO_MIXED_SYMBOLIC, + ICON_RADIO_SYMBOLIC, + ICON_ROTATION_ALLOWED_SYMBOLIC, + ICON_ROTATION_LOCKED_SYMBOLIC, + ICON_SECURITY_HIGH, + ICON_SECURITY_HIGH_SYMBOLIC, + ICON_SECURITY_LOW, + ICON_SECURITY_LOW_SYMBOLIC, + ICON_SECURITY_MEDIUM, + ICON_SECURITY_MEDIUM_SYMBOLIC, + ICON_SEMI_STARRED, + ICON_SEMI_STARRED_SYMBOLIC, + ICON_SOFTWARE_UPDATE_AVAILABLE_SYMBOLIC, + ICON_SOFTWARE_UPDATE_URGENT_SYMBOLIC, + ICON_STARRED, + ICON_STARRED_SYMBOLIC, + ICON_TASK_DUE_SYMBOLIC, + ICON_TASK_PAST_DUE_SYMBOLIC, + ICON_TOUCHPAD_DISABLED_SYMBOLIC, + ICON_USER_AVAILABLE, + ICON_USER_AVAILABLE_SYMBOLIC, + ICON_USER_AWAY, + ICON_USER_AWAY_SYMBOLIC, + ICON_USER_BUSY, + ICON_USER_BUSY_SYMBOLIC, + ICON_USER_IDLE_SYMBOLIC, + ICON_USER_INVISIBLE, + ICON_USER_INVISIBLE_SYMBOLIC, + ICON_USER_OFFLINE, + ICON_USER_OFFLINE_SYMBOLIC, + ICON_USER_STATUS_PENDING_SYMBOLIC, + ICON_USER_TRASH_FULL_SYMBOLIC, + ICON_USER_TYPING, + ICON_VIEW_PRIVATE, + ICON_VIEW_PRIVATE_SYMBOLIC, + ICON_VIEW_WRAPPED_SYMBOLIC, + ICON_WEATHER_CLEAR_NIGHT_SYMBOLIC, + ICON_WEATHER_CLEAR_SYMBOLIC, + ICON_WEATHER_FEW_CLOUDS_NIGHT_SYMBOLIC, + ICON_WEATHER_FEW_CLOUDS_SYMBOLIC, + ICON_WEATHER_FOG_NIGHT_SYMBOLIC, + ICON_WEATHER_FOG_SYMBOLIC, + ICON_WEATHER_OVERCAST_NIGHT_SYMBOLIC, + ICON_WEATHER_OVERCAST_SYMBOLIC, + ICON_WEATHER_SEVERE_ALERT_SYMBOLIC, + ICON_WEATHER_SHOWERS_NIGHT_SYMBOLIC, + ICON_WEATHER_SHOWERS_SCATTERED_NIGHT_SYMBOLIC, + ICON_WEATHER_SHOWERS_SCATTERED_SYMBOLIC, + ICON_WEATHER_SHOWERS_SYMBOLIC, + ICON_WEATHER_SNOW_NIGHT_SYMBOLIC, + ICON_WEATHER_SNOW_SYMBOLIC, + ICON_WEATHER_STORM_NIGHT_SYMBOLIC, + ICON_WEATHER_STORM_SYMBOLIC, + ICON_WEATHER_STORM_TORNADO_NIGHT_SYMBOLIC, + ICON_WEATHER_STORM_TORNADO_SYMBOLIC, + ICON_WEATHER_WINDY_SYMBOLIC, } -EsSyscallType :: enum { - ES_SYSCALL_ALLOCATE, - ES_SYSCALL_FREE, - ES_SYSCALL_SHARE_MEMORY, - ES_SYSCALL_MAP_OBJECT, - ES_SYSCALL_OPEN_SHARED_MEMORY, - ES_SYSCALL_CREATE_PROCESS, - ES_SYSCALL_GET_CREATION_ARGUMENT, - ES_SYSCALL_TERMINATE_THREAD, - ES_SYSCALL_CREATE_THREAD, - ES_SYSCALL_WAIT, - ES_SYSCALL_TERMINATE_PROCESS, - ES_SYSCALL_CREATE_EVENT, - ES_SYSCALL_SET_EVENT, - ES_SYSCALL_RESET_EVENT, - ES_SYSCALL_POLL_EVENT, - ES_SYSCALL_PAUSE_PROCESS, - ES_SYSCALL_CRASH_PROCESS, - ES_SYSCALL_GET_THREAD_ID, - ES_SYSCALL_GET_PROCESS_STATE, - ES_SYSCALL_YIELD_SCHEDULER, - ES_SYSCALL_SLEEP, - ES_SYSCALL_OPEN_PROCESS, - ES_SYSCALL_SET_TLS, - ES_SYSCALL_TIMER_SET, - ES_SYSCALL_TIMER_CREATE, - ES_SYSCALL_GET_PROCESS_STATUS, - ES_SYSCALL_CREATE_SURFACE, - ES_SYSCALL_GET_LINEAR_BUFFER, - ES_SYSCALL_INVALIDATE_RECTANGLE, - ES_SYSCALL_COPY_TO_SCREEN, - ES_SYSCALL_FORCE_SCREEN_UPDATE, - ES_SYSCALL_FILL_RECTANGLE, - ES_SYSCALL_COPY_SURFACE, - ES_SYSCALL_CLEAR_MODIFIED_REGION, - ES_SYSCALL_DRAW_SURFACE, - ES_SYSCALL_REDRAW_ALL, - ES_SYSCALL_DRAW_BOX, - ES_SYSCALL_DRAW_BITMAP, - ES_SYSCALL_SURFACE_RESET, - ES_SYSCALL_SURFACE_SHARE, - ES_SYSCALL_DRAW_STYLED_BOX, - ES_SYSCALL_SURFACE_SCROLL, - ES_SYSCALL_RESIZE_SURFACE, - ES_SYSCALL_GET_MESSAGE, - ES_SYSCALL_POST_MESSAGE, - ES_SYSCALL_POST_MESSAGE_REMOTE, - ES_SYSCALL_WAIT_MESSAGE, - ES_SYSCALL_CREATE_WINDOW, - ES_SYSCALL_UPDATE_WINDOW, - ES_SYSCALL_SET_CURSOR_STYLE, - ES_SYSCALL_MOVE_WINDOW, - ES_SYSCALL_GET_WINDOW_BOUNDS, - ES_SYSCALL_RESET_CLICK_CHAIN, - ES_SYSCALL_GET_CURSOR_POSITION, - ES_SYSCALL_SET_CURSOR_POSITION, - ES_SYSCALL_COPY, - ES_SYSCALL_GET_CLIPBOARD_HEADER, - ES_SYSCALL_PASTE_TEXT, - ES_SYSCALL_SET_FOCUSED_WINDOW, - ES_SYSCALL_SET_WINDOW_TITLE, - ES_SYSCALL_GET_SCREEN_BOUNDS, - ES_SYSCALL_WINDOW_OPEN, - ES_SYSCALL_WINDOW_SET_BLEND_BOUNDS, - ES_SYSCALL_WINDOW_GET_BLEND_BOUNDS, - ES_SYSCALL_WINDOW_GET_ID, - ES_SYSCALL_SET_WINDOW_ALPHA, - ES_SYSCALL_DOCKED_WINDOW_CREATE, - ES_SYSCALL_WINDOW_SHARE, - ES_SYSCALL_SET_EMBED_WINDOW, - ES_SYSCALL_OPEN_NODE, - ES_SYSCALL_READ_FILE_SYNC, - ES_SYSCALL_WRITE_FILE_SYNC, - ES_SYSCALL_RESIZE_FILE, - ES_SYSCALL_REFRESH_NODE_INFORMATION, - ES_SYSCALL_ENUMERATE_DIRECTORY_CHILDREN, - ES_SYSCALL_DELETE_NODE, - ES_SYSCALL_MOVE_NODE, - ES_SYSCALL_READ_CONSTANT_BUFFER, - ES_SYSCALL_SHARE_CONSTANT_BUFFER, - ES_SYSCALL_CREATE_CONSTANT_BUFFER, - ES_SYSCALL_EXECUTE, - ES_SYSCALL_INSTANCE_CREATE_REMOTE, - ES_SYSCALL_MAILSLOT_SEND_DATA, - ES_SYSCALL_MAILSLOT_SEND_MESSAGE, - ES_SYSCALL_MAILSLOT_SHARE, - ES_SYSCALL_PIPE_CREATE, - ES_SYSCALL_PIPE_WRITE, - ES_SYSCALL_PIPE_READ, - ES_SYSCALL_USER_GET_HOME_FOLDER, - ES_SYSCALL_USER_LOGIN, - ES_SYSCALL_GET_SYSTEM_CONSTANTS, - ES_SYSCALL_TAKE_SYSTEM_SNAPSHOT, - ES_SYSCALL_SET_SYSTEM_CONSTANT, - ES_SYSCALL_GET_SYSTEM_INFORMATION, - ES_SYSCALL_PRINT, - ES_SYSCALL_CLOSE_HANDLE, - ES_SYSCALL_BATCH, - ES_SYSCALL_SHUTDOWN, - ES_SYSCALL_POSIX, - ES_SYSCALL_COUNT, +FatalError :: enum { + FATAL_ERROR_INVALID_BUFFER, + FATAL_ERROR_UNKNOWN_SYSCALL, + FATAL_ERROR_INVALID_MEMORY_REGION, + FATAL_ERROR_MEMORY_REGION_LOCKED_BY_KERNEL, + FATAL_ERROR_PATH_LENGTH_EXCEEDS_LIMIT, + FATAL_ERROR_INVALID_HANDLE, + FATAL_ERROR_MUTEX_NOT_ACQUIRED_BY_THREAD, + FATAL_ERROR_MUTEX_ALREADY_ACQUIRED, + FATAL_ERROR_BUFFER_NOT_ACCESSIBLE, + FATAL_ERROR_SHARED_MEMORY_REGION_TOO_LARGE, + FATAL_ERROR_SHARED_MEMORY_STILL_MAPPED, + FATAL_ERROR_COULD_NOT_LOAD_FONT, + FATAL_ERROR_COULD_NOT_DRAW_FONT, + FATAL_ERROR_COULD_NOT_ALLOCATE_MEMORY, + FATAL_ERROR_INCORRECT_FILE_ACCESS, + FATAL_ERROR_TOO_MANY_WAIT_OBJECTS, + FATAL_ERROR_INCORRECT_NODE_TYPE, + FATAL_ERROR_PROCESSOR_EXCEPTION, + FATAL_ERROR_UNKNOWN, + FATAL_ERROR_RECURSIVE_BATCH, + FATAL_ERROR_CORRUPT_HEAP, + FATAL_ERROR_CORRUPT_LINKED_LIST, + FATAL_ERROR_INDEX_OUT_OF_BOUNDS, + FATAL_ERROR_INVALID_STRING_LENGTH, + FATAL_ERROR_SPINLOCK_NOT_ACQUIRED, + FATAL_ERROR_UNKNOWN_SNAPSHOT_TYPE, + FATAL_ERROR_PROCESS_ALREADY_ATTACHED, + FATAL_ERROR_INTERNAL, + FATAL_ERROR_INSUFFICIENT_PERMISSIONS, + FATAL_ERROR_ABORT, + FATAL_ERROR_COUNT, } -EsStandardFont :: enum { - ES_STANDARD_FONT_REGULAR, - ES_STANDARD_FONT_BOLD, - ES_STANDARD_FONT_MONOSPACED, +SyscallType :: enum { + SYSCALL_ALLOCATE, + SYSCALL_FREE, + SYSCALL_SHARE_MEMORY, + SYSCALL_MAP_OBJECT, + SYSCALL_OPEN_SHARED_MEMORY, + SYSCALL_CREATE_PROCESS, + SYSCALL_GET_CREATION_ARGUMENT, + SYSCALL_TERMINATE_THREAD, + SYSCALL_CREATE_THREAD, + SYSCALL_WAIT, + SYSCALL_TERMINATE_PROCESS, + SYSCALL_CREATE_EVENT, + SYSCALL_SET_EVENT, + SYSCALL_RESET_EVENT, + SYSCALL_POLL_EVENT, + SYSCALL_PAUSE_PROCESS, + SYSCALL_CRASH_PROCESS, + SYSCALL_GET_THREAD_ID, + SYSCALL_GET_PROCESS_STATE, + SYSCALL_YIELD_SCHEDULER, + SYSCALL_SLEEP, + SYSCALL_OPEN_PROCESS, + SYSCALL_SET_TLS, + SYSCALL_TIMER_SET, + SYSCALL_TIMER_CREATE, + SYSCALL_GET_PROCESS_STATUS, + SYSCALL_CREATE_SURFACE, + SYSCALL_GET_LINEAR_BUFFER, + SYSCALL_INVALIDATE_RECTANGLE, + SYSCALL_COPY_TO_SCREEN, + SYSCALL_FORCE_SCREEN_UPDATE, + SYSCALL_FILL_RECTANGLE, + SYSCALL_COPY_SURFACE, + SYSCALL_CLEAR_MODIFIED_REGION, + SYSCALL_DRAW_SURFACE, + SYSCALL_REDRAW_ALL, + SYSCALL_DRAW_BOX, + SYSCALL_DRAW_BITMAP, + SYSCALL_SURFACE_RESET, + SYSCALL_SURFACE_SHARE, + SYSCALL_DRAW_STYLED_BOX, + SYSCALL_SURFACE_SCROLL, + SYSCALL_RESIZE_SURFACE, + SYSCALL_GET_MESSAGE, + SYSCALL_POST_MESSAGE, + SYSCALL_POST_MESSAGE_REMOTE, + SYSCALL_WAIT_MESSAGE, + SYSCALL_CREATE_WINDOW, + SYSCALL_UPDATE_WINDOW, + SYSCALL_SET_CURSOR_STYLE, + SYSCALL_MOVE_WINDOW, + SYSCALL_GET_WINDOW_BOUNDS, + SYSCALL_RESET_CLICK_CHAIN, + SYSCALL_GET_CURSOR_POSITION, + SYSCALL_SET_CURSOR_POSITION, + SYSCALL_COPY, + SYSCALL_GET_CLIPBOARD_HEADER, + SYSCALL_PASTE_TEXT, + SYSCALL_SET_FOCUSED_WINDOW, + SYSCALL_SET_WINDOW_TITLE, + SYSCALL_GET_SCREEN_BOUNDS, + SYSCALL_WINDOW_OPEN, + SYSCALL_WINDOW_SET_BLEND_BOUNDS, + SYSCALL_WINDOW_GET_BLEND_BOUNDS, + SYSCALL_WINDOW_GET_ID, + SYSCALL_SET_WINDOW_ALPHA, + SYSCALL_DOCKED_WINDOW_CREATE, + SYSCALL_WINDOW_SHARE, + SYSCALL_SET_EMBED_WINDOW, + SYSCALL_OPEN_NODE, + SYSCALL_READ_FILE_SYNC, + SYSCALL_WRITE_FILE_SYNC, + SYSCALL_RESIZE_FILE, + SYSCALL_REFRESH_NODE_INFORMATION, + SYSCALL_ENUMERATE_DIRECTORY_CHILDREN, + SYSCALL_DELETE_NODE, + SYSCALL_MOVE_NODE, + SYSCALL_READ_CONSTANT_BUFFER, + SYSCALL_SHARE_CONSTANT_BUFFER, + SYSCALL_CREATE_CONSTANT_BUFFER, + SYSCALL_EXECUTE, + SYSCALL_INSTANCE_CREATE_REMOTE, + SYSCALL_MAILSLOT_SEND_DATA, + SYSCALL_MAILSLOT_SEND_MESSAGE, + SYSCALL_MAILSLOT_SHARE, + SYSCALL_PIPE_CREATE, + SYSCALL_PIPE_WRITE, + SYSCALL_PIPE_READ, + SYSCALL_USER_GET_HOME_FOLDER, + SYSCALL_USER_LOGIN, + SYSCALL_GET_SYSTEM_CONSTANTS, + SYSCALL_TAKE_SYSTEM_SNAPSHOT, + SYSCALL_SET_SYSTEM_CONSTANT, + SYSCALL_GET_SYSTEM_INFORMATION, + SYSCALL_PRINT, + SYSCALL_CLOSE_HANDLE, + SYSCALL_BATCH, + SYSCALL_SHUTDOWN, + SYSCALL_POSIX, + SYSCALL_COUNT, } -EsMessageType :: enum { - ES_MESSAGE_WM_START = 0x1000, - ES_MESSAGE_MOUSE_MOVED = 0x1001, - ES_MESSAGE_WINDOW_ACTIVATED = 0x1003, - ES_MESSAGE_WINDOW_DEACTIVATED = 0x1004, - ES_MESSAGE_WINDOW_DESTROYED = 0x1005, - ES_MESSAGE_MOUSE_EXIT = 0x1006 , - ES_MESSAGE_CLICK_REPEAT = 0x1009, - ES_MESSAGE_WINDOW_RESIZED = 0x100B, - ES_MESSAGE_MOUSE_LEFT_PRESSED = 0x100C , - ES_MESSAGE_MOUSE_LEFT_RELEASED = 0x100D, - ES_MESSAGE_MOUSE_RIGHT_PRESSED = 0x100E, - ES_MESSAGE_MOUSE_RIGHT_RELEASED = 0x100F, - ES_MESSAGE_MOUSE_MIDDLE_PRESSED = 0x1010, - ES_MESSAGE_MOUSE_MIDDLE_RELEASED = 0x1011 , - ES_MESSAGE_KEY_PRESSED = 0x1012, - ES_MESSAGE_KEY_RELEASED = 0x1013, - ES_MESSAGE_UPDATE_WINDOW = 0x1014, - ES_MESSAGE_WM_END = 0x13FF, - ES_MESSAGE_PAINT = 0x2000 , - ES_MESSAGE_DESTROY = 0x2001 , - ES_MESSAGE_MEASURE = 0x2002 , - ES_MESSAGE_SIZE = 0x2003 , - ES_MESSAGE_ADD_CHILD = 0x2004 , - ES_MESSAGE_REMOVE_CHILD = 0x2005 , - ES_MESSAGE_HIT_TEST = 0x2006 , - ES_MESSAGE_HOVERED_START = 0x2007 , - ES_MESSAGE_HOVERED_END = 0x2008 , - ES_MESSAGE_PRESSED_START = 0x2009 , - ES_MESSAGE_PRESSED_END = 0x200A , - ES_MESSAGE_FOCUSED_START = 0x200B , - ES_MESSAGE_FOCUSED_END = 0x200C , - ES_MESSAGE_FOCUS_WITHIN_START = 0x200D , - ES_MESSAGE_FOCUS_WITHIN_END = 0x200E , - ES_MESSAGE_Z_ORDER = 0x2010 , - ES_MESSAGE_ANIMATE = 0x2011 , - ES_MESSAGE_MOUSE_DRAGGED = 0x2012 , - ES_MESSAGE_KEY_TYPED = 0x2013 , - ES_MESSAGE_PAINT_BACKGROUND = 0x2014 , - ES_MESSAGE_PAINT_FOREGROUND = 0x2015 , - ES_MESSAGE_ENSURE_VISIBLE = 0x2016 , - ES_MESSAGE_GET_CURSOR = 0x2017 , - ES_MESSAGE_WINDOW_CREATED = 0x2018 , - ES_MESSAGE_CLICKED = 0x3000 , - ES_MESSAGE_SCROLLBAR_MOVED = 0x3001 , - ES_MESSAGE_RECALCULATE_CONTENT_SIZE = 0x3002 , - ES_MESSAGE_DESKTOP_EXECUTE = 0x4800, - ES_MESSAGE_POWER_BUTTON_PRESSED = 0x4801, - ES_MESSAGE_TASKBAR_WINDOW_ADD = 0x4804, - ES_MESSAGE_TASKBAR_WINDOW_REMOVE = 0x4805, - ES_MESSAGE_TASKBAR_WINDOW_ACTIVATE = 0x4806, - ES_MESSAGE_TASKBAR_WINDOW_SET_TITLE = 0x4807, - ES_MESSAGE_DOCKED_WINDOW_CREATE = 0x4808, - ES_MESSAGE_PROGRAM_CRASH = 0x4C00, - ES_MESSAGE_PROGRAM_FAILED_TO_START = 0x4C01, - ES_MESSAGE_RECEIVE_DATA = 0x5100, - ES_MESSAGE_MAILSLOT_CLOSED = 0x5101, - ES_MESSAGE_CLIPBOARD_UPDATED = 0x5001, - ES_MESSAGE_SYSTEM_CONSTANT_UPDATED = 0x5004, - ES_MESSAGE_TIMER = 0x5006, - ES_MESSAGE_OBJECT_DESTROY = 0x5007, - ES_MESSAGE_LIST_VIEW_GET_ITEM_CONTENT = 0x6000, - ES_MESSAGE_LIST_VIEW_SET_ITEM_STATE = 0x6001, - ES_MESSAGE_LIST_VIEW_GET_ITEM_STATE = 0x6002, - ES_MESSAGE_LIST_VIEW_PAINT_ITEM = 0x6003 , - ES_MESSAGE_LIST_VIEW_PAINT_CELL = 0x6004 , - ES_MESSAGE_LIST_VIEW_SORT_COLUMN = 0x6005, - ES_MESSAGE_LIST_VIEW_CHOOSE_ITEM = 0x6006, - ES_MESSAGE_LIST_VIEW_FIND_ITEM = 0x6007, - ES_MESSAGE_LIST_VIEW_TOGGLE_DISCLOSURE = 0x6008, - ES_MESSAGE_LIST_VIEW_MEASURE_ITEM_HEIGHT = 0x6009, - ES_MESSAGE_LIST_VIEW_LAYOUT_ITEM = 0x600A, - ES_MESSAGE_LIST_VIEW_SET_ITEM_VISIBILITY = 0x600B, - ES_MESSAGE_LIST_VIEW_RELAY_MESSAGE = 0x600C, - ES_MESSAGE_LIST_VIEW_SET_ITEM_POSITION = 0x600D, - ES_MESSAGE_USER_START = 0x8000, - ES_MESSAGE_USER_END = 0xBFFF, +StandardFont :: enum { + STANDARD_FONT_REGULAR, + STANDARD_FONT_BOLD, + STANDARD_FONT_MONOSPACED, } -EsDrawMode :: enum { - ES_DRAW_MODE_REPEAT_FIRST = 1 , - ES_DRAW_MODE_STRECH, - ES_DRAW_MODE_REPEAT, - ES_DRAW_MODE_NONE, +MessageType :: enum { + MESSAGE_WM_START = 0x1000, + MESSAGE_MOUSE_MOVED = 0x1001, + MESSAGE_WINDOW_ACTIVATED = 0x1003, + MESSAGE_WINDOW_DEACTIVATED = 0x1004, + MESSAGE_WINDOW_DESTROYED = 0x1005, + MESSAGE_MOUSE_EXIT = 0x1006 , + MESSAGE_CLICK_REPEAT = 0x1009, + MESSAGE_WINDOW_RESIZED = 0x100B, + MESSAGE_MOUSE_LEFT_PRESSED = 0x100C , + MESSAGE_MOUSE_LEFT_RELEASED = 0x100D, + MESSAGE_MOUSE_RIGHT_PRESSED = 0x100E, + MESSAGE_MOUSE_RIGHT_RELEASED = 0x100F, + MESSAGE_MOUSE_MIDDLE_PRESSED = 0x1010, + MESSAGE_MOUSE_MIDDLE_RELEASED = 0x1011 , + MESSAGE_KEY_PRESSED = 0x1012, + MESSAGE_KEY_RELEASED = 0x1013, + MESSAGE_UPDATE_WINDOW = 0x1014, + MESSAGE_WM_END = 0x13FF, + MESSAGE_PAINT = 0x2000 , + MESSAGE_DESTROY = 0x2001 , + MESSAGE_MEASURE = 0x2002 , + MESSAGE_SIZE = 0x2003 , + MESSAGE_ADD_CHILD = 0x2004 , + MESSAGE_REMOVE_CHILD = 0x2005 , + MESSAGE_HIT_TEST = 0x2006 , + MESSAGE_HOVERED_START = 0x2007 , + MESSAGE_HOVERED_END = 0x2008 , + MESSAGE_PRESSED_START = 0x2009 , + MESSAGE_PRESSED_END = 0x200A , + MESSAGE_FOCUSED_START = 0x200B , + MESSAGE_FOCUSED_END = 0x200C , + MESSAGE_FOCUS_WITHIN_START = 0x200D , + MESSAGE_FOCUS_WITHIN_END = 0x200E , + MESSAGE_Z_ORDER = 0x2010 , + MESSAGE_ANIMATE = 0x2011 , + MESSAGE_MOUSE_DRAGGED = 0x2012 , + MESSAGE_KEY_TYPED = 0x2013 , + MESSAGE_PAINT_BACKGROUND = 0x2014 , + MESSAGE_PAINT_FOREGROUND = 0x2015 , + MESSAGE_ENSURE_VISIBLE = 0x2016 , + MESSAGE_GET_CURSOR = 0x2017 , + MESSAGE_WINDOW_CREATED = 0x2018 , + MESSAGE_CLICKED = 0x3000 , + MESSAGE_SCROLLBAR_MOVED = 0x3001 , + MESSAGE_RECALCULATE_CONTENT_SIZE = 0x3002 , + MESSAGE_TEXTBOX_UPDATED = 0x3003 , + MESSAGE_DESKTOP_EXECUTE = 0x4800, + MESSAGE_POWER_BUTTON_PRESSED = 0x4801, + MESSAGE_TASKBAR_WINDOW_ADD = 0x4804, + MESSAGE_TASKBAR_WINDOW_REMOVE = 0x4805, + MESSAGE_TASKBAR_WINDOW_ACTIVATE = 0x4806, + MESSAGE_TASKBAR_WINDOW_SET_TITLE = 0x4807, + MESSAGE_DOCKED_WINDOW_CREATE = 0x4808, + MESSAGE_PROGRAM_CRASH = 0x4C00, + MESSAGE_PROGRAM_FAILED_TO_START = 0x4C01, + MESSAGE_RECEIVE_DATA = 0x5100, + MESSAGE_MAILSLOT_CLOSED = 0x5101, + MESSAGE_CLIPBOARD_UPDATED = 0x5001, + MESSAGE_SYSTEM_CONSTANT_UPDATED = 0x5004, + MESSAGE_TIMER = 0x5006, + MESSAGE_OBJECT_DESTROY = 0x5007, + MESSAGE_LIST_VIEW_GET_ITEM_CONTENT = 0x6000, + MESSAGE_LIST_VIEW_SET_ITEM_STATE = 0x6001, + MESSAGE_LIST_VIEW_GET_ITEM_STATE = 0x6002, + MESSAGE_LIST_VIEW_PAINT_ITEM = 0x6003 , + MESSAGE_LIST_VIEW_PAINT_CELL = 0x6004 , + MESSAGE_LIST_VIEW_SORT_COLUMN = 0x6005, + MESSAGE_LIST_VIEW_CHOOSE_ITEM = 0x6006, + MESSAGE_LIST_VIEW_FIND_ITEM = 0x6007, + MESSAGE_LIST_VIEW_TOGGLE_DISCLOSURE = 0x6008, + MESSAGE_LIST_VIEW_MEASURE_ITEM_HEIGHT = 0x6009, + MESSAGE_LIST_VIEW_LAYOUT_ITEM = 0x600A, + MESSAGE_LIST_VIEW_SET_ITEM_VISIBILITY = 0x600B, + MESSAGE_LIST_VIEW_RELAY_MESSAGE = 0x600C, + MESSAGE_LIST_VIEW_SET_ITEM_POSITION = 0x600D, + MESSAGE_PROGRAM_START = 0x7000, + MESSAGE_PROGRAM_EXIT = 0x7001, + MESSAGE_USER_START = 0x8000, + MESSAGE_USER_END = 0xBFFF, } -EsClipboardFormat :: enum { - ES_CLIPBOARD_FORMAT_EMPTY, - ES_CLIPBOARD_FORMAT_TEXT, - ES_CLIPBOARD_FORMAT_FILE_LIST, +DrawMode :: enum { + DRAW_MODE_REPEAT_FIRST = 1 , + DRAW_MODE_STRECH, + DRAW_MODE_REPEAT, + DRAW_MODE_NONE, } -EsColorFormat :: enum { - ES_COLOR_FORMAT_32_XRGB, +ClipboardFormat :: enum { + CLIPBOARD_FORMAT_EMPTY, + CLIPBOARD_FORMAT_TEXT, + CLIPBOARD_FORMAT_FILE_LIST, } -EsCursorStyle :: enum { - ES_CURSOR_NORMAL, - ES_CURSOR_TEXT, - ES_CURSOR_RESIZE_VERTICAL, - ES_CURSOR_RESIZE_HORIZONTAL, - ES_CURSOR_RESIZE_DIAGONAL_1, - ES_CURSOR_RESIZE_DIAGONAL_2, - ES_CURSOR_SPLIT_VERTICAL, - ES_CURSOR_SPLIT_HORIZONTAL, - ES_CURSOR_HAND_HOVER, - ES_CURSOR_HAND_DRAG, - ES_CURSOR_HAND_POINT, - ES_CURSOR_SCROLL_UP_LEFT, - ES_CURSOR_SCROLL_UP, - ES_CURSOR_SCROLL_UP_RIGHT, - ES_CURSOR_SCROLL_LEFT, - ES_CURSOR_SCROLL_CENTER, - ES_CURSOR_SCROLL_RIGHT, - ES_CURSOR_SCROLL_DOWN_LEFT, - ES_CURSOR_SCROLL_DOWN, - ES_CURSOR_SCROLL_DOWN_RIGHT, - ES_CURSOR_SELECT_LINES, - ES_CURSOR_DROP_TEXT, - ES_CURSOR_CROSS_HAIR_PICK, - ES_CURSOR_CROSS_HAIR_RESIZE, - ES_CURSOR_MOVE_HOVER, - ES_CURSOR_MOVE_DRAG, - ES_CURSOR_ROTATE_HOVER, - ES_CURSOR_ROTATE_DRAG, - ES_CURSOR_BLANK, +ColorFormat :: enum { + COLOR_FORMAT_32_XRGB, } -EsWindowStyle :: enum { - ES_WINDOW_NORMAL, - ES_WINDOW_CONTAINER, - ES_WINDOW_MENU, +CursorStyle :: enum { + CURSOR_NORMAL, + CURSOR_TEXT, + CURSOR_RESIZE_VERTICAL, + CURSOR_RESIZE_HORIZONTAL, + CURSOR_RESIZE_DIAGONAL_1, + CURSOR_RESIZE_DIAGONAL_2, + CURSOR_SPLIT_VERTICAL, + CURSOR_SPLIT_HORIZONTAL, + CURSOR_HAND_HOVER, + CURSOR_HAND_DRAG, + CURSOR_HAND_POINT, + CURSOR_SCROLL_UP_LEFT, + CURSOR_SCROLL_UP, + CURSOR_SCROLL_UP_RIGHT, + CURSOR_SCROLL_LEFT, + CURSOR_SCROLL_CENTER, + CURSOR_SCROLL_RIGHT, + CURSOR_SCROLL_DOWN_LEFT, + CURSOR_SCROLL_DOWN, + CURSOR_SCROLL_DOWN_RIGHT, + CURSOR_SELECT_LINES, + CURSOR_DROP_TEXT, + CURSOR_CROSS_HAIR_PICK, + CURSOR_CROSS_HAIR_RESIZE, + CURSOR_MOVE_HOVER, + CURSOR_MOVE_DRAG, + CURSOR_ROTATE_HOVER, + CURSOR_ROTATE_DRAG, + CURSOR_BLANK, } -ES_NODE_FILE :: (0); -ES_NODE_DIRECTORY :: (0x4000); -ES_NODE_INVALID :: (0x8000); -EsBatchCall :: struct { - index :EsSyscallType, +WindowStyle :: enum { + WINDOW_NORMAL, + WINDOW_CONTAINER, + WINDOW_MENU, +} + +NODE_FILE :: (0); +NODE_DIRECTORY :: (0x4000); +NODE_INVALID :: (0x8000); +BatchCall :: struct { + index :SyscallType, stopBatchIfError :bool, using _ : struct #raw_union { argument0 :uintptr, @@ -652,60 +1727,57 @@ EsBatchCall :: struct { argument3 :uintptr, } -EsThreadInformation :: struct { - handle :EsHandle, +ThreadInformation :: struct { + handle :Handle, tid :uintptr, } -EsProcessInformation :: struct { - handle :EsHandle, +ProcessInformation :: struct { + handle :Handle, pid :uintptr, - mainThread :EsThreadInformation, + mainThread :ThreadInformation, } -EsUniqueIdentifier :: struct { +UniqueIdentifier :: struct { using _ : struct #raw_union { d :[16]u8, }, } -EsNodeInformation :: struct { - handle :EsHandle, - type :EsNodeType, - using _ : struct #raw_union { - fileSize :EsFileOffset, - directoryChildren :EsFileOffset, - }, - +NodeInformation :: struct { + handle :Handle, + type :NodeType, + fileSize :FileOffset, + directoryChildren :FileOffset, } -EsDirectoryChild :: struct { - name :[ES_MAX_DIRECTORY_CHILD_NAME_LENGTH]i8, +DirectoryChild :: struct { + name :[MAX_DIRECTORY_CHILD_NAME_LENGTH]i8, nameBytes :uintptr, - information :EsNodeInformation, + information :NodeInformation, } -EsPoint :: struct { +Point :: struct { x :i32, y :i32, } -EsRectangle :: struct { +Rectangle :: struct { left :i32, right :i32, top :i32, bottom :i32, } -EsRectangle16 :: struct { +Rectangle16 :: struct { left :i16, right :i16, top :i16, bottom :i16, } -EsColor :: struct { +Color :: struct { using _ : struct #raw_union { using _ : struct { blue :u8, @@ -718,97 +1790,97 @@ EsColor :: struct { } -EsLinearBuffer :: struct { +LinearBuffer :: struct { width :uintptr, height :uintptr, stride :uintptr, - colorFormat :EsColorFormat, - handle :EsHandle, - flags :u32, + colorFormat :ColorFormat, + handle :Handle, } -_EsRectangleAndColor :: struct { - rectangle :EsRectangle, - color :EsColor, +RectangleAndColor :: struct { + rectangle :Rectangle, + color :Color, } -_EsStyledBoxData :: struct { +StyledBoxData :: struct { backgroundColor :u32, borderColor :u32, - borderSize :u8, + borders :Rectangle16, cornerRadius :u8, roundedCornersToExclude :u8, ox :i32, oy :i32, width :i32, height :i32, - clip :EsRectangle, + clip :Rectangle, } -_EsInstanceCreateRemoteArguments :: struct { +InstanceCreateRemoteArguments :: struct { what :^i8, argument :^i8, whatBytes :uintptr, argumentBytes :uintptr, - modalWindowParent :EsHandle, + modalWindowParent :Handle, apiInstance :^rawptr, } -_EsDrawSurfaceArguments :: struct { - source :EsRectangle, - destination :EsRectangle, - border :EsRectangle, +DrawSurfaceArguments :: struct { + source :Rectangle, + destination :Rectangle, + border :Rectangle, alpha :u16, } -EsSpinlock :: struct { +Spinlock :: struct { state :u8, } -EsMutex :: struct { - event :EsHandle, - spinlock :EsSpinlock, +Mutex :: struct { + event :Handle, + spinlock :Spinlock, state :u8, queued :u32, } -EsCrashReason :: struct { - errorCode :EsError, +CrashReason :: struct { + errorCode :Error, } -EsProcessState :: struct { - crashReason :EsCrashReason, - creationArgument :EsGeneric, +ProcessState :: struct { + crashReason :CrashReason, + creationArgument :Generic, id :uintptr, executableState :uintptr, flags :u8, } -EsIORequestProgress :: struct { - accessed :EsFileOffset, - progress :EsFileOffset, +IORequestProgress :: struct { + accessed :FileOffset, + progress :FileOffset, completed :bool, cancelled :bool, - error :EsError, + error :Error, } -EsClipboardHeader :: struct { +ClipboardHeader :: struct { customBytes :uintptr, - format :EsClipboardFormat, + format :ClipboardFormat, textBytes :uintptr, unused :uintptr, } -EsPainter :: struct { - surface :EsHandle, - clip :EsRectangle, +Painter :: struct { + surface :Handle, + clip :Rectangle, offsetX :i32, offsetY :i32, + fullAlpha :bool, } -EsMessage :: struct { - type :EsMessageType, - _context :EsGeneric, +Message :: struct { + type :MessageType, + _context :Generic, using _ : struct #raw_union { _argument :^rawptr, mouseMoved : struct { @@ -847,20 +1919,20 @@ EsMessage :: struct { ctrl :u8, shift :u8, numpad :u8, - notHandledBy :EsObject, + notHandledBy :Object, }, crash : struct { - reason :EsCrashReason, - process :EsHandle, - processNameBuffer :EsHandle, + reason :CrashReason, + process :Handle, + processNameBuffer :Handle, processNameBytes :uintptr, pid :uintptr, }, - clipboard :EsClipboardHeader, + clipboard :ClipboardHeader, receive : struct { - buffer :EsHandle, + buffer :Handle, bytes :uintptr, }, @@ -876,35 +1948,35 @@ EsMessage :: struct { }, desktopExecute : struct { - whatBuffer :EsHandle, - argumentBuffer :EsHandle, - mailslot :EsHandle, + whatBuffer :Handle, + argumentBuffer :Handle, + mailslot :Handle, whatBytes :uintptr, argumentBytes :uintptr, modalWindowParent :u64, }, dockedWindowCreate : struct { - pipe :EsHandle, + pipe :Handle, }, taskbar : struct { id :u64, - buffer :EsHandle, + buffer :Handle, bytes :uintptr, }, windowResized : struct { - content :EsRectangle, + content :Rectangle, }, - painter :^EsPainter, + painter :^Painter, measure : struct { width :i32, height :i32, }, - child :EsObject, + child :Object, size : struct { width :i32, height :i32, @@ -918,7 +1990,7 @@ EsMessage :: struct { zOrder : struct { index :uintptr, - child :^EsElement, + child :^Element, }, scrollbarMoved : struct { @@ -926,20 +1998,19 @@ EsMessage :: struct { }, ensureVisible : struct { - child :^EsElement, + child :^Element, }, - cursorStyle :EsCursorStyle, + cursorStyle :CursorStyle, getItemContent : struct { mask :u32, - index :EsListViewIndex, - column :EsListViewIndex, - group :EsListViewIndex, + index :ListViewIndex, + column :ListViewIndex, + group :ListViewIndex, text :^i8, textBytes :uintptr, - iconHash :u32, - iconWidth :u16, - iconHeight :u16, + iconID :u16, + iconSize :u16, indentation :u16, spaceAfterIcon :u16, }, @@ -947,39 +2018,39 @@ EsMessage :: struct { accessItemState : struct { mask :u32, state :u32, - iIndexFrom :EsListViewIndex, - eIndexTo :EsListViewIndex, - group :EsListViewIndex, + iIndexFrom :ListViewIndex, + eIndexTo :ListViewIndex, + group :ListViewIndex, }, measureItemHeight : struct { - iIndexFrom :EsListViewIndex, - eIndexTo :EsListViewIndex, - group :EsListViewIndex, + iIndexFrom :ListViewIndex, + eIndexTo :ListViewIndex, + group :ListViewIndex, height :i32, }, layoutItem : struct { - index :EsListViewIndex, - group :EsListViewIndex, - knownIndex :EsListViewIndex, - knownGroup :EsListViewIndex, - bounds :EsRectangle, + index :ListViewIndex, + group :ListViewIndex, + knownIndex :ListViewIndex, + knownGroup :ListViewIndex, + bounds :Rectangle, }, toggleItemDisclosure : struct { - index :EsListViewIndex, - group :EsListViewIndex, + index :ListViewIndex, + group :ListViewIndex, }, findItem : struct { type :u8, backwards :u8, inclusive :bool, - indexFrom :EsListViewIndex, - groupFrom :EsListViewIndex, - foundIndex :EsListViewIndex, - foundGroup :EsListViewIndex, + indexFrom :ListViewIndex, + groupFrom :ListViewIndex, + foundIndex :ListViewIndex, + foundGroup :ListViewIndex, using _ : struct #raw_union { using _ : struct { prefix :^i8, @@ -997,58 +2068,57 @@ EsMessage :: struct { }, listViewColumn : struct { - index :EsListViewIndex, + index :ListViewIndex, descending :bool, }, setItemVisibility : struct { - index :EsListViewIndex, - group :EsListViewIndex, + index :ListViewIndex, + group :ListViewIndex, visible :bool, }, setItemPosition : struct { - index :EsListViewIndex, - group :EsListViewIndex, - bounds :EsRectangle, + index :ListViewIndex, + group :ListViewIndex, + bounds :Rectangle, }, listViewPaint : struct { - surface :EsHandle, - bounds :EsRectangle, - clip :EsRectangle, - index :EsListViewIndex, - group :EsListViewIndex, - column :EsListViewIndex, - _internal :^rawptr, + painter :^Painter, + width :i32, + height :i32, + index :ListViewIndex, + group :ListViewIndex, + column :ListViewIndex, }, }, } -EsDebuggerMessage :: struct { - process :EsHandle, - reason :EsCrashReason, +DebuggerMessage :: struct { + process :Handle, + reason :CrashReason, } -EsDriveInformation :: struct { +DriveInformation :: struct { name :[64]i8, nameBytes :uintptr, mountpoint :[256]i8, mountpointBytes :uintptr, } -EsSnapshotProcessesItem :: struct { +SnapshotProcessesItem :: struct { pid :i64, memoryUsage :i64, cpuTimeSlices :i64, - name :[ES_SNAPSHOT_MAX_PROCESS_NAME_LENGTH]i8, + name :[SNAPSHOT_MAX_PROCESS_NAME_LENGTH]i8, nameLength :uintptr, internal :u64, } -EsSystemInformation :: struct { +SystemInformation :: struct { processCount :uintptr, threadCount :uintptr, handleCount :uintptr, @@ -1067,37 +2137,37 @@ EsSystemInformation :: struct { kernelRegions :uintptr, } -EsSnapshotProcesses :: struct { +SnapshotProcesses :: struct { count :uintptr, - processes :[]EsSnapshotProcessesItem, + processes :[]SnapshotProcessesItem, } -_EsPOSIXSyscall :: struct { +POSIXSyscall :: struct { index :int, arguments :[7]int, } -EsProcessCreationArguments :: struct { +ProcessCreationArguments :: struct { executablePath :^i8, executablePathBytes :uintptr, environmentBlock :^rawptr, environmentBlockBytes :uintptr, - creationArgument :EsGeneric, + creationArgument :Generic, permissions :u64, } -_EsUserLoginArguments :: struct { +UserLoginArguments :: struct { name :^i8, nameBytes :uintptr, home :^i8, homeBytes :uintptr, } -EsInstance :: struct { +Instance :: struct { _private :^rawptr, } -EsListViewColumn :: struct { +ListViewColumn :: struct { title :^i8, titleBytes :uintptr, width :i32, @@ -1105,193 +2175,207 @@ EsListViewColumn :: struct { flags :u32, } -EsListViewStyle :: struct { - flags :u32, +ListViewStyle :: struct { fixedWidth :i32, fixedHeight :i32, groupHeaderHeight :i32, gapX :i32, gapY :i32, - margin :EsRectangle16, - columns :^EsListViewColumn, + margin :Rectangle16, + columns :^ListViewColumn, columnCount :uintptr, emptyMessage :^i8, emptyMessageBytes :uintptr, } -EsBatch :: inline proc (calls :^EsBatchCall, count :uintptr){ ((proc (^EsBatchCall, uintptr))(rawptr(uintptr(0x1000 + 0 * size_of(int)))))(calls, count); } -EsProcessCreate :: inline proc (executablePath :^i8, executablePathLength :uintptr, information :^EsProcessInformation, argument :EsGeneric) -> EsError{ return ((proc (^i8, uintptr, ^EsProcessInformation, EsGeneric) -> EsError)(rawptr(uintptr(0x1000 + 1 * size_of(int)))))(executablePath, executablePathLength, information, argument); } -EsThreadCreate :: inline proc (entryFunction :EsThreadEntryFunction, information :^EsThreadInformation, argument :EsGeneric) -> EsError{ return ((proc (EsThreadEntryFunction, ^EsThreadInformation, EsGeneric) -> EsError)(rawptr(uintptr(0x1000 + 2 * size_of(int)))))(entryFunction, information, argument); } -EsSurfaceCreate :: inline proc (width :uintptr, height :uintptr, flags :u32) -> EsHandle{ return ((proc (uintptr, uintptr, u32) -> EsHandle)(rawptr(uintptr(0x1000 + 3 * size_of(int)))))(width, height, flags); } -EsEventCreate :: inline proc (autoReset :bool) -> EsHandle{ return ((proc (bool) -> EsHandle)(rawptr(uintptr(0x1000 + 4 * size_of(int)))))(autoReset); } -EsThreadLocalStorageSetAddress :: inline proc (address :^rawptr){ ((proc (^rawptr))(rawptr(uintptr(0x1000 + 5 * size_of(int)))))(address); } -EsConstantBufferRead :: inline proc (constantBuffer :EsHandle, output :^rawptr){ ((proc (EsHandle, ^rawptr))(rawptr(uintptr(0x1000 + 6 * size_of(int)))))(constantBuffer, output); } -EsConstantBufferShare :: inline proc (constantBuffer :EsHandle, targetProcess :EsHandle) -> EsHandle{ return ((proc (EsHandle, EsHandle) -> EsHandle)(rawptr(uintptr(0x1000 + 7 * size_of(int)))))(constantBuffer, targetProcess); } -EsConstantBufferCreate :: inline proc (data :^rawptr, dataBytes :uintptr, targetProcess :EsHandle) -> EsHandle{ return ((proc (^rawptr, uintptr, EsHandle) -> EsHandle)(rawptr(uintptr(0x1000 + 8 * size_of(int)))))(data, dataBytes, targetProcess); } -EsProcessOpen :: inline proc (pid :u64) -> EsHandle{ return ((proc (u64) -> EsHandle)(rawptr(uintptr(0x1000 + 9 * size_of(int)))))(pid); } -EsHandleClose :: inline proc (handle :EsHandle) -> EsError{ return ((proc (EsHandle) -> EsError)(rawptr(uintptr(0x1000 + 10 * size_of(int)))))(handle); } -EsTakeSystemSnapshot :: inline proc (type :i32, bufferSize :^uintptr) -> EsHandle{ return ((proc (i32, ^uintptr) -> EsHandle)(rawptr(uintptr(0x1000 + 11 * size_of(int)))))(type, bufferSize); } -EsGetSystemInformation :: inline proc (systemInformation :^EsSystemInformation){ ((proc (^EsSystemInformation))(rawptr(uintptr(0x1000 + 12 * size_of(int)))))(systemInformation); } -EsNodeOpen :: inline proc (path :^i8, pathLength :uintptr, flags :u64, information :^EsNodeInformation) -> EsError{ return ((proc (^i8, uintptr, u64, ^EsNodeInformation) -> EsError)(rawptr(uintptr(0x1000 + 13 * size_of(int)))))(path, pathLength, flags, information); } -EsNodeFindUniqueName :: inline proc (buffer :^i8, originalBytes :uintptr, bufferBytes :uintptr) -> uintptr{ return ((proc (^i8, uintptr, uintptr) -> uintptr)(rawptr(uintptr(0x1000 + 14 * size_of(int)))))(buffer, originalBytes, bufferBytes); } -EsFileReadAll :: inline proc (filePath :^i8, filePathLength :uintptr, fileSize :^uintptr){ ((proc (^i8, uintptr, ^uintptr))(rawptr(uintptr(0x1000 + 15 * size_of(int)))))(filePath, filePathLength, fileSize); } -EsFileReadSync :: inline proc (file :EsHandle, offset :EsFileOffset, size :uintptr, buffer :^rawptr) -> uintptr{ return ((proc (EsHandle, EsFileOffset, uintptr, ^rawptr) -> uintptr)(rawptr(uintptr(0x1000 + 16 * size_of(int)))))(file, offset, size, buffer); } -EsFileWriteSync :: inline proc (file :EsHandle, offset :EsFileOffset, size :uintptr, buffer :^rawptr) -> uintptr{ return ((proc (EsHandle, EsFileOffset, uintptr, ^rawptr) -> uintptr)(rawptr(uintptr(0x1000 + 17 * size_of(int)))))(file, offset, size, buffer); } -EsFileResize :: inline proc (file :EsHandle, newSize :EsFileOffset) -> EsError{ return ((proc (EsHandle, EsFileOffset) -> EsError)(rawptr(uintptr(0x1000 + 18 * size_of(int)))))(file, newSize); } -EsNodeRefreshInformation :: inline proc (information :^EsNodeInformation){ ((proc (^EsNodeInformation))(rawptr(uintptr(0x1000 + 19 * size_of(int)))))(information); } -EsDirectoryEnumerateChildren :: inline proc (directory :EsHandle, buffer :^EsDirectoryChild, bufferCount :uintptr) -> int{ return ((proc (EsHandle, ^EsDirectoryChild, uintptr) -> int)(rawptr(uintptr(0x1000 + 20 * size_of(int)))))(directory, buffer, bufferCount); } -EsNodeDelete :: inline proc (node :EsHandle) -> EsError{ return ((proc (EsHandle) -> EsError)(rawptr(uintptr(0x1000 + 21 * size_of(int)))))(node); } -EsNodeMove :: inline proc (node :EsHandle, newDirectory :EsHandle, newName :^i8, newNameLength :uintptr) -> EsError{ return ((proc (EsHandle, EsHandle, ^i8, uintptr) -> EsError)(rawptr(uintptr(0x1000 + 22 * size_of(int)))))(node, newDirectory, newName, newNameLength); } -EsThreadTerminate :: inline proc (thread :EsHandle){ ((proc (EsHandle))(rawptr(uintptr(0x1000 + 23 * size_of(int)))))(thread); } -EsProcessTerminate :: inline proc (process :EsHandle, status :i32){ ((proc (EsHandle, i32))(rawptr(uintptr(0x1000 + 24 * size_of(int)))))(process, status); } -EsProcessTerminateCurrent :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 25 * size_of(int)))))(); } -EsProcessPause :: inline proc (process :EsHandle, resume :bool){ ((proc (EsHandle, bool))(rawptr(uintptr(0x1000 + 26 * size_of(int)))))(process, resume); } -EsProcessCrash :: inline proc (error :EsError, message :^i8, messageBytes :uintptr){ ((proc (EsError, ^i8, uintptr))(rawptr(uintptr(0x1000 + 27 * size_of(int)))))(error, message, messageBytes); } -EsThreadGetID :: inline proc (thread :EsHandle) -> uintptr{ return ((proc (EsHandle) -> uintptr)(rawptr(uintptr(0x1000 + 28 * size_of(int)))))(thread); } -EsProcessGetID :: inline proc (process :EsHandle) -> uintptr{ return ((proc (EsHandle) -> uintptr)(rawptr(uintptr(0x1000 + 29 * size_of(int)))))(process); } -EsSpinlockRelease :: inline proc (spinlock :^EsSpinlock){ ((proc (^EsSpinlock))(rawptr(uintptr(0x1000 + 30 * size_of(int)))))(spinlock); } -EsSpinlockAcquire :: inline proc (spinlock :^EsSpinlock){ ((proc (^EsSpinlock))(rawptr(uintptr(0x1000 + 31 * size_of(int)))))(spinlock); } -EsMutexRelease :: inline proc (mutex :^EsMutex){ ((proc (^EsMutex))(rawptr(uintptr(0x1000 + 32 * size_of(int)))))(mutex); } -EsMutexAcquire :: inline proc (mutex :^EsMutex){ ((proc (^EsMutex))(rawptr(uintptr(0x1000 + 33 * size_of(int)))))(mutex); } -EsMutexDestroy :: inline proc (mutex :^EsMutex){ ((proc (^EsMutex))(rawptr(uintptr(0x1000 + 34 * size_of(int)))))(mutex); } -EsSchedulerYield :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 35 * size_of(int)))))(); } -EsEventSet :: inline proc (event :EsHandle){ ((proc (EsHandle))(rawptr(uintptr(0x1000 + 36 * size_of(int)))))(event); } -EsEventReset :: inline proc (event :EsHandle){ ((proc (EsHandle))(rawptr(uintptr(0x1000 + 37 * size_of(int)))))(event); } -EsEventPoll :: inline proc (event :EsHandle) -> EsError{ return ((proc (EsHandle) -> EsError)(rawptr(uintptr(0x1000 + 38 * size_of(int)))))(event); } -EsWait :: inline proc (objects :^EsHandle, objectCount :uintptr, timeoutMs :uintptr) -> uintptr{ return ((proc (^EsHandle, uintptr, uintptr) -> uintptr)(rawptr(uintptr(0x1000 + 39 * size_of(int)))))(objects, objectCount, timeoutMs); } -EsSleep :: inline proc (milliseconds :u64){ ((proc (u64))(rawptr(uintptr(0x1000 + 40 * size_of(int)))))(milliseconds); } -EsMemoryOpen :: inline proc (size :uintptr, name :^i8, nameLength :uintptr, flags :u32) -> EsHandle{ return ((proc (uintptr, ^i8, uintptr, u32) -> EsHandle)(rawptr(uintptr(0x1000 + 41 * size_of(int)))))(size, name, nameLength, flags); } -EsMemoryShare :: inline proc (sharedMemoryRegion :EsHandle, targetProcess :EsHandle, readOnly :bool) -> EsHandle{ return ((proc (EsHandle, EsHandle, bool) -> EsHandle)(rawptr(uintptr(0x1000 + 42 * size_of(int)))))(sharedMemoryRegion, targetProcess, readOnly); } -EsObjectMap :: inline proc (object :EsHandle, offset :uintptr, size :uintptr, flags :u32){ ((proc (EsHandle, uintptr, uintptr, u32))(rawptr(uintptr(0x1000 + 43 * size_of(int)))))(object, offset, size, flags); } -EsMemoryAllocate :: inline proc (size :uintptr){ ((proc (uintptr))(rawptr(uintptr(0x1000 + 44 * size_of(int)))))(size); } -EsMemoryFree :: inline proc (address :^rawptr) -> EsError{ return ((proc (^rawptr) -> EsError)(rawptr(uintptr(0x1000 + 45 * size_of(int)))))(address); } -EsGetCreationArgument :: inline proc (object :EsHandle) -> EsGeneric{ return ((proc (EsHandle) -> EsGeneric)(rawptr(uintptr(0x1000 + 46 * size_of(int)))))(object); } -EsProcessGetState :: inline proc (process :EsHandle, state :^EsProcessState){ ((proc (EsHandle, ^EsProcessState))(rawptr(uintptr(0x1000 + 47 * size_of(int)))))(process, state); } -EsSurfaceGetLinearBuffer :: inline proc (surface :EsHandle, linearBuffer :^EsLinearBuffer){ ((proc (EsHandle, ^EsLinearBuffer))(rawptr(uintptr(0x1000 + 48 * size_of(int)))))(surface, linearBuffer); } -EsRectangleInvalidate :: inline proc (surface :EsHandle, rectangle :EsRectangle){ ((proc (EsHandle, EsRectangle))(rawptr(uintptr(0x1000 + 49 * size_of(int)))))(surface, rectangle); } -EsCopyToScreen :: inline proc (source :EsHandle, point :EsPoint, depth :u16){ ((proc (EsHandle, EsPoint, u16))(rawptr(uintptr(0x1000 + 50 * size_of(int)))))(source, point, depth); } -EsForceScreenUpdate :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 51 * size_of(int)))))(); } -EsDrawRectangle :: inline proc (surface :EsHandle, rectangle :EsRectangle, color :EsColor){ ((proc (EsHandle, EsRectangle, EsColor))(rawptr(uintptr(0x1000 + 52 * size_of(int)))))(surface, rectangle, color); } -EsDrawRectangleClipped :: inline proc (surface :EsHandle, rectangle :EsRectangle, color :EsColor, clipRegion :EsRectangle){ ((proc (EsHandle, EsRectangle, EsColor, EsRectangle))(rawptr(uintptr(0x1000 + 53 * size_of(int)))))(surface, rectangle, color, clipRegion); } -EsDrawSurfaceBlit :: inline proc (destination :EsHandle, source :EsHandle, destinationPoint :EsPoint){ ((proc (EsHandle, EsHandle, EsPoint))(rawptr(uintptr(0x1000 + 54 * size_of(int)))))(destination, source, destinationPoint); } -EsDrawSurface :: inline proc (destination :EsHandle, source :EsHandle, destinationRegion :EsRectangle, sourceRegion :EsRectangle, borderRegion :EsRectangle, mode :EsDrawMode, alpha :u16) -> EsError{ return ((proc (EsHandle, EsHandle, EsRectangle, EsRectangle, EsRectangle, EsDrawMode, u16) -> EsError)(rawptr(uintptr(0x1000 + 55 * size_of(int)))))(destination, source, destinationRegion, sourceRegion, borderRegion, mode, alpha); } -EsDrawSurfaceClipped :: inline proc (destination :EsHandle, source :EsHandle, destinationRegion :EsRectangle, sourceRegion :EsRectangle, borderRegion :EsRectangle, mode :EsDrawMode, alpha :u16, clipRegion :EsRectangle) -> EsError{ return ((proc (EsHandle, EsHandle, EsRectangle, EsRectangle, EsRectangle, EsDrawMode, u16, EsRectangle) -> EsError)(rawptr(uintptr(0x1000 + 56 * size_of(int)))))(destination, source, destinationRegion, sourceRegion, borderRegion, mode, alpha, clipRegion); } -EsDrawBitmap :: inline proc (destination :EsHandle, destinationPoint :EsPoint, bitmap :^rawptr, width :uintptr, height :uintptr, stride :uintptr, colorFormat :EsColorFormat){ ((proc (EsHandle, EsPoint, ^rawptr, uintptr, uintptr, uintptr, EsColorFormat))(rawptr(uintptr(0x1000 + 57 * size_of(int)))))(destination, destinationPoint, bitmap, width, height, stride, colorFormat); } -EsSurfaceClearInvalidatedRegion :: inline proc (surface :EsHandle){ ((proc (EsHandle))(rawptr(uintptr(0x1000 + 58 * size_of(int)))))(surface); } -EsRectangleClip :: inline proc (parent :EsRectangle, rectangle :EsRectangle, output :^EsRectangle) -> bool{ return ((proc (EsRectangle, EsRectangle, ^EsRectangle) -> bool)(rawptr(uintptr(0x1000 + 59 * size_of(int)))))(parent, rectangle, output); } -EsDrawBox :: inline proc (surface :EsHandle, rectangle :EsRectangle, style :u8, color :u32, clipRegion :EsRectangle){ ((proc (EsHandle, EsRectangle, u8, u32, EsRectangle))(rawptr(uintptr(0x1000 + 60 * size_of(int)))))(surface, rectangle, style, color, clipRegion); } -EsRedrawAll :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 61 * size_of(int)))))(); } -EsMessagePost :: inline proc (message :^EsMessage) -> EsError{ return ((proc (^EsMessage) -> EsError)(rawptr(uintptr(0x1000 + 62 * size_of(int)))))(message); } -EsMessagePostRemote :: inline proc (process :EsHandle, message :^EsMessage) -> EsError{ return ((proc (EsHandle, ^EsMessage) -> EsError)(rawptr(uintptr(0x1000 + 63 * size_of(int)))))(process, message); } -EsExtractArguments :: inline proc (string :^i8, bytes :uintptr, delimiterByte :u8, replacementDelimiter :u8, argvAllocated :uintptr, argv :^^i8, argc :^uintptr) -> bool{ return ((proc (^i8, uintptr, u8, u8, uintptr, ^^i8, ^uintptr) -> bool)(rawptr(uintptr(0x1000 + 64 * size_of(int)))))(string, bytes, delimiterByte, replacementDelimiter, argvAllocated, argv, argc); } -EsCStringLength :: inline proc (string :^i8) -> uintptr{ return ((proc (^i8) -> uintptr)(rawptr(uintptr(0x1000 + 65 * size_of(int)))))(string); } -EsStringLength :: inline proc (string :^i8, end :u8) -> uintptr{ return ((proc (^i8, u8) -> uintptr)(rawptr(uintptr(0x1000 + 66 * size_of(int)))))(string, end); } -EsMemoryCopy :: inline proc (destination :^rawptr, source :^rawptr, bytes :uintptr){ ((proc (^rawptr, ^rawptr, uintptr))(rawptr(uintptr(0x1000 + 67 * size_of(int)))))(destination, source, bytes); } -EsMemoryMove :: inline proc (_start :^rawptr, _end :^rawptr, amount :int, zeroEmptySpace :bool){ ((proc (^rawptr, ^rawptr, int, bool))(rawptr(uintptr(0x1000 + 68 * size_of(int)))))(_start, _end, amount, zeroEmptySpace); } -EsMemoryCopyReverse :: inline proc (_destination :^rawptr, _source :^rawptr, bytes :uintptr){ ((proc (^rawptr, ^rawptr, uintptr))(rawptr(uintptr(0x1000 + 69 * size_of(int)))))(_destination, _source, bytes); } -EsMemoryZero :: inline proc (destination :^rawptr, bytes :uintptr){ ((proc (^rawptr, uintptr))(rawptr(uintptr(0x1000 + 70 * size_of(int)))))(destination, bytes); } -EsMemoryCompare :: inline proc (a :^rawptr, b :^rawptr, bytes :uintptr) -> i32{ return ((proc (^rawptr, ^rawptr, uintptr) -> i32)(rawptr(uintptr(0x1000 + 71 * size_of(int)))))(a, b, bytes); } -EsMemorySumBytes :: inline proc (data :^u8, bytes :uintptr) -> u8{ return ((proc (^u8, uintptr) -> u8)(rawptr(uintptr(0x1000 + 72 * size_of(int)))))(data, bytes); } -EsPrintDirect :: inline proc (string :^i8, stringLength :uintptr){ ((proc (^i8, uintptr))(rawptr(uintptr(0x1000 + 73 * size_of(int)))))(string, stringLength); } -EsStringFormat :: inline proc (buffer :^i8, bufferLength :uintptr, format :^i8, args : ..any) -> uintptr{ return ((proc (^i8, uintptr, ^i8, ..any) -> uintptr)(rawptr(uintptr(0x1000 + 74 * size_of(int)))))(buffer, bufferLength, format, ); } -EsStringFormatAppend :: inline proc (buffer :^i8, bufferLength :uintptr, bufferPosition :^uintptr, format :^i8, args : ..any){ ((proc (^i8, uintptr, ^uintptr, ^i8, ..any))(rawptr(uintptr(0x1000 + 75 * size_of(int)))))(buffer, bufferLength, bufferPosition, format, ); } -EsPrintHelloWorld :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 76 * size_of(int)))))(); } -EsGetRandomByte :: inline proc () -> u8{ return ((proc () -> u8)(rawptr(uintptr(0x1000 + 77 * size_of(int)))))(); } -EsSort :: inline proc (_base :^rawptr, nmemb :uintptr, size :uintptr, compar :EsComparisonCallbackFunction, argument :EsGeneric){ ((proc (^rawptr, uintptr, uintptr, EsComparisonCallbackFunction, EsGeneric))(rawptr(uintptr(0x1000 + 78 * size_of(int)))))(_base, nmemb, size, compar, argument); } -EsSortWithSwapCallback :: inline proc (_base :^rawptr, nmemb :uintptr, size :uintptr, compar :EsComparisonCallbackFunction, argument :EsGeneric, swap :EsSwapCallbackFunction){ ((proc (^rawptr, uintptr, uintptr, EsComparisonCallbackFunction, EsGeneric, EsSwapCallbackFunction))(rawptr(uintptr(0x1000 + 79 * size_of(int)))))(_base, nmemb, size, compar, argument, swap); } -EsStringCompare :: inline proc (s1 :^i8, s2 :^i8, length1 :uintptr, length2 :uintptr) -> i32{ return ((proc (^i8, ^i8, uintptr, uintptr) -> i32)(rawptr(uintptr(0x1000 + 80 * size_of(int)))))(s1, s2, length1, length2); } -EsIntegerParse :: inline proc (text :^i8, bytes :uintptr) -> i64{ return ((proc (^i8, uintptr) -> i64)(rawptr(uintptr(0x1000 + 81 * size_of(int)))))(text, bytes); } -EsCRTmemset :: inline proc (s :^rawptr, c :i32, n :uintptr){ ((proc (^rawptr, i32, uintptr))(rawptr(uintptr(0x1000 + 82 * size_of(int)))))(s, c, n); } -EsCRTmemcpy :: inline proc (dest :^rawptr, src :^rawptr, n :uintptr){ ((proc (^rawptr, ^rawptr, uintptr))(rawptr(uintptr(0x1000 + 83 * size_of(int)))))(dest, src, n); } -EsCRTmemmove :: inline proc (dest :^rawptr, src :^rawptr, n :uintptr){ ((proc (^rawptr, ^rawptr, uintptr))(rawptr(uintptr(0x1000 + 84 * size_of(int)))))(dest, src, n); } -EsCRTstrlen :: inline proc (s :^i8) -> uintptr{ return ((proc (^i8) -> uintptr)(rawptr(uintptr(0x1000 + 85 * size_of(int)))))(s); } -EsCRTstrnlen :: inline proc (s :^i8, maxlen :uintptr) -> uintptr{ return ((proc (^i8, uintptr) -> uintptr)(rawptr(uintptr(0x1000 + 86 * size_of(int)))))(s, maxlen); } -EsCRTmalloc :: inline proc (size :uintptr){ ((proc (uintptr))(rawptr(uintptr(0x1000 + 87 * size_of(int)))))(size); } -EsCRTcalloc :: inline proc (num :uintptr, size :uintptr){ ((proc (uintptr, uintptr))(rawptr(uintptr(0x1000 + 88 * size_of(int)))))(num, size); } -EsCRTfree :: inline proc (ptr :^rawptr){ ((proc (^rawptr))(rawptr(uintptr(0x1000 + 89 * size_of(int)))))(ptr); } -EsCRTabs :: inline proc (n :i32) -> i32{ return ((proc (i32) -> i32)(rawptr(uintptr(0x1000 + 90 * size_of(int)))))(n); } -EsCRTrealloc :: inline proc (ptr :^rawptr, size :uintptr){ ((proc (^rawptr, uintptr))(rawptr(uintptr(0x1000 + 91 * size_of(int)))))(ptr, size); } -EsCRTgetenv :: inline proc (name :^i8) -> ^i8{ return ((proc (^i8) -> ^i8)(rawptr(uintptr(0x1000 + 92 * size_of(int)))))(name); } -EsCRTstrncmp :: inline proc (s1 :^i8, s2 :^i8, n :uintptr) -> i32{ return ((proc (^i8, ^i8, uintptr) -> i32)(rawptr(uintptr(0x1000 + 93 * size_of(int)))))(s1, s2, n); } -EsCRTmemcmp :: inline proc (s1 :^rawptr, s2 :^rawptr, n :uintptr) -> i32{ return ((proc (^rawptr, ^rawptr, uintptr) -> i32)(rawptr(uintptr(0x1000 + 94 * size_of(int)))))(s1, s2, n); } -EsCRTqsort :: inline proc (_base :^rawptr, nmemb :uintptr, size :uintptr, compar :EsCRTComparisonCallback){ ((proc (^rawptr, uintptr, uintptr, EsCRTComparisonCallback))(rawptr(uintptr(0x1000 + 95 * size_of(int)))))(_base, nmemb, size, compar); } -EsCRTstrcmp :: inline proc (s1 :^i8, s2 :^i8) -> i32{ return ((proc (^i8, ^i8) -> i32)(rawptr(uintptr(0x1000 + 96 * size_of(int)))))(s1, s2); } -EsCRTstrstr :: inline proc (haystack :^i8, needle :^i8) -> ^i8{ return ((proc (^i8, ^i8) -> ^i8)(rawptr(uintptr(0x1000 + 97 * size_of(int)))))(haystack, needle); } -EsCRTstrcpy :: inline proc (dest :^i8, src :^i8) -> ^i8{ return ((proc (^i8, ^i8) -> ^i8)(rawptr(uintptr(0x1000 + 98 * size_of(int)))))(dest, src); } -EsCRTisalpha :: inline proc (c :i32) -> i32{ return ((proc (i32) -> i32)(rawptr(uintptr(0x1000 + 99 * size_of(int)))))(c); } -EsCRTmemchr :: inline proc (_s :^rawptr, _c :i32, n :uintptr){ ((proc (^rawptr, i32, uintptr))(rawptr(uintptr(0x1000 + 100 * size_of(int)))))(_s, _c, n); } -EsCRTisdigit :: inline proc (c :i32) -> i32{ return ((proc (i32) -> i32)(rawptr(uintptr(0x1000 + 101 * size_of(int)))))(c); } -EsCRTstrcat :: inline proc (dest :^i8, src :^i8) -> ^i8{ return ((proc (^i8, ^i8) -> ^i8)(rawptr(uintptr(0x1000 + 102 * size_of(int)))))(dest, src); } -EsCRTtolower :: inline proc (c :i32) -> i32{ return ((proc (i32) -> i32)(rawptr(uintptr(0x1000 + 103 * size_of(int)))))(c); } -EsCRTstrncpy :: inline proc (dest :^i8, src :^i8, n :uintptr) -> ^i8{ return ((proc (^i8, ^i8, uintptr) -> ^i8)(rawptr(uintptr(0x1000 + 104 * size_of(int)))))(dest, src, n); } -EsCRTstrtoul :: inline proc (nptr :^i8, endptr :^^i8, base :i32) -> u64{ return ((proc (^i8, ^^i8, i32) -> u64)(rawptr(uintptr(0x1000 + 105 * size_of(int)))))(nptr, endptr, base); } -EsExecute :: inline proc (what :^i8, whatBytes :uintptr, argument :^i8, argumentBytes :uintptr){ ((proc (^i8, uintptr, ^i8, uintptr))(rawptr(uintptr(0x1000 + 106 * size_of(int)))))(what, whatBytes, argument, argumentBytes); } -EsAbort :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 107 * size_of(int)))))(); } -EsMailslotSendData :: inline proc (mailslot :EsHandle, data :^rawptr, bytes :uintptr) -> bool{ return ((proc (EsHandle, ^rawptr, uintptr) -> bool)(rawptr(uintptr(0x1000 + 108 * size_of(int)))))(mailslot, data, bytes); } -EsCRTfloorf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 109 * size_of(int)))))(x); } -EsCRTceilf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 110 * size_of(int)))))(x); } -EsCRTsinf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 111 * size_of(int)))))(x); } -EsCRTcosf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 112 * size_of(int)))))(x); } -EsCRTatan2f :: inline proc (y :f32, x :f32) -> f32{ return ((proc (f32, f32) -> f32)(rawptr(uintptr(0x1000 + 113 * size_of(int)))))(y, x); } -EsCRTfmodf :: inline proc (x :f32, y :f32) -> f32{ return ((proc (f32, f32) -> f32)(rawptr(uintptr(0x1000 + 114 * size_of(int)))))(x, y); } -EsCRTacosf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 115 * size_of(int)))))(x); } -EsCRTasinf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 116 * size_of(int)))))(x); } -EsCRTatanf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 117 * size_of(int)))))(x); } -EsRandomSeed :: inline proc (x :u64){ ((proc (u64))(rawptr(uintptr(0x1000 + 118 * size_of(int)))))(x); } -EsCRTsqrtf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 119 * size_of(int)))))(x); } -EsCRTsqrtl :: inline proc (x :EsLongDouble) -> EsLongDouble{ return ((proc (EsLongDouble) -> EsLongDouble)(rawptr(uintptr(0x1000 + 120 * size_of(int)))))(x); } -EsCRTfabsl :: inline proc (x :EsLongDouble) -> EsLongDouble{ return ((proc (EsLongDouble) -> EsLongDouble)(rawptr(uintptr(0x1000 + 121 * size_of(int)))))(x); } -_EsSyscall :: inline proc (a :uintptr, b :uintptr, c :uintptr, d :uintptr, e :uintptr, f :uintptr) -> uintptr{ return ((proc (uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) -> uintptr)(rawptr(uintptr(0x1000 + 122 * size_of(int)))))(a, b, c, d, e, f); } -EsProcessorReadTimeStamp :: inline proc () -> u64{ return ((proc () -> u64)(rawptr(uintptr(0x1000 + 123 * size_of(int)))))(); } -EsHeapAllocate :: inline proc (size :uintptr, zeroMemory :bool){ ((proc (uintptr, bool))(rawptr(uintptr(0x1000 + 124 * size_of(int)))))(size, zeroMemory); } -EsHeapFree :: inline proc (address :^rawptr){ ((proc (^rawptr))(rawptr(uintptr(0x1000 + 125 * size_of(int)))))(address); } -EsPrint :: inline proc (format :^i8, args : ..any){ ((proc (^i8, ..any))(rawptr(uintptr(0x1000 + 126 * size_of(int)))))(format, ); } -EsMemoryFill :: inline proc (from :^rawptr, to :^rawptr, byte :u8){ ((proc (^rawptr, ^rawptr, u8))(rawptr(uintptr(0x1000 + 127 * size_of(int)))))(from, to, byte); } -EsInitialiseCStandardLibrary :: inline proc (argc :^i32, argv :^^^i8){ ((proc (^i32, ^^^i8))(rawptr(uintptr(0x1000 + 128 * size_of(int)))))(argc, argv); } -EsMakeLinuxSystemCall2 :: inline proc (n :int, a1 :int, a2 :int, a3 :int, a4 :int, a5 :int, a6 :int) -> int{ return ((proc (int, int, int, int, int, int, int) -> int)(rawptr(uintptr(0x1000 + 129 * size_of(int)))))(n, a1, a2, a3, a4, a5, a6); } -EsProcessCreate2 :: inline proc (arguments :^EsProcessCreationArguments, information :^EsProcessInformation) -> EsError{ return ((proc (^EsProcessCreationArguments, ^EsProcessInformation) -> EsError)(rawptr(uintptr(0x1000 + 130 * size_of(int)))))(arguments, information); } -EsCRTatoi :: inline proc (string :^i8) -> i32{ return ((proc (^i8) -> i32)(rawptr(uintptr(0x1000 + 131 * size_of(int)))))(string); } -EsProcessGetExitStatus :: inline proc (process :EsHandle) -> i32{ return ((proc (EsHandle) -> i32)(rawptr(uintptr(0x1000 + 132 * size_of(int)))))(process); } -EsSurfaceReset :: inline proc (surface :EsHandle){ ((proc (EsHandle))(rawptr(uintptr(0x1000 + 133 * size_of(int)))))(surface); } -EsTimerCreate :: inline proc () -> EsHandle{ return ((proc () -> EsHandle)(rawptr(uintptr(0x1000 + 134 * size_of(int)))))(); } -EsTimerSet :: inline proc (handle :EsHandle, afterMs :u64, object :EsObject, argument :EsGeneric){ ((proc (EsHandle, u64, EsObject, EsGeneric))(rawptr(uintptr(0x1000 + 135 * size_of(int)))))(handle, afterMs, object, argument); } -EsFileWriteAll :: inline proc (filePath :^i8, filePathLength :uintptr, data :^rawptr, fileSize :uintptr) -> EsError{ return ((proc (^i8, uintptr, ^rawptr, uintptr) -> EsError)(rawptr(uintptr(0x1000 + 136 * size_of(int)))))(filePath, filePathLength, data, fileSize); } -EsUserGetHomeFolder :: inline proc (buffer :^i8, bufferBytes :uintptr) -> uintptr{ return ((proc (^i8, uintptr) -> uintptr)(rawptr(uintptr(0x1000 + 137 * size_of(int)))))(buffer, bufferBytes); } -EsAssert :: inline proc (expression :bool, failureMessage :^i8){ ((proc (bool, ^i8))(rawptr(uintptr(0x1000 + 138 * size_of(int)))))(expression, failureMessage); } -EsResizeArray :: inline proc (array :^^rawptr, allocated :^uintptr, needed :uintptr, itemSize :uintptr){ ((proc (^^rawptr, ^uintptr, uintptr, uintptr))(rawptr(uintptr(0x1000 + 139 * size_of(int)))))(array, allocated, needed, itemSize); } -EsMessageLoopEnter :: inline proc (callback :EsMessageCallbackFunction){ ((proc (EsMessageCallbackFunction))(rawptr(uintptr(0x1000 + 140 * size_of(int)))))(callback); } -_EsInstanceCreate :: inline proc (bytes :uintptr) -> ^EsInstance{ return ((proc (uintptr) -> ^EsInstance)(rawptr(uintptr(0x1000 + 141 * size_of(int)))))(bytes); } -EsMouseGetPosition :: inline proc (relativeWindow :^EsElement) -> EsPoint{ return ((proc (^EsElement) -> EsPoint)(rawptr(uintptr(0x1000 + 142 * size_of(int)))))(relativeWindow); } -EsMouseSetPosition :: inline proc (relativeWindow :^EsElement, x :i32, y :i32){ ((proc (^EsElement, i32, i32))(rawptr(uintptr(0x1000 + 143 * size_of(int)))))(relativeWindow, x, y); } -EsNewWindow :: inline proc (instance :^EsInstance, style :EsWindowStyle) -> ^EsElement{ return ((proc (^EsInstance, EsWindowStyle) -> ^EsElement)(rawptr(uintptr(0x1000 + 144 * size_of(int)))))(instance, style); } -EsNewPanel :: inline proc (parent :^EsElement, style :EsData, flags :u64) -> ^EsElement{ return ((proc (^EsElement, EsData, u64) -> ^EsElement)(rawptr(uintptr(0x1000 + 145 * size_of(int)))))(parent, style, flags); } -EsNewScrollbar :: inline proc (parent :^EsElement, flags :u64, userCallback :EsUICallbackFunction, _context :EsGeneric) -> ^EsElement{ return ((proc (^EsElement, u64, EsUICallbackFunction, EsGeneric) -> ^EsElement)(rawptr(uintptr(0x1000 + 146 * size_of(int)))))(parent, flags, userCallback, _context); } -EsNewButton :: inline proc (parent :^EsElement, label :^i8, labelBytes :int, flags :u64, userCallback :EsUICallbackFunction, _context :EsGeneric) -> ^EsElement{ return ((proc (^EsElement, ^i8, int, u64, EsUICallbackFunction, EsGeneric) -> ^EsElement)(rawptr(uintptr(0x1000 + 147 * size_of(int)))))(parent, label, labelBytes, flags, userCallback, _context); } -EsNewTextbox :: inline proc (parent :^EsElement, flags :u64, userCallback :EsUICallbackFunction, _context :EsGeneric) -> ^EsElement{ return ((proc (^EsElement, u64, EsUICallbackFunction, EsGeneric) -> ^EsElement)(rawptr(uintptr(0x1000 + 148 * size_of(int)))))(parent, flags, userCallback, _context); } -EsNewNumericEntry :: inline proc (parent :^EsElement, flags :u64, userCallback :EsUICallbackFunction, _context :EsGeneric) -> ^EsElement{ return ((proc (^EsElement, u64, EsUICallbackFunction, EsGeneric) -> ^EsElement)(rawptr(uintptr(0x1000 + 149 * size_of(int)))))(parent, flags, userCallback, _context); } -EsNewListView :: inline proc (parent :^EsElement, flags :u64, style :^EsListViewStyle, userCallback :EsUICallbackFunction, _context :EsGeneric) -> ^EsElement{ return ((proc (^EsElement, u64, ^EsListViewStyle, EsUICallbackFunction, EsGeneric) -> ^EsElement)(rawptr(uintptr(0x1000 + 150 * size_of(int)))))(parent, flags, style, userCallback, _context); } -EsElementGetInstance :: inline proc (element :^EsElement) -> ^EsInstance{ return ((proc (^EsElement) -> ^EsInstance)(rawptr(uintptr(0x1000 + 151 * size_of(int)))))(element); } -EsElementFocus :: inline proc (element :^EsElement, ensureVisible :bool){ ((proc (^EsElement, bool))(rawptr(uintptr(0x1000 + 152 * size_of(int)))))(element, ensureVisible); } -EsScrollbarSetMeasurements :: inline proc (scrollbar :^EsElement, viewportSize :i32, contentSize :i32){ ((proc (^EsElement, i32, i32))(rawptr(uintptr(0x1000 + 153 * size_of(int)))))(scrollbar, viewportSize, contentSize); } -EsScrollbarSetPosition :: inline proc (scrollbar :^EsElement, position :f32, sendMovedMessage :bool, smoothScroll :bool){ ((proc (^EsElement, f32, bool, bool))(rawptr(uintptr(0x1000 + 154 * size_of(int)))))(scrollbar, position, sendMovedMessage, smoothScroll); } -EsWindowGetBounds :: inline proc (window :^EsElement, bounds :^EsRectangle){ ((proc (^EsElement, ^EsRectangle))(rawptr(uintptr(0x1000 + 155 * size_of(int)))))(window, bounds); } -EsListViewInsert :: inline proc (listView :^EsElement, group :EsListViewIndex, index :EsListViewIndex, count :uintptr){ ((proc (^EsElement, EsListViewIndex, EsListViewIndex, uintptr))(rawptr(uintptr(0x1000 + 156 * size_of(int)))))(listView, group, index, count); } -EsListViewInsertGroup :: inline proc (listView :^EsElement, group :EsListViewIndex){ ((proc (^EsElement, EsListViewIndex))(rawptr(uintptr(0x1000 + 157 * size_of(int)))))(listView, group); } -EsListViewRemove :: inline proc (listView :^EsElement, group :EsListViewIndex, index :EsListViewIndex, count :int, removedHeight :i32){ ((proc (^EsElement, EsListViewIndex, EsListViewIndex, int, i32))(rawptr(uintptr(0x1000 + 158 * size_of(int)))))(listView, group, index, count, removedHeight); } -EsListViewRemoveGroup :: inline proc (listView :^EsElement, group :EsListViewIndex){ ((proc (^EsElement, EsListViewIndex))(rawptr(uintptr(0x1000 + 159 * size_of(int)))))(listView, group); } -EsListViewInvalidate :: inline proc (listView :^EsElement, deltaHeight :i32, recalculateHeight :bool){ ((proc (^EsElement, i32, bool))(rawptr(uintptr(0x1000 + 160 * size_of(int)))))(listView, deltaHeight, recalculateHeight); } -EsListViewEnsureVisible :: inline proc (listView :^EsElement, group :EsListViewIndex, index :EsListViewIndex){ ((proc (^EsElement, EsListViewIndex, EsListViewIndex))(rawptr(uintptr(0x1000 + 161 * size_of(int)))))(listView, group, index); } -EsListViewResetSearchBuffer :: inline proc (object :^EsElement){ ((proc (^EsElement))(rawptr(uintptr(0x1000 + 162 * size_of(int)))))(object); } -EsDataParse :: inline proc (cFormat :^i8, args : ..any) -> EsData{ return ((proc (^i8, ..any) -> EsData)(rawptr(uintptr(0x1000 + 163 * size_of(int)))))(cFormat, ); } -EsDataNone :: inline proc () -> EsData{ return ((proc () -> EsData)(rawptr(uintptr(0x1000 + 164 * size_of(int)))))(); } +NumericEntryProperties :: struct { + value :i32, + dp :i32, + delta :i32, + speed :i32, + minimum :i32, + maximum :i32, + cPrefix :^i8, + cSuffix :^i8, +} + +Batch :: inline proc (calls :^BatchCall, count :uintptr){ addr := 0x1000 + 0 * size_of(int); ((proc (^BatchCall, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(calls, count); } +ProcessCreate :: inline proc (executablePath :^i8, executablePathLength :uintptr, information :^ProcessInformation, argument :Generic) -> Error{ addr := 0x1000 + 1 * size_of(int); return ((proc (^i8, uintptr, ^ProcessInformation, Generic) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(executablePath, executablePathLength, information, argument); } +ThreadCreate :: inline proc (entryFunction :ThreadEntryFunction, information :^ThreadInformation, argument :Generic) -> Error{ addr := 0x1000 + 2 * size_of(int); return ((proc (ThreadEntryFunction, ^ThreadInformation, Generic) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(entryFunction, information, argument); } +SurfaceCreate :: inline proc (width :uintptr, height :uintptr, flags :u32) -> Handle{ addr := 0x1000 + 3 * size_of(int); return ((proc (uintptr, uintptr, u32) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(width, height, flags); } +EventCreate :: inline proc (autoReset :bool) -> Handle{ addr := 0x1000 + 4 * size_of(int); return ((proc (bool) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(autoReset); } +ThreadLocalStorageSetAddress :: inline proc (address :^rawptr){ addr := 0x1000 + 5 * size_of(int); ((proc (^rawptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(address); } +ConstantBufferRead :: inline proc (constantBuffer :Handle, output :^rawptr){ addr := 0x1000 + 6 * size_of(int); ((proc (Handle, ^rawptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(constantBuffer, output); } +ConstantBufferShare :: inline proc (constantBuffer :Handle, targetProcess :Handle) -> Handle{ addr := 0x1000 + 7 * size_of(int); return ((proc (Handle, Handle) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(constantBuffer, targetProcess); } +ConstantBufferCreate :: inline proc (data :^rawptr, dataBytes :uintptr, targetProcess :Handle) -> Handle{ addr := 0x1000 + 8 * size_of(int); return ((proc (^rawptr, uintptr, Handle) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(data, dataBytes, targetProcess); } +ProcessOpen :: inline proc (pid :u64) -> Handle{ addr := 0x1000 + 9 * size_of(int); return ((proc (u64) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(pid); } +HandleClose :: inline proc (handle :Handle) -> Error{ addr := 0x1000 + 10 * size_of(int); return ((proc (Handle) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(handle); } +TakeSystemSnapshot :: inline proc (type :i32, bufferSize :^uintptr) -> Handle{ addr := 0x1000 + 11 * size_of(int); return ((proc (i32, ^uintptr) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(type, bufferSize); } +GetSystemInformation :: inline proc (systemInformation :^SystemInformation){ addr := 0x1000 + 12 * size_of(int); ((proc (^SystemInformation))(rawptr(((^uintptr)(uintptr(addr)))^)))(systemInformation); } +NodeOpen :: inline proc (path :^i8, pathLength :uintptr, flags :u64, information :^NodeInformation) -> Error{ addr := 0x1000 + 13 * size_of(int); return ((proc (^i8, uintptr, u64, ^NodeInformation) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(path, pathLength, flags, information); } +NodeFindUniqueName :: inline proc (buffer :^i8, originalBytes :uintptr, bufferBytes :uintptr) -> uintptr{ addr := 0x1000 + 14 * size_of(int); return ((proc (^i8, uintptr, uintptr) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(buffer, originalBytes, bufferBytes); } +FileReadAll :: inline proc (filePath :^i8, filePathLength :uintptr, fileSize :^uintptr){ addr := 0x1000 + 15 * size_of(int); ((proc (^i8, uintptr, ^uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(filePath, filePathLength, fileSize); } +FileReadSync :: inline proc (file :Handle, offset :FileOffset, size :uintptr, buffer :^rawptr) -> uintptr{ addr := 0x1000 + 16 * size_of(int); return ((proc (Handle, FileOffset, uintptr, ^rawptr) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(file, offset, size, buffer); } +FileWriteSync :: inline proc (file :Handle, offset :FileOffset, size :uintptr, buffer :^rawptr) -> uintptr{ addr := 0x1000 + 17 * size_of(int); return ((proc (Handle, FileOffset, uintptr, ^rawptr) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(file, offset, size, buffer); } +FileResize :: inline proc (file :Handle, newSize :FileOffset) -> Error{ addr := 0x1000 + 18 * size_of(int); return ((proc (Handle, FileOffset) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(file, newSize); } +NodeRefreshInformation :: inline proc (information :^NodeInformation){ addr := 0x1000 + 19 * size_of(int); ((proc (^NodeInformation))(rawptr(((^uintptr)(uintptr(addr)))^)))(information); } +DirectoryEnumerateChildren :: inline proc (directory :Handle, buffer :^DirectoryChild, bufferCount :uintptr) -> int{ addr := 0x1000 + 20 * size_of(int); return ((proc (Handle, ^DirectoryChild, uintptr) -> int)(rawptr(((^uintptr)(uintptr(addr)))^)))(directory, buffer, bufferCount); } +NodeDelete :: inline proc (node :Handle) -> Error{ addr := 0x1000 + 21 * size_of(int); return ((proc (Handle) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(node); } +NodeMove :: inline proc (node :Handle, newDirectory :Handle, newName :^i8, newNameLength :uintptr) -> Error{ addr := 0x1000 + 22 * size_of(int); return ((proc (Handle, Handle, ^i8, uintptr) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(node, newDirectory, newName, newNameLength); } +ThreadTerminate :: inline proc (thread :Handle){ addr := 0x1000 + 23 * size_of(int); ((proc (Handle))(rawptr(((^uintptr)(uintptr(addr)))^)))(thread); } +ProcessTerminate :: inline proc (process :Handle, status :i32){ addr := 0x1000 + 24 * size_of(int); ((proc (Handle, i32))(rawptr(((^uintptr)(uintptr(addr)))^)))(process, status); } +ProcessTerminateCurrent :: inline proc (){ addr := 0x1000 + 25 * size_of(int); ((proc ())(rawptr(((^uintptr)(uintptr(addr)))^)))(); } +ProcessPause :: inline proc (process :Handle, resume :bool){ addr := 0x1000 + 26 * size_of(int); ((proc (Handle, bool))(rawptr(((^uintptr)(uintptr(addr)))^)))(process, resume); } +ProcessCrash :: inline proc (error :Error, message :^i8, messageBytes :uintptr){ addr := 0x1000 + 27 * size_of(int); ((proc (Error, ^i8, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(error, message, messageBytes); } +ThreadGetID :: inline proc (thread :Handle) -> uintptr{ addr := 0x1000 + 28 * size_of(int); return ((proc (Handle) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(thread); } +ProcessGetID :: inline proc (process :Handle) -> uintptr{ addr := 0x1000 + 29 * size_of(int); return ((proc (Handle) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(process); } +SpinlockRelease :: inline proc (spinlock :^Spinlock){ addr := 0x1000 + 30 * size_of(int); ((proc (^Spinlock))(rawptr(((^uintptr)(uintptr(addr)))^)))(spinlock); } +SpinlockAcquire :: inline proc (spinlock :^Spinlock){ addr := 0x1000 + 31 * size_of(int); ((proc (^Spinlock))(rawptr(((^uintptr)(uintptr(addr)))^)))(spinlock); } +MutexRelease :: inline proc (mutex :^Mutex){ addr := 0x1000 + 32 * size_of(int); ((proc (^Mutex))(rawptr(((^uintptr)(uintptr(addr)))^)))(mutex); } +MutexAcquire :: inline proc (mutex :^Mutex){ addr := 0x1000 + 33 * size_of(int); ((proc (^Mutex))(rawptr(((^uintptr)(uintptr(addr)))^)))(mutex); } +MutexDestroy :: inline proc (mutex :^Mutex){ addr := 0x1000 + 34 * size_of(int); ((proc (^Mutex))(rawptr(((^uintptr)(uintptr(addr)))^)))(mutex); } +SchedulerYield :: inline proc (){ addr := 0x1000 + 35 * size_of(int); ((proc ())(rawptr(((^uintptr)(uintptr(addr)))^)))(); } +EventSet :: inline proc (event :Handle){ addr := 0x1000 + 36 * size_of(int); ((proc (Handle))(rawptr(((^uintptr)(uintptr(addr)))^)))(event); } +EventReset :: inline proc (event :Handle){ addr := 0x1000 + 37 * size_of(int); ((proc (Handle))(rawptr(((^uintptr)(uintptr(addr)))^)))(event); } +EventPoll :: inline proc (event :Handle) -> Error{ addr := 0x1000 + 38 * size_of(int); return ((proc (Handle) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(event); } +Wait :: inline proc (objects :^Handle, objectCount :uintptr, timeoutMs :uintptr) -> uintptr{ addr := 0x1000 + 39 * size_of(int); return ((proc (^Handle, uintptr, uintptr) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(objects, objectCount, timeoutMs); } +Sleep :: inline proc (milliseconds :u64){ addr := 0x1000 + 40 * size_of(int); ((proc (u64))(rawptr(((^uintptr)(uintptr(addr)))^)))(milliseconds); } +MemoryOpen :: inline proc (size :uintptr, name :^i8, nameLength :uintptr, flags :u32) -> Handle{ addr := 0x1000 + 41 * size_of(int); return ((proc (uintptr, ^i8, uintptr, u32) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(size, name, nameLength, flags); } +MemoryShare :: inline proc (sharedMemoryRegion :Handle, targetProcess :Handle, readOnly :bool) -> Handle{ addr := 0x1000 + 42 * size_of(int); return ((proc (Handle, Handle, bool) -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(sharedMemoryRegion, targetProcess, readOnly); } +ObjectMap :: inline proc (object :Handle, offset :uintptr, size :uintptr, flags :u32){ addr := 0x1000 + 43 * size_of(int); ((proc (Handle, uintptr, uintptr, u32))(rawptr(((^uintptr)(uintptr(addr)))^)))(object, offset, size, flags); } +MemoryAllocate :: inline proc (size :uintptr){ addr := 0x1000 + 44 * size_of(int); ((proc (uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(size); } +MemoryFree :: inline proc (address :^rawptr) -> Error{ addr := 0x1000 + 45 * size_of(int); return ((proc (^rawptr) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(address); } +GetCreationArgument :: inline proc (object :Handle) -> Generic{ addr := 0x1000 + 46 * size_of(int); return ((proc (Handle) -> Generic)(rawptr(((^uintptr)(uintptr(addr)))^)))(object); } +ProcessGetState :: inline proc (process :Handle, state :^ProcessState){ addr := 0x1000 + 47 * size_of(int); ((proc (Handle, ^ProcessState))(rawptr(((^uintptr)(uintptr(addr)))^)))(process, state); } +SurfaceGetLinearBuffer :: inline proc (surface :Handle, linearBuffer :^LinearBuffer){ addr := 0x1000 + 48 * size_of(int); ((proc (Handle, ^LinearBuffer))(rawptr(((^uintptr)(uintptr(addr)))^)))(surface, linearBuffer); } +RectangleInvalidate :: inline proc (surface :Handle, rectangle :Rectangle){ addr := 0x1000 + 49 * size_of(int); ((proc (Handle, Rectangle))(rawptr(((^uintptr)(uintptr(addr)))^)))(surface, rectangle); } +CopyToScreen :: inline proc (source :Handle, point :Point, depth :u16){ addr := 0x1000 + 50 * size_of(int); ((proc (Handle, Point, u16))(rawptr(((^uintptr)(uintptr(addr)))^)))(source, point, depth); } +ForceScreenUpdate :: inline proc (){ addr := 0x1000 + 51 * size_of(int); ((proc ())(rawptr(((^uintptr)(uintptr(addr)))^)))(); } +DrawRectangle :: inline proc (surface :Handle, rectangle :Rectangle, color :Color){ addr := 0x1000 + 52 * size_of(int); ((proc (Handle, Rectangle, Color))(rawptr(((^uintptr)(uintptr(addr)))^)))(surface, rectangle, color); } +DrawRectangleClipped :: inline proc (surface :Handle, rectangle :Rectangle, color :Color, clipRegion :Rectangle){ addr := 0x1000 + 53 * size_of(int); ((proc (Handle, Rectangle, Color, Rectangle))(rawptr(((^uintptr)(uintptr(addr)))^)))(surface, rectangle, color, clipRegion); } +DrawSurfaceBlit :: inline proc (destination :Handle, source :Handle, destinationPoint :Point){ addr := 0x1000 + 54 * size_of(int); ((proc (Handle, Handle, Point))(rawptr(((^uintptr)(uintptr(addr)))^)))(destination, source, destinationPoint); } +DrawSurface :: inline proc (destination :Handle, source :Handle, destinationRegion :Rectangle, sourceRegion :Rectangle, borderRegion :Rectangle, mode :DrawMode, alpha :u16) -> Error{ addr := 0x1000 + 55 * size_of(int); return ((proc (Handle, Handle, Rectangle, Rectangle, Rectangle, DrawMode, u16) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(destination, source, destinationRegion, sourceRegion, borderRegion, mode, alpha); } +DrawSurfaceClipped :: inline proc (destination :Handle, source :Handle, destinationRegion :Rectangle, sourceRegion :Rectangle, borderRegion :Rectangle, mode :DrawMode, alpha :u16, clipRegion :Rectangle) -> Error{ addr := 0x1000 + 56 * size_of(int); return ((proc (Handle, Handle, Rectangle, Rectangle, Rectangle, DrawMode, u16, Rectangle) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(destination, source, destinationRegion, sourceRegion, borderRegion, mode, alpha, clipRegion); } +DrawBitmap :: inline proc (destination :Handle, destinationPoint :Point, bitmap :^rawptr, width :uintptr, height :uintptr, stride :uintptr, colorFormat :ColorFormat){ addr := 0x1000 + 57 * size_of(int); ((proc (Handle, Point, ^rawptr, uintptr, uintptr, uintptr, ColorFormat))(rawptr(((^uintptr)(uintptr(addr)))^)))(destination, destinationPoint, bitmap, width, height, stride, colorFormat); } +SurfaceClearInvalidatedRegion :: inline proc (surface :Handle){ addr := 0x1000 + 58 * size_of(int); ((proc (Handle))(rawptr(((^uintptr)(uintptr(addr)))^)))(surface); } +RectangleClip :: inline proc (parent :Rectangle, rectangle :Rectangle, output :^Rectangle) -> bool{ addr := 0x1000 + 59 * size_of(int); return ((proc (Rectangle, Rectangle, ^Rectangle) -> bool)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, rectangle, output); } +DrawBox :: inline proc (surface :Handle, rectangle :Rectangle, style :u8, color :u32, clipRegion :Rectangle){ addr := 0x1000 + 60 * size_of(int); ((proc (Handle, Rectangle, u8, u32, Rectangle))(rawptr(((^uintptr)(uintptr(addr)))^)))(surface, rectangle, style, color, clipRegion); } +RedrawAll :: inline proc (){ addr := 0x1000 + 61 * size_of(int); ((proc ())(rawptr(((^uintptr)(uintptr(addr)))^)))(); } +MessagePost :: inline proc (message :^Message) -> Error{ addr := 0x1000 + 62 * size_of(int); return ((proc (^Message) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(message); } +MessagePostRemote :: inline proc (process :Handle, message :^Message) -> Error{ addr := 0x1000 + 63 * size_of(int); return ((proc (Handle, ^Message) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(process, message); } +ExtractArguments :: inline proc (string :^i8, bytes :uintptr, delimiterByte :u8, replacementDelimiter :u8, argvAllocated :uintptr, argv :^^i8, argc :^uintptr) -> bool{ addr := 0x1000 + 64 * size_of(int); return ((proc (^i8, uintptr, u8, u8, uintptr, ^^i8, ^uintptr) -> bool)(rawptr(((^uintptr)(uintptr(addr)))^)))(string, bytes, delimiterByte, replacementDelimiter, argvAllocated, argv, argc); } +CStringLength :: inline proc (string :^i8) -> uintptr{ addr := 0x1000 + 65 * size_of(int); return ((proc (^i8) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(string); } +StringLength :: inline proc (string :^i8, end :u8) -> uintptr{ addr := 0x1000 + 66 * size_of(int); return ((proc (^i8, u8) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(string, end); } +MemoryCopy :: inline proc (destination :^rawptr, source :^rawptr, bytes :uintptr){ addr := 0x1000 + 67 * size_of(int); ((proc (^rawptr, ^rawptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(destination, source, bytes); } +MemoryMove :: inline proc (_start :^rawptr, _end :^rawptr, amount :int, zeroEmptySpace :bool){ addr := 0x1000 + 68 * size_of(int); ((proc (^rawptr, ^rawptr, int, bool))(rawptr(((^uintptr)(uintptr(addr)))^)))(_start, _end, amount, zeroEmptySpace); } +MemoryCopyReverse :: inline proc (_destination :^rawptr, _source :^rawptr, bytes :uintptr){ addr := 0x1000 + 69 * size_of(int); ((proc (^rawptr, ^rawptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(_destination, _source, bytes); } +MemoryZero :: inline proc (destination :^rawptr, bytes :uintptr){ addr := 0x1000 + 70 * size_of(int); ((proc (^rawptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(destination, bytes); } +MemoryCompare :: inline proc (a :^rawptr, b :^rawptr, bytes :uintptr) -> i32{ addr := 0x1000 + 71 * size_of(int); return ((proc (^rawptr, ^rawptr, uintptr) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(a, b, bytes); } +MemorySumBytes :: inline proc (data :^u8, bytes :uintptr) -> u8{ addr := 0x1000 + 72 * size_of(int); return ((proc (^u8, uintptr) -> u8)(rawptr(((^uintptr)(uintptr(addr)))^)))(data, bytes); } +PrintDirect :: inline proc (string :^i8, stringLength :uintptr){ addr := 0x1000 + 73 * size_of(int); ((proc (^i8, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(string, stringLength); } +StringFormat :: inline proc (buffer :^i8, bufferLength :uintptr, format :^i8, args : ..any) -> uintptr{ addr := 0x1000 + 74 * size_of(int); return ((proc (^i8, uintptr, ^i8, ..any) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(buffer, bufferLength, format, ); } +StringFormatAppend :: inline proc (buffer :^i8, bufferLength :uintptr, bufferPosition :^uintptr, format :^i8, args : ..any){ addr := 0x1000 + 75 * size_of(int); ((proc (^i8, uintptr, ^uintptr, ^i8, ..any))(rawptr(((^uintptr)(uintptr(addr)))^)))(buffer, bufferLength, bufferPosition, format, ); } +PrintHelloWorld :: inline proc (){ addr := 0x1000 + 76 * size_of(int); ((proc ())(rawptr(((^uintptr)(uintptr(addr)))^)))(); } +GetRandomByte :: inline proc () -> u8{ addr := 0x1000 + 77 * size_of(int); return ((proc () -> u8)(rawptr(((^uintptr)(uintptr(addr)))^)))(); } +Sort :: inline proc (_base :^rawptr, nmemb :uintptr, size :uintptr, compar :ComparisonCallbackFunction, argument :Generic){ addr := 0x1000 + 78 * size_of(int); ((proc (^rawptr, uintptr, uintptr, ComparisonCallbackFunction, Generic))(rawptr(((^uintptr)(uintptr(addr)))^)))(_base, nmemb, size, compar, argument); } +SortWithSwapCallback :: inline proc (_base :^rawptr, nmemb :uintptr, size :uintptr, compar :ComparisonCallbackFunction, argument :Generic, swap :SwapCallbackFunction){ addr := 0x1000 + 79 * size_of(int); ((proc (^rawptr, uintptr, uintptr, ComparisonCallbackFunction, Generic, SwapCallbackFunction))(rawptr(((^uintptr)(uintptr(addr)))^)))(_base, nmemb, size, compar, argument, swap); } +StringCompare :: inline proc (s1 :^i8, s2 :^i8, length1 :uintptr, length2 :uintptr) -> i32{ addr := 0x1000 + 80 * size_of(int); return ((proc (^i8, ^i8, uintptr, uintptr) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(s1, s2, length1, length2); } +IntegerParse :: inline proc (text :^i8, bytes :uintptr) -> i64{ addr := 0x1000 + 81 * size_of(int); return ((proc (^i8, uintptr) -> i64)(rawptr(((^uintptr)(uintptr(addr)))^)))(text, bytes); } +CRTmemset :: inline proc (s :^rawptr, c :i32, n :uintptr){ addr := 0x1000 + 82 * size_of(int); ((proc (^rawptr, i32, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(s, c, n); } +CRTmemcpy :: inline proc (dest :^rawptr, src :^rawptr, n :uintptr){ addr := 0x1000 + 83 * size_of(int); ((proc (^rawptr, ^rawptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(dest, src, n); } +CRTmemmove :: inline proc (dest :^rawptr, src :^rawptr, n :uintptr){ addr := 0x1000 + 84 * size_of(int); ((proc (^rawptr, ^rawptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(dest, src, n); } +CRTstrlen :: inline proc (s :^i8) -> uintptr{ addr := 0x1000 + 85 * size_of(int); return ((proc (^i8) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(s); } +CRTstrnlen :: inline proc (s :^i8, maxlen :uintptr) -> uintptr{ addr := 0x1000 + 86 * size_of(int); return ((proc (^i8, uintptr) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(s, maxlen); } +CRTmalloc :: inline proc (size :uintptr){ addr := 0x1000 + 87 * size_of(int); ((proc (uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(size); } +CRTcalloc :: inline proc (num :uintptr, size :uintptr){ addr := 0x1000 + 88 * size_of(int); ((proc (uintptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(num, size); } +CRTfree :: inline proc (ptr :^rawptr){ addr := 0x1000 + 89 * size_of(int); ((proc (^rawptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(ptr); } +CRTabs :: inline proc (n :i32) -> i32{ addr := 0x1000 + 90 * size_of(int); return ((proc (i32) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(n); } +CRTrealloc :: inline proc (ptr :^rawptr, size :uintptr){ addr := 0x1000 + 91 * size_of(int); ((proc (^rawptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(ptr, size); } +CRTgetenv :: inline proc (name :^i8) -> ^i8{ addr := 0x1000 + 92 * size_of(int); return ((proc (^i8) -> ^i8)(rawptr(((^uintptr)(uintptr(addr)))^)))(name); } +CRTstrncmp :: inline proc (s1 :^i8, s2 :^i8, n :uintptr) -> i32{ addr := 0x1000 + 93 * size_of(int); return ((proc (^i8, ^i8, uintptr) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(s1, s2, n); } +CRTmemcmp :: inline proc (s1 :^rawptr, s2 :^rawptr, n :uintptr) -> i32{ addr := 0x1000 + 94 * size_of(int); return ((proc (^rawptr, ^rawptr, uintptr) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(s1, s2, n); } +CRTqsort :: inline proc (_base :^rawptr, nmemb :uintptr, size :uintptr, compar :CRTComparisonCallback){ addr := 0x1000 + 95 * size_of(int); ((proc (^rawptr, uintptr, uintptr, CRTComparisonCallback))(rawptr(((^uintptr)(uintptr(addr)))^)))(_base, nmemb, size, compar); } +CRTstrcmp :: inline proc (s1 :^i8, s2 :^i8) -> i32{ addr := 0x1000 + 96 * size_of(int); return ((proc (^i8, ^i8) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(s1, s2); } +CRTstrstr :: inline proc (haystack :^i8, needle :^i8) -> ^i8{ addr := 0x1000 + 97 * size_of(int); return ((proc (^i8, ^i8) -> ^i8)(rawptr(((^uintptr)(uintptr(addr)))^)))(haystack, needle); } +CRTstrcpy :: inline proc (dest :^i8, src :^i8) -> ^i8{ addr := 0x1000 + 98 * size_of(int); return ((proc (^i8, ^i8) -> ^i8)(rawptr(((^uintptr)(uintptr(addr)))^)))(dest, src); } +CRTisalpha :: inline proc (c :i32) -> i32{ addr := 0x1000 + 99 * size_of(int); return ((proc (i32) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(c); } +CRTmemchr :: inline proc (_s :^rawptr, _c :i32, n :uintptr){ addr := 0x1000 + 100 * size_of(int); ((proc (^rawptr, i32, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(_s, _c, n); } +CRTisdigit :: inline proc (c :i32) -> i32{ addr := 0x1000 + 101 * size_of(int); return ((proc (i32) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(c); } +CRTstrcat :: inline proc (dest :^i8, src :^i8) -> ^i8{ addr := 0x1000 + 102 * size_of(int); return ((proc (^i8, ^i8) -> ^i8)(rawptr(((^uintptr)(uintptr(addr)))^)))(dest, src); } +CRTtolower :: inline proc (c :i32) -> i32{ addr := 0x1000 + 103 * size_of(int); return ((proc (i32) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(c); } +CRTstrncpy :: inline proc (dest :^i8, src :^i8, n :uintptr) -> ^i8{ addr := 0x1000 + 104 * size_of(int); return ((proc (^i8, ^i8, uintptr) -> ^i8)(rawptr(((^uintptr)(uintptr(addr)))^)))(dest, src, n); } +CRTstrtoul :: inline proc (nptr :^i8, endptr :^^i8, base :i32) -> u64{ addr := 0x1000 + 105 * size_of(int); return ((proc (^i8, ^^i8, i32) -> u64)(rawptr(((^uintptr)(uintptr(addr)))^)))(nptr, endptr, base); } +Execute :: inline proc (what :^i8, whatBytes :uintptr, argument :^i8, argumentBytes :uintptr){ addr := 0x1000 + 106 * size_of(int); ((proc (^i8, uintptr, ^i8, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(what, whatBytes, argument, argumentBytes); } +Abort :: inline proc (){ addr := 0x1000 + 107 * size_of(int); ((proc ())(rawptr(((^uintptr)(uintptr(addr)))^)))(); } +MailslotSendData :: inline proc (mailslot :Handle, data :^rawptr, bytes :uintptr) -> bool{ addr := 0x1000 + 108 * size_of(int); return ((proc (Handle, ^rawptr, uintptr) -> bool)(rawptr(((^uintptr)(uintptr(addr)))^)))(mailslot, data, bytes); } +CRTfloorf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 109 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); } +CRTceilf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 110 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); } +CRTsinf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 111 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); } +CRTcosf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 112 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); } +CRTatan2f :: inline proc (y :f32, x :f32) -> f32{ addr := 0x1000 + 113 * size_of(int); return ((proc (f32, f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(y, x); } +CRTfmodf :: inline proc (x :f32, y :f32) -> f32{ addr := 0x1000 + 114 * size_of(int); return ((proc (f32, f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x, y); } +CRTacosf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 115 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); } +CRTasinf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 116 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); } +CRTatanf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 117 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); } +RandomSeed :: inline proc (x :u64){ addr := 0x1000 + 118 * size_of(int); ((proc (u64))(rawptr(((^uintptr)(uintptr(addr)))^)))(x); } +CRTsqrtf :: inline proc (x :f32) -> f32{ addr := 0x1000 + 119 * size_of(int); return ((proc (f32) -> f32)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); } +CRTsqrtl :: inline proc (x :LongDouble) -> LongDouble{ addr := 0x1000 + 120 * size_of(int); return ((proc (LongDouble) -> LongDouble)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); } +CRTfabsl :: inline proc (x :LongDouble) -> LongDouble{ addr := 0x1000 + 121 * size_of(int); return ((proc (LongDouble) -> LongDouble)(rawptr(((^uintptr)(uintptr(addr)))^)))(x); } +Syscall :: inline proc (a :uintptr, b :uintptr, c :uintptr, d :uintptr, e :uintptr, f :uintptr) -> uintptr{ addr := 0x1000 + 122 * size_of(int); return ((proc (uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(a, b, c, d, e, f); } +ProcessorReadTimeStamp :: inline proc () -> u64{ addr := 0x1000 + 123 * size_of(int); return ((proc () -> u64)(rawptr(((^uintptr)(uintptr(addr)))^)))(); } +HeapAllocate :: inline proc (size :uintptr, zeroMemory :bool){ addr := 0x1000 + 124 * size_of(int); ((proc (uintptr, bool))(rawptr(((^uintptr)(uintptr(addr)))^)))(size, zeroMemory); } +HeapFree :: inline proc (address :^rawptr){ addr := 0x1000 + 125 * size_of(int); ((proc (^rawptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(address); } +Print :: inline proc (format :^i8, args : ..any){ addr := 0x1000 + 126 * size_of(int); ((proc (^i8, ..any))(rawptr(((^uintptr)(uintptr(addr)))^)))(format, ); } +MemoryFill :: inline proc (from :^rawptr, to :^rawptr, byte :u8){ addr := 0x1000 + 127 * size_of(int); ((proc (^rawptr, ^rawptr, u8))(rawptr(((^uintptr)(uintptr(addr)))^)))(from, to, byte); } +InitialiseCStandardLibrary :: inline proc (argc :^i32, argv :^^^i8){ addr := 0x1000 + 128 * size_of(int); ((proc (^i32, ^^^i8))(rawptr(((^uintptr)(uintptr(addr)))^)))(argc, argv); } +MakeLinuxSystemCall2 :: inline proc (n :int, a1 :int, a2 :int, a3 :int, a4 :int, a5 :int, a6 :int) -> int{ addr := 0x1000 + 129 * size_of(int); return ((proc (int, int, int, int, int, int, int) -> int)(rawptr(((^uintptr)(uintptr(addr)))^)))(n, a1, a2, a3, a4, a5, a6); } +ProcessCreate2 :: inline proc (arguments :^ProcessCreationArguments, information :^ProcessInformation) -> Error{ addr := 0x1000 + 130 * size_of(int); return ((proc (^ProcessCreationArguments, ^ProcessInformation) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(arguments, information); } +CRTatoi :: inline proc (string :^i8) -> i32{ addr := 0x1000 + 131 * size_of(int); return ((proc (^i8) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(string); } +ProcessGetExitStatus :: inline proc (process :Handle) -> i32{ addr := 0x1000 + 132 * size_of(int); return ((proc (Handle) -> i32)(rawptr(((^uintptr)(uintptr(addr)))^)))(process); } +SurfaceReset :: inline proc (surface :Handle){ addr := 0x1000 + 133 * size_of(int); ((proc (Handle))(rawptr(((^uintptr)(uintptr(addr)))^)))(surface); } +TimerCreate :: inline proc () -> Handle{ addr := 0x1000 + 134 * size_of(int); return ((proc () -> Handle)(rawptr(((^uintptr)(uintptr(addr)))^)))(); } +TimerSet :: inline proc (handle :Handle, afterMs :u64, object :Object, argument :Generic){ addr := 0x1000 + 135 * size_of(int); ((proc (Handle, u64, Object, Generic))(rawptr(((^uintptr)(uintptr(addr)))^)))(handle, afterMs, object, argument); } +FileWriteAll :: inline proc (filePath :^i8, filePathLength :uintptr, data :^rawptr, fileSize :uintptr) -> Error{ addr := 0x1000 + 136 * size_of(int); return ((proc (^i8, uintptr, ^rawptr, uintptr) -> Error)(rawptr(((^uintptr)(uintptr(addr)))^)))(filePath, filePathLength, data, fileSize); } +UserGetHomeFolder :: inline proc (buffer :^i8, bufferBytes :uintptr) -> uintptr{ addr := 0x1000 + 137 * size_of(int); return ((proc (^i8, uintptr) -> uintptr)(rawptr(((^uintptr)(uintptr(addr)))^)))(buffer, bufferBytes); } +Assert :: inline proc (expression :bool, failureMessage :^i8){ addr := 0x1000 + 138 * size_of(int); ((proc (bool, ^i8))(rawptr(((^uintptr)(uintptr(addr)))^)))(expression, failureMessage); } +ResizeArray :: inline proc (array :^^rawptr, allocated :^uintptr, needed :uintptr, itemSize :uintptr){ addr := 0x1000 + 139 * size_of(int); ((proc (^^rawptr, ^uintptr, uintptr, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(array, allocated, needed, itemSize); } +MessageLoopEnter :: inline proc (callback :MessageCallbackFunction = nil){ addr := 0x1000 + 140 * size_of(int); ((proc (MessageCallbackFunction))(rawptr(((^uintptr)(uintptr(addr)))^)))(callback); } +InstanceCreate :: inline proc (bytes :uintptr) -> ^Instance{ addr := 0x1000 + 141 * size_of(int); return ((proc (uintptr) -> ^Instance)(rawptr(((^uintptr)(uintptr(addr)))^)))(bytes); } +MouseGetPosition :: inline proc (relativeWindow :^Window = nil) -> Point{ addr := 0x1000 + 142 * size_of(int); return ((proc (^Window) -> Point)(rawptr(((^uintptr)(uintptr(addr)))^)))(relativeWindow); } +MouseSetPosition :: inline proc (relativeWindow :^Window, x :i32, y :i32){ addr := 0x1000 + 143 * size_of(int); ((proc (^Window, i32, i32))(rawptr(((^uintptr)(uintptr(addr)))^)))(relativeWindow, x, y); } +NewPanel :: inline proc (parent :^Element, cStyle :^i8, flags :u64 = FLAGS_DEFAULT) -> ^Panel{ addr := 0x1000 + 144 * size_of(int); return ((proc (^Element, ^i8, u64) -> ^Panel)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, cStyle, flags); } +NewCustomPanel :: inline proc (parent :^Element, style :Data, flags :u64 = FLAGS_DEFAULT) -> ^Panel{ addr := 0x1000 + 145 * size_of(int); return ((proc (^Element, Data, u64) -> ^Panel)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, style, flags); } +NewWindow :: inline proc (instance :^Instance, style :WindowStyle = WindowStyle.WINDOW_NORMAL) -> ^Window{ addr := 0x1000 + 146 * size_of(int); return ((proc (^Instance, WindowStyle) -> ^Window)(rawptr(((^uintptr)(uintptr(addr)))^)))(instance, style); } +NewScrollbar :: inline proc (parent :^Element, flags :u64 = FLAGS_DEFAULT, userCallback :UICallbackFunction = nil, _context :Generic = nil) -> ^Scrollbar{ addr := 0x1000 + 147 * size_of(int); return ((proc (^Element, u64, UICallbackFunction, Generic) -> ^Scrollbar)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, flags, userCallback, _context); } +NewButton :: inline proc (parent :^Element, label :^i8 = nil, labelBytes :int = -1, flags :u64 = FLAGS_DEFAULT, userCallback :UICallbackFunction = nil, _context :Generic = nil) -> ^Button{ addr := 0x1000 + 148 * size_of(int); return ((proc (^Element, ^i8, int, u64, UICallbackFunction, Generic) -> ^Button)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, label, labelBytes, flags, userCallback, _context); } +NewTextbox :: inline proc (parent :^Element, flags :u64 = FLAGS_DEFAULT, userCallback :UICallbackFunction = nil, _context :Generic = nil) -> ^Textbox{ addr := 0x1000 + 149 * size_of(int); return ((proc (^Element, u64, UICallbackFunction, Generic) -> ^Textbox)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, flags, userCallback, _context); } +NewNumericEntry :: inline proc (parent :^Element, flags :u64 = FLAGS_DEFAULT, userCallback :UICallbackFunction = nil, _context :Generic = nil) -> ^NumericEntry{ addr := 0x1000 + 150 * size_of(int); return ((proc (^Element, u64, UICallbackFunction, Generic) -> ^NumericEntry)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, flags, userCallback, _context); } +NewListView :: inline proc (parent :^Element, flags :u64 = FLAGS_DEFAULT, style :^ListViewStyle = nil, userCallback :UICallbackFunction = nil, _context :Generic = nil) -> ^ListView{ addr := 0x1000 + 151 * size_of(int); return ((proc (^Element, u64, ^ListViewStyle, UICallbackFunction, Generic) -> ^ListView)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, flags, style, userCallback, _context); } +NewMenu :: inline proc (parent :^Element, flags :u64 = FLAGS_DEFAULT, userCallback :MenuCallbackFunction = nil, _context :Generic = nil) -> ^Menu{ addr := 0x1000 + 152 * size_of(int); return ((proc (^Element, u64, MenuCallbackFunction, Generic) -> ^Menu)(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, flags, userCallback, _context); } +NewMenuItem :: inline proc (parent :^Element, flags :u64, label :^i8, labelBytes :int = -1, callback :MenuCallbackFunction = nil, _context :Generic = nil){ addr := 0x1000 + 153 * size_of(int); ((proc (^Element, u64, ^i8, int, MenuCallbackFunction, Generic))(rawptr(((^uintptr)(uintptr(addr)))^)))(parent, flags, label, labelBytes, callback, _context); } +ElementGetInstance :: inline proc (element :^Element) -> ^INSTANCE_TYPE{ addr := 0x1000 + 154 * size_of(int); return ((proc (^Element) -> ^INSTANCE_TYPE)(rawptr(((^uintptr)(uintptr(addr)))^)))(element); } +ElementFocus :: inline proc (element :^Element, ensureVisible :bool){ addr := 0x1000 + 155 * size_of(int); ((proc (^Element, bool))(rawptr(((^uintptr)(uintptr(addr)))^)))(element, ensureVisible); } +ElementSetDisabled :: inline proc (element :^Element, disabled :bool){ addr := 0x1000 + 156 * size_of(int); ((proc (^Element, bool))(rawptr(((^uintptr)(uintptr(addr)))^)))(element, disabled); } +ElementSetCallback :: inline proc (element :^Element, callback :UICallbackFunction, _context :Generic){ addr := 0x1000 + 157 * size_of(int); ((proc (^Element, UICallbackFunction, Generic))(rawptr(((^uintptr)(uintptr(addr)))^)))(element, callback, _context); } +ScrollbarSetMeasurements :: inline proc (scrollbar :^Scrollbar, viewportSize :i32, contentSize :i32){ addr := 0x1000 + 158 * size_of(int); ((proc (^Scrollbar, i32, i32))(rawptr(((^uintptr)(uintptr(addr)))^)))(scrollbar, viewportSize, contentSize); } +ScrollbarSetPosition :: inline proc (scrollbar :^Scrollbar, position :f32, sendMovedMessage :bool, smoothScroll :bool){ addr := 0x1000 + 159 * size_of(int); ((proc (^Scrollbar, f32, bool, bool))(rawptr(((^uintptr)(uintptr(addr)))^)))(scrollbar, position, sendMovedMessage, smoothScroll); } +WindowGetBounds :: inline proc (window :^Window) -> Rectangle{ addr := 0x1000 + 160 * size_of(int); return ((proc (^Window) -> Rectangle)(rawptr(((^uintptr)(uintptr(addr)))^)))(window); } +WindowGetToolbar :: inline proc (window :^Window) -> ^Element{ addr := 0x1000 + 161 * size_of(int); return ((proc (^Window) -> ^Element)(rawptr(((^uintptr)(uintptr(addr)))^)))(window); } +ListViewInsert :: inline proc (listView :^ListView, group :ListViewIndex, index :ListViewIndex, count :uintptr){ addr := 0x1000 + 162 * size_of(int); ((proc (^ListView, ListViewIndex, ListViewIndex, uintptr))(rawptr(((^uintptr)(uintptr(addr)))^)))(listView, group, index, count); } +ListViewInsertGroup :: inline proc (listView :^ListView, group :ListViewIndex){ addr := 0x1000 + 163 * size_of(int); ((proc (^ListView, ListViewIndex))(rawptr(((^uintptr)(uintptr(addr)))^)))(listView, group); } +ListViewRemove :: inline proc (listView :^ListView, group :ListViewIndex, index :ListViewIndex, count :int, removedHeight :i32){ addr := 0x1000 + 164 * size_of(int); ((proc (^ListView, ListViewIndex, ListViewIndex, int, i32))(rawptr(((^uintptr)(uintptr(addr)))^)))(listView, group, index, count, removedHeight); } +ListViewRemoveGroup :: inline proc (listView :^ListView, group :ListViewIndex){ addr := 0x1000 + 165 * size_of(int); ((proc (^ListView, ListViewIndex))(rawptr(((^uintptr)(uintptr(addr)))^)))(listView, group); } +ListViewInvalidate :: inline proc (listView :^ListView, deltaHeight :i32, recalculateHeight :bool){ addr := 0x1000 + 166 * size_of(int); ((proc (^ListView, i32, bool))(rawptr(((^uintptr)(uintptr(addr)))^)))(listView, deltaHeight, recalculateHeight); } +ListViewEnsureVisible :: inline proc (listView :^ListView, group :ListViewIndex, index :ListViewIndex){ addr := 0x1000 + 167 * size_of(int); ((proc (^ListView, ListViewIndex, ListViewIndex))(rawptr(((^uintptr)(uintptr(addr)))^)))(listView, group, index); } +ListViewResetSearchBuffer :: inline proc (listView :^ListView){ addr := 0x1000 + 168 * size_of(int); ((proc (^ListView))(rawptr(((^uintptr)(uintptr(addr)))^)))(listView); } +ButtonSetIcon :: inline proc (button :^Button, iconID :u32){ addr := 0x1000 + 169 * size_of(int); ((proc (^Button, u32))(rawptr(((^uintptr)(uintptr(addr)))^)))(button, iconID); } +DataParse :: inline proc (cFormat :^i8, args : ..any) -> Data{ addr := 0x1000 + 170 * size_of(int); return ((proc (^i8, ..any) -> Data)(rawptr(((^uintptr)(uintptr(addr)))^)))(cFormat, ); } + ////////////////////////////////////////////////////// -Handle :: distinct i32; Errno :: distinct i32; -INVALID_HANDLE :: ~Handle(0); - stdin: Handle = 0; stdout: Handle = 1; stderr: Handle = 2; @@ -1309,6 +2393,7 @@ O_SYNC :: 0x01000; O_ASYNC :: 0x02000; O_CLOEXEC :: 0x80000; +ERROR_SUCCESS :: 0; ERROR_UNSUPPORTED :: 1; read :: proc(fd: Handle, data: []byte) -> (int, Errno) { @@ -1316,11 +2401,16 @@ read :: proc(fd: Handle, data: []byte) -> (int, Errno) { } write :: proc(fd: Handle, data: []byte) -> (int, Errno) { + if (fd == stdout) { + PrintDirect((^i8)(&data[0]), (uintptr)(len(data))); + return len(data), ERROR_SUCCESS; + } + return -1, ERROR_UNSUPPORTED; } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { - return -1, ERROR_UNSUPPORTED; + return INVALID_HANDLE, ERROR_UNSUPPORTED; } close :: proc(fd: Handle) -> Errno { From 48ab7f876c51dfb009f8ff53d345bb575ce4fb4c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 25 Sep 2019 20:52:47 +0100 Subject: [PATCH 076/143] Fix Implicit Selector Expressions do not work for parameteric struct parameters. #438 --- src/check_expr.cpp | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5ef42a3fc..5535e6772 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6078,6 +6078,19 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper for_array(i, ce->args) { Ast *arg = ce->args[i]; ast_node(fv, FieldValue, arg); + + if (fv->field->kind == Ast_Ident) { + String name = fv->field->Ident.token.string; + isize index = lookup_polymorphic_record_parameter(original_type, name); + if (index >= 0) { + TypeTuple *params = get_record_polymorphic_params(original_type); + Entity *e = params->variables[i]; + if (e->kind == Entity_Constant) { + check_expr_with_type_hint(c, &operands[i], fv->value, e->type); + } + } + + } check_expr_or_type(c, &operands[i], fv->value); } @@ -6088,7 +6101,17 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper } else { operands = array_make(heap_allocator(), 0, 2*ce->args.count); - check_unpack_arguments(c, nullptr, -1, &operands, ce->args, false, false); + + Entity **lhs = nullptr; + isize lhs_count = -1; + + TypeTuple *params = get_record_polymorphic_params(original_type); + if (params != nullptr) { + lhs = params->variables.data; + lhs_count = params->variables.count; + } + + check_unpack_arguments(c, lhs, lhs_count, &operands, ce->args, false, false); } CallArgumentError err = CallArgumentError_None; @@ -6217,6 +6240,9 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper } score += s; } + + // NOTE(bill): Add type info the parameters + add_type_info_type(c, o->type); } { From f4f6e9ad49d6992712815bc7b2e94c8333f33523 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 25 Sep 2019 21:07:56 +0100 Subject: [PATCH 077/143] Fix -debug crash on windows caused by missing debug info for files. --- core/os/os_windows.odin | 2 +- src/ir.cpp | 13 ++++++++++++- src/ir_print.cpp | 6 ++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index 9618f83be..e45cf9f5f 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -322,4 +322,4 @@ is_windows_8_1 :: proc() -> bool { is_windows_10 :: proc() -> bool { osvi := get_windows_version_ansi(); return (osvi.major_version == 10 && osvi.minor_version == 0); -} \ No newline at end of file +} diff --git a/src/ir.cpp b/src/ir.cpp index 1c326359b..758267c24 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10028,7 +10028,11 @@ void ir_init_module(irModule *m, Checker *c) { { irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompileUnit); - di->CompileUnit.file = m->info->files.entries[0].value; // Zeroth is the init file + + GB_ASSERT(m->info->files.entries.count > 0); + AstFile *file = m->info->files.entries[0].value; + + di->CompileUnit.file = file; // Zeroth is the init file di->CompileUnit.producer = str_lit("odin"); map_set(&m->debug_info, hash_pointer(m), di); @@ -10047,6 +10051,13 @@ void ir_init_module(irModule *m, Checker *c) { array_init(&m->debug_location_stack, heap_allocator()); // TODO(lachsinc): ir_allocator() ?? } + + { + for_array(i, m->info->files.entries) { + AstFile *file = m->info->files.entries[i].value; + ir_add_debug_info_file(m, file); + } + } } void ir_destroy_module(irModule *m) { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 30ad914a9..9414a2338 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2450,11 +2450,13 @@ void print_llvm_ir(irGen *ir) { for_array(di_index, m->debug_info.entries) { irDebugInfo *di = m->debug_info.entries[di_index].value; + GB_ASSERT_MSG(di != nullptr, "Invalid irDebugInfo"); ir_fprintf(f, "!%d = ", di->id); - switch (di->kind) { case irDebugInfo_CompileUnit: { - irDebugInfo *file = *map_get(&m->debug_info, hash_pointer(di->CompileUnit.file)); + irDebugInfo **found = map_get(&m->debug_info, hash_pointer(di->CompileUnit.file)); + GB_ASSERT_MSG(found != nullptr, "Missing debug info for: %.*s\n", LIT(di->CompileUnit.file->fullpath)); + irDebugInfo *file = *found; ir_fprintf(f, "distinct !DICompileUnit(" "language: DW_LANG_C_plus_plus" // Is this good enough? From 218d1131e84c4c45da8b9796f46d52094df2962e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Sep 2019 09:25:33 +0100 Subject: [PATCH 078/143] Change how foreign imports work for mac --- src/main.cpp | 8 +++++++- src/unicode.cpp | 1 - src/utf8proc/utf8proc.c | 1 - 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index e6af04a3a..b294e7f96 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1242,12 +1242,18 @@ int main(int arg_count, char **arg_ptr) { if (lib.len > 2 && lib[0] == '-' && lib[1] == 'f') { // framework thingie lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2); + } else if (string_ends_with(lib, str_lit(".framework"))) { + // framework thingie + String lib_name = lib; + lib_name = remove_extension_from_path(lib_name); + lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name)); } else if (string_ends_with(lib, str_lit(".a"))) { // static libs, absolute full path relative to the file in which the lib was imported from lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); } else if (string_ends_with(lib, str_lit(".dylib"))) { // dynamic lib, relative path to executable - lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib)); + // lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib)); + lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); } else { // dynamic or static system lib, just link regularly searching system library paths lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); diff --git a/src/unicode.cpp b/src/unicode.cpp index 0ad658806..679d56365 100644 --- a/src/unicode.cpp +++ b/src/unicode.cpp @@ -2,7 +2,6 @@ #pragma warning(disable: 4245) extern "C" { -#include "utf8proc/utf8proc.h" #include "utf8proc/utf8proc.c" } #pragma warning(pop) diff --git a/src/utf8proc/utf8proc.c b/src/utf8proc/utf8proc.c index e821889c6..29fc250fc 100644 --- a/src/utf8proc/utf8proc.c +++ b/src/utf8proc/utf8proc.c @@ -40,7 +40,6 @@ * Implementation of libutf8proc. */ - #include "utf8proc.h" #include "utf8proc_data.c" From 66ae4e5afc87e4804cf371b49cc68cbecf253373 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 1 Oct 2019 20:38:50 +0100 Subject: [PATCH 079/143] Change ODIN_OS string for osx from "osx" to "darwin" to allow for other platforms --- core/os/os_darwin.odin | 295 ++++++++++++++++++ core/time/{time_osx.odin => time_darwin.odin} | 0 src/build_settings.cpp | 16 +- src/check_type.cpp | 2 +- src/ir_print.cpp | 14 +- 5 files changed, 313 insertions(+), 14 deletions(-) create mode 100644 core/os/os_darwin.odin rename core/time/{time_osx.odin => time_darwin.odin} (100%) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin new file mode 100644 index 000000000..7b183b3aa --- /dev/null +++ b/core/os/os_darwin.odin @@ -0,0 +1,295 @@ +package os + +foreign import dl "system:dl" +foreign import libc "system:c" + +import "core:runtime" +import "core:strings" + +OS :: "darwin"; + +Handle :: distinct i32; +File_Time :: distinct u64; +Errno :: distinct int; + +INVALID_HANDLE :: ~Handle(0); + +O_RDONLY :: 0x00000; +O_WRONLY :: 0x00001; +O_RDWR :: 0x00002; +O_CREATE :: 0x00040; +O_EXCL :: 0x00080; +O_NOCTTY :: 0x00100; +O_TRUNC :: 0x00200; +O_NONBLOCK :: 0x00800; +O_APPEND :: 0x00400; +O_SYNC :: 0x01000; +O_ASYNC :: 0x02000; +O_CLOEXEC :: 0x80000; + + +SEEK_SET :: 0; +SEEK_CUR :: 1; +SEEK_END :: 2; +SEEK_DATA :: 3; +SEEK_HOLE :: 4; +SEEK_MAX :: SEEK_HOLE; + + + +// NOTE(zangent): These are OS specific! +// Do not mix these up! +RTLD_LAZY :: 0x1; +RTLD_NOW :: 0x2; +RTLD_LOCAL :: 0x4; +RTLD_GLOBAL :: 0x8; +RTLD_NODELETE :: 0x80; +RTLD_NOLOAD :: 0x10; +RTLD_FIRST :: 0x100; + + +// "Argv" arguments converted to Odin strings +args := _alloc_command_line_arguments(); + +_File_Time :: struct { + seconds: i64, + nanoseconds: i64, +} + +Stat :: struct { + device_id: i32, // ID of device containing file + mode: u16, // Mode of the file + nlink: u16, // Number of hard links + serial: u64, // File serial number + uid: u32, // User ID of the file's owner + gid: u32, // Group ID of the file's group + rdev: i32, // Device ID, if device + + last_access: File_Time, // Time of last access + modified: File_Time, // Time of last modification + status_change: File_Time, // Time of last status change + created: File_Time, // Time of creation + + size: i64, // Size of the file, in bytes + blocks: i64, // Number of blocks allocated for the file + block_size: i32, // Optimal blocksize for I/O + flags: u32, // User-defined flags for the file + gen_num: u32, // File generation number ..? + _spare: i32, // RESERVED + _reserve1, + _reserve2: i64, // RESERVED +}; + +// File type +S_IFMT :: 0o170000; // Type of file mask +S_IFIFO :: 0o010000; // Named pipe (fifo) +S_IFCHR :: 0o020000; // Character special +S_IFDIR :: 0o040000; // Directory +S_IFBLK :: 0o060000; // Block special +S_IFREG :: 0o100000; // Regular +S_IFLNK :: 0o120000; // Symbolic link +S_IFSOCK :: 0o140000; // Socket + +// File mode +// Read, write, execute/search by owner +S_IRWXU :: 0o0700; // RWX mask for owner +S_IRUSR :: 0o0400; // R for owner +S_IWUSR :: 0o0200; // W for owner +S_IXUSR :: 0o0100; // X for owner + +// Read, write, execute/search by group +S_IRWXG :: 0o0070; // RWX mask for group +S_IRGRP :: 0o0040; // R for group +S_IWGRP :: 0o0020; // W for group +S_IXGRP :: 0o0010; // X for group + +// Read, write, execute/search by others +S_IRWXO :: 0o0007; // RWX mask for other +S_IROTH :: 0o0004; // R for other +S_IWOTH :: 0o0002; // W for other +S_IXOTH :: 0o0001; // X for other + +S_ISUID :: 0o4000; // Set user id on execution +S_ISGID :: 0o2000; // Set group id on execution +S_ISVTX :: 0o1000; // Directory restrcted delete + +S_ISLNK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFLNK; +S_ISREG :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFREG; +S_ISDIR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFDIR; +S_ISCHR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFCHR; +S_ISBLK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFBLK; +S_ISFIFO :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFIFO; +S_ISSOCK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFSOCK; + +R_OK :: 4; // Test for read permission +W_OK :: 2; // Test for write permission +X_OK :: 1; // Test for execute permission +F_OK :: 0; // Test for file existance + +foreign libc { + @(link_name="open") _unix_open :: proc(path: cstring, flags: int, #c_vararg mode: ..any) -> Handle ---; + @(link_name="close") _unix_close :: proc(handle: Handle) ---; + @(link_name="read") _unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---; + @(link_name="write") _unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---; + @(link_name="lseek") _unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int ---; + @(link_name="gettid") _unix_gettid :: proc() -> u64 ---; + @(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^Stat) -> int ---; + @(link_name="access") _unix_access :: proc(path: cstring, mask: int) -> int ---; + + @(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---; + @(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---; + @(link_name="free") _unix_free :: proc(ptr: rawptr) ---; + @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---; + @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---; + + @(link_name="exit") _unix_exit :: proc(status: int) ---; +} + +foreign dl { + @(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: int) -> rawptr ---; + @(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---; + @(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int ---; + @(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---; +} + +open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { + cstr := strings.clone_to_cstring(path); + handle := _unix_open(cstr, flags, mode); + delete(cstr); + if handle == -1 { + return INVALID_HANDLE, 1; + } + return handle, 0; +} + +close :: proc(fd: Handle) { + _unix_close(fd); +} + +write :: proc(fd: Handle, data: []u8) -> (int, Errno) { + assert(fd != -1); + + bytes_written := _unix_write(fd, &data[0], len(data)); + if(bytes_written == -1) { + return 0, 1; + } + return bytes_written, 0; +} + +read :: proc(fd: Handle, data: []u8) -> (int, Errno) { + assert(fd != -1); + + bytes_read := _unix_read(fd, &data[0], len(data)); + if bytes_read == -1 { + return 0, 1; + } + return bytes_read, 0; +} + +seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { + assert(fd != -1); + + final_offset := i64(_unix_lseek(fd, int(offset), whence)); + if final_offset == -1 { + return 0, 1; + } + return final_offset, 0; +} + +file_size :: proc(fd: Handle) -> (i64, Errno) { + prev, _ := seek(fd, 0, SEEK_CUR); + size, err := seek(fd, 0, SEEK_END); + seek(fd, prev, SEEK_SET); + return i64(size), err; +} + + + +// NOTE(bill): Uses startup to initialize it +stdin: Handle = 0; // get_std_handle(win32.STD_INPUT_HANDLE); +stdout: Handle = 1; // get_std_handle(win32.STD_OUTPUT_HANDLE); +stderr: Handle = 2; // get_std_handle(win32.STD_ERROR_HANDLE); + +/* TODO(zangent): Implement these! +last_write_time :: proc(fd: Handle) -> File_Time {} +last_write_time_by_name :: proc(name: string) -> File_Time {} +*/ + +is_path_separator :: proc(r: rune) -> bool { + return r == '/'; +} + +stat :: inline proc(path: string) -> (Stat, bool) { + s: Stat; + cstr := strings.clone_to_cstring(path); + defer delete(cstr); + ret_int := _unix_stat(cstr, &s); + return s, ret_int==0; +} + +access :: inline proc(path: string, mask: int) -> bool { + cstr := strings.clone_to_cstring(path); + defer delete(cstr); + return _unix_access(cstr, mask) == 0; +} + +heap_alloc :: inline proc(size: int) -> rawptr { + assert(size > 0); + return _unix_calloc(1, size); +} +heap_resize :: inline proc(ptr: rawptr, new_size: int) -> rawptr { + return _unix_realloc(ptr, new_size); +} +heap_free :: inline proc(ptr: rawptr) { + _unix_free(ptr); +} + +getenv :: proc(name: string) -> (string, bool) { + path_str := strings.clone_to_cstring(name); + defer delete(path_str); + cstr := _unix_getenv(path_str); + if cstr == nil { + return "", false; + } + return string(cstr), true; +} + +exit :: inline proc(code: int) -> ! { + _unix_exit(code); +} + + +current_thread_id :: proc "contextless" () -> int { + // return int(_unix_gettid()); + return 0; +} + +dlopen :: inline proc(filename: string, flags: int) -> rawptr { + cstr := strings.clone_to_cstring(filename); + defer delete(cstr); + handle := _unix_dlopen(cstr, flags); + return handle; +} +dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr { + assert(handle != nil); + cstr := strings.clone_to_cstring(symbol); + defer delete(cstr); + proc_handle := _unix_dlsym(handle, cstr); + return proc_handle; +} +dlclose :: inline proc(handle: rawptr) -> bool { + assert(handle != nil); + return _unix_dlclose(handle) == 0; +} +dlerror :: proc() -> string { + return string(_unix_dlerror()); +} + + +_alloc_command_line_arguments :: proc() -> []string { + res := make([]string, len(runtime.args__)); + for arg, i in runtime.args__ { + res[i] = string(arg); + } + return res; +} diff --git a/core/time/time_osx.odin b/core/time/time_darwin.odin similarity index 100% rename from core/time/time_osx.odin rename to core/time/time_darwin.odin diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 956ffe1ed..b4abf41a7 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -2,7 +2,7 @@ enum TargetOsKind { TargetOs_Invalid, TargetOs_windows, - TargetOs_osx, + TargetOs_darwin, TargetOs_linux, TargetOs_essence, @@ -30,7 +30,7 @@ enum TargetEndianKind { String target_os_names[TargetOs_COUNT] = { str_lit(""), str_lit("windows"), - str_lit("osx"), + str_lit("darwin"), str_lit("linux"), str_lit("essence"), }; @@ -166,8 +166,8 @@ gb_global TargetMetrics target_linux_amd64 = { str_lit("x86_64-pc-linux-gnu"), }; -gb_global TargetMetrics target_osx_amd64 = { - TargetOs_osx, +gb_global TargetMetrics target_darwin_amd64 = { + TargetOs_darwin, TargetArch_amd64, 8, 16, @@ -189,7 +189,7 @@ struct NamedTargetMetrics { gb_global NamedTargetMetrics named_targets[] = { { str_lit("essence_amd64"), &target_essence_amd64 }, - { str_lit("macos_amd64"), &target_osx_amd64 }, + { str_lit("darwin_amd64"), &target_darwin_amd64 }, { str_lit("linux_386"), &target_linux_386 }, { str_lit("linux_amd64"), &target_linux_amd64 }, { str_lit("windows_386"), &target_windows_386 }, @@ -566,7 +566,7 @@ void init_build_context(TargetMetrics *cross_target) { #if defined(GB_SYSTEM_WINDOWS) metrics = target_windows_amd64; #elif defined(GB_SYSTEM_OSX) - metrics = target_osx_amd64; + metrics = target_darwin_amd64; #else metrics = target_linux_amd64; #endif @@ -618,7 +618,7 @@ void init_build_context(TargetMetrics *cross_target) { case TargetOs_windows: bc->link_flags = str_lit("/machine:x64 "); break; - case TargetOs_osx: + case TargetOs_darwin: break; case TargetOs_linux: bc->link_flags = str_lit("-arch x86-64 "); @@ -631,7 +631,7 @@ void init_build_context(TargetMetrics *cross_target) { case TargetOs_windows: bc->link_flags = str_lit("/machine:x86 "); break; - case TargetOs_osx: + case TargetOs_darwin: gb_printf_err("Unsupported architecture\n"); gb_exit(1); break; diff --git a/src/check_type.cpp b/src/check_type.cpp index 465c11731..9f5ed0ed3 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1915,7 +1915,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall } } } else if (build_context.ODIN_OS == "linux" || - build_context.ODIN_OS == "osx") { + build_context.ODIN_OS == "darwin") { Type *bt = core_type(original_type); switch (bt->kind) { // Okay to pass by value (usually) diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 9414a2338..db9eb1bfb 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1165,7 +1165,8 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven switch (cc) { case ProcCC_Odin: ir_write_str_lit(f, ""); break; case ProcCC_Contextless: ir_write_str_lit(f, ""); break; - case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break; + // case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break; + case ProcCC_CDecl: ir_write_str_lit(f, ""); break; case ProcCC_StdCall: ir_write_str_lit(f, "cc 64 "); break; case ProcCC_FastCall: ir_write_str_lit(f, "cc 65 "); break; case ProcCC_None: ir_write_str_lit(f, ""); break; @@ -1175,8 +1176,8 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven void ir_print_context_parameter_prefix(irFileBuffer *f, irModule *m) { ir_print_type(f, m, t_context_ptr); - ir_write_str_lit(f, " noalias nonnull nocapture inreg "); - // ir_write_str_lit(f, " noalias nonnull nocapture "); + // ir_write_str_lit(f, " noalias nonnull nocapture inreg "); + ir_write_str_lit(f, " noalias nonnull nocapture "); } void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { @@ -1227,6 +1228,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { ir_write_str_lit(f, ", "); ir_print_type(f, m, type); ir_fprintf(f, "* %%%d, align 1", instr->ZeroInit.address->index); + // ir_fprintf(f, "* %%%d", instr->ZeroInit.address->index); break; } @@ -2244,9 +2246,11 @@ void print_llvm_ir(irGen *ir) { defer (ir_file_buffer_destroy(f)); i32 word_bits = cast(i32)(8*build_context.word_size); - if (build_context.ODIN_OS == "osx" || build_context.ODIN_OS == "macos") { + if (build_context.ODIN_OS == "darwin") { GB_ASSERT(word_bits == 64); - ir_write_str_lit(f, "target triple = \"x86_64-apple-macosx10.8\"\n\n"); + ir_write_str_lit(f, "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\"\n"); + ir_write_str_lit(f, "target triple = \"x86_64-apple-macosx10.8\"\n"); + ir_write_str_lit(f, "\n"); } else if (build_context.ODIN_OS == "windows") { ir_fprintf(f, "target triple = \"x86%s-pc-windows-msvc\"\n\n", word_bits == 64 ? "_64" : ""); if (word_bits == 64 && build_context.metrics.arch == TargetArch_amd64) { From 068993a819b17dca442f286a0b9b7817bf8d7120 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 1 Oct 2019 20:55:15 +0100 Subject: [PATCH 080/143] Remove os_osx.odin --- core/os/os_osx.odin | 295 -------------------------------------------- 1 file changed, 295 deletions(-) delete mode 100644 core/os/os_osx.odin diff --git a/core/os/os_osx.odin b/core/os/os_osx.odin deleted file mode 100644 index 3185fecc6..000000000 --- a/core/os/os_osx.odin +++ /dev/null @@ -1,295 +0,0 @@ -package os - -foreign import dl "system:dl" -foreign import libc "system:c" - -import "core:runtime" -import "core:strings" - -OS :: "osx"; - -Handle :: distinct i32; -File_Time :: distinct u64; -Errno :: distinct int; - -INVALID_HANDLE :: ~Handle(0); - -O_RDONLY :: 0x00000; -O_WRONLY :: 0x00001; -O_RDWR :: 0x00002; -O_CREATE :: 0x00040; -O_EXCL :: 0x00080; -O_NOCTTY :: 0x00100; -O_TRUNC :: 0x00200; -O_NONBLOCK :: 0x00800; -O_APPEND :: 0x00400; -O_SYNC :: 0x01000; -O_ASYNC :: 0x02000; -O_CLOEXEC :: 0x80000; - - -SEEK_SET :: 0; -SEEK_CUR :: 1; -SEEK_END :: 2; -SEEK_DATA :: 3; -SEEK_HOLE :: 4; -SEEK_MAX :: SEEK_HOLE; - - - -// NOTE(zangent): These are OS specific! -// Do not mix these up! -RTLD_LAZY :: 0x1; -RTLD_NOW :: 0x2; -RTLD_LOCAL :: 0x4; -RTLD_GLOBAL :: 0x8; -RTLD_NODELETE :: 0x80; -RTLD_NOLOAD :: 0x10; -RTLD_FIRST :: 0x100; - - -// "Argv" arguments converted to Odin strings -args := _alloc_command_line_arguments(); - -_File_Time :: struct { - seconds: i64, - nanoseconds: i64, -} - -Stat :: struct { - device_id: i32, // ID of device containing file - mode: u16, // Mode of the file - nlink: u16, // Number of hard links - serial: u64, // File serial number - uid: u32, // User ID of the file's owner - gid: u32, // Group ID of the file's group - rdev: i32, // Device ID, if device - - last_access: File_Time, // Time of last access - modified: File_Time, // Time of last modification - status_change: File_Time, // Time of last status change - created: File_Time, // Time of creation - - size: i64, // Size of the file, in bytes - blocks: i64, // Number of blocks allocated for the file - block_size: i32, // Optimal blocksize for I/O - flags: u32, // User-defined flags for the file - gen_num: u32, // File generation number ..? - _spare: i32, // RESERVED - _reserve1, - _reserve2: i64, // RESERVED -}; - -// File type -S_IFMT :: 0o170000; // Type of file mask -S_IFIFO :: 0o010000; // Named pipe (fifo) -S_IFCHR :: 0o020000; // Character special -S_IFDIR :: 0o040000; // Directory -S_IFBLK :: 0o060000; // Block special -S_IFREG :: 0o100000; // Regular -S_IFLNK :: 0o120000; // Symbolic link -S_IFSOCK :: 0o140000; // Socket - -// File mode -// Read, write, execute/search by owner -S_IRWXU :: 0o0700; // RWX mask for owner -S_IRUSR :: 0o0400; // R for owner -S_IWUSR :: 0o0200; // W for owner -S_IXUSR :: 0o0100; // X for owner - -// Read, write, execute/search by group -S_IRWXG :: 0o0070; // RWX mask for group -S_IRGRP :: 0o0040; // R for group -S_IWGRP :: 0o0020; // W for group -S_IXGRP :: 0o0010; // X for group - -// Read, write, execute/search by others -S_IRWXO :: 0o0007; // RWX mask for other -S_IROTH :: 0o0004; // R for other -S_IWOTH :: 0o0002; // W for other -S_IXOTH :: 0o0001; // X for other - -S_ISUID :: 0o4000; // Set user id on execution -S_ISGID :: 0o2000; // Set group id on execution -S_ISVTX :: 0o1000; // Directory restrcted delete - -S_ISLNK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFLNK; -S_ISREG :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFREG; -S_ISDIR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFDIR; -S_ISCHR :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFCHR; -S_ISBLK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFBLK; -S_ISFIFO :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFIFO; -S_ISSOCK :: inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFSOCK; - -R_OK :: 4; // Test for read permission -W_OK :: 2; // Test for write permission -X_OK :: 1; // Test for execute permission -F_OK :: 0; // Test for file existance - -foreign libc { - @(link_name="open") _unix_open :: proc(path: cstring, flags: int, #c_vararg mode: ..any) -> Handle ---; - @(link_name="close") _unix_close :: proc(handle: Handle) ---; - @(link_name="read") _unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---; - @(link_name="write") _unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---; - @(link_name="lseek") _unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int ---; - @(link_name="gettid") _unix_gettid :: proc() -> u64 ---; - @(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^Stat) -> int ---; - @(link_name="access") _unix_access :: proc(path: cstring, mask: int) -> int ---; - - @(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---; - @(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---; - @(link_name="free") _unix_free :: proc(ptr: rawptr) ---; - @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---; - @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---; - - @(link_name="exit") _unix_exit :: proc(status: int) ---; -} - -foreign dl { - @(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: int) -> rawptr ---; - @(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---; - @(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int ---; - @(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---; -} - -open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { - cstr := strings.clone_to_cstring(path); - handle := _unix_open(cstr, flags, mode); - delete(cstr); - if handle == -1 { - return INVALID_HANDLE, 1; - } - return handle, 0; -} - -close :: proc(fd: Handle) { - _unix_close(fd); -} - -write :: proc(fd: Handle, data: []u8) -> (int, Errno) { - assert(fd != -1); - - bytes_written := _unix_write(fd, &data[0], len(data)); - if(bytes_written == -1) { - return 0, 1; - } - return bytes_written, 0; -} - -read :: proc(fd: Handle, data: []u8) -> (int, Errno) { - assert(fd != -1); - - bytes_read := _unix_read(fd, &data[0], len(data)); - if bytes_read == -1 { - return 0, 1; - } - return bytes_read, 0; -} - -seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { - assert(fd != -1); - - final_offset := i64(_unix_lseek(fd, int(offset), whence)); - if final_offset == -1 { - return 0, 1; - } - return final_offset, 0; -} - -file_size :: proc(fd: Handle) -> (i64, Errno) { - prev, _ := seek(fd, 0, SEEK_CUR); - size, err := seek(fd, 0, SEEK_END); - seek(fd, prev, SEEK_SET); - return i64(size), err; -} - - - -// NOTE(bill): Uses startup to initialize it -stdin: Handle = 0; // get_std_handle(win32.STD_INPUT_HANDLE); -stdout: Handle = 1; // get_std_handle(win32.STD_OUTPUT_HANDLE); -stderr: Handle = 2; // get_std_handle(win32.STD_ERROR_HANDLE); - -/* TODO(zangent): Implement these! -last_write_time :: proc(fd: Handle) -> File_Time {} -last_write_time_by_name :: proc(name: string) -> File_Time {} -*/ - -is_path_separator :: proc(r: rune) -> bool { - return r == '/'; -} - -stat :: inline proc(path: string) -> (Stat, bool) { - s: Stat; - cstr := strings.clone_to_cstring(path); - defer delete(cstr); - ret_int := _unix_stat(cstr, &s); - return s, ret_int==0; -} - -access :: inline proc(path: string, mask: int) -> bool { - cstr := strings.clone_to_cstring(path); - defer delete(cstr); - return _unix_access(cstr, mask) == 0; -} - -heap_alloc :: inline proc(size: int) -> rawptr { - assert(size > 0); - return _unix_calloc(1, size); -} -heap_resize :: inline proc(ptr: rawptr, new_size: int) -> rawptr { - return _unix_realloc(ptr, new_size); -} -heap_free :: inline proc(ptr: rawptr) { - _unix_free(ptr); -} - -getenv :: proc(name: string) -> (string, bool) { - path_str := strings.clone_to_cstring(name); - defer delete(path_str); - cstr := _unix_getenv(path_str); - if cstr == nil { - return "", false; - } - return string(cstr), true; -} - -exit :: inline proc(code: int) -> ! { - _unix_exit(code); -} - - -current_thread_id :: proc "contextless" () -> int { - // return int(_unix_gettid()); - return 0; -} - -dlopen :: inline proc(filename: string, flags: int) -> rawptr { - cstr := strings.clone_to_cstring(filename); - defer delete(cstr); - handle := _unix_dlopen(cstr, flags); - return handle; -} -dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr { - assert(handle != nil); - cstr := strings.clone_to_cstring(symbol); - defer delete(cstr); - proc_handle := _unix_dlsym(handle, cstr); - return proc_handle; -} -dlclose :: inline proc(handle: rawptr) -> bool { - assert(handle != nil); - return _unix_dlclose(handle) == 0; -} -dlerror :: proc() -> string { - return string(_unix_dlerror()); -} - - -_alloc_command_line_arguments :: proc() -> []string { - res := make([]string, len(runtime.args__)); - for arg, i in runtime.args__ { - res[i] = string(arg); - } - return res; -} From dae514a2c99875db0dbda56309c7349a68432e19 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Oct 2019 09:40:05 +0100 Subject: [PATCH 081/143] Fix Using any in if statement asserts compiler #441 --- src/check_expr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5535e6772..697abef5f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1580,8 +1580,10 @@ void check_cast_error_suggestion(CheckerContext *c, Operand *o, Type *type) { void check_is_expressible(CheckerContext *c, Operand *o, Type *type) { - GB_ASSERT(is_type_constant_type(type)); GB_ASSERT(o->mode == Addressing_Constant); + if (!is_type_constant_type(type)) { + return; + } if (!check_representable_as_constant(c, o->value, type, &o->value)) { gbString a = expr_to_string(o->expr); gbString b = type_to_string(type); From 7fa2d25eea28955c12d8fc6a597e8615562c0ee9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Oct 2019 10:22:41 +0100 Subject: [PATCH 082/143] Fix #complete switch with pointer case doesn't compile #416 --- src/check_stmt.cpp | 4 ++-- src/types.cpp | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 9163fadc2..26e3f8c26 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1205,7 +1205,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { GB_PANIC("Unknown type to type switch statement"); } - if (ptr_set_exists(&seen, y.type)) { + if (type_ptr_set_exists(&seen, y.type)) { TokenPos pos = cc->token.pos; gbString expr_str = expr_to_string(y.expr); error(y.expr, @@ -1257,7 +1257,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { for_array(i, variants) { Type *t = variants[i]; - if (!ptr_set_exists(&seen, t)) { + if (!type_ptr_set_exists(&seen, t)) { array_add(&unhandled, t); } } diff --git a/src/types.cpp b/src/types.cpp index 94b89d8f5..d8a579510 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -551,8 +551,27 @@ i64 type_offset_of (Type *t, i32 index); gbString type_to_string (Type *type); void init_map_internal_types(Type *type); Type * bit_set_to_int(Type *t); +bool are_types_identical(Type *x, Type *y); +bool type_ptr_set_exists(PtrSet *s, Type *t) { + if (ptr_set_exists(s, t)) { + return true; + } + + // TODO(bill, 2019-10-05): This is very slow and it's probably a lot + // faster to cache types correctly + for_array(i, s->entries) { + Type *f = s->entries[i].ptr; + if (are_types_identical(t, f)) { + ptr_set_add(s, t); + return true; + } + } + + return false; +} + Type *base_type(Type *t) { for (;;) { if (t == nullptr) { From 6c69e8c043e7dcf9d9965c7b28c7bdae44e0537c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 6 Oct 2019 14:55:25 +0100 Subject: [PATCH 083/143] Make `typeid` semantics consistent across variables and constants --- src/check_decl.cpp | 54 ++++++++++++++++++++++++++------------- src/check_expr.cpp | 61 ++++++++++++++++++++++++++++++++++----------- src/checker.cpp | 16 +++++------- src/exact_value.cpp | 18 +++++++++++++ src/ir.cpp | 5 ++++ src/parser.cpp | 4 --- 6 files changed, 113 insertions(+), 45 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 166b6e715..5e8479a7f 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -41,11 +41,20 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri } if (operand->mode == Addressing_Type) { - gbString t = type_to_string(operand->type); - error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string)); - gb_string_free(t); - e->type = operand->type; - return nullptr; + if (e->type != nullptr && is_type_typeid(e->type)) { + add_type_info_type(ctx, operand->type); + add_type_and_value(ctx->info, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type)); + return e->type; + } else { + gbString t = type_to_string(operand->type); + defer (gb_string_free(t)); + error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string)); + if (e->type == nullptr) { + error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a type\n", LIT(e->token.string)); + } + e->type = operand->type; + return nullptr; + } } @@ -240,7 +249,7 @@ isize total_attribute_count(DeclInfo *decl) { } -void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) { +void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) { GB_ASSERT(e->type == nullptr); DeclInfo *decl = decl_info_of_entity(e); @@ -248,9 +257,8 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) check_decl_attributes(ctx, decl->attributes, const_decl_attribute, nullptr); } - - bool is_distinct = is_type_distinct(type_expr); - Ast *te = remove_type_alias_clutter(type_expr); + bool is_distinct = is_type_distinct(init_expr); + Ast *te = remove_type_alias_clutter(init_expr); e->type = t_invalid; String name = e->token.string; Type *named = alloc_type_named(name, nullptr, e); @@ -266,7 +274,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) named->Named.base = base_type(bt); if (is_distinct && is_type_typeid(e->type)) { - error(type_expr, "'distinct' cannot be applied to 'typeid'"); + error(init_expr, "'distinct' cannot be applied to 'typeid'"); is_distinct = false; } if (!is_distinct) { @@ -275,6 +283,19 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) e->TypeName.is_type_alias = true; } + + if (decl->type_expr != nullptr) { + Type *t = check_type(ctx, decl->type_expr); + if (t != nullptr && !is_type_typeid(t)) { + Operand operand = {}; + operand.mode = Addressing_Type; + operand.type = e->type; + operand.expr = init_expr; + check_assignment(ctx, &operand, t, str_lit("constant declaration")); + } + } + + // using decl if (decl->is_using) { // NOTE(bill): Must be an enum declaration @@ -363,15 +384,14 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, switch (operand.mode) { case Addressing_Type: { + if (e->type != nullptr && !is_type_typeid(e->type)) { + check_assignment(ctx, &operand, e->type, str_lit("constant declaration")); + } + e->kind = Entity_TypeName; e->type = nullptr; - DeclInfo *d = ctx->decl; - if (d->type_expr != nullptr) { - error(e->token, "A type declaration cannot have an type parameter"); - } - d->type_expr = d->init_expr; - check_type_decl(ctx, e, d->type_expr, named_type); + check_type_decl(ctx, e, ctx->decl->init_expr, named_type); return; } @@ -1070,7 +1090,7 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_ check_const_decl(&c, e, d->type_expr, d->init_expr, named_type); break; case Entity_TypeName: { - check_type_decl(&c, e, d->type_expr, named_type); + check_type_decl(&c, e, d->init_expr, named_type); break; } case Entity_Procedure: diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 697abef5f..6a0d8221f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -442,6 +442,10 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type } if (operand->mode == Addressing_Type) { + if (is_type_typeid(type)) { + add_type_info_type(c, operand->type); + return 4; + } return -1; } @@ -755,7 +759,12 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co return; } - if (!check_is_assignable_to(c, operand, type)) { + if (check_is_assignable_to(c, operand, type)) { + if (operand->mode == Addressing_Type && is_type_typeid(type)) { + add_type_info_type(c, operand->type); + add_type_and_value(c->info, operand->expr, Addressing_Value, type, exact_value_typeid(operand->type)); + } + } else { gbString expr_str = expr_to_string(operand->expr); gbString op_type_str = type_to_string(operand->type); gbString type_str = type_to_string(type); @@ -1734,6 +1743,23 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) { return; } + if (x->mode == Addressing_Type && is_type_typeid(y->type)) { + add_type_info_type(c, x->type); + add_type_and_value(c->info, x->expr, Addressing_Value, y->type, exact_value_typeid(x->type)); + + x->mode = Addressing_Value; + x->type = t_untyped_bool; + return; + } else if (is_type_typeid(x->type) && y->mode == Addressing_Type) { + add_type_info_type(c, y->type); + add_type_and_value(c->info, y->expr, Addressing_Value, x->type, exact_value_typeid(y->type)); + + x->mode = Addressing_Value; + x->type = t_untyped_bool; + return; + } + + gbString err_str = nullptr; defer (if (err_str != nullptr) { @@ -2324,8 +2350,16 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint // If only one is a type, this is an error if (xt ^ yt) { GB_ASSERT(xt != yt); - if (xt) error_operand_not_expression(x); - if (yt) error_operand_not_expression(y); + if (xt) { + if (!is_type_typeid(y->type)) { + error_operand_not_expression(x); + } + } + if (yt) { + if (!is_type_typeid(x->type)) { + error_operand_not_expression(y); + } + } } break; @@ -5254,6 +5288,11 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { } } score += s; + + if (o.mode == Addressing_Type && is_type_typeid(e->type)) { + add_type_info_type(c, o.type); + add_type_and_value(c->info, o.expr, Addressing_Value, e->type, exact_value_typeid(o.type)); + } } if (variadic) { @@ -5496,6 +5535,11 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) { } score += s; } + + if (o->mode == Addressing_Type && is_type_typeid(e->type)) { + add_type_info_type(c, o->type); + add_type_and_value(c->info, o->expr, Addressing_Value, e->type, exact_value_typeid(o->type)); + } } if (data) { @@ -6432,17 +6476,6 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) { } } - // NOTE(bill): Should this be here or on the `add_entity_use`? - // if (ce->proc != nullptr) { - // Entity *e = entity_of_node(&c->info, ce->proc); - // if (e != nullptr && e->kind == Entity_Procedure) { - // String msg = e->Procedure.deprecated_message; - // if (msg.len > 0) { - // warning(call, "%.*s is deprecated: %.*s", LIT(e->token.string), LIT(msg)); - // } - // } - // } - CallArgumentData data = check_call_arguments(c, operand, proc_type, call); Type *result_type = data.result_type; gb_zero_item(operand); diff --git a/src/checker.cpp b/src/checker.cpp index 994e0776d..f30273439 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2613,14 +2613,14 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { Entity *e = nullptr; d->attributes = vd->attributes; + d->type_expr = vd->type; + d->init_expr = init; if (is_ast_type(init)) { e = alloc_entity_type_name(d->scope, token, nullptr); - if (vd->type != nullptr) { - error(name, "A type declaration cannot have an type parameter"); - } - d->type_expr = init; - d->init_expr = init; + // if (vd->type != nullptr) { + // error(name, "A type declaration cannot have an type parameter"); + // } } else if (init->kind == Ast_ProcLit) { if (c->scope->flags&ScopeFlag_Type) { error(name, "Procedure declarations are not allowed within a struct"); @@ -2647,19 +2647,15 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { pl->type->ProcType.calling_convention = cc; } d->proc_lit = init; - d->type_expr = vd->type; + d->init_expr = init; } else if (init->kind == Ast_ProcGroup) { ast_node(pg, ProcGroup, init); e = alloc_entity_proc_group(d->scope, token, nullptr); if (fl != nullptr) { error(name, "Procedure groups are not allowed within a foreign block"); } - d->init_expr = init; - d->type_expr = vd->type; } else { e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value); - d->type_expr = vd->type; - d->init_expr = init; } e->identifier = name; diff --git a/src/exact_value.cpp b/src/exact_value.cpp index fcc6f1973..95d04d93b 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -38,6 +38,7 @@ enum ExactValueKind { ExactValue_Pointer, ExactValue_Compound, // TODO(bill): Is this good enough? ExactValue_Procedure, // TODO(bill): Is this good enough? + ExactValue_Typeid, ExactValue_Count, }; @@ -54,6 +55,7 @@ struct ExactValue { Quaternion256 value_quaternion; Ast * value_compound; Ast * value_procedure; + Type * value_typeid; }; }; @@ -82,6 +84,8 @@ HashKey hash_exact_value(ExactValue v) { return hash_pointer(v.value_compound); case ExactValue_Procedure: return hash_pointer(v.value_procedure); + case ExactValue_Typeid: + return hash_pointer(v.value_typeid); } return hashing_proc(&v, gb_size_of(ExactValue)); @@ -154,6 +158,13 @@ ExactValue exact_value_procedure(Ast *node) { } +ExactValue exact_value_typeid(Type *type) { + ExactValue result = {ExactValue_Typeid}; + result.value_typeid = type; + return result; +} + + ExactValue exact_value_integer_from_string(String const &string) { ExactValue result = {ExactValue_Integer}; big_int_from_string(&result.value_integer, string); @@ -889,6 +900,13 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) { } break; } + + case ExactValue_Typeid: + switch (op) { + case Token_CmpEq: return are_types_identical(x.value_typeid, y.value_typeid); + case Token_NotEq: return !are_types_identical(x.value_typeid, y.value_typeid); + } + break; } GB_PANIC("Invalid comparison"); diff --git a/src/ir.cpp b/src/ir.cpp index 758267c24..f29d389f4 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6592,6 +6592,11 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { return ir_emit_conv(proc, x, tv.type); } + if (tv.value.kind == ExactValue_Typeid) { + irValue *v = ir_typeid(proc->module, tv.value.value_typeid); + return ir_emit_conv(proc, v, tv.type); + } + return ir_add_module_constant(proc->module, tv.type, tv.value); } diff --git a/src/parser.cpp b/src/parser.cpp index 204ff3984..fb093ffd9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1923,10 +1923,6 @@ Ast *parse_operand(AstFile *f, bool lhs) { case Token_typeid: { Token token = expect_token(f, Token_typeid); - // Ast *specialization = nullptr; - // if (allow_token(f, Token_Quo)) { - // specialization = parse_type(f); - // } return ast_typeid_type(f, token, nullptr); } break; From e1b711b3b3476ecde0ed7e64e65fe4314a702b61 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 6 Oct 2019 15:07:16 +0100 Subject: [PATCH 084/143] Update demo.odin with more information --- examples/demo/demo.odin | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 9554eaa2e..eec7da45a 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -10,6 +10,24 @@ when os.OS == "windows" { import "core:thread" } +/* + The Odin programming language is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals: + * simplicity + * high performance + * built for modern systems + * joy of programming + + # Installing Odin + Getting Started - https://odin-lang.org/docs/install/ + Instructions for downloading and install the Odin compiler and libraries. + + # Learning Odin + Overview of Odin - https://odin-lang.org/docs/overview/ + An overview of the Odin programming language. + Frequently Asked Questions (FAQ) - https://odin-lang.org/docs/faq/ + Answers to common questions about Odin. +*/ + @(link_name="general_stuff") general_stuff :: proc() { fmt.println("# general_stuff"); @@ -38,8 +56,6 @@ general_stuff :: proc() { _ = (^f32)(ptr)^; _ = (cast(^f32)ptr)^; - - // Questions: Should there be two ways to do it? } /* From 4e8a801b3504f402e06d6928e889b33c7872f88f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 6 Oct 2019 18:13:15 +0100 Subject: [PATCH 085/143] strings.split; strings.index; eprint* over print*_err; --- core/fmt/fmt.odin | 18 +++-- core/reflect/types.odin | 6 +- core/runtime/core.odin | 4 +- core/strconv/strconv.odin | 4 + core/strings/builder.odin | 4 + core/strings/strings.odin | 150 +++++++++++++++++++++++++++++++++++++- examples/demo/demo.odin | 12 ++- src/build_settings.cpp | 2 +- 8 files changed, 183 insertions(+), 17 deletions(-) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index a2f1166ac..6903b9bdb 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -59,12 +59,18 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int { // print* procedures return the number of bytes written -print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); } -print_err :: proc(args: ..any) -> int { return fprint(context.stderr, ..args); } -println :: proc(args: ..any) -> int { return fprintln(context.stdout, ..args); } -println_err :: proc(args: ..any) -> int { return fprintln(context.stderr, ..args); } -printf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stdout, fmt, ..args); } -printf_err :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stderr, fmt, ..args); } +print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); } +println :: proc(args: ..any) -> int { return fprintln(context.stdout, ..args); } +printf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stdout, fmt, ..args); } + +eprint :: proc(args: ..any) -> int { return fprint(context.stderr, ..args); } +eprintln :: proc(args: ..any) -> int { return fprintln(context.stderr, ..args); } +eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stderr, fmt, ..args); } + + +@(deprecated="prefer eprint") print_err :: proc(args: ..any) -> int { return eprint(..args); } +@(deprecated="prefer eprintf") println_err :: proc(args: ..any) -> int { return eprintln(..args); } +@(deprecated="prefer eprintln") printf_err :: proc(fmt: string, args: ..any) -> int { return eprintf(fmt, ..args); } // aprint* procedures return a string that was allocated with the current context diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 8130668b3..d1678a1b2 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -304,10 +304,8 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) { write_byte(buf, info.signed ? 'i' : 'u'); write_i64(buf, i64(8*ti.size), 10); switch info.endianness { - case rt.Type_Info_Endianness.Little: - write_string(buf, "le"); - case rt.Type_Info_Endianness.Big: - write_string(buf, "be"); + case .Little: write_string(buf, "le"); + case .Big: write_string(buf, "be"); } } case rt.Type_Info_Rune: diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 022a84e9e..c401dbdf3 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -40,7 +40,7 @@ Type_Info_Enum_Value :: union { u8, u16, u32, u64, uint, uintptr, }; -Type_Info_Endianness :: enum u8 { +Platform_Endianness :: enum u8 { Platform = 0, Little = 1, Big = 2, @@ -48,7 +48,7 @@ Type_Info_Endianness :: enum u8 { // Variant Types Type_Info_Named :: struct {name: string, base: ^Type_Info}; -Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness}; +Type_Info_Integer :: struct {signed: bool, endianness: Platform_Endianness}; Type_Info_Rune :: struct {}; Type_Info_Float :: struct {}; Type_Info_Complex :: struct {}; diff --git a/core/strconv/strconv.odin b/core/strconv/strconv.odin index ac78f78dc..447178bc3 100644 --- a/core/strconv/strconv.odin +++ b/core/strconv/strconv.odin @@ -205,7 +205,11 @@ itoa :: proc(buf: []byte, i: int) -> string { atoi :: proc(s: string) -> int { return parse_int(s); } +atof :: proc(s: string) -> f64 { + return parse_f64(s); +} +ftoa :: append_float; append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string { return string(generic_ftoa(buf, f, fmt, prec, bit_size)); } diff --git a/core/strings/builder.odin b/core/strings/builder.odin index 68f1a7ceb..f7dac04ba 100644 --- a/core/strings/builder.odin +++ b/core/strings/builder.odin @@ -21,6 +21,10 @@ grow_builder :: proc(b: ^Builder, cap: int) { reserve(&b.buf, cap); } +reset_builder :: proc(b: ^Builder) { + clear(&b.buf); +} + builder_from_slice :: proc(backing: []byte) -> Builder { s := transmute(mem.Raw_Slice)backing; d := mem.Raw_Dynamic_Array{ diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 8f9db86be..0c9ffa7d3 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -155,6 +155,73 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> string { return string(b); } +@private +_split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocator) -> []string { + s, n := s_, n_; + + if n == 0 { + return nil; + } + + if sep == "" { + l := utf8.rune_count_in_string(s); + if n < 0 || n > l { + n = l; + } + + res := make([dynamic]string, n); + for i := 0; i < n-1; i += 1 { + r, w := utf8.decode_rune_in_string(s); + res[i] = s[:w]; + s = s[w:]; + } + if n > 0 { + res[n-1] = s; + } + return res[:]; + } + + if n < 0 { + n = count(s, sep) + 1; + } + + res := make([dynamic]string, n); + + n -= 1; + + i := 0; + for ; i < n; i += 1 { + m := index(s, sep); + if m < 0 { + break; + } + res[i] = s[:m+sep_save]; + s = s[m+len(sep):]; + } + res[i] = s; + + return res[:i+1]; +} + +split :: inline proc(s, sep: string, allocator := context.allocator) -> []string { + return _split(s, sep, 0, -1, allocator); +} + +split_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string { + return _split(s, sep, 0, n, allocator); +} + +split_after :: inline proc(s, sep: string, allocator := context.allocator) -> []string { + return _split(s, sep, len(sep), -1, allocator); +} + +split_after_n :: inline proc(s, sep: string, n: int, allocator := context.allocator) -> []string { + return _split(s, sep, len(sep), n, allocator); +} + + + + index_byte :: proc(s: string, c: byte) -> int { for i := 0; i < len(s); i += 1 { if s[i] == c do return i; @@ -170,7 +237,25 @@ last_index_byte :: proc(s: string, c: byte) -> int { return -1; } + + +@private PRIME_RABIN_KARP :: 16777619; + index :: proc(s, substr: string) -> int { + hash_str_rabin_karp :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) { + for i := 0; i < len(s); i += 1 { + hash = hash*PRIME_RABIN_KARP + u32(s[i]); + } + sq := u32(PRIME_RABIN_KARP); + for i := len(s); i > 0; i >>= 1 { + if (i & 1) != 0 { + pow *= sq; + } + sq *= sq; + } + return; + } + n := len(substr); switch { case n == 0: @@ -186,9 +271,68 @@ index :: proc(s, substr: string) -> int { return -1; } - for i := 0; i < len(s)-n+1; i += 1 { - x := s[i:i+n]; - if x == substr { + hash, pow := hash_str_rabin_karp(substr); + h: u32; + for i := 0; i < n; i += 1 { + h = h*PRIME_RABIN_KARP + u32(s[i]); + } + if h == hash && s[:n] == substr { + return 0; + } + for i := n; i < len(s); /**/ { + h *= PRIME_RABIN_KARP; + h += u32(s[i]); + h -= pow * u32(s[i-n]); + i += 1; + if h == hash && s[i-n:i] == substr { + return i - n; + } + } + return -1; +} + +last_index :: proc(s, substr: string) -> int { + hash_str_rabin_karp_reverse :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) { + for i := len(s) - 1; i >= 0; i -= 1 { + hash = hash*PRIME_RABIN_KARP + u32(s[i]); + } + sq := u32(PRIME_RABIN_KARP); + for i := len(s); i > 0; i >>= 1 { + if (i & 1) != 0 { + pow *= sq; + } + sq *= sq; + } + return; + } + + n := len(substr); + switch { + case n == 0: + return len(s); + case n == 1: + return last_index_byte(s, substr[0]); + case n == len(s): + return substr == s ? 0 : -1; + case n > len(s): + return -1; + } + + hash, pow := hash_str_rabin_karp_reverse(substr); + last := len(s) - n; + h: u32; + for i := len(s)-1; i >= last; i -= 1 { + h = h*PRIME_RABIN_KARP + u32(s[i]); + } + if h == hash && s[last:] == substr { + return last; + } + + for i := last-1; i >= 0; i -= 1 { + h *= PRIME_RABIN_KARP; + h += u32(s[i]); + h -= pow * u32(s[i+n]); + if h == hash && s[i:i+n] == substr { return i; } } diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index eec7da45a..2c8148501 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -4,6 +4,7 @@ import "core:fmt" import "core:mem" import "core:os" import "core:reflect" +import "core:strings" import "intrinsics" when os.OS == "windows" { @@ -1189,7 +1190,15 @@ where_clauses :: proc() { } main :: proc() { - when true { + x := "foobarbaz"; + i : int; + i = strings.last_index(x, "foo"); fmt.println(i); + i = strings.last_index(x, "bar"); fmt.println(i); + i = strings.last_index(x, "baz"); fmt.println(i); + i = strings.last_index(x, "asd"); fmt.println(i); + i = strings.last_index(x, "a"); fmt.println(i); + i = strings.last_index(x, "ba"); fmt.println(i); + when false { general_stuff(); union_type(); parametric_polymorphism(); @@ -1212,3 +1221,4 @@ main :: proc() { where_clauses(); } } + diff --git a/src/build_settings.cpp b/src/build_settings.cpp index b4abf41a7..5d1c07a67 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -55,7 +55,7 @@ TargetEndianKind target_endians[TargetArch_COUNT] = { -String const ODIN_VERSION = str_lit("0.10.1"); +String const ODIN_VERSION = str_lit("0.10.2"); From d62503d031855534adddc37f84bd2e92dc2a5467 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 6 Oct 2019 18:14:02 +0100 Subject: [PATCH 086/143] Change precedence for `in` and `notin` to match + - | ~ --- core/odin/parser/parser.odin | 10 +++++----- examples/demo/demo.odin | 10 +--------- src/parser.cpp | 11 ++++++----- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index f652e2c02..7c5c096ba 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1144,17 +1144,17 @@ token_precedence :: proc(p: ^Parser, kind: token.Kind) -> int { token.Lt_Eq, token.Gt_Eq: return 5; case token.In, token.Notin: - if p.expr_level >= 0 || p.allow_in_expr { - return 6; + if p.expr_level < 0 && !p.allow_in_expr { + return 0; } - return 0; + fallthrough; case token.Add, token.Sub, token.Or, token.Xor: - return 7; + return 6; case token.Mul, token.Quo, token.Mod, token.Mod_Mod, token.And, token.And_Not, token.Shl, token.Shr: - return 8; + return 7; } return 0; } diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 2c8148501..1460bf8be 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1190,15 +1190,7 @@ where_clauses :: proc() { } main :: proc() { - x := "foobarbaz"; - i : int; - i = strings.last_index(x, "foo"); fmt.println(i); - i = strings.last_index(x, "bar"); fmt.println(i); - i = strings.last_index(x, "baz"); fmt.println(i); - i = strings.last_index(x, "asd"); fmt.println(i); - i = strings.last_index(x, "a"); fmt.println(i); - i = strings.last_index(x, "ba"); fmt.println(i); - when false { + when true { general_stuff(); union_type(); parametric_polymorphism(); diff --git a/src/parser.cpp b/src/parser.cpp index fb093ffd9..29254d7e8 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2479,17 +2479,18 @@ i32 token_precedence(AstFile *f, TokenKind t) { case Token_LtEq: case Token_GtEq: return 5; + case Token_in: case Token_notin: - if (f->expr_level >= 0 || f->allow_in_expr) { - return 6; + if (f->expr_level < 0 && !f->allow_in_expr) { + return 0; } - return 0; + /*fallthrough*/ case Token_Add: case Token_Sub: case Token_Or: case Token_Xor: - return 7; + return 6; case Token_Mul: case Token_Quo: case Token_Mod: @@ -2498,7 +2499,7 @@ i32 token_precedence(AstFile *f, TokenKind t) { case Token_AndNot: case Token_Shl: case Token_Shr: - return 8; + return 7; } return 0; } From 562b518394ca358ac8aef1df9b480106fafe9375 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 6 Oct 2019 18:54:29 +0100 Subject: [PATCH 087/143] Change print*_err to eprint* in core library --- core/encoding/cel/cel.odin | 6 +++--- core/encoding/cel/token.odin | 6 +++--- core/odin/parser/parser.odin | 12 ++++++------ core/odin/tokenizer/tokenizer.odin | 6 +++--- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/core/encoding/cel/cel.odin b/core/encoding/cel/cel.odin index 793dba231..754d8cbfa 100644 --- a/core/encoding/cel/cel.odin +++ b/core/encoding/cel/cel.odin @@ -168,9 +168,9 @@ destroy :: proc(p: ^Parser) { } error :: proc(p: ^Parser, pos: Pos, msg: string, args: ..any) { - fmt.printf_err("%s(%d:%d) Error: ", pos.file, pos.line, pos.column); - fmt.printf_err(msg, ..args); - fmt.println_err(); + fmt.eprintf("%s(%d:%d) Error: ", pos.file, pos.line, pos.column); + fmt.eprintf(msg, ..args); + fmt.eprintln(); p.error_count += 1; } diff --git a/core/encoding/cel/token.odin b/core/encoding/cel/token.odin index 1ad86b299..a2bcb963a 100644 --- a/core/encoding/cel/token.odin +++ b/core/encoding/cel/token.odin @@ -183,9 +183,9 @@ tokenizer_init :: proc(t: ^Tokenizer, src: []byte, file := "") { } token_error :: proc(t: ^Tokenizer, msg: string, args: ..any) { - fmt.printf_err("%s(%d:%d) Error: ", t.file, t.line_count, t.read_offset-t.line_offset+1); - fmt.printf_err(msg, ..args); - fmt.println_err(); + fmt.eprintf("%s(%d:%d) Error: ", t.file, t.line_count, t.read_offset-t.line_offset+1); + fmt.eprintf(msg, ..args); + fmt.eprintln(); t.error_count += 1; } diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 7c5c096ba..cc3768030 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -51,14 +51,14 @@ Import_Decl_Kind :: enum { default_warning_handler :: proc(pos: token.Pos, msg: string, args: ..any) { - fmt.printf_err("%s(%d:%d): Warning: ", pos.file, pos.line, pos.column); - fmt.printf_err(msg, ..args); - fmt.printf_err("\n"); + fmt.eprintf("%s(%d:%d): Warning: ", pos.file, pos.line, pos.column); + fmt.eprintf(msg, ..args); + fmt.eprintf("\n"); } default_error_handler :: proc(pos: token.Pos, msg: string, args: ..any) { - fmt.printf_err("%s(%d:%d): ", pos.file, pos.line, pos.column); - fmt.printf_err(msg, ..args); - fmt.printf_err("\n"); + fmt.eprintf("%s(%d:%d): ", pos.file, pos.line, pos.column); + fmt.eprintf(msg, ..args); + fmt.eprintf("\n"); } warn :: proc(p: ^Parser, pos: token.Pos, msg: string, args: ..any) { diff --git a/core/odin/tokenizer/tokenizer.odin b/core/odin/tokenizer/tokenizer.odin index b29ac700d..98aef62b0 100644 --- a/core/odin/tokenizer/tokenizer.odin +++ b/core/odin/tokenizer/tokenizer.odin @@ -54,9 +54,9 @@ offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos { } default_error_handler :: proc(pos: token.Pos, msg: string, args: ..any) { - fmt.printf_err("%s(%d:%d) ", pos.file, pos.line, pos.column); - fmt.printf_err(msg, ..args); - fmt.printf_err("\n"); + fmt.eprintf("%s(%d:%d) ", pos.file, pos.line, pos.column); + fmt.eprintf(msg, ..args); + fmt.eprintf("\n"); } error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) { From 939459b635b5042b10ab64a28efc573600ac98cb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 6 Oct 2019 19:16:55 +0100 Subject: [PATCH 088/143] Change implicit semicolon rules for record types within procedure bodies; Update `package odin/*` --- core/encoding/json/marshal.odin | 7 +- core/odin/ast/ast.odin | 188 +++---- core/odin/ast/clone.odin | 4 +- core/odin/ast/file.odin | 4 +- core/odin/parser/parser.odin | 760 ++++++++++++++--------------- core/odin/token/token.odin | 333 ------------- core/odin/tokenizer/tokenizer.odin | 149 +++--- core/runtime/core.odin | 2 +- core/strconv/generic_float.odin | 2 +- src/parser.cpp | 3 +- 10 files changed, 559 insertions(+), 893 deletions(-) delete mode 100644 core/odin/token/token.odin diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 52d75524a..60839b21b 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -284,11 +284,10 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error { t := runtime.type_info_base(ti); switch info in t.variant { case runtime.Type_Info_Integer: - using runtime.Type_Info_Endianness; switch info.endianness { - case Platform: return false; - case Little: return ODIN_ENDIAN != "little"; - case Big: return ODIN_ENDIAN != "big"; + case .Platform: return false; + case .Little: return ODIN_ENDIAN != "little"; + case .Big: return ODIN_ENDIAN != "big"; } } return false; diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index baad5f802..309d2c147 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -1,6 +1,6 @@ package odin_ast -import "core:odin/token" +import "core:odin/tokenizer" Proc_Tag :: enum { Bounds_Check, @@ -33,12 +33,12 @@ Node_State_Flags :: distinct bit_set[Node_State_Flag]; Comment_Group :: struct { - list: []token.Token, + list: []tokenizer.Token, } Node :: struct { - pos: token.Pos, - end: token.Pos, + pos: tokenizer.Pos, + end: tokenizer.Pos, derived: any, state_flags: Node_State_Flags, } @@ -67,29 +67,29 @@ Ident :: struct { Implicit :: struct { using node: Expr, - tok: token.Token, + tok: tokenizer.Token, } Undef :: struct { using node: Expr, - tok: token.Kind, + tok: tokenizer.Token_Kind, } Basic_Lit :: struct { using node: Expr, - tok: token.Token, + tok: tokenizer.Token, } Basic_Directive :: struct { using node: Expr, - tok: token.Token, + tok: tokenizer.Token, name: string, } Ellipsis :: struct { using node: Expr, - tok: token.Kind, + tok: tokenizer.Token_Kind, expr: ^Expr, } @@ -99,44 +99,44 @@ Proc_Lit :: struct { body: ^Stmt, tags: Proc_Tags, inlining: Proc_Inlining, - where_token: token.Token, + where_token: tokenizer.Token, where_clauses: []^Expr, } Comp_Lit :: struct { using node: Expr, type: ^Expr, - open: token.Pos, + open: tokenizer.Pos, elems: []^Expr, - close: token.Pos, + close: tokenizer.Pos, } Tag_Expr :: struct { using node: Expr, - op: token.Token, + op: tokenizer.Token, name: string, expr: ^Expr, } Unary_Expr :: struct { using node: Expr, - op: token.Token, + op: tokenizer.Token, expr: ^Expr, } Binary_Expr :: struct { using node: Expr, left: ^Expr, - op: token.Token, + op: tokenizer.Token, right: ^Expr, } Paren_Expr :: struct { using node: Expr, - open: token.Pos, + open: tokenizer.Pos, expr: ^Expr, - close: token.Pos, + close: tokenizer.Pos, } Selector_Expr :: struct { @@ -153,74 +153,74 @@ Implicit_Selector_Expr :: struct { Index_Expr :: struct { using node: Expr, expr: ^Expr, - open: token.Pos, + open: tokenizer.Pos, index: ^Expr, - close: token.Pos, + close: tokenizer.Pos, } Deref_Expr :: struct { using node: Expr, expr: ^Expr, - op: token.Token, + op: tokenizer.Token, } Slice_Expr :: struct { using node: Expr, expr: ^Expr, - open: token.Pos, + open: tokenizer.Pos, low: ^Expr, - interval: token.Token, + interval: tokenizer.Token, high: ^Expr, - close: token.Pos, + close: tokenizer.Pos, } Call_Expr :: struct { using node: Expr, inlining: Proc_Inlining, expr: ^Expr, - open: token.Pos, + open: tokenizer.Pos, args: []^Expr, - ellipsis: token.Token, - close: token.Pos, + ellipsis: tokenizer.Token, + close: tokenizer.Pos, } Field_Value :: struct { using node: Expr, field: ^Expr, - sep: token.Pos, + sep: tokenizer.Pos, value: ^Expr, } Ternary_Expr :: struct { using node: Expr, cond: ^Expr, - op1: token.Token, + op1: tokenizer.Token, x: ^Expr, - op2: token.Token, + op2: tokenizer.Token, y: ^Expr, } Type_Assertion :: struct { using node: Expr, expr: ^Expr, - dot: token.Pos, - open: token.Pos, + dot: tokenizer.Pos, + open: tokenizer.Pos, type: ^Expr, - close: token.Pos, + close: tokenizer.Pos, } Type_Cast :: struct { using node: Expr, - tok: token.Token, - open: token.Pos, + tok: tokenizer.Token, + open: tokenizer.Pos, type: ^Expr, - close: token.Pos, + close: tokenizer.Pos, expr: ^Expr, } Auto_Cast :: struct { using node: Expr, - op: token.Token, + op: tokenizer.Token, expr: ^Expr, } @@ -235,7 +235,7 @@ Bad_Stmt :: struct { Empty_Stmt :: struct { using node: Stmt, - semicolon: token.Pos, // Position of the following ';' + semicolon: tokenizer.Pos, // Position of the following ';' } Expr_Stmt :: struct { @@ -245,7 +245,7 @@ Expr_Stmt :: struct { Tag_Stmt :: struct { using node: Stmt, - op: token.Token, + op: tokenizer.Token, name: string, stmt: ^Stmt, } @@ -253,7 +253,7 @@ Tag_Stmt :: struct { Assign_Stmt :: struct { using node: Stmt, lhs: []^Expr, - op: token.Token, + op: tokenizer.Token, rhs: []^Expr, } @@ -261,15 +261,15 @@ Assign_Stmt :: struct { Block_Stmt :: struct { using node: Stmt, label: ^Expr, - open: token.Pos, + open: tokenizer.Pos, stmts: []^Stmt, - close: token.Pos, + close: tokenizer.Pos, } If_Stmt :: struct { using node: Stmt, label: ^Expr, - if_pos: token.Pos, + if_pos: tokenizer.Pos, init: ^Stmt, cond: ^Expr, body: ^Stmt, @@ -278,7 +278,7 @@ If_Stmt :: struct { When_Stmt :: struct { using node: Stmt, - when_pos: token.Pos, + when_pos: tokenizer.Pos, cond: ^Expr, body: ^Stmt, else_stmt: ^Stmt, @@ -297,7 +297,7 @@ Defer_Stmt :: struct { For_Stmt :: struct { using node: Stmt, label: ^Expr, - for_pos: token.Pos, + for_pos: tokenizer.Pos, init: ^Stmt, cond: ^Expr, post: ^Stmt, @@ -307,10 +307,10 @@ For_Stmt :: struct { Range_Stmt :: struct { using node: Stmt, label: ^Expr, - for_pos: token.Pos, + for_pos: tokenizer.Pos, val0: ^Expr, val1: ^Expr, - in_pos: token.Pos, + in_pos: tokenizer.Pos, expr: ^Expr, body: ^Stmt, } @@ -318,16 +318,16 @@ Range_Stmt :: struct { Case_Clause :: struct { using node: Stmt, - case_pos: token.Pos, + case_pos: tokenizer.Pos, list: []^Expr, - terminator: token.Token, + terminator: tokenizer.Token, body: []^Stmt, } Switch_Stmt :: struct { using node: Stmt, label: ^Expr, - switch_pos: token.Pos, + switch_pos: tokenizer.Pos, init: ^Stmt, cond: ^Expr, body: ^Stmt, @@ -337,7 +337,7 @@ Switch_Stmt :: struct { Type_Switch_Stmt :: struct { using node: Stmt, label: ^Expr, - switch_pos: token.Pos, + switch_pos: tokenizer.Pos, tag: ^Stmt, expr: ^Expr, body: ^Stmt, @@ -346,7 +346,7 @@ Type_Switch_Stmt :: struct { Branch_Stmt :: struct { using node: Stmt, - tok: token.Token, + tok: tokenizer.Token, label: ^Ident, } @@ -377,7 +377,7 @@ Value_Decl :: struct { Package_Decl :: struct { using node: Decl, docs: ^Comment_Group, - token: token.Token, + token: tokenizer.Token, name: string, comment: ^Comment_Group, } @@ -386,9 +386,9 @@ Import_Decl :: struct { using node: Decl, docs: ^Comment_Group, is_using: bool, - import_tok: token.Token, - name: token.Token, - relpath: token.Token, + import_tok: tokenizer.Token, + name: tokenizer.Token, + relpath: tokenizer.Token, fullpath: string, comment: ^Comment_Group, } @@ -397,7 +397,7 @@ Foreign_Block_Decl :: struct { using node: Decl, docs: ^Comment_Group, attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily - tok: token.Token, + tok: tokenizer.Token, foreign_library: ^Expr, body: ^Stmt, } @@ -405,8 +405,8 @@ Foreign_Block_Decl :: struct { Foreign_Import_Decl :: struct { using node: Decl, docs: ^Comment_Group, - foreign_tok: token.Token, - import_tok: token.Token, + foreign_tok: tokenizer.Token, + import_tok: tokenizer.Token, name: ^Ident, collection_name: string, fullpaths: []string, @@ -467,18 +467,18 @@ Field_Flags_Signature_Results :: Field_Flags_Signature; Proc_Group :: struct { using node: Expr, - tok: token.Token, - open: token.Pos, + tok: tokenizer.Token, + open: tokenizer.Pos, args: []^Expr, - close: token.Pos, + close: tokenizer.Pos, } Attribute :: struct { using node: Node, - tok: token.Kind, - open: token.Pos, + tok: tokenizer.Token_Kind, + open: tokenizer.Pos, elems: []^Expr, - close: token.Pos, + close: tokenizer.Pos, } Field :: struct { @@ -487,57 +487,57 @@ Field :: struct { names: []^Expr, // Could be polymorphic type: ^Expr, default_value: ^Expr, - tag: token.Token, + tag: tokenizer.Token, flags: Field_Flags, comment: ^Comment_Group, } Field_List :: struct { using node: Node, - open: token.Pos, + open: tokenizer.Pos, list: []^Field, - close: token.Pos, + close: tokenizer.Pos, } // Types Typeid_Type :: struct { using node: Expr, - tok: token.Kind, + tok: tokenizer.Token_Kind, specialization: ^Expr, } Helper_Type :: struct { using node: Expr, - tok: token.Kind, + tok: tokenizer.Token_Kind, type: ^Expr, } Distinct_Type :: struct { using node: Expr, - tok: token.Kind, + tok: tokenizer.Token_Kind, type: ^Expr, } Opaque_Type :: struct { using node: Expr, - tok: token.Kind, + tok: tokenizer.Token_Kind, type: ^Expr, } Poly_Type :: struct { using node: Expr, - dollar: token.Pos, + dollar: tokenizer.Pos, type: ^Ident, specialization: ^Expr, } Proc_Type :: struct { using node: Expr, - tok: token.Token, + tok: tokenizer.Token, calling_convention: Proc_Calling_Convention, params: ^Field_List, - arrow: token.Pos, + arrow: tokenizer.Pos, results: ^Field_List, tags: Proc_Tags, generic: bool, @@ -546,34 +546,34 @@ Proc_Type :: struct { Pointer_Type :: struct { using node: Expr, - pointer: token.Pos, + pointer: tokenizer.Pos, elem: ^Expr, } Array_Type :: struct { using node: Expr, - open: token.Pos, + open: tokenizer.Pos, len: ^Expr, // Ellipsis node for [?]T arrray types, nil for slice types - close: token.Pos, + close: tokenizer.Pos, elem: ^Expr, } Dynamic_Array_Type :: struct { using node: Expr, - open: token.Pos, - dynamic_pos: token.Pos, - close: token.Pos, + open: tokenizer.Pos, + dynamic_pos: tokenizer.Pos, + close: tokenizer.Pos, elem: ^Expr, } Struct_Type :: struct { using node: Expr, - tok_pos: token.Pos, + tok_pos: tokenizer.Pos, poly_params: ^Field_List, align: ^Expr, fields: ^Field_List, name_count: int, - where_token: token.Token, + where_token: tokenizer.Token, where_clauses: []^Expr, is_packed: bool, is_raw_union: bool, @@ -581,46 +581,46 @@ Struct_Type :: struct { Union_Type :: struct { using node: Expr, - tok_pos: token.Pos, + tok_pos: tokenizer.Pos, poly_params: ^Field_List, align: ^Expr, variants: []^Expr, - where_token: token.Token, + where_token: tokenizer.Token, where_clauses: []^Expr, } Enum_Type :: struct { using node: Expr, - tok_pos: token.Pos, + tok_pos: tokenizer.Pos, base_type: ^Expr, - open: token.Pos, + open: tokenizer.Pos, fields: []^Expr, - close: token.Pos, + close: tokenizer.Pos, is_using: bool, } Bit_Field_Type :: struct { using node: Expr, - tok_pos: token.Pos, + tok_pos: tokenizer.Pos, align: ^Expr, - open: token.Pos, + open: tokenizer.Pos, fields: []^Field_Value, // Field_Value with ':' rather than '=' - close: token.Pos, + close: tokenizer.Pos, } Bit_Set_Type :: struct { using node: Expr, - tok_pos: token.Pos, - open: token.Pos, + tok_pos: tokenizer.Pos, + open: tokenizer.Pos, elem: ^Expr, underlying: ^Expr, - close: token.Pos, + close: tokenizer.Pos, } Map_Type :: struct { using node: Expr, - tok_pos: token.Pos, + tok_pos: tokenizer.Pos, key: ^Expr, value: ^Expr, } diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index ded47a931..ddb3068f1 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -2,9 +2,9 @@ package odin_ast import "core:mem" import "core:fmt" -import "core:odin/token" +import "core:odin/tokenizer" -new :: proc($T: typeid, pos, end: token.Pos) -> ^T { +new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T { n := mem.new(T); n.pos = pos; n.end = end; diff --git a/core/odin/ast/file.odin b/core/odin/ast/file.odin index 9d7550f45..dafb10e14 100644 --- a/core/odin/ast/file.odin +++ b/core/odin/ast/file.odin @@ -1,6 +1,6 @@ package odin_ast -import "core:odin/token" +import "core:odin/tokenizer" Package_Kind :: enum { Normal, @@ -26,7 +26,7 @@ File :: struct { src: []byte, pkg_decl: ^Package_Decl, - pkg_token: token.Token, + pkg_token: tokenizer.Token, pkg_name: string, decls: [dynamic]^Stmt, diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index cc3768030..213041924 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1,13 +1,12 @@ package odin_parser import "core:odin/ast" -import "core:odin/token" import "core:odin/tokenizer" import "core:fmt" -Warning_Handler :: #type proc(pos: token.Pos, fmt: string, args: ..any); -Error_Handler :: #type proc(pos: token.Pos, fmt: string, args: ..any); +Warning_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, args: ..any); +Error_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, args: ..any); Parser :: struct { file: ^ast.File, @@ -16,8 +15,8 @@ Parser :: struct { warn: Warning_Handler, err: Error_Handler, - prev_tok: token.Token, - curr_tok: token.Token, + prev_tok: tokenizer.Token, + curr_tok: tokenizer.Token, // >= 0: In Expression // < 0: In Control Clause @@ -50,25 +49,25 @@ Import_Decl_Kind :: enum { -default_warning_handler :: proc(pos: token.Pos, msg: string, args: ..any) { +default_warning_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) { fmt.eprintf("%s(%d:%d): Warning: ", pos.file, pos.line, pos.column); fmt.eprintf(msg, ..args); fmt.eprintf("\n"); } -default_error_handler :: proc(pos: token.Pos, msg: string, args: ..any) { +default_error_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) { fmt.eprintf("%s(%d:%d): ", pos.file, pos.line, pos.column); fmt.eprintf(msg, ..args); fmt.eprintf("\n"); } -warn :: proc(p: ^Parser, pos: token.Pos, msg: string, args: ..any) { +warn :: proc(p: ^Parser, pos: tokenizer.Pos, msg: string, args: ..any) { if p.warn != nil { p.warn(pos, msg, ..args); } p.file.syntax_warning_count += 1; } -error :: proc(p: ^Parser, pos: token.Pos, msg: string, args: ..any) { +error :: proc(p: ^Parser, pos: tokenizer.Pos, msg: string, args: ..any) { if p.err != nil { p.err(pos, msg, ..args); } @@ -77,11 +76,11 @@ error :: proc(p: ^Parser, pos: token.Pos, msg: string, args: ..any) { } -end_pos :: proc(tok: token.Token) -> token.Pos { +end_pos :: proc(tok: tokenizer.Token) -> tokenizer.Pos { pos := tok.pos; pos.offset += len(tok.text); - if tok.kind == token.Comment { + if tok.kind == .Comment { if tok.text[:2] != "/*" { pos.column += len(tok.text); } else { @@ -133,13 +132,13 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool { docs := p.lead_comment; - p.file.pkg_token = expect_token(p, token.Package); - if p.file.pkg_token.kind != token.Package { + p.file.pkg_token = expect_token(p, .Package); + if p.file.pkg_token.kind != .Package { return false; } - pkg_name := expect_token_after(p, token.Ident, "package"); - if pkg_name.kind == token.Ident { + pkg_name := expect_token_after(p, .Ident, "package"); + if pkg_name.kind == .Ident { if is_blank_ident(pkg_name) { error(p, pkg_name.pos, "invalid package name '_'"); } @@ -161,7 +160,7 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool { p.file.decls = make([dynamic]^ast.Stmt); - for p.curr_tok.kind != token.EOF { + for p.curr_tok.kind != .EOF { stmt := parse_stmt(p); if stmt != nil { if _, ok := stmt.derived.(ast.Empty_Stmt); !ok { @@ -181,16 +180,16 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool { next_token0 :: proc(p: ^Parser) -> bool { p.curr_tok = tokenizer.scan(&p.tok); - if p.curr_tok.kind == token.EOF { + if p.curr_tok.kind == .EOF { // error(p, p.curr_tok.pos, "token is EOF"); return false; } return true; } -consume_comment :: proc(p: ^Parser) -> (tok: token.Token, end_line: int) { +consume_comment :: proc(p: ^Parser) -> (tok: tokenizer.Token, end_line: int) { tok = p.curr_tok; - assert(tok.kind == token.Comment); + assert(tok.kind == .Comment); end_line = tok.pos.line; if tok.text[1] == '*' { @@ -210,11 +209,11 @@ consume_comment :: proc(p: ^Parser) -> (tok: token.Token, end_line: int) { } consume_comment_group :: proc(p: ^Parser, n: int) -> (comments: ^ast.Comment_Group, end_line: int) { - list: [dynamic]token.Token; + list: [dynamic]tokenizer.Token; end_line = p.curr_tok.pos.line; - for p.curr_tok.kind == token.Comment && + for p.curr_tok.kind == .Comment && p.curr_tok.pos.line <= end_line+n { - comment: token.Token; + comment: tokenizer.Token; comment, end_line = consume_comment(p); append(&list, comment); } @@ -228,31 +227,31 @@ consume_comment_group :: proc(p: ^Parser, n: int) -> (comments: ^ast.Comment_Gro return; } -consume_comment_groups :: proc(p: ^Parser, prev: token.Token) { - if p.curr_tok.kind == token.Comment { +consume_comment_groups :: proc(p: ^Parser, prev: tokenizer.Token) { + if p.curr_tok.kind == .Comment { comment: ^ast.Comment_Group; end_line := 0; if p.curr_tok.pos.line == prev.pos.line { comment, end_line = consume_comment_group(p, 0); - if p.curr_tok.pos.line != end_line || p.curr_tok.kind == token.EOF { + if p.curr_tok.pos.line != end_line || p.curr_tok.kind == .EOF { p.line_comment = comment; } } end_line = -1; - for p.curr_tok.kind == token.Comment { + for p.curr_tok.kind == .Comment { comment, end_line = consume_comment_group(p, 1); } if end_line+1 >= p.curr_tok.pos.line || end_line < 0 { p.lead_comment = comment; } - assert(p.curr_tok.kind != token.Comment); + assert(p.curr_tok.kind != .Comment); } } -advance_token :: proc(p: ^Parser) -> token.Token { +advance_token :: proc(p: ^Parser) -> tokenizer.Token { p.lead_comment = nil; p.line_comment = nil; p.prev_tok = p.curr_tok; @@ -264,39 +263,39 @@ advance_token :: proc(p: ^Parser) -> token.Token { return prev; } -expect_token :: proc(p: ^Parser, kind: token.Kind) -> token.Token { +expect_token :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> tokenizer.Token { prev := p.curr_tok; if prev.kind != kind { - e := token.to_string(kind); - g := token.to_string(prev.kind); + e := tokenizer.to_string(kind); + g := tokenizer.to_string(prev.kind); error(p, prev.pos, "expected '%s', got '%s'", e, g); } advance_token(p); return prev; } -expect_token_after :: proc(p: ^Parser, kind: token.Kind, msg: string) -> token.Token { +expect_token_after :: proc(p: ^Parser, kind: tokenizer.Token_Kind, msg: string) -> tokenizer.Token { prev := p.curr_tok; if prev.kind != kind { - e := token.to_string(kind); - g := token.to_string(prev.kind); + e := tokenizer.to_string(kind); + g := tokenizer.to_string(prev.kind); error(p, prev.pos, "expected '%s' after %s, got '%s'", e, msg, g); } advance_token(p); return prev; } -expect_operator :: proc(p: ^Parser) -> token.Token { +expect_operator :: proc(p: ^Parser) -> tokenizer.Token { prev := p.curr_tok; - if !token.is_operator(prev.kind) { - g := token.to_string(prev.kind); + if !tokenizer.is_operator(prev.kind) { + g := tokenizer.to_string(prev.kind); error(p, prev.pos, "expected an operator, got '%s'", g); } advance_token(p); return prev; } -allow_token :: proc(p: ^Parser, kind: token.Kind) -> bool { +allow_token :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> bool { if p.curr_tok.kind == kind { advance_token(p); return true; @@ -313,8 +312,8 @@ is_blank_ident :: proc{ is_blank_ident_string :: inline proc(str: string) -> bool { return str == "_"; } -is_blank_ident_token :: inline proc(tok: token.Token) -> bool { - if tok.kind == token.Ident { +is_blank_ident_token :: inline proc(tok: tokenizer.Token) -> bool { + if tok.kind == .Ident { return is_blank_ident_string(tok.text); } return false; @@ -347,7 +346,8 @@ is_semicolon_optional_for_node :: proc(p: ^Parser, node: ^ast.Node) -> bool { case ast.Pointer_Type: return is_semicolon_optional_for_node(p, n.elem); case ast.Struct_Type, ast.Union_Type, ast.Enum_Type, ast.Bit_Field_Type: - return true; + // Require semicolon within a procedure body + return p.curr_proc == nil; case ast.Proc_Lit: return true; @@ -371,16 +371,16 @@ is_semicolon_optional_for_node :: proc(p: ^Parser, node: ^ast.Node) -> bool { expect_semicolon :: proc(p: ^Parser, node: ^ast.Node) -> bool { - if allow_token(p, token.Semicolon) { + if allow_token(p, .Semicolon) { return true; } prev := p.prev_tok; - if prev.kind == token.Semicolon { + if prev.kind == .Semicolon { return true; } - if p.curr_tok.kind == token.EOF { + if p.curr_tok.kind == .EOF { return true; } @@ -391,20 +391,20 @@ expect_semicolon :: proc(p: ^Parser, node: ^ast.Node) -> bool { } } else { switch p.curr_tok.kind { - case token.Close_Brace: - case token.Close_Paren: - case token.Else: + case .Close_Brace: + case .Close_Paren: + case .Else: return true; } } } - error(p, prev.pos, "expected ';', got %s", token.to_string(prev.kind)); + error(p, prev.pos, "expected ';', got %s", tokenizer.to_string(prev.kind)); return false; } -new_blank_ident :: proc(p: ^Parser, pos: token.Pos) -> ^ast.Ident { - tok: token.Token; +new_blank_ident :: proc(p: ^Parser, pos: tokenizer.Pos) -> ^ast.Ident { + tok: tokenizer.Token; tok.pos = pos; i := ast.new(ast.Ident, pos, end_pos(tok)); i.name = "_"; @@ -415,11 +415,11 @@ parse_ident :: proc(p: ^Parser) -> ^ast.Ident { tok := p.curr_tok; pos := tok.pos; name := "_"; - if tok.kind == token.Ident { + if tok.kind == .Ident { name = tok.text; advance_token(p); } else { - expect_token(p, token.Ident); + expect_token(p, .Ident); } i := ast.new(ast.Ident, pos, end_pos(tok)); i.name = name; @@ -428,9 +428,9 @@ parse_ident :: proc(p: ^Parser) -> ^ast.Ident { parse_stmt_list :: proc(p: ^Parser) -> []^ast.Stmt { list: [dynamic]^ast.Stmt; - for p.curr_tok.kind != token.Case && - p.curr_tok.kind != token.Close_Brace && - p.curr_tok.kind != token.EOF { + for p.curr_tok.kind != .Case && + p.curr_tok.kind != .Close_Brace && + p.curr_tok.kind != .EOF { stmt := parse_stmt(p); if stmt != nil { if _, ok := stmt.derived.(ast.Empty_Stmt); !ok { @@ -454,7 +454,7 @@ parse_block_stmt :: proc(p: ^Parser, is_when: bool) -> ^ast.Stmt { } parse_when_stmt :: proc(p: ^Parser) -> ^ast.When_Stmt { - tok := expect_token(p, token.When); + tok := expect_token(p, .When); cond: ^ast.Expr; body: ^ast.Stmt; @@ -468,20 +468,20 @@ parse_when_stmt :: proc(p: ^Parser) -> ^ast.When_Stmt { if cond == nil { error(p, p.curr_tok.pos, "expected a condition for when statement"); } - if allow_token(p, token.Do) { + if allow_token(p, .Do) { body = convert_stmt_to_body(p, parse_stmt(p)); } else { body = parse_block_stmt(p, true); } - if allow_token(p, token.Else) { + if allow_token(p, .Else) { switch p.curr_tok.kind { - case token.When: + case .When: else_stmt = parse_when_stmt(p); - case token.Open_Brace: + case .Open_Brace: else_stmt = parse_block_stmt(p, true); - case token.Do: - expect_token(p, token.Do); + case .Do: + expect_token(p, .Do); else_stmt = convert_stmt_to_body(p, parse_stmt(p)); case: error(p, p.curr_tok.pos, "expected when statement block statement"); @@ -513,7 +513,7 @@ convert_stmt_to_expr :: proc(p: ^Parser, stmt: ^ast.Stmt, kind: string) -> ^ast. } parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt { - tok := expect_token(p, token.If); + tok := expect_token(p, .If); init: ^ast.Stmt; cond: ^ast.Expr; @@ -524,11 +524,11 @@ parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt { p.expr_level = -1; prev_allow_in_expr := p.allow_in_expr; p.allow_in_expr = true; - if allow_token(p, token.Semicolon) { + if allow_token(p, .Semicolon) { cond = parse_expr(p, false); } else { init = parse_simple_stmt(p, nil); - if allow_token(p, token.Semicolon) { + if allow_token(p, .Semicolon) { cond = parse_expr(p, false); } else { cond = convert_stmt_to_expr(p, init, "boolean expression"); @@ -543,20 +543,20 @@ parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt { error(p, p.curr_tok.pos, "expected a condition for if statement"); } - if allow_token(p, token.Do) { + if allow_token(p, .Do) { body = convert_stmt_to_body(p, parse_stmt(p)); } else { body = parse_block_stmt(p, false); } - if allow_token(p, token.Else) { + if allow_token(p, .Else) { switch p.curr_tok.kind { - case token.If: + case .If: else_stmt = parse_if_stmt(p); - case token.Open_Brace: + case .Open_Brace: else_stmt = parse_block_stmt(p, false); - case token.Do: - expect_token(p, token.Do); + case .Do: + expect_token(p, .Do); else_stmt = convert_stmt_to_body(p, parse_stmt(p)); case: error(p, p.curr_tok.pos, "expected if statement block statement"); @@ -582,7 +582,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { error(p, p.curr_tok.pos, "you cannot use a for statement in the file scope"); } - tok := expect_token(p, token.For); + tok := expect_token(p, .For); init: ^ast.Stmt; cond: ^ast.Stmt; @@ -590,13 +590,13 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { body: ^ast.Stmt; is_range := false; - if p.curr_tok.kind != token.Open_Brace && p.curr_tok.kind != token.Do { + if p.curr_tok.kind != .Open_Brace && p.curr_tok.kind != .Do { prev_level := p.expr_level; defer p.expr_level = prev_level; p.expr_level = -1; - if p.curr_tok.kind == token.In { - in_tok := expect_token(p, token.In); + if p.curr_tok.kind == .In { + in_tok := expect_token(p, .In); rhs: ^ast.Expr; prev_allow_range := p.allow_range; @@ -604,7 +604,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { rhs = parse_expr(p, false); p.allow_range = prev_allow_range; - if allow_token(p, token.Do) { + if allow_token(p, .Do) { body = convert_stmt_to_body(p, parse_stmt(p)); } else { body = parse_body(p); @@ -618,27 +618,27 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { return range_stmt; } - if p.curr_tok.kind != token.Semicolon { + if p.curr_tok.kind != .Semicolon { cond = parse_simple_stmt(p, {Stmt_Allow_Flag.In}); - if as, ok := cond.derived.(ast.Assign_Stmt); ok && as.op.kind == token.In { + if as, ok := cond.derived.(ast.Assign_Stmt); ok && as.op.kind == .In { is_range = true; } } - if !is_range && allow_token(p, token.Semicolon) { + if !is_range && allow_token(p, .Semicolon) { init = cond; cond = nil; - if p.curr_tok.kind != token.Semicolon { + if p.curr_tok.kind != .Semicolon { cond = parse_simple_stmt(p, nil); } expect_semicolon(p, cond); - if p.curr_tok.kind != token.Open_Brace && p.curr_tok.kind != token.Do { + if p.curr_tok.kind != .Open_Brace && p.curr_tok.kind != .Do { post = parse_simple_stmt(p, nil); } } } - if allow_token(p, token.Do) { + if allow_token(p, .Do) { body = convert_stmt_to_body(p, parse_stmt(p)); } else { body = parse_body(p); @@ -686,11 +686,11 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt { } parse_case_clause :: proc(p: ^Parser, is_type_switch: bool) -> ^ast.Case_Clause { - tok := expect_token(p, token.Case); + tok := expect_token(p, .Case); list: []^ast.Expr; - if p.curr_tok.kind != token.Colon { + if p.curr_tok.kind != .Colon { prev_allow_range, prev_allow_in_expr := p.allow_range, p.allow_in_expr; defer p.allow_range, p.allow_in_expr = prev_allow_range, prev_allow_in_expr; p.allow_range, p.allow_in_expr = !is_type_switch, !is_type_switch; @@ -698,7 +698,7 @@ parse_case_clause :: proc(p: ^Parser, is_type_switch: bool) -> ^ast.Case_Clause list = parse_rhs_expr_list(p); } - terminator := expect_token(p, token.Colon); + terminator := expect_token(p, .Colon); stmts := parse_stmt_list(p); @@ -710,20 +710,20 @@ parse_case_clause :: proc(p: ^Parser, is_type_switch: bool) -> ^ast.Case_Clause } parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt { - tok := expect_token(p, token.Switch); + tok := expect_token(p, .Switch); init: ^ast.Stmt; tag: ^ast.Stmt; is_type_switch := false; clauses: [dynamic]^ast.Stmt; - if p.curr_tok.kind != token.Open_Brace { + if p.curr_tok.kind != .Open_Brace { prev_level := p.expr_level; defer p.expr_level = prev_level; p.expr_level = -1; - if p.curr_tok.kind == token.In { - in_tok := expect_token(p, token.In); + if p.curr_tok.kind == .In { + in_tok := expect_token(p, .In); is_type_switch = true; lhs := make([]^ast.Expr, 1); @@ -738,12 +738,12 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt { tag = as; } else { tag = parse_simple_stmt(p, {Stmt_Allow_Flag.In}); - if as, ok := tag.derived.(ast.Assign_Stmt); ok && as.op.kind == token.In { + if as, ok := tag.derived.(ast.Assign_Stmt); ok && as.op.kind == .In { is_type_switch = true; - } else if allow_token(p, token.Semicolon) { + } else if allow_token(p, .Semicolon) { init = tag; tag = nil; - if p.curr_tok.kind != token.Open_Brace { + if p.curr_tok.kind != .Open_Brace { tag = parse_simple_stmt(p, nil); } } @@ -751,14 +751,14 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt { } - open := expect_token(p, token.Open_Brace); + open := expect_token(p, .Open_Brace); - for p.curr_tok.kind == token.Case { + for p.curr_tok.kind == .Case { clause := parse_case_clause(p, is_type_switch); append(&clauses, clause); } - close := expect_token(p, token.Close_Brace); + close := expect_token(p, .Close_Brace); body := ast.new(ast.Block_Stmt, open.pos, end_pos(close)); body.stmts = clauses[:]; @@ -778,23 +778,23 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt { } } -parse_attribute :: proc(p: ^Parser, tok: token.Token, open_kind, close_kind: token.Kind, docs: ^ast.Comment_Group) -> ^ast.Stmt { +parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind: tokenizer.Token_Kind, docs: ^ast.Comment_Group) -> ^ast.Stmt { elems: [dynamic]^ast.Expr; - open, close: token.Token; + open, close: tokenizer.Token; - if p.curr_tok.kind == token.Ident { + if p.curr_tok.kind == .Ident { elem := parse_ident(p); append(&elems, elem); } else { open = expect_token(p, open_kind); p.expr_level += 1; for p.curr_tok.kind != close_kind && - p.curr_tok.kind != token.EOF { + p.curr_tok.kind != .EOF { elem: ^ast.Expr; elem = parse_ident(p); - if p.curr_tok.kind == token.Eq { - eq := expect_token(p, token.Eq); + if p.curr_tok.kind == .Eq { + eq := expect_token(p, .Eq); value := parse_value(p); fv := ast.new(ast.Field_Value, elem.pos, value.end); fv.field = elem; @@ -805,7 +805,7 @@ parse_attribute :: proc(p: ^Parser, tok: token.Token, open_kind, close_kind: tok } append(&elems, elem); - if !allow_token(p, token.Comma) { + if !allow_token(p, .Comma) { break; } } @@ -852,12 +852,12 @@ parse_foreign_block_decl :: proc(p: ^Parser) -> ^ast.Stmt { } -parse_foreign_block :: proc(p: ^Parser, tok: token.Token) -> ^ast.Foreign_Block_Decl { +parse_foreign_block :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Foreign_Block_Decl { docs := p.lead_comment; foreign_library: ^ast.Expr; switch p.curr_tok.kind { - case token.Open_Brace: + case .Open_Brace: i := ast.new(ast.Ident, tok.pos, end_pos(tok)); i.name = "_"; foreign_library = i; @@ -871,14 +871,14 @@ parse_foreign_block :: proc(p: ^Parser, tok: token.Token) -> ^ast.Foreign_Block_ defer p.in_foreign_block = prev_in_foreign_block; p.in_foreign_block = true; - open := expect_token(p, token.Open_Brace); - for p.curr_tok.kind != token.Close_Brace && p.curr_tok.kind != token.EOF { + open := expect_token(p, .Open_Brace); + for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF { decl := parse_foreign_block_decl(p); if decl != nil { append(&decls, decl); } } - close := expect_token(p, token.Close_Brace); + close := expect_token(p, .Close_Brace); body := ast.new(ast.Block_Stmt, open.pos, end_pos(close)); body.open = open.pos; @@ -896,16 +896,16 @@ parse_foreign_block :: proc(p: ^Parser, tok: token.Token) -> ^ast.Foreign_Block_ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl { docs := p.lead_comment; - tok := expect_token(p, token.Foreign); + tok := expect_token(p, .Foreign); switch p.curr_tok.kind { - case token.Ident, token.Open_Brace: + case .Ident, .Open_Brace: return parse_foreign_block(p, tok); - case token.Import: - import_tok := expect_token(p, token.Import); + case .Import: + import_tok := expect_token(p, .Import); name: ^ast.Ident; - if p.curr_tok.kind == token.Ident { + if p.curr_tok.kind == .Ident { name = parse_ident(p); } @@ -914,19 +914,19 @@ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl { } fullpaths: [dynamic]string; - if allow_token(p, token.Open_Brace) { - for p.curr_tok.kind != token.Close_Brace && - p.curr_tok.kind != token.EOF { - path := expect_token(p, token.String); + if allow_token(p, .Open_Brace) { + for p.curr_tok.kind != .Close_Brace && + p.curr_tok.kind != .EOF { + path := expect_token(p, .String); append(&fullpaths, path.text); - if !allow_token(p, token.Comma) { + if !allow_token(p, .Comma) { break; } } - expect_token(p, token.Close_Brace); + expect_token(p, .Close_Brace); } else { - path := expect_token(p, token.String); + path := expect_token(p, .String); reserve(&fullpaths, 1); append(&fullpaths, path.text); } @@ -954,29 +954,29 @@ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl { parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { switch p.curr_tok.kind { // Operands - case token.Context, // Also allows for 'context = ' - token.Proc, - token.Inline, token.No_Inline, - token.Ident, - token.Integer, token.Float, token.Imag, - token.Rune, token.String, - token.Open_Paren, - token.Pointer, + case .Context, // Also allows for 'context = ' + .Proc, + .Inline, .No_Inline, + .Ident, + .Integer, .Float, .Imag, + .Rune, .String, + .Open_Paren, + .Pointer, // Unary Expressions - token.Add, token.Sub, token.Xor, token.Not, token.And: + .Add, .Sub, .Xor, .Not, .And: s := parse_simple_stmt(p, {Stmt_Allow_Flag.Label}); expect_semicolon(p, s); return s; - case token.Import: return parse_import_decl(p); - case token.Foreign: return parse_foreign_decl(p); - case token.If: return parse_if_stmt(p); - case token.When: return parse_when_stmt(p); - case token.For: return parse_for_stmt(p); - case token.Switch: return parse_switch_stmt(p); + case .Import: return parse_import_decl(p); + case .Foreign: return parse_foreign_decl(p); + case .If: return parse_if_stmt(p); + case .When: return parse_when_stmt(p); + case .For: return parse_for_stmt(p); + case .Switch: return parse_switch_stmt(p); - case token.Defer: + case .Defer: tok := advance_token(p); stmt := parse_stmt(p); switch s in stmt.derived { @@ -992,7 +992,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { ds.stmt = stmt; return ds; - case token.Return: + case .Return: tok := advance_token(p); if p.expr_level > 0 { @@ -1000,11 +1000,11 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { } results: [dynamic]^ast.Expr; - for p.curr_tok.kind != token.Semicolon { + for p.curr_tok.kind != .Semicolon { result := parse_expr(p, false); append(&results, result); - if p.curr_tok.kind != token.Comma || - p.curr_tok.kind == token.EOF { + if p.curr_tok.kind != .Comma || + p.curr_tok.kind == .EOF { break; } advance_token(p); @@ -1019,10 +1019,10 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { rs.results = results[:]; return rs; - case token.Break, token.Continue, token.Fallthrough: + case .Break, .Continue, .Fallthrough: tok := advance_token(p); label: ^ast.Expr; - if tok.kind != token.Fallthrough && p.curr_tok.kind == token.Ident { + if tok.kind != .Fallthrough && p.curr_tok.kind == .Ident { label = parse_ident(p); } end := label != nil ? label.end : end_pos(tok); @@ -1030,11 +1030,11 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { expect_semicolon(p, s); return s; - case token.Using: + case .Using: docs := p.lead_comment; - tok := expect_token(p, token.Using); + tok := expect_token(p, .Using); - if p.curr_tok.kind == token.Import { + if p.curr_tok.kind == .Import { return parse_import_decl(p, Import_Decl_Kind.Using); } @@ -1045,14 +1045,14 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { return ast.new(ast.Bad_Stmt, tok.pos, end_pos(p.prev_tok)); } - if p.curr_tok.kind != token.Colon { + if p.curr_tok.kind != .Colon { end := list[len(list)-1]; expect_semicolon(p, end); us := ast.new(ast.Using_Stmt, tok.pos, end.end); us.list = list; return us; } - expect_token_after(p, token.Colon, "identifier list"); + expect_token_after(p, .Colon, "identifier list"); decl := parse_value_decl(p, list, docs); if decl != nil do switch d in &decl.derived { case ast.Value_Decl: @@ -1063,14 +1063,14 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { error(p, tok.pos, "illegal use of 'using' statement"); return ast.new(ast.Bad_Stmt, tok.pos, end_pos(p.prev_tok)); - case token.At: + case .At: docs := p.lead_comment; tok := advance_token(p); - return parse_attribute(p, tok, token.Open_Paren, token.Close_Paren, docs); + return parse_attribute(p, tok, .Open_Paren, .Close_Paren, docs); - case token.Hash: - tok := expect_token(p, token.Hash); - tag := expect_token(p, token.Ident); + case .Hash: + tok := expect_token(p, .Hash); + tag := expect_token(p, .Ident); name := tag.text; switch name { @@ -1110,50 +1110,50 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { te.stmt = stmt; return te; } - case token.Open_Brace: + case .Open_Brace: return parse_block_stmt(p, false); - case token.Semicolon: + case .Semicolon: tok := advance_token(p); s := ast.new(ast.Empty_Stmt, tok.pos, end_pos(tok)); return s; } tok := advance_token(p); - error(p, tok.pos, "expected a statement, got %s", token.to_string(tok.kind)); + error(p, tok.pos, "expected a statement, got %s", tokenizer.to_string(tok.kind)); s := ast.new(ast.Bad_Stmt, tok.pos, end_pos(tok)); return s; } -token_precedence :: proc(p: ^Parser, kind: token.Kind) -> int { +token_precedence :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> int { switch kind { - case token.Question: + case .Question: return 1; - case token.Ellipsis, token.Range_Half: + case .Ellipsis, .Range_Half: if !p.allow_range { return 0; } return 2; - case token.Cmp_Or: + case .Cmp_Or: return 3; - case token.Cmp_And: + case .Cmp_And: return 4; - case token.Cmp_Eq, token.Not_Eq, - token.Lt, token.Gt, - token.Lt_Eq, token.Gt_Eq: + case .Cmp_Eq, .Not_Eq, + .Lt, .Gt, + .Lt_Eq, .Gt_Eq: return 5; - case token.In, token.Notin: + case .In, .Notin: if p.expr_level < 0 && !p.allow_in_expr { return 0; } fallthrough; - case token.Add, token.Sub, token.Or, token.Xor: + case .Add, .Sub, .Or, .Xor: return 6; - case token.Mul, token.Quo, - token.Mod, token.Mod_Mod, - token.And, token.And_Not, - token.Shl, token.Shr: + case .Mul, .Quo, + .Mod, .Mod_Mod, + .And, .And_Not, + .Shl, .Shr: return 7; } return 0; @@ -1187,9 +1187,9 @@ parse_body :: proc(p: ^Parser) -> ^ast.Block_Stmt { defer p.expr_level = prev_expr_level; p.expr_level = 0; - open := expect_token(p, token.Open_Brace); + open := expect_token(p, .Open_Brace); stmts := parse_stmt_list(p); - close := expect_token(p, token.Close_Brace); + close := expect_token(p, .Close_Brace); bs := ast.new(ast.Block_Stmt, open.pos, end_pos(close)); bs.open = open.pos; @@ -1216,7 +1216,7 @@ convert_stmt_to_body :: proc(p: ^Parser, stmt: ^ast.Stmt) -> ^ast.Stmt { } new_ast_field :: proc(names: []^ast.Expr, type: ^ast.Expr, default_value: ^ast.Expr) -> ^ast.Field { - pos, end: token.Pos; + pos, end: tokenizer.Pos; if len(names) > 0 { pos = names[0].pos; @@ -1306,22 +1306,22 @@ convert_to_ident_list :: proc(p: ^Parser, list: []Expr_And_Flags, ignore_flags, is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix { using Field_Prefix; switch p.curr_tok.kind { - case token.EOF: + case .EOF: return Invalid; - case token.Using: + case .Using: advance_token(p); return Using; - case token.In: + case .In: advance_token(p); return In; - case token.Auto_Cast: + case .Auto_Cast: advance_token(p); return Auto_Cast; - case token.Hash: + case .Hash: advance_token(p); defer advance_token(p); switch p.curr_tok.kind { - case token.Ident: + case .Ident: switch p.curr_tok.text { case "no_alias": return No_Alias; @@ -1414,7 +1414,7 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se } parse_var_type :: proc(p: ^Parser, flags: ast.Field_Flags) -> ^ast.Expr { - if ast.Field_Flag.Ellipsis in flags && p.curr_tok.kind == token.Ellipsis { + if ast.Field_Flag.Ellipsis in flags && p.curr_tok.kind == .Ellipsis { tok := advance_token(p); type := parse_type_or_ident(p); if type == nil { @@ -1426,11 +1426,11 @@ parse_var_type :: proc(p: ^Parser, flags: ast.Field_Flags) -> ^ast.Expr { return e; } type: ^ast.Expr; - if ast.Field_Flag.Typeid_Token in flags && p.curr_tok.kind == token.Typeid { - tok := expect_token(p, token.Typeid); + if ast.Field_Flag.Typeid_Token in flags && p.curr_tok.kind == .Typeid { + tok := expect_token(p, .Typeid); specialization: ^ast.Expr; end := tok.pos; - if allow_token(p, token.Quo) { + if allow_token(p, .Quo) { specialization = parse_type(p); end = specialization.end; } @@ -1482,8 +1482,8 @@ parse_ident_list :: proc(p: ^Parser, allow_poly_names: bool) -> []^ast.Expr { list: [dynamic]^ast.Expr; for { - if allow_poly_names && p.curr_tok.kind == token.Dollar { - tok := expect_token(p, token.Dollar); + if allow_poly_names && p.curr_tok.kind == .Dollar { + tok := expect_token(p, .Dollar); ident := parse_ident(p); if is_blank_ident(ident) { error(p, ident.pos, "invalid polymorphic type definition with a blank identifier"); @@ -1495,8 +1495,8 @@ parse_ident_list :: proc(p: ^Parser, allow_poly_names: bool) -> []^ast.Expr { ident := parse_ident(p); append(&list, ident); } - if p.curr_tok.kind != token.Comma || - p.curr_tok.kind == token.EOF { + if p.curr_tok.kind != .Comma || + p.curr_tok.kind == .EOF { break; } advance_token(p); @@ -1507,7 +1507,7 @@ parse_ident_list :: proc(p: ^Parser, allow_poly_names: bool) -> []^ast.Expr { -parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Field_Flags) -> (field_list: ^ast.Field_List, total_name_count: int) { +parse_field_list :: proc(p: ^Parser, follow: tokenizer.Token_Kind, allowed_flags: ast.Field_Flags) -> (field_list: ^ast.Field_List, total_name_count: int) { handle_field :: proc(p: ^Parser, seen_ellipsis: ^bool, fields: ^[dynamic]^ast.Field, docs: ^ast.Comment_Group, @@ -1517,10 +1517,10 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel expect_field_separator :: proc(p: ^Parser, param: ^ast.Expr) -> bool { tok := p.curr_tok; - if allow_token(p, token.Comma) { + if allow_token(p, .Comma) { return true; } - if allow_token(p, token.Semicolon) { + if allow_token(p, .Semicolon) { error(p, tok.pos, "expected a comma, got a semicolon"); return true; } @@ -1539,10 +1539,10 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel type: ^ast.Expr; default_value: ^ast.Expr; - tag: token.Token; + tag: tokenizer.Token; - expect_token_after(p, token.Colon, "field list"); - if p.curr_tok.kind != token.Eq { + expect_token_after(p, .Colon, "field list"); + if p.curr_tok.kind != .Eq { type = parse_var_type(p, allowed_flags); tt := ast.unparen_expr(type); if is_signature && !any_polymorphic_names { @@ -1552,7 +1552,7 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel } } - if allow_token(p, token.Eq) { + if allow_token(p, .Eq) { default_value = parse_expr(p, false); if ast.Field_Flag.Default_Parameters notin allowed_flags { error(p, p.curr_tok.pos, "default parameters are only allowed for procedures"); @@ -1580,8 +1580,8 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel } if type != nil && default_value == nil { - if p.curr_tok.kind == token.String { - tag = expect_token(p, token.String); + if p.curr_tok.kind == .String { + tag = expect_token(p, .String); if .Tags notin allowed_flags { error(p, tag.pos, "Field tags are only allowed within structures"); } @@ -1616,8 +1616,8 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel allow_poly_names := allow_typeid_token; for p.curr_tok.kind != follow && - p.curr_tok.kind != token.Colon && - p.curr_tok.kind != token.EOF { + p.curr_tok.kind != .Colon && + p.curr_tok.kind != .EOF { prefix_flags := parse_field_prefixes(p); param := parse_var_type(p, allowed_flags & {ast.Field_Flag.Typeid_Token, ast.Field_Flag.Ellipsis}); if _, ok := param.derived.(ast.Ellipsis); ok { @@ -1631,15 +1631,15 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel eaf := Expr_And_Flags{param, prefix_flags}; append(&list, eaf); - if !allow_token(p, token.Comma) { + if !allow_token(p, .Comma) { break; } } - if p.curr_tok.kind != token.Colon { + if p.curr_tok.kind != .Colon { for eaf in list { type := eaf.expr; - tok: token.Token; + tok: tokenizer.Token; tok.pos = type.pos; if ast.Field_Flag.Results notin allowed_flags { tok.text = "_"; @@ -1670,7 +1670,7 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel total_name_count += len(names); handle_field(p, &seen_ellipsis, &fields, docs, names, allowed_flags, set_flags); - for p.curr_tok.kind != follow && p.curr_tok.kind != token.EOF { + for p.curr_tok.kind != follow && p.curr_tok.kind != .EOF { docs = p.lead_comment; set_flags = parse_field_prefixes(p); names = parse_ident_list(p, allow_poly_names); @@ -1690,11 +1690,11 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel parse_results :: proc(p: ^Parser) -> (list: ^ast.Field_List, diverging: bool) { - if !allow_token(p, token.Arrow_Right) { + if !allow_token(p, .Arrow_Right) { return; } - if allow_token(p, token.Not) { + if allow_token(p, .Not) { diverging = true; return; } @@ -1702,7 +1702,7 @@ parse_results :: proc(p: ^Parser) -> (list: ^ast.Field_List, diverging: bool) { prev_level := p.expr_level; defer p.expr_level = prev_level; - if p.curr_tok.kind != token.Open_Paren { + if p.curr_tok.kind != .Open_Paren { type := parse_type(p); field := new_ast_field(nil, type, nil); @@ -1712,9 +1712,9 @@ parse_results :: proc(p: ^Parser) -> (list: ^ast.Field_List, diverging: bool) { return; } - expect_token(p, token.Open_Paren); - list, _ = parse_field_list(p, token.Close_Paren, ast.Field_Flags_Signature_Results); - expect_token_after(p, token.Close_Paren, "parameter list"); + expect_token(p, .Open_Paren); + list, _ = parse_field_list(p, .Close_Paren, ast.Field_Flags_Signature_Results); + expect_token_after(p, .Close_Paren, "parameter list"); return; } @@ -1740,9 +1740,9 @@ string_to_calling_convention :: proc(s: string) -> ast.Proc_Calling_Convention { } parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) { - for p.curr_tok.kind == token.Hash { - _ = expect_token(p, token.Hash); - ident := expect_token(p, token.Ident); + for p.curr_tok.kind == .Hash { + _ = expect_token(p, .Hash); + ident := expect_token(p, .Ident); switch ident.text { case "bounds_check": @@ -1760,10 +1760,10 @@ parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) { return; } -parse_proc_type :: proc(p: ^Parser, tok: token.Token) -> ^ast.Proc_Type { +parse_proc_type :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Proc_Type { cc := ast.Proc_Calling_Convention.Invalid; - if p.curr_tok.kind == token.String { - str := expect_token(p, token.String); + if p.curr_tok.kind == .String { + str := expect_token(p, .String); cc = string_to_calling_convention(str.text); if cc == ast.Proc_Calling_Convention.Invalid { error(p, str.pos, "unknown calling convention '%s'", str.text); @@ -1778,9 +1778,9 @@ parse_proc_type :: proc(p: ^Parser, tok: token.Token) -> ^ast.Proc_Type { } } - expect_token(p, token.Open_Paren); - params, _ := parse_field_list(p, token.Close_Paren, ast.Field_Flags_Signature_Params); - expect_token(p, token.Close_Paren); + expect_token(p, .Open_Paren); + params, _ := parse_field_list(p, .Close_Paren, ast.Field_Flags_Signature_Params); + expect_token(p, .Close_Paren); results, diverging := parse_results(p); is_generic := false; @@ -1811,7 +1811,7 @@ parse_proc_type :: proc(p: ^Parser, tok: token.Token) -> ^ast.Proc_Type { return pt; } -check_poly_params_for_type :: proc(p: ^Parser, poly_params: ^ast.Field_List, tok: token.Token) { +check_poly_params_for_type :: proc(p: ^Parser, poly_params: ^ast.Field_List, tok: tokenizer.Token) { if poly_params == nil { return; } @@ -1830,46 +1830,46 @@ check_poly_params_for_type :: proc(p: ^Parser, poly_params: ^ast.Field_List, tok parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { switch p.curr_tok.kind { - case token.Ident: + case .Ident: return parse_ident(p); - case token.Undef: - tok := expect_token(p, token.Undef); + case .Undef: + tok := expect_token(p, .Undef); undef := ast.new(ast.Undef, tok.pos, end_pos(tok)); undef.tok = tok.kind; return undef; - case token.Context: - tok := expect_token(p, token.Context); + case .Context: + tok := expect_token(p, .Context); ctx := ast.new(ast.Implicit, tok.pos, end_pos(tok)); ctx.tok = tok; return ctx; - case token.Integer, token.Float, token.Imag, - token.Rune, token.String: + case .Integer, .Float, .Imag, + .Rune, .String: tok := advance_token(p); bl := ast.new(ast.Basic_Lit, tok.pos, end_pos(tok)); bl.tok = tok; return bl; - case token.Size_Of, token.Align_Of, token.Offset_Of: + case .Size_Of, .Align_Of, .Offset_Of: tok := advance_token(p); expr := ast.new(ast.Implicit, tok.pos, end_pos(tok)); expr.tok = tok; return parse_call_expr(p, expr); - case token.Open_Brace: + case .Open_Brace: if !lhs { return parse_literal_value(p, nil); } - case token.Open_Paren: - open := expect_token(p, token.Open_Paren); + case .Open_Paren: + open := expect_token(p, .Open_Paren); p.expr_level += 1; expr := parse_expr(p, false); p.expr_level -= 1; - close := expect_token(p, token.Close_Paren); + close := expect_token(p, .Close_Paren); pe := ast.new(ast.Paren_Expr, open.pos, end_pos(close)); pe.open = open.pos; @@ -1877,7 +1877,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { pe.close = close.pos; return pe; - case token.Distinct: + case .Distinct: tok := advance_token(p); type := parse_type(p); dt := ast.new(ast.Distinct_Type, tok.pos, type.end); @@ -1885,16 +1885,16 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { dt.type = type; return dt; - case token.Opaque: + case .Opaque: tok := advance_token(p); type := parse_type(p); ot := ast.new(ast.Opaque_Type, tok.pos, type.end); ot.tok = tok.kind; ot.type = type; return ot; - case token.Hash: - tok := expect_token(p, token.Hash); - name := expect_token(p, token.Ident); + case .Hash: + tok := expect_token(p, .Hash); + name := expect_token(p, .Ident); switch name.text { case "type": type := parse_type(p); @@ -1922,15 +1922,15 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { return te; } - case token.Inline, token.No_Inline: + case .Inline, .No_Inline: tok := advance_token(p); expr := parse_unary_expr(p, lhs); pi := ast.Proc_Inlining.None; switch tok.kind { - case token.Inline: + case .Inline: pi = ast.Proc_Inlining.Inline; - case token.No_Inline: + case .No_Inline: pi = ast.Proc_Inlining.No_Inline; } @@ -1951,25 +1951,25 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { } return expr; - case token.Proc: - tok := expect_token(p, token.Proc); + case .Proc: + tok := expect_token(p, .Proc); - if p.curr_tok.kind == token.Open_Brace { - open := expect_token(p, token.Open_Brace); + if p.curr_tok.kind == .Open_Brace { + open := expect_token(p, .Open_Brace); args: [dynamic]^ast.Expr; - for p.curr_tok.kind != token.Close_Brace && - p.curr_tok.kind != token.EOF { + for p.curr_tok.kind != .Close_Brace && + p.curr_tok.kind != .EOF { elem := parse_expr(p, false); append(&args, elem); - if !allow_token(p, token.Comma) { + if !allow_token(p, .Comma) { break; } } - close := expect_token(p, token.Close_Brace); + close := expect_token(p, .Close_Brace); if len(args) == 0 { error(p, tok.pos, "expected at least 1 argument in procedure group"); @@ -1985,10 +1985,10 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { type := parse_proc_type(p, tok); - where_token: token.Token; + where_token: tokenizer.Token; where_clauses: []^ast.Expr; - if (p.curr_tok.kind == token.Where) { - where_token = expect_token(p, token.Where); + if (p.curr_tok.kind == .Where) { + where_token = expect_token(p, .Where); prev_level := p.expr_level; p.expr_level = -1; where_clauses = parse_rhs_expr_list(p); @@ -1996,24 +1996,24 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { } if p.allow_type && p.expr_level < 0 { - if where_token.kind != token.Invalid { + if where_token.kind != .Invalid { error(p, where_token.pos, "'where' clauses are not allowed on procedure types"); } return type; } body: ^ast.Stmt; - if allow_token(p, token.Undef) { + if allow_token(p, .Undef) { // Okay - if where_token.kind != token.Invalid { + if where_token.kind != .Invalid { error(p, where_token.pos, "'where' clauses are not allowed on procedure literals without a defined body (replaced with ---"); } - } else if p.curr_tok.kind == token.Open_Brace { + } else if p.curr_tok.kind == .Open_Brace { prev_proc := p.curr_proc; p.curr_proc = type; body = parse_body(p); p.curr_proc = prev_proc; - } else if allow_token(p, token.Do) { + } else if allow_token(p, .Do) { prev_proc := p.curr_proc; p.curr_proc = type; body = convert_stmt_to_body(p, parse_stmt(p)); @@ -2029,13 +2029,13 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { pl.where_clauses = where_clauses; return pl; - case token.Dollar: + case .Dollar: tok := advance_token(p); type := parse_ident(p); end := type.end; specialization: ^ast.Expr; - if allow_token(p, token.Quo) { + if allow_token(p, .Quo) { specialization = parse_type(p); end = specialization.pos; } @@ -2049,19 +2049,19 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { pt.specialization = specialization; return pt; - case token.Typeid: + case .Typeid: tok := advance_token(p); ti := ast.new(ast.Typeid_Type, tok.pos, end_pos(tok)); ti.tok = tok.kind; ti.specialization = nil; return ti; - case token.Type_Of: + case .Type_Of: tok := advance_token(p); i := ast.new(ast.Implicit, tok.pos, end_pos(tok)); i.tok = tok; type: ^ast.Expr = parse_call_expr(p, i); - for p.curr_tok.kind == token.Period { + for p.curr_tok.kind == .Period { period := advance_token(p); field := parse_ident(p); @@ -2075,24 +2075,24 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { return type; - case token.Pointer: - tok := expect_token(p, token.Pointer); + case .Pointer: + tok := expect_token(p, .Pointer); elem := parse_type(p); ptr := ast.new(ast.Pointer_Type, tok.pos, elem.end); ptr.elem = elem; return ptr; - case token.Open_Bracket: - open := expect_token(p, token.Open_Bracket); + case .Open_Bracket: + open := expect_token(p, .Open_Bracket); count: ^ast.Expr; - if p.curr_tok.kind == token.Question { - tok := expect_token(p, token.Question); + if p.curr_tok.kind == .Question { + tok := expect_token(p, .Question); q := ast.new(ast.Unary_Expr, tok.pos, end_pos(tok)); q.op = tok; count = q; - } else if p.curr_tok.kind == token.Dynamic { - tok := expect_token(p, token.Dynamic); - close := expect_token(p, token.Close_Bracket); + } else if p.curr_tok.kind == .Dynamic { + tok := expect_token(p, .Dynamic); + close := expect_token(p, .Close_Bracket); elem := parse_type(p); da := ast.new(ast.Dynamic_Array_Type, open.pos, elem.end); da.open = open.pos; @@ -2101,12 +2101,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { da.elem = elem; return da; - } else if p.curr_tok.kind != token.Close_Bracket { + } else if p.curr_tok.kind != .Close_Bracket { p.expr_level += 1; count = parse_expr(p, false); p.expr_level -= 1; } - close := expect_token(p, token.Close_Bracket); + close := expect_token(p, .Close_Bracket); elem := parse_type(p); at := ast.new(ast.Array_Type, open.pos, elem.end); at.open = open.pos; @@ -2115,11 +2115,11 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { at.elem = elem; return at; - case token.Map: - tok := expect_token(p, token.Map); - expect_token(p, token.Open_Bracket); + case .Map: + tok := expect_token(p, .Map); + expect_token(p, .Open_Bracket); key := parse_type(p); - expect_token(p, token.Close_Bracket); + expect_token(p, .Close_Bracket); value := parse_type(p); mt := ast.new(ast.Map_Type, tok.pos, value.end); @@ -2128,8 +2128,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { mt.value = value; return mt; - case token.Struct: - tok := expect_token(p, token.Struct); + case .Struct: + tok := expect_token(p, .Struct); poly_params: ^ast.Field_List; align: ^ast.Expr; @@ -2138,21 +2138,21 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { fields: ^ast.Field_List; name_count: int; - if allow_token(p, token.Open_Paren) { + if allow_token(p, .Open_Paren) { param_count: int; - poly_params, param_count = parse_field_list(p, token.Close_Paren, ast.Field_Flags_Record_Poly_Params); + poly_params, param_count = parse_field_list(p, .Close_Paren, ast.Field_Flags_Record_Poly_Params); if param_count == 0 { error(p, poly_params.pos, "expected at least 1 polymorphic parameter"); poly_params = nil; } - expect_token_after(p, token.Close_Paren, "parameter list"); + expect_token_after(p, .Close_Paren, "parameter list"); check_poly_params_for_type(p, poly_params, tok); } prev_level := p.expr_level; p.expr_level = -1; - for allow_token(p, token.Hash) { - tag := expect_token_after(p, token.Ident, "#"); + for allow_token(p, .Hash) { + tag := expect_token_after(p, .Ident, "#"); switch tag.text { case "packed": if is_packed do error(p, tag.pos, "duplicate struct tag '#%s'", tag.text); @@ -2174,19 +2174,19 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { error(p, tok.pos, "'#raw_union' cannot also be '#packed"); } - where_token: token.Token; + where_token: tokenizer.Token; where_clauses: []^ast.Expr; - if (p.curr_tok.kind == token.Where) { - where_token = expect_token(p, token.Where); + if (p.curr_tok.kind == .Where) { + where_token = expect_token(p, .Where); prev_level := p.expr_level; p.expr_level = -1; where_clauses = parse_rhs_expr_list(p); p.expr_level = prev_level; } - expect_token(p, token.Open_Brace); - fields, name_count = parse_field_list(p, token.Close_Brace, ast.Field_Flags_Struct); - close := expect_token(p, token.Close_Brace); + expect_token(p, .Open_Brace); + fields, name_count = parse_field_list(p, .Close_Brace, ast.Field_Flags_Struct); + close := expect_token(p, .Close_Brace); st := ast.new(ast.Struct_Type, tok.pos, end_pos(close)); st.poly_params = poly_params; @@ -2199,26 +2199,26 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { st.where_clauses = where_clauses; return st; - case token.Union: - tok := expect_token(p, token.Union); + case .Union: + tok := expect_token(p, .Union); poly_params: ^ast.Field_List; align: ^ast.Expr; - if allow_token(p, token.Open_Paren) { + if allow_token(p, .Open_Paren) { param_count: int; - poly_params, param_count = parse_field_list(p, token.Close_Paren, ast.Field_Flags_Record_Poly_Params); + poly_params, param_count = parse_field_list(p, .Close_Paren, ast.Field_Flags_Record_Poly_Params); if param_count == 0 { error(p, poly_params.pos, "expected at least 1 polymorphic parameter"); poly_params = nil; } - expect_token_after(p, token.Close_Paren, "parameter list"); + expect_token_after(p, .Close_Paren, "parameter list"); check_poly_params_for_type(p, poly_params, tok); } prev_level := p.expr_level; p.expr_level = -1; - for allow_token(p, token.Hash) { - tag := expect_token_after(p, token.Ident, "#"); + for allow_token(p, .Hash) { + tag := expect_token_after(p, .Ident, "#"); switch tag.text { case "align": if align != nil do error(p, tag.pos, "duplicate union tag '#%s'", tag.text); @@ -2229,10 +2229,10 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { } p.expr_level = prev_level; - where_token: token.Token; + where_token: tokenizer.Token; where_clauses: []^ast.Expr; - if (p.curr_tok.kind == token.Where) { - where_token = expect_token(p, token.Where); + if (p.curr_tok.kind == .Where) { + where_token = expect_token(p, .Where); prev_level := p.expr_level; p.expr_level = -1; where_clauses = parse_rhs_expr_list(p); @@ -2241,19 +2241,19 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { variants: [dynamic]^ast.Expr; - expect_token_after(p, token.Open_Brace, "union"); + expect_token_after(p, .Open_Brace, "union"); - for p.curr_tok.kind != token.Close_Brace && p.curr_tok.kind != token.EOF { + for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF { type := parse_type(p); if _, ok := type.derived.(ast.Bad_Expr); !ok { append(&variants, type); } - if !allow_token(p, token.Comma) { + if !allow_token(p, .Comma) { break; } } - close := expect_token(p, token.Close_Brace); + close := expect_token(p, .Close_Brace); ut := ast.new(ast.Union_Type, tok.pos, end_pos(close)); ut.poly_params = poly_params; @@ -2264,15 +2264,15 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { return ut; - case token.Enum: - tok := expect_token(p, token.Enum); + case .Enum: + tok := expect_token(p, .Enum); base_type: ^ast.Expr; - if p.curr_tok.kind != token.Open_Brace { + if p.curr_tok.kind != .Open_Brace { base_type = parse_type(p); } - open := expect_token(p, token.Open_Brace); + open := expect_token(p, .Open_Brace); fields := parse_elem_list(p); - close := expect_token(p, token.Close_Brace); + close := expect_token(p, .Close_Brace); et := ast.new(ast.Enum_Type, tok.pos, end_pos(close)); et.base_type = base_type; @@ -2281,8 +2281,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { et.close = close.pos; return et; - case token.Bit_Field: - tok := expect_token(p, token.Bit_Field); + case .Bit_Field: + tok := expect_token(p, .Bit_Field); fields: [dynamic]^ast.Field_Value; align: ^ast.Expr; @@ -2290,8 +2290,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { prev_level := p.expr_level; p.expr_level = -1; - for allow_token(p, token.Hash) { - tag := expect_token_after(p, token.Ident, "#"); + for allow_token(p, .Hash) { + tag := expect_token_after(p, .Ident, "#"); switch tag.text { case "align": if align != nil { @@ -2305,11 +2305,11 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { p.expr_level = prev_level; - open := expect_token_after(p, token.Open_Brace, "bit_field"); + open := expect_token_after(p, .Open_Brace, "bit_field"); - for p.curr_tok.kind != token.Close_Brace && p.curr_tok.kind != token.EOF { + for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF { name := parse_ident(p); - colon := expect_token(p, token.Colon); + colon := expect_token(p, .Colon); value := parse_expr(p, true); fv := ast.new(ast.Field_Value, name.pos, value.end); @@ -2318,12 +2318,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { fv.value = value; append(&fields, fv); - if !allow_token(p, token.Comma) { + if !allow_token(p, .Comma) { break; } } - close := expect_token(p, token.Close_Brace); + close := expect_token(p, .Close_Brace); bft := ast.new(ast.Bit_Field_Type, tok.pos, end_pos(close)); bft.tok_pos = tok.pos; @@ -2334,9 +2334,9 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { return bft; - case token.Bit_Set: - tok := expect_token(p, token.Bit_Set); - open := expect_token(p, token.Open_Bracket); + case .Bit_Set: + tok := expect_token(p, .Bit_Set); + open := expect_token(p, .Open_Bracket); elem, underlying: ^ast.Expr; prev_allow_range := p.allow_range; @@ -2344,12 +2344,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { elem = parse_expr(p, false); p.allow_range = prev_allow_range; - if allow_token(p, token.Semicolon) { + if allow_token(p, .Semicolon) { underlying = parse_type(p); } - close := expect_token(p, token.Close_Bracket); + close := expect_token(p, .Close_Bracket); bst := ast.new(ast.Bit_Set_Type, tok.pos, end_pos(close)); bst.tok_pos = tok.pos; @@ -2388,7 +2388,7 @@ is_literal_type :: proc(expr: ^ast.Expr) -> bool { } parse_value :: proc(p: ^Parser) -> ^ast.Expr { - if p.curr_tok.kind == token.Open_Brace { + if p.curr_tok.kind == .Open_Brace { return parse_literal_value(p, nil); } return parse_expr(p, false); @@ -2397,10 +2397,10 @@ parse_value :: proc(p: ^Parser) -> ^ast.Expr { parse_elem_list :: proc(p: ^Parser) -> []^ast.Expr { elems: [dynamic]^ast.Expr; - for p.curr_tok.kind != token.Close_Brace && p.curr_tok.kind != token.EOF { + for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF { elem := parse_value(p); - if p.curr_tok.kind == token.Eq { - eq := expect_token(p, token.Eq); + if p.curr_tok.kind == .Eq { + eq := expect_token(p, .Eq); value := parse_value(p); fv := ast.new(ast.Field_Value, elem.pos, value.end); @@ -2413,7 +2413,7 @@ parse_elem_list :: proc(p: ^Parser) -> []^ast.Expr { append(&elems, elem); - if !allow_token(p, token.Comma) { + if !allow_token(p, .Comma) { break; } } @@ -2423,14 +2423,14 @@ parse_elem_list :: proc(p: ^Parser) -> []^ast.Expr { parse_literal_value :: proc(p: ^Parser, type: ^ast.Expr) -> ^ast.Comp_Lit { elems: []^ast.Expr; - open := expect_token(p, token.Open_Brace); + open := expect_token(p, .Open_Brace); p.expr_level += 1; - if p.curr_tok.kind != token.Close_Brace { + if p.curr_tok.kind != .Close_Brace { elems = parse_elem_list(p); } p.expr_level -= 1; - close := expect_token_after(p, token.Close_Brace, "compound literal"); + close := expect_token_after(p, .Close_Brace, "compound literal"); pos := type != nil ? type.pos : open.pos; lit := ast.new(ast.Comp_Lit, pos, end_pos(close)); @@ -2444,30 +2444,30 @@ parse_literal_value :: proc(p: ^Parser, type: ^ast.Expr) -> ^ast.Comp_Lit { parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Call_Expr { args: [dynamic]^ast.Expr; - ellipsis: token.Token; + ellipsis: tokenizer.Token; p.expr_level += 1; - open := expect_token(p, token.Open_Paren); + open := expect_token(p, .Open_Paren); - for p.curr_tok.kind != token.Close_Paren && - p.curr_tok.kind != token.EOF && + for p.curr_tok.kind != .Close_Paren && + p.curr_tok.kind != .EOF && ellipsis.pos.line == 0 { - if p.curr_tok.kind == token.Comma { + if p.curr_tok.kind == .Comma { error(p, p.curr_tok.pos, "expected an expression not ,"); - } else if p.curr_tok.kind == token.Eq { + } else if p.curr_tok.kind == .Eq { error(p, p.curr_tok.pos, "expected an expression not ="); } prefix_ellipsis := false; - if p.curr_tok.kind == token.Ellipsis { + if p.curr_tok.kind == .Ellipsis { prefix_ellipsis = true; - ellipsis = expect_token(p, token.Ellipsis); + ellipsis = expect_token(p, .Ellipsis); } arg := parse_expr(p, false); - if p.curr_tok.kind == token.Eq { - eq := expect_token(p, token.Eq); + if p.curr_tok.kind == .Eq { + eq := expect_token(p, .Eq); if prefix_ellipsis { error(p, ellipsis.pos, "'..' must be applied to value rather than a field name"); @@ -2484,12 +2484,12 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Call_Expr { append(&args, arg); - if !allow_token(p, token.Comma) { + if !allow_token(p, .Comma) { break; } } - close := expect_token_after(p, token.Close_Paren, "argument list"); + close := expect_token_after(p, .Close_Paren, "argument list"); p.expr_level -= 1; ce := ast.new(ast.Call_Expr, operand.pos, end_pos(close)); @@ -2520,23 +2520,23 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a case: loop = false; - case token.Open_Paren: + case .Open_Paren: operand = parse_call_expr(p, operand); - case token.Open_Bracket: + case .Open_Bracket: prev_allow_range := p.allow_range; defer p.allow_range = prev_allow_range; p.allow_range = false; indicies: [2]^ast.Expr; - interval: token.Token; + interval: tokenizer.Token; is_slice_op := false; p.expr_level += 1; - open := expect_token(p, token.Open_Bracket); + open := expect_token(p, .Open_Bracket); switch p.curr_tok.kind { - case token.Colon, token.Ellipsis, token.Range_Half: + case .Colon, .Ellipsis, .Range_Half: // NOTE(bill): Do not err yet break; case: @@ -2544,18 +2544,18 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a } switch p.curr_tok.kind { - case token.Ellipsis, token.Range_Half: + case .Ellipsis, .Range_Half: error(p, p.curr_tok.pos, "expected a colon, not a range"); fallthrough; - case token.Colon: + case .Colon: interval = advance_token(p); is_slice_op = true; - if (p.curr_tok.kind != token.Close_Bracket && p.curr_tok.kind != token.EOF) { + if (p.curr_tok.kind != .Close_Bracket && p.curr_tok.kind != .EOF) { indicies[1] = parse_expr(p, false); } } - close := expect_token(p, token.Close_Bracket); + close := expect_token(p, .Close_Bracket); p.expr_level -= 1; if is_slice_op { @@ -2579,10 +2579,10 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a } - case token.Period: - tok := expect_token(p, token.Period); + case .Period: + tok := expect_token(p, .Period); switch p.curr_tok.kind { - case token.Ident: + case .Ident: field := parse_ident(p); sel := ast.new(ast.Selector_Expr, operand.pos, field.end); @@ -2591,10 +2591,10 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a operand = sel; - case token.Open_Paren: - open := expect_token(p, token.Open_Paren); + case .Open_Paren: + open := expect_token(p, .Open_Paren); type := parse_type(p); - close := expect_token(p, token.Close_Paren); + close := expect_token(p, .Close_Paren); ta := ast.new(ast.Type_Assertion, operand.pos, end_pos(close)); ta.expr = operand; @@ -2610,15 +2610,15 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a operand = ast.new(ast.Bad_Expr, operand.pos, end_pos(tok)); } - case token.Pointer: - op := expect_token(p, token.Pointer); + case .Pointer: + op := expect_token(p, .Pointer); deref := ast.new(ast.Deref_Expr, operand.pos, end_pos(op)); deref.expr = operand; deref.op = op; operand = deref; - case token.Open_Brace: + case .Open_Brace: if !is_lhs && is_literal_type(operand) && p.expr_level >= 0 { operand = parse_literal_value(p, operand); } else { @@ -2639,11 +2639,11 @@ parse_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { } parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { switch p.curr_tok.kind { - case token.Transmute, token.Cast: + case .Transmute, .Cast: tok := advance_token(p); - open := expect_token(p, token.Open_Paren); + open := expect_token(p, .Open_Paren); type := parse_type(p); - close := expect_token(p, token.Close_Paren); + close := expect_token(p, .Close_Paren); expr := parse_unary_expr(p, lhs); tc := ast.new(ast.Type_Cast, tok.pos, expr.end); @@ -2654,7 +2654,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { tc.expr = expr; return tc; - case token.Auto_Cast: + case .Auto_Cast: op := advance_token(p); expr := parse_unary_expr(p, lhs); @@ -2663,9 +2663,9 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { ac.expr = expr; return ac; - case token.Add, token.Sub, - token.Not, token.Xor, - token.And: + case .Add, .Sub, + .Not, .Xor, + .And: op := advance_token(p); expr := parse_unary_expr(p, lhs); @@ -2674,7 +2674,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { ue.expr = expr; return ue; - case token.Period: + case .Period: op := advance_token(p); field := parse_ident(p); ise := ast.new(ast.Implicit_Selector_Expr, op.pos, field.end); @@ -2695,10 +2695,10 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr { } expect_operator(p); - if op.kind == token.Question { + if op.kind == .Question { cond := expr; x := parse_expr(p, lhs); - colon := expect_token(p, token.Colon); + colon := expect_token(p, .Colon); y := parse_expr(p, lhs); te := ast.new(ast.Ternary_Expr, expr.pos, end_pos(p.prev_tok)); te.cond = cond; @@ -2732,7 +2732,7 @@ parse_expr_list :: proc(p: ^Parser, lhs: bool) -> ([]^ast.Expr) { for { expr := parse_expr(p, lhs); append(&list, expr); - if p.curr_tok.kind != token.Comma || p.curr_tok.kind == token.EOF { + if p.curr_tok.kind != .Comma || p.curr_tok.kind == .EOF { break; } advance_token(p); @@ -2754,7 +2754,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt { lhs := parse_lhs_expr_list(p); op := p.curr_tok; switch { - case token.is_assignment_operator(op.kind): + case tokenizer.is_assignment_operator(op.kind): // if p.curr_proc == nil { // error(p, p.curr_tok.pos, "simple statements are not allowed at the file scope"); // return ast.new(ast.Bad_Stmt, start_tok.pos, end_pos(p.curr_tok)); @@ -2771,9 +2771,9 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt { stmt.rhs = rhs; return stmt; - case op.kind == token.In: + case op.kind == .In: if .In in flags { - allow_token(p, token.In); + allow_token(p, .In); prev_allow_range := p.allow_range; p.allow_range = true; expr := parse_expr(p, false); @@ -2788,11 +2788,11 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt { stmt.rhs = rhs; return stmt; } - case op.kind == token.Colon: - expect_token_after(p, token.Colon, "identifier list"); + case op.kind == .Colon: + expect_token_after(p, .Colon, "identifier list"); if .Label in flags && len(lhs) == 1 { switch p.curr_tok.kind { - case token.Open_Brace, token.If, token.For, token.Switch: + case .Open_Brace, .If, .For, .Switch: label := lhs[0]; stmt := parse_stmt(p); @@ -2827,9 +2827,9 @@ parse_value_decl :: proc(p: ^Parser, names: []^ast.Expr, docs: ^ast.Comment_Grou type := parse_type_or_ident(p); switch p.curr_tok.kind { - case token.Eq, token.Colon: + case .Eq, .Colon: sep := advance_token(p); - is_mutable = sep.kind != token.Colon; + is_mutable = sep.kind != .Colon; values = parse_rhs_expr_list(p); if len(values) > len(names) { @@ -2858,7 +2858,7 @@ parse_value_decl :: proc(p: ^Parser, names: []^ast.Expr, docs: ^ast.Comment_Grou if !is_mutable && len(values) > 0 { end = values[len(values)-1]; } - if p.curr_tok.kind == token.Close_Brace && + if p.curr_tok.kind == .Close_Brace && p.curr_tok.pos.line == p.prev_tok.pos.line { } else { @@ -2884,13 +2884,13 @@ parse_value_decl :: proc(p: ^Parser, names: []^ast.Expr, docs: ^ast.Comment_Grou parse_import_decl :: proc(p: ^Parser, kind := Import_Decl_Kind.Standard) -> ^ast.Import_Decl { docs := p.lead_comment; - tok := expect_token(p, token.Import); + tok := expect_token(p, .Import); - import_name: token.Token; + import_name: tokenizer.Token; is_using := kind != Import_Decl_Kind.Standard; switch p.curr_tok.kind { - case token.Ident: + case .Ident: import_name = advance_token(p); case: import_name.pos = p.curr_tok.pos; @@ -2900,7 +2900,7 @@ parse_import_decl :: proc(p: ^Parser, kind := Import_Decl_Kind.Standard) -> ^ast error(p, import_name.pos, "illegal import name: '_'"); } - path := expect_token_after(p, token.String, "import"); + path := expect_token_after(p, .String, "import"); decl := ast.new(ast.Import_Decl, tok.pos, end_pos(path)); decl.docs = docs; diff --git a/core/odin/token/token.odin b/core/odin/token/token.odin deleted file mode 100644 index 737ff3586..000000000 --- a/core/odin/token/token.odin +++ /dev/null @@ -1,333 +0,0 @@ -package odin_token - -import "core:strings" - -Token :: struct { - kind: Kind, - text: string, - pos: Pos, -} - -Pos :: struct { - file: string, - offset: int, // starting at 0 - line: int, // starting at 1 - column: int, // starting at 1 -} - -pos_compare :: proc(lhs, rhs: Pos) -> int { - if lhs.offset != rhs.offset { - return (lhs.offset < rhs.offset) ? -1 : +1; - } - if lhs.line != rhs.line { - return (lhs.line < rhs.line) ? -1 : +1; - } - if lhs.column != rhs.column { - return (lhs.column < rhs.column) ? -1 : +1; - } - return strings.compare(lhs.file, rhs.file); -} - -using Kind :: enum u32 { - Invalid, - EOF, - Comment, - - B_Literal_Begin, - Ident, - Integer, - Float, - Imag, - Rune, - String, - B_Literal_End, - - B_Operator_Begin, - Eq, - Not, - Hash, - At, - Dollar, - Pointer, - Question, - Add, - Sub, - Mul, - Quo, - Mod, - Mod_Mod, - And, - Or, - Xor, - And_Not, - Shl, - Shr, - - Cmp_And, - Cmp_Or, - - B_Assign_Op_Begin, - Add_Eq, - Sub_Eq, - Mul_Eq, - Quo_Eq, - Mod_Eq, - Mod_Mod_Eq, - And_Eq, - Or_Eq, - Xor_Eq, - And_Not_Eq, - Shl_Eq, - Shr_Eq, - Cmp_And_Eq, - Cmp_Or_Eq, - B_Assign_Op_End, - - Arrow_Right, - Arrow_Left, - Double_Arrow_Right, - Undef, - - B_Comparison_Begin, - Cmp_Eq, - Not_Eq, - Lt, - Gt, - Lt_Eq, - Gt_Eq, - B_Comparison_End, - - Open_Paren, - Close_Paren, - Open_Bracket, - Close_Bracket, - Open_Brace, - Close_Brace, - Colon, - Semicolon, - Period, - Comma, - Ellipsis, - Range_Half, - Back_Slash, - B_Operator_End, - - B_Keyword_Begin, - Import, - Foreign, - Package, - Typeid, - When, - Where, - If, - Else, - For, - Switch, - In, - Notin, - Do, - Case, - Break, - Continue, - Fallthrough, - Defer, - Return, - Proc, - Macro, - Struct, - Union, - Enum, - Bit_Field, - Bit_Set, - Map, - Dynamic, - Auto_Cast, - Cast, - Transmute, - Distinct, - Opaque, - Using, - Inline, - No_Inline, - Context, - Size_Of, - Align_Of, - Offset_Of, - Type_Of, - Const, - B_Keyword_End, - - COUNT, - - B_Custom_Keyword_Begin = COUNT+1, - // ... Custom keywords -}; - -tokens := [Kind.COUNT]string { - "Invalid", - "EOF", - "Comment", - - "", - "identifier", - "integer", - "float", - "imaginary", - "rune", - "string", - "", - - "", - "=", - "!", - "#", - "@", - "$", - "^", - "?", - "+", - "-", - "*", - "/", - "%", - "%%", - "&", - "|", - "~", - "&~", - "<<", - ">>", - - "&&", - "||", - - "", - "+=", - "-=", - "*=", - "/=", - "%=", - "%%=", - "&=", - "|=", - "~=", - "&~=", - "<<=", - ">>=", - "&&=", - "||=", - "", - - "->", - "<-", - "=>", - "---", - - "", - "==", - "!=", - "<", - ">", - "<=", - ">=", - "", - - "(", - ")", - "[", - "]", - "{", - "}", - ":", - ";", - ".", - ",", - "..", - "..<", - "\\", - "", - - "", - "import", - "foreign", - "package", - "typeid", - "when", - "where", - "if", - "else", - "for", - "switch", - "in", - "notin", - "do", - "case", - "break", - "continue", - "fallthrough", - "defer", - "return", - "proc", - "macro", - "struct", - "union", - "enum", - "bit_field", - "bit_set", - "map", - "dynamic", - "auto_cast", - "cast", - "transmute", - "distinct", - "opaque", - "using", - "inline", - "no_inline", - "context", - "size_of", - "align_of", - "offset_of", - "type_of", - "const", - "", -}; - -custom_keyword_tokens: []string; - -to_string :: proc(kind: Kind) -> string { - if Invalid <= kind && kind < COUNT { - return tokens[kind]; - } - if B_Custom_Keyword_Begin < kind { - n := int(u16(kind)-u16(B_Custom_Keyword_Begin)); - if n < len(custom_keyword_tokens) { - return custom_keyword_tokens[n]; - } - } - - return "Invalid"; -} - -is_literal :: proc(kind: Kind) -> bool { return B_Literal_Begin < kind && kind < B_Literal_End; } -is_operator :: proc(kind: Kind) -> bool { - switch kind { - case B_Operator_Begin..B_Operator_End: - return true; - case In, Notin: - return true; - } - return false; -} -is_assignment_operator :: proc(kind: Kind) -> bool { - return B_Assign_Op_Begin < kind && kind < B_Assign_Op_End || kind == Eq; -} -is_keyword :: proc(kind: Kind) -> bool { - switch { - case B_Keyword_Begin < kind && kind < B_Keyword_End: - return true; - case B_Custom_Keyword_Begin < kind: - return true; - } - return false; -} diff --git a/core/odin/tokenizer/tokenizer.odin b/core/odin/tokenizer/tokenizer.odin index 98aef62b0..26aab7c1c 100644 --- a/core/odin/tokenizer/tokenizer.odin +++ b/core/odin/tokenizer/tokenizer.odin @@ -1,10 +1,9 @@ package odin_tokenizer import "core:fmt" -import "core:odin/token" import "core:unicode/utf8" -Error_Handler :: #type proc(pos: token.Pos, fmt: string, args: ..any); +Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any); Tokenizer :: struct { // Immutable data @@ -41,11 +40,11 @@ init :: proc(t: ^Tokenizer, src: []byte, path: string, err: Error_Handler = defa } @(private) -offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos { +offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> Pos { line := t.line_count; column := offset - t.line_offset + 1; - return token.Pos { + return Pos { file = t.path, offset = offset, line = line, @@ -53,7 +52,7 @@ offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> token.Pos { }; } -default_error_handler :: proc(pos: token.Pos, msg: string, args: ..any) { +default_error_handler :: proc(pos: Pos, msg: string, args: ..any) { fmt.eprintf("%s(%d:%d) ", pos.file, pos.line, pos.column); fmt.eprintf(msg, ..args); fmt.eprintf("\n"); @@ -322,15 +321,15 @@ scan_rune :: proc(t: ^Tokenizer) -> string { return string(t.src[offset : t.offset]); } -scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, string) { +scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Token_Kind, string) { scan_mantissa :: proc(t: ^Tokenizer, base: int) { for digit_val(t.ch) < base || t.ch == '_' { advance_rune(t); } } - scan_exponent :: proc(t: ^Tokenizer, kind: ^token.Kind) { + scan_exponent :: proc(t: ^Tokenizer, kind: ^Token_Kind) { if t.ch == 'e' || t.ch == 'E' { - kind^ = token.Float; + kind^ = .Float; advance_rune(t); if t.ch == '-' || t.ch == '+' { advance_rune(t); @@ -345,16 +344,16 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str // NOTE(bill): This needs to be here for sanity's sake switch t.ch { case 'i', 'j', 'k': - kind^ = token.Imag; + kind^ = .Imag; advance_rune(t); } } - scan_fraction :: proc(t: ^Tokenizer, kind: ^token.Kind) -> (early_exit: bool) { + scan_fraction :: proc(t: ^Tokenizer, kind: ^Token_Kind) -> (early_exit: bool) { if t.ch == '.' && peek_byte(t) == '.' { return true; } if t.ch == '.' { - kind^ = token.Float; + kind^ = .Float; advance_rune(t); scan_mantissa(t, 10); } @@ -363,22 +362,22 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str offset := t.offset; - kind := token.Integer; + kind := Token_Kind.Integer; seen_point := seen_decimal_point; if seen_point { offset -= 1; - kind = token.Float; + kind = .Float; scan_mantissa(t, 10); scan_exponent(t, &kind); } else { if t.ch == '0' { - int_base :: inline proc(t: ^Tokenizer, kind: ^token.Kind, base: int, msg: string) { + int_base :: inline proc(t: ^Tokenizer, kind: ^Token_Kind, base: int, msg: string) { prev := t.offset; advance_rune(t); scan_mantissa(t, base); if t.offset - prev <= 1 { - kind^ = token.Invalid; + kind^ = .Invalid; error(t, t.offset, msg); } } @@ -395,7 +394,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str advance_rune(t); scan_mantissa(t, 16); if t.offset - prev <= 1 { - kind = token.Invalid; + kind = .Invalid; error(t, t.offset, "illegal hexadecimal floating-point number"); } else { sub := t.src[prev+1 : t.offset]; @@ -440,15 +439,15 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (token.Kind, str } -scan :: proc(t: ^Tokenizer) -> token.Token { - switch2 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind) -> token.Kind { +scan :: proc(t: ^Tokenizer) -> Token { + switch2 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind) -> Token_Kind { if t.ch == '=' { advance_rune(t); return tok1; } return tok0; } - switch3 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind, ch2: rune, tok2: token.Kind) -> token.Kind { + switch3 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2: Token_Kind) -> Token_Kind { if t.ch == '=' { advance_rune(t); return tok1; @@ -459,7 +458,7 @@ scan :: proc(t: ^Tokenizer) -> token.Token { } return tok0; } - switch4 :: proc(t: ^Tokenizer, tok0, tok1: token.Kind, ch2: rune, tok2, tok3: token.Kind) -> token.Kind { + switch4 :: proc(t: ^Tokenizer, tok0, tok1: Token_Kind, ch2: rune, tok2, tok3: Token_Kind) -> Token_Kind { if t.ch == '=' { advance_rune(t); return tok1; @@ -480,25 +479,25 @@ scan :: proc(t: ^Tokenizer) -> token.Token { offset := t.offset; - kind: token.Kind; + kind: Token_Kind; lit: string; pos := offset_to_pos(t, offset); switch ch := t.ch; true { case is_letter(ch): lit = scan_identifier(t); - kind = token.Ident; + kind = .Ident; check_keyword: if len(lit) > 1 { // TODO(bill): Maybe have a hash table lookup rather than this linear search - for i in token.B_Keyword_Begin .. token.B_Keyword_End { - if lit == token.tokens[i] { - kind = token.Kind(i); + for i in Token_Kind.B_Keyword_Begin .. Token_Kind.B_Keyword_End { + if lit == tokens[i] { + kind = Token_Kind(i); break check_keyword; } } - for keyword, i in token.custom_keyword_tokens { + for keyword, i in custom_keyword_tokens { if lit == keyword { - kind = token.Kind(i+1)+token.B_Custom_Keyword_Begin; + kind = Token_Kind(i+1) + .B_Custom_Keyword_Begin; break check_keyword; } } @@ -509,115 +508,115 @@ scan :: proc(t: ^Tokenizer) -> token.Token { advance_rune(t); switch ch { case -1: - kind = token.EOF; + kind = .EOF; case '"': - kind = token.String; + kind = .String; lit = scan_string(t); case '\'': - kind = token.Rune; + kind = .Rune; lit = scan_rune(t); case '`': - kind = token.String; + kind = .String; lit = scan_raw_string(t); case '=': if t.ch == '>' { advance_rune(t); - kind = token.Double_Arrow_Right; + kind = .Double_Arrow_Right; } else { - kind = switch2(t, token.Eq, token.Cmp_Eq); + kind = switch2(t, .Eq, .Cmp_Eq); } - case '!': kind = switch2(t, token.Not, token.Not_Eq); + case '!': kind = switch2(t, .Not, .Not_Eq); case '#': - kind = token.Hash; + kind = .Hash; if t.ch == '!' { - kind = token.Comment; + kind = .Comment; lit = scan_comment(t); } - case '?': kind = token.Question; - case '@': kind = token.At; - case '$': kind = token.Dollar; - case '^': kind = token.Pointer; - case '+': kind = switch2(t, token.Add, token.Add_Eq); + case '?': kind = .Question; + case '@': kind = .At; + case '$': kind = .Dollar; + case '^': kind = .Pointer; + case '+': kind = switch2(t, .Add, .Add_Eq); case '-': if t.ch == '>' { advance_rune(t); - kind = token.Arrow_Right; + kind = .Arrow_Right; } else if t.ch == '-' && peek_byte(t) == '-' { advance_rune(t); advance_rune(t); - kind = token.Undef; + kind = .Undef; } else { - kind = switch2(t, token.Sub, token.Sub_Eq); + kind = switch2(t, .Sub, .Sub_Eq); } - case '*': kind = switch2(t, token.Mul, token.Mul_Eq); + case '*': kind = switch2(t, .Mul, .Mul_Eq); case '/': if t.ch == '/' || t.ch == '*' { - kind = token.Comment; + kind = .Comment; lit = scan_comment(t); } else { - kind = switch2(t, token.Quo, token.Quo_Eq); + kind = switch2(t, .Quo, .Quo_Eq); } - case '%': kind = switch4(t, token.Mod, token.Mod_Eq, '%', token.Mod_Mod, token.Mod_Mod_Eq); + case '%': kind = switch4(t, .Mod, .Mod_Eq, '%', .Mod_Mod, .Mod_Mod_Eq); case '&': if t.ch == '~' { advance_rune(t); - kind = switch2(t, token.And_Not, token.And_Not_Eq); + kind = switch2(t, .And_Not, .And_Not_Eq); } else { - kind = switch3(t, token.And, token.And_Eq, '&', token.Cmp_And); + kind = switch3(t, .And, .And_Eq, '&', .Cmp_And); } - case '|': kind = switch3(t, token.Or, token.Or_Eq, '|', token.Cmp_Or); - case '~': kind = token.Xor; + case '|': kind = switch3(t, .Or, .Or_Eq, '|', .Cmp_Or); + case '~': kind = .Xor; case '<': if t.ch == '-' { advance_rune(t); - kind = token.Arrow_Left; + kind = .Arrow_Left; } else { - kind = switch4(t, token.Lt, token.Lt_Eq, '<', token.Shl, token.Shl_Eq); + kind = switch4(t, .Lt, .Lt_Eq, '<', .Shl, .Shl_Eq); } - case '>': kind = switch4(t, token.Gt, token.Gt_Eq, '>', token.Shr,token.Shr_Eq); + case '>': kind = switch4(t, .Gt, .Gt_Eq, '>', .Shr,.Shr_Eq); - case '≠': kind = token.Not_Eq; - case '≤': kind = token.Lt_Eq; - case '≥': kind = token.Gt_Eq; - case '∈': kind = token.In; - case '∉': kind = token.Notin; + case '≠': kind = .Not_Eq; + case '≤': kind = .Lt_Eq; + case '≥': kind = .Gt_Eq; + case '∈': kind = .In; + case '∉': kind = .Notin; case '.': if '0' <= t.ch && t.ch <= '9' { kind, lit = scan_number(t, true); } else { - kind = token.Period; + kind = .Period; if t.ch == '.' { advance_rune(t); - kind = token.Ellipsis; + kind = .Ellipsis; if t.ch == '<' { advance_rune(t); - kind = token.Range_Half; + kind = .Range_Half; } } } - case ':': kind = token.Colon; - case ',': kind = token.Comma; - case ';': kind = token.Semicolon; - case '(': kind = token.Open_Paren; - case ')': kind = token.Close_Paren; - case '[': kind = token.Open_Bracket; - case ']': kind = token.Close_Bracket; - case '{': kind = token.Open_Brace; - case '}': kind = token.Close_Brace; + case ':': kind = .Colon; + case ',': kind = .Comma; + case ';': kind = .Semicolon; + case '(': kind = .Open_Paren; + case ')': kind = .Close_Paren; + case '[': kind = .Open_Bracket; + case ']': kind = .Close_Bracket; + case '{': kind = .Open_Brace; + case '}': kind = .Close_Brace; - case '\\': kind = token.Back_Slash; + case '\\': kind = .Back_Slash; case: if ch != utf8.RUNE_BOM { error(t, t.offset, "illegal character '%r': %d", ch, ch); } - kind = token.Invalid; + kind = .Invalid; } } if lit == "" { lit = string(t.src[offset : t.offset]); } - return token.Token{kind, lit, pos}; + return Token{kind, lit, pos}; } diff --git a/core/runtime/core.odin b/core/runtime/core.odin index c401dbdf3..729932781 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -814,7 +814,7 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { key: Map_Key, next: int, value: V, - } + }; _, is_string := type_info_base(type_info_of(K)).variant.(Type_Info_String); header.is_key_string = is_string; diff --git a/core/strconv/generic_float.odin b/core/strconv/generic_float.odin index f0e43bcc9..59eaa20d5 100644 --- a/core/strconv/generic_float.odin +++ b/core/strconv/generic_float.odin @@ -105,7 +105,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic Buffer :: struct { b: []byte, n: int, - } + }; to_bytes :: proc(b: Buffer) -> []byte do return b.b[:b.n]; add_bytes :: proc(buf: ^Buffer, bytes: ..byte) { diff --git a/src/parser.cpp b/src/parser.cpp index 29254d7e8..e17d19787 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1344,7 +1344,8 @@ bool is_semicolon_optional_for_node(AstFile *f, Ast *s) { case Ast_UnionType: case Ast_EnumType: case Ast_BitFieldType: - return true; + // Require semicolon within a procedure body + return f->curr_proc == false; case Ast_ProcLit: return true; From 71b32ae117a2e9fcbcd290ea9d7e587b23ed7403 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 6 Oct 2019 19:20:00 +0100 Subject: [PATCH 089/143] Update demo.odin --- examples/demo/demo.odin | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 1460bf8be..a5f3500f1 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -69,7 +69,7 @@ general_stuff :: proc() { Foo :: struct { x: int, b: bool, - } + }; f := Foo{137, true}; x, b := expand_to_tuple(f); fmt.println(f); @@ -228,18 +228,18 @@ union_type :: proc() { orientation: Quaternion, derived: any, - } + }; Frog :: struct { using entity: Entity, jump_height: f32, - } + }; Monster :: struct { using entity: Entity, is_robot: bool, is_zombie: bool, - } + }; // See `parametric_polymorphism` procedure for details new_entity :: proc($T: typeid) -> ^Entity { @@ -273,18 +273,18 @@ union_type :: proc() { orientation: Quaternion, derived: union {Frog, Monster}, - } + }; Frog :: struct { using entity: ^Entity, jump_height: f32, - } + }; Monster :: struct { using entity: ^Entity, is_robot: bool, is_zombie: bool, - } + }; // See `parametric_polymorphism` procedure for details new_entity :: proc($T: typeid) -> ^Entity { @@ -402,13 +402,13 @@ parametric_polymorphism :: proc() { hash: u32, key: Key, value: Value, - } + }; TABLE_SIZE_MIN :: 32; Table :: struct(Key, Value: typeid) { count: int, allocator: mem.Allocator, slots: []Table_Slot(Key, Value), - } + }; // Only allow types that are specializations of a (polymorphic) slice make_slice :: proc($T: typeid/[]$E, len: int) -> T { @@ -532,7 +532,7 @@ parametric_polymorphism :: proc() { Foo1, Foo2, Foo3, - } + }; Para_Union :: union(T: typeid) {T, Error}; r: Para_Union(int); fmt.println(typeid_of(type_of(r))); @@ -728,19 +728,19 @@ map_type :: proc() { Enum_u8 :: enum u8 { A = 0, B = 1 << 8 - 1, - } + }; Enum_u64 :: enum u64 { A = 0, B = 1 << 64 - 1, - } + }; Enum_i8 :: enum i8 { A = 0, B = -(1 << 7), - } + }; Enum_i64 :: enum i64 { A = 0, B = -(1 << 63), - } + }; map_u8: map[Enum_u8]u8; map_u8[Enum_u8.A] = u8(Enum_u8.B); @@ -764,7 +764,7 @@ map_type :: proc() { demo_struct :: struct { member: Enum_i64, - } + }; map_string: map[string]demo_struct; map_string["Hellope!"] = demo_struct{Enum_i64.B}; @@ -846,7 +846,7 @@ complete_switch :: proc() { B, C, D, - } + }; b := Foo.B; f := Foo.A; @@ -916,7 +916,7 @@ bit_set_type :: proc() { Thursday, Friday, Saturday, - } + }; Days :: distinct bit_set[Day]; WEEKEND :: Days{Sunday, Saturday}; @@ -1003,7 +1003,7 @@ reflection :: proc() { x: int `tag1`, y: string `json:"y_field"`, z: bool, // no tag - } + }; id := typeid_of(Foo); names := reflect.struct_field_names(id); @@ -1105,7 +1105,7 @@ inline_for_statement :: proc() { B, C = 6, D, - } + }; fmt.println("Enum types"); inline for elem, idx in Foo_Enum { fmt.println(elem, idx); @@ -1180,7 +1180,7 @@ where_clauses :: proc() { N > 2 { x: [N]T, y: [N-2]T, - } + }; T :: i32; N :: 5; From 1b8c3ca22a28b8ca36175d3e20a3993cba315dae Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 8 Oct 2019 20:28:45 +0100 Subject: [PATCH 090/143] Fix typos and make demo work with -vet --- core/fmt/fmt.odin | 4 ++-- core/strings/strings.odin | 6 +++--- examples/demo/demo.odin | 1 - src/check_type.cpp | 6 ++++-- src/parser.cpp | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 6903b9bdb..e6830e734 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -69,8 +69,8 @@ eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stder @(deprecated="prefer eprint") print_err :: proc(args: ..any) -> int { return eprint(..args); } -@(deprecated="prefer eprintf") println_err :: proc(args: ..any) -> int { return eprintln(..args); } -@(deprecated="prefer eprintln") printf_err :: proc(fmt: string, args: ..any) -> int { return eprintf(fmt, ..args); } +@(deprecated="prefer eprintf") printf_err :: proc(fmt: string, args: ..any) -> int { return eprintf(fmt, ..args); } +@(deprecated="prefer eprintln") println_err :: proc(args: ..any) -> int { return eprintln(..args); } // aprint* procedures return a string that was allocated with the current context diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 0c9ffa7d3..921e4f009 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -169,9 +169,9 @@ _split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocato n = l; } - res := make([dynamic]string, n); + res := make([dynamic]string, n, allocator); for i := 0; i < n-1; i += 1 { - r, w := utf8.decode_rune_in_string(s); + _, w := utf8.decode_rune_in_string(s); res[i] = s[:w]; s = s[w:]; } @@ -185,7 +185,7 @@ _split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocato n = count(s, sep) + 1; } - res := make([dynamic]string, n); + res := make([dynamic]string, n, allocator); n -= 1; diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index a5f3500f1..ff861b1de 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -4,7 +4,6 @@ import "core:fmt" import "core:mem" import "core:os" import "core:reflect" -import "core:strings" import "intrinsics" when os.OS == "windows" { diff --git a/src/check_type.cpp b/src/check_type.cpp index 9f5ed0ed3..65e0bc880 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2016,8 +2016,10 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCal break; } } - } else if (build_context.ODIN_OS == "linux") { - + } else if (build_context.ODIN_OS == "linux" || build_context.ODIN_OS == "darwin") { + if (build_context.ODIN_ARCH == "amd64") { + + } } else { // IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for // their architectures diff --git a/src/parser.cpp b/src/parser.cpp index e17d19787..025a181ba 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1345,7 +1345,7 @@ bool is_semicolon_optional_for_node(AstFile *f, Ast *s) { case Ast_EnumType: case Ast_BitFieldType: // Require semicolon within a procedure body - return f->curr_proc == false; + return f->curr_proc == nullptr; case Ast_ProcLit: return true; From 94a638b436f9c7fe70d0196f670af9a6000026b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Hjortsh=C3=B8j?= Date: Thu, 10 Oct 2019 11:10:10 +0200 Subject: [PATCH 091/143] Update README.md Remove license badge (Github shows it themselves now) and add discord badge --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 092c33155..920cf71fb 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ - - + +
From 5b52fed268b3544bea562f4263d447b96ebacd3a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 10 Oct 2019 20:41:16 +0100 Subject: [PATCH 092/143] Correct (experimental) System V AMD64 ABI support --- src/check_type.cpp | 174 ++++++++++++++++++++++++++++++++++++++++++++- src/ir.cpp | 111 ++++++++++++++++++++++------- src/ir_print.cpp | 82 ++++++++++++++------- 3 files changed, 316 insertions(+), 51 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index 65e0bc880..fe5825c47 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1837,6 +1837,168 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) { return tuple; } +Array systemv_distribute_struct_fields(Type *t, i32 level=0) { + t = base_type(t); + GB_ASSERT_MSG(t->kind == Type_Struct, "%s %d", type_to_string(t), level); + TypeStruct *ts = &t->Struct; + + auto distributed = array_make(heap_allocator(), 0, ts->fields.count); + + for_array(field_index, ts->fields) { + Entity *f = ts->fields[field_index]; + Type *bt = core_type(f->type); + switch (bt->kind) { + case Type_Struct: + if (bt->Struct.is_raw_union) { + goto DEFAULT; + } else { + // IMPORTANT TOOD(bill): handle #packed structs correctly + // IMPORTANT TODO(bill): handle #align structs correctly + auto nested = systemv_distribute_struct_fields(f->type, level+1); + for_array(i, nested) { + array_add(&distributed, nested[i]); + } + array_free(&nested); + } + break; + + case Type_Array: + for (i64 i = 0; i < bt->Array.count; i++) { + array_add(&distributed, bt->Array.elem); + } + break; + + case Type_BitSet: + array_add(&distributed, bit_set_to_int(bt)); + break; + + case Type_Tuple: + GB_PANIC("Invalid struct field type"); + break; + + case Type_Slice: + case Type_DynamicArray: + case Type_Map: + case Type_Union: + case Type_BitField: // TODO(bill): Ignore? + // NOTE(bill, 2019-10-10): Odin specific, don't worry about C calling convention yet + goto DEFAULT; + + case Type_Pointer: + case Type_Proc: + case Type_SimdVector: // TODO(bill): Is this correct logic? + default: + DEFAULT:; + if (type_size_of(bt) > 0) { + array_add(&distributed, bt); + } + break; + } + } + + return distributed; +} + +Type *struct_type_from_systemv_distribute_struct_fields(Type *abi_type) { + GB_ASSERT(is_type_tuple(abi_type)); + Type *final_type = alloc_type_struct(); + final_type->Struct.fields = abi_type->Tuple.variables; + return final_type; +} + + +Type *handle_single_distributed_type_parameter(Array const &types, bool packed, isize *offset) { + GB_ASSERT(types.count > 0); + + if (types.count == 1) { + if (offset) *offset = 1; + if (is_type_float(types[0])) { + return types[0]; + } else if (type_size_of(types[0]) == 8) { + return types[0]; + } else { + return t_u64; + } + } else if (types.count >= 2) { + if (types[0] == t_f32 && types[1] == t_f32) { + if (offset) *offset = 2; + return alloc_type_simd_vector(2, t_f32); + } else if (type_size_of(types[0]) == 8) { + if (offset) *offset = 1; + return types[0]; + } + + i64 total_size = 0; + isize i = 0; + if (packed) { + for (; i < types.count && total_size < 8; i += 1) { + Type *t = types[i]; + i64 s = type_size_of(t); + total_size += s; + } + } else { + for (; i < types.count && total_size < 8; i += 1) { + Type *t = types[i]; + i64 s = gb_max(type_size_of(t), 0); + i64 a = gb_max(type_align_of(t), 1); + isize ts = align_formula(total_size, a); + if (ts >= 8) { + break; + } + total_size = ts + s; + } + } + if (offset) *offset = i; + return t_u64; + } + + return nullptr; +} + +Type *handle_struct_system_v_amd64_abi_type(Type *t) { + GB_ASSERT(is_type_struct(t)); + Type *bt = core_type(t); + i64 size = type_size_of(bt); + + if (!bt->Struct.is_raw_union) { + auto field_types = systemv_distribute_struct_fields(bt); + defer (array_free(&field_types)); + + GB_ASSERT(field_types.count <= 16); + + Type *final_type = nullptr; + + if (field_types.count == 0) { + // Do nothing + } else if (field_types.count == 1) { + final_type = field_types[0]; + } else { + if (size <= 8) { + isize offset = 0; + final_type = handle_single_distributed_type_parameter(field_types, bt->Struct.is_packed, &offset); + } else { + isize offset = 0; + isize next_offset = 0; + Type *two_types[2] = {}; + + two_types[0] = handle_single_distributed_type_parameter(field_types, bt->Struct.is_packed, &offset); + auto remaining = array_slice(field_types, offset, field_types.count); + two_types[1] = handle_single_distributed_type_parameter(remaining, bt->Struct.is_packed, &next_offset); + GB_ASSERT(offset + next_offset == field_types.count); + + auto variables = array_make(heap_allocator(), 2); + variables[0] = alloc_entity_param(nullptr, empty_token, two_types[0], false, false); + variables[1] = alloc_entity_param(nullptr, empty_token, two_types[1], false, false); + final_type = alloc_type_tuple(); + final_type->Tuple.variables = variables; + } + } + return final_type; + } else { + return t; + } +} + Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCallingConvention cc) { Type *new_type = original_type; @@ -1901,6 +2063,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall { i64 align = type_align_of(original_type); i64 size = type_size_of(original_type); + switch (8*size) { case 8: new_type = t_u8; break; case 16: new_type = t_u16; break; @@ -1944,6 +2107,15 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall i64 size = type_size_of(original_type); if (8*size > 16) { new_type = alloc_type_pointer(original_type); + } else if (build_context.ODIN_ARCH == "amd64") { + // NOTE(bill): System V AMD64 ABI + if (bt->Struct.is_raw_union) { + // TODO(bill): Handle raw union correctly for + break; + } + + new_type = handle_struct_system_v_amd64_abi_type(bt); + return new_type; } break; @@ -2018,7 +2190,7 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCal } } else if (build_context.ODIN_OS == "linux" || build_context.ODIN_OS == "darwin") { if (build_context.ODIN_ARCH == "amd64") { - + } } else { // IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for diff --git a/src/ir.cpp b/src/ir.cpp index f29d389f4..16a017407 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -147,6 +147,7 @@ struct irProcedure { Array context_stack; + i32 parameter_count; irValue *return_ptr_hint_value; Ast * return_ptr_hint_ast; @@ -425,6 +426,7 @@ enum irParamPasskind { irParamPass_Integer, // Pass as an integer of the same size irParamPass_ConstRef, // Pass as a pointer but the value is immutable irParamPass_BitCast, // Pass by value and bit cast to the correct type + irParamPass_Tuple, // Pass across multiple parameters (System V AMD64, up to 2) }; struct irValueParam { @@ -433,6 +435,7 @@ struct irValueParam { Entity * entity; Type * type; Type * original_type; + i32 index; Array referrers; }; @@ -914,15 +917,18 @@ irValue *ir_value_global(Entity *e, irValue *value) { if (value) value->uses += 1; return v; } -irValue *ir_value_param(irProcedure *parent, Entity *e, Type *abi_type) { +irValue *ir_value_param(irProcedure *parent, Entity *e, Type *abi_type, i32 index) { irValue *v = ir_alloc_value(irValue_Param); v->Param.kind = irParamPass_Value; v->Param.parent = parent; - v->Param.entity = e; - v->Param.original_type = e->type; + if (e != nullptr) { + v->Param.entity = e; + v->Param.original_type = e->type; + } v->Param.type = abi_type; + v->Param.index = index; - if (abi_type != e->type) { + if (e != nullptr && abi_type != e->type) { if (is_type_pointer(abi_type)) { GB_ASSERT(e->kind == Entity_Variable); v->Param.kind = irParamPass_Pointer; @@ -935,8 +941,12 @@ irValue *ir_value_param(irProcedure *parent, Entity *e, Type *abi_type) { v->Param.kind = irParamPass_Value; } else if (is_type_simd_vector(abi_type)) { v->Param.kind = irParamPass_BitCast; + } else if (is_type_float(abi_type)) { + v->Param.kind = irParamPass_BitCast; + } else if (is_type_tuple(abi_type)) { + v->Param.kind = irParamPass_Tuple; } else { - GB_PANIC("Invalid abi type pass kind"); + GB_PANIC("Invalid abi type pass kind %s", type_to_string(abi_type)); } } array_init(&v->Param.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here @@ -1429,7 +1439,7 @@ irValue *ir_value_procedure(irModule *m, Entity *entity, Type *type, Ast *type_e Type *t = base_type(type); GB_ASSERT(is_type_proc(t)); - array_init(&v->Proc.params, ir_allocator(), 0, t->Proc.param_count); + array_init(&v->Proc.params, heap_allocator(), 0, t->Proc.param_count); return v; } @@ -1499,7 +1509,9 @@ void ir_start_block(irProcedure *proc, irBlock *block) { } - +irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t); +irValue *ir_address_from_load_or_generate_local(irProcedure *proc, irValue *val); +irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index); @@ -1713,9 +1725,12 @@ irValue *ir_add_global_generated(irModule *m, Type *type, irValue *value) { irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type, i32 index) { - irValue *v = ir_value_param(proc, e, abi_type); + irValue *v = ir_value_param(proc, e, abi_type, index); + array_add(&proc->params, v); irValueParam *p = &v->Param; + irValue *res = nullptr; + ir_push_debug_location(proc->module, e ? e->identifier : nullptr, proc->debug_scope, e); defer (ir_pop_debug_location(proc->module)); @@ -1750,6 +1765,24 @@ irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type, i ir_emit_store(proc, l, x); return x; } + case irParamPass_Tuple: { + irValue *l = ir_add_local(proc, e, expr, true, index); + Type *st = struct_type_from_systemv_distribute_struct_fields(abi_type); + irValue *ptr = ir_emit_bitcast(proc, l, alloc_type_pointer(st)); + if (abi_type->Tuple.variables.count > 0) { + array_pop(&proc->params); + } + for_array(i, abi_type->Tuple.variables) { + Type *t = abi_type->Tuple.variables[i]->type; + + irValue *elem = ir_value_param(proc, nullptr, t, index+cast(i32)i); + array_add(&proc->params, elem); + + irValue *dst = ir_emit_struct_ep(proc, ptr, cast(i32)i); + ir_emit_store(proc, dst, elem); + } + return ir_emit_load(proc, l); + } } @@ -2945,10 +2978,6 @@ void ir_emit_unreachable(irProcedure *proc) { ir_emit(proc, ir_instr_unreachable(proc)); } -irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t); -irValue *ir_address_from_load_or_generate_local(irProcedure *proc, irValue *val); -irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index); - irValue *ir_get_package_value(irModule *m, String package_name, String entity_name) { AstPackage *rt_pkg = get_core_package(m->info, package_name); @@ -2998,7 +3027,7 @@ Array ir_value_to_array(irProcedure *p, irValue *value) { } -irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, ProcInlining inlining = ProcInlining_none, bool use_return_ptr_hint = false) { +irValue *ir_emit_call(irProcedure *p, irValue *value, Array const &args, ProcInlining inlining = ProcInlining_none, bool use_return_ptr_hint = false) { Type *pt = base_type(ir_type(value)); GB_ASSERT(pt->kind == Type_Proc); Type *results = pt->Proc.results; @@ -3008,6 +3037,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro context_ptr = ir_find_or_generate_context_ptr(p); } + bool is_c_vararg = pt->Proc.c_vararg; isize param_count = pt->Proc.param_count; if (is_c_vararg) { @@ -3016,9 +3046,13 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro } else { GB_ASSERT_MSG(param_count == args.count, "%td == %td", param_count, args.count); } + + auto processed_args = array_make(heap_allocator(), 0, args.count); + for (isize i = 0; i < param_count; i++) { Entity *e = pt->Proc.params->Tuple.variables[i]; if (e->kind != Entity_Variable) { + array_add(&processed_args, args[i]); continue; } GB_ASSERT(e->flags & EntityFlag_Param); @@ -3027,20 +3061,29 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro Type *new_type = pt->Proc.abi_compat_params[i]; Type *arg_type = ir_type(args[i]); if (are_types_identical(arg_type, new_type)) { + array_add(&processed_args, args[i]); // NOTE(bill): Done } else if (!are_types_identical(original_type, new_type)) { if (is_type_pointer(new_type) && !is_type_pointer(original_type)) { if (e->flags&EntityFlag_ImplicitReference) { - args[i] = ir_address_from_load_or_generate_local(p, args[i]); + array_add(&processed_args, ir_address_from_load_or_generate_local(p, args[i])); } else if (!is_type_pointer(arg_type)) { - args[i] = ir_copy_value_to_ptr(p, args[i], original_type, 16); + array_add(&processed_args, ir_copy_value_to_ptr(p, args[i], original_type, 16)); } } else if (is_type_integer(new_type)) { - args[i] = ir_emit_transmute(p, args[i], new_type); + array_add(&processed_args, ir_emit_transmute(p, args[i], new_type)); } else if (new_type == t_llvm_bool) { - args[i] = ir_emit_conv(p, args[i], new_type); + array_add(&processed_args, ir_emit_conv(p, args[i], new_type)); } else if (is_type_simd_vector(new_type)) { - args[i] = ir_emit_bitcast(p, args[i], new_type); + array_add(&processed_args, ir_emit_bitcast(p, args[i], new_type)); + } else if (is_type_tuple(new_type)) { + Type *abi_type = pt->Proc.abi_compat_params[i]; + Type *st = struct_type_from_systemv_distribute_struct_fields(abi_type); + irValue *x = ir_emit_transmute(p, args[i], st); + for (isize j = 0; j < new_type->Tuple.variables.count; j++) { + irValue *xx = ir_emit_struct_ev(p, x, cast(i32)j); + array_add(&processed_args, xx); + } } } } @@ -3066,10 +3109,10 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro return_ptr = ir_add_local_generated(p, rt, true); } GB_ASSERT(is_type_pointer(ir_type(return_ptr))); - ir_emit(p, ir_instr_call(p, value, return_ptr, args, nullptr, context_ptr, inlining)); + ir_emit(p, ir_instr_call(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining)); result = ir_emit_load(p, return_ptr); } else { - result = ir_emit(p, ir_instr_call(p, value, nullptr, args, abi_rt, context_ptr, inlining)); + result = ir_emit(p, ir_instr_call(p, value, nullptr, processed_args, abi_rt, context_ptr, inlining)); if (abi_rt != results) { result = ir_emit_transmute(p, result, rt); } @@ -9540,6 +9583,7 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) { //////////////////////////////////////////////////////////////// void ir_number_proc_registers(irProcedure *proc) { + // i32 reg_index = proc->parameter_count; i32 reg_index = 0; for_array(i, proc->blocks) { irBlock *b = proc->blocks[i]; @@ -9595,13 +9639,15 @@ void ir_begin_procedure_body(irProcedure *proc) { proc->entry_block = ir_new_block(proc, proc->type_expr, "entry"); ir_start_block(proc, proc->entry_block); + i32 parameter_index = 0; + if (proc->type->Proc.return_by_pointer) { // NOTE(bill): this must be the first parameter stored Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(proc->type->Proc.results)); Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false); e->flags |= EntityFlag_Sret | EntityFlag_NoAlias; - irValue *param = ir_value_param(proc, e, ptr_type); + irValue *param = ir_value_param(proc, e, ptr_type, -1); param->Param.kind = irParamPass_Pointer; ir_module_add_value(proc->module, e, param); @@ -9630,13 +9676,19 @@ void ir_begin_procedure_body(irProcedure *proc) { Entity *e = params->variables[i]; if (e->kind != Entity_Variable) { + parameter_index += 1; continue; } Type *abi_type = proc->type->Proc.abi_compat_params[i]; if (e->token.string != "" && !is_blank_ident(e->token)) { - irValue *param = ir_add_param(proc, e, name, abi_type, cast(i32)(i+1)); - array_add(&proc->params, param); + ir_add_param(proc, e, name, abi_type, parameter_index); + } + + if (is_type_tuple(abi_type)) { + parameter_index += cast(i32)abi_type->Tuple.variables.count; + } else { + parameter_index += 1; } } } else { @@ -9645,6 +9697,7 @@ void ir_begin_procedure_body(irProcedure *proc) { for_array(i, params->variables) { Entity *e = params->variables[i]; if (e->kind != Entity_Variable) { + parameter_index += 1; continue; } Type *abi_type = e->type; @@ -9652,8 +9705,12 @@ void ir_begin_procedure_body(irProcedure *proc) { abi_type = abi_types[i]; } if (e->token.string != "" && !is_blank_ident(e->token)) { - irValue *param = ir_add_param(proc, e, nullptr, abi_type, cast(i32)(i+1)); - array_add(&proc->params, param); + ir_add_param(proc, e, nullptr, abi_type, parameter_index); + } + if (is_type_tuple(abi_type)) { + parameter_index += cast(i32)abi_type->Tuple.variables.count; + } else { + parameter_index += 1; } } } @@ -9695,11 +9752,13 @@ void ir_begin_procedure_body(irProcedure *proc) { if (proc->type->Proc.calling_convention == ProcCC_Odin) { Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("__.context_ptr")), t_context_ptr, false, false); e->flags |= EntityFlag_NoAlias; - irValue *param = ir_value_param(proc, e, e->type); + irValue *param = ir_value_param(proc, e, e->type, -1); ir_module_add_value(proc->module, e, param); irContextData ctx = {param, proc->scope_index}; array_add(&proc->context_stack, ctx); } + + proc->parameter_count = parameter_index; } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index db9eb1bfb..f76539fd6 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1130,7 +1130,11 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin break; } case irValue_Param: - ir_print_encoded_local(f, value->Param.entity->token.string); + if (value->Param.index >= 0) { + ir_fprintf(f, "%%_.%d", value->Param.index); + } else { + ir_print_encoded_local(f, value->Param.entity->token.string); + } break; case irValue_SourceCodeLocation: { irValue *file = value->SourceCodeLocation.file; @@ -1936,9 +1940,6 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { } ir_write_byte(f, ' '); irValue *arg = call->args[i]; - if (is_type_boolean(t)) { - - } ir_print_value(f, m, arg, t); param_index++; } @@ -1953,24 +1954,43 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { param_index++; } } else { - GB_ASSERT(call->args.count == params->variables.count); + // GB_ASSERT(call->args.count == params->variables.count); + isize arg_index = 0; for_array(i, params->variables) { Entity *e = params->variables[i]; GB_ASSERT(e != nullptr); - if (e->kind != Entity_Variable) continue; + if (e->kind != Entity_Variable) { + arg_index++; + continue; + } if (param_index > 0) ir_write_str_lit(f, ", "); - irValue *arg = call->args[i]; Type *t = proc_type->Proc.abi_compat_params[i]; + if (is_type_tuple(t)) { + for_array(j, t->Tuple.variables) { + if (j > 0) ir_write_str_lit(f, ", "); - ir_print_type(f, m, t); - if (e->flags&EntityFlag_NoAlias) { - ir_write_str_lit(f, " noalias"); + irValue *arg = call->args[arg_index++]; + + ir_print_type(f, m, t->Tuple.variables[j]->type); + if (e->flags&EntityFlag_NoAlias) { + ir_write_str_lit(f, " noalias"); + } + ir_write_byte(f, ' '); + ir_print_value(f, m, arg, t); + param_index++; + } + } else { + irValue *arg = call->args[arg_index++]; + ir_print_type(f, m, t); + if (e->flags&EntityFlag_NoAlias) { + ir_write_str_lit(f, " noalias"); + } + ir_write_byte(f, ' '); + ir_print_value(f, m, arg, t); + param_index++; } - ir_write_byte(f, ' '); - ir_print_value(f, m, arg, t); - param_index++; } } } @@ -2089,7 +2109,8 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { if (param_count > 0) { TypeTuple *params = &proc_type->params->Tuple; - for (isize i = 0; i < param_count; i++) { + isize parameter_index = 0; + for (isize i = 0; i < param_count; i++, parameter_index++) { Entity *e = params->variables[i]; Type *original_type = e->type; Type *abi_type = proc_type->abi_compat_params[i]; @@ -2099,16 +2120,29 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { if (i+1 == params->variables.count && proc_type->c_vararg) { ir_write_str_lit(f, " ..."); } else { - ir_print_type(f, m, abi_type); - if (e->flags&EntityFlag_NoAlias) { - ir_write_str_lit(f, " noalias"); - } - if (proc->body != nullptr) { - if (e->token.string != "" && !is_blank_ident(e->token)) { - ir_write_byte(f, ' '); - ir_print_encoded_local(f, e->token.string); - } else { - ir_fprintf(f, " %%_.param_%td", i); + if (is_type_tuple(abi_type)) { + for_array(j, abi_type->Tuple.variables) { + if (j > 0) ir_write_string(f, str_lit(", ")); + + Type *tft = abi_type->Tuple.variables[j]->type; + ir_print_type(f, m, tft); + if (e->flags&EntityFlag_NoAlias) { + ir_write_str_lit(f, " noalias"); + } + + if (proc->body != nullptr) { + ir_fprintf(f, " %%_.%td", parameter_index+j); + } + } + parameter_index += abi_type->Tuple.variables.count-1; + param_index += abi_type->Tuple.variables.count-1; + } else { + ir_print_type(f, m, abi_type); + if (e->flags&EntityFlag_NoAlias) { + ir_write_str_lit(f, " noalias"); + } + if (proc->body != nullptr) { + ir_fprintf(f, " %%_.%td", parameter_index); } } } From abfa8945661f24006e4f8506c1ec2861569228ec Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 10 Oct 2019 20:52:07 +0100 Subject: [PATCH 093/143] Fix general IR parameter case --- src/check_type.cpp | 16 +++++++++------- src/ir.cpp | 5 ++++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index fe5825c47..89ee15666 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2108,14 +2108,16 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall if (8*size > 16) { new_type = alloc_type_pointer(original_type); } else if (build_context.ODIN_ARCH == "amd64") { - // NOTE(bill): System V AMD64 ABI - if (bt->Struct.is_raw_union) { - // TODO(bill): Handle raw union correctly for - break; - } + if (is_type_struct(bt)) { + // NOTE(bill): System V AMD64 ABI + if (bt->Struct.is_raw_union) { + // TODO(bill): Handle raw union correctly for + break; + } - new_type = handle_struct_system_v_amd64_abi_type(bt); - return new_type; + new_type = handle_struct_system_v_amd64_abi_type(bt); + return new_type; + } } break; diff --git a/src/ir.cpp b/src/ir.cpp index 16a017407..017a12025 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3061,8 +3061,8 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array const &ar Type *new_type = pt->Proc.abi_compat_params[i]; Type *arg_type = ir_type(args[i]); if (are_types_identical(arg_type, new_type)) { - array_add(&processed_args, args[i]); // NOTE(bill): Done + array_add(&processed_args, args[i]); } else if (!are_types_identical(original_type, new_type)) { if (is_type_pointer(new_type) && !is_type_pointer(original_type)) { if (e->flags&EntityFlag_ImplicitReference) { @@ -3085,6 +3085,9 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array const &ar array_add(&processed_args, xx); } } + } else { + irValue *x = ir_emit_conv(p, args[i], new_type); + array_add(&processed_args, x); } } From 8672ff1c55147a1b6f276b8e3f64d3d48eb0edf9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 10 Oct 2019 20:57:31 +0100 Subject: [PATCH 094/143] Fix typo in System V ABI determination --- src/check_type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index 89ee15666..672dee338 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2105,7 +2105,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall case Type_Struct: { i64 align = type_align_of(original_type); i64 size = type_size_of(original_type); - if (8*size > 16) { + if (size > 16) { new_type = alloc_type_pointer(original_type); } else if (build_context.ODIN_ARCH == "amd64") { if (is_type_struct(bt)) { From 672a8f5dbd101441b732abd2b3ec1c656fc4e30f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 10 Oct 2019 21:13:06 +0100 Subject: [PATCH 095/143] Add Odin types for System V ABI --- src/check_type.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/check_type.cpp b/src/check_type.cpp index 672dee338..e4f3cbf0e 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1848,6 +1848,50 @@ Array systemv_distribute_struct_fields(Type *t, i32 level=0) { Entity *f = ts->fields[field_index]; Type *bt = core_type(f->type); switch (bt->kind) { + case Type_Basic: + switch (bt->Basic.kind){ + case Basic_complex64: + array_add(&distributed, t_f32); + array_add(&distributed, t_f32); + break; + case Basic_complex128: + array_add(&distributed, t_f64); + array_add(&distributed, t_f64); + break; + case Basic_quaternion128: + array_add(&distributed, t_f32); + array_add(&distributed, t_f32); + array_add(&distributed, t_f32); + array_add(&distributed, t_f32); + break; + case Basic_quaternion256: + array_add(&distributed, t_f64); + array_add(&distributed, t_f64); + array_add(&distributed, t_f64); + array_add(&distributed, t_f64); + break; + case Basic_string: + array_add(&distributed, t_u8_ptr); + array_add(&distributed, t_int); + break; + case Basic_any: + GB_ASSERT(type_size_of(t_uintptr) == type_size_of(t_typeid)); + array_add(&distributed, t_rawptr); + array_add(&distributed, t_uintptr); + break; + + case Basic_u128: + case Basic_i128: + if (build_context.ODIN_OS == "windows") { + array_add(&distributed, alloc_type_simd_vector(2, t_u64)); + } else { + array_add(&distributed, bt); + } + default: + goto DEFAULT; + } + break; + case Type_Struct: if (bt->Struct.is_raw_union) { goto DEFAULT; @@ -1877,6 +1921,10 @@ Array systemv_distribute_struct_fields(Type *t, i32 level=0) { break; case Type_Slice: + array_add(&distributed, t_rawptr); + array_add(&distributed, t_int); + break; + case Type_DynamicArray: case Type_Map: case Type_Union: From 31391519353ba65e032cf6681d056cc7401557e3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 10 Oct 2019 21:24:32 +0100 Subject: [PATCH 096/143] Minor fix to systemv_distribute_struct_fields --- src/check_type.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index e4f3cbf0e..0d9722ad8 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1837,9 +1837,9 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) { return tuple; } -Array systemv_distribute_struct_fields(Type *t, i32 level=0) { +Array systemv_distribute_struct_fields(Type *t) { t = base_type(t); - GB_ASSERT_MSG(t->kind == Type_Struct, "%s %d", type_to_string(t), level); + GB_ASSERT_MSG(t->kind == Type_Struct, "%s", type_to_string(t)); TypeStruct *ts = &t->Struct; auto distributed = array_make(heap_allocator(), 0, ts->fields.count); @@ -1865,11 +1865,7 @@ Array systemv_distribute_struct_fields(Type *t, i32 level=0) { array_add(&distributed, t_f32); break; case Basic_quaternion256: - array_add(&distributed, t_f64); - array_add(&distributed, t_f64); - array_add(&distributed, t_f64); - array_add(&distributed, t_f64); - break; + goto DEFAULT; case Basic_string: array_add(&distributed, t_u8_ptr); array_add(&distributed, t_int); @@ -1887,6 +1883,8 @@ Array systemv_distribute_struct_fields(Type *t, i32 level=0) { } else { array_add(&distributed, bt); } + break; + default: goto DEFAULT; } @@ -1898,7 +1896,7 @@ Array systemv_distribute_struct_fields(Type *t, i32 level=0) { } else { // IMPORTANT TOOD(bill): handle #packed structs correctly // IMPORTANT TODO(bill): handle #align structs correctly - auto nested = systemv_distribute_struct_fields(f->type, level+1); + auto nested = systemv_distribute_struct_fields(f->type); for_array(i, nested) { array_add(&distributed, nested[i]); } From 39b3c8c80fa65ce91174659c5155b5e51512e8c1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 10 Oct 2019 21:39:46 +0100 Subject: [PATCH 097/143] Update System V ABI to for more Odin types --- src/check_type.cpp | 254 +++++++++++++++++++++++++-------------------- 1 file changed, 139 insertions(+), 115 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index 0d9722ad8..917682f33 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1838,108 +1838,109 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) { } Array systemv_distribute_struct_fields(Type *t) { - t = base_type(t); - GB_ASSERT_MSG(t->kind == Type_Struct, "%s", type_to_string(t)); - TypeStruct *ts = &t->Struct; + Type *bt = core_type(t); - auto distributed = array_make(heap_allocator(), 0, ts->fields.count); - for_array(field_index, ts->fields) { - Entity *f = ts->fields[field_index]; - Type *bt = core_type(f->type); - switch (bt->kind) { - case Type_Basic: - switch (bt->Basic.kind){ - case Basic_complex64: - array_add(&distributed, t_f32); - array_add(&distributed, t_f32); - break; - case Basic_complex128: - array_add(&distributed, t_f64); - array_add(&distributed, t_f64); - break; - case Basic_quaternion128: - array_add(&distributed, t_f32); - array_add(&distributed, t_f32); - array_add(&distributed, t_f32); - array_add(&distributed, t_f32); - break; - case Basic_quaternion256: - goto DEFAULT; - case Basic_string: - array_add(&distributed, t_u8_ptr); - array_add(&distributed, t_int); - break; - case Basic_any: - GB_ASSERT(type_size_of(t_uintptr) == type_size_of(t_typeid)); - array_add(&distributed, t_rawptr); - array_add(&distributed, t_uintptr); - break; + isize distributed_cap = 1; + if (bt->kind == Type_Struct) { + distributed_cap = bt->Struct.fields.count; + } + auto distributed = array_make(heap_allocator(), 0, distributed_cap); - case Basic_u128: - case Basic_i128: - if (build_context.ODIN_OS == "windows") { - array_add(&distributed, alloc_type_simd_vector(2, t_u64)); - } else { - array_add(&distributed, bt); - } - break; - default: - goto DEFAULT; - } + switch (bt->kind) { + case Type_Basic: + switch (bt->Basic.kind){ + case Basic_complex64: + array_add(&distributed, t_f32); + array_add(&distributed, t_f32); break; - - case Type_Struct: - if (bt->Struct.is_raw_union) { - goto DEFAULT; - } else { - // IMPORTANT TOOD(bill): handle #packed structs correctly - // IMPORTANT TODO(bill): handle #align structs correctly - auto nested = systemv_distribute_struct_fields(f->type); - for_array(i, nested) { - array_add(&distributed, nested[i]); - } - array_free(&nested); - } + case Basic_complex128: + array_add(&distributed, t_f64); + array_add(&distributed, t_f64); break; - - case Type_Array: - for (i64 i = 0; i < bt->Array.count; i++) { - array_add(&distributed, bt->Array.elem); - } + case Basic_quaternion128: + array_add(&distributed, t_f32); + array_add(&distributed, t_f32); + array_add(&distributed, t_f32); + array_add(&distributed, t_f32); break; - - case Type_BitSet: - array_add(&distributed, bit_set_to_int(bt)); - break; - - case Type_Tuple: - GB_PANIC("Invalid struct field type"); - break; - - case Type_Slice: - array_add(&distributed, t_rawptr); + case Basic_quaternion256: + goto DEFAULT; + case Basic_string: + array_add(&distributed, t_u8_ptr); array_add(&distributed, t_int); break; + case Basic_any: + GB_ASSERT(type_size_of(t_uintptr) == type_size_of(t_typeid)); + array_add(&distributed, t_rawptr); + array_add(&distributed, t_uintptr); + break; - case Type_DynamicArray: - case Type_Map: - case Type_Union: - case Type_BitField: // TODO(bill): Ignore? - // NOTE(bill, 2019-10-10): Odin specific, don't worry about C calling convention yet - goto DEFAULT; - - case Type_Pointer: - case Type_Proc: - case Type_SimdVector: // TODO(bill): Is this correct logic? - default: - DEFAULT:; - if (type_size_of(bt) > 0) { + case Basic_u128: + case Basic_i128: + if (build_context.ODIN_OS == "windows") { + array_add(&distributed, alloc_type_simd_vector(2, t_u64)); + } else { array_add(&distributed, bt); } break; + + default: + goto DEFAULT; } + break; + + case Type_Struct: + if (bt->Struct.is_raw_union) { + goto DEFAULT; + } else { + // IMPORTANT TOOD(bill): handle #packed structs correctly + // IMPORTANT TODO(bill): handle #align structs correctly + for_array(field_index, bt->Struct.fields) { + Entity *f = bt->Struct.fields[field_index]; + auto nested = systemv_distribute_struct_fields(f->type); + array_add_elems(&distributed, nested.data, nested.count); + array_free(&nested); + } + } + break; + + case Type_Array: + for (i64 i = 0; i < bt->Array.count; i++) { + array_add(&distributed, bt->Array.elem); + } + break; + + case Type_BitSet: + array_add(&distributed, bit_set_to_int(bt)); + break; + + case Type_Tuple: + GB_PANIC("Invalid struct field type"); + break; + + case Type_Slice: + array_add(&distributed, t_rawptr); + array_add(&distributed, t_int); + break; + + case Type_DynamicArray: + case Type_Map: + case Type_Union: + case Type_BitField: // TODO(bill): Ignore? + // NOTE(bill, 2019-10-10): Odin specific, don't worry about C calling convention yet + goto DEFAULT; + + case Type_Pointer: + case Type_Proc: + case Type_SimdVector: // TODO(bill): Is this correct logic? + default: + DEFAULT:; + if (type_size_of(bt) > 0) { + array_add(&distributed, bt); + } + break; } return distributed; @@ -2002,11 +2003,48 @@ Type *handle_single_distributed_type_parameter(Array const &types, bool } Type *handle_struct_system_v_amd64_abi_type(Type *t) { - GB_ASSERT(is_type_struct(t)); + Type *original_type = t; Type *bt = core_type(t); + t = base_type(t); i64 size = type_size_of(bt); - if (!bt->Struct.is_raw_union) { + switch (t->kind) { + case Type_Array: + case Type_Slice: + case Type_DynamicArray: + case Type_Struct: + break; + + case Type_Basic: + switch (bt->Basic.kind) { + case Basic_string: + case Basic_any: + case Basic_complex64: + case Basic_complex128: + case Basic_quaternion128: + break; + } + return original_type; + case Type_Pointer: + case Type_Map: + case Type_Union: + case Type_Enum: + case Type_Proc: + case Type_BitField: + case Type_BitSet: + case Type_SimdVector: + return original_type; + } + + bool is_packed = false; + if (is_type_struct(bt)) { + is_packed = bt->Struct.is_packed; + } + + if (is_type_raw_union(bt)) { + // TODO(bill): Handle raw union correctly for + return t; + } else { auto field_types = systemv_distribute_struct_fields(bt); defer (array_free(&field_types)); @@ -2015,21 +2053,21 @@ Type *handle_struct_system_v_amd64_abi_type(Type *t) { Type *final_type = nullptr; if (field_types.count == 0) { - // Do nothing + return t; } else if (field_types.count == 1) { final_type = field_types[0]; } else { if (size <= 8) { isize offset = 0; - final_type = handle_single_distributed_type_parameter(field_types, bt->Struct.is_packed, &offset); + final_type = handle_single_distributed_type_parameter(field_types, is_packed, &offset); } else { isize offset = 0; isize next_offset = 0; Type *two_types[2] = {}; - two_types[0] = handle_single_distributed_type_parameter(field_types, bt->Struct.is_packed, &offset); + two_types[0] = handle_single_distributed_type_parameter(field_types, is_packed, &offset); auto remaining = array_slice(field_types, offset, field_types.count); - two_types[1] = handle_single_distributed_type_parameter(remaining, bt->Struct.is_packed, &next_offset); + two_types[1] = handle_single_distributed_type_parameter(remaining, is_packed, &next_offset); GB_ASSERT(offset + next_offset == field_types.count); auto variables = array_make(heap_allocator(), 2); @@ -2040,8 +2078,6 @@ Type *handle_struct_system_v_amd64_abi_type(Type *t) { } } return final_type; - } else { - return t; } } @@ -2141,29 +2177,17 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall case Type_Pointer: break; case Type_Proc: break; // NOTE(bill): Just a pointer - // Odin specific - case Type_Slice: - case Type_Array: - case Type_DynamicArray: - case Type_Map: - case Type_Union: - // Could be in C too - case Type_Struct: { - i64 align = type_align_of(original_type); - i64 size = type_size_of(original_type); + default: { + i64 size = type_size_of(original_type); if (size > 16) { new_type = alloc_type_pointer(original_type); } else if (build_context.ODIN_ARCH == "amd64") { - if (is_type_struct(bt)) { - // NOTE(bill): System V AMD64 ABI - if (bt->Struct.is_raw_union) { - // TODO(bill): Handle raw union correctly for - break; - } - - new_type = handle_struct_system_v_amd64_abi_type(bt); - return new_type; + // NOTE(bill): System V AMD64 ABI + new_type = handle_struct_system_v_amd64_abi_type(bt); + if (are_types_identical(core_type(original_type), new_type)) { + new_type = original_type; } + return new_type; } break; From fa81061db0d08a508ab8bbedfcf7bf5ad1e27daa Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 10 Oct 2019 21:50:20 +0100 Subject: [PATCH 098/143] Minor fix to Odin types with System V ABI --- src/check_type.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index 917682f33..329755ea5 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2003,15 +2003,16 @@ Type *handle_single_distributed_type_parameter(Array const &types, bool } Type *handle_struct_system_v_amd64_abi_type(Type *t) { + if (type_size_of(t) > 16) { + return alloc_type_pointer(t); + } Type *original_type = t; Type *bt = core_type(t); t = base_type(t); i64 size = type_size_of(bt); switch (t->kind) { - case Type_Array: case Type_Slice: - case Type_DynamicArray: case Type_Struct: break; @@ -2023,16 +2024,12 @@ Type *handle_struct_system_v_amd64_abi_type(Type *t) { case Basic_complex128: case Basic_quaternion128: break; + default: + return original_type; } - return original_type; - case Type_Pointer: - case Type_Map: - case Type_Union: - case Type_Enum: - case Type_Proc: - case Type_BitField: - case Type_BitSet: - case Type_SimdVector: + break; + + default: return original_type; } From 2a6d9e8927ad1eb1e5f3a79fc9ed068a02cbfdfc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 13 Oct 2019 12:38:23 +0100 Subject: [PATCH 099/143] `#panic`; Minor change to demo.odin; Fix `#assert` bug at file scope --- core/odin/parser/parser.odin | 2 +- core/runtime/core.odin | 54 +++++++++++++++--------------- examples/demo/demo.odin | 20 +++++------ src/check_expr.cpp | 22 +++++++++++-- src/check_type.cpp | 39 +++++++++++++++++----- src/checker.cpp | 13 ++++++-- src/checker.hpp | 1 + src/main.cpp | 14 +++----- src/parser.cpp | 38 +++------------------ src/types.cpp | 64 ++++++++++++++++++++---------------- 10 files changed, 145 insertions(+), 122 deletions(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 213041924..fee9b7bdc 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1091,7 +1091,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { case: error(p, stmt.pos, "#complete can only be applied to a switch statement"); } return stmt; - case "assert": + case "assert", "panic": bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(tag)); bd.tok = tok; bd.name = name; diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 729932781..9ad5d3d8a 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -6,6 +6,7 @@ package runtime import "core:os" import "core:mem" import "core:log" +import "intrinsics" // Naming Conventions: // In general, Ada_Case for types and snake_case for values @@ -187,12 +188,13 @@ Typeid_Kind :: enum u8 { #assert(len(Typeid_Kind) < 32); Typeid_Bit_Field :: bit_field #align align_of(uintptr) { - index: 8*size_of(align_of(uintptr)) - 8, + index: 8*size_of(uintptr) - 8, kind: 5, // Typeid_Kind named: 1, special: 1, // signed, cstring, etc reserved: 1, } +#assert(size_of(Typeid_Bit_Field) == size_of(uintptr)); // NOTE(bill): only the ones that are needed (not all types) // This will be set by the compiler @@ -678,7 +680,7 @@ assert :: proc(condition: bool, message := "", loc := #caller_location) -> bool if p == nil { p = default_assertion_failure_proc; } - p("Runtime assertion", message, loc); + p("runtime assertion", message, loc); }(message, loc); } return condition; @@ -690,7 +692,7 @@ panic :: proc(message: string, loc := #caller_location) -> ! { if p == nil { p = default_assertion_failure_proc; } - p("Panic", message, loc); + p("panic", message, loc); } @builtin @@ -816,8 +818,7 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { value: V, }; - _, is_string := type_info_base(type_info_of(K)).variant.(Type_Info_String); - header.is_key_string = is_string; + header.is_key_string = intrinsics.type_is_string(K); header.entry_size = int(size_of(Entry)); header.entry_align = int(align_of(Entry)); header.value_offset = uintptr(offset_of(Entry, value)); @@ -828,33 +829,34 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { __get_map_key :: proc "contextless" (k: $K) -> Map_Key { key := k; map_key: Map_Key; - ti := type_info_base_without_enum(type_info_of(K)); - switch _ in ti.variant { - case Type_Info_Integer: - switch 8*size_of(key) { - case 8: map_key.hash = u64(( ^u8)(&key)^); - case 16: map_key.hash = u64(( ^u16)(&key)^); - case 32: map_key.hash = u64(( ^u32)(&key)^); - case 64: map_key.hash = u64(( ^u64)(&key)^); - case: panic("Unhandled integer size"); - } - case Type_Info_Rune: + + T :: intrinsics.type_core_type(K); + + when intrinsics.type_is_integer(T) { + sz :: 8*size_of(T); + when sz == 8 do map_key.hash = u64(( ^u8)(&key)^); + else when sz == 16 do map_key.hash = u64((^u16)(&key)^); + else when sz == 32 do map_key.hash = u64((^u32)(&key)^); + else when sz == 64 do map_key.hash = u64((^u64)(&key)^); + else do #assert(false, "Unhandled integer size"); + } else when intrinsics.type_is_rune(T) { map_key.hash = u64((^rune)(&key)^); - case Type_Info_Pointer: + } else when intrinsics.type_is_pointer(T) { map_key.hash = u64(uintptr((^rawptr)(&key)^)); - case Type_Info_Float: - switch 8*size_of(key) { - case 32: map_key.hash = u64((^u32)(&key)^); - case 64: map_key.hash = u64((^u64)(&key)^); - case: panic("Unhandled float size"); - } - case Type_Info_String: + } else when intrinsics.type_is_float(T) { + sz :: 8*size_of(T); + when sz == 32 do map_key.hash = u64((^u32)(&key)^); + else when sz == 64 do map_key.hash = u64((^u64)(&key)^); + else do #assert(false, "Unhandled float size"); + } else when intrinsics.type_is_string(T) { + #assert(T == string); str := (^string)(&key)^; map_key.hash = default_hash_string(str); map_key.str = str; - case: - panic("Unhandled map key type"); + } else { + #assert(false, "Unhandled map key type"); } + return map_key; } diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index ff861b1de..5ee9ded84 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -28,9 +28,9 @@ when os.OS == "windows" { Answers to common questions about Odin. */ -@(link_name="general_stuff") -general_stuff :: proc() { - fmt.println("# general_stuff"); +@(link_name="extra_general_stuff") +extra_general_stuff :: proc() { + fmt.println("# extra_general_stuff"); { // `do` for inline statements rather than block foo :: proc() do fmt.println("Foo!"); if false do foo(); @@ -209,8 +209,8 @@ union_type :: proc() { } } - Vector3 :: struct {x, y, z: f32}; - Quaternion :: struct {x, y, z, w: f32}; + Vector3 :: distinct [3]f32; + Quaternion :: distinct quaternion128; // More realistic examples { @@ -320,17 +320,17 @@ union_type :: proc() { /* Entity :: struct { - .. + ... derived: union{^Frog, ^Monster}, } Frog :: struct { using entity: Entity, - .. + ... } Monster :: struct { using entity: Entity, - .. + ... } new_entity :: proc(T: type) -> ^Entity { @@ -539,7 +539,7 @@ parametric_polymorphism :: proc() { fmt.println(r); r = 123; fmt.println(r); - r = Error.Foo0; + r = Error.Foo0; // r = .Foo0; is allow too, see implicit selector expressions below fmt.println(r); } @@ -1190,7 +1190,7 @@ where_clauses :: proc() { main :: proc() { when true { - general_stuff(); + extra_general_stuff(); union_type(); parametric_polymorphism(); threading_example(); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6a0d8221f..7c418c4f0 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3071,7 +3071,6 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ } if (selector->kind != Ast_Ident) { - // if (selector->kind != Ast_Ident) { error(selector, "Illegal selector kind: '%.*s'", LIT(ast_strings[selector->kind])); operand->mode = Addressing_Invalid; operand->expr = node; @@ -3544,6 +3543,25 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 operand->type = t_untyped_bool; operand->mode = Addressing_Constant; + } else if (name == "panic") { + if (ce->args.count != 1) { + error(call, "'#panic' expects 1 argument, got %td", ce->args.count); + return false; + } + if (!is_type_string(operand->type) && operand->mode != Addressing_Constant) { + gbString str = expr_to_string(ce->args[0]); + error(call, "'%s' is not a constant string", str); + gb_string_free(str); + return false; + } + error(call, "Compile time panic: %.*s", LIT(operand->value.value_string)); + if (c->proc_name != "") { + gbString str = type_to_string(c->curr_proc_sig); + error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); + gb_string_free(str); + } + operand->type = t_invalid; + operand->mode = Addressing_NoValue; } else if (name == "defined") { if (ce->args.count != 1) { error(call, "'#defined' expects 1 argument, got %td", ce->args.count); @@ -6349,7 +6367,7 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) { ce->proc->kind == Ast_BasicDirective) { ast_node(bd, BasicDirective, ce->proc); String name = bd->name; - if (name == "location" || name == "assert" || name == "defined" || name == "load") { + if (name == "location" || name == "assert" || name == "panic" || name == "defined" || name == "load") { operand->mode = Addressing_Builtin; operand->builtin_id = BuiltinProc_DIRECTIVE; operand->expr = ce->proc; diff --git a/src/check_type.cpp b/src/check_type.cpp index 329755ea5..4d107a9ac 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1847,7 +1847,7 @@ Array systemv_distribute_struct_fields(Type *t) { } auto distributed = array_make(heap_allocator(), 0, distributed_cap); - + i64 sz = type_size_of(bt); switch (bt->kind) { case Type_Basic: switch (bt->Basic.kind){ @@ -1925,9 +1925,9 @@ Array systemv_distribute_struct_fields(Type *t) { array_add(&distributed, t_int); break; + case Type_Union: case Type_DynamicArray: case Type_Map: - case Type_Union: case Type_BitField: // TODO(bill): Ignore? // NOTE(bill, 2019-10-10): Odin specific, don't worry about C calling convention yet goto DEFAULT; @@ -1937,7 +1937,7 @@ Array systemv_distribute_struct_fields(Type *t) { case Type_SimdVector: // TODO(bill): Is this correct logic? default: DEFAULT:; - if (type_size_of(bt) > 0) { + if (sz > 0) { array_add(&distributed, bt); } break; @@ -1959,13 +1959,22 @@ Type *handle_single_distributed_type_parameter(Array const &types, bool if (types.count == 1) { if (offset) *offset = 1; + + i64 sz = type_size_of(types[0]); + if (is_type_float(types[0])) { return types[0]; - } else if (type_size_of(types[0]) == 8) { - return types[0]; - } else { - return t_u64; } + switch (sz) { + case 0: + GB_PANIC("Zero sized type found!"); + case 1: + case 2: + case 4: + case 8: + return types[0]; + } + return t_u64; } else if (types.count >= 2) { if (types[0] == t_f32 && types[1] == t_f32) { if (offset) *offset = 2; @@ -2050,7 +2059,7 @@ Type *handle_struct_system_v_amd64_abi_type(Type *t) { Type *final_type = nullptr; if (field_types.count == 0) { - return t; + final_type = t; } else if (field_types.count == 1) { final_type = field_types[0]; } else { @@ -2072,8 +2081,22 @@ Type *handle_struct_system_v_amd64_abi_type(Type *t) { variables[1] = alloc_entity_param(nullptr, empty_token, two_types[1], false, false); final_type = alloc_type_tuple(); final_type->Tuple.variables = variables; + if (t->kind == Type_Struct) { + // NOTE(bill): Make this packed + final_type->Tuple.is_packed = t->Struct.is_packed; + } } } + + + GB_ASSERT(final_type != nullptr); + i64 ftsz = type_size_of(final_type); + i64 otsz = type_size_of(original_type); + if (ftsz != otsz) { + // TODO(bill): Handle this case which will be caused by #packed most likely + GB_PANIC("Incorrectly handled case for handle_struct_system_v_amd64_abi_type, %lld vs %lld", ftsz, otsz); + } + return final_type; } } diff --git a/src/checker.cpp b/src/checker.cpp index f30273439..8ce9d8ec2 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3367,8 +3367,9 @@ bool collect_file_decls(CheckerContext *ctx, Array const &decls) { if (es->expr->kind == Ast_CallExpr) { ast_node(ce, CallExpr, es->expr); if (ce->proc->kind == Ast_BasicDirective) { - Operand o = {}; - check_expr(ctx, &o, es->expr); + if (ctx->collect_delayed_decls) { + array_add(&ctx->scope->delayed_directives, es->expr); + } } } case_end; @@ -3525,12 +3526,18 @@ void check_import_entities(Checker *c) { for_array(i, pkg->files) { AstFile *f = pkg->files[i]; CheckerContext ctx = c->init_ctx; - add_curr_ast_file(&ctx, f); + for_array(j, f->scope->delayed_imports) { Ast *decl = f->scope->delayed_imports[j]; check_add_import_decl(&ctx, decl); } + } + for_array(i, pkg->files) { + AstFile *f = pkg->files[i]; + CheckerContext ctx = c->init_ctx; + add_curr_ast_file(&ctx, f); + for_array(j, f->scope->delayed_directives) { Ast *expr = f->scope->delayed_directives[j]; Operand o = {}; diff --git a/src/checker.hpp b/src/checker.hpp index 58cb01a82..f86acce5c 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -222,6 +222,7 @@ struct ForeignContext { typedef Array CheckerTypePath; typedef Array CheckerPolyPath; + // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { Map untyped; // Key: Ast * | Expression -> ExprInfo diff --git a/src/main.cpp b/src/main.cpp index b294e7f96..78859e04e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -445,7 +445,7 @@ bool parse_build_flags(Array args) { path = substring(path, 0, string_extension_position(path)); } #endif - build_context.out_filepath = path; + build_context.out_filepath = path_to_full_path(heap_allocator(), path); } else { gb_printf_err("Invalid -out path, got %.*s\n", LIT(path)); bad_flags = true; @@ -624,7 +624,7 @@ bool parse_build_flags(Array args) { break; } - if (str == "dll") { + if (str == "dll" || str == "shared") { build_context.is_dll = true; } else if (str == "exe") { build_context.is_dll = false; @@ -1112,7 +1112,7 @@ int main(int arg_count, char **arg_ptr) { if (0) { #ifdef GB_SYSTEM_UNIX } else if (selected_target_metrics->metrics == &target_essence_amd64) { - system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s", + system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s", LIT(output_base), LIT(output_base), LIT(build_context.link_flags)); #endif } else { @@ -1239,10 +1239,7 @@ int main(int arg_count, char **arg_ptr) { // This allows you to specify '-f' in a #foreign_system_library, // without having to implement any new syntax specifically for MacOS. #if defined(GB_SYSTEM_OSX) - if (lib.len > 2 && lib[0] == '-' && lib[1] == 'f') { - // framework thingie - lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", (int)(lib.len) - 2, lib.text + 2); - } else if (string_ends_with(lib, str_lit(".framework"))) { + if (string_ends_with(lib, str_lit(".framework"))) { // framework thingie String lib_name = lib; lib_name = remove_extension_from_path(lib_name); @@ -1251,8 +1248,7 @@ int main(int arg_count, char **arg_ptr) { // static libs, absolute full path relative to the file in which the lib was imported from lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); } else if (string_ends_with(lib, str_lit(".dylib"))) { - // dynamic lib, relative path to executable - // lib_str = gb_string_append_fmt(lib_str, " -l:%s/%.*s ", cwd, LIT(lib)); + // dynamic lib lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); } else { // dynamic or static system lib, just link regularly searching system library paths diff --git a/src/parser.cpp b/src/parser.cpp index 025a181ba..f69efc0ce 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3970,34 +3970,6 @@ Ast *parse_stmt(AstFile *f) { return s; } - // case Token_static: { - // CommentGroup *docs = f->lead_comment; - // Token token = expect_token(f, Token_static); - - // Ast *decl = nullptr; - // Array list = parse_lhs_expr_list(f); - // if (list.count == 0) { - // syntax_error(token, "Illegal use of 'static' statement"); - // expect_semicolon(f, nullptr); - // return ast_bad_stmt(f, token, f->curr_token); - // } - - // expect_token_after(f, Token_Colon, "identifier list"); - // decl = parse_value_decl(f, list, docs); - - // if (decl != nullptr && decl->kind == Ast_ValueDecl) { - // if (decl->ValueDecl.is_mutable) { - // decl->ValueDecl.is_static = true; - // } else { - // error(token, "'static' may only be currently used with variable declaration"); - // } - // return decl; - // } - - // syntax_error(token, "Illegal use of 'static' statement"); - // return ast_bad_stmt(f, token, f->curr_token); - // } break; - case Token_using: { CommentGroup *docs = f->lead_comment; Token token = expect_token(f, Token_using); @@ -4071,12 +4043,10 @@ Ast *parse_stmt(AstFile *f) { } else if (tag == "assert") { Ast *t = ast_basic_directive(f, hash_token, tag); return ast_expr_stmt(f, parse_call_expr(f, t)); - } /* else if (name.string == "no_deferred") { - s = parse_stmt(f); - s->stmt_state_flags |= StmtStateFlag_no_deferred; - } */ - - if (tag == "include") { + } else if (tag == "panic") { + Ast *t = ast_basic_directive(f, hash_token, tag); + return ast_expr_stmt(f, parse_call_expr(f, t)); + } else if (tag == "include") { syntax_error(token, "#include is not a valid import declaration kind. Did you mean 'import'?"); s = ast_bad_stmt(f, token, f->curr_token); } else { diff --git a/src/types.cpp b/src/types.cpp index d8a579510..8ad352f62 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -113,21 +113,22 @@ struct BasicType { struct TypeStruct { Array fields; Array tags; - Ast *node; - Scope * scope; + Array offsets; + Ast * node; + Scope * scope; - Array offsets; - bool are_offsets_set; - bool are_offsets_being_processed; - bool is_packed; - bool is_raw_union; - bool is_polymorphic; - bool is_poly_specialized; Type * polymorphic_params; // Type_Tuple Type * polymorphic_parent; - i64 custom_align; // NOTE(bill): Only used in structs at the moment + i64 custom_align; Entity * names; + + bool are_offsets_set; + bool are_offsets_being_processed; + bool is_packed; + bool is_raw_union; + bool is_polymorphic; + bool is_poly_specialized; }; struct TypeUnion { @@ -137,12 +138,11 @@ struct TypeUnion { i64 variant_block_size; i64 custom_align; i64 tag_size; + Type * polymorphic_params; // Type_Tuple + Type * polymorphic_parent; bool no_nil; - - bool is_polymorphic; - bool is_poly_specialized; - Type * polymorphic_params; // Type_Tuple - Type * polymorphic_parent; + bool is_polymorphic; + bool is_poly_specialized; }; #define TYPE_KINDS \ @@ -190,7 +190,9 @@ struct TypeUnion { TYPE_KIND(Tuple, struct { \ Array variables; /* Entity_Variable */ \ Array offsets; \ + bool are_offsets_being_processed; \ bool are_offsets_set; \ + bool is_packed; \ }) \ TYPE_KIND(Proc, struct { \ Ast *node; \ @@ -201,9 +203,8 @@ struct TypeUnion { i32 result_count; \ Array abi_compat_params; \ Type * abi_compat_result_type; \ - bool return_by_pointer; \ - bool variadic; \ i32 variadic_index; \ + bool variadic; \ bool require_results; \ bool c_vararg; \ bool is_polymorphic; \ @@ -211,6 +212,7 @@ struct TypeUnion { bool has_proc_default_values; \ bool has_named_results; \ bool diverging; /* no return */ \ + bool return_by_pointer; \ u64 tags; \ isize specialization_count; \ ProcCallingConvention calling_convention; \ @@ -1782,7 +1784,8 @@ bool are_types_identical(Type *x, Type *y) { case Type_Tuple: if (y->kind == Type_Tuple) { - if (x->Tuple.variables.count == y->Tuple.variables.count) { + if (x->Tuple.variables.count == y->Tuple.variables.count && + x->Tuple.is_packed == y->Tuple.is_packed) { for_array(i, x->Tuple.variables) { Entity *xe = x->Tuple.variables[i]; Entity *ye = y->Tuple.variables[i]; @@ -2231,19 +2234,22 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty if (type->Array.count <= 4) { // HACK(bill): Memory leak switch (type->Array.count) { - #define _ARRAY_FIELD_CASE(_length, _name) \ - case (_length): \ - if (field_name == _name) { \ + #define _ARRAY_FIELD_CASE_IF(_length, _name) \ + if (field_name == (_name)) { \ selection_add_index(&sel, (_length)-1); \ sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \ return sel; \ - } \ + } + #define _ARRAY_FIELD_CASE(_length, _name0, _name1) \ + case (_length): \ + _ARRAY_FIELD_CASE_IF(_length, _name0); \ + _ARRAY_FIELD_CASE_IF(_length, _name1); \ /*fallthrough*/ - _ARRAY_FIELD_CASE(4, "w"); - _ARRAY_FIELD_CASE(3, "z"); - _ARRAY_FIELD_CASE(2, "y"); - _ARRAY_FIELD_CASE(1, "x"); + _ARRAY_FIELD_CASE(4, "w", "a"); + _ARRAY_FIELD_CASE(3, "z", "b"); + _ARRAY_FIELD_CASE(2, "y", "g"); + _ARRAY_FIELD_CASE(1, "x", "r"); default: break; #undef _ARRAY_FIELD_CASE @@ -2590,9 +2596,9 @@ bool type_set_offsets(Type *t) { } } else if (is_type_tuple(t)) { if (!t->Tuple.are_offsets_set) { - t->Struct.are_offsets_being_processed = true; - t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, false, false); - t->Struct.are_offsets_being_processed = false; + t->Tuple.are_offsets_being_processed = true; + t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false); + t->Tuple.are_offsets_being_processed = false; t->Tuple.are_offsets_set = true; return true; } From 03053a18ce78e567cf1ee596c4975e69790d3def Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 13 Oct 2019 12:51:47 +0100 Subject: [PATCH 100/143] Fix IR generation bug for nested foreign procedure declaration --- src/ir.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 017a12025..0bf706f67 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8265,24 +8265,27 @@ void ir_build_constant_value_decl(irProcedure *proc, AstValueDecl *vd) { name = e->Procedure.link_name; } + HashKey key = hash_string(name); + irValue **prev_value = map_get(&proc->module->members, key); + if (prev_value != nullptr) { + // NOTE(bill): Don't do mutliple declarations in the IR + return; + } + + irValue *value = ir_value_procedure(proc->module, e, e->type, pl->type, pl->body, name); value->Proc.tags = pl->tags; value->Proc.inlining = pl->inlining; - ir_module_add_value(proc->module, e, value); - ir_build_proc(value, proc); - if (value->Proc.is_foreign || value->Proc.is_export) { - HashKey key = hash_string(name); - irValue **prev_value = map_get(&proc->module->members, key); - if (prev_value == nullptr) { - // NOTE(bill): Don't do mutliple declarations in the IR - map_set(&proc->module->members, key, value); - } + map_set(&proc->module->members, key, value); } else { array_add(&proc->children, &value->Proc); } + + ir_module_add_value(proc->module, e, value); + ir_build_proc(value, proc); } } } From 45683703ea6cc0578796c891b50bad1c75ecc687 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 13 Oct 2019 14:29:56 +0100 Subject: [PATCH 101/143] Fix System V for certain structs --- src/check_type.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index 4d107a9ac..f366c42d1 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1968,10 +1968,11 @@ Type *handle_single_distributed_type_parameter(Array const &types, bool switch (sz) { case 0: GB_PANIC("Zero sized type found!"); - case 1: - case 2: - case 4: - case 8: + case 1: return t_u8; + case 2: return t_u16; + case 4: return t_u32; + case 8: return t_u64; + default: return types[0]; } return t_u64; @@ -2005,6 +2006,12 @@ Type *handle_single_distributed_type_parameter(Array const &types, bool } } if (offset) *offset = i; + switch (total_size) { + case 1: return t_u8; + case 2: return t_u16; + case 4: return t_u32; + case 8: return t_u64; + } return t_u64; } @@ -2094,7 +2101,13 @@ Type *handle_struct_system_v_amd64_abi_type(Type *t) { i64 otsz = type_size_of(original_type); if (ftsz != otsz) { // TODO(bill): Handle this case which will be caused by #packed most likely - GB_PANIC("Incorrectly handled case for handle_struct_system_v_amd64_abi_type, %lld vs %lld", ftsz, otsz); + switch (otsz) { + case 1: + case 2: + case 4: + case 8: + GB_PANIC("Incorrectly handled case for handle_struct_system_v_amd64_abi_type, %s %lld vs %s %lld", type_to_string(final_type), ftsz, type_to_string(original_type), otsz); + } } return final_type; From b53fe14c22fe2e7063979353735ca0aa5b0e2605 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 13 Oct 2019 16:06:41 +0100 Subject: [PATCH 102/143] Change `error` to `syntax_error` in parser --- src/check_type.cpp | 1 - src/parser.cpp | 56 +++++++++++++++++++++++----------------------- src/tokenizer.cpp | 9 ++++++++ 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/src/check_type.cpp b/src/check_type.cpp index f366c42d1..da6419877 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1975,7 +1975,6 @@ Type *handle_single_distributed_type_parameter(Array const &types, bool default: return types[0]; } - return t_u64; } else if (types.count >= 2) { if (types[0] == t_f32 && types[1] == t_f32) { if (offset) *offset = 2; diff --git a/src/parser.cpp b/src/parser.cpp index f69efc0ce..7f866922a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -427,7 +427,7 @@ void syntax_error(Ast *node, char *fmt, ...) { bool ast_node_expect(Ast *node, AstKind kind) { if (node->kind != kind) { - error(node, "Expected %.*s, got %.*s", LIT(ast_strings[kind]), LIT(ast_strings[node->kind])); + syntax_error(node, "Expected %.*s, got %.*s", LIT(ast_strings[kind]), LIT(ast_strings[node->kind])); return false; } return true; @@ -1662,7 +1662,7 @@ void check_polymorphic_params_for_type(AstFile *f, Ast *polymorphic_params, Toke for_array(i, field->Field.names) { Ast *name = field->Field.names[i]; if (name->kind == Ast_PolyType) { - error(name, "Polymorphic names are not needed for %.*s parameters", LIT(token.string)); + syntax_error(name, "Polymorphic names are not needed for %.*s parameters", LIT(token.string)); return; // TODO(bill): Err multiple times or just the once? } } @@ -4207,7 +4207,7 @@ void parser_add_package(Parser *p, AstPackage *pkg) { if (found) { GB_ASSERT(pkg->files.count > 0); AstFile *f = pkg->files[0]; - error(f->package_token, "Non-unique package name '%.*s'", LIT(pkg->name)); + syntax_error(f->package_token, "Non-unique package name '%.*s'", LIT(pkg->name)); GB_ASSERT((*found)->files.count > 0); TokenPos pos = (*found)->files[0]->package_token.pos; error_line("\tpreviously declared at %.*s(%td:%td)\n", LIT(pos.file), pos.line, pos.column); @@ -4283,22 +4283,22 @@ bool try_add_import_path(Parser *p, String const &path, String const &rel_path, switch (rd_err) { case ReadDirectory_InvalidPath: - error(pos, "Invalid path: %.*s", LIT(rel_path)); + syntax_error(pos, "Invalid path: %.*s", LIT(rel_path)); return false; case ReadDirectory_NotExists: - error(pos, "Path does not exist: %.*s", LIT(rel_path)); + syntax_error(pos, "Path does not exist: %.*s", LIT(rel_path)); return false; case ReadDirectory_Permission: - error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path)); + syntax_error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path)); return false; case ReadDirectory_NotDir: - error(pos, "Expected a directory for a package, got a file: %.*s", LIT(rel_path)); + syntax_error(pos, "Expected a directory for a package, got a file: %.*s", LIT(rel_path)); return false; case ReadDirectory_Empty: - error(pos, "Empty directory: %.*s", LIT(rel_path)); + syntax_error(pos, "Empty directory: %.*s", LIT(rel_path)); return false; case ReadDirectory_Unknown: - error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path)); + syntax_error(pos, "Unknown error whilst reading path %.*s", LIT(rel_path)); return false; } @@ -4400,7 +4400,7 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir, String file_str = {}; if (colon_pos == 0) { - error(node, "Expected a collection name"); + syntax_error(node, "Expected a collection name"); return false; } @@ -4415,11 +4415,11 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir, if (has_windows_drive) { String sub_file_path = substring(file_str, 3, file_str.len); if (!is_import_path_valid(sub_file_path)) { - error(node, "Invalid import path: '%.*s'", LIT(file_str)); + syntax_error(node, "Invalid import path: '%.*s'", LIT(file_str)); return false; } } else if (!is_import_path_valid(file_str)) { - error(node, "Invalid import path: '%.*s'", LIT(file_str)); + syntax_error(node, "Invalid import path: '%.*s'", LIT(file_str)); return false; } @@ -4427,7 +4427,7 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir, if (collection_name.len > 0) { if (collection_name == "system") { if (node->kind != Ast_ForeignImportDecl) { - error(node, "The library collection 'system' is restrict for 'foreign_library'"); + syntax_error(node, "The library collection 'system' is restrict for 'foreign_library'"); return false; } else { *path = file_str; @@ -4435,7 +4435,7 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir, } } else if (!find_library_collection_path(collection_name, &base_dir)) { // NOTE(bill): It's a naughty name - error(node, "Unknown library collection: '%.*s'", LIT(collection_name)); + syntax_error(node, "Unknown library collection: '%.*s'", LIT(collection_name)); return false; } } else { @@ -4556,7 +4556,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array array_add(&fl->fullpaths, fullpath); } if (fl->fullpaths.count == 0) { - error(decls[i], "No foreign paths found"); + syntax_error(decls[i], "No foreign paths found"); decls[i] = ast_bad_decl(f, fl->filepaths[0], fl->filepaths[fl->filepaths.count-1]); goto end; } @@ -4605,7 +4605,7 @@ bool parse_build_tag(Token token_for_pos, String s) { is_notted = true; p = substring(p, 1, p.len); if (p.len == 0) { - error(token_for_pos, "Expected a build platform after '!'"); + syntax_error(token_for_pos, "Expected a build platform after '!'"); break; } } @@ -4634,7 +4634,7 @@ bool parse_build_tag(Token token_for_pos, String s) { } } if (os == TargetOs_Invalid && arch == TargetArch_Invalid) { - error(token_for_pos, "Invalid build tag platform: %.*s", LIT(p)); + syntax_error(token_for_pos, "Invalid build tag platform: %.*s", LIT(p)); break; } } @@ -4680,11 +4680,11 @@ bool parse_file(Parser *p, AstFile *f) { Token package_name = expect_token_after(f, Token_Ident, "package"); if (package_name.kind == Token_Ident) { if (package_name.string == "_") { - error(package_name, "Invalid package name '_'"); + syntax_error(package_name, "Invalid package name '_'"); } else if (f->pkg->kind != Package_Runtime && package_name.string == "runtime") { - error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string)); + syntax_error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string)); } else if (is_package_name_reserved(package_name.string)) { - error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string)); + syntax_error(package_name, "Use of reserved package name '%.*s'", LIT(package_name.string)); } } f->package_name = package_name.string; @@ -4751,28 +4751,28 @@ ParseFileError process_imported_file(Parser *p, ImportedFile const &imported_fil if (err != ParseFile_None) { if (err == ParseFile_EmptyFile) { if (fi->fullpath == p->init_fullpath) { - error(pos, "Initial file is empty - %.*s\n", LIT(p->init_fullpath)); + syntax_error(pos, "Initial file is empty - %.*s\n", LIT(p->init_fullpath)); gb_exit(1); } } else { switch (err) { case ParseFile_WrongExtension: - error(pos, "Failed to parse file: %.*s; invalid file extension: File must have the extension '.odin'", LIT(fi->name)); + syntax_error(pos, "Failed to parse file: %.*s; invalid file extension: File must have the extension '.odin'", LIT(fi->name)); break; case ParseFile_InvalidFile: - error(pos, "Failed to parse file: %.*s; invalid file or cannot be found", LIT(fi->name)); + syntax_error(pos, "Failed to parse file: %.*s; invalid file or cannot be found", LIT(fi->name)); break; case ParseFile_Permission: - error(pos, "Failed to parse file: %.*s; file permissions problem", LIT(fi->name)); + syntax_error(pos, "Failed to parse file: %.*s; file permissions problem", LIT(fi->name)); break; case ParseFile_NotFound: - error(pos, "Failed to parse file: %.*s; file cannot be found ('%.*s')", LIT(fi->name), LIT(fi->fullpath)); + syntax_error(pos, "Failed to parse file: %.*s; file cannot be found ('%.*s')", LIT(fi->name), LIT(fi->fullpath)); break; case ParseFile_InvalidToken: - error(err_pos, "Failed to parse file: %.*s; invalid token found in file", LIT(fi->name)); + syntax_error(err_pos, "Failed to parse file: %.*s; invalid token found in file", LIT(fi->name)); break; case ParseFile_EmptyFile: - error(pos, "Failed to parse file: %.*s; file contains no tokens", LIT(fi->name)); + syntax_error(pos, "Failed to parse file: %.*s; file contains no tokens", LIT(fi->name)); break; } @@ -4789,7 +4789,7 @@ ParseFileError process_imported_file(Parser *p, ImportedFile const &imported_fil if (pkg->name.len == 0) { pkg->name = file->package_name; } else if (file->tokens.count > 0 && pkg->name != file->package_name) { - error(file->package_token, "Different package name, expected '%.*s', got '%.*s'", LIT(pkg->name), LIT(file->package_name)); + syntax_error(file->package_token, "Different package name, expected '%.*s', got '%.*s'", LIT(pkg->name), LIT(file->package_name)); } p->total_line_count += file->tokenizer.line_count; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index d5e04aa1e..4b0db7ac4 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -401,6 +401,15 @@ void syntax_error(Token token, char *fmt, ...) { va_end(va); } +void syntax_error(TokenPos pos, char *fmt, ...) { + va_list va; + va_start(va, fmt); + Token token = {}; + token.pos = pos; + syntax_error_va(token, fmt, va); + va_end(va); +} + void syntax_warning(Token token, char *fmt, ...) { va_list va; va_start(va, fmt); From eaabb888d4e24ebcaccd1ae6c57f7dc8d762bd02 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 15 Oct 2019 17:42:55 +0100 Subject: [PATCH 103/143] Update Odin Logo --- misc/logo-slim.png | Bin 73988 -> 76402 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/misc/logo-slim.png b/misc/logo-slim.png index 6e33dc6b884ad5e57d20842ec2c219f185c4a20c..ed9b6061eb2080ccb6bebb3975421fb2e84b9141 100644 GIT binary patch literal 76402 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
+A;s?0nsAq_tN>PT8S7 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 # The Odin Programming Language From 1416946757af20b530899962033b5c0ebb69dfa2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 23 Oct 2019 21:42:28 +0100 Subject: [PATCH 115/143] Add token.odin --- core/odin/tokenizer/token.odin | 335 +++++++++++++++++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 core/odin/tokenizer/token.odin diff --git a/core/odin/tokenizer/token.odin b/core/odin/tokenizer/token.odin new file mode 100644 index 000000000..d692da5d9 --- /dev/null +++ b/core/odin/tokenizer/token.odin @@ -0,0 +1,335 @@ +package odin_tokenizer + +import "core:strings" + +Token :: struct { + kind: Token_Kind, + text: string, + pos: Pos, +} + +Pos :: struct { + file: string, + offset: int, // starting at 0 + line: int, // starting at 1 + column: int, // starting at 1 +} + +pos_compare :: proc(lhs, rhs: Pos) -> int { + if lhs.offset != rhs.offset { + return (lhs.offset < rhs.offset) ? -1 : +1; + } + if lhs.line != rhs.line { + return (lhs.line < rhs.line) ? -1 : +1; + } + if lhs.column != rhs.column { + return (lhs.column < rhs.column) ? -1 : +1; + } + return strings.compare(lhs.file, rhs.file); +} + +Token_Kind :: enum u32 { + Invalid, + EOF, + Comment, + + B_Literal_Begin, + Ident, + Integer, + Float, + Imag, + Rune, + String, + B_Literal_End, + + B_Operator_Begin, + Eq, + Not, + Hash, + At, + Dollar, + Pointer, + Question, + Add, + Sub, + Mul, + Quo, + Mod, + Mod_Mod, + And, + Or, + Xor, + And_Not, + Shl, + Shr, + + Cmp_And, + Cmp_Or, + + B_Assign_Op_Begin, + Add_Eq, + Sub_Eq, + Mul_Eq, + Quo_Eq, + Mod_Eq, + Mod_Mod_Eq, + And_Eq, + Or_Eq, + Xor_Eq, + And_Not_Eq, + Shl_Eq, + Shr_Eq, + Cmp_And_Eq, + Cmp_Or_Eq, + B_Assign_Op_End, + + Arrow_Right, + Arrow_Left, + Double_Arrow_Right, + Undef, + + B_Comparison_Begin, + Cmp_Eq, + Not_Eq, + Lt, + Gt, + Lt_Eq, + Gt_Eq, + B_Comparison_End, + + Open_Paren, + Close_Paren, + Open_Bracket, + Close_Bracket, + Open_Brace, + Close_Brace, + Colon, + Semicolon, + Period, + Comma, + Ellipsis, + Range_Half, + Back_Slash, + B_Operator_End, + + B_Keyword_Begin, + Import, + Foreign, + Package, + Typeid, + When, + Where, + If, + Else, + For, + Switch, + In, + Notin, + Do, + Case, + Break, + Continue, + Fallthrough, + Defer, + Return, + Proc, + Macro, + Struct, + Union, + Enum, + Bit_Field, + Bit_Set, + Map, + Dynamic, + Auto_Cast, + Cast, + Transmute, + Distinct, + Opaque, + Using, + Inline, + No_Inline, + Context, + Size_Of, + Align_Of, + Offset_Of, + Type_Of, + Const, + B_Keyword_End, + + COUNT, + + B_Custom_Keyword_Begin = COUNT+1, + // ... Custom keywords +}; + +tokens := [Token_Kind.COUNT]string { + "Invalid", + "EOF", + "Comment", + + "", + "identifier", + "integer", + "float", + "imaginary", + "rune", + "string", + "", + + "", + "=", + "!", + "#", + "@", + "$", + "^", + "?", + "+", + "-", + "*", + "/", + "%", + "%%", + "&", + "|", + "~", + "&~", + "<<", + ">>", + + "&&", + "||", + + "", + "+=", + "-=", + "*=", + "/=", + "%=", + "%%=", + "&=", + "|=", + "~=", + "&~=", + "<<=", + ">>=", + "&&=", + "||=", + "", + + "->", + "<-", + "=>", + "---", + + "", + "==", + "!=", + "<", + ">", + "<=", + ">=", + "", + + "(", + ")", + "[", + "]", + "{", + "}", + ":", + ";", + ".", + ",", + "..", + "..<", + "\\", + "", + + "", + "import", + "foreign", + "package", + "typeid", + "when", + "where", + "if", + "else", + "for", + "switch", + "in", + "notin", + "do", + "case", + "break", + "continue", + "fallthrough", + "defer", + "return", + "proc", + "macro", + "struct", + "union", + "enum", + "bit_field", + "bit_set", + "map", + "dynamic", + "auto_cast", + "cast", + "transmute", + "distinct", + "opaque", + "using", + "inline", + "no_inline", + "context", + "size_of", + "align_of", + "offset_of", + "type_of", + "const", + "", +}; + +custom_keyword_tokens: []string; + +to_string :: proc(kind: Token_Kind) -> string { + if Token_Kind.Invalid <= kind && kind < Token_Kind.COUNT { + return tokens[kind]; + } + if Token_Kind.B_Custom_Keyword_Begin < kind { + n := int(u16(kind)-u16(Token_Kind.B_Custom_Keyword_Begin)); + if n < len(custom_keyword_tokens) { + return custom_keyword_tokens[n]; + } + } + + return "Invalid"; +} + +is_literal :: proc(kind: Token_Kind) -> bool { + return Token_Kind.B_Literal_Begin < kind && kind < Token_Kind.B_Literal_End; +} +is_operator :: proc(kind: Token_Kind) -> bool { + switch kind { + case .B_Operator_Begin .. .B_Operator_End: + return true; + case .In, .Notin: + return true; + } + return false; +} +is_assignment_operator :: proc(kind: Token_Kind) -> bool { + return Token_Kind.B_Assign_Op_Begin < kind && kind < Token_Kind.B_Assign_Op_End || kind == Token_Kind.Eq; +} +is_keyword :: proc(kind: Token_Kind) -> bool { + switch { + case Token_Kind.B_Keyword_Begin < kind && kind < Token_Kind.B_Keyword_End: + return true; + case Token_Kind.B_Custom_Keyword_Begin < kind: + return true; + } + return false; +} From 7140f4291546748adf2ddb977f3605f7aab31856 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 23 Oct 2019 21:43:13 +0100 Subject: [PATCH 116/143] Modify runtime to reduce dependencies on other packages --- core/runtime/core.odin | 66 +++++++++++++---------- core/runtime/internal.odin | 106 ++++++++++++++++++++++++++++++++++--- src/checker.cpp | 1 + 3 files changed, 140 insertions(+), 33 deletions(-) diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 9ad5d3d8a..7ba98ae30 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -237,7 +237,22 @@ global_scratch_allocator_data: mem.Scratch_Allocator; +Raw_Slice :: struct { + data: rawptr, + len: int, +} +Raw_Dynamic_Array :: struct { + data: rawptr, + len: int, + cap: int, + allocator: mem.Allocator, +} + +Raw_Map :: struct { + hashes: []int, + entries: Raw_Dynamic_Array, +} INITIAL_MAP_CAP :: 16; @@ -261,7 +276,7 @@ Map_Entry_Header :: struct { } Map_Header :: struct { - m: ^mem.Raw_Map, + m: ^Raw_Map, is_key_string: bool, entry_size: int, @@ -394,7 +409,7 @@ default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code @builtin copy :: proc "contextless" (dst, src: $T/[]$E) -> int { n := max(0, min(len(dst), len(src))); - if n > 0 do mem.copy(&dst[0], &src[0], n*size_of(E)); + if n > 0 do mem_copy(&dst[0], &src[0], n*size_of(E)); return n; } @@ -405,7 +420,7 @@ pop :: proc "contextless" (array: ^$T/[dynamic]$E) -> E { if array == nil do return E{}; assert(len(array) > 0); res := array[len(array)-1]; - (^mem.Raw_Dynamic_Array)(array).len -= 1; + (^Raw_Dynamic_Array)(array).len -= 1; return res; } @@ -469,14 +484,11 @@ make :: proc{ mem.make_map, }; - - - @builtin clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) { if m == nil do return; - raw_map := (^mem.Raw_Map)(m); - entries := (^mem.Raw_Dynamic_Array)(&raw_map.entries); + raw_map := (^Raw_Map)(m); + entries := (^Raw_Dynamic_Array)(&raw_map.entries); entries.len = 0; for _, i in raw_map.hashes { raw_map.hashes[i] = -1; @@ -507,11 +519,11 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) { } arg_len = min(cap(array)-len(array), arg_len); if arg_len > 0 { - a := (^mem.Raw_Dynamic_Array)(array); + a := (^Raw_Dynamic_Array)(array); data := (^E)(a.data); assert(data != nil); val := arg; - mem.copy(mem.ptr_offset(data, a.len), &val, size_of(E)); + mem_copy(mem.ptr_offset(data, a.len), &val, size_of(E)); a.len += arg_len; } } @@ -529,10 +541,10 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) } arg_len = min(cap(array)-len(array), arg_len); if arg_len > 0 { - a := (^mem.Raw_Dynamic_Array)(array); + a := (^Raw_Dynamic_Array)(array); data := (^E)(a.data); assert(data != nil); - mem.copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len); + mem_copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len); a.len += arg_len; } } @@ -549,13 +561,13 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_ @builtin clear_dynamic_array :: inline proc "contextless" (array: ^$T/[dynamic]$E) { - if array != nil do (^mem.Raw_Dynamic_Array)(array).len = 0; + if array != nil do (^Raw_Dynamic_Array)(array).len = 0; } @builtin reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool { if array == nil do return false; - a := (^mem.Raw_Dynamic_Array)(array); + a := (^Raw_Dynamic_Array)(array); if capacity <= a.cap do return true; @@ -582,7 +594,7 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal @builtin resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> bool { if array == nil do return false; - a := (^mem.Raw_Dynamic_Array)(array); + a := (^Raw_Dynamic_Array)(array); if length <= a.cap { a.len = max(length, 0); @@ -722,7 +734,7 @@ unreachable :: proc(message := "", loc := #caller_location) -> ! { __dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int, loc := #caller_location) { - array := (^mem.Raw_Dynamic_Array)(array_); + array := (^Raw_Dynamic_Array)(array_); array.allocator = context.allocator; assert(array.allocator.procedure != nil); @@ -733,7 +745,7 @@ __dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, ca } __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int, loc := #caller_location) -> bool { - array := (^mem.Raw_Dynamic_Array)(array_); + array := (^Raw_Dynamic_Array)(array_); if cap <= array.cap do return true; @@ -755,7 +767,7 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: } __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int, loc := #caller_location) -> bool { - array := (^mem.Raw_Dynamic_Array)(array_); + array := (^Raw_Dynamic_Array)(array_); ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc); if ok do array.len = len; @@ -765,7 +777,7 @@ __dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int, items: rawptr, item_count: int, loc := #caller_location) -> int { - array := (^mem.Raw_Dynamic_Array)(array_); + array := (^Raw_Dynamic_Array)(array_); if items == nil do return 0; if item_count <= 0 do return 0; @@ -782,13 +794,13 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int, assert(array.data != nil); data := uintptr(array.data) + uintptr(elem_size*array.len); - mem.copy(rawptr(data), items, elem_size * item_count); + mem_copy(rawptr(data), items, elem_size * item_count); array.len += item_count; return array.len; } __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int, loc := #caller_location) -> int { - array := (^mem.Raw_Dynamic_Array)(array_); + array := (^Raw_Dynamic_Array)(array_); ok := true; if array.cap <= array.len+1 { @@ -811,7 +823,7 @@ __dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: in // Map __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { - header := Map_Header{m = (^mem.Raw_Map)(m)}; + header := Map_Header{m = (^Raw_Map)(m)}; Entry :: struct { key: Map_Key, next: int, @@ -885,7 +897,7 @@ source_code_location_hash :: proc(s: Source_Code_Location) -> u64 { __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: mem.Allocator, loc := #caller_location) -> bool { - array := (^mem.Raw_Slice)(array_); + array := (^Raw_Slice)(array_); if new_count < array.len do return true; @@ -911,7 +923,7 @@ __dynamic_map_reserve :: proc(using header: Map_Header, cap: int, loc := #caller } __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) #no_bounds_check { new_header: Map_Header = header; - nm := mem.Raw_Map{}; + nm := Raw_Map{}; nm.entries.allocator = m.entries.allocator; new_header.m = &nm; @@ -943,7 +955,7 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #c e := __dynamic_map_get_entry(new_header, j); e.next = fr.entry_index; ndata := uintptr(e); - mem.copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size); + mem_copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size); if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header, loc); } @@ -986,7 +998,7 @@ __dynamic_map_set :: proc(h: Map_Header, key: Map_Key, value: rawptr, loc := #ca e := __dynamic_map_get_entry(h, index); e.key = key; val := (^byte)(uintptr(e) + h.value_offset); - mem.copy(val, value, h.value_size); + mem_copy(val, value, h.value_size); } if __dynamic_map_full(h) { @@ -1065,7 +1077,7 @@ __dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds } else { old := __dynamic_map_get_entry(h, fr.entry_index); end := __dynamic_map_get_entry(h, m.entries.len-1); - mem.copy(old, end, entry_size); + mem_copy(old, end, entry_size); if last := __dynamic_map_find(h, old.key); last.entry_prev >= 0 { last_entry := __dynamic_map_get_entry(h, last.entry_prev); diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index a5099944b..630942805 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -1,9 +1,22 @@ package runtime -import "core:mem" import "core:os" -import "core:unicode/utf8" +mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr { + if src == nil do return dst; + // NOTE(bill): This _must_ be implemented like C's memmove + foreign _ { + when size_of(rawptr) == 8 { + @(link_name="llvm.memmove.p0i8.p0i8.i64") + llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---; + } else { + @(link_name="llvm.memmove.p0i8.p0i8.i32") + llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---; + } + } + llvm_memmove(dst, src, len, 1, false); + return dst; +} print_u64 :: proc(fd: os.Handle, x: u64) { digits := "0123456789"; @@ -336,17 +349,22 @@ string_ge :: inline proc "contextless" (a, b: string) -> bool { return string_cm cstring_len :: proc "contextless" (s: cstring) -> int { n := 0; - for p := (^byte)(s); p != nil && p^ != 0; p = mem.ptr_offset(p, 1) { - n += 1; + p := uintptr((^byte)(s)); + for p != 0 && (^byte)(p)^ != 0 { + p += 1; } return n; } cstring_to_string :: proc "contextless" (s: cstring) -> string { + Raw_String :: struct { + data: ^byte, + len: int, + }; if s == nil do return ""; ptr := (^byte)(s); n := cstring_len(s); - return transmute(string)mem.Raw_String{ptr, n}; + return transmute(string)Raw_String{ptr, n}; } @@ -435,8 +453,84 @@ type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column handle_error(file, line, column, from, to); } + string_decode_rune :: inline proc "contextless" (s: string) -> (rune, int) { - return utf8.decode_rune_in_string(s); + // NOTE(bill): Duplicated here to remove dependency on package unicode/utf8 + + @static accept_sizes := [256]u8{ + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f + + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf + 0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf + 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef + 0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff + }; + Accept_Range :: struct {lo, hi: u8}; + + @static accept_ranges := [5]Accept_Range{ + {0x80, 0xbf}, + {0xa0, 0xbf}, + {0x80, 0x9f}, + {0x90, 0xbf}, + {0x80, 0x8f}, + }; + + MASKX :: 0b0011_1111; + MASK2 :: 0b0001_1111; + MASK3 :: 0b0000_1111; + MASK4 :: 0b0000_0111; + + LOCB :: 0b1000_0000; + HICB :: 0b1011_1111; + + + RUNE_ERROR :: '\ufffd'; + + n := len(s); + if n < 1 { + return RUNE_ERROR, 0; + } + s0 := s[0]; + x := accept_sizes[s0]; + if x >= 0xF0 { + mask := rune(x) << 31 >> 31; // NOTE(bill): Create 0x0000 or 0xffff. + return rune(s[0])&~mask | RUNE_ERROR&mask, 1; + } + sz := x & 7; + accept := accept_ranges[x>>4]; + if n < int(sz) { + return RUNE_ERROR, 1; + } + b1 := s[1]; + if b1 < accept.lo || accept.hi < b1 { + return RUNE_ERROR, 1; + } + if sz == 2 { + return rune(s0&MASK2)<<6 | rune(b1&MASKX), 2; + } + b2 := s[2]; + if b2 < LOCB || HICB < b2 { + return RUNE_ERROR, 1; + } + if sz == 3 { + return rune(s0&MASK3)<<12 | rune(b1&MASKX)<<6 | rune(b2&MASKX), 3; + } + b3 := s[3]; + if b3 < LOCB || HICB < b3 { + return RUNE_ERROR, 1; + } + return rune(s0&MASK4)<<18 | rune(b1&MASKX)<<12 | rune(b2&MASKX)<<6 | rune(b3&MASKX), 4; } bounds_check_error_loc :: inline proc "contextless" (using loc := #caller_location, index, count: int) { diff --git a/src/checker.cpp b/src/checker.cpp index 8ce9d8ec2..e7b347f1a 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1628,6 +1628,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("mul_quaternion256"), str_lit("quo_quaternion128"), str_lit("quo_quaternion256"), + str_lit("cstring_to_string"), str_lit("umodti3"), str_lit("udivti3"), From c60fb10a6a0b668e9dab7e4cb899664f5e32419e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Oct 2019 10:40:17 +0100 Subject: [PATCH 117/143] Move old demos and old stuff to /misc --- {examples => misc}/old_demos/demo001.odin | 0 {examples => misc}/old_demos/demo002.odin | 0 {examples => misc}/old_demos/demo004.odin | 0 {examples => misc}/old_demos/demo005.odin | 0 {examples => misc}/old_demos/demo006.odin | 0 {examples => misc}/old_demos/demo007.odin | 0 {examples => misc}/old_demos/demo008.odin | 0 {examples => misc}/old_demos/old_runtime.odin | 0 {examples => misc}/old_stuff/demo_backup.odin | 0 misc/shell.bat | 4 ++-- 10 files changed, 2 insertions(+), 2 deletions(-) rename {examples => misc}/old_demos/demo001.odin (100%) rename {examples => misc}/old_demos/demo002.odin (100%) rename {examples => misc}/old_demos/demo004.odin (100%) rename {examples => misc}/old_demos/demo005.odin (100%) rename {examples => misc}/old_demos/demo006.odin (100%) rename {examples => misc}/old_demos/demo007.odin (100%) rename {examples => misc}/old_demos/demo008.odin (100%) rename {examples => misc}/old_demos/old_runtime.odin (100%) rename {examples => misc}/old_stuff/demo_backup.odin (100%) diff --git a/examples/old_demos/demo001.odin b/misc/old_demos/demo001.odin similarity index 100% rename from examples/old_demos/demo001.odin rename to misc/old_demos/demo001.odin diff --git a/examples/old_demos/demo002.odin b/misc/old_demos/demo002.odin similarity index 100% rename from examples/old_demos/demo002.odin rename to misc/old_demos/demo002.odin diff --git a/examples/old_demos/demo004.odin b/misc/old_demos/demo004.odin similarity index 100% rename from examples/old_demos/demo004.odin rename to misc/old_demos/demo004.odin diff --git a/examples/old_demos/demo005.odin b/misc/old_demos/demo005.odin similarity index 100% rename from examples/old_demos/demo005.odin rename to misc/old_demos/demo005.odin diff --git a/examples/old_demos/demo006.odin b/misc/old_demos/demo006.odin similarity index 100% rename from examples/old_demos/demo006.odin rename to misc/old_demos/demo006.odin diff --git a/examples/old_demos/demo007.odin b/misc/old_demos/demo007.odin similarity index 100% rename from examples/old_demos/demo007.odin rename to misc/old_demos/demo007.odin diff --git a/examples/old_demos/demo008.odin b/misc/old_demos/demo008.odin similarity index 100% rename from examples/old_demos/demo008.odin rename to misc/old_demos/demo008.odin diff --git a/examples/old_demos/old_runtime.odin b/misc/old_demos/old_runtime.odin similarity index 100% rename from examples/old_demos/old_runtime.odin rename to misc/old_demos/old_runtime.odin diff --git a/examples/old_stuff/demo_backup.odin b/misc/old_stuff/demo_backup.odin similarity index 100% rename from examples/old_stuff/demo_backup.odin rename to misc/old_stuff/demo_backup.odin diff --git a/misc/shell.bat b/misc/shell.bat index 36db84570..85a7949c6 100644 --- a/misc/shell.bat +++ b/misc/shell.bat @@ -1,8 +1,8 @@ @echo off rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x86 1> NUL -call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL -rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL +rem call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" x64 1> NUL +call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 1> NUL rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 1> NUL rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 1> NUL set _NO_DEBUG_HEAP=1 From 1da0668653a4bc800a56629664f4e716c4560fa3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Oct 2019 11:50:01 +0100 Subject: [PATCH 118/143] Add `utf8.rune_index` --- core/unicode/utf8/utf8.odin | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/core/unicode/utf8/utf8.odin b/core/unicode/utf8/utf8.odin index 33cb48e1c..4a4e2f459 100644 --- a/core/unicode/utf8/utf8.odin +++ b/core/unicode/utf8/utf8.odin @@ -167,9 +167,20 @@ decode_last_rune :: proc(s: []u8) -> (rune, int) { return r, size; } +rune_index :: proc(s: string, index: int) -> (r: rune = RUNE_ERROR, ok: bool = false) { + if index < 0 { + return; + } - - + i := 0; + for c in s { + if i == index { + return r, true; + } + i += 1; + } + return; +} valid_rune :: proc(r: rune) -> bool { if r < 0 { From 2c75fe2314aa6de6c8f80d519bbb1812ad77b444 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Oct 2019 11:50:42 +0100 Subject: [PATCH 119/143] Allow for cycles in record polymorphic parameters but not in actualized fields --- src/check_expr.cpp | 78 ++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 195443159..ea9248089 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6127,47 +6127,57 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper defer (array_free(&operands)); bool named_fields = false; + { + // NOTE(bill, 2019-10-26): Allow a cycle in the parameters but not in the fields themselves + auto prev_type_path = c->type_path; + c->type_path = new_checker_type_path(); + defer ({ + destroy_checker_type_path(c->type_path); + c->type_path = prev_type_path; + }); - if (is_call_expr_field_value(ce)) { - named_fields = true; - operands = array_make(heap_allocator(), ce->args.count); - for_array(i, ce->args) { - Ast *arg = ce->args[i]; - ast_node(fv, FieldValue, arg); + if (is_call_expr_field_value(ce)) { + named_fields = true; + operands = array_make(heap_allocator(), ce->args.count); + for_array(i, ce->args) { + Ast *arg = ce->args[i]; + ast_node(fv, FieldValue, arg); - if (fv->field->kind == Ast_Ident) { - String name = fv->field->Ident.token.string; - isize index = lookup_polymorphic_record_parameter(original_type, name); - if (index >= 0) { - TypeTuple *params = get_record_polymorphic_params(original_type); - Entity *e = params->variables[i]; - if (e->kind == Entity_Constant) { - check_expr_with_type_hint(c, &operands[i], fv->value, e->type); + if (fv->field->kind == Ast_Ident) { + String name = fv->field->Ident.token.string; + isize index = lookup_polymorphic_record_parameter(original_type, name); + if (index >= 0) { + TypeTuple *params = get_record_polymorphic_params(original_type); + Entity *e = params->variables[i]; + if (e->kind == Entity_Constant) { + check_expr_with_type_hint(c, &operands[i], fv->value, e->type); + } } + } - + check_expr_or_type(c, &operands[i], fv->value); } - check_expr_or_type(c, &operands[i], fv->value); + + bool vari_expand = (ce->ellipsis.pos.line != 0); + if (vari_expand) { + error(ce->ellipsis, "Invalid use of '..' in a polymorphic type call'"); + } + + } else { + operands = array_make(heap_allocator(), 0, 2*ce->args.count); + + Entity **lhs = nullptr; + isize lhs_count = -1; + + TypeTuple *params = get_record_polymorphic_params(original_type); + if (params != nullptr) { + lhs = params->variables.data; + lhs_count = params->variables.count; + } + + check_unpack_arguments(c, lhs, lhs_count, &operands, ce->args, false, false); } - bool vari_expand = (ce->ellipsis.pos.line != 0); - if (vari_expand) { - error(ce->ellipsis, "Invalid use of '..' in a polymorphic type call'"); - } - - } else { - operands = array_make(heap_allocator(), 0, 2*ce->args.count); - - Entity **lhs = nullptr; - isize lhs_count = -1; - - TypeTuple *params = get_record_polymorphic_params(original_type); - if (params != nullptr) { - lhs = params->variables.data; - lhs_count = params->variables.count; - } - - check_unpack_arguments(c, lhs, lhs_count, &operands, ce->args, false, false); } CallArgumentError err = CallArgumentError_None; From 94879ed14997c4d2745ddb669d08b34437ceff75 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Oct 2019 12:14:04 +0100 Subject: [PATCH 120/143] Fix Compiler assertion when applying `using` to `_` procedure parameter. #451 --- src/check_decl.cpp | 3 +-- src/check_stmt.cpp | 7 +++---- src/entity.cpp | 3 ++- src/ir.cpp | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 5e8479a7f..ebfc29899 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1167,11 +1167,10 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty for_array(i, scope->elements.entries) { Entity *f = scope->elements.entries[i].value; if (f->kind == Entity_Variable) { - Entity *uvar = alloc_entity_using_variable(e, f->token, f->type); + Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr); uvar->Variable.is_immutable = is_immutable; if (is_value) uvar->flags |= EntityFlag_Value; - ProcUsingVar puv = {e, uvar}; array_add(&using_entities, puv); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 26e3f8c26..72913903d 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -496,8 +496,7 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b for_array(i, found->elements.entries) { Entity *f = found->elements.entries[i].value; if (f->kind == Entity_Variable) { - Entity *uvar = alloc_entity_using_variable(e, f->token, f->type); - uvar->using_expr = expr; + Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, expr); Entity *prev = scope_insert(ctx->scope, uvar); if (prev != nullptr) { gbString expr_str = expr_to_string(expr); @@ -2052,7 +2051,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { // TODO(bill): Should a 'continue' happen here? } - for (isize entity_index = 0; entity_index < entity_count; entity_index++) { + for (isize entity_index = 0; entity_index < 1; entity_index++) { Entity *e = entities[entity_index]; if (e == nullptr) { continue; @@ -2071,7 +2070,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { for_array(i, scope->elements.entries) { Entity *f = scope->elements.entries[i].value; if (f->kind == Entity_Variable) { - Entity *uvar = alloc_entity_using_variable(e, f->token, f->type); + Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr); uvar->Variable.is_immutable = is_immutable; Entity *prev = scope_insert(ctx->scope, uvar); if (prev != nullptr) { diff --git a/src/entity.cpp b/src/entity.cpp index 78726171d..bbea68e8b 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -221,12 +221,13 @@ Entity *alloc_entity_variable(Scope *scope, Token token, Type *type, bool is_imm return entity; } -Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type) { +Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type, Ast *using_expr) { GB_ASSERT(parent != nullptr); token.pos = parent->token.pos; Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type); entity->using_parent = parent; entity->parent_proc_decl = parent->parent_proc_decl; + entity->using_expr = using_expr; entity->flags |= EntityFlag_Using; entity->flags |= EntityFlag_Used; entity->state = EntityState_Resolved; diff --git a/src/ir.cpp b/src/ir.cpp index bea9ee8b3..c654e2bf8 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9743,7 +9743,7 @@ void ir_begin_procedure_body(irProcedure *proc) { } Type *abi_type = proc->type->Proc.abi_compat_params[i]; - if (e->token.string != "" && !is_blank_ident(e->token)) { + if (e->token.string != "") { ir_add_param(proc, e, name, abi_type, parameter_index); } @@ -9766,7 +9766,7 @@ void ir_begin_procedure_body(irProcedure *proc) { if (abi_types.count > 0) { abi_type = abi_types[i]; } - if (e->token.string != "" && !is_blank_ident(e->token)) { + if (e->token.string != "") { ir_add_param(proc, e, nullptr, abi_type, parameter_index); } if (is_type_tuple(abi_type)) { From 7fae890ef9eb72f3131914f9af2469f9bfb1e59e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Oct 2019 14:06:29 +0100 Subject: [PATCH 121/143] Allow ranges for array-like compound literals --- core/odin/parser/parser.odin | 3 + src/check_expr.cpp | 239 +++++++++++++++++++++++++++-------- src/check_stmt.cpp | 84 +----------- src/common.cpp | 3 + src/exact_value.cpp | 2 +- src/ir.cpp | 124 ++++++++++++++---- src/ir_print.cpp | 48 +++++-- src/parser.cpp | 11 +- src/parser.hpp | 1 + 9 files changed, 345 insertions(+), 170 deletions(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index fee9b7bdc..fb3a87e8b 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2391,6 +2391,9 @@ parse_value :: proc(p: ^Parser) -> ^ast.Expr { if p.curr_tok.kind == .Open_Brace { return parse_literal_value(p, nil); } + prev_allow_range = p.allow_range; + defer p.allow_range = prev_allow_range; + p.allow_range = true; return parse_expr(p, false); } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ea9248089..f07ebe09c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6635,6 +6635,98 @@ bool ternary_compare_types(Type *x, Type *y) { } +bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand *y, ExactValue *inline_for_depth_) { + if (!is_ast_range(node)) { + return false; + } + + ast_node(ie, BinaryExpr, node); + + check_expr(c, x, ie->left); + if (x->mode == Addressing_Invalid) { + return false; + } + check_expr(c, y, ie->right); + if (y->mode == Addressing_Invalid) { + return false; + } + + convert_to_typed(c, x, y->type); + if (x->mode == Addressing_Invalid) { + return false; + } + convert_to_typed(c, y, x->type); + if (y->mode == Addressing_Invalid) { + return false; + } + + convert_to_typed(c, x, default_type(y->type)); + if (x->mode == Addressing_Invalid) { + return false; + } + convert_to_typed(c, y, default_type(x->type)); + if (y->mode == Addressing_Invalid) { + return false; + } + + if (!are_types_identical(x->type, y->type)) { + if (x->type != t_invalid && + y->type != t_invalid) { + gbString xt = type_to_string(x->type); + gbString yt = type_to_string(y->type); + gbString expr_str = expr_to_string(x->expr); + error(ie->op, "Mismatched types in interval expression '%s' : '%s' vs '%s'", expr_str, xt, yt); + gb_string_free(expr_str); + gb_string_free(yt); + gb_string_free(xt); + } + return false; + } + + Type *type = x->type; + if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) { + error(ie->op, "Only numerical and pointer types are allowed within interval expressions"); + return false; + } + + if (x->mode == Addressing_Constant && + y->mode == Addressing_Constant) { + ExactValue a = x->value; + ExactValue b = y->value; + + GB_ASSERT(are_types_identical(x->type, y->type)); + + TokenKind op = Token_Lt; + switch (ie->op.kind) { + case Token_Ellipsis: op = Token_LtEq; break; + case Token_RangeHalf: op = Token_Lt; break; + default: error(ie->op, "Invalid range operator"); break; + } + bool ok = compare_exact_values(op, a, b); + if (!ok) { + // TODO(bill): Better error message + error(ie->op, "Invalid interval range"); + return false; + } + + ExactValue inline_for_depth = exact_value_sub(b, a); + if (ie->op.kind == Token_Ellipsis) { + inline_for_depth = exact_value_increment_one(inline_for_depth); + } + + if (inline_for_depth_) *inline_for_depth_ = inline_for_depth; + } else { + error(ie->op, "Interval expressions must be constant"); + return false; + } + + add_type_and_value(&c->checker->info, ie->left, x->mode, x->type, x->value); + add_type_and_value(&c->checker->info, ie->right, y->mode, y->type, y->value); + + return true; +} + + ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Stmt; @@ -6697,35 +6789,26 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_ast_node(bl, BasicLit, node); - // NOTE(bill, 2018-06-17): Placing this in the parser is slower than - // placing it here for some reason. So don't move it to the parsing - // stage if you _think_ it will be faster, only do it if you _know_ it - // will be faster. Type *t = t_invalid; - switch (bl->token.kind) { - case Token_Integer: t = t_untyped_integer; break; - case Token_Float: t = t_untyped_float; break; - case Token_String: t = t_untyped_string; break; - case Token_Rune: t = t_untyped_rune; break; - case Token_Imag: { - String s = bl->token.string; - Rune r = s[s.len-1]; - // NOTE(bill, 2019-08-25): Allow for quaternions by having j and k imaginary numbers - switch (r) { - case 'i': t = t_untyped_complex; break; - case 'j': t = t_untyped_quaternion; break; - case 'k': t = t_untyped_quaternion; break; + switch (bl->value.kind) { + case ExactValue_String: t = t_untyped_string; break; + case ExactValue_Float: t = t_untyped_float; break; + case ExactValue_Complex: t = t_untyped_complex; break; + case ExactValue_Quaternion: t = t_untyped_quaternion; break; + case ExactValue_Integer: + t = t_untyped_integer; + if (bl->token.kind == Token_Rune) { + t = t_untyped_rune; } - break; - } default: - GB_PANIC("Unknown literal"); + GB_PANIC("Unhandled value type for basic literal"); break; } + o->mode = Addressing_Constant; o->type = t; - o->value = exact_value_from_basic_literal(bl->token); + o->value = bl->value; case_end; case_ast_node(bd, BasicDirective, node); @@ -7090,9 +7173,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (is_type_simd_vector(t)) { error(cl->elems[0], "'field = value' is not allowed for SIMD vector literals"); } else { - Map seen = {}; - map_init(&seen, heap_allocator()); - defer (map_destroy(&seen)); + RangeCache rc = range_cache_make(heap_allocator()); + defer (range_cache_destroy(&rc)); for_array(i, cl->elems) { Ast *elem = cl->elems[i]; @@ -7102,36 +7184,89 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } ast_node(fv, FieldValue, elem); - Operand op_index = {}; - check_expr(c, &op_index, fv->field); + if (is_ast_range(fv->field)) { + Token op = fv->field->BinaryExpr.op; - if (op_index.mode != Addressing_Constant || !is_type_integer(core_type(op_index.type))) { - error(elem, "Expected a constant integer as an array field"); - continue; + Operand x = {}; + Operand y = {}; + bool ok = check_range(c, fv->field, &x, &y, nullptr); + if (!ok) { + continue; + } + if (x.mode != Addressing_Constant || !is_type_integer(core_type(x.type))) { + error(x.expr, "Expected a constant integer as an array field"); + continue; + } + + if (y.mode != Addressing_Constant || !is_type_integer(core_type(y.type))) { + error(y.expr, "Expected a constant integer as an array field"); + continue; + } + + i64 lo = exact_value_to_i64(x.value); + i64 hi = exact_value_to_i64(y.value); + if (op.kind == Token_RangeHalf) { + hi -= 1; + } + i64 max_index = hi; + + bool new_range = range_cache_add_range(&rc, lo, hi); + if (!new_range) { + error(elem, "Overlapping field range index %lld %.*s %lld for %.*s", lo, LIT(op.string), hi, LIT(context_name)); + continue; + } + + + if (max_type_count >= 0 && (lo < 0 || lo >= max_type_count)) { + error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", lo, max_type_count, LIT(context_name)); + continue; + } + if (max_type_count >= 0 && (hi < 0 || hi >= max_type_count)) { + error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", hi, max_type_count, LIT(context_name)); + continue; + } + + if (max < max_index) { + max = max_index; + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, fv->value, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; + } else { + Operand op_index = {}; + check_expr(c, &op_index, fv->field); + + if (op_index.mode != Addressing_Constant || !is_type_integer(core_type(op_index.type))) { + error(elem, "Expected a constant integer as an array field"); + continue; + } + + i64 index = exact_value_to_i64(op_index.value); + + if (max_type_count >= 0 && (index < 0 || index >= max_type_count)) { + error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", index, max_type_count, LIT(context_name)); + continue; + } + + bool new_index = range_cache_add_index(&rc, index); + if (!new_index) { + error(elem, "Duplicate field index %lld for %.*s", index, LIT(context_name)); + continue; + } + + if (max < index) { + max = index; + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, fv->value, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; } - - i64 index = exact_value_to_i64(op_index.value); - - if (max_type_count >= 0 && (index < 0 || index >= max_type_count)) { - error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", index, max_type_count, LIT(context_name)); - continue; - } - - if (map_get(&seen, hash_integer(u64(index))) != nullptr) { - error(elem, "Duplicate field index %lld for %.*s", index, LIT(context_name)); - continue; - } - map_set(&seen, hash_integer(u64(index)), true); - - if (max < index) { - max = index; - } - - Operand operand = {}; - check_expr_with_type_hint(c, &operand, fv->value, elem_type); - check_assignment(c, &operand, elem_type, context_name); - - is_constant = is_constant && operand.mode == Addressing_Constant; } cl->max_index = max; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 72913903d..d4398664b 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -605,89 +605,15 @@ void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { if (is_ast_range(expr)) { ast_node(ie, BinaryExpr, expr); - Operand x = {Addressing_Invalid}; - Operand y = {Addressing_Invalid}; + Operand x = {}; + Operand y = {}; - check_expr(ctx, &x, ie->left); - if (x.mode == Addressing_Invalid) { - goto skip_expr; - } - check_expr(ctx, &y, ie->right); - if (y.mode == Addressing_Invalid) { + bool ok = check_range(ctx, expr, &x, &y, &inline_for_depth); + if (!ok) { goto skip_expr; } - convert_to_typed(ctx, &x, y.type); - if (x.mode == Addressing_Invalid) { - goto skip_expr; - } - convert_to_typed(ctx, &y, x.type); - if (y.mode == Addressing_Invalid) { - goto skip_expr; - } - - convert_to_typed(ctx, &x, default_type(y.type)); - if (x.mode == Addressing_Invalid) { - goto skip_expr; - } - convert_to_typed(ctx, &y, default_type(x.type)); - if (y.mode == Addressing_Invalid) { - goto skip_expr; - } - - if (!are_types_identical(x.type, y.type)) { - if (x.type != t_invalid && - y.type != t_invalid) { - gbString xt = type_to_string(x.type); - gbString yt = type_to_string(y.type); - gbString expr_str = expr_to_string(x.expr); - error(ie->op, "Mismatched types in interval expression '%s' : '%s' vs '%s'", expr_str, xt, yt); - gb_string_free(expr_str); - gb_string_free(yt); - gb_string_free(xt); - } - goto skip_expr; - } - - Type *type = x.type; - if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) { - error(ie->op, "Only numerical and pointer types are allowed within interval expressions"); - goto skip_expr; - } - - if (x.mode == Addressing_Constant && - y.mode == Addressing_Constant) { - ExactValue a = x.value; - ExactValue b = y.value; - - GB_ASSERT(are_types_identical(x.type, y.type)); - - TokenKind op = Token_Lt; - switch (ie->op.kind) { - case Token_Ellipsis: op = Token_LtEq; break; - case Token_RangeHalf: op = Token_Lt; break; - default: error(ie->op, "Invalid range operator"); break; - } - bool ok = compare_exact_values(op, a, b); - if (!ok) { - // TODO(bill): Better error message - error(ie->op, "Invalid interval range"); - goto skip_expr; - } - - inline_for_depth = exact_value_sub(b, a); - if (ie->op.kind == Token_Ellipsis) { - inline_for_depth = exact_value_increment_one(inline_for_depth); - } - - } else { - error(ie->op, "Interval expressions must be constant"); - goto skip_expr; - } - - add_type_and_value(&ctx->checker->info, ie->left, x.mode, x.type, x.value); - add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value); - val0 = type; + val0 = x.type; val1 = t_int; } else { Operand operand = {Addressing_Invalid}; diff --git a/src/common.cpp b/src/common.cpp index db6505a36..b034ad720 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -143,6 +143,9 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) { #define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++) +#include "range_cache.cpp" + + u64 fnv64a(void const *data, isize len) { u8 const *bytes = cast(u8 const *)data; diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 95d04d93b..42b22c8ef 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -293,12 +293,12 @@ ExactValue exact_value_from_basic_literal(Token token) { case 'i': return exact_value_complex(0, imag); case 'j': return exact_value_quaternion(0, 0, imag, 0); case 'k': return exact_value_quaternion(0, 0, 0, imag); + default: GB_PANIC("Invalid imaginary basic literal"); } } case Token_Rune: { Rune r = GB_RUNE_INVALID; gb_utf8_decode(token.string.text, token.string.len, &r); - // gb_printf("%.*s rune: %d\n", LIT(token.string), r); return exact_value_i64(r); } default: diff --git a/src/ir.cpp b/src/ir.cpp index c654e2bf8..5eeba91a2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7865,14 +7865,40 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { if (ir_is_elem_const(proc->module, fv->value, et)) { continue; } - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); - irCompoundLitElemTempData data = {}; - data.expr = fv->value; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op == Token_Ellipsis) { + hi += 1; + } + + irValue *value = ir_build_expr(proc, fv->value); + + for (i64 k = lo; k < hi; k++) { + irCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = cast(i32)k; + array_add(&temp_data, data); + } + + } else { + auto tav = fv->field->tav; + GB_ASSERT(tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(tav.value); + + irCompoundLitElemTempData data = {}; + data.value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et); + data.expr = fv->value; + data.elem_index = cast(i32)index; + array_add(&temp_data, data); + } } else { if (ir_is_elem_const(proc->module, elem, et)) { @@ -7897,15 +7923,15 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { defer (proc->return_ptr_hint_value = return_ptr_hint_value); defer (proc->return_ptr_hint_used = return_ptr_hint_used); + irValue *field_expr = temp_data[i].value; Ast *expr = temp_data[i].expr; - if (expr == nullptr) { - continue; - } proc->return_ptr_hint_value = temp_data[i].gep; proc->return_ptr_hint_ast = unparen_expr(expr); - irValue *field_expr = ir_build_expr(proc, expr); + if (field_expr == nullptr) { + field_expr = ir_build_expr(proc, expr); + } Type *t = ir_type(field_expr); GB_ASSERT(t->kind != Type_Tuple); irValue *ev = ir_emit_conv(proc, field_expr, et); @@ -7945,19 +7971,43 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { continue; } + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); - GB_ASSERT(fv->field->tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(fv->field->tav.value); + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op == Token_Ellipsis) { + hi += 1; + } - irValue *field_expr = ir_build_expr(proc, fv->value); - GB_ASSERT(!is_type_tuple(ir_type(field_expr))); + irValue *value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et); - irValue *ev = ir_emit_conv(proc, field_expr, et); + for (i64 k = lo; k < hi; k++) { + irCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = cast(i32)k; + array_add(&temp_data, data); + } - irCompoundLitElemTempData data = {}; - data.value = ev; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); + } else { + GB_ASSERT(fv->field->tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(fv->field->tav.value); + + irValue *field_expr = ir_build_expr(proc, fv->value); + GB_ASSERT(!is_type_tuple(ir_type(field_expr))); + + irValue *ev = ir_emit_conv(proc, field_expr, et); + + irCompoundLitElemTempData data = {}; + data.value = ev; + data.elem_index = cast(i32)index; + array_add(&temp_data, data); + } } else { if (ir_is_elem_const(proc->module, elem, et)) { continue; @@ -8015,14 +8065,36 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { Ast *elem = cl->elems[i]; if (elem->kind == Ast_FieldValue) { ast_node(fv, FieldValue, elem); - GB_ASSERT(fv->field->tav.mode == Addressing_Constant); + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); - i64 field_index = exact_value_to_i64(fv->field->tav.value); + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op == Token_Ellipsis) { + hi += 1; + } - irValue *ev = ir_build_expr(proc, fv->value); - irValue *value = ir_emit_conv(proc, ev, et); - irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index); - ir_emit_store(proc, ep, value); + irValue *value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et); + + for (i64 k = lo; k < hi; k++) { + irValue *ep = ir_emit_array_epi(proc, items, cast(i32)k); + ir_emit_store(proc, ep, value); + } + } else { + GB_ASSERT(fv->field->tav.mode == Addressing_Constant); + + i64 field_index = exact_value_to_i64(fv->field->tav.value); + + irValue *ev = ir_build_expr(proc, fv->value); + irValue *value = ir_emit_conv(proc, ev, et); + irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index); + ir_emit_store(proc, ep, value); + } } else { irValue *value = ir_emit_conv(proc, ir_build_expr(proc, elem), et); irValue *ep = ir_emit_array_epi(proc, items, cast(i32)i); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index cece0c1db..1d0c8af35 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -887,17 +887,47 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * for (isize j = 0; j < elem_count; j++) { Ast *elem = cl->elems[j]; ast_node(fv, FieldValue, elem); - TypeAndValue index_tav = fv->field->tav; - GB_ASSERT(index_tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(index_tav.value); - if (index == i) { - TypeAndValue tav = fv->value->tav; - if (tav.mode != Addressing_Constant) { + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op == Token_Ellipsis) { + hi += 1; + } + if (lo == i) { + TypeAndValue tav = fv->value->tav; + if (tav.mode != Addressing_Constant) { + break; + } + for (i64 k = lo; k < hi; k++) { + if (k > lo) ir_write_str_lit(f, ", "); + + ir_print_compound_element(f, m, tav.value, elem_type); + } + + found = true; + i += (hi-lo-1); + break; + } + } else { + TypeAndValue index_tav = fv->field->tav; + GB_ASSERT(index_tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(index_tav.value); + if (index == i) { + TypeAndValue tav = fv->value->tav; + if (tav.mode != Addressing_Constant) { + break; + } + ir_print_compound_element(f, m, tav.value, elem_type); + found = true; break; } - ir_print_compound_element(f, m, tav.value, elem_type); - found = true; - break; } } diff --git a/src/parser.cpp b/src/parser.cpp index 7f866922a..10aa10119 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -588,6 +588,7 @@ Ast *ast_undef(AstFile *f, Token token) { Ast *ast_basic_lit(AstFile *f, Token basic_lit) { Ast *result = alloc_ast_node(f, Ast_BasicLit); result->BasicLit.token = basic_lit; + result->BasicLit.value = exact_value_from_basic_literal(basic_lit); return result; } @@ -1509,8 +1510,11 @@ Ast *parse_value(AstFile *f) { if (f->curr_token.kind == Token_OpenBrace) { return parse_literal_value(f, nullptr); } - - Ast *value = parse_expr(f, false); + Ast *value; + bool prev_allow_range = f->allow_range; + f->allow_range = true; + value = parse_expr(f, false); + f->allow_range = prev_allow_range; return value; } @@ -1735,7 +1739,8 @@ Ast *parse_operand(AstFile *f, bool lhs) { operand = ast_bad_expr(f, token, f->curr_token); } operand->stmt_state_flags |= StmtStateFlag_no_deferred; - } */ else if (name.string == "file") { return ast_basic_directive(f, token, name.string); + } */ else if (name.string == "file") { + return ast_basic_directive(f, token, name.string); } else if (name.string == "line") { return ast_basic_directive(f, token, name.string); } else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string); } else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string); diff --git a/src/parser.hpp b/src/parser.hpp index 9c3f733e5..83df7a9d6 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -222,6 +222,7 @@ enum StmtAllowFlag { AST_KIND(Undef, "undef", Token) \ AST_KIND(BasicLit, "basic literal", struct { \ Token token; \ + ExactValue value; \ }) \ AST_KIND(BasicDirective, "basic directive", struct { \ Token token; \ From 1734eb949f5f58c61c541695386b58c06124f9e6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Oct 2019 14:18:38 +0100 Subject: [PATCH 122/143] Update utf8.accept_sizes to use ranged fields --- core/unicode/utf8/utf8.odin | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/core/unicode/utf8/utf8.odin b/core/unicode/utf8/utf8.odin index 4a4e2f459..4c991c1fc 100644 --- a/core/unicode/utf8/utf8.odin +++ b/core/unicode/utf8/utf8.odin @@ -41,23 +41,17 @@ accept_ranges := [5]Accept_Range{ }; accept_sizes := [256]u8{ - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x30-0x3f - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x40-0x4f - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x50-0x5f - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x60-0x6f - 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x70-0x7f - - 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x80-0x8f - 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0x90-0x9f - 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xa0-0xaf - 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xb0-0xbf - 0xf1, 0xf1, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xc0-0xcf - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, // 0xd0-0xdf - 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef - 0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff + 0x00..0x7f = 0xf0, + 0x80..0xc1 = 0xf1, + 0xc2..0xdf = 0x02, + 0xe0 = 0x13, + 0xe1..0xec = 0x03, + 0xed = 0x23, + 0xee..0xef = 0x03, + 0xf0 = 0x34, + 0xf1..0xf3 = 0x04, + 0xf4 = 0x44, + 0xf5..0xff = 0xf1, }; encode_rune :: proc(c: rune) -> ([4]u8, int) { From d808f9eccf961a63630d6751c7367d8dc375c4b9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Oct 2019 14:29:04 +0100 Subject: [PATCH 123/143] Add range_cache.cpp --- build.bat | 1 - examples/demo/demo.odin | 20 ++++++++++-- src/range_cache.cpp | 70 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 src/range_cache.cpp diff --git a/build.bat b/build.bat index 6e5450c2b..b95e8a2ab 100644 --- a/build.bat +++ b/build.bat @@ -39,7 +39,6 @@ set linker_settings=%libs% %linker_flags% del *.pdb > NUL 2> NUL del *.ilk > NUL 2> NUL - cl %compiler_settings% "src\main.cpp" ^ /link %linker_settings% -OUT:%exe_name% ^ && odin run examples/demo/demo.odin diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 5ee9ded84..cd6ac6bf5 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -50,9 +50,9 @@ extra_general_stuff :: proc() { i := i32(137); ptr := &i; - _ = (^f32)(ptr); + _ = (^f32)(ptr); // Call-based syntax // ^f32(ptr) == ^(f32(ptr)) - _ = cast(^f32)ptr; + _ = cast(^f32)ptr; // Operator-based syntax _ = (^f32)(ptr)^; _ = (cast(^f32)ptr)^; @@ -1188,6 +1188,21 @@ where_clauses :: proc() { } } +ranged_fields_for_array_compound_literals :: proc() { + fmt.println("\n#ranged fields for array compound literals"); + { // Normal Array Literal + foo := [?]int{1, 4, 9, 16}; + fmt.println(foo); + } + i := 2; + foo := [?]int { + 0 = 123, + 5..9 = 54, + 10..<16 = i*3 + (i-1)*2, + }; + fmt.println(foo); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8] +} + main :: proc() { when true { extra_general_stuff(); @@ -1210,6 +1225,7 @@ main :: proc() { quaternions(); inline_for_statement(); where_clauses(); + ranged_fields_for_array_compound_literals(); } } diff --git a/src/range_cache.cpp b/src/range_cache.cpp new file mode 100644 index 000000000..9701fb432 --- /dev/null +++ b/src/range_cache.cpp @@ -0,0 +1,70 @@ + +// Integers only +struct RangeValue { + i64 lo; + i64 hi; +}; + +struct RangeCache { + Array ranges; +}; + + +RangeCache range_cache_make(gbAllocator a) { + RangeCache cache = {}; + array_init(&cache.ranges, a); + return cache; +} + +void range_cache_destroy(RangeCache *c) { + array_free(&c->ranges); +} + +bool range_cache_add_index(RangeCache *c, i64 index) { + for_array(i, c->ranges) { + RangeValue v = c->ranges[i]; + if (v.lo <= index && index <= v.hi) { + return false; + } + } + RangeValue v = {index, index}; + array_add(&c->ranges, v); + return true; +} + + +bool range_cache_add_range(RangeCache *c, i64 lo, i64 hi) { + GB_ASSERT(lo <= hi); + for_array(i, c->ranges) { + RangeValue v = c->ranges[i]; + if (hi < v.lo) { + continue; + } + if (lo > v.hi) { + continue; + } + + if (v.hi < hi) { + v.hi = hi; + } + if (lo < v.lo) { + v.lo = lo; + } + c->ranges[i] = v; + return false; + } + RangeValue v = {lo, hi}; + array_add(&c->ranges, v); + return true; +} + + +bool range_cache_index_exists(RangeCache *c, i64 index) { + for_array(i, c->ranges) { + RangeValue v = c->ranges[i]; + if (v.lo <= index && index <= v.hi) { + return true; + } + } + return false; +} From a5e42a046531405e0b8830ae092470c2aa2e67a8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Oct 2019 14:36:28 +0100 Subject: [PATCH 124/143] Add `ranged_fields_for_array_compound_literals` --- examples/demo/demo.odin | 44 ++++++++++++++++++++++++++++++++++------- src/check_expr.cpp | 9 ++++++--- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index cd6ac6bf5..fa970fa43 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1194,13 +1194,43 @@ ranged_fields_for_array_compound_literals :: proc() { foo := [?]int{1, 4, 9, 16}; fmt.println(foo); } - i := 2; - foo := [?]int { - 0 = 123, - 5..9 = 54, - 10..<16 = i*3 + (i-1)*2, - }; - fmt.println(foo); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8] + { // Indexed + foo := [?]int{ + 3 = 16, + 1 = 4, + 2 = 9, + 0 = 1, + }; + fmt.println(foo); + } + { // Ranges + i := 2; + foo := [?]int { + 0 = 123, + 5..9 = 54, + 10..<16 = i*3 + (i-1)*2, + }; + #assert(len(foo) == 16); + fmt.println(foo); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8] + } + { // Slice and Dynamic Array support + i := 2; + foo_slice := []int { + 0 = 123, + 5..9 = 54, + 10..<16 = i*3 + (i-1)*2, + }; + assert(len(foo) == 16); + fmt.println(foo_slice); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8] + + foo_dynamic_array := [dynamic]int { + 0 = 123, + 5..9 = 54, + 10..<16 = i*3 + (i-1)*2, + }; + assert(len(foo) == 16); + fmt.println(foo_dynamic_array); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8] + } } main :: proc() { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f07ebe09c..7491094c8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7205,10 +7205,13 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type i64 lo = exact_value_to_i64(x.value); i64 hi = exact_value_to_i64(y.value); + i64 max_index = hi; if (op.kind == Token_RangeHalf) { hi -= 1; } - i64 max_index = hi; + if (op.kind == Token_Ellipsis) { + max_index += 1; + } bool new_range = range_cache_add_range(&rc, lo, hi); if (!new_range) { @@ -7257,8 +7260,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type continue; } - if (max < index) { - max = index; + if (max < index+1) { + max = index+1; } Operand operand = {}; From c7cb754514110d7d245ee2508fb8ccae7e24a420 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Oct 2019 14:37:27 +0100 Subject: [PATCH 125/143] Fix typos --- examples/demo/demo.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index fa970fa43..4d14973f6 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1220,7 +1220,7 @@ ranged_fields_for_array_compound_literals :: proc() { 5..9 = 54, 10..<16 = i*3 + (i-1)*2, }; - assert(len(foo) == 16); + assert(len(foo_slice) == 16); fmt.println(foo_slice); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8] foo_dynamic_array := [dynamic]int { @@ -1228,7 +1228,7 @@ ranged_fields_for_array_compound_literals :: proc() { 5..9 = 54, 10..<16 = i*3 + (i-1)*2, }; - assert(len(foo) == 16); + assert(len(foo_dynamic_array) == 16); fmt.println(foo_dynamic_array); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8] } } From 14e8b299b73c87d5c48e73add91d7a427d554d75 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Oct 2019 14:43:06 +0100 Subject: [PATCH 126/143] Fix slice and dynamic array lengths determined from ranged compound literals --- src/check_expr.cpp | 7 ++----- src/ir.cpp | 4 ++-- src/parser.hpp | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7491094c8..3c4d737a4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7209,9 +7209,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (op.kind == Token_RangeHalf) { hi -= 1; } - if (op.kind == Token_Ellipsis) { - max_index += 1; - } bool new_range = range_cache_add_range(&rc, lo, hi); if (!new_range) { @@ -7229,7 +7226,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type continue; } - if (max < max_index) { + if (max < hi) { max = max_index; } @@ -7272,7 +7269,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } } - cl->max_index = max; + cl->max_count = max; } diff --git a/src/ir.cpp b/src/ir.cpp index 5eeba91a2..ae60be7e3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1552,7 +1552,7 @@ irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) { if (count == 0) { return ir_value_nil(type); } - count = gb_max(cl->max_index+1, count); + count = gb_max(cl->max_count, count); Type *elem = base_type(type)->Slice.elem; Type *t = alloc_type_array(elem, count); irValue *backing_array = ir_add_module_constant(m, t, value); @@ -8047,7 +8047,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { irValue *size = ir_const_int(type_size_of(et)); irValue *align = ir_const_int(type_align_of(et)); - i64 item_count = gb_max(cl->max_index+1, cl->elems.count); + i64 item_count = gb_max(cl->max_count, cl->elems.count); { auto args = array_make(a, 5); diff --git a/src/parser.hpp b/src/parser.hpp index 83df7a9d6..f07f3ce0d 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -250,7 +250,7 @@ enum StmtAllowFlag { Ast *type; \ Array elems; \ Token open, close; \ - i64 max_index; \ + i64 max_count; \ }) \ AST_KIND(_ExprBegin, "", bool) \ AST_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \ From 5aa46d31b2af6bd39ce441c7668726d6227d753a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Oct 2019 14:46:21 +0100 Subject: [PATCH 127/143] Move `package decimal` to be a subpackage of `package strconv` --- core/{ => strconv}/decimal/decimal.odin | 2 +- core/strconv/generic_float.odin | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename core/{ => strconv}/decimal/decimal.odin (99%) diff --git a/core/decimal/decimal.odin b/core/strconv/decimal/decimal.odin similarity index 99% rename from core/decimal/decimal.odin rename to core/strconv/decimal/decimal.odin index 97c586635..15853c5a7 100644 --- a/core/decimal/decimal.odin +++ b/core/strconv/decimal/decimal.odin @@ -1,6 +1,6 @@ // Multiple precision decimal numbers // NOTE: This is only for floating point printing and nothing else -package decimal +package strconv_decimal Decimal :: struct { digits: [384]byte, // big-endian digits diff --git a/core/strconv/generic_float.odin b/core/strconv/generic_float.odin index 59eaa20d5..24cbf3b15 100644 --- a/core/strconv/generic_float.odin +++ b/core/strconv/generic_float.odin @@ -1,6 +1,6 @@ package strconv -using import "core:decimal" +using import "decimal" Int_Flag :: enum { Prefix, From 2db16d6a320c2c59bb5e932d7ed291dcc011af65 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Oct 2019 15:05:36 +0100 Subject: [PATCH 128/143] Add for `package utf8`: `rune_at_pos`, `rune_string_at_pos`, `rune_at`, `rune_offset` --- core/unicode/utf8/utf8.odin | 51 ++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/core/unicode/utf8/utf8.odin b/core/unicode/utf8/utf8.odin index 4c991c1fc..acdd887f0 100644 --- a/core/unicode/utf8/utf8.odin +++ b/core/unicode/utf8/utf8.odin @@ -161,19 +161,58 @@ decode_last_rune :: proc(s: []u8) -> (rune, int) { return r, size; } -rune_index :: proc(s: string, index: int) -> (r: rune = RUNE_ERROR, ok: bool = false) { - if index < 0 { - return; +rune_at_pos :: proc(s: string, pos: int) -> rune { + if pos < 0 { + return RUNE_ERROR; } i := 0; for c in s { - if i == index { - return r, true; + if i == pos { + return r; } i += 1; } - return; + return RUNE_ERROR; +} + +rune_string_at_pos :: proc(s: string, pos: int) -> string { + if pos < 0 { + return ""; + } + + i := 0; + for c, offset in s { + if i == pos { + w := rune_size(c); + return s[offset:][:w]; + } + i += 1; + } + return ""; +} + +rune_at :: proc(s: string, byte_index: int) -> rune { + str := s[byte_index:]; + r, _ := decode_rune_in_string(s[byte_index:]); + return r; +} + +// Returns the byte position of rune at position pos in s with an optional start byte position. +// Returns -1 if it runs out of the string. +rune_offset :: proc(s: string, pos: int, start: int = 0) -> int { + if pos < 0 { + return -1; + } + + i := 0; + for c, offset in s[start:] { + if i == pos { + return offset+start; + } + i += 1; + } + return -1; } valid_rune :: proc(r: rune) -> bool { From 0977ac111a48283ac9784ad9ebb3f18f9db6fd74 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 27 Oct 2019 08:34:20 +0000 Subject: [PATCH 129/143] Fix typo in `package utf8`; add `wchar_t` to `package c` --- core/c/c.odin | 2 ++ core/unicode/utf8/utf8.odin | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/core/c/c.odin b/core/c/c.odin index 47af84165..3ed49c0c2 100644 --- a/core/c/c.odin +++ b/core/c/c.odin @@ -31,3 +31,5 @@ ssize_t :: b.int; ptrdiff_t :: b.int; uintptr_t :: b.uintptr; intptr_t :: b.int; + +wchar_t :: (ODIN_OS == "windows") ? b.u16 : b.u32; diff --git a/core/unicode/utf8/utf8.odin b/core/unicode/utf8/utf8.odin index acdd887f0..c30f7b733 100644 --- a/core/unicode/utf8/utf8.odin +++ b/core/unicode/utf8/utf8.odin @@ -167,7 +167,7 @@ rune_at_pos :: proc(s: string, pos: int) -> rune { } i := 0; - for c in s { + for r in s { if i == pos { return r; } From 5e81fc72b97dc3a27fee3ea1e0ae9bffab56e8d5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 27 Oct 2019 10:35:35 +0000 Subject: [PATCH 130/143] New `package math` and `package math/linalg` --- core/math/linalg/linalg.odin | 257 ++++++++++++ core/math/math.odin | 781 +++++++++++++++++------------------ src/check_expr.cpp | 28 +- 3 files changed, 671 insertions(+), 395 deletions(-) create mode 100644 core/math/linalg/linalg.odin diff --git a/core/math/linalg/linalg.odin b/core/math/linalg/linalg.odin new file mode 100644 index 000000000..9a4781668 --- /dev/null +++ b/core/math/linalg/linalg.odin @@ -0,0 +1,257 @@ +package linalg + +import "core:math" + +// Generic + +dot_vector :: proc(a, b: $T/[$N]$E) -> (c: E) { + for i in 0.. (c: f32) { + return real(a)*real(a) + imag(a)*imag(b) + jmag(a)*jmag(b) + kmag(a)*kmag(b); +} +dot_quaternion256 :: proc(a, b: $T/quaternion256) -> (c: f64) { + return real(a)*real(a) + imag(a)*imag(b) + jmag(a)*jmag(b) + kmag(a)*kmag(b); +} + +dot :: proc{dot_vector, dot_quaternion128, dot_quaternion256}; + +cross2 :: proc(a, b: $T/[2]$E) -> E { + return a[0]*b[1] - b[0]*a[1]; +} + +cross3 :: proc(a, b: $T/[3]$E) -> (c: T) { + c[0] = +(a[1]*b[2] - b[1]*a[2]); + c[1] = -(a[2]*b[3] - b[2]*a[3]); + c[2] = +(a[3]*b[1] - b[3]*a[1]); + return; +} + +cross :: proc{cross2, cross3}; + + +normalize_vector :: proc(v: $T/[$N]$E) -> T { + return v / length(v); +} +normalize_quaternion128 :: proc(q: $Q/quaternion128) -> Q { + return q/abs(q); +} +normalize_quaternion256 :: proc(q: $Q/quaternion256) -> Q { + return q/abs(q); +} +normalize :: proc{normalize_vector, normalize_quaternion128, normalize_quaternion256}; + +normalize0_vector :: proc(v: $T/[$N]$E) -> T { + m := length(v); + return m == 0 ? 0 : v/m; +} +normalize0_quaternion128 :: proc(q: $Q/quaternion128) -> Q { + m := abs(q); + return m == 0 ? 0 : q/m; +} +normalize0_quaternion256 :: proc(q: $Q/quaternion256) -> Q { + m := abs(q); + return m == 0 ? 0 : q/m; +} +normalize0 :: proc{normalize0_vector, normalize0_quaternion128, normalize0_quaternion256}; + + +length :: proc(v: $T/[$N]$E) -> E { + return math.sqrt(dot(v, v)); +} + + +identity :: proc($T: typeid/[$N][N]$E) -> (m: T) { + for i in 0.. (m: ((M == N) ? T : [M][N]E)) { + for j in 0.. (c: ((I == J && J == K && A == B) ? A : [I][K]E)) { + for i in 0.. (c: B) { + for i in 0.. V { + Raw_Quaternion :: struct {xyz: [3]f32, r: f32}; + + q := transmute(Raw_Quaternion)q; + v := transmute([3]f32)v; + + t := cross(2*q.xyz, v); + return V(v + q.r*t + cross(q.xyz, t)); +} + +mul_quaternion256_vector3 :: proc(q: $Q/quaternion256, v: $V/[3]$F/f64) -> V { + Raw_Quaternion :: struct {xyz: [3]f64, r: f64}; + + q := transmute(Raw_Quaternion)q; + v := transmute([3]f64)v; + + t := cross(2*q.xyz, v); + return V(v + q.r*t + cross(q.xyz, t)); +} +mul_quaternion_vector3 :: proc{mul_quaternion128_vector3, mul_quaternion256_vector3}; + +mul :: proc{mul_matrix, mul_matrix_vector, mul_quaternion128_vector3, mul_quaternion256_vector3}; + + +// Specific + +Float :: f32; + +Vector2 :: distinct [2]Float; +Vector3 :: distinct [3]Float; +Vector4 :: distinct [4]Float; + +Matrix2x1 :: distinct [2][1]Float; +Matrix2x2 :: distinct [2][2]Float; +Matrix2x3 :: distinct [2][3]Float; +Matrix2x4 :: distinct [2][4]Float; + +Matrix3x1 :: distinct [3][1]Float; +Matrix3x2 :: distinct [3][2]Float; +Matrix3x3 :: distinct [3][3]Float; +Matrix3x4 :: distinct [3][4]Float; + +Matrix4x1 :: distinct [4][1]Float; +Matrix4x2 :: distinct [4][2]Float; +Matrix4x3 :: distinct [4][3]Float; +Matrix4x4 :: distinct [4][4]Float; + + +Matrix2 :: Matrix2x2; +Matrix3 :: Matrix3x3; +Matrix4 :: Matrix4x4; + + +Quaternion :: distinct (size_of(Float) == size_of(f32) ? quaternion128 : quaternion256); + + +translate_matrix4 :: proc(v: Vector3) -> Matrix4 { + m := identity(Matrix4); + m[3][0] = v[0]; + m[3][1] = v[1]; + m[3][2] = v[2]; + return m; +} + + +rotate_matrix4 :: proc(v: Vector3, angle_radians: Float) -> Matrix4 { + c := math.cos(angle_radians); + s := math.sin(angle_radians); + + a := normalize(v); + t := a * (1-c); + + rot := identity(Matrix4); + + rot[0][0] = c + t[0]*a[0]; + rot[0][1] = 0 + t[0]*a[1] + s*a[2]; + rot[0][2] = 0 + t[0]*a[2] - s*a[1]; + rot[0][3] = 0; + + rot[1][0] = 0 + t[1]*a[0] - s*a[2]; + rot[1][1] = c + t[1]*a[1]; + rot[1][2] = 0 + t[1]*a[2] + s*a[0]; + rot[1][3] = 0; + + rot[2][0] = 0 + t[2]*a[0] + s*a[1]; + rot[2][1] = 0 + t[2]*a[1] - s*a[0]; + rot[2][2] = c + t[2]*a[2]; + rot[2][3] = 0; + + return rot; +} + +scale_matrix4 :: proc(m: Matrix4, v: Vector3) -> Matrix4 { + mm := m; + mm[0][0] *= v[0]; + mm[1][1] *= v[1]; + mm[2][2] *= v[2]; + return mm; +} + + +look_at :: proc(eye, centre, up: Vector3) -> Matrix4 { + f := normalize(centre - eye); + s := normalize(cross(f, up)); + u := cross(s, f); + return Matrix4{ + {+s.x, +u.x, -f.x, 0}, + {+s.y, +u.y, -f.y, 0}, + {+s.z, +u.z, -f.z, 0}, + {-dot(s, eye), -dot(u, eye), +dot(f, eye), 1}, + }; +} + + +perspective :: proc(fovy, aspect, near, far: Float) -> (m: Matrix4) { + tan_half_fovy := math.tan(0.5 * fovy); + m[0][0] = 1 / (aspect*tan_half_fovy); + m[1][1] = 1 / (tan_half_fovy); + m[2][2] = -(far + near) / (far - near); + m[2][3] = -1; + m[3][2] = -2*far*near / (far - near); + return; +} + + +ortho3d :: proc(left, right, bottom, top, near, far: Float) -> (m: Matrix4) { + m[0][0] = +2 / (right - left); + m[1][1] = +2 / (top - bottom); + m[2][2] = -2 / (far - near); + m[3][0] = -(right + left) / (right - left); + m[3][1] = -(top + bottom) / (top - bottom); + m[3][2] = -(far + near) / (far- near); + m[3][3] = 1; + return; +} + + +axis_angle :: proc(axis: Vector3, angle_radians: Float) -> Quaternion { + t := angle_radians*0.5; + w := math.cos(t); + v := normalize(axis) * math.sin(t); + return quaternion(w, v.x, v.y, v.z); +} + +angle_axis :: proc(angle_radians: Float, axis: Vector3) -> Quaternion { + t := angle_radians*0.5; + w := math.cos(t); + v := normalize(axis) * math.sin(t); + return quaternion(w, v.x, v.y, v.z); +} + +euler_angles :: proc(pitch, yaw, roll: Float) -> Quaternion { + p := axis_angle({1, 0, 0}, pitch); + y := axis_angle({0, 1, 0}, yaw); + r := axis_angle({0, 0, 1}, roll); + return (y * p) * r; +} diff --git a/core/math/math.odin b/core/math/math.odin index ed04cbfbc..583da00d0 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -1,36 +1,41 @@ package math +import "intrinsics" + +Float_Class :: enum { + Normal, // an ordinary nonzero floating point value + Subnormal, // a subnormal floating point value + Zero, // zero + Neg_Zero, // the negative zero + NaN, // Not-A-Number (NaN) + Inf, // positive infinity + Neg_Inf // negative infinity +}; + TAU :: 6.28318530717958647692528676655900576; PI :: 3.14159265358979323846264338327950288; E :: 2.71828182845904523536; + +τ :: TAU; +π :: PI; +e :: E; + SQRT_TWO :: 1.41421356237309504880168872420969808; SQRT_THREE :: 1.73205080756887729352744634150587236; SQRT_FIVE :: 2.23606797749978969640917366873127623; -LOG_TWO :: 0.693147180559945309417232121458176568; -LOG_TEN :: 2.30258509299404568401799145468436421; +LN2 :: 0.693147180559945309417232121458176568; +LN10 :: 2.30258509299404568401799145468436421; -EPSILON :: 1.19209290e-7; +MAX_F64_PRECISION :: 16; // Maximum number of meaningful digits after the decimal point for 'f64' +MAX_F32_PRECISION :: 8; // Maximum number of meaningful digits after the decimal point for 'f32' -τ :: TAU; -π :: PI; - -Vec2 :: distinct [2]f32; -Vec3 :: distinct [3]f32; -Vec4 :: distinct [4]f32; - -// Column major -Mat2 :: distinct [2][2]f32; -Mat3 :: distinct [3][3]f32; -Mat4 :: distinct [4][4]f32; - -Quat :: struct {x, y, z, w: f32}; - -QUAT_IDENTITY := Quat{x = 0, y = 0, z = 0, w = 1}; +RAD_PER_DEG :: TAU/360.0; +DEG_PER_RAD :: 360.0/TAU; -@(default_calling_convention="c") +@(default_calling_convention="none") foreign _ { @(link_name="llvm.sqrt.f32") sqrt_f32 :: proc(x: f32) -> f32 ---; @@ -58,9 +63,9 @@ foreign _ { fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---; @(link_name="llvm.log.f32") - log_f32 :: proc(x: f32) -> f32 ---; + ln_f32 :: proc(x: f32) -> f32 ---; @(link_name="llvm.log.f64") - log_f64 :: proc(x: f64) -> f64 ---; + ln_f64 :: proc(x: f64) -> f64 ---; @(link_name="llvm.exp.f32") exp_f32 :: proc(x: f32) -> f32 ---; @@ -68,20 +73,40 @@ foreign _ { exp_f64 :: proc(x: f64) -> f64 ---; } -log :: proc{log_f32, log_f64}; -exp :: proc{exp_f32, exp_f64}; +sqrt :: proc{sqrt_f32, sqrt_f64}; +sin :: proc{sin_f32, sin_f64}; +cos :: proc{cos_f32, cos_f64}; +pow :: proc{pow_f32, pow_f64}; +fmuladd :: proc{fmuladd_f32, fmuladd_f64}; +ln :: proc{ln_f32, ln_f64}; +exp :: proc{exp_f32, exp_f64}; + +log_f32 :: proc(x, base: f32) -> f32 { return ln(x) / ln(base); } +log_f64 :: proc(x, base: f64) -> f64 { return ln(x) / ln(base); } +log :: proc{log_f32, log_f64}; + +log2_f32 :: proc(x: f32) -> f32 { return ln(x)/LN2; } +log2_f64 :: proc(x: f64) -> f64 { return ln(x)/LN2; } +log2 :: proc{log2_f32, log2_f64}; + +log10_f32 :: proc(x: f32) -> f32 { return ln(x)/LN10; } +log10_f64 :: proc(x: f64) -> f64 { return ln(x)/LN10; } +log10 :: proc{log10_f32, log10_f64}; + tan_f32 :: proc "c" (θ: f32) -> f32 { return sin(θ)/cos(θ); } tan_f64 :: proc "c" (θ: f64) -> f64 { return sin(θ)/cos(θ); } +tan :: proc{tan_f32, tan_f64}; lerp :: proc(a, b: $T, t: $E) -> (x: T) { return a*(1-t) + b*t; } unlerp_f32 :: proc(a, b, x: f32) -> (t: f32) { return (x-a)/(b-a); } unlerp_f64 :: proc(a, b, x: f64) -> (t: f64) { return (x-a)/(b-a); } +unlerp :: proc{unlerp_f32, unlerp_f64}; - -sign_f32 :: proc(x: f32) -> f32 { return x >= 0 ? +1 : -1; } -sign_f64 :: proc(x: f64) -> f64 { return x >= 0 ? +1 : -1; } +sign_f32 :: proc(x: f32) -> f32 { return f32(int(0 < x) - int(x < 0)); } +sign_f64 :: proc(x: f64) -> f64 { return f64(int(0 < x) - int(x < 0)); } +sign :: proc{sign_f32, sign_f64}; copy_sign_f32 :: proc(x, y: f32) -> f32 { ix := transmute(u32)x; @@ -90,7 +115,6 @@ copy_sign_f32 :: proc(x, y: f32) -> f32 { ix |= iy & 0x8000_0000; return transmute(f32)ix; } - copy_sign_f64 :: proc(x, y: f64) -> f64 { ix := transmute(u64)x; iy := transmute(u64)y; @@ -98,22 +122,89 @@ copy_sign_f64 :: proc(x, y: f64) -> f64 { ix |= iy & 0x8000_0000_0000_0000; return transmute(f64)ix; } - - -sqrt :: proc{sqrt_f32, sqrt_f64}; -sin :: proc{sin_f32, sin_f64}; -cos :: proc{cos_f32, cos_f64}; -tan :: proc{tan_f32, tan_f64}; -pow :: proc{pow_f32, pow_f64}; -fmuladd :: proc{fmuladd_f32, fmuladd_f64}; -sign :: proc{sign_f32, sign_f64}; copy_sign :: proc{copy_sign_f32, copy_sign_f64}; -round_f32 :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); } -round_f64 :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); } +to_radians_f32 :: proc(degrees: f32) -> f32 { return degrees * RAD_PER_DEG; } +to_radians_f64 :: proc(degrees: f64) -> f64 { return degrees * RAD_PER_DEG; } +to_degrees_f32 :: proc(radians: f32) -> f32 { return radians * DEG_PER_RAD; } +to_degrees_f64 :: proc(radians: f64) -> f64 { return radians * DEG_PER_RAD; } +to_radians :: proc{to_radians_f32, to_radians_f64}; +to_degrees :: proc{to_degrees_f32, to_degrees_f64}; + +trunc_f32 :: proc(x: f32) -> f32 { + trunc_internal :: proc(f: f32) -> f32 { + mask :: 0xff; + shift :: 32 - 9; + bias :: 0x7f; + + if f < 1 { + switch { + case f < 0: return -trunc_internal(-f); + case f == 0: return f; + case: return 0; + } + } + + x := transmute(u32)f; + e := (x >> shift) & mask - bias; + + if e < shift { + x &= ~(1 << (shift-e)) - 1; + } + return transmute(f32)x; + } + switch classify(x) { + case .Zero, .Neg_Zero, .NaN, .Inf, .Neg_Inf: + return x; + } + return trunc_internal(x); +} + +trunc_f64 :: proc(x: f64) -> f64 { + trunc_internal :: proc(f: f64) -> f64 { + mask :: 0x7ff; + shift :: 64 - 12; + bias :: 0x3ff; + + if f < 1 { + switch { + case f < 0: return -trunc_internal(-f); + case f == 0: return f; + case: return 0; + } + } + + x := transmute(u64)f; + e := (x >> shift) & mask - bias; + + if e < shift { + x &= ~(1 << (shift-e)) - 1; + } + return transmute(f64)x; + } + switch classify(x) { + case .Zero, .Neg_Zero, .NaN, .Inf, .Neg_Inf: + return x; + } + return trunc_internal(x); +} + +trunc :: proc{trunc_f32, trunc_f64}; + +round_f32 :: proc(x: f32) -> f32 { + return x < 0 ? ceil(x - 0.5) : floor(x + 0.5); +} +round_f64 :: proc(x: f64) -> f64 { + return x < 0 ? ceil(x - 0.5) : floor(x + 0.5); +} round :: proc{round_f32, round_f64}; + +ceil_f32 :: proc(x: f32) -> f32 { return -floor(-x); } +ceil_f64 :: proc(x: f64) -> f64 { return -floor(-x); } +ceil :: proc{ceil_f32, ceil_f64}; + floor_f32 :: proc(x: f32) -> f32 { if x == 0 || is_nan(x) || is_inf(x) { return x; @@ -144,33 +235,27 @@ floor_f64 :: proc(x: f64) -> f64 { } floor :: proc{floor_f32, floor_f64}; -ceil_f32 :: proc(x: f32) -> f32 { return -floor_f32(-x); } -ceil_f64 :: proc(x: f64) -> f64 { return -floor_f64(-x); } -ceil :: proc{ceil_f32, ceil_f64}; -remainder_f32 :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; } -remainder_f64 :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; } -remainder :: proc{remainder_f32, remainder_f64}; - -mod_f32 :: proc(x, y: f32) -> (n: f32) { - z := abs(y); - n = remainder(abs(x), z); - if sign(n) < 0 { - n += z; +floor_div :: proc(x, y: $T) -> T + where intrinsics.type_is_integer(T) { + a := x / y; + r := x % y; + if (r > 0 && y < 0) || (r < 0 && y > 0) { + a -= 1; } - return copy_sign(n, x); + return a; } -mod_f64 :: proc(x, y: f64) -> (n: f64) { - z := abs(y); - n = remainder(abs(x), z); - if sign(n) < 0 { - n += z; - } - return copy_sign(n, x); -} -mod :: proc{mod_f32, mod_f64}; -// TODO(bill): These need to implemented with the actual instructions +floor_mod :: proc(x, y: $T) -> T + where intrinsics.type_is_integer(T) { + r := x % y; + if (r > 0 && y < 0) || (r < 0 && y > 0) { + r += y; + } + return r; +} + + modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) { shift :: 32 - 8 - 1; mask :: 0xff; @@ -190,8 +275,8 @@ modf_f32 :: proc(x: f32) -> (int: f32, frac: f32) { i := transmute(u32)x; e := uint(i>>shift)&mask - bias; - if e < 32-9 { - i &~= 1<<(32-9-e) - 1; + if e < shift { + i &~= 1<<(shift-e) - 1; } int = transmute(f32)i; frac = x - int; @@ -216,360 +301,274 @@ modf_f64 :: proc(x: f64) -> (int: f64, frac: f64) { i := transmute(u64)x; e := uint(i>>shift)&mask - bias; - if e < 64-12 { - i &~= 1<<(64-12-e) - 1; + if e < shift { + i &~= 1<<(shift-e) - 1; } int = transmute(f64)i; frac = x - int; return; } modf :: proc{modf_f32, modf_f64}; +split_decimal :: modf; -is_nan_f32 :: inline proc(x: f32) -> bool { return x != x; } -is_nan_f64 :: inline proc(x: f64) -> bool { return x != x; } +mod_f32 :: proc(x, y: f32) -> (n: f32) { + z := abs(y); + n = remainder(abs(x), z); + if sign(n) < 0 { + n += z; + } + return copy_sign(n, x); +} +mod_f64 :: proc(x, y: f64) -> (n: f64) { + z := abs(y); + n = remainder(abs(x), z); + if sign(n) < 0 { + n += z; + } + return copy_sign(n, x); +} +mod :: proc{mod_f32, mod_f64}; + +remainder_f32 :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; } +remainder_f64 :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; } +remainder :: proc{remainder_f32, remainder_f64}; + + + +gcd :: proc(x, y: $T) -> T + where intrinsics.type_is_ordered_numeric(T) { + x, y := x, y; + for y != 0 { + x %= y; + x, y = y, x; + } + return abs(x); +} + +lcm :: proc(x, y: $T) -> T + where intrinsics.type_is_ordered_numeric(T) { + return x / gcd(x, y) * y; +} + +frexp_f32 :: proc(x: f32) -> (significand: f32, exponent: int) { + switch { + case x == 0: + return 0, 0; + case x < 0: + significand, exponent = frexp(-x); + return -significand, exponent; + } + ex := trunc(log2(x)); + exponent = int(ex); + significand = x / pow(2.0, ex); + if abs(significand) >= 1 { + exponent += 1; + significand /= 2; + } + if exponent == 1024 && significand == 0 { + significand = 0.99999999999999988898; + } + return; +} +frexp_f64 :: proc(x: f64) -> (significand: f64, exponent: int) { + switch { + case x == 0: + return 0, 0; + case x < 0: + significand, exponent = frexp(-x); + return -significand, exponent; + } + ex := trunc(log2(x)); + exponent = int(ex); + significand = x / pow(2.0, ex); + if abs(significand) >= 1 { + exponent += 1; + significand /= 2; + } + if exponent == 1024 && significand == 0 { + significand = 0.99999999999999988898; + } + return; +} +frexp :: proc{frexp_f32, frexp_f64}; + + + + +binomial :: proc(n, k: int) -> int { + switch { + case k <= 0: return 1; + case 2*k > n: return binomial(n, n-k); + } + + b := n; + for i in 2.. int { + when size_of(int) == size_of(i64) { + @static table := [21]int{ + 1, + 1, + 2, + 6, + 24, + 120, + 720, + 5_040, + 40_320, + 362_880, + 3_628_800, + 39_916_800, + 479_001_600, + 6_227_020_800, + 87_178_291_200, + 1_307_674_368_000, + 20_922_789_888_000, + 355_687_428_096_000, + 6_402_373_705_728_000, + 121_645_100_408_832_000, + 2_432_902_008_176_640_000, + }; + } else { + @static table := [13]int{ + 1, + 1, + 2, + 6, + 24, + 120, + 720, + 5_040, + 40_320, + 362_880, + 3_628_800, + 39_916_800, + 479_001_600, + }; + } + + assert(n >= 0, "parameter must not be negative"); + assert(n < len(table), "parameter is too large to lookup in the table"); + return 0; +} + +classify_f32 :: proc(x: f32) -> Float_Class { + switch { + case x == 0: + i := transmute(i32)x; + if i < 0 { + return .Neg_Zero; + } + return .Zero; + case x*0.5 == x: + if x < 0 { + return .Neg_Inf; + } + return .Inf; + case x != x: + return .NaN; + } + + u := transmute(u32)x; + exp := int(u>>23) & (1<<8 - 1); + if exp == 0 { + return .Subnormal; + } + return .Normal; +} +classify_f64 :: proc(x: f64) -> Float_Class { + switch { + case x == 0: + i := transmute(i64)x; + if i < 0 { + return .Neg_Zero; + } + return .Zero; + case x*0.5 == x: + if x < 0 { + return .Neg_Inf; + } + return .Inf; + case x != x: + return .NaN; + } + u := transmute(u64)x; + exp := int(u>>52) & (1<<11 - 1); + if exp == 0 { + return .Subnormal; + } + return .Normal; +} +classify :: proc{classify_f32, classify_f64}; + +is_nan_f32 :: proc(x: f32) -> bool { return classify(x) == .NaN; } +is_nan_f64 :: proc(x: f64) -> bool { return classify(x) == .NaN; } is_nan :: proc{is_nan_f32, is_nan_f64}; -is_finite_f32 :: inline proc(x: f32) -> bool { return !is_nan(x-x); } -is_finite_f64 :: inline proc(x: f64) -> bool { return !is_nan(x-x); } -is_finite :: proc{is_finite_f32, is_finite_f64}; - -is_inf_f32 :: proc(x: f32, sign := 0) -> bool { - return sign >= 0 && x > F32_MAX || sign <= 0 && x < -F32_MAX; -} -is_inf_f64 :: proc(x: f64, sign := 0) -> bool { - return sign >= 0 && x > F64_MAX || sign <= 0 && x < -F64_MAX; -} -// If sign > 0, is_inf reports whether f is positive infinity -// If sign < 0, is_inf reports whether f is negative infinity -// If sign == 0, is_inf reports whether f is either infinity +is_inf_f32 :: proc(x: f32) -> bool { return classify(abs(x)) == .Inf; } +is_inf_f64 :: proc(x: f64) -> bool { return classify(abs(x)) == .Inf; } is_inf :: proc{is_inf_f32, is_inf_f64}; -to_radians :: proc(degrees: f32) -> f32 { return degrees * TAU / 360; } -to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; } +is_power_of_two :: proc(x: int) -> bool { + return x > 0 && (x & (x-1)) == 0; +} - - - -mul :: proc{ - mat3_mul, - mat4_mul, mat4_mul_vec4, - quat_mul, quat_mulf, -}; - -div :: proc{quat_div, quat_divf}; - -inverse :: proc{mat4_inverse, quat_inverse}; -dot :: proc{vec_dot, quat_dot}; -cross :: proc{cross2, cross3}; - -vec_dot :: proc(a, b: $T/[$N]$E) -> E { - res: E; - for i in 0.. int { + k := x -1; + when size_of(int) == 8 { + k = k | (k >> 32); } - return res; + k = k | (k >> 16); + k = k | (k >> 8); + k = k | (k >> 4); + k = k | (k >> 2); + k = k | (k >> 1); + k += 1 + int(x <= 0); + return k; } -cross2 :: proc(a, b: $T/[2]$E) -> E { - return a[0]*b[1] - a[1]*b[0]; +sum :: proc(x: $T/[]$E) -> (res: E) + where intrinsics.BuiltinProc_type_is_numeric(E) { + for i in x { + res += i; + } + return; } -cross3 :: proc(a, b: $T/[3]$E) -> T { - i := swizzle(a, 1, 2, 0) * swizzle(b, 2, 0, 1); - j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0); - return T(i - j); +prod :: proc(x: $T/[]$E) -> (res: E) + where intrinsics.BuiltinProc_type_is_numeric(E) { + for i in x { + res *= i; + } + return; +} + +cumsum_inplace :: proc(x: $T/[]$E) -> T + where intrinsics.BuiltinProc_type_is_numeric(E) { + for i in 1.. E { return sqrt(dot(v, v)); } - -norm :: proc(v: $T/[$N]$E) -> T { return v / length(v); } - -norm0 :: proc(v: $T/[$N]$E) -> T { - m := length(v); - return m == 0 ? 0 : v/m; -} - - - -identity :: proc($T: typeid/[$N][N]$E) -> T { - m: T; - for i in 0.. M { - for j in 0.. T + where intrinsics.BuiltinProc_type_is_numeric(E) { + N := min(len(dst), len(src)); + if N > 0 { + dst[0] = src[0]; + for i in 1.. Mat3 { - c: Mat3; - for j in 0..<3 { - for i in 0..<3 { - c[j][i] = a[0][i]*b[j][0] + - a[1][i]*b[j][1] + - a[2][i]*b[j][2]; - } - } - return c; -} - -mat4_mul :: proc(a, b: Mat4) -> Mat4 { - c: Mat4; - for j in 0..<4 { - for i in 0..<4 { - c[j][i] = a[0][i]*b[j][0] + - a[1][i]*b[j][1] + - a[2][i]*b[j][2] + - a[3][i]*b[j][3]; - } - } - return c; -} - -mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 { - return Vec4{ - m[0][0]*v[0] + m[1][0]*v[1] + m[2][0]*v[2] + m[3][0]*v[3], - m[0][1]*v[0] + m[1][1]*v[1] + m[2][1]*v[2] + m[3][1]*v[3], - m[0][2]*v[0] + m[1][2]*v[1] + m[2][2]*v[2] + m[3][2]*v[3], - m[0][3]*v[0] + m[1][3]*v[1] + m[2][3]*v[2] + m[3][3]*v[3], - }; -} - -mat4_inverse :: proc(m: Mat4) -> Mat4 { - o: Mat4; - - sf00 := m[2][2] * m[3][3] - m[3][2] * m[2][3]; - sf01 := m[2][1] * m[3][3] - m[3][1] * m[2][3]; - sf02 := m[2][1] * m[3][2] - m[3][1] * m[2][2]; - sf03 := m[2][0] * m[3][3] - m[3][0] * m[2][3]; - sf04 := m[2][0] * m[3][2] - m[3][0] * m[2][2]; - sf05 := m[2][0] * m[3][1] - m[3][0] * m[2][1]; - sf06 := m[1][2] * m[3][3] - m[3][2] * m[1][3]; - sf07 := m[1][1] * m[3][3] - m[3][1] * m[1][3]; - sf08 := m[1][1] * m[3][2] - m[3][1] * m[1][2]; - sf09 := m[1][0] * m[3][3] - m[3][0] * m[1][3]; - sf10 := m[1][0] * m[3][2] - m[3][0] * m[1][2]; - sf11 := m[1][1] * m[3][3] - m[3][1] * m[1][3]; - sf12 := m[1][0] * m[3][1] - m[3][0] * m[1][1]; - sf13 := m[1][2] * m[2][3] - m[2][2] * m[1][3]; - sf14 := m[1][1] * m[2][3] - m[2][1] * m[1][3]; - sf15 := m[1][1] * m[2][2] - m[2][1] * m[1][2]; - sf16 := m[1][0] * m[2][3] - m[2][0] * m[1][3]; - sf17 := m[1][0] * m[2][2] - m[2][0] * m[1][2]; - sf18 := m[1][0] * m[2][1] - m[2][0] * m[1][1]; - - - o[0][0] = +(m[1][1] * sf00 - m[1][2] * sf01 + m[1][3] * sf02); - o[0][1] = -(m[1][0] * sf00 - m[1][2] * sf03 + m[1][3] * sf04); - o[0][2] = +(m[1][0] * sf01 - m[1][1] * sf03 + m[1][3] * sf05); - o[0][3] = -(m[1][0] * sf02 - m[1][1] * sf04 + m[1][2] * sf05); - - o[1][0] = -(m[0][1] * sf00 - m[0][2] * sf01 + m[0][3] * sf02); - o[1][1] = +(m[0][0] * sf00 - m[0][2] * sf03 + m[0][3] * sf04); - o[1][2] = -(m[0][0] * sf01 - m[0][1] * sf03 + m[0][3] * sf05); - o[1][3] = +(m[0][0] * sf02 - m[0][1] * sf04 + m[0][2] * sf05); - - o[2][0] = +(m[0][1] * sf06 - m[0][2] * sf07 + m[0][3] * sf08); - o[2][1] = -(m[0][0] * sf06 - m[0][2] * sf09 + m[0][3] * sf10); - o[2][2] = +(m[0][0] * sf11 - m[0][1] * sf09 + m[0][3] * sf12); - o[2][3] = -(m[0][0] * sf08 - m[0][1] * sf10 + m[0][2] * sf12); - - o[3][0] = -(m[0][1] * sf13 - m[0][2] * sf14 + m[0][3] * sf15); - o[3][1] = +(m[0][0] * sf13 - m[0][2] * sf16 + m[0][3] * sf17); - o[3][2] = -(m[0][0] * sf14 - m[0][1] * sf16 + m[0][3] * sf18); - o[3][3] = +(m[0][0] * sf15 - m[0][1] * sf17 + m[0][2] * sf18); - - ood := 1.0 / (m[0][0] * o[0][0] + - m[0][1] * o[0][1] + - m[0][2] * o[0][2] + - m[0][3] * o[0][3]); - - o[0][0] *= ood; - o[0][1] *= ood; - o[0][2] *= ood; - o[0][3] *= ood; - o[1][0] *= ood; - o[1][1] *= ood; - o[1][2] *= ood; - o[1][3] *= ood; - o[2][0] *= ood; - o[2][1] *= ood; - o[2][2] *= ood; - o[2][3] *= ood; - o[3][0] *= ood; - o[3][1] *= ood; - o[3][2] *= ood; - o[3][3] *= ood; - - return o; -} - - -mat4_translate :: proc(v: Vec3) -> Mat4 { - m := identity(Mat4); - m[3][0] = v[0]; - m[3][1] = v[1]; - m[3][2] = v[2]; - m[3][3] = 1; - return m; -} - -mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 { - c := cos(angle_radians); - s := sin(angle_radians); - - a := norm(v); - t := a * (1-c); - - rot := identity(Mat4); - - rot[0][0] = c + t[0]*a[0]; - rot[0][1] = 0 + t[0]*a[1] + s*a[2]; - rot[0][2] = 0 + t[0]*a[2] - s*a[1]; - rot[0][3] = 0; - - rot[1][0] = 0 + t[1]*a[0] - s*a[2]; - rot[1][1] = c + t[1]*a[1]; - rot[1][2] = 0 + t[1]*a[2] + s*a[0]; - rot[1][3] = 0; - - rot[2][0] = 0 + t[2]*a[0] + s*a[1]; - rot[2][1] = 0 + t[2]*a[1] - s*a[0]; - rot[2][2] = c + t[2]*a[2]; - rot[2][3] = 0; - - return rot; -} - -scale_vec3 :: proc(m: Mat4, v: Vec3) -> Mat4 { - mm := m; - mm[0][0] *= v[0]; - mm[1][1] *= v[1]; - mm[2][2] *= v[2]; - return mm; -} - -scale_f32 :: proc(m: Mat4, s: f32) -> Mat4 { - mm := m; - mm[0][0] *= s; - mm[1][1] *= s; - mm[2][2] *= s; - return mm; -} - -scale :: proc{scale_vec3, scale_f32}; - - -look_at :: proc(eye, centre, up: Vec3) -> Mat4 { - f := norm(centre - eye); - s := norm(cross(f, up)); - u := cross(s, f); - - return Mat4{ - {+s.x, +u.x, -f.x, 0}, - {+s.y, +u.y, -f.y, 0}, - {+s.z, +u.z, -f.z, 0}, - {-dot(s, eye), -dot(u, eye), dot(f, eye), 1}, - }; -} - -perspective :: proc(fovy, aspect, near, far: f32) -> Mat4 { - m: Mat4; - tan_half_fovy := tan(0.5 * fovy); - - m[0][0] = 1.0 / (aspect*tan_half_fovy); - m[1][1] = 1.0 / (tan_half_fovy); - m[2][2] = -(far + near) / (far - near); - m[2][3] = -1.0; - m[3][2] = -2.0*far*near / (far - near); - return m; -} - - -ortho3d :: proc(left, right, bottom, top, near, far: f32) -> Mat4 { - m := identity(Mat4); - m[0][0] = +2.0 / (right - left); - m[1][1] = +2.0 / (top - bottom); - m[2][2] = -2.0 / (far - near); - m[3][0] = -(right + left) / (right - left); - m[3][1] = -(top + bottom) / (top - bottom); - m[3][2] = -(far + near) / (far - near); - return m; -} - - -// Quaternion operations - -conj :: proc(q: Quat) -> Quat { - return Quat{-q.x, -q.y, -q.z, q.w}; -} - -quat_mul :: proc(q0, q1: Quat) -> Quat { - d: Quat; - d.x = q0.w * q1.x + q0.x * q1.w + q0.y * q1.z - q0.z * q1.y; - d.y = q0.w * q1.y - q0.x * q1.z + q0.y * q1.w + q0.z * q1.x; - d.z = q0.w * q1.z + q0.x * q1.y - q0.y * q1.x + q0.z * q1.w; - d.w = q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z; - return d; -} - -quat_mulf :: proc(q: Quat, f: f32) -> Quat { return Quat{q.x*f, q.y*f, q.z*f, q.w*f}; } -quat_divf :: proc(q: Quat, f: f32) -> Quat { return Quat{q.x/f, q.y/f, q.z/f, q.w/f}; } - -quat_div :: proc(q0, q1: Quat) -> Quat { return mul(q0, quat_inverse(q1)); } -quat_inverse :: proc(q: Quat) -> Quat { return div(conj(q), dot(q, q)); } -quat_dot :: proc(q0, q1: Quat) -> f32 { return q0.x*q1.x + q0.y*q1.y + q0.z*q1.z + q0.w*q1.w; } - -quat_norm :: proc(q: Quat) -> Quat { - m := sqrt(dot(q, q)); - return div(q, m); -} - -axis_angle :: proc(axis: Vec3, angle_radians: f32) -> Quat { - v := norm(axis) * sin(0.5*angle_radians); - w := cos(0.5*angle_radians); - return Quat{v.x, v.y, v.z, w}; -} - -euler_angles :: proc(pitch, yaw, roll: f32) -> Quat { - p := axis_angle(Vec3{1, 0, 0}, pitch); - y := axis_angle(Vec3{0, 1, 0}, yaw); - r := axis_angle(Vec3{0, 0, 1}, roll); - return mul(mul(y, p), r); -} - -quat_to_mat4 :: proc(q: Quat) -> Mat4 { - a := quat_norm(q); - xx := a.x*a.x; yy := a.y*a.y; zz := a.z*a.z; - xy := a.x*a.y; xz := a.x*a.z; yz := a.y*a.z; - wx := a.w*a.x; wy := a.w*a.y; wz := a.w*a.z; - - m := identity(Mat4); - - m[0][0] = 1 - 2*(yy + zz); - m[0][1] = 2*(xy + wz); - m[0][2] = 2*(xz - wy); - - m[1][0] = 2*(xy - wz); - m[1][1] = 1 - 2*(xx + zz); - m[1][2] = 2*(yz + wx); - - m[2][0] = 2*(xz + wy); - m[2][1] = 2*(yz - wx); - m[2][2] = 1 - 2*(xx + yy); - return m; -} - - - F32_DIG :: 6; F32_EPSILON :: 1.192092896e-07; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3c4d737a4..a3b8befa9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3344,7 +3344,7 @@ BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_end - BuiltinProc__ty -bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id) { +bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { ast_node(ce, CallExpr, call); if (ce->inlining != ProcInlining_none) { error(call, "Inlining operators are not allowed on built-in procedures"); @@ -3882,6 +3882,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } operand->mode = Addressing_Value; + if (type_hint != nullptr && check_is_castable_to(c, operand, type_hint)) { + operand->type = type_hint; + } + break; } @@ -3945,6 +3949,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 default: GB_PANIC("Invalid type"); break; } + if (type_hint != nullptr && check_is_castable_to(c, operand, type_hint)) { + operand->type = type_hint; + } + break; } @@ -4033,6 +4041,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 default: GB_PANIC("Invalid type"); break; } + if (type_hint != nullptr && check_is_castable_to(c, operand, type_hint)) { + operand->type = type_hint; + } + break; } @@ -4087,6 +4099,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 default: GB_PANIC("Invalid type"); break; } + if (type_hint != nullptr && check_is_castable_to(c, operand, type_hint)) { + operand->type = type_hint; + } + break; } @@ -4134,6 +4150,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 default: GB_PANIC("Invalid type"); break; } + if (type_hint != nullptr && check_is_castable_to(c, operand, type_hint)) { + operand->type = type_hint; + } + break; } @@ -6363,7 +6383,7 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper -ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) { +ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint) { ast_node(ce, CallExpr, call); if (ce->proc != nullptr && ce->proc->kind == Ast_BasicDirective) { @@ -6470,7 +6490,7 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) { if (operand->mode == Addressing_Builtin) { i32 id = operand->builtin_id; - if (!check_builtin_procedure(c, operand, call, id)) { + if (!check_builtin_procedure(c, operand, call, id, type_hint)) { operand->mode = Addressing_Invalid; } operand->expr = call; @@ -7930,7 +7950,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_ast_node(ce, CallExpr, node); - return check_call_expr(c, o, node); + return check_call_expr(c, o, node, type_hint); case_end; case_ast_node(de, DerefExpr, node); From d760b95e4fafd637a573bc1bd8879797eff0df8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Hjortsh=C3=B8j?= Date: Sun, 27 Oct 2019 18:02:39 +0100 Subject: [PATCH 131/143] Update ci.yml --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50ca88d95..d225bcfb9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,10 +33,11 @@ jobs: - name: Install cURL run: choco install curl - name: Download and unpack LLVM bins + shell: cmd + working-directory: run: | cd bin curl -sL https://github.com/odin-lang/Odin/releases/download/llvm-windows/llvm-binaries.zip --output llvm-binaries.zip - ls 7z x llvm-binaries.zip > nul - name: build Odin run: | From 684bf7aa61ce285d1ba2cd2f02a932106d02581b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Hjortsh=C3=B8j?= Date: Sun, 27 Oct 2019 18:04:14 +0100 Subject: [PATCH 132/143] Update ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d225bcfb9..59f47547b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: run: choco install curl - name: Download and unpack LLVM bins shell: cmd - working-directory: + working-directory: $GITHUB_WORKSPACE/odin/bin run: | cd bin curl -sL https://github.com/odin-lang/Odin/releases/download/llvm-windows/llvm-binaries.zip --output llvm-binaries.zip From 72cad591bd64ff221b01161856693b758d1c1417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Hjortsh=C3=B8j?= Date: Sun, 27 Oct 2019 18:07:14 +0100 Subject: [PATCH 133/143] Update ci.yml --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 59f47547b..b0f716db6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,6 @@ jobs: run: choco install curl - name: Download and unpack LLVM bins shell: cmd - working-directory: $GITHUB_WORKSPACE/odin/bin run: | cd bin curl -sL https://github.com/odin-lang/Odin/releases/download/llvm-windows/llvm-binaries.zip --output llvm-binaries.zip From a7a31e4c23ee2385e5cfa93863b3bb64aa88121c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Hjortsh=C3=B8j?= Date: Sun, 27 Oct 2019 18:12:23 +0100 Subject: [PATCH 134/143] Set CI shell on windows to cmd.exe --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0f716db6..7c43b01e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,14 +39,17 @@ jobs: curl -sL https://github.com/odin-lang/Odin/releases/download/llvm-windows/llvm-binaries.zip --output llvm-binaries.zip 7z x llvm-binaries.zip > nul - name: build Odin + shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat ./build_ci.bat - name: Odin run + shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat odin run examples/demo/demo.odin - name: Odin check + shell: cmd run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat odin check examples/demo/demo.odin -vet From a29a6d928562f9fac36d860ee9a1fb679ead57ae Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 27 Oct 2019 18:43:40 +0000 Subject: [PATCH 135/143] Fix typos in `package linalg`; Fix norm_float64 in `package rand` --- core/math/linalg/linalg.odin | 11 ++++++++--- core/math/rand/normal.odin | 4 ++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/core/math/linalg/linalg.odin b/core/math/linalg/linalg.odin index 9a4781668..66a11b47a 100644 --- a/core/math/linalg/linalg.odin +++ b/core/math/linalg/linalg.odin @@ -1,6 +1,7 @@ package linalg import "core:math" +import "intrinsics" // Generic @@ -78,9 +79,11 @@ transpose :: proc(a: $T/[$N][$M]$E) -> (m: ((M == N) ? T : [M][N]E)) { return; } -mul_matrix :: proc(a: $A/[$I][$J]$E, b: $B/[J][$K]E) -> (c: ((I == J && J == K && A == B) ? A : [I][K]E)) { +mul_matrix :: proc(a: $A/[$I][$J]$E, b: $B/[J][$K]E) -> (c: ((I == J && J == K && A == B) ? A : [I][K]E)) + where !intrinsics.type_is_array(E), + intrinsics.type_is_numeric(E) { for i in 0.. (c: ((I == J && J == K & return; } -mul_matrix_vector :: proc(a: $A/[$I][$J]$E, b: $B/[I]E) -> (c: B) { +mul_matrix_vector :: proc(a: $A/[$I][$J]$E, b: $B/[I]E) -> (c: B) + where !intrinsics.type_is_array(E), + intrinsics.type_is_numeric(E) { for i in 0.. f64 { if i == 0 { for { - x = -math.log(float64(r)) * (1.0/ rn); - y := -math.log(float64(r)); + x = -math.ln(float64(r)) * (1.0/ rn); + y := -math.ln(float64(r)); if y+y >= x*x { break; } From 416ff149bd0f3ae1ff7d8093450cf42fc4aa3994 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 27 Oct 2019 19:42:21 +0000 Subject: [PATCH 136/143] Fix procedure group "best fit" algorithm for polymorphic procedures --- core/math/linalg/linalg.odin | 27 ++++++++++++++++++++++++--- src/check_expr.cpp | 34 ++++++++++++++++++---------------- src/check_type.cpp | 7 ++++--- src/checker.hpp | 1 + 4 files changed, 47 insertions(+), 22 deletions(-) diff --git a/core/math/linalg/linalg.odin b/core/math/linalg/linalg.odin index 66a11b47a..ceef645cb 100644 --- a/core/math/linalg/linalg.odin +++ b/core/math/linalg/linalg.odin @@ -70,7 +70,7 @@ identity :: proc($T: typeid/[$N][N]$E) -> (m: T) { return m; } -transpose :: proc(a: $T/[$N][$M]$E) -> (m: ((M == N) ? T : [M][N]E)) { +transpose :: proc(a: $T/[$N][$M]$E) -> (m: [M][N]E) { for j in 0.. (m: ((M == N) ? T : [M][N]E)) { return; } -mul_matrix :: proc(a: $A/[$I][$J]$E, b: $B/[J][$K]E) -> (c: ((I == J && J == K && A == B) ? A : [I][K]E)) +mul_matrix :: proc(a, b: $M/[$N][N]$E) -> (c: M) where !intrinsics.type_is_array(E), intrinsics.type_is_numeric(E) { + for i in 0.. (c: [I][K]E) + where !intrinsics.type_is_array(E), + intrinsics.type_is_numeric(E), + I != J { for i in 0.. (c: ((I == J && J == K & return; } + mul_matrix_vector :: proc(a: $A/[$I][$J]$E, b: $B/[I]E) -> (c: B) where !intrinsics.type_is_array(E), intrinsics.type_is_numeric(E) { @@ -124,7 +139,13 @@ mul_quaternion256_vector3 :: proc(q: $Q/quaternion256, v: $V/[3]$F/f64) -> V { } mul_quaternion_vector3 :: proc{mul_quaternion128_vector3, mul_quaternion256_vector3}; -mul :: proc{mul_matrix, mul_matrix_vector, mul_quaternion128_vector3, mul_quaternion256_vector3}; +mul :: proc{ + mul_matrix, + mul_matrix_differ, + mul_matrix_vector, + mul_quaternion128_vector3, + mul_quaternion256_vector3, +}; // Specific diff --git a/src/check_expr.cpp b/src/check_expr.cpp index a3b8befa9..b5d24e008 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5855,6 +5855,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type } + if (proc_arg_count >= 0 && proc_arg_count_all_equal) { lhs_count = proc_arg_count; if (lhs_count > 0) { @@ -5898,9 +5899,8 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type gb_free(heap_allocator(), lhs); } - ValidIndexAndScore *valids = gb_alloc_array(heap_allocator(), ValidIndexAndScore, procs.count); - isize valid_count = 0; - defer (gb_free(heap_allocator(), valids)); + auto valids = array_make(heap_allocator(), 0, procs.count); + defer (array_free(&valids)); gbString expr_name = expr_to_string(operand->expr); defer (gb_string_free(expr_name)); @@ -5915,12 +5915,14 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type ctx.no_polymorphic_errors = true; ctx.allow_polymorphic_types = is_type_polymorphic(pt); + ctx.hide_polymorphic_errors = true; err = call_checker(&ctx, call, pt, p, operands, CallArgumentMode_NoErrors, &data); if (err != CallArgumentError_None) { continue; } + if (data.gen_entity != nullptr) { Entity *e = data.gen_entity; DeclInfo *decl = data.gen_entity->decl_info; @@ -5936,31 +5938,31 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type } } - valids[valid_count].index = i; - valids[valid_count].score = data.score; - valid_count++; + ValidIndexAndScore item = {}; + item.index = i; + item.score = data.score; + array_add(&valids, item); } } - if (valid_count > 1) { - gb_sort_array(valids, valid_count, valid_index_and_score_cmp); + if (valids.count > 1) { + gb_sort_array(valids.data, valids.count, valid_index_and_score_cmp); i64 best_score = valids[0].score; Entity *best_entity = procs[valids[0].index]; - for (isize i = 1; i < valid_count; i++) { + for (isize i = 1; i < valids.count; i++) { if (best_score > valids[i].score) { - valid_count = i; + valids.count = i; break; } if (best_entity == procs[valids[i].index]) { - valid_count = i; + valids.count = i; break; } - best_score = valids[i].score; } } - if (valid_count == 0) { + if (valids.count == 0) { begin_error_block(); defer (end_error_block()); @@ -6015,7 +6017,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type } result_type = t_invalid; - } else if (valid_count > 1) { + } else if (valids.count > 1) { begin_error_block(); defer (end_error_block()); @@ -6030,11 +6032,11 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type } error_line(")\n"); - for (isize i = 0; i < valid_count; i++) { + for (isize i = 0; i < valids.count; i++) { Entity *proc = procs[valids[i].index]; TokenPos pos = proc->token.pos; Type *t = base_type(proc->type); GB_ASSERT(t->kind == Type_Proc); - gbString pt; + gbString pt = nullptr; defer (gb_string_free(pt)); if (t->Proc.node != nullptr) { pt = expr_to_string(t->Proc.node); diff --git a/src/check_type.cpp b/src/check_type.cpp index da6419877..de33cc1a5 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1263,20 +1263,21 @@ bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Typ Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Operand operand) { bool modify_type = !ctx->no_polymorphic_errors; + bool show_error = modify_type && !ctx->hide_polymorphic_errors; if (!is_operand_value(operand)) { - if (modify_type) { + if (show_error) { error(operand.expr, "Cannot determine polymorphic type from parameter"); } return t_invalid; } if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) { - if (modify_type) { + if (show_error) { set_procedure_abi_types(ctx, poly_type); } return poly_type; } - if (modify_type) { + if (show_error) { gbString pts = type_to_string(poly_type); gbString ots = type_to_string(operand.type); defer (gb_string_free(pts)); diff --git a/src/checker.hpp b/src/checker.hpp index f86acce5c..c33514511 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -285,6 +285,7 @@ struct CheckerContext { bool collect_delayed_decls; bool allow_polymorphic_types; bool no_polymorphic_errors; + bool hide_polymorphic_errors; bool in_polymorphic_specialization; Scope * polymorphic_scope; }; From b5fdb3f855b145564836c7936691197f1021308d Mon Sep 17 00:00:00 2001 From: Kevin Watters Date: Mon, 28 Oct 2019 11:13:47 -0400 Subject: [PATCH 137/143] Remove unused variables in utf8.odin. --- core/unicode/utf8/utf8.odin | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/unicode/utf8/utf8.odin b/core/unicode/utf8/utf8.odin index c30f7b733..bbf3994cd 100644 --- a/core/unicode/utf8/utf8.odin +++ b/core/unicode/utf8/utf8.odin @@ -193,7 +193,6 @@ rune_string_at_pos :: proc(s: string, pos: int) -> string { } rune_at :: proc(s: string, byte_index: int) -> rune { - str := s[byte_index:]; r, _ := decode_rune_in_string(s[byte_index:]); return r; } @@ -206,7 +205,7 @@ rune_offset :: proc(s: string, pos: int, start: int = 0) -> int { } i := 0; - for c, offset in s[start:] { + for _, offset in s[start:] { if i == pos { return offset+start; } From fe5c642d9fe79f22586d54e10a98dd643199c608 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 29 Oct 2019 08:47:05 +0000 Subject: [PATCH 138/143] Fix `runtime.cstring_len` --- core/runtime/internal.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 630942805..164610ae6 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -348,12 +348,12 @@ string_le :: inline proc "contextless" (a, b: string) -> bool { return string_cm string_ge :: inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) >= 0; } cstring_len :: proc "contextless" (s: cstring) -> int { - n := 0; - p := uintptr((^byte)(s)); + p0 := uintptr((^byte)(s)); + p := p0; for p != 0 && (^byte)(p)^ != 0 { p += 1; } - return n; + return int(p - p0); } cstring_to_string :: proc "contextless" (s: cstring) -> string { From ee8d3e03f89b1f8065fc9563d84830482bc3f387 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Oct 2019 18:25:39 +0000 Subject: [PATCH 139/143] Delay determination of procedure abi types until as late as possible to prevent type undetermination in self-referential data types #454 --- src/check_expr.cpp | 4 ++-- src/check_type.cpp | 20 ++++++++++++-------- src/ir.cpp | 3 +++ src/ir_print.cpp | 5 +++++ src/types.cpp | 9 +++++++-- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b5d24e008..51497af7e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -89,7 +89,7 @@ Type * check_init_variable (CheckerContext *c, Entity *e, Operand * Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCallingConvention cc); Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCallingConvention cc); bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type *abi_return_type); -void set_procedure_abi_types(CheckerContext *c, Type *type); +void set_procedure_abi_types(gbAllocator a, Type *type); void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type); Entity *entity_from_expr(Ast *expr) { @@ -963,7 +963,7 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source, } if (modify_type) { - set_procedure_abi_types(c, source); + set_procedure_abi_types(c->allocator, source); } return true; diff --git a/src/check_type.cpp b/src/check_type.cpp index de33cc1a5..45c59f2bc 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1273,7 +1273,7 @@ Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Oper if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) { if (show_error) { - set_procedure_abi_types(ctx, poly_type); + set_procedure_abi_types(ctx->allocator, poly_type); } return poly_type; } @@ -2362,18 +2362,22 @@ bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type return false; } -void set_procedure_abi_types(CheckerContext *c, Type *type) { +void set_procedure_abi_types(gbAllocator allocator, Type *type) { type = base_type(type); if (type->kind != Type_Proc) { return; } - type->Proc.abi_compat_params = array_make(c->allocator, cast(isize)type->Proc.param_count); + if (type->Proc.abi_types_set) { + return; + } + + type->Proc.abi_compat_params = array_make(allocator, cast(isize)type->Proc.param_count); for (i32 i = 0; i < type->Proc.param_count; i++) { Entity *e = type->Proc.params->Tuple.variables[i]; if (e->kind == Entity_Variable) { Type *original_type = e->type; - Type *new_type = type_to_abi_compat_param_type(c->allocator, original_type, type->Proc.calling_convention); + Type *new_type = type_to_abi_compat_param_type(allocator, original_type, type->Proc.calling_convention); type->Proc.abi_compat_params[i] = new_type; switch (type->Proc.calling_convention) { case ProcCC_Odin: @@ -2387,8 +2391,10 @@ void set_procedure_abi_types(CheckerContext *c, Type *type) { } // NOTE(bill): The types are the same - type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results, type->Proc.calling_convention); - type->Proc.return_by_pointer = abi_compat_return_by_pointer(c->allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type); + type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(allocator, type->Proc.results, type->Proc.calling_convention); + type->Proc.return_by_pointer = abi_compat_return_by_pointer(allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type); + + type->Proc.abi_types_set = true; } // NOTE(bill): 'operands' is for generating non generic procedure type @@ -2486,8 +2492,6 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, } type->Proc.is_polymorphic = is_polymorphic; - set_procedure_abi_types(c, type); - return success; } diff --git a/src/ir.cpp b/src/ir.cpp index ae60be7e3..d4aecebf0 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3038,6 +3038,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array const &ar context_ptr = ir_find_or_generate_context_ptr(p); } + set_procedure_abi_types(heap_allocator(), pt); bool is_c_vararg = pt->Proc.c_vararg; isize param_count = pt->Proc.param_count; @@ -10019,6 +10020,8 @@ void ir_insert_code_before_proc(irProcedure* proc, irProcedure *parent) { void ir_build_proc(irValue *value, irProcedure *parent) { irProcedure *proc = &value->Proc; + set_procedure_abi_types(heap_allocator(), proc->type); + proc->parent = parent; if (proc->body != nullptr) { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 1d0c8af35..d47dfc898 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -323,12 +323,15 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) { void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) { + set_procedure_abi_types(heap_allocator(), t); + i64 word_bits = 8*build_context.word_size; t = base_type(t); GB_ASSERT(is_type_proc(t)); isize param_count = t->Proc.param_count; isize result_count = t->Proc.result_count; + ir_print_proc_results(f, m, t); ir_write_string(f, str_lit(" (")); if (t->Proc.return_by_pointer) { @@ -2125,6 +2128,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { + set_procedure_abi_types(heap_allocator(), proc->type); + if (proc->body == nullptr) { ir_write_str_lit(f, "declare "); // if (proc->tags & ProcTag_dll_import) { diff --git a/src/types.cpp b/src/types.cpp index 8ad352f62..bef69ee30 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -205,6 +205,7 @@ struct TypeUnion { Type * abi_compat_result_type; \ i32 variadic_index; \ bool variadic; \ + bool abi_types_set; \ bool require_results; \ bool c_vararg; \ bool is_polymorphic; \ @@ -2360,7 +2361,9 @@ i64 type_size_of(Type *t) { return 0; } // NOTE(bill): Always calculate the size when it is a Type_Basic - if (t->kind != Type_Basic && t->cached_size >= 0) { + if (t->kind == Type_Named && t->cached_size >= 0) { + + } else if (t->kind != Type_Basic && t->cached_size >= 0) { return t->cached_size; } TypePath path = {0}; @@ -2375,7 +2378,9 @@ i64 type_align_of(Type *t) { return 1; } // NOTE(bill): Always calculate the size when it is a Type_Basic - if (t->kind != Type_Basic && t->cached_align > 0) { + if (t->kind == Type_Named && t->cached_align >= 0) { + + } if (t->kind != Type_Basic && t->cached_align > 0) { return t->cached_align; } From 01dfb1dac8b71b2b84bb585395063c52779f5674 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Oct 2019 20:17:50 +0000 Subject: [PATCH 140/143] Fix double calling of lhs of logical binary expressions --- src/check_expr.cpp | 8 ++++++-- src/check_type.cpp | 29 +++++++++++++++++++---------- src/ir.cpp | 15 ++++++++------- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 51497af7e..8612167c9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -62,7 +62,7 @@ Type * make_optional_ok_type (Type *value); void check_type_decl (CheckerContext *c, Entity *e, Ast *type_expr, Type *def); Entity * check_selector (CheckerContext *c, Operand *operand, Ast *node, Type *type_hint); Entity * check_ident (CheckerContext *c, Operand *o, Ast *n, Type *named_type, Type *type_hint, bool allow_import_name); -Entity * find_polymorphic_record_entity (CheckerContext *c, Type *original_type, isize param_count, Array ordered_operands); +Entity * find_polymorphic_record_entity (CheckerContext *c, Type *original_type, isize param_count, Array const &ordered_operands, bool *failure); void check_not_tuple (CheckerContext *c, Operand *operand); void convert_to_typed (CheckerContext *c, Operand *operand, Type *target_type); gbString expr_to_string (Ast *expression); @@ -6336,12 +6336,16 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper { gbAllocator a = c->allocator; - Entity *found_entity = find_polymorphic_record_entity(c, original_type, param_count, ordered_operands); + bool failure = false; + Entity *found_entity = find_polymorphic_record_entity(c, original_type, param_count, ordered_operands, &failure); if (found_entity) { operand->mode = Addressing_Type; operand->type = found_entity->type; return err; } + if (failure) { + return CallArgumentError_NoneConstantParameter; + } String generated_name = make_string_c(expr_to_string(call)); diff --git a/src/check_type.cpp b/src/check_type.cpp index 45c59f2bc..ef68203ab 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -248,38 +248,47 @@ bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) { } -Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array ordered_operands) { +Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array const &ordered_operands, bool *failure) { auto *found_gen_types = map_get(&ctx->checker->info.gen_types, hash_pointer(original_type)); if (found_gen_types != nullptr) { for_array(i, *found_gen_types) { Entity *e = (*found_gen_types)[i]; Type *t = base_type(e->type); TypeTuple *tuple = get_record_polymorphic_params(t); - bool ok = true; GB_ASSERT(param_count == tuple->variables.count); + + bool skip = false; + for (isize j = 0; j < param_count; j++) { Entity *p = tuple->variables[j]; Operand o = ordered_operands[j]; if (p->kind == Entity_TypeName) { if (is_type_polymorphic(o.type)) { // NOTE(bill): Do not add polymorphic version to the gen_types - ok = false; - } - if (!are_types_identical(o.type, p->type)) { - ok = false; + skip = true; + break; + } else if (!are_types_identical(o.type, p->type)) { + skip = true; + break; } } else if (p->kind == Entity_Constant) { - if (!are_types_identical(o.type, p->type)) { - ok = false; + if (o.mode != Addressing_Constant) { + if (failure) *failure = true; + skip = true; + break; } if (!compare_exact_values(Token_CmpEq, o.value, p->Constant.value)) { - ok = false; + skip = true; + break; + } else if (!are_types_identical(o.type, p->type)) { + skip = true; + break; } } else { GB_PANIC("Unknown entity kind"); } } - if (ok) { + if (!skip) { return e; } } diff --git a/src/ir.cpp b/src/ir.cpp index d4aecebf0..e7317a960 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5647,7 +5647,8 @@ irValue *ir_emit_logical_binary_expr(irProcedure *proc, TokenKind op, Ast *left, } ir_start_block(proc, rhs); - array_add(&edges, ir_build_expr(proc, right)); + irValue *edge = ir_build_expr(proc, right); + array_add(&edges, edge); ir_emit_jump(proc, done); ir_start_block(proc, done); @@ -5656,8 +5657,6 @@ irValue *ir_emit_logical_binary_expr(irProcedure *proc, TokenKind op, Ast *left, irValue *ir_emit_logical_binary_expr(irProcedure *proc, Ast *expr) { ast_node(be, BinaryExpr, expr); - irBlock *rhs = ir_new_block(proc, nullptr, "logical.cmp.rhs"); - irBlock *done = ir_new_block(proc, nullptr, "logical.cmp.done"); Type *type = type_of_expr(expr); type = default_type(type); @@ -6879,9 +6878,6 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { case_end; case_ast_node(be, BinaryExpr, expr); - irValue *left = ir_build_expr(proc, be->left); - Type *type = default_type(tv.type); - switch (be->op.kind) { case Token_Add: case Token_Sub: @@ -6895,6 +6891,8 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { case Token_AndNot: case Token_Shl: case Token_Shr: { + irValue *left = ir_build_expr(proc, be->left); + Type *type = default_type(tv.type); irValue *right = ir_build_expr(proc, be->right); return ir_emit_arith(proc, be->op.kind, left, right, type); } @@ -6906,10 +6904,11 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { case Token_LtEq: case Token_Gt: case Token_GtEq: { + irValue *left = ir_build_expr(proc, be->left); + Type *type = default_type(tv.type); irValue *right = ir_build_expr(proc, be->right); irValue *cmp = ir_emit_comp(proc, be->op.kind, left, right); return ir_emit_conv(proc, cmp, type); - break; } case Token_CmpAnd: @@ -6919,6 +6918,8 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { case Token_in: case Token_notin: { + irValue *left = ir_build_expr(proc, be->left); + Type *type = default_type(tv.type); irValue *right = ir_build_expr(proc, be->right); Type *rt = base_type(ir_type(right)); switch (rt->kind) { From 560bdc339b1137ab6f52878a13dce0a4742b6153 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Oct 2019 22:39:12 +0000 Subject: [PATCH 141/143] Fix stack overflow bug caused by polymorphic record with polymorphic constant parameters. #447 DOES NOT FIX THE UNDERLYING BUG --- src/check_expr.cpp | 8 ++++---- src/check_type.cpp | 18 +++++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8612167c9..254a7ce51 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6343,9 +6343,8 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper operand->type = found_entity->type; return err; } - if (failure) { - return CallArgumentError_NoneConstantParameter; - } + + String generated_name = make_string_c(expr_to_string(call)); @@ -6458,7 +6457,8 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Type *t Ast *s = ident->SelectorExpr.selector; ident = s; } - Type *ot = operand->type; GB_ASSERT(ot->kind == Type_Named); + Type *ot = operand->type; + GB_ASSERT(ot->kind == Type_Named); Entity *e = ot->Named.type_name; add_entity_use(c, ident, e); add_type_and_value(&c->checker->info, call, Addressing_Type, ot, empty_exact_value); diff --git a/src/check_type.cpp b/src/check_type.cpp index ef68203ab..cf5855a3e 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -262,25 +262,29 @@ Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, for (isize j = 0; j < param_count; j++) { Entity *p = tuple->variables[j]; Operand o = ordered_operands[j]; + Entity *oe = entity_of_node(o.expr); + if (p == oe) { + // NOTE(bill): This is the same type, make sure that it will be be same thing and use that + // Saves on a lot of checking too below + continue; + } + if (p->kind == Entity_TypeName) { if (is_type_polymorphic(o.type)) { // NOTE(bill): Do not add polymorphic version to the gen_types skip = true; break; - } else if (!are_types_identical(o.type, p->type)) { + } + if (!are_types_identical(o.type, p->type)) { skip = true; break; } } else if (p->kind == Entity_Constant) { - if (o.mode != Addressing_Constant) { - if (failure) *failure = true; - skip = true; - break; - } if (!compare_exact_values(Token_CmpEq, o.value, p->Constant.value)) { skip = true; break; - } else if (!are_types_identical(o.type, p->type)) { + } + if (!are_types_identical(o.type, p->type)) { skip = true; break; } From a20c31d6b509076141fe69f33d2fe3b465122f78 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Oct 2019 22:58:38 +0000 Subject: [PATCH 142/143] Fix polymorphic record parameter determination bug caused by polymorphic constants not being handled correctly #447 --- src/check_expr.cpp | 2 -- src/check_type.cpp | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 254a7ce51..fae38fa01 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6344,8 +6344,6 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper return err; } - - String generated_name = make_string_c(expr_to_string(call)); CheckerContext ctx = *c; diff --git a/src/check_type.cpp b/src/check_type.cpp index cf5855a3e..9f8310e44 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -461,6 +461,10 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< e = alloc_entity_type_name(scope, token, operand.type); e->TypeName.is_type_alias = true; } else { + if (is_type_polymorphic(base_type(operand.type))) { + is_polymorphic = true; + can_check_fields = false; + } e = alloc_entity_constant(scope, token, operand.type, operand.value); } } else { From 44a303e5778fb8564964d53523634f34f8589489 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 1 Nov 2019 19:00:23 +0000 Subject: [PATCH 143/143] Add dummy packages purely for documentation of `builtin` and `intrinsics` --- core/builtin/builtin.odin | 105 ++++++++++++++++++++++++++ core/intrinsics/intrinsics.odin | 126 ++++++++++++++++++++++++++++++++ 2 files changed, 231 insertions(+) create mode 100644 core/builtin/builtin.odin create mode 100644 core/intrinsics/intrinsics.odin diff --git a/core/builtin/builtin.odin b/core/builtin/builtin.odin new file mode 100644 index 000000000..74ade0260 --- /dev/null +++ b/core/builtin/builtin.odin @@ -0,0 +1,105 @@ +// This is purely for documentation +package builtin + +nil :: nil; +false :: 0!==0; +true :: 0==0; + +ODIN_OS :: ODIN_OS; +ODIN_ARCH :: ODIN_ARCH; +ODIN_ENDIAN :: ODIN_ENDIAN; +ODIN_VENDOR :: ODIN_VENDOR; +ODIN_VERSION :: ODIN_VERSION; +ODIN_ROOT :: ODIN_ROOT; +ODIN_DEBUG :: ODIN_DEBUG; + +byte :: u8; // alias + +bool :: bool; +b8 :: b8; +b16 :: b16; +b32 :: b32; +b64 :: b64; + +i8 :: i8; +u8 :: u8; +i16 :: i16; +u16 :: u16; +i32 :: i32; +u32 :: u32; +i64 :: i64; +u64 :: u64; + +i128 :: i128; +u128 :: u128; + +rune :: rune; + +f16 :: f16; +f32 :: f32; +f64 :: f64; + +complex32 :: complex32; +complex64 :: complex64; +complex128 :: complex128; + +quaternion128 :: quaternion128; +quaternion256 :: quaternion256; + +int :: int; +uint :: uint; +uintptr :: uintptr; + +rawptr :: rawptr; +string :: string; +cstring :: cstring; +any :: any; + +typeid :: typeid; + +// Endian Specific Types +i16le :: i16le; +u16le :: u16le; +i32le :: i32le; +u32le :: u32le; +i64le :: i64le; +u64le :: u64le; +i128le :: i128le; +u128le :: u128le; + +i16be :: i16be; +u16be :: u16be; +i32be :: i32be; +u32be :: u32be; +i64be :: i64be; +u64be :: u64be; +i128be :: i128be; +u128be :: u128be; + +// Procedures +len :: proc(array: Array_Type) -> int --- +cap :: proc(array: Array_Type) -> int --- + +size_of :: proc($T: typeid) -> int --- +align_of :: proc($T: typeid) -> int --- +offset_of :: proc($T: typeid) -> uintptr --- +type_of :: proc(x: expr) -> type --- +type_info_of :: proc($T: typeid) -> ^runtime.Type_Info --- +typeid_of :: proc($T: typeid) -> typeid --- + +swizzle :: proc(x: [N]T, indices: ..int) -> [len(indices)]T --- + +complex :: proc(real, imag: Float) -> Complex_Type --- +quaternion :: proc(real, imag, jmag, kmag: Float) -> Quaternion_Type --- +real :: proc(value: Complex_Or_Quaternion) -> Float --- +imag :: proc(value: Complex_Or_Quaternion) -> Float --- +jmag :: proc(value: Quaternion) -> Float --- +kmag :: proc(value: Quaternion) -> Float --- +conj :: proc(value: Complex_Or_Quaternion) -> Complex_Or_Quaternion --- + +expand_to_tuple :: proc(value: Struct_Or_Array) -> (A, B, C, ...) --- + +min :: proc(values: ..T) -> T --- +max :: proc(values: ..T) -> T --- +abs :: proc(value: T) -> T --- +clamp :: proc(value, minimum, maximum: T) -> T --- diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin new file mode 100644 index 000000000..8ee12554c --- /dev/null +++ b/core/intrinsics/intrinsics.odin @@ -0,0 +1,126 @@ +// This is purely for documentation +package intrinsics + + +vector :: proc() --- + +atomic_fence :: proc() --- +atomic_fence_acq :: proc() --- +atomic_fence_rel :: proc() --- +atomic_fence_acqrel :: proc() --- + +atomic_store :: proc(dst: ^$T, val: $T) --- +atomic_store_rel :: proc(dst: ^$T, val: $T) --- +atomic_store_relaxed :: proc(dst: ^$T, val: $T) --- +atomic_store_unordered :: proc(dst: ^$T, val: $T) --- + +atomic_load :: proc(dst: ^$T) -> T --- +atomic_load_acq :: proc(dst: ^$T) -> T --- +atomic_load_relaxed :: proc(dst: ^$T) -> T --- +atomic_load_unordered :: proc(dst: ^$T) -> T --- + +atomic_add :: proc(dst; ^$T, val: $T) -> T --- +atomic_add_acq :: proc(dst; ^$T, val: $T) -> T --- +atomic_add_rel :: proc(dst; ^$T, val: $T) -> T --- +atomic_add_acqrel :: proc(dst; ^$T, val: $T) -> T --- +atomic_add_relaxed :: proc(dst; ^$T, val: $T) -> T --- +atomic_sub :: proc(dst; ^$T, val: $T) -> T --- +atomic_sub_acq :: proc(dst; ^$T, val: $T) -> T --- +atomic_sub_rel :: proc(dst; ^$T, val: $T) -> T --- +atomic_sub_acqrel :: proc(dst; ^$T, val: $T) -> T --- +atomic_sub_relaxed :: proc(dst; ^$T, val: $T) -> T --- +atomic_and :: proc(dst; ^$T, val: $T) -> T --- +atomic_and_acq :: proc(dst; ^$T, val: $T) -> T --- +atomic_and_rel :: proc(dst; ^$T, val: $T) -> T --- +atomic_and_acqrel :: proc(dst; ^$T, val: $T) -> T --- +atomic_and_relaxed :: proc(dst; ^$T, val: $T) -> T --- +atomic_nand :: proc(dst; ^$T, val: $T) -> T --- +atomic_nand_acq :: proc(dst; ^$T, val: $T) -> T --- +atomic_nand_rel :: proc(dst; ^$T, val: $T) -> T --- +atomic_nand_acqrel :: proc(dst; ^$T, val: $T) -> T --- +atomic_nand_relaxed :: proc(dst; ^$T, val: $T) -> T --- +atomic_or :: proc(dst; ^$T, val: $T) -> T --- +atomic_or_acq :: proc(dst; ^$T, val: $T) -> T --- +atomic_or_rel :: proc(dst; ^$T, val: $T) -> T --- +atomic_or_acqrel :: proc(dst; ^$T, val: $T) -> T --- +atomic_or_relaxed :: proc(dst; ^$T, val: $T) -> T --- +atomic_xor :: proc(dst; ^$T, val: $T) -> T --- +atomic_xor_acq :: proc(dst; ^$T, val: $T) -> T --- +atomic_xor_rel :: proc(dst; ^$T, val: $T) -> T --- +atomic_xor_acqrel :: proc(dst; ^$T, val: $T) -> T --- +atomic_xor_relaxed :: proc(dst; ^$T, val: $T) -> T --- + +atomic_xchg :: proc(dst; ^$T, val: $T) -> T --- +atomic_xchg_acq :: proc(dst; ^$T, val: $T) -> T --- +atomic_xchg_rel :: proc(dst; ^$T, val: $T) -> T --- +atomic_xchg_acqrel :: proc(dst; ^$T, val: $T) -> T --- +atomic_xchg_relaxed :: proc(dst; ^$T, val: $T) -> T --- + +atomic_cxchg :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchg_acq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchg_rel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchg_acqrel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchg_relaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchg_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchg_failacq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchg_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchg_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- + +atomic_cxchgweak :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchgweak_acq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchgweak_rel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchgweak_acqrel :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchgweak_relaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchgweak_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchgweak_failacq :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchgweak_acq_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- +atomic_cxchgweak_acqrel_failrelaxed :: proc(dst: ^$T, old, new: T) -> (T, /*option*/bool) --- + + +// Constant type tests + +type_base_type :: proc($T: typeid) -> type --- +type_core_type :: proc($T: typeid) -> type --- +type_elem_type :: proc($T: typeid) -> type --- + +type_is_boolean :: proc($T: typeid) -> bool --- +type_is_integer :: proc($T: typeid) -> bool --- +type_is_rune :: proc($T: typeid) -> bool --- +type_is_float :: proc($T: typeid) -> bool --- +type_is_complex :: proc($T: typeid) -> bool --- +type_is_quaternion :: proc($T: typeid) -> bool --- +type_is_string :: proc($T: typeid) -> bool --- +type_is_typeid :: proc($T: typeid) -> bool --- +type_is_any :: proc($T: typeid) -> bool --- + +type_is_endian_little :: proc($T: typeid) -> bool --- +type_is_endian_big :: proc($T: typeid) -> bool --- +type_is_numeric :: proc($T: typeid) -> bool --- +type_is_ordered :: proc($T: typeid) -> bool --- +type_is_ordered_numeric :: proc($T: typeid) -> bool --- +type_is_indexable :: proc($T: typeid) -> bool --- +type_is_sliceable :: proc($T: typeid) -> bool --- +type_is_simple_compare :: proc($T: typeid) -> bool --- // easily compared using memcmp +type_is_dereferenceable :: proc($T: typeid) -> bool --- +type_is_valid_map_key :: proc($T: typeid) -> bool --- + +type_is_named :: proc($T: typeid) -> bool --- +type_is_pointer :: proc($T: typeid) -> bool --- +type_is_opaque :: proc($T: typeid) -> bool --- +type_is_array :: proc($T: typeid) -> bool --- +type_is_slice :: proc($T: typeid) -> bool --- +type_is_dynamic_array :: proc($T: typeid) -> bool --- +type_is_map :: proc($T: typeid) -> bool --- +type_is_struct :: proc($T: typeid) -> bool --- +type_is_union :: proc($T: typeid) -> bool --- +type_is_enum :: proc($T: typeid) -> bool --- +type_is_proc :: proc($T: typeid) -> bool --- +type_is_bit_field :: proc($T: typeid) -> bool --- +type_is_bit_field_value :: proc($T: typeid) -> bool --- +type_is_bit_set :: proc($T: typeid) -> bool --- +type_is_simd_vector :: proc($T: typeid) -> bool --- + +type_has_nil :: proc($T: typeid) -> bool --- + +type_proc_parameter_count :: proc($T: typeid) -> int where type_is_proc(T) --- +type_proc_return_count :: proc($T: typeid) -> int where type_is_proc(T) ---

w_FTI{DyAq6Sybt zcf*HY+fHT0Q}=T1=e}ddb7RzWmRqRM(@(8W(r@R8C`fsEnt+f6-W*V)9Y|dOO|Ll% zH%SLLq2TBIeEu0w1L$43_GyEuXCmA)mTI2W8VKTLU|<9Qe=3*Hh}*J`-ypSgU6tcp zWCa6mQm^*Do=LAeaaAoyR`Gci^9}lu=o<)6t^ovG<8uR{X2I6>_4s^(TVz$u_PzH?JVrp_7AiAQmIuM8KP0pM6x zzK`>AGowhE?@E@qt5e`~A-CC#Z)c4|F-kXYI1~WcXviMeGDPnlXW7TL-5c z7-h91U+V$ns%5@?p+cj8291T|ao1?Yh{83x#w1wDfCvemC|rULE;G$0`PMsaI0jb{w~sY6Xg(_IrgZzqxy{jiLb2a`M7A{?G9yzmYU;JnuWU9|MA& ztG5SW_^ojP-k`+@F?q*CJ_o(*RGy@18DnhRA7mZIKGm;+tz`mczCO5dKo-^x&mhlkQW;5G^m}w za-F+I+=4SfGwJ;7Ruk$HZ0$R7Gm93uq6eVOKPSjJ;<|DJ*SMP*^$3uRYmhYg;Foxj z5Q@{lYAKj#T}hV#^Q7(-@e*C~9y~H_=$kSD6Ziyel8z%#LG|ILib*qVX!=Et*OVG7 zn1#0Py|3TX<;&okl*Lwf6@{*(z6F3}91w5L^7ep`968)& z;b#L*he?+*9{;9sDr9A6m!D}p)Uzb{yFSjKXp}^m;^?R=EA&qJ^K35=ynYBn(EY=?SYr~~GScknMh5YkucN8Uwb`=v^IiP2C4v9*&P}9u`yq1t$$S>sUkH)Td z&THpDzWKBiAL6_WKE}Z-(x$(e&+L>DpC$(4aa&2+I=PpV9d_!W0C}NJj|NqKJ0MIV zkr}|9K*G$;afqb@2lAW<){?2P+ijf;O z9eYl!1mMl07TRh@I}vAuH&tL~kitibR= zVV#lg{2emq9pu1Lsu|y*o1zE|NV&uVy=dyoeaVy;D24&>>(EV^q|jQ6-^r=OgOrI; z@#D{ceI{_X1iKa5L}}0txDIz302`#j!b_7`Wt;?|(Zv1ylpVNoF9i-2lp5G2X^ix@ z_nhTm1X8rFWOJN0y$5N-15_}}`&?BIqUK#6`7B36ddoMb8Q6S71k7weYZ<3JC0aG(tYh6W@34N^Yx!M+-py8Bn=EwhF*ddr68(;=-4Dsr7AR2b_S<&6&pf z>Ab6UpIn=R0{*fOp?%1?^Op4?pAC+MK<~S9!E@w#*bh+ArZo1u8Ln!|JA_7gpt|e&bl3izZ=%pq zn|1YvLWMR#8uachwS++B&m?T%IzZEKicM=)1(enXwuP+d+PH+hBBUR*y=7xw{Nsk)3Xd$$l84N5w>;E<3GieYVK6eMQ1FF*C*2~}EpatF zP_}H?A6I-AhKYUM^2bVV9eyl(j|AyCZ}WBE@f2E zC0pLA&7vKFT<+SqJ`pWw{oABf3!8<5%`PvqI+n=sQlBoqI|U;Z&g?(T-AyOxp;LAtv^LIDYX_YhEOI=(h*Fd+246kISv+ zJV~Xa8>@Zc_qJ4O#Z7KcCRU;-@@mlorS4tauF39Nym+50{%N{-M5t6ymcKyB`ur*{ z8AZmuJ$gPmLnF@U1>txIzr_are8XHtA(UJ;M)MChJ4-zW&;s13k6N{2t-+3{0fd}U zt}=FHPwe)}qF|Pw63Car`U`g?gP_$_4e3AVn&I?kNwU=!iWfqn-}wWlC67!^VY|z= zB}9y2`te`7e8(BO6P@nSvBQ{Nmyu2`xL)22o!LKaI48`l zo)^-e`D?upI23RC#YO;9Z*d?>F}q{uMmGUiAYD#!&Z$p)i{VSpgNju9$3h}zY`Z$h zwi3R0a5v;!0<-N}abheOW}jT8*H>s8UI!_FG^ROq4AWpxyRSicu7O|Q=|plBTiikC zHN<|8$XW0EpB55* z)xoNu^sM9**h$mXPTf0LJXRt%JEpu@K#st-wptA|fxR}Tps(KxI>AVCy7-2b3tz7` z=&Q*p2B(a!n$*2YV*sf`{1M+=+o}j;;&zeyI-C;diN@W@h6N+Ve`~dh{k!E{bGvf7 zgmLCRv&882%Lx_o(7murhY|O8VYQnip(Qw|b3*!=wRQ&}Y!Q;2r^850u`Q|A4AOq{ z|Fr-z-MHFF`-Za;wQy2il0EtIVU$`UJmYK3xdgsq8=;z*3r~VeIxYXbZP^iP$DV3m z%Vm%IEO@QEhWsrK995}EAN`QvNU`omp!H;9CNq0N0Nk(XQw4M7r#`cKg)|64pmInZjbUu+yhNsU3#x7 z_Ourx2}N?nM@F|Sie+DS_$(1172gSSe_C3i<&qvTme(5nh&}fH#H!U^jU*Xqw5MWUD=%s7ETgzBE$w@;Wgk(O8x4GlJ;~qI z3%XH}nw4@~3%rv9o=XLZ;_iZV??BcyA)2%t82z-QE|pETYLaL0DKImpl4t7L3o1Ts zhxm)PHN)GT0px9}GAg`Zb)K0+>Q+08y3~!JTD5FW!z$3%Kv-e)m=kqrK*CzmR%KyD z!-=Hc z@Q4h|lkIU#zK&@PnlD%i4dIw$&0b!#8a~lTyJ4`#figGmX$AeBJU?x@fCI z$v&~>yq@6fWj>wyYN^aI-k+S{3$E}5EL1I5` z8^9-BCXaR{z1}25EeIgxgFd|VldEx|s>`tqQjnS83-}PHJA&be77w`WN%<0G1JYY3 zkX|SuDwm!gYzjvYHeGETWK(08S~J+N=j}05 zc2zG&zOl`?odaN5!iKJk(wCTg1FNZ3xS~qQ;|i2sij>vG#6`pLN}h~sqB?E^x8Ol9 zXI~>BFNI>200go7iSePyV#*YS=5{*3%Db*MXXjw}nU)*JQ^U!YnRyE-I0%cB0u%R; z>m3BE0N7pi)^cb=_G!e6M}*kh@6M(LmOL#>5W!V6|SUQFvF5b@Kg@@u~=me%uJswW?LBZv+0F7J5W9dIvP+(4_=)u z%osGlQ!{Z?%|~)J_)8ITT!o_KXmO>jaWv=4j7^w0rrWRsyufYV<0!nT*%295lyrNY zzfn3G(ptbcJ{2K9DXe>|j%e{joeZBtxxri#bDW|~BITu1NxEYfTsnixf}N+^tUv9{ zo@l3y`+i5*#TOPbeI>*r#4GCc+{)~b*K>$(X9r=OaUr8K0dDepbW_zk2ETGF-bup! zKT(l<@hb@f*A8>h9@g}1aZid{wEQueJI6TqBG&Pla$C~fXWX^S0*yhj4nI%vB zj_Gy)ymG?mCcd^Ee=49Aoto@v7K%!YY%EI@>x1C~#X$u+1b^HQBmHkahHK+nJWQ0vRuN{XTXuZ+Rj^E;wfktzQ_jDfuS2kJR z8;2spKd8D7QUSAozq7kc?Sa(1%V1vF!vn%%A7I&(xi5>BR-lj?7K2d6Zo| z)PAuh9yjdDcc_7Pdm6f0gHdK;Jk#_bu2YJwG39%)Kza)jXgbfCjaA-|sr>gv*soQtPoMr{A_G@N#l_vrxe;`cra@ zODybib8XvgqF;lN%Z01w?8WYcz5|~nvgNm@Mc#J0QfVgD&9^OCkgu+udkr5b!-m}Q zE||qjKRQ?2a9T(hfEdfZRuWnO51@Nn#TefGrhl9syjdSU(go452MiWqN7b>vc$3id z^p|!n6sU_p42T>*{?za2LCbu9P$GbzHkD!}oos8T#r0F8rUD58+to|eh9YgAA50RQ zbFH?OR4*h`FiIje35PuCC)q0jkn#e?**vtNqO1eIt5Imok^ZEbacGM-&XhP?DypNF zp{BolWwpHD(vPg~vl>{dOqO^F&wRO|&#-CyR+lsMxE|hSTX$v}l7c_oDxTvkxCPy< zRv<(20E4p~-}3hAQ1b=?Nim8&`n*4gpK~So9rOKo46P+sA~gJdSYMl2`=b;>%EPU` zA1xbr>pv3k#a*_JOy9&MH2qoGjv^OMy%#j7iFZ-Dy521O)!?k6=4*Krbh_A!Zm-$2 z-FHL$U|{yFcwJJ2om^dExz)2BW*7g41WvQxL{X)?KbBQ0G=}HYSAkN=;bPd2wycdX zl6w+aTF>-$(buo8TYvjcB*k7?)uv_)-1cKPCYPn|Uy;+Bod7tFT8rq8hdTc&q*-f^b35ayVw;(j%=c|pZT~42 zSdC%^(FaeTuDN?-2Y+i%rMY+L(|F4~71~!9+A*~;JJS=DjmVf|-*LKcuBB+%U zRcK%9+q<8TC65FfT)wA(J^~{8r!hwbb2!8+on{#YHk+PGTwLRj{0i~duj6eTYF^q; z+1Fmi>7z%!R9m2c{R)a$HzNt-rev(W2ktM|lo!inryjY{4ap52o)q*?+aQS9Iaj^c zJD8SLYO>u?ulhTS9<(|@`eUOvyk3a`ISBS^%Jvknu4q%>^D zpAPrX>P0awj2PlB8#W+{d29@!5D>dGCLwhw9hz`i(D71n+f8py0V0gjlDg_r&m4yY z0y^i2nzNjD4Mbgj%>9V&=6F2)$AhTka+TgNSF|?W#5A&kV1yOM8h!E|ul@#M z%K|j!Yyd>2g-TR32_@e&^1Xv1Ccfymzx{d8F!m4@SYPpUk|V(sN?-Cn$^4OIM{aX8 zDY-Q2Hl3vFY-H-heqqes6*+g$aadm(@W`l$n{Bv%-#xjLT+!xmn03NXWJ@001KMAq$s(!x zk~X0E5exO|pYwkp3EX@mgvQHgb(z+saFCVGU)4d7;C+t(eg)K>zJB(TQBy5=#tOB1 zgPwHs(~8qL5%pImJC-CWy_hSM2ANui4t5H696-bs+F^%+m5#VH?_C}ha7zxbfl6$;)fif@0dDhxuh1`0wV{O6j2 z%N=~?iqFqEPrQpBmK=2JY^eTpYUb79GpF~Fu&G=7I~1I)B)#&yHM_aj}moDv6=7edNz{ZMh@9iH)#yEA%tdX+=j zm#H|pEtRCk5_0~nCIy3ibvKS_ncQ@Tys#{`0ctDZ&i;aUJ$iFf&=Lx%+R~M+bPg5^Ej9T5;Tv5<~ns%;!s0ZY{4+AnNE(hCfEOH9ZVXe?1bj1HZrqegvSU0w)e z7#uz%ap8Pkx_&i5weE!${P)jA2k9vC-MtG}_$8KB6thJ3S^3%Fkf@X1p4e;hX!$-N zEpy`sub;aZZuFX#i#G9}N8~t|Gz8O%=yv>Xt=NjNBCLe&I*w&IPjpe%SXG&aco%~j`p06tArdZ-zm6w z!Y21~_ZhLM9+E5w;TpN}zjF0yiDc;Ky)|ZRJL7)5?QBDs$`{85m?U@N%N0AXnAEwk z@+KtL%(vh?7SWsK*KwoG*P*pfo!mHP5fi6oSrh)-=hwK@x7X`z*RQI}Wn~5m+)f>5 zKkUtBna+4>HLlo*bdm=VFGN(+O+Jpb(u$d#UW#wyGW56@vedF?dI;z($R52B)73nr zITP8SdV!CH_<8M=WH!pM<*AT>QMC_090uCYjx8~vHo3R&0D0z3oa|y4G`P`Ef!3^b zzi94NzTn*ul_y+|oi7p&sd%zRS2V-LBlX^}T>IR~1Thb2nUkko*YZg8nFy{Eu>9ko z=F)*|I6!O~#U;V7fehMcO7|bA;>pqkYmR+& z5%@q8$6wg1L|1y|i|gf765S7izpjvboNtqhQ|;wZ+gWRrHzED|ayT^gTA#^6e5ebe zO%nir?RGw8sv<-kjkW|W{GNvdS(uW5SBW$pr!su{t^hb{5`!79vg$wf2+asLLjOpu zCaT!6oE(sx3LttTOY8lsezW&j{MR0{gCvwNIA6ljbuwB zmTNfiW{qTz+?xkrU;MC-_e`oATw*FA5d~>Gw+NnCF#G629Z>YFpD$_XZXfjBn+_}9 zid{{h?f8Wj^pa$YdH96R>rEiYMzcJDDlt3)k#EF8>0x2r$gaSCFszPSIS zs+IlhFtH6C#R45t>1bO7ys%jstI0D@{qW`)cMo*0B(O4hkGWLN_Bj$%sybkQ9QAuh z)oi|T!(bD31D0~RBr{<4oPQIM^LRbTD4e z#_sLZQ`G?GIz7{{9s8;G69P6;~CS!&g9Yrr3-ty)@J7Z zp+d_PY_<$do#mybsgopN;^0SE?GnNZTW1e%#^ksgU?*-WhQ1Q@%3zk{_!Xx9XY=M% zLHUY;gkX;KV1StYbfK%OENbPO_tJ|>P;9-`aD<5@y^b${B}TnZ0=;O+z32_vm}d6~ z3L>en-Ga3dvukASy}=63>R7qofj(|ZARNV)tVYFd^$(ZEa0l_Nz%=RbXZIMIed@!b zny}^1@M99i@pMwL_XZ=w838&^@|6-R`P32^7@?lyk~!6Xed3CR01&~A0sIzTbvtLt zhM#mzHfm?kkr>xs2&IAKXq?o;-BN9vgOla3iKgr&3Mmvt9Wa)3JJD{$99J|->^mCnNiYn*y z?QbgBQb!N_b@FACEt`Ykxn=hobOAzBbh<16P-_8S|`%{ZqH0 zw;5d&aFuExvivG#F2cP?d-Gpt2cS?wPUta?Mc+T@r*3YAfqsPeV~=l=}}T7;8oPUyii${Wxo#Rncmo z8sntakIv)(y1$vPSEe;t&AW2XA^UCQeHW{a*)7}^iMcj-1)xD z2+MsVQ*V8`BPcf15Uknj?^^#Nvk<$M%USubQ>L~%66ByKsGEh__c|-5w=BW=gjh9H z%L5K`6Av5e?23>$sh^6TNS|7X{E2P0pbR}zpduNEzvmZe7kdrV6B=w zWM=ia?EI_$RUsbG8NO69<^BX=PXV8F9hmS?r=$!-H0Mpyn)_D1h6lHjbZ0M~JzZ2c z_mmOQho&?uE)k|#2gjH3m=o<<7H3Xw6bQ6z;2)bY`N``f;Xo%W6GD7*id0)^Eqom5I9psdCxW1TPdC?T;~ zxO^DvBk>9smrd5d2|*gpaO$nRNoHJ*Ai{pQ)w+_ot@pW({kaek4`$ANAIcTtY;i`6 z;JL-Fen$hl-Kh!4$MNJ zLews$4Yi^DB+&niQI<1*`qbWnYL`kDC#bLmw7q-o{xqjGt<4D8_5`u{;pVs~A2qjx zw<9H_f9|5pNP*>Jm$$AW)u{N$wCw|9IhsY_mpg(9x-(?Wr~&~XG$5_6y(uKT_5yB^ zRW}Fm$lpI%WTW7_wn>H(dPo8n1ufE{5_3?bUOs=C&3$=OoS@l&=Dj zT#>cwhsh$ZW<9NQ_)_(Pe^;fJ+WSO#psDz(dy7^3g`)JT`y) zWQ1^%6kEyDuvG0C1j|yTnJ+y`Ej6MN2jlw+yQu(><$0-MJ8+lxcWSfK5rV}P5367* zLPJ}JCQ-80yc2Tf6bGA@>+Fb&6L#V^i9nX2eQ7@%cxUgW_d3{j3x7734 z;3AI8!2OIXa&zlO(BH~{)U0q|%f5?_1q)i;MZA7mqvdNsUOM%0Z$f01GwDB#;kVL2 zi>ZV#0Q5g3O3MyYq*a33)$BO5_ps1%j!JxKXzHQv)w;b6tq#hM?TX~1ZC~dQCu;pW z+%PL7kI8p*Z251SxM`n#(7I7X_3n$x{2n?@bI989C*Q5~2|>jx_WTnV z`Q2CFN4+Pw-zpM65HgXG~)p|*Qp;!O_=+w<=-u*2k-6%>bmVEZi_tUihv~!X4K(fOD2T!An{frroH>6 z?qtK6>k8A+M^|S@V1utZMhw(+n@?iT@E@T`XEgxF)YFO{-OT}B6GGTRw$k)UVxkr6 zwdu6Tu~iWd9aNrm6D@mNN92yO@T{1mk!O8%C^53;dXDN%?$*CtTamXGJCd;;2>sRy z#bx%lNfw-=cMD7I`7b%pTL;y_dnc84)`6&_V#qXf^*uayFDA(vC4=Kqz2Ldg;R- zM1)xp4Zr)g2y`q@g%qpn$9@t2GxYOeaPf-;dd0fncM$+(+6RiVo*>e48A%%cq74yxkv3 zfhocwVs!4!!57H>;fyNrsvD0*kMySeomR`N720o}Oc55yfbxs&#SVrX&Wmp+7AQ>4 zN$%jE!oE632LFUY`7RlDm>@J5E$K%jggp~1eXtK6&nJyFl-mec<{23tLSJsDEi#{}mu z#^+|24dlmSJ8boVz7|8ce(8nY;{f4EL<}{V>A1DvL~yFn(+q$Y^5UI7Ud)uov!c)m ze+fB*sS+V1_e=gH?{v-BRflgca+d62(9mH2zwZQ(S0_Lv1|R8=nKkwC4lj0uANekK z(ln|ZhIU+hubn)T(GjP2%WpDwtVVN&!;`v}Cq z)sqO5-BGXICa#;iJfpZL0EL4Zg1B!6*Cx;oB6EP=_5}>Ld&W5bxWvD#A3A_4vJ^^o zgPtjV>M!KGw_etRn~S$JeD8)+5XNk)!Hc~b%L$waaXr;ReW`MKX-Ug?>W7fR=ZQi% zUJpu#UCZrCSH;2&EeIAI=@j2dLmi6?mAe+Z$opU77M^wC{gbQu{z1`8fZ>-?=;@Hy z@hhuH|E`#{%w!c`x0CQox@5^<_LZ7(#dQD>37pS7X>O)DwSyLKAREIS=rp7ziM8)m z^C+YeQ(kU>sC7?XTvFqSaUu zVUr1L)~atpm-<}Q5K#_{gs7?pDxTrCmFqB{v8?O=1A-tyK{P-z;0EIfBOMvJqn=N0 zg;)LkhW%b6TMmQy_nk^B>pQd45m%18XS6J{{|Bx?kIgQ)aD3y# z1iiVvonPQ9`Qq%)00I?|BL(~!y}d^kb^x)Hck0NZJuUfajh&UL?-!ezr-&$eNx~d!+GBGj$06QW0IA*`QJ%}IW}8tbMuK=7AEBH-kOn-v6|-n0|SEtvy?ODbA|bt#>QZh z3;ZDftnZ6&B`P6!n-5+VGthv*8ox}$bRf-GT^qXOAD~e~@v9p*3`{Xp;;x3NCIHuN z2g*8z)+S`rPU7NMBBdSW8&u+K2D-&hKx4{)6MbSD9CYy2{|Ha9N>XC@b@fB9jC=e*$IO^HG?&w%jo_`>kvR>6S3 z_&Ti*GvXru!HVQ6Z{Q99py2#3p#a&rga7~~KmjPJ?UQ@a>$_5?s0@g=y&t*c83C-%FS%;)eIH%TN% zUnaVkq3>YUBlD^bNTyMbwhfeO*UBHQYR3D7-qNxf4f-ngbUS`=Tcsq!brlY`I>cik!|!{|N~=-JW@12u z#dthA#GPY$aKUo=DK_LgoB>YClbPSuzZZ%53Gv#$YEzZ}{)6Ssp6Rb*>2hdmaaub!bcG`YNZ=<*k$76t~;Etzk%$y_xAk~P#V`rd_$UbRA z(7qg&Jxh9i2n7z>O^zrA%C+bR4M(xLl>=tw6=B%`tw8kE56>lY5d;Omfna&GB=iGL zb!`f}GM^)1|4H3bwGwC-HEyx9$~Zdi_?|~iWR4c6r(`{!8sCubo zAOR+d=L}ya0ho^;eE~K^FUd&esQbUrIU=rn2-cipU>AK7 zccJj^aZEGWt1S3fyF;&T{p^YCF^m=&%agJgR>E!x+h_ZGHOTt9Zf{4_!ODy{GHq>& z^!?_N?u?gR29}!;w#pNgp1KeNv*SZKuZ4C=;v8x0BAk^cpd&;rvQW%{zPW--{uWhm z=d@{OG=A4GURO$LA$55L=Et$C&uNls=gi+#`U{j}(VS`6hBu~|S1g-f=t)Zo)Wx0l zXNsPv{p(%dvf66&a-7J99|Dq0*}T4Sao%%i$a!R{?+0TeCLiXuIno#kEJmu%A}zo0 z3EIA|fLD@lQ(elk3^z99jmRd->&~a-zq#m=)X51GAKEP3A@^bv)#m#E&V`nkH<9zL zz7`*PVfpq)zE9em^nM&bQFSYC+T^{e^*!ta#-#pJFa1o8ykJ>{TBa9K-{)|)p(If{ z?x5^0V>O@i9{VAi)WYtTfX2albFJW^^nfq;ggjQ-ghYu<&f$vfyL3w5M1qC~VbBqcPP6uCbg`kph5=*V0I?2}hiCE0~Q(O)}Ca;A>;nP3)rCYu*d zBImujG8rHLIUw^e%c{c!;b3BT*!0-o9(#C*f5SmLeCWVie2Qi9%(h!T6qAlRn-&b?|7p#vlT4lAENq6@9Y zOTLPQm4qU5q{ktAeQB0%(sGfk`f<^o|8z+GSC0C7N2LBr#haL6Q;n$X12xQm5qoFZ zV}7r@Y{B&(`jEofu(M`~Q~(HS{@1HpJ*zwS(FElVU4PtDP*GLWw+`xwUZI_Olr=)|<$FXZkjLqRdzJw|{*%nO@TbzkDA z1dP`DfK^@0L_zcfhq2e*_B9E1kAh9c_cOcxhaPI`emd%YDwr)^O4T&KyJ&k zoqErBp~=DT6v(PS#s*RTmC*g|=${*T3bFLY;)LH67W8)QD6K(azt(|XYaEo>lrc-3 zEG;H@ITxCZ?Rtn9uyW_wEq3Y*?OG)hsyB~4cJ&=74fH4d341^B6V=alEcWnF%)kAK za0C-~!9IHMuWOWv?04?#X-OpX@K60W$%y@+hM&4UJ@K!H&Tq7& z)bXlj=PU{>)&}8`cY*p|<`yvIB^gkkvY!zp#qp~Bwc z3q#SXJpbE!M*sNiWU-fJYli8?U_2rNhH%6Q(DcYFFa<*Cktp>)c!H}wr0T$W11uOs zC;gqsd(kApG)EVn2V}8{LlPuIs2*~g)yVw0_sq!;1WC)NrkA4J8hA3SM9eUC8q9*#a-FDgK2D#b7&Xs!B>y>3R5t5r zOR^Pzv}#194NzrSDU%0EQm#01ThpKl0%}+%CjG)t*Po^gd)ZGL^6m6pKA`pExp8fa zz0S;4;8k}`us}FL4qjc^k$GZ)v8sD<{MD^HQsklO zZtwF!BP`EgjXwvZ`$G?C8XsR2!_WAY!`BPJ({r*n^^EC=ccs*?(fsXI=v29csZ0^5n(XF9|H9N0iPR0D64G`DS~5 zl_qi9Q`1^|7FyPflHbW&X-f5o&d89w>$?Kjz!Wuif8r=f8v z^`WS8+{nisgO4SGBlS9VNh*&cCeN@PVD}nrl?t8EA(P+n!<&H~tsy#PZPM0D_fhI` zX%Q_j)_&6WY&^P=3Zh+1<&Wzbn$yAul-AUztwS-tTg})visQr=v&DCa;-CHSIxO!R z+X&x=lEolmDVAXfdHG9)<-7Txum+BEr~TBn(c*dd(tr6L5;H-eG`;Y(R&$M5Av0`D zy#XYw+EiL+P8KOui7fMb*^Y@$<49lji)_MxgDi$KQ}OL83>q!BUpdv+@oh#$9+^^Q z?AJPd1^L@n80FAvMi-nS9bADeJ1%(GS&Zg0v0?V5tgqS7qcFxi#ssqh+Q`sgLqj}_ zLe4?jSKQoer~7^CM0&$q7G>Ii3&tCGuX_wVBy6~xUFwG0Dis{fvHKR3N_&=dX2%{s z91m>4r>raUl<}(H%Uimwn1f7w5%IegW$`jLi1&oE8fAD+$)AEcR}m=ZR^XtJ@rgbJ zxm{$;30*yz+#`96sY6BDOBt%yEXJUJlHl$Kh&Re6-cW>dS|ROa)Exk;SeL>H44x@V6f zYE7c99}7OOpl~iq*5vZuOFn7$91V+FzbW8&a1Lg~hUQO5xU?NxZwLjjaF4W&CVR=q z+zNa(R}#SwD?{3rtn9x?6B&%tj4Je7$EP(U1CXbr?3WtV2n zK2Ai~bNMRaLsfIn@718c=jrb%#e0*3>c^~$@V`vzzb>m#4sJWAWC&|+?@Y%HGxn?c zoM*DGnUfWqR+`c+y*_uC2j~g7oJBfu_}ofx;$j-4BJvMyd+t--XA%nWz^u#b5Q7r7{Xs= z7Ex39f8Jw*Sup}&JxExUs;y-Qh2A(6=rSMO^~y=4JS^14gGtouY9Rb7gv1nEMKMZf zewAn%%4^cs7jO)k;RmufSp=jWVpd2G0IL~SILWtIDPg>XLMhzLT{TS-p*-xd2keC2 ziKn2NU3Inc9ML>lYdZq6nq~m%N{e#|r5VCbIevTc} zT_~oLFX?*#f^h_6U=Tz6G!VX68EhD-`=wSNYV7N^(*JK)QNwZN_ig=%CqdZ0gARxFX z-H=%@_cSte1%l6U4180#ethSzhOr^E!^go%o($e1L-2hltDrm+|yb5zyFV5 z>rH7C7fnq65v>2Cj}OaN2ll)p)Kp?}N24&fvvaZ1da)`E7dKCUYzW5@yuZx)->wj&hI-(m$+AMw&|zYadA8ZlNo0O;zxE_C)HOS3wi;mRhxL zNT%FAQ83mK%!wL_>W>ME%j{F-;Id#bB{FHxa)n}MrdM5FN^YS;Wix4wyj;s%*@7w7 zN#?~)9>X`%Vo_^VMVloALBK}Z)0)vZCG;-3Lziqf5fsDpQiRM`=8&3X zjxIKu3nY*%aVfAHASXQGKU*C_V50KBxs1fQ|5=}B3OTiTE@O87Oyelh$f=nhgLp|&F8^Ke+hAv(hwZxTC4>=M zDAOpMUM<%SwaZCv+Bg;K*IlS%c)ROvc!(h2g@7(96!Ta&ha?$YkR1HSsuvZ<3Uht`HrEb@67xJ`a9wQ%sn{BFat_WC9d6j?J>A?WU+9a#~!CP%L0a z|G}I1d=S0k-K{$y;U_&7zreXB;%*P9HV5lq0mGFI`?KBd$42IMGxmw5PK9~77{cIS zG9UYSZ_DXLe)QzCRc{ey{vOD+6@stLrOB>;IRMCRxfr1iX2+IMi850HY<9NH%NeM{ zipE&KrFuX*;2TuGuv74ej@5ivU<~{DX<+P@bvFjn6xlpCglVp?BmLxl z4V*?21o#O&-U|ZXc$HCFq)4`oV|@6bY6U&S8;HBU>Pz%EN~AcNo|Y)Cv_kM(=sx1_ z5{(f4%FfTPGrK)lOrESXk}^{#?AjM26g#c`eM{;}C6eqg6PtYuDh9!T<_XM8{u1X9X;kVZfd-+q+hIzfFhhl$_Zkj>q5RrFFO$9B*I9CH1o_T|^%%B?Nsn8!H zp#Afkr1IT7E$?dO=b1PAh6)gU*s;q=%a-2d%3LpFcOG{;L#1iK3Drw;a^uy^NFx$` z;jt8Hdc6Xn_M`(OksfCnE^enbF&V>-s5^#o$S@>=D+BIPfeZsF z^|be@N@Pt4GOM1H6A5(WVWob?zLDleuek!Xj9~+dC$PP87uCUmeB;5do4Ml)?B*E$ z#Fjr+i}!==^%mhbD{|8xquht`-m0`!oxvoP%)k4VA|`_%_!|PSd`y4w5!tQYl~?^l z_`2n`cpDlDhzI$0wZ<{du5e|EP@^p?(O@RSoY??@fd~g|A#Bd9RzEjnnZ@;Oc(@;i zm6*Dt?j_Zff%G)a_pce2pxgNsP$G(ON0|6(I7Pqn|56rJXiidC(m z(b@*vvhI1G_|P%ZOf<)c6)#CqcqDhY_u$29qIM8Uv^1Jl@qQcqWXy53(iH+qfHL4&t2k8p=t}j@R74Z~lo_E!Po_lyr9cN5ECYC<8x zvnLh{1fXl6AqNWDb2Mlt_Ud$F5ZeKfqTIcrWLSj1^MY_=g7CN;YjdoT3gKw=`QkNm z84WR1N6e>#Pn!?lXOqMkwGmOU+E|Ygpr(82u`j+qcH{Ql==?GaT6y>ivrHmmmEA}D zt6k@}Zc{xZ7JA%F=KSGH;&bj@64rmlxqgE3uw;!U7+oX`N@M}=2-{ ze?_?|{5mfxCb(6GO25GW11*+H%mU97=d~d{Nb7Kae80 zmOCy=9*^jpCb(9fX*$c5*hwOQ(4qLvb+T7?mTH)@Xv`~sbAVnlUXp%$L?qoX+N z(c)Y9+gX<^DXISn_`L&{!H{NDZqyq@X_Y5eS@v&eJSnT1_KwC)vx#!vsT zPkMrvf|^VUcO0Xn;fIu9Jb!z!JVKJ9XliCO51uW2cNhGKN7hI=FP2Aa_V^czKA+e5 z?>I~91}Y(&@TLSL_>h8g!~ZBsXrKPuiw2(0a*hHB zD4_2e<-=p~iiX1%hEHlRO>}Dpsjgb^+keFXgZu@j=5sE;6?C)!kKuBRYiHVMGvm{P~B0SJw6|;-!E0%ko<>-F-?{8 zdzO45`BOuA#b9*RpWcZYNpfS|rf^nZ>^G(n@3zs9ML^9hQ5{fl-kHVX{d{8R5tt5g z(y6(Y{E6n?P@S$K^bwC(+8iBT(GGp{g7%EMSWb(@GImQBzuL*`)({hI3@o<){`^X| zo{w*>wu?=khJBjbH!g3Gu{W_zsLut9bEEC7o+ZK1%11U z=vp`u3gA+7BOYUD_YBr4C+)Cc&L6sv>w6vYp+ot7&g)I7_j2qMUvKH4ia1YU^8Skx7hdmr+{w0kd~IaX?~9m^ zDr(POl+c<#AUn_FK0dtjkuu3ILKw{PTBE{?kcY~6LQx(wl>}oBSI*jB-ou^LU1r2= z0pg;?Ehzs}dS^J?Muxl5DzdyAYR;#)-Oa&FFO0aD;mLsfjif}2Fq>}l3cIFlpX4?p zV%WBT7%0@%m=zvDEN^A45*~q7Y)C>sRH{#XrSi{pA>dHDeZ?KGP-4AAr!Rim=^iqnEG*{@NCRR`ERQ?(~+Q&lS+{0@absAMYm=EWV2Ia;qZmy#%wNs-Y5wm5JG8n z(bIAM%|D_-N8N>nz$wd{bpO6$ZrHPK!T6BW-u^I3qVebJPcdEutHTC&$!}mUqK)HK zo}4fTS}V#5Hb|<~(8_!^!dK3WW`rSoR)9WXJb6kD5QHeCZCj@^+=r`ef%x^D#lXr5 zIfLeEnb`q|P#(yxCD-I^BZA(BCbCJyzittZdM+)BIm z|9JrriYbBql0S~y@BxL^vq5OTM;+qeEBz7$?BJ$v2%yJ*(J zS;M(;)9e#BE@XI8p{{4sYh`pBU zuD<-KXp}Q!vwGZCLJS|D7gATk;1UtvAoINoY`MGPN|QnjlLP|tejOw1Lqlul zT;W$iXqp}x6zaJ|xvFl%2_aSmKNc$-C{>B%?Tg{_=$noOR^)~Q^G4>}BCTG6#%_LWLh&@@%Euo&v zXq6zLx;)THnzJc}qc_IsY+p<75YlX&nq`rD>N;F*4 zD-wB;88=5tGxf~C^8t-UO^cQ z4l_cUhffLJ#MOdRlWTUvNj8bq7-x(g-oP6w6o$19>?{v|wvh%mv7Ea|Pm{bdqG)FM z<`5=`wfuofIpsTU?B6e5uzT+uIdHK}n`-jnhxB=rLgh17^~^&a#mGiS0pa+&k!mus z86NAAdvyal^38DP24rTW|J~6M;%oWpWId#V$Y3J9Q|bKb`4x@$_ z#sy5zlr^*PX#4w>h{Tg|pm=UXPd!3av^?ASI;1I}AAANF%?8}4MFjpxa;5QYXrRIx z!RL1k(x}X;di|k$o}FA_8pYBWY*JtK%z#ptz-`kF$RGH|>=l+3{;>W@RM(mEH0+>^ zaToMf7=S_Z(J?Rf6Io!urmFrlRlidaH+0eka7>MUJUJDjNJdp{Px4!E*r_)$H;+gD zv4iZdVd{nDQIW{vZxwNtMX{~@Tv9fE86uU3om2nuqmXve&b3gvKLr_?C#pj@+ZLSBFGT=aq;oV0~^z#ZpZ!;aP%UNA$!l0?@{#6dRC=Ef4VXsL*UUxHU zG_m(??so^$GbV!-_hN2{RW1X{X4l-#lzDDvHc0aV}8Iw;JA63g9OTVHJ4 zbNvVg;zCo1ls#&eWY*ifw*~?ZB5#?wW=J@+N#ioJO=_Glg{%V~lDANdDylxh};dNA-IzcAddI9h7P8>#s9;tnZ~M*hwj4w0$Vh7tCAm6T-0kO2b}% zI1DmG+LzvI<`MGTxjvC0YO3=)RqC!Dr5SNsN%JB70?`o)9`MRY4(4)1u9ZG{%!v<6 zijpJZE1N;MuFA0$ic8UT5uZ+fWd9KaBa%51%&vWLQ!{z(gd8)2L`+@cgRR_a?7 zH7rImAmfIc1hD5t{1L`FnO=|-(eZup0b;|y0C1>sztAP7qD!Gdhl#9Vq<`NwC znB?TmTJL)>?fd%`(ZO%-TUNRj+{_D#!9LFTU=o2cX4DBfb`|^qmasy=kOD1PhA@^- zW0vXguA`(E=*u*5%-%(F)H_(+jL>k~j--BwBJ)-S3&1c4p7vxW;h8`C{#1${4=pJr zzAsi0CFX}&>IJe#8k9pM*XoY=t$^TM)^pwQh3t(;C{?%LABY(ub3XR3xrnJliBrmr zCWb}k)lD+t#KXVIk?ae`+KO>C>~=wVUTnDotLqVA05OS;i1ty)^+uqGlEg>oB}l=V zFP3lZd;?>;8dS;6pY%j{n->3{he~B~1?eBRdDJ>4!hnTFGqh(f!ypX5y?s?`@6{+u zE>ua99Uzr8IhS4UledZL72N>lv1n>uQnI8w{G+uZIHe(cxMfsZSxE-II$KJ7go*m zdBWkm!p=EnPTdp7ibUOPp78daOcP?Hj`YzOavAQhzb>WD1O2{WRyeEY`3|7diL$Q| zvKs^*4nKYyzvF_vYM@>crA7{X-DaVQAcuXX>c+I6u^umWGS$N|$#Cz=Q$&@e7kqe^ z*q(Dxgock#6U?d^_t|{&U{PQ43)EYp1VjquP1OgJD`_PlyXks*av3h5FRo0x#`8Bj z{kI?IRoLY=(5|th2z}d#kR7+>8NKRm6u5zqr(3up;>$(}*!fG4gzfRX6MRbJ>j-O7 z5<&ILV=Rn)3Bk8hSV^Kh?bcU%-CUFc(UU_(1aWRXNh`eTwsV7-Qu61_;06k(6!0zJ z%khaxk-rRf!YqU}BHzgPtpk2lG%x=djJs$r9RR5*Rn)9?BHNPa)+4mtkMeROa@UwW zhRuoJRCs9>nTW^6t@eh}&3To}4WwkdOPVbBSJm$@P}o<|bCmjKu`v#3h04xwcDJWT zd94WE@r0wyk|R;NO!d*&!pcLMI&l9tC`uucS-U8lO;|>F*jPno7_fTZ~a24D*6em)L(O}0dWZ5nBs)W`&^ z+?%{{d+mz}`$_optg_D#9OfEV`R0e!H2Pjz81r&P#C0ge_7i>2YeIYWj@I8#)OlN! z?EUzX8mC4zi6W(o`-CSfoI&0>Unb_707%w66!wQS3Q$f|hG$J&y=vc&J5_k>5U~{v zP{5jK&-W?Nlrz9lDAg1D(-PS|!XDp6zr^3fkp}^T>Y|)gs&%uYBEKZ-l`u}(*HlV$ zD_a^h**E zbDR7JtpDEX6n)+gZ!5a?3JnLd4`OJne z_IHL-k9&ld6{rfB{~Up5B*LqZaIVV0xhgzFZi%QZXA-B zI}hC3#`RbS?l1_`tOJVoh_ju`Nl^HBN0aRE#-u>mcQHT-`DGbr7UKez82l^p#L^xV zCK=_8af@k9;i1(vCZ(rQuz~+uWe{-3>}i}*B~FL_^u4m%-X*r$;Cowj>Z~9m!LX-} z{?3=L>oP*5AqNNqm>zcoUsw25J+9KkPRlHeoQgl_vv=HcwAA7U)Q&m)!bNSDA2)xu zlHk~u!a?9SpDAz+2GDhxej5Xf8Hm~V83BN3ujS_y5#X_{F#a$EmM*T0C?ec>qR7H_ z(Y{Ka7~L|+>Y0W*l}sqGB}^i=qYi5s zEME4I*Q^e4hPBG!W>An-x!(Z82;PsuGk2x^tEEO*OBpXh58EIQfm5HRkwd@uC1}xL z$KGX?XgazNeWJL%Ct4!pLYT3lRv+k4Z(IAOq$-Gc8^##Vc+5!1IM$zndQfQVns0(~hA)xr-X#xjpm z^;Qi>6_Oc+Xa;IyGGqbPPGcMU4}_NOH~U<$?fC<5N}nmilZq4Ww0KZFjpj+ok~L?@ zYw7nu7C3&0^`0$@kJ4QE{?wWGFFfQO4-5MV0c8l$F@$UQde8+dc`4MI>nWYQfsf+v z+!3rf23~zy6f*fC$_ZOGm(svXiC=}S^ynj!weE(EFVH_=!28|VV`LcIGp=iX-NrG(FwpJm>k zK)6#CRA$Rb&Klda%_0mgz}B)sR1_z~(DRX#j~wBtSIdUQ%}7T%cO(looR-8Tg8}*z zyTQWAM9L^H^5ed zPvMNNkQQb^b^+T0JV;c$e@0l-506gxqL%ltdLbr-vkg@+ckyy&%nto?LRWJ<=97lI zD@oIK43SqZGM+7R-NJizuQmt@dYfX<~GFk)zdA}nDH&}-gU$@7NqUOWcywy*C zjUU^5+G>#yr9Rihwt=5MDzJH+gr4uYZtQS#`R~>S?X@%o5zU`H*J|R4=MX8BQcn_ zZa95kegnjgBX+A>>3Ud54(@48`quGtjw!qCE5&SitVxgpJDL^_p$g^YMD%lHx4DcY z1{e>;V=Y>=_TvXe$G%wRz8MB4U!?&eWLzX{Mqcw7 z2h};Df|B&Os=B;y3lbB){C^eNQw!kyoO4@TcJB{9-ImI_34+9WVwnUQXQU3W)vk}! zIi@q&X!&wj5zn|fz|wI(c4rkRn#=msNQ%TM>%6&{7i_eSgFE}m(6k)>lw+^|fjAAVA4z1DVrY&;4= z&1OLgqMS<%e$1`34cx_}12pb8ejvIc90=QIa5itI1MwD~v%=uu8vf}<@96~T zy$~@Kb0p=u8;`yLq3jF4%H$GdTKVU+Ui>~#8ZbBM6`Lwr8}_m7DCEVp&-&zR_H z^U~|lC?}e>Ra77=Ob>b2ac~qaDpYC+e3T%vT>J6!Zx4S4wH}HPMs|}1()Z!e#yN(3 zC<(bERnCRr3j?zS-zHd>ziOQ0IbBwN)(B(Mukx2f{WKEg)dm057u#4?7+rD5Bi!W+ z30fHE2iyJ2W6$!IxvattNFv71Kyluz9ek1}fUjdjz?#e$u~14Gi^#9$sJ>gHip4vT z_N<#vCDT)jO2M%AAE0M2>7 z<3j^mER@9PCJz;uVh-2(l$tV1Aj;8KmQPeBI|1KB39F>yV_i>6>Rh zo0cw=L{I0rmhYUQfU;-apao}Tvo83w_OU$*@dI2R@9VBH6pvY$X5-P#qm<9v><01EkCuel~cWl zF$5_8i!2L<)6V6vKnH&jC;jzxI8W4J+Hw0Qg2UzOw0=JF?sCp#Wm0e^Fm-Fu{>2k# zivFUqIK&>u+|TGjj2&*v#Xa_Y909nH>B`C}F##%nHCB6TXIvqTTdvYlJT}}d((13` zSlzx&L>`$1adwYSBtm0#5J>F>yhO{kxZO6-&mjk1wzEYd!4s9DT-lZ8xTo<11;~m9 zNYc=X*QN`64EvtFc*=SjjcjJ3>q{ZT)ku__!9na`qj$h>I%$RFSQ1=`_UK}Dew{OD zf)4RbPGpdq>&nvSR!|dp;kfPKi_T96q@_qxQ;aWVTUu`gjQHegd6l4Imvy@UGGbn- zejPOrvS#6+>LUS(GWSlo_A0nT3pKh001;e6@Cre_YzBbg@|w89piZ)Nr_BL{@vo)3 zD4HQtWW}rp@@n~KtFw*3pAk@d-19{;kFaEHy_0Wd$t$WIDk4JQmAuESu7ivx0b@>c zdHziSJK900+`hDU27x`)aA6eSq!QU0EE~O+3kueUkV&aIMiE$Ry1J-iF-ma;-%7Uc zl$oOjs;jRQImM}LGca~2BHmWSNfHS=nE*uGk?stqvLCdjvb6(>wOlXQE00N_yOodTI1uu}Mf4LM&W%Vb zC==wNp6Fsf4DlfNo)v=fUPcv4m~IM~xeb}|oHNtEx;zai|7gAK*Owoy7bN?O(Y6vt zL$v$PXe0|m;?cLqr6!|oPllSMc*_Ink`lL6Mq^0t!H>mpg6$ueQPiF`3{FqmsU?!$ zx5&JgaMwIPA&T}H9bmZ&{dq;5nsg!Oh+o;$Rw+}*0uRhcnQ7*N@0ChZEwNSoJjJ*L z4J%*`u0_JFK)qW_^pT+Pw7v8$wEHZzg9HhuZRlA%a+o~+q9IZGs!yjT2pmmUUemM1rTst!uNqZBBE3(@voJo!lt$y8!i2F{_6p4+Xk|?D>V~gDs|fy}kpT0*mFo^f%?EDUWYvEY zbxeSCZzsR*y2kFHSfq!S;RoGlBEGGCm3Gb&vLuud;0y37X=5LbCR|z;Q_)rU&in73 z_Zxwb*pOOrr$01P7l{sdtGGEF- zO^ViZ{-}U$;W*czm6zEsc%fj%lQv<*E<98vb~We$>n=aWKlO`)gp*l2qt0#N=fIy6 z>@CdKfrkhPQrUdzWiY1Y6x?X4v}9f@mqG9ks3$`<=~q?}rC_noi?;{5{Rx_> zZrEEKnxSnK1rUOP*Y*8v0BrmV2iPSQ1>@p#cHt`59zvl1%(1qLW_NfL=41?xYBBxnb>^6lwv~l z&wQ4a!YdOx?5+g6i!{hpj? z*o`YQl&!eoBHqAZoB&Qk$TF8BJvy`33$O%vd}R(^65KI&n!a2i6C3)SavGmLepE4E`Mn`w`F5)f!U13m77X^GPC?{Ik#RibeHkl*+&bNQ%Qcl;fBn#$~os0N|vfrdPm{|yPqBBIeX zaV+3s<_LFws#VlBwqwUKi}>Ti^yft!G^ps8YTCxBWhfKukn~v+e{|}h`&J-_5CKs7 z_VIPoSbeQ;Z!b zd6sp9qnRvm*3o0%lJUA?^pQs;y-+FHVFN!gJKP*_toA$W50`Km`XGn~gAVOPrSzUE(TJhQ=gX#Y9|GSJ$JZ3iZsX zID$dz{{X%~LBC6Ex3FC8TvL-Vuk`4ai5?CP*k|xILNyE;s*q?0{N{%ep~t!|bOwrs z0(++}P)3U}aI?y${pnSfNv|M?C#nqnUP-0|gtqAznbFMA>dw^b>m2tPFne&?Tdx8N z5EX}=OYiiJAT#6&eEHIBUvR&xCSxkS?&pF*Kobp)=+GSDN#zCr03ZNKL_t*0)he-M zgHwuNMH#z|iGw<@jP~=BUE{`9v9Bg$p0>rC)}3Ky)9|JEUxES_V}XxmN~avMX5PBrnW1*S{yhZUj1m93Y#k#&`Rd zL=%W37+mQKVR-q!2kb6v8!W$1!za3!xuH=Yk?A`q8_i?1H6yQDvoNZV;Ow&rrnW}< z3D^OhbD)B>x@D_Q9kUwrz{`qiuYhs?Z+K?Ge@ufXx~GTqsH)w;dZVy{OSUqGd;Hc} zR|{?!81^>b|Mma`b(vf`Ih;sBr4Ng)q&f4EeyJ0+=K7@{BRbT%jGgQaY#f)OhbzUR zjwk9UX`<)~jE}FD-=29rCp1ssW1 zminNPVobZ->lM{i{m~$*WGJ?4ludBzsFLnHiYifx7{%)Ls~%ZIHZwG}?@zsUMudhd zIKOLBXkrlvP$}UtAc=+)+6v-BfIEmWbO!tzS{4zjXgk|isA zJ0Lr?Af$*Tkwmc6Nn#DqVR_zGfyUf*JofrnoKL7*I|322NCmn+scy9&BksN-f&#eO1v5gXi|f*hM&btm5k zP|PX~lC)~Q6*`ak)8H1tH7YL-NQqhna=mm6~}7O=K>(gPU1IXv9Vm%PL=934V_ND z+PXTro*tJmX&BLuVM1EM{8kJ8SkK~evF%|)a6`@jS9y}Tn(CK;PZeT-X!lmdFsYMC zoVTVEM9W}F+O{5mZwl^l@IuuBM1cIO|CK<(g!y=}HC=}bjXn&BDDLwg=3ng^+f!fQ zI$#Tnwy-QfrYgAkW%#YC%jo8FcF0bfS)f2AOIPiWuGN1jRLsvqfQAKYFL0z%tEEQ8vNvY*)wXM z+^eB)8%~WW?XQGSof|#!1K^Y_sl~%rdEa=u*sU%Zrk)4=AU{c9Hq0#Gepe%8Md_IW zqN^J31^OP9^iZXVp}3r}G~i3z6%f_0$n{w%+Yw1kk-fMoPomJtfhZ4T?q*c{U%PJ^ z=D<8rRyF*N`lWqUi3cw^SmvM^yTkY6Q^#CSuZ5rjgBI+9R;^JU86cSVOjfoqcnBHt zD4OfzNS-H@nFmA6t!V<`Wsd{Xc*&pR)pk*=*_RUZ)P{*Z3wYl}%I=#nDD4H0BD*3Y z6`{ek#hp))Qu@Z6NmUxNiz8asc4{*?z|J8~o!MszOGkF1vO_hmM>bgKwl$0g0ZS3- zGP$tS-31bqHETVPJIcjm)(p95G#!lwqG;n|CI||2)bM+fq4qo(boC2VFgvuS-`dIeo?!EQ~#z1m31u! zA{nMHVMjZ&>~yEzAMVmSsyzNv9eZ~=wTt+)f!|kM)V8%ED2GqOtLo0ZeVU^gG{+?~r=$4NS{t`UKp-|Nwe8q1B6S^3tlD&y z&}X6f>xzMp$iI00W93<=JW5y>HmB5D6`x2N~Jz0m2ZhJN5#T?hT3mw3=b z!5ui1#Bt%co#UbZx5-Ex;Z(bNY~FKDzh3u}C&^P!KCZjIGs-XiAOAzPZQmgxB7Gpz z%LlROl*b$;|K{~C820`9@47&4`oSGtd&edbk90yEiF45C3o#4Xf9yLAkKd^K#cc_sgYUx+$!%`Dt#ae=?Z0Qe+*CF{B42a~uO_Vn$LLj|ddC zQZtQ}w7*i5sJTSHQ)R!s_mo2q+IPtR&Mcq*>Wy;UcW)EjHp-&@7e4h-viDwl$fcjZ zL2kbN9ueVSMue0DbT!%s=;&Z9EjkZfJ_ATML{&l8LImngTUtwW;F;6!eMzDSI@Oi0`Hz9)5{3jMVQ%_|5h;ca^eZ$GW`x zf-5*159Pr9w#pmNdYWwAbBnz0C0AW9H-3N006n80gxmldF2&OlbnU!b&B7lW{ikd)Y zHuy>%Npw0Q!Hz-x0G(bN6=dqmR}D&PKKR7IXuD;h%LB6Lj8np7o)3&&YcIozuaek{ z_K#wqUgO|8e;A={a@n*!b^jr*yyB-R^`1|#XZIY*A+U(R|EzNkEd2llEqx(1W^9U=R8IZe8^t%yr&)~&wJ`|^8H)xl*_;JZMpcWZ_D>@y(9aY`)QH`NU_xF5kY{mu9p5)7QWBNwRg%Eg~|B1yBn{|0)^InaD@ z5N%dr4c&`!0KQqJ5I?#)XQjy~s^*3cN4e5ZKMT&chzl{0RYL$9vc%MhKz2L*jCxh^ zc9!~x*h-mW)S?-RtFXKsu%L0$7n0*&C!T46GzlCQokwteR9tWEO(y<2V%t9Si8mvd z63z8p!kKH?6sL{_AF-kc4HN?((W#|UTY9W&DY^O>x-{j5m0hF8(ZM-i4q_wAPJ>TM zu`W{906Zs!K!B(v=flBKwYbV!S(8&wI82^@+Ocx{(T6O<{KE3l&rDgma$CWG;vV2} z4?jR2f80Z<{X-AgPtJVyW97_eKUS{$&aLvHOTR9k{>pa=vecnx&b_Qn^6BJ2OJ-i; zfjI`j9wY}FygR+zbKf@k?;rfa@O~*pj(+I=@~kHxKdf`aVF$=7U+^S(*>j#CmtA$O zyzk>*mg~NEoAGY}C^=J;n9Dy2yv8LQPOW+{G|IgN&Qc9Bd0&?%SJD)4XO%g=s{=P~ z1BomNH!Az)&}rXU%5Z3Mh@Boo5Qf;(&7ntH!$V^>Lddo$anL&nMYIw(cBBgfpph_V zgzQ7-l|~L-)m#xsZ zyTO}tj0)Fih-*C%O>4ntP#2Z4^MQynCleaukBPs%_uL}SJ>@8Q_9;ipAqVcWkd9@` z-S=*j4_KByQH?lJi6)V=o_*qMe~&!!VENhCoG!1p`5)x{pZuD9>Weo`%YfFqet~_t z%JLTxk@Y6CW`!O-_YpQO1>y{_EpEPJzwi@Zk~{9ckFLe+;*DoMS=N@=I@z*iH#y_9 ziLay8es6q~0gRzp*13?wdBW{N{rf^yVgc4b8u5cs^ zZt#$B!0Vp1ykLfm8|IWEd-!2jX8Mj>yA^{V5~<>{J9IoFP@;}fpe*h{Kqi}6HX&0F z4qbJjCW-{hfpoC0)sNYE_ZULOA9g{!5--iidpfo?En*5s$`>Q#u#e27L@fk^6VTy= z-b41^Dla?zk@A$2j+Cu?Jor=h(a&5f_ift&B(jWOurff8%YrlX=zU{z9D|us)dc;)au}!w=a{e(F`H$+J#5M*jS~E9E=4+||ZoS(uSk59qr29No7M_AdM=&b-mx za@$?9efy5tI1l%3pLyDb#>Y}bPkv3-Z79`wKE)jMapd5g=E6E2SKxpcui}qbVH8$MmAmh`U;g3FdzRvF ztrXdB-@S(Sw>_|3?!9lDlR7LD9q!Bq4i@d&E)7=MVj(rmy?eL(tG^(Dh_sYaq^?g} z0yso|xG}rN$%K!tnW=z1={Cv+!!Sw?mTW@jUqEMu+Xt$5wQDC5W!pa0?^xV{0ZY%H zJAKJT3c*g@$T^E2QQ6cz^=3xqxTlLaSpswC(k!|!U8ZPicKObl6^r8fnbGJr@fy-q z^(FWS0Ku^bY_o3WA~{>xX+g~ad+#A{KJz4b{Beg5+dLTMW1qWD?z!)QG!Vi#MWo2l zhwm#-JR!btWBKyvqYst0{o5at3opJ}&b{~=*%AC_x0Huy0?uP{=H$uQ_%-krfUZ(x ztSnP``(J!qZv21m)DAt{?6!8Q5-Czd4nJ^j`MqB{Yqsy}zWoEa=<_#(iDn@Gv8O&t zjymF?*?yKO`|P!+oc-!&$Qh>{FYo&6OXQjxZ#5Z`rqAqwR>*qDAvd9TD+tsvAP_&u z=)qc)p~$=b_S5pNzx{N&Ps&->x;*rt{p3%7_v|6xmt200yyO4*nD+tt+{O6uM@{50 zIB&4DbMubqdmk(Vy#;HAthEKFWo=FB`nt_$Ph$&OIzoeu=v5oOvRZ0VrCVpos*lo1 ztZrOD48Q9VuwBCru>@$Enq>zIj$a^%fg$Y4r)1iLdWW02p6u+hseh%71?ksWnwi$I z(oNCo6ur`SDKtT?vUX z50rpzHkQ$}t~B{-M!&jJShnO`WO<{rzcHY|kp+G2H-OITUwVpcS@7h+doH-51+v(m z^S;NHHTj7bK4~$H8z_%F>QMQeUpPyC?ln)BefQde)Qc`vW+e|^d7fOeL&l`ni<(Zc zOLSky^e^C=l2EC()1)%WWWQ18wGqHTvrs3iwhk*32JNBmane+}pYcQieNUGA z1032lT}{}~6A?e6veTV9sElw}hWBc4zI=qvvMo#@gCa~5P9a&aMy5o&>6fqKZ*ErL zKkCT7wr51e_u{BPWTR2wK3jK}pMBL6T2l^Z-gZWYY4>XobwWCrk zU?EA6IY(wSTT=+Y&~%K}&=1%hv7^`Hw!~nyVIz?c@lwV4RwigpkS8UrSU>S>hy_i> zxrv9gjXz++Mo4@}3H3L-Y{KbxfygjA!e-cl0)p>h+0d;M3;}0Bo3FcJL>i{=eqp&t zYpTz0&?-O^JI7XA;@&S2+~_#@xI^TPFFi>P*l+6+ba>gZUgh$yd`Hf^_?z~k%a+~8vD>}(Js|JD>{{_GK!RpE*p^b{tY;rTE2Dev+a}-s{y)eG$1MMLu(h=! zFMZZy#-E$y@*Z%jLhE^9lLn7rxcR2z&zHbIK)p`)!AViq#rj%UIDUa(G|CtPQ}QD2oGN0A2#v3Y9`iZFM^lmc zU^^vVZ{I0Mj{IqW0q2}3xZZf-=kleKnI%ZW{v$rOz%pBHG8Vgum*|On6{(L_jJjQ5 z`F-cVCRPJPjKG`VO=s2jp}n>5E;3YbXeh#yUBOYKu>{;;t7B#8S95)Uc$lTEt-11a zk$th(pK2^&&vuH)>t1kzJomImE+a-O>$S=iU%g4rz33bA{oC##gFbM-t@4bMA2Hkh zqARYKyYJiHsPo7bsa8Q9dFXy}%46qGWPj{4*UEc8cC{S$@B`$mXP>yCz4s?Q=Hc=i zZ`oVkdCsMB%kB5HEYbm^Gjs@=M8uzM&*s#8MHf}&#pK93(3K)`#>q#^qaHCI#C-I! zugQ0Bz0;RbNwKGKUiT7z(M(E`h`jrP%cWM4Tkg15{`|bl<-dRM^YW6XpCB)K=Hukx z1DAXC?bbcF$S<7zWAgA1UM}zb@E3#tZz)hxBdv6)d-_BifPGIG!BM9WpRgDRdZSsg zIznq34%8a`5P;iKzm5}D7yt+o|DTtETvUcE?iz0kKJ_z4k2Q(gA0dFEajMcM!2!mm z9%x1972hS2CN3NCb2=Rr`ZMMxo=ZjD$#kXXAl{6!OJ5acbq1O=v-<dW51zRK(sXBEs(Vp z5l2Wl_J{-InWsK_wx7>^@p`%XhFi?3h=|;G{|@=vkAGEu?mzvF{OyOYl@+XpmnO*^|G48FRj5~QQ7K)Mm*1;)zfFh!RYfB%pe{54>1Yf`{02+VRPx{aVcu&n}2cx!?E6H5Y17Z7!N={6f*1rnffLil&iwlrXUOs z5XDrAZPNu<#~!4t6~Ze7m3l27SWeA_^xD>*r0L4#)mJ)K^~;yRi#BlN|m!; z^0ySLsg@l9_cBKz;Nhdkp+N6+?i(G}OrUH3k~0mmT1 ze%QhL%99sl>7V%AwQ~1;50D{Ue$DsgSO4%M^5ILrE<2WVI0rmrFZs2fdXAj-nCUrq zT4^EL^!;TH0@>qjy_qdgsdvJKELr20kKo70TP;ltorcWOf zm;DG+yx;ladK^i|;37x~6D3>?n4!TEgCC}3I8^mF1V$l&ZnCq@nC&)xlF^qQm1+ev_P6ro$Jl zBi#358qk%8&mwa6i?E?dN<(zWswc?Rx)cjL6HL{;1h^z~8rRyIgq5 zwL*tbfS+L9Q|&+qW*ms_ePP?((y*d73=& zQHMD_6xAsJKtP3&JlK5~yDgn#d3WgC)qW4$Z>zlY+4Fng-@W;E`QT;WfJ_6lpn0-W zPJEc0bi#bV^wG<{Cf~c|P6E(o2HrqJ*lt-|@BphDyswl12!!NKTN53)UAQcG zC$SLH( zmz}fB9ybdtVshYzaf808$g0naB?}1~6!iY{%+y)&@)ujQdZOT5-2RKV2{jGmJX_Pr z2R5q$VS!15j@lQ_QrK4Lw55IUz6?j_V%q0;SLN&%KXz${e)}Ew$~({bw48s*b>e>; zUUkU#hD3@yWbZxXSqrlCi?6s|?!3=WyjS=yX6%O_xR0Fn_@id~yXf-kTDl(-*dnGj}L!=bjf>*2ONv+ zSg-O|ANqp)+B?sa>%a4Zr8qqP*oVrmzU9Yc_wXlq`=v~jfv%#JF5r&Rc9YTN-blgB z>;$~nK#mN+J^dD>)mBPC-wU-)x@=dM1@B%IS(mWA7v=49kUe3e(>^@V7@VAoG7#2Q z7+FFwB<8@hYKKM7iL7%~`o2gA;`2d}Ou#$!L#sx4xX_<^7od+LEIxi6vh_TkK!qL$ zUYk@lF;gFvAed}V1eXYiL3Ayc##cvSXYwH&I#Wy}v9(u4o=G6cg))En( zJcpI;>V{(I)IfbjUasT_6t(H`!DG03ZNKL_t(8KyVJy=D;?lOPWA*LoO58 zfJg`D&l{%T^V{mgbex$bX}}W=&KOH$>ICPL0uz`ZY}mn>5f@6f_$0m4qk#&wy&)ZTz+UpyljgJZi?6s&?zm@Lb2i~c8CYP>ZutHk^0xo_ zarw^o!{1*|%KrQACBO2MXUKv3ZS`!ixO~yBeeM|m#wMGW316^9C6Ii>nWxNdN35?` z`O6Eh6bnKdVCmV9A|iWk*-d`@g{REYar3Qr$onq-T6f*t;at#LMb_6v{`|blLhwxc*@L~Y5p#;OSllN!(HmCQn)+LWAHW80G8c0H)R(SpHbw&ZLF zTWd`NnZ>287iLL82xWaiXb|jl{PU-uMbbVzNR8X3P2-sq(i3gFL}dCSF1u8wZihlp zNoX&UCzMWxb_SRLPrQv|gYon8pr*pf@}sv-zb2q?{E_?1%bqpMsvpg`HdgKm;eAsKbqe_MA|x!iikee&CXc9DGb+V3xv$6*KUE5H1vXUblC=sAH(Htw?oKtmu` z0wl~7bz(Gsu1imO?8D`8$IU;g_sJ{1Avb*QcHxj>>Qno9^>ZI52kyW3Y(MY);Fa>g zj`dWJC+s1Z6$BfC&+7GbaHxc_{fwxYxgij=adOfpPi)^ zujOoxUFNb`AfK%X`Db-{ke7bm2Yt(uy42C5a}w_jdba7rgIw-75D7}Kubc*Lh2xoN z+I@5WQN08tIdWi8I6?lyV(bM?p{-2rrw_hEmz_Ksqu`V|`q0QlgX5+bN)H7AQyax! zzx6|fdkc7gnFZ`lhe$CAtPk}(YQ%aG2wr*LNrGM(mZ^<2ZZ{v%}5}Js} z!TawiPkX}rioz$ayg~lq?zlhh`}6wC#tF-p_io!EZ~x0nBAkB>#xCn2Gk|qYcrDX3~Fw|G3gTjnO${Vqs^Zs@KsK7mgQ_z<0QfBEITs^tK)c zq*6Ro)Vs8;Fw~Jv&ek{0sgI)VY!9!0q(;K`5Mi~#d0GY{2~7p>Gl==fI0IyZ#C8s}HjyQDxnbsl~Ui1~Y{jU4d5jEm}?Tel``=S{Uk@vJ0%>?4? zYi0@TKzo3`;%ncP-~GQoAln|;K0EeqyRFH;d;POz&-NGR*ap!#RnQv<&T;v*-HQoR z|Dz`MB{u%XfU=t9r(;%dV8NMaP;LibvEIN|M&+kp`+Rxxt4^2QT9Cu1+%aGhah`#9 zgBB0avXw8(DO1{f+Yp*z=Md)$ro!e`&Zpsd^IjF+XwB^s}U z$cJUFa%%xviR}{H*x6+ld894eN%n%W-&wI`kfx++Lp}vsQ7mHP=(7x!Vk zXTTJ6P1f1tVBxm@VRx!srK3EoPWdSW)cHd3@<;$NTfB2iPmlGaw zDDS_9ZqwnUf72N`w8BpwWPytNnrgqvUWugYrUPR*PKHC8137qbm-Ceu$NdhI8*LWP z;6Jm8sm}O-9F`FB7PvyZU;@%;5Ct05+jS7%MuX1>zigsYk8xitFu}$5E%aL2m(`ux zo7>RI#`+W)>s5RlE|P`-GfQ$;jyhyt`SItUIB4YM?>~L5yzkQM8MGlnq3u&6da}qD zKlK>dYwI}kdtmzxx!{s(bJmh_<};3)eH+~a+jq$M7k@+2d2EC9`&r_A6<+MgCSW|fzI*gQKlEM;;DApFGhA20jvGyk6T_kQs6 z(;hfpRFrIezTwPMWw*7l>22S!F7LVUim55+eMTFBE3GsIP%HfVBcHuiK6LSyW_b}2 zdC?gs$;rnbk@pGLEK3v!v@E`JufZ89xg&Et?o?r{I`}>)HlkxM6%F_~wB!!xuq(;3 z*ci)ZWXB$LxV+=n-!NtEHuowoqAD;D>8k!2XevOP-^)&-SN;ye7PU(ohiOqu>KwZ| zQt{93`SK-8sy|g67c*`kP?_Jp^`a`K{c|=hAnW!&RT}CF{)!+5+?!Z-zEf8Ln~+gG zP+GZQ@(4O!n*?j7S44DQX3~|!!o?#*+Gkm)kgk3Ga%>?Yg4HPcz%)?gHaf})#pUM4+!x@ zGOY?IK+jSe3t$U?zEHp)119_$-Zz2EtF7l{U&|{Zvb$yNZ;%t=4<7NB131ExVHL=O zR$_p*z!RT~!1)V71jWMPU|zeS!B!DC(-HKH9zzQ_HeZ@^ZTe#;;H{tDSFkSi+L0y} z*rfF}Nj?ce+T7IGPHC~gq5TQmf0miLE|23Lxp}O4fyAtZKr2S~8c~6c8|X7?`-Px0 zp83@tG-X7pU#zvt^PY619C65gL!LxLZoA`N`O6P}wdq6QaT7Y@trtJ_7}6Em1NEc>POHmfdG$Ql$GoL&=_C5D*lfU}lRZ9>V zWe8&y5d`)$sFLZiyWjh7ACp^eziW1=Ll4?d-ty|FCCi${9FGR0amgRQnC$_W+P&yo ztB&)-Wjz+WoAKNK#P>)wyYd!B5{eTYX;^7`|EInx@BX`s7oJhTa_muu%kTZiH^^IF z{dC!Vw=Cerubh4Mbt`}G5{ossRKe$$p-J>vHW5S)uz)?=kmQK-F^0upBsf?N&f8oe zs<__u!AxA`9SvFH6|JtTP(wnkV!K@OdDw|%6P{DoR}X5G6C8tOR(6%XkCs+EA`4lB z4TF0v*mpnK=2VOJzm`Oa{0?we9Pe+>-FK50o__2?nY`zNUy*yZ?eMmyWvJ26H;}S* zkKN?Cr_GP?=`Y?W|KDBrThk6fLEZ=Kv!^`slw)T5yX>lO$*p(Z*Ch%Z{Dhz@W<`)m zlGK_Ze&L%xkPlz_^;tR&+JA5PS1)*cYqJJMPDEJtvaFerbE;KNdemWZ%H!tG7ku`M zH^|lBy48oIyOTaW@6==E=!YFV+s}oc_|o*uzc?u6L}oyR^3`G0q2d86ty<*vyY7>B z{I`$D0}Gte8BaMu9)4&HPQgw@6BwAy=wG@ouE?CBPxmmR%=U_xDriFDv@#o&>rs3Z z9&-b|C^7{`@44`D`NiLTk6in$#gArc*?srjxPvIlZ!Pl5gBw6q{+g-LWzEl5U4)bmSbFw~?;w%^EG2j^WP_Pcj z(;M^{yA#W%{6QC5kOd?0NIp1cTB`3SDbL;upes5T?G9)NMr{Fupi-a;O~6&k8f|d} zHsuAU9VPqkJO6jlKmEn;$QQ1?#WM>Wf=PG0fo$SMPdQrl*=vts|J!%0%lkA-C+dSy zG%z^x8OP1OGk*Jybvgf&Uk^*9NL`3|VFjQAWLOq7R&6z<$lrYY>V<#d?U|<>D-YRc z58t+kL8ABEzAZ)=3^Ga)dEHCr{|ei-2e!*O@4wR98>{X}_t>%~Kk>r+*>5d)$Sz&N zN3hT=M2KTzqSBpW*BzXvIlJatx5|4zaQQ54yREIszkG3gl&|=lMj$gg)*nH`Rgo1S zdv4)71Z1_QwPy=;6@&BkX<+U)-z`ChpcJ{g_B*%A|MI(kC4cq4OO}4;zKF;%M;<2c z`1Lo+PyfU-Wy|jRXPbi@J9c8U{0gNs)?rLlag# zCWK{w`&Y&I(I&U6=Ui;-^4o3DJ?G5ybXQkbSAA6-hD1oVKY|~{S)nC0iYv;i zc%Gdw^SifmIZhT~x5}qWC96^bb zjuGIB6UokK@VeG#UtWwg8@DS18lxK!Lg*ZNb?t~#8hGi?y}SskH*AmXtQxV3KN|XK zk0KL}hxgdAs}(ohU%lVEQ^yWC_r!yB#3ZyV3H!H2!vvbnIQAeMIHcOUe(33$SSen8 z%VNkhymkCY?A@n(_IXOTJun43gF%q;tUM0MyCgIi)JuZcj7&#^8nq<;{Ma-sTUC9! z-$}$5X0IRWv-xI<*tRTQp$Wna>8vi|4heqCN@0Ts=Xb!kEO{29$cQ zTj)LN^*Vm{=Vx)v_in(#CePdlitU5%JpV-e?CbBr$b$xQeVJ6YK1F>RUTNS>zon5* zxgaWpvZ|sE7IUpTT?mugRqTzE)`5INo&cnAY(qF`6ft1ksm`HSJdo`$J7#RZ6B_d7 z91{s5NQS~#Z0lCOe?)4B@OvEIQ2^p@KN;pAZj(?&1gjNCQz4d6h6YU{j4+Ezi zcQ87()P&9nEhCWufd;t_yMmlRQ|C?{aPe73Rp#BWX&Y{P>s^ znpv=94IZ03PhBhBnj@wyI9$so0Y+tR3|dsU$~`IWw|d~e?|inB#+F(Qm!3o3y6#X% z<%`-<1I+WdEP?b(f=O%(shH|!A{FPTFpLolZF`lwM;VsWvxEde-_6@lG zzGs_$-7o+gupG&w1tt2qfBR0{Pt@6>AgoNtz?c50bAO$Z3z% zK5uCQDID@3_{Aj5FERR~4cA?%jVpJeT|mc1hCUHHArazOAJ?yq5-TD*hDfk_bm@T8 z#vD+|h3BU&#gsYed#|ISraA?E(inH{*n+n-m`i_d+7hfQd}U(Xw+jK@jzCBwmc{QjP)*i{kI?A4fNw=h#aHO( zbJG^%m061`>l~-N^+*T<2347bP(f+)W7$NZV)a~R{rFku4Ah$oj%=m$H0Qd9f1`w?IRr_h}aPQ!6tGoYdmE$Skk&tKyvwi~Ho6@Rg7s^_+C!x$;<^ z@}Q&9m0%%26z_5Jkweh6bA`uSuj5aT&mn?|&{Ww7uu%NvtvF|n*$+J{_Dr|deK_r{ zfuRVB;DQr}R-SOyTKBl~30kr0P z;+Z@Ush)f;pOSr2(2-K*HUH+0XVF?O_byvnYPjSaT4P`oqNln9C}k5K=;QizUsSD7 zc50lI@8a@0vBelAWXBNy^h}Ftqdn?cJrx5t*@!8%GYi}}U)=9vL)J|t$GVwhQ+oSKz*%bb z`6U)aGCz`qr=mRR+{v&%dEv>p5-5)N;tem_E49OxHk700paf`v3eS&{25^R9ZIKwq z<%k%d#GXiwaCAgo0wNuqx7J=N?%(6#;~IrPqxTA!i|6`RDVGu6!X*YrT#? z{AIGBvkB@1n9ME$iaI!<;%Ka)WR3=-8Z7Fg zTxiM#%IU|{PoemXLUJ_`UaagdhrxZjWB+}s&jx?sx%tHxW5Dvp&phls&NyaY^r~1@ zU$1-I^%T8{%?toVZgKs*6NXlv8DFn^-1(&Sl=VK>G^{7uB8-n!k_lxwl-_)j8X zC-28{iiaP1PH)Y#>9C;#(YJROrBrl%L{xRU_^hKUl~HTGjz8SLNfc>g zsBFCP;;rgT?}>7nHWUmdA|MyuoRd<=n%cBQ$dUBYO}}KN%5gnppjzv#_|2c5!Dqkw z2h3lzGWS$AwY1dm_H$3b&%gOT9C64XRyY}lKo3F<5M$p+IY{)ciNZyj=VRx^Co+AZ zPLykFQi?c~6eI3sn8w2L5DK z9e$AjI^gtU_C@cW6<)gcxGU^Smj=Pk_qg!=+!KaYo<>*q9(O#$(y+EQ8p;OOD|XpgWAR8*w?d-tfk|2TQq2*6M%I}+*f zM<0lT_U%_$&V5fz3rFojuuUk5D#akeu99z2N2M4;WFUI2@#Jyy?9>I7v>!fvU-azO zDT0eQ{2Y&QJ!V**N%^rzX@cc06_p&{Zzl0L3f{QlFAsbdm2>Dkg(FN|nMjh7S^3>( zR;r_D`>chl@$ql{0XN?HROKR2oAw*r4?q6m<+$>))5DGr7srs3G$ahvbTFx@y+z{BHtU}Fm+ovGit$Il9AVx#I6lrs)3)>tqS&}M0wF3DMB)uOL~@~ zKJA>^VV}D8AmW}zLiQ2LLm(kyAfGR-PNpl-*!dH;2ps4w2ujG|VtvI^Tuyf3S9tEw zefywqpYqkx8@KGhD+|`fwyOaszIzBk5~#OBt%kEtsP?L-%vgqHuWvzAWF>|a06KT9 zH9U=O%8X@L9L^z6=WiKkaT5eeQurvN1Vl;(p$X>^DERB7xu{B`hV2ujO98b=Rs-$Q zAZ^{Y6E{Eb3VY~Om#DK-hZ-(Dr~06obsM(ePmfL4##hYqkzy)U5+YP>&6LQ*;5Cs0 z`a`c81&5*mOrEi{G6dhDLkq?qOR~r>*3lv-Wtdbifsu3$lz|1}IG5Ko=xr`3y%L`m zC@+esK%k+@L|)Z&hiFYjAE^bl0Ez>viuzmY9>2Tu8C?DC-(&8A>TR1c)oL}o?VRKB z%kO*uM;5+wYJp+1{H|IirYGVyv(Qe=xaNscG#zG4+XIbM+k^OLh^Z1M0P);bx+cT zL?sN*&8Y~mAcZS>ADN<#8!<3nen`{itb#fdK@LD=#H6y|>!%$(1bupzzmMH}kGr0H zEz%md2}(W$FysN8cl<$>r_p)uap&W+;&(kbG|yQHdmapqpUbYmmS}*Kl5DY16x0V# zPF;d66)$@keqet@yeC0ovJpO7p##I^zX>=SeI`uI0-K*N$zx|=9*tM%J zut#XUQ9!ATbCO#eSvG~t7{y8;ns=XM>ImO=wbt>{j761gIO*tNQp-hJ)EsrZDh;{1 z%x#BmK8^M4LZ?PaV9MM=D<9}FR;&1D9Sx8y38fv%+<##2{CX4{8W-{>8}B{v+M+f1 z#CLAM4Q)I_e&0d;@S`tYj!*pa8O5Sb-}tn>B+|(j8F++0x%EXV`cPuPXrXUh@LQrU zQ`&?aIX)g&8EhB6*a)wPX41uMq>{?v=0sW1&GDkYy}qPqVG`afsa@vO?Vdq4sXpG1 z11kv=#>Zm*X7GD993zC8ga z^p|EW$C5SnSXDX~pMDpT*`;F(&KTREyqU|eX!Rxo3UWE+X<{0!R`OjUds$j0gh>3_ zv3obB&n-V=yLZp7*ndE;@I#mm>? z;pgXqlv6B8$e>L*W0o2_yAVo0FSi>>x(Prkk@mh}2>#HagOhELaSk-o?*y`CmNh7nTtBD zXd69JuY3IW-Ou6E-})V1n_vCrJeg{>8ZJ6}EPnCr4`B46L$WklnbHfxwAGan%V?Ad z6x;B+s>)o8EDU|t1Qyc^KLyy74umO3V=^!3WLuJt0v36gHlZWUG>VVUNC+>0nxMl` z-gflZ+h_HA-~uV&Qho&h03ZNKL_t&&7CqS+lt+$!`cCFUY|WyF1TW>5hSF8U0Q5i$ zzX7JnsUI)ziIlA7^pwY;r3MU6UU-JrkHh*netTJ4rd{YPFw4?UL-o2ag(zT-J zFtG*?=ZrnD@-#XR;LayzM*vd3`d_2#WNdprH84B4jE5fQrxTFF&(2<$9@-<*(ZdHJ z55HaNd9)$ja{o)%)fx;<=zCTgMLq92>qvBKbdumblZ6qkG1&03=PQ(g33I}k$r{@} zIWDB2N2ST%rNMvx)g{=ry*w&Xt2rEc0IeG!Xzkb-CQUHsJ;bI+Bg38*14*GIjp8p$ zUi}pyQ7LYoi)Qu0nmWpEPDu+I_UYdT-}=lY_|)a67a%7Gz=Ts^0h$!|c}v&gli#@k zzrX#j*txTLuYJfqeeuIDz6YPY{EUJIGlodsXn3X05`i(MN!`ra_O2Tk-9jfm{xn2N^>P8(fpa(j3C}-!)1#8e+*I{T@aH-NLYA@<< zX{q6y6RYRar_Nr1MXT6LF9vT-4GyZSbH^6ErGeK!b=ER0T)BzqtmFe3Ix=>lue@xd z;lJ?4Rm<&fRZGE-SLaoq&^2P%fLIpSgGxKuD806D6(+v27*a6hp%wrzq+bt=A6xy- z^;c#s#f!66XpoBB+_{jG3>cE3cLIWZpYsJm!)2!hU3eNXpOBNCyLRK1SxYM0GyH%7 zst^y+=Lsk-{@U?Pc`XYPp0Gu#q={;lkU#2>65!A3#n9}1UT$rD&f(nCj>a#(`Cc45 zV&8J2@;{WQdJo+2mr3~KH-C#+bC*`OQ>I$Y;li`V;+Nm~AdXgEJMV&_@>S$6GcfWC zdG$RX2rui6wrppMwPl-N14l)LY2A)py|1TtBVk%rq5=9Fl+52L zwS%W_jWUEHNiqXupDhQ za)87+N;x3P5N*ZaSiEW@Hg7Fo#C7og{R6=A3?`%^YGd*MZn)<~!NXuARe00mvh$BY zhl+z{>UEDl+&dXs9m%FRhGs;TfW91P;Kl|)deIC6{L-+3oiKZR> ziI$t`((}^@N|l=~`H(I`ltne)i>!{R?e)kaK&T_7w_O~o*=>PVp^G%Ie;<7NvzOx2 z?>z%u#Ho^MDoFLWHnPR{0&&e>wiciI?jP~nTOY-aox7TD^WcGd;|E{39G`mcnc>Fi{&og5w(l*S*8>SKpOJ0m0~Z0I4b zE0K<4#OSeh^w24_gQxCwr({E|`S1J?-|_J(Avza3s|jK_pP);5F2NW{#7@8Ee9Qs+ z^s20B;fjr+NLfz?`8hcW0kk-Wa~iC8f916mSP;r*Lm?HTkN-M#sNu}x8z+J!q6{>SN1>ySl0Fo5X?ZZ-Vxm^86Y0Oyd|%f(%-pL2Mim`AS-&PUX9bH({oc7 zVAdkNm5x21qQp@L^~bRd-nstNwCsT(ZA?0TkugdMfD+?Hs2K%_ z8i7$1Z9ixH(fGwT--j{b@Sy}02-?zdDzkdrc<&4N#Mgg|8Lw3zz9dtv<}l&R<8bYF zKZIjKPjXSXkW%KM0@FHyh_h)bKJ!jeh?qBFQqIk(O! zD4Lj^?=dK4I;D|}b3J0@?^j{ez4utKauW-OL9c8$wIOrPVf^SJmD}V1;O-~q5GP`Z zW$7))?q7Kt9RS?*#H>h{TD+L(SsFY%7TMD<2s=_H+L}?2PTrIMS18$*3fhIlzU*Gfy zw(lrk=U~&IfqUco|9UyDe&1Q>(y1d--M~&wQDxacA$qxwv~JGxL@iQmCXxI?&|*9;b}BZ~EWkCn9j2Mc3W5NmYQZX)zV=G(v-&;!WzjGLSTV}$e963;6ABT~ zs5j(rCCwz|Cp>$W8L2=*m)9xOB&#Uy^{rUM_WFix*uJxs1;s%rYUKqu-VIQzIh=Ds z_1yQgIjb;##YWP`f-q}=9XfWX;p`I*ZcyGz%w4`Q{&ud$#yuIg8VGs851B`t9*UeNRru z+IZf-iv~RPVlwT`B?CCE&jISM0CK%llq4QewE5|%lmrdyH*{)!L>3I$?KO-z zy07D=`(MCSU;7PSon5`%P^MbV;rzFZ!L{G}P>38zFe7;rz8KIRZ$_RJ!jncH=&3N> zL(!tP3^?i>;rJ+EkO5T@h~~?IxUrZ1)N4jBYoV80gw8l-zsl3-0QS-ak!hybRe}FXh;={GeY*-a z+0sW(Ndr}C(17)u%IDMpptp=hD5c%}fZMQX8*YDWdX^6Au8u7=T+-;EnT=cVr$=7Z z&%+oxQm6?p!)@CSdJMt?hXr+hhBb7^3|KKSODkk-7?+OZPCqH`t*JX|hm6y=$kk+96fHhUy=YoP!gHh7Tr@ur%cH z;!Z?pKIvFM2pI6sH&xlA1RNcRc)Z@vii&5h>a`;gsR%zjygoMgaKJLsPM1SF2JC z_7EHwu4(ejwjLx8h@WCR4Jkh^B`R90h@BV*&Hyh;jf{GaZe0+3l`y7Bk-AhY5?Ei< zJ>k?5IC`X6li-ng9_ZAu96$rW;luaC*RMRkG7l9G0N?$^eb}|TmD?^vJ6&Wb_}4~o zQF!g6F?!U2_|M-xfJv_|689kb8hU7jXPIpUHMc(SBA$6^EBIb+gUOld-tmKyF zY?no#BI=hvePW^V{qITs^I&IBr9E%df!J`y=b1M+2^*~zS49so78V{egDzWb$eZM$ zPKO#eOoKMWo(Tg0^ypg6#%Rc`F-B6k?Irq~vr5C{JvMFGRXNujSN98Vu$ld` zl$NYmhleN47mZ0ZZO?9ndpjd~|me8D0)DkCAEje@LW=zje%=7{PAoXw{GeS4vQ-|B^{GIeNi*xf4Z zbcUBN1-1gu(QeNM2cW~cr019 z5ug43O}O~1(Rk0rr=x3^>N64|4gL4RcR&Bnc;K%u;=lg*2(}6x<&=8Wk&-wHD5PEL zU@<7jf>M*L2K1V-FWCsC0Jmk)E(kjl6_FnA0``jja3Y@=!A{73JEV4d zOPlOO8sxB%@#Mv=v{p%1ruH1O27?%1uW zjK(pxSEpLd;oOs|z4V#$S7Y{)^n!x zNA2}(GR0M*YOX6|1LE}}KY@xmJS(D1>ean7SXfNGO{5#|dkJ;bpj3V?J@fF&V|D@H z#(Q53WOJpiqA2_ z?Gw=$ATnG&>mt`pecrAjW)DtwUb2$W6h|v5WvH}!1EaoehxXK+_)icR6~xI+cxtKrYf6E5iIlk>fV-rqm!Gzs?1X`~t5CgBmT|?Z z%%{E=FIOo`J-VlB2Xa#%x%Bd^rI-@lm2N=*&G8QI+Y_fBUwzQbwAo8BdDaSOS1S-N znB(hS+zLJFy_U74F-A_kHO!usl>n2OUG4E6)o;UxtJZF=Y-jgweC7df=`p+xhB1O? z5!q?)#KVTbsRpw=M=U_T0i|y=4d~Y!-@N)=_{{syMEB@ri^W<(WRx>NG|;E_Sh{*6 zuKB^u_{D$Uk8Rtl*PO^Su>W58&gU-2=RSNMx_9ZMrtMN4O#BGZpOQ|L9&KBUJ3Xy- z2h~X5lb)uil(oCUe$W-sr)nEt1jY0i+XEH#HTq1=JSv?l>i-)fIe%+vAER#OJ4E-z z`|+1Bgd}D$f5JC2AEo5qWdtzInDhk|C_H@!G;KRy|r+tVD{u_-l87$|pvXN2m+L;xd1n0)nN%ua# zIa1_(6vII8PCV)$Bx6~5IJ^K&f$OyiiS9@%>ySK2|Kq{lL% z(PopuhCO+f^tH1^mp86$hwl9SQu`b}V}46q4BLUGAEM)tC<~D(DwamlWMLNBK}6mi^k+;G`1~EyfPTI4jjJ!kXFqV3@Y)Tn))5F1%{UE% zq6-SI{U-eU_xDx4LN}$M559fPW%$BJ&*Q13C<|P_tJMMtPRR;QTdJs7(`-uRAkizr z5ZlYjmM2|S;?OykeMyI$UKP1jUDRHmm zRi+6W+LX>w>VYiPtpcVco+hDGTIf=idW$1j>I*l+O}htLEl_g z*;w1UZ6|Je@D%_&Agy6{t_=sx#QqV&>SZe}loZM71CLaao?=$kxueuti1@t8>-1Ap zKcz;i&3Er^1>hAIYX~+~}d1aj)x3bULK2 zhLN{6B$6d?bdKWX)H88p1wCEXCD}!_Vv55-i9FPTIK*uHMO_cDT|`X&*M;A`7!X+{ zAKeC4tWg;#Hxc5FFgmHrU?~tCtkr7isdL`e%ip(duYQ|SaS#eXo@z2r8)!Ir)ILpl z=~2Wb#8d!2ly}6ChUNX`$=9?d21*r{-cxPviE*8dom%<8c03O(K{h*aY?Ku5JkYgs z`L2U)+jnJT#mQDA>7FO1W7F21AV3)hsR${beAIpo51P6EsTo+iaeMU6)n4B?;DsBL zv&|V9_S#}<8f8O8|H;Twx&y)bC>dl3pnsog8QQv?-Y?G>nAUS>0Tpj#Y^TsQiB`WqjqeB+%>{reVk?bm$ZY;^C^Q2~uq53 z+z)TU&wh7ro4oe^eS71ZpS=uUykY`+bn9qER`^sBw6Ui_3*Fk**W!8l&qSNps>=5X zKwAj_zm3_4m4_|C&ST2Ie?aX zEfn6?P4!xjGtND-BwMqvrGZiJ)uU5lwWJ5-;ZXw`u27$|_;pNQxE6#^MdL-Ai;8Nl zhV#c&&!x{>vKFt*D~?;0+oHTdnvEB_FzjNqEZsJr^hZ%JgEnMtbMeA6@VwHy%2Vf+ z@!s$!pMUk*&A9u?S)fQ!vH{Q4(6Q!l$=THh&8*+J6?Z%~Jya(Sv!GORv(xeK|NWRONi)fCYRPz?Ga=C6tRY5hi1RS9AlP-$l>Dqz6_ z0Ui}^Sh~u?;9h;?ZdpyBZHxuzZ;rIbJ@tbBh2UwkOc^}GeQ`f}J5fRN9YTaDvtlHHnlHPiI8}ik~Ibf{KkCrY;1?UPm0VK z?@&&%;{fIy{Y;9x5aN8QpjU|luP=!BGh}M5d+ctl$A7za(|3J+cWb@!1v3bB?{2MQ zSIFBM%kbFU+NwTx?QTsa!liE<6NT%~CK5frWYq>-^P^kwt2UnB-oI~eeB)3!|xC>)l^C}Kyj5;zstI8`;=3r4SE`VHFY@>f6*p=JNz?;*F=zEwu6>Vi|v{8 zCfU*^@Q*Rp+OZ*z8mg1k7PAC6iNTqKUu1NkxJ02I1rSU)ix4~s?dFD_dj2)1R7=e{ zoY%lhpSyT1rY%?->5kNB28Hq(d+GC+uEUf$#e2!U9VEs}r_-$R;Va?g5p7nWtMs24 z5ZSCYYT$w1-8)r43_9?~fF4);v31N@xEfEtvV^l((w#%kt{ri~_`@q|EDo%B==u3T z^zbqV?vSz}lCtYdg6Z=aZ-q)plql5ih=Ic@ssM4 zABAhb`yrfk)ImW9vG#N(bIySwz*?`@ap$8`amAOe!;7!XZJGuEIOF8e_|=cD!1ytT zP}5RE0d`oL@2p5?a)sJi_6`r_K2sSQP*Ak1tPF}S%IO1gFtegcV<@0g0o&WvpabnS zr;ajjm@I2?fd-p$Y_i^o*9B&jK{}T$6$#9BDJ6vll4l6>>gyuU*6ppR*UP21XE(i) z)q1=qjoPQ7mwxwCuW3OFlsMV$K*9+l2V$Ro)gI+NPtH~$x}1k5X^l!Q;jJ?R2T^$> z>=i&rgQODwRL+Mv|^7srJV98S+AkKCj&4sYbx#4tJ+g9c&&{!_cP@ZuPSzB@{~gahN?Cw zOfoDCcuW%J=-s3ovVO{*7-``{2Gka9X2-W?ows4w``#9WIF? zKEyJieA6v$MjEqy!2s7Kc?|z;%T#nGH4JiBL+_r|#|tlAx!#nK8P9T1dmtWb8>id! zSgi`#w#5%}ajc{YnVWBTPhiUM&+ZX#mX37QHCKD<125te-)P&r(gENtCm)GxzxyGa zeDqKy1F^o`bPXVYV$iDIAKQn z=;U1}f@#vBphr@B9}^$MW%LxY0cojxL5>LvnN3Y;)UzE@JM2@ZKSH5M`wHdIO+0|ItNtxo7FbJ%;>jZmUL3?c8|b=cfYmqdtMX_ z$$l+?^S4W_h+asTyc;Hl4AxEcf^sQfr>6Ky%~ z`j#^eanP&lENC1y*KKW-#OMwNSZZjm=w*PfLA;mGLCbGjA_i7=wNN-LUbz9E`N7Tj z_05l9M}zILGWFZL7ryrCOYy~zo`;^|R6lz+M&bfd@c9&~J=PI$G>j5Not=sZH)6HXAj1Mc zZ9`&yF~%UjQAGHE)tow^c4@t%Vd5dgLsVk8%2oSw!N1Nuc z10B?!s+oAcBY?6n#LBQY=#yMZ_q#_%iE=$|zJD@4{*B+X*=s-jq$6?d_dbkMju{q> zp`NCcjt%KUA273&P2jG_UdBhhcr9L-Iy4Ln~>o(&HKe-kE_qsc= zX>;>l`(C|!;LD%96yN&PJFs`JuFTKu0M8|_`aRqbaHow|F$lE^Z*9?XJ;w|Ae(zA$osUk# zww=3?Bb#VBb@Txkx?jK2dH~>or>0}=#vNd(3FtmF%*)@*L~FxBW&?WYc7=kV=@S*E zE=zXod2=zt(_=^NS6Squ3+@uBrEG9+~w;{9{rHX)?;*;FvLYMTI z&l$e9B|YV&y!8?X#CyD9ul=+WkHB@``!L2IdoUFk+nkSNGS5B9YY@eI9-oGfeDRlf zeoEWC_LGl49M}KoV>tVykyTAq$;o_C7TMfMV;M&~z8kA;u#` z7>!m;zDuX4JrAO3x7F_eD|t4~g;22qBm^dC-};(Z-4+>`OhweaY) zb^C6tUbi)W6F^H#4M!c^FP4A&h=JIrUn4Jlu0WAqNWP@0xODWv{juLZO?c_#wS|XO zbBywg;Vn7$RLWni#zpxi5lAqO%X^o(6qUWKm_@Colp_Ej zO&v+iCNX-Eot>4x4G8{iY0n=%lN}I2x!7=f>?roIA_VZF(<@L>%3M9T3GI=m8N;N~ zS(L^tR%z?>cy->YQaS+O$V2+WIahe;CsnU_U$}fdrp{Z<^-JUf2nA4lpU}WdU%q-1 zo}IotK44FrDk?I@To{%zrCU?;$wBhY zfOOCLBN@R%Q1b~;&G1|mE-DFM zow^6n4eSue%a&Xwv;B-YrFQVtiJ6i~LA{ZomZ&TC5eqvZTe|Nc?+f5iVT`y;uZrh^ z#fDvNiy>0Yf*J3D7iLx)^}`PAhZ-D?A2ASv8to&0YEBU~7UbCafI{Yu9NG^DG}yOI zbLsrNIj&cDX?8B1@*4_b{p?u#s2Cu5W|LHk-m50EebYvXK94(WP~{x&+{LeB%?1%M z5prT`P-ai2p4~d)g7MW#Xz9xJc<8x#p$eh!rCdjy;gmefEk{1vzgE#_QYM;F)XoOX zE;wX5ETCcoBE5{`!)rjx(#*Nb)XR(lyi@IyRgeKS&K9@F7;gqd79=*OI6bwg%p>*o zjx-p-JJW+Ee#R|%O;KSCl%`OOAt|4_jSH8r!>7M@W1GG9y?Xb+mp*)rbID zgQZNKoZuw`x^}{$`}J<wt`Zp#d5NA%j1?Q^;~IqCC%?MbC{St> z8;yh-SQ7!f`+Kab8-*uW#m@TlV`1TlbF}@z8?F4`;(q9 z0LSos^oVL+zc6iKY%|jl#vHx-HhNRM#jTObOZKbVC_s~5vV-7R=8?F2AXZ^KHCMuO z@obxt)hCJ;`I$FN-h149-(+0%^hF1C z8b0*-U*OrvGulK$<0ND<=y;b1Oc=*B?L>5`al=YW?sxY}x5Y}t6M9VKM1p_2m?6r7 zmD_eo?RHEohhULH9mzOxBiX{BP`*-Y;j&e_@%PN!9wYVlTh8@emyXLZ1q&et8<2HIvtf6%H6AH7YsXKU?nXRr_4jJ zd|m$d=0@kYmrVut<}pF5(JoTV|u`sXxlR!bqkx zPMRMy{p8`XXvO+BSBE36K}^}y=YIlH*FD%!j!mi-#Iv}*{}s){^@P_ z@z4K+jhmYH+8ZY+$p#=sKnhK>?7L`*GdxtFj32S}YMVsbM7&{8RuTB80p$O(Idx{3 zH7b0~&d+j}IU)EVf8y#0rBa$$Fu4EB%kDkbNo8t`q1CAm%3<=%l@;{@Lk3hE^u;SS zVDf9LSouYdI19f8$$jX&l3PU_J8Wr7Q4|2M6p>+fYUV2nWQpmu9>EJN(fW2|>e&q*) z0KolE&k0_-@q~m@QlUf{LJ|N+d3wTIPaS-toTJh3Q0ov#L3?2cWuK~k^61^Y6UH5V zP-R;uOi;GGMuTD!=Zp4eTP553Z7TvZ+ zbLnf=ZNZb#OE<>WhBX0YEK2jJqMZ4p?=G;=?9mNV2r7)33BxDT0C2cq+;DX2SiV4R z+xDIK>y(AjAQYrBNQmK67|%->+J8E?`d#TecJ9U>@0$u<&?MWh%Pho4hQZ0OSot-f zU*oAXlQgKH@_hs|MaitFR9;zQP)3(eIIc2Uv3ctb-2XJKg7zwK;A%B)t7umO(o6In z88rgQ;!Z<8$Rxp}xX51vA9y_oH6qO$a!MlGL`y7>FuJRO$1*_jQ;JtSw<8%l!HC>+ z?;G>lPZ~1<*Ztt5ID6a(g$p@3!515I2s8zL+#kI5r(c-fCK^H$b#m!x2CRFW{uyZC zsS9n$n7=A$Y!6^4XGY74$ zRw#v`whstTISIW-MwMtCB3Gelrwj{u>e1s7gFxuKWI*)n+7aW&R3Fsy*z6))xcZ2Ob9-F8F%Eq4G)@maN-QC-LyR_2M!Snz$3~eB`Bp#dL8*;Z{#z07gY;y zlq5z_nk(77QZ$oi_P?Rsw^!kRa_{vXj!w-LU8#ZigtJf~&hCrZ{WiRd-Kx)g7 zS8P8K=%sFid}){jf?4aJ>k^Tb_V&;zwbMd58nAMNN4%r;g92VwYkH$#a}3RRQRcRW z6$a&boi~R7qylozVcX7DJUw+uMf=mVbk#<@Fnd*`mqUF_cTs-vy^)vx`i8A|{G}yO zAV>&Z^onCMEZE6tWG{aZ@{PZOjSd}Vc%_sP)t5uHa$p1{_TCGQs$7k}W9M%C<*8X* z4->1tbM3klJ9KDic+gC7tn74Q$cbE0PgJ(HX7hspqBqZFtZbw0nR0k2nGs?yBL-f| zgQ$-b(&ZDzRsx9D);jKdY#KiwWz?&x^|%FHEy0G84iW)AASTJ#gyK|+*-jIP`vPu( z!t`>^-&vUz2K5ashI0Ccwa?k;1wj;BoftcX$60*dc<&3i>Z@({+D|<8FkJV8kK){M zBLjbkJ3?ks@#0PcB5;3T;&goI^Z$j3lU{8D1qK|$8e{|h#8q|zbzfWEY-^)oShQ5g zn}~L)Xpb``2)^^e;`U8@{_vUbuaL)jkOyWS@Bh^5DlMg4(dn!f>FGi0sb}f75eVfa z$-FAb!CBmYVA4YDZf*YM5BE--i+a>0G>8Qcgm4`)q&G$!)W5R42cMaXSiK3W(;$p3 zDdC}q;fs)YY20MUn=@rVflSgT(c#koM?t>GKI#m22Wc~IH*2wkC| zTd4cI6NX_x#UU#I@aIQf#`c}NMVOD8pcRd5p1K|kLgC#A=g@+yOiDaC^O=AZ8M#8^ z#YV+=bU5~~!8rWT>TPV#zdTR81cwwKy+=TlOA!H@$|25^{?A(e6s+ffPIKP66Ls)2 zi6-$zeuWP3)&r2?RpiCGG9@-A1)kXyhEuX&&wz9Zk{7O6S9t9=J=A8e{c|6CJHC7M zJJGLqH%%9-A~k+AsmztN8@J&rKfMj#|Ib^S^V$^-^LYkmB8@2-avVy1URPN-XvHhs zGs+^i*U8F^otImW+jHeR(2iT$)Z&K%YGr_$VrON_hp$x6fjlH9o`DpesEDX`vA_+=j=dEC#F+01Xz$ z#zdfOZX$2t;n2BHbugs;(0q!a_MDJYonH5}=q3O_*UlaAz6+17Z0oMwt+?xnnF^dK zM^uPUs!JWZcj<@=Pd~h}j-@NtkaEoiazC|W=#+Cg_RdE((ydsHdiGF{;W^~5$auVU9Z^Pn03y5KgOa#aQ|)Z+0i!C|t#B4UzEs}*>oFM3^3;k94iX0QE( zV-LgiKfEHG1Q(Sw{jVT=St7&y;M3Fb!O#5{o_uavMQ*Sldg4>yT{3Wa(JPBl32@Eo zZku1iVkw|nfkd$C<#QQXZRZet`|VQ)5QR4M3`Ze}k=4Uj8uI*HI(raGp~%uzANpwc zDO0j?SahRtUV?}=09WBukGq2|=M z5IqEwtf9U5^pWTx-bI~DH{U-+?DLnhX%vGaDhQVOOg==xi{a`-?wd%V1Bz%DK|%h@ z*uqC8sTa#pwqlH2a^{gZXus;{&tIRNfmw^zh$|A9>$9=#ZV?srQRpr7kLSg4>9)x- zWn7-30wyq}JU;>xLOxym6Lo-EoK`f7|FuDJ(;oAp2zpjOpVwa!^g8ZCJCP|JIeocy<5qm_-)_hE{^J&`-%$4Q zE2lmZlrQ+^>}{*yQ38aD8(aZZ86!%fF4IqPHw}Yywm%*;&bYkxNbO_PmC=q+R4XL_ zwpVioyqtLfkqbFdHVtB6cyUeI!MfM^jOpR|e5%2zEGyS<#RE^zEupVS%T{l~^D|e9 z;S#o;x3qf?dyov#PJ9Q09TO5>_RTQn8obeF&2otc6mH$pdx@ zzP8eQU$MiYNF=>X~L11On ztNR+{g#1b|k=%OKY@p}>BA<#^1CBC`<7~7fzZ=3)aM7JlRban-7BSE4OO{O&3 zr|)LzOfHEs%ru$>=<*O0O7(gjf4t{;T=~`OG2^wi?an#==tFV+53j)ar;Z9F>Hf6n zo@k9BbV1xh&&3H=!f?-xOEY%#jhH`ndk#>?OJbX~72;@T z7!-J))p~m@wcnPu+{jd+Cyi9qLIe@|ten5_`l|(gx%}+)us}Lj6G&d5#YhjyNh-wm zJi7qP*K8^!@xG_$!Yj&Haq}s1#nprM>50P+DL>^403LpBE_Us%YrY6%@5A?aL?+!= zbDwM=tLKNj8qfAfPU$r#9<&JoO9j-cTPM8#t;aT0-oO3xBy8Hc(6Cc0)jLKKp0>E!?e;Ql1?=sOJCW*Zh3nXjtJ^?Cn;J9fL7?`#jy0lg( zPg+rnwo?e7WI=*J5ve0Eq&IPKyV|6*WwR8E#Q2a=vYO_Bn%0s4!$i9hNGOaQmA`QL zI(+imH{e%ooNMpdqZ>YZ#oO`yYc56q@S>xH2NZEZ^=^&zo44U>|NbX@=ihI}I_0%% ze#lk-(4wJJjL2AW`1$OaB@nV0u0^e6B0Fh+I|j;KUtkICcztUaA>W2+;IQ&YVVIE@XUtO50hS=hbLcJ zkb-CtQdUMfetIR_ik_rNv~^G3ln_kjY@9qYIzkxJ1XxI31|t!HtpzF|nQkswAf%O# zGjb&QJIGS$RF>7FqCa@8MQUHX_qg#5dhKJ6J`~se;0jC_e}t+NVT>nh11gyG@G~>; z!E62#PeiXhwcK$!Aztj8|2v9E3r!pNbr7kaQ9FYY*pBU$r7B%&>2<+t|HB*b+PmU2AAK8s__=ps;9lKDiLr+p@P_ZL z+q4~D`?uTilVAK<10K>JmR*@C7*9p&FG*5%!(bsX83yhX_S~f(7==9+WT$EK<77{z zc3u5m=5^=LRVDgSFe?nu1oZi|uj6Dl zHMo(@A-UrDIjLIJ0loSpf=8a_u6Cy8Ma$PH>OrZdPi%&ls$B(W)&<6l+{L6D# z8;(6L8;3O9Sn)|fsq=dRdJ=R;IV^*p1sB;g=rJig$_l z%2tvN>DLXT8+hrDJU5l16q0yb?70XPmzCR7pxY~rfDL)S?evj&_k^*PJOF?hbC%)0r)Md8RDGU|jpV;E zfSM}-K#MX!EJ&wsbn{B&w)}x8)0$h<2Qcxl^Y6kw zeS20KbbtW`_q7DfF1e;c?@A|g_82{Mwx3ZFa<}7+0iFbHa#3;ecpyNPl5wEgBemO{ zx(s6{;aMjKTqA=Hp*+N`*pF#P+g^%5LZbDOezEeAkQc#TTEH{YS7Q3S)yhlvzRvpI zcp-5v{p5oy!#SI`?!*JnF9d~%ZIZmUJ_9w%&VQ#N$F$yLVN^w4L5!-qV@nMmf9G*H z?YPEX#Jn8j(5U(t#-H{R}i^c8H|u{#t)-kfb~PEp7Ko)9RMxhs*+ zH07q5q@pqKG|Db{Inm<@)xZD3F?i2gPiz<-T)%NE{@)Fcb09^98^LV|kp}X7V;^L% zhkkM*54fu|U`hsQ^gx^Qf?SNe>HJKGtzV{8C)JpaB1022Ag>Fuk5W`JJVX&3X>X)# z3tge0mJTBcXNj;t?m(;}PrdGO!`;sXuf1(2Vvad#IIjJ{zu>KBD zHx0oHV+}d9UA9m1i>bA4U|mP!r=H?d`LyU4wi!}n12q#9PxAfq0pEe!=Q15?S+aX+Pfnu}H_Zwo-TE*D76wEaAGyTscz2MfWuzkla{NTF#v0^Q+Oy;OTPI(H?__;Ta001BW zNklm>m`b1`OfMJ1DIuWB8K22xuTzds7IM!+HT|`zmYIc@<I+ExORlzAB+TDt2i?yh7Eh)@{WL zvsXtUk_+QBVl4#wqEim8+-|gGTj8bC^V%uNqgPFHQ9rFK0MRAGUI3XuX1}I^8vW*# zjT(&NI$i4Drz^hxk<&2z!0Ll^fWpZ9^bb#B+1f1(%wiZ(4=SY$1L)A<#ykjVlxWH! z3DuH9VS5^ys-=-{7Wt{~y%b=ua?d7d`F!r(@N77Xnu>ZlcWl9zK71xl9eZfQcDAZrW~Mg(?7@C(nl3mI-&pD;f6dah36`gb{7l2a4-s;wL|>0iFX7ZZ;Uc zf(|mE&CwzZueMGi#GHRp8U0*sM7J07=oz5S>yo(coWmsjoqFBl_jf&utG;?2X3uS# z*M97ghv2#&d<<_t>uBN0(jU7Xr;HwPi^hnP7db`V#_&9^$x0VCLl_KNu}@VPo#lz| ztW$h^p1`v#HV>@!bZX}px|pjfjLybR4?dee<)MpzLx;#`ypS`-`*bzf2i+k*a`PjZQEE-c9lgc!Q&CqAb;E(Od6OXikLQ`gdQ?jtf zIgC4E2)_Q&Gcc%sugbOo!0y&Mes=TIn6s3(meIhKw#5LLx0KoOPK8fe2YbBln z4GmO_a~up0$e?C)sTLuvMYRER=D|0TNOvI8k{1CNjiYllQmf3hCs|i&rX^*LKux|_$w58aYY|n8kK+2A6noG#ck;}G>hhBL(Z}hN+FBT zy8;)K7npGJFw|-pp$Td0_FcID*#&~0JW!GxhWGH&;{zgXdh1QLIFRD4_F{x5Dhe6Y zw>#c9VRXY4?vnOj-|;-A%wDBL10o_}drWqboK|r@K8j4om$pR~Dw|AU&Bm%-zG3Ua6uUIZKB01h;md1qtH(IgEys)}~o@#=CIJMuRH z$AKmfz$Ih20R?8DIOii-(ON?4Nsl^!-`)8%CQhD(Yd(4r4jEeQXvlQT5eMVCAAStK zzUd*{@$ic#Y9*Q#Jr5G6?X-Wvs8&KrLuBKR!i$cb0j56R&I9gKnxRY3Z6Iz;y zkp2TxI~a9i#G^se29x;etgsrp!zriejAFOQH$iwtOoVdc@KxFzIq1?wF+v!PAmw#> zVbBNm>5Ah1b`# z>Ts@>C?}RzEps&Rd4U+XUmW1Q84vKVMzm}`mB)pa+v7$K!H3>?68h~`{pLB@zFY2{ zgqt6n+Av@ECJEto+A&22(~-2h_;it#!IGR;P1@@<@0yueSMp%Mmk0A-iMI#h6p>Ko z3F^pjp(-V-=q;_GF2!Clbg<)^%SgQPtTAz!+h$DbT!CT<7K&VR7O%m_zWy7$?`#pwk9JD!EK4sGww=E18oqhCjQFL!v#?;YNjP+C!NW#tlPDg_jNh+qUmUtp?QV8I;dlD(aG9 zx(Wd#dXhB>g3)ByGsuYR2xW~P)*qK&a5M(=tv(@6rtLd+;b%8LgO^@grTaI~>?~h_ z*vEQZcrYEL6s3SQkx21aq@Q@`5a9UdH|%#yP&Igk52gD+m6S$ zV-IeseE_gy=PvyGkAKAzQx;_Jr(SxXSM+hbFBu_}F!4dQ$BS_qqZg2$rp=0$#=s+r2M!c6^K55<)L-}b&7UUXsTXGBb05732Om_uh*zeg4?h^!{qRcs=B9^m+k=y#qCNoN zNcYsWyoqt7bg$|gJ??oX%EixQVQ=h?3>r1G*`6y1<>wlnrLqT8I~esMDX}*8neIzg zXW8YnaPq@O*(;?k3Rih$2hl*U=p<2wsv}3ERA5x9r!csSh>%kMK3y>O@Mqz&1Ut~+YJAN{T8%vWcuVB99s1vp!a>av1}wiuCHUSru*2o7; zW!}Dm+!cl;4SNUPNWqQb==olv3koj2wr~~x<*UEK2i|cqF1_%SroHxVT|48d4@|(g zu_N%~U*3hKtJdob4shPFE^)%J8;-N6B?chVZu?}>*9Ab7%ADFPw)qOVp~s7C!r}DA zyE?q&XFH`mZq#W2D?>~7P=Gc08<27(u1HT?8t7n4k2mIy!ym#9V8Thm(4nQdHH`iGbjRfv9EEeo9gN2&Ex>crmtpOu9XgW*6ylnu zD@Ur{!d5h^7zk2Pcwa|{S`8#w87yDBg?Z`(j~#%z zRy2uhNEsl|p^Ak2W&gfinXh;lAbb4>q=6_X!_8mx(9xB z`%`%8g;}`fqi@Bq1FH{pl4-9i?@o-rLmd7*ecTalXGY8qw%W0^LZry`vj~jJ%UVNtQ3J>wsz$l(4%NwI? z*eu9)I{z!na7kZSV;Uuh_nG zcPbN}=Ogp;l9ZhJCdOv$4q*f1M@vxKtfXBtTIF}f-XM8p&{seU{6Ti#P_V9S(<)xT5|8-n`?noSYNOLR21zFgCP#^3+s1GKb zawyiU--1`?tit43%Q1byTC~<}{xr;#Hd!m(o?ScP@S**1)bM>Ua@auh?$LHbPHF9i zt+@VWUT-8D4=Y1|-y5#1ewo`^Qe-9{Izi|JzE|CZO|>BSwAJ? zu>u)2Z&WI%4;D*3t#m4bh-lygJ*};ETz}h>#a#QpycGxS-@M*Ba^z5a^^@n%3J8i_BG@(?fLM#_*QagDH2o} zb!44Gn9v@k_nsX{srU&5cw4rWkm4SPT5}7V+DhJ(XCTbUo)v+pY9kx<{*q8a}c)g*oCzlwqfIz?O4BQJ2q_Ij&&Qi zW8J20czwe*tl6*~yINb(xkC$jbnS%hT|1(Cmk#LJtuuxU=!qc%dSOt%Ug*=S>l>oQ zrsrQ-gkRtN61HsHnZ3^gnvA&v#kgsD#71P&XX6FV*C2K6+!5Wo5Wl4{)(Bpqhj2Na zhc#t@C9lN+y?b;C|2m^r_b%wwvkQ85>w?}ryWqfm`~6KuT&6h-SK>ea_yiWO+z?1r zRz}dP+uLvfPz34nHzhJo5XLF(2=9R|om$YLr2uGgO^fi780QaQEfy%PESnwbDw)WQd;nk+~z874xm z1$@o|j2R17;3HqU4j+2wDY#_9Dd^Co*Iv91x~PDssl1v~PZvD%x3V=TT82XfW!NY( zAhRIVGA6Q=^ijGdrM*)7ER?e_iB?ieFI-8wXKzT^Ssw*JVt@pUdi#TgoX4tO-K+X0 zl2@|QJ?6__SM$SCDLAK_9=w@2f9!#$UtNxA^Vi^?&l!m^Bb(nJnoC_ecf{ZU9WfYx zA4Bm*)1u|;aL1#s;)R(j5=BKx?@l21J3?_J(Ja>=Wl4;n=5VG zz7uynIu*A){7P6z$!fU_+ES`qEas}86{VP5q*3|0bHEjsjKf>TjcUGO73q|*hvAg5 zhc%u5;*bAlIKTRgbYDUEpqP9_5CkW7b zSk?zQE@ge1?$&x8*WU6to}4rjpS$91&3Wxs-vV$oT7}Q;CC|tEx~N+dD`hq@=%Nle zrA9VJJAV-tfx#(92i~lyeYdp5u%Eb|3+1V&^+7U(=+t(QQhr;@@0Dz(`7{j_LMLOP z_aZ|VA_WVyiqnSENHB>c!5cx##;v>X^E+O`h{+3a!MKAlVrb)|Ro{$h`Ra|h^Rel8 z`qia+Oypp*Gai$pKLxXReTCFYTFH1*UdfODk!joZop|Kw8Myt?SHvrSJ_@`Ctp3o(PT#Gj8ZE@j?h+HJ*Lddk{0YpDI#p|q`v}0=D!)KH?7P`orZ1K7= zq#?-_?%@LRO5Ul0c|~L>MXjLBBLiE1vTsx%S7oze0RmKzx8iv&pOm5sj|t(Lv1lEp zFMJ-u2KUAV;||7A!}rmH`c0ZvuiK2f|2hLtytEi~;*A$FK#D?eEx+en{8T@*OwpC3 z7b7bFpPROA--(ANPRAXOPQ%8n!I&FQ%5W^JjMC7hc{p(_bAVc$+!o73^00H@G1M-} zAx7d{#)xJ?XOr~Cu`L&~Xv3Z(hkc)t=%8G$llM$`y#s*a%nc^WwlkT^OoT+)>jVf! zXN%e!_MGo(t>YIr{S{A6nu%+!cpDDfZ(u2_oT~+cZS?^e?4pf@I`_ip$3G?Iigg0? zESP0QQL1(EYq4V9C%{1!_$D#tl-gmToHoezXjOSFu4b1ChNYe7TcZ7zVVO*Q9w;W> z>7laz&>btwPh`i0C1;!K|NDvj)Dh%k5A2K>jZlQE=UcT5;}Fvg4=f|e$? z!0oBz0nA(cIwrof0FS-65Us5~UI(BRW#pLwOc9J3&}5jYu1IB6Rl zX%_ByWEwVY4Qmt(7UGLSPBS5P8f)^N3cFG{YCHtKM`g>ElYHm6PJp(36U!eZ6@?RX z=@K+HD@DaLA)P`n+J7jN@=-M=jYu#d4oplO7^4_Q#yBv6qKurufZ)i) zL=uTf5sVJVjRT_)Vq)k(9rsFNNT|dF;tg0(A=m-}ZRrOTxGl7|xA)%mw;i0l)_R_2 zt$p6#E$w}OP0w!s_kG`U_Q%?5ul1~tz0dhIskE$<-^*)X*WCf2N(O4Ng#h8W07}_J zTwlWF(=Webzx01UXg~LhziGepzK_}i$Z$l?X6BJ-rplKiYQ16VQ>@@2fNY{cnB<^? zZjE%XbRRPu+Pf}GMyUteKz}p~m(?C$7N#9~3{Jc_K8Q2u=oB2%Ehfki)_Hj*urYos zO2swf?Jk3xH{NrBPNMY(EMNQV=j_M+^Uv7Nz312LpM2kU+F$r4*hZY`OddaTuE+MJ zldOjeOZXH#3wnGTVsaDR9Aeguz#5u`EdFhW>WwdVIQ`z7LOpJvy)ul*x20%TU2uIK zbix}1ikF78%=Fg#H)<`RR!?5%g>wrDafRG~S-GY!JmCtTeEBtd_b-0Xe)>Hhuy6R9 zH`(9#%YV-P>R}UV?2kh5B^znSfB$Qkd^3u4YnV>*%oo`F5 z_QM@NTA$IUG{igl=uYSm0d+l=#(CFh((}q0@ zuEc*M`}LTzF=d^j3v_s$=}rYk`lW+=6$bp>ez9hM9wkW-8Ja=XVmUSlBW?5Lk+xd` zb~w4YeFgI|W_Lv5jw67#7^R2v+w{24D;U(9YrS!O9dnQ0zw#R&w(tFcAGh!O2Y<`H z>+gOWXBoq%=(2V>^@#*+C@Z*~5f|u)-{@u~Z$^R4VR?4zQ5lmrrrak|2aha(d;kyy zj~ft%h@*zL7JEm2P$UnGbPF#oR|&U)UJ$Z%(IV|m(PqRTpjDF%yL-ePLa3u5o@o0v zGpPB;FTZ9#{Xaio?|#n*?W?}>nSIMQzSX|v&;Kd==C{4ozUggmwYUA*um2Mn`cHlO z75m^vKVk3x$j9wBKlGx#?}IO9x;F^PNIbSB41BiD1oF*WcopPfnE4-iK%+H>FSv!q zlL(oCtULuH^0@NqYoE0b{qD!@{U82A`>o&k1AE_Zf6PAkdw*;XXayt$uID}M;E|_( z&BzgbeFwf+F>uc_UlwF>&z-P*`U4?Sfb^cemeUr07hWUhX}+!Vy3_Ab>C7bVd9hs| z#2m!aGS(mr?4tdnMVDR&Pls09G83s;g2Ei0n>*mIefGhA^gq7ae)bpMYv2D5{~p{+ z**dZldKO^~GLov@W0y5G@2#h77fh)$`*nsqJerDWxdu<+dG)&(_44Yz6=l_3H#7%F znGgKphPWPrJA3#3wl7w z=A8D*XCLgnA9&H;`+*mO#;^X$udr`^+c(%-zwWE-Yv24P``S0Z$=>qjH`!ah=Bw;2 zU;UN#6<_hpUjEEy?WNDWYA?O~s(tF^SM8;jU$alX^s2r1$@_A z^^P-b94vvvIj8-``+v{g^5)&U7(Nf6Y@77^`Uj754}03|=Z~1R{)*CvfA16aKi>1c zEg8T22giE>Qob{Lc%07OkY5b-rrx5bD;d}fSY`kmhccld1FP(pLJM$q=y0=vV-AfD zk@2<0M^T6U@~?l`zW1O0xc!~xamL<#TG!@WuWhZ_g>xB(gN5Z5J2FWnA2Q_LEc$v1 z2Horq{_*$y$WQ+jGy6Y17&^$95facMq@m9@aHVs=`+@AGma)uetngG-AU4KGe;4qd zI1x;z_a0wrJ7pS8pz)mnv#K^_04VTeb` zY=pO7p8te&<;3f)@TRb?it*oxz|lsMt`ugQN<1D4uSzU?eZ zTmoGV(q|E`Tyt6UnQdgoTn$ygvp%3Rk@dtsv5SuF)Pu#o5~(kpgOe{Ro56sp;%@Ns z1=Rkf`pKd@H}K?*D))H~Du8h4#Z{I8dB8ez34<#Qdwl5irbo!0xO!joTqP*=w0Wf0 zI?_R@CcN94y+Uh(fXQ~guz(FiW*B_CLHPx(oF@+tGDiSNpaaRwsuQYa$_@=cOZS96 zo6z3b5La>gVz{#dKtfIlG>qz?z-+722!aeK;Vl;%gIc5fwB!TGoiph#j{`Z_tcr6p z7B>;YgHay`o znYI!E64>p83c;oWtLTTV^(5M$9vG4KR4(u+dhCpdMn@Bau~*1cQEvQ89+Fge5(c>f}(zZpXIw`nqba>hklj>qqiY- zeHA2l)5if3S92ZKoXw~$j#IW0mQyG$sl~Rymv5xbX}$E)*|W^G%&03rb5Srt_x{U> z(a=Ju&?wPq>NQYNCYnJS(ScrX@lqo`U(_;*q8ApbgB~j(*MlLr`8FkI%tC5%hHq1Xp z9@c_h1v~6!(liLf(fCb>8nBLBN*|@tv7-S9HN*9qJi~PMsxF4pN>0Xzdo;Go&&0^F z5y)xH8sJv|{`Ip9649v_g7f>F%E|;Os%t3<18A6iQ*M}SDG{$UAgP_5F`dyYTTEG> zBtI~uDZX!frpxqvd6}2WH_}iAG*a=w-{boXc@SDBFK8>rsLzBB8UO$w07*naR4*wG zfcbtM3x}pIzX6)C30Vi+H#E4_W03L-4 zRR}`>?kt$@%IwPGa*_2IjM64&M>%JqOO$*1wUUDCivmDKNv?d-0Gu2Ln{FT7qln}S zP_JWlVb;#c-&s~~1Zcz2Latp~ijwN#8vSI)vpnmdkKZg_YPvrANS^LbF!LyBl%W!I z%7)$Nhw(^%$SKAeV?zt`((P6BJdEXH@oOiA6(begw=J`-JN*dEP%r;iW^t5f%Nde6 zPh2#i=ghceU1KAG4hM9n23DPn7L#NyHM@e6GNLJ```HO0k&XwGW)D&zF>AO>$%t_~i7t&y5e-g~a=Mg#!b8`EpLbqrp~1(qL2f z#IvLTV-#L3i4ST8Gq#@9NwmufjX{;>kvogY`~m&hHSVj%NZqN@oIur@Z5UnX#OuAGn2kkwF2@ z)op9G2+SEsx`^}4!}siquW@$WvU;Jr8AOcT`!U>`B}8Q*}%?f}|smb+WS z$`_n>nW#sx;1J*;*R=VtKZ-^wY|25LX6>?pWdn~Akw1;R$A0{Pwq#9CWO%rI-Y^cQ z29^yPs%JZFz=9aU!T0ej5d}Ta7i~4+q+IeOV8H$J(2t^$x*in;IvL76^=E*47Lb|- z8MF(HxUR$Sd8bb1@N>iD`;TZxHU4xq9eX?;YWx#T4m1(57omgZ)gOoMJ1q24E zjl~>v1Jl6$X#7}h**KJ zUkB*(*@)?QR-`|OR=aRV-fgRnv)wbcGlMRK!iU>J*gJAOcoDgF;_KdN5qHe#o-|bO@~J9MfbWA+SD0MO!7D@vmg+#Hbf{Et9wELcUBQY@miaB1o;uI12Vcuv2lnJ#R}Wz?EYu*#REDe0XofT# z1ep+t&jz0(gYiV7bhCS%ekTC!?n{YvtBi{%1yVtJ5U)gqyHtq?<=p*3nFzs30SOq~ zda$YO90>Gp%R{;g@YIkJrc*oX9`V>k7C|buYq3L=O24DRmbNBJYyr6Lh0p0u*&y-Z zZ3LOC8__O8ZfMp^nz2YP-vE%Rv*>X(fv+JK`Y5FZAJd5g*@3J^cSc7`^$D8Q!*o2(2OTPmy3?D; z+K<6BYR~eWHGLdwF~sHg=Hb#il>5DWCce&cSq(Ewa_uHgug^&ex{XIPQWM}{o4tfe zyCRu5e$c)m`3)2P-6BNF3^?hW`IM`y(u+TW|9zVfy6IYRi(1C+r-V$I# z+URGlF@oN-`us1|1&L@KLK%CTf-kg@qQv?ZJs9w1W}H?7VJpquPGOY(_+DL?j{V9X1@lJP=bfN5rC~Sll3bvBYT8vaDq|XUqgqF-8k<( zkB>VT159Ebla$g6t2Pij-RXI#hJ9pqgfc|R@2p-O8nn%h{lz6tKBqbj;<09DYjI}> z&X#x}6QmqWa~klesb*1pu&qAbtK8wB9D?5}#g3_QummqLz!UzbZTp#=r#kv6k8l=^BI*7ps71UT!zXvsX`RBQ!THWEvLJW9P-vPd z2Px8{kgmqO1tH|6cRq5mYRKvAgwr;pA9S*sF;%w$OhK?`S&zkMh=%cyXjI{;MO`#2 zg&u6$I)`pdfS*(9&zwRgAo3obRNt)wQbz`U^0r>=<)+ZJbK^Z<#48DAxKW`o_yd`p zD#P$bN^vm#@vzCWE5&g)qTFWNg>XGVfXFXdNN^AXzYX5|jyUU3x53P_cRhgBrlD!t z)AbtHY}R_s=ufTO@inn-1X9pEGR6oQBlAeHpBM}>db_AZ)5XOwiZTY6rhALZ+&Ic` zjih|h|6plEHuSAIls%#@-4hW7c+E~@2qk;JZlKVZkzoU{!~L$9cf;ENnG?g|G}Zl2 zOUKC#(V}~5U$PCs?C`ZOLx*fIPisY57jWtV8)Hp@Ca4}pf6<}ipfNv_Wpo|GSjt*k z+))QE`RG7AeC#v%cf%rtxSrO%*JB(`v(Ln1Gm!&$&F(O37s_v9${WFaIos$sC7-bY z>v0eFGmX2B4|17nVZ=Y)a+|4h;$UhVQ6km>ydB&x{+Up81;U9AXCMz`=6K+M;@Sf( z@feRJ)-J+{?Ml^81HE~8TA1l7h_(|t_XuPUhZT1UjjjSy6ExT_f8-{0qKyB&xeLO z90f{^yVSLcmfds_XGG9T;Y+&Q8#lC1yDjA55qHKIFd(5A>&`H&xbKC%r^36zfx8r? z<6#%+1A%BHPZ(N}dZ#f@^wYDw;7mRCa1AbB7_bg``LgXgan&YXIFy498wG}7Km>}<;kYRu0BlSkGDe4WT_r|}J9Z2cQgJJab zBVk>%VZEcWgZa@i!L>|_W>mkkK>D?vk|Xe!IudP_J=NBjcjE|nyCQ=ZyageN)T0;V zX(Q+qQ3~@DI0F8S6*BuA06IiO7(U_rCe`h%bO5AOrR5wMkPGVOWyYT(nixr(IzNMB z@d3>f$*To}5#(wT$NJ^|WPGH{DUs=B*NIe2aseIpZ zzddy*J&0_KbqzE59!BF4!5T!eGZ${4P#McyWCp;%SyPYZ<^Nn@6|5{g$unaf3bdPl z7_ADhd{Bp#s89Dhh!0@I>U(E%ic^LG(Ad`FIm)`vbeJ;w)b+`Emnc2Hq>>*#+J=v` zR?gOktm+X4RBu6zuxMJa4FE*T`Tn1GR`U>=+SP29MW!P`9Oux=+uuj0*P__f{17^s0fyP7}s|Fi*n#fZQHvW_?G3T#RE zR^mXxfi+_+>uAX__4ZRKZ+xWQd6y6VCrss@g6Jc?A+FWNbQVJ8M$nZWy=rNZ0^Zz= z7Adgof1JEM%M~5!oYs%@Co41WQ+G3yQpoF74z`U!zF8Xm9KV3F zZ1EIYU~Sy73Pa&~CrrjmlI6n5T(wvq{(xzy2^cmmQ z$KZ8RBV0OxG&s!&5O5x#;&Y;mO7Pwv^@F+J0H3nv5$(sYYf8tQ;+@*D9Rg|$Y)EDd zp!<}R#-V|A3-&IVRsaU$ftizua~dG$)@(PBlfT>kTc^vrfdfGA)zR>l@n{j=p9XtnqCWi#AU4 z1bmA#LcTtw{^YOTHnJ-@r>AGmk8+1Sb^a5lUDT&(uEhHp9`t~^Dj&WUX}XU8sRLaP zYi0e~BmA0rZ2{>B9Joo57EBX|lOoPbm)Z^i?evGn!UJ*wQ;UHFawOZZUSc3<*d`Jz z)VT48G0?!egW})3Pnb(Y|J^(XvEBK2*dE|L9XwJ8hLD*8)||7-EWAQ^K7fIrg-|q} zyZvp!T%`6S4XES*4V}0pdOX&;bU}T?l2I6c2Heg@wphZ^8jhjyfgA=E#tZlwi-P6l? zdnhSHBW>XTP9=|n`12Cj*ex&$2OO3i=vY`fjoD$?)*a40MyKYIzX9{hO2=Dh>mGFpbcVqmpW4WZEjc+)ORAf?ZD|S9&7_1 zFyAtUIy?;$Mg-Xqh+u|_-qFGbOGL?(=Zm&;zAzsV_!P`=Oj^aMyv0a%L^}ea4Zk8< z9nYXo1y{60BLYKT2H<9|%puArYYz9%&Q&CY?;XJ+F|iKII7awviC~!mh*z&Kacj2s?_KWnMmgViR8X3r3a$X~ z(gW?rYr7CbJ$eiz*3bc>e_X-)D|^gN6arR61}eN329)>FbgC(YsQQyD0Ua2MS&R z<|VQbZ157G5={B9(j%3A8^WeR(}*T`0Y)l_LZ|CSc&rg7IbuV_-Y=xFji}J_mh#yR z2>TUmzH_ewvu|uj@LP&7&p+YYz>p;mC{qMHEfFcMqt9J<7?JD*J`QxoyvfN6Qr!5G zJ(~30^@KE}IFE=$GvpD7%>)@4Pj+%qXZgIwxl`Cf2O4gWDYNoxS zyI7|ILQL*P+I zcQK&yT~h9DEpdH|Hy%2Law6vkV(gVtMIb1&B?Auj%5~b}pz7FTRv5~UNdR^;^(_$) zLM#jnzearK)(gtW!H4;8FCz!QJQD2n=pF5SSGn04xrq4HYd7kN3BWY&-ZEaG&Upaha#2L}9@@M}X($ z`-{g<2VX-|#6k}_&l-HS91A{H{W=wmg5uu^XYj=nTjqPdnV*oF(d5Iv7`A}3S zyy(VhA1|Bp0NG(SAC9%1Q~5RMe{9`xoQ)yZF|~y_k~MYOImaBWQ+8o+t@d03{@l^o z823n_7n<@kdTHj<@c#{#Dc317B-V2govzl0)2W)tvUsEl4rAlw;CPuy6JA+)Z zZnjnqEx08FCl6(fcKS23FMqTdN2)>7X8R)`i)HbtMd)7c^qe}UWySniUIZr60z_w} zCH^(8(m6yI>;LBZ9;q#|hcgyC$4g)wtamU50JwkvrnB@APN^?x+%V)m1&C7AE3Q#N zSV*SBoK0y29(AzFoiR;So<;qW>$``Ybuc}jHf!fH{E|U;O&U?(fPCTjzYmCz1Y4LJqVuB+^Ybr);wYZs4TSJD!Js&dDXM_0B z`fU^F5Ch_4m1c8VMAk?~;HEehMLzLOdT#uTt|HCMEOF5kfncM`n9fN86|vA*U@KalnvFg7xXcgXl9 z?8jqPF;SS?gzx4+UtGqNpJ)zxx>NRo8(fd&qwgZ;Lye+0LbA~JTsM4dZsJyBYx5fU z^T@WN1?usM_YV$)IaX^E!l~fFQ6&6AYO+kJbPJNQb42f4 z?)nE^Qivq7MFY(meBdq_8|ZhICGi{ZzigLy2@6k#M;8ng2tjP4r2yz?a89gslJ^H*>kI}NS_BXHs=%_-4T>@+Oh*-V@p!9bti_sH zflv^ZUSEV_DIb9E{!W4Hlnv(Tv+3B595gqWl}F{|zl0#p2X|_2WnM6%%I@$nJ%bDp z%9S{5alMvpV1skl3SeBFmW(Xnh;Zl_zh9lYMq|D+?8OqW!jhx2 zu}?cAiogA^-Yj&a znB~w^-T*~||Dq8iPkIKw>QEf@kQk~{QXI#T25A}@c8rGGvkD>yA({~t*EQqARBJpW z82E<2wS==74#zPkG~VPdqaI>LV9}VM$cE;aCT>-2KoO0!_cQ3j7&n&TaPNGSW)?;O z`&5R^$!jd@#5QS!lc`QYk5TB{6^qK_bn=15ZC5A0X6j#V<(Q=VONNP`S$!c1;}sB- zd+t{5>C+UMr9c$%aTz3A2DtGyVE^N{5 z#LLa!ybP22KxhxSU5nytgHb6v6bMjU7;~r5A|w3`Z2H0vGn)_aH_4F=-npi605r~u z@7v+Y_EWEwgSz{chEYC8KYl8lUr`{$H~;VK!oXNz60S+7NaHC=^T7GusUr{JFbgj zhAmq$gYUdmmGsUv_QZQ-8jb^KL~~4pKcXX+*J;crCt^%=l6@?4WRy))K5?KWH!x>9 zPcV$wm0MfRlF1cd{y;&_&+uz|k3-XOgvGI(3a7gSk*Mbv)jL@2lO}h?<^7BW?p6#AAky;XmlBr^3=*5{+_xQR6GYU2Z9NAFcOEuW(LABxN};hBH#*^u4Gj(GKf$^FM>`= z1~mZK2e;ya(WD6e4!q8cMXS8fu0(v^2tXY@b?&YaY5)_D?nu$dxL2ns6wIUB#z3d1 z4HFc;qTQ9r#T{SIypG6`KTTu`>%_K)zrQ|&a1!(T$D527XsVfZ8BIWXT!A^AfDW$9 zZm)eR|J}HXQ4aT`L`fZ8-Q#dsG%I5~l(_TkU?7?4Jml~2X>S3suLaJ(k#p~>INZS> zjV^KQq#5OcBi8&Zs#4b0$HT|i0Oy3p+%hnMM1M9t=htSCEc@9NnpZRr&jB3A)VUxC z^b>JC>4C}IC``KB8{vynvD?}R_MtEil7**M?y#p0(k=iWY#+|*3D>h3@zaF>6fq<8 z9l!t`Fb-##a1XYNGQeOViXdQi%IQjp(W`o$VQ7SWqBX(e=t}mkN`&RJZag2HJbXv^ zCGg&+GII`R;KkK}UW`1b2LmUk%7j_+yJjxZkS7^<$Y)T!^!Y@{WZqsk<^X+Xf9H`p z^MyvrHCXdb(A^n)iO|v61X{Mw^rF-3e(n%3GnZ9&{QLo^DGMUTFYFM{61SxI?1Wck z2g2tb5nd3w_yY!wS%XH-yWblImLBW_>xhvE(N!m7)o$c~vyWiVVXWvDogRsz`(S#9 zAwWMY2R&}t$&wmkBoKOCq^?h2AMhRkBMR>#pkN&E`Z+;Frn54_K46wN=vqq5=Sn~} zXc&Q)h}@f>XfoW05r7f}`?x1^o(sHMoK{N(e@z1NPDV zo*F?JFP=T7Xz^TVJCG=c#ANE2f}(AZ&H!-7X)ree9l-7Y0f0N!Vop$uh)kyQ!$Fq~ zMwCRiJyRrt*&9??Uy#FL$XB62k$!-THj%1E!(Eh!dv?Hm`qaJ4IHUt~ICGeO0cyw^ z^e-9mdT{Asas`n~*Jb95IyL#747b1#{)<`y$4&M5aM9zF$Nqm} z-t&6m*rXAbIa;S%po54*;et*(vVy&%R+u#gvGS>x`@K=lHu5?|Uw3w-2x{M;vqN2f z9LePJ?Vo?NG;|OphC!4_eK&AF80L-)Zc7M_E*7v2 zP_{@;$~Fbx0hQJrAcupiy0esZ*{Ev4tr5Dfk?4}^m?QnwEZ~(l^R;QmM0&tjNnPC2 zRd0a}mhy~*&yH7(g3!YnrE5u(jR8X5bzs+X_(}#vL7WIDI|( zcK|G5O&eQ9)aeRxS?+V&Q~0pj@_7rL7~-ZVxnumq=vmeZ4LCJ#WVDpTLC;+J8J$V} zHGqgiVo=nLbJJtHU%A6yX*)g+AdUYla56APtKOhyO=tdZ&_Bj2208?pOuG!e?@Hc8 z4Ojvsa{#=_pO%KuzvKTHu&crxxH1rfSkX}`(MW=m(Cwvnhk>|@ok2S0KnhGs;|3tF zk;@PUVZ@vPTA|MgpEyJxjq{#)CA*a2d>KS-wH+#(XqXaAin9R(gt63nI1YfZUyG<2 zK_+x5`zw-q6MU3c$6Ca*>##O$TWZew=Z0p-cgE|nW&%2cs)UVzH>geCPdEnEomE#H zOtXatcMa|?3BlcU(BRJCFhGFd?he6&%iyj-f;+)of;+)&a0~G9o_}%rs;_%>?cJ+a z)w63fG=yvv_!s52HXaTV3Xc|TB!Zo)vZd@K?7}px*Wi&$5B$+}5IJmMDL+jjP#jnk zG%#}xhmm7@H;~oUCcO=?O$~ci4|)NSv_jY{I?cVGShqmP;Dvb~n$+Vfjn5w5MH9rK z!Sg;16dC$BOBlmMr)UND0%}1&(r;Yz(@+T6&2$xFfgLQ|O|~>R|8jha_^tk;k;ZTu zjm1l_eD*0H*X{2VO>ntK2p8^8NR65fZ<*SM+r9`ou%+ z(pNN3tie33;UQyA)G@cKd0tsnl%hjqDD#`mIo)>skT*udgG*`s#1=QXAxckB(#%-g zVeS=fB~eW5$B|U_hx`Mg$wAYI>N&`*@#U3MlyE!O6)c;bj;fW7$hhFLVzWk!k0t_= z(Xz;im5+(mVJ4}-(4=Q2{gLWjhLB}9!CAq3Q9~RhN`zDR&_;ld zMGgPp9s5_^%lSX7ofO1K&foG9=_$g_MYoyOPrn^`{NdKT`G!Nx|3OJ@10H_At~vZ9 zu-wh#qoYbioTc6L?=5%$6Y^o7R5IwEj?s00w@|Gjc(_li}>^JQQ1l6h9E= zgf=CcutnRZN2vc7URAGbe`g&zW6PG!iQT}W`n^qS_G>~V&SIaow3u~I1x)qxcY;C4 zn{scYT#yTC0i%=Rq^x+xjFk&kZ!1xNgAa{ZY#e4qXxzLrKcf53!JUo0`@DFv=7pk5 zJfsAqLYt460++z2pVR>@zdycxBd}1sLDxy+Cgoy>YY3T>Hep)72i>0JHeKp@YycTkFvzsOgBQcH7B*TS7{&B88&%gi(q$ z0^LqmE(jmWXmdb72!buR1%TE!;pk)1R33DTTvHXpd67l7&XcU+#bNxPUII~Lg7Yoh zX(UPt1hZ)Hq9y(*vCAIRJsX_Gdxyr>#1<71DVEyL3hr}n{q;&iag>uUC6lWP7ONRNO|uj`nd#mzTQJ@^UJU%Z)S3EFS##!@SjL95GH%IgO+;F0b9 z?#0_CXv71~6Sh4k+dqpLpF71S_#GGi$T=J(jt%iUda!s1F*P43qQU^Dk5VvGerY+I zp1i78YYe%z^>|}0Ro*mKs1gUR6_u$yatxR&9x?w}ng0I#rmX(uUN!>qs%ah3d>HR?6*!7l6OZaN|0gS~(klOR%vOQ^5q&0YbQt}L_9^lfZUxz{ zayxKDUL@v6;Lv_V3J_pj^7i9i;w*Fgkr*x~z<2PB)+d3trAld5`T8q-ZKHYT_X{Pa zVam6dp(;>WNti#Un&kZrvoa^c?To_M>o4xX38Zs!+O%$Fw|bJPU<4 zVVlSsRj z2B<(CiuDR7tgDcmai%=Nocmrl**#+D6blAGWz^xvbuh4gy!gg+%!C$WpRiLAkxd6z zlh>iRM|c7-VpzEgMsro?cNP#d3pu-Y+mhh`mMT;71OCcMNLNyI`7Mt)Bd;L)dZH%= zu0n9{-kQR#lR6U=9y6$sx!F0{k9+couBSbJU6IMEL@39QzzUO0c?u+MCe4d2(`{82 zzg`wv$GQadu(rhx)=thLDS9m_gA_PQz`T?c^#`$JtxA+d-*1Bjx1x72_S0&DVk%cL zH5O5zP0El}%p`QuD0wg(>TmAiBwKw+xL01+M?VG_j-k{p8h~({@6|2ugJiN$2g8D> zdIz&2`KV^(j1}tSAY7ckGUfp?b!%-BaP7G#SqV@Yk{y59b!_fPw6$5jd4r3@`-Mi%+w*`?&Mh#Rpd+|BI+>mlchfL}H)Q@)U3c-nVIlU=v5 zDa}B1rN~KnS*zJS*Me=MleD0t&c#UtnNr5 ziuHK)7jw94;~sc*@V>w6ABPX-4psCw91CARTs++AjGxM^`;_->`DQ~Q5;VCJ(lUL5 zq|oWeit=KgL;DIS$EXd8>YAvnW7@eY*_LMR{d;S{HFXc_kZtF;e{?-uIkITZa^}`j zT!d)$6+XTESP1hrRRd+xS%hMC09L=~Li{gQEgJP*L)^eMEU6|z=e%v3`s{5=2b*5t z17vHUYu)r6KD3tlcNGS7_GnsAI?RQ6oDq_~!QK_fnWo4c>FElbU^f5?10phF+=+XN zK3CzW@q}QpBp(Sk`K*!@Cxv|5BhiRzi<~`r?!lT?EGCD9_y>YtF^s1Ztmboeo!t!Q z=-Pz{9rfiL8w|l(mS={g2``9xV`0~g%@~}6FsSBghO31&NUM#El=(uleYHav{k0v3 z76Fm(-i%vq^)k%Jg+ErlwQn380s=OQD_)Lc@wuISV;i9+|Ed!QJJ z4mo=Kh9>xh+>rr4))mtJaY-&3VpjwVO?Eii&olh8hv#9XwAeT0rqTYy4POAgw8-i1 zy8?`P4D!crR4OJb-kY){{re%;+WRcgo)icMH9?+4cqtCm^%AR=f$af?8cs&V8kwl3 z+K_kM?xj_BsJAOgnotuyTphj_WWUf;(Zy?c6I4r>+x{SMEE|eBlh0m8G9DWeozX13 zHJXhYz{g2@IJ|>oA=zlb81HP>5H%Sa>p$N^nb#k&?q@m3>W_=m=M(jq4vlHUD%{-a_7`I_)&{-=?CJQTt%PVAL|+F! zADY1MA~q$n*ZhoR9o{f#wr(FtI)NXLGu?rF%7eao!D>L%3#pJT5XC=usCoK?P`GjI zF}vJ!_N!KJBdGxr2qJBlG6vTklm5w0@w*~HLf;2Oj3YRh5MK^MU!n=TW}~bxt|p}J zZwK&^X{^FEp16L17&9cQKYc5M&F19H|7AP4d2yup7G`l|TVxmBh_spp16fKXm^V8! zpa@EYA(nh}+$Hm?ag$@zChsh4I6n$)T8r#sh(RDTd3u?&FuLupd#$0w54qu!E~JMj z-?(CioXpbIX9x639TdWI=X}H(%DL&x$|YSQirhC6cB_R|rnO=&HSPDlf^@2f6Y1% z96MFv+{d^H_&xhxHa|7I zl9dsGrPd}5Q{M?1MalY7Y@9(^p zP4ZG8W+(_>T=5j5Q|acC7&0}Q#(~64IWc@OL=`P^HW4(m{=t-OaP4vLAn+;q3i5(- zuGi#*l#BUJ!o;#m-9`IE#OTGc$kVr%)W^8VI6W0nES1}9ZSJlpiC(fPMo9_rd30bC zep@RwawuezZcS5rW9E7uk5j|5EXQ@naoE+%Y+ZBo=5(^dv-CghYc)wlURQKbDS|zx zrsj13z=+uOwZh*TlvcZ8HlvcbG92jUw#GQZN=bPDx)bA&7zl=e>+o z9uAMZAk^*ngy)nLI|~CAe+g zhG9x#LBXu)y27>P9nkT?GaQVup%jGej=;Pt6MatsG-nhx zN6}OeB)c>8BX_MXlAJALxqak=eaAEamVG5=goh-u zJ8q$5CT50wNC0LZlgg=kG9~OjN^@%syA4cUZa3kpvJ#98K}(J zC*{bvC28oYc!ml1$n{Y107j7@2Z37Q!OlN}9EhS&7TTioJKP{ciL zz!@`-V`q8L*d1ysT_!uR4l$b<>@B=9i#cGD1r1~1WzF+4> zmgL;hGqsLlSFcK=$*xBq?FtXlSi@Q}8WAtl_HlkMBfSynZ@3V%r+iPZr{M%N!;yHJ zBMK??VpbU?%|4hNY8pCYrlT9n?HBnJ^DBCom`ppZaUoUF%TBdEzAve!E>frQO7aBC z{}RC7kn5{7zy@qRFt&MK1dpgnCG;JxWMBY*NVDMc1~b8A%pEVE2EY>J-YpQwBkDwn zaa=xEg6Q#!2C!7THIN>0dd)S4(8#NHhP~zNk2lS;wQVOpLrz30@3W0Tq%cdutYI_! zNcf96u|`Pdq1=VOSyA@6KJTPufg^EVjr4jE3A3=)`gk{<}x{Juxm|BRK$+**k2M0csb_cj9`wB z66F_1pL1mAY$hpLTMhbfP6MBDp8#i~l{w9%`X(78QR+bZeN`&5Y)R+zVF7sTqH_Q! z-$;pK@b*TMfxh)E739RfCT~vsQFKFDVZh_upTv%iR0noDUK?>JbEv zTR7`;e=q4R96h`YcVCL<1}}85gdYU-Jrn)#E*<>mcc2-e#t>miC(vl;#3v?0Na14y z9Q_2oi<>IlCahSyy(m{{piFlW<%fn1CEtI^?WG?G@&3Nw2tDNHp0T+T+2Nv4GcX|l zW@q!s`nmzgG+9JTQ9l5A>E5cu*NqnB&JL^aiKmy>HYfdPJo9n6GL?UOXrmFOm)L@( zSTVX{_x<};8+mbJ;J%bls-Y}%?C2?V{&WO@T7M%%-{QOs#;9hIJ3mzo{5Wg?;_<6} z(Ir9$q&Z{DH62@5OwVxAU-r+~*$i zPXQdGhOtjV0noETht)+Bk_lHH!FunAcZneaA3|7v-Q|jHf;Dp;L3}0L##rHhe zlz7?(VDz$FopR22Y{oQ;RT0+*~9gN6I33 zOlhYN=z##G+1Lws_7fv=vQaV%w^e*);A>)LfB7hH6kgUqg3~q)aa;?5Nti{R$rilP zkmt!$^-v4;DNXeS71qhV#cUi>Y_78AO0R-&PDJ^n*I5SPb2&O;g?P zAY(>y3fSE;(FBU^O23wI8oN?8!L27wcCXHODhMEARFpu5d_qm%0yADJ4N|(6_G*BB zDHnVVxj4}tb4ceM$GkKcjHYm*$am(BdJm~B*rUIE`PwNtw zX$c2o7(&nui|oOYC*{8Q#YI12CS`>==f8XDjUb`z@Ju{n&>=x&J6|wI?Bg|&!&V#7 z{V$25^BpHEVJSRA7+8`YuEy-u{!MR0U%aRYLI&D~(Zen!Lls|lSla8_ZPEP?f9m=> zp|QGbOvH215QHNF!*CidQ0xUn;;Vr~z1e~j!Yj?3T#0WY1bN$KgIob8C`U)mpXvWZ zcgSr8jS~;SivSHp6SawSSPI0^L!ck;SHNN z%EG;h;u@p2$vtymx)PJ)z6D}7SYO+*?9ywaN*mj{?xIg9g75DBoBrIjO4*2Xp1bv= zeGhVue!H@=o6K$Icr_!1-~h%u6TPKTwk4@?RGb6Mme5mIR5gTyMT|XdqFoHbJACE~ zzD)5hBNyAD>4sH6s4X(xh_C$ZVTJTTv^-(wKdMiV3UZEC{r&5y(QncL6{Dm|GPs11L=UV%?Tk@(9N-emSojM zCuyXs_@h_jBpf)?m&6RE`-bParG}#FUjr#oXj>#=mgU-@fC+-R*tJNb=(PsStJ|Vt z|34=U!&+h`Gygo6_Bp4IX@4TrRgVgSazFDaJ^FlaXmM||=3;g%O$cV~nI*bys?Gr4 z8UCm1?ccO~X-738=g%Nw4|jz2F%HcFo5mdjLnJq>_O1mMIQV>Ro?Vgu2)m(<1hRjT z5E?xuL+E~8Z#$Og2r3lb5F}f)!;B9RKz~W!)Kz!wA9Z}+CNW32Pri@}h}_kF8jRI1 z(k{7pO8}v7_@(p(Nr{fOos6RNy2X)(7twz)eHGBtnV{G* zWi_ge%9mIEjLG&nfk3eS%Uw#viVK^Y(&lBHUu^n;ljSXaI2XEjy$U<*K`ia?uobgr zZ_bsRmHD(6YZkLNqA}r~sG%W#P~*uTjU|bs zv&pKsVEqwKU8r=*wrCoR{!^rXayF5vZTGjrLg0`n$GFr*Ly?0eoM*22*puFZgjKPS z-paQ^IZT56_-#bf(o|JO~%I0 z%L8101%&OVS^Wk{%L?Wc)>ytbf#n#ZlAEM!$=&6Y1){0eqZxYwU17556^B9BOiEng zzNkNHkZ(PZ5d2r|su%c9+`50M~%lAhi zOQ@_VG#tjTcjZ0Z93hfXynPe5=g{s*y=>N+jDlk&>g(5+yo*9Z4>{Jw9yixtZst6A zMz`cB$8_b<#x|dsjT*Q$am!O^d~e=TWCwjitMj8i7V$c<;@hTM}C0K7}~8F*0KtH8U1@Jwy9zK&xu&a8<6H_ z1YU2gPM+vdCo&kV%~)>kg8p+6`?KC*CE%iSuHSVKk^9EWG;NQ?x=d zvKkSQ;vus|zT)})kevGu^z5FifUh)r%1=U|UK;y@;w;mzFV7>?NvMqoK=G$iyYQUQ zQ>>DfpLBtB-thw>YIkBy)rsO@ID-U>_;iU`#B|_E*QU-m_=ABir}{xWmnOvs$pykU z#eQbL{R-$(h!j}1zpE1WWcci1h(-HI9|B&44O05%oC=}hg;8B`>AsBK`w+OHXzs-*OpT6HIpI^>(@8CeP(+t%$UZnVi#B_nI53$vmtQUDBee$!pJQIhM3lTZU@wDF z4#!kuBvk%}rhQB9nr`v#JoHxYUiI_K90m-LSmT2vv`*j}<|SGlIk=v&z<0F&=`>}^h*-oTR<7&MbBGuSZrAAPO#qjDZTZvt$5z;>GCe-dX*lDpDR#2V+^vta z4975WcS+h6FJB+v>MBq#P`Ql(M}^p_d;%gI;dj6HxSvkAls2F>fGFjgMHo|w;iIYz zIzv!`tUKux99$Ez8iK0eMA9>=mgUH8VLyFLb#>*2%#b}a9k=sbP1v%JiwaG==1x2& zx&L!YB{cGU6?j?QQmOYHA#(e?`66}kwhq9%oEkoh++#rh#1g)QbO;lT+WGQ6f4?FEpWC_BpaK@2TT}Ypj8pPuas( zOxzsOEkA(g&91!)te4EPPDY)lUCM^#winBCgErcccFG%enKc5oUCZ3qM6{m6x-<@z z&Byn-qs7EX@Ljb_aOM{h!b~p~J|2X}o!DrCtb?AVRqmN|h7txZv-aG(@2urWNs8)k z)db^LSO3XBMa*9ex-c?8x@vaGy4|T=Y#mDTWnz}%T)&U~XDkep;SYd#8{{VPj@-oWOHIgR5 F{{sjwv8@0A From 0bdc3b4f21eca0ff15d5053348711f4b60b7baab Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 15 Oct 2019 17:54:37 +0100 Subject: [PATCH 104/143] Fix Values coerce to typeid #443 --- src/check_expr.cpp | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7c418c4f0..f8bb88595 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -676,17 +676,6 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co return; } - #if 0 - if (operand->mode == Addressing_Type) { - Type *t = base_type(type); - if (t->kind == Type_Pointer && - t->Pointer.elem == t_type_info) { - add_type_info_type(c, type); - return; - } - } - #endif - if (is_type_untyped(operand->type)) { Type *target_type = type; if (type == nullptr || is_type_any(type)) { @@ -1590,10 +1579,7 @@ void check_cast_error_suggestion(CheckerContext *c, Operand *o, Type *type) { void check_is_expressible(CheckerContext *c, Operand *o, Type *type) { GB_ASSERT(o->mode == Addressing_Constant); - if (!is_type_constant_type(type)) { - return; - } - if (!check_representable_as_constant(c, o->value, type, &o->value)) { + if (!is_type_constant_type(type) || !check_representable_as_constant(c, o->value, type, &o->value)) { gbString a = expr_to_string(o->expr); gbString b = type_to_string(type); defer( From 12ae5ed09e3e798147d2f940cabfbdcead638272 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 15 Oct 2019 20:47:27 +0100 Subject: [PATCH 105/143] Fix missing typeid conversion case for variadic parameters --- src/check_expr.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f8bb88595..44bbc8988 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5339,6 +5339,10 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { if (is_type_any(elem)) { add_type_info_type(c, o.type); } + if (o.mode == Addressing_Type && is_type_typeid(t)) { + add_type_info_type(c, o.type); + add_type_and_value(c->info, o.expr, Addressing_Value, t, exact_value_typeid(o.type)); + } } } } From 2afe4bea67ff50c2ad41ff7c3ba7fbdc18748746 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 15 Oct 2019 22:43:04 +0100 Subject: [PATCH 106/143] Add `instrincs.type_is_valid_map_key` --- src/check_expr.cpp | 2 ++ src/checker_builtin_procs.hpp | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 44bbc8988..b2a2528dd 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3317,6 +3317,7 @@ BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_end - BuiltinProc__ty is_type_sliceable, is_type_simple_compare, is_type_dereferenceable, + is_type_valid_for_keys, is_type_named, is_type_pointer, @@ -4899,6 +4900,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_type_is_sliceable: case BuiltinProc_type_is_simple_compare: case BuiltinProc_type_is_dereferenceable: + case BuiltinProc_type_is_valid_map_key: case BuiltinProc_type_is_named: case BuiltinProc_type_is_pointer: case BuiltinProc_type_is_opaque: diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index b119452d4..50d27d715 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -134,6 +134,7 @@ BuiltinProc__type_begin, BuiltinProc_type_is_sliceable, BuiltinProc_type_is_simple_compare, // easily compared using memcmp BuiltinProc_type_is_dereferenceable, + BuiltinProc_type_is_valid_map_key, BuiltinProc_type_is_named, BuiltinProc_type_is_pointer, @@ -291,8 +292,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_ordered_numeric"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_indexable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_sliceable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_is_simple_compare"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics,}, + {STR_LIT("type_is_simple_compare"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_dereferenceable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_valid_map_key"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_named"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_pointer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, From 10b109e25f05862f478ba4c82f18ba22c8289017 Mon Sep 17 00:00:00 2001 From: Tetralux Date: Sat, 19 Oct 2019 17:55:05 +0100 Subject: [PATCH 107/143] Clarify that you can pass a directory to `odin build` Changes the usage information to this: ``` D:\Software\odin\odin.exe is a tool for managing Odin source code Usage: D:\Software\odin\odin.exe command [arguments] Commands: build compile .odin file, or directory of .odin files, as an executable. one must contain the program's entry point, all must be in the same package. run same as 'build', but also then runs the newly compiled executable. check parse and type check .odin file query parse, type check, and output a .json file containing information about the program docs generate documentation for a .odin file version print version ``` --- src/main.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 78859e04e..acb580ca2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -160,8 +160,9 @@ void usage(String argv0) { print_usage_line(0, "Usage:"); print_usage_line(1, "%.*s command [arguments]", LIT(argv0)); print_usage_line(0, "Commands:"); - print_usage_line(1, "build compile .odin file as executable"); - print_usage_line(1, "run compile and run .odin file"); + print_usage_line(1, "build compile .odin file, or directory of .odin files, as an executable."); + print_usage_line(1, " one must contain the program's entry point, all must be in the same package."); + print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable."); print_usage_line(1, "check parse and type check .odin file"); print_usage_line(1, "query parse, type check, and output a .json file containing information about the program"); print_usage_line(1, "docs generate documentation for a .odin file"); From 9f0a28017daa4f39f3c16e46df7e766e5de3ca38 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 20 Oct 2019 10:50:18 +0100 Subject: [PATCH 108/143] Fix typo in `string_to_string16` #444 --- src/string.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/string.cpp b/src/string.cpp index a29f3bd77..6812c5c39 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -404,7 +404,7 @@ String16 string_to_string16(gbAllocator a, String s) { } text[len] = 0; - return make_string16(text, len-1); + return make_string16(text, len); } From f12ded54f2b1a390f556e67a17ff0bf4c301a8e3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 20 Oct 2019 13:11:28 +0100 Subject: [PATCH 109/143] Support for named indices for array-like compound literals `{3 = a, 1 = b}` --- src/check_expr.cpp | 103 ++++++++++++++++++++++++++++++++--------- src/ir.cpp | 112 +++++++++++++++++++++++++++++++++------------ src/ir_print.cpp | 60 ++++++++++++++++++------ src/parser.hpp | 1 + 4 files changed, 213 insertions(+), 63 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b2a2528dd..60c057ae9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7066,7 +7066,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type i64 max = 0; - isize index = 0; Type *bet = base_type(elem_type); if (!elem_type_can_be_constant(bet)) { @@ -7077,40 +7076,100 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type break; } - for (; index < cl->elems.count; index++) { - Ast *e = cl->elems[index]; - if (e == nullptr) { - error(node, "Invalid literal element"); - continue; + if (cl->elems[0]->kind == Ast_FieldValue) { + if (is_type_simd_vector(t)) { + error(cl->elems[0], "'field = value' is not allowed for SIMD vector literals"); + } else { + Map seen = {}; + map_init(&seen, heap_allocator()); + defer (map_destroy(&seen)); + + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind != Ast_FieldValue) { + error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } + ast_node(fv, FieldValue, elem); + + Operand op_index = {}; + check_expr(c, &op_index, fv->field); + + if (op_index.mode != Addressing_Constant || !is_type_integer(core_type(op_index.type))) { + error(elem, "Expected a constant integer as an array field"); + continue; + } + + i64 index = exact_value_to_i64(op_index.value); + + if (max_type_count >= 0 && (index < 0 || index >= max_type_count)) { + error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", index, max_type_count, LIT(context_name)); + continue; + } + + if (map_get(&seen, hash_integer(u64(index))) != nullptr) { + error(elem, "Duplicate field index %lld for %.*s", index, LIT(context_name)); + continue; + } + map_set(&seen, hash_integer(u64(index)), true); + + if (max < index) { + max = index; + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, fv->value, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; + } + + cl->max_index = max; } - if (e->kind == Ast_FieldValue) { - error(e, "'field = value' is only allowed in struct literals"); - continue; + + } else { + isize index = 0; + for (; index < cl->elems.count; index++) { + Ast *e = cl->elems[index]; + if (e == nullptr) { + error(node, "Invalid literal element"); + continue; + } + + if (e->kind == Ast_FieldValue) { + error(e, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } + + if (0 <= max_type_count && max_type_count <= index) { + error(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name)); + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, e, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; } - if (0 <= max_type_count && max_type_count <= index) { - error(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name)); + if (max < index) { + max = index; } - - Operand operand = {}; - check_expr_with_type_hint(c, &operand, e, elem_type); - check_assignment(c, &operand, elem_type, context_name); - - is_constant = is_constant && operand.mode == Addressing_Constant; - } - if (max < index) { - max = index; } + if (t->kind == Type_Array) { if (is_to_be_determined_array_count) { t->Array.count = max; - } else if (0 < max && max < t->Array.count) { - error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max); + } else if (cl->elems[0]->kind != Ast_FieldValue) { + if (0 < max && max < t->Array.count) { + error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max); + } } } + if (t->kind == Type_SimdVector) { if (!is_constant) { error(node, "Expected all constant elements for a simd vector"); diff --git a/src/ir.cpp b/src/ir.cpp index 0bf706f67..bea9ee8b3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1552,6 +1552,7 @@ irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) { if (count == 0) { return ir_value_nil(type); } + count = gb_max(cl->max_index+1, count); Type *elem = base_type(type)->Slice.elem; Type *t = alloc_type_array(elem, count); irValue *backing_array = ir_add_module_constant(m, t, value); @@ -7859,13 +7860,29 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { // NOTE(bill): Separate value, gep, store into their own chunks for_array(i, cl->elems) { Ast *elem = cl->elems[i]; - if (ir_is_elem_const(proc->module, elem, et)) { - continue; + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + if (ir_is_elem_const(proc->module, fv->value, et)) { + continue; + } + auto tav = fv->field->tav; + GB_ASSERT(tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(tav.value); + + irCompoundLitElemTempData data = {}; + data.expr = fv->value; + data.elem_index = cast(i32)index; + array_add(&temp_data, data); + + } else { + if (ir_is_elem_const(proc->module, elem, et)) { + continue; + } + irCompoundLitElemTempData data = {}; + data.expr = elem; + data.elem_index = cast(i32)i; + array_add(&temp_data, data); } - irCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); } for_array(i, temp_data) { @@ -7881,6 +7898,9 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { defer (proc->return_ptr_hint_used = return_ptr_hint_used); Ast *expr = temp_data[i].expr; + if (expr == nullptr) { + continue; + } proc->return_ptr_hint_value = temp_data[i].gep; proc->return_ptr_hint_ast = unparen_expr(expr); @@ -7918,18 +7938,40 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { for_array(i, cl->elems) { Ast *elem = cl->elems[i]; - if (ir_is_elem_const(proc->module, elem, et)) { - continue; - } - irValue *field_expr = ir_build_expr(proc, elem); - Type *t = ir_type(field_expr); - GB_ASSERT(t->kind != Type_Tuple); - irValue *ev = ir_emit_conv(proc, field_expr, et); + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); - irCompoundLitElemTempData data = {}; - data.value = ev; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); + if (ir_is_elem_const(proc->module, fv->value, et)) { + continue; + } + + + GB_ASSERT(fv->field->tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(fv->field->tav.value); + + irValue *field_expr = ir_build_expr(proc, fv->value); + GB_ASSERT(!is_type_tuple(ir_type(field_expr))); + + irValue *ev = ir_emit_conv(proc, field_expr, et); + + irCompoundLitElemTempData data = {}; + data.value = ev; + data.elem_index = cast(i32)index; + array_add(&temp_data, data); + } else { + if (ir_is_elem_const(proc->module, elem, et)) { + continue; + } + irValue *field_expr = ir_build_expr(proc, elem); + GB_ASSERT(!is_type_tuple(ir_type(field_expr))); + + irValue *ev = ir_emit_conv(proc, field_expr, et); + + irCompoundLitElemTempData data = {}; + data.value = ev; + data.elem_index = cast(i32)i; + array_add(&temp_data, data); + } } for_array(i, temp_data) { @@ -7950,28 +7992,42 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { if (cl->elems.count == 0) { break; } - Type *elem = bt->DynamicArray.elem; + Type *et = bt->DynamicArray.elem; gbAllocator a = ir_allocator(); - irValue *size = ir_const_int(type_size_of(elem)); - irValue *align = ir_const_int(type_align_of(elem)); + irValue *size = ir_const_int(type_size_of(et)); + irValue *align = ir_const_int(type_align_of(et)); + + i64 item_count = gb_max(cl->max_index+1, cl->elems.count); { + auto args = array_make(a, 5); args[0] = ir_emit_conv(proc, v, t_rawptr); args[1] = size; args[2] = align; - args[3] = ir_const_int(2*cl->elems.count); + args[3] = ir_const_int(2*item_count); // TODO(bill): Is this too much waste? args[4] = ir_emit_source_code_location(proc, proc_name, pos); ir_emit_runtime_call(proc, "__dynamic_array_reserve", args); } - i64 item_count = cl->elems.count; - irValue *items = ir_generate_array(proc->module, elem, item_count, str_lit("dacl$"), cast(i64)cast(intptr)expr); + irValue *items = ir_generate_array(proc->module, et, item_count, str_lit("dacl$"), cast(i64)cast(intptr)expr); - for_array(field_index, cl->elems) { - Ast *f = cl->elems[field_index]; - irValue *value = ir_emit_conv(proc, ir_build_expr(proc, f), elem); - irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index); - ir_emit_store(proc, ep, value); + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + GB_ASSERT(fv->field->tav.mode == Addressing_Constant); + + i64 field_index = exact_value_to_i64(fv->field->tav.value); + + irValue *ev = ir_build_expr(proc, fv->value); + irValue *value = ir_emit_conv(proc, ev, et); + irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index); + ir_emit_store(proc, ep, value); + } else { + irValue *value = ir_emit_conv(proc, ir_build_expr(proc, elem), et); + irValue *ep = ir_emit_array_epi(proc, items, cast(i32)i); + ir_emit_store(proc, ep, value); + } } { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index f76539fd6..cece0c1db 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -876,22 +876,56 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * ir_write_str_lit(f, "zeroinitializer"); break; } - GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count); + if (cl->elems[0]->kind == Ast_FieldValue) { + // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand + ir_write_byte(f, '['); + for (i64 i = 0; i < type->Array.count; i++) { + if (i > 0) ir_write_str_lit(f, ", "); - ir_write_byte(f, '['); + bool found = false; - for (isize i = 0; i < elem_count; i++) { - if (i > 0) ir_write_str_lit(f, ", "); - TypeAndValue tav = cl->elems[i]->tav; - GB_ASSERT(tav.mode != Addressing_Invalid); - ir_print_compound_element(f, m, tav.value, elem_type); + for (isize j = 0; j < elem_count; j++) { + Ast *elem = cl->elems[j]; + ast_node(fv, FieldValue, elem); + TypeAndValue index_tav = fv->field->tav; + GB_ASSERT(index_tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(index_tav.value); + if (index == i) { + TypeAndValue tav = fv->value->tav; + if (tav.mode != Addressing_Constant) { + break; + } + ir_print_compound_element(f, m, tav.value, elem_type); + found = true; + break; + } + } + + if (!found) { + ir_print_type(f, m, elem_type); + ir_write_byte(f, ' '); + ir_write_str_lit(f, "zeroinitializer"); + } + } + ir_write_byte(f, ']'); + } else { + GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count); + + ir_write_byte(f, '['); + + for (isize i = 0; i < elem_count; i++) { + if (i > 0) ir_write_str_lit(f, ", "); + TypeAndValue tav = cl->elems[i]->tav; + GB_ASSERT(tav.mode != Addressing_Invalid); + ir_print_compound_element(f, m, tav.value, elem_type); + } + for (isize i = elem_count; i < type->Array.count; i++) { + if (i >= elem_count) ir_write_str_lit(f, ", "); + ir_print_compound_element(f, m, empty_exact_value, elem_type); + } + + ir_write_byte(f, ']'); } - for (isize i = elem_count; i < type->Array.count; i++) { - if (i >= elem_count) ir_write_str_lit(f, ", "); - ir_print_compound_element(f, m, empty_exact_value, elem_type); - } - - ir_write_byte(f, ']'); } else if (is_type_simd_vector(type)) { ast_node(cl, CompoundLit, value.value_compound); diff --git a/src/parser.hpp b/src/parser.hpp index 419cf9da3..9c3f733e5 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -249,6 +249,7 @@ enum StmtAllowFlag { Ast *type; \ Array elems; \ Token open, close; \ + i64 max_index; \ }) \ AST_KIND(_ExprBegin, "", bool) \ AST_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \ From e15dfa8eb6c64b9c39fbd8ea0712e31082137d63 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 20 Oct 2019 18:26:30 +0100 Subject: [PATCH 110/143] Fix missing check for zero elements --- src/check_expr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 60c057ae9..195443159 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7076,7 +7076,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type break; } - if (cl->elems[0]->kind == Ast_FieldValue) { + if (cl->elems.count > 0 && cl->elems[0]->kind == Ast_FieldValue) { if (is_type_simd_vector(t)) { error(cl->elems[0], "'field = value' is not allowed for SIMD vector literals"); } else { @@ -7162,7 +7162,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (t->kind == Type_Array) { if (is_to_be_determined_array_count) { t->Array.count = max; - } else if (cl->elems[0]->kind != Ast_FieldValue) { + } else if (cl->elems.count > 0 && cl->elems[0]->kind != Ast_FieldValue) { if (0 < max && max < t->Array.count) { error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max); } From c0e8113f6f031a3e80efbb4f556f2831b1350905 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Hjortsh=C3=B8j?= Date: Mon, 21 Oct 2019 19:46:05 +0200 Subject: [PATCH 111/143] Add github CI action --- .github/workflows/ci.yml | 54 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..50ca88d95 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,54 @@ +name: CI +on: [push, pull_request] + +jobs: + build_unix: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macOS-latest] + + steps: + - uses: actions/checkout@v1 + - name: (macOS) Download LLVM and setup PATH + if: startsWith(matrix.os, 'macOS') + run: | + brew install llvm + echo ::add-path::/usr/local/opt/llvm/bin + echo ::set-env name=CPATH::`xcrun --show-sdk-path`/usr/include + - name: (Linux) Download LLVM + if: startsWith(matrix.os, 'ubuntu') + run: | + sudo apt-get install llvm + - name: build odin + run: make release + - name: Odin run + run: ./odin run examples/demo/demo.odin + - name: Odin check + run: ./odin check examples/demo/demo.odin -vet + build_windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v1 + - name: Install cURL + run: choco install curl + - name: Download and unpack LLVM bins + run: | + cd bin + curl -sL https://github.com/odin-lang/Odin/releases/download/llvm-windows/llvm-binaries.zip --output llvm-binaries.zip + ls + 7z x llvm-binaries.zip > nul + - name: build Odin + run: | + call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat + ./build_ci.bat + - name: Odin run + run: | + call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat + odin run examples/demo/demo.odin + - name: Odin check + run: | + call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat + odin check examples/demo/demo.odin -vet + + From 286c5b7b2402c3f51d78975c3d60665c93aab5b6 Mon Sep 17 00:00:00 2001 From: Mikkel Hjortshoej Date: Mon, 21 Oct 2019 23:01:32 +0200 Subject: [PATCH 112/143] Remove old CI runners --- .travis.yml | 24 ------------------------ appveyor.yml | 19 ------------------- 2 files changed, 43 deletions(-) delete mode 100644 .travis.yml delete mode 100644 appveyor.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a0169259d..000000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: cpp -git: - depth: false - -os: - - linux - - osx - -compiler: - - clang - -addons: - homebrew: - packages: - - llvm - -script: - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export PATH="/usr/local/opt/llvm/bin:$PATH" ; fi - - make release - - ./odin run examples/demo/demo.odin - - ./odin check examples/demo/demo.odin -vet - -notifications: - email: false diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 5e5abe979..000000000 --- a/appveyor.yml +++ /dev/null @@ -1,19 +0,0 @@ -image: - - Visual Studio 2017 -shallow_clone: true - -platform: x64 - -install: - - cd bin - - appveyor DownloadFile https://github.com/odin-lang/Odin/releases/download/llvm-windows/llvm-binaries.zip - - 7z x llvm-binaries.zip > nul - - cd .. - -build_script: - - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" - - ./build_ci.bat - -test_script: - - odin run examples/demo/demo.odin - - odin check examples/demo/demo.odin -vet \ No newline at end of file From 818d6dbbea3907679f47ce8eb931a58c6f4137d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Hjortsh=C3=B8j?= Date: Mon, 21 Oct 2019 23:05:18 +0200 Subject: [PATCH 113/143] Update README.md with new CI badge --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 920cf71fb..f4c6ba791 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,12 @@ +
-
- - + + From 516df9123d8b4bc322420150480dca1112cbd02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikkel=20Hjortsh=C3=B8j?= Date: Mon, 21 Oct 2019 23:08:16 +0200 Subject: [PATCH 114/143] Update README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index f4c6ba791..d3de6f332 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,6 @@ - - -