From 96d48bb38739faef5960da4ec82fd5f3c6f7f887 Mon Sep 17 00:00:00 2001 From: zong-zhe Date: Wed, 24 Aug 2022 16:29:45 +0800 Subject: [PATCH 01/11] feat(compiler-base): add error message depends on fluent. add error message loader based on fluent0.16.0. issue #115 --- kclvm/compiler_base/error/Cargo.toml | 2 + .../error/src/diagnostic/error_message.rs | 372 ++++++++++++++++++ .../src/diagnostic/locales/en-US/default.ftl | 3 + .../compiler_base/error/src/diagnostic/mod.rs | 4 + .../error/src/diagnostic/style.rs | 2 +- .../error/src/diagnostic/tests.rs | 36 ++ kclvm/compiler_base/error/src/emitter.rs | 4 +- 7 files changed, 420 insertions(+), 3 deletions(-) create mode 100644 kclvm/compiler_base/error/src/diagnostic/error_message.rs create mode 100644 kclvm/compiler_base/error/src/diagnostic/locales/en-US/default.ftl diff --git a/kclvm/compiler_base/error/Cargo.toml b/kclvm/compiler_base/error/Cargo.toml index 62b678e79..60ca88963 100644 --- a/kclvm/compiler_base/error/Cargo.toml +++ b/kclvm/compiler_base/error/Cargo.toml @@ -8,4 +8,6 @@ edition = "2021" [dependencies] compiler_base_macros = {path = "../macros", version = "0.1.0"} rustc_errors = {path="../3rdparty/rustc_errors", version="0.1.0"} +fluent = "0.16.0" +unic-langid = {version="0.9.0", features = ["macros"]} termcolor = "1.0" \ No newline at end of file diff --git a/kclvm/compiler_base/error/src/diagnostic/error_message.rs b/kclvm/compiler_base/error/src/diagnostic/error_message.rs new file mode 100644 index 000000000..b2b44b230 --- /dev/null +++ b/kclvm/compiler_base/error/src/diagnostic/error_message.rs @@ -0,0 +1,372 @@ +//! The crate provides `ErrorMessage` to define the message displayed in diagnostics, +//! and provides `TemplateLoader` to load text template file ("*.ftl"). +//! +use std::fs; + +use compiler_base_macros::bug; +use fluent::{FluentArgs, FluentBundle, FluentResource}; +use unic_langid::langid; + +/// Enum `ErrorMessage` defines the message displayed in diagnostics. +/// +/// The builtin `ErrorMessage` includes: +/// - StrMessage: the string messages. +/// - TemplateMessage: the string loaded from "*.ftl" file, depends on "fluent-0.16.0". +/// +/// `StrMessage` is only a string. +/// +/// # Examples +/// +/// ```rust +/// # use compiler_base_error::diagnostic::error_message::ErrorMessage; +/// let str_msg = ErrorMessage::StrMessage("This is a str message".to_string()); +/// ``` +/// +/// `TemplateMessage` is the message loaded from '*.ftl' file, depends on "fluent-0.16.0". +/// With the help of "fluent-0.16.0", you can get a message string by a message index. +/// +/// "*.ftl" file looks like, e.g. './src/diagnostic/locales/en-US/default.ftl' : +/// +/// ``` ignore +/// 1. invalid-syntax = Invalid syntax +/// 2. .expected = Expected one of `{$expected_items}` +/// ``` +/// +/// - In line 1, `invalid-syntax` is a `MessageIndex`, `Invalid syntax` is the `TemplateMessage` to this `MessageIndex`. +/// - In line 2, `.expected` is another `MessageIndex`, it is a sub-`MessageIndex` of `invalid-syntax`. +/// - In line 2, Sub-`MessageIndex` must start with a point `.` and it is optional. +/// - In line 2, `Expected one of `{$expected_items}`` is the `TemplateMessage` to `.expected`. It is an interpolated string. +/// - In line 2, `{$expected_items}` is a `MessageArgs` of the `Expected one of `{$expected_items}`` +/// and `MessageArgs` can be recognized as a Key-Value entry, it is optional. +/// +/// The pattern of above '*.ftl' file looks like: +/// ``` ignore +/// 1. . = > +/// 2. .Optional<.> = > +/// ``` +/// +/// And with the help of `TemplateLoader`, you can load '*ftl' files from local. +/// For more information about the `TemplateLoader` see the doc above enum `TemplateLoader`. +/// +/// And for the 'default.ftl', you can get messages as below: +/// +/// 1. If you want the message 'Invalid syntax' in line 1. +/// +/// ```rust +/// # use compiler_base_error::diagnostic::error_message::ErrorMessage; +/// # use compiler_base_error::diagnostic::error_message::TemplateLoader; +/// # use compiler_base_error::diagnostic::error_message::MessageArgs; +/// # use compiler_base_error::diagnostic::error_message::MessageIndex; +/// # use std::borrow::Borrow; +/// +/// // 1. Prepare an empty `MessageArgs`, Message in line 1 is not an interpolated string. +/// let no_args = MessageArgs::new(); +/// +/// // 2. Prepare the `MessageIndex` whose value is 'invalid-syntax'. +/// let msg_index = MessageIndex::from("invalid-syntax"); +/// +/// // 3. Only need the message in line 1, so do not need the sub-`MessageIndex` which is optional. +/// let no_sub_msg_index = None; +/// +/// // 4. Create a `TemplateMessage` by the `MessageIndex`, sub-`MessageIndex` and `MessageArgs`. +/// let template_msg = ErrorMessage::new_template_msg(msg_index, no_sub_msg_index, &no_args); +/// +/// // 5. With the help of `TemplateLoader`, you can get the message in 'default.ftl'. +/// let template_loader = TemplateLoader::new_with_template_path("./src/diagnostic/locales/en-US/default.ftl".to_string()); +/// let msg_in_line_1 = template_msg.trans_msg_to_str(Some(&template_loader)); +/// +/// assert_eq!(msg_in_line_1, "Invalid syntax"); +/// ``` +/// +/// 2. If you want the message 'Expected one of `{$expected_items}`' in line 2. +/// +/// ```rust +/// # use compiler_base_error::diagnostic::error_message::ErrorMessage; +/// # use compiler_base_error::diagnostic::error_message::TemplateLoader; +/// # use compiler_base_error::diagnostic::error_message::MessageArgs; +/// # use compiler_base_error::diagnostic::error_message::MessageIndex; +/// # use std::borrow::Borrow; +/// +/// // 1. Prepare the `MessageArgs` for `{$expected_items}`. +/// let mut args = MessageArgs::new(); +/// args.set("expected_items", "I am an expected item"); +/// +/// // 2. Prepare the `MessageIndex` whose value is 'invalid-syntax'. +/// let msg_index = MessageIndex::from("invalid-syntax"); +/// +/// // 3. The sub-`MessageIndex` is 'expected'. +/// let sub_msg_index = MessageIndex::from("expected"); +/// +/// // 4. Create a `TemplateMessage` by the `MessageIndex`, sub-`MessageIndex` and `MessageArgs`. +/// let template_msg = ErrorMessage::new_template_msg(msg_index, Some(sub_msg_index), &args); +/// +/// // 5. With the help of `TemplateLoader`, you can get the message in 'default.ftl'. +/// let template_loader = TemplateLoader::new_with_template_path("./src/diagnostic/locales/en-US/default.ftl".to_string()); +/// let msg_in_line_2 = template_msg.trans_msg_to_str(Some(&template_loader)); +/// +/// assert_eq!(msg_in_line_2, "Expected one of `\u{2068}I am an expected item\u{2069}`"); +/// ``` +pub enum ErrorMessage<'a> { + StrMessage(String), + TemplateMessage(TemplateMessageIndex, &'a MessageArgs<'a>), +} + +/// You can find the message in template file by `MessageIndex` which is part of `TemplateMessageIndex`. +/// `MessageIndex` only supports "String". +/// You need to use `MessageIndex` together with enum `ErrorMessage` and struct `TemplateMessageIndex`. +/// +/// For more infomation, see the doc above enum `ErrorMessage` and struct `TemplateMessageIndex`. +pub type MessageIndex = String; + +/// You can find the message in template file by `TemplateMessageIndex`. +/// `TemplateMessageIndex` includes one index and one sub-index. +/// Index and sub-index are both `MessageIndex`, and sub-index is optional. +/// You need to use `TemplateMessageIndex` together with enum `ErrorMessage` and type `MessageIndex`. +/// +/// For more infomation, see the doc above enum `ErrorMessage` and struct `MessageIndex`. +pub struct TemplateMessageIndex(pub MessageIndex, pub Option); + +impl<'a> ErrorMessage<'a> { + /// Create a string error message. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::diagnostic::error_message::ErrorMessage; + /// let str_msg = ErrorMessage::new_str_msg("This is a str message".to_string()); + /// ``` + pub fn new_str_msg(str_msg: String) -> Self { + Self::StrMessage(str_msg) + } + + /// Create an error message loaded from template file(*.ftl). + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::diagnostic::error_message::ErrorMessage; + /// # use compiler_base_error::diagnostic::error_message::MessageArgs; + /// # use compiler_base_error::diagnostic::error_message::MessageIndex; + /// # use std::borrow::Borrow; + /// + /// // 1. Create the `MessageArgs` for the interpolated string 'Expected one of `{$expected_items}`'. + /// let mut args = MessageArgs::new(); + /// args.set("expected_items", "I am an expected item"); + /// + /// // 2. Create the `MessageIndex` whose value is 'invalid-syntax'. + /// let msg_index = MessageIndex::from("invalid-syntax"); + /// + /// // 3. Create sub-`MessageIndex` is 'expected'. + /// let sub_msg_index = MessageIndex::from("expected"); + /// + /// // 4. Create a `TemplateMessage` by the `MessageIndex`, sub-`MessageIndex` and `MessageArgs`. + /// let template_msg = ErrorMessage::new_template_msg(msg_index, Some(sub_msg_index), &args); + /// ``` + /// + /// For more infomation about how to load message from '*.ftl' file, + /// see the doc above enum `ErrorMessage` and struct `TemplateLoader`. + pub fn new_template_msg( + index: String, + sub_index: Option, + args: &'a MessageArgs, + ) -> Self { + let sub_index = match sub_index { + Some(sub_i) => Some(MessageIndex::from(sub_i)), + None => None, + }; + let template_index = TemplateMessageIndex(MessageIndex::from(index), sub_index); + Self::TemplateMessage(template_index, args) + } + + /// Get the content of the message in string. + /// + /// # Examples + /// + /// 1. ErrorMessage::StrMessage will directly return the "String" and do not need the `TemplateLoader`. + /// + /// ```rust + /// # use compiler_base_error::diagnostic::error_message::ErrorMessage; + /// let str_msg = ErrorMessage::new_str_msg("This is a str message".to_string()); + /// assert_eq!("This is a str message", str_msg.trans_msg_to_str(None)) + /// ``` + /// + /// 2. ErrorMessage::TemplateMessage will load the message string with the help of `TemplateLoader`. + /// + /// ```rust + /// # use compiler_base_error::diagnostic::error_message::ErrorMessage; + /// # use compiler_base_error::diagnostic::error_message::MessageArgs; + /// # use compiler_base_error::diagnostic::error_message::MessageIndex; + /// # use compiler_base_error::diagnostic::error_message::TemplateLoader; + /// + /// // 1. Create the `ErrorMessage` + /// let mut args = MessageArgs::new(); + /// args.set("expected_items", "I am an expected item"); + /// let msg_index = MessageIndex::from("invalid-syntax"); + /// let sub_msg_index = MessageIndex::from("expected"); + /// let template_msg = ErrorMessage::new_template_msg(msg_index, Some(sub_msg_index), &args); + /// + /// // 2. Use the `ErrorMessage` and `TemplateLoader` to get the message. + /// let template_loader = TemplateLoader::new_with_template_path("./src/diagnostic/locales/en-US/default.ftl".to_string()); + /// let msg_in_line_2 = template_msg.trans_msg_to_str(Some(&template_loader)); + /// ``` + /// + /// # Panics + /// + /// Without the `TemplateLoader` for `ErrorMessage::TemplateMessage.trans_msg_to_str()`, it will `panic`. + /// + /// For more infomation about how to load message from '*.ftl' file, + /// see the doc above enum `ErrorMessage` and struct `TemplateLoader`. + pub fn trans_msg_to_str(&self, template_loader: Option<&'a TemplateLoader>) -> String { + match self { + ErrorMessage::StrMessage(s) => s.to_string(), + ErrorMessage::TemplateMessage(index, msg_args) => match template_loader { + Some(template_loader) => template_loader.load_message(index, msg_args), + None => bug!("'TemplateLoader' is not found."), + }, + } + } +} + +/// `MessageArgs` is the arguments of the interpolated string in `ErrorMessage`. +/// +/// `MessageArgs` is a Key-Value entry which only supports "set" and without "get". +/// You need getting nothing from `MessageArgs`. Only setting it and senting it to `ErrorMessage` is enough. +/// +/// Note: Currently both `Key` and `Value` of `MessageArgs` types only support string (&str). +/// +/// # Examples +/// +/// ```rust +/// # use compiler_base_error::diagnostic::error_message::MessageArgs; +/// # use compiler_base_error::diagnostic::error_message::ErrorMessage; +/// # use compiler_base_error::diagnostic::error_message::MessageIndex; +/// # use std::borrow::Borrow; +/// +/// # let mut args = MessageArgs::new(); +/// # args.set("expected_items", "I am an expected item"); +/// # let msg_index = MessageIndex::from("invalid-syntax"); +/// # let sub_msg_index = MessageIndex::from("expected"); +/// +/// let mut msg_args = MessageArgs::new(); +/// // You only need "set()". +/// msg_args.set("This is Key", "This is Value"); +/// +/// // When you use it, just sent it to `ErrorMessage`. +/// let template_msg = ErrorMessage::new_template_msg(msg_index, Some(sub_msg_index), &args); +/// ``` +/// +/// For more information about the `ErrorMessage` see the doc above enum `ErrorMessage`. +pub struct MessageArgs<'a>(FluentArgs<'a>); +impl<'a> MessageArgs<'a> { + pub fn new() -> Self { + Self(FluentArgs::new()) + } + + pub fn set(&mut self, k: &'a str, v: &'a str) { + self.0.set(k, v); + } +} + +/// `TemplateLoader` load template contents from "*.ftl" file. +pub struct TemplateLoader { + template_inner: TemplateLoaderInner, +} + +impl TemplateLoader { + /// You can only use the constructor 'new_with_template_path' to construct `TemplateLoader`. + /// In the constructor 'new_with_template_path', it will load the template contents. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::diagnostic::error_message::TemplateLoader; + /// let template_loader = TemplateLoader::new_with_template_path("./src/diagnostic/locales/en-US/default.ftl".to_string()); + /// ``` + pub fn new_with_template_path(template_path: String) -> Self { + Self { + template_inner: TemplateLoaderInner::new_with_template_path(template_path), + } + } + + /// You can use this method to find message from template by `TemplateMessageIndex` and `MessageArgs`. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::diagnostic::error_message::ErrorMessage; + /// # use compiler_base_error::diagnostic::error_message::TemplateLoader; + /// # use compiler_base_error::diagnostic::error_message::MessageArgs; + /// # use compiler_base_error::diagnostic::error_message::MessageIndex; + /// # use compiler_base_error::diagnostic::error_message::TemplateMessageIndex; + /// + /// // 1. Create the `TemplateMessageIndex` and `MessageArgs`. + /// + /// let mut args = MessageArgs::new(); + /// args.set("expected_items", "I am an expected item"); + /// let msg_index = MessageIndex::from("invalid-syntax"); + /// let sub_msg_index = MessageIndex::from("expected"); + /// let template_index = TemplateMessageIndex(msg_index, Some(sub_msg_index)); + /// + /// // 2. With the help of `TemplateLoader`, you can get the message in 'default.ftl'. + /// + /// let template_loader = TemplateLoader::new_with_template_path("./src/diagnostic/locales/en-US/default.ftl".to_string()); + /// let msg_in_line_2 = template_loader.load_message(&template_index, &args); + /// ``` + /// + /// For more information about the `MessageArgs`, `TemplateMessageIndex` see the doc above enum `ErrorMessage`. + pub fn load_message( + &self, + err_msg_index: &TemplateMessageIndex, + msg_args: &MessageArgs, + ) -> String { + let MessageArgs(args) = msg_args; + + let TemplateMessageIndex(index, sub_index) = err_msg_index; + + let msg = self + .template_inner + .get_template_bunder() + .get_message(index) + .unwrap_or_else(|| bug!("Message doesn't exist.")); + + let pattern = match sub_index { + Some(s_id) => { + let attr = msg.get_attribute(s_id).unwrap(); + attr.value() + } + None => msg.value().unwrap_or_else(|| bug!("Message has no value.")), + }; + let value = self.template_inner.get_template_bunder().format_pattern( + pattern, + Some(&args), + &mut vec![], + ); + value.to_string() + } +} + +// `TemplateLoaderInner` is used to privatize the default constructor of `TemplateLoader`. +struct TemplateLoaderInner { + template_bunder: FluentBundle, +} + +impl TemplateLoaderInner { + fn new_with_template_path(template_path: String) -> Self { + let mut template_bunder = FluentBundle::new(vec![langid!("en-US")]); + let resource = fs::read_to_string(template_path).unwrap_or_else(|_err| { + bug!("Failed to read '*ftl' file"); + }); + let source = FluentResource::try_new(resource).unwrap_or_else(|_err| { + bug!("Failed to add FTL resources to the bundle."); + }); + template_bunder.add_resource(source).unwrap_or_else(|_err| { + bug!("Failed to parse an FTL string."); + }); + + Self { template_bunder } + } + + fn get_template_bunder(&self) -> &FluentBundle { + &self.template_bunder + } +} diff --git a/kclvm/compiler_base/error/src/diagnostic/locales/en-US/default.ftl b/kclvm/compiler_base/error/src/diagnostic/locales/en-US/default.ftl new file mode 100644 index 000000000..67e493db8 --- /dev/null +++ b/kclvm/compiler_base/error/src/diagnostic/locales/en-US/default.ftl @@ -0,0 +1,3 @@ +invalid-syntax = + Invalid syntax + .expected = Expected one of `{$expected_items}` diff --git a/kclvm/compiler_base/error/src/diagnostic/mod.rs b/kclvm/compiler_base/error/src/diagnostic/mod.rs index 316cb299a..10b648499 100644 --- a/kclvm/compiler_base/error/src/diagnostic/mod.rs +++ b/kclvm/compiler_base/error/src/diagnostic/mod.rs @@ -1,5 +1,6 @@ pub use rustc_errors::styled_buffer::StyledBuffer; use rustc_errors::Style; +pub mod error_message; pub mod components; pub mod style; @@ -21,6 +22,9 @@ where /// # Examples /// /// ```rust + /// # use compiler_base_error::diagnostic::style::DiagnosticStyle; + /// # use compiler_base_error::diagnostic::StyledBuffer; + /// # use compiler_base_error::diagnostic::Component; /// struct ComponentWithStyleLogo { /// text: String /// } diff --git a/kclvm/compiler_base/error/src/diagnostic/style.rs b/kclvm/compiler_base/error/src/diagnostic/style.rs index 7db6e003f..fca8e8985 100644 --- a/kclvm/compiler_base/error/src/diagnostic/style.rs +++ b/kclvm/compiler_base/error/src/diagnostic/style.rs @@ -55,7 +55,7 @@ impl DiagnosticStyle { /// /// ```rust /// # use rustc_errors::Style; - /// # use compiler_base_error::style::DiagnosticStyle; + /// # use compiler_base_error::diagnostic::style::DiagnosticStyle; /// /// let mut color_spec = DiagnosticStyle::NeedFix.render_style_to_color_spec(); /// assert!(DiagnosticStyle::NeedFix.check_is_expected_colorspec(&color_spec)); diff --git a/kclvm/compiler_base/error/src/diagnostic/tests.rs b/kclvm/compiler_base/error/src/diagnostic/tests.rs index 722c9b28f..d84f823c3 100644 --- a/kclvm/compiler_base/error/src/diagnostic/tests.rs +++ b/kclvm/compiler_base/error/src/diagnostic/tests.rs @@ -75,3 +75,39 @@ mod test_components { assert_eq!(result.get(0).unwrap().get(0).unwrap().style, None); } } + +mod test_error_message { + use crate::diagnostic::error_message::{ + ErrorMessage, MessageArgs, MessageIndex, TemplateLoader, + }; + + #[test] + fn test_template_message() { + let template_path = "./src/diagnostic/locales/en-US/default.ftl"; + let no_args = MessageArgs::new(); + let msg_index = MessageIndex::from("invalid-syntax"); + let no_sub_msg_index = None; + let template_msg = ErrorMessage::new_template_msg(msg_index, no_sub_msg_index, &no_args); + let template_loader = TemplateLoader::new_with_template_path(template_path.to_string()); + let msg_in_line_1 = template_msg.trans_msg_to_str(Some(&template_loader)); + assert_eq!(msg_in_line_1, "Invalid syntax"); + + let mut args = MessageArgs::new(); + args.set("expected_items", "I am an expected item"); + let msg_index = MessageIndex::from("invalid-syntax"); + let sub_msg_index = MessageIndex::from("expected"); + let template_msg = ErrorMessage::new_template_msg(msg_index, Some(sub_msg_index), &args); + let template_loader = TemplateLoader::new_with_template_path(template_path.to_string()); + let msg_in_line_2 = template_msg.trans_msg_to_str(Some(&template_loader)); + assert_eq!( + msg_in_line_2, + "Expected one of `\u{2068}I am an expected item\u{2069}`" + ); + } + + #[test] + fn test_str_message() { + let str_msg = ErrorMessage::new_str_msg("This is a str msg".to_string()); + assert_eq!(str_msg.trans_msg_to_str(None), "This is a str msg"); + } +} diff --git a/kclvm/compiler_base/error/src/emitter.rs b/kclvm/compiler_base/error/src/emitter.rs index e3d7f79b6..148d80388 100644 --- a/kclvm/compiler_base/error/src/emitter.rs +++ b/kclvm/compiler_base/error/src/emitter.rs @@ -30,7 +30,7 @@ use termcolor::{Buffer, BufferWriter, ColorChoice, ColorSpec, StandardStream, Wr /// /// 1. Define your Emitter: /// -/// ```no_run rust +/// ```ignore rust /// /// // create a new `Emitter` /// struct DummyEmitter { @@ -64,7 +64,7 @@ use termcolor::{Buffer, BufferWriter, ColorChoice, ColorSpec, StandardStream, Wr /// /// 2. Use your Emitter with diagnostic: /// -/// ```no_run rust +/// ```ignore rust /// /// // Create a diagnostic for emitting. /// let mut diagnostic = Diagnostic::::new(); From f06944f032edf2f3d0fe39278196ac043a677752 Mon Sep 17 00:00:00 2001 From: zong-zhe Date: Thu, 25 Aug 2022 14:33:46 +0800 Subject: [PATCH 02/11] make pub -> pub(crate) --- .../error/src/diagnostic/error_message.rs | 312 +++--------------- 1 file changed, 52 insertions(+), 260 deletions(-) diff --git a/kclvm/compiler_base/error/src/diagnostic/error_message.rs b/kclvm/compiler_base/error/src/diagnostic/error_message.rs index b2b44b230..1c18ae778 100644 --- a/kclvm/compiler_base/error/src/diagnostic/error_message.rs +++ b/kclvm/compiler_base/error/src/diagnostic/error_message.rs @@ -1,5 +1,4 @@ //! The crate provides `ErrorMessage` to define the message displayed in diagnostics, -//! and provides `TemplateLoader` to load text template file ("*.ftl"). //! use std::fs; @@ -7,165 +6,56 @@ use compiler_base_macros::bug; use fluent::{FluentArgs, FluentBundle, FluentResource}; use unic_langid::langid; -/// Enum `ErrorMessage` defines the message displayed in diagnostics. -/// -/// The builtin `ErrorMessage` includes: -/// - StrMessage: the string messages. -/// - TemplateMessage: the string loaded from "*.ftl" file, depends on "fluent-0.16.0". -/// -/// `StrMessage` is only a string. -/// -/// # Examples -/// -/// ```rust -/// # use compiler_base_error::diagnostic::error_message::ErrorMessage; -/// let str_msg = ErrorMessage::StrMessage("This is a str message".to_string()); -/// ``` -/// -/// `TemplateMessage` is the message loaded from '*.ftl' file, depends on "fluent-0.16.0". -/// With the help of "fluent-0.16.0", you can get a message string by a message index. -/// -/// "*.ftl" file looks like, e.g. './src/diagnostic/locales/en-US/default.ftl' : -/// -/// ``` ignore -/// 1. invalid-syntax = Invalid syntax -/// 2. .expected = Expected one of `{$expected_items}` -/// ``` -/// -/// - In line 1, `invalid-syntax` is a `MessageIndex`, `Invalid syntax` is the `TemplateMessage` to this `MessageIndex`. -/// - In line 2, `.expected` is another `MessageIndex`, it is a sub-`MessageIndex` of `invalid-syntax`. -/// - In line 2, Sub-`MessageIndex` must start with a point `.` and it is optional. -/// - In line 2, `Expected one of `{$expected_items}`` is the `TemplateMessage` to `.expected`. It is an interpolated string. -/// - In line 2, `{$expected_items}` is a `MessageArgs` of the `Expected one of `{$expected_items}`` -/// and `MessageArgs` can be recognized as a Key-Value entry, it is optional. -/// -/// The pattern of above '*.ftl' file looks like: -/// ``` ignore -/// 1. . = > -/// 2. .Optional<.> = > -/// ``` -/// -/// And with the help of `TemplateLoader`, you can load '*ftl' files from local. -/// For more information about the `TemplateLoader` see the doc above enum `TemplateLoader`. -/// -/// And for the 'default.ftl', you can get messages as below: -/// -/// 1. If you want the message 'Invalid syntax' in line 1. -/// -/// ```rust -/// # use compiler_base_error::diagnostic::error_message::ErrorMessage; -/// # use compiler_base_error::diagnostic::error_message::TemplateLoader; -/// # use compiler_base_error::diagnostic::error_message::MessageArgs; -/// # use compiler_base_error::diagnostic::error_message::MessageIndex; -/// # use std::borrow::Borrow; -/// -/// // 1. Prepare an empty `MessageArgs`, Message in line 1 is not an interpolated string. -/// let no_args = MessageArgs::new(); -/// -/// // 2. Prepare the `MessageIndex` whose value is 'invalid-syntax'. -/// let msg_index = MessageIndex::from("invalid-syntax"); -/// -/// // 3. Only need the message in line 1, so do not need the sub-`MessageIndex` which is optional. -/// let no_sub_msg_index = None; -/// -/// // 4. Create a `TemplateMessage` by the `MessageIndex`, sub-`MessageIndex` and `MessageArgs`. -/// let template_msg = ErrorMessage::new_template_msg(msg_index, no_sub_msg_index, &no_args); -/// -/// // 5. With the help of `TemplateLoader`, you can get the message in 'default.ftl'. -/// let template_loader = TemplateLoader::new_with_template_path("./src/diagnostic/locales/en-US/default.ftl".to_string()); -/// let msg_in_line_1 = template_msg.trans_msg_to_str(Some(&template_loader)); -/// -/// assert_eq!(msg_in_line_1, "Invalid syntax"); -/// ``` -/// -/// 2. If you want the message 'Expected one of `{$expected_items}`' in line 2. -/// -/// ```rust -/// # use compiler_base_error::diagnostic::error_message::ErrorMessage; -/// # use compiler_base_error::diagnostic::error_message::TemplateLoader; -/// # use compiler_base_error::diagnostic::error_message::MessageArgs; -/// # use compiler_base_error::diagnostic::error_message::MessageIndex; -/// # use std::borrow::Borrow; -/// -/// // 1. Prepare the `MessageArgs` for `{$expected_items}`. -/// let mut args = MessageArgs::new(); -/// args.set("expected_items", "I am an expected item"); -/// -/// // 2. Prepare the `MessageIndex` whose value is 'invalid-syntax'. -/// let msg_index = MessageIndex::from("invalid-syntax"); -/// -/// // 3. The sub-`MessageIndex` is 'expected'. -/// let sub_msg_index = MessageIndex::from("expected"); -/// -/// // 4. Create a `TemplateMessage` by the `MessageIndex`, sub-`MessageIndex` and `MessageArgs`. -/// let template_msg = ErrorMessage::new_template_msg(msg_index, Some(sub_msg_index), &args); -/// -/// // 5. With the help of `TemplateLoader`, you can get the message in 'default.ftl'. -/// let template_loader = TemplateLoader::new_with_template_path("./src/diagnostic/locales/en-US/default.ftl".to_string()); -/// let msg_in_line_2 = template_msg.trans_msg_to_str(Some(&template_loader)); -/// -/// assert_eq!(msg_in_line_2, "Expected one of `\u{2068}I am an expected item\u{2069}`"); -/// ``` -pub enum ErrorMessage<'a> { +// Enum `ErrorMessage` defines the message displayed in diagnostics. +// +// The builtin `ErrorMessage` includes: +// - StrMessage: the string messages. +// - TemplateMessage: the string loaded from "*.ftl" file, depends on "fluent-0.16.0". +// +// `StrMessage` is only a string. +// +// `TemplateMessage` is the message loaded from '*.ftl' file, depends on "fluent-0.16.0". +// With the help of "fluent-0.16.0", you can get a message string by a message index. +// +// "*.ftl" file looks like, e.g. './src/diagnostic/locales/en-US/default.ftl' : +// +// ``` +// 1. invalid-syntax = Invalid syntax +// 2. .expected = Expected one of `{$expected_items}` +// ``` +// +// - In line 1, `invalid-syntax` is a `MessageIndex`, `Invalid syntax` is the `TemplateMessage` to this `MessageIndex`. +// - In line 2, `.expected` is another `MessageIndex`, it is a sub-`MessageIndex` of `invalid-syntax`. +// - In line 2, Sub-`MessageIndex` must start with a point `.` and it is optional. +// - In line 2, `Expected one of `{$expected_items}`` is the `TemplateMessage` to `.expected`. It is an interpolated string. +// - In line 2, `{$expected_items}` is a `MessageArgs` of the `Expected one of `{$expected_items}`` +// and `MessageArgs` can be recognized as a Key-Value entry, it is optional. +// +// The pattern of above '*.ftl' file looks like: +// ``` +// 1. . = > +// 2. .Optional<.> = > +// ``` +pub(crate) enum ErrorMessage<'a> { StrMessage(String), TemplateMessage(TemplateMessageIndex, &'a MessageArgs<'a>), } -/// You can find the message in template file by `MessageIndex` which is part of `TemplateMessageIndex`. -/// `MessageIndex` only supports "String". -/// You need to use `MessageIndex` together with enum `ErrorMessage` and struct `TemplateMessageIndex`. -/// -/// For more infomation, see the doc above enum `ErrorMessage` and struct `TemplateMessageIndex`. -pub type MessageIndex = String; +// `MessageIndex` only supports "String". +pub(crate) type MessageIndex = String; -/// You can find the message in template file by `TemplateMessageIndex`. -/// `TemplateMessageIndex` includes one index and one sub-index. -/// Index and sub-index are both `MessageIndex`, and sub-index is optional. -/// You need to use `TemplateMessageIndex` together with enum `ErrorMessage` and type `MessageIndex`. -/// -/// For more infomation, see the doc above enum `ErrorMessage` and struct `MessageIndex`. -pub struct TemplateMessageIndex(pub MessageIndex, pub Option); +// `TemplateMessageIndex` includes one index and one sub-index. +// Index and sub-index are both `MessageIndex`, and sub-index is optional. +pub(crate) struct TemplateMessageIndex(pub(crate) MessageIndex, pub(crate) Option); impl<'a> ErrorMessage<'a> { - /// Create a string error message. - /// - /// # Examples - /// - /// ```rust - /// # use compiler_base_error::diagnostic::error_message::ErrorMessage; - /// let str_msg = ErrorMessage::new_str_msg("This is a str message".to_string()); - /// ``` - pub fn new_str_msg(str_msg: String) -> Self { + // Create a string error message. + pub(crate) fn new_str_msg(str_msg: String) -> Self { Self::StrMessage(str_msg) } - /// Create an error message loaded from template file(*.ftl). - /// - /// # Examples - /// - /// ```rust - /// # use compiler_base_error::diagnostic::error_message::ErrorMessage; - /// # use compiler_base_error::diagnostic::error_message::MessageArgs; - /// # use compiler_base_error::diagnostic::error_message::MessageIndex; - /// # use std::borrow::Borrow; - /// - /// // 1. Create the `MessageArgs` for the interpolated string 'Expected one of `{$expected_items}`'. - /// let mut args = MessageArgs::new(); - /// args.set("expected_items", "I am an expected item"); - /// - /// // 2. Create the `MessageIndex` whose value is 'invalid-syntax'. - /// let msg_index = MessageIndex::from("invalid-syntax"); - /// - /// // 3. Create sub-`MessageIndex` is 'expected'. - /// let sub_msg_index = MessageIndex::from("expected"); - /// - /// // 4. Create a `TemplateMessage` by the `MessageIndex`, sub-`MessageIndex` and `MessageArgs`. - /// let template_msg = ErrorMessage::new_template_msg(msg_index, Some(sub_msg_index), &args); - /// ``` - /// - /// For more infomation about how to load message from '*.ftl' file, - /// see the doc above enum `ErrorMessage` and struct `TemplateLoader`. - pub fn new_template_msg( + // Create an error message loaded from template file(*.ftl). + pub(crate) fn new_template_msg( index: String, sub_index: Option, args: &'a MessageArgs, @@ -178,45 +68,8 @@ impl<'a> ErrorMessage<'a> { Self::TemplateMessage(template_index, args) } - /// Get the content of the message in string. - /// - /// # Examples - /// - /// 1. ErrorMessage::StrMessage will directly return the "String" and do not need the `TemplateLoader`. - /// - /// ```rust - /// # use compiler_base_error::diagnostic::error_message::ErrorMessage; - /// let str_msg = ErrorMessage::new_str_msg("This is a str message".to_string()); - /// assert_eq!("This is a str message", str_msg.trans_msg_to_str(None)) - /// ``` - /// - /// 2. ErrorMessage::TemplateMessage will load the message string with the help of `TemplateLoader`. - /// - /// ```rust - /// # use compiler_base_error::diagnostic::error_message::ErrorMessage; - /// # use compiler_base_error::diagnostic::error_message::MessageArgs; - /// # use compiler_base_error::diagnostic::error_message::MessageIndex; - /// # use compiler_base_error::diagnostic::error_message::TemplateLoader; - /// - /// // 1. Create the `ErrorMessage` - /// let mut args = MessageArgs::new(); - /// args.set("expected_items", "I am an expected item"); - /// let msg_index = MessageIndex::from("invalid-syntax"); - /// let sub_msg_index = MessageIndex::from("expected"); - /// let template_msg = ErrorMessage::new_template_msg(msg_index, Some(sub_msg_index), &args); - /// - /// // 2. Use the `ErrorMessage` and `TemplateLoader` to get the message. - /// let template_loader = TemplateLoader::new_with_template_path("./src/diagnostic/locales/en-US/default.ftl".to_string()); - /// let msg_in_line_2 = template_msg.trans_msg_to_str(Some(&template_loader)); - /// ``` - /// - /// # Panics - /// - /// Without the `TemplateLoader` for `ErrorMessage::TemplateMessage.trans_msg_to_str()`, it will `panic`. - /// - /// For more infomation about how to load message from '*.ftl' file, - /// see the doc above enum `ErrorMessage` and struct `TemplateLoader`. - pub fn trans_msg_to_str(&self, template_loader: Option<&'a TemplateLoader>) -> String { + // Get the content of the message in string. + pub(crate) fn trans_msg_to_str(&self, template_loader: Option<&'a TemplateLoader>) -> String { match self { ErrorMessage::StrMessage(s) => s.to_string(), ErrorMessage::TemplateMessage(index, msg_args) => match template_loader { @@ -227,94 +80,33 @@ impl<'a> ErrorMessage<'a> { } } -/// `MessageArgs` is the arguments of the interpolated string in `ErrorMessage`. -/// -/// `MessageArgs` is a Key-Value entry which only supports "set" and without "get". -/// You need getting nothing from `MessageArgs`. Only setting it and senting it to `ErrorMessage` is enough. -/// -/// Note: Currently both `Key` and `Value` of `MessageArgs` types only support string (&str). -/// -/// # Examples -/// -/// ```rust -/// # use compiler_base_error::diagnostic::error_message::MessageArgs; -/// # use compiler_base_error::diagnostic::error_message::ErrorMessage; -/// # use compiler_base_error::diagnostic::error_message::MessageIndex; -/// # use std::borrow::Borrow; -/// -/// # let mut args = MessageArgs::new(); -/// # args.set("expected_items", "I am an expected item"); -/// # let msg_index = MessageIndex::from("invalid-syntax"); -/// # let sub_msg_index = MessageIndex::from("expected"); -/// -/// let mut msg_args = MessageArgs::new(); -/// // You only need "set()". -/// msg_args.set("This is Key", "This is Value"); -/// -/// // When you use it, just sent it to `ErrorMessage`. -/// let template_msg = ErrorMessage::new_template_msg(msg_index, Some(sub_msg_index), &args); -/// ``` -/// -/// For more information about the `ErrorMessage` see the doc above enum `ErrorMessage`. -pub struct MessageArgs<'a>(FluentArgs<'a>); +// `MessageArgs` is the arguments of the interpolated string in `ErrorMessage`. +// `MessageArgs` is a Key-Value entry which only supports "set" and without "get". +// Note: Currently both `Key` and `Value` of `MessageArgs` types only support string (&str). +pub(crate) struct MessageArgs<'a>(FluentArgs<'a>); impl<'a> MessageArgs<'a> { - pub fn new() -> Self { + pub(crate) fn new() -> Self { Self(FluentArgs::new()) } - pub fn set(&mut self, k: &'a str, v: &'a str) { + pub(crate) fn set(&mut self, k: &'a str, v: &'a str) { self.0.set(k, v); } } -/// `TemplateLoader` load template contents from "*.ftl" file. -pub struct TemplateLoader { +// `TemplateLoader` load template contents from "*.ftl" file. +pub(crate) struct TemplateLoader { template_inner: TemplateLoaderInner, } impl TemplateLoader { - /// You can only use the constructor 'new_with_template_path' to construct `TemplateLoader`. - /// In the constructor 'new_with_template_path', it will load the template contents. - /// - /// # Examples - /// - /// ```rust - /// # use compiler_base_error::diagnostic::error_message::TemplateLoader; - /// let template_loader = TemplateLoader::new_with_template_path("./src/diagnostic/locales/en-US/default.ftl".to_string()); - /// ``` - pub fn new_with_template_path(template_path: String) -> Self { + pub(crate) fn new_with_template_path(template_path: String) -> Self { Self { template_inner: TemplateLoaderInner::new_with_template_path(template_path), } } - /// You can use this method to find message from template by `TemplateMessageIndex` and `MessageArgs`. - /// - /// # Examples - /// - /// ```rust - /// # use compiler_base_error::diagnostic::error_message::ErrorMessage; - /// # use compiler_base_error::diagnostic::error_message::TemplateLoader; - /// # use compiler_base_error::diagnostic::error_message::MessageArgs; - /// # use compiler_base_error::diagnostic::error_message::MessageIndex; - /// # use compiler_base_error::diagnostic::error_message::TemplateMessageIndex; - /// - /// // 1. Create the `TemplateMessageIndex` and `MessageArgs`. - /// - /// let mut args = MessageArgs::new(); - /// args.set("expected_items", "I am an expected item"); - /// let msg_index = MessageIndex::from("invalid-syntax"); - /// let sub_msg_index = MessageIndex::from("expected"); - /// let template_index = TemplateMessageIndex(msg_index, Some(sub_msg_index)); - /// - /// // 2. With the help of `TemplateLoader`, you can get the message in 'default.ftl'. - /// - /// let template_loader = TemplateLoader::new_with_template_path("./src/diagnostic/locales/en-US/default.ftl".to_string()); - /// let msg_in_line_2 = template_loader.load_message(&template_index, &args); - /// ``` - /// - /// For more information about the `MessageArgs`, `TemplateMessageIndex` see the doc above enum `ErrorMessage`. - pub fn load_message( + pub(crate) fn load_message( &self, err_msg_index: &TemplateMessageIndex, msg_args: &MessageArgs, From fed01f034cb6e3360ba07a3c456b6df0f3a3b9a1 Mon Sep 17 00:00:00 2001 From: zong-zhe Date: Thu, 25 Aug 2022 16:21:32 +0800 Subject: [PATCH 03/11] add walk dir --- kclvm/compiler_base/error/Cargo.toml | 3 +- .../error/src/diagnostic/error_message.rs | 46 ++++++++++++++----- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/kclvm/compiler_base/error/Cargo.toml b/kclvm/compiler_base/error/Cargo.toml index 60ca88963..94f5cc9bb 100644 --- a/kclvm/compiler_base/error/Cargo.toml +++ b/kclvm/compiler_base/error/Cargo.toml @@ -10,4 +10,5 @@ compiler_base_macros = {path = "../macros", version = "0.1.0"} rustc_errors = {path="../3rdparty/rustc_errors", version="0.1.0"} fluent = "0.16.0" unic-langid = {version="0.9.0", features = ["macros"]} -termcolor = "1.0" \ No newline at end of file +termcolor = "1.0" +walkdir = "2" \ No newline at end of file diff --git a/kclvm/compiler_base/error/src/diagnostic/error_message.rs b/kclvm/compiler_base/error/src/diagnostic/error_message.rs index 1c18ae778..edc0435d7 100644 --- a/kclvm/compiler_base/error/src/diagnostic/error_message.rs +++ b/kclvm/compiler_base/error/src/diagnostic/error_message.rs @@ -1,10 +1,11 @@ //! The crate provides `ErrorMessage` to define the message displayed in diagnostics, //! -use std::fs; +use std::{fs, path::Path}; use compiler_base_macros::bug; use fluent::{FluentArgs, FluentBundle, FluentResource}; use unic_langid::langid; +use walkdir::{DirEntry, WalkDir}; // Enum `ErrorMessage` defines the message displayed in diagnostics. // @@ -145,16 +146,7 @@ struct TemplateLoaderInner { impl TemplateLoaderInner { fn new_with_template_path(template_path: String) -> Self { let mut template_bunder = FluentBundle::new(vec![langid!("en-US")]); - let resource = fs::read_to_string(template_path).unwrap_or_else(|_err| { - bug!("Failed to read '*ftl' file"); - }); - let source = FluentResource::try_new(resource).unwrap_or_else(|_err| { - bug!("Failed to add FTL resources to the bundle."); - }); - template_bunder.add_resource(source).unwrap_or_else(|_err| { - bug!("Failed to parse an FTL string."); - }); - + load_all_templates_in_dir_to_resources(template_path, &mut template_bunder); Self { template_bunder } } @@ -162,3 +154,35 @@ impl TemplateLoaderInner { &self.template_bunder } } + +fn is_ftl_file(entry: &DirEntry) -> bool { + entry + .file_name() + .to_str() + .map(|s| s.ends_with(".ftl")) + .unwrap_or(false) +} + +fn load_all_templates_in_dir_to_resources( + dir: String, + fluent_bundle: &mut FluentBundle, +) { + if !std::path::Path::new(&dir).exists() { + bug!("Failed to load '*.ftl' dir"); + } + + for entry in WalkDir::new(dir) { + let entry = entry.unwrap_or_else(|_err| bug!("Failed to load '*.ftl' dir")); + if is_ftl_file(&entry) { + let resource = fs::read_to_string(entry.path()).unwrap_or_else(|_err| { + bug!("Failed to read '*ftl' file"); + }); + let source = FluentResource::try_new(resource).unwrap_or_else(|_err| { + bug!("Failed to add FTL resources to the bundle."); + }); + fluent_bundle.add_resource(source).unwrap_or_else(|_err| { + bug!("Failed to parse an FTL string."); + }); + } + } +} From 9f4a4511142a21251ccfb20aecb456c3fab2e32c Mon Sep 17 00:00:00 2001 From: zong-zhe Date: Thu, 25 Aug 2022 16:26:11 +0800 Subject: [PATCH 04/11] fix typo --- .../error/src/diagnostic/error_message.rs | 10 +++++----- kclvm/compiler_base/error/src/diagnostic/tests.rs | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/kclvm/compiler_base/error/src/diagnostic/error_message.rs b/kclvm/compiler_base/error/src/diagnostic/error_message.rs index edc0435d7..16121822e 100644 --- a/kclvm/compiler_base/error/src/diagnostic/error_message.rs +++ b/kclvm/compiler_base/error/src/diagnostic/error_message.rs @@ -1,6 +1,6 @@ //! The crate provides `ErrorMessage` to define the message displayed in diagnostics, //! -use std::{fs, path::Path}; +use std::fs; use compiler_base_macros::bug; use fluent::{FluentArgs, FluentBundle, FluentResource}; @@ -101,9 +101,9 @@ pub(crate) struct TemplateLoader { } impl TemplateLoader { - pub(crate) fn new_with_template_path(template_path: String) -> Self { + pub(crate) fn new_with_template_dir(template_dir: String) -> Self { Self { - template_inner: TemplateLoaderInner::new_with_template_path(template_path), + template_inner: TemplateLoaderInner::new_with_template_dir(template_dir), } } @@ -144,9 +144,9 @@ struct TemplateLoaderInner { } impl TemplateLoaderInner { - fn new_with_template_path(template_path: String) -> Self { + fn new_with_template_dir(template_dir: String) -> Self { let mut template_bunder = FluentBundle::new(vec![langid!("en-US")]); - load_all_templates_in_dir_to_resources(template_path, &mut template_bunder); + load_all_templates_in_dir_to_resources(template_dir, &mut template_bunder); Self { template_bunder } } diff --git a/kclvm/compiler_base/error/src/diagnostic/tests.rs b/kclvm/compiler_base/error/src/diagnostic/tests.rs index d84f823c3..9c3f7f161 100644 --- a/kclvm/compiler_base/error/src/diagnostic/tests.rs +++ b/kclvm/compiler_base/error/src/diagnostic/tests.rs @@ -83,12 +83,12 @@ mod test_error_message { #[test] fn test_template_message() { - let template_path = "./src/diagnostic/locales/en-US/default.ftl"; + let template_dir = "./src/diagnostic/locales/en-US"; let no_args = MessageArgs::new(); let msg_index = MessageIndex::from("invalid-syntax"); let no_sub_msg_index = None; let template_msg = ErrorMessage::new_template_msg(msg_index, no_sub_msg_index, &no_args); - let template_loader = TemplateLoader::new_with_template_path(template_path.to_string()); + let template_loader = TemplateLoader::new_with_template_dir(template_dir.to_string()); let msg_in_line_1 = template_msg.trans_msg_to_str(Some(&template_loader)); assert_eq!(msg_in_line_1, "Invalid syntax"); @@ -97,7 +97,7 @@ mod test_error_message { let msg_index = MessageIndex::from("invalid-syntax"); let sub_msg_index = MessageIndex::from("expected"); let template_msg = ErrorMessage::new_template_msg(msg_index, Some(sub_msg_index), &args); - let template_loader = TemplateLoader::new_with_template_path(template_path.to_string()); + let template_loader = TemplateLoader::new_with_template_dir(template_dir.to_string()); let msg_in_line_2 = template_msg.trans_msg_to_str(Some(&template_loader)); assert_eq!( msg_in_line_2, From 872a7c917ea29353d511fa04ede7504ca0a5911c Mon Sep 17 00:00:00 2001 From: zong-zhe Date: Thu, 25 Aug 2022 18:18:35 +0800 Subject: [PATCH 05/11] a simpler template loader --- .../error/src/diagnostic/error_message.rs | 237 ++++++++++-------- .../locales/en-US/test/default1.ftl | 3 + .../error/src/diagnostic/tests.rs | 54 ++-- 3 files changed, 174 insertions(+), 120 deletions(-) create mode 100644 kclvm/compiler_base/error/src/diagnostic/locales/en-US/test/default1.ftl diff --git a/kclvm/compiler_base/error/src/diagnostic/error_message.rs b/kclvm/compiler_base/error/src/diagnostic/error_message.rs index 16121822e..779b36e56 100644 --- a/kclvm/compiler_base/error/src/diagnostic/error_message.rs +++ b/kclvm/compiler_base/error/src/diagnostic/error_message.rs @@ -1,4 +1,4 @@ -//! The crate provides `ErrorMessage` to define the message displayed in diagnostics, +//! The crate provides `TemplateLoader` to load the message displayed in diagnostics from "*.ftl" files, //! use std::fs; @@ -7,115 +7,115 @@ use fluent::{FluentArgs, FluentBundle, FluentResource}; use unic_langid::langid; use walkdir::{DirEntry, WalkDir}; -// Enum `ErrorMessage` defines the message displayed in diagnostics. -// -// The builtin `ErrorMessage` includes: -// - StrMessage: the string messages. -// - TemplateMessage: the string loaded from "*.ftl" file, depends on "fluent-0.16.0". -// -// `StrMessage` is only a string. -// -// `TemplateMessage` is the message loaded from '*.ftl' file, depends on "fluent-0.16.0". -// With the help of "fluent-0.16.0", you can get a message string by a message index. -// -// "*.ftl" file looks like, e.g. './src/diagnostic/locales/en-US/default.ftl' : -// -// ``` -// 1. invalid-syntax = Invalid syntax -// 2. .expected = Expected one of `{$expected_items}` -// ``` -// -// - In line 1, `invalid-syntax` is a `MessageIndex`, `Invalid syntax` is the `TemplateMessage` to this `MessageIndex`. -// - In line 2, `.expected` is another `MessageIndex`, it is a sub-`MessageIndex` of `invalid-syntax`. -// - In line 2, Sub-`MessageIndex` must start with a point `.` and it is optional. -// - In line 2, `Expected one of `{$expected_items}`` is the `TemplateMessage` to `.expected`. It is an interpolated string. -// - In line 2, `{$expected_items}` is a `MessageArgs` of the `Expected one of `{$expected_items}`` -// and `MessageArgs` can be recognized as a Key-Value entry, it is optional. -// -// The pattern of above '*.ftl' file looks like: -// ``` -// 1. . = > -// 2. .Optional<.> = > -// ``` -pub(crate) enum ErrorMessage<'a> { - StrMessage(String), - TemplateMessage(TemplateMessageIndex, &'a MessageArgs<'a>), -} - -// `MessageIndex` only supports "String". -pub(crate) type MessageIndex = String; - -// `TemplateMessageIndex` includes one index and one sub-index. -// Index and sub-index are both `MessageIndex`, and sub-index is optional. -pub(crate) struct TemplateMessageIndex(pub(crate) MessageIndex, pub(crate) Option); - -impl<'a> ErrorMessage<'a> { - // Create a string error message. - pub(crate) fn new_str_msg(str_msg: String) -> Self { - Self::StrMessage(str_msg) - } - - // Create an error message loaded from template file(*.ftl). - pub(crate) fn new_template_msg( - index: String, - sub_index: Option, - args: &'a MessageArgs, - ) -> Self { - let sub_index = match sub_index { - Some(sub_i) => Some(MessageIndex::from(sub_i)), - None => None, - }; - let template_index = TemplateMessageIndex(MessageIndex::from(index), sub_index); - Self::TemplateMessage(template_index, args) - } - - // Get the content of the message in string. - pub(crate) fn trans_msg_to_str(&self, template_loader: Option<&'a TemplateLoader>) -> String { - match self { - ErrorMessage::StrMessage(s) => s.to_string(), - ErrorMessage::TemplateMessage(index, msg_args) => match template_loader { - Some(template_loader) => template_loader.load_message(index, msg_args), - None => bug!("'TemplateLoader' is not found."), - }, - } - } -} - -// `MessageArgs` is the arguments of the interpolated string in `ErrorMessage`. -// `MessageArgs` is a Key-Value entry which only supports "set" and without "get". -// Note: Currently both `Key` and `Value` of `MessageArgs` types only support string (&str). -pub(crate) struct MessageArgs<'a>(FluentArgs<'a>); -impl<'a> MessageArgs<'a> { - pub(crate) fn new() -> Self { - Self(FluentArgs::new()) - } - - pub(crate) fn set(&mut self, k: &'a str, v: &'a str) { - self.0.set(k, v); - } -} - -// `TemplateLoader` load template contents from "*.ftl" file. -pub(crate) struct TemplateLoader { +/// Struct `TemplateLoader` load template contents from "*.ftl" file. +/// +/// "*.ftl" file looks like, e.g. './src/diagnostic/locales/en-US/default.ftl' : +/// +/// ``` ignore +/// 1. invalid-syntax = Invalid syntax +/// 2. .expected = Expected one of `{$expected_items}` +/// ``` +/// +/// - In line 1, `invalid-syntax` is a `index`, `Invalid syntax` is the `Message String` to this `index`. +/// - In line 2, `.expected` is another `index`, it is a `sub_index` of `invalid-syntax`. +/// - In line 2, `sub_index` must start with a point `.` and it is optional. +/// - In line 2, `Expected one of `{$expected_items}`` is the `Message String` to `.expected`. It is an interpolated string. +/// - In line 2, `{$expected_items}` is a `MessageArgs` of the `Expected one of `{$expected_items}`` +/// and `MessageArgs` can be recognized as a Key-Value entry, it is optional. +/// +/// The pattern of above '*.ftl' file looks like: +/// ``` ignore +/// 1. <'index'> = <'message_string' with optional 'MessageArgs'> +/// 2. = <'message_string' with optional 'MessageArgs'> +/// ``` +pub struct TemplateLoader { template_inner: TemplateLoaderInner, } impl TemplateLoader { - pub(crate) fn new_with_template_dir(template_dir: String) -> Self { + /// Create the `TemplateLoader` with template (*.ftl) files directory. + /// `TemplateLoader` will load all the files end with "*.ftl" under the directory recursively. + /// + /// template_files + /// | + /// |---- template.ftl + /// |---- sub_template_files + /// | + /// |---- sub_template.ftl + /// + /// 'template.ftl' and 'sub_template.ftl' can both loaded by the `new_with_template_dir()`. + /// + /// # Examples + /// + /// ```rust + /// # use compiler_base_error::diagnostic::error_message::TemplateLoader; + /// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/".to_string()); + /// ``` + pub fn new_with_template_dir(template_dir: String) -> Self { Self { template_inner: TemplateLoaderInner::new_with_template_dir(template_dir), } } - pub(crate) fn load_message( + /// Get the message string from "*.ftl" file by `index`, `sub_index` and `MessageArgs`. + /// For more information about "*.ftl" file, see the doc above `TemplateLoader`. + /// + /// ``` ignore + /// 1. invalid-syntax = Invalid syntax + /// 2. .expected = Expected one of `{$expected_items}` + /// ``` + /// And for the 'default.ftl' shown above, you can get messages as follow: + /// + /// 1. If you want the message 'Invalid syntax' in line 1. + /// + /// ```rust + /// # use compiler_base_error::diagnostic::error_message::TemplateLoader; + /// # use compiler_base_error::diagnostic::error_message::MessageArgs; + /// # use std::borrow::Borrow; + /// + /// // 1. Prepare an empty `MessageArgs`, Message in line 1 is not an interpolated string. + /// let no_args = MessageArgs::new(); + /// + /// // 2. `index` is 'invalid-syntax' and has no `sub_index`. + /// let index = "invalid-syntax"; + /// let sub_index = None; + /// + /// // 3. Create the `TemplateLoader` with template (*.ftl) files directory. + /// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/".to_string()); + /// let msg_in_line_1 = error_message.get_msg_to_str(index, sub_index, &no_args); + /// + /// assert_eq!(msg_in_line_1, "Invalid syntax"); + /// ``` + /// + /// 2. If you want the message 'Expected one of `{$expected_items}`' in line 2. + /// + /// ```rust + /// # use compiler_base_error::diagnostic::error_message::TemplateLoader; + /// # use compiler_base_error::diagnostic::error_message::MessageArgs; + /// # use std::borrow::Borrow; + /// + /// // 1. Prepare the `MessageArgs` for `{$expected_items}`. + /// let mut args = MessageArgs::new(); + /// args.set("expected_items", "I am an expected item"); + /// + /// // 2. `index` is 'invalid-syntax'. + /// let index = "invalid-syntax"; + /// + /// // 3. `sub_index` is 'expected'. + /// let sub_index = "expected"; + /// + /// // 4. With the help of `TemplateLoader`, you can get the message in 'default.ftl'. + /// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/".to_string()); + /// let msg_in_line_2 = error_message.get_msg_to_str(index, Some(sub_index), &args); + /// + /// assert_eq!(msg_in_line_2, "Expected one of `\u{2068}I am an expected item\u{2069}`"); + /// ``` + pub fn get_msg_to_str( &self, - err_msg_index: &TemplateMessageIndex, - msg_args: &MessageArgs, + index: &str, + sub_index: Option<&str>, + args: &MessageArgs, ) -> String { - let MessageArgs(args) = msg_args; - - let TemplateMessageIndex(index, sub_index) = err_msg_index; - let msg = self .template_inner .get_template_bunder() @@ -129,6 +129,8 @@ impl TemplateLoader { } None => msg.value().unwrap_or_else(|| bug!("Message has no value.")), }; + + let MessageArgs(args) = args; let value = self.template_inner.get_template_bunder().format_pattern( pattern, Some(&args), @@ -138,6 +140,43 @@ impl TemplateLoader { } } +/// `MessageArgs` is the arguments of the interpolated string. +/// +/// `MessageArgs` is a Key-Value entry which only supports "set" and without "get". +/// You need getting nothing from `MessageArgs`. Only setting it and senting it to `TemplateLoader` is enough. +/// +/// Note: Currently both `Key` and `Value` of `MessageArgs` types only support string (&str). +/// +/// # Examples +/// +/// ```rust +/// # use compiler_base_error::diagnostic::error_message::MessageArgs; +/// # use compiler_base_error::diagnostic::error_message::TemplateLoader; +/// # use std::borrow::Borrow; +/// +/// let index = "invalid-syntax"; +/// let sub_index = Some("expected"); +/// let mut msg_args = MessageArgs::new(); +/// // You only need "set()". +/// msg_args.set("This is Key", "This is Value"); +/// +/// // When you use it, just sent it to `TemplateLoader`. +/// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/".to_string()); +/// let msg_in_line_1 = error_message.get_msg_to_str(index, sub_index, &msg_args); +/// ``` +/// +/// For more information about the `TemplateLoader` see the doc above struct `TemplateLoader`. +pub struct MessageArgs<'a>(FluentArgs<'a>); +impl<'a> MessageArgs<'a> { + pub fn new() -> Self { + Self(FluentArgs::new()) + } + + pub fn set(&mut self, k: &'a str, v: &'a str) { + self.0.set(k, v); + } +} + // `TemplateLoaderInner` is used to privatize the default constructor of `TemplateLoader`. struct TemplateLoaderInner { template_bunder: FluentBundle, diff --git a/kclvm/compiler_base/error/src/diagnostic/locales/en-US/test/default1.ftl b/kclvm/compiler_base/error/src/diagnostic/locales/en-US/test/default1.ftl new file mode 100644 index 000000000..4290d805b --- /dev/null +++ b/kclvm/compiler_base/error/src/diagnostic/locales/en-US/test/default1.ftl @@ -0,0 +1,3 @@ +invalid-syntax-1 = + Invalid syntax 1 + .expected_1 = Expected one of `{$expected_items}` 1 diff --git a/kclvm/compiler_base/error/src/diagnostic/tests.rs b/kclvm/compiler_base/error/src/diagnostic/tests.rs index 9c3f7f161..1af962857 100644 --- a/kclvm/compiler_base/error/src/diagnostic/tests.rs +++ b/kclvm/compiler_base/error/src/diagnostic/tests.rs @@ -77,37 +77,49 @@ mod test_components { } mod test_error_message { - use crate::diagnostic::error_message::{ - ErrorMessage, MessageArgs, MessageIndex, TemplateLoader, - }; + use crate::diagnostic::error_message::{MessageArgs, TemplateLoader}; #[test] fn test_template_message() { let template_dir = "./src/diagnostic/locales/en-US"; - let no_args = MessageArgs::new(); - let msg_index = MessageIndex::from("invalid-syntax"); - let no_sub_msg_index = None; - let template_msg = ErrorMessage::new_template_msg(msg_index, no_sub_msg_index, &no_args); let template_loader = TemplateLoader::new_with_template_dir(template_dir.to_string()); - let msg_in_line_1 = template_msg.trans_msg_to_str(Some(&template_loader)); - assert_eq!(msg_in_line_1, "Invalid syntax"); let mut args = MessageArgs::new(); + check_template_msg( + "invalid-syntax", + None, + &args, + "Invalid syntax", + &template_loader, + ); + args.set("expected_items", "I am an expected item"); - let msg_index = MessageIndex::from("invalid-syntax"); - let sub_msg_index = MessageIndex::from("expected"); - let template_msg = ErrorMessage::new_template_msg(msg_index, Some(sub_msg_index), &args); - let template_loader = TemplateLoader::new_with_template_dir(template_dir.to_string()); - let msg_in_line_2 = template_msg.trans_msg_to_str(Some(&template_loader)); - assert_eq!( - msg_in_line_2, - "Expected one of `\u{2068}I am an expected item\u{2069}`" + check_template_msg( + "invalid-syntax", + Some("expected"), + &args, + "Expected one of `\u{2068}I am an expected item\u{2069}`", + &template_loader, + ); + + args.set("expected_items", "I am an expected item"); + check_template_msg( + "invalid-syntax-1", + Some("expected_1"), + &args, + "Expected one of `\u{2068}I am an expected item\u{2069}` 1", + &template_loader, ); } - #[test] - fn test_str_message() { - let str_msg = ErrorMessage::new_str_msg("This is a str msg".to_string()); - assert_eq!(str_msg.trans_msg_to_str(None), "This is a str msg"); + fn check_template_msg( + index: &str, + sub_index: Option<&str>, + args: &MessageArgs, + expected_msg: &str, + template_loader: &TemplateLoader, + ) { + let msg_in_line = template_loader.get_msg_to_str(index, sub_index, &args); + assert_eq!(msg_in_line, expected_msg); } } From 63206b0c694feb9cb4b77baa38b1d48ae1586e7f Mon Sep 17 00:00:00 2001 From: zong-zhe Date: Thu, 25 Aug 2022 21:05:16 +0800 Subject: [PATCH 06/11] add error for template loader --- kclvm/compiler_base/error/Cargo.toml | 6 +- .../error/src/diagnostic/error_message.rs | 85 +++++++++++-------- .../error/src/diagnostic/tests.rs | 4 +- 3 files changed, 55 insertions(+), 40 deletions(-) diff --git a/kclvm/compiler_base/error/Cargo.toml b/kclvm/compiler_base/error/Cargo.toml index 94f5cc9bb..f7ec91b00 100644 --- a/kclvm/compiler_base/error/Cargo.toml +++ b/kclvm/compiler_base/error/Cargo.toml @@ -8,7 +8,9 @@ edition = "2021" [dependencies] compiler_base_macros = {path = "../macros", version = "0.1.0"} rustc_errors = {path="../3rdparty/rustc_errors", version="0.1.0"} -fluent = "0.16.0" unic-langid = {version="0.9.0", features = ["macros"]} + +fluent = "0.16.0" termcolor = "1.0" -walkdir = "2" \ No newline at end of file +walkdir = "2" +anyhow = "1.0" \ No newline at end of file diff --git a/kclvm/compiler_base/error/src/diagnostic/error_message.rs b/kclvm/compiler_base/error/src/diagnostic/error_message.rs index 779b36e56..3cadb33ab 100644 --- a/kclvm/compiler_base/error/src/diagnostic/error_message.rs +++ b/kclvm/compiler_base/error/src/diagnostic/error_message.rs @@ -1,8 +1,8 @@ -//! The crate provides `TemplateLoader` to load the message displayed in diagnostics from "*.ftl" files, +//! The crate provides `TemplateLoader` to load the error message displayed in diagnostics from "*.ftl" files, //! use std::fs; -use compiler_base_macros::bug; +use anyhow::{bail, Context, Error, Result}; use fluent::{FluentArgs, FluentBundle, FluentResource}; use unic_langid::langid; use walkdir::{DirEntry, WalkDir}; @@ -49,12 +49,12 @@ impl TemplateLoader { /// /// ```rust /// # use compiler_base_error::diagnostic::error_message::TemplateLoader; - /// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/".to_string()); + /// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/"); /// ``` - pub fn new_with_template_dir(template_dir: String) -> Self { - Self { - template_inner: TemplateLoaderInner::new_with_template_dir(template_dir), - } + pub fn new_with_template_dir(template_dir: &str) -> Result { + let template_inner = TemplateLoaderInner::new_with_template_dir(template_dir) + .with_context(|| format!("Failed to load '*.ftl' from '{}'", template_dir))?; + Ok(Self { template_inner }) } /// Get the message string from "*.ftl" file by `index`, `sub_index` and `MessageArgs`. @@ -81,8 +81,8 @@ impl TemplateLoader { /// let sub_index = None; /// /// // 3. Create the `TemplateLoader` with template (*.ftl) files directory. - /// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/".to_string()); - /// let msg_in_line_1 = error_message.get_msg_to_str(index, sub_index, &no_args); + /// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + /// let msg_in_line_1 = error_message.get_msg_to_str(index, sub_index, &no_args).unwrap(); /// /// assert_eq!(msg_in_line_1, "Invalid syntax"); /// ``` @@ -105,8 +105,8 @@ impl TemplateLoader { /// let sub_index = "expected"; /// /// // 4. With the help of `TemplateLoader`, you can get the message in 'default.ftl'. - /// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/".to_string()); - /// let msg_in_line_2 = error_message.get_msg_to_str(index, Some(sub_index), &args); + /// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); + /// let msg_in_line_2 = error_message.get_msg_to_str(index, Some(sub_index), &args).unwrap(); /// /// assert_eq!(msg_in_line_2, "Expected one of `\u{2068}I am an expected item\u{2069}`"); /// ``` @@ -115,19 +115,21 @@ impl TemplateLoader { index: &str, sub_index: Option<&str>, args: &MessageArgs, - ) -> String { - let msg = self - .template_inner - .get_template_bunder() - .get_message(index) - .unwrap_or_else(|| bug!("Message doesn't exist.")); + ) -> Result { + let msg = match self.template_inner.get_template_bunder().get_message(index) { + Some(m) => m, + None => bail!("Message doesn't exist."), + }; let pattern = match sub_index { Some(s_id) => { let attr = msg.get_attribute(s_id).unwrap(); attr.value() } - None => msg.value().unwrap_or_else(|| bug!("Message has no value.")), + None => match msg.value() { + Some(v) => v, + None => bail!("Message has no value."), + }, }; let MessageArgs(args) = args; @@ -136,7 +138,7 @@ impl TemplateLoader { Some(&args), &mut vec![], ); - value.to_string() + Ok(value.to_string()) } } @@ -161,7 +163,7 @@ impl TemplateLoader { /// msg_args.set("This is Key", "This is Value"); /// /// // When you use it, just sent it to `TemplateLoader`. -/// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/".to_string()); +/// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); /// let msg_in_line_1 = error_message.get_msg_to_str(index, sub_index, &msg_args); /// ``` /// @@ -183,10 +185,11 @@ struct TemplateLoaderInner { } impl TemplateLoaderInner { - fn new_with_template_dir(template_dir: String) -> Self { + fn new_with_template_dir(template_dir: &str) -> Result { let mut template_bunder = FluentBundle::new(vec![langid!("en-US")]); - load_all_templates_in_dir_to_resources(template_dir, &mut template_bunder); - Self { template_bunder } + load_all_templates_in_dir_to_resources(template_dir, &mut template_bunder) + .with_context(|| format!("Failed to load '*.ftl' from '{}'", template_dir))?; + Ok(Self { template_bunder }) } fn get_template_bunder(&self) -> &FluentBundle { @@ -203,25 +206,35 @@ fn is_ftl_file(entry: &DirEntry) -> bool { } fn load_all_templates_in_dir_to_resources( - dir: String, + dir: &str, fluent_bundle: &mut FluentBundle, -) { +) -> Result<()> { if !std::path::Path::new(&dir).exists() { - bug!("Failed to load '*.ftl' dir"); + bail!("Failed to load '*.ftl' dir"); } for entry in WalkDir::new(dir) { - let entry = entry.unwrap_or_else(|_err| bug!("Failed to load '*.ftl' dir")); + let entry = match entry { + Ok(entry) => entry, + Err(_) => bail!("Failed to load '*.ftl' dir"), + }; + if is_ftl_file(&entry) { - let resource = fs::read_to_string(entry.path()).unwrap_or_else(|_err| { - bug!("Failed to read '*ftl' file"); - }); - let source = FluentResource::try_new(resource).unwrap_or_else(|_err| { - bug!("Failed to add FTL resources to the bundle."); - }); - fluent_bundle.add_resource(source).unwrap_or_else(|_err| { - bug!("Failed to parse an FTL string."); - }); + let resource = match fs::read_to_string(entry.path()) { + Ok(res) => res, + Err(_) => bail!("Failed to read '*ftl' file"), + }; + + let source = match FluentResource::try_new(resource) { + Ok(s) => s, + Err(_) => bail!("Failed to add FTL resources to the bundle."), + }; + + match fluent_bundle.add_resource(source) { + Ok(_) => {} + Err(_) => bail!("Failed to parse an FTL string."), + } } } + Ok(()) } diff --git a/kclvm/compiler_base/error/src/diagnostic/tests.rs b/kclvm/compiler_base/error/src/diagnostic/tests.rs index 1af962857..ff67508ad 100644 --- a/kclvm/compiler_base/error/src/diagnostic/tests.rs +++ b/kclvm/compiler_base/error/src/diagnostic/tests.rs @@ -82,7 +82,7 @@ mod test_error_message { #[test] fn test_template_message() { let template_dir = "./src/diagnostic/locales/en-US"; - let template_loader = TemplateLoader::new_with_template_dir(template_dir.to_string()); + let template_loader = TemplateLoader::new_with_template_dir(template_dir).unwrap(); let mut args = MessageArgs::new(); check_template_msg( @@ -120,6 +120,6 @@ mod test_error_message { template_loader: &TemplateLoader, ) { let msg_in_line = template_loader.get_msg_to_str(index, sub_index, &args); - assert_eq!(msg_in_line, expected_msg); + assert_eq!(msg_in_line.unwrap(), expected_msg); } } From 5e1b13bb3e3211c6bc970cde8e529a8725d99740 Mon Sep 17 00:00:00 2001 From: zong-zhe Date: Fri, 26 Aug 2022 16:38:00 +0800 Subject: [PATCH 07/11] fix comments --- ...error_message.rs => diagnostic_message.rs} | 78 ++++++++----------- .../compiler_base/error/src/diagnostic/mod.rs | 2 +- .../error/src/diagnostic/tests.rs | 2 +- 3 files changed, 34 insertions(+), 48 deletions(-) rename kclvm/compiler_base/error/src/diagnostic/{error_message.rs => diagnostic_message.rs} (74%) diff --git a/kclvm/compiler_base/error/src/diagnostic/error_message.rs b/kclvm/compiler_base/error/src/diagnostic/diagnostic_message.rs similarity index 74% rename from kclvm/compiler_base/error/src/diagnostic/error_message.rs rename to kclvm/compiler_base/error/src/diagnostic/diagnostic_message.rs index 3cadb33ab..8935827a1 100644 --- a/kclvm/compiler_base/error/src/diagnostic/error_message.rs +++ b/kclvm/compiler_base/error/src/diagnostic/diagnostic_message.rs @@ -1,33 +1,12 @@ -//! The crate provides `TemplateLoader` to load the error message displayed in diagnostics from "*.ftl" files, +//! The crate provides `TemplateLoader` to load the diagnositc message displayed in diagnostics from "*.ftl" files, //! -use std::fs; - -use anyhow::{bail, Context, Error, Result}; +use anyhow::{bail, Context, Result}; use fluent::{FluentArgs, FluentBundle, FluentResource}; +use std::fs; use unic_langid::langid; use walkdir::{DirEntry, WalkDir}; /// Struct `TemplateLoader` load template contents from "*.ftl" file. -/// -/// "*.ftl" file looks like, e.g. './src/diagnostic/locales/en-US/default.ftl' : -/// -/// ``` ignore -/// 1. invalid-syntax = Invalid syntax -/// 2. .expected = Expected one of `{$expected_items}` -/// ``` -/// -/// - In line 1, `invalid-syntax` is a `index`, `Invalid syntax` is the `Message String` to this `index`. -/// - In line 2, `.expected` is another `index`, it is a `sub_index` of `invalid-syntax`. -/// - In line 2, `sub_index` must start with a point `.` and it is optional. -/// - In line 2, `Expected one of `{$expected_items}`` is the `Message String` to `.expected`. It is an interpolated string. -/// - In line 2, `{$expected_items}` is a `MessageArgs` of the `Expected one of `{$expected_items}`` -/// and `MessageArgs` can be recognized as a Key-Value entry, it is optional. -/// -/// The pattern of above '*.ftl' file looks like: -/// ``` ignore -/// 1. <'index'> = <'message_string' with optional 'MessageArgs'> -/// 2. = <'message_string' with optional 'MessageArgs'> -/// ``` pub struct TemplateLoader { template_inner: TemplateLoaderInner, } @@ -48,7 +27,7 @@ impl TemplateLoader { /// # Examples /// /// ```rust - /// # use compiler_base_error::diagnostic::error_message::TemplateLoader; + /// # use compiler_base_error::diagnostic::diagnostic_message::TemplateLoader; /// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/"); /// ``` pub fn new_with_template_dir(template_dir: &str) -> Result { @@ -60,17 +39,32 @@ impl TemplateLoader { /// Get the message string from "*.ftl" file by `index`, `sub_index` and `MessageArgs`. /// For more information about "*.ftl" file, see the doc above `TemplateLoader`. /// + /// "*.ftl" file looks like, e.g. './src/diagnostic/locales/en-US/default.ftl' : + /// /// ``` ignore /// 1. invalid-syntax = Invalid syntax /// 2. .expected = Expected one of `{$expected_items}` /// ``` + /// + /// - In line 1, `invalid-syntax` is a `index`, `Invalid syntax` is the `Message String` to this `index`. + /// - In line 2, `.expected` is another `index`, it is a `sub_index` of `invalid-syntax`. + /// - In line 2, `sub_index` must start with a point `.` and it is optional. + /// - In line 2, `Expected one of `{$expected_items}`` is the `Message String` to `.expected`. It is an interpolated string. + /// - In line 2, `{$expected_items}` is a `MessageArgs` of the `Expected one of `{$expected_items}`` + /// and `MessageArgs` can be recognized as a Key-Value entry, it is optional. + /// + /// The pattern of above '*.ftl' file looks like: + /// ``` ignore + /// 1. <'index'> = <'message_string' with optional 'MessageArgs'> + /// 2. = <'message_string' with optional 'MessageArgs'> + /// ``` /// And for the 'default.ftl' shown above, you can get messages as follow: /// /// 1. If you want the message 'Invalid syntax' in line 1. /// /// ```rust - /// # use compiler_base_error::diagnostic::error_message::TemplateLoader; - /// # use compiler_base_error::diagnostic::error_message::MessageArgs; + /// # use compiler_base_error::diagnostic::diagnostic_message::TemplateLoader; + /// # use compiler_base_error::diagnostic::diagnostic_message::MessageArgs; /// # use std::borrow::Borrow; /// /// // 1. Prepare an empty `MessageArgs`, Message in line 1 is not an interpolated string. @@ -90,8 +84,8 @@ impl TemplateLoader { /// 2. If you want the message 'Expected one of `{$expected_items}`' in line 2. /// /// ```rust - /// # use compiler_base_error::diagnostic::error_message::TemplateLoader; - /// # use compiler_base_error::diagnostic::error_message::MessageArgs; + /// # use compiler_base_error::diagnostic::diagnostic_message::TemplateLoader; + /// # use compiler_base_error::diagnostic::diagnostic_message::MessageArgs; /// # use std::borrow::Borrow; /// /// // 1. Prepare the `MessageArgs` for `{$expected_items}`. @@ -152,8 +146,8 @@ impl TemplateLoader { /// # Examples /// /// ```rust -/// # use compiler_base_error::diagnostic::error_message::MessageArgs; -/// # use compiler_base_error::diagnostic::error_message::TemplateLoader; +/// # use compiler_base_error::diagnostic::diagnostic_message::MessageArgs; +/// # use compiler_base_error::diagnostic::diagnostic_message::TemplateLoader; /// # use std::borrow::Borrow; /// /// let index = "invalid-syntax"; @@ -214,26 +208,18 @@ fn load_all_templates_in_dir_to_resources( } for entry in WalkDir::new(dir) { - let entry = match entry { - Ok(entry) => entry, - Err(_) => bail!("Failed to load '*.ftl' dir"), - }; + let entry = entry?; if is_ftl_file(&entry) { - let resource = match fs::read_to_string(entry.path()) { - Ok(res) => res, - Err(_) => bail!("Failed to read '*ftl' file"), - }; + let resource = fs::read_to_string(entry.path())?; - let source = match FluentResource::try_new(resource) { - Ok(s) => s, + match FluentResource::try_new(resource) { + Ok(s) => match fluent_bundle.add_resource(s) { + Err(_) => bail!("Failed to parse an FTL string."), + Ok(_) => {} + }, Err(_) => bail!("Failed to add FTL resources to the bundle."), }; - - match fluent_bundle.add_resource(source) { - Ok(_) => {} - Err(_) => bail!("Failed to parse an FTL string."), - } } } Ok(()) diff --git a/kclvm/compiler_base/error/src/diagnostic/mod.rs b/kclvm/compiler_base/error/src/diagnostic/mod.rs index 10b648499..e7c11f5a9 100644 --- a/kclvm/compiler_base/error/src/diagnostic/mod.rs +++ b/kclvm/compiler_base/error/src/diagnostic/mod.rs @@ -1,6 +1,6 @@ pub use rustc_errors::styled_buffer::StyledBuffer; use rustc_errors::Style; -pub mod error_message; +pub mod diagnostic_message; pub mod components; pub mod style; diff --git a/kclvm/compiler_base/error/src/diagnostic/tests.rs b/kclvm/compiler_base/error/src/diagnostic/tests.rs index ff67508ad..a651d1f54 100644 --- a/kclvm/compiler_base/error/src/diagnostic/tests.rs +++ b/kclvm/compiler_base/error/src/diagnostic/tests.rs @@ -77,7 +77,7 @@ mod test_components { } mod test_error_message { - use crate::diagnostic::error_message::{MessageArgs, TemplateLoader}; + use crate::diagnostic::diagnostic_message::{MessageArgs, TemplateLoader}; #[test] fn test_template_message() { From fb6fa3ef3a90d3ea56a3b20bd1f1610f6fd5a7b1 Mon Sep 17 00:00:00 2001 From: zong-zhe Date: Fri, 26 Aug 2022 19:30:11 +0800 Subject: [PATCH 08/11] add some comments --- .../src/diagnostic/diagnostic_message.rs | 63 +++++++++++-------- kclvm/compiler_base/error/src/lib.rs | 11 ++++ 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/kclvm/compiler_base/error/src/diagnostic/diagnostic_message.rs b/kclvm/compiler_base/error/src/diagnostic/diagnostic_message.rs index 8935827a1..e794e348b 100644 --- a/kclvm/compiler_base/error/src/diagnostic/diagnostic_message.rs +++ b/kclvm/compiler_base/error/src/diagnostic/diagnostic_message.rs @@ -2,38 +2,42 @@ //! use anyhow::{bail, Context, Result}; use fluent::{FluentArgs, FluentBundle, FluentResource}; -use std::fs; +use std::{fs, sync::Arc}; use unic_langid::langid; use walkdir::{DirEntry, WalkDir}; /// Struct `TemplateLoader` load template contents from "*.ftl" file. +/// +/// `TemplateLoader` will operate on files locally. +/// +/// In order to avoid the performance loss and thread safety problems that +/// may occur during the constructing the `TemplateLoader`, we close the constructor of `TemplateLoader`. +/// +/// You only need to pass the path of the "*.ftl" file to `DiagnosticHandler`, +/// and `DiagnosticHandler` will automatically construct `TemplateLoader` and load the template file. +/// +/// `TemplateLoader` is only useful for you, when you want to get message from template file by `get_msg_to_str()`. +/// For more information about how to use `get_msg_to_str()`, see the doc above `get_msg_to_str()`. pub struct TemplateLoader { - template_inner: TemplateLoaderInner, + template_inner: Arc, } impl TemplateLoader { - /// Create the `TemplateLoader` with template (*.ftl) files directory. - /// `TemplateLoader` will load all the files end with "*.ftl" under the directory recursively. - /// - /// template_files - /// | - /// |---- template.ftl - /// |---- sub_template_files - /// | - /// |---- sub_template.ftl - /// - /// 'template.ftl' and 'sub_template.ftl' can both loaded by the `new_with_template_dir()`. - /// - /// # Examples - /// - /// ```rust - /// # use compiler_base_error::diagnostic::diagnostic_message::TemplateLoader; - /// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/"); - /// ``` - pub fn new_with_template_dir(template_dir: &str) -> Result { + // Create the `TemplateLoader` with template (*.ftl) files directory. + // `TemplateLoader` will load all the files end with "*.ftl" under the directory recursively. + // + // template_files + // | + // |---- template.ftl + // |---- sub_template_files + // | + // |---- sub_template.ftl + // + // 'template.ftl' and 'sub_template.ftl' can both loaded by the `new_with_template_dir()`. + pub(crate) fn new_with_template_dir(template_dir: &str) -> Result { let template_inner = TemplateLoaderInner::new_with_template_dir(template_dir) .with_context(|| format!("Failed to load '*.ftl' from '{}'", template_dir))?; - Ok(Self { template_inner }) + Ok(Self { template_inner: Arc::new(template_inner) }) } /// Get the message string from "*.ftl" file by `index`, `sub_index` and `MessageArgs`. @@ -62,7 +66,7 @@ impl TemplateLoader { /// /// 1. If you want the message 'Invalid syntax' in line 1. /// - /// ```rust + /// ```ignore rust /// # use compiler_base_error::diagnostic::diagnostic_message::TemplateLoader; /// # use compiler_base_error::diagnostic::diagnostic_message::MessageArgs; /// # use std::borrow::Borrow; @@ -75,6 +79,8 @@ impl TemplateLoader { /// let sub_index = None; /// /// // 3. Create the `TemplateLoader` with template (*.ftl) files directory. + /// // We cloesd the constructor of `TemplateLoader`. + /// // For more information, see the doc above the `TemplateLoader`. /// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); /// let msg_in_line_1 = error_message.get_msg_to_str(index, sub_index, &no_args).unwrap(); /// @@ -83,7 +89,7 @@ impl TemplateLoader { /// /// 2. If you want the message 'Expected one of `{$expected_items}`' in line 2. /// - /// ```rust + /// ```ignore rust /// # use compiler_base_error::diagnostic::diagnostic_message::TemplateLoader; /// # use compiler_base_error::diagnostic::diagnostic_message::MessageArgs; /// # use std::borrow::Borrow; @@ -99,6 +105,8 @@ impl TemplateLoader { /// let sub_index = "expected"; /// /// // 4. With the help of `TemplateLoader`, you can get the message in 'default.ftl'. + /// // We cloesd the constructor of `TemplateLoader`. + /// // For more information, see the doc above the `TemplateLoader`. /// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); /// let msg_in_line_2 = error_message.get_msg_to_str(index, Some(sub_index), &args).unwrap(); /// @@ -145,7 +153,7 @@ impl TemplateLoader { /// /// # Examples /// -/// ```rust +/// ```ignore rust /// # use compiler_base_error::diagnostic::diagnostic_message::MessageArgs; /// # use compiler_base_error::diagnostic::diagnostic_message::TemplateLoader; /// # use std::borrow::Borrow; @@ -156,8 +164,11 @@ impl TemplateLoader { /// // You only need "set()". /// msg_args.set("This is Key", "This is Value"); /// -/// // When you use it, just sent it to `TemplateLoader`. +/// // We cloesd the constructor of `TemplateLoader`. +/// // For more information, see the doc above the `TemplateLoader`. /// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); +/// +/// // When you use it, just sent it to `TemplateLoader`. /// let msg_in_line_1 = error_message.get_msg_to_str(index, sub_index, &msg_args); /// ``` /// diff --git a/kclvm/compiler_base/error/src/lib.rs b/kclvm/compiler_base/error/src/lib.rs index 754d6b3a1..513174bb3 100644 --- a/kclvm/compiler_base/error/src/lib.rs +++ b/kclvm/compiler_base/error/src/lib.rs @@ -1,5 +1,16 @@ pub mod diagnostic; mod emitter; +pub use diagnostic::diagnostic_message::TemplateLoader; pub use emitter::Emitter; pub use emitter::TerminalEmitter; + + +mod test{ + use crate::diagnostic::diagnostic_message::TemplateLoader; + + #[test] + fn test(){ + TemplateLoader::new_with_template_dir("template_dir"); + } +} From 7439f2ac37508c82e5092ab9eabcf8618b1182e9 Mon Sep 17 00:00:00 2001 From: zong-zhe Date: Fri, 26 Aug 2022 19:33:25 +0800 Subject: [PATCH 09/11] fmt --- .../src/diagnostic/diagnostic_message.rs | 20 ++++++++++--------- kclvm/compiler_base/error/src/lib.rs | 10 ---------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/kclvm/compiler_base/error/src/diagnostic/diagnostic_message.rs b/kclvm/compiler_base/error/src/diagnostic/diagnostic_message.rs index e794e348b..5f00ad0f4 100644 --- a/kclvm/compiler_base/error/src/diagnostic/diagnostic_message.rs +++ b/kclvm/compiler_base/error/src/diagnostic/diagnostic_message.rs @@ -7,15 +7,15 @@ use unic_langid::langid; use walkdir::{DirEntry, WalkDir}; /// Struct `TemplateLoader` load template contents from "*.ftl" file. -/// -/// `TemplateLoader` will operate on files locally. -/// -/// In order to avoid the performance loss and thread safety problems that +/// +/// `TemplateLoader` will operate on files locally. +/// +/// In order to avoid the performance loss and thread safety problems that /// may occur during the constructing the `TemplateLoader`, we close the constructor of `TemplateLoader`. -/// -/// You only need to pass the path of the "*.ftl" file to `DiagnosticHandler`, +/// +/// You only need to pass the path of the "*.ftl" file to `DiagnosticHandler`, /// and `DiagnosticHandler` will automatically construct `TemplateLoader` and load the template file. -/// +/// /// `TemplateLoader` is only useful for you, when you want to get message from template file by `get_msg_to_str()`. /// For more information about how to use `get_msg_to_str()`, see the doc above `get_msg_to_str()`. pub struct TemplateLoader { @@ -37,7 +37,9 @@ impl TemplateLoader { pub(crate) fn new_with_template_dir(template_dir: &str) -> Result { let template_inner = TemplateLoaderInner::new_with_template_dir(template_dir) .with_context(|| format!("Failed to load '*.ftl' from '{}'", template_dir))?; - Ok(Self { template_inner: Arc::new(template_inner) }) + Ok(Self { + template_inner: Arc::new(template_inner), + }) } /// Get the message string from "*.ftl" file by `index`, `sub_index` and `MessageArgs`. @@ -167,7 +169,7 @@ impl TemplateLoader { /// // We cloesd the constructor of `TemplateLoader`. /// // For more information, see the doc above the `TemplateLoader`. /// let error_message = TemplateLoader::new_with_template_dir("./src/diagnostic/locales/en-US/").unwrap(); -/// +/// /// // When you use it, just sent it to `TemplateLoader`. /// let msg_in_line_1 = error_message.get_msg_to_str(index, sub_index, &msg_args); /// ``` diff --git a/kclvm/compiler_base/error/src/lib.rs b/kclvm/compiler_base/error/src/lib.rs index 513174bb3..c385e5d6a 100644 --- a/kclvm/compiler_base/error/src/lib.rs +++ b/kclvm/compiler_base/error/src/lib.rs @@ -4,13 +4,3 @@ mod emitter; pub use diagnostic::diagnostic_message::TemplateLoader; pub use emitter::Emitter; pub use emitter::TerminalEmitter; - - -mod test{ - use crate::diagnostic::diagnostic_message::TemplateLoader; - - #[test] - fn test(){ - TemplateLoader::new_with_template_dir("template_dir"); - } -} From ef50f9a0f315a6c2802ce53adcba3a2c4b3f272b Mon Sep 17 00:00:00 2001 From: zong-zhe Date: Fri, 26 Aug 2022 19:34:30 +0800 Subject: [PATCH 10/11] remove useless import --- kclvm/compiler_base/error/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kclvm/compiler_base/error/src/lib.rs b/kclvm/compiler_base/error/src/lib.rs index c385e5d6a..2b9bf46ec 100644 --- a/kclvm/compiler_base/error/src/lib.rs +++ b/kclvm/compiler_base/error/src/lib.rs @@ -1,6 +1,5 @@ pub mod diagnostic; mod emitter; -pub use diagnostic::diagnostic_message::TemplateLoader; pub use emitter::Emitter; -pub use emitter::TerminalEmitter; +pub use emitter::TerminalEmitter; \ No newline at end of file From 6a68a0c661d01eb374070fc6127c6c5213191b2e Mon Sep 17 00:00:00 2001 From: zong-zhe Date: Fri, 26 Aug 2022 19:35:49 +0800 Subject: [PATCH 11/11] fix typo --- kclvm/compiler_base/error/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kclvm/compiler_base/error/src/lib.rs b/kclvm/compiler_base/error/src/lib.rs index 2b9bf46ec..754d6b3a1 100644 --- a/kclvm/compiler_base/error/src/lib.rs +++ b/kclvm/compiler_base/error/src/lib.rs @@ -2,4 +2,4 @@ pub mod diagnostic; mod emitter; pub use emitter::Emitter; -pub use emitter::TerminalEmitter; \ No newline at end of file +pub use emitter::TerminalEmitter;