mirror of
https://github.com/imjasonh/nescript
synced 2026-07-17 06:02:01 +00:00
M2: Add function/array parsing, IR data structures and lowering
Parser extensions: - Function declarations with params and return types (fun, inline fun) - Array type syntax (u8[16]), array literal expressions ([1, 2, 3]) - fast/slow variable placement hints - Functions stored in Program AST IR module (new): - IrProgram, IrFunction, IrBasicBlock, IrOp, IrTerminator types - AST-to-IR lowering pass with: - Expression lowering to virtual temps - Control flow (if/else, while, loop) to basic blocks with branches - Break/continue via loop context stack - Short-circuit logical and/or - Button reads, draw sprites, wait_frame - Constants inlined as LoadImm - State handlers lowered as separate IR functions Tests: 6 new parser tests, 11 new IR lowering tests (153 total) https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
This commit is contained in:
parent
fd5a940c89
commit
664ccc05db
8 changed files with 1295 additions and 22 deletions
163
src/ir/mod.rs
163
src/ir/mod.rs
|
|
@ -1,3 +1,160 @@
|
|||
// IR module — stub for Milestone 1.
|
||||
// The IR phase will be implemented in Milestone 2.
|
||||
// For M1, we compile directly from AST to 6502 instructions.
|
||||
mod lowering;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use lowering::lower;
|
||||
|
||||
use crate::lexer::Span;
|
||||
use std::fmt;
|
||||
|
||||
/// A unique identifier for a variable across the program.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct VarId(pub u32);
|
||||
|
||||
/// A virtual register — unlimited supply, resolved during codegen.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct IrTemp(pub u32);
|
||||
|
||||
impl fmt::Display for IrTemp {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "t{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for VarId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "v{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// The top-level IR program.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IrProgram {
|
||||
pub functions: Vec<IrFunction>,
|
||||
pub globals: Vec<IrGlobal>,
|
||||
pub rom_data: Vec<IrRomBlock>,
|
||||
}
|
||||
|
||||
/// A global variable in the IR.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IrGlobal {
|
||||
pub var_id: VarId,
|
||||
pub name: String,
|
||||
pub size: u16,
|
||||
pub init_value: Option<u16>,
|
||||
}
|
||||
|
||||
/// A block of constant data to be placed in ROM.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IrRomBlock {
|
||||
pub label: String,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
/// An IR function (includes state handlers, user functions, etc.)
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IrFunction {
|
||||
pub name: String,
|
||||
pub blocks: Vec<IrBasicBlock>,
|
||||
pub locals: Vec<IrLocal>,
|
||||
pub param_count: usize,
|
||||
pub has_return: bool,
|
||||
pub source_span: Span,
|
||||
}
|
||||
|
||||
/// A local variable within a function.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IrLocal {
|
||||
pub var_id: VarId,
|
||||
pub name: String,
|
||||
pub size: u16,
|
||||
}
|
||||
|
||||
/// A basic block — a straight-line sequence of ops ending with a terminator.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct IrBasicBlock {
|
||||
pub label: String,
|
||||
pub ops: Vec<IrOp>,
|
||||
pub terminator: IrTerminator,
|
||||
}
|
||||
|
||||
/// An IR operation.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum IrOp {
|
||||
// Load/Store
|
||||
LoadImm(IrTemp, u8),
|
||||
LoadVar(IrTemp, VarId),
|
||||
StoreVar(VarId, IrTemp),
|
||||
|
||||
// Arithmetic (8-bit)
|
||||
Add(IrTemp, IrTemp, IrTemp),
|
||||
Sub(IrTemp, IrTemp, IrTemp),
|
||||
Mul(IrTemp, IrTemp, IrTemp),
|
||||
And(IrTemp, IrTemp, IrTemp),
|
||||
Or(IrTemp, IrTemp, IrTemp),
|
||||
Xor(IrTemp, IrTemp, IrTemp),
|
||||
ShiftLeft(IrTemp, IrTemp, u8),
|
||||
ShiftRight(IrTemp, IrTemp, u8),
|
||||
Negate(IrTemp, IrTemp),
|
||||
Complement(IrTemp, IrTemp),
|
||||
|
||||
// Comparison (sets a boolean temp)
|
||||
CmpEq(IrTemp, IrTemp, IrTemp),
|
||||
CmpNe(IrTemp, IrTemp, IrTemp),
|
||||
CmpLt(IrTemp, IrTemp, IrTemp),
|
||||
CmpGt(IrTemp, IrTemp, IrTemp),
|
||||
CmpLtEq(IrTemp, IrTemp, IrTemp),
|
||||
CmpGtEq(IrTemp, IrTemp, IrTemp),
|
||||
|
||||
// Array access
|
||||
ArrayLoad(IrTemp, VarId, IrTemp),
|
||||
ArrayStore(VarId, IrTemp, IrTemp),
|
||||
|
||||
// Function call
|
||||
Call(Option<IrTemp>, String, Vec<IrTemp>),
|
||||
|
||||
// Hardware operations
|
||||
DrawSprite {
|
||||
sprite_name: String,
|
||||
x: IrTemp,
|
||||
y: IrTemp,
|
||||
frame: Option<IrTemp>,
|
||||
},
|
||||
ReadInput,
|
||||
WaitFrame,
|
||||
Transition(String),
|
||||
|
||||
// Source mapping
|
||||
SourceLoc(Span),
|
||||
}
|
||||
|
||||
/// A basic block terminator.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum IrTerminator {
|
||||
/// Unconditional jump to a label.
|
||||
Jump(String),
|
||||
/// Conditional branch: if temp != 0 goto true_label else goto false_label.
|
||||
Branch(IrTemp, String, String),
|
||||
/// Return from function, optionally with a value.
|
||||
Return(Option<IrTemp>),
|
||||
/// Unreachable (after infinite loops, etc.)
|
||||
Unreachable,
|
||||
}
|
||||
|
||||
impl IrProgram {
|
||||
/// Count total number of IR operations across all functions.
|
||||
pub fn op_count(&self) -> usize {
|
||||
self.functions
|
||||
.iter()
|
||||
.flat_map(|f| &f.blocks)
|
||||
.map(|b| b.ops.len())
|
||||
.sum()
|
||||
}
|
||||
}
|
||||
|
||||
impl IrFunction {
|
||||
/// Count total number of IR operations in this function.
|
||||
pub fn op_count(&self) -> usize {
|
||||
self.blocks.iter().map(|b| b.ops.len()).sum()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue