Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 50 additions & 10 deletions sv-parser-parser/src/behavioral_statements/case_statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,40 @@ pub(crate) fn case_statement_normal(s: Span) -> IResult<Span, CaseStatement> {
let (s, a) = opt(unique_priority)(s)?;
let (s, b) = case_keyword(s)?;
let (s, c) = paren(case_expression)(s)?;
let (s, d) = case_item(s)?;
let (s, (e, f)) = many_till(case_item, keyword("endcase"))(s)?;
Ok((
s,
CaseStatement::Normal(Box::new(CaseStatementNormal {
nodes: (a, b, c, d, e, f),
})),
))
if !matches!(
c.nodes.1.nodes.0,
CaseExpressionExpression::TypeReference(_)
) {
let (s, d) = case_item(s)?;
let (s, (e, f)) = many_till(case_item, keyword("endcase"))(s)?;
Ok((
s,
CaseStatement::Normal(Box::new(CaseStatementNormal {
nodes: (a, b, c, d, e, f),
})),
))
} else {
let verify_case_item = |d: &CaseItem| {
if let CaseItem::NonDefault(non_def_item) = d {
matches!(
non_def_item.nodes.0.nodes.0.nodes.0,
CaseExpressionExpression::TypeReference(_)
) && non_def_item.nodes.0.nodes.1.iter().all(|(_, cie)| {
matches!(cie.nodes.0, CaseExpressionExpression::TypeReference(_))
})
} else {
true
}
};
let (s, d) = verify(case_item, verify_case_item)(s)?;
let (s, (e, f)) = many_till(verify(case_item, verify_case_item), keyword("endcase"))(s)?;
Ok((
s,
CaseStatement::Normal(Box::new(CaseStatementNormal {
nodes: (a, b, c, d, e, f),
})),
))
}
}

#[tracable_parser]
Expand Down Expand Up @@ -75,7 +101,14 @@ pub(crate) fn case_keyword(s: Span) -> IResult<Span, CaseKeyword> {
#[tracable_parser]
#[packrat_parser]
pub(crate) fn case_expression(s: Span) -> IResult<Span, CaseExpression> {
let (s, a) = expression(s)?;
let (s, a) = alt((
map(expression, |x| {
CaseExpressionExpression::Expression(Box::new(x))
}),
map(type_reference, |x| {
CaseExpressionExpression::TypeReference(Box::new(x))
}),
))(s)?;
Ok((s, CaseExpression { nodes: (a,) }))
}

Expand Down Expand Up @@ -160,7 +193,14 @@ pub(crate) fn case_inside_item_nondefault(s: Span) -> IResult<Span, CaseInsideIt
#[tracable_parser]
#[packrat_parser]
pub(crate) fn case_item_expression(s: Span) -> IResult<Span, CaseItemExpression> {
let (s, a) = expression(s)?;
let (s, a) = alt((
map(expression, |x| {
CaseExpressionExpression::Expression(Box::new(x))
}),
map(type_reference, |x| {
CaseExpressionExpression::TypeReference(Box::new(x))
}),
))(s)?;
Ok((s, CaseItemExpression { nodes: (a,) }))
}

Expand Down
40 changes: 32 additions & 8 deletions sv-parser-parser/src/expressions/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,16 +305,40 @@ pub(crate) fn expression_operator_assignment(s: Span) -> IResult<Span, Expressio
#[tracable_parser]
#[packrat_parser]
pub(crate) fn expression_binary(s: Span) -> IResult<Span, Expression> {
let (s, a) = expression(s)?;
let (s, a) = alt((
map(expression, |x| {
ExpressionBinaryOperand::Expression(Box::new(x))
}),
map(type_reference, |x| {
ExpressionBinaryOperand::TypeReference(Box::new(x))
}),
))(s)?;
let is_equality = peek(alt((symbol("=="), symbol("!="))))(s).is_ok();
let (s, b) = binary_operator(s)?;
let (s, c) = many0(attribute_instance)(s)?;
let (s, d) = expression(s)?;
Ok((
s,
Expression::Binary(Box::new(ExpressionBinary {
nodes: (a, b, c, d),
})),
))
let (s, d) = alt((
map(expression, |x| {
ExpressionBinaryOperand::Expression(Box::new(x))
}),
map(type_reference, |x| {
ExpressionBinaryOperand::TypeReference(Box::new(x))
}),
))(s)?;

// Enforces Footnote (40) in IEEE STD 1800 - 2017
let op1_is_type_ref = matches!(a, ExpressionBinaryOperand::TypeReference(_));
let op2_is_type_ref = matches!(d, ExpressionBinaryOperand::TypeReference(_));
if !(op1_is_type_ref || op2_is_type_ref) || (is_equality && op1_is_type_ref && op2_is_type_ref)
{
Ok((
s,
Expression::Binary(Box::new(ExpressionBinary {
nodes: (a, b, c, d),
})),
))
} else {
Err(Err::Error(make_error(s, ErrorKind::Fail)))
}
}

#[tracable_parser]
Expand Down
69 changes: 47 additions & 22 deletions sv-parser-parser/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ mod unit {

#[test]
fn test_data_declaration() {
// Implicit data_type is not allowed unless the `var` keyword is used.
test!(data_declaration, "logic x = 0;", Ok((_, _)));
test!(data_declaration, " x = 0;", Err(_));
test!(data_declaration, "var logic x = 0;", Ok((_, _)));
test!(data_declaration, "var x = 0;", Ok((_, _)));
test!(data_declaration, "const logic x = 0;", Ok((_, _)));
test!(data_declaration, "const x = 0;", Err(_));
// Implicit data_type is not allowed unless the `var` keyword is used.
test!(data_declaration, "logic x = 0;", Ok((_, _)));
test!(data_declaration, " x = 0;", Err(_));
test!(data_declaration, "var logic x = 0;", Ok((_, _)));
test!(data_declaration, "var x = 0;", Ok((_, _)));
test!(data_declaration, "const logic x = 0;", Ok((_, _)));
test!(data_declaration, "const x = 0;", Err(_));
}

#[test]
Expand Down Expand Up @@ -332,6 +332,14 @@ mod unit {
test!(expression, "(!a ? 0 : !b : 1 : c ? 0 : 1)", Ok((_, _)));
}

#[test]
fn test_bin_op_expression() {
test!(expression, "type(logic) == type(logic)", Ok((_, _)));
test!(expression, "type(logic) != type(logic)", Ok((_, _)));
test!(expression, "type(logic) + type(logic)", Err(_));
test!(expression, "type(logic) == a", Err(_));
}

#[test]
fn test_text_macro_definition() {
test!(text_macro_definition, r##"`define a b c"##, Ok((_, _)));
Expand Down Expand Up @@ -809,11 +817,7 @@ mod spec {
r##"a = add (* mode = "cla" *) (b, c);"##,
Ok((_, _))
);
test!(
statement,
r##"a = b ? (* no_glitch *) c : d;"##,
Ok((_, _))
);
test!(statement, r##"a = b ? (* no_glitch *) c : d;"##, Ok((_, _)));
}

#[test]
Expand Down Expand Up @@ -2685,11 +2689,7 @@ mod spec {
status = p.current_status();"##,
Ok((_, _))
);
test!(
statement,
r##"status = current_status(p);"##,
Ok((_, _))
);
test!(statement, r##"status = current_status(p);"##, Ok((_, _)));
test!(many1(module_item), r##"Packet p = new;"##, Ok((_, _)));
test!(
many1(module_item),
Expand Down Expand Up @@ -3512,11 +3512,7 @@ mod spec {
end"##,
Ok((_, _))
);
test!(
statement,
r##"put_ref = new(); // illegal"##,
Ok((_, _))
);
test!(statement, r##"put_ref = new(); // illegal"##, Ok((_, _)));
test!(
many1(module_item),
r##"interface class IntfBase1;
Expand Down Expand Up @@ -15942,6 +15938,35 @@ mod spec {
Ok((_, _))
);
}

#[test]
fn test_case_statement_comparison() {
test!(
many1(case_statement),
r##"case (type(logic))
type(logic[11:0]) : ;
type(logic) : ;
default : ;
endcase"##,
Ok((_, _))
);
test!(
many1(case_statement),
r##"case (type(logic))
1 : ;
default : ;
endcase"##,
Err(_)
);
test!(
many1(case_statement),
r##"case (type(logic))
x : ;
default : ;
endcase"##,
Err(_)
);
}
}

mod error {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,13 @@ pub enum CaseKeyword {

#[derive(Clone, Debug, PartialEq, Node)]
pub struct CaseExpression {
pub nodes: (Expression,),
pub nodes: (CaseExpressionExpression,),
}

#[derive(Clone, Debug, PartialEq, Node)]
pub enum CaseExpressionExpression {
Expression(Box<Expression>),
TypeReference(Box<TypeReference>),
}

#[derive(Clone, Debug, PartialEq, Node)]
Expand Down Expand Up @@ -104,7 +110,7 @@ pub struct CaseInsideItemNondefault {

#[derive(Clone, Debug, PartialEq, Node)]
pub struct CaseItemExpression {
pub nodes: (Expression,),
pub nodes: (CaseExpressionExpression,),
}

#[derive(Clone, Debug, PartialEq, Node)]
Expand Down
10 changes: 8 additions & 2 deletions sv-parser-syntaxtree/src/expressions/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,19 @@ pub struct ExpressionOperatorAssignment {
#[derive(Clone, Debug, PartialEq, Node)]
pub struct ExpressionBinary {
pub nodes: (
Expression,
ExpressionBinaryOperand,
BinaryOperator,
Vec<AttributeInstance>,
Expression,
ExpressionBinaryOperand,
),
}

#[derive(Clone, Debug, PartialEq, Node)]
pub enum ExpressionBinaryOperand {
Expression(Box<Expression>),
TypeReference(Box<TypeReference>),
}

#[derive(Clone, Debug, PartialEq, Node)]
pub struct TaggedUnionExpression {
pub nodes: (Keyword, MemberIdentifier, Option<Expression>),
Expand Down
23 changes: 23 additions & 0 deletions sv-parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,4 +451,27 @@ endmodule"##;
let ret = parse_sv_str(src, &path, &defines, &[""], false, false);
assert!(ret.is_ok());
}

#[test]
fn test_type_equality() {
let src = r##"module top #( parameter type T = type(logic[11:0]) )
();
initial begin
case (type(T))
type(logic[11:0]) : ;
default : $stop;
endcase
if (type(T) == type(logic[12:0])) $stop;
if (type(T) != type(logic[11:0])) $stop;
if (type(T) === type(logic[12:0])) $stop;
if (type(T) !== type(logic[11:0])) $stop;
$finish;
end
endmodule"##;

let path = PathBuf::from("");
let defines = HashMap::new();
let ret = parse_sv_str(src, &path, &defines, &[""], false, false);
assert!(ret.is_ok());
}
}
Loading