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::{DefineContext, Namespace};
use crate::reference_table::{self, ReferenceCandidate};
use crate::scope;
use crate::symbol::ClockDomain as SymClockDomain;
use crate::symbol::Direction as SymDirection;
use crate::symbol::Type as SymType;
use crate::symbol::{
Affiliation, AliasInterfaceProperty, AliasModuleProperty, AliasPackageProperty, ConnectTarget,
ConnectTargetIdentifier, DocComment, DocCommentLine, EnumMemberProperty, EnumMemberValue,
EnumProperty, FunctionCallArgument, FunctionCallSite, FunctionProperty, GenericBoundKind,
GenericConstProperty, GenericParameterProperty, InstanceProperty, InterfaceProperty,
ModportFunctionMemberProperty, ModportProperty, ModportVariableMemberProperty, ModuleProperty,
PackageProperty, Parameter, ParameterKind, ParameterProperty, Port, PortProperty,
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, VerylWalker};
#[derive(Default)]
struct AssignmentTargetHandler {
point: HandlerPoint,
select_depth: usize,
targets: Vec<GenericSymbolPath>,
}
impl Handler for AssignmentTargetHandler {
fn set_point(&mut self, point: HandlerPoint) {
self.point = point;
}
}
impl VerylGrammarTrait for AssignmentTargetHandler {
fn select(&mut self, _arg: &Select) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => self.select_depth += 1,
HandlerPoint::After => self.select_depth -= 1,
}
Ok(())
}
fn expression_identifier(&mut self, arg: &ExpressionIdentifier) -> Result<(), ParolError> {
if matches!(self.point, HandlerPoint::Before) && self.select_depth == 0 {
self.targets.push(arg.into());
}
Ok(())
}
}
#[derive(Default)]
struct AssignmentTargetWalker {
handler: AssignmentTargetHandler,
}
impl VerylWalker for AssignmentTargetWalker {
fn get_handlers(&mut self) -> Option<Vec<&mut dyn Handler>> {
Some(vec![&mut self.handler])
}
}
fn assignment_targets(expression: &Expression) -> Vec<GenericSymbolPath> {
let mut walker = AssignmentTargetWalker::default();
walker.expression(expression);
walker.handler.targets
}
fn function_call_site(callee: GenericSymbolPath, call: &FunctionCall) -> FunctionCallSite {
let range = TokenRange::from_range(&callee.range, &TokenRange::from(call));
let mut arguments = Vec::new();
if let Some(list) = &call.function_call_opt {
let items: Vec<&ArgumentItem> = list.argument_list.as_ref().into();
for item in items {
if let Some(named) = &item.argument_item_opt {
let name = item
.argument_expression
.expression
.unwrap_identifier()
.map(|x| x.identifier().token.text);
arguments.push(FunctionCallArgument {
name,
targets: assignment_targets(named.expression.as_ref()),
});
} else {
arguments.push(FunctionCallArgument {
name: None,
targets: assignment_targets(item.argument_expression.expression.as_ref()),
});
}
}
}
FunctionCallSite {
callee,
arguments,
range,
}
}
#[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,
project_name: StrId,
point: HandlerPoint,
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>>,
write_paths: Vec<Vec<GenericSymbolPath>>,
call_sites: Vec<Vec<FunctionCallSite>>,
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>,
exist_clock_without_domain: bool,
in_proto: bool,
in_import: bool,
file_scope_import_item: Vec<GenericSymbolPathNamespace>,
file_scope_import_wildcard: Vec<GenericSymbolPathNamespace>,
mixin_sources: Vec<GenericSymbolPath>,
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>,
reference_candidates: Vec<Vec<ReferenceCandidate>>,
}
#[derive(Clone)]
enum StructOrUnion {
InStruct,
InUnion,
}
impl CreateSymbolTable {
pub fn new(build_opt: &Build, project_name: StrId) -> Self {
let mut namespace = Namespace::new();
namespace.push(project_name);
scope::set_current(scope::intern_namespace(&namespace));
Self {
build_opt: build_opt.clone(),
project_name,
..Default::default()
}
}
fn push_namespace(&mut self, name: StrId) {
scope::enter(name);
}
fn pop_namespace(&mut self) {
scope::exit();
}
fn insert_namespace(&self, token: &Token) {
if let TokenSource::File { path, .. } = token.source {
let attrs = attribute_table::get(token);
let define_context: DefineContext = attrs.as_slice().into();
scope::insert_token_scope(token.id, path, scope::current(), &define_context);
}
}
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 define_context: DefineContext = attrs.as_slice().into();
scope::namespace(scope::current(), &define_context)
}
fn current_namespace(&self) -> Namespace {
scope::namespace(scope::current(), &DefineContext::default())
}
fn insert_symbol(&mut self, token: &Token, kind: SymbolKind, public: bool) -> Option<SymbolId> {
let doc_comment = self.create_doc_comment(token);
let owned_scope_kind = scope::scope_kind_of(&kind);
let mut symbol = Symbol::new(token, kind, &self.get_namespace(token), public, doc_comment);
let scope = symbol.scope;
if attribute_table::contains(token, Attr::Allow(AllowItem::UnusedVariable)) {
symbol.allow_unused = true;
}
let id = symbol_table::insert(token, symbol);
if let Some(id) = id {
self.insert_namespace(token);
if let Some(kind) = owned_scope_kind {
let owned = scope::intern_child(scope, token.text, kind);
scope::set_kind_owner(owned, kind, id);
}
} 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
&& scope::depth(scope::current()) == 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.current_namespace(),
wildcard: false,
};
symbol_table::add_import(import);
}
for x in &self.file_scope_import_wildcard {
let import = SymImport {
path: x.clone(),
namespace: self.current_namespace(),
wildcard: true,
};
symbol_table::add_import(import);
}
}
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,
parent: None,
import,
};
x.push(cand);
}
}
fn insert_reference_functions(&mut self, id: SymbolId) {
let funcs = std::mem::take(&mut self.reference_functions);
symbol_table::add_reference_functions(id, funcs);
}
fn is_in_expression_identifier(&self) -> bool {
!self.in_expression_identifier.is_empty()
}
fn add_reference_candidate(&mut self, candidate: ReferenceCandidate) {
if let Some(candidates) = self.reference_candidates.last_mut() {
candidates.push(candidate);
} else {
reference_table::add(candidate);
}
}
fn pop_reference_candidates(&mut self) {
fn is_import_item(candidate: &ReferenceCandidate) -> bool {
match candidate {
ReferenceCandidate::ScopedIdentifier {
in_import_declaration,
..
} => *in_import_declaration,
ReferenceCandidate::ImportItem { .. } => true,
_ => false,
}
}
if let Some(candidates) = self.reference_candidates.pop() {
let (import_items, other_itesm): (Vec<_>, Vec<_>) =
candidates.into_iter().partition(is_import_item);
for item in import_items {
reference_table::add(item);
}
for item in other_itesm {
reference_table::add(item);
}
}
}
}
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.current_namespace();
}
}
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 {
self.add_reference_candidate(arg.into());
}
Ok(())
}
fn scoped_identifier(&mut self, arg: &ScopedIdentifier) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
if !self.with_member_reference {
self.add_reference_candidate((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(),
);
symbol_table::insert_sv_member(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,
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,
};
self.add_reference_candidate(cand);
} else {
self.add_reference_candidate(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;
self.add_reference_candidate(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());
if let Some(call_sites) = self.call_sites.last_mut() {
call_sites.push(function_call_site(path.clone(), &fc.function_call));
}
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.current_namespace();
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(),
};
self.add_reference_candidate(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.push_namespace(name);
self.affiliation.push(Affiliation::StatementBlock);
}
HandlerPoint::After => {
self.pop_namespace();
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 matches!(
arg.identifier_statement_group.as_ref(),
IdentifierStatementGroup::Assignment(_)
) && let Some(paths) = self.write_paths.last_mut()
{
paths.push(arg.expression_identifier.as_ref().into());
}
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 let IdentifierStatementGroup::FunctionCall(fc) =
arg.identifier_statement_group.as_ref()
{
let path: GenericSymbolPath = arg.expression_identifier.as_ref().into();
self.reference_functions.push(path.clone());
if let Some(call_sites) = self.call_sites.last_mut() {
call_sites.push(function_call_site(path.clone(), &fc.function_call));
}
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.current_namespace();
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 for_statement(&mut self, arg: &ForStatement) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
let (_, name) = self.get_anonymous_block_name(None);
self.push_namespace(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.pop_namespace();
}
}
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);
}
}
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,
is_proto: false,
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.push_namespace(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(),
generated_from: None,
};
SymbolKind::ModportFunctionMember(property)
}
_ => {
let direction: crate::symbol::Direction =
item.direction.as_ref().into();
let property = ModportVariableMemberProperty {
direction,
variable: SymbolId::default(),
generated_from: None,
};
SymbolKind::ModportVariableMember(property)
}
};
if let Some(id) =
self.insert_symbol(&item.identifier.identifier_token.token, kind, false)
{
members.push(id);
}
}
self.pop_namespace();
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 {
self.add_reference_candidate((*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 {
self.add_reference_candidate((*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.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 {
self.add_reference_candidate(arg.into());
}
Ok(())
}
fn enum_declaration(&mut self, arg: &EnumDeclaration) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
let name = arg.identifier.text();
self.push_namespace(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.pop_namespace();
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::Unresolved
};
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 text = resource_table::insert_str(&format!("{prefix}_{}", token.text));
let mangled_token = Token {
id: resource_table::new_token_id(),
text,
..token
};
let kind = SymbolKind::EnumMemberMangled;
let enum_scope = scope::exit();
self.insert_symbol(&mangled_token, kind, false);
scope::set_current(enum_scope);
}
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.push_namespace(name);
self.push_type_dag_cand();
}
HandlerPoint::After => {
self.struct_or_union = None;
self.pop_namespace();
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 {
is_proto: false,
r#type: Some(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 affiliation = self.affiliation.last().cloned().unwrap();
let clock_domain = if let Some(ref x) = inst.component_instantiation_opt {
self.insert_clock_domain(&x.clock_domain)
} else if affiliation == Affiliation::Module {
SymClockDomain::Implicit
} 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.current_namespace(),
);
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 => {
self.add_reference_candidate(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() {
std::mem::take(&mut self.connect_target_identifiers)
} 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 => {
self.add_reference_candidate(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() {
std::mem::take(&mut self.connect_target_identifiers)
} 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,
is_proto: false,
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,
is_proto: false,
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 concatenation_assignment(
&mut self,
arg: &ConcatenationAssignment,
) -> Result<(), ParolError> {
if matches!(self.point, HandlerPoint::Before)
&& let Some(paths) = self.write_paths.last_mut()
{
let items: Vec<_> = arg.assign_concatenation_list.as_ref().into();
paths.extend(
items
.into_iter()
.map(|item| item.hierarchical_identifier.as_ref().into()),
);
}
Ok(())
}
fn function_declaration(&mut self, arg: &FunctionDeclaration) -> Result<(), ParolError> {
let name = arg.identifier.text();
match self.point {
HandlerPoint::Before => {
self.push_namespace(name);
self.generic_context.push();
self.ports.push(Vec::new());
self.reference_paths.push(Vec::new());
self.write_paths.push(Vec::new());
self.call_sites.push(Vec::new());
self.affiliation.push(Affiliation::Function);
self.push_type_dag_cand();
}
HandlerPoint::After => {
self.pop_namespace();
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 write_paths: Vec<_> = self.write_paths.pop().unwrap();
let call_sites: Vec<_> = self.call_sites.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(self.project_name, Definition::Function(arg.clone()));
let property = FunctionProperty {
affiliation,
is_proto: false,
range,
generic_parameters,
generic_consts,
generic_references: vec![],
ports,
ret,
reference_paths,
constantable: None,
write_paths,
call_sites,
conditional_effects: Box::default(),
definition: Some(definition),
};
if let Some(id) = self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::Function(property),
false,
) {
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> {
fn add_import(
handler: &mut CreateSymbolTable,
path: GenericSymbolPathNamespace,
import: SymImport,
) {
if handler.affiliation.is_empty() {
if import.wildcard {
handler.file_scope_import_wildcard.push(path);
} else {
handler.file_scope_import_item.push(path);
}
} else {
symbol_table::add_import(import);
}
}
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();
if let Some(ref x) = arg.import_declaration_opt {
match x.import_declaration_opt_group.as_ref() {
ImportDeclarationOptGroup::Star(_) => {
let import = SymImport {
path: path.clone(),
namespace: path.1.clone(),
wildcard: true,
};
add_import(self, path, import);
}
ImportDeclarationOptGroup::MultipleImportList(x) => {
let item_list: Vec<_> = x.multiple_import_list.as_ref().into();
for x in item_list {
self.add_reference_candidate(
(arg.scoped_identifier.as_ref(), x).into(),
);
let mut item_path = path.clone();
item_path
.0
.append(&x.identifier.identifier_token.token, &[]);
let import = SymImport {
path: item_path.clone(),
namespace: item_path.1.clone(),
wildcard: false,
};
add_import(self, item_path, import);
}
}
}
} else {
let import = SymImport {
path: path.clone(),
namespace: path.1.clone(),
wildcard: false,
};
add_import(self, path, import);
}
}
HandlerPoint::After => self.in_import = false,
}
Ok(())
}
fn mixin_declaration(&mut self, arg: &MixinDeclaration) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
let path: GenericSymbolPath = arg.scoped_identifier.as_ref().into();
self.mixin_sources.push(path);
}
Ok(())
}
fn module_declaration(&mut self, arg: &ModuleDeclaration) -> Result<(), ParolError> {
let name = arg.identifier.text();
match self.point {
HandlerPoint::Before => {
self.push_namespace(name);
self.generic_context.push();
self.parameters.push(Vec::new());
self.ports.push(Vec::new());
self.affiliation.push(Affiliation::Module);
self.reference_candidates.push(Vec::new());
self.module_namspace_depth = scope::depth(scope::current());
self.exist_clock_without_domain = false;
self.apply_file_scope_import();
self.push_type_dag_cand();
}
HandlerPoint::After => {
self.pop_namespace();
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();
self.pop_reference_candidates();
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(self.project_name, 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(),
is_proto: false,
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.push_namespace(name);
if let Some(x) = self.for_identifier {
self.insert_symbol(&x, SymbolKind::Genvar, false);
self.for_identifier = None;
}
}
HandlerPoint::After => {
self.pop_namespace();
}
}
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.push_namespace(name)
}
HandlerPoint::After => {
self.pop_namespace();
}
}
Ok(())
}
fn interface_declaration(&mut self, arg: &InterfaceDeclaration) -> Result<(), ParolError> {
let name = arg.identifier.text();
match self.point {
HandlerPoint::Before => {
self.push_namespace(name);
self.generic_context.push();
self.parameters.push(Vec::new());
self.affiliation.push(Affiliation::Interface);
self.reference_candidates.push(Vec::new());
self.apply_file_scope_import();
self.push_type_dag_cand();
}
HandlerPoint::After => {
self.pop_namespace();
self.affiliation.pop();
self.pop_reference_candidates();
let (generic_parameters, generic_consts) = self.generic_context.pop();
let mixin_sources: Vec<_> = std::mem::take(&mut self.mixin_sources);
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(self.project_name, Definition::Interface(arg.clone()));
let property = InterfaceProperty {
range: arg.into(),
is_proto: false,
proto,
generic_parameters,
generic_consts,
generic_references: vec![],
mixin_sources,
parameters,
members: std::mem::take(&mut self.declaration_items),
definition: Some(definition),
};
if let Some(id) = self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::Interface(property),
self.is_public,
) {
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.push_namespace(name);
self.generic_context.push();
self.affiliation.push(Affiliation::Package);
self.reference_candidates.push(Vec::new());
self.apply_file_scope_import();
self.push_type_dag_cand();
}
HandlerPoint::After => {
self.pop_namespace();
self.affiliation.pop();
self.pop_reference_candidates();
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,
is_proto: false,
proto,
generic_parameters,
generic_consts,
generic_references: vec![],
members: std::mem::take(&mut self.declaration_items),
};
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,
is_proto: false,
};
SymbolKind::AliasModule(property)
}
AliasDeclarationGroup::Interface(_) => {
let property = AliasInterfaceProperty {
target,
is_proto: false,
};
SymbolKind::AliasInterface(property)
}
AliasDeclarationGroup::Package(_) => {
let property = AliasPackageProperty {
target,
is_proto: false,
};
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.push_namespace(arg.identifier.text());
self.affiliation.push(Affiliation::Module);
self.in_proto = true;
self.parameters.push(Vec::new());
self.ports.push(Vec::new());
self.reference_candidates.push(Vec::new());
}
HandlerPoint::After => {
self.pop_namespace();
self.affiliation.pop();
self.pop_reference_candidates();
self.in_proto = false;
let parameters: Vec<_> = self.parameters.pop().unwrap();
let ports: Vec<_> = self.ports.pop().unwrap();
let definition = definition_table::insert(
self.project_name,
Definition::ProtoModule(arg.clone()),
);
let property = ModuleProperty {
range: arg.into(),
is_proto: true,
proto: None,
generic_parameters: vec![],
generic_consts: vec![],
generic_references: vec![],
parameters,
ports,
default_clock: None,
default_reset: None,
definition,
test: None,
};
self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::Module(property),
self.is_public,
);
}
}
Ok(())
}
fn proto_interface_declaration(
&mut self,
arg: &ProtoInterfaceDeclaration,
) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.push_namespace(arg.identifier.text());
self.affiliation.push(Affiliation::Interface);
self.parameters.push(Vec::new());
self.reference_candidates.push(Vec::new());
self.apply_file_scope_import();
}
HandlerPoint::After => {
self.pop_namespace();
self.affiliation.pop();
self.pop_reference_candidates();
let parameters: Vec<_> = self.parameters.pop().unwrap();
let property = InterfaceProperty {
range: arg.into(),
is_proto: true,
proto: None,
generic_parameters: vec![],
generic_consts: vec![],
generic_references: vec![],
mixin_sources: vec![],
parameters,
members: std::mem::take(&mut self.declaration_items),
definition: None,
};
self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::Interface(property),
self.is_public,
);
}
}
Ok(())
}
fn proto_package_declaration(
&mut self,
arg: &ProtoPackageDeclaration,
) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.push_namespace(arg.identifier.text());
self.affiliation.push(Affiliation::Package);
self.reference_candidates.push(Vec::new());
self.apply_file_scope_import();
}
HandlerPoint::After => {
self.pop_namespace();
self.affiliation.pop();
self.pop_reference_candidates();
let property = PackageProperty {
range: arg.into(),
is_proto: true,
proto: None,
generic_parameters: vec![],
generic_consts: vec![],
generic_references: vec![],
members: std::mem::take(&mut self.declaration_items),
};
self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::Package(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 = ParameterProperty {
token,
is_proto: true,
r#type,
kind: ParameterKind::Const,
value: None,
};
let kind = SymbolKind::Parameter(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(());
}
TypeDefProperty {
is_proto: true,
r#type: Some(r#type),
}
} else {
TypeDefProperty {
is_proto: true,
r#type: None,
}
};
let kind = SymbolKind::TypeDef(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.push_namespace(name);
self.generic_context.push();
self.ports.push(Vec::new());
self.affiliation.push(Affiliation::Function);
}
HandlerPoint::After => {
self.pop_namespace();
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(
self.project_name,
Definition::ProtoFunction(arg.clone()),
);
let property = FunctionProperty {
affiliation,
is_proto: true,
range,
generic_parameters,
generic_consts,
generic_references: vec![],
ports,
ret,
reference_paths: vec![],
constantable: None,
write_paths: vec![],
call_sites: vec![],
conditional_effects: Box::default(),
definition: Some(definition),
};
if let Some(id) = self.insert_symbol(
&arg.identifier.identifier_token.token,
SymbolKind::Function(property),
false,
) {
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,
is_proto: true,
};
SymbolKind::AliasModule(property)
}
ProtoAliasDeclarationGroup::Interface(_) => {
let property = AliasInterfaceProperty {
target,
is_proto: true,
};
SymbolKind::AliasInterface(property)
}
ProtoAliasDeclarationGroup::Package(_) => {
let property = AliasPackageProperty {
target,
is_proto: true,
};
SymbolKind::AliasPackage(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(())
}
}