Skip to content

Commit

Permalink
Add initial support for different VHDL standards (#284)
Browse files Browse the repository at this point in the history
  • Loading branch information
Schottkyc137 authored Apr 9, 2024
1 parent 84269c3 commit 60e21e6
Show file tree
Hide file tree
Showing 15 changed files with 699 additions and 371 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,21 @@ configuration file in the [TOML](https://github.com/toml-lang/toml) format named

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

Define the VHDL revision to use for parsing and analysis with the `standard` key.
The expected value is the year associated the VHDL standard.
Supported standards are 1993, 2008 and 2019 where both the long version ("2008") and the short version ("08") can be
used.
If nothing is specified, 2008 is used.

> [!NOTE]
> Defining the standard feature is a relatively new feature (since april 2024).
> Anything but the 2008 standard will not change much at the moment.
**Example vhdl_ls.toml**

```toml
# What standard to use. This is optional and defaults to VHDL2008.
standard = "2008"
# File names are either absolute or relative to the parent folder of the vhdl_ls.toml file
[libraries]
lib2.files = [
Expand Down
10 changes: 1 addition & 9 deletions vhdl_lang/src/analysis/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -825,7 +825,7 @@ impl<'a> AnalyzeContext<'a> {
Err(EvalError::Unknown)
}
}
AttributeDesignator::Ascending | AttributeDesignator::Descending => {
AttributeDesignator::Ascending => {
let typ = prefix.as_type_of_attr_prefix(prefix_pos, attr, diagnostics)?;

if typ.array_type().is_some() {
Expand Down Expand Up @@ -2558,14 +2558,6 @@ constant c0 : arr_t := (others => 0);
test.ctx().boolean()
)))
);

let code = test.snippet("arr_t'descending");
assert_eq!(
test.name_resolve(&code, None, &mut NoDiagnostics),
Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous(
test.ctx().boolean()
)))
);
}

#[test]
Expand Down
1 change: 0 additions & 1 deletion vhdl_lang/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ pub enum AttributeDesignator {
Range(RangeAttribute),
Ident(WithRef<Symbol>),
Ascending,
Descending,
Left,
Right,
High,
Expand Down
1 change: 0 additions & 1 deletion vhdl_lang/src/ast/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ impl Display for AttributeDesignator {
AttributeDesignator::Range(r) => write!(f, "{r}"),
AttributeDesignator::Type(t) => write!(f, "{t}"),
AttributeDesignator::Ascending => write!(f, "ascending"),
AttributeDesignator::Descending => write!(f, "descending"),
AttributeDesignator::Left => write!(f, "left"),
AttributeDesignator::Right => write!(f, "right"),
AttributeDesignator::Low => write!(f, "low"),
Expand Down
18 changes: 18 additions & 0 deletions vhdl_lang/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ use toml::{Table, Value};

use crate::data::error_codes::ErrorCode;
use crate::data::*;
use crate::standard::VHDLStandard;

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

let standard = if let Some(std) = config.get("standard") {
let std_str = std.as_str().ok_or("standard must be a string")?;
VHDLStandard::try_from(std_str)
.map_err(|_| format!("Unsupported standard '{std_str}'"))?
} else {
VHDLStandard::default()
};

let libs = config
.get("libraries")
.ok_or("missing field libraries")?
Expand Down Expand Up @@ -177,6 +187,7 @@ impl Config {
Ok(Config {
libraries,
severities,
standard,
})
}

Expand Down Expand Up @@ -225,6 +236,7 @@ impl Config {
///
/// In case of conflict the appended config takes precedence
pub fn append(&mut self, config: &Config, messages: &mut dyn MessageHandler) {
self.standard = config.standard;
for library in config.iter_libraries() {
if let Some(parent_library) = self.libraries.get_mut(&library.name) {
*parent_library = library.clone();
Expand Down Expand Up @@ -321,6 +333,12 @@ impl Config {
pub fn severities(&self) -> &SeverityMap {
&self.severities
}

/// The VHDL standard to use if no more specific config is present.
/// By default, VHDL 2008 is assumed
pub fn standard(&self) -> VHDLStandard {
self.standard
}
}

fn substitute_environment_variables<'a, M>(s: &str, map: &'a M) -> Result<String, String>
Expand Down
2 changes: 2 additions & 0 deletions vhdl_lang/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod project;
mod syntax;

mod completion;
mod standard;

pub use crate::config::Config;
pub use crate::data::{
Expand All @@ -40,3 +41,4 @@ pub use crate::syntax::{
};

pub use completion::{list_completion_options, CompletionItem};
pub use standard::VHDLStandard;
15 changes: 5 additions & 10 deletions vhdl_lang/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::completion::{list_completion_options, CompletionItem};
use crate::config::Config;
use crate::lint::dead_code::UnusedDeclarationsLinter;
use crate::named_entity::{AnyEnt, EntRef};
use crate::standard::VHDLStandard;
use crate::syntax::VHDLParser;
use crate::{data::*, EntHierarchy, EntityId};
use fnv::{FnvHashMap, FnvHashSet};
Expand All @@ -28,8 +29,8 @@ pub struct Project {
}

impl Project {
pub fn new() -> Project {
let parser = VHDLParser::default();
pub fn new(vhdl_standard: VHDLStandard) -> Project {
let parser = VHDLParser::new(vhdl_standard);
Project {
root: DesignRoot::new(parser.symbols.clone()),
files: FnvHashMap::default(),
Expand All @@ -47,7 +48,7 @@ impl Project {
/// Create instance from given configuration.
/// Files referred by configuration are parsed into corresponding libraries.
pub fn from_config(config: Config, messages: &mut dyn MessageHandler) -> Project {
let mut project = Project::new();
let mut project = Project::new(config.standard());
let files = project.load_files_from_config(&config, messages);
project.parse_and_add_files(files, messages);
project.config = config;
Expand All @@ -58,7 +59,7 @@ impl Project {
/// The design state is reset, new files are added and parsed. Existing source files will be
/// kept and parsed from in-memory source (required for incremental document updates).
pub fn update_config(&mut self, config: Config, messages: &mut dyn MessageHandler) {
self.parser = VHDLParser::default();
self.parser = VHDLParser::new(config.standard());
self.root = DesignRoot::new(self.parser.symbols.clone());

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

impl Default for Project {
fn default() -> Self {
Self::new()
}
}

pub struct SourceFile {
library_names: FnvHashSet<Symbol>,
source: Source,
Expand Down
37 changes: 37 additions & 0 deletions vhdl_lang/src/standard.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#[derive(Clone, Copy, PartialEq, Eq, Default, Debug, Ord, PartialOrd)]
pub enum VHDLStandard {
VHDL1993,
#[default]
VHDL2008,
VHDL2019,
}

#[test]
fn order_of_standards() {
assert!(VHDLStandard::VHDL2008 > VHDLStandard::VHDL1993);
}

impl TryFrom<&str> for VHDLStandard {
type Error = ();

fn try_from(value: &str) -> Result<Self, Self::Error> {
use VHDLStandard::*;
Ok(match value {
"1993" | "93" => VHDL1993,
"2008" | "08" => VHDL2008,
"2019" | "19" => VHDL2019,
_ => return Err(()),
})
}
}

impl AsRef<str> for VHDLStandard {
fn as_ref(&self) -> &str {
use VHDLStandard::*;
match self {
VHDL1993 => "1993",
VHDL2008 => "2008",
VHDL2019 => "2019",
}
}
}
8 changes: 7 additions & 1 deletion vhdl_lang/src/syntax/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@ use super::design_unit::parse_design_file;
use super::tokens::{Symbols, TokenStream, Tokenizer};
use crate::ast::DesignFile;
use crate::data::*;
use crate::standard::VHDLStandard;
use std::io;
use std::sync::Arc;

#[derive(Default)]
pub struct VHDLParser {
pub symbols: Arc<Symbols>,
}

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

impl VHDLParser {
pub fn new(vhdl_standard: VHDLStandard) -> VHDLParser {
VHDLParser {
symbols: Arc::new(Symbols::from_standard(vhdl_standard)),
}
}

pub fn symbol(&self, name: &Latin1String) -> Symbol {
self.symbols.symtab().insert(name)
}
Expand Down
11 changes: 11 additions & 0 deletions vhdl_lang/src/syntax/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use crate::ast;
use crate::ast::*;
use crate::data::Range;
use crate::data::*;
use crate::standard::VHDLStandard;
use crate::syntax::concurrent_statement::parse_map_aspect;
use crate::syntax::context::{parse_context, DeclarationOrReference};
use crate::syntax::names::parse_association_element;
Expand Down Expand Up @@ -81,6 +82,12 @@ impl CodeBuilder {
}
}

pub fn with_standard(vhdl_standard: VHDLStandard) -> CodeBuilder {
CodeBuilder {
symbols: Arc::new(Symbols::from_standard(vhdl_standard)),
}
}

pub fn code_from_source(&self, source: Source) -> Code {
let contents = source.contents();

Expand Down Expand Up @@ -132,6 +139,10 @@ impl Code {
CodeBuilder::new().code(code)
}

pub fn with_standard(code: &str, vhdl_standard: VHDLStandard) -> Code {
CodeBuilder::with_standard(vhdl_standard).code(code)
}

pub fn new_with_file_name(file_name: &Path, code: &str) -> Code {
CodeBuilder::new().code_with_file_name(file_name, code)
}
Expand Down
2 changes: 2 additions & 0 deletions vhdl_lang/src/syntax/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#[macro_use]
mod tokenizer;
/// Contains constant keywords for different versions of VHDL.
mod keywords;
mod tokenstream;

pub use tokenizer::*;
Expand Down
Loading

0 comments on commit 60e21e6

Please sign in to comment.