From e29eb0b6ed45f23458dc5af79f5ba134dcc458f3 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Sat, 29 Oct 2022 14:17:17 +0900 Subject: [PATCH 01/12] Change: color.rs to style.rs --- compiler/erg_common/color.rs | 9 -- compiler/erg_common/error.rs | 6 +- compiler/erg_common/lib.rs | 2 +- compiler/erg_common/macros.rs | 10 +- compiler/erg_common/style.rs | 114 ++++++++++++++++++ .../context/initialize/const_func.rs | 2 +- compiler/erg_compiler/error.rs | 2 +- compiler/erg_parser/error.rs | 2 +- 8 files changed, 128 insertions(+), 19 deletions(-) delete mode 100644 compiler/erg_common/color.rs create mode 100644 compiler/erg_common/style.rs diff --git a/compiler/erg_common/color.rs b/compiler/erg_common/color.rs deleted file mode 100644 index 3fb6b402..00000000 --- a/compiler/erg_common/color.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! Escape sequences change the color of the terminal - -pub const RESET: &str = "\x1b[m"; -pub const DEEP_RED: &str = "\x1b[31m"; -pub const RED: &str = "\x1b[91m"; -pub const GREEN: &str = "\x1b[92m"; -pub const YELLOW: &str = "\x1b[93m"; -pub const BLUE: &str = "\x1b[94m"; -pub const CYAN: &str = "\x1b[96m"; diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index 2ebd3c94..a926031f 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -7,8 +7,12 @@ use std::fmt::Write as _; use std::io::{stderr, BufWriter, Write as _}; use crate::astr::AtomicStr; -use crate::color::*; use crate::config::Input; +use crate::style::Color; +use crate::style::Color::{Cyan, Green, Magenta, Red, Yellow}; +use crate::style::Spans; +use crate::style::RESET; +use crate::style::{ATT_RESET, UNDERLINE}; use crate::traits::{Locational, Stream}; use crate::{fmt_option, impl_display_from_debug, switch_lang}; diff --git a/compiler/erg_common/lib.rs b/compiler/erg_common/lib.rs index 389af0a1..fb17b9a5 100644 --- a/compiler/erg_common/lib.rs +++ b/compiler/erg_common/lib.rs @@ -3,7 +3,6 @@ use std::fmt; pub mod astr; pub mod cache; -pub mod color; pub mod config; pub mod datetime; pub mod dict; @@ -24,6 +23,7 @@ pub mod set; pub mod shared; pub mod stdin; pub mod str; +pub mod style; pub mod traits; pub mod tsort; pub mod tty; diff --git a/compiler/erg_common/macros.rs b/compiler/erg_common/macros.rs index caed3350..4ab4eee0 100644 --- a/compiler/erg_common/macros.rs +++ b/compiler/erg_common/macros.rs @@ -353,7 +353,7 @@ macro_rules! debug_enum_assert { macro_rules! debug_info { ($output:ident) => {{ #[allow(unused_imports)] - use $crate::color::{CYAN, RESET}; + use $crate::style::{CYAN, RESET}; write!( $output, "[{}DEBUG{}] {}:{:04}: ", @@ -366,7 +366,7 @@ macro_rules! debug_info { }}; () => {{ #[allow(unused_imports)] - use $crate::color::{CYAN, RESET}; + use $crate::style::{CYAN, RESET}; print!("[{}DEBUG{}] {}:{:04}: ", CYAN, RESET, file!(), line!()); }}; } @@ -410,7 +410,7 @@ macro_rules! log { (c $color:ident, $($arg: tt)*) => {{ if cfg!(feature = "debug") { - use $crate::color::*; + use $crate::style::*; $crate::debug_info!(); print!("{}", $color); println!($($arg)*); @@ -420,7 +420,7 @@ macro_rules! log { (f+c $output:ident, $color:ident, $($arg: tt)*) => {{ if cfg!(feature = "debug") { - use $crate::color::*; + use $crate::style::*; $crate::debug_info!($output); write!($output, "{}", $color).unwrap(); write!($output, $($arg)*).unwrap(); @@ -431,7 +431,7 @@ macro_rules! log { ($($arg: tt)*) => {{ if cfg!(feature = "debug") { - use $crate::color::*; + use $crate::style::*; $crate::debug_info!(); println!($($arg)*); print!("{}", RESET); // reset color anyway diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs new file mode 100644 index 00000000..479672c5 --- /dev/null +++ b/compiler/erg_common/style.rs @@ -0,0 +1,114 @@ +use std::fmt::Display; + +pub const ATT_RESET: &str = "\x1b[0m"; +pub const BOLD: &str = "\x1b[1m"; +pub const UNDERLINE: &str = "\x1b[4m"; + +// Escape sequences change the color of the terminal +pub const RESET: &str = "\x1b[m"; +pub const BLACK: &str = "\x1b[30m"; +pub const DEEP_RED: &str = "\x1b[31m"; +pub const DEEP_GREEN: &str = "\x1b[32m"; +pub const DEEP_YELLOW: &str = "\x1b[33m"; +pub const DEEP_BLUE: &str = "\x1b[34m"; +pub const DEEP_MAGENTA: &str = "\x1b[35m"; +pub const DEEP_CYAN: &str = "\x1b[36m"; +pub const GRAY: &str = "\x1b[37m"; +pub const RED: &str = "\x1b[91m"; +pub const GREEN: &str = "\x1b[92m"; +pub const YELLOW: &str = "\x1b[93m"; +pub const BLUE: &str = "\x1b[94m"; +pub const MAGENTA: &str = "\x1b[95m"; +pub const CYAN: &str = "\x1b[96m"; +pub const WHITE: &str = "\x1b[97m"; + +#[derive(Debug)] +pub enum Color { + Cyan, + Green, + Gray, + Magenta, + Red, + Yellow, +} + +impl Color { + fn as_str<'a>(self) -> &'a str { + match self { + Color::Cyan => CYAN, + Color::Green => GREEN, + Color::Gray => GRAY, + Color::Magenta => MAGENTA, + Color::Red => RED, + Color::Yellow => YELLOW, + } + } +} + +pub struct Span<'a> { + text: &'a str, + color: Color, +} + +impl<'a> Span<'a> { + pub fn new(text: &'a str, color: Color) -> Self { + Self { text, color } + } +} + +impl Display for Span<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let color = self.color.as_str(); + write!(f, "{}{}{RESET}", color, self.text) + } +} + +pub struct Spans<'a>(Vec>); + +impl<'a> Spans<'a> { + pub fn new() -> Self { + Self(Vec::new()) + } + + pub fn from(s: Vec>) -> Self { + Self(s) + } + + pub fn push_str(&mut self, text: &str, color: Color) { + let span = Span::new(text, color); + } + + pub fn push_span(&mut self, span: Span<'a>) { + self.0.push(span); + } + + fn connect(self) -> String { + let mut s = String::new(); + for x in self.0.into_iter() { + s.push_str(x.color.as_str()); + s.push_str(x.text); + } + s + RESET + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn colorings_fg() { + println!("{DEEP_RED}Hello{RESET}, {RED}World{RESET}"); + println!("{DEEP_GREEN}Hello{RESET}, {GREEN}World{RESET}"); + println!("{YELLOW}Hello{RESET}, {DEEP_YELLOW}World{RESET}"); + println!("{DEEP_BLUE}Hello{RESET}, {BLUE}World{RESET}"); + println!("{CYAN}Hello{RESET}, {DEEP_CYAN}World{RESET}"); + println!("{MAGENTA}Hello{RESET}, {DEEP_MAGENTA}World{RESET}"); + println!("{GRAY}Hello{RESET}, {WHITE}World{RESET}"); + } + + #[test] + fn style_test() { + println!("{BOLD}bold{ATT_RESET}"); + println!("{UNDERLINE}UNDERLINED{ATT_RESET}"); + } +} diff --git a/compiler/erg_compiler/context/initialize/const_func.rs b/compiler/erg_compiler/context/initialize/const_func.rs index cd7388b2..4313f863 100644 --- a/compiler/erg_compiler/context/initialize/const_func.rs +++ b/compiler/erg_compiler/context/initialize/const_func.rs @@ -7,8 +7,8 @@ use crate::ty::constructors::{and, mono}; use crate::ty::value::{EvalValueResult, GenTypeObj, TypeObj, ValueObj}; use crate::ty::ValueArgs; use erg_common::astr::AtomicStr; -use erg_common::color::{RED, RESET, YELLOW}; use erg_common::error::{ErrorCore, ErrorKind, Location}; +use erg_common::style::{RED, RESET, YELLOW}; /// Requirement: Type, Impl := Type -> ClassType pub fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult { diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index f4df5bb0..c9bfbe43 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -1,10 +1,10 @@ use std::fmt::Display; use erg_common::astr::AtomicStr; -use erg_common::color::{GREEN, RED, RESET, YELLOW}; use erg_common::config::Input; use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay}; use erg_common::set::Set; +use erg_common::style::{GREEN, RED, RESET, YELLOW}; use erg_common::traits::{Locational, Stream}; use erg_common::vis::Visibility; use erg_common::{ diff --git a/compiler/erg_parser/error.rs b/compiler/erg_parser/error.rs index 03b97e85..4f007dab 100644 --- a/compiler/erg_parser/error.rs +++ b/compiler/erg_parser/error.rs @@ -2,9 +2,9 @@ //! //! パーサーが出すエラーを定義 use erg_common::astr::AtomicStr; -use erg_common::color::{RED, RESET}; use erg_common::config::Input; use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay}; +use erg_common::style::{RED, RESET}; use erg_common::traits::Stream; use erg_common::{impl_display_and_error, impl_stream_for_wrapper, switch_lang}; From 2e8ac2848d34d0ae6767ee81e6c97471bccfef64 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Sat, 12 Nov 2022 17:55:08 +0900 Subject: [PATCH 02/12] Update: add colors, attributes and Span structure --- compiler/erg_common/style.rs | 327 +++++++++++++++++++++++++++++------ 1 file changed, 275 insertions(+), 52 deletions(-) diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index 479672c5..f466ac1c 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -1,94 +1,317 @@ -use std::fmt::Display; - -pub const ATT_RESET: &str = "\x1b[0m"; +pub const ATTR_RESET: &str = "\x1b[0m"; pub const BOLD: &str = "\x1b[1m"; pub const UNDERLINE: &str = "\x1b[4m"; // Escape sequences change the color of the terminal pub const RESET: &str = "\x1b[m"; pub const BLACK: &str = "\x1b[30m"; -pub const DEEP_RED: &str = "\x1b[31m"; -pub const DEEP_GREEN: &str = "\x1b[32m"; -pub const DEEP_YELLOW: &str = "\x1b[33m"; -pub const DEEP_BLUE: &str = "\x1b[34m"; -pub const DEEP_MAGENTA: &str = "\x1b[35m"; -pub const DEEP_CYAN: &str = "\x1b[36m"; -pub const GRAY: &str = "\x1b[37m"; -pub const RED: &str = "\x1b[91m"; -pub const GREEN: &str = "\x1b[92m"; -pub const YELLOW: &str = "\x1b[93m"; pub const BLUE: &str = "\x1b[94m"; -pub const MAGENTA: &str = "\x1b[95m"; pub const CYAN: &str = "\x1b[96m"; +pub const GRAY: &str = "\x1b[37m"; +pub const GREEN: &str = "\x1b[92m"; +pub const MAGENTA: &str = "\x1b[95m"; +pub const RED: &str = "\x1b[91m"; pub const WHITE: &str = "\x1b[97m"; +pub const YELLOW: &str = "\x1b[93m"; +// custom colors when use `pretty` +pub const CUSTOM_RED: &str = "\x1b[38;2;185;64;71m"; +pub const CUSTOM_BLUE: &str = "\x1b[38;2;230;234;227m"; +pub const CUSTOM_GRAY: &str = "\x1b[38;2;244;0;25m"; +pub const CUSTOM_CYAN: &str = "\x1b[38;2;160;216;239m"; +pub const CUSTOM_MAGENTA: &str = "\x1b[38;2;103;65;150m"; +pub const CUSTOM_GREEN: &str = "\x1b[38;2;170;209;71m"; +pub const CUSTOM_YELLOW: &str = "\x1b[38;2;230;180;34m"; -#[derive(Debug)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)] pub enum Color { + Reset, + Black, + Blue, Cyan, - Green, Gray, + Green, Magenta, Red, + White, Yellow, + CustomRed, + CustomBlue, + CustomGray, + CustomCyan, + CustomMagenta, + CustomGreen, + CustomYellow, } impl Color { - fn as_str<'a>(self) -> &'a str { + pub fn as_str(&self) -> &'static str { match self { + Color::Reset => RESET, + Color::Black => BLACK, + Color::Blue => BLUE, Color::Cyan => CYAN, - Color::Green => GREEN, Color::Gray => GRAY, + Color::Green => GREEN, Color::Magenta => MAGENTA, Color::Red => RED, Color::Yellow => YELLOW, + Color::White => WHITE, + Color::CustomRed => CUSTOM_RED, + Color::CustomBlue => CUSTOM_BLUE, + Color::CustomGray => CUSTOM_GRAY, + Color::CustomCyan => CUSTOM_CYAN, + Color::CustomMagenta => CUSTOM_MAGENTA, + Color::CustomGreen => CUSTOM_GREEN, + Color::CustomYellow => CUSTOM_YELLOW, } } } -pub struct Span<'a> { - text: &'a str, - color: Color, +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)] +pub enum Attribute { + Reset, + Underline, + Bold, } -impl<'a> Span<'a> { - pub fn new(text: &'a str, color: Color) -> Self { - Self { text, color } +impl Attribute { + pub fn as_str(&self) -> &'static str { + match self { + Attribute::Reset => ATTR_RESET, + Attribute::Underline => UNDERLINE, + Attribute::Bold => BOLD, + } } } -impl Display for Span<'_> { +#[derive(Debug, Clone, Copy)] +pub struct ThemeColors { + pub error: Color, + pub warning: Color, + pub exception: Color, + pub gutter: Color, + pub hint: Color, +} + +#[derive(Debug, Clone, Copy)] +pub struct Characters { + pub hat: char, // error + pub wave: char, // exception + pub line: char, // warning and left bottom line + pub vbar: char, // gutter separator + pub lbot: char, // left bottom curve + pub vbreak: char, // gutter omission + pub lbrac: char, // error kind modifier left bracket + pub rbrac: char, // error kind modifier right bracket +} + +impl Characters { + pub fn mark(&self, kind: &str) -> String { + let mark = match kind { + "Error" => self.hat, + "Warning" => self.line, + "Exception" => self.wave, + invalid => panic!("In Characters, Invalid parameter: {invalid}"), + }; + mark.to_string() + } + pub fn left_bottom_line(&self) -> String { + format!(" {}{} ", self.lbot, self.line) + } + + pub fn error_kind_format(&self, kind: &str, err_num: usize) -> String { + const PADDING: usize = 4; + format!("{kind}{}#{err_num:>0PADDING$}{}", self.lbrac, self.rbrac,) + } +#[derive(Debug, Clone, Copy)] +pub struct Theme { + pub colors: ThemeColors, + pub characters: Characters, +} + +impl Theme { + pub const fn characters(&self) -> (Color, &Characters) { + (self.colors.gutter, &self.characters) + } + + pub const fn error(&self) -> (Color, char) { + (self.colors.error, self.characters.hat) + } + + pub const fn warning(&self) -> (Color, char) { + (self.colors.warning, self.characters.line) + } + + pub const fn exception(&self) -> (Color, char) { + (self.colors.exception, self.characters.wave) + } + + pub const fn hint(&self) -> (Color, char) { + (self.colors.hint, self.characters.wave) + } + + pub fn error_kind_format(&self, kind: &str, err_num: usize) -> String { + self.characters.error_kind_format(kind, err_num) + } +} + +pub const THEME: Theme = Theme { + colors: COLORS, + characters: CHARS, +}; + +pub const CHARS: Characters = Characters { + hat: '-', + line: '-', + vbar: '|', + wave: '~', + lbot: '`', + vbreak: ':', + lbrac: '[', + rbrac: ']', +}; +pub const COLORS: ThemeColors = ThemeColors { + error: Color::Red, + warning: Color::Yellow, + exception: Color::Magenta, + gutter: Color::Cyan, + hint: Color::Green, +}; + +#[derive(Debug)] +pub struct StrSpan<'a> { + span: &'a str, + color: Option, + attribute: Option, +} + +impl<'a> StrSpan<'a> { + pub const fn new<'b: 'a>( + span: &'b str, + color: Option, + attribute: Option, + ) -> Self { + Self { + span, + color, + attribute, + } + } +} + +impl std::fmt::Display for StrSpan<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let color = self.color.as_str(); - write!(f, "{}{}{RESET}", color, self.text) + match (self.color, self.attribute) { + (None, None) => todo!(), + (None, Some(attr)) => write!(f, "{}{}{}", attr.as_str(), self.span, ATTR_RESET), + (Some(color), None) => write!(f, "{}{}{}", color.as_str(), self.span, RESET), + (Some(color), Some(attr)) => { + write!( + f, + "{}{}{}{}{}", + color.as_str(), + attr.as_str(), + self.span, + RESET, + ATTR_RESET + ) + } + } + } +} +#[derive(Debug)] +pub struct StringSpan { + span: String, + color: Option, + attribute: Option, +} + +impl StringSpan { + pub fn new(s: &str, color: Option, attribute: Option) -> Self { + Self { + span: String::from(s), + color, + attribute, + } + } + + pub fn push_str(&mut self, s: &str) { + self.span.push_str(s); } } -pub struct Spans<'a>(Vec>); - -impl<'a> Spans<'a> { - pub fn new() -> Self { - Self(Vec::new()) - } - - pub fn from(s: Vec>) -> Self { - Self(s) - } - - pub fn push_str(&mut self, text: &str, color: Color) { - let span = Span::new(text, color); - } - - pub fn push_span(&mut self, span: Span<'a>) { - self.0.push(span); - } - - fn connect(self) -> String { - let mut s = String::new(); - for x in self.0.into_iter() { - s.push_str(x.color.as_str()); - s.push_str(x.text); +impl std::fmt::Display for StringSpan { + fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result { + match (self.color, self.attribute) { + (None, None) => write!(f, "{}", self.span), + (None, Some(attr)) => write!(f, "{}{}{}", attr.as_str(), self.span, ATTR_RESET), + (Some(color), None) => write!(f, "{}{}{}", color.as_str(), self.span, RESET), + (Some(color), Some(attr)) => write!( + f, + "{}{}{}{}{}", + attr.as_str(), + color.as_str(), + self.span, + RESET, + ATTR_RESET + ), } - s + RESET + } +} + +#[derive(Debug, Default)] +pub struct StringSpans { + spans: Vec, +} + +impl StringSpans { + pub fn push_str(&mut self, s: &str) { + if self.is_same_color(Color::Gray) { + self.spans.last_mut().unwrap().span.push_str(s); + } else { + self.spans.push(StringSpan::new(s, None, None)); + } + } + + pub fn push_str_with_color(&mut self, s: &str, color: Color) { + if self.is_same_color(color) { + self.spans.last_mut().unwrap().span.push_str(s); + } else { + self.spans.push(StringSpan::new(s, Some(color), None)); + } + } + + pub fn push_str_with_color_and_attribute(&mut self, s: &str, color: Color, attr: Attribute) { + if self.is_same_color(color) && self.is_same_attribute(attr) { + self.spans.last_mut().unwrap().span.push_str(s); + } else { + self.spans.push(StringSpan::new(s, Some(color), Some(attr))); + } + } + + pub fn is_same_color(&self, color: Color) -> bool { + if let Some(span) = self.spans.last() { + return span.color == Some(color); + } + false + } + + pub fn is_same_attribute(&self, attr: Attribute) -> bool { + if let Some(span) = self.spans.last() { + if let Some(span_attr) = span.attribute { + return span_attr == attr; + } + } + false + } +} + +impl std::fmt::Display for StringSpans { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + for span in self.spans.iter() { + write!(f, "{}", span)?; + } + Ok(()) } } From a16d46423f70d204390527d10b05c9e06ee88e5b Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Sat, 12 Nov 2022 18:03:10 +0900 Subject: [PATCH 03/12] Update: use `Span` and const Theme in style.rs --- compiler/erg_common/error.rs | 242 ++++++++++----- compiler/erg_compiler/error.rs | 387 +++++++++++++++--------- compiler/erg_parser/error.rs | 36 ++- compiler/erg_parser/lex.rs | 7 +- compiler/erg_parser/parse.rs | 7 +- compiler/erg_parser/tests/parse_test.rs | 3 +- 6 files changed, 449 insertions(+), 233 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index a926031f..240d5498 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -3,16 +3,17 @@ //! エラー処理に関する汎用的なコンポーネントを提供する use std::cmp; use std::fmt; -use std::fmt::Write as _; use std::io::{stderr, BufWriter, Write as _}; use crate::astr::AtomicStr; use crate::config::Input; +use crate::style::Attribute; +use crate::style::Characters; use crate::style::Color; -use crate::style::Color::{Cyan, Green, Magenta, Red, Yellow}; -use crate::style::Spans; -use crate::style::RESET; -use crate::style::{ATT_RESET, UNDERLINE}; +use crate::style::StrSpan; +use crate::style::StringSpan; +use crate::style::StringSpans; +use crate::style::Theme; use crate::traits::{Locational, Stream}; use crate::{fmt_option, impl_display_from_debug, switch_lang}; @@ -362,59 +363,83 @@ impl ErrorCore { } pub fn bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self { + const URL: StrSpan = StrSpan::new( + "https://github.com/erg-lang/erg", + Some(Color::White), + Some(Attribute::Underline), + ); + Self::new( errno, CompilerSystemError, loc, switch_lang!( - "japanese" => format!("これはErgのバグです、開発者に報告して下さい (https://github.com/erg-lang/erg)\n{fn_name}:{line}より発生"), - "simplified_chinese" => format!("这是Erg的bug,请报告给https://github.com/erg-lang/erg\n原因来自: {fn_name}:{line}"), - "traditional_chinese" => format!("这是Erg的bug,请报告给https://github.com/erg-lang/erg\n原因来自: {fn_name}:{line}"), - "english" => format!("this is a bug of Erg, please report it to https://github.com/erg-lang/erg\ncaused from: {fn_name}:{line}"), + "japanese" => format!("これはErgのバグです、開発者に報告して下さい({URL})\n{fn_name}:{line}より発生"), + "simplified_chinese" => format!("这是Erg的bug,请报告给{URL}\n原因来自: {fn_name}:{line}"), + "traditional_chinese" => format!("这是Erg的bug,请报告给{URL}\n原因来自: {fn_name}:{line}"), + "english" => format!("this is a bug of Erg, please report it to {URL}\ncaused from: {fn_name}:{line}"), ), None, ) } } -pub const VBAR_UNICODE: &str = "│"; -pub const VBAR_BREAK_UNICODE: &str = "·"; - -fn format_code_and_pointer( +#[allow(clippy::too_many_arguments)] +fn format_context( e: &E, ln_begin: usize, ln_end: usize, col_begin: usize, col_end: usize, + // kinds of error color and gutter(line number and vertical bar) + colors: (Color, Color), + // for formatting points + chars: &Characters, + // kinds of error for specify the color + mark: char, ) -> String { + let (err_color, gutter_color) = colors; + let mark = mark.to_string(); let codes = if e.input().is_repl() { vec![e.input().reread()] } else { e.input().reread_lines(ln_begin, ln_end) }; - let mut res = CYAN.to_string(); + let mut context = StringSpans::default(); let final_step = ln_end - ln_begin; + let max_digit = ln_end.to_string().len(); + let offset = format!("{} {} ", &" ".repeat(max_digit), chars.vbreak); for (i, lineno) in (ln_begin..=ln_end).enumerate() { - let mut pointer = " ".repeat(lineno.to_string().len() + 2); // +2 means `| ` + context.push_str_with_color( + &format!("{:( pub trait ErrorDisplay { fn core(&self) -> &ErrorCore; fn input(&self) -> &Input; + /// Colors and indication char for each type(error, warning, exception) + fn theme(&self) -> &Theme; /// The block name the error caused. /// This will be None if the error occurred before semantic analysis. /// As for the internal error, do not put the fn name here. @@ -457,26 +484,85 @@ pub trait ErrorDisplay { } fn show(&self) -> String { - format!( - "{}{}{}: {}{}\n", - self.format_header(), - self.format_code_and_pointer(), - self.core().kind, - self.core().desc, - fmt_option!(pre format!("\n{GREEN}hint{RESET}: "), self.core().hint) - ) + let theme = self.theme(); + let ((color, mark), kind) = if self.core().kind.is_error() { + (theme.error(), "Error") + } else if self.core().kind.is_warning() { + (theme.warning(), "Warning") + } else { + (theme.exception(), "Exception") + }; + + let (gutter_color, chars) = theme.characters(); + let kind = StringSpan::new( + &theme.error_kind_format(kind, self.core().errno), + Some(color), + Some(Attribute::Bold), + ); + + if let Some(hint) = self.core().hint.as_ref() { + let (hint_color, _) = theme.hint(); + let mut hints = StringSpans::default(); + hints.push_str_with_color_and_attribute("hint: ", hint_color, Attribute::Bold); + hints.push_str(hint); + format!( + "\ +{} +{}{}: {} + +{} + +", + self.format_header(kind), + self.format_code_and_pointer((color, gutter_color), mark, chars), + self.core().kind, + self.core().desc, + hints, + ) + } else { + format!( + "\ +{} +{}{}: {} + +", + self.format_header(kind), + self.format_code_and_pointer((color, gutter_color), mark, chars), + self.core().kind, + self.core().desc, + ) + } } /// for fmt::Display fn format(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let theme = self.theme(); + let ((color, mark), kind) = if self.core().kind.is_error() { + (theme.error(), "Error") + } else if self.core().kind.is_warning() { + (theme.warning(), "Warning") + } else { + (theme.exception(), "Exception") + }; + let (hint, _) = theme.hint(); + let (gutter_color, chars) = theme.characters(); + let context = self.format_code_and_pointer((color, gutter_color), mark, chars); + let kind = StringSpan::new( + &theme.error_kind_format(kind, self.core().errno), + Some(color), + Some(Attribute::Bold), + ); writeln!( f, - "{}{}{}: {}{}", - self.format_header(), - self.format_code_and_pointer(), + "\ +{} +{}{}: {} +{}", + self.format_header(kind), + context, self.core().kind, self.core().desc, - fmt_option!(pre format!("\n{GREEN}hint{RESET}: "), self.core().hint), + fmt_option!(pre StrSpan::new("hint: ", Some(hint), Some(Attribute::Bold)), self.core().hint) )?; if let Some(inner) = self.ref_inner() { inner.format(f) @@ -485,14 +571,7 @@ pub trait ErrorDisplay { } } - fn format_header(&self) -> String { - let (color, err_or_warn) = if self.core().kind.is_warning() { - (YELLOW, "Warning") - } else if self.core().kind.is_exception() { - ("", "Exception") - } else { - (RED, "Error") - }; + fn format_header(&self, kind: StringSpan) -> String { let loc = match self.core().loc { Location::Range { ln_begin, ln_end, .. @@ -515,13 +594,17 @@ pub trait ErrorDisplay { "".to_string() }; format!( - "{color}{err_or_warn}[#{errno:>04}]{RESET}: File {input}{loc}{caused_by}\n", - errno = self.core().errno, + "{kind}: File {input}{loc}{caused_by}\n", input = self.input().enclosed_name(), ) } - fn format_code_and_pointer(&self) -> String { + fn format_code_and_pointer( + &self, + colors: (Color, Color), + mark: char, + chars: &Characters, + ) -> String { match self.core().loc { Location::RangePair { ln_first, @@ -529,13 +612,25 @@ pub trait ErrorDisplay { ln_second, col_second, } => { - format_code_and_pointer(self, ln_first.0, ln_first.1, col_first.0, col_first.1) - + &format_code_and_pointer( + format_context( + self, + ln_first.0, + ln_first.1, + col_first.0, + col_first.1, + colors, + chars, + mark, + ) + + + &format_context( self, ln_second.0, ln_second.1, col_second.0, col_second.1, + colors, + chars, + mark, ) } Location::Range { @@ -543,40 +638,49 @@ pub trait ErrorDisplay { col_begin, ln_end, col_end, - } => format_code_and_pointer(self, ln_begin, ln_end, col_begin, col_end), + } => format_context( + self, ln_begin, ln_end, col_begin, col_end, colors, chars, mark, + ), Location::LineRange(ln_begin, ln_end) => { + let (err_color, gutter_color) = colors; + let mut cxt = StringSpans::default(); let codes = if self.input().is_repl() { vec![self.input().reread()] } else { self.input().reread_lines(ln_begin, ln_end) }; - let mut res = CYAN.to_string(); + let mark = mark.to_string(); for (i, lineno) in (ln_begin..=ln_end).enumerate() { - let mut pointer = " ".repeat(lineno.to_string().len() + 2); // +2 means `| ` - pointer += &"^".repeat(cmp::max(1, codes[i].len())); - writeln!( - res, - "{lineno}{VBAR_UNICODE} {code}\n{pointer}", - code = codes[i] - ) - .unwrap(); + cxt.push_str_with_color(&format!("{lineno} {}", chars.vbar), err_color); + cxt.push_str(&codes[i]); + cxt.push_str(&" ".repeat(lineno.to_string().len() + 3)); // +3 means ` | ` + cxt.push_str_with_color(&mark.repeat(cmp::max(1, codes[i].len())), gutter_color) } - res + RESET + cxt.to_string() } Location::Line(lineno) => { + let (_, gutter_color) = colors; let code = if self.input().is_repl() { self.input().reread() } else { self.input().reread_lines(lineno, lineno).remove(0) }; - format!("{CYAN}{lineno}{VBAR_UNICODE} {code}\n{RESET}") + let mut cxt = StringSpans::default(); + cxt.push_str_with_color(&format!(" {lineno} {} ", chars.vbar), gutter_color); + cxt.push_str(&code); + cxt.push_str("\n"); + cxt.to_string() } Location::Unknown => match self.input() { Input::File(_) => "\n".to_string(), - other => format!( - "{CYAN}?{VBAR_UNICODE} {code}\n{RESET}", - code = other.reread() - ), + + other => { + let (_, gutter_color) = colors; + let mut cxt = StringSpans::default(); + cxt.push_str_with_color(&format!(" ? {}", chars.vbar), gutter_color); + cxt.push_str(&other.reread()); + cxt.to_string() + } }, } } diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index c9bfbe43..9d7d0cb7 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -4,7 +4,7 @@ use erg_common::astr::AtomicStr; use erg_common::config::Input; use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay}; use erg_common::set::Set; -use erg_common::style::{GREEN, RED, RESET, YELLOW}; +use erg_common::style::{Attribute, Color, StrSpan, StringSpan, Theme, THEME}; use erg_common::traits::{Locational, Stream}; use erg_common::vis::Visibility; use erg_common::{ @@ -112,6 +112,7 @@ pub struct CompileError { pub core: Box, // ErrorCore is large, so box it pub input: Input, pub caused_by: AtomicStr, + pub theme: Theme, } impl_display_and_error!(CompileError); @@ -122,6 +123,7 @@ impl From for CompileError { core: Box::new(err.core), input: err.input, caused_by: "".into(), + theme: THEME, } } } @@ -133,6 +135,9 @@ impl ErrorDisplay for CompileError { fn input(&self) -> &Input { &self.input } + fn theme(&self) -> &Theme { + &self.theme + } fn caused_by(&self) -> &str { &self.caused_by } @@ -141,12 +146,19 @@ impl ErrorDisplay for CompileError { } } +const URL: StrSpan = StrSpan::new( + "https://github.com/erg-lang/erg", + Some(Color::White), + Some(Attribute::Underline), +); + impl CompileError { pub fn new(core: ErrorCore, input: Input, caused_by: AtomicStr) -> Self { Self { core: Box::new(core), input, caused_by, + theme: THEME, } } @@ -163,10 +175,10 @@ impl CompileError { CompilerSystemError, loc, switch_lang!( - "japanese" => format!("これはErg compilerのバグです、開発者に報告して下さい (https://github.com/erg-lang/erg)\n{fn_name}:{line}より発生"), - "simplified_chinese" => format!("这是Erg编译器的错误,请报告给https://github.com/erg-lang/erg\n原因来自: {fn_name}:{line}"), - "traditional_chinese" => format!("這是Erg編譯器的錯誤,請報告給https://github.com/erg-lang/erg\n原因來自: {fn_name}:{line}"), - "english" => format!("this is a bug of the Erg compiler, please report it to https://github.com/erg-lang/erg\ncaused from: {fn_name}:{line}"), + "japanese" => format!("これはErg compilerのバグです、開発者に報告して下さい ({URL})\n\n{fn_name}:{line}より発生"), + "simplified_chinese" => format!("这是Erg编译器的错误,请报告给{URL}\n\n原因来自: {fn_name}:{line}"), + "traditional_chinese" => format!("這是Erg編譯器的錯誤,請報告給{URL}\n\n原因來自: {fn_name}:{line}"), + "english" => format!("this is a bug of the Erg compiler, please report it to {URL}\n\ncaused from: {fn_name}:{line}"), ), None, ), @@ -189,16 +201,16 @@ impl CompileError { loc, switch_lang!( "japanese" => format!("スタックの要素数が異常です (要素数: {stack_len}, ブロックID: {block_id})\n\ - これはコンパイラのバグです、開発者に報告して下さい (https://github.com/erg-lang/erg)\n\ + これはコンパイラのバグです、開発者に報告して下さい ({URL})\n\ {fn_name}より発生"), "simplified_chinese" => format!("堆栈中的元素数无效(元素数: {stack_len},块id: {block_id})\n\ - 这是 Erg 编译器的一个错误,请报告它 (https://github.com/erg-lang/erg)\n\ + 这是 Erg 编译器的一个错误,请报告它 ({URL})\n\ 起因于: {fn_name}"), "traditional_chinese" => format!("堆棧中的元素數無效(元素數: {stack_len},塊id: {block_id})\n\ - 這是 Erg 編譯器的一個錯誤,請報告它 (https://github.com/erg-lang/erg)\n\ + 這是 Erg 編譯器的一個錯誤,請報告它 ({URL})\n\ 起因於: {fn_name}"), "english" => format!("the number of elements in the stack is invalid (num of elems: {stack_len}, block id: {block_id})\n\ - this is a bug of the Erg compiler, please report it (https://github.com/erg-lang/erg)\n\ + this is a bug of the Erg compiler, please report it ({URL})\n\ caused from: {fn_name}"), ), None, @@ -249,6 +261,10 @@ impl CompileError { pub type TyCheckError = CompileError; +const ERR: Color = THEME.colors.error; +const WARNING: Color = THEME.colors.warning; +const HINT: Color = THEME.colors.hint; + impl TyCheckError { pub fn dummy(input: Input, errno: usize) -> Self { Self::new(ErrorCore::dummy(errno), input, "".into()) @@ -271,10 +287,10 @@ impl TyCheckError { CompilerSystemError, loc, switch_lang!( - "japanese" => format!("これはErg compilerのバグです、開発者に報告して下さい (https://github.com/erg-lang/erg)\n{fn_name}:{line}より発生"), - "simplified_chinese" => format!("这是Erg编译器的错误,请报告给https://github.com/erg-lang/erg\n原因来自: {fn_name}:{line}"), - "traditional_chinese" => format!("這是Erg編譯器的錯誤,請報告給https://github.com/erg-lang/erg\n原因來自: {fn_name}:{line}"), - "english" => format!("this is a bug of the Erg compiler, please report it to https://github.com/erg-lang/erg\ncaused from: {fn_name}:{line}"), + "japanese" => format!("これはErg compilerのバグです、開発者に報告して下さい ({URL})\n\n{fn_name}:{line}より発生"), + "simplified_chinese" => format!("这是Erg编译器的错误,请报告给{URL}\n\n原因来自: {fn_name}:{line}"), + "traditional_chinese" => format!("這是Erg編譯器的錯誤,請報告給{URL}\n\n原因來自: {fn_name}:{line}"), + "english" => format!("this is a bug of the Erg compiler, please report it to {URL}\n\ncaused from: {fn_name}:{line}"), ), None, ), @@ -361,16 +377,23 @@ impl TyCheckError { ), None => "".into(), }; + let name = StringSpan::new( + &format!("{}{}", name, ord), + Some(WARNING), + Some(Attribute::Bold), + ); + let expect = StringSpan::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); + let found = StringSpan::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, TypeError, loc, switch_lang!( - "japanese" => format!("{YELLOW}{name}{ord}{RESET}の型が違います。\n予期した型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}\n{}", fmt_option_map!(pre "与えられた型の単一化候補:\n", candidates, |x: &Set| x.folded_display())), - "simplified_chinese" => format!("{YELLOW}{name}{ord}{RESET}的类型不匹配: \n预期: {GREEN}{expect}{RESET}\n但找到: {RED}{found}{RESET}\n{}", fmt_option_map!(pre "某一类型的统一候选: \n", candidates, |x: &Set| x.folded_display())), - "traditional_chinese" => format!("{YELLOW}{name}{ord}{RESET}的類型不匹配: \n預期: {GREEN}{expect}{RESET}\n但找到: {RED}{found}{RESET}\n{}", fmt_option_map!(pre "某一類型的統一候選\n", candidates, |x: &Set| x.folded_display())), - "english" => format!("the type of {YELLOW}{name}{ord}{RESET} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}\n{}", fmt_option_map!(pre "unification candidates of a given type:\n", candidates, |x: &Set| x.folded_display())), + "japanese" => format!("{name}の型が違います\n\n予期した型: {expect}\n与えられた型: {found}{}", fmt_option_map!(pre "\n与えられた型の単一化候補: ", candidates, |x: &Set| x.folded_display())), + "simplified_chinese" => format!("{name}的类型不匹配\n\n预期: {expect}\n但找到: {found}{}", fmt_option_map!(pre "\n某一类型的统一候选: ", candidates, |x: &Set| x.folded_display())), + "traditional_chinese" => format!("{name}的類型不匹配\n\n預期: {expect}\n但找到: {found}{}", fmt_option_map!(pre "\n某一類型的統一候選: ", candidates, |x: &Set| x.folded_display())), + "english" => format!("the type of {name} is mismatched\n\nexpected: {expect}\nbut found: {found}{}", fmt_option_map!(pre "\nunification candidates of a given type: ", candidates, |x: &Set| x.folded_display())), ), hint, ), @@ -388,16 +411,18 @@ impl TyCheckError { expect: &Type, found: &Type, ) -> Self { + let expect = StringSpan::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); + let found = StringSpan::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, TypeError, loc, switch_lang!( - "japanese" => format!("{name}の戻り値の型が違います。\n予期した型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}"), - "simplified_chinese" => format!("{name}的返回类型不匹配: \n预期: {GREEN}{expect}{RESET}\n但找到: {RED}{found}{RESET}"), - "traditional_chinese" => format!("{name}的返回類型不匹配: \n預期: {GREEN}{expect}{RESET}\n但找到: {RED}{found}{RESET}"), - "english" => format!("the return type of {name} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"), + "japanese" => format!("{name}の戻り値の型が違います\n\n予期した型: {expect}\n与えられた型: {found}"), + "simplified_chinese" => format!("{name}的返回类型不匹配\n\n预期: {expect}\n但找到: {found}"), + "traditional_chinese" => format!("{name}的返回類型不匹配\n\n預期: {expect}\n但找到: {found}"), + "english" => format!("the return type of {name} is mismatched\n\nexpected: {expect}\nbut found: {found}"), ), None, ), @@ -440,16 +465,18 @@ impl TyCheckError { expect: usize, found: usize, ) -> Self { + let expect = StringSpan::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); + let found = StringSpan::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, TypeError, loc, switch_lang!( - "japanese" => format!("ポジショナル引数の数が違います。\n予期した個数: {GREEN}{expect}{RESET}\n与えられた個数: {RED}{found}{RESET}"), - "simplified_chinese" => format!("正则参数的数量不匹配: \n预期: {GREEN}{expect}{RESET}\n但找到: {RED}{found}{RESET}"), - "traditional_chinese" => format!("正則參數的數量不匹配: \n預期: {GREEN}{expect}{RESET}\n但找到: {RED}{found}{RESET}"), - "english" => format!("the number of positional arguments is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"), + "japanese" => format!("ポジショナル引数の数が違います\n\n予期した個数: {expect}\n与えられた個数: {found}"), + "simplified_chinese" => format!("正则参数的数量不匹配\n\n预期: {expect}\n但找到: {found}"), + "traditional_chinese" => format!("正則參數的數量不匹配\n\n預期: {expect}\n但找到: {found}"), + "english" => format!("the number of positional arguments is mismatched\n\nexpected: {expect}\nbut found: {found}"), ), None, ), @@ -528,6 +555,21 @@ impl TyCheckError { kw_args_len: usize, ) -> Self { let name = readable_name(callee_name); + let expect = StringSpan::new( + &format!("{}", params_len), + Some(HINT), + Some(Attribute::Bold), + ); + let pos_args_len = StringSpan::new( + &format!("{}", pos_args_len), + Some(ERR), + Some(Attribute::Bold), + ); + let kw_args_len = StringSpan::new( + &format!("{}", kw_args_len), + Some(ERR), + Some(Attribute::Bold), + ); Self::new( ErrorCore::new( errno, @@ -536,27 +578,29 @@ impl TyCheckError { switch_lang!( "japanese" => format!( "{name}に渡された引数の数が多すぎます -必要な引数の合計数: {GREEN}{params_len}{RESET}個 -渡された引数の数: {RED}{pos_args_len}{RESET}個 -キーワード引数の数: {RED}{kw_args_len}{RESET}個" + +必要な引数の合計数: {expect}個 +渡された引数の数: {pos_args_len}個 +キーワード引数の数: {kw_args_len}個" ), "simplified_chinese" => format!("传递给{name}的参数过多 - 所需参数总数: {GREEN}{params_len}{RESET} - 传递的参数数量: {RED}{pos_args_len}{RESET} - 关键字参数的数量: {RED}{kw_args_len}{RESET} - " + +: {expect} +: {pos_args_len} +: {kw_args_len}" ), "traditional_chinese" => format!("傳遞給{name}的參數過多 - 所需參數總數: {GREEN}{params_len}{RESET} - 傳遞的參數數量: {RED}{pos_args_len}{RESET} - 關鍵字參數的數量: {RED}{kw_args_len}{RESET} - " + +所需參數總數: {expect} +遞的參數數量: {pos_args_len} +字參數的數量: {kw_args_len}" ), "english" => format!( - "too many arguments for {name}: -total expected params: {GREEN}{params_len}{RESET} -passed positional args: {RED}{pos_args_len}{RESET} -passed keyword args: {RED}{kw_args_len}{RESET}" + "too many arguments for {name} + +total expected params: {expect} +passed positional args: {pos_args_len} +passed keyword args: {kw_args_len}" ), ), None, @@ -576,16 +620,21 @@ passed keyword args: {RED}{kw_args_len}{RESET}" missing_params: Vec, ) -> Self { let name = readable_name(callee_name); + let vec_cxt = StringSpan::new( + &fmt_vec(&missing_params), + Some(WARNING), + Some(Attribute::Bold), + ); Self::new( ErrorCore::new( errno, TypeError, loc, switch_lang!( - "japanese" => format!("{name}に渡された引数が{missing_len}個足りません({YELLOW}{}{RESET})。", fmt_vec(&missing_params)), - "simplified_chinese" => format!("{name}的{missing_len}个位置参数不被传递。({YELLOW}{}{RESET})。", fmt_vec(&missing_params)), - "traditional_chinese" => format!("{name}的{missing_len}個位置參數不被傳遞。({YELLOW}{}{RESET})。", fmt_vec(&missing_params)), - "english" => format!("missing {missing_len} positional argument(s) for {name}: {YELLOW}{}{RESET}", fmt_vec(&missing_params)), + "japanese" => format!("{name}に渡された引数が{missing_len}個足りません({vec_cxt})" ), + "simplified_chinese" => format!("{name}的{missing_len}个位置参数不被传递({vec_cxt})"), + "traditional_chinese" => format!("{name}的{missing_len}個位置參數不被傳遞({vec_cxt})"), + "english" => format!("missing {missing_len} positional argument(s) for {name}: {vec_cxt}"), ), None, ), @@ -603,16 +652,17 @@ passed keyword args: {RED}{kw_args_len}{RESET}" arg_name: &str, ) -> Self { let name = readable_name(callee_name); + let found = StringSpan::new(arg_name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, TypeError, loc, switch_lang!( - "japanese" => format!("{name}の引数{RED}{arg_name}{RESET}が複数回渡されています"), - "simplified_chinese" => format!("{name}的参数{RED}{arg_name}{RESET}被多次传递"), - "traditional_chinese" => format!("{name}的參數{RED}{arg_name}{RESET}被多次傳遞"), - "english" => format!("{name}'s argument {RED}{arg_name}{RESET} is passed multiple times"), + "japanese" => format!("{name}の引数{found}が複数回渡されています"), + "simplified_chinese" => format!("{name}的参数{found}被多次传递"), + "traditional_chinese" => format!("{name}的參數{found}被多次傳遞"), + "english" => format!("{name}'s argument {found} is passed multiple times"), ), None, ), @@ -630,16 +680,17 @@ passed keyword args: {RED}{kw_args_len}{RESET}" param_name: &str, ) -> Self { let name = readable_name(callee_name); + let found = StringSpan::new(param_name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, TypeError, loc, switch_lang!( - "japanese" => format!("{name}には予期しないキーワード引数{RED}{param_name}{RESET}が渡されています"), - "simplified_chinese" => format!("{name}得到了意外的关键字参数{RED}{param_name}{RESET}"), - "traditional_chinese" => format!("{name}得到了意外的關鍵字參數{RED}{param_name}{RESET}"), - "english" => format!("{name} got unexpected keyword argument {RED}{param_name}{RESET}"), + "japanese" => format!("{name}には予期しないキーワード引数{found}が渡されています"), + "simplified_chinese" => format!("{name}得到了意外的关键字参数{found}"), + "traditional_chinese" => format!("{name}得到了意外的關鍵字參數{found}"), + "english" => format!("{name} got unexpected keyword argument {found}"), ), None, ), @@ -656,16 +707,18 @@ passed keyword args: {RED}{kw_args_len}{RESET}" loc: Location, caused_by: AtomicStr, ) -> Self { + let lhs_t = StringSpan::new(&format!("{}", lhs_t), Some(WARNING), Some(Attribute::Bold)); + let rhs_t = StringSpan::new(&format!("{}", rhs_t), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, TypeError, loc, switch_lang!( - "japanese" => format!("型の単一化に失敗しました:\n左辺: {YELLOW}{lhs_t}{RESET}\n右辺: {YELLOW}{rhs_t}{RESET}"), - "simplified_chinese" => format!("类型统一失败: \n左边: {YELLOW}{lhs_t}{RESET}\n右边: {YELLOW}{rhs_t}{RESET}"), - "traditional_chinese" => format!("類型統一失敗: \n左邊: {YELLOW}{lhs_t}{RESET}\n右邊: {YELLOW}{rhs_t}{RESET}"), - "english" => format!("unification failed:\nlhs: {YELLOW}{lhs_t}{RESET}\nrhs: {YELLOW}{rhs_t}{RESET}"), + "japanese" => format!("型の単一化に失敗しました\n\n左辺: {lhs_t}\n右辺: {rhs_t}"), + "simplified_chinese" => format!("类型统一失败\n\n左边: {lhs_t}\n右边: {rhs_t}"), + "traditional_chinese" => format!("類型統一失敗\n\n左邊: {lhs_t}\n右邊: {rhs_t}"), + "english" => format!("unification failed\n\nlhs: {lhs_t}\nrhs: {rhs_t}"), ), None, ), @@ -682,16 +735,18 @@ passed keyword args: {RED}{kw_args_len}{RESET}" loc: Location, caused_by: AtomicStr, ) -> Self { + let lhs_t = StringSpan::new(&format!("{}", lhs_t), Some(WARNING), Some(Attribute::Bold)); + let rhs_t = StringSpan::new(&format!("{}", rhs_t), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, TypeError, loc, switch_lang!( - "japanese" => format!("型の再単一化に失敗しました:\n左辺: {YELLOW}{lhs_t}{RESET}\n右辺: {YELLOW}{rhs_t}{RESET}"), - "simplified_chinese" => format!("重新统一类型失败: \n左边: {YELLOW}{lhs_t}{RESET}\n右边: {YELLOW}{rhs_t}{RESET}"), - "traditional_chinese" => format!("重新統一類型失敗: \n左邊: {YELLOW}{lhs_t}{RESET}\n右邊: {YELLOW}{rhs_t}{RESET}"), - "english" => format!("re-unification failed:\nlhs: {YELLOW}{lhs_t}{RESET}\nrhs: {YELLOW}{rhs_t}{RESET}"), + "japanese" => format!("型の再単一化に失敗しました\n\n左辺: {lhs_t}\n右辺: {rhs_t}"), + "simplified_chinese" => format!("重新统一类型失败\n\n左边: {lhs_t}\n右边: {rhs_t}"), + "traditional_chinese" => format!("重新統一類型失敗\n\n左邊: {lhs_t}\n右邊: {rhs_t}"), + "english" => format!("re-unification failed\n\nlhs: {lhs_t}\nrhs: {rhs_t}"), ), None, ), @@ -708,16 +763,18 @@ passed keyword args: {RED}{kw_args_len}{RESET}" loc: Location, caused_by: AtomicStr, ) -> Self { + let sub_t = StringSpan::new(&format!("{}", sub_t), Some(WARNING), Some(Attribute::Bold)); + let sup_t = StringSpan::new(&format!("{}", sup_t), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, TypeError, loc, switch_lang!( - "japanese" => format!("この式の部分型制約を満たせません:\nサブタイプ: {YELLOW}{sub_t}{RESET}\nスーパータイプ: {YELLOW}{sup_t}{RESET}"), - "simplified_chinese" => format!("无法满足此表达式中的子类型约束: \n子类型: {YELLOW}{sub_t}{RESET}\n超类型: {YELLOW}{sup_t}{RESET}"), - "traditional_chinese" => format!("無法滿足此表達式中的子類型約束: \n子類型: {YELLOW}{sub_t}{RESET}\n超類型: {YELLOW}{sup_t}{RESET}"), - "english" => format!("the subtype constraint in this expression cannot be satisfied:\nsubtype: {YELLOW}{sub_t}{RESET}\nsupertype: {YELLOW}{sup_t}{RESET}"), + "japanese" => format!("この式の部分型制約を満たせません\n\nサブタイプ: {sub_t}\nスーパータイプ: {sup_t}"), + "simplified_chinese" => format!("无法满足此表达式中的子类型约束\n\n子类型: {sub_t}\n超类型: {sup_t}"), + "traditional_chinese" => format!("無法滿足此表達式中的子類型約束\n\n子類型: {sub_t}\n超類型: {sup_t}"), + "english" => format!("the subtype constraint in this expression cannot be satisfied:\nsubtype: {sub_t}\nsupertype: {sup_t}"), ), None, ), @@ -733,16 +790,18 @@ passed keyword args: {RED}{kw_args_len}{RESET}" rhs: &Predicate, caused_by: AtomicStr, ) -> Self { + let lhs = StringSpan::new(&format!("{}", lhs), Some(WARNING), Some(Attribute::Bold)); + let rhs = StringSpan::new(&format!("{}", rhs), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, TypeError, Location::Unknown, switch_lang!( - "japanese" => format!("述語式の単一化に失敗しました:\n左辺: {YELLOW}{lhs}{RESET}\n右辺: {YELLOW}{rhs}{RESET}"), - "simplified_chinese" => format!("无法统一谓词表达式: \n左边: {YELLOW}{lhs}{RESET}\n左边: {YELLOW}{rhs}{RESET}"), - "traditional_chinese" => format!("無法統一謂詞表達式: \n左邊: {YELLOW}{lhs}{RESET}\n左邊: {YELLOW}{rhs}{RESET}"), - "english" => format!("predicate unification failed:\nlhs: {YELLOW}{lhs}{RESET}\nrhs: {YELLOW}{rhs}{RESET}"), + "japanese" => format!("述語式の単一化に失敗しました\n\n左辺: {lhs}\n右辺: {rhs}"), + "simplified_chinese" => format!("无法统一谓词表达式\n\n左边: {lhs}\n左边: {rhs}"), + "traditional_chinese" => format!("無法統一謂詞表達式\n\n左邊: {lhs}\n左邊: {rhs}"), + "english" => format!("predicate unification failed\n\nlhs: {lhs}\nrhs: {rhs}"), ), None, ), @@ -812,6 +871,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}" name: &str, hint: Option, ) -> Self { + let found = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -819,16 +879,16 @@ passed keyword args: {RED}{kw_args_len}{RESET}" loc, switch_lang!( "japanese" => format!( - "{RED}{name}{RESET}にメソッドを定義することはできません", + "{found}にメソッドを定義することはできません", ), "simplified_chinese" => format!( - "{RED}{name}{RESET}不可定义方法", + "{found}不可定义方法", ), "traditional_chinese" => format!( - "{RED}{name}{RESET}不可定義方法", + "{found}不可定義方法", ), "english" => format!( - "cannot define methods for {RED}{name}{RESET}", + "cannot define methods for {found}", ), ), hint, @@ -850,16 +910,19 @@ passed keyword args: {RED}{kw_args_len}{RESET}" found: &Type, hint: Option, ) -> Self { + let member_name = StringSpan::new(member_name, Some(WARNING), Some(Attribute::Bold)); + let expect = StringSpan::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); + let found = StringSpan::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, TypeError, loc, switch_lang!( - "japanese" => format!("{YELLOW}{member_name}{RESET}の型が違います。\n{trait_type}で宣言された型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}"), - "simplified_chinese" => format!("{YELLOW}{member_name}{RESET}的类型不匹配: \n在{trait_type}中声明的类型: {GREEN}{expect}{RESET}\n但找到: {RED}{found}{RESET}"), - "traditional_chinese" => format!("{YELLOW}{member_name}{RESET}的類型不匹配: \n在{trait_type}中聲明的類型: {GREEN}{expect}{RESET}\n但找到: {RED}{found}{RESET}"), - "english" => format!("the type of {YELLOW}{member_name}{RESET} is mismatched:\ndeclared in {trait_type}: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"), + "japanese" => format!("{member_name}の型が違います\n\n{trait_type}で宣言された型: {expect}\n与えられた型: {found}"), + "simplified_chinese" => format!("{member_name}的类型不匹配\n\n在{trait_type}中声明的类型: {expect}\n但找到: {found}"), + "traditional_chinese" => format!("{member_name}的類型不匹配\n\n在{trait_type}中聲明的類型: {expect}\n但找到: {found}"), + "english" => format!("the type of {member_name} is mismatched\n\ndeclared in {trait_type}: {expect}\nbut found: {found}"), ), hint, ), @@ -878,16 +941,17 @@ passed keyword args: {RED}{kw_args_len}{RESET}" class_type: &Type, hint: Option, ) -> Self { + let member_name = StringSpan::new(member_name, Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, TypeError, Location::Unknown, switch_lang!( - "japanese" => format!("{trait_type}の{YELLOW}{member_name}{RESET}が{class_type}で実装されていません"), - "simplified_chinese" => format!("{trait_type}中的{YELLOW}{member_name}{RESET}没有在{class_type}中实现"), - "traditional_chinese" => format!("{trait_type}中的{YELLOW}{member_name}{RESET}沒有在{class_type}中實現"), - "english" => format!("{YELLOW}{member_name}{RESET} of {trait_type} is not implemented in {class_type}"), + "japanese" => format!("{trait_type}の{member_name}が{class_type}で実装されていません"), + "simplified_chinese" => format!("{trait_type}中的{member_name}没有在{class_type}中实现"), + "traditional_chinese" => format!("{trait_type}中的{member_name}沒有在{class_type}中實現"), + "english" => format!("{member_name} of {trait_type} is not implemented in {class_type}"), ), hint, ), @@ -906,16 +970,17 @@ passed keyword args: {RED}{kw_args_len}{RESET}" class_type: &Type, hint: Option, ) -> Self { + let member_name = StringSpan::new(member_name, Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, TypeError, Location::Unknown, switch_lang!( - "japanese" => format!("{class_type}の{YELLOW}{member_name}{RESET}は{trait_type}で宣言されていません"), - "simplified_chinese" => format!("{class_type}中的{YELLOW}{member_name}{RESET}没有在{trait_type}中声明"), - "traditional_chinese" => format!("{class_type}中的{YELLOW}{member_name}{RESET}沒有在{trait_type}中聲明"), - "english" => format!("{YELLOW}{member_name}{RESET} of {class_type} is not declared in {trait_type}"), + "japanese" => format!("{class_type}の{member_name}は{trait_type}で宣言されていません"), + "simplified_chinese" => format!("{class_type}中的{member_name}没有在{trait_type}中声明"), + "traditional_chinese" => format!("{class_type}中的{member_name}沒有在{trait_type}中聲明"), + "english" => format!("{member_name} of {class_type} is not declared in {trait_type}"), ), hint, ), @@ -931,16 +996,17 @@ passed keyword args: {RED}{kw_args_len}{RESET}" loc: Location, caused_by: AtomicStr, ) -> Self { + let found = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, TypeError, loc, switch_lang!( - "japanese" => format!("型変数{RED}{name}{RESET}が定義されていません"), - "simplified_chinese" => format!("类型变量{RED}{name}{RESET}没有定义"), - "traditional_chinese" => format!("類型變量{RED}{name}{RESET}沒有定義"), - "english" => format!("type variable {RED}{name}{RESET} is not defined"), + "japanese" => format!("型変数{found}が定義されていません"), + "simplified_chinese" => format!("类型变量{found}没有定义"), + "traditional_chinese" => format!("類型變量{found}沒有定義"), + "english" => format!("type variable {found} is not defined"), ), None, ), @@ -962,10 +1028,10 @@ passed keyword args: {RED}{kw_args_len}{RESET}" TypeError, expr.loc(), switch_lang!( - "japanese" => format!("{expr}の型を一意に決定できませんでした\n候補: {}", fmt_vec(candidates)), - "simplified_chinese" => format!("无法确定{expr}的类型\n候选: {}", fmt_vec(candidates)), - "traditional_chinese" => format!("無法確定{expr}的類型\n候選: {}", fmt_vec(candidates)), - "english" => format!("cannot determine the type of {expr}\ncandidates: {}", fmt_vec(candidates)), + "japanese" => format!("{expr}の型を一意に決定できませんでした\n\n候補: {}", fmt_vec(candidates)), + "simplified_chinese" => format!("无法确定{expr}的类型\n\n候选: {}", fmt_vec(candidates)), + "traditional_chinese" => format!("無法確定{expr}的類型\n\n候選: {}", fmt_vec(candidates)), + "english" => format!("cannot determine the type of {expr}\n\ncandidates: {}", fmt_vec(candidates)), ), Some( switch_lang!( @@ -1111,6 +1177,7 @@ impl OwnershipError { moved_loc: Location, caused_by: S, ) -> Self { + let found = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -1118,19 +1185,19 @@ impl OwnershipError { name_loc, switch_lang!( "japanese" => format!( - "{RED}{name}{RESET}は{}行目ですでに移動されています", + "{found}は{}行目ですでに移動されています", moved_loc.ln_begin().unwrap_or(0) ), "simplified_chinese" => format!( - "{RED}{name}{RESET}已移至第{}行", + "{found}已移至第{}行", moved_loc.ln_begin().unwrap_or(0) ), "traditional_chinese" => format!( - "{RED}{name}{RESET}已移至第{}行", + "{found}已移至第{}行", moved_loc.ln_begin().unwrap_or(0) ), "english" => format!( - "{RED}{name}{RESET} was moved in line {}", + "{found} was moved in line {}", moved_loc.ln_begin().unwrap_or(0) ), ), @@ -1227,16 +1294,18 @@ impl LowerError { found_t: &Type, ) -> Self { let name = readable_name(name); + let expect = StringSpan::new(&format!("{}", spec_t), Some(HINT), Some(Attribute::Bold)); + let found = StringSpan::new(&format!("{}", found_t), Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, TypeError, loc, switch_lang!( - "japanese" => format!("{name}は{GREEN}{spec_t}{RESET}型として宣言されましたが、{RED}{found_t}{RESET}型のオブジェクトが代入されています"), - "simplified_chinese" => format!("{name}被声明为{GREEN}{spec_t}{RESET},但分配了一个{RED}{found_t}{RESET}对象"), - "traditional_chinese" => format!("{name}被聲明為{GREEN}{spec_t}{RESET},但分配了一個{RED}{found_t}{RESET}對象"), - "english" => format!("{name} was declared as {GREEN}{spec_t}{RESET}, but an {RED}{found_t}{RESET} object is assigned"), + "japanese" => format!("{name}は{expect}型として宣言されましたが、{found}型のオブジェクトが代入されています"), + "simplified_chinese" => format!("{name}被声明为{expect},但分配了一个{found}对象"), + "traditional_chinese" => format!("{name}被聲明為{expect},但分配了一個{found}對象"), + "english" => format!("{name} was declared as {expect}, but an {found} object is assigned"), ), Option::::None, ), @@ -1263,16 +1332,17 @@ impl LowerError { ) .into() }); + let found = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, NameError, loc, switch_lang!( - "japanese" => format!("{RED}{name}{RESET}という変数は定義されていません"), - "simplified_chinese" => format!("{RED}{name}{RESET}未定义"), - "traditional_chinese" => format!("{RED}{name}{RESET}未定義"), - "english" => format!("{RED}{name}{RESET} is not defined"), + "japanese" => format!("{found}という変数は定義されていません"), + "simplified_chinese" => format!("{found}未定义"), + "traditional_chinese" => format!("{found}未定義"), + "english" => format!("{found} is not defined"), ), hint, ), @@ -1299,16 +1369,17 @@ impl LowerError { ) .into() }); + let found = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, AttributeError, loc, switch_lang!( - "japanese" => format!("{obj_t}型オブジェクトに{RED}{name}{RESET}という属性はありません"), - "simplified_chinese" => format!("{obj_t}对象没有属性{RED}{name}{RESET}"), - "traditional_chinese" => format!("{obj_t}對像沒有屬性{RED}{name}{RESET}"), - "english" => format!("{obj_t} object has no attribute {RED}{name}{RESET}"), + "japanese" => format!("{obj_t}型オブジェクトに{found}という属性はありません"), + "simplified_chinese" => format!("{obj_t}对象没有属性{found}"), + "traditional_chinese" => format!("{obj_t}對像沒有屬性{found}"), + "english" => format!("{obj_t} object has no attribute {found}"), ), hint, ), @@ -1337,16 +1408,17 @@ impl LowerError { ) .into() }); + let found = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, AttributeError, loc, switch_lang!( - "japanese" => format!("{obj_name}(: {obj_t})に{RED}{name}{RESET}という属性はありません"), - "simplified_chinese" => format!("{obj_name}(: {obj_t})没有属性{RED}{name}{RESET}"), - "traditional_chinese" => format!("{obj_name}(: {obj_t})沒有屬性{RED}{name}{RESET}"), - "english" => format!("{obj_name}(: {obj_t}) has no attribute {RED}{name}{RESET}"), + "japanese" => format!("{obj_name}(: {obj_t})に{found}という属性はありません"), + "simplified_chinese" => format!("{obj_name}(: {obj_t})没有属性{found}"), + "traditional_chinese" => format!("{obj_name}(: {obj_t})沒有屬性{found}"), + "english" => format!("{obj_name}(: {obj_t}) has no attribute {found}"), ), hint, ), @@ -1362,17 +1434,17 @@ impl LowerError { caused_by: AtomicStr, name: &str, ) -> Self { - let name = readable_name(name); + let name = StringSpan::new(readable_name(name), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, AssignError, loc, switch_lang!( - "japanese" => format!("変数{YELLOW}{name}{RESET}に複数回代入することはできません"), - "simplified_chinese" => format!("不能为变量{YELLOW}{name}{RESET}分配多次"), - "traditional_chinese" => format!("不能為變量{YELLOW}{name}{RESET}分配多次"), - "english" => format!("variable {YELLOW}{name}{RESET} cannot be assigned more than once"), + "japanese" => format!("変数{name}に複数回代入することはできません"), + "simplified_chinese" => format!("不能为变量{name}分配多次"), + "traditional_chinese" => format!("不能為變量{name}分配多次"), + "english" => format!("variable {name} cannot be assigned more than once"), ), None, ), @@ -1388,17 +1460,17 @@ impl LowerError { name: &str, caused_by: AtomicStr, ) -> Self { - let name = readable_name(name); + let name = StringSpan::new(readable_name(name), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, UnusedWarning, loc, switch_lang!( - "japanese" => format!("{YELLOW}{name}{RESET}は使用されていません"), - "simplified_chinese" => format!("{YELLOW}{name}{RESET}未使用"), - "traditional_chinese" => format!("{YELLOW}{name}{RESET}未使用"), - "english" => format!("{YELLOW}{name}{RESET} is not used"), + "japanese" => format!("{name}は使用されていません"), + "simplified_chinese" => format!("{name}未使用"), + "traditional_chinese" => format!("{name}未使用"), + "english" => format!("{name} is not used"), ), None, ), @@ -1408,17 +1480,21 @@ impl LowerError { } pub fn del_error(input: Input, errno: usize, ident: &Identifier, caused_by: AtomicStr) -> Self { - let name = readable_name(ident.inspect()); + let name = StringSpan::new( + readable_name(ident.inspect()), + Some(WARNING), + Some(Attribute::Bold), + ); Self::new( ErrorCore::new( errno, NameError, ident.loc(), switch_lang!( - "japanese" => format!("{YELLOW}{name}{RESET}は削除できません"), - "simplified_chinese" => format!("{YELLOW}{name}{RESET}不能删除"), - "traditional_chinese" => format!("{YELLOW}{name}{RESET}不能刪除"), - "english" => format!("{YELLOW}{name}{RESET} cannot be deleted"), + "japanese" => format!("{name}は削除できません"), + "simplified_chinese" => format!("{name}不能删除"), + "traditional_chinese" => format!("{name}不能刪除"), + "english" => format!("{name} cannot be deleted"), ), None, ), @@ -1451,16 +1527,17 @@ impl LowerError { "english" => "public", ) }; + let found = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, VisibilityError, loc, switch_lang!( - "japanese" => format!("{RED}{name}{RESET}は{visibility}変数です"), - "simplified_chinese" => format!("{RED}{name}{RESET}是{visibility}变量",), - "traditional_chinese" => format!("{RED}{name}{RESET}是{visibility}變量",), - "english" => format!("{RED}{name}{RESET} is {visibility} variable",), + "japanese" => format!("{found}は{visibility}変数です"), + "simplified_chinese" => format!("{found}是{visibility}变量",), + "traditional_chinese" => format!("{found}是{visibility}變量",), + "english" => format!("{found} is {visibility} variable",), ), None, ), @@ -1477,6 +1554,12 @@ impl LowerError { superclass: &Type, caused_by: S, ) -> Self { + let name = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); + let superclass = StringSpan::new( + &format!("{}", superclass), + Some(WARNING), + Some(Attribute::Bold), + ); Self::new( ErrorCore::new( errno, @@ -1484,16 +1567,16 @@ impl LowerError { name_loc, switch_lang!( "japanese" => format!( - "{RED}{name}{RESET}は{YELLOW}{superclass}{RESET}で既に定義されています", + "{name}は{superclass}で既に定義されています", ), "simplified_chinese" => format!( - "{RED}{name}{RESET}已在{YELLOW}{superclass}{RESET}中定义", + "{name}已在{superclass}中定义", ), "traditional_chinese" => format!( - "{RED}{name}{RESET}已在{YELLOW}{superclass}{RESET}中定義", + "{name}已在{superclass}中定義", ), "english" => format!( - "{RED}{name}{RESET} is already defined in {YELLOW}{superclass}{RESET}", + "{name} is already defined in {superclass}", ), ), Some(switch_lang!( @@ -1574,11 +1657,21 @@ impl LowerError { similar_py_mod: Option, ) -> Self { let hint = match (similar_erg_mod, similar_py_mod) { - (Some(erg), Some(py)) => Some(format!( - "similar name erg module {YELLOW}{erg}{RESET} and python module {YELLOW}{py}{RESET} exists (to import python modules, use `pyimport`)", - )), - (Some(erg), None) => Some(format!("similar name erg module exists: {YELLOW}{erg}{RESET}")), - (None, Some(py)) => Some(format!("similar name python module exists: {YELLOW}{py}{RESET} (to import python modules, use `pyimport`)")), + (Some(erg), Some(py)) => { + let erg = StringSpan::new(&erg, Some(WARNING), Some(Attribute::Bold)); + let py = StringSpan::new(&py, Some(WARNING), Some(Attribute::Bold)); + Some(format!( + "similar name erg module {erg} and python module {py} exists (to import python modules, use `pyimport`)", + )) + } + (Some(erg), None) => { + let erg = StringSpan::new(&erg, Some(WARNING), Some(Attribute::Bold)); + Some(format!("similar name erg module exists: {erg}")) + } + (None, Some(py)) => { + let py = StringSpan::new(&py, Some(WARNING), Some(Attribute::Bold)); + Some(format!("similar name python module exists: {py} (to import python modules, use `pyimport`)")) + } (None, None) => None, }; let hint = hint.map(AtomicStr::from); @@ -1638,16 +1731,22 @@ impl LowerError { cast_to: &Type, hint: Option, ) -> Self { + let name = StringSpan::new(name, Some(WARNING), Some(Attribute::Bold)); + let found = StringSpan::new( + &format!("{}", cast_to), + Some(WARNING), + Some(Attribute::Bold), + ); Self::new( ErrorCore::new( errno, TypeError, loc, switch_lang!( - "japanese" => format!("{YELLOW}{name}{RESET}の型を{RED}{cast_to}{RESET}にキャストすることはできません"), - "simplified_chinese" => format!("{YELLOW}{name}{RESET}的类型无法转换为{RED}{cast_to}{RESET}"), - "traditional_chinese" => format!("{YELLOW}{name}{RESET}的類型無法轉換為{RED}{cast_to}{RESET}"), - "english" => format!("the type of {YELLOW}{name}{RESET} cannot be cast to {RED}{cast_to}{RESET}"), + "japanese" => format!("{name}の型を{found}にキャストすることはできません"), + "simplified_chinese" => format!("{name}的类型无法转换为{found}"), + "traditional_chinese" => format!("{name}的類型無法轉換為{found}"), + "english" => format!("the type of {name} cannot be cast to {found}"), ), hint, ), diff --git a/compiler/erg_parser/error.rs b/compiler/erg_parser/error.rs index 4f007dab..d291bae2 100644 --- a/compiler/erg_parser/error.rs +++ b/compiler/erg_parser/error.rs @@ -4,7 +4,7 @@ use erg_common::astr::AtomicStr; use erg_common::config::Input; use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay}; -use erg_common::style::{RED, RESET}; +use erg_common::style::{Attribute, Color, StrSpan, StringSpan, Theme}; use erg_common::traits::Stream; use erg_common::{impl_display_and_error, impl_stream_for_wrapper, switch_lang}; @@ -38,15 +38,20 @@ impl LexError { } pub fn compiler_bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self { + const URL: StrSpan = StrSpan::new( + "https://github.com/erg-lang/erg", + Some(Color::White), + Some(Attribute::Underline), + ); Self::new(ErrorCore::new( errno, CompilerSystemError, loc, switch_lang!( - "japanese" => format!("これはErg compilerのバグです、開発者に報告して下さい (https://github.com/erg-lang/erg)\n{fn_name}:{line}より発生"), - "simplified_chinese" => format!("这是Erg编译器的一个错误,请报告给https://github.com/erg-lang/erg\n原因来自: {fn_name}:{line}"), - "traditional_chinese" => format!("這是Erg編譯器的一個錯誤,請報告給https://github.com/erg-lang/erg\n原因來自: {fn_name}:{line}"), - "english" => format!("this is a bug of the Erg compiler, please report it to https://github.com/erg-lang/erg\ncaused from: {fn_name}:{line}"), + "japanese" => format!("これはErg compilerのバグです、開発者に報告して下さい ({URL})\n{fn_name}:{line}より発生"), + "simplified_chinese" => format!("这是Erg编译器的一个错误,请报告给{URL}\n原因来自: {fn_name}:{line}"), + "traditional_chinese" => format!("這是Erg編譯器的一個錯誤,請報告給{URL}\n原因來自: {fn_name}:{line}"), + "english" => format!("this is a bug of the Erg compiler, please report it to {URL}\ncaused from: {fn_name}:{line}"), ), None, )) @@ -115,15 +120,16 @@ impl LexError { ) .into() }); + let name = StringSpan::new(name, Some(Color::Red), Some(Attribute::Underline)); Self::new(ErrorCore::new( errno, NameError, loc, switch_lang!( - "japanese" => format!("{RED}{name}{RESET}という変数は定義されていません"), - "simplified_chinese" => format!("{RED}{name}{RESET}未定义"), - "traditional_chinese" => format!("{RED}{name}{RESET}未定義"), - "english" => format!("{RED}{name}{RESET} is not defined"), + "japanese" => format!("{name}という変数は定義されていません"), + "simplified_chinese" => format!("{name}未定义"), + "traditional_chinese" => format!("{name}未定義"), + "english" => format!("{name} is not defined"), ), hint, )) @@ -158,6 +164,7 @@ pub type DesugaringResult = Result; pub struct ParserRunnerError { pub core: ErrorCore, pub input: Input, + pub theme: Theme, } impl_display_and_error!(ParserRunnerError); @@ -169,6 +176,9 @@ impl ErrorDisplay for ParserRunnerError { fn input(&self) -> &Input { &self.input } + fn theme(&self) -> &Theme { + &self.theme + } fn caused_by(&self) -> &str { "" } @@ -178,8 +188,8 @@ impl ErrorDisplay for ParserRunnerError { } impl ParserRunnerError { - pub const fn new(core: ErrorCore, input: Input) -> Self { - Self { core, input } + pub const fn new(core: ErrorCore, input: Input, theme: Theme) -> Self { + Self { core, input, theme } } } @@ -191,10 +201,10 @@ impl_stream_for_wrapper!(ParserRunnerErrors, ParserRunnerError); impl MultiErrorDisplay for ParserRunnerErrors {} impl ParserRunnerErrors { - pub fn convert(input: &Input, errs: ParseErrors) -> Self { + pub fn convert(input: &Input, errs: ParseErrors, theme: Theme) -> Self { Self( errs.into_iter() - .map(|err| ParserRunnerError::new(*err.0, input.clone())) + .map(|err| ParserRunnerError::new(*err.0, input.clone(), theme)) .collect(), ) } diff --git a/compiler/erg_parser/lex.rs b/compiler/erg_parser/lex.rs index ae33973c..3fe8d4d7 100644 --- a/compiler/erg_parser/lex.rs +++ b/compiler/erg_parser/lex.rs @@ -4,6 +4,7 @@ use std::cmp::Ordering; use erg_common::cache::CacheSet; use erg_common::config::ErgConfig; use erg_common::config::Input; +use erg_common::style::THEME; use erg_common::traits::{Locational, Runnable, Stream}; use erg_common::{debug_power_assert, fn_name_full, normalize_newline, switch_lang}; @@ -41,7 +42,7 @@ impl Runnable for LexerRunner { let lexer = Lexer::from_str(self.input().read()); let ts = lexer .lex() - .map_err(|errs| LexerRunnerErrors::convert(self.input(), errs))?; + .map_err(|errs| LexerRunnerErrors::convert(self.input(), errs, THEME))?; println!("{ts}"); Ok(0) } @@ -51,13 +52,13 @@ impl Runnable for LexerRunner { if cfg!(feature = "debug") { let ts = lexer .lex() - .map_err(|errs| LexerRunnerErrors::convert(self.input(), errs))?; + .map_err(|errs| LexerRunnerErrors::convert(self.input(), errs, THEME))?; println!("{ts}"); Ok(ts.to_string()) } else { Ok(lexer .lex() - .map_err(|errs| LexerRunnerErrors::convert(self.input(), errs))? + .map_err(|errs| LexerRunnerErrors::convert(self.input(), errs, THEME))? .to_string()) } } diff --git a/compiler/erg_parser/parse.rs b/compiler/erg_parser/parse.rs index 78c4c043..54072623 100644 --- a/compiler/erg_parser/parse.rs +++ b/compiler/erg_parser/parse.rs @@ -11,6 +11,7 @@ use erg_common::error::Location; use erg_common::option_enum_unwrap; use erg_common::set::Set as HashSet; use erg_common::str::Str; +use erg_common::style::THEME; use erg_common::traits::Runnable; use erg_common::traits::{Locational, Stream}; use erg_common::{ @@ -206,16 +207,16 @@ impl ParserRunner { pub fn parse_token_stream(&mut self, ts: TokenStream) -> Result { Parser::new(ts) .parse() - .map_err(|errs| ParserRunnerErrors::convert(self.input(), errs)) + .map_err(|errs| ParserRunnerErrors::convert(self.input(), errs, THEME)) } pub fn parse(&mut self, src: String) -> Result { let ts = Lexer::new(Input::Str(src)) .lex() - .map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?; + .map_err(|errs| ParserRunnerErrors::convert(self.input(), errs, THEME))?; Parser::new(ts) .parse() - .map_err(|errs| ParserRunnerErrors::convert(self.input(), errs)) + .map_err(|errs| ParserRunnerErrors::convert(self.input(), errs, THEME)) } } diff --git a/compiler/erg_parser/tests/parse_test.rs b/compiler/erg_parser/tests/parse_test.rs index 76bc8a76..5fe10fc4 100644 --- a/compiler/erg_parser/tests/parse_test.rs +++ b/compiler/erg_parser/tests/parse_test.rs @@ -1,5 +1,6 @@ use erg_common::config::{ErgConfig, Input}; use erg_common::error::MultiErrorDisplay; +use erg_common::style::THEME; use erg_common::traits::Runnable; use erg_parser::error::ParserRunnerErrors; @@ -58,7 +59,7 @@ fn parse_test_from_code(file_path: &'static str) -> Result<(), ParserRunnerError match parser.parse_token_stream( lexer .lex() - .map_err(|errs| ParserRunnerErrors::convert(&input, errs))?, + .map_err(|errs| ParserRunnerErrors::convert(&input, errs, THEME))?, ) { Ok(module) => { println!("{module}"); From d4f5674c5fd755de3b876336dc7f278b1b160aef Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Sat, 12 Nov 2022 18:04:14 +0900 Subject: [PATCH 04/12] Clean: specify color name --- compiler/erg_common/macros.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/erg_common/macros.rs b/compiler/erg_common/macros.rs index 4ab4eee0..d9ca66a7 100644 --- a/compiler/erg_common/macros.rs +++ b/compiler/erg_common/macros.rs @@ -400,7 +400,7 @@ macro_rules! log { (f $output: ident, $($arg: tt)*) => {{ if cfg!(feature = "debug") { - use $crate::color::RESET; + use $crate::color::{RESET, GREEN, RED}; $crate::debug_info!($output); write!($output, $($arg)*).unwrap(); write!($output, "{}", RESET).unwrap(); // color color anyway @@ -410,7 +410,7 @@ macro_rules! log { (c $color:ident, $($arg: tt)*) => {{ if cfg!(feature = "debug") { - use $crate::style::*; + use $crate::style::{RESET, GREEN, RED}; $crate::debug_info!(); print!("{}", $color); println!($($arg)*); @@ -420,9 +420,9 @@ macro_rules! log { (f+c $output:ident, $color:ident, $($arg: tt)*) => {{ if cfg!(feature = "debug") { - use $crate::style::*; + use $crate::style::{RESET, GREEN}; $crate::debug_info!($output); - write!($output, "{}", $color).unwrap(); + write!($output, "{}{}{}", $color, $($arg)*, RESET).unwrap(); write!($output, $($arg)*).unwrap(); write!($output, "{}", RESET).unwrap(); // reset color anyway $output.flush().unwrap(); From 7b5d20a3b358f0f44db609ef5b78e23ef1f0d631 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Sat, 12 Nov 2022 18:08:23 +0900 Subject: [PATCH 05/12] Add: `unicode` and `pretty` features flag --- Cargo.toml | 8 ++---- compiler/erg_common/Cargo.toml | 3 +- compiler/erg_common/style.rs | 48 ++++++++++++++++++++++++++++++++ compiler/erg_compiler/Cargo.toml | 2 ++ compiler/erg_parser/Cargo.toml | 2 ++ 5 files changed, 57 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d4ae26d2..ca80f407 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,11 +27,7 @@ homepage = "https://erg-lang.org/" [features] # when "debug" feature is turned on, that of the following crates will also be turned on. -debug = [ - "erg_common/debug", - "erg_parser/debug", - "erg_compiler/debug", -] +debug = ["erg_common/debug", "erg_parser/debug", "erg_compiler/debug"] japanese = [ "erg_common/japanese", "erg_parser/japanese", @@ -47,6 +43,8 @@ traditional_chinese = [ "erg_parser/traditional_chinese", "erg_compiler/traditional_chinese", ] +unicode = ["erg_common/unicode", "erg_parser/unicode", "erg_compiler/unicode"] +pretty = ["erg_common/pretty", "erg_parser/pretty", "erg_compiler/unicode"] pre-commit = [] [dependencies] diff --git a/compiler/erg_common/Cargo.toml b/compiler/erg_common/Cargo.toml index 96fc13f3..649edf26 100644 --- a/compiler/erg_common/Cargo.toml +++ b/compiler/erg_common/Cargo.toml @@ -9,13 +9,14 @@ edition.workspace = true repository.workspace = true homepage.workspace = true -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] debug = [] japanese = [] simplified_chinese = [] traditional_chinese = [] +unicode = [] +pretty = [] [target.'cfg(unix)'.dependencies] libc = { version = "0.2", default-features = false } diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index f466ac1c..6de2e52b 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -115,14 +115,38 @@ impl Characters { }; mark.to_string() } + #[cfg(not(feature = "unicode"))] pub fn left_bottom_line(&self) -> String { format!(" {}{} ", self.lbot, self.line) } + #[cfg(feature = "unicode")] + pub fn left_bottom_line(&self) -> String { + format!("{}{} ", self.lbot, self.line) + } + #[cfg(not(feature = "pretty"))] pub fn error_kind_format(&self, kind: &str, err_num: usize) -> String { const PADDING: usize = 4; format!("{kind}{}#{err_num:>0PADDING$}{}", self.lbrac, self.rbrac,) } + + #[cfg(feature = "pretty")] + pub fn error_kind_format(&self, kind: &str, err_num: usize) -> String { + const PADDING: usize = 4; + let emoji = if kind == "Error" { + "🚫" + } else if kind == "Warning" { + "⚠" + } else { + "😱" + }; + format!( + "{emoji} {kind}{}#{err_num:>0PADDING$}{}", + self.lbrac, self.rbrac, + ) + } +} + #[derive(Debug, Clone, Copy)] pub struct Theme { pub colors: ThemeColors, @@ -160,6 +184,7 @@ pub const THEME: Theme = Theme { characters: CHARS, }; +#[cfg(not(feature = "unicode"))] pub const CHARS: Characters = Characters { hat: '-', line: '-', @@ -170,6 +195,20 @@ pub const CHARS: Characters = Characters { lbrac: '[', rbrac: ']', }; + +#[cfg(feature = "unicode")] +pub const CHARS: Characters = Characters { + hat: '-', + line: '─', + vbar: '│', + wave: '~', + lbot: '╰', + vbreak: '·', + lbrac: '[', + rbrac: ']', +}; + +#[cfg(not(feature = "pretty"))] pub const COLORS: ThemeColors = ThemeColors { error: Color::Red, warning: Color::Yellow, @@ -178,6 +217,15 @@ pub const COLORS: ThemeColors = ThemeColors { hint: Color::Green, }; +#[cfg(feature = "pretty")] +pub const COLORS: ThemeColors = ThemeColors { + error: Color::CustomRed, + warning: Color::CustomYellow, + exception: Color::CustomMagenta, + gutter: Color::CustomCyan, + hint: Color::CustomGreen, +}; + #[derive(Debug)] pub struct StrSpan<'a> { span: &'a str, diff --git a/compiler/erg_compiler/Cargo.toml b/compiler/erg_compiler/Cargo.toml index 821ad7eb..eecd50a8 100644 --- a/compiler/erg_compiler/Cargo.toml +++ b/compiler/erg_compiler/Cargo.toml @@ -22,6 +22,8 @@ traditional_chinese = [ "erg_common/traditional_chinese", "erg_parser/traditional_chinese", ] +unicode = ["erg_common/unicode"] +pretty = ["erg_common/pretty"] [dependencies] erg_common = { version = "0.5.11", path = "../erg_common" } diff --git a/compiler/erg_parser/Cargo.toml b/compiler/erg_parser/Cargo.toml index 5a06a53d..abaece33 100644 --- a/compiler/erg_parser/Cargo.toml +++ b/compiler/erg_parser/Cargo.toml @@ -14,6 +14,8 @@ debug = ["erg_common/debug"] japanese = ["erg_common/japanese"] simplified_chinese = ["erg_common/simplified_chinese"] traditional_chinese = ["erg_common/traditional_chinese"] +unicode = ["erg_common/unicode"] +pretty = ["erg_common/pretty"] [dependencies] erg_common = { version = "0.5.11", path = "../erg_common" } From 35841d0647c7356a763cd56f8e6b67a71a956c04 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Sat, 12 Nov 2022 18:08:43 +0900 Subject: [PATCH 06/12] Clean: add doc comments --- compiler/erg_common/error.rs | 78 +++++++++++++++-- compiler/erg_common/style.rs | 147 ++++++++++++++++++++++++++++++--- compiler/erg_compiler/error.rs | 125 ++++++++++++++++++++++++++++ 3 files changed, 331 insertions(+), 19 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index 240d5498..5e5e89eb 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -222,23 +222,72 @@ impl From<&str> for ErrorKind { } } -/// points the location (of an error) in a code +/// +/// Points the location (of an error) in a code. +/// The beginning and end of each row and column where the error occurred. +/// Basically, the beginning and end of each row and column where the error occurred is kept. +/// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] pub enum Location { + /// + /// Error used when the error is caused by a discrepancy with a code on another line + /// + /// # Example + /// + /// Ownership error + /// + /// ``` + /// a: Nat = 1 + /// a.consume_ownership() // move occurs + /// + /// function(a) // borrowed after moved + /// ``` + /// + /// `a` moves ownership in a method(or function) that are defined and consume it. + /// + /// ``` + /// Location::RangePair { + /// ln_first: (2, 2), + /// col_first: (0, 1), + /// ln_second: (4, 4), + /// col_second: (9, 10), + /// } + /// ``` + /// RangePair { ln_first: (usize, usize), col_first: (usize, usize), ln_second: (usize, usize), col_second: (usize, usize), }, + /// + /// Location used for basic errors + /// ``` + /// // erg + /// a = 1 + /// a = 2 + /// // Value assigned to the structure + /// Location::Range { + /// ln_begin: 2, + /// col_begin: 0, + /// ln_end: 2, + /// col_end: 1, + /// } + /// ``` + /// Range { ln_begin: usize, col_begin: usize, ln_end: usize, col_end: usize, }, + /// Used for loss of location information when desugared. + /// If there are guaranteed to be multiple rows LineRange(usize, usize), + /// Used when Location information is lost when desugared + /// If it is guaranteed to be a single line Line(usize), + /// Used by default in case of loss of Location information #[default] Unknown, } @@ -320,8 +369,8 @@ impl Location { } } -/// Erg内で使われるエラーの共通部分 -/// 使用する場合は必ずwrapすること +/// In Erg, common parts used by error. +/// Must be wrap when to use. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ErrorCore { pub errno: usize, @@ -443,19 +492,26 @@ fn format_context( } /// format: -/// ```console +/// ``` /// Error[#{.errno}]: File {file}, line {.loc (as line)}, in {.caused_by} /// {.loc (as line)}| {src} /// {pointer} /// {.kind}: {.desc} +/// +/// {.hint} +/// /// ``` /// /// example: -/// ```console -/// Error[#12]: File , line 1, in -/// 1| 100 = i -/// ^^^ -/// SyntaxError: cannot assign to 100 +/// ``` +/// Error[#2223]: File , line 1, in +/// +/// 1 | 100 = i +/// --- +/// ╰─ SyntaxError: cannot assign to 100 +/// +/// hint: hint message here +/// /// ``` pub trait ErrorDisplay { fn core(&self) -> &ErrorCore; @@ -500,6 +556,7 @@ pub trait ErrorDisplay { Some(Attribute::Bold), ); + // When hint is None, hint desc is "" and empty line is displayed, but hint is Some(...), hint desc is "..." and filled by text if let Some(hint) = self.core().hint.as_ref() { let (hint_color, _) = theme.hint(); let mut hints = StringSpans::default(); @@ -606,6 +663,8 @@ pub trait ErrorDisplay { chars: &Characters, ) -> String { match self.core().loc { + // TODO: Current implementation does not allow for multiple descriptions of errors to be given at each location + // In the future, this will be implemented in a different structure that can handle multiple lines and multiple files Location::RangePair { ln_first, col_first, @@ -622,6 +681,7 @@ pub trait ErrorDisplay { chars, mark, ) + + "\n" // TODO: dealing with error chains + &format_context( self, ln_second.0, diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index 6de2e52b..ab07643a 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -115,15 +115,20 @@ impl Characters { }; mark.to_string() } + + // "`-" #[cfg(not(feature = "unicode"))] pub fn left_bottom_line(&self) -> String { format!(" {}{} ", self.lbot, self.line) } + // `╰─` #[cfg(feature = "unicode")] pub fn left_bottom_line(&self) -> String { format!("{}{} ", self.lbot, self.line) } + + // kind[padded error number] #[cfg(not(feature = "pretty"))] pub fn error_kind_format(&self, kind: &str, err_num: usize) -> String { const PADDING: usize = 4; @@ -226,6 +231,17 @@ pub const COLORS: ThemeColors = ThemeColors { hint: Color::CustomGreen, }; +/// +/// StrSpan is for const color adn attribute &str. +/// It is an immutable string. +/// # Example +/// ``` +///const URL: StrSpan = StrSpan::new( +/// "https://github.com/erg-lang/erg", +/// Some(Color::White), +/// Some(Attribute::Underline), +///); +/// ``` #[derive(Debug)] pub struct StrSpan<'a> { span: &'a str, @@ -267,6 +283,11 @@ impl std::fmt::Display for StrSpan<'_> { } } } + +/// +/// `StringSpan` is for coloring and attribute text. +/// String, Color(&str) and Attribute(&str) +/// #[derive(Debug)] pub struct StringSpan { span: String, @@ -283,6 +304,16 @@ impl StringSpan { } } + /// + /// Methods for pushing additional &str for strings that already have attributes or colors. + /// + /// # Example + /// ``` + /// let mut span = StringSpan::new("sample text", None, Attribute::Underline); + /// span.push_str("\n"); + /// span.push_str("Next break line text"); + /// println!("{span}"); // Two lines of text underlined are displayed + /// ``` pub fn push_str(&mut self, s: &str) { self.span.push_str(s); } @@ -307,12 +338,45 @@ impl std::fmt::Display for StringSpan { } } +/// +/// `StringSpans` is vector of `StringSpan` and almost the same as Vec\. +/// It is possible to change the color and attribute of each String. +/// That's why, if you don't change any color or attribute, you should use 'StringSpan' not `StringSpans` +/// +/// # Example +/// ``` +/// let mut spans = StringSpans::default(); +/// spans.push_srt("Default color is gray, "); +/// spans.push_str_with_color("and it is possible to color text.\n", Color::Red); +/// spans.push_str("Basically, this `StringSpans` is one sentence, "); +/// spans.push_str_with_color("so if you want to multiline sentences, you need to add `\n`.", Color::Magenta); +/// println!("{}", spans); // Pushed colored text are displayed +/// ``` +/// Basically,initialize by default with mutable. +/// Then, &str(s) are pushed to the Vec, specifying colors or attributes. +/// #[derive(Debug, Default)] pub struct StringSpans { spans: Vec, } impl StringSpans { + /// + /// It is possible push &str type with gray color to Vector. + /// + /// # Example + /// ``` + /// let mut spans = StringSpans::default() + /// spans.push_str("sample text"); + /// spans.push_str("\n"); + /// spans.push_str("new text here"); + /// println!("{}", spans); + /// /* + /// sample text + /// new text here + /// */ + /// + /// ``` pub fn push_str(&mut self, s: &str) { if self.is_same_color(Color::Gray) { self.spans.last_mut().unwrap().span.push_str(s); @@ -321,6 +385,18 @@ impl StringSpans { } } + /// + /// It is possible to push &str type with specify color to Vector. + /// + /// # Example + /// ``` + /// let mut spans = StringSpans::default(); + /// spans.push_str_with_color("Cyan color text", Color::Cyan); + /// spans.push_str_with_color("Red color text", Color::Red); + /// spans.push_str_with_color(", pushed texts become a single String.", Color::Yellow); + /// spans.push_str_with_color("\n If you want to add break lines, you should add `\n`.", Color::Magenta); + /// println!("{}", spans); + /// `` pub fn push_str_with_color(&mut self, s: &str, color: Color) { if self.is_same_color(color) { self.spans.last_mut().unwrap().span.push_str(s); @@ -329,6 +405,18 @@ impl StringSpans { } } + /// + /// Text can be pushed color and attribute to Vector. + /// When color or attribute are different, it will be pushed as different String. + /// + /// # Example + /// ``` + /// let mut spans = StringSpans::default(); + /// spans.push_str_with_color_and_attribute("Magenta and bold text\n", Color::Magenta, Attribute::Bold); + /// spans.push_str_with_color_and_attribute("White and underlined text", Color::White, Attribute::Underline); + /// spans.push_str_with_color_and_attribute("Must be specify the color and attribute", None, Attribute::Underline); + /// println!("{}", spans); + /// ``` pub fn push_str_with_color_and_attribute(&mut self, s: &str, color: Color, attr: Attribute) { if self.is_same_color(color) && self.is_same_attribute(attr) { self.spans.last_mut().unwrap().span.push_str(s); @@ -367,19 +455,58 @@ impl std::fmt::Display for StringSpans { mod tests { use super::*; #[test] - fn colorings_fg() { - println!("{DEEP_RED}Hello{RESET}, {RED}World{RESET}"); - println!("{DEEP_GREEN}Hello{RESET}, {GREEN}World{RESET}"); - println!("{YELLOW}Hello{RESET}, {DEEP_YELLOW}World{RESET}"); - println!("{DEEP_BLUE}Hello{RESET}, {BLUE}World{RESET}"); - println!("{CYAN}Hello{RESET}, {DEEP_CYAN}World{RESET}"); - println!("{MAGENTA}Hello{RESET}, {DEEP_MAGENTA}World{RESET}"); + fn text_fg_colorings() { + println!("{YELLOW}Hello{RESET}, {RED}World{RESET}"); + println!("{BLUE}Hello{RESET}, {GREEN}World{RESET}"); + println!("{MAGENTA}Hello{RESET}, {BLACK}World{RESET}"); println!("{GRAY}Hello{RESET}, {WHITE}World{RESET}"); + println!("{CUSTOM_BLUE}Hello{RESET}, {CUSTOM_CYAN}World{RESET}"); + println!("{CUSTOM_GRAY}Hello{RESET}, {CUSTOM_GREEN}World{RESET}"); + println!("{CUSTOM_MAGENTA}Hello{RESET}, {CUSTOM_RED}World{RESET}"); + println!("{CUSTOM_YELLOW}Hello{RESET}"); } #[test] - fn style_test() { - println!("{BOLD}bold{ATT_RESET}"); - println!("{UNDERLINE}UNDERLINED{ATT_RESET}"); + fn text_attribute() { + println!("{BOLD}bold{ATTR_RESET}"); + println!("{UNDERLINE}UNDERLINED{ATTR_RESET}"); + } + + #[test] + fn str_spans_test() { + let mut spans = StringSpans::default(); + spans.push_str("Gray is default color\n"); + spans.push_str("If you specify the color, "); + spans.push_str("you should use `push_str_with_color()`\n"); + + spans.push_str_with_color( + "It is possible to change text foreground color...\n", + Color::White, + ); + spans.push_str_with_color("Cyan color text, ", Color::Cyan); + spans.push_str_with_color("Black color text, ", Color::Black); + spans.push_str_with_color("Blue color text, ", Color::Blue); + spans.push_str_with_color("Red color text, ", Color::Red); + spans.push_str_with_color("pushed texts become a String.", Color::Yellow); + spans.push_str_with_color( + "\nIf you want to add break lines, you should add `\\n`.\n", + Color::Magenta, + ); + + spans.push_str_with_color( + "It is also possible to change text attribute...\n", + Color::White, + ); + spans.push_str_with_color_and_attribute( + "Green and bold text\n", + Color::Green, + Attribute::Bold, + ); + spans.push_str_with_color_and_attribute( + "White and underlined text", + Color::White, + Attribute::Underline, + ); + println!("{}", spans); } } diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index 9d7d0cb7..ac01ac73 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -1791,3 +1791,128 @@ pub type SingleCompileResult = Result; pub type CompileResult = Result; pub type CompileWarning = CompileError; pub type CompileWarnings = CompileErrors; + +#[cfg(test)] +mod test { + + use erg_common::{config::Input, error::Location}; + + use crate::ty::Type; + + use super::TyCheckError; + + #[test] + fn default_arg_error_test() { + let loc = Location::Range { + ln_begin: 1, + col_begin: 0, + ln_end: 1, + col_end: 5, + }; + let input = Input::Pipe("a = 1".to_string()); + let caused_by = "File name here basically"; + let desc = "Some kinds of error description here"; + let hint = Some("Some hint massage here\n".into()); + + let err = TyCheckError::syntax_error(input, 0, loc, caused_by.into(), desc, hint); + print!("{}", err); + + let loc = Location::Range { + ln_begin: 1, + col_begin: 24, + ln_end: 1, + col_end: 27, + }; + let input = Input::Pipe("Person = Class { name = Str }".to_string()); + let caused_by = "File name here basically"; + let err = TyCheckError::args_missing_error( + input, + 0, + loc, + "\"Callee name here\"", + caused_by.into(), + 0, + vec!["sample".into(), "args".into(), "here".into()], + ); + print!("{}", err); + + let loc = Location::Range { + ln_begin: 1, + col_begin: 0, + ln_end: 3, + col_end: 5, + }; + let input = Input::Pipe( + "\ +if True: + sample + end +" + .to_string(), + ); + let caused_by = "File name here basically"; + let err = TyCheckError::args_missing_error( + input, + 0, + loc, + "\"Callee name here\"", + caused_by.into(), + 0, + vec!["sample".into(), "args".into(), "here".into()], + ); + print!("{}", err); + + let loc = Location::RangePair { + ln_first: (1, 2), + col_first: (0, 1), + ln_second: (4, 4), + col_second: (9, 10), + }; + let input = Input::Pipe( + "\ +a: Nat = 1 +a.ownership_is_moved() + +function(a) +" + .to_string(), + ); + let err = TyCheckError::checker_bug(input, 0, loc, "file_name", 0); + print!("{}", err); + + let loc = Location::Range { + ln_begin: 1, + col_begin: 0, + ln_end: 1, + col_end: 3, + }; + let input = Input::Pipe("add(x, y):Nat = x - y".to_string()); + let err = TyCheckError::checker_bug(input, 0, loc, "file_name", 0); + print!("{}", err); + + let loc = Location::Range { + ln_begin: 1, + col_begin: 11, + ln_end: 1, + col_end: 14, + }; + let expect = Type::Nat; + let found = Type::Obj; + let input = Input::Pipe("add(x, y): Nat = x - y".to_string()); + let caused_by = "File name here basically"; + let err = TyCheckError::return_type_error( + input, + 0, + loc, + caused_by.into(), + "name", + &expect, + &found, + ); + print!("{}", err); + + let input = Input::Pipe("Dummy code here".to_string()); + let err = TyCheckError::unreachable(input, "file name here", 1); + print!("{}", err); + } +} From 2f33460c775252b42600ba2c61cffd4c761d5ea4 Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama Date: Sun, 13 Nov 2022 20:05:30 +0900 Subject: [PATCH 07/12] Update style.rs --- compiler/erg_common/style.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index ab07643a..e63fe51d 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -232,15 +232,15 @@ pub const COLORS: ThemeColors = ThemeColors { }; /// -/// StrSpan is for const color adn attribute &str. +/// `StrSpan` is for const color and attribute &str. /// It is an immutable string. /// # Example /// ``` -///const URL: StrSpan = StrSpan::new( +/// const URL: StrSpan = StrSpan::new( /// "https://github.com/erg-lang/erg", /// Some(Color::White), /// Some(Attribute::Underline), -///); +/// ); /// ``` #[derive(Debug)] pub struct StrSpan<'a> { @@ -475,7 +475,7 @@ mod tests { #[test] fn str_spans_test() { let mut spans = StringSpans::default(); - spans.push_str("Gray is default color\n"); + spans.push_str("Gray is the default color\n"); spans.push_str("If you specify the color, "); spans.push_str("you should use `push_str_with_color()`\n"); @@ -483,10 +483,10 @@ mod tests { "It is possible to change text foreground color...\n", Color::White, ); - spans.push_str_with_color("Cyan color text, ", Color::Cyan); - spans.push_str_with_color("Black color text, ", Color::Black); - spans.push_str_with_color("Blue color text, ", Color::Blue); - spans.push_str_with_color("Red color text, ", Color::Red); + spans.push_str_with_color("Cyan text, ", Color::Cyan); + spans.push_str_with_color("Black text, ", Color::Black); + spans.push_str_with_color("Blue text, ", Color::Blue); + spans.push_str_with_color("Red text, ", Color::Red); spans.push_str_with_color("pushed texts become a String.", Color::Yellow); spans.push_str_with_color( "\nIf you want to add break lines, you should add `\\n`.\n", From 0f208054e1564f6c6c12acb206b158726b54d713 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Mon, 14 Nov 2022 07:30:10 +0900 Subject: [PATCH 08/12] Clean: closer to struct --- compiler/erg_common/style.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index e63fe51d..0ef1b0e6 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -93,6 +93,24 @@ pub struct ThemeColors { pub hint: Color, } +#[cfg(not(feature = "pretty"))] +pub const COLORS: ThemeColors = ThemeColors { + error: Color::Red, + warning: Color::Yellow, + exception: Color::Magenta, + gutter: Color::Cyan, + hint: Color::Green, +}; + +#[cfg(feature = "pretty")] +pub const COLORS: ThemeColors = ThemeColors { + error: Color::CustomRed, + warning: Color::CustomYellow, + exception: Color::CustomMagenta, + gutter: Color::CustomCyan, + hint: Color::CustomGreen, +}; + #[derive(Debug, Clone, Copy)] pub struct Characters { pub hat: char, // error @@ -213,24 +231,6 @@ pub const CHARS: Characters = Characters { rbrac: ']', }; -#[cfg(not(feature = "pretty"))] -pub const COLORS: ThemeColors = ThemeColors { - error: Color::Red, - warning: Color::Yellow, - exception: Color::Magenta, - gutter: Color::Cyan, - hint: Color::Green, -}; - -#[cfg(feature = "pretty")] -pub const COLORS: ThemeColors = ThemeColors { - error: Color::CustomRed, - warning: Color::CustomYellow, - exception: Color::CustomMagenta, - gutter: Color::CustomCyan, - hint: Color::CustomGreen, -}; - /// /// `StrSpan` is for const color and attribute &str. /// It is an immutable string. From bdf47dea72301108f35521d6f61c345445b7246d Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Mon, 14 Nov 2022 07:46:22 +0900 Subject: [PATCH 09/12] Clean: remove pub from chars and add reversed --- compiler/erg_common/error.rs | 97 ++++++++++++++++++++++++------------ compiler/erg_common/style.rs | 35 +++++++------ 2 files changed, 84 insertions(+), 48 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index 5e5e89eb..5e1572b8 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -440,14 +440,13 @@ fn format_context( ln_end: usize, col_begin: usize, col_end: usize, - // kinds of error color and gutter(line number and vertical bar) - colors: (Color, Color), + err_color: Color, + gutter_color: Color, // for formatting points chars: &Characters, // kinds of error for specify the color mark: char, ) -> String { - let (err_color, gutter_color) = colors; let mark = mark.to_string(); let codes = if e.input().is_repl() { vec![e.input().reread()] @@ -457,10 +456,11 @@ fn format_context( let mut context = StringSpans::default(); let final_step = ln_end - ln_begin; let max_digit = ln_end.to_string().len(); - let offset = format!("{} {} ", &" ".repeat(max_digit), chars.vbreak); + let (vbreak, vbar) = chars.gutters(); + let offset = format!("{} {} ", &" ".repeat(max_digit), vbreak); for (i, lineno) in (ln_begin..=ln_end).enumerate() { context.push_str_with_color( - &format!("{: String { match self.core().loc { // TODO: Current implementation does not allow for multiple descriptions of errors to be given at each location - // In the future, this will be implemented in a different structure that can handle multiple lines and multiple files + // In the future, this will be implemented in a different structure that can handle multiple lines and files Location::RangePair { ln_first, col_first, @@ -677,7 +700,8 @@ pub trait ErrorDisplay { ln_first.1, col_first.0, col_first.1, - colors, + err_color, + gutter_color, chars, mark, ) + @@ -688,7 +712,8 @@ pub trait ErrorDisplay { ln_second.1, col_second.0, col_second.1, - colors, + err_color, + gutter_color, chars, mark, ) @@ -699,10 +724,18 @@ pub trait ErrorDisplay { ln_end, col_end, } => format_context( - self, ln_begin, ln_end, col_begin, col_end, colors, chars, mark, + self, + ln_begin, + ln_end, + col_begin, + col_end, + err_color, + gutter_color, + chars, + mark, ), Location::LineRange(ln_begin, ln_end) => { - let (err_color, gutter_color) = colors; + let (_, vbar) = chars.gutters(); let mut cxt = StringSpans::default(); let codes = if self.input().is_repl() { vec![self.input().reread()] @@ -711,7 +744,7 @@ pub trait ErrorDisplay { }; let mark = mark.to_string(); for (i, lineno) in (ln_begin..=ln_end).enumerate() { - cxt.push_str_with_color(&format!("{lineno} {}", chars.vbar), err_color); + cxt.push_str_with_color(&format!("{lineno} {}", vbar), err_color); cxt.push_str(&codes[i]); cxt.push_str(&" ".repeat(lineno.to_string().len() + 3)); // +3 means ` | ` cxt.push_str_with_color(&mark.repeat(cmp::max(1, codes[i].len())), gutter_color) @@ -719,14 +752,14 @@ pub trait ErrorDisplay { cxt.to_string() } Location::Line(lineno) => { - let (_, gutter_color) = colors; + let (_, vbar) = chars.gutters(); let code = if self.input().is_repl() { self.input().reread() } else { self.input().reread_lines(lineno, lineno).remove(0) }; let mut cxt = StringSpans::default(); - cxt.push_str_with_color(&format!(" {lineno} {} ", chars.vbar), gutter_color); + cxt.push_str_with_color(&format!(" {lineno} {} ", vbar), gutter_color); cxt.push_str(&code); cxt.push_str("\n"); cxt.to_string() @@ -735,9 +768,9 @@ pub trait ErrorDisplay { Input::File(_) => "\n".to_string(), other => { - let (_, gutter_color) = colors; + let (_, vbar) = chars.gutters(); let mut cxt = StringSpans::default(); - cxt.push_str_with_color(&format!(" ? {}", chars.vbar), gutter_color); + cxt.push_str_with_color(&format!(" ? {}", vbar), gutter_color); cxt.push_str(&other.reread()); cxt.to_string() } diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index 0ef1b0e6..7b1b62c8 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -1,6 +1,7 @@ pub const ATTR_RESET: &str = "\x1b[0m"; pub const BOLD: &str = "\x1b[1m"; pub const UNDERLINE: &str = "\x1b[4m"; +pub const REVERSED: &str = "\x1b[7m"; // Escape sequences change the color of the terminal pub const RESET: &str = "\x1b[m"; @@ -72,6 +73,7 @@ pub enum Attribute { Reset, Underline, Bold, + Reversed, } impl Attribute { @@ -80,6 +82,7 @@ impl Attribute { Attribute::Reset => ATTR_RESET, Attribute::Underline => UNDERLINE, Attribute::Bold => BOLD, + Attribute::Reversed => REVERSED, } } } @@ -113,14 +116,14 @@ pub const COLORS: ThemeColors = ThemeColors { #[derive(Debug, Clone, Copy)] pub struct Characters { - pub hat: char, // error - pub wave: char, // exception - pub line: char, // warning and left bottom line - pub vbar: char, // gutter separator - pub lbot: char, // left bottom curve - pub vbreak: char, // gutter omission - pub lbrac: char, // error kind modifier left bracket - pub rbrac: char, // error kind modifier right bracket + hat: char, // error + wave: char, // exception + line: char, // warning and left bottom line + vbar: char, // gutter separator + lbot: char, // left bottom curve + vbreak: char, // gutter omission + lbrac: char, // error kind modifier left bracket + rbrac: char, // error kind modifier right bracket } impl Characters { @@ -134,13 +137,17 @@ impl Characters { mark.to_string() } - // "`-" + pub fn gutters(&self) -> (char, char) { + (self.vbreak, self.vbar) + } + + // " `- " #[cfg(not(feature = "unicode"))] pub fn left_bottom_line(&self) -> String { format!(" {}{} ", self.lbot, self.line) } - // `╰─` + // `╰─ ` #[cfg(feature = "unicode")] pub fn left_bottom_line(&self) -> String { format!("{}{} ", self.lbot, self.line) @@ -196,10 +203,6 @@ impl Theme { pub const fn hint(&self) -> (Color, char) { (self.colors.hint, self.characters.wave) } - - pub fn error_kind_format(&self, kind: &str, err_num: usize) -> String { - self.characters.error_kind_format(kind, err_num) - } } pub const THEME: Theme = Theme { @@ -463,13 +466,13 @@ mod tests { println!("{CUSTOM_BLUE}Hello{RESET}, {CUSTOM_CYAN}World{RESET}"); println!("{CUSTOM_GRAY}Hello{RESET}, {CUSTOM_GREEN}World{RESET}"); println!("{CUSTOM_MAGENTA}Hello{RESET}, {CUSTOM_RED}World{RESET}"); - println!("{CUSTOM_YELLOW}Hello{RESET}"); } #[test] fn text_attribute() { - println!("{BOLD}bold{ATTR_RESET}"); + println!("{BOLD}BOLD{ATTR_RESET}"); println!("{UNDERLINE}UNDERLINED{ATTR_RESET}"); + println!("{REVERSED}REVERSED{ATTR_RESET}") } #[test] From b2c75b1c380d698a0af7975216683844c4936056 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Mon, 14 Nov 2022 07:49:34 +0900 Subject: [PATCH 10/12] Clean: `StringSpan` to `StyledString` --- compiler/erg_common/error.rs | 28 +++++----- compiler/erg_common/style.rs | 51 +++++++++--------- compiler/erg_compiler/error.rs | 96 +++++++++++++++++----------------- compiler/erg_parser/error.rs | 6 +-- 4 files changed, 91 insertions(+), 90 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index 5e1572b8..4964e329 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -10,12 +10,12 @@ use crate::config::Input; use crate::style::Attribute; use crate::style::Characters; use crate::style::Color; -use crate::style::StrSpan; -use crate::style::StringSpan; -use crate::style::StringSpans; +use crate::style::StyledStr; +use crate::style::StyledString; +use crate::style::StyledStrings; use crate::style::Theme; use crate::traits::{Locational, Stream}; -use crate::{fmt_option, impl_display_from_debug, switch_lang}; +use crate::{impl_display_from_debug, switch_lang}; /// ErrorKindと言っているが、ErrorだけでなくWarning, Exceptionも含まれる /// Numbering of this is not specifically related to ErrFmt.errno(). @@ -412,7 +412,7 @@ impl ErrorCore { } pub fn bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self { - const URL: StrSpan = StrSpan::new( + const URL: StyledStr = StyledStr::new( "https://github.com/erg-lang/erg", Some(Color::White), Some(Attribute::Underline), @@ -453,7 +453,7 @@ fn format_context( } else { e.input().reread_lines(ln_begin, ln_end) }; - let mut context = StringSpans::default(); + let mut context = StyledStrings::default(); let final_step = ln_end - ln_begin; let max_digit = ln_end.to_string().len(); let (vbreak, vbar) = chars.gutters(); @@ -550,7 +550,7 @@ pub trait ErrorDisplay { }; let (gutter_color, chars) = theme.characters(); - let kind = StringSpan::new( + let kind = StyledString::new( &chars.error_kind_format(kind, self.core().errno), Some(color), Some(Attribute::Bold), @@ -559,7 +559,7 @@ pub trait ErrorDisplay { // When hint is None, hint desc is "" and empty line is displayed, but hint is Some(...), hint desc is "..." and filled by text if let Some(hint) = self.core().hint.as_ref() { let (hint_color, _) = theme.hint(); - let mut hints = StringSpans::default(); + let mut hints = StyledStrings::default(); hints.push_str_with_color_and_attribute("hint: ", hint_color, Attribute::Bold); hints.push_str(hint); format!( @@ -602,7 +602,7 @@ pub trait ErrorDisplay { (theme.exception(), "Exception") }; let (gutter_color, chars) = theme.characters(); - let kind = StringSpan::new( + let kind = StyledString::new( &chars.error_kind_format(kind, self.core().errno), Some(color), Some(Attribute::Bold), @@ -611,7 +611,7 @@ pub trait ErrorDisplay { // When hint is None, hint desc is "" and empty line is displayed, but hint is Some(...), hint desc is "..." and filled by text if let Some(hint) = self.core().hint.as_ref() { let (hint_color, _) = theme.hint(); - let mut hints = StringSpans::default(); + let mut hints = StyledStrings::default(); hints.push_str_with_color_and_attribute("hint: ", hint_color, Attribute::Bold); hints.push_str(hint); writeln!( @@ -650,7 +650,7 @@ pub trait ErrorDisplay { } } - fn format_header(&self, kind: StringSpan) -> String { + fn format_header(&self, kind: StyledString) -> String { let loc = match self.core().loc { Location::Range { ln_begin, ln_end, .. @@ -736,7 +736,7 @@ pub trait ErrorDisplay { ), Location::LineRange(ln_begin, ln_end) => { let (_, vbar) = chars.gutters(); - let mut cxt = StringSpans::default(); + let mut cxt = StyledStrings::default(); let codes = if self.input().is_repl() { vec![self.input().reread()] } else { @@ -758,7 +758,7 @@ pub trait ErrorDisplay { } else { self.input().reread_lines(lineno, lineno).remove(0) }; - let mut cxt = StringSpans::default(); + let mut cxt = StyledStrings::default(); cxt.push_str_with_color(&format!(" {lineno} {} ", vbar), gutter_color); cxt.push_str(&code); cxt.push_str("\n"); @@ -769,7 +769,7 @@ pub trait ErrorDisplay { other => { let (_, vbar) = chars.gutters(); - let mut cxt = StringSpans::default(); + let mut cxt = StyledStrings::default(); cxt.push_str_with_color(&format!(" ? {}", vbar), gutter_color); cxt.push_str(&other.reread()); cxt.to_string() diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index 7b1b62c8..e434698f 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -235,24 +235,24 @@ pub const CHARS: Characters = Characters { }; /// -/// `StrSpan` is for const color and attribute &str. +/// `StyledStr` is for const color and attribute &str. /// It is an immutable string. /// # Example /// ``` -/// const URL: StrSpan = StrSpan::new( +/// const URL: StyledStr = StyledStr::new( /// "https://github.com/erg-lang/erg", /// Some(Color::White), /// Some(Attribute::Underline), /// ); /// ``` #[derive(Debug)] -pub struct StrSpan<'a> { +pub struct StyledStr<'a> { span: &'a str, color: Option, attribute: Option, } -impl<'a> StrSpan<'a> { +impl<'a> StyledStr<'a> { pub const fn new<'b: 'a>( span: &'b str, color: Option, @@ -266,7 +266,7 @@ impl<'a> StrSpan<'a> { } } -impl std::fmt::Display for StrSpan<'_> { +impl std::fmt::Display for StyledStr<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match (self.color, self.attribute) { (None, None) => todo!(), @@ -288,17 +288,17 @@ impl std::fmt::Display for StrSpan<'_> { } /// -/// `StringSpan` is for coloring and attribute text. +/// `StyledString` is for coloring and attribute text. /// String, Color(&str) and Attribute(&str) /// #[derive(Debug)] -pub struct StringSpan { +pub struct StyledString { span: String, color: Option, attribute: Option, } -impl StringSpan { +impl StyledString { pub fn new(s: &str, color: Option, attribute: Option) -> Self { Self { span: String::from(s), @@ -312,7 +312,7 @@ impl StringSpan { /// /// # Example /// ``` - /// let mut span = StringSpan::new("sample text", None, Attribute::Underline); + /// let mut span = StyledString::new("sample text", None, Attribute::Underline); /// span.push_str("\n"); /// span.push_str("Next break line text"); /// println!("{span}"); // Two lines of text underlined are displayed @@ -322,7 +322,7 @@ impl StringSpan { } } -impl std::fmt::Display for StringSpan { +impl std::fmt::Display for StyledString { fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result { match (self.color, self.attribute) { (None, None) => write!(f, "{}", self.span), @@ -342,16 +342,16 @@ impl std::fmt::Display for StringSpan { } /// -/// `StringSpans` is vector of `StringSpan` and almost the same as Vec\. +/// `StyledStrings` is vector of `StyledString` and almost the same as Vec\. /// It is possible to change the color and attribute of each String. -/// That's why, if you don't change any color or attribute, you should use 'StringSpan' not `StringSpans` +/// That's why, if you don't change any color or attribute, you should use 'StyledString' not `StyledStrings` /// /// # Example /// ``` -/// let mut spans = StringSpans::default(); +/// let mut spans = StyledStrings::default(); /// spans.push_srt("Default color is gray, "); /// spans.push_str_with_color("and it is possible to color text.\n", Color::Red); -/// spans.push_str("Basically, this `StringSpans` is one sentence, "); +/// spans.push_str("Basically, this `StyledStrings` is one sentence, "); /// spans.push_str_with_color("so if you want to multiline sentences, you need to add `\n`.", Color::Magenta); /// println!("{}", spans); // Pushed colored text are displayed /// ``` @@ -359,17 +359,17 @@ impl std::fmt::Display for StringSpan { /// Then, &str(s) are pushed to the Vec, specifying colors or attributes. /// #[derive(Debug, Default)] -pub struct StringSpans { - spans: Vec, +pub struct StyledStrings { + spans: Vec, } -impl StringSpans { +impl StyledStrings { /// /// It is possible push &str type with gray color to Vector. /// /// # Example /// ``` - /// let mut spans = StringSpans::default() + /// let mut spans = StyledStrings::default() /// spans.push_str("sample text"); /// spans.push_str("\n"); /// spans.push_str("new text here"); @@ -384,7 +384,7 @@ impl StringSpans { if self.is_same_color(Color::Gray) { self.spans.last_mut().unwrap().span.push_str(s); } else { - self.spans.push(StringSpan::new(s, None, None)); + self.spans.push(StyledString::new(s, None, None)); } } @@ -393,7 +393,7 @@ impl StringSpans { /// /// # Example /// ``` - /// let mut spans = StringSpans::default(); + /// let mut spans = StyledStrings::default(); /// spans.push_str_with_color("Cyan color text", Color::Cyan); /// spans.push_str_with_color("Red color text", Color::Red); /// spans.push_str_with_color(", pushed texts become a single String.", Color::Yellow); @@ -404,7 +404,7 @@ impl StringSpans { if self.is_same_color(color) { self.spans.last_mut().unwrap().span.push_str(s); } else { - self.spans.push(StringSpan::new(s, Some(color), None)); + self.spans.push(StyledString::new(s, Some(color), None)); } } @@ -414,7 +414,7 @@ impl StringSpans { /// /// # Example /// ``` - /// let mut spans = StringSpans::default(); + /// let mut spans = StyledStrings::default(); /// spans.push_str_with_color_and_attribute("Magenta and bold text\n", Color::Magenta, Attribute::Bold); /// spans.push_str_with_color_and_attribute("White and underlined text", Color::White, Attribute::Underline); /// spans.push_str_with_color_and_attribute("Must be specify the color and attribute", None, Attribute::Underline); @@ -424,7 +424,8 @@ impl StringSpans { if self.is_same_color(color) && self.is_same_attribute(attr) { self.spans.last_mut().unwrap().span.push_str(s); } else { - self.spans.push(StringSpan::new(s, Some(color), Some(attr))); + self.spans + .push(StyledString::new(s, Some(color), Some(attr))); } } @@ -445,7 +446,7 @@ impl StringSpans { } } -impl std::fmt::Display for StringSpans { +impl std::fmt::Display for StyledStrings { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { for span in self.spans.iter() { write!(f, "{}", span)?; @@ -477,7 +478,7 @@ mod tests { #[test] fn str_spans_test() { - let mut spans = StringSpans::default(); + let mut spans = StyledStrings::default(); spans.push_str("Gray is the default color\n"); spans.push_str("If you specify the color, "); spans.push_str("you should use `push_str_with_color()`\n"); diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index ac01ac73..d287a8f3 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -4,7 +4,7 @@ use erg_common::astr::AtomicStr; use erg_common::config::Input; use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay}; use erg_common::set::Set; -use erg_common::style::{Attribute, Color, StrSpan, StringSpan, Theme, THEME}; +use erg_common::style::{Attribute, Color, StyledStr, StyledString, Theme, THEME}; use erg_common::traits::{Locational, Stream}; use erg_common::vis::Visibility; use erg_common::{ @@ -146,7 +146,7 @@ impl ErrorDisplay for CompileError { } } -const URL: StrSpan = StrSpan::new( +const URL: StyledStr = StyledStr::new( "https://github.com/erg-lang/erg", Some(Color::White), Some(Attribute::Underline), @@ -377,13 +377,13 @@ impl TyCheckError { ), None => "".into(), }; - let name = StringSpan::new( + let name = StyledString::new( &format!("{}{}", name, ord), Some(WARNING), Some(Attribute::Bold), ); - let expect = StringSpan::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); - let found = StringSpan::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); + let expect = StyledString::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); + let found = StyledString::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -411,8 +411,8 @@ impl TyCheckError { expect: &Type, found: &Type, ) -> Self { - let expect = StringSpan::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); - let found = StringSpan::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); + let expect = StyledString::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); + let found = StyledString::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -465,8 +465,8 @@ impl TyCheckError { expect: usize, found: usize, ) -> Self { - let expect = StringSpan::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); - let found = StringSpan::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); + let expect = StyledString::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); + let found = StyledString::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -555,17 +555,17 @@ impl TyCheckError { kw_args_len: usize, ) -> Self { let name = readable_name(callee_name); - let expect = StringSpan::new( + let expect = StyledString::new( &format!("{}", params_len), Some(HINT), Some(Attribute::Bold), ); - let pos_args_len = StringSpan::new( + let pos_args_len = StyledString::new( &format!("{}", pos_args_len), Some(ERR), Some(Attribute::Bold), ); - let kw_args_len = StringSpan::new( + let kw_args_len = StyledString::new( &format!("{}", kw_args_len), Some(ERR), Some(Attribute::Bold), @@ -620,7 +620,7 @@ passed keyword args: {kw_args_len}" missing_params: Vec, ) -> Self { let name = readable_name(callee_name); - let vec_cxt = StringSpan::new( + let vec_cxt = StyledString::new( &fmt_vec(&missing_params), Some(WARNING), Some(Attribute::Bold), @@ -652,7 +652,7 @@ passed keyword args: {kw_args_len}" arg_name: &str, ) -> Self { let name = readable_name(callee_name); - let found = StringSpan::new(arg_name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(arg_name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -680,7 +680,7 @@ passed keyword args: {kw_args_len}" param_name: &str, ) -> Self { let name = readable_name(callee_name); - let found = StringSpan::new(param_name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(param_name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -707,8 +707,8 @@ passed keyword args: {kw_args_len}" loc: Location, caused_by: AtomicStr, ) -> Self { - let lhs_t = StringSpan::new(&format!("{}", lhs_t), Some(WARNING), Some(Attribute::Bold)); - let rhs_t = StringSpan::new(&format!("{}", rhs_t), Some(WARNING), Some(Attribute::Bold)); + let lhs_t = StyledString::new(&format!("{}", lhs_t), Some(WARNING), Some(Attribute::Bold)); + let rhs_t = StyledString::new(&format!("{}", rhs_t), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -735,8 +735,8 @@ passed keyword args: {kw_args_len}" loc: Location, caused_by: AtomicStr, ) -> Self { - let lhs_t = StringSpan::new(&format!("{}", lhs_t), Some(WARNING), Some(Attribute::Bold)); - let rhs_t = StringSpan::new(&format!("{}", rhs_t), Some(WARNING), Some(Attribute::Bold)); + let lhs_t = StyledString::new(&format!("{}", lhs_t), Some(WARNING), Some(Attribute::Bold)); + let rhs_t = StyledString::new(&format!("{}", rhs_t), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -763,8 +763,8 @@ passed keyword args: {kw_args_len}" loc: Location, caused_by: AtomicStr, ) -> Self { - let sub_t = StringSpan::new(&format!("{}", sub_t), Some(WARNING), Some(Attribute::Bold)); - let sup_t = StringSpan::new(&format!("{}", sup_t), Some(WARNING), Some(Attribute::Bold)); + let sub_t = StyledString::new(&format!("{}", sub_t), Some(WARNING), Some(Attribute::Bold)); + let sup_t = StyledString::new(&format!("{}", sup_t), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -790,8 +790,8 @@ passed keyword args: {kw_args_len}" rhs: &Predicate, caused_by: AtomicStr, ) -> Self { - let lhs = StringSpan::new(&format!("{}", lhs), Some(WARNING), Some(Attribute::Bold)); - let rhs = StringSpan::new(&format!("{}", rhs), Some(WARNING), Some(Attribute::Bold)); + let lhs = StyledString::new(&format!("{}", lhs), Some(WARNING), Some(Attribute::Bold)); + let rhs = StyledString::new(&format!("{}", rhs), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -871,7 +871,7 @@ passed keyword args: {kw_args_len}" name: &str, hint: Option, ) -> Self { - let found = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -910,9 +910,9 @@ passed keyword args: {kw_args_len}" found: &Type, hint: Option, ) -> Self { - let member_name = StringSpan::new(member_name, Some(WARNING), Some(Attribute::Bold)); - let expect = StringSpan::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); - let found = StringSpan::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); + let member_name = StyledString::new(member_name, Some(WARNING), Some(Attribute::Bold)); + let expect = StyledString::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); + let found = StyledString::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -941,7 +941,7 @@ passed keyword args: {kw_args_len}" class_type: &Type, hint: Option, ) -> Self { - let member_name = StringSpan::new(member_name, Some(WARNING), Some(Attribute::Bold)); + let member_name = StyledString::new(member_name, Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -970,7 +970,7 @@ passed keyword args: {kw_args_len}" class_type: &Type, hint: Option, ) -> Self { - let member_name = StringSpan::new(member_name, Some(WARNING), Some(Attribute::Bold)); + let member_name = StyledString::new(member_name, Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -996,7 +996,7 @@ passed keyword args: {kw_args_len}" loc: Location, caused_by: AtomicStr, ) -> Self { - let found = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -1177,7 +1177,7 @@ impl OwnershipError { moved_loc: Location, caused_by: S, ) -> Self { - let found = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -1294,8 +1294,8 @@ impl LowerError { found_t: &Type, ) -> Self { let name = readable_name(name); - let expect = StringSpan::new(&format!("{}", spec_t), Some(HINT), Some(Attribute::Bold)); - let found = StringSpan::new(&format!("{}", found_t), Some(ERR), Some(Attribute::Bold)); + let expect = StyledString::new(&format!("{}", spec_t), Some(HINT), Some(Attribute::Bold)); + let found = StyledString::new(&format!("{}", found_t), Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -1332,7 +1332,7 @@ impl LowerError { ) .into() }); - let found = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -1369,7 +1369,7 @@ impl LowerError { ) .into() }); - let found = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -1408,7 +1408,7 @@ impl LowerError { ) .into() }); - let found = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -1434,7 +1434,7 @@ impl LowerError { caused_by: AtomicStr, name: &str, ) -> Self { - let name = StringSpan::new(readable_name(name), Some(WARNING), Some(Attribute::Bold)); + let name = StyledString::new(readable_name(name), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -1460,7 +1460,7 @@ impl LowerError { name: &str, caused_by: AtomicStr, ) -> Self { - let name = StringSpan::new(readable_name(name), Some(WARNING), Some(Attribute::Bold)); + let name = StyledString::new(readable_name(name), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -1480,7 +1480,7 @@ impl LowerError { } pub fn del_error(input: Input, errno: usize, ident: &Identifier, caused_by: AtomicStr) -> Self { - let name = StringSpan::new( + let name = StyledString::new( readable_name(ident.inspect()), Some(WARNING), Some(Attribute::Bold), @@ -1527,7 +1527,7 @@ impl LowerError { "english" => "public", ) }; - let found = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( errno, @@ -1554,8 +1554,8 @@ impl LowerError { superclass: &Type, caused_by: S, ) -> Self { - let name = StringSpan::new(name, Some(ERR), Some(Attribute::Bold)); - let superclass = StringSpan::new( + let name = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); + let superclass = StyledString::new( &format!("{}", superclass), Some(WARNING), Some(Attribute::Bold), @@ -1658,18 +1658,18 @@ impl LowerError { ) -> Self { let hint = match (similar_erg_mod, similar_py_mod) { (Some(erg), Some(py)) => { - let erg = StringSpan::new(&erg, Some(WARNING), Some(Attribute::Bold)); - let py = StringSpan::new(&py, Some(WARNING), Some(Attribute::Bold)); + let erg = StyledString::new(&erg, Some(WARNING), Some(Attribute::Bold)); + let py = StyledString::new(&py, Some(WARNING), Some(Attribute::Bold)); Some(format!( "similar name erg module {erg} and python module {py} exists (to import python modules, use `pyimport`)", )) } (Some(erg), None) => { - let erg = StringSpan::new(&erg, Some(WARNING), Some(Attribute::Bold)); + let erg = StyledString::new(&erg, Some(WARNING), Some(Attribute::Bold)); Some(format!("similar name erg module exists: {erg}")) } (None, Some(py)) => { - let py = StringSpan::new(&py, Some(WARNING), Some(Attribute::Bold)); + let py = StyledString::new(&py, Some(WARNING), Some(Attribute::Bold)); Some(format!("similar name python module exists: {py} (to import python modules, use `pyimport`)")) } (None, None) => None, @@ -1731,8 +1731,8 @@ impl LowerError { cast_to: &Type, hint: Option, ) -> Self { - let name = StringSpan::new(name, Some(WARNING), Some(Attribute::Bold)); - let found = StringSpan::new( + let name = StyledString::new(name, Some(WARNING), Some(Attribute::Bold)); + let found = StyledString::new( &format!("{}", cast_to), Some(WARNING), Some(Attribute::Bold), diff --git a/compiler/erg_parser/error.rs b/compiler/erg_parser/error.rs index d291bae2..95d63f01 100644 --- a/compiler/erg_parser/error.rs +++ b/compiler/erg_parser/error.rs @@ -4,7 +4,7 @@ use erg_common::astr::AtomicStr; use erg_common::config::Input; use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay}; -use erg_common::style::{Attribute, Color, StrSpan, StringSpan, Theme}; +use erg_common::style::{Attribute, Color, StyledStr, StyledString, Theme}; use erg_common::traits::Stream; use erg_common::{impl_display_and_error, impl_stream_for_wrapper, switch_lang}; @@ -38,7 +38,7 @@ impl LexError { } pub fn compiler_bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self { - const URL: StrSpan = StrSpan::new( + const URL: StyledStr = StyledStr::new( "https://github.com/erg-lang/erg", Some(Color::White), Some(Attribute::Underline), @@ -120,7 +120,7 @@ impl LexError { ) .into() }); - let name = StringSpan::new(name, Some(Color::Red), Some(Attribute::Underline)); + let name = StyledString::new(name, Some(Color::Red), Some(Attribute::Underline)); Self::new(ErrorCore::new( errno, NameError, From c1ee6f4dc945b1da351d3dedddf42372dd05d3b1 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Mon, 14 Nov 2022 07:59:56 +0900 Subject: [PATCH 11/12] Clean: `span` to `text` --- compiler/erg_common/style.rs | 138 +++++++++++++++++------------------ 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index e434698f..5ccd5e0f 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -247,19 +247,19 @@ pub const CHARS: Characters = Characters { /// ``` #[derive(Debug)] pub struct StyledStr<'a> { - span: &'a str, + text: &'a str, color: Option, attribute: Option, } impl<'a> StyledStr<'a> { pub const fn new<'b: 'a>( - span: &'b str, + text: &'b str, color: Option, attribute: Option, ) -> Self { Self { - span, + text, color, attribute, } @@ -270,15 +270,15 @@ impl std::fmt::Display for StyledStr<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match (self.color, self.attribute) { (None, None) => todo!(), - (None, Some(attr)) => write!(f, "{}{}{}", attr.as_str(), self.span, ATTR_RESET), - (Some(color), None) => write!(f, "{}{}{}", color.as_str(), self.span, RESET), + (None, Some(attr)) => write!(f, "{}{}{}", attr.as_str(), self.text, ATTR_RESET), + (Some(color), None) => write!(f, "{}{}{}", color.as_str(), self.text, RESET), (Some(color), Some(attr)) => { write!( f, "{}{}{}{}{}", color.as_str(), attr.as_str(), - self.span, + self.text, RESET, ATTR_RESET ) @@ -293,7 +293,7 @@ impl std::fmt::Display for StyledStr<'_> { /// #[derive(Debug)] pub struct StyledString { - span: String, + text: String, color: Option, attribute: Option, } @@ -301,7 +301,7 @@ pub struct StyledString { impl StyledString { pub fn new(s: &str, color: Option, attribute: Option) -> Self { Self { - span: String::from(s), + text: String::from(s), color, attribute, } @@ -312,28 +312,28 @@ impl StyledString { /// /// # Example /// ``` - /// let mut span = StyledString::new("sample text", None, Attribute::Underline); - /// span.push_str("\n"); - /// span.push_str("Next break line text"); - /// println!("{span}"); // Two lines of text underlined are displayed + /// let mut text = StyledString::new("sample text", None, Attribute::Underline); + /// text.push_str("\n"); + /// text.push_str("Next break line text"); + /// println!("{text}"); // Two lines of text underlined are displayed /// ``` pub fn push_str(&mut self, s: &str) { - self.span.push_str(s); + self.text.push_str(s); } } impl std::fmt::Display for StyledString { fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result { match (self.color, self.attribute) { - (None, None) => write!(f, "{}", self.span), - (None, Some(attr)) => write!(f, "{}{}{}", attr.as_str(), self.span, ATTR_RESET), - (Some(color), None) => write!(f, "{}{}{}", color.as_str(), self.span, RESET), + (None, None) => write!(f, "{}", self.text), + (None, Some(attr)) => write!(f, "{}{}{}", attr.as_str(), self.text, ATTR_RESET), + (Some(color), None) => write!(f, "{}{}{}", color.as_str(), self.text, RESET), (Some(color), Some(attr)) => write!( f, "{}{}{}{}{}", attr.as_str(), color.as_str(), - self.span, + self.text, RESET, ATTR_RESET ), @@ -348,19 +348,19 @@ impl std::fmt::Display for StyledString { /// /// # Example /// ``` -/// let mut spans = StyledStrings::default(); -/// spans.push_srt("Default color is gray, "); -/// spans.push_str_with_color("and it is possible to color text.\n", Color::Red); -/// spans.push_str("Basically, this `StyledStrings` is one sentence, "); -/// spans.push_str_with_color("so if you want to multiline sentences, you need to add `\n`.", Color::Magenta); -/// println!("{}", spans); // Pushed colored text are displayed +/// let mut texts = StyledStrings::default(); +/// texts.push_srt("Default color is gray, "); +/// texts.push_str_with_color("and it is possible to color text.\n", Color::Red); +/// texts.push_str("Basically, this `StyledStrings` is one sentence, "); +/// texts.push_str_with_color("so if you want to multiline sentences, you need to add `\n`.", Color::Magenta); +/// println!("{}", texts); // Pushed colored text are displayed /// ``` /// Basically,initialize by default with mutable. /// Then, &str(s) are pushed to the Vec, specifying colors or attributes. /// #[derive(Debug, Default)] pub struct StyledStrings { - spans: Vec, + texts: Vec, } impl StyledStrings { @@ -369,11 +369,11 @@ impl StyledStrings { /// /// # Example /// ``` - /// let mut spans = StyledStrings::default() - /// spans.push_str("sample text"); - /// spans.push_str("\n"); - /// spans.push_str("new text here"); - /// println!("{}", spans); + /// let mut texts = StyledStrings::default() + /// texts.push_str("sample text"); + /// texts.push_str("\n"); + /// texts.push_str("new text here"); + /// println!("{}", texts); /// /* /// sample text /// new text here @@ -382,9 +382,9 @@ impl StyledStrings { /// ``` pub fn push_str(&mut self, s: &str) { if self.is_same_color(Color::Gray) { - self.spans.last_mut().unwrap().span.push_str(s); + self.texts.last_mut().unwrap().text.push_str(s); } else { - self.spans.push(StyledString::new(s, None, None)); + self.texts.push(StyledString::new(s, None, None)); } } @@ -393,18 +393,18 @@ impl StyledStrings { /// /// # Example /// ``` - /// let mut spans = StyledStrings::default(); - /// spans.push_str_with_color("Cyan color text", Color::Cyan); - /// spans.push_str_with_color("Red color text", Color::Red); - /// spans.push_str_with_color(", pushed texts become a single String.", Color::Yellow); - /// spans.push_str_with_color("\n If you want to add break lines, you should add `\n`.", Color::Magenta); - /// println!("{}", spans); + /// let mut texts = StyledStrings::default(); + /// texts.push_str_with_color("Cyan color text", Color::Cyan); + /// texts.push_str_with_color("Red color text", Color::Red); + /// texts.push_str_with_color(", pushed texts become a single String.", Color::Yellow); + /// texts.push_str_with_color("\n If you want to add break lines, you should add `\n`.", Color::Magenta); + /// println!("{}", texts); /// `` pub fn push_str_with_color(&mut self, s: &str, color: Color) { if self.is_same_color(color) { - self.spans.last_mut().unwrap().span.push_str(s); + self.texts.last_mut().unwrap().text.push_str(s); } else { - self.spans.push(StyledString::new(s, Some(color), None)); + self.texts.push(StyledString::new(s, Some(color), None)); } } @@ -414,32 +414,32 @@ impl StyledStrings { /// /// # Example /// ``` - /// let mut spans = StyledStrings::default(); - /// spans.push_str_with_color_and_attribute("Magenta and bold text\n", Color::Magenta, Attribute::Bold); - /// spans.push_str_with_color_and_attribute("White and underlined text", Color::White, Attribute::Underline); - /// spans.push_str_with_color_and_attribute("Must be specify the color and attribute", None, Attribute::Underline); - /// println!("{}", spans); + /// let mut texts = StyledStrings::default(); + /// texts.push_str_with_color_and_attribute("Magenta and bold text\n", Color::Magenta, Attribute::Bold); + /// texts.push_str_with_color_and_attribute("White and underlined text", Color::White, Attribute::Underline); + /// texts.push_str_with_color_and_attribute("Must be specify the color and attribute", None, Attribute::Underline); + /// println!("{}", texts); /// ``` pub fn push_str_with_color_and_attribute(&mut self, s: &str, color: Color, attr: Attribute) { if self.is_same_color(color) && self.is_same_attribute(attr) { - self.spans.last_mut().unwrap().span.push_str(s); + self.texts.last_mut().unwrap().text.push_str(s); } else { - self.spans + self.texts .push(StyledString::new(s, Some(color), Some(attr))); } } pub fn is_same_color(&self, color: Color) -> bool { - if let Some(span) = self.spans.last() { - return span.color == Some(color); + if let Some(text) = self.texts.last() { + return text.color == Some(color); } false } pub fn is_same_attribute(&self, attr: Attribute) -> bool { - if let Some(span) = self.spans.last() { - if let Some(span_attr) = span.attribute { - return span_attr == attr; + if let Some(text) = self.texts.last() { + if let Some(text_attr) = text.attribute { + return text_attr == attr; } } false @@ -448,8 +448,8 @@ impl StyledStrings { impl std::fmt::Display for StyledStrings { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - for span in self.spans.iter() { - write!(f, "{}", span)?; + for text in self.texts.iter() { + write!(f, "{}", text)?; } Ok(()) } @@ -477,40 +477,40 @@ mod tests { } #[test] - fn str_spans_test() { - let mut spans = StyledStrings::default(); - spans.push_str("Gray is the default color\n"); - spans.push_str("If you specify the color, "); - spans.push_str("you should use `push_str_with_color()`\n"); + fn str_texts_test() { + let mut texts = StyledStrings::default(); + texts.push_str("Gray is the default color\n"); + texts.push_str("If you specify the color, "); + texts.push_str("you should use `push_str_with_color()`\n"); - spans.push_str_with_color( + texts.push_str_with_color( "It is possible to change text foreground color...\n", Color::White, ); - spans.push_str_with_color("Cyan text, ", Color::Cyan); - spans.push_str_with_color("Black text, ", Color::Black); - spans.push_str_with_color("Blue text, ", Color::Blue); - spans.push_str_with_color("Red text, ", Color::Red); - spans.push_str_with_color("pushed texts become a String.", Color::Yellow); - spans.push_str_with_color( + texts.push_str_with_color("Cyan text, ", Color::Cyan); + texts.push_str_with_color("Black text, ", Color::Black); + texts.push_str_with_color("Blue text, ", Color::Blue); + texts.push_str_with_color("Red text, ", Color::Red); + texts.push_str_with_color("pushed texts become a String.", Color::Yellow); + texts.push_str_with_color( "\nIf you want to add break lines, you should add `\\n`.\n", Color::Magenta, ); - spans.push_str_with_color( + texts.push_str_with_color( "It is also possible to change text attribute...\n", Color::White, ); - spans.push_str_with_color_and_attribute( + texts.push_str_with_color_and_attribute( "Green and bold text\n", Color::Green, Attribute::Bold, ); - spans.push_str_with_color_and_attribute( + texts.push_str_with_color_and_attribute( "White and underlined text", Color::White, Attribute::Underline, ); - println!("{}", spans); + println!("{}", texts); } } From 910d095180d4f566ee38544bf0f0ad2992010526 Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama Date: Mon, 14 Nov 2022 11:02:28 +0900 Subject: [PATCH 12/12] Fix doc test errors --- compiler/erg_common/error.rs | 10 +++++----- compiler/erg_common/style.rs | 16 +++++++++++----- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index 4964e329..5ba416bc 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -236,7 +236,7 @@ pub enum Location { /// /// Ownership error /// - /// ``` + /// ```erg /// a: Nat = 1 /// a.consume_ownership() // move occurs /// @@ -245,7 +245,7 @@ pub enum Location { /// /// `a` moves ownership in a method(or function) that are defined and consume it. /// - /// ``` + /// ```erg /// Location::RangePair { /// ln_first: (2, 2), /// col_first: (0, 1), @@ -262,7 +262,7 @@ pub enum Location { }, /// /// Location used for basic errors - /// ``` + /// ```erg /// // erg /// a = 1 /// a = 2 @@ -492,7 +492,7 @@ fn format_context( } /// format: -/// ``` +/// ```txt /// Error[#{.errno}]: File {file}, line {.loc (as line)}, in {.caused_by} /// {.loc (as line)}| {src} /// {pointer} @@ -503,7 +503,7 @@ fn format_context( /// ``` /// /// example: -/// ``` +/// ```txt /// Error[#2223]: File , line 1, in /// /// 1 | 100 = i diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index 5ccd5e0f..d4feb738 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -239,6 +239,7 @@ pub const CHARS: Characters = Characters { /// It is an immutable string. /// # Example /// ``` +/// # use erg_common::style::{Color, Attribute, StyledStr}; /// const URL: StyledStr = StyledStr::new( /// "https://github.com/erg-lang/erg", /// Some(Color::White), @@ -312,7 +313,8 @@ impl StyledString { /// /// # Example /// ``` - /// let mut text = StyledString::new("sample text", None, Attribute::Underline); + /// # use erg_common::style::{Color, Attribute, StyledString}; + /// let mut text = StyledString::new("sample text", None, Some(Attribute::Underline)); /// text.push_str("\n"); /// text.push_str("Next break line text"); /// println!("{text}"); // Two lines of text underlined are displayed @@ -348,8 +350,9 @@ impl std::fmt::Display for StyledString { /// /// # Example /// ``` +/// # use erg_common::style::{Color, Attribute, StyledStrings}; /// let mut texts = StyledStrings::default(); -/// texts.push_srt("Default color is gray, "); +/// texts.push_str("Default color is gray, "); /// texts.push_str_with_color("and it is possible to color text.\n", Color::Red); /// texts.push_str("Basically, this `StyledStrings` is one sentence, "); /// texts.push_str_with_color("so if you want to multiline sentences, you need to add `\n`.", Color::Magenta); @@ -369,7 +372,8 @@ impl StyledStrings { /// /// # Example /// ``` - /// let mut texts = StyledStrings::default() + /// # use erg_common::style::StyledStrings; + /// let mut texts = StyledStrings::default(); /// texts.push_str("sample text"); /// texts.push_str("\n"); /// texts.push_str("new text here"); @@ -393,13 +397,14 @@ impl StyledStrings { /// /// # Example /// ``` + /// # use erg_common::style::{Color, Attribute, StyledStrings}; /// let mut texts = StyledStrings::default(); /// texts.push_str_with_color("Cyan color text", Color::Cyan); /// texts.push_str_with_color("Red color text", Color::Red); /// texts.push_str_with_color(", pushed texts become a single String.", Color::Yellow); /// texts.push_str_with_color("\n If you want to add break lines, you should add `\n`.", Color::Magenta); /// println!("{}", texts); - /// `` + /// ``` pub fn push_str_with_color(&mut self, s: &str, color: Color) { if self.is_same_color(color) { self.texts.last_mut().unwrap().text.push_str(s); @@ -414,10 +419,11 @@ impl StyledStrings { /// /// # Example /// ``` + /// # use erg_common::style::{Color, Attribute, StyledStrings}; /// let mut texts = StyledStrings::default(); /// texts.push_str_with_color_and_attribute("Magenta and bold text\n", Color::Magenta, Attribute::Bold); /// texts.push_str_with_color_and_attribute("White and underlined text", Color::White, Attribute::Underline); - /// texts.push_str_with_color_and_attribute("Must be specify the color and attribute", None, Attribute::Underline); + /// // texts.push_str_with_color_and_attribute("Must be specify the color and attribute", None, Attribute::Underline); /// println!("{}", texts); /// ``` pub fn push_str_with_color_and_attribute(&mut self, s: &str, color: Color, attr: Attribute) {