diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-20 11:00:16 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-20 11:00:16 +0000 |
| commit | 0c4db4fea1960571318444bd39593533b04b3716 (patch) | |
| tree | c0370d23f10225a6ee3dfe73590f38ca05877606 | |
| parent | cf9af14fe749c52473fdf5a327c3e935e45bf0e7 (diff) | |
feat(library): add experimental string RIGHT function
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | pseudocode-lib/README.md | 2 | ||||
| -rw-r--r-- | pseudocode-lib/_exp_string.cc | 7 | ||||
| -rw-r--r-- | pseudocode-lib/_exp_string.cps | 6 | ||||
| -rw-r--r-- | tests/library/exp-string/expected.txt | 4 | ||||
| -rw-r--r-- | tests/library/exp-string/notes.md | 4 | ||||
| -rw-r--r-- | tests/library/exp-string/program.cps | 29 |
6 files changed, 47 insertions, 5 deletions
diff --git a/pseudocode-lib/README.md b/pseudocode-lib/README.md index b776d16..6a4c23c 100644 --- a/pseudocode-lib/README.md +++ b/pseudocode-lib/README.md @@ -20,3 +20,5 @@ INCLUDE paths are relative to the program. Adjust them when the program is elsew The library provides `&`, `_EXP_STRING_NUM_TO_STR` (INTEGER/REAL), `_EXP_STRING_STR_TO_NUM` (REAL), `_EXP_STRING_LENGTH` (byte length) and `_EXP_STRING_OUTPUT` (text plus newline). Numeric formatting uses `std::to_string`; parsing uses `std::stod` and requires full consumption. C++ standard exceptions print the user call line and are catchable with TRY/CATCH. The built-in STRING remains available with its existing lifetime and NUL limitations. Owning class values inside whole-record or BYVAL-array copies still have bitwise-copy limitations. `_EXP_STRING_LEFT(S : _EXP_STRING, Count : INTEGER)` returns a new `_EXP_STRING` containing up to Count bytes from the beginning. Nonpositive counts return an empty string; counts exceeding the length return the whole string. Embedded NUL bytes are preserved. + +`_EXP_STRING_RIGHT(S : _EXP_STRING, Count : INTEGER)` returns a new `_EXP_STRING` containing up to Count bytes from the end. Nonpositive counts return an empty string; counts exceeding the length return the whole string. Embedded NUL bytes are preserved. diff --git a/pseudocode-lib/_exp_string.cc b/pseudocode-lib/_exp_string.cc index ada7c8c..d881187 100644 --- a/pseudocode-lib/_exp_string.cc +++ b/pseudocode-lib/_exp_string.cc @@ -73,6 +73,13 @@ void _exp_string_impl_left(void *Target, void *Handle, long long Count) { text(Target) = Source.substr(0, Length); }); } +void _exp_string_impl_right(void *Target, void *Handle, long long Count) { + checked([&] { + const auto &Source = text(Handle); + auto Length = Count <= 0 ? 0 : std::min(static_cast<std::size_t>(Count), Source.size()); + text(Target) = Source.substr(Source.size() - Length, Length); + }); +} void _exp_string_impl_output(void *Handle) { checked([&] { const auto &Text = text(Handle); diff --git a/pseudocode-lib/_exp_string.cps b/pseudocode-lib/_exp_string.cps index 34b1302..31e3b43 100644 --- a/pseudocode-lib/_exp_string.cps +++ b/pseudocode-lib/_exp_string.cps @@ -15,6 +15,7 @@ EXTERN "C" EXTERN_PROCEDURE _exp_string_impl_from_real(_EXP_STRING_HANDLE, C_DOU EXTERN "C" EXTERN_FUNCTION _exp_string_impl_to_real(_EXP_STRING_HANDLE) RETURNS C_DOUBLE EXTERN "C" EXTERN_FUNCTION _exp_string_impl_length(_EXP_STRING_HANDLE) RETURNS _EXP_STRING_C_INTEGER EXTERN "C" EXTERN_PROCEDURE _exp_string_impl_left(_EXP_STRING_HANDLE, _EXP_STRING_HANDLE, _EXP_STRING_C_INTEGER) +EXTERN "C" EXTERN_PROCEDURE _exp_string_impl_right(_EXP_STRING_HANDLE, _EXP_STRING_HANDLE, _EXP_STRING_C_INTEGER) EXTERN "C" EXTERN_PROCEDURE _exp_string_impl_output(_EXP_STRING_HANDLE) CLASS _EXP_STRING @@ -71,3 +72,8 @@ FUNCTION _EXP_STRING_LEFT(S : _EXP_STRING, Count : INTEGER) RETURNS _EXP_STRING CALL _exp_string_impl_left(Result._HANDLE, S._HANDLE, (_EXP_STRING_C_INTEGER)Count) RETURN Result ENDFUNCTION +FUNCTION _EXP_STRING_RIGHT(S : _EXP_STRING, Count : INTEGER) RETURNS _EXP_STRING + DECLARE Result : _EXP_STRING + CALL _exp_string_impl_right(Result._HANDLE, S._HANDLE, (_EXP_STRING_C_INTEGER)Count) + RETURN Result +ENDFUNCTION diff --git a/tests/library/exp-string/expected.txt b/tests/library/exp-string/expected.txt index 19f0d9b..ef650f3 100644 --- a/tests/library/exp-string/expected.txt +++ b/tests/library/exp-string/expected.txt @@ -12,3 +12,7 @@ ABC 0:0:0 ABCDEFGH 4 +FGH +0:0:0 +ABCDEFGH +4 diff --git a/tests/library/exp-string/notes.md b/tests/library/exp-string/notes.md index f44a2b3..ff25d0f 100644 --- a/tests/library/exp-string/notes.md +++ b/tests/library/exp-string/notes.md @@ -5,3 +5,7 @@ Review status: pending human review. Copies of hello are independent; assigning world to the copy gives helloworld when concatenated. Empty length is zero, and three NUL bytes retain length three. One hundred appended five-byte words grow 20000 bytes to 20500, preserved by BYVAL and RETURN. C++17 formatting gives 42 and 1.250000. Parsing 12.5 compares equal to 12.5. Trailing junk and negative counts emit the explicit library reasons at user lines 27 and 32, then are caught. Discarded numeric and Echo results must release their owned strings at statement end. The explicitly deleted heap object prints heap. This fixture covers compiler/library extensions, including numeric text formatting. LEFT keeps ABC, returns zero bytes for an empty source or nonpositive count, and clamps 20 to all eight letters. Taking four bytes from three NULs followed by hello retains all four bytes. + +RIGHT keeps FGH, returns zero bytes for an empty source or nonpositive count, and clamps 20 to all eight letters. Taking four bytes from hello followed by three NULs retains the final o and all three NULs. + +The added checks use separate procedures to keep generated temporary-object cleanup small enough for the ordinary runner timeout. diff --git a/tests/library/exp-string/program.cps b/tests/library/exp-string/program.cps index c9dad8a..f8c037f 100644 --- a/tests/library/exp-string/program.cps +++ b/tests/library/exp-string/program.cps @@ -39,8 +39,27 @@ DECLARE Heap : _EXP_STRING Heap <- NEW _EXP_STRING((C_STRING)"heap") CALL _EXP_STRING_OUTPUT(Heap) DELETE Heap -DECLARE Letters : _EXP_STRING((C_STRING)"ABCDEFGH") -CALL _EXP_STRING_OUTPUT(_EXP_STRING_LEFT(Letters, 3)) -OUTPUT _EXP_STRING_LENGTH(_EXP_STRING_LEFT(Empty, 2)), ":", _EXP_STRING_LENGTH(_EXP_STRING_LEFT(Letters, 0)), ":", _EXP_STRING_LENGTH(_EXP_STRING_LEFT(Letters, -1)) -CALL _EXP_STRING_OUTPUT(_EXP_STRING_LEFT(Letters, 20)) -OUTPUT _EXP_STRING_LENGTH(_EXP_STRING_LEFT(Nuls & A, 4)) +CALL CheckLeft() +CALL CheckRight() + +PROCEDURE CheckLeft() + DECLARE Letters : _EXP_STRING((C_STRING)"ABCDEFGH") + DECLARE Empty : _EXP_STRING + DECLARE Nuls : _EXP_STRING(3, (C_CHAR)'\0') + DECLARE A : _EXP_STRING((C_STRING)"hello") + CALL _EXP_STRING_OUTPUT(_EXP_STRING_LEFT(Letters, 3)) + OUTPUT _EXP_STRING_LENGTH(_EXP_STRING_LEFT(Empty, 2)), ":", _EXP_STRING_LENGTH(_EXP_STRING_LEFT(Letters, 0)), ":", _EXP_STRING_LENGTH(_EXP_STRING_LEFT(Letters, -1)) + CALL _EXP_STRING_OUTPUT(_EXP_STRING_LEFT(Letters, 20)) + OUTPUT _EXP_STRING_LENGTH(_EXP_STRING_LEFT(Nuls & A, 4)) +ENDPROCEDURE + +PROCEDURE CheckRight() + DECLARE Letters : _EXP_STRING((C_STRING)"ABCDEFGH") + DECLARE Empty : _EXP_STRING + DECLARE Nuls : _EXP_STRING(3, (C_CHAR)'\0') + DECLARE A : _EXP_STRING((C_STRING)"hello") + CALL _EXP_STRING_OUTPUT(_EXP_STRING_RIGHT(Letters, 3)) + OUTPUT _EXP_STRING_LENGTH(_EXP_STRING_RIGHT(Empty, 2)), ":", _EXP_STRING_LENGTH(_EXP_STRING_RIGHT(Letters, 0)), ":", _EXP_STRING_LENGTH(_EXP_STRING_RIGHT(Letters, -1)) + CALL _EXP_STRING_OUTPUT(_EXP_STRING_RIGHT(Letters, 20)) + OUTPUT _EXP_STRING_LENGTH(_EXP_STRING_RIGHT(A & Nuls, 4)) +ENDPROCEDURE |
