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 | |
| 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>
| -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 | ||||
| -rw-r--r-- | doc/cpsc.1.md | 22 | ||||
| -rw-r--r-- | doc/language/cpsc-language-overview.7.md | 6 | ||||
| -rw-r--r-- | doc/language/keyword/cpsc-keyword-function.7.md | 2 | ||||
| -rw-r--r-- | doc/language/keyword/cpsc-keyword-global.7.md | 45 | ||||
| -rw-r--r-- | doc/language/keyword/cpsc-keyword-include.7.md | 42 | ||||
| -rw-r--r-- | plugin/syntaxes/cie-pseudocode.tmLanguage.json | 2 |
10 files changed, 156 insertions, 20 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. diff --git a/doc/cpsc.1.md b/doc/cpsc.1.md index 92f73b5..2bb1f1c 100644 --- a/doc/cpsc.1.md +++ b/doc/cpsc.1.md @@ -6,15 +6,19 @@ cpsc - compile and run CIE pseudocode # SYNOPSIS -**cpsc** [**-r**] [**-S**] [**-o** *output*] *source* +**cpsc** [**-r**] [**-S**] [**-o** *output*] *source* [*source* ...] **cpsc** **-h** # DESCRIPTION -Compile one pseudocode source file to a native executable, or to textual LLVM IR with **-S**. Options may appear before or after the source path. Source input from stdin is not supported. +Compile one or more pseudocode source files to a native executable, or to textual LLVM IR with **-S**. Options may appear among the source paths. Source input from stdin is not supported. -Without **-o**, save beside the source file, replacing its extension with `.out` for an executable or `.ll` for IR. This naming also applies on Windows. With **-r** alone, run without saving a file. +Without **-o**, save beside the entry source file, replacing its extension with `.out` for an executable or `.ll` for IR. This naming also applies on Windows. 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. + +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. # OPTIONS @@ -25,7 +29,7 @@ Without **-o**, save beside the source file, replacing its extension with `.out` : Save to the specified path. Without **-S**, save a native executable; with **-S**, save LLVM IR. Use the path exactly as given; its extension does not select the output format. May be specified only once. With **-r**, keep this file even if execution fails. **-S** -: Save textual LLVM IR instead of a native executable. Without **-o**, use the source filename with a `.ll` extension beside the source file. May be combined with **-r** to save IR and run the program. +: Save textual LLVM IR instead of a native executable. Without **-o**, use the entry source filename with a `.ll` extension beside the source file. May be combined with **-r** to save IR and run the program. **-r** : Run the compiled program with the runner selected at build time (see EXECUTION MODES). Save output first when **-S** or **-o** is also present; otherwise do not save a file. The program inherits stdin, stdout and stderr; `INPUT` can read terminal or piped input. @@ -88,6 +92,12 @@ cpsc test.cps -o test.out ./test.out ``` +Compile a program whose `me.cps` contains `INCLUDE "lib.cps"`: + +```sh +cpsc me.cps lib.cps -r +``` + # EXIT STATUS **0** @@ -96,13 +106,13 @@ cpsc test.cps -o test.out **1** : An argument, file, compilation or execution-engine error occurred, including missing input, when PATH mode cannot validate `lli` from LLVM 23 or NONE mode receives **-r**. -With **-r**, return the executed program's exit status. In PATH mode, failure to launch `lli` or a child-process crash returns 1. +With **-r**, return the executed program's exit status. MAIN's INTEGER result is truncated to 32 bits before returning to the operating system. In PATH mode, failure to launch `lli` or a child-process crash returns 1. An uncaught program exception returns 1 after printing `Unhandled exception. Program terminated.` to standard output. Runtime check failures print the source line and error reason to standard output before throwing and can be handled with TRY/CATCH/ENDTRY. # NOTES -Compiler diagnostics go to stderr. Failed source compilation does not write output; failed native linking does not replace an existing output file. Successful compilation overwrites an existing output file, but an output path that refers to the source file (including a symbolic or hard link) is rejected. +Compiler diagnostics go to stderr. With multiple input files, lexer, parser and code generation diagnostics include the source path after the line number. Failed source compilation does not write output; failed native linking does not replace an existing output file. Successful compilation overwrites an existing output file, but an output path that refers to any input source file (including a symbolic or hard link) is rejected. 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. diff --git a/doc/language/cpsc-language-overview.7.md b/doc/language/cpsc-language-overview.7.md index cb31d93..b03e0df 100644 --- a/doc/language/cpsc-language-overview.7.md +++ b/doc/language/cpsc-language-overview.7.md @@ -20,8 +20,12 @@ Declare variables before use. See DECLARE for built-in types and arrays, TYPE fo The compiler extensions TRY/CATCH/ENDTRY and THROW support anonymous exceptions with stack unwinding. Runtime check failures print the source line and error reason to standard output before throwing and can be caught. An uncaught exception also prints a generic termination message and returns status 1. There is no error object or what() support. +Multi-file builds use the compiler extensions INCLUDE and GLOBAL. Pass every source file on the command line and include the files whose definitions are needed. The entry file contains the sole top-level executable code, or a parameterless FUNCTION MAIN returning INTEGER; definitions alone do not form a runnable program. + # KEYWORDS +- [cpsc-keyword-include(7)](keyword/cpsc-keyword-include.7.md): import definitions from another compilation unit. +- [cpsc-keyword-global(7)](keyword/cpsc-keyword-global.7.md): declare shared primitive variables. - [cpsc-keyword-constant(7)](keyword/cpsc-keyword-constant.7.md): declare a named literal with block scope. - [cpsc-keyword-declare(7)](keyword/cpsc-keyword-declare.7.md): declare variables and arrays. - [cpsc-keyword-input(7)](keyword/cpsc-keyword-input.7.md): read a value from standard input. @@ -49,7 +53,7 @@ The compiler extensions TRY/CATCH/ENDTRY and THROW support anonymous exceptions - [cpsc-keyword-div(7)](keyword/cpsc-keyword-div.7.md): perform integer division. - [cpsc-keyword-mod(7)](keyword/cpsc-keyword-mod.7.md): find the integer division remainder. -Closing and auxiliary keywords are documented with their main constructs: THEN/ELSE/ENDIF with IF; OF/OTHERWISE/ENDCASE with CASE; CATCH/ENDTRY/THROW with TRY; ENDWHILE with WHILE; UNTIL with REPEAT; TO/STEP/NEXT with FOR; RETURN/RETURNS/BYVAL/BYREF and function/procedure closing keywords with FUNCTION/PROCEDURE; READ/WRITE/APPEND with OPENFILE; ARRAY/OF and INTEGER/REAL/BOOLEAN/CHAR/STRING with DECLARE; ENDTYPE with TYPE; PUBLIC/PRIVATE/ENDCLASS with CLASS. TRUE/FALSE are BOOLEAN literals. +Closing and auxiliary keywords are documented with their main constructs: THEN/ELSE/ENDIF with IF; OF/OTHERWISE/ENDCASE with CASE; CATCH/ENDTRY/THROW with TRY; ENDWHILE with WHILE; UNTIL with REPEAT; TO/STEP/NEXT with FOR; RETURN/RETURNS/BYVAL/BYREF and function/procedure closing keywords with FUNCTION/PROCEDURE; READ/WRITE/APPEND with OPENFILE; ARRAY/OF and INTEGER/REAL/BOOLEAN/CHAR/STRING with DECLARE; ENDGLOBAL with GLOBAL; ENDTYPE with TYPE; PUBLIC/PRIVATE/ENDCLASS with CLASS. TRUE/FALSE are BOOLEAN literals. # BUILT-IN FUNCTIONS diff --git a/doc/language/keyword/cpsc-keyword-function.7.md b/doc/language/keyword/cpsc-keyword-function.7.md index c20bb50..d734da3 100644 --- a/doc/language/keyword/cpsc-keyword-function.7.md +++ b/doc/language/keyword/cpsc-keyword-function.7.md @@ -23,6 +23,8 @@ Parameters use `name : type`, optionally prefixed by BYVAL. BYVAL is the default A FUNCTION inside CLASS defines a member function, called as `Object.Method(arguments)`. It follows the same parameter and return rules. Within a method, use `this.Method(arguments)` to call another method on the current object; see [cpsc-keyword-class(7)](cpsc-keyword-class.7.md). +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. + # EXAMPLE ```text diff --git a/doc/language/keyword/cpsc-keyword-global.7.md b/doc/language/keyword/cpsc-keyword-global.7.md new file mode 100644 index 0000000..643e0bb --- /dev/null +++ b/doc/language/keyword/cpsc-keyword-global.7.md @@ -0,0 +1,45 @@ +% CPSC-KEYWORD-GLOBAL(7) + +# NAME + +cpsc-keyword-global, cpsc-keyword-endglobal - declare shared primitive variables + +# SYNOPSIS + +```text +GLOBAL + DECLARE name : type + name <- literal +ENDGLOBAL +``` + +# DESCRIPTION + +GLOBAL and ENDGLOBAL are compiler extensions. Any number of GLOBAL blocks may appear at top level. Their bodies allow only DECLARE of INTEGER, REAL, CHAR, STRING or BOOLEAN variables and literal assignments to declared global variables. Negative numeric literals are allowed. Arrays, records, classes, C aliases, constructor arguments, calls, NEW and computed expressions are unsupported. + +Global variables have program lifetime and shared writable storage. They are visible throughout their own source file and in files importing them with INCLUDE, including inside functions and methods. Local variables and parameters may shadow them. Initializers are constants established before entry; omitted initializers use zero, FALSE or null, with null STRING values read as empty strings. A STRING literal initializes a pointer to shared literal storage. + +A GLOBAL block does not count as top-level executable code. A build still requires top-level executable statements in exactly one file, or a parameterless FUNCTION MAIN returning INTEGER. + +# EXAMPLE + +```text +GLOBAL + DECLARE Counter : INTEGER + Counter <- 2 +ENDGLOBAL + +PROCEDURE Increment + Counter <- Counter + 1 +ENDPROCEDURE + +FUNCTION MAIN RETURNS INTEGER + CALL Increment() + OUTPUT Counter + RETURN 0 +ENDFUNCTION +``` + +# SEE ALSO + +[cpsc-language-overview(7)](../cpsc-language-overview.7.md), [cpsc-keyword-include(7)](cpsc-keyword-include.7.md), [cpsc-keyword-declare(7)](cpsc-keyword-declare.7.md), [cpsc-keyword-function(7)](cpsc-keyword-function.7.md). diff --git a/doc/language/keyword/cpsc-keyword-include.7.md b/doc/language/keyword/cpsc-keyword-include.7.md new file mode 100644 index 0000000..5600472 --- /dev/null +++ b/doc/language/keyword/cpsc-keyword-include.7.md @@ -0,0 +1,42 @@ +% CPSC-KEYWORD-INCLUDE(7) + +# NAME + +cpsc-keyword-include - import definitions from another source file + +# SYNOPSIS + +```text +INCLUDE "path.cps" +``` + +# DESCRIPTION + +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. + +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. + +# EXAMPLE + +`me.cps`: + +```text +INCLUDE "lib.cps" +OUTPUT Add(1, 2) +``` + +`lib.cps`: + +```text +FUNCTION Add(a : INTEGER, b : INTEGER) RETURNS INTEGER + RETURN a + b +ENDFUNCTION +``` + +Run with `cpsc me.cps lib.cps -r` to print `3`. + +# SEE ALSO + +[cpsc(1)](../../cpsc.1.md), [cpsc-language-overview(7)](../cpsc-language-overview.7.md), [cpsc-keyword-global(7)](cpsc-keyword-global.7.md), [cpsc-keyword-function(7)](cpsc-keyword-function.7.md). diff --git a/plugin/syntaxes/cie-pseudocode.tmLanguage.json b/plugin/syntaxes/cie-pseudocode.tmLanguage.json index 7416518..0ae08cc 100644 --- a/plugin/syntaxes/cie-pseudocode.tmLanguage.json +++ b/plugin/syntaxes/cie-pseudocode.tmLanguage.json @@ -25,7 +25,7 @@ "name": "keyword.control.cie-pseudocode" }, { - "match": "(?<!\\w)(?:DECLARE|TYPE|ENDTYPE|FUNCTION|ENDFUNCTION|PROCEDURE|ENDPROCEDURE|RETURNS|BYREF|BYVAL|OF)(?!\\w)", + "match": "(?<!\\w)(?:INCLUDE|GLOBAL|ENDGLOBAL|DECLARE|TYPE|ENDTYPE|FUNCTION|ENDFUNCTION|PROCEDURE|ENDPROCEDURE|RETURNS|BYREF|BYVAL|OF)(?!\\w)", "name": "storage.modifier.cie-pseudocode" }, { |
