aboutsummaryrefslogtreecommitdiff
path: root/AGENTS
diff options
context:
space:
mode:
Diffstat (limited to 'AGENTS')
-rw-r--r--AGENTS/CONVENTIONS.md19
-rw-r--r--AGENTS/PITFALLS.md3
-rw-r--r--AGENTS/SUBSYSTEMS.md21
3 files changed, 22 insertions, 21 deletions
diff --git a/AGENTS/CONVENTIONS.md b/AGENTS/CONVENTIONS.md
index c05734f..e09b6ee 100644
--- a/AGENTS/CONVENTIONS.md
+++ b/AGENTS/CONVENTIONS.md
@@ -58,16 +58,15 @@ non-zero when any flag is set. The parser still drops a failed statement, skips
token, and continues — later statements can be swallowed during recovery, but the
failure is always diagnosed and reflected in the exit code.
-**BYREF is a pointer-typed parameter, inferred structurally at call sites.**
-`FunctionGen` emits pointer params for BYREF; call sites (in CodeGen, duplicated for
-call-expr and call-stmt) treat *any* pointer-typed callee param as BYREF and require the
-argument to be a bare variable whose alloca is passed. The callee side, however, binds
-by the *declared* flag. Since STRING itself lowers to `ptr`, the two sides disagree for
-STRING: the caller always passes the alloca, but a declared-BYVAL STRING param (the
-default) copies that alloca *address* and treats it as the string data pointer — reading
-garbage at runtime. Only declared-BYREF STRING parameters work, and STRING arguments can
-never be literals/expressions. Function names get no mangling — a pseudocode
-`FUNCTION printf` collides with libc.
+**Calls dispatch on the declared signature.** `FunctionGen::emitPrototype` records every
+function's pseudocode signature (`FuncSig`: return type name + per-param type name and
+BYREF flag); `CodeGen::marshalCallArgs` — the single call-marshalling path for both
+call-expr and call-stmt — requires BYREF arguments to be bare variables (their alloca is
+passed) and coerces BYVAL arguments to the declared parameter type. STRING works on both
+sides in both modes. Top-level prototypes are pre-registered before statement emission,
+so call-before-definition is fine; a call with no registered signature is a compile
+error. Function names get no mangling — a pseudocode `FUNCTION printf` collides with
+libc.
**Builtins are plain identifiers backed by one table.** All 11 builtins
(LENGTH/MID/RIGHT/LEFT/LCASE/UCASE/ASC/CHR/IS_NUM/NUM_TO_STR/STR_TO_NUM) parse as
diff --git a/AGENTS/PITFALLS.md b/AGENTS/PITFALLS.md
index b068dee..393f507 100644
--- a/AGENTS/PITFALLS.md
+++ b/AGENTS/PITFALLS.md
@@ -20,8 +20,7 @@ test programs.
bits.
- **`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 substitutes INTEGER for a nullptr result — so wrong
- inference prints garbage instead of erroring.
+ unknown-function calls; OUTPUT reports an error for a nullptr result.
- The lexer emits no newline tokens; the grammar is purely keyword-delimited. Bare
`RETURN` is only recognized right before ENDIF/ELSE/ENDFUNCTION/ENDPROCEDURE.
- Invalid modules still print their IR, but `verifyModule` runs at the end of
diff --git a/AGENTS/SUBSYSTEMS.md b/AGENTS/SUBSYSTEMS.md
index 2910bb3..f26cddc 100644
--- a/AGENTS/SUBSYSTEMS.md
+++ b/AGENTS/SUBSYSTEMS.md
@@ -6,9 +6,10 @@ known bugs: `PITFALLS.md`.)
**Arrays** (`ArrayHandler`): a DECLAREd array is one malloc'd flat buffer (memset to
zero), row-major, any rank, any bounds. Bounds and multipliers are *compile-time SSA
values* cached in `ArrayMetadata` (global `ArrayTable` map, keyed by name). Every access
-goes through `getMetadata` → per-dimension `emitIndexCheck` → `computeFlatIndex` →
-`getElementPointer`; never hand-roll indexing. STRING elements read as null until
-written; every read path must replicate the null-guard `select` to the empty string.
+goes through `emitCheckedIndices` (validates the index count for the caller's semantics,
+then per-dimension coerce + `emitIndexCheck`) → `computeFlatIndex` → `loadElement`
+(load + the STRING null-guard `select` to the empty string); never hand-roll indexing
+or element loads.
`OUTPUT arr` (and partially-indexed accesses) is intercepted by
`ArrayHandler::tryEmitArrayOutput` — the first branch of OUTPUT dispatch, emitting
nested print loops — so any rework of OUTPUT must preserve that interception.
@@ -17,12 +18,14 @@ nested print loops — so any rework of OUTPUT must preserve that interception.
name. Params are `tuple<name, typeString, isByRef>`. BYVAL args are copied into
entry-block allocas; BYREF args bind the incoming pointer directly as the variable's
storage. Missing RETURNS defaults the return type to INTEGER; procedures use "VOID".
-**Definitions must precede first call**: calling a not-yet-defined function fabricates
-an extern declaration (i64 return, param types guessed from the arguments), and when the
-real definition arrives, `emitFunctionDef` reuses that declaration by name without
-checking the signature — the body attaches to the wrong prototype and the module is
-invalid. Body emission is inverted: CodeGen injects a `StmtEmitter` callback, and must
-restore its own insert point afterwards.
+`emitPrototype` records each function's pseudocode signature in a `FuncSig` map
+(`FunctionGen::getSignature`); `CodeGen::marshalCallArgs` dispatches call arguments on
+those *declared* param types and BYREF flags (BYVAL args are coerced to the declared
+type), and `getExprTypeInfo` reads return types from the same map. Top-level prototypes
+are pre-registered at the start of `compile()`, so calls may precede definitions;
+calling a name with no signature is a compile error (no extern is fabricated). Body
+emission is inverted: CodeGen injects a `StmtEmitter` callback, and must restore its
+own insert point afterwards.
**Runtime checks** (`RuntimeCheck`): only array bounds checking is actually wired up.
`emitDivZeroCheck` exists but has **zero call sites** — division by zero (for `/`, DIV