From 60e21e6e20481b72606f50b25303fdb0bda91d8c Mon Sep 17 00:00:00 2001 From: Lukas Scheller <45085299+Schottkyc137@users.noreply.github.com> Date: Tue, 9 Apr 2024 22:03:36 +0200 Subject: [PATCH] Add initial support for different VHDL standards (#284) --- README.md | 12 + vhdl_lang/src/analysis/names.rs | 10 +- vhdl_lang/src/ast.rs | 1 - vhdl_lang/src/ast/display.rs | 1 - vhdl_lang/src/config.rs | 18 + vhdl_lang/src/lib.rs | 2 + vhdl_lang/src/project.rs | 15 +- vhdl_lang/src/standard.rs | 37 ++ vhdl_lang/src/syntax/parser.rs | 8 +- vhdl_lang/src/syntax/test.rs | 11 + vhdl_lang/src/syntax/tokens.rs | 2 + vhdl_lang/src/syntax/tokens/keywords.rs | 470 ++++++++++++++++++++++ vhdl_lang/src/syntax/tokens/tokenizer.rs | 471 ++++++----------------- vhdl_lang/src/syntax/type_declaration.rs | 6 +- vhdl_ls/src/vhdl_server.rs | 6 +- 15 files changed, 699 insertions(+), 371 deletions(-) create mode 100644 vhdl_lang/src/standard.rs create mode 100644 vhdl_lang/src/syntax/tokens/keywords.rs diff --git a/README.md b/README.md index faa7acc9..abb92dd5 100644 --- a/README.md +++ b/README.md @@ -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 = [ diff --git a/vhdl_lang/src/analysis/names.rs b/vhdl_lang/src/analysis/names.rs index e95b8f56..9b2c4128 100644 --- a/vhdl_lang/src/analysis/names.rs +++ b/vhdl_lang/src/analysis/names.rs @@ -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() { @@ -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] diff --git a/vhdl_lang/src/ast.rs b/vhdl_lang/src/ast.rs index 8e65d23b..bf6cbc4c 100644 --- a/vhdl_lang/src/ast.rs +++ b/vhdl_lang/src/ast.rs @@ -107,7 +107,6 @@ pub enum AttributeDesignator { Range(RangeAttribute), Ident(WithRef), Ascending, - Descending, Left, Right, High, diff --git a/vhdl_lang/src/ast/display.rs b/vhdl_lang/src/ast/display.rs index 88fcb388..a33f28c3 100644 --- a/vhdl_lang/src/ast/display.rs +++ b/vhdl_lang/src/ast/display.rs @@ -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"), diff --git a/vhdl_lang/src/config.rs b/vhdl_lang/src/config.rs index 71d18f63..ca606fda 100644 --- a/vhdl_lang/src/config.rs +++ b/vhdl_lang/src/config.rs @@ -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, + standard: VHDLStandard, // Defines the severity that diagnostics are displayed with severities: SeverityMap, } @@ -111,6 +113,14 @@ impl Config { let config = string.parse::().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")? @@ -177,6 +187,7 @@ impl Config { Ok(Config { libraries, severities, + standard, }) } @@ -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(); @@ -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 diff --git a/vhdl_lang/src/lib.rs b/vhdl_lang/src/lib.rs index 559b4043..3393bc2d 100644 --- a/vhdl_lang/src/lib.rs +++ b/vhdl_lang/src/lib.rs @@ -21,6 +21,7 @@ mod project; mod syntax; mod completion; +mod standard; pub use crate::config::Config; pub use crate::data::{ @@ -40,3 +41,4 @@ pub use crate::syntax::{ }; pub use completion::{list_completion_options, CompletionItem}; +pub use standard::VHDLStandard; diff --git a/vhdl_lang/src/project.rs b/vhdl_lang/src/project.rs index b48924ef..b35b3ec6 100644 --- a/vhdl_lang/src/project.rs +++ b/vhdl_lang/src/project.rs @@ -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}; @@ -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(), @@ -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; @@ -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, @@ -344,12 +345,6 @@ fn multiply(value: T, n: usize) -> Vec { } } -impl Default for Project { - fn default() -> Self { - Self::new() - } -} - pub struct SourceFile { library_names: FnvHashSet, source: Source, diff --git a/vhdl_lang/src/standard.rs b/vhdl_lang/src/standard.rs new file mode 100644 index 00000000..ff782a93 --- /dev/null +++ b/vhdl_lang/src/standard.rs @@ -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 { + use VHDLStandard::*; + Ok(match value { + "1993" | "93" => VHDL1993, + "2008" | "08" => VHDL2008, + "2019" | "19" => VHDL2019, + _ => return Err(()), + }) + } +} + +impl AsRef for VHDLStandard { + fn as_ref(&self) -> &str { + use VHDLStandard::*; + match self { + VHDL1993 => "1993", + VHDL2008 => "2008", + VHDL2019 => "2019", + } + } +} diff --git a/vhdl_lang/src/syntax/parser.rs b/vhdl_lang/src/syntax/parser.rs index f87ff107..e683846f 100644 --- a/vhdl_lang/src/syntax/parser.rs +++ b/vhdl_lang/src/syntax/parser.rs @@ -8,10 +8,10 @@ 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, } @@ -19,6 +19,12 @@ pub struct VHDLParser { 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) } diff --git a/vhdl_lang/src/syntax/test.rs b/vhdl_lang/src/syntax/test.rs index 8fb2924a..6edfea7b 100644 --- a/vhdl_lang/src/syntax/test.rs +++ b/vhdl_lang/src/syntax/test.rs @@ -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; @@ -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(); @@ -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) } diff --git a/vhdl_lang/src/syntax/tokens.rs b/vhdl_lang/src/syntax/tokens.rs index 2cc3e2a9..0aa19a44 100644 --- a/vhdl_lang/src/syntax/tokens.rs +++ b/vhdl_lang/src/syntax/tokens.rs @@ -6,6 +6,8 @@ #[macro_use] mod tokenizer; +/// Contains constant keywords for different versions of VHDL. +mod keywords; mod tokenstream; pub use tokenizer::*; diff --git a/vhdl_lang/src/syntax/tokens/keywords.rs b/vhdl_lang/src/syntax/tokens/keywords.rs new file mode 100644 index 00000000..a1ce23a9 --- /dev/null +++ b/vhdl_lang/src/syntax/tokens/keywords.rs @@ -0,0 +1,470 @@ +use crate::ast::{AttributeDesignator, RangeAttribute, SignalAttribute, TypeAttribute}; +use crate::standard::VHDLStandard; +use crate::syntax::Kind; +use crate::syntax::Kind::*; + +const KEYWORDS_1993: &[Kind] = &[ + Abs, + Access, + After, + Alias, + All, + And, + Architecture, + Array, + Assert, + Attribute, + Begin, + Block, + Body, + Buffer, + Bus, + Case, + Component, + Configuration, + Constant, + Disconnect, + Downto, + Else, + Elsif, + End, + Entity, + Exit, + File, + For, + Function, + Generate, + Generic, + Group, + Guarded, + If, + Impure, + In, + Inertial, + InOut, + Is, + Label, + Library, + Linkage, + Literal, + Loop, + Map, + Mod, + Nand, + New, + Next, + Nor, + Not, + Null, + Of, + On, + Open, + Or, + Others, + Out, + Package, + Port, + Postponed, + Procedure, + Process, + Pure, + Range, + Record, + Register, + Reject, + Rem, + Report, + Return, + ROL, + ROR, + Select, + Severity, + Signal, + Shared, + SLA, + SLL, + SRA, + SRL, + Subtype, + Then, + To, + Transport, + Type, + Unaffected, + Units, + Until, + Use, + Variable, + Wait, + When, + While, + With, + Xor, + Xnor, +]; + +const KEYWORDS_2008: &[Kind] = &[ + Abs, + Access, + After, + Alias, + All, + And, + Architecture, + Array, + Assert, + Assume, + AssumeGuarantee, + Attribute, + Begin, + Block, + Body, + Buffer, + Bus, + Case, + Component, + Configuration, + Constant, + Context, + Cover, + Default, + Disconnect, + Downto, + Else, + Elsif, + End, + Entity, + Exit, + Fairness, + File, + For, + Force, + Function, + Generate, + Generic, + Group, + Guarded, + If, + Impure, + In, + Inertial, + InOut, + Is, + Label, + Library, + Linkage, + Literal, + Loop, + Map, + Mod, + Nand, + New, + Next, + Nor, + Not, + Null, + Of, + On, + Open, + Or, + Others, + Out, + Package, + Parameter, + Port, + Postponed, + Procedure, + Process, + Property, + Protected, + Pure, + Range, + Record, + Register, + Reject, + Release, + Rem, + Report, + Restrict, + RestrictGuarantee, + Return, + ROL, + ROR, + Select, + Sequence, + Severity, + Signal, + Shared, + SLA, + SLL, + SRA, + SRL, + Strong, + Subtype, + Then, + To, + Transport, + Type, + Unaffected, + Units, + Until, + Use, + Variable, + Vmode, + Vprop, + Vunit, + Wait, + When, + While, + With, + Xor, + Xnor, +]; + +const KEYWORDS_2019: &[Kind] = &[ + Abs, + Access, + After, + Alias, + All, + And, + Architecture, + Array, + Assert, + Assume, + Attribute, + Begin, + Block, + Body, + Buffer, + Bus, + Case, + Component, + Configuration, + Constant, + Context, + Cover, + Default, + Disconnect, + Downto, + Else, + Elsif, + End, + Entity, + Exit, + Fairness, + File, + For, + Force, + Function, + Generate, + Generic, + Group, + Guarded, + If, + Impure, + In, + Inertial, + InOut, + Is, + Label, + Library, + Linkage, + Literal, + Loop, + Map, + Mod, + Nand, + New, + Next, + Nor, + Not, + Null, + Of, + On, + Open, + Or, + Others, + Out, + Package, + Parameter, + Port, + Postponed, + Procedure, + Process, + Property, + Protected, + Private, + Pure, + Range, + Record, + Register, + Reject, + Release, + Rem, + Report, + Restrict, + Return, + ROL, + ROR, + Select, + Sequence, + Severity, + Signal, + Shared, + SLA, + SLL, + SRA, + SRL, + Strong, + Subtype, + Then, + To, + Transport, + Type, + Unaffected, + Units, + Until, + Use, + Variable, + View, + Vpkg, + Vmode, + Vprop, + Vunit, + Wait, + When, + While, + With, + Xor, + Xnor, +]; + +const ATTRIBUTES_1993: &[AttributeDesignator] = &[ + AttributeDesignator::Left, + AttributeDesignator::Right, + AttributeDesignator::High, + AttributeDesignator::Low, + AttributeDesignator::Ascending, + AttributeDesignator::Image, + AttributeDesignator::Value, + AttributeDesignator::Pos, + AttributeDesignator::Val, + AttributeDesignator::Succ, + AttributeDesignator::Pred, + AttributeDesignator::LeftOf, + AttributeDesignator::RightOf, + AttributeDesignator::Range(RangeAttribute::Range), + AttributeDesignator::Range(RangeAttribute::ReverseRange), + AttributeDesignator::Length, + AttributeDesignator::Signal(SignalAttribute::Delayed), + AttributeDesignator::Signal(SignalAttribute::Stable), + AttributeDesignator::Signal(SignalAttribute::Quiet), + AttributeDesignator::Signal(SignalAttribute::Transaction), + AttributeDesignator::Signal(SignalAttribute::Event), + AttributeDesignator::Signal(SignalAttribute::Active), + AttributeDesignator::Signal(SignalAttribute::LastEvent), + AttributeDesignator::Signal(SignalAttribute::LastActive), + AttributeDesignator::Signal(SignalAttribute::LastValue), + AttributeDesignator::Signal(SignalAttribute::Driving), + AttributeDesignator::Signal(SignalAttribute::DrivingValue), + AttributeDesignator::SimpleName, + AttributeDesignator::InstanceName, + AttributeDesignator::PathName, + // AttributeDesignator::Type(TypeAttribute::Base), +]; + +const ATTRIBUTES_2008: &[AttributeDesignator] = &[ + // AttributeDesignator::Type(TypeAttribute::Base), + AttributeDesignator::Left, + AttributeDesignator::Right, + AttributeDesignator::High, + AttributeDesignator::Low, + AttributeDesignator::Ascending, + AttributeDesignator::Image, + AttributeDesignator::Value, + AttributeDesignator::Pos, + AttributeDesignator::Val, + AttributeDesignator::Succ, + AttributeDesignator::Pred, + AttributeDesignator::LeftOf, + AttributeDesignator::RightOf, + AttributeDesignator::Type(TypeAttribute::Subtype), + AttributeDesignator::Range(RangeAttribute::Range), + AttributeDesignator::Range(RangeAttribute::ReverseRange), + AttributeDesignator::Length, + AttributeDesignator::Type(TypeAttribute::Element), + AttributeDesignator::Signal(SignalAttribute::Delayed), + AttributeDesignator::Signal(SignalAttribute::Stable), + AttributeDesignator::Signal(SignalAttribute::Quiet), + AttributeDesignator::Signal(SignalAttribute::Transaction), + AttributeDesignator::Signal(SignalAttribute::Event), + AttributeDesignator::Signal(SignalAttribute::Active), + AttributeDesignator::Signal(SignalAttribute::LastEvent), + AttributeDesignator::Signal(SignalAttribute::LastActive), + AttributeDesignator::Signal(SignalAttribute::LastValue), + AttributeDesignator::Signal(SignalAttribute::Driving), + AttributeDesignator::Signal(SignalAttribute::DrivingValue), + AttributeDesignator::SimpleName, + AttributeDesignator::InstanceName, + AttributeDesignator::PathName, +]; + +const ATTRIBUTES_2019: &[AttributeDesignator] = &[ + // AttributeDesignator::Type(TypeAttribute::Base), + AttributeDesignator::Left, + AttributeDesignator::Right, + AttributeDesignator::High, + AttributeDesignator::Low, + AttributeDesignator::Ascending, + AttributeDesignator::Length, + AttributeDesignator::Range(RangeAttribute::Range), + AttributeDesignator::Range(RangeAttribute::ReverseRange), + AttributeDesignator::Type(TypeAttribute::Subtype), + AttributeDesignator::Image, + AttributeDesignator::Pos, + AttributeDesignator::Succ, + AttributeDesignator::Pred, + AttributeDesignator::LeftOf, + AttributeDesignator::RightOf, + // DesignatedSubtype + // Reflect + // Index + AttributeDesignator::Value, + AttributeDesignator::Val, + AttributeDesignator::Type(TypeAttribute::Element), + AttributeDesignator::Signal(SignalAttribute::Delayed), + AttributeDesignator::Signal(SignalAttribute::Stable), + AttributeDesignator::Signal(SignalAttribute::Quiet), + AttributeDesignator::Signal(SignalAttribute::Transaction), + AttributeDesignator::Signal(SignalAttribute::Event), + AttributeDesignator::Signal(SignalAttribute::Active), + AttributeDesignator::Signal(SignalAttribute::LastEvent), + AttributeDesignator::Signal(SignalAttribute::LastActive), + AttributeDesignator::Signal(SignalAttribute::LastValue), + AttributeDesignator::Signal(SignalAttribute::Driving), + AttributeDesignator::Signal(SignalAttribute::DrivingValue), + AttributeDesignator::SimpleName, + AttributeDesignator::InstanceName, + AttributeDesignator::PathName, +]; + +impl VHDLStandard { + /// Get all keywords that this VHDL standard defines + pub fn keywords(&self) -> &'static [Kind] { + match self { + VHDLStandard::VHDL1993 => KEYWORDS_1993, + VHDLStandard::VHDL2008 => KEYWORDS_2008, + VHDLStandard::VHDL2019 => KEYWORDS_2019, + } + } + + /// Get all builtin attributes that this VHDL standard defines + pub fn builtin_attributes(&self) -> &'static [AttributeDesignator] { + match self { + VHDLStandard::VHDL1993 => ATTRIBUTES_1993, + VHDLStandard::VHDL2008 => ATTRIBUTES_2008, + VHDLStandard::VHDL2019 => ATTRIBUTES_2019, + } + } +} diff --git a/vhdl_lang/src/syntax/tokens/tokenizer.rs b/vhdl_lang/src/syntax/tokens/tokenizer.rs index ad0f51fe..9c7e4c3b 100644 --- a/vhdl_lang/src/syntax/tokens/tokenizer.rs +++ b/vhdl_lang/src/syntax/tokens/tokenizer.rs @@ -11,7 +11,8 @@ use crate::ast::{BaseSpecifier, Ident}; use crate::data::*; /// The kind of a Token -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, IntoStaticStr)] +#[strum(serialize_all = "lowercase")] pub enum Kind { // Keywords Architecture, @@ -97,14 +98,38 @@ pub enum Kind { Vunit, Parameter, Literal, + Bus, + Disconnect, + Group, + Guarded, + Register, + Assume, + #[strum(serialize = "assume_guarantee")] + AssumeGuarantee, + Cover, + Fairness, + Property, + Restrict, + #[strum(serialize = "restrict_guarantee")] + RestrictGuarantee, + Sequence, + Strong, + Vmode, + Vprop, + Private, + View, + Vpkg, // Unary operators Abs, Not, // Unary and binary operators + #[strum(serialize = "+")] Plus, + #[strum(serialize = "-")] Minus, + #[strum(serialize = "??")] QueQue, // Binary operators @@ -124,50 +149,97 @@ pub enum Kind { Mod, Rem, + #[strum(serialize = "=")] EQ, + #[strum(serialize = "/=")] NE, + #[strum(serialize = "<")] LT, + #[strum(serialize = "<=")] LTE, + #[strum(serialize = ">")] GT, + #[strum(serialize = ">=")] GTE, + #[strum(serialize = "?=")] QueEQ, + #[strum(serialize = "?/=")] QueNE, + #[strum(serialize = "?<")] QueLT, + #[strum(serialize = "?<=")] QueLTE, + #[strum(serialize = "?>")] QueGT, + #[strum(serialize = "?>=")] QueGTE, + #[strum(serialize = "?")] Que, + #[strum(serialize = "*")] Times, + #[strum(serialize = "**")] Pow, + #[strum(serialize = "/")] Div, + #[strum(serialize = "{identifier}")] Identifier, + #[strum(serialize = "{abstract_literal}")] AbstractLiteral, + #[strum(serialize = "{string}")] StringLiteral, + #[strum(serialize = "{bit_string}")] BitString, + #[strum(serialize = "{character}")] Character, + #[strum(serialize = "'")] Tick, + #[strum(serialize = "(")] LeftPar, + #[strum(serialize = ")")] RightPar, + #[strum(serialize = "[")] LeftSquare, + #[strum(serialize = "]")] RightSquare, + #[strum(serialize = ";")] SemiColon, + #[strum(serialize = ":")] Colon, + #[strum(serialize = "|")] Bar, + #[strum(serialize = ".")] Dot, + #[strum(serialize = "<>")] BOX, + #[strum(serialize = "<<")] LtLt, + #[strum(serialize = ">>")] GtGt, + #[strum(serialize = "^")] Circ, + #[strum(serialize = "@")] CommAt, + #[strum(serialize = "&")] Concat, + #[strum(serialize = ",")] Comma, + #[strum(serialize = ":=")] ColonEq, + #[strum(serialize = "=>")] RightArrow, - GraveAccent, // ` - Text, // Raw text that is not processed (i.e. tokenized) further. Used in tool directives + #[strum(serialize = "`")] + GraveAccent, + #[strum(serialize = "{text}")] + Text, // Raw text that is not processed (i.e. tokenized) further. Used in tool directives +} + +impl Kind { + pub fn as_str(&self) -> &str { + self.into() + } } use self::Kind::*; @@ -266,163 +338,7 @@ macro_rules! try_init_token_kind { } pub fn kind_str(kind: Kind) -> &'static str { - match kind { - // Keywords - Architecture => "architecture", - Entity => "entity", - Configuration => "configuration", - Package => "package", - Block => "block", - Process => "process", - Generate => "generate", - Postponed => "postponed", - Library => "library", - Label => "label", - Use => "use", - Context => "context", - Body => "body", - Component => "component", - Is => "is", - Return => "return", - Null => "null", - Of => "of", - On => "on", - Generic => "generic", - Map => "map", - Default => "default", - Port => "port", - Attribute => "attribute", - Begin => "begin", - If => "if", - Loop => "loop", - While => "while", - Case => "case", - Else => "else", - Elsif => "elsif", - Then => "then", - When => "when", - With => "with", - Select => "select", - Next => "next", - Exit => "exit", - For => "for", - Force => "force", - Release => "release", - Assert => "assert", - Report => "report", - Severity => "severity", - Wait => "wait", - After => "after", - Transport => "transport", - Inertial => "inertial", - Reject => "reject", - Unaffected => "unaffected", - Until => "until", - End => "end", - All => "all", - Range => "range", - Downto => "downto", - To => "to", - In => "in", - Out => "out", - InOut => "inout", - Buffer => "buffer", - Linkage => "linkage", - Signal => "signal", - Constant => "constant", - Variable => "variable", - File => "file", - Open => "open", - Alias => "alias", - Shared => "shared", - Others => "others", - Record => "record", - Type => "type", - Subtype => "subtype", - Access => "access", - Units => "units", - New => "new", - Array => "array", - Protected => "protected", - Pure => "pure", - Impure => "impure", - Function => "function", - Procedure => "procedure", - Vunit => "vunit", - Parameter => "parameter", - Literal => "literal", - - // Unary operators - Abs => "abs", - Not => "not", - - // Unary and binary operators - Plus => "plus", - Minus => "minus", - QueQue => "??", - - // Binary operators - And => "and", - Or => "or", - Nand => "nand", - Nor => "nor", - Xor => "xor", - Xnor => "xnor", - SLL => "sll", - SRL => "srl", - SLA => "sla", - SRA => "sra", - ROL => "rol", - ROR => "ror", - - Mod => "mod", - Rem => "rem", - - EQ => "=", - NE => "/=", - LT => "<", - LTE => "<=", - GT => ">", - GTE => ">=", - - QueEQ => "?=", - QueNE => "?/=", - QueLT => "?<", - QueLTE => "?<=", - QueGT => "?>", - QueGTE => "?>=", - Que => "?", - - Times => "*", - Pow => "**", - Div => "/", - - Identifier => "{identifier}", - AbstractLiteral => "{abstract_literal}", - StringLiteral => "{string}", - BitString => "{bit_string}", - Character => "{character}", - Tick => "'", - LeftPar => "(", - RightPar => ")", - LeftSquare => "[", - RightSquare => "]", - SemiColon => ";", - Colon => ":", - Bar => "|", - Dot => ".", - BOX => "<>", - LtLt => "<<", - GtGt => ">>", - Circ => "^", - CommAt => "@", - Concat => "&", - Comma => ",", - ColonEq => ":=", - RightArrow => "=>", - GraveAccent => "`", - Text => "{text}", - } + kind.into() } /// Create s string representation of the kinds separated by a separator @@ -652,7 +568,9 @@ pub struct Comment { pub multi_line: bool, } +use crate::standard::VHDLStandard; use std::convert::AsRef; +use strum::IntoStaticStr; impl AsRef for Token { fn as_ref(&self) -> &SrcPos { @@ -1465,199 +1383,25 @@ impl Symbols { (Identifier, Value::Identifier(symbol)) } } -} - -impl std::default::Default for Symbols { - fn default() -> Symbols { - let keywords_init = [ - ("architecture", Architecture), - ("entity", Entity), - ("configuration", Configuration), - ("package", Package), - ("block", Block), - ("process", Process), - ("generate", Generate), - ("postponed", Postponed), - ("library", Library), - ("label", Label), - ("use", Use), - ("context", Context), - ("body", Body), - ("component", Component), - ("is", Is), - ("return", Return), - ("null", Null), - ("of", Of), - ("on", On), - ("generic", Generic), - ("map", Map), - ("default", Default), - ("port", Port), - ("attribute", Attribute), - ("begin", Begin), - ("end", End), - ("if", If), - ("loop", Loop), - ("while", While), - ("case", Case), - ("else", Else), - ("elsif", Elsif), - ("then", Then), - ("when", When), - ("with", With), - ("select", Select), - ("next", Next), - ("exit", Exit), - ("for", For), - ("force", Force), - ("release", Release), - ("assert", Assert), - ("report", Report), - ("severity", Severity), - ("wait", Wait), - ("after", After), - ("transport", Transport), - ("inertial", Inertial), - ("reject", Reject), - ("unaffected", Unaffected), - ("until", Until), - ("all", All), - ("range", Range), - ("downto", Downto), - ("to", To), - ("in", In), - ("out", Out), - ("inout", InOut), - ("buffer", Buffer), - ("linkage", Linkage), - ("signal", Signal), - ("constant", Constant), - ("variable", Variable), - ("file", File), - ("open", Open), - ("alias", Alias), - ("shared", Shared), - ("others", Others), - ("record", Record), - ("type", Type), - ("subtype", Subtype), - ("access", Access), - ("units", Units), - ("new", New), - ("array", Array), - ("protected", Protected), - ("pure", Pure), - ("impure", Impure), - ("function", Function), - ("procedure", Procedure), - ("abs", Abs), - ("not", Not), - ("and", And), - ("or", Or), - ("nand", Nand), - ("nor", Nor), - ("xor", Xor), - ("xnor", Xnor), - ("sll", SLL), - ("srl", SRL), - ("sla", SLA), - ("sra", SRA), - ("rol", ROL), - ("ror", ROR), - ("mod", Mod), - ("rem", Rem), - ("vunit", Vunit), - ("parameter", Parameter), - ]; - - let attributes = [ - ( - "reverse_range", - AttributeDesignator::Range(ast::RangeAttribute::ReverseRange), - ), - ( - "element", - AttributeDesignator::Type(ast::TypeAttribute::Element), - ), - ("ascending", AttributeDesignator::Ascending), - ("descending", AttributeDesignator::Descending), - ("high", AttributeDesignator::High), - ("low", AttributeDesignator::Low), - ("left", AttributeDesignator::Left), - ("right", AttributeDesignator::Right), - ("length", AttributeDesignator::Length), - ("image", AttributeDesignator::Image), - ("value", AttributeDesignator::Value), - ("pos", AttributeDesignator::Pos), - ("val", AttributeDesignator::Val), - ("succ", AttributeDesignator::Succ), - ("pred", AttributeDesignator::Pred), - ("leftof", AttributeDesignator::LeftOf), - ("rightof", AttributeDesignator::RightOf), - ( - "delayed", - AttributeDesignator::Signal(ast::SignalAttribute::Delayed), - ), - ( - "active", - AttributeDesignator::Signal(ast::SignalAttribute::Active), - ), - ( - "event", - AttributeDesignator::Signal(ast::SignalAttribute::Event), - ), - ( - "quiet", - AttributeDesignator::Signal(ast::SignalAttribute::Quiet), - ), - ( - "stable", - AttributeDesignator::Signal(ast::SignalAttribute::Stable), - ), - ( - "transaction", - AttributeDesignator::Signal(ast::SignalAttribute::Transaction), - ), - ( - "last_event", - AttributeDesignator::Signal(ast::SignalAttribute::LastEvent), - ), - ( - "last_active", - AttributeDesignator::Signal(ast::SignalAttribute::LastActive), - ), - ( - "last_value", - AttributeDesignator::Signal(ast::SignalAttribute::LastValue), - ), - ( - "driving", - AttributeDesignator::Signal(ast::SignalAttribute::Driving), - ), - ( - "driving_value", - AttributeDesignator::Signal(ast::SignalAttribute::DrivingValue), - ), - ("simple_name", AttributeDesignator::SimpleName), - ("instance_name", AttributeDesignator::InstanceName), - ("path_name", AttributeDesignator::PathName), - ]; + pub fn from_standard(version: VHDLStandard) -> Symbols { let symtab = SymbolTable::default(); - let mut keywords = Vec::with_capacity(keywords_init.len()); + let kw = version.keywords(); + let mut keywords = Vec::with_capacity(kw.len()); let mut latin1 = Latin1String::empty(); - for (keyword, kind) in keywords_init.iter() { + for kind in kw { latin1.bytes.clear(); - latin1.bytes.extend_from_slice(keyword.as_bytes()); + latin1.bytes.extend_from_slice(kind.as_str().as_bytes()); let symbol = symtab.insert(&latin1); assert_eq!(symbol.id, keywords.len()); keywords.push(*kind); } - let attributes = attributes - .into_iter() - .map(|(name, des)| (symtab.insert_utf8(name), des)) + let attributes = version + .builtin_attributes() + .iter() + .map(|attr| (symtab.insert_utf8(format!("{attr}").as_str()), attr.clone())) .collect(); Symbols { @@ -1668,6 +1412,12 @@ impl std::default::Default for Symbols { } } +impl std::default::Default for Symbols { + fn default() -> Symbols { + Self::from_standard(VHDLStandard::default()) + } +} + pub struct Tokenizer<'a> { symbols: &'a Symbols, buffer: Latin1String, @@ -2002,6 +1752,7 @@ impl<'a> Tokenizer<'a> { mod tests { use super::*; use crate::syntax::test::Code; + use itertools::Itertools; use pretty_assertions::assert_eq; fn kinds(tokens: &[Token]) -> Vec { @@ -2998,4 +2749,38 @@ entity -- € })] ); } + + #[test] + fn tokenize_different_versions() { + let code_str = "view default"; + let code = Code::with_standard(code_str, VHDLStandard::VHDL1993); + let (tokens, _) = code.tokenize_result(); + assert_eq!( + tokens + .into_iter() + .map(|tok| tok.unwrap().kind) + .collect_vec(), + vec![Identifier, Identifier] + ); + + let code = Code::with_standard(code_str, VHDLStandard::VHDL2008); + let (tokens, _) = code.tokenize_result(); + assert_eq!( + tokens + .into_iter() + .map(|tok| tok.unwrap().kind) + .collect_vec(), + vec![Identifier, Default] + ); + + let code = Code::with_standard(code_str, VHDLStandard::VHDL2019); + let (tokens, _) = code.tokenize_result(); + assert_eq!( + tokens + .into_iter() + .map(|tok| tok.unwrap().kind) + .collect_vec(), + vec![View, Default] + ); + } } diff --git a/vhdl_lang/src/syntax/type_declaration.rs b/vhdl_lang/src/syntax/type_declaration.rs index b9a07f58..be713407 100644 --- a/vhdl_lang/src/syntax/type_declaration.rs +++ b/vhdl_lang/src/syntax/type_declaration.rs @@ -890,8 +890,8 @@ end package; assert_eq!( type_decl_strings[0], vec![ - "subtype", "negative", "is", "integer", "range", "minus", "2", "**", "31", "to", - "minus", "1", ";" + "subtype", "negative", "is", "integer", "range", "-", "2", "**", "31", "to", "-", + "1", ";" ], ); assert_eq!(type_decl_strings[1], vec!["type", "incomplete", ";"],); @@ -904,7 +904,7 @@ end package; "range", "100", "downto", - "minus", + "-", "100", ";" ], diff --git a/vhdl_ls/src/vhdl_server.rs b/vhdl_ls/src/vhdl_server.rs index ae7b8100..dd2dd504 100644 --- a/vhdl_ls/src/vhdl_server.rs +++ b/vhdl_ls/src/vhdl_server.rs @@ -18,7 +18,7 @@ use std::path::{Path, PathBuf}; use vhdl_lang::{ kind_str, AnyEntKind, Concurrent, Config, Design, Diagnostic, EntHierarchy, EntRef, EntityId, InterfaceEnt, Message, MessageHandler, Object, Overloaded, Project, Severity, SeverityMap, - Source, SrcPos, Token, Type, + Source, SrcPos, Token, Type, VHDLStandard, }; #[derive(Default, Clone)] @@ -45,7 +45,7 @@ impl VHDLServer { rpc, settings, use_external_config: true, - project: Project::new(), + project: Project::new(VHDLStandard::default()), files_with_notifications: FnvHashMap::default(), init_params: None, config_file: None, @@ -59,7 +59,7 @@ impl VHDLServer { rpc, settings: Default::default(), use_external_config, - project: Project::new(), + project: Project::new(VHDLStandard::default()), files_with_notifications: FnvHashMap::default(), init_params: None, config_file: None,