276 lines
7.5 KiB
Rust
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))
|
|
}
|
|
}
|