1use crate::builder::value::{build_some_value, Value, ValueContent};
3use crate::context::Context;
4use crate::cursor::{Cursor, Error, Token, UnexpectedRuleSnafu};
5use crate::diagnostics::{DiagnosticError, DiagnosticWarning};
6use crate::location::FileLocation;
7use crate::map::Map;
8use crate::parser::Rule;
9use crate::reference::{Reference, TypeDefinitionTarget};
10
11#[derive(Clone, Debug, PartialEq)]
13pub struct TypeDefinition {
14 pub name: Token,
16 pub loc: FileLocation,
18 pub contents: TypeDefinitionContents,
20}
21impl std::fmt::Display for TypeDefinition {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 write!(f, "{}", self.name)
24 }
25}
26
27#[derive(Clone, Debug, PartialEq)]
29pub enum TypeDefinitionContents {
30 Regular(RegularTypeDefinition),
32 Enum(EnumTypeDefinition),
34 Bundle(BundleTypeDefinition),
36}
37
38#[derive(Clone, Debug, Default, PartialEq)]
40pub struct RegularTypeDefinition {
41 parent: Option<Reference<Token, TypeDefinitionTarget>>,
43 units: Map<String, Token>,
45 domain: Option<TypeDomain>,
47}
48
49#[derive(Clone, Debug, Default, PartialEq)]
51pub struct TypeDomain {
52 intervals: Vec<TypeInterval>,
54}
55
56#[derive(Clone, Debug, PartialEq)]
58pub enum TypeInterval {
59 Closed { lower: Bound, upper: Bound },
61 LowerBound(Bound),
63 UpperBound(Bound),
65 Point(Bound),
68}
69
70#[derive(Clone, Debug, PartialEq)]
72pub struct Bound {
73 pub value: Value,
75 pub inclusive: bool,
77}
78impl Default for Bound {
79 fn default() -> Self {
80 Self {
81 value: Value {
82 content: ValueContent::ToBeDetermined,
83 loc: Default::default(),
84 unit: Default::default(),
85 },
86 inclusive: true,
87 }
88 }
89}
90
91#[derive(Clone, Debug, Default, PartialEq)]
93pub struct EnumTypeDefinition {
94 pub values: Map<String, Value>,
96}
97
98#[derive(Clone, Debug, Default, PartialEq)]
100pub struct BundleTypeDefinition {
101 pub fields: Map<String, BundleFieldDefinition>,
103}
104
105#[derive(Clone, Debug, PartialEq)]
107pub struct BundleFieldDefinition {
108 pub name: Token,
110 pub loc: FileLocation,
112 pub definition: Reference<Token, TypeDefinitionTarget>,
114}
115impl std::fmt::Display for BundleFieldDefinition {
116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117 write!(f, "{}", self.name)
118 }
119}
120
121pub fn build_type_definition(ctx: &mut Context, type_definition: Cursor) -> Result<(), Error> {
123 let mut cs = type_definition.into_inner();
124 let contents = cs.req_first(Rule::type_definition_contents)?;
125 for type_definition_any in contents.into_inner().get_all(Rule::type_definition_any) {
126 let def = build_type_definition_any(ctx, type_definition_any)?;
127 if let Err(dupe) = ctx.specification.types.insert(def.to_string(), def) {
128 ctx.error(DiagnosticError::DuplicateDefinition, &dupe.loc.clone());
129 }
130 }
131 Ok(())
132}
133
134pub fn build_type_definition_any(
136 ctx: &mut Context,
137 type_definition_any: Cursor,
138) -> Result<TypeDefinition, Error> {
139 let mut cs = type_definition_any.into_inner();
140 let c = cs.req_next()?;
141 match c.as_rule() {
142 Rule::type_regular => build_regular_type_definition(ctx, c),
143 Rule::type_bundle => build_bundle_type(ctx, c),
144 Rule::type_enum => build_enum_type(ctx, c),
145 _ => UnexpectedRuleSnafu::from(c).fail()?,
146 }
147}
148
149pub fn build_regular_type_definition(
151 ctx: &mut Context,
152 type_regular: Cursor,
153) -> Result<TypeDefinition, Error> {
154 let loc = type_regular.as_location();
155 let mut cs = type_regular.into_inner();
156 let name = cs.req_first(Rule::some_type)?.into();
157
158 let mut def = RegularTypeDefinition::default();
159
160 for c in cs {
161 match c.as_rule() {
162 Rule::type_parent => {
163 let parent: Token = c.into_inner().req_first(Rule::some_type)?.into();
164 def.parent = Some(parent.into());
165 }
166 Rule::type_units => build_type_units(ctx, &mut def.units, c)?,
167 Rule::type_domain => {
168 def.domain = Some(build_type_domain(ctx, c)?);
169 }
170 _ => UnexpectedRuleSnafu::from(c).fail()?,
171 };
172 }
173
174 let def = TypeDefinition {
175 name,
176 loc,
177 contents: TypeDefinitionContents::Regular(def),
178 };
179
180 Ok(def)
181}
182
183pub fn build_type_units(
185 ctx: &mut Context,
186 units: &mut Map<String, Token>,
187 type_units: Cursor,
188) -> Result<(), Error> {
189 for some_unit in type_units.into_inner().get_all(Rule::some_unit) {
190 let token: Token = some_unit.into();
191 if let Err(dupe) = units.insert(token.to_string(), token) {
192 ctx.warn(DiagnosticWarning::Generic, &dupe.loc);
193 }
194 }
195 Ok(())
196}
197
198pub fn build_type_domain(ctx: &mut Context, type_domain: Cursor) -> Result<TypeDomain, Error> {
200 let mut domain = TypeDomain::default();
201 for c in type_domain.into_inner() {
202 match c.as_rule() {
203 Rule::type_domain_closed_range => {
204 let mut lower = Bound::default();
205 let mut upper = Bound::default();
206 for c in c.into_inner() {
207 match c.as_rule() {
208 Rule::type_domain_range_lower => {
209 lower = build_type_domain_range_lower(ctx, c)?;
210 }
211 Rule::type_domain_range_upper => {
212 upper = build_type_domain_range_upper(ctx, c)?;
213 }
214 Rule::kw_separator_enum_word => (),
215 _ => UnexpectedRuleSnafu::from(c).fail()?,
216 };
217 }
218 domain.intervals.push(TypeInterval::Closed { lower, upper });
219 }
220 Rule::type_domain_range_lower => {
221 domain
222 .intervals
223 .push(TypeInterval::LowerBound(build_type_domain_range_lower(
224 ctx, c,
225 )?))
226 }
227
228 Rule::type_domain_range_upper => {
229 domain
230 .intervals
231 .push(TypeInterval::UpperBound(build_type_domain_range_upper(
232 ctx, c,
233 )?))
234 }
235 Rule::type_domain_constant => {
236 domain.intervals.push(build_type_domain_constant(ctx, c)?)
237 }
238 _ => UnexpectedRuleSnafu::from(c).fail()?,
239 };
240 }
241 Ok(domain)
242}
243
244pub fn build_type_domain_range_lower(
246 ctx: &mut Context,
247 type_domain_range_lower: Cursor,
248) -> Result<Bound, Error> {
249 let mut bound = Bound::default();
250 for c in type_domain_range_lower.into_inner() {
251 match c.as_rule() {
252 Rule::kw_comparison_least => {
253 bound.inclusive = true;
254 }
255 Rule::some_value => {
256 bound.value = build_some_value(ctx, c)?;
257 }
258 Rule::kw_control_of => (),
259 Rule::kw_comparison_at => (),
260 Rule::kw_comparison_greater => (),
261 Rule::kw_comparison_than => (),
262 _ => UnexpectedRuleSnafu::from(c).fail()?,
263 };
264 }
265 Ok(bound)
266}
267
268pub fn build_type_domain_range_upper(
270 ctx: &mut Context,
271 type_domain_range_upper: Cursor,
272) -> Result<Bound, Error> {
273 let mut bound = Bound::default();
274 for c in type_domain_range_upper.into_inner() {
275 match c.as_rule() {
276 Rule::kw_comparison_most => {
277 bound.inclusive = true;
278 }
279 Rule::some_value => {
280 bound.value = build_some_value(ctx, c)?;
281 }
282 Rule::kw_control_of => (),
283 Rule::kw_comparison_at => (),
284 Rule::kw_comparison_smaller => (),
285 Rule::kw_comparison_than => (),
286 _ => UnexpectedRuleSnafu::from(c).fail()?,
287 };
288 }
289 Ok(bound)
290}
291
292pub fn build_type_domain_constant(
294 ctx: &mut Context,
295 type_domain_constant: Cursor,
296) -> Result<TypeInterval, Error> {
297 let mut cs = type_domain_constant.into_inner();
298 let not_equal = cs
299 .req_next()
300 .map(|p| p.as_rule() == Rule::kw_comparison_not)?;
301 let value = cs
302 .req_first(Rule::some_value)
303 .and_then(|some_value| build_some_value(ctx, some_value))?;
304 Ok(TypeInterval::Point(Bound {
305 value,
306 inclusive: !not_equal,
307 }))
308}
309
310pub fn build_enum_type(ctx: &mut Context, type_enum: Cursor) -> Result<TypeDefinition, Error> {
312 let mut cs = type_enum.into_inner();
313 let name = cs
314 .req_first(Rule::some_type)
315 .map(|some_type| some_type.into())?;
316
317 let mut enum_def = EnumTypeDefinition::default();
318 let loc = cs.as_location();
319
320 for c in cs {
321 if let Some(values) = match c.as_rule() {
322 Rule::enum_values_inline => Some(c.into_inner().get_all(Rule::some_value)),
323 Rule::enum_value_line => Some(c.into_inner().get_all(Rule::some_value)),
324 _ => None,
325 } {
326 for some_value in values {
327 let value = build_some_value(ctx, some_value)?;
328 if let Err(dupe) = enum_def.values.insert(value.to_string(), value) {
329 ctx.warn(DiagnosticWarning::Redefinition, &dupe.loc);
330 }
331 }
332 }
333 }
334
335 let def = TypeDefinition {
336 name,
337 loc,
338 contents: TypeDefinitionContents::Enum(enum_def),
339 };
340
341 Ok(def)
342}
343
344pub fn build_bundle_type(ctx: &mut Context, type_bundle: Cursor) -> Result<TypeDefinition, Error> {
346 let mut bundle = BundleTypeDefinition::default();
347 let mut cs = type_bundle.into_inner();
348 let name = cs
349 .req_first(Rule::some_type)
350 .map(|some_type| some_type.into())?;
351
352 let loc = cs.as_location();
353
354 for c in cs {
355 if let Some(fields) = match c.as_rule() {
356 Rule::bundle_fields_inline => Some(c.into_inner().get_all(Rule::bundle_field)),
357 Rule::bundle_field_line => Some(c.into_inner().get_all(Rule::bundle_field)),
358 _ => None,
359 } {
360 for bundle_field in fields {
361 let field = build_bundle_field(ctx, bundle_field)?;
362 if let Err(dupe) = bundle.fields.insert(field.to_string(), field) {
363 ctx.warn(DiagnosticWarning::Redefinition, &dupe.loc);
364 }
365 }
366 }
367 }
368
369 let def = TypeDefinition {
370 name,
371 loc,
372 contents: TypeDefinitionContents::Bundle(bundle),
373 };
374
375 Ok(def)
376}
377
378pub fn build_bundle_field(
380 ctx: &mut Context,
381 bundle_field: Cursor,
382) -> Result<BundleFieldDefinition, Error> {
383 let mut cs = bundle_field.into_inner();
384 let name = cs.req_first(Rule::some_name)?.into();
385 let definition: Reference<Token, _> = cs
386 .req_first(Rule::some_type)
387 .map(Into::<Token>::into)?
388 .into();
389 Ok(BundleFieldDefinition {
390 name,
391 loc: cs.as_location(),
392 definition,
393 })
394}