Start fixing error outputs
Signed-off-by: Marcel Müller <neikos@neikos.email>
This commit is contained in:
parent
d6ac7af36b
commit
7f7bf5c98d
16 changed files with 319 additions and 21 deletions
|
|
@ -63,7 +63,7 @@ pub enum Instruction {
|
|||
slot: VariableSlot,
|
||||
},
|
||||
PushScope {
|
||||
#[expect(unused)]
|
||||
#[allow(unused)]
|
||||
inherit_parent: bool,
|
||||
},
|
||||
Abort,
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@ use annotate_snippets::Level;
|
|||
use annotate_snippets::Renderer;
|
||||
use annotate_snippets::Snippet;
|
||||
use thiserror::Error;
|
||||
use winnow::stream::Offset;
|
||||
|
||||
use crate::input::NomoInput;
|
||||
use crate::lexer::ParseError;
|
||||
use crate::parser::AstError;
|
||||
|
||||
/// An error occurred while producing an Ast
|
||||
#[derive(Debug, Error)]
|
||||
pub struct AstFailure {
|
||||
errors: Vec<AstError>,
|
||||
|
|
@ -26,6 +28,7 @@ impl AstFailure {
|
|||
AstFailure { errors }
|
||||
}
|
||||
|
||||
/// Create a CLI printable report
|
||||
pub fn to_report(&self, source: &str) -> String {
|
||||
let reports = self
|
||||
.errors
|
||||
|
|
@ -38,12 +41,14 @@ impl AstFailure {
|
|||
.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)),
|
||||
.element(annotate_snippets::Snippet::source(source).annotation(
|
||||
annotate_snippets::AnnotationKind::Primary.span(
|
||||
constrain_without_whitespace(
|
||||
source,
|
||||
error.span.clone().map(|s| s.range).unwrap_or_else(|| 0..0),
|
||||
),
|
||||
),
|
||||
)
|
||||
))
|
||||
.elements(
|
||||
error
|
||||
.help
|
||||
|
|
@ -59,6 +64,18 @@ impl AstFailure {
|
|||
}
|
||||
}
|
||||
|
||||
fn constrain_without_whitespace(
|
||||
input: &str,
|
||||
range: std::ops::Range<usize>,
|
||||
) -> std::ops::Range<usize> {
|
||||
let trimmed = input[range].trim();
|
||||
let start = trimmed.offset_from(&input);
|
||||
let end = start + trimmed.len();
|
||||
|
||||
start..end
|
||||
}
|
||||
|
||||
/// An error occurred during lexing
|
||||
#[derive(Debug, Error)]
|
||||
pub struct ParseFailure {
|
||||
input: Arc<str>,
|
||||
|
|
@ -79,6 +96,7 @@ impl ParseFailure {
|
|||
}
|
||||
}
|
||||
|
||||
/// Produce a CLi printable report
|
||||
pub fn to_report(&self) -> String {
|
||||
let reports = self
|
||||
.errors
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ pub trait NomoFunction<T>: 'static + Send + Sync {
|
|||
|
||||
#[cfg(feature = "unstable-pub")]
|
||||
#[derive(Default)]
|
||||
#[expect(missing_docs)]
|
||||
pub struct FunctionMap {
|
||||
funcs: HashMap<String, ErasedNomoFunction>,
|
||||
}
|
||||
|
|
@ -45,6 +46,7 @@ pub(crate) struct FunctionMap {
|
|||
}
|
||||
|
||||
impl FunctionMap {
|
||||
#[expect(missing_docs)]
|
||||
pub fn register<NF: NomoFunction<T>, T>(&mut self, name: impl Into<String>, func: NF) {
|
||||
self.funcs
|
||||
.insert(name.into(), ErasedNomoFunction::erase(func));
|
||||
|
|
|
|||
|
|
@ -1,10 +1,3 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use annotate_snippets::AnnotationKind;
|
||||
use annotate_snippets::Level;
|
||||
use annotate_snippets::Renderer;
|
||||
use annotate_snippets::Snippet;
|
||||
use thiserror::Error;
|
||||
use winnow::LocatingSlice;
|
||||
use winnow::Parser;
|
||||
use winnow::RecoverableParser;
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ macro_rules! unstable_pub {
|
|||
($(#[$m:meta])* mod $name:ident) => {
|
||||
$(#[$m])*
|
||||
#[cfg(feature = "unstable-pub")]
|
||||
#[allow(missing_docs)]
|
||||
pub mod $name;
|
||||
#[cfg(not(feature = "unstable-pub"))]
|
||||
mod $name;
|
||||
|
|
|
|||
|
|
@ -104,13 +104,14 @@ impl FromRecoverableError<Input<'_>, AstError> for AstError {
|
|||
.filter(|t| t.kind() != TokenKind::Whitespace);
|
||||
let last = tokens.next();
|
||||
let first = tokens.last();
|
||||
|
||||
match (last, first) {
|
||||
(None, None) => None,
|
||||
(None, Some(single)) | (Some(single), None) => Some(SourceSpan {
|
||||
range: single.source().get_range(),
|
||||
}),
|
||||
(Some(last), Some(first)) => {
|
||||
let start = first.source().get_range().start;
|
||||
let start = first.source().get_range().end;
|
||||
let end = last.source().get_range().end;
|
||||
|
||||
Some(SourceSpan { range: start..end })
|
||||
|
|
@ -212,7 +213,7 @@ pub enum TemplateAstExpr<'input> {
|
|||
ElseConditional {
|
||||
expression: Option<Box<TemplateAstExpr<'input>>>,
|
||||
},
|
||||
#[expect(unused)]
|
||||
#[allow(unused)]
|
||||
Invalid(&'input [TemplateToken]),
|
||||
MathOperation {
|
||||
op: TokenOperator,
|
||||
|
|
@ -311,7 +312,7 @@ fn parse_action<'input>(input: &mut Input<'input>) -> Result<TemplateAstExpr<'in
|
|||
(parse_block(
|
||||
cut_err(not(repeat_till(
|
||||
0..,
|
||||
any,
|
||||
parse_expression,
|
||||
peek((ws, TokenKind::RightDelim)),
|
||||
)
|
||||
.map(|((), _)| ())))
|
||||
|
|
@ -342,7 +343,7 @@ fn parse_for_chain<'input>(input: &mut Input<'input>) -> Result<TemplateAstExpr<
|
|||
|
||||
let (content, taken) = resume_after_cut(
|
||||
repeat_till(0.., parse_ast, loop_end),
|
||||
repeat_till(0.., any, parse_end).map(|((), _)| ()),
|
||||
repeat_till(0.., parse_ast, parse_end).map(|((), _)| ()),
|
||||
)
|
||||
.with_taken()
|
||||
.parse_next(input)?;
|
||||
|
|
@ -372,9 +373,11 @@ fn parse_for_loop<'input>(input: &mut Input<'input>) -> Result<TemplateAstExpr<'
|
|||
ws,
|
||||
TokenKind::For,
|
||||
ws,
|
||||
TokenKind::Ident,
|
||||
cut_err(TokenKind::Ident.context(AstError::ctx().msg("Expected identifier here"))),
|
||||
ws,
|
||||
TokenKind::In,
|
||||
cut_err(
|
||||
TokenKind::In.context(AstError::ctx().msg("Missing `in` in `for _ in <expr>`")),
|
||||
),
|
||||
ws,
|
||||
parse_expression.map(Box::new),
|
||||
)
|
||||
|
|
@ -601,11 +604,34 @@ where
|
|||
fn parse_operand<'input>(input: &mut Input<'input>) -> Result<TemplateAstExpr<'input>, AstError> {
|
||||
trace(
|
||||
"operand",
|
||||
alt((parse_function, parse_variable_access, parse_literal)),
|
||||
alt((
|
||||
parse_keywords_fail,
|
||||
parse_function,
|
||||
parse_variable_access,
|
||||
parse_literal,
|
||||
)),
|
||||
)
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parse_keywords_fail<'input>(
|
||||
input: &mut Input<'input>,
|
||||
) -> Result<TemplateAstExpr<'input>, AstError> {
|
||||
let value = alt((
|
||||
TokenKind::ConditionalIf,
|
||||
TokenKind::For,
|
||||
TokenKind::End,
|
||||
TokenKind::In,
|
||||
))
|
||||
.take()
|
||||
.map(TemplateAstExpr::Invalid)
|
||||
.parse_next(input)?;
|
||||
|
||||
cut_err(fail::<_, (), _>.context(AstError::ctx().msg("Found literal, expected expression")))
|
||||
.value(value)
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn parse_literal<'input>(input: &mut Input<'input>) -> Result<TemplateAstExpr<'input>, AstError> {
|
||||
trace(
|
||||
"literal",
|
||||
|
|
@ -895,7 +921,7 @@ mod tests {
|
|||
help: None,
|
||||
span: Some(
|
||||
SourceSpan {
|
||||
range: 0..6,
|
||||
range: 2..6,
|
||||
},
|
||||
),
|
||||
is_fatal: false,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue