From: Brendan Hansen Date: Fri, 2 Jul 2021 03:47:20 +0000 (-0500) Subject: bugfixes; starting work on wasm module X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=330300c7626eaa4579bc9ea4331cb0d87a8b5339;p=onyx.git bugfixes; starting work on wasm module --- diff --git a/bin/onyx b/bin/onyx index 018c527e..592017b5 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/core/conv.onyx b/core/conv.onyx index cd020b69..842407d3 100644 --- a/core/conv.onyx +++ b/core/conv.onyx @@ -186,7 +186,7 @@ f64_to_str :: (f: f64, buf: [] u8) -> str { // This is better than the above version, but still relies on converting the integer // part of the float to an integer, which could overflow. -f64_to_str :: (f: f64, buf: [] u8) -> str { +f64_to_str :: (f: f64, buf: [] u8, digits_after_decimal := 4) -> str { math :: package core.math len := 0; @@ -208,15 +208,14 @@ f64_to_str :: (f: f64, buf: [] u8) -> str { digits := "0123456789"; - decimals :: 4; - for i: decimals { + for i: digits_after_decimal { dec_part *= 10; v := math.trunc(dec_part); dec_part -= v; buf.data[len + i] = digits[cast(i32) v]; } - len += decimals; + len += digits_after_decimal; return str.{ buf.data, len }; } @@ -226,7 +225,6 @@ str_format :: (format: str, buffer: [] u8, va: ..any) -> str { } str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str { - @Cleanup Output :: struct { data: ^u8; count: u32; @@ -241,7 +239,12 @@ str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str { }, (use output: ^Output, s: str) { - for c: s do output->write(c); + for c: s { + if count >= capacity do return; + + data[count] = c; + count += 1; + } } } } @@ -251,7 +254,6 @@ str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str { Format :: struct { digits_after_decimal := cast(u32) 4; } - formatting := Format.{}; vararg_index := 0; @@ -259,6 +261,7 @@ str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str { defer i += 1; ch := format[i]; + formatting := Format.{}; if ch == #char "{" { if format[i + 1] == #char "{" { @@ -267,8 +270,8 @@ str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str { continue; } + i += 1; while true { - i += 1; ch = format[i]; switch ch { @@ -282,6 +285,7 @@ str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str { i += 1; } + ch = format[i]; formatting.digits_after_decimal = digits; } @@ -299,7 +303,7 @@ str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str { arg := va[vararg_index]; vararg_index += 1; - print_any(^output, arg); + print_any(^output, formatting, arg); continue; } @@ -309,7 +313,7 @@ str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str { return .{ output.data, output.count }; - print_any :: (output: ^Output, v: any) { + print_any :: (output: ^Output, formatting: Format, v: any) { use package builtin.type_info array :: package core.array @@ -320,6 +324,19 @@ str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str { else do output->write("false"); } + case u8 { + value := *(cast(^u8) v.data); + + if value > 31 { + output->write(value); + + } else { + ibuf : [128] u8; + istr := i64_to_str(~~value, 16, ~~ibuf); + output->write(istr); + } + } + case i32, u32 { value := *(cast(^i32) v.data); @@ -340,7 +357,7 @@ str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str { value := *(cast(^f32) v.data); fbuf : [128] u8; - fstr := f64_to_str(~~value, ~~fbuf); + fstr := f64_to_str(~~value, ~~fbuf, formatting.digits_after_decimal); output->write(fstr); } @@ -348,7 +365,7 @@ str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str { value := *(cast(^f64) v.data); fbuf : [128] u8; - fstr := f64_to_str(~~value, ~~fbuf); + fstr := f64_to_str(~~value, ~~fbuf, formatting.digits_after_decimal); output->write(fstr); } @@ -377,13 +394,23 @@ str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str { output->write(member.name); output->write(" = "); - print_any(output, .{ ~~(cast(^u8) v.data + member.offset), member.type }); + print_any(output, formatting, .{ ~~(cast(^u8) v.data + member.offset), member.type }); } output->write(" }"); } - if info.kind == .Function do output->write(""); + if info.kind == .Function { + output->write("func["); + + value := *(cast(^i32) v.data); + + ibuf : [128] u8; + istr := i64_to_str(~~value, 10, ~~ibuf); + output->write(istr); + + output->write("]"); + } if info.kind == .Pointer { value := *(cast(^rawptr) v.data); @@ -405,7 +432,7 @@ str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str { for i: count { if i != 0 do output->write(", "); - print_any(output, .{ ~~(cast(^u8) data + get_type_info(a.of).size * i), a.of }); + print_any(output, formatting, .{ ~~(cast(^u8) data + get_type_info(a.of).size * i), a.of }); } output->write(" ]"); @@ -420,7 +447,7 @@ str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str { for i: a.count { if i != 0 do output->write(", "); - print_any(output, .{ ~~(cast(^u8) data + get_type_info(a.of).size * i), a.of }); + print_any(output, formatting, .{ ~~(cast(^u8) data + get_type_info(a.of).size * i), a.of }); } output->write(" ]"); diff --git a/core/io/reader.onyx b/core/io/reader.onyx index 943d360b..4367566e 100644 --- a/core/io/reader.onyx +++ b/core/io/reader.onyx @@ -24,10 +24,17 @@ read_byte :: (use reader: ^Reader) -> u8 { return byte; } -read_bytes :: (use reader: ^Reader, bytes := 1, allocator := context.allocator) -> str { - buffer := memory.make_slice(u8, bytes, allocator); - stream_read(stream, buffer); - return buffer; +read_bytes :: #match { + (use reader: ^Reader, bytes := 1, allocator := context.allocator) -> str { + buffer := memory.make_slice(u8, bytes, allocator); + stream_read(stream, buffer); + return buffer; + }, + + (use reader: ^Reader, bytes: [] u8) -> str { + err, bytes_read := stream_read(stream, bytes); + return bytes; + } } read_u32 :: (use reader: ^Reader) -> u32 { @@ -192,4 +199,4 @@ skip_whitespace :: (use reader: ^Reader) { skip_bytes :: (use reader: ^Reader, bytes: u32) { for _: bytes do stream_read_byte(stream); -} \ No newline at end of file +} diff --git a/modules/js_events/js_events.onyx b/modules/js_events/js_events.onyx index ec441cb8..ae73ff9b 100644 --- a/modules/js_events/js_events.onyx +++ b/modules/js_events/js_events.onyx @@ -95,20 +95,20 @@ init :: () { event_setup(^event_storage, sizeof Event); } -consume :: () -> Iterator(Event) { - next :: (_: rawptr) -> (Event, bool) { - use package core.intrinsics.onyx { __zero_value } - if event_storage.event_count == 0 do return __zero_value(Event), false; +#private_file processing_event: Event +consume :: () -> Iterator(^Event) { + next :: (_: rawptr) -> (^Event, bool) { + if event_storage.event_count == 0 do return null, false; @CodeGeneration // This instruction (and all instructions involving Event) generate a TON of instructions because Event is a union. - event := event_storage.event_buffer[0]; + processing_event := event_storage.event_buffer[0]; for i: 0 .. Num_Buffered_Events - 2 { event_storage.event_buffer[i] = event_storage.event_buffer[i + 1]; } event_storage.event_count -= 1; - return event, true; + return ^processing_event, true; } return .{ null, next }; diff --git a/modules/wasm_utils/module.onyx b/modules/wasm_utils/module.onyx new file mode 100644 index 00000000..7d8a471c --- /dev/null +++ b/modules/wasm_utils/module.onyx @@ -0,0 +1,14 @@ +/* + +WebAssembly 32-bit disassembly and decompiler utils + +*/ + +package wasm_utils + +#load "./types" +#load "./utils" + +#private map :: package core.map +#private io :: package core.io +#private hash :: package core.hash diff --git a/modules/wasm_utils/types.onyx b/modules/wasm_utils/types.onyx new file mode 100644 index 00000000..e4b5f748 --- /dev/null +++ b/modules/wasm_utils/types.onyx @@ -0,0 +1,91 @@ +package wasm_utils + +WasmSection :: enum { + Custom :: 0x00; + Type :: 0x01; + Import :: 0x02; + Function :: 0x03; + Table :: 0x04; + Memory :: 0x05; + Global :: 0x06; + Export :: 0x07; + Start :: 0x08; + Element :: 0x09; + Code :: 0x0a; + Data :: 0x0b; + DataCount :: 0x0c; +} + +#add_match hash.to_u32, (w: WasmSection) -> u32 { + return hash.to_u32(cast(u32) w); +} + +WasmBinary :: struct { + data: [] u8; + + // Section number -> Offset into data + // This does not work for custom sections, as they all have the same section number + section_locations : map.Map(WasmSection, i32); + + // So there is a custom section location that maps the name of the custom section + // to the offset into the file. The backing-store for the keys is just the data + // itself, as the names are in the data for the binary. + custom_section_locations : map.Map(str, i32); +} + +load :: (data: [] u8, allocator := context.allocator) -> WasmBinary { + binary: WasmBinary; + binary.data = data; + + #context_scope { + context.allocator = allocator; + map.init(^binary.section_locations, -1); + map.init(^binary.custom_section_locations, -1); + } + + assert(parse_section_locations(^binary), "Failed to parse WASM binary"); + + return binary; +} + + +#private_file +parse_section_locations :: (use bin: ^WasmBinary) -> bool { + stream := io.string_stream_make(data); + reader := io.reader_make(^stream); + + { + // Checking the magic string + magic_buffer: [4] u8; + + if !(io.read_bytes(^reader, cast([] u8) magic_buffer) == ~~u8.[ 0, #char "a", #char "s", #char "m" ]) do return false; + if !(io.read_bytes(^reader, cast([] u8) magic_buffer) == ~~u8.[ 1, 0, 0, 0 ]) do return false; // This may not be necessary + } + + while !io.stream_end_of_file(^stream) { + section_number := cast(WasmSection) io.read_byte(^reader); + section_size := read_uleb128(^reader); + _, pos := io.stream_tell(^stream); + + switch section_number { + @Incomplete + case .Custom --- + + case .Type, .Import, .Function, .Table, .Memory, .Global, + .Export, .Start, .Element, .Code, .Data, .DataCount { + map.put(^section_locations, section_number, pos); + } + + case #default { + buffer: [128] u8; + conv :: package core.conv + assert(false, conv.str_format("Bad section number {}", ~~buffer, cast(i32) section_number)); + } + } + + err := io.stream_seek(^stream, pos + ~~section_size, .Start); + if err == .OutOfBounds do break; + } + + return true; +} diff --git a/modules/wasm_utils/utils.onyx b/modules/wasm_utils/utils.onyx new file mode 100644 index 00000000..326da066 --- /dev/null +++ b/modules/wasm_utils/utils.onyx @@ -0,0 +1,39 @@ +package wasm_utils + +#private_file io :: package core.io + +#private +read_uleb128 :: (use reader: ^io.Reader) -> u64 { + result: u64 = 0; + shift := 0; + byte: u8; + + while true { + byte = io.read_byte(reader); + result |= ~~((byte & 127) << ~~shift); + if (byte & 128) == 0 do break; + + shift += 7; + } + + return result; +} + +#private +read_sleb128 :: (use reader: ^io.Reader, size := 4) -> i64 { + result: i64 = 0; + shift := 0; + byte: u8 = 128; + + while (byte & 128) != 0 { + byte = io.read_byte(reader); + result |= ~~((byte & 127) << ~~shift); + shift += 7; + } + + if (shift < size) && (byte & 64) > 0 { + result |= 0xFFFFFFFFFFFFFFFF << ~~shift; + } + + return result; +} diff --git a/src/onyxtypes.c b/src/onyxtypes.c index 36fc57bf..58734c65 100644 --- a/src/onyxtypes.c +++ b/src/onyxtypes.c @@ -484,6 +484,9 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) { AstPolyCallType* pc_type = (AstPolyCallType *) type_node; if (!(pc_type->callee && pc_type->callee->kind == Ast_Kind_Poly_Struct_Type)) { + // If it is an unresolved field access, just return because an error will be printed elsewhere. + if (pc_type->callee->kind == Ast_Kind_Field_Access) return NULL; + onyx_report_error(pc_type->token->pos, "Cannot instantiate a concrete type off of a non-polymorphic type."); return NULL; } diff --git a/tests/new_printf b/tests/new_printf index 3442358f..08594c78 100644 --- a/tests/new_printf +++ b/tests/new_printf @@ -1 +1 @@ -123 Test { } false 0x4E8 +123 Test {} false 12.3 12.34567 diff --git a/tests/new_printf.onyx b/tests/new_printf.onyx index c53077ad..cf188d54 100644 --- a/tests/new_printf.onyx +++ b/tests/new_printf.onyx @@ -3,5 +3,5 @@ use package core main :: (args: [] cstr) { - printf("{} {} {{ }} {} {}\n", 123, "Test", false, ^stdio.print_writer); + printf("{} {} {{}} {} {.1} {.5}\n", 123, "Test", false, 12.34, 12.3456789); }