From 2a82770de3f54b2469be3f524de3d2ee35cd2ccc Mon Sep 17 00:00:00 2001 From: Lukas Scheller <45085299+Schottkyc137@users.noreply.github.com> Date: Thu, 9 May 2024 15:30:02 +0200 Subject: [PATCH] Replace position-based source code information with token-based source code information (#301) --- vhdl_lang/src/analysis/analyze.rs | 10 +- vhdl_lang/src/analysis/assignment.rs | 11 +- vhdl_lang/src/analysis/association.rs | 144 +++-- vhdl_lang/src/analysis/concurrent.rs | 66 ++- vhdl_lang/src/analysis/declarative.rs | 112 ++-- vhdl_lang/src/analysis/design_unit.rs | 103 ++-- vhdl_lang/src/analysis/expression.rs | 219 +++---- vhdl_lang/src/analysis/literals.rs | 40 +- vhdl_lang/src/analysis/names.rs | 459 ++++++++------- vhdl_lang/src/analysis/overloaded.rs | 55 +- vhdl_lang/src/analysis/package_instance.rs | 37 +- vhdl_lang/src/analysis/range.rs | 69 ++- vhdl_lang/src/analysis/root.rs | 28 +- vhdl_lang/src/analysis/scope.rs | 28 +- vhdl_lang/src/analysis/semantic.rs | 44 +- vhdl_lang/src/analysis/sequential.rs | 33 +- vhdl_lang/src/analysis/standard.rs | 12 +- vhdl_lang/src/analysis/subprogram.rs | 24 +- vhdl_lang/src/analysis/target.rs | 14 +- vhdl_lang/src/analysis/tests/mod.rs | 19 +- .../src/analysis/tests/package_instance.rs | 1 + .../src/analysis/tests/view_declarations.rs | 1 + vhdl_lang/src/analysis/types.rs | 39 +- vhdl_lang/src/ast.rs | 253 ++++---- vhdl_lang/src/ast/display.rs | 11 +- vhdl_lang/src/ast/search.rs | 117 ++-- vhdl_lang/src/ast/token_range.rs | 114 ++++ vhdl_lang/src/ast/util.rs | 85 +-- vhdl_lang/src/completion.rs | 2 +- vhdl_lang/src/data/source.rs | 62 -- vhdl_lang/src/named_entity.rs | 14 +- vhdl_lang/src/named_entity/design.rs | 14 +- vhdl_lang/src/named_entity/region.rs | 9 +- vhdl_lang/src/named_entity/types.rs | 32 +- vhdl_lang/src/named_entity/visibility.rs | 5 +- vhdl_lang/src/syntax/attributes.rs | 9 +- vhdl_lang/src/syntax/common.rs | 20 +- vhdl_lang/src/syntax/component_declaration.rs | 6 +- vhdl_lang/src/syntax/concurrent_statement.rs | 190 +++--- vhdl_lang/src/syntax/configuration.rs | 29 +- vhdl_lang/src/syntax/context.rs | 4 +- vhdl_lang/src/syntax/design_unit.rs | 97 ++-- vhdl_lang/src/syntax/expression.rs | 541 +++++++++--------- vhdl_lang/src/syntax/interface_declaration.rs | 33 +- vhdl_lang/src/syntax/names.rs | 465 ++++++++------- vhdl_lang/src/syntax/object_declaration.rs | 6 +- vhdl_lang/src/syntax/parser.rs | 12 + vhdl_lang/src/syntax/range.rs | 52 +- vhdl_lang/src/syntax/sequential_statement.rs | 253 ++++---- vhdl_lang/src/syntax/subprogram.rs | 52 +- vhdl_lang/src/syntax/subtype_indication.rs | 90 +-- vhdl_lang/src/syntax/test.rs | 112 +++- vhdl_lang/src/syntax/tokens/tokenizer.rs | 157 +++-- vhdl_lang/src/syntax/tokens/tokenstream.rs | 21 +- vhdl_lang/src/syntax/type_declaration.rs | 25 +- vhdl_lang/src/syntax/view.rs | 15 +- vhdl_ls/src/vhdl_server.rs | 2 +- 57 files changed, 2553 insertions(+), 1924 deletions(-) create mode 100644 vhdl_lang/src/ast/token_range.rs diff --git a/vhdl_lang/src/analysis/analyze.rs b/vhdl_lang/src/analysis/analyze.rs index 9682d414..a6c841c7 100644 --- a/vhdl_lang/src/analysis/analyze.rs +++ b/vhdl_lang/src/analysis/analyze.rs @@ -132,7 +132,7 @@ pub fn as_fatal(res: EvalResult) -> FatalResult> { } } -pub(super) struct AnalyzeContext<'a> { +pub(super) struct AnalyzeContext<'a, 't> { pub(super) root: &'a DesignRoot, pub work_sym: Symbol, @@ -158,16 +158,16 @@ pub(super) struct AnalyzeContext<'a> { uses: RefCell>, missing_unit: RefCell)>>, uses_library_all: RefCell>, - pub ctx: &'a dyn TokenAccess, + pub ctx: &'t dyn TokenAccess, } -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { pub fn new( root: &'a DesignRoot, current_unit: &UnitId, arena: &'a Arena, - ctx: &'a dyn TokenAccess, - ) -> AnalyzeContext<'a> { + ctx: &'t dyn TokenAccess, + ) -> AnalyzeContext<'a, 't> { AnalyzeContext { work_sym: root.symbol_utf8("work"), std_sym: root.symbol_utf8("std"), diff --git a/vhdl_lang/src/analysis/assignment.rs b/vhdl_lang/src/analysis/assignment.rs index a9234fc0..5d5ef89c 100644 --- a/vhdl_lang/src/analysis/assignment.rs +++ b/vhdl_lang/src/analysis/assignment.rs @@ -7,19 +7,20 @@ use super::analyze::*; use super::scope::*; use super::target::AssignmentType; +use crate::ast::token_range::WithTokenSpan; use crate::ast::*; use crate::data::*; use crate::named_entity::*; -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { // @TODO maybe make generic function for expression/waveform. // wait until type checking to see if it makes sense pub fn analyze_expr_assignment( &self, scope: &Scope<'a>, - target: &mut WithPos, + target: &mut WithTokenSpan, assignment_type: AssignmentType, - rhs: &mut AssignmentRightHand>, + rhs: &mut AssignmentRightHand>, diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { let ttyp = as_fatal(self.resolve_target(scope, target, assignment_type, diagnostics))?; @@ -59,7 +60,7 @@ impl<'a> AnalyzeContext<'a> { pub fn analyze_waveform_assignment( &self, scope: &Scope<'a>, - target: &mut WithPos, + target: &mut WithTokenSpan, assignment_type: AssignmentType, rhs: &mut AssignmentRightHand, diagnostics: &mut dyn DiagnosticHandler, @@ -124,7 +125,7 @@ impl<'a> AnalyzeContext<'a> { &self, scope: &Scope<'a>, ttyp: Option>, - expr: &mut WithPos, + expr: &mut WithTokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { if let Some(ttyp) = ttyp { diff --git a/vhdl_lang/src/analysis/association.rs b/vhdl_lang/src/analysis/association.rs index 33b5d17b..ac48e5cf 100644 --- a/vhdl_lang/src/analysis/association.rs +++ b/vhdl_lang/src/analysis/association.rs @@ -7,6 +7,7 @@ use crate::analysis::names::ObjectName; use fnv::FnvHashMap; use itertools::Itertools; +use vhdl_lang::TokenSpan; use super::analyze::*; use super::names::ResolvedName; @@ -83,12 +84,12 @@ impl<'a> ResolvedFormal<'a> { } } -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { fn resolve_formal( &self, formal_region: &FormalRegion<'a>, scope: &Scope<'a>, - name_pos: &SrcPos, + name_pos: TokenSpan, name: &mut Name, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { @@ -97,14 +98,14 @@ impl<'a> AnalyzeContext<'a> { let resolved_prefix = self.resolve_formal( formal_region, scope, - &prefix.pos, + prefix.span, &mut prefix.item, diagnostics, )?; let suffix_ent = resolved_prefix .type_mark - .selected(&prefix.pos, suffix) + .selected(self.ctx, prefix.span, suffix) .into_eval_result(diagnostics)?; if let TypedSelection::RecordElement(elem) = suffix_ent { suffix.set_unique_reference(elem.into()); @@ -113,19 +114,28 @@ impl<'a> AnalyzeContext<'a> { { Ok(resolved_formal) } else { - bail!(diagnostics, Diagnostic::invalid_formal(name_pos)); + bail!( + diagnostics, + Diagnostic::invalid_formal(name_pos.pos(self.ctx)) + ); } } else { - bail!(diagnostics, Diagnostic::invalid_formal(name_pos)); + bail!( + diagnostics, + Diagnostic::invalid_formal(name_pos.pos(self.ctx)) + ); } } Name::SelectedAll(_) => { - bail!(diagnostics, Diagnostic::invalid_formal(name_pos)); + bail!( + diagnostics, + Diagnostic::invalid_formal(name_pos.pos(self.ctx)) + ); } Name::Designator(designator) => { let (idx, ent) = formal_region - .lookup(name_pos, designator.designator()) + .lookup(&name_pos.pos(self.ctx), designator.item.designator()) .into_eval_result(diagnostics)?; designator.set_unique_reference(ent.inner()); Ok(ResolvedFormal::new_basic(idx, ent)) @@ -134,30 +144,42 @@ impl<'a> AnalyzeContext<'a> { let resolved_prefix = self.resolve_formal( formal_region, scope, - &prefix.pos, + prefix.span, &mut prefix.item, diagnostics, )?; if resolved_prefix.is_converted { // Converted formals may not be further selected - bail!(diagnostics, Diagnostic::invalid_formal(name_pos)); + bail!( + diagnostics, + Diagnostic::invalid_formal(name_pos.pos(self.ctx)) + ); } self.drange_unknown_type(scope, drange.as_mut(), diagnostics)?; Ok(resolved_prefix.partial()) } Name::Attribute(..) => { - bail!(diagnostics, Diagnostic::invalid_formal(name_pos)); + bail!( + diagnostics, + Diagnostic::invalid_formal(name_pos.pos(self.ctx)) + ); } Name::CallOrIndexed(ref mut fcall) => { let prefix = if let Some(prefix) = fcall.name.item.prefix() { prefix } else { - bail!(diagnostics, Diagnostic::invalid_formal(name_pos)); + bail!( + diagnostics, + Diagnostic::invalid_formal(name_pos.pos(self.ctx)) + ); }; - if formal_region.lookup(name_pos, prefix.designator()).is_err() { + if formal_region + .lookup(&name_pos.pos(self.ctx), prefix.designator()) + .is_err() + { // The prefix of the name was not found in the formal region // it must be a type conversion or a single parameter function call @@ -175,12 +197,15 @@ impl<'a> AnalyzeContext<'a> { )?, ) } else { - bail!(diagnostics, Diagnostic::invalid_formal_conversion(name_pos)); + bail!( + diagnostics, + Diagnostic::invalid_formal_conversion(name_pos.pos(self.ctx)) + ); }; let converted_typ = match as_fatal(self.name_resolve( scope, - &fcall.name.pos, + fcall.name.span, &mut fcall.name.item, diagnostics, ))? { @@ -189,7 +214,11 @@ impl<'a> AnalyzeContext<'a> { if !typ.base().is_closely_related(ctyp) { bail!( diagnostics, - Diagnostic::invalid_type_conversion(pos, ctyp, typ) + Diagnostic::invalid_type_conversion( + pos.pos(self.ctx), + ctyp, + typ + ) ); } typ @@ -209,7 +238,10 @@ impl<'a> AnalyzeContext<'a> { if candidates.len() > 1 { // Ambiguous call - bail!(diagnostics, Diagnostic::ambiguous_call(&des, candidates)); + bail!( + diagnostics, + Diagnostic::ambiguous_call(self.ctx, &des, candidates) + ); } else if let Some(ent) = candidates.pop() { fcall.name.set_unique_reference(&ent); ent.return_type().unwrap() @@ -218,7 +250,7 @@ impl<'a> AnalyzeContext<'a> { bail!( diagnostics, Diagnostic::new( - &fcall.name.pos, + &fcall.name.pos(self.ctx), format!( "No function '{}' accepting {}", fcall.name, @@ -230,7 +262,10 @@ impl<'a> AnalyzeContext<'a> { } } _ => { - bail!(diagnostics, Diagnostic::invalid_formal_conversion(name_pos)); + bail!( + diagnostics, + Diagnostic::invalid_formal_conversion(name_pos.pos(self.ctx)) + ); } }; @@ -239,7 +274,7 @@ impl<'a> AnalyzeContext<'a> { let resolved_prefix = self.resolve_formal( formal_region, scope, - &indexed_name.name.pos, + indexed_name.name.span, &mut indexed_name.name.item, diagnostics, )?; @@ -256,14 +291,23 @@ impl<'a> AnalyzeContext<'a> { if let Some(resolved_formal) = resolved_prefix.partial_with_typ(new_typ) { Ok(resolved_formal) } else { - bail!(diagnostics, Diagnostic::invalid_formal(name_pos)); + bail!( + diagnostics, + Diagnostic::invalid_formal(name_pos.pos(self.ctx)) + ); } } else { - bail!(diagnostics, Diagnostic::invalid_formal(name_pos)); + bail!( + diagnostics, + Diagnostic::invalid_formal(name_pos.pos(self.ctx)) + ); } } Name::External(..) => { - bail!(diagnostics, Diagnostic::invalid_formal(name_pos)); + bail!( + diagnostics, + Diagnostic::invalid_formal(name_pos.pos(self.ctx)) + ); } } } @@ -281,7 +325,7 @@ impl<'a> AnalyzeContext<'a> { fail = true; diagnostics.add( - formal, + formal.pos(self.ctx), "Named arguments are not allowed before positional arguments", ErrorCode::NamedBeforePositional, ); @@ -304,7 +348,7 @@ impl<'a> AnalyzeContext<'a> { scope: &Scope<'a>, elems: &'e mut [AssociationElement], diagnostics: &mut dyn DiagnosticHandler, - ) -> EvalResult>)>> { + ) -> EvalResult>)>> { self.check_positional_before_named(elems, diagnostics)?; // Formal region index => actual position, resolved formal @@ -316,46 +360,46 @@ impl<'a> AnalyzeContext<'a> { let resolved_formal = as_fatal(self.resolve_formal( formal_region, scope, - &formal.pos, + formal.span, &mut formal.item, diagnostics, ))?; - result.push((&formal.pos, resolved_formal)); + result.push((formal.span, resolved_formal)); } else if let Some(formal) = formal_region.nth(actual_idx) { // Actual index is same as formal index for positional argument let formal = ResolvedFormal::new_basic(actual_idx, formal); - result.push((&actual.pos, Some(formal))); + result.push((actual.span, Some(formal))); } else { diagnostics.add( - &actual.pos, + &actual.pos(self.ctx), "Unexpected extra argument", ErrorCode::TooManyArguments, ); - result.push((&actual.pos, None)); + result.push((actual.span, None)); }; } Ok(result) } - fn check_missing_and_duplicates<'e>( + fn check_missing_and_duplicates( &self, error_pos: &SrcPos, // The position of the instance/call-site - resolved_pairs: &[(&'e SrcPos, Option>)], + resolved_pairs: &[(TokenSpan, Option>)], formal_region: &FormalRegion<'a>, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult>> { let mut is_error = false; let mut result = Vec::default(); - let mut associated: FnvHashMap = Default::default(); + let mut associated: FnvHashMap = Default::default(); for (actual_pos, resolved_formal) in resolved_pairs.iter() { match resolved_formal { Some(resolved_formal) => { if let Some((prev_pos, prev_formal)) = associated.get(&resolved_formal.idx) { if !(resolved_formal.is_partial && prev_formal.is_partial) { let mut diag = Diagnostic::new( - actual_pos, + actual_pos.pos(self.ctx), format!( "{} has already been associated", resolved_formal.iface.describe(), @@ -363,13 +407,13 @@ impl<'a> AnalyzeContext<'a> { ErrorCode::AlreadyAssociated, ); - diag.add_related(prev_pos, "Previously associated here"); + diag.add_related(prev_pos.pos(self.ctx), "Previously associated here"); is_error = true; diagnostics.push(diag); } } result.push(resolved_formal.type_mark); - associated.insert(resolved_formal.idx, (actual_pos, *resolved_formal)); + associated.insert(resolved_formal.idx, (*actual_pos, *resolved_formal)); } None => { is_error = true; @@ -452,19 +496,19 @@ impl<'a> AnalyzeContext<'a> { resolved_formal, expr, scope, - &actual.pos, + actual.span, diagnostics, )?; } self.expr_pos_with_ttyp( scope, resolved_formal.type_mark, - &actual.pos, + actual.span, expr, diagnostics, )?; } else { - self.expr_pos_unknown_ttyp(scope, &actual.pos, expr, diagnostics)?; + self.expr_pos_unknown_ttyp(scope, actual.span, expr, diagnostics)?; } } ActualPart::Open => {} @@ -481,7 +525,7 @@ impl<'a> AnalyzeContext<'a> { resolved_formal: &ResolvedFormal<'a>, expr: &mut Expression, scope: &Scope<'a>, - actual_pos: &SrcPos, + actual_pos: TokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { match resolved_formal.iface.interface_class() { @@ -490,7 +534,7 @@ impl<'a> AnalyzeContext<'a> { as_fatal(self.expression_as_name(expr, scope, actual_pos, diagnostics))? else { diagnostics.add( - actual_pos, + actual_pos.pos(self.ctx), "Expression must be a name denoting a signal", ErrorCode::InterfaceModeMismatch, ); @@ -501,7 +545,7 @@ impl<'a> AnalyzeContext<'a> { ) if base.class() == ObjectClass::Signal) { diagnostics.add( - actual_pos, + actual_pos.pos(self.ctx), "Name must denote a signal name", ErrorCode::InterfaceModeMismatch, ); @@ -512,7 +556,7 @@ impl<'a> AnalyzeContext<'a> { as_fatal(self.expression_as_name(expr, scope, actual_pos, diagnostics))? else { diagnostics.add( - actual_pos, + actual_pos.pos(self.ctx), "Expression must be a name denoting a variable or shared variable", ErrorCode::InterfaceModeMismatch, ); @@ -523,7 +567,7 @@ impl<'a> AnalyzeContext<'a> { ) if base.class() == ObjectClass::Variable || base.class() == ObjectClass::SharedVariable) { diagnostics.add( - actual_pos, + actual_pos.pos(self.ctx), "Name must denote a variable name", ErrorCode::InterfaceModeMismatch, ); @@ -534,7 +578,7 @@ impl<'a> AnalyzeContext<'a> { as_fatal(self.expression_as_name(expr, scope, actual_pos, diagnostics))? else { diagnostics.add( - actual_pos, + actual_pos.pos(self.ctx), "Expression must be a name denoting a file", ErrorCode::InterfaceModeMismatch, ); @@ -545,7 +589,7 @@ impl<'a> AnalyzeContext<'a> { AnyEntKind::File(_) | AnyEntKind::InterfaceFile(_) )) { diagnostics.add( - actual_pos, + actual_pos.pos(self.ctx), "Name must denote a file name", ErrorCode::InterfaceModeMismatch, ); @@ -560,12 +604,12 @@ impl<'a> AnalyzeContext<'a> { &self, expr: &mut Expression, scope: &Scope<'a>, - pos: &SrcPos, + span: TokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult { match expr { Expression::Name(name) => { - let resolved = self.name_resolve(scope, pos, name, diagnostics)?; + let resolved = self.name_resolve(scope, span, name, diagnostics)?; Ok(resolved) } _ => Err(EvalError::Unknown), @@ -575,7 +619,7 @@ impl<'a> AnalyzeContext<'a> { fn to_formal_conversion_argument( parameters: &mut [AssociationElement], -) -> Option<(&SrcPos, &mut Box)> { +) -> Option<(TokenSpan, &mut Box)> { if let &mut [AssociationElement { ref formal, ref mut actual, @@ -584,7 +628,7 @@ fn to_formal_conversion_argument( if formal.is_some() { return None; } else if let ActualPart::Expression(Expression::Name(ref mut actual_name)) = actual.item { - return Some((&actual.pos, actual_name)); + return Some((actual.span, actual_name)); } } None diff --git a/vhdl_lang/src/analysis/concurrent.rs b/vhdl_lang/src/analysis/concurrent.rs index 745f189d..1fa9d5b6 100644 --- a/vhdl_lang/src/analysis/concurrent.rs +++ b/vhdl_lang/src/analysis/concurrent.rs @@ -6,6 +6,7 @@ use super::*; use crate::analysis::names::ResolvedName; +use crate::ast::token_range::WithTokenSpan; use crate::ast::*; use crate::data::error_codes::ErrorCode; use crate::data::*; @@ -13,7 +14,7 @@ use crate::named_entity::*; use analyze::*; use target::AssignmentType; -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { pub fn analyze_concurrent_part( &self, scope: &Scope<'a>, @@ -47,7 +48,7 @@ impl<'a> AnalyzeContext<'a> { label.name(), parent, AnyEntKind::Concurrent(statement.statement.item.label_typ()), - Some(label.pos()), + Some(label.pos(self.ctx)), None, ); statement.label.decl.set(ent.id()); @@ -137,7 +138,13 @@ impl<'a> AnalyzeContext<'a> { let typ = as_fatal(self.drange_type(scope, discrete_range, diagnostics))?; let nested = scope.nested(); nested.add( - index_name.define(self.arena, parent, AnyEntKind::LoopParameter(typ), None), + index_name.define( + self.ctx, + self.arena, + parent, + AnyEntKind::LoopParameter(typ), + None, + ), diagnostics, ); self.analyze_generate_body(&nested, parent, body, diagnostics)?; @@ -237,6 +244,7 @@ impl<'a> AnalyzeContext<'a> { let mut inner_parent = parent; if let Some(label) = alternative_label { let ent = label.define( + self.ctx, self.arena, parent, AnyEntKind::Concurrent(Some(Concurrent::Generate)), @@ -267,7 +275,7 @@ impl<'a> AnalyzeContext<'a> { InstantiatedUnit::Entity(ref mut entity_name, ref mut architecture_name) => { let Some(resolved) = as_fatal(self.name_resolve( scope, - &entity_name.pos, + entity_name.span, &mut entity_name.item, diagnostics, ))? @@ -283,7 +291,7 @@ impl<'a> AnalyzeContext<'a> { if let Some(arch) = as_fatal(self.get_architecture( diagnostics, library_name, - &architecture_name.item.pos, + self.ctx.get_pos(architecture_name.item.token), entity_ident, &architecture_name.item.item, ))? { @@ -296,7 +304,7 @@ impl<'a> AnalyzeContext<'a> { let (generic_region, port_region) = ent_region.to_entity_formal(); self.check_association( - &entity_name.pos, + &entity_name.pos(self.ctx), &generic_region, scope, instance @@ -307,7 +315,7 @@ impl<'a> AnalyzeContext<'a> { diagnostics, )?; self.check_association( - &entity_name.pos, + &entity_name.pos(self.ctx), &port_region, scope, instance @@ -320,13 +328,17 @@ impl<'a> AnalyzeContext<'a> { Ok(()) } _ => { - diagnostics - .push(resolved.kind_error(entity_name.suffix_pos(), "entity")); + diagnostics.push( + resolved + .kind_error(entity_name.suffix_pos().pos(self.ctx), "entity"), + ); Ok(()) } }, other => { - diagnostics.push(other.kind_error(entity_name.suffix_pos(), "entity")); + diagnostics.push( + other.kind_error(entity_name.suffix_pos().pos(self.ctx), "entity"), + ); Ok(()) } } @@ -334,7 +346,7 @@ impl<'a> AnalyzeContext<'a> { InstantiatedUnit::Component(ref mut component_name) => { let Some(resolved) = as_fatal(self.name_resolve( scope, - &component_name.pos, + component_name.span, &mut component_name.item, diagnostics, ))? @@ -345,8 +357,10 @@ impl<'a> AnalyzeContext<'a> { let ent = match resolved { ResolvedName::Final(ent) => ent, other => { - diagnostics - .push(other.kind_error(component_name.suffix_pos(), "component")); + diagnostics.push( + other + .kind_error(component_name.suffix_pos().pos(self.ctx), "component"), + ); return Ok(()); } }; @@ -354,7 +368,7 @@ impl<'a> AnalyzeContext<'a> { if let AnyEntKind::Component(ent_region) = ent.kind() { let (generic_region, port_region) = ent_region.to_entity_formal(); self.check_association( - &component_name.pos, + &component_name.pos(self.ctx), &generic_region, scope, instance @@ -365,7 +379,7 @@ impl<'a> AnalyzeContext<'a> { diagnostics, )?; self.check_association( - &component_name.pos, + &component_name.pos(self.ctx), &port_region, scope, instance @@ -377,14 +391,16 @@ impl<'a> AnalyzeContext<'a> { )?; Ok(()) } else { - diagnostics.push(resolved.kind_error(component_name.suffix_pos(), "component")); + diagnostics.push( + resolved.kind_error(component_name.suffix_pos().pos(self.ctx), "component"), + ); Ok(()) } } InstantiatedUnit::Configuration(ref mut config_name) => { let Some(resolved) = as_fatal(self.name_resolve( scope, - &config_name.pos, + config_name.span, &mut config_name.item, diagnostics, ))? @@ -394,8 +410,12 @@ impl<'a> AnalyzeContext<'a> { match resolved { ResolvedName::Design(ent) if matches!(ent.kind(), Design::Configuration) => {} other => { - diagnostics - .push(other.kind_error(config_name.suffix_pos(), "configuration")); + diagnostics.push( + other.kind_error( + config_name.suffix_pos().pos(self.ctx), + "configuration", + ), + ); return Ok(()); } } @@ -421,13 +441,13 @@ impl<'a> AnalyzeContext<'a> { pub fn sensitivity_list_check( &self, scope: &Scope<'a>, - names: &mut [WithPos], + names: &mut [WithTokenSpan], diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { for name in names.iter_mut() { if let Some(object_name) = as_fatal(self.resolve_object_name( scope, - &name.pos, + name.span, &mut name.item, "is not a signal and cannot be in a sensitivity list", ErrorCode::DisallowedInSensitivityList, @@ -435,7 +455,7 @@ impl<'a> AnalyzeContext<'a> { ))? { if object_name.base.class() != ObjectClass::Signal { diagnostics.add( - &name.pos, + &name.pos(self.ctx), format!( "{} is not a signal and cannot be in a sensitivity list", object_name.base.describe_class() @@ -446,7 +466,7 @@ impl<'a> AnalyzeContext<'a> { && !object_name.base.is_port() { diagnostics.add( - &name.pos, + &name.pos(self.ctx), format!( "{} cannot be in a sensitivity list", object_name.base.describe_class() diff --git a/vhdl_lang/src/analysis/declarative.rs b/vhdl_lang/src/analysis/declarative.rs index f9290480..faf704ea 100644 --- a/vhdl_lang/src/analysis/declarative.rs +++ b/vhdl_lang/src/analysis/declarative.rs @@ -111,7 +111,7 @@ impl Declaration { } } -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { pub fn analyze_declarative_part( &self, scope: &Scope<'a>, @@ -143,20 +143,21 @@ impl<'a> AnalyzeContext<'a> { find_full_type_definition(type_decl.ident.name(), remaining); let (decl_pos, span) = match full_definiton { - Some(full_decl) => { - (full_decl.ident.pos(), Some(full_decl.span)) - } + Some(full_decl) => ( + self.ctx.get_pos(full_decl.ident.tree.token), + Some(full_decl.span), + ), None => { let error = Diagnostic::new( - type_decl.ident.pos(), + type_decl.ident.pos(self.ctx), format!( "Missing full type declaration of incomplete type '{}'", type_decl.ident.name() ), ErrorCode::MissingFullTypeDeclaration, - ).related(type_decl.ident.pos(), "The full type declaration shall occur immediately within the same declarative part"); + ).related(type_decl.ident.pos(self.ctx), "The full type declaration shall occur immediately within the same declarative part"); diagnostics.push(error); - (type_decl.ident.pos(), None) + (type_decl.ident.pos(self.ctx), None) } }; @@ -173,7 +174,7 @@ impl<'a> AnalyzeContext<'a> { ); reference.set_unique_reference(ent); - entry.insert((ent, type_decl.ident.pos().clone())); + entry.insert((ent, type_decl.ident.pos(self.ctx).clone())); scope.add(ent, diagnostics); } Entry::Occupied(entry) => { @@ -181,7 +182,7 @@ impl<'a> AnalyzeContext<'a> { diagnostics.push(Diagnostic::duplicate_error( &type_decl.ident, - type_decl.ident.pos(), + type_decl.ident.pos(self.ctx), Some(decl_pos), )); } @@ -231,7 +232,7 @@ impl<'a> AnalyzeContext<'a> { span, } = alias; - let resolved_name = self.name_resolve(scope, &name.pos, &mut name.item, diagnostics); + let resolved_name = self.name_resolve(scope, name.span, &mut name.item, diagnostics); if let Some(ref mut subtype_indication) = subtype_indication { // Object alias @@ -244,7 +245,10 @@ impl<'a> AnalyzeContext<'a> { match resolved_name { ResolvedName::ObjectName(oname) => { if let Some(ref signature) = signature { - diagnostics.push(Diagnostic::should_not_have_signature("Alias", signature)); + diagnostics.push(Diagnostic::should_not_have_signature( + "Alias", + signature.pos(self.ctx), + )); } match oname.base { ObjectBase::Object(base_object) => AnyEntKind::ObjectAlias { @@ -269,10 +273,13 @@ impl<'a> AnalyzeContext<'a> { | ResolvedName::Design(_) | ResolvedName::Expression(_) => { if let Some(ref signature) = signature { - diagnostics.push(Diagnostic::should_not_have_signature("Alias", signature)); + diagnostics.push(Diagnostic::should_not_have_signature( + "Alias", + signature.pos(self.ctx), + )); } diagnostics.add( - &name.pos, + &name.pos(self.ctx), format!("{} cannot be aliased", resolved_name.describe_type()), ErrorCode::MismatchedKinds, ); @@ -280,7 +287,10 @@ impl<'a> AnalyzeContext<'a> { } ResolvedName::Type(typ) => { if let Some(ref signature) = signature { - diagnostics.push(Diagnostic::should_not_have_signature("Alias", signature)); + diagnostics.push(Diagnostic::should_not_have_signature( + "Alias", + signature.pos(self.ctx), + )); } AnyEntKind::Type(Type::Alias(typ)) } @@ -296,14 +306,14 @@ impl<'a> AnalyzeContext<'a> { AnyEntKind::Overloaded(Overloaded::Alias(ent)) } else { diagnostics.push(Diagnostic::no_overloaded_with_signature( - &des.pos, + des.pos(self.ctx), &des.item, &overloaded, )); return Err(EvalError::Unknown); } } else { - diagnostics.push(Diagnostic::signature_required(name)); + diagnostics.push(Diagnostic::signature_required(name.pos(self.ctx))); return Err(EvalError::Unknown); } } @@ -318,7 +328,7 @@ impl<'a> AnalyzeContext<'a> { } }; - Ok(designator.define(self.arena, parent, kind, Some(*span))) + Ok(designator.define(self.ctx, self.arena, parent, kind, Some(*span))) } pub(crate) fn analyze_declaration( @@ -370,7 +380,7 @@ impl<'a> AnalyzeContext<'a> { self.expr_pos_with_ttyp( scope, subtype.type_mark(), - &expr.pos, + expr.span, &mut expr.item, diagnostics, )?; @@ -410,7 +420,7 @@ impl<'a> AnalyzeContext<'a> { Related::None }, kind, - Some(object_decl.ident.tree.pos().clone()), + Some(object_decl.ident.pos(self.ctx).clone()), Some(src_span), ); object_decl.ident.decl.set(object_ent.id()); @@ -442,8 +452,13 @@ impl<'a> AnalyzeContext<'a> { if let Some(subtype) = subtype { scope.add( - self.arena - .define(ident, parent, AnyEntKind::File(subtype), Some(src_span)), + self.arena.define( + self.ctx, + ident, + parent, + AnyEntKind::File(subtype), + Some(src_span), + ), diagnostics, ); } @@ -451,6 +466,7 @@ impl<'a> AnalyzeContext<'a> { Declaration::Component(ref mut component) => { let nested = scope.nested(); let ent = self.arena.define( + self.ctx, &mut component.ident, parent, AnyEntKind::Component(Region::default()), @@ -480,6 +496,7 @@ impl<'a> AnalyzeContext<'a> { ))? { scope.add( self.arena.define( + self.ctx, &mut attr_decl.ident, parent, AnyEntKind::Attribute(typ), @@ -547,6 +564,7 @@ impl<'a> AnalyzeContext<'a> { } Declaration::SubprogramInstantiation(ref mut instance) => { let subpgm_ent = self.arena.define( + self.ctx, &mut instance.ident, parent, AnyEntKind::Overloaded(Overloaded::Subprogram(Signature::new( @@ -558,7 +576,7 @@ impl<'a> AnalyzeContext<'a> { let referenced_name = &mut instance.subprogram_name; if let Some(name) = as_fatal(self.name_resolve( scope, - &referenced_name.pos, + referenced_name.span, &mut referenced_name.item, diagnostics, ))? { @@ -582,6 +600,7 @@ impl<'a> AnalyzeContext<'a> { } Declaration::Package(ref mut instance) => { let ent = self.arena.define( + self.ctx, &mut instance.ident, parent, AnyEntKind::Design(Design::PackageInstance(Region::default())), @@ -627,7 +646,7 @@ impl<'a> AnalyzeContext<'a> { Type::Record(region) => region, _ => { let diag = Diagnostic::new( - &view.typ.type_mark, + &view.typ.type_mark.pos(self.ctx), format!( "The type of a view must be a record type, not {}", typ.type_mark().describe() @@ -647,7 +666,7 @@ impl<'a> AnalyzeContext<'a> { let desi = Designator::Identifier(name.item.item.clone()); let Some(record_element) = record_region.lookup(&desi) else { diagnostics.push(Diagnostic::new( - &name.item.pos, + name.item.pos(self.ctx), format!("Not a part of {}", typ.type_mark().describe()), ErrorCode::Unresolved, )); @@ -659,12 +678,13 @@ impl<'a> AnalyzeContext<'a> { } if !unassociated.is_empty() { diagnostics.add( - &view.ident.tree, + view.ident.pos(self.ctx), pretty_format_unassociated_message(&unassociated), ErrorCode::Unassociated, ); } Ok(self.arena.define( + self.ctx, &mut view.ident, parent, AnyEntKind::View(typ), @@ -701,7 +721,8 @@ impl<'a> AnalyzeContext<'a> { } = attr_spec; let attr_ent = match scope.lookup( - &ident.item.pos, + self.ctx, + ident.item.token, &Designator::Identifier(ident.item.name().clone()), ) { Ok(NamedEntities::Single(ent)) => { @@ -710,14 +731,14 @@ impl<'a> AnalyzeContext<'a> { self.expr_pos_with_ttyp( scope, attr_ent.typ(), - &expr.pos, + expr.span, &mut expr.item, diagnostics, )?; attr_ent } else { diagnostics.add( - &ident.item.pos, + ident.item.pos(self.ctx), format!("{} is not an attribute", ent.describe()), ErrorCode::MismatchedKinds, ); @@ -726,7 +747,7 @@ impl<'a> AnalyzeContext<'a> { } Ok(NamedEntities::Overloaded(_)) => { diagnostics.add( - &ident.item.pos, + ident.item.pos(self.ctx), format!("Overloaded name '{}' is not an attribute", ident.item), ErrorCode::MismatchedKinds, ); @@ -743,14 +764,15 @@ impl<'a> AnalyzeContext<'a> { signature, }) = entity_name { - let ent: EntRef = match scope.lookup(&designator.pos, &designator.item.item) { + let ent: EntRef = match scope.lookup(self.ctx, designator.token, &designator.item.item) + { Ok(NamedEntities::Single(ent)) => { designator.set_unique_reference(ent); if let Some(signature) = signature { diagnostics.push(Diagnostic::should_not_have_signature( "Attribute specification", - &signature.pos, + &signature.pos(self.ctx), )); } ent @@ -766,7 +788,7 @@ impl<'a> AnalyzeContext<'a> { ent.into() } else { diagnostics.push(Diagnostic::no_overloaded_with_signature( - &designator.pos, + designator.pos(self.ctx), &designator.item.item, &overloaded, )); @@ -781,7 +803,7 @@ impl<'a> AnalyzeContext<'a> { designator.set_unique_reference(ent); ent } else { - diagnostics.push(Diagnostic::signature_required(designator)); + diagnostics.push(Diagnostic::signature_required(designator.pos(self.ctx))); return Ok(()); } } @@ -796,7 +818,7 @@ impl<'a> AnalyzeContext<'a> { if Some(*entity_class) != get_entity_class(ent) { diagnostics.add( - designator, + designator.pos(self.ctx), format!("{} is not of class {}", ent.describe(), entity_class), ErrorCode::MismatchedEntityClass, ); @@ -810,7 +832,7 @@ impl<'a> AnalyzeContext<'a> { | EntityClass::Configuration => { if ent != parent { diagnostics.add( - designator, + designator.pos(self.ctx), "Attribute specification must be in the immediate declarative part", ErrorCode::MisplacedAttributeSpec, ); @@ -831,7 +853,7 @@ impl<'a> AnalyzeContext<'a> { | EntityClass::Label => { if ent.parent != Some(parent) { diagnostics.add( - designator, + designator.pos(self.ctx), "Attribute specification must be in the immediate declarative part", ErrorCode::MisplacedAttributeSpec, ); @@ -840,7 +862,10 @@ impl<'a> AnalyzeContext<'a> { } } - let res = unsafe { self.arena.add_attr(ent.id(), &designator.pos, attr_ent) }; + let res = unsafe { + self.arena + .add_attr(ent.id(), designator.pos(self.ctx), attr_ent) + }; if let Err(diagnostic) = res { diagnostics.push(diagnostic); @@ -865,6 +890,7 @@ impl<'a> AnalyzeContext<'a> { diagnostics, )?; self.arena.define( + self.ctx, &mut file_decl.ident, parent, AnyEntKind::InterfaceFile(file_type.type_mark().to_owned()), @@ -876,6 +902,7 @@ impl<'a> AnalyzeContext<'a> { } InterfaceDeclaration::Type(ref mut ident) => { let typ = TypeEnt::from_any(self.arena.define( + self.ctx, ident, parent, AnyEntKind::Type(Type::Interface), @@ -916,6 +943,7 @@ impl<'a> AnalyzeContext<'a> { )?; self.arena.define( + self.ctx, &mut instance.ident, parent, AnyEntKind::Design(Design::InterfacePackageInstance(package_region)), @@ -938,6 +966,7 @@ impl<'a> AnalyzeContext<'a> { let (subtype, class) = self.analyze_simple_mode_indication(scope, mode, diagnostics)?; Ok(self.arena.define( + self.ctx, &mut object_decl.ident, parent, AnyEntKind::Object(Object { @@ -954,8 +983,8 @@ impl<'a> AnalyzeContext<'a> { } ModeIndication::View(view) => { let resolved = - self.name_resolve(scope, &view.name.pos, &mut view.name.item, diagnostics)?; - let view_ent = self.resolve_view_ent(&resolved, diagnostics, &view.name.pos)?; + 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)?; @@ -963,7 +992,7 @@ impl<'a> AnalyzeContext<'a> { bail!( diagnostics, Diagnostic::new( - &ast_declared_subtype.type_mark, + &ast_declared_subtype.type_mark.pos(self.ctx), "Specified subtype must match the subtype declared for the view", ErrorCode::TypeMismatch ) @@ -971,6 +1000,7 @@ impl<'a> AnalyzeContext<'a> { } } Ok(self.arena.define( + self.ctx, &mut object_decl.ident, parent, AnyEntKind::Object(Object { @@ -999,7 +1029,7 @@ impl<'a> AnalyzeContext<'a> { self.expr_pos_with_ttyp( scope, subtype.type_mark(), - &expression.pos, + expression.span, &mut expression.item, diagnostics, )?; diff --git a/vhdl_lang/src/analysis/design_unit.rs b/vhdl_lang/src/analysis/design_unit.rs index 125a8b9d..3814b2d7 100644 --- a/vhdl_lang/src/analysis/design_unit.rs +++ b/vhdl_lang/src/analysis/design_unit.rs @@ -6,6 +6,7 @@ use super::*; use crate::analysis::names::ResolvedName; +use crate::ast::token_range::WithTokenSpan; use crate::ast::*; use crate::data::error_codes::ErrorCode; use crate::data::*; @@ -13,7 +14,7 @@ use crate::named_entity::*; use crate::HasTokenSpan; use analyze::*; -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { pub fn analyze_primary_unit( &self, unit: &mut AnyPrimaryUnit, @@ -51,7 +52,7 @@ impl<'a> AnalyzeContext<'a> { unit.name().clone(), self.work_library(), AnyEntKind::Design(Design::Entity(Visibility::default(), Region::default())), - Some(unit.pos()), + Some(unit.ident_pos(self.ctx)), Some(unit.span()), ); @@ -101,7 +102,7 @@ impl<'a> AnalyzeContext<'a> { as_fatal(self.lookup_entity_for_configuration(&root_region, unit, diagnostics))? { if let Some(primary_pos) = named_entity.decl_pos() { - let secondary_pos = unit.pos(); + let secondary_pos = unit.ident_pos(self.ctx); if primary_pos.source == secondary_pos.source && primary_pos.start() > secondary_pos.start() { @@ -119,6 +120,7 @@ impl<'a> AnalyzeContext<'a> { }; self.arena.define( + self.ctx, &mut unit.ident, self.work_library(), AnyEntKind::Design(Design::Configuration), @@ -137,7 +139,7 @@ impl<'a> AnalyzeContext<'a> { unit.name().clone(), self.work_library(), AnyEntKind::Design(Design::Package(Visibility::default(), Region::default())), - Some(unit.pos()), + Some(unit.ident_pos(self.ctx)), Some(unit.span()), ); @@ -184,7 +186,7 @@ impl<'a> AnalyzeContext<'a> { unit.name().clone(), self.work_library(), AnyEntKind::Design(Design::PackageInstance(Region::default())), - Some(unit.pos()), + Some(unit.ident_pos(self.ctx)), Some(unit.span()), ); @@ -219,6 +221,7 @@ impl<'a> AnalyzeContext<'a> { self.analyze_context_clause(&scope, &mut unit.items, diagnostics)?; self.arena.define( + self.ctx, &mut unit.ident, self.work_library(), AnyEntKind::Design(Design::Context(scope.into_region())), @@ -237,21 +240,24 @@ impl<'a> AnalyzeContext<'a> { let Some(primary) = as_fatal(self.lookup_in_library( diagnostics, self.work_library_name(), - &unit.entity_name.item.pos, + unit.entity_name.item.pos(self.ctx), &Designator::Identifier(unit.entity_name.item.item.clone()), ))? else { return Ok(()); }; unit.entity_name.set_unique_reference(primary.into()); - self.check_secondary_before_primary(&primary, unit.pos(), diagnostics); + self.check_secondary_before_primary(&primary, unit.ident_pos(self.ctx), diagnostics); let (visibility, region) = if let Design::Entity(ref visibility, ref region) = primary.kind() { (visibility, region) } else { - let mut diagnostic = - Diagnostic::new(unit.pos(), "Expected an entity", ErrorCode::MismatchedKinds); + let mut diagnostic = Diagnostic::new( + unit.ident_pos(self.ctx), + "Expected an entity", + ErrorCode::MismatchedKinds, + ); if let Some(pos) = primary.decl_pos() { diagnostic.add_related(pos, format!("Found {}", primary.describe())) @@ -264,6 +270,7 @@ impl<'a> AnalyzeContext<'a> { self.analyze_context_clause(&root_scope, &mut unit.context_clause, diagnostics)?; let arch = self.arena.define( + self.ctx, &mut unit.ident, primary.into(), AnyEntKind::Design(Design::Architecture(primary)), @@ -292,7 +299,7 @@ impl<'a> AnalyzeContext<'a> { let Some(primary) = as_fatal(self.lookup_in_library( diagnostics, self.work_library_name(), - &unit.ident.tree.pos, + unit.ident_pos(self.ctx), &Designator::Identifier(unit.ident.tree.item.clone()), ))? else { @@ -303,8 +310,11 @@ impl<'a> AnalyzeContext<'a> { Design::Package(ref visibility, ref region) | Design::UninstPackage(ref visibility, ref region) => (visibility, region), _ => { - let mut diagnostic = - Diagnostic::new(unit.pos(), "Expected a package", ErrorCode::MismatchedKinds); + let mut diagnostic = Diagnostic::new( + unit.ident_pos(self.ctx), + "Expected a package", + ErrorCode::MismatchedKinds, + ); if let Some(pos) = primary.decl_pos() { diagnostic.add_related(pos, format!("Found {}", primary.describe())) @@ -319,12 +329,12 @@ impl<'a> AnalyzeContext<'a> { Some(self.work_library()), Related::DeclaredBy(primary.into()), AnyEntKind::Design(Design::PackageBody), - Some(unit.ident.tree.pos.clone()), + Some(unit.ident_pos(self.ctx).clone()), Some(unit.span()), ); unit.ident.decl.set(body.id()); - self.check_secondary_before_primary(&primary, unit.pos(), diagnostics); + self.check_secondary_before_primary(&primary, unit.ident_pos(self.ctx), diagnostics); // @TODO make pattern of primary/secondary extension let root_scope = Scope::new(Region::with_visibility(visibility.clone())); @@ -371,6 +381,7 @@ impl<'a> AnalyzeContext<'a> { diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult { let ent_name = &mut config.entity_name; + let ent_name_span = ent_name.span; match ent_name.item { // Entities are implicitly defined for configurations @@ -379,29 +390,29 @@ impl<'a> AnalyzeContext<'a> { .lookup_in_library( diagnostics, self.work_library_name(), - &ent_name.pos, + &ent_name_span.pos(self.ctx), &designator.item, ) .map(|design| { - designator.reference.set_unique_reference(design.into()); + designator.set_unique_reference(design.into()); design })?), // configuration cfg of lib.ent Name::Selected(ref mut prefix, ref mut designator) => { - let name = self.name_resolve(scope, &prefix.pos, &mut prefix.item, diagnostics)?; + let name = self.name_resolve(scope, prefix.span, &mut prefix.item, diagnostics)?; match name { ResolvedName::Library(ref library_name) => { if library_name != self.work_library_name() { diagnostics.add( - &prefix.pos, + &prefix.pos(self.ctx), format!("Configuration must be within the same library '{}' as the corresponding entity", self.work_library_name()), ErrorCode::ConfigNotInSameLibrary); Err(EvalError::Unknown) } else { let primary_ent = self.lookup_in_library( diagnostics, library_name, - &designator.pos, + designator.pos(self.ctx), &designator.item.item, )?; designator @@ -412,7 +423,7 @@ impl<'a> AnalyzeContext<'a> { Design::Entity(..) => Ok(primary_ent), _ => { diagnostics.add( - designator, + designator.pos(self.ctx), format!( "{} does not denote an entity", primary_ent.describe() @@ -425,14 +436,14 @@ impl<'a> AnalyzeContext<'a> { } } other => { - diagnostics.push(other.kind_error(&prefix.pos, "library")); + diagnostics.push(other.kind_error(&prefix.pos(self.ctx), "library")); Err(EvalError::Unknown) } } } _ => { diagnostics.add( - &ent_name, + &ent_name.pos(self.ctx), "Expected selected name", ErrorCode::MismatchedKinds, ); @@ -445,7 +456,7 @@ impl<'a> AnalyzeContext<'a> { &self, diagnostics: &mut dyn DiagnosticHandler, scope: &Scope<'a>, - prefix: &mut WithPos, + prefix: &mut WithTokenSpan, ) -> EvalResult> { match self.resolve_context_item_name(diagnostics, scope, prefix)? { UsedNames::Single(visible) => match visible.into_non_overloaded() { @@ -454,7 +465,7 @@ impl<'a> AnalyzeContext<'a> { bail!( diagnostics, Diagnostic::new( - &prefix, + &prefix.pos(self.ctx), "Invalid prefix of a selected name", ErrorCode::MismatchedKinds ) @@ -465,7 +476,7 @@ impl<'a> AnalyzeContext<'a> { bail!( diagnostics, Diagnostic::new( - &prefix, + &prefix.pos(self.ctx), "'.all' may not be the prefix of a selected name", ErrorCode::MismatchedKinds ) @@ -478,24 +489,24 @@ impl<'a> AnalyzeContext<'a> { &self, diagnostics: &mut dyn DiagnosticHandler, scope: &Scope<'a>, - name: &mut WithPos, + name: &mut WithTokenSpan, ) -> EvalResult> { match &mut name.item { Name::Selected(ref mut prefix, ref mut suffix) => { let prefix_ent = self.resolve_context_item_prefix(diagnostics, scope, prefix)?; - let visible = self.lookup_selected(diagnostics, &prefix.pos, prefix_ent, suffix)?; + let visible = self.lookup_selected(diagnostics, prefix.span, prefix_ent, suffix)?; suffix.set_reference(&visible); Ok(UsedNames::Single(visible)) } Name::SelectedAll(prefix) => { let prefix_ent = self.resolve_context_item_prefix(diagnostics, scope, prefix)?; - Ok(UsedNames::AllWithin(prefix.pos.clone(), prefix_ent)) + Ok(UsedNames::AllWithin(prefix.pos(self.ctx), prefix_ent)) } Name::Designator(designator) => { let visible = scope - .lookup(&name.pos, designator.designator()) + .lookup(self.ctx, name.span, designator.designator()) .into_eval_result(diagnostics)?; designator.set_reference(&visible); Ok(UsedNames::Single(visible)) @@ -508,7 +519,7 @@ impl<'a> AnalyzeContext<'a> { bail!( diagnostics, Diagnostic::new( - &name.pos, + &name.pos(self.ctx), "Invalid selected name", ErrorCode::MismatchedKinds ) @@ -532,16 +543,19 @@ impl<'a> AnalyzeContext<'a> { if self.work_sym == library_name.item.item { library_name.set_unique_reference(self.work_library()); diagnostics.add( - &library_name.item, + library_name.item.pos(self.ctx), "Library clause not necessary for current working library", ErrorCode::UnnecessaryWorkLibrary, ) } else if let Some(library) = self.get_library(&library_name.item.item) { library_name.set_unique_reference(library); - scope.make_potentially_visible(Some(&library_name.item.pos), library); + scope.make_potentially_visible( + Some(library_name.item.pos(self.ctx)), + library, + ); } else { diagnostics.add( - &library_name.item, + library_name.item.pos(self.ctx), format!("No such library '{}'", library_name.item), ErrorCode::Unresolved, ); @@ -559,7 +573,7 @@ impl<'a> AnalyzeContext<'a> { Name::Selected(..) => {} _ => { diagnostics.add( - &name.pos, + &name.pos(self.ctx), "Context reference must be a selected name", ErrorCode::MismatchedKinds, ); @@ -580,14 +594,14 @@ impl<'a> AnalyzeContext<'a> { // OK AnyEntKind::Design(Design::Context(ref context_region)) => { scope.add_context_visibility( - Some(&name.pos), + Some(&name.pos(self.ctx)), context_region, ); } _ => { if let Name::Selected(_, ref suffix) = name.item { diagnostics.add( - suffix, + suffix.pos(self.ctx), format!( "{} does not denote a context declaration", ent.describe() @@ -622,7 +636,7 @@ impl<'a> AnalyzeContext<'a> { Name::SelectedAll(..) => {} _ => { diagnostics.add( - &name.pos, + &name.pos(self.ctx), "Use clause must be a selected name", ErrorCode::MismatchedKinds, ); @@ -637,12 +651,12 @@ impl<'a> AnalyzeContext<'a> { }; match context_item { UsedNames::Single(visible) => { - visible.make_potentially_visible_in(Some(&name.pos), scope); + visible.make_potentially_visible_in(Some(&name.pos(self.ctx)), scope); } UsedNames::AllWithin(visibility_pos, named_entity) => match named_entity.kind() { AnyEntKind::Library => { let library_name = named_entity.designator().expect_identifier(); - self.use_all_in_library(&name.pos, library_name, scope)?; + self.use_all_in_library(&name.pos(self.ctx), library_name, scope)?; } AnyEntKind::Design(design) => match design { Design::UninstPackage(..) => { @@ -654,7 +668,10 @@ impl<'a> AnalyzeContext<'a> { Design::Package(_, ref primary_region) | Design::PackageInstance(ref primary_region) | Design::InterfacePackageInstance(ref primary_region) => { - scope.make_all_potentially_visible(Some(&name.pos), primary_region); + scope.make_all_potentially_visible( + Some(&name.pos(self.ctx)), + primary_region, + ); } _ => { diagnostics.add( @@ -683,12 +700,12 @@ impl<'a> AnalyzeContext<'a> { pub fn analyze_package_instance_name( &self, scope: &Scope<'a>, - package_name: &mut WithPos, + package_name: &mut WithTokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { let name = self.name_resolve( scope, - &package_name.pos, + package_name.span, &mut package_name.item, diagnostics, )?; @@ -698,7 +715,7 @@ impl<'a> AnalyzeContext<'a> { } } diagnostics.add( - &package_name.pos, + &package_name.pos(self.ctx), format!("'{package_name}' is not an uninstantiated generic package"), ErrorCode::MismatchedKinds, ); diff --git a/vhdl_lang/src/analysis/expression.rs b/vhdl_lang/src/analysis/expression.rs index 6f65a8a4..5391a541 100644 --- a/vhdl_lang/src/analysis/expression.rs +++ b/vhdl_lang/src/analysis/expression.rs @@ -6,16 +6,19 @@ use fnv::FnvHashMap; use fnv::FnvHashSet; +use vhdl_lang::TokenAccess; use super::analyze::*; use super::overloaded::Disambiguated; use super::overloaded::DisambiguatedType; use super::overloaded::ResolvedCall; use super::scope::*; +use crate::ast::token_range::{WithToken, WithTokenSpan}; use crate::ast::*; use crate::data::error_codes::ErrorCode; use crate::data::*; use crate::named_entity::*; +use crate::{TokenId, TokenSpan}; #[derive(Debug, PartialEq, Eq)] pub enum ExpressionType<'a> { @@ -57,16 +60,16 @@ impl<'a> From> for ExpressionType<'a> { } } -pub(super) struct TypeMatcher<'c, 'a> { +pub(super) struct TypeMatcher<'c, 'a, 't> { // Allow implicit type conversion from universal real/integer to other integer types implicit_type_conversion: bool, // Allow implicit type conversion from abstract types to universal real/integer implicit_type_conversion_from_universal: bool, - context: &'c AnalyzeContext<'a>, + context: &'c AnalyzeContext<'a, 't>, } -impl<'c, 'a> TypeMatcher<'c, 'a> { +impl<'c, 'a, 't> TypeMatcher<'c, 'a, 't> { // Returns true if the expression types is possible given the target type pub fn is_possible(&self, types: &ExpressionType<'a>, ttyp: BaseType<'a>) -> bool { if types.match_type(ttyp) { @@ -153,8 +156,8 @@ impl<'c, 'a> TypeMatcher<'c, 'a> { } } -impl<'a> AnalyzeContext<'a> { - pub fn strict_matcher(&self) -> TypeMatcher<'_, 'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { + pub fn strict_matcher(&self) -> TypeMatcher<'_, 'a, 't> { TypeMatcher { implicit_type_conversion: false, implicit_type_conversion_from_universal: false, @@ -162,7 +165,7 @@ impl<'a> AnalyzeContext<'a> { } } - pub fn any_matcher(&self) -> TypeMatcher<'_, 'a> { + pub fn any_matcher(&self) -> TypeMatcher<'_, 'a, 't> { TypeMatcher { implicit_type_conversion: true, implicit_type_conversion_from_universal: true, @@ -170,7 +173,7 @@ impl<'a> AnalyzeContext<'a> { } } - pub fn implicit_matcher(&self) -> TypeMatcher<'_, 'a> { + pub fn implicit_matcher(&self) -> TypeMatcher<'_, 'a, 't> { TypeMatcher { implicit_type_conversion: true, implicit_type_conversion_from_universal: false, @@ -213,16 +216,16 @@ impl<'a> AnalyzeContext<'a> { pub fn expr_unknown_ttyp( &self, scope: &Scope<'a>, - expr: &mut WithPos, + expr: &mut WithTokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { - self.expr_pos_unknown_ttyp(scope, &expr.pos, &mut expr.item, diagnostics) + self.expr_pos_unknown_ttyp(scope, expr.span, &mut expr.item, diagnostics) } pub fn expr_unambiguous_type( &self, scope: &Scope<'a>, - expr: &mut WithPos, + expr: &mut WithTokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { match self.expr_type(scope, expr, diagnostics)? { @@ -232,8 +235,8 @@ impl<'a> AnalyzeContext<'a> { | ExpressionType::Null | ExpressionType::Aggregate => { diagnostics.add( - &expr.pos, - "Ambiguous expression. You can use a qualified expression type'(expr) to disambiguate.", + expr.pos(self.ctx), + "Ambiguous expression. You can use a qualified expression type'(expr) to disambiguate.", ErrorCode::AmbiguousExpression, ); Err(EvalError::Unknown) @@ -245,13 +248,13 @@ impl<'a> AnalyzeContext<'a> { &self, diagnostics: &mut dyn DiagnosticHandler, scope: &Scope<'a>, - op_pos: &SrcPos, + op_pos: TokenId, op: Operator, arity: usize, ) -> EvalResult>> { let designator = Designator::OperatorSymbol(op); match scope - .lookup(op_pos, &designator) + .lookup(self.ctx, op_pos, &designator) .into_eval_result(diagnostics)? { NamedEntities::Single(ent) => { @@ -259,7 +262,7 @@ impl<'a> AnalyzeContext<'a> { bail!( diagnostics, Diagnostic::internal( - op_pos, + op_pos.pos(self.ctx), format!( "Operator symbol cannot denote non-overloaded symbol {}", ent.describe(), @@ -278,7 +281,7 @@ impl<'a> AnalyzeContext<'a> { bail!( diagnostics, Diagnostic::new( - op_pos, + self.ctx.get_pos(op_pos), format!("Found no match for {}", designator.describe()), ErrorCode::Unresolved, ) @@ -293,7 +296,7 @@ impl<'a> AnalyzeContext<'a> { pub fn operand_types( &self, scope: &Scope<'a>, - operands: &mut [&mut WithPos], + operands: &mut [&mut WithTokenSpan], diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult>> { let mut operand_types = Vec::with_capacity(operands.len()); @@ -315,15 +318,15 @@ impl<'a> AnalyzeContext<'a> { pub fn check_op( &self, scope: &Scope<'a>, - op: &mut WithPos>, + op: &mut WithToken>, overloaded: OverloadedEnt<'a>, - exprs: &mut [&mut WithPos], + exprs: &mut [&mut WithTokenSpan], diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { op.set_unique_reference(&overloaded); for (idx, expr) in exprs.iter_mut().enumerate() { let target_type = overloaded.formals().nth(idx).unwrap().type_mark(); - self.expr_pos_with_ttyp(scope, target_type, &expr.pos, &mut expr.item, diagnostics)?; + self.expr_pos_with_ttyp(scope, target_type, expr.span, &mut expr.item, diagnostics)?; } Ok(()) } @@ -332,9 +335,9 @@ impl<'a> AnalyzeContext<'a> { &self, scope: &Scope<'a>, ttyp: Option>, // Optional target type constraint - op: &mut WithPos>, + op: &mut WithToken>, overloaded: Vec>, - exprs: &mut [&mut WithPos], + exprs: &mut [&mut WithTokenSpan], diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { // @TODO lookup already set reference to get O(N) instead of O(N^2) when disambiguating deeply nested ambiguous operators @@ -407,7 +410,7 @@ impl<'a> AnalyzeContext<'a> { if candidates.is_empty() { diagnostics.add( - &op.pos, + self.ctx.get_pos(op.token), format!("Found no match for {}", designator.describe()), ErrorCode::Unresolved, ); @@ -433,12 +436,12 @@ impl<'a> AnalyzeContext<'a> { pub fn operator_type( &self, scope: &Scope<'a>, - op: &mut WithPos>, - exprs: &mut [&mut WithPos], + op: &mut WithToken>, + exprs: &mut [&mut WithTokenSpan], diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { let op_candidates = - self.lookup_operator(diagnostics, scope, &op.pos, op.item.item, exprs.len())?; + self.lookup_operator(diagnostics, scope, op.token, op.item.item, exprs.len())?; match self.disambiguate_op(scope, None, op, op_candidates, exprs, diagnostics)? { Disambiguated::Unambiguous(overloaded) => Ok(ExpressionType::Unambiguous( @@ -456,16 +459,16 @@ impl<'a> AnalyzeContext<'a> { pub fn expr_type( &self, scope: &Scope<'a>, - expr: &mut WithPos, + expr: &mut WithTokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { - self.expr_pos_type(scope, &expr.pos, &mut expr.item, diagnostics) + self.expr_pos_type(scope, expr.span, &mut expr.item, diagnostics) } pub fn expr_pos_type( &self, scope: &Scope<'a>, - expr_pos: &SrcPos, + span: TokenSpan, expr: &mut Expression, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { @@ -477,7 +480,7 @@ impl<'a> AnalyzeContext<'a> { self.operator_type(scope, op, &mut [inner.as_mut()], diagnostics) } Expression::Name(ref mut name) => self - .expression_name_types(scope, expr_pos, name.as_mut(), diagnostics) + .expression_name_types(scope, span, name.as_mut(), diagnostics) .map(ExpressionType::from), Expression::Aggregate(_) => Ok(ExpressionType::Aggregate), Expression::Qualified(ref mut qexpr) => { @@ -506,11 +509,11 @@ impl<'a> AnalyzeContext<'a> { Literal::String(_) => Ok(ExpressionType::String), Literal::BitString(_) => Ok(ExpressionType::String), Literal::Character(chr) => { - match scope.lookup(expr_pos, &Designator::Character(*chr)) { + match scope.lookup(self.ctx, span, &Designator::Character(*chr)) { Ok(NamedEntities::Single(ent)) => { // Should never happen but better know if it does diagnostics.add( - expr_pos, + span.pos(self.ctx), format!( "Character literal cannot denote non-overloaded symbol {}", ent.describe(), @@ -526,7 +529,7 @@ impl<'a> AnalyzeContext<'a> { Ok(ExpressionType::Unambiguous(return_type)) } else { diagnostics.add( - expr_pos, + span.pos(self.ctx), format!( "Character literal cannot denote procedure symbol {}", ent.describe(), @@ -566,11 +569,11 @@ impl<'a> AnalyzeContext<'a> { pub fn expr_pos_unknown_ttyp( &self, scope: &Scope<'a>, - pos: &SrcPos, + span: TokenSpan, expr: &mut Expression, diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { - as_fatal(self.expr_pos_type(scope, pos, expr, diagnostics))?; + as_fatal(self.expr_pos_type(scope, span, expr, diagnostics))?; Ok(()) } @@ -587,7 +590,7 @@ impl<'a> AnalyzeContext<'a> { self.expr_pos_with_ttyp( scope, target_type, - &expr.pos, + expr.span, &mut expr.item, diagnostics, )?; @@ -603,7 +606,7 @@ impl<'a> AnalyzeContext<'a> { pub fn analyze_allocation( &self, scope: &Scope<'a>, - alloc: &mut WithPos, + alloc: &mut WithTokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { match &mut alloc.item { @@ -621,16 +624,18 @@ impl<'a> AnalyzeContext<'a> { &self, scope: &Scope<'a>, target_type: TypeEnt<'a>, - expr: &mut WithPos, + expr: &mut WithTokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { - self.expr_pos_with_ttyp(scope, target_type, &expr.pos, &mut expr.item, diagnostics) + self.expr_pos_with_ttyp(scope, target_type, expr.span, &mut expr.item, diagnostics) } - fn implicit_bool_types(&self, scope: &Scope<'a>, pos: &SrcPos) -> FnvHashSet> { - if let Ok(NamedEntities::Overloaded(overloaded)) = - scope.lookup(pos, &Designator::OperatorSymbol(Operator::QueQue)) - { + fn implicit_bool_types(&self, scope: &Scope<'a>, span: TokenSpan) -> FnvHashSet> { + if let Ok(NamedEntities::Overloaded(overloaded)) = scope.lookup( + self.ctx, + span, + &Designator::OperatorSymbol(Operator::QueQue), + ) { overloaded .entities() .filter_map(|ent| ent.formals().nth(0).map(|typ| typ.type_mark().base())) @@ -644,17 +649,17 @@ impl<'a> AnalyzeContext<'a> { pub fn boolean_expr( &self, scope: &Scope<'a>, - expr: &mut WithPos, + expr: &mut WithTokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { if let Some(types) = as_fatal(self.expr_type(scope, expr, diagnostics))? { match types { ExpressionType::Unambiguous(typ) => { if typ.base() != self.boolean().base() { - let implicit_bools = self.implicit_bool_types(scope, &expr.pos); + let implicit_bools = self.implicit_bool_types(scope, expr.span); if !implicit_bools.contains(&typ.base()) { diagnostics.add( - &expr.pos, + expr.pos(self.ctx), format!( "{} cannot be implicitly converted to {}. Operator ?? is not defined for this type.", typ.describe(), @@ -670,7 +675,7 @@ impl<'a> AnalyzeContext<'a> { self.expr_with_ttyp(scope, self.boolean(), expr, diagnostics)?; } else { let implicit_bool_types: FnvHashSet<_> = self - .implicit_bool_types(scope, &expr.pos) + .implicit_bool_types(scope, expr.span) .intersection(&types) .cloned() .collect(); @@ -682,7 +687,7 @@ impl<'a> AnalyzeContext<'a> { } std::cmp::Ordering::Greater => { let mut diag = Diagnostic::new( - &expr.pos, + &expr.pos(self.ctx), "Ambiguous use of implicit boolean conversion ??", ErrorCode::AmbiguousCall, ); @@ -692,7 +697,7 @@ impl<'a> AnalyzeContext<'a> { std::cmp::Ordering::Less => { let mut diag = Diagnostic::new( - &expr.pos, + expr.pos(self.ctx), format!( "Cannot disambiguate expression to {}", self.boolean().describe() @@ -723,22 +728,18 @@ impl<'a> AnalyzeContext<'a> { &self, scope: &Scope<'a>, target_type: TypeEnt<'a>, - expr_pos: &SrcPos, + span: TokenSpan, expr: &mut Expression, diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { let target_base = target_type.base_type(); match expr { - Expression::Literal(ref mut lit) => self.analyze_literal_with_target_type( - scope, - target_type, - expr_pos, - lit, - diagnostics, - )?, + Expression::Literal(ref mut lit) => { + self.analyze_literal_with_target_type(scope, target_type, span, lit, diagnostics)? + } Expression::Name(ref mut name) => self.expression_name_with_ttyp( scope, - expr_pos, + span, name.as_mut(), target_type, diagnostics, @@ -749,7 +750,7 @@ impl<'a> AnalyzeContext<'a> { { if !self.can_be_target_type(type_mark, target_base.base()) { diagnostics.push(Diagnostic::type_mismatch( - expr_pos, + &span.pos(self.ctx), &type_mark.describe(), target_type, )); @@ -760,7 +761,7 @@ impl<'a> AnalyzeContext<'a> { let op_candidates = match as_fatal(self.lookup_operator( diagnostics, scope, - &op.pos, + op.token, op.item.item, 2, ))? { @@ -781,7 +782,7 @@ impl<'a> AnalyzeContext<'a> { if !self.can_be_target_type(op_type, target_type.base()) { diagnostics.push(Diagnostic::type_mismatch( - expr_pos, + &span.pos(self.ctx), &op_type.describe(), target_type, )); @@ -789,7 +790,7 @@ impl<'a> AnalyzeContext<'a> { } Some(Disambiguated::Ambiguous(candidates)) => { diagnostics.push(Diagnostic::ambiguous_op( - &op.pos, + op.pos(self.ctx), op.item.item, candidates, )); @@ -801,7 +802,7 @@ impl<'a> AnalyzeContext<'a> { let op_candidates = match as_fatal(self.lookup_operator( diagnostics, scope, - &op.pos, + op.token, op.item.item, 1, ))? { @@ -824,7 +825,7 @@ impl<'a> AnalyzeContext<'a> { if !self.can_be_target_type(op_type, target_type.base()) { diagnostics.push(Diagnostic::type_mismatch( - expr_pos, + &span.pos(self.ctx), &op_type.describe(), target_type, )); @@ -832,7 +833,7 @@ impl<'a> AnalyzeContext<'a> { } Some(Disambiguated::Ambiguous(candidates)) => { diagnostics.push(Diagnostic::ambiguous_op( - &op.pos, + op.pos(self.ctx), op.item.item, candidates, )); @@ -860,7 +861,7 @@ impl<'a> AnalyzeContext<'a> { scope, target_base, record_scope, - expr_pos, + span, assocs, diagnostics, )?; @@ -869,7 +870,7 @@ impl<'a> AnalyzeContext<'a> { self.analyze_aggregate(scope, assocs, diagnostics)?; diagnostics.add( - expr_pos, + span.pos(self.ctx), format!("composite does not match {}", target_type.describe()), ErrorCode::TypeMismatch, ); @@ -918,7 +919,7 @@ impl<'a> AnalyzeContext<'a> { scope: &Scope<'a>, record_type: TypeEnt<'a>, elems: &RecordRegion<'a>, - full_pos: &SrcPos, + span: TokenSpan, assocs: &mut [ElementAssociation], diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { @@ -930,6 +931,7 @@ impl<'a> AnalyzeContext<'a> { ElementAssociation::Named(ref mut choices, ref mut actual_expr) => { let typ = if choices.len() == 1 { let choice = choices.first_mut().unwrap(); + let choice_span = choice.span; match &mut choice.item { Choice::Expression(choice_expr) => { if let Some(simple_name) = @@ -937,13 +939,18 @@ impl<'a> AnalyzeContext<'a> { { if let Some(elem) = elems.lookup(&simple_name.item) { simple_name.set_unique_reference(&elem); - associated.associate(&elem, &choice.pos, diagnostics); + associated.associate( + self.ctx, + &elem, + choice.span, + diagnostics, + ); Some(elem.type_mark().base()) } else { is_ok_so_far = false; diagnostics.push(Diagnostic::no_declaration_within( &record_type, - &choice.pos, + &choice_span.pos(self.ctx), &simple_name.item, )); None @@ -951,7 +958,7 @@ impl<'a> AnalyzeContext<'a> { } else { is_ok_so_far = false; diagnostics.add( - &choice.pos, + &choice.pos(self.ctx), "Record aggregate choice must be a simple name", ErrorCode::MismatchedKinds, ); @@ -961,7 +968,7 @@ impl<'a> AnalyzeContext<'a> { Choice::DiscreteRange(_) => { is_ok_so_far = false; diagnostics.add( - &choice.pos, + &choice.pos(self.ctx), "Record aggregate choice must be a simple name", ErrorCode::MismatchedKinds, ); @@ -981,7 +988,7 @@ impl<'a> AnalyzeContext<'a> { .collect(); if remaining_types.len() > 1 { - let mut diag = Diagnostic::new(&choice.pos, format!("Other elements of record '{}' are not of the same type", record_type.designator()), ErrorCode::TypeMismatch); + let mut diag = Diagnostic::new(&choice.pos(self.ctx), format!("Other elements of record '{}' are not of the same type", record_type.designator()), ErrorCode::TypeMismatch); for elem in elems.iter() { if !associated.is_associated(&elem) { if let Some(decl_pos) = elem.decl_pos() { @@ -1000,7 +1007,7 @@ impl<'a> AnalyzeContext<'a> { } else if remaining_types.is_empty() { diagnostics.push( Diagnostic::new( - &choice.pos, + &choice.pos(self.ctx), format!( "All elements of record '{}' are already associated", record_type.designator() @@ -1019,7 +1026,12 @@ impl<'a> AnalyzeContext<'a> { for elem in elems.iter() { if !associated.is_associated(&elem) { - associated.associate(&elem, &choice.pos, diagnostics); + associated.associate( + self.ctx, + &elem, + choice.span, + diagnostics, + ); } } @@ -1033,9 +1045,9 @@ impl<'a> AnalyzeContext<'a> { } else { if let (Some(first), Some(last)) = (choices.first(), choices.last()) { is_ok_so_far = false; - let pos = first.pos.combine(&last.pos); + let pos = first.span.combine(last.span); diagnostics.add( - &pos, + pos.pos(self.ctx), "Record aggregate choice must be a simple name", ErrorCode::MismatchedKinds, ); @@ -1047,7 +1059,7 @@ impl<'a> AnalyzeContext<'a> { self.expr_pos_with_ttyp( scope, typ.into(), - &actual_expr.pos, + actual_expr.span, &mut actual_expr.item, diagnostics, )?; @@ -1058,13 +1070,13 @@ impl<'a> AnalyzeContext<'a> { ElementAssociation::Positional(ref mut expr) => { if let Some(elem) = elems.nth(idx) { self.expr_with_ttyp(scope, elem.type_mark(), expr, diagnostics)?; - associated.associate(elem, &expr.pos, diagnostics); + associated.associate(self.ctx, elem, expr.span, diagnostics); } else { self.expr_unknown_ttyp(scope, expr, diagnostics)?; diagnostics.push( Diagnostic::new( - &expr.pos, + expr.pos(self.ctx), format!( "Unexpected positional association for record '{}'", record_type.designator() @@ -1087,7 +1099,7 @@ impl<'a> AnalyzeContext<'a> { if !associated.is_associated(&elem) { diagnostics.push( Diagnostic::new( - full_pos, + span.pos(self.ctx), format!( "Missing association of record element '{}'", elem.designator() @@ -1125,7 +1137,7 @@ impl<'a> AnalyzeContext<'a> { Choice::Expression(index_expr) => { match self.expr_as_discrete_range_type( scope, - &choice.pos, + choice.span, index_expr, diagnostics, )? { @@ -1133,7 +1145,7 @@ impl<'a> AnalyzeContext<'a> { if let Some(index_type) = index_type { if !self.can_be_target_type(typ, index_type) { diagnostics.push(Diagnostic::type_mismatch( - &choice.pos, + &choice.pos(self.ctx), &typ.describe(), index_type.into(), )); @@ -1147,7 +1159,7 @@ impl<'a> AnalyzeContext<'a> { self.expr_pos_with_ttyp( scope, index_type.into(), - &choice.pos, + choice.span, index_expr, diagnostics, )?; @@ -1193,7 +1205,7 @@ impl<'a> AnalyzeContext<'a> { } } else { diagnostics.add( - &expr.pos, + &expr.pos(self.ctx), format!( "Expected sub-aggregate for target {}", array_type.describe() @@ -1209,12 +1221,12 @@ impl<'a> AnalyzeContext<'a> { if is_elem || !is_array { // Prefer element type in presence of ambiguity - self.expr_pos_with_ttyp(scope, elem_type, &expr.pos, &mut expr.item, diagnostics)?; + self.expr_pos_with_ttyp(scope, elem_type, expr.span, &mut expr.item, diagnostics)?; } else if is_array { - self.expr_pos_with_ttyp(scope, array_type, &expr.pos, &mut expr.item, diagnostics)?; + self.expr_pos_with_ttyp(scope, array_type, expr.span, &mut expr.item, diagnostics)?; } } else { - self.expr_pos_with_ttyp(scope, elem_type, &expr.pos, &mut expr.item, diagnostics)?; + self.expr_pos_with_ttyp(scope, elem_type, expr.span, &mut expr.item, diagnostics)?; } Ok(()) @@ -1241,26 +1253,27 @@ impl Diagnostic { } #[derive(Default)] -struct RecordAssociations<'a>(FnvHashMap); +struct RecordAssociations(FnvHashMap); -impl<'a> RecordAssociations<'a> { +impl RecordAssociations { fn associate( &mut self, + ctx: &dyn TokenAccess, elem: &RecordElement, - pos: &'a SrcPos, + pos: TokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) { if let Some(prev_pos) = self.0.insert(elem.id(), pos) { diagnostics.push( Diagnostic::new( - pos, + pos.pos(ctx), format!( "Record element '{}' has already been associated", elem.designator() ), ErrorCode::AlreadyAssociated, ) - .related(prev_pos, "Previously associated here"), + .related(prev_pos.pos(ctx), "Previously associated here"), ); } } @@ -1286,7 +1299,11 @@ mod test { diagnostics: &mut dyn DiagnosticHandler, ) -> Option> { let mut expr = code.expr(); - as_fatal(self.ctx().expr_type(&self.scope, &mut expr, diagnostics)).unwrap() + as_fatal( + self.ctx(&code.tokenize()) + .expr_type(&self.scope, &mut expr, diagnostics), + ) + .unwrap() } fn expr_with_ttyp( @@ -1296,8 +1313,8 @@ mod test { diagnostics: &mut dyn DiagnosticHandler, ) { let mut expr = code.expr(); - self.ctx() - .expr_pos_with_ttyp(&self.scope, ttyp, &expr.pos, &mut expr.item, diagnostics) + self.ctx(&code.tokenize()) + .expr_pos_with_ttyp(&self.scope, ttyp, expr.span, &mut expr.item, diagnostics) .unwrap() } } @@ -1357,7 +1374,7 @@ mod test { assert_eq!( test.expr_type(&test.snippet("0"), &mut NoDiagnostics), Some(ExpressionType::Unambiguous( - test.ctx().universal_integer().into() + test.ctx(&Vec::new()).universal_integer().into() )) ); } @@ -1368,7 +1385,7 @@ mod test { assert_eq!( test.expr_type(&test.snippet("0.0"), &mut NoDiagnostics), Some(ExpressionType::Unambiguous( - test.ctx().universal_real().into() + test.ctx(&Vec::new()).universal_real().into() )) ); } @@ -1623,7 +1640,7 @@ function \"+\"(a : integer; b : character) return integer; assert_eq!( test.expr_type(&code, &mut NoDiagnostics), Some(ExpressionType::Unambiguous( - test.ctx().universal_integer().into() + test.ctx(&code.tokenize()).universal_integer().into() )) ); } @@ -1644,13 +1661,13 @@ function with_arg(arg : natural) return integer; let code = test.snippet("no_arg"); test.expr_with_ttyp( &code, - test.ctx().universal_integer().into(), + test.ctx(&code.tokenize()).universal_integer().into(), &mut NoDiagnostics, ); let code = test.snippet("with_arg(0)"); test.expr_with_ttyp( &code, - test.ctx().universal_integer().into(), + test.ctx(&code.tokenize()).universal_integer().into(), &mut NoDiagnostics, ); } diff --git a/vhdl_lang/src/analysis/literals.rs b/vhdl_lang/src/analysis/literals.rs index 91bbe3a6..a76c0c28 100644 --- a/vhdl_lang/src/analysis/literals.rs +++ b/vhdl_lang/src/analysis/literals.rs @@ -12,12 +12,13 @@ use crate::ast::*; use crate::data::error_codes::ErrorCode; use crate::data::*; use crate::named_entity::*; +use crate::TokenSpan; -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { /// Analyze a string literal or expanded bit-string literal for type-matching fn analyze_string_literal( &self, - pos: &SrcPos, + span: TokenSpan, string_lit: Latin1String, target_base: TypeEnt, target_type: TypeEnt, @@ -28,7 +29,7 @@ impl<'a> AnalyzeContext<'a> { let chr = Designator::Character(*chr); if !literals.contains(&chr) { diagnostics.add( - pos, + span.pos(self.ctx), format!("{} does not define character {}", elem_type.describe(), chr), ErrorCode::InvalidLiteral, ); @@ -37,7 +38,7 @@ impl<'a> AnalyzeContext<'a> { } } else { diagnostics.add( - pos, + span.pos(self.ctx), format!("string literal does not match {}", target_type.describe()), ErrorCode::TypeMismatch, ); @@ -50,7 +51,7 @@ impl<'a> AnalyzeContext<'a> { &self, scope: &Scope<'a>, target_type: TypeEnt<'a>, - pos: &SrcPos, + span: TokenSpan, literal: &mut Literal, diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { @@ -62,7 +63,7 @@ impl<'a> AnalyzeContext<'a> { if !self.can_be_target_type(self.universal_integer().into(), target_type.base()) { diagnostics.add( - pos, + span.pos(self.ctx), format!("integer literal does not match {}", target_type.describe()), ErrorCode::TypeMismatch, ); @@ -71,7 +72,7 @@ impl<'a> AnalyzeContext<'a> { AbstractLiteral::Real(_) => { if !self.can_be_target_type(self.universal_real().into(), target_type.base()) { diagnostics.add( - pos, + span.pos(self.ctx), format!("real literal does not match {}", target_type.describe()), ErrorCode::TypeMismatch, ); @@ -82,7 +83,7 @@ impl<'a> AnalyzeContext<'a> { Type::Enum(literals) => { if !literals.contains(&Designator::Character(*char)) { diagnostics.add( - pos, + span.pos(self.ctx), format!( "character literal does not match {}", target_type.describe() @@ -93,7 +94,7 @@ impl<'a> AnalyzeContext<'a> { } _ => { diagnostics.add( - pos, + span.pos(self.ctx), format!( "character literal does not match {}", target_type.describe() @@ -104,7 +105,7 @@ impl<'a> AnalyzeContext<'a> { }, Literal::String(string_lit) => { self.analyze_string_literal( - pos, + span, string_lit.to_owned(), target_base, target_type, @@ -114,7 +115,7 @@ impl<'a> AnalyzeContext<'a> { Literal::BitString(bit_string) => { match bit_string_to_string(bit_string) { Ok(string_lit) => self.analyze_string_literal( - pos, + span, string_lit, target_base, target_type, @@ -124,7 +125,7 @@ impl<'a> AnalyzeContext<'a> { match err { BitStringConversionError::IllegalDecimalCharacter(rel_pos) => { diagnostics.add( - pos, + span.pos(self.ctx), format!( "Illegal digit '{}' for base 10", bit_string.value.bytes[rel_pos] as char, @@ -134,7 +135,7 @@ impl<'a> AnalyzeContext<'a> { } BitStringConversionError::IllegalTruncate(_, _) => { diagnostics.add( - pos, + span.pos(self.ctx), format!( "Truncating vector to length {} would lose information", bit_string.length.unwrap() // Safe as this error can only happen when there is a length @@ -144,7 +145,7 @@ impl<'a> AnalyzeContext<'a> { } BitStringConversionError::EmptySignedExpansion => { diagnostics.add( - pos, + span.pos(self.ctx), "Cannot expand an empty signed bit string", ErrorCode::InvalidLiteral, ); @@ -158,7 +159,7 @@ impl<'a> AnalyzeContext<'a> { Ok(physical_type) => { if physical_type.base_type() != target_base { diagnostics.push(Diagnostic::type_mismatch( - pos, + &span.pos(self.ctx), &physical_type.describe(), target_type, )) @@ -172,7 +173,7 @@ impl<'a> AnalyzeContext<'a> { Literal::Null => { if !matches!(target_base.kind(), Type::Access(_)) { diagnostics.add( - pos, + span.pos(self.ctx), format!("null literal does not match {}", target_base.describe()), ErrorCode::TypeMismatch, ); @@ -188,7 +189,8 @@ impl<'a> AnalyzeContext<'a> { unit: &mut WithRef, ) -> Result, Diagnostic> { match scope.lookup( - &unit.item.pos, + self.ctx, + unit.item.token, &Designator::Identifier(unit.item.item.clone()), )? { NamedEntities::Single(unit_ent) => { @@ -197,14 +199,14 @@ impl<'a> AnalyzeContext<'a> { Ok(*physical_ent) } else { Err(Diagnostic::new( - &unit.item.pos, + unit.item.pos(self.ctx), format!("{} is not a physical unit", unit_ent.describe()), ErrorCode::InvalidLiteral, )) } } NamedEntities::Overloaded(_) => Err(Diagnostic::new( - &unit.item.pos, + unit.item.pos(self.ctx), "Overloaded name may not be physical unit", ErrorCode::MismatchedKinds, )), diff --git a/vhdl_lang/src/analysis/names.rs b/vhdl_lang/src/analysis/names.rs index ad64bf2b..b6d398e3 100644 --- a/vhdl_lang/src/analysis/names.rs +++ b/vhdl_lang/src/analysis/names.rs @@ -6,6 +6,7 @@ use crate::analysis::target::AssignmentType; use fnv::FnvHashSet; +use vhdl_lang::{TokenAccess, TokenSpan}; use super::analyze::*; use super::expression::ExpressionType; @@ -13,6 +14,7 @@ use super::overloaded::Disambiguated; use super::overloaded::DisambiguatedType; use super::overloaded::SubprogramKind; use super::scope::*; +use crate::ast::token_range::{WithToken, WithTokenSpan}; use crate::ast::*; use crate::data::error_codes::ErrorCode; use crate::data::*; @@ -151,7 +153,7 @@ pub enum ResolvedName<'a> { Library(Symbol), Design(DesignEnt<'a>), Type(TypeEnt<'a>), - Overloaded(WithPos, OverloadedName<'a>), + Overloaded(WithToken, OverloadedName<'a>), ObjectName(ObjectName<'a>), /// The result of a function call and any subsequent selections thereof Expression(DisambiguatedType<'a>), @@ -338,7 +340,8 @@ impl<'a> ResolvedName<'a> { pub(crate) fn as_type_of_attr_prefix( &self, - prefix_pos: &SrcPos, + ctx: &dyn TokenAccess, + prefix_pos: TokenSpan, attr: &AttributeSuffix, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { @@ -346,7 +349,9 @@ impl<'a> ResolvedName<'a> { Ok(typ) } else { diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute( - prefix_pos, self, attr, + &prefix_pos.pos(ctx), + self, + attr, )); Err(EvalError::Unknown) } @@ -354,7 +359,8 @@ impl<'a> ResolvedName<'a> { fn as_type_of_signal_attr_prefix( &self, - prefix_pos: &SrcPos, + ctx: &dyn TokenAccess, + prefix_pos: TokenSpan, attr: &AttributeSuffix, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { @@ -365,7 +371,7 @@ impl<'a> ResolvedName<'a> { } diagnostics.add( - prefix_pos, + prefix_pos.pos(ctx), format!( "Expected signal prefix for '{} attribute, got {}", attr.attr, @@ -421,14 +427,14 @@ pub enum AttrResolveResult<'a> { #[derive(Debug)] pub struct AttributeSuffix<'a> { - pub signature: &'a mut Option>, - pub attr: &'a mut WithPos, - pub expr: &'a mut Option>>, + pub signature: &'a mut Option>, + pub attr: &'a mut WithToken, + pub expr: &'a mut Option>>, } #[derive(Debug)] enum Suffix<'a> { - Selected(&'a mut WithPos>), + Selected(&'a mut WithToken>), All, Slice(&'a mut DiscreteRange), Attribute(AttributeSuffix<'a>), @@ -438,7 +444,7 @@ enum Suffix<'a> { enum SplitName<'a> { Designator(&'a mut WithRef), External(&'a mut ExternalName), - Suffix(&'a mut WithPos, Suffix<'a>), + Suffix(&'a mut WithTokenSpan, Suffix<'a>), } impl<'a> SplitName<'a> { @@ -471,7 +477,7 @@ impl<'a> SplitName<'a> { enum TypeOrMethod<'a> { Type(TypeEnt<'a>), - Method(WithPos, OverloadedName<'a>), + Method(WithToken, OverloadedName<'a>), } fn could_be_indexed_name(assocs: &[AssociationElement]) -> bool { @@ -480,19 +486,21 @@ fn could_be_indexed_name(assocs: &[AssociationElement]) -> bool { .all(|assoc| assoc.formal.is_none() && !matches!(assoc.actual.item, ActualPart::Open)) } -pub fn as_type_conversion(assocs: &mut [AssociationElement]) -> Option<(&SrcPos, &mut Expression)> { +pub fn as_type_conversion( + assocs: &mut [AssociationElement], +) -> Option<(TokenSpan, &mut Expression)> { if assocs.len() == 1 && could_be_indexed_name(assocs) { if let ActualPart::Expression(ref mut expr) = assocs[0].actual.item { - return Some((&assocs[0].actual.pos, expr)); + return Some((assocs[0].actual.span, expr)); } } None } -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { fn name_to_type( &self, - pos: &SrcPos, + pos: TokenSpan, // Reference to set if overloaded name was disambiguated reference: Option<&mut Reference>, name: ResolvedName<'a>, @@ -500,7 +508,7 @@ impl<'a> AnalyzeContext<'a> { match name { ResolvedName::Library(_) | ResolvedName::Design(_) | ResolvedName::Type(_) => { Err(Diagnostic::new( - pos, + pos.pos(self.ctx), format!("{} cannot be used in an expression", name.describe_type()), ErrorCode::MismatchedKinds, )) @@ -515,7 +523,7 @@ impl<'a> AnalyzeContext<'a> { } AnyEntKind::InterfaceFile(typ) => Ok(Some(DisambiguatedType::Unambiguous(*typ))), _ => Err(Diagnostic::new( - pos, + pos.pos(self.ctx), format!("{} cannot be used in an expression", name.describe_type()), ErrorCode::MismatchedKinds, )), @@ -541,7 +549,7 @@ impl<'a> AnalyzeContext<'a> { fn name_to_unambiguous_type( &self, - pos: &SrcPos, + span: TokenSpan, name: &ResolvedName<'a>, ttyp: TypeEnt<'a>, // Optional reference to set when disambiguating overloaded @@ -550,7 +558,7 @@ impl<'a> AnalyzeContext<'a> { match name { ResolvedName::Library(_) | ResolvedName::Design(_) | ResolvedName::Type(_) => { Err(Diagnostic::new( - pos, + span.pos(self.ctx), format!("{} cannot be used in an expression", name.describe_type()), ErrorCode::MismatchedKinds, )) @@ -561,7 +569,7 @@ impl<'a> AnalyzeContext<'a> { AnyEntKind::File(subtype) => Ok(Some(subtype.type_mark())), AnyEntKind::InterfaceFile(typ) => Ok(Some(*typ)), _ => Err(Diagnostic::new( - pos, + span.pos(self.ctx), format!("{} cannot be used in an expression", name.describe_type()), ErrorCode::MismatchedKinds, )), @@ -576,7 +584,7 @@ impl<'a> AnalyzeContext<'a> { Ok(Some(ent.return_type().unwrap())) } Disambiguated::Ambiguous(overloaded) => { - Err(Diagnostic::ambiguous_call(des, overloaded)) + Err(Diagnostic::ambiguous_call(self.ctx, des, overloaded)) } } } else { @@ -611,7 +619,7 @@ impl<'a> AnalyzeContext<'a> { if let ActualPart::Expression(expr) = &mut assoc.actual.item { return self.expr_as_discrete_range_type( scope, - &assoc.actual.pos, + assoc.actual.span, expr, diagnostics, ); @@ -623,7 +631,7 @@ impl<'a> AnalyzeContext<'a> { pub fn expr_as_discrete_range_type( &self, scope: &Scope<'a>, - expr_pos: &SrcPos, + expr_pos: TokenSpan, expr: &mut Expression, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult>> { @@ -654,7 +662,7 @@ impl<'a> AnalyzeContext<'a> { bail!( diagnostics, Diagnostic::new( - expr_pos, + expr_pos.pos(self.ctx), format!("{} cannot be used as a discrete range", typ.describe()), ErrorCode::MismatchedKinds, ) @@ -671,8 +679,8 @@ impl<'a> AnalyzeContext<'a> { fn resolve_typed_suffix( &self, scope: &Scope<'a>, - prefix_pos: &SrcPos, - name_pos: &SrcPos, + prefix_pos: TokenSpan, + name_pos: TokenSpan, prefix_typ: TypeEnt<'a>, suffix: &mut Suffix, diagnostics: &mut dyn DiagnosticHandler, @@ -680,7 +688,7 @@ impl<'a> AnalyzeContext<'a> { match suffix { Suffix::Selected(suffix) => Ok(Some( match prefix_typ - .selected(prefix_pos, suffix) + .selected(self.ctx, prefix_pos, suffix) .into_eval_result(diagnostics)? { TypedSelection::RecordElement(elem) => { @@ -688,7 +696,7 @@ impl<'a> AnalyzeContext<'a> { TypeOrMethod::Type(elem.type_mark()) } TypedSelection::ProtectedMethod(name) => TypeOrMethod::Method( - WithPos::new(suffix.item.item.clone(), suffix.pos.clone()), + WithToken::new(suffix.item.item.clone(), suffix.token), name, ), }, @@ -704,7 +712,7 @@ impl<'a> AnalyzeContext<'a> { } } else { diagnostics.add( - name_pos, + name_pos.pos(self.ctx), format!( "Cannot slice {}-dimensional {}", indexes.len(), @@ -742,14 +750,14 @@ impl<'a> AnalyzeContext<'a> { self.expr_pos_with_ttyp( scope, ttyp.into(), - &actual.pos, + actual.span, expr, diagnostics, )?; } else { self.expr_pos_unknown_ttyp( scope, - &actual.pos, + actual.span, expr, diagnostics, )?; @@ -763,7 +771,7 @@ impl<'a> AnalyzeContext<'a> { bail!( diagnostics, Diagnostic::dimension_mismatch( - name_pos, + &name_pos.pos(self.ctx), prefix_typ, assocs.len(), num_indexes, @@ -786,7 +794,7 @@ impl<'a> AnalyzeContext<'a> { pub(crate) fn array_index_expression_in_attribute( &self, indexes: &[Option>], - mut expr: Option<&mut WithPos>, + mut expr: Option<&mut WithTokenSpan>, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { let idx = if let Some(expr) = expr.as_mut() { @@ -796,7 +804,7 @@ impl<'a> AnalyzeContext<'a> { idx as usize } else { diagnostics.add( - &expr.pos, + &expr.span.pos(self.ctx), "Expected an integer literal", ErrorCode::MismatchedKinds, ); @@ -817,7 +825,7 @@ impl<'a> AnalyzeContext<'a> { if let Some(expr) = expr { let ndims = indexes.len(); let dimensions = plural("dimension", "dimensions", ndims); - diagnostics.add(&expr.pos, format!("Index {idx} out of range for array with {ndims} {dimensions}, expected 1 to {ndims}"), ErrorCode::DimensionMismatch); + diagnostics.add(&expr.pos(self.ctx), format!("Index {idx} out of range for array with {ndims} {dimensions}, expected 1 to {ndims}"), ErrorCode::DimensionMismatch); } Err(EvalError::Unknown) } @@ -827,7 +835,7 @@ impl<'a> AnalyzeContext<'a> { &self, resolved: &ResolvedName<'a>, diagnostics: &mut dyn DiagnosticHandler, - pos: &SrcPos, + pos: TokenSpan, ) -> EvalResult> { let ent = match resolved { ResolvedName::Final(ent) => { @@ -835,7 +843,7 @@ impl<'a> AnalyzeContext<'a> { bail!( diagnostics, Diagnostic::new( - pos, + pos.pos(self.ctx), format!("{} is not a view", resolved.describe()), ErrorCode::MismatchedKinds ) @@ -847,7 +855,7 @@ impl<'a> AnalyzeContext<'a> { bail!( diagnostics, Diagnostic::new( - pos, + pos.pos(self.ctx), format!("{} is not a view", resolved.describe()), ErrorCode::MismatchedKinds ) @@ -859,8 +867,8 @@ impl<'a> AnalyzeContext<'a> { pub fn attribute_suffix( &self, - name_pos: &SrcPos, - prefix_pos: &SrcPos, + name_pos: TokenSpan, + prefix_pos: TokenSpan, scope: &Scope<'a>, prefix: &ResolvedName<'a>, attr: &mut AttributeSuffix, @@ -871,7 +879,7 @@ impl<'a> AnalyzeContext<'a> { | AttributeDesignator::Right | AttributeDesignator::High | AttributeDesignator::Low => { - let typ = prefix.as_type_of_attr_prefix(prefix_pos, attr, diagnostics)?; + let typ = prefix.as_type_of_attr_prefix(self.ctx, prefix_pos, attr, diagnostics)?; if let Some((_, indexes)) = typ.array_type() { self.array_index_expression_in_attribute( @@ -881,34 +889,40 @@ impl<'a> AnalyzeContext<'a> { ) .map(AttrResolveResult::Value) } else if typ.is_scalar() { - check_no_attr_argument(attr, diagnostics); + check_no_attr_argument(self.ctx, attr, diagnostics); Ok(AttrResolveResult::Value(typ.into())) } else { diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute( - name_pos, prefix, attr, + &name_pos.pos(self.ctx), + prefix, + attr, )); Err(EvalError::Unknown) } } AttributeDesignator::Ascending => { - let typ = prefix.as_type_of_attr_prefix(prefix_pos, attr, diagnostics)?; + let typ = prefix.as_type_of_attr_prefix(self.ctx, prefix_pos, attr, diagnostics)?; if typ.array_type().is_some() { Ok(AttrResolveResult::Value(self.boolean().base())) } else if typ.is_scalar() { - check_no_attr_argument(attr, diagnostics); + check_no_attr_argument(self.ctx, attr, diagnostics); Ok(AttrResolveResult::Value(self.boolean().base())) } else { diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute( - name_pos, prefix, attr, + &name_pos.pos(self.ctx), + prefix, + attr, )); Err(EvalError::Unknown) } } AttributeDesignator::Image => { - let typ = prefix.as_type_of_attr_prefix(prefix_pos, attr, diagnostics)?; + let typ = prefix.as_type_of_attr_prefix(self.ctx, prefix_pos, attr, diagnostics)?; - if let Some(ref mut expr) = check_single_argument(name_pos, attr, diagnostics) { + if let Some(ref mut expr) = + check_single_argument(self.ctx, name_pos, attr, diagnostics) + { self.expr_with_ttyp(scope, typ, expr, diagnostics)?; } @@ -916,15 +930,19 @@ impl<'a> AnalyzeContext<'a> { Ok(AttrResolveResult::Value(self.string().base())) } else { diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute( - name_pos, prefix, attr, + &name_pos.pos(self.ctx), + prefix, + attr, )); Err(EvalError::Unknown) } } AttributeDesignator::Value => { - let typ = prefix.as_type_of_attr_prefix(prefix_pos, attr, diagnostics)?; + let typ = prefix.as_type_of_attr_prefix(self.ctx, prefix_pos, attr, diagnostics)?; - if let Some(ref mut expr) = check_single_argument(name_pos, attr, diagnostics) { + if let Some(ref mut expr) = + check_single_argument(self.ctx, name_pos, attr, diagnostics) + { self.expr_with_ttyp(scope, self.string(), expr, diagnostics)?; } @@ -932,31 +950,39 @@ impl<'a> AnalyzeContext<'a> { Ok(AttrResolveResult::Value(typ.base())) } else { diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute( - name_pos, prefix, attr, + &name_pos.pos(self.ctx), + prefix, + attr, )); Err(EvalError::Unknown) } } AttributeDesignator::Pos => { - let typ = prefix.as_type_of_attr_prefix(prefix_pos, attr, diagnostics)?; + let typ = prefix.as_type_of_attr_prefix(self.ctx, prefix_pos, attr, diagnostics)?; if typ.base().is_discrete() { - if let Some(ref mut expr) = check_single_argument(name_pos, attr, diagnostics) { + if let Some(ref mut expr) = + check_single_argument(self.ctx, name_pos, attr, diagnostics) + { self.expr_with_ttyp(scope, typ, expr, diagnostics)?; } Ok(AttrResolveResult::Value(self.universal_integer())) } else { diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute( - name_pos, prefix, attr, + &name_pos.pos(self.ctx), + prefix, + attr, )); Err(EvalError::Unknown) } } AttributeDesignator::Val => { - let typ = prefix.as_type_of_attr_prefix(prefix_pos, attr, diagnostics)?; + let typ = prefix.as_type_of_attr_prefix(self.ctx, prefix_pos, attr, diagnostics)?; if typ.base().is_discrete() { - if let Some(ref mut expr) = check_single_argument(name_pos, attr, diagnostics) { + if let Some(ref mut expr) = + check_single_argument(self.ctx, name_pos, attr, diagnostics) + { self.expr_with_ttyp( scope, self.universal_integer().into(), @@ -967,7 +993,9 @@ impl<'a> AnalyzeContext<'a> { Ok(AttrResolveResult::Value(typ.base())) } else { diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute( - name_pos, prefix, attr, + &name_pos.pos(self.ctx), + prefix, + attr, )); Err(EvalError::Unknown) } @@ -976,28 +1004,34 @@ impl<'a> AnalyzeContext<'a> { | AttributeDesignator::Pred | AttributeDesignator::LeftOf | AttributeDesignator::RightOf => { - let typ = prefix.as_type_of_attr_prefix(prefix_pos, attr, diagnostics)?; + let typ = prefix.as_type_of_attr_prefix(self.ctx, prefix_pos, attr, diagnostics)?; if typ.base().is_discrete() { - if let Some(ref mut expr) = check_single_argument(name_pos, attr, diagnostics) { + if let Some(ref mut expr) = + check_single_argument(self.ctx, name_pos, attr, diagnostics) + { self.expr_with_ttyp(scope, typ, expr, diagnostics)?; } Ok(AttrResolveResult::Value(typ.base())) } else { diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute( - name_pos, prefix, attr, + &name_pos.pos(self.ctx), + prefix, + attr, )); Err(EvalError::Unknown) } } AttributeDesignator::Length => { - let typ = prefix.as_type_of_attr_prefix(prefix_pos, attr, diagnostics)?; + let typ = prefix.as_type_of_attr_prefix(self.ctx, prefix_pos, attr, diagnostics)?; if typ.array_type().is_some() { Ok(AttrResolveResult::Value(self.universal_integer())) } else { diagnostics.push(Diagnostic::cannot_be_prefix_of_attribute( - name_pos, prefix, attr, + &name_pos.pos(self.ctx), + prefix, + attr, )); Err(EvalError::Unknown) } @@ -1005,12 +1039,17 @@ impl<'a> AnalyzeContext<'a> { AttributeDesignator::SimpleName | AttributeDesignator::InstanceName | AttributeDesignator::PathName => { - check_no_attr_argument(attr, diagnostics); + check_no_attr_argument(self.ctx, attr, diagnostics); Ok(AttrResolveResult::Value(self.string().base())) } AttributeDesignator::Signal(sattr) => { - let typ = prefix.as_type_of_signal_attr_prefix(prefix_pos, attr, diagnostics)?; + let typ = prefix.as_type_of_signal_attr_prefix( + self.ctx, + prefix_pos, + attr, + diagnostics, + )?; let expr = attr.expr.as_mut().map(|expr| expr.as_mut()); match sattr { SignalAttribute::Delayed => { @@ -1026,35 +1065,35 @@ impl<'a> AnalyzeContext<'a> { Ok(AttrResolveResult::Value(self.boolean().base())) } SignalAttribute::Transaction => { - check_no_sattr_argument(sattr, expr, diagnostics); + check_no_sattr_argument(self.ctx, sattr, expr, diagnostics); Ok(AttrResolveResult::Value(self.bit().base())) } SignalAttribute::Event => { - check_no_sattr_argument(sattr, expr, diagnostics); + check_no_sattr_argument(self.ctx, sattr, expr, diagnostics); Ok(AttrResolveResult::Value(self.boolean().base())) } SignalAttribute::Active => { - check_no_sattr_argument(sattr, expr, diagnostics); + check_no_sattr_argument(self.ctx, sattr, expr, diagnostics); Ok(AttrResolveResult::Value(self.boolean().base())) } SignalAttribute::LastEvent => { - check_no_sattr_argument(sattr, expr, diagnostics); + check_no_sattr_argument(self.ctx, sattr, expr, diagnostics); Ok(AttrResolveResult::Value(self.time().base())) } SignalAttribute::LastActive => { - check_no_sattr_argument(sattr, expr, diagnostics); + check_no_sattr_argument(self.ctx, sattr, expr, diagnostics); Ok(AttrResolveResult::Value(self.time().base())) } SignalAttribute::LastValue => { - check_no_sattr_argument(sattr, expr, diagnostics); + check_no_sattr_argument(self.ctx, sattr, expr, diagnostics); Ok(AttrResolveResult::Value(typ.base())) } SignalAttribute::Driving => { - check_no_sattr_argument(sattr, expr, diagnostics); + check_no_sattr_argument(self.ctx, sattr, expr, diagnostics); Ok(AttrResolveResult::Value(self.boolean().base())) } SignalAttribute::DrivingValue => { - check_no_sattr_argument(sattr, expr, diagnostics); + check_no_sattr_argument(self.ctx, sattr, expr, diagnostics); Ok(AttrResolveResult::Value(typ.base())) } } @@ -1067,7 +1106,7 @@ impl<'a> AnalyzeContext<'a> { Ok(AttrResolveResult::Value(attr.typ().base())) } else { diagnostics.add( - &attr.attr.pos, + attr.attr.pos(self.ctx), format!("Unknown attribute '{}", attr.attr.item), ErrorCode::Unresolved, ); @@ -1075,7 +1114,7 @@ impl<'a> AnalyzeContext<'a> { } } else { diagnostics.add( - name_pos, + name_pos.pos(self.ctx), format!( "{} may not be the prefix of a user defined attribute", prefix.describe() @@ -1087,7 +1126,7 @@ impl<'a> AnalyzeContext<'a> { } AttributeDesignator::Range(_) => { diagnostics.add( - name_pos, + name_pos.pos(self.ctx), "Range cannot be used as an expression", ErrorCode::MismatchedKinds, ); @@ -1118,13 +1157,13 @@ impl<'a> AnalyzeContext<'a> { &self, prefix: &ResolvedName<'a>, suffix: &TypeAttribute, - pos: &SrcPos, + pos: TokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { // all type attribute suffixes require that the prefix be an object type let Some(obj) = prefix.as_object_name() else { diagnostics.add( - pos, + pos.pos(self.ctx), format!( "The {} attribute can only be used on objects, not {}", suffix, @@ -1141,7 +1180,7 @@ impl<'a> AnalyzeContext<'a> { Ok(elem_type) } else { diagnostics.add( - pos, + pos.pos(self.ctx), "The element attribute can only be used for array types", ErrorCode::IllegalAttribute, ); @@ -1154,7 +1193,7 @@ impl<'a> AnalyzeContext<'a> { pub fn name_resolve( &self, scope: &Scope<'a>, - name_pos: &SrcPos, + name_pos: TokenSpan, name: &mut Name, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { @@ -1164,7 +1203,7 @@ impl<'a> AnalyzeContext<'a> { fn name_resolve_with_suffixes( &self, scope: &Scope<'a>, - name_pos: &SrcPos, + span: TokenSpan, name: &mut Name, ttyp: Option>, has_suffix: bool, @@ -1175,18 +1214,18 @@ impl<'a> AnalyzeContext<'a> { let mut resolved = match SplitName::from_name(name) { SplitName::Designator(designator) => { let name = scope - .lookup(name_pos, designator.designator()) + .lookup(self.ctx, span, designator.designator()) .into_eval_result(diagnostics)?; return Ok(match name { NamedEntities::Single(ent) => { designator.set_unique_reference(ent); ResolvedName::from_scope_not_overloaded(ent) - .map_err(|(e, code)| Diagnostic::new(name_pos, e, code)) + .map_err(|(e, code)| Diagnostic::new(span.pos(self.ctx), e, code)) .into_eval_result(diagnostics)? } NamedEntities::Overloaded(overloaded) => ResolvedName::Overloaded( - WithPos::new(designator.item.clone(), name_pos.clone()), + WithToken::new(designator.designator().clone(), span.start_token), overloaded, ), }); @@ -1202,7 +1241,7 @@ impl<'a> AnalyzeContext<'a> { SplitName::Suffix(p, s) => { let resolved = self.name_resolve_with_suffixes( scope, - &p.pos, + p.span, &mut p.item, None, true, @@ -1233,13 +1272,14 @@ impl<'a> AnalyzeContext<'a> { Disambiguated::Ambiguous(ents) => { if let Some(types) = ambiguous_functions_to_types(&ents) { if has_suffix || ttyp.is_some() { - diagnostics.push(Diagnostic::ambiguous_call(des, ents)); + diagnostics + .push(Diagnostic::ambiguous_call(self.ctx, des, ents)); } resolved = ResolvedName::Expression(DisambiguatedType::Ambiguous(types)); } else { diagnostics.add( - &prefix.pos, + &prefix.pos(self.ctx), "Procedure calls are not valid in names and expressions", ErrorCode::MismatchedKinds, ); @@ -1254,7 +1294,7 @@ impl<'a> AnalyzeContext<'a> { ResolvedName::Expression(DisambiguatedType::Unambiguous(typ)); } else { diagnostics.add( - &prefix.pos, + &prefix.pos(self.ctx), "Procedure calls are not valid in names and expressions", ErrorCode::MismatchedKinds, ); @@ -1268,7 +1308,7 @@ impl<'a> AnalyzeContext<'a> { if let Suffix::Attribute(ref mut attr) = suffix { let typ = - self.attribute_suffix(name_pos, &prefix.pos, scope, &resolved, attr, diagnostics)?; + self.attribute_suffix(span, prefix.span, scope, &resolved, attr, diagnostics)?; return match typ { AttrResolveResult::Type(base) => Ok(ResolvedName::Type(base.into())), AttrResolveResult::Value(base) => Ok(ResolvedName::Expression( @@ -1294,7 +1334,7 @@ impl<'a> AnalyzeContext<'a> { match as_fatal(self.disambiguate( scope, - name_pos, + &span.pos(self.ctx), des, assocs, SubprogramKind::Function(if has_suffix { @@ -1309,14 +1349,15 @@ impl<'a> AnalyzeContext<'a> { Some(Disambiguated::Ambiguous(ents)) => { if let Some(types) = ambiguous_functions_to_types(&ents) { if has_suffix || ttyp.is_some() { - diagnostics.push(Diagnostic::ambiguous_call(des, ents)); + diagnostics + .push(Diagnostic::ambiguous_call(self.ctx, des, ents)); } resolved = ResolvedName::Expression(DisambiguatedType::Ambiguous(types)); } else { diagnostics.add( - &prefix.pos, + &prefix.pos(self.ctx), "Procedure calls are not valid in names and expressions", ErrorCode::MismatchedKinds, ); @@ -1331,7 +1372,7 @@ impl<'a> AnalyzeContext<'a> { ); } else { diagnostics.add( - &prefix.pos, + &prefix.pos(self.ctx), "Procedure calls are not valid in names and expressions", ErrorCode::MismatchedKinds, ); @@ -1344,7 +1385,7 @@ impl<'a> AnalyzeContext<'a> { } } else { diagnostics.push(Diagnostic::unreachable( - name_pos, + &span.pos(self.ctx), "CallOrIndexed should already be handled", )); return Err(EvalError::Unknown); @@ -1353,8 +1394,8 @@ impl<'a> AnalyzeContext<'a> { ResolvedName::ObjectName(oname) => { match self.resolve_typed_suffix( scope, - &prefix.pos, - name_pos, + prefix.span, + span, oname.type_mark(), &mut suffix, diagnostics, @@ -1367,7 +1408,7 @@ impl<'a> AnalyzeContext<'a> { } None => { diagnostics.push(Diagnostic::cannot_be_prefix( - &prefix.pos, + &prefix.pos(self.ctx), resolved, suffix, )); @@ -1379,8 +1420,8 @@ impl<'a> AnalyzeContext<'a> { DisambiguatedType::Unambiguous(typ) => { match self.resolve_typed_suffix( scope, - &prefix.pos, - name_pos, + prefix.span, + span, *typ, &mut suffix, diagnostics, @@ -1394,7 +1435,7 @@ impl<'a> AnalyzeContext<'a> { } None => { diagnostics.push(Diagnostic::cannot_be_prefix( - &prefix.pos, + &prefix.pos(self.ctx), resolved, suffix, )); @@ -1414,7 +1455,7 @@ impl<'a> AnalyzeContext<'a> { self.lookup_in_library( diagnostics, library_name, - &designator.pos, + designator.pos(self.ctx), &designator.item.item, ) .map(|design| { @@ -1426,33 +1467,43 @@ impl<'a> AnalyzeContext<'a> { })?, ); } else { - diagnostics.push(Diagnostic::cannot_be_prefix(name_pos, resolved, suffix)); + diagnostics.push(Diagnostic::cannot_be_prefix( + &span.pos(self.ctx), + resolved, + suffix, + )); return Err(EvalError::Unknown); } } ResolvedName::Design(ref ent) => { if let Suffix::Selected(ref mut designator) = suffix { let name = ent - .selected(&prefix.pos, designator) + .selected(self.ctx, prefix.span, designator) .into_eval_result(diagnostics)?; resolved = match name { NamedEntities::Single(named_entity) => { designator.set_reference(&name); ResolvedName::from_design_not_overloaded(named_entity) - .map_err(|(e, code)| Diagnostic::new(&designator.pos, e, code)) + .map_err(|(e, code)| { + Diagnostic::new(designator.pos(self.ctx), e, code) + }) .into_eval_result(diagnostics)? } NamedEntities::Overloaded(overloaded) => { // Could be used for an alias of a subprogram ResolvedName::Overloaded( - WithPos::new(designator.item.item.clone(), designator.pos.clone()), + WithToken::new(designator.item.item.clone(), designator.token), overloaded, ) } } } else { - diagnostics.push(Diagnostic::cannot_be_prefix(name_pos, resolved, suffix)); + diagnostics.push(Diagnostic::cannot_be_prefix( + &span.pos(self.ctx), + resolved, + suffix, + )); return Err(EvalError::Unknown); } } @@ -1466,11 +1517,19 @@ impl<'a> AnalyzeContext<'a> { } } - diagnostics.push(Diagnostic::cannot_be_prefix(name_pos, resolved, suffix)); + diagnostics.push(Diagnostic::cannot_be_prefix( + &span.pos(self.ctx), + resolved, + suffix, + )); return Err(EvalError::Unknown); } ResolvedName::Final(_) => { - diagnostics.push(Diagnostic::cannot_be_prefix(name_pos, resolved, suffix)); + diagnostics.push(Diagnostic::cannot_be_prefix( + &span.pos(self.ctx), + resolved, + suffix, + )); return Err(EvalError::Unknown); } } @@ -1484,7 +1543,7 @@ impl<'a> AnalyzeContext<'a> { pub fn resolve_object_name( &self, scope: &Scope<'a>, - name_pos: &SrcPos, + name_pos: TokenSpan, name: &mut Name, err_msg: &'static str, error_code: ErrorCode, @@ -1500,7 +1559,7 @@ impl<'a> AnalyzeContext<'a> { | ResolvedName::Expression(_) | ResolvedName::Final(_) => { diagnostics.add( - name_pos, + name_pos.pos(self.ctx), format!("{} {}", resolved.describe(), err_msg), error_code, ); @@ -1512,7 +1571,7 @@ impl<'a> AnalyzeContext<'a> { pub fn type_name( &self, scope: &Scope<'a>, - name_pos: &SrcPos, + name_pos: TokenSpan, name: &mut Name, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { @@ -1526,7 +1585,7 @@ impl<'a> AnalyzeContext<'a> { | ResolvedName::Expression(_) | ResolvedName::Final(_) => { diagnostics.add( - name_pos, + name_pos.pos(self.ctx), format!("Expected type name, got {}", resolved.describe()), ErrorCode::MismatchedKinds, ); @@ -1539,7 +1598,7 @@ impl<'a> AnalyzeContext<'a> { &self, scope: &Scope<'a>, typ: TypeEnt<'a>, - pos: &SrcPos, + pos: TokenSpan, expr: &mut Expression, diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { @@ -1548,7 +1607,7 @@ impl<'a> AnalyzeContext<'a> { ExpressionType::Unambiguous(ctyp) => { if !typ.base().is_closely_related(ctyp.base()) { diagnostics.add( - pos, + pos.pos(self.ctx), format!( "{} cannot be converted to {}", ctyp.describe(), @@ -1562,7 +1621,7 @@ impl<'a> AnalyzeContext<'a> { | ExpressionType::Ambiguous(_) | ExpressionType::Null | ExpressionType::Aggregate => diagnostics.add( - pos, + pos.pos(self.ctx), format!( "{} cannot be the argument of type conversion", types.describe() @@ -1578,13 +1637,13 @@ impl<'a> AnalyzeContext<'a> { pub fn expression_name_types( &self, scope: &Scope<'a>, - expr_pos: &SrcPos, + span: TokenSpan, name: &mut Name, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { let resolved = - self.name_resolve_with_suffixes(scope, expr_pos, name, None, false, diagnostics)?; - match self.name_to_type(expr_pos, name.suffix_reference_mut(), resolved) { + self.name_resolve_with_suffixes(scope, span, name, None, false, diagnostics)?; + match self.name_to_type(span, name.suffix_reference_mut(), resolved) { Ok(Some(typ)) => Ok(typ), Ok(None) => Err(EvalError::Unknown), Err(diag) => { @@ -1598,30 +1657,26 @@ impl<'a> AnalyzeContext<'a> { pub fn expression_name_with_ttyp( &self, scope: &Scope<'a>, - expr_pos: &SrcPos, + span: TokenSpan, name: &mut Name, ttyp: TypeEnt<'a>, diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { if let Some(resolved) = as_fatal(self.name_resolve_with_suffixes( scope, - expr_pos, + span, name, Some(ttyp), false, diagnostics, ))? { // @TODO target_type already used above, functions could probably be simplified - match self.name_to_unambiguous_type( - expr_pos, - &resolved, - ttyp, - name.suffix_reference_mut(), - ) { + match self.name_to_unambiguous_type(span, &resolved, ttyp, name.suffix_reference_mut()) + { Ok(Some(type_mark)) => { if !self.can_be_target_type(type_mark, ttyp.base()) { diagnostics.push(Diagnostic::type_mismatch( - expr_pos, + &span.pos(self.ctx), &resolved.describe_type(), ttyp, )); @@ -1641,8 +1696,8 @@ impl<'a> AnalyzeContext<'a> { pub fn analyze_indexed_name( &self, scope: &Scope<'a>, - name_pos: &SrcPos, - suffix_pos: &SrcPos, + name_pos: TokenSpan, + suffix_pos: TokenSpan, type_mark: TypeEnt<'a>, indexes: &mut [Index], diagnostics: &mut dyn DiagnosticHandler, @@ -1663,7 +1718,7 @@ impl<'a> AnalyzeContext<'a> { { if indexes.len() != index_types.len() { diagnostics.push(Diagnostic::dimension_mismatch( - name_pos, + &name_pos.pos(self.ctx), base_type, indexes.len(), index_types.len(), @@ -1679,7 +1734,7 @@ impl<'a> AnalyzeContext<'a> { bail!( diagnostics, Diagnostic::new( - suffix_pos, + suffix_pos.pos(self.ctx), format!("{} cannot be indexed", type_mark.describe()), ErrorCode::MismatchedKinds, ) @@ -1690,9 +1745,9 @@ impl<'a> AnalyzeContext<'a> { pub fn lookup_selected( &self, diagnostics: &mut dyn DiagnosticHandler, - prefix_pos: &SrcPos, + prefix_pos: TokenSpan, prefix: EntRef<'a>, - suffix: &mut WithPos>, + suffix: &mut WithToken>, ) -> EvalResult> { match prefix.actual_kind() { AnyEntKind::Library => { @@ -1700,7 +1755,7 @@ impl<'a> AnalyzeContext<'a> { let named_entity = self.lookup_in_library( diagnostics, library_name, - &suffix.pos, + suffix.pos(self.ctx), &suffix.item.item, )?; suffix @@ -1712,27 +1767,27 @@ impl<'a> AnalyzeContext<'a> { AnyEntKind::Object(ref object) => Ok(object .subtype .type_mark() - .selected(prefix_pos, suffix) + .selected(self.ctx, prefix_pos, suffix) .into_eval_result(diagnostics)? .into_any()), AnyEntKind::ObjectAlias { ref type_mark, .. } => Ok(type_mark - .selected(prefix_pos, suffix) + .selected(self.ctx, prefix_pos, suffix) .into_eval_result(diagnostics)? .into_any()), AnyEntKind::ExternalAlias { ref type_mark, .. } => Ok(type_mark - .selected(prefix_pos, suffix) + .selected(self.ctx, prefix_pos, suffix) .into_eval_result(diagnostics)? .into_any()), AnyEntKind::ElementDeclaration(ref subtype) => Ok(subtype .type_mark() - .selected(prefix_pos, suffix) + .selected(self.ctx, prefix_pos, suffix) .into_eval_result(diagnostics)? .into_any()), AnyEntKind::Design(_) => { let design = DesignEnt::from_any(prefix) .ok_or_else(|| { Diagnostic::internal( - &suffix.pos, + suffix.pos(self.ctx), format!( "Internal error when expecting design unit, got {}", prefix.describe() @@ -1742,7 +1797,7 @@ impl<'a> AnalyzeContext<'a> { .into_eval_result(diagnostics)?; let named = design - .selected(prefix_pos, suffix) + .selected(self.ctx, prefix_pos, suffix) .into_eval_result(diagnostics)?; Ok(named) } @@ -1750,7 +1805,7 @@ impl<'a> AnalyzeContext<'a> { _ => { bail!( diagnostics, - Diagnostic::invalid_selected_name_prefix(prefix, prefix_pos) + Diagnostic::invalid_selected_name_prefix(prefix, &prefix_pos.pos(self.ctx)) ); } } @@ -1882,11 +1937,12 @@ impl Diagnostic { } pub fn ambiguous_call<'a>( - call_name: &WithPos, + ctx: &dyn TokenAccess, + call_name: &WithToken, candidates: impl IntoIterator>, ) -> Diagnostic { let mut diag = Diagnostic::new( - &call_name.pos, + call_name.pos(ctx), format!("Ambiguous call to {}", call_name.item.describe()), ErrorCode::AmbiguousCall, ); @@ -1895,10 +1951,14 @@ impl Diagnostic { } } -fn check_no_attr_argument(suffix: &AttributeSuffix, diagnostics: &mut dyn DiagnosticHandler) { +fn check_no_attr_argument( + ctx: &dyn TokenAccess, + suffix: &AttributeSuffix, + diagnostics: &mut dyn DiagnosticHandler, +) { if let Some(ref expr) = suffix.expr { diagnostics.add( - &expr.pos, + &expr.pos(ctx), format!("'{} attribute does not take an argument", suffix.attr), ErrorCode::TooManyArguments, ) @@ -1906,13 +1966,14 @@ fn check_no_attr_argument(suffix: &AttributeSuffix, diagnostics: &mut dyn Diagno } fn check_no_sattr_argument( + ctx: &dyn TokenAccess, attr: SignalAttribute, - expr: Option<&mut WithPos>, + expr: Option<&mut WithTokenSpan>, diagnostics: &mut dyn DiagnosticHandler, ) { if let Some(ref expr) = expr { diagnostics.add( - &expr.pos, + expr.pos(ctx), format!("'{attr} attribute does not take an argument"), ErrorCode::TooManyArguments, ) @@ -1920,15 +1981,16 @@ fn check_no_sattr_argument( } fn check_single_argument<'a>( - pos: &SrcPos, + ctx: &dyn TokenAccess, + pos: TokenSpan, suffix: &'a mut AttributeSuffix, diagnostics: &mut dyn DiagnosticHandler, -) -> Option<&'a mut WithPos> { +) -> Option<&'a mut WithTokenSpan> { if let Some(ref mut expr) = suffix.expr { Some(expr) } else { diagnostics.add( - pos, + pos.pos(ctx), format!("'{} attribute requires a single argument", suffix.attr), ErrorCode::Unassociated, ); @@ -1969,9 +2031,9 @@ mod test { diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { let mut name = code.name(); - self.ctx().name_resolve_with_suffixes( + self.ctx(&code.tokenize()).name_resolve_with_suffixes( &self.scope, - &name.pos, + name.span, &mut name.item, ttyp, false, @@ -1986,10 +2048,10 @@ mod test { diagnostics: &mut dyn DiagnosticHandler, ) { let mut name = code.name(); - self.ctx() + self.ctx(&code.tokenize()) .expression_name_with_ttyp( &self.scope, - &name.pos, + name.span, &mut name.item, ttyp, diagnostics, @@ -2003,9 +2065,9 @@ mod test { diagnostics: &mut dyn DiagnosticHandler, ) -> Option> { let mut name = code.name(); - as_fatal(self.ctx().expression_name_types( + as_fatal(self.ctx(&code.tokenize()).expression_name_types( &self.scope, - &name.pos, + name.span, &mut name.item, diagnostics, )) @@ -2589,7 +2651,7 @@ type arr_t is array (integer range 0 to 3) of integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().universal_integer().into() + test.ctx(&code.tokenize()).universal_integer().into() ))) ); } @@ -2609,7 +2671,7 @@ constant c0 : arr_t := (others => 0); assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().universal_integer().into() + test.ctx(&code.tokenize()).universal_integer().into() ))) ); } @@ -2629,7 +2691,7 @@ constant c0 : arr_t := (others => 0); assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().boolean() + test.ctx(&code.tokenize()).boolean() ))) ); } @@ -2642,7 +2704,7 @@ constant c0 : arr_t := (others => 0); assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().string() + test.ctx(&code.tokenize()).string() ))) ); @@ -2651,7 +2713,7 @@ constant c0 : arr_t := (others => 0); assert_eq!( test.name_resolve(&code, None, &mut diagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().string() + test.ctx(&code.tokenize()).string() ))) ); check_diagnostics( @@ -2673,7 +2735,7 @@ constant c0 : arr_t := (others => 0); assert_eq!( test.name_resolve(&code, None, &mut diagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().integer() + test.ctx(&code.tokenize()).integer() ))) ); check_diagnostics( @@ -2694,7 +2756,7 @@ constant c0 : arr_t := (others => 0); assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().integer() + test.ctx(&code.tokenize()).integer() ))) ); } @@ -2707,7 +2769,7 @@ constant c0 : arr_t := (others => 0); assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().universal_integer().into() + test.ctx(&code.tokenize()).universal_integer().into() ))) ); @@ -2715,7 +2777,7 @@ constant c0 : arr_t := (others => 0); assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().character() + test.ctx(&code.tokenize()).character() ))) ); @@ -2724,7 +2786,7 @@ constant c0 : arr_t := (others => 0); assert_eq!( test.name_resolve(&code, None, &mut diagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().character() + test.ctx(&code.tokenize()).character() ))) ); check_diagnostics( @@ -2740,7 +2802,7 @@ constant c0 : arr_t := (others => 0); assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().character() + test.ctx(&code.tokenize()).character() ))) ); @@ -2748,7 +2810,7 @@ constant c0 : arr_t := (others => 0); assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().character() + test.ctx(&code.tokenize()).character() ))) ); @@ -2756,7 +2818,7 @@ constant c0 : arr_t := (others => 0); assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().character() + test.ctx(&code.tokenize()).character() ))) ); @@ -2764,7 +2826,7 @@ constant c0 : arr_t := (others => 0); assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().character() + test.ctx(&code.tokenize()).character() ))) ); } @@ -2833,7 +2895,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().integer() + test.ctx(&code.tokenize()).integer() ))) ); @@ -2841,7 +2903,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().integer() + test.ctx(&code.tokenize()).integer() ))) ); @@ -2849,7 +2911,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().boolean() + test.ctx(&code.tokenize()).boolean() ))) ); @@ -2857,7 +2919,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().boolean() + test.ctx(&code.tokenize()).boolean() ))) ); @@ -2865,7 +2927,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().bit() + test.ctx(&code.tokenize()).bit() ))) ); @@ -2873,7 +2935,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().boolean() + test.ctx(&code.tokenize()).boolean() ))) ); @@ -2881,7 +2943,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().boolean() + test.ctx(&code.tokenize()).boolean() ))) ); @@ -2889,7 +2951,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().time() + test.ctx(&code.tokenize()).time() ))) ); @@ -2897,7 +2959,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().time() + test.ctx(&code.tokenize()).time() ))) ); @@ -2905,7 +2967,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().integer() + test.ctx(&code.tokenize()).integer() ))) ); @@ -2913,7 +2975,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().boolean() + test.ctx(&code.tokenize()).boolean() ))) ); @@ -2921,7 +2983,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().integer() + test.ctx(&code.tokenize()).integer() ))) ); } @@ -2987,21 +3049,21 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().string() + test.ctx(&code.tokenize()).string() ))) ); let code = test.snippet("thesig'instance_name"); assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().string() + test.ctx(&code.tokenize()).string() ))) ); let code = test.snippet("thesig'path_name"); assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().string() + test.ctx(&code.tokenize()).string() ))) ); } @@ -3013,7 +3075,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().integer() + test.ctx(&code.tokenize()).integer() ))) ); @@ -3021,7 +3083,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().real() + test.ctx(&code.tokenize()).real() ))) ); } @@ -3034,7 +3096,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut diagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().integer() + test.ctx(&code.tokenize()).integer() ))) ); check_diagnostics( @@ -3051,7 +3113,7 @@ signal thesig : integer; assert_eq!( test.name_resolve(&code, None, &mut diagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( - test.ctx().real() + test.ctx(&code.tokenize()).real() ))) ); @@ -3180,9 +3242,12 @@ type enum_t is (alpha, beta); assert_eq!( test.name_resolve(&code, None, &mut NoDiagnostics), Ok(ResolvedName::Expression(DisambiguatedType::Ambiguous( - vec![test.ctx().real().base(), test.ctx().integer().base()] - .into_iter() - .collect() + vec![ + test.ctx(&code.tokenize()).real().base(), + test.ctx(&code.tokenize()).integer().base() + ] + .into_iter() + .collect() ))) ); } @@ -3201,9 +3266,15 @@ type enum_t is (alpha, beta); let code = test.snippet("myfun(f1)"); let mut diagnostics = Vec::new(); assert_eq!( - test.name_resolve(&code, Some(test.ctx().integer()), &mut diagnostics), + test.name_resolve( + &code, + Some(test.ctx(&code.tokenize()).integer()), + &mut diagnostics + ), Ok(ResolvedName::Expression(DisambiguatedType::Ambiguous( - vec![test.ctx().integer().base()].into_iter().collect() + vec![test.ctx(&code.tokenize()).integer().base()] + .into_iter() + .collect() ))) ); check_diagnostics( diff --git a/vhdl_lang/src/analysis/overloaded.rs b/vhdl_lang/src/analysis/overloaded.rs index 0e400eff..7674e2a8 100644 --- a/vhdl_lang/src/analysis/overloaded.rs +++ b/vhdl_lang/src/analysis/overloaded.rs @@ -5,11 +5,13 @@ // Copyright (c) 2023, Olof Kraigher olof.kraigher@gmail.com use fnv::FnvHashSet; +use vhdl_lang::TokenAccess; use super::analyze::*; use super::expression::ExpressionType; use super::scope::*; use crate::ast::search::clear_references; +use crate::ast::token_range::WithToken; use crate::ast::*; use crate::data::error_codes::ErrorCode; use crate::data::*; @@ -80,7 +82,8 @@ impl<'a> Candidates<'a> { fn finish( self, - name: &WithPos, + ctx: &dyn TokenAccess, + name: &WithToken, ttyp: Option>, ) -> Result, Diagnostic> { let (remaining, mut rejected) = self.split(); @@ -98,7 +101,7 @@ impl<'a> Candidates<'a> { // Special case to get better error for single rejected enumeration literal // For example when assigning true to an integer. return Err(Diagnostic::new( - name, + name.pos(ctx), format!("'{}' does not match {}", name, ttyp.describe()), ErrorCode::TypeMismatch, )); @@ -113,7 +116,7 @@ impl<'a> Candidates<'a> { ("Could not resolve", ErrorCode::Unresolved) }; - let mut diag = Diagnostic::new(name, format!("{err_prefix} '{name}'"), code); + let mut diag = Diagnostic::new(name.pos(ctx), format!("{err_prefix} '{name}'"), code); rejected.sort_by(|x, y| x.ent.decl_pos().cmp(&y.ent.decl_pos())); @@ -183,7 +186,7 @@ impl<'a> AsRef> for ResolvedCall<'a> { } } -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { /// Typecheck one overloaded call where the exact subprogram is known pub fn check_call( &self, @@ -246,7 +249,7 @@ impl<'a> AnalyzeContext<'a> { match &mut assoc.actual.item { ActualPart::Expression(expr) => { let actual_type = - self.expr_pos_type(scope, &assoc.actual.pos, expr, diagnostics)?; + self.expr_pos_type(scope, assoc.actual.span, expr, diagnostics)?; actual_types.push(Some(actual_type)); } ActualPart::Open => { @@ -262,8 +265,8 @@ impl<'a> AnalyzeContext<'a> { pub fn disambiguate( &self, scope: &Scope<'a>, - call_pos: &SrcPos, // The position of the entire call - call_name: &WithPos, // The position and name of the subprogram name in the call + call_pos: &SrcPos, // The position of the entire call + call_name: &WithToken, // The position and name of the subprogram name in the call assocs: &mut [AssociationElement], kind: SubprogramKind<'a>, all_overloaded: Vec>, @@ -284,7 +287,7 @@ impl<'a> AnalyzeContext<'a> { self.check_call(scope, call_pos, ent, assocs, diagnostics)?; return Ok(Disambiguated::Unambiguous(ent)); } else if ok_kind.is_empty() { - diagnostics.push(Diagnostic::ambiguous(call_name, all_overloaded)); + diagnostics.push(Diagnostic::ambiguous(self.ctx, call_name, all_overloaded)); return Err(EvalError::Unknown); } @@ -297,7 +300,7 @@ impl<'a> AnalyzeContext<'a> { return Ok(Disambiguated::Unambiguous(ent)); } else if ok_kind.is_empty() { diagnostics.add( - call_name, + call_name.pos(self.ctx), format!("uninstantiated subprogram {} cannot be called", call_name), ErrorCode::InvalidCall, ); @@ -313,7 +316,7 @@ impl<'a> AnalyzeContext<'a> { return Ok(Disambiguated::Unambiguous(ent)); } else if ok_formals.is_empty() { // No candidate matched actual/formal profile - diagnostics.push(Diagnostic::ambiguous(call_name, ok_kind)); + diagnostics.push(Diagnostic::ambiguous(self.ctx, call_name, ok_kind)); return Err(EvalError::Unknown); } @@ -329,6 +332,7 @@ impl<'a> AnalyzeContext<'a> { return Ok(Disambiguated::Unambiguous(ent)); } else if ok_assoc_types.is_empty() { diagnostics.push(Diagnostic::ambiguous( + self.ctx, call_name, ok_formals.into_iter().map(|resolved| resolved.subpgm), )); @@ -347,6 +351,7 @@ impl<'a> AnalyzeContext<'a> { return Ok(Disambiguated::Unambiguous(ent)); } else if ok_return_type.is_empty() { diagnostics.push(Diagnostic::ambiguous( + self.ctx, call_name, ok_assoc_types.into_iter().map(|resolved| resolved.subpgm), )); @@ -380,7 +385,7 @@ impl<'a> AnalyzeContext<'a> { pub fn disambiguate_no_actuals( &self, - name: &WithPos, + name: &WithToken, ttyp: Option>, overloaded: &OverloadedName<'a>, ) -> Result>, Diagnostic> { @@ -404,18 +409,19 @@ impl<'a> AnalyzeContext<'a> { } } - Ok(Some(candidates.finish(name, ttyp)?)) + Ok(Some(candidates.finish(self.ctx, name, ttyp)?)) } } impl Diagnostic { fn ambiguous<'a>( - name: &WithPos, + ctx: &dyn TokenAccess, + name: &WithToken, rejected: impl IntoIterator>, ) -> Self { let mut diag = Diagnostic::new( - &name.pos, - format!("Could not resolve call to '{}'", name.designator()), + name.pos(ctx), + format!("Could not resolve call to '{}'", name.item.designator()), ErrorCode::AmbiguousCall, ); diag.add_subprogram_candidates("Does not match", rejected); @@ -442,22 +448,24 @@ mod tests { let mut fcall = code.function_call(); let des = if let Name::Designator(des) = &fcall.item.name.item { - WithPos::new(des.item.clone(), fcall.item.name.pos.clone()) + WithToken::new(des.item.clone(), fcall.span.start_token) } else { panic!("Expected designator") }; - let overloaded = if let NamedEntities::Overloaded(overloaded) = - self.scope.lookup(&fcall.item.name.pos, &des.item).unwrap() + let overloaded = if let NamedEntities::Overloaded(overloaded) = self + .scope + .lookup(&self.tokens, fcall.span, &des.item) + .unwrap() { overloaded } else { panic!("Expected overloaded") }; - as_fatal(self.ctx().disambiguate( + as_fatal(self.ctx(&code.tokenize()).disambiguate( &self.scope, - &fcall.pos, + &fcall.pos(&code.tokenize()), &des, &mut fcall.item.parameters, overloaded::SubprogramKind::Function(ttyp), @@ -735,7 +743,7 @@ function myfun(arg1 : integer) return character; let code = test.snippet("to_string(0)"); let uint_to_string = test - .ctx() + .ctx(&code.tokenize()) .universal_integer() .lookup_implicit_of("TO_STRING"); @@ -750,7 +758,10 @@ function myfun(arg1 : integer) return character; let test = TestSetup::new(); let code = test.snippet("minimum(0, integer'(0))"); - let minimum = test.ctx().integer().lookup_implicit_of("MINIMUM"); + let minimum = test + .ctx(&code.tokenize()) + .integer() + .lookup_implicit_of("MINIMUM"); assert_eq!( test.disambiguate(&code, None, &mut NoDiagnostics), diff --git a/vhdl_lang/src/analysis/package_instance.rs b/vhdl_lang/src/analysis/package_instance.rs index efbed60c..1422aa9c 100644 --- a/vhdl_lang/src/analysis/package_instance.rs +++ b/vhdl_lang/src/analysis/package_instance.rs @@ -23,7 +23,7 @@ use crate::named_entity::*; use crate::Diagnostic; use crate::NullDiagnostics; -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { pub fn generic_package_instance( &self, scope: &Scope<'a>, @@ -42,7 +42,7 @@ impl<'a> AnalyzeContext<'a> { self.generic_instance( package_ent, scope, - &unit.ident.tree.pos, + unit.ident.tree.pos(self.ctx), &package_region, generic_map, diagnostics, @@ -62,8 +62,9 @@ impl<'a> AnalyzeContext<'a> { // @TODO check missing associations for (idx, assoc) in generic_map.iter_mut().enumerate() { let formal = if let Some(formal) = &mut assoc.formal { + let formal_pos = formal.pos(self.ctx); if let Name::Designator(des) = &mut formal.item { - match generics.lookup(&formal.pos, &des.item) { + match generics.lookup(&formal_pos, &des.item) { Ok((_, ent)) => { des.set_unique_reference(&ent); ent @@ -75,7 +76,7 @@ impl<'a> AnalyzeContext<'a> { } } else { diagnostics.add( - &formal.pos, + &formal.pos(self.ctx), "Expected simple name for package generic formal", ErrorCode::MismatchedKinds, ); @@ -85,7 +86,7 @@ impl<'a> AnalyzeContext<'a> { ent } else { diagnostics.add( - &assoc.actual.pos, + &assoc.actual.pos(self.ctx), "Extra actual for generic map", ErrorCode::TooManyArguments, ); @@ -102,7 +103,7 @@ impl<'a> AnalyzeContext<'a> { Name::Slice(prefix, drange) => { let typ = self.type_name( scope, - &prefix.pos, + prefix.span, &mut prefix.item, diagnostics, )?; @@ -117,7 +118,7 @@ impl<'a> AnalyzeContext<'a> { } } else { diagnostics.add( - &assoc.actual.pos, + &assoc.actual.pos(self.ctx), format!( "Array constraint cannot be used for {}", typ.describe() @@ -132,15 +133,15 @@ impl<'a> AnalyzeContext<'a> { Name::CallOrIndexed(call) if call.could_be_indexed_name() => self .type_name( scope, - &call.name.pos, + call.name.span, &mut call.name.item, diagnostics, )?, - _ => self.type_name(scope, &assoc.actual.pos, name, diagnostics)?, + _ => self.type_name(scope, assoc.actual.span, name, diagnostics)?, } } else { diagnostics.add( - &assoc.actual.pos, + &assoc.actual.pos(self.ctx), "Cannot map expression to type generic", ErrorCode::MismatchedKinds, ); @@ -152,14 +153,14 @@ impl<'a> AnalyzeContext<'a> { GpkgInterfaceEnt::Constant(obj) => self.expr_pos_with_ttyp( scope, self.map_type_ent(&mapping, obj.type_mark()), - &assoc.actual.pos, + assoc.actual.span, expr, diagnostics, )?, GpkgInterfaceEnt::Subprogram(target) => match expr { Expression::Name(name) => { let resolved = - self.name_resolve(scope, &assoc.actual.pos, name, diagnostics)?; + self.name_resolve(scope, assoc.actual.span, name, diagnostics)?; if let ResolvedName::Overloaded(des, overloaded) = resolved { let signature = target.subprogram_key().map(|base_type| { mapping @@ -171,7 +172,7 @@ impl<'a> AnalyzeContext<'a> { name.set_unique_reference(&ent); } else { let mut diag = Diagnostic::new( - &assoc.actual.pos, + &assoc.actual.pos(self.ctx), format!( "Cannot map '{}' to subprogram generic {}{}", des, @@ -190,7 +191,7 @@ impl<'a> AnalyzeContext<'a> { } } else { diagnostics.add( - &assoc.actual.pos, + &assoc.actual.pos(self.ctx), format!( "Cannot map {} to subprogram generic", resolved.describe() @@ -202,24 +203,24 @@ impl<'a> AnalyzeContext<'a> { Expression::Literal(Literal::String(string)) => { if Operator::from_latin1(string.clone()).is_none() { diagnostics.add( - &assoc.actual.pos, + &assoc.actual.pos(self.ctx), "Invalid operator symbol", ErrorCode::InvalidOperatorSymbol, ); } } _ => diagnostics.add( - &assoc.actual.pos, + &assoc.actual.pos(self.ctx), "Cannot map expression to subprogram generic", ErrorCode::MismatchedKinds, ), }, GpkgInterfaceEnt::Package(_) => match expr { Expression::Name(name) => { - self.name_resolve(scope, &assoc.actual.pos, name, diagnostics)?; + self.name_resolve(scope, assoc.actual.span, name, diagnostics)?; } _ => diagnostics.add( - &assoc.actual.pos, + &assoc.actual.pos(self.ctx), "Cannot map expression to package generic", ErrorCode::MismatchedKinds, ), diff --git a/vhdl_lang/src/analysis/range.rs b/vhdl_lang/src/analysis/range.rs index 121af377..2741d28a 100644 --- a/vhdl_lang/src/analysis/range.rs +++ b/vhdl_lang/src/analysis/range.rs @@ -11,13 +11,14 @@ use super::names::ResolvedName; use super::overloaded::Disambiguated; use super::overloaded::DisambiguatedType; use super::scope::*; +use crate::ast::token_range::WithTokenSpan; use crate::ast::Range; use crate::ast::*; use crate::data::error_codes::ErrorCode; use crate::data::*; use crate::named_entity::*; -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { pub fn range_unknown_typ( &self, scope: &Scope<'a>, @@ -41,7 +42,7 @@ impl<'a> AnalyzeContext<'a> { fn range_expr_type( &self, scope: &Scope<'a>, - expr: &mut WithPos, + expr: &mut WithTokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { match self.expr_type(scope, expr, diagnostics)? { @@ -50,7 +51,7 @@ impl<'a> AnalyzeContext<'a> { Ok(DisambiguatedType::Unambiguous(typ)) } else { diagnostics.add( - &expr.pos, + &expr.pos(self.ctx), format!("Non-scalar {} cannot be used in a range", typ.describe()), ErrorCode::NonScalarInRange, ); @@ -62,7 +63,7 @@ impl<'a> AnalyzeContext<'a> { )), ExpressionType::String | ExpressionType::Null | ExpressionType::Aggregate => { diagnostics.add( - &expr.pos, + &expr.pos(self.ctx), "Non-scalar expression cannot be used in a range", ErrorCode::NonScalarInRange, ); @@ -78,7 +79,7 @@ impl<'a> AnalyzeContext<'a> { diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { let resolved = - self.name_resolve(scope, &attr.name.pos, &mut attr.name.item, diagnostics)?; + self.name_resolve(scope, attr.name.span, &mut attr.name.item, diagnostics)?; let typ = match resolved { ResolvedName::Type(typ) => typ, ResolvedName::ObjectName(oname) => oname.type_mark(), @@ -93,8 +94,8 @@ impl<'a> AnalyzeContext<'a> { ent.return_type().unwrap() } else { diagnostics.add( - &attr.name.pos, - format!( + &attr.name.pos(self.ctx), + format!( "{} cannot be prefix of range attribute, array type or object is required", resolved.describe() ), @@ -112,7 +113,7 @@ impl<'a> AnalyzeContext<'a> { | ResolvedName::Library(_) | ResolvedName::Design(_) => { diagnostics.add( - &attr.name.pos, + &attr.name.pos(self.ctx), format!( "{} cannot be prefix of range attribute, array type or object is required", resolved.describe() @@ -136,14 +137,14 @@ impl<'a> AnalyzeContext<'a> { if let Some(decl_pos) = typ.decl_pos() { // To debug if it ever happens eprintln!("{}", decl_pos.show("Array with no indexes")); - eprintln!("{}", attr.name.pos.show("Used here")); + eprintln!("{}", attr.name.pos(self.ctx).show("Used here")); panic!("Internal error") } Err(EvalError::Unknown) } } else { diagnostics.add( - &attr.name.pos, + &attr.name.pos(self.ctx), format!( "{} cannot be prefix of range attribute, array type or object is required", resolved.describe() @@ -176,7 +177,7 @@ impl<'a> AnalyzeContext<'a> { return Ok(typ); } else { diagnostics.add( - constraint.pos(), + constraint.span().pos(self.ctx), format!( "Range type mismatch, left is {}, right is {}", l.base().describe(), @@ -196,7 +197,7 @@ impl<'a> AnalyzeContext<'a> { } (DisambiguatedType::Ambiguous(_), DisambiguatedType::Ambiguous(_)) => { diagnostics.add( - constraint.pos(), + constraint.span().pos(self.ctx), "Range is ambiguous", ErrorCode::TypeMismatch, ); @@ -228,14 +229,14 @@ impl<'a> AnalyzeContext<'a> { Ok(typ) } else if types.is_empty() { diagnostics.add( - constraint.pos(), + constraint.span().pos(self.ctx), "Range type of left and right side does not match", ErrorCode::TypeMismatch, ); Err(EvalError::Unknown) } else { diagnostics.add( - constraint.pos(), + constraint.span().pos(self.ctx), "Range is ambiguous", ErrorCode::TypeMismatch, ); @@ -269,7 +270,7 @@ impl<'a> AnalyzeContext<'a> { Ok(typ) } else { diagnostics.add( - &drange.pos(), + &drange.span().pos(self.ctx), format!( "Non-discrete {} cannot be used in discrete range", typ.describe() @@ -292,14 +293,14 @@ impl<'a> AnalyzeContext<'a> { self.expr_pos_with_ttyp( scope, target_type, - &constraint.left_expr.pos, + constraint.left_expr.span, &mut constraint.left_expr.item, diagnostics, )?; self.expr_pos_with_ttyp( scope, target_type, - &constraint.right_expr.pos, + constraint.right_expr.span, &mut constraint.right_expr.item, diagnostics, )?; @@ -313,10 +314,11 @@ impl<'a> AnalyzeContext<'a> { } = name.as_mut(); let prefix_typ = as_fatal( - self.name_resolve(scope, &name.pos, &mut name.item, diagnostics) + self.name_resolve(scope, name.span, &mut name.item, diagnostics) .and_then(|prefix| { prefix.as_type_of_attr_prefix( - &name.pos, + self.ctx, + name.span, &AttributeSuffix { signature, attr, @@ -329,7 +331,7 @@ impl<'a> AnalyzeContext<'a> { if let Some(ref mut signature) = signature { diagnostics.add( - &signature.pos, + &signature.pos(self.ctx), format!("Did not expect signature for '{attr} attribute"), ErrorCode::UnexpectedSignature, ); @@ -346,7 +348,7 @@ impl<'a> AnalyzeContext<'a> { { if !self.can_be_target_type(index_typ.into(), target_type.base()) { diagnostics.push(Diagnostic::type_mismatch( - &range.pos(), + &range.span().pos(self.ctx), &index_typ.describe(), target_type, )) @@ -395,6 +397,7 @@ mod tests { use crate::syntax::test::check_diagnostics; use crate::syntax::test::Code; use crate::Diagnostic; + use vhdl_lang::Token; impl<'a> TestSetup<'a> { fn range_type( @@ -402,16 +405,17 @@ mod tests { code: &Code, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { - self.ctx() + self.ctx(&code.tokenize()) .range_type(&self.scope, &mut code.range(), diagnostics) } fn range_type_ast( &'a self, rng: &mut Range, + tokens: &Vec, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { - self.ctx().range_type(&self.scope, rng, diagnostics) + self.ctx(tokens).range_type(&self.scope, rng, diagnostics) } } @@ -422,7 +426,7 @@ mod tests { let code = test.snippet("0 to 1"); assert_eq!( test.range_type(&code, &mut NoDiagnostics), - Ok(test.ctx().universal_integer()) + Ok(test.ctx(&code.tokenize()).universal_integer()) ); } @@ -433,7 +437,7 @@ mod tests { let code = test.snippet("-1 to 1"); assert_eq!( test.range_type(&code, &mut NoDiagnostics), - Ok(test.ctx().universal_integer()) + Ok(test.ctx(&code.tokenize()).universal_integer()) ); } @@ -454,8 +458,11 @@ mod tests { let code = test.snippet("0.0 to 1.0"); let mut diagnostics = Vec::new(); assert_eq!( - test.ctx() - .drange_type(&test.scope, &mut code.discrete_range(), &mut diagnostics), + test.ctx(&code.tokenize()).drange_type( + &test.scope, + &mut code.discrete_range(), + &mut diagnostics + ), Err(EvalError::Unknown) ); @@ -503,18 +510,18 @@ function f1 return integer; let code = test.snippet("f1 to 'a'"); let mut rng = code.range(); assert_eq!( - test.range_type_ast(&mut rng, &mut NoDiagnostics), + test.range_type_ast(&mut rng, &code.tokenize(), &mut NoDiagnostics), Ok(test.lookup_type("CHARACTER").base()) ); - check_no_unresolved(&mut rng); + check_no_unresolved(&mut rng, &code.tokenize()); let code = test.snippet("'a' to f1"); let mut rng = code.range(); assert_eq!( - test.range_type_ast(&mut rng, &mut NoDiagnostics), + test.range_type_ast(&mut rng, &code.tokenize(), &mut NoDiagnostics), Ok(test.lookup_type("CHARACTER").base()) ); - check_no_unresolved(&mut rng); + check_no_unresolved(&mut rng, &code.tokenize()); } #[test] diff --git a/vhdl_lang/src/analysis/root.rs b/vhdl_lang/src/analysis/root.rs index 68bf51b4..a90ef855 100644 --- a/vhdl_lang/src/analysis/root.rs +++ b/vhdl_lang/src/analysis/root.rs @@ -42,6 +42,12 @@ pub(crate) struct LockedUnit { pub tokens: Vec, } +impl HasSrcPos for LockedUnit { + fn pos(&self) -> &SrcPos { + self.ident.pos(&self.tokens) + } +} + impl HasUnitId for LockedUnit { fn unit_id(&self) -> &UnitId { &self.unit_id @@ -136,7 +142,7 @@ impl Library { match self.units.entry(unit.key().clone()) { Entry::Occupied(entry) => { self.duplicates - .push((entry.get().ident().pos.clone(), unit)); + .push((entry.get().ident().pos(&entry.get().tokens).clone(), unit)); } Entry::Vacant(entry) => { self.added.insert(unit_id); @@ -168,9 +174,10 @@ impl Library { fn append_duplicate_diagnostics(&self, diagnostics: &mut dyn DiagnosticHandler) { for (prev_pos, unit) in self.duplicates.iter() { + let tokens = &unit.tokens; let diagnostic = match unit.key() { UnitKey::Primary(ref primary_name) => Diagnostic::new( - unit.pos(), + unit.ident_pos(tokens), format!( "A primary unit has already been declared with name '{}' in library '{}'", primary_name, &self.name @@ -179,12 +186,12 @@ impl Library { ), UnitKey::Secondary(ref primary_name, ref name) => match unit.kind() { AnyKind::Secondary(SecondaryKind::Architecture) => Diagnostic::new( - unit.ident(), + unit.ident_pos(tokens), format!("Duplicate architecture '{name}' of entity '{primary_name}'",), ErrorCode::Duplicate, ), AnyKind::Secondary(SecondaryKind::PackageBody) => Diagnostic::new( - unit.pos(), + unit.ident_pos(tokens), format!("Duplicate package body of package '{primary_name}'"), ErrorCode::Duplicate, ), @@ -236,15 +243,7 @@ impl Library { for unit_ids in self.units_by_source.values() { let mut unit_ids: Vec = unit_ids.clone().into_iter().collect(); - unit_ids.sort_by_key(|unit_id| { - self.units - .get(unit_id.key()) - .unwrap() - .ident() - .pos - .range() - .start - }); + unit_ids.sort_by_key(|unit_id| self.units.get(unit_id.key()).unwrap().pos().start()); result.append(&mut unit_ids); } result @@ -1006,7 +1005,7 @@ impl DesignRoot { std_lib, // Will be overwritten below AnyEntKind::Design(Design::Package(Visibility::default(), Region::default())), - Some(std_package.ident.pos()), + Some(std_package.ident_pos(&locked_unit.tokens)), None, ) }; @@ -1018,6 +1017,7 @@ impl DesignRoot { // Reserve space in the arena for the standard types self.standard_types = Some(StandardTypes::new( + &locked_unit.tokens, &arena, standard_pkg, &mut std_package.decl, diff --git a/vhdl_lang/src/analysis/scope.rs b/vhdl_lang/src/analysis/scope.rs index cee81ded..3abf6ef4 100644 --- a/vhdl_lang/src/analysis/scope.rs +++ b/vhdl_lang/src/analysis/scope.rs @@ -9,6 +9,7 @@ use crate::data::*; use crate::named_entity::*; use crate::data::error_codes::ErrorCode; +use crate::{TokenAccess, TokenSpan}; use fnv::FnvHashMap; use std::cell::RefCell; use std::collections::hash_map::Entry; @@ -121,19 +122,21 @@ impl<'a> ScopeInner<'a> { /// Lookup a named entity that was made potentially visible via a use clause fn lookup_visible( &self, - pos: &SrcPos, + ctx: &dyn TokenAccess, + span: TokenSpan, designator: &Designator, ) -> Result>, Diagnostic> { let mut visible = Visible::default(); self.lookup_visiblity_into(designator, &mut visible); - visible.into_unambiguous(pos, designator) + visible.into_unambiguous(ctx, span, designator) } /// Lookup a designator from within the region itself /// Thus all parent regions and visibility is relevant fn lookup_uncached( &self, - pos: &SrcPos, + ctx: &dyn TokenAccess, + span: TokenSpan, designator: &Designator, ) -> Result, Diagnostic> { let result = if let Some(enclosing) = self.lookup_enclosing(designator) { @@ -143,7 +146,7 @@ impl<'a> ScopeInner<'a> { // In case of overloaded local, non-conflicting visible names are still relevant NamedEntities::Overloaded(enclosing_overloaded) => { if let Ok(Some(NamedEntities::Overloaded(overloaded))) = - self.lookup_visible(pos, designator) + self.lookup_visible(ctx, span, designator) { Some(NamedEntities::Overloaded( enclosing_overloaded.with_visible(overloaded), @@ -154,13 +157,13 @@ impl<'a> ScopeInner<'a> { } } } else { - self.lookup_visible(pos, designator)? + self.lookup_visible(ctx, span, designator)? }; match result { Some(visible) => Ok(visible), None => Err(Diagnostic::new( - pos, + span.pos(ctx), match designator { Designator::Identifier(ident) => { format!("No declaration of '{ident}'") @@ -180,14 +183,15 @@ impl<'a> ScopeInner<'a> { fn lookup( &mut self, - pos: &SrcPos, + ctx: &dyn TokenAccess, + span: TokenSpan, designator: &Designator, ) -> Result, Diagnostic> { if let Some(res) = self.cache.get(designator) { return Ok(res.clone()); } - let ents = self.lookup_uncached(pos, designator)?; + let ents = self.lookup_uncached(ctx, span, designator)?; if let Entry::Vacant(vacant) = self.cache.entry(designator.clone()) { Ok(vacant.insert(ents).clone()) } else { @@ -318,10 +322,14 @@ impl<'a> Scope<'a> { pub fn lookup( &self, - pos: &SrcPos, + ctx: &dyn TokenAccess, + span: impl Into, designator: &Designator, ) -> Result, Diagnostic> { - self.0.as_ref().borrow_mut().lookup(pos, designator) + self.0 + .as_ref() + .borrow_mut() + .lookup(ctx, span.into(), designator) } /// Used when using context clauses diff --git a/vhdl_lang/src/analysis/semantic.rs b/vhdl_lang/src/analysis/semantic.rs index 8133290c..37fd1438 100644 --- a/vhdl_lang/src/analysis/semantic.rs +++ b/vhdl_lang/src/analysis/semantic.rs @@ -8,34 +8,35 @@ use super::names::ResolvedName; use super::overloaded::Disambiguated; use super::overloaded::SubprogramKind; use super::scope::*; +use crate::ast::token_range::WithTokenSpan; use crate::ast::*; use crate::data::error_codes::ErrorCode; use crate::data::*; use crate::named_entity::*; -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { pub fn resolve_type_mark( &self, scope: &Scope<'a>, - type_mark: &mut WithPos, + type_mark: &mut WithTokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { let name = self.name_resolve( scope, - &type_mark.item.name.pos, + type_mark.item.name.span, &mut type_mark.item.name.item, diagnostics, )?; if let Some(attr) = &type_mark.item.attr { - let pos = type_mark.item.name.suffix_pos(); + let span = type_mark.item.name.suffix_pos(); let typ = match name { ResolvedName::Type(typ) if *attr == TypeAttribute::Element => typ, ResolvedName::ObjectName(obj) => obj.type_mark(), other => { let mut diag = Diagnostic::new( - type_mark, + type_mark.pos(self.ctx), format!("Expected type, got {}", other.describe()), ErrorCode::MismatchedKinds, ); @@ -54,7 +55,7 @@ impl<'a> AnalyzeContext<'a> { Ok(elem_type) } else { diagnostics.add( - pos, + span.pos(self.ctx), format!("array type expected for '{attr} attribute",), ErrorCode::TypeMismatch, ); @@ -67,7 +68,7 @@ impl<'a> AnalyzeContext<'a> { ResolvedName::Type(typ) => Ok(typ), other => { let mut diag = Diagnostic::new( - type_mark, + type_mark.pos(self.ctx), format!("Expected type, got {}", other.describe()), ErrorCode::MismatchedKinds, ); @@ -85,16 +86,16 @@ impl<'a> AnalyzeContext<'a> { &self, scope: &Scope<'a>, ttyp: Option>, - choices: &mut [WithPos], + choices: &mut [WithTokenSpan], diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { for choice in choices.iter_mut() { match choice.item { Choice::Expression(ref mut expr) => { if let Some(ttyp) = ttyp { - self.expr_pos_with_ttyp(scope, ttyp, &choice.pos, expr, diagnostics)?; + self.expr_pos_with_ttyp(scope, ttyp, choice.span, expr, diagnostics)?; } else { - self.expr_pos_unknown_ttyp(scope, &choice.pos, expr, diagnostics)?; + self.expr_pos_unknown_ttyp(scope, choice.span, expr, diagnostics)?; } } Choice::DiscreteRange(ref mut drange) => { @@ -119,7 +120,7 @@ impl<'a> AnalyzeContext<'a> { for AssociationElement { actual, .. } in elems.iter_mut() { match actual.item { ActualPart::Expression(ref mut expr) => { - self.expr_pos_unknown_ttyp(scope, &actual.pos, expr, diagnostics)?; + self.expr_pos_unknown_ttyp(scope, actual.span, expr, diagnostics)?; } ActualPart::Open => {} } @@ -130,13 +131,14 @@ impl<'a> AnalyzeContext<'a> { pub fn analyze_procedure_call( &self, scope: &Scope<'a>, - fcall: &mut WithPos, + fcall: &mut WithTokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { + let fcall_span = fcall.span; let CallOrIndexed { name, parameters } = &mut fcall.item; let resolved = - match as_fatal(self.name_resolve(scope, &name.pos, &mut name.item, diagnostics))? { + match as_fatal(self.name_resolve(scope, name.span, &mut name.item, diagnostics))? { Some(resolved) => resolved, None => { // Continue checking missing names even if procedure is not found @@ -149,7 +151,7 @@ impl<'a> AnalyzeContext<'a> { ResolvedName::Overloaded(ref des, names) => { match as_fatal(self.disambiguate( scope, - &fcall.pos, + &fcall_span.pos(self.ctx), des, parameters, SubprogramKind::Procedure, @@ -157,14 +159,14 @@ impl<'a> AnalyzeContext<'a> { diagnostics, ))? { Some(Disambiguated::Ambiguous(candidates)) => { - diagnostics.push(Diagnostic::ambiguous_call(des, candidates)) + diagnostics.push(Diagnostic::ambiguous_call(self.ctx, des, candidates)) } Some(Disambiguated::Unambiguous(ent)) => { name.set_unique_reference(&ent); if !ent.is_procedure() { let mut diagnostic = Diagnostic::new( - &name.pos, + &name.pos(self.ctx), "Invalid procedure call", ErrorCode::InvalidCall, ); @@ -179,7 +181,7 @@ impl<'a> AnalyzeContext<'a> { diagnostics.push(diagnostic); } else if ent.is_uninst_subprogram_body() { diagnostics.add( - &name.pos, + &name.pos(self.ctx), format!("uninstantiated {} cannot be called", ent.describe()), ErrorCode::InvalidCall, ) @@ -193,14 +195,14 @@ impl<'a> AnalyzeContext<'a> { name.set_unique_reference(ent); let (generic_region, port_region) = region.to_entity_formal(); self.check_association( - &fcall.item.name.pos, + &fcall.item.name.pos(self.ctx), &generic_region, scope, &mut [], diagnostics, )?; self.check_association( - &fcall.item.name.pos, + &fcall.item.name.pos(self.ctx), &port_region, scope, &mut [], @@ -208,7 +210,7 @@ impl<'a> AnalyzeContext<'a> { )?; } else { diagnostics.add( - &name.pos, + &name.pos(self.ctx), format!("{} is not a procedure", resolved.describe_type()), ErrorCode::MismatchedKinds, ); @@ -217,7 +219,7 @@ impl<'a> AnalyzeContext<'a> { } resolved => { diagnostics.add( - &name.pos, + &name.pos(self.ctx), format!("{} is not a procedure", resolved.describe_type()), ErrorCode::MismatchedKinds, ); diff --git a/vhdl_lang/src/analysis/sequential.rs b/vhdl_lang/src/analysis/sequential.rs index 14998efa..058a28f5 100644 --- a/vhdl_lang/src/analysis/sequential.rs +++ b/vhdl_lang/src/analysis/sequential.rs @@ -12,7 +12,7 @@ use crate::named_entity::*; use analyze::*; use target::AssignmentType; -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { pub fn define_labels_for_sequential_part( &self, scope: &Scope<'a>, @@ -26,7 +26,7 @@ impl<'a> AnalyzeContext<'a> { label.name(), parent, AnyEntKind::Sequential(statement.statement.item.label_typ()), - Some(label.pos()), + Some(label.pos(self.ctx)), None, ); statement.label.decl.set(ent.id()); @@ -107,6 +107,7 @@ impl<'a> AnalyzeContext<'a> { statement: &mut LabeledSequentialStatement, diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { + let statement_span = statement.statement.span; match statement.statement.item { SequentialStatement::Return(ref mut ret) => { let ReturnStatement { ref mut expression } = ret; @@ -117,7 +118,7 @@ impl<'a> AnalyzeContext<'a> { self.expr_with_ttyp(scope, ttyp, expression, diagnostics)?; } else { diagnostics.add( - &statement.statement.pos, + &statement.statement.pos(self.ctx), "Functions cannot return without a value", ErrorCode::VoidReturn, ); @@ -126,7 +127,7 @@ impl<'a> AnalyzeContext<'a> { SequentialRoot::Procedure => { if expression.is_some() { diagnostics.add( - &statement.statement.pos, + &statement.statement.pos(self.ctx), "Procedures cannot return a value", ErrorCode::NonVoidReturn, ); @@ -134,7 +135,7 @@ impl<'a> AnalyzeContext<'a> { } SequentialRoot::Process => { diagnostics.add( - &statement.statement.pos, + &statement.statement.pos(self.ctx), "Cannot return from a process", ErrorCode::IllegalReturn, ); @@ -186,7 +187,7 @@ impl<'a> AnalyzeContext<'a> { self.check_loop_label(scope, parent, loop_label, diagnostics); } else if !find_outer_loop(parent, None) { diagnostics.add( - &statement.statement.pos, + &statement_span.pos(self.ctx), "Exit can only be used inside a loop", ErrorCode::ExitOutsideLoop, ) @@ -206,7 +207,7 @@ impl<'a> AnalyzeContext<'a> { self.check_loop_label(scope, parent, loop_label, diagnostics); } else if !find_outer_loop(parent, None) { diagnostics.add( - &statement.statement.pos, + &statement_span.pos(self.ctx), "Next can only be used inside a loop", ErrorCode::NextOutsideLoop, ) @@ -257,8 +258,13 @@ impl<'a> AnalyzeContext<'a> { let typ = as_fatal(self.drange_type(scope, drange, diagnostics))?; let region = scope.nested(); region.add( - self.arena - .define(index, parent, AnyEntKind::LoopParameter(typ), None), + self.arena.define( + self.ctx, + index, + parent, + AnyEntKind::LoopParameter(typ), + None, + ), diagnostics, ); self.analyze_sequential_part(®ion, parent, statements, diagnostics)?; @@ -330,7 +336,8 @@ impl<'a> AnalyzeContext<'a> { diagnostics: &mut dyn DiagnosticHandler, ) { match scope.lookup( - &label.item.pos, + self.ctx, + label.item.token, &Designator::Identifier(label.item.item.clone()), ) { Ok(NamedEntities::Single(ent)) => { @@ -338,21 +345,21 @@ impl<'a> AnalyzeContext<'a> { if matches!(ent.kind(), AnyEntKind::Sequential(Some(Sequential::Loop))) { if !find_outer_loop(parent, Some(label.item.name())) { diagnostics.add( - &label.item.pos, + label.item.pos(self.ctx), format!("Cannot be used outside of loop '{}'", ent.designator()), ErrorCode::InvalidLoopLabel, ); } } else { diagnostics.add( - &label.item.pos, + label.item.pos(self.ctx), format!("Expected loop label, got {}", ent.describe()), ErrorCode::MismatchedKinds, ); } } Ok(NamedEntities::Overloaded(_)) => diagnostics.add( - &label.item.pos, + label.item.pos(self.ctx), format!( "Expected loop label, got overloaded name {}", &label.item.item diff --git a/vhdl_lang/src/analysis/standard.rs b/vhdl_lang/src/analysis/standard.rs index 736bc788..238fa682 100644 --- a/vhdl_lang/src/analysis/standard.rs +++ b/vhdl_lang/src/analysis/standard.rs @@ -11,6 +11,7 @@ use crate::ast::ObjectClass; use crate::ast::Operator; use crate::data::DiagnosticHandler; use crate::syntax::Symbols; +use vhdl_lang::TokenAccess; use super::analyze::AnalyzeContext; use crate::named_entity::*; @@ -63,7 +64,12 @@ pub(crate) struct StandardTypes { } impl StandardTypes { - pub fn new<'a>(arena: &'a Arena, standard_pkg: EntRef<'a>, decls: &mut [Declaration]) -> Self { + pub fn new<'a>( + ctx: &dyn TokenAccess, + arena: &'a Arena, + standard_pkg: EntRef<'a>, + decls: &mut [Declaration], + ) -> Self { let mut boolean = None; let mut boolean_vector = None; let mut bit = None; @@ -87,7 +93,7 @@ impl StandardTypes { Some(standard_pkg), Related::None, AnyEntKind::Type(Type::Incomplete), - Some(type_decl.ident.tree.pos.clone()), + Some(type_decl.ident.pos(ctx).clone()), None, ) .id(); @@ -158,7 +164,7 @@ impl StandardTypes { } } -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { fn ident(&self, name: &str) -> Designator { Designator::Identifier(self.root.symbol_utf8(name)) } diff --git a/vhdl_lang/src/analysis/subprogram.rs b/vhdl_lang/src/analysis/subprogram.rs index 427eca52..3807c6bc 100644 --- a/vhdl_lang/src/analysis/subprogram.rs +++ b/vhdl_lang/src/analysis/subprogram.rs @@ -5,6 +5,7 @@ // Copyright (c) 2023, Olof Kraigher olof.kraigher@gmail.com use super::names::*; use super::*; +use crate::ast::token_range::WithTokenSpan; use crate::ast::*; use crate::data::error_codes::ErrorCode; use crate::data::*; @@ -13,7 +14,7 @@ use crate::{ast, HasTokenSpan}; use analyze::*; use itertools::Itertools; -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { fn subprogram_header( &self, scope: &Scope<'a>, @@ -51,7 +52,7 @@ impl<'a> AnalyzeContext<'a> { .into_designator(), parent, AnyEntKind::Overloaded(to_kind(Signature::new(FormalRegion::new_params(), None))), - Some(&subprogram.subpgm_designator().pos), + Some(subprogram.subpgm_designator().pos(self.ctx)), None, ); @@ -135,7 +136,7 @@ impl<'a> AnalyzeContext<'a> { pub fn resolve_signature( &self, scope: &Scope<'a>, - signature: &mut WithPos, + signature: &mut WithTokenSpan, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult { let (args, return_type) = match &mut signature.item { @@ -215,7 +216,7 @@ impl<'a> AnalyzeContext<'a> { match as_fatal(self.generic_instance( inst_subprogram_ent, scope, - &instance.ident.tree.pos, + instance.ident.tree.pos(self.ctx), region, &mut instance.generic_map, diagnostics, @@ -229,7 +230,8 @@ impl<'a> AnalyzeContext<'a> { ) { Ok(signature) => Ok(signature), Err((err, code)) => { - let mut diag = Diagnostic::new(&instance.ident.tree.pos, err, code); + let mut diag = + Diagnostic::new(instance.ident.tree.pos(self.ctx), err, code); if let Some(pos) = uninstantiated_subprogram.decl_pos() { diag.add_related(pos, "When instantiating this declaration"); } @@ -255,7 +257,7 @@ impl<'a> AnalyzeContext<'a> { None => None, Some(ref mut signature) => Some(( self.resolve_signature(scope, signature, diagnostics)?, - signature.pos.clone(), + signature.pos(self.ctx), )), }; let overloaded_ent = match name { @@ -266,7 +268,7 @@ impl<'a> AnalyzeContext<'a> { .collect_vec(); if choices.is_empty() { diagnostics.add( - &instantiation.ident.tree.pos, + instantiation.ident.tree.pos(self.ctx), format!( "{} does not denote an uninstantiated subprogram", name.describe() @@ -306,7 +308,7 @@ impl<'a> AnalyzeContext<'a> { resolved_ent } else { diagnostics.add( - &instantiation.subprogram_name.pos, + &instantiation.subprogram_name.pos(self.ctx), format!( "No uninstantiated subprogram exists with signature {}", key.describe() @@ -319,7 +321,7 @@ impl<'a> AnalyzeContext<'a> { // There are multiple candidates // and there is no signature to resolve let mut err = Diagnostic::new( - &instantiation.subprogram_name.pos, + &instantiation.subprogram_name.pos(self.ctx), format!("Ambiguous instantiation of '{}'", overloaded.designator()), ErrorCode::AmbiguousInstantiation, ); @@ -334,7 +336,7 @@ impl<'a> AnalyzeContext<'a> { } _ => { diagnostics.add( - &instantiation.subprogram_name.pos, + &instantiation.subprogram_name.pos(self.ctx), format!( "{} does not denote an uninstantiated subprogram", name.describe() @@ -348,7 +350,7 @@ impl<'a> AnalyzeContext<'a> { Ok(overloaded_ent) } else { diagnostics.add( - &instantiation.subprogram_name.pos, + &instantiation.subprogram_name.pos(self.ctx), format!("{} cannot be instantiated", overloaded_ent.describe()), ErrorCode::MismatchedKinds, ); diff --git a/vhdl_lang/src/analysis/target.rs b/vhdl_lang/src/analysis/target.rs index 25a8df10..cd7117e3 100644 --- a/vhdl_lang/src/analysis/target.rs +++ b/vhdl_lang/src/analysis/target.rs @@ -1,9 +1,11 @@ use super::analyze::*; use super::scope::*; +use crate::ast::token_range::WithTokenSpan; use crate::ast::*; use crate::data::error_codes::ErrorCode; use crate::data::*; use crate::named_entity::*; +use vhdl_lang::TokenSpan; /// Analysis of assignment targets /// @@ -11,17 +13,17 @@ use crate::named_entity::*; /// target <= 1; /// target(0).elem := 1 -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { pub fn resolve_target( &self, scope: &Scope<'a>, - target: &mut WithPos, + target: &mut WithTokenSpan, assignment_type: AssignmentType, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { match target.item { Target::Name(ref mut name) => { - self.resolve_target_name(scope, name, &target.pos, assignment_type, diagnostics) + self.resolve_target_name(scope, name, target.span, assignment_type, diagnostics) } Target::Aggregate(ref mut assocs) => { self.analyze_aggregate(scope, assocs, diagnostics)?; @@ -34,7 +36,7 @@ impl<'a> AnalyzeContext<'a> { &self, scope: &Scope<'a>, target: &mut Name, - target_pos: &SrcPos, + target_pos: TokenSpan, assignment_type: AssignmentType, diagnostics: &mut dyn DiagnosticHandler, ) -> EvalResult> { @@ -48,7 +50,7 @@ impl<'a> AnalyzeContext<'a> { )?; if !object_name.base.can_be_assigned_to() { diagnostics.add( - target_pos, + target_pos.pos(self.ctx), format!( "{} may not be the target of an assignment", object_name.base.describe_class() @@ -57,7 +59,7 @@ impl<'a> AnalyzeContext<'a> { ); } else if !object_name.base.is_valid_assignment_type(assignment_type) { diagnostics.add( - target_pos, + target_pos.pos(self.ctx), format!( "{} may not be the target of a {} assignment", object_name.base.describe_class(), diff --git a/vhdl_lang/src/analysis/tests/mod.rs b/vhdl_lang/src/analysis/tests/mod.rs index 6274e756..378a3012 100644 --- a/vhdl_lang/src/analysis/tests/mod.rs +++ b/vhdl_lang/src/analysis/tests/mod.rs @@ -54,11 +54,11 @@ pub(super) struct TestSetup<'a> { root: DesignRoot, arena: Arena, pub scope: Scope<'a>, - tokens: MockTokenAccess, + pub(crate) tokens: MockTokenAccess, } #[cfg(test)] -struct MockTokenAccess { +pub(crate) struct MockTokenAccess { token: Token, } @@ -104,7 +104,8 @@ impl<'a> TestSetup<'a> { } } - pub fn ctx(&'a self) -> AnalyzeContext<'a> { + #[allow(clippy::ptr_arg)] + pub fn ctx<'t>(&'a self, tokens: &'t Vec) -> AnalyzeContext<'a, 't> { let ctx = AnalyzeContext::new( &self.root, &UnitId::package( @@ -112,7 +113,7 @@ impl<'a> TestSetup<'a> { &self.root.symbol_utf8("dummy"), ), &self.arena, - &self.tokens, + tokens, ); ctx.add_implicit_context_clause(&self.scope).unwrap(); ctx @@ -132,7 +133,7 @@ impl<'a> TestSetup<'a> { None, None, ); - self.ctx() + self.ctx(&code.tokenize()) .analyze_declarative_part( &self.scope, dummy_parent, @@ -148,7 +149,7 @@ impl<'a> TestSetup<'a> { let designator = self.snippet(sym).designator(); self.scope - .lookup(&designator.pos, &designator.item) + .lookup(&self.tokens, designator.token, &designator.item) .unwrap() .into_non_overloaded() .unwrap() @@ -157,8 +158,10 @@ impl<'a> TestSetup<'a> { pub fn lookup_overloaded(&'a self, code: Code) -> OverloadedEnt<'a> { let des = code.designator(); - if let NamedEntities::Overloaded(overloaded) = - self.scope.lookup(&des.pos, &des.item).unwrap() + if let NamedEntities::Overloaded(overloaded) = self + .scope + .lookup(&self.tokens, des.token, &des.item) + .unwrap() { overloaded .entities() diff --git a/vhdl_lang/src/analysis/tests/package_instance.rs b/vhdl_lang/src/analysis/tests/package_instance.rs index 0d5777c6..72556b61 100644 --- a/vhdl_lang/src/analysis/tests/package_instance.rs +++ b/vhdl_lang/src/analysis/tests/package_instance.rs @@ -5,6 +5,7 @@ // Copyright (c) 2019, Olof Kraigher olof.kraigher@gmail.com use super::*; +use pretty_assertions::assert_eq; use vhdl_lang::data::error_codes::ErrorCode; #[test] diff --git a/vhdl_lang/src/analysis/tests/view_declarations.rs b/vhdl_lang/src/analysis/tests/view_declarations.rs index 26bedcec..521daea9 100644 --- a/vhdl_lang/src/analysis/tests/view_declarations.rs +++ b/vhdl_lang/src/analysis/tests/view_declarations.rs @@ -2,6 +2,7 @@ use crate::analysis::tests::{check_diagnostics, check_no_diagnostics, LibraryBui use crate::data::ErrorCode; use crate::Diagnostic; use crate::VHDLStandard::VHDL2019; +use pretty_assertions::assert_eq; #[test] pub fn view_mode_declaration_must_have_declared_subtype() { diff --git a/vhdl_lang/src/analysis/types.rs b/vhdl_lang/src/analysis/types.rs index 349b5d8c..07482f4a 100644 --- a/vhdl_lang/src/analysis/types.rs +++ b/vhdl_lang/src/analysis/types.rs @@ -11,7 +11,7 @@ use crate::data::*; use crate::named_entity::{Signature, *}; use analyze::*; -impl<'a> AnalyzeContext<'a> { +impl<'a, 't> AnalyzeContext<'a, 't> { pub fn resolve_subtype_indication( &self, scope: &Scope<'a>, @@ -30,7 +30,7 @@ impl<'a> AnalyzeContext<'a> { if let Some(constraint) = constraint { self.analyze_subtype_constraint( scope, - &type_mark.pos, + &type_mark.pos(self.ctx), base_type.base(), &mut constraint.item, diagnostics, @@ -53,6 +53,7 @@ impl<'a> AnalyzeContext<'a> { match type_decl.def { TypeDefinition::Enumeration(ref mut enumeration) => { let enum_type = TypeEnt::define_with_opt_id( + self.ctx, self.arena, overwrite_id, &mut type_decl.ident, @@ -74,7 +75,7 @@ impl<'a> AnalyzeContext<'a> { literal.tree.item.clone().into_designator(), enum_type.into(), AnyEntKind::Overloaded(Overloaded::EnumLiteral(signature.clone())), - Some(&literal.tree.pos), + Some(literal.pos(self.ctx)), None, ); literal.decl.set(literal_ent.id()); @@ -108,12 +109,13 @@ impl<'a> AnalyzeContext<'a> { if let Some(prev_pos) = ent.decl_pos() { diagnostics.push(Diagnostic::duplicate_error( &type_decl.ident.tree, - &type_decl.ident.tree.pos, + type_decl.ident.tree.pos(self.ctx), Some(prev_pos), )) } } else { let ptype_body: &'a AnyEnt = TypeEnt::define_with_opt_id( + self.ctx, self.arena, overwrite_id, &mut type_decl.ident, @@ -149,7 +151,7 @@ impl<'a> AnalyzeContext<'a> { if !is_ok { diagnostics.add( - type_decl.ident.pos(), + type_decl.ident.pos(self.ctx), format!("'{}' is not a protected type", &type_decl.ident), ErrorCode::TypeMismatch, ); @@ -157,7 +159,7 @@ impl<'a> AnalyzeContext<'a> { } None => { diagnostics.add( - type_decl.ident.pos(), + type_decl.ident.pos(self.ctx), format!("No declaration of protected type '{}'", &type_decl.ident), ErrorCode::Unresolved, ); @@ -168,6 +170,7 @@ impl<'a> AnalyzeContext<'a> { // Protected type name is visible inside its declarative region // This will be overwritten later when the protected type region is finished let ptype: &'a AnyEnt = TypeEnt::define_with_opt_id( + self.ctx, self.arena, overwrite_id, &mut type_decl.ident, @@ -219,6 +222,7 @@ impl<'a> AnalyzeContext<'a> { } TypeDefinition::Record(ref mut element_decls) => { let type_ent = TypeEnt::define_with_opt_id( + self.ctx, self.arena, overwrite_id, &mut type_decl.ident, @@ -234,6 +238,7 @@ impl<'a> AnalyzeContext<'a> { self.resolve_subtype_indication(scope, &mut elem_decl.subtype, diagnostics); if let Some(subtype) = as_fatal(subtype)? { let elem = self.arena.define( + self.ctx, &mut elem_decl.ident, type_ent.into(), AnyEntKind::ElementDeclaration(subtype), @@ -264,6 +269,7 @@ impl<'a> AnalyzeContext<'a> { self.resolve_subtype_indication(scope, subtype_indication, diagnostics); if let Some(subtype) = as_fatal(subtype)? { let type_ent = TypeEnt::define_with_opt_id( + self.ctx, self.arena, overwrite_id, &mut type_decl.ident, @@ -303,6 +309,7 @@ impl<'a> AnalyzeContext<'a> { let is_1d = indexes.len() == 1; let array_ent = TypeEnt::define_with_opt_id( + self.ctx, self.arena, overwrite_id, &mut type_decl.ident, @@ -328,6 +335,7 @@ impl<'a> AnalyzeContext<'a> { diagnostics, ))? { let type_ent = TypeEnt::define_with_opt_id( + self.ctx, self.arena, overwrite_id, &mut type_decl.ident, @@ -347,6 +355,7 @@ impl<'a> AnalyzeContext<'a> { )?; let phys_type = TypeEnt::define_with_opt_id( + self.ctx, self.arena, overwrite_id, &mut type_decl.ident, @@ -357,6 +366,7 @@ impl<'a> AnalyzeContext<'a> { scope.add(phys_type.into(), diagnostics); let primary = self.arena.define( + self.ctx, &mut physical.primary_unit, parent, AnyEntKind::PhysicalLiteral(phys_type), @@ -373,7 +383,7 @@ impl<'a> AnalyzeContext<'a> { Ok(secondary_unit_type) => { if secondary_unit_type.base_type() != phys_type { diagnostics.add( - &value.unit.item.pos, + value.unit.item.pos(self.ctx), format!( "Physical unit of type '{}' does not match {}", secondary_unit_type.designator(), @@ -387,6 +397,7 @@ impl<'a> AnalyzeContext<'a> { } let secondary_unit = self.arena.define( + self.ctx, secondary_unit_name, parent, AnyEntKind::PhysicalLiteral(phys_type), @@ -421,7 +432,7 @@ impl<'a> AnalyzeContext<'a> { UniversalType::Real } else { diagnostics.add( - &range.pos(), + &range.span().pos(self.ctx), "Expected real or integer range", ErrorCode::TypeMismatch, ); @@ -432,6 +443,7 @@ impl<'a> AnalyzeContext<'a> { }; let type_ent = TypeEnt::define_with_opt_id( + self.ctx, self.arena, overwrite_id, &mut type_decl.ident, @@ -454,6 +466,7 @@ impl<'a> AnalyzeContext<'a> { TypeDefinition::File(ref mut type_mark) => { let file_type = TypeEnt::define_with_opt_id( + self.ctx, self.arena, overwrite_id, &mut type_decl.ident, @@ -527,7 +540,7 @@ impl<'a> AnalyzeContext<'a> { } } else { diagnostics.add( - drange.pos(), + drange.span().pos(self.ctx), format!("Got extra index constraint for {}", base_type.describe()), ErrorCode::TooManyConstraints, ); @@ -551,7 +564,7 @@ impl<'a> AnalyzeContext<'a> { if let Some(constraint) = constraint { self.analyze_subtype_constraint( scope, - &constraint.pos, + &constraint.span.pos(self.ctx), elem_type.base(), &mut constraint.item, diagnostics, @@ -590,14 +603,16 @@ impl<'a> AnalyzeContext<'a> { if let Some(elem) = region.lookup(&des) { self.analyze_subtype_constraint( scope, - &constraint.pos, + &constraint.pos(self.ctx), elem.type_mark().base(), &mut constraint.item, diagnostics, )?; } else { diagnostics.push(Diagnostic::no_declaration_within( - &base_type, &ident.pos, &des, + &base_type, + ident.pos(self.ctx), + &des, )) } } diff --git a/vhdl_lang/src/ast.rs b/vhdl_lang/src/ast.rs index c6e50091..193a27e2 100644 --- a/vhdl_lang/src/ast.rs +++ b/vhdl_lang/src/ast.rs @@ -13,8 +13,10 @@ mod any_design_unit; #[macro_use] pub mod search; +pub mod token_range; pub(crate) use self::util::*; +use crate::ast::token_range::*; pub(crate) use any_design_unit::*; use crate::data::*; @@ -83,10 +85,10 @@ pub enum Operator { /// LRM 8.6 Attribute names #[derive(PartialEq, Debug, Clone)] pub struct AttributeName { - pub name: WithPos, - pub signature: Option>, - pub attr: WithPos, - pub expr: Option>>, + pub name: WithTokenSpan, + pub signature: Option>, + pub attr: WithToken, + pub expr: Option>>, } #[derive(PartialEq, Debug, Copy, Clone, Eq)] @@ -163,18 +165,18 @@ impl From for ObjectClass { /// LRM 8.7 External names #[derive(PartialEq, Debug, Clone)] pub enum ExternalPath { - Package(WithPos), - Absolute(WithPos), + Package(WithTokenSpan), + Absolute(WithTokenSpan), // usize field indicates the number of up-levels ('^') - Relative(WithPos, usize), + Relative(WithTokenSpan, usize), } /// LRM 8.7 External names #[derive(PartialEq, Debug, Clone)] pub struct ExternalName { pub class: ExternalObjectClass, - pub path: WithPos, + pub path: WithTokenSpan, pub subtype: SubtypeIndication, } @@ -182,9 +184,9 @@ pub struct ExternalName { #[derive(PartialEq, Debug, Clone)] pub enum Name { Designator(WithRef), - Selected(Box>, WithPos>), - SelectedAll(Box>), - Slice(Box>, Box), + Selected(Box>, WithToken>), + SelectedAll(Box>), + Slice(Box>, Box), Attribute(Box), CallOrIndexed(Box), External(Box), @@ -193,7 +195,7 @@ pub enum Name { /// LRM 9.3.4 Function calls #[derive(PartialEq, Debug, Clone)] pub struct CallOrIndexed { - pub name: WithPos, + pub name: WithTokenSpan, pub parameters: Vec, } @@ -208,8 +210,8 @@ pub enum Choice { /// LRM 9.3.3 Aggregates #[derive(PartialEq, Debug, Clone)] pub enum ElementAssociation { - Positional(WithPos), - Named(Vec>, WithPos), + Positional(WithTokenSpan), + Named(Vec>, WithTokenSpan), } /// LRM 6.5.7 Association Lists @@ -222,8 +224,8 @@ pub enum ActualPart { /// LRM 6.5.7 Association Lists #[derive(PartialEq, Debug, Clone)] pub struct AssociationElement { - pub formal: Option>, - pub actual: WithPos, + pub formal: Option>, + pub actual: WithTokenSpan, } /// LRM 15.5 Abstract literals @@ -268,19 +270,19 @@ pub enum Allocator { /// LRM 9.3.5 Qualified expressions #[derive(PartialEq, Debug, Clone)] pub struct QualifiedExpression { - pub type_mark: WithPos, - pub expr: WithPos, + pub type_mark: WithTokenSpan, + pub expr: WithTokenSpan, } /// LRM 9. Expressions #[derive(PartialEq, Debug, Clone)] pub enum Expression { Binary( - WithPos>, - Box>, - Box>, + WithToken>, + Box>, + Box>, ), - Unary(WithPos>, Box>), + Unary(WithToken>, Box>), /// LRM 9.3.3 Aggregates Aggregate(Vec), @@ -295,11 +297,11 @@ pub enum Expression { Literal(Literal), /// LRM 9.3.7 Allocators - New(Box>), + New(Box>), } /// An identifier together with the lexical source location it occurs in. -pub type Ident = WithPos; +pub type Ident = WithToken; #[derive(PartialEq, Eq, Debug, Clone, Copy)] pub enum Direction { @@ -314,15 +316,15 @@ pub enum Direction { /// | simple_expression direction simple_expression #[derive(PartialEq, Debug, Clone)] pub enum DiscreteRange { - Discrete(WithPos, Option), + Discrete(WithTokenSpan, Option), Range(Range), } #[derive(PartialEq, Debug, Clone)] pub struct RangeConstraint { pub direction: Direction, - pub left_expr: Box>, - pub right_expr: Box>, + pub left_expr: Box>, + pub right_expr: Box>, } #[derive(PartialEq, Debug, Clone)] @@ -335,14 +337,17 @@ pub enum Range { #[derive(PartialEq, Debug, Clone)] pub struct ElementConstraint { pub ident: Ident, - pub constraint: Box>, + pub constraint: Box>, } #[derive(PartialEq, Debug, Clone)] pub enum SubtypeConstraint { Range(Range), /// Empty Vec means Open - Array(Vec, Option>>), + Array( + Vec, + Option>>, + ), Record(Vec), } @@ -356,15 +361,15 @@ pub struct RecordElementResolution { /// LRM 6.3 Subtype declarations #[derive(PartialEq, Debug, Clone)] pub enum ResolutionIndication { - FunctionName(WithPos), - ArrayElement(WithPos), + FunctionName(WithTokenSpan), + ArrayElement(WithTokenSpan), Record(Vec), Unresolved, } #[derive(PartialEq, Debug, Clone)] pub struct TypeMark { - pub name: WithPos, + pub name: WithTokenSpan, pub attr: Option, } @@ -372,8 +377,8 @@ pub struct TypeMark { #[derive(PartialEq, Debug, Clone)] pub struct SubtypeIndication { pub resolution: ResolutionIndication, - pub type_mark: WithPos, - pub constraint: Option>, + pub type_mark: WithTokenSpan, + pub constraint: Option>, } /// LRM 5.3 Array Types @@ -381,7 +386,7 @@ pub struct SubtypeIndication { pub enum ArrayIndex { /// Unbounded /// {identifier} range <> - IndexSubtypeDefintion(WithPos), + IndexSubtypeDefintion(WithTokenSpan), /// Constraint Discrete(DiscreteRange), @@ -440,6 +445,12 @@ impl WithDecl { } } +impl WithDecl> { + pub fn pos<'a>(&'a self, ctx: &'a dyn TokenAccess) -> &SrcPos { + self.tree.pos(ctx) + } +} + impl From for WithDecl { fn from(value: T) -> Self { WithDecl::new(value) @@ -452,15 +463,9 @@ impl> AsRef for WithDecl { } } -#[derive(PartialEq, Debug, Clone)] -pub struct WithToken { - item: T, - token: TokenId, -} - -impl WithToken { - pub fn new(item: T, token: TokenId) -> WithToken { - WithToken { item, token } +impl HasDesignator for WithToken> { + fn designator(&self) -> &Designator { + self.item.designator() } } @@ -468,10 +473,10 @@ impl WithToken { #[with_token_span] #[derive(PartialEq, Debug, Clone)] pub struct AliasDeclaration { - pub designator: WithDecl>, + pub designator: WithDecl>, pub subtype_indication: Option, - pub name: WithPos, - pub signature: Option>, + pub name: WithTokenSpan, + pub signature: Option>, } /// LRM 6.7 Attribute declarations @@ -479,14 +484,14 @@ pub struct AliasDeclaration { #[derive(PartialEq, Debug, Clone)] pub struct AttributeDeclaration { pub ident: WithDecl, - pub type_mark: WithPos, + pub type_mark: WithTokenSpan, } /// LRM 7.2 Attribute specification #[derive(PartialEq, Debug, Clone)] pub struct EntityTag { - pub designator: WithPos>, - pub signature: Option>, + pub designator: WithToken>, + pub signature: Option>, } /// LRM 7.2 Attribute specification @@ -529,7 +534,7 @@ pub struct AttributeSpecification { pub ident: WithRef, pub entity_name: EntityName, pub entity_class: EntityClass, - pub expr: WithPos, + pub expr: WithTokenSpan, } /// LRM 7.2 Attribute specification @@ -571,7 +576,7 @@ pub enum EnumerationLiteral { pub enum TypeDefinition { /// LRM 5.2 Scalar Types /// LRM 5.2.2 Enumeration types - Enumeration(Vec>>), + Enumeration(Vec>>), /// LRM 5.2.3 Integer types /// 5.2.5 Floating-point types Numeric(Range), @@ -588,7 +593,7 @@ pub enum TypeDefinition { /// LRM 5.4.2 Incomplete type declarations Incomplete(Reference), /// LRM 5.5 File types - File(WithPos), + File(WithTokenSpan), /// LRM 5.6 Protected types Protected(ProtectedTypeDeclaration), ProtectedBody(ProtectedTypeBody), @@ -602,7 +607,7 @@ pub enum TypeDefinition { pub struct TypeDeclaration { pub ident: WithDecl, pub def: TypeDefinition, - pub end_ident_pos: Option, + pub end_ident_pos: Option, } /// LRM 6.4.2 Object Declarations @@ -627,7 +632,7 @@ pub struct ObjectDeclaration { pub class: ObjectClass, pub ident: WithDecl, pub subtype_indication: SubtypeIndication, - pub expression: Option>, + pub expression: Option>, } #[with_token_span] @@ -635,8 +640,8 @@ pub struct ObjectDeclaration { pub struct FileDeclaration { pub ident: WithDecl, pub subtype_indication: SubtypeIndication, - pub open_info: Option>, - pub file_name: Option>, + pub open_info: Option>, + pub file_name: Option>, } #[derive(PartialEq, Eq, Debug, Clone)] @@ -648,7 +653,7 @@ pub enum SubprogramDesignator { /// LRM 4.2 Subprogram declaration #[derive(PartialEq, Debug, Clone)] pub struct ProcedureSpecification { - pub designator: WithDecl>, + pub designator: WithDecl>, pub header: Option, // The `parameter` token, if such a token exists pub param_tok: Option, @@ -659,12 +664,12 @@ pub struct ProcedureSpecification { #[derive(PartialEq, Debug, Clone)] pub struct FunctionSpecification { pub pure: bool, - pub designator: WithDecl>, + pub designator: WithDecl>, pub header: Option, // The `parameter` token, if such a token exists pub param_tok: Option, pub parameter_list: Vec, - pub return_type: WithPos, + pub return_type: WithTokenSpan, } /// LRM 4.3 Subprogram bodies @@ -674,7 +679,7 @@ pub struct SubprogramBody { pub specification: SubprogramSpecification, pub declarations: Vec, pub statements: Vec, - pub end_ident_pos: Option, + pub end_ident_pos: Option, } /// LRM 4.2.1 Subprogram Header @@ -700,16 +705,16 @@ pub enum SubprogramKind { pub struct SubprogramInstantiation { pub kind: SubprogramKind, pub ident: WithDecl, - pub subprogram_name: WithPos, - pub signature: Option>, + pub subprogram_name: WithTokenSpan, + pub signature: Option>, pub generic_map: Option, } /// LRM 4.5.3 Signatures #[derive(PartialEq, Debug, Clone)] pub enum Signature { - Function(Vec>, WithPos), - Procedure(Vec>), + Function(Vec>, WithTokenSpan), + Procedure(Vec>), } #[derive(PartialEq, Debug, Clone)] @@ -751,7 +756,7 @@ pub struct SimpleModeIndication { pub class: ObjectClass, pub subtype_indication: SubtypeIndication, pub bus: bool, - pub expression: Option>, + pub expression: Option>, } #[derive(PartialEq, Debug, Clone, Copy)] @@ -763,13 +768,13 @@ pub enum ModeViewIndicationKind { #[derive(PartialEq, Debug, Clone)] pub struct ModeViewIndication { pub kind: ModeViewIndicationKind, - pub name: WithPos, + pub name: WithTokenSpan, pub subtype_indication: Option, } #[derive(PartialEq, Debug, Clone)] pub enum SubprogramDefault { - Name(WithPos), + Name(WithTokenSpan), Box, } @@ -785,7 +790,7 @@ pub enum InterfacePackageGenericMapAspect { #[derive(PartialEq, Debug, Clone)] pub struct InterfacePackageDeclaration { pub ident: WithDecl, - pub package_name: WithPos, + pub package_name: WithTokenSpan, pub generic_map: InterfacePackageGenericMapAspect, } @@ -822,7 +827,7 @@ pub struct ComponentDeclaration { pub ident: WithDecl, pub generic_list: Vec, pub port_list: Vec, - pub end_ident_pos: Option, + pub end_ident_pos: Option, } #[derive(PartialEq, Debug, Clone, TokenSpan)] @@ -845,24 +850,24 @@ pub enum Declaration { /// LRM 10.2 Wait statement #[derive(PartialEq, Debug, Clone)] pub struct WaitStatement { - pub sensitivity_clause: Vec>, - pub condition_clause: Option>, - pub timeout_clause: Option>, + pub sensitivity_clause: Vec>, + pub condition_clause: Option>, + pub timeout_clause: Option>, } /// LRM 10.3 Assertion statement #[derive(PartialEq, Debug, Clone)] pub struct AssertStatement { - pub condition: WithPos, - pub report: Option>, - pub severity: Option>, + pub condition: WithTokenSpan, + pub report: Option>, + pub severity: Option>, } /// LRM 10.4 Report statement #[derive(PartialEq, Debug, Clone)] pub struct ReportStatement { - pub report: WithPos, - pub severity: Option>, + pub report: WithTokenSpan, + pub severity: Option>, } /// LRM 10.5 Signal assignment statement @@ -875,8 +880,8 @@ pub enum Target { /// LRM 10.5 Signal assignment statement #[derive(PartialEq, Debug, Clone)] pub struct WaveformElement { - pub value: WithPos, - pub after: Option>, + pub value: WithTokenSpan, + pub after: Option>, } /// LRM 10.5 Signal assignment statement @@ -890,13 +895,15 @@ pub enum Waveform { #[derive(PartialEq, Debug, Clone)] pub enum DelayMechanism { Transport, - Inertial { reject: Option> }, + Inertial { + reject: Option>, + }, } /// LRM 10.5 Signal assignment statement #[derive(PartialEq, Debug, Clone)] pub struct SignalAssignment { - pub target: WithPos, + pub target: WithTokenSpan, pub delay_mechanism: Option, pub rhs: AssignmentRightHand, } @@ -909,22 +916,22 @@ pub enum ForceMode { #[derive(PartialEq, Debug, Clone)] pub struct SignalForceAssignment { - pub target: WithPos, + pub target: WithTokenSpan, pub force_mode: Option, - pub rhs: AssignmentRightHand>, + pub rhs: AssignmentRightHand>, } #[derive(PartialEq, Debug, Clone)] pub struct SignalReleaseAssignment { - pub target: WithPos, + pub target: WithTokenSpan, pub force_mode: Option, } /// LRM 10.6 Variable assignment statement #[derive(PartialEq, Debug, Clone)] pub struct VariableAssignment { - pub target: WithPos, - pub rhs: AssignmentRightHand>, + pub target: WithTokenSpan, + pub rhs: AssignmentRightHand>, } /// LRM 10.5 Signal assignment statement @@ -938,7 +945,7 @@ pub enum AssignmentRightHand { #[derive(PartialEq, Debug, Clone)] pub struct Conditional { - pub condition: WithPos, + pub condition: WithTokenSpan, pub item: T, } @@ -957,13 +964,13 @@ pub struct IfStatement { #[derive(PartialEq, Debug, Clone)] pub struct Alternative { - pub choices: Vec>, + pub choices: Vec>, pub item: T, } #[derive(PartialEq, Debug, Clone)] pub struct Selection { - pub expression: WithPos, + pub expression: WithTokenSpan, pub alternatives: Vec>, } @@ -971,7 +978,7 @@ pub struct Selection { #[derive(PartialEq, Debug, Clone)] pub struct CaseStatement { pub is_matching: bool, - pub expression: WithPos, + pub expression: WithTokenSpan, pub alternatives: Vec>>, pub end_label_pos: Option, } @@ -979,7 +986,7 @@ pub struct CaseStatement { /// LRM 10.10 Loop statement #[derive(PartialEq, Debug, Clone)] pub enum IterationScheme { - While(WithPos), + While(WithTokenSpan), For(WithDecl, DiscreteRange), } @@ -995,20 +1002,20 @@ pub struct LoopStatement { #[derive(PartialEq, Debug, Clone)] pub struct NextStatement { pub loop_label: Option>, - pub condition: Option>, + pub condition: Option>, } /// LRM 10.12 Exit statement #[derive(PartialEq, Debug, Clone)] pub struct ExitStatement { pub loop_label: Option>, - pub condition: Option>, + pub condition: Option>, } /// LRM 10.13 Return statement #[derive(PartialEq, Debug, Clone)] pub struct ReturnStatement { - pub expression: Option>, + pub expression: Option>, } /// LRM 10. Sequential statements @@ -1021,7 +1028,7 @@ pub enum SequentialStatement { SignalAssignment(SignalAssignment), SignalForceAssignment(SignalForceAssignment), SignalReleaseAssignment(SignalReleaseAssignment), - ProcedureCall(WithPos), + ProcedureCall(WithTokenSpan), If(IfStatement), Case(CaseStatement), Loop(LoopStatement), @@ -1035,14 +1042,14 @@ pub enum SequentialStatement { #[derive(PartialEq, Debug, Clone)] pub struct LabeledSequentialStatement { pub label: WithDecl>, - pub statement: WithPos, + pub statement: WithTokenSpan, } /// LRM 11.2 Block statement #[with_token_span] #[derive(PartialEq, Debug, Clone)] pub struct BlockStatement { - pub guard_condition: Option>, + pub guard_condition: Option>, pub header: BlockHeader, pub decl: Vec, pub statements: Vec, @@ -1060,7 +1067,7 @@ pub struct BlockHeader { #[derive(PartialEq, Debug, Clone)] pub enum SensitivityList { - Names(Vec>), + Names(Vec>), All, } @@ -1079,7 +1086,7 @@ pub struct ProcessStatement { #[derive(PartialEq, Debug, Clone)] pub struct ConcurrentProcedureCall { pub postponed: bool, - pub call: WithPos, + pub call: WithTokenSpan, } /// LRM 11.5 Concurrent assertion statements @@ -1094,7 +1101,7 @@ pub struct ConcurrentAssertStatement { pub struct ConcurrentSignalAssignment { pub postponed: bool, pub guarded: bool, - pub target: WithPos, + pub target: WithTokenSpan, pub delay_mechanism: Option, pub rhs: AssignmentRightHand, } @@ -1102,9 +1109,9 @@ pub struct ConcurrentSignalAssignment { /// 11.7 Component instantiation statements #[derive(PartialEq, Debug, Clone)] pub enum InstantiatedUnit { - Component(WithPos), - Entity(WithPos, Option>), - Configuration(WithPos), + Component(WithTokenSpan), + Entity(WithTokenSpan, Option>), + Configuration(WithTokenSpan), } impl InstantiatedUnit { @@ -1195,7 +1202,7 @@ pub struct ModeViewDeclaration { pub ident: WithDecl, pub typ: SubtypeIndication, pub elements: Vec, - pub end_ident_pos: Option, + pub end_ident_pos: Option, } #[with_token_span] @@ -1207,9 +1214,9 @@ pub struct ModeViewElement { #[derive(PartialEq, Debug, Clone)] pub enum ElementMode { - Simple(WithPos), - Record(WithPos), - Array(WithPos), + Simple(WithToken), + Record(WithTokenSpan), + Array(WithTokenSpan), } /// LRM 11. Concurrent statements @@ -1230,7 +1237,7 @@ pub enum ConcurrentStatement { #[derive(PartialEq, Debug, Clone)] pub struct LabeledConcurrentStatement { pub label: WithDecl>, - pub statement: WithPos, + pub statement: WithTokenSpan, } /// LRM 13. Design units and their analysis @@ -1270,7 +1277,7 @@ impl SeparatedList { } pub type IdentList = SeparatedList>; -pub type NameList = SeparatedList>; +pub type NameList = SeparatedList>; /// LRM 12.4. Use clauses #[with_token_span] @@ -1300,7 +1307,7 @@ pub enum ContextItem { pub struct ContextDeclaration { pub ident: WithDecl, pub items: ContextClause, - pub end_ident_pos: Option, + pub end_ident_pos: Option, } /// LRM 4.9 Package instantiation declaration @@ -1309,7 +1316,7 @@ pub struct ContextDeclaration { pub struct PackageInstantiation { pub context_clause: ContextClause, pub ident: WithDecl, - pub package_name: WithPos, + pub package_name: WithTokenSpan, pub generic_map: Option, } @@ -1324,8 +1331,8 @@ pub enum InstantiationList { /// LRM 7.3.2 Binding indication #[derive(PartialEq, Debug, Clone)] pub enum EntityAspect { - Entity(WithPos, Option), - Configuration(WithPos), + Entity(WithTokenSpan, Option), + Configuration(WithTokenSpan), Open, } @@ -1341,13 +1348,13 @@ pub struct BindingIndication { #[derive(PartialEq, Debug, Clone)] pub struct ComponentSpecification { pub instantiation_list: InstantiationList, - pub component_name: WithPos, + pub component_name: WithTokenSpan, } /// LRM 7.3.4 Verification unit binding indication #[derive(PartialEq, Debug, Clone)] pub struct VUnitBindingIndication { - pub vunit_list: Vec>, + pub vunit_list: Vec>, } /// LRM 7.3 Configuration specification @@ -1386,7 +1393,7 @@ pub enum ConfigurationItem { /// LRM 3.4 Configuration declarations #[derive(PartialEq, Debug, Clone)] pub struct BlockConfiguration { - pub block_spec: WithPos, + pub block_spec: WithTokenSpan, pub use_clauses: Vec, pub items: Vec, } @@ -1397,11 +1404,11 @@ pub struct BlockConfiguration { pub struct ConfigurationDeclaration { pub context_clause: ContextClause, pub ident: WithDecl, - pub entity_name: WithPos, + pub entity_name: WithTokenSpan, pub decl: Vec, pub vunit_bind_inds: Vec, pub block_config: BlockConfiguration, - pub end_ident_pos: Option, + pub end_ident_pos: Option, } /// LRM 3.2 Entity declarations @@ -1414,7 +1421,7 @@ pub struct EntityDeclaration { pub port_clause: Option>, pub decl: Vec, pub statements: Vec, - pub end_ident_pos: Option, + pub end_ident_pos: Option, } /// LRM 3.3 Architecture bodies @@ -1427,7 +1434,7 @@ pub struct ArchitectureBody { pub begin_token: TokenId, pub decl: Vec, pub statements: Vec, - pub end_ident_pos: Option, + pub end_ident_pos: Option, } /// LRM 4.7 Package declarations @@ -1438,7 +1445,7 @@ pub struct PackageDeclaration { pub ident: WithDecl, pub generic_clause: Option>, pub decl: Vec, - pub end_ident_pos: Option, + pub end_ident_pos: Option, } /// LRM 4.8 Package bodies @@ -1448,7 +1455,7 @@ pub struct PackageBody { pub context_clause: ContextClause, pub ident: WithDecl, pub decl: Vec, - pub end_ident_pos: Option, + pub end_ident_pos: Option, } /// LRM 13.1 Design units diff --git a/vhdl_lang/src/ast/display.rs b/vhdl_lang/src/ast/display.rs index 186554b7..ff5aee64 100644 --- a/vhdl_lang/src/ast/display.rs +++ b/vhdl_lang/src/ast/display.rs @@ -9,7 +9,7 @@ use super::*; use std::fmt::{Display, Formatter, Result}; -impl Display for WithPos { +impl Display for WithTokenSpan { fn fmt(&self, f: &mut Formatter<'_>) -> Result { write!(f, "{}", &self.item) } @@ -21,6 +21,15 @@ impl Display for WithDecl { } } +impl Display for WithToken +where + T: Display, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", &self.item) + } +} + impl Display for BaseSpecifier { fn fmt(&self, f: &mut Formatter<'_>) -> Result { match self { diff --git a/vhdl_lang/src/ast/search.rs b/vhdl_lang/src/ast/search.rs index d6e6781c..c5d1badf 100644 --- a/vhdl_lang/src/ast/search.rs +++ b/vhdl_lang/src/ast/search.rs @@ -11,7 +11,7 @@ use crate::named_entity::{EntRef, HasEntityId, Reference, Related}; use crate::syntax::{HasTokenSpan, TokenAccess}; #[must_use] -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] pub enum SearchResult { Found, NotFound, @@ -39,7 +39,7 @@ impl SearchState { pub enum FoundDeclaration<'a> { Object(&'a ObjectDeclaration), ElementDeclaration(&'a ElementDeclaration), - EnumerationLiteral(&'a Ident, &'a WithDecl>), + EnumerationLiteral(&'a Ident, &'a WithDecl>), InterfaceObject(&'a InterfaceObjectDeclaration), InterfaceFile(&'a InterfaceFileDeclaration), File(&'a FileDeclaration), @@ -92,7 +92,7 @@ pub trait Searcher { /// Search an identifier that has a reference to a declaration fn search_ident_ref(&mut self, ctx: &dyn TokenAccess, ident: &WithRef) -> SearchState { - self.search_pos_with_ref(ctx, &ident.item.pos, &ident.reference) + self.search_pos_with_ref(ctx, ident.item.pos(ctx), &ident.reference) } /// Search a declaration of a named entity @@ -213,7 +213,7 @@ fn search_selection( } fn search_assignment( - target: &WithPos, + target: &WithTokenSpan, rhs: &AssignmentRightHand, searcher: &mut impl Searcher, ctx: &dyn TokenAccess, @@ -240,16 +240,16 @@ fn search_assignment( } } -impl Search for WithPos { +impl Search for WithTokenSpan { fn search(&self, ctx: &dyn TokenAccess, searcher: &mut impl Searcher) -> SearchResult { - return_if_finished!(searcher.search_with_pos(ctx, &self.pos)); + return_if_finished!(searcher.search_with_pos(ctx, &self.pos(ctx))); match self.item { Choice::DiscreteRange(ref drange) => { return_if_found!(drange.search(ctx, searcher)); } Choice::Expression(ref expr) => { - return_if_found!(search_pos_expr(ctx, &self.pos, expr, searcher)); + return_if_found!(search_pos_expr(ctx, &self.pos(ctx), expr, searcher)); } Choice::Others => {} } @@ -257,10 +257,10 @@ impl Search for WithPos { } } -impl Search for WithPos { +impl Search for WithTokenSpan { fn search(&self, ctx: &dyn TokenAccess, searcher: &mut impl Searcher) -> SearchResult { match self.item { - Target::Name(ref name) => search_pos_name(&self.pos, name, searcher, ctx), + Target::Name(ref name) => search_pos_name(&self.pos(ctx), name, searcher, ctx), Target::Aggregate(ref assocs) => assocs.search(ctx, searcher), } } @@ -286,7 +286,7 @@ impl Search for LabeledSequentialStatement { return_if_found!(expression.search(ctx, searcher)); } SequentialStatement::ProcedureCall(ref pcall) => { - return_if_finished!(searcher.search_with_pos(ctx, &pcall.pos)); + return_if_finished!(searcher.search_with_pos(ctx, &pcall.pos(ctx))); return_if_found!(pcall.item.search(ctx, searcher)); } SequentialStatement::If(ref ifstmt) => { @@ -324,7 +324,7 @@ impl Search for LabeledSequentialStatement { } = exit_stmt; if let Some(loop_label) = loop_label { return_if_found!(searcher - .search_pos_with_ref(ctx, &loop_label.item.pos, &loop_label.reference) + .search_pos_with_ref(ctx, loop_label.item.pos(ctx), &loop_label.reference) .or_not_found()); } return_if_found!(condition.search(ctx, searcher)); @@ -336,7 +336,7 @@ impl Search for LabeledSequentialStatement { } = next_stmt; if let Some(loop_label) = loop_label { return_if_found!(searcher - .search_pos_with_ref(ctx, &loop_label.item.pos, &loop_label.reference) + .search_pos_with_ref(ctx, loop_label.item.pos(ctx), &loop_label.reference) .or_not_found()); } return_if_found!(condition.search(ctx, searcher)); @@ -441,7 +441,7 @@ impl Search for InstantiationStatement { return_if_found!(searcher .search_pos_with_ref( ctx, - &architecture_name.item.pos, + architecture_name.item.pos(ctx), &architecture_name.reference ) .or_not_found()); @@ -530,7 +530,7 @@ impl Search for LabeledConcurrentStatement { call, .. } = pcall; - return_if_finished!(searcher.search_with_pos(ctx, &call.pos)); + return_if_finished!(searcher.search_with_pos(ctx, &call.pos(ctx))); return_if_found!(call.item.search(ctx, searcher)); } ConcurrentStatement::Assert(ref assert) => { @@ -559,11 +559,11 @@ impl Search for LabeledConcurrentStatement { } } -impl Search for WithPos> { +impl Search for WithToken> { fn search(&self, ctx: &dyn TokenAccess, searcher: &mut impl Searcher) -> SearchResult { - return_if_finished!(searcher.search_with_pos(ctx, &self.pos)); + return_if_finished!(searcher.search_with_pos(ctx, self.pos(ctx))); searcher - .search_designator_ref(ctx, &self.pos, &self.item) + .search_designator_ref(ctx, self.pos(ctx), &self.item) .or_not_found() } } @@ -602,7 +602,7 @@ fn search_pos_name( if let AttributeDesignator::Ident(ref user_attr) = attr.item { return_if_finished!(searcher.search_pos_with_ref( ctx, - &attr.pos, + attr.pos(ctx), &user_attr.reference )); } @@ -619,10 +619,10 @@ fn search_pos_name( } } -impl Search for WithPos { +impl Search for WithTokenSpan { fn search(&self, ctx: &dyn TokenAccess, searcher: &mut impl Searcher) -> SearchResult { - return_if_finished!(searcher.search_with_pos(ctx, &self.pos)); - search_pos_name(&self.pos, &self.item, searcher, ctx) + return_if_finished!(searcher.search_with_pos(ctx, &self.pos(ctx))); + search_pos_name(&self.pos(ctx), &self.item, searcher, ctx) } } @@ -634,16 +634,16 @@ impl Search for ElementConstraint { } } -impl Search for WithPos { +impl Search for WithTokenSpan { fn search(&self, ctx: &dyn TokenAccess, searcher: &mut impl Searcher) -> SearchResult { - return_if_finished!(searcher.search_with_pos(ctx, &self.pos)); + return_if_finished!(searcher.search_with_pos(ctx, &self.pos(ctx))); self.item.search(ctx, searcher) } } -impl Search for WithPos { +impl Search for WithTokenSpan { fn search(&self, ctx: &dyn TokenAccess, searcher: &mut impl Searcher) -> SearchResult { - return_if_finished!(searcher.search_with_pos(ctx, &self.pos)); + return_if_finished!(searcher.search_with_pos(ctx, &self.pos(ctx))); match self.item { SubtypeConstraint::Array(ref dranges, ref constraint) => { return_if_found!(dranges.search(ctx, searcher)); @@ -676,9 +676,9 @@ impl Search for SubtypeIndication { } } -impl Search for WithPos { +impl Search for WithTokenSpan { fn search(&self, ctx: &dyn TokenAccess, searcher: &mut impl Searcher) -> SearchResult { - return_if_finished!(searcher.search_with_pos(ctx, &self.pos)); + return_if_finished!(searcher.search_with_pos(ctx, &self.pos(ctx))); self.item.name.search(ctx, searcher) } } @@ -785,7 +785,7 @@ impl Search for TypeDeclaration { TypeDefinition::Incomplete(ref reference) => { // Incomplete type should reference full declaration return_if_found!(searcher - .search_pos_with_ref(ctx, self.ident.pos(), reference) + .search_pos_with_ref(ctx, self.ident.pos(ctx), reference) .or_not_found()); } TypeDefinition::Enumeration(ref literals) => { @@ -830,14 +830,14 @@ fn search_pos_expr( match expr { Expression::Binary(ref op, ref left, ref right) => { return_if_found!(searcher - .search_pos_with_ref(ctx, &op.pos, &op.item.reference) + .search_pos_with_ref(ctx, op.pos(ctx), &op.item.reference) .or_not_found()); return_if_found!(left.search(ctx, searcher)); right.search(ctx, searcher) } Expression::Unary(ref op, ref expr) => { return_if_found!(searcher - .search_pos_with_ref(ctx, &op.pos, &op.item.reference) + .search_pos_with_ref(ctx, op.pos(ctx), &op.item.reference) .or_not_found()); expr.search(ctx, searcher) } @@ -845,7 +845,7 @@ fn search_pos_expr( Expression::Aggregate(ref assocs) => assocs.search(ctx, searcher), Expression::Qualified(ref qexpr) => qexpr.search(ctx, searcher), Expression::New(ref alloc) => { - return_if_finished!(searcher.search_with_pos(ctx, &alloc.pos)); + return_if_finished!(searcher.search_with_pos(ctx, &alloc.pos(ctx))); match alloc.item { Allocator::Qualified(ref qexpr) => qexpr.search(ctx, searcher), Allocator::Subtype(ref subtype) => subtype.search(ctx, searcher), @@ -888,12 +888,17 @@ impl Search for AssociationElement { fn search(&self, ctx: &dyn TokenAccess, searcher: &mut impl Searcher) -> SearchResult { let AssociationElement { formal, actual } = self; if let Some(formal) = formal { - return_if_found!(search_pos_name(&formal.pos, &formal.item, searcher, ctx)); + return_if_found!(search_pos_name( + &formal.pos(ctx), + &formal.item, + searcher, + ctx + )); } match actual.item { ActualPart::Expression(ref expr) => { - return_if_found!(search_pos_expr(ctx, &actual.pos, expr, searcher)); + return_if_found!(search_pos_expr(ctx, &actual.pos(ctx), expr, searcher)); } ActualPart::Open => {} } @@ -926,9 +931,9 @@ impl Search for Waveform { } } -impl Search for WithPos { +impl Search for WithTokenSpan { fn search(&self, ctx: &dyn TokenAccess, searcher: &mut impl Searcher) -> SearchResult { - search_pos_expr(ctx, &self.pos, &self.item, searcher) + search_pos_expr(ctx, &self.span.pos(ctx), &self.item, searcher) } } @@ -1004,7 +1009,7 @@ impl Search for Declaration { }) = entity_name { return_if_found!(searcher - .search_pos_with_ref(ctx, &designator.pos, &designator.item.reference) + .search_pos_with_ref(ctx, designator.pos(ctx), &designator.item.reference) .or_not_found()); if let Some(signature) = signature { return_if_found!(signature.item.search(ctx, searcher)); @@ -1097,7 +1102,7 @@ impl Search for ModeViewElement { fn search(&self, ctx: &dyn TokenAccess, searcher: &mut impl Searcher) -> SearchResult { for name in self.names.items.iter() { return_if_found!(searcher - .search_pos_with_ref(ctx, &name.item.pos, &name.reference) + .search_pos_with_ref(ctx, name.item.pos(ctx), &name.reference) .or_not_found()); } NotFound @@ -1224,7 +1229,7 @@ impl Search for LibraryClause { fn search(&self, ctx: &dyn TokenAccess, searcher: &mut impl Searcher) -> SearchResult { for name in self.name_list.items.iter() { return_if_found!(searcher - .search_pos_with_ref(ctx, &name.item.pos, &name.reference) + .search_pos_with_ref(ctx, name.item.pos(ctx), &name.reference) .or_not_found()); } NotFound @@ -1421,7 +1426,7 @@ impl<'a> Searcher for ItemAtCursor<'a> { } } - fn search_decl(&mut self, _ctx: &dyn TokenAccess, decl: FoundDeclaration) -> SearchState { + fn search_decl(&mut self, ctx: &dyn TokenAccess, decl: FoundDeclaration) -> SearchState { if let Some(id) = decl.ent_id() { let ent = self.root.get_ent(id); @@ -1432,7 +1437,7 @@ impl<'a> Searcher for ItemAtCursor<'a> { } if let Some(end_pos) = decl.end_ident_pos() { - return self.search_decl_pos(end_pos, ent); + return self.search_decl_pos(ctx.get_pos(end_pos), ent); } } NotFinished @@ -1621,7 +1626,7 @@ impl<'a> FindAllReferences<'a> { } impl<'a> Searcher for FindAllReferences<'a> { - fn search_decl(&mut self, _ctx: &dyn TokenAccess, decl: FoundDeclaration) -> SearchState { + fn search_decl(&mut self, ctx: &dyn TokenAccess, decl: FoundDeclaration) -> SearchState { if let Some(id) = decl.ent_id() { let other = self.root.get_ent(id); @@ -1630,7 +1635,7 @@ impl<'a> Searcher for FindAllReferences<'a> { self.references.push(decl_pos.clone()); } if let Some(pos) = decl.end_ident_pos() { - self.references.push(pos.clone()); + self.references.push(ctx.get_pos(pos).clone()); } } } @@ -1654,38 +1659,38 @@ impl<'a> Searcher for FindAllReferences<'a> { } impl<'a> FoundDeclaration<'a> { - fn end_ident_pos(&self) -> Option<&SrcPos> { + fn end_ident_pos(&self) -> Option { match self { FoundDeclaration::InterfaceObject(_) => None, FoundDeclaration::ForIndex(..) => None, FoundDeclaration::ForGenerateIndex(..) => None, - FoundDeclaration::Subprogram(value) => value.end_ident_pos.as_ref(), + FoundDeclaration::Subprogram(value) => value.end_ident_pos, FoundDeclaration::SubprogramDecl(..) => None, FoundDeclaration::Object(..) => None, FoundDeclaration::ElementDeclaration(..) => None, FoundDeclaration::EnumerationLiteral(..) => None, FoundDeclaration::File(..) => None, - FoundDeclaration::Type(value) => value.end_ident_pos.as_ref(), + FoundDeclaration::Type(value) => value.end_ident_pos, FoundDeclaration::InterfaceType(..) => None, FoundDeclaration::InterfacePackage(..) => None, FoundDeclaration::InterfaceFile(..) => None, FoundDeclaration::PhysicalTypePrimary(..) => None, FoundDeclaration::PhysicalTypeSecondary(..) => None, - FoundDeclaration::Component(value) => value.end_ident_pos.as_ref(), + FoundDeclaration::Component(value) => value.end_ident_pos, FoundDeclaration::Attribute(..) => None, FoundDeclaration::Alias(..) => None, - FoundDeclaration::Package(value) => value.end_ident_pos.as_ref(), - FoundDeclaration::PackageBody(value) => value.end_ident_pos.as_ref(), + FoundDeclaration::Package(value) => value.end_ident_pos, + FoundDeclaration::PackageBody(value) => value.end_ident_pos, FoundDeclaration::PackageInstance(..) => None, - FoundDeclaration::Configuration(value) => value.end_ident_pos.as_ref(), - FoundDeclaration::Entity(value) => value.end_ident_pos.as_ref(), - FoundDeclaration::Architecture(value) => value.end_ident_pos.as_ref(), - FoundDeclaration::Context(value) => value.end_ident_pos.as_ref(), + FoundDeclaration::Configuration(value) => value.end_ident_pos, + FoundDeclaration::Entity(value) => value.end_ident_pos, + FoundDeclaration::Architecture(value) => value.end_ident_pos, + FoundDeclaration::Context(value) => value.end_ident_pos, FoundDeclaration::GenerateBody(..) => None, FoundDeclaration::ConcurrentStatement(..) => None, FoundDeclaration::SequentialStatement(..) => None, FoundDeclaration::SubprogramInstantiation(_) => None, - FoundDeclaration::View(view) => view.end_ident_pos.as_ref(), + FoundDeclaration::View(view) => view.end_ident_pos, } } @@ -1894,7 +1899,8 @@ pub fn clear_references(tree: &mut impl Search, ctx: &dyn TokenAccess) { } #[cfg(test)] -pub fn check_no_unresolved(tree: &mut impl Search) { +#[allow(clippy::ptr_arg)] +pub fn check_no_unresolved(tree: &mut impl Search, tokens: &Vec) { #[derive(Default)] struct CheckNoUnresolved; @@ -1911,6 +1917,5 @@ pub fn check_no_unresolved(tree: &mut impl Search) { } let mut searcher = CheckNoUnresolved; - let tokens: Vec = Vec::new(); - let _ = tree.search(&tokens, &mut searcher); + let _ = tree.search(tokens, &mut searcher); } diff --git a/vhdl_lang/src/ast/token_range.rs b/vhdl_lang/src/ast/token_range.rs new file mode 100644 index 00000000..5d924af2 --- /dev/null +++ b/vhdl_lang/src/ast/token_range.rs @@ -0,0 +1,114 @@ +/// For most applications in the context of a language server, +/// the lexical position (i.e., a position in the source code) +/// of all AST nodes must be known. +/// In the context of `vhdl_lang`, this information is provided +/// using Token information. Each AST element knows the token span that it was declared in. +/// Information, such as the position can be queried using the `pos(TokenAccess)` method. +/// A [TokenAccess] is a context object that is passed in all relevant operations +/// (i.e., when traversing the AST using the [Search] trait +/// or when getting the source code information when generating code outlines in a language server). +/// This is also the mechanic used to extract supplementary information, such as comments for +/// documentation generation. +use crate::{SrcPos, TokenAccess, TokenId, TokenSpan}; + +/// A struct that associates some generic item to a single token. +#[derive(Eq, PartialEq, Debug, Clone)] +pub struct WithToken { + pub item: T, + pub token: TokenId, +} + +impl WithToken { + pub fn new(item: T, token: TokenId) -> WithToken { + WithToken { item, token } + } + + /// Retrieves the position of this object using the provided `TokenAccess`. + pub fn pos<'a>(&'a self, ctx: &'a dyn TokenAccess) -> &'a SrcPos { + ctx.get_pos(self.token) + } + + /// Maps this element into another element applying the given function + /// but retaining the source location (i.e., the token). + pub(crate) fn map_into(self, f: F) -> WithToken + where + F: FnOnce(T) -> U, + { + WithToken { + item: f(self.item), + token: self.token, + } + } + + /// Maps this element into another element applying the given function + /// but retaining the source location. + /// The returned object's `TokenSpan` will have this token id as start and end. + pub(crate) fn map_into_span(self, f: F) -> WithTokenSpan + where + F: FnOnce(T) -> U, + { + WithTokenSpan { + item: f(self.item), + span: self.token.into(), + } + } +} + +/// A struct that associates some generic item to a contiguous span of tokens. +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct WithTokenSpan { + pub item: T, + pub span: TokenSpan, +} + +impl WithTokenSpan { + pub fn new(item: T, span: TokenSpan) -> WithTokenSpan { + WithTokenSpan { item, span } + } + + pub fn from(item: T, span: impl Into) -> WithTokenSpan { + WithTokenSpan { + item, + span: span.into(), + } + } + + /// Retrieves the position of this object using the provided `TokenAccess`. + pub fn pos(&self, ctx: &dyn TokenAccess) -> SrcPos { + self.span.pos(ctx) + } + + /// Maps this element into another element applying the given function + /// but retaining the source location (i.e., the token span). + pub(crate) fn map_into(self, f: F) -> WithTokenSpan + where + F: FnOnce(T) -> U, + { + WithTokenSpan { + item: f(self.item), + span: self.span, + } + } + + /// Attempts to map this element into another element applying the given function. + /// If the function returns `None`, this will also return `None`. + /// Otherwise, the semantics are the same as [map_into](WithTokenSpan::map_into) + pub(crate) fn try_map_into(self, f: F) -> Option> + where + F: FnOnce(T) -> Option, + { + Some(WithTokenSpan { + item: f(self.item)?, + span: self.span, + }) + } + + /// Returns a new `WithTokenSpan` object that encompasses this item + /// but extends the token span starting with the given token. + pub(crate) fn start_with(self, id: TokenId) -> Self { + WithTokenSpan { + item: self.item, + span: self.span.start_with(id), + } + } +} diff --git a/vhdl_lang/src/ast/util.rs b/vhdl_lang/src/ast/util.rs index d206f7f0..9d527bca 100644 --- a/vhdl_lang/src/ast/util.rs +++ b/vhdl_lang/src/ast/util.rs @@ -9,33 +9,34 @@ use super::*; use crate::data::error_codes::ErrorCode; use crate::data::*; use crate::named_entity::{Concurrent, Sequential}; +use crate::TokenSpan; -impl WithPos { - pub fn suffix_pos(&self) -> &SrcPos { +impl WithTokenSpan { + pub fn suffix_pos(&self) -> TokenSpan { match self.item { - Name::Designator(..) => &self.pos, - Name::Selected(_, ref suffix) => &suffix.pos, + Name::Designator(..) => self.span, + Name::Selected(_, ref suffix) => suffix.token.into(), // @TODO add pos of .all? - Name::SelectedAll(ref prefix) => &prefix.pos, - Name::CallOrIndexed(ref fcall) => fcall.name.suffix_pos(), - Name::Slice(ref prefix, ..) => prefix.suffix_pos(), - Name::Attribute(ref attr, ..) => attr.name.suffix_pos(), - Name::External(..) => &self.pos, + Name::SelectedAll(ref prefix) => prefix.span, + Name::CallOrIndexed(ref fcall) => fcall.name.span, + Name::Slice(ref prefix, ..) => prefix.span, + Name::Attribute(ref attr, ..) => attr.name.span, + Name::External(..) => self.span, } } } -pub fn to_simple_name(name: WithPos) -> DiagnosticResult { +pub fn to_simple_name(ctx: &dyn TokenAccess, name: WithTokenSpan) -> DiagnosticResult { match name.item { Name::Designator(WithRef { item: Designator::Identifier(ident), .. - }) => Ok(WithPos { + }) => Ok(WithToken { item: ident, - pos: name.pos, + token: name.span.start_token, }), _ => Err(Diagnostic::new( - &name, + &name.span.pos(ctx), "Expected simple name", ErrorCode::SyntaxError, )), @@ -65,7 +66,7 @@ pub trait HasDesignator { fn designator(&self) -> &Designator; } -impl HasDesignator for WithPos { +impl HasDesignator for WithTokenSpan { fn designator(&self) -> &Designator { self.item.designator() } @@ -95,8 +96,14 @@ impl Ident { } } -impl WithPos { - pub fn into_ref(self) -> WithPos> { +impl WithTokenSpan { + pub fn into_ref(self) -> WithTokenSpan> { + self.map_into(|name| name.into_ref()) + } +} + +impl WithToken { + pub fn into_ref(self) -> WithToken> { self.map_into(|name| name.into_ref()) } } @@ -106,11 +113,9 @@ pub trait HasIdent { fn name(&self) -> &Symbol { &self.ident().item } -} -impl HasSrcPos for T { - fn pos(&self) -> &SrcPos { - &self.ident().pos + fn ident_pos<'a>(&'a self, ctx: &'a dyn TokenAccess) -> &SrcPos { + self.ident().pos(ctx) } } @@ -198,8 +203,8 @@ impl HasIdent for AnyDesignUnit { } } -impl<'a, T: HasIdent> From<&'a T> for WithPos { - fn from(other: &'a T) -> WithPos { +impl<'a, T: HasIdent> From<&'a T> for WithToken { + fn from(other: &'a T) -> WithToken { other.ident().to_owned().map_into(Designator::Identifier) } } @@ -248,8 +253,8 @@ impl From for Designator { } } -impl From> for WithPos { - fn from(other: WithPos) -> WithPos { +impl From> for WithTokenSpan { + fn from(other: WithTokenSpan) -> WithTokenSpan { other.map_into(|sym| sym.into()) } } @@ -270,10 +275,10 @@ impl SubprogramDesignator { } impl SubprogramSpecification { - pub fn pos(&self) -> &SrcPos { + pub fn token(&self) -> TokenId { match self { - SubprogramSpecification::Function(ref function) => &function.designator.tree.pos, - SubprogramSpecification::Procedure(ref procedure) => &procedure.designator.tree.pos, + SubprogramSpecification::Function(ref function) => function.designator.tree.token, + SubprogramSpecification::Procedure(ref procedure) => procedure.designator.tree.token, } } } @@ -369,7 +374,7 @@ impl CallOrIndexed { for elem in parameters.iter_mut() { if let ActualPart::Expression(ref mut expr) = &mut elem.actual.item { indexes.push(Index { - pos: &elem.actual.pos, + pos: elem.actual.span, expr, }); } @@ -386,12 +391,12 @@ impl CallOrIndexed { } pub struct IndexedName<'a> { - pub name: &'a mut WithPos, + pub name: &'a mut WithTokenSpan, pub indexes: Vec>, } pub struct Index<'a> { - pub pos: &'a SrcPos, + pub pos: TokenSpan, pub expr: &'a mut Expression, } @@ -418,32 +423,32 @@ impl AttributeName { } impl RangeConstraint { - pub fn pos(&self) -> SrcPos { - self.left_expr.pos.combine(&self.right_expr.pos) + pub fn span(&self) -> TokenSpan { + self.left_expr.span.combine(self.right_expr.span) } } impl crate::ast::Range { - pub fn pos(&self) -> SrcPos { + pub fn span(&self) -> TokenSpan { use crate::ast::Range::*; match self { - Range(constraint) => constraint.pos(), - Attribute(attr) => attr.name.pos.combine(&attr.attr.pos), + Range(constraint) => constraint.span(), + Attribute(attr) => attr.name.span.end_with(attr.attr.token), } } } impl DiscreteRange { - pub fn pos(&self) -> SrcPos { + pub fn span(&self) -> TokenSpan { match self { - DiscreteRange::Discrete(type_mark, _) => type_mark.pos.clone(), - DiscreteRange::Range(range) => range.pos(), + DiscreteRange::Discrete(type_mark, _) => type_mark.span, + DiscreteRange::Range(range) => range.span(), } } } impl SubprogramSpecification { - pub fn subpgm_designator(&self) -> &WithPos { + pub fn subpgm_designator(&self) -> &WithToken { match self { SubprogramSpecification::Procedure(s) => &s.designator.tree, SubprogramSpecification::Function(s) => &s.designator.tree, @@ -459,7 +464,7 @@ impl SubprogramSpecification { } impl SubprogramDeclaration { - pub fn subpgm_designator(&self) -> &WithPos { + pub fn subpgm_designator(&self) -> &WithToken { self.specification.subpgm_designator() } diff --git a/vhdl_lang/src/completion.rs b/vhdl_lang/src/completion.rs index d22fb6e4..7ff5b98e 100644 --- a/vhdl_lang/src/completion.rs +++ b/vhdl_lang/src/completion.rs @@ -390,7 +390,7 @@ impl<'a> Searcher for CompletionSearcher<'a> { } // Early-exit for when we are inside a statement. for statement in &body.statements { - let pos = &statement.statement.pos; + let pos = &statement.statement.pos(ctx); // Early exit. The cursor is below the current statement. if pos.start() > self.cursor { diff --git a/vhdl_lang/src/data/source.rs b/vhdl_lang/src/data/source.rs index 8cb6578b..965ee26f 100644 --- a/vhdl_lang/src/data/source.rs +++ b/vhdl_lang/src/data/source.rs @@ -276,74 +276,12 @@ impl PartialOrd for SrcPos { } } -/// A generic object with an associated source file and lexical range. -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct WithPos { - pub item: T, - pub pos: SrcPos, -} - -impl WithPos { - pub fn new(item: T, pos: impl AsRef) -> WithPos { - WithPos { - item, - pos: pos.as_ref().clone(), - } - } - - pub fn from(item: T, pos: impl Into) -> WithPos { - WithPos { - item, - pos: pos.into(), - } - } - - pub fn map_into(self, f: F) -> WithPos - where - F: FnOnce(T) -> U, - { - WithPos { - item: f(self.item), - pos: self.pos, - } - } - - pub fn try_map_into(self, f: F) -> Option> - where - F: FnOnce(T) -> Option, - { - Some(WithPos { - item: f(self.item)?, - pos: self.pos, - }) - } - - pub fn combine_pos_with(self, other: &dyn AsRef) -> Self { - WithPos { - item: self.item, - pos: self.pos.combine_into(other.as_ref()), - } - } -} - -impl AsRef for WithPos { - fn as_ref(&self) -> &SrcPos { - &self.pos - } -} - impl AsRef for SrcPos { fn as_ref(&self) -> &SrcPos { self } } -impl From> for SrcPos { - fn from(with_pos: WithPos) -> SrcPos { - with_pos.pos - } -} - impl SrcPos { const LINE_CONTEXT: u32 = 2; diff --git a/vhdl_lang/src/named_entity.rs b/vhdl_lang/src/named_entity.rs index 73b657df..c6902daf 100644 --- a/vhdl_lang/src/named_entity.rs +++ b/vhdl_lang/src/named_entity.rs @@ -32,8 +32,9 @@ mod region; pub(crate) use region::RegionKind; pub use region::{AsUnique, NamedEntities, OverloadedName, Region, SetReference}; mod formal_region; +use crate::ast::token_range::WithToken; use crate::data::error_codes::ErrorCode; -use crate::TokenSpan; +use crate::{TokenAccess, TokenSpan}; pub use formal_region::{ FormalRegion, GpkgInterfaceEnt, GpkgRegion, InterfaceClass, InterfaceEnt, RecordElement, RecordRegion, @@ -218,6 +219,7 @@ impl Arena { pub fn define<'a, T: HasIdent>( &'a self, + ctx: &dyn TokenAccess, decl: &mut WithDecl, parent: EntRef<'a>, kind: AnyEntKind<'a>, @@ -227,7 +229,7 @@ impl Arena { decl.tree.name().clone(), parent, kind, - Some(decl.tree.pos()), + Some(decl.tree.ident_pos(ctx)), src_span, ); decl.decl.set(ent.id()); @@ -703,6 +705,7 @@ impl HasEntityId for ModeViewDeclaration { impl WithDecl { pub fn define<'a>( &mut self, + ctx: &dyn TokenAccess, arena: &'a Arena, parent: EntRef<'a>, kind: AnyEntKind<'a>, @@ -712,7 +715,7 @@ impl WithDecl { self.tree.name().clone(), parent, kind, - Some(self.tree.pos()), + Some(self.tree.pos(ctx)), src_span, ); self.decl.set(ent.id()); @@ -720,9 +723,10 @@ impl WithDecl { } } -impl WithDecl> { +impl WithDecl> { pub fn define<'a>( &mut self, + ctx: &dyn TokenAccess, arena: &'a Arena, parent: EntRef<'a>, kind: AnyEntKind<'a>, @@ -732,7 +736,7 @@ impl WithDecl> { self.tree.item.clone(), parent, kind, - Some(&self.tree.pos), + Some(self.tree.pos(ctx)), src_span, ); self.decl.set(ent.id()); diff --git a/vhdl_lang/src/named_entity/design.rs b/vhdl_lang/src/named_entity/design.rs index ef182d0a..2f632688 100644 --- a/vhdl_lang/src/named_entity/design.rs +++ b/vhdl_lang/src/named_entity/design.rs @@ -10,10 +10,8 @@ use super::*; use crate::ast::Designator; use crate::ast::HasDesignator; use crate::ast::WithRef; -use crate::data::WithPos; use crate::named_entity::visibility::Visibility; use crate::Diagnostic; -use crate::SrcPos; pub enum Design<'a> { Entity(Visibility<'a>, Region<'a>), @@ -78,8 +76,9 @@ impl<'a> DesignEnt<'a> { pub fn selected( &self, - prefix_pos: &SrcPos, - suffix: &WithPos>, + ctx: &dyn TokenAccess, + prefix_pos: TokenSpan, + suffix: &WithToken>, ) -> Result, Diagnostic> { match self.kind() { Design::Package(_, ref region) @@ -90,12 +89,15 @@ impl<'a> DesignEnt<'a> { } else { Err(Diagnostic::no_declaration_within( self, - &suffix.pos, + suffix.pos(ctx), &suffix.item.item, )) } } - _ => Err(Diagnostic::invalid_selected_name_prefix(self, prefix_pos)), + _ => Err(Diagnostic::invalid_selected_name_prefix( + self, + &prefix_pos.pos(ctx), + )), } } } diff --git a/vhdl_lang/src/named_entity/region.rs b/vhdl_lang/src/named_entity/region.rs index 342d5b6c..53c33906 100644 --- a/vhdl_lang/src/named_entity/region.rs +++ b/vhdl_lang/src/named_entity/region.rs @@ -5,6 +5,7 @@ // Copyright (c) 2023, Olof Kraigher olof.kraigher@gmail.com use super::*; +use crate::ast::token_range::WithTokenSpan; use crate::ast::*; use crate::named_entity::overloaded::SubprogramKey; use fnv::FnvHashMap; @@ -417,7 +418,13 @@ impl SetReference for WithRef { } } -impl SetReference for WithPos { +impl SetReference for WithTokenSpan { + fn set_unique_reference(&mut self, ent: &AnyEnt) { + self.item.set_unique_reference(ent); + } +} + +impl SetReference for WithToken { fn set_unique_reference(&mut self, ent: &AnyEnt) { self.item.set_unique_reference(ent); } diff --git a/vhdl_lang/src/named_entity/types.rs b/vhdl_lang/src/named_entity/types.rs index 15282555..8cb5ba38 100644 --- a/vhdl_lang/src/named_entity/types.rs +++ b/vhdl_lang/src/named_entity/types.rs @@ -8,8 +8,7 @@ use std::ops::Deref; use super::*; use crate::ast::{Designator, HasDesignator, Ident, WithDecl, WithRef}; -use crate::data::WithPos; -use crate::{Diagnostic, SrcPos}; +use crate::Diagnostic; use fnv::FnvHashSet; @@ -82,6 +81,7 @@ pub struct TypeEnt<'a>(EntRef<'a>); impl<'a> TypeEnt<'a> { pub fn define_with_opt_id( + ctx: &dyn TokenAccess, arena: &'a Arena, id: Option, ident: &mut WithDecl, @@ -103,7 +103,7 @@ impl<'a> TypeEnt<'a> { Some(parent), related, AnyEntKind::Type(kind), - Some(ident.tree.pos.clone()), + Some(ident.pos(ctx).clone()), None, ) } @@ -113,7 +113,7 @@ impl<'a> TypeEnt<'a> { Some(parent), related, AnyEntKind::Type(kind), - Some(ident.tree.pos.clone()), + Some(ident.pos(ctx).clone()), None, ) }; @@ -187,8 +187,9 @@ impl<'a> TypeEnt<'a> { /// where prefix has this type pub fn selected( self, - prefix_pos: &SrcPos, - suffix: &WithPos>, + ctx: &dyn TokenAccess, + prefix_pos: TokenSpan, + suffix: &WithToken>, ) -> Result, Diagnostic> { match self.kind() { Type::Record(ref region) => { @@ -197,7 +198,7 @@ impl<'a> TypeEnt<'a> { } else { Err(Diagnostic::no_declaration_within( &self, - &suffix.pos, + suffix.pos(ctx), &suffix.item.item, )) } @@ -206,7 +207,7 @@ impl<'a> TypeEnt<'a> { if let Some(decl) = region.lookup_immediate(suffix.designator()) { match decl { NamedEntities::Single(ent) => Err(Diagnostic::new( - &suffix.pos, + suffix.pos(ctx), format!( "Protected type selection must be a method, got {}", ent.describe() @@ -220,19 +221,19 @@ impl<'a> TypeEnt<'a> { } else { Err(Diagnostic::no_declaration_within( &self, - &suffix.pos, + suffix.pos(ctx), &suffix.item.item, )) } } Type::Incomplete => Err(Diagnostic::new( - prefix_pos, + prefix_pos.pos(ctx), "Cannot select incomplete type before full type definition", ErrorCode::MismatchedKinds, )), - Type::Subtype(subtype) => subtype.type_mark().selected(prefix_pos, suffix), - Type::Access(subtype, ..) => subtype.type_mark().selected(prefix_pos, suffix), - Type::Alias(alias) => alias.selected(prefix_pos, suffix), + Type::Subtype(subtype) => subtype.type_mark().selected(ctx, prefix_pos, suffix), + Type::Access(subtype, ..) => subtype.type_mark().selected(ctx, prefix_pos, suffix), + Type::Alias(alias) => alias.selected(ctx, prefix_pos, suffix), Type::Array { .. } | Type::File { .. } | Type::Interface { .. } @@ -240,7 +241,10 @@ impl<'a> TypeEnt<'a> { | Type::Physical { .. } | Type::Universal { .. } | Type::Integer { .. } - | Type::Real { .. } => Err(Diagnostic::invalid_selected_name_prefix(&self, prefix_pos)), + | Type::Real { .. } => Err(Diagnostic::invalid_selected_name_prefix( + &self, + &prefix_pos.pos(ctx), + )), } } diff --git a/vhdl_lang/src/named_entity/visibility.rs b/vhdl_lang/src/named_entity/visibility.rs index 5b7db6c7..de82b1a3 100644 --- a/vhdl_lang/src/named_entity/visibility.rs +++ b/vhdl_lang/src/named_entity/visibility.rs @@ -177,7 +177,8 @@ impl<'a> Visible<'a> { pub fn into_unambiguous( self, - pos: &SrcPos, + ctx: &dyn TokenAccess, + span: TokenSpan, designator: &Designator, ) -> Result>, Diagnostic> { let mut named_entities: Vec<_> = self @@ -200,7 +201,7 @@ impl<'a> Visible<'a> { } else { // Duplicate visible items hide each other let mut error = Diagnostic::new( - pos, + span.pos(ctx), format!("Name '{designator}' is hidden by conflicting use clause"), ErrorCode::ConflictingUseClause, ); diff --git a/vhdl_lang/src/syntax/attributes.rs b/vhdl_lang/src/syntax/attributes.rs index 046018f9..3db76d7f 100644 --- a/vhdl_lang/src/syntax/attributes.rs +++ b/vhdl_lang/src/syntax/attributes.rs @@ -37,15 +37,16 @@ fn parse_entity_class(ctx: &mut ParsingContext<'_>) -> ParseResult } pub fn parse_entity_name_list(ctx: &mut ParsingContext<'_>) -> ParseResult> { - Ok(expect_token!(ctx.stream, token, + Ok(expect_token!(ctx.stream, token, token_id, Identifier | StringLiteral => { let mut entity_name_list = Vec::new(); let mut token = token; + let mut token_id = token_id; loop { let designator = match token.kind { - Identifier => token.to_identifier_value()?.map_into(Designator::Identifier), - StringLiteral => token.to_operator_symbol()?.map_into(Designator::OperatorSymbol), + Identifier => token.to_identifier_value(token_id)?.map_into(Designator::Identifier), + StringLiteral => token.to_operator_symbol(token_id)?.map_into(Designator::OperatorSymbol), _ => unreachable!(""), }; @@ -63,6 +64,7 @@ pub fn parse_entity_name_list(ctx: &mut ParsingContext<'_>) -> ParseResult token); } else { break entity_name_list; @@ -118,6 +120,7 @@ pub fn parse_attribute(ctx: &mut ParsingContext<'_>) -> ParseResult( @@ -33,15 +33,15 @@ where pub fn check_end_identifier_mismatch( ctx: &mut ParsingContext, - ident: &WithPos, - end_ident: Option>, -) -> Option { + ident: &WithToken, + end_ident: Option>, +) -> Option { if let Some(end_ident) = end_ident { if ident.item == end_ident.item { - return Some(end_ident.pos); + return Some(end_ident.token); } else { ctx.diagnostics.push(Diagnostic::syntax_error( - &end_ident.pos, + end_ident.pos(ctx), format!("End identifier mismatch, expected {}", ident.item), )); } @@ -57,17 +57,17 @@ pub fn check_label_identifier_mismatch( if let Some(ident) = label { if let Some(end_ident) = end_ident { if ident.item == end_ident.item { - return Some(end_ident.pos); + return Some(end_ident.pos(ctx).clone()); } else { ctx.diagnostics.push(Diagnostic::syntax_error( - &end_ident.pos, + end_ident.pos(ctx), format!("End label mismatch, expected {}", ident.item), )); } } } else if let Some(end_ident) = end_ident { ctx.diagnostics.push(Diagnostic::syntax_error( - &end_ident.pos, + end_ident.pos(ctx), format!( "End label '{}' found for unlabeled statement", end_ident.item diff --git a/vhdl_lang/src/syntax/component_declaration.rs b/vhdl_lang/src/syntax/component_declaration.rs index 95640c92..03ed4d60 100644 --- a/vhdl_lang/src/syntax/component_declaration.rs +++ b/vhdl_lang/src/syntax/component_declaration.rs @@ -105,7 +105,7 @@ mod tests { use crate::ast::Ident; use crate::syntax::test::Code; - use crate::SrcPos; + use crate::TokenId; use crate::VHDLStandard::VHDL2019; fn to_component( @@ -113,7 +113,7 @@ mod tests { span: TokenSpan, generic_list: Vec, port_list: Vec, - end_ident_pos: Option, + end_ident_pos: Option, ) -> ComponentDeclaration { ComponentDeclaration { span, @@ -176,7 +176,7 @@ end component foo; code.token_span(), vec![], vec![], - Some(code.s("foo", 2).pos()) + Some(code.s("foo", 2).token()) ) ); } diff --git a/vhdl_lang/src/syntax/concurrent_statement.rs b/vhdl_lang/src/syntax/concurrent_statement.rs index b1caacad..3381449b 100644 --- a/vhdl_lang/src/syntax/concurrent_statement.rs +++ b/vhdl_lang/src/syntax/concurrent_statement.rs @@ -19,6 +19,7 @@ use super::sequential_statement::{ }; use super::tokens::Kind::*; use super::waveform::{parse_delay_mechanism, parse_waveform}; +use crate::ast::token_range::WithTokenSpan; use crate::ast::*; use crate::data::*; use crate::syntax::{Kind, TokenAccess}; @@ -241,26 +242,27 @@ pub fn parse_process_statement( } fn to_procedure_call( - target: WithPos, + ctx: &mut ParsingContext<'_>, + target: WithTokenSpan, postponed: bool, ) -> ParseResult { match target.item { Target::Name(Name::CallOrIndexed(call)) => Ok(ConcurrentProcedureCall { postponed, - call: WithPos::new(*call, target.pos), + call: WithTokenSpan::new(*call, target.span), }), Target::Name(name) => Ok(ConcurrentProcedureCall { postponed, - call: WithPos::from( + call: WithTokenSpan::new( CallOrIndexed { - name: WithPos::from(name, target.pos.clone()), + name: WithTokenSpan::new(name, target.span), parameters: vec![], }, - target.pos, + target.span, ), }), Target::Aggregate(..) => Err(Diagnostic::syntax_error( - target, + target.pos(ctx.stream), "Expected procedure call, got aggregate", )), } @@ -269,7 +271,7 @@ fn to_procedure_call( /// Assume target and <= is parsed already fn parse_assignment_known_target( ctx: &mut ParsingContext<'_>, - target: WithPos, + target: WithTokenSpan, ) -> ParseResult { // @TODO postponed let postponed = false; @@ -289,14 +291,14 @@ fn parse_assignment_known_target( fn parse_assignment_or_procedure_call( ctx: &mut ParsingContext<'_>, - target: WithPos, + target: WithTokenSpan, ) -> ParseResult { expect_token!(ctx.stream, token, LTE => { parse_assignment_known_target(ctx, target) }, SemiColon => { - Ok(ConcurrentStatement::ProcedureCall(to_procedure_call(target, false)?)) + Ok(ConcurrentStatement::ProcedureCall(to_procedure_call(ctx, target, false)?)) }) } @@ -460,7 +462,7 @@ fn parse_if_generate_statement( let mut condition = parse_expression(ctx)?; let mut alternative_label = None; if ctx.stream.skip_if_kind(Colon) { - alternative_label = Some(WithDecl::new(expression_to_ident(condition)?)); + alternative_label = Some(WithDecl::new(expression_to_ident(ctx, condition)?)); condition = parse_expression(ctx)?; } ctx.stream.expect_kind(Generate)?; @@ -486,13 +488,14 @@ fn parse_if_generate_statement( let alternative_label = expect_token!( ctx.stream, token, + token_id, Generate => { None }, Identifier => { ctx.stream.expect_kind(Colon)?; ctx.stream.expect_kind(Generate)?; - Some(WithDecl::new(token.to_identifier_value()?)) + Some(WithDecl::new(token.to_identifier_value(token_id)?)) } ); let body = parse_generate_body(ctx, alternative_label)?; @@ -623,7 +626,7 @@ pub fn parse_concurrent_statement( _ => { let target = parse_name(ctx)?.map_into(Target::Name); ctx.stream.expect_kind(SemiColon)?; - ConcurrentStatement::ProcedureCall(to_procedure_call(target, true)?) + ConcurrentStatement::ProcedureCall(to_procedure_call(ctx, target, true)?) } } }, @@ -633,7 +636,7 @@ pub fn parse_concurrent_statement( let token = ctx.stream.peek_expect()?; match token.kind { Generic|Port => { - name.expect_selected()?; + name.expect_selected(ctx)?; let unit = InstantiatedUnit::Component(name); ConcurrentStatement::Instance(parse_instantiation_statement(ctx, start_tok, unit)?) } @@ -685,37 +688,37 @@ pub fn parse_labeled_concurrent_statements( pub fn parse_labeled_concurrent_statement( ctx: &mut ParsingContext<'_>, ) -> ParseResult { - let start = ctx.stream.peek_expect()?; + let start_pos = ctx.stream.get_current_token_id(); if ctx.stream.next_kind_is(Identifier) { let name = parse_name(ctx)?; if ctx.stream.skip_if_kind(Colon) { - let label = Some(to_simple_name(name)?); + let label = Some(to_simple_name(ctx.stream, name)?); - let start = ctx.stream.peek_expect()?; + let start_pos = ctx.stream.get_current_token_id(); let statement = parse_concurrent_statement(ctx, label.as_ref())?; - let end = ctx.stream.last().unwrap(); + let end_pos = ctx.stream.get_last_token_id(); Ok(LabeledConcurrentStatement { label: WithDecl::new(label), - statement: WithPos::new(statement, start.pos.combine(&end.pos)), + statement: WithTokenSpan::new(statement, TokenSpan::new(start_pos, end_pos)), }) } else { let target = name.map_into(Target::Name); let statement = parse_assignment_or_procedure_call(ctx, target)?; - let end = ctx.stream.last().unwrap(); + let end_pos = ctx.stream.get_last_token_id(); Ok(LabeledConcurrentStatement { label: WithDecl::new(None), - statement: WithPos::new(statement, start.pos.combine(&end.pos)), + statement: WithTokenSpan::new(statement, TokenSpan::new(start_pos, end_pos)), }) } } else { let statement = parse_concurrent_statement(ctx, None)?; - let end = ctx.stream.last().unwrap(); + let end_pos = ctx.stream.get_last_token_id(); Ok(LabeledConcurrentStatement { label: WithDecl::new(None), - statement: WithPos::new(statement, start.pos.combine(&end.pos)), + statement: WithTokenSpan::new(statement, TokenSpan::new(start_pos, end_pos)), }) } } @@ -740,7 +743,7 @@ mod tests { assert_eq!(stmt.label.tree, None); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::ProcedureCall(call), code.pos()) + WithTokenSpan::new(ConcurrentStatement::ProcedureCall(call), code.token_span()) ); } @@ -755,7 +758,7 @@ mod tests { assert_eq!(stmt.label.tree, None); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::ProcedureCall(call), code.pos()) + WithTokenSpan::new(ConcurrentStatement::ProcedureCall(call), code.token_span()) ); } @@ -770,9 +773,9 @@ mod tests { assert_eq!(stmt.label.tree, Some(code.s1("name").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::ProcedureCall(call), - code.s1("foo(clk);") + code.s1("foo(clk);").token_span() ) ); } @@ -788,7 +791,7 @@ mod tests { assert_eq!(stmt.label.tree, None); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::ProcedureCall(call), code.pos()) + WithTokenSpan::new(ConcurrentStatement::ProcedureCall(call), code.token_span()) ); } @@ -818,9 +821,9 @@ end block;", decl: code.s1("constant const : natural := 0;").declarative_part(), statements: vec![LabeledConcurrentStatement { label: Some(code.s1("name2").ident()).into(), - statement: WithPos::new( + statement: WithTokenSpan::new( ConcurrentStatement::ProcedureCall(call), - code.s1("foo(clk);").pos(), + code.s1("foo(clk);").token_span(), ), }], end_label_pos: None, @@ -830,7 +833,10 @@ end block;", assert_eq!(stmt.label.tree, Some(code.s1("name").ident())); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Block(block), code.pos_after("name : ")) + WithTokenSpan::new( + ConcurrentStatement::Block(block), + code.pos_after("name : ").token_span() + ) ); } @@ -859,7 +865,10 @@ end block name;", assert_eq!(stmt.label.tree, Some(code.s1("name").ident())); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Block(block), code.pos_after("name : ")) + WithTokenSpan::new( + ConcurrentStatement::Block(block), + code.pos_after("name : ").token_span() + ) ); } @@ -888,7 +897,10 @@ end block;", assert_eq!(stmt.label.tree, Some(code.s1("name").ident())); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Block(block), code.pos_after("name : ")) + WithTokenSpan::new( + ConcurrentStatement::Block(block), + code.pos_after("name : ").token_span() + ) ); } @@ -917,7 +929,10 @@ end block;", assert_eq!(stmt.label.tree, Some(code.s1("name").ident())); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Block(block), code.pos_after("name : ")) + WithTokenSpan::new( + ConcurrentStatement::Block(block), + code.pos_after("name : ").token_span() + ) ); } @@ -950,7 +965,10 @@ end block;", assert_eq!(stmt.label.tree, Some(code.s1("name").ident())); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Block(block), code.pos_after("name: ")) + WithTokenSpan::new( + ConcurrentStatement::Block(block), + code.pos_after("name: ").token_span() + ) ); } @@ -974,7 +992,7 @@ end process;", assert_eq!(stmt.label.tree, None); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Process(process), code.pos()) + WithTokenSpan::new(ConcurrentStatement::Process(process), code.token_span()) ); } @@ -998,9 +1016,9 @@ end process name;", assert_eq!(stmt.label.tree, Some(code.s1("name").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::Process(process), - code.pos_after("name : ") + code.pos_after("name : ").token_span() ) ); } @@ -1025,7 +1043,7 @@ end process;", assert_eq!(stmt.label.tree, None); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Process(process), code.pos()) + WithTokenSpan::new(ConcurrentStatement::Process(process), code.token_span()) ); } @@ -1049,7 +1067,7 @@ end postponed process;", assert_eq!(stmt.label.tree, None); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Process(process), code.pos()) + WithTokenSpan::new(ConcurrentStatement::Process(process), code.token_span()) ); } @@ -1079,7 +1097,7 @@ end postponed process;", ); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Process(process), code.pos()) + WithTokenSpan::new(ConcurrentStatement::Process(process), code.token_span()) ); } @@ -1106,7 +1124,7 @@ end process;", assert_eq!(stmt.label.tree, None); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Process(process), code.pos()) + WithTokenSpan::new(ConcurrentStatement::Process(process), code.token_span()) ); } @@ -1136,7 +1154,7 @@ end process;", ); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Process(process), code.pos()) + WithTokenSpan::new(ConcurrentStatement::Process(process), code.token_span()) ); } @@ -1166,7 +1184,7 @@ end process;", assert_eq!(stmt.label.tree, None); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Process(process), code.pos()) + WithTokenSpan::new(ConcurrentStatement::Process(process), code.token_span()) ); } @@ -1185,7 +1203,7 @@ end process;", assert_eq!(stmt.label.tree, None); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Assert(assert), code.pos()) + WithTokenSpan::new(ConcurrentStatement::Assert(assert), code.token_span()) ); } @@ -1204,7 +1222,7 @@ end process;", assert_eq!(stmt.label.tree, None); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Assert(assert), code.pos()) + WithTokenSpan::new(ConcurrentStatement::Assert(assert), code.token_span()) ); } @@ -1222,7 +1240,7 @@ end process;", assert_eq!(stmt.label.tree, None); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Assignment(assign), code.pos()) + WithTokenSpan::new(ConcurrentStatement::Assignment(assign), code.token_span()) ); } @@ -1243,7 +1261,7 @@ end process;", assert_eq!(stmt.label.tree, None); assert_eq!( stmt.statement, - WithPos::new(ConcurrentStatement::Assignment(assign), code.pos()) + WithTokenSpan::new(ConcurrentStatement::Assignment(assign), code.token_span()) ); } @@ -1275,7 +1293,7 @@ with x(0) + 1 select rhs: AssignmentRightHand::Selected(selection) }) ); - assert_eq!(stmt.statement.pos, code.pos()); + assert_eq!(stmt.statement.span, code.token_span()); } #[test] @@ -1292,9 +1310,9 @@ with x(0) + 1 select assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::Instance(inst), - code.pos_after("inst: ") + code.pos_after("inst: ").token_span() ) ); } @@ -1313,9 +1331,9 @@ with x(0) + 1 select assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::Instance(inst), - code.pos_after("inst: ") + code.pos_after("inst: ").token_span() ) ); } @@ -1334,9 +1352,9 @@ with x(0) + 1 select assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::Instance(inst), - code.pos_after("inst: ") + code.pos_after("inst: ").token_span() ) ); } @@ -1358,9 +1376,9 @@ with x(0) + 1 select assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::Instance(inst), - code.pos_after("inst: ") + code.pos_after("inst: ").token_span() ) ); } @@ -1398,9 +1416,9 @@ inst: component lib.foo.bar assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::Instance(inst), - code.pos_after("inst: ") + code.pos_after("inst: ").token_span() ) ); } @@ -1430,9 +1448,9 @@ inst: lib.foo.bar assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::Instance(inst), - code.pos_after("inst: ") + code.pos_after("inst: ").token_span() ) ); } @@ -1462,9 +1480,9 @@ inst: lib.foo.bar assert_eq!(stmt.label.tree, Some(code.s1("inst").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::Instance(inst), - code.pos_after("inst: ") + code.pos_after("inst: ").token_span() ) ); } @@ -1492,9 +1510,9 @@ end generate;", assert_eq!(stmt.label.tree, Some(code.s1("gen").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::ForGenerate(gen), - code.pos_after("gen: ") + code.pos_after("gen: ").token_span() ) ); } @@ -1523,9 +1541,9 @@ end generate;", assert_eq!(stmt.label.tree, Some(code.s1("gen").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::ForGenerate(gen), - code.pos_after("gen: ") + code.pos_after("gen: ").token_span() ) ); } @@ -1549,9 +1567,9 @@ end generate;", assert_eq!(stmt.label.tree, Some(code.s1("gen").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::ForGenerate(gen), - code.pos_after("gen: ") + code.pos_after("gen: ").token_span() ) ); } @@ -1608,9 +1626,9 @@ end generate;", assert_eq!(stmt.label.tree, Some(code.s1("gen").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::ForGenerate(gen), - code.pos_after("gen: ") + code.pos_after("gen: ").token_span() ) ); } @@ -1662,9 +1680,9 @@ end generate;", assert_eq!(stmt.label.tree, Some(code.s1("gen").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::IfGenerate(gen), - code.pos_after("gen: ") + code.pos_after("gen: ").token_span() ) ); } @@ -1697,9 +1715,9 @@ end generate;", assert_eq!(stmt.label.tree, Some(code.s1("gen").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::IfGenerate(gen), - code.pos_after("gen: ") + code.pos_after("gen: ").token_span() ) ); } @@ -1749,9 +1767,9 @@ end generate;", assert_eq!(stmt.label.tree, Some(code.s1("gen").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::IfGenerate(gen), - code.pos_after("gen: ") + code.pos_after("gen: ").token_span() ) ); } @@ -1809,9 +1827,9 @@ end generate;", assert_eq!(stmt.label.tree, Some(code.s1("gen").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::IfGenerate(gen), - code.pos_after("gen: ") + code.pos_after("gen: ").token_span() ) ); } @@ -1863,9 +1881,9 @@ end generate;", assert_eq!(stmt.label.tree, Some(code.s1("gen").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::IfGenerate(gen), - code.pos_after("gen: ") + code.pos_after("gen: ").token_span() ) ); assert_eq!( @@ -1927,9 +1945,9 @@ end generate;", assert_eq!(stmt.label.tree, Some(code.s1("gen").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::IfGenerate(gen), - code.pos_after("gen: ") + code.pos_after("gen: ").token_span() ) ); } @@ -1976,9 +1994,9 @@ end generate;", assert_eq!(stmt.label.tree, Some(code.s1("gen").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::CaseGenerate(gen), - code.pos_after("gen: ") + code.pos_after("gen: ").token_span() ) ); } @@ -2025,9 +2043,9 @@ end generate gen1;", assert_eq!(stmt.label.tree, Some(code.s1("gen1").ident())); assert_eq!( stmt.statement, - WithPos::new( + WithTokenSpan::new( ConcurrentStatement::CaseGenerate(gen), - code.pos_after("gen1: ") + code.pos_after("gen1: ").token_span() ) ); } diff --git a/vhdl_lang/src/syntax/configuration.rs b/vhdl_lang/src/syntax/configuration.rs index 6124bdcd..1bdcc970 100644 --- a/vhdl_lang/src/syntax/configuration.rs +++ b/vhdl_lang/src/syntax/configuration.rs @@ -10,6 +10,7 @@ use super::concurrent_statement::parse_generic_and_port_map; use super::context::parse_use_clause; use super::names::{parse_name, parse_selected_name}; use super::tokens::{Kind::*, TokenSpan}; +use crate::ast::token_range::WithTokenSpan; use crate::ast::*; use crate::data::*; use vhdl_lang::syntax::parser::ParsingContext; @@ -112,7 +113,7 @@ fn parse_component_configuration_known_spec( enum ComponentSpecificationOrName { ComponentSpec(ComponentSpecification), - Name(WithPos), + Name(WithTokenSpan), } fn parse_component_specification_or_name( @@ -145,7 +146,7 @@ fn parse_component_specification_or_name( match sep_token.kind { Colon => { ctx.stream.skip(); - let ident = to_simple_name(name)?; + let ident = to_simple_name(ctx.stream, name)?; let component_name = parse_selected_name(ctx)?; Ok(ComponentSpecificationOrName::ComponentSpec(ComponentSpecification { instantiation_list: InstantiationList::Labels(vec![ident]), @@ -154,7 +155,7 @@ fn parse_component_specification_or_name( } Comma => { ctx.stream.skip(); - let mut idents = vec![to_simple_name(name)?]; + let mut idents = vec![to_simple_name(ctx.stream, name)?]; loop { idents.push(ctx.stream.expect_ident()?); expect_token!( @@ -193,7 +194,7 @@ fn parse_configuration_item_known_keyword( fn parse_block_configuration_known_name( ctx: &mut ParsingContext<'_>, - name: WithPos, + name: WithTokenSpan, ) -> ParseResult { let block_spec = name; // @TODO use clauses @@ -340,7 +341,7 @@ pub fn parse_configuration_specification( } } ComponentSpecificationOrName::Name(name) => Err(Diagnostic::syntax_error( - name, + name.pos(ctx.stream), "Expected component specification", )), } @@ -404,7 +405,7 @@ end configuration cfg; use_clauses: vec![], items: vec![], }, - end_ident_pos: Some(code.s("cfg", 2).pos()) + end_ident_pos: Some(code.s("cfg", 2).token()) } ); } @@ -437,7 +438,7 @@ end configuration cfg; use_clauses: vec![], items: vec![], }, - end_ident_pos: Some(code.s("cfg", 2).pos()) + end_ident_pos: Some(code.s("cfg", 2).token()) } ); } @@ -472,7 +473,7 @@ end configuration cfg; use_clauses: vec![], items: vec![], }, - end_ident_pos: Some(code.s("cfg", 2).pos()) + end_ident_pos: Some(code.s("cfg", 2).token()) } ); } @@ -501,7 +502,7 @@ end configuration cfg; use_clauses: vec![], items: vec![], }, - end_ident_pos: Some(code.s("cfg", 2).pos()) + end_ident_pos: Some(code.s("cfg", 2).token()) } ); } @@ -545,7 +546,7 @@ end configuration cfg; }) ], }, - end_ident_pos: Some(code.s("cfg", 2).pos()) + end_ident_pos: Some(code.s("cfg", 2).token()) } ); } @@ -592,7 +593,7 @@ end configuration cfg; }), }),], }, - end_ident_pos: Some(code.s("cfg", 2).pos()) + end_ident_pos: Some(code.s("cfg", 2).token()) } ); } @@ -650,7 +651,7 @@ end configuration cfg; }), }),], }, - end_ident_pos: Some(code.s("cfg", 2).pos()) + end_ident_pos: Some(code.s("cfg", 2).token()) } ); } @@ -699,7 +700,7 @@ end configuration cfg; block_config: None, }),], }, - end_ident_pos: Some(code.s("cfg", 2).pos()) + end_ident_pos: Some(code.s("cfg", 2).token()) } ); } @@ -779,7 +780,7 @@ end configuration cfg; }) ], }, - end_ident_pos: Some(code.s("cfg", 2).pos()) + end_ident_pos: Some(code.s("cfg", 2).token()) } ); } diff --git a/vhdl_lang/src/syntax/context.rs b/vhdl_lang/src/syntax/context.rs index 49855c10..b236e538 100644 --- a/vhdl_lang/src/syntax/context.rs +++ b/vhdl_lang/src/syntax/context.rs @@ -76,7 +76,7 @@ pub fn parse_context(ctx: &mut ParsingContext<'_>) -> ParseResult) -> ParseResult match parse_context(ctx) { Ok(DeclarationOrReference::Declaration(context_decl)) => { if !context_clause.is_empty() { - let mut diagnostic = Diagnostic::syntax_error(&context_decl.ident, "Context declaration may not be preceeded by a context clause"); + let mut diagnostic = Diagnostic::syntax_error(context_decl.ident.pos(ctx), "Context declaration may not be preceeded by a context clause"); for context_item in context_clause.iter() { diagnostic.add_related(context_item.get_pos(ctx.stream), context_item_message(context_item, "may not come before context declaration")); @@ -277,6 +277,7 @@ mod tests { use crate::data::Diagnostic; use crate::syntax::test::{check_diagnostics, check_no_diagnostics, Code}; use crate::syntax::{HasTokenSpan, TokenAccess}; + use pretty_assertions::assert_eq; fn parse_str(code: &str) -> (Code, DesignFile, Vec) { let code = Code::new(code); @@ -307,7 +308,7 @@ mod tests { fn simple_entity( ident: Ident, span: TokenSpan, - end_ident_pos: Option, + end_ident_pos: Option, ) -> AnyDesignUnit { AnyDesignUnit::Primary(AnyPrimaryUnit::Entity(EntityDeclaration { span, @@ -350,7 +351,7 @@ end entity myent; simple_entity( code.s1("myent").ident(), code.token_span(), - Some(code.s("myent", 2).pos()), + Some(code.s("myent", 2).token()), ) )] ); @@ -555,50 +556,56 @@ end; expected_streams ); - let code_myent = code.s1_from_start(";"); - let code_myent2 = code.s1_to_end("entity myent2").s1_from_start(";"); - let code_myent3 = code.s1_to_end("entity myent3").s1_from_start(";"); - let code_myent4 = code.s1_to_end("entity myent4").s1_from_start(";"); + let code_myent = code.between("entity myent", ";").to_new(); + let code_myent2 = code.between("entity myent2", ";").to_new(); + let code_myent3 = code.between("entity myent3", ";").to_new(); + let code_myent4 = code.between("entity myent4", ";").to_new(); assert_eq!( - design_file.design_units, - [ - ( - substreams[0].clone(), - simple_entity(code.s1("myent").ident(), code_myent.token_span(), None,) - ), - ( - substreams[1].clone(), - simple_entity( - code.s1("myent2").ident(), - code_myent2 - .token_span() - .apply_offset(code.s1("entity myent2").token()), - Some(code.s("myent2", 2).pos()), - ) - ), - ( - substreams[2].clone(), - simple_entity( - code.s1("myent3").ident(), - code_myent3 - .token_span() - .apply_offset(code.s1("entity myent3").token()), - Some(code.s("myent3", 2).pos()), - ) - ), - ( - substreams[3].clone(), - simple_entity( - code.s1("myent4").ident(), - code_myent4 - .token_span() - .apply_offset(code.s1("entity myent4").token()), - None - ) + design_file.design_units[0], + ( + substreams[0].clone(), + simple_entity( + code_myent.s1("myent").ident(), + code_myent.token_span(), + None, + ) + ) + ); + assert_eq!( + design_file.design_units[1], + ( + substreams[1].clone(), + simple_entity( + code_myent2.s1("myent2").ident(), + code_myent2.token_span(), + Some(code_myent2.s("myent2", 2).token()), ) - ] + ) + ); + assert_eq!( + design_file.design_units[2], + ( + substreams[2].clone(), + simple_entity( + code_myent3.s1("myent3").ident(), + code_myent3.token_span(), + Some(code_myent3.s("myent3", 2).token()), + ) + ), + ); + assert_eq!( + design_file.design_units[3], + ( + substreams[3].clone(), + simple_entity( + code_myent4.s1("myent4").ident(), + code_myent4.token_span(), + None + ) + ) ); + assert_eq!(design_file.design_units.len(), 4); } // An simple entity with only a name @@ -607,7 +614,7 @@ end; entity_name: Ident, span: TokenSpan, begin_token: TokenId, - end_ident_pos: Option, + end_ident_pos: Option, ) -> AnyDesignUnit { AnyDesignUnit::Secondary(AnySecondaryUnit::Architecture(ArchitectureBody { span, @@ -663,7 +670,7 @@ end architecture arch_name; code.s1("myent").ident(), code.token_span(), code.s1("begin").token(), - Some(code.s("arch_name", 2).pos()), + Some(code.s("arch_name", 2).token()), ) )] ); diff --git a/vhdl_lang/src/syntax/expression.rs b/vhdl_lang/src/syntax/expression.rs index 9157b921..0a7a787c 100644 --- a/vhdl_lang/src/syntax/expression.rs +++ b/vhdl_lang/src/syntax/expression.rs @@ -8,16 +8,16 @@ use super::common::ParseResult; use super::names::{parse_name, parse_type_mark}; use super::subtype_indication::parse_subtype_constraint; use super::tokens::{Kind, Kind::*}; -use crate::ast; +use crate::ast::token_range::{WithToken, WithTokenSpan}; use crate::ast::{Literal, *}; -use crate::data::{Diagnostic, WithPos}; +use crate::data::Diagnostic; use crate::syntax::TokenAccess; +use crate::{ast, TokenSpan}; use vhdl_lang::syntax::parser::ParsingContext; -fn name_to_expression(name: WithPos) -> WithPos { - WithPos { - item: Expression::Name(Box::new(name.item)), - pos: name.pos, +impl WithTokenSpan { + pub fn into_expression(self) -> WithTokenSpan { + self.map_into(|name| Expression::Name(Box::new(name))) } } @@ -145,19 +145,20 @@ fn kind_to_binary_op(kind: Kind) -> Option<(Operator, usize)> { pub fn parse_aggregate_initial_choices( ctx: &mut ParsingContext<'_>, - choices: Vec>, -) -> ParseResult>> { + choices: Vec>, +) -> ParseResult>> { let mut choices = choices; let mut result = Vec::new(); loop { expect_token!( ctx.stream, token, + token_id, RightPar => { if choices.len() == 1 { - if let Some(WithPos{item: Choice::Expression(expr), pos}) = choices.pop() { - result.push(ElementAssociation::Positional(WithPos::new(expr, pos))); - return Ok(WithPos::from(result, token.pos.clone())) + if let Some(WithTokenSpan{item: Choice::Expression(expr), span}) = choices.pop() { + result.push(ElementAssociation::Positional(WithTokenSpan::new(expr, span))); + return Ok(WithTokenSpan::from(result, token_id)) } } @@ -165,8 +166,8 @@ pub fn parse_aggregate_initial_choices( }, Comma => { if choices.len() == 1 { - if let Some(WithPos{item: Choice::Expression(expr), pos}) = choices.pop() { - result.push(ElementAssociation::Positional(WithPos::new(expr, pos))); + if let Some(WithTokenSpan{item: Choice::Expression(expr), span}) = choices.pop() { + result.push(ElementAssociation::Positional(WithTokenSpan::new(expr, span))); choices = parse_choices(ctx)?; continue; } @@ -181,8 +182,9 @@ pub fn parse_aggregate_initial_choices( expect_token!( ctx.stream, token, + token_id, RightPar => { - return Ok(WithPos::from(result, token.pos.clone())) + return Ok(WithTokenSpan::from(result, token_id)) }, Comma => { choices = parse_choices(ctx)?; @@ -195,10 +197,13 @@ pub fn parse_aggregate_initial_choices( pub fn parse_aggregate( ctx: &mut ParsingContext<'_>, -) -> ParseResult>> { - ctx.stream.expect_kind(LeftPar)?; +) -> ParseResult>> { + let start_tok = ctx.stream.expect_kind(LeftPar)?; if let Some(token) = ctx.stream.pop_if_kind(RightPar) { - return Ok(WithPos::from(Vec::new(), ctx.stream.get_pos(token).clone())); + return Ok(WithTokenSpan::from( + Vec::new(), + TokenSpan::new(start_tok, token), + )); }; let choices = parse_choices(ctx)?; parse_aggregate_initial_choices(ctx, choices) @@ -206,11 +211,11 @@ pub fn parse_aggregate( fn parse_half_range( ctx: &mut ParsingContext<'_>, - left_expr: WithPos, + left_expr: WithTokenSpan, direction: Direction, -) -> ParseResult> { +) -> ParseResult> { let right_expr = parse_expression(ctx)?; - let pos = left_expr.pos.combine(&right_expr.pos); + let pos = left_expr.span.combine(right_expr.span); let range = DiscreteRange::Range(ast::Range::Range(RangeConstraint { direction, @@ -218,15 +223,12 @@ fn parse_half_range( right_expr: Box::new(right_expr), })); - Ok(WithPos::new(range, pos)) + Ok(WithTokenSpan::new(range, pos)) } -fn parse_choice(ctx: &mut ParsingContext<'_>) -> ParseResult> { +fn parse_choice(ctx: &mut ParsingContext<'_>) -> ParseResult> { if let Some(token) = ctx.stream.pop_if_kind(Others) { - return Ok(WithPos::new( - Choice::Others, - ctx.stream.get_pos(token).clone(), - )); + return Ok(WithTokenSpan::from(Choice::Others, token)); } let left_expr = parse_expression(ctx)?; @@ -241,7 +243,7 @@ fn parse_choice(ctx: &mut ParsingContext<'_>) -> ParseResult> { } } -pub fn parse_choices(ctx: &mut ParsingContext<'_>) -> ParseResult>> { +pub fn parse_choices(ctx: &mut ParsingContext<'_>) -> ParseResult>> { let mut choices = Vec::new(); loop { choices.push(parse_choice(ctx)?); @@ -254,23 +256,23 @@ pub fn parse_choices(ctx: &mut ParsingContext<'_>) -> ParseResult) -> ParseResult> { +fn parse_allocator(ctx: &mut ParsingContext<'_>) -> ParseResult> { ctx.stream.expect_kind(New)?; let type_mark = parse_type_mark(ctx)?; if ctx.stream.skip_if_kind(Tick) { let expr = parse_expression(ctx)?; - let pos = type_mark.pos.clone().combine_into(&expr); - Ok(WithPos { + let span = type_mark.span.combine(expr.span); + Ok(WithTokenSpan { item: Allocator::Qualified(QualifiedExpression { type_mark, expr }), - pos, + span, }) } else { - let mut pos = type_mark.pos.clone(); + let mut span = type_mark.span; let constraint = { if let Some(constraint) = parse_subtype_constraint(ctx)? { - pos = pos.combine(&constraint.pos); + span = span.combine(constraint.span); Some(constraint) } else { None @@ -283,15 +285,19 @@ fn parse_allocator(ctx: &mut ParsingContext<'_>) -> ParseResult) -> ParseResult> { - let pos = name.pos.clone(); +pub fn name_to_type_mark( + ctx: &mut ParsingContext<'_>, + name: WithTokenSpan, +) -> ParseResult> { + let pos = name.pos(ctx); + let name_span = name.span; let type_mark = name .try_map_into(|name| match name { Name::Attribute(attr) => { @@ -305,7 +311,7 @@ pub fn name_to_type_mark(name: WithPos) -> ParseResult> } } _ => Some(TypeMark { - name: WithPos::from(name_to_selected_name(name)?, pos.clone()), + name: WithTokenSpan::from(name_to_selected_name(name)?, name_span), attr: None, }), }) @@ -325,34 +331,36 @@ fn name_to_selected_name(name: Name) -> Option { } } -fn parse_expression_or_aggregate(ctx: &mut ParsingContext<'_>) -> ParseResult> { +fn parse_expression_or_aggregate( + ctx: &mut ParsingContext<'_>, +) -> ParseResult> { let mut choices = parse_choices(ctx)?; if choices.len() == 1 && matches!( choices.first().unwrap(), - WithPos { + WithTokenSpan { item: Choice::Expression(_), .. } ) { - let WithPos { + let WithTokenSpan { item: Choice::Expression(expr), - pos, + span, } = choices.pop().unwrap() else { unreachable!(); }; peek_token!( - ctx.stream, token, + ctx.stream, token, token_id, // Was aggregate Comma | RightArrow => { Ok(parse_aggregate_initial_choices( ctx, - vec![WithPos::new(Choice::Expression(expr), pos)], + vec![WithTokenSpan::new(Choice::Expression(expr), span)], )?.map_into(Expression::Aggregate)) }, @@ -360,10 +368,10 @@ fn parse_expression_or_aggregate(ctx: &mut ParsingContext<'_>) -> ParseResult { ctx.stream.skip(); // Lexical position between parenthesis - let expr = WithPos { - item: expr, - pos: token.pos.clone(), - }; + let expr = WithTokenSpan::from( + expr, + token_id + ); Ok(expr) } ) @@ -377,89 +385,93 @@ fn parse_expression_or_aggregate(ctx: &mut ParsingContext<'_>) -> ParseResult) -> ParseResult> { +fn parse_primary(ctx: &mut ParsingContext<'_>) -> ParseResult> { let token = ctx.stream.peek_expect()?; + let token_id = ctx.stream.get_current_token_id(); match token.kind { Identifier | LtLt => { let name = parse_name(ctx)?; if ctx.stream.skip_if_kind(Tick) { let lpar = ctx.stream.expect_kind(LeftPar)?; - let expr = - parse_expression_or_aggregate(ctx)?.combine_pos_with(ctx.stream.get_pos(lpar)); - let pos = name.pos.combine(&expr); - Ok(WithPos { - item: Expression::Qualified(Box::new(QualifiedExpression { - type_mark: name_to_type_mark(name)?, + let expr = parse_expression_or_aggregate(ctx)?.start_with(lpar); + let span = name.span.combine(expr.span); + Ok(WithTokenSpan::new( + Expression::Qualified(Box::new(QualifiedExpression { + type_mark: name_to_type_mark(ctx, name)?, expr, })), - pos, - }) + span, + )) } else { - Ok(name_to_expression(name)) + Ok(name.into_expression()) } } BitString => { ctx.stream.skip(); Ok(token - .to_bit_string()? - .map_into(|bs| Expression::Literal(Literal::BitString(bs)))) + .to_bit_string(token_id)? + .map_into_span(|bs| Expression::Literal(Literal::BitString(bs)))) } Character => { ctx.stream.skip(); Ok(token - .to_character_value()? - .map_into(|chr| Expression::Literal(Literal::Character(chr)))) + .to_character_value(token_id)? + .map_into_span(|chr| Expression::Literal(Literal::Character(chr)))) } StringLiteral => { if ctx.stream.next_kinds_are(&[StringLiteral, LeftPar]) { - // Probably an function call via operator symbol "foo"() + // Probably a function call via operator symbol "foo"() parse_name(ctx).map(|name| name.map_into(|name| Expression::Name(Box::new(name)))) } else { ctx.stream.skip(); Ok(token - .to_string_value()? - .map_into(|string| Expression::Literal(Literal::String(string)))) + .to_string_value(token_id)? + .map_into_span(|string| Expression::Literal(Literal::String(string)))) } } Null => { ctx.stream.skip(); - Ok(WithPos { - item: Expression::Literal(Literal::Null), - pos: token.pos.clone(), - }) + Ok(WithTokenSpan::from( + Expression::Literal(Literal::Null), + token_id, + )) } New => { let alloc = parse_allocator(ctx)?; - let new_pos = token.pos.combine(&alloc); - Ok(WithPos { - item: Expression::New(Box::new(alloc)), - pos: new_pos, - }) + let new_pos = TokenSpan::new(token_id, alloc.span.end_token); + Ok(WithTokenSpan::new( + Expression::New(Box::new(alloc)), + new_pos, + )) } AbstractLiteral => { ctx.stream.skip(); - let value = token.to_abstract_literal()?; + let value = token.to_abstract_literal(token_id)?; // Physical unit if let Some(unit_token) = ctx.stream.pop_if_kind(Identifier) { - let unit = ctx.stream.get_token(unit_token).to_identifier_value()?; - let pos = value.pos.combine_into(&unit); + let unit = ctx + .stream + .get_token(unit_token) + .to_identifier_value(unit_token)?; + let span = TokenSpan::new(value.token, unit.token); let physical = PhysicalLiteral { value: value.item, unit: WithRef::new(unit), }; - Ok(WithPos { - item: Expression::Literal(Literal::Physical(physical)), - pos, - }) + Ok(WithTokenSpan::new( + Expression::Literal(Literal::Physical(physical)), + span, + )) } else { - Ok(value.map_into(|value| Expression::Literal(Literal::AbstractLiteral(value)))) + Ok(value + .map_into_span(|value| Expression::Literal(Literal::AbstractLiteral(value)))) } } LeftPar => { ctx.stream.skip(); - parse_expression_or_aggregate(ctx).map(|expr| expr.combine_pos_with(&token)) + parse_expression_or_aggregate(ctx).map(|expr| expr.start_with(token_id)) } kind => { @@ -468,15 +480,15 @@ fn parse_primary(ctx: &mut ParsingContext<'_>) -> ParseResult) -> ParseResult, min_precedence: usize, -) -> ParseResult> { +) -> ParseResult> { let mut lhs = parse_primary(ctx)?; while let Some(token) = ctx.stream.peek() { + let token_id = ctx.stream.get_current_token_id(); if token.kind == RightPar { return Ok(lhs); }; @@ -502,15 +515,15 @@ fn parse_expr( if op_precedence > min_precedence { ctx.stream.skip(); let rhs = parse_expr(ctx, op_precedence)?; - let pos = lhs.pos.combine(&rhs); - lhs = WithPos { - item: Expression::Binary( - WithPos::new(WithRef::new(binary_op), token.pos.clone()), + let pos = lhs.span.combine(rhs.span); + lhs = WithTokenSpan::new( + Expression::Binary( + WithToken::new(WithRef::new(binary_op), token_id), Box::new(lhs), Box::new(rhs), ), pos, - }; + ); } else { return Ok(lhs); } @@ -535,7 +548,7 @@ fn parse_expr( /// 6. sign: + | - /// 7. multiplying_operator: * | / | mod | rem /// 8. misc_operator: ** | abs | not -pub fn parse_expression(ctx: &mut ParsingContext<'_>) -> ParseResult> { +pub fn parse_expression(ctx: &mut ParsingContext<'_>) -> ParseResult> { let state = ctx.stream.state(); parse_expr(ctx, 0).map_err(|err| { ctx.stream.set_state(state); @@ -555,9 +568,9 @@ mod tests { let code = Code::new("'a'"); assert_eq!( code.with_stream(parse_expression), - WithPos { + WithTokenSpan { item: Expression::Literal(Literal::Character(b'a')), - pos: code.pos() + span: code.token_span() } ); } @@ -567,9 +580,9 @@ mod tests { let code = Code::new("71"); assert_eq!( code.with_stream(parse_expression), - WithPos { + WithTokenSpan { item: Expression::Literal(Literal::AbstractLiteral(AbstractLiteral::Integer(71))), - pos: code.pos() + span: code.token_span() } ); } @@ -579,9 +592,9 @@ mod tests { let code = Code::new("7.1"); assert_eq!( code.with_stream(parse_expression), - WithPos { + WithTokenSpan { item: Expression::Literal(Literal::AbstractLiteral(AbstractLiteral::Real(7.1))), - pos: code.pos() + span: code.token_span() } ); } @@ -591,11 +604,11 @@ mod tests { let code = Code::new("\"string\""); assert_eq!( code.with_stream(parse_expression), - WithPos { + WithTokenSpan { item: Expression::Literal(Literal::String(Latin1String::from_utf8_unchecked( "string" ))), - pos: code.pos() + span: code.token_span() } ); } @@ -627,9 +640,9 @@ mod tests { let code = Code::new("null"); assert_eq!( code.with_stream(parse_expression), - WithPos { + WithTokenSpan { item: Expression::Literal(Literal::Null), - pos: code.pos() + span: code.token_span() } ); } @@ -642,23 +655,23 @@ mod tests { fn parses_add_expression() { let code = Code::new("1 + 2"); - let lhs = WithPos { + let lhs = WithTokenSpan { item: Expression::Literal(int(1)), - pos: code.s1("1").pos(), + span: code.s1("1").token_span(), }; - let rhs = WithPos { + let rhs = WithTokenSpan { item: Expression::Literal(int(2)), - pos: code.s1("2").pos(), + span: code.s1("2").token_span(), }; - let expr_add = WithPos { + let expr_add = WithTokenSpan { item: Expression::Binary( - WithPos::new(WithRef::new(Operator::Plus), code.s1("+").pos()), + WithToken::new(WithRef::new(Operator::Plus), code.s1("+").token()), Box::new(lhs), Box::new(rhs), ), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr_add); @@ -667,23 +680,23 @@ mod tests { #[test] fn parses_sub_expression() { let code = Code::new("1 - 2"); - let lhs = WithPos { + let lhs = WithTokenSpan { item: Expression::Literal(int(1)), - pos: code.s1("1").pos(), + span: code.s1("1").token_span(), }; - let rhs = WithPos { + let rhs = WithTokenSpan { item: Expression::Literal(int(2)), - pos: code.s1("2").pos(), + span: code.s1("2").token_span(), }; - let expr_sub = WithPos { + let expr_sub = WithTokenSpan { item: Expression::Binary( - WithPos::new(WithRef::new(Operator::Minus), code.s1("-").pos()), + WithToken::new(WithRef::new(Operator::Minus), code.s1("-").token()), Box::new(lhs), Box::new(rhs), ), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr_sub); @@ -692,17 +705,17 @@ mod tests { #[test] fn parses_abs_expression() { let code = Code::new("abs 9"); - let expr = WithPos { + let expr = WithTokenSpan { item: Expression::Literal(int(9)), - pos: code.s1("9").pos(), + span: code.s1("9").token_span(), }; - let expr_abs = WithPos { + let expr_abs = WithTokenSpan { item: Expression::Unary( - WithPos::new(WithRef::new(Operator::Abs), code.s1("abs").pos()), + WithToken::new(WithRef::new(Operator::Abs), code.s1("abs").token()), Box::new(expr), ), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr_abs); @@ -711,17 +724,17 @@ mod tests { #[test] fn parses_condition_operator() { let code = Code::new("?? 9"); - let expr = WithPos { + let expr = WithTokenSpan { item: Expression::Literal(int(9)), - pos: code.s1("9").pos(), + span: code.s1("9").token_span(), }; - let expr_cond = WithPos { + let expr_cond = WithTokenSpan { item: Expression::Unary( - WithPos::new(WithRef::new(Operator::QueQue), code.s1("??").pos()), + WithToken::new(WithRef::new(Operator::QueQue), code.s1("??").token()), Box::new(expr), ), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr_cond); @@ -730,19 +743,19 @@ mod tests { #[test] fn parses_not_expression() { let code = Code::new("not false"); - let name_false = WithPos { + let name_false = WithTokenSpan { item: Expression::Name(Box::new(Name::Designator( Designator::Identifier(code.symbol("false")).into_ref(), ))), - pos: code.s1("false").pos(), + span: code.s1("false").token_span(), }; - let expr_not = WithPos { + let expr_not = WithTokenSpan { item: Expression::Unary( - WithPos::new(WithRef::new(Operator::Not), code.s1("not").pos()), + WithToken::new(WithRef::new(Operator::Not), code.s1("not").token()), Box::new(name_false), ), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr_not); @@ -754,14 +767,14 @@ mod tests { let type_mark = code.s1("integer_vector").type_mark(); let expr = code.s1("(0, 1)").expr(); - let alloc = WithPos { + let alloc = WithTokenSpan { item: Allocator::Qualified(QualifiedExpression { type_mark, expr }), - pos: code.s1("integer_vector'(0, 1)").pos(), + span: code.s1("integer_vector'(0, 1)").token_span(), }; - let new_expr = WithPos { + let new_expr = WithTokenSpan { item: Expression::New(Box::new(alloc)), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), new_expr); @@ -771,14 +784,14 @@ mod tests { fn parses_new_allocator_subtype() { let code = Code::new("new integer_vector"); - let alloc = WithPos { + let alloc = WithTokenSpan { item: Allocator::Subtype(code.s1("integer_vector").subtype_indication()), - pos: code.s1("integer_vector").pos(), + span: code.s1("integer_vector").token_span(), }; - let new_expr = WithPos { + let new_expr = WithTokenSpan { item: Expression::New(Box::new(alloc)), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), new_expr); @@ -788,14 +801,14 @@ mod tests { fn parses_new_allocator_subtype_constraint() { let code = Code::new("new integer_vector(0 to 1)"); - let alloc = WithPos { + let alloc = WithTokenSpan { item: Allocator::Subtype(code.s1("integer_vector(0 to 1)").subtype_indication()), - pos: code.s1("integer_vector(0 to 1)").pos(), + span: code.s1("integer_vector(0 to 1)").token_span(), }; - let new_expr = WithPos { + let new_expr = WithTokenSpan { item: Expression::New(Box::new(alloc)), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), new_expr); @@ -805,14 +818,14 @@ mod tests { fn parses_new_allocator_subtype_constraint_range_attribute() { let code = Code::new("new integer_vector(foo'range)"); - let alloc = WithPos { + let alloc = WithTokenSpan { item: Allocator::Subtype(code.s1("integer_vector(foo'range)").subtype_indication()), - pos: code.s1("integer_vector(foo'range)").pos(), + span: code.s1("integer_vector(foo'range)").token_span(), }; - let new_expr = WithPos { + let new_expr = WithTokenSpan { item: Expression::New(Box::new(alloc)), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), new_expr); @@ -821,12 +834,12 @@ mod tests { #[test] fn parses_physical_unit_expression() { let code = Code::new("1 ns"); - let expr = WithPos { + let expr = WithTokenSpan { item: Expression::Literal(Literal::Physical(PhysicalLiteral { value: AbstractLiteral::Integer(1), unit: code.s1("ns").ident().into_ref(), })), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr); @@ -835,12 +848,12 @@ mod tests { #[test] fn parses_physical_unit_expression_real() { let code = Code::new("1.0 ns"); - let expr = WithPos { + let expr = WithTokenSpan { item: Expression::Literal(Literal::Physical(PhysicalLiteral { value: AbstractLiteral::Real(1.0), unit: code.s1("ns").ident().into_ref(), })), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr); @@ -849,24 +862,24 @@ mod tests { #[test] fn parses_physical_unit_expression_binary() { let code = Code::new("2 * 1 ns"); - let time_expr = WithPos { + let time_expr = WithTokenSpan { item: Expression::Literal(Literal::Physical(PhysicalLiteral { value: AbstractLiteral::Integer(1), unit: code.s1("ns").ident().into_ref(), })), - pos: code.s1("1 ns").pos(), + span: code.s1("1 ns").token_span(), }; - let two_expr = WithPos { + let two_expr = WithTokenSpan { item: Expression::Literal(int(2)), - pos: code.s1("2").pos(), + span: code.s1("2").token_span(), }; - let expr = WithPos { + let expr = WithTokenSpan { item: Expression::Binary( - WithPos::new(WithRef::new(Operator::Times), code.s1("*").pos()), + WithToken::new(WithRef::new(Operator::Times), code.s1("*").token()), Box::new(two_expr), Box::new(time_expr), ), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr); } @@ -874,19 +887,19 @@ mod tests { #[test] fn parses_physical_unit_expression_unary() { let code = Code::new("- 1 ns"); - let time_expr = WithPos { + let time_expr = WithTokenSpan { item: Expression::Literal(Literal::Physical(PhysicalLiteral { value: AbstractLiteral::Integer(1), unit: code.s1("ns").ident().into_ref(), })), - pos: code.s1("1 ns").pos(), + span: code.s1("1 ns").token_span(), }; - let expr = WithPos { + let expr = WithTokenSpan { item: Expression::Unary( - WithPos::new(WithRef::new(Operator::Minus), code.s1("-").pos()), + WithToken::new(WithRef::new(Operator::Minus), code.s1("-").token()), Box::new(time_expr), ), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr); @@ -898,9 +911,9 @@ mod tests { let type_mark = code.s1("foo").type_mark(); let expr = code.s1("(1+2)").expr(); - let qexpr = WithPos { + let qexpr = WithTokenSpan { item: Expression::Qualified(Box::new(QualifiedExpression { type_mark, expr })), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), qexpr); @@ -909,13 +922,13 @@ mod tests { #[test] fn qualified_expression_precedence() { let code = Code::new("mark0'(0) < mark1'(1)"); - let expr = WithPos { + let expr = WithTokenSpan { item: Expression::Binary( - WithPos::new(WithRef::new(Operator::LT), code.s1("<").pos()), + WithToken::new(WithRef::new(Operator::LT), code.s1("<").token()), Box::new(code.s1("mark0'(0)").expr()), Box::new(code.s1("mark1'(1)").expr()), ), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.expr(), expr); @@ -927,9 +940,9 @@ mod tests { let type_mark = code.s1("foo").type_mark(); let expr = code.s1("(others => '1')").expr(); - let qexpr = WithPos { + let qexpr = WithTokenSpan { item: Expression::Qualified(Box::new(QualifiedExpression { type_mark, expr })), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), qexpr); @@ -938,22 +951,22 @@ mod tests { #[test] fn parses_positional_aggregate() { let code = Code::new("(1, 2)"); - let one_expr = WithPos { + let one_expr = WithTokenSpan { item: Expression::Literal(int(1)), - pos: code.s1("1").pos(), + span: code.s1("1").token_span(), }; - let two_expr = WithPos { + let two_expr = WithTokenSpan { item: Expression::Literal(int(2)), - pos: code.s1("2").pos(), + span: code.s1("2").token_span(), }; let assoc_list = vec![ ElementAssociation::Positional(one_expr), ElementAssociation::Positional(two_expr), ]; - let expr = WithPos { + let expr = WithTokenSpan { item: Expression::Aggregate(assoc_list), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr); @@ -962,22 +975,22 @@ mod tests { #[test] fn parses_named_aggregate() { let code = Code::new("(1 => 2)"); - let one_expr = WithPos { + let one_expr = WithTokenSpan { item: Expression::Literal(int(1)), - pos: code.s1("1").pos(), + span: code.s1("1").token_span(), }; - let two_expr = WithPos { + let two_expr = WithTokenSpan { item: Expression::Literal(int(2)), - pos: code.s1("2").pos(), + span: code.s1("2").token_span(), }; let assoc_list = vec![ElementAssociation::Named( vec![one_expr.map_into(Choice::Expression)], two_expr, )]; - let expr = WithPos { + let expr = WithTokenSpan { item: Expression::Aggregate(assoc_list), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr); @@ -986,19 +999,19 @@ mod tests { #[test] fn parses_named_aggregate_many_choices() { let code = Code::new("(1 | 2 => 3)"); - let one_expr = WithPos { + let one_expr = WithTokenSpan { item: Expression::Literal(int(1)), - pos: code.s1("1").pos(), + span: code.s1("1").token_span(), }; - let two_expr = WithPos { + let two_expr = WithTokenSpan { item: Expression::Literal(int(2)), - pos: code.s1("2").pos(), + span: code.s1("2").token_span(), }; - let three_expr = WithPos { + let three_expr = WithTokenSpan { item: Expression::Literal(int(3)), - pos: code.s1("3").pos(), + span: code.s1("3").token_span(), }; let assoc_list = vec![ElementAssociation::Named( @@ -1008,9 +1021,9 @@ mod tests { ], three_expr, )]; - let expr = WithPos { + let expr = WithTokenSpan { item: Expression::Aggregate(assoc_list), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr); @@ -1019,18 +1032,21 @@ mod tests { #[test] fn parses_others_aggregate() { let code = Code::new("(others => 1)"); - let one_expr = WithPos { + let one_expr = WithTokenSpan { item: Expression::Literal(int(1)), - pos: code.s1("1").pos(), + span: code.s1("1").token_span(), }; let assoc_list = vec![ElementAssociation::Named( - vec![WithPos::new(Choice::Others, code.s1("others"))], + vec![WithTokenSpan::new( + Choice::Others, + code.s1("others").token_span(), + )], one_expr, )]; - let expr = WithPos { + let expr = WithTokenSpan { item: Expression::Aggregate(assoc_list), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr); @@ -1042,26 +1058,26 @@ mod tests { let (pos, code) = { if *direction == Direction::Descending { let code = Code::new("(1 downto 0 => 2)"); - (code.s1("1 downto 0").pos(), code) + (code.s1("1 downto 0").token_span(), code) } else { let code = Code::new("(1 to 0 => 2)"); - (code.s1("1 to 0").pos(), code) + (code.s1("1 to 0").token_span(), code) } }; - let one_expr = WithPos { + let one_expr = WithTokenSpan { item: Expression::Literal(int(1)), - pos: code.s1("1").pos(), + span: code.s1("1").token_span(), }; - let zero_expr = WithPos { + let zero_expr = WithTokenSpan { item: Expression::Literal(int(0)), - pos: code.s1("0").pos(), + span: code.s1("0").token_span(), }; - let two_expr = WithPos { + let two_expr = WithTokenSpan { item: Expression::Literal(int(2)), - pos: code.s1("2").pos(), + span: code.s1("2").token_span(), }; let range = DiscreteRange::Range(ast::Range::Range(RangeConstraint { @@ -1071,12 +1087,12 @@ mod tests { })); let assoc_list = vec![ElementAssociation::Named( - vec![WithPos::new(Choice::DiscreteRange(range), pos)], + vec![WithTokenSpan::new(Choice::DiscreteRange(range), pos)], two_expr, )]; - let expr = WithPos { + let expr = WithTokenSpan { item: Expression::Aggregate(assoc_list), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr); @@ -1086,29 +1102,35 @@ mod tests { #[test] fn parses_multiple_others_aggregate() { let code = Code::new("(others => 1, others => 2)"); - let one_expr = WithPos { + let one_expr = WithTokenSpan { item: Expression::Literal(int(1)), - pos: code.s1("1").pos(), + span: code.s1("1").token_span(), }; - let two_expr = WithPos { + let two_expr = WithTokenSpan { item: Expression::Literal(int(2)), - pos: code.s1("2").pos(), + span: code.s1("2").token_span(), }; let assoc_list = vec![ ElementAssociation::Named( - vec![WithPos::new(Choice::Others, code.s("others", 1))], + vec![WithTokenSpan::new( + Choice::Others, + code.s("others", 1).token_span(), + )], one_expr, ), ElementAssociation::Named( - vec![WithPos::new(Choice::Others, code.s("others", 2))], + vec![WithTokenSpan::new( + Choice::Others, + code.s("others", 2).token_span(), + )], two_expr, ), ]; - let expr = WithPos { + let expr = WithTokenSpan { item: Expression::Aggregate(assoc_list), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr); @@ -1117,26 +1139,26 @@ mod tests { #[test] fn parses_mixed_aggregate() { let code = Code::new("(1 => 2, 3)"); - let one_expr = WithPos { + let one_expr = WithTokenSpan { item: Expression::Literal(int(1)), - pos: code.s1("1").pos(), + span: code.s1("1").token_span(), }; - let two_expr = WithPos { + let two_expr = WithTokenSpan { item: Expression::Literal(int(2)), - pos: code.s1("2").pos(), + span: code.s1("2").token_span(), }; - let three_expr = WithPos { + let three_expr = WithTokenSpan { item: Expression::Literal(int(3)), - pos: code.s1("3").pos(), + span: code.s1("3").token_span(), }; let assoc_list = vec![ ElementAssociation::Named(vec![one_expr.map_into(Choice::Expression)], two_expr), ElementAssociation::Positional(three_expr), ]; - let expr = WithPos { + let expr = WithTokenSpan { item: Expression::Aggregate(assoc_list), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr); @@ -1151,44 +1173,44 @@ mod tests { } code.push_str("11123)"); let code = Code::new(&code); - assert_eq!(code.with_stream(parse_expression).pos, code.pos()); + assert_eq!(code.with_stream(parse_expression).span, code.token_span()); } #[test] fn parses_nested_expression_par_second() { let code = Code::new("1 + (2 + 3)"); - let one = WithPos { + let one = WithTokenSpan { item: Expression::Literal(int(1)), - pos: code.s1("1").pos(), + span: code.s1("1").token_span(), }; - let two = WithPos { + let two = WithTokenSpan { item: Expression::Literal(int(2)), - pos: code.s1("2").pos(), + span: code.s1("2").token_span(), }; - let three = WithPos { + let three = WithTokenSpan { item: Expression::Literal(int(3)), - pos: code.s1("3").pos(), + span: code.s1("3").token_span(), }; - let expr_add0 = WithPos { + let expr_add0 = WithTokenSpan { item: Expression::Binary( - WithPos::new(WithRef::new(Operator::Plus), code.s("+", 2).pos()), + WithToken::new(WithRef::new(Operator::Plus), code.s("+", 2).token()), Box::new(two), Box::new(three), ), - pos: code.s1("(2 + 3)").pos(), + span: code.s1("(2 + 3)").token_span(), }; - let expr_add1 = WithPos { + let expr_add1 = WithTokenSpan { item: Expression::Binary( - WithPos::new(WithRef::new(Operator::Plus), code.s("+", 1).pos()), + WithToken::new(WithRef::new(Operator::Plus), code.s("+", 1).token()), Box::new(one), Box::new(expr_add0), ), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr_add1); @@ -1198,49 +1220,49 @@ mod tests { fn parses_nested_expression_par_first() { let code = Code::new("(1 + 2) + 3"); - let one = WithPos { + let one = WithTokenSpan { item: Expression::Literal(int(1)), - pos: code.s1("1").pos(), + span: code.s1("1").token_span(), }; - let two = WithPos { + let two = WithTokenSpan { item: Expression::Literal(int(2)), - pos: code.s1("2").pos(), + span: code.s1("2").token_span(), }; - let three = WithPos { + let three = WithTokenSpan { item: Expression::Literal(int(3)), - pos: code.s1("3").pos(), + span: code.s1("3").token_span(), }; - let expr_add0 = WithPos { + let expr_add0 = WithTokenSpan { item: Expression::Binary( - WithPos::new(WithRef::new(Operator::Plus), code.s("+", 1).pos()), + WithToken::new(WithRef::new(Operator::Plus), code.s("+", 1).token()), Box::new(one), Box::new(two), ), - pos: code.s1("(1 + 2)").pos(), + span: code.s1("(1 + 2)").token_span(), }; - let expr_add1 = WithPos { + let expr_add1 = WithTokenSpan { item: Expression::Binary( - WithPos::new(WithRef::new(Operator::Plus), code.s("+", 2).pos()), + WithToken::new(WithRef::new(Operator::Plus), code.s("+", 2).token()), Box::new(expr_add0), Box::new(three), ), - pos: code.pos(), + span: code.token_span(), }; assert_eq!(code.with_stream(parse_expression), expr_add1); } /// Format expression as a string to simplify testing of precedence. - fn fmt(expr: &WithPos) -> String { + fn fmt(ctx: &dyn TokenAccess, expr: &WithTokenSpan) -> String { match expr.item { Expression::Binary(ref op, ref lhs, ref rhs) => { - format!("({} {:?} {})", fmt(lhs), op.item.item, fmt(rhs)) + format!("({} {:?} {})", fmt(ctx, lhs), op.item.item, fmt(ctx, rhs)) } - Expression::Unary(ref op, ref rhs) => format!("({:?} {})", op.item.item, fmt(rhs)), + Expression::Unary(ref op, ref rhs) => format!("({:?} {})", op.item.item, fmt(ctx, rhs)), Expression::Literal(ref lit) => match lit { Literal::Null => "null".to_string(), // @TODO quote and escape @@ -1259,22 +1281,21 @@ mod tests { } }, _ => { - println!("{}", expr.pos.code_context()); + println!("{}", expr.pos(ctx).code_context()); panic!("Cannot format {lit:?}"); } }, _ => { - println!("{}", expr.pos.code_context()); + println!("{}", expr.pos(ctx).code_context()); panic!("Cannot format {expr:?}"); } } } fn assert_expression_is(code: &str, expr_str: &str) { - assert_eq!( - fmt(&Code::new(code).with_stream(parse_expression)), - expr_str - ); + let code = Code::new(code); + let ctx = code.tokenize(); + assert_eq!(fmt(&ctx, &code.with_stream(parse_expression)), expr_str); } #[test] diff --git a/vhdl_lang/src/syntax/interface_declaration.rs b/vhdl_lang/src/syntax/interface_declaration.rs index b4fc0fef..4b6b8e8c 100644 --- a/vhdl_lang/src/syntax/interface_declaration.rs +++ b/vhdl_lang/src/syntax/interface_declaration.rs @@ -12,6 +12,7 @@ use super::object_declaration::parse_optional_assignment; use super::subprogram::parse_subprogram_specification; use super::subtype_indication::parse_subtype_indication; use super::tokens::{Kind::*, *}; +use crate::ast::token_range::WithToken; /// LRM 6.5 Interface declarations use crate::ast::*; use crate::data::*; @@ -21,8 +22,9 @@ use vhdl_lang::VHDLStandard::VHDL2019; pub(crate) fn parse_optional_mode( ctx: &mut ParsingContext<'_>, -) -> ParseResult>> { +) -> ParseResult>> { let token = ctx.stream.peek_expect()?; + let id = ctx.stream.get_current_token_id(); let mode = match token.kind { In => Mode::In, Out => Mode::Out, @@ -32,7 +34,7 @@ pub(crate) fn parse_optional_mode( _ => return Ok(None), }; ctx.stream.skip(); - Ok(Some(WithPos::new(mode, token.pos.clone()))) + Ok(Some(WithToken::new(mode, id))) } fn unexpected_object_class_kind(list_type: InterfaceType, token: &Token) -> Diagnostic { @@ -46,8 +48,9 @@ fn unexpected_object_class_kind(list_type: InterfaceType, token: &Token) -> Diag fn parse_optional_object_class( ctx: &mut ParsingContext<'_>, list_type: InterfaceType, -) -> ParseResult>> { +) -> ParseResult>> { let token = ctx.stream.peek_expect()?; + let id = ctx.stream.get_current_token_id(); let class = match token.kind { Constant => ObjectClass::Constant, @@ -57,7 +60,7 @@ fn parse_optional_object_class( _ => return Err(unexpected_object_class_kind(list_type, token)), }; ctx.stream.skip(); - Ok(Some(WithPos::new(class, token.pos.clone()))) + Ok(Some(WithToken::new(class, id))) } fn parse_interface_file_declaration( @@ -71,7 +74,7 @@ fn parse_interface_file_declaration( if ctx.stream.next_kind_is(Open) { if let Some(ident) = idents.first() { return Err(Diagnostic::syntax_error( - ident, + ident.pos(ctx), "interface_file_declaration may not have file open information", )); } @@ -79,7 +82,7 @@ fn parse_interface_file_declaration( if ctx.stream.next_kind_is(Is) { if let Some(ident) = idents.first() { return Err(Diagnostic::syntax_error( - ident, + ident.pos(ctx), "interface_file_declaration may not have file name", )); } @@ -152,13 +155,13 @@ fn parse_view_mode_indication(ctx: &mut ParsingContext<'_>) -> ParseResult, list_type: InterfaceType, - explicit_object_class: Option<&WithPos>, + explicit_object_class: Option<&WithToken>, idents: &[Ident], ) -> ParseResult { - let object_class_pos = explicit_object_class.map(|class| &class.pos); + let object_class_tok = explicit_object_class.map(|class| class.token); let mode_with_pos = parse_optional_mode(ctx)?; let mode = mode_with_pos.as_ref().map(|mode| mode.item); - let mode_pos = mode_with_pos.map(|mode| mode.pos); + let mode_tok = mode_with_pos.map(|mode| mode.token); let object_class = match ( list_type, @@ -179,25 +182,25 @@ fn parse_simple_mode_indication( // @TODO maybe move this to a semantic check? for ident in idents.iter() { if object_class == ObjectClass::Constant && mode.unwrap_or_default() != Mode::In { - let pos = mode_pos.as_ref().unwrap_or(&ident.pos); + let token_id = mode_tok.unwrap_or(ident.token); return Err(Diagnostic::syntax_error( - pos, + ctx.get_pos(token_id), "Interface constant declaration may only have mode=in", )); }; if list_type == InterfaceType::Port && object_class != ObjectClass::Signal { - let pos = object_class_pos.unwrap_or(&ident.pos); + let tok = object_class_tok.unwrap_or(ident.token); return Err(Diagnostic::syntax_error( - pos, + ctx.get_pos(tok), "Port list only allows signal object class", )); }; if list_type == InterfaceType::Generic && object_class != ObjectClass::Constant { - let pos = object_class_pos.unwrap_or(&ident.pos); + let tok = object_class_tok.unwrap_or(ident.token); return Err(Diagnostic::syntax_error( - pos, + ctx.get_pos(tok), "Generic list only allows constant object class", )); }; diff --git a/vhdl_lang/src/syntax/names.rs b/vhdl_lang/src/syntax/names.rs index d2f4385f..54922fc8 100644 --- a/vhdl_lang/src/syntax/names.rs +++ b/vhdl_lang/src/syntax/names.rs @@ -11,63 +11,69 @@ use super::subprogram::parse_signature; use super::subtype_indication::parse_subtype_indication; use super::tokens::{Kind::*, TokenAccess}; use crate::ast; +use crate::ast::token_range::{WithToken, WithTokenSpan}; use crate::ast::{Literal, *}; use crate::data::error_codes::ErrorCode; -use crate::data::{Diagnostic, WithPos}; +use crate::data::Diagnostic; use crate::syntax::separated_list::parse_list_with_separator_or_recover; use crate::syntax::TokenId; use vhdl_lang::syntax::parser::ParsingContext; +use vhdl_lang::TokenSpan; -pub fn parse_designator(ctx: &mut ParsingContext<'_>) -> ParseResult> { +pub fn parse_designator(ctx: &mut ParsingContext<'_>) -> ParseResult> { Ok(expect_token!( ctx.stream, token, - Identifier => token.to_identifier_value()?.map_into(Designator::Identifier), - StringLiteral => token.to_operator_symbol()?.map_into(Designator::OperatorSymbol), - Character => token.to_character_value()?.map_into(Designator::Character) + token_id, + Identifier => token.to_identifier_value(token_id)?.map_into(Designator::Identifier), + StringLiteral => token.to_operator_symbol(token_id)?.map_into(Designator::OperatorSymbol), + Character => token.to_character_value(token_id)?.map_into(Designator::Character) )) } -pub fn parse_selected_name(ctx: &mut ParsingContext<'_>) -> ParseResult> { - let mut name = parse_designator(ctx)?.into_ref().map_into(Name::Designator); +pub fn parse_selected_name(ctx: &mut ParsingContext<'_>) -> ParseResult> { + let mut name = parse_designator(ctx)? + .into_ref() + .map_into_span(Name::Designator); loop { if !ctx.stream.skip_if_kind(Dot) { break; } if let Some(tok) = ctx.stream.pop_if_kind(All) { - let pos = ctx.stream.get_pos(tok).combine(&name.pos); - name = WithPos::from(Name::SelectedAll(Box::new(name)), pos); + let span = name.span.end_with(tok); + name = WithTokenSpan::from(Name::SelectedAll(Box::new(name)), span); } else { let suffix = parse_designator(ctx)?.into_ref(); - let pos = suffix.pos.combine(&name.pos); - name = WithPos::from(Name::Selected(Box::new(name), suffix), pos); + let span = name.span.end_with(suffix.token); + name = WithTokenSpan::from(Name::Selected(Box::new(name), suffix), span); } } Ok(name) } -pub fn parse_type_mark(ctx: &mut ParsingContext<'_>) -> ParseResult> { +pub fn parse_type_mark(ctx: &mut ParsingContext<'_>) -> ParseResult> { let name = parse_selected_name(ctx)?; parse_type_mark_starting_with_name(ctx, name) } pub fn parse_type_mark_starting_with_name( ctx: &mut ParsingContext<'_>, - name: WithPos, -) -> ParseResult> { + name: WithTokenSpan, +) -> ParseResult> { let state = ctx.stream.state(); + let name_span = name.span; // Check if it is a type mark with a subtype or element attribute: // Example: signal sig0 : sig1'subtype; if ctx.stream.pop_if_kind(Tick).is_some() { if let Ok(attr) = ctx.stream.expect_attribute_designator() { if let AttributeDesignator::Type(typattr) = attr.item { - return Ok(WithPos { - pos: attr.pos.combine_into(&name.pos), + return Ok(WithTokenSpan { item: TypeMark { name, attr: Some(typattr), }, + span: name_span.end_with(attr.token), }); } } @@ -75,9 +81,9 @@ pub fn parse_type_mark_starting_with_name( ctx.stream.set_state(state); }; - Ok(WithPos { - pos: name.pos.clone(), + Ok(WithTokenSpan { item: TypeMark { name, attr: None }, + span: name_span, }) } @@ -91,18 +97,21 @@ impl Name { } } -impl WithPos { - pub fn expect_selected(&self) -> Result<(), Diagnostic> { +impl WithTokenSpan { + pub fn expect_selected(&self, ctx: &dyn TokenAccess) -> Result<(), Diagnostic> { match self.item.expect_selected() { Ok(_) => Ok(()), - Err(msg) => Err(Diagnostic::syntax_error(self, msg)), + Err(msg) => Err(Diagnostic::syntax_error(self.pos(ctx), msg)), } } } -pub fn expression_to_ident(name: WithPos) -> ParseResult { - let name = expression_to_name(name)?; - to_simple_name(name) +pub fn expression_to_ident( + ctx: &mut ParsingContext<'_>, + name: WithTokenSpan, +) -> ParseResult { + let name = expression_to_name(ctx, name)?; + to_simple_name(ctx, name) } pub fn parse_identifier_list(ctx: &mut ParsingContext<'_>) -> ParseResult> { @@ -116,60 +125,77 @@ pub fn parse_identifier_list(ctx: &mut ParsingContext<'_>) -> ParseResult) -> ParseResult> { +fn expression_to_name( + ctx: &dyn TokenAccess, + expr: WithTokenSpan, +) -> ParseResult> { match expr.item { - Expression::Name(name) => Ok(WithPos { + Expression::Name(name) => Ok(WithTokenSpan { item: *name, - pos: expr.pos, + span: expr.span, }), Expression::Literal(Literal::String(val)) => { if let Some(op) = Operator::from_latin1(val) { - Ok(WithPos { + Ok(WithTokenSpan { item: Name::Designator(Designator::OperatorSymbol(op).into_ref()), - pos: expr.pos, + span: expr.span, }) } else { Err(Diagnostic::syntax_error( - expr.pos, + expr.span.pos(ctx), "Invalid operator symbol", )) } } - Expression::Literal(Literal::Character(val)) => Ok(WithPos { + Expression::Literal(Literal::Character(val)) => Ok(WithTokenSpan { item: Name::Designator(Designator::Character(val).into_ref()), - pos: expr.pos, + span: expr.span, }), - _ => Err(Diagnostic::syntax_error(&expr, "Expected name")), + _ => Err(Diagnostic::syntax_error(expr.pos(ctx), "Expected name")), } } -fn actual_to_expression(actual: WithPos) -> ParseResult> { +fn actual_to_expression( + ctx: &dyn TokenAccess, + actual: WithTokenSpan, +) -> ParseResult> { match actual.item { - ActualPart::Expression(expr) => Ok(WithPos::from(expr, actual.pos)), - _ => Err(Diagnostic::syntax_error(&actual, "Expected expression")), + ActualPart::Expression(expr) => Ok(WithTokenSpan::from(expr, actual.span)), + _ => Err(Diagnostic::syntax_error( + actual.pos(ctx), + "Expected expression", + )), } } -fn actual_part_to_name(actual: WithPos) -> ParseResult> { +fn actual_part_to_name( + ctx: &dyn TokenAccess, + actual: WithTokenSpan, +) -> ParseResult> { match actual.item { - ActualPart::Expression(expr) => expression_to_name(WithPos::from(expr, actual.pos)), - _ => Err(Diagnostic::syntax_error(&actual, "Expected name")), + ActualPart::Expression(expr) => { + expression_to_name(ctx, WithTokenSpan::from(expr, actual.span)) + } + _ => Err(Diagnostic::syntax_error(actual.pos(ctx), "Expected name")), } } -fn assoc_to_expression(assoc: AssociationElement) -> ParseResult> { +fn assoc_to_expression( + ctx: &dyn TokenAccess, + assoc: AssociationElement, +) -> ParseResult> { match assoc.formal { - Some(name) => Err(Diagnostic::syntax_error(&name, "Expected expression")), - None => actual_to_expression(assoc.actual), + Some(name) => Err(Diagnostic::syntax_error( + name.pos(ctx), + "Expected expression", + )), + None => actual_to_expression(ctx, assoc.actual), } } -fn parse_actual_part(ctx: &mut ParsingContext<'_>) -> ParseResult> { +fn parse_actual_part(ctx: &mut ParsingContext<'_>) -> ParseResult> { if let Some(token) = ctx.stream.pop_if_kind(Open) { - Ok(WithPos::from( - ActualPart::Open, - ctx.stream.get_pos(token).clone(), - )) + Ok(WithTokenSpan::from(ActualPart::Open, token)) } else { Ok(parse_expression(ctx)?.map_into(ActualPart::Expression)) } @@ -179,7 +205,7 @@ pub fn parse_association_element(ctx: &mut ParsingContext<'_>) -> ParseResult, - prefix: WithPos, + prefix: WithTokenSpan, first: AssociationElement, -) -> ParseResult> { +) -> ParseResult> { let mut association_elements = Vec::new(); association_elements.push(first); @@ -232,14 +258,15 @@ fn parse_function_call( expect_token!( ctx.stream, token, + token_id, Comma => {}, RightPar => { - let pos = token.pos.combine(&prefix); - return Ok(WithPos { + let span = TokenSpan::new(prefix.span.start_token, token_id); + return Ok(WithTokenSpan { item: Name::CallOrIndexed(Box::new(CallOrIndexed { name: prefix, parameters: association_elements})), - pos, + span, }); } ) @@ -248,29 +275,29 @@ fn parse_function_call( fn parse_attribute_name( ctx: &mut ParsingContext<'_>, - name: WithPos, - signature: Option>, -) -> ParseResult> { + name: WithTokenSpan, + signature: Option>, +) -> ParseResult> { let attr = ctx.stream.expect_attribute_designator()?; - let (expression, pos) = { + let (expression, span) = { if ctx.stream.skip_if_kind(LeftPar) { let ret = Some(parse_expression(ctx)?); let rpar_token = ctx.stream.expect_kind(RightPar)?; - (ret, ctx.stream.get_pos(rpar_token).combine(&name)) + (ret, name.span.end_with(rpar_token)) } else { - (None, attr.pos.combine(&name)) + (None, name.span.end_with(attr.token)) } }; - Ok(WithPos { + Ok(WithTokenSpan { item: Name::Attribute(Box::new(AttributeName { name, attr, signature, expr: expression.map(Box::new), })), - pos, + span, }) } @@ -279,15 +306,16 @@ enum DesignatorOrAll { All, } -fn parse_suffix(ctx: &mut ParsingContext<'_>) -> ParseResult> { +fn parse_suffix(ctx: &mut ParsingContext<'_>) -> ParseResult> { let name = { expect_token!( ctx.stream, token, - Identifier => token.to_identifier_value()?.map_into(|ident| DesignatorOrAll::Designator(Designator::Identifier(ident))), - Character => token.to_character_value()?.map_into(|byte| DesignatorOrAll::Designator(Designator::Character(byte))), - StringLiteral => token.to_operator_symbol()?.map_into(|string| DesignatorOrAll::Designator(Designator::OperatorSymbol(string))), - All => WithPos::from(DesignatorOrAll::All, token.pos.clone()) + token_id, + Identifier => token.to_identifier_value(token_id)?.map_into(|ident| DesignatorOrAll::Designator(Designator::Identifier(ident))), + Character => token.to_character_value(token_id)?.map_into(|byte| DesignatorOrAll::Designator(Designator::Character(byte))), + StringLiteral => token.to_operator_symbol(token_id)?.map_into(|string| DesignatorOrAll::Designator(Designator::OperatorSymbol(string))), + All => WithToken::new(DesignatorOrAll::All, token_id) ) }; @@ -306,18 +334,18 @@ fn parse_inner_external_name(ctx: &mut ParsingContext<'_>) -> ParseResult { ctx.stream.skip(); let path_name = parse_name(ctx)?; - let path_pos = path_name.pos.clone().combine_into(&token); - WithPos::from(ExternalPath::Package(path_name), path_pos) + let path_pos = path_name.span.start_with(token_id); + WithTokenSpan::from(ExternalPath::Package(path_name), path_pos) }, Dot => { ctx.stream.skip(); let path_name = parse_name(ctx)?; - let path_pos = path_name.pos.clone().combine_into(&token); - WithPos::from(ExternalPath::Absolute(path_name), path_pos) + let path_pos = path_name.span.start_with(token_id); + WithTokenSpan::from(ExternalPath::Absolute(path_name), path_pos) }, Circ => { ctx.stream.skip(); @@ -328,13 +356,13 @@ fn parse_inner_external_name(ctx: &mut ParsingContext<'_>) -> ParseResult { let path_name = parse_name(ctx)?; - let path_pos = path_name.pos.clone(); - WithPos::from(ExternalPath::Relative(path_name, 0), path_pos) + let path_span = path_name.span; + WithTokenSpan::from(ExternalPath::Relative(path_name, 0), path_span) } ); @@ -349,21 +377,21 @@ fn parse_inner_external_name(ctx: &mut ParsingContext<'_>) -> ParseResult) -> ParseResult> { +fn _parse_name(ctx: &mut ParsingContext<'_>) -> ParseResult> { let mut name = { if let Some(token) = ctx.stream.pop_if_kind(LtLt) { let external_name = Name::External(Box::new(parse_inner_external_name(ctx)?)); let end_token = ctx.stream.expect_kind(GtGt)?; - WithPos::from(external_name, ctx.stream.get_span(token, end_token)) + WithTokenSpan::from(external_name, TokenSpan::new(token, end_token)) } else { let suffix = parse_suffix(ctx)?; match suffix.item { DesignatorOrAll::Designator(designator) => { - WithPos::from(Name::Designator(designator.into_ref()), suffix.pos) + WithTokenSpan::from(Name::Designator(designator.into_ref()), suffix.token) } DesignatorOrAll::All => { return Err(Diagnostic::syntax_error( - suffix.pos, + suffix.pos(ctx), "Illegal prefix 'all' for name", )); } @@ -376,22 +404,22 @@ fn _parse_name(ctx: &mut ParsingContext<'_>) -> ParseResult> { Dot => { ctx.stream.skip(); let suffix = parse_suffix(ctx)?; - let pos = name.pos.combine(&suffix.pos); + let span = name.span.end_with(suffix.token); match suffix.item { DesignatorOrAll::Designator(designator) => { - name = WithPos { + name = WithTokenSpan { item: Name::Selected( Box::new(name), - WithPos::from(designator.into_ref(), suffix.pos), + WithToken::new(designator.into_ref(), suffix.token), ), - pos, + span, } } DesignatorOrAll::All => { - name = WithPos { + name = WithTokenSpan { item: Name::SelectedAll(Box::new(name)), - pos, + span, } } } @@ -426,6 +454,7 @@ fn _parse_name(ctx: &mut ParsingContext<'_>) -> ParseResult> { expect_token!( ctx.stream, sep_token, + sep_token_id, Comma => { name = parse_function_call(ctx, name, assoc)?; }, @@ -439,21 +468,21 @@ fn _parse_name(ctx: &mut ParsingContext<'_>) -> ParseResult> { } }; let rpar_token = ctx.stream.expect_kind(RightPar)?; - let pos = ctx.stream.get_pos(rpar_token).combine(&name); + let span = name.span.end_with(rpar_token); let discrete_range = DiscreteRange::Range(ast::Range::Range(RangeConstraint { - left_expr: Box::new(assoc_to_expression(assoc)?), + left_expr: Box::new(assoc_to_expression(ctx, assoc)?), direction, right_expr: Box::new(right_expr), })); - name = WithPos { + name = WithTokenSpan { item: Name::Slice(Box::new(name), Box::new(discrete_range)), - pos, + span, }; }, RightPar => { - let pos = sep_token.pos.combine(&name); + let span = name.span.end_with(sep_token_id); let item = match into_range(assoc) { Ok(range) => Name::Slice(Box::new(name), Box::new(DiscreteRange::Range(range))), Err(assoc) => Name::CallOrIndexed(Box::new(CallOrIndexed { @@ -462,7 +491,7 @@ fn _parse_name(ctx: &mut ParsingContext<'_>) -> ParseResult> { })), }; - name = WithPos::new(item, pos); + name = WithTokenSpan::new(item, span); } ) } @@ -500,7 +529,7 @@ pub fn into_range(assoc: AssociationElement) -> Result) -> ParseResult> { +pub fn parse_name(ctx: &mut ParsingContext<'_>) -> ParseResult> { let state = ctx.stream.state(); _parse_name(ctx).map_err(|err| { ctx.stream.set_state(state); @@ -521,7 +550,7 @@ mod tests { code.with_stream(parse_selected_name), code.s1("foo") .ident() - .map_into(|sym| Name::Designator(Designator::Identifier(sym).into_ref())) + .map_into_span(|sym| Name::Designator(Designator::Identifier(sym).into_ref())) ); } @@ -543,11 +572,14 @@ mod tests { .ident() .map_into(Designator::Identifier) .into_ref() - .map_into(Name::Designator); - let foo_bar = WithPos::from(Name::Selected(Box::new(foo), bar), code.s1("foo.bar").pos()); - let foo_bar_baz = WithPos::from( + .map_into_span(Name::Designator); + let foo_bar = WithTokenSpan::from( + Name::Selected(Box::new(foo), bar), + code.s1("foo.bar").token_span(), + ); + let foo_bar_baz = WithTokenSpan::from( Name::Selected(Box::new(foo_bar), baz), - code.s1("foo.bar.baz").pos(), + code.s1("foo.bar.baz").token_span(), ); assert_eq!(code.with_stream(parse_selected_name), foo_bar_baz); @@ -561,8 +593,11 @@ mod tests { .ident() .map_into(Designator::Identifier) .into_ref() - .map_into(Name::Designator); - let foo_all = WithPos::from(Name::SelectedAll(Box::new(foo)), code.s1("foo.all").pos()); + .map_into_span(Name::Designator); + let foo_all = WithTokenSpan::from( + Name::SelectedAll(Box::new(foo)), + code.s1("foo.all").token_span(), + ); assert_eq!(code.with_stream(parse_selected_name), foo_all); } @@ -584,9 +619,9 @@ mod tests { let code = Code::new("foo"); assert_eq!( code.with_stream(parse_name), - WithPos { + WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("foo")).into_ref()), - pos: code.s1("foo").pos() + span: code.s1("foo").token_span() } ); } @@ -596,9 +631,9 @@ mod tests { let code = Code::new("'a'"); assert_eq!( code.with_stream(parse_name), - WithPos { + WithTokenSpan { item: Name::Designator(Designator::Character(b'a').into_ref()), - pos: code.s1("'a'").pos() + span: code.s1("'a'").token_span() } ); } @@ -608,9 +643,9 @@ mod tests { let code = Code::new("\"+\""); assert_eq!( code.with_stream(parse_name), - WithPos { + WithTokenSpan { item: Name::Designator(Designator::OperatorSymbol(Operator::Plus).into_ref()), - pos: code.s1("\"+\"").pos() + span: code.s1("\"+\"").token_span() } ); @@ -618,9 +653,9 @@ mod tests { let code = Code::new("\"AND\""); assert_eq!( code.with_stream(parse_name), - WithPos { + WithTokenSpan { item: Name::Designator(Designator::OperatorSymbol(Operator::And).into_ref()), - pos: code.s1("\"AND\"").pos() + span: code.s1("\"AND\"").token_span() } ); @@ -628,9 +663,9 @@ mod tests { let code = Code::new("\"and\""); assert_eq!( code.with_stream(parse_name), - WithPos { + WithTokenSpan { item: Name::Designator(Designator::OperatorSymbol(Operator::And).into_ref()), - pos: code.s1("\"and\"").pos() + span: code.s1("\"and\"").token_span() } ); } @@ -639,29 +674,29 @@ mod tests { fn test_selected_name() { let code = Code::new("foo.bar.baz"); - let foo = WithPos { + let foo = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("foo")).into_ref()), - pos: code.s1("foo").pos(), + span: code.s1("foo").token_span(), }; - let bar = WithPos { + let bar = WithToken { item: Designator::Identifier(code.symbol("bar")), - pos: code.s1("bar").pos(), + token: code.s1("bar").token(), }; - let baz = WithPos { + let baz = WithToken { item: Designator::Identifier(code.symbol("baz")), - pos: code.s1("baz").pos(), + token: code.s1("baz").token(), }; - let foo_bar = WithPos { + let foo_bar = WithTokenSpan { item: Name::Selected(Box::new(foo), bar.into_ref()), - pos: code.s1("foo.bar").pos(), + span: code.s1("foo.bar").token_span(), }; - let foo_bar_baz = WithPos { + let foo_bar_baz = WithTokenSpan { item: Name::Selected(Box::new(foo_bar), baz.into_ref()), - pos: code.s1("foo.bar.baz").pos(), + span: code.s1("foo.bar.baz").token_span(), }; assert_eq!(code.with_stream(parse_name), foo_bar_baz); @@ -671,14 +706,14 @@ mod tests { fn test_selected_name_all() { let code = Code::new("foo.all"); - let foo = WithPos { + let foo = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("foo")).into_ref()), - pos: code.s1("foo").pos(), + span: code.s1("foo").token_span(), }; - let foo_all = WithPos { + let foo_all = WithTokenSpan { item: Name::SelectedAll(Box::new(foo)), - pos: code.s1("foo.all").pos(), + span: code.s1("foo.all").token_span(), }; assert_eq!(code.with_stream(parse_name), foo_all); @@ -687,16 +722,16 @@ mod tests { #[test] fn test_slice_name_range_to() { let code = Code::new("prefix(0 to 3)"); - let prefix = WithPos { + let prefix = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("prefix")).into_ref()), - pos: code.s1("prefix").pos(), + span: code.s1("prefix").token_span(), }; - let slice = WithPos { + let slice = WithTokenSpan { item: Name::Slice( Box::new(prefix), Box::new(code.s1("0 to 3").discrete_range()), ), - pos: code.s1("prefix(0 to 3)").pos(), + span: code.s1("prefix(0 to 3)").token_span(), }; assert_eq!(code.with_stream(parse_name), slice); } @@ -704,16 +739,16 @@ mod tests { #[test] fn test_slice_name_range_downto() { let code = Code::new("prefix(3 downto 0)"); - let prefix = WithPos { + let prefix = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("prefix")).into_ref()), - pos: code.s1("prefix").pos(), + span: code.s1("prefix").token_span(), }; - let slice = WithPos { + let slice = WithTokenSpan { item: Name::Slice( Box::new(prefix), Box::new(code.s1("3 downto 0").discrete_range()), ), - pos: code.s1("prefix(3 downto 0)").pos(), + span: code.s1("prefix(3 downto 0)").token_span(), }; assert_eq!(code.with_stream(parse_name), slice); } @@ -721,16 +756,16 @@ mod tests { #[test] fn test_slice_range_attribute() { let code = Code::new("prefix(foo(0)'range)"); - let prefix = WithPos { + let prefix = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("prefix")).into_ref()), - pos: code.s1("prefix").pos(), + span: code.s1("prefix").token_span(), }; - let slice = WithPos { + let slice = WithTokenSpan { item: Name::Slice( Box::new(prefix), Box::new(code.s1("foo(0)'range").discrete_range()), ), - pos: code.s1("prefix(foo(0)'range)").pos(), + span: code.s1("prefix(foo(0)'range)").token_span(), }; assert_eq!(code.with_stream(parse_name), slice); } @@ -738,18 +773,18 @@ mod tests { #[test] fn test_attribute_name() { let code = Code::new("prefix'foo"); - let prefix = WithPos { + let prefix = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("prefix")).into_ref()), - pos: code.s1("prefix").pos(), + span: code.s1("prefix").token_span(), }; - let attr = WithPos { + let attr = WithTokenSpan { item: Name::Attribute(Box::new(AttributeName { name: prefix, attr: code.s1("foo").attr_ident(), signature: None, expr: None, })), - pos: code.s1("prefix'foo").pos(), + span: code.s1("prefix'foo").token_span(), }; assert_eq!(code.with_stream(parse_name), attr); } @@ -757,21 +792,21 @@ mod tests { #[test] fn test_attribute_name_range() { let code = Code::new("prefix'range"); - let prefix = WithPos { + let prefix = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("prefix")).into_ref()), - pos: code.s1("prefix").pos(), + span: code.s1("prefix").token_span(), }; - let attr = WithPos { + let attr = WithTokenSpan { item: Name::Attribute(Box::new(AttributeName { name: prefix, - attr: WithPos { + attr: WithToken { item: AttributeDesignator::Range(RangeAttribute::Range), - pos: code.s1("range").pos(), + token: code.s1("range").token(), }, signature: None, expr: None, })), - pos: code.s1("prefix'range").pos(), + span: code.s1("prefix'range").token_span(), }; assert_eq!(code.with_stream(parse_name), attr); } @@ -779,21 +814,21 @@ mod tests { #[test] fn test_attribute_name_subtype() { let code = Code::new("prefix'subtype"); - let prefix = WithPos { + let prefix = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("prefix")).into_ref()), - pos: code.s1("prefix").pos(), + span: code.s1("prefix").token_span(), }; - let attr = WithPos { + let attr = WithTokenSpan { item: Name::Attribute(Box::new(AttributeName { name: prefix, - attr: WithPos { + attr: WithToken { item: AttributeDesignator::Type(TypeAttribute::Subtype), - pos: code.s1("subtype").pos(), + token: code.s1("subtype").token(), }, signature: None, expr: None, })), - pos: code.s1("prefix'subtype").pos(), + span: code.s1("prefix'subtype").token_span(), }; assert_eq!(code.with_stream(parse_name), attr); } @@ -801,21 +836,21 @@ mod tests { #[test] fn test_attribute_name_element() { let code = Code::new("prefix'element"); - let prefix = WithPos { + let prefix = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("prefix")).into_ref()), - pos: code.s1("prefix").pos(), + span: code.s1("prefix").token_span(), }; - let attr = WithPos { + let attr = WithTokenSpan { item: Name::Attribute(Box::new(AttributeName { name: prefix, - attr: WithPos { + attr: WithToken { item: AttributeDesignator::Type(TypeAttribute::Element), - pos: code.s1("element").pos(), + token: code.s1("element").token(), }, signature: None, expr: None, })), - pos: code.s1("prefix'element").pos(), + span: code.s1("prefix'element").token_span(), }; assert_eq!(code.with_stream(parse_name), attr); } @@ -827,8 +862,8 @@ mod tests { assert_eq!( code.with_stream(parse_type_mark), - WithPos { - pos: name.pos.clone(), + WithTokenSpan { + span: name.span, item: TypeMark { name, attr: None }, } ); @@ -840,8 +875,8 @@ mod tests { assert_eq!( code.with_stream(parse_type_mark), - WithPos { - pos: code.pos(), + WithTokenSpan { + span: code.token_span(), item: TypeMark { name: code.s1("prefix").name(), attr: Some(TypeAttribute::Subtype) @@ -856,8 +891,8 @@ mod tests { assert_eq!( code.with_stream(parse_type_mark), - WithPos { - pos: code.pos(), + WithTokenSpan { + span: code.token_span(), item: TypeMark { name: code.s1("prefix").name(), attr: Some(TypeAttribute::Element) @@ -869,18 +904,18 @@ mod tests { #[test] fn test_attribute_name_expression() { let code = Code::new("prefix'foo(expr+1)"); - let prefix = WithPos { + let prefix = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("prefix")).into_ref()), - pos: code.s1("prefix").pos(), + span: code.s1("prefix").token_span(), }; - let attr = WithPos { + let attr = WithTokenSpan { item: Name::Attribute(Box::new(AttributeName { name: prefix, attr: code.s1("foo").attr_ident(), signature: None, expr: Some(Box::new(code.s1("expr+1").expr())), })), - pos: code.s1("prefix'foo(expr+1)").pos(), + span: code.s1("prefix'foo(expr+1)").token_span(), }; assert_eq!(code.with_stream(parse_name), attr); } @@ -888,18 +923,18 @@ mod tests { #[test] fn test_attribute_name_signature_expression() { let code = Code::new("prefix[return natural]'foo(expr+1)"); - let prefix = WithPos { + let prefix = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("prefix")).into_ref()), - pos: code.s1("prefix").pos(), + span: code.s1("prefix").token_span(), }; - let attr = WithPos { + let attr = WithTokenSpan { item: Name::Attribute(Box::new(AttributeName { name: prefix, attr: code.s1("foo").attr_ident(), signature: Some(code.s1("[return natural]").signature()), expr: Some(Box::new(code.s1("expr+1").expr())), })), - pos: code.s1("prefix[return natural]'foo(expr+1)").pos(), + span: code.s1("prefix[return natural]'foo(expr+1)").token_span(), }; assert_eq!(code.with_stream(parse_name), attr); } @@ -913,9 +948,9 @@ mod tests { ctx.stream.expect_kind(LeftSquare)?; result }); - let prefix = WithPos { + let prefix = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("prefix")).into_ref()), - pos: code.s1("prefix").pos(), + span: code.s1("prefix").token_span(), }; assert_eq!(name, Ok(prefix)); } @@ -929,9 +964,9 @@ mod tests { ctx.stream.expect_kind(LeftPar)?; result }); - let prefix = WithPos { + let prefix = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("prefix")).into_ref()), - pos: code.s1("prefix").pos(), + span: code.s1("prefix").token_span(), }; assert_eq!(name, prefix); } @@ -940,12 +975,12 @@ mod tests { fn test_function_call_no_formal() { let code = Code::new("foo(0)"); - let foo = WithPos { + let foo = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("foo")).into_ref()), - pos: code.s1("foo").pos(), + span: code.s1("foo").token_span(), }; - let foo_0 = WithPos { + let foo_0 = WithTokenSpan { item: Name::CallOrIndexed(Box::new(CallOrIndexed { name: foo, parameters: vec![AssociationElement { @@ -953,7 +988,7 @@ mod tests { actual: code.s1("0").expr().map_into(ActualPart::Expression), }], })), - pos: code.s1("foo(0)").pos(), + span: code.s1("foo(0)").token_span(), }; assert_eq!(code.with_stream(parse_name), foo_0); @@ -963,12 +998,12 @@ mod tests { fn test_function_call_many() { let code = Code::new("prefix(0, 1)(3).suffix"); - let prefix = WithPos { + let prefix = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("prefix")).into_ref()), - pos: code.s1("prefix").pos(), + span: code.s1("prefix").token_span(), }; - let prefix_index = WithPos { + let prefix_index = WithTokenSpan { item: Name::CallOrIndexed(Box::new(CallOrIndexed { name: prefix, parameters: vec![ @@ -982,10 +1017,10 @@ mod tests { }, ], })), - pos: code.s1("prefix(0, 1)").pos(), + span: code.s1("prefix(0, 1)").token_span(), }; - let prefix_index_3 = WithPos { + let prefix_index_3 = WithTokenSpan { item: Name::CallOrIndexed(Box::new(CallOrIndexed { name: prefix_index, parameters: vec![AssociationElement { @@ -993,17 +1028,17 @@ mod tests { actual: code.s1("3").expr().map_into(ActualPart::Expression), }], })), - pos: code.s1("prefix(0, 1)(3)").pos(), + span: code.s1("prefix(0, 1)(3)").token_span(), }; - let suffix = WithPos { + let suffix = WithToken { item: Designator::Identifier(code.symbol("suffix")), - pos: code.s1("suffix").pos(), + token: code.s1("suffix").token(), }; - let prefix_index_3_suffix = WithPos { + let prefix_index_3_suffix = WithTokenSpan { item: Name::Selected(Box::new(prefix_index_3), suffix.into_ref()), - pos: code.s1("prefix(0, 1)(3).suffix").pos(), + span: code.s1("prefix(0, 1)(3).suffix").token_span(), }; assert_eq!(code.with_stream(parse_name), prefix_index_3_suffix); @@ -1013,14 +1048,14 @@ mod tests { fn test_function_call() { let code = Code::new("foo(arg => 0)"); - let foo = WithPos { + let foo = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("foo")).into_ref()), - pos: code.s1("foo").pos(), + span: code.s1("foo").token_span(), }; - let arg = WithPos { + let arg = WithTokenSpan { item: Name::Designator(Designator::Identifier(code.symbol("arg")).into_ref()), - pos: code.s1("arg").pos(), + span: code.s1("arg").token_span(), }; let assoc_elem = AssociationElement { @@ -1028,12 +1063,12 @@ mod tests { actual: code.s1("0").expr().map_into(ActualPart::Expression), }; - let foo_call = WithPos { + let foo_call = WithTokenSpan { item: Name::CallOrIndexed(Box::new(CallOrIndexed { name: foo, parameters: vec![assoc_elem], })), - pos: code.s1("foo(arg => 0)").pos(), + span: code.s1("foo(arg => 0)").token_span(), }; assert_eq!(code.with_stream(parse_name), foo_call); @@ -1044,11 +1079,11 @@ mod tests { let code = Code::new("(open, arg => open)"); let elem1 = AssociationElement { formal: None, - actual: WithPos::new(ActualPart::Open, code.s1("open").pos()), + actual: WithTokenSpan::new(ActualPart::Open, code.s1("open").token_span()), }; let elem2 = AssociationElement { formal: Some(code.s1("arg").name()), - actual: WithPos::new(ActualPart::Open, code.s("open", 2)), + actual: WithTokenSpan::new(ActualPart::Open, code.s("open", 2).token_span()), }; assert_eq!( code.with_stream_no_diagnostics(parse_association_list), @@ -1067,15 +1102,15 @@ mod tests { let code = Code::new("<< signal dut.foo : std_logic >>"); let external_name = ExternalName { class: ExternalObjectClass::Signal, - path: WithPos::new( + path: WithTokenSpan::new( ExternalPath::Relative(code.s1("dut.foo").name(), 0), - code.s1("dut.foo").pos(), + code.s1("dut.foo").token_span(), ), subtype: code.s1("std_logic").subtype_indication(), }; assert_eq!( code.with_stream(parse_name), - WithPos::new(Name::External(Box::new(external_name)), code) + WithTokenSpan::new(Name::External(Box::new(external_name)), code.token_span()) ); } @@ -1084,15 +1119,15 @@ mod tests { let code = Code::new("<< signal ^.dut.gen(0) : std_logic >>"); let external_name = ExternalName { class: ExternalObjectClass::Signal, - path: WithPos::new( + path: WithTokenSpan::new( ExternalPath::Relative(code.s1("dut.gen(0)").name(), 1), - code.s1("^.dut.gen(0)").pos(), + code.s1("^.dut.gen(0)").token_span(), ), subtype: code.s1("std_logic").subtype_indication(), }; assert_eq!( code.with_stream(parse_name), - WithPos::new(Name::External(Box::new(external_name)), code) + WithTokenSpan::new(Name::External(Box::new(external_name)), code.token_span()) ); } @@ -1101,15 +1136,15 @@ mod tests { let code = Code::new("<< signal ^.^.^.dut.gen(0) : std_logic >>"); let external_name = ExternalName { class: ExternalObjectClass::Signal, - path: WithPos::new( + path: WithTokenSpan::new( ExternalPath::Relative(code.s1("dut.gen(0)").name(), 3), - code.s1("^.^.^.dut.gen(0)").pos(), + code.s1("^.^.^.dut.gen(0)").token_span(), ), subtype: code.s1("std_logic").subtype_indication(), }; assert_eq!( code.with_stream(parse_name), - WithPos::new(Name::External(Box::new(external_name)), code) + WithTokenSpan::new(Name::External(Box::new(external_name)), code.token_span()) ); } @@ -1118,15 +1153,15 @@ mod tests { let code = Code::new("<< signal .dut.gen(0) : std_logic >>"); let external_name = ExternalName { class: ExternalObjectClass::Signal, - path: WithPos::new( + path: WithTokenSpan::new( ExternalPath::Absolute(code.s1("dut.gen(0)").name()), - code.s1(".dut.gen(0)").pos(), + code.s1(".dut.gen(0)").token_span(), ), subtype: code.s1("std_logic").subtype_indication(), }; assert_eq!( code.with_stream(parse_name), - WithPos::new(Name::External(Box::new(external_name)), code) + WithTokenSpan::new(Name::External(Box::new(external_name)), code.token_span()) ); } @@ -1135,15 +1170,15 @@ mod tests { let code = Code::new("<< signal @lib.pkg : std_logic >>"); let external_name = ExternalName { class: ExternalObjectClass::Signal, - path: WithPos::new( + path: WithTokenSpan::new( ExternalPath::Package(code.s1("lib.pkg").name()), - code.s1("@lib.pkg").pos(), + code.s1("@lib.pkg").token_span(), ), subtype: code.s1("std_logic").subtype_indication(), }; assert_eq!( code.with_stream(parse_name), - WithPos::new(Name::External(Box::new(external_name)), code) + WithTokenSpan::new(Name::External(Box::new(external_name)), code.token_span()) ); } @@ -1158,15 +1193,15 @@ mod tests { let code = Code::new(&format!("<< {string} dut.foo : std_logic >>")); let external_name = ExternalName { class, - path: WithPos::new( + path: WithTokenSpan::new( ExternalPath::Relative(code.s1("dut.foo").name(), 0), - code.s1("dut.foo").pos(), + code.s1("dut.foo").token_span(), ), subtype: code.s1("std_logic").subtype_indication(), }; assert_eq!( code.with_stream(parse_name), - WithPos::new(Name::External(Box::new(external_name)), code) + WithTokenSpan::new(Name::External(Box::new(external_name)), code.token_span()) ); } } diff --git a/vhdl_lang/src/syntax/object_declaration.rs b/vhdl_lang/src/syntax/object_declaration.rs index 41d50d72..07b904ad 100644 --- a/vhdl_lang/src/syntax/object_declaration.rs +++ b/vhdl_lang/src/syntax/object_declaration.rs @@ -9,15 +9,15 @@ use super::expression::parse_expression; use super::names::parse_identifier_list; use super::subtype_indication::parse_subtype_indication; use super::tokens::{Kind::*, TokenSpan}; +use crate::ast::token_range::WithTokenSpan; /// LRM 6.4.2 Object Declarations use crate::ast::*; -use crate::data::WithPos; use crate::Diagnostic; use vhdl_lang::syntax::parser::ParsingContext; pub fn parse_optional_assignment( ctx: &mut ParsingContext<'_>, -) -> ParseResult>> { +) -> ParseResult>> { if ctx.stream.pop_if_kind(ColonEq).is_some() { let expr = parse_expression(ctx)?; Ok(Some(expr)) @@ -109,7 +109,7 @@ pub fn parse_file_declaration(ctx: &mut ParsingContext<'_>) -> ParseResult, @@ -23,6 +25,16 @@ pub(crate) struct ParsingContext<'a> { pub standard: VHDLStandard, } +impl TokenAccess for ParsingContext<'_> { + fn get_token(&self, id: TokenId) -> &Token { + self.stream.get_token(id) + } + + fn get_token_slice(&self, start_id: TokenId, end_id: TokenId) -> &[Token] { + self.stream.get_token_slice(start_id, end_id) + } +} + pub type ParserResult = Result<(Source, DesignFile), io::Error>; impl VHDLParser { diff --git a/vhdl_lang/src/syntax/range.rs b/vhdl_lang/src/syntax/range.rs index cfcf0b1a..35c7c144 100644 --- a/vhdl_lang/src/syntax/range.rs +++ b/vhdl_lang/src/syntax/range.rs @@ -10,8 +10,9 @@ use super::expression::name_to_type_mark; use super::expression::parse_expression; use super::tokens::Kind::*; use crate::ast; +use crate::ast::token_range::WithTokenSpan; use crate::ast::*; -use crate::data::{Diagnostic, WithPos}; +use crate::data::Diagnostic; use vhdl_lang::syntax::parser::ParsingContext; pub fn parse_direction(ctx: &mut ParsingContext) -> ParseResult { @@ -23,8 +24,8 @@ pub fn parse_direction(ctx: &mut ParsingContext) -> ParseResult { } enum NameOrRange { - Name(WithPos), - Range(WithPos), + Name(WithTokenSpan), + Range(WithTokenSpan), } fn parse_name_or_range(ctx: &mut ParsingContext<'_>) -> ParseResult { @@ -35,48 +36,51 @@ fn parse_name_or_range(ctx: &mut ParsingContext<'_>) -> ParseResult let direction = parse_direction(ctx)?; let right_expr = parse_expression(ctx)?; - let pos = expr.pos.combine(&right_expr.pos); + let span = expr.span.combine(right_expr.span); let range = ast::Range::Range(RangeConstraint { direction, left_expr: Box::new(expr), right_expr: Box::new(right_expr), }); - return Ok(NameOrRange::Range(WithPos::from(range, pos))); + return Ok(NameOrRange::Range(WithTokenSpan::from(range, span))); } _ => {} } - if let WithPos { + if let WithTokenSpan { item: Expression::Name(name), - pos, + span, } = expr { if let Name::Attribute(attribute_name) = *name { if attribute_name.as_range().is_some() { let range = ast::Range::Attribute(attribute_name); - Ok(NameOrRange::Range(WithPos::from(range, pos))) + Ok(NameOrRange::Range(WithTokenSpan::from(range, span))) } else { - Ok(NameOrRange::Name(WithPos::from( + Ok(NameOrRange::Name(WithTokenSpan::from( Name::Attribute(attribute_name), - pos, + span, ))) } } else { - Ok(NameOrRange::Name(WithPos::from(*name, pos))) + Ok(NameOrRange::Name(WithTokenSpan::from(*name, span))) } } else { - Err(Diagnostic::syntax_error(&expr, "Expected name or range")) + Err(Diagnostic::syntax_error( + expr.pos(ctx), + "Expected name or range", + )) } } /// {selected_name}'range /// {selected_name}'reverse_range /// 2. {expr} to|downto {expr} -pub fn parse_range(ctx: &mut ParsingContext<'_>) -> ParseResult> { +pub fn parse_range(ctx: &mut ParsingContext<'_>) -> ParseResult> { match parse_name_or_range(ctx)? { NameOrRange::Range(range) => Ok(range), - NameOrRange::Name(name) => Err(Diagnostic::syntax_error(&name, "Expected range")), + NameOrRange::Name(name) => Err(Diagnostic::syntax_error(name.pos(ctx), "Expected range")), } } @@ -84,7 +88,7 @@ pub fn parse_discrete_range(ctx: &mut ParsingContext<'_>) -> ParseResult Ok(DiscreteRange::Range(range.item)), Ok(NameOrRange::Name(name)) => { - let type_mark = name_to_type_mark(name)?; + let type_mark = name_to_type_mark(ctx, name)?; let range = parse_optional(ctx, Range, parse_range)?.map(|range| range.item); Ok(DiscreteRange::Discrete(type_mark, range)) } @@ -96,7 +100,7 @@ pub fn parse_array_index_constraint(ctx: &mut ParsingContext<'_>) -> ParseResult match parse_name_or_range(ctx) { Ok(NameOrRange::Range(range)) => Ok(ArrayIndex::Discrete(DiscreteRange::Range(range.item))), Ok(NameOrRange::Name(name)) => { - let type_mark = name_to_type_mark(name)?; + let type_mark = name_to_type_mark(ctx, name)?; if ctx.stream.skip_if_kind(Range) { if ctx.stream.skip_if_kind(BOX) { @@ -127,13 +131,13 @@ mod tests { let code = Code::new("foo.bar to 1"); assert_eq!( code.with_stream(parse_range), - WithPos::new( + WithTokenSpan::new( ast::Range::Range(RangeConstraint { direction: Direction::Ascending, left_expr: Box::new(code.s1("foo.bar").expr()), right_expr: Box::new(code.s1("1").expr()) },), - code.pos() + code.token_span() ) ); } @@ -143,9 +147,9 @@ mod tests { let code = Code::new("foo.bar'range"); assert_eq!( code.with_stream(parse_range), - WithPos::new( + WithTokenSpan::new( ast::Range::Attribute(Box::new(code.s1("foo.bar'range").attribute_name())), - code.pos() + code.token_span() ) ); } @@ -155,9 +159,9 @@ mod tests { let code = Code::new("foo.bar'reverse_range"); assert_eq!( code.with_stream(parse_range), - WithPos::new( + WithTokenSpan::new( ast::Range::Attribute(Box::new(code.s1("foo.bar'reverse_range").attribute_name())), - code.pos() + code.token_span() ) ); } @@ -167,13 +171,13 @@ mod tests { let code = Code::new("foo.bar'length downto 0"); assert_eq!( code.with_stream(parse_range), - WithPos::new( + WithTokenSpan::new( ast::Range::Range(RangeConstraint { direction: Direction::Descending, left_expr: Box::new(code.s1("foo.bar'length").expr()), right_expr: Box::new(code.s1("0").expr()) }), - code.pos() + code.token_span() ) ); } diff --git a/vhdl_lang/src/syntax/sequential_statement.rs b/vhdl_lang/src/syntax/sequential_statement.rs index 971dd706..b95c181d 100644 --- a/vhdl_lang/src/syntax/sequential_statement.rs +++ b/vhdl_lang/src/syntax/sequential_statement.rs @@ -12,10 +12,12 @@ use super::names::parse_name; use super::range::parse_discrete_range; use super::tokens::Kind::*; use super::waveform::{parse_delay_mechanism, parse_waveform}; +use crate::ast::token_range::WithTokenSpan; use crate::ast::*; use crate::data::*; use crate::syntax::common::check_label_identifier_mismatch; use vhdl_lang::syntax::parser::ParsingContext; +use vhdl_lang::TokenSpan; /// LRM 10.2 Wait statement fn parse_wait_statement(ctx: &mut ParsingContext<'_>) -> ParseResult { @@ -286,7 +288,7 @@ pub fn parse_signal_assignment_right_hand( /// LRM 10.6 Variable assignment statement fn parse_variable_assignment_right_hand( ctx: &mut ParsingContext<'_>, -) -> ParseResult>> { +) -> ParseResult>> { parse_assignment_right_hand(ctx, parse_expression) } @@ -366,7 +368,7 @@ where pub fn parse_selection( ctx: &mut ParsingContext<'_>, - expression: WithPos, + expression: WithTokenSpan, parse_item: F, ) -> ParseResult> where @@ -413,7 +415,7 @@ fn parse_optional_force_mode(ctx: &mut ParsingContext<'_>) -> ParseResult