use nom::{ branch::alt, bytes::complete::tag, character::complete::{alpha1, alphanumeric1, char, multispace0, multispace1, u64 as decimal}, combinator::{consumed, map, opt, recognize}, error::{context, ParseError, VerboseError}, multi::{many0, many1, separated_list0}, sequence::{delimited, pair, preceded, separated_pair, terminated, tuple}, }; use crate::parser::proc::{proc_block, ProcBlock}; use crate::parser::{ assign_statement, declaration, identifier, intliteral, widthspec, ws0, Assign, IResult, NetDecl, Span, }; #[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 module_item(input: Span) -> IResult { alt(( map(assign_statement, |assig| ModuleItem::Assign(assig)), map(proc_block, |proc| ModuleItem::Proc(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) }