sunflower/src/pest_parser.rs

222 lines
7.6 KiB
Rust

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<S: ToString>(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<Rule>) -> Statement {
fn parse_statement(pair: Pair<Rule>) -> 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<Rule>) -> 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<Rule>) -> 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<Rule>) -> Value {
match pair.as_rule() {
Rule::number => {
if let Ok(f) = pair.as_str().parse::<i32>() {
Value::Int(f)
} else if let Ok(f) = pair.as_str().parse::<f32>() {
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() {}
}