use crate::analyzer_error::{
AnalyzerError, DuplicatedIdentifierKind, InvalidModifierKind, InvalidTestKind,
MultipleDefaultKind,
};
use crate::attribute::Attribute as Attr;
use crate::attribute::{AllowItem, EnumEncodingItem};
use crate::attribute_table;
use crate::definition_table::{self, Definition};
use crate::generic_inference_table::{self, PendingEntry};
use crate::namespace::Namespace;
use crate::namespace_table;
use crate::reference_table::{self, ReferenceCandidate};
use crate::symbol::ClockDomain as SymClockDomain;
use crate::symbol::Direction as SymDirection;
use crate::symbol::ModportDefault as SymModportDefault;
use crate::symbol::Type as SymType;
use crate::symbol::{
Affiliation, AliasInterfaceProperty, AliasModuleProperty, AliasPackageProperty, ConnectTarget,
ConnectTargetIdentifier, DocComment, DocCommentLine, EnumMemberProperty, EnumMemberValue,
EnumProperty, FunctionProperty, GenericBoundKind, GenericConstProperty,
GenericParameterProperty, InstanceProperty, InterfaceProperty, ModportFunctionMemberProperty,
ModportProperty, ModportVariableMemberProperty, ModuleProperty, PackageProperty, Parameter,
ParameterKind, ParameterProperty, Port, PortProperty, ProtoConstProperty,
ProtoInterfaceProperty, ProtoModuleProperty, ProtoPackageProperty, ProtoTypeDefProperty,
StructMemberProperty, StructProperty, Symbol, SymbolId, SymbolKind, TestProperty, TestType,
TypeDefProperty, TypeKind, TypeModifierKind, UnionMemberProperty, UnionProperty,
VariableProperty,
};
use crate::symbol_path::{GenericSymbolPath, GenericSymbolPathNamespace, SymbolPathNamespace};
use crate::symbol_table;
use crate::symbol_table::Bind as SymBind;
use crate::symbol_table::Connect as SymConnect;
use crate::symbol_table::Import as SymImport;
use crate::symbol_table::Msb as SymMsb;
use crate::type_dag::{self, Context, TypeDagCandidate};
use std::collections::{HashMap, HashSet};
use veryl_metadata::ClockType;
use veryl_metadata::{Build, ResetType};
use veryl_parser::ParolError;
use veryl_parser::doc_comment_table;
use veryl_parser::resource_table::{self, StrId};
use veryl_parser::token_range::TokenRange;
use veryl_parser::veryl_grammar_trait::*;
use veryl_parser::veryl_token::{Token, TokenSource};
use veryl_parser::veryl_walker::{Handler, HandlerPoint};
#[derive(Default)]
struct GenericContext {
params: Vec<Vec<SymbolId>>,
consts: Vec<Vec<SymbolId>>,
}
impl GenericContext {
pub fn push(&mut self) {
self.params.push(Vec::new());
self.consts.push(Vec::new());
}
pub fn pop(&mut self) -> (Vec<SymbolId>, Vec<SymbolId>) {
(self.params.pop().unwrap(), self.consts.pop().unwrap())
}
pub fn push_param(&mut self, id: SymbolId) {
self.params.last_mut().unwrap().push(id);
}
pub fn push_const(&mut self, id: SymbolId) {
self.consts.last_mut().unwrap().push(id);
}
}
#[derive(Default)]
pub struct CreateSymbolTable {
pub errors: Vec<AnalyzerError>,
build_opt: Build,
point: HandlerPoint,
namespace: Namespace,
project_namespace: Namespace,
module_namspace_depth: usize,
default_block: Option<StrId>,
for_identifier: Option<Token>,
anonymous_block: usize,
attribute_lines: HashSet<u32>,
struct_or_union: Option<StructOrUnion>,
enum_member_prefix: Option<String>,
enum_members: Vec<Option<SymbolId>>,
struct_union_members: Vec<Option<SymbolId>>,
declaration_items: Vec<SymbolId>,
affiliation: Vec<Affiliation>,
connect_target_identifiers: Vec<ConnectTargetIdentifier>,
parameter_connects: HashMap<Token, ConnectTarget>,
port_connects: HashMap<Token, ConnectTarget>,
parameters: Vec<Vec<Parameter>>,
ports: Vec<Vec<Port>>,
reference_paths: Vec<Vec<GenericSymbolPath>>,
needs_default_generic_argument: bool,
generic_context: GenericContext,
default_clock: Option<SymbolId>,
default_clock_candidates: Vec<SymbolId>,
default_reset: Option<SymbolId>,
defualt_reset_candidates: Vec<SymbolId>,
interface_members: HashMap<StrId, SymbolId>,
modport_member_ids: Vec<SymbolId>,
modport_ids: Vec<SymbolId>,
exist_clock_without_domain: bool,
in_proto: bool,
in_import: bool,
file_scope_import_item: Vec<GenericSymbolPathNamespace>,
file_scope_import_wildcard: Vec<GenericSymbolPathNamespace>,
is_public: bool,
identifier_factor_names: Vec<ExpressionIdentifier>,
in_named_argument: Vec<bool>,
in_argument_expression: Vec<()>,
type_dag_candidates: Vec<Vec<TypeDagCandidate>>,
with_member_reference: bool,
identifier_path: Vec<SymbolPathNamespace>,
select_dimension: Vec<usize>,
in_expression_identifier: Vec<()>,
in_select: bool,
reference_functions: Vec<GenericSymbolPath>,
}
#[derive(Clone)]
enum StructOrUnion {
InStruct,
InUnion,
}
impl CreateSymbolTable {
pub fn new(build_opt: &Build) -> Self {
Self {
build_opt: build_opt.clone(),
project_namespace: namespace_table::get_default(),
..Default::default()
}
}
fn insert_namespace(&self, token: &Token) {
if let TokenSource::File { path, .. } = token.source {
let namespace = self.get_namespace(token);
namespace_table::insert(token.id, path, &namespace);
}
}
fn get_anonymous_block_name(&mut self, prefix: Option<StrId>) -> (String, StrId) {
let name = if let Some(x) = prefix {
format!("{}@{}", x, self.anonymous_block)
} else {
format!("@{}", self.anonymous_block)
};
let id = resource_table::insert_str(&name);
self.anonymous_block += 1;
(name, id)
}
fn check_identifer_with_type_path(
&mut self,
identifier: &Identifier,
type_path: &GenericSymbolPath,
) -> bool {
let identifier_token = identifier.identifier_token.token;
let type_base = type_path.paths[0].base;
if identifier_token.text == type_base.text {
self.errors.push(AnalyzerError::duplicated_identifier(
&identifier_token.to_string(),
DuplicatedIdentifierKind::Normal,
&identifier_token.into(),
));
false
} else {
true
}
}
fn check_identifer_with_type(&mut self, identifier: &Identifier, r#type: &SymType) -> bool {
if let Some(user_defined) = r#type.get_user_defined() {
self.check_identifer_with_type_path(identifier, &user_defined.path)
} else {
true
}
}
fn get_namespace(&self, token: &Token) -> Namespace {
let attrs = attribute_table::get(token);
let mut ret = self.namespace.clone();
ret.define_context = attrs.as_slice().into();
ret
}
fn insert_symbol(&mut self, token: &Token, kind: SymbolKind, public: bool) -> Option<SymbolId> {
let doc_comment = self.create_doc_comment(token);
let mut symbol = Symbol::new(token, kind, &self.get_namespace(token), public, doc_comment);
if attribute_table::contains(token, Attr::Allow(AllowItem::UnusedVariable)) {
symbol.allow_unused = true;
}
let id = symbol_table::insert(token, symbol);
if id.is_some() {
self.insert_namespace(token);
} else {
let canonical = resource_table::canonical_str_id(token.text);
let kind = if canonical != token.text {
DuplicatedIdentifierKind::RawIdentifier {
raw: token.text.to_string(),
}
} else {
DuplicatedIdentifierKind::Normal
};
self.errors.push(AnalyzerError::duplicated_identifier(
&canonical.to_string(),
kind,
&token.into(),
));
}
id
}
fn create_doc_comment(&self, token: &Token) -> DocComment {
let line = token.line;
if let TokenSource::File { path, .. } = token.source {
if line == 0 {
DocComment::default()
} else if let Some(doc_comment) = doc_comment_table::get(path, line) {
DocComment(vec![DocCommentLine {
text: doc_comment,
line,
}])
} else {
let mut candidate_line = line - 1;
while self.attribute_lines.contains(&candidate_line) {
if candidate_line == 0 {
break;
}
candidate_line -= 1;
}
let mut ret = Vec::new();
while let Some(doc_comment) = doc_comment_table::get(path, candidate_line) {
ret.push(DocCommentLine {
text: doc_comment,
line: candidate_line,
});
candidate_line -= 1;
}
ret.reverse();
DocComment(ret)
}
} else {
DocComment::default()
}
}
fn insert_clock_domain(&mut self, clock_domain: &ClockDomain) -> SymClockDomain {
if clock_domain.identifier.identifier_token.to_string() == "_" {
return SymClockDomain::Implicit;
}
let token = &clock_domain.identifier.identifier_token.token;
let id = if let Ok(symbol) = symbol_table::resolve((token, &self.get_namespace(token))) {
symbol.found.id
} else {
let symbol = Symbol::new(
token,
SymbolKind::ClockDomain,
&self.get_namespace(token),
false,
DocComment::default(),
);
symbol_table::insert(token, symbol).unwrap()
};
SymClockDomain::Explicit(id)
}
fn get_signal_prefix_suffix(&self, kind: TypeKind) -> (Option<String>, Option<String>) {
match kind {
TypeKind::Clock => match self.build_opt.clock_type {
ClockType::PosEdge => {
let prefix = self.build_opt.clock_posedge_prefix.clone();
let suffix = self.build_opt.clock_posedge_suffix.clone();
return (prefix, suffix);
}
ClockType::NegEdge => {
let prefix = self.build_opt.clock_negedge_prefix.clone();
let suffix = self.build_opt.clock_negedge_suffix.clone();
return (prefix, suffix);
}
},
TypeKind::Reset => match self.build_opt.reset_type {
ResetType::AsyncHigh | ResetType::SyncHigh => {
let prefix = self.build_opt.reset_high_prefix.clone();
let suffix = self.build_opt.reset_high_suffix.clone();
return (prefix, suffix);
}
ResetType::AsyncLow | ResetType::SyncLow => {
let prefix = self.build_opt.reset_low_prefix.clone();
let suffix = self.build_opt.reset_low_suffix.clone();
return (prefix, suffix);
}
},
_ => {}
}
(None, None)
}
fn push_default_clock_reset(&mut self, identifier: &Token, id: SymbolId, kind: &SymbolKind) {
let r#type = match kind {
SymbolKind::Variable(x) => &x.r#type,
SymbolKind::Port(x) => &x.r#type,
_ => unreachable!(),
};
let can_be_default_clock = r#type.can_be_default_clock();
let can_be_default_reset = r#type.can_be_default_reset();
let in_module_top_hierarchy = *self.affiliation.last().unwrap() == Affiliation::Module
&& self.namespace.depth() == self.module_namspace_depth;
if let Some(default_modifier) = r#type.find_modifier(&TypeModifierKind::Default) {
let error_reason = if !in_module_top_hierarchy {
Some(InvalidModifierKind::NotTopModule)
} else if !(can_be_default_clock || can_be_default_reset) {
Some(InvalidModifierKind::NotClockReset)
} else {
None
};
if let Some(reason) = error_reason {
self.errors.push(AnalyzerError::invalid_modifier(
&default_modifier.to_string(),
reason,
&default_modifier.token.token.into(),
));
return;
}
if can_be_default_clock && self.default_clock.is_none() {
self.default_clock = Some(id);
} else if can_be_default_clock {
self.errors.push(AnalyzerError::multiple_default(
MultipleDefaultKind::Clock,
&identifier.to_string(),
&identifier.into(),
));
}
if can_be_default_reset && self.default_reset.is_none() {
self.default_reset = Some(id);
} else if can_be_default_reset {
self.errors.push(AnalyzerError::multiple_default(
MultipleDefaultKind::Reset,
&identifier.to_string(),
&identifier.into(),
));
}
} else if in_module_top_hierarchy {
if can_be_default_clock {
self.default_clock_candidates.push(id);
} else if can_be_default_reset {
self.defualt_reset_candidates.push(id);
}
}
}
fn check_missing_clock_domain(&mut self, token: &Token, r#type: &SymType) {
if r#type.kind.is_clock() {
if self.exist_clock_without_domain {
self.errors
.push(AnalyzerError::missing_clock_domain(&token.into()));
}
self.exist_clock_without_domain = true;
}
}
fn apply_file_scope_import(&self) {
for x in &self.file_scope_import_item {
let import = SymImport {
path: x.clone(),
namespace: self.namespace.clone(),
wildcard: false,
};
symbol_table::add_import(import);
}
for x in &self.file_scope_import_wildcard {
let import = SymImport {
path: x.clone(),
namespace: self.namespace.clone(),
wildcard: true,
};
symbol_table::add_import(import);
}
}
fn push_interface_member(&mut self, identifier: &Identifier, symbol_id: SymbolId) {
if self
.affiliation
.last()
.map(|x| matches!(x, Affiliation::Interface))
.unwrap_or(false)
{
let text = identifier.text();
self.interface_members.insert(text, symbol_id);
}
}
fn link_modport_members(&self) {
for id in &self.modport_member_ids {
let mut mp_member = symbol_table::get(*id).unwrap();
match mp_member.kind {
SymbolKind::ModportFunctionMember(_) => {
if let Some(id) = self.interface_members.get(&mp_member.token.text) {
let property = ModportFunctionMemberProperty { function: *id };
let kind = SymbolKind::ModportFunctionMember(property);
mp_member.kind = kind;
symbol_table::update(mp_member);
}
}
SymbolKind::ModportVariableMember(x) => {
if let Some(id) = self.interface_members.get(&mp_member.token.text) {
let mut property = x;
property.variable = *id;
let kind = SymbolKind::ModportVariableMember(property);
mp_member.kind = kind;
symbol_table::update(mp_member);
}
}
_ => (),
}
}
}
fn expand_modport_default_member(&mut self, interface_id: SymbolId) {
let interface_namesapce = symbol_table::get(interface_id)
.map(|x| x.inner_namespace())
.unwrap();
for id in &self.modport_ids.clone() {
let mut mp = symbol_table::get(*id).unwrap();
if let SymbolKind::Modport(ref x) = mp.kind {
let mut members = x.members.clone();
members.append(&mut self.get_modport_default_members(&mp, &interface_namesapce));
let property = ModportProperty {
interface: interface_id,
members,
default: x.default.clone(),
};
let kind = SymbolKind::Modport(property);
mp.kind = kind;
symbol_table::update(mp);
}
}
}
fn get_modport_default_members(
&mut self,
mp: &Symbol,
interface_namesapce: &Namespace,
) -> Vec<SymbolId> {
let mut ret = Vec::new();
if let SymbolKind::Modport(ref x) = mp.kind
&& let Some(ref default) = x.default
{
let default_member_directions = Self::collect_modport_default_member_target_directions(
default,
interface_namesapce,
);
let explicit_members: HashSet<_> = x
.members
.iter()
.map(|x| symbol_table::get(*x).unwrap().token.text)
.collect();
let mut default_members: Vec<_> = self
.interface_members
.iter()
.filter(|(text, id)| {
if explicit_members.contains(text) {
false
} else if matches!(default, SymModportDefault::Same(_)) {
true
} else {
let symbol = symbol_table::get(**id).unwrap();
matches!(symbol.kind, SymbolKind::Variable(_))
}
})
.collect();
default_members.sort_by(|x, y| x.1.cmp(y.1));
let namespace = mp.inner_namespace();
for (text, id) in default_members {
let direction = match default {
SymModportDefault::Input => Some(SymDirection::Input),
SymModportDefault::Output => Some(SymDirection::Output),
SymModportDefault::Same(_) => default_member_directions.get(text).copied(),
SymModportDefault::Converse(_) => {
default_member_directions.get(text).map(|x| x.converse())
}
};
let Some(direction) = direction else {
continue;
};
let path = mp.token.source.get_path().unwrap();
let token = Token::generate(*text, path);
namespace_table::insert(token.id, path, &namespace);
symbol_table::add_reference(*id, &token);
let kind = if matches!(direction, SymDirection::Import) {
let property = ModportFunctionMemberProperty { function: *id };
SymbolKind::ModportFunctionMember(property)
} else {
let property = ModportVariableMemberProperty {
direction,
variable: *id,
};
SymbolKind::ModportVariableMember(property)
};
let symbol = Symbol::new(&token, kind, &namespace, false, DocComment::default());
if let Some(id) = symbol_table::insert(&token, symbol) {
ret.push(id);
}
}
}
ret
}
fn collect_modport_default_member_target_directions(
default: &SymModportDefault,
namespace: &Namespace,
) -> HashMap<StrId, SymDirection> {
let mut ret: HashMap<_, _> = HashMap::new();
match default {
SymModportDefault::Same(targets) | SymModportDefault::Converse(targets) => {
for target in targets {
let Ok(mp_symbol) = symbol_table::resolve((target, namespace)) else {
continue;
};
let SymbolKind::Modport(ref modport) = mp_symbol.found.kind else {
continue;
};
for member in &modport.members {
let Some(member_symbol) = symbol_table::get(*member) else {
continue;
};
if let SymbolKind::ModportVariableMember(member) = member_symbol.kind {
ret.insert(member_symbol.token.text, member.direction);
} else if matches!(default, SymModportDefault::Same(_))
&& matches!(member_symbol.kind, SymbolKind::ModportFunctionMember(_))
{
ret.insert(member_symbol.token.text, SymDirection::Import);
}
}
}
}
_ => {}
}
ret
}
fn push_declaration_item(&mut self, id: SymbolId) {
if matches!(
self.affiliation.last(),
Some(&Affiliation::Interface) | Some(&Affiliation::Package)
) {
self.declaration_items.push(id);
}
}
fn push_type_dag_cand(&mut self) {
self.type_dag_candidates.push(Vec::new());
}
fn pop_type_dag_cand(&mut self, symbol: Option<(SymbolId, Context, bool)>) {
if let Some(candidates) = self.type_dag_candidates.pop() {
for mut cand in candidates {
if let Some(symbol) = &symbol {
cand.set_parent((symbol.0, symbol.1));
}
type_dag::add(cand);
}
}
if let Some(x) = self.type_dag_candidates.last_mut()
&& let Some(symbol) = &symbol
{
let import = if symbol.2 {
let mut import = self.file_scope_import_item.clone();
import.extend(self.file_scope_import_wildcard.clone());
import
} else {
Vec::new()
};
let cand = TypeDagCandidate::Symbol {
id: symbol.0,
context: symbol.1,
project_namespace: self.project_namespace.clone(),
parent: None,
import,
};
x.push(cand);
}
}
fn insert_reference_functions(&mut self, id: SymbolId) {
let funcs = self.reference_functions.drain(..).collect();
symbol_table::add_reference_functions(id, funcs);
}
fn is_in_expression_identifier(&self) -> bool {
!self.in_expression_identifier.is_empty()
}
}
impl Handler for CreateSymbolTable {
fn set_point(&mut self, p: HandlerPoint) {
self.point = p;
}
}
fn scoped_identifier_tokens(arg: &ScopedIdentifier) -> Vec<Token> {
let mut ret = Vec::new();
ret.push(arg.identifier().token);
for x in &arg.scoped_identifier_list {
ret.push(x.identifier.identifier_token.token);
}
ret
}
impl VerylGrammarTrait for CreateSymbolTable {
fn select(&mut self, _arg: &Select) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.in_select = true;
}
HandlerPoint::After => {
self.in_select = false;
if self.is_in_expression_identifier() {
*self.select_dimension.last_mut().unwrap() += 1;
}
}
}
Ok(())
}
fn lsb(&mut self, arg: &Lsb) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point
&& !(self.is_in_expression_identifier() && self.in_select)
{
self.errors
.push(AnalyzerError::invalid_lsb(&arg.lsb_token.token.into()));
}
Ok(())
}
fn msb(&mut self, arg: &Msb) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
if self.is_in_expression_identifier() && self.in_select {
let token = arg.msb_token.token;
let path = self.identifier_path.last().unwrap().clone();
let dimension = self.select_dimension.last().unwrap();
let msb = SymMsb {
token,
path,
dimension: *dimension,
};
symbol_table::add_msb(msb);
} else {
self.errors
.push(AnalyzerError::invalid_msb(&arg.msb_token.token.into()));
}
}
Ok(())
}
fn identifier(&mut self, arg: &Identifier) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
self.insert_namespace(&arg.identifier_token.token);
if self.is_in_expression_identifier() {
self.identifier_path
.last_mut()
.unwrap()
.0
.push(arg.identifier_token.token.text);
self.identifier_path.last_mut().unwrap().1 = self.namespace.clone();
}
}
Ok(())
}
fn dollar_identifier(&mut self, arg: &DollarIdentifier) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
self.insert_namespace(&arg.dollar_identifier_token.token);
}
Ok(())
}
fn hierarchical_identifier(&mut self, arg: &HierarchicalIdentifier) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
reference_table::add(arg.into());
}
Ok(())
}
fn scoped_identifier(&mut self, arg: &ScopedIdentifier) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
if !self.with_member_reference {
reference_table::add((arg, self.in_import).into());
}
if let ScopedIdentifierGroup::DollarIdentifier(x) = arg.scoped_identifier_group.as_ref()
&& x.dollar_identifier.dollar_identifier_token.to_string() == "$sv"
{
let mut namespace = Namespace::new();
for (i, token) in scoped_identifier_tokens(arg).iter().enumerate() {
if i != 0 {
let symbol = Symbol::new(
token,
SymbolKind::SystemVerilog,
&namespace,
false,
DocComment::default(),
);
let _ = symbol_table::insert(token, symbol);
}
namespace.push(token.text);
}
}
let ident = arg.identifier().token;
if ident.to_string() != "_" {
let path: GenericSymbolPath = arg.into();
let namespace = self.get_namespace(&ident);
let cand = TypeDagCandidate::Path {
path: Box::new(path),
namespace,
project_namespace: self.project_namespace.clone(),
parent: None,
};
if let Some(x) = self.type_dag_candidates.last_mut() {
x.push(cand);
}
}
if let Some(paths) = self.reference_paths.last_mut() {
let path: GenericSymbolPath = arg.into();
paths.push(path);
}
}
Ok(())
}
fn expression_identifier(&mut self, arg: &ExpressionIdentifier) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.with_member_reference = true;
if *self.in_named_argument.last().unwrap_or(&false)
&& !self.in_argument_expression.is_empty()
{
let func_pos = self.identifier_factor_names.len() - 2;
let function = self.identifier_factor_names.get(func_pos).unwrap().clone();
let cand = ReferenceCandidate::NamedArgument {
arg: arg.clone(),
function,
};
reference_table::add(cand);
} else {
reference_table::add(arg.into());
}
self.identifier_path.push(SymbolPathNamespace::default());
self.select_dimension.push(0);
self.in_expression_identifier.push(());
}
HandlerPoint::After => {
self.connect_target_identifiers.push(arg.into());
self.with_member_reference = false;
self.identifier_path.pop();
self.select_dimension.pop();
self.in_expression_identifier.pop();
}
}
Ok(())
}
fn generic_arg_identifier(&mut self, arg: &GenericArgIdentifier) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.with_member_reference = true;
reference_table::add(arg.into());
}
HandlerPoint::After => self.with_member_reference = false,
}
Ok(())
}
fn identifier_factor(&mut self, arg: &IdentifierFactor) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.identifier_factor_names
.push(*arg.expression_identifier.clone());
if let Some(x) = arg.identifier_factor_opt.as_ref()
&& let IdentifierFactorOptGroup::FunctionCall(fc) =
x.identifier_factor_opt_group.as_ref()
{
let path: GenericSymbolPath = arg.expression_identifier.as_ref().into();
self.reference_functions.push(path.clone());
let has_generic_args = path
.paths
.last()
.map(|p| !p.arguments.is_empty())
.unwrap_or(false);
if !has_generic_args {
let arg_exprs: Vec<_> =
if let Some(list) = &fc.function_call.function_call_opt {
let items: Vec<&ArgumentItem> = list.argument_list.as_ref().into();
items
.iter()
.filter(|item| item.argument_item_opt.is_none())
.map(|item| (*item.argument_expression.expression).clone())
.collect()
} else {
Vec::new()
};
let call_token = arg
.expression_identifier
.scoped_identifier
.identifier()
.token;
let namespace = self.namespace.clone();
generic_inference_table::push_pending(PendingEntry {
call_token_id: call_token.id,
call_token,
path,
arg_exprs,
namespace,
});
}
}
}
HandlerPoint::After => {
self.identifier_factor_names.pop();
}
}
Ok(())
}
fn argument_item(&mut self, arg: &ArgumentItem) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.in_named_argument.push(arg.argument_item_opt.is_some());
}
HandlerPoint::After => {
self.in_named_argument.pop();
}
}
Ok(())
}
fn argument_expression(&mut self, _arg: &ArgumentExpression) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.in_argument_expression.push(());
}
HandlerPoint::After => {
self.in_argument_expression.pop();
}
}
Ok(())
}
fn struct_constructor_item(&mut self, arg: &StructConstructorItem) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
let cand = ReferenceCandidate::StructConstructorItem {
arg: arg.clone(),
r#type: self.identifier_factor_names.last().unwrap().clone(),
};
reference_table::add(cand);
}
Ok(())
}
fn attribute(&mut self, arg: &Attribute) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
let line = arg.hash_l_bracket.hash_l_bracket_token.token.line;
self.attribute_lines.insert(line);
}
Ok(())
}
fn statement_block(&mut self, _arg: &StatementBlock) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
let (_, name) = self.get_anonymous_block_name(None);
self.namespace.push(name);
self.affiliation.push(Affiliation::StatementBlock);
}
HandlerPoint::After => {
self.namespace.pop();
self.affiliation.pop();
}
}
Ok(())
}
fn let_statement(&mut self, arg: &LetStatement) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
let mut r#type: SymType = if let Some(ref x) = arg.let_statement_opt {
x.array_type.as_ref().into()
} else {
SymType::create_inferred((&arg.identifier.identifier_token).into())
};
if !self.check_identifer_with_type(&arg.identifier, &r#type) {
return Ok(());
}
r#type.is_const = true;
let affiliation = self.affiliation.last().cloned().unwrap();
let (prefix, suffix) = self.get_signal_prefix_suffix(r#type.kind.clone());
let clock_domain = if let Some(ref x) = arg.let_statement_opt
&& let Some(ref y) = x.let_statement_opt0
{
self.insert_clock_domain(&y.clock_domain)
} else if affiliation == Affiliation::Module {
self.check_missing_clock_domain(&arg.identifier.identifier_token.token, &r#type);
SymClockDomain::Implicit
} else {
SymClockDomain::None
};
let property = VariableProperty {
r#type,
affiliation,
prefix,
suffix,
clock_domain,
loop_variable: false,
};
let kind = SymbolKind::Variable(property);
if let Some(id) =
self.insert_symbol(&arg.identifier.identifier_token.token, kind.clone(), false)
{
self.push_default_clock_reset(&arg.identifier.identifier_token.token, id, &kind);
}
}
Ok(())
}
fn identifier_statement(&mut self, arg: &IdentifierStatement) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.identifier_factor_names
.push(*arg.expression_identifier.clone());
if let IdentifierStatementGroup::Assignment(x) =
arg.identifier_statement_group.as_ref()
&& let AssignmentGroup::DiamondOperator(_) =
x.assignment.assignment_group.as_ref()
{
let connect = SymConnect::Statement(
arg.expression_identifier.as_ref().clone(),
x.assignment.expression.as_ref().clone(),
);
symbol_table::add_connect(connect);
}
if matches!(
arg.identifier_statement_group.as_ref(),
IdentifierStatementGroup::FunctionCall(_)
) {
let path: GenericSymbolPath = arg.expression_identifier.as_ref().into();
self.reference_functions.push(path);
}
}
HandlerPoint::After => {
self.identifier_factor_names.pop();
}
}
Ok(())
}
fn for_statement(&mut self, arg: &ForStatement) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
let (_, name) = self.get_anonymous_block_name(None);
self.namespace.push(name);
let r#type = SymType {
modifier: Vec::new(),
kind: TypeKind::I32,
width: Vec::new(),
array: Vec::new(),
array_type: None,
is_const: false,
token: TokenRange::default(),
};
let affiliation = self.affiliation.last().cloned().unwrap();
let property = VariableProperty {
r#type,
affiliation,
prefix: None,
suffix: None,
clock_domain: SymClockDomain::None,
loop_variable: true,
};
let kind = SymbolKind::Variable(property);
self.insert_symbol(&arg.identifier.identifier_token.token, kind, false);
}
HandlerPoint::After => {
self.namespace.pop();
}
}
Ok(())
}
fn let_declaration(&mut self, arg: &LetDeclaration) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
let mut r#type: SymType = if let Some(ref x) = arg.let_declaration_opt {
x.array_type.as_ref().into()
} else {
SymType::create_inferred((&arg.identifier.identifier_token).into())
};
if !self.check_identifer_with_type(&arg.identifier, &r#type) {
return Ok(());
}
r#type.is_const = true;
let affiliation = self.affiliation.last().cloned().unwrap();
let (prefix, suffix) = self.get_signal_prefix_suffix(r#type.kind.clone());
let clock_domain = if let Some(ref x) = arg.let_declaration_opt
&& let Some(ref y) = x.let_declaration_opt0
{
self.insert_clock_domain(&y.clock_domain)
} else if affiliation == Affiliation::Module {
self.check_missing_clock_domain(&arg.identifier.identifier_token.token, &r#type);
SymClockDomain::Implicit
} else {
SymClockDomain::None
};
let property = VariableProperty {
r#type,
affiliation,
prefix,
suffix,
clock_domain,
loop_variable: false,
};
let kind = SymbolKind::Variable(property);
if let Some(id) =
self.insert_symbol(&arg.identifier.identifier_token.token, kind.clone(), false)
{
self.push_declaration_item(id);
self.push_default_clock_reset(&arg.identifier.identifier_token.token, id, &kind);
}
}
Ok(())
}
fn var_declaration(&mut self, arg: &VarDeclaration) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
let r#type: SymType = if let Some(ref x) = arg.var_declaration_opt {
x.array_type.as_ref().into()
} else {
SymType::create_inferred((&arg.identifier.identifier_token).into())
};
if !self.check_identifer_with_type(&arg.identifier, &r#type) {
return Ok(());
}
let affiliation = self.affiliation.last().cloned().unwrap();
let (prefix, suffix) = self.get_signal_prefix_suffix(r#type.kind.clone());
let clock_domain = if let Some(ref x) = arg.var_declaration_opt
&& let Some(ref y) = x.var_declaration_opt0
{
self.insert_clock_domain(&y.clock_domain)
} else if affiliation == Affiliation::Module {
self.check_missing_clock_domain(&arg.identifier.identifier_token.token, &r#type);
SymClockDomain::Implicit
} else {
SymClockDomain::None
};
let property = VariableProperty {
r#type,
affiliation,
prefix,
suffix,
clock_domain,
loop_variable: false,
};
let kind = SymbolKind::Variable(property);
if let Some(id) =
self.insert_symbol(&arg.identifier.identifier_token.token, kind.clone(), false)
{
self.push_declaration_item(id);
self.push_default_clock_reset(&arg.identifier.identifier_token.token, id, &kind);
self.push_interface_member(&arg.identifier, id);
}
}
Ok(())
}
fn const_declaration(&mut self, arg: &ConstDeclaration) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.push_type_dag_cand();
}
HandlerPoint::After => {
let token = arg.identifier.identifier_token.token;
let value = Some(*arg.expression.clone());
let r#type = if let Some(ref opt) = arg.const_declaration_opt {
match &*opt.const_declaration_opt_group {
ConstDeclarationOptGroup::ArrayType(x) => {
let r#type: SymType = x.array_type.as_ref().into();
if !self.check_identifer_with_type(&arg.identifier, &r#type) {
self.pop_type_dag_cand(None);
return Ok(());
}
r#type
}
ConstDeclarationOptGroup::Type(_) => SymType {
modifier: vec![],
kind: TypeKind::Type,
width: vec![],
array: vec![],
array_type: None,
is_const: false,
token: opt.const_declaration_opt_group.as_ref().into(),
},
}
} else {
SymType::create_inferred((&arg.identifier.identifier_token).into())
};
let property = ParameterProperty {
token,
r#type,
kind: ParameterKind::Const,
value,
};
let kind = SymbolKind::Parameter(property);
if let Some(id) = self.insert_symbol(&token, kind, false) {
self.push_declaration_item(id);
self.pop_type_dag_cand(Some((id, Context::Const, false)));
} else {
self.pop_type_dag_cand(None);
}
}
}
Ok(())
}
fn gen_declaration(&mut self, arg: &GenDeclaration) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.push_type_dag_cand();
}
HandlerPoint::After => {
let token = arg.identifier.identifier_token.token;
let value = *arg.expression.clone();
let bound = match arg.gen_declaration_group.as_ref() {
GenDeclarationGroup::GenericProtoBound(x) => {
let r#type: SymType = x.generic_proto_bound.as_ref().into();
if !self.check_identifer_with_type(&arg.identifier, &r#type) {
return Ok(());
}
GenericBoundKind::Proto(Box::new(r#type))
}
GenDeclarationGroup::Type(_) => GenericBoundKind::Type,
};
let kind = SymbolKind::GenericConst(GenericConstProperty { bound, value });
if let Some(id) = self.insert_symbol(&token, kind, false) {
self.push_declaration_item(id);
self.pop_type_dag_cand(Some((id, Context::Const, false)));
self.generic_context.push_const(id);
} else {
self.pop_type_dag_cand(None);
}
}
}
Ok(())
}
fn modport_declaration(&mut self, arg: &ModportDeclaration) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.namespace.push(arg.identifier.text());
self.push_type_dag_cand();
}
HandlerPoint::After => {
let mut members = Vec::new();
let items: Vec<_> = if let Some(ref x) = arg.modport_declaration_opt {
x.modport_list.as_ref().into()
} else {
Vec::new()
};
for item in items {
let kind = match &*item.direction {
Direction::Modport(_) => {
continue;
}
Direction::Import(_) => {
let property = ModportFunctionMemberProperty {
function: SymbolId::default(),
};
SymbolKind::ModportFunctionMember(property)
}
_ => {
let direction: crate::symbol::Direction =
item.direction.as_ref().into();
let property = ModportVariableMemberProperty {
direction,
variable: SymbolId::default(),
};
SymbolKind::ModportVariableMember(property)
}
};
if let Some(id) =
self.insert_symbol(&item.identifier.identifier_token.token, kind, false)
{
members.push(id);
self.modport_member_ids.push(id);
}
}
self.namespace.pop();
let default = if let Some(ref x) = arg.modport_declaration_opt0 {
match x.modport_default.as_ref() {
ModportDefault::Input(_) => Some(crate::symbol::ModportDefault::Input),
ModportDefault::Output(_) => Some(crate::symbol::ModportDefault::Output),
ModportDefault::SameLParenModportDefaultListRParen(x) => {
let targets: Vec<_> = x.modport_default_list.as_ref().into();
for target in &targets {
reference_table::add((*target).into());
}
let modports: Vec<_> =
targets.iter().map(|x| x.identifier_token.token).collect();
Some(crate::symbol::ModportDefault::Same(modports))
}
ModportDefault::ConverseLParenModportDefaultListRParen(x) => {
let targets: Vec<_> = x.modport_default_list.as_ref().into();
for target in &targets {
reference_table::add((*target).into());
}
let modports: Vec<_> =
targets.iter().map(|x| x.identifier_token.token).collect();
Some(crate::symbol::ModportDefault::Converse(modports))
}
}
} else {
None
};
let property = ModportProperty {
interface: SymbolId(0),
members,
default,
};
let kind = SymbolKind::Modport(property);
if let Some(id) =
self.insert_symbol(&arg.identifier.identifier_token.token, kind, false)
{
self.push_declaration_item(id);
self.modport_ids.push(id);
self.pop_type_dag_cand(Some((id, Context::Modport, false)));
} else {
self.pop_type_dag_cand(None);
}
}
}
Ok(())
}
fn modport_item(&mut self, arg: &ModportItem) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
reference_table::add(arg.into());
}
Ok(())
}
fn enum_declaration(&mut self, arg: &EnumDeclaration) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
let name = arg.identifier.text();
self.namespace.push(name);
self.enum_member_prefix = Some(arg.identifier.identifier_token.to_string());
for attr in attribute_table::get(&arg.r#enum.enum_token.token) {
if let Attr::EnumMemberPrefix(x) = attr {
self.enum_member_prefix = Some(x.to_string());
}
}
self.push_type_dag_cand();
}
HandlerPoint::After => {
self.namespace.pop();
self.enum_member_prefix = None;
let enum_type: Option<SymType> = arg
.enum_declaration_opt
.as_ref()
.map(|x| x.scalar_type.as_ref().into());
if let Some(ref r#type) = enum_type
&& !self.check_identifer_with_type(&arg.identifier, r#type)
{
self.pop_type_dag_cand(None);
return Ok(());
}
let mut enum_encoding = EnumEncodingItem::Sequential;
for attr in attribute_table::get(&arg.r#enum.enum_token.token) {
if let Attr::EnumEncoding(x) = attr {
enum_encoding = x;
}
}
let property = EnumProperty {
r#type: enum_type,
width: 0,
members: self.enum_members.drain(0..).flatten().collect(),
encoding: enum_encoding,
};
let kind = SymbolKind::Enum(property);
if let Some(id) =
self.insert_symbol(&arg.identifier.identifier_token.token, kind, false)
{
self.push_declaration_item(id);
self.pop_type_dag_cand(Some((id, Context::Enum, false)));
} else {
self.pop_type_dag_cand(None);
}
}
}
Ok(())
}
fn enum_item(&mut self, arg: &EnumItem) -> Result<(), ParolError> {
if let HandlerPoint::After = self.point {
let token = arg.identifier.identifier_token.token;
let value = if let Some(x) = &arg.enum_item_opt {
EnumMemberValue::ExplicitValue(x.expression.as_ref().clone(), None)
} else {
EnumMemberValue::ImplicitValue(0)
};
let prefix = self.enum_member_prefix.clone().unwrap();
let property = EnumMemberProperty { value, prefix };
let kind = SymbolKind::EnumMember(property);
let id = self.insert_symbol(&token, kind, false);
self.enum_members.push(id);
let prefix = self.enum_member_prefix.clone().unwrap();
let path = token.source.get_path().unwrap();
let text = resource_table::insert_str(&format!("{prefix}_{}", token.text));
let mangled_token = Token::generate(text, path);
let kind = SymbolKind::EnumMemberMangled;
let namespace = self.namespace.pop();
self.insert_symbol(&mangled_token, kind, false);
if let Some(namespace) = namespace {
self.namespace.push(namespace);
}
}
Ok(())
}
fn struct_union_declaration(&mut self, arg: &StructUnionDeclaration) -> Result<(), ParolError> {
let name = arg.identifier.text();
match self.point {
HandlerPoint::Before => {
self.struct_or_union = match &*arg.struct_union {
StructUnion::Struct(_) => Some(StructOrUnion::InStruct),
StructUnion::Union(_) => Some(StructOrUnion::InUnion),
};
if arg.struct_union_declaration_opt.is_some() {
self.generic_context.push();
}
self.namespace.push(name);
self.push_type_dag_cand();
}
HandlerPoint::After => {
self.struct_or_union = None;
self.namespace.pop();
let generic_parameters = if arg.struct_union_declaration_opt.is_some() {
self.generic_context.pop().0
} else {
vec![]
};
let members: Vec<_> = self.struct_union_members.drain(0..).flatten().collect();
let (context, kind) = match &*arg.struct_union {
StructUnion::Struct(_) => {
let property = StructProperty {
members,
generic_parameters,
generic_references: vec![],
};
(Context::Struct, SymbolKind::Struct(property))
}
StructUnion::Union(_) => {
let property = UnionProperty {
members,
generic_parameters,
generic_references: vec![],
};
(Context::Union, SymbolKind::Union(property))
}
};
if let Some(id) =
self.insert_symbol(&arg.identifier.identifier_token.token, kind, false)
{
self.push_declaration_item(id);
self.pop_type_dag_cand(Some((id, context, false)));
} else {
self.pop_type_dag_cand(None);
}
}
}
Ok(())
}
fn type_def_declaration(&mut self, arg: &TypeDefDeclaration) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.push_type_dag_cand();
}
HandlerPoint::After => {
let r#type = arg.array_type.as_ref().into();
if !self.check_identifer_with_type(&arg.identifier, &r#type) {
self.pop_type_dag_cand(None);
return Ok(());
}
let property = TypeDefProperty { r#type };
let kind = SymbolKind::TypeDef(property);
if let Some(id) =
self.insert_symbol(&arg.identifier.identifier_token.token, kind, false)
{
self.push_declaration_item(id);
self.pop_type_dag_cand(Some((id, Context::TypeDef, false)));
} else {
self.pop_type_dag_cand(None);
}
}
}
Ok(())
}
fn struct_union_item(&mut self, arg: &StructUnionItem) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
let r#type: SymType = arg.scalar_type.as_ref().into();
if !self.check_identifer_with_type(&arg.identifier, &r#type) {
return Ok(());
}
let kind = match self.struct_or_union.clone().unwrap() {
StructOrUnion::InStruct => {
let property = StructMemberProperty { r#type };
SymbolKind::StructMember(property)
}
StructOrUnion::InUnion => {
let property = UnionMemberProperty { r#type };
SymbolKind::UnionMember(property)
}
};
let id = self.insert_symbol(&arg.identifier.identifier_token.token, kind, false);
self.struct_union_members.push(id);
}
Ok(())
}
fn inst_declaration(&mut self, arg: &InstDeclaration) -> Result<(), ParolError> {
if let HandlerPoint::After = self.point {
let inst = &arg.component_instantiation;
let array: Vec<_> = if let Some(ref x) = inst.component_instantiation_opt0 {
let x: Vec<_> = x.array.as_ref().into();
x.iter().map(|x| (*x).clone()).collect()
} else {
Vec::new()
};
let type_name: GenericSymbolPath = inst.scoped_identifier.as_ref().into();
if !self.check_identifer_with_type_path(&inst.identifier, &type_name) {
return Ok(());
}
let parameter_connects = self.parameter_connects.drain().collect();
let port_connects = self.port_connects.drain().collect();
let clock_domain = if let Some(ref x) = inst.component_instantiation_opt {
self.insert_clock_domain(&x.clock_domain)
} else {
SymClockDomain::None
};
let property = InstanceProperty {
array,
type_name,
parameter_connects,
port_connects,
clock_domain,
};
let kind = SymbolKind::Instance(property);
self.insert_symbol(&inst.identifier.identifier_token.token, kind, false);
}
Ok(())
}
fn connect_declaration(&mut self, arg: &ConnectDeclaration) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
let connect = SymConnect::Declaration(
arg.hierarchical_identifier.as_ref().clone(),
arg.expression.as_ref().clone(),
);
symbol_table::add_connect(connect);
}
Ok(())
}
fn bind_declaration(&mut self, arg: &BindDeclaration) -> Result<(), ParolError> {
if let HandlerPoint::After = self.point {
let inst = &arg.component_instantiation;
let parameter_connects = self.parameter_connects.drain().collect();
let port_connects = self.port_connects.drain().collect();
let type_name: GenericSymbolPath = inst.scoped_identifier.as_ref().into();
if !self.check_identifer_with_type_path(&inst.identifier, &type_name) {
return Ok(());
}
let clock_domain = if let Some(ref x) = inst.component_instantiation_opt {
self.insert_clock_domain(&x.clock_domain)
} else {
SymClockDomain::None
};
let property = InstanceProperty {
array: Vec::new(),
type_name,
parameter_connects,
port_connects,
clock_domain,
};
let doc_comment = self.create_doc_comment(&inst.identifier.identifier_token.token);
let target = GenericSymbolPathNamespace(
arg.scoped_identifier.as_ref().into(),
self.namespace.clone(),
);
let bind = SymBind {
token: inst.identifier.identifier_token.token,
target,
doc_comment,
property,
};
symbol_table::add_bind(bind);
}
Ok(())
}
fn inst_parameter_item(&mut self, arg: &InstParameterItem) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
reference_table::add(arg.into());
self.connect_target_identifiers.clear();
}
HandlerPoint::After => {
let parameter = arg.identifier.identifier_token.token;
let identifiers = if arg.inst_parameter_item_opt.is_some() {
self.connect_target_identifiers.drain(0..).collect()
} else {
vec![ConnectTargetIdentifier {
path: vec![(parameter.text, vec![])],
}]
};
let expression = if let Some(x) = &arg.inst_parameter_item_opt {
x.expression.as_ref().clone()
} else {
arg.identifier.as_ref().into()
};
let target = ConnectTarget {
identifiers,
expression,
};
self.parameter_connects.insert(parameter, target);
}
}
Ok(())
}
fn inst_port_item(&mut self, arg: &InstPortItem) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
reference_table::add(arg.into());
self.connect_target_identifiers.clear();
}
HandlerPoint::After => {
let port = arg.identifier.identifier_token.token;
let identifiers = if arg.inst_port_item_opt.is_some() {
self.connect_target_identifiers.drain(0..).collect()
} else {
vec![ConnectTargetIdentifier {
path: vec![(port.text, vec![])],
}]
};
let expression = if let Some(x) = &arg.inst_port_item_opt {
x.expression.as_ref().clone()
} else {
arg.identifier.as_ref().into()
};
let target = ConnectTarget {
identifiers,
expression,
};
self.port_connects.insert(port, target);
}
}
Ok(())
}
fn with_parameter_item(&mut self, arg: &WithParameterItem) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
let token = arg.identifier.identifier_token.token;
let kind = match &*arg.with_parameter_item_group {
WithParameterItemGroup::Param(_) => ParameterKind::Param,
WithParameterItemGroup::Const(_) => ParameterKind::Const,
};
let value = arg
.with_parameter_item_opt
.as_ref()
.map(|x| x.expression.as_ref().clone());
let property = match &*arg.with_parameter_item_group0 {
WithParameterItemGroup0::ArrayType(x) => {
let r#type: SymType = x.array_type.as_ref().into();
if !self.check_identifer_with_type(&arg.identifier, &r#type) {
return Ok(());
}
ParameterProperty {
token,
r#type,
kind,
value,
}
}
WithParameterItemGroup0::Type(_) => {
let r#type: SymType = SymType {
modifier: vec![],
kind: TypeKind::Type,
width: vec![],
array: vec![],
array_type: None,
is_const: false,
token: arg.with_parameter_item_group0.as_ref().into(),
};
ParameterProperty {
token,
r#type,
kind,
value,
}
}
};
let kind = SymbolKind::Parameter(property);
if let Some(id) =
self.insert_symbol(&arg.identifier.identifier_token.token, kind, false)
{
let parameter = Parameter {
name: arg.identifier.text(),
symbol: id,
};
self.parameters.last_mut().unwrap().push(parameter);
}
}
Ok(())
}
fn with_generic_parameter_list(
&mut self,
_arg: &WithGenericParameterList,
) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
self.needs_default_generic_argument = false;
}
Ok(())
}
fn with_generic_parameter_item(
&mut self,
arg: &WithGenericParameterItem,
) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
let default_value: Option<GenericSymbolPath> =
if let Some(ref x) = arg.with_generic_parameter_item_opt {
self.needs_default_generic_argument = true;
Some(x.with_generic_argument_item.as_ref().into())
} else {
None
};
let bound = match arg.generic_bound.as_ref() {
GenericBound::Type(_) => GenericBoundKind::Type,
GenericBound::InstScopedIdentifier(x) => {
let type_path: GenericSymbolPath = x.scoped_identifier.as_ref().into();
if !self.check_identifer_with_type_path(&arg.identifier, &type_path) {
return Ok(());
}
GenericBoundKind::Inst(type_path)
}
GenericBound::GenericProtoBound(x) => {
let r#type: SymType = x.generic_proto_bound.as_ref().into();
if !self.check_identifer_with_type(&arg.identifier, &r#type) {
return Ok(());
}
GenericBoundKind::Proto(Box::new(r#type))
}
};
if !self.needs_default_generic_argument || default_value.is_some() {
let property = GenericParameterProperty {
bound,
default_value,
};
let kind = SymbolKind::GenericParameter(property);
if let Some(id) =
self.insert_symbol(&arg.identifier.identifier_token.token, kind, false)
{
self.generic_context.push_param(id);
}
} else {
self.errors.push(AnalyzerError::missing_default_argument(
&arg.identifier.identifier_token.token.to_string(),
&arg.identifier.as_ref().into(),
));
}
}
Ok(())
}
fn port_declaration_item(&mut self, arg: &PortDeclarationItem) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
let token = arg.identifier.identifier_token.token;
let affiliation = self.affiliation.last().cloned().unwrap();
let property = match &*arg.port_declaration_item_group {
PortDeclarationItemGroup::PortTypeConcrete(x) => {
let x = x.port_type_concrete.as_ref();
let r#type: SymType = x.array_type.as_ref().into();
if !self.check_identifer_with_type(&arg.identifier, &r#type) {
return Ok(());
}
let direction: SymDirection = x.direction.as_ref().into();
let (prefix, suffix) = self.get_signal_prefix_suffix(r#type.kind.clone());
let clock_domain = if let Some(ref x) = x.port_type_concrete_opt {
self.insert_clock_domain(&x.clock_domain)
} else if affiliation == Affiliation::Module {
self.check_missing_clock_domain(
&arg.identifier.identifier_token.token,
&r#type,
);
SymClockDomain::Implicit
} else {
SymClockDomain::None
};
let default_value = x
.port_type_concrete_opt0
.as_ref()
.map(|x| *x.port_default_value.expression.clone());
PortProperty {
token,
r#type,
direction,
prefix,
suffix,
clock_domain,
default_value,
is_proto: self.in_proto,
}
}
PortDeclarationItemGroup::PortTypeAbstract(x) => {
let x = &x.port_type_abstract;
let clock_domain = if let Some(ref x) = x.port_type_abstract_opt {
self.insert_clock_domain(&x.clock_domain)
} else if affiliation == Affiliation::Module {
SymClockDomain::Implicit
} else {
SymClockDomain::None
};
let kind = if let Some(ref x) = x.port_type_abstract_opt0 {
TypeKind::AbstractInterface(Some(x.identifier.text()))
} else {
TypeKind::AbstractInterface(None)
};
let array: Vec<_> = if let Some(ref x) = x.port_type_abstract_opt1 {
let x: Vec<_> = x.array.as_ref().into();
x.iter().map(|x| (*x).clone()).collect()
} else {
Vec::new()
};
let r#type = SymType {
kind,
modifier: vec![],
width: vec![],
array,
array_type: None,
is_const: false,
token: arg.port_declaration_item_group.as_ref().into(),
};
PortProperty {
token,
r#type,
direction: SymDirection::Interface,
prefix: None,
suffix: None,
clock_domain,
default_value: None,
is_proto: self.in_proto,
}
}
};
let kind = SymbolKind::Port(property);
if let Some(id) =
self.insert_symbol(&arg.identifier.identifier_token.token, kind.clone(), false)
{
let port = Port {
token: arg.identifier.identifier_token.clone(),
symbol: id,
};
self.ports.last_mut().unwrap().push(port);
self.push_default_clock_reset(&arg.identifier.identifier_token.token, id, &kind);
}
}
Ok(())
}
fn function_declaration(&mut self, arg: &FunctionDeclaration) -> Result<(), ParolError> {
let name = arg.identifier.text();
match self.point {
HandlerPoint::Before => {
self.namespace.push(name);
self.generic_context.push();
self.ports.push(Vec::new());
self.reference_paths.push(Vec::new());
self.affiliation.push(Affiliation::Function);
self.push_type_dag_cand();
}
HandlerPoint::After => {
self.namespace.pop();
self.affiliation.pop();
let (generic_parameters, generic_consts) = self.generic_context.pop();
let ports: Vec<_> = self.ports.pop().unwrap();
let reference_paths: Vec<_> = self.reference_paths.pop().unwrap();
let ret = arg
.function_declaration_opt1
.as_ref()
.map(|x| (&*x.scalar_type).into());
if let Some(ret) = &ret
&& !self.check_identifer_with_type(&arg.identifier, ret)
{
self.pop_type_dag_cand(None);
return Ok(());
}
let affiliation = self
.affiliation
.last()
.cloned()
.unwrap_or(Affiliation::ProjectNamespace);
let range = TokenRange::new(
&arg.function.function_token,
&arg.statement_block.r_brace.r_brace_token,
);
let definition = definition_table::insert(Definition::Function(arg.clone()));
let property = FunctionProperty {
affiliation,
range,
generic_parameters,
generic_consts,
generic_references: vec![],
ports,
ret,
reference_paths,
constantable: None,
definition: Some(definition),
};
if let Some(id) = self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::Function(property),
false,
) {
self.push_interface_member(&arg.identifier, id);
self.push_declaration_item(id);
self.pop_type_dag_cand(Some((id, Context::Function, false)));
if affiliation == Affiliation::ProjectNamespace {
self.insert_reference_functions(id);
}
} else {
self.pop_type_dag_cand(None);
self.reference_functions.clear();
}
}
}
Ok(())
}
fn import_declaration(&mut self, arg: &ImportDeclaration) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.in_import = true;
let namespace = self.get_namespace(&arg.scoped_identifier.identifier().token);
let path: GenericSymbolPath = arg.scoped_identifier.as_ref().into();
let path: GenericSymbolPathNamespace = (&path, &namespace).into();
let wildcard = arg.import_declaration_opt.is_some();
let import = SymImport {
path: path.clone(),
namespace: path.1.clone(),
wildcard,
};
if self.affiliation.is_empty() {
if wildcard {
self.file_scope_import_wildcard.push(path);
} else {
self.file_scope_import_item.push(path);
}
} else {
symbol_table::add_import(import);
}
}
HandlerPoint::After => self.in_import = false,
}
Ok(())
}
fn module_declaration(&mut self, arg: &ModuleDeclaration) -> Result<(), ParolError> {
let name = arg.identifier.text();
match self.point {
HandlerPoint::Before => {
self.namespace.push(name);
self.generic_context.push();
self.parameters.push(Vec::new());
self.ports.push(Vec::new());
self.affiliation.push(Affiliation::Module);
self.module_namspace_depth = self.namespace.depth();
self.exist_clock_without_domain = false;
self.apply_file_scope_import();
self.push_type_dag_cand();
}
HandlerPoint::After => {
self.namespace.pop();
self.affiliation.pop();
self.module_namspace_depth = 0;
let (generic_parameters, generic_consts) = self.generic_context.pop();
let parameters: Vec<_> = self.parameters.pop().unwrap();
let ports: Vec<_> = self.ports.pop().unwrap();
let default_clock = if self.default_clock.is_some() {
self.default_clock
} else if self.default_clock_candidates.len() == 1 {
Some(self.default_clock_candidates[0])
} else {
None
};
let default_reset = if self.default_reset.is_some() {
self.default_reset
} else if self.defualt_reset_candidates.len() == 1 {
Some(self.defualt_reset_candidates[0])
} else {
None
};
self.default_clock = None;
self.default_clock_candidates.clear();
self.default_reset = None;
self.defualt_reset_candidates.clear();
let proto = if let Some(x) = arg.module_declaration_opt0.as_ref() {
let path: GenericSymbolPath = x.scoped_identifier.as_ref().into();
if !self.check_identifer_with_type_path(&arg.identifier, &path) {
self.pop_type_dag_cand(None);
return Ok(());
}
Some(path)
} else {
None
};
let definition = definition_table::insert(Definition::Module(arg.clone()));
let test = (|| {
let attrs = attribute_table::get(&arg.module.module_token.token);
let mut test_attr = None;
let mut ignored = false;
for attr in &attrs {
if let Attr::Test(_, top) = attr {
test_attr = Some(*top);
}
if matches!(attr, Attr::Ignore) {
ignored = true;
}
}
if let Some(top) = test_attr {
let path = if let TokenSource::File { path, .. } =
arg.identifier.identifier_token.token.source
{
path
} else {
return None;
};
let top = top.or(Some(name));
return Some(TestProperty {
r#type: TestType::Native,
path,
top,
ignored,
});
}
None
})();
let property = ModuleProperty {
range: arg.into(),
proto,
generic_parameters,
generic_consts,
generic_references: vec![],
parameters,
ports,
default_clock,
default_reset,
definition,
test,
};
if let Some(id) = self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::Module(property),
self.is_public,
) {
self.pop_type_dag_cand(Some((id, Context::Module, true)));
self.insert_reference_functions(id);
} else {
self.pop_type_dag_cand(None);
self.reference_functions.clear();
}
}
}
Ok(())
}
fn generate_for_declaration(&mut self, arg: &GenerateForDeclaration) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
self.for_identifier = Some(arg.identifier.identifier_token.token);
}
Ok(())
}
fn generate_named_block(&mut self, arg: &GenerateNamedBlock) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::Block,
false,
);
let name = arg.identifier.text();
self.default_block = Some(name);
self.namespace.push(name);
if let Some(x) = self.for_identifier {
self.insert_symbol(&x, SymbolKind::Genvar, false);
self.for_identifier = None;
}
}
HandlerPoint::After => {
self.namespace.pop();
}
}
Ok(())
}
fn generate_optional_named_block(
&mut self,
arg: &GenerateOptionalNamedBlock,
) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
let name = if let Some(ref x) = arg.generate_optional_named_block_opt {
self.insert_symbol(
&x.identifier.identifier_token.token,
SymbolKind::Block,
false,
);
x.identifier.text()
} else {
let (_, name) = self.get_anonymous_block_name(self.default_block);
name
};
self.namespace.push(name)
}
HandlerPoint::After => {
self.namespace.pop();
}
}
Ok(())
}
fn interface_declaration(&mut self, arg: &InterfaceDeclaration) -> Result<(), ParolError> {
let name = arg.identifier.text();
match self.point {
HandlerPoint::Before => {
self.namespace.push(name);
self.generic_context.push();
self.parameters.push(Vec::new());
self.affiliation.push(Affiliation::Interface);
self.interface_members.clear();
self.modport_member_ids.clear();
self.modport_ids.clear();
self.apply_file_scope_import();
self.push_type_dag_cand();
}
HandlerPoint::After => {
self.namespace.pop();
self.affiliation.pop();
let (generic_parameters, generic_consts) = self.generic_context.pop();
let parameters: Vec<_> = self.parameters.pop().unwrap();
let proto = if let Some(x) = arg.interface_declaration_opt0.as_ref() {
let path: GenericSymbolPath = x.scoped_identifier.as_ref().into();
if !self.check_identifer_with_type_path(&arg.identifier, &path) {
return Ok(());
}
Some(path)
} else {
None
};
let definition = definition_table::insert(Definition::Interface(arg.clone()));
let property = InterfaceProperty {
range: arg.into(),
proto,
generic_parameters,
generic_consts,
generic_references: vec![],
parameters,
members: self.declaration_items.drain(..).collect(),
definition,
};
if let Some(id) = self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::Interface(property),
self.is_public,
) {
self.link_modport_members();
self.expand_modport_default_member(id);
self.pop_type_dag_cand(Some((id, Context::Interface, true)));
self.insert_reference_functions(id);
} else {
self.pop_type_dag_cand(None);
self.reference_functions.clear();
};
}
}
Ok(())
}
fn package_declaration(&mut self, arg: &PackageDeclaration) -> Result<(), ParolError> {
let name = arg.identifier.text();
match self.point {
HandlerPoint::Before => {
self.namespace.push(name);
self.generic_context.push();
self.affiliation.push(Affiliation::Package);
self.apply_file_scope_import();
self.push_type_dag_cand();
}
HandlerPoint::After => {
self.namespace.pop();
self.affiliation.pop();
let (generic_parameters, generic_consts) = self.generic_context.pop();
let range = TokenRange::new(&arg.package.package_token, &arg.r_brace.r_brace_token);
let proto = if let Some(x) = arg.package_declaration_opt0.as_ref() {
let path: GenericSymbolPath = x.scoped_identifier.as_ref().into();
if !self.check_identifer_with_type_path(&arg.identifier, &path) {
self.pop_type_dag_cand(None);
return Ok(());
}
Some(path)
} else {
None
};
let property = PackageProperty {
range,
proto,
generic_parameters,
generic_consts,
generic_references: vec![],
members: self.declaration_items.drain(..).collect(),
};
if let Some(id) = self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::Package(property),
self.is_public,
) {
self.pop_type_dag_cand(Some((id, Context::Package, true)));
self.insert_reference_functions(id);
} else {
self.pop_type_dag_cand(None);
self.reference_functions.clear();
}
}
}
Ok(())
}
fn alias_declaration(&mut self, arg: &AliasDeclaration) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.push_type_dag_cand();
}
HandlerPoint::After => {
let target: GenericSymbolPath = arg.scoped_identifier.as_ref().into();
if !self.check_identifer_with_type_path(&arg.identifier, &target) {
return Ok(());
}
let kind = match &*arg.alias_declaration_group {
AliasDeclarationGroup::Module(_) => {
let property = AliasModuleProperty { target };
SymbolKind::AliasModule(property)
}
AliasDeclarationGroup::Interface(_) => {
let property = AliasInterfaceProperty { target };
SymbolKind::AliasInterface(property)
}
AliasDeclarationGroup::Package(_) => {
let property = AliasPackageProperty { target };
SymbolKind::AliasPackage(property)
}
};
if let Some(id) =
self.insert_symbol(&arg.identifier.identifier_token.token, kind, self.is_public)
{
self.push_declaration_item(id);
self.pop_type_dag_cand(Some((id, Context::Alias, false)));
} else {
self.pop_type_dag_cand(None);
}
}
}
Ok(())
}
fn proto_module_declaration(&mut self, arg: &ProtoModuleDeclaration) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.namespace.push(arg.identifier.text());
self.affiliation.push(Affiliation::Module);
self.in_proto = true;
self.parameters.push(Vec::new());
self.ports.push(Vec::new());
}
HandlerPoint::After => {
self.namespace.pop();
self.affiliation.pop();
self.in_proto = false;
let parameters: Vec<_> = self.parameters.pop().unwrap();
let ports: Vec<_> = self.ports.pop().unwrap();
let definition = definition_table::insert(Definition::ProtoModule(arg.clone()));
let property = ProtoModuleProperty {
range: arg.into(),
parameters,
ports,
definition,
};
self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::ProtoModule(property),
self.is_public,
);
}
}
Ok(())
}
fn proto_interface_declaration(
&mut self,
arg: &ProtoInterfaceDeclaration,
) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.namespace.push(arg.identifier.text());
self.affiliation.push(Affiliation::Interface);
self.parameters.push(Vec::new());
self.apply_file_scope_import();
}
HandlerPoint::After => {
self.namespace.pop();
self.affiliation.pop();
let parameters: Vec<_> = self.parameters.pop().unwrap();
let property = ProtoInterfaceProperty {
range: arg.into(),
parameters,
members: self.declaration_items.drain(..).collect(),
};
if let Some(interface_id) = self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::ProtoInterface(property),
self.is_public,
) {
self.link_modport_members();
self.expand_modport_default_member(interface_id);
}
}
}
Ok(())
}
fn proto_package_declaration(
&mut self,
arg: &ProtoPackageDeclaration,
) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.namespace.push(arg.identifier.text());
self.affiliation.push(Affiliation::Package);
self.apply_file_scope_import();
}
HandlerPoint::After => {
self.namespace.pop();
self.affiliation.pop();
let property = ProtoPackageProperty {
range: arg.into(),
members: self.declaration_items.drain(..).collect(),
};
self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::ProtoPackage(property),
self.is_public,
);
}
}
Ok(())
}
fn proto_const_declaration(&mut self, arg: &ProtoConstDeclaration) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
let token = arg.identifier.identifier_token.token;
let r#type = match &*arg.proto_const_declaration_group {
ProtoConstDeclarationGroup::ArrayType(x) => x.array_type.as_ref().into(),
ProtoConstDeclarationGroup::Type(_) => SymType {
modifier: vec![],
kind: TypeKind::Type,
width: vec![],
array: vec![],
array_type: None,
is_const: false,
token: arg.proto_const_declaration_group.as_ref().into(),
},
};
if !self.check_identifer_with_type(&arg.identifier, &r#type) {
return Ok(());
}
let property = ProtoConstProperty { token, r#type };
let kind = SymbolKind::ProtoConst(property);
if let Some(id) = self.insert_symbol(&token, kind, false) {
self.push_declaration_item(id);
}
}
Ok(())
}
fn proto_type_def_declaration(
&mut self,
arg: &ProtoTypeDefDeclaration,
) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
let token = arg.identifier.identifier_token.token;
let proprety = if let Some(ref x) = arg.proto_type_def_declaration_opt {
let r#type = x.array_type.as_ref().into();
if !self.check_identifer_with_type(&arg.identifier, &r#type) {
self.pop_type_dag_cand(None);
return Ok(());
}
ProtoTypeDefProperty {
r#type: Some(r#type),
}
} else {
ProtoTypeDefProperty { r#type: None }
};
let kind = SymbolKind::ProtoTypeDef(proprety);
if let Some(id) = self.insert_symbol(&token, kind, false) {
self.push_declaration_item(id);
}
}
Ok(())
}
fn proto_function_declaration(
&mut self,
arg: &ProtoFunctionDeclaration,
) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
let name = arg.identifier.text();
self.namespace.push(name);
self.generic_context.push();
self.ports.push(Vec::new());
self.affiliation.push(Affiliation::Function);
}
HandlerPoint::After => {
self.namespace.pop();
self.affiliation.pop();
let (generic_parameters, generic_consts) = self.generic_context.pop();
let ports: Vec<_> = self.ports.pop().unwrap();
let ret = arg
.proto_function_declaration_opt1
.as_ref()
.map(|x| (&*x.scalar_type).into());
if let Some(ret) = &ret
&& !self.check_identifer_with_type(&arg.identifier, ret)
{
return Ok(());
}
let affiliation = self.affiliation.last().cloned().unwrap();
let range =
TokenRange::new(&arg.function.function_token, &arg.semicolon.semicolon_token);
let definition = definition_table::insert(Definition::ProtoFunction(arg.clone()));
let property = FunctionProperty {
affiliation,
range,
generic_parameters,
generic_consts,
generic_references: vec![],
ports,
ret,
reference_paths: vec![],
constantable: None,
definition: Some(definition),
};
if let Some(id) = self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::ProtoFunction(property),
false,
) {
self.push_interface_member(&arg.identifier, id);
self.push_declaration_item(id);
}
}
}
Ok(())
}
fn proto_alias_declaration(&mut self, arg: &ProtoAliasDeclaration) -> Result<(), ParolError> {
if let HandlerPoint::After = self.point {
let target: GenericSymbolPath = arg.scoped_identifier.as_ref().into();
if !self.check_identifer_with_type_path(&arg.identifier, &target) {
return Ok(());
}
let kind = match &*arg.proto_alias_declaration_group {
ProtoAliasDeclarationGroup::Module(_) => {
let property = AliasModuleProperty { target };
SymbolKind::ProtoAliasModule(property)
}
ProtoAliasDeclarationGroup::Interface(_) => {
let property = AliasInterfaceProperty { target };
SymbolKind::ProtoAliasInterface(property)
}
ProtoAliasDeclarationGroup::Package(_) => {
let property = AliasPackageProperty { target };
SymbolKind::ProtoAliasPackage(property)
}
};
if let Some(id) =
self.insert_symbol(&arg.identifier.identifier_token.token, kind, false)
{
self.push_declaration_item(id);
}
}
Ok(())
}
fn embed_declaration(&mut self, arg: &EmbedDeclaration) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.push_type_dag_cand();
}
HandlerPoint::After => {
let way = arg.identifier.identifier_token.to_string();
let mut test_attr = None;
let mut ignored = false;
let attrs = attribute_table::get(&arg.embed.embed_token.token);
for attr in &attrs {
if let Attr::Test(x, y) = attr {
test_attr = Some((*x, *y));
}
if matches!(attr, Attr::Ignore) {
ignored = true;
}
}
let content = &arg.embed_content;
let r#type = match way.as_str() {
"inline" => Some(TestType::Inline),
"cocotb" => Some(TestType::CocotbEmbed(content.clone())),
_ => None,
};
let (token, kind) = if let (Some((token, top)), Some(r#type)) = (test_attr, r#type)
{
let content_source = content.triple_l_brace.triple_l_brace_token.token.source;
let path = if let TokenSource::File { path, .. } = content_source {
path
} else {
unreachable!()
};
if top.is_none() && way == "cocotb" {
self.errors.push(AnalyzerError::invalid_test(
InvalidTestKind::NoTopModuleCocotb,
&token.into(),
));
}
let property = TestProperty {
r#type,
path,
top,
ignored,
};
(token, SymbolKind::Test(property))
} else {
let (name, _) =
self.get_anonymous_block_name(Some(arg.embed.embed_token.token.text));
let token = arg.embed.embed_token.replace(&name);
(token.token, SymbolKind::Embed)
};
if let Some(id) = self.insert_symbol(&token, kind, false) {
self.pop_type_dag_cand(Some((id, Context::Embed, false)));
} else {
self.pop_type_dag_cand(None);
}
}
}
Ok(())
}
fn include_declaration(&mut self, arg: &IncludeDeclaration) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
let way = arg.identifier.identifier_token.to_string();
let mut test_attr = None;
let mut ignored = false;
let attrs = attribute_table::get(&arg.include.include_token.token);
for attr in &attrs {
if let Attr::Test(x, y) = attr {
test_attr = Some((*x, *y));
}
if matches!(attr, Attr::Ignore) {
ignored = true;
}
}
let content = &arg.string_literal.string_literal_token.token;
let r#type = match way.as_str() {
"inline" => Some(TestType::Inline),
"cocotb" => Some(TestType::CocotbInclude(content.text)),
_ => None,
};
if let (Some((token, top)), Some(r#type)) = (test_attr, r#type) {
let path = if let TokenSource::File { path, .. } = content.source {
path
} else {
unreachable!()
};
if top.is_none() && way == "cocotb" {
self.errors.push(AnalyzerError::invalid_test(
InvalidTestKind::NoTopModuleCocotb,
&token.into(),
));
}
let property = TestProperty {
r#type,
path,
top,
ignored,
};
self.insert_symbol(&token, SymbolKind::Test(property), false);
}
}
Ok(())
}
fn description_item(&mut self, arg: &DescriptionItem) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
if let DescriptionItem::DescriptionItemOptPublicDescriptionItem(x) = &arg {
self.is_public = x.description_item_opt.is_some();
}
}
HandlerPoint::After => {
self.is_public = false;
}
}
Ok(())
}
fn veryl(&mut self, _arg: &Veryl) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.push_type_dag_cand();
}
HandlerPoint::After => {
self.pop_type_dag_cand(None);
}
}
Ok(())
}
}