From 8d9510e9aebc013785b6339b15cf3a1d2cb8c6f2 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Sat, 25 Oct 2025 10:12:36 -0700 Subject: [PATCH] update docs --- CLAUDE.md | 34 +++++++++++++++++++++++++++++++ GUIDE.md | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 4b3ac5e..31440d8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -222,6 +222,40 @@ HALT HALT ``` +### Function Definition Patterns + +When defining functions, you MUST prevent the PC from falling through into function bodies. Two patterns: + +**Pattern 1: JUMP over function bodies (Recommended)** +``` +MAKE_FUNCTION (params) .body +STORE function_name +JUMP .end ; Skip over function body +.body: + + RETURN +.end: + +``` + +**Pattern 2: Function bodies after HALT** +``` +MAKE_FUNCTION (params) .body +STORE function_name + +HALT ; Stop before function bodies +.body: + + RETURN +``` + +Pattern 1 is required for: +- Defining multiple functions before using them +- REPL mode +- Any case where execution continues after defining a function + +Pattern 2 only works if you HALT before reaching function bodies. + ### REPL Mode (Incremental Execution) For building REPLs (like the Shrimp REPL), use `vm.continue()` and `vm.appendBytecode()`: diff --git a/GUIDE.md b/GUIDE.md index f51bf0a..99b8073 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -241,6 +241,40 @@ CALL ## Compiler Patterns +### Function Definitions + +When defining functions, you must prevent the PC from "falling through" into the function body during sequential execution. There are two standard patterns: + +**Pattern 1: JUMP over function bodies (Recommended)** +``` +MAKE_FUNCTION (params) .body +STORE function_name +JUMP .end ; Skip over function body +.body: + + RETURN +.end: + +``` + +**Pattern 2: Function bodies after HALT** +``` +MAKE_FUNCTION (params) .body +STORE function_name + +HALT ; Stop execution before function bodies +.body: + + RETURN +``` + +**Important**: Pattern 2 only works if you HALT before reaching function bodies. Pattern 1 is more flexible and required for: +- Defining multiple functions before using them +- REPL mode (incremental execution) +- Any case where execution continues after defining a function + +**Why?** `MAKE_FUNCTION` creates a function value but doesn't jump to the body—it just stores the body's address. Without JUMP or HALT, the PC increments into the function body and executes it as top-level code. + ### If-Else ``` @@ -362,7 +396,8 @@ Functions automatically capture current scope: PUSH 0 STORE counter MAKE_FUNCTION () .increment -RETURN +STORE increment_fn +JUMP .main .increment: LOAD counter ; Captured variable @@ -371,6 +406,18 @@ RETURN STORE counter LOAD counter RETURN + +.main: + LOAD increment_fn + PUSH 0 + PUSH 0 + CALL ; Returns 1 + POP + LOAD increment_fn + PUSH 0 + PUSH 0 + CALL ; Returns 2 (counter persists!) + HALT ``` ### Tail Recursion @@ -378,7 +425,7 @@ Use TAIL_CALL instead of CALL for last call: ``` MAKE_FUNCTION (n acc) .factorial STORE factorial -<...> +JUMP .main .factorial: LOAD n @@ -398,6 +445,15 @@ STORE factorial PUSH 2 PUSH 0 TAIL_CALL ; Reuses stack frame + +.main: + LOAD factorial + PUSH 5 + PUSH 1 + PUSH 2 + PUSH 0 + CALL ; factorial(5, 1) = 120 + HALT ``` ### Optional Function Calls (TRY_CALL)