Skip to main content

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}