futilehdl/src/parser/module.rs

124 lines
2.8 KiB
Rust
Raw Normal View History

2022-01-16 21:06:52 +00:00
use nom::{
branch::alt,
bytes::complete::tag,
2022-01-17 00:15:27 +00:00
character::complete::{char, multispace1},
2022-01-16 21:10:52 +00:00
combinator::{consumed, map},
error::context,
multi::{many1, separated_list0},
2022-01-17 00:15:27 +00:00
sequence::{delimited, tuple, terminated},
2022-01-16 21:06:52 +00:00
};
use crate::parser::{
2022-01-16 21:10:52 +00:00
assign_statement, declaration, identifier, ws0, Assign, IResult,
NetDecl, Span, proc::{proc_block, ProcBlock},
2022-01-16 21:06:52 +00:00
};
#[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)
}
2022-01-17 00:15:27 +00:00
fn assign_item(input: Span) -> IResult<Span, Assign> {
context(
"assignment",
delimited(
ws0(terminated(tag("assign"), multispace1)),
ws0(assign_statement),
ws0(char(';')),
),
)(input)
}
2022-01-16 21:06:52 +00:00
fn module_item(input: Span) -> IResult<Span, ModuleItem> {
alt((
2022-01-17 14:54:16 +00:00
map(assign_item, ModuleItem::Assign),
2022-01-16 21:10:52 +00:00
map(proc_block, ModuleItem::Proc),
2022-01-16 21:06:52 +00:00
))(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)
}
2022-01-17 14:54:16 +00:00
#[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();
}
}