diff --git a/crates/analyzer/src/handlers.rs b/crates/analyzer/src/handlers.rs index 03e0a2a7..e571622d 100644 --- a/crates/analyzer/src/handlers.rs +++ b/crates/analyzer/src/handlers.rs @@ -45,7 +45,6 @@ use self::{check_assignment::CheckAssignment, create_type_dag::CreateTypeDag}; pub struct Pass1Handlers<'a> { check_attribute: CheckAttribute<'a>, - check_direction: CheckDirection<'a>, check_embed_include: CheckEmbedInclude<'a>, check_identifier: CheckIdentifier<'a>, check_number: CheckNumber<'a>, @@ -58,7 +57,6 @@ impl<'a> Pass1Handlers<'a> { pub fn new(text: &'a str, build_opt: &'a Build, lint_opt: &'a Lint) -> Self { Self { check_attribute: CheckAttribute::new(text), - check_direction: CheckDirection::new(text), check_embed_include: CheckEmbedInclude::new(text), check_identifier: CheckIdentifier::new(text, lint_opt), check_number: CheckNumber::new(text), @@ -71,7 +69,6 @@ impl<'a> Pass1Handlers<'a> { pub fn get_handlers(&mut self) -> Vec<&mut dyn Handler> { vec![ &mut self.check_attribute as &mut dyn Handler, - &mut self.check_direction as &mut dyn Handler, &mut self.check_embed_include as &mut dyn Handler, &mut self.check_identifier as &mut dyn Handler, &mut self.check_number as &mut dyn Handler, @@ -84,7 +81,6 @@ impl<'a> Pass1Handlers<'a> { pub fn get_errors(&mut self) -> Vec { let mut ret = Vec::new(); ret.append(&mut self.check_attribute.errors); - ret.append(&mut self.check_direction.errors); ret.append(&mut self.check_embed_include.errors); ret.append(&mut self.check_identifier.errors); ret.append(&mut self.check_number.errors); @@ -97,6 +93,7 @@ impl<'a> Pass1Handlers<'a> { pub struct Pass2Handlers<'a> { check_enum: CheckEnum<'a>, + check_direction: CheckDirection<'a>, check_modport: CheckModport<'a>, check_function: CheckFunction<'a>, check_type: CheckType<'a>, @@ -114,6 +111,7 @@ impl<'a> Pass2Handlers<'a> { pub fn new(text: &'a str, _build_opt: &'a Build, _lint_opt: &'a Lint) -> Self { Self { check_enum: CheckEnum::new(text), + check_direction: CheckDirection::new(text), check_modport: CheckModport::new(text), check_function: CheckFunction::new(text), check_type: CheckType::new(text), @@ -131,6 +129,7 @@ impl<'a> Pass2Handlers<'a> { pub fn get_handlers(&mut self) -> Vec<&mut dyn Handler> { vec![ &mut self.check_enum as &mut dyn Handler, + &mut self.check_direction as &mut dyn Handler, &mut self.check_modport as &mut dyn Handler, &mut self.check_function as &mut dyn Handler, &mut self.check_type as &mut dyn Handler, @@ -148,6 +147,7 @@ impl<'a> Pass2Handlers<'a> { pub fn get_errors(&mut self) -> Vec { let mut ret = Vec::new(); ret.append(&mut self.check_enum.errors); + ret.append(&mut self.check_direction.errors); ret.append(&mut self.check_modport.errors); ret.append(&mut self.check_function.errors); ret.append(&mut self.check_type.errors); diff --git a/crates/analyzer/src/handlers/check_direction.rs b/crates/analyzer/src/handlers/check_direction.rs index 79a20ce4..a9255bbe 100644 --- a/crates/analyzer/src/handlers/check_direction.rs +++ b/crates/analyzer/src/handlers/check_direction.rs @@ -1,4 +1,6 @@ use crate::analyzer_error::AnalyzerError; +use crate::symbol::SymbolKind; +use crate::symbol_table; use veryl_parser::veryl_grammar_trait::*; use veryl_parser::veryl_walker::{Handler, HandlerPoint}; use veryl_parser::ParolError; @@ -11,6 +13,7 @@ pub struct CheckDirection<'a> { in_function: bool, in_module: bool, in_modport: bool, + is_interface_port: bool, } impl<'a> CheckDirection<'a> { @@ -28,6 +31,17 @@ impl<'a> Handler for CheckDirection<'a> { } } +fn is_interface_type(arg: &ArrayType) -> bool { + if let ScalarTypeGroup::VariableTypeScalarTypeOpt(x) = &*arg.scalar_type.scalar_type_group { + if let VariableType::ScopedIdentifier(x) = x.variable_type.as_ref() { + let symbol = symbol_table::resolve(x.scoped_identifier.as_ref()).unwrap(); + return matches!(symbol.found.kind, SymbolKind::Interface(_)); + } + } + + false +} + impl<'a> VerylGrammarTrait for CheckDirection<'a> { fn port_declaration_item(&mut self, arg: &PortDeclarationItem) -> Result<(), ParolError> { if let HandlerPoint::Before = self.point { @@ -35,8 +49,10 @@ impl<'a> VerylGrammarTrait for CheckDirection<'a> { arg.port_declaration_item_group.as_ref() { let x = x.port_type_concrete.as_ref(); + let r#type = &x.array_type; + + self.is_interface_port = is_interface_type(r#type); if let Direction::Inout(_) = x.direction.as_ref() { - let r#type = &x.array_type; let is_tri = r#type .scalar_type .scalar_type_list @@ -58,8 +74,35 @@ impl<'a> VerylGrammarTrait for CheckDirection<'a> { fn direction(&mut self, arg: &Direction) -> Result<(), ParolError> { if let HandlerPoint::Before = self.point { match arg { + Direction::Input(x) => { + if self.is_interface_port { + self.errors.push(AnalyzerError::invalid_direction( + "input", + self.text, + &x.input.input_token.token.into(), + )); + } + } + Direction::Output(x) => { + if self.is_interface_port { + self.errors.push(AnalyzerError::invalid_direction( + "output", + self.text, + &x.output.output_token.token.into(), + )); + } + } + Direction::Inout(x) => { + if self.is_interface_port { + self.errors.push(AnalyzerError::invalid_direction( + "inout", + self.text, + &x.inout.inout_token.token.into(), + )); + } + } Direction::Ref(x) => { - if !self.in_function { + if !self.in_function || self.is_interface_port { self.errors.push(AnalyzerError::invalid_direction( "ref", self.text, @@ -77,7 +120,7 @@ impl<'a> VerylGrammarTrait for CheckDirection<'a> { } } Direction::Import(x) => { - if !self.in_modport { + if !self.in_modport || self.is_interface_port { self.errors.push(AnalyzerError::invalid_direction( "import", self.text, @@ -85,7 +128,6 @@ impl<'a> VerylGrammarTrait for CheckDirection<'a> { )); } } - _ => (), } } Ok(()) diff --git a/crates/analyzer/src/tests.rs b/crates/analyzer/src/tests.rs index 02b8bb02..873c6348 100644 --- a/crates/analyzer/src/tests.rs +++ b/crates/analyzer/src/tests.rs @@ -595,6 +595,22 @@ fn invalid_direction() { let errors = analyze(code); assert!(matches!(errors[0], AnalyzerError::InvalidDirection { .. })); + + let code = r#" + interface InterfaceG { + var value: logic; + modport mp { + value: input, + } + } + + module ModuleG ( + port_a: input InterfaceG + ){} + "#; + + let errors = analyze(code); + assert!(matches!(errors[0], AnalyzerError::InvalidDirection { .. })); } #[test]