From 1ed0e276a37d39386b22b08c1f9e575a8f8f8725 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Tue, 20 Oct 2026 01:31:47 +0000 Subject: docs(man): correct class lifetime and allocation support Co-Authored-By: Claude Opus 5.5 --- doc/cpsc.1.md | 4 ++-- doc/language/function/cpsc-function-malloc.7.md | 4 ++-- doc/language/function/cpsc-function-realloc.7.md | 2 +- doc/language/keyword/cpsc-keyword-case.7.md | 2 +- doc/language/keyword/cpsc-keyword-class.7.md | 10 +++++----- doc/language/keyword/cpsc-keyword-delete.7.md | 4 ++-- doc/language/keyword/cpsc-keyword-operator.7.md | 15 +++++++++------ doc/language/keyword/cpsc-keyword-try.7.md | 4 +++- doc/language/keyword/cpsc-keyword-while.7.md | 2 +- 9 files changed, 26 insertions(+), 21 deletions(-) (limited to 'doc') diff --git a/doc/cpsc.1.md b/doc/cpsc.1.md index 3fe1778..566e3a1 100644 --- a/doc/cpsc.1.md +++ b/doc/cpsc.1.md @@ -16,7 +16,7 @@ Compile one or more pseudocode source files to a native executable, or to textua Without **-o**, save beside the entry source file, replacing its extension with `.exe` on Windows or `.out` elsewhere for an executable, or `.ll` for IR. With **-r** alone, run without saving a file. -Each input is a compilation unit. Use top-level `INCLUDE "lib.cps"` to import another input's exported definitions, including its transitive imports. Paths are relative to the including source; every included file must also appear on the command line. Repeated includes and include cycles are harmless. Giving the same input twice, including symbolic or hard links, is an error. Duplicate definitions across files are errors even if the files do not include each other. +Each input is a compilation unit. Use top-level `INCLUDE "lib.cps"` to import another input's exported definitions, including its transitive imports. Paths are relative to the including source; every included file must also appear on the command line. Repeated includes and include cycles are harmless. Giving the same input twice, including symbolic or hard links, is an error. Duplicate definitions across files are errors even if the files do not include each other; distinct parameter signatures may share a name when every definition specifies OVERLOAD. 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. @@ -116,7 +116,7 @@ Compiler diagnostics go to stderr. With multiple input files, lexer, parser and Missing input, including invoking `cpsc` without arguments, reports `cpsc: fatal error: no input files`. Ordinary lexical, syntax and semantic errors use `error:`; failures that prevent compilation, such as file I/O errors, use `fatal error:`. Compilation and argument failures end with one `compilation terminated.` line. Execution-stage failures do not print that line. -Generated IR uses the C++ exception ABI. Native binaries need the C++ runtime; EMBEDDED includes it, while PATH uses the runtime available to `lli`. Exception execution is verified on Linux with LLVM 23; Windows and macOS remain unverified. +Generated IR uses the C++ exception ABI. Native binaries need the C++ runtime; EMBEDDED includes it, while PATH uses the runtime available to `lli`. Nightly CI runs embedded exception tests on Linux, Windows and macOS with LLVM 23. # SEE ALSO diff --git a/doc/language/function/cpsc-function-malloc.7.md b/doc/language/function/cpsc-function-malloc.7.md index c0ca1a6..077e17f 100644 --- a/doc/language/function/cpsc-function-malloc.7.md +++ b/doc/language/function/cpsc-function-malloc.7.md @@ -14,9 +14,9 @@ MALLOC(bytes) 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. -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; it is unrelated to the CIE class NEW construct. The caller must supply enough bytes and initialize values before reading them. User memory is not automatically released. +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. -Only allocations from explicit memory builtins are tracked. Internal STRING and ARRAY buffers remain outside this ownership system. Tracking validates FREE/REALLOC addresses, not memory accesses, bounds or stale aliases after address reuse. +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. # EXAMPLE diff --git a/doc/language/function/cpsc-function-realloc.7.md b/doc/language/function/cpsc-function-realloc.7.md index dc2d61f..7b29c45 100644 --- a/doc/language/function/cpsc-function-realloc.7.md +++ b/doc/language/function/cpsc-function-realloc.7.md @@ -14,7 +14,7 @@ REALLOC(pointer, bytes) 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. -A null pointer behaves as MALLOC(bytes). A non-null pointer must start an active explicit MALLOC or REALLOC 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. +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. For a valid pointer and zero bytes, REALLOC releases the block and returns null. This rule is independent of libc's zero-size behavior. For a nonzero size, successful resizing preserves the smaller of the old and new sizes; added bytes are uninitialized. The returned address may differ from the input. Use the returned pointer afterward; previous aliases must not be used. diff --git a/doc/language/keyword/cpsc-keyword-case.7.md b/doc/language/keyword/cpsc-keyword-case.7.md index 96bcdd8..2d64439 100644 --- a/doc/language/keyword/cpsc-keyword-case.7.md +++ b/doc/language/keyword/cpsc-keyword-case.7.md @@ -22,7 +22,7 @@ Each label header must start on a new line and end with a colon on that line. It Labels and range endpoints may be expressions, including function calls. A single value uses ordinary equality; a TO range includes both endpoints and uses ordinary ordering. Evaluate the lower endpoint first and evaluate the upper endpoint only if the lower comparison succeeds. Do not evaluate later labels after a match. Unlike CONSTANT initializers, CASE labels are not restricted to literals. -STRING comparisons use contents. Enumerations and explicit pointer types follow their ordinary comparison rules; pointers support equality only. Records and whole arrays cannot be compared. The compiler emits conditional branches and disables jump tables for functions containing CASE. +STRING comparisons use contents. Enumerations and explicit pointer types follow their ordinary comparison rules; pointers support equality only. Records and classes require matching comparison overloads that return BOOLEAN; whole arrays cannot be compared. See [cpsc-keyword-operator(7)](cpsc-keyword-operator.7.md). The compiler emits conditional branches and disables jump tables for functions containing CASE. # EXAMPLE diff --git a/doc/language/keyword/cpsc-keyword-class.7.md b/doc/language/keyword/cpsc-keyword-class.7.md index a46ecda..c17f3ef 100644 --- a/doc/language/keyword/cpsc-keyword-class.7.md +++ b/doc/language/keyword/cpsc-keyword-class.7.md @@ -28,21 +28,23 @@ object <- NEW ClassName(arguments) Declare a class at top level with at least one field or method. Fields and methods are public by default; PUBLIC or PRIVATE may be specified for each member. Fields do not use DECLARE. ENDCLASS closes the declaration. Fields and methods share a case-insensitive member namespace; fields and methods cannot share a name. Methods with distinct parameter signatures may share a name when every definition is prefixed with OVERLOAD, after any access keyword; see [cpsc-keyword-overload(7)](cpsc-keyword-overload.7.md). -Call methods as `Object.Method(arguments)` in expressions or as standalone statements, or use `CALL Object.Method(arguments)`. A receiver may be a variable, array element, nested field, or pointer dereference. Calls may precede definitions; methods may call later methods or recurse. Parameters and return values follow the ordinary FUNCTION and PROCEDURE rules. Access on function or method results remains unsupported. +Call methods as `Object.Method(arguments)` in expressions or as standalone statements, or use `CALL Object.Method(arguments)`. A receiver may be a variable, array element, nested field, or pointer dereference. Class-valued function and method results also support method calls, such as `Make().Get()`, using a temporary receiver. Direct field access, indexing and dereferencing on call results remain unsupported. Calls may precede definitions; methods may call later methods or recurse. Parameters and return values follow the ordinary FUNCTION and PROCEDURE rules. Within a method, bare field names refer to the current object's fields. The compiler extension `this` refers directly to the current object: use `this.Field` or `this.Method(arguments)` without pointer dereferencing. An unqualified call such as `Method(arguments)` still names a global function or procedure. PRIVATE members are accessible only from methods of the owning class, including access through another instance of that class. Parameters and local variables, arrays, or constants may shadow fields; this produces a warning with the source line and does not prevent compilation. The local name takes precedence; `this.Field` continues to access the field. The name `this` cannot be a class member or a method parameter or local declaration. -Classes retain record value semantics: zero initialization, whole-value copying, arrays, pointers, and ordinary function/procedure parameters. Methods modify the receiver's storage. The object reference `this` may be read, returned, or passed as an object, including BYREF to a procedure; `this <- Other` copies Other into the current object without rebinding the reference. PRIVATE fields still initialize and copy with the whole value. +Classes retain record value semantics: zero initialization, whole-value copying, arrays, pointers, and ordinary function/procedure parameters. Methods modify the receiver's storage. The object reference `this` may be read, returned, or passed as an object, including BYREF to a procedure; `this <- Other` assigns into the current object without rebinding the reference. PRIVATE fields still initialize and copy with the whole value. A constructor is a PROCEDURE named NEW, following guide section 10.2. It may be PUBLIC or PRIVATE; FUNCTION NEW and global PROCEDURE NEW are errors. Member names are case insensitive, so New and new also name the constructor. Multiple NEW procedures are allowed when every definition specifies OVERLOAD and their parameter signatures differ. Explicit `Object.NEW(arguments)`, `CALL Object.NEW(arguments)` and `this.NEW(arguments)` behave like ordinary member calls and may be repeated; they do not zero the object or reconstruct its fields. `DECLARE Object : ClassName`, `DECLARE Object : ClassName()` and `DECLARE Object : ClassName(arguments)` zero the object's storage, construct its fields recursively in declaration order, then call its NEW procedure. These automatic DECLARE, field and array calls are compiler extensions. Array elements and class-valued fields in records or classes use parameterless construction, before the enclosing constructor runs. A required constructor argument cannot be omitted; supplying arguments to a class without NEW is an error. Empty parentheses are allowed for a class without NEW. Constructor arguments after ARRAY OF are unsupported. A declaration executed again, such as inside a loop, first destroys its previous live incarnation, then zeroes and constructs its original storage again. +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. Whole records and BYVAL arrays still copy their class fields or elements shallowly. 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. -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` remains a value copy into A's current object and does not rebind A. BYVAL parameters copy the caller's value and can rebind independently. +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. For an array element, field (including a bare field inside a method), BYREF parameter, this, or pointer dereference, NEW constructs a heap object and copies its value into the existing target. That temporary allocation is retained. INHERITS, SUPER and array fields remain unsupported. @@ -68,5 +70,3 @@ OUTPUT Item.Get() # SEE ALSO [cpsc-keyword-overload(7)](cpsc-keyword-overload.7.md), [cpsc-language-overview(7)](../cpsc-language-overview.7.md), [cpsc-keyword-delete(7)](cpsc-keyword-delete.7.md), [cpsc-keyword-type(7)](cpsc-keyword-type.7.md), [cpsc-keyword-function(7)](cpsc-keyword-function.7.md), [cpsc-keyword-procedure(7)](cpsc-keyword-procedure.7.md), [cpsc-keyword-call(7)](cpsc-keyword-call.7.md). - -An `OVERLOAD PROCEDURE NEW(BYREF Other : ClassName)` defines a copy constructor. BYVAL class arguments and RETURN of class lvalues invoke it; a same-class BYVAL constructor is rejected. Classes without one retain bitwise copying. 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. diff --git a/doc/language/keyword/cpsc-keyword-delete.7.md b/doc/language/keyword/cpsc-keyword-delete.7.md index d8e2f03..a45d5fa 100644 --- a/doc/language/keyword/cpsc-keyword-delete.7.md +++ b/doc/language/keyword/cpsc-keyword-delete.7.md @@ -36,6 +36,8 @@ A completed construction or BYVAL copy marks the object alive. Destruction clear Exception unwinding destroys live objects in each function frame being left before the caller's CATCH runs. A CATCH inside the same function retains its objects until function exit. An uncaught exception reaching main's final handler skips destruction of main-level objects. If a destructor throws during unwinding, its exception propagates and interrupts the remaining cleanup instead of terminating as C++ would. +Discarded class results and temporary method or operator receivers are destroyed at statement end, including exception exits. For copy constructors and ownership transfer of class results, see [cpsc-keyword-class(7)](cpsc-keyword-class.7.md). + Ordinary method access rules apply to explicit, keyword and automatic destruction. A private DELETE makes destruction outside the owning class a compile error. # EXAMPLE @@ -55,5 +57,3 @@ DELETE Object # SEE ALSO [cpsc-keyword-class(7)](cpsc-keyword-class.7.md), [cpsc-keyword-declare(7)](cpsc-keyword-declare.7.md), [cpsc-keyword-try(7)](cpsc-keyword-try.7.md), [cpsc-function-free(7)](../function/cpsc-function-free.7.md). - -An `OVERLOAD PROCEDURE NEW(BYREF Other : ClassName)` defines a copy constructor. BYVAL class arguments and RETURN of class lvalues invoke it; a same-class BYVAL constructor is rejected. Classes without one retain bitwise copying. 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. diff --git a/doc/language/keyword/cpsc-keyword-operator.7.md b/doc/language/keyword/cpsc-keyword-operator.7.md index 090921f..0673416 100644 --- a/doc/language/keyword/cpsc-keyword-operator.7.md +++ b/doc/language/keyword/cpsc-keyword-operator.7.md @@ -2,7 +2,7 @@ # NAME -cpsc-keyword-operator - overload unary and binary operators +cpsc-keyword-operator - overload unary, binary and assignment operators # SYNOPSIS @@ -17,12 +17,15 @@ CLASS T OVERLOAD FUNCTION OPERATOR-() RETURNS R statements ENDFUNCTION + OVERLOAD PROCEDURE OPERATOR<-(BYREF right : T) + statements + ENDPROCEDURE ENDCLASS ``` # DESCRIPTION -OPERATOR is a compiler extension, absent from the CIE guide. Declare operators with OVERLOAD FUNCTION, at top level or inside CLASS. OPERATOR is reserved; whitespace before the operator is optional. Parentheses are required. Parameters and return values follow FUNCTION rules: parameters default to BYVAL, BYREF is forbidden, and omitting RETURNS defaults to INTEGER. Whole-array operands and array results are unsupported. +OPERATOR is a compiler extension, absent from the CIE guide. Declare unary and binary operators with OVERLOAD FUNCTION, at top level or inside CLASS. Assignment uses a member OVERLOAD PROCEDURE as described below. OPERATOR is reserved; whitespace before the operator is optional. Parentheses are required. Operator functions follow FUNCTION rules: parameters default to BYVAL, BYREF is forbidden, and omitting RETURNS defaults to INTEGER. Whole-array operands and array results are unsupported. Binary operators are `+ - * / DIV MOD & = <> < <= > >= AND OR`. Unary operators are `- NOT`. A global binary definition takes two parameters and a unary definition takes one; at least one parameter must be a record, class or enum. A pointer alias alone does not qualify. A member binary definition takes one explicit parameter and a unary definition takes none; this supplies the left or sole operand. PUBLIC and PRIVATE precede OVERLOAD as for other methods. @@ -32,9 +35,11 @@ The expression has the selected function's declared return type. Comparisons and Operators keep their existing precedence, operand count and associativity. Operands are evaluated once, from left to right; overloaded AND and OR evaluate both operands. Operators are independent: defining = does not define <>, and operands are never swapped to find a match. A matching overload takes precedence over the built-in operation; otherwise the existing built-in rules apply. -Member operators on variables, fields, array elements and pointer dereferences modify the original receiver. Class-valued expressions can also receive operator calls, supporting chains such as `(A + B) + C`. A temporary receiver follows the compiler's existing function-scoped object cleanup rules, rather than C++ full-expression lifetimes. Copies and return values retain the ordinary class value semantics. +Member operators on variables, fields, array elements and pointer dereferences modify the original receiver. Class-valued expressions can also receive operator calls, supporting chains such as `(A + B) + C`. Temporary receivers are destroyed at statement end, including exception exits; ordinary DECLARE objects remain function-scoped. Copies and return values retain the ordinary class value semantics. + +Explicit calls use `OPERATOR+(A, B)` for global definitions and `A.OPERATOR+(B)` for members. They also work as statements, optionally prefixed with CALL, to discard results. Class-valued call results support explicit member operator calls, such as `Make().OPERATOR+(B)`. Indexing, function-call, address-of and dereference operators cannot be overloaded. -Explicit calls use `OPERATOR+(A, B)` for global definitions and `A.OPERATOR+(B)` for members. They also work as statements, optionally prefixed with CALL, to discard results. As with ordinary method calls, explicit member access on a function result is unsupported. Assignment, indexing, function-call, address-of and dereference operators cannot be overloaded. +A class may define `OVERLOAD PROCEDURE OPERATOR<-(BYREF Other : ClassName)` or an overload taking another exact static type. Assignment to a class lvalue selects this member before falling back to same-class bitwise assignment. The procedure takes exactly one explicit parameter; BYREF may bind a designator or materialized temporary. Keyword NEW assignment retains its allocation behavior. Self-assignment handling belongs to the operator body. # EXAMPLE @@ -57,5 +62,3 @@ OUTPUT Sum.Value # SEE ALSO [cpsc-keyword-overload(7)](cpsc-keyword-overload.7.md), [cpsc-keyword-function(7)](cpsc-keyword-function.7.md), [cpsc-keyword-class(7)](cpsc-keyword-class.7.md), [cpsc-keyword-include(7)](cpsc-keyword-include.7.md). - -A class may define `OVERLOAD PROCEDURE OPERATOR<-(BYREF Other : ClassName)` or an overload taking another exact static type. Assignment to a class lvalue selects this member before falling back to same-class bitwise assignment. The procedure takes exactly one explicit parameter; BYREF may bind a materialized temporary. Keyword NEW assignment retains its allocation behavior. Self-assignment handling belongs to the operator body. diff --git a/doc/language/keyword/cpsc-keyword-try.7.md b/doc/language/keyword/cpsc-keyword-try.7.md index eea0510..611e4ba 100644 --- a/doc/language/keyword/cpsc-keyword-try.7.md +++ b/doc/language/keyword/cpsc-keyword-try.7.md @@ -26,7 +26,9 @@ THROW takes no argument and always raises a new anonymous exception. An exceptio Runtime checks throw the same anonymous exceptions for division by zero, array index errors, null pointer dereferences, invalid enumeration values, array-parameter bounds mismatches, and file misuse. Before throwing, a runtime check prints the source line and error reason to standard error, even when CATCH handles the exception. Explicit THROW prints no diagnostic itself. Compiler errors cannot be caught. If no handler catches an exception, the program prints `Unhandled exception. Program terminated.` to standard error and returns status 1. -Arrays declared inside either body remain local to that block. Stack unwinding does not automatically free heap strings or arrays, close files, or run user-defined destructors. Exception execution is verified on Linux with LLVM 23; Windows and macOS remain unverified. +Arrays declared inside either body remain local to that block. Stack unwinding destroys live objects in function frames being left; objects declared in a function containing the selected CATCH remain alive until that function exits. Temporary class values are cleaned up before entering the handler. Main-level objects are destroyed only on normal program end. See [cpsc-keyword-delete(7)](cpsc-keyword-delete.7.md) for destructor and lifetime rules. + +Unwinding does not automatically release internal STRING or ARRAY buffers, release keyword NEW allocations, or close files. Nightly CI runs embedded exception tests on Linux, Windows and macOS with LLVM 23. # EXAMPLE diff --git a/doc/language/keyword/cpsc-keyword-while.7.md b/doc/language/keyword/cpsc-keyword-while.7.md index 98090e3..b83ccfb 100644 --- a/doc/language/keyword/cpsc-keyword-while.7.md +++ b/doc/language/keyword/cpsc-keyword-while.7.md @@ -14,7 +14,7 @@ ENDWHILE # DESCRIPTION -Test before each iteration; the body may run zero times. ENDWHILE closes the loop. The WHILE header has no DO keyword. +Test before each iteration; the body may run zero times. ENDWHILE closes the loop. The standard WHILE header has no DO keyword; the compiler also accepts `WHILE condition DO` for compatibility. # EXAMPLE -- cgit v1.3.1-4-g156e