Add left recursion detection

This commit is contained in:
dalance 2019-07-09 20:18:10 +09:00
parent 3f8242d639
commit 32b072e523
9 changed files with 322 additions and 240 deletions

View File

@ -1,3 +1,7 @@
#[macro_use]
pub mod utils;
pub use utils::*;
pub mod behavioral_statements;
pub mod declarations;
pub mod expressions;
@ -7,7 +11,6 @@ pub mod primitive_instances;
pub mod source_text;
pub mod specify_section;
pub mod udp_declaration_and_instantiation;
pub mod utils;
pub use behavioral_statements::*;
pub use declarations::*;
pub use expressions::*;
@ -17,6 +20,8 @@ pub use primitive_instances::*;
pub use source_text::*;
pub use specify_section::*;
pub use udp_declaration_and_instantiation::*;
pub use utils::*;
pub type Span<'a> = nom_locate::LocatedSpan<&'a str>;
pub type Span<'a> = nom_locate::LocatedSpanEx<&'a str, u64>;
// IDs for left recursion detection
static REC_PRIMARY: u32 = 0;

View File

@ -416,125 +416,135 @@ mod tests {
use super::*;
#[test]
fn test() {
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("659"))),
"Ok((LocatedSpanEx { offset: 3, line: 1, fragment: \"\", extra: () }, IntegralNumber(DecimalNumber(UnsignedNumber(UnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"659\", extra: () }, []) })))))"
fn test_number() {
parser_test!(
number,
"659",
Ok((_, Number::IntegralNumber(IntegralNumber::DecimalNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("'h 837FF"))),
"Ok((LocatedSpanEx { offset: 8, line: 1, fragment: \"\", extra: () }, IntegralNumber(HexNumber(HexNumber { nodes: (None, HexBase { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"\\\'h\", extra: () }, [Space(LocatedSpanEx { offset: 2, line: 1, fragment: \" \", extra: () })]) }, HexValue { nodes: (LocatedSpanEx { offset: 3, line: 1, fragment: \"837FF\", extra: () }, []) }) }))))"
parser_test!(
number,
"'h 837FF",
Ok((_, Number::IntegralNumber(IntegralNumber::HexNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("'o7460"))),
"Ok((LocatedSpanEx { offset: 6, line: 1, fragment: \"\", extra: () }, IntegralNumber(OctalNumber(OctalNumber { nodes: (None, OctalBase { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"\\\'o\", extra: () }, []) }, OctalValue { nodes: (LocatedSpanEx { offset: 2, line: 1, fragment: \"7460\", extra: () }, []) }) }))))"
parser_test!(
number,
"'h 837FF",
Ok((_, Number::IntegralNumber(IntegralNumber::HexNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("4af"))),
"Err(Error((LocatedSpanEx { offset: 1, line: 1, fragment: \"af\", extra: () }, Eof)))"
parser_test!(
number,
"'o7460",
Ok((_, Number::IntegralNumber(IntegralNumber::OctalNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("4'b1001"))),
"Ok((LocatedSpanEx { offset: 7, line: 1, fragment: \"\", extra: () }, IntegralNumber(BinaryNumber(BinaryNumber { nodes: (Some(Size { nodes: (NonZeroUnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"4\", extra: () }, []) },) }), BinaryBase { nodes: (LocatedSpanEx { offset: 1, line: 1, fragment: \"\\\'b\", extra: () }, []) }, BinaryValue { nodes: (LocatedSpanEx { offset: 3, line: 1, fragment: \"1001\", extra: () }, []) }) }))))"
parser_test!(number, "'4af", Err(_));
parser_test!(
number,
"4'b1001",
Ok((_, Number::IntegralNumber(IntegralNumber::BinaryNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("5 'D 3"))),
"Ok((LocatedSpanEx { offset: 6, line: 1, fragment: \"\", extra: () }, IntegralNumber(DecimalNumber(BaseUnsigned(DecimalNumberBaseUnsigned { nodes: (Some(Size { nodes: (NonZeroUnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"5\", extra: () }, [Space(LocatedSpanEx { offset: 1, line: 1, fragment: \" \", extra: () })]) },) }), DecimalBase { nodes: (LocatedSpanEx { offset: 2, line: 1, fragment: \"\\\'D\", extra: () }, [Space(LocatedSpanEx { offset: 4, line: 1, fragment: \" \", extra: () })]) }, UnsignedNumber { nodes: (LocatedSpanEx { offset: 5, line: 1, fragment: \"3\", extra: () }, []) }) })))))"
parser_test!(
number,
"5 'D 3",
Ok((_, Number::IntegralNumber(IntegralNumber::DecimalNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("3'b01x"))),
"Ok((LocatedSpanEx { offset: 6, line: 1, fragment: \"\", extra: () }, IntegralNumber(BinaryNumber(BinaryNumber { nodes: (Some(Size { nodes: (NonZeroUnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"3\", extra: () }, []) },) }), BinaryBase { nodes: (LocatedSpanEx { offset: 1, line: 1, fragment: \"\\\'b\", extra: () }, []) }, BinaryValue { nodes: (LocatedSpanEx { offset: 3, line: 1, fragment: \"01x\", extra: () }, []) }) }))))"
parser_test!(
number,
"3'b01x",
Ok((_, Number::IntegralNumber(IntegralNumber::BinaryNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("12'hx"))),
"Ok((LocatedSpanEx { offset: 5, line: 1, fragment: \"\", extra: () }, IntegralNumber(HexNumber(HexNumber { nodes: (Some(Size { nodes: (NonZeroUnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"12\", extra: () }, []) },) }), HexBase { nodes: (LocatedSpanEx { offset: 2, line: 1, fragment: \"\\\'h\", extra: () }, []) }, HexValue { nodes: (LocatedSpanEx { offset: 4, line: 1, fragment: \"x\", extra: () }, []) }) }))))"
parser_test!(
number,
"12'hx",
Ok((_, Number::IntegralNumber(IntegralNumber::HexNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("16'hz"))),
"Ok((LocatedSpanEx { offset: 5, line: 1, fragment: \"\", extra: () }, IntegralNumber(HexNumber(HexNumber { nodes: (Some(Size { nodes: (NonZeroUnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"16\", extra: () }, []) },) }), HexBase { nodes: (LocatedSpanEx { offset: 2, line: 1, fragment: \"\\\'h\", extra: () }, []) }, HexValue { nodes: (LocatedSpanEx { offset: 4, line: 1, fragment: \"z\", extra: () }, []) }) }))))"
parser_test!(
number,
"16'hz",
Ok((_, Number::IntegralNumber(IntegralNumber::HexNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("8 'd -6"))),
"Err(Error((LocatedSpanEx { offset: 2, line: 1, fragment: \"\\\'d -6\", extra: () }, Eof)))"
parser_test!(number, "8 'd -6", Err(_));
parser_test!(
number,
"4 'shf",
Ok((_, Number::IntegralNumber(IntegralNumber::HexNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("4 'shf"))),
"Ok((LocatedSpanEx { offset: 6, line: 1, fragment: \"\", extra: () }, IntegralNumber(HexNumber(HexNumber { nodes: (Some(Size { nodes: (NonZeroUnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"4\", extra: () }, [Space(LocatedSpanEx { offset: 1, line: 1, fragment: \" \", extra: () })]) },) }), HexBase { nodes: (LocatedSpanEx { offset: 2, line: 1, fragment: \"\\\'sh\", extra: () }, []) }, HexValue { nodes: (LocatedSpanEx { offset: 5, line: 1, fragment: \"f\", extra: () }, []) }) }))))"
parser_test!(
number,
"16'sd?",
Ok((_, Number::IntegralNumber(IntegralNumber::DecimalNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("16'sd?"))),
"Ok((LocatedSpanEx { offset: 6, line: 1, fragment: \"\", extra: () }, IntegralNumber(DecimalNumber(BaseZNumber(DecimalNumberBaseZNumber { nodes: (Some(Size { nodes: (NonZeroUnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"16\", extra: () }, []) },) }), DecimalBase { nodes: (LocatedSpanEx { offset: 2, line: 1, fragment: \"\\\'sd\", extra: () }, []) }, ZNumber { nodes: (LocatedSpanEx { offset: 5, line: 1, fragment: \"?\", extra: () }, []) }) })))))"
parser_test!(
number,
"27_195_000",
Ok((_, Number::IntegralNumber(IntegralNumber::DecimalNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("27_195_000"))),
"Ok((LocatedSpanEx { offset: 10, line: 1, fragment: \"\", extra: () }, IntegralNumber(DecimalNumber(UnsignedNumber(UnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"27_195_000\", extra: () }, []) })))))"
parser_test!(
number,
"16'b0011_0101_0001_1111",
Ok((_, Number::IntegralNumber(IntegralNumber::BinaryNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("16'b0011_0101_0001_1111"))),
"Ok((LocatedSpanEx { offset: 23, line: 1, fragment: \"\", extra: () }, IntegralNumber(BinaryNumber(BinaryNumber { nodes: (Some(Size { nodes: (NonZeroUnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"16\", extra: () }, []) },) }), BinaryBase { nodes: (LocatedSpanEx { offset: 2, line: 1, fragment: \"\\\'b\", extra: () }, []) }, BinaryValue { nodes: (LocatedSpanEx { offset: 4, line: 1, fragment: \"0011_0101_0001_1111\", extra: () }, []) }) }))))"
parser_test!(
number,
"32 'h 12ab_f001",
Ok((_, Number::IntegralNumber(IntegralNumber::HexNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("32 'h 12ab_f001"))),
"Ok((LocatedSpanEx { offset: 15, line: 1, fragment: \"\", extra: () }, IntegralNumber(HexNumber(HexNumber { nodes: (Some(Size { nodes: (NonZeroUnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"32\", extra: () }, [Space(LocatedSpanEx { offset: 2, line: 1, fragment: \" \", extra: () })]) },) }), HexBase { nodes: (LocatedSpanEx { offset: 3, line: 1, fragment: \"\\\'h\", extra: () }, [Space(LocatedSpanEx { offset: 5, line: 1, fragment: \" \", extra: () })]) }, HexValue { nodes: (LocatedSpanEx { offset: 6, line: 1, fragment: \"12ab_f001\", extra: () }, []) }) }))))"
parser_test!(
number,
"1.2",
Ok((_, Number::RealNumber(RealNumber::FixedPointNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("1.2"))),
"Ok((LocatedSpanEx { offset: 3, line: 1, fragment: \"\", extra: () }, RealNumber(FixedPointNumber(FixedPointNumber { nodes: (UnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"1\", extra: () }, []) }, Symbol { nodes: (LocatedSpanEx { offset: 1, line: 1, fragment: \".\", extra: () }, []) }, UnsignedNumber { nodes: (LocatedSpanEx { offset: 2, line: 1, fragment: \"2\", extra: () }, []) }) }))))"
parser_test!(
number,
"0.1",
Ok((_, Number::RealNumber(RealNumber::FixedPointNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("0.1"))),
"Ok((LocatedSpanEx { offset: 3, line: 1, fragment: \"\", extra: () }, RealNumber(FixedPointNumber(FixedPointNumber { nodes: (UnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"0\", extra: () }, []) }, Symbol { nodes: (LocatedSpanEx { offset: 1, line: 1, fragment: \".\", extra: () }, []) }, UnsignedNumber { nodes: (LocatedSpanEx { offset: 2, line: 1, fragment: \"1\", extra: () }, []) }) }))))"
parser_test!(
number,
"2394.26331",
Ok((_, Number::RealNumber(RealNumber::FixedPointNumber(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("2394.26331"))),
"Ok((LocatedSpanEx { offset: 10, line: 1, fragment: \"\", extra: () }, RealNumber(FixedPointNumber(FixedPointNumber { nodes: (UnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"2394\", extra: () }, []) }, Symbol { nodes: (LocatedSpanEx { offset: 4, line: 1, fragment: \".\", extra: () }, []) }, UnsignedNumber { nodes: (LocatedSpanEx { offset: 5, line: 1, fragment: \"26331\", extra: () }, []) }) }))))"
parser_test!(
number,
"1.2E12",
Ok((_, Number::RealNumber(RealNumber::Floating(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("1.2E12"))),
"Ok((LocatedSpanEx { offset: 6, line: 1, fragment: \"\", extra: () }, RealNumber(Floating(RealNumberFloating { nodes: (UnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"1\", extra: () }, []) }, Some((Symbol { nodes: (LocatedSpanEx { offset: 1, line: 1, fragment: \".\", extra: () }, []) }, UnsignedNumber { nodes: (LocatedSpanEx { offset: 2, line: 1, fragment: \"2\", extra: () }, []) })), Exp { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 3, line: 1, fragment: \"E\", extra: () }, []) },) }, None, UnsignedNumber { nodes: (LocatedSpanEx { offset: 4, line: 1, fragment: \"12\", extra: () }, []) }) }))))"
parser_test!(
number,
"1.30e-2",
Ok((_, Number::RealNumber(RealNumber::Floating(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("1.30e-2"))),
"Ok((LocatedSpanEx { offset: 7, line: 1, fragment: \"\", extra: () }, RealNumber(Floating(RealNumberFloating { nodes: (UnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"1\", extra: () }, []) }, Some((Symbol { nodes: (LocatedSpanEx { offset: 1, line: 1, fragment: \".\", extra: () }, []) }, UnsignedNumber { nodes: (LocatedSpanEx { offset: 2, line: 1, fragment: \"30\", extra: () }, []) })), Exp { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 4, line: 1, fragment: \"e\", extra: () }, []) },) }, Some(Minus(Symbol { nodes: (LocatedSpanEx { offset: 5, line: 1, fragment: \"-\", extra: () }, []) })), UnsignedNumber { nodes: (LocatedSpanEx { offset: 6, line: 1, fragment: \"2\", extra: () }, []) }) }))))"
parser_test!(
number,
"0.1e-0",
Ok((_, Number::RealNumber(RealNumber::Floating(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("0.1e-0"))),
"Ok((LocatedSpanEx { offset: 6, line: 1, fragment: \"\", extra: () }, RealNumber(Floating(RealNumberFloating { nodes: (UnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"0\", extra: () }, []) }, Some((Symbol { nodes: (LocatedSpanEx { offset: 1, line: 1, fragment: \".\", extra: () }, []) }, UnsignedNumber { nodes: (LocatedSpanEx { offset: 2, line: 1, fragment: \"1\", extra: () }, []) })), Exp { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 3, line: 1, fragment: \"e\", extra: () }, []) },) }, Some(Minus(Symbol { nodes: (LocatedSpanEx { offset: 4, line: 1, fragment: \"-\", extra: () }, []) })), UnsignedNumber { nodes: (LocatedSpanEx { offset: 5, line: 1, fragment: \"0\", extra: () }, []) }) }))))"
parser_test!(
number,
"23E10",
Ok((_, Number::RealNumber(RealNumber::Floating(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("23E10"))),
"Ok((LocatedSpanEx { offset: 5, line: 1, fragment: \"\", extra: () }, RealNumber(Floating(RealNumberFloating { nodes: (UnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"23\", extra: () }, []) }, None, Exp { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 2, line: 1, fragment: \"E\", extra: () }, []) },) }, None, UnsignedNumber { nodes: (LocatedSpanEx { offset: 3, line: 1, fragment: \"10\", extra: () }, []) }) }))))"
parser_test!(
number,
"29E-2",
Ok((_, Number::RealNumber(RealNumber::Floating(_))))
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("29E-2"))),
"Ok((LocatedSpanEx { offset: 5, line: 1, fragment: \"\", extra: () }, RealNumber(Floating(RealNumberFloating { nodes: (UnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"29\", extra: () }, []) }, None, Exp { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 2, line: 1, fragment: \"E\", extra: () }, []) },) }, Some(Minus(Symbol { nodes: (LocatedSpanEx { offset: 3, line: 1, fragment: \"-\", extra: () }, []) })), UnsignedNumber { nodes: (LocatedSpanEx { offset: 4, line: 1, fragment: \"2\", extra: () }, []) }) }))))"
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("236.123_763_e-12"))),
"Ok((LocatedSpanEx { offset: 16, line: 1, fragment: \"\", extra: () }, RealNumber(Floating(RealNumberFloating { nodes: (UnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"236\", extra: () }, []) }, Some((Symbol { nodes: (LocatedSpanEx { offset: 3, line: 1, fragment: \".\", extra: () }, []) }, UnsignedNumber { nodes: (LocatedSpanEx { offset: 4, line: 1, fragment: \"123_763_\", extra: () }, []) })), Exp { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 12, line: 1, fragment: \"e\", extra: () }, []) },) }, Some(Minus(Symbol { nodes: (LocatedSpanEx { offset: 13, line: 1, fragment: \"-\", extra: () }, []) })), UnsignedNumber { nodes: (LocatedSpanEx { offset: 14, line: 1, fragment: \"12\", extra: () }, []) }) }))))"
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new(".12"))),
"Err(Error((LocatedSpanEx { offset: 0, line: 1, fragment: \".12\", extra: () }, Digit)))"
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("9."))),
"Err(Error((LocatedSpanEx { offset: 1, line: 1, fragment: \".\", extra: () }, Eof)))"
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new("4.E3"))),
"Err(Error((LocatedSpanEx { offset: 1, line: 1, fragment: \".E3\", extra: () }, Eof)))"
);
assert_eq!(
format!("{:?}", all_consuming(number)(Span::new(".2e-7"))),
"Err(Error((LocatedSpanEx { offset: 0, line: 1, fragment: \".2e-7\", extra: () }, Digit)))"
);
assert_eq!(
format!(
"{:?}",
all_consuming(unbased_unsized_literal)(Span::new("'0"))
),
"Ok((LocatedSpanEx { offset: 2, line: 1, fragment: \"\", extra: () }, UnbasedUnsizedLiteral { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"\\\'0\", extra: () }, []) },) }))"
parser_test!(
number,
"236.123_763_e-12",
Ok((_, Number::RealNumber(RealNumber::Floating(_))))
);
parser_test!(number, ".12", Err(_));
parser_test!(number, "9.", Err(_));
parser_test!(number, "4.E3", Err(_));
parser_test!(number, ".2e-7", Err(_));
}
#[test]
fn test_unbased_unsized_literal() {
parser_test!(unbased_unsized_literal, "'0", Ok((_, _)));
parser_test!(unbased_unsized_literal, "'1", Ok((_, _)));
parser_test!(unbased_unsized_literal, "'x", Ok((_, _)));
parser_test!(unbased_unsized_literal, "'z", Ok((_, _)));
}
}

View File

@ -52,6 +52,7 @@ pub fn binary_operator(s: Span) -> IResult<Span, BinaryOperator> {
let (s, a) = alt((
alt((
symbol("+"),
symbol("->"),
symbol("-"),
symbol("**"),
symbol("*"),
@ -76,7 +77,6 @@ pub fn binary_operator(s: Span) -> IResult<Span, BinaryOperator> {
symbol(">>"),
symbol("<<<"),
symbol("<<"),
symbol("->"),
symbol("<->"),
symbol("<="),
symbol("<"),
@ -130,32 +130,82 @@ mod tests {
use nom::combinator::*;
#[test]
fn test() {
assert_eq!(
format!("{:?}", all_consuming(unary_operator)(Span::new("~"))),
"Ok((LocatedSpanEx { offset: 1, line: 1, fragment: \"\", extra: () }, UnaryOperator { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"~\", extra: () }, []) },) }))"
);
assert_eq!(
format!("{:?}", all_consuming(binary_operator)(Span::new(">>>"))),
"Ok((LocatedSpanEx { offset: 3, line: 1, fragment: \"\", extra: () }, BinaryOperator { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \">>>\", extra: () }, []) },) }))"
);
assert_eq!(
format!("{:?}", all_consuming(inc_or_dec_operator)(Span::new("++"))),
"Ok((LocatedSpanEx { offset: 2, line: 1, fragment: \"\", extra: () }, IncOrDecOperator { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"++\", extra: () }, []) },) }))"
);
assert_eq!(
format!(
"{:?}",
all_consuming(unary_module_path_operator)(Span::new("^~"))
),
"Ok((LocatedSpanEx { offset: 2, line: 1, fragment: \"\", extra: () }, UnaryModulePathOperator { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"^~\", extra: () }, []) },) }))"
);
assert_eq!(
format!(
"{:?}",
all_consuming(binary_module_path_operator)(Span::new("||"))
),
"Ok((LocatedSpanEx { offset: 2, line: 1, fragment: \"\", extra: () }, BinaryModulePathOperator { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"||\", extra: () }, []) },) }))"
);
fn test_unary_operator() {
parser_test!(unary_operator, "+", Ok((_, _)));
parser_test!(unary_operator, "-", Ok((_, _)));
parser_test!(unary_operator, "!", Ok((_, _)));
parser_test!(unary_operator, "&", Ok((_, _)));
parser_test!(unary_operator, "|", Ok((_, _)));
parser_test!(unary_operator, "~&", Ok((_, _)));
parser_test!(unary_operator, "~|", Ok((_, _)));
parser_test!(unary_operator, "~^", Ok((_, _)));
parser_test!(unary_operator, "^~", Ok((_, _)));
parser_test!(unary_operator, "^", Ok((_, _)));
parser_test!(unary_operator, "~", Ok((_, _)));
}
#[test]
fn test_binary_operator() {
parser_test!(binary_operator, "+", Ok((_, _)));
parser_test!(binary_operator, "-", Ok((_, _)));
parser_test!(binary_operator, "**", Ok((_, _)));
parser_test!(binary_operator, "*", Ok((_, _)));
parser_test!(binary_operator, "/", Ok((_, _)));
parser_test!(binary_operator, "%", Ok((_, _)));
parser_test!(binary_operator, "===", Ok((_, _)));
parser_test!(binary_operator, "==?", Ok((_, _)));
parser_test!(binary_operator, "==", Ok((_, _)));
parser_test!(binary_operator, "!==", Ok((_, _)));
parser_test!(binary_operator, "!=?", Ok((_, _)));
parser_test!(binary_operator, "!=", Ok((_, _)));
parser_test!(binary_operator, "&&", Ok((_, _)));
parser_test!(binary_operator, "||", Ok((_, _)));
parser_test!(binary_operator, "&", Ok((_, _)));
parser_test!(binary_operator, "|", Ok((_, _)));
parser_test!(binary_operator, "^~", Ok((_, _)));
parser_test!(binary_operator, "^", Ok((_, _)));
parser_test!(binary_operator, "~^", Ok((_, _)));
parser_test!(binary_operator, ">>>", Ok((_, _)));
parser_test!(binary_operator, ">>", Ok((_, _)));
parser_test!(binary_operator, "<<<", Ok((_, _)));
parser_test!(binary_operator, "<<", Ok((_, _)));
parser_test!(binary_operator, "->", Ok((_, _)));
parser_test!(binary_operator, "<->", Ok((_, _)));
parser_test!(binary_operator, "<=", Ok((_, _)));
parser_test!(binary_operator, "<", Ok((_, _)));
parser_test!(binary_operator, ">=", Ok((_, _)));
parser_test!(binary_operator, ">", Ok((_, _)));
}
#[test]
fn test_inc_or_dec_operator() {
parser_test!(inc_or_dec_operator, "++", Ok((_, _)));
parser_test!(inc_or_dec_operator, "--", Ok((_, _)));
}
#[test]
fn test_unary_module_path_operator() {
parser_test!(unary_module_path_operator, "!", Ok((_, _)));
parser_test!(unary_module_path_operator, "&", Ok((_, _)));
parser_test!(unary_module_path_operator, "|", Ok((_, _)));
parser_test!(unary_module_path_operator, "~&", Ok((_, _)));
parser_test!(unary_module_path_operator, "~|", Ok((_, _)));
parser_test!(unary_module_path_operator, "~^", Ok((_, _)));
parser_test!(unary_module_path_operator, "^~", Ok((_, _)));
parser_test!(unary_module_path_operator, "^", Ok((_, _)));
parser_test!(unary_module_path_operator, "~", Ok((_, _)));
}
#[test]
fn test_binary_module_path_operator() {
parser_test!(binary_module_path_operator, "==", Ok((_, _)));
parser_test!(binary_module_path_operator, "!=", Ok((_, _)));
parser_test!(binary_module_path_operator, "&&", Ok((_, _)));
parser_test!(binary_module_path_operator, "||", Ok((_, _)));
parser_test!(binary_module_path_operator, "&", Ok((_, _)));
parser_test!(binary_module_path_operator, "|", Ok((_, _)));
parser_test!(binary_module_path_operator, "^~", Ok((_, _)));
parser_test!(binary_module_path_operator, "^", Ok((_, _)));
parser_test!(binary_module_path_operator, "~^", Ok((_, _)));
}
}

View File

@ -348,7 +348,7 @@ pub fn primary(s: Span) -> IResult<Span, Primary> {
Primary::EmptyUnpackedArrayConcatenation
}),
primary_concatenation,
map(function_subroutine_call, |x| {
map(rec(function_subroutine_call, REC_PRIMARY), |x| {
Primary::FunctionSubroutineCall(x)
}),
map(let_expression, |x| Primary::LetExpression(x)),
@ -571,38 +571,46 @@ mod tests {
use super::*;
#[test]
fn test() {
assert_eq!(
format!("{:?}", all_consuming(primary)(Span::new("2.1ns"))),
"Ok((LocatedSpanEx { offset: 5, line: 1, fragment: \"\", extra: () }, PrimaryLiteral(TimeLiteral(FixedPointTimeLiteral(FixedPointTimeLiteral { nodes: (FixedPointNumber { nodes: (UnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"2\", extra: () }, []) }, Symbol { nodes: (LocatedSpanEx { offset: 1, line: 1, fragment: \".\", extra: () }, []) }, UnsignedNumber { nodes: (LocatedSpanEx { offset: 2, line: 1, fragment: \"1\", extra: () }, []) }) }, NS(Symbol { nodes: (LocatedSpanEx { offset: 3, line: 1, fragment: \"ns\", extra: () }, []) })) })))))"
);
assert_eq!(
format!("{:?}", all_consuming(primary)(Span::new("40 ps"))),
"Ok((LocatedSpanEx { offset: 5, line: 1, fragment: \"\", extra: () }, PrimaryLiteral(TimeLiteral(UnsignedTimeLiteral(UnsignedTimeLiteral { nodes: (UnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"40\", extra: () }, [Space(LocatedSpanEx { offset: 2, line: 1, fragment: \" \", extra: () })]) }, PS(Symbol { nodes: (LocatedSpanEx { offset: 3, line: 1, fragment: \"ps\", extra: () }, []) })) })))))"
);
assert_eq!(
format!("{:?}", all_consuming(primary)(Span::new("'0"))),
"Ok((LocatedSpanEx { offset: 2, line: 1, fragment: \"\", extra: () }, PrimaryLiteral(UnbasedUnsizedLiteral(UnbasedUnsizedLiteral { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"\\\'0\", extra: () }, []) },) }))))"
);
assert_eq!(
format!("{:?}", all_consuming(primary)(Span::new("10"))),
"Ok((LocatedSpanEx { offset: 2, line: 1, fragment: \"\", extra: () }, PrimaryLiteral(Number(IntegralNumber(DecimalNumber(UnsignedNumber(UnsignedNumber { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"10\", extra: () }, []) })))))))"
);
assert_eq!(
format!("{:?}", all_consuming(primary)(Span::new("\"aaa\""))),
"Ok((LocatedSpanEx { offset: 5, line: 1, fragment: \"\", extra: () }, PrimaryLiteral(StringLiteral(StringLiteral { nodes: (LocatedSpanEx { offset: 1, line: 1, fragment: \"aaa\", extra: () }, []) }))))"
);
//assert_eq!(
// format!("{:?}", all_consuming(primary)(Span::new("this"))),
// "Ok((LocatedSpanEx { offset: 4, line: 1, fragment: \"\", extra: () }, This(This { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"this\", extra: () }, []) },) })))"
//);
//assert_eq!(
// format!("{:?}", all_consuming(primary)(Span::new("$"))),
// "Ok((LocatedSpanEx { offset: 1, line: 1, fragment: \"\", extra: () }, Dollar(Dollar { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"$\", extra: () }, []) },) })))"
//);
//assert_eq!(
// format!("{:?}", all_consuming(primary)(Span::new("null"))),
// "Ok((LocatedSpanEx { offset: 4, line: 1, fragment: \"\", extra: () }, Null(Null { nodes: (Symbol { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"null\", extra: () }, []) },) })))"
//);
fn test_primary() {
let ret = all_consuming(primary)(Span::new_extra("2.1ns", 0));
if let Ok((_, Primary::PrimaryLiteral(PrimaryLiteral::TimeLiteral(_)))) = ret {
} else {
assert!(false, "{:?}", ret)
}
let ret = all_consuming(primary)(Span::new_extra("40 ps", 0));
if let Ok((_, Primary::PrimaryLiteral(PrimaryLiteral::TimeLiteral(_)))) = ret {
} else {
assert!(false, "{:?}", ret)
}
let ret = all_consuming(primary)(Span::new_extra("'0", 0));
if let Ok((_, Primary::PrimaryLiteral(PrimaryLiteral::UnbasedUnsizedLiteral(_)))) = ret {
} else {
assert!(false, "{:?}", ret)
}
let ret = all_consuming(primary)(Span::new_extra("10", 0));
if let Ok((_, Primary::PrimaryLiteral(PrimaryLiteral::Number(_)))) = ret {
} else {
assert!(false, "{:?}", ret)
}
let ret = all_consuming(primary)(Span::new_extra("\"aaa\"", 0));
if let Ok((_, Primary::PrimaryLiteral(PrimaryLiteral::StringLiteral(_)))) = ret {
} else {
assert!(false, "{:?}", ret)
}
let ret = all_consuming(primary)(Span::new_extra("this", 0));
if let Ok((_, Primary::This(_))) = ret {
} else {
assert!(false, "{:?}", ret)
}
let ret = all_consuming(primary)(Span::new_extra("$", 0));
if let Ok((_, Primary::Dollar(_))) = ret {
} else {
assert!(false, "{:?}", ret)
}
let ret = all_consuming(primary)(Span::new_extra("null", 0));
if let Ok((_, Primary::Null(_))) = ret {
} else {
assert!(false, "{:?}", ret)
}
}
}

View File

@ -57,27 +57,9 @@ mod tests {
use super::*;
#[test]
fn test() {
assert_eq!(
format!(
"{:?}",
all_consuming(string_literal)(Span::new("\"aaa aaaa\""))
),
"Ok((LocatedSpanEx { offset: 10, line: 1, fragment: \"\", extra: () }, StringLiteral { nodes: (LocatedSpanEx { offset: 1, line: 1, fragment: \"aaa aaaa\", extra: () }, []) }))"
);
assert_eq!(
format!(
"{:?}",
all_consuming(string_literal)(Span::new(r#""aaa\" aaaa""#))
),
"Ok((LocatedSpanEx { offset: 12, line: 1, fragment: \"\", extra: () }, StringLiteral { nodes: (LocatedSpanEx { offset: 1, line: 1, fragment: \"aaa\\\\\\\" aaaa\", extra: () }, []) }))"
);
assert_eq!(
format!(
"{:?}",
all_consuming(string_literal)(Span::new(r#""aaa\"""#))
),
"Ok((LocatedSpanEx { offset: 7, line: 1, fragment: \"\", extra: () }, StringLiteral { nodes: (LocatedSpanEx { offset: 1, line: 1, fragment: \"aaa\\\\\\\"\", extra: () }, []) }))"
);
fn test_string_literal() {
parser_test!(string_literal, "\"aaa aaaa\"", Ok((_, _)));
parser_test!(string_literal, r#""aaa\" aaaa""#, Ok((_, _)));
parser_test!(string_literal, r#""aaa\"""#, Ok((_, _)));
}
}

View File

@ -38,27 +38,17 @@ mod tests {
use super::*;
#[test]
fn test() {
assert_eq!(
format!(
"{:?}",
all_consuming(attribute_instance)(Span::new("(* full_case, parallel_case *)"))
),
"Ok((LocatedSpanEx { offset: 30, line: 1, fragment: \"\", extra: () }, AttributeInstance { nodes: ([AttrSpec { nodes: (SimpleIdentifier(SimpleIdentifier { nodes: (LocatedSpanEx { offset: 3, line: 1, fragment: \"full_case\", extra: () }, []) }), None) }, AttrSpec { nodes: (SimpleIdentifier(SimpleIdentifier { nodes: (LocatedSpanEx { offset: 14, line: 1, fragment: \"parallel_case\", extra: () }, [Space(LocatedSpanEx { offset: 27, line: 1, fragment: \" \", extra: () })]) }), None) }],) }))"
fn test_attribute_instance() {
parser_test!(
attribute_instance,
"(* full_case, parallel_case *)",
Ok((_, _))
);
assert_eq!(
format!(
"{:?}",
all_consuming(attribute_instance)(Span::new("(* full_case=1 *)"))
),
"Ok((LocatedSpanEx { offset: 17, line: 1, fragment: \"\", extra: () }, AttributeInstance { nodes: ([AttrSpec { nodes: (SimpleIdentifier(SimpleIdentifier { nodes: (LocatedSpanEx { offset: 3, line: 1, fragment: \"full_case\", extra: () }, []) }), Some(Nullary(PrimaryLiteral(Number(IntegralNumber(DecimalNumber(UnsignedNumber(UnsignedNumber { nodes: (LocatedSpanEx { offset: 13, line: 1, fragment: \"1\", extra: () }, [Space(LocatedSpanEx { offset: 14, line: 1, fragment: \" \", extra: () })]) })))))))) }],) }))"
);
assert_eq!(
format!(
"{:?}",
all_consuming(attribute_instance)(Span::new("(* full_case=1, parallel_case = 0 *)"))
),
"Ok((LocatedSpanEx { offset: 36, line: 1, fragment: \"\", extra: () }, AttributeInstance { nodes: ([AttrSpec { nodes: (SimpleIdentifier(SimpleIdentifier { nodes: (LocatedSpanEx { offset: 3, line: 1, fragment: \"full_case\", extra: () }, []) }), Some(Nullary(PrimaryLiteral(Number(IntegralNumber(DecimalNumber(UnsignedNumber(UnsignedNumber { nodes: (LocatedSpanEx { offset: 13, line: 1, fragment: \"1\", extra: () }, []) })))))))) }, AttrSpec { nodes: (SimpleIdentifier(SimpleIdentifier { nodes: (LocatedSpanEx { offset: 16, line: 1, fragment: \"parallel_case\", extra: () }, [Space(LocatedSpanEx { offset: 29, line: 1, fragment: \" \", extra: () })]) }), Some(Nullary(PrimaryLiteral(Number(IntegralNumber(DecimalNumber(UnsignedNumber(UnsignedNumber { nodes: (LocatedSpanEx { offset: 32, line: 1, fragment: \"0\", extra: () }, [Space(LocatedSpanEx { offset: 33, line: 1, fragment: \" \", extra: () })]) })))))))) }],) }))"
parser_test!(attribute_instance, "(* full_case=1 *)", Ok((_, _)));
parser_test!(
attribute_instance,
"(* full_case=1, parallel_case = 0 *)",
Ok((_, _))
);
}
}

View File

@ -40,17 +40,8 @@ mod tests {
use nom::combinator::*;
#[test]
fn test() {
assert_eq!(
format!("{:?}", all_consuming(comment)(Span::new("// comment"))),
"Ok((LocatedSpanEx { offset: 10, line: 1, fragment: \"\", extra: () }, Comment { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"// comment\", extra: () },) }))"
);
assert_eq!(
format!(
"{:?}",
all_consuming(comment)(Span::new("/* comment\n\n */"))
),
"Ok((LocatedSpanEx { offset: 15, line: 3, fragment: \"\", extra: () }, Comment { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"/* comment\\n\\n */\", extra: () },) }))"
);
fn test_comment() {
parser_test!(comment, "// comment", Ok((_, _)));
parser_test!(comment, "/* comment\n\n */", Ok((_, _)));
}
}

View File

@ -1011,33 +1011,36 @@ mod tests {
use super::*;
#[test]
fn test() {
assert_eq!(
format!("{:?}", all_consuming(identifier)(Span::new("shiftreg_a"))),
"Ok((LocatedSpanEx { offset: 10, line: 1, fragment: \"\", extra: () }, SimpleIdentifier(SimpleIdentifier { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"shiftreg_a\", extra: () }, []) })))"
fn test_identifier() {
parser_test!(
identifier,
"shiftreg_a",
Ok((_, Identifier::SimpleIdentifier(_)))
);
assert_eq!(
format!("{:?}", all_consuming(identifier)(Span::new("_bus3"))),
"Ok((LocatedSpanEx { offset: 5, line: 1, fragment: \"\", extra: () }, SimpleIdentifier(SimpleIdentifier { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"_bus3\", extra: () }, []) })))"
parser_test!(
identifier,
"_bus3",
Ok((_, Identifier::SimpleIdentifier(_)))
);
assert_eq!(
format!("{:?}", all_consuming(identifier)(Span::new("n$657"))),
"Ok((LocatedSpanEx { offset: 5, line: 1, fragment: \"\", extra: () }, SimpleIdentifier(SimpleIdentifier { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"n$657\", extra: () }, []) })))"
parser_test!(
identifier,
"n$657",
Ok((_, Identifier::SimpleIdentifier(_)))
);
assert_eq!(
format!("{:?}", all_consuming(identifier)(Span::new("\\busa+index"))),
"Ok((LocatedSpanEx { offset: 11, line: 1, fragment: \"\", extra: () }, EscapedIdentifier(EscapedIdentifier { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"\\\\busa+index\", extra: () }, []) })))"
parser_test!(
identifier,
"\\busa+index",
Ok((_, Identifier::EscapedIdentifier(_)))
);
assert_eq!(
format!("{:?}", all_consuming(identifier)(Span::new("\\-clock"))),
"Ok((LocatedSpanEx { offset: 7, line: 1, fragment: \"\", extra: () }, EscapedIdentifier(EscapedIdentifier { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"\\\\-clock\", extra: () }, []) })))"
);
assert_eq!(
format!(
"{:?}",
all_consuming(system_tf_identifier)(Span::new("$display"))
),
"Ok((LocatedSpanEx { offset: 8, line: 1, fragment: \"\", extra: () }, SystemTfIdentifier { nodes: (LocatedSpanEx { offset: 0, line: 1, fragment: \"$display\", extra: () }, []) }))"
parser_test!(
identifier,
"\\-clock",
Ok((_, Identifier::EscapedIdentifier(_)))
);
}
#[test]
fn test_system_tf_identifier() {
parser_test!(system_tf_identifier, "$display", Ok((_, _)));
}
}

View File

@ -3,8 +3,9 @@ use nom::branch::*;
use nom::bytes::complete::*;
use nom::character::complete::*;
use nom::combinator::*;
use nom::error::*;
use nom::multi::*;
use nom::IResult;
use nom::{Err, IResult};
// -----------------------------------------------------------------------------
@ -84,6 +85,21 @@ where
}
}
pub fn rec<'a, O, F>(f: F, id: u32) -> impl Fn(Span<'a>) -> IResult<Span<'a>, O>
where
F: Fn(Span<'a>) -> IResult<Span<'a>, O>,
{
move |s: Span<'a>| {
if check_bit(s, id) {
return Err(Err::Error(make_error(s, ErrorKind::Fix)));
}
let s = set_bit(s, id, true);
let (s, x) = f(s)?;
let s = set_bit(s, id, false);
Ok((s, x))
}
}
// -----------------------------------------------------------------------------
pub fn white_space(s: Span) -> IResult<Span, WhiteSpace> {
@ -109,4 +125,31 @@ pub fn concat<'a>(a: Span<'a>, b: Span<'a>) -> Option<Span<'a>> {
}
}
pub fn check_bit(s: Span, id: u32) -> bool {
((s.extra >> id) & 1) == 1
}
pub fn set_bit(s: Span, id: u32, bit: bool) -> Span {
let val = if bit { 1u64 << id } else { 0u64 };
let mask = !(1u64 << id);
let val = (s.extra & mask) | val;
Span {
offset: s.offset,
line: s.line,
fragment: s.fragment,
extra: val,
}
}
// -----------------------------------------------------------------------------
#[cfg(test)]
macro_rules! parser_test {
( $x:expr, $y:expr, $z:pat ) => {
let ret = all_consuming($x)(Span::new_extra($y, 0));
if let $z = ret {
} else {
assert!(false, "{:?}", ret)
}
};
}