From 32b072e523c1ae9a5ce491391c7ca9e42fea046e Mon Sep 17 00:00:00 2001 From: dalance Date: Tue, 9 Jul 2019 20:18:10 +0900 Subject: [PATCH] Add left recursion detection --- src/parser.rs | 11 +- src/parser/expressions/numbers.rs | 204 +++++++++++++++------------- src/parser/expressions/operators.rs | 106 +++++++++++---- src/parser/expressions/primaries.rs | 76 ++++++----- src/parser/expressions/strings.rs | 26 +--- src/parser/general/attributes.rs | 30 ++-- src/parser/general/comments.rs | 15 +- src/parser/general/identifiers.rs | 49 +++---- src/parser/utils.rs | 45 +++++- 9 files changed, 322 insertions(+), 240 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 1bfb7b3..1159379 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -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; diff --git a/src/parser/expressions/numbers.rs b/src/parser/expressions/numbers.rs index 2cf2a7e..d68077d 100644 --- a/src/parser/expressions/numbers.rs +++ b/src/parser/expressions/numbers.rs @@ -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((_, _))); } } diff --git a/src/parser/expressions/operators.rs b/src/parser/expressions/operators.rs index 838cb36..6415488 100644 --- a/src/parser/expressions/operators.rs +++ b/src/parser/expressions/operators.rs @@ -52,6 +52,7 @@ pub fn binary_operator(s: Span) -> IResult { let (s, a) = alt(( alt(( symbol("+"), + symbol("->"), symbol("-"), symbol("**"), symbol("*"), @@ -76,7 +77,6 @@ pub fn binary_operator(s: Span) -> IResult { 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((_, _))); } } diff --git a/src/parser/expressions/primaries.rs b/src/parser/expressions/primaries.rs index e403331..72411e6 100644 --- a/src/parser/expressions/primaries.rs +++ b/src/parser/expressions/primaries.rs @@ -348,7 +348,7 @@ pub fn primary(s: Span) -> IResult { 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) + } } } diff --git a/src/parser/expressions/strings.rs b/src/parser/expressions/strings.rs index 66c1dbf..1540b78 100644 --- a/src/parser/expressions/strings.rs +++ b/src/parser/expressions/strings.rs @@ -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((_, _))); } } diff --git a/src/parser/general/attributes.rs b/src/parser/general/attributes.rs index 8b53c70..392f6cd 100644 --- a/src/parser/general/attributes.rs +++ b/src/parser/general/attributes.rs @@ -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((_, _)) ); } } diff --git a/src/parser/general/comments.rs b/src/parser/general/comments.rs index dca2dcc..9093a69 100644 --- a/src/parser/general/comments.rs +++ b/src/parser/general/comments.rs @@ -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((_, _))); } } diff --git a/src/parser/general/identifiers.rs b/src/parser/general/identifiers.rs index 23b6953..632650c 100644 --- a/src/parser/general/identifiers.rs +++ b/src/parser/general/identifiers.rs @@ -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((_, _))); + } } diff --git a/src/parser/utils.rs b/src/parser/utils.rs index 2f22dc7..22a2123 100644 --- a/src/parser/utils.rs +++ b/src/parser/utils.rs @@ -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, O> +where + F: Fn(Span<'a>) -> IResult, 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 { @@ -109,4 +125,31 @@ pub fn concat<'a>(a: Span<'a>, b: Span<'a>) -> Option> { } } +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) + } + }; +}