From 04be9eb4009123ab347e2a8a227bb401e5792dd7 Mon Sep 17 00:00:00 2001 From: dimgigov Date: Sun, 7 Jun 2026 18:05:04 +0300 Subject: [PATCH] feat(stdlib): add String_Chars, String_FromBool, fix Fmt and Net - String.bux: add String_Chars(s, index) for char-at-index access - String.bux: add String_FromBool(b) conversion - Fmt.bux: rewrite with correct stdlib imports (was using non-existent names) - Net.bux: fix String_Len -> bux_strlen (String_Len not imported) - All lib modules compile successfully --- lib/Fmt.bux | 128 +++++++++++++++++++++++++++++++++++-------------- lib/Net.bux | 2 +- lib/String.bux | 10 ++++ 3 files changed, 104 insertions(+), 36 deletions(-) diff --git a/lib/Fmt.bux b/lib/Fmt.bux index ed253b4..9b91177 100644 --- a/lib/Fmt.bux +++ b/lib/Fmt.bux @@ -1,42 +1,100 @@ +// Fmt.bux — String formatting with positional placeholders {0}, {1}, {2}... +// +// Usage: +// Fmt_Fmt1("Hello, {0}!", "World") +// Fmt_FmtInt("Count: {0}", 42) +// Fmt_FmtBool("Active: {0}", true) +// Fmt_Fmt2("Name: {0}, Age: {1}", name, String_FromInt(age)) + 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); -} +import Std::String::{ + String_Eq, + String_FromInt, + String_FromFloat, + String_FromBool, + StringBuilder, + StringBuilder_New, + StringBuilder_Append, + StringBuilder_Build, + String_Chars +}; -func Fmt_Fmt2(pattern: String, a: String, b: String) -> String { - return String_Format2(pattern, a, b); -} +extern func bux_strlen(s: String) -> uint; +extern func bux_str_to_int(s: String) -> int64; +extern func bux_alloc(size: uint) -> *void; -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"); +// Core formatting engine: replace {0}..{9} in template with args +func Fmt_Format(tmpl: String, argStrs: *String, argCount: int) -> String { + let sb: StringBuilder = StringBuilder_New(); + var i: uint = 0; + let tmplLen: uint = bux_strlen(tmpl); + while i < tmplLen { + // Check for { + let ch: String = String_Chars(tmpl, i); + if String_Eq(ch, "{") { + let digitIdx: uint = i + 1; + if digitIdx < tmplLen { + let digitCh: String = String_Chars(tmpl, digitIdx); + let d: int64 = bux_str_to_int(digitCh); + if d >= 0 && d < argCount as int64 { + // Consume {d} + i = i + 2; // skip past digit + // Check for closing } + if i < tmplLen { + let closeCh: String = String_Chars(tmpl, i); + if String_Eq(closeCh, "}") { + i = i + 1; // skip } + let argStr: String = *(argStrs + (d * 8) as uint); + StringBuilder_Append(&sb, argStr); + continue; + } + } + } + } + } + // Normal character: append it + StringBuilder_Append(&sb, ch); + i = i + 1; } - return String_Format1(pattern, "false"); + return StringBuilder_Build(&sb); } + +// Convenience wrappers +func Fmt_Fmt1(tmpl: String, a1: String) -> String { + var args: *String = bux_alloc(8) as *String; + *(args + 0) = a1; + return Fmt_Format(tmpl, args, 1); +} + +func Fmt_FmtInt(tmpl: String, val: int64) -> String { + let s: String = String_FromInt(val); + return Fmt_Fmt1(tmpl, s); +} + +func Fmt_FmtBool(tmpl: String, val: bool) -> String { + let s: String = String_FromBool(val); + return Fmt_Fmt1(tmpl, s); +} + +func Fmt_FmtFloat(tmpl: String, val: float64) -> String { + let s: String = String_FromFloat(val); + return Fmt_Fmt1(tmpl, s); +} + +func Fmt_Fmt2(tmpl: String, a1: String, a2: String) -> String { + var args: *String = bux_alloc(16) as *String; + *(args + 0) = a1; + *(args + 8) = a2; + return Fmt_Format(tmpl, args, 2); +} + +func Fmt_Fmt3(tmpl: String, a1: String, a2: String, a3: String) -> String { + var args: *String = bux_alloc(24) as *String; + *(args + 0) = a1; + *(args + 8) = a2; + *(args + 16) = a3; + return Fmt_Format(tmpl, args, 3); +} + } diff --git a/lib/Net.bux b/lib/Net.bux index 2c01965..f1a0d98 100644 --- a/lib/Net.bux +++ b/lib/Net.bux @@ -42,7 +42,7 @@ func Net_Connect(fd: int, addr: String, port: int) -> bool { /* Send data. Returns bytes sent or -1 on error. */ func Net_Send(fd: int, data: String) -> int { - return bux_socket_send(fd, data, String_Len(data) as int); + return bux_socket_send(fd, data, bux_strlen(data) as int); } /* Receive up to maxLen bytes. Returns empty string on error/EOF. */ diff --git a/lib/String.bux b/lib/String.bux index 878a18c..27e49fb 100644 --- a/lib/String.bux +++ b/lib/String.bux @@ -161,6 +161,11 @@ func String_Join2(a: String, b: String, sep: String) -> String { // String find/replace/format // --------------------------------------------------------------------------- +// String_Chars — return single-character string at index (for iteration) +func String_Chars(s: String, index: uint) -> String { + return bux_str_slice(s, index, 1); +} + func String_Find(haystack: String, needle: String) -> String { return bux_strstr(haystack, needle); } @@ -185,6 +190,11 @@ func String_ToFloat(s: String) -> float64 { return bux_str_to_float(s); } +func String_FromBool(b: bool) -> String { + if b { return "true"; } + return "false"; +} + func String_FromFloat(f: float64) -> String { return bux_float_to_string(f); }