use super::parser;
use crate::errors::{CalyxResult, Error, Span};
use crate::ir;
use atty::Stream;
use std::io::stdin;
use std::path::{Path, PathBuf};
#[derive(Debug)]
pub struct NamespaceDef {
pub imports: Vec<String>,
pub components: Vec<ComponentDef>,
pub externs: Vec<(String, Vec<ir::Primitive>)>,
}
impl NamespaceDef {
pub fn new(file: &Option<PathBuf>, lib_path: &Path) -> CalyxResult<Self> {
let mut namespace = match file {
Some(file) => parser::CalyxParser::parse_file(file),
None => {
if atty::isnt(Stream::Stdin) {
parser::CalyxParser::parse(stdin())
} else {
Err(Error::InvalidFile(
"No file provided and terminal not a TTY".to_string(),
))
}
}
}?;
namespace.externs.iter_mut().for_each(|(path, _)| {
*path = lib_path.join(path.clone()).to_string_lossy().to_string();
});
let mut deps: Vec<PathBuf> = namespace
.imports
.clone()
.into_iter()
.map(|f| lib_path.join(f))
.collect();
while let Some(path) = deps.pop() {
let mut ns = parser::CalyxParser::parse_file(&path)?;
namespace.components.append(&mut ns.components);
let parent = match path.parent() {
Some(a) => a,
None => Path::new("."),
};
namespace.externs.append(
&mut ns
.externs
.into_iter()
.map(|(path, exts)| {
(parent.join(path).to_string_lossy().to_string(), exts)
})
.collect(),
);
deps.append(
&mut ns.imports.into_iter().map(|f| parent.join(f)).collect(),
);
}
Ok(namespace)
}
}
#[derive(Debug)]
pub struct ComponentDef {
pub name: ir::Id,
pub signature: Vec<ir::PortDef>,
pub cells: Vec<Cell>,
pub groups: Vec<Group>,
pub continuous_assignments: Vec<Wire>,
pub control: Control,
pub attributes: ir::Attributes,
}
#[derive(Debug)]
pub enum Port {
Comp { component: ir::Id, port: ir::Id },
This { port: ir::Id },
Hole { group: ir::Id, name: ir::Id },
}
impl Port {
pub fn port_name(&self) -> &ir::Id {
match self {
Port::Comp { port, .. } => port,
Port::This { port } => port,
Port::Hole { name, .. } => name,
}
}
}
#[derive(Debug)]
pub enum NumType {
Decimal,
Binary,
Octal,
Hex,
}
#[derive(Debug)]
pub struct BitNum {
pub width: u64,
pub num_type: NumType,
pub val: u64,
pub span: Option<Span>,
}
#[derive(Debug)]
pub enum Atom {
Port(Port),
Num(BitNum),
}
#[derive(Debug)]
pub enum GuardExpr {
And(Box<GuardExpr>, Box<GuardExpr>),
Or(Box<GuardExpr>, Box<GuardExpr>),
Not(Box<GuardExpr>),
Eq(Atom, Atom),
Neq(Atom, Atom),
Gt(Atom, Atom),
Lt(Atom, Atom),
Geq(Atom, Atom),
Leq(Atom, Atom),
Atom(Atom),
}
#[derive(Debug)]
pub struct Guard {
pub guard: Option<GuardExpr>,
pub expr: Atom,
}
#[derive(Debug)]
pub struct Proto {
pub name: ir::Id,
pub params: Vec<u64>,
}
#[derive(Debug)]
pub struct Cell {
pub name: ir::Id,
pub prototype: Proto,
pub attributes: ir::Attributes,
}
impl Cell {
pub fn from(
name: ir::Id,
proto: ir::Id,
params: Vec<u64>,
attributes: ir::Attributes,
) -> Cell {
Cell {
name,
prototype: Proto {
name: proto,
params,
},
attributes,
}
}
}
#[derive(Debug)]
pub struct Group {
pub name: ir::Id,
pub wires: Vec<Wire>,
pub attributes: ir::Attributes,
}
#[derive(Debug)]
pub struct Wire {
pub src: Guard,
pub dest: Port,
}
#[derive(Debug)]
pub enum Control {
Seq {
stmts: Vec<Control>,
attributes: ir::Attributes,
},
Par {
stmts: Vec<Control>,
attributes: ir::Attributes,
},
If {
port: Port,
cond: ir::Id,
tbranch: Box<Control>,
fbranch: Box<Control>,
attributes: ir::Attributes,
},
While {
port: Port,
cond: ir::Id,
body: Box<Control>,
attributes: ir::Attributes,
},
Enable {
comp: ir::Id,
attributes: ir::Attributes,
},
Invoke {
comp: ir::Id,
inputs: Vec<(ir::Id, Atom)>,
outputs: Vec<(ir::Id, Atom)>,
attributes: ir::Attributes,
},
Empty {},
}