1use std::collections::HashSet;
12
13use chumsky::error::Rich;
14use thiserror::Error;
15
16use crate::parameter::{Parameter, ParameterKind, ValueType};
17use crate::property::{Property, PropertyKind};
18use crate::string_storage::{Segments, Span};
19use crate::syntax::{RawComponent, RawParameter, RawProperty};
20use crate::value::{Value, parse_value};
21
22pub fn typed_analysis(
27 components: Vec<RawComponent<'_>>,
28) -> Result<Vec<TypedComponent<'_>>, Vec<TypedError<'_>>> {
29 let mut typed_components = Vec::with_capacity(components.len());
30 let mut errors = Vec::new();
31 for comp in components {
32 match typed_component(comp) {
33 Ok(typed_comp) => typed_components.push(typed_comp),
34 Err(errs) => errors.extend(errs),
35 }
36 }
37
38 if errors.is_empty() {
39 Ok(typed_components)
40 } else {
41 Err(errors)
42 }
43}
44
45fn typed_component(comp: RawComponent<'_>) -> Result<TypedComponent<'_>, Vec<TypedError<'_>>> {
46 let mut existing_props = HashSet::with_capacity(comp.properties.len());
47 let mut properties = Vec::with_capacity(comp.properties.len());
48 let mut errors = Vec::new();
49 for prop in comp.properties {
50 match parsed_property(&mut existing_props, prop) {
51 Ok(prop) => match Property::try_from(prop) {
53 Ok(property) => properties.push(property),
54 Err(errs) => errors.extend(errs),
55 },
56 Err(errs) => errors.extend(errs),
57 }
58 }
59
60 let mut children = Vec::with_capacity(comp.children.len());
61 for comp in comp.children {
62 match typed_component(comp) {
63 Ok(child) => children.push(child),
64 Err(errs) => errors.extend(errs),
65 }
66 }
67
68 if errors.is_empty() {
69 Ok(TypedComponent {
70 name: comp.name,
71 properties,
72 children,
73 span: comp.span,
74 })
75 } else {
76 Err(errors)
77 }
78}
79
80fn parsed_property<'src>(
81 _existing: &mut HashSet<&str>,
82 prop: RawProperty<'src>,
83) -> Result<ParsedProperty<'src>, Vec<TypedError<'src>>> {
84 let kind = PropertyKind::from(prop.name.clone());
86
87 let parameters = parameters(prop.parameters)?;
88 let value_types = value_types(&kind, ¶meters)?;
89
90 let value = parse_value(&value_types, &prop.value).map_err(|errs| {
92 errs.into_iter()
93 .map(|err| TypedError::ValueSyntax {
94 value: prop.value.clone(),
95 err,
96 })
97 .collect::<Vec<_>>()
98 })?;
99
100 Ok(ParsedProperty {
101 kind,
102 parameters,
103 value,
104 span: prop.name.span(),
105 name: prop.name,
106 })
107}
108
109#[derive(Debug, Clone)]
111pub struct TypedComponent<'src> {
112 pub name: Segments<'src>,
114 pub properties: Vec<Property<Segments<'src>>>,
116 pub children: Vec<TypedComponent<'src>>,
118 pub span: Span,
120}
121
122#[derive(Debug, Clone)]
124pub struct ParsedProperty<'src> {
125 pub kind: PropertyKind<Segments<'src>>,
127 pub name: Segments<'src>,
129 pub parameters: Vec<Parameter<Segments<'src>>>,
131 pub value: Value<Segments<'src>>,
133 pub span: Span,
135}
136
137#[non_exhaustive]
139#[derive(Error, Debug, Clone)]
140pub enum TypedError<'src> {
141 #[error("Parameter '{parameter}' occurs multiple times")]
143 ParameterDuplicated {
144 parameter: ParameterKind<Segments<'src>>,
146 span: Span,
148 },
149
150 #[error("Parameter '{parameter}' does not allow multiple values")]
152 ParameterMultipleValuesDisallowed {
153 parameter: ParameterKind<Segments<'src>>,
155 span: Span,
157 },
158
159 #[error("Parameter '{parameter}={value}' value must be quoted")]
161 ParameterValueMustBeQuoted {
162 parameter: ParameterKind<Segments<'src>>,
164 value: Segments<'src>,
166 span: Span,
168 },
169
170 #[error("Parameter '{parameter}=\"{value}\"' value must not be quoted")]
172 ParameterValueMustNotBeQuoted {
173 parameter: ParameterKind<Segments<'src>>,
175 value: Segments<'src>,
177 span: Span,
179 },
180
181 #[error("Invalid value for parameter '{parameter}={value}'")]
183 ParameterValueInvalid {
184 parameter: ParameterKind<Segments<'src>>,
186 value: Segments<'src>,
188 span: Span,
190 },
191
192 #[error("Invalid value type '{value_type}' for property '{property}'")]
194 ValueTypeDisallowed {
195 property: PropertyKind<Segments<'src>>,
197 value_type: ValueType<Segments<'src>>,
199 expected_types: &'static [ValueType<String>],
201 span: Span,
203 },
204
205 #[error("Syntax error in value '{value}': {err}")]
207 ValueSyntax {
208 value: Segments<'src>,
210 err: Rich<'src, char>,
212 },
213
214 #[error("Expected property kind '{expected}', found '{found}'")]
216 PropertyUnexpectedKind {
217 expected: PropertyKind<Segments<'src>>,
219 found: PropertyKind<Segments<'src>>,
221 span: Span,
223 },
224
225 #[error("Property '{property}' has no values")]
227 PropertyMissingValue {
228 property: PropertyKind<Segments<'src>>,
230 span: Span,
232 },
233
234 #[error("Property '{property}' requires exactly {expected} value(s), but found {found}")]
236 PropertyInvalidValueCount {
237 property: PropertyKind<Segments<'src>>,
239 expected: usize,
241 found: usize,
243 span: Span,
245 },
246
247 #[error("Invalid value '{value}' for property '{property}'")]
249 PropertyInvalidValue {
250 property: PropertyKind<Segments<'src>>,
252 value: String,
254 span: Span,
256 },
257
258 #[error("Expected {expected:?} value(s) for property '{property}', found {found}")]
260 PropertyUnexpectedValue {
261 property: PropertyKind<Segments<'src>>,
263 expected: &'static [ValueType<String>],
265 found: ValueType<Segments<'src>>,
267 span: Span,
269 },
270}
271
272impl TypedError<'_> {
273 #[must_use]
275 pub fn span(&self) -> Span {
276 match self {
277 TypedError::ParameterDuplicated { span, .. }
278 | TypedError::ParameterMultipleValuesDisallowed { span, .. }
279 | TypedError::ParameterValueMustBeQuoted { span, .. }
280 | TypedError::ParameterValueMustNotBeQuoted { span, .. }
281 | TypedError::ParameterValueInvalid { span, .. }
282 | TypedError::ValueTypeDisallowed { span, .. }
283 | TypedError::PropertyUnexpectedKind { span, .. }
284 | TypedError::PropertyInvalidValueCount { span, .. }
285 | TypedError::PropertyInvalidValue { span, .. }
286 | TypedError::PropertyMissingValue { span, .. }
287 | TypedError::PropertyUnexpectedValue { span, .. } => *span,
288
289 TypedError::ValueSyntax { err, .. } => (*err.span()).into(),
290 }
291 }
292}
293
294fn parameters(
295 params: Vec<RawParameter<Segments<'_>>>,
296) -> Result<Vec<Parameter<Segments<'_>>>, Vec<TypedError<'_>>> {
297 let mut parsed = Vec::with_capacity(params.len());
298 let mut errors = Vec::new();
299 for param in params {
300 match Parameter::try_from(param) {
301 Ok(typed) => parsed.push(typed),
302 Err(errs) => errors.extend(errs),
303 }
304 }
305
306 if errors.is_empty() {
307 Ok(parsed)
308 } else {
309 Err(errors)
310 }
311}
312
313fn value_types<'src>(
314 prop_kind: &PropertyKind<Segments<'src>>,
315 params: &Vec<Parameter<Segments<'src>>>,
316) -> Result<Vec<ValueType<String>>, Vec<TypedError<'src>>> {
317 if let Some(Parameter::ValueType { value, span }) = params
319 .iter()
320 .find(|param| matches!(param, Parameter::ValueType { .. }))
321 {
322 match prop_kind.value_types() {
323 Some(value_types) => {
324 if value_types
325 .iter()
326 .any(|a| a.try_eq_known(&value.to_owned()).unwrap_or(false))
327 {
328 Ok(vec![value.to_owned()])
330 } else {
331 Err(vec![TypedError::ValueTypeDisallowed {
332 property: prop_kind.clone(),
333 value_type: value.clone(),
334 expected_types: value_types,
335 span: *span,
336 }])
337 }
338 }
339
340 None => Ok(vec![value.to_owned()]),
342 }
343 } else {
344 match prop_kind.value_types() {
345 Some(value_types) => value_types
349 .iter()
350 .filter(|&t| !matches!(t, ValueType::<String>::Binary))
351 .map(|t| Ok(t.clone()))
352 .collect(),
353
354 None => Ok(vec![ValueType::<String>::Unrecognized(
358 Segments::default().to_string(),
359 )]),
360 }
361 }
362}