Skip to content

Commit 90746bf

Browse files
support embed component path
(refs: #1751)
1 parent 4255cd0 commit 90746bf

20 files changed

Lines changed: 36244 additions & 34153 deletions

File tree

crates/analyzer/src/handlers/create_symbol_table.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2255,15 +2255,23 @@ impl VerylGrammarTrait for CreateSymbolTable {
22552255
}
22562256
}
22572257

2258-
let content = &arg.embed_content.embed_content_token.token;
2258+
let content = &arg.embed_content;
2259+
let content_source = content
2260+
.embed_triple_l_brace
2261+
.embed_triple_l_brace_token
2262+
.token
2263+
.source;
22592264
let r#type = match way.as_str() {
22602265
"inline" => Some(TestType::Inline),
2261-
"cocotb" => Some(TestType::CocotbEmbed(content.text)),
2266+
"cocotb" => Some(TestType::CocotbEmbed(
2267+
content.as_ref().clone(),
2268+
self.namespace.clone(),
2269+
)),
22622270
_ => None,
22632271
};
22642272

22652273
if let (Some((token, top)), Some(r#type)) = (test_attr, r#type) {
2266-
let path = if let TokenSource::File { path, .. } = content.source {
2274+
let path = if let TokenSource::File { path, .. } = content_source {
22672275
path
22682276
} else {
22692277
unreachable!()

crates/analyzer/src/symbol.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2176,7 +2176,7 @@ pub struct GenericInstanceProperty {
21762176
#[derive(Debug, Clone)]
21772177
pub enum TestType {
21782178
Inline,
2179-
CocotbEmbed(StrId),
2179+
CocotbEmbed(syntax_tree::EmbedContent, Namespace),
21802180
CocotbInclude(StrId),
21812181
}
21822182

crates/analyzer/src/symbol_path.rs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::namespace::Namespace;
22
use crate::namespace_table;
33
use crate::symbol::{DocComment, GenericInstanceProperty, GenericMap, Symbol, SymbolKind};
4-
use crate::symbol_table;
4+
use crate::symbol_table::{self, ResolveError, ResolveResult};
55
use crate::{SVec, svec};
66
use std::cmp::Ordering;
77
use std::fmt;
@@ -460,6 +460,66 @@ impl GenericSymbolPath {
460460
}
461461
}
462462

463+
pub fn resolve_path(
464+
&self,
465+
namespace: &Namespace,
466+
generic_maps: Option<&Vec<GenericMap>>,
467+
) -> (Result<ResolveResult, ResolveError>, GenericSymbolPath) {
468+
let mut path = self.clone();
469+
path.resolve_imported(namespace, generic_maps);
470+
471+
for i in 0..path.len() {
472+
let base = path.base_path(i);
473+
if let Ok(symbol) = symbol_table::resolve((&base, namespace)) {
474+
if !symbol.found.kind.is_generic() {
475+
continue;
476+
}
477+
478+
let params = symbol.found.generic_parameters();
479+
let n_args = path.paths[i].arguments.len();
480+
481+
for param in params.iter().skip(n_args) {
482+
path.paths[i]
483+
.arguments
484+
.push(param.1.default_value.as_ref().unwrap().clone());
485+
}
486+
487+
for arg in &mut path.paths[i].arguments {
488+
if let Ok(symbol) = symbol_table::resolve((&arg.mangled_path(), namespace)) {
489+
if let Some(target) = symbol.found.alias_target() {
490+
if let (Ok(_), path) =
491+
target.resolve_path(&symbol.found.namespace, generic_maps)
492+
{
493+
*arg = path;
494+
}
495+
}
496+
}
497+
}
498+
}
499+
}
500+
501+
if let Some(maps) = generic_maps {
502+
path.apply_map(maps);
503+
}
504+
505+
let result = symbol_table::resolve((&path.mangled_path(), namespace));
506+
if let Ok(symbol) = &result {
507+
if let Some(target) = symbol.found.alias_target() {
508+
if let Some(parent) = symbol.found.get_parent() {
509+
if matches!(parent.kind, SymbolKind::GenericInstance(_)) {
510+
// Alias target may be a generic parameter if it is defined in a generic package.
511+
// Need to apply parent's generic map to resolve a generic parameter.
512+
let map = parent.generic_maps();
513+
return target.resolve_path(&symbol.found.namespace, Some(&map));
514+
}
515+
}
516+
return target.resolve_path(&symbol.found.namespace, generic_maps);
517+
}
518+
}
519+
520+
(result, path)
521+
}
522+
463523
/// Resolve and expand path if the path is imported at declaration
464524
pub fn resolve_imported(
465525
&mut self,

crates/analyzer/src/tests.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3770,6 +3770,20 @@ fn undefined_identifier() {
37703770
errors[1],
37713771
AnalyzerError::UndefinedIdentifier { .. }
37723772
));
3773+
3774+
let code = r#"
3775+
module ModuleA {
3776+
embed(inline) sv {{{
3777+
\((( ModuleB ))) u_monitor();
3778+
}}}
3779+
}
3780+
"#;
3781+
3782+
let errors = analyze(code);
3783+
assert!(matches!(
3784+
errors[0],
3785+
AnalyzerError::UndefinedIdentifier { .. }
3786+
));
37733787
}
37743788

37753789
#[test]

crates/emitter/src/emitter.rs

Lines changed: 41 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ pub struct Emitter {
6060
single_line: Vec<()>,
6161
multi_line: Vec<()>,
6262
adjust_line: bool,
63+
keep_tail_newline: bool,
6364
in_always_ff: bool,
6465
in_direction_modport: bool,
6566
in_direction_with_var: bool,
@@ -108,6 +109,7 @@ impl Default for Emitter {
108109
single_line: Vec::new(),
109110
multi_line: Vec::new(),
110111
adjust_line: false,
112+
keep_tail_newline: false,
111113
in_always_ff: false,
112114
in_direction_modport: false,
113115
in_direction_with_var: false,
@@ -328,7 +330,7 @@ impl Emitter {
328330
fn push_token(&mut self, x: &Token) {
329331
self.consume_adjust_line(x);
330332
let text = resource_table::get_str_value(x.text).unwrap();
331-
let text = if text.ends_with('\n') {
333+
let text = if !self.keep_tail_newline && text.ends_with('\n') {
332334
self.consumed_next_newline = true;
333335
text.trim_end()
334336
} else {
@@ -1559,8 +1561,7 @@ impl Emitter {
15591561
}
15601562

15611563
let user_defined = r#type.unwrap().get_user_defined()?;
1562-
let (type_symbol, _) =
1563-
resolve_generic_path(&user_defined.path, &symbol.namespace, Some(map));
1564+
let (type_symbol, _) = user_defined.path.resolve_path(&symbol.namespace, Some(map));
15641565
type_symbol
15651566
.ok()
15661567
.map(|x| (x.found, x.full_path, x.generic_tables))
@@ -1796,10 +1797,10 @@ impl Emitter {
17961797
) -> (Result<ResolveResult, ResolveError>, GenericSymbolPath) {
17971798
let generic_map = self.generic_map.last();
17981799
if let Some(namespace) = namespace {
1799-
resolve_generic_path(path, namespace, generic_map)
1800+
path.resolve_path(namespace, generic_map)
18001801
} else {
18011802
let namespace = namespace_table::get(path.paths[0].base.id).unwrap();
1802-
resolve_generic_path(path, &namespace, generic_map)
1803+
path.resolve_path(&namespace, generic_map)
18031804
}
18041805
}
18051806

@@ -2007,6 +2008,11 @@ impl VerylWalker for Emitter {
20072008
}
20082009
}
20092010

2011+
/// Semantic action for non-terminal 'EscapedBackslash'
2012+
fn escaped_backslash(&mut self, arg: &EscapedBackslash) {
2013+
self.token(&arg.escaped_backslash_token.replace("\\"));
2014+
}
2015+
20102016
/// Semantic action for non-terminal 'Bool'
20112017
fn bool(&mut self, arg: &Bool) {
20122018
self.veryl_token(&arg.bool_token.replace("logic"));
@@ -5268,21 +5274,39 @@ impl VerylWalker for Emitter {
52685274
/// Semantic action for non-terminal 'EmbedDeclaration'
52695275
fn embed_declaration(&mut self, arg: &EmbedDeclaration) {
52705276
if arg.identifier.identifier_token.to_string() == "inline" {
5271-
let text = arg.embed_content.embed_content_token.to_string();
5272-
let text = if arg.identifier0.identifier_token.to_string() == "sv" {
5273-
&text
5274-
.replace("{{{", "`ifndef SYNTHESIS")
5275-
.replace("}}}", "`endif")
5276-
} else {
5277-
text.strip_prefix("{{{")
5278-
.unwrap()
5279-
.strip_prefix("}}}")
5280-
.unwrap()
5281-
};
5282-
self.veryl_token(&arg.embed_content.embed_content_token.replace(text));
5277+
let is_sv = arg.identifier0.identifier_token.to_string() == "sv";
5278+
5279+
if is_sv {
5280+
self.token(
5281+
&arg.embed_content
5282+
.embed_triple_l_brace
5283+
.embed_triple_l_brace_token
5284+
.replace("`ifndef SYNTHESIS"),
5285+
);
5286+
}
5287+
5288+
self.keep_tail_newline = true;
5289+
for x in &arg.embed_content.embed_content_list {
5290+
self.embed_item(&x.embed_item);
5291+
}
5292+
self.keep_tail_newline = false;
5293+
5294+
if is_sv {
5295+
self.token(
5296+
&arg.embed_content
5297+
.embed_triple_r_brace
5298+
.embed_triple_r_brace_token
5299+
.replace("`endif"),
5300+
);
5301+
}
52835302
}
52845303
}
52855304

5305+
/// Semantic action for non-terminal 'EmbedIdentifier'
5306+
fn embed_identifier(&mut self, arg: &EmbedIdentifier) {
5307+
self.scoped_identifier(&arg.scoped_identifier);
5308+
}
5309+
52865310
/// Semantic action for non-terminal 'IncludeDeclaration'
52875311
fn include_declaration(&mut self, arg: &IncludeDeclaration) {
52885312
if arg.identifier.identifier_token.to_string() == "inline" {
@@ -5724,63 +5748,3 @@ pub fn emitting_identifier(arg: &Identifier) -> Identifier {
57245748
};
57255749
identifier_with_prefix_suffix(arg, &prefix, &suffix)
57265750
}
5727-
5728-
pub fn resolve_generic_path(
5729-
path: &GenericSymbolPath,
5730-
namespace: &Namespace,
5731-
generic_maps: Option<&Vec<GenericMap>>,
5732-
) -> (Result<ResolveResult, ResolveError>, GenericSymbolPath) {
5733-
let mut path = path.clone();
5734-
path.resolve_imported(namespace, generic_maps);
5735-
5736-
for i in 0..path.len() {
5737-
let base = path.base_path(i);
5738-
if let Ok(symbol) = symbol_table::resolve((&base, namespace)) {
5739-
if !symbol.found.kind.is_generic() {
5740-
continue;
5741-
}
5742-
5743-
let params = symbol.found.generic_parameters();
5744-
let n_args = path.paths[i].arguments.len();
5745-
5746-
for param in params.iter().skip(n_args) {
5747-
path.paths[i]
5748-
.arguments
5749-
.push(param.1.default_value.as_ref().unwrap().clone());
5750-
}
5751-
5752-
for arg in &mut path.paths[i].arguments {
5753-
if let Ok(symbol) = symbol_table::resolve((&arg.mangled_path(), namespace)) {
5754-
if let Some(target) = symbol.found.alias_target() {
5755-
if let (Ok(_), path) =
5756-
resolve_generic_path(&target, &symbol.found.namespace, generic_maps)
5757-
{
5758-
*arg = path;
5759-
}
5760-
}
5761-
}
5762-
}
5763-
}
5764-
}
5765-
5766-
if let Some(maps) = generic_maps {
5767-
path.apply_map(maps);
5768-
}
5769-
5770-
let result = symbol_table::resolve((&path.mangled_path(), namespace));
5771-
if let Ok(symbol) = &result {
5772-
if let Some(target) = symbol.found.alias_target() {
5773-
if let Some(parent) = symbol.found.get_parent() {
5774-
if matches!(parent.kind, SymbolKind::GenericInstance(_)) {
5775-
// Alias target may be a generic parameter if it is defined in a generic package.
5776-
// Need to apply parent's generic map to resolve a generic parameter.
5777-
let map = parent.generic_maps();
5778-
return resolve_generic_path(&target, &symbol.found.namespace, Some(&map));
5779-
}
5780-
}
5781-
return resolve_generic_path(&target, &symbol.found.namespace, generic_maps);
5782-
}
5783-
}
5784-
5785-
(result, path)
5786-
}

crates/emitter/src/expaneded_modport.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::emitter::{SymbolContext, resolve_generic_path, symbol_string};
1+
use crate::emitter::{SymbolContext, symbol_string};
22
use std::collections::HashMap;
33
use veryl_analyzer::attribute::ExpandItem;
44
use veryl_analyzer::attribute_table;
@@ -497,7 +497,7 @@ fn resolve_interface(
497497
let mut path = user_defined.get_user_defined()?.path.clone();
498498
path.paths.pop(); // remove modport path
499499

500-
let (result, _) = resolve_generic_path(&path, namespace, Some(&generic_map.to_vec()));
500+
let (result, _) = path.resolve_path(namespace, Some(&generic_map.to_vec()));
501501
result
502502
.ok()
503503
.map(|x| (x.found, x.full_path, x.generic_tables))

crates/formatter/src/formatter.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ pub struct Formatter {
3232
single_line: Vec<()>,
3333
multi_line: Vec<()>,
3434
adjust_line: bool,
35+
keep_tail_newline: bool,
3536
in_scalar_type: bool,
3637
in_expression: Vec<()>,
3738
in_attribute: bool,
@@ -53,6 +54,7 @@ impl Default for Formatter {
5354
single_line: Vec::new(),
5455
multi_line: Vec::new(),
5556
adjust_line: false,
57+
keep_tail_newline: false,
5658
in_scalar_type: false,
5759
in_expression: Vec::new(),
5860
in_attribute: false,
@@ -214,7 +216,7 @@ impl Formatter {
214216
fn push_token(&mut self, x: &Token) {
215217
self.consume_adjust_line(x);
216218
let text = resource_table::get_str_value(x.text).unwrap();
217-
let text = if text.ends_with('\n') {
219+
let text = if !self.keep_tail_newline && text.ends_with('\n') {
218220
self.consumed_next_newline = true;
219221
text.trim_end()
220222
} else {
@@ -2780,6 +2782,37 @@ impl VerylWalker for Formatter {
27802782
self.embed_content(&arg.embed_content);
27812783
}
27822784

2785+
/// Semantic action for non-terminal 'EmbedContent'
2786+
fn embed_content(&mut self, arg: &EmbedContent) {
2787+
self.embed_triple_l_brace(&arg.embed_triple_l_brace);
2788+
self.keep_tail_newline = true;
2789+
for x in &arg.embed_content_list {
2790+
self.embed_item(&x.embed_item);
2791+
}
2792+
self.keep_tail_newline = false;
2793+
if !self
2794+
.string
2795+
.chars()
2796+
.last()
2797+
.map(|c| c.is_ascii_whitespace())
2798+
.unwrap_or(false)
2799+
{
2800+
self.newline();
2801+
}
2802+
self.embed_triple_r_brace(&arg.embed_triple_r_brace);
2803+
}
2804+
2805+
/// Semantic action for non-terminal 'EmbedIdentifier'
2806+
fn embed_identifier(&mut self, arg: &EmbedIdentifier) {
2807+
self.escaped_l_paren(&arg.escaped_l_paren);
2808+
self.embed_l_paren(&arg.embed_l_paren);
2809+
self.embed_l_paren(&arg.embed_l_paren0);
2810+
self.scoped_identifier(&arg.scoped_identifier);
2811+
self.embed_r_paren(&arg.embed_r_paren);
2812+
self.embed_r_paren(&arg.embed_r_paren0);
2813+
self.embed_r_paren(&arg.embed_r_paren1);
2814+
}
2815+
27832816
/// Semantic action for non-terminal 'IncludeDeclaration'
27842817
fn include_declaration(&mut self, arg: &IncludeDeclaration) {
27852818
self.include(&arg.include);

0 commit comments

Comments
 (0)