From 65599524f5b41ffb6d8d55664611612c0b57ad47 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Tue, 20 Oct 2026 11:01:01 +0000 Subject: feat(library): add experimental string MID function Co-Authored-By: Claude Opus 5.5 --- pseudocode-lib/README.md | 2 ++ pseudocode-lib/_exp_string.cc | 8 ++++++++ pseudocode-lib/_exp_string.cps | 6 ++++++ tests/library/exp-string/expected.txt | 6 ++++++ tests/library/exp-string/notes.md | 2 ++ tests/library/exp-string/program.cps | 13 +++++++++++++ 6 files changed, 37 insertions(+) diff --git a/pseudocode-lib/README.md b/pseudocode-lib/README.md index 6a4c23c..55367d0 100644 --- a/pseudocode-lib/README.md +++ b/pseudocode-lib/README.md @@ -22,3 +22,5 @@ The library provides `&`, `_EXP_STRING_NUM_TO_STR` (INTEGER/REAL), `_EXP_STRING_ `_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. + +`_EXP_STRING_MID(S : _EXP_STRING, Start : INTEGER, Count : INTEGER)` returns a new `_EXP_STRING` containing up to Count bytes from the one-based Start position. Starts below 1 clamp to 1; starts beyond the end and nonpositive counts return an empty string. Counts clamp to the remaining bytes. Embedded NUL bytes are preserved. diff --git a/pseudocode-lib/_exp_string.cc b/pseudocode-lib/_exp_string.cc index d881187..d406274 100644 --- a/pseudocode-lib/_exp_string.cc +++ b/pseudocode-lib/_exp_string.cc @@ -80,6 +80,14 @@ void _exp_string_impl_right(void *Target, void *Handle, long long Count) { text(Target) = Source.substr(Source.size() - Length, Length); }); } +void _exp_string_impl_mid(void *Target, void *Handle, long long Start, long long Count) { + checked([&] { + const auto &Source = text(Handle); + auto Position = Start <= 1 ? 0 : std::min(static_cast(Start - 1), Source.size()); + auto Length = Count <= 0 ? 0 : std::min(static_cast(Count), Source.size() - Position); + text(Target) = Source.substr(Position, 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 31e3b43..30eef71 100644 --- a/pseudocode-lib/_exp_string.cps +++ b/pseudocode-lib/_exp_string.cps @@ -16,6 +16,7 @@ EXTERN "C" EXTERN_FUNCTION _exp_string_impl_to_real(_EXP_STRING_HANDLE) RETURNS 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_mid(_EXP_STRING_HANDLE, _EXP_STRING_HANDLE, _EXP_STRING_C_INTEGER, _EXP_STRING_C_INTEGER) EXTERN "C" EXTERN_PROCEDURE _exp_string_impl_output(_EXP_STRING_HANDLE) CLASS _EXP_STRING @@ -77,3 +78,8 @@ FUNCTION _EXP_STRING_RIGHT(S : _EXP_STRING, Count : INTEGER) RETURNS _EXP_STRING CALL _exp_string_impl_right(Result._HANDLE, S._HANDLE, (_EXP_STRING_C_INTEGER)Count) RETURN Result ENDFUNCTION +FUNCTION _EXP_STRING_MID(S : _EXP_STRING, Start : INTEGER, Count : INTEGER) RETURNS _EXP_STRING + DECLARE Result : _EXP_STRING + CALL _exp_string_impl_mid(Result._HANDLE, S._HANDLE, (_EXP_STRING_C_INTEGER)Start, (_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 ef650f3..a3ce792 100644 --- a/tests/library/exp-string/expected.txt +++ b/tests/library/exp-string/expected.txt @@ -16,3 +16,9 @@ FGH 0:0:0 ABCDEFGH 4 +BCD +AB +GH +0:0 +0:0 +4 diff --git a/tests/library/exp-string/notes.md b/tests/library/exp-string/notes.md index ff25d0f..c05d6d7 100644 --- a/tests/library/exp-string/notes.md +++ b/tests/library/exp-string/notes.md @@ -9,3 +9,5 @@ LEFT keeps ABC, returns zero bytes for an empty source or nonpositive count, and 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. + +MID positions 2..4 give BCD. The minimum INTEGER start clamps to 1 and gives AB; a maximum count from position 7 gives GH. Empty input, a maximum start, and nonpositive counts give length zero. Four bytes starting at the second of three NULs retain two NULs and AB. diff --git a/tests/library/exp-string/program.cps b/tests/library/exp-string/program.cps index f8c037f..0b6c977 100644 --- a/tests/library/exp-string/program.cps +++ b/tests/library/exp-string/program.cps @@ -41,6 +41,7 @@ CALL _EXP_STRING_OUTPUT(Heap) DELETE Heap CALL CheckLeft() CALL CheckRight() +CALL CheckMid() PROCEDURE CheckLeft() DECLARE Letters : _EXP_STRING((C_STRING)"ABCDEFGH") @@ -63,3 +64,15 @@ PROCEDURE CheckRight() CALL _EXP_STRING_OUTPUT(_EXP_STRING_RIGHT(Letters, 20)) OUTPUT _EXP_STRING_LENGTH(_EXP_STRING_RIGHT(A & Nuls, 4)) ENDPROCEDURE + +PROCEDURE CheckMid() + DECLARE Letters : _EXP_STRING((C_STRING)"ABCDEFGH") + DECLARE Empty : _EXP_STRING + DECLARE Nuls : _EXP_STRING(3, (C_CHAR)'\0') + CALL _EXP_STRING_OUTPUT(_EXP_STRING_MID(Letters, 2, 3)) + CALL _EXP_STRING_OUTPUT(_EXP_STRING_MID(Letters, -9223372036854775808, 2)) + CALL _EXP_STRING_OUTPUT(_EXP_STRING_MID(Letters, 7, 9223372036854775807)) + OUTPUT _EXP_STRING_LENGTH(_EXP_STRING_MID(Empty, 1, 2)), ":", _EXP_STRING_LENGTH(_EXP_STRING_MID(Letters, 9223372036854775807, 2)) + OUTPUT _EXP_STRING_LENGTH(_EXP_STRING_MID(Letters, 2, 0)), ":", _EXP_STRING_LENGTH(_EXP_STRING_MID(Letters, 2, -1)) + OUTPUT _EXP_STRING_LENGTH(_EXP_STRING_MID(Nuls & Letters, 2, 4)) +ENDPROCEDURE -- cgit v1.3.1-4-g156e