use nom::{ branch::alt, combinator::map, error::context, multi::{many1, separated_list1}, sequence::{delimited, separated_pair, tuple}, }; use crate::parser::{ assign_statement, expression, expression::{expression, Expression}, tokens::{token, TokenKind as tk, TokenSpan}, Assign, IResult, Span, }; #[derive(Debug)] pub struct ProcBlock<'a> { pub net: Span<'a>, pub items: Vec>, } #[derive(Debug)] pub enum ProcStatement<'a> { IfElse(IfElseBlock), Assign(Assign<'a>), Match(MatchBlock<'a>), Block(Vec>), } // TODO: postponed because annoying to implement #[derive(Debug)] pub struct IfElseBlock {} #[derive(Debug)] pub struct MatchBlock<'a> { pub expr: Expression<'a>, pub arms: Vec<(Expression<'a>, ProcStatement<'a>)>, } fn match_arm(input: TokenSpan) -> IResult { separated_pair(expression, token(tk::FatArrow), proc_statement)(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) } fn statement_block(input: TokenSpan) -> IResult> { delimited( token(tk::LBrace), separated_list1(token(tk::Semicolon), proc_statement), token(tk::RBrace), )(input) } /// parse a statement that is valid inside a proc block fn proc_statement(input: TokenSpan) -> IResult { alt(( map(match_block, ProcStatement::Match), map(statement_block, ProcStatement::Block), map(assign_statement, ProcStatement::Assign), ))(input) } pub fn proc_block(input: TokenSpan) -> IResult { context( "proc block", map( tuple(( token(tk::Proc), delimited(token(tk::LParen), token(tk::Ident), token(tk::RParen)), delimited(token(tk::LBrace), many1(proc_statement), token(tk::RBrace)), )), |(_, net, items)| ProcBlock { net: net.span(), items, }, ), )(input) }