1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
use crate::node::{ChainNode, CommandNode, Nodes, PipeNode};
use gtmpl_value::{FuncError, Value};
use std::{fmt, num::ParseIntError, string::FromUtf8Error};
use thiserror::Error;

#[derive(Debug)]
pub struct ErrorContext {
    pub name: String,
    pub line: usize,
}

impl fmt::Display for ErrorContext {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}:{}", self.name, self.line)
    }
}

#[derive(Error, Debug)]
pub enum ParseError {
    #[error("unexpected {0} in define clause")]
    UnexpectedInDefineClause(Nodes),
    #[error("unexpected end")]
    UnexpectedEnd,
    #[error("template: {0}:{1}")]
    WithContext(ErrorContext, String),
    #[error("no tree")]
    NoTree,
    #[error(transparent)]
    NodeError(#[from] NodeError),
    #[error("enable gtmpl_dynamic_template to use a pipeline as name")]
    NoDynamicTemplate,
    #[error("unable to parse string: {0}")]
    UnableToParseString(String),
}

impl ParseError {
    pub fn with_context(name: impl ToString, line: usize, msg: impl ToString) -> Self {
        Self::WithContext(
            ErrorContext {
                name: name.to_string(),
                line,
            },
            msg.to_string(),
        )
    }
}

#[derive(Error, Debug)]
pub enum NodeError {
    #[error("unable to unquote")]
    UnquoteError,
    #[error("NaN")]
    NaN,
    #[error("not a tree node")]
    NaTN,
}

#[derive(Error, Debug)]
pub enum PrintError {
    #[error("unable to process verb: {0}")]
    UnableToProcessVerb(String),
    #[error("{0:X} is not a valid char")]
    NotAValidChar(i128),
    #[error("unable to format {0} as {1}")]
    UnableToFormat(Value, char),
    #[error("unable to terminate format arg: {0}")]
    UnableToTerminateFormatArg(String),
    #[error("missing ] in {0}")]
    MissingClosingBracket(String),
    #[error("unable to parse index: {0}")]
    UnableToParseIndex(ParseIntError),
    #[error("unable to parse width: {0}")]
    UnableToParseWidth(ParseIntError),
    #[error("width after index (e.g. %[3]2d)")]
    WithAfterIndex,
    #[error("precision after index (e.g. %[3].2d)")]
    PrecisionAfterIndex,
}

#[derive(Error, Debug)]
pub enum ExecError {
    #[error("{0} is an incomplete or empty template")]
    IncompleteTemplate(String),
    #[error("{0}")]
    IOError(#[from] std::io::Error),
    #[error("unknown node: {0}")]
    UnknownNode(Nodes),
    #[error("expected if or with node, got {0}")]
    ExpectedIfOrWith(Nodes),
    #[error("unable to convert output to uft-8: {0}")]
    Utf8ConversionFailed(FromUtf8Error),
    #[error("empty var stack")]
    EmptyStack,
    #[error("var context smaller than {0}")]
    VarContextToSmall(usize),
    #[error("invalid range {0:?}")]
    InvalidRange(Value),
    #[error("pipeline must yield a String")]
    PipelineMustYieldString,
    #[error("template {0} not defined")]
    TemplateNotDefined(String),
    #[error("exceeded max template depth")]
    MaxTemplateDepth,
    #[error("error evaluating pipe: {0}")]
    ErrorEvaluatingPipe(PipeNode),
    #[error("no arguments for command node: {0}")]
    NoArgsForCommandNode(CommandNode),
    #[error("cannot evaluate command: {0}")]
    CannotEvaluateCommand(Nodes),
    #[error("field chain without fields :/")]
    FieldChainWithoutFields,
    #[error("{0} has arguments but cannot be invoked as function")]
    NotAFunctionButArguments(String),
    #[error("no fields in eval_chain_node")]
    NoFieldsInEvalChainNode,
    #[error("indirection through explicit nul in {0}")]
    NullInChain(ChainNode),
    #[error("cannot handle {0} as argument")]
    InvalidArgument(Nodes),
    #[error("{0} is not a defined function")]
    UndefinedFunction(String),
    #[error(transparent)]
    FuncError(#[from] FuncError),
    #[error("can't give argument to non-function {0}")]
    ArgumentForNonFunction(Nodes),
    #[error("only maps and objects have fields")]
    OnlyMapsAndObjectsHaveFields,
    #[error("no field {0} for {1}")]
    NoFiledFor(String, Value),
    #[error("variable {0} not found")]
    VariableNotFound(String),
}

#[derive(Error, Debug)]
pub enum TemplateError {
    #[error(transparent)]
    ExecError(#[from] ExecError),
    #[error(transparent)]
    ParseError(#[from] ParseError),
}