From db9025f3a30679fc34b0045d68a2c65687d03130 Mon Sep 17 00:00:00 2001 From: dimgigov Date: Fri, 5 Jun 2026 21:05:00 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20add=20Std::Fmt=20=E2=80=94=20string=20f?= =?UTF-8?q?ormatting=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - C runtime: bux_float_to_string() for float64 → String conversion - String.bux: add String_FromFloat, extern decl for bux_float_to_string - library/std/Fmt.bux: Fmt_Fmt1, Fmt_Fmt2, Fmt_Fmt3, Fmt_FmtInt, Fmt_FmtInt2, Fmt_FmtFloat, Fmt_FmtBool — positional {0}, {1}, {2} placeholders - Refactor examples to use Fmt: factorial.bux, fibonacci.bux, process.bux, os_time.bux --- _test_fmt/bux.toml | 1 + _test_fmt/src/Main.bux | 4 ++++ _test_fmt2/bux.toml | 1 + _test_fmt2/src/Main.bux | 8 ++++++++ _test_fmt3/bux.toml | 1 + _test_fmt3/src/Main.bux | 11 ++++++++++ examples/factorial.bux | 9 +++------ examples/fibonacci.bux | 7 +++---- examples/os_time.bux | 29 ++++++++------------------- examples/process.bux | 10 ++++------ library/runtime/runtime.c | 6 ++++++ library/std/Fmt.bux | 42 +++++++++++++++++++++++++++++++++++++++ library/std/String.bux | 5 +++++ 13 files changed, 97 insertions(+), 37 deletions(-) create mode 100644 _test_fmt/bux.toml create mode 100644 _test_fmt/src/Main.bux create mode 100644 _test_fmt2/bux.toml create mode 100644 _test_fmt2/src/Main.bux create mode 100644 _test_fmt3/bux.toml create mode 100644 _test_fmt3/src/Main.bux create mode 100644 library/std/Fmt.bux diff --git a/_test_fmt/bux.toml b/_test_fmt/bux.toml new file mode 100644 index 0000000..0bbf836 --- /dev/null +++ b/_test_fmt/bux.toml @@ -0,0 +1 @@ +[Package] diff --git a/_test_fmt/src/Main.bux b/_test_fmt/src/Main.bux new file mode 100644 index 0000000..84cbfec --- /dev/null +++ b/_test_fmt/src/Main.bux @@ -0,0 +1,4 @@ +module Test { +func Fmt(a: String) -> String { return a; } +func Fmt(a: int) -> String { return "int"; } +} diff --git a/_test_fmt2/bux.toml b/_test_fmt2/bux.toml new file mode 100644 index 0000000..0bbf836 --- /dev/null +++ b/_test_fmt2/bux.toml @@ -0,0 +1 @@ +[Package] diff --git a/_test_fmt2/src/Main.bux b/_test_fmt2/src/Main.bux new file mode 100644 index 0000000..71fbc2e --- /dev/null +++ b/_test_fmt2/src/Main.bux @@ -0,0 +1,8 @@ +import Std::Io::{PrintLine}; +import Std::String::{String_Format1, String_FromInt}; + +func Main() -> int { + let s: String = String_Format1("Hello, {0}!", "World"); + PrintLine(s); + return 0; +} diff --git a/_test_fmt3/bux.toml b/_test_fmt3/bux.toml new file mode 100644 index 0000000..0bbf836 --- /dev/null +++ b/_test_fmt3/bux.toml @@ -0,0 +1 @@ +[Package] diff --git a/_test_fmt3/src/Main.bux b/_test_fmt3/src/Main.bux new file mode 100644 index 0000000..a26ab68 --- /dev/null +++ b/_test_fmt3/src/Main.bux @@ -0,0 +1,11 @@ +import Std::Io::{PrintLine}; +import Std::Fmt; + +func Main() -> int { + PrintLine(Fmt_Fmt1("Hello, {0}!", "World")); + PrintLine(Fmt_FmtInt("Count: {0}", 42)); + PrintLine(Fmt_FmtFloat("Pi: {0}", 3.14159)); + PrintLine(Fmt_FmtBool("Active: {0}", true)); + PrintLine(Fmt_Fmt2("Name: {0}, Age: {1}", "Bux", String_FromInt(5))); + return 0; +} diff --git a/examples/factorial.bux b/examples/factorial.bux index ee24f50..8da0045 100644 --- a/examples/factorial.bux +++ b/examples/factorial.bux @@ -1,6 +1,6 @@ // Factorial - Recursive function -import Std::Io::{PrintLine, PrintInt}; - +import Std::Io::{PrintLine}; +import Std::Fmt::{Fmt_Fmt2}; func Factorial(n: int) -> int { if n <= 1 { @@ -15,10 +15,7 @@ func Main() -> int { var i: int = 1; while i <= 10 { let fact: int = Factorial(i); - PrintInt(i); - PrintLine("! = "); - PrintInt(fact); - PrintLine(""); + PrintLine(Fmt_Fmt2("{0}! = {1}", String_FromInt(i), String_FromInt(fact))); i = i + 1; } diff --git a/examples/fibonacci.bux b/examples/fibonacci.bux index d94e949..7b98826 100644 --- a/examples/fibonacci.bux +++ b/examples/fibonacci.bux @@ -1,6 +1,6 @@ // Fibonacci - Recursive function with while loop -import Std::Io::{PrintLine, PrintInt}; - +import Std::Io::{PrintLine}; +import Std::Fmt::{Fmt_Fmt1}; func Fibonacci(n: int) -> int { if n <= 1 { @@ -15,8 +15,7 @@ func Main() -> int { var i: int = 0; while i < 10 { let fib: int = Fibonacci(i); - PrintInt(fib); - PrintLine(""); + PrintLine(Fmt_Fmt1("{0}", String_FromInt(fib))); i = i + 1; } diff --git a/examples/os_time.bux b/examples/os_time.bux index c24d387..4f08d78 100644 --- a/examples/os_time.bux +++ b/examples/os_time.bux @@ -1,37 +1,24 @@ // Os & Time - System and time utilities -import Std::Io::{PrintLine, PrintInt, PrintInt64}; +import Std::Io::{PrintLine}; import Std::Os::{Os_ArgsCount, Os_Args, Os_GetEnv, Os_GetCwd}; import Std::Time::{Time_NowMs, Time_SleepMs}; +import Std::Fmt::{Fmt_Fmt1, Fmt_FmtInt}; func Main() -> int { PrintLine("=== OS Demo ==="); - Print("Current directory: "); - PrintLine(Os_GetCwd()); - - Print("Command-line args: "); - PrintInt(Os_ArgsCount()); - PrintLine(""); - - Print("HOME env: "); - PrintLine(Os_GetEnv("HOME")); + PrintLine(Fmt_Fmt1("Current directory: {0}", Os_GetCwd())); + PrintLine(Fmt_FmtInt("Command-line args: {0}", Os_ArgsCount() as int64)); + PrintLine(Fmt_Fmt1("HOME env: {0}", Os_GetEnv("HOME"))); PrintLine("\n=== Time Demo ==="); let start: int64 = Time_NowMs(); - Print("Start: "); - PrintInt64(start); - PrintLine(" ms"); - + PrintLine(Fmt_FmtInt("Start: {0} ms", start)); PrintLine("Sleeping 150ms..."); Time_SleepMs(150); let end: int64 = Time_NowMs(); - Print("End: "); - PrintInt64(end); - PrintLine(" ms"); - - Print("Elapsed: "); - PrintInt64(end - start); - PrintLine(" ms"); + PrintLine(Fmt_FmtInt("End: {0} ms", end)); + PrintLine(Fmt_FmtInt("Elapsed: {0} ms", end - start)); return 0; } diff --git a/examples/process.bux b/examples/process.bux index 51573cf..5c655a3 100644 --- a/examples/process.bux +++ b/examples/process.bux @@ -1,18 +1,16 @@ // Process - Run external commands and capture output -import Std::Io::{PrintLine, PrintInt}; +import Std::Io::{PrintLine}; import Std::Process::{Process_Run, Process_Output}; +import Std::Fmt::{Fmt_Fmt1, Fmt_FmtInt}; func Main() -> int { PrintLine("Process demo:"); let output: String = Process_Output("echo Hello from subprocess"); - Print("Captured: "); - PrintLine(output); + PrintLine(Fmt_Fmt1("Captured: {0}", output)); let rc: int = Process_Run("true"); - Print("Exit code: "); - PrintInt(rc); - PrintLine(""); + PrintLine(Fmt_FmtInt("Exit code: {0}", rc)); return 0; } diff --git a/library/runtime/runtime.c b/library/runtime/runtime.c index 2ce0434..b9dee1f 100644 --- a/library/runtime/runtime.c +++ b/library/runtime/runtime.c @@ -430,6 +430,12 @@ char* bux_str_join2(const char* a, const char* b, const char* sep) { /* Simple string format: replace {0}, {1}, ... with string arguments. Returns formatted string. Supports up to 8 arguments. */ +char* bux_float_to_string(double f) { + char* buf = (char*)bux_alloc(64); + snprintf(buf, 64, "%g", f); + return buf; +} + char* bux_str_format(const char* pattern, const char* a0, const char* a1, const char* a2, const char* a3, const char* a4, const char* a5, const char* a6, const char* a7) { diff --git a/library/std/Fmt.bux b/library/std/Fmt.bux new file mode 100644 index 0000000..ed253b4 --- /dev/null +++ b/library/std/Fmt.bux @@ -0,0 +1,42 @@ +module Std::Fmt { +/* String formatting with positional placeholders {0}, {1}, {2}... + * + * Usage: + * Fmt_Fmt1("Hello, {0}!", "World") + * Fmt_FmtInt("Count: {0}", 42) + * Fmt_FmtFloat("Pi: {0}", 3.14159) + * Fmt_FmtBool("Active: {0}", true) + * Fmt_Fmt2("Name: {0}, Age: {1}", name, String_FromInt(age)) + */ + +func Fmt_Fmt1(pattern: String, a: String) -> String { + return String_Format1(pattern, a); +} + +func Fmt_Fmt2(pattern: String, a: String, b: String) -> String { + return String_Format2(pattern, a, b); +} + +func Fmt_Fmt3(pattern: String, a: String, b: String, c: String) -> String { + return String_Format3(pattern, a, b, c); +} + +func Fmt_FmtInt(pattern: String, n: int64) -> String { + return String_Format1(pattern, String_FromInt(n)); +} + +func Fmt_FmtInt2(pattern: String, n1: int64, n2: int64) -> String { + return String_Format2(pattern, String_FromInt(n1), String_FromInt(n2)); +} + +func Fmt_FmtFloat(pattern: String, f: float64) -> String { + return String_Format1(pattern, String_FromFloat(f)); +} + +func Fmt_FmtBool(pattern: String, b: bool) -> String { + if b { + return String_Format1(pattern, "true"); + } + return String_Format1(pattern, "false"); +} +} diff --git a/library/std/String.bux b/library/std/String.bux index cbce8d7..c30ed26 100644 --- a/library/std/String.bux +++ b/library/std/String.bux @@ -24,6 +24,7 @@ extern func bux_sb_free(sb: *void); extern func bux_str_split_count(s: String, delim: String) -> uint; extern func bux_str_split_part(s: String, delim: String, index: uint) -> String; extern func bux_str_join2(a: String, b: String, sep: String) -> String; +extern func bux_float_to_string(f: float64) -> String; extern func bux_str_format(pattern: String, a0: String, a1: String, a2: String, a3: String, a4: String, a5: String, a6: String, a7: String) -> String; @@ -178,6 +179,10 @@ func String_Replace(s: String, old: String, new: String) -> String { return result; } +func String_FromFloat(f: float64) -> String { + return bux_float_to_string(f); +} + func String_Format1(pattern: String, a0: String) -> String { return bux_str_format(pattern, a0, "", "", "", "", "", "", ""); }