diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-27 13:30:54 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-27 13:30:54 +0000 |
| commit | 24f410430b33aaf1f288b83ea37e18fa959e9d3e (patch) | |
| tree | 1f10b4ad2fae28a54064be270de70454343a4d64 | |
| parent | 0dd0b0908300eee08a06ee51d9eb48b85fd97d74 (diff) | |
docs(memory): describe standard-library allocation and explicit imports
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | AGENTS/ARCH/LAYOUT.md | 2 | ||||
| -rw-r--r-- | AGENTS/CONVENTIONS/CALLS.md | 16 | ||||
| -rw-r--r-- | AGENTS/CONVENTIONS/EXCEPTIONS_AND_UNITS.md | 6 | ||||
| -rw-r--r-- | AGENTS/CONVENTIONS/STRINGS.md | 2 | ||||
| -rw-r--r-- | AGENTS/EXTENDING.md | 4 | ||||
| -rw-r--r-- | AGENTS/PITFALLS/modules-and-stdlib.md | 8 | ||||
| -rw-r--r-- | AGENTS/SUBSYSTEMS.md | 4 | ||||
| -rw-r--r-- | AGENTS/SUBSYSTEMS/CLASS_LIFETIME.md | 5 | ||||
| -rw-r--r-- | AGENTS/SUBSYSTEMS/MEMORY.md | 40 | ||||
| -rw-r--r-- | AGENTS/SUBSYSTEMS/STDLIB.md | 13 | ||||
| -rw-r--r-- | AGENTS/TESTING.md | 2 | ||||
| -rw-r--r-- | doc/cpsc.1.md | 4 | ||||
| -rw-r--r-- | doc/language/cpsc-language-overview.7.md | 11 | ||||
| -rw-r--r-- | doc/language/function/cpsc-function-free.7.md | 4 | ||||
| -rw-r--r-- | doc/language/function/cpsc-function-malloc.7.md | 4 | ||||
| -rw-r--r-- | doc/language/function/cpsc-function-realloc.7.md | 4 | ||||
| -rw-r--r-- | doc/language/keyword/cpsc-keyword-class.7.md | 2 | ||||
| -rw-r--r-- | doc/language/keyword/cpsc-keyword-delete.7.md | 6 | ||||
| -rw-r--r-- | pseudocode-lib/README.md | 26 |
19 files changed, 112 insertions, 51 deletions
diff --git a/AGENTS/ARCH/LAYOUT.md b/AGENTS/ARCH/LAYOUT.md index dc8696e..c2cfee2 100644 --- a/AGENTS/ARCH/LAYOUT.md +++ b/AGENTS/ARCH/LAYOUT.md @@ -23,7 +23,7 @@ | `lib/CodeGen/Designator.cc`, `TypeCheckGen.cc` | TYPE pre-pass, member lookup/calls and lvalue access; type admission and user-kind binary operators | | `lib/CodeGen/CTypeGen.cc` | CodeGen methods for native C scalar conversions, casts, arithmetic and input/output | | `lib/CodeGen/NativeTypeSystem.cc` | Builtin registration, native C type imports/aliases and scalar promotion | -| `lib/CodeGen/MemoryHandler.cc` | Explicit raw memory allocation, resizing and release with a live-address tracking list | +| `lib/CodeGen/MemoryGen.cc` | Keyword NEW/DELETE calls to visible EXTERN helpers in memory.cps; memory.cc owns allocation tracking | | `lib/CodeGen/FileHandler.cc`, `FileRuntimeIO.cc` | File runtime setup/lookup/open and call entry points; read/write/close/EOF helper bodies | | `lib/CodeGen/ArrayHandler.cc`, `ArrayParameters.cc`, `ArrayOutput.cc` | Array allocation/indexing, parameter binding/arguments and whole/subarray output | | `include/cps/CABI.h`, `lib/CodeGen/CABI/ClangABI.cc`, `lib/CodeGen/CABI/Lowering.cc` | EXTERN C ABI: the ABI description, the only file that includes clang CodeGen headers, and the generic lowering of signatures, arguments and returns | diff --git a/AGENTS/CONVENTIONS/CALLS.md b/AGENTS/CONVENTIONS/CALLS.md index 3fc2daa..55b3647 100644 --- a/AGENTS/CONVENTIONS/CALLS.md +++ b/AGENTS/CONVENTIONS/CALLS.md @@ -32,9 +32,10 @@ bridge C void* and nominal pseudocode pointer types. An expression's expected result type filters overloads when present. Overload sets, visibility filtering and exact selection: [SUBSYSTEMS/FUNCTIONS.md](../SUBSYSTEMS/FUNCTIONS.md#signatures-and-call-resolution). -- In all cases, `emitPrototype` rejects names that collide with runtime/libc symbols - (`isReservedRuntimeName`), builtins, or enum values. Signatures retain the first - declaration spelling for LLVM lookup, independently of call-site casing. +- `emitPrototype` rejects builtin and enum names. Ordinary non-EXTERN, non-OVERLOAD + definitions also reject runtime/libc names (`isReservedRuntimeName`); OVERLOAD + definitions have signature-mangled symbols and cannot replace libc symbols. + Signatures retain the first declaration spelling for LLVM lookup, independently of call-site casing. - Methods use `Class.Method` names and a hidden leading receiver address; their FuncSig parameters contain only explicit source parameters. @@ -52,11 +53,12 @@ callback CodeGen injects into FunctionGen). BYVAL arrays copy their buffer at ca entry and clone STRING-bearing elements; BYREF binds the caller's buffer. **Builtins are plain identifiers backed by one table.** Builtins -(EOF/MALLOC/FREE/REALLOC) parse as ordinary calls — no lexer/parser support, and the +(EOF/INT) parse as ordinary calls — no lexer/parser support, and the names are not reserved words. The inline constexpr `Builtins` table in the internal `lib/CodeGen/Builtins.h` ({Name, Arity, ReturnTypeName}) is the single source of truth: `emitCall` checks arity against it before dispatching to the per-builtin emit branches (still an if-chain, ahead of the user-function fallback), and -`getExprTypeInfo` reads return types from it. EOF and the memory builtins consume the -call source line for runtime diagnostics; they touch mutable runtime state and can -throw. +`getExprTypeInfo` reads return types from it. EOF and INT consume the call source +line for runtime diagnostics and can throw. +MALLOC/REALLOC/FREE are ordinary OVERLOAD functions in memory.cps, with no builtin +dispatch or type rules in the compiler. diff --git a/AGENTS/CONVENTIONS/EXCEPTIONS_AND_UNITS.md b/AGENTS/CONVENTIONS/EXCEPTIONS_AND_UNITS.md index deed7ec..8ee97ec 100644 --- a/AGENTS/CONVENTIONS/EXCEPTIONS_AND_UNITS.md +++ b/AGENTS/CONVENTIONS/EXCEPTIONS_AND_UNITS.md @@ -41,8 +41,10 @@ it only on non-library to library calls. Runtime helper line arguments use RuntimeCheck::lineValue too. Compiler diagnostics retain the owning file location. **Default standard library.** The driver extracts embedded std.cps, its imported units -and matching objects to a temporary directory that survives linking/execution. User +and matching objects to a content-keyed cache (or temporary fallback) that survives +linking/execution. User units implicitly import std.cps; normal transitive visibility applies. -no-std -suppresses all default library inputs and objects. Explicit libraries retain the +suppresses all default library inputs and objects. std.cps imports string.cps and +memory.cps; keyword NEW/DELETE require the latter even with -no-std. Explicit libraries retain the ordinary INCLUDE/command-line rules. Source files and objects are embedded by a build-time Perl generator. Saved -S output remains IR only. diff --git a/AGENTS/CONVENTIONS/STRINGS.md b/AGENTS/CONVENTIONS/STRINGS.md index 9bb81cf..d07c217 100644 --- a/AGENTS/CONVENTIONS/STRINGS.md +++ b/AGENTS/CONVENTIONS/STRINGS.md @@ -26,5 +26,5 @@ handles. Records and BYVAL arrays containing STRING recursively copy their string-bearing fields/elements; RETURN and temporary cleanup preserve ownership. C_STRING casts borrow a STRING buffer or construct an owning STRING copy in the other direction. FileHandler owns copied open-file names and frees them on close; READFILE -buffers are copied into STRING and released. Explicit MemoryHandler allocations remain +buffers are copied into STRING and released. Explicit memory-library allocations remain separate from these internal objects. diff --git a/AGENTS/EXTENDING.md b/AGENTS/EXTENDING.md index 5728ac5..358e80e 100644 --- a/AGENTS/EXTENDING.md +++ b/AGENTS/EXTENDING.md @@ -23,7 +23,7 @@ already terminated the block. `Builtins` table in the internal `lib/CodeGen/Builtins.h` (single source of truth — arity checking in `emitCall`, the return type in `getExprTypeInfo`, and the reject-user-redefinition check all read it), then implement IR emission as a method on the fitting handler -(for example MemoryHandler) or inline, and add the name intercept in `CodeGen::emitCall` — null-check every emitted argument before use, like the existing +(for example FileHandler) or inline, and add the name intercept in `CodeGen::emitCall` — null-check every emitted argument before use, like the existing branches do. `emitCall` lives in `ExpressionGen.cc`. Builtins are plain identifiers — nothing is needed in lexer/parser. **New binary operator:** token (if multi-char) → one line in `BinopPrecedence` @@ -80,4 +80,4 @@ also be registered in EmbeddedRunner for static-runtime JIT symbol lookup. `setupExternalFunctions()` (re-declaring the same symbol in two handlers is fine — it dedupes by name). -**Standard-library functions:** define ordinary functions/operators in pseudocode-lib/string.cps with C ABI helpers in string.cc as needed. std.cps imports all public library units. CMake rebuilds and embeds source/object changes; do not add string functions to Builtins.h. Ordinary string literals need STRING.NEW(C_STRING); the compiler bridges OUTPUT/casts/files through C_STR(), INPUT through READ_INPUT(), and READFILE through assignment from C_STRING. +**Standard-library functions:** define ordinary functions/operators in the appropriate pseudocode-lib/*.cps unit with C ABI helpers in the matching .cc as needed. std.cps imports all public library units. CMake rebuilds and embeds source/object changes; do not add standard-library functions to Builtins.h. Memory allocation functions live in memory.cps/memory.cc; only keyword NEW/DELETE need the MemoryGen bridge. Ordinary string literals need STRING.NEW(C_STRING); the compiler bridges OUTPUT/casts/files through C_STR(), INPUT through READ_INPUT(), and READFILE through assignment from C_STRING. diff --git a/AGENTS/PITFALLS/modules-and-stdlib.md b/AGENTS/PITFALLS/modules-and-stdlib.md index 4f6c446..5394d78 100644 --- a/AGENTS/PITFALLS/modules-and-stdlib.md +++ b/AGENTS/PITFALLS/modules-and-stdlib.md @@ -13,11 +13,15 @@ Part of the [pitfalls index](../PITFALLS.md). - GLOBAL accepts only the five primitive scalar types and literal initializers; arrays, user types and computed initializers are rejected. - Own top-level constants remain positional, imported constants do not. -- **Default standard library.** std.cps and its imported STRING library are embedded +- **Default standard library.** std.cps and its imported STRING and memory libraries are embedded and automatically linked. - Use -no-std before explicitly supplying a replacement STRING class/library; otherwise duplicate definitions fail. - Ordinary literals require a visible STRING class with NEW(C_STRING). - C_TYPE/INCLUDE/EXTERN syntax strings are parser metadata and do not construct STRING. - - -S emits IR only; manual linking needs string.o and the C++ runtime. + - Keyword NEW/DELETE and MALLOC/REALLOC/FREE require memory.cps; -no-std users + must explicitly import it. Ordinary constructor/destructor methods still work + without it. + - -S emits IR only; default-library manual linking needs string.o, memory.o and + the C++ runtime. diff --git a/AGENTS/SUBSYSTEMS.md b/AGENTS/SUBSYSTEMS.md index d3a7dba..4753ab1 100644 --- a/AGENTS/SUBSYSTEMS.md +++ b/AGENTS/SUBSYSTEMS.md @@ -18,8 +18,8 @@ Deep-dives on the CodeGen helper subsystems, split by topic under `SUBSYSTEMS/`. - [Runtime checks and exceptions](SUBSYSTEMS/RUNTIME_CHECKS_EXCEPTIONS.md): `RuntimeCheck`, TRY/CATCH/THROW lowering, cleanup pads, EH runtime per platform. - [Files](SUBSYSTEMS/FILES.md): `FileHandler` text-file runtime and open-file table. -- [Explicit memory](SUBSYSTEMS/MEMORY.md): `MemoryHandler` allocation tracking, - MALLOC/REALLOC/FREE. +- [Explicit memory](SUBSYSTEMS/MEMORY.md): standard-library MALLOC/REALLOC/FREE, + allocation tracking and keyword NEW/DELETE bridging. - [Standard library](SUBSYSTEMS/STDLIB.md): `pseudocode-lib/`, embedding, STRING class. - [Templates](SUBSYSTEMS/TEMPLATES.md): template declarations, resolution, cloning, instantiation, body emission. diff --git a/AGENTS/SUBSYSTEMS/CLASS_LIFETIME.md b/AGENTS/SUBSYSTEMS/CLASS_LIFETIME.md index eb7f039..98693e5 100644 --- a/AGENTS/SUBSYSTEMS/CLASS_LIFETIME.md +++ b/AGENTS/SUBSYSTEMS/CLASS_LIFETIME.md @@ -18,7 +18,7 @@ Part of the [subsystem notes](../SUBSYSTEMS.md). Builds on [classes](CLASSES.md) class parameters; `symbolAddress` loads their current object address for all value, lvalue, address-of, receiver and BYREF paths. Field aliases, this and BYREF parameters bind addresses directly. -- Assignment-only `NewExprAST` uses checked MemoryHandler allocation (at least one byte +- Assignment-only `NewExprAST` uses checked memory-library allocation (at least one byte for method-only classes), zero initialization and construction, then rebinds reference slots or copies into other destinations. - Ordinary assignment invokes an exact member OPERATOR<- when available, otherwise it @@ -31,7 +31,8 @@ Part of the [subsystem notes](../SUBSYSTEMS.md). Builds on [classes](CLASSES.md) ordinary DELETE method first, then fields in reverse declaration order. Explicit DELETE method calls remain ordinary calls without field recursion. - Keyword DELETE resolves a class lvalue, validates its allocation start through - MemoryHandler before any destruction, destroys it, then releases it through FREE; + the memory-library validator before any destruction, destroys it, then releases it + through the same runtime as FREE; aliases remain dangling. - Stack lifetimes use a per-function `StackObjects` list saved/restored around function emission. DECLARE and BYVAL copies share ownership registration, including arrays and diff --git a/AGENTS/SUBSYSTEMS/MEMORY.md b/AGENTS/SUBSYSTEMS/MEMORY.md index 8b0ccfc..40cfe9e 100644 --- a/AGENTS/SUBSYSTEMS/MEMORY.md +++ b/AGENTS/SUBSYSTEMS/MEMORY.md @@ -3,29 +3,39 @@ Part of the [subsystem notes](../SUBSYSTEMS.md). Related: [class lifetime](CLASS_LIFETIME.md). -**Explicit memory** (`MemoryHandler`): lazily emits internal allocation/find/release/ -resize helpers and a linked list of live allocation start addresses. +**Explicit memory** lives in `pseudocode-lib/memory.cps` and `memory.cc`. +MALLOC/REALLOC/FREE are ordinary OVERLOAD functions calling `_memory_impl_*` +EXTERN "C" helpers. `lib/CodeGen/MemoryGen.cc` only bridges keyword NEW/DELETE to +visible helper declarations, checking their signatures and using FunctionGen's +C ABI lowering, library call-line hook and exception-aware calls. ## Tracking -- Explicit MALLOC/REALLOC and keyword NEW allocations enter the list; STRING/ARRAY - internals are not tracked here and keep their own ownership. -- Helpers use RuntimeCheck and ExceptionHandler, including source-line arguments and - per-function unwind preparation. -- Sizes accept INTEGER and C integers and convert to native size_t. +- memory.cc owns a linked list of live allocation start addresses. Explicit + MALLOC/REALLOC and keyword NEW share it; STRING/ARRAY internals keep their own + ownership outside the list. +- Errors print the existing reason with __cps_user_line and throw 0. The #LIB call + hook supplies the user line, including keyword NEW/DELETE helper calls. +- Sizes accept INTEGER and every supported C integer (including _Bool) through + ordinary overloads. Wrappers explicitly cast to unsigned long long; C++ converts + that value to native size_t, preserving the old integer conversion behavior. +- std.cps imports memory.cps. With -no-std, explicitly import and supply memory.cps, + including for keyword NEW/DELETE. Missing visible helpers are compiler errors. ## Operations -- `emitValidate` always calls the find helper, including for null, so keyword DELETE +- `_memory_impl_validate` always searches, including for null, so keyword DELETE validates before running destructors. -- FREE validates non-null addresses, unlinks and frees the tracking node, releases the - block and returns the original address. +- FREE validates non-null addresses, unlinks the tracking node, releases the block + and node, and returns the original address. Null is returned without searching. - Zero-byte allocation returns null. -- REALLOC validates non-null addresses before its zero-size release path; null behaves - as MALLOC. Positive-size resizing updates the node only after success, leaving the old - block and record intact on failure. -- Node allocation precedes the user allocation; if the latter fails, its node is freed - before the diagnostic and anonymous throw. +- REALLOC validates non-null addresses before its zero-size release path; null + behaves as MALLOC. Positive-size resizing updates the node only after success, + leaving the old block and record intact on failure. +- Node allocation precedes the user allocation; if the latter fails, its node is + freed before the diagnostic and anonymous throw. +- Keyword NEW reserves at least one byte for method-only classes. NEW constructs + objects and DELETE destroys them; FREE/REALLOC never invoke destruction. ## Limitation diff --git a/AGENTS/SUBSYSTEMS/STDLIB.md b/AGENTS/SUBSYSTEMS/STDLIB.md index d43899f..6c7b14c 100644 --- a/AGENTS/SUBSYSTEMS/STDLIB.md +++ b/AGENTS/SUBSYSTEMS/STDLIB.md @@ -15,10 +15,19 @@ import rules: [CONVENTIONS/EXCEPTIONS_AND_UNITS.md](../CONVENTIONS/EXCEPTIONS_AN reused when identical, otherwise published by atomic rename; the cache is never deleted, so a killed run leaks nothing. Only if no cache directory is usable does it fall back to a temporary `cpsc-std` directory removed on exit. The driver - implicitly imports std.cps unless -no-std is set. std.cps imports string.cps. + implicitly imports std.cps unless -no-std is set. std.cps imports string.cps and memory.cps. - Source/object resources are embedded in installed/released cpsc, which needs no separate library directory; manually linking saved IR still requires the matching - string.o and the C++ runtime. + string.o, memory.o and the C++ runtime for default-library builds. + +## Explicit memory + +- memory.cps defines ordinary OVERLOAD MALLOC/REALLOC/FREE wrappers over memory.cc + C ABI helpers. Sizes support INTEGER and all supported C integers. +- Keyword NEW/DELETE call visible EXTERN helpers through MemoryGen and FunctionGen; + no compiler allocation list or memory builtin dispatch remains. With -no-std, + explicitly import memory.cps, including when only keyword NEW/DELETE is needed. +- Runtime errors print __cps_user_line and throw 0. See [MEMORY.md](MEMORY.md). ## STRING and I/O bridging diff --git a/AGENTS/TESTING.md b/AGENTS/TESTING.md index f3628d2..c00843c 100644 --- a/AGENTS/TESTING.md +++ b/AGENTS/TESTING.md @@ -24,4 +24,4 @@ Perl generators use Random.pm's SHA-256 sequence with explicit big-endian extrac Before committing a test change, build the affected references and run the affected CTest cases. Compiler defects may fail: inspect retained diagnostics and document the failure accurately. Workflow changes follow the commit checks in [ARCH/NIGHTLY.md](ARCH/NIGHTLY.md). No compiler implementation changes belong in a tests-only task. -The explicit STRING library integration fixture lives in `tests/library/exp-string`. CMake copies it to the build tree as `test-cases/i/exp-string`, where relative source paths reach the built library and its object file. It passes -no-std to avoid loading a second library copy. Manifests may supply compiler_args for every native/IR/runner compiler invocation. It uses the ordinary native/runner harness and appears as `i/exp-string` in CTest. +The explicit library integration fixtures live in `tests/library/exp-string` and `tests/library/exp-memory`. CMake copies them to the build tree under `test-cases/i/`, where relative source paths reach the built libraries and their objects. Both pass -no-std to avoid loading a second library copy. exp-string imports std.cps, including memory.cps for its keyword NEW/DELETE; exp-memory imports only memory.cps and checks C integer sizes and shared tracking with NEW/DELETE. Manifests may supply compiler_args for every native/IR/runner compiler invocation. Both use the ordinary native/runner harness and appear as `i/exp-string` and `i/exp-memory` in CTest. diff --git a/doc/cpsc.1.md b/doc/cpsc.1.md index caa829c..e0e92e0 100644 --- a/doc/cpsc.1.md +++ b/doc/cpsc.1.md @@ -20,7 +20,7 @@ Each input is a compilation unit. Use top-level `INCLUDE "lib.cps"` to import an Exactly one file may contain top-level executable statements (including top-level DECLARE). Alternatively, define a parameterless `FUNCTION MAIN RETURNS INTEGER` in one file and have no top-level executable statements anywhere. Builds containing only definitions and no MAIN fail with `error: no main program`. GLOBAL blocks declare shared primitive variables. INCLUDE, GLOBAL and MAIN entry points are compiler extensions beyond the Cambridge guide. -The embedded standard library is loaded and linked automatically. Its std.cps imports string.cps, which defines the STRING class and ordinary string functions. No extra files are needed for default compilation. With **-no-std**, supply any required library inputs explicitly; ordinary string literals require a visible STRING class. A literal with an adjacent uppercase C suffix, such as `"hello"C`, has type C_STRING and does not require that class. +The embedded standard library is loaded and linked automatically. Its std.cps imports string.cps, which defines the STRING class and ordinary string functions, and memory.cps, which provides MALLOC/REALLOC/FREE and the allocation runtime used by keyword NEW/DELETE. No extra files are needed for default compilation. With **-no-std**, supply any required library inputs explicitly; ordinary string literals require a visible STRING class, and keyword NEW/DELETE require memory.cps. A literal with an adjacent uppercase C suffix, such as `"hello"C`, has type C_STRING and does not require that class. # OPTIONS @@ -31,7 +31,7 @@ The embedded standard library is loaded and linked automatically. Its std.cps im : Save to the specified path. Without **-S**, save a native executable; with **-S**, save LLVM IR. Use the path exactly as given; its extension does not select the output format. May be specified only once. With **-r**, keep this file even if execution fails. **-S** -: Save textual LLVM IR instead of a native executable. Without **-o**, use the entry source filename with a `.ll` extension beside the source file. May be combined with **-r** to save IR and run the program. Manually linking saved IR that uses the standard library requires the matching string.o and C++ runtime; native output and **-r** supply them automatically. +: Save textual LLVM IR instead of a native executable. Without **-o**, use the entry source filename with a `.ll` extension beside the source file. May be combined with **-r** to save IR and run the program. Manually linking saved IR that uses the standard library requires the matching string.o, memory.o and C++ runtime; native output and **-r** supply them automatically. **-r** : Run the compiled program with the runner selected at build time (see EXECUTION MODES). Save output first when **-S** or **-o** is also present; otherwise do not save a file. The program inherits stdin, stdout and stderr; `INPUT` can read terminal or piped input. diff --git a/doc/language/cpsc-language-overview.7.md b/doc/language/cpsc-language-overview.7.md index fcdb4b5..2c2019c 100644 --- a/doc/language/cpsc-language-overview.7.md +++ b/doc/language/cpsc-language-overview.7.md @@ -80,14 +80,19 @@ These ordinary functions and the STRING class come from the embedded standard li - [cpsc-function-num_to_str(7)](function/cpsc-function-num_to_str.7.md): convert a number to text. - [cpsc-function-str_to_num(7)](function/cpsc-function-str_to_num.7.md): convert text to a real number. -# BUILT-IN FUNCTIONS +# MEMORY LIBRARY FUNCTIONS + +These ordinary extension functions come from memory.cps, imported by std.cps automatically. Keyword NEW/DELETE use the same allocation runtime. With **-no-std**, import and supply memory.cps explicitly. -- [cpsc-function-eof(7)](function/cpsc-function-eof.7.md): test for the end of a text file. -- [cpsc-function-int(7)](function/cpsc-function-int.7.md): take the integer part of a number. - [cpsc-function-malloc(7)](function/cpsc-function-malloc.7.md): allocate raw memory. - [cpsc-function-realloc(7)](function/cpsc-function-realloc.7.md): resize an explicit allocation. - [cpsc-function-free(7)](function/cpsc-function-free.7.md): release an explicit allocation. +# BUILT-IN FUNCTIONS + +- [cpsc-function-eof(7)](function/cpsc-function-eof.7.md): test for the end of a text file. +- [cpsc-function-int(7)](function/cpsc-function-int.7.md): take the integer part of a number. + # UNSUPPORTED FEATURES DATE, SET types and DEFINE, random-file operations (RANDOM/SEEK/GETRECORD/PUTRECORD), INT, RAND, whole-array assignment or return, array fields, and class inheritance (INHERITS/SUPER). diff --git a/doc/language/function/cpsc-function-free.7.md b/doc/language/function/cpsc-function-free.7.md index 366b317..ef4b72e 100644 --- a/doc/language/function/cpsc-function-free.7.md +++ b/doc/language/function/cpsc-function-free.7.md @@ -12,12 +12,14 @@ FREE(pointer) # DESCRIPTION -FREE is a compiler extension. Its argument and return type are C `void*`. Explicitly cast other pointer types to a `void*` alias before passing them. A null pointer is accepted and returned. A non-null pointer must be the start of an active explicit MALLOC, REALLOC or keyword NEW allocation; internal STRING/ARRAY storage, stack addresses, interior addresses and already released allocations are rejected with a source-line diagnostic on stderr and an anonymous exception. +FREE is an extension provided by the memory.cps standard-library unit. Its argument and return type are C `void*`. Explicitly cast other pointer types to a `void*` alias before passing them. A null pointer is accepted and returned. A non-null pointer must be the start of an active explicit MALLOC, REALLOC or keyword NEW allocation; internal STRING/ARRAY storage, stack addresses, interior addresses and already released allocations are rejected with a source-line diagnostic on stderr and an anonymous exception. FREE returns its input address after releasing the allocation. It does not clear the caller's variable. The returned address and all aliases are invalid for memory access. Calling FREE again on that address throws unless a subsequent allocation has reused the address. Tracking cannot distinguish stale aliases once an address is reused. The result can be discarded with a standalone call. No user destructor is called. Use keyword DELETE on a class object to destroy it and its fields before releasing its allocation. +The default std.cps imports memory.cps automatically. With **-no-std**, explicitly INCLUDE memory.cps and pass it as a compiler input; its INCLUDE_OBJ links memory.o for native output and execution. Manual linking of saved IR requires the matching library objects and C++ runtime. + # EXAMPLE ```text diff --git a/doc/language/function/cpsc-function-malloc.7.md b/doc/language/function/cpsc-function-malloc.7.md index 077e17f..6a2c272 100644 --- a/doc/language/function/cpsc-function-malloc.7.md +++ b/doc/language/function/cpsc-function-malloc.7.md @@ -12,12 +12,14 @@ MALLOC(bytes) # DESCRIPTION -MALLOC is a compiler extension returning a C `void*` to the beginning of an uninitialized allocation. The size is in bytes and accepts INTEGER or a C integer, converted to the host size_t using C integer conversion rules. Negative values are not separately rejected. MALLOC(0) returns null without allocating. A nonzero allocation failure prints the source line and reason to stderr, then throws an anonymous exception catchable with TRY/CATCH. Allocation tracking failures behave the same way. +MALLOC is an extension provided by the memory.cps standard-library unit returning a C `void*` to the beginning of an uninitialized allocation. The size is in bytes and accepts INTEGER or a C integer, converted to the host size_t using C integer conversion rules. Negative values are not separately rejected. MALLOC(0) returns null without allocating. A nonzero allocation failure prints the source line and reason to stderr, then throws an anonymous exception catchable with TRY/CATCH. Allocation tracking failures behave the same way. Declare a `void*` alias with C_TYPE and explicitly cast the result to a C or pseudocode pointer before dereferencing. MALLOC does not initialize fields or call constructors. Keyword NEW uses the same tracked allocation path, then initializes and constructs the class object. The caller of MALLOC must supply enough bytes and initialize values before reading them. User memory is not automatically released. Explicit MALLOC/REALLOC and keyword NEW allocations are tracked. Internal STRING and ARRAY buffers remain outside this ownership system. Tracking validates FREE, REALLOC and keyword DELETE addresses, not memory accesses, bounds or stale aliases after address reuse. +The default std.cps imports memory.cps automatically. With **-no-std**, explicitly INCLUDE memory.cps and pass it as a compiler input; its INCLUDE_OBJ links memory.o for native output and execution. Manual linking of saved IR requires the matching library objects and C++ runtime. + # EXAMPLE ```text diff --git a/doc/language/function/cpsc-function-realloc.7.md b/doc/language/function/cpsc-function-realloc.7.md index 7b29c45..03c5bef 100644 --- a/doc/language/function/cpsc-function-realloc.7.md +++ b/doc/language/function/cpsc-function-realloc.7.md @@ -12,7 +12,7 @@ REALLOC(pointer, bytes) # DESCRIPTION -REALLOC is a compiler extension returning C `void*`. The pointer argument must also be C `void*`; explicitly cast other pointer types. The size accepts INTEGER or a C integer and converts to host size_t, just as MALLOC does. +REALLOC is an extension provided by the memory.cps standard-library unit returning C `void*`. The pointer argument must also be C `void*`; explicitly cast other pointer types. The size accepts INTEGER or a C integer and converts to host size_t, just as MALLOC does. A null pointer behaves as MALLOC(bytes). A non-null pointer must start an active tracked MALLOC, REALLOC or keyword NEW allocation, even when bytes is zero. Invalid addresses print the source line and reason to stderr and throw an anonymous exception before touching the memory or allocation record. Resizing or releasing memory with REALLOC does not invoke constructors or destructors. @@ -20,6 +20,8 @@ For a valid pointer and zero bytes, REALLOC releases the block and returns null. On nonzero allocation failure, REALLOC prints the source line and reason and throws an anonymous exception. The original allocation and its tracking record remain valid. In `p <- REALLOC(p, bytes)`, assignment occurs only on success, so a CATCH handler can still use or release the old p. A successful resize updates the existing record without allocating a new tracking node. Internal STRING/ARRAY buffers cannot be resized with this function. +The default std.cps imports memory.cps automatically. With **-no-std**, explicitly INCLUDE memory.cps and pass it as a compiler input; its INCLUDE_OBJ links memory.o for native output and execution. Manual linking of saved IR requires the matching library objects and C++ runtime. + # EXAMPLE ```text diff --git a/doc/language/keyword/cpsc-keyword-class.7.md b/doc/language/keyword/cpsc-keyword-class.7.md index dffd4a1..2a713c0 100644 --- a/doc/language/keyword/cpsc-keyword-class.7.md +++ b/doc/language/keyword/cpsc-keyword-class.7.md @@ -42,7 +42,7 @@ A constructor is a PROCEDURE named NEW, following guide section 10.2. It may be An `OVERLOAD PROCEDURE NEW(BYREF Other : ClassName)` defines a copy constructor. BYVAL class lvalue arguments and RETURN of class lvalues invoke it; a same-class BYVAL constructor is rejected. Classes without one retain bitwise copying for fields without STRING ownership. Records and BYVAL arrays recursively clone STRING-bearing fields or elements. Other owning class fields retain the existing shallow-copy limitations. Class results transfer ownership directly into BYVAL arguments, RETURN and ordinary assignment without an assignment overload. Discarded results and temporary receivers live until the statement ends, including exception exits. Ordinary user BYREF calls still require bare variables; constructor calls can bind temporaries. -The keyword NEW is allowed only as the complete right side of assignment: `Target <- NEW ClassName`, `Target <- NEW ClassName()` or `Target <- NEW ClassName(arguments)`. Target must have exactly the named class type. NEW uses the checked MALLOC allocation path, zeroes storage and constructs fields before calling NEW. A method-only class receives at least one byte of heap storage so its object address is non-null. Allocation failure reports a runtime error and throws; constructor exceptions also propagate to TRY/CATCH. Private constructor access and argument checks follow ordinary member-call rules. +The keyword NEW is allowed only as the complete right side of assignment: `Target <- NEW ClassName`, `Target <- NEW ClassName()` or `Target <- NEW ClassName(arguments)`. Target must have exactly the named class type. NEW requires the memory.cps standard-library unit, imported by default; with **-no-std**, import and supply it explicitly. NEW uses the checked MALLOC allocation path, zeroes storage and constructs fields before calling NEW. A method-only class receives at least one byte of heap storage so its object address is non-null. Allocation failure reports a runtime error and throws; constructor exceptions also propagate to TRY/CATCH. Private constructor access and argument checks follow ordinary member-call rules. When Target is a declared class variable, including a function local or BYVAL parameter, NEW rebinds that variable to the heap object. No `^` dereference is needed to access it. Address-of, BYREF calls and method calls use its current object. Pointers taken before rebinding continue to refer to the previous object. Ordinary `A <- B` assigns into A's current object without rebinding A: it calls a matching member OPERATOR<- when defined, otherwise it copies the same-class value. See [cpsc-keyword-operator(7)](cpsc-keyword-operator.7.md). BYVAL parameters own their copied or transferred value and can rebind independently. diff --git a/doc/language/keyword/cpsc-keyword-delete.7.md b/doc/language/keyword/cpsc-keyword-delete.7.md index a45d5fa..c9165cc 100644 --- a/doc/language/keyword/cpsc-keyword-delete.7.md +++ b/doc/language/keyword/cpsc-keyword-delete.7.md @@ -26,9 +26,11 @@ Destructors, keyword DELETE and automatic destruction are compiler extensions; t An explicit `Object.DELETE()`, `CALL Object.DELETE()` or `this.DELETE()` is an ordinary method call. It calls only the method, without automatically destroying fields or releasing memory. It does not end the object's automatic lifetime. -The statement `DELETE Object` requires an addressable class object. It first checks that the address is the start of an active tracked heap allocation, including allocations created by keyword NEW. Stack objects, internal array storage, interior addresses and previously released allocations fail with a source-line runtime diagnostic and an anonymous exception before any destructor runs. Address reuse can make a stale alias indistinguishable from a current allocation. +The statement `DELETE Object` requires an addressable class object and the memory.cps standard-library unit. It first checks that the address is the start of an active tracked heap allocation, including allocations created by keyword NEW. Stack objects, internal array storage, interior addresses and previously released allocations fail with a source-line runtime diagnostic and an anonymous exception before any destructor runs. Address reuse can make a stale alias indistinguishable from a current allocation. -After validation, DELETE calls the object's DELETE method if present, then recursively destroys its class-valued fields in reverse declaration order, including through record fields, and releases the allocation through FREE. The variable and all aliases remain dangling. If destruction throws, memory release is not reached. Heap objects are never automatically destroyed. +Keyword DELETE uses memory.cps, imported by default; with **-no-std**, import and supply it explicitly. Ordinary DELETE method calls and automatic destruction do not require the memory library. + +After validation, DELETE calls the object's DELETE method if present, then recursively destroys its class-valued fields in reverse declaration order, including through record fields, and releases the allocation through the same memory-library runtime as FREE. The variable and all aliases remain dangling. If destruction throws, memory release is not reached. Heap objects are never automatically destroyed. Automatic destruction (RAII) applies to original storage created by DECLARE, including main-level declarations, arrays and records containing class values, and to BYVAL copies containing class values. Destruction occurs in reverse declaration order on RETURN, at the end of a function or procedure, and at normal program end. Array elements are destroyed in reverse flat element order. Block exit alone does not destroy these function-scoped lifetimes. A declaration executed again first destroys its previous live incarnation, then zeroes and constructs the original storage again. diff --git a/pseudocode-lib/README.md b/pseudocode-lib/README.md index a12620a..2fc4e8e 100644 --- a/pseudocode-lib/README.md +++ b/pseudocode-lib/README.md @@ -1,6 +1,6 @@ # Standard pseudocode library -`cpsc` embeds `std.cps`, its imported `string.cps`, and the matching `string.o`. Programs use STRING and its functions without INCLUDE statements or extra command-line inputs: +`cpsc` embeds `std.cps`, its imported `string.cps` and `memory.cps`, and the matching `string.o` and `memory.o`. Programs use STRING, its functions and the memory functions without INCLUDE statements or extra command-line inputs: ```text DECLARE Greeting : STRING @@ -17,10 +17,30 @@ OUTPUT LENGTH("hello") ```sh cmake --build build -build/cpsc -no-std prog.cps build/pseudocode-lib/std.cps build/pseudocode-lib/string.cps -r +build/cpsc -no-std prog.cps build/pseudocode-lib/std.cps build/pseudocode-lib/string.cps build/pseudocode-lib/memory.cps -r ``` -INCLUDE paths are relative to the including source. Adjust the example paths when the program is elsewhere. Native compilation and `-r` automatically link the required library object. `-S` only emits IR; manually linking that IR requires `build/pseudocode-lib/string.o` and a compatible C++ runtime. +INCLUDE paths are relative to the including source. Adjust the example paths when the program is elsewhere. Native compilation and `-r` automatically link the required library objects. `-S` only emits IR; manually linking default-library IR requires `build/pseudocode-lib/string.o`, `build/pseudocode-lib/memory.o` and a compatible C++ runtime. + +`memory.cps` provides ordinary `MALLOC(bytes)`, `REALLOC(pointer, bytes)` and `FREE(pointer)` functions. Sizes accept INTEGER or any supported C integer, including _Bool, and convert to native size_t; pointer arguments and all results use C `void*`. Zero-byte allocation returns null. FREE(null) returns null; other FREE calls return the released address. REALLOC(null, size) allocates, and REALLOC(pointer, 0) validates and frees the allocation, returning null. Failed nonzero resizing leaves the original block valid. Invalid addresses and allocation failures print the user call line and throw an anonymous exception. + +These functions and keyword NEW/DELETE share one allocation list. NEW constructs objects; DELETE validates before destruction; FREE and REALLOC perform no destruction. STRING/ARRAY internal buffers are outside this list. Addresses must start active allocations; tracking cannot distinguish stale aliases after address reuse or validate memory accesses. + +With `-no-std`, keyword NEW/DELETE also require the memory library. A program can import only memory.cps, without STRING: + +```text +INCLUDE "build/pseudocode-lib/memory.cps" +TYPE Raw = C_TYPE("void*") +DECLARE P : Raw +P <- MALLOC(8) +FREE(P) +``` + +```sh +build/cpsc -no-std prog.cps build/pseudocode-lib/memory.cps -r +``` + +Manual linking of IR from this memory-only build requires memory.o and the C++ runtime. STRING is an owning class backed by `std::string`. Constructors accept no arguments, another STRING, C_STRING, or `(INTEGER count, C_CHAR character)`. Copies and assignments are independent, including STRING fields inside records and BYVAL arrays. `_HANDLE` is public for implementation access; do not modify or free it. |
