use thiserror::Error;
use crate::parser::ParseError;
use crate::engine::{ComputeError, ErrorSeverity};
#[derive(Debug, Error)]
pub enum YufmathError {
#[error("解析错误: {0}")]
Parse(#[from] ParseError),
#[error("计算错误: {0}")]
Compute(#[from] ComputeError),
#[error("格式化错误: {0}")]
Format(#[from] FormatError),
#[error("IO 错误: {0}")]
Io(#[from] std::io::Error),
#[error("配置错误: {message}")]
Config { message: String },
#[error("内部错误: {message}")]
Internal { message: String },
}
#[derive(Debug, Error, Clone, PartialEq)]
pub enum FormatError {
#[error("不支持的格式:{format}")]
UnsupportedFormat { format: String },
#[error("格式化失败:{message}")]
FormatFailure { message: String },
}
impl YufmathError {
pub fn config(message: impl Into<String>) -> Self {
YufmathError::Config {
message: message.into(),
}
}
pub fn internal(message: impl Into<String>) -> Self {
YufmathError::Internal {
message: message.into(),
}
}
pub fn user_friendly_message(&self) -> String {
match self {
YufmathError::Parse(e) => e.user_friendly_message(),
YufmathError::Compute(e) => e.user_friendly_message(),
YufmathError::Format(e) => match e {
FormatError::UnsupportedFormat { format } => {
format!("不支持的输出格式 '{}'。支持的格式:standard, latex, mathml", format)
}
FormatError::FormatFailure { message } => {
format!("格式化失败:{}。请检查表达式是否过于复杂", message)
}
},
YufmathError::Io(e) => {
format!("文件操作错误:{}。请检查文件路径和权限", e)
}
YufmathError::Config { message } => {
format!("配置错误:{}。请检查配置文件或参数设置", message)
}
YufmathError::Internal { message } => {
format!("内部错误:{}。这可能是程序缺陷,请报告此问题", message)
}
}
}
pub fn suggestions(&self) -> Vec<String> {
match self {
YufmathError::Parse(e) => e.suggestions(),
YufmathError::Compute(e) => e.suggestions(),
YufmathError::Format(e) => match e {
FormatError::UnsupportedFormat { .. } => {
vec![
"使用支持的格式:standard, latex, mathml".to_string(),
"检查格式名称的拼写是否正确".to_string(),
]
}
FormatError::FormatFailure { .. } => {
vec![
"尝试简化表达式".to_string(),
"检查表达式是否包含不支持的元素".to_string(),
"使用不同的输出格式".to_string(),
]
}
},
YufmathError::Io(_) => {
vec![
"检查文件路径是否正确".to_string(),
"确保有足够的文件访问权限".to_string(),
"检查磁盘空间是否充足".to_string(),
]
}
YufmathError::Config { .. } => {
vec![
"检查配置文件的语法是否正确".to_string(),
"确保所有必需的配置项都已设置".to_string(),
"参考文档了解正确的配置格式".to_string(),
]
}
YufmathError::Internal { .. } => {
vec![
"这是程序内部错误,请报告给开发者".to_string(),
"尝试重启程序".to_string(),
"检查是否有可用的程序更新".to_string(),
]
}
}
}
pub fn severity(&self) -> ErrorSeverity {
match self {
YufmathError::Parse(_) => ErrorSeverity::Medium,
YufmathError::Compute(e) => e.severity(),
YufmathError::Format(_) => ErrorSeverity::Low,
YufmathError::Io(_) => ErrorSeverity::Medium,
YufmathError::Config { .. } => ErrorSeverity::Medium,
YufmathError::Internal { .. } => ErrorSeverity::High,
}
}
pub fn is_recoverable(&self) -> bool {
match self {
YufmathError::Parse(_) => true,
YufmathError::Compute(e) => e.is_recoverable(),
YufmathError::Format(_) => true,
YufmathError::Io(_) => true,
YufmathError::Config { .. } => true,
YufmathError::Internal { .. } => false,
}
}
pub fn format_error_report(&self, input: Option<&str>) -> String {
let mut report = String::new();
report.push_str(&format!("错误: {}\n", self.user_friendly_message()));
if let (YufmathError::Parse(parse_error), Some(input_str)) = (self, input) {
if let Some(pos) = parse_error.position() {
if pos < input_str.len() {
report.push_str(&format!("\n输入:{}\n", input_str));
report.push_str(&format!("位置:{}{}\n", " ".repeat(pos + 3), "^"));
}
}
}
report.push_str(&format!("\n严重程度:{:?}\n", self.severity()));
let suggestions = self.suggestions();
if !suggestions.is_empty() {
report.push_str("\n建议解决方案:\n");
for (i, suggestion) in suggestions.iter().enumerate() {
report.push_str(&format!(" {}. {}\n", i + 1, suggestion));
}
}
if self.is_recoverable() {
report.push_str("\n此错误可以修复,请根据建议进行调整后重试\n");
} else {
report.push_str("\n此错误无法自动恢复,可能需要程序重启或联系技术支持\n");
}
report
}
}
impl FormatError {
pub fn unsupported_format(format: impl Into<String>) -> Self {
FormatError::UnsupportedFormat {
format: format.into(),
}
}
pub fn format_failure(message: impl Into<String>) -> Self {
FormatError::FormatFailure {
message: message.into(),
}
}
}