use crate::ast::*; use crate::error::CompileError; use crate::token::{Span, Token, TokenKind}; use crate::ui_decl::UiElement; pub struct Parser<'a> { tokens: &'a [Token], pos: usize, } impl<'a> Parser<'a> { pub fn new(tokens: &'a [Token]) -> Self { Self { tokens, pos: 0 } } fn peek(&self) -> &TokenKind { &self.tokens[self.pos].kind } fn span(&self) -> Span { self.tokens[self.pos].span } fn advance(&mut self) -> &Token { let tok = &self.tokens[self.pos]; if self.pos + 1 < self.tokens.len() { self.pos += 1; } tok } fn expect(&mut self, expected: &TokenKind) -> Result<&Token, CompileError> { if std::mem::discriminant(self.peek()) == std::mem::discriminant(expected) { Ok(self.advance()) } else { Err(CompileError::new( format!("Expected {:?}, found {:?}", expected, self.peek()), self.span(), )) } } fn expect_ident(&mut self) -> Result { match self.peek().clone() { TokenKind::Ident(name) => { let name = name.clone(); self.advance(); Ok(name) } _ => Err(CompileError::new( format!("Expected identifier, found {:?}", self.peek()), self.span(), )), } } fn expect_string(&mut self) -> Result { match self.peek().clone() { TokenKind::StringLit(s) => { let s = s.clone(); self.advance(); Ok(s) } _ => Err(CompileError::new( format!("Expected string literal, found {:?}", self.peek()), self.span(), )), } } fn eat(&mut self, kind: &TokenKind) -> bool { if std::mem::discriminant(self.peek()) == std::mem::discriminant(kind) { self.advance(); true } else { false } } pub fn parse(&mut self) -> Result { let mut name = String::new(); let mut category = CategoryKind::Utility; let mut inputs = Vec::new(); let mut outputs = Vec::new(); let mut params = Vec::new(); let mut state = Vec::new(); let mut ui = None; let mut process = Vec::new(); let mut draw = None; while *self.peek() != TokenKind::Eof { match self.peek() { TokenKind::Name => { self.advance(); name = self.expect_string()?; } TokenKind::Category => { self.advance(); category = match self.peek() { TokenKind::Generator => { self.advance(); CategoryKind::Generator } TokenKind::Effect => { self.advance(); CategoryKind::Effect } TokenKind::Utility => { self.advance(); CategoryKind::Utility } _ => { return Err(CompileError::new( "Expected generator, effect, or utility", self.span(), )); } }; } TokenKind::Inputs => { self.advance(); inputs = self.parse_port_block()?; } TokenKind::Outputs => { self.advance(); outputs = self.parse_port_block()?; } TokenKind::Params => { self.advance(); params = self.parse_params_block()?; } TokenKind::State => { self.advance(); state = self.parse_state_block()?; } TokenKind::Ui => { self.advance(); ui = Some(self.parse_ui_block()?); } TokenKind::Process => { self.advance(); process = self.parse_block()?; } TokenKind::Draw => { self.advance(); draw = Some(self.parse_block()?); } _ => { return Err(CompileError::new( format!("Unexpected token {:?} at top level", self.peek()), self.span(), )); } } } if name.is_empty() { return Err(CompileError::new( "Script must have a name declaration", Span::new(1, 1), )); } Ok(Script { name, category, inputs, outputs, params, state, ui, process, draw, }) } fn parse_port_block(&mut self) -> Result, CompileError> { self.expect(&TokenKind::LBrace)?; let mut ports = Vec::new(); while *self.peek() != TokenKind::RBrace { let span = self.span(); let name = self.expect_ident()?; self.expect(&TokenKind::Colon)?; let signal = match self.peek() { TokenKind::Audio => { self.advance(); SignalKind::Audio } TokenKind::Cv => { self.advance(); SignalKind::Cv } TokenKind::Midi => { self.advance(); SignalKind::Midi } _ => { return Err(CompileError::new( "Expected audio, cv, or midi", self.span(), )); } }; ports.push(PortDecl { name, signal, span }); } self.expect(&TokenKind::RBrace)?; Ok(ports) } fn parse_params_block(&mut self) -> Result, CompileError> { self.expect(&TokenKind::LBrace)?; let mut params = Vec::new(); while *self.peek() != TokenKind::RBrace { let span = self.span(); let name = self.expect_ident()?; self.expect(&TokenKind::Colon)?; let default = self.parse_number()?; self.expect(&TokenKind::LBracket)?; let min = self.parse_number()?; self.expect(&TokenKind::Comma)?; let max = self.parse_number()?; self.expect(&TokenKind::RBracket)?; let unit = self.expect_string()?; params.push(ParamDecl { name, default, min, max, unit, span, }); } self.expect(&TokenKind::RBrace)?; Ok(params) } fn parse_number(&mut self) -> Result { let negative = self.eat(&TokenKind::Minus); let val = match self.peek() { TokenKind::FloatLit(v) => { let v = *v; self.advance(); v } TokenKind::IntLit(v) => { let v = *v as f32; self.advance(); v } _ => { return Err(CompileError::new( format!("Expected number, found {:?}", self.peek()), self.span(), )); } }; Ok(if negative { -val } else { val }) } fn parse_state_block(&mut self) -> Result, CompileError> { self.expect(&TokenKind::LBrace)?; let mut decls = Vec::new(); while *self.peek() != TokenKind::RBrace { let span = self.span(); let name = self.expect_ident()?; self.expect(&TokenKind::Colon)?; let ty = self.parse_state_type()?; decls.push(StateDecl { name, ty, span }); } self.expect(&TokenKind::RBrace)?; Ok(decls) } fn parse_state_type(&mut self) -> Result { match self.peek() { TokenKind::F32 => { self.advance(); Ok(StateType::F32) } TokenKind::Int => { self.advance(); Ok(StateType::Int) } TokenKind::Bool => { self.advance(); Ok(StateType::Bool) } TokenKind::Sample => { self.advance(); Ok(StateType::Sample) } TokenKind::LBracket => { self.advance(); let size = match self.peek() { TokenKind::IntLit(n) => { let n = *n as usize; self.advance(); n } _ => { return Err(CompileError::new( "Expected integer size for array", self.span(), )); } }; self.expect(&TokenKind::RBracket)?; match self.peek() { TokenKind::F32 => { self.advance(); Ok(StateType::ArrayF32(size)) } TokenKind::Int => { self.advance(); Ok(StateType::ArrayInt(size)) } _ => Err(CompileError::new("Expected f32 or int after array size", self.span())), } } _ => Err(CompileError::new( format!("Expected type (f32, int, bool, sample, [N]f32, [N]int), found {:?}", self.peek()), self.span(), )), } } fn parse_ui_block(&mut self) -> Result, CompileError> { self.expect(&TokenKind::LBrace)?; let mut elements = Vec::new(); while *self.peek() != TokenKind::RBrace { elements.push(self.parse_ui_element()?); } self.expect(&TokenKind::RBrace)?; Ok(elements) } fn parse_ui_element(&mut self) -> Result { match self.peek() { TokenKind::Param => { self.advance(); let name = self.expect_ident()?; Ok(UiElement::Param(name)) } TokenKind::Sample => { self.advance(); let name = self.expect_ident()?; Ok(UiElement::Sample(name)) } TokenKind::Group => { self.advance(); let label = self.expect_string()?; let children = self.parse_ui_block()?; Ok(UiElement::Group { label, children }) } TokenKind::Canvas => { self.advance(); self.expect(&TokenKind::LBracket)?; let width = self.parse_number()?; self.expect(&TokenKind::Comma)?; let height = self.parse_number()?; self.expect(&TokenKind::RBracket)?; Ok(UiElement::Canvas { width, height }) } TokenKind::Spacer => { self.advance(); let px = self.parse_number()?; Ok(UiElement::Spacer(px)) } _ => Err(CompileError::new( format!("Expected UI element (param, sample, group, canvas, spacer), found {:?}", self.peek()), self.span(), )), } } fn parse_block(&mut self) -> Result { self.expect(&TokenKind::LBrace)?; let mut stmts = Vec::new(); while *self.peek() != TokenKind::RBrace { stmts.push(self.parse_stmt()?); } self.expect(&TokenKind::RBrace)?; Ok(stmts) } fn parse_stmt(&mut self) -> Result { match self.peek() { TokenKind::Let => self.parse_let(), TokenKind::If => self.parse_if(), TokenKind::For => self.parse_for(), _ => { // Assignment or expression statement let span = self.span(); let expr = self.parse_expr()?; if self.eat(&TokenKind::Eq) { // This is an assignment: expr = value let value = self.parse_expr()?; self.eat(&TokenKind::Semicolon); let target = self.expr_to_lvalue(expr, span)?; Ok(Stmt::Assign { target, value, span }) } else { self.eat(&TokenKind::Semicolon); Ok(Stmt::ExprStmt(expr)) } } } } fn expr_to_lvalue(&self, expr: Expr, span: Span) -> Result { match expr { Expr::Ident(name, s) => Ok(LValue::Ident(name, s)), Expr::Index(base, idx, s) => { if let Expr::Ident(name, _) = *base { Ok(LValue::Index(name, idx, s)) } else { Err(CompileError::new("Invalid assignment target", span)) } } _ => Err(CompileError::new("Invalid assignment target", span)), } } fn parse_let(&mut self) -> Result { let span = self.span(); self.advance(); // consume 'let' let mutable = self.eat(&TokenKind::Mut); let name = self.expect_ident()?; self.expect(&TokenKind::Eq)?; let init = self.parse_expr()?; self.eat(&TokenKind::Semicolon); Ok(Stmt::Let { name, mutable, init, span, }) } fn parse_if(&mut self) -> Result { let span = self.span(); self.advance(); // consume 'if' let cond = self.parse_expr()?; let then_block = self.parse_block()?; let else_block = if self.eat(&TokenKind::Else) { if *self.peek() == TokenKind::If { // else if -> wrap in a block with single if statement Some(vec![self.parse_if()?]) } else { Some(self.parse_block()?) } } else { None }; Ok(Stmt::If { cond, then_block, else_block, span, }) } fn parse_for(&mut self) -> Result { let span = self.span(); self.advance(); // consume 'for' let var = self.expect_ident()?; self.expect(&TokenKind::In)?; // Expect 0..end let zero_span = self.span(); match self.peek() { TokenKind::IntLit(0) => { self.advance(); } _ => { return Err(CompileError::new( "For loop range must start at 0 (e.g. 0..buffer_size)", zero_span, )); } } self.expect(&TokenKind::DotDot)?; let end = self.parse_expr()?; let body = self.parse_block()?; Ok(Stmt::For { var, end, body, span, }) } // Expression parsing with precedence climbing fn parse_expr(&mut self) -> Result { self.parse_or() } fn parse_or(&mut self) -> Result { let mut left = self.parse_and()?; while *self.peek() == TokenKind::PipePipe { let span = self.span(); self.advance(); let right = self.parse_and()?; left = Expr::BinOp(Box::new(left), BinOp::Or, Box::new(right), span); } Ok(left) } fn parse_and(&mut self) -> Result { let mut left = self.parse_equality()?; while *self.peek() == TokenKind::AmpAmp { let span = self.span(); self.advance(); let right = self.parse_equality()?; left = Expr::BinOp(Box::new(left), BinOp::And, Box::new(right), span); } Ok(left) } fn parse_equality(&mut self) -> Result { let mut left = self.parse_comparison()?; loop { let op = match self.peek() { TokenKind::EqEq => BinOp::Eq, TokenKind::BangEq => BinOp::Ne, _ => break, }; let span = self.span(); self.advance(); let right = self.parse_comparison()?; left = Expr::BinOp(Box::new(left), op, Box::new(right), span); } Ok(left) } fn parse_comparison(&mut self) -> Result { let mut left = self.parse_additive()?; loop { let op = match self.peek() { TokenKind::Lt => BinOp::Lt, TokenKind::Gt => BinOp::Gt, TokenKind::LtEq => BinOp::Le, TokenKind::GtEq => BinOp::Ge, _ => break, }; let span = self.span(); self.advance(); let right = self.parse_additive()?; left = Expr::BinOp(Box::new(left), op, Box::new(right), span); } Ok(left) } fn parse_additive(&mut self) -> Result { let mut left = self.parse_multiplicative()?; loop { let op = match self.peek() { TokenKind::Plus => BinOp::Add, TokenKind::Minus => BinOp::Sub, _ => break, }; let span = self.span(); self.advance(); let right = self.parse_multiplicative()?; left = Expr::BinOp(Box::new(left), op, Box::new(right), span); } Ok(left) } fn parse_multiplicative(&mut self) -> Result { let mut left = self.parse_unary()?; loop { let op = match self.peek() { TokenKind::Star => BinOp::Mul, TokenKind::Slash => BinOp::Div, TokenKind::Percent => BinOp::Mod, _ => break, }; let span = self.span(); self.advance(); let right = self.parse_unary()?; left = Expr::BinOp(Box::new(left), op, Box::new(right), span); } Ok(left) } fn parse_unary(&mut self) -> Result { match self.peek() { TokenKind::Minus => { let span = self.span(); self.advance(); let expr = self.parse_unary()?; Ok(Expr::UnaryOp(UnaryOp::Neg, Box::new(expr), span)) } TokenKind::Bang => { let span = self.span(); self.advance(); let expr = self.parse_unary()?; Ok(Expr::UnaryOp(UnaryOp::Not, Box::new(expr), span)) } _ => self.parse_postfix(), } } fn parse_postfix(&mut self) -> Result { let mut expr = self.parse_primary()?; // Handle indexing: expr[index] while *self.peek() == TokenKind::LBracket { let span = self.span(); self.advance(); let index = self.parse_expr()?; self.expect(&TokenKind::RBracket)?; expr = Expr::Index(Box::new(expr), Box::new(index), span); } Ok(expr) } fn parse_primary(&mut self) -> Result { let span = self.span(); match self.peek().clone() { TokenKind::FloatLit(v) => { self.advance(); Ok(Expr::FloatLit(v, span)) } TokenKind::IntLit(v) => { self.advance(); Ok(Expr::IntLit(v, span)) } TokenKind::True => { self.advance(); Ok(Expr::BoolLit(true, span)) } TokenKind::False => { self.advance(); Ok(Expr::BoolLit(false, span)) } TokenKind::LParen => { self.advance(); let expr = self.parse_expr()?; self.expect(&TokenKind::RParen)?; Ok(expr) } // Cast: int(expr) or float(expr) TokenKind::Int => { self.advance(); self.expect(&TokenKind::LParen)?; let expr = self.parse_expr()?; self.expect(&TokenKind::RParen)?; Ok(Expr::Cast(CastKind::ToInt, Box::new(expr), span)) } TokenKind::F32 => { self.advance(); self.expect(&TokenKind::LParen)?; let expr = self.parse_expr()?; self.expect(&TokenKind::RParen)?; Ok(Expr::Cast(CastKind::ToFloat, Box::new(expr), span)) } TokenKind::Ident(name) => { let name = name.clone(); self.advance(); // Check if it's a function call if *self.peek() == TokenKind::LParen { self.advance(); let mut args = Vec::new(); if *self.peek() != TokenKind::RParen { args.push(self.parse_expr()?); while self.eat(&TokenKind::Comma) { args.push(self.parse_expr()?); } } self.expect(&TokenKind::RParen)?; Ok(Expr::Call(name, args, span)) } else { Ok(Expr::Ident(name, span)) } } _ => Err(CompileError::new( format!("Expected expression, found {:?}", self.peek()), span, )), } } } #[cfg(test)] mod tests { use super::*; use crate::lexer::Lexer; fn parse_script(source: &str) -> Result { let mut lexer = Lexer::new(source); let tokens = lexer.tokenize()?; let mut parser = Parser::new(&tokens); parser.parse() } #[test] fn test_minimal_script() { let script = parse_script(r#" name "Test" category utility process {} "#).unwrap(); assert_eq!(script.name, "Test"); assert_eq!(script.category, CategoryKind::Utility); } #[test] fn test_ports_and_params() { let script = parse_script(r#" name "Gain" category effect inputs { audio_in: audio cv_mod: cv } outputs { audio_out: audio } params { gain: 1.0 [0.0, 2.0] "" } process {} "#).unwrap(); assert_eq!(script.inputs.len(), 2); assert_eq!(script.outputs.len(), 1); assert_eq!(script.params.len(), 1); assert_eq!(script.params[0].name, "gain"); assert_eq!(script.params[0].default, 1.0); } #[test] fn test_state_with_sample() { let script = parse_script(r#" name "Sampler" category generator state { clip: sample phase: f32 buffer: [4096]f32 counter: int } process {} "#).unwrap(); assert_eq!(script.state.len(), 4); assert_eq!(script.state[0].ty, StateType::Sample); assert_eq!(script.state[1].ty, StateType::F32); assert_eq!(script.state[2].ty, StateType::ArrayF32(4096)); assert_eq!(script.state[3].ty, StateType::Int); } #[test] fn test_process_with_for_loop() { let script = parse_script(r#" name "Pass" category effect inputs { audio_in: audio } outputs { audio_out: audio } process { for i in 0..buffer_size { audio_out[i * 2] = audio_in[i * 2]; audio_out[i * 2 + 1] = audio_in[i * 2 + 1]; } } "#).unwrap(); assert_eq!(script.process.len(), 1); } #[test] fn test_expressions() { let script = parse_script(r#" name "Expr" category utility process { let x = 1.0 + 2.0 * 3.0; let y = sin(x) + cos(3.14); let z = int(x * 100.0); } "#).unwrap(); assert_eq!(script.process.len(), 3); } #[test] fn test_ui_block() { let script = parse_script(r#" name "UI Test" category utility params { gain: 1.0 [0.0, 2.0] "" mix: 0.5 [0.0, 1.0] "" } state { clip: sample } ui { sample clip param gain group "Advanced" { param mix } } process {} "#).unwrap(); let ui = script.ui.unwrap(); assert_eq!(ui.len(), 3); } }