#![allow(clippy::similar_names)]
use crate::ast_lowering::ast_to_hir_fold::expression::ConstantExpressionFolder;
use crate::ast_lowering::ast_to_hir_fold::{Branches, DeclarationHandler, ExpressionFolder, Fold};
use crate::ast_lowering::branch_resolution::BranchResolver;
use crate::ast_lowering::error::{Error, Type};
use crate::ast_lowering::name_resolution::Resolver;
use crate::hir::{Discipline, Nature, Net, Port};
use crate::ir::{ast, AttributeNode};
use crate::ir::{DisciplineId, ExpressionId, NatureId};
use crate::parser::error::Unsupported;
use crate::symbol::{keywords, Ident};
use crate::symbol_table::SymbolDeclaration;
use crate::{Ast, Hir};
pub struct Global<'lt, H: DeclarationHandler> {
pub(super) base: Fold<'lt>,
pub(super) declaration_handler: &'lt mut H,
}
impl<'lt, H: DeclarationHandler> Global<'lt, H> {
pub fn new(ast: &'lt mut Ast, declaration_handler: &'lt mut H) -> Self {
let mut res = Self {
base: Fold {
hir: Hir::init(ast),
ast: &*ast,
errors: Vec::with_capacity(32),
resolver: Resolver::new(&*ast),
},
declaration_handler,
};
res.base.resolver.enter_scope(&ast.top_symbols);
res
}
pub fn fold(mut self) -> std::result::Result<Branches<'lt, H>, Vec<Error>> {
for id in self.base.hir.attributes.indices() {
self.base.hir[id].value = self.base.hir[id]
.value
.map(|expr| self.fold_constant_expr(expr))
.flatten();
}
self.base.hir.natures = self
.base
.ast
.natures
.iter_enumerated()
.filter_map(|(id, nature)| {
self.declaration_handler
.handle_declaration(&mut self.base, SymbolDeclaration::Nature(id));
self.fold_nature(id, nature)
})
.collect();
self.base.hir.disciplines = self
.base
.ast
.disciplines
.iter_enumerated()
.map(|(id, discipline)| {
self.declaration_handler
.handle_declaration(&mut self.base, SymbolDeclaration::Discipline(id));
self.fold_discipline(discipline)
})
.collect();
self.base.hir.nets = self
.base
.ast
.nets
.iter_enumerated()
.filter_map(|(id, net)| {
self.declaration_handler
.handle_declaration(&mut self.base, SymbolDeclaration::Net(id));
self.fold_net(net)
})
.collect();
self.base.hir.ports = self
.base
.ast
.ports
.iter_enumerated()
.filter_map(|(id, port)| {
self.declaration_handler
.handle_declaration(&mut self.base, SymbolDeclaration::Port(id));
self.fold_port(port)
})
.collect();
if self.base.errors.is_empty() {
Ok(Branches {
branch_resolver: BranchResolver::new(self.base.ast),
base: self.base,
declaration_handler: self.declaration_handler,
})
} else {
Err(self.base.errors)
}
}
fn fold_discipline(
&mut self,
discipline: &AttributeNode<ast::Discipline>,
) -> AttributeNode<Discipline> {
discipline.copy_with(|old| {
let flow_nature = old.flow_nature.and_then(|ident| {
resolve!(self.base; ident as
Nature(id) => {
return Some(id)
}
);
None
});
let potential_nature = old.potential_nature.and_then(|ident| {
resolve!(self.base; ident as
Nature(id) => {
return Some(id)
}
);
None
});
Discipline {
name: old.name,
flow_nature,
potential_nature,
continuous: old.continuous,
}
})
}
fn fold_nature(
&mut self,
id: NatureId,
nature_node: &AttributeNode<ast::Nature>,
) -> Option<AttributeNode<Nature>> {
let nature = &nature_node.contents;
let idt_nature = nature
.idt_nature
.and_then(|ident| {
resolve!(self.base; ident as
Nature(id) => {
return Some(id)
}
);
None
})
.unwrap_or(id);
let ddt_nature = nature
.ddt_nature
.and_then(|ident| {
resolve!(self.base; ident as
Nature(id) => {
return Some(id)
}
);
None
})
.unwrap_or(id);
let abstol = self.fold_constant_expr(nature.abstol);
let units = self.fold_constant_expr(nature.units);
let abstol = abstol?;
let units = units?;
Some(self.base.ast[id].copy_with(|old| Nature {
name: old.name,
abstol,
units,
access: old.access,
idt_nature,
ddt_nature,
}))
}
fn fold_port(&mut self, port: &AttributeNode<ast::Port>) -> Option<Port> {
let discipline = self.resolve_discipline(&port.contents.discipline)?;
let net = self.base.hir.nets.push(port.copy_with(|port| Net {
name: port.name,
discipline,
signed: port.signed,
net_type: port.net_type,
}));
Some(Port {
input: port.contents.input,
output: port.contents.output,
net,
})
}
fn fold_net(&mut self, net: &AttributeNode<ast::Net>) -> Option<AttributeNode<Net>> {
let discipline = self.resolve_discipline(&net.contents.discipline)?;
Some(net.copy_with(|old| Net {
name: old.name,
discipline,
signed: old.signed,
net_type: old.net_type,
}))
}
pub fn resolve_discipline(&mut self, ident: &Ident) -> Option<DisciplineId> {
match ident.name {
keywords::EMPTY_SYMBOL => {
self.base.error(Error {
error_type: Type::Unsupported(Unsupported::DefaultDiscipline),
source: ident.span,
});
None
}
_ => {
resolve!(self.base; ident as Discipline(id) => {return Some(id)});
None
}
}
}
pub fn fold_constant_expr(&mut self, expr: ExpressionId) -> Option<ExpressionId> {
ConstantExpressionFolder().fold(expr, &mut self.base)
}
}