aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-20 10:56:22 +0000
committer_ov4 <ov4@ov4.org>2026-10-20 10:56:22 +0000
commitcf9af14fe749c52473fdf5a327c3e935e45bf0e7 (patch)
tree4c22c4a919e3da709b16055ff6762ea1195b6237
parent1ed0e276a37d39386b22b08c1f9e575a8f8f8725 (diff)
feat(library): add experimental string LEFT function
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--pseudocode-lib/README.md4
-rw-r--r--pseudocode-lib/_exp_string.cc8
-rw-r--r--pseudocode-lib/_exp_string.cps6
-rw-r--r--tests/library/exp-string/expected.txt4
-rw-r--r--tests/library/exp-string/notes.md2
-rw-r--r--tests/library/exp-string/program.cps5
6 files changed, 28 insertions, 1 deletions
diff --git a/pseudocode-lib/README.md b/pseudocode-lib/README.md
index 92a4bbb..b776d16 100644
--- a/pseudocode-lib/README.md
+++ b/pseudocode-lib/README.md
@@ -17,4 +17,6 @@ INCLUDE paths are relative to the program. Adjust them when the program is elsew
`_EXP_STRING` owns an unbounded `std::string` through one handle. Constructors accept no arguments, another `_EXP_STRING`, `C_STRING`, or `(INTEGER count, C_CHAR character)`. Cast literals to C types explicitly; built-in STRING is not a constructor argument. Copy construction and assignment own independent strings. `_HANDLE` is public only for library implementation access; do not modify or free it.
-The first version 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.
+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.
diff --git a/pseudocode-lib/_exp_string.cc b/pseudocode-lib/_exp_string.cc
index 248b718..ada7c8c 100644
--- a/pseudocode-lib/_exp_string.cc
+++ b/pseudocode-lib/_exp_string.cc
@@ -1,3 +1,4 @@
+#include <algorithm>
#include <cstdio>
#include <exception>
#include <stdexcept>
@@ -65,6 +66,13 @@ double _exp_string_impl_to_real(void *Handle) {
long long _exp_string_impl_length(void *Handle) {
return checked([&] { return static_cast<long long>(text(Handle).size()); });
}
+void _exp_string_impl_left(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(0, 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 369e20f..34b1302 100644
--- a/pseudocode-lib/_exp_string.cps
+++ b/pseudocode-lib/_exp_string.cps
@@ -14,6 +14,7 @@ EXTERN "C" EXTERN_PROCEDURE _exp_string_impl_from_int(_EXP_STRING_HANDLE, _EXP_S
EXTERN "C" EXTERN_PROCEDURE _exp_string_impl_from_real(_EXP_STRING_HANDLE, C_DOUBLE)
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_output(_EXP_STRING_HANDLE)
CLASS _EXP_STRING
@@ -65,3 +66,8 @@ ENDFUNCTION
PROCEDURE _EXP_STRING_OUTPUT(S : _EXP_STRING)
CALL _exp_string_impl_output(S._HANDLE)
ENDPROCEDURE
+FUNCTION _EXP_STRING_LEFT(S : _EXP_STRING, Count : INTEGER) RETURNS _EXP_STRING
+ DECLARE Result : _EXP_STRING
+ CALL _exp_string_impl_left(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 fab16b1..19f0d9b 100644
--- a/tests/library/exp-string/expected.txt
+++ b/tests/library/exp-string/expected.txt
@@ -8,3 +8,7 @@ TRUE
conversion caught
length caught
heap
+ABC
+0:0:0
+ABCDEFGH
+4
diff --git a/tests/library/exp-string/notes.md b/tests/library/exp-string/notes.md
index ca7d489..f44a2b3 100644
--- a/tests/library/exp-string/notes.md
+++ b/tests/library/exp-string/notes.md
@@ -3,3 +3,5 @@
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.
diff --git a/tests/library/exp-string/program.cps b/tests/library/exp-string/program.cps
index 719d9a4..c9dad8a 100644
--- a/tests/library/exp-string/program.cps
+++ b/tests/library/exp-string/program.cps
@@ -39,3 +39,8 @@ 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))