Refactor TextMacroUsage
This commit is contained in:
parent
a6789b9752
commit
65abee8270
@ -78,6 +78,7 @@ pub(crate) fn include_compiler_directive(s: Span) -> IResult<Span, IncludeCompil
|
||||
alt((
|
||||
include_compiler_directive_double_quote,
|
||||
include_compiler_directive_angle_bracket,
|
||||
include_compiler_directive_text_macro_usage,
|
||||
))(s)
|
||||
}
|
||||
|
||||
@ -113,6 +114,22 @@ pub(crate) fn include_compiler_directive_angle_bracket(
|
||||
))
|
||||
}
|
||||
|
||||
#[tracable_parser]
|
||||
#[packrat_parser]
|
||||
pub(crate) fn include_compiler_directive_text_macro_usage(
|
||||
s: Span,
|
||||
) -> IResult<Span, IncludeCompilerDirective> {
|
||||
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<Span, AngleBracketLiteral> {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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<String, Option<Define>>;
|
||||
pub type Defines = HashMap<String, Option<Define>>;
|
||||
|
||||
pub fn preprocess<T: AsRef<Path>, U: AsRef<Path>>(
|
||||
path: T,
|
||||
@ -89,6 +89,15 @@ pub fn preprocess<T: AsRef<Path>, U: AsRef<Path>>(
|
||||
let mut s = String::new();
|
||||
reader.read_to_string(&mut s)?;
|
||||
|
||||
preprocess_str(&s, path, pre_defines, include_paths)
|
||||
}
|
||||
|
||||
fn preprocess_str<T: AsRef<Path>, U: AsRef<Path>>(
|
||||
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<T: AsRef<Path>, U: AsRef<Path>>(
|
||||
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<T: AsRef<Path>, U: AsRef<Path>>(
|
||||
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<String> {
|
||||
|
||||
x.push(c);
|
||||
}
|
||||
ret.push(x);
|
||||
ret
|
||||
}
|
||||
|
||||
fn resolve_text_macro_usage<T: AsRef<Path>, U: AsRef<Path>>(
|
||||
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::*;
|
||||
|
@ -33,6 +33,7 @@ pub struct ResetallCompilerDirective {
|
||||
pub enum IncludeCompilerDirective {
|
||||
DoubleQuote(Box<IncludeCompilerDirectiveDoubleQuote>),
|
||||
AngleBracket(Box<IncludeCompilerDirectiveAngleBracket>),
|
||||
TextMacroUsage(Box<IncludeCompilerDirectiveTextMacroUsage>),
|
||||
}
|
||||
|
||||
#[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<WhiteSpace>),
|
||||
@ -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)]
|
||||
|
@ -7,26 +7,33 @@ use sv_parser::parse_sv;
|
||||
struct Opt {
|
||||
pub files: Vec<PathBuf>,
|
||||
|
||||
#[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<PathBuf>,
|
||||
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
Err(x) => {
|
||||
println!("parse failed: {:?} ({})", path, x);
|
||||
}
|
||||
|
@ -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<T: AsRef<Path>, U: AsRef<Path>>(
|
||||
path: T,
|
||||
pre_defines: &HashMap<String, Option<Define>>,
|
||||
include_paths: &[U],
|
||||
) -> Result<SyntaxTree, Error> {
|
||||
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 {
|
||||
Ok((_, x)) => Ok((
|
||||
SyntaxTree {
|
||||
node: x.into(),
|
||||
text,
|
||||
}),
|
||||
},
|
||||
defines,
|
||||
)),
|
||||
Err(_) => Err(ErrorKind::Parse.into()),
|
||||
}
|
||||
}
|
||||
@ -84,15 +87,18 @@ pub fn parse_lib<T: AsRef<Path>, U: AsRef<Path>>(
|
||||
path: T,
|
||||
pre_defines: &HashMap<String, Option<Define>>,
|
||||
include_paths: &[U],
|
||||
) -> Result<SyntaxTree, Error> {
|
||||
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 {
|
||||
Ok((_, x)) => Ok((
|
||||
SyntaxTree {
|
||||
node: x.into(),
|
||||
text,
|
||||
}),
|
||||
},
|
||||
defines,
|
||||
)),
|
||||
Err(_) => Err(ErrorKind::Parse.into()),
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user