Skip to content

Commit

Permalink
Merge pull request #915 from taichi-ishitani/enum_encoding
Browse files Browse the repository at this point in the history
Add `enum_encoding` attribute
  • Loading branch information
dalance authored Aug 27, 2024
2 parents 03c00a8 + b7e65fc commit 656eb70
Show file tree
Hide file tree
Showing 11 changed files with 388 additions and 99 deletions.
45 changes: 44 additions & 1 deletion crates/analyzer/src/analyzer_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,16 @@ pub enum AnalyzerError {
error_location: SourceSpan,
},

#[diagnostic(severity(Error), code(invalid_enum_encoding), help(""), url(""))]
#[error("{identifier} is not valid enum encoding")]
InvalidEnumEncoding {
identifier: String,
#[source_code]
input: NamedSource<String>,
#[label("Error location")]
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(too_large_enum_variant),
Expand All @@ -620,7 +630,7 @@ pub enum AnalyzerError {
help(""),
url("")
)]
#[error("The implicit value of enum variant {identifier} cannot be evaluated")]
#[error("The value of enum variant {identifier} cannot be evaluated")]
UnevaluatableEnumVariant {
identifier: String,
#[source_code]
Expand All @@ -629,6 +639,17 @@ pub enum AnalyzerError {
error_location: SourceSpan,
},

#[diagnostic(severity(Error), code(invalid_enum_variant_value), help(""), url(""))]
#[error("The value of enum variant {identifier} is not encoded value by {encoding}")]
InvalidEnumVariant {
identifier: String,
encoding: String,
#[source_code]
input: NamedSource<String>,
#[label("Error location")]
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(too_large_number),
Expand Down Expand Up @@ -1333,6 +1354,14 @@ impl AnalyzerError {
}
}

pub fn invalid_enum_encoding(identifier: &str, source: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidEnumEncoding {
identifier: identifier.to_string(),
input: AnalyzerError::named_source(source, token),
error_location: token.into(),
}
}

pub fn too_large_enum_variant(
identifier: &str,
value: isize,
Expand All @@ -1357,6 +1386,20 @@ impl AnalyzerError {
}
}

pub fn invalid_enum_variant_value(
identifier: &str,
encoding: &str,
source: &str,
token: &TokenRange,
) -> Self {
AnalyzerError::InvalidEnumVariant {
identifier: identifier.to_string(),
encoding: encoding.to_string(),
input: AnalyzerError::named_source(source, token),
error_location: token.into(),
}
}

pub fn too_large_number(width: usize, source: &str, token: &TokenRange) -> Self {
AnalyzerError::TooLargeNumber {
width,
Expand Down
48 changes: 48 additions & 0 deletions crates/analyzer/src/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub enum Attribute {
Ifndef(StrId),
Sv(StrId),
Allow(AllowItem),
EnumEncoding(EnumEncodingItem),
EnumMemberPrefix(StrId),
Test(Token, Option<StrId>),
}
Expand All @@ -20,6 +21,7 @@ impl fmt::Display for Attribute {
Attribute::Ifndef(x) => format!("ifndef({})", x),
Attribute::Sv(x) => format!("sv(\"{}\")", x),
Attribute::Allow(x) => format!("allow({})", x),
Attribute::EnumEncoding(x) => format!("enum_encoding({})", x),
Attribute::EnumMemberPrefix(x) => format!("enum_member_prefix({})", x),
Attribute::Test(x, _) => format!("test({})", x.text),
};
Expand All @@ -32,6 +34,7 @@ pub enum AttributeError {
UnknownAttribute,
MismatchArgs(&'static str),
InvalidAllow(StrId),
InvalidEnumEncoding(StrId),
}

fn get_arg_ident(
Expand Down Expand Up @@ -82,6 +85,10 @@ struct Pattern {
pub missing_port: StrId,
pub missing_reset_statement: StrId,
pub unused_variable: StrId,
pub enum_encoding: StrId,
pub sequential: StrId,
pub onehot: StrId,
pub gray: StrId,
pub enum_member_prefix: StrId,
pub test: StrId,
}
Expand All @@ -96,6 +103,10 @@ impl Pattern {
missing_port: resource_table::insert_str("missing_port"),
missing_reset_statement: resource_table::insert_str("missing_reset_statement"),
unused_variable: resource_table::insert_str("unused_variable"),
enum_encoding: resource_table::insert_str("enum_encoding"),
sequential: resource_table::insert_str("sequential"),
onehot: resource_table::insert_str("onehot"),
gray: resource_table::insert_str("gray"),
enum_member_prefix: resource_table::insert_str("enum_member_prefix"),
test: resource_table::insert_str("test"),
}
Expand Down Expand Up @@ -149,6 +160,24 @@ impl TryFrom<&veryl_parser::veryl_grammar_trait::Attribute> for Attribute {
Err(AttributeError::MismatchArgs("allowable rule"))
}
}
x if x == pat.enum_encoding => {
let arg = get_arg_ident(&value.attribute_opt, 0);

if let Some(arg) = arg {
match arg.text {
x if x == pat.sequential => {
Ok(Attribute::EnumEncoding(EnumEncodingItem::Sequential))
}
x if x == pat.onehot => {
Ok(Attribute::EnumEncoding(EnumEncodingItem::OneHot))
}
x if x == pat.gray => Ok(Attribute::EnumEncoding(EnumEncodingItem::Gray)),
_ => Err(AttributeError::InvalidEnumEncoding(arg.text)),
}
} else {
Err(AttributeError::MismatchArgs("enum encoding rule"))
}
}
x if x == pat.enum_member_prefix => {
let arg = get_arg_ident(&value.attribute_opt, 0);

Expand Down Expand Up @@ -190,3 +219,22 @@ impl fmt::Display for AllowItem {
text.fmt(f)
}
}

#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub enum EnumEncodingItem {
#[default]
Sequential,
OneHot,
Gray,
}

impl fmt::Display for EnumEncodingItem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let text = match self {
EnumEncodingItem::Sequential => "sequential",
EnumEncodingItem::OneHot => "one_hot",
EnumEncodingItem::Gray => "gray",
};
text.fmt(f)
}
}
7 changes: 7 additions & 0 deletions crates/analyzer/src/handlers/check_attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ impl<'a> VerylGrammarTrait for CheckAttribute<'a> {
&arg.identifier.as_ref().into(),
));
}
crate::attribute::AttributeError::InvalidEnumEncoding(x) => {
self.errors.push(AnalyzerError::invalid_enum_encoding(
&x.to_string(),
self.text,
&arg.identifier.as_ref().into(),
));
}
}
}
}
Expand Down
10 changes: 2 additions & 8 deletions crates/analyzer/src/handlers/check_enum.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::analyzer_error::AnalyzerError;
use crate::evaluator::Evaluator;
use crate::symbol::{EnumMemberValue, SymbolKind};
use crate::symbol::SymbolKind;
use crate::symbol_table;
use veryl_parser::veryl_grammar_trait::*;
use veryl_parser::veryl_walker::{Handler, HandlerPoint};
Expand Down Expand Up @@ -54,13 +54,7 @@ impl<'a> VerylGrammarTrait for CheckEnum<'a> {
for id in r#enum.members {
let member_symbol = symbol_table::get(id).unwrap();
if let SymbolKind::EnumMember(member) = member_symbol.kind {
let member_value = match member.value {
EnumMemberValue::ExplicitValue(_expression, evaluated) => {
evaluated.unwrap_or(0)
}
EnumMemberValue::ImplicitValue(x) => x,
};

let member_value = member.value.value().unwrap_or(0);
if calc_width(member_value) > width {
self.errors.push(AnalyzerError::too_large_enum_variant(
&member_symbol.token.to_string(),
Expand Down
Loading

0 comments on commit 656eb70

Please sign in to comment.