feat: String_ToFloat + Json escape sequence support
- Add bux_str_to_float() C runtime wrapper (strtod) - Add String_ToFloat() in library/std/String.bux - Update JsonParser_ParseNumber to use String_ToFloat (decimals now work) - Update JsonParser_ParseString to decode escape sequences (\n, \t, \r, \", \\, \b, \f) - Fix use-after-free in JsonParser_ParseString: String_Copy before StringBuilder_Free
This commit is contained in:
@@ -141,6 +141,7 @@ String manipulation utilities.
|
|||||||
| `String_FromInt` | `func String_FromInt(n: int64) -> String` | Int to string |
|
| `String_FromInt` | `func String_FromInt(n: int64) -> String` | Int to string |
|
||||||
| `String_FromFloat` | `func String_FromFloat(f: float64) -> String` | Float to string |
|
| `String_FromFloat` | `func String_FromFloat(f: float64) -> String` | Float to string |
|
||||||
| `String_ToInt` | `func String_ToInt(s: String) -> int64` | String to int |
|
| `String_ToInt` | `func String_ToInt(s: String) -> int64` | String to int |
|
||||||
|
| `String_ToFloat` | `func String_ToFloat(s: String) -> float64` | String to float |
|
||||||
|
|
||||||
### Find, Replace & Format
|
### Find, Replace & Format
|
||||||
|
|
||||||
|
|||||||
@@ -221,6 +221,11 @@ char* bux_strncpy(char* dest, const char* src, unsigned int n) {
|
|||||||
return strncpy(dest, src, (size_t)n);
|
return strncpy(dest, src, (size_t)n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double bux_str_to_float(const char* s) {
|
||||||
|
if (!s) return 0.0;
|
||||||
|
return strtod(s, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* String find: returns pointer to first occurrence of needle in haystack, or NULL */
|
/* String find: returns pointer to first occurrence of needle in haystack, or NULL */
|
||||||
const char* bux_strstr(const char* haystack, const char* needle) {
|
const char* bux_strstr(const char* haystack, const char* needle) {
|
||||||
if (!haystack || !needle) return NULL;
|
if (!haystack || !needle) return NULL;
|
||||||
|
|||||||
+24
-6
@@ -236,7 +236,7 @@ func JsonParser_ParseString(p: *JsonParser) -> String {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
JsonParser_Advance(p);
|
JsonParser_Advance(p);
|
||||||
let start: uint = p.pos;
|
let sb: StringBuilder = StringBuilder_New();
|
||||||
while true {
|
while true {
|
||||||
let c: int = JsonParser_Peek(p);
|
let c: int = JsonParser_Peek(p);
|
||||||
if c == 0 || c == 34 {
|
if c == 0 || c == 34 {
|
||||||
@@ -244,22 +244,40 @@ func JsonParser_ParseString(p: *JsonParser) -> String {
|
|||||||
}
|
}
|
||||||
if c == 92 {
|
if c == 92 {
|
||||||
JsonParser_Advance(p);
|
JsonParser_Advance(p);
|
||||||
if JsonParser_Peek(p) == 0 {
|
let esc: int = JsonParser_Peek(p);
|
||||||
|
if esc == 0 {
|
||||||
p.error = "Unterminated string escape";
|
p.error = "Unterminated string escape";
|
||||||
|
StringBuilder_Free(&sb);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
if esc == 110 { StringBuilder_AppendChar(&sb, 10 as char8); } // \n
|
||||||
|
else if esc == 116 { StringBuilder_AppendChar(&sb, 9 as char8); } // \t
|
||||||
|
else if esc == 114 { StringBuilder_AppendChar(&sb, 13 as char8); } // \r
|
||||||
|
else if esc == 98 { StringBuilder_AppendChar(&sb, 8 as char8); } // \b
|
||||||
|
else if esc == 102 { StringBuilder_AppendChar(&sb, 12 as char8); } // \f
|
||||||
|
else if esc == 34 { StringBuilder_AppendChar(&sb, 34 as char8); } // \"
|
||||||
|
else if esc == 92 { StringBuilder_AppendChar(&sb, 92 as char8); } // \\
|
||||||
|
else {
|
||||||
|
// Unknown escape — keep literal
|
||||||
|
StringBuilder_AppendChar(&sb, 92 as char8);
|
||||||
|
StringBuilder_AppendChar(&sb, esc as char8);
|
||||||
|
}
|
||||||
JsonParser_Advance(p);
|
JsonParser_Advance(p);
|
||||||
} else {
|
} else {
|
||||||
|
StringBuilder_AppendChar(&sb, c as char8);
|
||||||
JsonParser_Advance(p);
|
JsonParser_Advance(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let endPos: uint = p.pos;
|
|
||||||
if JsonParser_Peek(p) != 34 {
|
if JsonParser_Peek(p) != 34 {
|
||||||
p.error = "Unterminated string";
|
p.error = "Unterminated string";
|
||||||
|
StringBuilder_Free(&sb);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
JsonParser_Advance(p);
|
JsonParser_Advance(p);
|
||||||
return String_Slice(p.src, start, endPos - start);
|
let raw: String = StringBuilder_Build(&sb);
|
||||||
|
let result: String = String_Copy(raw);
|
||||||
|
StringBuilder_Free(&sb);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
func JsonParser_ParseNumber(p: *JsonParser) -> JsonValue {
|
func JsonParser_ParseNumber(p: *JsonParser) -> JsonValue {
|
||||||
@@ -288,8 +306,8 @@ func JsonParser_ParseNumber(p: *JsonParser) -> JsonValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let numStr: String = String_Slice(p.src, start, p.pos - start);
|
let numStr: String = String_Slice(p.src, start, p.pos - start);
|
||||||
let n: int64 = String_ToInt(numStr);
|
let n: float64 = String_ToFloat(numStr);
|
||||||
return Json_Number(n as float64);
|
return Json_Number(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
func JsonParser_ParseArray(p: *JsonParser) -> JsonValue {
|
func JsonParser_ParseArray(p: *JsonParser) -> JsonValue {
|
||||||
|
|||||||
@@ -179,6 +179,12 @@ func String_Replace(s: String, old: String, new: String) -> String {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern func bux_str_to_float(s: String) -> float64;
|
||||||
|
|
||||||
|
func String_ToFloat(s: String) -> float64 {
|
||||||
|
return bux_str_to_float(s);
|
||||||
|
}
|
||||||
|
|
||||||
func String_FromFloat(f: float64) -> String {
|
func String_FromFloat(f: float64) -> String {
|
||||||
return bux_float_to_string(f);
|
return bux_float_to_string(f);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user