1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-08 08:55:38 +00:00
nescript/examples/arrays_and_functions.ne

88 lines
2 KiB
Text
Raw Normal View History

// Arrays and Functions — demonstrates M2 features.
//
// Shows: arrays, functions with parameters and return values,
// while loops, constants, inline functions.
//
// Build: cargo run -- build examples/arrays_and_functions.ne
game "Arrays Demo" {
mapper: NROM
}
const NUM_ENEMIES: u8 = 4
const SPEED: u8 = 1
var player_x: u8 = 128
var player_y: u8 = 200
// Enemy positions stored in arrays
var enemy_x: u8[4] = [30, 80, 130, 200]
var enemy_y: u8[4] = [40, 80, 120, 60]
// Function: clamp value to screen bounds
fun clamp(val: u8, max: u8) -> u8 {
if val > max {
return max
}
return val
}
// Inline function: absolute difference
W0110 inline fallback warning + docs refresh W0110: when a function marked `inline` has a body shape the IR lowerer can't splice (conditional early return, loops, nested control flow, empty void body), the analyzer now emits a warning at the declaration site so the declined hint is visible instead of silently falling back to a regular JSR. Implementation: - New `W0110` error code in `src/errors/diagnostic.rs` (warning level). - New `pub fn can_inline_fun(return_type, body) -> bool` in `src/ir/lowering.rs`, extracted from the existing capture logic so the analyzer and the IR lowerer share the same eligibility rules and can never drift. - New `check_inline_declinability` analyzer pass called from the tail of `analyze_program`, mirroring the existing `check_sprite_scanline_budget` / `check_unreachable_states` passes. Emits W0110 with help + note text pointing at the two accepted body shapes. - `capture_inline_bodies` now defers to `can_inline_fun` instead of duplicating the match pattern, so the two sides stay in lockstep by construction. Four regression tests in `src/analyzer/tests.rs` cover the conditional-return and while-loop declines plus the two accepted shapes (single-return expression, void sequence). Example source cleanups: `wrap52` in `examples/war/deck.ne` and `abs_diff` in both `examples/arrays_and_functions.ne` and `examples/loop_break_continue.ne` drop the `inline` keyword. All three were dead hints — the `inline` was being silently declined before this change, so removing it is source-only; the three ROMs are byte-identical, all 32 emulator goldens still match. Docs refresh - `docs/language-guide.md`: rewrote the Inline Functions section (real behaviour + W0110), added W0105/W0106/W0107/W0108/W0109/ W0110 to the warnings table, added the `debug.sprite_overflow*` builtins + sprite-per-scanline mitigations section to the Debug Mode docs, added a `cycle_sprites` statement entry and cross-referenced it from `draw`. - `docs/nes-reference.md`: fleshed out the "NEScript Memory Usage" block with the full ZP + high-RAM layout, including the new `$07EF` / `$07FC` / `$07FD` slots for sprite cycling and the debug sprite-overflow telemetry. - `docs/future-work.md`: documented all four debug query builtins in the "What ships today" block; updated the open "OAM allocation strategy" question to reference the shipped `cycle_sprites` path and ask about an automatic-flicker game attribute as a follow-up. - `docs/architecture.md`: updated the `ir/` and `optimizer/` module summaries to describe real inline splicing (now in lowering, not the optimizer). - `README.md`: reframed the `inline` bullet from "hint" to "real splicing for single-return / void-body shapes"; expanded the debug-support bullet to mention the four query builtins and their stripping in release builds; added a new bullet for the three-layer sprite-per-scanline mitigations; bumped the test count from 497 → 694; updated the war.ne entry to mention the seven compiler bugs are all fixed and point readers at `git log` (instead of the deleted COMPILER_BUGS.md). - `examples/README.md`: same `git log`-pointing rewrite for the war.ne entry. Deletions - `examples/war/COMPILER_BUGS.md` is removed. All seven catalogued bugs are fixed; the file's historical value lives in `git log` now. Every source-code comment and doc reference to the file has been updated to either point at `git log` or just describe the bug in place. Test count: 616 unit + 75 integration + 3 doctests = 694 total. Clippy / fmt clean. 32/32 emulator goldens match. https://claude.ai/code/session_0143dTgh3UeRrtfHgQwzcv5z
2026-04-15 23:19:07 +00:00
// Not marked `inline`: the conditional early return is one of
// the shapes the inliner declines (W0110). Living with the JSR
// is the correct call here since rewriting as a branchless max
// wouldn't fit in a single-return expression.
fun abs_diff(a: u8, b: u8) -> u8 {
if a > b {
return a - b
}
return b - a
}
// Function: check collision between two points
fun check_collision(x1: u8, y1: u8, x2: u8, y2: u8) -> u8 {
var dx: u8 = abs_diff(x1, x2)
var dy: u8 = abs_diff(y1, y2)
if dx < 8 {
if dy < 8 {
return 1
}
}
return 0
}
on frame {
// Player movement
if button.right { player_x += SPEED }
if button.left { player_x -= SPEED }
if button.down { player_y += SPEED }
if button.up { player_y -= SPEED }
player_x = clamp(player_x, 240)
player_y = clamp(player_y, 224)
// Update and draw enemies
var i: u8 = 0
while i < NUM_ENEMIES {
// Move enemies down slowly
enemy_y[i] += 1
if enemy_y[i] > 224 {
enemy_y[i] = 0
}
// Check collision with player
var hit: u8 = check_collision(player_x, player_y, enemy_x[i], enemy_y[i])
if hit == 1 {
// Reset enemy position on collision
enemy_y[i] = 0
}
draw Enemy at: (enemy_x[i], enemy_y[i])
i += 1
}
draw Player at: (player_x, player_y)
}
start Main