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    /// Deployment message IDs do not belong in reusable schemas.
32    MessageIdUnsupported { item: String },
33    /// Commands must belong to a logical command topic.
34    CommandGroupRequired { packet: String },
35    /// cFS command packets require an explicit command code.
36    MissingCommandCode { packet: String },
37    /// Command codes are only meaningful for cFS command packets.
38    CommandCodeUnsupported { item: String },
39    /// Command codes must be literal non-negative integers for cFS codegen today.
40    CommandCodeValueUnsupported { packet: String },
41    /// Generated command-code constants use the cFE function-code ABI type.
42    CommandCodeOutOfRange { packet: String, value: u64 },
43    /// Function codes must be unique within one logical command topic.
44    DuplicateCommandCodeInGroup {
45        group: String,
46        cc: String,
47        first_packet: String,
48        second_packet: String,
49    },
50    /// Dynamic arrays parse today, but cFS ABI codegen has no ownership/length model yet.
51    DynamicArrayUnsupported {
52        container: String,
53        field: String,
54        ty: String,
55    },
56    /// Non-string bounded arrays parse today, but cFS ABI codegen has no inline representation yet.
57    BoundedArrayUnsupported {
58        container: String,
59        field: String,
60        ty: String,
61    },
62}
63
64impl fmt::Display for CodegenError {
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66        match self {
67            CodegenError::OptionalFieldUnsupported { .. }
68            | CodegenError::DefaultValueUnsupported { .. }
69            | CodegenError::UnboundedStringUnsupported { .. }
70            | CodegenError::DynamicArrayUnsupported { .. }
71            | CodegenError::BoundedArrayUnsupported { .. } => fmt_field_error(self, f),
72            CodegenError::EnumFieldUnsupported { .. }
73            | CodegenError::EnumRepresentationUnsupported { .. }
74            | CodegenError::EnumVariantValueRequired { .. }
75            | CodegenError::EnumVariantValueOutOfRange { .. } => fmt_enum_error(self, f),
76            CodegenError::LegacyMessageUnsupported { .. }
77            | CodegenError::MessageIdUnsupported { .. }
78            | CodegenError::CommandGroupRequired { .. } => fmt_packet_error(self, f),
79            CodegenError::MissingCommandCode { .. }
80            | CodegenError::CommandCodeUnsupported { .. }
81            | CodegenError::CommandCodeValueUnsupported { .. }
82            | CodegenError::CommandCodeOutOfRange { .. } => fmt_command_error(self, f),
83            CodegenError::DuplicateCommandCodeInGroup { .. } => fmt_duplicate_error(self, f),
84        }
85    }
86}
87
88fn fmt_field_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89    match error {
90        CodegenError::OptionalFieldUnsupported { .. }
91        | CodegenError::DefaultValueUnsupported { .. }
92        | CodegenError::UnboundedStringUnsupported { .. } => fmt_scalar_field_error(error, f),
93        CodegenError::DynamicArrayUnsupported { .. }
94        | CodegenError::BoundedArrayUnsupported { .. } => fmt_array_field_error(error, f),
95        _ => unreachable!("non-field error passed to fmt_field_error"),
96    }
97}
98
99fn fmt_scalar_field_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100    match error {
101        CodegenError::OptionalFieldUnsupported { container, field } => write!(
102            f,
103            "optional field `{container}.{field}` is not supported by cFS codegen yet"
104        ),
105        CodegenError::DefaultValueUnsupported { container, field } => write!(
106            f,
107            "default value for field `{container}.{field}` is not supported by cFS codegen yet"
108        ),
109        CodegenError::UnboundedStringUnsupported { container, field } => write!(
110            f,
111            "unbounded string field `{container}.{field}` is not supported by cFS codegen; use `string[<=N]` or `string[N]`"
112        ),
113        _ => unreachable!("non-scalar field error passed to fmt_scalar_field_error"),
114    }
115}
116
117fn fmt_array_field_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118    match error {
119        CodegenError::DynamicArrayUnsupported {
120            container,
121            field,
122            ty,
123        } => write!(
124            f,
125            "dynamic array field `{container}.{field}` with type `{ty}` is not supported by cFS codegen yet"
126        ),
127        CodegenError::BoundedArrayUnsupported {
128            container,
129            field,
130            ty,
131        } => write!(
132            f,
133            "bounded array field `{container}.{field}` with type `{ty}` is not supported by cFS codegen yet"
134        ),
135        _ => unreachable!("non-array field error passed to fmt_array_field_error"),
136    }
137}
138
139fn fmt_enum_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140    match error {
141        CodegenError::EnumFieldUnsupported {
142            container,
143            field,
144            ty,
145        } => write!(
146            f,
147            "enum field `{container}.{field}` with type `{ty}` needs an explicit integer representation for cFS codegen"
148        ),
149        CodegenError::EnumRepresentationUnsupported { enum_name, repr } => write!(
150            f,
151            "enum `{enum_name}` uses unsupported representation `{repr}`; cFS codegen supports integer enum representations"
152        ),
153        CodegenError::EnumVariantValueRequired { enum_name, variant } => write!(
154            f,
155            "enum `{enum_name}` variant `{variant}` needs an explicit value for cFS codegen"
156        ),
157        CodegenError::EnumVariantValueOutOfRange {
158            enum_name,
159            variant,
160            value,
161            repr,
162        } => write!(
163            f,
164            "enum `{enum_name}` variant `{variant}` value `{value}` does not fit `{repr}`"
165        ),
166        _ => unreachable!("non-enum error passed to fmt_enum_error"),
167    }
168}
169
170fn fmt_packet_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171    match error {
172        CodegenError::LegacyMessageUnsupported { packet } => write!(
173            f,
174            "legacy message `{packet}` is not supported by cFS codegen; use `command` or `telemetry`"
175        ),
176        CodegenError::MessageIdUnsupported { item } => write!(
177            f,
178            "`@mid(...)` is not supported on `{item}`; assign its logical topic in the mission manifest"
179        ),
180        CodegenError::CommandGroupRequired { packet } => write!(
181            f,
182            "command `{packet}` must be declared inside a `commands` group"
183        ),
184        _ => unreachable!("non-packet error passed to fmt_packet_error"),
185    }
186}
187
188fn fmt_command_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189    match error {
190        CodegenError::MissingCommandCode { packet } => {
191            write!(f, "command `{packet}` is missing required `@cc(...)`")
192        }
193        CodegenError::CommandCodeUnsupported { item } => write!(
194            f,
195            "`@cc(...)` is only supported on command packets, found on `{item}`"
196        ),
197        CodegenError::CommandCodeValueUnsupported { packet } => write!(
198            f,
199            "command `{packet}` has unresolved or non-integer `@cc(...)`; cFS codegen requires an integer, hex, or local integer constant command code"
200        ),
201        CodegenError::CommandCodeOutOfRange { packet, value } => write!(
202            f,
203            "command `{packet}` has function code `{value}` outside the supported `u16` range"
204        ),
205        _ => unreachable!("non-command error passed to fmt_command_error"),
206    }
207}
208
209fn fmt_duplicate_error(error: &CodegenError, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210    match error {
211        CodegenError::DuplicateCommandCodeInGroup {
212            group,
213            cc,
214            first_packet,
215            second_packet,
216        } => write!(
217            f,
218            "duplicate function code `{cc}` in command topic `{group}` used by commands `{first_packet}` and `{second_packet}`"
219        ),
220        _ => unreachable!("non-duplicate error passed to fmt_duplicate_error"),
221    }
222}
223
224impl StdError for CodegenError {}