124 lines
2.8 KiB
Rust
124 lines
2.8 KiB
Rust
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<PortDecl<'a>>,
|
|
pub items: Vec<ModuleItem<'a>>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum ModuleItem<'a> {
|
|
Assign(Assign<'a>),
|
|
Proc(ProcBlock<'a>),
|
|
}
|
|
|
|
fn port_decl(i: Span) -> IResult<Span, PortDecl> {
|
|
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<Span, Vec<PortDecl>> {
|
|
separated_list0(ws0(char(',')), ws0(port_decl))(input)
|
|
}
|
|
|
|
fn assign_item(input: Span) -> IResult<Span, Assign> {
|
|
context(
|
|
"assignment",
|
|
delimited(
|
|
ws0(terminated(tag("assign"), multispace1)),
|
|
ws0(assign_statement),
|
|
ws0(char(';')),
|
|
),
|
|
)(input)
|
|
}
|
|
|
|
fn module_item(input: Span) -> IResult<Span, ModuleItem> {
|
|
alt((
|
|
map(assign_item, ModuleItem::Assign),
|
|
map(proc_block, ModuleItem::Proc),
|
|
))(input)
|
|
}
|
|
|
|
/// parse a top-level module declaration
|
|
pub fn module(input: Span) -> IResult<Span, Module> {
|
|
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)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
use nom::combinator::all_consuming;
|
|
|
|
#[test]
|
|
fn test_decl() {
|
|
declaration("reg abcd".into()).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn test_assignment_item() {
|
|
all_consuming(assign_item)(" assign a = b ; ".into()).unwrap();
|
|
all_consuming(assign_item)(" assign a = b | c ; ".into()).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn test_module_item() {
|
|
all_consuming(module_item)(" assign a = b ;".into()).unwrap();
|
|
}
|
|
}
|
|
|
|
|