use std::{
collections::{HashMap, HashSet},
rc::Rc,
};
use super::super::raw;
trait CompleteRawDecl {
fn complete(&self, deps: &super::Deps) -> Option<super::TopDecl>;
}
impl CompleteRawDecl for raw::OptionDecl {
fn complete(&self, deps: &super::Deps) -> Option<super::TopDecl> {
deps.get(self.item().typ()).map(|dep| {
let name = self.name().to_owned();
let item = super::ItemDecl::new(dep);
super::Option_ {
name,
item,
imported_depth: self.imported_depth(),
}
.into()
})
}
}
impl CompleteRawDecl for raw::UnionDecl {
fn complete(&self, deps: &super::Deps) -> Option<super::TopDecl> {
if self.items().is_empty() {
panic!("the union ({}) is empty", self.name());
}
self.items()
.iter()
.map(|raw_item| {
deps.get(raw_item.typ())
.map(|typ| super::UnionItemDecl::new(typ, raw_item.id()))
})
.collect::<Option<Vec<_>>>()
.map(|items| {
let name = self.name().to_owned();
super::Union {
name,
items,
imported_depth: self.imported_depth(),
}
.into()
})
}
}
impl CompleteRawDecl for raw::ArrayDecl {
fn complete(&self, deps: &super::Deps) -> Option<super::TopDecl> {
deps.get(self.item().typ()).map(|dep| {
let item_size = dep.total_size().unwrap_or_else(|| {
panic!(
"the item type ({}) of array ({}) doesn't have fixed size",
self.item().typ(),
self.name(),
);
});
if item_size == 0 {
panic!("the array ({}) has no size", self.name());
}
let name = self.name().to_owned();
let item = super::ItemDecl::new(dep);
let item_count = self.item_count();
super::Array {
name,
item,
item_count,
imported_depth: self.imported_depth(),
item_size,
}
.into()
})
}
}
impl CompleteRawDecl for raw::StructDecl {
fn complete(&self, deps: &super::Deps) -> Option<super::TopDecl> {
let mut fields = Vec::with_capacity(self.fields().len());
let mut field_sizes = Vec::with_capacity(self.fields().len());
for raw_field in self.fields() {
let field_name = raw_field.name();
if let Some(dep) = deps.get(raw_field.typ()) {
if let Some(field_size) = dep.total_size() {
field_sizes.push(field_size);
} else {
panic!(
"the filed type ({}) in struct ({}) doesn't have fixed size",
field_name,
self.name(),
);
}
let field = super::FieldDecl::new(field_name, dep);
fields.push(field);
} else {
break;
}
}
if fields.len() != self.fields().len() {
return None;
}
if field_sizes.iter().sum::<usize>() == 0 {
panic!("the struct ({}) has no size", self.name());
}
let name = self.name().to_owned();
Some(
super::Struct {
name,
fields,
imported_depth: self.imported_depth(),
field_sizes,
}
.into(),
)
}
}
impl CompleteRawDecl for raw::VectorDecl {
fn complete(&self, deps: &super::Deps) -> Option<super::TopDecl> {
deps.get(self.item().typ()).map(|dep| {
let name = self.name().to_owned();
let item = super::ItemDecl::new(dep);
if let Some(item_size) = dep.total_size() {
super::FixVec {
name,
item,
imported_depth: self.imported_depth(),
item_size,
}
.into()
} else {
super::DynVec {
name,
item,
imported_depth: self.imported_depth(),
}
.into()
}
})
}
}
impl CompleteRawDecl for raw::TableDecl {
fn complete(&self, deps: &super::Deps) -> Option<super::TopDecl> {
self.fields()
.iter()
.map(|raw_field| {
let field_name = raw_field.name();
deps.get(raw_field.typ())
.map(|dep| super::FieldDecl::new(field_name, dep))
})
.collect::<Option<Vec<_>>>()
.map(|fields| {
let name = self.name().to_owned();
super::Table {
name,
fields,
imported_depth: self.imported_depth(),
}
.into()
})
}
}
impl super::Ast {
pub(crate) fn complete(raw: raw::Ast) -> Self {
let mut decls_idx = HashMap::new();
let mut decls_keys = HashSet::new();
for decl in raw.decls() {
let name = decl.name();
if super::TopDecl::new_primitive(name.to_lowercase().as_str()).is_some() {
panic!("the name `{}` is reserved", name);
}
if decls_idx.insert(name, decl).is_some() || !decls_keys.insert(name) {
panic!("the name `{}` is used more than once", name);
};
let decls_keys_clone = decls_keys
.iter()
.cloned()
.map(str::to_lowercase)
.collect::<HashSet<String>>();
if decls_keys_clone.len() != decls_keys.len() {
panic!("the name `{}` is used more than once, It seems that only the capitalization is inconsistent", name);
}
}
let mut decls_result = HashMap::new();
decls_result.insert(
"byte",
Rc::new(super::TopDecl::new_primitive("byte").unwrap()),
);
loop {
if decls_keys.is_empty() {
break;
}
let incompleted = decls_keys.len();
decls_keys.retain(|&name| {
let decl_raw = decls_idx.get(name).unwrap();
if let Some(decl) = super::TopDecl::complete(decl_raw, &decls_result) {
decls_result.insert(name, Rc::new(decl));
false
} else {
true
}
});
if decls_keys.len() == incompleted {
panic!(
"there are {} types which are unable to be completed: {:?}",
incompleted, decls_keys
);
}
}
let namespace = raw.namespace().to_owned();
let imports = raw
.imports()
.iter()
.filter(|r| r.imported_depth() == 0)
.map(super::ImportStmt::complete)
.collect();
let mut decls = Vec::with_capacity(raw.decls().len());
for decl in raw.decls() {
let result = decls_result.get(decl.name()).unwrap();
decls.push(Rc::clone(result));
}
let syntax_version = raw.syntax_version().unwrap().to_owned();
Self {
syntax_version,
namespace,
imports,
decls,
}
}
}
impl super::ImportStmt {
fn complete(raw: &raw::ImportStmt) -> Self {
Self {
name: raw.name().to_owned(),
paths: raw.paths().to_owned(),
path_supers: raw.path_supers(),
}
}
}
impl super::TopDecl {
fn complete(raw: &raw::TopDecl, deps: &super::Deps) -> Option<Self> {
match raw {
raw::TopDecl::Option_(inner) => inner.complete(deps),
raw::TopDecl::Union(inner) => inner.complete(deps),
raw::TopDecl::Array(inner) => inner.complete(deps),
raw::TopDecl::Struct(inner) => inner.complete(deps),
raw::TopDecl::Vector(inner) => inner.complete(deps),
raw::TopDecl::Table(inner) => inner.complete(deps),
}
}
}