1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-15 20:58:20 +00:00
nescript/src/main.rs

148 lines
4.1 KiB
Rust
Raw Normal View History

Implement NEScript compiler Milestone 1 ("Hello Sprite") Complete implementation of the NEScript compiler pipeline for M1: - Lexer: full tokenization with hex/binary/decimal literals, all keywords, operators - Parser: recursive descent with Pratt expression parsing (M1 subset) - Analyzer: symbol resolution, type checking, memory allocation - 6502 Assembler: full opcode encoding table (~150 valid combinations) - Code Generator: AST → 6502 instructions (direct, no IR for M1) - Runtime: NES hardware init, NMI handler, controller read, OAM DMA - Linker: NROM layout, vector table, palette loading, CHR data - ROM Builder: iNES header generation, PRG/CHR padding - CLI: `build` and `check` subcommands via clap 143 tests across all modules: - 22 lexer tests (literals, keywords, operators, error recovery) - 18 parser tests (expressions, statements, game structure, errors) - 7 analyzer tests (symbol resolution, memory allocation, transitions) - 30 assembler tests (every addressing mode, label resolution) - 7 codegen tests (var init, arithmetic, buttons, draw, comparisons) - 11 runtime tests (init sequence, NMI handler, controller read) - 10 ROM builder tests (iNES format, mirroring, banking, validation) - 5 linker tests (vector table, CHR data, palette loading) - 7 integration tests (end-to-end compilation, error detection) CI: GitHub Actions for check, fmt, clippy, test Pre-commit: script for local fmt + clippy + test validation https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
2026-04-11 22:07:56 +00:00
use clap::Parser;
use std::path::PathBuf;
use nescript::analyzer;
use nescript::codegen::CodeGen;
use nescript::errors::render_diagnostics;
use nescript::ir;
Implement NEScript compiler Milestone 1 ("Hello Sprite") Complete implementation of the NEScript compiler pipeline for M1: - Lexer: full tokenization with hex/binary/decimal literals, all keywords, operators - Parser: recursive descent with Pratt expression parsing (M1 subset) - Analyzer: symbol resolution, type checking, memory allocation - 6502 Assembler: full opcode encoding table (~150 valid combinations) - Code Generator: AST → 6502 instructions (direct, no IR for M1) - Runtime: NES hardware init, NMI handler, controller read, OAM DMA - Linker: NROM layout, vector table, palette loading, CHR data - ROM Builder: iNES header generation, PRG/CHR padding - CLI: `build` and `check` subcommands via clap 143 tests across all modules: - 22 lexer tests (literals, keywords, operators, error recovery) - 18 parser tests (expressions, statements, game structure, errors) - 7 analyzer tests (symbol resolution, memory allocation, transitions) - 30 assembler tests (every addressing mode, label resolution) - 7 codegen tests (var init, arithmetic, buttons, draw, comparisons) - 11 runtime tests (init sequence, NMI handler, controller read) - 10 ROM builder tests (iNES format, mirroring, banking, validation) - 5 linker tests (vector table, CHR data, palette loading) - 7 integration tests (end-to-end compilation, error detection) CI: GitHub Actions for check, fmt, clippy, test Pre-commit: script for local fmt + clippy + test validation https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
2026-04-11 22:07:56 +00:00
use nescript::linker::Linker;
use nescript::optimizer;
Implement NEScript compiler Milestone 1 ("Hello Sprite") Complete implementation of the NEScript compiler pipeline for M1: - Lexer: full tokenization with hex/binary/decimal literals, all keywords, operators - Parser: recursive descent with Pratt expression parsing (M1 subset) - Analyzer: symbol resolution, type checking, memory allocation - 6502 Assembler: full opcode encoding table (~150 valid combinations) - Code Generator: AST → 6502 instructions (direct, no IR for M1) - Runtime: NES hardware init, NMI handler, controller read, OAM DMA - Linker: NROM layout, vector table, palette loading, CHR data - ROM Builder: iNES header generation, PRG/CHR padding - CLI: `build` and `check` subcommands via clap 143 tests across all modules: - 22 lexer tests (literals, keywords, operators, error recovery) - 18 parser tests (expressions, statements, game structure, errors) - 7 analyzer tests (symbol resolution, memory allocation, transitions) - 30 assembler tests (every addressing mode, label resolution) - 7 codegen tests (var init, arithmetic, buttons, draw, comparisons) - 11 runtime tests (init sequence, NMI handler, controller read) - 10 ROM builder tests (iNES format, mirroring, banking, validation) - 5 linker tests (vector table, CHR data, palette loading) - 7 integration tests (end-to-end compilation, error detection) CI: GitHub Actions for check, fmt, clippy, test Pre-commit: script for local fmt + clippy + test validation https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
2026-04-11 22:07:56 +00:00
#[derive(Parser)]
#[command(name = "nescript", about = "NEScript compiler — NES game development")]
enum Cli {
/// Compile a .ne source file into a .nes ROM
Build {
/// Input source file
input: PathBuf,
/// Output ROM file (default: input with .nes extension)
#[arg(short, long)]
output: Option<PathBuf>,
/// Enable debug mode (runtime checks, debug.log)
#[arg(long)]
debug: bool,
Implement NEScript compiler Milestone 1 ("Hello Sprite") Complete implementation of the NEScript compiler pipeline for M1: - Lexer: full tokenization with hex/binary/decimal literals, all keywords, operators - Parser: recursive descent with Pratt expression parsing (M1 subset) - Analyzer: symbol resolution, type checking, memory allocation - 6502 Assembler: full opcode encoding table (~150 valid combinations) - Code Generator: AST → 6502 instructions (direct, no IR for M1) - Runtime: NES hardware init, NMI handler, controller read, OAM DMA - Linker: NROM layout, vector table, palette loading, CHR data - ROM Builder: iNES header generation, PRG/CHR padding - CLI: `build` and `check` subcommands via clap 143 tests across all modules: - 22 lexer tests (literals, keywords, operators, error recovery) - 18 parser tests (expressions, statements, game structure, errors) - 7 analyzer tests (symbol resolution, memory allocation, transitions) - 30 assembler tests (every addressing mode, label resolution) - 7 codegen tests (var init, arithmetic, buttons, draw, comparisons) - 11 runtime tests (init sequence, NMI handler, controller read) - 10 ROM builder tests (iNES format, mirroring, banking, validation) - 5 linker tests (vector table, CHR data, palette loading) - 7 integration tests (end-to-end compilation, error detection) CI: GitHub Actions for check, fmt, clippy, test Pre-commit: script for local fmt + clippy + test validation https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
2026-04-11 22:07:56 +00:00
},
/// Type-check a source file without building
Check {
/// Input source file
input: PathBuf,
},
}
fn main() {
let cli = Cli::parse();
match cli {
Cli::Build {
input,
output,
debug,
} => {
Implement NEScript compiler Milestone 1 ("Hello Sprite") Complete implementation of the NEScript compiler pipeline for M1: - Lexer: full tokenization with hex/binary/decimal literals, all keywords, operators - Parser: recursive descent with Pratt expression parsing (M1 subset) - Analyzer: symbol resolution, type checking, memory allocation - 6502 Assembler: full opcode encoding table (~150 valid combinations) - Code Generator: AST → 6502 instructions (direct, no IR for M1) - Runtime: NES hardware init, NMI handler, controller read, OAM DMA - Linker: NROM layout, vector table, palette loading, CHR data - ROM Builder: iNES header generation, PRG/CHR padding - CLI: `build` and `check` subcommands via clap 143 tests across all modules: - 22 lexer tests (literals, keywords, operators, error recovery) - 18 parser tests (expressions, statements, game structure, errors) - 7 analyzer tests (symbol resolution, memory allocation, transitions) - 30 assembler tests (every addressing mode, label resolution) - 7 codegen tests (var init, arithmetic, buttons, draw, comparisons) - 11 runtime tests (init sequence, NMI handler, controller read) - 10 ROM builder tests (iNES format, mirroring, banking, validation) - 5 linker tests (vector table, CHR data, palette loading) - 7 integration tests (end-to-end compilation, error detection) CI: GitHub Actions for check, fmt, clippy, test Pre-commit: script for local fmt + clippy + test validation https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
2026-04-11 22:07:56 +00:00
let output = output.unwrap_or_else(|| input.with_extension("nes"));
match compile(&input, debug) {
Implement NEScript compiler Milestone 1 ("Hello Sprite") Complete implementation of the NEScript compiler pipeline for M1: - Lexer: full tokenization with hex/binary/decimal literals, all keywords, operators - Parser: recursive descent with Pratt expression parsing (M1 subset) - Analyzer: symbol resolution, type checking, memory allocation - 6502 Assembler: full opcode encoding table (~150 valid combinations) - Code Generator: AST → 6502 instructions (direct, no IR for M1) - Runtime: NES hardware init, NMI handler, controller read, OAM DMA - Linker: NROM layout, vector table, palette loading, CHR data - ROM Builder: iNES header generation, PRG/CHR padding - CLI: `build` and `check` subcommands via clap 143 tests across all modules: - 22 lexer tests (literals, keywords, operators, error recovery) - 18 parser tests (expressions, statements, game structure, errors) - 7 analyzer tests (symbol resolution, memory allocation, transitions) - 30 assembler tests (every addressing mode, label resolution) - 7 codegen tests (var init, arithmetic, buttons, draw, comparisons) - 11 runtime tests (init sequence, NMI handler, controller read) - 10 ROM builder tests (iNES format, mirroring, banking, validation) - 5 linker tests (vector table, CHR data, palette loading) - 7 integration tests (end-to-end compilation, error detection) CI: GitHub Actions for check, fmt, clippy, test Pre-commit: script for local fmt + clippy + test validation https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
2026-04-11 22:07:56 +00:00
Ok(rom) => {
std::fs::write(&output, rom).unwrap_or_else(|e| {
eprintln!("error: failed to write {}: {e}", output.display());
std::process::exit(1);
});
println!(
"compiled {} -> {} ({} bytes)",
input.display(),
output.display(),
std::fs::metadata(&output).map(|m| m.len()).unwrap_or(0)
);
}
Err(()) => std::process::exit(1),
}
}
Cli::Check { input } => match check(&input) {
Ok(()) => println!("no errors found in {}", input.display()),
Err(()) => std::process::exit(1),
},
}
}
fn compile(input: &PathBuf, _debug: bool) -> Result<Vec<u8>, ()> {
Implement NEScript compiler Milestone 1 ("Hello Sprite") Complete implementation of the NEScript compiler pipeline for M1: - Lexer: full tokenization with hex/binary/decimal literals, all keywords, operators - Parser: recursive descent with Pratt expression parsing (M1 subset) - Analyzer: symbol resolution, type checking, memory allocation - 6502 Assembler: full opcode encoding table (~150 valid combinations) - Code Generator: AST → 6502 instructions (direct, no IR for M1) - Runtime: NES hardware init, NMI handler, controller read, OAM DMA - Linker: NROM layout, vector table, palette loading, CHR data - ROM Builder: iNES header generation, PRG/CHR padding - CLI: `build` and `check` subcommands via clap 143 tests across all modules: - 22 lexer tests (literals, keywords, operators, error recovery) - 18 parser tests (expressions, statements, game structure, errors) - 7 analyzer tests (symbol resolution, memory allocation, transitions) - 30 assembler tests (every addressing mode, label resolution) - 7 codegen tests (var init, arithmetic, buttons, draw, comparisons) - 11 runtime tests (init sequence, NMI handler, controller read) - 10 ROM builder tests (iNES format, mirroring, banking, validation) - 5 linker tests (vector table, CHR data, palette loading) - 7 integration tests (end-to-end compilation, error detection) CI: GitHub Actions for check, fmt, clippy, test Pre-commit: script for local fmt + clippy + test validation https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
2026-04-11 22:07:56 +00:00
let source = std::fs::read_to_string(input).map_err(|e| {
eprintln!("error: failed to read {}: {e}", input.display());
})?;
let filename = input.to_string_lossy();
// Parse
let (program, parse_diags) = nescript::parser::parse(&source);
if !parse_diags.is_empty() {
render_diagnostics(&source, &filename, &parse_diags);
}
if parse_diags
.iter()
.any(nescript::errors::Diagnostic::is_error)
{
return Err(());
}
let program = program.ok_or(())?;
// Analyze
let analysis = analyzer::analyze(&program);
if !analysis.diagnostics.is_empty() {
render_diagnostics(&source, &filename, &analysis.diagnostics);
}
if analysis
.diagnostics
.iter()
.any(nescript::errors::Diagnostic::is_error)
{
return Err(());
}
// IR lowering and optimization
let mut ir_program = ir::lower(&program, &analysis);
optimizer::optimize(&mut ir_program);
// Code generation (still AST-based for M2; IR codegen comes in M3)
Implement NEScript compiler Milestone 1 ("Hello Sprite") Complete implementation of the NEScript compiler pipeline for M1: - Lexer: full tokenization with hex/binary/decimal literals, all keywords, operators - Parser: recursive descent with Pratt expression parsing (M1 subset) - Analyzer: symbol resolution, type checking, memory allocation - 6502 Assembler: full opcode encoding table (~150 valid combinations) - Code Generator: AST → 6502 instructions (direct, no IR for M1) - Runtime: NES hardware init, NMI handler, controller read, OAM DMA - Linker: NROM layout, vector table, palette loading, CHR data - ROM Builder: iNES header generation, PRG/CHR padding - CLI: `build` and `check` subcommands via clap 143 tests across all modules: - 22 lexer tests (literals, keywords, operators, error recovery) - 18 parser tests (expressions, statements, game structure, errors) - 7 analyzer tests (symbol resolution, memory allocation, transitions) - 30 assembler tests (every addressing mode, label resolution) - 7 codegen tests (var init, arithmetic, buttons, draw, comparisons) - 11 runtime tests (init sequence, NMI handler, controller read) - 10 ROM builder tests (iNES format, mirroring, banking, validation) - 5 linker tests (vector table, CHR data, palette loading) - 7 integration tests (end-to-end compilation, error detection) CI: GitHub Actions for check, fmt, clippy, test Pre-commit: script for local fmt + clippy + test validation https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
2026-04-11 22:07:56 +00:00
let codegen = CodeGen::new(&analysis.var_allocations, &program.constants);
let instructions = codegen.generate(&program);
// Link into ROM
let linker = Linker::new(program.game.mirroring);
let rom = linker.link(&instructions);
Ok(rom)
}
fn check(input: &PathBuf) -> Result<(), ()> {
let source = std::fs::read_to_string(input).map_err(|e| {
eprintln!("error: failed to read {}: {e}", input.display());
})?;
let filename = input.to_string_lossy();
let (program, parse_diags) = nescript::parser::parse(&source);
if !parse_diags.is_empty() {
render_diagnostics(&source, &filename, &parse_diags);
}
if parse_diags
.iter()
.any(nescript::errors::Diagnostic::is_error)
{
return Err(());
}
let program = program.ok_or(())?;
let analysis = analyzer::analyze(&program);
if !analysis.diagnostics.is_empty() {
render_diagnostics(&source, &filename, &analysis.diagnostics);
}
if analysis
.diagnostics
.iter()
.any(nescript::errors::Diagnostic::is_error)
{
return Err(());
}
Ok(())
}