Skip to content

Commit

Permalink
Merge pull request #511 from dalance/import_resolve
Browse files Browse the repository at this point in the history
Add import resolve support
  • Loading branch information
dalance authored Feb 26, 2024
2 parents 97827c3 + dd69f51 commit 6e272ed
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 3 deletions.
21 changes: 21 additions & 0 deletions crates/analyzer/src/analyzer_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,20 @@ pub enum AnalyzerError {
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(invalid_import),
help("fix import item"),
url("https://dalance.github.io/veryl/book/06_appendix/02_semantic_error.html#invalid_import")
)]
#[error("This item can't be imported")]
InvalidImport {
#[source_code]
input: NamedSource,
#[label("Error location")]
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(invalid_lsb),
Expand Down Expand Up @@ -499,6 +513,13 @@ impl AnalyzerError {
}
}

pub fn invalid_import(source: &str, token: &VerylToken) -> Self {
AnalyzerError::InvalidImport {
input: AnalyzerError::named_source(source, token),
error_location: token.token.into(),
}
}

pub fn invalid_lsb(source: &str, token: &VerylToken) -> Self {
AnalyzerError::InvalidLsb {
input: AnalyzerError::named_source(source, token),
Expand Down
130 changes: 129 additions & 1 deletion crates/analyzer/src/handlers/create_reference.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::analyzer_error::AnalyzerError;
use crate::namespace::Namespace;
use crate::namespace_table;
use crate::symbol::{Symbol, SymbolKind};
use crate::symbol_table::{self, SymbolPath};
use crate::symbol_table::{self, ResolveSymbol, SymbolPath};
use veryl_parser::resource_table::TokenId;
use veryl_parser::veryl_grammar_trait::*;
use veryl_parser::veryl_token::Token;
use veryl_parser::veryl_walker::{Handler, HandlerPoint};
Expand All @@ -12,12 +14,16 @@ pub struct CreateReference<'a> {
pub errors: Vec<AnalyzerError>,
text: &'a str,
point: HandlerPoint,
top_level: bool,
file_scope_imported_items: Vec<TokenId>,
file_scope_imported_packages: Vec<Namespace>,
}

impl<'a> CreateReference<'a> {
pub fn new(text: &'a str) -> Self {
Self {
text,
top_level: true,
..Default::default()
}
}
Expand Down Expand Up @@ -287,4 +293,126 @@ impl<'a> VerylGrammarTrait for CreateReference<'a> {
}
Ok(())
}

fn module_declaration(&mut self, arg: &ModuleDeclaration) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.top_level = false;
let mut namespace = Namespace::default();
namespace.push(arg.identifier.identifier_token.token.text);
for x in &self.file_scope_imported_items {
symbol_table::add_imported_item(*x, &namespace);
}
for x in &self.file_scope_imported_packages {
symbol_table::add_imported_package(x, &namespace);
}
}
HandlerPoint::After => {
self.top_level = true;
}
}
Ok(())
}

fn interface_declaration(&mut self, arg: &InterfaceDeclaration) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.top_level = false;
let mut namespace = Namespace::default();
namespace.push(arg.identifier.identifier_token.token.text);
for x in &self.file_scope_imported_items {
symbol_table::add_imported_item(*x, &namespace);
}
for x in &self.file_scope_imported_packages {
symbol_table::add_imported_package(x, &namespace);
}
}
HandlerPoint::After => {
self.top_level = true;
}
}
Ok(())
}

fn package_declaration(&mut self, arg: &PackageDeclaration) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.top_level = false;
let mut namespace = Namespace::default();
namespace.push(arg.identifier.identifier_token.token.text);
for x in &self.file_scope_imported_items {
symbol_table::add_imported_item(*x, &namespace);
}
for x in &self.file_scope_imported_packages {
symbol_table::add_imported_package(x, &namespace);
}
}
HandlerPoint::After => {
self.top_level = true;
}
}
Ok(())
}

fn import_declaration(&mut self, arg: &ImportDeclaration) -> Result<(), ParolError> {
// This should be executed after scoped_identifier
if let HandlerPoint::After = self.point {
let is_wildcard = arg.import_declaration_opt.is_some();
let namespace =
namespace_table::get(arg.scoped_identifier.identifier.identifier_token.token.id)
.unwrap();
match symbol_table::resolve(arg.scoped_identifier.as_ref()) {
Ok(symbol) => {
if let ResolveSymbol::Symbol(x) = symbol.found {
match x.kind {
SymbolKind::Package if is_wildcard => {
let mut target = x.namespace.clone();
target.push(x.token.text);

if self.top_level {
self.file_scope_imported_packages.push(target);
} else {
symbol_table::add_imported_package(&target, &namespace);
}
}
SymbolKind::SystemVerilog => (),
_ if is_wildcard => {
self.errors.push(AnalyzerError::invalid_import(
self.text,
&arg.scoped_identifier.identifier.identifier_token,
));
}
_ => {
if self.top_level {
self.file_scope_imported_items.push(x.token.id);
} else {
symbol_table::add_imported_item(x.token.id, &namespace);
}
}
}
}
}
Err(err) => {
if let Some(last_found) = err.last_found {
let name = format!("{}", last_found.token.text);
let member = format!("{}", err.not_found);
self.errors.push(AnalyzerError::unknown_member(
&name,
&member,
self.text,
&arg.scoped_identifier.identifier.identifier_token,
));
} else {
let name = format!("{}", err.not_found);
self.errors.push(AnalyzerError::undefined_identifier(
&name,
self.text,
&arg.scoped_identifier.identifier.identifier_token,
));
}
}
}
}
Ok(())
}
}
2 changes: 2 additions & 0 deletions crates/analyzer/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub struct Symbol {
pub kind: SymbolKind,
pub namespace: Namespace,
pub references: Vec<Token>,
pub imported: Vec<Namespace>,
pub evaluated: Cell<Option<Evaluated>>,
pub allow_unused: bool,
pub doc_comment: Vec<StrId>,
Expand All @@ -46,6 +47,7 @@ impl Symbol {
kind,
namespace: namespace.to_owned(),
references: Vec::new(),
imported: Vec::new(),
evaluated: Cell::new(None),
allow_unused: false,
doc_comment,
Expand Down
37 changes: 35 additions & 2 deletions crates/analyzer/src/symbol_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ impl SymbolTable {
namespace.matched(&symbol.namespace)
} else {
namespace.included(&symbol.namespace)
|| symbol.imported.iter().any(|x| namespace.included(x))
};
if included && symbol.namespace.depth() >= max_depth {
symbol.evaluate();
Expand Down Expand Up @@ -414,6 +415,26 @@ impl SymbolTable {
}
}

pub fn add_imported_item(&mut self, target: TokenId, namespace: &Namespace) {
for (_, symbols) in self.table.iter_mut() {
for symbol in symbols.iter_mut() {
if symbol.token.id == target {
symbol.imported.push(namespace.to_owned());
}
}
}
}

pub fn add_imported_package(&mut self, target: &Namespace, namespace: &Namespace) {
for (_, symbols) in self.table.iter_mut() {
for symbol in symbols.iter_mut() {
if symbol.namespace.matched(target) {
symbol.imported.push(namespace.to_owned());
}
}
}
}

pub fn add_project_local(&mut self, prj: StrId, from: StrId, to: StrId) {
self.project_local_table
.entry(prj)
Expand All @@ -434,13 +455,15 @@ impl fmt::Display for SymbolTable {
let mut symbol_width = 0;
let mut namespace_width = 0;
let mut reference_width = 0;
let mut import_width = 0;
let mut vec: Vec<_> = self.table.iter().collect();
vec.sort_by(|x, y| format!("{}", x.0).cmp(&format!("{}", y.0)));
for (k, v) in &vec {
symbol_width = symbol_width.max(format!("{k}").len());
for symbol in *v {
namespace_width = namespace_width.max(format!("{}", symbol.namespace).len());
reference_width = reference_width.max(format!("{}", symbol.references.len()).len());
import_width = import_width.max(format!("{}", symbol.imported.len()).len());
}
}
for (k, v) in &vec {
Expand All @@ -455,15 +478,17 @@ impl fmt::Display for SymbolTable {
};
writeln!(
f,
" {:symbol_width$} @ {:namespace_width$} {{ refs: {:reference_width$} }}: {}{},",
" {:symbol_width$} @ {:namespace_width$} {{ref: {:reference_width$}, import: {:import_width$}}}: {}{},",
k,
symbol.namespace,
symbol.references.len(),
symbol.imported.len(),
symbol.kind,
evaluated,
symbol_width = symbol_width,
namespace_width = namespace_width,
reference_width = reference_width
reference_width = reference_width,
import_width = import_width,
)?;
}
}
Expand Down Expand Up @@ -705,6 +730,14 @@ pub fn add_reference(target: TokenId, token: &Token) {
SYMBOL_TABLE.with(|f| f.borrow_mut().add_reference(target, token))
}

pub fn add_imported_item(target: TokenId, namespace: &Namespace) {
SYMBOL_TABLE.with(|f| f.borrow_mut().add_imported_item(target, namespace))
}

pub fn add_imported_package(target: &Namespace, namespace: &Namespace) {
SYMBOL_TABLE.with(|f| f.borrow_mut().add_imported_package(target, namespace))
}

pub fn add_project_local(prj: StrId, from: StrId, to: StrId) {
SYMBOL_TABLE.with(|f| f.borrow_mut().add_project_local(prj, from, to))
}
Expand Down
20 changes: 20 additions & 0 deletions testcases/sv/44_import_resolve.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module veryl_testcase_Module44;
logic [10-1:0] a;
logic [10-1:0] b;
logic [10-1:0] c;

import veryl_testcase_Package44A::z;
import veryl_testcase_Package44B::*;

assign a = veryl_testcase_Package44A::z;
assign b = z;
assign c = y;
endmodule

package veryl_testcase_Package44A;
localparam int unsigned z = 0;
endpackage

package veryl_testcase_Package44B;
localparam int unsigned y = 0;
endpackage
20 changes: 20 additions & 0 deletions testcases/veryl/44_import_resolve.veryl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module Module44 {
var a: logic<10>;
var b: logic<10>;
var c: logic<10>;

import Package44A::z;
import Package44B::*;

assign a = Package44A::z;
assign b = z;
assign c = y;
}

package Package44A {
localparam z: u32 = 0;
}

package Package44B {
localparam y: u32 = 0;
}

0 comments on commit 6e272ed

Please sign in to comment.