Skip to content

Commit

Permalink
Merge pull request #204 from Schottkyc137/map-aspect-lax-parsing
Browse files Browse the repository at this point in the history
Improve diagnostics for map aspects
  • Loading branch information
kraigher authored Oct 21, 2023
2 parents 34883b5 + 5da474c commit a6cc02f
Show file tree
Hide file tree
Showing 11 changed files with 354 additions and 106 deletions.
9 changes: 9 additions & 0 deletions vhdl_lang/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,15 @@ pub struct SeparatedList<T> {
pub tokens: Vec<TokenId>,
}

impl<T> Default for SeparatedList<T> {
fn default() -> Self {
SeparatedList {
items: Vec::default(),
tokens: Vec::default(),
}
}
}

impl SeparatedList<AssociationElement> {
/// Returns an iterator over the formal elements of this list
pub fn formals(&self) -> impl Iterator<Item = &Designator> {
Expand Down
28 changes: 17 additions & 11 deletions vhdl_lang/src/syntax/concurrent_statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ fn parse_block_header(
"Duplicate generic map",
));
}
let (list, closing_paren) = parse_association_list(stream)?;
let (list, closing_paren) = parse_association_list(stream, diagnostics)?;
stream.expect_kind(SemiColon)?;
if generic_map.is_none() {
generic_map = Some(MapAspect {
Expand Down Expand Up @@ -133,7 +133,7 @@ fn parse_block_header(
"Duplicate port map",
));
}
let (list, closing_paren) = parse_association_list(stream)?;
let (list, closing_paren) = parse_association_list(stream, diagnostics)?;
stream.expect_kind(SemiColon)?;
if port_map.is_none() {
port_map = Some(MapAspect {
Expand Down Expand Up @@ -332,10 +332,14 @@ pub fn parse_concurrent_assert_statement(
})
}

pub fn parse_map_aspect(stream: &TokenStream, aspect_kind: Kind) -> ParseResult<Option<MapAspect>> {
pub fn parse_map_aspect(
stream: &TokenStream,
aspect_kind: Kind,
diagnostics: &mut dyn DiagnosticHandler,
) -> ParseResult<Option<MapAspect>> {
if let Some(aspect) = stream.pop_if_kind(aspect_kind) {
stream.expect_kind(Map)?;
let (list, closing_paren) = parse_association_list(stream)?;
let (list, closing_paren) = parse_association_list(stream, diagnostics)?;
Ok(Some(MapAspect {
start: aspect,
list,
Expand All @@ -349,18 +353,20 @@ pub fn parse_map_aspect(stream: &TokenStream, aspect_kind: Kind) -> ParseResult<
#[allow(clippy::type_complexity)]
pub fn parse_generic_and_port_map(
stream: &TokenStream,
diagnostics: &mut dyn DiagnosticHandler,
) -> ParseResult<(Option<MapAspect>, Option<MapAspect>)> {
let generic_map = parse_map_aspect(stream, Generic)?;
let port_map = parse_map_aspect(stream, Port)?;
let generic_map = parse_map_aspect(stream, Generic, diagnostics)?;
let port_map = parse_map_aspect(stream, Port, diagnostics)?;

Ok((generic_map, port_map))
}

pub fn parse_instantiation_statement(
stream: &TokenStream,
unit: InstantiatedUnit,
diagnostics: &mut dyn DiagnosticHandler,
) -> ParseResult<InstantiationStatement> {
let (generic_map, port_map) = parse_generic_and_port_map(stream)?;
let (generic_map, port_map) = parse_generic_and_port_map(stream, diagnostics)?;

let semi = stream.expect_kind(SemiColon)?;

Expand Down Expand Up @@ -586,12 +592,12 @@ pub fn parse_concurrent_statement(
Component => {
stream.skip();
let unit = InstantiatedUnit::Component(parse_selected_name(stream)?);
ConcurrentStatement::Instance(parse_instantiation_statement(stream, unit)?)
ConcurrentStatement::Instance(parse_instantiation_statement(stream, unit, diagnostics)?)
},
Configuration => {
stream.skip();
let unit = InstantiatedUnit::Configuration(parse_selected_name(stream)?);
ConcurrentStatement::Instance(parse_instantiation_statement(stream, unit)?)
ConcurrentStatement::Instance(parse_instantiation_statement(stream, unit, diagnostics)?)
},
Entity => {
stream.skip();
Expand All @@ -606,7 +612,7 @@ pub fn parse_concurrent_statement(
}
};
let unit = InstantiatedUnit::Entity(name, arch.map(WithRef::new));
ConcurrentStatement::Instance(parse_instantiation_statement(stream, unit)?)
ConcurrentStatement::Instance(parse_instantiation_statement(stream, unit, diagnostics)?)
},
For => ConcurrentStatement::ForGenerate(parse_for_generate_statement(stream, label, diagnostics)?),
If => ConcurrentStatement::IfGenerate(parse_if_generate_statement(stream, label, diagnostics)?),
Expand All @@ -633,7 +639,7 @@ pub fn parse_concurrent_statement(
match token.kind {
Generic|Port => {
let unit = InstantiatedUnit::Component(into_selected_name(name)?);
ConcurrentStatement::Instance(parse_instantiation_statement(stream, unit)?)
ConcurrentStatement::Instance(parse_instantiation_statement(stream, unit, diagnostics)?)
}
_ => {
parse_assignment_or_procedure_call(stream, name.map_into(Target::Name))?
Expand Down
26 changes: 17 additions & 9 deletions vhdl_lang/src/syntax/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ fn parse_entity_aspect(stream: &TokenStream) -> ParseResult<EntityAspect> {
fn parse_binding_indication_known_entity_aspect(
entity_aspect: Option<EntityAspect>,
stream: &TokenStream,
diagnostics: &mut dyn DiagnosticHandler,
) -> ParseResult<BindingIndication> {
let (generic_map, port_map) = parse_generic_and_port_map(stream)?;
let (generic_map, port_map) = parse_generic_and_port_map(stream, diagnostics)?;

stream.expect_kind(SemiColon)?;
Ok(BindingIndication {
Expand All @@ -52,13 +53,16 @@ fn parse_binding_indication_known_entity_aspect(
}

/// LRM 7.3.2
fn parse_binding_indication(stream: &TokenStream) -> ParseResult<BindingIndication> {
fn parse_binding_indication(
stream: &TokenStream,
diagnostics: &mut dyn DiagnosticHandler,
) -> ParseResult<BindingIndication> {
let entity_aspect = if stream.skip_if_kind(Use) {
Some(parse_entity_aspect(stream)?)
} else {
None
};
parse_binding_indication_known_entity_aspect(entity_aspect, stream)
parse_binding_indication_known_entity_aspect(entity_aspect, stream, diagnostics)
}

fn parse_component_configuration_known_spec(
Expand All @@ -78,7 +82,7 @@ fn parse_component_configuration_known_spec(
(None, vunit_bind_inds)
} else {
let aspect = parse_entity_aspect(stream)?;
let bind_ind = parse_binding_indication_known_entity_aspect(Some(aspect), stream)?;
let bind_ind = parse_binding_indication_known_entity_aspect(Some(aspect), stream, diagnostics)?;

if stream.skip_if_kind(Use) {
(Some(bind_ind), parse_vunit_binding_indication_list_known_keyword(stream)?)
Expand Down Expand Up @@ -284,7 +288,10 @@ pub fn parse_configuration_declaration(
break parse_vunit_binding_indication_list_known_keyword(stream)?;
}

decl.push(ConfigurationDeclarativeItem::Use(parse_use_clause(stream)?));
decl.push(ConfigurationDeclarativeItem::Use(parse_use_clause(
stream,
diagnostics,
)?));
}
_ => break Vec::new(),
}
Expand Down Expand Up @@ -312,11 +319,12 @@ pub fn parse_configuration_declaration(
/// LRM 7.3 Configuration Specification
pub fn parse_configuration_specification(
stream: &TokenStream,
diagnsotics: &mut dyn DiagnosticHandler,
) -> ParseResult<ConfigurationSpecification> {
stream.expect_kind(For)?;
match parse_component_specification_or_name(stream)? {
ComponentSpecificationOrName::ComponentSpec(spec) => {
let bind_ind = parse_binding_indication(stream)?;
let bind_ind = parse_binding_indication(stream, diagnsotics)?;
if stream.skip_if_kind(Use) {
let vunit_bind_inds = parse_vunit_binding_indication_list_known_keyword(stream)?;
stream.expect_kind(End)?;
Expand Down Expand Up @@ -814,7 +822,7 @@ end configuration cfg;
let code = Code::new("for all : lib.pkg.comp use entity work.foo(rtl);");

assert_eq!(
code.with_stream(parse_configuration_specification),
code.with_stream_no_diagnostics(parse_configuration_specification),
ConfigurationSpecification {
spec: ComponentSpecification {
instantiation_list: InstantiationList::All,
Expand All @@ -838,7 +846,7 @@ end configuration cfg;
let code = Code::new("for all : lib.pkg.comp use entity work.foo(rtl); end for;");

assert_eq!(
code.with_stream(parse_configuration_specification),
code.with_stream_no_diagnostics(parse_configuration_specification),
ConfigurationSpecification {
spec: ComponentSpecification {
instantiation_list: InstantiationList::All,
Expand All @@ -864,7 +872,7 @@ end configuration cfg;
);

assert_eq!(
code.with_stream(parse_configuration_specification),
code.with_stream_no_diagnostics(parse_configuration_specification),
ConfigurationSpecification {
spec: ComponentSpecification {
instantiation_list: InstantiationList::All,
Expand Down
35 changes: 22 additions & 13 deletions vhdl_lang/src/syntax/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ use crate::data::*;
use crate::syntax::separated_list::{parse_ident_list, parse_name_list};

/// LRM 13. Design units and their analysis
pub fn parse_library_clause(stream: &TokenStream) -> ParseResult<LibraryClause> {
pub fn parse_library_clause(
stream: &TokenStream,
diagnsotics: &mut dyn DiagnosticHandler,
) -> ParseResult<LibraryClause> {
let library_token = stream.expect_kind(Library)?;
let name_list = parse_ident_list(stream)?;
let name_list = parse_ident_list(stream, diagnsotics)?;
let semi_token = stream.expect_kind(SemiColon)?;
Ok(LibraryClause {
library_token,
Expand All @@ -25,10 +28,13 @@ pub fn parse_library_clause(stream: &TokenStream) -> ParseResult<LibraryClause>
}

/// LRM 12.4. Use clauses
pub fn parse_use_clause(stream: &TokenStream) -> ParseResult<UseClause> {
pub fn parse_use_clause(
stream: &TokenStream,
diagnsotics: &mut dyn DiagnosticHandler,
) -> ParseResult<UseClause> {
let use_token = stream.expect_kind(Use)?;

let name_list = parse_name_list(stream)?;
let name_list = parse_name_list(stream, diagnsotics)?;
let semi_token = stream.expect_kind(SemiColon)?;
Ok(UseClause {
use_token,
Expand All @@ -43,10 +49,13 @@ pub enum DeclarationOrReference {
Reference(ContextReference),
}

pub fn parse_context_reference(stream: &TokenStream) -> ParseResult<ContextReference> {
pub fn parse_context_reference(
stream: &TokenStream,
diagnostics: &mut dyn DiagnosticHandler,
) -> ParseResult<ContextReference> {
let context_token = stream.expect_kind(Context)?;

let name_list = parse_name_list(stream)?;
let name_list = parse_name_list(stream, diagnostics)?;
let semi_token = stream.expect_kind(SemiColon)?;
Ok(ContextReference {
context_token,
Expand All @@ -69,9 +78,9 @@ pub fn parse_context(
let token = stream.peek_expect()?;
try_init_token_kind!(
token,
Library => items.push(ContextItem::Library(parse_library_clause(stream)?)),
Use => items.push(ContextItem::Use(parse_use_clause(stream)?)),
Context => items.push(ContextItem::Context(parse_context_reference(stream)?)),
Library => items.push(ContextItem::Library(parse_library_clause(stream, diagnostics)?)),
Use => items.push(ContextItem::Use(parse_use_clause(stream, diagnostics)?)),
Context => items.push(ContextItem::Context(parse_context_reference(stream, diagnostics)?)),
End => {
stream.skip();
stream.pop_if_kind(Context);
Expand Down Expand Up @@ -117,7 +126,7 @@ mod tests {
fn test_library_clause_single_name() {
let code = Code::new("library foo;");
assert_eq!(
code.with_stream(parse_library_clause),
code.with_stream_no_diagnostics(parse_library_clause),
LibraryClause {
library_token: code.s1("library").token(),
name_list: code.s1("foo").ident_list(),
Expand All @@ -130,7 +139,7 @@ mod tests {
fn test_library_clause_multiple_names() {
let code = Code::new("library foo, bar;");
assert_eq!(
code.with_stream(parse_library_clause),
code.with_stream_no_diagnostics(parse_library_clause),
LibraryClause {
library_token: code.s1("library").token(),
name_list: code.s1("foo, bar").ident_list(),
Expand All @@ -143,7 +152,7 @@ mod tests {
fn test_use_clause_single_name() {
let code = Code::new("use lib.foo;");
assert_eq!(
code.with_stream(parse_use_clause),
code.with_stream_no_diagnostics(parse_use_clause),
UseClause {
use_token: code.s1("use").token(),
name_list: code.s1("lib.foo").name_list(),
Expand All @@ -156,7 +165,7 @@ mod tests {
fn test_use_clause_multiple_names() {
let code = Code::new("use foo.'a', lib.bar.all;");
assert_eq!(
code.with_stream(parse_use_clause),
code.with_stream_no_diagnostics(parse_use_clause),
UseClause {
use_token: code.s1("use").token(),
name_list: code.s1("foo.'a', lib.bar.all").name_list(),
Expand Down
21 changes: 12 additions & 9 deletions vhdl_lang/src/syntax/declarative_part.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ use crate::ast::{ContextClause, Declaration, PackageInstantiation};
use crate::data::DiagnosticHandler;
use crate::syntax::concurrent_statement::parse_map_aspect;

pub fn parse_package_instantiation(stream: &TokenStream) -> ParseResult<PackageInstantiation> {
pub fn parse_package_instantiation(
stream: &TokenStream,
diagnsotics: &mut dyn DiagnosticHandler,
) -> ParseResult<PackageInstantiation> {
stream.expect_kind(Package)?;
let ident = stream.expect_ident()?;
stream.expect_kind(Is)?;
stream.expect_kind(New)?;
let package_name = parse_selected_name(stream)?;
let generic_map = parse_map_aspect(stream, Generic)?;
let generic_map = parse_map_aspect(stream, Generic, diagnsotics)?;
stream.expect_kind(SemiColon)?;

Ok(PackageInstantiation {
Expand Down Expand Up @@ -98,10 +101,10 @@ pub fn parse_declarative_part(
Component => parse_component_declaration(stream, diagnostics)
.map(Declaration::Component)?,
Impure | Pure | Function | Procedure => parse_subprogram(stream, diagnostics)?,
Package => parse_package_instantiation(stream).map(Declaration::Package)?,
For => {
parse_configuration_specification(stream).map(Declaration::Configuration)?
}
Package => parse_package_instantiation(stream, diagnostics)
.map(Declaration::Package)?,
For => parse_configuration_specification(stream, diagnostics)
.map(Declaration::Configuration)?,
_ => unreachable!(),
};
declarations.push(decl);
Expand All @@ -128,7 +131,7 @@ pub fn parse_declarative_part(

Use | Alias => {
let decl: ParseResult<Declaration> = match token.kind {
Use => parse_use_clause(stream).map(Declaration::Use),
Use => parse_use_clause(stream, diagnostics).map(Declaration::Use),
Alias => parse_alias_declaration(stream).map(Declaration::Alias),
_ => unreachable!(),
};
Expand Down Expand Up @@ -170,7 +173,7 @@ package ident is new lib.foo.bar;
",
);
assert_eq!(
code.with_stream(parse_package_instantiation),
code.with_stream_no_diagnostics(parse_package_instantiation),
PackageInstantiation {
context_clause: ContextClause::default(),
ident: code.s1("ident").decl_ident(),
Expand All @@ -191,7 +194,7 @@ package ident is new lib.foo.bar
",
);
assert_eq!(
code.with_stream(parse_package_instantiation),
code.with_stream_no_diagnostics(parse_package_instantiation),
PackageInstantiation {
context_clause: ContextClause::default(),
ident: code.s1("ident").decl_ident(),
Expand Down
6 changes: 3 additions & 3 deletions vhdl_lang/src/syntax/design_unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,15 @@ pub fn parse_design_file(
try_init_token_kind!(
token,
Library => {
match parse_library_clause(stream) {
match parse_library_clause(stream, diagnostics) {
Ok(library) => {
context_clause.push(ContextItem::Library(library));
},
Err(diagnostic) => diagnostics.push(diagnostic),
}
},
Use => {
match parse_use_clause(stream) {
match parse_use_clause(stream, diagnostics) {
Ok(use_clause) => {
context_clause.push(ContextItem::Use(use_clause));
},
Expand Down Expand Up @@ -243,7 +243,7 @@ pub fn parse_design_file(
Err(diagnostic) => diagnostics.push(diagnostic),
};
} else if stream.next_kinds_are(&[Package, Identifier, Is, New]) {
match parse_package_instantiation(stream) {
match parse_package_instantiation(stream, diagnostics) {
Ok(mut inst) => {
let tokens = stream.slice_tokens();
inst.context_clause = take_context_clause(&mut context_clause);
Expand Down
Loading

0 comments on commit a6cc02f

Please sign in to comment.