use nom::{ branch::alt, bytes::complete::tag, character::complete::{char, multispace1}, combinator::{consumed, map}, error::context, multi::{many1, separated_list0}, sequence::{delimited, tuple, terminated}, }; use crate::parser::{ assign_statement, declaration, identifier, ws0, Assign, IResult, NetDecl, Span, proc::{proc_block, ProcBlock}, }; #[derive(Debug)] pub enum PortDirection { Input, Output, } #[derive(Debug)] pub struct PortDecl<'a> { pub pos: Span<'a>, pub direction: PortDirection, pub net: NetDecl<'a>, } #[derive(Debug)] pub struct Module<'a> { pub name: &'a str, pub ports: Vec>, pub items: Vec>, } #[derive(Debug)] pub enum ModuleItem<'a> { Assign(Assign<'a>), Proc(ProcBlock<'a>), } fn port_decl(i: Span) -> IResult { map( consumed(tuple(( alt(( map(tag("input"), |_| PortDirection::Input), map(tag("output"), |_| PortDirection::Output), )), declaration, ))), |(pos, (direction, net))| PortDecl { pos, direction, net, }, )(i) } fn ports_list(input: Span) -> IResult> { separated_list0(ws0(char(',')), ws0(port_decl))(input) } fn assign_item(input: Span) -> IResult { context( "assignment", delimited( ws0(terminated(tag("assign"), multispace1)), ws0(assign_statement), ws0(char(';')), ), )(input) } fn module_item(input: Span) -> IResult { alt(( map(assign_statement, ModuleItem::Assign), map(proc_block, ModuleItem::Proc), ))(input) } /// parse a top-level module declaration pub fn module(input: Span) -> IResult { context( "module", map( tuple(( tag("module"), ws0(identifier), ws0(delimited(char('('), ws0(ports_list), char(')'))), ws0(delimited(char('{'), many1(ws0(module_item)), char('}'))), )), |(_, name, ports, items)| Module { name: (*name.fragment()), ports, items, }, ), )(input) }