use std::collections::BTreeMap;
use purs_constructor::*;
use purs_type::*;
use std::fmt::{Display, Formatter};
#[derive(Debug)]
pub struct PursModule {
name: String,
imports: BTreeMap<String, Vec<String>>,
types: Vec<PursType>,
}
impl PursModule {
pub fn new(name: String, types: Vec<PursType>) -> Self {
let mut imports = BTreeMap::new();
imports.insert(
"Data.Generic".to_string(),
vec!["class Generic".to_string()],
);
for type_ in &types {
match *type_ {
PursType::Struct(ref name, ref fields) => {
Self::accumulate_imports(&mut imports, name);
for &(ref _name, ref type_) in fields.iter() {
Self::accumulate_imports(&mut imports, type_)
}
}
PursType::TupleStruct(ref name, ref fields) => {
Self::accumulate_imports(&mut imports, name);
for field in fields.iter() {
Self::accumulate_imports(&mut imports, field)
}
}
PursType::Enum(ref name, ref c) => {
Self::accumulate_imports(&mut imports, name);
for item in c.iter() {
Self::accumulate_imports(&mut imports, item)
}
}
}
}
PursModule {
name,
imports,
types,
}
}
fn accumulate_imports(imports: &mut BTreeMap<String, Vec<String>>, type_: &PursConstructor) {
if let Some(ref import) = type_.module {
let mut value = imports.entry(import.clone()).or_insert_with(Vec::new);
if value.iter().find(|i| **i == type_.name).is_none() {
value.push(type_.name.clone())
}
}
for param in &type_.parameters {
Self::accumulate_imports(imports, param)
}
}
}
impl Display for PursModule {
fn fmt(&self, f: &mut Formatter) -> ::std::fmt::Result {
write!(f, "module {} where\n\n", self.name)?;
for (key, value) in &self.imports {
if key == "PRIM" {
continue;
}
write!(f, "import {} (", key)?;
for v in value.iter() {
write!(f, "\n{}", v)?;
}
write!(f, "\n)\n")?;
}
write!(f, "\n")?;
for type_ in &self.types {
match *type_ {
PursType::TupleStruct(ref constructor_, ref _fields) => {
write!(f, "{}\n\n", type_)?;
write!(
f,
"derive instance generic{} :: Generic {}\n\n",
constructor_.name,
constructor_.name
)?;
}
PursType::Struct(ref constructor, ref _fields) => {
write!(f, "{}\n\n", type_)?;
write!(
f,
"derive instance generic{} :: Generic {}\n\n",
constructor.name,
constructor.name
)?;
}
PursType::Enum(ref constructor, ref _constructors) => {
write!(f, "{}\n\n", type_)?;
write!(
f,
"derive instance generic{} :: Generic {}\n\n",
constructor.name,
constructor.name
)?;
}
}
}
Ok(())
}
}
#[macro_export]
macro_rules! purs_module {
( $name:expr ; $( $p:path ),* ) => {
{
let purs_types = vec![
$( <$p>::as_purs_type() ),*
];
PursModule::new($name, purs_types)
}
}
}