解决 macro 定义不存在解析失败的问题

This commit is contained in:
锦恢 2024-09-25 20:50:01 +08:00
parent ca272a67b8
commit c8ae0f78a4
4 changed files with 74 additions and 10 deletions

View File

@ -22,10 +22,15 @@ impl LSPServer {
self.srcs.wait_parse_ready(file_id, false); self.srcs.wait_parse_ready(file_id, false);
let file = self.srcs.get_file(file_id)?; let file = self.srcs.get_file(file_id)?;
let file = file.read().ok()?; let file = file.read().ok()?;
let token: String = get_definition_token(file.text.line(pos.line as usize), pos);
let line_text = file.text.line(pos.line as usize);
let token: String = get_definition_token(&line_text, pos);
info!("definition token: {:?}", token); info!("definition token: {:?}", token);
let scope_tree = self.srcs.scope_tree.read().ok()?; let scope_tree = self.srcs.scope_tree.read().ok()?;
let def = scope_tree let def = scope_tree
@ -47,7 +52,9 @@ impl LSPServer {
self.srcs.wait_parse_ready(file_id, false); self.srcs.wait_parse_ready(file_id, false);
let file: std::sync::Arc<std::sync::RwLock<crate::sources::Source>> = self.srcs.get_file(file_id)?; let file: std::sync::Arc<std::sync::RwLock<crate::sources::Source>> = self.srcs.get_file(file_id)?;
let file: std::sync::RwLockReadGuard<'_, crate::sources::Source> = file.read().ok()?; let file: std::sync::RwLockReadGuard<'_, crate::sources::Source> = file.read().ok()?;
let token: String = get_definition_token(file.text.line(pos.line as usize), pos);
let line_text = file.text.line(pos.line as usize);
let token: String = get_definition_token(&line_text, pos);
let scope_tree: std::sync::RwLockReadGuard<'_, Option<GenericScope>> = self.srcs.scope_tree.read().ok()?; let scope_tree: std::sync::RwLockReadGuard<'_, Option<GenericScope>> = self.srcs.scope_tree.read().ok()?;
@ -89,7 +96,9 @@ impl LSPServer {
self.srcs.wait_parse_ready(file_id, false); self.srcs.wait_parse_ready(file_id, false);
let file = self.srcs.get_file(file_id)?; let file = self.srcs.get_file(file_id)?;
let file = file.read().ok()?; let file = file.read().ok()?;
let token = get_definition_token(file.text.line(pos.line as usize), pos);
let line_text = file.text.line(pos.line as usize);
let token = get_definition_token(&line_text, pos);
let scope_tree = self.srcs.scope_tree.read().ok()?; let scope_tree = self.srcs.scope_tree.read().ok()?;
// use the byte_idx of the definition if possible, otherwise use the cursor // use the byte_idx of the definition if possible, otherwise use the cursor
let byte_idx = let byte_idx =
@ -125,7 +134,7 @@ fn all_identifiers(syntax_tree: &SyntaxTree, token: &str) -> Vec<(String, usize)
} }
/// retrieve the token the user invoked goto definition or hover on /// retrieve the token the user invoked goto definition or hover on
fn get_definition_token(line: RopeSlice, pos: Position) -> String { fn get_definition_token(line: &RopeSlice, pos: Position) -> String {
let mut token = String::new(); let mut token = String::new();
let mut line_iter = line.chars(); let mut line_iter = line.chars();
for _ in 0..(line.utf16_cu_to_char(pos.character as usize)) { for _ in 0..(line.utf16_cu_to_char(pos.character as usize)) {
@ -387,7 +396,8 @@ mod tests {
fn test_definition_token() { fn test_definition_token() {
test_init(); test_init();
let line = Rope::from_str("assign ab_c[2:0] = 3'b000;"); let line = Rope::from_str("assign ab_c[2:0] = 3'b000;");
let token = get_definition_token(line.line(0), Position::new(0, 10)); let line_text = line.line(0);
let token = get_definition_token(&line_text, Position::new(0, 10));
assert_eq!(token, "ab_c".to_owned()); assert_eq!(token, "ab_c".to_owned());
} }
@ -402,7 +412,8 @@ mod tests {
let syntax_tree = parse(&doc, &url, &None, &Vec::new()).unwrap(); let syntax_tree = parse(&doc, &url, &None, &Vec::new()).unwrap();
let scope_tree = get_scopes(&syntax_tree, &url).unwrap(); let scope_tree = get_scopes(&syntax_tree, &url).unwrap();
let token = get_definition_token(doc.line(3), Position::new(3, 13)); let line_text = doc.line(3);
let token = get_definition_token(&line_text, Position::new(3, 13));
for def in scope_tree.defs { for def in scope_tree.defs {
if token == def.ident() { if token == def.ident() {
assert_eq!(doc.byte_to_pos(def.byte_idx()), Position::new(3, 9)) assert_eq!(doc.byte_to_pos(def.byte_idx()), Position::new(3, 9))

View File

@ -0,0 +1,3 @@
pub fn goto_include_definition() {
}

View File

@ -239,6 +239,8 @@ impl Sources {
let range = &file.last_change_range.clone(); let range = &file.last_change_range.clone();
drop(file); drop(file);
info!("do parse in {:?}", uri.to_string());
let syntax_tree = parse(&text, uri, range, &inc_dirs.read().unwrap()); let syntax_tree = parse(&text, uri, range, &inc_dirs.read().unwrap());
let mut scope_tree = match &syntax_tree { let mut scope_tree = match &syntax_tree {
Some(tree) => get_scopes(tree, uri), Some(tree) => get_scopes(tree, uri),
@ -295,6 +297,8 @@ impl Sources {
// eprintln!("{:#?}", *global_scope); // eprintln!("{:#?}", *global_scope);
drop(global_scope); drop(global_scope);
// 通过条件锁进行控制
let mut valid = lock.lock().unwrap(); let mut valid = lock.lock().unwrap();
*valid = true; *valid = true;
cvar.notify_all(); cvar.notify_all();
@ -409,6 +413,7 @@ pub fn parse(
let mut parse_iterations = 1; let mut parse_iterations = 1;
let mut i = 0; let mut i = 0;
let mut includes: Vec<PathBuf> = inc_paths.to_vec(); let mut includes: Vec<PathBuf> = inc_paths.to_vec();
let mut defines = HashMap::new();
let mut reverted_change = false; let mut reverted_change = false;
let mut text = doc.clone(); let mut text = doc.clone();
@ -417,7 +422,7 @@ pub fn parse(
match parse_sv_str( match parse_sv_str(
&text.to_string(), &text.to_string(),
uri.to_file_path().unwrap(), uri.to_file_path().unwrap(),
&HashMap::new(), &defines,
&includes, &includes,
true, true,
true true
@ -427,7 +432,7 @@ pub fn parse(
} }
Err(err) => { Err(err) => {
match err { match err {
// syntax error // 语法错误
sv_parser::Error::Parse(trace) => match trace { sv_parser::Error::Parse(trace) => match trace {
Some((_, bpos)) => { Some((_, bpos)) => {
let mut line_start = text.byte_to_line(bpos); let mut line_start = text.byte_to_line(bpos);
@ -450,8 +455,8 @@ pub fn parse(
} }
None => return None, None => return None,
}, },
// include error, take the include path from the error message and
// add it as an include dir for the next parser invocation // 遇到 include 错误,那就把提示中的 include 加入解析中再次解析
sv_parser::Error::Include { source: x } => { sv_parser::Error::Include { source: x } => {
if let sv_parser::Error::File { source: _, path: z } = *x { if let sv_parser::Error::File { source: _, path: z } = *x {
// Include paths have to be relative to the working directory // Include paths have to be relative to the working directory
@ -472,6 +477,17 @@ pub fn parse(
parse_iterations += 1; parse_iterations += 1;
} }
} }
// 宏定义不存在的错误
sv_parser::Error::DefineNotFound(not_found_macro_name) => {
let com_define = Define {
identifier: not_found_macro_name.to_string(),
arguments: Vec::new(),
text: Some(DefineText {text: "undefined".to_string(), origin: None})
};
defines.insert(not_found_macro_name, Some(com_define));
parse_iterations += 1;
}
_ => error!("parse error, {:?}", err), _ => error!("parse error, {:?}", err),
}; };
} }

View File

@ -99,6 +99,40 @@ mod test_fast {
} }
} }
#[cfg(test)]
mod test_svparse {
use std::{fs, path::PathBuf};
use ropey::Rope;
use tower_lsp::lsp_types::Url;
use crate::sources::parse;
#[test]
fn test_mycpu() {
let includes: Vec<PathBuf> = Vec::new();
let path = "/home/dide/project/Digital-Test/MipsDesign/src/MyCpu.v";
let text = match fs::read_to_string(path) {
Ok(text) => text,
Err(_) => return
};
let doc = Rope::from_str(&text);
let uri = Url::from_file_path(&path).unwrap();
let result = parse(&doc, &uri, &None, &includes);
match result {
Some(syntax_tree) => {
println!("success");
},
None => {
eprintln!("gen None");
}
}
}
}
#[cfg(test)] #[cfg(test)]
mod test_scope_tree { mod test_scope_tree {
use std::{collections::HashMap, fs, path::{Path, PathBuf}}; use std::{collections::HashMap, fs, path::{Path, PathBuf}};