aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AGENTS/PITFALLS/core-language.md2
-rw-r--r--doc/language/function/cpsc-function-chr.7.md4
-rw-r--r--pseudocode-lib/README.md2
-rw-r--r--pseudocode-lib/string.cc6
-rw-r--r--pseudocode-lib/string.cps8
-rw-r--r--tests/i/string-values/notes.md2
-rw-r--r--tests/library/exp-string/notes.md2
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.