diff options
Diffstat (limited to 'core')
| -rw-r--r-- | core/dynlib/lib.odin | 3 | ||||
| -rw-r--r-- | core/dynlib/lib_windows.odin | 24 | ||||
| -rw-r--r-- | core/encoding/cel/token.odin | 20 | ||||
| -rw-r--r-- | core/fmt/fmt.odin | 38 | ||||
| -rw-r--r-- | core/mem/allocators.odin | 30 | ||||
| -rw-r--r-- | core/mem/mem.odin | 8 | ||||
| -rw-r--r-- | core/odin/ast/ast.odin | 5 | ||||
| -rw-r--r-- | core/odin/parser/parser.odin | 75 | ||||
| -rw-r--r-- | core/odin/token/token.odin | 30 | ||||
| -rw-r--r-- | core/odin/tokenizer/tokenizer.odin | 10 | ||||
| -rw-r--r-- | core/os/os.odin | 24 | ||||
| -rw-r--r-- | core/runtime/core.odin | 38 | ||||
| -rw-r--r-- | core/strconv/strconv.odin | 6 | ||||
| -rw-r--r-- | core/strings/builder.odin | 4 | ||||
| -rw-r--r-- | core/strings/strings.odin | 17 | ||||
| -rw-r--r-- | core/sync/sync_windows.odin | 28 | ||||
| -rw-r--r-- | core/sys/win32/comdlg32.odin | 100 | ||||
| -rw-r--r-- | core/sys/win32/crt.odin | 14 | ||||
| -rw-r--r-- | core/sys/win32/general.odin | 3 | ||||
| -rw-r--r-- | core/sys/win32/kernel32.odin | 47 | ||||
| -rw-r--r-- | core/types/types.odin | 5 | ||||
| -rw-r--r-- | core/unicode/utf8/utf8.odin | 2 |
22 files changed, 411 insertions, 120 deletions
diff --git a/core/dynlib/lib.odin b/core/dynlib/lib.odin new file mode 100644 index 000000000..66742b835 --- /dev/null +++ b/core/dynlib/lib.odin @@ -0,0 +1,3 @@ +package dynlib + +Library :: opaque rawptr; diff --git a/core/dynlib/lib_windows.odin b/core/dynlib/lib_windows.odin new file mode 100644 index 000000000..67ce47cc1 --- /dev/null +++ b/core/dynlib/lib_windows.odin @@ -0,0 +1,24 @@ +package dynlib + +import "core:sys/win32" +import "core:strings" + +load_library :: proc(path: string, global_symbols := false) -> (Library, bool) { + // NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL + + wide_path := win32.utf8_to_wstring(path, context.temp_allocator); + handle := cast(Library)win32.load_library_w(wide_path); + return handle, handle != nil; +} + +unload_library :: proc(library: Library) -> bool { + ok := win32.free_library(cast(win32.Hmodule)library); + return bool(ok); +} + +symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) { + c_str := strings.new_cstring(symbol, context.temp_allocator); + ptr = win32.get_proc_address(cast(win32.Hmodule)library, c_str); + found == ptr != nil; + return; +} diff --git a/core/encoding/cel/token.odin b/core/encoding/cel/token.odin index 46c8d61be..9c3bdf715 100644 --- a/core/encoding/cel/token.odin +++ b/core/encoding/cel/token.odin @@ -78,7 +78,7 @@ Token :: struct { } Tokenizer :: struct { - src: []byte, + src: []byte, file: string, // May not be used @@ -281,7 +281,7 @@ digit_value :: proc(r: rune) -> int { } scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) { - scan_manitissa :: proc(t: ^Tokenizer, base: int) { + scan_mantissa :: proc(t: ^Tokenizer, base: int) { for digit_value(t.curr_rune) < base || t.curr_rune == '_' { advance_to_next_rune(t); } @@ -294,7 +294,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) { advance_to_next_rune(t); } if digit_value(t.curr_rune) < 10 { - scan_manitissa(t, 10); + scan_mantissa(t, 10); } else { token_error(t, "Illegal floating point exponent"); } @@ -305,7 +305,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) { if t.curr_rune == '.' { tok = Float; advance_to_next_rune(t); - scan_manitissa(t, 10); + scan_mantissa(t, 10); } return scan_exponent(t, tok, offset); @@ -317,7 +317,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) { if seen_decimal_point { offset -= 1; tok = Float; - scan_manitissa(t, 10); + scan_mantissa(t, 10); return scan_exponent(t, tok, offset); } @@ -327,24 +327,24 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) { switch t.curr_rune { case 'b', 'B': advance_to_next_rune(t); - scan_manitissa(t, 2); + scan_mantissa(t, 2); if t.offset - offset <= 2 { token_error(t, "Illegal binary number"); } case 'o', 'O': advance_to_next_rune(t); - scan_manitissa(t, 8); + scan_mantissa(t, 8); if t.offset - offset <= 2 { token_error(t, "Illegal octal number"); } case 'x', 'X': advance_to_next_rune(t); - scan_manitissa(t, 16); + scan_mantissa(t, 16); if t.offset - offset <= 2 { token_error(t, "Illegal hexadecimal number"); } case: - scan_manitissa(t, 10); + scan_mantissa(t, 10); switch t.curr_rune { case '.', 'e', 'E': return scan_fraction(t, tok, offset); @@ -354,7 +354,7 @@ scan_number :: proc(t: ^Tokenizer, seen_decimal_point: bool) -> (Kind, string) { return tok, string(t.src[offset:t.offset]); } - scan_manitissa(t, 10); + scan_mantissa(t, 10); return scan_fraction(t, tok, offset); } diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index c4a535d77..344f61e80 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -468,11 +468,10 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d buf: [256]byte; start := 0; - using strconv.Int_Flag; flags: strconv.Int_Flags; - if fi.hash && !fi.zero do flags |= {Prefix}; - if fi.plus do flags |= {Plus}; - if fi.space do flags |= {Space}; + if fi.hash && !fi.zero do flags |= {.Prefix}; + if fi.plus do flags |= {.Plus}; + if fi.space do flags |= {.Space}; s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags); if fi.hash && fi.zero { @@ -746,11 +745,10 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") { ti = runtime.type_info_base(ti); switch info in ti.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; @@ -1008,6 +1006,20 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { fmt_arg(fi, any{rawptr(data), info.elem.id}, verb); } + case runtime.Type_Info_Simd_Vector: + if info.is_x86_mmx { + strings.write_string(fi.buf, "intrinsics.x86_mmx<>"); + } + strings.write_byte(fi.buf, '<'); + defer strings.write_byte(fi.buf, '>'); + for i in 0..info.count-1 { + if i > 0 do strings.write_string(fi.buf, ", "); + + data := uintptr(v.data) + uintptr(i*info.elem_size); + fmt_arg(fi, any{rawptr(data), info.elem.id}, verb); + } + + case runtime.Type_Info_Slice: strings.write_byte(fi.buf, '['); defer strings.write_byte(fi.buf, ']'); @@ -1448,5 +1460,15 @@ write_type :: proc(buf: ^strings.Builder, ti: ^runtime.Type_Info) { 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/mem/allocators.odin b/core/mem/allocators.odin index af6ed329a..77cc0abf1 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -47,12 +47,10 @@ arena_allocator :: proc(arena: ^Arena) -> Allocator { arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr { - using Allocator_Mode; arena := cast(^Arena)allocator_data; - switch mode { - case Alloc: + case .Alloc: total_size := size + alignment; if arena.offset + total_size > len(arena.data) { @@ -66,14 +64,14 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, arena.peak_used = max(arena.peak_used, arena.offset); return zero(ptr, size); - case Free: + case .Free: // NOTE(bill): Free all at once // Use Arena_Temp_Memory if you want to free a block - case Free_All: + case .Free_All: arena.offset = 0; - case Resize: + case .Resize: return default_resize_align(old_memory, old_size, size, alignment, arena_allocator(arena)); } @@ -227,7 +225,6 @@ stack_allocator :: proc(stack: ^Stack) -> Allocator { stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr { - using Allocator_Mode; s := cast(^Stack)allocator_data; if s.data == nil { @@ -256,9 +253,9 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, } switch mode { - case Alloc: + case .Alloc: return raw_alloc(s, size, alignment); - case Free: + case .Free: if old_memory == nil { return nil; } @@ -288,11 +285,11 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, s.prev_offset = int(header.prev_offset); - case Free_All: + case .Free_All: s.prev_offset = 0; s.curr_offset = 0; - case Resize: + case .Resize: if old_memory == nil { return raw_alloc(s, size, alignment); } @@ -374,13 +371,14 @@ small_stack_allocator :: proc(stack: ^Small_Stack) -> Allocator { small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, flags: u64, location := #caller_location) -> rawptr { - using Allocator_Mode; s := cast(^Small_Stack)allocator_data; if s.data == nil { return nil; } + alignment = clamp(alignment, 1, 8*size_of(Stack_Allocation_Header{}.padding)/2); + raw_alloc :: proc(s: ^Small_Stack, size, alignment: int) -> rawptr { curr_addr := uintptr(&s.data[0]) + uintptr(s.offset); padding := calc_padding_with_header(curr_addr, uintptr(alignment), size_of(Small_Stack_Allocation_Header)); @@ -401,9 +399,9 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, } switch mode { - case Alloc: + case .Alloc: return raw_alloc(s, size, alignment); - case Free: + case .Free: if old_memory == nil { return nil; } @@ -426,10 +424,10 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, s.offset = int(old_offset); - case Free_All: + case .Free_All: s.offset = 0; - case Resize: + case .Resize: if old_memory == nil { return raw_alloc(s, size, alignment); } diff --git a/core/mem/mem.odin b/core/mem/mem.odin index 4bb94ba0f..47591437f 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -183,6 +183,14 @@ align_forward_uintptr :: proc(ptr, align: uintptr) -> uintptr { return uintptr(p); } + +align_forward_int :: inline proc(ptr, align: int) -> int { + return int(align_forward_uintptr(uintptr(ptr), uintptr(align))); +} +align_forward_uint :: inline proc(ptr, align: uint) -> uint { + return uint(align_forward_uintptr(uintptr(ptr), uintptr(align))); +} + context_from_allocator :: proc(a: Allocator) -> type_of(context) { context.allocator = a; return context; diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 784c89e6a..59d18a0c0 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -144,6 +144,10 @@ Selector_Expr :: struct { field: ^Ident, } +Implicit_Selector_Expr :: struct { + using node: Expr, + field: ^Ident, +} Index_Expr :: struct { using node: Expr, @@ -365,7 +369,6 @@ Value_Decl :: struct { type: ^Expr, values: []^Expr, comment: ^Comment_Group, - is_static: bool, is_using: bool, is_mutable: bool, } diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 7c7a816c9..ccae59a7c 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -857,10 +857,6 @@ parse_foreign_block :: proc(p: ^Parser, tok: token.Token) -> ^ast.Foreign_Block_ foreign_library: ^ast.Expr; switch p.curr_tok.kind { - case token.Export: - i := ast.new(ast.Implicit, tok.pos, end_pos(tok)); - i.tok = expect_token(p, token.Export); - foreign_library = i; case token.Open_Brace: i := ast.new(ast.Ident, tok.pos, end_pos(tok)); i.name = "_"; @@ -903,7 +899,7 @@ parse_foreign_decl :: proc(p: ^Parser) -> ^ast.Decl { tok := expect_token(p, token.Foreign); switch p.curr_tok.kind { - case token.Export, token.Ident, token.Open_Brace: + case token.Ident, token.Open_Brace: return parse_foreign_block(p, tok); case token.Import: @@ -1033,37 +1029,6 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { expect_semicolon(p, s); return s; - case token.Static: - docs := p.lead_comment; - tok := expect_token(p, token.Static); - - list := parse_lhs_expr_list(p); - if len(list) == 0 { - error(p, tok.pos, "illegal use of 'static' statement"); - expect_semicolon(p, nil); - return ast.new(ast.Bad_Stmt, tok.pos, end_pos(p.prev_tok)); - } - - expect_token_after(p, token.Colon, "identifier list"); - decl := parse_value_decl(p, list, docs); - if decl != nil do switch d in &decl.derived { - case ast.Value_Decl: - if d.is_mutable { - d.is_static = true; - } else { - error(p, tok.pos, "'static' may only be currently used with variable declarations"); - } - case: - error(p, tok.pos, "illegal use of 'static' statement"); - } - - error(p, tok.pos, "illegal use of 'static' statement"); - if decl != nil { - return decl; - } - - return ast.new(ast.Bad_Stmt, tok.pos, end_pos(p.prev_tok)); - case token.Using: docs := p.lead_comment; tok := expect_token(p, token.Using); @@ -1112,9 +1077,9 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { stmt := parse_stmt(p); switch name { case "bounds_check": - stmt.state_flags |= {ast.Node_State_Flag.Bounds_Check}; + stmt.state_flags |= {.Bounds_Check}; case "no_bounds_check": - stmt.state_flags |= {ast.Node_State_Flag.No_Bounds_Check}; + stmt.state_flags |= {.No_Bounds_Check}; } return stmt; case "complete": @@ -1758,6 +1723,29 @@ string_to_calling_convention :: proc(s: string) -> ast.Proc_Calling_Convention { return Invalid; } +parse_proc_tags :: proc(p: ^Parser) -> (tags: Proc_Tags) { + for p.curr_tok.kind == token.Hash { + tok := expect_token(p, token.Hash); + 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": + tags |= {.No_Bounds_Check}; + case: + } + } + + if .Bounds_Check in tags && .No_Bounds_Check in tags { + p.err(p.curr_tok.pos, "#bounds_check and #no_bounds_check applied to the same procedure type"); + } + + return; +} + parse_proc_type :: proc(p: ^Parser, tok: token.Token) -> ^ast.Proc_Type { cc := ast.Proc_Calling_Convention.Invalid; if p.curr_tok.kind == token.String { @@ -2616,6 +2604,13 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { ue.expr = expr; return ue; + case token.Period: + op := advance_token(p); + field := parse_ident(p); + ise := ast.new(ast.Implicit_Selector_Expr, op.pos, field.end); + ise.field = field; + return ise; + } return parse_atom_expr(p, parse_operand(p, lhs), lhs); } @@ -2707,7 +2702,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt { return stmt; case op.kind == token.In: - if Stmt_Allow_Flag.In in flags { + if .In in flags { allow_token(p, token.In); prev_allow_range := p.allow_range; p.allow_range = true; @@ -2725,7 +2720,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt { } case op.kind == token.Colon: expect_token_after(p, token.Colon, "identifier list"); - if Stmt_Allow_Flag.Label in flags && len(lhs) == 1 { + if .Label in flags && len(lhs) == 1 { switch p.curr_tok.kind { case token.Open_Brace, token.If, token.For, token.Switch: label := lhs[0]; diff --git a/core/odin/token/token.odin b/core/odin/token/token.odin index 46b3fc846..7e985d46d 100644 --- a/core/odin/token/token.odin +++ b/core/odin/token/token.odin @@ -28,7 +28,7 @@ pos_compare :: proc(lhs, rhs: Pos) -> int { return strings.compare(lhs.file, rhs.file); } -using Kind :: enum u16 { +using Kind :: enum u32 { Invalid, EOF, Comment, @@ -113,7 +113,6 @@ using Kind :: enum u16 { B_Keyword_Begin, Import, - Export, Foreign, Package, Typeid, @@ -139,7 +138,6 @@ using Kind :: enum u16 { Bit_Field, Bit_Set, Map, - Static, Dynamic, Auto_Cast, Cast, @@ -161,6 +159,9 @@ using Kind :: enum u16 { B_Keyword_End, COUNT, + + B_Custom_Keyword_Begin = COUNT+1, + // ... Custom keywords }; tokens := [Kind.COUNT]string { @@ -248,7 +249,6 @@ tokens := [Kind.COUNT]string { "", "import", - "export", "foreign", "package", "typeid", @@ -274,7 +274,6 @@ tokens := [Kind.COUNT]string { "bit_field", "bit_set", "map", - "static", "dynamic", "auto_cast", "cast", @@ -296,10 +295,19 @@ tokens := [Kind.COUNT]string { "", }; +custom_keyword_tokens: []string; + to_string :: proc(kind: Kind) -> string { - if min(Kind) <= kind && kind <= max(Kind) { + 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"; } @@ -316,4 +324,12 @@ is_operator :: proc(kind: Kind) -> bool { 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 { return B_Keyword_Begin < kind && kind < B_Keyword_End; } +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 a009d6ba3..fca475839 100644 --- a/core/odin/tokenizer/tokenizer.odin +++ b/core/odin/tokenizer/tokenizer.odin @@ -486,12 +486,18 @@ scan :: proc(t: ^Tokenizer) -> token.Token { case is_letter(ch): lit = scan_identifier(t); kind = token.Ident; - if len(lit) > 1 { + 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); - break; + break check_keyword; + } + } + for keyword, i in token.custom_keyword_tokens { + if lit == keyword { + kind = token.Kind(i+1)+token.B_Custom_Keyword_Begin; + break check_keyword; } } } diff --git a/core/os/os.odin b/core/os/os.odin index eda3b66cf..d9bb318c4 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -51,6 +51,20 @@ write_encoded_rune :: proc(fd: Handle, r: rune) { } +file_size_from_path :: proc(path: string) -> i64 { + fd, err := open(path, O_RDONLY, 0); + if err != 0 { + return -1; + } + defer close(fd); + + length: i64; + if length, err = file_size(fd); err != 0 { + return -1; + } + return length; +} + read_entire_file :: proc(name: string) -> (data: []byte, success: bool) { fd, err := open(name, O_RDONLY, 0); if err != 0 { @@ -109,20 +123,18 @@ read_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) { heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr { - using mem.Allocator_Mode; - switch mode { - case Alloc: + case .Alloc: return heap_alloc(size); - case Free: + case .Free: heap_free(old_memory); return nil; - case Free_All: + case .Free_All: // NOTE(bill): Does nothing - case Resize: + case .Resize: if old_memory == nil { return heap_alloc(size); } diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 9307b5589..1ce7cfac5 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -112,9 +112,14 @@ Type_Info_Bit_Set :: struct { lower: i64, upper: i64, }; - Type_Info_Opaque :: struct { elem: ^Type_Info, +}; +Type_Info_Simd_Vector :: struct { + elem: ^Type_Info, + elem_size: int, + count: int, + is_x86_mmx: bool, } Type_Info :: struct { @@ -145,6 +150,7 @@ Type_Info :: struct { Type_Info_Bit_Field, Type_Info_Bit_Set, Type_Info_Opaque, + Type_Info_Simd_Vector, }, } @@ -245,8 +251,10 @@ Map_Entry_Header :: struct { Map_Header :: struct { m: ^mem.Raw_Map, is_key_string: bool, + entry_size: int, entry_align: int, + value_offset: uintptr, value_size: int, } @@ -827,29 +835,23 @@ __get_map_key :: proc "contextless" (key: $K) -> Map_Key { return map_key; } +_fnv64a :: proc(data: []byte, seed: u64 = 0xcbf29ce484222325) -> u64 { + h: u64 = seed; + for b in data { + h = (h ~ u64(b)) * 0x100000001b3; + } + return h; +} + default_hash :: proc(data: []byte) -> u64 { - fnv64a :: proc(data: []byte) -> u64 { - h: u64 = 0xcbf29ce484222325; - for b in data { - h = (h ~ u64(b)) * 0x100000001b3; - } - return h; - } - return fnv64a(data); + return _fnv64a(data); } default_hash_string :: proc(s: string) -> u64 do return default_hash(([]byte)(s)); source_code_location_hash :: proc(s: Source_Code_Location) -> u64 { - fnv64a :: proc(data: []byte, seed: u64 = 0xcbf29ce484222325) -> u64 { - h: u64 = seed; - for b in data { - h = (h ~ u64(b)) * 0x100000001b3; - } - return h; - } - hash := fnv64a(cast([]byte)s.file_path); + hash := _fnv64a(cast([]byte)s.file_path); hash = hash ~ (u64(s.line) * 0x100000001b3); hash = hash ~ (u64(s.column) * 0x100000001b3); return hash; @@ -857,7 +859,6 @@ 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_); @@ -936,7 +937,6 @@ __dynamic_map_get :: proc(h: Map_Header, key: Map_Key) -> rawptr { } __dynamic_map_set :: proc(h: Map_Header, key: Map_Key, value: rawptr, loc := #caller_location) #no_bounds_check { - index: int; assert(value != nil); diff --git a/core/strconv/strconv.odin b/core/strconv/strconv.odin index 0526a65ba..d509d7b6a 100644 --- a/core/strconv/strconv.odin +++ b/core/strconv/strconv.odin @@ -475,7 +475,7 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i } i-=1; a[i] = digits[u % b]; - if Int_Flag.Prefix in flags { + if .Prefix in flags { ok := true; switch base { case 2: i-=1; a[i] = 'b'; @@ -493,9 +493,9 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i switch { case neg: i-=1; a[i] = '-'; - case Int_Flag.Plus in flags: + case .Plus in flags: i-=1; a[i] = '+'; - case Int_Flag.Space in flags: + case .Space in flags: i-=1; a[i] = ' '; } diff --git a/core/strings/builder.odin b/core/strings/builder.odin index e86d748cc..547c456ba 100644 --- a/core/strings/builder.odin +++ b/core/strings/builder.odin @@ -61,8 +61,8 @@ write_bytes :: proc(b: ^Builder, x: []byte) { append(&b.buf, ..x); } -@(private) -static DIGITS_LOWER := "0123456789abcdefx"; +@(private, static) +DIGITS_LOWER := "0123456789abcdefx"; write_quoted_string :: proc(b: ^Builder, s: string, quote: byte = '"') { write_byte(b, quote); diff --git a/core/strings/strings.odin b/core/strings/strings.odin index efc5f2a6d..60fb56b27 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -329,6 +329,10 @@ is_space :: proc(r: rune) -> bool { return false; } +is_null :: proc(r: rune) -> bool { + return r == 0x0000; +} + index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> int { for r, i in s { if p(r) == truth { @@ -478,6 +482,19 @@ trim_space :: proc(s: string) -> string { } +trim_left_null :: proc(s: string) -> string { + return trim_left_proc(s, is_null); +} + +trim_right_null :: proc(s: string) -> string { + return trim_right_proc(s, is_null); +} + +trim_null :: proc(s: string) -> string { + return trim_right_null(trim_left_null(s)); +} + + // returns a slice of sub-strings into `s` // `allocator` is used only for the slice // `skip_empty=true` does not return zero-length substrings diff --git a/core/sync/sync_windows.odin b/core/sync/sync_windows.odin index 3854f6807..b0a9d944c 100644 --- a/core/sync/sync_windows.odin +++ b/core/sync/sync_windows.odin @@ -2,6 +2,11 @@ package sync import "core:sys/win32" +foreign { + @(link_name="llvm.x86.sse2.pause") + yield_processor :: proc() --- +} + Semaphore :: struct { _handle: win32.Handle, } @@ -14,6 +19,12 @@ Condition :: struct { event: win32.Handle, } +Ticket_Mutex :: struct { + ticket: u64, + serving: u64, +} + + current_thread_id :: proc() -> i32 { return i32(win32.get_current_thread_id()); } @@ -81,3 +92,20 @@ condition_destroy :: proc(using c: ^Condition) { win32.close_handle(event); } } + + +ticket_mutex_init :: proc(m: ^Ticket_Mutex) { + atomic_store(&m.ticket, 0, Ordering.Relaxed); + atomic_store(&m.serving, 0, Ordering.Relaxed); +} + +ticket_mutex_lock :: inline proc(m: ^Ticket_Mutex) { + ticket := atomic_add(&m.ticket, 1, Ordering.Relaxed); + for ticket != m.serving { + yield_processor(); + } +} + +ticket_mutex_unlock :: inline proc(m: ^Ticket_Mutex) { + atomic_add(&m.serving, 1, Ordering.Relaxed); +} diff --git a/core/sys/win32/comdlg32.odin b/core/sys/win32/comdlg32.odin index 790c9d598..3d9fb74c4 100644 --- a/core/sys/win32/comdlg32.odin +++ b/core/sys/win32/comdlg32.odin @@ -2,6 +2,7 @@ package win32 foreign import "system:comdlg32.lib" +import "core:strings" OFN_Hook_Proc :: #type proc "stdcall" (hdlg: Hwnd, msg: u32, wparam: Wparam, lparam: Lparam) -> Uint_Ptr; @@ -61,11 +62,91 @@ Open_File_Name_W :: struct { foreign comdlg32 { @(link_name="GetOpenFileNameA") get_open_file_name_a :: proc(arg1: ^Open_File_Name_A) -> Bool --- @(link_name="GetOpenFileNameW") get_open_file_name_w :: proc(arg1: ^Open_File_Name_W) -> Bool --- - + @(link_name="GetSaveFileNameA") get_save_file_name_a :: proc(arg1: ^Open_File_Name_A) -> Bool --- + @(link_name="GetSaveFileNameW") get_save_file_name_w :: proc(arg1: ^Open_File_Name_W) -> Bool --- @(link_name="CommDlgExtendedError") comm_dlg_extended_error :: proc() -> u32 --- } -OFN_ALLOWMULTISELECT :: 0x00000200; +OPEN_TITLE :: "Select file to open"; +OPEN_FLAGS :: u32(OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST); +OPEN_FLAGS_MULTI :: u32(OPEN_FLAGS | OFN_ALLOWMULTISELECT | OFN_EXPLORER); + +SAVE_TITLE :: "Select file to save"; +SAVE_FLAGS :: u32(OFN_OVERWRITEPROMPT | OFN_EXPLORER); +SAVE_EXT :: "txt"; + +Open_Save_Mode :: enum { + Open = 0, + Save = 1, +} + +_open_file_dialog :: proc(title: string, dir: string, + filters: []string, default_filter: u32, + flags: u32, default_ext: string, + mode: Open_Save_Mode, allocator := context.temp_allocator) -> (path: string, ok: bool = true) { + file_buf := make([]u16, MAX_PATH_WIDE, allocator); + + // Filters need to be passed as a pair of strings (title, filter) + filter_len := u32(len(filters)); + if filter_len % 2 != 0 do return "", false; + default_filter = clamp(default_filter, 1, filter_len / 2); + + filter: string; + filter = strings.join(filters, "\u0000", context.temp_allocator); + filter = strings.concatenate({filter, "\u0000"}, context.temp_allocator); + + ofn := Open_File_Name_W{ + struct_size = size_of(Open_File_Name_W), + file = Wstring(&file_buf[0]), + max_file = MAX_PATH_WIDE, + title = utf8_to_wstring(title, context.temp_allocator), + filter = utf8_to_wstring(filter, context.temp_allocator), + initial_dir = utf8_to_wstring(dir, context.temp_allocator), + filter_index = u32(default_filter), + def_ext = utf8_to_wstring(default_ext, context.temp_allocator), + flags = u32(flags), + }; + + switch mode { + case .Open: + ok = bool(get_open_file_name_w(&ofn)); + case .Save: + ok = bool(get_save_file_name_w(&ofn)); + case: + ok = false; + } + + if !ok { + delete(file_buf); + return "", false; + } + + file_name := ucs2_to_utf8(file_buf[:], allocator); + path = strings.trim_right_null(file_name); + return; +} + +select_file_to_open :: proc(title := OPEN_TITLE, dir := ".", + filters := []string{"All Files", "*.*"}, default_filter := u32(1), + flags := OPEN_FLAGS, allocator := context.temp_allocator) -> (path: string, ok: bool) { + + path, ok = _open_file_dialog(title, dir, filters, default_filter, flags, "", Open_Save_Mode.Open, allocator); + return; +} + +select_file_to_save :: proc(title := SAVE_TITLE, dir := ".", + filters := []string{"All Files", "*.*"}, default_filter := u32(1), + flags := SAVE_FLAGS, default_ext := SAVE_EXT, + allocator := context.temp_allocator) -> (path: string, ok: bool) { + + path, ok = _open_file_dialog(title, dir, filters, default_filter, flags, default_ext, Open_Save_Mode.Save, allocator); + return; +} + +// TODO: Implement convenience function for select_file_to_open with ALLOW_MULTI_SELECT that takes +// it output of the form "path\u0000\file1u\0000file2" and turns it into []string with the path + file pre-concatenated for you. + +OFN_ALLOWMULTISELECT :: 0x00000200; // NOTE(Jeroen): Without OFN_EXPLORER it uses the Win3 dialog. OFN_CREATEPROMPT :: 0x00002000; OFN_DONTADDTORECENT :: 0x02000000; OFN_ENABLEHOOK :: 0x00000020; @@ -91,3 +172,18 @@ OFN_PATHMUSTEXIST :: 0x00000800; OFN_READONLY :: 0x00000001; OFN_SHAREAWARE :: 0x00004000; OFN_SHOWHELP :: 0x00000010; + +CDERR_DIALOGFAILURE :: 0x0000FFFF; +CDERR_GENERALCODES :: 0x00000000; +CDERR_STRUCTSIZE :: 0x00000001; +CDERR_INITIALIZATION :: 0x00000002; +CDERR_NOTEMPLATE :: 0x00000003; +CDERR_NOHINSTANCE :: 0x00000004; +CDERR_LOADSTRFAILURE :: 0x00000005; +CDERR_FINDRESFAILURE :: 0x00000006; +CDERR_LOADRESFAILURE :: 0x00000007; +CDERR_LOCKRESFAILURE :: 0x00000008; +CDERR_MEMALLOCFAILURE :: 0x00000009; +CDERR_MEMLOCKFAILURE :: 0x0000000A; +CDERR_NOHOOK :: 0x0000000B; +CDERR_REGISTERMSGFAIL :: 0x0000000C;
\ No newline at end of file diff --git a/core/sys/win32/crt.odin b/core/sys/win32/crt.odin new file mode 100644 index 000000000..46fba6fe8 --- /dev/null +++ b/core/sys/win32/crt.odin @@ -0,0 +1,14 @@ +package win32 + +import "core:strings"; + +foreign { + @(link_name="_wgetcwd") _get_cwd_wide :: proc(buffer: Wstring, buf_len: int) -> ^Wstring --- +} + +get_cwd :: proc(allocator := context.temp_allocator) -> string { + buffer := make([]u16, MAX_PATH_WIDE, allocator); + _get_cwd_wide(Wstring(&buffer[0]), MAX_PATH_WIDE); + file := ucs2_to_utf8(buffer[:], allocator); + return strings.trim_right_null(file); +}
\ No newline at end of file diff --git a/core/sys/win32/general.odin b/core/sys/win32/general.odin index c34294b51..f4f3de380 100644 --- a/core/sys/win32/general.odin +++ b/core/sys/win32/general.odin @@ -108,6 +108,8 @@ File_Attribute_Data :: struct { file_size_low: u32, } +// NOTE(Jeroen): The widechar version might want at least the 32k MAX_PATH_WIDE +// https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-findfirstfilew#parameters Find_Data_W :: struct{ file_attributes: u32, creation_time: Filetime, @@ -798,6 +800,7 @@ is_key_down :: inline proc(key: Key_Code) -> bool { return get_async_key_state(i MAX_PATH :: 0x00000104; +MAX_PATH_WIDE :: 0x8000; HANDLE_FLAG_INHERIT :: 1; HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2; diff --git a/core/sys/win32/kernel32.odin b/core/sys/win32/kernel32.odin index 56a150a5c..6e9c752fb 100644 --- a/core/sys/win32/kernel32.odin +++ b/core/sys/win32/kernel32.odin @@ -56,8 +56,8 @@ foreign kernel32 { @(link_name="GetFileSizeEx") get_file_size_ex :: proc(file_handle: Handle, file_size: ^i64) -> Bool ---; @(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: cstring) -> u32 ---; @(link_name="GetFileAttributesW") get_file_attributes_w :: proc(filename: Wstring) -> u32 ---; - @(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: cstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool ---; - @(link_name="GetFileAttributesExW") get_file_attributes_ex_w :: proc(filename: Wstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool ---; + @(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: cstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---; + @(link_name="GetFileAttributesExW") get_file_attributes_ex_w :: proc(filename: Wstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: ^File_Attribute_Data) -> Bool ---; @(link_name="GetFileInformationByHandle") get_file_information_by_handle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool ---; @(link_name="CreateDirectoryA") create_directory_a :: proc(path: cstring, security_attributes: ^Security_Attributes) -> Bool ---; @@ -164,7 +164,7 @@ foreign kernel32 { @(link_name="LoadLibraryA") load_library_a :: proc(c_str: cstring) -> Hmodule ---; @(link_name="LoadLibraryW") load_library_w :: proc(c_str: Wstring) -> Hmodule ---; - @(link_name="FreeLibrary") free_library :: proc(h: Hmodule) ---; + @(link_name="FreeLibrary") free_library :: proc(h: Hmodule) -> Bool ---; @(link_name="GetProcAddress") get_proc_address :: proc(h: Hmodule, c_str: cstring) -> rawptr ---; @(link_name="GetFullPathNameA") get_full_path_name_a :: proc(filename: cstring, buffer_length: u32, buffer: cstring, file_part: ^Wstring) -> u32 ---; @@ -177,3 +177,44 @@ foreign kernel32 { @(link_name="GetCurrentDirectorya") get_current_directory_a :: proc(buffer_length: u32, buffer: cstring) -> u32 ---; @(link_name="GetCurrentDirectoryW") get_current_directory_w :: proc(buffer_length: u32, buffer: Wstring) -> u32 ---; } + +Memory_Basic_Information :: struct { + base_address: rawptr, + allocation_base: rawptr, + allocation_protect: u32, + region_size: uint, + state: u32, + protect: u32, + type: u32, +} + +@(default_calling_convention = "std") +foreign kernel32 { + @(link_name="VirtualAlloc") virtual_alloc :: proc(address: rawptr, size: uint, allocation_type: u32, protect: u32) -> rawptr --- + @(link_name="VirtualAllocEx") virtual_alloc_ex :: proc(process: Handle, address: rawptr, size: uint, allocation_type: u32, protect: u32) -> rawptr --- + @(link_name="VirtualFree") virtual_free :: proc(address: rawptr, size: uint, free_type: u32) -> Bool --- + @(link_name="VirtualLock") virtual_lock :: proc(address: rawptr, size: uint) -> Bool --- + @(link_name="VirtualProtect") virtual_protect :: proc(address: rawptr, size: uint, new_protect: u32, old_protect: ^u32) -> Bool --- + @(link_name="VirtualQuery") virtual_query :: proc(address: rawptr, buffer: ^Memory_Basic_Information, length: uint) -> uint --- +} + +MEM_COMMIT :: 0x00001000; +MEM_RESERVE :: 0x00002000; +MEM_DECOMMIT :: 0x00004000; +MEM_RELEASE :: 0x00008000; +MEM_RESET :: 0x00080000; +MEM_RESET_UNDO :: 0x01000000; + +MEM_LARGE_PAGES :: 0x20000000; +MEM_PHYSICAL :: 0x00400000; +MEM_TOP_DOWN :: 0x00100000; +MEM_WRITE_WATCH :: 0x00200000; + +PAGE_NOACCESS :: 0x01; +PAGE_READONLY :: 0x02; +PAGE_READWRITE :: 0x04; +PAGE_WRITECOPY :: 0x08; +PAGE_EXECUTE :: 0x10; +PAGE_EXECUTE_READ :: 0x20; +PAGE_EXECUTE_READWRITE :: 0x40; +PAGE_EXECUTE_WRITECOPY :: 0x80; diff --git a/core/types/types.odin b/core/types/types.odin index 485530fea..dc4db549f 100644 --- a/core/types/types.odin +++ b/core/types/types.odin @@ -267,3 +267,8 @@ is_opaque :: proc(info: ^rt.Type_Info) -> bool { _, 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; +} diff --git a/core/unicode/utf8/utf8.odin b/core/unicode/utf8/utf8.odin index 50b33a680..d0396b9e0 100644 --- a/core/unicode/utf8/utf8.odin +++ b/core/unicode/utf8/utf8.odin @@ -90,7 +90,7 @@ encode_rune :: proc(r: rune) -> ([4]u8, int) { buf[0] = 0xf0 | u8(r>>18); buf[1] = 0x80 | u8(r>>12) & mask; buf[2] = 0x80 | u8(r>>6) & mask; - buf[3] = 0x80 | u8(r) & mask; + buf[3] = 0x80 | u8(r) & mask; return buf, 4; } |