diff --git a/sv-parser-parser/src/general/compiler_directives.rs b/sv-parser-parser/src/general/compiler_directives.rs index 4556c03..232d22e 100644 --- a/sv-parser-parser/src/general/compiler_directives.rs +++ b/sv-parser-parser/src/general/compiler_directives.rs @@ -78,6 +78,7 @@ pub(crate) fn include_compiler_directive(s: Span) -> IResult IResult { + let (s, a) = symbol("`")(s)?; + let (s, b) = keyword("include")(s)?; + let (s, c) = text_macro_usage(s)?; + Ok(( + s, + IncludeCompilerDirective::TextMacroUsage(Box::new( + IncludeCompilerDirectiveTextMacroUsage { nodes: (a, b, c) }, + )), + )) +} + #[tracable_parser] #[packrat_parser] pub(crate) fn angle_bracket_literal(s: Span) -> IResult { diff --git a/sv-parser-parser/src/tests.rs b/sv-parser-parser/src/tests.rs index 7f8becb..9c00537 100644 --- a/sv-parser-parser/src/tests.rs +++ b/sv-parser-parser/src/tests.rs @@ -286,6 +286,7 @@ mod unit { test!(comment, "//", Ok((_, _))); test!(comment, "/* comment\n\n */", Ok((_, _))); test!(comment, "/* comment\n//aaa\n */", Ok((_, _))); + test!(comment, "/*! comment\n * aaa\n */", Ok((_, _))); } #[test] @@ -316,6 +317,22 @@ mod unit { Ok((_, _)) ); } + + #[test] + fn test_regression() { + test!( + source_text, + r##"package pkg; localparam [5:0] RES = RES5[0]; endpackage"##, + Ok((_, _)) + ); + test!( + source_text, + r##"interface intf (); localparam TYPE DEFAULT = TYPE'(0); endinterface"##, + Ok((_, _)) + ); + test!(source_text, r##"`macro(A, B, logic, C)"##, Ok((_, _))); + test!(source_text, r##"`macro(A, B, logic, a())"##, Ok((_, _))); + } } mod spec { @@ -15787,6 +15804,10 @@ mod spec { #[test] fn debug() { - test!(source_text, r##"/* comment\n//aaa\n */"##, Ok((_, _))); + test!( + source_text, + r##"interface intf (); localparam TYPE DEFAULT = TYPE'(0); endinterface"##, + Ok((_, _)) + ); nom_tracable::cumulative_histogram(); } diff --git a/sv-parser-pp/src/preprocess.rs b/sv-parser-pp/src/preprocess.rs index 70e8182..59092e5 100644 --- a/sv-parser-pp/src/preprocess.rs +++ b/sv-parser-pp/src/preprocess.rs @@ -7,7 +7,7 @@ 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}; +use sv_parser_syntaxtree::{IncludeCompilerDirective, Locate, NodeEvent, RefNode, TextMacroUsage}; #[derive(Debug)] pub struct PreprocessedText { @@ -76,7 +76,7 @@ pub struct Define { path: PathBuf, } -type Defines = HashMap>; +pub type Defines = HashMap>; pub fn preprocess, U: AsRef>( path: T, @@ -89,6 +89,15 @@ pub fn preprocess, U: AsRef>( let mut s = String::new(); reader.read_to_string(&mut s)?; + preprocess_str(&s, path, pre_defines, include_paths) +} + +fn preprocess_str, U: AsRef>( + s: &str, + path: T, + pre_defines: &Defines, + include_paths: &[U], +) -> Result<(PreprocessedText, Defines), Error> { let mut skip = false; let mut skip_nodes = vec![]; let mut defines = HashMap::new(); @@ -223,19 +232,26 @@ pub fn preprocess, U: AsRef>( defines.insert(id, Some(define)); } NodeEvent::Enter(RefNode::IncludeCompilerDirective(x)) if !skip => { - let path = match x { + let mut path = match x { IncludeCompilerDirective::DoubleQuote(x) => { let (_, _, ref literal) = x.nodes; let (locate, _) = literal.nodes; - locate.str(&s).trim_matches('"') + let p = locate.str(&s).trim_matches('"'); + PathBuf::from(p) } IncludeCompilerDirective::AngleBracket(x) => { let (_, _, ref literal) = x.nodes; let (locate, _) = literal.nodes; - locate.str(&s).trim_start_matches('<').trim_end_matches('>') + let p = locate.str(&s).trim_start_matches('<').trim_end_matches('>'); + PathBuf::from(p) + } + IncludeCompilerDirective::TextMacroUsage(x) => { + let (_, _, ref x) = x.nodes; + let (p, _, _, _) = + resolve_text_macro_usage(x, s, path.as_ref(), &defines, include_paths)?; + PathBuf::from(p) } }; - let mut path = PathBuf::from(path); if path.is_relative() { if !path.exists() { for include_path in include_paths { @@ -253,55 +269,10 @@ pub fn preprocess, U: AsRef>( ret.merge(include); } NodeEvent::Enter(RefNode::TextMacroUsage(x)) if !skip => { - let (_, ref name, ref args) = x.nodes; - let id = identifier((&name.nodes.0).into(), &s).unwrap(); - - let mut actual_args = Vec::new(); - if let Some(args) = args { - let (_, ref args, _) = args.nodes; - let (ref args,) = args.nodes; - for arg in args.contents() { - let (ref arg,) = arg.nodes; - let arg: Locate = arg.try_into().unwrap(); - let arg = arg.str(&s); - actual_args.push(arg); - } - } - - let define = defines.get(&id); - if let Some(Some(define)) = define { - let mut arg_map = HashMap::new(); - for (i, (arg, default)) in define.arguments.iter().enumerate() { - let value = if let Some(actual_arg) = actual_args.get(i) { - *actual_arg - } else { - if let Some(default) = default { - default - } else { - return Err(ErrorKind::Preprocess.into()); - } - }; - arg_map.insert(String::from(arg), value); - } - - if let Some((ref text, ref range)) = define.text { - let mut replaced = String::from(""); - for text in split_text(&text) { - if let Some(value) = arg_map.get(&text) { - replaced.push_str(*value); - } else { - replaced.push_str(&text.replace("``", "").replace("\\\n", "")); - } - } - ret.push(&replaced, define.path.clone(), *range); - } else { - return Err(ErrorKind::Preprocess.into()); - } - } else if let Some(_) = define { - return Err(ErrorKind::Preprocess.into()); - } else { - return Err(ErrorKind::Preprocess.into()); - } + let (text, path, range, new_defines) = + resolve_text_macro_usage(x, s, path.as_ref(), &defines, include_paths)?; + ret.push(&text, path, range); + defines = new_defines; } NodeEvent::Enter(x) => { if skip_nodes.contains(&x) { @@ -352,9 +323,77 @@ fn split_text(s: &str) -> Vec { x.push(c); } + ret.push(x); ret } +fn resolve_text_macro_usage, U: AsRef>( + x: &TextMacroUsage, + s: &str, + path: T, + defines: &Defines, + include_paths: &[U], +) -> Result<(String, PathBuf, Range, Defines), Error> { + let (_, ref name, ref args) = x.nodes; + let id = identifier((&name.nodes.0).into(), &s).unwrap(); + + let mut actual_args = Vec::new(); + if let Some(args) = args { + let (_, ref args, _) = args.nodes; + let (ref args,) = args.nodes; + for arg in args.contents() { + let (ref arg,) = arg.nodes; + let arg = arg.str(&s); + actual_args.push(arg); + } + } + + let define = defines.get(&id); + if let Some(Some(define)) = define { + let mut arg_map = HashMap::new(); + for (i, (arg, default)) in define.arguments.iter().enumerate() { + let value = if let Some(actual_arg) = actual_args.get(i) { + *actual_arg + } else { + if let Some(default) = default { + default + } else { + return Err(ErrorKind::DefineArgNotFound(String::from(arg)).into()); + } + }; + arg_map.insert(String::from(arg), value); + } + + if let Some((ref text, ref range)) = define.text { + let mut replaced = String::from(""); + for text in split_text(&text) { + if let Some(value) = arg_map.get(&text) { + replaced.push_str(*value); + } else { + replaced.push_str(&text.replace("``", "").replace("\\\n", "")); + } + } + // separator is required + replaced.push_str(" "); + + let (replaced, new_defines) = + preprocess_str(&replaced, path.as_ref(), &defines, include_paths)?; + return Ok(( + String::from(replaced.text()), + define.path.clone(), + *range, + new_defines, + )); + } else { + return Err(ErrorKind::DefineTextNotFound(String::from(id)).into()); + } + } else if let Some(_) = define { + return Err(ErrorKind::DefineTextNotFound(String::from(id)).into()); + } else { + return Err(ErrorKind::DefineNotFound(String::from(id)).into()); + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/sv-parser-syntaxtree/src/general/compiler_directives.rs b/sv-parser-syntaxtree/src/general/compiler_directives.rs index 9d5ab71..b9facdb 100644 --- a/sv-parser-syntaxtree/src/general/compiler_directives.rs +++ b/sv-parser-syntaxtree/src/general/compiler_directives.rs @@ -33,6 +33,7 @@ pub struct ResetallCompilerDirective { pub enum IncludeCompilerDirective { DoubleQuote(Box), AngleBracket(Box), + TextMacroUsage(Box), } #[derive(Clone, Debug, PartialEq, Node)] @@ -45,6 +46,11 @@ pub struct IncludeCompilerDirectiveAngleBracket { pub nodes: (Symbol, Keyword, AngleBracketLiteral), } +#[derive(Clone, Debug, PartialEq, Node)] +pub struct IncludeCompilerDirectiveTextMacroUsage { + pub nodes: (Symbol, Keyword, TextMacroUsage), +} + #[derive(Clone, Debug, PartialEq, Node)] pub struct AngleBracketLiteral { pub nodes: (Locate, Vec), @@ -101,7 +107,7 @@ pub struct ListOfActualArguments { #[derive(Clone, Debug, PartialEq, Node)] pub struct ActualArgument { - pub nodes: (Expression,), + pub nodes: (Locate,), } #[derive(Clone, Debug, PartialEq, Node)] diff --git a/sv-parser/examples/parse_sv.rs b/sv-parser/examples/parse_sv.rs index 931c336..7d62dbd 100644 --- a/sv-parser/examples/parse_sv.rs +++ b/sv-parser/examples/parse_sv.rs @@ -7,25 +7,32 @@ use sv_parser::parse_sv; struct Opt { pub files: Vec, - #[structopt(short = "I", long = "include", multiple = true, number_of_values = 1)] + /// Include path + #[structopt(short = "i", long = "include", multiple = true, number_of_values = 1)] pub includes: Vec, /// Show syntax tree #[structopt(short = "t", long = "tree")] pub tree: bool, + + /// Quiet + #[structopt(short = "q", long = "quiet")] + pub quiet: bool, } fn main() { let opt = Opt::from_args(); + let mut defines = HashMap::new(); for path in &opt.files { - let syntax_tree = parse_sv(&path, &HashMap::new(), &opt.includes); - - match syntax_tree { - Ok(x) => { + match parse_sv(&path, &defines, &opt.includes) { + Ok((syntax_tree, new_defines)) => { if opt.tree { - println!("{}", x); + println!("{}", syntax_tree); + } + defines = new_defines; + if !opt.quiet { + println!("parse succeeded: {:?}", path); } - println!("parse succeeded: {:?}", path); } Err(x) => { println!("parse failed: {:?} ({})", path, x); diff --git a/sv-parser/src/lib.rs b/sv-parser/src/lib.rs index 1c90c7b..6824725 100644 --- a/sv-parser/src/lib.rs +++ b/sv-parser/src/lib.rs @@ -6,7 +6,7 @@ use std::fmt; use std::path::Path; use sv_parser_error::{Error, ErrorKind}; use sv_parser_parser::{lib_parser, sv_parser, Span, SpanInfo}; -use sv_parser_pp::preprocess::{preprocess, Define, PreprocessedText}; +use sv_parser_pp::preprocess::{preprocess, Define, Defines, PreprocessedText}; pub use sv_parser_syntaxtree::*; pub struct SyntaxTree { @@ -67,15 +67,18 @@ pub fn parse_sv, U: AsRef>( path: T, pre_defines: &HashMap>, include_paths: &[U], -) -> Result { - let (text, _) = preprocess(path, pre_defines, include_paths)?; +) -> Result<(SyntaxTree, Defines), Error> { + let (text, defines) = preprocess(path, pre_defines, include_paths)?; let span = Span::new_extra(text.text(), SpanInfo::default()); let result = all_consuming(sv_parser)(span); match result { - Ok((_, x)) => Ok(SyntaxTree { - node: x.into(), - text, - }), + Ok((_, x)) => Ok(( + SyntaxTree { + node: x.into(), + text, + }, + defines, + )), Err(_) => Err(ErrorKind::Parse.into()), } } @@ -84,15 +87,18 @@ pub fn parse_lib, U: AsRef>( path: T, pre_defines: &HashMap>, include_paths: &[U], -) -> Result { - let (text, _) = preprocess(path, pre_defines, include_paths)?; +) -> Result<(SyntaxTree, Defines), Error> { + let (text, defines) = preprocess(path, pre_defines, include_paths)?; let span = Span::new_extra(text.text(), SpanInfo::default()); let result = all_consuming(lib_parser)(span); match result { - Ok((_, x)) => Ok(SyntaxTree { - node: x.into(), - text, - }), + Ok((_, x)) => Ok(( + SyntaxTree { + node: x.into(), + text, + }, + defines, + )), Err(_) => Err(ErrorKind::Parse.into()), } }