about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--awk/scheme/scheme/Makefile52
-rw-r--r--awk/scheme/scheme/README.md380
-rw-r--r--awk/scheme/scheme/TODO.txt70
-rw-r--r--awk/scheme/scheme/WHAT-NEEDS-FIXING.md49
-rwxr-xr-xawk/scheme/scheme/bin/compiler.awk1140
-rwxr-xr-xawk/scheme/scheme/bin/repl14
-rwxr-xr-xawk/scheme/scheme/bin/vm.awk1751
-rw-r--r--awk/scheme/scheme/diagram.md161
-rw-r--r--awk/scheme/scheme/examples/cons.test.scm3
-rw-r--r--awk/scheme/scheme/examples/define.test.scm2
-rw-r--r--awk/scheme/scheme/examples/lambda.test.scm12
-rw-r--r--awk/scheme/scheme/examples/let-and-define.test.scm9
-rw-r--r--awk/scheme/scheme/examples/let.test.scm2
-rw-r--r--awk/scheme/scheme/scratch/OUTLINE.md372
-rw-r--r--awk/scheme/scheme/scratch/arch-notes.md230
-rw-r--r--awk/scheme/scheme/scratch/complex_test.scm.asm44
-rw-r--r--awk/scheme/scheme/scratch/forth/README.md139
-rwxr-xr-xawk/scheme/scheme/scratch/forth/forth.awk249
-rw-r--r--awk/scheme/scheme/scratch/ideas-for-string-support.md556
-rw-r--r--awk/scheme/scheme/scratch/random.txt112
-rwxr-xr-xawk/scheme/scheme/scratch/run.sh5
-rw-r--r--awk/scheme/scheme/scratch/test.asm16
-rw-r--r--awk/scheme/scheme/scratch/test.scm8
-rw-r--r--awk/scheme/scheme/scratch/test.scm.asm7
-rw-r--r--awk/scheme/scheme/test/README.md144
-rw-r--r--awk/scheme/scheme/test/examples/calculator.scm14
-rw-r--r--awk/scheme/scheme/test/examples/list_utils.scm17
-rw-r--r--awk/scheme/scheme/test/examples/string_utils.scm16
-rw-r--r--awk/scheme/scheme/test/integration/basic_arithmetic.scm10
-rw-r--r--awk/scheme/scheme/test/integration/complex_programs.scm86
-rw-r--r--awk/scheme/scheme/test/integration/function_composition.scm9
-rw-r--r--awk/scheme/scheme/test/integration/higher_order_functions.scm55
-rw-r--r--awk/scheme/scheme/test/integration/list_operations.scm10
-rw-r--r--awk/scheme/scheme/test/integration/string_operations.scm9
-rw-r--r--awk/scheme/scheme/test/regression/edge_cases.scm21
-rw-r--r--awk/scheme/scheme/test/regression/nested_expressions.scm15
-rwxr-xr-xawk/scheme/scheme/test/run_tests.sh189
-rw-r--r--awk/scheme/scheme/test/unit/additional_lists.scm24
-rw-r--r--awk/scheme/scheme/test/unit/advanced_control_flow.scm46
-rw-r--r--awk/scheme/scheme/test/unit/advanced_functions.scm68
-rw-r--r--awk/scheme/scheme/test/unit/basic_higher_order_functions.scm24
-rw-r--r--awk/scheme/scheme/test/unit/basic_map_operations.scm15
-rw-r--r--awk/scheme/scheme/test/unit/basic_numeric_operations.scm40
-rw-r--r--awk/scheme/scheme/test/unit/basic_stdlib_test.scm4
-rw-r--r--awk/scheme/scheme/test/unit/booleans.scm6
-rw-r--r--awk/scheme/scheme/test/unit/caddr_test.scm1
-rw-r--r--awk/scheme/scheme/test/unit/call_stack_infrastructure.scm6
-rw-r--r--awk/scheme/scheme/test/unit/closures.scm3
-rw-r--r--awk/scheme/scheme/test/unit/comprehensive_higher_order_functions.scm52
-rw-r--r--awk/scheme/scheme/test/unit/comprehensive_numeric_and_type_operations.scm174
-rw-r--r--awk/scheme/scheme/test/unit/control_flow.scm56
-rw-r--r--awk/scheme/scheme/test/unit/environment_scoping.scm66
-rw-r--r--awk/scheme/scheme/test/unit/error_handling.scm42
-rw-r--r--awk/scheme/scheme/test/unit/essential_numeric_operations.scm29
-rw-r--r--awk/scheme/scheme/test/unit/functions.scm8
-rw-r--r--awk/scheme/scheme/test/unit/inc_alias_test.scm13
-rw-r--r--awk/scheme/scheme/test/unit/lambdas.scm4
-rw-r--r--awk/scheme/scheme/test/unit/let.scm3
-rw-r--r--awk/scheme/scheme/test/unit/lists.scm7
-rw-r--r--awk/scheme/scheme/test/unit/minimal_closure_env.scm8
-rw-r--r--awk/scheme/scheme/test/unit/minimal_function_persistence.scm2
-rw-r--r--awk/scheme/scheme/test/unit/minimal_global_persistence.scm2
-rw-r--r--awk/scheme/scheme/test/unit/numbers.scm9
-rw-r--r--awk/scheme/scheme/test/unit/performance_stress.scm62
-rw-r--r--awk/scheme/scheme/test/unit/simple_additional_lists.scm9
-rw-r--r--awk/scheme/scheme/test/unit/simple_cond.scm4
-rw-r--r--awk/scheme/scheme/test/unit/simple_control_flow.scm19
-rw-r--r--awk/scheme/scheme/test/unit/simple_member.scm5
-rw-r--r--awk/scheme/scheme/test/unit/simple_stdlib_test.scm13
-rw-r--r--awk/scheme/scheme/test/unit/simple_string_append_test.scm11
-rw-r--r--awk/scheme/scheme/test/unit/single_list.scm4
-rw-r--r--awk/scheme/scheme/test/unit/stdlib_lists.scm55
-rw-r--r--awk/scheme/scheme/test/unit/stdlib_results_test.scm42
-rw-r--r--awk/scheme/scheme/test/unit/string_append_variable_args.scm54
-rw-r--r--awk/scheme/scheme/test/unit/strings.scm16
-rw-r--r--awk/scheme/scheme/test/unit/variables.scm8
-rw-r--r--awk/scheme/scheme/test/unit/vm_instructions.scm77
-rw-r--r--awk/uxn/.gitignore3
-rw-r--r--awk/uxn/README.md0
-rw-r--r--awk/uxn/awk/uxnasm.awk916
-rw-r--r--awk/uxn/ref/uxnasm.c481
-rwxr-xr-xawk/uxn/test/runner.sh105
-rw-r--r--awk/uxn/test/tal/brk.tal1
-rw-r--r--awk/uxn/test/tal/brk_test.tal1
-rw-r--r--awk/uxn/test/tal/brk_with_data.tal1
-rw-r--r--awk/uxn/test/tal/bunnymark.tal221
-rw-r--r--awk/uxn/test/tal/life.tal221
-rw-r--r--awk/uxn/test/tal/opctest.tal492
-rw-r--r--awk/uxn/test/tal/proper.tal1
-rw-r--r--awk/uxn/test/tal/simple.tal1
-rw-r--r--awk/uxn/test/tal/simple2.tal1
-rw-r--r--awk/uxn/test/tal/simple3.tal1
-rwxr-xr-xbash/computer295
-rwxr-xr-xbash/exploration246
-rwxr-xr-xbash/logging.sh146
-rwxr-xr-xbash/metrics18
-rwxr-xr-xbash/synthesis240
-rw-r--r--js/seed/README.md15
-rwxr-xr-xjs/seed/seed75
-rw-r--r--js/seed/src/app.js8
-rw-r--r--js/seed/src/dev.js4
-rw-r--r--js/seed/src/view.js6
102 files changed, 9086 insertions, 1482 deletions
diff --git a/awk/scheme/scheme/Makefile b/awk/scheme/scheme/Makefile
new file mode 100644
index 0000000..52eaed5
--- /dev/null
+++ b/awk/scheme/scheme/Makefile
@@ -0,0 +1,52 @@
+# Makefile for Awk-Scheme
+
+.PHONY: test test-debug clean
+
+# Default target
+all: test
+
+# Run all tests
+test:
+	@echo "Running Awk-Scheme test suite..."
+	@./test/run_tests.sh
+
+# Run tests with debug output
+test-debug:
+	@echo "Running Awk-Scheme test suite with debug output..."
+	@DEBUG=1 ./test/run_tests.sh
+
+# Run specific test categories
+test-unit:
+	@echo "Running unit tests..."
+	@find test/unit -name "*.scm" -exec ./scheme {} \;
+
+test-integration:
+	@echo "Running integration tests..."
+	@find test/integration -name "*.scm" -exec ./scheme {} \;
+
+test-examples:
+	@echo "Running example programs..."
+	@find test/examples -name "*.scm" -exec ./scheme {} \;
+
+test-regression:
+	@echo "Running regression tests..."
+	@find test/regression -name "*.scm" -exec ./scheme {} \;
+
+# Clean up temporary files
+clean:
+	@echo "Cleaning up temporary files..."
+	@rm -f /tmp/scheme_vm.state /tmp/scheme_vm.env
+	@find . -name "*.tmp" -delete
+	@find . -name "*~" -delete
+
+# Show help
+help:
+	@echo "Available targets:"
+	@echo "  test          - Run all tests"
+	@echo "  test-debug    - Run all tests with debug output"
+	@echo "  test-unit     - Run only unit tests"
+	@echo "  test-integration - Run only integration tests"
+	@echo "  test-examples - Run only example programs"
+	@echo "  test-regression - Run only regression tests"
+	@echo "  clean         - Clean up temporary files"
+	@echo "  help          - Show this help message" 
\ No newline at end of file
diff --git a/awk/scheme/scheme/README.md b/awk/scheme/scheme/README.md
index 5dae265..0b925f4 100644
--- a/awk/scheme/scheme/README.md
+++ b/awk/scheme/scheme/README.md
@@ -1,220 +1,232 @@
 # Awk-Scheme
 
-## Overview
-A scheme interpreter implemented in AWK:
+A Scheme interpreter implemented in AWK with a stack-based virtual machine.
 
-- A compiler that translates scheme expressions to stack-based VM instructions
-- A virtual machine that executes the compiled code
-- Support for basic arithmetic, list operations, functions, and variable bindings
-- **Closure support** for nested function definitions and lexical scoping
-- Persistent global state between REPL sessions
+## Overview
 
-## Architecture
+- **Compiler** (`bin/compiler.awk`): Translates Scheme to VM bytecode
+- **Virtual Machine** (`bin/vm.awk`): Executes bytecode with stack-based evaluation
+- **REPL** (`bin/repl`): Interactive interface with debug support
+- **Standard Library**: Essential functions for lists, strings, math, and control flow
+- **Higher-Order Functions**: `map` and `filter` with support for all function types
 
-### Components
-1. **Compiler** (`bin/compiler.awk`):
-   - Lexical analyzer for tokenizing input
-   - Recursive descent parser for scheme expressions
-   - Code generator that produces stack-based VM instructions
-   - Handles nested expressions and proper scoping
-   - **Generates closure creation code for lambda expressions**
-
-2. **Virtual Machine** (`bin/vm.awk`):
-   - Stack-based execution model
-   - Typed value system with runtime type checking
-   - Environment-based variable binding
-   - **Direct function execution** (no program array modification)
-   - **Closure support** with environment capture and restoration
-   - Heap memory for cons cells
-   - State persistence for globals and functions
-
-3. **REPL** (`bin/repl`):
-   - Interactive command line interface
-   - Multi-line input support
-   - State persistence between sessions
-   - Debug mode support
+## Quick Start
 
-### Data Types
-All values are tagged with their type:
-- `N:value` - Numbers (integers)
-- `B:value` - Booleans (0/1)
-- `P:index` - Pairs (cons cells)
-- `F:name` - Functions
-- `NIL:` - Empty list
-- `S:name` - Symbols
-- **`CLOSURE:func_name:env_id` - Closure objects (function + captured environment)**
-
-## Usage
-
-### Running the REPL
 ```bash
-# Start interactive REPL
+# Interactive REPL
 ./scheme
 
-# Run a Scheme file
-./scheme myprogram.scm
+# Run a file
+./scheme program.scm
 
-# Enable debug output
+# Debug mode
 DEBUG=1 ./scheme
 ```
 
-### Basic Operations
+## Core Features
 
-1. **Arithmetic**:
+### Basic Operations
 ```scheme
-scheme> (+ 1 2 3)
-N:6
-scheme> (* 4 (- 10 5))
-N:20
+(+ 1 2 3)                    ; => N:6
+(define x 42)                ; => N:42
+(cons 1 (cons 2 nil))        ; => P:1
+((lambda (x) (+ x 1)) 41)    ; => N:42
 ```
 
-2. **Comparisons**:
+### Higher-Order Functions
 ```scheme
-scheme> (< 1 2)
-B:1
-scheme> (= 42 42)
-B:1
+(map abs (list -1 -2 -3))    ; => (1 2 3)
+(filter positive? (list -1 2 -3 4))  ; => (2 4)
+(define double (lambda (x) (* x 2)))
+(map double (list 1 2 3))    ; => (2 4 6)
 ```
 
-3. **Lists**:
+### Control Flow
 ```scheme
-scheme> (cons 1 (cons 2 nil))
-P:1
-scheme> (car (cons 1 2))
-N:1
+(if (> 5 3) "yes" "no")      ; => STR:yes
+(cond ((> 5 10) "big") 
+      ((> 5 3) "medium") 
+      (else "small"))        ; => STR:medium
 ```
 
-4. **Variables**:
-```scheme
-scheme> (define x 42)
-N:42
-scheme> x
-N:42
+## Standard Library
+
+### Numeric Operations
+- `(+ - * /)` - Basic arithmetic (supports multiple arguments)
+- `(modulo expt abs min max)` - Advanced math
+- `(zero? positive? negative?)` - Number predicates
+
+### List Operations
+- `(cons car cdr length append reverse member)` - Core list functions
+- `(cadr caddr list-ref list-tail)` - List access utilities
+- `(null? pair?)` - List type predicates
+
+### String Operations
+- `(string-length string-append string-ref substring)` - String manipulation
+- `(string=? string<? string>?)` - String comparison
+
+### Control Flow
+- `(if cond and or not)` - Logic and conditionals
+
+## Architecture
+
+### Data Types
+All values are tagged: `N:42` (number), `B:1` (boolean), `P:1` (pair), `S:name` (symbol), `CLOSURE:fn:env` (closure), `STR:content` (string), `NIL:` (empty list).
+
+### VM Instructions
+- **Stack**: `PUSH_CONST`, `POP`, `ADD`, `SUB`, `MUL`, `DIV`
+- **Environment**: `STORE`, `LOOKUP`, `POP_ENV`
+- **Functions**: `LABEL`, `CALL`, `RETURN`
+- **Closures**: `CAPTURE_ENV`, `PUSH_CONST CLOSURE:fn:env`
+
+### Execution Flow
+```
+Scheme Code → Compiler → VM Bytecode → Virtual Machine → Result
 ```
 
-5. **Functions**:
-```scheme
-scheme> (define add (x y) (+ x y))
-scheme> (add 2 3)
-N:5
+## Testing
+
+```bash
+# Run all tests
+./test/run_tests.sh
+
+# Run with debug
+DEBUG=1 ./test/run_tests.sh
 ```
 
-6. **Let Expressions**:
-```scheme
-scheme> (let ((x 10) (y 20)) (+ x y))
-N:30
+Test categories:
+- **Unit tests**: Individual features
+- **Integration tests**: Feature combinations
+- **Examples**: Demonstration programs
+- **Regression tests**: Edge cases
+
+*Note: The test suite is comprehensive, but some advanced closure/currying and edge-case features are still being debugged. See Known Issues below.*
+
+## Debugging
+
+### Enable Debug Mode
+```bash
+DEBUG=1 ./scheme                    # REPL with debug
+DEBUG=1 ./scheme program.scm        # File with debug
+echo "(+ 1 2)" | DEBUG=1 ./scheme   # Single expression
 ```
 
-7. **Lambda Functions**:
-```scheme
-scheme> ((lambda (x) (+ x 1)) 41)
-N:42
-scheme> ((lambda (x y) (+ x y)) 20 22)
-N:42
+**S-expression Debugging:**
+```bash
+DEBUG_SEXPR=1 ./scheme program.scm  # Enable detailed S-expression parsing/codegen debug output
 ```
 
-8. **Closures**:
-```scheme
-scheme> (let ((x 10)) ((lambda (y) (+ x y)) 32))
-N:42
-scheme> (let ((add1 (lambda (x) (+ x 1)))) (add1 41))
-N:42
-```
-
-**Note**: Nested lambda definitions (lambdas defined inside other lambdas) are not yet supported.
-
-## Implementation Details
-
-### Compiler Pipeline
-1. **Lexical Analysis**:
-   - Tokenizes input into numbers, symbols, and parentheses
-   - Handles whitespace and basic comments
-
-2. **Parsing**:
-   - Builds expression tree from tokens
-   - Validates syntax and expression structure
-
-3. **Code Generation**:
-   - Translates expressions to VM instructions
-   - Manages scope and variable bindings
-   - Handles function definitions
-   - **Generates closure creation code for lambda expressions**
-
-### Virtual Machine
-1. **Stack Operations**:
-   - PUSH_CONST: Push constant value
-   - POP: Remove top value
-   - STORE: Store variable binding
-   - LOOKUP: Retrieve variable value
-
-2. **Function Calls**:
-   - **Direct execution** of function code with proper program restoration
-   - Environment frame management
-   - **Closure support** with environment capture and restoration
-
-3. **Closure System**:
-   - **CAPTURE_ENV**: Captures current environment for closure creation
-   - **Environment restoration**: Restores captured environments on closure calls
-   - **Variable lookup enhancement**: Checks closure environments for variable resolution
-
-4. **Memory Management**:
-   - Stack-based evaluation
-   - Simple heap for cons cells
-   - Basic reference counting (not fully implemented)
-
-### State Persistence
-- Global variables and functions persist between sessions
-- State stored in `/tmp/scheme_vm.state` and `/tmp/scheme_vm.env`
-- Automatic state loading/saving
-- **Note**: State persistence is enabled by default in the REPL
-
-## Extending the System
-
-### Adding New Special Forms
-1. Add parsing in `compile_expr()`
-2. Implement code generation function
-3. Add corresponding VM instructions if needed
-
-### Adding New Data Types
-1. Define new type tag in VM
-2. Add type checking predicates
-3. Implement value construction/access
-4. Update relevant operations
-
-### Adding VM Instructions
-1. Add instruction handling in `execute()`
-2. Implement instruction logic
-3. Update compiler to generate new instruction
-
-### Debugging
-- Enable debug output: `DEBUG=1 ./scheme`
-- Debug messages show:
-  - Lexical analysis
-  - Parsing steps
-  - Code generation
-  - VM execution
-  - Stack operations
-  - Environment changes
-  - **Closure creation and restoration**
-- **Note**: Some debug output may be suppressed in the current implementation
+### Debug Output Shows
+- Token parsing and expression tree construction
+- VM instruction generation
+- Step-by-step execution with stack state
+- Environment changes and variable lookups
+- Function calls and closure operations
+
+### Command-Line Debugging Hints
+
+**View bytecode generation**:
+```bash
+echo "(+ 1 2)" | ./bin/compiler.awk
+```
+
+**Step-by-step VM execution**:
+```bash
+echo "(+ 1 2)" | ./bin/compiler.awk | DEBUG=1 ./bin/vm.awk
+```
+
+**Trace specific functions**:
+```bash
+grep -n "function_name" bin/vm.awk
+```
+
+**Check syntax errors**:
+```bash
+echo "(+ 1" | ./bin/compiler.awk  # Should show error
+```
+
+**Compare outputs**:
+```bash
+diff <(echo "(+ 1 2)" | ./bin/compiler.awk) <(echo "(+ 2 1)" | ./bin/compiler.awk)
+```
+
+### Common Issues
+
+**"Unknown expression type"**: Usually a parsing issue. Check for unsupported syntax.
+
+**"Stack underflow"**: Function arguments not consumed correctly. Check function definitions.
+
+**"Undefined variable"**: Variable not bound in current environment. Check `define` statements.
+
+**"Undefined function"**: Function not registered in VM. Check standard library implementation.
 
 ## Limitations
-Current implementation does not support:
-- **Nested lambda definitions** (lambdas defined inside other lambdas) - this causes "Undefined closure function" errors
-- Floating point numbers
-- Strings
+
+**Not Supported**:
+- Floating point numbers (integers only)
 - Proper tail recursion
 - Garbage collection
-- Error recovery in REPL
-- Full numeric tower
 - Macros
-- Standard library
-
-## Future Enhancements
-1. **Nested lambda support** (complex but achievable)
-2. Proper tail call optimization
-3. Garbage collection
-4. Error recovery
-5. More data types
-6. Standard library
-7. Better debugging tools
\ No newline at end of file
+- Full numeric tower
+
+**Partially Supported**:
+- Comments (basic handling, may be unreliable)
+- State persistence (experimental, not fully reliable)
+- Error recovery in REPL
+
+**Performance**: Educational implementation, not optimized for speed.
+
+## Extending
+
+### Adding Standard Library Functions
+
+1. **Implement in VM** (`bin/vm.awk`):
+```awk
+function stdlib_new_function() {
+    if (stack_ptr < 1) error("new-function requires one argument")
+    val = pop()
+    # ... implementation ...
+    push(result)
+}
+```
+
+2. **Register function**:
+```awk
+FUNCTIONS["new-function"] = "stdlib_new_function"
+```
+
+3. **Add dispatch** in `vm_call_function()`:
+```awk
+} else if (built_in_name == "stdlib_new_function") {
+    stdlib_new_function()
+    return
+```
+
+4. **Test**: Create test file and verify functionality.
+
+### Adding Special Forms
+
+1. Add parsing in `compile_expr()`
+2. Implement code generation function
+3. Add VM instructions if needed
+
+## Forth Implementation
+
+The VM is language-agnostic. A Forth compiler (`scratch/forth/forth.awk`) demonstrates this by generating the same bytecode format.
+
+```bash
+cd scratch/forth
+echo "5 3 + ." | awk -f forth.awk  # => Result: N:8
+```
+
+## Files
+
+- `bin/compiler.awk` - Scheme to bytecode compiler
+- `bin/vm.awk` - Virtual machine implementation
+- `bin/repl` - Interactive REPL
+- `test/` - Comprehensive test suite
+- `scratch/forth/` - Forth implementation for VM validation
+
+## Known Issues
+
+- Some advanced closure/currying and higher-order function tests are still failing and are under active investigation. See WHAT-NEEDS-FIXING.md for current status and debugging plan.
diff --git a/awk/scheme/scheme/TODO.txt b/awk/scheme/scheme/TODO.txt
deleted file mode 100644
index f576fba..0000000
--- a/awk/scheme/scheme/TODO.txt
+++ /dev/null
@@ -1,70 +0,0 @@
-Scheme Interpreter TODO
-=====================
-
-Current State:
--------------
-- Basic arithmetic operations (+,-,*,/) are working
-- Let expressions with simple bindings are working
-- Function definitions (define) and lambda expressions are implemented (no nested lambdas)
-- Stack-based virtual machine with environment for variable bindings
-- Closures supported for top-level lambdas (not nested)
-- State persistence for globals and functions between REPL sessions
-
-Recent Changes:
---------------
-1. Improved function table and environment handling
-2. Enhanced debug logging for function calls and environment
-3. Refined lambda compilation and closure creation
-4. Updated documentation and architectural notes
-
-Current Issues / Limitations:
-----------------------------
-1. **Nested Lambda Support**:
-   - Lambdas defined inside other lambdas are not supported ("Undefined closure function" errors)
-2. **Reference Counting**:
-   - Reference counting for heap objects (cons cells) is stubbed but not enforced
-3. **Error Handling**:
-   - Minimal error recovery, especially in the REPL
-4. **Tail Recursion**:
-   - No proper tail call optimization
-5. **Data Types**:
-   - No floating point, string, or full numeric tower support
-6. **Garbage Collection**:
-   - No GC; memory for cons cells is not reclaimed
-7. **Standard Library**:
-   - No standard library or macros
-
-Next Steps:
------------
-1. **Implement Nested Lambda Support**:
-   - Refactor closure environment capture and restoration
-   - Update compiler and VM to support nested closures
-2. **Improve Memory Management**:
-   - Implement or enforce reference counting
-   - Plan for future garbage collection
-3. **Enhance Error Handling**:
-   - Add better error messages and recovery in REPL and VM
-4. **Tail Call Optimization**:
-   - Investigate and implement proper tail recursion
-5. **Testing and Debugging**:
-   - Expand test suite for edge cases (especially closures and let/lambda)
-   - Continue using DEBUG=1 for tracing execution
-6. **Documentation and Code Quality**:
-   - Keep architectural notes and code comments up to date
-   - Document any new patterns or changes
-
-Technical Notes:
----------------
-- Function calls use LOOKUP, GET_VALUE, and CALL instructions
-- Environment stack manages variable bindings and function parameters
-- Function code is stored in the FUNCTIONS table with unique names
-- Lambda functions use __lambda_N naming scheme; closures capture environment at creation
-- State is persisted to /tmp/scheme_vm.state and /tmp/scheme_vm.env
-
-Debugging Tips:
---------------
-1. Enable DEBUG=1 to see detailed execution logs
-2. Check stack and environment contents before and after each operation
-3. Monitor closure creation and environment capture/restoration
-4. Verify function code storage and retrieval in the FUNCTIONS table
-5. Use and expand test cases for all supported features 
\ No newline at end of file
diff --git a/awk/scheme/scheme/WHAT-NEEDS-FIXING.md b/awk/scheme/scheme/WHAT-NEEDS-FIXING.md
new file mode 100644
index 0000000..f8b5a0c
--- /dev/null
+++ b/awk/scheme/scheme/WHAT-NEEDS-FIXING.md
@@ -0,0 +1,49 @@
+# What Needs Fixing
+
+## Current State (as of latest debugging)
+
+- **Testing Infrastructure:**
+  - Test runner and environment variable handling are robust; DEBUG/DEBUG_SEXPR work as intended.
+  - Only 6/51 tests pass; 45 fail, including basic, integration, closure, and higher-order function tests.
+  - Most failures are silent (no assertion errors/output), indicating expressions are not being evaluated or CALLs are mis-emitted.
+
+- **Recent Fixes and Attempts:**
+  - Refactored top-level CALL emission logic in the compiler to match idiomatic Scheme/Lisp behavior:
+    - Now, CALL is only emitted for top-level compound expressions whose first symbol is not a special form (define, let, lambda, if, cond, and, or, not).
+    - Special forms are handled by the compiler, not as function calls.
+  - Helper function added to extract the first symbol from a compound expression string.
+  - Type-tracking logic for top-level CALL emission has been removed for simplicity and robustness.
+  - This approach is modeled after working reference implementations (e.g., [maryrosecook/littlelisp](https://raw.githubusercontent.com/maryrosecook/littlelisp/refs/heads/master/littlelisp.js)).
+
+- **Current Symptoms:**
+  - Many tests still fail, including basic arithmetic, map, closures, and higher-order functions.
+  - Failures are mostly silent: no assertion errors, no output, suggesting expressions are not being evaluated or results are not printed.
+  - Some improvement: a few more tests pass compared to previous attempts, but the majority still fail.
+
+## What Has Been Ruled Out
+- The VM and test runner are not the source of the remaining failures.
+- S-expression parsing and body handling are robust and not the source of the bug.
+- The new CALL emission logic is more correct, but not sufficient to fix all test failures.
+- The bug is not due to missing CALLs for assert/display/user-defined function calls at the top level.
+
+## Next Steps: Plan for Remaining Bugs
+
+1. **Targeted Debugging of Failing Tests:**
+   - Focus on a representative failing test (e.g., basic_numeric_operations, closures, or a simple assert).
+   - Inspect the generated assembly and VM output for these tests to confirm whether CALL is being emitted and executed as expected.
+   - Check for missing PRINT/DISPLAY or incorrect stack state after CALL.
+
+2. **Special Form Handling Review:**
+   - Ensure that all special forms (let, lambda, if, cond, etc.) are handled correctly and do not result in spurious CALLs or missed evaluation.
+   - Confirm that nested expressions within special forms are compiled and evaluated as expected.
+
+3. **Test and Iterate:**
+   - After each fix, re-run the minimal and representative tests to confirm progress.
+   - Once minimal tests pass, move to more complex closure and higher-order function tests.
+
+4. **Document Findings:**
+   - Update this file after each major fix or discovery, so the next debugging session has a clear starting point.
+
+## Goal (Restated)
+- Ensure top-level and nested expression evaluation is correct for all cases, including special forms, closures, and function applications.
+- Systematically fix all remaining failing tests by following the above plan. 
\ No newline at end of file
diff --git a/awk/scheme/scheme/bin/compiler.awk b/awk/scheme/scheme/bin/compiler.awk
index 94d6e99..dec4c22 100755
--- a/awk/scheme/scheme/bin/compiler.awk
+++ b/awk/scheme/scheme/bin/compiler.awk
@@ -1,19 +1,47 @@
 #!/usr/bin/awk -f
 
-# This is a Scheme-to-Assembly compiler implemented in AWK
-# It takes Scheme expressions as input and outputs assembly instructions
-# for a custom stack-based virtual machine
+# Scheme-to-VM Compiler
+# 
+# This compiler translates Scheme expressions into stack-based VM instructions.
+# The design prioritizes simplicity and correctness, making it suitable for
+# educational purposes and small-scale applications.
+#
+# Architecture Overview:
+# - Lexical analysis tokenizes input into meaningful units
+# - Recursive descent parsing builds expression trees
+# - Code generation produces VM instructions for execution
+# - Special form handling for control flow and function definitions
+# - Standard library integration for extended functionality
+#
+# Key Design Decisions:
+# - Recursive descent parsing for simplicity and predictable behavior
+# - Stack-based instruction generation for efficient VM execution
+# - Environment-based variable binding for lexical scoping
+# - Special form recognition for control flow constructs
+# - Standard library function integration for extended functionality
+# - Stack clearing between expressions to prevent argument pollution
 
 BEGIN {
+
+    # Debug mode configuration
+    # FIXME: Don't leave in, trigger on flag
+    print "[DEBUG_SEXPR] BEGIN block reached" > "/dev/stderr"
+    print "[DEBUG_SEXPR] ENVIRON[\"DEBUG_SEXPR\"] = " ENVIRON["DEBUG_SEXPR"] > "/dev/stderr"
+    DEBUG_SEXPR = (ENVIRON["DEBUG_SEXPR"] == "1") ? 1 : 0
+    if (DEBUG_SEXPR) print "[DEBUG_SEXPR] DEBUG_SEXPR is enabled" > "/dev/stderr"
+
     # Compiler maintains internal state for code generation
     curr_token = ""      # Current token being processed by lexer
     input_buffer = ""    # Buffer for input text being tokenized
     next_label = 0       # Counter for generating unique labels
     program = ""         # Accumulates the full program text
     
+    # Debug mode configuration
     # AWK FEATURE: ENVIRON is a built-in array containing environment variables
     # Unlike JS process.env, this is automatically available in awk
     DEBUG = (ENVIRON["DEBUG"] == "1") ? 1 : 0
+    error_flag = 0  # Set to 1 if any error occurs
+    DEBUG_SEXPR = (ENVIRON["DEBUG_SEXPR"] == "1") ? 1 : 0
 }
 
 # Debug logging helper function
@@ -27,6 +55,7 @@ function debug(msg) {
 # This is awk's main input processing loop - every line from stdin/files goes here
 # In JS, you'd need to explicitly read lines from a stream
 {
+    if (DEBUG_SEXPR) print "[DEBUG_SEXPR] Reading line: [" $0 "]" > "/dev/stderr"
     if (program != "") program = program "\n"
     program = program $0  # $0 is the current line being processed
 }
@@ -39,63 +68,136 @@ END {
     
     # Parse and compile each expression in the program
     split_expressions(program)
+    debug("END block: error_flag=" error_flag)
+    # If error_flag was set, exit 1
+    if (error_flag) exit 1
+    debug("END block: exiting")
+    exit 0
 }
 
 # Splits input into individual Scheme expressions
-# Handles nested parentheses and comments
-function split_expressions(prog, current, paren_count, i, c, expr, cleaned) {
+# This function handles the complexity of Scheme syntax including:
+# - Nested parentheses and proper expression boundaries
+# - Comments that can span multiple lines
+# - String literals that may contain parentheses
+# - Whitespace normalization for consistent parsing
+#
+# The function processes the entire program text and identifies complete
+# expressions that can be compiled independently
+function split_expressions(prog, current, paren_count, i, c, expr, cleaned, lines, n, line, in_string, out, j) {
     current = ""
     paren_count = 0
-    
-    # Clean up the input:
-    # 1. Remove comments (text between ; and next opening paren)
-    # 2. Normalize whitespace
-    # 3. Trim leading/trailing whitespace
-    cleaned = prog
-    # AWK FEATURE: gsub() is a built-in function for global substitution (like replaceAll in JS)
-    # gsub(pattern, replacement, target) - modifies target in place and returns count
-    gsub(/;[^(]*\(/, "(", cleaned)  # Remove comments before expressions
-    gsub(/\)[^)]*;/, ")", cleaned)  # Remove comments after expressions
-    gsub(/[ \t\n]+/, " ", cleaned)  # Normalize whitespace to single spaces
-    # AWK FEATURE: sub() is like gsub() but only replaces the first occurrence
-    sub(/^[ \t\n]+/, "", cleaned)   # Trim leading whitespace
-    sub(/[ \t\n]+$/, "", cleaned)   # Trim trailing whitespace
-    
+    n = split(prog, lines, "\n")
+    out = ""
+    for (j = 1; j <= n; j++) {
+        line = lines[j]
+        if (line ~ /^[ \t]*;/) continue
+        in_string = 0
+        cleaned_line = ""
+        for (i = 1; i <= length(line); i++) {
+            c = substr(line, i, 1)
+            if (c == "\"") in_string = !in_string
+            if (!in_string && c == ";") break
+            cleaned_line = cleaned_line c
+        }
+        out = out cleaned_line "\n"
+    }
+    cleaned = out
     debug("Cleaned program: [" cleaned "]")
-    
     if (cleaned == "") return
-    
-    # Parse expressions by tracking parenthesis nesting
-    # AWK FEATURE: length(string) returns the length of a string
-    # Unlike JS string.length, this is a function call, not a property
+    if (cleaned == "") return
+    in_string = 0
     for (i = 1; i <= length(cleaned); i++) {
         c = substr(cleaned, i, 1)
-        
-        if (c == "(") {
+        if (c == "\"" && !in_string) {
+            in_string = 1
+            if (paren_count == 0) current = ""
+        } else if (c == "\"" && in_string) {
+            in_string = 0
+        }
+        if (c == "(" && !in_string) {
             if (paren_count == 0) current = ""
             paren_count++
         }
-        
         current = current c
-        
-        if (c == ")") {
+        if (c == ")" && !in_string) {
             paren_count--
             if (paren_count == 0) {
-                # Complete expression found - compile it
                 expr = current
                 sub(/^\s+/, "", expr)
                 sub(/\s+$/, "", expr)
-                
                 debug("Processing expression: [" expr "]")
-                program = expr  # Set for parser
+                program = expr
+                expr_str = expr
                 expr = parse_expr()
-                compile_expr(expr)
+                if (substr(expr_str, 1, 1) == "(") {
+                    op = extract_first_symbol(expr_str)
+                    if (op != "define" && op != "let" && op != "lambda" && op != "if" && op != "cond" && op != "and" && op != "or" && op != "not") {
+                        compile_expr(expr)
+                        print "CALL"
+                    } else {
+                        compile_expr(expr)
+                    }
+                } else {
+                    compile_expr(expr)
+                }
+                print "CLEAR_STACK"
                 current = ""
             }
         }
+        if (paren_count == 0 && !in_string && c == " " && current != "") {
+            expr = current
+            sub(/^\s+/, "", expr)
+            sub(/\s+$/, "", expr)
+            if (expr != "") {
+                debug("Processing atomic expression: [" expr "]")
+                program = expr
+                expr_str = expr
+                expr = parse_expr()
+                if (substr(expr_str, 1, 1) == "(") {
+                    op = extract_first_symbol(expr_str)
+                    if (op != "define" && op != "let" && op != "lambda" && op != "if" && op != "cond" && op != "and" && op != "or" && op != "not") {
+                        compile_expr(expr)
+                        print "CALL"
+                    } else {
+                        compile_expr(expr)
+                    }
+                } else {
+                    compile_expr(expr)
+                }
+                print "CLEAR_STACK"
+            }
+            current = ""
+        }
+    }
+    if (paren_count == 0 && !in_string && current != "") {
+        expr = current
+        sub(/^\s+/, "", expr)
+        sub(/\s+$/, "", expr)
+        if (expr != "") {
+            debug("Processing final atomic expression: [" expr "]")
+            program = expr
+            expr_str = expr
+            expr = parse_expr()
+            if (substr(expr_str, 1, 1) == "(") {
+                op = extract_first_symbol(expr_str)
+                if (op != "define" && op != "let" && op != "lambda" && op != "if" && op != "cond" && op != "and" && op != "or" && op != "not") {
+                    compile_expr(expr)
+                    print "CALL"
+                } else {
+                    compile_expr(expr)
+                }
+            } else {
+                compile_expr(expr)
+            }
+            print "CLEAR_STACK"
+        }
+    }
+    if (paren_count > 0) {
+        debug("paren_count at end of split_expressions: " paren_count)
+        error("Unmatched opening parentheses - incomplete expression")
+        exit 1
     }
-    
-    # Add final HALT instruction
     print "HALT"
 }
 
@@ -126,6 +228,37 @@ function next_token() {
         return c
     }
     
+    # Handle string literals (double quotes)
+    if (c == "\"") {
+        str = ""
+        input_buffer = substr(input_buffer, 2)  # Skip opening quote
+        
+        while (length(input_buffer) > 0) {
+            c = substr(input_buffer, 1, 1)
+            if (c == "\"") {
+                input_buffer = substr(input_buffer, 2)  # Skip closing quote
+                break
+            }
+            if (c == "\\") {
+                # Handle escape sequences
+                input_buffer = substr(input_buffer, 2)
+                if (length(input_buffer) > 0) {
+                    c = substr(input_buffer, 1, 1)
+                    if (c == "n") str = str "\n"
+                    else if (c == "t") str = str "\t"
+                    else if (c == "\\") str = str "\\"
+                    else if (c == "\"") str = str "\""
+                    else error("Invalid escape sequence: \\" c)
+                    input_buffer = substr(input_buffer, 2)
+                }
+            } else {
+                str = str c
+                input_buffer = substr(input_buffer, 2)
+            }
+        }
+        return "\"" str "\""  # Return with quotes for identification
+    }
+    
     # Handle numbers (including negative numbers)
     # AWK FEATURE: substr(string, start, length) extracts substring
     # Unlike JS string.slice(), this is 1-indexed and requires explicit length
@@ -158,7 +291,13 @@ function next_token() {
 }
 
 # Recursive descent parser for Scheme expressions
-# Returns parsed expression as a string
+# This parser implements a simple but complete parsing strategy that:
+# - Handles nested expressions through recursion
+# - Distinguishes between atoms and list expressions
+# - Provides clear error messages for malformed input
+# - Supports string literals and various atom types
+#
+# Returns parsed expression as a string for further processing
 function parse_expr(token, result) {
     token = next_token()
     if (token == "EOF") return ""
@@ -169,11 +308,22 @@ function parse_expr(token, result) {
         return result
     }
     
+    # Handle string literals
+    if (substr(token, 1, 1) == "\"") {
+        debug("Parsed string: " token)
+        return token
+    }
+    
     debug("Parsed token: " token)
     return token
 }
 
 # Parses a list expression (anything in parentheses)
+# This function handles the complexity of nested list structures by:
+# - Recursively parsing each element in the list
+# - Maintaining proper nesting levels
+# - Providing clear error messages for unmatched parentheses
+# - Supporting empty lists and nested expressions
 function parse_list(result, expr) {
     result = ""
     
@@ -190,55 +340,80 @@ function parse_list(result, expr) {
 }
 
 # Splits an expression into operator and arguments
-# Handles nested expressions correctly
-function split_expr(expr, i, len, c, op, args, paren_count) {
-    # AWK FEATURE: length(string) returns the length of a string
-    # Unlike JS string.length, this is a function call, not a property
+# This function handles the complexity of Scheme function calls by:
+# - Correctly identifying the operator (first element)
+# - Preserving nested expressions as single arguments
+# - Handling whitespace and parentheses properly
+# - Supporting both simple calls and complex nested expressions
+#
+# Handles nested expressions correctly by tracking parenthesis nesting
+function split_expr(expr, i, len, c, op, args, paren_count, j, c2) {
     len = length(expr)
     paren_count = 0
-    
-    for (i = 1; i <= len; i++) {
-        c = substr(expr, i, 1)
-        if (c == " " && paren_count == 0) {
-            op = substr(expr, 1, i - 1)
-            args = substr(expr, i + 1)
-            break
+    op = ""
+    if (substr(expr, 1, 1) == "(") {
+        # Operator is a parenthesized expression
+        paren_count = 1
+        for (i = 2; i <= len; i++) {
+            c = substr(expr, i, 1)
+            if (c == "(") paren_count++
+            if (c == ")") paren_count--
+            if (paren_count == 0) {
+                op = substr(expr, 1, i)
+                # Skip any whitespace after the closing paren
+                j = i + 1
+                while (j <= len && (substr(expr, j, 1) == " " || substr(expr, j, 1) == "\t")) j++
+                args = substr(expr, j)
+                break
+            }
+        }
+    } else {
+        for (i = 1; i <= len; i++) {
+            c = substr(expr, i, 1)
+            if (c == " " && paren_count == 0) {
+                op = substr(expr, 1, i - 1)
+                args = substr(expr, i + 1)
+                break
+            }
+            if (c == "(") paren_count++
+            if (c == ")") paren_count--
+        }
+        if (!op) {
+            op = expr
+            args = ""
         }
-        if (c == "(") paren_count++
-        if (c == ")") paren_count--
-    }
-    
-    if (!op) {
-        op = expr
-        args = ""
     }
-    
     debug("Split expr: op=" op " args=" args)
-    # AWK FEATURE: SUBSEP is a built-in variable used as separator for array indices
-    # When you use array[key1,key2], awk internally stores it as array[key1 SUBSEP key2]
-    # This allows multi-dimensional arrays in awk (though they're really single-dimensional)
     return op SUBSEP args
 }
 
-# Splits argument list handling nested parentheses
-function split_args(args, arg_array, len, i, c, current, paren_count, arg_count) {
+# Splits argument list handling nested parentheses and string literals
+function split_args(args, arg_array, len, i, c, current, paren_count, arg_count, in_string) {
     # AWK FEATURE: length(string) returns the length of a string
     # Unlike JS string.length, this is a function call, not a property
     len = length(args)
     current = ""
     paren_count = 0
     arg_count = 0
+    in_string = 0
     
     for (i = 1; i <= len; i++) {
         c = substr(args, i, 1)
         
-        if (c == "(") paren_count++
-        if (c == ")") paren_count--
+        # Handle string literals
+        if (c == "\"" && !in_string) {
+            in_string = 1
+        } else if (c == "\"" && in_string) {
+            in_string = 0
+        }
+        
+        if (c == "(" && !in_string) paren_count++
+        if (c == ")" && !in_string) paren_count--
         
-        if (c == " " && paren_count == 0 && current != "") {
+        if (c == " " && paren_count == 0 && !in_string && current != "") {
             arg_array[++arg_count] = current
             current = ""
-        } else if (c != " " || paren_count > 0) {
+        } else if (c != " " || paren_count > 0 || in_string) {
             current = current c
         }
     }
@@ -256,40 +431,40 @@ function compile_number(num) {
     print "PUSH_CONST N:" num
 }
 
+# Code generation for string literals
+function compile_string(str) {
+    debug("Compiling string: " str)
+    # Remove outer quotes and emit string constant
+    content = substr(str, 2, length(str) - 2)
+    # Escape newlines and other special characters for output
+    gsub(/\n/, "\\n", content)
+    gsub(/\t/, "\\t", content)
+    gsub(/\\/, "\\\\", content)
+    print "PUSH_CONST STR:" content
+}
+
 # Code generation for primitive operations (+, -, *, cons, etc)
 function compile_primitive_call(op, args, arg_array, nargs, i) {
     debug("Primitive call: op=" op " args=" args)
     nargs = split_args(args, arg_array)
     
-    # Check if this is a lambda function call
-    # AWK FEATURE: ~ is the regex match operator (like /pattern/.test() in JS)
-    # The pattern is a regex literal, not a string
     if (op ~ /^\(lambda /) {
-        # This is a lambda function call
-        # First compile all arguments
         for (i = 1; i <= nargs; i++) {
             compile_expr(arg_array[i])
         }
-        
-        # Then compile the lambda function (this will push the function name)
         compile_expr(op)
-        
-        # Call the function - the lambda name is now on top of stack
         print "CALL"
-        return
+        return "function"
     }
-    
-    # Then emit appropriate operation
     if (op == "+") {
-        # Compile arguments
         for (i = 1; i <= nargs; i++) {
             compile_expr(arg_array[i])
         }
         for (i = 1; i < nargs; i++)
             print "ADD"
+        return "value"
     }
     else if (op == "-") {
-        # Compile arguments
         for (i = 1; i <= nargs; i++) {
             compile_expr(arg_array[i])
         }
@@ -299,64 +474,257 @@ function compile_primitive_call(op, args, arg_array, nargs, i) {
         }
         for (i = 1; i < nargs; i++)
             print "SUB"
+        return "value"
     }
     else if (op == "*") {
-        # Compile arguments
         for (i = 1; i <= nargs; i++) {
             compile_expr(arg_array[i])
         }
         for (i = 1; i < nargs; i++)
             print "MUL"
+        return "value"
+    }
+    else if (op == "/") {
+        if (nargs < 2) error("/ requires at least 2 arguments")
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        for (i = 1; i < nargs; i++)
+            print "DIV"
+        return "value"
+    }
+    else if (op == "modulo" || op == "%") {
+        if (nargs != 2) error("modulo requires 2 arguments")
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        print "LOOKUP modulo"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "expt") {
+        if (nargs != 2) error("expt requires 2 arguments")
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        print "LOOKUP expt"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "abs") {
+        if (nargs != 1) error("abs requires 1 argument")
+        compile_expr(arg_array[1])
+        print "LOOKUP abs"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "min") {
+        if (nargs != 2) error("min requires 2 arguments")
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        print "LOOKUP min"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "max") {
+        if (nargs != 2) error("max requires 2 arguments")
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        print "LOOKUP max"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
     }
     else if (op == "cons") {
         if (nargs != 2) error("cons requires 2 arguments")
-        # Compile arguments
         for (i = 1; i <= nargs; i++) {
             compile_expr(arg_array[i])
         }
         print "CONS"
+        return "value"
     }
     else if (op == "car") {
         if (nargs != 1) error("car requires 1 argument")
-        # Compile argument
         compile_expr(arg_array[1])
         print "CAR"
+        return "value"
     }
     else if (op == "cdr") {
         if (nargs != 1) error("cdr requires 1 argument")
-        # Compile argument
         compile_expr(arg_array[1])
         print "CDR"
+        return "value"
     }
     else if (op == "<") {
         if (nargs != 2) error("< requires 2 arguments")
-        # Compile arguments
         for (i = 1; i <= nargs; i++) {
             compile_expr(arg_array[i])
         }
         print "LT"
+        return "value"
     }
     else if (op == "=") {
         if (nargs != 2) error("= requires 2 arguments")
-        # Compile arguments
         for (i = 1; i <= nargs; i++) {
             compile_expr(arg_array[i])
         }
         print "EQ"
+        return "value"
     }
-    else {
-        # Function call for user-defined functions
-        debug("Function call: " op)
-        # First compile arguments
+    # Standard library functions
+    else if (op == "null?") {
+        if (nargs != 1) error("null? requires 1 argument")
+        compile_expr(arg_array[1])
+        print "LOOKUP null?"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "pair?") {
+        if (nargs != 1) error("pair? requires 1 argument")
+        compile_expr(arg_array[1])
+        print "LOOKUP pair?"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "number?") {
+        if (nargs != 1) error("number? requires 1 argument")
+        compile_expr(arg_array[1])
+        print "LOOKUP number?"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "string?") {
+        if (nargs != 1) error("string? requires 1 argument")
+        compile_expr(arg_array[1])
+        print "LOOKUP string?"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "boolean?") {
+        if (nargs != 1) error("boolean? requires 1 argument")
+        compile_expr(arg_array[1])
+        print "LOOKUP boolean?"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "symbol?") {
+        if (nargs != 1) error("symbol? requires 1 argument")
+        compile_expr(arg_array[1])
+        print "LOOKUP symbol?"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "zero?") {
+        if (nargs != 1) error("zero? requires 1 argument")
+        compile_expr(arg_array[1])
+        print "LOOKUP zero?"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "list") {
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        print "LOOKUP list"
+        print "GET_VALUE"
+        print "CALL_WITH_ARGS " nargs
+        return "value"
+    }
+    else if (op == "reverse") {
+        if (nargs != 1) error("reverse requires 1 argument")
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        print "LOOKUP reverse"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "member") {
+        if (nargs != 2) error("member requires 2 arguments")
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        print "LOOKUP member"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "map") {
+        if (nargs != 2) error("map requires 2 arguments")
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        print "LOOKUP map"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "filter") {
+        if (nargs != 2) error("filter requires 2 arguments")
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        print "LOOKUP filter"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "string-length") {
+        if (nargs != 1) error("string-length requires 1 argument")
+        compile_expr(arg_array[1])
+        print "LOOKUP string-length"
+        print "GET_VALUE"
+        print "CALL"
+        return "value"
+    }
+    else if (op == "string-append") {
+        if (nargs < 2) error("string-append requires at least 2 arguments")
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        print "LOOKUP string-append"
+        print "GET_VALUE"
+        print "CALL_WITH_ARGS " nargs
+        return "value"
+    }
+    else if (op == "assert" || op == "display" || op == "error" || op == "print") {
         for (i = 1; i <= nargs; i++) {
             compile_expr(arg_array[i])
         }
-        # Then look up the function name
         print "LOOKUP " op
-        # Get the actual function name
         print "GET_VALUE"
-        # Call the function
         print "CALL"
+        return "function"
+    }
+    else {
+        # Function call for user-defined functions or higher-order/callable expressions
+        debug("Function call: " op)
+        for (i = 1; i <= nargs; i++) {
+            compile_expr(arg_array[i])
+        }
+        if (substr(op, 1, 1) == "(") {
+            if (DEBUG_SEXPR) print "[DEBUG_SEXPR] compile_primitive_call: compiling operator expr: [" op "]" > "/dev/stderr"
+            compile_expr(op)
+        } else {
+            print "LOOKUP " op
+            print "GET_VALUE"
+        }
+        print "CALL"
+        return "function"
     }
 }
 
@@ -403,55 +771,33 @@ function split_bindings(bindings, binding_array, count, current, paren_count, i,
 }
 
 # Compiles let expressions (local variable bindings)
-function compile_let(args, bindings, body, binding_array, nbindings, i, var, val, binding_parts) {
-    # Split into bindings and body
+function compile_let(args, bindings, body, binding_array, nbindings, i, var, val, binding_parts, sexprs, nsexprs, j, expr, last_type) {
     if (substr(args, 1, 1) != "(") error("Malformed let expression")
-    
-    # Find matching closing parenthesis for bindings
     paren_count = 1
     i = 2
-    # AWK FEATURE: length(string) returns the length of a string
-    # Unlike JS string.length, this is a function call, not a property
     while (paren_count > 0 && i <= length(args)) {
         if (substr(args, i, 1) == "(") paren_count++
         if (substr(args, i, 1) == ")") paren_count--
         i++
     }
     if (paren_count > 0) error("Unmatched parenthesis in let bindings")
-    
-    bindings = substr(args, 2, i - 3)  # Remove outer parentheses
+    bindings = substr(args, 2, i - 3)
     body = substr(args, i)
-    
-    # Trim whitespace from body
     sub(/^[ \t\n]+/, "", body)
     sub(/[ \t\n]+$/, "", body)
-    
     debug("Let bindings: " bindings)
     debug("Let body: " body)
-    
-    # Compile each binding
     nbindings = split_bindings(bindings, binding_array)
     for (i = 1; i <= nbindings; i++) {
         debug("Processing binding: " binding_array[i])
-        
-        # Find the variable name (everything up to the first space)
         var = binding_array[i]
         sub(/ .*$/, "", var)
-        
-        # Find the value (everything after the first space)
         val = binding_array[i]
         sub(/^[^ ]+ /, "", val)
-        
         debug("Binding var: " var " val: " val)
-        
-        # Compile the value
         if (substr(val, 1, 1) == "(") {
-            # Handle lambda or other compound expressions
             if (substr(val, 2, 6) == "lambda") {
-                # This is a lambda expression
-                # Pass the entire lambda expression to compile_lambda
                 compile_lambda(val)
-                # Store the function name in the environment
                 print "STORE " var
             } else {
                 compile_expr(val)
@@ -462,84 +808,115 @@ function compile_let(args, bindings, body, binding_array, nbindings, i, var, val
             print "STORE " var
         }
     }
-    
-    # Compile the body
-    compile_expr(body)
-    
-    # Clean up bindings AFTER evaluating body
+    nsexprs = split_sexpressions(body, sexprs)
+    if (DEBUG_SEXPR) {
+        printf("[DEBUG_SEXPR] compile_let: splitting body, found %d expressions\n", nsexprs) > "/dev/stderr"
+        for (j = 1; j <= nsexprs; j++) {
+            printf("[DEBUG_SEXPR]   %d: [%s]\n", j, sexprs[j]) > "/dev/stderr"
+        }
+    }
+    last_type = "value"
+    for (j = 1; j <= nsexprs; j++) {
+        expr = sexprs[j]
+        sub(/^[ \t\n]+/, "", expr)
+        sub(/[ \t\n]+$/, "", expr)
+        if (DEBUG_SEXPR) printf("[DEBUG_SEXPR]   let body expr: [%s]\n", expr) > "/dev/stderr"
+        last_type = compile_expr(expr)
+    }
     for (i = nbindings; i >= 1; i--) {
         print "POP_ENV"
     }
+    return last_type
 }
 
 # Compiles define expressions (function/variable definitions)
-function compile_define(args, name, params, body, param_array, nparams, i, paren_start, paren_end) {
-    # Set flag for global definition
+function compile_define(args, name, params, body, param_array, nparams, i, paren_start, paren_end, sexprs, nsexprs, j, expr, is_define, last_body_idx) {
+    if (DEBUG_SEXPR) print "[DEBUG_SEXPR] compile_define called with args: [" args "]" > "/dev/stderr"
     print "PUSH_CONST B:1"
-    print "STORE from_define"  # Must match exactly what vm_store checks for
-    
-    # Find the function name (everything up to the first space)
+    print "STORE from_define"
     i = index(args, " ")
     if (i == 0) error("Malformed define expression")
     name = substr(args, 1, i - 1)
     args = substr(args, i + 1)
-
-    # Check if it's a function or variable definition
+    debug("compile_define: args = [" args "]")
     if (substr(args, 1, 1) == "(") {
-        # It's a function definition
         paren_count = 1
-        i = 2
-        while (paren_count > 0 && i <= length(args)) {
-            if (substr(args, i, 1) == "(") paren_count++
-            if (substr(args, i, 1) == ")") paren_count--
-            i++
-        }
-        if (paren_count > 0) error("Unmatched parenthesis in parameter list")
-
-        params = substr(args, 2, i - 3)  # Remove parentheses
-        body = substr(args, i + 1)
-
-        # Create function label
-        print "LABEL " name
-
-        # Process parameters
-        # AWK FEATURE: split(string, array, separator) splits string into array elements
-        # Unlike JS string.split() which returns an array, this populates an existing array
-        nparams = split(params, param_array, " ")
-        for (i = 1; i <= nparams; i++) {
-            print "STORE " param_array[i]
+        close_paren = 0
+        for (i = 2; i <= length(args); i++) {
+            c = substr(args, i, 1)
+            if (c == "(") paren_count++
+            if (c == ")") paren_count--
+            if (paren_count == 0) { close_paren = i; break }
         }
-
-        # Compile function body
-        compile_expr(body)
-
-        # Clean up parameters and return
-        for (i = nparams; i >= 1; i--) {
-            print "POP_ENV"
+        if (close_paren == 0) error("Unmatched parenthesis in define")
+        rest = substr(args, close_paren + 1)
+        sub(/^[ \t\n]+/, "", rest)
+        if (rest == "") {
+            if (DEBUG_SEXPR) print "[DEBUG_SEXPR] variable definition (parenthesized value): [" name "] value: [" args "]" > "/dev/stderr"
+            compile_expr(args)
+            print "STORE " name
+            return
+        } else {
+            params = substr(args, 2, close_paren - 2)
+            body = rest
+            if (DEBUG_SEXPR) print "[DEBUG_SEXPR] function definition: [" name "] params: [" params "] body: [" body "]" > "/dev/stderr"
+            print "LABEL " name
+            nparams = split(params, param_array, " ")
+            for (i = 1; i <= nparams; i++) {
+                print "STORE " param_array[i]
+            }
+            nsexprs = split_sexpressions(body, sexprs)
+            if (DEBUG_SEXPR) {
+                printf("[DEBUG_SEXPR] compile_define: splitting body, found %d expressions\n", nsexprs) > "/dev/stderr"
+                for (j = 1; j <= nsexprs; j++) {
+                    printf("[DEBUG_SEXPR]   %d: [%s]\n", j, sexprs[j]) > "/dev/stderr"
+                }
+            }
+            last_body_idx = 0
+            for (j = 1; j <= nsexprs; j++) {
+                expr = sexprs[j]
+                sub(/^[ \t\n]+/, "", expr)
+                sub(/[ \t\n]+$/, "", expr)
+                is_define = (substr(expr, 2, 6) == "define")
+                if (is_define) {
+                    if (DEBUG_SEXPR) printf("[DEBUG_SEXPR]   local define: [%s]\n", expr) > "/dev/stderr"
+                    compile_expr(expr)
+                } else {
+                    last_body_idx = j
+                }
+            }
+            for (j = 1; j <= nsexprs; j++) {
+                expr = sexprs[j]
+                sub(/^[ \t\n]+/, "", expr)
+                sub(/[ \t\n]+$/, "", expr)
+                is_define = (substr(expr, 2, 6) == "define")
+                if (!is_define && expr != "") {
+                    if (DEBUG_SEXPR) printf("[DEBUG_SEXPR]   body expr: [%s]\n", expr) > "/dev/stderr"
+                    compile_expr(expr)
+                }
+            }
+            for (i = nparams; i >= 1; i--) {
+                print "POP_ENV"
+            }
+            print "RETURN"
+            return
         }
-        print "RETURN"
     } else {
-        # Variable definition
-        debug("Defining variable: " name " with value: " args)
-        compile_expr(args)  # Compile the value
-        print "STORE " name  # Store the variable
+        if (DEBUG_SEXPR) print "[DEBUG_SEXPR] variable definition: [" name "] value: [" args "]" > "/dev/stderr"
+        compile_expr(args)
+        print "STORE " name
     }
 }
 
 # Compiles lambda expressions (anonymous functions)
-function compile_lambda(args, params, body, param_array, nparams, i, lambda_name) {
-    # Generate a unique name for the lambda function
+function compile_lambda(args, params, body, param_array, nparams, i, lambda_name, expr, op, rest, sexprs, nsexprs, j, is_define, last_body_idx) {
+    if (DEBUG_SEXPR) print "[DEBUG_SEXPR] compile_lambda called" > "/dev/stderr"
     lambda_name = "__lambda_" next_label++
-    
     debug("compile_lambda: args = [" args "]")
-    
-    # Handle both full lambda expression and just the arguments part
     if (substr(args, 1, 7) == "(lambda") {
         debug("compile_lambda: detected full lambda expression")
-        # Full lambda expression: (lambda (params) body)
-        args = substr(args, 8)  # Remove "(lambda"
+        args = substr(args, 8)
         debug("compile_lambda: after removing (lambda: [" args "]")
-        # Find the closing parenthesis of the entire lambda expression
         paren_count = 0
         i = 1
         while (i <= length(args)) {
@@ -547,88 +924,343 @@ function compile_lambda(args, params, body, param_array, nparams, i, lambda_name
             if (c == "(") paren_count++
             if (c == ")") {
                 paren_count--
-                if (paren_count == -1) break  # Found the closing paren of the lambda
+                if (paren_count == -1) break
             }
             i++
         }
         if (paren_count != -1) error("Unmatched parenthesis in lambda")
-        args = substr(args, 1, i - 1)  # Remove the closing parenthesis
+        args = substr(args, 1, i - 1)
         debug("compile_lambda: after removing closing paren: [" args "]")
-        # Remove leading whitespace
         sub(/^[ \t\n]+/, "", args)
         debug("compile_lambda: after removing leading whitespace: [" args "]")
     }
-    
-    # Split into parameters and body
     if (substr(args, 1, 1) != "(") error("Malformed lambda expression")
-    
-    # Find matching closing parenthesis for parameters
     paren_count = 1
     i = 2
-    # AWK FEATURE: length(string) returns the length of a string
-    # Unlike JS string.length, this is a function call, not a property
     while (paren_count > 0 && i <= length(args)) {
         if (substr(args, i, 1) == "(") paren_count++
         if (substr(args, i, 1) == ")") paren_count--
         i++
     }
     if (paren_count > 0) error("Unmatched parenthesis in lambda parameters")
-    
-    params = substr(args, 2, i - 3)  # Remove parentheses
+    params = substr(args, 2, i - 3)
     body = substr(args, i)
-    
-    # Trim whitespace from body
     sub(/^[ \t\n]+/, "", body)
     sub(/[ \t\n]+$/, "", body)
-    
     debug("Lambda parameters: " params)
     debug("Lambda body: " body)
-    
-    # Create function label
+    if (DEBUG_SEXPR) print "[DEBUG_SEXPR] body to split_sexpressions: [" body "]" > "/dev/stderr"
     print "LABEL " lambda_name
-    
-    # Process parameters
-    # AWK FEATURE: split(string, array, separator) splits string into array elements
-    # Unlike JS string.split() which returns an array, this populates an existing array
     nparams = split(params, param_array, " ")
     for (i = 1; i <= nparams; i++) {
         print "STORE " param_array[i]
     }
-    
-    # Compile function body
-    compile_expr(body)
-    
-    # Clean up parameters and return
+    nsexprs = split_sexpressions(body, sexprs)
+    if (DEBUG_SEXPR) {
+        printf("[DEBUG_SEXPR] compile_lambda: processing %d expressions\n", nsexprs) > "/dev/stderr"
+    }
+    last_body_idx = 0
+    for (j = 1; j <= nsexprs; j++) {
+        expr = sexprs[j]
+        sub(/^[ \t\n]+/, "", expr)
+        sub(/[ \t\n]+$/, "", expr)
+        is_define = (substr(expr, 2, 6) == "define")
+        if (is_define) {
+            if (DEBUG_SEXPR) printf("[DEBUG_SEXPR]   local define: [%s]\n", expr) > "/dev/stderr"
+            compile_expr(expr)
+        } else {
+            last_body_idx = j
+        }
+    }
+    for (j = 1; j <= nsexprs; j++) {
+        expr = sexprs[j]
+        sub(/^[ \t\n]+/, "", expr)
+        sub(/[ \t\n]+$/, "", expr)
+        is_define = (substr(expr, 2, 6) == "define")
+        if (!is_define && expr != "") {
+            if (DEBUG_SEXPR) printf("[DEBUG_SEXPR]   body expr: [%s]\n", expr) > "/dev/stderr"
+            compile_expr(expr)
+        }
+    }
     for (i = nparams; i >= 1; i--) {
         print "POP_ENV"
     }
-    print "RETURN"
-    
-    # Create closure that captures current environment
     print "CAPTURE_ENV " lambda_name
     print "PUSH_CONST CLOSURE:" lambda_name ":ENV_ID"
+    print "RETURN"
+}
+
+# Compile if expression: (if condition then-expr else-expr)
+function compile_if(args,    split_result, condition, then_expr, else_expr, else_label, end_label) {
+    debug("Compiling if expression: " args)
+    
+    # Split into condition, then-expr, and else-expr
+    split_result = split_expr(args)
+    condition = substr(split_result, 1, index(split_result, SUBSEP) - 1)
+    
+    # Get the rest and split again for then/else
+    args = substr(split_result, index(split_result, SUBSEP) + 1)
+    split_result = split_expr(args)
+    then_expr = substr(split_result, 1, index(split_result, SUBSEP) - 1)
+    else_expr = substr(split_result, index(split_result, SUBSEP) + 1)
+    
+    debug("If condition: " condition)
+    debug("If then: " then_expr)
+    debug("If else: " else_expr)
+    
+    # Generate unique labels
+    else_label = "else_" next_label++
+    end_label = "endif_" next_label++
+    
+    # Compile condition
+    compile_expr(condition)
+    
+    # Jump to else if condition is false
+    print "JUMP_IF_FALSE " else_label
+    
+    # Compile then expression
+    compile_expr(then_expr)
+    
+    # Jump to end
+    print "JUMP " end_label
+    
+    # Else label
+    print "LABEL " else_label
+    
+    # Compile else expression
+    compile_expr(else_expr)
+    
+    # End label
+    print "LABEL " end_label
+}
+
+# Compile cond expression: (cond (test1 expr1) (test2 expr2) ... (else expr))
+function compile_cond(args,    test, expr, test_label, end_label) {
+    debug("Compiling cond expression: " args)
+    
+    # Parse the first clause: (test expr)
+    # Remove outer parentheses
+    args = substr(args, 2, length(args) - 2)
+    
+    # Find the first space after the test
+    paren_count = 0
+    for (i = 1; i <= length(args); i++) {
+        c = substr(args, i, 1)
+        if (c == "(") paren_count++
+        if (c == ")") paren_count--
+        if (c == " " && paren_count == 0) {
+            test = substr(args, 1, i - 1)
+            expr = substr(args, i + 1)
+            # Remove the rest of the cond (other clauses)
+            if (index(expr, ") (") > 0) {
+                expr = substr(expr, 1, index(expr, ") (") - 1)
+            }
+            break
+        }
+    }
+    
+    if (!test) {
+        test = args
+        expr = ""
+    }
+    
+    debug("Cond test: " test " expr: " expr)
+    
+    # Generate labels
+    test_label = "cond_test_" next_label++
+    end_label = "cond_end_" next_label++
+    
+    # Compile test
+    compile_expr(test)
+    
+    # Jump to else if test is false
+    print "JUMP_IF_FALSE " test_label
+    
+    # Compile expression
+    compile_expr(expr)
+    
+    # Jump to end
+    print "JUMP " end_label
+    
+    # Else label
+    print "LABEL " test_label
+    
+    # End label
+    print "LABEL " end_label
+}
+
+# Compile and expression: (and expr1 expr2 ...)
+function compile_and(args,    expressions, nexprs, i, expr, short_circuit_label, end_label, split_result, remaining_args) {
+    debug("Compiling and expression: " args)
+    
+    # Parse expressions properly using split_expr
+    expressions[1] = ""
+    nexprs = 0
+    remaining_args = args
+    
+    while (remaining_args != "") {
+        nexprs++
+        split_result = split_expr(remaining_args)
+        expressions[nexprs] = substr(split_result, 1, index(split_result, SUBSEP) - 1)
+        remaining_args = substr(split_result, index(split_result, SUBSEP) + 1)
+    }
+    
+    if (nexprs == 0) {
+        # Empty and returns true
+        print "PUSH_CONST B:1"
+        return
+    }
+    
+    if (nexprs == 1) {
+        # Single expression
+        compile_expr(expressions[1])
+        return
+    }
+    
+    # Generate labels
+    short_circuit_label = "and_short_" next_label++
+    end_label = "and_end_" next_label++
+    
+    for (i = 1; i <= nexprs; i++) {
+        expr = expressions[i]
+        debug("And expression " i ": " expr)
+        
+        # Compile expression
+        compile_expr(expr)
+        
+        # If not the last expression, check for short-circuit
+        if (i < nexprs) {
+            print "JUMP_IF_FALSE " short_circuit_label
+        }
+    }
+    
+    # Jump to end
+    print "JUMP " end_label
+    
+    # Short-circuit label (result is false)
+    print "LABEL " short_circuit_label
+    print "PUSH_CONST B:0"
+    
+    # End label
+    print "LABEL " end_label
+}
+
+# Compile or expression: (or expr1 expr2 ...)
+function compile_or(args,    expressions, nexprs, i, expr, short_circuit_label, end_label, split_result, remaining_args) {
+    debug("Compiling or expression: " args)
+    
+    # Parse expressions properly using split_expr
+    expressions[1] = ""
+    nexprs = 0
+    remaining_args = args
+    
+    while (remaining_args != "") {
+        nexprs++
+        split_result = split_expr(remaining_args)
+        expressions[nexprs] = substr(split_result, 1, index(split_result, SUBSEP) - 1)
+        remaining_args = substr(split_result, index(split_result, SUBSEP) + 1)
+    }
+    
+    if (nexprs == 0) {
+        # Empty or returns false
+        print "PUSH_CONST B:0"
+        return
+    }
+    
+    if (nexprs == 1) {
+        # Single expression
+        compile_expr(expressions[1])
+        return
+    }
+    
+    # Generate labels
+    short_circuit_label = "or_short_" next_label++
+    end_label = "or_end_" next_label++
+    
+    for (i = 1; i <= nexprs; i++) {
+        expr = expressions[i]
+        debug("Or expression " i ": " expr)
+        
+        # Compile expression
+        compile_expr(expr)
+        
+        # If not the last expression, check for short-circuit
+        if (i < nexprs) {
+            print "JUMP_IF_TRUE " short_circuit_label
+        }
+    }
+    
+    # Jump to end
+    print "JUMP " end_label
+    
+    # Short-circuit label (result is true)
+    print "LABEL " short_circuit_label
+    print "PUSH_CONST B:1"
+    
+    # End label
+    print "LABEL " end_label
+}
+
+# Compile not expression: (not expr)
+function compile_not(args,    expr) {
+    debug("Compiling not expression: " args)
+    
+    # Compile the expression
+    compile_expr(args)
+    
+    # Negate the result
+    print "NOT"
 }
 
 # Main expression compiler - dispatches based on expression type
-function compile_expr(expr,    split_result, op, args) {
+function compile_expr(expr,    split_result, op, args, result_type) {
+    if (DEBUG_SEXPR) print "[DEBUG_SEXPR] compile_expr called with expr: [" expr "]" > "/dev/stderr"
     debug("Compiling expression: " expr)
     
+    # Handle empty expressions
+    if (expr == "") {
+        debug("Skipping empty expression")
+        return "value"
+    }
+    
+    # Handle comment lines
+    if (expr ~ /^[ \t]*;;/ || expr ~ /^[ \t]*;/) {
+        debug("Skipping comment line: [" expr "]")
+        return "value"
+    }
+    
+    # Handle string literals
+    if (substr(expr, 1, 1) == "\"") {
+        compile_string(expr)
+        return "value"
+    }
+    
     # Handle numeric literals
     if (expr ~ /^-?[0-9]+$/) {
         compile_number(expr)
-        return
+        return "value"
     }
     
     # Handle nil constant
     if (expr == "nil") {
         print "PUSH_CONST NIL:"
-        return
+        return "value"
     }
     
-    # Handle variable lookup
-    if (expr ~ /^[a-zA-Z_][a-zA-Z0-9_]*$/) {
+    # Handle boolean literals
+    if (expr == "#t") {
+        print "PUSH_CONST B:1"
+        return "value"
+    }
+    if (expr == "#f") {
+        print "PUSH_CONST B:0"
+        return "value"
+    }
+    
+    # Handle variable lookup (only if not a parenthesized expression)
+    if (expr ~ /^[a-zA-Z_][a-zA-Z0-9_?-]*$/) {
         print "LOOKUP " expr
-        return
+        return "value"
     }
     
     # Handle compound expressions (lists)
@@ -637,24 +1269,116 @@ function compile_expr(expr,    split_result, op, args) {
         split_result = split_expr(expr)
         op = substr(split_result, 1, index(split_result, SUBSEP) - 1)
         args = substr(split_result, index(split_result, SUBSEP) + 1)
-        
+        if (DEBUG_SEXPR) print "[DEBUG_SEXPR] split_expr op: [" op "] args: [" args "]" > "/dev/stderr"
         if (op == "define") {
             compile_define(args)
+            return "value"
         } else if (op == "let") {
-            compile_let(args)
+            result_type = compile_let(args)
+            return result_type
         } else if (op == "lambda") {
             compile_lambda(args)
+            return "function"
+        } else if (op == "if") {
+            compile_if(args)
+            # TODO: Could be value or function, but usually value
+            return "value"
+        } else if (op == "cond") {
+            compile_cond(args)
+            # TODO: Could be value or function, but usually value
+            return "value"
+        } else if (op == "and") {
+            compile_and(args)
+            return "value"
+        } else if (op == "or") {
+            compile_or(args)
+            return "value"
+        } else if (op == "not") {
+            compile_not(args)
+            return "value"
         } else {
-            compile_primitive_call(op, args)
+            return compile_primitive_call(op, args)
         }
-        return
     }
     
     error("Unknown expression type: " expr)
+    return "value"
 }
 
 # Error reporting helper
 function error(msg) {
     print "Error: " msg > "/dev/stderr"
+    error_flag = 1
     exit 1
-}
\ No newline at end of file
+}
+
+# Split a string into top-level S-expressions (returns count, fills sexpr_array)
+function split_sexpressions(str, sexpr_array, i, c, in_string, paren_count, current, n, in_comment) {
+    if (DEBUG_SEXPR) print "[DEBUG_SEXPR] split_sexpressions called" > "/dev/stderr"
+    in_string = 0
+    paren_count = 0
+    current = ""
+    n = 0
+    in_comment = 0
+    i = 1
+    while (i <= length(str)) {
+        c = substr(str, i, 1)
+        # Skip whitespace
+        if (!in_string && (c == " " || c == "\t" || c == "\n")) { i++; continue; }
+        # Skip comments (start with ; to end of line)
+        if (!in_string && c == ";") {
+            while (i <= length(str) && substr(str, i, 1) != "\n") i++;
+            i++; continue;
+        }
+        # Parse S-expression
+        current = ""
+        if (c == "(") {
+            paren_count = 0
+            while (i <= length(str)) {
+                c = substr(str, i, 1)
+                current = current c
+                if (c == "\"") in_string = !in_string
+                if (!in_string && c == "(") paren_count++
+                if (!in_string && c == ")") paren_count--
+                i++
+                if (paren_count == 0 && !in_string) break
+            }
+            sexpr_array[++n] = current
+        } else {
+            # Parse an atom
+            while (i <= length(str)) {
+                c = substr(str, i, 1)
+                if (!in_string && (c == " " || c == "\t" || c == "\n" || c == "(" || c == ")" || c == ";")) break;
+                if (c == "\"") in_string = !in_string
+                current = current c
+                i++
+            }
+            if (current != "") sexpr_array[++n] = current
+        }
+    }
+    if (DEBUG_SEXPR) {
+        printf("[DEBUG_SEXPR] split_sexpressions: found %d expressions\n", n) > "/dev/stderr"
+        for (i = 1; i <= n; i++) {
+            printf("[DEBUG_SEXPR]   %d: [%s]\n", i, sexpr_array[i]) > "/dev/stderr"
+        }
+        print "[DEBUG_SEXPR] split_sexpressions returning" > "/dev/stderr"
+    }
+    return n
+}
+
+# Helper: Extract first symbol from a compound expression string
+function extract_first_symbol(expr_str, op) {
+    # Assumes expr_str starts with '('
+    op = ""
+    i = 2
+    # Skip whitespace after '('
+    while (i <= length(expr_str) && (substr(expr_str, i, 1) == " " || substr(expr_str, i, 1) == "\t")) i++
+    # Read until next whitespace or ')'
+    while (i <= length(expr_str)) {
+        c = substr(expr_str, i, 1)
+        if (c == " " || c == "\t" || c == ")") break
+        op = op c
+        i++
+    }
+    return op
+}
diff --git a/awk/scheme/scheme/bin/repl b/awk/scheme/scheme/bin/repl
index 1fce388..0f1a049 100755
--- a/awk/scheme/scheme/bin/repl
+++ b/awk/scheme/scheme/bin/repl
@@ -89,10 +89,15 @@ evaluate_expression() {
         # BASH FEATURE: -v var=value passes variables to awk
         # Unlike JS where you'd use process.env, this sets awk variables directly
         result=$(awk -v PERSIST=1 -v DEBUG="$DEBUG" -f "$VM" "$ASM_FILE" 2>&1)
+        vm_exit_code=$?
         debug "VM output: $result"
+        debug "VM exit code: $vm_exit_code"
         if [ -n "$result" ]; then
             echo "$result"
         fi
+        if [ $vm_exit_code -ne 0 ]; then
+            return $vm_exit_code
+        fi
         return 0
     else
         echo "Compilation error" >&2
@@ -109,11 +114,16 @@ if [ "$#" -gt 0 ]; then
         exit 1
     fi
     debug "Reading file: $1"
-    file_content=$(cat "$1" | tr '\n' ' ')
+    file_content=$(cat "$1")
     debug "File content: $file_content"
+    # TODO: Workaround for curried/closure tests: just print the result of the last expression.
+    # This avoids emitting an extra CALL for the final value if it is not a function.
+    # A more robust solution would be to have the compiler analyze the top-level expression and only emit CALLs for function results,
+    # or to have the VM detect and print non-function results at the top level.
     evaluate_expression "$file_content"
+    exit_code=$?
     cleanup "keep_state"  # Keep state after file execution
-    exit 0
+    exit $exit_code
 fi
 
 # REPL state
diff --git a/awk/scheme/scheme/bin/vm.awk b/awk/scheme/scheme/bin/vm.awk
index ea15884..33a52a2 100755
--- a/awk/scheme/scheme/bin/vm.awk
+++ b/awk/scheme/scheme/bin/vm.awk
@@ -1,58 +1,89 @@
 #!/usr/bin/awk -f
 
-# This is a stack-based virtual machine for executing compiled Scheme code
-# It implements a simple instruction set with support for:
-# - Basic arithmetic operations
-# - Function calls and returns
-# - Variable bindings and lookups
-# - Cons cells and list operations
+# Stack-based Virtual Machine for Awk-Scheme
+#
+# This VM implements a simple but complete execution environment for compiled Scheme code.
+# The design prioritizes simplicity and correctness over performance, making it suitable
+# for educational purposes and small-scale applications.
+#
+# Architecture Overview:
+# - Stack-based execution model for simplicity and predictable memory usage
+# - Typed value system with runtime type checking for safety
+# - Environment-based variable binding supporting lexical scoping
+# - Closure support for nested function definitions and lexical scoping
+# - Persistent state between sessions for REPL continuity
+#
+# Key Design Decisions:
+# - All values are tagged with their type to enable runtime type checking
+# - Environment frames are pushed/popped for function calls to support lexical scoping
+# - Closures capture their creation environment to support nested functions
+# - State persistence uses simple text files for debugging and REPL continuity
+# - Function calls execute code directly rather than modifying the program array
 
 BEGIN {
     # Type system tags for runtime type checking
-    T_NUMBER = "N"    # Numbers (integers)
-    T_BOOLEAN = "B"   # Booleans (0/1)
-    T_SYMBOL = "S"    # Symbols (identifiers)
-    T_PAIR = "P"      # Cons cells (pairs)
-    T_FUNCTION = "F"  # Function references
-    T_NIL = "NIL"     # Empty list marker
+    # These prefixes enable safe value manipulation and clear error messages
+    T_NUMBER = "N"    # Numbers (integers only for simplicity)
+    T_BOOLEAN = "B"   # Booleans (0/1 for compatibility with AWK)
+    T_SYMBOL = "S"    # Symbols (identifiers and variable names)
+    T_PAIR = "P"      # Cons cells (pairs for list construction)
+    T_FUNCTION = "F"  # Function references (for function values)
+    T_NIL = "NIL"     # Empty list marker (distinct from null)
     T_CLOSURE = "CLOSURE"  # Closure objects (function + captured environment)
+    T_STRING = "STR"  # String literals (for text manipulation)
+
+    # Virtual machine registers and state
+    stack_ptr = 0     # Points to top of evaluation stack (1-indexed)
+    heap_ptr = 0      # Points to next free heap location for cons cells
+    pc = 0            # Program counter for instruction fetch and execution
 
-    # Virtual machine registers
-    stack_ptr = 0     # Points to top of evaluation stack
-    heap_ptr = 0      # Points to next free heap location
-    pc = 0            # Program counter for instruction fetch
-    
     # Original program storage for nested function definitions
-    # AWK FEATURE: delete array removes all elements from an array
-    # Unlike JS where you'd set array = [], this clears the array in place
+    # This preserves the complete program during function calls to support
+    # nested function definitions and complex control flow
     delete original_program  # Stores the original program before function calls
-    
+
+    # Debug mode configuration
     # AWK FEATURE: ENVIRON is a built-in array containing environment variables
     DEBUG = (ENVIRON["DEBUG"] == "1") ? 1 : 0
 
     # Environment for variable bindings
+    # This implements lexical scoping by maintaining a stack of variable bindings
     env_size = 0     # Current size of environment stack
-    
+
     # Closure support - captured environments for nested lambdas
+    # Closures capture their creation environment to support lexical scoping
+    # in nested function definitions
     delete closure_envs      # Maps env_id to captured environment arrays
     delete closure_env_names # Variable names in captured environments
     delete closure_env_vals  # Variable values in captured environments
     delete closure_env_sizes # Size of each captured environment
     next_env_id = 1         # Counter for generating unique environment IDs
-    
+
     # Function table for storing defined functions
+    # Functions are stored by name for efficient lookup during execution
     delete func_def_names  # Function names
     delete func_def_pc     # Entry points
     delete func_def_code   # Function bodies
     func_def_size = 0      # Number of defined functions
-    
+
     # Call stack for function returns
+    # Tracks return addresses for proper function call/return semantics
     call_stack_ptr = 0
 
+    # Enhanced call stack for nested function calls (for map/filter support)
+    # This enables function calls from within built-in functions
+    call_stack_size = 0                    # Current size of call stack
+    call_stack_return_pc[100]              # Return program counters
+    call_stack_return_env[100]             # Return environment sizes
+    call_stack_return_stack[100]           # Return stack pointers
+    call_stack_return_func[100]            # Return function names (for debugging)
+
     # Global function registry - clear it first
+    # This maps function names to their implementations for efficient dispatch
     delete FUNCTIONS       # Maps function names to implementations
 
     # State persistence configuration
+    # Uses simple text files for debugging and REPL continuity
     STATE_FILE = "/tmp/scheme_vm.state"
     debug("STATE_FILE_PATH: " STATE_FILE)
     debug("PERSIST_FLAG: " PERSIST)
@@ -76,7 +107,7 @@ BEGIN {
                     sub(/ .*$/, "", name)
                     code = line
                     sub(/^[^ ]+ /, "", code)
-                    
+
                     # Read the rest of the function code (until next FUNC or end of file)
                     debug("LOADING_STATE: Reading function code for " name)
                     while ((getline line < STATE_FILE) > 0) {
@@ -88,10 +119,10 @@ BEGIN {
                         }
                         code = code "\n" line
                     }
-                    
+
                     debug("Loaded function: " name)
                     debug("Code: " code)
-                    
+
                     # Store function in FUNCTIONS table
                     FUNCTIONS[name] = code
                     debug("LOADED_FUNCTION: " name " with code length " length(code))
@@ -110,15 +141,67 @@ BEGIN {
     delete func_env_sizes  # Size of each function's environment
 
     # Register built-in functions first
+    # These provide the core language operations and are always available
+    # The registration maps Scheme function names to internal VM function names
+    # for efficient dispatch during execution
     debug("REGISTERING_BUILTINS: " length(FUNCTIONS) " functions before")
+
+    # Arithmetic operations - core numeric functionality
     FUNCTIONS["+"] = "add"
     FUNCTIONS["-"] = "subtract"
     FUNCTIONS["*"] = "multiply"
     FUNCTIONS["/"] = "divide"
+    FUNCTIONS["modulo"] = "modulo"
+    FUNCTIONS["%"] = "modulo"  # Alias for modulo
+    FUNCTIONS["expt"] = "expt"
+    FUNCTIONS["abs"] = "abs"
+    FUNCTIONS["min"] = "min"
+    FUNCTIONS["max"] = "max"
     FUNCTIONS["="] = "equals"
     FUNCTIONS["<"] = "less_than"
     FUNCTIONS[">"] = "greater_than"
-    FUNCTIONS["add1"] = "add_one"
+    FUNCTIONS["inc"] = "add_one"
+    FUNCTIONS["++"] = "add_one"  # Alias for inc function
+    
+    # Output
+    FUNCTIONS["display"] = "display"
+
+    # String operations - text manipulation utilitie
+    FUNCTIONS["string-length"] = "string_length"
+    FUNCTIONS["string-append"] = "string_append"
+    FUNCTIONS["string-ref"] = "string_ref"
+    FUNCTIONS["substring"] = "substring"
+    FUNCTIONS["string=?"] = "string_equal"
+    FUNCTIONS["string<?"] = "string_less_than"
+    FUNCTIONS["string>?"] = "string_greater_than"
+
+    # Type predicates - essential for type checking
+    FUNCTIONS["number?"] = "number_p"
+    FUNCTIONS["string?"] = "string_p"
+    FUNCTIONS["boolean?"] = "boolean_p"
+    FUNCTIONS["symbol?"] = "symbol_p"
+    FUNCTIONS["zero?"] = "zero_p"
+    FUNCTIONS["positive?"] = "positive_p"
+    FUNCTIONS["negative?"] = "negative_p"
+
+    # Standard library - List utilities
+    # The implementation prioritizes simplicity over performance
+    FUNCTIONS["list"] = "stdlib_list"
+    FUNCTIONS["null?"] = "stdlib_null_p"
+    FUNCTIONS["pair?"] = "stdlib_pair_p"
+    FUNCTIONS["length"] = "stdlib_length"
+    FUNCTIONS["append"] = "stdlib_append"
+    FUNCTIONS["reverse"] = "stdlib_reverse"
+    FUNCTIONS["member"] = "stdlib_member"
+    FUNCTIONS["cadr"] = "stdlib_cadr"
+    FUNCTIONS["caddr"] = "stdlib_caddr"
+    FUNCTIONS["list-ref"] = "stdlib_list_ref"
+    FUNCTIONS["list-tail"] = "stdlib_list_tail"
+    FUNCTIONS["map"] = "stdlib_map"
+    FUNCTIONS["filter"] = "stdlib_filter"
+    FUNCTIONS["assert"] = "assert"
+    FUNCTIONS["error"] = "user_error"
+
     debug("REGISTERING_BUILTINS: " length(FUNCTIONS) " functions after")
 
     # Environment persistence configuration
@@ -134,9 +217,9 @@ BEGIN {
                     sub(/ .*$/, "", name)
                     val = line
                     sub(/^[^ ]+ /, "", val)
-                    
+
                     debug("Loaded env var: " name " = " val)
-                    
+
                     # Store in environment
                     env_name[env_size] = name
                     env_val[env_size] = val
@@ -187,6 +270,12 @@ function isPair(val) { return getType(val) == T_PAIR }
 function isFunction(val) { return getType(val) == T_FUNCTION }
 function isNil(val) { return getType(val) == T_NIL }
 function isClosure(val) { return getType(val) == T_CLOSURE }
+function isString(val) { return getType(val) == T_STRING }
+
+# String helper functions
+function makeString(val) {
+    return T_STRING ":" val
+}
 
 # Closure helper functions
 function makeClosure(func_name, env_id) {
@@ -195,7 +284,7 @@ function makeClosure(func_name, env_id) {
 
 function getClosureFunction(closure_val) {
     # Extract function name from CLOSURE:func_name:env_id
-    return substr(closure_val, index(closure_val, ":") + 1, 
+    return substr(closure_val, index(closure_val, ":") + 1,
                  index(substr(closure_val, index(closure_val, ":") + 1), ":") - 1)
 }
 
@@ -208,20 +297,16 @@ function getClosureEnvId(closure_val) {
 
 # Environment capture for closures
 function captureEnvironment(env_id, i) {
-    debug("Capturing environment with ID: " env_id)
+    if (DEBUG) print "[DEBUG_CLOSURE] Capturing environment with ID: " env_id > "/dev/stderr"
     closure_env_sizes[env_id] = env_size
-    
-    # Copy current environment to closure environment
     for (i = 0; i < env_size; i++) {
-        # Only capture non-global variables
         if (env_name[i] !~ /^__global_/) {
             closure_env_names[env_id, i] = env_name[i]
             closure_env_vals[env_id, i] = env_val[i]
-            debug("Captured: " env_name[i] " = " env_val[i])
+            if (DEBUG) print "[DEBUG_CLOSURE]   Captured: " env_name[i] " = " env_val[i] > "/dev/stderr"
         }
     }
-    
-    debug("Captured environment size: " closure_env_sizes[env_id])
+    if (DEBUG) print "[DEBUG_CLOSURE] Captured environment size: " closure_env_sizes[env_id] > "/dev/stderr"
 }
 
 # VM instruction to capture environment
@@ -229,7 +314,7 @@ function vm_capture_env(func_name) {
     debug("Capturing environment for function: " func_name)
     env_id = next_env_id++
     captureEnvironment(env_id)
-    
+
     # Replace the placeholder ENV_ID in the closure value
     # Find the closure value on the stack and update it
     if (stack_ptr > 0) {
@@ -245,14 +330,14 @@ function vm_capture_env(func_name) {
 
 # Environment restoration for closures
 function pushClosureEnvironment(env_id, i) {
-    debug("Pushing closure environment: " env_id)
+    if (DEBUG) print "[DEBUG_CLOSURE] Pushing closure environment: " env_id > "/dev/stderr"
     if (env_id in closure_env_sizes) {
         for (i = 0; i < closure_env_sizes[env_id]; i++) {
             if ((env_id, i) in closure_env_names) {
                 env_name[env_size] = closure_env_names[env_id, i]
                 env_val[env_size] = closure_env_vals[env_id, i]
                 env_size++
-                debug("Restored: " closure_env_names[env_id, i] " = " closure_env_vals[env_id, i])
+                if (DEBUG) print "[DEBUG_CLOSURE]   Restored: " closure_env_names[env_id, i] " = " closure_env_vals[env_id, i] > "/dev/stderr"
             }
         }
     }
@@ -304,7 +389,7 @@ function vm_add() {
     if (stack_ptr < 2) error("ADD requires two operands")
     val2 = pop()
     val1 = pop()
-    if (!isNumber(val1) || !isNumber(val2)) 
+    if (!isNumber(val1) || !isNumber(val2))
         error("ADD requires numeric operands")
     result = getValue(val1) + getValue(val2)
     push(makeValue(T_NUMBER, result))
@@ -342,6 +427,61 @@ function vm_divide() {
     push(makeValue(T_NUMBER, result))
 }
 
+function vm_modulo() {
+    if (stack_ptr < 2) error("MODULO requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2))
+        error("MODULO requires numeric operands")
+    if (getValue(val2) == 0)
+        error("Modulo by zero")
+    a = getValue(val1)
+    b = getValue(val2)
+    result = a % b
+    if (result < 0) result = result + b
+    push(makeValue(T_NUMBER, result))
+}
+
+function vm_expt() {
+    if (stack_ptr < 2) error("EXPT requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2))
+        error("EXPT requires numeric operands")
+    result = getValue(val1) ^ getValue(val2)
+    push(makeValue(T_NUMBER, result))
+}
+
+function vm_abs() {
+    if (stack_ptr < 1) error("ABS requires one operand")
+    val = pop()
+    if (!isNumber(val))
+        error("ABS requires numeric operand")
+    result = getValue(val)
+    if (result < 0) result = -result
+    push(makeValue(T_NUMBER, result))
+}
+
+function vm_min() {
+    if (stack_ptr < 2) error("MIN requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2))
+        error("MIN requires numeric operands")
+    result = (getValue(val1) < getValue(val2)) ? getValue(val1) : getValue(val2)
+    push(makeValue(T_NUMBER, result))
+}
+
+function vm_max() {
+    if (stack_ptr < 2) error("MAX requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2))
+        error("MAX requires numeric operands")
+    result = (getValue(val1) > getValue(val2)) ? getValue(val1) : getValue(val2)
+    push(makeValue(T_NUMBER, result))
+}
+
 # List operation implementations
 function vm_cons() {
     if (stack_ptr < 2) error("CONS requires two operands")
@@ -400,10 +540,26 @@ function execute(instr) {
     split(instr, parts, " ")
     op = parts[1]
     debug("Execute: " instr)
-    
+
     # Dispatch based on instruction opcode
     if (op == "PUSH_CONST") {
-        push(parts[2])
+        # Reconstruct the full value in case it contains spaces
+        value = parts[2]
+        for (i = 3; i <= length(parts); i++) {
+            value = value " " parts[i]
+        }
+        
+        # Handle escape sequences in string constants
+        if (value ~ /^STR:/) {
+            str_content = substr(value, 5)  # Remove "STR:" prefix
+            # Convert escape sequences back to actual characters
+            gsub(/\\n/, "\n", str_content)
+            gsub(/\\t/, "\t", str_content)
+            gsub(/\\\\/, "\\", str_content)
+            value = "STR:" str_content
+        }
+        
+        push(value)
     }
     else if (op == "POP") {
         pop()
@@ -416,7 +572,6 @@ function execute(instr) {
         if (stack_ptr < 2) error("SWAP requires two operands")
         val2 = pop()
         val1 = pop()
-        val1 = pop()
         push(val2)
         push(val1)
     }
@@ -485,6 +640,9 @@ function execute(instr) {
     else if (op == "CALL") {
         vm_call_function()
     }
+    else if (op == "CALL_WITH_ARGS") {
+        vm_call_function_with_args(parts[2])
+    }
     else if (op == "RETURN") {
         debug("EXECUTING_RETURN")
         # The call_stack_ptr is no longer used for return, so this instruction is effectively removed.
@@ -496,6 +654,24 @@ function execute(instr) {
     else if (op == "CAPTURE_ENV") {
         vm_capture_env(parts[2])
     }
+    else if (op == "JUMP") {
+        vm_jump(parts[2])
+    }
+    else if (op == "JUMP_IF_FALSE") {
+        vm_jump_if_false(parts[2])
+    }
+    else if (op == "JUMP_IF_TRUE") {
+        vm_jump_if_true(parts[2])
+    }
+    else if (op == "NOT") {
+        vm_not()
+    }
+    else if (op == "POP") {
+        vm_pop()
+    }
+    else if (op == "CLEAR_STACK") {
+        vm_clear_stack()
+    }
     else {
         error("Unknown instruction: " op)
     }
@@ -506,8 +682,11 @@ function execute(instr) {
 # NR is a built-in variable that contains the current record (line) number
 # Unlike JS where you'd need to track line numbers manually
 {
-    program[NR-1] = $0  # $0 is the current line being processed
-    original_program[NR-1] = $0  # Keep a copy of the original program
+    # Skip empty lines
+    if (length($0) > 0) {
+        program[NR-1] = $0  # $0 is the current line being processed
+        original_program[NR-1] = $0  # Keep a copy of the original program
+    }
 }
 
 # AWK FEATURE: END block runs after all input has been processed
@@ -519,17 +698,79 @@ END {
         # debug("EXECUTING_PC_" pc ": " program[pc])
         execute(program[pc++])
     }
-    
+
     # Save state if we didn't halt normally
     if (!normal_exit && PERSIST) {
         save_state()
     }
 }
 
+# Control flow instruction implementations
+function vm_jump(label) {
+    debug("Jumping to label: " label)
+    # Find the label in the program
+    for (i = 0; i < length(program); i++) {
+        if (program[i] == "LABEL " label) {
+            pc = i
+            return
+        }
+    }
+    error("Label not found: " label)
+}
+
+function vm_jump_if_false(label) {
+    if (stack_ptr < 1) error("JUMP_IF_FALSE requires one operand")
+    val = pop()
+    debug("Jump if false: " val " -> " label)
+
+    # Check if value is false (0, false, or nil)
+    is_false = (val == "B:0" || val == "N:0" || val == "NIL:")
+    if (is_false) {
+        vm_jump(label)
+    }
+}
+
+function vm_jump_if_true(label) {
+    if (stack_ptr < 1) error("JUMP_IF_TRUE requires one operand")
+    val = pop()
+    debug("Jump if true: " val " -> " label)
+
+    # Check if value is true (non-zero, non-false, non-nil)
+    is_true = (val != "B:0" && val != "N:0" && val != "NIL:")
+    if (is_true) {
+        vm_jump(label)
+    }
+}
+
+function vm_not() {
+    if (stack_ptr < 1) error("NOT requires one operand")
+    val = pop()
+    debug("NOT: " val)
+
+    # Negate the boolean value
+    if (val == "B:0" || val == "N:0" || val == "NIL:") {
+        push(makeValue(T_BOOLEAN, "1"))
+    } else {
+        push(makeValue(T_BOOLEAN, "0"))
+    }
+}
+
+function vm_pop() {
+    if (stack_ptr < 1) error("POP requires one operand")
+    val = pop()
+    debug("POP: " val)
+    # Value is discarded
+}
+
+function vm_clear_stack() {
+    debug("Clearing stack (was " stack_ptr " items)")
+    stack_ptr = 0
+}
+
 # Variable binding implementation
 function vm_store(name) {
     debug("Storing " peek() " as " name " at env_size: " env_size)
-    
+
     # Handle global definitions specially
     if (lookup_no_error("from_define")) {
         name = "__global_" name
@@ -540,7 +781,7 @@ function vm_store(name) {
                 break
             }
         }
-        
+
         # Remove any previous definition of this global
         for (i = env_size - 1; i >= 0; i--) {
             if (env_name[i] == name) {
@@ -554,7 +795,7 @@ function vm_store(name) {
             }
         }
     }
-    
+
     # Handle lambda functions
     val = peek()
     if (isSymbol(val)) {
@@ -571,12 +812,12 @@ function vm_store(name) {
             return
         }
     }
-    
+
     # Add to environment
     env_name[env_size] = name
     env_val[env_size] = peek()
     env_size++
-    
+
     debug("Environment after store:")
     dump_env()
 }
@@ -585,13 +826,13 @@ function vm_store(name) {
 function vm_pop_env() {
     if (env_size <= 0) error("Environment underflow")
     debug("Popping environment at size: " env_size)
-    
+
     # Don't pop globals
     if (env_name[env_size-1] ~ /^__global_/) {
         debug("Keeping global definition: " env_name[env_size-1])
         return
     }
-    
+
     debug("Removing: " env_name[env_size-1] " = " env_val[env_size-1])
     env_size--
 }
@@ -637,7 +878,7 @@ function vm_lookup(name, i, global_name, val) {
 function vm_define_function(name, start_pc) {
     debug("Defining function: " name " at " start_pc)
     debug("call_stack_ptr: " call_stack_ptr)
-    
+
     # Clear the from_define flag
     for (i = env_size - 1; i >= 0; i--) {
         if (env_name[i] == "from_define") {
@@ -646,11 +887,11 @@ function vm_define_function(name, start_pc) {
             break
         }
     }
-    
+
     # Build function code
     code = ""
     i = start_pc
-    
+
     # If we're inside a function call, we need to find the corresponding position
     # in the original program. For now, use a simple heuristic.
     if (call_stack_ptr > 0) {
@@ -675,28 +916,29 @@ function vm_define_function(name, start_pc) {
         }
     }
     code = code "\nRETURN"
-    
+
     # Store function
     debug("Storing function: " name " = " code)
     FUNCTIONS[name] = code
     debug("Function stored. Total functions: " length(FUNCTIONS))
     debug("FUNCTION_STORED: " name)
-    
+
     pc = i + 1
 }
 
 # Function call implementation
-function vm_call_function(code_lines, j, saved_pc, saved_env_size, arg, param_name) {
+function vm_call_function(code_lines, j, saved_pc, saved_env_size, arg, param_name, param_names, nparams, k) {
     # Get function name from stack
     func_name = pop()
     debug("Calling function: " func_name)
     debug("CALLING_FUNCTION: " func_name)
-    
+    debug("Stack pointer before function call: " stack_ptr)
+
     # If name is a symbol, get its value
     if (isSymbol(func_name)) {
         func_name = getValue(func_name)
     }
-    
+
     # Check if it's a built-in function first
     if (func_name in FUNCTIONS) {
         built_in_name = FUNCTIONS[func_name]
@@ -732,9 +974,153 @@ function vm_call_function(code_lines, j, saved_pc, saved_env_size, arg, param_na
             debug("Calling built-in function: add_one")
             add_one()
             return
+        } else if (built_in_name == "modulo") {
+            debug("Calling built-in function: modulo")
+            modulo()
+            return
+        } else if (built_in_name == "expt") {
+            debug("Calling built-in function: expt")
+            expt()
+            return
+        } else if (built_in_name == "abs") {
+            debug("Calling built-in function: abs")
+            abs()
+            return
+        } else if (built_in_name == "min") {
+            debug("Calling built-in function: min")
+            min()
+            return
+        } else if (built_in_name == "max") {
+            debug("Calling built-in function: max")
+            max()
+            return
+        } else if (built_in_name == "string_length") {
+            debug("Calling built-in function: string_length")
+            string_length()
+            return
+        } else if (built_in_name == "string_append") {
+            debug("Calling built-in function: string_append")
+            string_append()
+            return
+        } else if (built_in_name == "string_ref") {
+            debug("Calling built-in function: string_ref")
+            string_ref()
+            return
+        } else if (built_in_name == "substring") {
+            debug("Calling built-in function: substring")
+            substring()
+            return
+        } else if (built_in_name == "string_equal") {
+            debug("Calling built-in function: string_equal")
+            string_equal()
+            return
+        } else if (built_in_name == "string_less_than") {
+            debug("Calling built-in function: string_less_than")
+            string_less_than()
+            return
+        } else if (built_in_name == "string_greater_than") {
+            debug("Calling built-in function: string_greater_than")
+            string_greater_than()
+            return
+        } else if (built_in_name == "number_p") {
+            debug("Calling built-in function: number_p")
+            number_p()
+            return
+        } else if (built_in_name == "string_p") {
+            debug("Calling built-in function: string_p")
+            string_p()
+            return
+        } else if (built_in_name == "boolean_p") {
+            debug("Calling built-in function: boolean_p")
+            boolean_p()
+            return
+        } else if (built_in_name == "symbol_p") {
+            debug("Calling built-in function: symbol_p")
+            symbol_p()
+            return
+        } else if (built_in_name == "zero_p") {
+            debug("Calling built-in function: zero_p")
+            zero_p()
+            return
+        } else if (built_in_name == "positive_p") {
+            debug("Calling built-in function: positive_p")
+            positive_p()
+            return
+        } else if (built_in_name == "negative_p") {
+            debug("Calling built-in function: negative_p")
+            negative_p()
+            return
+        } else if (built_in_name == "stdlib_list") {
+            debug("Calling standard library function: stdlib_list")
+            stdlib_list()
+            return
+        } else if (built_in_name == "stdlib_null_p") {
+            debug("Calling standard library function: stdlib_null_p")
+            stdlib_null_p()
+            return
+        } else if (built_in_name == "stdlib_pair_p") {
+            debug("Calling standard library function: stdlib_pair_p")
+            stdlib_pair_p()
+            return
+        } else if (built_in_name == "stdlib_length") {
+            debug("Calling standard library function: stdlib_length")
+            stdlib_length()
+            return
+        } else if (built_in_name == "stdlib_append") {
+            debug("Calling standard library function: stdlib_append")
+            stdlib_append()
+            return
+    } else if (built_in_name == "display") {
+        debug("Calling built-in function: display")
+        display()
+        return
+    } else if (built_in_name == "stdlib_list") {
+        debug("Calling standard library function: stdlib_list")
+        stdlib_list()
+        return
+    } else if (built_in_name == "stdlib_reverse") {
+        debug("Calling standard library function: stdlib_reverse")
+        stdlib_reverse()
+        return
+    } else if (built_in_name == "stdlib_member") {
+        debug("Calling standard library function: stdlib_member")
+        stdlib_member()
+        return
+    } else if (built_in_name == "stdlib_cadr") {
+            debug("Calling standard library function: stdlib_cadr")
+            stdlib_cadr()
+            return
+        } else if (built_in_name == "stdlib_caddr") {
+            debug("Calling standard library function: stdlib_caddr")
+            stdlib_caddr()
+            return
+        } else if (built_in_name == "stdlib_list_ref") {
+            debug("Calling standard library function: stdlib_list_ref")
+            stdlib_list_ref()
+            return
+        } else if (built_in_name == "stdlib_list_tail") {
+            debug("Calling standard library function: stdlib_list_tail")
+            stdlib_list_tail()
+            return
+        } else if (built_in_name == "stdlib_map") {
+            debug("Calling standard library function: stdlib_map")
+            stdlib_map()
+            return
+        } else if (built_in_name == "stdlib_filter") {
+            debug("Calling standard library function: stdlib_filter")
+            stdlib_filter()
+            return
+        } else if (built_in_name == "assert") {
+            debug("Calling built-in function: assert")
+            assert()
+            return
+        } else if (built_in_name == "user_error") {
+            debug("Calling built-in function: user_error")
+            user_error()
+            return
         }
     }
-    
+
     # Handle anonymous functions and closures
     if (func_name ~ /^__lambda_/) {
         if (!(func_name in FUNCTIONS)) {
@@ -745,79 +1131,122 @@ function vm_call_function(code_lines, j, saved_pc, saved_env_size, arg, param_na
         debug("Calling closure: " func_name)
         closure_func = getClosureFunction(func_name)
         closure_env_id = getClosureEnvId(func_name)
-        
+
         if (!(closure_func in FUNCTIONS)) {
             error("Undefined closure function: " closure_func)
         }
-        
+
         # Restore the captured environment
         pushClosureEnvironment(closure_env_id)
-        
+
         # Use the closure's function name for the rest of the call
         func_name = closure_func
     } else if (!(func_name in FUNCTIONS)) {
         error("Undefined function: " func_name)
     }
-    
+
     saved_pc = pc
     saved_env_size = env_size
-    
-    # AWK FEATURE: split(string, array, separator) splits string into array elements
-    # Unlike JS string.split() which returns an array, this populates an existing array
+
     split(FUNCTIONS[func_name], code_lines, "\n")
-    
-    # Check if this is a parameterized function
-    if (code_lines[1] ~ /^STORE /) {
-        # This is a parameterized function (lambda)
-        # Get parameter name from STORE instruction
-        param_name = substr(code_lines[1], 7)
-        debug("Found parameter name: " param_name)
-        debug("FUNCTION_PARAM: " param_name)
-        
-        # Get argument from stack
-        arg = pop()
-        debug("Function argument: " arg)
-        debug("FUNCTION_ARG: " arg)
-        
-        # Create new environment frame
-        debug("Creating new environment frame at size: " env_size)
-        env_name[env_size] = param_name
-        env_val[env_size] = arg
-        env_size++
-        debug("FUNCTION_ENV_STORE: " param_name " = " arg " at index " (env_size-1))
-        
-        # Execute function code directly, skipping STORE and POP_ENV instructions
-        for (j = 2; j <= length(code_lines); j++) {
+
+    # --- Multi-parameter function support ---
+    # Collect all leading STORE instructions as parameter names
+    nparams = 0
+    for (j = 1; j <= length(code_lines); j++) {
+        if (code_lines[j] ~ /^STORE /) {
+            nparams++
+            param_names[nparams] = substr(code_lines[j], 7)
+        } else {
+            break
+        }
+    }
+    if (nparams > 0) {
+        debug("Function parameters: " nparams)
+        # Pop arguments in reverse order so first argument is bound to first param
+        for (k = nparams; k >= 1; k--) {
+            arg = pop()
+            param_name = param_names[k]
+            debug("Binding argument to parameter: " param_name " = " arg)
+            env_name[env_size] = param_name
+            env_val[env_size] = arg
+            env_size++
+            debug("FUNCTION_ENV_STORE: " param_name " = " arg " at index " (env_size-1))
+        }
+        # Execute function code, skipping STORE and POP_ENV instructions
+        for (j = nparams + 1; j <= length(code_lines); j++) {
             if (code_lines[j] != "" && code_lines[j] != "POP_ENV") {
                 debug("Executing function instruction: " code_lines[j])
                 execute(code_lines[j])
             }
         }
-        
-        # Clean up parameter
-        vm_pop_env()
-        
-        # Return to caller
+        # Clean up parameters
+        for (k = 1; k <= nparams; k++) {
+            vm_pop_env()
+        }
         debug("Function completed, returning to PC: " saved_pc)
-        pc = saved_pc
-        return
-    } else {
-        # This is a built-in function or non-parameterized function
-        debug("Calling non-parameterized function: " func_name)
-        
-        # Execute all function code directly
-        for (j in code_lines) {
-            if (code_lines[j] != "") {
-                debug("Executing function instruction: " code_lines[j])
-                execute(code_lines[j])
+        if (DEBUG) {
+            if (stack_ptr > 0) {
+                debug("[DEBUG_VM] Value on stack after CALL: " stack[stack_ptr-1])
+            } else {
+                debug("[DEBUG_VM] Stack is empty after CALL")
             }
         }
-        
-        # Return to caller
-        debug("Function completed, returning to PC: " saved_pc)
         pc = saved_pc
         return
     }
+    # --- End multi-parameter support ---
+
+    # This is a built-in function or non-parameterized function
+    debug("Calling non-parameterized function: " func_name)
+    for (j in code_lines) {
+        if (code_lines[j] != "") {
+            debug("Executing function instruction: " code_lines[j])
+            execute(code_lines[j])
+        }
+    }
+    debug("Function completed, returning to PC: " saved_pc)
+    if (DEBUG) {
+        if (stack_ptr > 0) {
+            debug("[DEBUG_VM] Value on stack after CALL: " stack[stack_ptr-1])
+        } else {
+            debug("[DEBUG_VM] Stack is empty after CALL")
+        }
+    }
+    pc = saved_pc
+    return
+}
+
+# Function call with argument count implementation
+function vm_call_function_with_args(arg_count, code_lines, j, saved_pc, saved_env_size, arg, param_name) {
+    # Get function name from stack
+    func_name = pop()
+    debug("Calling function with args: " func_name " (arg_count: " arg_count ")")
+    debug("CALLING_FUNCTION_WITH_ARGS: " func_name " (arg_count: " arg_count ")")
+    debug("Stack pointer before function call: " stack_ptr)
+
+    # If name is a symbol, get its value
+    if (isSymbol(func_name)) {
+        func_name = getValue(func_name)
+    }
+
+    # Check if it's a built-in function first
+    if (func_name in FUNCTIONS) {
+        built_in_name = FUNCTIONS[func_name]
+        if (built_in_name == "stdlib_list") {
+            debug("Calling standard library function with args: stdlib_list (arg_count: " arg_count ")")
+            stdlib_list_with_args(arg_count)
+            return
+        } else if (built_in_name == "string_append") {
+            debug("Calling built-in function with args: string_append (arg_count: " arg_count ")")
+            string_append_with_args(arg_count)
+            return
+        }
+    }
+
+    # For other functions, fall back to regular call
+    debug("Falling back to regular function call for: " func_name)
+    vm_call_function()
 }
 
 # Function return implementation - no longer needed with direct execution
@@ -827,25 +1256,25 @@ function vm_call_function(code_lines, j, saved_pc, saved_env_size, arg, param_na
 #         # Save return value
 #         ret_val = pop()
 #         debug("VM_RETURN: return value = " ret_val)
-#         
+#
 #         # Restore environment
 #         while (env_size > env_stack[call_stack_ptr]) {
 #             debug("Popping environment at size: " env_size)
 #             vm_pop_env()
 #         }
-#         
+#
 #         # Restore program counter
 #         pc = call_stack[call_stack_ptr--]
 #         debug("VM_RETURN: restored PC = " pc)
-#         
+#
 #         # Restore the original program at the call position
 #         program[pc] = original_program_at_call[call_stack_ptr + 1]
 #         debug("Restored original program: " original_program_at_call[call_stack_ptr + 1])
-#         
+#
 #         # Push return value
 #         push(ret_val)
 #         debug("VM_RETURN: pushed return value " ret_val)
-#         
+#
 #         debug("Returned with value: " ret_val " and env_size: " env_size)
 #     }
 # }
@@ -969,13 +1398,213 @@ function divide() {
 }
 
 function add_one() {
-    if (stack_ptr < 1) error("add1 requires one operand")
+    if (stack_ptr < 1) error("inc requires one operand")
     val = pop()
-    if (!isNumber(val)) error("add1 requires numeric operand")
+    if (!isNumber(val)) error("inc requires numeric operand")
     result = getValue(val) + 1
     push(makeValue(T_NUMBER, result))
 }
 
+function modulo() {
+    if (stack_ptr < 2) error("modulo requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2)) error("modulo requires numeric operands")
+    if (getValue(val2) == 0) error("Modulo by zero")
+    a = getValue(val1)
+    b = getValue(val2)
+    result = a % b
+    if (result < 0) result = result + b
+    push(makeValue(T_NUMBER, result))
+}
+
+function expt() {
+    if (stack_ptr < 2) error("expt requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2)) error("expt requires numeric operands")
+    result = getValue(val1) ^ getValue(val2)
+    push(makeValue(T_NUMBER, result))
+}
+
+function abs() {
+    if (stack_ptr < 1) error("abs requires one operand")
+    val = pop()
+    if (!isNumber(val)) error("abs requires numeric operand")
+    result = getValue(val)
+    if (result < 0) result = -result
+    push(makeValue(T_NUMBER, result))
+}
+
+function min() {
+    if (stack_ptr < 2) error("min requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2)) error("min requires numeric operands")
+    result = (getValue(val1) < getValue(val2)) ? getValue(val1) : getValue(val2)
+    push(makeValue(T_NUMBER, result))
+}
+
+function max() {
+    if (stack_ptr < 2) error("max requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isNumber(val1) || !isNumber(val2)) error("max requires numeric operands")
+    result = (getValue(val1) > getValue(val2)) ? getValue(val1) : getValue(val2)
+    push(makeValue(T_NUMBER, result))
+}
+
+# String operations
+function string_length() {
+    if (stack_ptr < 1) error("string-length requires one operand")
+    val = pop()
+    if (!isString(val)) error("string-length requires string operand")
+    str = getValue(val)
+    push(makeValue(T_NUMBER, length(str)))
+}
+
+function string_append() {
+    if (stack_ptr < 2) error("string-append requires at least two operands")
+    result = ""
+    # Pop all arguments and concatenate (in reverse order)
+    while (stack_ptr > 0) {
+        val = pop()
+        if (!isString(val)) error("string-append requires string operands")
+        result = getValue(val) result  # Prepend to maintain order
+    }
+    push(makeString(result))
+}
+
+function string_append_with_args(arg_count) {
+    if (arg_count < 2) error("string-append requires at least two operands")
+    if (stack_ptr < arg_count) error("string-append requires " arg_count " arguments, but only " stack_ptr " available")
+    
+    result = ""
+    # Pop specified number of arguments and concatenate (in reverse order)
+    for (i = arg_count; i >= 1; i--) {
+        val = pop()
+        if (!isString(val)) error("string-append requires string operands")
+        result = getValue(val) result  # Prepend to maintain order
+    }
+    push(makeString(result))
+}
+
+function string_ref() {
+    if (stack_ptr < 2) error("string-ref requires two operands")
+    index_val = pop()
+    str_val = pop()
+    if (!isNumber(index_val)) error("string-ref index must be a number")
+    if (!isString(str_val)) error("string-ref requires string operand")
+
+    str = getValue(str_val)
+    idx = getValue(index_val) + 1  # Convert to 1-indexed
+    if (idx < 1 || idx > length(str)) error("string-ref index out of bounds")
+
+    char = substr(str, idx, 1)
+    push(makeString(char))
+}
+
+function substring() {
+    if (stack_ptr < 3) error("substring requires three operands")
+    end = pop()
+    start = pop()
+    str_val = pop()
+
+    if (!isNumber(start) || !isNumber(end)) error("substring indices must be numbers")
+    if (!isString(str_val)) error("substring requires string operand")
+
+    str = getValue(str_val)
+    start_idx = getValue(start) + 1  # Convert to 1-indexed
+    end_idx = getValue(end) + 1
+
+    if (start_idx < 1 || end_idx > length(str) || start_idx > end_idx) {
+        error("substring indices out of bounds")
+    }
+
+    result = substr(str, start_idx, end_idx - start_idx + 1)
+    push(makeString(result))
+}
+
+function string_equal() {
+    if (stack_ptr < 2) error("string=? requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isString(val1) || !isString(val2)) error("string=? requires string operands")
+    result = (getValue(val1) == getValue(val2)) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function string_less_than() {
+    if (stack_ptr < 2) error("string<? requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isString(val1) || !isString(val2)) error("string<? requires string operands")
+    result = (getValue(val1) < getValue(val2)) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function string_greater_than() {
+    if (stack_ptr < 2) error("string>? requires two operands")
+    val2 = pop()
+    val1 = pop()
+    if (!isString(val1) || !isString(val2)) error("string>? requires string operands")
+    result = (getValue(val1) > getValue(val2)) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+# Type predicates - essential for type checking
+function number_p() {
+    if (stack_ptr < 1) error("number? requires one operand")
+    val = pop()
+    result = isNumber(val) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function string_p() {
+    if (stack_ptr < 1) error("string? requires one operand")
+    val = pop()
+    result = isString(val) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function boolean_p() {
+    if (stack_ptr < 1) error("boolean? requires one operand")
+    val = pop()
+    result = isBoolean(val) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function symbol_p() {
+    if (stack_ptr < 1) error("symbol? requires one operand")
+    val = pop()
+    result = isSymbol(val) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function zero_p() {
+    if (stack_ptr < 1) error("zero? requires one operand")
+    val = pop()
+    if (!isNumber(val)) error("zero? requires numeric operand")
+    result = (getValue(val) == 0) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function positive_p() {
+    if (stack_ptr < 1) error("positive? requires one operand")
+    val = pop()
+    if (!isNumber(val)) error("positive? requires numeric operand")
+    result = (getValue(val) > 0) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+function negative_p() {
+    if (stack_ptr < 1) error("negative? requires one operand")
+    val = pop()
+    if (!isNumber(val)) error("negative? requires numeric operand")
+    result = (getValue(val) < 0) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
 # Get value from top of stack
 function vm_get_value() {
     val = pop()
@@ -994,4 +1623,888 @@ function vm_get_value() {
         # For other types, just push the value back
         push(val)
     }
+}
+
+# Print a value to stdout (handles numbers, strings, booleans, and lists)
+function display() {
+    if (stack_ptr < 1) error("display requires one argument")
+    val = pop()
+    print display_value(val)
+}
+
+# Assert function for testing - checks if condition is true
+function assert() {
+    if (stack_ptr < 1) error("assert requires one argument")
+    val = pop()
+    if (!isBoolean(val) && !isNumber(val)) {
+        error("assert requires boolean or number argument")
+    }
+    if (getValue(val) == "0" || getValue(val) == "B:0") {
+        error("Assertion failed")
+    }
+}
+
+# User-callable error function
+function user_error() {
+    if (stack_ptr < 1) error("error requires one argument")
+    val = pop()
+    if (!isString(val)) {
+        error("error requires string argument")
+    }
+    error(getValue(val))
+}
+
+# Recursively convert a value to a string for display
+function display_value(val,   t, idx, pair, car_val, cdr_val, result) {
+    t = getType(val)
+    if (t == T_NUMBER) return getValue(val)
+    if (t == T_BOOLEAN) return (getValue(val) == "1" ? "#t" : "#f")
+    if (t == T_STRING) return getValue(val)
+    if (t == T_SYMBOL) return getValue(val)
+    if (t == T_NIL) return "()"
+    if (t == T_PAIR) {
+        result = "("
+        idx = getValue(val)
+        pair = getHeap(idx)
+        car_val = substr(pair, 1, index(pair, ",") - 1)
+        cdr_val = substr(pair, index(pair, ",") + 1)
+        result = result display_value(car_val)
+        while (cdr_val != "NIL:" && isPair(cdr_val)) {
+            idx = getValue(cdr_val)
+            pair = getHeap(idx)
+            car_val = substr(pair, 1, index(pair, ",") - 1)
+            cdr_val = substr(pair, index(pair, ",") + 1)
+            result = result " " display_value(car_val)
+        }
+        if (cdr_val != "NIL:") {
+            result = result " . " display_value(cdr_val)
+        }
+        result = result ")"
+        return result
+    }
+    if (t == T_CLOSURE) return "#<closure>"
+    if (t == T_FUNCTION) return "#<function>"
+    return "#<unknown>"
+}
+
+# Standard Library Functions
+# These implement essential Scheme list utilities following standard conventions
+# Each function prioritizes correctness and clear error messages over performance
+# The implementation uses the VM's heap for cons cell allocation and management
+
+# Create a list from elements
+# This function handles variable argument counts by building the list from the stack
+# The implementation reverses the stack order to maintain proper list construction
+function stdlib_list() {
+    debug("stdlib_list called with stack_ptr: " stack_ptr)
+    debug("Stack contents before list: " stack_ptr " items")
+    # This will be a special form handled by the compiler
+    # For now, we'll implement it as a function that takes arguments from stack
+    if (stack_ptr < 1) {
+        # No arguments, return empty list
+        debug("No arguments, returning NIL:")
+        push("NIL:")
+        return
+    }
+
+    # Build list from stack elements (arguments are in reverse order on stack)
+    result = "NIL:"
+    nargs = stack_ptr
+    debug("Building list with " nargs " arguments")
+
+    # Pop arguments and build list in correct order
+    for (i = nargs; i >= 1; i--) {
+        val = pop()
+        debug("Popped argument " i ": " val)
+        # Create cons cell with current value and result
+        pair_val = val "," result
+        pair_idx = allocate(pair_val)
+        result = makeValue(T_PAIR, pair_idx)
+        debug("Created pair: " result)
+    }
+
+    debug("Final result: " result)
+    debug("Stack contents after list: " stack_ptr " items")
+    push(result)
+}
+
+# Create a list from elements with explicit argument count
+# This function only consumes the specified number of arguments
+function stdlib_list_with_args(arg_count) {
+    debug("stdlib_list_with_args called with arg_count: " arg_count)
+    debug("Stack contents before list: " stack_ptr " items")
+    
+    if (arg_count < 0) {
+        error("Invalid argument count for list: " arg_count)
+    }
+    
+    if (arg_count == 0) {
+        # No arguments, return empty list
+        debug("No arguments, returning NIL:")
+        push("NIL:")
+        return
+    }
+
+    if (stack_ptr < arg_count) {
+        error("list requires " arg_count " arguments, but only " stack_ptr " available")
+    }
+
+    # Build list from stack elements (arguments are in reverse order on stack)
+    result = "NIL:"
+    debug("Building list with " arg_count " arguments")
+
+    # Pop arguments and build list in correct order
+    for (i = arg_count; i >= 1; i--) {
+        val = pop()
+        debug("Popped argument " i ": " val)
+        # Create cons cell with current value and result
+        pair_val = val "," result
+        pair_idx = allocate(pair_val)
+        result = makeValue(T_PAIR, pair_idx)
+        debug("Created pair: " result)
+    }
+
+    debug("Final result: " result)
+    debug("Stack contents after list: " stack_ptr " items")
+    push(result)
+}
+
+# Check if value is null (empty list)
+# This predicate is essential for list processing and control flow
+function stdlib_null_p() {
+    if (stack_ptr < 1) error("null? requires one argument")
+    val = pop()
+    result = (val == "NIL:") ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+# Check if value is a pair (cons cell)
+# This predicate enables safe list manipulation by checking types
+function stdlib_pair_p() {
+    if (stack_ptr < 1) error("pair? requires one argument")
+    val = pop()
+    result = isPair(val) ? "1" : "0"
+    push(makeValue(T_BOOLEAN, result))
+}
+
+# Get length of a list
+# This function traverses the list structure to count elements
+# It provides clear error messages for non-list arguments
+function stdlib_length() {
+    if (stack_ptr < 1) error("length requires one argument")
+    val = pop()
+
+    if (val == "NIL:") {
+        push(makeValue(T_NUMBER, "0"))
+        return
+    }
+
+    if (!isPair(val)) {
+        error("length requires a list argument")
+    }
+
+    count = 0
+    current = val
+
+    while (current != "NIL:" && isPair(current)) {
+        count++
+        # Get cdr of current pair
+        pair_idx = getValue(current)
+        pair = getHeap(pair_idx)
+        cdr_val = substr(pair, index(pair, ",") + 1)
+        current = cdr_val
+    }
+
+    push(makeValue(T_NUMBER, count))
+}
+
+# Append two lists
+# This function creates a new list by copying the first list and
+# replacing its final NIL: with the second list
+function stdlib_append() {
+    if (stack_ptr < 2) error("append requires two arguments")
+    list2 = pop()
+    list1 = pop()
+
+    if (list1 == "NIL:") {
+        push(list2)
+        return
+    }
+
+    if (!isPair(list1)) {
+        error("append requires list arguments")
+    }
+
+    # Copy first list
+    result = copy_list(list1)
+
+    # Find end of first list
+    current = result
+    while (current != "NIL:" && isPair(current)) {
+        pair_idx = getValue(current)
+        pair = getHeap(pair_idx)
+        cdr_val = substr(pair, index(pair, ",") + 1)
+
+        if (cdr_val == "NIL:") {
+            # Replace NIL: with second list
+            new_pair_val = substr(pair, 1, index(pair, ",")) list2
+            heap[pair_idx] = new_pair_val
+            break
+        }
+        current = cdr_val
+    }
+
+    push(result)
+}
+
+# Get second element of list (car of cdr)
+# This function implements the standard Scheme cadr operation
+# It provides clear error messages for lists with insufficient elements
+function stdlib_cadr() {
+    if (stack_ptr < 1) error("cadr requires one argument")
+    val = pop()
+
+    if (val == "NIL:" || !isPair(val)) {
+        error("cadr requires a list with at least 2 elements")
+    }
+
+    # Get cdr
+    pair_idx = getValue(val)
+    pair = getHeap(pair_idx)
+    cdr_val = substr(pair, index(pair, ",") + 1)
+
+    if (cdr_val == "NIL:" || !isPair(cdr_val)) {
+        error("cadr requires a list with at least 2 elements")
+    }
+
+    # Get car of cdr
+    cdr_pair_idx = getValue(cdr_val)
+    cdr_pair = getHeap(cdr_pair_idx)
+    cadr_val = substr(cdr_pair, 1, index(cdr_pair, ",") - 1)
+
+    push(cadr_val)
+}
+
+# Get third element of list (car of cdr of cdr)
+# This function implements the standard Scheme caddr operation
+# It provides clear error messages for lists with insufficient elements
+function stdlib_caddr() {
+    if (stack_ptr < 1) error("caddr requires one argument")
+    val = pop()
+
+    if (val == "NIL:" || !isPair(val)) {
+        error("caddr requires a list with at least 3 elements")
+    }
+
+    # Get cdr of cdr
+    pair_idx = getValue(val)
+    pair = getHeap(pair_idx)
+    cdr_val = substr(pair, index(pair, ",") + 1)
+
+    if (cdr_val == "NIL:" || !isPair(cdr_val)) {
+        error("caddr requires a list with at least 3 elements")
+    }
+
+    cdr_pair_idx = getValue(cdr_val)
+    cdr_pair = getHeap(cdr_pair_idx)
+    cdot_val = substr(cdr_pair, index(cdr_pair, ",") + 1)
+
+    if (cdot_val == "NIL:" || !isPair(cdot_val)) {
+        error("caddr requires a list with at least 3 elements")
+    }
+
+    # Get car of cdr of cdr
+    cdot_pair_idx = getValue(cdot_val)
+    cdot_pair = getHeap(cdot_pair_idx)
+    caddr_val = substr(cdot_pair, 1, index(cdot_pair, ",") - 1)
+
+    push(caddr_val)
+}
+
+# Reverse a list
+# This function creates a new list with elements in reverse order
+# It traverses the original list and builds the result using cons
+function stdlib_reverse() {
+    if (stack_ptr < 1) error("reverse requires one argument")
+    list_val = pop()
+
+    if (list_val == "NIL:") {
+        push("NIL:")
+        return
+    }
+
+    if (!isPair(list_val)) {
+        error("reverse requires a list argument")
+    }
+
+    # Build reversed list
+    result = "NIL:"
+    current = list_val
+
+    while (current != "NIL:" && isPair(current)) {
+        # Get car of current pair
+        pair_idx = getValue(current)
+        pair = getHeap(pair_idx)
+        car_val = substr(pair, 1, index(pair, ",") - 1)
+
+        # Add to result
+        pair_val = car_val "," result
+        pair_idx = allocate(pair_val)
+        result = makeValue(T_PAIR, pair_idx)
+
+        # Move to next element
+        current = substr(pair, index(pair, ",") + 1)
+    }
+
+    push(result)
+}
+
+# Check if element is member of list
+# This function returns the sublist starting from the matching element
+# or NIL: if the element is not found
+function stdlib_member() {
+    debug("stdlib_member called with stack_ptr: " stack_ptr)
+    if (stack_ptr < 2) error("member requires two arguments")
+    list_val = pop()
+    elem_val = pop()
+    debug("stdlib_member: elem_val=" elem_val " list_val=" list_val)
+
+    if (list_val == "NIL:") {
+        push("NIL:")
+        return
+    }
+
+    if (!isPair(list_val)) {
+        error("member requires a list as second argument")
+    }
+
+    current = list_val
+
+    while (current != "NIL:" && isPair(current)) {
+        # Get car of current pair
+        pair_idx = getValue(current)
+        pair = getHeap(pair_idx)
+        car_val = substr(pair, 1, index(pair, ",") - 1)
+
+        # Check if element matches
+        if (car_val == elem_val) {
+            push(current)  # Return the sublist starting from this element
+            return
+        }
+
+        # Move to next element
+        current = substr(pair, index(pair, ",") + 1)
+    }
+
+    # Element not found
+    push("NIL:")
+}
+
+# Get element at index in list
+function stdlib_list_ref() {
+    if (stack_ptr < 2) error("list-ref requires two arguments")
+    index_val = pop()
+    list_val = pop()
+
+    if (!isNumber(index_val)) {
+        error("list-ref index must be a number")
+    }
+
+    idx = getValue(index_val)
+
+    if (list_val == "NIL:") {
+        error("list-ref index out of bounds")
+    }
+
+    if (!isPair(list_val)) {
+        error("list-ref requires a list argument")
+    }
+
+    current = list_val
+    count = 0
+
+    while (current != "NIL:" && isPair(current)) {
+        if (count == idx) {
+            # Get car of current pair
+            pair_idx = getValue(current)
+            pair = getHeap(pair_idx)
+            car_val = substr(pair, 1, index(pair, ",") - 1)
+            push(car_val)
+            return
+        }
+
+        # Move to next element
+        pair_idx = getValue(current)
+        pair = getHeap(pair_idx)
+        current = substr(pair, index(pair, ",") + 1)
+        count++
+    }
+
+    error("list-ref index out of bounds")
+}
+
+# Get list from index onwards
+function stdlib_list_tail() {
+    if (stack_ptr < 2) error("list-tail requires two arguments")
+    index_val = pop()
+    list_val = pop()
+
+    if (!isNumber(index_val)) {
+        error("list-tail index must be a number")
+    }
+
+    idx = getValue(index_val)
+
+    if (idx == 0) {
+        push(list_val)
+        return
+    }
+
+    if (list_val == "NIL:") {
+        error("list-tail index out of bounds")
+    }
+
+    if (!isPair(list_val)) {
+        error("list-tail requires a list argument")
+    }
+
+    current = list_val
+    count = 0
+
+    while (current != "NIL:" && isPair(current)) {
+        if (count == idx) {
+            push(current)
+            return
+        }
+
+        # Move to next element
+        pair_idx = getValue(current)
+        pair = getHeap(pair_idx)
+        current = substr(pair, index(pair, ",") + 1)
+        count++
+    }
+
+    if (count == idx) {
+        push("NIL:")
+        return
+    }
+
+    error("list-tail index out of bounds")
+}
+
+# Helper function to copy a list
+function copy_list(list_val, result, current, pair_idx, pair, car_val, cdr_val) {
+    if (list_val == "NIL:") {
+        return "NIL:"
+    }
+
+    if (!isPair(list_val)) {
+        error("copy_list requires a list argument")
+    }
+
+    result = "NIL:"
+    current = list_val
+
+    # Build result list in reverse order
+    temp_stack[0] = 0
+    while (current != "NIL:" && isPair(current)) {
+        pair_idx = getValue(current)
+        pair = getHeap(pair_idx)
+        car_val = substr(pair, 1, index(pair, ",") - 1)
+
+        temp_stack[++temp_stack[0]] = car_val
+
+        cdr_val = substr(pair, index(pair, ",") + 1)
+        current = cdr_val
+    }
+
+    # Build result in correct order
+    for (i = temp_stack[0]; i >= 1; i--) {
+        if (result == "NIL:") {
+            result = temp_stack[i]
+        } else {
+            pair_val = temp_stack[i] "," result
+            pair_idx = allocate(pair_val)
+            result = makeValue(T_PAIR, pair_idx)
+        }
+    }
+
+    return result
+}
+
+# Apply function to each element of a list
+function stdlib_map() {
+    if (stack_ptr < 2) error("map requires two arguments")
+    list_val = pop()
+    func_val = pop()
+
+    debug("Map called with function: " func_val " and list: " list_val)
+
+    if (!isClosure(func_val) && !isSymbol(func_val)) {
+        error("map requires a function as first argument")
+    }
+
+    if (list_val == "NIL:") {
+        push("NIL:")
+        return
+    }
+
+    if (!isPair(list_val)) {
+        error("map requires a list as second argument")
+    }
+
+    result = "NIL:"
+    current = list_val
+    temp_stack[0] = 0
+
+    # Process each element and collect results
+    while (current != "NIL:" && isPair(current)) {
+        pair_idx = getValue(current)
+        pair = getHeap(pair_idx)
+        car_val = substr(pair, 1, index(pair, ",") - 1)
+
+        debug("Map processing element: " car_val)
+
+        # Use new function call context
+        call_function_context(func_val, car_val)
+
+        # Get the result
+        mapped_val = pop()
+        temp_stack[++temp_stack[0]] = mapped_val
+
+        debug("Map collected result: " mapped_val)
+
+        cdr_val = substr(pair, index(pair, ",") + 1)
+        current = cdr_val
+    }
+
+    # Build result list in correct order
+    for (i = temp_stack[0]; i >= 1; i--) {
+        if (result == "NIL:") {
+            result = temp_stack[i]
+        } else {
+            pair_val = temp_stack[i] "," result
+            pair_idx = allocate(pair_val)
+            result = makeValue(T_PAIR, pair_idx)
+        }
+    }
+
+    debug("Map returning result: " result)
+    push(result)
+}
+
+# Filter list elements based on predicate function
+function stdlib_filter() {
+    if (stack_ptr < 2) error("filter requires two arguments")
+    list_val = pop()
+    pred_val = pop()
+
+    debug("Filter called with predicate: " pred_val " and list: " list_val)
+
+    if (!isClosure(pred_val) && !isSymbol(pred_val)) {
+        error("filter requires a function as first argument")
+    }
+
+    if (list_val == "NIL:") {
+        push("NIL:")
+        return
+    }
+
+    if (!isPair(list_val)) {
+        error("filter requires a list as second argument")
+    }
+
+    result = "NIL:"
+    current = list_val
+    temp_stack[0] = 0
+
+    # Process each element and collect matching results
+    while (current != "NIL:" && isPair(current)) {
+        pair_idx = getValue(current)
+        pair = getHeap(pair_idx)
+        car_val = substr(pair, 1, index(pair, ",") - 1)
+
+        debug("Filter processing element: " car_val)
+
+        # Use new function call context
+        call_function_context(pred_val, car_val)
+
+        # Get the predicate result
+        pred_result = pop()
+        debug("Filter predicate result: " pred_result)
+        if (is_truthy(pred_result)) {
+            temp_stack[++temp_stack[0]] = car_val
+            debug("Filter keeping element: " car_val)
+        }
+
+        cdr_val = substr(pair, index(pair, ",") + 1)
+        current = cdr_val
+    }
+
+    # Build result list in correct order
+    for (i = temp_stack[0]; i >= 1; i--) {
+        if (result == "NIL:") {
+            result = temp_stack[i]
+        } else {
+            pair_val = temp_stack[i] "," result
+            pair_idx = allocate(pair_val)
+            result = makeValue(T_PAIR, pair_idx)
+        }
+    }
+
+    debug("Filter returning result: " result)
+    push(result)
+}
+
+# Helper function to call a function (used by map and filter)
+function call_function() {
+    func_val = pop()
+    arg = pop()
+    
+    if (isSymbol(func_val)) {
+        func_name = getValue(func_val)
+        if (func_name in FUNCTIONS) {
+            # Built-in function
+            push(arg)
+            built_in_name = FUNCTIONS[func_name]
+            if (built_in_name == "add") {
+                add()
+            } else if (built_in_name == "subtract") {
+                subtract()
+            } else if (built_in_name == "multiply") {
+                multiply()
+            } else if (built_in_name == "divide") {
+                divide()
+            } else if (built_in_name == "modulo") {
+                modulo()
+            } else if (built_in_name == "expt") {
+                expt()
+            } else if (built_in_name == "abs") {
+                abs()
+            } else if (built_in_name == "min") {
+                min()
+            } else if (built_in_name == "max") {
+                max()
+            } else if (built_in_name == "add_one") {
+                add_one()
+            } else {
+                error("Unsupported built-in function in map: " func_name)
+            }
+        } else {
+            # User-defined function - simplified for now
+            error("User-defined functions not yet supported in map")
+        }
+    } else if (isClosure(func_val)) {
+        # Lambda function - simplified for now
+        error("Lambda functions not yet supported in map")
+    } else {
+        error("Invalid function type in map")
+    }
+}
+
+# Context management functions for nested function calls
+function save_call_context(func_name) {
+    if (call_stack_size >= 100) {
+        error("Call stack overflow - too many nested function calls")
+    }
+    
+    call_stack_return_pc[call_stack_size] = pc
+    call_stack_return_env[call_stack_size] = env_size
+    call_stack_return_stack[call_stack_size] = stack_ptr
+    call_stack_return_func[call_stack_size] = func_name
+    
+    call_stack_size++
+    debug("Saved call context for " func_name " - stack size: " call_stack_size)
+}
+
+function restore_call_context() {
+    if (call_stack_size <= 0) {
+        error("Call stack underflow - trying to restore with empty stack")
+    }
+    
+    call_stack_size--
+    pc = call_stack_return_pc[call_stack_size]
+    env_size = call_stack_return_env[call_stack_size]
+    # Don't restore stack_ptr - the nested call should leave its result on top
+    # stack_ptr = call_stack_return_stack[call_stack_size]
+    
+    debug("Restored call context - stack size: " call_stack_size " (stack_ptr: " stack_ptr ")")
+}
+
+function call_function_context(func_val, arg) {
+    debug("Calling function in context: " func_val " with arg: " arg)
+    
+    # Save current context
+    save_call_context("nested_call")
+    
+    # Push argument and function
+    push(arg)
+    push(func_val)
+    
+    # Execute function call
+    execute_nested_function_call()
+    
+    # Restore context
+    restore_call_context()
+}
+
+function execute_nested_function_call() {
+    func_val = pop()
+    arg = pop()
+    
+    debug("Executing nested function call: " func_val " with arg: " arg)
+    
+    if (isSymbol(func_val)) {
+        func_name = getValue(func_val)
+        debug("Function name from symbol: " func_name)
+        
+        # Handle lambda functions (__lambda_*)
+        if (func_name ~ /^__lambda_/) {
+            if (!(func_name in FUNCTIONS)) {
+                error("Undefined lambda function: " func_name)
+            }
+            call_user_function_nested(func_name, arg)
+        } else if (func_name in FUNCTIONS) {
+            # Built-in function
+            push(arg)
+            built_in_name = FUNCTIONS[func_name]
+            debug("Built-in function name: " built_in_name)
+            call_builtin_function_nested(built_in_name)
+        } else {
+            # User-defined function
+            call_user_function_nested(func_name, arg)
+        }
+    } else if (isClosure(func_val)) {
+        # Lambda function with captured environment
+        debug("Calling closure in nested context: " func_val)
+        call_closure_nested(func_val, arg)
+    } else {
+        error("Invalid function type in nested call: " func_val)
+    }
+}
+
+# Helper function to check if a value is truthy
+function is_truthy(val) {
+    if (val == "B:0" || val == "#f") {
+        return 0
+    }
+    return 1
+}
+
+function call_builtin_function_nested(built_in_name) {
+    debug("Calling built-in function in nested context: " built_in_name)
+    
+    if (built_in_name == "add") {
+        add()
+    } else if (built_in_name == "subtract") {
+        subtract()
+    } else if (built_in_name == "multiply") {
+        multiply()
+    } else if (built_in_name == "divide") {
+        divide()
+    } else if (built_in_name == "modulo") {
+        modulo()
+    } else if (built_in_name == "expt") {
+        expt()
+    } else if (built_in_name == "abs") {
+        abs()
+    } else if (built_in_name == "min") {
+        min()
+    } else if (built_in_name == "max") {
+        max()
+    } else if (built_in_name == "add_one") {
+        add_one()
+    } else if (built_in_name == "number_p") {
+        number_p()
+    } else if (built_in_name == "string_p") {
+        string_p()
+    } else if (built_in_name == "boolean_p") {
+        boolean_p()
+    } else if (built_in_name == "symbol_p") {
+        symbol_p()
+    } else if (built_in_name == "zero_p") {
+        zero_p()
+    } else if (built_in_name == "positive_p") {
+        positive_p()
+    } else if (built_in_name == "negative_p") {
+        negative_p()
+    } else {
+        error("Unsupported built-in function in nested call: " built_in_name)
+    }
+}
+
+function call_user_function_nested(func_name, arg) {
+    debug("Calling user function in nested context: " func_name " with arg: " arg)
+    
+    if (!(func_name in FUNCTIONS)) {
+        error("Undefined user function: " func_name)
+    }
+    
+    # Get function code
+    split(FUNCTIONS[func_name], code_lines, "\n")
+    
+    # Check if this is a parameterized function
+    if (code_lines[1] ~ /^STORE /) {
+        # This is a parameterized function (lambda)
+        param_name = substr(code_lines[1], 7)
+        debug("Found parameter name: " param_name)
+        
+        # Create new environment frame
+        debug("Creating new environment frame at size: " env_size)
+        env_name[env_size] = param_name
+        env_val[env_size] = arg
+        env_size++
+        debug("FUNCTION_ENV_STORE: " param_name " = " arg " at index " (env_size-1))
+        
+        # Execute function code directly, skipping STORE and POP_ENV instructions
+        for (j = 2; j <= length(code_lines); j++) {
+            if (code_lines[j] != "" && code_lines[j] != "POP_ENV") {
+                debug("Executing function instruction: " code_lines[j])
+                execute(code_lines[j])
+            }
+        }
+        
+        # Clean up parameter
+        vm_pop_env()
+    } else {
+        # This is a non-parameterized function
+        debug("Calling non-parameterized function: " func_name)
+        
+        # Push argument for non-parameterized functions
+        push(arg)
+        
+        # Execute all function code directly
+        for (j in code_lines) {
+            if (code_lines[j] != "") {
+                debug("Executing function instruction: " code_lines[j])
+                execute(code_lines[j])
+            }
+        }
+    }
+}
+
+function call_closure_nested(closure_val, arg) {
+    debug("Calling closure in nested context: " closure_val " with arg: " arg)
+    
+    # Extract closure information
+    closure_func = getClosureFunction(closure_val)
+    closure_env_id = getClosureEnvId(closure_val)
+    
+    debug("Closure function: " closure_func " env_id: " closure_env_id)
+    
+    if (!(closure_func in FUNCTIONS)) {
+        error("Undefined closure function: " closure_func)
+    }
+    
+    # Save current environment state
+    saved_env_size = env_size
+    
+    # Restore the captured environment
+    pushClosureEnvironment(closure_env_id)
+    
+    # Now call the user function with the restored environment
+    call_user_function_nested(closure_func, arg)
+    
+    # Restore original environment (closure environment is automatically cleaned up)
+    # Note: We don't need to explicitly restore since the nested call context handles this
 }
\ No newline at end of file
diff --git a/awk/scheme/scheme/diagram.md b/awk/scheme/scheme/diagram.md
index 689a44a..cbd39e2 100644
--- a/awk/scheme/scheme/diagram.md
+++ b/awk/scheme/scheme/diagram.md
@@ -1,68 +1,41 @@
 # Awk-Scheme Architecture
-## Component Interaction Diagram
+
+## Component Overview
 
 ```
-+----------------+     Scheme Code      +----------------+    Assembly     +----------------+
++----------------+     Scheme Code      +----------------+    Bytecode     +----------------+
 |                | ----------------->   |                | ------------->  |                |
 |      REPL      |   "(+ 1 2)"          |    Compiler    |  "PUSH_CONST    |       VM       |
 |   (bin/repl)   |   "(lambda (x) ...)" | compiler.awk   |   N:1           |    vm.awk      |
 |                |                      |                |   PUSH_CONST    |                |
-|  - Multi-line  |                      | - Lexer        |   N:2           | - Stack-based  |
+|  - Interactive |                      | - Lexer        |   N:2           | - Stack-based  |
 |  - Debug mode  |                      | - Parser       |   ADD           | - Type system  |
 |  - File input  |                      | - Code gen     |   HALT"         | - Environment  |
-|                |                      | - Closure gen  |   CAPTURE_ENV   | - Direct exec  |
+|                |                      | - Closure gen  |                 | - Direct exec  |
 |                | <-----------------   |                | <-------------  |                |
 |                |  Output: "N:3"       |                |   Result        |                |
 +----------------+                      +----------------+                 +----------------+
-       ^                                                                      |
-       |                                                                      v
-       |                                                              +----------------+
-       |                                                              |  Persistence   |
-       |                                                              | /tmp files:    |
-       +--------------------------------------------------------------+ - vm.state     |
-                                                                      | - vm.env       |
-                                                                      +----------------+
-
-Debug Flow (when DEBUG=1):
-+----------------+     Debug Info      +----------------+    Debug Info    +----------------+
-|     REPL       | ----------------->  |   Compiler     | ------------->   |      VM        |
-|                |  [Input received]   |                | [Tokens found]   |                |
-| [Debug output] |                     | [Parsing tree] | [Stack ops]      | [Stack state]  |
-|     stderr     | <-----------------  |  [Gen code]    | [Closure info]   | [Environment]  |
-+----------------+                     +----------------+                  +----------------+
-
-Execution Flow Example:
-┌─────────────┐         ┌─────────────┐         ┌─────────────┐         ┌─────────────┐
-│   Input:    │         │  Lexer/     │         │  Code Gen   │         │     VM      │
-│  (+ 1 2)    │ ------> │  Parser:    │ ------> │ PUSH_CONST  │ ------> │ Stack:      │
-│             │         │  (+         │         │   N:1       │         │  [N:1]      │
-│             │         │   1         │         │ PUSH_CONST  │         │  [N:1,N:2]  │
-│             │         │   2)        │         │   N:2       │         │  [N:3]      │
-│             │         │             │         │ ADD         │         │             │
-└─────────────┘         └─────────────┘         └─────────────┘         └─────────────┘
-
-Closure Flow Example:
-┌─────────────┐         ┌─────────────┐         ┌─────────────┐         ┌─────────────┐
-│   Input:    │         │  Lexer/     │         │  Code Gen   │         │     VM      │
-│(let ((x 10))│ ------->│  Parser:    │ ------> │ STORE x     │ ------> │ Env: [x=10] │
-│  ((lambda   │         │  (let       │         │ LABEL λ     │         │             │
-│   (y) (+ x  │         │   ((x 10))  │         │ CAPTURE_ENV │         │ Closure:    │
-│   y)) 32))) │         │   (lambda   │         │ PUSH_CONST  │         │  λ+env_id   │
-│             │         │    (y) ...) │         │ CLOSURE:... │         │             │
-│             │         │             │         │ CALL        │         │ Result: 42  │
-└─────────────┘         └─────────────┘         └─────────────┘         └─────────────┘
-
-State Management:
-┌─────────────┐         ┌─────────────┐         ┌─────────────┐         ┌─────────────┐
-│   Global    │         │ Environment │         │  Function   │         │  Closure    │
-│  Variables  │ ------> │   Stack     │ ------> │   Calls     │ ------> │ Environment │
-│ (persist)   │         │ (frames)    │         │ (direct)    │         │ (captured)  │
-└─────────────┘         └─────────────┘         └─────────────┘         └─────────────┘
-
-Data Type System:
+```
+
+## Execution Flow
+
+```
+Scheme Code → Compiler → VM Bytecode → Virtual Machine → Result
+     ↓           ↓           ↓              ↓            ↓
+  "(+ 1 2)"   Tokens    PUSH_CONST     Stack: [1]    "N:3"
+              Tree      N:1            Stack: [1,2]   
+                        PUSH_CONST      Stack: [3]
+                        N:2
+                        ADD
+                        HALT
+```
+
+## Data Types
+
+```
 ┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
 │   Numbers   │    │  Booleans   │    │   Symbols   │    │   Closures  │
-│   N:value   │    │   B:value   │    │   S:name    │    │CLOSURE:fn:env_id│
+│   N:value   │    │   B:value   │    │   S:name    │    │CLOSURE:fn:env│
 └─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘
        │                   │                   │                   │
        └───────────────────┼───────────────────┼───────────────────┘
@@ -71,21 +44,73 @@ Data Type System:
                     │    Pairs    │    │     Nil     │
                     │   P:index   │    │    NIL:     │
                     └─────────────┘    └─────────────┘
+                           │                   │
+                           └───────────────────┘
+                    ┌─────────────┐
+                    │   Strings   │
+                    │  STR:content│
+                    └─────────────┘
+```
 
-VM Instruction Set:
-┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
-│   Stack Ops     │    │  Environment    │    │   Functions     │
-│ PUSH_CONST val  │    │ STORE name      │    │ LABEL name      │
-│ POP             │    │ LOOKUP name     │    │ CALL            │
-│ ADD/SUB/MUL/DIV │    │ POP_ENV         │    │ RETURN          │
-│ GET_VALUE       │    │                 │    │                 │
-└─────────────────┘    └─────────────────┘    └─────────────────┘
-         │                       │                       │
-         └───────────────────────┼───────────────────────┘
-                                 │
-                    ┌─────────────────┐
-                    │    Closures     │
-                    │ CAPTURE_ENV fn  │
-                    │ PUSH_CONST      │
-                    │ CLOSURE:fn:env  │
-                    └─────────────────┘
\ No newline at end of file
+## VM Instructions
+
+### Core Operations
+- **Stack**: `PUSH_CONST`, `POP`, `ADD`, `SUB`, `MUL`, `DIV`
+- **Environment**: `STORE`, `LOOKUP`, `POP_ENV`
+- **Functions**: `LABEL`, `CALL`, `RETURN`
+- **Closures**: `CAPTURE_ENV`, `PUSH_CONST CLOSURE:fn:env`
+
+### Example: Lambda Function
+```
+Input: ((lambda (x) (+ x 1)) 41)
+
+Bytecode:
+LABEL __lambda_0
+STORE x
+LOOKUP x
+PUSH_CONST N:1
+ADD
+POP_ENV
+RETURN
+PUSH_CONST N:41
+CALL __lambda_0
+
+Result: N:42
+```
+
+## Standard Library Functions
+
+### Numeric
+- `(+ - * / modulo expt abs min max)`
+- `(zero? positive? negative?)`
+
+### Lists
+- `(cons car cdr length append reverse member)`
+- `(cadr caddr list-ref list-tail null? pair?)`
+
+### Strings
+- `(string-length string-append string-ref substring)`
+- `(string=? string<? string>?)`
+
+### Control Flow
+- `(if cond and or not)`
+
+### Higher-Order
+- `(map filter)` - Support all function types (built-in, lambda, user-defined, closures)
+
+## Forth Implementation
+
+The VM is language-agnostic. Forth compiler generates same bytecode:
+
+```
+Forth: "5 3 + ."
+  ↓
+Bytecode: PUSH_CONST N:5
+          PUSH_CONST N:3
+          ADD
+          PRINT
+          POP
+          HALT
+  ↓
+Result: N:8
+```
\ No newline at end of file
diff --git a/awk/scheme/scheme/examples/cons.test.scm b/awk/scheme/scheme/examples/cons.test.scm
deleted file mode 100644
index d1e3847..0000000
--- a/awk/scheme/scheme/examples/cons.test.scm
+++ /dev/null
@@ -1,3 +0,0 @@
-(cons (+ 1 2)
-      (cons (* 3 4)
-            nil))
diff --git a/awk/scheme/scheme/examples/define.test.scm b/awk/scheme/scheme/examples/define.test.scm
deleted file mode 100644
index ec66b04..0000000
--- a/awk/scheme/scheme/examples/define.test.scm
+++ /dev/null
@@ -1,2 +0,0 @@
-(define add2 (x) (+ x 2))
-(add2 40) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/examples/lambda.test.scm b/awk/scheme/scheme/examples/lambda.test.scm
deleted file mode 100644
index 1f2bb09..0000000
--- a/awk/scheme/scheme/examples/lambda.test.scm
+++ /dev/null
@@ -1,12 +0,0 @@
-; Test lambda function support
-((lambda (x) (+ x 1)) 41)  ; Should return 42
-
-; Test lambda with multiple parameters
-((lambda (x y) (+ x y)) 20 22)  ; Should return 42
-
-; Test lambda in let expression
-(let ((add1 (lambda (x) (+ x 1))))
-  (add1 41))  ; Should return 42
-
-; Test nested lambda
-((lambda (x) ((lambda (y) (+ x y)) 1)) 41)  ; Should return 42 
\ No newline at end of file
diff --git a/awk/scheme/scheme/examples/let-and-define.test.scm b/awk/scheme/scheme/examples/let-and-define.test.scm
deleted file mode 100644
index fade30b..0000000
--- a/awk/scheme/scheme/examples/let-and-define.test.scm
+++ /dev/null
@@ -1,9 +0,0 @@
-; Let expression example
-(let ((x 5) (y 3))
-  (+ x y))
-
-; Function definition example
-(define add2 (x)
-  (+ x 2))
-
-(add2 40)  ; Returns 42
\ No newline at end of file
diff --git a/awk/scheme/scheme/examples/let.test.scm b/awk/scheme/scheme/examples/let.test.scm
deleted file mode 100644
index 2cdc3b8..0000000
--- a/awk/scheme/scheme/examples/let.test.scm
+++ /dev/null
@@ -1,2 +0,0 @@
-(let ((x 5))
-  (+ x 2))
diff --git a/awk/scheme/scheme/scratch/OUTLINE.md b/awk/scheme/scheme/scratch/OUTLINE.md
new file mode 100644
index 0000000..073afef
--- /dev/null
+++ b/awk/scheme/scheme/scratch/OUTLINE.md
@@ -0,0 +1,372 @@
+# Blog Post Outline: "I Built a Scheme VM in AWK and It's Surprisingly Not Terrible"
+
+## Introduction
+- Hook: "What do you get when you cross a functional programming language with a text processing tool from the 1970s?"
+- Brief context: My journey from JS/functional programming to AWK/compilers/VMs
+- Thesis: Building a Scheme VM in AWK taught me more about language design than I expected, and it evolved into a surprisingly capable system
+
+## The Setup: Why AWK? (And Why Not?)
+- The initial reaction: "AWK? Really?"
+- What AWK actually is: a text processing language with some surprising features
+- The appeal: simple, ubiquitous, built-in associative arrays
+- The challenges: 1-indexed strings, weird syntax, limited data structures
+- The realization: AWK is basically a functional language in disguise
+
+## Architecture Overview: The Three-Layer Cake
+- **Layer 1: The Compiler** (`bin/compiler.awk`)
+  - Takes Scheme expressions, outputs VM bytecode
+  - Recursive descent parsing (because AWK doesn't have fancy parser generators)
+  - The joy of implementing `car` and `cdr` in a language that doesn't have lists
+  - Error detection for incomplete expressions (because debugging is hard enough)
+
+- **Layer 2: The Virtual Machine** (`bin/vm.awk`)
+  - Stack-based execution (because registers are hard)
+  - Type system with tagged values (`N:5`, `B:1`, `P:42`)
+  - Environment management for lexical scoping
+  - The weirdness of implementing closures in AWK
+  - Higher-order functions with nested call support (because functional programming is fun)
+
+- **Layer 3: The REPL** (`bin/repl`)
+  - Interactive development (because who doesn't love a good REPL?)
+  - State persistence between sessions
+  - The challenge of making AWK feel interactive
+
+## The Evolution: From Simple Interpreter to Language-Agnostic VM
+
+### The Early Days: Basic Scheme
+- Started with simple arithmetic and basic functions
+- The joy of getting `(+ 1 2)` to work
+- Why stack-based execution made sense in AWK
+- The challenge of implementing lists with cons cells
+
+### The Middle Phase: Functions and Closures
+- Adding user-defined functions (because Scheme needs functions)
+- Implementing closures (because lexical scoping is important)
+- The complexity of environment management in AWK
+- Why capturing environments was harder than expected
+
+### The Current State: Higher-Order Functions and Multi-Language Support
+- Adding `map` and `filter` with full function support
+- The nested function call system (because higher-order functions need to call other functions)
+- The Forth compiler experiment (because why not?)
+- Proving the VM is truly language-agnostic
+
+## The Weirdness: AWK Quirks That Made Me Question My Life Choices
+
+### 1-Indexed Everything
+- Strings, arrays, everything starts at 1
+- The constant `substr(string, 1, index(string, ":") - 1)` dance
+- Why `substr()` needs explicit length but `index()` returns 1-indexed positions
+- The mental gymnastics of converting between 0-indexed and 1-indexed
+
+### Associative Arrays (The Good Part)
+- AWK's killer feature: built-in hash maps
+- How we use them for environments, function tables, closures
+- The joy of `array[key] = value` without any setup
+- The weirdness of `for (key in array)` syntax
+
+### String Manipulation: A Love-Hate Relationship
+- `gsub()` for global substitution (like `replaceAll()`)
+- `sub()` for single substitution
+- The regex syntax that looks like it's from another planet
+- Why string concatenation is just space-separation
+
+### File I/O: The AWK Way
+- `getline` for reading files (returns 1/0/-1, not the data)
+- `printf` with `>` for writing files
+- The weirdness of `close()` being explicit
+- State persistence using simple text files
+
+## The Compiler: From Scheme to Bytecode
+
+### Lexical Analysis: Tokenizing in AWK
+- How we split Scheme expressions into tokens
+- Handling parentheses, strings, numbers, symbols
+- The challenge of nested expressions
+- Why we need to track string literals to avoid paren confusion
+
+### Parsing: Recursive Descent in AWK
+- Implementing a parser without parser generators
+- The beauty of recursive functions in AWK
+- How we handle function calls, special forms, literals
+- The joy of implementing `if` and `cond` without proper control flow
+- Error detection for incomplete expressions (because users make mistakes)
+
+### Code Generation: From AST to Bytecode
+- The instruction set: `PUSH_CONST`, `ADD`, `CALL`, `HALT`
+- How we generate stack-based code
+- The challenge of variable scoping
+- Why function calls are just `CALL` instructions
+
+## The Virtual Machine: Stack-Based Execution
+
+### The Stack: Our Best Friend
+- Simple stack operations: `push()`, `pop()`, `peek()`
+- How everything becomes stack manipulation
+- The beauty of stack-based execution
+- Why we don't need registers (much)
+
+### Type System: Tagged Values
+- Every value is `type:value` (e.g., `N:5`, `B:1`)
+- Runtime type checking with `getType()` and `getValue()`
+- The challenge of implementing lists with cons cells
+- Why we need a heap for complex data structures
+
+### Environment Management: Lexical Scoping in AWK
+- How we implement variable bindings
+- Environment frames for function calls
+- The complexity of closures
+- Why capturing environments is harder than it looks
+
+### Function Calls: The Magic
+- Built-in functions vs user-defined functions
+- How we handle function lookup and execution
+- The challenge of parameter passing
+- Why `CALL` is more complex than it seems
+
+### Higher-Order Functions: The Real Magic
+- How `map` and `filter` work with any function type
+- The nested function call system
+- Why calling functions from within functions is tricky
+- The joy of data transformation pipelines
+
+## The Forth Experiment: Proving Language Agnosticism
+
+### The Original Approach: Forth → Scheme → VM
+- Translating Forth to Scheme expressions
+- Using the existing compiler pipeline
+- Why this felt like cheating
+
+### The Real Deal: Forth → VM Directly
+- Building a Forth compiler that generates bytecode
+- The joy of `PUSH_CONST N:5` and `ADD`
+- Proving the VM is truly language-agnostic
+- Why this is the real achievement
+
+### The Insight: Universal VM Target
+- Any language can target this VM
+- The same bytecode from different sources
+- Why this matters for language design
+- The power of a well-designed instruction set
+
+## The Testing Journey: From Chaos to Order
+
+### The Early Days: Manual Testing
+- Running expressions by hand
+- The pain of debugging without proper tests
+- Why testing is crucial even for small projects
+
+### The Evolution: Comprehensive Test Suite
+- 48 unit tests covering all features
+- Integration tests for complex scenarios
+- Regression tests to prevent bugs
+- Examples that demonstrate usage
+
+### The Test Runner: Making Testing Easy
+- Automated test execution
+- Clear pass/fail reporting
+- Error detection and reporting
+- Why good tooling matters
+
+## The REPL: Making AWK Interactive
+
+### State Persistence: Between Sessions
+- Saving function definitions to files
+- Loading state on startup
+- The simplicity of text-based persistence
+- Why we don't need a database
+
+### Interactive Development: The AWK Way
+- Reading input line by line
+- Compiling and executing each expression
+- The challenge of maintaining state
+- Why the REPL feels surprisingly natural
+
+## Lessons Learned: What AWK Taught Me About Language Design
+
+### Simplicity is Powerful
+- AWK's simple model enables complex things
+- How constraints lead to creativity
+- Why less is often more in language design
+
+### Stack-Based Execution is Beautiful
+- The elegance of stack operations
+- How it simplifies the VM
+- Why many real VMs use this approach
+
+### Type Systems Matter
+- Runtime type checking prevents bugs
+- Tagged values enable safe operations
+- Why type safety is worth the overhead
+
+### Environment Management is Hard
+- Lexical scoping requires careful implementation
+- Closures add significant complexity
+- Why proper scoping is crucial for functional languages
+
+### Higher-Order Functions are Worth It
+- The power of function composition
+- How data transformation becomes elegant
+- Why functional programming patterns matter
+
+### Language Agnosticism is Achievable
+- A well-designed VM can support multiple languages
+- The benefits of shared runtime and standard library
+- Why this approach reduces implementation complexity
+
+## The Weirdest Parts: AWK Quirks That Made Me Laugh/Cry
+
+### The 1-Indexed String Functions
+- `substr(string, 1, length)` vs `string.slice(0, length)`
+- The constant mental conversion
+- Why this exists and how to cope
+
+### Associative Array Syntax
+- `array[key] = value` without declaration
+- The joy of `for (key in array)`
+- Why this is AWK's best feature
+
+### File I/O Patterns
+- `getline` returning status codes
+- The explicit `close()` requirement
+- Why AWK's I/O model is actually quite elegant
+
+### String Manipulation
+- `gsub()` and `sub()` for regex replacement
+- The regex syntax that looks alien
+- Why AWK's string handling is powerful but weird
+
+## Performance and Limitations: The Reality Check
+
+### What Works Well
+- Simple expressions compile and run quickly
+- The REPL is responsive
+- State persistence works reliably
+- The type system prevents many bugs
+- Higher-order functions work smoothly
+- The test suite catches regressions
+
+### What's Slow/Weird
+- Complex expressions can be slow
+- Memory usage with large programs
+- The 1-indexed string operations
+- Limited data structures beyond arrays
+- No tail call optimization
+
+### The AWK Tax
+- Everything is string-based under the hood
+- No native data structures beyond arrays
+- Limited control flow constructs
+- The constant string manipulation overhead
+
+## The Current State: A Surprisingly Capable System
+
+### What We Have
+- Full Scheme interpreter with higher-order functions
+- Language-agnostic VM with Forth support
+- Comprehensive test suite (48 tests)
+- Interactive REPL with state persistence
+- Error detection and reporting
+- Standard library with 50+ functions
+
+### What Makes It Special
+- Built entirely in AWK (no external dependencies)
+- Supports complex functional programming patterns
+- Language-agnostic VM design
+- Comprehensive testing and documentation
+- Clean, maintainable architecture
+
+### The Numbers
+- ~3,900 lines of AWK code
+- 48 unit tests + integration/regression tests
+- 50+ standard library functions
+- 2 target languages (Scheme, Forth)
+- 0 external dependencies
+
+## Conclusion: Was It Worth It?
+
+### The Unexpected Benefits
+- Deep understanding of VM architecture
+- Appreciation for language design decisions
+- The joy of building something from scratch
+- Why constraints breed creativity
+- The power of comprehensive testing
+
+### The AWK Revelation
+- AWK is more powerful than it looks
+- Functional programming concepts work everywhere
+- Simple tools can build complex systems
+- Why the Unix philosophy matters
+
+### The Bigger Picture
+- How this relates to real VMs (JVM, .NET, etc.)
+- The universality of stack-based execution
+- Why language-agnostic VMs are powerful
+- The future of language design
+
+### Final Thoughts
+- "I built a Scheme VM in AWK and it's surprisingly not terrible"
+- The value of building things in unexpected languages
+- Why understanding the fundamentals matters
+- The joy of programming for its own sake
+- How constraints can lead to better design
+
+## Technical Appendix: Key Code Snippets
+
+### The VM's Main Loop
+```awk
+while (pc < length(program)) {
+    execute(program[pc++])
+}
+```
+
+### Type System Implementation
+```awk
+function makeValue(type, val) {
+    return type ":" val
+}
+```
+
+### Stack Operations
+```awk
+function push(val) {
+    stack[++stack_ptr] = val
+}
+```
+
+### Higher-Order Functions
+```awk
+function stdlib_map() {
+    # Get function and list from stack
+    func = pop()
+    list = pop()
+    # Call function for each element
+    result = execute_nested_function_call(func, element)
+}
+```
+
+### The Forth Compiler
+```awk
+if (token ~ /^-?[0-9]+$/) {
+    bytecode = bytecode "PUSH_CONST N:" token "\n"
+} else if (token == "+") {
+    bytecode = bytecode "ADD\n"
+}
+```
+
+### Error Detection
+```awk
+if (paren_count > 0) {
+    error("Unmatched opening parentheses - incomplete expression")
+}
+```
+
+## Resources and Further Reading
+- AWK documentation and tutorials
+- Scheme language specification
+- Virtual machine design principles
+- Stack-based execution models
+- Language implementation techniques
+- Functional programming concepts
+- Higher-order functions and closures
+- Language-agnostic VM design 
\ No newline at end of file
diff --git a/awk/scheme/scheme/scratch/arch-notes.md b/awk/scheme/scheme/scratch/arch-notes.md
index 060ca72..bb2e240 100644
--- a/awk/scheme/scheme/scratch/arch-notes.md
+++ b/awk/scheme/scheme/scratch/arch-notes.md
@@ -1,7 +1,7 @@
 # Awk-Scheme: Architectural Notes
 
 ## Overview
-Awk-Scheme is a minimal Scheme interpreter implemented in AWK, composed of a compiler and a stack-based virtual machine (VM). The architecture is modular, with clear separation of concerns between parsing/compilation and execution. The design leverages several classic architectural patterns to achieve extensibility, maintainability, and clarity.
+A little Scheme interpreter implemented in AWK, composed of a compiler and a stack-based virtual machine. The architecture seeks to be modular, with clear separation of concerns between parsing/compilation and execution. The system has evolved to support higher-order functions, nested function calls, and language-agnostic VM design with Forth as a second target language.
 
 ---
 
@@ -10,6 +10,7 @@ Awk-Scheme is a minimal Scheme interpreter implemented in AWK, composed of a com
 1. **Input**: User provides Scheme code (via REPL or file).
 2. **Compilation**: The compiler (`bin/compiler.awk`) parses and compiles Scheme code into VM instructions.
 3. **Execution**: The VM (`bin/vm.awk`) executes the instructions, managing state, environment, and memory.
+4. **Output**: Results are displayed via the `display` function or returned as typed values.
 
 ---
 
@@ -18,22 +19,32 @@ Awk-Scheme is a minimal Scheme interpreter implemented in AWK, composed of a com
 ### 2.1. Lexical Analysis (Lexer)
 - **Pattern**: *Lexer/Parser Separation* (classic compiler front-end)
 - **Why**: Decouples tokenization from parsing, making the code easier to reason about and extend.
-- **How**: The compiler tokenizes input into numbers, symbols, and parentheses, handling whitespace and comments.
+- **How**: The compiler tokenizes input into numbers, symbols, strings, and parentheses, handling whitespace and comments with proper string literal recognition.
 
 ### 2.2. Parsing (Recursive Descent)
 - **Pattern**: *Recursive Descent Parser*
 - **Why**: Simple, direct mapping from grammar to code; easy to debug and extend for a small language.
-- **How**: The parser builds an expression tree from tokens, handling nested expressions and validating syntax.
+- **How**: The parser builds an expression tree from tokens, handling nested expressions, string literals, and validating syntax with proper parenthesis matching and error detection for incomplete expressions.
 
 ### 2.3. Code Generation
 - **Pattern**: *Visitor/Dispatcher* (for expression types)
-- **Why**: Each expression type (number, variable, list, special form) is handled by a dedicated function, improving maintainability.
-- **How**: The compiler emits stack-based VM instructions for each expression, handling special forms (define, let, lambda) and function calls.
+- **Why**: Each expression type (number, variable, list, special form, string) is handled by a dedicated function, improving maintainability.
+- **How**: The compiler emits stack-based VM instructions for each expression, handling special forms (define, let, lambda) and function calls with proper argument validation.
 
-### 2.4. Closure Support
+### 2.4. Primitive Function Handling
+- **Pattern**: *Strategy Pattern* (for different function types)
+- **Why**: Different functions require different compilation strategies - some are built-in primitives, others are standard library functions, and some are user-defined.
+- **How**: The compiler uses explicit dispatch in `compile_primitive_call()` to handle arithmetic operations, list operations, string operations, and standard library functions with appropriate argument validation.
+
+### 2.5. Closure Support
 - **Pattern**: *Closure Conversion* (from functional programming)
 - **Why**: Enables lexical scoping and first-class functions by capturing the environment at lambda creation.
-- **How**: The compiler emits instructions to capture the current environment and create closure objects.
+- **How**: The compiler emits `CAPTURE_ENV` instructions to capture the current environment and create closure objects with unique environment IDs.
+
+### 2.6. Error Detection
+- **Pattern**: *Fail-Fast Error Detection*
+- **Why**: Early detection of syntax errors prevents runtime issues and improves debugging.
+- **How**: The compiler validates parenthesis matching and detects incomplete expressions during parsing, providing clear error messages.
 
 ---
 
@@ -42,74 +53,229 @@ Awk-Scheme is a minimal Scheme interpreter implemented in AWK, composed of a com
 ### 3.1. Stack-Based Execution
 - **Pattern**: *Stack Machine* (classic VM design)
 - **Why**: Simplicity and direct mapping from compiled instructions to execution; easy to implement in AWK.
-- **How**: The VM maintains an evaluation stack for operands and results, executing instructions sequentially.
+- **How**: The VM maintains an evaluation stack for operands and results, executing instructions sequentially with proper stack management and cleanup.
 
 ### 3.2. Typed Value System
 - **Pattern**: *Tagged Union* (Algebraic Data Type)
 - **Why**: Enables runtime type checking and safe operations on heterogeneous values.
-- **How**: All values are tagged (e.g., `N:`, `B:`, `P:`, `F:`, `CLOSURE:`) and checked at runtime.
+- **How**: All values are tagged (e.g., `N:`, `B:`, `P:`, `F:`, `CLOSURE:`, `STR:`) and checked at runtime with type predicates.
 
 ### 3.3. Environment Model
 - **Pattern**: *Environment Chain* (Lexical Scoping)
-- **Why**: Supports variable bindings, lexical scope, and closures.
-- **How**: The VM maintains an environment stack for variable bindings, with special handling for global and closure environments.
+- **Why**: Supports variable bindings, lexical scope, and closures with proper variable lookup.
+- **How**: The VM maintains an environment stack for variable bindings, with special handling for global and closure environments, including environment restoration for closure calls.
 
 ### 3.4. Function and Closure Handling
 - **Pattern**: *Direct Function Execution* (no program array modification)
 - **Why**: Simplifies call/return logic and avoids mutation of the instruction stream.
-- **How**: Functions are stored as code blocks; calls execute code directly, with environment management for parameters and closures.
+- **How**: Functions are stored as code blocks; calls execute code directly, with environment management for parameters and closures, including proper environment capture and restoration.
+
+### 3.5. Function Dispatch System
+- **Pattern**: *Registry Pattern* (for function lookup)
+- **Why**: Enables efficient function dispatch and supports function aliasing for user convenience.
+- **How**: The VM maintains a `FUNCTIONS` registry mapping function names to implementations, allowing multiple names to point to the same function (e.g., `inc` and `++`).
+
+### 3.6. Variable Argument Functions
+- **Pattern**: *Variadic Function* (for flexible argument handling)
+- **Why**: Enables functions like `string-append` to accept any number of arguments, improving usability.
+- **How**: Functions like `string_append()` process all arguments on the stack using a loop, maintaining proper argument order and type checking.
+
+### 3.7. Higher-Order Functions
+- **Pattern**: *Function as Data* (first-class functions)
+- **Why**: Enables functional programming patterns like `map` and `filter` with user-defined functions, lambdas, and closures.
+- **How**: The VM implements `map` and `filter` functions that can accept any function type (built-in, user-defined, lambda, closure) through a nested function call mechanism.
+
+### 3.8. Nested Function Call System
+- **Pattern**: *Context Preservation* (for nested execution)
+- **Why**: Enables higher-order functions to call other functions while preserving the calling context.
+- **How**: The VM maintains a call stack that saves and restores execution context, allowing functions to be called from within other functions without losing state.
 
-### 3.5. Heap and Memory Management
+### 3.9. Output System
+- **Pattern**: *Visitor Pattern* (for value display)
+- **Why**: Different value types require different display formats, and the display logic should be extensible.
+- **How**: The `display_value()` function recursively visits different value types, converting them to readable string representations with proper list formatting.
+
+### 3.10. Heap and Memory Management
 - **Pattern**: *Manual Heap with Reference Counting (partial)*
-- **Why**: Enables cons cell allocation and basic memory management.
+- **Why**: Enables cons cell allocation and basic memory management for list operations.
 - **How**: The VM allocates cons cells on a heap array, with a placeholder for reference counting (not fully implemented).
 
-### 3.6. State Persistence
+### 3.11. State Persistence
 - **Pattern**: *State Serialization*
-- **Why**: Allows global state and functions to persist across REPL sessions.
-- **How**: The VM serializes global variables and function definitions to files, loading them on startup.
+- **Why**: Allows global state and functions to persist across REPL sessions for continuity.
+- **How**: The VM serializes global variables and function definitions to files, loading them on startup with proper state restoration.
+
+---
+
+## 4. Standard Library Architecture
+
+### 4.1. Function Registration
+- **Pattern**: *Registry Pattern* (for extensible function library)
+- **Why**: Enables easy addition of new standard library functions without modifying core VM logic.
+- **How**: Functions are registered in the `FUNCTIONS` table during VM initialization, with dispatch logic in `vm_call_function()`.
+
+### 4.2. Function Aliasing
+- **Pattern**: *Alias Pattern* (for user convenience)
+- **Why**: Allows multiple names for the same function, improving usability and providing familiar syntax.
+- **How**: Multiple entries in the `FUNCTIONS` table point to the same implementation (e.g., `inc` and `++` both point to `add_one`).
+
+### 4.3. String Operations
+- **Pattern**: *Builder Pattern* (for string construction)
+- **Why**: String operations like concatenation need to handle variable numbers of arguments efficiently.
+- **How**: Functions like `string_append()` build the result incrementally by processing all arguments on the stack in order.
+
+### 4.4. Higher-Order Functions
+- **Pattern**: *Functional Programming Patterns*
+- **Why**: Enables data transformation and filtering with user-defined functions.
+- **How**: `map` and `filter` functions accept any function type and execute them in a nested context, supporting complex data processing pipelines.
+
+---
+
+## 5. Language-Agnostic VM Design
+
+### 5.1. Forth Compiler
+- **Pattern**: *Multi-Language Frontend*
+- **Why**: Demonstrates the VM's language-agnostic nature and validates the instruction set design.
+- **How**: A separate Forth compiler (`scratch/forth/forth.awk`) generates the same VM bytecode, proving that the VM can execute code from different source languages.
+
+### 5.2. Shared Instruction Set
+- **Pattern**: *Universal Bytecode*
+- **Why**: Enables multiple languages to target the same VM, reducing implementation complexity.
+- **How**: Both Scheme and Forth compilers generate identical VM instructions, allowing seamless execution of mixed-language programs.
+
+### 5.3. Standard Library Integration
+- **Pattern**: *Shared Runtime*
+- **Why**: Provides consistent functionality across different source languages.
+- **How**: The VM's standard library functions are available to all languages targeting the VM, ensuring consistent behavior.
+
+---
+
+## 6. Testing Architecture
+
+### 6.1. Comprehensive Test Suite
+- **Pattern**: *Layered Testing Strategy*
+- **Why**: Ensures correctness across different levels of complexity and use cases.
+- **How**: Tests are organized into unit tests (48 tests), integration tests, regression tests, and examples, covering basic operations to complex higher-order function scenarios.
+
+### 6.2. Test Organization
+- **Pattern**: *Test Categories*
+- **Why**: Different types of tests serve different purposes in validation.
+- **How**: Unit tests focus on individual features, integration tests validate complex interactions, regression tests prevent regressions, and examples demonstrate usage patterns.
+
+### 6.3. Error Detection Testing
+- **Pattern**: *Negative Testing*
+- **Why**: Ensures the system properly handles and reports errors.
+- **How**: Tests include syntax error detection, type checking, and edge cases to validate error handling behavior.
 
 ---
 
-## 4. Extensibility and Maintainability
-- **Pattern**: *Separation of Concerns*
+## 7. Extensibility and Maintainability
+
+### 7.1. Separation of Concerns
+- **Pattern**: *Layered Architecture*
 - **Why**: Compiler and VM are independent, making it easy to extend the language or change the execution model.
-- **Pattern**: *Table-Driven Dispatch* (for built-in functions)
-- **Why**: Adding new primitives or special forms is straightforward.
+- **How**: Clear interfaces between compilation and execution phases, with well-defined instruction formats.
+
+### 7.2. Function Extension
+- **Pattern**: *Open/Closed Principle* (open for extension, closed for modification)
+- **Why**: Adding new functions should not require changes to existing code.
+- **How**: New functions are added by registering them in the `FUNCTIONS` table and implementing the corresponding VM function.
+
+### 7.3. Error Handling
+- **Pattern**: *Fail-Fast* (for debugging)
+- **Why**: Early error detection helps identify issues quickly during development.
+- **How**: Functions validate arguments and types at runtime, throwing descriptive error messages.
+
+### 7.4. Language Extension
+- **Pattern**: *Plugin Architecture* (for new languages)
+- **Why**: Enables new languages to target the VM without modifying existing code.
+- **How**: New language compilers can be added as separate modules that generate the same VM bytecode.
 
 ---
 
-## 5. Notable Limitations
-- No support for nested lambdas (yet), proper tail recursion, or garbage collection.
-- Reference counting is stubbed but not enforced.
-- Error handling is minimal.
+## 8. Notable Limitations and Future Enhancements
+
+### 8.1. Current Limitations
+- **Tail Recursion**: No proper tail call optimization
+- **Garbage Collection**: Reference counting is stubbed but not enforced
+- **Error Recovery**: Minimal error recovery in REPL
+- **Type System**: Basic runtime type checking only
+- **Performance**: Limited optimization for complex expressions
+
+### 8.2. Architectural Patterns for Future Enhancements
+- **Continuation-Passing Style**: For proper tail recursion
+- **Generational Garbage Collection**: For memory management
+- **Exception Handling**: For better error recovery
+- **Type Inference**: For compile-time type checking
+- **JIT Compilation**: For performance optimization
 
 ---
 
-## 6. Summary Table: Patterns Used
+## 9. Summary Table: Patterns Used
 
 | Area                | Pattern(s) Used                  | Why?                                 |
 |---------------------|----------------------------------|--------------------------------------|
 | Lexing/Parsing      | Lexer/Parser, Recursive Descent  | Simplicity, extensibility            |
-| Code Generation     | Visitor/Dispatcher               | Maintainability, clarity             |
+| Code Generation     | Visitor/Dispatcher, Strategy     | Maintainability, clarity             |
 | VM Execution        | Stack Machine, Tagged Union      | Simplicity, type safety              |
 | Environment         | Environment Chain, Closure Conv. | Lexical scoping, closures            |
-| Function Dispatch   | Table-Driven Dispatch            | Extensibility                        |
+| Function Dispatch   | Registry Pattern, Alias Pattern  | Extensibility, usability             |
+| String Operations   | Builder Pattern, Variadic Func.  | Flexibility, user experience         |
+| Output System       | Visitor Pattern                  | Extensibility, type-specific display |
 | State Persistence   | State Serialization              | REPL continuity                      |
 | Memory Management   | Manual Heap, Ref Counting (stub) | List support, future GC              |
+| Error Handling      | Fail-Fast                        | Debugging, development               |
+| Higher-Order Funcs  | Function as Data, Context Pres.  | Functional programming support       |
+| Multi-Language      | Universal Bytecode, Shared Runtime| Language agnosticism                 |
+| Testing             | Layered Testing, Test Categories | Comprehensive validation             |
 
 ---
 
-## 7. Architectural Choices: Rationale
+## 10. Architectural Choices: Rationale
+
+### 10.1. Language Choice
 - **AWK as Implementation Language**: Chosen for portability and as a challenge; influences the use of arrays and string-based data structures.
+- **Why**: AWK's built-in associative arrays and string manipulation capabilities map well to the VM's needs.
+
+### 10.2. VM Design
 - **Stack Machine**: Maps well to AWK's capabilities and keeps the VM simple.
+- **Why**: Stack operations are straightforward to implement in AWK and provide clear semantics.
+
+### 10.3. Modularity
 - **Separation of Compiler/VM**: Enables clear boundaries and easier debugging.
+- **Why**: Independent development and testing of compilation and execution phases.
+
+### 10.4. Type System
 - **Explicit Typing**: Reduces runtime errors and clarifies value handling.
+- **Why**: Tagged values provide runtime safety and clear debugging information.
+
+### 10.5. Language Agnosticism
+- **Universal VM Target**: Enables multiple languages to share the same runtime.
+- **Why**: Reduces implementation complexity and enables language experimentation.
 
 ---
 
-## 8. Flow Diagram (Textual)
+## 11. Flow Diagram (Textual)
 
 ```
-User Input (Scheme) → [Compiler] → VM Instructions → [VM] → Result/State
-```
\ No newline at end of file
+User Input (Scheme/Forth) → [Compiler] → VM Instructions → [VM] → Result/State
+                                                              ↓
+                                                      [Display/Output]
+```
+
+## 12. Key Architectural Insights
+
+### 12.1. Pattern Composition
+The system demonstrates how classic architectural patterns can be composed to create a functional interpreter. The combination of Registry, Visitor, and Strategy patterns enables extensibility while maintaining simplicity.
+
+### 12.2. AWK-Specific Adaptations
+The patterns are adapted to AWK's strengths: associative arrays for registries, string manipulation for value representation, and procedural programming for the VM loop.
+
+### 12.3. Extensibility Through Registration
+The function registration system demonstrates how a simple registry pattern can enable significant extensibility without complex inheritance hierarchies or plugin systems.
+
+### 12.4. Language Agnosticism
+The VM's language-agnostic design demonstrates how a well-designed instruction set can support multiple source languages, enabling experimentation and reducing implementation complexity.
+
+### 12.5. Higher-Order Function Support
+The nested function call system shows how complex functional programming features can be implemented in a simple stack-based VM, enabling powerful data transformation capabilities.
\ No newline at end of file
diff --git a/awk/scheme/scheme/scratch/complex_test.scm.asm b/awk/scheme/scheme/scratch/complex_test.scm.asm
deleted file mode 100644
index 67870c3..0000000
--- a/awk/scheme/scheme/scratch/complex_test.scm.asm
+++ /dev/null
@@ -1,44 +0,0 @@
-# Test proper list construction (3 2 1)
-# Building the list in proper order: car points to value, cdr points to next pair
-
-# Start with empty list
-PUSH_CONST NIL:           # [nil]
-PRINT                     # Print nil
-
-# Build (1 . nil)
-PUSH_CONST NIL:          # [nil]
-PUSH_CONST N:1          # [nil 1]
-SWAP                    # [1 nil]
-CONS                    # [(1 . nil)]
-DUP
-PRINT                   # Print (1 . nil)
-
-# Build (2 . (1 . nil))
-PUSH_CONST N:2         # [(1.nil) 2]
-SWAP                   # [2 (1.nil)]
-CONS                   # [(2 . (1.nil))]
-DUP
-PRINT                  # Print (2 . (1.nil))
-
-# Build (3 . (2 . (1 . nil)))
-PUSH_CONST N:3        # [(2.(1.nil)) 3]
-SWAP                  # [3 (2.(1.nil))]
-CONS                  # [(3 . (2.(1.nil)))]
-DUP
-PRINT                 # Print full structure
-
-# Test CAR/CDR operations
-DUP                   # Keep a copy of the list for later
-DUP                   # Another copy for CAR
-CAR                   # Get first element (3)
-PRINT                 # Should print 3
-
-SWAP                  # Bring back our spare list copy
-CDR                   # Get rest of list ((2 . (1 . nil)))
-DUP
-PRINT                 # Print rest of list
-
-CAR                   # Get first of rest (2)
-PRINT                 # Should print 2
-
-HALT
\ No newline at end of file
diff --git a/awk/scheme/scheme/scratch/forth/README.md b/awk/scheme/scheme/scratch/forth/README.md
new file mode 100644
index 0000000..db1d1fe
--- /dev/null
+++ b/awk/scheme/scheme/scratch/forth/README.md
@@ -0,0 +1,139 @@
+# FORTH Compiler for Awk-Scheme VM
+
+## What This Is
+
+This is a **Forth compiler** that generates bytecode for the Awk-Scheme VM directly, without any modifications to the VM itself.
+
+## What It Demonstrates
+
+This proves that your VM is **truly language-agnostic**. The VM doesn't know or care whether the bytecode came from:
+
+- The Scheme compiler
+- This Forth compiler
+- Any other language compiler
+
+## Key Insight
+
+Both approaches generate the **exact same bytecode**:
+
+```
+Forth: 5 3 +
+  ↓ (direct compilation)
+VM: PUSH_CONST N:5
+    PUSH_CONST N:3
+    ADD
+    HALT
+```
+
+The VM executes this bytecode identically regardless of the source language!
+
+## Architecture Benefits
+
+1. **No VM modifications required** - The VM remains unchanged
+2. **Language independence** - Any language can target this VM
+3. **Shared runtime** - All languages benefit from the same VM optimizations
+4. **Consistent semantics** - All languages get the same type system and memory management
+5. **Easy to extend** - Adding new languages just requires new compilers
+
+## How It Works
+
+The `forth_compiler` program:
+
+1. **Parses Forth expressions** into tokens
+2. **Generates VM bytecode directly** for each token
+3. **Executes the bytecode** using the existing VM
+4. **Displays results** from the VM
+
+## Supported Forth Words
+
+### Basic Arithmetic
+- `+` - Addition
+- `-` - Subtraction  
+- `*` - Multiplication
+- `/` - Division
+
+### Advanced Math (using VM standard library)
+- `abs` - Absolute value
+- `mod` - Modulo operation
+- `min` - Minimum of two numbers
+- `max` - Maximum of two numbers
+
+### Type Predicates (using VM standard library)
+- `zero?` - Check if top of stack is zero
+- `positive?` - Check if top of stack is positive
+- `negative?` - Check if top of stack is negative
+- `number?` - Check if top of stack is a number
+
+### Stack Operations
+- `.` - Print top of stack
+- `cr` - Print newline
+- `dup` - Duplicate top of stack
+- `swap` - Swap top two elements
+- `drop` - Drop top of stack
+- `2drop` - Drop top two elements
+
+### List Operations
+- `cons` - Create cons cell
+- `car` - Get car of cons cell
+- `cdr` - Get cdr of cons cell
+
+### Logic Operations
+- `=` - Equality comparison
+- `<` - Less than comparison
+- `>` - Greater than comparison
+- `not` - Logical NOT
+
+### System
+- `words` - List all available words
+- `bye` - Exit the Forth interpreter
+
+## Testing
+
+```bash
+# Basic arithmetic
+echo "5 3 +" | ./scratch/forth/forth.awk
+
+# Advanced math using VM standard library
+echo "-5 abs ." | ./scratch/forth/forth.awk
+echo "17 5 mod ." | ./scratch/forth/forth.awk
+echo "10 3 min ." | ./scratch/forth/forth.awk
+
+# Type predicates
+echo "0 zero? ." | ./scratch/forth/forth.awk
+echo "5 positive? ." | ./scratch/forth/forth.awk
+echo "-3 negative? ." | ./scratch/forth/forth.awk
+
+# Stack manipulation
+echo "5 dup * ." | ./scratch/forth/forth.awk
+echo "10 20 swap . ." | ./scratch/forth/forth.awk
+
+# List operations
+echo "1 2 cons car ." | ./scratch/forth/forth.awk
+```
+
+## What This Proves
+
+This implementation demonstrates several important architectural principles:
+
+### 1. Language Agnosticism
+The VM is completely indifferent to the source language. It only cares about the bytecode format.
+
+### 2. Compiler Independence
+Different languages can have completely different compilers that all target the same VM.
+
+### 3. Shared Runtime Benefits
+All languages get the same:
+- Type system
+- Memory management
+- Error handling
+- Performance characteristics
+- Debugging capabilities
+
+### 4. Extensibility
+Adding a new language is as simple as writing a new compiler that generates the right bytecode.
+
+## Conclusion
+
+This proves your VM design is successful as a **universal target** for multiple languages. The VM is the common denominator - a pure execution engine that can run bytecode from any language that targets its instruction set.
+
+This is exactly the kind of flexibility and language-agnostic design that makes a VM architecture powerful! 
\ No newline at end of file
diff --git a/awk/scheme/scheme/scratch/forth/forth.awk b/awk/scheme/scheme/scratch/forth/forth.awk
new file mode 100755
index 0000000..618f4d5
--- /dev/null
+++ b/awk/scheme/scheme/scratch/forth/forth.awk
@@ -0,0 +1,249 @@
+#!/usr/bin/awk -f
+
+# Forth-to-VM Compiler for VM Validation
+# 
+# This compiler translates Forth expressions to VM bytecode, validating
+# the VM implementation by testing individual operations.
+#
+# Architecture:
+# - Forth-to-VM compiler that generates VM instructions
+# - Uses existing VM to validate instruction execution
+# - Tests individual operations (not a true REPL with persistent stack)
+# - Stack-based operations that validate VM behavior
+#
+# Note: Each line is executed in a separate VM instance, so stack state
+# does not persist between lines. This is a limitation of the current VM
+# design that doesn't impact the scheme implementation, I don't think. 
+
+BEGIN {
+    print "Forth VM Compiler (for VM validation)"
+    print "Type 'bye' to exit, 'words' to see available words"
+    print "Note: Each line runs in a separate VM instance"
+    print "forth> "
+}
+
+# Main input processing loop
+{
+    if ($0 == "bye") {
+        printf("Goodbye!\n")
+        exit
+    } else {
+        # Compile Forth to VM bytecode and execute
+        compile_and_execute($0)
+        printf("forth> ")
+    }
+}
+
+# Compile Forth expression to VM bytecode and execute
+function compile_and_execute(line,   tokens, i, token, bytecode) {
+    split(line, tokens, " ")
+    bytecode = ""
+    
+    for (i = 1; i <= length(tokens); i++) {
+        token = tokens[i]
+        if (token == "") continue
+        
+        if (token ~ /^-?[0-9]+$/) {
+            # Number - push constant
+            bytecode = bytecode "PUSH_CONST N:" token "\n"
+        } else if (token == "+") {
+            # Addition
+            bytecode = bytecode "ADD\n"
+        } else if (token == "-") {
+            # Subtraction
+            bytecode = bytecode "SUB\n"
+        } else if (token == "*") {
+            # Multiplication
+            bytecode = bytecode "MUL\n"
+        } else if (token == "/") {
+            # Division
+            bytecode = bytecode "DIV\n"
+        } else if (token == ".") {
+            # Print top of stack and consume it
+            bytecode = bytecode "PRINT\n"
+            bytecode = bytecode "POP\n"
+        } else if (token == "cr") {
+            # Print newline
+            bytecode = bytecode "PUSH_CONST STR:\\n\n"
+            bytecode = bytecode "PRINT\n"
+        } else if (token == "dup") {
+            # Duplicate top of stack
+            bytecode = bytecode "DUP\n"
+        } else if (token == "swap") {
+            # Swap top two stack elements
+            bytecode = bytecode "SWAP\n"
+        } else if (token == "drop") {
+            # Drop top of stack
+            bytecode = bytecode "POP\n"
+        } else if (token == ".s") {
+            # Show stack contents (non-destructive)
+            bytecode = bytecode "PUSH_CONST STR:Stack: \n"
+            bytecode = bytecode "PRINT\n"
+            bytecode = bytecode "POP\n"
+            # Note: Full stack inspection would require VM support
+        } else if (token == "depth") {
+            # Show stack depth
+            bytecode = bytecode "PUSH_CONST STR:Depth: \n"
+            bytecode = bytecode "PRINT\n"
+            bytecode = bytecode "POP\n"
+            # Note: Stack depth would require VM support
+        } else if (token == "=") {
+            # Equality comparison
+            bytecode = bytecode "EQ\n"
+        } else if (token == "<") {
+            # Less than comparison
+            bytecode = bytecode "LT\n"
+        } else if (token == ">") {
+            # Greater than (implement as swap and less than)
+            bytecode = bytecode "SWAP\n"
+            bytecode = bytecode "LT\n"
+        } else if (token == "not") {
+            # Logical NOT
+            bytecode = bytecode "NOT\n"
+        } else if (token == "abs") {
+            # Absolute value
+            bytecode = bytecode "PUSH_CONST S:abs\n"
+            bytecode = bytecode "LOOKUP abs\n"
+            bytecode = bytecode "GET_VALUE\n"
+            bytecode = bytecode "CALL\n"
+        } else if (token == "mod") {
+            # Modulo operation
+            bytecode = bytecode "PUSH_CONST S:modulo\n"
+            bytecode = bytecode "LOOKUP modulo\n"
+            bytecode = bytecode "GET_VALUE\n"
+            bytecode = bytecode "CALL\n"
+        } else if (token == "min") {
+            # Minimum of two numbers
+            bytecode = bytecode "PUSH_CONST S:min\n"
+            bytecode = bytecode "LOOKUP min\n"
+            bytecode = bytecode "GET_VALUE\n"
+            bytecode = bytecode "CALL\n"
+        } else if (token == "max") {
+            # Maximum of two numbers
+            bytecode = bytecode "PUSH_CONST S:max\n"
+            bytecode = bytecode "LOOKUP max\n"
+            bytecode = bytecode "GET_VALUE\n"
+            bytecode = bytecode "CALL\n"
+        } else if (token == "zero?") {
+            # Check if top of stack is zero
+            bytecode = bytecode "PUSH_CONST S:zero?\n"
+            bytecode = bytecode "LOOKUP zero?\n"
+            bytecode = bytecode "GET_VALUE\n"
+            bytecode = bytecode "CALL\n"
+        } else if (token == "positive?") {
+            # Check if top of stack is positive
+            bytecode = bytecode "PUSH_CONST S:positive?\n"
+            bytecode = bytecode "LOOKUP positive?\n"
+            bytecode = bytecode "GET_VALUE\n"
+            bytecode = bytecode "CALL\n"
+        } else if (token == "negative?") {
+            # Check if top of stack is negative
+            bytecode = bytecode "PUSH_CONST S:negative?\n"
+            bytecode = bytecode "LOOKUP negative?\n"
+            bytecode = bytecode "GET_VALUE\n"
+            bytecode = bytecode "CALL\n"
+        } else if (token == "number?") {
+            # Check if top of stack is a number
+            bytecode = bytecode "PUSH_CONST S:number?\n"
+            bytecode = bytecode "LOOKUP number?\n"
+            bytecode = bytecode "GET_VALUE\n"
+            bytecode = bytecode "CALL\n"
+        } else if (token == "cons") {
+            # Create cons cell
+            bytecode = bytecode "CONS\n"
+        } else if (token == "car") {
+            # Get car of cons cell
+            bytecode = bytecode "CAR\n"
+        } else if (token == "cdr") {
+            # Get cdr of cons cell
+            bytecode = bytecode "CDR\n"
+        } else if (token == "over") {
+            # Copy second item to top ( a b -- a b a )
+            # This is complex with basic operations, skip for now
+            bytecode = bytecode "DUP\n"
+        } else if (token == "2drop") {
+            # Drop top two items ( a b -- )
+            bytecode = bytecode "POP\n"
+            bytecode = bytecode "POP\n"
+        } else if (token == "words") {
+            # List all available words
+            bytecode = bytecode "PUSH_CONST STR:Available words: + - * / . cr dup swap drop\n"
+            bytecode = bytecode "PRINT\n"
+            bytecode = bytecode "POP\n"
+            bytecode = bytecode "PUSH_CONST STR:Stack: .s depth 2drop\n"
+            bytecode = bytecode "PRINT\n"
+            bytecode = bytecode "POP\n"
+            bytecode = bytecode "PUSH_CONST STR:Logic: = < > not\n"
+            bytecode = bytecode "PRINT\n"
+            bytecode = bytecode "POP\n"
+            bytecode = bytecode "PUSH_CONST STR:Lists: cons car cdr\n"
+            bytecode = bytecode "PRINT\n"
+            bytecode = bytecode "POP\n"
+            bytecode = bytecode "PUSH_CONST STR:Math: abs mod min max\n"
+            bytecode = bytecode "PRINT\n"
+            bytecode = bytecode "POP\n"
+            bytecode = bytecode "PUSH_CONST STR:Predicates: zero? positive? negative? number?\n"
+            bytecode = bytecode "PRINT\n"
+            bytecode = bytecode "POP\n"
+            bytecode = bytecode "PUSH_CONST STR:Env: store lookup env\n"
+            bytecode = bytecode "PRINT\n"
+            bytecode = bytecode "POP\n"
+            bytecode = bytecode "PUSH_CONST STR:Control: if then\n"
+            bytecode = bytecode "PRINT\n"
+            bytecode = bytecode "POP\n"
+            bytecode = bytecode "PUSH_CONST STR:Debug: bye\n"
+            bytecode = bytecode "PRINT\n"
+            bytecode = bytecode "POP\n"
+        }
+    }
+    
+    # Add HALT instruction only if we haven't already printed something
+    # This prevents double output
+    if (bytecode !~ /PRINT/) {
+        bytecode = bytecode "HALT\n"
+    }
+    
+    # Execute the bytecode
+    execute_bytecode(bytecode)
+}
+
+# Execute VM bytecode
+function execute_bytecode(bytecode) {
+    # Write bytecode to temporary file
+    temp_file = "/tmp/forth_bytecode.tmp"
+    printf("%s", bytecode) > temp_file
+    close(temp_file)
+    
+    # Try different VM paths based on current directory
+    vm_path = "bin/vm.awk"
+    cmd = "awk -v PERSIST=1 -f " vm_path " < " temp_file " 2>/dev/null"
+    
+    # Read all output lines
+    output = ""
+    while ((cmd | getline line) > 0) {
+        if (output != "") output = output "\n"
+        output = output line
+    }
+    close(cmd)
+    
+    # If that failed, try the relative path from forth directory
+    if (output == "" || output ~ /No such file/) {
+        vm_path = "../../bin/vm.awk"
+        cmd = "awk -v PERSIST=1 -f " vm_path " < " temp_file " 2>/dev/null"
+        
+        # Read all output lines
+        output = ""
+        while ((cmd | getline line) > 0) {
+            if (output != "") output = output "\n"
+            output = output line
+        }
+        close(cmd)
+    }
+    
+    # Clean up
+    system("rm -f " temp_file)
+    
+    if (output != "") {
+        printf("Result: %s\n", output)
+    }
+} 
\ No newline at end of file
diff --git a/awk/scheme/scheme/scratch/ideas-for-string-support.md b/awk/scheme/scheme/scratch/ideas-for-string-support.md
deleted file mode 100644
index 0d81e5f..0000000
--- a/awk/scheme/scheme/scratch/ideas-for-string-support.md
+++ /dev/null
@@ -1,556 +0,0 @@
-# String Support Implementation Plan for Awk-Scheme
-
-## Overview
-This document outlines a comprehensive plan for adding string support to the Awk-Scheme interpreter. The implementation will follow the existing architecture patterns and maintain consistency with the current type system and execution model.
-
-## Current Architecture Analysis
-
-### Type System
-- Current types: `N:`, `B:`, `S:`, `P:`, `F:`, `NIL:`, `CLOSURE:`
-- All values use `type:value` format for runtime type checking
-- Type checking via `getType()` and `getValue()` functions
-- Type predicates: `isNumber()`, `isBoolean()`, `isSymbol()`, etc.
-
-### Compiler Pipeline
-1. **Lexer** (`next_token()`): Handles numbers, symbols, parentheses
-2. **Parser** (`parse_expr()`, `parse_list()`): Builds expression trees
-3. **Code Generator**: Emits VM instructions for different expression types
-4. **Expression Compiler** (`compile_expr()`): Dispatches based on expression type
-
-### VM Architecture
-- Stack-based execution with typed values
-- Environment-based variable binding
-- Built-in function registry (`FUNCTIONS` table)
-- Direct function execution (no program array modification)
-- State persistence for globals and functions
-
-## String Implementation Plan
-
-### Phase 1: Core String Type System
-
-#### 1.1 VM Type System Extensions
-**File: `bin/vm.awk`**
-
-```awk
-# Add to BEGIN block
-T_STRING = "STR"  # String type tag
-
-# Add type predicate
-function isString(val) { return getType(val) == T_STRING }
-
-# String value constructor
-function makeString(val) {
-    return T_STRING ":" val
-}
-```
-
-**Changes Required:**
-- Add `T_STRING` constant in BEGIN block
-- Add `isString()` predicate function
-- Add `makeString()` constructor function
-- Update type checking in existing operations where needed
-
-#### 1.2 String Storage Strategy
-**Options:**
-1. **Inline storage**: Store strings directly in the type:value format
-   - Pros: Simple, fast access
-   - Cons: Limited by awk string length, no escaping issues
-   
-2. **Heap storage**: Store strings in heap like cons cells
-   - Pros: Unlimited length, consistent with existing patterns
-   - Cons: More complex, requires string management
-
-**Recommendation**: Start with inline storage for simplicity, can migrate to heap later.
-
-### Phase 2: Compiler Extensions
-
-#### 2.1 Lexer String Support
-**File: `bin/compiler.awk`**
-
-**Current lexer handles:**
-- Numbers: `-?[0-9]+`
-- Symbols: `[a-zA-Z_][a-zA-Z0-9_]*`
-- Parentheses: `(`, `)`
-
-**New string tokenization:**
-```awk
-# Add to next_token() function
-# Handle string literals (double quotes)
-if (c == "\"") {
-    str = ""
-    input_buffer = substr(input_buffer, 2)  # Skip opening quote
-    
-    while (length(input_buffer) > 0) {
-        c = substr(input_buffer, 1, 1)
-        if (c == "\"") {
-            input_buffer = substr(input_buffer, 2)  # Skip closing quote
-            break
-        }
-        if (c == "\\") {
-            # Handle escape sequences
-            input_buffer = substr(input_buffer, 2)
-            if (length(input_buffer) > 0) {
-                c = substr(input_buffer, 1, 1)
-                if (c == "n") str = str "\n"
-                else if (c == "t") str = str "\t"
-                else if (c == "\\") str = str "\\"
-                else if (c == "\"") str = str "\""
-                else error("Invalid escape sequence: \\" c)
-                input_buffer = substr(input_buffer, 2)
-            }
-        } else {
-            str = str c
-            input_buffer = substr(input_buffer, 2)
-        }
-    }
-    return "\"" str "\""  # Return with quotes for identification
-}
-```
-
-**Escape Sequences to Support:**
-- `\"` - Literal double quote
-- `\\` - Literal backslash  
-- `\n` - Newline
-- `\t` - Tab
-- `\r` - Carriage return
-
-#### 2.2 Parser String Support
-**File: `bin/compiler.awk`**
-
-**Update `parse_expr()`:**
-```awk
-function parse_expr(token, result) {
-    token = next_token()
-    if (token == "EOF") return ""
-    
-    if (token == "(") {
-        result = parse_list()
-        debug("Parsed list: " result)
-        return result
-    }
-    
-    # Handle string literals
-    if (substr(token, 1, 1) == "\"") {
-        debug("Parsed string: " token)
-        return token
-    }
-    
-    debug("Parsed token: " token)
-    return token
-}
-```
-
-#### 2.3 Code Generation for Strings
-**File: `bin/compiler.awk`**
-
-**Add to `compile_expr()`:**
-```awk
-function compile_expr(expr, split_result, op, args) {
-    debug("Compiling expression: " expr)
-    
-    # Handle string literals
-    if (substr(expr, 1, 1) == "\"") {
-        compile_string(expr)
-        return
-    }
-    
-    # ... existing code for numbers, nil, variables, etc.
-}
-
-function compile_string(str) {
-    debug("Compiling string: " str)
-    # Remove outer quotes and emit string constant
-    content = substr(str, 2, length(str) - 2)
-    print "PUSH_CONST STR:" content
-}
-```
-
-### Phase 3: VM String Operations
-
-#### 3.1 String Built-in Functions
-**File: `bin/vm.awk`**
-
-**Add to BEGIN block (built-in registration):**
-```awk
-# String operations
-FUNCTIONS["string-length"] = "string_length"
-FUNCTIONS["string-append"] = "string_append"
-FUNCTIONS["string-ref"] = "string_ref"
-FUNCTIONS["substring"] = "substring"
-FUNCTIONS["string=?"] = "string_equal"
-FUNCTIONS["string<?"] = "string_less_than"
-FUNCTIONS["string>?"] = "string_greater_than"
-FUNCTIONS["string-ci=?"] = "string_ci_equal"
-FUNCTIONS["string-ci<?"] = "string_ci_less_than"
-FUNCTIONS["string-ci>?"] = "string_ci_greater_than"
-```
-
-**Add to function call dispatch in `vm_call_function()`:**
-```awk
-} else if (built_in_name == "string_length") {
-    debug("Calling built-in function: string_length")
-    string_length()
-    return
-} else if (built_in_name == "string_append") {
-    debug("Calling built-in function: string_append")
-    string_append()
-    return
-# ... etc for other string functions
-```
-
-#### 3.2 String Function Implementations
-**File: `bin/vm.awk`**
-
-```awk
-# String length
-function string_length() {
-    if (stack_ptr < 1) error("string-length requires one operand")
-    val = pop()
-    if (!isString(val)) error("string-length requires string operand")
-    str = getValue(val)
-    push(makeValue(T_NUMBER, length(str)))
-}
-
-# String concatenation
-function string_append() {
-    if (stack_ptr < 2) error("string-append requires at least two operands")
-    result = ""
-    # Pop all arguments and concatenate
-    while (stack_ptr > 0) {
-        val = pop()
-        if (!isString(val)) error("string-append requires string operands")
-        result = getValue(val) result
-    }
-    push(makeString(result))
-}
-
-# String character access (0-indexed)
-function string_ref() {
-    if (stack_ptr < 2) error("string-ref requires two operands")
-    index_val = pop()
-    str_val = pop()
-    if (!isNumber(index_val)) error("string-ref index must be a number")
-    if (!isString(str_val)) error("string-ref requires string operand")
-    
-    str = getValue(str_val)
-    idx = getValue(index_val) + 1  # Convert to 1-indexed
-    if (idx < 1 || idx > length(str)) error("string-ref index out of bounds")
-    
-    char = substr(str, idx, 1)
-    push(makeString(char))
-}
-
-# Substring extraction
-function substring() {
-    if (stack_ptr < 3) error("substring requires three operands")
-    end = pop()
-    start = pop()
-    str_val = pop()
-    
-    if (!isNumber(start) || !isNumber(end)) error("substring indices must be numbers")
-    if (!isString(str_val)) error("substring requires string operand")
-    
-    str = getValue(str_val)
-    start_idx = getValue(start) + 1  # Convert to 1-indexed
-    end_idx = getValue(end) + 1
-    
-    if (start_idx < 1 || end_idx > length(str) || start_idx > end_idx) {
-        error("substring indices out of bounds")
-    }
-    
-    result = substr(str, start_idx, end_idx - start_idx + 1)
-    push(makeString(result))
-}
-
-# String comparison (case-sensitive)
-function string_equal() {
-    if (stack_ptr < 2) error("string=? requires two operands")
-    val2 = pop()
-    val1 = pop()
-    if (!isString(val1) || !isString(val2)) error("string=? requires string operands")
-    result = (getValue(val1) == getValue(val2)) ? "1" : "0"
-    push(makeValue(T_BOOLEAN, result))
-}
-
-function string_less_than() {
-    if (stack_ptr < 2) error("string<? requires two operands")
-    val2 = pop()
-    val1 = pop()
-    if (!isString(val1) || !isString(val2)) error("string<? requires string operands")
-    result = (getValue(val1) < getValue(val2)) ? "1" : "0"
-    push(makeValue(T_BOOLEAN, result))
-}
-
-function string_greater_than() {
-    if (stack_ptr < 2) error("string>? requires two operands")
-    val2 = pop()
-    val1 = pop()
-    if (!isString(val1) || !isString(val2)) error("string>? requires string operands")
-    result = (getValue(val1) > getValue(val2)) ? "1" : "0"
-    push(makeValue(T_BOOLEAN, result))
-}
-
-# Case-insensitive string comparison
-function string_ci_equal() {
-    if (stack_ptr < 2) error("string-ci=? requires two operands")
-    val2 = pop()
-    val1 = pop()
-    if (!isString(val1) || !isString(val2)) error("string-ci=? requires string operands")
-    # Convert to lowercase for comparison
-    str1 = tolower(getValue(val1))
-    str2 = tolower(getValue(val2))
-    result = (str1 == str2) ? "1" : "0"
-    push(makeValue(T_BOOLEAN, result))
-}
-
-function string_ci_less_than() {
-    if (stack_ptr < 2) error("string-ci<? requires two operands")
-    val2 = pop()
-    val1 = pop()
-    if (!isString(val1) || !isString(val2)) error("string-ci<? requires string operands")
-    str1 = tolower(getValue(val1))
-    str2 = tolower(getValue(val2))
-    result = (str1 < str2) ? "1" : "0"
-    push(makeValue(T_BOOLEAN, result))
-}
-
-function string_ci_greater_than() {
-    if (stack_ptr < 2) error("string-ci>? requires two operands")
-    val2 = pop()
-    val1 = pop()
-    if (!isString(val1) || !isString(val2)) error("string-ci>? requires string operands")
-    str1 = tolower(getValue(val1))
-    str2 = tolower(getValue(val2))
-    result = (str1 > str2) ? "1" : "0"
-    push(makeValue(T_BOOLEAN, result))
-}
-```
-
-### Phase 4: Enhanced String Operations
-
-#### 4.1 Additional String Functions
-```awk
-# String to number conversion
-function string_to_number() {
-    if (stack_ptr < 1) error("string->number requires one operand")
-    val = pop()
-    if (!isString(val)) error("string->number requires string operand")
-    str = getValue(val)
-    if (str ~ /^-?[0-9]+$/) {
-        push(makeValue(T_NUMBER, str))
-    } else {
-        push(makeValue(T_BOOLEAN, "0"))  # Return false for invalid numbers
-    }
-}
-
-# Number to string conversion
-function number_to_string() {
-    if (stack_ptr < 1) error("number->string requires one operand")
-    val = pop()
-    if (!isNumber(val)) error("number->string requires number operand")
-    num = getValue(val)
-    push(makeString(num))
-}
-
-# String splitting
-function string_split() {
-    if (stack_ptr < 2) error("string-split requires two operands")
-    delimiter = pop()
-    str_val = pop()
-    if (!isString(delimiter) || !isString(str_val)) {
-        error("string-split requires string operands")
-    }
-    
-    str = getValue(str_val)
-    delim = getValue(delimiter)
-    
-    # Use awk's split function
-    split(str, parts, delim)
-    result = ""
-    for (i = 1; i <= length(parts); i++) {
-        if (result != "") result = result " "
-        result = result "\"" parts[i] "\""
-    }
-    push(makeString("(" result ")"))
-}
-```
-
-#### 4.2 String Formatting
-```awk
-# String formatting (simple version)
-function format() {
-    if (stack_ptr < 2) error("format requires at least two operands")
-    format_str = pop()
-    if (!isString(format_str)) error("format requires string format operand")
-    
-    # Simple implementation - replace ~a with arguments
-    fmt = getValue(format_str)
-    arg_count = 0
-    
-    while (stack_ptr > 0) {
-        val = pop()
-        arg_count++
-        # Replace ~a with the value
-        gsub(/~a/, val, fmt)
-    }
-    
-    push(makeString(fmt))
-}
-```
-
-### Phase 5: State Persistence for Strings
-
-#### 5.1 String State Management
-**File: `bin/vm.awk`**
-
-**Update `save_state()` and state loading:**
-- Strings stored in environment will be automatically persisted
-- No special handling needed since strings use inline storage
-- String literals in function definitions will be preserved
-
-**Considerations:**
-- Long strings may impact state file size
-- Escape sequences need proper handling in state files
-- String encoding consistency across sessions
-
-### Phase 6: Testing and Validation
-
-#### 6.1 Test Cases
-**Create test files:**
-
-```scheme
-; Basic string literals
-"hello world"
-""
-"\"quoted\""
-"line1\nline2"
-
-; String operations
-(string-length "hello")
-(string-append "hello" " " "world")
-(string-ref "hello" 0)
-(substring "hello world" 0 4)
-
-; String comparisons
-(string=? "hello" "hello")
-(string=? "hello" "world")
-(string<? "abc" "def")
-(string>? "xyz" "abc")
-
-; Case-insensitive comparisons
-(string-ci=? "Hello" "hello")
-(string-ci<? "ABC" "def")
-
-; Conversions
-(string->number "123")
-(number->string 456)
-(string->number "abc")
-
-; String in expressions
-(define greeting "Hello")
-(define name "World")
-(string-append greeting " " name)
-
-; Strings in functions
-(define (greet name) (string-append "Hello, " name "!"))
-(greet "Alice")
-```
-
-#### 6.2 Edge Cases to Test
-- Empty strings
-- Strings with special characters
-- Escape sequences
-- Very long strings
-- String operations on non-string types
-- String comparisons with different encodings
-- String persistence across REPL sessions
-
-### Phase 7: Performance and Optimization
-
-#### 7.1 Performance Considerations
-- **String concatenation**: Current `string-append` is O(n²) - consider optimization
-- **String storage**: Monitor memory usage with large strings
-- **String comparisons**: Consider early termination for long strings
-- **Escape sequence processing**: Optimize lexer for common cases
-
-#### 7.2 Potential Optimizations
-```awk
-# Optimized string concatenation (build in reverse)
-function string_append_optimized() {
-    if (stack_ptr < 2) error("string-append requires at least two operands")
-    
-    # Count arguments and pre-allocate
-    arg_count = 0
-    temp_stack[0] = stack_ptr
-    
-    # Pop all arguments to temp storage
-    while (stack_ptr > 0) {
-        val = pop()
-        if (!isString(val)) error("string-append requires string operands")
-        temp_stack[++arg_count] = getValue(val)
-    }
-    
-    # Concatenate in reverse order (more efficient)
-    result = ""
-    for (i = arg_count; i >= 1; i--) {
-        result = result temp_stack[i]
-    }
-    
-    push(makeString(result))
-}
-```
-
-### Phase 8: Documentation and Examples
-
-#### 8.1 Update README.md
-- Add string data type to type system documentation
-- Include string usage examples
-- Document all string built-in functions
-- Add string limitations and considerations
-
-#### 8.2 Update diagram.md
-- Add string type to data type diagram
-- Include string operations in VM instruction set
-- Show string flow in execution examples
-
-### Implementation Order and Risk Assessment
-
-#### High Priority (Core Functionality)
-1. **Type system extensions** - Low risk, foundational
-2. **Lexer string support** - Medium risk, affects parsing
-3. **Basic string operations** - Low risk, self-contained
-4. **String literals in expressions** - Medium risk, integration
-
-#### Medium Priority (Enhanced Features)
-5. **String comparisons** - Low risk, straightforward
-6. **String conversions** - Low risk, utility functions
-7. **State persistence** - Low risk, automatic
-
-#### Lower Priority (Advanced Features)
-8. **String formatting** - Medium risk, complex parsing
-9. **String splitting** - Low risk, utility function
-10. **Performance optimizations** - Low risk, optional
-
-#### Risk Mitigation
-- **Regression testing**: Ensure existing functionality unchanged
-- **Incremental implementation**: Add features one at a time
-- **Comprehensive testing**: Test all edge cases
-- **Backward compatibility**: Maintain existing API
-
-### Success Criteria
-1. String literals parse and compile correctly
-2. Basic string operations work as expected
-3. String state persists across REPL sessions
-4. No regression in existing functionality
-5. Performance remains acceptable
-6. Documentation is complete and accurate
-
-### Future Enhancements
-1. **Heap-based string storage** for very long strings
-2. **String interning** for memory efficiency
-3. **Unicode support** (complex, requires significant changes)
-4. **Regular expression support** for string matching
-5. **String formatting with more features** (like Common Lisp format)
-6. **String streams** for efficient string building
-
-This plan provides a comprehensive roadmap for implementing string support while maintaining the existing architecture and ensuring backward compatibility. 
\ No newline at end of file
diff --git a/awk/scheme/scheme/scratch/random.txt b/awk/scheme/scheme/scratch/random.txt
deleted file mode 100644
index 20b3bcf..0000000
--- a/awk/scheme/scheme/scratch/random.txt
+++ /dev/null
@@ -1,112 +0,0 @@
-Other Uses for the Awk-Scheme VM
-================================
-
-The stack-based VM in Awk-Scheme is surprisingly versatile. Here are some realistic alternatives that could be implemented using the same VM architecture:
-
-## 1. Forth Implementation
-**Feasibility: High**
-
-Forth is a natural fit since it's already stack-based:
-- **Stack Operations**: VM already has PUSH_CONST, POP, DUP, SWAP
-- **Arithmetic**: ADD, SUB, MUL, DIV are perfect for Forth
-- **Memory**: Could extend heap for Forth's memory model
-- **Control Flow**: Would need to add conditional jumps and loops
-- **Words**: Could map Forth words to VM functions
-
-**Required Extensions:**
-- JMP, JZ (jump if zero), JNZ instructions
-- More stack operations (OVER, ROT, etc.)
-- Memory read/write operations
-- Input/output operations
-
-## 2. Simple Calculator Language
-**Feasibility: Very High**
-
-A basic calculator with variables and functions:
-- **Syntax**: `x = 5; y = x + 3; print y`
-- **Features**: Variables, basic math, simple functions
-- **VM Fit**: Perfect - already has arithmetic, variables, functions
-
-**Minimal Changes Needed:**
-- New parser for calculator syntax
-- Assignment operator handling
-- Print statement
-
-## 3. Configuration Language
-**Feasibility: High**
-
-A simple config language for key-value pairs and nested structures:
-- **Syntax**: `server { port = 8080; host = "localhost"; }`
-- **Features**: Nested objects, arrays, basic expressions
-- **VM Fit**: Good - can use cons cells for nested structures
-
-**Required Extensions:**
-- String support
-- Object/struct creation
-- Field access operations
-
-## 4. Simple Scripting Language
-**Feasibility: Medium**
-
-A basic scripting language with loops and conditionals:
-- **Syntax**: `if x > 0 { y = x * 2; } else { y = 0; }`
-- **Features**: Variables, conditionals, loops, functions
-- **VM Fit**: Good but needs control flow
-
-**Required Extensions:**
-- Conditional jumps
-- Loop constructs
-- Boolean logic operations
-
-## 5. Data Processing Language
-**Feasibility: Medium**
-
-A language for simple data transformations:
-- **Syntax**: `filter(x > 0) | map(x * 2) | sum()`
-- **Features**: Pipeline operations, list processing
-- **VM Fit**: Good - can use cons cells for lists
-
-**Required Extensions:**
-- List operations (map, filter, reduce)
-- Pipeline operator
-- More built-in functions
-
-## 6. Simple Logic/Constraint Language
-**Feasibility: High**
-
-A language for expressing simple constraints and rules:
-- **Syntax**: `rule: if age > 18 then can_vote = true`
-- **Features**: Rules, facts, simple inference
-- **VM Fit**: Good - boolean operations and variables
-
-**Required Extensions:**
-- Boolean logic (AND, OR, NOT)
-- Rule evaluation
-- Fact storage
-
-## VM Strengths for Alternative Languages:
-1. **Stack-based**: Natural for many languages
-2. **Typed values**: Good foundation for type safety
-3. **Environment model**: Supports variables and scoping
-4. **Function system**: Reusable for different syntaxes
-5. **Extensible**: Easy to add new instructions
-
-## VM Limitations for Alternative Languages:
-1. **Limited data types**: Only numbers, booleans, pairs, symbols
-2. **No strings**: Would need to add string support
-3. **Limited control flow**: Only function calls, no loops/conditionals
-4. **No I/O**: Would need file/console operations
-5. **Memory constraints**: Simple heap model
-
-## Most Realistic Next Steps:
-1. **Forth**: Natural progression, leverages existing stack operations
-2. **Calculator**: Minimal changes, good learning exercise
-3. **Config Language**: Practical use case, moderate complexity
-
-## Implementation Strategy:
-1. Keep the VM unchanged
-2. Write new compilers for different syntaxes
-3. Add minimal VM extensions as needed
-4. Reuse existing VM infrastructure (stack, environment, functions)
-
-The VM's simplicity is actually a strength - it's easy to understand and extend, making it a good foundation for experimenting with different language designs. 
\ No newline at end of file
diff --git a/awk/scheme/scheme/scratch/run.sh b/awk/scheme/scheme/scratch/run.sh
deleted file mode 100755
index 0afdb41..0000000
--- a/awk/scheme/scheme/scratch/run.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/bash
-# Compile Scheme to VM instructions
-awk -f compiler.awk test.scm > test.asm
-# Run VM instructions
-awk -f vm.awk test.asm
\ No newline at end of file
diff --git a/awk/scheme/scheme/scratch/test.asm b/awk/scheme/scheme/scratch/test.asm
deleted file mode 100644
index 8e7d8df..0000000
--- a/awk/scheme/scheme/scratch/test.asm
+++ /dev/null
@@ -1,16 +0,0 @@
-PUSH_CONST N:1
-PUSH_CONST N:2
-ADD
-PUSH_CONST N:3
-PUSH_CONST N:4
-MUL
-PUSH_CONST N:10
-PUSH_CONST N:2
-PUSH_CONST N:3
-ADD
-SUB
-PUSH_CONST NIL:
-CONS
-CONS
-CONS
-HALT
diff --git a/awk/scheme/scheme/scratch/test.scm b/awk/scheme/scheme/scratch/test.scm
deleted file mode 100644
index a01b174..0000000
--- a/awk/scheme/scheme/scratch/test.scm
+++ /dev/null
@@ -1,8 +0,0 @@
-;; Build a list of calculated values
-(cons (+ 1 2)           ; First element: 1 + 2 = 3
-      (cons (* 3 4)     ; Second element: 3 * 4 = 12
-            (cons (- 10 
-                    (+ 2 3))  ; Third element: 10 - (2 + 3) = 5
-                  nil)))      ; End of list
-
-;; This should create a list: (3 12 5)
\ No newline at end of file
diff --git a/awk/scheme/scheme/scratch/test.scm.asm b/awk/scheme/scheme/scratch/test.scm.asm
deleted file mode 100644
index 526e2b1..0000000
--- a/awk/scheme/scheme/scratch/test.scm.asm
+++ /dev/null
@@ -1,7 +0,0 @@
-PUSH_CONST N:5
-PUSH_CONST N:3
-ADD
-PUSH_CONST N:2
-MUL
-PRINT # should output N:16
-HALT
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/README.md b/awk/scheme/scheme/test/README.md
new file mode 100644
index 0000000..7106cb3
--- /dev/null
+++ b/awk/scheme/scheme/test/README.md
@@ -0,0 +1,144 @@
+# Test Suite Documentation
+
+## Overview
+The test suite is organized into four categories to ensure comprehensive coverage of the Scheme implementation:
+
+## Test Categories
+
+### Unit Tests (`test/unit/`)
+Focused tests for individual language features and components:
+
+#### Core Language Features
+- `basic_arithmetic.scm` - Basic arithmetic operations (+, -, *, /)
+- `essential_numeric_operations.scm` - Core numeric functions (abs, modulo, expt)
+- `comprehensive_numeric_and_type_operations.scm` - Full numeric and type predicate testing
+- `booleans.scm` - Boolean operations and logic
+- `strings.scm` - String operations and manipulation
+- `lists.scm` - Basic list operations (cons, car, cdr)
+- `variables.scm` - Variable binding and lookup
+- `functions.scm` - Function definition and calling
+- `lambdas.scm` - Lambda function creation and execution
+- `closures.scm` - Closure environment capture
+- `let.scm` - Let binding expressions
+- `control_flow.scm` - Basic control flow (if, cond)
+- `advanced_control_flow.scm` - Complex control flow patterns
+- `advanced_functions.scm` - Advanced function features
+
+#### Higher-Order Functions
+- `basic_map_operations.scm` - Basic map function testing
+- `basic_higher_order_functions.scm` - Map and filter with built-in functions
+- `comprehensive_higher_order_functions.scm` - Full map/filter with all function types
+- `call_stack_infrastructure.scm` - Call stack and nested function support
+
+#### Standard Library
+- `basic_stdlib_test.scm` - Basic standard library functions
+- `simple_stdlib_test.scm` - Simple standard library usage
+- `stdlib_lists.scm` - List utility functions
+- `stdlib_results_test.scm` - Standard library result validation
+- `additional_lists.scm` - Additional list operations
+- `simple_additional_lists.scm` - Simple list operations
+
+#### Error Handling and Edge Cases
+- `error_handling.scm` - Error condition testing
+- `performance_stress.scm` - Performance and stress testing
+- `vm_instructions.scm` - VM instruction validation
+
+#### Debug and Development
+- `debug_*.scm` - Various debug and development tests
+
+### Integration Tests (`test/integration/`)
+Tests that combine multiple language features in realistic scenarios:
+
+- `basic_arithmetic.scm` - Arithmetic operations in context
+- `list_operations.scm` - List operations with other features
+- `string_operations.scm` - String operations in context
+- `function_composition.scm` - Function composition patterns
+- `complex_programs.scm` - Complex multi-feature programs
+- `higher_order_functions.scm` - Higher-order functions with complex scenarios
+
+### Regression Tests (`test/regression/`)
+Tests to prevent regressions in previously fixed issues:
+
+- `edge_cases.scm` - Edge case handling
+- `nested_expressions.scm` - Complex nested expression evaluation
+
+### Examples (`test/examples/`)
+Example programs demonstrating language capabilities:
+
+- `calculator.scm` - Simple calculator implementation
+- `list_utils.scm` - List utility functions
+- `string_utils.scm` - String utility functions
+
+## Test Naming Conventions
+
+### Unit Tests
+- `basic_*.scm` - Basic functionality testing
+- `essential_*.scm` - Core language features
+- `comprehensive_*.scm` - Full feature testing
+- `advanced_*.scm` - Advanced language features
+- `simple_*.scm` - Simple, focused tests
+- `debug_*.scm` - Debug and development tests
+
+### Integration Tests
+- `*_operations.scm` - Operations in context
+- `*_composition.scm` - Feature composition
+- `complex_*.scm` - Complex multi-feature scenarios
+- `higher_order_*.scm` - Higher-order function scenarios
+
+## Running Tests
+
+```bash
+# Run all tests
+./test/run_tests.sh
+
+# Run specific test category
+./test/run_tests.sh unit
+./test/run_tests.sh integration
+./test/run_tests.sh regression
+./test/run_tests.sh examples
+
+# Run individual test
+./bin/compiler.awk test/unit/basic_arithmetic.scm | ./bin/vm.awk
+```
+
+## Test Coverage
+
+The test suite covers:
+
+### Core Language Features
+- ✅ Arithmetic operations (+, -, *, /, modulo, expt, abs, min, max)
+- ✅ Type predicates (number?, string?, boolean?, symbol?, zero?, positive?, negative?)
+- ✅ List operations (cons, car, cdr, length, append, reverse, member)
+- ✅ String operations (string-length, string-append, string-ref, substring, string comparisons)
+- ✅ Variable binding (define, let)
+- ✅ Function definition and calling
+- ✅ Lambda functions and closures
+- ✅ Control flow (if, cond, and, or, not)
+
+### Higher-Order Functions
+- ✅ Map function with all function types (built-in, lambda, user-defined, closures)
+- ✅ Filter function with all function types
+- ✅ Nested higher-order function calls
+- ✅ Complex data processing pipelines
+
+### Standard Library
+- ✅ List utilities (null?, pair?, cadr, caddr, list-ref, list-tail)
+- ✅ String utilities (all string operations)
+- ✅ Control flow utilities (all control flow constructs)
+
+### Integration Scenarios
+- ✅ Complex programs combining multiple features
+- ✅ Function composition patterns
+- ✅ Data processing pipelines
+- ✅ Higher-order function scenarios
+
+## Adding New Tests
+
+When adding new tests:
+
+1. **Unit Tests**: Focus on a single feature or component
+2. **Integration Tests**: Combine multiple features in realistic scenarios
+3. **Regression Tests**: Prevent specific bugs from recurring
+4. **Examples**: Demonstrate language capabilities
+
+Use descriptive names that indicate the test's purpose and scope. 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/examples/calculator.scm b/awk/scheme/scheme/test/examples/calculator.scm
new file mode 100644
index 0000000..43895ff
--- /dev/null
+++ b/awk/scheme/scheme/test/examples/calculator.scm
@@ -0,0 +1,14 @@
+; Function definitions and arithmetic
+
+(define add (x y) (+ x y))
+(define subtract (x y) (- x y))
+(define multiply (x y) (* x y))
+(define divide (x y) (/ x y))
+
+(add 10 5)
+(subtract 10 5)
+(multiply 10 5)
+(divide 10 5)
+
+; Chain operations
+(add (multiply 3 4) (divide 10 2)) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/examples/list_utils.scm b/awk/scheme/scheme/test/examples/list_utils.scm
new file mode 100644
index 0000000..19d7299
--- /dev/null
+++ b/awk/scheme/scheme/test/examples/list_utils.scm
@@ -0,0 +1,17 @@
+; List operations and function definitions
+
+(define make-pair (x y) (cons x y))
+(define make-triple (x y z) (cons x (cons y (cons z nil))))
+(define first (lst) (car lst))
+(define second (lst) (car (cdr lst)))
+(define third (lst) (car (cdr (cdr lst))))
+(define rest (lst) (cdr lst))
+
+(make-pair 1 2)
+(first (make-pair 1 2))
+(rest (make-pair 1 2))
+
+(make-triple 1 2 3)
+(first (make-triple 1 2 3))
+(second (make-triple 1 2 3))
+(third (make-triple 1 2 3)) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/examples/string_utils.scm b/awk/scheme/scheme/test/examples/string_utils.scm
new file mode 100644
index 0000000..6973922
--- /dev/null
+++ b/awk/scheme/scheme/test/examples/string_utils.scm
@@ -0,0 +1,16 @@
+; String operations and function composition
+
+(define greet (name) (string-append "Hello, " name "!"))
+(define shout (message) (string-append message "!!!"))
+(define count-chars (text) (string-length text))
+(define first-char (text) (string-ref text 0))
+(define last-char (text) (string-ref text (- (string-length text) 1)))
+
+(greet "World")
+(shout "Hello")
+(count-chars "Hello World")
+(first-char "Hello")
+(last-char "Hello")
+
+; Compose operations
+(shout (greet "Alice")) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/integration/basic_arithmetic.scm b/awk/scheme/scheme/test/integration/basic_arithmetic.scm
new file mode 100644
index 0000000..f2ee0ca
--- /dev/null
+++ b/awk/scheme/scheme/test/integration/basic_arithmetic.scm
@@ -0,0 +1,10 @@
+; Strive to tests compilation and the execution of arithmetic expressions
+
+(define a 10)
+(define b 5)
+(+ a b)
+(- a b)
+(* a b)
+(/ a b)
+(define result (+ (* a b) (- a b)))
+result 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/integration/complex_programs.scm b/awk/scheme/scheme/test/integration/complex_programs.scm
new file mode 100644
index 0000000..4ea5aa1
--- /dev/null
+++ b/awk/scheme/scheme/test/integration/complex_programs.scm
@@ -0,0 +1,86 @@
+;; Complex Program Integration Tests
+;; Tests that combine multiple language features in realistic scenarios
+
+;; Simple calculator with multiple operations
+(define calculator (op a b)
+  (cond ((= op "add") (+ a b))
+        ((= op "sub") (- a b))
+        ((= op "mul") (* a b))
+        ((= op "div") (/ a b))
+        (else "unknown operation")))
+
+(calculator "add" 5 3)
+(calculator "sub" 10 4)
+(calculator "mul" 6 7)
+(calculator "div" 15 3)
+
+;; List processing pipeline
+(define process-list (lst)
+  (if (null? lst)
+      nil
+      (cons (* (car lst) 2)
+            (process-list (cdr lst)))))
+
+(define filter-even (lst)
+  (if (null? lst)
+      nil
+      (if (= (modulo (car lst) 2) 0)
+          (cons (car lst) (filter-even (cdr lst)))
+          (filter-even (cdr lst)))))
+
+(define sample-list (cons 1 (cons 2 (cons 3 (cons 4 (cons 5 nil))))))
+(process-list sample-list)
+(filter-even sample-list)
+
+;; String processing utilities
+(define string-reverse (str)
+  (define reverse-helper (str idx)
+    (if (< idx 0)
+        ""
+        (string-append (substring str idx (+ idx 1))
+                      (reverse-helper str (- idx 1)))))
+  (reverse-helper str (- (string-length str) 1)))
+
+(string-reverse "hello")
+(string-reverse "racecar")
+
+;; Higher-order list operations
+(define map (f lst)
+  (if (null? lst)
+      nil
+      (cons (f (car lst))
+            (map f (cdr lst)))))
+
+(define square (x) (* x x))
+(map square (cons 1 (cons 2 (cons 3 nil))))
+
+;; Complex nested data structures
+(define make-person (name age)
+  (cons name (cons age nil)))
+
+(define person-name (person) (car person))
+(define person-age (person) (car (cdr person)))
+
+(define alice (make-person "Alice" 25))
+(define bob (make-person "Bob" 30))
+(define people (cons alice (cons bob nil)))
+
+(person-name alice)
+(person-age bob)
+(length people)
+
+;; Recursive tree-like structure
+(define make-tree (value left right)
+  (cons value (cons left (cons right nil))))
+
+(define tree-value (tree) (car tree))
+(define tree-left (tree) (car (cdr tree)))
+(define tree-right (tree) (car (cdr (cdr tree))))
+
+(define sample-tree (make-tree 5
+                              (make-tree 3 nil nil)
+                              (make-tree 7 nil nil)))
+
+(tree-value sample-tree)
+(tree-value (tree-left sample-tree))
+(tree-value (tree-right sample-tree)) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/integration/function_composition.scm b/awk/scheme/scheme/test/integration/function_composition.scm
new file mode 100644
index 0000000..7009888
--- /dev/null
+++ b/awk/scheme/scheme/test/integration/function_composition.scm
@@ -0,0 +1,9 @@
+; Defining and using functions together
+
+(define add (x y) (+ x y))
+(define multiply (x y) (* x y))
+(define square (x) (multiply x x))
+(define add-square (x y) (add (square x) (square y)))
+(add-square 3 4)
+(define result (add-square 5 12))
+result
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/integration/higher_order_functions.scm b/awk/scheme/scheme/test/integration/higher_order_functions.scm
new file mode 100644
index 0000000..99d40e9
--- /dev/null
+++ b/awk/scheme/scheme/test/integration/higher_order_functions.scm
@@ -0,0 +1,55 @@
+;; Integration test for higher-order functions with complex scenarios
+
+;; Test 1: Data processing pipeline
+(define numbers (list 1 2 3 4 5 6 7 8 9 10))
+
+;; Filter even numbers, then double them
+(define even-doubled (map (lambda (x) (* x 2)) 
+                         (filter (lambda (x) (= (modulo x 2) 0)) numbers)))
+(assert (= (length even-doubled) 5))
+(assert (= (car even-doubled) 4))   ; 2 * 2
+(assert (= (cadr even-doubled) 8))  ; 4 * 2
+(assert (= (caddr even-doubled) 12)) ; 6 * 2
+
+;; Test 2: Complex predicate composition
+(define between-5-and-15 (lambda (x) (and (> x 5) (< x 15))))
+(define add-10 (lambda (x) (+ x 10)))
+(define filtered-and-transformed (map add-10 
+                                     (filter between-5-and-15 numbers)))
+(assert (= (length filtered-and-transformed) 4))
+(assert (= (car filtered-and-transformed) 16))  ; 6 + 10
+(assert (= (cadr filtered-and-transformed) 17)) ; 7 + 10
+
+;; Test 3: Multiple transformation stages
+(define pipeline-result (map (lambda (x) (* x 3))
+                            (map (lambda (x) (+ x 1))
+                                 (filter (lambda (x) (> x 5)) numbers))))
+(assert (= (length pipeline-result) 5))
+(assert (= (car pipeline-result) 21))  ; (6 + 1) * 3
+(assert (= (cadr pipeline-result) 24)) ; (7 + 1) * 3
+
+;; Test 4: Function composition with user-defined functions
+(define square (lambda (x) (* x x)))
+(define squares-of-odds (map square 
+                             (filter (lambda (x) (= (modulo x 2) 1)) numbers)))
+(assert (= (length squares-of-odds) 5))
+(assert (= (car squares-of-odds) 1))   ; 1^2
+(assert (= (cadr squares-of-odds) 9))  ; 3^2
+(assert (= (caddr squares-of-odds) 25)) ; 5^2
+
+;; Test 5: Nested higher-order functions
+(define make-filter (lambda (predicate) 
+  (lambda (list) (filter predicate list))))
+
+(define make-mapper (lambda (transform)
+  (lambda (list) (map transform list))))
+
+(define filter-evens (make-filter (lambda (x) (= (modulo x 2) 0))))
+(define double-all (make-mapper (lambda (x) (* x 2))))
+
+(define result (double-all (filter-evens numbers)))
+(assert (= (length result) 5))
+(assert (= (car result) 4))   ; 2 * 2
+(assert (= (cadr result) 8))  ; 4 * 2
+
+(display "Higher-order functions integration test passed!\n") 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/integration/list_operations.scm b/awk/scheme/scheme/test/integration/list_operations.scm
new file mode 100644
index 0000000..3a82919
--- /dev/null
+++ b/awk/scheme/scheme/test/integration/list_operations.scm
@@ -0,0 +1,10 @@
+; List operations and function definitions
+
+(define make-list (x y z) (cons x (cons y (cons z nil))))
+(define first (lst) (car lst))
+(define second (lst) (car (cdr lst)))
+(define third (lst) (car (cdr (cdr lst))))
+(define my-list (make-list 1 2 3))
+(first my-list)
+(second my-list)
+(third my-list) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/integration/string_operations.scm b/awk/scheme/scheme/test/integration/string_operations.scm
new file mode 100644
index 0000000..72a19d9
--- /dev/null
+++ b/awk/scheme/scheme/test/integration/string_operations.scm
@@ -0,0 +1,9 @@
+; String operations and variable bindings
+
+(define greeting "Hello")
+(define name "World")
+(string-append greeting ", " name "!")
+(define message (string-append greeting ", " name "!"))
+(string-length message)
+(string-ref message 0)
+(substring message 0 5) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/regression/edge_cases.scm b/awk/scheme/scheme/test/regression/edge_cases.scm
new file mode 100644
index 0000000..7794ede
--- /dev/null
+++ b/awk/scheme/scheme/test/regression/edge_cases.scm
@@ -0,0 +1,21 @@
+; Tests that might catch regressions ¯\_༼ ಠ_ಠ ༽_/¯
+
+; Empty string
+(string-length "")
+(string-append "" "")
+
+; Single character
+(string-length "a")
+(string-ref "a" 0)
+
+; Zero and negative numbers
+(+ 0 0)
+(- 0)
+(* 0 5)
+(/ 0 5)
+
+; Nil
+nil
+(cons 1 nil)
+(car (cons 1 nil))
+(cdr (cons 1 nil)) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/regression/nested_expressions.scm b/awk/scheme/scheme/test/regression/nested_expressions.scm
new file mode 100644
index 0000000..c564f29
--- /dev/null
+++ b/awk/scheme/scheme/test/regression/nested_expressions.scm
@@ -0,0 +1,15 @@
+; Nested expressions that have caused issues before
+
+(+ (+ (+ 1 2) (+ 3 4)) (+ (+ 5 6) (+ 7 8)))
+
+(define add (x y) (+ x y))
+(define double (x) (* x 2))
+(double (add 3 4))
+
+(let ((x 10))
+  (let ((y 20))
+    (let ((z 30))
+      (+ x (+ y z)))))
+
+(string-append "a" (string-append "b" "c"))
+(string-length (string-append "hello" " banana")) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/run_tests.sh b/awk/scheme/scheme/test/run_tests.sh
new file mode 100755
index 0000000..b32d57b
--- /dev/null
+++ b/awk/scheme/scheme/test/run_tests.sh
@@ -0,0 +1,189 @@
+#!/bin/bash
+
+# Awk-Scheme Test Runner
+# Runs all tests and reports results
+
+# set -e  # Exit on any error - commented out to allow all tests to run
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+BLUE='\033[0;34m'
+NC='\033[0m' # No Color
+
+# Test counters
+TOTAL_TESTS=0
+PASSED_TESTS=0
+FAILED_TESTS=0
+FAILED_TEST_NAMES=()
+
+# Get the project root directory
+PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+SCHEME_BIN="$PROJECT_ROOT/scheme"
+
+# Debug flag
+DEBUG=${DEBUG:-0}
+
+# Function to print colored output
+print_status() {
+    local status=$1
+    local message=$2
+    case $status in
+        "PASS")
+            echo -e "${GREEN}✓ PASS${NC}: $message"
+            ;;
+        "FAIL")
+            echo -e "${RED}✗ FAIL${NC}: $message"
+            ;;
+        "INFO")
+            echo -e "${BLUE}ℹ INFO${NC}: $message"
+            ;;
+        "WARN")
+            echo -e "${YELLOW}⚠ WARN${NC}: $message"
+            ;;
+    esac
+}
+
+# Function to run a single test
+run_test() {
+    local test_file=$1
+    local test_name=$(basename "$test_file" .scm)
+    local rel_test_file=${test_file#$PROJECT_ROOT/}
+    
+    TOTAL_TESTS=$((TOTAL_TESTS + 1))
+    
+    print_status "INFO" "Running test: $test_name"
+    
+    # Check if test file exists
+    if [ ! -f "$test_file" ]; then
+        print_status "FAIL" "Test file not found: $test_file"
+        FAILED_TESTS=$((FAILED_TESTS + 1))
+        return 1
+    fi
+    
+    # Run the test
+    local output
+    local exit_code
+    
+    if [ "$DEBUG" = "1" ]; then
+        # Run with debug output
+        output=$(env DEBUG=1 timeout 15s stdbuf -oL "$SCHEME_BIN" "$test_file" 2>&1)
+        exit_code=$?
+    else
+        # Run normally
+        output=$(timeout 15s stdbuf -oL "$SCHEME_BIN" "$test_file" 2>&1)
+        exit_code=$?
+    fi
+
+    # Check for timeout (exit code 124)
+    if [ $exit_code -eq 124 ]; then
+        print_status "FAIL" "$test_name (timeout)"
+        FAILED_TESTS=$((FAILED_TESTS + 1))
+        FAILED_TEST_NAMES+=("$rel_test_file")
+        echo "Error: Test timed out after 15 seconds."
+        echo
+        return 1
+    fi
+    
+    # Check if test passed (exit code 0)
+    if [ $exit_code -eq 0 ]; then
+        print_status "PASS" "$test_name"
+        PASSED_TESTS=$((PASSED_TESTS + 1))
+        
+        if [ "$DEBUG" = "1" ]; then
+            echo "Output:"
+            echo "$output" | sed 's/^/  /'
+            echo
+        fi
+    else
+        print_status "FAIL" "$test_name (exit code: $exit_code)"
+        FAILED_TESTS=$((FAILED_TESTS + 1))
+        FAILED_TEST_NAMES+=("$rel_test_file")
+        
+        echo "Error output:"
+        echo "$output" | sed 's/^/  /'
+        echo
+    fi
+}
+
+# Function to run all tests in a directory
+run_test_directory() {
+    local dir=$1
+    local dir_name=$(basename "$dir")
+    
+    echo
+    print_status "INFO" "Running tests in: $dir_name"
+    echo "=================================="
+    
+    if [ ! -d "$dir" ]; then
+        print_status "WARN" "Directory not found: $dir"
+        return
+    fi
+    
+    # Find all .scm files in the directory
+    local test_files=($(find "$dir" -name "*.scm" -type f | sort))
+    
+    if [ ${#test_files[@]} -eq 0 ]; then
+        print_status "WARN" "No test files found in $dir"
+        return
+    fi
+    
+    for test_file in "${test_files[@]}"; do
+        run_test "$test_file"
+    done
+}
+
+# Function to print summary
+print_summary() {
+    echo
+    echo "=================================="
+    print_status "INFO" "Test Summary"
+    echo "=================================="
+    echo "Total tests: $TOTAL_TESTS"
+    echo -e "Passed: ${GREEN}$PASSED_TESTS${NC}"
+    echo -e "Failed: ${RED}$FAILED_TESTS${NC}"
+    
+    if [ $FAILED_TESTS -eq 0 ]; then
+        echo -e "${GREEN}All tests passed!${NC}"
+        exit 0
+    else
+        echo -e "${RED}Some tests failed!${NC}"
+        echo
+        echo "Failed tests:"
+        for test_path in "${FAILED_TEST_NAMES[@]}"; do
+            echo -e "  ${RED}✗${NC} $test_path"
+        done
+        exit 1
+    fi
+}
+
+# Main execution
+main() {
+    echo "Awk-Scheme Test Runner"
+    echo "====================="
+    echo "Project root: $PROJECT_ROOT"
+    echo "Scheme binary: $SCHEME_BIN"
+    echo "Debug mode: $DEBUG"
+    echo
+    
+    # Check if scheme binary exists
+    if [ ! -f "$SCHEME_BIN" ]; then
+        print_status "FAIL" "Scheme binary not found: $SCHEME_BIN"
+        exit 1
+    fi
+    
+    # Make sure it's executable
+    chmod +x "$SCHEME_BIN"
+    
+    # Run tests in order of importance
+    run_test_directory "$PROJECT_ROOT/test/unit"
+    run_test_directory "$PROJECT_ROOT/test/integration"
+    run_test_directory "$PROJECT_ROOT/test/examples"
+    run_test_directory "$PROJECT_ROOT/test/regression"
+    
+    print_summary
+}
+
+# Run main function
+main "$@" 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/additional_lists.scm b/awk/scheme/scheme/test/unit/additional_lists.scm
new file mode 100644
index 0000000..369f26d
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/additional_lists.scm
@@ -0,0 +1,24 @@
+;; Even more list utilities
+
+(list)
+(list 1)
+(list 1 2)
+(list 1 2 3)
+(list "a" "b" "c")
+
+(reverse nil)
+(reverse (list 1))
+(reverse (list 1 2))
+(reverse (list 1 2 3))
+(reverse (list "a" "b" "c"))
+
+(member 1 nil)
+(member 1 (list 1))
+(member 2 (list 1 2 3))
+(member 4 (list 1 2 3))
+(member "a" (list "a" "b" "c"))
+(member "d" (list "a" "b" "c"))
+
+(reverse (list 1 2 3))
+(member 2 (reverse (list 1 2 3)))
+(list (car (member 2 (list 1 2 3))) (cadr (member 2 (list 1 2 3)))) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/advanced_control_flow.scm b/awk/scheme/scheme/test/unit/advanced_control_flow.scm
new file mode 100644
index 0000000..0b37d4c
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/advanced_control_flow.scm
@@ -0,0 +1,46 @@
+;; Advanced Control Flow Tests
+;; Tests for complex control flow patterns
+
+;; Nested if expressions
+(if (if #t #f #t) "nested-true" "nested-false")
+(if (if #f #t #f) "nested-true" "nested-false")
+
+;; Complex cond expressions
+(cond ((< 5 3) "first")
+      ((> 10 5) "second")
+      ((= 2 2) "third")
+      (else "else"))
+
+(cond ((= 1 2) "first")
+      ((= 2 3) "second")
+      ((= 3 4) "third")
+      (else "else"))
+
+;; Multiple conditions in cond
+(cond ((and #t #f) "and-false")
+      ((or #f #t) "or-true")
+      ((not #f) "not-true")
+      (else "else"))
+
+;; Short-circuit evaluation with side effects
+(and #f (display "should-not-print"))
+(or #t (display "should-not-print"))
+
+;; Complex boolean expressions
+(and (or #f #t) (and #t #t))
+(or (and #f #f) (or #t #f))
+(not (and #t #f))
+(not (or #f #f))
+
+;; Nested boolean expressions
+(if (and (or #t #f) (and #t #t)) "complex-true" "complex-false")
+(if (or (and #f #f) (or #t #f)) "complex-true" "complex-false")
+
+;; Conditional with function calls
+(if (= (+ 2 3) 5) "math-true" "math-false")
+(if (< (* 3 4) 10) "math-true" "math-false")
+
+;; Multiple nested conditions
+(cond ((< 1 2) (if (> 3 2) "nested-true" "nested-false"))
+      ((> 5 3) "second")
+      (else "else")) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/advanced_functions.scm b/awk/scheme/scheme/test/unit/advanced_functions.scm
new file mode 100644
index 0000000..fb707b9
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/advanced_functions.scm
@@ -0,0 +1,68 @@
+;; Advanced Function Tests
+;; Tests for complex function patterns
+
+;; Recursive functions
+(define factorial (n)
+  (if (= n 0)
+      1
+      (* n (factorial (- n 1)))))
+
+(factorial 5)
+(factorial 0)
+
+;; Nested function definitions
+(define outer (x)
+  (define inner (y)
+    (+ x y))
+  (inner 10))
+
+(outer 5)
+
+;; Higher-order functions (functions that return functions)
+(define make-adder (n)
+  (lambda (x) (+ n x)))
+
+(define add5 (make-adder 5))
+(add5 3)
+
+;; Function composition
+(define compose (f g)
+  (lambda (x) (f (g x))))
+
+(define double (x) (* x 2))
+(define square (x) (* x x))
+(define double-square (compose double square))
+(double-square 3)
+
+;; Variable argument functions (testing existing string-append)
+(string-append "a" "b" "c" "d")
+(string-append "hello" " " "world" "!")
+
+;; Functions with complex bodies
+(define complex-func (x y)
+  (if (> x y)
+      (+ x (* y 2))
+      (if (= x y)
+          (* x y)
+          (- y x))))
+
+(complex-func 10 5)
+(complex-func 5 5)
+(complex-func 3 7)
+
+;; Functions that use multiple standard library functions
+(define list-processor (lst)
+  (if (null? lst)
+      0
+      (+ (car lst) (list-processor (cdr lst)))))
+
+(list-processor (cons 1 (cons 2 (cons 3 nil))))
+
+;; Functions with side effects
+(define side-effect-func (x)
+  (display "processing: ")
+  (display x)
+  (display "\n")
+  (* x 2))
+
+(side-effect-func 5) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/basic_higher_order_functions.scm b/awk/scheme/scheme/test/unit/basic_higher_order_functions.scm
new file mode 100644
index 0000000..d16d104
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/basic_higher_order_functions.scm
@@ -0,0 +1,24 @@
+(define nums (list 1 2 3 4 5))
+(define doubled (map abs nums))
+(assert (= (length doubled) 5))
+(assert (= (car doubled) 1))
+(assert (= (cadr doubled) 2))
+
+(define mixed (list -1 2 -3 4 -5))
+(define positive-nums (filter positive? mixed))
+(assert (= (length positive-nums) 2))
+(assert (= (car positive-nums) 2))
+(assert (= (cadr positive-nums) 4))
+
+(define absolute-positive (map abs (filter positive? mixed)))
+(assert (= (length absolute-positive) 2))
+(assert (= (car absolute-positive) 2))
+(assert (= (cadr absolute-positive) 4))
+
+(define filtered-then-mapped (map abs (filter negative? mixed)))
+(assert (= (length filtered-then-mapped) 3))
+(assert (= (car filtered-then-mapped) 1))
+(assert (= (cadr filtered-then-mapped) 3))
+(assert (= (caddr filtered-then-mapped) 5))
+
+(display "Map and filter comprehensive test passed!\n") 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/basic_map_operations.scm b/awk/scheme/scheme/test/unit/basic_map_operations.scm
new file mode 100644
index 0000000..3dc244c
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/basic_map_operations.scm
@@ -0,0 +1,15 @@
+(define nums (list 1 2 3 4 5))
+(define doubled (map abs nums))
+(assert (= (length doubled) 5))
+(assert (= (car doubled) 1))
+(assert (= (cadr doubled) 2))
+(assert (= (caddr doubled) 3))
+
+(define negative-nums (list -1 -2 -3))
+(define absolute-nums (map abs negative-nums))
+(assert (= (length absolute-nums) 3))
+(assert (= (car absolute-nums) 1))
+(assert (= (cadr absolute-nums) 2))
+(assert (= (caddr absolute-nums) 3))
+
+(display "Map with built-in functions test passed!\n") 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/basic_numeric_operations.scm b/awk/scheme/scheme/test/unit/basic_numeric_operations.scm
new file mode 100644
index 0000000..7c58ef1
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/basic_numeric_operations.scm
@@ -0,0 +1,40 @@
+(assert (= (modulo 17 5) 2))
+(assert (= (modulo -17 5) 3))
+(assert (= (% 17 5) 2))
+
+(assert (= (expt 2 3) 8))
+(assert (= (expt 5 0) 1))
+
+(assert (= (abs 5) 5))
+(assert (= (abs -5) 5))
+(assert (= (abs 0) 0))
+
+(assert (= (min 3 7) 3))
+(assert (= (max 3 7) 7))
+
+(assert (number? 42))
+(assert (not (number? "hello")))
+(assert (string? "hello"))
+(assert (not (string? 42)))
+(assert (boolean? #t))
+(assert (not (boolean? 42)))
+
+(assert (zero? 0))
+(assert (not (zero? 1)))
+(assert (positive? 1))
+(assert (not (positive? -1)))
+(assert (negative? -1))
+(assert (not (negative? 1)))
+
+(define double (lambda (x) (* x 2)))
+(define nums (list 1 2 3))
+(define doubled (map double nums))
+(assert (= (length doubled) 3))
+(assert (= (car doubled) 2))
+
+(define even? (lambda (x) (= (modulo x 2) 0)))
+(define evens (filter even? nums))
+(assert (= (length evens) 1))
+(assert (= (car evens) 2))
+
+(display "All new function tests passed!\n") 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/basic_stdlib_test.scm b/awk/scheme/scheme/test/unit/basic_stdlib_test.scm
new file mode 100644
index 0000000..da6bbbe
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/basic_stdlib_test.scm
@@ -0,0 +1,4 @@
+(null? nil)
+(pair? (cons 1 2))
+(length (cons 1 (cons 2 nil)))
+(cadr (cons 1 (cons 2 (cons 3 nil)))) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/booleans.scm b/awk/scheme/scheme/test/unit/booleans.scm
new file mode 100644
index 0000000..2443201
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/booleans.scm
@@ -0,0 +1,6 @@
+(= 1 1)
+(= 1 2)
+(< 1 2)
+(< 2 1)
+(> 5 3)
+(> 3 5)
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/caddr_test.scm b/awk/scheme/scheme/test/unit/caddr_test.scm
new file mode 100644
index 0000000..66e0988
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/caddr_test.scm
@@ -0,0 +1 @@
+(caddr (cons 1 (cons 2 (cons 3 nil)))) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/call_stack_infrastructure.scm b/awk/scheme/scheme/test/unit/call_stack_infrastructure.scm
new file mode 100644
index 0000000..090ad43
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/call_stack_infrastructure.scm
@@ -0,0 +1,6 @@
+(assert (= (abs 5) 5))
+(assert (= (modulo 17 5) 2))
+(assert (number? 42))
+(assert (positive? 10))
+
+(display "Call stack infrastructure test passed!\n") 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/closures.scm b/awk/scheme/scheme/test/unit/closures.scm
new file mode 100644
index 0000000..7f3c5ec
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/closures.scm
@@ -0,0 +1,3 @@
+(let ((x 10)) ((lambda (y) (+ x y)) 32))
+(let ((add1 (lambda (x) (+ x 1)))) (add1 41))
+(let ((x 5)) (let ((f (lambda (y) (+ x y)))) (f 10))) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/comprehensive_higher_order_functions.scm b/awk/scheme/scheme/test/unit/comprehensive_higher_order_functions.scm
new file mode 100644
index 0000000..d204775
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/comprehensive_higher_order_functions.scm
@@ -0,0 +1,52 @@
+(define nums (list 1 2 3 4 5))
+(define absolute-nums (map abs (list -1 -2 -3)))
+(assert (= (length absolute-nums) 3))
+(assert (= (car absolute-nums) 1))
+(assert (= (cadr absolute-nums) 2))
+(assert (= (caddr absolute-nums) 3))
+
+(define mixed (list -1 2 -3 4 -5))
+(define positive-nums (filter positive? mixed))
+(assert (= (length positive-nums) 2))
+(assert (= (car positive-nums) 2))
+(assert (= (cadr positive-nums) 4))
+
+(define double (lambda (x) (* x 2)))
+(define doubled (map double nums))
+(assert (= (length doubled) 5))
+(assert (= (car doubled) 2))
+(assert (= (cadr doubled) 4))
+(assert (= (caddr doubled) 6))
+
+(define even? (lambda (x) (= (modulo x 2) 0)))
+(define evens (filter even? nums))
+(assert (= (length evens) 2))
+(assert (= (car evens) 2))
+(assert (= (cadr evens) 4))
+
+(define add-one (lambda (x) (+ x 1)))
+(define incremented (map add-one nums))
+(assert (= (length incremented) 5))
+(assert (= (car incremented) 2))
+(assert (= (cadr incremented) 3))
+
+(define greater-than-3 (lambda (x) (> x 3)))
+(define large-nums (filter greater-than-3 nums))
+(assert (= (length large-nums) 2))
+(assert (= (car large-nums) 4))
+(assert (= (cadr large-nums) 5))
+
+(define complex-result (map double (filter even? nums)))
+(assert (= (length complex-result) 2))
+(assert (= (car complex-result) 4))
+(assert (= (cadr complex-result) 8))
+
+(define add-one (lambda (x) (+ x 1)))
+(define double (lambda (x) (* x 2)))
+(define triple (lambda (x) (* x 3)))
+(define processed (map triple (map double (map add-one nums))))
+(assert (= (length processed) 5))
+(assert (= (car processed) 12))
+(assert (= (cadr processed) 18))
+
+(display "All map and filter tests passed!\n") 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/comprehensive_numeric_and_type_operations.scm b/awk/scheme/scheme/test/unit/comprehensive_numeric_and_type_operations.scm
new file mode 100644
index 0000000..2c07a85
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/comprehensive_numeric_and_type_operations.scm
@@ -0,0 +1,174 @@
+;; Test file for new functions: numeric operations, type predicates, and list operations
+
+;; Test essential numeric operations
+(assert (= (modulo 17 5) 2))
+(assert (= (modulo -17 5) 3))
+(assert (= (modulo 17 -5) 2))
+(assert (= (% 17 5) 2))  ; Test alias
+
+(assert (= (expt 2 3) 8))
+(assert (= (expt 5 0) 1))
+(assert (= (expt 2 10) 1024))
+
+(assert (= (abs 5) 5))
+(assert (= (abs -5) 5))
+(assert (= (abs 0) 0))
+
+(assert (= (min 3 7) 3))
+(assert (= (min 7 3) 3))
+(assert (= (min -5 10) -5))
+(assert (= (min 5 5) 5))
+
+(assert (= (max 3 7) 7))
+(assert (= (max 7 3) 7))
+(assert (= (max -5 10) 10))
+(assert (= (max 5 5) 5))
+
+;; Test type predicates
+(assert (number? 42))
+(assert (number? -17))
+(assert (not (number? "hello")))
+(assert (not (number? #t)))
+(assert (not (number? nil)))
+
+(assert (string? "hello"))
+(assert (string? ""))
+(assert (not (string? 42)))
+(assert (not (string? #t)))
+(assert (not (string? nil)))
+
+(assert (boolean? #t))
+(assert (boolean? #f))
+(assert (not (boolean? 42)))
+(assert (not (boolean? "hello")))
+(assert (not (boolean? nil)))
+
+;; Note: symbol? test commented out until quote is implemented
+;; (assert (symbol? 'hello))
+;; (assert (not (symbol? 42)))
+;; (assert (not (symbol? "hello")))
+;; (assert (not (symbol? #t)))
+;; (assert (not (symbol? nil)))
+
+;; Test numeric predicates
+(assert (zero? 0))
+(assert (not (zero? 1)))
+(assert (not (zero? -1)))
+
+(assert (positive? 1))
+(assert (positive? 42))
+(assert (not (positive? 0)))
+(assert (not (positive? -1)))
+
+(assert (negative? -1))
+(assert (negative? -42))
+(assert (not (negative? 0)))
+(assert (not (negative? 1)))
+
+;; Test list operations: map
+(define double (lambda (x) (* x 2)))
+(define square (lambda (x) (* x x)))
+(define even? (lambda (x) (= (modulo x 2) 0)))
+
+(define nums (list 1 2 3 4 5))
+(define doubled (map double nums))
+(assert (= (length doubled) 5))
+(assert (= (car doubled) 2))
+(assert (= (cadr doubled) 4))
+(assert (= (caddr doubled) 6))
+
+(define squared (map square nums))
+(assert (= (car squared) 1))
+(assert (= (cadr squared) 4))
+(assert (= (caddr squared) 9))
+
+;; Test list operations: filter
+(define evens (filter even? nums))
+(assert (= (length evens) 2))
+(assert (= (car evens) 2))
+(assert (= (cadr evens) 4))
+
+(define odds (filter (lambda (x) (not (even? x))) nums))
+(assert (= (length odds) 3))
+(assert (= (car odds) 1))
+(assert (= (cadr odds) 3))
+(assert (= (caddr odds) 5))
+
+;; Test empty list handling
+(assert (null? (map double nil)))
+(assert (null? (filter even? nil)))
+
+;; Test complex combinations
+(define mixed (list 1 "hello" 3 #t 5))
+(define numbers-only (filter number? mixed))
+(assert (= (length numbers-only) 3))
+(assert (= (car numbers-only) 1))
+(assert (= (cadr numbers-only) 3))
+(assert (= (caddr numbers-only) 5))
+
+(define strings-only (filter string? mixed))
+(assert (= (length strings-only) 1))
+(assert (string=? (car strings-only) "hello"))
+
+;; Test nested operations
+(define nested (list (list 1 2) (list 3 4) (list 5 6)))
+(define lengths (map length nested))
+(assert (= (car lengths) 2))
+(assert (= (cadr lengths) 2))
+(assert (= (caddr lengths) 2))
+
+;; Test with higher-order functions
+(define add1 (lambda (x) (+ x 1)))
+(define range (list 1 2 3 4 5))
+(define incremented (map add1 range))
+(assert (= (car incremented) 2))
+(assert (= (cadr incremented) 3))
+(assert (= (caddr incremented) 4))
+
+;; Test edge cases
+(assert (= (abs -0) 0))
+(assert (= (min 1 1) 1))
+(assert (= (max 1 1) 1))
+(assert (= (modulo 0 5) 0))
+
+;; Test type checking with predicates
+(define test-list (list 1 "hello" #t nil))
+(assert (number? (car test-list)))
+(assert (string? (cadr test-list)))
+(assert (boolean? (caddr test-list)))
+(assert (null? (caddr test-list)))
+
+;; Test complex numeric operations
+(assert (= (expt (abs -2) 3) 8))
+(assert (= (modulo (expt 3 2) 4) 1))
+(assert (= (min (abs -5) (abs 3)) 3))
+(assert (= (max (abs -2) (abs 7)) 7))
+
+;; Test list operations with complex predicates
+(define complex-nums (list -5 0 3 -2 7))
+(define positive-nums (filter positive? complex-nums))
+(assert (= (length positive-nums) 2))
+(assert (= (car positive-nums) 3))
+(assert (= (cadr positive-nums) 7))
+
+(define negative-nums (filter negative? complex-nums))
+(assert (= (length negative-nums) 2))
+(assert (= (car negative-nums) -5))
+(assert (= (cadr negative-nums) -2))
+
+;; Test map with different return types
+(define type-names (map (lambda (x) 
+                          (cond 
+                            ((number? x) "number")
+                            ((string? x) "string")
+                            ((boolean? x) "boolean")
+                            ((null? x) "nil")
+                            (else "unknown"))) 
+                        test-list))
+(assert (string=? (car type-names) "number"))
+(assert (string=? (cadr type-names) "string"))
+(assert (string=? (caddr type-names) "boolean"))
+(assert (string=? (caddr type-names) "nil"))
+
+;; All tests passed!
+(display "All new function tests passed!\n") 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/control_flow.scm b/awk/scheme/scheme/test/unit/control_flow.scm
new file mode 100644
index 0000000..0a99b9a
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/control_flow.scm
@@ -0,0 +1,56 @@
+(if #t "true" "false")
+(if #f "true" "false")
+(if 0 "true" "false")
+(if 42 "true" "false")
+(if nil "true" "false")
+(if (cons 1 2) "true" "false")
+
+(cond (#t "first")
+      (#f "second")
+      (else "else"))
+
+(cond (#f "first")
+      (#t "second")
+      (else "else"))
+
+(cond (#f "first")
+      (#f "second")
+      (else "else"))
+
+(and)
+(and #t)
+(and #f)
+(and #t #t)
+(and #t #f)
+(and #f #t)
+(and #f #f)
+(and #t #t #t)
+(and #t #f #t)
+
+(or)
+(or #t)
+(or #f)
+(or #t #t)
+(or #t #f)
+(or #f #t)
+(or #f #f)
+(or #f #f #t)
+(or #f #f #f)
+
+(not #t)
+(not #f)
+(not 0)
+(not 42)
+(not nil)
+(not (cons 1 2))
+
+(if (and #t #f) "and-true" "and-false")
+(if (or #f #t) "or-true" "or-false")
+(if (not #t) "not-true" "not-false")
+
+(cond ((and #t #t) "and-true")
+      ((or #f #f) "or-false")
+      (else "else"))
+
+(and #f (error "should not evaluate"))
+(or #t (error "should not evaluate")) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/environment_scoping.scm b/awk/scheme/scheme/test/unit/environment_scoping.scm
new file mode 100644
index 0000000..3d208cf
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/environment_scoping.scm
@@ -0,0 +1,66 @@
+;; Environment and Scoping Tests
+;; Tests for lexical scoping, variable shadowing, and environment management
+
+;; Variable shadowing
+(define x 10)
+(let ((x 20))
+  x)
+x
+
+;; Nested let expressions
+(let ((x 1))
+  (let ((y 2))
+    (let ((z 3))
+      (+ x (+ y z)))))
+
+;; Shadowing in nested environments
+(define global 100)
+(let ((global 200))
+  (let ((global 300))
+    global)
+  global)
+global
+
+;; Function parameter shadowing
+(define shadow-test (x)
+  (let ((x (+ x 10)))
+    x))
+
+(shadow-test 5)
+
+;; Complex nested scoping
+(let ((a 1))
+  (let ((b (+ a 1)))
+    (let ((c (+ b 1)))
+      (let ((a (+ c 1)))  ;; shadows outer a
+        (+ a b c)))))
+
+;; Environment persistence in closures
+(define make-counter ()
+  (let ((count 0))
+    (lambda ()
+      (let ((old-count count))
+        (let ((count (+ count 1)))  ;; shadows outer count
+          old-count)))))
+
+(define counter (make-counter))
+(counter)
+(counter)
+(counter)
+
+;; Multiple closures sharing environment
+(define make-pair (x y)
+  (let ((get-x (lambda () x))
+        (get-y (lambda () y))
+        (set-x (lambda (new-x) (let ((x new-x)) x))))
+    (list get-x get-y set-x)))
+
+;; Complex environment nesting with functions
+(define outer-env (x)
+  (define inner-env (y)
+    (define deepest-env (z)
+      (+ x (+ y z)))
+    (deepest-env 1))
+  (inner-env 2))
+
+(outer-env 3) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/error_handling.scm b/awk/scheme/scheme/test/unit/error_handling.scm
new file mode 100644
index 0000000..28f105d
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/error_handling.scm
@@ -0,0 +1,42 @@
+;; Error Handling and Edge Cases Tests
+;; Tests for proper error handling and edge cases
+
+;; Division by zero
+(/ 10 0)
+
+;; Stack underflow scenarios
+;; These should error when stack is empty
+(car nil)
+(cdr nil)
+(car (cons 1 nil))
+(cdr (cons 1 nil))
+
+;; Type errors
+(car 42)
+(cdr "hello")
+(cons 1 2 3)  ;; cons should take exactly 2 arguments
+
+;; Invalid function calls
+(+ 1)  ;; + needs at least 2 arguments
+(* 5)  ;; * needs at least 2 arguments
+(string-ref "hello")  ;; string-ref needs 2 arguments
+(string-ref "hello" 10)  ;; index out of bounds
+
+;; List operations on non-lists
+(length 42)
+(length "hello")
+(null? 42)
+(pair? "hello")
+
+;; Standard library edge cases
+(list-ref nil 0)
+(list-ref (cons 1 nil) 5)
+(list-tail nil 1)
+(cadr nil)
+(caddr (cons 1 (cons 2 nil)))
+
+;; Invalid string operations
+(string-ref "" 0)
+(string-ref "a" 1)
+(substring "hello" 3 1)  ;; start > end
+(substring "hello" 10 15)  ;; out of bounds 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/essential_numeric_operations.scm b/awk/scheme/scheme/test/unit/essential_numeric_operations.scm
new file mode 100644
index 0000000..0f0105b
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/essential_numeric_operations.scm
@@ -0,0 +1,29 @@
+(assert (= (modulo 17 5) 2))
+(assert (= (modulo -17 5) 3))
+(assert (= (% 17 5) 2))
+
+(assert (= (expt 2 3) 8))
+(assert (= (expt 5 0) 1))
+
+(assert (= (abs 5) 5))
+(assert (= (abs -5) 5))
+(assert (= (abs 0) 0))
+
+(assert (= (min 3 7) 3))
+(assert (= (max 3 7) 7))
+
+(assert (number? 42))
+(assert (not (number? "hello")))
+(assert (string? "hello"))
+(assert (not (string? 42)))
+(assert (boolean? #t))
+(assert (not (boolean? 42)))
+
+(assert (zero? 0))
+(assert (not (zero? 1)))
+(assert (positive? 1))
+(assert (not (positive? -1)))
+(assert (negative? -1))
+(assert (not (negative? 1)))
+
+(display "All basic new function tests passed!\n") 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/functions.scm b/awk/scheme/scheme/test/unit/functions.scm
new file mode 100644
index 0000000..43b3a71
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/functions.scm
@@ -0,0 +1,8 @@
+(define add (x y) (+ x y))
+(add 2 3)
+(define double (x) (* x 2))
+(double 5)
+(define square (x) (* x x))
+(square 4)
+(define add-three (x y z) (+ x (+ y z)))
+(add-three 1 2 3) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/inc_alias_test.scm b/awk/scheme/scheme/test/unit/inc_alias_test.scm
new file mode 100644
index 0000000..cf7ae94
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/inc_alias_test.scm
@@ -0,0 +1,13 @@
+(assert (= (inc 41) 42))
+(assert (= (inc 0) 1))
+(assert (= (inc -1) 0))
+
+;; Test ++ alias
+(assert (= (++ 41) 42))
+(assert (= (++ 0) 1))
+(assert (= (++ -1) 0))
+
+;; Test that both inc and ++ are the same function
+(assert (= (inc 10) (++ 10)))
+(assert (= (inc 999) 1000))
+(assert (= (++ 999) 1000))
diff --git a/awk/scheme/scheme/test/unit/lambdas.scm b/awk/scheme/scheme/test/unit/lambdas.scm
new file mode 100644
index 0000000..a287b47
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/lambdas.scm
@@ -0,0 +1,4 @@
+((lambda (x) (+ x 1)) 41)
+((lambda (x y) (+ x y)) 20 22)
+(define add1 (lambda (x) (+ x 1)))
+(add1 41) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/let.scm b/awk/scheme/scheme/test/unit/let.scm
new file mode 100644
index 0000000..f3fa367
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/let.scm
@@ -0,0 +1,3 @@
+(let ((x 10) (y 20)) (+ x y))
+(let ((x 5)) (* x x))
+(let ((x 10)) (let ((y 20)) (+ x y))) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/lists.scm b/awk/scheme/scheme/test/unit/lists.scm
new file mode 100644
index 0000000..bc7b7f4
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/lists.scm
@@ -0,0 +1,7 @@
+(cons 1 2)
+(car (cons 1 2))
+(cdr (cons 1 2))
+(cons 1 (cons 2 (cons 3 nil)))
+(car (cons 1 (cons 2 (cons 3 nil))))
+(car (cdr (cons 1 (cons 2 (cons 3 nil)))))
+(car (cdr (cdr (cons 1 (cons 2 (cons 3 nil)))))) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/minimal_closure_env.scm b/awk/scheme/scheme/test/unit/minimal_closure_env.scm
new file mode 100644
index 0000000..a7de816
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/minimal_closure_env.scm
@@ -0,0 +1,8 @@
+(define make-outer
+  (lambda (x)
+    (lambda (y)
+      (let ((x (+ x y)))
+        (lambda (z) (+ x y z))))))
+
+(define closure1 ((make-outer 10) 5))
+(closure1 2) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/minimal_function_persistence.scm b/awk/scheme/scheme/test/unit/minimal_function_persistence.scm
new file mode 100644
index 0000000..c6825e4
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/minimal_function_persistence.scm
@@ -0,0 +1,2 @@
+(define add2 (lambda (x) (+ x 2)))
+(add2 40) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/minimal_global_persistence.scm b/awk/scheme/scheme/test/unit/minimal_global_persistence.scm
new file mode 100644
index 0000000..7b75b28
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/minimal_global_persistence.scm
@@ -0,0 +1,2 @@
+(define foo 42)
+foo 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/numbers.scm b/awk/scheme/scheme/test/unit/numbers.scm
new file mode 100644
index 0000000..b4f255c
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/numbers.scm
@@ -0,0 +1,9 @@
+(+ 1 2)
+(+ 10 20 30)
+(- 10 5)
+(- 5)
+(* 3 4)
+(* 2 3 4)
+(/ 10 2)
+(/ 20 4 2)
+(inc 41) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/performance_stress.scm b/awk/scheme/scheme/test/unit/performance_stress.scm
new file mode 100644
index 0000000..06b7f65
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/performance_stress.scm
@@ -0,0 +1,62 @@
+;; Performance and Stress Tests
+;; Tests for handling large data structures and deep recursion
+
+;; Large list construction
+(define make-large-list (n)
+  (if (= n 0)
+      nil
+      (cons n (make-large-list (- n 1)))))
+
+;; Test with moderately large list (not too large to avoid timeout)
+(make-large-list 10)
+
+;; Deep recursion test
+(define deep-recursion (n)
+  (if (= n 0)
+      0
+      (+ 1 (deep-recursion (- n 1)))))
+
+(deep-recursion 10)
+
+;; Complex nested expressions
+(+ (+ (+ 1 2) (+ 3 4)) (+ (+ 5 6) (+ 7 8)))
+
+;; Multiple function calls in sequence
+(define test-sequence (n)
+  (if (= n 0)
+      0
+      (+ n (test-sequence (- n 1)))))
+
+(test-sequence 5)
+
+;; String operations on larger strings
+(string-append "very" " " "long" " " "string" " " "with" " " "many" " " "parts")
+
+;; List operations on nested lists
+(define nested-list (cons 1 (cons (cons 2 (cons 3 nil)) (cons 4 nil))))
+(car (car (cdr nested-list)))
+
+;; Multiple arithmetic operations
+(+ (* (+ 1 2) (+ 3 4)) (- (* 5 6) (+ 7 8)))
+
+;; Complex boolean expressions
+(and (or #t #f) (and #t (or #f #t)) (not #f))
+
+;; Nested function calls
+(define outer (x)
+  (define middle (y)
+    (define inner (z)
+      (+ x (+ y z)))
+    (inner 1))
+  (middle 2))
+
+(outer 3)
+
+;; Memory stress with multiple large operations
+(define stress-test (n)
+  (if (= n 0)
+      0
+      (+ (length (make-large-list n))
+         (stress-test (- n 1)))))
+
+(stress-test 3)  ;; Keep small to avoid timeout 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/simple_additional_lists.scm b/awk/scheme/scheme/test/unit/simple_additional_lists.scm
new file mode 100644
index 0000000..e75c2bb
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/simple_additional_lists.scm
@@ -0,0 +1,9 @@
+(list)
+(list 1)
+(list 1 2)
+
+(reverse nil)
+(reverse (list 1))
+
+(member 1 nil)
+(member 1 (list 1)) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/simple_cond.scm b/awk/scheme/scheme/test/unit/simple_cond.scm
new file mode 100644
index 0000000..03dd9cd
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/simple_cond.scm
@@ -0,0 +1,4 @@
+;; Simple Cond Test
+
+;; Test cond with simple condition
+(cond (#t "true") (else "false")) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/simple_control_flow.scm b/awk/scheme/scheme/test/unit/simple_control_flow.scm
new file mode 100644
index 0000000..41df610
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/simple_control_flow.scm
@@ -0,0 +1,19 @@
+;; Simple Control Flow Tests
+
+;; Test if expressions
+(if #t "true" "false")
+(if #f "true" "false")
+
+;; Test and expressions
+(and #t #t)
+(and #t #f)
+(and #f #t)
+
+;; Test or expressions
+(or #t #t)
+(or #t #f)
+(or #f #t)
+
+;; Test not expressions
+(not #t)
+(not #f) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/simple_member.scm b/awk/scheme/scheme/test/unit/simple_member.scm
new file mode 100644
index 0000000..b2aa9d6
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/simple_member.scm
@@ -0,0 +1,5 @@
+;; Simple member test
+
+;; Test with pre-built list
+(define mylist (list 1))
+(member 1 mylist) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/simple_stdlib_test.scm b/awk/scheme/scheme/test/unit/simple_stdlib_test.scm
new file mode 100644
index 0000000..0bc7866
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/simple_stdlib_test.scm
@@ -0,0 +1,13 @@
+;; Simple test for standard library functions
+
+;; Test null? with nil
+(null? nil)
+
+;; Test null? with a pair
+(null? (cons 1 2))
+
+;; Test pair? with a pair
+(pair? (cons 1 2))
+
+;; Test pair? with nil
+(pair? nil) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/simple_string_append_test.scm b/awk/scheme/scheme/test/unit/simple_string_append_test.scm
new file mode 100644
index 0000000..52d9719
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/simple_string_append_test.scm
@@ -0,0 +1,11 @@
+;; Simple test for string-append with multiple arguments
+
+(display "Testing string-append with 3 arguments: ")
+(display (string-append "a" "b" "c"))
+(display "\n")
+
+(display "Testing string-append with 4 arguments: ")
+(display (string-append "Hello" " " "World" "!"))
+(display "\n")
+
+(display "Test completed!\n") 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/single_list.scm b/awk/scheme/scheme/test/unit/single_list.scm
new file mode 100644
index 0000000..325c710
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/single_list.scm
@@ -0,0 +1,4 @@
+;; Single list test
+
+;; Test with one element
+(list 1) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/stdlib_lists.scm b/awk/scheme/scheme/test/unit/stdlib_lists.scm
new file mode 100644
index 0000000..9a51809
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/stdlib_lists.scm
@@ -0,0 +1,55 @@
+;; Standard Library List Functions Tests
+;; Phase 1: Core list utilities
+
+;; Test null? function
+(null? nil)
+(null? (cons 1 2))
+(null? (cons 1 nil))
+
+;; Test pair? function
+(pair? (cons 1 2))
+(pair? nil)
+(pair? 42)
+(pair? "hello")
+
+;; Test length function
+(length nil)
+(length (cons 1 nil))
+(length (cons 1 (cons 2 nil)))
+(length (cons 1 (cons 2 (cons 3 nil))))
+
+;; Test list construction using cons
+(length (cons 1 (cons 2 (cons 3 nil))))
+
+;; Test cadr function
+(cadr (cons 1 (cons 2 (cons 3 nil))))
+(cadr (cons "a" (cons "b" nil)))
+
+;; Test caddr function
+(caddr (cons 1 (cons 2 (cons 3 nil))))
+(caddr (cons "x" (cons "y" (cons "z" nil))))
+
+;; Test list-ref function
+(list-ref (cons 1 (cons 2 (cons 3 nil))) 0)
+(list-ref (cons 1 (cons 2 (cons 3 nil))) 1)
+(list-ref (cons 1 (cons 2 (cons 3 nil))) 2)
+
+;; Test list-tail function
+(list-tail (cons 1 (cons 2 (cons 3 nil))) 0)
+(list-tail (cons 1 (cons 2 (cons 3 nil))) 1)
+(list-tail (cons 1 (cons 2 (cons 3 nil))) 2)
+(list-tail (cons 1 (cons 2 (cons 3 nil))) 3)
+
+;; Test append function
+(append nil (cons 1 (cons 2 nil)))
+(append (cons 1 (cons 2 nil)) nil)
+(append (cons 1 (cons 2 nil)) (cons 3 (cons 4 nil)))
+
+;; Test edge cases and error conditions
+;; These should produce errors:
+;; (cadr nil)
+;; (cadr (cons 1 nil))
+;; (caddr (cons 1 (cons 2 nil)))
+;; (list-ref nil 0)
+;; (list-ref (cons 1 nil) 5)
+;; (list-tail nil 1) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/stdlib_results_test.scm b/awk/scheme/scheme/test/unit/stdlib_results_test.scm
new file mode 100644
index 0000000..3a36ce5
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/stdlib_results_test.scm
@@ -0,0 +1,42 @@
+;; Test standard library functions
+
+;; Test null? function
+(null? nil)
+(null? (cons 1 2))
+(null? (cons 1 nil))
+
+;; Test pair? function
+(pair? (cons 1 2))
+(pair? nil)
+(pair? 42)
+(pair? "hello")
+
+;; Test length function
+(length nil)
+(length (cons 1 nil))
+(length (cons 1 (cons 2 nil)))
+(length (cons 1 (cons 2 (cons 3 nil))))
+
+;; Test cadr function
+(cadr (cons 1 (cons 2 (cons 3 nil))))
+(cadr (cons "a" (cons "b" nil)))
+
+;; Test caddr function
+(caddr (cons 1 (cons 2 (cons 3 nil))))
+(caddr (cons "x" (cons "y" (cons "z" nil))))
+
+;; Test list-ref function
+(list-ref (cons 1 (cons 2 (cons 3 nil))) 0)
+(list-ref (cons 1 (cons 2 (cons 3 nil))) 1)
+(list-ref (cons 1 (cons 2 (cons 3 nil))) 2)
+
+;; Test list-tail function
+(list-tail (cons 1 (cons 2 (cons 3 nil))) 0)
+(list-tail (cons 1 (cons 2 (cons 3 nil))) 1)
+(list-tail (cons 1 (cons 2 (cons 3 nil))) 2)
+(list-tail (cons 1 (cons 2 (cons 3 nil))) 3)
+
+;; Test append function
+(append nil (cons 1 (cons 2 nil)))
+(append (cons 1 (cons 2 nil)) nil)
+(append (cons 1 (cons 2 nil)) (cons 3 (cons 4 nil))) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/string_append_variable_args.scm b/awk/scheme/scheme/test/unit/string_append_variable_args.scm
new file mode 100644
index 0000000..ad53fb6
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/string_append_variable_args.scm
@@ -0,0 +1,54 @@
+;; Test string-append with variable arguments
+;; This test verifies that string-append can handle 2 or more arguments
+
+;; Test with 2 arguments (original functionality)
+(display "Testing 2 arguments: ")
+(display (string-append "hello" " world"))
+(display "\n")
+
+;; Test with 3 arguments
+(display "Testing 3 arguments: ")
+(display (string-append "a" "b" "c"))
+(display "\n")
+
+;; Test with 4 arguments
+(display "Testing 4 arguments: ")
+(display (string-append "Hello" " " "World" "!"))
+(display "\n")
+
+;; Test with 5 arguments
+(display "Testing 5 arguments: ")
+(display (string-append "The" " " "quick" " " "fox"))
+(display "\n")
+
+;; Test with empty strings
+(display "Testing empty strings: ")
+(display (string-append "" "" ""))
+(display "\n")
+
+;; Test with mixed content
+(display "Testing mixed content: ")
+(display (string-append "Number: " "42" " is " "even"))
+(display "\n")
+
+;; Test with single character strings
+(display "Testing single chars: ")
+(display (string-append "a" "b" "c" "d" "e"))
+(display "\n")
+
+;; Test with newlines and spaces
+(display "Testing with newlines: ")
+(display (string-append "Line 1" "\n" "Line 2" "\n" "Line 3"))
+(display "\n")
+
+;; Test with many arguments
+(display "Testing many arguments: ")
+(display (string-append "1" "2" "3" "4" "5" "6" "7" "8" "9" "0"))
+(display "\n")
+
+;; Test that it still works with 2 arguments (regression test)
+(display "Regression test (2 args): ")
+(display (string-append "test" "ing"))
+(display "\n")
+
+(display "All string-append variable argument tests completed!\n") 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/strings.scm b/awk/scheme/scheme/test/unit/strings.scm
new file mode 100644
index 0000000..a198cd2
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/strings.scm
@@ -0,0 +1,16 @@
+; Unit tests for string operations
+; Test all string built-in functions
+
+(string-length "hello")
+(string-length "")
+(string-append "hello" " world")
+(string-ref "hello" 0)
+(string-ref "hello" 4)
+(substring "hello world" 0 4)
+(substring "hello world" 6 10)
+(string=? "hello" "hello")
+(string=? "hello" "world")
+(string<? "abc" "def")
+(string<? "def" "abc")
+(string>? "xyz" "abc")
+(string>? "abc" "xyz") 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/variables.scm b/awk/scheme/scheme/test/unit/variables.scm
new file mode 100644
index 0000000..c153148
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/variables.scm
@@ -0,0 +1,8 @@
+; Unit tests for variable operations
+; Test define and variable lookup
+
+(define x 42)
+(define y 10)
+x
+y
+(+ x y) 
\ No newline at end of file
diff --git a/awk/scheme/scheme/test/unit/vm_instructions.scm b/awk/scheme/scheme/test/unit/vm_instructions.scm
new file mode 100644
index 0000000..c17ff52
--- /dev/null
+++ b/awk/scheme/scheme/test/unit/vm_instructions.scm
@@ -0,0 +1,77 @@
+;; VM Instructions Coverage Tests
+;; Tests for VM instructions that might not be well covered
+
+;; Test DUP instruction (duplicate top of stack)
+(define test-dup (x)
+  (+ x x))  ;; This should use DUP internally
+
+(test-dup 5)
+
+;; Test SWAP instruction (swap top two stack elements)
+(define test-swap (x y)
+  (- y x))  ;; This might use SWAP internally
+
+(test-swap 10 5)
+
+;; Test environment operations (STORE, LOOKUP, POP_ENV)
+(define test-env (x)
+  (let ((y (+ x 1)))
+    (+ x y)))
+
+(test-env 5)
+
+;; Test function calls (CALL, CALL_WITH_ARGS, RETURN)
+(define helper (x) (+ x 1))
+(define caller (y) (helper y))
+
+(caller 10)
+
+;; Test closures (CAPTURE_ENV, GET_VALUE)
+(define make-adder (n)
+  (lambda (x) (+ n x)))
+
+(define add5 (make-adder 5))
+(add5 3)
+
+;; Test control flow instructions (JUMP, JUMP_IF_FALSE, JUMP_IF_TRUE)
+(define test-control (x)
+  (if (> x 5)
+      (+ x 10)
+      (- x 10)))
+
+(test-control 7)
+(test-control 3)
+
+;; Test complex nested control flow
+(define complex-control (x y)
+  (cond ((> x y) (+ x y))
+        ((= x y) (* x y))
+        (else (- y x))))
+
+(complex-control 10 5)
+(complex-control 5 5)
+(complex-control 3 7)
+
+;; Test stack manipulation
+(define test-stack (a b c)
+  (+ a (+ b c)))  ;; This should exercise stack operations
+
+(test-stack 1 2 3)
+
+;; Test multiple function calls in sequence
+(define f1 (x) (+ x 1))
+(define f2 (x) (* x 2))
+(define f3 (x) (- x 1))
+
+(f3 (f2 (f1 5)))
+
+;; Test variable argument functions (exercises CALL_WITH_ARGS)
+(string-append "a" "b" "c" "d" "e")
+
+;; Test nested function definitions (exercises environment management)
+(define outer (x)
+  (define inner (y)
+    (+ x y))
+  (inner 10))
+
+(outer 5) 
\ No newline at end of file
diff --git a/awk/uxn/.gitignore b/awk/uxn/.gitignore
new file mode 100644
index 0000000..f71ddea
--- /dev/null
+++ b/awk/uxn/.gitignore
@@ -0,0 +1,3 @@
+**/out/
+**/uxnasm
+
diff --git a/awk/uxn/README.md b/awk/uxn/README.md
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/awk/uxn/README.md
diff --git a/awk/uxn/awk/uxnasm.awk b/awk/uxn/awk/uxnasm.awk
new file mode 100644
index 0000000..cfcdd00
--- /dev/null
+++ b/awk/uxn/awk/uxnasm.awk
@@ -0,0 +1,916 @@
+#!/usr/bin/awk -f
+
+# Uxntal Assembler in AWK - Two-Pass Implementation
+
+BEGIN {
+    # Constants
+    PAGE = 256
+    MAX_LABELS = 1024
+    MAX_REFS = 4096
+    
+    # Global state
+    ptr = PAGE
+    data_length = PAGE
+    
+    # Label and reference tracking
+    labels_len = 0
+    refs_len = 0
+    macros_len = 0
+    
+    # Device tracking
+    devices_len = 0
+    last_padding = ""
+    last_size = 0
+    current_device = ""
+    
+    # Lambda tracking
+    lambda_len = 0
+    lambda_ptr = 0
+    
+    # Opcode table
+    split("LIT INC POP NIP SWP ROT DUP OVR EQU NEQ GTH LTH JMP JCN JSR STH LDZ STZ LDR STR LDA STA DEI DEO ADD SUB MUL DIV AND ORA EOR SFT", ops)
+    
+    # Utility strings
+    hexad = "0123456789abcdef"
+    
+    # Check arguments
+    if (ARGC < 3) {
+        printf "usage: uxnasm.awk [-v] input.tal output.rom\n" > "/dev/stderr"
+        exit 1
+    }
+    
+    if (ARGC == 3 && substr(ARGV[1], 1, 2) == "-v") {
+        printf "Uxnasm.awk\n"
+        exit 0
+    }
+    
+    if (ARGC != 3) {
+        printf "usage: uxnasm.awk [-v] input.tal output.rom\n" > "/dev/stderr"
+        exit 1
+    }
+    
+    input_file = ARGV[1]
+    output_file = ARGV[2]
+    
+    # Remove output file from ARGV so AWK doesn't try to read it
+    ARGV[2] = ""
+    
+    # Two-pass assembly
+    if (!pass1_collect_symbols(input_file)) {
+        exit 1
+    }
+    
+    if (!pass2_generate_code(input_file)) {
+        exit 1
+    }
+    
+    if (!build_output(output_file)) {
+        exit 1
+    }
+    
+    printf "Assembled %s in %d bytes(%.2f%% used), %d labels, %d refs.\n",
+           output_file, data_length - PAGE, (data_length - PAGE) / 652.80, labels_len, refs_len
+}
+
+# Utility functions
+function remove_comments(line,    result, i, c, depth) {
+    # Remove comments from a line
+    # Comments are delimited by ( and ) and can be nested
+    result = ""
+    depth = 0
+    
+    for (i = 1; i <= length(line); i++) {
+        c = substr(line, i, 1)
+        if (c == "(") {
+            depth++
+        } else if (c == ")") {
+            depth--
+        } else if (depth == 0) {
+            result = result c
+        }
+    }
+    
+    # Trim whitespace
+    gsub(/^[ \t]+|[ \t]+$/, "", result)
+    return result
+}
+
+function shex(s,    d, n, c, i) {
+    n = 0
+    for (i = 1; i <= length(s); i++) {
+        c = substr(s, i, 1)
+        d = index(hexad, c) - 1
+        if (d < 0) return -1
+        n = n * 16 + d
+    }
+    return n
+}
+
+function ishex(x) {
+    return shex(x) >= 0
+}
+
+function findopcode(s,    i, m, base, c) {
+    # Special case for BRK
+    if (s == "BRK") return 0
+    
+    for (i = 1; i <= 32; i++) {
+        if (substr(ops[i], 1, 3) == substr(s, 1, 3)) {
+            base = i - 1
+            if (i == 1) base = base + 128  # LIT special case
+            
+            m = 4
+            while (m <= length(s)) {
+                c = substr(s, m, 1)
+                if (c == "2")
+                    base = base + 32
+                else if (c == "r")
+                    base = base + 64
+                else if (c == "k")
+                    base = base + 128
+                else
+                    return -1
+                m++
+            }
+            return base
+        }
+    }
+    return -1
+}
+
+function isopc(x) {
+    return findopcode(x) >= 0 || x == "BRK"
+}
+
+function makelabel(name, setscope) {
+    if (labels_len >= MAX_LABELS) {
+        printf "Labels limit exceeded\n" > "/dev/stderr"
+        return 0
+    }
+    
+    labels_len++
+    labels[labels_len, "name"] = name
+    labels[labels_len, "addr"] = ptr
+    labels[labels_len, "refs"] = 0
+    
+    printf "DEBUG: Created label '%s' at addr %d\n", name, ptr > "/dev/stderr"
+    
+    return 1
+}
+
+function findlabel(name,    i) {
+    for (i = 1; i <= labels_len; i++) {
+        if (labels[i, "name"] == name) {
+            return i
+        }
+    }
+    return 0
+}
+
+function makeref(label, rune, addr) {
+    if (refs_len >= MAX_REFS) {
+        printf "References limit exceeded\n" > "/dev/stderr"
+        return 0
+    }
+    
+    refs_len++
+    refs[refs_len, "name"] = label
+    refs[refs_len, "rune"] = rune
+    refs[refs_len, "addr"] = addr
+    
+    return 1
+}
+
+function makedevice(name, base_addr) {
+    if (devices_len >= MAX_LABELS) {
+        printf "Devices limit exceeded\n" > "/dev/stderr"
+        return 0
+    }
+    
+    devices_len++
+    devices[devices_len, "name"] = name
+    devices[devices_len, "base"] = base_addr
+    devices[devices_len, "fields_len"] = 0
+    
+    return 1
+}
+
+function adddevicefield(device_name, field_name, size) {
+    # Find device
+    for (i = 1; i <= devices_len; i++) {
+        if (devices[i, "name"] == device_name) {
+            devices[i, "fields_len"]++
+            devices[i, "fields", devices[i, "fields_len"], "name"] = field_name
+            devices[i, "fields", devices[i, "fields_len"], "size"] = size
+            return 1
+        }
+    }
+    return 0
+}
+
+function finddevicefield(device_name, field_name,    i, j) {
+    for (i = 1; i <= devices_len; i++) {
+        if (devices[i, "name"] == device_name) {
+            addr = devices[i, "base"]
+            for (j = 1; j <= devices[i, "fields_len"]; j++) {
+                if (devices[i, "fields", j, "name"] == field_name) {
+                    return addr
+                }
+                addr += devices[i, "fields", j, "size"]
+            }
+        }
+    }
+    return -1
+}
+
+# --- PASS 1: Symbol/Label Collection ---
+function pass1_collect_symbols(filename) {
+    ptr = PAGE
+    data_length = PAGE
+    
+    while ((getline < filename) > 0) {
+        pass1_process_line($0)
+    }
+    close(filename)
+    
+    return 1
+}
+
+function pass1_process_line(line_text,    tokens, i, token, j) {
+    line_text = remove_comments(line_text)
+    if (line_text == "") return 1
+    
+    # Custom tokenization to handle quoted strings properly
+    tokens_len = 0
+    i = 1
+    while (i <= length(line_text)) {
+        c = substr(line_text, i, 1)
+        if (c == " " || c == "\t") {
+            i++
+            continue
+        }
+        
+        if (c == "\"") {
+            # Handle quoted string - capture everything until closing quote
+            token = "\""
+            i++
+            while (i <= length(line_text) && substr(line_text, i, 1) != "\"") {
+                token = token substr(line_text, i, 1)
+                i++
+            }
+            if (i <= length(line_text)) {
+                token = token "\""
+                i++
+            }
+            tokens[++tokens_len] = token
+        } else {
+            # Regular token - capture until whitespace
+            token = ""
+            while (i <= length(line_text) && substr(line_text, i, 1) != " " && substr(line_text, i, 1) != "\t") {
+                token = token substr(line_text, i, 1)
+                i++
+            }
+            if (token != "") {
+                tokens[++tokens_len] = token
+            }
+        }
+    }
+    
+    # Combine - tokens with / (like -Screen/pixel)
+    for (i = 1; i < tokens_len; i++) {
+        if (tokens[i] == "-" && index(tokens[i+1], "/") > 0) {
+            tokens[i] = tokens[i] tokens[i+1]
+            for (j = i + 1; j < tokens_len; j++) {
+                tokens[j] = tokens[j+1]
+            }
+            tokens_len--
+        }
+    }
+    
+    for (i = 1; i <= tokens_len; i++) {
+        token = tokens[i]
+        printf "DEBUG: pass1 processing token: '%s'\n", token > "/dev/stderr"
+        if (!pass1_parse_token(token)) {
+            printf "ERROR: Failed to parse token '%s' at line %d\n", token, line_number > "/dev/stderr"
+            return 0
+        }
+    }
+    return 1
+}
+
+function pass1_parse_token(w) {
+    
+                # Skip standalone tokens
+            if (w == ">" || w == "-") {
+                return 1
+            }
+    
+    # Handle device definitions and labels
+    if (substr(w, 1, 1) == "@") {
+        printf "DEBUG: Processing @ token: %s\n", w > "/dev/stderr"
+        # Check if this is a macro definition (labels starting with @<)
+        printf "DEBUG: Checking macro condition: substr(w, 2, 1)='%s', substr(w, length(w), 1)='%s'\n", substr(w, 2, 1), substr(w, length(w), 1) > "/dev/stderr"
+        printf "DEBUG: Condition check: '%s' == '<' && '%s' == '>' = %s\n", substr(w, 2, 1), substr(w, length(w), 1), (substr(w, 2, 1) == "<" && substr(w, length(w), 1) == ">") > "/dev/stderr"
+        if (substr(w, 2, 1) == "<" && substr(w, length(w), 1) == ">") {
+            printf "DEBUG: Found macro definition: %s\n", w > "/dev/stderr"
+            makemacro(substr(w, 3, length(w) - 3))
+            return 1
+        }
+        
+        # Check if this is a device definition (has base address)
+        if (last_padding != "" && current_device == "") {
+            makedevice(substr(w, 2), shex(last_padding))
+            current_device = substr(w, 2)
+            last_padding = ""  # Reset after device definition
+        } else {
+            makelabel(substr(w, 2), 1)
+        }
+        return 1
+    }
+    
+    # Handle device fields
+    if (substr(w, 1, 1) == "&") {
+        if (current_device != "") {
+            adddevicefield(current_device, substr(w, 2), last_size)
+        } else {
+            makelabel(w, 0)
+        }
+        return 1
+    }
+    
+    # Skip brackets and control flow
+    if (substr(w, 1, 1) == "[" || substr(w, 1, 1) == "]" || w == "{") {
+        return 1
+    }
+    
+    # Handle lambda labels
+    if (w == "}") {
+        makelabel(makelambda(lambda_len++))
+        return 1
+    }
+    
+    # Handle padding and size
+    if (substr(w, 1, 1) == "|") {
+        last_padding = substr(w, 2)
+        # Set pointer based on padding value (no writing, just positioning)
+        if (last_padding == "0000") {
+            ptr = 0
+        } else if (last_padding == "0100") {
+            ptr = PAGE
+        } else {
+            ptr = shex(last_padding)
+        }
+        return 1
+    }
+    if (substr(w, 1, 1) == "$") {
+        last_size = shex(substr(w, 2))
+        # Advance pointer by size (no writing, just positioning)
+        ptr += last_size
+        return 1
+    }
+    
+    # Handle references (just collect them, don't resolve yet)
+    if (substr(w, 1, 1) == "_") {
+        makeref(substr(w, 2), substr(w, 1, 1), ptr)
+        ptr++
+        return 1
+    }
+    if (substr(w, 1, 1) == ",") {
+        makeref(substr(w, 2), substr(w, 1, 1), ptr + 1)
+        ptr += 2
+        return 1
+    }
+    if (substr(w, 1, 1) == "-") {
+        # Check if this is a device field reference
+        if (index(substr(w, 2), "/") > 0) {
+            # Device field reference - just advance pointer (will be resolved in pass2)
+            ptr++
+        } else {
+            makeref(substr(w, 2), substr(w, 1, 1), ptr)
+            ptr++
+        }
+        return 1
+    }
+    if (substr(w, 1, 1) == ".") {
+        # Check if this is a device field reference
+        if (index(substr(w, 2), "/") > 0) {
+            # Device field reference - just advance pointer
+            ptr += 2
+        } else {
+            makeref(substr(w, 2), substr(w, 1, 1), ptr + 1)
+            ptr += 2
+        }
+        return 1
+    }
+    if (substr(w, 1, 1) == "=") {
+        makeref(substr(w, 2), substr(w, 1, 1), ptr)
+        ptr += 2
+        return 1
+    }
+    if (substr(w, 1, 1) == ";") {
+        makeref(substr(w, 2), substr(w, 1, 1), ptr + 1)
+        ptr += 3
+        return 1
+    }
+    if (substr(w, 1, 1) == "?") {
+        makeref(substr(w, 2), substr(w, 1, 1), ptr + 1)
+        ptr += 3
+        return 1
+    }
+    if (substr(w, 1, 1) == "!") {
+        makeref(substr(w, 2), substr(w, 1, 1), ptr + 1)
+        ptr += 3
+        return 1
+    }
+    
+    # Handle hex literals (with # prefix or raw hex values)
+    if (substr(w, 1, 1) == "#") {
+        if (length(substr(w, 2)) > 2) {
+            ptr += 3  # LIT2 + 2 bytes
+        } else {
+            ptr += 2  # LIT + 1 byte
+        }
+        return 1
+    }
+    
+    # Handle raw hex values (like font data)
+    if (ishex(w)) {
+        if (length(w) > 2) {
+            ptr += 3  # LIT2 + 2 bytes
+        } else {
+            ptr += 2  # LIT + 1 byte
+        }
+        return 1
+    }
+    
+    # Handle opcodes
+    if (isopc(w)) {
+        ptr++
+        return 1
+    }
+    
+    # Handle strings
+    if (substr(w, 1, 1) == "\"") {
+        ptr += length(substr(w, 2))
+        return 1
+    }
+    
+    # Handle macro definitions (labels starting with @<)
+    if (substr(w, 1, 1) == "@" && substr(w, 2, 1) == "<" && substr(w, length(w), 1) == ">") {
+        makemacro(substr(w, 3, length(w) - 3))
+        return 1
+    }
+    
+    # Handle macro calls (tokens starting with <)
+    if (substr(w, 1, 1) == "<" && substr(w, length(w), 1) == ">") {
+        # Just advance pointer in pass1, will be expanded in pass2
+        ptr += 1  # Placeholder - actual size depends on macro content
+        return 1
+    }
+    
+    # Handle unknown tokens as label references (fallback)
+    makeref(w, " ", ptr + 1)
+    ptr += 3  # LIT2 + 2 bytes
+    return 1
+}
+
+# --- PASS 2: Code Generation ---
+function pass2_generate_code(filename) {
+    ptr = PAGE
+    data_length = PAGE
+    
+    while ((getline < filename) > 0) {
+        pass2_process_line($0)
+    }
+    close(filename)
+    
+    return 1
+}
+
+function pass2_process_line(line_text,    tokens, i, token, j) {
+    line_text = remove_comments(line_text)
+    if (line_text == "") return 1
+    
+    # Custom tokenization to handle quoted strings properly
+    tokens_len = 0
+    i = 1
+    while (i <= length(line_text)) {
+        c = substr(line_text, i, 1)
+        if (c == " " || c == "\t") {
+            i++
+            continue
+        }
+        
+        if (c == "\"") {
+            # Handle quoted string - capture everything until closing quote
+            token = "\""
+            i++
+            while (i <= length(line_text) && substr(line_text, i, 1) != "\"") {
+                token = token substr(line_text, i, 1)
+                i++
+            }
+            if (i <= length(line_text)) {
+                token = token "\""
+                i++
+            }
+            tokens[++tokens_len] = token
+        } else {
+            # Regular token - capture until whitespace
+            token = ""
+            while (i <= length(line_text) && substr(line_text, i, 1) != " " && substr(line_text, i, 1) != "\t") {
+                token = token substr(line_text, i, 1)
+                i++
+            }
+            if (token != "") {
+                tokens[++tokens_len] = token
+            }
+        }
+    }
+    
+    # Combine - tokens with / (like -Screen/pixel)
+    for (i = 1; i < tokens_len; i++) {
+        if (tokens[i] == "-" && index(tokens[i+1], "/") > 0) {
+            tokens[i] = tokens[i] tokens[i+1]
+            for (j = i + 1; j < tokens_len; j++) {
+                tokens[j] = tokens[j+1]
+            }
+            tokens_len--
+        }
+    }
+    
+    for (i = 1; i <= tokens_len; i++) {
+        token = tokens[i]
+        if (!pass2_parse_token(token)) {
+            printf "ERROR: Failed to parse token '%s' at line %d\n", token, line_number > "/dev/stderr"
+            return 0
+        }
+    }
+    return 1
+}
+
+function pass2_parse_token(w) {
+    printf "DEBUG: pass2_parse_token processing '%s'\n", w > "/dev/stderr"
+    
+    # Skip standalone tokens (but not device field references)
+    if (w == ">") {
+        return 1
+    }
+    
+    # Handle labels (just skip, already collected in pass 1)
+    if (substr(w, 1, 1) == "@" || substr(w, 1, 1) == "&") {
+        return 1
+    }
+    
+    # Skip brackets and control flow
+    if (substr(w, 1, 1) == "[" || substr(w, 1, 1) == "]" || w == "{") {
+        return 1
+    }
+    
+    # Handle lambda labels (just skip, already collected in pass 1)
+    if (w == "}") {
+        return 1
+    }
+    
+    # Handle padding
+    if (substr(w, 1, 1) == "|") {
+        # Set pointer based on padding value (no writing, just positioning)
+        padding_val = substr(w, 2)
+        if (padding_val == "0000") {
+            ptr = 0
+        } else if (padding_val == "0100") {
+            ptr = PAGE
+        } else {
+            ptr = shex(padding_val)
+        }
+        return 1
+    }
+    if (substr(w, 1, 1) == "$") {
+        # Advance pointer by size (no writing, just positioning)
+        size_val = shex(substr(w, 2))
+        ptr += size_val
+        return 1
+    }
+    
+    # Handle references (resolve them now)
+    if (substr(w, 1, 1) == "_") {
+        resolve_ref(substr(w, 2), substr(w, 1, 1), ptr) && writebyte(0xff)
+        return 1
+    }
+    if (substr(w, 1, 1) == ",") {
+        resolve_ref(substr(w, 2), substr(w, 1, 1), ptr + 1) && writebyte(128) && writebyte(0xff)
+        return 1
+    }
+    if (substr(w, 1, 1) == "-") {
+        # Device field reference
+        if (index(substr(w, 2), "/") > 0) {
+            resolve_device_ref(substr(w, 2), ptr)
+            writebyte(0xff)
+        } else {
+            resolve_ref(substr(w, 2), substr(w, 1, 1), ptr)
+            writebyte(0xff)
+        }
+        return 1
+    }
+    if (substr(w, 1, 1) == ".") {
+        # Check if this is a device field reference
+        if (index(substr(w, 2), "/") > 0) {
+            resolve_device_ref(substr(w, 2), ptr + 1) && writebyte(128) && writebyte(0xff)
+        } else {
+            resolve_ref(substr(w, 2), substr(w, 1, 1), ptr + 1) && writebyte(128) && writebyte(0xff)
+        }
+        return 1
+    }
+    if (substr(w, 1, 1) == "=") {
+        resolve_ref(substr(w, 2), substr(w, 1, 1), ptr) && writeshort(0xffff)
+        return 1
+    }
+    if (substr(w, 1, 1) == ";") {
+        resolve_ref(substr(w, 2), substr(w, 1, 1), ptr + 1) && writebyte(160) && writeshort(0xffff)
+        return 1
+    }
+    if (substr(w, 1, 1) == "?") {
+        resolve_ref(substr(w, 2), substr(w, 1, 1), ptr + 1) && writebyte(32) && writeshort(0xffff)
+        return 1
+    }
+    if (substr(w, 1, 1) == "!") {
+        resolve_ref(substr(w, 2), substr(w, 1, 1), ptr + 1) && writebyte(64) && writeshort(0xffff)
+        return 1
+    }
+    
+    # Handle hex literals (with # prefix or raw hex values)
+    if (substr(w, 1, 1) == "#") {
+        writehex(w)
+        return 1
+    }
+    
+    # Handle raw hex values (like font data)
+    if (ishex(w)) {
+        writehex(w)
+        return 1
+    }
+    
+    # Handle opcodes
+    if (isopc(w)) {
+        writebyte(findopcode(w))
+        return 1
+    }
+    
+    # Handle string literals
+    if (substr(w, 1, 1) == "\"") {
+        writestring(substr(w, 2, length(w) - 2))
+        return 1
+    }
+    
+    # Handle macro calls (tokens starting with <)
+    if (substr(w, 1, 1) == "<" && substr(w, length(w), 1) == ">") {
+        expandmacro(substr(w, 2, length(w) - 2))
+        return 1
+    }
+    
+    # Handle unknown tokens as label references (fallback)
+    printf "DEBUG: Unknown token '%s' treated as label reference\n", w > "/dev/stderr"
+    makeref(w, " ", ptr + 1)
+    ptr += 3  # LIT2 + 2 bytes
+    return 1
+}
+
+function resolve_ref(label, rune, addr,    l, rel) {
+    l = findlabel(label)
+    if (l == 0) {
+        printf "Label unknown: %s\n", label > "/dev/stderr"
+        return 0
+    }
+    
+    # Resolve based on reference type
+    if (rune == "_" || rune == ",") {
+        rel = labels[l, "addr"] - addr - 2
+        data[addr] = rel
+    } else if (rune == "-" || rune == ".") {
+        data[addr] = labels[l, "addr"]
+    } else if (rune == "=" || rune == ";") {
+        data[addr] = int(labels[l, "addr"] / 256)
+        data[addr + 1] = labels[l, "addr"] % 256
+    } else if (rune == "?" || rune == "!") {
+        rel = labels[l, "addr"] - addr - 2
+        data[addr] = int(rel / 256)
+        data[addr + 1] = rel % 256
+    }
+    
+    labels[l, "refs"]++
+    return 1
+}
+
+function resolve_device_ref(device_field, addr,    device_name, field_name, device_addr) {
+    # Split device/field
+    split(device_field, parts, "/")
+    if (length(parts) != 2) {
+        printf "Invalid device field: %s\n", device_field > "/dev/stderr"
+        return 0
+    }
+    
+    device_name = parts[1]
+    field_name = parts[2]
+    
+    device_addr = finddevicefield(device_name, field_name)
+    if (device_addr == -1) {
+        printf "Device field unknown: %s\n", device_field > "/dev/stderr"
+        return 0
+    }
+    
+    data[addr] = device_addr
+    return 1
+}
+
+function writebyte(b) {
+    if (ptr >= 65536) {
+        printf "Writing outside memory\n" > "/dev/stderr"
+        return 0
+    }
+    
+    # Only write to data array if we're in the code section (ptr >= PAGE)
+    if (ptr >= PAGE) {
+        data[ptr] = b
+        if (b) {
+            data_length = ptr
+        }
+        printf "DEBUG: writebyte(%d) at ptr %d, data_length now %d\n", b, ptr, data_length > "/dev/stderr"
+    }
+    ptr++
+    return 1
+}
+
+function writeshort(x) {
+    return writebyte(int(x / 256)) && writebyte(x % 256)
+}
+
+function writehex(w) {
+    if (substr(w, 1, 1) == "#") {
+        # Write LIT opcode
+        if (length(substr(w, 2)) > 2) {
+            writebyte(32)  # LIT2
+        } else {
+            writebyte(128)   # LIT (BRK + 128)
+        }
+        w = substr(w, 2)
+    }
+    
+    if (ishex(w)) {
+        if (length(w) == 2) {
+            return writebyte(shex(w))
+        } else if (length(w) == 4) {
+            return writeshort(shex(w))
+        }
+    }
+    
+    printf "Hexadecimal invalid: %s\n", w > "/dev/stderr"
+    return 0
+}
+
+# Macro functions
+function findmacro(name,    i) {
+    for (i = 0; i < macros_len; i++) {
+        if (macro_names[i] == name) {
+            return i
+        }
+    }
+    return -1
+}
+
+function makemacro(name,    i) {
+    printf "DEBUG: makemacro called with name: %s\n", name > "/dev/stderr"
+    if (macros_len >= 256) {
+        printf "Macros limit exceeded\n" > "/dev/stderr"
+        return 0
+    }
+    if (findmacro(name) >= 0) {
+        printf "Macro duplicate: %s\n", name > "/dev/stderr"
+        return 0
+    }
+    if (findlabel(name) >= 0) {
+        printf "Label duplicate: %s\n", name > "/dev/stderr"
+        return 0
+    }
+    
+    # Store macro name and initialize empty body
+    macro_names[macros_len] = name
+    macro_data[macros_len] = ""
+    macros_len++
+    
+    # Note: We'll capture the macro body in pass2 when we process the file again
+    return 1
+}
+
+function capture_macro_body(name, filename,    line, in_macro, macro_body, depth) {
+    # Reset file to beginning
+    close(filename)
+    in_macro = 0
+    macro_body = ""
+    depth = 0
+    
+    while ((getline line < filename) > 0) {
+        if (in_macro) {
+            # Check if we've reached the end of the macro (next label or closing brace)
+            if (substr(line, 1, 1) == "@" && substr(line, 2, 1) != "|") {
+                # Found next label, end of macro
+                break
+            }
+            
+            # Count braces for nested macro handling
+            for (i = 1; i <= length(line); i++) {
+                c = substr(line, i, 1)
+                if (c == "{") depth++
+                else if (c == "}") {
+                    depth--
+                    if (depth < 0) break  # End of macro
+                }
+            }
+            
+            if (depth < 0) break  # End of macro
+            
+            # Add line to macro body
+            macro_body = macro_body line "\n"
+        } else if (substr(line, 1, 1) == "@" && substr(line, 2, 1) == "<") {
+            # Check if this is our macro
+            macro_name = substr(line, 3)
+            if (substr(macro_name, length(macro_name), 1) == ">") {
+                macro_name = substr(macro_name, 1, length(macro_name) - 1)
+                if (macro_name == name) {
+                    in_macro = 1
+                    # Start capturing from next line
+                }
+            }
+        }
+    }
+    
+    close(filename)
+    
+    # Store the macro body
+    for (i = 0; i < macros_len; i++) {
+        if (macro_names[i] == name) {
+            macro_data[i] = macro_body
+            return 1
+        }
+    }
+    return 0
+}
+
+function expandmacro(name,    macro_idx, macro_text, tokens, i) {
+    macro_idx = findmacro(name)
+    if (macro_idx < 0) {
+        printf "Macro not found: %s\n", name > "/dev/stderr"
+        return 0
+    }
+    
+    # If macro body is empty, try to capture it
+    if (macro_data[macro_idx] == "") {
+        capture_macro_body(name, ARGV[1])
+    }
+    
+    macro_text = macro_data[macro_idx]
+    if (macro_text == "") {
+        printf "Macro body empty: %s\n", name > "/dev/stderr"
+        return 0
+    }
+    
+    # Process macro body line by line
+    split(macro_text, lines, "\n")
+    for (i = 1; i <= length(lines); i++) {
+        if (lines[i] != "") {
+            pass2_process_line(lines[i])
+        }
+    }
+    return 1
+}
+
+# Lambda functions
+function makelambda(id) {
+    # Create a unique lambda name like "λb" where suffix is hex digit
+    return sprintf("λ%c", substr(hexad, int(id / 16) + 1, 1) substr(hexad, (id % 16) + 1, 1))
+}
+
+function ord(c) {
+    return index(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", c) + 31
+}
+
+function writestring(w,    i, c) {
+    for (i = 1; i <= length(w); i++) {
+        c = substr(w, i, 1)
+        # Simple ASCII conversion
+        if (!writebyte(ord(c))) {
+            printf "String invalid\n" > "/dev/stderr"
+            return 0
+        }
+    }
+    return 1
+}
+
+function build_output(rompath) {
+    # Write ROM file
+    printf "DEBUG: Writing %d bytes from PAGE (%d) to data_length (%d)\n", data_length - PAGE + 1, PAGE, data_length > "/dev/stderr"
+    for (i = PAGE; i <= data_length; i++) {
+        printf "%c", data[i] > rompath
+    }
+    close(rompath)
+    
+    return 1
+}
diff --git a/awk/uxn/ref/uxnasm.c b/awk/uxn/ref/uxnasm.c
new file mode 100644
index 0000000..f25d6ce
--- /dev/null
+++ b/awk/uxn/ref/uxnasm.c
@@ -0,0 +1,481 @@
+#include <stdio.h>
+
+/*
+Copyright (c) 2021-2024 Devine Lu Linvega, Andrew Alderwick
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE.
+*/
+
+/* clang-format off */
+
+#define PAGE 0x0100
+#define ishex(x) (shex(x) >= 0)
+#define isopc(x) (findopcode(x) || scmp(x, "BRK", 4))
+#define isinvalid(x) (!x[0] || ishex(x) || isopc(x) || find(runes, x[0]) >= 0)
+#define writeshort(x) (writebyte(x >> 8, ctx) && writebyte(x & 0xff, ctx))
+#define findlabel(x) finditem(x, labels, labels_len)
+#define findmacro(x) finditem(x, macros, macro_len)
+#define error_top(id, msg) !printf("%s: %s\n", id, msg)
+#define error_asm(id) !printf("%s: %s in @%s, %s:%d.\n", id, token, scope, ctx->path, ctx->line)
+#define error_ref(id) !printf("%s: %s, %s:%d\n", id, r->name, r->data, r->line)
+
+typedef unsigned char Uint8;
+typedef signed char Sint8;
+typedef unsigned short Uint16;
+typedef struct { int line; char *path; } Context;
+typedef struct { char *name, rune, *data; Uint16 addr, refs, line; } Item;
+
+static int ptr, length;
+static char token[0x30], scope[0x40], lambda[0x05];
+static char dict[0x8000], *dictnext = dict;
+static Uint8 data[0x10000], lambda_stack[0x100], lambda_ptr, lambda_len;
+static Uint16 labels_len, refs_len, macro_len;
+static Item labels[0x400], refs[0x1000], macros[0x100];
+
+static char *runes = "|$@&,_.-;=!?#\"%~";
+static char *hexad = "0123456789abcdef";
+static char ops[][4] = {
+	"LIT", "INC", "POP", "NIP", "SWP", "ROT", "DUP", "OVR",
+	"EQU", "NEQ", "GTH", "LTH", "JMP", "JCN", "JSR", "STH",
+	"LDZ", "STZ", "LDR", "STR", "LDA", "STA", "DEI", "DEO",
+	"ADD", "SUB", "MUL", "DIV", "AND", "ORA", "EOR", "SFT"
+};
+
+/* clang-format on */
+
+static int
+find(char *s, char t)
+{
+	int i = 0;
+	char c;
+	while((c = *s++)) {
+		if(c == t) return i;
+		i++;
+	}
+	return -1;
+}
+
+static int
+shex(char *s)
+{
+	int d, n = 0;
+	char c;
+	while((c = *s++)) {
+		d = find(hexad, c);
+		if(d < 0) return d;
+		n = n << 4, n |= d;
+	}
+	return n;
+}
+
+static int
+scmp(char *a, char *b, int len)
+{
+	int i = 0;
+	while(a[i] == b[i])
+		if(!a[i] || ++i >= len) return 1;
+	return 0;
+}
+
+static char *
+copy(char *src, char *dst, char c)
+{
+	while(*src && *src != c) *dst++ = *src++;
+	*dst++ = 0;
+	return dst;
+}
+
+static char *
+save(char *s, char c)
+{
+	char *o = dictnext;
+	while((*dictnext++ = *s++) && *s);
+	*dictnext++ = c;
+	return o;
+}
+
+static char *
+join(char *a, char j, char *b)
+{
+	char *res = dictnext;
+	save(a, j), save(b, 0);
+	return res;
+}
+
+static char *
+push(char *s, char c)
+{
+	char *d;
+	for(d = dict; d < dictnext; d++) {
+		char *ss = s, *dd = d, a, b;
+		while((a = *dd++) == (b = *ss++))
+			if(!a && !b) return d;
+	}
+	return save(s, c);
+}
+
+static Item *
+finditem(char *name, Item *list, int len)
+{
+	int i;
+	if(name[0] == '&')
+		name = join(scope, '/', name + 1);
+	for(i = 0; i < len; i++)
+		if(scmp(list[i].name, name, 0x40))
+			return &list[i];
+	return NULL;
+}
+
+static Uint8
+findopcode(char *s)
+{
+	int i;
+	for(i = 0; i < 0x20; i++) {
+		int m = 3;
+		if(!scmp(ops[i], s, 3)) continue;
+		if(!i) i |= (1 << 7);
+		while(s[m]) {
+			if(s[m] == '2')
+				i |= (1 << 5);
+			else if(s[m] == 'r')
+				i |= (1 << 6);
+			else if(s[m] == 'k')
+				i |= (1 << 7);
+			else
+				return 0;
+			m++;
+		}
+		return i;
+	}
+	return 0;
+}
+
+static int
+walkcomment(FILE *f, Context *ctx)
+{
+	char c, last = 0;
+	int depth = 1;
+	while(f && fread(&c, 1, 1, f)) {
+		if(c <= 0x20) {
+			if(c == 0xa) ctx->line++;
+			if(last == '(')
+				depth++;
+			else if(last == ')' && --depth < 1)
+				return 1;
+			last = 0;
+		} else if(last <= 0x20)
+			last = c;
+		else
+			last = '~';
+	}
+	return error_asm("Comment incomplete");
+}
+
+static int parse(char *w, FILE *f, Context *ctx);
+
+static int
+walkmacro(Item *m, Context *ctx)
+{
+	unsigned char c;
+	char *dataptr = m->data, *_token = token;
+	while((c = *dataptr++)) {
+		if(c < 0x21) {
+			*_token = 0x00;
+			if(token[0] && !parse(token, NULL, ctx)) return 0;
+			_token = token;
+		} else if(_token - token < 0x2f)
+			*_token++ = c;
+		else
+			return error_asm("Token size exceeded");
+	}
+	return 1;
+}
+
+static int
+walkfile(FILE *f, Context *ctx)
+{
+	unsigned char c;
+	char *_token = token;
+	while(f && fread(&c, 1, 1, f)) {
+		if(c < 0x21) {
+			*_token = 0x00;
+			if(token[0] && !parse(token, f, ctx)) return 0;
+			if(c == 0xa) ctx->line++;
+			_token = token;
+		} else if(_token - token < 0x2f)
+			*_token++ = c;
+		else
+			return error_asm("Token size exceeded");
+	}
+	*_token = 0;
+	return parse(token, f, ctx);
+}
+
+static char *
+makelambda(int id)
+{
+	lambda[0] = (char)0xce;
+	lambda[1] = (char)0xbb;
+	lambda[2] = hexad[id >> 0x4];
+	lambda[3] = hexad[id & 0xf];
+	return lambda;
+}
+
+static int
+makemacro(char *name, FILE *f, Context *ctx)
+{
+	int depth = 0;
+	char c;
+	Item *m;
+	if(macro_len >= 0x100) return error_asm("Macros limit exceeded");
+	if(isinvalid(name)) return error_asm("Macro invalid");
+	if(findmacro(name)) return error_asm("Macro duplicate");
+	if(findlabel(name)) return error_asm("Label duplicate");
+	m = &macros[macro_len++];
+	m->name = push(name, 0);
+	m->data = dictnext;
+	while(f && fread(&c, 1, 1, f) && c != '{')
+		if(c == 0xa) ctx->line++;
+	while(f && fread(&c, 1, 1, f)) {
+		if(c == 0xa) ctx->line++;
+		if(c == '%') return error_asm("Macro nested");
+		if(c == '{') depth++;
+		if(c == '}' && --depth) break;
+		*dictnext++ = c;
+	}
+	*dictnext++ = 0;
+	return 1;
+}
+
+static int
+makelabel(char *name, int setscope, Context *ctx)
+{
+	Item *l;
+	if(name[0] == '&')
+		name = join(scope, '/', name + 1);
+	if(labels_len >= 0x400) return error_asm("Labels limit exceeded");
+	if(isinvalid(name)) return error_asm("Label invalid");
+	if(findmacro(name)) return error_asm("Label duplicate");
+	if(findlabel(name)) return error_asm("Label duplicate");
+	l = &labels[labels_len++];
+	l->name = push(name, 0);
+	l->addr = ptr;
+	l->refs = 0;
+	if(setscope) copy(name, scope, '/');
+	return 1;
+}
+
+static int
+makeref(char *label, char rune, Uint16 addr, Context *ctx)
+{
+	Item *r;
+	if(refs_len >= 0x1000) return error_asm("References limit exceeded");
+	r = &refs[refs_len++];
+	if(label[0] == '{') {
+		lambda_stack[lambda_ptr++] = lambda_len;
+		r->name = push(makelambda(lambda_len++), 0);
+		if(label[1]) return error_asm("Label invalid");
+	} else if(label[0] == '&' || label[0] == '/') {
+		r->name = join(scope, '/', label + 1);
+	} else
+		r->name = push(label, 0);
+	r->rune = rune;
+	r->addr = addr;
+	r->line = ctx->line;
+	r->data = ctx->path;
+	return 1;
+}
+
+static int
+writepad(char *w, Context *ctx)
+{
+	Item *l;
+	int rel = w[0] == '$' ? ptr : 0;
+	if(ishex(w + 1)) {
+		ptr = shex(w + 1) + rel;
+		return 1;
+	}
+	if((l = findlabel(w + 1))) {
+		ptr = l->addr + rel;
+		return 1;
+	}
+	return error_asm("Padding invalid");
+}
+
+static int
+writebyte(Uint8 b, Context *ctx)
+{
+	if(ptr < PAGE)
+		return error_asm("Writing zero-page");
+	else if(ptr >= 0x10000)
+		return error_asm("Writing outside memory");
+	else if(ptr < length)
+		return error_asm("Writing rewind");
+	data[ptr++] = b;
+	if(b)
+		length = ptr;
+	return 1;
+}
+
+static int
+writehex(char *w, Context *ctx)
+{
+	if(*w == '#')
+		writebyte(findopcode("LIT") | !!(++w)[2] << 5, ctx);
+	if(ishex(w)) {
+		if(w[1] && !w[2])
+			return writebyte(shex(w), ctx);
+		else if(w[3] && !w[4])
+			return writeshort(shex(w));
+	}
+	return error_asm("Hexadecimal invalid");
+}
+
+static int
+writestring(char *w, Context *ctx)
+{
+	char c;
+	while((c = *(w++)))
+		if(!writebyte(c, ctx)) return error_asm("String invalid");
+	return 1;
+}
+
+static int
+assemble(char *filename)
+{
+	FILE *f;
+	int res;
+	Context ctx;
+	ctx.line = 1;
+	ctx.path = push(filename, 0);
+	if(!(f = fopen(filename, "r")))
+		return error_top("File missing", filename);
+	res = walkfile(f, &ctx);
+	fclose(f);
+	return res;
+}
+
+static int
+parse(char *w, FILE *f, Context *ctx)
+{
+	Item *m;
+	switch(w[0]) {
+	case 0x0: return 1;
+	case '(':
+		if(w[1] <= 0x20)
+			return walkcomment(f, ctx);
+		else
+			return error_asm("Invalid word");
+	case '%': return makemacro(w + 1, f, ctx);
+	case '@': return makelabel(w + 1, 1, ctx);
+	case '&': return makelabel(w, 0, ctx);
+	case '}': return makelabel(makelambda(lambda_stack[--lambda_ptr]), 0, ctx);
+	case '#': return writehex(w, ctx);
+	case '_': return makeref(w + 1, w[0], ptr, ctx) && writebyte(0xff, ctx);
+	case ',': return makeref(w + 1, w[0], ptr + 1, ctx) && writebyte(findopcode("LIT"), ctx) && writebyte(0xff, ctx);
+	case '-': return makeref(w + 1, w[0], ptr, ctx) && writebyte(0xff, ctx);
+	case '.': return makeref(w + 1, w[0], ptr + 1, ctx) && writebyte(findopcode("LIT"), ctx) && writebyte(0xff, ctx);
+	case ':': printf("Deprecated rune %s, use =%s\n", w, w + 1); /* fall-through */
+	case '=': return makeref(w + 1, w[0], ptr, ctx) && writeshort(0xffff);
+	case ';': return makeref(w + 1, w[0], ptr + 1, ctx) && writebyte(findopcode("LIT2"), ctx) && writeshort(0xffff);
+	case '?': return makeref(w + 1, w[0], ptr + 1, ctx) && writebyte(0x20, ctx) && writeshort(0xffff);
+	case '!': return makeref(w + 1, w[0], ptr + 1, ctx) && writebyte(0x40, ctx) && writeshort(0xffff);
+	case '"': return writestring(w + 1, ctx);
+	case '~': return !assemble(w + 1) ? error_asm("Include missing") : 1;
+	case '$':
+	case '|': return writepad(w, ctx);
+	case '[':
+	case ']': return 1;
+	}
+	if(ishex(w)) return writehex(w, ctx);
+	if(isopc(w)) return writebyte(findopcode(w), ctx);
+	if((m = findmacro(w))) return walkmacro(m, ctx);
+	return makeref(w, ' ', ptr + 1, ctx) && writebyte(0x60, ctx) && writeshort(0xffff);
+}
+
+static int
+resolve(char *filename)
+{
+	int i, rel;
+	if(!length) return error_top("Output empty", filename);
+	for(i = 0; i < refs_len; i++) {
+		Item *r = &refs[i], *l = findlabel(r->name);
+		Uint8 *rom = data + r->addr;
+		if(!l) return error_ref("Label unknown");
+		switch(r->rune) {
+		case '_':
+		case ',':
+			*rom = rel = l->addr - r->addr - 2;
+			if((Sint8)data[r->addr] != rel)
+				return error_ref("Reference too far");
+			break;
+		case '-':
+		case '.':
+			*rom = l->addr;
+			break;
+		case ':':
+		case '=':
+		case ';':
+			*rom++ = l->addr >> 8, *rom = l->addr;
+			break;
+		case '?':
+		case '!':
+		default:
+			rel = l->addr - r->addr - 2;
+			*rom++ = rel >> 8, *rom = rel;
+			break;
+		}
+		l->refs++;
+	}
+	return 1;
+}
+
+static int
+build(char *rompath)
+{
+	int i;
+	FILE *dst, *dstsym;
+	char *sympath = join(rompath, '.', "sym");
+	/* rom */
+	if(!(dst = fopen(rompath, "wb")))
+		return !error_top("Output file invalid", rompath);
+	for(i = 0; i < labels_len; i++)
+		if(!labels[i].refs && (unsigned char)(labels[i].name[0] - 'A') > 25)
+			printf("-- Unused label: %s\n", labels[i].name);
+	fwrite(data + PAGE, length - PAGE, 1, dst);
+	printf(
+		"Assembled %s in %d bytes(%.2f%% used), %d labels, %d macros.\n",
+		rompath,
+		length - PAGE,
+		(length - PAGE) / 652.80,
+		labels_len,
+		macro_len);
+	/* sym */
+	if(!(dstsym = fopen(sympath, "wb")))
+		return !error_top("Symbols file invalid", sympath);
+	for(i = 0; i < labels_len; i++) {
+		Uint8 hb = labels[i].addr >> 8, lb = labels[i].addr;
+		char c, d = 0, *name = labels[i].name;
+		fwrite(&hb, 1, 1, dstsym);
+		fwrite(&lb, 1, 1, dstsym);
+		while((c = *name++)) fwrite(&c, 1, 1, dstsym);
+		fwrite(&d, 1, 1, dstsym);
+	}
+	fclose(dst), fclose(dstsym);
+	return 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+	ptr = PAGE;
+	copy("on-reset", scope, 0);
+	if(argc == 2 && scmp(argv[1], "-v", 2)) return !printf("Uxnasm - Uxntal Assembler, 15 Jan 2025.\n");
+	if(argc != 3) return error_top("usage", "uxnasm [-v] input.tal output.rom");
+	return !assemble(argv[1]) || !resolve(argv[2]) || !build(argv[2]);
+}
diff --git a/awk/uxn/test/runner.sh b/awk/uxn/test/runner.sh
new file mode 100755
index 0000000..711dd28
--- /dev/null
+++ b/awk/uxn/test/runner.sh
@@ -0,0 +1,105 @@
+#!/bin/bash
+
+# Test runner for Uxntal AWK assembler
+# Compares output with reference C implementation
+
+set -e
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+# Paths
+AWK_ASM="../awk/uxnasm.awk"
+REF_ASM="../ref/uxnasm"
+TEST_DIR="tal"
+OUT_DIR="out"
+
+# Ensure output directory exists
+mkdir -p "$OUT_DIR"
+
+echo "Testing Uxntal AWK Assembler"
+echo "============================="
+
+# Check if reference assembler exists
+if [ ! -f "$REF_ASM" ]; then
+    echo -e "${RED}Error: Reference assembler not found at $REF_ASM${NC}"
+    echo "Please compile the reference implementation first:"
+    echo "  cd ../ref && make"
+    exit 1
+fi
+
+# Check if AWK assembler exists
+if [ ! -f "$AWK_ASM" ]; then
+    echo -e "${RED}Error: AWK assembler not found at $AWK_ASM${NC}"
+    exit 1
+fi
+
+# Test function
+test_file() {
+    local input_file="$1"
+    local base_name=$(basename "$input_file" .tal)
+    
+    echo -n "Testing $base_name.tal... "
+    
+    # Run reference assembler
+    if ! "$REF_ASM" "$input_file" "$OUT_DIR/${base_name}_ref.rom" >/dev/null 2>&1; then
+        echo -e "${RED}FAIL${NC} (reference assembler failed)"
+        return 1
+    fi
+    
+    # Run AWK assembler
+    if [ "$DEBUG_AWK" -eq 1 ]; then
+        awk -f "$AWK_ASM" "$input_file" "$OUT_DIR/${base_name}_awk.rom" 2> "$OUT_DIR/${base_name}_awk.debug"
+    else
+        awk -f "$AWK_ASM" "$input_file" "$OUT_DIR/${base_name}_awk.rom" >/dev/null 2>&1
+    fi
+    
+    # Compare outputs
+    if cmp -s "$OUT_DIR/${base_name}_ref.rom" "$OUT_DIR/${base_name}_awk.rom"; then
+        echo -e "${GREEN}PASS${NC}"
+        if [ "$DEBUG_AWK" -eq 1 ]; then
+            echo "  Debug output: $OUT_DIR/${base_name}_awk.debug"
+        fi
+        return 0
+    else
+        echo -e "${RED}FAIL${NC} (outputs differ)"
+        echo "  Reference size: $(wc -c < "$OUT_DIR/${base_name}_ref.rom") bytes"
+        echo "  AWK size: $(wc -c < "$OUT_DIR/${base_name}_awk.rom") bytes"
+        echo "  Diff:"
+        xxd "$OUT_DIR/${base_name}_ref.rom" > "$OUT_DIR/${base_name}_ref.hex"
+        xxd "$OUT_DIR/${base_name}_awk.rom" > "$OUT_DIR/${base_name}_awk.hex"
+        diff "$OUT_DIR/${base_name}_ref.hex" "$OUT_DIR/${base_name}_awk.hex" || true
+        if [ "$DEBUG_AWK" -eq 1 ]; then
+            echo "  Debug output: $OUT_DIR/${base_name}_awk.debug"
+        fi
+        return 1
+    fi
+}
+
+# Run tests
+failed=0
+total=0
+
+for test_file in "$TEST_DIR"/*.tal; do
+    if [ -f "$test_file" ]; then
+        total=$((total + 1))
+        if ! test_file "$test_file"; then
+            failed=$((failed + 1))
+        fi
+    fi
+done
+
+echo
+echo "============================="
+echo "Results: $((total - failed))/$total tests passed"
+
+if [ $failed -eq 0 ]; then
+    echo -e "${GREEN}All tests passed!${NC}"
+    exit 0
+else
+    echo -e "${RED}$failed tests failed${NC}"
+    exit 1
+fi
diff --git a/awk/uxn/test/tal/brk.tal b/awk/uxn/test/tal/brk.tal
new file mode 100644
index 0000000..bf83010
--- /dev/null
+++ b/awk/uxn/test/tal/brk.tal
@@ -0,0 +1 @@
+BRK
\ No newline at end of file
diff --git a/awk/uxn/test/tal/brk_test.tal b/awk/uxn/test/tal/brk_test.tal
new file mode 100644
index 0000000..487f63d
--- /dev/null
+++ b/awk/uxn/test/tal/brk_test.tal
@@ -0,0 +1 @@
+BRK 
\ No newline at end of file
diff --git a/awk/uxn/test/tal/brk_with_data.tal b/awk/uxn/test/tal/brk_with_data.tal
new file mode 100644
index 0000000..c055e74
--- /dev/null
+++ b/awk/uxn/test/tal/brk_with_data.tal
@@ -0,0 +1 @@
+#01 #02 ADD BRK 
\ No newline at end of file
diff --git a/awk/uxn/test/tal/bunnymark.tal b/awk/uxn/test/tal/bunnymark.tal
new file mode 100644
index 0000000..579d305
--- /dev/null
+++ b/awk/uxn/test/tal/bunnymark.tal
@@ -0,0 +1,221 @@
+( bunnymark.tal )
+	( November 2021, Kira Oakley )
+	( March 2022, Devine Lu Linvega )
+
+|00 @System &vector $2 &pad $6 &r $2 &g $2 &b $2 &debug $1 &halt $1
+|20 @Screen &vector $2 &width $2 &height $2 &auto $1 &pad $1 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1
+|80 @Controller &vector $2 &button $1 &key $1
+|90 @Mouse &vector $2 &x $2 &y $2 &state $1 &wheel $1
+|c0 @DateTime &year $2 &month $1 &day $1 &hour $1 &minute $1 &second $1 &dotw $1 &doty $2 &isdst $1
+
+|0000
+
+	@frames $2
+	@last $1
+
+|0100
+
+@on-reset ( -> )
+	( | theme )
+	#2ce9 .System/r DEO2
+	#01c0 .System/g DEO2
+	#2ce5 .System/b DEO2
+	( | interrupts )
+	;on-frame .Screen/vector DEO2
+	( | fps label )
+	.Screen/width DEI2 #0046 SUB2 .Screen/x DEO2
+	#0008 .Screen/y DEO2
+	;text/fps #42 <draw-str>
+	( | bunnies label )
+	#0004 .Screen/x DEO2
+	;text/bunnies #42 <draw-str>
+	( | instructions label )
+	.Screen/width DEI2 #01 SFT2 #0050 SUB2 .Screen/x DEO2
+	;text/instructions #43 <draw-str>
+	#0028 #0008 #0000 <draw-dec>
+	( | seed prng )
+	prng-init BRK
+
+@on-frame ( -> )
+	.frames LDZ2k INC2 ROT STZ2
+	.DateTime/second DEI .last LDZ EQU ?{
+		.DateTime/second DEI .last STZ
+		.Screen/width DEI2 #002b SUB2 #0008 .frames LDZ2 <draw-dec>
+		#0000 .frames STZ2 }
+	( | mouse handling )
+	.Mouse/state DEI
+	( ) DUP #01 NEQ ?{ add-bunny }
+	( ) #02 LTH ?{ remove-bunny }
+	( | controller handling )
+	.Controller/button DEI
+	( ) DUP #01 NEQ ?{ add-bunny }
+	( ) #02 LTH ?{ remove-bunny }
+	( | clear )
+	#0000 DUP2 .Screen/x DEO2
+	.Screen/y DEO2
+	[ LIT2 80 -Screen/pixel ] DEO
+	;sprite/length LDA2 #0000
+	&loop ( -- )
+		EQU2k ?&bail
+		DUP2 <draw-bunny>
+		INC2 !&loop
+	&bail ( -- )
+		POP2 POP2 BRK
+
+@add-bunny ( -- )
+	;sprite/length LDA2
+	( | cap bunny count at 65535 )
+	DUP2 #ffff EQU2 ?&bail
+	( | compute the offset to the beginning of this new bunny's data )
+	DUP2 #30 SFT2 ;sprite/array ADD2
+	( | populate the new bunny's x/y/xvel/yvel with random values )
+	#00 rand OVR2 STA2
+	rand #1f AND rand OVR2 INC2 INC2 STA2
+	#00 rand #7f AND OVR2 #0004 ADD2 STA2
+	#00 rand #7f AND OVR2 #0006 ADD2 STA2
+	( | pop ptr to bunny data )
+	POP2
+	( | write new increased array length )
+	INC2 DUP2 ;sprite/length STA2
+	( | update label )
+	STH2k #0028 #0008 STH2r <draw-dec>
+	&bail ( pop sprite/length )
+		POP2 JMP2r
+
+@remove-bunny ( -- )
+	;sprite/length LDA2
+	( don't let length go below 0 ) ORAk #00 EQU ?&bail
+	#0001 SUB2 DUP2 ;sprite/length STA2
+	( update label ) STH2k #0028 #0008 STH2r <draw-dec>
+	&bail POP2 JMP2r
+
+(
+@|drawing )
+
+@<draw-bunny> ( idx -- )
+	( | compute the offset to the beginning of this bunny's data )
+	#30 SFT2 ;sprite/array ADD2
+	( | move the sprite by its velocity )
+	LDA2k OVR2 #0004 ADD2 LDA2 ADD2 OVR2 STA2
+	INC2k INC2 LDA2 OVR2 #0006 ADD2 LDA2 ADD2 OVR2 INC2 INC2 STA2
+	( | check for right wall collision + bounce x )
+	DUP2 #0004 ADD2 LDA2 #0f SFT2 #0001 EQU2 ?&skip-max-x
+	LDA2k #05 SFT2 #0008 ADD2 .Screen/width DEI2 LTH2 ?&skip-max-x
+	DUP2 #0004 ADD2 LDA2 #ffff MUL2 OVR2 #0004 ADD2 STA2
+	&skip-max-x ( check for left wall collision + bounce x )
+		LDA2k #0f SFT2 #0000 EQU2 ?&skip-min-x
+		DUP2 #0004 ADD2 LDA2 #ffff MUL2 OVR2 #0004 ADD2 STA2
+	&skip-min-x ( check for bottom wall collision + bounce y )
+		DUP2 #0006 ADD2 LDA2 #0f SFT2 #0001 EQU2 ?&skip-max-y
+		INC2k INC2 LDA2 #05 SFT2 #0010 ADD2 .Screen/height DEI2 LTH2 ?&skip-max-y
+		DUP2 #0006 ADD2 LDA2 #ffff MUL2 OVR2 #0006 ADD2 STA2
+		!&skip-gravity
+	&skip-max-y ( check for top wall collision + bounce x )
+		INC2k INC2 LDA2 #0f SFT2 #0000 EQU2 ?&skip-min-y
+		DUP2 #0006 ADD2 LDA2 #ffff MUL2 OVR2 #0006 ADD2 STA2
+		!&skip-gravity
+	&skip-min-y ( apply gravity )
+		DUP2 #0006 ADD2 LDA2 #0004 ADD2 OVR2 #0006 ADD2 STA2
+	&skip-gravity ( draw the sprite )
+		( top ) LDA2k #05 SFT2 .Screen/x DEO2
+		INC2 INC2 LDA2 #05 SFT2 .Screen/y DEO2
+		( draw ) [ LIT2 15 -Screen/auto ] DEO
+		;bunny-chr .Screen/addr DEO2
+		[ LIT2 85 -Screen/sprite ] DEO
+		[ LIT2 00 -Screen/auto ] DEO
+		JMP2r
+
+@<draw-str> ( x* y* text* color -- )
+	,&t STR
+	[ LIT2 01 -Screen/auto ] DEO
+	&loop ( -- )
+		LDAk #20 SUB #00 SWP #30 SFT2 ;font ADD2 .Screen/addr DEO2
+		[ LIT2 &t $1 -Screen/sprite ] DEO
+		INC2 LDAk ?&loop
+	POP2 JMP2r
+
+@<draw-dec> ( x* y* num* -- )
+	[ LIT2 01 -Screen/auto ] DEO
+	SWP2 .Screen/y DEO2
+	SWP2 .Screen/x DEO2
+	#2710 DIV2k DUP <draw-digit>
+	MUL2 SUB2 #03e8 DIV2k DUP <draw-digit>
+	MUL2 SUB2 #0064 DIV2k DUP <draw-digit>
+	MUL2 SUB2 NIP #0a DIVk DUP <draw-digit>
+	MUL SUB <draw-digit>
+	[ LIT2 00 -Screen/auto ] DEO
+	JMP2r
+
+@<draw-digit> ( num -- )
+	#30 SFT #00 SWP ;font/num ADD2 .Screen/addr DEO2
+	[ LIT2 41 -Screen/sprite ] DEO
+	JMP2r
+
+(
+@|random )
+
+@prng-init ( -- )
+	[ LIT2 00 -DateTime/second ] DEI [ LIT2 00 -DateTime/minute ] DEI #60 SFT2 EOR2 [ LIT2 00 -DateTime/hour ] DEI #c0 SFT2 EOR2 ,prng/x STR2
+	[ LIT2 00 -DateTime/hour ] DEI #04 SFT2 [ LIT2 00 -DateTime/day ] DEI #10 SFT2 EOR2 [ LIT2 00 -DateTime/month ] DEI #60 SFT2 EOR2 .DateTime/year DEI2 #a0 SFT2 EOR2 ,prng/y STR2
+	JMP2r
+
+@prng ( -- number* )
+	[ LIT2 &x $2 ] DUP2 #50 SFT2 EOR2 DUP2 #03 SFT2 EOR2 [ LIT2 &y $2 ] DUP2 ,&x STR2
+	DUP2 #01 SFT2 EOR2 EOR2 ,&y STR2k POP JMP2r
+
+@rand ( -- number )
+	prng ADD JMP2r
+	( static string data )
+
+(
+@|assets )
+
+@text &fps "FPS: $1
+	&bunnies "BUNS: $1
+	&instructions "CLICK 20 "TO 20 "ADD 20 "BUNNIES! $1
+
+@font ( atari8.uf1 )
+	[
+	0000 0000 0000 0000 6060 6060 6000 6000
+	6666 6600 0000 0000 006c fe6c 6cfe 6c00
+	183e 603c 067c 1800 0066 6c18 3066 4600
+	386c 3870 decc 7600 6060 6000 0000 0000
+	0e1c 1818 181c 0e00 7038 1818 1838 7000
+	0066 3cff 3c66 0000 0018 187e 1818 0000
+	0000 0000 0030 3060 0000 007e 0000 0000
+	0000 0000 0018 1800 0206 0c18 3060 4000 ] &num [
+	3c66 6e76 6666 3c00 1838 1818 1818 7e00
+	3c66 060c 1830 7e00 7e0c 180c 0666 3c00
+	0c1c 3c6c 7e0c 0c00 7e60 7c06 0666 3c00
+	3c60 607c 6666 3c00 7e06 0c18 3030 3000
+	3c66 663c 6666 3c00 3c66 663e 060c 3800
+	0060 6000 6060 0000 0030 3000 3030 6000
+	0c18 3060 3018 0c00 0000 7e00 007e 0000
+	6030 180c 1830 6000 3c66 060c 1800 1800
+	3c66 6e6a 6e60 3e00 183c 6666 7e66 6600
+	7c66 667c 6666 7c00 3c66 6060 6066 3c00
+	786c 6666 666c 7800 7e60 607c 6060 7e00
+	7e60 607c 6060 6000 3e60 606e 6666 3e00
+	6666 667e 6666 6600 7830 3030 3030 7800
+	0606 0606 0666 3c00 666c 7870 786c 6600
+	6060 6060 6060 7e00 c6ee fed6 c6c6 c600
+	6676 7e7e 6e66 6600 3c66 6666 6666 3c00
+	7c66 667c 6060 6000 3c66 6666 766c 3600
+	7c66 667c 6c66 6600 3c66 603c 0666 3c00
+	7e18 1818 1818 1800 6666 6666 6666 3e00
+	6666 6666 663c 1800 c6c6 c6d6 feee c600
+	6666 3c18 3c66 6600 6666 663c 1818 1800
+	7e06 0c18 3060 7e00 7860 6060 6060 7800 ]
+
+@fill-icn [ ffff ffff ffff ffff ]
+
+@bunny-chr [
+	2466 6600 2424 003c 4200 007e 7e7e 7e7e
+	1818 3c3c 1800 0000 ff66 4242 667e 4242 ]
+
+(
+@|memory )
+
+@sprite &length $2
+	&array &x 0600 &y 0500 &xvel 0060 &yvel 0010
+
diff --git a/awk/uxn/test/tal/life.tal b/awk/uxn/test/tal/life.tal
new file mode 100644
index 0000000..718068b
--- /dev/null
+++ b/awk/uxn/test/tal/life.tal
@@ -0,0 +1,221 @@
+( uxnemu life.rom )
+	( Any live cell with fewer than two live neighbours dies, as if by underpopulation. )
+	( Any live cell with two or three live neighbours lives on to the next generation. )
+	( Any live cell with more than three live neighbours dies, as if by overpopulation. )
+	( Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction. )
+
+|00 @System &vector $2 &expansion $2 &wst $1 &rst $1 &metadata $2 &r $2 &g $2 &b $2 &debug $1 &state $1
+|10 @Console &vector $2 &read $1 &pad $5 &write $1 &error $1
+|20 @Screen &vector $2 &width $2 &height $2 &auto $1 &pad $1 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1
+|30 @Audio0 &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1
+|80 @Controller &vector $2 &button $1 &key $1
+|90 @Mouse &vector $2 &x $2 &y $2 &state $1 &wheel $1
+|000
+
+	@world &count $2
+	@anchor &x $2 &y $2 &x2 $2 &y2 $2
+
+|100
+
+@on-reset ( -> )
+	( | theme )
+	#02cf .System/r DEO2
+	#02ff .System/g DEO2
+	#024f .System/b DEO2
+	( | resize )
+	#00c0 DUP2 .Screen/width DEO2
+	.Screen/height DEO2
+	( | vectors )
+	;on-frame .Screen/vector DEO2
+	;on-mouse .Mouse/vector DEO2
+	;on-control .Controller/vector DEO2
+	( | glider )
+	#0703 <set-cell>
+	#0704 <set-cell>
+	#0504 <set-cell>
+	#0705 <set-cell>
+	#0605 <set-cell>
+	( | center )
+	.Screen/width DEI2 #01 SFT2 #0040 SUB2 DUP2 .anchor/x STZ2
+	#007e ADD2 .anchor/x2 STZ2
+	.Screen/height DEI2 #01 SFT2 #0040 SUB2 DUP2 .anchor/y STZ2
+	#007e ADD2 .anchor/y2 STZ2
+	BRK
+
+@on-frame ( -> )
+	[ LIT2 00 -Mouse/state ] DEI EQU ?{ BRK }
+	#0000 .world/count STZ2
+	[ LIT &f $1 ] INCk ,&f STR
+	( ) #03 AND #00 EQU ?{ BRK }
+	<run>
+	BRK
+
+@on-mouse ( -> )
+	[ LIT2 00 -Mouse/state ] DEI NEQ #42 ADD ;cursor-icn <update-cursor>
+	( | on touch in rect )
+	.Mouse/state DEI ?{ BRK }
+	.Mouse/x DEI2 .Mouse/y DEI2 .anchor within-rect ?{ BRK }
+	( | paint )
+	.Mouse/x DEI2 .anchor/x LDZ2 SUB2 #01 SFT NIP
+	( ) .Mouse/y DEI2 .anchor/y LDZ2 SUB2 #01 SFT NIP <set-cell>
+	<redraw>
+	BRK
+
+@on-control ( -> )
+	.Controller/key DEI
+	( ) DUP #20 NEQ ?{
+		#0000 ;on-frame .Screen/vector DEI2 ORA ?{ SWP2 }
+		POP2 .Screen/vector DEO2 }
+	( ) #1b NEQ ?{ ;MMU/clear1 .System/expansion DEO2 }
+	BRK
+
+(
+@|core )
+
+@<run> ( -- )
+	;MMU/clear2 .System/expansion DEO2
+	#4000
+	&ver ( -- )
+		DUP ,&y STR
+		#4000
+	&hor ( -- )
+		DUP [ LIT &y $1 ] <run-cell>
+		INC GTHk ?&hor
+	POP2 INC GTHk ?&ver
+	POP2
+	( move ) ;MMU/move21 .System/expansion DEO2
+	!<redraw>
+
+@<run-cell> ( x y -- )
+	( x y ) DUP2 STH2k
+	( neighbours ) get-neighbours
+	( state ) STH2r get-index LDA #00 EQU ?&dead
+	DUP #02 LTH ?&dies
+	DUP #03 GTH ?&dies
+	POP !&save
+	&dies POP POP2 JMP2r
+	&dead ( -- )
+		DUP #03 EQU ?&birth
+		POP POP2 JMP2r
+		&birth POP !&save
+	&save ( x y -- )
+		STH2
+		#01 STH2r get-index #1000 ADD2 STA
+		.world/count LDZ2 INC2 .world/count STZ2
+		JMP2r
+
+@get-index ( x y -- index* )
+	( y ) #3f AND #00 SWP #60 SFT2 ROT
+	( x ) #3f AND #00 SWP ADD2 ;bank1 ADD2 JMP2r
+
+@<set-cell> ( x y -- )
+	get-index STH2
+	#01 STH2r STA
+	JMP2r
+
+@get-neighbours ( x y -- neighbours )
+	,&y STR
+	,&x STR
+	[ LITr 00 ] #0800
+	&l ( -- )
+		#00 OVRk ADD2 ;&mask ADD2 LDA2
+		( ) [ LIT &y $1 ] ADD SWP
+		( ) [ LIT &x $1 ] ADD SWP get-index LDA [ STH ADDr ]
+		( stop at 3 ) DUPr [ LITr 03 ] GTHr [ LITr _&end ] JCNr
+		( ) INC GTHk ?&l
+	&end POP2 STHr JMP2r
+	&mask [
+	ffff 00ff 01ff ff00 0100 ff01 0001 0101 ]
+
+@within-rect ( x* y* rect -- flag )
+	STH
+	( y < rect.y1 ) DUP2 STHkr INC INC LDZ2 LTH2 ?&skip
+	( y > rect.y2 ) DUP2 STHkr #06 ADD LDZ2 GTH2 ?&skip
+	SWP2
+	( x < rect.x1 ) DUP2 STHkr LDZ2 LTH2 ?&skip
+	( x > rect.x2 ) DUP2 STHkr #04 ADD LDZ2 GTH2 ?&skip
+	POP2 POP2 POPr #01 JMP2r
+	&skip POP2 POP2 POPr #00 JMP2r
+
+(
+@|drawing )
+
+@<redraw> ( -- )
+	( | draw count )
+	.anchor/x LDZ2 .Screen/x DEO2
+	.anchor/y2 LDZ2 #0008 ADD2 .Screen/y DEO2
+	[ LIT2 01 -Screen/auto ] DEO
+	.world/count LDZ2 <draw-short>
+	( | draw grid )
+	[ LIT2 01 -Screen/auto ] DEO
+	.anchor/y LDZ2 .Screen/y DEO2
+	;bank2 ;bank1
+	&l ( -- )
+		DUP #3f AND ?{
+			.Screen/y DEI2k INC2 INC2 ROT DEO2
+			.anchor/x LDZ2 .Screen/x DEO2 }
+		LDAk INC .Screen/pixel DEO
+		[ LIT2 00 -Screen/pixel ] DEO
+		INC2 GTH2k ?&l
+	POP2 POP2 JMP2r
+
+@<draw-short> ( short* -- )
+	SWP <draw-byte>
+	( >> )
+
+@<draw-byte> ( byte color -- )
+	DUP #04 SFT <draw-hex>
+	#0f AND
+	( >> )
+
+@<draw-hex> ( char color -- )
+	#00 SWP #30 SFT2 ;font-hex ADD2 .Screen/addr DEO2
+	[ LIT2 03 -Screen/sprite ] DEO
+	JMP2r
+
+@<update-cursor> ( color addr* -- )
+	[ LIT2 00 -Screen/auto ] DEO
+	;fill-icn .Screen/addr DEO2
+	#40 <draw-cursor>
+	.Mouse/x DEI2 ,<draw-cursor>/x STR2
+	.Mouse/y DEI2 ,<draw-cursor>/y STR2
+	.Screen/addr DEO2
+	( >> )
+
+@<draw-cursor> ( color -- )
+	[ LIT2 &x $2 ] .Screen/x DEO2
+	[ LIT2 &y $2 ] .Screen/y DEO2
+	.Screen/sprite DEO
+	JMP2r
+
+(
+@|assets )
+
+@MMU ( programs )
+	&clear1 [ 01 1000 0000 =bank3 0000 =bank1 ]
+	&clear2 [ 01 1000 0000 =bank3 0000 =bank2 ]
+	&move21 [ 01 1000 0000 =bank2 0000 =bank1 ]
+
+@cursor-icn [ 80c0 e0f0 f8e0 1000 ]
+
+@fill-icn [ ffff ffff ffff ffff ]
+
+@font-hex [
+	7c82 8282 8282 7c00 3010 1010 1010 3800
+	7c82 027c 8080 fe00 7c82 021c 0282 7c00
+	2242 82fe 0202 0200 fe80 807c 0282 7c00
+	7c82 80fc 8282 7c00 fe82 0408 0810 1000
+	7c82 827c 8282 7c00 7c82 827e 0202 0200
+	7c82 82fe 8282 8200 fc82 82fc 8282 fc00
+	7c82 8080 8082 7c00 fc82 8282 8282 fc00
+	fe80 80f0 8080 fe00 fe80 80f0 8080 8000 ]
+
+(
+@|memory )
+
+|8000 @bank1 $1000
+
+@bank2 $1000
+
+@bank3 $1000
+
diff --git a/awk/uxn/test/tal/opctest.tal b/awk/uxn/test/tal/opctest.tal
new file mode 100644
index 0000000..b803de6
--- /dev/null
+++ b/awk/uxn/test/tal/opctest.tal
@@ -0,0 +1,492 @@
+( Opcode Tester )
+
+|0013
+
+	@Zeropage &byte $1 &short $2
+	@id $1
+
+|100
+
+@on-reset ( -> )
+
+	( part 1
+		> LIT2: Puts a short on the stack
+		> LIT: Puts a byte on the stack
+		> #06 DEO: Write to metadata ports
+		> #18 DEO: Write a letter in terminal )
+
+	;meta #06 DEO2
+	[ LIT2 "kO ] #18 DEO #18 DEO
+	[ LIT2 "1 18 ] DEO #0a18 DEO
+
+	( part 2
+		> LITr: Put a byte on return stack
+		> STH: Move a byte from working stack to return stack
+		> STH2r: Move a short from return stack to working stack )
+
+	[ LITr "k ] [ LIT "O ] STH STH2r #18 DEO #18 DEO
+	[ LIT2 "2 18 ] DEO #0a18 DEO
+
+	( part 3
+		> LIT2r: Put a short on return stack
+		> DUP: Duplicate byte
+		> ADDr: Add bytes on return stack )
+
+	[ LIT2r "k 4d ] #01 DUP STH ADDr STH ADDr STH2r #18 DEO #18 DEO
+	[ LIT2 "3 18 ] DEO #0a18 DEO
+
+	( part 4
+		> JSI: Subroutine to relative short address
+		> JMP2r: Jumps to absolute address on return stack )
+
+	subroutine
+	[ LIT2 "4 18 ] DEO #0a18 DEO
+
+	( part 5
+		> POP2: Removes a short from the stack
+		> INC2: Increments short on stack
+		> DUP2: Duplicate short
+		> LDA: load byte from absolute address
+		> JCI: Conditional subroutine to relative short address )
+
+	;Dict/ok pstr
+	[ LIT2 "5 18 ] DEO #0a18 DEO
+
+	( part 6
+		> JSR2: Jump to subroutine from short pointer
+		> LDAk: Non-destructive load byte from absolute address )
+
+	{ "Ok $1 } STH2r ;pstr-jcn JSR2
+	[ LIT2 "6 18 ] DEO #0a18 DEO
+
+	( part 7
+		> Relative distance bytes )
+
+	rel-distance/entry SWP #18 DEO #18 DEO
+	[ LIT2 "7 18 ] DEO #0a18 DEO
+
+	( part xx
+		> GTH2k: Non-destructive greater-than short
+		> LDA2k: Non-destructive load short from absolute address
+		> STA2: Store short at absolute address )
+
+	[ LIT2r 0000 ]
+	;tests/end ;tests
+	&l
+		run-test [ LITr 00 ] STH ADD2r
+		INC2 INC2 GTH2k ?&l
+	POP2 POP2
+	STH2r ;tests/end ;tests SUB2 #01 SFT2
+	EQU2 ;Dict/opctests test-part
+
+	( Part xx
+		> Testing that stacks are circular and wrapping
+		> Storing 12 at -1 and 34 at 0 )
+
+	POP #12 #34 ADD #46 EQU STH
+	POP #1234 ADD #46 EQU STH
+	POP2 #1111 #2222 ADD2 #3333 EQU2
+	STHr AND STHr AND
+	;Dict/stack-wrap test-part
+
+	( restore stack ) #0000 #0000
+
+	( Part xx
+		> Testing RAM wrapping
+		> Storing 12 in 0xffff, and 34 in 0x0000 )
+
+	#1234 #ffff STA2
+	( LDA ) #0000 LDA #ffff LDA ADD #46 EQU
+	( LDA2 ) #ffff LDA2 ADD #46 EQU
+	AND ;Dict/ram-wrap test-part
+
+	( Part xx
+		> Testing that zero-page is wrapping )
+
+	#5678 #ff STZ2
+	( LDZ ) #00 LDZ #ff LDZ ADD #ce EQU
+	( LDZ2 ) #ff LDZ2 ADD #ce EQU
+	AND ;Dict/zp-wrap test-part
+
+	( Part xx
+		> Testing that device page is wrapping )
+
+	#1234 #ff DEO2
+	( DEI ) #00 DEI #ff DEI ADD #46 EQU
+	( DEI2 ) #ff DEI2 ADD #46 EQU
+	AND ;Dict/dev-wrap test-part
+	#0000 DEO #00ff DEO
+
+	( end )
+
+	[ LIT &fail 80 ]
+		DUP #80 EQU ;Dict/result test-part
+		#0f DEO
+
+	#0a18 DEO
+	#010e DEO
+
+BRK
+
+(
+@|metadata )
+
+@meta 00
+	( name ) "Opctest 0a
+	( details ) "A 20 "Testing 20 "Program 0a
+	( author ) "By 20 "Devine 20 "Lu 20 "Linvega 0a
+	( date ) "24 20 "Jun 20 "2025 $2
+
+@test-part ( f name* -- )
+	pstr ?{
+		#01 ;on-reset/fail STA
+		;Dict/failed !pstr }
+	;Dict/passed !pstr
+
+@run-test ( addr* -- addr* f )
+
+	LDA2k JSR2 DUP ?&pass
+		;Dict/missed pstr
+		[ LIT2 &name $2 ] pstr
+		[ LIT2 "# 18 ] DEO
+		[ LIT2 "a -id ] LDZ ADD #18 DEO
+		#0a18 DEO
+		#01 ;on-reset/fail STA
+		&pass
+	.id LDZ INC .id STZ
+
+JMP2r
+
+@set ( name* -- f )
+
+	;run-test/name STA2 #01
+	[ LIT2 ff -id ] STZ
+
+JMP2r
+
+@pstr ( str* -- )
+	DUP2 LDA
+		DUP ?{ POP POP2 JMP2r }
+		#18 DEO
+	INC2 !pstr
+
+@pstr-jcn ( str* -- )
+	LDAk #18 DEO
+	INC2 LDAk ,pstr-jcn JCN
+	POP2
+	JMP2r
+
+@tests
+=op-equ [
+	=op-equ/a =op-equ/b =op-equ/c =op-equ/d
+	=op-equ/e =op-equ/f =op-equ/g =op-equ/h ]
+=op-neq [
+	=op-neq/a =op-neq/b =op-neq/c =op-neq/d
+	=op-neq/e =op-neq/f =op-neq/g =op-neq/h ]
+=op-gth [
+	=op-gth/a =op-gth/b =op-gth/c =op-gth/d
+	=op-gth/e =op-gth/f =op-gth/g =op-gth/h ]
+=op-lth [
+	=op-lth/a =op-lth/b =op-lth/c =op-lth/d
+	=op-lth/e =op-lth/f =op-lth/g =op-lth/h ]
+=op-add [
+	=op-add/a =op-add/b =op-add/c =op-add/d
+	=op-add/e =op-add/f =op-add/g =op-add/h ]
+=op-sub [
+	=op-sub/a =op-sub/b =op-sub/c =op-sub/d
+	=op-sub/e =op-sub/f =op-sub/g =op-sub/h ]
+=op-mul [
+	=op-mul/a =op-mul/b =op-mul/c =op-mul/d
+	=op-mul/e =op-mul/f =op-mul/g =op-mul/h ]
+=op-div [
+	=op-div/a =op-div/b =op-div/c =op-div/d =op-div/e
+	=op-div/f =op-div/g =op-div/h =op-div/i =op-div/j ]
+=op-inc [
+	=op-inc/a =op-inc/b =op-inc/c =op-inc/d
+	=op-inc/e =op-inc/f =op-inc/g =op-inc/h ]
+=op-pop [
+	=op-pop/a =op-pop/b =op-pop/c =op-pop/d
+	=op-pop/e =op-pop/f =op-pop/g =op-pop/h ]
+=op-dup [
+	=op-dup/a =op-dup/b ]
+=op-nip [
+	=op-nip/a =op-nip/b =op-nip/c =op-nip/d ]
+=op-swp [
+	=op-swp/a =op-swp/b ]
+=op-ovr [
+	=op-ovr/a =op-ovr/b ]
+=op-rot [
+	=op-rot/a =op-rot/b ]
+=op-and [
+	=op-and/a =op-and/b =op-and/c =op-and/d
+	=op-and/e =op-and/f =op-and/g =op-and/h ]
+=op-ora [
+	=op-ora/a =op-ora/b =op-ora/c =op-ora/d
+	=op-ora/e =op-ora/f =op-ora/g =op-ora/h ]
+=op-eor [
+	=op-eor/a =op-eor/b =op-eor/c =op-eor/d
+	=op-eor/e =op-eor/f =op-eor/g =op-eor/h ]
+=op-sft [
+	=op-sft/a =op-sft/b =op-sft/c =op-sft/d
+	=op-sft/e =op-sft/f =op-sft/g =op-sft/h ]
+=op-stz [
+	=op-stz/a =op-stz/b =op-stz/c =op-stz/d ]
+=op-str [
+	=op-str/a =op-str/b =op-str/c =op-str/d ]
+=op-sta [
+	=op-sta/a =op-sta/b =op-sta/c =op-sta/d ]
+=op-jmp [
+	=op-jmp/a =op-jmp/b ]
+=op-jcn [
+	=op-jcn/a =op-jcn/b =op-jcn/c =op-jcn/d ]
+=op-jsr [
+	=op-jsr/a =op-jsr/b ]
+=op-sth [
+	=op-sth/a =op-sth/b ]
+=op-jci [
+	=op-jci/a =op-jci/b =op-jci/c ]
+=op-jmi [
+	=op-jmi/a ]
+=op-jsi [
+	=op-jsi/a =op-jsi/b =op-jsi/c =op-jsi/d ]
+	&end
+
+@op-equ ;Dict/equ !set
+	&a #f8 #f8 EQU [ #01 ] EQU JMP2r
+	&b #01 #01 EQU [ #01 ] EQU JMP2r
+	&c #f8 #01 EQU [ #00 ] EQU JMP2r
+	&d #00 #ff EQU [ #00 ] EQU JMP2r
+	&e #f801 #f801 EQU2 [ #01 ] EQU JMP2r
+	&f #01f8 #01f8 EQU2 [ #01 ] EQU JMP2r
+	&g #f801 #01f8 EQU2 [ #00 ] EQU JMP2r
+	&h #01f8 #f801 EQU2 [ #00 ] EQU JMP2r
+@op-neq ;Dict/neq !set
+	&a #f8 #f8 NEQ [ #00 ] EQU JMP2r
+	&b #01 #01 NEQ [ #00 ] EQU JMP2r
+	&c #f8 #01 NEQ [ #01 ] EQU JMP2r
+	&d #01 #f8 NEQ [ #01 ] EQU JMP2r
+	&e #f801 #f801 NEQ2 [ #00 ] EQU JMP2r
+	&f #01f8 #01f8 NEQ2 [ #00 ] EQU JMP2r
+	&g #f801 #01f8 NEQ2 [ #01 ] EQU JMP2r
+	&h #01f8 #f801 NEQ2 [ #01 ] EQU JMP2r
+@op-gth ;Dict/gth !set
+	&a #f8 #f8 GTH [ #00 ] EQU JMP2r
+	&b #01 #01 GTH [ #00 ] EQU JMP2r
+	&c #f8 #01 GTH [ #01 ] EQU JMP2r
+	&d #01 #f8 GTH [ #00 ] EQU JMP2r
+	&e #f801 #f801 GTH2 [ #00 ] EQU JMP2r
+	&f #01f8 #01f8 GTH2 [ #00 ] EQU JMP2r
+	&g #f801 #01f8 GTH2 [ #01 ] EQU JMP2r
+	&h #01f8 #f801 GTH2 [ #00 ] EQU JMP2r
+@op-lth ;Dict/lth !set
+	&a #f8 #f8 LTH [ #00 ] EQU JMP2r
+	&b #01 #01 LTH [ #00 ] EQU JMP2r
+	&c #f8 #01 LTH [ #00 ] EQU JMP2r
+	&d #01 #ff LTH [ #01 ] EQU JMP2r
+	&e #f801 #f801 LTH2 [ #00 ] EQU JMP2r
+	&f #01f8 #01f8 LTH2 [ #00 ] EQU JMP2r
+	&g #f801 #01f8 LTH2 [ #00 ] EQU JMP2r
+	&h #01f8 #f801 LTH2 [ #01 ] EQU JMP2r
+@op-add ;Dict/add !set
+	&a #ff #00 ADD [ #ff ] EQU JMP2r
+	&b #01 #ff ADD [ #00 ] EQU JMP2r
+	&c #ff #ff ADD [ #fe ] EQU JMP2r
+	&d #12 #34 ADDk ADD ADD [ #8c ] EQU JMP2r
+	&e #ffff #0000 ADD2 [ #ffff ] EQU2 JMP2r
+	&f #0001 #ffff ADD2 [ #0000 ] EQU2 JMP2r
+	&g #ffff #ffff ADD2 [ #fffe ] EQU2 JMP2r
+	&h #fffe #ffff ADD2 [ #fffd ] EQU2 JMP2r
+@op-sub ;Dict/sub !set
+	&a #ff #00 SUB [ #ff ] EQU JMP2r
+	&b #01 #ff SUB [ #02 ] EQU JMP2r
+	&c #ff #ff SUB [ #00 ] EQU JMP2r
+	&d #fe #ff SUB [ #ff ] EQU JMP2r
+	&e #ffff #0000 SUB2 [ #ffff ] EQU2 JMP2r
+	&f #0001 #ffff SUB2 [ #0002 ] EQU2 JMP2r
+	&g #ffff #ffff SUB2 [ #0000 ] EQU2 JMP2r
+	&h #fffe #ffff SUB2 [ #ffff ] EQU2 JMP2r
+@op-mul ;Dict/mul !set
+	&a #00 #01 MUL [ #00 ] EQU JMP2r
+	&b #3f #e7 MUL [ #d9 ] EQU JMP2r
+	&c #37 #3f MUL [ #89 ] EQU JMP2r
+	&d #10 #02 MUL [ #20 ] EQU JMP2r
+	&e #1000 #0003 MUL2 [ #3000 ] EQU2 JMP2r
+	&f #abcd #1234 MUL2 [ #4fa4 ] EQU2 JMP2r
+	&g #8000 #0200 MUL2 [ #0000 ] EQU2 JMP2r
+	&h #2222 #0003 MUL2 [ #6666 ] EQU2 JMP2r
+@op-div ;Dict/div !set
+	&a #10 #06 DIV [ #02 ] EQU JMP2r
+	&b #20 #20 DIV [ #01 ] EQU JMP2r
+	&c #34 #01 DIV [ #34 ] EQU JMP2r
+	&d #02 #ef DIV [ #00 ] EQU JMP2r
+	&e #02 #00 DIV [ #00 ] EQU JMP2r
+	&f #03e8 #0006 DIV2 [ #00a6 ] EQU2 JMP2r
+	&g #abcd #1234 DIV2 [ #0009 ] EQU2 JMP2r
+	&h #8000 #0200 DIV2 [ #0040 ] EQU2 JMP2r
+	&i #2222 #0003 DIV2 [ #0b60 ] EQU2 JMP2r
+	&j #0202 #0000 DIV2 [ #0000 ] EQU2 JMP2r
+@op-inc ;Dict/inc !set
+	&a #01 INC [ #02 ] EQU JMP2r
+	&b #ff INC [ #00 ] EQU JMP2r
+	&c #fe INC [ #ff ] EQU JMP2r
+	&d #00 INC [ #01 ] EQU JMP2r
+	&e #0001 INC2 [ #0002 ] EQU2 JMP2r
+	&f #ffff INC2 [ #0000 ] EQU2 JMP2r
+	&g #fffe INC2 [ #ffff ] EQU2 JMP2r
+	&h #0000 INC2 [ #0001 ] EQU2 JMP2r
+@op-pop ;Dict/pop !set
+	&a #0a #0b POP [ #0a ] EQU JMP2r
+	&b #0a #0b #0c POP POP [ #0a ] EQU JMP2r
+	&c #0a #0b #0c ADD POP [ #0a ] EQU JMP2r
+	&d #0a #0b #0c POP ADD [ #15 ] EQU JMP2r
+	&e #0a0b #0c0d POP2 [ #0a0b ] EQU2 JMP2r
+	&f #0a0b #0c0d #0e0f POP2 POP2 [ #0a0b ] EQU2 JMP2r
+	&g #0a0b #0c0d #0e0f ADD2 POP2 [ #0a0b ] EQU2 JMP2r
+	&h #0a0b #0c0d #0e0f POP2 ADD2 [ #1618 ] EQU2 JMP2r
+@op-dup ;Dict/dup !set
+	&a #0a #0b DUP ADD ADD [ #20 ] EQU JMP2r
+	&b #0a0b DUP2 ADD2 [ #1416 ] EQU2 JMP2r
+@op-nip ;Dict/nip !set
+	&a #12 #34 #56 NIP ADD [ #68 ] EQU JMP2r
+	&b #12 #34 #56 NIPk ADD2 ADD [ #f2 ] EQU JMP2r
+	&c #1234 #5678 #9abc NIP2 ADD2 [ #acf0 ] EQU2 JMP2r
+	&d #1234 #5678 #9abc NIP2k ADD2 ADD2 ADD2 [ #9e24 ] EQU2 JMP2r
+@op-swp ;Dict/swp !set
+	&a #02 #10 SWP DIV [ #08 ] EQU JMP2r
+	&b #0a0b #0c0d SWP2 NIP2 [ #0a0b ] EQU2 JMP2r
+@op-ovr ;Dict/ovr !set
+	&a #02 #10 OVR DIV ADD [ #0a ] EQU JMP2r
+	&b #0a0b #0c0d OVR2 NIP2 ADD2 [ #1416 ] EQU2 JMP2r
+@op-rot ;Dict/rot !set
+	&a #02 #04 #10 ROT DIV ADD [ #0c ] EQU JMP2r
+	&b #0a0b #0c0d #0c0f ROT2 ADD2 NIP2 [ #161a ] EQU2 JMP2r
+@op-and ;Dict/and !set
+	&a #fc #3f AND [ #3c ] EQU JMP2r
+	&b #f0 #0f AND [ #00 ] EQU JMP2r
+	&c #ff #3c AND [ #3c ] EQU JMP2r
+	&d #02 #03 AND [ #02 ] EQU JMP2r
+	&e #f0f0 #00f0 AND2 [ #00f0 ] EQU2 JMP2r
+	&f #aaaa #5555 AND2 [ #0000 ] EQU2 JMP2r
+	&g #ffff #1234 AND2 [ #1234 ] EQU2 JMP2r
+	&h #abcd #0a0c AND2 [ #0a0c ] EQU2 JMP2r
+@op-ora ;Dict/ora !set
+	&a #0f #f0 ORA [ #ff ] EQU JMP2r
+	&b #ab #cd ORA [ #ef ] EQU JMP2r
+	&c #12 #34 ORA [ #36 ] EQU JMP2r
+	&d #88 #10 ORA [ #98 ] EQU JMP2r
+	&e #0f0f #f0f0 ORA2 [ #ffff ] EQU2 JMP2r
+	&f #abab #cdcd ORA2 [ #efef ] EQU2 JMP2r
+	&g #1122 #1234 ORA2 [ #1336 ] EQU2 JMP2r
+	&h #8888 #1000 ORA2 [ #9888 ] EQU2 JMP2r
+@op-eor ;Dict/eor !set
+	&a #00 #00 EOR [ #00 ] EQU JMP2r
+	&b #ff #00 EOR [ #ff ] EQU JMP2r
+	&c #aa #55 EOR [ #ff ] EQU JMP2r
+	&d #ff #ff EOR [ #00 ] EQU JMP2r
+	&e #ffff #ff00 EOR2 [ #00ff ] EQU2 JMP2r
+	&f #aaaa #5555 EOR2 [ #ffff ] EQU2 JMP2r
+	&g #1122 #1234 EOR2 [ #0316 ] EQU2 JMP2r
+	&h #8888 #1000 EOR2 [ #9888 ] EQU2 JMP2r
+@op-sft ;Dict/sft !set
+	&a #ff #08 SFT [ #00 ] EQU JMP2r
+	&b #ff #e0 SFT [ #00 ] EQU JMP2r
+	&c #ff #11 SFT [ #fe ] EQU JMP2r
+	&d #ff #12 SFT [ #7e ] EQU JMP2r
+	&e #ffff #01 SFT2 [ #7fff ] EQU2 JMP2r
+	&f #ffff #70 SFT2 [ #ff80 ] EQU2 JMP2r
+	&g #ffff #7e SFT2 [ #0180 ] EQU2 JMP2r
+	&h #ffff #e3 SFT2 [ #c000 ] EQU2 JMP2r
+@op-stz ;Dict/stz !set
+	&a #ab .Zeropage/byte STZ .Zeropage/byte LDZ [ #ab ] EQU JMP2r
+	&b #cd .Zeropage/byte STZ .Zeropage/byte LDZ [ #cd ] EQU JMP2r
+	&c #1234 .Zeropage/short STZ2 .Zeropage/short LDZ2 [ #1234 ] EQU2 JMP2r
+	&d #5678 .Zeropage/short STZ2 .Zeropage/short LDZ2 [ #5678 ] EQU2 JMP2r
+@op-str ;Dict/str !set
+	[ LIT &before1 $1 ] [ LIT2 &before2 $2 ]
+	&a #22 ,&before1 STR ,&before1 LDR [ #22 ] EQU JMP2r
+	&b #ef ,&after1 STR ,&after1 LDR [ #ef ] EQU JMP2r
+	&c #1234 ,&before2 STR2 ,&before2 LDR2 [ #1234 ] EQU2 JMP2r
+	&d #5678 ,&after2 STR2 ,&after2 LDR2 [ #5678 ] EQU2 JMP2r
+	[ LIT &after1 $1 ] [ LIT2 &after2 $2 ]
+@op-sta ;Dict/sta !set
+	&a #34 ;Absolute/byte STA ;Absolute/byte LDA [ #34 ] EQU JMP2r
+	&b #56 ;Absolute/byte STA ;Absolute/byte LDA [ #56 ] EQU JMP2r
+	&c #1234 ;Absolute/short STA2 ;Absolute/short LDA2 [ #1234 ] EQU2 JMP2r
+	&d #5678 ;Absolute/short STA2 ;Absolute/short LDA2 [ #5678 ] EQU2 JMP2r
+@op-jmp ;Dict/jmp !set
+	&a #12 #34 ,&reljmp JMP SWP &reljmp POP [ #12 ] EQU JMP2r
+	&b #56 #78 ;&absjmp JMP2 SWP &absjmp POP [ #56 ] EQU JMP2r
+@op-jcn ;Dict/jcn !set
+	&a #23 #01 ,&reljcn-y JCN INC &reljcn-y [ #23 ] EQU JMP2r
+	&b #23 #00 ,&reljcn-n JCN INC &reljcn-n [ #24 ] EQU JMP2r
+	&c #23 #01 ;&absjcn-y JCN2 INC &absjcn-y [ #23 ] EQU JMP2r
+	&d #23 #00 ;&absjcn-n JCN2 INC &absjcn-n [ #24 ] EQU JMP2r
+@op-jsr ;Dict/jsr !set
+	&a #1234 #5678 ,&routine JSR [ #68ac ] EQU2 JMP2r
+	&b #12 #34 ;routine JSR2 [ #46 ] EQU JMP2r
+	&routine ADD2 JMP2r
+@op-sth ;Dict/sth !set
+	&a #0a STH #0b STH ADDr STHr [ #15 ] EQU JMP2r
+	&b #000a STH2 #000b STH2 ADD2r STH2r [ #0015 ] EQU2 JMP2r
+@op-jci ;Dict/jci !set
+	&before #01 JMP2r
+	&a #01 ?&skip-a #00 JMP2r &skip-a #01 JMP2r
+	&b #00 ?&skip-b #01 JMP2r &skip-b #00 JMP2r
+	&c #01 ?&before #00 JMP2r
+@op-jmi ;Dict/jmi !set
+	&a !&skip-a #00 JMP2r &skip-a #01 JMP2r
+@op-jsi ;Dict/jsi !set
+	&a #02 #04 routine #06 EQU JMP2r
+	&b ;&return special &return JMP2r
+	&c ,&skip-c JMP &routine-c ADD JMP2r &skip-c #02 #04 op-jsi/routine-c #06 EQU JMP2r
+	&d ,&skip-d JMP &routine-d ADD JMP2r &skip-d #02 #04 op-jsi-far-routine-d #06 EQU JMP2r
+
+@special ( routine* -- f )
+
+	( test that the stack order is LIFO )
+	DUP2 STH2kr EQU2
+	ROT ROT DUP2r STHr STHr SWP EQU2 AND
+
+JMP2r
+
+@routine ( a b -- c ) ADD JMP2r
+@subroutine ( -- ) [ LIT2 "kO ] #18 DEO #18 DEO JMP2r
+@Absolute &byte $1 &short $2
+
+@Dict [
+	&ok "Ok $1
+	&done "Tests 20 "Complete. 0a $1
+	&opctests "Opcodes $1
+	&stack-wrap "Stack-wrap $1
+	&ram-wrap "RAM-wrap $1
+	&zp-wrap "Zeropage-wrap $1
+	&dev-wrap "Devices-wrap $1
+	&result "Result: $1
+	&passed 20 "passed! 0a $1
+	&missed "Opcode 20 "Failed 20 "-- 20 $1
+	&failed 20 "failed. 0a $1
+	&equ "EQU $1 &neq "NEQ $1 &gth "GTH $1 &lth "LTH $1
+	&add "ADD $1 &sub "SUB $1 &mul "MUL $1 &div "DIV $1
+	&inc "INC $1 &pop "POP $1 &dup "DUP $1 &nip "NIP $1
+	&swp "SWP $1 &ovr "OVR $1 &rot "ROT $1
+	&and "AND $1 &ora "ORA $1 &eor "EOR $1 &sft "SFT $1
+	&stz "STZ $1 &str "STR $1 &sta "STA $1
+	&jmp "JMP $1 &jcn "JCN $1 &jsr "JSR $1 &sth "STH $1
+	&jmi "JMI $1 &jci "JCI $1 &jsi "JSI $1
+]
+
+(
+@|Relative Distance Bytes )
+
+@rel-distance
+&back "O $7c
+&entry
+	,&back LDR
+	,&forw LDR
+	JMP2r
+$7e
+&forw "k
+
+@op-jsi-far-routine-d
+	op-jsi/routine-d JMP2r
+
diff --git a/awk/uxn/test/tal/proper.tal b/awk/uxn/test/tal/proper.tal
new file mode 100644
index 0000000..be8e04b
--- /dev/null
+++ b/awk/uxn/test/tal/proper.tal
@@ -0,0 +1 @@
+@on-reset #01 #02 ADD BRK
\ No newline at end of file
diff --git a/awk/uxn/test/tal/simple.tal b/awk/uxn/test/tal/simple.tal
new file mode 100644
index 0000000..c055e74
--- /dev/null
+++ b/awk/uxn/test/tal/simple.tal
@@ -0,0 +1 @@
+#01 #02 ADD BRK 
\ No newline at end of file
diff --git a/awk/uxn/test/tal/simple2.tal b/awk/uxn/test/tal/simple2.tal
new file mode 100644
index 0000000..6a37b65
--- /dev/null
+++ b/awk/uxn/test/tal/simple2.tal
@@ -0,0 +1 @@
+#01 #02 ADD BRK
\ No newline at end of file
diff --git a/awk/uxn/test/tal/simple3.tal b/awk/uxn/test/tal/simple3.tal
new file mode 100644
index 0000000..09086b7
--- /dev/null
+++ b/awk/uxn/test/tal/simple3.tal
@@ -0,0 +1 @@
+#01 #02 ADD
\ No newline at end of file
diff --git a/bash/computer b/bash/computer
new file mode 100755
index 0000000..e5aa36d
--- /dev/null
+++ b/bash/computer
@@ -0,0 +1,295 @@
+#!/bin/bash
+
+# Get the directory where this script is located
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# Computer Dispatch System
+# This script intelligently routes prompts to the most appropriate thinking mechanism
+# or directly to Ollama based on complexity, question type, and user intent.
+#
+# APPLICATION LOGIC:
+# The computer dispatch system implements an intelligent routing mechanism that
+# analyzes user prompts and determines the optimal response strategy. The system
+# operates through three distinct phases designed to maximize response quality:
+#
+# PHASE 1 - PROMPT ANALYSIS:
+#   - Analyzes prompt complexity, length, and question type
+#   - Identifies user intent and specific keywords
+#   - Determines if direct Ollama response is appropriate
+#   - Classifies prompts into response categories
+#
+# PHASE 2 - MECHANISM SELECTION:
+#   - Routes to appropriate thinking mechanism based on classification
+#   - Uses decision tree with keywords for clear cases
+#   - Considers prompt complexity and user intent
+#   - Falls back to direct Ollama for simple cases
+#
+# PHASE 3 - RESPONSE EXECUTION:
+#   - Executes the selected mechanism or direct Ollama call
+#   - Maintains transparency about the routing decision
+#   - Provides consistent output format regardless of mechanism
+#   - Logs the decision process for analysis
+#
+# DISPATCH MODELING:
+# The system applies intelligent routing principles to AI response generation:
+#   - Prompt classification helps match complexity to appropriate mechanism
+#   - Keyword analysis identifies specific user needs and intent
+#   - Decision tree provides consistent, predictable routing logic
+#   - Direct Ollama routing handles simple cases efficiently
+#   - Transparency shows users how their prompt was processed
+#   - The system may improve response quality by using specialized mechanisms
+#
+# The dispatch process emphasizes efficiency and appropriateness,
+# ensuring users get the best possible response for their specific needs.
+# The system balances speed with depth based on prompt characteristics.
+
+# --- Model Configuration ---
+DEFAULT_MODEL="gemma3n:e2b"
+
+# --- Defaults ---
+DEFAULT_ROUNDS=2
+
+# --- Argument Validation ---
+if [ "$#" -lt 1 ]; then
+    echo -e "\n\tComputer"
+    echo -e "\tThis script intelligently routes prompts to the most appropriate thinking mechanism"
+    echo -e "\tor directly to Ollama based on complexity, question type, and user intent."
+    echo -e "\n\tUsage: $0 [-f <file_path>] [-d] \"<your prompt>\" [number_of_rounds]"
+    echo -e "\n\tExample: $0 -f ./input.txt \"Please analyze this text\" 2"
+    echo -e "\n\tIf number_of_rounds is not provided, the program will default to $DEFAULT_ROUNDS rounds."
+    echo -e "\n\t-f <file_path> (optional): Append the contents of the file to the prompt."
+    echo -e "\n\t-d (optional): Force direct Ollama response (bypass thinking mechanisms)."
+    echo -e "\n"
+    exit 1
+fi
+
+# --- Argument Parsing ---
+FILE_PATH=""
+FORCE_DIRECT=false
+while getopts "f:d" opt; do
+  case $opt in
+    f)
+      FILE_PATH="$OPTARG"
+      ;;
+    d)
+      FORCE_DIRECT=true
+      ;;
+    *)
+      echo "Invalid option: -$OPTARG" >&2
+      exit 1
+      ;;
+  esac
+done
+shift $((OPTIND -1))
+
+PROMPT="$1"
+if [ -z "$2" ]; then
+    ROUNDS=$DEFAULT_ROUNDS
+else
+    ROUNDS=$2
+fi
+
+# If file path is provided, append its contents to the prompt
+if [ -n "$FILE_PATH" ]; then
+    if [ ! -f "$FILE_PATH" ]; then
+        echo "File not found: $FILE_PATH" >&2
+        exit 1
+    fi
+    FILE_CONTENTS=$(cat "$FILE_PATH")
+    PROMPT="$PROMPT\n[FILE CONTENTS]\n$FILE_CONTENTS\n[END FILE]"
+fi
+
+# Source the logging system using absolute path
+source "${SCRIPT_DIR}/logging.sh"
+
+# --- File Initialization ---
+# Create a temporary directory if it doesn't exist
+mkdir -p ~/tmp
+# Create a unique file for this session based on the timestamp
+SESSION_FILE=~/tmp/computer_$(date +%Y%m%d_%H%M%S).txt
+
+# Initialize timing
+SESSION_ID=$(generate_session_id)
+start_timer "$SESSION_ID" "computer"
+
+echo "Computer Dispatch Session Log: ${SESSION_FILE}"
+echo "---------------------------------"
+
+# Store the initial user prompt in the session file
+echo "USER PROMPT: ${PROMPT}" >> "${SESSION_FILE}"
+echo "FORCE DIRECT: ${FORCE_DIRECT}" >> "${SESSION_FILE}"
+echo "" >> "${SESSION_FILE}"
+
+# --- Prompt Analysis Function ---
+analyze_prompt() {
+    local prompt="$1"
+    local analysis=""
+    
+    # Check for direct Ollama requests
+    if [[ "$prompt" =~ (direct|simple|quick|fast|straight) ]]; then
+        analysis="DIRECT"
+        return
+    fi
+    
+    # Check prompt length (simple heuristic for complexity)
+    local word_count=$(echo "$prompt" | wc -w)
+    
+    # Very short prompts (likely simple questions)
+    if [ "$word_count" -le 5 ]; then
+        analysis="DIRECT"
+        return
+    fi
+    
+    # Keyword-based classification
+    if [[ "$prompt" =~ (consensus|agree|disagree|vote|multiple|perspectives|opinions) ]]; then
+        analysis="CONSENSUS"
+    elif [[ "$prompt" =~ (synthesize|combine|integrate|unify|merge|consolidate) ]]; then
+        analysis="SYNTHESIS"
+    elif [[ "$prompt" =~ (explore|paths|alternatives|options|compare|strategies|approaches) ]]; then
+        analysis="EXPLORATION"
+    elif [[ "$prompt" =~ (analyze|examine|explore|investigate|deep|thorough|comprehensive) ]]; then
+        analysis="SOCRATIC"
+    elif [[ "$prompt" =~ (improve|refine|edit|revise|better|enhance|polish|fix) ]]; then
+        analysis="CRITIQUE"
+    elif [[ "$prompt" =~ (review|feedback|peer|collaborate|suggest|advice) ]]; then
+        analysis="PEER_REVIEW"
+    else
+        # Default to direct for unclear cases
+        analysis="DIRECT"
+    fi
+    
+    echo "$analysis"
+}
+
+# --- Mechanism Selection ---
+echo "Analyzing prompt and selecting mechanism..."
+echo "PROMPT ANALYSIS:" >> "${SESSION_FILE}"
+
+if [ "$FORCE_DIRECT" = true ]; then
+    MECHANISM="DIRECT"
+    REASON="User requested direct response with -d flag"
+else
+    MECHANISM=$(analyze_prompt "$PROMPT")
+    case "$MECHANISM" in
+        "DIRECT")
+            REASON="Simple prompt or direct request"
+            ;;
+        "CONSENSUS")
+            REASON="Multiple perspectives or consensus needed"
+            ;;
+        "SYNTHESIS")
+            REASON="Integration of multiple approaches needed"
+            ;;
+        "EXPLORATION")
+            REASON="Systematic exploration of alternatives needed"
+            ;;
+        "SOCRATIC")
+            REASON="Deep analysis or exploration required"
+            ;;
+        "CRITIQUE")
+            REASON="Improvement or refinement requested"
+            ;;
+        "PEER_REVIEW")
+            REASON="Collaborative review or feedback needed"
+            ;;
+        *)
+            REASON="Default fallback"
+            MECHANISM="DIRECT"
+            ;;
+    esac
+fi
+
+echo "Selected mechanism: ${MECHANISM}" >> "${SESSION_FILE}"
+echo "Reason: ${REASON}" >> "${SESSION_FILE}"
+echo "" >> "${SESSION_FILE}"
+
+echo "Selected mechanism: ${MECHANISM}"
+echo "Reason: ${REASON}"
+echo "---------------------------------"
+
+# --- Response Execution ---
+echo "Executing selected mechanism..."
+echo "RESPONSE EXECUTION:" >> "${SESSION_FILE}"
+
+case "$MECHANISM" in
+    "DIRECT")
+        echo "Using direct Ollama response..."
+        echo "DIRECT OLLAMA RESPONSE:" >> "${SESSION_FILE}"
+        
+        DIRECT_PROMPT="You are an expert assistant. You always flag if you don't know something. Please provide a clear, helpful response to the following prompt: ${PROMPT}"
+        
+        RESPONSE=$(ollama run "${DEFAULT_MODEL}" "${DIRECT_PROMPT}")
+        
+        echo "${RESPONSE}" >> "${SESSION_FILE}"
+        echo "" >> "${SESSION_FILE}"
+        
+        echo "---------------------------------"
+        echo "Direct response:"
+        echo "---------------------------------"
+        echo "${RESPONSE}"
+        ;;
+        
+    "CONSENSUS")
+        echo "Delegating to consensus mechanism..."
+        echo "DELEGATING TO CONSENSUS:" >> "${SESSION_FILE}"
+        
+        # Execute consensus script and display output directly
+        "${SCRIPT_DIR}/consensus" "${PROMPT}" "${ROUNDS}" 2>&1 | tee -a "${SESSION_FILE}"
+        ;;
+        
+    "SOCRATIC")
+        echo "Delegating to Socratic mechanism..."
+        echo "DELEGATING TO SOCRATIC:" >> "${SESSION_FILE}"
+        
+        # Execute Socratic script and display output directly
+        "${SCRIPT_DIR}/socratic" "${PROMPT}" "${ROUNDS}" 2>&1 | tee -a "${SESSION_FILE}"
+        ;;
+        
+    "CRITIQUE")
+        echo "Delegating to critique mechanism..."
+        echo "DELEGATING TO CRITIQUE:" >> "${SESSION_FILE}"
+        
+        # Execute critique script and display output directly
+        "${SCRIPT_DIR}/critique" "${PROMPT}" "${ROUNDS}" 2>&1 | tee -a "${SESSION_FILE}"
+        ;;
+        
+        "PEER_REVIEW")
+        echo "Delegating to peer-review mechanism..."
+        echo "DELEGATING TO PEER_REVIEW:" >> "${SESSION_FILE}"
+        
+        # Execute peer-review script and display output directly
+        "${SCRIPT_DIR}/peer-review" "${PROMPT}" "${ROUNDS}" 2>&1 | tee -a "${SESSION_FILE}"
+        ;;
+        
+        "SYNTHESIS")
+        echo "Delegating to synthesis mechanism..."
+        echo "DELEGATING TO SYNTHESIS:" >> "${SESSION_FILE}"
+        
+        # Execute synthesis script and display output directly
+        "${SCRIPT_DIR}/synthesis" "${PROMPT}" "${ROUNDS}" 2>&1 | tee -a "${SESSION_FILE}"
+        ;;
+        
+        "EXPLORATION")
+        echo "Delegating to exploration mechanism..."
+        echo "DELEGATING TO EXPLORATION:" >> "${SESSION_FILE}"
+        
+        # Execute exploration script and display output directly
+        "${SCRIPT_DIR}/exploration" "${PROMPT}" "${ROUNDS}" 2>&1 | tee -a "${SESSION_FILE}"
+        ;;
+esac
+
+# --- Final Summary ---
+echo "" >> "${SESSION_FILE}"
+echo "DISPATCH SUMMARY:" >> "${SESSION_FILE}"
+echo "================" >> "${SESSION_FILE}"
+echo "Original Prompt: ${PROMPT}" >> "${SESSION_FILE}"
+echo "Selected Mechanism: ${MECHANISM}" >> "${SESSION_FILE}"
+echo "Reason: ${REASON}" >> "${SESSION_FILE}"
+echo "Rounds: ${ROUNDS}" >> "${SESSION_FILE}"
+
+# End timing
+duration=$(end_timer "$SESSION_ID" "computer")
+
+echo ""
+echo "Execution time: ${duration} seconds"
+echo "Full dispatch log: ${SESSION_FILE}" 
\ No newline at end of file
diff --git a/bash/exploration b/bash/exploration
new file mode 100755
index 0000000..8dc09b7
--- /dev/null
+++ b/bash/exploration
@@ -0,0 +1,246 @@
+#!/bin/bash
+
+# Get the directory where this script is located
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# Exploration System
+# This script systematically explores multiple solution paths and compares alternatives.
+#
+# APPLICATION LOGIC:
+# The exploration process implements a branching analysis system that systematically
+# explores multiple approaches to a problem and compares their merits. The system
+# operates through three distinct phases designed to maximize discovery and comparison:
+#
+# PHASE 1 - PATH GENERATION:
+#   - Identifies multiple possible approaches to the problem
+#   - Generates alternative solution paths
+#   - Ensures comprehensive coverage of the solution space
+#   - Creates a foundation for systematic comparison
+#
+# PHASE 2 - PATH EXPLORATION:
+#   - Explores each identified path in detail
+#   - Develops the implications and consequences of each approach
+#   - Identifies strengths, weaknesses, and trade-offs
+#   - Provides detailed analysis of each alternative
+#
+# PHASE 3 - COMPARATIVE ANALYSIS:
+#   - Systematically compares all explored paths
+#   - Evaluates relative merits and trade-offs
+#   - Identifies optimal approaches or combinations
+#   - Provides recommendations based on different criteria
+#
+# EXPLORATION MODELING:
+# The system applies systematic exploration principles to AI response generation:
+#   - Multiple paths ensure comprehensive problem coverage
+#   - Systematic comparison reveals optimal approaches
+#   - Trade-off analysis helps users make informed decisions
+#   - The process may reveal unexpected insights or approaches
+#   - Transparency shows how different paths were evaluated
+#   - The method may identify novel solutions that single-path approaches miss
+#
+# The exploration process emphasizes systematic analysis and comparison,
+# ensuring users understand the full range of possible approaches and their implications.
+
+# Source the logging system using absolute path
+source "${SCRIPT_DIR}/logging.sh"
+
+# --- Model Configuration ---
+EXPLORATION_MODEL="llama3:8b-instruct-q4_K_M"
+ANALYSIS_MODEL="phi3:3.8b-mini-4k-instruct-q4_K_M"
+
+# --- Defaults ---
+DEFAULT_PATHS=3
+
+# --- Argument Validation ---
+if [ "$#" -lt 1 ]; then
+    echo -e "\n\tExploration"
+    echo -e "\tThis script systematically explores multiple solution paths and compares alternatives."
+    echo -e "\n\tUsage: $0 [-f <file_path>] [-p <number_of_paths>] \"<your prompt>\" [number_of_rounds]"
+    echo -e "\n\tExample: $0 -f ./input.txt -p 4 \"How can we solve this problem?\" 2"
+    echo -e "\n\tIf number_of_rounds is not provided, the program will default to 2 rounds."
+    echo -e "\n\t-f <file_path> (optional): Append the contents of the file to the prompt."
+    echo -e "\n\t-p <paths> (optional): Number of solution paths to explore (default: 3)."
+    echo -e "\n"
+    exit 1
+fi
+
+# --- Argument Parsing ---
+FILE_PATH=""
+NUM_PATHS=$DEFAULT_PATHS
+while getopts "f:p:" opt; do
+  case $opt in
+    f)
+      FILE_PATH="$OPTARG"
+      ;;
+    p)
+      NUM_PATHS="$OPTARG"
+      ;;
+    *)
+      echo "Invalid option: -$OPTARG" >&2
+      exit 1
+      ;;
+  esac
+done
+shift $((OPTIND -1))
+
+PROMPT="$1"
+if [ -z "$2" ]; then
+    ROUNDS=2
+else
+    ROUNDS=$2
+fi
+
+# If file path is provided, append its contents to the prompt
+if [ -n "$FILE_PATH" ]; then
+    if [ ! -f "$FILE_PATH" ]; then
+        echo "File not found: $FILE_PATH" >&2
+        exit 1
+    fi
+    FILE_CONTENTS=$(cat "$FILE_PATH")
+    PROMPT="$PROMPT\n[FILE CONTENTS]\n$FILE_CONTENTS\n[END FILE]"
+fi
+
+# --- File Initialization ---
+mkdir -p ~/tmp
+SESSION_FILE=~/tmp/exploration_$(date +%Y%m%d_%H%M%S).txt
+
+# Initialize timing
+SESSION_ID=$(generate_session_id)
+start_timer "$SESSION_ID" "exploration"
+
+echo "Exploration Session Log: ${SESSION_FILE}"
+echo "---------------------------------"
+
+# Store the initial user prompt in the session file
+echo "USER PROMPT: ${PROMPT}" >> "${SESSION_FILE}"
+echo "NUMBER OF PATHS: ${NUM_PATHS}" >> "${SESSION_FILE}"
+echo "" >> "${SESSION_FILE}"
+
+# --- Phase 1: Path Generation ---
+echo "Phase 1: Generating solution paths..."
+echo "PHASE 1 - PATH GENERATION:" >> "${SESSION_FILE}"
+
+PATH_GENERATION_PROMPT="You are a strategic thinker. Your task is to identify ${NUM_PATHS} distinct, viable approaches to the following problem. Each path should represent a different strategy or methodology.
+
+PROBLEM: ${PROMPT}
+
+Please identify ${NUM_PATHS} different solution paths. For each path, provide:
+1. A clear name/title for the approach
+2. A brief description of the strategy
+3. The key principles or methodology it follows
+
+Format your response as:
+PATH 1: [Name]
+[Description]
+
+PATH 2: [Name]
+[Description]
+
+etc.
+
+Ensure the paths are genuinely different approaches, not just variations of the same idea."
+
+paths_output=$(ollama run "${EXPLORATION_MODEL}" "${PATH_GENERATION_PROMPT}")
+
+echo "GENERATED PATHS:" >> "${SESSION_FILE}"
+echo "${paths_output}" >> "${SESSION_FILE}"
+echo "" >> "${SESSION_FILE}"
+
+# --- Phase 2: Path Exploration ---
+echo "Phase 2: Exploring each path in detail..."
+echo "PHASE 2 - PATH EXPLORATION:" >> "${SESSION_FILE}"
+
+declare -a path_analyses
+declare -a path_names
+
+# Extract path names and explore each one
+for i in $(seq 1 "${NUM_PATHS}"); do
+    echo "  Exploring path ${i}..."
+    
+    # Extract the path description (simplified approach)
+    path_section=$(echo "${paths_output}" | sed -n "/PATH ${i}:/,/PATH $((i+1)):/p" | sed '$d')
+    if [ -z "$path_section" ]; then
+        path_section=$(echo "${paths_output}" | sed -n "/PATH ${i}:/,\$p")
+    fi
+    
+    # Generate path name from the section
+    path_name=$(echo "${path_section}" | head -n1 | sed 's/^PATH [0-9]*: //')
+    
+    EXPLORATION_PROMPT="You are a detailed analyst. Explore the following solution path in depth, considering its implications, requirements, and potential outcomes.
+
+ORIGINAL PROBLEM: ${PROMPT}
+
+PATH TO EXPLORE: ${path_section}
+
+Please provide a comprehensive analysis of this path including:
+1. Detailed implementation approach
+2. Potential benefits and advantages
+3. Potential challenges and risks
+4. Resource requirements and constraints
+5. Expected outcomes and timeline
+6. Success factors and critical elements
+7. Potential variations or adaptations
+
+Provide a thorough, well-structured analysis."
+
+    path_analysis=$(ollama run "${EXPLORATION_MODEL}" "${EXPLORATION_PROMPT}")
+    
+    path_analyses[$((i-1))]="${path_analysis}"
+    path_names[$((i-1))]="${path_name}"
+    
+    echo "PATH ${i} ANALYSIS (${path_name}):" >> "${SESSION_FILE}"
+    echo "${path_analysis}" >> "${SESSION_FILE}"
+    echo "" >> "${SESSION_FILE}"
+done
+
+# --- Phase 3: Comparative Analysis ---
+echo "Phase 3: Comparing and evaluating paths..."
+echo "PHASE 3 - COMPARATIVE ANALYSIS:" >> "${SESSION_FILE}"
+
+# Create comparison prompt
+COMPARISON_PROMPT="You are a strategic analyst. Compare and evaluate the following solution paths for the given problem.
+
+ORIGINAL PROBLEM: ${PROMPT}
+
+PATH ANALYSES:"
+
+for i in $(seq 0 $((NUM_PATHS-1))); do
+    COMPARISON_PROMPT="${COMPARISON_PROMPT}
+
+PATH ${i+1}: ${path_names[$i]}
+${path_analyses[$i]}"
+done
+
+COMPARISON_PROMPT="${COMPARISON_PROMPT}
+
+Please provide a comprehensive comparative analysis including:
+1. Direct comparison of approaches across key criteria
+2. Relative strengths and weaknesses of each path
+3. Trade-offs and opportunity costs
+4. Risk assessment for each approach
+5. Recommendations based on different scenarios
+6. Potential for combining elements from multiple paths
+7. Final recommendation with justification
+
+Provide a clear, structured comparison that helps decision-making."
+
+comparative_analysis=$(ollama run "${ANALYSIS_MODEL}" "${COMPARISON_PROMPT}")
+
+echo "COMPARATIVE ANALYSIS:" >> "${SESSION_FILE}"
+echo "${comparative_analysis}" >> "${SESSION_FILE}"
+
+# End timing
+duration=$(end_timer "$SESSION_ID" "exploration")
+
+# --- Final Output ---
+echo "---------------------------------"
+echo "Exploration process complete."
+echo "Comparative analysis:"
+echo "---------------------------------"
+
+echo "${comparative_analysis}"
+echo ""
+echo "Paths explored: ${NUM_PATHS}"
+echo "Execution time: ${duration} seconds"
+echo ""
+echo "Full exploration log: ${SESSION_FILE}" 
\ No newline at end of file
diff --git a/bash/logging.sh b/bash/logging.sh
new file mode 100755
index 0000000..c37aaf4
--- /dev/null
+++ b/bash/logging.sh
@@ -0,0 +1,146 @@
+#!/bin/bash
+
+# Unified Logging System
+# This script provides consistent logging and performance metrics across all thinking mechanisms.
+
+# --- Logging Configuration ---
+LOG_DIR=~/tmp/ai_thinking
+METRICS_FILE="${LOG_DIR}/performance_metrics.json"
+SESSION_LOG="${LOG_DIR}/session_$(date +%Y%m%d_%H%M%S).json"
+
+# Create logging directory
+mkdir -p "${LOG_DIR}"
+
+# --- Timing Functions ---
+start_timer() {
+    local session_id="$1"
+    local mechanism="$2"
+    local start_time=$(date +%s.%N)
+    
+    # Store start time
+    echo "$start_time" > "/tmp/${session_id}_start"
+    
+    # Log session start
+    log_session_start "$session_id" "$mechanism" "$start_time"
+}
+
+end_timer() {
+    local session_id="$1"
+    local mechanism="$2"
+    local end_time=$(date +%s.%N)
+    local start_time=$(cat "/tmp/${session_id}_start" 2>/dev/null || echo "$end_time")
+    
+    # Calculate duration
+    local duration=$(echo "$end_time - $start_time" | bc -l 2>/dev/null || echo "0")
+    
+    # Log session end
+    log_session_end "$session_id" "$mechanism" "$end_time" "$duration"
+    
+    # Clean up
+    rm -f "/tmp/${session_id}_start"
+    
+    echo "$duration"
+}
+
+# --- Session Logging ---
+log_session_start() {
+    local session_id="$1"
+    local mechanism="$2"
+    local start_time="$3"
+    
+    cat > "${SESSION_LOG}" << EOF
+{
+  "session_id": "${session_id}",
+  "mechanism": "${mechanism}",
+  "start_time": "${start_time}",
+  "prompt": "${PROMPT:-""}",
+  "status": "started"
+}
+EOF
+}
+
+log_session_end() {
+    local session_id="$1"
+    local mechanism="$2"
+    local end_time="$3"
+    local duration="$4"
+    
+    # Update session log
+    cat > "${SESSION_LOG}" << EOF
+{
+  "session_id": "${session_id}",
+  "mechanism": "${mechanism}",
+  "start_time": "$(cat "${SESSION_LOG}" | jq -r '.start_time' 2>/dev/null || echo "")",
+  "end_time": "${end_time}",
+  "duration": "${duration}",
+  "prompt": "${PROMPT:-""}",
+  "status": "completed"
+}
+EOF
+    
+    # Update metrics file
+    update_metrics "$mechanism" "$duration"
+}
+
+# --- Metrics Management ---
+update_metrics() {
+    local mechanism="$1"
+    local duration="$2"
+    
+    # Create metrics file if it doesn't exist
+    if [ ! -f "${METRICS_FILE}" ]; then
+        cat > "${METRICS_FILE}" << EOF
+{
+  "total_sessions": 0,
+  "mechanisms": {},
+  "average_durations": {}
+}
+EOF
+    fi
+    
+    # Update metrics using jq (if available) or simple text processing
+    if command -v jq >/dev/null 2>&1; then
+        # Use jq for proper JSON handling
+        local temp_file=$(mktemp)
+        jq --arg mechanism "$mechanism" --arg duration "$duration" '
+            .total_sessions += 1 |
+            .mechanisms[$mechanism] = (.mechanisms[$mechanism] // 0) + 1 |
+            .average_durations[$mechanism] = (
+                (.average_durations[$mechanism] // 0) * (.mechanisms[$mechanism] - 1) + ($duration | tonumber)
+            ) / .mechanisms[$mechanism]
+        ' "${METRICS_FILE}" > "$temp_file"
+        mv "$temp_file" "${METRICS_FILE}"
+    else
+        # Fallback: simple text-based metrics
+        echo "$(date +%Y%m%d_%H%M%S),${mechanism},${duration}" >> "${LOG_DIR}/simple_metrics.csv"
+    fi
+}
+
+# --- Utility Functions ---
+generate_session_id() {
+    echo "session_$(date +%Y%m%d_%H%M%S)_$$"
+}
+
+get_metrics_summary() {
+    if [ -f "${METRICS_FILE}" ]; then
+        echo "=== Performance Metrics ==="
+        if command -v jq >/dev/null 2>&1; then
+            jq -r '.mechanisms | to_entries[] | "\(.key): \(.value) sessions"' "${METRICS_FILE}"
+            echo ""
+            jq -r '.average_durations | to_entries[] | "\(.key): \(.value | tonumber | floor)s average"' "${METRICS_FILE}"
+        else
+            echo "Metrics available in: ${METRICS_FILE}"
+        fi
+    else
+        echo "No metrics available yet."
+    fi
+}
+
+# --- Export Functions for Other Scripts ---
+export -f start_timer
+export -f end_timer
+export -f log_session_start
+export -f log_session_end
+export -f update_metrics
+export -f generate_session_id
+export -f get_metrics_summary 
\ No newline at end of file
diff --git a/bash/metrics b/bash/metrics
new file mode 100755
index 0000000..ad430b5
--- /dev/null
+++ b/bash/metrics
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Metrics Viewer
+# This script displays performance metrics from the unified logging system.
+
+# Source the logging system
+source ./logging.sh
+
+echo "AI Thinking System - Performance Metrics"
+echo "========================================"
+echo ""
+
+# Display metrics summary
+get_metrics_summary
+
+echo ""
+echo "Detailed metrics file: ${METRICS_FILE}"
+echo "Session logs directory: ${LOG_DIR}" 
\ No newline at end of file
diff --git a/bash/synthesis b/bash/synthesis
new file mode 100755
index 0000000..417279e
--- /dev/null
+++ b/bash/synthesis
@@ -0,0 +1,240 @@
+#!/bin/bash
+
+# Get the directory where this script is located
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# Synthesis System
+# This script combines outputs from multiple thinking mechanisms into a coherent final response.
+#
+# APPLICATION LOGIC:
+# The synthesis process implements a multi-mechanism integration system that combines
+# outputs from different thinking strategies into a unified, coherent response. The system
+# operates through three distinct phases designed to maximize comprehensiveness and clarity:
+#
+# PHASE 1 - MECHANISM EXECUTION:
+#   - Executes multiple thinking mechanisms on the same prompt
+#   - Collects diverse perspectives and approaches
+#   - Ensures comprehensive coverage of the problem space
+#   - Creates a foundation for synthesis
+#
+# PHASE 2 - CONFLICT RESOLUTION:
+#   - Identifies contradictions and conflicts between mechanism outputs
+#   - Resolves disagreements through logical analysis
+#   - Prioritizes information based on confidence and relevance
+#   - Maintains intellectual honesty about uncertainties
+#
+# PHASE 3 - SYNTHESIS GENERATION:
+#   - Combines the best elements from each mechanism
+#   - Creates a coherent narrative that addresses all aspects
+#   - Provides a unified response that leverages multiple perspectives
+#   - Ensures the final output is greater than the sum of its parts
+#
+# SYNTHESIS MODELING:
+# The system applies integrative thinking principles to AI response generation:
+#   - Multiple mechanisms provide diverse perspectives on the same problem
+#   - Conflict resolution ensures logical consistency in the final output
+#   - Synthesis leverages the strengths of each individual mechanism
+#   - The process may reveal insights that individual mechanisms miss
+#   - Transparency shows how different perspectives were integrated
+#   - The method may provide more comprehensive and balanced responses
+#
+# The synthesis process emphasizes comprehensiveness and coherence,
+# ensuring users get the benefits of multiple thinking approaches in a unified response.
+
+# Source the logging system using absolute path
+source "${SCRIPT_DIR}/logging.sh"
+
+# --- Model Configuration ---
+SYNTHESIS_MODEL="llama3:8b-instruct-q4_K_M"
+
+# --- Defaults ---
+DEFAULT_MECHANISMS=("consensus" "critique" "socratic")
+
+# --- Argument Validation ---
+if [ "$#" -lt 1 ]; then
+    echo -e "\n\tSynthesis"
+    echo -e "\tThis script combines outputs from multiple thinking mechanisms into a coherent final response."
+    echo -e "\n\tUsage: $0 [-f <file_path>] [-m <mechanism1,mechanism2,...>] \"<your prompt>\" [number_of_rounds]"
+    echo -e "\n\tExample: $0 -f ./input.txt -m consensus,critique \"Please analyze this text\" 2"
+    echo -e "\n\tIf number_of_rounds is not provided, the program will default to 2 rounds."
+    echo -e "\n\t-f <file_path> (optional): Append the contents of the file to the prompt."
+    echo -e "\n\t-m <mechanisms> (optional): Comma-separated list of mechanisms to use (default: consensus,critique,socratic)."
+    echo -e "\n"
+    exit 1
+fi
+
+# --- Argument Parsing ---
+FILE_PATH=""
+MECHANISMS_STR=""
+while getopts "f:m:" opt; do
+  case $opt in
+    f)
+      FILE_PATH="$OPTARG"
+      ;;
+    m)
+      MECHANISMS_STR="$OPTARG"
+      ;;
+    *)
+      echo "Invalid option: -$OPTARG" >&2
+      exit 1
+      ;;
+  esac
+done
+shift $((OPTIND -1))
+
+PROMPT="$1"
+if [ -z "$2" ]; then
+    ROUNDS=2
+else
+    ROUNDS=$2
+fi
+
+# Parse mechanisms
+if [ -n "$MECHANISMS_STR" ]; then
+    IFS=',' read -ra MECHANISMS <<< "$MECHANISMS_STR"
+else
+    MECHANISMS=("${DEFAULT_MECHANISMS[@]}")
+fi
+
+# If file path is provided, append its contents to the prompt
+if [ -n "$FILE_PATH" ]; then
+    if [ ! -f "$FILE_PATH" ]; then
+        echo "File not found: $FILE_PATH" >&2
+        exit 1
+    fi
+    FILE_CONTENTS=$(cat "$FILE_PATH")
+    PROMPT="$PROMPT\n[FILE CONTENTS]\n$FILE_CONTENTS\n[END FILE]"
+fi
+
+# --- File Initialization ---
+mkdir -p ~/tmp
+SESSION_FILE=~/tmp/synthesis_$(date +%Y%m%d_%H%M%S).txt
+
+# Initialize timing
+SESSION_ID=$(generate_session_id)
+start_timer "$SESSION_ID" "synthesis"
+
+echo "Synthesis Session Log: ${SESSION_FILE}"
+echo "---------------------------------"
+
+# Store the initial user prompt in the session file
+echo "USER PROMPT: ${PROMPT}" >> "${SESSION_FILE}"
+echo "MECHANISMS: ${MECHANISMS[*]}" >> "${SESSION_FILE}"
+echo "" >> "${SESSION_FILE}"
+
+# --- Phase 1: Mechanism Execution ---
+echo "Phase 1: Executing thinking mechanisms..."
+echo "PHASE 1 - MECHANISM EXECUTION:" >> "${SESSION_FILE}"
+
+declare -a mechanism_outputs
+declare -a mechanism_names
+
+for i in "${!MECHANISMS[@]}"; do
+    mechanism="${MECHANISMS[$i]}"
+    echo "  Executing ${mechanism} mechanism..."
+    
+    # Execute the mechanism using absolute path
+    if [ -f "${SCRIPT_DIR}/${mechanism}" ]; then
+        output=$("${SCRIPT_DIR}/${mechanism}" "${PROMPT}" "${ROUNDS}" 2>&1)
+        mechanism_outputs[$i]="${output}"
+        mechanism_names[$i]="${mechanism}"
+        
+        echo "MECHANISM ${i+1} (${mechanism}):" >> "${SESSION_FILE}"
+        echo "${output}" >> "${SESSION_FILE}"
+        echo "" >> "${SESSION_FILE}"
+    else
+        echo "  WARNING: Mechanism ${mechanism} not found, skipping..." >&2
+    fi
+done
+
+# --- Phase 2: Conflict Resolution ---
+echo "Phase 2: Analyzing and resolving conflicts..."
+echo "PHASE 2 - CONFLICT RESOLUTION:" >> "${SESSION_FILE}"
+
+# Create conflict analysis prompt
+CONFLICT_PROMPT="You are a conflict resolution specialist. Analyze the following outputs from different thinking mechanisms and identify any contradictions, conflicts, or areas of disagreement.
+
+ORIGINAL PROMPT: ${PROMPT}
+
+MECHANISM OUTPUTS:"
+
+for i in "${!MECHANISMS[@]}"; do
+    if [ -n "${mechanism_outputs[$i]}" ]; then
+        CONFLICT_PROMPT="${CONFLICT_PROMPT}
+
+${mechanism_names[$i]} OUTPUT:
+${mechanism_outputs[$i]}"
+    fi
+done
+
+CONFLICT_PROMPT="${CONFLICT_PROMPT}
+
+Please identify:
+1. Any direct contradictions between the outputs
+2. Areas where the mechanisms disagree
+3. Information that appears to be conflicting
+4. How these conflicts might be resolved
+
+Provide a clear analysis of conflicts and potential resolutions."
+
+conflict_analysis=$(ollama run "${SYNTHESIS_MODEL}" "${CONFLICT_PROMPT}")
+
+echo "CONFLICT ANALYSIS:" >> "${SESSION_FILE}"
+echo "${conflict_analysis}" >> "${SESSION_FILE}"
+echo "" >> "${SESSION_FILE}"
+
+# --- Phase 3: Synthesis Generation ---
+echo "Phase 3: Generating unified synthesis..."
+echo "PHASE 3 - SYNTHESIS GENERATION:" >> "${SESSION_FILE}"
+
+# Create synthesis prompt
+SYNTHESIS_PROMPT="You are a synthesis specialist. Your task is to combine the outputs from multiple thinking mechanisms into a coherent, unified response that leverages the strengths of each approach.
+
+ORIGINAL PROMPT: ${PROMPT}
+
+MECHANISM OUTPUTS:"
+
+for i in "${!MECHANISMS[@]}"; do
+    if [ -n "${mechanism_outputs[$i]}" ]; then
+        SYNTHESIS_PROMPT="${SYNTHESIS_PROMPT}
+
+${mechanism_names[$i]} OUTPUT:
+${mechanism_outputs[$i]}"
+    fi
+done
+
+SYNTHESIS_PROMPT="${SYNTHESIS_PROMPT}
+
+CONFLICT ANALYSIS:
+${conflict_analysis}
+
+Please create a unified synthesis that:
+1. Combines the best insights from each mechanism
+2. Resolves any identified conflicts logically
+3. Provides a comprehensive response that addresses all aspects
+4. Maintains intellectual honesty about uncertainties
+5. Creates a coherent narrative that flows naturally
+6. Leverages the unique strengths of each thinking approach
+
+Your synthesis should be greater than the sum of its parts - it should provide insights that individual mechanisms might miss."
+
+final_synthesis=$(ollama run "${SYNTHESIS_MODEL}" "${SYNTHESIS_PROMPT}")
+
+echo "FINAL SYNTHESIS:" >> "${SESSION_FILE}"
+echo "${final_synthesis}" >> "${SESSION_FILE}"
+
+# End timing
+duration=$(end_timer "$SESSION_ID" "synthesis")
+
+# --- Final Output ---
+echo "---------------------------------"
+echo "Synthesis process complete."
+echo "Final unified response:"
+echo "---------------------------------"
+
+echo "${final_synthesis}"
+echo ""
+echo "Mechanisms used: ${MECHANISMS[*]}"
+echo "Execution time: ${duration} seconds"
+echo ""
+echo "Full synthesis log: ${SESSION_FILE}" 
\ No newline at end of file
diff --git a/js/seed/README.md b/js/seed/README.md
index 8159cb3..981ca7d 100644
--- a/js/seed/README.md
+++ b/js/seed/README.md
@@ -1,6 +1,6 @@
 # Seed: Minimal FRP/TEA Web App Starter Kit
 
-This is an opinionated, minimal starting point for browser-native web apps using a functional, Elm-style architecture (FRP/TEA) and only browser APIs. No frameworks, no build step, just ES modules.
+This is an opinionated, hopefully simple starting point for browser-native web apps using a functional, Elm-style architecture (FRP/TEA) and only browser APIs. No rulers, no kings, no frameworks, no build step, only ES modules.
 
 ## Architecture
 - **state.js**: App state definition and helpers
@@ -15,14 +15,9 @@ This is an opinionated, minimal starting point for browser-native web apps using
 - **View**: Pure function `(state) => html`
 - **Entrypoint**: Handles events, dispatches actions, triggers re-render
 
-## Why?
-- Simple, testable, and maintainable
-- No dependencies
-- Encourages functional, declarative code
-
 ## How to Extend and Use This Template
 
-This template is designed to be a flexible, opinionated starting point for any browser-native app.
+This template is designed to be a flexible, opinionated starting point for any kinda app, especially proofs of concept, toys, and prototypes.
 
 ### Key Files to Extend
 - **src/state.js**: Define the app's state shape and any helper functions for cloning or initializing state.
@@ -69,9 +64,9 @@ Suppose you want to add a button that increments a counter:
      ```
 
 ### Tips
-- Keep all state transitions in `update.js` for predictability.
-- Keep all DOM rendering in `view.js` for clarity.
-- Use the `postRender` hook for accessibility or focus management.
+- Keep all state transitions in `update.js`.
+- Keep all DOM rendering in `view.js`.
+- Use the `postRender` hook for accessibility or focus management stuff.
 - Add new features by extending state, update, view, and wiring up events in `app.js`.
 
 ---
diff --git a/js/seed/seed b/js/seed/seed
new file mode 100755
index 0000000..15276e7
--- /dev/null
+++ b/js/seed/seed
@@ -0,0 +1,75 @@
+#!/bin/bash
+
+set -euo pipefail
+
+# Usage: seed plant
+
+if [ "$#" -ne 1 ] || [ "$1" != "plant" ]; then
+  echo "Usage: $0 plant"
+  exit 1
+fi
+
+if [ "$EUID" -eq 0 ]; then
+  echo "Do not run this script as root."
+  exit 1
+fi
+
+if ! command -v git >/dev/null 2>&1; then
+  echo "Warning: git is not installed. You won't be able to initialize a git repo."
+fi
+
+SRC_DIR="$(cd "$(dirname "$0")" && pwd)"
+
+read -rp "Enter new project name: " DEST_DIR
+
+if [ -z "$DEST_DIR" ]; then
+  echo "Project name cannot be empty."
+  exit 1
+fi
+
+DEST_PATH="$PWD/$DEST_DIR"
+
+if [ -e "$DEST_PATH" ]; then
+  echo "Error: '$DEST_PATH' already exists."
+  exit 1
+fi
+
+cleanup() {
+  if [ -d "$DEST_PATH" ]; then
+    echo "Cleaning up partial directory..."
+    rm -rf "$DEST_PATH"
+  fi
+}
+trap cleanup INT TERM
+
+echo "Copying seed template to '$DEST_PATH'..."
+mkdir "$DEST_PATH"
+
+if command -v rsync >/dev/null 2>&1; then
+  rsync -a --exclude='.git' --exclude='seed' "$SRC_DIR/" "$DEST_PATH/"
+else
+  cp -r "$SRC_DIR/"* "$DEST_PATH/"
+  cp -r "$SRC_DIR/".* "$DEST_PATH/" 2>/dev/null || true
+  rm -rf "$DEST_PATH/.git" "$DEST_PATH/seed"
+fi
+
+cd "$DEST_PATH"
+
+# Optionally, update README
+if [ -f README.md ]; then
+  sed -i '' "1s/.*/# $DEST_DIR/" README.md 2>/dev/null || sed -i "1s/.*/# $DEST_DIR/" README.md
+fi
+
+echo "Initialized new project in '$DEST_PATH'."
+
+read -rp "Do you want to initialize a git repository? (y/n): " INIT_GIT
+if [[ "$INIT_GIT" =~ ^[Yy]$ ]]; then
+  git init
+  echo "Git repository initialized."
+else
+  echo "Skipping git initialization."
+fi
+
+echo "Next steps:"
+echo "  cd \"$DEST_PATH\""
+echo "  and tend to the seed you've planted..." 
\ No newline at end of file
diff --git a/js/seed/src/app.js b/js/seed/src/app.js
index 34b4579..49ad9d1 100644
--- a/js/seed/src/app.js
+++ b/js/seed/src/app.js
@@ -155,11 +155,3 @@ function setHistoryPointer(idx) {
     updateHistoryInfo();
   }
 }
-
-function handleSliderChange(e) {
-  setHistoryPointer(Number(e.target.value));
-}
-
-function handleStepperChange(e) {
-  setHistoryPointer(Number(e.target.value));
-} 
\ No newline at end of file
diff --git a/js/seed/src/dev.js b/js/seed/src/dev.js
index ee1a6e7..173fc3c 100644
--- a/js/seed/src/dev.js
+++ b/js/seed/src/dev.js
@@ -1,8 +1,8 @@
 // devMode.js
-// Minimal, single-file dev mode with scriptable console API
+// Simpleish, single-file dev mode with interactive console API
 
 /**
- * Initialize dev mode: exposes a scriptable API for stepping through state history.
+ * Initialize dev mode: exposes an API for stepping through state history.
  * @param {object} opts
  * @param {function} opts.getState - returns current app state
  * @param {function} opts.setState - sets app state
diff --git a/js/seed/src/view.js b/js/seed/src/view.js
index 5feef6e..4c6e680 100644
--- a/js/seed/src/view.js
+++ b/js/seed/src/view.js
@@ -4,10 +4,10 @@
 /**
  * Pure view functions for the application.
  *
- * Why pure functions returning HTML strings?
+ * Why pure functions returning HTML strings? Because Elm does it, tbh.
  * - Keeps rendering logic stateless and easy to test.
- * - Ensures the UI is always a direct function of state, avoiding UI bugs from incremental DOM updates.
- * - Using template literals is minimal and browser-native, with no dependencies.
+ * - Ensures the UI is always a direct function of state, which should in theory totally avoid bugs from incremental DOM updates.
+ * - Using template literals is minimal and browser-native, with no dependencies, and is fun.
  *
  * Why escape output?
  * - Prevents XSS and ensures all user/content data is safely rendered.