NAC_Blockchain/cnnl-compiler/src/nac_lint.rs

392 lines
13 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! NAC 去以太坊化 Lint 检查器
//!
//! 在 CNNL 编译器中检测并自动纠正以太坊化术语,
//! 防止开发者误用 RPC、EVM、Solidity 等以太坊概念。
//!
//! # 设计原则
//! - 输入 RPC → 错误,建议使用 NAC Lens
//! - 输入 EVM → 错误,建议使用 NVM
//! - 输入 Solidity → 错误,建议使用 Charter
//! - 输入 JSON-RPC → 错误,建议使用 NAC Lens 协议
//! - 输入 eth_ / net_ / web3_ 方法前缀 → 错误,建议使用 nac_ 方法
use std::collections::HashMap;
/// 以太坊化术语检测规则
#[derive(Debug, Clone)]
pub struct EthTermRule {
/// 错误的以太坊术语
pub eth_term: &'static str,
/// 正确的 NAC 术语
pub nac_term: &'static str,
/// 错误说明
pub message: &'static str,
/// 是否大小写不敏感匹配
pub case_insensitive: bool,
}
/// NAC 去以太坊化 Lint 诊断
#[derive(Debug, Clone)]
pub struct EthLintDiagnostic {
/// 发现位置(字节偏移)
pub span: std::ops::Range<usize>,
/// 发现的以太坊术语
pub found: String,
/// 建议的 NAC 术语
pub suggestion: String,
/// 错误消息
pub message: String,
/// 是否可自动修复
pub auto_fixable: bool,
}
impl std::fmt::Display for EthLintDiagnostic {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"[NAC-LINT-E001] 去以太坊化错误:在 {}..{} 发现 '{}'\n\
→ 错误:{}\n\
→ 建议:将 '{}' 替换为 '{}'",
self.span.start,
self.span.end,
self.found,
self.message,
self.found,
self.suggestion
)
}
}
/// NAC 去以太坊化 Lint 检查器
pub struct NacDeEthLint {
rules: Vec<EthTermRule>,
}
impl NacDeEthLint {
/// 创建标准 NAC 去以太坊化检查器
pub fn new() -> Self {
let rules = vec![
// RPC 相关
EthTermRule {
eth_term: "RPC",
nac_term: "NAC Lens",
message: "NAC 公链不使用 RPC 协议。NAC 原生网络协议为 NAC Lens元协议文明网络栈",
case_insensitive: false,
},
EthTermRule {
eth_term: "rpc",
nac_term: "nac_lens",
message: "NAC 公链不使用 rpc。请使用 NAC Lens 协议nac_lens",
case_insensitive: false,
},
EthTermRule {
eth_term: "NRPC",
nac_term: "NAC Lens",
message: "NRPC 已更名为 NAC Lens。请使用 NAC Lens 协议",
case_insensitive: false,
},
EthTermRule {
eth_term: "JSON-RPC",
nac_term: "NAC Lens",
message: "NAC 公链不使用 JSON-RPC以太坊协议。请使用 NAC Lens 原生协议",
case_insensitive: true,
},
EthTermRule {
eth_term: "jsonrpc",
nac_term: "nac_lens",
message: "NAC 公链不使用 jsonrpc 字段(以太坊 JSON-RPC 格式)。请使用 NAC Lens 请求格式",
case_insensitive: false,
},
// 虚拟机相关
EthTermRule {
eth_term: "EVM",
nac_term: "NVM",
message: "NAC 公链不使用 EVM以太坊虚拟机。NAC 原生虚拟机为 NVMNAC Virtual Machine",
case_insensitive: false,
},
EthTermRule {
eth_term: "evm",
nac_term: "nvm",
message: "NAC 公链不使用 evm。请使用 NVMnvm",
case_insensitive: false,
},
// 智能合约语言
EthTermRule {
eth_term: "Solidity",
nac_term: "Charter",
message: "NAC 公链不使用 Solidity以太坊合约语言。NAC 原生智能合约语言为 Charter",
case_insensitive: false,
},
EthTermRule {
eth_term: "solidity",
nac_term: "charter",
message: "NAC 公链不使用 solidity。请使用 Charter 合约语言",
case_insensitive: false,
},
// 共识机制
EthTermRule {
eth_term: "PoS",
nac_term: "CBPP",
message: "NAC 公链不使用 PoS权益证明。NAC 原生共识为 CBPP宪政区块生产协议",
case_insensitive: false,
},
EthTermRule {
eth_term: "PoW",
nac_term: "CBPP",
message: "NAC 公链不使用 PoW工作量证明。NAC 原生共识为 CBPP",
case_insensitive: false,
},
// 网络协议
EthTermRule {
eth_term: "P2P",
nac_term: "CSNP",
message: "NAC 公链不使用传统 P2P 网络。NAC 原生网络协议为 CSNP宪政感知神经网络协议",
case_insensitive: false,
},
// 以太坊方法前缀
EthTermRule {
eth_term: "eth_",
nac_term: "nac_",
message: "NAC 公链不使用 eth_ 方法前缀(以太坊 JSON-RPC。请使用 nac_ 方法前缀",
case_insensitive: false,
},
EthTermRule {
eth_term: "net_version",
nac_term: "nac_chainId",
message: "NAC 公链不使用 net_version以太坊方法。请使用 nac_chainId",
case_insensitive: false,
},
EthTermRule {
eth_term: "web3_",
nac_term: "nac_",
message: "NAC 公链不使用 web3_ 方法前缀。请使用 nac_ 方法前缀",
case_insensitive: false,
},
// 代币标准
EthTermRule {
eth_term: "ERC20",
nac_term: "ACC-20",
message: "NAC 公链不使用 ERC20以太坊代币标准。NAC 原生代币标准为 ACC-20",
case_insensitive: false,
},
EthTermRule {
eth_term: "ERC-20",
nac_term: "ACC-20",
message: "NAC 公链不使用 ERC-20。NAC 原生代币标准为 ACC-20",
case_insensitive: false,
},
EthTermRule {
eth_term: "ERC721",
nac_term: "ACC-721",
message: "NAC 公链不使用 ERC721以太坊 NFT 标准。NAC 原生 NFT 标准为 ACC-721",
case_insensitive: false,
},
// 地址类型
EthTermRule {
eth_term: "address(20)",
nac_term: "Address(32)",
message: "NAC 地址为 32 字节,不是以太坊的 20 字节地址",
case_insensitive: false,
},
];
Self { rules }
}
/// 对源代码进行去以太坊化检查
pub fn check(&self, source: &str) -> Vec<EthLintDiagnostic> {
let mut diagnostics = Vec::new();
for rule in &self.rules {
let term = rule.eth_term;
let search = if rule.case_insensitive {
source.to_lowercase()
} else {
source.to_string()
};
let search_term = if rule.case_insensitive {
term.to_lowercase()
} else {
term.to_string()
};
let mut start = 0;
while let Some(pos) = search[start..].find(&search_term) {
let abs_pos = start + pos;
let end_pos = abs_pos + term.len();
// 检查是否是完整词(避免误匹配子字符串)
let before_ok = abs_pos == 0
|| !source[..abs_pos]
.chars()
.last()
.map(|c| c.is_alphanumeric() || c == '_')
.unwrap_or(false);
let after_ok = end_pos >= source.len()
|| !source[end_pos..]
.chars()
.next()
.map(|c| c.is_alphanumeric() || c == '_')
.unwrap_or(false)
|| term.ends_with('_'); // 前缀匹配(如 eth_
if before_ok && after_ok {
diagnostics.push(EthLintDiagnostic {
span: abs_pos..end_pos,
found: source[abs_pos..end_pos].to_string(),
suggestion: rule.nac_term.to_string(),
message: rule.message.to_string(),
auto_fixable: true,
});
}
start = abs_pos + 1;
}
}
// 按位置排序
diagnostics.sort_by_key(|d| d.span.start);
diagnostics
}
/// 自动修复:将所有以太坊化术语替换为 NAC 术语
pub fn auto_fix(&self, source: &str) -> (String, Vec<EthLintDiagnostic>) {
let diagnostics = self.check(source);
if diagnostics.is_empty() {
return (source.to_string(), diagnostics);
}
// 构建替换映射(按长度降序,避免短词替换长词的子串)
let mut replacement_map: HashMap<&str, &str> = HashMap::new();
for rule in &self.rules {
replacement_map.insert(rule.eth_term, rule.nac_term);
}
let mut result = source.to_string();
// 从后往前替换,避免位置偏移
let mut sorted_diags = diagnostics.clone();
sorted_diags.sort_by_key(|d| std::cmp::Reverse(d.span.start));
for diag in &sorted_diags {
if diag.auto_fixable {
result.replace_range(diag.span.clone(), &diag.suggestion);
}
}
(result, diagnostics)
}
/// 生成人类可读的错误报告
pub fn report(&self, source: &str, filename: &str) -> String {
let diagnostics = self.check(source);
if diagnostics.is_empty() {
return format!("✅ [NAC-LINT] {} 通过去以太坊化检查,无以太坊化术语", filename);
}
let mut report = format!(
"❌ [NAC-LINT] {} 发现 {} 处以太坊化术语,必须修正:\n\n",
filename,
diagnostics.len()
);
for (i, diag) in diagnostics.iter().enumerate() {
// 计算行号
let line_num = source[..diag.span.start].chars().filter(|&c| c == '\n').count() + 1;
report.push_str(&format!(
" [{}/{}] 第{}行:{}\n",
i + 1,
diagnostics.len(),
line_num,
diag
));
report.push('\n');
}
report.push_str("\n💡 运行 `cnnl-compiler --fix` 可自动修正所有可修复的问题");
report
}
}
impl Default for NacDeEthLint {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rpc_detection() {
let lint = NacDeEthLint::new();
let source = "connect to RPC endpoint";
let diags = lint.check(source);
assert!(!diags.is_empty(), "应检测到 RPC");
assert_eq!(diags[0].suggestion, "NAC Lens");
}
#[test]
fn test_evm_detection() {
let lint = NacDeEthLint::new();
let source = "deploy to EVM";
let diags = lint.check(source);
assert!(!diags.is_empty(), "应检测到 EVM");
assert_eq!(diags[0].suggestion, "NVM");
}
#[test]
fn test_solidity_detection() {
let lint = NacDeEthLint::new();
let source = "write Solidity contract";
let diags = lint.check(source);
assert!(!diags.is_empty(), "应检测到 Solidity");
assert_eq!(diags[0].suggestion, "Charter");
}
#[test]
fn test_eth_method_prefix() {
let lint = NacDeEthLint::new();
let source = r#"call "eth_blockNumber""#;
let diags = lint.check(source);
assert!(!diags.is_empty(), "应检测到 eth_ 前缀");
assert_eq!(diags[0].suggestion, "nac_");
}
#[test]
fn test_auto_fix() {
let lint = NacDeEthLint::new();
let source = "use RPC to connect to EVM";
let (fixed, diags) = lint.auto_fix(source);
assert!(!diags.is_empty());
assert!(!fixed.contains("RPC") || fixed.contains("NAC Lens"));
}
#[test]
fn test_clean_source() {
let lint = NacDeEthLint::new();
let source = "use NAC Lens to connect to NVM via Charter";
let diags = lint.check(source);
assert!(diags.is_empty(), "干净的 NAC 代码不应有警告");
}
#[test]
fn test_nrpc_detection() {
let lint = NacDeEthLint::new();
let source = "NRPC protocol version";
let diags = lint.check(source);
assert!(!diags.is_empty(), "应检测到 NRPC");
assert_eq!(diags[0].suggestion, "NAC Lens");
}
#[test]
fn test_erc20_detection() {
let lint = NacDeEthLint::new();
let source = "implement ERC20 token";
let diags = lint.check(source);
assert!(!diags.is_empty(), "应检测到 ERC20");
assert_eq!(diags[0].suggestion, "ACC-20");
}
}