568 lines
18 KiB
Rust
568 lines
18 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, 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<Range> {
|
||
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::<String>::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::<String>::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::<String>::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::<String>::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<String>,
|
||
pub assign_val: Option<String>,
|
||
pub assign_type: AssignType,
|
||
pub range: Range
|
||
}
|
||
|
||
#[derive(Debug, Serialize, PartialEq, PartialOrd, Eq, Ord, Deserialize, Clone)]
|
||
pub struct InstParameter {
|
||
pub parameter: Option<String>,
|
||
pub assign_val: Option<String>,
|
||
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<Range>,
|
||
pub intstparam_assignments: Vec<InstParameter>,
|
||
pub instports: Option<Range>,
|
||
pub intstport_assignments: Vec<InstPort>,
|
||
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<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,
|
||
#[serde(rename = "fileType")]
|
||
pub file_type: String,
|
||
pub content: Vec<Module>
|
||
}
|
||
|
||
impl FastHdlparam {
|
||
pub fn add_define(&mut self, name: &str, replacement: &str, range: Range, params: Vec<DefineParam>) {
|
||
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<Range>, params_assign: Vec<InstParameter>, port_range: Option<Range>, ports_assign: Vec<InstPort>) {
|
||
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<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
|
||
}
|
||
|
||
/// 相比于 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<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 下的所有 module,并根据条件返回
|
||
pub fn walk_module(&self, path_string: &str, condition: impl Fn(&Module) -> bool) -> Option<Module> {
|
||
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<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 机制
|
||
}
|
||
|
||
} |