diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-23 01:19:28 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-23 01:19:28 +0000 |
| commit | 90fc80c193453e8d5038530f310fc007f9ff9789 (patch) | |
| tree | e324ea2c88f63610cc5f13f0b55114f12b5b8f98 | |
| parent | 7c681c33e17550bfc8a0dc969129a2ea855a39fe (diff) | |
fix(stdlib)!: return CHAR from CHR
BREAKING CHANGE: CHR now returns CHAR instead of STRING, so user overloads and templates select or deduce CHAR for CHR(...).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | AGENTS/PITFALLS/core-language.md | 2 | ||||
| -rw-r--r-- | doc/language/function/cpsc-function-chr.7.md | 4 | ||||
| -rw-r--r-- | pseudocode-lib/README.md | 2 | ||||
| -rw-r--r-- | pseudocode-lib/string.cc | 6 | ||||
| -rw-r--r-- | pseudocode-lib/string.cps | 8 | ||||
| -rw-r--r-- | tests/i/string-values/notes.md | 2 | ||||
| -rw-r--r-- | tests/library/exp-string/notes.md | 2 |
7 files changed, 10 insertions, 16 deletions
diff --git a/AGENTS/PITFALLS/core-language.md b/AGENTS/PITFALLS/core-language.md index dd222c7..5ff97ca 100644 --- a/AGENTS/PITFALLS/core-language.md +++ b/AGENTS/PITFALLS/core-language.md @@ -31,7 +31,7 @@ source, most also by compiling and running test programs. annotate `BYVAL` explicitly. - **`/` always yields REAL** (double FDiv), even for two INTEGERs; integer division is DIV/MOD only. - - CHR returns an owning one-byte STRING, not CHAR; CHR(0) retains one NUL byte. + - CHR returns CHAR, not STRING; CHR(0) is a NUL CHAR that converts to a one-byte STRING. - STR_TO_NUM always returns REAL and shares parseNumber (strtod, full consumption, overflow rejected) with IS_NUM. - NUM_TO_STR keeps the full signed i64 range for INTEGER; REAL uses the shortest round-trip text (realText in string.cc), byte-identical to OUTPUT's IR helper in diff --git a/doc/language/function/cpsc-function-chr.7.md b/doc/language/function/cpsc-function-chr.7.md index 3ae8612..b67b0c6 100644 --- a/doc/language/function/cpsc-function-chr.7.md +++ b/doc/language/function/cpsc-function-chr.7.md @@ -7,14 +7,14 @@ cpsc-function-chr - convert a byte code to text # SYNOPSIS ```text -CHR(code : INTEGER) RETURNS STRING +CHR(code : INTEGER) RETURNS CHAR ``` # DESCRIPTION Provided by the standard string library, loaded and linked by default. -Convert the low eight bits of code to a one-byte string. The result is STRING, not CHAR, but a STRING of length 1 converts implicitly to CHAR on assignment. Use ASCII codes 1 to 127 for ordinary text; code 0 produces one NUL byte, so LENGTH(CHR(0)) is 1. +Convert the low eight bits of code to a CHAR. The result is CHAR, not STRING; a CHAR converts implicitly to STRING where a STRING is expected. Use ASCII codes 1 to 127 for ordinary text; code 0 produces one NUL byte, so LENGTH(CHR(0)) is 1. # EXAMPLE diff --git a/pseudocode-lib/README.md b/pseudocode-lib/README.md index 4e70a44..f3c683f 100644 --- a/pseudocode-lib/README.md +++ b/pseudocode-lib/README.md @@ -33,7 +33,7 @@ The library provides `&`, six case-sensitive content comparisons, and these ordi - `MID(S, Start, Count)` uses a one-based Start. Starts below 1 clamp to 1; starts beyond the end and nonpositive counts return empty. Counts clamp to the remaining bytes. - `LCASE(CHAR)` and `UCASE(CHAR)` return CHAR, following guide section 5.5. STRING overloads return independent strings. Nonletters and embedded NUL bytes are preserved; use ASCII for predictable case conversion. - `ASC(CHAR)` and `ASC(STRING)` return the unsigned character or first-byte code; an empty string returns zero. -- `CHR(Code)` returns a one-byte STRING containing the low eight bits. `LENGTH(CHR(0))` is 1. +- `CHR(Code)` returns a CHAR containing the low eight bits. `LENGTH(CHR(0))` is 1. - `NUM_TO_STR(INTEGER)` and `NUM_TO_STR(REAL)` convert INTEGER to decimal text and REAL to the shortest round-trip text (Python `repr` style, identical to OUTPUT: `2.0`, `0.1`, `1e-07`, `inf`). - `STR_TO_NUM(S)` returns REAL through the same `parseNumber` helper as IS_NUM (`strtod`, full consumption). Invalid text and trailing junk throw `STR_TO_NUM: '<text>' is not a number`; overflow throws `... is out of the REAL range`; underflow is accepted. - `IS_NUM(S)` agrees with STR_TO_NUM: full consumption by `strtod` and no overflow, without throwing. Leading whitespace is accepted; trailing whitespace, trailing junk, empty input, embedded NUL bytes, and overflowing values (`1e999`) are rejected. diff --git a/pseudocode-lib/string.cc b/pseudocode-lib/string.cc index c47899c..4395304 100644 --- a/pseudocode-lib/string.cc +++ b/pseudocode-lib/string.cc @@ -163,11 +163,7 @@ long long _string_impl_asc(void *Handle) { long long _string_impl_asc_char(char Ch) { return checked([&]() -> long long { return static_cast<unsigned char>(Ch); }); } -void _string_impl_chr(void *Target, long long Code) { - checked([&] { - text(Target).assign(1, static_cast<char>(static_cast<unsigned char>(Code))); - }); -} +char _string_impl_chr_char(long long Code) { return static_cast<char>(static_cast<unsigned char>(Code)); } int _string_impl_is_num(void *Handle) { return checked([&]() -> int { double Number = 0; diff --git a/pseudocode-lib/string.cps b/pseudocode-lib/string.cps index a118326..1ad63d3 100644 --- a/pseudocode-lib/string.cps +++ b/pseudocode-lib/string.cps @@ -23,7 +23,7 @@ EXTERN "C" EXTERN_PROCEDURE _string_impl_ucase(_STRING_HANDLE, _STRING_HANDLE) EXTERN "C" EXTERN_FUNCTION _string_impl_ucase_char(C_CHAR) RETURNS C_CHAR EXTERN "C" EXTERN_FUNCTION _string_impl_asc(_STRING_HANDLE) RETURNS _STRING_C_INTEGER EXTERN "C" EXTERN_FUNCTION _string_impl_asc_char(C_CHAR) RETURNS _STRING_C_INTEGER -EXTERN "C" EXTERN_PROCEDURE _string_impl_chr(_STRING_HANDLE, _STRING_C_INTEGER) +EXTERN "C" EXTERN_FUNCTION _string_impl_chr_char(_STRING_C_INTEGER) RETURNS C_CHAR EXTERN "C" EXTERN_FUNCTION _string_impl_is_num(_STRING_HANDLE) RETURNS C_INT EXTERN "C" EXTERN_FUNCTION _string_impl_c_str(_STRING_HANDLE) RETURNS C_STRING EXTERN "C" EXTERN_PROCEDURE _string_impl_input(_STRING_HANDLE) @@ -121,10 +121,8 @@ ENDFUNCTION OVERLOAD FUNCTION ASC(Ch : CHAR) RETURNS INTEGER RETURN (INTEGER)_string_impl_asc_char((C_CHAR)Ch) ENDFUNCTION -FUNCTION CHR(Code : INTEGER) RETURNS STRING - DECLARE Result : STRING - CALL _string_impl_chr(Result._HANDLE, (_STRING_C_INTEGER)Code) - RETURN Result +FUNCTION CHR(Code : INTEGER) RETURNS CHAR + RETURN (CHAR)_string_impl_chr_char((_STRING_C_INTEGER)Code) ENDFUNCTION FUNCTION IS_NUM(S : STRING) RETURNS BOOLEAN RETURN (BOOLEAN)_string_impl_is_num(S._HANDLE) diff --git a/tests/i/string-values/notes.md b/tests/i/string-values/notes.md index 1e821cc..0e4be24 100644 --- a/tests/i/string-values/notes.md +++ b/tests/i/string-values/notes.md @@ -2,4 +2,4 @@ Human review: pending. Expected output is traced from independent string values. -Record copies and BYVAL array calls must preserve the source when a copy changes. Self-assignment preserves the value. Global and constant strings remain available to functions. Comparisons use case-sensitive content ordering. Ordinary literals retain the legacy NUL truncation; CHR can construct an owning one-byte NUL string. +Record copies and BYVAL array calls must preserve the source when a copy changes. Self-assignment preserves the value. Global and constant strings remain available to functions. Comparisons use case-sensitive content ordering. Ordinary literals retain the legacy NUL truncation; CHR(0) returns a NUL CHAR that converts to a one-byte NUL string. diff --git a/tests/library/exp-string/notes.md b/tests/library/exp-string/notes.md index e2a1bbc..50080be 100644 --- a/tests/library/exp-string/notes.md +++ b/tests/library/exp-string/notes.md @@ -18,6 +18,6 @@ UCASE converts AbC@19 to ABC@19 without modifying the source. Its CHAR overload ASC returns 65 for CHAR A and the first byte of ABCDEFGH, zero for empty strings or NUL, and 255 for a byte with all eight bits set. These byte-code functions are compiler/library extensions. -CHR codes 65 and 90 concatenate to AZ; converting A to a code and back preserves 65. Code zero produces one retained NUL byte. Taking the low eight bits gives 65 for 321 and 255 for -1. +CHR codes 65 and 90 concatenate to AZ; converting A to a code and back preserves 65. CHR returns CHAR; code zero produces a NUL CHAR whose STRING conversion retains one byte. Taking the low eight bits gives 65 for 321 and 255 for -1. IS_NUM accepts 12.5 and a leading space before 12.5. It rejects trailing junk, empty input, trailing space, whitespace alone, and a NUL byte before or after a valid number, without throwing. Numeric recognition follows the compiler's strtod-based extension. |
