I have a situation where I want capture compiler directives in a SystemVerilog file. Be it an include orifdef. Currently, I haven't found a clean way to do it. Here is what I tried, which I've taken mostly from existing code:
pub fn get_preprocessor_text<V: BuildHasher>(
path: PathBuf,
pre_defines: &Defines<V>,
) -> Result<(PreprocessorText, String), Error> {
let f = File::open(path.clone()).map_err(|x| Error::File {
source: x,
path: path.clone(),
})?;
let mut reader = BufReader::new(f);
let mut s = String::new();
if let Err(_) = reader.read_to_string(&mut s) {
return Err(Error::ReadUtf8(path));
}
let mut defines = HashMap::new();
let sv_cov_pre_defines = [
("SV_COV_START", "0"),
("SV_COV_STOP", "1"),
("SV_COV_RESET", "2"),
("SV_COV_CHECK", "3"),
("SV_COV_MODULE", "10"),
("SV_COV_HIER", "11"),
("SV_COV_ASSERTION", "20"),
("SV_COV_FSM_STATE", "21"),
("SV_COV_STATEMENT", "22"),
("SV_COV_TOGGLE", "23"),
("SV_COV_OVERFLOW", "-2"),
("SV_COV_ERROR", "-1"),
("SV_COV_NOCOV", "0"),
("SV_COV_OK", "1"),
("SV_COV_PARTIAL", "2"),
];
for (k, v) in sv_cov_pre_defines {
let define = Define {
identifier: k.to_string(),
arguments: Vec::new(),
text: Some(DefineText {
text: v.to_string(),
origin: None,
}),
};
defines.insert(k.to_string(), Some(define));
}
for (k, v) in pre_defines {
defines.insert(k.clone(), (*v).clone());
}
let span = Span::new_extra(&s, SpanInfo::default());
let (_, pp_text) = all_consuming(pp_parser)(span).map_err(|x| match x {
nom::Err::Incomplete(_) => Error::Preprocess(None),
nom::Err::Error(e) => {
if let Some(pos) = error_position(&e) {
Error::Preprocess(Some((path, pos)))
} else {
Error::Preprocess(None)
}
}
nom::Err::Failure(e) => {
if let Some(pos) = error_position(&e) {
Error::Preprocess(Some((path, pos)))
} else {
Error::Preprocess(None)
}
}
})?;
Ok((pp_text, s))
}
fn identifier(node: RefNode, s: &str) -> Option<String> {
for x in node {
match x {
RefNode::SimpleIdentifier(x) => {
let x: Locate = x.nodes.0.try_into().unwrap();
return Some(String::from(x.str(s)));
}
RefNode::EscapedIdentifier(x) => {
let x: Locate = x.nodes.0.try_into().unwrap();
let x = x.str(s);
let x = &x[1..]; // remove \
return Some(String::from(x));
}
_ => (),
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_conditional_compiler_directives() {
let path = "some_system_verilog_file_with_conditional_compiliation.sv";
let (preprocessor_text, s) = get_preprocessor_text(path.into(), &HashMap::new()).unwrap();
let mut conditional_compiler_directives = vec![];
for n in preprocessor_text.into_iter().event() {
match n {
NodeEvent::Enter(RefNode::IfdefDirective(x)) => {
let (_, _, ref ifid, _, _, _, _, _) = x.nodes;
let ifid = identifier(ifid.into(), &s).unwrap();
conditional_compiler_directives.push(ifid);
}
NodeEvent::Enter(RefNode::IfndefDirective(x)) => {
let (_, _, ref ifid, _, _, _, _, _) = x.nodes;
let ifid = identifier(ifid.into(), &s).unwrap();
conditional_compiler_directives.push(ifid);
}
_ => (),
}
}
assert!(conditional_compiler_directives.contains(&"MY_DEFINE".to_string()));
assert!(conditional_compiler_directives.contains(&"MY_DEFINED".to_string()));
assert!(conditional_compiler_directives.contains(&"MY_DEFINE_WITH_VALUE".to_string()));
}
}
This works alright, but it requires me to bring nom into the client code, which I am hesitant about. I was wondering if there is a better way to do this, or are their any plans to do it in the future?
Hi,
First of, thank you for the amazing work.
I have a situation where I want capture compiler directives in a SystemVerilog file. Be it an
include or
ifdef. Currently, I haven't found a clean way to do it. Here is what I tried, which I've taken mostly from existing code:This works alright, but it requires me to bring nom into the client code, which I am hesitant about. I was wondering if there is a better way to do this, or are their any plans to do it in the future?