From 104e950d63e78e3976a5ee8394292ef1eadfb31e Mon Sep 17 00:00:00 2001 From: Mattias Hansson Date: Wed, 11 Feb 2026 14:06:09 +0100 Subject: [PATCH] Updated docs to describe new SCRIPT blocks including macros --- .../script_library_demo.c65 | 2 + language.md | 110 ++++++++++++- syntax.md | 145 ++++++++++++++++++ 3 files changed, 256 insertions(+), 1 deletion(-) diff --git a/examples/script_library_demo/script_library_demo.c65 b/examples/script_library_demo/script_library_demo.c65 index 3983237..f7221e5 100644 --- a/examples/script_library_demo/script_library_demo.c65 +++ b/examples/script_library_demo/script_library_demo.c65 @@ -39,6 +39,8 @@ ENDSCRIPT // SCRIPT MACRO: Named macros with parameters //----------------------------------------------------------- SCRIPT MACRO delay(cycles) + if cycles < 2: + fail("Cannot delay less than 2 cycles") emit_delay(cycles) ENDSCRIPT diff --git a/language.md b/language.md index 7b3a286..0de5460 100644 --- a/language.md +++ b/language.md @@ -495,6 +495,101 @@ SCRIPT ENDSCRIPT ``` +### SCRIPT LIBRARY Blocks + +Define reusable Starlark functions that persist across all subsequent SCRIPT blocks: + +```c65 +SCRIPT LIBRARY +def emit_nops(count): + for i in range(count): + print(" nop") + +def emit_delay(cycles): + for i in range(cycles // 4): + print(" nop") + print(" nop") + remainder = cycles % 4 + if remainder >= 3: + print(" bit $ea") + remainder -= 3 + for i in range(remainder // 2): + print(" nop") +ENDSCRIPT + +// Later, use the library functions: +SCRIPT + emit_nops(5) + emit_delay(10) +ENDSCRIPT +``` + +Library functions are typically placed in include files for reuse across projects. Multiple SCRIPT LIBRARY blocks accumulate. + +### SCRIPT MACRO Blocks + +Define named, parameterized macros that expand inline when invoked: + +```c65 +SCRIPT MACRO delay(cycles) + if cycles < 2: + fail("Cannot delay less than 2 cycles") + emit_delay(cycles) +ENDSCRIPT + +SCRIPT MACRO set_irq(handler) + print(" lda #<%s" % handler) + print(" sta $fffe") + print(" lda #>%s" % handler) + print(" sta $ffff") +ENDSCRIPT +``` + +#### Invoking Macros + +Outside ASM blocks, use `@name(args)`: + +```c65 +BYTE CONST CYCLES_PER_LINE = 63 + +@delay(10) +@delay(CYCLES_PER_LINE-20) +@set_irq(my_handler) +``` + +Inside ASM blocks, use `|@name(args)|`: + +```c65 +ASM + lda #$00 + |@delay(8)| + sta $d020 +ENDASM +``` + +#### Parameter Types + +- **Integer expressions**: Numbers, constants, arithmetic - passed as int +- **Labels**: Bare identifiers that aren't constants - passed as string + +```c65 +@delay(10) // 10 passed as int +@delay(CYCLES_PER_LINE-20) // Evaluated, passed as int +@set_irq(my_handler) // "my_handler" passed as string +``` + +#### Error Handling + +Use `fail()` to stop compilation with an error: + +```c65 +SCRIPT MACRO delay(cycles) + if cycles < 2: + fail("Cannot delay less than 2 cycles") + emit_delay(cycles) +ENDSCRIPT +``` + --- ## Preprocessor @@ -975,6 +1070,19 @@ ASM ENDASM SCRIPT - # Python code + # Starlark code ENDSCRIPT + +SCRIPT LIBRARY + def my_func(): + print(" nop") +ENDSCRIPT + +SCRIPT MACRO name(param) + my_func() +ENDSCRIPT + +// Macro invocation +@name(10) // Outside ASM +|@name(10)| // Inside ASM ``` diff --git a/syntax.md b/syntax.md index ec461ce..bc874ef 100644 --- a/syntax.md +++ b/syntax.md @@ -366,6 +366,151 @@ ENDSCRIPT --- +### SCRIPT LIBRARY...ENDSCRIPT + +Defines reusable Starlark functions that persist across all subsequent SCRIPT blocks. + +**Syntax:** +``` +SCRIPT LIBRARY + +ENDSCRIPT +``` + +**Examples:** + +**Defining reusable functions:** +``` +SCRIPT LIBRARY +def emit_nops(count): + for i in range(count): + print(" nop") + +def emit_delay(cycles): + for i in range(cycles // 4): + print(" nop") + print(" nop") + remainder = cycles % 4 + if remainder >= 3: + print(" bit $ea") + remainder -= 3 + for i in range(remainder // 2): + print(" nop") +ENDSCRIPT +``` + +**Using library functions in SCRIPT blocks:** +``` +SCRIPT + emit_nops(5) + emit_delay(10) +ENDSCRIPT +``` + +**Notes:** +- Functions defined in SCRIPT LIBRARY are available to all subsequent SCRIPT, SCRIPT LIBRARY, and SCRIPT MACRO blocks +- Multiple SCRIPT LIBRARY blocks accumulate - later blocks can use functions from earlier ones +- Typically placed in include files for reuse across projects +- The library block itself can also use `print()` to emit code, but this is uncommon + +--- + +### SCRIPT MACRO...ENDSCRIPT + +Defines a named, parameterized macro that expands inline when invoked. + +**Syntax:** +``` +SCRIPT MACRO name(param1, param2, ...) + +ENDSCRIPT +``` + +**Invocation:** +``` +@name(arg1, arg2, ...) // Outside ASM blocks +|@name(arg1, arg2, ...)| // Inside ASM blocks +``` + +**Examples:** + +**Defining macros:** +``` +SCRIPT MACRO delay(cycles) + if cycles < 2: + fail("Cannot delay less than 2 cycles") + emit_delay(cycles) +ENDSCRIPT + +SCRIPT MACRO set_irq(handler) + print(" lda #<%s" % handler) + print(" sta $fffe") + print(" lda #>%s" % handler) + print(" sta $ffff") +ENDSCRIPT +``` + +**Invoking macros outside ASM blocks:** +``` +BYTE CONST CYCLES_PER_LINE = 63 + +@delay(10) +@delay(CYCLES_PER_LINE-20) +@set_irq(my_handler) +``` + +**Invoking macros inside ASM blocks:** +``` +ASM + lda #$00 + |@delay(8)| + sta $d020 +ENDASM +``` + +**Parameter Types:** + +1. **Integer expressions** - Evaluated at compile time: + - Literal numbers: `10`, `$FF`, `%11110000` + - Constants: `CYCLES_PER_LINE`, `MAX_VALUE` + - Arithmetic: `CYCLES_PER_LINE-20`, `BASE+OFFSET` + - Passed to macro as Starlark `int` + +2. **Labels/Identifiers** - Passed as strings: + - Bare identifiers that don't resolve to constants: `my_handler`, `loop_start` + - Passed to macro as Starlark `string` + - Use in generated assembly: `print(" jmp %s" % label)` + +**Checking parameter types in macros:** +``` +SCRIPT MACRO flexible(value) + if type(value) == "int": + print(" lda #%d" % value) + else: + print(" lda %s" % value) +ENDSCRIPT +``` + +**Error handling with fail():** +``` +SCRIPT MACRO delay(cycles) + if cycles < 2: + fail("Cannot delay less than 2 cycles") + emit_delay(cycles) +ENDSCRIPT +``` + +The `fail()` function stops compilation with an error message pointing to the macro invocation site. + +**Notes:** +- Macros are NOT executed at definition time - only when invoked +- Macros have access to all SCRIPT LIBRARY functions +- `print()` output replaces the macro invocation site +- Everything expands inline - no JSR/RTS overhead +- Use for cycle-critical code like raster timing + +--- + ## Expression Syntax Expressions evaluate left to right with no operator precedence.