use crate::compiling::{Metadata, Token};
use crate::compiling::failing::logger::Logger;
use crate::compiling::failing::position_info::PositionInfo;
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum MessageType {
Error,
Warning,
Info
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Message {
pub kind: MessageType,
pub trace: Vec<PositionInfo>,
pub code: Option<String>,
pub message: Option<String>,
pub comment: Option<String>
}
impl Message {
pub fn new(code: Option<&String>, trace: &[PositionInfo], kind: MessageType) -> Self {
Message {
kind,
trace: trace.iter().rev().cloned().collect(),
code: code.cloned(),
message: None,
comment: None
}
}
pub fn new_msg(message: impl AsRef<str>, kind: MessageType) -> Self {
Message {
kind,
trace: vec![],
code: None,
message: Some(message.as_ref().to_string()),
comment: None
}
}
pub fn new_at_token(meta: &impl Metadata, token: Option<Token>, kind: MessageType) -> Self {
Self::new(meta.get_code(), &Self::get_full_trace(meta, PositionInfo::from_token(meta, token)), kind)
}
pub fn new_err_msg(message: impl AsRef<str>) -> Self {
Self::new_msg(message, MessageType::Error)
}
pub fn new_warn_msg(message: impl AsRef<str>) -> Self {
Self::new_msg(message, MessageType::Warning)
}
pub fn new_info_msg(message: impl AsRef<str>) -> Self {
Self::new_msg(message, MessageType::Info)
}
pub fn new_err_at_token(meta: &impl Metadata, token: Option<Token>) -> Self {
Self::new_at_token(meta, token, MessageType::Error)
}
pub fn new_warn_at_token(meta: &impl Metadata, token: Option<Token>) -> Self {
Self::new_at_token(meta, token, MessageType::Warning)
}
pub fn new_info_at_token(meta: &impl Metadata, token: Option<Token>) -> Self {
Self::new_at_token(meta, token, MessageType::Info)
}
pub fn new_err_at_position(meta: &impl Metadata, pos: PositionInfo) -> Self {
Self::new(meta.get_code(), &Self::get_full_trace(meta, pos), MessageType::Error)
}
pub fn new_warn_at_position(meta: &impl Metadata, pos: PositionInfo) -> Self {
Self::new(meta.get_code(), &Self::get_full_trace(meta, pos), MessageType::Warning)
}
pub fn new_info_at_position(meta: &impl Metadata, pos: PositionInfo) -> Self {
Self::new(meta.get_code(), &Self::get_full_trace(meta, pos), MessageType::Info)
}
pub fn message<T: AsRef<str>>(mut self, text: T) -> Self {
self.message = Some(String::from(text.as_ref()));
self
}
pub fn comment<T: AsRef<str>>(mut self, text: T) -> Self {
self.comment = Some(String::from(text.as_ref()));
self
}
pub fn show(&self) {
if !self.trace.is_empty() {
Logger::new(self.kind.clone(), &self.trace)
.header(self.kind.clone())
.line(self.message.clone())
.path()
.snippet(self.code.clone())
.line(self.comment.clone());
}
else {
Logger::new(self.kind.clone(), &self.trace)
.header(self.kind.clone())
.line(self.message.clone())
.padded_line(self.comment.clone());
}
}
fn get_full_trace(meta: &impl Metadata, position: PositionInfo) -> Vec<PositionInfo> {
let mut trace = meta.get_trace();
trace.push(position);
trace
}
}
#[cfg(test)]
mod test {
use crate::prelude::{DefaultMetadata, Message, Metadata, PositionInfo};
#[test]
fn test_message() {
Message::new_err_msg("This is not a message")
.comment("Or is it?")
.show();
}
#[test]
fn test_message_with_code() {
let code = Some([
"... some code",
"name = false",
"... further code",
].join("\n"));
let path = Some(format!("path/to/file"));
let position = PositionInfo::at_pos(path.clone(), (2, 1), 14, 4);
let guess = "type";
let mut meta = DefaultMetadata::new(vec![], path, code);
Message::new_err_at_position(&mut meta, position)
.message("Type of this parameter is invalid")
.comment(format!("Maybe you meant type {guess} instead"))
.show();
}
}