use std::io::Cursor; use neotoma::{ cache::ParsingCache, literal::Literal, optional::Optional, parser::{Parser, Source, parse}, recursive::Recursive, result::{Error, ParseResult}, utf8class::Utf8Class, }; // Arithmetic expression AST #[derive(Debug, Clone, PartialEq)] enum ArithmeticExpr { Number(String), Variable(String), Real(String, String), // integer part, fractional part BinaryOp { left: Box, op: String, right: Box, }, Parenthesized(Box), } // Number parser #[derive(Clone)] struct NumberParser; impl Parser for NumberParser { type Output = ArithmeticExpr; fn read( &self, source: &mut Source, cache: &mut impl ParsingCache, _context: &mut Ctx, ) -> ParseResult where S: neotoma::parser::Parsable, { let integer = Utf8Class::with_min("0123456789", 1); if let Ok(digits) = integer.parse(source, cache, _context) { return Ok(ArithmeticExpr::Number(digits)); } Err(Error::NoMatch) } } // Variable parser #[derive(Clone)] struct VariableParser; impl Parser for VariableParser { type Output = ArithmeticExpr; fn read( &self, source: &mut Source, cache: &mut impl ParsingCache, _context: &mut Ctx, ) -> ParseResult where S: neotoma::parser::Parsable, { let alpha = Utf8Class::from_predicate_min(|c| c.is_ascii_alphabetic(), 1); if let Ok(var) = alpha.parse(source, cache, _context) { return Ok(ArithmeticExpr::Variable(var)); } Err(Error::NoMatch) } } // Real number parser (integer.integer) #[derive(Clone)] struct RealParser; impl Parser for RealParser { type Output = ArithmeticExpr; fn read( &self, source: &mut Source, cache: &mut impl ParsingCache, _context: &mut Ctx, ) -> ParseResult where S: neotoma::parser::Parsable, { let integer = Utf8Class::with_min("0123456789", 1); let point = Literal::from_bytes_const(b"."); if let Ok(int_part) = integer.parse(source, cache, _context) { if point.parse(source, cache, _context).is_ok() { if let Ok(frac_part) = integer.parse(source, cache, _context) { return Ok(ArithmeticExpr::Real(int_part, frac_part)); } } } Err(Error::NoMatch) } } // Factor parser - handles numbers, variables, reals, and parenthesized expressions struct FactorParser { expr_parser: Recursive, } impl FactorParser { fn new() -> Self { Self { expr_parser: Recursive::new(), } } } impl Parser for FactorParser { type Output = ArithmeticExpr; fn read( &self, source: &mut Source, cache: &mut impl ParsingCache, _context: &mut Ctx, ) -> ParseResult where S: neotoma::parser::Parsable, { let whitespace = Optional::new(Utf8Class::whitespace()); let oparen = Literal::from_bytes_const(b"("); if oparen.parse(source, cache, _context).is_ok() { let _ = whitespace.parse(source, cache, _context); if let Ok(inner_expr) = self.expr_parser.parse(source, cache, _context) { let _ = whitespace.parse(source, cache, _context); let cparen = Literal::from_bytes_const(b")"); if cparen.parse(source, cache, _context).is_ok() { return Ok(ArithmeticExpr::Parenthesized(Box::new(inner_expr))); } } } // Try real number first (more specific than integer) let real_parser = RealParser; if let Ok(real_expr) = real_parser.parse(source, cache, _context) { return Ok(real_expr); } // Try variable let var_parser = VariableParser; if let Ok(var_expr) = var_parser.parse(source, cache, _context) { return Ok(var_expr); } // Try integer let num_parser = NumberParser; if let Ok(num_expr) = num_parser.parse(source, cache, _context) { return Ok(num_expr); } Err(Error::NoMatch) } } // Term parser - handles multiplication and division struct TermParser { factor_parser: FactorParser, } impl TermParser { fn new() -> Self { Self { factor_parser: FactorParser::new(), } } } impl Parser for TermParser { type Output = ArithmeticExpr; fn read( &self, source: &mut Source, cache: &mut impl ParsingCache, _context: &mut Ctx, ) -> ParseResult where S: neotoma::parser::Parsable, { let whitespace = Optional::new(Utf8Class::whitespace()); let multiply = Literal::from_bytes_const(b"*"); let divide = Literal::from_bytes_const(b"/"); // Parse first factor if let Ok(mut left) = self.factor_parser.parse(source, cache, _context) { // Try to parse operator and second factor let _ = whitespace.parse(source, cache, _context); // Check for multiply if multiply.parse(source, cache, _context).is_ok() { let _ = whitespace.parse(source, cache, _context); if let Ok(right) = self.factor_parser.parse(source, cache, _context) { left = ArithmeticExpr::BinaryOp { left: Box::new(left), op: "*".to_string(), right: Box::new(right), }; } } // Check for divide (if multiply didn't match) else if divide.parse(source, cache, _context).is_ok() { let _ = whitespace.parse(source, cache, _context); if let Ok(right) = self.factor_parser.parse(source, cache, _context) { left = ArithmeticExpr::BinaryOp { left: Box::new(left), op: "/".to_string(), right: Box::new(right), }; } } return Ok(left); } Err(Error::NoMatch) } } // Main expression parser - handles addition and subtraction struct ArithmeticExpression { term_parser: TermParser, } impl ArithmeticExpression { fn new() -> Self { ArithmeticExpression { term_parser: TermParser::new(), } } } impl Default for ArithmeticExpression { fn default() -> Self { Self::new() } } impl Parser for ArithmeticExpression { type Output = ArithmeticExpr; fn read( &self, source: &mut Source, cache: &mut impl ParsingCache, _context: &mut Ctx, ) -> ParseResult where S: neotoma::parser::Parsable, { let whitespace = Optional::new(Utf8Class::whitespace()); let plus = Literal::from_bytes_const(b"+"); let minus = Literal::from_bytes_const(b"-"); // Parse first term if let Ok(mut left) = self.term_parser.parse(source, cache, _context) { // Try to parse operator and second term let _ = whitespace.parse(source, cache, _context); // Check for plus if plus.parse(source, cache, _context).is_ok() { let _ = whitespace.parse(source, cache, _context); if let Ok(right) = self.term_parser.parse(source, cache, _context) { left = ArithmeticExpr::BinaryOp { left: Box::new(left), op: "+".to_string(), right: Box::new(right), }; } } // Check for minus (if plus didn't match) else if minus.parse(source, cache, _context).is_ok() { let _ = whitespace.parse(source, cache, _context); if let Ok(right) = self.term_parser.parse(source, cache, _context) { left = ArithmeticExpr::BinaryOp { left: Box::new(left), op: "-".to_string(), right: Box::new(right), }; } } return Ok(left); } Err(Error::NoMatch) } } #[test] fn hardcoded_arithmetic_parser() { let expression = ArithmeticExpression::new(); let cursor = Cursor::new(br#"1 + 2 * 3"#); let mut source = Source::new(cursor); let result = parse(expression, &mut source); // Just verify it parses without error for now assert!(result.is_ok()); // We can also check the structure if let Ok(expr) = result { match expr { ArithmeticExpr::BinaryOp { left, op, right } => { assert_eq!(op, "+"); // Left should be "1" if let ArithmeticExpr::Number(n) = *left { assert_eq!(n, "1"); } // Right should be "2 * 3" if let ArithmeticExpr::BinaryOp { left: l2, op: op2, right: r2, } = *right { assert_eq!(op2, "*"); if let (ArithmeticExpr::Number(n2), ArithmeticExpr::Number(n3)) = (*l2, *r2) { assert_eq!(n2, "2"); assert_eq!(n3, "3"); } } } _ => panic!("Expected binary operation"), } } } #[test] fn arithmetic_with_parentheses() { let expression = ArithmeticExpression::new(); let cursor = Cursor::new(br#"(1 + 2) * 3"#); let mut source = Source::new(cursor); let result = parse(expression, &mut source); assert!(result.is_ok()); } #[test] fn arithmetic_with_variables() { let expression = ArithmeticExpression::new(); let cursor = Cursor::new(br#"x + y * z"#); let mut source = Source::new(cursor); let result = parse(expression, &mut source); assert!(result.is_ok()); } #[test] fn complex_expression() { let expression = ArithmeticExpression::new(); let cursor = Cursor::new(br#"1 + 2 + 3 * 3"#); let mut source = Source::new(cursor); let result = parse(expression, &mut source); assert!( result.is_ok(), "Complex expression should parse successfully" ); } #[test] fn two_levels_of_nesting() { let expression = ArithmeticExpression::new(); let cursor = Cursor::new(br#"((1 + 2))"#); let mut source = Source::new(cursor); let result = parse(expression, &mut source); println!("Two levels result: {result:?}"); assert!( result.is_ok(), "Two levels of nesting should parse successfully" ); } #[test] fn three_levels_of_nesting() { let expression = ArithmeticExpression::new(); let cursor = Cursor::new(br#"(((1 + 2)))"#); let mut source = Source::new(cursor); let result = parse(expression, &mut source); assert!( result.is_ok(), "Three levels of nesting should parse successfully" ); } #[test] fn five_levels_of_nesting() { let expression = ArithmeticExpression::new(); let cursor = Cursor::new(br#"((((1 + 2))))"#); let mut source = Source::new(cursor); let result = parse(expression, &mut source); assert!( result.is_ok(), "Five levels of nesting should parse successfully" ); // Verify the structure has the right nesting if let Ok(expr) = result { let mut current = &expr; let mut depth = 0; // Count how deep the parentheses nesting goes while let ArithmeticExpr::Parenthesized(inner) = current { depth += 1; current = inner; } assert_eq!(depth, 4, "Should have 4 levels of parentheses nesting"); } } #[test] fn ten_levels_of_nesting() { let expression = ArithmeticExpression::new(); let cursor = Cursor::new(br#"(((((((((1 + 2)))))))))"#); let mut source = Source::new(cursor); let result = parse(expression, &mut source); assert!( result.is_ok(), "Ten levels of nesting should parse successfully" ); // Verify the structure has the right nesting if let Ok(expr) = result { let mut current = &expr; let mut depth = 0; // Count how deep the parentheses nesting goes while let ArithmeticExpr::Parenthesized(inner) = current { depth += 1; current = inner; } assert_eq!(depth, 9, "Should have 9 levels of parentheses nesting"); } }