diff --git a/CHANGELOG.md b/CHANGELOG.md index 151253a..76f5e24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased](https://github.com/dalance/sv-parser/compare/v0.3.3...Unreleased) - ReleaseDate +* [Fixed] define with string literal + ## [v0.3.3](https://github.com/dalance/sv-parser/compare/v0.3.2...v0.3.3) - 2019-11-01 * [Fixed] define arument diff --git a/sv-parser-parser/src/general/compiler_directives.rs b/sv-parser-parser/src/general/compiler_directives.rs index cd5ed41..572eb78 100644 --- a/sv-parser-parser/src/general/compiler_directives.rs +++ b/sv-parser-parser/src/general/compiler_directives.rs @@ -478,6 +478,9 @@ pub(crate) fn else_group_of_lines(s: Span) -> IResult { pub(crate) fn source_description(s: Span) -> IResult { alt(( map(comment, |x| SourceDescription::Comment(Box::new(x))), + map(string_literal, |x| { + SourceDescription::StringLiteral(Box::new(x)) + }), source_description_not_directive, map(compiler_directive, |x| { SourceDescription::CompilerDirective(Box::new(x)) @@ -489,7 +492,7 @@ pub(crate) fn source_description(s: Span) -> IResult { #[packrat_parser] pub(crate) fn source_description_not_directive(s: Span) -> IResult { let (s, a) = many1(alt(( - is_not("`/"), + is_not("`/\""), terminated(tag("/"), peek(not(alt((tag("/"), tag("*")))))), )))(s)?; diff --git a/sv-parser-pp/src/preprocess.rs b/sv-parser-pp/src/preprocess.rs index f509c1b..55394e7 100644 --- a/sv-parser-pp/src/preprocess.rs +++ b/sv-parser-pp/src/preprocess.rs @@ -8,7 +8,9 @@ use std::io::{BufReader, Read}; use std::path::{Path, PathBuf}; use sv_parser_error::{Error, ErrorKind}; use sv_parser_parser::{pp_parser, Span, SpanInfo}; -use sv_parser_syntaxtree::{IncludeCompilerDirective, Locate, NodeEvent, RefNode, TextMacroUsage}; +use sv_parser_syntaxtree::{ + IncludeCompilerDirective, Locate, NodeEvent, RefNode, SourceDescription, TextMacroUsage, +}; #[derive(Debug)] pub struct PreprocessedText { @@ -158,6 +160,13 @@ fn preprocess_str, U: AsRef>( let range = Range::new(locate.offset, locate.offset + locate.len); ret.push(locate.str(&s), path.as_ref(), range); } + NodeEvent::Enter(RefNode::SourceDescription(SourceDescription::StringLiteral(x))) + if !skip => + { + let locate: Locate = (&**x).try_into().unwrap(); + let range = Range::new(locate.offset, locate.offset + locate.len); + ret.push(locate.str(&s), path.as_ref(), range); + } NodeEvent::Enter(RefNode::KeywordsDirective(x)) if !skip => { let locate: Locate = x.try_into().unwrap(); let range = Range::new(locate.offset, locate.offset + locate.len); @@ -340,7 +349,9 @@ fn identifier(node: RefNode, s: &str) -> Option { } fn split_text(s: &str) -> Vec { + let mut is_string = false; let mut is_ident = false; + let mut is_backquote_prev = false; let mut is_ident_prev; let mut x = String::from(""); let mut ret = vec![]; @@ -348,12 +359,31 @@ fn split_text(s: &str) -> Vec { is_ident_prev = is_ident; is_ident = c.is_ascii_alphanumeric() | (c == '_'); - if is_ident != is_ident_prev { + if c == '"' && is_backquote_prev { + x.push(c); ret.push(x); x = String::from(""); + } else if c == '"' && !is_string { + ret.push(x); + x = String::from(""); + x.push(c); + is_string = true; + } else if c == '"' && is_string { + x.push(c); + ret.push(x); + x = String::from(""); + is_string = false; + } else if !is_string { + if is_ident != is_ident_prev { + ret.push(x); + x = String::from(""); + } + x.push(c); + } else { + x.push(c); } - x.push(c); + is_backquote_prev = c == '`'; } ret.push(x); ret @@ -402,7 +432,13 @@ fn resolve_text_macro_usage, U: AsRef>( if let Some(value) = arg_map.get(&text) { replaced.push_str(*value); } else { - replaced.push_str(&text.replace("``", "").replace("\\\n", "")); + replaced.push_str( + &text + .replace("``", "") + .replace("`\\`\"", "\\\"") + .replace("`\"", "\"") + .replace("\\\n", ""), + ); } } // separator is required @@ -538,6 +574,43 @@ module a (); always @(posedge clk) begin if (!(!(a[i].b && c[i]))) begin $display ("xxx(()[]]{}}}", a[i].b, c[i]) ; end end ; +endmodule +"## + ); + } + + #[test] + fn test5() { + let (ret, _) = + preprocess(get_testcase("test5.sv"), &HashMap::new(), &[] as &[String]).unwrap(); + assert_eq!( + ret.text(), + r##"module a; + + + +initial begin +$display("`HI, world"); +$display( "`HI, world" ); +$display( "Hello, x" ); +end +endmodule +"## + ); + } + + #[test] + fn test6() { + let (ret, _) = + preprocess(get_testcase("test6.sv"), &HashMap::new(), &[] as &[String]).unwrap(); + assert_eq!( + ret.text(), + r##" + +module a; +initial begin +$display( "left side: \"right side\"" ); +end endmodule "## ); diff --git a/sv-parser-pp/testcases/test5.sv b/sv-parser-pp/testcases/test5.sv new file mode 100644 index 0000000..662575d --- /dev/null +++ b/sv-parser-pp/testcases/test5.sv @@ -0,0 +1,10 @@ +module a; +`define HI Hello +`define LO "`HI, world" +`define H(x) "Hello, x" +initial begin +$display("`HI, world"); +$display(`LO); +$display(`H(world)); +end +endmodule diff --git a/sv-parser-pp/testcases/test6.sv b/sv-parser-pp/testcases/test6.sv new file mode 100644 index 0000000..752c735 --- /dev/null +++ b/sv-parser-pp/testcases/test6.sv @@ -0,0 +1,7 @@ +`define msg(x,y) `"x: `\`"y`\`"`" + +module a; +initial begin +$display(`msg(left side,right side)); +end +endmodule diff --git a/sv-parser-syntaxtree/src/general/compiler_directives.rs b/sv-parser-syntaxtree/src/general/compiler_directives.rs index b9facdb..3b1e76d 100644 --- a/sv-parser-syntaxtree/src/general/compiler_directives.rs +++ b/sv-parser-syntaxtree/src/general/compiler_directives.rs @@ -177,6 +177,7 @@ pub struct ElseGroupOfLines { #[derive(Clone, Debug, PartialEq, Node)] pub enum SourceDescription { Comment(Box), + StringLiteral(Box), NotDirective(Box), CompilerDirective(Box), } diff --git a/sv-parser/src/lib.rs b/sv-parser/src/lib.rs index 8397d00..24a82eb 100644 --- a/sv-parser/src/lib.rs +++ b/sv-parser/src/lib.rs @@ -7,7 +7,7 @@ use std::fmt; use std::path::{Path, PathBuf}; pub use sv_parser_error::{Error, ErrorKind}; use sv_parser_parser::{lib_parser, sv_parser, Span, SpanInfo}; -use sv_parser_pp::preprocess::{preprocess, Define, Defines, PreprocessedText}; +pub use sv_parser_pp::preprocess::{preprocess, Define, Defines, PreprocessedText}; pub use sv_parser_syntaxtree::*; pub struct SyntaxTree {