437 lines
14 KiB
Rust
437 lines
14 KiB
Rust
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, 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 }
|
||
}
|
||
}
|
||
|
||
#[derive(Debug, Clone, Serialize, PartialEq, 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)
|
||
}
|
||
|
||
/// 判断输入的 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
|
||
}
|
||
|
||
/// 对所有的 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
|
||
}
|
||
}
|
||
|
||
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
|
||
}
|
||
|
||
// #[derive(Debug, Serialize)]
|
||
// pub struct InstPort {
|
||
// pub name: String,
|
||
// pub range: Range
|
||
// }
|
||
|
||
// #[derive(Debug, Serialize)]
|
||
// pub struct InstParameter {
|
||
// pub name: String,
|
||
// pub value: String,
|
||
// pub range: Range
|
||
// }
|
||
|
||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||
pub struct Instance {
|
||
pub name: String,
|
||
#[serde(rename = "type")]
|
||
pub inst_type: String,
|
||
pub instparams: Option<Range>,
|
||
pub instports: Option<Range>,
|
||
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.end.line;
|
||
new_port_range.start.character = self.range.end.character + 1;
|
||
}
|
||
|
||
new_port_range.end.line += 1;
|
||
new_port_range.affine(-1, -1);
|
||
return new_port_range;
|
||
}
|
||
|
||
self.range.clone()
|
||
}
|
||
|
||
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.end.line;
|
||
new_param_range.start.character = self.range.end.character;
|
||
new_param_range.end.line += 1;
|
||
return new_param_range;
|
||
}
|
||
|
||
self.range.clone()
|
||
}
|
||
}
|
||
|
||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||
pub struct Module {
|
||
pub name: String,
|
||
pub params: Vec<Parameter>,
|
||
pub ports: Vec<Port>,
|
||
pub instances: Vec<Instance>,
|
||
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<DefineParam>
|
||
}
|
||
|
||
#[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<String>,
|
||
running_phase: Option<String>,
|
||
}
|
||
|
||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||
pub struct Macro {
|
||
pub defines: Vec<Define>,
|
||
pub includes: Vec<Include>,
|
||
pub errors: Vec<Error>,
|
||
pub invalid: Vec<Range>
|
||
}
|
||
|
||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||
#[serde(rename_all = "camelCase")]
|
||
pub struct FastHdlparam {
|
||
#[serde(rename = "macro")]
|
||
pub fast_macro: Macro,
|
||
pub content: Vec<Module>
|
||
}
|
||
|
||
impl FastHdlparam {
|
||
pub fn add_define(&mut self, name: &str, replacement: &str, start_line: u32, start_character: u32,
|
||
end_line: u32, end_character: u32, params: Vec<DefineParam>) {
|
||
let define = Define {
|
||
name: name.to_string(),
|
||
replacement: replacement.to_string(),
|
||
range: Range {
|
||
start: Position { line: start_line, character: start_character },
|
||
end: Position { line: end_line, character: end_character }
|
||
},
|
||
params
|
||
};
|
||
self.fast_macro.defines.push(define);
|
||
}
|
||
|
||
pub fn new_module(&mut self, name: &str, line: u32, character: u32, end_character: u32) {
|
||
let module = Module {
|
||
name: name.to_string(),
|
||
params: Vec::new(),
|
||
ports: Vec::new(),
|
||
instances: Vec::new(),
|
||
range: Range {
|
||
start: Position {
|
||
line, character
|
||
},
|
||
end: Position {
|
||
line, character: end_character
|
||
}
|
||
}
|
||
};
|
||
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,
|
||
start_line: u32, start_character: u32, end_line: u32, end_character: u32) {
|
||
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: Range {
|
||
start: Position {
|
||
line: start_line, character: start_character
|
||
},
|
||
end: Position {
|
||
line:end_line, character: end_character
|
||
}
|
||
}
|
||
};
|
||
last_module.params.push(parameter);
|
||
}
|
||
}
|
||
|
||
pub fn add_port(&mut self, name: &str, dir_type: &str, net_type: &str, width: &str,
|
||
start_line: u32, start_character: u32, end_line: u32, end_character: u32) {
|
||
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: Range {
|
||
start: Position {
|
||
line: start_line, character: start_character
|
||
},
|
||
end: Position {
|
||
line:end_line, character: end_character
|
||
}
|
||
}
|
||
};
|
||
last_module.ports.push(port);
|
||
last_module.ports.dedup();
|
||
}
|
||
}
|
||
|
||
pub fn add_instance(&mut self, name: &str, inst_type: &str, line: u32, character: u32, end_character: u32,
|
||
param_start_line: u32, param_start_character: u32, param_end_line: u32, param_end_character: u32,
|
||
port_start_line: u32, port_start_character: u32, port_end_line: u32, port_end_character: u32 ) {
|
||
if let Some(last_module) = self.content.last_mut() {
|
||
let instance = Instance {
|
||
name: name.to_string(),
|
||
inst_type: inst_type.to_string(),
|
||
instparams: if param_start_line == 0 {
|
||
None
|
||
} else {
|
||
Some(
|
||
Range {
|
||
start: Position {
|
||
line: param_start_line, character: param_start_character
|
||
},
|
||
end: Position {
|
||
line: param_end_line, character: param_end_character
|
||
}
|
||
}
|
||
)
|
||
},
|
||
instports: if port_start_line == 0 {
|
||
None
|
||
} else {
|
||
Some(
|
||
Range {
|
||
start: Position {
|
||
line: port_start_line, character: port_start_character
|
||
},
|
||
end: Position {
|
||
line: port_end_line, character: port_end_character
|
||
}
|
||
}
|
||
)
|
||
},
|
||
range: Range {
|
||
start: Position {
|
||
line, character
|
||
},
|
||
end: Position {
|
||
line, character: end_character
|
||
}
|
||
}
|
||
};
|
||
last_module.instances.push(instance);
|
||
}
|
||
}
|
||
}
|
||
|
||
pub struct HdlFile {
|
||
pub fast: FastHdlparam,
|
||
pub name_to_module: HashMap<String, Module>
|
||
}
|
||
|
||
pub struct HdlParam {
|
||
/// 路径到 HdlFile 的映射
|
||
pub path_to_hdl_file: RwLock<HashMap<String, HdlFile>>,
|
||
/// 模块名字到其所在的 HdlFile 路径的映射
|
||
pub module_name_to_path: RwLock<HashMap<String, String>>
|
||
}
|
||
|
||
impl HdlParam {
|
||
pub fn new() -> Self {
|
||
Self {
|
||
path_to_hdl_file: RwLock::new(HashMap::<String, HdlFile>::new()),
|
||
module_name_to_path: RwLock::new(HashMap::<String, String>::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::<String, Module>::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<Module> {
|
||
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
|
||
}
|
||
|
||
/// 输入 module 名字,找到 module 定义的文件的路径
|
||
pub fn find_module_definition_path(&self, module_name: &str) -> Option<String> {
|
||
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 下的所有 instance,并根据条件返回
|
||
pub fn walk_instantiation(&self, path_string: &str, condition: impl Fn(&Module, &Instance) -> bool) -> Option<Instance> {
|
||
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 机制
|
||
}
|
||
|
||
} |