diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-17 09:18:23 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-17 09:18:23 +0000 |
| commit | 9467ae311ddc0ce8b4c329f3dbcec88fb279719d (patch) | |
| tree | 6102b28ca01d88c96bab5d13a4f0dcb547649d2f /AGENTS | |
| parent | 64aa538142148faf06b9a3c71907eacee04cd49d (diff) | |
docs: multi-file builds
Document INCLUDE visibility, primitive GLOBAL variables and MAIN entry rules,
and highlight the new keywords in the editor grammar.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'AGENTS')
| -rw-r--r-- | AGENTS/ARCH.md | 24 | ||||
| -rw-r--r-- | AGENTS/CONVENTIONS.md | 20 | ||||
| -rw-r--r-- | AGENTS/PITFALLS.md | 9 | ||||
| -rw-r--r-- | AGENTS/SUBSYSTEMS.md | 4 |
4 files changed, 45 insertions, 12 deletions
diff --git a/AGENTS/ARCH.md b/AGENTS/ARCH.md index 1178934..aef89ed 100644 --- a/AGENTS/ARCH.md +++ b/AGENTS/ARCH.md @@ -6,9 +6,9 @@ other major versions and non-Clang compilers. Execution is selected at build time: external lli, an embedded static LLVM engine, or disabled. ``` -file ──> Lexer ──> Parser ──> vector<unique_ptr<StmtAST>> ──> CodeGen ──> LLVM IR ──> NativeCompiler (object emission + embedded LLD) +files ──> Lexer ──> Parser ──> vector<unique_ptr<StmtAST>> ──> CodeGen ──> LLVM IR ──> NativeCompiler (object emission + embedded LLD) (istream) (recursive (flat program list; (one llvm::Module "cps_module", - descent) FunctionDefAST mixed in) everything else inside i32 main()) + descent) FunctionDefAST mixed in) entry code inside i32 main()) ``` Fixed value representation (ABI — much code infers types backwards from these): @@ -83,7 +83,18 @@ Windows/macOS await CI verification. Driver behavior (`tools/driver/main.cc`): -- One source file, with optional `-S`, `-o path` and `-r`; options may precede or follow the source. +- One or more source files, with optional `-S`, `-o path` and `-r`; options may appear among inputs. + Each stream is parsed independently. INCLUDE paths are relative to the including file, + 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. + 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 + all units before payloads are completed, with included units visited first. + GLOBAL declarations and literal initializers are emitted before function bodies. + Own constants retain source-order visibility; imported constants are visible from the start. No stdin source input. Missing input, including no arguments, prints `cpsc: fatal error: no input files` and `compilation terminated.`, then returns 1. - `-h` anywhere in the arguments prints one documentation pointer to stdout and @@ -93,7 +104,7 @@ Driver behavior (`tools/driver/main.cc`): verification. Diagnostics stay on stderr; source errors preserve existing output. Native linking uses a staged file beside the output and renames it on success. - `-S` selects textual IR; otherwise output is a native executable. Without `-o`, - replace the source extension with `.ll` or `.out` beside the source on every OS. + replace the entry source extension with `.ll` or `.out` beside the source on every OS. `-o` paths are used literally and never select the format. `-r` alone saves nothing; either `-S` or `-o` requests saving before execution. - Lexer, Parser and CodeGen track error flags (`hadError()`); any error, including @@ -101,9 +112,11 @@ Driver behavior (`tools/driver/main.cc`): also return 1. Ordinary compiler errors use `error:`; failures that prevent compilation, such as file I/O errors, use `fatal error:`. The driver prints `compilation terminated.` once on compilation failure, including argument errors. + Multi-input lexer/parser/codegen diagnostics append the source path after the line number; + Diagnostics.h keeps single-input diagnostic text unchanged. Execution-stage failures do not print that line. Check the exit code rather than grepping stderr. -- Successful compilation overwrites the output, but paths aliasing the source +- Successful compilation overwrites the output, but paths aliasing any input source (including symlinks/hard links) are rejected. - In PATH mode, `-r` executes PATH's `lli` using LLVM Support process APIs, with inherited stdin/stdout/stderr and no shell. Missing lli is rejected before @@ -292,6 +305,7 @@ do not modify the real release for local verification. | `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 | | `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/GlobalGen.cc` | Primitive GLOBAL declaration and constant-initializer passes | | `lib/CodeGen/ConstantGen.cc` | Literal constants, declaration conflicts and lexical binding restoration | | `lib/CodeGen/ValueTypeGen.cc`, `OutputGen.cc`, `Builtins.h` | Expression typing, coercion/declarations, scalar output and the shared builtin table | | `lib/CodeGen/Designator.cc`, `TypeCheckGen.cc` | TYPE pre-pass, member lookup/calls and lvalue access; type admission and user-kind binary operators | diff --git a/AGENTS/CONVENTIONS.md b/AGENTS/CONVENTIONS.md index 87a95b7..2686760 100644 --- a/AGENTS/CONVENTIONS.md +++ b/AGENTS/CONVENTIONS.md @@ -97,7 +97,7 @@ 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, IsReference}`) in CodeGen is the only symbol table. +TypeName, IsArray, ConstantValue, ScopeID, IsReference, IsGlobal}`) 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 @@ -107,8 +107,8 @@ also bound directly by FunctionGen). `prepareSymbolDeclaration` diagnoses same-scope conflicts involving constants before declaration emission. Unique scope IDs distinguish sibling blocks; `emitScopedBlock` restores only bindings introduced by constants or hiding constants, preserving other variables' existing -function-wide visibility. FunctionGen saves/restores Symbols and inherits only -previously visible top-level constants (ScopeID 0). CodeGen isolates constant +function-wide visibility. FunctionGen saves/restores Symbols and inherits visible globals plus +previously visible top-level constants (ScopeID 0). Locals may shadow globals. CodeGen isolates constant scope bookkeeping and array metadata around each function body. Arrays also restore metadata at control-flow block exits. @@ -142,7 +142,7 @@ 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 get no mangling, so +no registered signature is a compile error. Global function names except MAIN get no mangling, so `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 @@ -180,3 +180,15 @@ plain calls. RETURN must finish all active catches after evaluating its value. throwing. Generated main catches anything unhandled, prints the generic termination message to stdout, and returns 1. Explicit bare THROW prints no diagnostic itself. Arrays in TRY and CATCH use separate block scopes; scalars retain existing function scope. + +**Compilation units and entry points.** SourceUnit borrows its AST list; it and the +visibility matrix must outlive compile(). Select the owning unit before each pre-pass, +prototype or body so diagnostics and name lookup use that file. TypeSystem's predicate +filters types and their enum values; FuncSig records OwnerUnit. Rebuild Symbols from +visible exports for each unit: imported constants are available immediately, own +constants only at their declaration, and globals from the beginning. GLOBAL bodies +contain only primitive scalar declarations and literal assignments; IsGlobal storage +is an LLVM GlobalVariable and must survive FunctionGen's symbol reset. User MAIN is +case insensitive, takes no parameters and returns INTEGER; its LLVM name is +__cps_main with internal linkage. The generated i32 main wrapper calls it through +ExceptionHandler, truncates its result and retains the final uncaught handler. diff --git a/AGENTS/PITFALLS.md b/AGENTS/PITFALLS.md index f2f4f7b..d811ea4 100644 --- a/AGENTS/PITFALLS.md +++ b/AGENTS/PITFALLS.md @@ -5,6 +5,13 @@ Every bullet below was confirmed against the source, most also by compiling and running 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. + 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 + scalar types and literal initializers; arrays, user types and computed initializers + are rejected. Own top-level constants remain positional, imported constants do not. - **OUTPUT accepts comma-separated expressions (§5.1).** Values are evaluated and printed left to right without automatic separators; the final scalar adds a newline. Whole arrays and subarrays still print each element on its own line, including in @@ -37,7 +44,7 @@ test programs. - **`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. -- **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. Only previously declared top-level constants are inherited by functions. Constants have no writable storage: assignment, INPUT, READFILE targets, FOR variables, BYREF and address-of are rejected. +- **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 uses token line information to recognize labels. Bare `RETURN` is recognized diff --git a/AGENTS/SUBSYSTEMS.md b/AGENTS/SUBSYSTEMS.md index 1621f11..d21dfe8 100644 --- a/AGENTS/SUBSYSTEMS.md +++ b/AGENTS/SUBSYSTEMS.md @@ -24,7 +24,7 @@ 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. Params are `ParamDecl{name, typeString, mode, array rank/bounds}`. BYVAL args are +name (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 @@ -34,7 +34,7 @@ map (`FunctionGen::getSignature`); `CodeGen::marshalCallArgs` dispatches call ar 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 TYPE pre-pass), so calls may precede definitions; calling a name with no signature is a -compile error (no extern is fabricated). Functions inherit previously declared top-level CONSTANT values; local constants use the same Symbols table with lexical binding restoration. Body emission is inverted: CodeGen injects 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 ArrayTable) afterwards. |
