diff --git a/src/errors.rs b/src/errors.rs deleted file mode 100644 index 427a343..0000000 --- a/src/errors.rs +++ /dev/null @@ -1,108 +0,0 @@ -use std::sync::Arc; - -use annotate_snippets::AnnotationKind; -use annotate_snippets::Level; -use annotate_snippets::Renderer; -use annotate_snippets::Snippet; -use thiserror::Error; - -use crate::input::NomoInput; -use crate::lexer::ParseError; -use crate::parser::AstError; - -#[derive(Debug, Error)] -pub struct AstFailure { - errors: Vec, -} - -impl std::fmt::Display for AstFailure { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("TODO") - } -} - -impl AstFailure { - pub(crate) fn from_errors(errors: Vec) -> AstFailure { - AstFailure { errors } - } - - pub fn to_report(&self, source: &str) -> String { - let reports = self - .errors - .iter() - .map(|error| { - annotate_snippets::Level::ERROR - .primary_title( - error - .message - .as_deref() - .unwrap_or("An error occurred while producing an Ast"), - ) - .element( - annotate_snippets::Snippet::source(source).annotation( - annotate_snippets::AnnotationKind::Primary - .span(error.span.clone().map(|s| s.range).unwrap_or_else(|| 0..0)), - ), - ) - .elements( - error - .help - .as_ref() - .map(|help| annotate_snippets::Level::HELP.message(help)), - ) - }) - .collect::>(); - - let renderer = annotate_snippets::Renderer::styled() - .decor_style(annotate_snippets::renderer::DecorStyle::Unicode); - renderer.render(&reports) - } -} - -#[derive(Debug, Error)] -pub struct ParseFailure { - input: Arc, - errors: Vec, -} - -impl std::fmt::Display for ParseFailure { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(&self.to_report()) - } -} - -impl ParseFailure { - pub(crate) fn from_errors(errors: Vec, input: NomoInput) -> ParseFailure { - ParseFailure { - input: Arc::from(input.to_string()), - errors, - } - } - - pub fn to_report(&self) -> String { - let reports = self - .errors - .iter() - .map(|error| { - Level::ERROR - .primary_title( - error - .message - .as_deref() - .unwrap_or("An error occurred while parsing"), - ) - .element( - Snippet::source(self.input.as_ref()).annotation( - AnnotationKind::Primary - .span(error.span.clone().map(|s| s.range).unwrap_or_else(|| 0..0)), - ), - ) - .elements(error.help.as_ref().map(|help| Level::HELP.message(help))) - }) - .collect::>(); - - let renderer = - Renderer::styled().decor_style(annotate_snippets::renderer::DecorStyle::Unicode); - renderer.render(&reports) - } -} diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index 65872b7..277f3e3 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -39,13 +39,60 @@ use winnow::token::take_until; use winnow::token::take_while; use crate::SourceSpan; -use crate::errors::ParseFailure; use crate::input::NomoInput; use crate::resume_after_cut; type Input<'input> = Recoverable, ParseError>; type PResult<'input, T> = Result; +#[derive(Debug, Error)] +pub struct ParseFailure { + input: Arc, + errors: Vec, +} + +impl std::fmt::Display for ParseFailure { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.to_report()) + } +} + +impl ParseFailure { + fn from_errors(errors: Vec, input: NomoInput) -> ParseFailure { + ParseFailure { + input: Arc::from(input.to_string()), + errors, + } + } + + pub fn to_report(&self) -> String { + let reports = self + .errors + .iter() + .map(|error| { + Level::ERROR + .primary_title( + error + .message + .as_deref() + .unwrap_or("An error occurred while parsing"), + ) + .element( + Snippet::source(self.input.as_ref()).annotation( + AnnotationKind::Primary + .span(error.span.clone().map(|s| s.range).unwrap_or_else(|| 0..0)), + ), + ) + .elements(error.help.as_ref().map(|help| Level::HELP.message(help))) + }) + .collect::>(); + + let renderer = + Renderer::styled().decor_style(annotate_snippets::renderer::DecorStyle::Unicode); + renderer.render(&reports) + } +} + #[derive(Debug, Clone)] pub struct ParseError { pub(crate) message: Option, diff --git a/src/lib.rs b/src/lib.rs index b16d474..9311ac0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,76 +26,7 @@ feature = "document-features", cfg_attr(doc, doc = ::document_features::document_features!()) )] -//! -//! ## Syntax -//! -//! Nomo tries to keep a consistent syntax across its features. -//! The main concepts are: -//! -//! [`nomo`](crate) uses `{{ }}` as its identifiers. Each of them forms a 'block'. -//! -//! There are two kinds of blocks: -//! -//! - `{{= }}` Interpolations -//! - `{{ }}` everything else -//! -//! ### Expressions -//! -//! An expression in [`nomo`](crate) is anything that produces a value. Notably, control structures -//! _do not_ create values. This is different to rust. -//! -//! So for example this does not work: -//! -//! ```nomo -//! {{= if is_active "Active" else "Inactive" end }} -//! ``` -//! -//! If you wish to conditionally output something, you would write: -//! -//! ```nomo -//! {{ if is_active }} -//! Active -//! {{ else }} -//! Inactive -//! {{ end }} -//! ``` -//! -//! In expressions you can write: -//! - Mathematical expressions (`+-*/`) -//! - Logical/Binary expressions (`&&`, `||`, `>`, ...) -//! - Literals (`12`, `292.21`, `"Hello"`) -//! -//! ### Interpolations -//! -//! Interpolations is how one prints out data. A [`NomoValue`] can be printed if it is a: -//! -//! - String -//! - Integer/SignedInteger -//! - Bool -//! - Float -//! -//! All other values will result in an error. -//! -//! ### Control Structures -//! -//! [`Nomo`](crate) supports several control structures: -//! -//! **Conditions `if/else`**: -//! -//! ```nomo -//! {{ if }} -//! {{ else if }} -//! {{ else }} -//! {{ end }} -//! ``` -//! -//! **Loops `for .. in`** -//! -//! ```nomo -//! {{ for in }} -//! {{ else }} -//! {{ end }} -//! ``` +//! use std::collections::HashMap; @@ -136,9 +67,6 @@ unstable_pub!( mod parser ); -/// Nomo Functions -pub mod errors; - /// Nomo Functions pub mod functions; /// Input for nomo @@ -153,13 +81,13 @@ pub enum NomoError { ParseError { #[from] #[expect(missing_docs)] - source: errors::ParseFailure, + source: lexer::ParseFailure, }, /// Invalid Template AstError { #[from] #[expect(missing_docs)] - source: errors::AstFailure, + source: parser::AstFailure, }, /// An error occurred while evaluating diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 73cc0b2..a357725 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1,3 +1,4 @@ +use thiserror::Error; use winnow::Parser; use winnow::RecoverableParser; use winnow::combinator::Infix::Left; @@ -27,7 +28,6 @@ use winnow::stream::TokenSlice; use winnow::token::any; use crate::SourceSpan; -use crate::errors::AstFailure; use crate::lexer::TemplateToken; use crate::lexer::TokenKind; use crate::lexer::TokenOperator; @@ -151,6 +151,55 @@ impl ParserError> for AstError { } } +#[derive(Debug, Error)] +pub struct AstFailure { + errors: Vec, +} + +impl std::fmt::Display for AstFailure { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("TODO") + } +} + +impl AstFailure { + fn from_errors(errors: Vec) -> AstFailure { + AstFailure { errors } + } + + pub fn to_report(&self, source: &str) -> String { + let reports = self + .errors + .iter() + .map(|error| { + annotate_snippets::Level::ERROR + .primary_title( + error + .message + .as_deref() + .unwrap_or("An error occurred while producing an Ast"), + ) + .element( + annotate_snippets::Snippet::source(source).annotation( + annotate_snippets::AnnotationKind::Primary + .span(error.span.clone().map(|s| s.range).unwrap_or_else(|| 0..0)), + ), + ) + .elements( + error + .help + .as_ref() + .map(|help| annotate_snippets::Level::HELP.message(help)), + ) + }) + .collect::>(); + + let renderer = annotate_snippets::Renderer::styled() + .decor_style(annotate_snippets::renderer::DecorStyle::Unicode); + renderer.render(&reports) + } +} + type Input<'input> = Recoverable, AstError>; impl<'input> Parser, TemplateToken, AstError> for TokenKind { diff --git a/src/value.rs b/src/value.rs index b652dfd..903fc73 100644 --- a/src/value.rs +++ b/src/value.rs @@ -246,12 +246,12 @@ impl NomoValue { pub(crate) fn try_to_string(&self) -> Option { match self { NomoValue::String { value } => Some(value.to_string()), + NomoValue::Array { .. } => None, NomoValue::Bool { value } => Some(value.to_string()), + NomoValue::Object { .. } => None, NomoValue::Integer { value } => Some(value.to_string()), NomoValue::SignedInteger { value } => Some(value.to_string()), NomoValue::Float { value } => Some(value.to_string()), - NomoValue::Array { .. } => None, - NomoValue::Object { .. } => None, NomoValue::Iterator { .. } => None, NomoValue::Undefined => None, }