Skip to content

Commit cd872d1

Browse files
authored
Merge pull request #61 from Bochlin/master
Add block_header and analyze guard_condition
2 parents 7a49fed + de9b2f8 commit cd872d1

File tree

4 files changed

+224
-4
lines changed

4 files changed

+224
-4
lines changed

vhdl_lang/src/analysis/concurrent.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,22 @@ impl<'a> AnalyzeContext<'a> {
3939

4040
match statement.statement {
4141
ConcurrentStatement::Block(ref mut block) => {
42+
if let Some(ref mut guard_condition) = block.guard_condition {
43+
self.analyze_expression(parent, guard_condition, diagnostics)?;
44+
}
4245
let mut region = parent.nested();
46+
if let Some(ref mut list) = block.header.generic_clause {
47+
self.analyze_interface_list(&mut region, list, diagnostics)?;
48+
}
49+
if let Some(ref mut list) = block.header.generic_map {
50+
self.analyze_assoc_elems(parent, list, diagnostics)?;
51+
}
52+
if let Some(ref mut list) = block.header.port_clause {
53+
self.analyze_interface_list(&mut region, list, diagnostics)?;
54+
}
55+
if let Some(ref mut list) = block.header.port_map {
56+
self.analyze_assoc_elems(parent, list, diagnostics)?;
57+
}
4358
self.analyze_declarative_part(&mut region, &mut block.decl, diagnostics)?;
4459
self.analyze_concurrent_part(&mut region, &mut block.statements, diagnostics)?;
4560
}

vhdl_lang/src/analysis/tests/resolves_names.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,3 +1046,33 @@ end architecture;
10461046
",
10471047
);
10481048
}
1049+
1050+
#[test]
1051+
fn block_names_are_visible() {
1052+
check_code_with_no_diagnostics(
1053+
"
1054+
entity ent is
1055+
port (ent_in : integer);
1056+
end entity;
1057+
1058+
architecture a of ent is
1059+
signal sig : integer;
1060+
begin
1061+
blk: block (ent_in = 1) is
1062+
generic( gen : integer := 0 );
1063+
generic map ( gen => 1);
1064+
port(
1065+
prt_in : in integer := 0;
1066+
prt_out : out integer := 0
1067+
);
1068+
port map (
1069+
prt_in => ent_in + sig,
1070+
prt_out => open
1071+
);
1072+
begin
1073+
prt_out <= gen + prt_in + sig;
1074+
end block;
1075+
end architecture;
1076+
",
1077+
);
1078+
}

vhdl_lang/src/ast.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,10 +853,20 @@ pub struct LabeledSequentialStatement {
853853
#[derive(PartialEq, Debug, Clone)]
854854
pub struct BlockStatement {
855855
pub guard_condition: Option<WithPos<Expression>>,
856+
pub header: BlockHeader,
856857
pub decl: Vec<Declaration>,
857858
pub statements: Vec<LabeledConcurrentStatement>,
858859
}
859860

861+
/// LRM 11.2 Block statement
862+
#[derive(PartialEq, Debug, Clone)]
863+
pub struct BlockHeader {
864+
pub generic_clause: Option<Vec<InterfaceDeclaration>>,
865+
pub generic_map: Option<Vec<AssociationElement>>,
866+
pub port_clause: Option<Vec<InterfaceDeclaration>>,
867+
pub port_map: Option<Vec<AssociationElement>>,
868+
}
869+
860870
#[derive(PartialEq, Debug, Clone)]
861871
pub enum SensitivityList {
862872
Names(Vec<WithPos<Name>>),

vhdl_lang/src/syntax/concurrent_statement.rs

Lines changed: 169 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use super::common::ParseResult;
99
use super::declarative_part::{is_declarative_part, parse_declarative_part};
1010
use super::expression::parse_aggregate_leftpar_known;
1111
use super::expression::{parse_choices, parse_expression};
12+
use super::interface_declaration::{parse_generic_interface_list, parse_port_interface_list};
1213
use super::names::{
1314
expression_to_ident, into_selected_name, parse_association_list, parse_name_initial_token,
1415
parse_selected_name,
@@ -31,10 +32,6 @@ pub fn parse_block_statement(
3132
let token = stream.peek_expect()?;
3233
let guard_condition = {
3334
match token.kind {
34-
Is => {
35-
stream.move_after(&token);
36-
None
37-
}
3835
LeftPar => {
3936
stream.move_after(&token);
4037
let expr = parse_expression(stream)?;
@@ -44,6 +41,8 @@ pub fn parse_block_statement(
4441
_ => None,
4542
}
4643
};
44+
stream.pop_if_kind(Is)?;
45+
let header = parse_block_header(stream, diagnostics)?;
4746
let decl = parse_declarative_part(stream, diagnostics, true)?;
4847
let statements = parse_labeled_concurrent_statements(stream, diagnostics)?;
4948
stream.expect_kind(Block)?;
@@ -52,11 +51,105 @@ pub fn parse_block_statement(
5251
stream.expect_kind(SemiColon)?;
5352
Ok(BlockStatement {
5453
guard_condition,
54+
header,
5555
decl,
5656
statements,
5757
})
5858
}
5959

60+
fn parse_block_header(
61+
stream: &mut TokenStream,
62+
diagnostics: &mut dyn DiagnosticHandler,
63+
) -> ParseResult<BlockHeader> {
64+
let mut generic_clause = None;
65+
let mut generic_map = None;
66+
let mut port_clause = None;
67+
let mut port_map = None;
68+
69+
loop {
70+
let token = stream.peek_expect()?;
71+
match token.kind {
72+
Generic => {
73+
stream.move_after(&token);
74+
if let Some(map_token) = stream.pop_if_kind(Map)? {
75+
if port_clause.is_some() || port_map.is_some() {
76+
diagnostics.push(Diagnostic::error(
77+
map_token,
78+
"Generic map must come before port clause and port map",
79+
));
80+
} else if generic_clause.is_none() {
81+
diagnostics.push(Diagnostic::error(
82+
map_token,
83+
"Generic map declared without preceeding generic clause",
84+
));
85+
} else if generic_map.is_some() {
86+
diagnostics.push(Diagnostic::error(map_token, "Duplicate generic map"));
87+
}
88+
let parsed_generic_map = Some(parse_association_list(stream)?);
89+
stream.expect_kind(SemiColon)?;
90+
if generic_map.is_none() {
91+
generic_map = parsed_generic_map;
92+
}
93+
} else {
94+
if generic_map.is_some() {
95+
diagnostics.push(Diagnostic::error(
96+
token,
97+
"Generic clause must come before generic map",
98+
));
99+
} else if generic_clause.is_some() {
100+
diagnostics.push(Diagnostic::error(token, "Duplicate generic clause"));
101+
}
102+
let parsed_generic_list = parse_generic_interface_list(stream, diagnostics)?;
103+
stream.expect_kind(SemiColon)?;
104+
if generic_clause.is_none() {
105+
generic_clause = Some(parsed_generic_list);
106+
}
107+
}
108+
}
109+
Port => {
110+
stream.move_after(&token);
111+
if let Some(map_token) = stream.pop_if_kind(Map)? {
112+
if port_clause.is_none() {
113+
diagnostics.push(Diagnostic::error(
114+
map_token,
115+
"Port map declared without preceeding port clause",
116+
));
117+
} else if port_map.is_some() {
118+
diagnostics.push(Diagnostic::error(map_token, "Duplicate port map"));
119+
}
120+
let parsed_port_map = Some(parse_association_list(stream)?);
121+
stream.expect_kind(SemiColon)?;
122+
if port_map.is_none() {
123+
port_map = parsed_port_map;
124+
}
125+
} else {
126+
if port_map.is_some() {
127+
diagnostics.push(Diagnostic::error(
128+
token,
129+
"Port clause declared after port map",
130+
));
131+
} else if port_clause.is_some() {
132+
diagnostics.push(Diagnostic::error(token, "Duplicate port clause"));
133+
}
134+
let parsed_port_list = parse_port_interface_list(stream, diagnostics)?;
135+
stream.expect_kind(SemiColon)?;
136+
if port_clause.is_none() {
137+
port_clause = Some(parsed_port_list);
138+
}
139+
}
140+
}
141+
_ => break,
142+
}
143+
}
144+
145+
Ok(BlockHeader {
146+
generic_clause,
147+
generic_map,
148+
port_clause,
149+
port_map,
150+
})
151+
}
152+
60153
/// LRM 11.3 Process statement
61154
pub fn parse_process_statement(
62155
stream: &mut TokenStream,
@@ -687,6 +780,12 @@ end block;
687780

688781
let block = BlockStatement {
689782
guard_condition: None,
783+
header: BlockHeader {
784+
generic_clause: None,
785+
generic_map: None,
786+
port_clause: None,
787+
port_map: None,
788+
},
690789
decl: code.s1("constant const : natural := 0;").declarative_part(),
691790
statements: vec![LabeledConcurrentStatement {
692791
label: Some(code.s1("name2").ident()),
@@ -709,6 +808,12 @@ end block name;
709808
);
710809
let block = BlockStatement {
711810
guard_condition: None,
811+
header: BlockHeader {
812+
generic_clause: None,
813+
generic_map: None,
814+
port_clause: None,
815+
port_map: None,
816+
},
712817
decl: vec![],
713818
statements: vec![],
714819
};
@@ -728,6 +833,66 @@ end block;
728833
);
729834
let block = BlockStatement {
730835
guard_condition: Some(code.s1("cond = true").expr()),
836+
header: BlockHeader {
837+
generic_clause: None,
838+
generic_map: None,
839+
port_clause: None,
840+
port_map: None,
841+
},
842+
decl: vec![],
843+
statements: vec![],
844+
};
845+
let stmt = code.with_stream_no_diagnostics(parse_labeled_concurrent_statement);
846+
assert_eq!(stmt.label, Some(code.s1("name").ident()));
847+
assert_eq!(stmt.statement, ConcurrentStatement::Block(block));
848+
}
849+
850+
#[test]
851+
fn test_guarded_block_variant() {
852+
let code = Code::new(
853+
"\
854+
name : block (cond = true) is
855+
begin
856+
end block;
857+
",
858+
);
859+
let block = BlockStatement {
860+
guard_condition: Some(code.s1("cond = true").expr()),
861+
header: BlockHeader {
862+
generic_clause: None,
863+
generic_map: None,
864+
port_clause: None,
865+
port_map: None,
866+
},
867+
decl: vec![],
868+
statements: vec![],
869+
};
870+
let stmt = code.with_stream_no_diagnostics(parse_labeled_concurrent_statement);
871+
assert_eq!(stmt.label, Some(code.s1("name").ident()));
872+
assert_eq!(stmt.statement, ConcurrentStatement::Block(block));
873+
}
874+
875+
#[test]
876+
fn test_block_header() {
877+
let code = Code::new(
878+
"\
879+
name: block is
880+
generic(gen: integer := 1);
881+
generic map(gen => 1);
882+
port(prt: integer := 1);
883+
port map(prt => 2);
884+
begin
885+
end block;
886+
",
887+
);
888+
let block = BlockStatement {
889+
guard_condition: None,
890+
header: BlockHeader {
891+
generic_clause: Some(vec![code.s1("gen: integer := 1").generic()]),
892+
generic_map: Some(code.s1("(gen => 1)").association_list()),
893+
port_clause: Some(vec![code.s1("prt: integer := 1").port()]),
894+
port_map: Some(code.s1("(prt => 2)").association_list()),
895+
},
731896
decl: vec![],
732897
statements: vec![],
733898
};

0 commit comments

Comments
 (0)