use nom::{ branch::alt, bytes::complete::tag, character::complete::char, combinator::map, error::context, multi::{many1, separated_list0, separated_list1}, sequence::{delimited, tuple, separated_pair}, }; use crate::parser::{identifier, ws0, expression, Expression, IResult, Span, Assign, assign_statement}; #[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: Span) -> IResult { separated_pair(ws0(expression), tag("=>"), ws0(proc_statement))(input) } fn match_block(input: Span) -> IResult { context( "match block", map( tuple(( ws0(tag("match")), ws0(delimited(char('('), ws0(expression), char(')'))), ws0(delimited(char('{'), separated_list1(char(','), ws0(match_arm)), char('}'))), )), |(_, expr, arms)| MatchBlock { expr, arms }, ), )(input) } fn statement_block(input: Span) -> IResult> { delimited(char('{'), separated_list1(char(';'), ws0(proc_statement)), char('}'))(input) } /// parse a statement that is valid inside a proc block fn proc_statement(input: Span) -> IResult { alt(( map(match_block, ProcStatement::Match), map(statement_block, ProcStatement::Block), map(assign_statement, ProcStatement::Assign), ))(input) } pub fn proc_block(input: Span) -> IResult { context( "proc block", map( tuple(( ws0(tag("proc")), ws0(delimited(char('('), ws0(identifier), char(')'))), ws0(delimited(char('{'), many1(ws0(proc_statement)), char('}'))), )), |(_, net, items)| ProcBlock { net, items }, ), )(input) } #[cfg(test)] mod test { use super::*; #[test] fn test_statement() { proc_statement(" abc = def ".into()).unwrap(); } #[test] fn test_match_arm() { match_arm(" 1 => abc = def ".into()).unwrap(); } #[test] fn test_match_block() { let input = " match (asdf) { 1 => a = 0, 2 => c = ~d } "; match_block(input.into()).unwrap(); } }