// 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;
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 };
}
}
str_format_va :: (format: str, buffer: [] u8, va: [] any) -> str {
- @Cleanup
Output :: struct {
data: ^u8;
count: u32;
},
(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;
+ }
}
}
}
Format :: struct {
digits_after_decimal := cast(u32) 4;
}
- formatting := Format.{};
vararg_index := 0;
defer i += 1;
ch := format[i];
+ formatting := Format.{};
if ch == #char "{" {
if format[i + 1] == #char "{" {
continue;
}
+ i += 1;
while true {
- i += 1;
ch = format[i];
switch ch {
i += 1;
}
+ ch = format[i];
formatting.digits_after_decimal = digits;
}
arg := va[vararg_index];
vararg_index += 1;
- print_any(^output, arg);
+ print_any(^output, formatting, arg);
continue;
}
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
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);
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);
}
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);
}
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("<function>");
+ 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);
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(" ]");
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(" ]");
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 {
skip_bytes :: (use reader: ^Reader, bytes: u32) {
for _: bytes do stream_read_byte(stream);
-}
\ No newline at end of file
+}
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 };
--- /dev/null
+/*
+
+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
--- /dev/null
+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;
+}
--- /dev/null
+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;
+}
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;
}
-123 Test { } false 0x4E8
+123 Test {} false 12.3 12.34567
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);
}