diff --git a/2 b/2 new file mode 100644 index 0000000..18f06ed --- /dev/null +++ b/2 @@ -0,0 +1,1553 @@ +#[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::*; + +#[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. + /// This is a static helper to avoid borrowing `self` when we already have a token ref. + 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, + { + // Peek at the start token. If no current token (parsing hasn't started), peek the buffer. + 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)?; + + // The end token is the current_token after parsing. + 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, + }) + } + + /// Skips tokens until a statement boundary is found to recover from errors. + fn synchronize(&mut self) -> Result<(), Error> { + // We advance once to consume the error-causing token if we haven't already + // But often the error happens after we consumed something. + // Safe bet: consume current, then look. + + // If we assign next, we might be skipping the very token we want to sync on if the error didn't consume it? + // Usually, in recursive descent, the error is raised when `current` is unexpected. + // We want to discard `current` and move on. + self.assign_next()?; + + while let Some(token) = &self.current_token { + if token.token_type == TokenType::Symbol(Symbol::Semicolon) { + // Consuming the semicolon is a good place to stop and resume parsing next statement + self.assign_next()?; + return Ok(()); + } + + // Check if the token looks like the start of a statement. + // If so, we don't consume it; we return so the loop in parse_all can try to parse it. + 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 { + // Check EOF without unwrapping error + 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); + // Recover + if self.synchronize().is_err() { + // If sync failed (e.g. EOF during sync), break + break; + } + } + } + } + + // Even if we had errors, we return whatever partial AST we managed to build. + // If expressions is empty and we had errors, it's a failed parse, but we return a block. + + // Use the last token position for end span, or start if nothing parsed + 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 assign_next hit EOF or error? + 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); + }; + + // check if the next or current token is an operator, comparison, or logical symbol + if self_matches_peek!( + self, + TokenType::Symbol(s) if s.is_operator() || s.is_comparison() || s.is_logical() + ) { + 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() + ) { + self.tokenizer.seek(SeekFrom::Current(-1))?; + return Ok(Some(self.infix(lhs)?)); + } + + Ok(Some(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) => { + // declaration is wrapped in spanned inside the function, but expects 'let' to be current + 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::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(); + // make sure the next token is a semi-colon + 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(_) + if self_matches_peek!(self, TokenType::Symbol(Symbol::Assign)) => + { + let spanned_assign = self.spanned(|p| p.assignment())?; + Some(Spanned { + span: spanned_assign.span, + node: Expression::Assignment(spanned_assign), + }) + } + + 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) => { + // Priority handles its own spanning + self.spanned(|p| p.priority())?.node.map(|node| *node) + } + + TokenType::Symbol(Symbol::Minus) => { + // Need to handle span manually because unary call is next + let start_span = self.current_span(); + self.assign_next()?; + let inner_expr = self.unary()?.ok_or(Error::UnexpectedEOF)?; + let combined_span = Span { + start_line: start_span.start_line, + start_col: start_span.start_col, + end_line: inner_expr.span.end_line, + end_col: inner_expr.span.end_col, + }; + Some(Spanned { + span: combined_span, + node: Expression::Negation(boxed!(inner_expr)), + }) + } + + TokenType::Symbol(Symbol::LogicalNot) => { + let start_span = self.current_span(); + self.assign_next()?; + let inner_expr = self.unary()?.ok_or(Error::UnexpectedEOF)?; + let combined_span = Span { + start_line: start_span.start_line, + start_col: start_span.start_col, + end_line: inner_expr.span.end_line, + end_col: inner_expr.span.end_col, + }; + Some(Spanned { + span: combined_span, + node: Expression::Logical(Spanned { + span: combined_span, + node: LogicalExpression::Not(boxed!(inner_expr)), + }), + }) + } + + _ => { + 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)?; + + match current_token.token_type { + TokenType::Number(_) | TokenType::Boolean(_) => { + let lit = self.spanned(|p| p.literal())?; + Ok(Spanned { + span: lit.span, + node: Expression::Literal(lit), + }) + } + TokenType::Identifier(ref ident) + if !self_matches_peek!(self, TokenType::Symbol(Symbol::LParen)) => + { + let span = self.current_span(); + Ok(Spanned { + span, + node: Expression::Variable(Spanned { + span, + node: ident.clone(), + }), + }) + } + TokenType::Symbol(Symbol::LParen) => Ok(*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())?; + Ok(Spanned { + span: inv.span, + node: Expression::Invocation(inv), + }) + } + TokenType::Symbol(Symbol::Minus) => { + let start_span = self.current_span(); + 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, + }; + Ok(Spanned { + span, + node: Expression::Negation(boxed!(inner)), + }) + } + TokenType::Symbol(Symbol::LogicalNot) => { + let start_span = self.current_span(); + 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, + }; + Ok(Spanned { + span, + node: Expression::Logical(Spanned { + span, + node: LogicalExpression::Not(boxed!(inner)), + }), + }) + } + _ => Err(Error::UnexpectedToken( + self.current_span(), + current_token.clone(), + )), + } + } + + 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 assignment(&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)?.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 expression = self.expression()?.ok_or(Error::UnexpectedEOF)?; + + Ok(AssignmentExpression { + identifier: Spanned { + span: identifier_span, + node: identifier, + }, + expression: boxed!(expression), + }) + } + + 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(_) => {} + _ => { + 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(); + + while token_matches!( + temp_token, + TokenType::Symbol(s) if s.is_operator() || s.is_comparison() || s.is_logical() + ) { + 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)); + + 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().unwrap(); + 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()?.unwrap(); + 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 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()?.unwrap(); + 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().unwrap(); + 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), + ))) + } + // ... (implementing other syscalls similarly using patterns above) + "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), + ))) + } + _ => { + // For Math functions or unknown functions + if SysCall::is_syscall(&invocation.name.node) { + // Attempt to parse as math if applicable, or error if strict + // Here we are falling back to simple handling or error. + // Since Math isn't fully expanded in this snippet, we return Unsupported. + Err(Error::UnsupportedKeyword( + self.current_span(), + self.current_token.clone().ok_or(Error::UnexpectedEOF)?, + )) + } else { + Err(Error::UnsupportedKeyword( + self.current_span(), + self.current_token.clone().ok_or(Error::UnexpectedEOF)?, + )) + } + } + } + } +} diff --git a/rust_compiler/libs/parser/src/lib.rs b/rust_compiler/libs/parser/src/lib.rs index d82ec44..bf5217e 100644 --- a/rust_compiler/libs/parser/src/lib.rs +++ b/rust_compiler/libs/parser/src/lib.rs @@ -563,7 +563,10 @@ impl<'a> Parser<'a> { }), }) } - TokenType::Symbol(Symbol::LParen) => Ok(*self.spanned(|p| p.priority())?.node.unwrap()), + TokenType::Symbol(Symbol::LParen) => Ok(*self + .spanned(|p| p.priority())? + .node + .ok_or(Error::UnexpectedEOF)?), TokenType::Identifier(_) if self_matches_peek!(self, TokenType::Symbol(Symbol::LParen)) => { @@ -663,14 +666,14 @@ impl<'a> Parser<'a> { } fn assignment(&mut self) -> Result { - let identifier_token = self.current_token.as_ref().unwrap(); + 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().unwrap(), + self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )); } }; @@ -966,7 +969,7 @@ impl<'a> Parser<'a> { self.tokenizer.seek(SeekFrom::Current(-1))?; } - Ok(expressions.pop().unwrap()) + expressions.pop().ok_or(Error::UnexpectedEOF) } fn priority(&mut self) -> Result>>, Error> { @@ -993,14 +996,14 @@ impl<'a> Parser<'a> { } fn invocation(&mut self) -> Result { - let identifier_token = self.current_token.as_ref().unwrap(); + 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().unwrap(), + self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )); } }; @@ -1033,7 +1036,7 @@ impl<'a> Parser<'a> { if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma)) && !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) { - let next_token = self.get_next()?.unwrap(); + let next_token = self.get_next()?.ok_or(Error::UnexpectedEOF)?; return Err(Error::UnexpectedToken( Self::token_to_span(next_token), next_token.clone(), @@ -1230,7 +1233,7 @@ impl<'a> Parser<'a> { node: Expression::Block(block), })) } else { - let next = self.get_next()?.unwrap(); + let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; return Err(Error::UnexpectedToken( Self::token_to_span(next), next.clone(), @@ -1325,7 +1328,7 @@ impl<'a> Parser<'a> { self.get_next()?.ok_or(Error::UnexpectedEOF)?, TokenType::Symbol(Symbol::RParen) ) { - let current_token = self.current_token.as_ref().unwrap(); + 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(), @@ -1354,7 +1357,7 @@ impl<'a> Parser<'a> { if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma)) && !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) { - let next = self.get_next()?.unwrap(); + let next = self.get_next()?.ok_or(Error::UnexpectedEOF)?; return Err(Error::UnexpectedToken( Self::token_to_span(next), next.clone(), @@ -1410,14 +1413,14 @@ impl<'a> Parser<'a> { _ => { return Err(Error::UnexpectedToken( self.current_span(), - self.current_token.clone().unwrap(), + self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )) } }, _ => { return Err(Error::UnexpectedToken( self.current_span(), - self.current_token.clone().unwrap(), + self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )) } } @@ -1448,7 +1451,7 @@ impl<'a> Parser<'a> { "sleep" => { check_length(self, &invocation.arguments, 1)?; let mut arg = invocation.arguments.into_iter(); - let expr = arg.next().unwrap(); + let expr = arg.next().ok_or(Error::UnexpectedEOF)?; Ok(SysCall::System(System::Sleep(boxed!(expr)))) } "hash" => { @@ -1459,7 +1462,7 @@ impl<'a> Parser<'a> { let LiteralOrVariable::Literal(lit_str) = lit_str else { return Err(Error::UnexpectedToken( self.current_span(), - self.current_token.clone().unwrap(), + self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )); }; @@ -1479,21 +1482,21 @@ impl<'a> Parser<'a> { _ => { return Err(Error::UnexpectedToken( self.current_span(), - self.current_token.clone().unwrap(), + self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )); } }, _ => { return Err(Error::UnexpectedToken( self.current_span(), - self.current_token.clone().unwrap(), + self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )); } }, _ => { return Err(Error::UnexpectedToken( self.current_span(), - self.current_token.clone().unwrap(), + self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )); } }; @@ -1509,7 +1512,7 @@ impl<'a> Parser<'a> { 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().unwrap(); + let variable = args.next().ok_or(Error::UnexpectedEOF)?; Ok(SysCall::System(sys_call::System::SetOnDevice( device, Literal::String(logic_type.to_string().replace("\"", "")), @@ -1521,7 +1524,7 @@ impl<'a> Parser<'a> { 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().unwrap(); + let variable = args.next().ok_or(Error::UnexpectedEOF)?; Ok(SysCall::System(sys_call::System::SetOnDeviceBatched( device_hash, Literal::String(logic_type.to_string().replace("\"", "")), @@ -1536,12 +1539,12 @@ impl<'a> Parser<'a> { // Since Math isn't fully expanded in this snippet, we return Unsupported. Err(Error::UnsupportedKeyword( self.current_span(), - self.current_token.clone().unwrap(), + self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )) } else { Err(Error::UnsupportedKeyword( self.current_span(), - self.current_token.clone().unwrap(), + self.current_token.clone().ok_or(Error::UnexpectedEOF)?, )) } }