From b47c302bbffd668334f307d512b674f804f8f2fc Mon Sep 17 00:00:00 2001 From: _ov4 Date: Sat, 17 Oct 2026 10:35:33 +0000 Subject: docs: document OVERLOAD Co-Authored-By: Claude Opus 5.5 --- AGENTS/ARCH.md | 2 +- AGENTS/CONVENTIONS.md | 5 ++- AGENTS/PITFALLS.md | 16 ++++++-- AGENTS/SUBSYSTEMS.md | 22 +++++++---- doc/language/cpsc-language-overview.7.md | 1 + doc/language/keyword/cpsc-keyword-class.7.md | 6 +-- doc/language/keyword/cpsc-keyword-function.7.md | 4 +- doc/language/keyword/cpsc-keyword-include.7.md | 2 +- doc/language/keyword/cpsc-keyword-overload.7.md | 50 ++++++++++++++++++++++++ doc/language/keyword/cpsc-keyword-procedure.7.md | 4 +- 10 files changed, 94 insertions(+), 18 deletions(-) create mode 100644 doc/language/keyword/cpsc-keyword-overload.7.md diff --git a/AGENTS/ARCH.md b/AGENTS/ARCH.md index f85364b..cb0bc20 100644 --- a/AGENTS/ARCH.md +++ b/AGENTS/ARCH.md @@ -88,7 +88,7 @@ Driver behavior (`tools/driver/main.cc`): matched against command-line inputs with fs::equivalent. The driver rejects repeated inputs and computes transitive symbol visibility; cycles do not copy statements. CodeGen records owners for signatures, types and exported constants/globals and filters - lookup by the current unit. Cross-file duplicate definitions are always errors. + lookup by the current unit. Cross-file duplicate definitions are errors; distinct explicit OVERLOAD signatures may share a name. The entry file contains the only top-level code, or parameterless FUNCTION MAIN returning INTEGER; MAIN plus top-level code and builds without either entry are errors. SourceUnit borrows parsed statements for compilation. Type names are reserved across diff --git a/AGENTS/CONVENTIONS.md b/AGENTS/CONVENTIONS.md index f912e79..5ab7459 100644 --- a/AGENTS/CONVENTIONS.md +++ b/AGENTS/CONVENTIONS.md @@ -142,7 +142,10 @@ arguments through `emitCoercedExpr`, and dispatches whole-array arguments to `ArrayHandler::emitArrayArgument`. RETURN values go through `emitCoercedExpr` against the declared return type. Top-level prototypes are pre-registered (after the TYPE pre-pass) before statement emission, so call-before-definition is fine; a call with -no registered signature is a compile error. Global function names except MAIN get no mangling, so +no registered signature is a compile error. OVERLOAD signatures append canonical +parameter types to the link name; ordinary names except MAIN get no mangling. +`getOverloads` filters by visibility and `resolveCall` selects exact static types/ranks. +Return types, modes and bounds never distinguish overloads. 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. Methods use diff --git a/AGENTS/PITFALLS.md b/AGENTS/PITFALLS.md index 951a2f6..8f35c3d 100644 --- a/AGENTS/PITFALLS.md +++ b/AGENTS/PITFALLS.md @@ -6,7 +6,8 @@ Every bullet below was confirmed against the source, most also by compiling and test programs. - **Multi-file extensions.** INCLUDE imports symbols, never text; every included file - must also be an input. Duplicate exports across files fail even without visibility. + must also be an input. Duplicate exports across files fail even without visibility, except distinct + signatures whose definitions all specify OVERLOAD. Only one file may contain top-level code; top-level DECLARE is a main local, not an export. Definitions-only builds now fail without FUNCTION MAIN returning INTEGER. MAIN cannot coexist with top-level code. GLOBAL accepts only the five primitive @@ -42,8 +43,8 @@ test programs. returns REAL. NUM_TO_STR formats INTEGER with bounded snprintf `"%lld"` (the full signed i64 range) and REAL with `"%f"`. REAL buffers cover the full fixed-point double range. - **`getExprTypeInfo` returns nullptr** for expressions it can't classify (null-check it - at any new call site) and internally defaults to INTEGER for arithmetic binaries and - unknown-function calls; OUTPUT reports an error for a nullptr result. + at any new call site) and internally defaults to INTEGER for unclassified arithmetic expressions; unknown or unmatched calls now diagnose and return nullptr. + OUTPUT reports an error for a nullptr result. - **CONSTANT** accepts only literals (including negative numeric literals), never expressions or other names. Constants have lexical block scope and may shadow outer names; bindings hiding constants are restored on block exit too. Functions inherit previously declared constants from their own unit and all visible imported top-level constants. Constants have no writable storage: assignment, INPUT, READFILE targets, FOR variables, BYREF and address-of are rejected. - **CASE OF** reads its selector once and tests expression labels in source order, with inclusive TO ranges and an optional final OTHERWISE. Label headers occupy their own source line; bodies may begin after the colon or on subsequent lines. Comparisons reuse ordinary operator rules; records and whole arrays are unsupported. - The lexer emits no newline tokens; most grammar is keyword-delimited, while CASE @@ -83,6 +84,15 @@ test programs. followed by `.` is swallowed into a REAL literal, so `1.foo` mislexes (only already-invalid programs can hit it). +- **OVERLOAD extension.** OVERLOAD is reserved and prefixes FUNCTION/PROCEDURE + (after PUBLIC/PRIVATE for methods). Every same-name definition must opt in. + Only count, canonical parameter types and array rank distinguish signatures: + return type, BYREF/BYVAL and array bounds do not. Calls match exact static types, + even for a single OVERLOAD definition; ordinary functions still coerce arguments. + Call visibility filters the set, but duplicate signatures conflict across all + inputs. MAIN and builtins cannot be overloaded. NEW supports overloads; DECLARE, + fields and arrays needing default construction require a matching no-argument NEW. + Private access is checked after selection, never used to select a public fallback. - **CLASS subset (ยง10).** `CLASS`/`ENDCLASS`/`PUBLIC`/`PRIVATE` are reserved. CLASS is a top-level record-derived value type with optional per-member access keywords (no DECLARE). Omitting access defaults to public, per the guide. diff --git a/AGENTS/SUBSYSTEMS.md b/AGENTS/SUBSYSTEMS.md index bb59ebf..dab3146 100644 --- a/AGENTS/SUBSYSTEMS.md +++ b/AGENTS/SUBSYSTEMS.md @@ -24,15 +24,20 @@ are a compile error there). Arrays keep their per-element newlines and dispatch continues with the next expression; a final array requires no extra newline. **Functions** (`FunctionGen`): plain LLVM functions, external linkage, exact pseudocode -name (MAIN uses internal __cps_main). Params are `ParamDecl{name, typeString, mode, array rank/bounds}`. BYVAL args are +name unless OVERLOAD appends a canonical parameter list (MAIN uses internal __cps_main). Params are `ParamDecl{name, typeString, mode, array rank/bounds}`. BYVAL args are copied into entry-block allocas (whole structs for records); BYREF args bind the incoming pointer directly as the variable's storage; array params are handed to the binder callback CodeGen injects (`setArrayParamBinder`) so FunctionGen never sees ArrayHandler. Missing RETURNS defaults the return type to INTEGER; procedures use "VOID". `emitPrototype` records each function's pseudocode signature in a `FuncSig` -map (`FunctionGen::getSignature`); `CodeGen::marshalCallArgs` dispatches call arguments -on those *declared* `ParamSig`s, and `getExprTypeInfo` reads return types from the same -map. Top-level prototypes are pre-registered at the start of `compile()` (after the +overload-set map (`FunctionGen::getOverloads`, filtered by unit visibility). +`resolveCall` selects exact static parameter types/ranks for OVERLOAD, while a single +ordinary definition keeps implicit conversions. Parameter keys exclude return types, +modes and bounds; equivalent C aliases use CIdentity. Every same-name definition must +be OVERLOAD; duplicate keys fail even across invisible units. FunctionGen tracks +prototype registration separately from source names and indexes signatures by LLVM +link name for RETURN (`getSignatureByLink`). `CodeGen::marshalCallArgs` consumes the +selected FuncSig, and `getExprTypeInfo` resolves the same calls without emitting IR. Top-level prototypes are pre-registered at the start of `compile()` (after the TYPE pre-pass), so calls may precede definitions; calling a name with no signature is a compile error (no extern is fabricated). Functions inherit visible GLOBAL storage and previously declared own top-level CONSTANT values, plus imported constants from the start; local constants use the same Symbols table with lexical binding restoration. Body emission is inverted: CodeGen injects a `StmtEmitter` callback, and must restore its own insert point (and the exchanged @@ -67,9 +72,12 @@ current method's owning class, including address-of, array elements and pointer dereferences. Other instances of the same class are accessible from its methods. Class ASTs also own their `FunctionDefAST` methods. PrototypeAST retains the owner -and access level; `getLinkName()` qualifies method symbols as `Class.Method`, while -global function names remain unmangled. CodeGen registers methods separately in -`ClassMethods` and pre-registers their prototypes after the type pre-pass. +and access level; `getLinkName()` supplies the source key `Class.Method`. +FunctionGen appends `(canonical parameter types)` only for OVERLOAD, leaving ordinary +symbols unchanged. CodeGen registers methods separately in +`ClassMethods` overload vectors and pre-registers their prototypes after the type pre-pass. +`resolveMethod` uses `resolveCall`; access is checked on the selected overload. +Constructor/default-construction paths select NEW through this same resolver. `MemberCallExprAST` keeps an addressable receiver separate from explicit arguments; `MemberCallStmtAST` discards its result. `emitMemberCall` checks access and prepends the receiver address to arguments marshalled by the existing `marshalCallArgs`. diff --git a/doc/language/cpsc-language-overview.7.md b/doc/language/cpsc-language-overview.7.md index 58df76c..93d2457 100644 --- a/doc/language/cpsc-language-overview.7.md +++ b/doc/language/cpsc-language-overview.7.md @@ -38,6 +38,7 @@ Multi-file builds use the compiler extensions INCLUDE and GLOBAL. Pass every sou - [cpsc-keyword-for(7)](keyword/cpsc-keyword-for.7.md): iterate over an integer range. - [cpsc-keyword-function(7)](keyword/cpsc-keyword-function.7.md): define a function that returns a value. - [cpsc-keyword-procedure(7)](keyword/cpsc-keyword-procedure.7.md): define a procedure and parameter modes. +- [cpsc-keyword-overload(7)](keyword/cpsc-keyword-overload.7.md): explicitly overload functions, procedures and constructors. - [cpsc-keyword-call(7)](keyword/cpsc-keyword-call.7.md): invoke a procedure. - [cpsc-keyword-openfile(7)](keyword/cpsc-keyword-openfile.7.md): open a text file. - [cpsc-keyword-readfile(7)](keyword/cpsc-keyword-readfile.7.md): read a line from a text file. diff --git a/doc/language/keyword/cpsc-keyword-class.7.md b/doc/language/keyword/cpsc-keyword-class.7.md index a58e8a8..986f2f6 100644 --- a/doc/language/keyword/cpsc-keyword-class.7.md +++ b/doc/language/keyword/cpsc-keyword-class.7.md @@ -26,7 +26,7 @@ object <- NEW ClassName(arguments) # DESCRIPTION -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; duplicate names and method overloading are rejected. +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. @@ -36,7 +36,7 @@ Parameters and local variables, arrays, or constants may shadow fields; this pro 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. -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. Only one NEW is allowed per class. 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. +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. @@ -67,4 +67,4 @@ OUTPUT Item.Get() # SEE ALSO -[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). +[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). diff --git a/doc/language/keyword/cpsc-keyword-function.7.md b/doc/language/keyword/cpsc-keyword-function.7.md index d734da3..9f3839d 100644 --- a/doc/language/keyword/cpsc-keyword-function.7.md +++ b/doc/language/keyword/cpsc-keyword-function.7.md @@ -25,6 +25,8 @@ A FUNCTION inside CLASS defines a member function, called as `Object.Method(argu As a compiler extension, a top-level `FUNCTION MAIN RETURNS INTEGER` with no parameters supplies the program entry point. MAIN is case insensitive and cannot coexist with top-level executable statements in any input file. Its INTEGER result, truncated to 32 bits, is returned as the process exit status. An uncaught exception prints the generic termination message and returns 1. A PROCEDURE MAIN or a MAIN with parameters or a non-INTEGER result is an error. The usual default INTEGER result type also applies when RETURNS is omitted. +Prefix a definition with OVERLOAD to share its name with other explicitly marked definitions having different parameter signatures. Calls then require exact argument types; see [cpsc-keyword-overload(7)](cpsc-keyword-overload.7.md). + # EXAMPLE ```text @@ -36,4 +38,4 @@ OUTPUT Double(4) # SEE ALSO -[cpsc-language-overview(7)](../cpsc-language-overview.7.md), [cpsc-keyword-class(7)](cpsc-keyword-class.7.md), [cpsc-keyword-procedure(7)](cpsc-keyword-procedure.7.md), [cpsc-keyword-call(7)](cpsc-keyword-call.7.md). +[cpsc-keyword-overload(7)](cpsc-keyword-overload.7.md), [cpsc-language-overview(7)](../cpsc-language-overview.7.md), [cpsc-keyword-class(7)](cpsc-keyword-class.7.md), [cpsc-keyword-procedure(7)](cpsc-keyword-procedure.7.md), [cpsc-keyword-call(7)](cpsc-keyword-call.7.md). diff --git a/doc/language/keyword/cpsc-keyword-include.7.md b/doc/language/keyword/cpsc-keyword-include.7.md index 5600472..95ff953 100644 --- a/doc/language/keyword/cpsc-keyword-include.7.md +++ b/doc/language/keyword/cpsc-keyword-include.7.md @@ -14,7 +14,7 @@ INCLUDE "path.cps" INCLUDE is a compiler extension, allowed only at top level. Resolve the path relative to the including source's directory. The included file must also be given on the command line; symbolic and hard links identify the same file. -Import functions, procedures, types (including enum values), classes and methods, top-level constants and GLOBAL variables. Imports are transitive. Repeated includes and cycles are harmless: INCLUDE imports symbols rather than copying statements. A file always sees its own definitions. Using an unimported definition produces the usual unknown or undefined name error. Definitions must be unique across all input files, even when they are not imported. +Import functions, procedures, types (including enum values), classes and methods, top-level constants and GLOBAL variables. Imports are transitive. Repeated includes and cycles are harmless: INCLUDE imports symbols rather than copying statements. A file always sees its own definitions. Using an unimported definition produces the usual unknown or undefined name error. Definitions must be unique across all input files, even when they are not imported. Explicit OVERLOAD definitions may share a name across files when their parameter signatures differ; callers see only visible overloads. See [cpsc-keyword-overload(7)](cpsc-keyword-overload.7.md). Imported constants are visible from the start of the including unit. A unit's own constants retain their ordinary declaration-order visibility. Top-level DECLARE variables are entry-program locals and are not exported. Pass all inputs together; there is no separate object-file compilation mode. diff --git a/doc/language/keyword/cpsc-keyword-overload.7.md b/doc/language/keyword/cpsc-keyword-overload.7.md new file mode 100644 index 0000000..f7df69f --- /dev/null +++ b/doc/language/keyword/cpsc-keyword-overload.7.md @@ -0,0 +1,50 @@ +% CPSC-KEYWORD-OVERLOAD(7) + +# NAME + +cpsc-keyword-overload - explicitly overload functions, procedures and constructors + +# SYNOPSIS + +```text +OVERLOAD FUNCTION name(parameters) RETURNS type + statements +ENDFUNCTION +OVERLOAD PROCEDURE name(parameters) + statements +ENDPROCEDURE +CLASS name + PUBLIC OVERLOAD PROCEDURE NEW(parameters) + statements + ENDPROCEDURE +ENDCLASS +``` + +# DESCRIPTION + +OVERLOAD is a compiler extension, absent from the CIE guide. Put it immediately before FUNCTION or PROCEDURE, after PUBLIC or PRIVATE when an access keyword is present. OVERLOAD is reserved. Every definition sharing a case-insensitive name must specify OVERLOAD. Global functions, procedures, class methods and NEW constructors support it; MAIN and built-in functions do not. + +Signatures differ by parameter count, parameter types, or array rank. Return types, FUNCTION versus PROCEDURE, BYREF versus BYVAL, and declared array bounds do not distinguish signatures. Overloads may return different types when their parameter signatures differ. Nominal user types remain distinct; equivalent native C type aliases identify the same type. + +Calls require an exact match to the arguments' static types. No implicit conversion is used to select an overload, even when only one OVERLOAD definition exists. Array arguments must be whole array variables with matching element types and rank. After selection, ordinary parameter-mode, array-bound and access checks apply. A failure reports `No matching overload for Name(T1, T2)`. Functions without OVERLOAD retain their ordinary argument conversions. + +Overloads may be defined in separate input files. A caller sees only its own and included units' definitions. Duplicate parameter signatures fail across all inputs, even when neither unit includes the other. See [cpsc-keyword-include(7)](cpsc-keyword-include.7.md). + +Methods use the same rules; fields and methods cannot share a name. Constructor calls select NEW by their explicit arguments. DECLARE without arguments, class-valued fields and array elements select a parameterless NEW; if NEW exists but has no matching parameterless overload, compilation fails. PRIVATE checks apply to the selected method or constructor. + +# EXAMPLE + +```text +OVERLOAD FUNCTION Area(Side : INTEGER) RETURNS INTEGER + RETURN Side * Side +ENDFUNCTION +OVERLOAD FUNCTION Area(Radius : REAL) RETURNS REAL + RETURN 3.14159 * Radius * Radius +ENDFUNCTION +OUTPUT Area(3) +OUTPUT Area(2.0) +``` + +# SEE ALSO + +[cpsc-keyword-function(7)](cpsc-keyword-function.7.md), [cpsc-keyword-procedure(7)](cpsc-keyword-procedure.7.md), [cpsc-keyword-class(7)](cpsc-keyword-class.7.md), [cpsc-keyword-call(7)](cpsc-keyword-call.7.md). diff --git a/doc/language/keyword/cpsc-keyword-procedure.7.md b/doc/language/keyword/cpsc-keyword-procedure.7.md index f21ef59..6d46fb2 100644 --- a/doc/language/keyword/cpsc-keyword-procedure.7.md +++ b/doc/language/keyword/cpsc-keyword-procedure.7.md @@ -20,6 +20,8 @@ Arrays accept `ARRAY OF type` or `ARRAY[lower:upper, ...] OF type`; explicit bou A PROCEDURE inside CLASS defines a member procedure, called as `Object.Method(arguments)` or `CALL Object.Method(arguments)`. It follows the same parameter rules and modifies the receiver. Within a method, `this` refers directly to the current object; see [cpsc-keyword-class(7)](cpsc-keyword-class.7.md). +Prefix a definition with OVERLOAD to share its name with other explicitly marked definitions having different parameter signatures. Calls then require exact argument types; see [cpsc-keyword-overload(7)](cpsc-keyword-overload.7.md). + # EXAMPLE ```text @@ -33,4 +35,4 @@ OUTPUT Count # SEE ALSO -[cpsc-language-overview(7)](../cpsc-language-overview.7.md), [cpsc-keyword-class(7)](cpsc-keyword-class.7.md), [cpsc-keyword-call(7)](cpsc-keyword-call.7.md), [cpsc-keyword-function(7)](cpsc-keyword-function.7.md). +[cpsc-keyword-overload(7)](cpsc-keyword-overload.7.md), [cpsc-language-overview(7)](../cpsc-language-overview.7.md), [cpsc-keyword-class(7)](cpsc-keyword-class.7.md), [cpsc-keyword-call(7)](cpsc-keyword-call.7.md), [cpsc-keyword-function(7)](cpsc-keyword-function.7.md). -- cgit v1.3.1-4-g156e