diff --git a/CHANGELOG.md b/CHANGELOG.md index e5b2c3e..f4b9237 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,18 +2,20 @@ ## [Unreleased](https://github.com/dalance/sv-parser/compare/v0.4.6...Unreleased) - ReleaseDate +* [Added] recursive define detection + ## [v0.4.6](https://github.com/dalance/sv-parser/compare/v0.4.5...v0.4.6) - 2019-12-02 -* [Fix] constant_bit_select -* [Fix] wrong linebreak at define macro usage +* [Fixed] constant_bit_select +* [Fixed] wrong linebreak at define macro usage ## [v0.4.5](https://github.com/dalance/sv-parser/compare/v0.4.4...v0.4.5) - 2019-11-28 -* [Fix] wrong space at define macro usage +* [Fixed] wrong space at define macro usage ## [v0.4.4](https://github.com/dalance/sv-parser/compare/v0.4.3...v0.4.4) - 2019-11-22 -* [Fix] \`resetall wrongly clear define list +* [Fixed] \`resetall wrongly clear define list ## [v0.4.3](https://github.com/dalance/sv-parser/compare/v0.4.2...v0.4.3) - 2019-11-15 diff --git a/sv-parser-error/src/lib.rs b/sv-parser-error/src/lib.rs index 1200343..a686640 100644 --- a/sv-parser-error/src/lib.rs +++ b/sv-parser-error/src/lib.rs @@ -24,6 +24,8 @@ pub enum ErrorKind { DefineNotFound(String), #[fail(display = "Define must have argument")] DefineNoArgs, + #[fail(display = "Recursive define is detected: {}", _0)] + DefineRecursive(String), } // ----------------------------------------------------------------------------- diff --git a/sv-parser-pp/src/preprocess.rs b/sv-parser-pp/src/preprocess.rs index f833ddd..25b3909 100644 --- a/sv-parser-pp/src/preprocess.rs +++ b/sv-parser-pp/src/preprocess.rs @@ -124,7 +124,7 @@ pub fn preprocess, U: AsRef>( let mut s = String::new(); reader.read_to_string(&mut s)?; - preprocess_str(&s, path, pre_defines, include_paths) + preprocess_str(&s, path, pre_defines, include_paths, vec![]) } pub fn preprocess_str, U: AsRef>( @@ -132,6 +132,7 @@ pub fn preprocess_str, U: AsRef>( path: T, pre_defines: &Defines, include_paths: &[U], + resolved_defines: Vec, ) -> Result<(PreprocessedText, Defines), Error> { let mut skip = false; let mut skip_nodes = vec![]; @@ -328,9 +329,14 @@ pub fn preprocess_str, U: AsRef>( IncludeCompilerDirective::TextMacroUsage(x) => { let (_, _, ref x) = x.nodes; skip_nodes.push(x.into()); - if let Some((p, _, _)) = - resolve_text_macro_usage(x, s, path.as_ref(), &defines, include_paths)? - { + if let Some((p, _, _)) = resolve_text_macro_usage( + x, + s, + path.as_ref(), + &defines, + include_paths, + resolved_defines.clone(), + )? { let p = p.trim().trim_matches('"'); PathBuf::from(p) } else { @@ -355,9 +361,14 @@ pub fn preprocess_str, U: AsRef>( ret.merge(include); } NodeEvent::Enter(RefNode::TextMacroUsage(x)) if !skip => { - if let Some((text, origin, new_defines)) = - resolve_text_macro_usage(x, s, path.as_ref(), &defines, include_paths)? - { + if let Some((text, origin, new_defines)) = resolve_text_macro_usage( + x, + s, + path.as_ref(), + &defines, + include_paths, + resolved_defines.clone(), + )? { ret.push(&text, origin); defines = new_defines; } @@ -433,10 +444,16 @@ fn resolve_text_macro_usage, U: AsRef>( path: T, defines: &Defines, include_paths: &[U], + mut resolved_defines: Vec, ) -> Result, Defines)>, Error> { let (_, ref name, ref args) = x.nodes; let id = identifier((&name.nodes.0).into(), &s).unwrap(); + if resolved_defines.contains(&id) { + return Err(ErrorKind::DefineRecursive(id).into()); + } + resolved_defines.push(id.clone()); + let mut actual_args = Vec::new(); let no_args = args.is_none(); if let Some(args) = args { @@ -504,8 +521,13 @@ fn resolve_text_macro_usage, U: AsRef>( // remove leading whitespace replaced = String::from(replaced.trim_start()); - let (replaced, new_defines) = - preprocess_str(&replaced, path.as_ref(), &defines, include_paths)?; + let (replaced, new_defines) = preprocess_str( + &replaced, + path.as_ref(), + &defines, + include_paths, + resolved_defines, + )?; Ok(Some(( String::from(replaced.text()), text.origin.clone(), @@ -681,4 +703,22 @@ endmodule "## ); } + + #[test] + fn test7() { + let ret = preprocess(get_testcase("test7.sv"), &HashMap::new(), &[] as &[String]); + assert_eq!( + format!("{:?}", ret), + "Err(Error { inner: \n\nRecursive define is detected: a })" + ); + } + + #[test] + fn test8() { + let ret = preprocess(get_testcase("test8.sv"), &HashMap::new(), &[] as &[String]); + assert_eq!( + format!("{:?}", ret), + "Err(Error { inner: \n\nRecursive define is detected: b })" + ); + } } diff --git a/sv-parser-pp/testcases/test7.sv b/sv-parser-pp/testcases/test7.sv new file mode 100644 index 0000000..fbc0adc --- /dev/null +++ b/sv-parser-pp/testcases/test7.sv @@ -0,0 +1,3 @@ +`define a `a +// direct recursion +`a diff --git a/sv-parser-pp/testcases/test8.sv b/sv-parser-pp/testcases/test8.sv new file mode 100644 index 0000000..97ceb53 --- /dev/null +++ b/sv-parser-pp/testcases/test8.sv @@ -0,0 +1,6 @@ +`define b `c +`define c `d +`define d `e +`define e `b +// indirect recursion +`b diff --git a/sv-parser/src/lib.rs b/sv-parser/src/lib.rs index 73da5fa..9d5a908 100644 --- a/sv-parser/src/lib.rs +++ b/sv-parser/src/lib.rs @@ -130,7 +130,7 @@ pub fn parse_sv_str, U: AsRef>( pre_defines: &HashMap>, include_paths: &[U], ) -> Result<(SyntaxTree, Defines), Error> { - let (text, defines) = preprocess_str(s, path, pre_defines, include_paths)?; + let (text, defines) = preprocess_str(s, path, pre_defines, include_paths, vec![])?; let span = Span::new_extra(text.text(), SpanInfo::default()); let result = all_consuming(sv_parser)(span); match result { @@ -203,7 +203,7 @@ pub fn parse_lib_str, U: AsRef>( pre_defines: &HashMap>, include_paths: &[U], ) -> Result<(SyntaxTree, Defines), Error> { - let (text, defines) = preprocess_str(s, path, pre_defines, include_paths)?; + let (text, defines) = preprocess_str(s, path, pre_defines, include_paths, vec![])?; let span = Span::new_extra(text.text(), SpanInfo::default()); let result = all_consuming(lib_parser)(span); match result {