Skip to content

Commit

Permalink
emit case statement/expression as case inside
Browse files Browse the repository at this point in the history
  • Loading branch information
taichi-ishitani committed Jun 12, 2024
1 parent 4982131 commit 6279cfa
Show file tree
Hide file tree
Showing 18 changed files with 10,225 additions and 10,245 deletions.
21 changes: 21 additions & 0 deletions crates/analyzer/src/analyzer_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,20 @@ pub enum AnalyzerError {
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(invalid_case_condition_non_elaborative),
help(""),
url("")
)]
#[error("Case condition value cannot be used because it is not evaluable at elaboration time")]
InvalidCaseConditionNonElaborative {
#[source_code]
input: NamedSource,
#[label("Error location")]
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(missing_default_argument),
Expand Down Expand Up @@ -1008,6 +1022,13 @@ impl AnalyzerError {
}
}

pub fn invalid_case_condition_non_elaborative(source: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidCaseConditionNonElaborative {
input: AnalyzerError::named_source(source, token),
error_location: token.into(),
}
}

pub fn invalid_modport_variable_item(
identifier: &str,
source: &str,
Expand Down
27 changes: 27 additions & 0 deletions crates/analyzer/src/handlers/check_expression.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::analyzer_error::AnalyzerError;
use crate::evaluator::{Evaluated, Evaluator};
use crate::symbol::SymbolKind;
use crate::symbol_table;
use veryl_parser::veryl_grammar_trait::*;
Expand All @@ -11,6 +12,8 @@ pub struct CheckExpression<'a> {
pub errors: Vec<AnalyzerError>,
text: &'a str,
point: HandlerPoint,
case_condition_depth: usize,
evaluator: Evaluator,
}

impl<'a> CheckExpression<'a> {
Expand All @@ -29,6 +32,30 @@ impl<'a> Handler for CheckExpression<'a> {
}

impl<'a> VerylGrammarTrait for CheckExpression<'a> {
fn case_condition(&mut self, _arg: &CaseCondition) -> Result<(), ParolError> {
match self.point {
HandlerPoint::Before => self.case_condition_depth += 1,
HandlerPoint::After => self.case_condition_depth -= 1,
}
Ok(())
}

fn expression(&mut self, arg: &Expression) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
if self.case_condition_depth >= 1 {
let result = matches!(self.evaluator.expression(arg), Evaluated::Variable { .. });
if result {
self.errors
.push(AnalyzerError::invalid_case_condition_non_elaborative(
self.text,
&arg.into(),
));
}
}
}
Ok(())
}

fn factor(&mut self, arg: &Factor) -> Result<(), ParolError> {
if let HandlerPoint::Before = self.point {
if let Factor::ExpressionIdentifierFactorOpt(x) = arg {
Expand Down
77 changes: 77 additions & 0 deletions crates/analyzer/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1551,3 +1551,80 @@ fn invalid_assignment_to_const() {
AnalyzerError::InvalidAssignmentToConst { .. }
));
}

#[test]
fn invalid_case_condition_expression() {
let code = r#"
module ModuleA (
i_sel: input logic<2>,
i_a : input logic<3>,
o_b : output logic,
o_c : output logic,
) {
local ONE: bit <2> = 2'd1;
always_comb {
case i_sel {
2'd0 : o_b = i_a[0];
ONE : o_b = i_a[1];
2'b1x : o_b = i_a[2];
default: o_b = i_a[2];
}
}
assign o_c = case i_sel {
2'd0 : i_a[0],
ONE : i_a[1],
2'b1x : i_a[2],
default: i_a[2],
};
}
"#;

let errors = analyze(code);
assert!(errors.is_empty());

let code = r#"
module ModuleB (
i_sel: input logic<2>,
i_a : input logic<3>,
o_b : output logic,
) {
let c: logic<2> = 2'd0;
always_comb {
case i_sel {
c : o_b = i_a[0];
default: o_b = i_a[1];
}
}
}
"#;

let errors = analyze(code);
assert!(matches!(
errors[0],
AnalyzerError::InvalidCaseConditionNonElaborative { .. }
));

let code = r#"
module ModuleC (
i_sel: input logic<2>,
i_a : input logic<3>,
o_b : output logic,
) {
let c: logic<2> = 2'd0;
assign o_b = case i_sel {
c : i_a[0],
default: i_a[1],
};
}
"#;

let errors = analyze(code);
assert!(matches!(
errors[0],
AnalyzerError::InvalidCaseConditionNonElaborative { .. }
));
}
6 changes: 3 additions & 3 deletions crates/emitter/src/aligner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -660,9 +660,9 @@ impl VerylWalker for Aligner {
fn case_item(&mut self, arg: &CaseItem) {
self.aligns[align_kind::EXPRESSION].start_item();
match &*arg.case_item_group {
CaseItemGroup::ExpressionCaseItemGroupList(x) => {
self.expression(&x.expression);
for x in &x.case_item_group_list {
CaseItemGroup::CaseCondition(x) => {
self.expression(&x.case_condition.expression);
for x in &x.case_condition.case_condition_list {
self.comma(&x.comma);
self.space(1);
self.expression(&x.expression);
Expand Down
36 changes: 18 additions & 18 deletions crates/emitter/src/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1052,60 +1052,60 @@ impl VerylWalker for Emitter {
self.token(&arg.case.case_token.replace("(("));
self.expression(&arg.expression);
self.space(1);
self.str("==");
self.str("==?");
self.space(1);
self.expression(&arg.expression0);
self.expression(&arg.case_condition.expression);
self.str(") ? (");
self.newline_push();
self.expression(&arg.expression1);
self.expression(&arg.expression0);
self.newline_pop();
for x in &arg.case_expression_list {
for x in &arg.case_condition.case_condition_list {
self.token(&x.comma.comma_token.replace(")"));
self.space(1);
self.str(": (");
self.expression(&arg.expression);
self.space(1);
self.str("==");
self.str("==?");
self.space(1);
self.expression(&x.expression);
self.str(") ? (");
self.newline_push();
self.expression(&arg.expression1);
self.expression(&arg.expression0);
self.newline_pop();
}
self.str(")");
self.space(1);
for x in &arg.case_expression_list0 {
for x in &arg.case_expression_list {
self.str(": (");
self.expression(&arg.expression);
self.space(1);
self.str("==");
self.str("==?");
self.space(1);
self.expression(&x.expression);
self.expression(&x.case_condition.expression);
self.str(") ? (");
self.newline_push();
self.expression(&x.expression0);
self.expression(&x.expression);
self.newline_pop();
for y in &x.case_expression_list0_list {
for y in &x.case_condition.case_condition_list {
self.token(&x.comma.comma_token.replace(")"));
self.space(1);
self.str(": (");
self.expression(&arg.expression);
self.space(1);
self.str("==");
self.str("==?");
self.space(1);
self.expression(&y.expression);
self.str(") ? (");
self.newline_push();
self.expression(&x.expression0);
self.expression(&x.expression);
self.newline_pop();
}
self.token(&x.comma.comma_token.replace(")"));
self.space(1);
}
self.str(": (");
self.newline_push();
self.expression(&arg.expression2);
self.expression(&arg.expression1);
self.newline_pop();
self.token(&arg.r_brace.r_brace_token.replace("))"));
}
Expand Down Expand Up @@ -1583,7 +1583,7 @@ impl VerylWalker for Emitter {
self.space(1);
self.str("(");
self.expression(&arg.expression);
self.token_will_push(&arg.l_brace.l_brace_token.replace(")"));
self.token_will_push(&arg.l_brace.l_brace_token.replace(") inside"));
for (i, x) in arg.case_statement_list.iter().enumerate() {
self.newline_list(i);
self.case_item(&x.case_item);
Expand All @@ -1596,9 +1596,9 @@ impl VerylWalker for Emitter {
fn case_item(&mut self, arg: &CaseItem) {
let start = self.dst_column;
match &*arg.case_item_group {
CaseItemGroup::ExpressionCaseItemGroupList(x) => {
self.expression(&x.expression);
for x in &x.case_item_group_list {
CaseItemGroup::CaseCondition(x) => {
self.expression(&x.case_condition.expression);
for x in &x.case_condition.case_condition_list {
self.comma(&x.comma);
self.space(1);
self.expression(&x.expression);
Expand Down
41 changes: 17 additions & 24 deletions crates/formatter/src/aligner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,34 +324,24 @@ impl VerylWalker for Aligner {
self.expression(&arg.expression);
self.l_brace(&arg.l_brace);
self.aligns[align_kind::EXPRESSION].start_item();
self.expression(&arg.expression0);
for x in &arg.case_expression_list {
self.comma(&x.comma);
self.space(1);
self.expression(&arg.expression);
}
self.case_condition(&arg.case_condition);
self.aligns[align_kind::EXPRESSION].finish_item();
self.colon(&arg.colon);
self.expression(&arg.expression1);
self.expression(&arg.expression0);
self.comma(&arg.comma);
for x in &arg.case_expression_list0 {
for x in &arg.case_expression_list {
self.aligns[align_kind::EXPRESSION].start_item();
self.expression(&x.expression);
for x in &x.case_expression_list0_list {
self.comma(&x.comma);
self.space(1);
self.expression(&x.expression);
}
self.case_condition(&x.case_condition);
self.aligns[align_kind::EXPRESSION].finish_item();
self.colon(&x.colon);
self.expression(&x.expression0);
self.expression(&x.expression);
self.comma(&x.comma);
}
self.aligns[align_kind::EXPRESSION].start_item();
self.defaul(&arg.defaul);
self.aligns[align_kind::EXPRESSION].finish_item();
self.colon(&arg.colon0);
self.expression(&arg.expression2);
self.expression(&arg.expression1);
if let Some(ref x) = arg.case_expression_opt {
self.comma(&x.comma);
}
Expand Down Expand Up @@ -525,14 +515,7 @@ impl VerylWalker for Aligner {
fn case_item(&mut self, arg: &CaseItem) {
self.aligns[align_kind::EXPRESSION].start_item();
match &*arg.case_item_group {
CaseItemGroup::ExpressionCaseItemGroupList(x) => {
self.expression(&x.expression);
for x in &x.case_item_group_list {
self.comma(&x.comma);
self.space(1);
self.expression(&x.expression);
}
}
CaseItemGroup::CaseCondition(x) => self.case_condition(&x.case_condition),
CaseItemGroup::Defaul(x) => self.defaul(&x.defaul),
}
self.aligns[align_kind::EXPRESSION].finish_item();
Expand All @@ -549,6 +532,16 @@ impl VerylWalker for Aligner {
}
}

/// Semantic action for non-terminal 'CaseCondition'
fn case_condition(&mut self, arg: &CaseCondition) {
self.expression(&arg.expression);
for x in &arg.case_condition_list {
self.comma(&x.comma);
self.space(1);
self.expression(&x.expression);
}
}

/// Semantic action for non-terminal 'LetDeclaration'
fn let_declaration(&mut self, arg: &LetDeclaration) {
self.r#let(&arg.r#let);
Expand Down
Loading

0 comments on commit 6279cfa

Please sign in to comment.