Amo/src/parser/expr.rs

276 lines
7.5 KiB
Rust

// <expr> ::= If <expr> <ifblock>
// | <let> { <let> } In <expr>
// | <infix_expr>
// | TypeOp <expr>
//
// <tightexpr> ::= Literal
// | OpenParen <expr> CloseParen
//
// <let> ::= Let Symbol Assign <expr>
//
// <ifblock> ::= Is <case> { Comma <case> } [ Comma ]
// | Then <expr> Else <expr>
//
// <case> ::= <binding_pattern> Aro <expr>
use std::{mem::{Discriminant, discriminant}, collections::LinkedList};
use crate::{token::{Literal, Token}, ir::{self, Identifier, expr::{Operation, set_last_ident_name}, BindingScope, pattern::Pattern, IrError}, cons_ll, join};
use super::{Parsable, pattern::BindingPattern, infix::{Rank1Exp, GenIR}, ParseError, WrappedLexer, absorb_token_or_error, parse_delineated_vec};
#[derive(Debug)]
pub enum Expr {
If(Box<Expr>, Box<IfBlock>),
Let(Box<LetStmt>, Vec<LetStmt>, Box<Expr>),
Infix(Rank1Exp),
Type(Box<Expr>),
}
impl Parsable for Expr {
fn expected() -> (Vec<Discriminant<Token>>, bool) {
let mut expected = Rank1Exp::expected().0;
expected.extend_from_slice(&[
discriminant(&Token::Let),
discriminant(&Token::If),
discriminant(&Token::TypeOp),
]);
(expected, false)
}
fn parse(l: &mut WrappedLexer) -> Result<Self, ParseError> {
let next = discriminant(l.curtok());
let infix_expected = Rank1Exp::expected().0;
if infix_expected.iter().find(|t| **t == next).is_some() {
Rank1Exp::parse(l).map(Expr::Infix)
} else {
match l.curtok() {
Token::Let => {
let initial_let = LetStmt::parse(l)?;
let subsequent_lets = Vec::parse(l)?;
absorb_token_or_error(l, discriminant(&Token::In))?;
let in_expr = Expr::parse(l)?;
Ok(Expr::Let(Box::new(initial_let), subsequent_lets, Box::new(in_expr)))
}
Token::TypeOp => {
l.monch();
let value = Expr::parse(l)?;
Ok(Expr::Type(Box::new(value)))
}
Token::If => {
l.monch();
let cond = Expr::parse(l)?;
let block = IfBlock::parse(l)?;
Ok(Expr::If(Box::new(cond), Box::new(block)))
},
_ => {
Err(ParseError {
location: l.span(),
expected: Self::expected().0,
})
}
}
}
}
}
impl Expr {
pub fn gen_ir(
self,
bindings: &BindingScope,
parent: &Identifier,
index: u32,
type_context: bool
) -> ir::Result<LinkedList<ir::expr::Expr>> {
match self {
Self::If(cond, if_block) => {
let self_ident = parent.subid_generate_name("ifblk", index);
let preceding_expressions = cond.gen_ir(bindings, &self_ident, 0, type_context)?;
let conditional = Operation::Conditional(match *if_block {
IfBlock::IfIs(case, more_cases) => {
Some(case).into_iter()
.chain(more_cases)
.enumerate()
.map(|(i, Case(pattern, expr))| {
let (pattern_bindings, pattern) = pattern.gen_ir(bindings, &self_ident, 2 * i as u32)?;
let new_scope = bindings.bind(pattern_bindings);
let new_exprs = expr.gen_ir(&new_scope, &self_ident, 2*i as u32 + 1, type_context)?;
Ok((pattern, new_exprs))
})
.collect::<ir::Result<Vec<_>>>()
}
IfBlock::IfThen(positive, negative) => {
vec![negative, positive]
.into_iter()
.enumerate()
.map(|(v, expr)|
expr.gen_ir(bindings, &self_ident, v as u32, type_context).map(|expr|
if v == 1 {
(Pattern::Literal(Literal::Int(1)), expr)
} else {
(Pattern::Universal, expr)
}
)
)
.rev()
.collect()
}
}?);
let new_expr = ir::expr::Expr {
identifier: self_ident,
operation: conditional,
formals: vec![preceding_expressions.back()
.ok_or(IrError::MissingExpression)?
.identifier
.clone()]
};
Ok(cons_ll(preceding_expressions, new_expr))
}
Self::Let(first_let, more_lets, finally) => {
let self_ident = parent.subid_generate_name("letmany", index);
let n_lets = more_lets.len() + 1;
let (bindings, prior_exprs) = [*first_let].into_iter()
.chain(more_lets)
.enumerate()
.try_fold(
(bindings.bind(Vec::with_capacity(n_lets)), LinkedList::new()),
|(bindings, exprs), (i, LetStmt(name, parsetree))| {
let new_exprs = set_last_ident_name(
parsetree.gen_ir(&bindings, &self_ident, i as u32, type_context)?,
name
);
let new_bindings = bindings.bind_single(
new_exprs.back()
.ok_or(IrError::MissingExpression)?
.identifier
.clone()
);
Ok((new_bindings, join(exprs, new_exprs)))
}
)?;
let exprs = finally.gen_ir(&bindings, &self_ident, n_lets as u32, type_context)?;
Ok(join(prior_exprs, exprs))
}
Self::Infix(infix) => infix.gen_ir(bindings, parent, index, type_context),
Self::Type(expr) =>
if type_context {
Err(IrError::NestedTypeDeclarations)
} else {
expr.gen_ir(bindings, parent, index, true)
}
}
}
}
// todo: refactor this to infix
#[derive(Debug)]
pub enum TightExpr {
Literal(Literal),
Grouped(Expr),
Symbol(String),
}
impl Parsable for TightExpr {
fn expected() -> (Vec<Discriminant<Token>>, bool) {
(
vec![
discriminant(&Token::Literal(Literal::Int(0))),
discriminant(&Token::OpenParen),
discriminant(&Token::Symbol(String::new())),
],
false
)
}
fn parse(l: &mut WrappedLexer) -> Result<Self, ParseError> {
let span = l.span();
match l.monch() {
Token::Literal(literal) => Ok(TightExpr::Literal(literal)),
Token::OpenParen => {
let expr = Expr::parse(l)?;
absorb_token_or_error(l, discriminant(&Token::CloseParen))?;
Ok(TightExpr::Grouped(expr))
}
Token::Symbol(name) => Ok(TightExpr::Symbol(name)),
_ => Err(ParseError {
location: span,
expected: Self::expected().0,
})
}
}
}
#[derive(Debug)]
pub enum IfBlock {
IfIs(Case, Vec<Case>),
IfThen(Expr, Expr),
}
impl Parsable for IfBlock {
fn expected() -> (Vec<Discriminant<Token>>, bool) {
(
vec![
discriminant(&Token::Is),
discriminant(&Token::Then),
],
false
)
}
fn parse(l: &mut WrappedLexer) -> Result<Self, ParseError> {
let span = l.span();
match l.monch() {
Token::Is => {
let initial_case = Case::parse(l)?;
let other_cases = if let Token::Comma = l.curtok() {
parse_delineated_vec(l, discriminant(&Token::Comma))?
} else {
Vec::new()
};
Ok(IfBlock::IfIs(initial_case, other_cases))
}
Token::Then => {
let positive = Expr::parse(l)?;
absorb_token_or_error(l, discriminant(&Token::Else))?;
let negative = Expr::parse(l)?;
Ok(IfBlock::IfThen(positive, negative))
}
_ => Err(ParseError {
location: span,
expected: Self::expected().0,
})
}
}
}
#[derive(Debug)]
pub struct LetStmt(String, Expr);
impl Parsable for LetStmt {
fn expected() -> (Vec<Discriminant<Token>>, bool) {
(vec![discriminant(&Token::Let)], false)
}
fn parse(l: &mut WrappedLexer) -> Result<Self, ParseError> {
absorb_token_or_error(l, discriminant(&Token::Let))?;
let symbol = String::parse(l)?;
absorb_token_or_error(l, discriminant(&Token::Assign))?;
let value = Expr::parse(l)?;
Ok(LetStmt(symbol, value))
}
}
#[derive(Debug)]
pub struct Case(BindingPattern, Expr);
impl Parsable for Case {
fn expected() -> (Vec<Discriminant<Token>>, bool) {
BindingPattern::expected()
}
fn parse(l: &mut WrappedLexer) -> Result<Self, ParseError> {
let pattern = BindingPattern::parse(l)?;
absorb_token_or_error(l, discriminant(&Token::DubAro))?;
let expr = Expr::parse(l)?;
Ok(Case(pattern, expr))
}
}