修复 undef预编译错误
This commit is contained in:
parent
4a73dc87f7
commit
1e390e0f44
@ -1,6 +1,7 @@
|
||||
use std::path::PathBuf;
|
||||
use thiserror::Error;
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@ -30,14 +31,14 @@ pub enum Error {
|
||||
#[error("Preprocess error: {0:?}")]
|
||||
Preprocess(Option<(PathBuf, usize)>),
|
||||
|
||||
#[error("Define argument not found: {0}")]
|
||||
DefineArgNotFound(String),
|
||||
#[error("Define argument not found: {0:?}")]
|
||||
DefineArgNotFound(Option<(String, usize, usize)>),
|
||||
|
||||
#[error("Define not found: {0}")]
|
||||
DefineNotFound(String),
|
||||
|
||||
#[error("Define must have argument")]
|
||||
DefineNoArgs(String), // String is the macro identifier.
|
||||
DefineNoArgs(Option<(String, usize, usize)>), // String is the macro identifier.
|
||||
|
||||
#[error("Exceed recursive limit")]
|
||||
ExceedRecursiveLimit,
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::range::Range;
|
||||
use nom::combinator::all_consuming;
|
||||
use nom::Parser;
|
||||
use nom_greedyerror::error_position;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::convert::TryInto;
|
||||
@ -256,6 +257,9 @@ pub fn preprocess_str<T: AsRef<Path>, U: AsRef<Path>, V: BuildHasher>(
|
||||
defines.insert(k.clone(), (*v).clone());
|
||||
}
|
||||
|
||||
// let contain_a = defines.contains_key("a");
|
||||
// println!("defines contain a: {contain_a}");
|
||||
|
||||
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),
|
||||
@ -445,7 +449,20 @@ pub fn preprocess_str<T: AsRef<Path>, U: AsRef<Path>, V: BuildHasher>(
|
||||
NodeEvent::Enter(RefNode::UndefineCompilerDirective(x)) => {
|
||||
let (_, _, ref name) = x.nodes;
|
||||
let id = identifier((&name.nodes.0).into(), &s).unwrap();
|
||||
defines.remove(&id);
|
||||
// 确保填充 define 的唯一性
|
||||
let mut is_cover = false;
|
||||
if let Some(define_text) = defines.get(&id) {
|
||||
if let Some(define_text) = define_text {
|
||||
if define_text.text.is_some() && define_text.text.clone().unwrap().text == "dide-undefined" {
|
||||
is_cover = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !is_cover {
|
||||
defines.remove(&id);
|
||||
}
|
||||
// println!("remove id {id}");
|
||||
|
||||
let locate: Locate = x.try_into().unwrap();
|
||||
let range = Range::new(locate.offset, locate.offset + locate.len);
|
||||
@ -598,7 +615,20 @@ pub fn preprocess_str<T: AsRef<Path>, U: AsRef<Path>, V: BuildHasher>(
|
||||
text: define_text,
|
||||
};
|
||||
|
||||
defines.insert(id, Some(define));
|
||||
// 确保填充 define 的唯一性
|
||||
let mut is_cover = false;
|
||||
if let Some(define_text) = defines.get(&id) {
|
||||
if let Some(define_text) = define_text {
|
||||
if define_text.text.is_some() && define_text.text.clone().unwrap().text == "dide-undefined" {
|
||||
// println!("enter dide");
|
||||
is_cover = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !is_cover {
|
||||
defines.insert(id, Some(define));
|
||||
}
|
||||
}
|
||||
|
||||
// Keep TextMacroDefinition after preprocess_inner().
|
||||
@ -697,6 +727,7 @@ pub fn preprocess_str<T: AsRef<Path>, U: AsRef<Path>, V: BuildHasher>(
|
||||
},
|
||||
)?;
|
||||
defines = new_defines;
|
||||
// println!("[IncludeCompilerDirective] change defines, contain a : {}", defines.contains_key("a"));
|
||||
ret.merge(include);
|
||||
}
|
||||
NodeEvent::Enter(RefNode::TextMacroUsage(x)) => {
|
||||
@ -714,6 +745,7 @@ pub fn preprocess_str<T: AsRef<Path>, U: AsRef<Path>, V: BuildHasher>(
|
||||
)? {
|
||||
ret.push(&text, origin);
|
||||
defines = new_defines;
|
||||
// println!("[TextMacroUsage] change defines, contain a : {}", defines.contains_key("a"));
|
||||
}
|
||||
|
||||
// Push the trailing whitespace attached to either
|
||||
@ -795,6 +827,23 @@ fn identifier(node: RefNode, s: &str) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
fn get_locate(node: RefNode) -> Option<Locate> {
|
||||
for x in node {
|
||||
match x {
|
||||
RefNode::SimpleIdentifier(x) => {
|
||||
let x: Locate = x.nodes.0.try_into().unwrap();
|
||||
return Some(x);
|
||||
}
|
||||
RefNode::EscapedIdentifier(x) => {
|
||||
let x: Locate = x.nodes.0.try_into().unwrap();
|
||||
return Some(x);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_str(node: RefNode, s: &str) -> String {
|
||||
let mut ret = String::from("");
|
||||
for x in node {
|
||||
@ -945,128 +994,15 @@ fn resolve_text_macro_usage<T: AsRef<Path>, U: AsRef<Path>>(
|
||||
let mut arg_map = HashMap::new();
|
||||
|
||||
if !define.arguments.is_empty() && no_args {
|
||||
return Err(Error::DefineNoArgs(define.identifier.clone()));
|
||||
}
|
||||
|
||||
for (i, (arg, default)) in define.arguments.iter().enumerate() {
|
||||
let value = match actual_args.get(i) {
|
||||
Some(Some(actual_arg)) => *actual_arg,
|
||||
Some(None) => {
|
||||
if let Some(default) = default {
|
||||
default
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if let Some(default) = default {
|
||||
default
|
||||
} else {
|
||||
return Err(Error::DefineArgNotFound(String::from(arg)));
|
||||
}
|
||||
}
|
||||
};
|
||||
arg_map.insert(String::from(arg), value);
|
||||
}
|
||||
|
||||
// restore () for textmacro without arguments
|
||||
let paren = if define.arguments.is_empty() {
|
||||
Some(args_str)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(ref text) = define.text {
|
||||
let mut replaced = String::from("");
|
||||
for text in split_text(&text.text) {
|
||||
if let Some(value) = arg_map.get(&text) {
|
||||
replaced.push_str(*value);
|
||||
} else {
|
||||
replaced.push_str(
|
||||
&text
|
||||
.replace("``", "") // Argument substitution.
|
||||
.replace("`\\`\"", "\\\"") // Escaped backslash.
|
||||
.replace("`\"", "\"") // Escaped quote.
|
||||
.replace("\\\n", "\n") // Line continuation (Unix).
|
||||
.replace("\\\r\n", "\r\n") // Line continuation (Windows).
|
||||
.replace("\\\r", "\r"), // Line continuation (old Mac).
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(paren) = paren {
|
||||
replaced.push_str(&paren);
|
||||
}
|
||||
|
||||
let (replaced, new_defines) = preprocess_str(
|
||||
&replaced,
|
||||
path.as_ref(),
|
||||
&defines,
|
||||
include_paths,
|
||||
false,
|
||||
strip_comments,
|
||||
resolve_depth,
|
||||
0, // include_depth
|
||||
)?;
|
||||
Ok(Some((
|
||||
String::from(replaced.text()),
|
||||
text.origin.clone(),
|
||||
new_defines,
|
||||
)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else if define.is_some() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(Error::DefineNotFound(id))
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_text_macro_usage_retain_error<T: AsRef<Path>, U: AsRef<Path>>(
|
||||
x: &TextMacroUsage,
|
||||
s: &str,
|
||||
path: T,
|
||||
defines: &Defines,
|
||||
include_paths: &[U],
|
||||
strip_comments: bool,
|
||||
resolve_depth: usize,
|
||||
) -> Result<Option<(String, Option<(PathBuf, Range)>, Defines)>, Error> {
|
||||
let (_, ref name, ref args) = x.nodes;
|
||||
let id = identifier((&name.nodes.0).into(), &s).unwrap();
|
||||
|
||||
if resolve_depth > RECURSIVE_LIMIT {
|
||||
return Err(Error::ExceedRecursiveLimit);
|
||||
}
|
||||
|
||||
let mut args_str = String::from("");
|
||||
let mut actual_args = Vec::new();
|
||||
let no_args = args.is_none();
|
||||
if let Some(args) = args {
|
||||
args_str.push_str(&get_str((&args.nodes.0).into(), s));
|
||||
args_str.push_str(&get_str((&args.nodes.1).into(), s));
|
||||
args_str.push_str(&get_str((&args.nodes.2).into(), s));
|
||||
|
||||
let (_, ref args, _) = args.nodes;
|
||||
let (ref args,) = args.nodes;
|
||||
for arg in args.contents() {
|
||||
if let Some(arg) = arg {
|
||||
let (ref arg,) = arg.nodes;
|
||||
let arg = arg.str(&s).trim_end();
|
||||
actual_args.push(Some(arg));
|
||||
let locate = get_locate(sv_parser_syntaxtree::RefNode::TextMacroIdentifier(name));
|
||||
if let Some(locate) = locate {
|
||||
let start_byte_idx = locate.offset;
|
||||
let end_byte_idx = start_byte_idx + locate.len;
|
||||
return Err(Error::DefineNoArgs(Some((define.identifier.clone(), start_byte_idx, end_byte_idx))))
|
||||
} else {
|
||||
actual_args.push(None);
|
||||
return Err(Error::DefineNoArgs(None));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let define = defines.get(&id);
|
||||
if let Some(Some(define)) = define {
|
||||
let mut arg_map = HashMap::new();
|
||||
|
||||
if !define.arguments.is_empty() && no_args {
|
||||
return Err(Error::DefineNoArgs(define.identifier.clone()));
|
||||
}
|
||||
|
||||
for (i, (arg, default)) in define.arguments.iter().enumerate() {
|
||||
let value = match actual_args.get(i) {
|
||||
@ -1082,7 +1018,16 @@ fn resolve_text_macro_usage_retain_error<T: AsRef<Path>, U: AsRef<Path>>(
|
||||
if let Some(default) = default {
|
||||
default
|
||||
} else {
|
||||
return Err(Error::DefineArgNotFound(String::from(arg)));
|
||||
// 找到对应出错的宏调用,再返回
|
||||
let locate: Option<Locate> = get_locate(sv_parser_syntaxtree::RefNode::TextMacroIdentifier(name));
|
||||
if let Some(locate) = locate {
|
||||
let arg_name = arg.to_string();
|
||||
let start_byte_idx = locate.offset;
|
||||
let end_byte_idx = start_byte_idx + locate.len;
|
||||
return Err(Error::DefineArgNotFound(Some((arg_name, start_byte_idx, end_byte_idx))));
|
||||
} else {
|
||||
return Err(Error::DefineArgNotFound(None));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1143,7 +1088,6 @@ fn resolve_text_macro_usage_retain_error<T: AsRef<Path>, U: AsRef<Path>>(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -29,19 +29,19 @@ fn main() {
|
||||
|
||||
// Original string can be got by SyntexTree::get_str(self, node: &RefNode)
|
||||
let id = syntax_tree.get_str(&id).unwrap();
|
||||
println!("module: {}", id);
|
||||
// println!("module: {}", id);
|
||||
}
|
||||
RefNode::ModuleDeclarationAnsi(x) => {
|
||||
let id = unwrap_node!(x, ModuleIdentifier).unwrap();
|
||||
let id = get_identifier(id).unwrap();
|
||||
let id = syntax_tree.get_str(&id).unwrap();
|
||||
println!("module: {}", id);
|
||||
// println!("module: {}", id);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("Parse failed");
|
||||
// println!("Parse failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ fn main() {
|
||||
false, // ignore_include
|
||||
) {
|
||||
Ok((preprocessed_text, new_defines)) => {
|
||||
println!("{}", preprocessed_text.text());
|
||||
// println!("{}", preprocessed_text.text());
|
||||
defines = new_defines;
|
||||
}
|
||||
_ => (),
|
||||
@ -79,24 +79,24 @@ fn main() {
|
||||
match parse_sv(&path, &defines, &opt.includes, false, opt.incomplete) {
|
||||
Ok((syntax_tree, new_defines)) => {
|
||||
if opt.tree {
|
||||
println!("{}", syntax_tree);
|
||||
// println!("{}", syntax_tree);
|
||||
}
|
||||
defines = new_defines;
|
||||
if !opt.quiet {
|
||||
println!("parse succeeded: {:?}", path);
|
||||
// println!("parse succeeded: {:?}", path);
|
||||
}
|
||||
}
|
||||
Err(x) => {
|
||||
match x {
|
||||
Error::Parse(Some((origin_path, origin_pos))) => {
|
||||
println!("parse failed: {:?}", path);
|
||||
// println!("parse failed: {:?}", path);
|
||||
print_parse_error(&origin_path, &origin_pos);
|
||||
}
|
||||
x => {
|
||||
println!("parse failed: {:?} ({:?})", path, x);
|
||||
// println!("parse failed: {:?} ({:?})", path, x);
|
||||
let mut err = x.source();
|
||||
while let Some(x) = err {
|
||||
println!(" Caused by {}", x);
|
||||
// println!(" Caused by {}", x);
|
||||
err = x.source();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user