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

Enable arrays of views #326

Merged
merged 6 commits into from
Aug 6, 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
2 changes: 1 addition & 1 deletion vhdl_lang/src/analysis/concurrent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
} else if statement.statement.item.can_have_label() {
// Generate an anonymous label if it is not explicitly defined
let ent = self.arena.alloc(
Designator::Anonymous(scope.next_anonymous()),
scope.anonymous_designator(),
Some(parent),
Related::None,
AnyEntKind::Concurrent(statement.statement.item.label_typ()),
Expand Down
210 changes: 155 additions & 55 deletions vhdl_lang/src/analysis/declarative.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,27 @@ use std::collections::HashSet;
use vhdl_lang::TokenSpan;

impl Declaration {
/// Returns whether the declaration denoted by `self` is allowed in the given context.
/// For example, within an architecture, only constants, signals and shared variables are allowed,
/// variables are not.
///
/// ### Conforming example:
/// ```vhdl
/// architecture arch of ent is
/// signal foo : bit;
/// begin
/// end arch;
/// ```
///
/// ### Non-Conforming example:
/// ```vhdl
/// architecture arch of ent is
/// variable foo : bit;
/// begin
/// end arch;
/// ```
///
/// The context is given by the parent element of the declaration.
pub fn is_allowed_in_context(&self, parent: &AnyEntKind) -> bool {
use Declaration::*;
use ObjectClass::*;
Expand Down Expand Up @@ -124,8 +145,6 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
let mut incomplete_types: FnvHashMap<Symbol, (EntRef<'a>, SrcPos)> = FnvHashMap::default();

for i in 0..declarations.len() {
// Handle incomplete types

let (WithTokenSpan { item: decl, span }, remaining) =
declarations[i..].split_first_mut().unwrap();

Expand All @@ -137,6 +156,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
)
}

// Handle incomplete types
match decl {
Declaration::Type(type_decl) => match type_decl.def {
TypeDefinition::Incomplete(ref mut reference) => {
Expand Down Expand Up @@ -369,9 +389,6 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
ent,
implicit.designator().clone(),
AnyEntKind::Overloaded(Overloaded::Alias(implicit)),
ent.decl_pos(),
ent.src_span,
Some(self.source()),
);
scope.add(impicit_alias, diagnostics);
}
Expand Down Expand Up @@ -943,39 +960,121 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
object_decl: &mut InterfaceObjectDeclaration,
diagnostics: &mut dyn DiagnosticHandler,
) -> EvalResult<Vec<EntRef<'a>>> {
let span = object_decl.span();
match &mut object_decl.mode {
ModeIndication::Simple(mode) => {
let (subtype, class) =
self.analyze_simple_mode_indication(scope, mode, diagnostics)?;
Ok(object_decl
.idents
.iter_mut()
.map(|ident| {
self.define(
ident,
parent,
AnyEntKind::Object(Object {
class,
iface: Some(ObjectInterface::simple(
object_decl.list_type,
mode.mode.as_ref().map(|mode| mode.item).unwrap_or_default(),
)),
subtype,
has_default: mode.expression.is_some(),
}),
span,
)
})
.collect_vec())
let objects = object_decl
.idents
.iter_mut()
.map(|ident| {
self.define(
ident,
parent,
AnyEntKind::Object(Object {
class: ObjectClass::Signal,
iface: None,
subtype: Subtype::new(self.universal_integer().into()),
has_default: false,
}),
object_decl.span,
)
})
.collect_vec();
for object in &objects {
let actual_object = match &mut object_decl.mode {
ModeIndication::Simple(mode) => {
let (subtype, class) =
self.analyze_simple_mode_indication(scope, mode, diagnostics)?;
Object {
class,
iface: Some(ObjectInterface::simple(
object_decl.list_type,
mode.mode.as_ref().map(|mode| mode.item).unwrap_or_default(),
)),
subtype,
has_default: mode.expression.is_some(),
}
}
ModeIndication::View(view) => {
let (view_ent, subtype) =
self.analyze_mode_indication(scope, object, view, diagnostics)?;
Object {
class: ObjectClass::Signal,
iface: Some(ObjectInterface::Port(InterfaceMode::View(view_ent))),
subtype,
has_default: false,
}
}
};
unsafe {
object.set_kind(AnyEntKind::Object(actual_object));
}
ModeIndication::View(view) => {
let resolved =
self.name_resolve(scope, view.name.span, &mut view.name.item, diagnostics)?;
let view_ent = self.resolve_view_ent(&resolved, diagnostics, view.name.span)?;
if let Some((_, ast_declared_subtype)) = &mut view.subtype_indication {
let declared_subtype =
self.resolve_subtype_indication(scope, ast_declared_subtype, diagnostics)?;
}

Ok(objects)
}

/// Analyzes a mode view indication of the form
/// ```vhdl
/// foo : view s_axis of axi_stream
/// ```
///
/// This function resolves all used types and verifies them.
/// If the provided view describes an array but no actual array type is given, i.e.:
/// ```vhdl
/// multiple_foos : view (s_axis)
/// ```
/// this function will declare an anonymous array indication with a single index and the
/// view's subtype as element, similar as if the view was declared like so:
/// ```vhdl
/// -- pseudo code
/// type anonymous is array (integer range <>) of axi_stream;
/// multiple_foos : view (s_axis) of anonymous
/// ```
/// The anonymous array type will be marked as being linked to the interface declaration
/// (in the example above: the `anonymous` type is implicitly declared by `multiple_foos`)
fn analyze_mode_indication(
&self,
scope: &Scope<'a>,
object_ent: EntRef<'a>,
view: &mut ModeViewIndication,
diagnostics: &mut dyn DiagnosticHandler,
) -> EvalResult<(ViewEnt<'a>, Subtype<'a>)> {
let resolved =
self.name_resolve(scope, view.name.span, &mut view.name.item, diagnostics)?;
let view_ent = self.resolve_view_ent(&resolved, diagnostics, view.name.span)?;
let subtype = if let Some((_, ast_declared_subtype)) = &mut view.subtype_indication {
let declared_subtype =
self.resolve_subtype_indication(scope, ast_declared_subtype, diagnostics)?;
match view.kind {
ModeViewIndicationKind::Array => {
let Type::Array {
indexes: _,
elem_type,
} = declared_subtype.type_mark().kind()
else {
bail!(
diagnostics,
Diagnostic::new(
ast_declared_subtype.type_mark.pos(self.ctx),
"Subtype must be an array",
ErrorCode::TypeMismatch
)
);
};
if *elem_type != view_ent.subtype().type_mark() {
bail!(
diagnostics,
Diagnostic::new(
ast_declared_subtype.type_mark.pos(self.ctx),
format!(
"Array element {} must match {} declared for the view",
elem_type.describe(),
view_ent.subtype().type_mark().describe()
),
ErrorCode::TypeMismatch
)
);
}
}
ModeViewIndicationKind::Record => {
if declared_subtype.type_mark() != view_ent.subtype().type_mark() {
bail!(
diagnostics,
Expand All @@ -987,25 +1086,26 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
);
}
}
Ok(object_decl
.idents
.iter_mut()
.map(|ident| {
self.define(
ident,
parent,
AnyEntKind::Object(Object {
class: ObjectClass::Signal,
iface: Some(ObjectInterface::Port(InterfaceMode::View(view_ent))),
subtype: *view_ent.subtype(),
has_default: false,
}),
span,
)
})
.collect_vec())
}
}
declared_subtype
} else {
match view.kind {
ModeViewIndicationKind::Array => {
let typ = Type::Array {
indexes: vec![Some(self.universal_integer())],
elem_type: view_ent.subtype().type_mark(),
};
let typ = self.arena.implicit(
object_ent,
scope.anonymous_designator(),
AnyEntKind::Type(typ),
);
Subtype::new(TypeEnt::from_any(typ).unwrap())
}
ModeViewIndicationKind::Record => *view_ent.subtype(),
}
};
Ok((view_ent, subtype))
}

pub fn analyze_simple_mode_indication(
Expand Down
6 changes: 3 additions & 3 deletions vhdl_lang/src/analysis/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ impl<'a, 't> AnalyzeContext<'a, 't> {

let types = match (left_types, right_types) {
(DisambiguatedType::Unambiguous(l), DisambiguatedType::Unambiguous(r)) => {
if let Some(typ) = self.common_type(l.base(), r.base()) {
return Ok(typ);
return if let Some(typ) = self.common_type(l.base(), r.base()) {
Ok(typ)
} else {
diagnostics.add(
constraint.span().pos(self.ctx),
Expand All @@ -185,7 +185,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
),
ErrorCode::TypeMismatch,
);
return Err(EvalError::Unknown);
Err(EvalError::Unknown)
}
}
(DisambiguatedType::Unambiguous(l), DisambiguatedType::Ambiguous(r)) => {
Expand Down
4 changes: 4 additions & 0 deletions vhdl_lang/src/analysis/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,10 @@ impl<'a> Scope<'a> {
inner.anon_idx += 1;
idx
}

pub fn anonymous_designator(&self) -> Designator {
Designator::Anonymous(self.next_anonymous())
}
}

impl<'a> NamedEntities<'a> {
Expand Down
2 changes: 1 addition & 1 deletion vhdl_lang/src/analysis/sequential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
} else if statement.statement.item.can_have_label() {
// Generate an anonymous label if it is not explicitly defined
let ent = self.arena.alloc(
Designator::Anonymous(scope.next_anonymous()),
scope.anonymous_designator(),
Some(parent),
Related::None,
AnyEntKind::Sequential(statement.statement.item.label_typ()),
Expand Down
3 changes: 0 additions & 3 deletions vhdl_lang/src/analysis/standard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,6 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
FormalRegion::new_params(),
return_type,
))),
implicit_of.decl_pos(),
implicit_of.src_span,
Some(self.source()),
);

for (name, kind) in formals.into_iter() {
Expand Down
Loading
Loading