aboutsummaryrefslogtreecommitdiff
path: root/AGENTS/CONVENTIONS/EXCEPTIONS_AND_UNITS.md
blob: 0b8a8875a6ae9d87aabab5b5c206a1597cc37dd7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

# Conventions: exceptions, compilation units and the standard library

Part of [Load-bearing conventions](../CONVENTIONS.md).

**Program exceptions use the C++ ABI; compiler diagnostics do not.**

- `ExceptionHandler` emits anonymous integer exceptions (an internal placeholder),
  `invoke`/`landingpad`/`resume`, and paired `__cxa_begin_catch`/`__cxa_end_catch`.
- Its handler stack and catch depth are keyed by LLVM function, so synthesizing file
  helpers never inherits the caller's catches.
- User calls, file runtime calls and THROW must use `ExceptionHandler::emitCall`;
  ordinary nonthrowing libc calls stay plain calls.
- RETURN must finish all active catches after evaluating its value.
- `RuntimeCheck::emitCheck` prints the source line and error reason to stderr before
  throwing. Generated main catches anything unhandled, prints the generic termination
  message to stderr, and returns 1. Explicit bare THROW prints no diagnostic itself.
- Arrays in TRY and CATCH use separate block scopes; scalars keep 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.

**Library regions.** PP_DEFINE __LIB enables library mode for subsequent source
positions; PP_UNDEF __LIB disables it, including inside functions. SourceUnit owns
LibraryLines and answers isLibrary(Line). RuntimeCheck queries the current unit's
map with each original source line and uses the shared external i32 __cps_user_line
only in enabled regions. FunctionGen's call hook updates that global for calls
from ordinary positions, regardless of the callee's header mode: a callee can
enable __LIB inside its body. Library calls preserve it. Runtime helper arguments
also use RuntimeCheck::lineValue. Templates keep definition source lines and
owning units; deferred object cleanup keeps its registration's line and unit.
Compiler diagnostics retain the owning file location.

**Default standard library.** The driver extracts embedded std.cps, its imported units
and matching objects to a content-keyed cache (or temporary fallback) that survives
linking/execution. User
units implicitly import std.cps; normal transitive visibility applies. -no-std
suppresses all default library inputs and objects. std.cps imports string.cps and
memory.cps; keyword NEW/DELETE require the latter even with -no-std. Explicit libraries retain the
ordinary INCLUDE/command-line rules. Source files and objects are embedded by a
build-time Perl generator. Saved -S output remains IR only.