use std::collections::HashMap; use std::sync::RwLock; use log::info; use serde::{Deserialize, Serialize}; use tower_lsp::lsp_types::Position as LspPosition; use tower_lsp::lsp_types::Range as LspRange; #[derive(Debug, Clone, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize)] pub struct Position { pub line: u32, pub character: u32 } impl Position { #[allow(unused)] pub fn to_lsp_position(&self) -> LspPosition { LspPosition { line: self.line, character: self.character } } pub fn from_lsp_position(pos: &LspPosition) -> Position { Position { line: pos.line, character: pos.character } } pub fn new(line: u32, character: u32) -> Position { Position { line, character } } } #[derive(Debug, Clone, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize)] pub struct Range { pub start: Position, pub end: Position } impl Range { #[allow(unused)] pub fn to_lsp_range(&self) -> LspRange { let start_pos = self.start.to_lsp_position(); let end_pos= self.end.to_lsp_position(); LspRange::new(start_pos, end_pos) } #[allow(unused)] pub fn from_lsp_range(range: &LspRange) -> Range { Range { start: Position { line: range.start.line, character: range.start.character }, end: Position { line: range.end.line, character: range.end.character } } } /// 判断输入的 position 是否在当前 range 内 pub fn contains(&self, postion: &LspPosition) -> bool { compare_pos(&self.start.to_lsp_position(), postion) != 1 && compare_pos(postion, &self.end.to_lsp_position()) != 1 } #[allow(unused)] pub fn before(&self, range: &Range) -> bool { let current_pos = &self.end.to_lsp_position(); let target_pos = &range.start.to_lsp_position(); compare_pos(current_pos, target_pos) != 1 } #[allow(unused)] pub fn after(&self, range: &Range) -> bool { let current_pos = &self.start.to_lsp_position(); let target_pos = &range.end.to_lsp_position(); compare_pos(current_pos, target_pos) != -1 } /// 对所有的 line 或者 所有的 character 进行偏移操作 pub fn affine(&mut self, line_offset: i32, character_offset: i32) -> &Range { if line_offset > 0 { self.start.line += line_offset as u32; self.end.line += line_offset as u32; } else { self.start.line -= (- line_offset) as u32; self.end.line -= (- line_offset) as u32; } if character_offset > 0 { self.start.character += character_offset as u32; self.end.character += character_offset as u32; } else { self.start.character -= (- character_offset) as u32; self.end.character -= (- character_offset) as u32; } self } pub fn is_empty(&self) -> bool { self.start.line == 0 && self.start.character == 0 && self.end.line == 0 && self.end.character == 0 } pub fn to_option(&self) -> Option { if self.is_empty() { None } else { Some(self.clone()) } } pub fn default() -> Range { Range { start: Position::new(0, 0), end: Position::new(0, 0) } } } /// 比较两个 pos 的位置关系 /// 1:pos1 在 pos2 后面 /// 0:pos1 和 pos2 一样 /// -1:pos1 在 pos2 前面 fn compare_pos(pos1: &LspPosition, pos2: &LspPosition) -> i32 { if pos1.line > pos2.line { 1 } else if pos1.line < pos2.line { -1 } else if pos1.character > pos2.character { 1 } else if pos1.character < pos2.character { -1 } else { 0 } } #[derive(Debug, Serialize, PartialEq, Deserialize, Clone)] pub struct Port { pub name: String, #[serde(rename = "type")] pub dir_type: String, pub net_type: String, pub width: String, pub signed: String, pub range: Range } #[derive(Debug, Serialize, PartialEq, Deserialize, Clone)] pub struct Parameter { pub name: String, pub net_type: String, pub init: String, pub range: Range } impl Port { pub fn to_vlog_description(&self) -> String { let mut port_desc_array = Vec::::new(); let dir_type = match self.dir_type.as_str() { "in" => "input", "out" => "output", _ => &self.dir_type }; port_desc_array.push(dir_type.to_string()); if self.net_type != "unknown" { port_desc_array.push(self.net_type.to_string()); } if self.signed != "unsigned" { port_desc_array.push("signed".to_string()); } if self.width != "1" { port_desc_array.push(self.width.to_string()); } port_desc_array.push(self.name.to_string()); let port_desc = port_desc_array.join(" "); port_desc } pub fn to_vhdl_description(&self) -> String { let mut port_desc_array = Vec::::new(); port_desc_array.push(self.name.to_string()); port_desc_array.push(":".to_string()); port_desc_array.push(self.dir_type.to_string()); let width_string = self.width.replace("[", "(").replace("]", ")").replace(":", " downto "); port_desc_array.push(format!("{}{};", self.net_type.to_lowercase(), width_string)); let port_desc = port_desc_array.join(" "); port_desc } } impl Parameter { pub fn to_vlog_description(&self) -> String { let mut param_desc_array = Vec::::new(); param_desc_array.push(format!("parameter {}", self.name)); if self.init != "unknown" { param_desc_array.push("=".to_string()); param_desc_array.push(self.init.to_string()); } let param_desc = param_desc_array.join(" "); param_desc } pub fn to_vhdl_description(&self) -> String { let mut param_desc_array = Vec::::new(); param_desc_array.push(format!("{} : {}", self.name, self.net_type.to_lowercase())); if self.init != "unknown" { param_desc_array.push(format!(" := {}", self.init)); } let param_desc = param_desc_array.join(" "); param_desc } } #[derive(Debug, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize, Clone)] pub enum AssignType { Named, Ordered } #[derive(Debug, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize, Clone)] pub struct InstPort { pub port: Option, pub assign_val: Option, pub assign_type: AssignType, pub range: Range } #[derive(Debug, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize, Clone)] pub struct InstParameter { pub parameter: Option, pub assign_val: Option, pub assign_type: AssignType, pub range: Range } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Instance { pub name: String, #[serde(rename = "type")] pub inst_type: String, pub instparams: Option, pub intstparam_assignments: Vec, pub instports: Option, pub intstport_assignments: Vec, pub range: Range } impl Instance { pub fn gen_dot_completion_port_range(&self) -> Range { // TODO: 精心调制这个方法 if let Some(port_range) = &self.instports { let mut new_port_range = port_range.clone(); info!("get port range: {new_port_range:?}, instance: {self:?}"); if let Some(param_range) = &self.instparams { new_port_range.start.line = param_range.end.line - 1; new_port_range.start.character = param_range.end.character; } else { new_port_range.start.line = self.range.start.line; new_port_range.start.character = self.range.start.character + 1; } new_port_range.end.line += 1; new_port_range.affine(-1, -1); return new_port_range; } self.range.clone() } #[allow(unused)] pub fn gen_dot_completion_param_range(&self) -> Range { // TODO: 精心调制这个方法 if let Some(param_range) = &self.instparams { let mut new_param_range = param_range.clone(); new_param_range.start.line = self.range.start.line; new_param_range.start.character = self.range.start.character + 1; new_param_range.end.line += 1; return new_param_range; } self.range.clone() } } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Module { pub name: String, #[serde(rename = "archName")] pub arch_name: String, pub params: Vec, pub ports: Vec, pub instances: Vec, pub range: Range } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct DefineParam { pub name: String, pub value: String } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Define { pub name: String, pub replacement: String, pub range: Range, pub params: Vec } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Include { pub path: String, pub range: Range } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Error { severity: String, message: String, source: String, range: Position, running_mode: Option, running_phase: Option, } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Macro { pub defines: Vec, pub includes: Vec, pub errors: Vec, pub invalid: Vec } #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct FastHdlparam { #[serde(rename = "macro")] pub fast_macro: Macro, #[serde(rename = "fileType")] pub file_type: String, pub content: Vec } impl FastHdlparam { pub fn add_define(&mut self, name: &str, replacement: &str, range: Range, params: Vec) { let define = Define { name: name.to_string(), replacement: replacement.to_string(), range, params }; self.fast_macro.defines.push(define); } pub fn new_module(&mut self, name: &str, range: Range) { let module = Module { name: name.to_string(), arch_name: "".to_string(), params: Vec::new(), ports: Vec::new(), instances: Vec::new(), range }; self.content.push(module); } pub fn update_module_range(&mut self, name: &str, end_line: u32, end_character: u32) { if let Some(matched_module) = self.content.iter_mut().find(|module| module.name == name) { matched_module.range.end.line = end_line; matched_module.range.end.character = end_character; } } pub fn add_parameter(&mut self, name: &str, net_type: &str, init: &str, range: Range) { if let Some(last_module) = self.content.last_mut() { let parameter = Parameter { name: name.to_string(), net_type: net_type.to_string(), init: init.to_string(), range }; last_module.params.push(parameter); last_module.params.dedup(); } } pub fn add_port(&mut self, name: &str, dir_type: &str, net_type: &str, width: &str, range: Range) { if let Some(last_module) = self.content.last_mut() { let port = Port { name: name.to_string(), dir_type: dir_type.to_string(), net_type: net_type.to_string(), width: width.to_string(), signed: "unsigned".to_string(), range }; last_module.ports.push(port); last_module.ports.dedup(); } } pub fn add_instance(&mut self, name: &str, inst_type: &str, range: Range, param_range: Option, params_assign: Vec, port_range: Option, ports_assign: Vec) { if let Some(last_module) = self.content.last_mut() { let instance = Instance { name: name.to_string(), inst_type: inst_type.to_string(), instparams: param_range, intstparam_assignments: params_assign, instports: port_range, intstport_assignments: ports_assign, range }; last_module.instances.push(instance); } } } pub struct HdlFile { pub fast: FastHdlparam, pub name_to_module: HashMap } pub struct HdlParam { /// 路径到 HdlFile 的映射 pub path_to_hdl_file: RwLock>, /// 模块名字到其所在的 HdlFile 路径的映射 pub module_name_to_path: RwLock> } impl HdlParam { pub fn new() -> Self { Self { path_to_hdl_file: RwLock::new(HashMap::::new()), module_name_to_path: RwLock::new(HashMap::::new()) } } /// 根据 path 更新 fast pub fn update_fast(&self, path: String, fast: FastHdlparam) { let mut fast_map = self.path_to_hdl_file.write().unwrap(); // 构建映射 let mut name_to_module = HashMap::::new(); let mut module_name_to_path = self.module_name_to_path.write().unwrap(); for module in &fast.content { name_to_module.insert(module.name.to_string(), module.clone()); if !module_name_to_path.contains_key(&module.name) { module_name_to_path.insert(module.name.to_string(), path.to_string()); } } let file = HdlFile { fast, name_to_module }; fast_map.insert(path, file); } /// 根据 module 的名字,找到 module 对象,拷贝返回 pub fn find_module_by_name(&self, name: &str) -> Option { let module_name_to_path = self.module_name_to_path.read().unwrap(); if let Some(path) = module_name_to_path.get(name) { let fast_map = self.path_to_hdl_file.read().unwrap(); if let Some(hdl_file) = fast_map.get(path) { if let Some(module) = hdl_file.name_to_module.get(name) { return Some(module.clone()); } } } None } /// 相比于 find_module_by_name,该方法会返回更多有关 该 module 的必要上下文, /// 避免重复获取锁,提升性能 /// 返回三元组 (module, file_type, def_path) pub fn find_module_context_by_name(&self, name: &str) -> Option<(Module, String, String)> { // 获取 module_name_to_path 的读锁并查找路径 let module_name_to_path = self.module_name_to_path.read().unwrap(); if let Some(path) = module_name_to_path.get(name) { // 获取 path_to_hdl_file 的读锁并查找 HdlFile let fast_map = self.path_to_hdl_file.read().unwrap(); if let Some(hdl_file) = fast_map.get(path) { // 查找模块 if let Some(module) = hdl_file.name_to_module.get(name) { return Some(( module.clone(), hdl_file.fast.file_type.to_string(), path.to_string() )); } } } None } /// 根据 module name 计算出对应的 file type,默认为 common pub fn find_file_type_by_module_name(&self, module_name: &str) -> String { if let Some((_, file_type, _)) = self.find_module_context_by_name(module_name) { return file_type; } "common".to_string() } /// 输入 module 名字,找到 module 定义的文件的路径 pub fn find_module_definition_path(&self, module_name: &str) -> Option { let module_name_to_path = self.module_name_to_path.read().unwrap(); if let Some(path) = module_name_to_path.get(module_name) { return Some(path.to_string()); } None } /// 遍历 path_string 下的所有 module,并根据条件返回 pub fn walk_module(&self, path_string: &str, condition: impl Fn(&Module) -> bool) -> Option { let path_to_hdl_file = self.path_to_hdl_file.read().unwrap(); if let Some(hdl_file) = path_to_hdl_file.get(path_string) { for def_module in &hdl_file.fast.content { if condition(def_module) { return Some(def_module.clone()); } } } None } /// 遍历 path_string 下的所有 instance,并根据条件返回 pub fn walk_instantiation(&self, path_string: &str, condition: impl Fn(&Module, &Instance) -> bool) -> Option { let path_to_hdl_file = self.path_to_hdl_file.read().unwrap(); if let Some(hdl_file) = path_to_hdl_file.get(path_string) { for def_module in &hdl_file.fast.content { for inst in &def_module.instances { if condition(def_module, inst) { return Some(inst.clone()); } } } } None } /// 跟随一个路径进行删除 pub fn delete_file(&self, path_string: &str) { let mut path_to_hdl_file = self.path_to_hdl_file.write().unwrap(); if let Some(hdl_file) = path_to_hdl_file.get(path_string) { // 根据 hdl_file.fast.content 删除 self.module_name_to_path let mut module_name_to_path = self.module_name_to_path.write().unwrap(); for module_info in &hdl_file.fast.content { module_name_to_path.remove(&module_info.name); } } path_to_hdl_file.remove(path_string); // TODO: 引入前端的 solve unhandled instance 机制 } }