use pest::{iterators::Pair, Parser}; use pest_derive::Parser; use crate::{expression::Expression, statement::Statement, value::Value}; #[derive(Parser)] #[grammar = "grammar.pest"] pub struct LangParser; pub fn parse(source: &S) -> (Statement, FuncHolder) { let source = source.to_string(); let pairs = LangParser::parse(Rule::root_statement, &source).unwrap(); handle_rules(pairs) } type Func = (String, Vec, Vec); #[derive(Default)] pub struct FuncHolder(Vec); impl FuncHolder { fn insert(mut self, name: String, params: Vec, body: Vec) -> Self { self.0.push((name, params, body)); self } } impl Extend for FuncHolder { fn extend(&mut self, iter: T) where T: IntoIterator, { self.0.extend(iter); } } impl Extend for FuncHolder { fn extend(&mut self, iter: T) where T: IntoIterator, { self.0 .extend(iter.into_iter().flat_map(|h| h.0.into_iter())); } } impl IntoIterator for FuncHolder { type Item = Func; type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } fn handle_rules(mut p: pest::iterators::Pairs) -> (Statement, FuncHolder) { let z = p.next().unwrap(); parse_statement(z) } fn parse_statement(pair: Pair) -> (Statement, FuncHolder) { match pair.as_rule() { Rule::root_statement => { let (z, f) = pair.into_inner().map(parse_statement).unzip(); (Statement::Body(z), f) } Rule::while_block => { let mut inner = pair.into_inner(); let expr = inner.next().unwrap(); let body = inner.next().unwrap(); ( Statement::While(parse_expression(expr), Box::new(parse_statement(body).0)), FuncHolder::default(), ) } Rule::if_block => { let mut inner = pair.into_inner(); let mut the_list = vec![]; let mut the_else = None; while let Some(expr) = inner.next() { if expr.as_rule() == Rule::expression { let body = inner.next().unwrap(); the_list.push((parse_expression(expr), parse_statement(body).0)); } else { the_else = Some(Box::new(parse_statement(expr).0)); } } (Statement::If(the_list, the_else), FuncHolder::default()) } Rule::assignment => { let mut inner = pair.into_inner(); let name = inner.next().unwrap(); let expr = inner.next().unwrap(); ( Statement::Assignment(name.as_str().to_string(), parse_expression(expr), false), FuncHolder::default(), ) } Rule::assignment_let => { let mut inner = pair.into_inner(); let name = inner.next().unwrap(); let expr = inner.next().unwrap(); ( Statement::Assignment(name.as_str().to_string(), parse_expression(expr), true), FuncHolder::default(), ) } Rule::expression => ( Statement::Expression(parse_expression(pair)), FuncHolder::default(), ), Rule::statement => { let inner = pair.into_inner().next().unwrap(); parse_statement(inner) } Rule::block => { let (z, _): (_, FuncHolder) = pair.into_inner().map(parse_statement).unzip(); (Statement::Body(z), FuncHolder::default()) } Rule::func_block => { let (statements, expression): (Vec<_>, Vec<_>) = pair .into_inner() .partition(|x| x.as_rule() != Rule::expression); // Only functions defined at the root are supported for now, so we drop the ones // defined in a block. let (mut v, _): (Vec, FuncHolder) = statements.into_iter().map(parse_statement).unzip(); if let Some(expr) = expression.into_iter().next() { let ret = parse_expression(expr); v.push(Statement::Return(Some(ret))); } (Statement::Body(v), FuncHolder::default()) } Rule::def => { let mut inner = pair.into_inner(); let name = inner.next().unwrap(); let args = inner .next() .unwrap() .into_inner() .map(|a| a.as_str().to_string()) .collect(); let body = inner.next().unwrap(); let body = parse_statement(body); ( Statement::Body(vec![]), FuncHolder::default().insert(name.as_str().to_string(), args, vec![body.0]), ) } Rule::ret => { let mut inner = pair.into_inner(); if let Some(expr) = inner.next() { ( Statement::Return(Some(parse_expression(expr))), FuncHolder::default(), ) } else { (Statement::Return(None), FuncHolder::default()) } } Rule::EOI => (Statement::Body(vec![]), FuncHolder::default()), x => unreachable!("How did we get to {:?}", x), } } fn parse_expression(pair: Pair) -> Expression { match pair.as_rule() { Rule::expression => { let mut inner = pair.into_inner(); parse_expression(inner.next().unwrap()) } Rule::equality | Rule::inequality | Rule::sum | Rule::product => { let mut inner = pair.into_inner(); let lhs = parse_expression(inner.next().unwrap()); if let Some(op) = inner.next() { let rhs = parse_expression(inner.next().unwrap()); Expression::Binary(Box::new(lhs), op.as_str().parse().unwrap(), Box::new(rhs)) } else { lhs } } Rule::value => { let mut inner = pair.into_inner(); let v = parse_value(inner.next().unwrap()); if let Some((name, args)) = method_call(inner.next().unwrap()) { Expression::CallMethod(Box::new(v), name, args) } else { v } } Rule::if_block_expr => { let mut inner = pair.into_inner(); let mut the_list = vec![]; let mut the_else = None; while let Some(expr) = inner.next() { if let Some(if_block) = inner.next() { let expr = parse_expression(expr); let if_block_body = if_block.into_inner(); let (a, b): (Vec<_>, Vec<_>) = if_block_body.partition(|a| a.as_rule() == Rule::statement); let (statements, _): (_, FuncHolder) = a.into_iter().map(parse_statement).unzip(); let z = b.into_iter().map(parse_expression).collect::>(); the_list.push((expr, Statement::Body(statements), z[0].clone())); } else { let if_block_body = expr.into_inner(); let (a, b): (Vec<_>, Vec<_>) = if_block_body.partition(|a| a.as_rule() == Rule::statement); let (statements, _): (_, FuncHolder) = a.into_iter().map(parse_statement).unzip(); let z = b.into_iter().map(parse_expression).collect::>(); the_else = Some(( Box::new(Statement::Body(statements)), Box::new(z[0].clone()), )); } } Expression::If(the_list, the_else.unwrap()) } _ => unreachable!(), } } fn method_call(pair: Pair) -> Option<(String, Vec)> { match pair.as_rule() { Rule::method_call => { let mut inner = pair.into_inner(); if let Some(name) = inner.next() { let args = inner .next() .unwrap() .into_inner() .map(parse_expression) .collect(); Some((name.as_str().to_string(), args)) } else { None } } _ => None, } } fn parse_value(pair: Pair) -> Expression { match pair.as_rule() { Rule::const_value => { Expression::Constant(parse_const_value(&pair.into_inner().next().unwrap())) } Rule::identifier => Expression::Variable(pair.as_str().to_string()), Rule::call => { let mut inner = pair.into_inner(); let name = inner.next().unwrap(); let args = inner .next() .unwrap() .into_inner() .map(parse_expression) .collect(); Expression::Call(name.as_str().to_string(), args) } Rule::parens => { let mut inner = pair.into_inner(); parse_expression(inner.next().unwrap()) } _ => unreachable!(), } } fn parse_const_value(pair: &Pair) -> Value { match pair.as_rule() { Rule::number => { if let Ok(f) = pair.as_str().parse::() { Value::Int(f) } else if let Ok(f) = pair.as_str().parse::() { Value::Float(f) } else { unreachable!() } } Rule::string => Value::String(pair.as_str().to_string()), Rule::boolean => Value::Bool(pair.as_str() == "true"), Rule::char => Value::Char(pair.as_str().chars().next().unwrap()), _ => unreachable!(), } }