288 lines
9.8 KiB
Rust
288 lines
9.8 KiB
Rust
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<S: ToString>(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<String>, Vec<Statement>);
|
|
|
|
#[derive(Default)]
|
|
pub struct FuncHolder(Vec<Func>);
|
|
|
|
impl FuncHolder {
|
|
fn insert(mut self, name: String, params: Vec<String>, body: Vec<Statement>) -> Self {
|
|
self.0.push((name, params, body));
|
|
self
|
|
}
|
|
}
|
|
|
|
impl Extend<Func> for FuncHolder {
|
|
fn extend<T>(&mut self, iter: T)
|
|
where
|
|
T: IntoIterator<Item = Func>,
|
|
{
|
|
self.0.extend(iter);
|
|
}
|
|
}
|
|
|
|
impl Extend<FuncHolder> for FuncHolder {
|
|
fn extend<T>(&mut self, iter: T)
|
|
where
|
|
T: IntoIterator<Item = FuncHolder>,
|
|
{
|
|
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<Func>;
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
self.0.into_iter()
|
|
}
|
|
}
|
|
|
|
fn handle_rules(mut p: pest::iterators::Pairs<Rule>) -> (Statement, FuncHolder) {
|
|
let z = p.next().unwrap();
|
|
parse_statement(z)
|
|
}
|
|
|
|
fn parse_statement(pair: Pair<Rule>) -> (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<Statement>, 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<Rule>) -> 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::<Vec<_>>();
|
|
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::<Vec<_>>();
|
|
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<Rule>) -> Option<(String, Vec<Expression>)> {
|
|
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<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!(),
|
|
}
|
|
}
|