ppTests Allow define __FILE__ and define __LINE__ to parse.

- Redefinitions are silently ignored.
- ifdef/ifndef will always treat them as defined.
- Enables compatibility with code from a silicon vendor I can think of.
- NOTE: Whitespace bugs around endif/undef are observable in testcases.
This commit is contained in:
damc 2022-07-25 22:21:28 +02:00
parent f85809f55a
commit 963e17a5ea
2 changed files with 53 additions and 42 deletions

View File

@ -1446,8 +1446,6 @@ pub(crate) const KEYWORDS_1800_2017: &[&str] = &[
]; ];
pub(crate) const KEYWORDS_DIRECTIVE: &[&str] = &[ pub(crate) const KEYWORDS_DIRECTIVE: &[&str] = &[
"__FILE__",
"__LINE__",
"begin_keywords", "begin_keywords",
"celldefine", "celldefine",
"default_nettype", "default_nettype",

View File

@ -399,7 +399,7 @@ pub fn preprocess_str<T: AsRef<Path>, U: AsRef<Path>, V: BuildHasher>(
let ifid = identifier(ifid.into(), &s).unwrap(); let ifid = identifier(ifid.into(), &s).unwrap();
let mut hit = false; let mut hit = false;
if defines.contains_key(&ifid) { if defines.contains_key(&ifid) || is_predefined_text_macro(&ifid) {
hit = true; hit = true;
} else { } else {
skip_nodes.push(ifbody.into()); skip_nodes.push(ifbody.into());
@ -413,7 +413,7 @@ pub fn preprocess_str<T: AsRef<Path>, U: AsRef<Path>, V: BuildHasher>(
let elsifid = identifier(elsifid.into(), &s).unwrap(); let elsifid = identifier(elsifid.into(), &s).unwrap();
if hit { if hit {
skip_nodes.push(elsifbody.into()); skip_nodes.push(elsifbody.into());
} else if defines.contains_key(&elsifid) { } else if defines.contains_key(&elsifid) || is_predefined_text_macro(&ifid) {
hit = true; hit = true;
} else { } else {
skip_nodes.push(elsifbody.into()); skip_nodes.push(elsifbody.into());
@ -447,7 +447,7 @@ pub fn preprocess_str<T: AsRef<Path>, U: AsRef<Path>, V: BuildHasher>(
let ifid = identifier(ifid.into(), &s).unwrap(); let ifid = identifier(ifid.into(), &s).unwrap();
let mut hit = false; let mut hit = false;
if !defines.contains_key(&ifid) { if !defines.contains_key(&ifid) && !is_predefined_text_macro(&ifid) {
hit = true; hit = true;
} else { } else {
skip_nodes.push(ifbody.into()); skip_nodes.push(ifbody.into());
@ -461,7 +461,7 @@ pub fn preprocess_str<T: AsRef<Path>, U: AsRef<Path>, V: BuildHasher>(
let elsifid = identifier(elsifid.into(), &s).unwrap(); let elsifid = identifier(elsifid.into(), &s).unwrap();
if hit { if hit {
skip_nodes.push(elsifbody.into()); skip_nodes.push(elsifbody.into());
} else if defines.contains_key(&elsifid) { } else if defines.contains_key(&elsifid) || is_predefined_text_macro(&ifid) {
hit = true; hit = true;
} else { } else {
skip_nodes.push(elsifbody.into()); skip_nodes.push(elsifbody.into());
@ -484,47 +484,49 @@ pub fn preprocess_str<T: AsRef<Path>, U: AsRef<Path>, V: BuildHasher>(
let (ref name, ref args) = proto.nodes; let (ref name, ref args) = proto.nodes;
let id = identifier(name.into(), &s).unwrap(); let id = identifier(name.into(), &s).unwrap();
let mut define_args = Vec::new(); if !is_predefined_text_macro(id.as_str()) {
if let Some(args) = args { let mut define_args = Vec::new();
let (_, ref args, _) = args.nodes; if let Some(args) = args {
let (ref args,) = args.nodes; let (_, ref args, _) = args.nodes;
for arg in args.contents() { let (ref args,) = args.nodes;
let (ref arg, ref default) = arg.nodes; for arg in args.contents() {
let (ref arg, _) = arg.nodes; let (ref arg, ref default) = arg.nodes;
let arg = String::from(arg.str(&s)); let (ref arg, _) = arg.nodes;
let arg = String::from(arg.str(&s));
let default = if let Some((_, x)) = default { let default = if let Some((_, x)) = default {
let x: Locate = x.try_into().unwrap(); let x: Locate = x.try_into().unwrap();
let x = String::from(x.str(&s)); let x = String::from(x.str(&s));
Some(x) Some(x)
} else { } else {
None None
}; };
define_args.push((arg, default)); define_args.push((arg, default));
}
} }
let define_text = if let Some(text) = text {
let text: Locate = text.try_into().unwrap();
let range = Range::new(text.offset, text.offset + text.len);
let text = String::from(text.str(&s));
Some(DefineText {
text,
origin: Some((PathBuf::from(path.as_ref()), range)),
})
} else {
None
};
let define = Define {
identifier: id.clone(),
arguments: define_args,
text: define_text,
};
defines.insert(id, Some(define));
} }
let define_text = if let Some(text) = text {
let text: Locate = text.try_into().unwrap();
let range = Range::new(text.offset, text.offset + text.len);
let text = String::from(text.str(&s));
Some(DefineText {
text,
origin: Some((PathBuf::from(path.as_ref()), range)),
})
} else {
None
};
let define = Define {
identifier: id.clone(),
arguments: define_args,
text: define_text,
};
defines.insert(id, Some(define));
// Keep TextMacroDefinition after preprocess // Keep TextMacroDefinition after preprocess
let locate: Locate = x.try_into().unwrap(); let locate: Locate = x.try_into().unwrap();
let range = Range::new(locate.offset, locate.offset + locate.len); let range = Range::new(locate.offset, locate.offset + locate.len);
@ -708,6 +710,17 @@ fn get_str(node: RefNode, s: &str) -> String {
ret ret
} }
fn is_predefined_text_macro(s: &str) -> bool {
match s {
"__LINE__" | "__FILE__" => {
true
}
_ => {
false
}
}
}
fn split_text(s: &str) -> Vec<String> { fn split_text(s: &str) -> Vec<String> {
let mut is_string = false; let mut is_string = false;
let mut is_ident = false; let mut is_ident = false;