1
0
Fork 0
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:
Claude 2026-04-11 23:25:26 +00:00
parent fd5a940c89
commit 664ccc05db
No known key found for this signature in database
8 changed files with 1295 additions and 22 deletions

View file

@ -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()
}
}