Skip to main content

synapse_codegen_cfs/
error.rs

1use std::{error::Error as StdError, fmt};
2
3/// Error returned when a parsed Synapse file cannot be emitted safely.
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum CodegenError {
6    /// Optional fields parse today, but cFS ABI codegen has no representation for them yet.
7    OptionalFieldUnsupported { container: String, field: String },
8    /// Field defaults parse today, but cFS ABI codegen does not generate initializers yet.
9    DefaultValueUnsupported { container: String, field: String },
10    /// Unrepresented enum fields parse today, but cFS ABI codegen needs an explicit representation.
11    EnumFieldUnsupported {
12        container: String,
13        field: String,
14        ty: String,
15    },
16    /// Represented enums must use integer ABI types.
17    EnumRepresentationUnsupported { enum_name: String, repr: String },
18    /// Represented enums require explicit values for every variant.
19    EnumVariantValueRequired { enum_name: String, variant: String },
20    /// Represented enum variant values must fit the selected ABI type.
21    EnumVariantValueOutOfRange {
22        enum_name: String,
23        variant: String,
24        value: i64,
25        repr: String,
26    },
27    /// Unbounded strings would generate pointer fields, which are not cFS packet/table ABI data.
28    UnboundedStringUnsupported { container: String, field: String },
29    /// The legacy `message` keyword is parsed for migration, but cFS codegen requires intent.
30    LegacyMessageUnsupported { packet: String },
31    /// cFS Software Bus command and telemetry packets require explicit message IDs.
32    MissingMid { packet: String },
33    /// Message IDs are only meaningful for cFS command and telemetry packets.
34    MessageIdUnsupported { item: String },
35    /// Message IDs must resolve to non-negative integers for cFS codegen.
36    MessageIdValueUnsupported { packet: String },
37    /// cFS command packets require an explicit command code.
38    MissingCommandCode { packet: String },
39    /// Command codes are only meaningful for cFS command packets.
40    CommandCodeUnsupported { item: String },
41    /// Command codes must be literal non-negative integers for cFS codegen today.
42    CommandCodeValueUnsupported { packet: String },
43    /// Literal MIDs must be unique within one generated file.
44    DuplicateMid {
45        mid: String,
46        first_packet: String,
47        second_packet: String,
48    },
49    /// Literal command MID/CC pairs must be unique within one generated file.
50    DuplicateCommandCode {
51        mid: String,
52        cc: String,
53        first_packet: String,
54        second_packet: String,
55    },
56    /// Literal command/telemetry MIDs must match the expected cFS command bit pattern.
57    MidRangeMismatch {
58        packet: String,
59        mid: String,
60        expected: &'static str,
61    },
62    /// Dynamic arrays parse today, but cFS ABI codegen has no ownership/length model yet.
63    DynamicArrayUnsupported {
64        container: String,
65        field: String,
66        ty: String,
67    },
68    /// Non-string bounded arrays parse today, but cFS ABI codegen has no inline representation yet.
69    BoundedArrayUnsupported {
70        container: String,
71        field: String,
72        ty: String,
73    },
74}
75
76impl fmt::Display for CodegenError {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        match self {
79            CodegenError::OptionalFieldUnsupported { .. }
80            | CodegenError::DefaultValueUnsupported { .. }
81            | CodegenError::UnboundedStringUnsupported { .. }
82            | CodegenError::DynamicArrayUnsupported { .. }
83            | CodegenError::BoundedArrayUnsupported { .. } => fmt_field_error(self, f),
84            CodegenError::EnumFieldUnsupported { .. }
85            | CodegenError::EnumRepresentationUnsupported { .. }
86            | CodegenError::EnumVariantValueRequired { .. }
87            | CodegenError::EnumVariantValueOutOfRange { .. } => fmt_enum_error(self, f),
88            CodegenError::LegacyMessageUnsupported { .. }
89            | CodegenError::MissingMid { .. }
90            | CodegenError::MessageIdUnsupported { .. }
91            | CodegenError::MessageIdValueUnsupported { .. }
92            | CodegenError::MidRangeMismatch { .. } => fmt_mid_error(self, f),
93            CodegenError::MissingCommandCode { .. }
94            | CodegenError::CommandCodeUnsupported { .. }
95            | CodegenError::CommandCodeValueUnsupported { .. } => fmt_command_error(self, f),
96            CodegenError::DuplicateMid { .. } | CodegenError::DuplicateCommandCode { .. } => {
97                fmt_duplicate_error(self, f)
98            }
99        }
100    }
101}
102
103fn fmt_field_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104    match error {
105        CodegenError::OptionalFieldUnsupported { .. }
106        | CodegenError::DefaultValueUnsupported { .. }
107        | CodegenError::UnboundedStringUnsupported { .. } => fmt_scalar_field_error(error, f),
108        CodegenError::DynamicArrayUnsupported { .. }
109        | CodegenError::BoundedArrayUnsupported { .. } => fmt_array_field_error(error, f),
110        _ => unreachable!("non-field error passed to fmt_field_error"),
111    }
112}
113
114fn fmt_scalar_field_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115    match error {
116        CodegenError::OptionalFieldUnsupported { container, field } => write!(
117            f,
118            "optional field `{container}.{field}` is not supported by cFS codegen yet"
119        ),
120        CodegenError::DefaultValueUnsupported { container, field } => write!(
121            f,
122            "default value for field `{container}.{field}` is not supported by cFS codegen yet"
123        ),
124        CodegenError::UnboundedStringUnsupported { container, field } => write!(
125            f,
126            "unbounded string field `{container}.{field}` is not supported by cFS codegen; use `string[<=N]` or `string[N]`"
127        ),
128        _ => unreachable!("non-scalar field error passed to fmt_scalar_field_error"),
129    }
130}
131
132fn fmt_array_field_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133    match error {
134        CodegenError::DynamicArrayUnsupported {
135            container,
136            field,
137            ty,
138        } => write!(
139            f,
140            "dynamic array field `{container}.{field}` with type `{ty}` is not supported by cFS codegen yet"
141        ),
142        CodegenError::BoundedArrayUnsupported {
143            container,
144            field,
145            ty,
146        } => write!(
147            f,
148            "bounded array field `{container}.{field}` with type `{ty}` is not supported by cFS codegen yet"
149        ),
150        _ => unreachable!("non-array field error passed to fmt_array_field_error"),
151    }
152}
153
154fn fmt_enum_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155    match error {
156        CodegenError::EnumFieldUnsupported {
157            container,
158            field,
159            ty,
160        } => write!(
161            f,
162            "enum field `{container}.{field}` with type `{ty}` needs an explicit integer representation for cFS codegen"
163        ),
164        CodegenError::EnumRepresentationUnsupported { enum_name, repr } => write!(
165            f,
166            "enum `{enum_name}` uses unsupported representation `{repr}`; cFS codegen supports integer enum representations"
167        ),
168        CodegenError::EnumVariantValueRequired { enum_name, variant } => write!(
169            f,
170            "enum `{enum_name}` variant `{variant}` needs an explicit value for cFS codegen"
171        ),
172        CodegenError::EnumVariantValueOutOfRange {
173            enum_name,
174            variant,
175            value,
176            repr,
177        } => write!(
178            f,
179            "enum `{enum_name}` variant `{variant}` value `{value}` does not fit `{repr}`"
180        ),
181        _ => unreachable!("non-enum error passed to fmt_enum_error"),
182    }
183}
184
185fn fmt_mid_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186    match error {
187        CodegenError::LegacyMessageUnsupported { .. }
188        | CodegenError::MissingMid { .. }
189        | CodegenError::MessageIdUnsupported { .. } => fmt_mid_presence_error(error, f),
190        CodegenError::MessageIdValueUnsupported { .. } | CodegenError::MidRangeMismatch { .. } => {
191            fmt_mid_value_error(error, f)
192        }
193        _ => unreachable!("non-MID error passed to fmt_mid_error"),
194    }
195}
196
197fn fmt_mid_presence_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198    match error {
199        CodegenError::LegacyMessageUnsupported { packet } => write!(
200            f,
201            "legacy message `{packet}` is not supported by cFS codegen; use `command` or `telemetry`"
202        ),
203        CodegenError::MissingMid { packet } => {
204            write!(f, "packet `{packet}` is missing required `@mid(...)`")
205        }
206        CodegenError::MessageIdUnsupported { item } => write!(
207            f,
208            "`@mid(...)` is only supported on command and telemetry packets, found on `{item}`"
209        ),
210        _ => unreachable!("non-MID presence error passed to fmt_mid_presence_error"),
211    }
212}
213
214fn fmt_mid_value_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215    match error {
216        CodegenError::MessageIdValueUnsupported { packet } => write!(
217            f,
218            "packet `{packet}` has unresolved or non-integer `@mid(...)`; cFS codegen requires an integer, hex, local integer constant, or imported integer constant message ID"
219        ),
220        CodegenError::MidRangeMismatch {
221            packet,
222            mid,
223            expected,
224        } => write!(f, "packet `{packet}` has MID `{mid}`, expected {expected}"),
225        _ => unreachable!("non-MID value error passed to fmt_mid_value_error"),
226    }
227}
228
229fn fmt_command_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230    match error {
231        CodegenError::MissingCommandCode { packet } => {
232            write!(f, "command `{packet}` is missing required `@cc(...)`")
233        }
234        CodegenError::CommandCodeUnsupported { item } => write!(
235            f,
236            "`@cc(...)` is only supported on command packets, found on `{item}`"
237        ),
238        CodegenError::CommandCodeValueUnsupported { packet } => write!(
239            f,
240            "command `{packet}` has unresolved or non-integer `@cc(...)`; cFS codegen requires an integer, hex, or local integer constant command code"
241        ),
242        _ => unreachable!("non-command error passed to fmt_command_error"),
243    }
244}
245
246fn fmt_duplicate_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247    match error {
248        CodegenError::DuplicateMid {
249            mid,
250            first_packet,
251            second_packet,
252        } => write!(
253            f,
254            "duplicate MID `{mid}` used by packets `{first_packet}` and `{second_packet}`"
255        ),
256        CodegenError::DuplicateCommandCode {
257            mid,
258            cc,
259            first_packet,
260            second_packet,
261        } => write!(
262            f,
263            "duplicate command MID/CC pair `{mid}`/`{cc}` used by packets `{first_packet}` and `{second_packet}`"
264        ),
265        _ => unreachable!("non-duplicate error passed to fmt_duplicate_error"),
266    }
267}
268
269impl StdError for CodegenError {}