use crate::prelude::*;
use std::fmt;
#[derive(Debug)]
pub enum RuntimeError {
ArithmeticError(RuntimeErrorStruct),
NewAtomicFactError(RuntimeErrorStruct),
StoreFactError(RuntimeErrorStruct),
ParseError(RuntimeErrorStruct),
ExecStmtError(RuntimeErrorStruct),
WellDefinedError(RuntimeErrorStruct),
VerifyError(RuntimeErrorStruct),
UnknownError(RuntimeErrorStruct),
InferError(RuntimeErrorStruct),
NameAlreadyUsedError(RuntimeErrorStruct),
DefineParamsError(RuntimeErrorStruct),
InstantiateError(RuntimeErrorStruct),
}
#[derive(Debug)]
pub struct RuntimeErrorStruct {
pub statement: Option<Stmt>,
pub msg: String,
pub conflict_with: Option<ConflictMsg>,
pub line_file: LineFile,
pub previous_error: Option<Box<RuntimeError>>,
pub inside_results: Vec<StmtResult>,
}
macro_rules! runtime_error_from_wrapper {
($wrapper:ident, $variant:ident) => {
#[derive(Debug)]
pub struct $wrapper(pub RuntimeErrorStruct);
impl From<$wrapper> for RuntimeError {
fn from(w: $wrapper) -> Self {
RuntimeError::$variant(w.0)
}
}
};
}
runtime_error_from_wrapper!(ArithmeticRuntimeError, ArithmeticError);
runtime_error_from_wrapper!(NewAtomicFactRuntimeError, NewAtomicFactError);
runtime_error_from_wrapper!(StoreFactRuntimeError, StoreFactError);
runtime_error_from_wrapper!(ParseRuntimeError, ParseError);
runtime_error_from_wrapper!(WellDefinedRuntimeError, WellDefinedError);
runtime_error_from_wrapper!(VerifyRuntimeError, VerifyError);
runtime_error_from_wrapper!(UnknownRuntimeError, UnknownError);
runtime_error_from_wrapper!(InferRuntimeError, InferError);
runtime_error_from_wrapper!(NameAlreadyUsedRuntimeError, NameAlreadyUsedError);
runtime_error_from_wrapper!(DefineParamsRuntimeError, DefineParamsError);
runtime_error_from_wrapper!(InstantiateRuntimeError, InstantiateError);
#[derive(Debug, Clone)]
pub struct ConflictMsg {
pub msg: String,
pub line_file: LineFile,
pub stmt: Option<Stmt>,
}
impl RuntimeErrorStruct {
pub fn new(
statement: Option<Stmt>,
msg: String,
line_file: LineFile,
previous_error: Option<RuntimeError>,
) -> Self {
RuntimeErrorStruct::new_with_conflict(
statement,
msg,
line_file,
None,
previous_error,
vec![],
)
}
pub fn new_with_conflict(
statement: Option<Stmt>,
msg: String,
line_file: LineFile,
conflict_with: Option<ConflictMsg>,
previous_error: Option<RuntimeError>,
inside_results: Vec<StmtResult>,
) -> Self {
RuntimeErrorStruct {
statement,
msg,
conflict_with,
line_file,
previous_error: boxed_previous_error(previous_error),
inside_results,
}
}
pub fn new_with_msg_previous_error(msg: String, previous_error: Option<RuntimeError>) -> Self {
RuntimeErrorStruct::new(None, msg, default_line_file(), previous_error)
}
pub fn exec_stmt_new(
stmt: Option<Stmt>,
info: String,
previous_error: Option<RuntimeError>,
inside_results: Vec<StmtResult>,
) -> Self {
let line_file = if let Some(ref stmt) = stmt {
stmt.line_file()
} else {
default_line_file()
};
RuntimeErrorStruct::new_with_conflict(
stmt,
info,
line_file,
None,
previous_error,
inside_results,
)
}
pub fn exec_stmt_new_with_stmt(
stmt: Stmt,
info: String,
previous_error: Option<RuntimeError>,
inside_results: Vec<StmtResult>,
) -> Self {
let line_file = stmt.line_file();
RuntimeErrorStruct::new_with_conflict(
Some(stmt),
info,
line_file,
None,
previous_error,
inside_results,
)
}
pub fn exec_stmt_with_message_and_cause(
stmt: Stmt,
message: String,
cause: Option<RuntimeError>,
inside_results: Vec<StmtResult>,
) -> Self {
let line_file = stmt.line_file();
let previous_error = if message.is_empty() {
cause
} else {
Some(
RuntimeError::new_unknown_error_with_msg_position_optional_fact_previous_error(
message.clone(),
line_file,
None,
cause,
),
)
};
RuntimeErrorStruct::exec_stmt_new_with_stmt(stmt, message, previous_error, inside_results)
}
}
impl std::error::Error for RuntimeError {}
impl RuntimeError {
pub fn into_struct(self) -> RuntimeErrorStruct {
match self {
RuntimeError::ArithmeticError(s) => s,
RuntimeError::NewAtomicFactError(s) => s,
RuntimeError::StoreFactError(s) => s,
RuntimeError::ParseError(s) => s,
RuntimeError::ExecStmtError(s) => s,
RuntimeError::WellDefinedError(s) => s,
RuntimeError::VerifyError(s) => s,
RuntimeError::UnknownError(s) => s,
RuntimeError::InferError(s) => s,
RuntimeError::NameAlreadyUsedError(s) => s,
RuntimeError::DefineParamsError(s) => s,
RuntimeError::InstantiateError(s) => s,
}
}
pub fn line_file(&self) -> LineFile {
match self {
RuntimeError::ArithmeticError(e) => e.line_file.clone(),
RuntimeError::NewAtomicFactError(e) => e.line_file.clone(),
RuntimeError::StoreFactError(e) => e.line_file.clone(),
RuntimeError::ParseError(e) => e.line_file.clone(),
RuntimeError::ExecStmtError(e) => e.line_file.clone(),
RuntimeError::WellDefinedError(e) => e.line_file.clone(),
RuntimeError::VerifyError(e) => e.line_file.clone(),
RuntimeError::UnknownError(e) => e.line_file.clone(),
RuntimeError::InferError(e) => e.line_file.clone(),
RuntimeError::NameAlreadyUsedError(e) => e.line_file.clone(),
RuntimeError::DefineParamsError(e) => e.line_file.clone(),
RuntimeError::InstantiateError(e) => e.line_file.clone(),
}
}
pub fn display_label(&self) -> &'static str {
match self {
RuntimeError::ArithmeticError(_) => "ArithmeticError",
RuntimeError::NewAtomicFactError(_) => "NewAtomicFactError",
RuntimeError::StoreFactError(_) => "StoreFactError",
RuntimeError::ParseError(_) => "ParseError",
RuntimeError::ExecStmtError(_) => "ExecStmtError",
RuntimeError::WellDefinedError(_) => "WellDefinedError",
RuntimeError::VerifyError(_) => "VerifyError",
RuntimeError::UnknownError(_) => "UnknownError",
RuntimeError::InferError(_) => "InferError",
RuntimeError::NameAlreadyUsedError(_) => "NameAlreadyUsedError",
RuntimeError::DefineParamsError(_) => "DefineParamsError",
RuntimeError::InstantiateError(_) => "InstantiateError",
}
}
pub fn message_text_for_duplicate_used_name_without_line_file(name: &str) -> String {
format!(
"name `{}` is already used, cannot be used again for other definitions",
name
)
}
pub fn new_infer_error_with_msg_position_previous_error(
msg: String,
line_file: LineFile,
previous_error: Option<RuntimeError>,
) -> Self {
InferRuntimeError(RuntimeErrorStruct::new(
None,
msg,
line_file,
previous_error,
))
.into()
}
pub fn new_define_params_error_with_msg_previous_error_position(
msg: String,
previous_error: Option<RuntimeError>,
line_file: LineFile,
) -> Self {
DefineParamsRuntimeError(RuntimeErrorStruct::new(
None,
msg,
line_file,
previous_error,
))
.into()
}
pub fn new_parse_error_with_msg_position_previous_error(
msg: String,
line_file: LineFile,
previous_error: Option<RuntimeError>,
) -> Self {
ParseRuntimeError(RuntimeErrorStruct::new(
None,
msg,
line_file,
previous_error,
))
.into()
}
pub fn new_parse_error_for_block_unexpected_indent_at_line_file(line_file: LineFile) -> Self {
let (line_no, path) = (line_file.0, line_file.1.as_ref());
Self::new_parse_error_with_msg_position_previous_error(
format!("unexpected indent at line {} in {}", line_no, path),
line_file,
None,
)
}
pub fn new_parse_error_for_block_expected_indent_at_line_file(line_file: LineFile) -> Self {
let (line_no, path) = (line_file.0, line_file.1.as_ref());
Self::new_parse_error_with_msg_position_previous_error(
format!("expected indent at line {} in {}", line_no, path),
line_file,
None,
)
}
pub fn new_parse_error_for_block_missing_body_at_line_file(line_file: LineFile) -> Self {
let (line_no, path) = (line_file.0, line_file.1.as_ref());
Self::new_parse_error_with_msg_position_previous_error(
format!("block header missing body at line {} in {}", line_no, path),
line_file,
None,
)
}
pub fn new_parse_error_for_block_inconsistent_indent_at_line_file(line_file: LineFile) -> Self {
let (line_no, path) = (line_file.0, line_file.1.as_ref());
Self::new_parse_error_with_msg_position_previous_error(
format!("inconsistent indent at line {} in {}", line_no, path),
line_file,
None,
)
}
pub fn new_verify_error_with_fact_msg_position_previous_error(
fact: Fact,
msg: String,
line_file: LineFile,
previous_error: Option<RuntimeError>,
) -> Self {
VerifyRuntimeError(RuntimeErrorStruct::new(
Some(fact.into_stmt()),
msg,
line_file,
previous_error,
))
.into()
}
pub fn new_verify_error_with_msg_position_previous_error(
msg: String,
line_file: LineFile,
previous_error: Option<RuntimeError>,
) -> Self {
VerifyRuntimeError(RuntimeErrorStruct::new(
None,
msg,
line_file,
previous_error,
))
.into()
}
pub fn new_unknown_error_with_msg_position_optional_fact_previous_error(
msg: String,
line_file: LineFile,
fact: Option<Fact>,
previous_error: Option<RuntimeError>,
) -> Self {
UnknownRuntimeError(RuntimeErrorStruct::new(
if let Some(fact) = fact {
Some(fact.into_stmt())
} else {
None
},
msg,
line_file,
previous_error,
))
.into()
}
pub fn new_verify_result_unknown_with_fact_previous_error(
fact: Fact,
msg: String,
previous_error: Option<RuntimeError>,
) -> Self {
let line_file = fact.line_file();
RuntimeError::new_unknown_error_with_msg_position_optional_fact_previous_error(
msg,
line_file,
Some(fact),
previous_error,
)
}
pub fn new_well_defined_error_with_msg_previous_error_position(
msg: String,
previous_error: Option<RuntimeError>,
line_file: LineFile,
) -> Self {
WellDefinedRuntimeError(RuntimeErrorStruct::new(
None,
msg,
line_file,
previous_error,
))
.into()
}
pub fn new_well_defined_error_wrapping_verify_runtime_error(e: RuntimeError) -> RuntimeError {
match e {
RuntimeError::VerifyError(inner) => {
let line_file = inner.line_file.clone();
let msg_for_well_defined = if inner.msg.is_empty() {
"verify fact error:".to_string()
} else {
inner.msg.clone()
};
WellDefinedRuntimeError(RuntimeErrorStruct::new(
None,
msg_for_well_defined,
line_file,
Some(VerifyRuntimeError(inner).into()),
))
.into()
}
_ => e,
}
}
}
impl fmt::Display for RuntimeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", "error")
}
}
impl fmt::Display for RuntimeErrorStruct {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.msg)
}
}
impl std::error::Error for RuntimeErrorStruct {}
impl From<RuntimeErrorStruct> for RuntimeError {
fn from(runtime_error_struct: RuntimeErrorStruct) -> Self {
runtime_error_struct.into()
}
}
fn boxed_previous_error(previous_error: Option<RuntimeError>) -> Option<Box<RuntimeError>> {
previous_error.map(Box::new)
}