222 lines
7.6 KiB
Rust
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() {}
|
|
}
|