initial commit

This commit is contained in:
Romain Paquet 2023-06-12 20:19:19 +02:00
commit 43df8c4b0a
9 changed files with 596 additions and 0 deletions

181
src/parsing/pest.rs Normal file
View file

@ -0,0 +1,181 @@
use lazy_static;
use pest::error::Error;
use pest::iterators::Pair;
use pest::pratt_parser::PrattParser;
use pest::Parser;
use crate::ast::*;
#[derive(pest_derive::Parser)]
#[grammar = "parsing/grammar.pest"]
struct KrParser;
lazy_static::lazy_static! {
static ref PRATT_PARSER: PrattParser<Rule> = {
use pest::pratt_parser::{Assoc::*, Op};
use Rule::*;
// Precedence is defined lowest to highest
PrattParser::new()
// Addition and subtract have equal precedence
.op(Op::infix(add, Left) | Op::infix(subtract, Left))
.op(Op::infix(multiply, Left) | Op::infix(divide, Left))
};
}
pub fn parse(source: &str) -> Result<Ast, Error<Rule>> {
let mut definitions: Vec<Ast> = vec![];
let pairs = KrParser::parse(Rule::source_file, source)?;
for pair in pairs {
match pair.as_rule() {
Rule::source_file => {
let pairs = pair.into_inner();
for pair in pairs {
match pair.as_rule() {
Rule::definition => {
let definition = parse_definition(pair.into_inner().next().unwrap());
definitions.push(definition);
}
Rule::EOI => {}
_ => panic!("unexpected rule in source_file: {:?}", pair.as_rule()),
}
}
}
_ => eprintln!("unexpected top-level rule {:?}", pair.as_rule()),
}
}
Ok(Ast::Module(definitions))
}
fn parse_block(pair: Pair<Rule>) -> Block {
let mut statements = vec![];
let mut value = None;
for pair in pair.into_inner() {
match pair.as_rule() {
Rule::statement => statements.push(parse_statement(pair)),
Rule::expr => value = Some(parse_expression(pair)),
_ => panic!("unexpected rule {:?} in block", pair.as_rule()),
}
}
Block { statements, value }
}
fn parse_statement(pair: Pair<Rule>) -> Statement {
let pair = pair.into_inner().next().unwrap();
match pair.as_rule() {
Rule::assign_statement => {
let mut pairs = pair.into_inner();
let identifier = pairs.next().unwrap().as_str().to_string();
let expr = parse_expression(pairs.next().unwrap());
Statement::AssignStatement(identifier, expr)
}
Rule::return_statement => {
let expr = if let Some(pair) = pair.into_inner().next() {
Some(parse_expression(pair))
} else {
None
};
Statement::ReturnStatement(expr)
}
Rule::call_statement => {
let call = parse_call(pair.into_inner().next().unwrap());
Statement::CallStatement(call)
}
_ => unreachable!("unexpected rule '{:?}' in parse_statement", pair.as_rule()),
}
}
fn parse_call(pair: Pair<Rule>) -> Call {
let mut pairs = pair.into_inner();
// TODO: support calls on more than identifiers (needs grammar change)
let callee = Expr::Identifier(pairs.next().unwrap().as_str().to_string());
let args: Vec<Expr> = pairs
.next()
.unwrap()
.into_inner()
.map(parse_expression)
.collect();
Call { callee, args }
}
fn parse_expression(pair: Pair<Rule>) -> Expr {
let pairs = pair.into_inner();
PRATT_PARSER
.map_primary(|primary| match primary.as_rule() {
Rule::integer_literal => Expr::IntegerLiteral(primary.as_str().parse().unwrap()),
Rule::float_literal => Expr::FloatLiteral(primary.as_str().parse().unwrap()),
Rule::string_literal => Expr::StringLiteral(
primary
.into_inner()
.next()
.unwrap()
.as_str()
.parse()
.unwrap(),
),
Rule::ident => Expr::Identifier(primary.as_str().to_string()),
Rule::expr => parse_expression(primary),
Rule::call => Expr::Call(Box::new(parse_call(primary))),
_ => unreachable!(
"Unexpected rule '{:?}' in primary expression",
primary.as_rule()
),
})
.map_infix(|lhs, op, rhs| {
let operator = match op.as_rule() {
Rule::add => BinaryOperator::Add,
Rule::subtract => BinaryOperator::Sub,
Rule::multiply => BinaryOperator::Mul,
Rule::divide => BinaryOperator::Div,
_ => unreachable!(),
};
Expr::BinaryExpression(Box::new(lhs), operator, Box::new(rhs))
})
.parse(pairs)
}
fn parse_parameter(pair: Pair<Rule>) -> Parameter {
assert!(pair.as_rule() == Rule::parameter);
let mut pair = pair.into_inner();
let name: String = pair.next().unwrap().as_str().to_string();
let typ = Type::from(pair.next().unwrap().as_str());
Parameter { name, typ }
}
fn parse_definition(pair: Pair<Rule>) -> Ast {
match pair.as_rule() {
Rule::func_def => {
let mut pairs = pair.into_inner();
let name = pairs.next().unwrap().as_str().to_string();
let parameters: Vec<Parameter> = pairs
.next()
.unwrap()
.into_inner()
.map(parse_parameter)
.collect();
let pair = pairs.next().unwrap();
// Before the block there is an optional return type
let (return_type, pair) = match pair.as_rule() {
Rule::ident => (Some(Type::from(pair.as_str())), pairs.next().unwrap()),
Rule::block => (None, pair),
_ => unreachable!(
"Unexpected rule '{:?}' in function definition, expected return type or block",
pair.as_rule()
),
};
let body = parse_block(pair);
let body = Box::new(body);
Ast::FunctionDefinition(FunctionDefinition {
name,
parameters,
return_type,
body,
})
}
_ => panic!("unexpected node for definition: {:?}", pair.as_rule()),
}
}