1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-08 17:06:04 +00:00
No description
Find a file
Claude 1525922faa
examples: add 5 new programs covering match/loop/logic/bitwise/scanline
Fills the biggest feature-coverage gaps in the existing example set:

- match_demo.ne          — match statement over a Screen enum,
                           driving a title / playing / paused /
                           game-over flow with a debounced controller.
- loop_break_continue.ne — `loop { ... }` with `break` and `continue`,
                           scanning an enemy array for the first hit.
- logic_ops.ne           — keyword-based `and` / `or` / `not` gating
                           movement and scoring on alive/paused flags.
- bitwise_ops.ne         — packed status-byte flags with `&` / `|` /
                           `^` / `>>` plus a health-bar render loop.
- scanline_split.ne      — MMC3 `on scanline(120)` handler rewriting
                           the scroll register mid-frame for a
                           classic status-bar split.

All 14 examples (9 existing + 5 new) pass the jsnes smoke test
(`14/14 ROMs rendered successfully`) and still pass `cargo fmt`,
`cargo clippy -D warnings`, and `cargo test`.

Known limitations surfaced while authoring these examples, to be
fixed in follow-up commits:

1. Array-literal global initializers (`var xs: u8[4] = [1,2,3,4]`)
   are silently dropped by `lower_program` — `eval_const` returns
   None for `Expr::ArrayLiteral` and no synthetic per-element
   init code is emitted. Affects `arrays_and_functions`,
   `structs_enums_for`, `loop_break_continue`, and any future
   array-using example. Arrays effectively boot at all-zero.

2. `draw` inside a loop body reuses one static OAM slot —
   `next_oam_slot` increments at IR-codegen time rather than at
   runtime, so N iterations all write to the same 4-byte OAM
   entry. Affects `arrays_and_functions`, `structs_enums_for`,
   `bitwise_ops` (health pips), and any loop that wants to
   render per-iteration sprites.

Both bugs are latent and didn't surface until I tried to write
examples that exercise the relevant features — the existing
integration tests only check iNES header structure, and the
jsnes smoke test's "at least one sprite rendered" bar is
satisfied by one sprite even when several were intended.

https://claude.ai/code/session_014Z5y3Q9krLcAxYpZQJhZ5V
2026-04-12 19:05:18 +00:00
.github/workflows CI: add emulator smoke test job 2026-04-12 18:49:36 +00:00
docs docs: future-work.md — document all new additions 2026-04-12 17:47:09 +00:00
examples examples: add 5 new programs covering match/loop/logic/bitwise/scanline 2026-04-12 19:05:18 +00:00
fuzz Add fuzz testing and parser edge case regression tests 2026-04-12 00:52:35 +00:00
scripts Implement NEScript compiler Milestone 1 ("Hello Sprite") 2026-04-11 22:07:56 +00:00
src Add jsnes emulator harness and fix four codegen bugs it surfaced 2026-04-12 18:46:58 +00:00
tests examples: add 5 new programs covering match/loop/logic/bitwise/scanline 2026-04-12 19:05:18 +00:00
.gitignore Implement NEScript compiler Milestone 1 ("Hello Sprite") 2026-04-11 22:07:56 +00:00
Cargo.lock M3: Asset pipeline, sprite/palette/background declarations, debug symbols 2026-04-12 00:09:47 +00:00
Cargo.toml M3: Asset pipeline, sprite/palette/background declarations, debug symbols 2026-04-12 00:09:47 +00:00
LICENSE Add README, LICENSE, examples, fix draw parser lookahead 2026-04-12 00:38:19 +00:00
plan.md Create initial engineering design document for NEScript 2026-04-11 17:42:43 -04:00
README.md README: list new language features and examples 2026-04-12 18:07:47 +00:00
spec.md Add NEScript language specification draft 2026-04-11 17:42:59 -04:00

NEScript

A statically-typed, compiled programming language for NES game development.

NEScript compiles .ne source files directly into playable iNES ROM files, with no external assembler or linker dependencies. The compiler handles everything from source text to a ROM you can run in any NES emulator.

Quick Start

# Build the compiler
cargo build --release

# Compile an example
cargo run -- build examples/hello_sprite.ne

# Run the output ROM in an emulator
# (produces examples/hello_sprite.nes)

Hello World

game "Hello" {
    mapper: NROM
}

var px: u8 = 128
var py: u8 = 120

on frame {
    if button.right { px += 2 }
    if button.left  { px -= 2 }
    if button.down  { py += 2 }
    if button.up    { py -= 2 }

    draw Smiley at: (px, py)
}

start Main

Features

  • Game-aware syntax -- states, sprites, palettes, and input are first-class constructs
  • Full type system -- u8, i8, u16, bool, fixed-size arrays (u8[N]), enum, struct
  • Rich control flow -- if/else, while, for i in 0..N, loop, match
  • Functions -- with parameters, return types, inline hint, recursion detection
  • State machines -- state with on enter, on exit, on frame, on scanline(N) handlers
  • Compile-time safety -- call depth limits, recursion detection, type checking, unused-var warnings
  • IR-based optimizer -- constant folding, dead code elimination, strength reduction, copy propagation, peephole passes
  • Multiple mappers -- NROM, MMC1, UxROM, MMC3 (including scanline IRQ dispatch)
  • Asset pipeline -- PNG-to-CHR conversion, palette definitions, inline tile data
  • Inline assembly -- asm { ... } with {var} substitution, plus raw asm { ... } for verbatim blocks
  • Hardware intrinsics -- poke(addr, value) / peek(addr) for direct register access
  • Debug support -- --debug flag, source maps, Mesen-compatible symbol export, debug.log / debug.assert
  • Compile-time diagnostics -- --dump-ir, --memory-map, --call-graph flags
  • Single binary -- no dependencies on ca65, Python, or any external tools

Documentation

Examples

Example Features demonstrated
hello_sprite.ne D-pad input, sprite drawing
bouncing_ball.ne Automatic movement, edge detection
coin_cavern.ne Multi-state game, functions, constants, gravity
arrays_and_functions.ne Arrays, functions, while loops, inline functions
state_machine.ne State transitions, on enter/exit, timers
sprites_and_palettes.ne Inline CHR data, palettes, scroll, type casting
mmc1_banked.ne MMC1 mapper, bank declarations, multiply
structs_enums_for.ne Structs, enums, for loops, struct literals
inline_asm_demo.ne Inline asm with {var} substitution, poke/peek

Compiler Commands

# Compile to ROM
nescript build game.ne

# Compile with custom output path
nescript build game.ne --output my_game.nes

# Type-check only (no ROM output)
nescript check game.ne

# View generated 6502 assembly
nescript build game.ne --asm-dump

# Enable debug mode
nescript build game.ne --debug

Emulator Compatibility

Output ROMs are standard iNES format and work with any NES emulator:

Project Status

NEScript implements all five planned milestones:

Milestone Status Key Features
M1: Hello Sprite Done Full compiler pipeline, assembler, ROM builder
M2: Game Loop Done Functions, arrays, IR, optimizer, call graph analysis
M3: Asset Pipeline Done PNG-to-CHR, sprites, palettes, debug symbols
M4: Optimization Done Strength reduction, ZP promotion, type casting, asm-dump
M5: Bank Switching Done MMC1/UxROM/MMC3, bank declarations, software mul/div

210 tests across 14 modules, with CI running fmt, clippy, test, and example compilation on every push.

License

MIT