//! Parser for el-ui component files. //! //! Hand-written recursive descent. Produces a `Vec` from a token stream. use crate::ast::*; use crate::error::{CompileError, CompileResult}; use crate::lexer::Token; pub fn parse(tokens: &[Token]) -> CompileResult> { let mut p = Parser::new(tokens); p.parse_program() } struct Parser<'a> { tokens: &'a [Token], pos: usize, } impl<'a> Parser<'a> { fn new(tokens: &'a [Token]) -> Self { Self { tokens, pos: 0 } } fn peek(&self) -> &Token { self.tokens.get(self.pos).unwrap_or(&Token::Eof) } fn advance(&mut self) -> &Token { let tok = self.tokens.get(self.pos).unwrap_or(&Token::Eof); if self.pos < self.tokens.len() { self.pos += 1; } tok } fn expect(&mut self, expected: &Token) -> CompileResult<()> { let tok = self.advance(); if tok == expected { Ok(()) } else { Err(CompileError::Parse { msg: format!("expected {:?}, got {:?}", expected, tok), }) } } fn expect_ident(&mut self) -> CompileResult { match self.advance().clone() { Token::Ident(s) => Ok(s), other => Err(CompileError::Parse { msg: format!("expected identifier, got {:?}", other), }), } } fn parse_program(&mut self) -> CompileResult> { let mut components = Vec::new(); while *self.peek() != Token::Eof { match self.peek() { Token::Component => { components.push(self.parse_component()?); } _ => { // Skip unknown top-level tokens self.advance(); } } } Ok(components) } fn parse_component(&mut self) -> CompileResult { self.expect(&Token::Component)?; let name = self.expect_ident()?; self.expect(&Token::LBrace)?; let mut props = Vec::new(); let mut state = Vec::new(); let mut methods = Vec::new(); let mut template = Template { nodes: Vec::new() }; loop { match self.peek().clone() { Token::RBrace => { self.advance(); break; } Token::Eof => break, Token::Props => { self.advance(); props = self.parse_prop_block()?; } Token::State => { self.advance(); state = self.parse_state_block()?; } Token::Fn => { methods.push(self.parse_method()?); } Token::Template => { self.advance(); // consume `template` template = self.parse_template_block()?; } _ => { self.advance(); // skip unknown } } } Ok(Component { name, props, state, methods, template }) } fn parse_prop_block(&mut self) -> CompileResult> { self.expect(&Token::LBrace)?; let mut props = Vec::new(); loop { match self.peek().clone() { Token::RBrace | Token::Eof => { self.advance(); break; } Token::Ident(name) => { self.advance(); self.expect(&Token::Colon)?; let type_name = self.parse_type_name()?; let default = if *self.peek() == Token::Eq { self.advance(); Some(self.parse_default_value()?) } else { None }; // Optional trailing comma/semicolon if matches!(self.peek(), Token::Comma | Token::Semicolon) { self.advance(); } props.push(PropDef { name, type_name, default }); } _ => { self.advance(); } } } Ok(props) } fn parse_state_block(&mut self) -> CompileResult> { self.expect(&Token::LBrace)?; let mut defs = Vec::new(); loop { match self.peek().clone() { Token::RBrace | Token::Eof => { self.advance(); break; } Token::Ident(name) => { self.advance(); self.expect(&Token::Colon)?; let type_name = self.parse_type_name()?; self.expect(&Token::Eq)?; let initial = self.parse_default_value()?; if matches!(self.peek(), Token::Comma | Token::Semicolon) { self.advance(); } defs.push(StateDef { name, type_name, initial }); } _ => { self.advance(); } } } Ok(defs) } fn parse_type_name(&mut self) -> CompileResult { let name = match self.peek().clone() { Token::Ident(s) => { self.advance(); s } other => return Err(CompileError::Parse { msg: format!("expected type name, got {:?}", other), }), }; // Check for array type [T] → already consumed base name, but array types // start with [ so this handles bare type names only Ok(name) } fn parse_default_value(&mut self) -> CompileResult { // Collect tokens until comma, semicolon, or next top-level item // We need to handle nested structures like Fn types, etc. let mut result = String::new(); let mut depth = 0i32; loop { match self.peek() { Token::Eof => break, Token::LParen | Token::LBrace | Token::LBracket => { depth += 1; let tok = self.advance(); result.push_str(&token_to_str(tok)); } Token::RParen | Token::RBrace | Token::RBracket => { if depth == 0 { break; } depth -= 1; let tok = self.advance(); result.push_str(&token_to_str(tok)); } Token::Comma | Token::Semicolon if depth == 0 => break, // These signal end of the value if at depth 0 Token::Ident(_) | Token::Props | Token::State | Token::Fn | Token::Template | Token::Component if depth == 0 => break, _ => { let tok = self.advance(); result.push_str(&token_to_str(tok)); result.push(' '); } } } Ok(result.trim().to_owned()) } fn parse_method(&mut self) -> CompileResult { self.expect(&Token::Fn)?; let name = self.expect_ident()?; self.expect(&Token::LParen)?; let mut params: Vec<(String, String)> = Vec::new(); loop { match self.peek().clone() { Token::RParen | Token::Eof => { self.advance(); break; } Token::Ident(pname) => { self.advance(); self.expect(&Token::Colon)?; let ptype = self.parse_type_name()?; params.push((pname, ptype)); if *self.peek() == Token::Comma { self.advance(); } } _ => { self.advance(); } } } self.expect(&Token::Arrow)?; let return_type = self.parse_type_name()?; // Read the method body between { } let body = self.read_block_raw()?; Ok(Method { name, params, return_type, body }) } /// Read everything between { and matching } as raw text. fn read_block_raw(&mut self) -> CompileResult { self.expect(&Token::LBrace)?; let mut result = String::new(); let mut depth = 1i32; loop { match self.peek() { Token::Eof => break, Token::LBrace => { depth += 1; self.advance(); result.push_str("{ "); } Token::RBrace => { depth -= 1; self.advance(); if depth == 0 { break; } result.push_str("} "); } tok => { result.push_str(&token_to_str(tok)); result.push(' '); self.advance(); } } } Ok(result.trim().to_owned()) } /// Parse the template block. At this point the lexer has already expanded /// the template into special tokens (LBrace/RBrace wrapping interpolations, /// LAngle/Ident for elements, etc.). fn parse_template_block(&mut self) -> CompileResult