use pest::{iterators::Pair, Parser}; use pest_derive::Parser; use crate::{ expression::{BinaryOperation, Expression}, statement::Statement, value::Value, }; #[derive(Parser)] #[grammar = "grammar.pest"] pub struct LangParser; pub fn parse(source: S) -> Statement { let source = source.to_string(); let pairs = LangParser::parse(Rule::root_statement, &source).unwrap(); handle_rules(pairs) } pub fn parser_test() { // let p = LangParser::parse(Rule::number, "-273.15").unwrap(); // println!("{:?}", p); // let p = LangParser::parse(Rule::number, "25565"); // println!("{:?}", p); // let str_test = LangParser::parse(Rule::string, "\"hello\"").unwrap(); // println!("{:?}", str_test); // let str_test = LangParser::parse(Rule::char, "'a'").unwrap(); // println!("{:?}", str_test); // let foo = LangParser::parse(Rule::statement, "10 + foo + bar(20) * 40;").unwrap(); // println!("{:?}", foo); // let bar = " // let x = 10; // let y = 20; // let z = x + y; // print(z); // while (x < y) { // x = x + 1; // } // let x = x + \"lmao\"; // "; // let bar = LangParser::parse(Rule::root_statement, bar); // println!("{:?}", bar); let baz = " if x { a; } else if y { b; } else { c; }"; let baz = LangParser::parse(Rule::root_statement, baz); println!("{:?}", baz); let x = "x == 10;"; let x = LangParser::parse(Rule::statement, x); handle_rules(x.unwrap()); } fn handle_rules(mut p: pest::iterators::Pairs) -> Statement { fn parse_statement(pair: Pair) -> Statement { match pair.as_rule() { Rule::root_statement => { Statement::Body(pair.into_inner().map(parse_statement).collect()) } 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))) } Rule::if_block => { let mut inner = pair.into_inner().into_iter(); 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))); } else { the_else = Some(Box::new(parse_statement(expr))); } } Statement::If(the_list, the_else) } 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) } 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) } Rule::expression => Statement::Expression(parse_expression(pair)), Rule::statement => { let inner = pair.into_inner().next().unwrap(); parse_statement(inner) } Rule::EOI => Statement::Body(vec![]), 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 => { 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::inequality => { 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::sum => { 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::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 inner = pair.into_inner().next().unwrap(); parse_value(inner) } _ => unreachable!(), } } 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!(), } } let z = p.next().unwrap(); parse_statement(z) } #[cfg(test)] mod tests { use pest::Parser; use super::{LangParser, Rule}; #[test] fn foo() {} }