diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-21 06:18:34 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-21 06:18:34 +0000 |
| commit | 3cdb5d202faf04993e5aad955078653251cb6073 (patch) | |
| tree | 900fc60ed1e32f324db9b0e7e1e7a68c2e9479d4 /AGENTS | |
| parent | db8c7f14d2f74c3db205782acf8222cb7d91a047 (diff) | |
docs: document TEMPLATE
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'AGENTS')
| -rw-r--r-- | AGENTS/ARCH.md | 4 | ||||
| -rw-r--r-- | AGENTS/CONVENTIONS.md | 4 | ||||
| -rw-r--r-- | AGENTS/EXTENDING.md | 2 | ||||
| -rw-r--r-- | AGENTS/PITFALLS.md | 1 | ||||
| -rw-r--r-- | AGENTS/SUBSYSTEMS.md | 12 |
5 files changed, 22 insertions, 1 deletions
diff --git a/AGENTS/ARCH.md b/AGENTS/ARCH.md index 75202cd..e6361a9 100644 --- a/AGENTS/ARCH.md +++ b/AGENTS/ARCH.md @@ -314,9 +314,11 @@ do not modify the real release for local verification. | `lib/Parser/ParserFunction.cc` | FUNCTION/PROCEDURE/CALL/RETURN + parameter-list parsing | | `lib/Parser/ParserFile.cc` | OPENFILE/READFILE/WRITEFILE/CLOSEFILE parsing | | `lib/Parser/ParserType.cc` | Type names, variable/array/constant declarations, TYPE/ENDTYPE and CLASS/ENDCLASS declarations, shared field and method parsing, SET/DEFINE reserved stubs | +| `include/cps/TemplateAST.h`, `lib/Parser/ParserType.cc` | TEMPLATE declarations, type parameter packs and canonical template ids; call and pack parsing also uses ParserExpression.cc/ParserFunction.cc | | `lib/CodeGen/CodeGen.cc` | Initialization, symbols, call arguments and main() compilation | | `lib/CodeGen/ExpressionGen.cc`, `StatementGen.cc`, `ControlFlowGen.cc` | Expression/statement dispatch and control-flow emission | | `lib/CodeGen/OperatorGen.cc`, `include/cps/Operator.h` | Exact global/member operator selection, calls and temporary receivers; shared operator spellings | +| `lib/CodeGen/TemplateGen.cc`, `TemplateClone.h`, `TemplateClone.cc` | Template registry validation, cached function/class instantiation, structural type substitution, pack expansion and deferred bodies; call deduction/selection lives in CodeGen.cc | | `lib/CodeGen/ConstructorGen.cc` | Construction, copying, assignment, destruction and deferred object cleanup | | `lib/CodeGen/GlobalGen.cc` | GLOBAL declarations and scalar/owning STRING initializers | | `lib/CodeGen/ConstantGen.cc` | Literal constants, declaration conflicts and lexical binding restoration | @@ -337,7 +339,7 @@ do not modify the real release for local verification. | `cmake/Manual.cmake`, `cmake/GenerateManual.cmake.in` | Optional manual generation with local-first Pandoc discovery | | `install.sh`, `install.ps1`, `cmake/Install.cmake.in`, `cmake/Release.cmake` | Artifact installation and versioned binary release packaging | -AST nodes live in `include/cps/AST.h` (+ `FunctionAST.h`, `FileAST.h`, `TypeAST.h`); +AST nodes live in `include/cps/AST.h` (+ `FunctionAST.h`, `FileAST.h`, `TypeAST.h`, `TemplateAST.h`); they are pure data with virtual destructors only — no codegen/visitor methods. ## Detail docs diff --git a/AGENTS/CONVENTIONS.md b/AGENTS/CONVENTIONS.md index 5863548..ed9acb1 100644 --- a/AGENTS/CONVENTIONS.md +++ b/AGENTS/CONVENTIONS.md @@ -137,6 +137,10 @@ declaration spelling for LLVM lookup, independently of call-site casing. Methods `Class.Method` names and a hidden leading receiver address; their FuncSig parameters contain only explicit source parameters. Method prototypes are pre-registered too. +**Templates substitute ASTs before ordinary emission.** Keep explicit `TemplateArgs` separate from call callee names; canonical type ids have no spaces (`Box<Pair<INTEGER,REAL>>`). `TemplateClone.cc` owns deep cloning and structural substitution; every new body AST node needs coverage there. A type parameter binds one canonical type and a pack binds a list; expanded parameter names use unlexable `#` suffixes. FunctionGen stores overload signatures in `IdentifierMap<std::deque<FuncSig>>` so instantiating another template cannot invalidate a held `FuncSig *` during marshalling. CodeGen owns cloned ASTs for the entire compile and caches each instance by declaration plus canonical arguments. + +**Template selection and context are shared by typing and emission.** When multiple definitions share a function/procedure name, every ordinary and template definition must specify OVERLOAD. `resolveCall` computes static argument types/ranks once, then tries exact ordinary, non-variadic template and variadic template tiers; same-tier ties are errors. Candidate checking must stay silent and must not instantiate speculative class types. Explicit arguments pre-bind types without allowing conversions. Instances keep the template owner for diagnostics/library behavior and the first requester in `VisibilityUnit` for lookup (`value_or(CurrentUnit)`). Deferred bodies use the symbol snapshot at the template declaration to preserve positional own constants; save and restore all caller context. Class resolution hooks must honor visibility and reserve/cache the record before resolving fields. + **Operator overloads share static selection.** OPERATOR is a reserved keyword; `OVERLOAD FUNCTION OPERATOR+(...)` records the token on PrototypeAST. Canonical names contain a space (`OPERATOR +`, `Class.OPERATOR AND`) to avoid collisions with diff --git a/AGENTS/EXTENDING.md b/AGENTS/EXTENDING.md index bb297d4..668941b 100644 --- a/AGENTS/EXTENDING.md +++ b/AGENTS/EXTENDING.md @@ -17,6 +17,8 @@ fall-through branch in control-flow codegen with `if (!Builder->GetInsertBlock()->hasTerminator())` — a RETURN in the body may have already terminated the block. +**New AST nodes must be cloned in `lib/CodeGen/TemplateClone.cc`.** Its dynamic_cast chains deep-clone every expression and statement permitted in a template body, preserving source lines. Add structural type substitution for each new type-bearing field and expand packs only through the argument-list helper. Unsupported nodes must diagnose rather than disappear; nested function definitions remain forbidden in template bodies. + **New builtin function:** add a `{Name, Arity, ReturnTypeName}` row to the shared `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 diff --git a/AGENTS/PITFALLS.md b/AGENTS/PITFALLS.md index 8d2d890..7bc78fb 100644 --- a/AGENTS/PITFALLS.md +++ b/AGENTS/PITFALLS.md @@ -91,6 +91,7 @@ test programs. 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. +- **TEMPLATE extension.** Top-level FUNCTION/PROCEDURE/CLASS only; all template parameters are types, with at most one final pack. Exact types are required even with explicit arguments (`Max<REAL>(1, 2.5)` fails). Deduction recognizes T and array element T, never the T inside Box<T>. When multiple ordinary/template functions share a name, every definition must specify OVERLOAD; exact ordinary definitions win, then non-variadic templates, then variadic templates, with same-tier ties ambiguous. Explicit arguments select templates only. Packs are final non-array parameters and expand only in call/constructor argument lists; pack fields are rejected, including in variadic classes. No non-type parameters, SIZEOF..., member/operator templates, specialization, bare injected class name or pointer-alias templates. Pointer-linked generic containers remain unsupported; use fixed fields or other supported value layouts. Class instances follow ordinary constructor rules, so a parameterized NEW alone does not permit `DECLARE B : Box<INTEGER>` without arguments. Template instances share the first requester's visibility for their cached body; positional constants come from the template declaration. Instantiation depth is limited to 64. Empty source lists `<>` are invalid and lex as inequality; `>>` remains two tokens, but adjacent `<-` and `>=` merge. Expression lookahead treats `A < B, C > (D)` as a template call; parenthesize comparisons to avoid that ambiguity. - **OPERATOR extension.** Unary/binary operators require OVERLOAD FUNCTION, with supported arity and at least one record/class/enum operand. Pointer aliases alone do not qualify. Exact matching considers visible globals and left-class members diff --git a/AGENTS/SUBSYSTEMS.md b/AGENTS/SUBSYSTEMS.md index 23a5270..3112142 100644 --- a/AGENTS/SUBSYSTEMS.md +++ b/AGENTS/SUBSYSTEMS.md @@ -196,3 +196,15 @@ Builder (RuntimeCheck emits through the same one), saving/restoring the insert b **Class copies and temporaries.** Callers construct BYVAL class lvalue arguments with a same-class BYREF OVERLOAD NEW when defined, otherwise they copy bits; the callee's RegisterCopy hook takes ownership. emitOwnedValue constructs lvalue copies and keeps pending arguments Alive until marshalling succeeds. RETURN copies lvalues and transfers rvalues. Records and BYVAL arrays recursively clone STRING-bearing fields/elements. Other owning class fields retain the existing shallow-copy limits. StackObject::Temporary uses statement cleanup and deferred temporary-only cleanup before local handlers, while ordinary objects remain function-scoped. Function-result method receivers are materialized by the same path as operator receivers. Assignment first selects an exact member OPERATOR<-; without one, STRING-bearing aggregate assignment clones string fields from lvalues or transfers them from rvalues, releasing the target's old string fields without invoking the enclosing class destructor; other classes retain their existing bitwise assignment behavior. **Standard library** (`pseudocode-lib/`): the default build compiles each .cc with the host compiler into build/pseudocode-lib/*.o, copies .cps units beside them, and embeds all these outputs in cpsc. StandardLibrary extracts the resources through linking/execution; the driver implicitly imports std.cps unless -no-std is set. std.cps imports string.cps. STRING is a #LIB class with a public internal void* handle owning std::string. The _string_impl_* C ABI reports __cps_user_line and throws 0 on std::exception. Functions/operators use ordinary resolution; StringValueGen bridges literals, C_STR, C conversions and file operands. C_STRING literals have an adjacent uppercase C suffix. INPUT delegates to READ_INPUT, OUTPUT uses C stdout buffers, and READFILE invokes assignment from C_STRING then frees its temporary buffer. Source/object resources are embedded in installed/released cpsc; saved IR requires the object when manually linked. + +## Templates + +`TemplateDeclAST` owns a function/procedure or class definition plus type parameters; `PackExpansionExprAST` represents a value pack used in an argument list. The top-level name scan registers templates without treating them as executable code. After ordinary prototype registration, `validateTemplates` checks OVERLOAD consistency across all units, including invisible definitions. CONSTANT/GLOBAL name checks use template-aware callable lookup. + +`CodeGen::resolveCall` retains ordinary fast paths when no templates exist. Otherwise it computes static argument types and whole-array ranks once, selecting exact ordinary definitions before non-variadic templates and then variadic templates. Explicit type arguments pre-bind positional parameters and constrain a pack prefix; deduction from `T` or array element `T` fills remaining bindings. Composite types such as `Box<T>` are checked after substitution but do not deduce T. Every position must match exactly and every non-pack type must be bound. Candidate failures stay silent; only the final no-match or ambiguity is diagnosed. `hasCallable` keeps CALL statement re-resolution aware of templates. + +`TemplateClone.{h,cc}` deep-clones body ASTs with structural type substitution, preserving source lines. Bindings map each type parameter to a list (one type for ordinary parameters). A final value pack expands into `Name#1` through `Name#N`; argument-list cloning expands references only in calls, member calls, NEW and DECLARE constructors. Class cloning substitutes fields, method types and owning class names; pack fields and nested function definitions are rejected. Add clone coverage whenever introducing a body AST node. + +`TemplateGen.cc` caches instances by source declaration and canonical type arguments, owns cloned ASTs for the compile lifetime and immediately registers selected function prototypes. Names are `Max<INTEGER>`, with the parameter signature appended for OVERLOAD. FunctionGen's signature deques keep pointers stable while recursive instantiation appends signatures. `TypeSystem::resolve` has a miss hook for visible class templates, including diagnostics for bare template names. It resolves arguments, reserves and caches an opaque record, defines its fields, records the template owner in TypeOwners and uses the factored `registerClassMethods`/`emitClassPrototypes` paths. Prototypes requested during the type pre-pass are deferred until it completes. Failed type names are remembered to avoid repeating the instantiation error; speculative candidate checks do not record failures. `findMethod` forces type resolution for template ids before NEW/DELETE lookup. + +After all units' statement loops, `drainTemplateBodies` emits queued functions and class methods through `emitStmt`, repeating for newly requested instances until the queue is empty. Instantiation depth is limited to 64. `selectUnit` restores the template owner's file, library mode and call hook; `VisibilityUnit` uses the first requester's transitive visibility, including requester-defined operators needed by a library template. Each body receives the symbol snapshot from the template declaration, preserving positional own constants and imported constants. SaveAndRestore guards and unit restoration retain the caller's state. |
