Skip to main content

aion_package/declared_command/
error.rs

1//! The refusals a render earns, one per honest way a parameter set and a
2//! declared command can fail to meet.
3
4use thiserror::Error;
5
6/// Why a declared command could not be rendered into an argv.
7///
8/// Every variant is TERMINAL for an executing action: the same parameter set
9/// against the same declaration fails identically however many times it is
10/// retried. The AWL side maps each of these back onto its own cause
11/// vocabulary with a source span; an executor reports the message as it
12/// stands.
13#[derive(Clone, Debug, PartialEq, Eq, Error)]
14pub enum RenderError {
15    /// The parameter set names something the command does not declare.
16    #[error(
17        "the parameter set names `{parameter}`, which command `{command}` does not declare; a \
18         value nothing consumes is a value nobody reviewed"
19    )]
20    ArgumentUndeclared {
21        /// The command being rendered.
22        command: String,
23        /// The undeclared name that was supplied.
24        parameter: String,
25    },
26    /// A declared parameter has neither a supplied value nor a default.
27    #[error(
28        "the parameter set omits `{parameter}`, which command `{command}` declares and gives no \
29         default; there is nothing for this surface to invent"
30    )]
31    ArgumentMissing {
32        /// The command being rendered.
33        command: String,
34        /// The parameter nothing filled.
35        parameter: String,
36    },
37    /// A supplied value's shape does not match the parameter's declared type.
38    #[error(
39        "parameter `{parameter}` of command `{command}` is declared a {declared}, and the \
40         parameter set supplies a {supplied}"
41    )]
42    ArgumentTypeMismatch {
43        /// The command being rendered.
44        command: String,
45        /// The parameter whose shape did not match.
46        parameter: String,
47        /// The value that was supplied, as a diagnostic reads it. Carried
48        /// rather than re-derived: the bytes a reader must be handed are the
49        /// ones that were actually seen.
50        observed: String,
51        /// The declared shape, as a diagnostic reads it.
52        declared: &'static str,
53        /// The supplied shape, as a diagnostic reads it.
54        supplied: &'static str,
55    },
56    /// An operand would emit leading-dash bytes into a position the program
57    /// is still reading options in, with no end-of-options marker before it.
58    #[error(
59        "command `{command}` would emit `{element}` for argument `{argument}`, which begins with \
60         `-`, and no `{marker}` argument stands before it. Nothing downstream could tell it from \
61         an option"
62    )]
63    LeadingDashOperand {
64        /// The command being rendered.
65        command: String,
66        /// How the declaration names the offending argument.
67        argument: String,
68        /// The element that would have been emitted.
69        element: String,
70        /// The end-of-options marker the declaration could have carried.
71        marker: &'static str,
72    },
73    /// A command line reads a parameter the command does not declare, so the
74    /// declaration and its own body disagree and no parameter set could
75    /// reconcile them.
76    ///
77    /// Unreachable for a contract the emitter produced — the check layer
78    /// refuses a hole naming an undeclared parameter before emission — so
79    /// this names an archive whose stored contract was hand-edited, or one
80    /// whose body and parameter list were assembled from different sources.
81    /// Refused rather than rendered as empty text: an argv silently missing a
82    /// value is a DIFFERENT command running under the author's name.
83    #[error(
84        "command `{command}` is written to put the value of `{parameter}` into one of its \
85         arguments, but the command declares no parameter of that name, so there is nothing \
86         anywhere that could fill it and no argument list to run; redeploying the document under \
87         the current spelling re-derives a command whose body and parameters agree"
88    )]
89    UnboundHole {
90        /// The command being rendered.
91        command: String,
92        /// The parameter the body reads and the declaration does not have.
93        parameter: String,
94    },
95    /// The command was read from a prior-form archive and carries a
96    /// construct the current form cannot express, so executing it could not
97    /// mean what its author wrote.
98    #[error(
99        "command `{command}` was deployed under a prior archive form and carries {construct}, \
100         which the current form does not express; the archive still reads and lists everywhere, \
101         and redeploying the document under the current spelling makes the command runnable again"
102    )]
103    PriorFormUnrenderable {
104        /// The command being rendered.
105        command: String,
106        /// The prior-form construct, named by the reader that found it.
107        construct: String,
108    },
109    /// A supplied value has no unambiguous argument form.
110    #[error(
111        "parameter `{parameter}` is {kind}, which has no unambiguous command-argument form; \
112         supply a string, number, or boolean"
113    )]
114    UnrepresentableValue {
115        /// The parameter whose value could not be rendered.
116        parameter: String,
117        /// The JSON kind that was supplied.
118        kind: &'static str,
119    },
120    /// A supplied string contains a NUL byte.
121    ///
122    /// Refused rather than truncated: an argument reaches the kernel as a
123    /// NUL-terminated string, so a NUL inside a value would silently cut the
124    /// argument short and change what the program receives.
125    #[error(
126        "parameter `{parameter}` contains a NUL byte, which cannot appear in a command argument"
127    )]
128    InteriorNul {
129        /// The parameter whose value carried the NUL.
130        parameter: String,
131    },
132}
133
134/// How a diagnostic names a value shape.
135#[must_use]
136pub const fn shape_word(list: bool) -> &'static str {
137    if list { "list" } else { "single value" }
138}