clifford_codegen/spec/error.rs
1//! Error types for specification parsing.
2//!
3//! These errors provide detailed information about what went wrong
4//! during parsing, making it easy to fix specification files.
5
6use thiserror::Error;
7
8/// Errors that can occur when parsing an algebra specification.
9#[derive(Debug, Error)]
10pub enum ParseError {
11 /// TOML syntax error.
12 #[error("TOML parse error: {0}")]
13 Toml(#[from] toml::de::Error),
14
15 /// Algebra dimension exceeds the maximum supported (6).
16 #[error("dimension {0} exceeds maximum of 6")]
17 DimensionTooLarge(usize),
18
19 /// Signature must have at least one basis vector.
20 #[error("signature must have at least one basis vector")]
21 EmptySignature,
22
23 /// Duplicate basis vector name in signature.
24 #[error("duplicate basis vector name: '{0}'")]
25 DuplicateBasisName(String),
26
27 /// Invalid basis vector name in signature.
28 #[error("invalid basis vector name: '{name}' (expected format: e1, e2, e3, etc.)")]
29 InvalidBasisName {
30 /// The invalid basis name.
31 name: String,
32 },
33
34 /// Basis vector index exceeds algebra dimension.
35 #[error("basis '{name}' references index {index} but algebra only has {dim} dimensions")]
36 BasisIndexOutOfBounds {
37 /// The basis name.
38 name: String,
39 /// The invalid index (1-based from name).
40 index: usize,
41 /// Algebra dimension.
42 dim: usize,
43 },
44
45 /// Basis vector indices are not contiguous (0, 1, 2, ...).
46 #[error(
47 "basis vector indices must be contiguous: expected index {expected} but found {found} for '{name}'"
48 )]
49 NonContiguousBasisIndices {
50 /// The expected index.
51 expected: usize,
52 /// The found index.
53 found: usize,
54 /// The basis name with the wrong index.
55 name: String,
56 },
57
58 /// Type references a grade that exceeds the algebra dimension.
59 #[error("type '{type_name}' has invalid grade {grade} (max: {max})")]
60 InvalidGrade {
61 /// The type name.
62 type_name: String,
63 /// The invalid grade.
64 grade: usize,
65 /// Maximum valid grade.
66 max: usize,
67 },
68
69 /// Type has wrong number of fields for its grades.
70 #[error("type '{type_name}' has {got} fields but needs {expected}")]
71 FieldCountMismatch {
72 /// The type name.
73 type_name: String,
74 /// Expected number of fields.
75 expected: usize,
76 /// Actual number of fields.
77 got: usize,
78 },
79
80 /// Duplicate field name in a type.
81 #[error("type '{type_name}' has duplicate field name: '{field}'")]
82 DuplicateFieldName {
83 /// The type name.
84 type_name: String,
85 /// The duplicate field name.
86 field: String,
87 },
88
89 /// Duplicate type name in specification.
90 #[error("duplicate type name: '{0}'")]
91 DuplicateTypeName(String),
92
93 /// Invalid blade name in blades section.
94 #[error("invalid blade name: '{name}' (expected format: e1, e12, e123, etc.)")]
95 InvalidBladeName {
96 /// The invalid blade name.
97 name: String,
98 },
99
100 /// Blade index exceeds algebra dimension.
101 #[error("blade '{name}' references basis index {index} but algebra only has {dim} dimensions")]
102 BladeIndexOutOfBounds {
103 /// The blade name.
104 name: String,
105 /// The invalid index.
106 index: usize,
107 /// Algebra dimension.
108 dim: usize,
109 },
110
111 /// Unknown type reference (e.g., in alias_of).
112 #[error("unknown type reference: '{0}'")]
113 UnknownType(String),
114
115 /// Type alias references itself.
116 #[error("type '{type_name}' cannot alias itself")]
117 SelfAlias {
118 /// The type name.
119 type_name: String,
120 },
121
122 /// Type alias forms a cycle.
123 #[error("type alias cycle detected involving '{type_name}'")]
124 AliasCycle {
125 /// The type name.
126 type_name: String,
127 },
128
129 /// Unknown field name in a type's field list.
130 #[error("type '{type_name}' has unknown field name: '{field}'")]
131 UnknownFieldName {
132 /// The type name.
133 type_name: String,
134 /// The unknown field name.
135 field: String,
136 },
137
138 /// Invalid value for a configuration field.
139 #[error("invalid value '{value}' for field '{field}', expected {expected}")]
140 InvalidValue {
141 /// The field name.
142 field: String,
143 /// The invalid value.
144 value: String,
145 /// Description of expected values.
146 expected: String,
147 },
148
149 /// Sparse type blade count doesn't match field count.
150 #[error("type '{type_name}' has {blades} blade mappings but {fields} fields")]
151 SparseBladeCountMismatch {
152 /// The type name.
153 type_name: String,
154 /// Number of blade mappings.
155 blades: usize,
156 /// Number of fields.
157 fields: usize,
158 },
159
160 /// Sparse type blade doesn't match specified grades.
161 #[error(
162 "type '{type_name}' blade '{blade}' has grade {blade_grade} but type only spans grades {grades:?}"
163 )]
164 SparseBladeGradeMismatch {
165 /// The type name.
166 type_name: String,
167 /// The blade name.
168 blade: String,
169 /// The blade's actual grade.
170 blade_grade: usize,
171 /// The expected grades.
172 grades: Vec<usize>,
173 },
174
175 /// Algebra is incomplete: some products don't have matching output types.
176 #[error(
177 "algebra '{name}' is incomplete: {count} products have no output type.\n{details}\nAdd missing types or set `complete = false` in [algebra] section."
178 )]
179 IncompleteAlgebra {
180 /// Algebra name.
181 name: String,
182 /// Number of missing products.
183 count: usize,
184 /// Human-readable details of missing products.
185 details: String,
186 },
187
188 /// Type is missing required field_map.
189 #[error(
190 "type '{type_name}' is missing required field_map (explicit blade-to-field mappings are required)"
191 )]
192 MissingFieldMap {
193 /// The type name.
194 type_name: String,
195 },
196
197 /// Blade grade in field_map doesn't match type's grades.
198 #[error(
199 "type '{type_name}' field '{field}' maps to blade '{blade}' (grade {blade_grade}) but type only spans grades {grades:?}"
200 )]
201 FieldMapGradeMismatch {
202 /// The type name.
203 type_name: String,
204 /// The field name.
205 field: String,
206 /// The blade name.
207 blade: String,
208 /// The blade's actual grade.
209 blade_grade: usize,
210 /// The expected grades.
211 grades: Vec<usize>,
212 },
213}
214
215/// Describes a product that has no matching output type.
216#[derive(Debug, Clone)]
217pub struct MissingProduct {
218 /// Left operand type name.
219 pub lhs: String,
220 /// Right operand type name.
221 pub rhs: String,
222 /// Product type name (e.g., "geometric", "exterior").
223 pub product_type: String,
224 /// Output grades produced by this product.
225 pub output_grades: Vec<usize>,
226}