#[cfg(test)] mod test; pub mod sys_call; pub mod tree_node; use crate::sys_call::System; use quick_error::quick_error; use std::io::SeekFrom; use sys_call::SysCall; use tokenizer::{ self, Tokenizer, TokenizerBuffer, token::{Keyword, Symbol, Token, TokenType}, }; use tree_node::*; pub trait Documentation { fn docs(&self) -> String; } #[macro_export] /// A macro to create a boxed value. macro_rules! boxed { ($e:expr) => { Box::new($e) }; } quick_error! { #[derive(Debug)] pub enum Error { TokenizerError(err: tokenizer::Error) { from() display("Tokenizer Error: {}", err) source(err) } UnexpectedToken(span: Span, token: Token) { display("Unexpected token: {}", token.token_type) } DuplicateIdentifier(span: Span, token: Token) { display("Duplicate identifier: {}", token.token_type) } InvalidSyntax(span: Span, reason: String) { display("Invalid syntax: {}", reason) } UnsupportedKeyword(span: Span, token: Token) { display("Unsupported keyword: {}", token.token_type) } UnexpectedEOF { display("Unexpected EOF") } } } impl From for lsp_types::Diagnostic { fn from(value: Error) -> Self { use Error::*; use lsp_types::*; match value { TokenizerError(e) => e.into(), UnexpectedToken(span, _) | DuplicateIdentifier(span, _) | InvalidSyntax(span, _) | UnsupportedKeyword(span, _) => Diagnostic { message: value.to_string(), severity: Some(DiagnosticSeverity::ERROR), range: span.into(), ..Default::default() }, UnexpectedEOF => Diagnostic { message: value.to_string(), severity: Some(DiagnosticSeverity::ERROR), ..Default::default() }, } } } macro_rules! self_matches_peek { ($self:ident, $pattern:pat) => { matches!($self.tokenizer.peek()?, Some(Token { token_type: $pattern, .. })) }; ($self:ident, $pattern:pat if $cond:expr) => { matches!($self.tokenizer.peek()?, Some(Token { token_type: $pattern, .. }) if $cond) }; } macro_rules! token_matches { ($token:ident, $pattern:pat) => { matches!($token.token_type, $pattern) }; ($token:expr, $pattern:pat) => { matches!($token.token_type, $pattern) }; ($token:ident, $pattern:pat if $cond:expr) => { matches!($token.token_type, $pattern if $cond) }; ($token:expr, $pattern:pat if $cond:expr) => { matches!($token.token_type, $pattern if $cond) }; } macro_rules! self_matches_current { ($self:ident, $pattern:pat) => { matches!($self.current_token, Some(Token { token_type: $pattern, .. })) }; ($self:ident, $pattern:pat if $cond:expr) => { matches!($self.current_token, Some(Token { token_type: $pattern, .. }) if $cond) }; } pub struct Parser<'a> { tokenizer: TokenizerBuffer<'a>, current_token: Option, pub errors: Vec, } impl<'a> Parser<'a> { pub fn new(tokenizer: Tokenizer<'a>) -> Self { Parser { tokenizer: TokenizerBuffer::new(tokenizer), current_token: None, errors: Vec::new(), } } /// Calculates a Span from a given Token reference. fn token_to_span(t: &Token) -> Span { let len = t.original_string.as_ref().map(|s| s.len()).unwrap_or(0); Span { start_line: t.line, start_col: t.column, end_line: t.line, end_col: t.column + len, } } fn current_span(&self) -> Span { self.current_token .as_ref() .map(Self::token_to_span) .unwrap_or(Span { start_line: 0, start_col: 0, end_line: 0, end_col: 0, }) } /// Helper to run a parsing closure and wrap the result in a Spanned struct fn spanned(&mut self, parser: F) -> Result, Error> where F: FnOnce(&mut Self) -> Result, { let start_token = if self.current_token.is_some() { self.current_token.clone() } else { self.tokenizer.peek()? }; let (start_line, start_col) = start_token .as_ref() .map(|t| (t.line, t.column)) .unwrap_or((1, 1)); let node = parser(self)?; let end_token = self.current_token.as_ref(); let (end_line, end_col) = end_token .map(|t| { let len = t.original_string.as_ref().map(|s| s.len()).unwrap_or(0); (t.line, t.column + len) }) .unwrap_or((start_line, start_col)); Ok(Spanned { span: Span { start_line, start_col, end_line, end_col, }, node, }) } fn synchronize(&mut self) -> Result<(), Error> { self.assign_next()?; while let Some(token) = &self.current_token { if token.token_type == TokenType::Symbol(Symbol::Semicolon) { self.assign_next()?; return Ok(()); } match token.token_type { TokenType::Keyword(Keyword::Fn) | TokenType::Keyword(Keyword::Let) | TokenType::Keyword(Keyword::If) | TokenType::Keyword(Keyword::While) | TokenType::Keyword(Keyword::Loop) | TokenType::Keyword(Keyword::Device) | TokenType::Keyword(Keyword::Return) => return Ok(()), _ => {} } self.assign_next()?; } Ok(()) } pub fn parse_all(&mut self) -> Result, Error> { let first_token = self.tokenizer.peek().unwrap_or(None); let (start_line, start_col) = first_token .as_ref() .map(|tok| (tok.line, tok.column)) .unwrap_or((1, 1)); let mut expressions = Vec::>::new(); loop { match self.tokenizer.peek() { Ok(None) => break, Err(e) => { self.errors.push(Error::TokenizerError(e)); break; } _ => {} } match self.parse() { Ok(Some(expression)) => { expressions.push(expression); } Ok(None) => break, Err(e) => { self.errors.push(e); if self.synchronize().is_err() { break; } } } } let end_token_opt = self.tokenizer.peek().unwrap_or(None); let (end_line, end_col) = end_token_opt .map(|tok| { let len = tok.original_string.as_ref().map(|s| s.len()).unwrap_or(0); (tok.line, tok.column + len) }) .unwrap_or((start_line, start_col)); let span = Span { start_line, end_line, start_col, end_col, }; Ok(Some(Expression::Block(Spanned { node: BlockExpression(expressions), span, }))) } pub fn parse(&mut self) -> Result>, Error> { self.assign_next()?; if self.current_token.is_none() { return Ok(None); } let expr = self.expression()?; if self_matches_peek!(self, TokenType::Symbol(Symbol::Semicolon)) { self.assign_next()?; } Ok(expr) } fn assign_next(&mut self) -> Result<(), Error> { self.current_token = self.tokenizer.next_token()?; Ok(()) } fn get_next(&mut self) -> Result, Error> { self.assign_next()?; Ok(self.current_token.as_ref()) } fn expression(&mut self) -> Result>, Error> { // Parse the Left Hand Side (unary/primary expression) let lhs = self.unary()?; let Some(lhs) = lhs else { return Ok(None); }; // Handle Postfix operators (Member Access, Method Call) immediately after unary let lhs = self.parse_postfix(lhs)?; // Handle Infix operators (Binary, Logical, Assignment) if self_matches_peek!( self, TokenType::Symbol(s) if s.is_operator() || s.is_comparison() || s.is_logical() || matches!(s, Symbol::Assign) ) { return Ok(Some(self.infix(lhs)?)); } else if self_matches_current!( self, TokenType::Symbol(s) if s.is_operator() || s.is_comparison() || s.is_logical() || matches!(s, Symbol::Assign) ) { self.tokenizer.seek(SeekFrom::Current(-1))?; return Ok(Some(self.infix(lhs)?)); } Ok(Some(lhs)) } /// Handles dot notation chains: x.y.z() fn parse_postfix( &mut self, mut lhs: Spanned, ) -> Result, Error> { loop { if self_matches_peek!(self, TokenType::Symbol(Symbol::Dot)) { self.assign_next()?; // consume Dot let identifier_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; let identifier_span = Self::token_to_span(identifier_token); let identifier = match identifier_token.token_type { TokenType::Identifier(ref id) => id.clone(), _ => { return Err(Error::UnexpectedToken( identifier_span, identifier_token.clone(), )); } }; // Check for Method Call '()' if self_matches_peek!(self, TokenType::Symbol(Symbol::LParen)) { // Method Call self.assign_next()?; // consume '(' let mut arguments = Vec::>::new(); while !token_matches!( self.get_next()?.ok_or(Error::UnexpectedEOF)?, TokenType::Symbol(Symbol::RParen) ) { let expression = self.expression()?.ok_or(Error::UnexpectedEOF)?; // Block expressions not allowed in args if let Expression::Block(_) = expression.node { return Err(Error::InvalidSyntax( self.current_span(), String::from("Block expressions are not allowed in method calls"), )); } arguments.push(expression); if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma)) && !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) { let next_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; return Err(Error::UnexpectedToken( Self::token_to_span(next_token), next_token.clone(), )); } if !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) { self.assign_next()?; } } // End span is the ')' let end_span = self.current_span(); let combined_span = Span { start_line: lhs.span.start_line, start_col: lhs.span.start_col, end_line: end_span.end_line, end_col: end_span.end_col, }; lhs = Spanned { span: combined_span, node: Expression::MethodCall(Spanned { span: combined_span, node: MethodCallExpression { object: boxed!(lhs), method: Spanned { span: identifier_span, node: identifier, }, arguments, }, }), }; } else { // Member Access let combined_span = Span { start_line: lhs.span.start_line, start_col: lhs.span.start_col, end_line: identifier_span.end_line, end_col: identifier_span.end_col, }; lhs = Spanned { span: combined_span, node: Expression::MemberAccess(Spanned { span: combined_span, node: MemberAccessExpression { object: boxed!(lhs), member: Spanned { span: identifier_span, node: identifier, }, }, }), }; } } else { break; } } Ok(lhs) } fn unary(&mut self) -> Result>, Error> { macro_rules! matches_keyword { ($keyword:expr, $($pattern:pat),+) => { matches!($keyword, $($pattern)|+) }; } let Some(current_token) = self.current_token.as_ref() else { return Ok(None); }; if token_matches!(current_token, TokenType::EOF) { return Ok(None); } let expr = match current_token.token_type { TokenType::Keyword(e) if matches_keyword!(e, Keyword::Enum) => { return Err(Error::UnsupportedKeyword( self.current_span(), current_token.clone(), )); } TokenType::Keyword(Keyword::Let) => Some(self.spanned(|p| p.declaration())?), TokenType::Keyword(Keyword::Device) => { let spanned_dev = self.spanned(|p| p.device())?; Some(Spanned { span: spanned_dev.span, node: Expression::DeviceDeclaration(spanned_dev), }) } TokenType::Keyword(Keyword::Const) => { let spanned_const = self.spanned(|p| p.const_declaration())?; Some(Spanned { span: spanned_const.span, node: Expression::ConstDeclaration(spanned_const), }) } TokenType::Keyword(Keyword::Fn) => { let spanned_fn = self.spanned(|p| p.function())?; Some(Spanned { span: spanned_fn.span, node: Expression::Function(spanned_fn), }) } TokenType::Keyword(Keyword::If) => { let spanned_if = self.spanned(|p| p.if_expression())?; Some(Spanned { span: spanned_if.span, node: Expression::If(spanned_if), }) } TokenType::Keyword(Keyword::Loop) => { let spanned_loop = self.spanned(|p| p.loop_expression())?; Some(Spanned { span: spanned_loop.span, node: Expression::Loop(spanned_loop), }) } TokenType::Keyword(Keyword::While) => { let spanned_while = self.spanned(|p| p.while_expression())?; Some(Spanned { span: spanned_while.span, node: Expression::While(spanned_while), }) } TokenType::Keyword(Keyword::Break) => { let span = self.current_span(); let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(next, TokenType::Symbol(Symbol::Semicolon)) { return Err(Error::UnexpectedToken( Self::token_to_span(next), next.clone(), )); } Some(Spanned { span, node: Expression::Break(span), }) } TokenType::Keyword(Keyword::Continue) => { let span = self.current_span(); let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(next, TokenType::Symbol(Symbol::Semicolon)) { return Err(Error::UnexpectedToken( Self::token_to_span(next), next.clone(), )); } Some(Spanned { span, node: Expression::Continue(span), }) } TokenType::Identifier(ref id) if SysCall::is_syscall(id) => { let spanned_call = self.spanned(|p| p.syscall())?; Some(Spanned { span: spanned_call.span, node: Expression::Syscall(spanned_call), }) } TokenType::Identifier(_) if self_matches_peek!(self, TokenType::Symbol(Symbol::LParen)) => { let spanned_invoke = self.spanned(|p| p.invocation())?; Some(Spanned { span: spanned_invoke.span, node: Expression::Invocation(spanned_invoke), }) } TokenType::Identifier(ref id) => { let span = self.current_span(); Some(Spanned { span, node: Expression::Variable(Spanned { span, node: id.clone(), }), }) } TokenType::Symbol(Symbol::LBrace) => { let spanned_block = self.spanned(|p| p.block())?; Some(Spanned { span: spanned_block.span, node: Expression::Block(spanned_block), }) } TokenType::Number(_) | TokenType::String(_) | TokenType::Boolean(_) => { let spanned_lit = self.spanned(|p| p.literal())?; Some(Spanned { span: spanned_lit.span, node: Expression::Literal(spanned_lit), }) } TokenType::Symbol(Symbol::LParen) => { self.spanned(|p| p.priority())?.node.map(|node| *node) } TokenType::Symbol(Symbol::Minus) => { let start_span = self.current_span(); self.assign_next()?; let inner_expr = self.unary()?.ok_or(Error::UnexpectedEOF)?; // NOTE: Unary negation can also have postfix applied to the inner expression // But generally -a.b parses as -(a.b), which is what parse_postfix ensures if called here. // However, we call parse_postfix on the RESULT of unary in expression(), so // `expression` sees `Negation`. `parse_postfix` doesn't apply to Negation node unless we allow it? // Actually, `x.y` binds tighter than `-`. `postfix` logic belongs inside `unary` logic or // `expression` logic. // If I have `-x.y`, standard precedence says `-(x.y)`. // `unary` returns `Negation(x)`. Then `expression` calls `postfix` on `Negation(x)`. // `postfix` loop runs on `Negation`. This implies `(-x).y`. This is usually WRONG. // `.` binds tighter than `-`. // So `unary` must call `postfix` on the *operand* of the negation. let inner_with_postfix = self.parse_postfix(inner_expr)?; let combined_span = Span { start_line: start_span.start_line, start_col: start_span.start_col, end_line: inner_with_postfix.span.end_line, end_col: inner_with_postfix.span.end_col, }; Some(Spanned { span: combined_span, node: Expression::Negation(boxed!(inner_with_postfix)), }) } TokenType::Symbol(Symbol::LogicalNot) => { let start_span = self.current_span(); self.assign_next()?; let inner_expr = self.unary()?.ok_or(Error::UnexpectedEOF)?; let inner_with_postfix = self.parse_postfix(inner_expr)?; let combined_span = Span { start_line: start_span.start_line, start_col: start_span.start_col, end_line: inner_with_postfix.span.end_line, end_col: inner_with_postfix.span.end_col, }; Some(Spanned { span: combined_span, node: Expression::Logical(Spanned { span: combined_span, node: LogicalExpression::Not(boxed!(inner_with_postfix)), }), }) } _ => { return Err(Error::UnexpectedToken( self.current_span(), current_token.clone(), )); } }; Ok(expr) } fn get_infix_child_node(&mut self) -> Result, Error> { let current_token = self.current_token.as_ref().ok_or(Error::UnexpectedEOF)?; let start_span = self.current_span(); let expr = match current_token.token_type { TokenType::Number(_) | TokenType::Boolean(_) => { let lit = self.spanned(|p| p.literal())?; Spanned { span: lit.span, node: Expression::Literal(lit), } } TokenType::Identifier(ref ident) if !self_matches_peek!(self, TokenType::Symbol(Symbol::LParen)) => { // This is a Variable. We need to check for Postfix operations on it. let span = self.current_span(); Spanned { span, node: Expression::Variable(Spanned { span, node: ident.clone(), }), } } TokenType::Symbol(Symbol::LParen) => *self .spanned(|p| p.priority())? .node .ok_or(Error::UnexpectedEOF)?, TokenType::Identifier(_) if self_matches_peek!(self, TokenType::Symbol(Symbol::LParen)) => { let inv = self.spanned(|p| p.invocation())?; Spanned { span: inv.span, node: Expression::Invocation(inv), } } TokenType::Symbol(Symbol::Minus) => { self.assign_next()?; let inner = self.get_infix_child_node()?; let span = Span { start_line: start_span.start_line, start_col: start_span.start_col, end_line: inner.span.end_line, end_col: inner.span.end_col, }; Spanned { span, node: Expression::Negation(boxed!(inner)), } } TokenType::Symbol(Symbol::LogicalNot) => { self.assign_next()?; let inner = self.get_infix_child_node()?; let span = Span { start_line: start_span.start_line, start_col: start_span.start_col, end_line: inner.span.end_line, end_col: inner.span.end_col, }; Spanned { span, node: Expression::Logical(Spanned { span, node: LogicalExpression::Not(boxed!(inner)), }), } } _ => { return Err(Error::UnexpectedToken( self.current_span(), current_token.clone(), )); } }; // Important: We must check for postfix operations here too // e.g. a + b.c self.parse_postfix(expr) } fn device(&mut self) -> Result { let current_token = self.current_token.as_ref().ok_or(Error::UnexpectedEOF)?; if !self_matches_current!(self, TokenType::Keyword(Keyword::Device)) { return Err(Error::UnexpectedToken( self.current_span(), current_token.clone(), )); } let identifier_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; let identifier_span = Self::token_to_span(identifier_token); let identifier = match identifier_token.token_type { TokenType::Identifier(ref id) => id.clone(), _ => { return Err(Error::UnexpectedToken( Self::token_to_span(identifier_token), identifier_token.clone(), )); } }; let current_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(current_token, TokenType::Symbol(Symbol::Assign)) { return Err(Error::UnexpectedToken( Self::token_to_span(current_token), current_token.clone(), )); } let device_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; let device = match device_token.token_type { TokenType::String(ref id) => id.clone(), _ => { return Err(Error::UnexpectedToken( Self::token_to_span(device_token), device_token.clone(), )); } }; Ok(DeviceDeclarationExpression { name: Spanned { span: identifier_span, node: identifier, }, device, }) } fn infix(&mut self, previous: Spanned) -> Result, Error> { let current_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?.clone(); match previous.node { Expression::Binary(_) | Expression::Logical(_) | Expression::Invocation(_) | Expression::Priority(_) | Expression::Literal(_) | Expression::Variable(_) | Expression::Negation(_) | Expression::MemberAccess(_) | Expression::MethodCall(_) => {} _ => { return Err(Error::InvalidSyntax( self.current_span(), String::from("Invalid expression for binary/logical operation"), )); } } let mut expressions = vec![previous]; let mut operators = Vec::::new(); let mut temp_token = current_token.clone(); // Include Assign in the operator loop while token_matches!( temp_token, TokenType::Symbol(s) if s.is_operator() || s.is_comparison() || s.is_logical() || matches!(s, Symbol::Assign) ) { let operator = match temp_token.token_type { TokenType::Symbol(s) => s, _ => unreachable!(), }; operators.push(operator); self.assign_next()?; expressions.push(self.get_infix_child_node()?); temp_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?.clone(); } if operators.len() != expressions.len() - 1 { return Err(Error::InvalidSyntax( self.current_span(), String::from("Invalid number of operators"), )); } // --- PRECEDENCE LEVEL 1: Exponent (**) --- for (i, operator) in operators.iter().enumerate().rev() { if operator == &Symbol::Exp { let right = expressions.remove(i + 1); let left = expressions.remove(i); let span = Span { start_line: left.span.start_line, start_col: left.span.start_col, end_line: right.span.end_line, end_col: right.span.end_col, }; expressions.insert( i, Spanned { span, node: Expression::Binary(Spanned { span, node: BinaryExpression::Exponent(boxed!(left), boxed!(right)), }), }, ); } } operators.retain(|symbol| symbol != &Symbol::Exp); // Common macro for binary ops macro_rules! process_binary_ops { ($ops:pat, $variant:ident) => { let mut current_iteration = 0; for (i, operator) in operators.iter().enumerate() { if matches!(operator, $ops) { let index = i - current_iteration; let left = expressions.remove(index); let right = expressions.remove(index); let span = Span { start_line: left.span.start_line, start_col: left.span.start_col, end_line: right.span.end_line, end_col: right.span.end_col, }; let node = match operator { Symbol::Asterisk => { BinaryExpression::Multiply(boxed!(left), boxed!(right)) } Symbol::Slash => BinaryExpression::Divide(boxed!(left), boxed!(right)), Symbol::Percent => { BinaryExpression::Modulo(boxed!(left), boxed!(right)) } Symbol::Plus => BinaryExpression::Add(boxed!(left), boxed!(right)), Symbol::Minus => { BinaryExpression::Subtract(boxed!(left), boxed!(right)) } _ => unreachable!(), }; expressions.insert( index, Spanned { span, node: Expression::Binary(Spanned { span, node }), }, ); current_iteration += 1; } } operators.retain(|symbol| !matches!(symbol, $ops)); }; } // --- PRECEDENCE LEVEL 2: Multiplicative (*, /, %) --- process_binary_ops!( Symbol::Slash | Symbol::Asterisk | Symbol::Percent, BinaryExpression ); // --- PRECEDENCE LEVEL 3: Additive (+, -) --- process_binary_ops!(Symbol::Plus | Symbol::Minus, BinaryExpression); // --- PRECEDENCE LEVEL 4: Comparison (<, >, <=, >=) --- let mut current_iteration = 0; for (i, operator) in operators.iter().enumerate() { if operator.is_comparison() && !matches!(operator, Symbol::Equal | Symbol::NotEqual) { let index = i - current_iteration; let left = expressions.remove(index); let right = expressions.remove(index); let span = Span { start_line: left.span.start_line, start_col: left.span.start_col, end_line: right.span.end_line, end_col: right.span.end_col, }; let node = match operator { Symbol::LessThan => LogicalExpression::LessThan(boxed!(left), boxed!(right)), Symbol::GreaterThan => { LogicalExpression::GreaterThan(boxed!(left), boxed!(right)) } Symbol::LessThanOrEqual => { LogicalExpression::LessThanOrEqual(boxed!(left), boxed!(right)) } Symbol::GreaterThanOrEqual => { LogicalExpression::GreaterThanOrEqual(boxed!(left), boxed!(right)) } _ => unreachable!(), }; expressions.insert( index, Spanned { span, node: Expression::Logical(Spanned { span, node }), }, ); current_iteration += 1; } } operators.retain(|symbol| { !symbol.is_comparison() || matches!(symbol, Symbol::Equal | Symbol::NotEqual) }); // --- PRECEDENCE LEVEL 5: Equality (==, !=) --- current_iteration = 0; for (i, operator) in operators.iter().enumerate() { if matches!(operator, Symbol::Equal | Symbol::NotEqual) { let index = i - current_iteration; let left = expressions.remove(index); let right = expressions.remove(index); let span = Span { start_line: left.span.start_line, start_col: left.span.start_col, end_line: right.span.end_line, end_col: right.span.end_col, }; let node = match operator { Symbol::Equal => LogicalExpression::Equal(boxed!(left), boxed!(right)), Symbol::NotEqual => LogicalExpression::NotEqual(boxed!(left), boxed!(right)), _ => unreachable!(), }; expressions.insert( index, Spanned { span, node: Expression::Logical(Spanned { span, node }), }, ); current_iteration += 1; } } operators.retain(|symbol| !matches!(symbol, Symbol::Equal | Symbol::NotEqual)); // --- PRECEDENCE LEVEL 6: Logical AND (&&) --- current_iteration = 0; for (i, operator) in operators.iter().enumerate() { if matches!(operator, Symbol::LogicalAnd) { let index = i - current_iteration; let left = expressions.remove(index); let right = expressions.remove(index); let span = Span { start_line: left.span.start_line, start_col: left.span.start_col, end_line: right.span.end_line, end_col: right.span.end_col, }; expressions.insert( index, Spanned { span, node: Expression::Logical(Spanned { span, node: LogicalExpression::And(boxed!(left), boxed!(right)), }), }, ); current_iteration += 1; } } operators.retain(|symbol| !matches!(symbol, Symbol::LogicalAnd)); // --- PRECEDENCE LEVEL 7: Logical OR (||) --- current_iteration = 0; for (i, operator) in operators.iter().enumerate() { if matches!(operator, Symbol::LogicalOr) { let index = i - current_iteration; let left = expressions.remove(index); let right = expressions.remove(index); let span = Span { start_line: left.span.start_line, start_col: left.span.start_col, end_line: right.span.end_line, end_col: right.span.end_col, }; expressions.insert( index, Spanned { span, node: Expression::Logical(Spanned { span, node: LogicalExpression::Or(boxed!(left), boxed!(right)), }), }, ); current_iteration += 1; } } operators.retain(|symbol| !matches!(symbol, Symbol::LogicalOr)); // --- PRECEDENCE LEVEL 8: Assignment (=) --- // Assignment is Right Associative: a = b = c => a = (b = c) // We iterate Right to Left for (i, operator) in operators.iter().enumerate().rev() { if matches!(operator, Symbol::Assign) { let right = expressions.remove(i + 1); let left = expressions.remove(i); let span = Span { start_line: left.span.start_line, start_col: left.span.start_col, end_line: right.span.end_line, end_col: right.span.end_col, }; expressions.insert( i, Spanned { span, node: Expression::Assignment(Spanned { span, node: AssignmentExpression { assignee: boxed!(left), expression: boxed!(right), }, }), }, ); } } operators.retain(|symbol| !matches!(symbol, Symbol::Assign)); if expressions.len() != 1 || !operators.is_empty() { return Err(Error::InvalidSyntax( self.current_span(), String::from("Invalid number of operators"), )); } if token_matches!( temp_token, TokenType::Symbol(Symbol::Semicolon) | TokenType::Symbol(Symbol::RParen) ) { self.tokenizer.seek(SeekFrom::Current(-1))?; } expressions.pop().ok_or(Error::UnexpectedEOF) } fn priority(&mut self) -> Result>>, Error> { let current_token = self.current_token.as_ref().ok_or(Error::UnexpectedEOF)?; if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) { return Err(Error::UnexpectedToken( self.current_span(), current_token.clone(), )); } self.assign_next()?; let expression = self.expression()?.ok_or(Error::UnexpectedEOF)?; let current_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(current_token, TokenType::Symbol(Symbol::RParen)) { return Err(Error::UnexpectedToken( Self::token_to_span(current_token), current_token.clone(), )); } Ok(Some(boxed!(expression))) } fn invocation(&mut self) -> Result { let identifier_token = self.current_token.as_ref().ok_or(Error::UnexpectedEOF)?; let identifier_span = Self::token_to_span(identifier_token); let identifier = match identifier_token.token_type { TokenType::Identifier(ref id) => id.clone(), _ => { return Err(Error::UnexpectedToken( self.current_span(), self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )); } }; let current_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) { return Err(Error::UnexpectedToken( Self::token_to_span(current_token), current_token.clone(), )); } let mut arguments = Vec::>::new(); while !token_matches!( self.get_next()?.ok_or(Error::UnexpectedEOF)?, TokenType::Symbol(Symbol::RParen) ) { let expression = self.expression()?.ok_or(Error::UnexpectedEOF)?; if let Expression::Block(_) = expression.node { return Err(Error::InvalidSyntax( self.current_span(), String::from("Block expressions are not allowed in function invocations"), )); } arguments.push(expression); if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma)) && !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) { let next_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; return Err(Error::UnexpectedToken( Self::token_to_span(next_token), next_token.clone(), )); } if !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) { self.assign_next()?; } } Ok(InvocationExpression { name: Spanned { span: identifier_span, node: identifier, }, arguments, }) } fn block(&mut self) -> Result { let mut expressions = Vec::>::new(); let current_token = self.current_token.as_ref().ok_or(Error::UnexpectedEOF)?; if !token_matches!(current_token, TokenType::Symbol(Symbol::LBrace)) { return Err(Error::UnexpectedToken( self.current_span(), current_token.clone(), )); } while !self_matches_peek!( self, TokenType::Symbol(Symbol::RBrace) | TokenType::Keyword(Keyword::Return) ) { let expression = self.parse()?.ok_or(Error::UnexpectedEOF)?; expressions.push(expression); } let current_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if token_matches!(current_token, TokenType::Keyword(Keyword::Return)) { // Need to capture return span let ret_start_span = Self::token_to_span(current_token); self.assign_next()?; let expression = self.expression()?.ok_or(Error::UnexpectedEOF)?; let ret_span = Span { start_line: ret_start_span.start_line, start_col: ret_start_span.start_col, end_line: expression.span.end_line, end_col: expression.span.end_col, }; let return_expr = Spanned { span: ret_span, node: Expression::Return(boxed!(expression)), }; expressions.push(return_expr); let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(next, TokenType::Symbol(Symbol::Semicolon)) { return Err(Error::UnexpectedToken( Self::token_to_span(next), next.clone(), )); } let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(next, TokenType::Symbol(Symbol::RBrace)) { return Err(Error::UnexpectedToken( Self::token_to_span(next), next.clone(), )); } } Ok(BlockExpression(expressions)) } fn const_declaration(&mut self) -> Result { // const let current_token = self.current_token.as_ref().ok_or(Error::UnexpectedEOF)?; if !self_matches_current!(self, TokenType::Keyword(Keyword::Const)) { return Err(Error::UnexpectedToken( self.current_span(), current_token.clone(), )); } // variable_name let ident_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; let ident_span = Self::token_to_span(ident_token); let ident = match ident_token.token_type { TokenType::Identifier(ref id) => id.clone(), _ => return Err(Error::UnexpectedToken(ident_span, ident_token.clone())), }; // `=` let assign_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?.clone(); if !token_matches!(assign_token, TokenType::Symbol(Symbol::Assign)) { return Err(Error::UnexpectedToken( Self::token_to_span(&assign_token), assign_token, )); } // literal value self.assign_next()?; let lit = self.spanned(|p| p.literal())?; Ok(ConstDeclarationExpression { name: Spanned { span: ident_span, node: ident, }, value: lit, }) } fn declaration(&mut self) -> Result { let current_token = self.current_token.as_ref().ok_or(Error::UnexpectedEOF)?; if !self_matches_current!(self, TokenType::Keyword(Keyword::Let)) { return Err(Error::UnexpectedToken( self.current_span(), current_token.clone(), )); } let identifier_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; let identifier_span = Self::token_to_span(identifier_token); let identifier = match identifier_token.token_type { TokenType::Identifier(ref id) => id.clone(), _ => { return Err(Error::UnexpectedToken( Self::token_to_span(identifier_token), identifier_token.clone(), )); } }; let current_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?.clone(); if !token_matches!(current_token, TokenType::Symbol(Symbol::Assign)) { return Err(Error::UnexpectedToken( Self::token_to_span(¤t_token), current_token.clone(), )); } self.assign_next()?; let assignment_expression = self.expression()?.ok_or(Error::UnexpectedEOF)?; let current_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(current_token, TokenType::Symbol(Symbol::Semicolon)) { return Err(Error::UnexpectedToken( Self::token_to_span(current_token), current_token.clone(), )); } Ok(Expression::Declaration( Spanned { span: identifier_span, node: identifier, }, boxed!(assignment_expression), )) } fn literal(&mut self) -> Result { let current_token = self.current_token.as_ref().ok_or(Error::UnexpectedEOF)?; let literal = match current_token.token_type { TokenType::Number(num) => Literal::Number(num), TokenType::String(ref string) => Literal::String(string.clone()), TokenType::Boolean(boolean) => Literal::Boolean(boolean), _ => { return Err(Error::UnexpectedToken( self.current_span(), current_token.clone(), )); } }; Ok(literal) } fn if_expression(&mut self) -> Result { // 'if' is current let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(next, TokenType::Symbol(Symbol::LParen)) { return Err(Error::UnexpectedToken( Self::token_to_span(next), next.clone(), )); } self.assign_next()?; let condition = self.expression()?.ok_or(Error::UnexpectedEOF)?; let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(next, TokenType::Symbol(Symbol::RParen)) { return Err(Error::UnexpectedToken( Self::token_to_span(next), next.clone(), )); } let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(next, TokenType::Symbol(Symbol::LBrace)) { return Err(Error::UnexpectedToken( Self::token_to_span(next), next.clone(), )); } let body = self.spanned(|p| p.block())?; let else_branch = if self_matches_peek!(self, TokenType::Keyword(Keyword::Else)) { self.assign_next()?; if self_matches_peek!(self, TokenType::Keyword(Keyword::If)) { self.assign_next()?; // Recurse for else if let if_expr = self.spanned(|p| p.if_expression())?; Some(boxed!(Spanned { span: if_expr.span, node: Expression::If(if_expr), })) } else if self_matches_peek!(self, TokenType::Symbol(Symbol::LBrace)) { self.assign_next()?; let block = self.spanned(|p| p.block())?; Some(boxed!(Spanned { span: block.span, node: Expression::Block(block), })) } else { let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; return Err(Error::UnexpectedToken( Self::token_to_span(next), next.clone(), )); } } else { None }; Ok(IfExpression { condition: boxed!(condition), body, else_branch, }) } fn loop_expression(&mut self) -> Result { let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(next, TokenType::Symbol(Symbol::LBrace)) { return Err(Error::UnexpectedToken( Self::token_to_span(next), next.clone(), )); } let body = self.spanned(|p| p.block())?; Ok(LoopExpression { body }) } fn while_expression(&mut self) -> Result { let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(next, TokenType::Symbol(Symbol::LParen)) { return Err(Error::UnexpectedToken( Self::token_to_span(next), next.clone(), )); } self.assign_next()?; let condition = self.expression()?.ok_or(Error::UnexpectedEOF)?; let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(next, TokenType::Symbol(Symbol::RParen)) { return Err(Error::UnexpectedToken( Self::token_to_span(next), next.clone(), )); } let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(next, TokenType::Symbol(Symbol::LBrace)) { return Err(Error::UnexpectedToken( Self::token_to_span(next), next.clone(), )); } let body = self.block()?; Ok(WhileExpression { condition: boxed!(condition), body, }) } fn function(&mut self) -> Result { // 'fn' is current let fn_ident_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; let fn_ident_span = Self::token_to_span(fn_ident_token); let fn_ident = match fn_ident_token.token_type { TokenType::Identifier(ref id) => id.clone(), _ => { return Err(Error::UnexpectedToken( Self::token_to_span(fn_ident_token), fn_ident_token.clone(), )); } }; let current_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) { return Err(Error::UnexpectedToken( Self::token_to_span(current_token), current_token.clone(), )); } let mut arguments = Vec::>::new(); while !token_matches!( self.get_next()?.ok_or(Error::UnexpectedEOF)?, TokenType::Symbol(Symbol::RParen) ) { let current_token = self.current_token.as_ref().ok_or(Error::UnexpectedEOF)?; let arg_span = Self::token_to_span(current_token); let argument = match current_token.token_type { TokenType::Identifier(ref id) => id.clone(), _ => { return Err(Error::UnexpectedToken( Self::token_to_span(current_token), current_token.clone(), )); } }; let spanned_arg = Spanned { span: arg_span, node: argument, }; if arguments.contains(&spanned_arg) { return Err(Error::DuplicateIdentifier( Self::token_to_span(current_token), current_token.clone(), )); } arguments.push(spanned_arg); if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma)) && !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) { let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; return Err(Error::UnexpectedToken( Self::token_to_span(next), next.clone(), )); } if !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) { self.assign_next()?; } } let current_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; if !token_matches!(current_token, TokenType::Symbol(Symbol::LBrace)) { return Err(Error::UnexpectedToken( Self::token_to_span(current_token), current_token.clone(), )); }; Ok(FunctionExpression { name: Spanned { span: fn_ident_span, node: fn_ident, }, arguments, body: self.block()?, }) } fn syscall(&mut self) -> Result { fn check_length( parser: &Parser, arguments: &[Spanned], length: usize, ) -> Result<(), Error> { if arguments.len() != length { return Err(Error::InvalidSyntax( parser.current_span(), format!("Expected {} arguments", length), )); } Ok(()) } macro_rules! literal_or_variable { ($iter:expr) => { match $iter { Some(expr) => match &expr.node { Expression::Literal(literal) => { LiteralOrVariable::Literal(literal.node.clone()) } Expression::Variable(ident) => LiteralOrVariable::Variable(ident.clone()), _ => { return Err(Error::UnexpectedToken( self.current_span(), self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )) } }, _ => { return Err(Error::UnexpectedToken( self.current_span(), self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )) } } }; } macro_rules! get_arg { ($matcher: ident, $arg: expr) => { match $arg { LiteralOrVariable::$matcher(i) => i, _ => { return Err(Error::InvalidSyntax( self.current_span(), String::from("Expected a variable"), )) } } }; } let invocation = self.invocation()?; match invocation.name.node.as_str() { "yield" => { check_length(self, &invocation.arguments, 0)?; Ok(SysCall::System(sys_call::System::Yield)) } "sleep" => { check_length(self, &invocation.arguments, 1)?; let mut arg = invocation.arguments.into_iter(); let expr = arg.next().ok_or(Error::UnexpectedEOF)?; Ok(SysCall::System(System::Sleep(boxed!(expr)))) } "hash" => { check_length(self, &invocation.arguments, 1)?; let mut args = invocation.arguments.into_iter(); let lit_str = literal_or_variable!(args.next()); let LiteralOrVariable::Literal(lit_str) = lit_str else { return Err(Error::UnexpectedToken( self.current_span(), self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )); }; Ok(SysCall::System(System::Hash(lit_str))) } "loadFromDevice" => { check_length(self, &invocation.arguments, 2)?; let mut args = invocation.arguments.into_iter(); let device = literal_or_variable!(args.next()); let next_arg = args.next(); let variable = match next_arg { Some(expr) => match expr.node { Expression::Literal(spanned_lit) => match spanned_lit.node { Literal::String(s) => s, _ => { return Err(Error::UnexpectedToken( self.current_span(), self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )); } }, _ => { return Err(Error::UnexpectedToken( self.current_span(), self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )); } }, _ => { return Err(Error::UnexpectedToken( self.current_span(), self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )); } }; Ok(SysCall::System(sys_call::System::LoadFromDevice( device, Literal::String(variable), ))) } "setOnDevice" => { check_length(self, &invocation.arguments, 3)?; let mut args = invocation.arguments.into_iter(); let device = literal_or_variable!(args.next()); let logic_type = get_arg!(Literal, literal_or_variable!(args.next())); let variable = args.next().ok_or(Error::UnexpectedEOF)?; Ok(SysCall::System(sys_call::System::SetOnDevice( device, Literal::String(logic_type.to_string().replace("\"", "")), boxed!(variable), ))) } "setOnDeviceBatched" => { check_length(self, &invocation.arguments, 3)?; let mut args = invocation.arguments.into_iter(); let device_hash = literal_or_variable!(args.next()); let logic_type = get_arg!(Literal, literal_or_variable!(args.next())); let variable = args.next().ok_or(Error::UnexpectedEOF)?; Ok(SysCall::System(sys_call::System::SetOnDeviceBatched( device_hash, Literal::String(logic_type.to_string().replace("\"", "")), boxed!(variable), ))) } _ => Err(Error::UnsupportedKeyword( self.current_span(), self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )), } } }