From c372c08dc940db58f1da9cadeb64b4cb3c837704 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Sat, 17 Oct 2026 06:58:13 +0000 Subject: fix(classes): preserve method-only heap objects and document NEW Allocate at least one byte for method-only classes so their heap addresses remain usable through pointers. Complete constructor diagnostics, field-order and exception coverage, document construction and rebinding, and highlight NEW. Co-Authored-By: Claude Opus 5.5 --- AGENTS/CONVENTIONS.md | 4 +++- AGENTS/PITFALLS.md | 12 ++++++++++-- AGENTS/SUBSYSTEMS.md | 20 +++++++++++++++++--- 3 files changed, 30 insertions(+), 6 deletions(-) (limited to 'AGENTS') diff --git a/AGENTS/CONVENTIONS.md b/AGENTS/CONVENTIONS.md index 83e73e2..87a95b7 100644 --- a/AGENTS/CONVENTIONS.md +++ b/AGENTS/CONVENTIONS.md @@ -97,7 +97,9 @@ and INPUT STRING buffers — declared in `SetupExternalFunctions`, never fetched bare `getFunction("malloc")`. **One symbol namespace, one table.** `Symbols` (name → `SymbolInfo{Storage, -TypeName, IsArray, ConstantValue, ScopeID}`) in CodeGen is the only symbol table. +TypeName, IsArray, ConstantValue, ScopeID, IsReference}`) in CodeGen is the only symbol table. +Use `symbolAddress` for an object address: class variables and BYVAL class parameters +store their current object address in a reference slot (`IsReference`). A non-null ConstantValue denotes a read-only CONSTANT with no Storage. Read it through `emitExpr`; all writable/address-taking paths must reject it through `requireWritable`. Register variables through `registerSymbol()` (parameters are diff --git a/AGENTS/PITFALLS.md b/AGENTS/PITFALLS.md index ec5d034..6ef422b 100644 --- a/AGENTS/PITFALLS.md +++ b/AGENTS/PITFALLS.md @@ -87,6 +87,14 @@ test programs. `this.Method(...)`; unqualified calls remain global. Parameters and local declarations shadowing fields warn without failing compilation. Method-only classes are allowed; empty classes and array fields remain unsupported. + PROCEDURE NEW is an ordinary case-insensitive member, also called automatically + after zero initialization by DECLARE and assignment-only keyword NEW. Fields and + array elements recursively require parameterless construction before the outer NEW. + Class variables and BYVAL class parameters use reference slots: keyword NEW rebinds + them, while ordinary assignment copies into their current object. Fields, array + elements, BYREF, this and pointer dereferences receive a value copy from NEW; + the temporary allocation leaks. Old address-of pointers retain the previous object. + Private access and ordinary argument checks apply to automatic construction too. - **Exception extensions.** TRY requires exactly one parameterless CATCH and ENDTRY. Bare THROW raises a new anonymous exception even inside CATCH; there is @@ -114,8 +122,8 @@ SET types (`SET`/`DEFINE` are reserved with dedicated errors), random files (OPENFILE...FOR RANDOM/SEEK/GETRECORD/PUTRECORD — TYPE is done, so these are unblocked now; the RANDOM keyword is reserved and gives a dedicated parse error), DATE, string escape sequences, -array-typed record fields, whole-array RETURN, class constructors/destructors, -NEW and class inheritance. Compiler fixtures now live in `tests/` (see TESTING.md). +array-typed record fields, whole-array RETURN, destructors/DELETE +and class inheritance (INHERITS/SUPER). Compiler fixtures now live in `tests/` (see TESTING.md). Nightly CI runs the compiler suites, packaged EMBEDDED smoke checks and existing plugin tests. The initial standard conflicts and missing diagnostic locations are fixed on Linux. diff --git a/AGENTS/SUBSYSTEMS.md b/AGENTS/SUBSYSTEMS.md index b21386d..1d13c57 100644 --- a/AGENTS/SUBSYSTEMS.md +++ b/AGENTS/SUBSYSTEMS.md @@ -78,8 +78,22 @@ FunctionGen binds field aliases and `this` to the incoming receiver storage befo binding explicit parameters. CodeGen saves/restores `CurrentClass` around each function body; unqualified calls still resolve globally. Local declarations and parameters may shadow fields with a source-line warning; `this.Field` remains -explicit. `this` cannot be redeclared within methods. Constructors and language-level -inheritance remain unsupported. +explicit. `this` cannot be redeclared within methods. `TypeInfo::IsClass` distinguishes +classes from records without changing their shared LLVM representation. + +`ConstructorGen.cc` emits recursive field construction in declaration order followed +by the ordinary NEW method, sharing `emitMethodCall` access checks, argument +marshalling and exception-aware calls. DECLARE zeroes its original storage on every +execution; arrays loop over all flat elements and default-construct each one. +Constructor argument lists are class-only, and field/array defaults require a +parameterless NEW. Explicit NEW method calls do not reconstruct fields. +`SymbolInfo::IsReference` marks a pointer slot for declared class variables and BYVAL +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 for method-only classes), zero initialization and +construction, then rebinds reference slots or copies into other destinations. Ordinary assignment always copies. Heap lifetimes +remain unmanaged; destructors, DELETE and INHERITS/SUPER are unsupported. **Runtime checks** (`RuntimeCheck`): array bounds, file misuse, enum ranges, null dereferences and array-parameter bounds contracts are checked at their emit sites. @@ -123,4 +137,4 @@ malloc/realloc buffer per line and strips one trailing `\r`; fopen modes are tex nothing is declared or emitted eagerly. Helper bodies are built with the *shared* Builder (RuntimeCheck emits through the same one), saving/restoring the insert block. -**Explicit memory** (`MemoryHandler`): lazily emits internal allocation/find/release/resize helpers and a linked list of live allocation start addresses. Only explicit MALLOC/REALLOC allocations enter the list; STRING/ARRAY internals retain their existing ownership. FREE validates non-null addresses, unlinks and frees the tracking node, releases the block and returns the original address. 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. 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. Address reuse can make stale aliases indistinguishable from current allocations; dereferences are not checked against this list. +**Explicit memory** (`MemoryHandler`): lazily emits internal allocation/find/release/resize helpers and a linked list of live allocation start addresses. Explicit MALLOC/REALLOC and keyword NEW allocations enter the list; STRING/ARRAY internals retain their existing ownership. FREE validates non-null addresses, unlinks and frees the tracking node, releases the block and returns the original address. 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. 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. Address reuse can make stale aliases indistinguishable from current allocations; dereferences are not checked against this list. -- cgit v1.3.1-4-g156e