use std::error::Error; use egg::{RecExpr, Id, FromOp, FromOpError}; use crate::language::EquationLanguage; pub fn parse_equation(input: &str) -> Result, ParseError> { let mut result: RecExpr = Default::default(); parse_equation_inner(&input.replace(" ", ""), &mut result)?; Ok(result) } // this is a very simple parser essentially copied from the technical interview fn parse_equation_inner(input: &str, expr: &mut RecExpr) -> Result { let mut level = 0; let mut precedence = 1000; // 0 = '=', 1 = '+-', 2 = '*/', 3 = '^' let mut operator_position: Option = None; for (i,c) in input.chars().enumerate() { if c == '(' { level += 1; } else if c == ')' { level -= 1; } if level > 0 { continue; } match c { '^' if precedence >= 3 => { operator_position = Some(i); precedence = 3; }, '*' | '/' if precedence >= 2 => { operator_position = Some(i); precedence = 2; }, '-' | '+' if precedence >= 1 => { operator_position = Some(i); precedence = 1; }, '=' => { operator_position = Some(i); precedence = 0; }, _ => {}, } } // no top level operator => either primitive item or in parantheses if let Some(operator_position) = operator_position { if operator_position == 0 && input.starts_with("-") { let inner = parse_equation_inner(&input[1 .. input.len()], expr)?; let id = expr.add(EquationLanguage::from_op("-", vec![inner])?); return Ok(id); } let left = parse_equation_inner(&input[0 .. operator_position], expr)?; let right = parse_equation_inner(&input[operator_position+1 .. input.len()], expr)?; let id = expr.add(EquationLanguage::from_op( &input[operator_position .. operator_position + 1], vec![left, right] )?); Ok(id) } else { if input.starts_with("(") && input.ends_with(")") { // expression in parentheses parse_equation_inner(&input[1..input.len()-1], expr) } else { // standalone integer if input == "x" { let id = expr.add(EquationLanguage::Unknown); Ok(id) } else { input.parse::() .map_err(|_|ParseError(format!("Failed conversion to i64: {}", &input)))?; let id = expr.add(EquationLanguage::from_op( input, vec![] )?); Ok(id) } } } } #[derive(Debug)] pub struct ParseError(String); impl Error for ParseError {} impl std::fmt::Display for ParseError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", &self.0) } } impl From for ParseError { fn from(value: FromOpError) -> Self { ParseError(format!("Error parsing {}", &value)) } }