Skip to content

Commit 60e21e6

Browse files
authored
Add initial support for different VHDL standards (#284)
1 parent 84269c3 commit 60e21e6

File tree

15 files changed

+699
-371
lines changed

15 files changed

+699
-371
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,21 @@ configuration file in the [TOML](https://github.com/toml-lang/toml) format named
132132

133133
Settings in a later files overwrites those from previously loaded files.
134134

135+
Define the VHDL revision to use for parsing and analysis with the `standard` key.
136+
The expected value is the year associated the VHDL standard.
137+
Supported standards are 1993, 2008 and 2019 where both the long version ("2008") and the short version ("08") can be
138+
used.
139+
If nothing is specified, 2008 is used.
140+
141+
> [!NOTE]
142+
> Defining the standard feature is a relatively new feature (since april 2024).
143+
> Anything but the 2008 standard will not change much at the moment.
144+
135145
**Example vhdl_ls.toml**
136146

137147
```toml
148+
# What standard to use. This is optional and defaults to VHDL2008.
149+
standard = "2008"
138150
# File names are either absolute or relative to the parent folder of the vhdl_ls.toml file
139151
[libraries]
140152
lib2.files = [

vhdl_lang/src/analysis/names.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,7 @@ impl<'a> AnalyzeContext<'a> {
825825
Err(EvalError::Unknown)
826826
}
827827
}
828-
AttributeDesignator::Ascending | AttributeDesignator::Descending => {
828+
AttributeDesignator::Ascending => {
829829
let typ = prefix.as_type_of_attr_prefix(prefix_pos, attr, diagnostics)?;
830830

831831
if typ.array_type().is_some() {
@@ -2558,14 +2558,6 @@ constant c0 : arr_t := (others => 0);
25582558
test.ctx().boolean()
25592559
)))
25602560
);
2561-
2562-
let code = test.snippet("arr_t'descending");
2563-
assert_eq!(
2564-
test.name_resolve(&code, None, &mut NoDiagnostics),
2565-
Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous(
2566-
test.ctx().boolean()
2567-
)))
2568-
);
25692561
}
25702562

25712563
#[test]

vhdl_lang/src/ast.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ pub enum AttributeDesignator {
107107
Range(RangeAttribute),
108108
Ident(WithRef<Symbol>),
109109
Ascending,
110-
Descending,
111110
Left,
112111
Right,
113112
High,

vhdl_lang/src/ast/display.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ impl Display for AttributeDesignator {
102102
AttributeDesignator::Range(r) => write!(f, "{r}"),
103103
AttributeDesignator::Type(t) => write!(f, "{t}"),
104104
AttributeDesignator::Ascending => write!(f, "ascending"),
105-
AttributeDesignator::Descending => write!(f, "descending"),
106105
AttributeDesignator::Left => write!(f, "left"),
107106
AttributeDesignator::Right => write!(f, "right"),
108107
AttributeDesignator::Low => write!(f, "low"),

vhdl_lang/src/config.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ use toml::{Table, Value};
1818

1919
use crate::data::error_codes::ErrorCode;
2020
use crate::data::*;
21+
use crate::standard::VHDLStandard;
2122

2223
#[derive(Clone, PartialEq, Eq, Default, Debug)]
2324
pub struct Config {
2425
// A map from library name to file name
2526
libraries: FnvHashMap<String, LibraryConfig>,
27+
standard: VHDLStandard,
2628
// Defines the severity that diagnostics are displayed with
2729
severities: SeverityMap,
2830
}
@@ -111,6 +113,14 @@ impl Config {
111113
let config = string.parse::<Value>().map_err(|err| err.to_string())?;
112114
let mut libraries = FnvHashMap::default();
113115

116+
let standard = if let Some(std) = config.get("standard") {
117+
let std_str = std.as_str().ok_or("standard must be a string")?;
118+
VHDLStandard::try_from(std_str)
119+
.map_err(|_| format!("Unsupported standard '{std_str}'"))?
120+
} else {
121+
VHDLStandard::default()
122+
};
123+
114124
let libs = config
115125
.get("libraries")
116126
.ok_or("missing field libraries")?
@@ -177,6 +187,7 @@ impl Config {
177187
Ok(Config {
178188
libraries,
179189
severities,
190+
standard,
180191
})
181192
}
182193

@@ -225,6 +236,7 @@ impl Config {
225236
///
226237
/// In case of conflict the appended config takes precedence
227238
pub fn append(&mut self, config: &Config, messages: &mut dyn MessageHandler) {
239+
self.standard = config.standard;
228240
for library in config.iter_libraries() {
229241
if let Some(parent_library) = self.libraries.get_mut(&library.name) {
230242
*parent_library = library.clone();
@@ -321,6 +333,12 @@ impl Config {
321333
pub fn severities(&self) -> &SeverityMap {
322334
&self.severities
323335
}
336+
337+
/// The VHDL standard to use if no more specific config is present.
338+
/// By default, VHDL 2008 is assumed
339+
pub fn standard(&self) -> VHDLStandard {
340+
self.standard
341+
}
324342
}
325343

326344
fn substitute_environment_variables<'a, M>(s: &str, map: &'a M) -> Result<String, String>

vhdl_lang/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ mod project;
2121
mod syntax;
2222

2323
mod completion;
24+
mod standard;
2425

2526
pub use crate::config::Config;
2627
pub use crate::data::{
@@ -40,3 +41,4 @@ pub use crate::syntax::{
4041
};
4142

4243
pub use completion::{list_completion_options, CompletionItem};
44+
pub use standard::VHDLStandard;

vhdl_lang/src/project.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::completion::{list_completion_options, CompletionItem};
1111
use crate::config::Config;
1212
use crate::lint::dead_code::UnusedDeclarationsLinter;
1313
use crate::named_entity::{AnyEnt, EntRef};
14+
use crate::standard::VHDLStandard;
1415
use crate::syntax::VHDLParser;
1516
use crate::{data::*, EntHierarchy, EntityId};
1617
use fnv::{FnvHashMap, FnvHashSet};
@@ -28,8 +29,8 @@ pub struct Project {
2829
}
2930

3031
impl Project {
31-
pub fn new() -> Project {
32-
let parser = VHDLParser::default();
32+
pub fn new(vhdl_standard: VHDLStandard) -> Project {
33+
let parser = VHDLParser::new(vhdl_standard);
3334
Project {
3435
root: DesignRoot::new(parser.symbols.clone()),
3536
files: FnvHashMap::default(),
@@ -47,7 +48,7 @@ impl Project {
4748
/// Create instance from given configuration.
4849
/// Files referred by configuration are parsed into corresponding libraries.
4950
pub fn from_config(config: Config, messages: &mut dyn MessageHandler) -> Project {
50-
let mut project = Project::new();
51+
let mut project = Project::new(config.standard());
5152
let files = project.load_files_from_config(&config, messages);
5253
project.parse_and_add_files(files, messages);
5354
project.config = config;
@@ -58,7 +59,7 @@ impl Project {
5859
/// The design state is reset, new files are added and parsed. Existing source files will be
5960
/// kept and parsed from in-memory source (required for incremental document updates).
6061
pub fn update_config(&mut self, config: Config, messages: &mut dyn MessageHandler) {
61-
self.parser = VHDLParser::default();
62+
self.parser = VHDLParser::new(config.standard());
6263
self.root = DesignRoot::new(self.parser.symbols.clone());
6364

6465
// Reset library associations for known files,
@@ -344,12 +345,6 @@ fn multiply<T: Clone>(value: T, n: usize) -> Vec<T> {
344345
}
345346
}
346347

347-
impl Default for Project {
348-
fn default() -> Self {
349-
Self::new()
350-
}
351-
}
352-
353348
pub struct SourceFile {
354349
library_names: FnvHashSet<Symbol>,
355350
source: Source,

vhdl_lang/src/standard.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#[derive(Clone, Copy, PartialEq, Eq, Default, Debug, Ord, PartialOrd)]
2+
pub enum VHDLStandard {
3+
VHDL1993,
4+
#[default]
5+
VHDL2008,
6+
VHDL2019,
7+
}
8+
9+
#[test]
10+
fn order_of_standards() {
11+
assert!(VHDLStandard::VHDL2008 > VHDLStandard::VHDL1993);
12+
}
13+
14+
impl TryFrom<&str> for VHDLStandard {
15+
type Error = ();
16+
17+
fn try_from(value: &str) -> Result<Self, Self::Error> {
18+
use VHDLStandard::*;
19+
Ok(match value {
20+
"1993" | "93" => VHDL1993,
21+
"2008" | "08" => VHDL2008,
22+
"2019" | "19" => VHDL2019,
23+
_ => return Err(()),
24+
})
25+
}
26+
}
27+
28+
impl AsRef<str> for VHDLStandard {
29+
fn as_ref(&self) -> &str {
30+
use VHDLStandard::*;
31+
match self {
32+
VHDL1993 => "1993",
33+
VHDL2008 => "2008",
34+
VHDL2019 => "2019",
35+
}
36+
}
37+
}

vhdl_lang/src/syntax/parser.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,23 @@ use super::design_unit::parse_design_file;
88
use super::tokens::{Symbols, TokenStream, Tokenizer};
99
use crate::ast::DesignFile;
1010
use crate::data::*;
11+
use crate::standard::VHDLStandard;
1112
use std::io;
1213
use std::sync::Arc;
1314

14-
#[derive(Default)]
1515
pub struct VHDLParser {
1616
pub symbols: Arc<Symbols>,
1717
}
1818

1919
pub type ParserResult = Result<(Source, DesignFile), io::Error>;
2020

2121
impl VHDLParser {
22+
pub fn new(vhdl_standard: VHDLStandard) -> VHDLParser {
23+
VHDLParser {
24+
symbols: Arc::new(Symbols::from_standard(vhdl_standard)),
25+
}
26+
}
27+
2228
pub fn symbol(&self, name: &Latin1String) -> Symbol {
2329
self.symbols.symtab().insert(name)
2430
}

vhdl_lang/src/syntax/test.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use crate::ast;
3333
use crate::ast::*;
3434
use crate::data::Range;
3535
use crate::data::*;
36+
use crate::standard::VHDLStandard;
3637
use crate::syntax::concurrent_statement::parse_map_aspect;
3738
use crate::syntax::context::{parse_context, DeclarationOrReference};
3839
use crate::syntax::names::parse_association_element;
@@ -81,6 +82,12 @@ impl CodeBuilder {
8182
}
8283
}
8384

85+
pub fn with_standard(vhdl_standard: VHDLStandard) -> CodeBuilder {
86+
CodeBuilder {
87+
symbols: Arc::new(Symbols::from_standard(vhdl_standard)),
88+
}
89+
}
90+
8491
pub fn code_from_source(&self, source: Source) -> Code {
8592
let contents = source.contents();
8693

@@ -132,6 +139,10 @@ impl Code {
132139
CodeBuilder::new().code(code)
133140
}
134141

142+
pub fn with_standard(code: &str, vhdl_standard: VHDLStandard) -> Code {
143+
CodeBuilder::with_standard(vhdl_standard).code(code)
144+
}
145+
135146
pub fn new_with_file_name(file_name: &Path, code: &str) -> Code {
136147
CodeBuilder::new().code_with_file_name(file_name, code)
137148
}

0 commit comments

Comments
 (0)