diff options
| author | Ginger Bill <bill@gingerbill.org> | 2017-03-02 19:24:34 +0000 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2017-03-02 19:24:34 +0000 |
| commit | 9e8c9be1ea825c2b5c66e62724519ae9ab8ab8f6 (patch) | |
| tree | 2d199c849c7a1d25c533bd96fe1abe883cf00454 | |
| parent | 9bc37f44002d89ed35643b2bfd8c384cb5ff1f48 (diff) | |
Allow pointers to `append`; Fix strconv stuff; `new_slice` allows for capacity
| -rw-r--r-- | build.bat | 4 | ||||
| -rw-r--r-- | code/demo.odin | 4 | ||||
| -rw-r--r-- | core/fmt.odin | 10 | ||||
| -rw-r--r-- | core/strconv.odin | 19 | ||||
| -rw-r--r-- | core/strings.odin | 4 | ||||
| -rw-r--r-- | core/sync.odin | 62 | ||||
| -rw-r--r-- | core/sys/windows.odin | 83 | ||||
| -rw-r--r-- | src/check_expr.c | 47 | ||||
| -rw-r--r-- | src/checker.c | 2 | ||||
| -rw-r--r-- | src/ir.c | 21 | ||||
| -rw-r--r-- | src/ir_print.c | 11 | ||||
| -rw-r--r-- | src/types.c | 5 |
12 files changed, 184 insertions, 88 deletions
@@ -44,8 +44,8 @@ del *.ilk > NUL 2> NUL cl %compiler_settings% "src\main.c" ^ /link %linker_settings% -OUT:%exe_name% ^ - && odin run code/demo.odin - rem && odin run code/Jaze/src/main.odin + && odin build code/Jaze/src/main.odin + rem && odin run code/demo.odin rem && odin build_dll code/example.odin ^ rem odin run code/demo.odin diff --git a/code/demo.odin b/code/demo.odin index 8162fc0d3..2d03e2ec7 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -6,6 +6,7 @@ #import "opengl.odin"; #import "os.odin"; #import "strconv.odin"; +#import "sync.odin"; main :: proc() { // buf: [64]byte; @@ -15,8 +16,7 @@ main :: proc() { // fmt.println(s); // fmt.printf("%3d\n", 102); - a: [10]int; - s := a[..0]; + s := new_slice(int, 0, 10); append(s, 1, 2, 6, 3, 6, 5, 5, 5, 5, 1, 2); fmt.println(s); diff --git a/core/fmt.odin b/core/fmt.odin index eb2353b72..abc0d1ac7 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -8,10 +8,10 @@ _BUFFER_SIZE :: 1<<12; write_string :: proc(buf: ^[]byte, s: string) { - append(buf^, ..cast([]byte)s); + append(buf, ..cast([]byte)s); } write_byte :: proc(buf: ^[]byte, b: byte) { - append(buf^, b); + append(buf, b); } write_rune :: proc(buf: ^[]byte, r: rune) { if r < utf8.RUNE_SELF { @@ -20,7 +20,7 @@ write_rune :: proc(buf: ^[]byte, r: rune) { } b, n := utf8.encode_rune(r); - append(buf^, ..b[..n]); + append(buf, ..b[..n]); } Fmt_Info :: struct { @@ -431,7 +431,7 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) { count := min(width, fi.buf.capacity-fi.buf.count); for _ in 0..count { - append(fi.buf^, pad_byte); + append(fi.buf, pad_byte); } } @@ -533,8 +533,6 @@ _pad :: proc(fi: ^Fmt_Info, s: string) { } fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) { - - match verb { // case 'e', 'E', 'f', 'F', 'g', 'G', 'v': // case 'f', 'F', 'v': diff --git a/core/strconv.odin b/core/strconv.odin index ff78847df..53d890a6b 100644 --- a/core/strconv.odin +++ b/core/strconv.odin @@ -109,12 +109,9 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [ round_shortest(d, mant, exp, flt); digs = Decimal_Slice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point}; match fmt { - case 'e', 'E': - prec = digs.count-1; - case 'f', 'F': - prec = max(digs.count-digs.decimal_point, 0); - case 'g', 'G': - prec = digs.count; + case 'e', 'E': prec = digs.count-1; + case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0); + case 'g', 'G': prec = digs.count; } } else { match fmt { @@ -139,9 +136,10 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic case 'f', 'F': add_bytes :: proc(dst: ^[]byte, w: ^int, bytes: ..byte) { for b in bytes { - if dst.count <= w^ { + if dst.capacity <= w^ { break; } + dst.count++; dst[w^] = b; w^++; } @@ -166,6 +164,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic add_bytes(^dst, ^w, '0'); } + // fractional part if prec > 0 { add_bytes(^dst, ^w, '.'); @@ -181,10 +180,12 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic return buf[..w]; case 'e', 'E': - return nil; // TODO + panic("strconv: e/E float printing is not yet supported"); + return buf; // TODO case 'g', 'G': - return nil; // TODO + panic("strconv: g/G float printing is not yet supported"); + return buf; // TODO } c: [2]byte; diff --git a/core/strings.odin b/core/strings.odin index 7439fff32..7b2f09230 100644 --- a/core/strings.odin +++ b/core/strings.odin @@ -1,8 +1,8 @@ new_c_string :: proc(s: string) -> ^byte { - c := new_c_string(byte, s.count+1); + c := new_slice(byte, s.count+1); copy(c, cast([]byte)s); c[s.count] = 0; - return c; + return c.data; } to_odin_string :: proc(c: ^byte) -> string { diff --git a/core/sync.odin b/core/sync.odin index 3126d6882..a2296c3b6 100644 --- a/core/sync.odin +++ b/core/sync.odin @@ -2,14 +2,14 @@ #import "atomic.odin"; Semaphore :: struct { - handle: win32.HANDLE, + _handle: win32.HANDLE, } Mutex :: struct { - semaphore: Semaphore, - counter: i32, - owner: i32, - recursion: i32, + _semaphore: Semaphore, + _counter: i32, + _owner: i32, + _recursion: i32, } current_thread_id :: proc() -> i32 { @@ -17,74 +17,74 @@ current_thread_id :: proc() -> i32 { } semaphore_init :: proc(s: ^Semaphore) { - s.handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil); + s._handle = win32.CreateSemaphoreA(nil, 0, 1<<31-1, nil); } semaphore_destroy :: proc(s: ^Semaphore) { - win32.CloseHandle(s.handle); + win32.CloseHandle(s._handle); } semaphore_post :: proc(s: ^Semaphore, count: int) { - win32.ReleaseSemaphore(s.handle, cast(i32)count, nil); + win32.ReleaseSemaphore(s._handle, cast(i32)count, nil); } semaphore_release :: proc(s: ^Semaphore) #inline { semaphore_post(s, 1); } semaphore_wait :: proc(s: ^Semaphore) { - win32.WaitForSingleObject(s.handle, win32.INFINITE); + win32.WaitForSingleObject(s._handle, win32.INFINITE); } mutex_init :: proc(m: ^Mutex) { - atomic.store(^m.counter, 0); - atomic.store(^m.owner, current_thread_id()); - semaphore_init(^m.semaphore); - m.recursion = 0; + atomic.store(^m._counter, 0); + atomic.store(^m._owner, current_thread_id()); + semaphore_init(^m._semaphore); + m._recursion = 0; } mutex_destroy :: proc(m: ^Mutex) { - semaphore_destroy(^m.semaphore); + semaphore_destroy(^m._semaphore); } mutex_lock :: proc(m: ^Mutex) { thread_id := current_thread_id(); - if atomic.fetch_add(^m.counter, 1) > 0 { - if thread_id != atomic.load(^m.owner) { - semaphore_wait(^m.semaphore); + if atomic.fetch_add(^m._counter, 1) > 0 { + if thread_id != atomic.load(^m._owner) { + semaphore_wait(^m._semaphore); } } - atomic.store(^m.owner, thread_id); - m.recursion++; + atomic.store(^m._owner, thread_id); + m._recursion++; } mutex_try_lock :: proc(m: ^Mutex) -> bool { thread_id := current_thread_id(); - if atomic.load(^m.owner) == thread_id { - atomic.fetch_add(^m.counter, 1); + if atomic.load(^m._owner) == thread_id { + atomic.fetch_add(^m._counter, 1); } else { expected: i32 = 0; - if atomic.load(^m.counter) != 0 { + if atomic.load(^m._counter) != 0 { return false; } - if atomic.compare_exchange(^m.counter, expected, 1) == 0 { + if atomic.compare_exchange(^m._counter, expected, 1) == 0 { return false; } - atomic.store(^m.owner, thread_id); + atomic.store(^m._owner, thread_id); } - m.recursion++; + m._recursion++; return true; } mutex_unlock :: proc(m: ^Mutex) { recursion: i32; thread_id := current_thread_id(); - assert(thread_id == atomic.load(^m.owner)); + assert(thread_id == atomic.load(^m._owner)); - m.recursion--; - recursion = m.recursion; + m._recursion--; + recursion = m._recursion; if recursion == 0 { - atomic.store(^m.owner, thread_id); + atomic.store(^m._owner, thread_id); } - if atomic.fetch_add(^m.counter, -1) > 1 { + if atomic.fetch_add(^m._counter, -1) > 1 { if recursion == 0 { - semaphore_release(^m.semaphore); + semaphore_release(^m._semaphore); } } } diff --git a/core/sys/windows.odin b/core/sys/windows.odin index 6d6059214..708c9c84d 100644 --- a/core/sys/windows.odin +++ b/core/sys/windows.odin @@ -40,14 +40,19 @@ WS_CAPTION :: 0x00C00000; WS_VISIBLE :: 0x10000000; WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX; -WM_DESTROY :: 0x0002; -WM_SIZE :: 0x0005; -WM_CLOSE :: 0x0010; -WM_ACTIVATEAPP :: 0x001C; -WM_QUIT :: 0x0012; -WM_KEYDOWN :: 0x0100; -WM_KEYUP :: 0x0101; -WM_SIZING :: 0x0214; +WM_DESTROY :: 0x0002; +WM_SIZE :: 0x0005; +WM_CLOSE :: 0x0010; +WM_ACTIVATEAPP :: 0x001C; +WM_QUIT :: 0x0012; +WM_KEYDOWN :: 0x0100; +WM_KEYUP :: 0x0101; +WM_SIZING :: 0x0214; +WM_MOUSEWHEEL :: 0x020A; +WM_SYSKEYDOWN :: 0x0104; +WM_WINDOWPOSCHANGED :: 0x0047; +WM_SETCURSOR :: 0x0020; +WM_CHAR :: 0x0102; PM_REMOVE :: 1; @@ -300,6 +305,68 @@ ReadBarrier :: proc() #foreign kernel32; + + +HMONITOR :: HANDLE; + +GWL_STYLE :: -16; + +HWND_TOP :: cast(HWND)cast(uint)0; + +MONITOR_DEFAULTTONULL :: 0x00000000; +MONITOR_DEFAULTTOPRIMARY :: 0x00000001; +MONITOR_DEFAULTTONEAREST :: 0x00000002; + +SWP_FRAMECHANGED :: 0x0020; +SWP_NOOWNERZORDER :: 0x0200; +SWP_NOZORDER :: 0x0004; +SWP_NOSIZE :: 0x0001; +SWP_NOMOVE :: 0x0002; + + +MONITORINFO :: struct #ordered { + size: u32, + monitor: RECT, + work: RECT, + flags: u32, +} + +WINDOWPLACEMENT :: struct #ordered { + length: u32, + flags: u32, + show_cmd: u32, + min_pos: POINT, + max_pos: POINT, + normal_pos: RECT, +} + +GetMonitorInfoA :: proc(monitor: HMONITOR, mi: ^MONITORINFO) -> BOOL #foreign user32; +MonitorFromWindow :: proc(wnd: HWND, flags : u32) -> HMONITOR #foreign user32; + +SetWindowPos :: proc(wnd: HWND, wndInsertAfter: HWND, x, y, width, height: i32, flags: u32) #foreign user32 "SetWindowPos"; + +GetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32; +SetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32; + +GetWindowLongPtrA :: proc(wnd: HWND, index: i32) -> i64 #foreign user32; +SetWindowLongPtrA :: proc(wnd: HWND, index: i32, new: i64) -> i64 #foreign user32; + +GetWindowText :: proc(wnd: HWND, str: ^byte, maxCount: i32) -> i32 #foreign user32; + +HIWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)((cast(u32)wParam >> 16) & 0xffff); } +HIWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)((cast(u32)lParam >> 16) & 0xffff); } +LOWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)wParam; } +LOWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)lParam; } + + + + + + + + + + BITMAPINFOHEADER :: struct #ordered { size: u32, width, height: i32, diff --git a/src/check_expr.c b/src/check_expr.c index 0e166ef1a..7e273fba4 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -2918,9 +2918,9 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id err = "Too many"; } - if (err) { + if (err != NULL) { gbString expr = expr_to_string(ce->proc); - error(ce->close, "`%s` arguments for `%s`, expected %td, got %td", + error(ce->close, "%s arguments for `%s`, expected %td, got %td", err, expr, bp->arg_count, ce->args.count); gb_string_free(expr); @@ -2962,6 +2962,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } break; case BuiltinProc_new_slice: { // new_slice :: proc(Type, len: int) -> []Type + // new_slice :: proc(Type, len, cap: int) -> []Type Operand op = {0}; check_expr_or_type(c, &op, ce->args.e[0]); Type *type = op.type; @@ -2970,15 +2971,27 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id return false; } - check_expr(c, &op, ce->args.e[1]); - if (op.mode == Addressing_Invalid) { - return false; - } - if (!is_type_integer(op.type)) { - gbString type_str = type_to_string(op.type); - error_node(call, "Length for `new_slice` must be an integer, got `%s`", type_str); - gb_string_free(type_str); - return false; + isize arg_count = ce->args.count; + if (arg_count < 2 || 3 < arg_count) { + error_node(ce->args.e[0], "`new_slice` expects 2 or 3 arguments, found %td", arg_count); + // NOTE(bill): Return the correct type to reduce errors + } else { + // If any are constant + i64 sizes[2] = {0}; + isize size_count = 0; + for (isize i = 1; i < arg_count; i++) { + i64 val = 0; + bool ok = check_index_value(c, ce->args.e[i], -1, &val); + if (ok && val >= 0) { + GB_ASSERT(size_count < gb_count_of(sizes)); + sizes[size_count++] = val; + } + } + + if (size_count == 2 && sizes[0] > sizes[1]) { + error_node(ce->args.e[1], "`new_slice` count and capacity are swapped"); + // No need quit + } } operand->mode = Addressing_Value; @@ -3060,7 +3073,8 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id // append :: proc([dynamic]Type, item: ..Type) // append :: proc([]Type, item: ..Type) Type *type = operand->type; - type = base_type(type); + bool is_pointer = is_type_pointer(type); + type = base_type(type_deref(type)); if (!is_type_dynamic_array(type) && !is_type_slice(type)) { gbString str = type_to_string(type); error_node(operand->expr, "Expected a slice or dynamic array, got `%s`", str); @@ -3068,6 +3082,15 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id return false; } + bool is_addressable = operand->mode == Addressing_Variable; + if (is_pointer) { + is_addressable = true; + } + if (!is_addressable) { + error_node(operand->expr, "`append` can only operate on addressable values"); + return false; + } + Type *elem = NULL; Type *slice_elem = NULL; if (is_type_dynamic_array(type)) { diff --git a/src/checker.c b/src/checker.c index f2addf241..3acefdccd 100644 --- a/src/checker.c +++ b/src/checker.c @@ -68,7 +68,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { {STR_LIT(""), 0, false, Expr_Stmt}, {STR_LIT("new"), 1, false, Expr_Expr}, - {STR_LIT("new_slice"), 2, false, Expr_Expr}, + {STR_LIT("new_slice"), 2, true, Expr_Expr}, {STR_LIT("free"), 1, false, Expr_Stmt}, {STR_LIT("reserve"), 2, false, Expr_Stmt}, @@ -3168,7 +3168,8 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv case BuiltinProc_new_slice: { ir_emit_comment(proc, str_lit("new_slice")); - // new_slice :: proc(Type, len: int) -> ^Type + // new_slice :: proc(Type, len: int) -> []Type + // new_slice :: proc(Type, len, cap: int) -> []Type gbAllocator allocator = proc->module->allocator; Type *type = type_of_expr(proc->module->info, ce->args.e[0]); @@ -3182,10 +3183,15 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv irValue *elem_align = ir_make_const_int(allocator, a); irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int); + irValue *capacity = count; - ir_emit_slice_bounds_check(proc, ast_node_token(ce->args.e[1]), v_zero, count, count, false); + if (ce->args.count == 3) { + capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[2]), t_int); + } + + ir_emit_slice_bounds_check(proc, ast_node_token(ce->args.e[1]), v_zero, count, capacity, false); - irValue *slice_size = ir_emit_arith(proc, Token_Mul, elem_size, count, t_int); + irValue *slice_size = ir_emit_arith(proc, Token_Mul, elem_size, capacity, t_int); irValue **args = gb_alloc_array(allocator, irValue *, 2); args[0] = slice_size; @@ -3195,7 +3201,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv irValue *ptr = ir_emit_conv(proc, call, ptr_type); irValue *slice = ir_add_local_generated(proc, slice_type); - ir_fill_slice(proc, slice, ptr, count, count); + ir_fill_slice(proc, slice, ptr, count, capacity); return ir_emit_load(proc, slice); } break; @@ -3330,7 +3336,12 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv ir_emit_comment(proc, str_lit("append")); gbAllocator a = proc->module->allocator; - irValue *array_ptr = ir_build_addr(proc, ce->args.e[0]).addr; + Type *value_type = type_of_expr(proc->module->info, ce->args.e[0]); + irAddr array_addr = ir_build_addr(proc, ce->args.e[0]); + irValue *array_ptr = array_addr.addr; + if (is_type_pointer(value_type)) { + array_ptr = ir_addr_load(proc, array_addr); + } Type *type = ir_type(array_ptr); GB_ASSERT(is_type_pointer(type)); type = base_type(type_deref(type)); diff --git a/src/ir_print.c b/src/ir_print.c index 9bc7e5f41..cca26b925 100644 --- a/src/ir_print.c +++ b/src/ir_print.c @@ -664,6 +664,11 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { ir_fprintf(f, "\t"); switch (instr->kind) { + default: { + GB_PANIC("<unknown instr> %d\n", instr->kind); + ir_fprintf(f, "; <unknown instr> %d\n", instr->kind); + } break; + case irInstr_StartupRuntime: { ir_fprintf(f, "call void "); ir_print_encoded_global(f, str_lit(IR_STARTUP_RUNTIME_PROC_NAME), false); @@ -1281,12 +1286,6 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { ir_fprintf(f, "\n"); */ } break; - - - default: { - GB_PANIC("<unknown instr> %d\n", instr->kind); - ir_fprintf(f, "; <unknown instr> %d\n", instr->kind); - } break; } } diff --git a/src/types.c b/src/types.c index 0142fa227..362e949fb 100644 --- a/src/types.c +++ b/src/types.c @@ -1342,9 +1342,6 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n } } - if (type->kind != Type_Record) { - return sel; - } if (is_type) { if (type->kind == Type_Record) { if (type->Record.names != NULL && @@ -1395,7 +1392,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n } } } - } else { + } else if (type->kind == Type_Record) { for (isize i = 0; i < type->Record.field_count; i++) { Entity *f = type->Record.fields[i]; if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) { |