1use crate::node::{ChainNode, CommandNode, Nodes, PipeNode};
2use gtmpl_value::{FuncError, Value};
3use std::{fmt, num::ParseIntError, string::FromUtf8Error};
4use thiserror::Error;
5
6#[derive(Debug)]
7pub struct ErrorContext {
8 pub name: String,
9 pub line: usize,
10}
11
12impl fmt::Display for ErrorContext {
13 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14 write!(f, "{}:{}", self.name, self.line)
15 }
16}
17
18#[derive(Error, Debug)]
19pub enum ParseError {
20 #[error("unexpected {0} in define clause")]
21 UnexpectedInDefineClause(Nodes),
22 #[error("unexpected end")]
23 UnexpectedEnd,
24 #[error("template: {0}:{1}")]
25 WithContext(ErrorContext, String),
26 #[error("no tree")]
27 NoTree,
28 #[error(transparent)]
29 NodeError(#[from] NodeError),
30 #[error("enable gtmpl_dynamic_template to use a pipeline as name")]
31 NoDynamicTemplate,
32 #[error("unable to parse string: {0}")]
33 UnableToParseString(String),
34}
35
36impl ParseError {
37 pub fn with_context(name: impl ToString, line: usize, msg: impl ToString) -> Self {
38 Self::WithContext(
39 ErrorContext {
40 name: name.to_string(),
41 line,
42 },
43 msg.to_string(),
44 )
45 }
46}
47
48#[derive(Error, Debug)]
49pub enum NodeError {
50 #[error("unable to unquote")]
51 UnquoteError,
52 #[error("NaN")]
53 NaN,
54 #[error("not a tree node")]
55 NaTN,
56}
57
58#[derive(Error, Debug)]
59pub enum PrintError {
60 #[error("unable to process verb: {0}")]
61 UnableToProcessVerb(String),
62 #[error("{0:X} is not a valid char")]
63 NotAValidChar(i128),
64 #[error("unable to format {0} as {1}")]
65 UnableToFormat(Value, char),
66 #[error("unable to terminate format arg: {0}")]
67 UnableToTerminateFormatArg(String),
68 #[error("missing ] in {0}")]
69 MissingClosingBracket(String),
70 #[error("unable to parse index: {0}")]
71 UnableToParseIndex(ParseIntError),
72 #[error("unable to parse width: {0}")]
73 UnableToParseWidth(ParseIntError),
74 #[error("width after index (e.g. %[3]2d)")]
75 WithAfterIndex,
76 #[error("precision after index (e.g. %[3].2d)")]
77 PrecisionAfterIndex,
78}
79
80#[derive(Error, Debug)]
81pub enum ExecError {
82 #[error("{0} is an incomplete or empty template")]
83 IncompleteTemplate(String),
84 #[error("{0}")]
85 IOError(#[from] std::io::Error),
86 #[error("unknown node: {0}")]
87 UnknownNode(Nodes),
88 #[error("expected if or with node, got {0}")]
89 ExpectedIfOrWith(Nodes),
90 #[error("unable to convert output to uft-8: {0}")]
91 Utf8ConversionFailed(FromUtf8Error),
92 #[error("empty var stack")]
93 EmptyStack,
94 #[error("var context smaller than {0}")]
95 VarContextToSmall(usize),
96 #[error("invalid range {0:?}")]
97 InvalidRange(Value),
98 #[error("pipeline must yield a String")]
99 PipelineMustYieldString,
100 #[error("template {0} not defined")]
101 TemplateNotDefined(String),
102 #[error("exceeded max template depth")]
103 MaxTemplateDepth,
104 #[error("error evaluating pipe: {0}")]
105 ErrorEvaluatingPipe(PipeNode),
106 #[error("no arguments for command node: {0}")]
107 NoArgsForCommandNode(CommandNode),
108 #[error("cannot evaluate command: {0}")]
109 CannotEvaluateCommand(Nodes),
110 #[error("field chain without fields :/")]
111 FieldChainWithoutFields,
112 #[error("{0} has arguments but cannot be invoked as function")]
113 NotAFunctionButArguments(String),
114 #[error("no fields in eval_chain_node")]
115 NoFieldsInEvalChainNode,
116 #[error("indirection through explicit nul in {0}")]
117 NullInChain(ChainNode),
118 #[error("cannot handle {0} as argument")]
119 InvalidArgument(Nodes),
120 #[error("{0} is not a defined function")]
121 UndefinedFunction(String),
122 #[error(transparent)]
123 FuncError(#[from] FuncError),
124 #[error("can't give argument to non-function {0}")]
125 ArgumentForNonFunction(Nodes),
126 #[error("only maps and objects have fields")]
127 OnlyMapsAndObjectsHaveFields,
128 #[error("no field {0} for {1}")]
129 NoFiledFor(String, Value),
130 #[error("variable {0} not found")]
131 VariableNotFound(String),
132}
133
134#[derive(Error, Debug)]
135pub enum TemplateError {
136 #[error(transparent)]
137 ExecError(#[from] ExecError),
138 #[error(transparent)]
139 ParseError(#[from] ParseError),
140}