Refactor TextMacroUsage

This commit is contained in:
dalance 2019-09-18 17:31:06 +09:00
parent a6789b9752
commit 65abee8270
6 changed files with 173 additions and 77 deletions

View File

@ -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> {

View File

@ -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();
}

View File

@ -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::*;

View File

@ -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)]

View File

@ -7,25 +7,32 @@ 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);
}
println!("parse succeeded: {:?}", path);
}
Err(x) => {
println!("parse failed: {:?} ({})", path, x);

View File

@ -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 {
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<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 {
node: x.into(),
text,
}),
Ok((_, x)) => Ok((
SyntaxTree {
node: x.into(),
text,
},
defines,
)),
Err(_) => Err(ErrorKind::Parse.into()),
}
}