From d907df14dd05c182fec645ce33e22de6f6b6f513 Mon Sep 17 00:00:00 2001 From: koniifer Date: Tue, 17 Dec 2024 02:06:48 +0000 Subject: [PATCH] primitive string formatter with struct & array support --- Cargo.lock | 6 +- sysdata/libraries/stn/src/formatters.hb | 146 ++++++++++++++++++ sysdata/libraries/stn/src/lib.hb | 1 + sysdata/libraries/stn/src/math.hb | 4 +- .../render_example/src/examples/mandelbrot.hb | 6 + sysdata/programs/test/src/main.hb | 2 +- .../programs/test/src/tests/stn/formatters.hb | 25 +++ sysdata/programs/test/src/tests/stn/lib.hb | 3 +- sysdata/system_config.toml | 23 +-- 9 files changed, 199 insertions(+), 17 deletions(-) create mode 100644 sysdata/libraries/stn/src/formatters.hb create mode 100644 sysdata/programs/test/src/tests/stn/formatters.hb diff --git a/Cargo.lock b/Cargo.lock index b37d780..dfd1f73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -213,12 +213,12 @@ dependencies = [ [[package]] name = "hbbytecode" version = "0.1.0" -source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#c0d957e70c7146f2c788a7b410632a940a18768f" +source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#945e5c70f6cb20a77fbb654a0ab6bef7d2b25aac" [[package]] name = "hblang" version = "0.1.0" -source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#c0d957e70c7146f2c788a7b410632a940a18768f" +source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#945e5c70f6cb20a77fbb654a0ab6bef7d2b25aac" dependencies = [ "hashbrown", "hbbytecode", @@ -229,7 +229,7 @@ dependencies = [ [[package]] name = "hbvm" version = "0.1.0" -source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#c0d957e70c7146f2c788a7b410632a940a18768f" +source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#945e5c70f6cb20a77fbb654a0ab6bef7d2b25aac" dependencies = [ "hbbytecode", ] diff --git a/sysdata/libraries/stn/src/formatters.hb b/sysdata/libraries/stn/src/formatters.hb new file mode 100644 index 0000000..cfc4189 --- /dev/null +++ b/sysdata/libraries/stn/src/formatters.hb @@ -0,0 +1,146 @@ +.{string, primitive, unsigned_int, signed_int, float, integer, memory, panic} := @use("stn") + +format_int := fn($T: type, v: T, str: ^u8): uint { + if integer(T) { + is_negative := signed_int(T) & v < 0 + i := 0 + if is_negative v = -v + + if v == 0 { + *str = '0' + return 1 + } + + loop if v == 0 break else { + remainder := v % 10 + v /= 10; + *(str + i) = @intcast(remainder + '0') + i += 1 + } + + if is_negative { + *(str + i) = '-' + i += 1 + } + + @inline(string.reverse, str) + return i + } else { + panic("Type is not an integer\0") + } +} + +format_bool := fn(v: bool, str: ^u8): uint { + if v { + memory.copy(u8, "true\0", str, 4) + return 4 + } else { + memory.copy(u8, "false\0", str, 5) + return 5 + } +} + +format_float := fn($T: type, v: T, str: ^u8, precision: uint): uint { + if float(T) { + is_negative := v < 0 + i := 0 + + if is_negative v = -v + + integer_part := @fti(v) + fractional_part := v - @itf(integer_part) + + loop if integer_part == 0 & i > 0 break else { + remainder := integer_part % 10 + integer_part /= 10; + *(str + i) = @intcast(remainder + '0') + i += 1 + } + + if is_negative { + *(str + i) = '-' + i += 1 + } + + @inline(string.reverse, str); + *(str + i) = '.' + i += 1 + + tolerance := @as(T, 0.000000001) + p := precision + loop if p <= 0 | fractional_part < tolerance break else { + fractional_part *= 10.0 + digit := @fti(fractional_part); + *(str + i) = @intcast(digit + '0') + i += 1 + fractional_part -= @itf(digit) + p -= 1 + } + + return i + } else { + panic("Type is not a floating point\0") + } +} + +format_inner := fn($T: type, v: T, str: ^u8, opts: FormatOptions): uint { + if integer(T) { + return @inline(format_int, T, v, str) + } else if T == bool { + return @inline(format_bool, v, str) + } else if float(T) { + return @inline(format_float, T, v, str, opts.decimal_digits) + } else { + i := 0 + // name := @nameof(T) + // len := string.length(name) + // memory.copy(u8, name, str, len) + len := 0 + memory.copy(u8, ".(\0", str + len, 2) + len += 2 + $loop if i == @len(T) break else { + v_sub := v[i] + TSub := @TypeOf(v_sub) + len += @inline(format_inner, TSub, v_sub, str + len, opts) + if i != @len(T) - 1 { + memory.copy(u8, ", \0", str + len, 2) + len += 2 + } else { + memory.copy(u8, ")\0", str + len, 1) + len += 1 + } + i += 1 + } + return len + } + panic("Unsupported formatter type\0") +} + +/* TODO: +* Custom formatters using struct methods (T._fmt(self, str): uint), +* Format struct names "Name.(x, y, z)" +* Format struct fields "Name.{a: x, b: y, c: z}" +* Optimise (so many instructions...) +* -> Consider switching `memory.copy` to loop for comptime stuff +* Optionally tabulate +* Add more FormatOption fields +* Support radices for integers +* Support scientific notation for floating point +* Support format string (impossible right now) +* Support nullables (impossible right now) +* Support pointers +*/ + +FormatOptions := struct { + decimal_digits: uint, +} + +$DEFAULT_OPTS := FormatOptions.(2) + +format := fn($T: type, v: T, str: ^u8): ^u8 return @inline(format_args, T, v, str, DEFAULT_OPTS) + +format_args := fn($T: type, v: T, str: ^u8, opts: FormatOptions): ^u8 { + @inline(string.clear, str) + _ = @inline(format_inner, T, v, str, opts) + return str +} \ No newline at end of file diff --git a/sysdata/libraries/stn/src/lib.hb b/sysdata/libraries/stn/src/lib.hb index 90b68b7..cd00b85 100644 --- a/sysdata/libraries/stn/src/lib.hb +++ b/sysdata/libraries/stn/src/lib.hb @@ -1,5 +1,6 @@ acs := @use("acs.hb") allocators := @use("alloc/lib.hb") +formatters := @use("formatters.hb") hashers := @use("hash/lib.hb") string := @use("string.hb") log := @use("log.hb") diff --git a/sysdata/libraries/stn/src/math.hb b/sysdata/libraries/stn/src/math.hb index b967579..55fca82 100644 --- a/sysdata/libraries/stn/src/math.hb +++ b/sysdata/libraries/stn/src/math.hb @@ -77,7 +77,7 @@ TAN_TABLE := [f32].(0.0, 0.01227246237956628, 0.02454862210892544, 0.03683218099 $TABLE_SIZE := @sizeof(@TypeOf(SIN_TABLE)) / @sizeof(f32) sin := fn(theta: f32): f32 { - si := @fti(theta * 0.5 * @itf(TABLE_SIZE) / PI) + si := @fti(theta * 0.5 * TABLE_SIZE / PI) d := theta - @itf(si) * 2.0 * PI / TABLE_SIZE ci := si + TABLE_SIZE / 4 & TABLE_SIZE - 1 si &= TABLE_SIZE - 1 @@ -85,7 +85,7 @@ sin := fn(theta: f32): f32 { } cos := fn(theta: f32): f32 { - ci := @fti(theta * 0.5 * @itf(TABLE_SIZE) / PI) + ci := @fti(theta * 0.5 * TABLE_SIZE / PI) d := theta - @itf(ci) * 2.0 * PI / TABLE_SIZE si := ci + TABLE_SIZE / 4 & TABLE_SIZE - 1 ci &= TABLE_SIZE - 1 diff --git a/sysdata/programs/render_example/src/examples/mandelbrot.hb b/sysdata/programs/render_example/src/examples/mandelbrot.hb index b88805f..46c8281 100644 --- a/sysdata/programs/render_example/src/examples/mandelbrot.hb +++ b/sysdata/programs/render_example/src/examples/mandelbrot.hb @@ -14,6 +14,12 @@ $X_MAX := -0.93 $Y_MIN := 0.31 $Y_MAX := 0.306 +// zoom into that weird curve part of the main cardioid +// $X_MIN := 0.25 +// $X_MAX := 0.34 +// $Y_MIN := -0.075 +// $Y_MAX := 0.075 + $MAX_ITERATION := 300 $USE_SUNSET := true diff --git a/sysdata/programs/test/src/main.hb b/sysdata/programs/test/src/main.hb index debec4e..f4421ba 100644 --- a/sysdata/programs/test/src/main.hb +++ b/sysdata/programs/test/src/main.hb @@ -3,5 +3,5 @@ serial_driver := @use("./tests/serial_driver.hb") main := fn(): uint { // return serial_driver.test() - return stn.sleep.test() + return stn.formatters.test() } \ No newline at end of file diff --git a/sysdata/programs/test/src/tests/stn/formatters.hb b/sysdata/programs/test/src/tests/stn/formatters.hb new file mode 100644 index 0000000..77b5409 --- /dev/null +++ b/sysdata/programs/test/src/tests/stn/formatters.hb @@ -0,0 +1,25 @@ +.{formatters: .{format, format_args}, log, memory, math} := @use("stn"); +.{Color} := @use("lib:render") + +Thingy := struct { + a: uint, + b: int, + c: SubThingy, +} + +SubThingy := struct { + a: f32, + b: bool, +} + +test := fn(): uint { + buffer := memory.request_page(1) + log.info(format(Thingy, .(-100, -100, .(-math.PI, true)), buffer)) + log.info(format(SubThingy, .(-math.E, false), buffer)) + log.info(format(Color, .{r: 1, g: 2, b: 3, a: 4}, buffer)) + // default value: .{decimal_digits: 2} + log.info(format_args(f64, math.LN_2, buffer, .{decimal_digits: 1 << 32})) + log.info(format([u8; 3], .(1, 2, 3), buffer)) + + return 0 +} \ No newline at end of file diff --git a/sysdata/programs/test/src/tests/stn/lib.hb b/sysdata/programs/test/src/tests/stn/lib.hb index da08b77..8aaa8ca 100644 --- a/sysdata/programs/test/src/tests/stn/lib.hb +++ b/sysdata/programs/test/src/tests/stn/lib.hb @@ -2,4 +2,5 @@ hashers := @use("./hashers.hb") allocators := @use("./allocators.hb") sleep := @use("./sleep.hb") dt := @use("./dt.hb") -process := @use("./process.hb") \ No newline at end of file +process := @use("./process.hb") +formatters := @use("./formatters.hb") \ No newline at end of file diff --git a/sysdata/system_config.toml b/sysdata/system_config.toml index aded1e2..49e94d7 100644 --- a/sysdata/system_config.toml +++ b/sysdata/system_config.toml @@ -23,13 +23,14 @@ resolution = "1024x768x24" [boot.limine.ableos.modules] -[boot.limine.ableos.modules.render_example] -path = "boot:///render_example.hbf" -[boot.limine.ableos.modules.sunset_server] -path = "boot:///sunset_server.hbf" +# [boot.limine.ableos.modules.render_example] +# path = "boot:///render_example.hbf" -[boot.limine.ableos.modules.ps2_mouse_driver] -path = "boot:///ps2_mouse_driver.hbf" +# [boot.limine.ableos.modules.sunset_server] +# path = "boot:///sunset_server.hbf" + +# [boot.limine.ableos.modules.ps2_mouse_driver] +# path = "boot:///ps2_mouse_driver.hbf" # [boot.limine.ableos.modules.ps2_keyboard_driver] # path = "boot:///ps2_keyboard_driver.hbf" @@ -40,12 +41,14 @@ path = "boot:///ps2_mouse_driver.hbf" # [boot.limine.ableos.modules.sunset_client_2] # path = "boot:///sunset_client_2.hbf" -[boot.limine.ableos.modules.ablefetch] -path = "boot:///ablefetch.hbf" +# [boot.limine.ableos.modules.ablefetch] +# path = "boot:///ablefetch.hbf" # [boot.limine.ableos.modules.diskio_driver] # path = "boot:///diskio_driver.hbf" +# [boot.limine.ableos.modules.angels_halo] +# path = "boot:///angels_halo.hbf" -#[boot.limine.ableos.modules.angels_halo] -#path = "boot:///angels_halo.hbf" +[boot.limine.ableos.modules.test] +path = "boot:///test.hbf"