完成前后端对接 | 完成 sv_parser 单元测试

This commit is contained in:
锦恢 2024-09-22 21:20:08 +08:00
parent ebc6e79cf0
commit 759c05f048
16 changed files with 452 additions and 35 deletions

View File

@ -511,3 +511,47 @@ fn get_column_by_offset(content: &[String], offset: usize) -> usize {
1 // if offset over the file lentghreturn 1
}
#[cfg(test)]
mod tests {
use std::fs;
use std::path::Path;
use super::sv_parser;
const testfiles_dir: &str = "testfiles";
macro_rules! unwrap_result {
($expr:expr) => {
match $expr {
Ok(e) => e,
Err(_) => return
}
};
}
macro_rules! unwrap_option {
($expr:expr) => {
match $expr {
Some(e) => e,
None => return
}
};
}
#[test]
fn test_sv_parse() {
let entries = unwrap_result!(fs::read_dir(testfiles_dir));
for entry in entries {
let entry = unwrap_result!(entry);
let file_path = entry.path();
if file_path.is_file() {
let extension = unwrap_option!(file_path.extension());
let file_path = unwrap_option!(file_path.to_str());
if extension == "v" || extension == "sv" {
let _ = sv_parser(file_path);
}
}
}
}
}

View File

@ -1,26 +1,20 @@
use std::future;
use std::{fs, future};
use std::path::PathBuf;
use std::sync::Arc;
use log::info;
use ropey::Rope;
use serde::Deserialize;
use serde_json::Value;
use serde::{Deserialize, Serialize};
use tower_lsp::jsonrpc::Result;
use tower_lsp::lsp_types::*;
use tower_lsp::{lsp_types::*, LanguageServer};
use crate::core::fast_hdlparam::FastHdlparam;
use crate::core::sv_parser::make_fast_from_syntaxtree;
use crate::definition::get_language_id_by_uri;
use crate::server::Backend;
use crate::sources::parse;
#[derive(Debug, Deserialize)]
pub struct CustomRequestParams {
// 定义你需要的参数
pub data: Value,
}
#[derive(Clone)]
pub struct CustomRequest;
@ -37,24 +31,77 @@ pub fn custom_request() -> Result<i32> {
Ok(123)
}
#[derive(Deserialize, Serialize, Debug)]
pub struct CustomParamRequestParams {
param: String,
}
#[derive(Clone)]
pub struct CustomParamRequest;
impl <'a>tower_lsp::jsonrpc::Method<&'a Arc<Backend>, (CustomParamRequestParams, ), Result<i32>> for CustomParamRequest {
type Future = future::Ready<Result<i32>>;
fn invoke(&self, _server: &'a Arc<Backend>, _params: (CustomParamRequestParams, )) -> Self::Future {
future::ready(custom_param_request(_params.0.param))
}
}
pub fn custom_param_request(param: String) -> Result<i32> {
info!("receive param: {:?}", param);
Ok(123)
}
#[derive(Deserialize, Serialize, Debug)]
pub struct DoFastApiRequestParams {
path: String,
}
#[derive(Clone)]
pub struct DoFastApi;
impl <'a>tower_lsp::jsonrpc::Method<&'a Arc<Backend>, (TextDocumentItem, ), Result<FastHdlparam>> for DoFastApi {
impl <'a>tower_lsp::jsonrpc::Method<&'a Arc<Backend>, (DoFastApiRequestParams, ), Result<FastHdlparam>> for DoFastApi {
type Future = future::Ready<Result<FastHdlparam>>;
fn invoke(&self, _server: &'a Arc<Backend>, _params: (TextDocumentItem, )) -> Self::Future {
let doc = _params.0;
future::ready(do_fast(doc))
fn invoke(&self, _server: &'a Arc<Backend>, _params: (DoFastApiRequestParams, )) -> Self::Future {
let request_param = _params.0;
let path = request_param.path;
future::ready(do_fast(path))
}
}
fn make_textdocumenitem_from_path(path_buf: &PathBuf) -> Option<TextDocumentItem> {
if let Ok(url) = Url::from_file_path(path_buf) {
if let Ok(text) = fs::read_to_string(path_buf) {
let language_id = get_language_id_by_uri(&url);
return Some(TextDocumentItem::new(url, language_id, -1, text));
}
}
None
}
/// 前端交互接口: do_fast输入文件路径计算出对应的 fast 结构
pub fn do_fast(doc: TextDocumentItem) -> Result<FastHdlparam> {
info!("lsp get doc: {:?}", doc);
pub fn do_fast(path: String) -> Result<FastHdlparam> {
info!("parse hdl path: {:?}", path);
let path_buf = PathBuf::from(&path);
let doc = match make_textdocumenitem_from_path(&path_buf) {
Some(doc) => doc,
None => {
let api_error = tower_lsp::jsonrpc::Error {
code: tower_lsp::jsonrpc::ErrorCode::InvalidParams,
message: std::borrow::Cow::Owned(format!("cannot make doc from path : {path}")),
data: None
};
return Err(api_error);
}
};
let uri = doc.uri;
let text = Rope::from_str(&doc.text);
let text = Rope::from(doc.text);
// fast 解析不需要 include
let includes: Vec<PathBuf> = Vec::new();

View File

@ -147,7 +147,7 @@ fn get_definition_token(line: RopeSlice, pos: Position) -> String {
}
fn get_language_id_by_uri(uri: &Url) -> String {
pub fn get_language_id_by_uri(uri: &Url) -> String {
let path = uri.path();
let ext_name = std::path::Path::new(path)
.extension()

View File

@ -224,19 +224,6 @@ pub trait Scope: std::fmt::Debug + Definition + Sync + Send {
}
/// 计算并得到有关 macro 的定义,保证 token 是以 ` 开头的
fn get_macro_definition(&self, token: &str, byte_idx: usize, url: &Url) -> Option<GenericDec> {
let mut definition: Option<GenericDec> = None;
if !token.starts_with("`") {
return definition;
}
// 计算 macro 的位置,需要 global scope 下的所有 defs 加上 current scope 上的位置
definition
}
/// returns all symbols in a document
fn document_symbols(&self, uri: &Url, doc: &Rope) -> Vec<DocumentSymbol> {
let mut symbols: Vec<DocumentSymbol> = Vec::new();

View File

@ -1,6 +1,7 @@
#![recursion_limit = "256"]
use custom_request::CustomRequest;
use custom_request::{ CustomParamRequest, CustomRequest, DoFastApi };
use log::info;
use std::sync::Arc;
use structopt::StructOpt;
@ -14,6 +15,7 @@ mod format;
mod server;
mod sources;
mod custom_request;
#[cfg(test)]
mod support;
use server::Backend;
@ -38,6 +40,8 @@ async fn main() {
let (service, socket) = LspService::build(|client| Arc::new(Backend::new(client, log_handle)))
.custom_method("custom/request", CustomRequest)
.custom_method("custom/paramRequest", CustomParamRequest)
.custom_method("api/fast", DoFastApi)
.finish();
Server::new(stdin, stdout, socket)

View File

@ -2,6 +2,7 @@ use crate::definition::def_types::*;
use crate::definition::get_scopes;
use crate::diagnostics::{get_diagnostics, is_hidden};
use crate::server::LSPServer;
use log::info;
use log::{debug, error};
use pathdiff::diff_paths;
use ropey::{Rope, RopeSlice};
@ -170,6 +171,7 @@ impl Sources {
}
// find and add all source/header files recursively from configured include and source directories
let src_paths = find_src_paths(&paths);
for path in src_paths {
if let Ok(url) = Url::from_file_path(&path) {
if let Ok(text) = fs::read_to_string(&path) {

@ -1 +1 @@
Subproject commit 4960ea3fb7c848462ce6e78dbae454ffc775803f
Subproject commit af11f5ff1ef091562d2b17cdf4de3614aedf2286

19
testfiles/child_1.v Normal file
View File

@ -0,0 +1,19 @@
module dependence_1 (
// this is a test
input a, b, c,
// a test
output Result // balabalabala for result
);
// a & b | ((b & c) & (b | c))
// &=*, |=+ AB + BC(B+C)
// Distribute AB + BBC + BCC
// Simplify AA = A AB + BC + BC
// Simplify A + A = A AB + BC
// Factor B(A+C)
assign Result = a & (b | c);
assign a = 11;
endmodule

9
testfiles/child_2.v Normal file
View File

@ -0,0 +1,9 @@
module dependence_2 (
input a, b, c,
output Q
);
assign Q = a & b | ((b & c) & (b | c));
endmodule

28
testfiles/head_1.v Normal file
View File

@ -0,0 +1,28 @@
`define cow 34
module dependence_1 (
input port_a, port_b, port_c,
output out_q
);
// a & b | ((b & c) & (b | c))
// &=*, |=+ AB + BC(B+C)
// Distribute AB + BBC + BCC
// Simplify AA = A AB + BC + BC
// Simplify A + A = A AB + BC
// Factor B(A+C)
assign out_q = port_b & (port_a | port_c);
endmodule
module test_1 (
input port_a, port_b,
output Q
);
assign Q = port_b & port_a;
endmodule
module helloTest();
assign a = 123;
endmodule //helloTest

11
testfiles/hello.v Normal file
View File

@ -0,0 +1,11 @@
`define awda adwwa
module hello;
initial begin
$display("hello world");
$finish;
end
endmodule

79
testfiles/parent.v Normal file
View File

@ -0,0 +1,79 @@
/*
* EN: A simple demo to test search order of dependence
* current file -> macro include -> whole project
* expect dependence_1 from child_1.v (macro include)
* expect dependence_2 from child_2.v (whole project)
* cannot find dependence_3 `main
*/
`include "child_1.v"
`include "child_2.v"
`define main out
`define simple ss
module Main (
// Main input
input a, b, c,
// Main output
output Qus, Qs, `main
);
initial begin
$display("hello world");
end
dependence_1 u_dependence_1_1(
.a(a),
.b(b),
.c(c),
.Result(Qus)
);
dependence_1 u_dependence_1_2(
.a(a),
.b(b),
.c(c),
.Result(Qus)
);
dependence_3 u_dependence_3(
.a(a),
.b(b),
.c(c),
.Q(Qs)
);
endmodule
/* @wavedrom this is wavedrom demo1
{
signal : [
{ name: "clk", wave: "p......" },
{ name: "bus", wave: "x.34.5x", data: "head body tail" },
{ name: "wire", wave: "0.1..0." }
]
}
*/
/* @wavedrom this is wavedrom demo2
{
signal: [
{ name: "pclk", wave: "p......." },
{ name: "Pclk", wave: "P......." },
{ name: "nclk", wave: "n......." },
{ name: "Nclk", wave: "N......." },
{},
{ name: "clk0", wave: "phnlPHNL" },
{ name: "clk1", wave: "xhlhLHl." },
{ name: "clk2", wave: "hpHplnLn" },
{ name: "clk3", wave: "nhNhplPl" },
{ name: "clk4", wave: "xlh.L.Hx" },
]}
*/

47
testfiles/test copy.v Normal file
View File

@ -0,0 +1,47 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2024 05 15 星期三
// Design Name: test
// Module Name: test.v
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//////////////////////////////////////////////////////////////////////////////////
module TOP
(
);
//============================================================================
//Input and output declaration.
//============================================================================
output spi_adc_csn;
output spi_dac_csn;
// output spi_iop_csn;
input spi_iop_csn;
// output spi_mul_sdt;
output spi_mul_sdi;
input spi_mul_sdo;
//============================================================================
//Wire and reg declaration.
//============================================================================
//============================================================================
//Wire and reg in this module.
//============================================================================
//============================================================================
//logic.
//============================================================================
endmodule

82
testfiles/test.sv Normal file
View File

@ -0,0 +1,82 @@
// Test Scenario to validate correct translation
// Refer: https://github.com/Nic30/hdlConvertor/issues/173
`define ADD 64
module dummy #(
parameter reg ADDR_WIDTH = 4,
parameter interger ADDER_OOO = 25,
parameter [63:0] ADDER_OOO_1 = (1 << ADDER_OOO) + 1,
parameter logic [63:0] ADD_OTHER = `ADD'hff1
) (c, a, b, d, f);
output reg c;
output logic [61:0] f;
input [ADDR_WIDTH_ANSI - 1:0] d;
input a, b;
and a1(c, a, b);
endmodule
module d2(y, a);
output [3:0] y;
input reg [2:0] a;
not n1 (y, a);
endmodule
module example (a, b, c, d);
input a, b, c;
output d;
wire tmp;
wire tmp2;
wire tmp3;
and a1 (tmp, a, b);
dummy du(
.c(tmp2), .a(b), .b(c));
dummy #(
.ADDR_WIDTH(8)
) duu(tmp3, b, c);
or o1 (d, tmp, tmp2);
endmodule
// test dummy comment
module dummy_ansi #(
parameter ADDR_WIDTH = 4,
parameter interger ADDER_OOO = 25,
parameter [63:0] ADDER_OOO_1 = (1 << ADDER_OOO) + 1,
parameter logic [63:0] ADD_OTHER = `ADD'hff1
) (
output [ADDR_WIDTH_ANSI - 1:0] c,
input [ADDR_WIDTH_ANSI-1: 0] a,
input [ADDR_WIDTH_ANSI-1:0] b
);
and a1(c, a, b);
assign c = a & b;
endmodule
module d2_ansi(
output [3:0] y,
input reg [2:0] a
);
not n1 (y, a);
endmodule
module example_ansi (
input a, b, c,
output d
);
wire tmp;
wire tmp2;
wire tmp3;
and a1 (tmp, a, b);
dummy_ansi du_ansi(
.c(tmp2), .b(b), .a(c));
dummy_ansi #(
.ADDR_WIDTH_ANSI(8)
) duu_ansi(
tmp3,
b,
c
);
or o1 (d, tmp, tmp2);
endmodule

16
testfiles/test.v Normal file
View File

@ -0,0 +1,16 @@
module testModule();
reg clk, rst;
reg port_1;
always @(posedge clk or negedge rst) begin
end
always @(posedge clk or negedge rst) begin
end
endmodule //testModule

42
testfiles/test.vhd Normal file
View File

@ -0,0 +1,42 @@
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity top_level is
generic (
WIDTH : integer := 4
);
port (
A : in STD_LOGIC_VECTOR(WIDTH-1 downto 0);
B : in STD_LOGIC_VECTOR(WIDTH-1 downto 0);
Cin : in STD_LOGIC;
Sum : out STD_LOGIC_VECTOR(WIDTH-1 downto 0);
Cout : out STD_LOGIC
);
end top_level;
architecture Behavioral of top_level is
component adder is
generic (
WIDTH : integer := 4
);
port (
A : in STD_LOGIC_VECTOR(WIDTH-1 downto 0);
B : in STD_LOGIC_VECTOR(WIDTH-1 downto 0);
Cin : in STD_LOGIC;
Sum : out STD_LOGIC_VECTOR(WIDTH-1 downto 0);
Cout : out STD_LOGIC
);
end component;
begin
adder_instance: adder
generic map (
WIDTH => X"100c00"
);
port map (
A => A,
B => B,
Cin => Cin,
Sum => Sum,
Cout => Cout
);
end Behavioral;