use nom::{ branch::alt, combinator::map, error::context, multi::{many0, separated_list1}, sequence::{delimited, separated_pair, terminated, tuple}, }; use crate::parser::{ expression::{expression, Expression}, tokens::{token, Token, TokenKind as tk, TokenSpan}, IResult, }; /// a block that is a single expression #[derive(Debug, Clone)] pub struct ExpressionBlock<'a> { pub assignments: Vec<(Token<'a>, Token<'a>, Expression<'a>)>, pub value: Expression<'a>, } /// an expression that contains a block #[derive(Debug, Clone)] pub enum BlockExpr<'a> { IfElse(IfElseBlock), Match(MatchBlock<'a>), Block(ExpressionBlock<'a>), } // TODO: postponed because annoying to implement #[derive(Debug, Clone)] pub struct IfElseBlock {} #[derive(Debug, Clone)] pub struct MatchBlock<'a> { pub expr: Expression<'a>, pub arms: Vec<(Expression<'a>, Expression<'a>)>, } fn match_arm(input: TokenSpan) -> IResult { separated_pair(expression, token(tk::FatArrow), expression)(input) } fn match_block(input: TokenSpan) -> IResult { context( "match block", map( tuple(( token(tk::Match), delimited(token(tk::LParen), expression, token(tk::RParen)), delimited( token(tk::LBrace), separated_list1(token(tk::Comma), match_arm), token(tk::RBrace), ), )), |(_, expr, arms)| MatchBlock { expr, arms }, ), )(input) } pub fn expression_block(input: TokenSpan) -> IResult { map( tuple(( many0(tuple(( alt((token(tk::Let), token(tk::Reg), token(tk::Next))), terminated(token(tk::Ident), token(tk::EqAssign)), terminated(expression, token(tk::Semicolon)), ))), expression, )), |(assignments, value)| ExpressionBlock { assignments, value }, )(input) } pub fn block_expr(input: TokenSpan) -> IResult { alt(( map(match_block, BlockExpr::Match), map( delimited(token(tk::LBrace), expression_block, token(tk::RBrace)), BlockExpr::Block, ), ))(input) }