Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add generics support #679

Merged
merged 1 commit into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions crates/analyzer/src/analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@ use crate::assign::{AssignPath, AssignPosition, AssignPositionTree, AssignPositi
use crate::attribute_table;
use crate::handlers::*;
use crate::msb_table;
use crate::namespace::Namespace;
use crate::namespace_table;
use crate::symbol::{
Direction, ParameterValue, Symbol, SymbolId, SymbolKind, TypeKind, VariableAffiniation,
Direction, DocComment, ParameterValue, Symbol, SymbolId, SymbolKind, TypeKind,
VariableAffiniation,
};
use crate::symbol_table::{self, SymbolPath};
use crate::symbol_path::SymbolPath;
use crate::symbol_table;
use crate::type_dag;
use itertools::Itertools;
use std::path::Path;
use veryl_metadata::{Lint, Metadata};
use veryl_parser::resource_table;
use veryl_parser::veryl_grammar_trait::*;
use veryl_parser::veryl_token::{Token, TokenSource};
use veryl_parser::veryl_walker::{Handler, VerylWalker};

pub struct AnalyzerPass1<'a> {
Expand Down Expand Up @@ -179,15 +183,33 @@ pub struct Analyzer {
lint_opt: Lint,
}

fn new_namespace(name: &str) -> (Token, Symbol) {
let token = Token::new(name, 0, 0, 0, 0, TokenSource::External);
let symbol = Symbol::new(
&token,
SymbolKind::Namespace,
&Namespace::new(),
false,
DocComment::default(),
);
(token, symbol)
}

impl Analyzer {
pub fn new(metadata: &Metadata) -> Self {
for locks in metadata.lockfile.lock_table.values() {
for lock in locks {
let prj = resource_table::insert_str(&lock.name);
let (token, symbol) = new_namespace(&lock.name);
symbol_table::insert(&token, symbol);
for lock_dep in &lock.dependencies {
let from = resource_table::insert_str(&lock_dep.name);
let to = metadata.lockfile.lock_table.get(&lock_dep.url).unwrap();
let to = to.iter().find(|x| x.version == lock_dep.version).unwrap();

let (token, symbol) = new_namespace(&to.name);
symbol_table::insert(&token, symbol);

let to = resource_table::insert_str(&to.name);
symbol_table::add_project_local(prj, from, to);
}
Expand Down
45 changes: 40 additions & 5 deletions crates/analyzer/src/analyzer_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,31 @@ pub enum AnalyzerError {

#[diagnostic(
severity(Error),
code(mismatch_arity),
code(mismatch_function_arity),
help("fix function arguments"),
url("https://doc.veryl-lang.org/book/06_appendix/02_semantic_error.html#mismatch_arity")
url("https://doc.veryl-lang.org/book/06_appendix/02_semantic_error.html#mismatch_function_arity")
)]
#[error("function \"{name}\" has {arity} arguments, but {args} arguments are supplied")]
MismatchArity {
MismatchFunctionArity {
name: String,
arity: usize,
args: usize,
#[source_code]
input: NamedSource,
#[label("Error location")]
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(mismatch_generics_arity),
help("fix generics arguments"),
url("https://doc.veryl-lang.org/book/06_appendix/02_semantic_error.html#mismatch_generics_arity")
)]
#[error(
"generics \"{name}\" has {arity} generic arguments, but {args} arguments are supplied"
)]
MismatchGenericsArity {
name: String,
arity: usize,
args: usize,
Expand Down Expand Up @@ -797,14 +816,30 @@ impl AnalyzerError {
}
}

pub fn mismatch_arity(
pub fn mismatch_function_arity(
name: &str,
arity: usize,
args: usize,
source: &str,
token: &TokenRange,
) -> Self {
AnalyzerError::MismatchFunctionArity {
name: name.to_string(),
arity,
args,
input: AnalyzerError::named_source(source, token),
error_location: token.into(),
}
}

pub fn mismatch_generics_arity(
name: &str,
arity: usize,
args: usize,
source: &str,
token: &TokenRange,
) -> Self {
AnalyzerError::MismatchArity {
AnalyzerError::MismatchGenericsArity {
name: name.to_string(),
arity,
args,
Expand Down
5 changes: 3 additions & 2 deletions crates/analyzer/src/handlers/check_function.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::analyzer_error::AnalyzerError;
use crate::symbol::SymbolKind;
use crate::symbol_table::{self, SymbolPath};
use crate::symbol_path::SymbolPath;
use crate::symbol_table;
use veryl_parser::veryl_grammar_trait::*;
use veryl_parser::veryl_walker::{Handler, HandlerPoint};
use veryl_parser::ParolError;
Expand Down Expand Up @@ -108,7 +109,7 @@ impl<'a> VerylGrammarTrait for CheckFunction<'a> {
.last()
.unwrap()
);
self.errors.push(AnalyzerError::mismatch_arity(
self.errors.push(AnalyzerError::mismatch_function_arity(
&name,
arity,
args,
Expand Down
1 change: 1 addition & 0 deletions crates/analyzer/src/handlers/check_instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ impl<'a> VerylGrammarTrait for CheckInstance<'a> {
}
SymbolKind::Interface(_) => (),
SymbolKind::SystemVerilog => (),
SymbolKind::GenericParameter => (),
_ => {
self.errors.push(AnalyzerError::mismatch_type(
name,
Expand Down
3 changes: 2 additions & 1 deletion crates/analyzer/src/handlers/check_msb_lsb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use crate::namespace::Namespace;
use crate::namespace_table;
use crate::symbol::Type as SymType;
use crate::symbol::{SymbolKind, TypeKind};
use crate::symbol_table::{self, SymbolPath, SymbolPathNamespace};
use crate::symbol_path::{SymbolPath, SymbolPathNamespace};
use crate::symbol_table;
use veryl_parser::veryl_grammar_trait::*;
use veryl_parser::veryl_walker::{Handler, HandlerPoint};
use veryl_parser::ParolError;
Expand Down
100 changes: 68 additions & 32 deletions crates/analyzer/src/handlers/create_reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use crate::analyzer_error::AnalyzerError;
use crate::namespace::Namespace;
use crate::namespace_table;
use crate::symbol::SymbolKind;
use crate::symbol_table::{self, ResolveError, ResolveErrorCause, SymbolPath};
use crate::symbol_path::{GenericSymbolPath, SymbolPath};
use crate::symbol_table::{self, ResolveError, ResolveErrorCause};
use veryl_parser::resource_table::TokenId;
use veryl_parser::veryl_grammar_trait::*;
use veryl_parser::veryl_token::TokenRange;
Expand All @@ -17,7 +18,6 @@ pub struct CreateReference<'a> {
top_level: bool,
file_scope_imported_items: Vec<TokenId>,
file_scope_imported_packages: Vec<Namespace>,
in_expression_identifier: Vec<()>,
}

impl<'a> CreateReference<'a> {
Expand Down Expand Up @@ -52,6 +52,57 @@ impl<'a> CreateReference<'a> {
unreachable!();
}
}

fn generic_symbol_path(&mut self, path: &GenericSymbolPath, namespace: &Namespace) {
if path.is_generic_reference() {
return;
}

for i in 0..path.len() {
let base_path = path.base_path(i);

match symbol_table::resolve((&base_path, namespace)) {
Ok(symbol) => {
symbol_table::add_reference(symbol.found.id, &path.paths[0].base);

// Check number of arguments
let params = symbol.found.generic_parameters().len();
let args = path.paths[i].arguments.len();
if params != args {
self.errors.push(AnalyzerError::mismatch_generics_arity(
&path.paths[i].base.to_string(),
params,
args,
self.text,
&path.range,
));
} else if let Some((token, new_symbol)) =
path.get_generic_instance(i, &symbol.found)
{
if let Some(ref x) = symbol_table::insert(&token, new_symbol) {
symbol_table::add_generic_instance(symbol.found.id, *x);
}

let table = symbol.found.generic_table(&path.paths[i].arguments);
let mut references = symbol.found.generic_references();
for path in &mut references {
path.apply_map(&table);
self.generic_symbol_path(path, &symbol.found.inner_namespace());
}
}
}
Err(err) => {
let single_path = path.paths.len() == 1;
let anonymous = path.paths[0].base.to_string() == "_";
if single_path && (anonymous || !path.resolvable) {
return;
}

self.push_resolve_error(err, &path.range);
}
}
}
}
}

impl<'a> Handler for CreateReference<'a> {
Expand Down Expand Up @@ -86,49 +137,34 @@ impl<'a> VerylGrammarTrait for CreateReference<'a> {

fn scoped_identifier(&mut self, arg: &ScopedIdentifier) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
if self.in_expression_identifier.is_empty() {
let ident = arg.identifier().token;
match symbol_table::resolve(arg) {
Ok(symbol) => {
for id in symbol.full_path {
symbol_table::add_reference(id, &ident);
}
}
Err(err) => {
self.push_resolve_error(err, &arg.into());
}
}
}
let ident = arg.identifier().token;
let path: GenericSymbolPath = arg.into();
let namespace = namespace_table::get(ident.id).unwrap();

self.generic_symbol_path(&path, &namespace);
}
Ok(())
}

fn expression_identifier(&mut self, arg: &ExpressionIdentifier) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => {
self.in_expression_identifier.push(());
// Should be executed after scoped_identifier to handle hierarchical access only
if let HandlerPoint::After = self.point {
let ident = arg.identifier().token;
let mut path: SymbolPath = arg.scoped_identifier.as_ref().into();
let namespace = namespace_table::get(ident.id).unwrap();

for x in &arg.expression_identifier_list0 {
path.push(x.identifier.identifier_token.token.text);

let ident = arg.identifier().token;
match symbol_table::resolve(arg) {
match symbol_table::resolve((&path, &namespace)) {
Ok(symbol) => {
for id in symbol.full_path {
symbol_table::add_reference(id, &ident);
}
symbol_table::add_reference(symbol.found.id, &ident);
}
Err(err) => {
let is_single_identifier = SymbolPath::from(arg).as_slice().len() == 1;
let name = ident.to_string();
if name == "_" && is_single_identifier {
return Ok(());
}

self.push_resolve_error(err, &arg.into());
}
}
}
HandlerPoint::After => {
self.in_expression_identifier.pop();
}
}
Ok(())
}
Expand Down
Loading
Loading