From 62b605c6c0ea13e9763c0a0115464007b13a8831 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Tue, 20 Oct 2026 11:57:16 +0000 Subject: refactor(strings): replace compiler builtins with the STRING library Construct literals as STRING values and route string operations through ordinary library functions and operators. Preserve value ownership in records, arrays, constants and file I/O. Co-Authored-By: Claude Opus 5.5 --- pseudocode-lib/string.cc | 158 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 pseudocode-lib/string.cc (limited to 'pseudocode-lib/string.cc') diff --git a/pseudocode-lib/string.cc b/pseudocode-lib/string.cc new file mode 100644 index 0000000..f2f03f6 --- /dev/null +++ b/pseudocode-lib/string.cc @@ -0,0 +1,158 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" int __cps_user_line; + +namespace { +template +decltype(auto) checked(Operation &&Op) { + try { + return std::forward(Op)(); + } catch (const std::exception &Error) { + std::fprintf(stderr, "[Fatal] line %d: %s\n", __cps_user_line, Error.what()); + throw 0; + } +} +std::string &text(void *Handle) { return *static_cast(Handle); } +} + +extern "C" { +void *_string_impl_new() { + return checked([] { return new std::string; }); +} +void *_string_impl_copy(void *Other) { + return checked([&] { return new std::string(text(Other)); }); +} +void *_string_impl_from_cstr(const char *Text) { + return checked([&] { return new std::string(Text); }); +} +void *_string_impl_from_count_char(long long Count, char Ch) { + return checked([&] { + if (Count < 0) throw std::invalid_argument("negative string length"); + return new std::string(static_cast(Count), Ch); + }); +} +void _string_impl_delete(void *Handle) { + checked([&] { delete static_cast(Handle); }); +} +void _string_impl_assign(void *Target, void *Other) { + checked([&] { text(Target) = text(Other); }); +} +void _string_impl_assign_cstr(void *Target, const char *Text) { + checked([&] { text(Target) = Text; }); +} +void _string_impl_concat(void *Target, void *A, void *B) { + checked([&] { text(Target) = text(A) + text(B); }); +} +void _string_impl_from_int(void *Target, long long Number) { + checked([&] { text(Target) = std::to_string(Number); }); +} +void _string_impl_from_real(void *Target, double Number) { + checked([&] { text(Target) = std::to_string(Number); }); +} +double _string_impl_to_real(void *Handle) { + return checked([&] { + std::size_t Consumed = 0; + double Number = std::stod(text(Handle), &Consumed); + if (Consumed != text(Handle).size()) + throw std::invalid_argument("unconsumed characters in string conversion"); + return Number; + }); +} +long long _string_impl_length(void *Handle) { + return checked([&] { return static_cast(text(Handle).size()); }); +} +void _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(Count), Source.size()); + text(Target) = Source.substr(0, Length); + }); +} +void _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(Count), Source.size()); + text(Target) = Source.substr(Source.size() - Length, Length); + }); +} +void _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 _string_impl_lcase(void *Target, void *Handle) { + checked([&] { + text(Target) = text(Handle); + for (char &Ch : text(Target)) + Ch = static_cast(std::tolower(static_cast(Ch))); + }); +} +char _string_impl_lcase_char(char Ch) { + return checked([&] { + return static_cast(std::tolower(static_cast(Ch))); + }); +} +void _string_impl_ucase(void *Target, void *Handle) { + checked([&] { + text(Target) = text(Handle); + for (char &Ch : text(Target)) + Ch = static_cast(std::toupper(static_cast(Ch))); + }); +} +char _string_impl_ucase_char(char Ch) { + return checked([&] { + return static_cast(std::toupper(static_cast(Ch))); + }); +} +long long _string_impl_asc(void *Handle) { + return checked([&]() -> long long { + const auto &Source = text(Handle); + return Source.empty() ? 0 : static_cast(Source.front()); + }); +} +long long _string_impl_asc_char(char Ch) { + return checked([&]() -> long long { return static_cast(Ch); }); +} +void _string_impl_chr(void *Target, long long Code) { + checked([&] { + text(Target).assign(1, static_cast(static_cast(Code))); + }); +} +int _string_impl_is_num(void *Handle) { + return checked([&]() -> int { + const auto &Source = text(Handle); + char *End = nullptr; + std::strtod(Source.c_str(), &End); + return !Source.empty() && End == Source.c_str() + Source.size(); + }); +} +const char *_string_impl_c_str(void *Handle) { + return text(Handle).c_str(); +} +int _string_impl_compare(void *A, void *B) { + return checked([&] { return text(A).compare(text(B)); }); +} +void _string_impl_input(void *Handle) { + checked([&] { + std::string Value; + int Ch; + do { Ch = std::getchar(); } while (Ch != EOF && std::isspace(static_cast(Ch))); + while (Ch != EOF && !std::isspace(static_cast(Ch))) { + Value.push_back(static_cast(Ch)); + Ch = std::getchar(); + } + if (Ch != EOF) std::ungetc(Ch, stdin); + text(Handle) = std::move(Value); + }); +} +} -- cgit v1.3.1-4-g156e