aboutsummaryrefslogtreecommitdiff
path: root/pseudocode-lib
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-18 08:16:01 +0000
committer_ov4 <ov4@ov4.org>2026-10-18 08:16:01 +0000
commit14c03b7c26ff06835fca631eed6a3e308946321a (patch)
tree33965d73902f019f2f778046e7f097ff26f35f01 /pseudocode-lib
parent0b1c500e9cbc7837dbef5fb24be21dc4f6078714 (diff)
feat(lib): add experimental _EXP_STRING backed by std::string
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'pseudocode-lib')
-rw-r--r--pseudocode-lib/README.md20
-rw-r--r--pseudocode-lib/_exp_string.cc75
-rw-r--r--pseudocode-lib/_exp_string.cps67
3 files changed, 162 insertions, 0 deletions
diff --git a/pseudocode-lib/README.md b/pseudocode-lib/README.md
new file mode 100644
index 0000000..92a4bbb
--- /dev/null
+++ b/pseudocode-lib/README.md
@@ -0,0 +1,20 @@
+# Experimental string library
+
+Build with `cmake --build build`. Include the built library in your program and pass it as a compiler input:
+
+```text
+INCLUDE "build/pseudocode-lib/_exp_string.cps"
+DECLARE Greeting : _EXP_STRING((C_STRING)"hello")
+CALL _EXP_STRING_OUTPUT(Greeting & _EXP_STRING_NUM_TO_STR(42))
+```
+
+```sh
+build/cpsc prog.cps build/pseudocode-lib/_exp_string.cps
+build/cpsc prog.cps build/pseudocode-lib/_exp_string.cps -r
+```
+
+INCLUDE paths are relative to the program. Adjust them when the program is elsewhere.
+
+`_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.
diff --git a/pseudocode-lib/_exp_string.cc b/pseudocode-lib/_exp_string.cc
new file mode 100644
index 0000000..248b718
--- /dev/null
+++ b/pseudocode-lib/_exp_string.cc
@@ -0,0 +1,75 @@
+#include <cstdio>
+#include <exception>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+extern "C" int __cps_user_line;
+
+namespace {
+template <class Operation>
+decltype(auto) checked(Operation &&Op) {
+ try {
+ return std::forward<Operation>(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<std::string *>(Handle); }
+}
+
+extern "C" {
+void *_exp_string_impl_new() {
+ return checked([] { return new std::string; });
+}
+void *_exp_string_impl_copy(void *Other) {
+ return checked([&] { return new std::string(text(Other)); });
+}
+void *_exp_string_impl_from_cstr(const char *Text) {
+ return checked([&] { return new std::string(Text); });
+}
+void *_exp_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<std::size_t>(Count), Ch);
+ });
+}
+void _exp_string_impl_delete(void *Handle) {
+ checked([&] { delete static_cast<std::string *>(Handle); });
+}
+void _exp_string_impl_assign(void *Target, void *Other) {
+ checked([&] { text(Target) = text(Other); });
+}
+void _exp_string_impl_assign_cstr(void *Target, const char *Text) {
+ checked([&] { text(Target) = Text; });
+}
+void _exp_string_impl_concat(void *Target, void *A, void *B) {
+ checked([&] { text(Target) = text(A) + text(B); });
+}
+void _exp_string_impl_from_int(void *Target, long long Number) {
+ checked([&] { text(Target) = std::to_string(Number); });
+}
+void _exp_string_impl_from_real(void *Target, double Number) {
+ checked([&] { text(Target) = std::to_string(Number); });
+}
+double _exp_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 _exp_string_impl_length(void *Handle) {
+ return checked([&] { return static_cast<long long>(text(Handle).size()); });
+}
+void _exp_string_impl_output(void *Handle) {
+ checked([&] {
+ const auto &Text = text(Handle);
+ std::fwrite(Text.data(), 1, Text.size(), stdout);
+ std::fputc('\n', stdout);
+ });
+}
+}
diff --git a/pseudocode-lib/_exp_string.cps b/pseudocode-lib/_exp_string.cps
new file mode 100644
index 0000000..369e20f
--- /dev/null
+++ b/pseudocode-lib/_exp_string.cps
@@ -0,0 +1,67 @@
+#LIB
+INCLUDE_OBJ "_exp_string.o"
+TYPE _EXP_STRING_HANDLE = C_TYPE("void*")
+TYPE _EXP_STRING_C_INTEGER = C_TYPE("long long")
+EXTERN "C" EXTERN_FUNCTION _exp_string_impl_new() RETURNS _EXP_STRING_HANDLE
+EXTERN "C" EXTERN_FUNCTION _exp_string_impl_copy(_EXP_STRING_HANDLE) RETURNS _EXP_STRING_HANDLE
+EXTERN "C" EXTERN_FUNCTION _exp_string_impl_from_cstr(C_STRING) RETURNS _EXP_STRING_HANDLE
+EXTERN "C" EXTERN_FUNCTION _exp_string_impl_from_count_char(_EXP_STRING_C_INTEGER, C_CHAR) RETURNS _EXP_STRING_HANDLE
+EXTERN "C" EXTERN_PROCEDURE _exp_string_impl_delete(_EXP_STRING_HANDLE)
+EXTERN "C" EXTERN_PROCEDURE _exp_string_impl_assign(_EXP_STRING_HANDLE, _EXP_STRING_HANDLE)
+EXTERN "C" EXTERN_PROCEDURE _exp_string_impl_assign_cstr(_EXP_STRING_HANDLE, C_STRING)
+EXTERN "C" EXTERN_PROCEDURE _exp_string_impl_concat(_EXP_STRING_HANDLE, _EXP_STRING_HANDLE, _EXP_STRING_HANDLE)
+EXTERN "C" EXTERN_PROCEDURE _exp_string_impl_from_int(_EXP_STRING_HANDLE, _EXP_STRING_C_INTEGER)
+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_output(_EXP_STRING_HANDLE)
+
+CLASS _EXP_STRING
+ PUBLIC _HANDLE : _EXP_STRING_HANDLE
+ OVERLOAD PROCEDURE NEW()
+ _HANDLE <- _exp_string_impl_new()
+ ENDPROCEDURE
+ OVERLOAD PROCEDURE NEW(BYREF Other : _EXP_STRING)
+ _HANDLE <- _exp_string_impl_copy(Other._HANDLE)
+ ENDPROCEDURE
+ OVERLOAD PROCEDURE NEW(Text : C_STRING)
+ _HANDLE <- _exp_string_impl_from_cstr(Text)
+ ENDPROCEDURE
+ OVERLOAD PROCEDURE NEW(Count : INTEGER, Ch : C_CHAR)
+ _HANDLE <- _exp_string_impl_from_count_char((_EXP_STRING_C_INTEGER)Count, Ch)
+ ENDPROCEDURE
+ PROCEDURE DELETE()
+ CALL _exp_string_impl_delete(_HANDLE)
+ ENDPROCEDURE
+ OVERLOAD PROCEDURE OPERATOR<-(BYREF Other : _EXP_STRING)
+ CALL _exp_string_impl_assign(_HANDLE, Other._HANDLE)
+ ENDPROCEDURE
+ OVERLOAD PROCEDURE OPERATOR<-(Text : C_STRING)
+ CALL _exp_string_impl_assign_cstr(_HANDLE, Text)
+ ENDPROCEDURE
+ENDCLASS
+
+OVERLOAD FUNCTION OPERATOR&(A : _EXP_STRING, B : _EXP_STRING) RETURNS _EXP_STRING
+ DECLARE Result : _EXP_STRING
+ CALL _exp_string_impl_concat(Result._HANDLE, A._HANDLE, B._HANDLE)
+ RETURN Result
+ENDFUNCTION
+OVERLOAD FUNCTION _EXP_STRING_NUM_TO_STR(Number : INTEGER) RETURNS _EXP_STRING
+ DECLARE Result : _EXP_STRING
+ CALL _exp_string_impl_from_int(Result._HANDLE, (_EXP_STRING_C_INTEGER)Number)
+ RETURN Result
+ENDFUNCTION
+OVERLOAD FUNCTION _EXP_STRING_NUM_TO_STR(Number : REAL) RETURNS _EXP_STRING
+ DECLARE Result : _EXP_STRING
+ CALL _exp_string_impl_from_real(Result._HANDLE, (C_DOUBLE)Number)
+ RETURN Result
+ENDFUNCTION
+FUNCTION _EXP_STRING_STR_TO_NUM(S : _EXP_STRING) RETURNS REAL
+ RETURN (REAL)_exp_string_impl_to_real(S._HANDLE)
+ENDFUNCTION
+FUNCTION _EXP_STRING_LENGTH(S : _EXP_STRING) RETURNS INTEGER
+ RETURN (INTEGER)_exp_string_impl_length(S._HANDLE)
+ENDFUNCTION
+PROCEDURE _EXP_STRING_OUTPUT(S : _EXP_STRING)
+ CALL _exp_string_impl_output(S._HANDLE)
+ENDPROCEDURE