diff --git a/readme.md b/readme.md index 06d853c..2329d5d 100644 --- a/readme.md +++ b/readme.md @@ -69,7 +69,7 @@ define $number := 5; print(`The square of $number is ${math.square($number)}`); ``` -(Note: This feature is under development, and string interpolation is planned for a future update.) +(Note: This feature is under development, and string interpolation is planned for the future.) --- @@ -84,9 +84,10 @@ fddl is very much a work in progress, with lots of planned improvements and addi - **Parser**: - [x] Parser parsing tilde and minus successfully - - [ ] Parser parsing the rest of the operators + - [x] Parser parsing function calls + - [x] Parser parsing the rest of the operators (mostly complete) - [ ] Working on building out functions to parse simple functionality in the language (if, while, for), and to read their expressions and values - - [ ] Implement parsing for function calls, expressions, checks, literally everything. + - [ ] Implement parsing for ~~~function calls,~~~ expressions, checks, literally everything. - **Compiler**: - [ ] Currently a placeholder. Implement the compiler to compile parsed code. diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 6def5f0..4b93baa 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -40,6 +40,10 @@ pub enum Operator { GreaterEqual, LessEqual, + // Logical operators + And, // For logical AND e.g. true && false + Or, // For logical OR e.g. true || false + // Equality (we'll add these logic for these later) EqualEqual, // For equality e.g. 5 == 5 NotEqual, // For inequality e.g. 5 != 5 diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 027c710..c52294c 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -179,11 +179,13 @@ impl Parser { } fn parse_expression(&mut self) -> Option { - // self.parse_primary(); // Now redundant // Start with the simplest elements + // Keeping old tests here for reference until release. + // self.parse_primary(); // Start with the simplest elements // self.parse_unary() // handles unary operators ('-' and '~') // self.parse_term() // handles binary operators ('+', '-', '*', '/') // self.parse_comparison() // handles comparison operators ('<', '>', '<=', '>=') - self.parse_equality() // handles equality operators ('==', '!=') + // self.parse_equality() // handles equality operators ('==', '!=') + self.parse_logical_or() // handles logical operators ('&&', '||') } // Each function below is fed into the function below it @@ -212,11 +214,9 @@ impl Parser { Some(Expression::Variable(name)) } Token::LeftParen => { - self.advance(); // Consume '(' - // Recursively parse the expression inside the parentheses - let expr = self.parse_expression()?; // Call the main expression parser + self.advance(); + let expr = self.parse_expression()?; - // Expect and consume the closing parenthesis if self.match_token(Token::RightParen) { // Return the inner expression, wrapped in Grouping AST node Some(Expression::Grouping(Box::new(expr))) @@ -235,24 +235,22 @@ impl Parser { } fn parse_unary(&mut self) -> Option { - let current_tok = self.current_token().clone(); + let operator_token_snapshot = self.current_token().clone(); - match current_tok { + match operator_token_snapshot { Token::Minus | Token::Tilde => { - self.advance(); - - let operator = match current_tok { - Token::Minus => Operator::Minus, + self.advance(); + let ast_operator = match operator_token_snapshot { + Token::Minus => Operator::Minus, Token::Tilde => Operator::Almost, - _ => unreachable!("Lexer should not produce other tokens here if first match is minus/tilde"), + _ => unreachable!("Lexer should not produce other tokens here if first match is minus/tilde. Checked by matches! macro."), }; - - let right_operand = self.parse_primary()?; - Some(Expression::Unary(operator, Box::new(right_operand))) + + let right_operand = self.parse_unary()?; + Some(Expression::Unary(ast_operator, Box::new(right_operand))) } _ => { - // If not a unary operator, just return the primary expression - self.parse_primary() + self.parse_call_expression() } } } @@ -339,6 +337,82 @@ impl Parser { Some(expr) } + fn parse_logical_or(&mut self) -> Option { + let mut expr = self.parse_logical_and()?; + + while matches!(self.current_token(), Token::Or) { + let operator_token = self.current_token().clone(); + self.advance(); + + let ast_operator = Operator::Or; + + let right_operand = self.parse_logical_and()?; + expr = Expression::Binary(Box::new(expr), ast_operator, Box::new(right_operand)); + } + Some(expr) + } + + fn parse_logical_and(&mut self) -> Option { + let mut expr = self.parse_equality()?; + + while matches!(self.current_token(), Token::And) { + let operator_token = self.current_token().clone(); + self.advance(); + + let ast_operator = Operator::And; + + let right_operand = self.parse_equality()?; + expr = Expression::Binary(Box::new(expr), ast_operator, Box::new(right_operand)); + } + Some(expr) + } + + fn parse_call_expression(&mut self) -> Option { + let mut expr = self.parse_primary()?; + + loop { + if self.check(&Token::LeftParen) { + expr = self.finish_call(expr)?; + } else { + break; + } + } + Some(expr) + } + + fn finish_call(&mut self, callee: Expression) -> Option { + self.advance(); + + let arguments = self.parse_arguments()?; + + if !self.match_token(Token::RightParen) { + eprintln!("Error: Expected ')' after arguments in function call."); + return None; + } + Some(Expression::FunctionCall(Box::new(callee), arguments)) + } + + fn parse_arguments(&mut self) -> Option> { + let mut arguments = Vec::new(); + + if self.check(&Token::RightParen) { + return Some(arguments); + } + + match self.parse_expression() { + Some(arg) => arguments.push(arg), + None => return None, + } + + while self.match_token(Token::Comma) { + match self.parse_expression() { + Some(arg) => arguments.push(arg), + None => return None, + } + } + Some(arguments) + } + fn check(&self, expected: &Token) -> bool { if self.is_at_end() { return false;