1use proc_macro2::Span;
2use quote::ToTokens;
3
4use crate::{dsl_hir, mir};
5
6pub fn transform(device: dsl_hir::Device) -> Result<mir::Device, syn::Error> {
7 let global_config = device.global_config_list.try_into()?;
8 let objects = transform_object_list(device.object_list, &global_config)?;
9
10 Ok(mir::Device {
11 name: None,
12 global_config,
13 objects,
14 })
15}
16
17impl From<dsl_hir::Access> for mir::Access {
18 fn from(value: dsl_hir::Access) -> Self {
19 match value {
20 dsl_hir::Access::RW => mir::Access::RW,
21 dsl_hir::Access::RO => mir::Access::RO,
22 dsl_hir::Access::WO => mir::Access::WO,
23 }
24 }
25}
26
27impl From<dsl_hir::ByteOrder> for mir::ByteOrder {
28 fn from(value: dsl_hir::ByteOrder) -> Self {
29 match value {
30 dsl_hir::ByteOrder::LE => mir::ByteOrder::LE,
31 dsl_hir::ByteOrder::BE => mir::ByteOrder::BE,
32 }
33 }
34}
35
36impl From<dsl_hir::BitOrder> for mir::BitOrder {
37 fn from(value: dsl_hir::BitOrder) -> Self {
38 match value {
39 dsl_hir::BitOrder::LSB0 => mir::BitOrder::LSB0,
40 dsl_hir::BitOrder::MSB0 => mir::BitOrder::MSB0,
41 }
42 }
43}
44
45impl TryFrom<syn::Ident> for mir::Integer {
46 type Error = syn::Error;
47
48 fn try_from(value: syn::Ident) -> Result<Self, Self::Error> {
49 match value.to_string().as_str() {
50 "u8" => Ok(mir::Integer::U8),
51 "u16" => Ok(mir::Integer::U16),
52 "u32" => Ok(mir::Integer::U32),
53 "i8" => Ok(mir::Integer::I8),
54 "i16" => Ok(mir::Integer::I16),
55 "i32" => Ok(mir::Integer::I32),
56 "i64" => Ok(mir::Integer::I64),
57 _ => Err(syn::Error::new(
58 value.span(),
59 "Must be an integer type: u8, u16, u32, i8, i16, i32, i64",
60 )),
61 }
62 }
63}
64
65impl TryFrom<dsl_hir::Repeat> for mir::Repeat {
66 type Error = syn::Error;
67
68 fn try_from(value: dsl_hir::Repeat) -> Result<Self, Self::Error> {
69 Ok(Self {
70 count: value.count.base10_parse()?,
71 stride: value.stride.base10_parse()?,
72 })
73 }
74}
75
76impl From<dsl_hir::BaseType> for mir::BaseType {
77 fn from(value: dsl_hir::BaseType) -> Self {
78 match value {
79 dsl_hir::BaseType::Bool => mir::BaseType::Bool,
80 dsl_hir::BaseType::Uint => mir::BaseType::Uint,
81 dsl_hir::BaseType::Int => mir::BaseType::Int,
82 }
83 }
84}
85
86impl TryFrom<dsl_hir::GlobalConfigList> for mir::GlobalConfig {
87 type Error = syn::Error;
88
89 fn try_from(value: dsl_hir::GlobalConfigList) -> Result<Self, Self::Error> {
90 let mut global_config = mir::GlobalConfig::default();
91
92 for config in value.configs.iter() {
93 let same_config_count = value
94 .configs
95 .iter()
96 .filter(|check_config| {
97 std::mem::discriminant(*check_config) == std::mem::discriminant(config)
98 })
99 .count();
100
101 if same_config_count > 1 {
102 return Err(syn::Error::new(
103 Span::call_site(),
104 format!("Duplicate global config found: `{config:?}`"),
105 ));
106 }
107
108 match config.clone() {
109 dsl_hir::GlobalConfig::DefaultRegisterAccess(value) => {
110 global_config.default_register_access = value.into()
111 }
112 dsl_hir::GlobalConfig::DefaultFieldAccess(value) => {
113 global_config.default_field_access = value.into()
114 }
115 dsl_hir::GlobalConfig::DefaultBufferAccess(value) => {
116 global_config.default_buffer_access = value.into()
117 }
118 dsl_hir::GlobalConfig::DefaultByteOrder(value) => {
119 global_config.default_byte_order = Some(value.into())
120 }
121 dsl_hir::GlobalConfig::DefaultBitOrder(value) => {
122 global_config.default_bit_order = value.into()
123 }
124 dsl_hir::GlobalConfig::RegisterAddressType(value) => {
125 global_config.register_address_type = Some(value.try_into()?)
126 }
127 dsl_hir::GlobalConfig::CommandAddressType(value) => {
128 global_config.command_address_type = Some(value.try_into()?)
129 }
130 dsl_hir::GlobalConfig::BufferAddressType(value) => {
131 global_config.buffer_address_type = Some(value.try_into()?)
132 }
133 dsl_hir::GlobalConfig::NameWordBoundaries(value) => {
134 global_config.name_word_boundaries = value
135 }
136 dsl_hir::GlobalConfig::DefmtFeature(lit_str) => {
137 global_config.defmt_feature = Some(lit_str.value())
138 }
139 }
140 }
141
142 Ok(global_config)
143 }
144}
145
146fn get_description(attrs: &dsl_hir::AttributeList) -> Option<String> {
147 let str = attrs
148 .attributes
149 .iter()
150 .filter_map(|attr| match attr {
151 dsl_hir::Attribute::Doc(val) => Some(val.as_str()),
152 dsl_hir::Attribute::Cfg(_, _) => None,
153 })
154 .collect::<Vec<_>>()
155 .join("\n");
156
157 if str.is_empty() { None } else { Some(str) }
158}
159
160fn get_cfg_attr(attrs: &dsl_hir::AttributeList) -> Result<mir::Cfg, syn::Error> {
161 let mut cfg_attrs = attrs
162 .attributes
163 .iter()
164 .filter_map(|attr| match attr {
165 dsl_hir::Attribute::Cfg(val, span) => Some((val, span)),
166 dsl_hir::Attribute::Doc(_) => None,
167 })
168 .collect::<Vec<_>>();
169
170 match cfg_attrs.len() {
171 0 => Ok(mir::Cfg::new(None)),
172 1 => Ok(mir::Cfg::new(Some(&cfg_attrs.remove(0).0.clone()))),
173 n => Err(syn::Error::new(
174 *cfg_attrs.remove(1).1,
175 format!("Only one cfg attribute is allowed, but {n} are found"),
176 )),
177 }
178}
179
180fn transform_object_list(
181 list: dsl_hir::ObjectList,
182 global_config: &mir::GlobalConfig,
183) -> Result<Vec<mir::Object>, syn::Error> {
184 let mut objects = Vec::new();
185
186 for object in list.objects.into_iter() {
187 let object = match object {
188 dsl_hir::Object::Block(block) => {
189 mir::Object::Block(transform_block(block, global_config)?)
190 }
191 dsl_hir::Object::Register(register) => {
192 mir::Object::Register(transform_register(register, global_config)?)
193 }
194 dsl_hir::Object::Command(command) => {
195 mir::Object::Command(transform_command(command, global_config)?)
196 }
197 dsl_hir::Object::Buffer(buffer) => {
198 mir::Object::Buffer(transform_buffer(buffer, global_config)?)
199 }
200 dsl_hir::Object::Ref(ref_object) => mir::Object::Ref(transform_ref(ref_object)?),
201 };
202
203 objects.push(object);
204 }
205
206 Ok(objects)
207}
208
209fn transform_block(
210 block: dsl_hir::Block,
211 global_config: &mir::GlobalConfig,
212) -> Result<mir::Block, syn::Error> {
213 Ok(mir::Block {
214 cfg_attr: get_cfg_attr(&block.attribute_list)?,
215 description: get_description(&block.attribute_list).unwrap_or_default(),
216 name: block.identifier.to_string(),
217 address_offset: block
218 .block_item_list
219 .block_items
220 .iter()
221 .find_map(|item| match item {
222 dsl_hir::BlockItem::AddressOffset(address_offset) => {
223 Some(address_offset.base10_parse())
224 }
225 _ => None,
226 })
227 .transpose()?
228 .unwrap_or(0),
229 repeat: block
230 .block_item_list
231 .block_items
232 .iter()
233 .find_map(|item| match item {
234 dsl_hir::BlockItem::Repeat(repeat) => Some(repeat.clone().try_into()),
235 _ => None,
236 })
237 .transpose()?,
238 objects: transform_object_list(block.object_list, global_config)?,
239 })
240}
241
242fn transform_register(
243 register: dsl_hir::Register,
244 global_config: &mir::GlobalConfig,
245) -> Result<mir::Register, syn::Error> {
246 Ok(mir::Register {
247 cfg_attr: get_cfg_attr(®ister.attribute_list)?,
248 description: get_description(®ister.attribute_list).unwrap_or_default(),
249 name: register.identifier.to_string(),
250 access: register
251 .register_item_list
252 .register_items
253 .iter()
254 .find_map(|i| match i {
255 dsl_hir::RegisterItem::Access(access) => Some((*access).into()),
256 _ => None,
257 })
258 .unwrap_or(global_config.default_register_access),
259 byte_order: register
260 .register_item_list
261 .register_items
262 .iter()
263 .find_map(|i| match i {
264 dsl_hir::RegisterItem::ByteOrder(bo) => Some((*bo).into()),
265 _ => None,
266 }),
267 bit_order: register
268 .register_item_list
269 .register_items
270 .iter()
271 .find_map(|i| match i {
272 dsl_hir::RegisterItem::BitOrder(bi) => Some((*bi).into()),
273 _ => None,
274 })
275 .unwrap_or(global_config.default_bit_order),
276 allow_bit_overlap: register
277 .register_item_list
278 .register_items
279 .iter()
280 .find_map(|i| match i {
281 dsl_hir::RegisterItem::AllowBitOverlap(b) => Some(b.value),
282 _ => None,
283 })
284 .unwrap_or_default(),
285 allow_address_overlap: register
286 .register_item_list
287 .register_items
288 .iter()
289 .find_map(|i| match i {
290 dsl_hir::RegisterItem::AllowAddressOverlap(b) => Some(b.value),
291 _ => None,
292 })
293 .unwrap_or_default(),
294 address: register
295 .register_item_list
296 .register_items
297 .iter()
298 .find_map(|i| match i {
299 dsl_hir::RegisterItem::Address(addr) => Some(addr.base10_parse()),
300 _ => None,
301 })
302 .transpose()?
303 .ok_or_else(|| {
304 syn::Error::new(
305 register.identifier.span(),
306 format!("Register `{}` must have an address", register.identifier),
307 )
308 })?,
309 size_bits: register
310 .register_item_list
311 .register_items
312 .iter()
313 .find_map(|i| match i {
314 dsl_hir::RegisterItem::SizeBits(sb) => Some(sb.base10_parse()),
315 _ => None,
316 })
317 .transpose()?
318 .ok_or_else(|| {
319 syn::Error::new(
320 register.identifier.span(),
321 format!(
322 "Register `{}` must have size bits specified",
323 register.identifier
324 ),
325 )
326 })?,
327 reset_value: register
328 .register_item_list
329 .register_items
330 .iter()
331 .find_map(|i| match i {
332 dsl_hir::RegisterItem::ResetValueArray(arr) => {
333 Some(Ok(mir::ResetValue::Array(arr.clone())))
334 }
335 dsl_hir::RegisterItem::ResetValueInt(int) => Some(
336 int.base10_parse::<i128>()
337 .map(|v| v as u128)
338 .or_else(|_| int.base10_parse::<u128>())
339 .map_err(|e| {
340 syn::Error::new(
341 int.span(),
342 format!("{e}: number is parsed as an i128 or u128"),
343 )
344 })
345 .map(mir::ResetValue::Integer),
346 ),
347 _ => None,
348 })
349 .transpose()?,
350 repeat: register
351 .register_item_list
352 .register_items
353 .iter()
354 .find_map(|i| match i {
355 dsl_hir::RegisterItem::Repeat(repeat) => Some(repeat.clone().try_into()),
356 _ => None,
357 })
358 .transpose()?,
359 fields: register
360 .field_list
361 .fields
362 .iter()
363 .map(|field| transform_field(field, global_config))
364 .collect::<Result<_, _>>()?,
365 })
366}
367
368fn transform_command(
369 command: dsl_hir::Command,
370 global_config: &mir::GlobalConfig,
371) -> Result<mir::Command, syn::Error> {
372 let command_value = command.value.ok_or_else(|| {
373 syn::Error::new(
374 command.identifier.span(),
375 format!("Command `{}` must have a value", command.identifier),
376 )
377 })?;
378 Ok(mir::Command {
379 cfg_attr: get_cfg_attr(&command.attribute_list)?,
380 description: get_description(&command.attribute_list).unwrap_or_default(),
381 name: command.identifier.to_string(),
382 address: match &command_value {
383 dsl_hir::CommandValue::Basic(lit) => lit,
384 dsl_hir::CommandValue::Extended {
385 command_item_list, ..
386 } => command_item_list
387 .items
388 .iter()
389 .find_map(|item| match item {
390 dsl_hir::CommandItem::Address(lit) => Some(lit),
391 _ => None,
392 })
393 .ok_or_else(|| {
394 syn::Error::new(
395 command.identifier.span(),
396 format!("Command `{}` must have an address", command.identifier),
397 )
398 })?,
399 }
400 .base10_parse()?,
401 byte_order: match &command_value {
402 dsl_hir::CommandValue::Basic(_) => None,
403 dsl_hir::CommandValue::Extended {
404 command_item_list, ..
405 } => command_item_list.items.iter().find_map(|item| match item {
406 dsl_hir::CommandItem::ByteOrder(order) => Some((*order).into()),
407 _ => None,
408 }),
409 },
410 bit_order: match &command_value {
411 dsl_hir::CommandValue::Basic(_) => None,
412 dsl_hir::CommandValue::Extended {
413 command_item_list, ..
414 } => command_item_list.items.iter().find_map(|item| match item {
415 dsl_hir::CommandItem::BitOrder(order) => Some((*order).into()),
416 _ => None,
417 }),
418 }
419 .unwrap_or(global_config.default_bit_order),
420 allow_bit_overlap: match &command_value {
421 dsl_hir::CommandValue::Basic(_) => None,
422 dsl_hir::CommandValue::Extended {
423 command_item_list, ..
424 } => command_item_list.items.iter().find_map(|item| match item {
425 dsl_hir::CommandItem::AllowBitOverlap(b) => Some(b.value),
426 _ => None,
427 }),
428 }
429 .unwrap_or_default(),
430 allow_address_overlap: match &command_value {
431 dsl_hir::CommandValue::Basic(_) => None,
432 dsl_hir::CommandValue::Extended {
433 command_item_list, ..
434 } => command_item_list.items.iter().find_map(|item| match item {
435 dsl_hir::CommandItem::AllowAddressOverlap(b) => Some(b.value),
436 _ => None,
437 }),
438 }
439 .unwrap_or_default(),
440 size_bits_in: match &command_value {
441 dsl_hir::CommandValue::Basic(_) => None,
442 dsl_hir::CommandValue::Extended {
443 command_item_list, ..
444 } => command_item_list.items.iter().find_map(|item| match item {
445 dsl_hir::CommandItem::SizeBitsIn(size) => Some(size.base10_parse()),
446 _ => None,
447 }),
448 }
449 .unwrap_or(Ok(0))?,
450 size_bits_out: match &command_value {
451 dsl_hir::CommandValue::Basic(_) => None,
452 dsl_hir::CommandValue::Extended {
453 command_item_list, ..
454 } => command_item_list.items.iter().find_map(|item| match item {
455 dsl_hir::CommandItem::SizeBitsOut(size) => Some(size.base10_parse()),
456 _ => None,
457 }),
458 }
459 .unwrap_or(Ok(0))?,
460 repeat: match &command_value {
461 dsl_hir::CommandValue::Basic(_) => None,
462 dsl_hir::CommandValue::Extended {
463 command_item_list, ..
464 } => command_item_list.items.iter().find_map(|item| match item {
465 dsl_hir::CommandItem::Repeat(repeat) => Some(repeat.clone().try_into()),
466 _ => None,
467 }),
468 }
469 .transpose()?,
470 in_fields: match &command_value {
471 dsl_hir::CommandValue::Basic(_)
472 | dsl_hir::CommandValue::Extended {
473 in_field_list: None,
474 ..
475 } => Vec::new(),
476 dsl_hir::CommandValue::Extended {
477 in_field_list: Some(in_field_list),
478 ..
479 } => in_field_list
480 .fields
481 .iter()
482 .map(|field| transform_field(field, global_config))
483 .collect::<Result<_, _>>()?,
484 },
485 out_fields: match &command_value {
486 dsl_hir::CommandValue::Basic(_)
487 | dsl_hir::CommandValue::Extended {
488 out_field_list: None,
489 ..
490 } => Vec::new(),
491 dsl_hir::CommandValue::Extended {
492 out_field_list: Some(out_field_list),
493 ..
494 } => out_field_list
495 .fields
496 .iter()
497 .map(|field| transform_field(field, global_config))
498 .collect::<Result<_, _>>()?,
499 },
500 })
501}
502
503fn transform_field(
504 field: &dsl_hir::Field,
505 global_config: &mir::GlobalConfig,
506) -> Result<mir::Field, syn::Error> {
507 let field_cfg_attr = get_cfg_attr(&field.attribute_list)?;
508 let field_description = get_description(&field.attribute_list).unwrap_or_default();
509
510 Ok(mir::Field {
511 cfg_attr: field_cfg_attr.clone(),
512 description: field_description.clone(),
513 name: field.identifier.to_string(),
514 access: field
515 .access
516 .map(Into::into)
517 .unwrap_or(global_config.default_field_access),
518 base_type: field.base_type.into(),
519 field_conversion: field
520 .field_conversion
521 .as_ref()
522 .map(|fc| transform_field_conversion(field_description, fc))
523 .transpose()?,
524 field_address: match &field.field_address {
525 dsl_hir::FieldAddress::Integer(start) if field.base_type.is_bool() => {
526 start.base10_parse()?..start.base10_parse()?
527 }
528 dsl_hir::FieldAddress::Integer(_) => {
529 return Err(syn::Error::new(
530 field.identifier.span(),
531 format!(
532 "Field `{}` has a non-bool base type and must specify the start and the end address",
533 field.identifier
534 ),
535 ));
536 }
537 dsl_hir::FieldAddress::Range { start, end } => {
538 start.base10_parse()?..end.base10_parse()?
539 }
540 dsl_hir::FieldAddress::RangeInclusive { start, end } => {
541 start.base10_parse()?..(end.base10_parse::<u32>()? + 1)
542 }
543 },
544 })
545}
546
547fn transform_field_conversion(
548 field_description: String,
549 field_conversion: &dsl_hir::FieldConversion,
550) -> Result<mir::FieldConversion, syn::Error> {
551 match field_conversion {
552 dsl_hir::FieldConversion::Direct { path, use_try } => Ok(mir::FieldConversion::Direct {
553 type_name: path
554 .to_token_stream()
555 .to_string()
556 .replace(char::is_whitespace, ""),
557 use_try: *use_try,
558 }),
559 dsl_hir::FieldConversion::Enum {
560 identifier,
561 enum_variant_list,
562 use_try,
563 } => Ok(mir::FieldConversion::Enum {
564 enum_value: mir::Enum::new(
565 field_description,
566 identifier.to_string(),
567 enum_variant_list
568 .variants
569 .iter()
570 .map(|v| {
571 Ok(mir::EnumVariant {
572 cfg_attr: get_cfg_attr(&v.attribute_list)?,
573 description: get_description(&v.attribute_list).unwrap_or_default(),
574 name: v.identifier.to_string(),
575 value: match &v.enum_value {
576 None => mir::EnumValue::Unspecified,
577 Some(dsl_hir::EnumValue::Specified(val)) => {
578 mir::EnumValue::Specified(val.base10_parse()?)
579 }
580 Some(dsl_hir::EnumValue::Default) => mir::EnumValue::Default,
581 Some(dsl_hir::EnumValue::CatchAll) => mir::EnumValue::CatchAll,
582 },
583 })
584 })
585 .collect::<Result<_, syn::Error>>()?,
586 ),
587 use_try: *use_try,
588 }),
589 }
590}
591
592fn transform_buffer(
593 buffer: dsl_hir::Buffer,
594 global_config: &mir::GlobalConfig,
595) -> Result<mir::Buffer, syn::Error> {
596 Ok(mir::Buffer {
597 cfg_attr: get_cfg_attr(&buffer.attribute_list)?,
598 description: get_description(&buffer.attribute_list).unwrap_or_default(),
599 name: buffer.identifier.to_string(),
600 access: buffer
601 .access
602 .map(Into::into)
603 .unwrap_or(global_config.default_buffer_access),
604 address: buffer
605 .address
606 .ok_or_else(|| {
607 syn::Error::new(
608 buffer.identifier.span(),
609 format!("Buffer `{}` must have an address", buffer.identifier),
610 )
611 })?
612 .base10_parse()?,
613 })
614}
615
616fn transform_ref(ref_object: dsl_hir::RefObject) -> Result<mir::RefObject, syn::Error> {
617 Ok(mir::RefObject {
618 cfg_attr: get_cfg_attr(&ref_object.attribute_list)?,
619 description: get_description(&ref_object.attribute_list).unwrap_or_default(),
620 name: ref_object.identifier.to_string(),
621 object_override: match *ref_object.object {
622 dsl_hir::Object::Block(block_override) => {
623 mir::ObjectOverride::Block(transform_block_override(block_override)?)
624 }
625 dsl_hir::Object::Register(register_override) => {
626 mir::ObjectOverride::Register(transform_register_override(register_override)?)
627 }
628 dsl_hir::Object::Command(command_override) => {
629 mir::ObjectOverride::Command(transform_command_override(command_override)?)
630 }
631 dsl_hir::Object::Buffer(_) => {
632 return Err(syn::Error::new(
633 ref_object.identifier.span(),
634 format!("Ref `{}` cannot ref a buffer", ref_object.identifier),
635 ));
636 }
637 dsl_hir::Object::Ref(_) => {
638 return Err(syn::Error::new(
639 ref_object.identifier.span(),
640 format!(
641 "Ref `{}` cannot ref another ref object",
642 ref_object.identifier
643 ),
644 ));
645 }
646 },
647 })
648}
649
650fn transform_block_override(
651 block_override: dsl_hir::Block,
652) -> Result<mir::BlockOverride, syn::Error> {
653 if !block_override.attribute_list.attributes.is_empty() {
654 return Err(syn::Error::new(
655 block_override.identifier.span(),
656 "No attributes (cfg or doc) are allowed on block overrides",
657 ));
658 }
659
660 if !block_override.object_list.objects.is_empty() {
661 return Err(syn::Error::new(
662 block_override.identifier.span(),
663 "No objects may be defined on block overrides",
664 ));
665 }
666
667 Ok(mir::BlockOverride {
668 name: block_override.identifier.to_string(),
669 address_offset: block_override
670 .block_item_list
671 .block_items
672 .iter()
673 .find_map(|item| match item {
674 dsl_hir::BlockItem::AddressOffset(address_offset) => {
675 Some(address_offset.base10_parse())
676 }
677 _ => None,
678 })
679 .transpose()?,
680 repeat: block_override
681 .block_item_list
682 .block_items
683 .iter()
684 .find_map(|item| match item {
685 dsl_hir::BlockItem::Repeat(repeat) => Some(repeat.clone().try_into()),
686 _ => None,
687 })
688 .transpose()?,
689 })
690}
691
692fn transform_register_override(
693 register_override: dsl_hir::Register,
694) -> Result<mir::RegisterOverride, syn::Error> {
695 if !register_override.attribute_list.attributes.is_empty() {
696 return Err(syn::Error::new(
697 register_override.identifier.span(),
698 "No attributes (cfg or doc) are allowed on register overrides",
699 ));
700 }
701
702 if !register_override.field_list.fields.is_empty() {
703 return Err(syn::Error::new(
704 register_override.identifier.span(),
705 "No fields are allowed on register overrides",
706 ));
707 }
708
709 for item in register_override.register_item_list.register_items.iter() {
710 match item {
711 dsl_hir::RegisterItem::ByteOrder(_) => {
712 return Err(syn::Error::new(
713 register_override.identifier.span(),
714 "No `ByteOrder` is allowed on register overrides",
715 ));
716 }
717 dsl_hir::RegisterItem::BitOrder(_) => {
718 return Err(syn::Error::new(
719 register_override.identifier.span(),
720 "No `BitOrder` is allowed on register overrides",
721 ));
722 }
723 dsl_hir::RegisterItem::SizeBits(_) => {
724 return Err(syn::Error::new(
725 register_override.identifier.span(),
726 "No `SizeBits` is allowed on register overrides",
727 ));
728 }
729 dsl_hir::RegisterItem::AllowBitOverlap(_) => {
730 return Err(syn::Error::new(
731 register_override.identifier.span(),
732 "No `AllowBitOverlap` is allowed on register overrides",
733 ));
734 }
735 dsl_hir::RegisterItem::Access(_) => {}
736 dsl_hir::RegisterItem::Address(_) => {}
737 dsl_hir::RegisterItem::ResetValueInt(_) => {}
738 dsl_hir::RegisterItem::ResetValueArray(_) => {}
739 dsl_hir::RegisterItem::Repeat(_) => {}
740 dsl_hir::RegisterItem::AllowAddressOverlap(_) => {}
741 }
742 }
743
744 Ok(mir::RegisterOverride {
745 name: register_override.identifier.to_string(),
746 access: register_override
747 .register_item_list
748 .register_items
749 .iter()
750 .find_map(|i| match i {
751 dsl_hir::RegisterItem::Access(access) => Some((*access).into()),
752 _ => None,
753 }),
754 address: register_override
755 .register_item_list
756 .register_items
757 .iter()
758 .find_map(|i| match i {
759 dsl_hir::RegisterItem::Address(addr) => Some(addr.base10_parse()),
760 _ => None,
761 })
762 .transpose()?,
763 allow_address_overlap: register_override
764 .register_item_list
765 .register_items
766 .iter()
767 .find_map(|i| match i {
768 dsl_hir::RegisterItem::AllowAddressOverlap(b) => Some(b.value),
769 _ => None,
770 })
771 .unwrap_or_default(),
772 reset_value: register_override
773 .register_item_list
774 .register_items
775 .iter()
776 .find_map(|i| match i {
777 dsl_hir::RegisterItem::ResetValueArray(arr) => {
778 Some(Ok(mir::ResetValue::Array(arr.clone())))
779 }
780 dsl_hir::RegisterItem::ResetValueInt(int) => Some(
781 int.base10_parse::<i128>()
782 .map(|v| v as u128)
783 .or_else(|_| int.base10_parse::<u128>())
784 .map_err(|e| {
785 syn::Error::new(
786 int.span(),
787 format!("{e}: number is parsed as an i128 or u128"),
788 )
789 })
790 .map(mir::ResetValue::Integer),
791 ),
792 _ => None,
793 })
794 .transpose()?,
795 repeat: register_override
796 .register_item_list
797 .register_items
798 .iter()
799 .find_map(|i| match i {
800 dsl_hir::RegisterItem::Repeat(repeat) => Some(repeat.clone().try_into()),
801 _ => None,
802 })
803 .transpose()?,
804 })
805}
806
807fn transform_command_override(
808 command_override: dsl_hir::Command,
809) -> Result<mir::CommandOverride, syn::Error> {
810 if !command_override.attribute_list.attributes.is_empty() {
811 return Err(syn::Error::new(
812 command_override.identifier.span(),
813 "No attributes (cfg or doc) are allowed on command overrides",
814 ));
815 }
816
817 let command_item_list = match &command_override.value {
818 Some(dsl_hir::CommandValue::Extended {
819 in_field_list: Some(_),
820 ..
821 }) => {
822 return Err(syn::Error::new(
823 command_override.identifier.span(),
824 "No `in` field list is allowed on command overrides",
825 ));
826 }
827 Some(dsl_hir::CommandValue::Extended {
828 out_field_list: Some(_),
829 ..
830 }) => {
831 return Err(syn::Error::new(
832 command_override.identifier.span(),
833 "No `out` field list is allowed on command overrides",
834 ));
835 }
836 Some(dsl_hir::CommandValue::Extended {
837 command_item_list,
838 in_field_list: None,
839 out_field_list: None,
840 }) => {
841 for ci in command_item_list.items.iter() {
842 match ci {
843 dsl_hir::CommandItem::ByteOrder(_) => {
844 return Err(syn::Error::new(
845 command_override.identifier.span(),
846 "No `ByteOrder` is allowed on command overrides",
847 ));
848 }
849 dsl_hir::CommandItem::BitOrder(_) => {
850 return Err(syn::Error::new(
851 command_override.identifier.span(),
852 "No `BitOrder` is allowed on command overrides",
853 ));
854 }
855 dsl_hir::CommandItem::SizeBitsIn(_) => {
856 return Err(syn::Error::new(
857 command_override.identifier.span(),
858 "No `SizeBitsIn` is allowed on command overrides",
859 ));
860 }
861 dsl_hir::CommandItem::SizeBitsOut(_) => {
862 return Err(syn::Error::new(
863 command_override.identifier.span(),
864 "No `SizeBitsOut` is allowed on command overrides",
865 ));
866 }
867 dsl_hir::CommandItem::AllowBitOverlap(_) => {
868 return Err(syn::Error::new(
869 command_override.identifier.span(),
870 "No `AllowBitOverlap` is allowed on command overrides",
871 ));
872 }
873 dsl_hir::CommandItem::AllowAddressOverlap(_) => {}
874 dsl_hir::CommandItem::Repeat(_) => {}
875 dsl_hir::CommandItem::Address(_) => {}
876 }
877 }
878
879 command_item_list
880 }
881 Some(dsl_hir::CommandValue::Basic(_)) => {
882 return Err(syn::Error::new(
883 command_override.identifier.span(),
884 "No basic address specifier is allowed on command overrides. Use the extended syntax with `{ }` instead",
885 ));
886 }
887 None => {
888 return Err(syn::Error::new(
889 command_override.identifier.span(),
890 "A value is required on command overrides",
891 ));
892 }
893 };
894
895 Ok(mir::CommandOverride {
896 name: command_override.identifier.to_string(),
897 address: command_item_list
898 .items
899 .iter()
900 .find_map(|item| match item {
901 dsl_hir::CommandItem::Address(lit) => Some(lit),
902 _ => None,
903 })
904 .map(|lit| lit.base10_parse())
905 .transpose()?,
906 allow_address_overlap: command_item_list
907 .items
908 .iter()
909 .find_map(|item| match item {
910 dsl_hir::CommandItem::AllowAddressOverlap(lit) => Some(lit.value),
911 _ => None,
912 })
913 .unwrap_or_default(),
914 repeat: command_item_list
915 .items
916 .iter()
917 .find_map(|item| match item {
918 dsl_hir::CommandItem::Repeat(repeat) => Some(mir::Repeat::try_from(repeat.clone())),
919 _ => None,
920 })
921 .transpose()?,
922 })
923}
924
925#[cfg(test)]
926mod tests {
927 use convert_case::Boundary;
928
929 use super::*;
930
931 #[test]
932 fn no_double_global_settings() {
933 let device = syn::parse_str::<dsl_hir::Device>(
934 "config { type DefaultRegisterAccess = RW; type DefaultRegisterAccess = RW; }",
935 )
936 .unwrap();
937
938 assert_eq!(
939 transform(device).unwrap_err().to_string(),
940 "Duplicate global config found: `DefaultRegisterAccess(RW)`"
941 );
942 }
943
944 #[test]
945 fn global_settings_correct() {
946 let device = syn::parse_str::<dsl_hir::Device>(
947 "config {
948 type DefaultRegisterAccess = RO;
949 type DefaultFieldAccess = RW;
950 type DefaultBufferAccess = WO;
951 type DefaultByteOrder = LE;
952 type DefaultBitOrder = MSB0;
953 type RegisterAddressType = i8;
954 type CommandAddressType = i64;
955 type BufferAddressType = u32;
956 type NameWordBoundaries = \"-\";
957 type DefmtFeature = \"defmt-03\";
958 }",
959 )
960 .unwrap();
961
962 let device = transform(device).unwrap();
963
964 assert_eq!(
965 device.global_config,
966 mir::GlobalConfig {
967 default_register_access: mir::Access::RO,
968 default_field_access: mir::Access::RW,
969 default_buffer_access: mir::Access::WO,
970 default_byte_order: Some(mir::ByteOrder::LE),
971 default_bit_order: mir::BitOrder::MSB0,
972 register_address_type: Some(mir::Integer::I8),
973 command_address_type: Some(mir::Integer::I64),
974 buffer_address_type: Some(mir::Integer::U32),
975 name_word_boundaries: vec![Boundary::Hyphen],
976 defmt_feature: Some("defmt-03".into()),
977 }
978 );
979 }
980
981 #[test]
982 fn buffer() {
983 assert_eq!(
984 transform(
985 syn::parse_str::<dsl_hir::Device>(
986 "
987 /// Hello world!
988 #[cfg(feature = \"foo\")]
989 /// This should be in order!
990 buffer Foo: RW = 5
991 ",
992 )
993 .unwrap()
994 )
995 .unwrap()
996 .objects,
997 &[mir::Object::Buffer(mir::Buffer {
998 cfg_attr: mir::Cfg::new(Some("feature = \"foo\"")),
999 description: " Hello world!\n This should be in order!".into(),
1000 name: "Foo".into(),
1001 access: mir::Access::RW,
1002 address: 5,
1003 })]
1004 );
1005
1006 assert_eq!(
1007 transform(
1008 syn::parse_str::<dsl_hir::Device>(
1009 "
1010 buffer Foo
1011 ",
1012 )
1013 .unwrap()
1014 )
1015 .unwrap_err()
1016 .to_string(),
1017 "Buffer `Foo` must have an address"
1018 );
1019 }
1020
1021 #[test]
1022 fn command() {
1023 assert_eq!(
1024 transform(
1025 syn::parse_str::<dsl_hir::Device>(
1026 "
1027 command Foo
1028 ",
1029 )
1030 .unwrap()
1031 )
1032 .unwrap_err()
1033 .to_string(),
1034 "Command `Foo` must have a value"
1035 );
1036
1037 assert_eq!(
1038 transform(
1039 syn::parse_str::<dsl_hir::Device>(
1040 "
1041 command Foo {}
1042 ",
1043 )
1044 .unwrap()
1045 )
1046 .unwrap_err()
1047 .to_string(),
1048 "Command `Foo` must have an address"
1049 );
1050
1051 assert_eq!(
1052 transform(
1053 syn::parse_str::<dsl_hir::Device>(
1054 "
1055 /// Hello world!
1056 #[cfg(feature = \"foo\")]
1057 /// This should be in order!
1058 command Foo = 5
1059 ",
1060 )
1061 .unwrap()
1062 )
1063 .unwrap()
1064 .objects,
1065 &[mir::Object::Command(mir::Command {
1066 cfg_attr: mir::Cfg::new(Some("feature = \"foo\"")),
1067 description: " Hello world!\n This should be in order!".into(),
1068 name: "Foo".into(),
1069 address: 5,
1070 ..Default::default()
1071 })]
1072 );
1073
1074 assert_eq!(
1075 transform(
1076 syn::parse_str::<dsl_hir::Device>(
1077 "
1078 config {
1079 type DefaultByteOrder = LE;
1080 type DefaultFieldAccess = RO;
1081 }
1082 command Bar {
1083 const SIZE_BITS_IN = 32;
1084 const SIZE_BITS_OUT = 16;
1085 const REPEAT = {
1086 count: 4,
1087 stride: 0x10,
1088 };
1089 const ADDRESS = 10;
1090
1091 in {
1092 /// Hello!
1093 #[cfg(bla)]
1094 val: WO bool = 0,
1095 foo: uint as crate::my_mod::MyStruct = 1..=5,
1096 }
1097 out {
1098 val: int as enum Val {
1099 One,
1100 /// Two!
1101 Two = 2,
1102 Three = default,
1103 #[cfg(yes)]
1104 Four = catch_all,
1105 } = 0..16,
1106 }
1107 }
1108 ",
1109 )
1110 .unwrap()
1111 )
1112 .unwrap()
1113 .objects,
1114 &[mir::Object::Command(mir::Command {
1115 name: "Bar".into(),
1116 address: 10,
1117 size_bits_in: 32,
1118 size_bits_out: 16,
1119 repeat: Some(mir::Repeat {
1120 count: 4,
1121 stride: 16
1122 }),
1123 in_fields: vec![
1124 mir::Field {
1125 cfg_attr: mir::Cfg::new(Some("bla")),
1126 description: " Hello!".into(),
1127 name: "val".into(),
1128 access: mir::Access::WO,
1129 base_type: mir::BaseType::Bool,
1130 field_conversion: None,
1131 field_address: 0..0,
1132 },
1133 mir::Field {
1134 cfg_attr: mir::Cfg::new(None),
1135 description: Default::default(),
1136 name: "foo".into(),
1137 access: mir::Access::RO,
1138 base_type: mir::BaseType::Uint,
1139 field_conversion: Some(mir::FieldConversion::Direct {
1140 type_name: "crate::my_mod::MyStruct".into(),
1141 use_try: false,
1142 }),
1143 field_address: 1..6,
1144 }
1145 ],
1146 out_fields: vec![mir::Field {
1147 cfg_attr: mir::Cfg::new(None),
1148 description: Default::default(),
1149 name: "val".into(),
1150 access: mir::Access::RO,
1151 base_type: mir::BaseType::Int,
1152 field_conversion: Some(mir::FieldConversion::Enum {
1153 enum_value: mir::Enum::new(
1154 Default::default(),
1155 "Val".into(),
1156 vec![
1157 mir::EnumVariant {
1158 cfg_attr: mir::Cfg::new(None),
1159 description: Default::default(),
1160 name: "One".into(),
1161 value: mir::EnumValue::Unspecified,
1162 },
1163 mir::EnumVariant {
1164 cfg_attr: mir::Cfg::new(None),
1165 description: " Two!".into(),
1166 name: "Two".into(),
1167 value: mir::EnumValue::Specified(2),
1168 },
1169 mir::EnumVariant {
1170 cfg_attr: mir::Cfg::new(None),
1171 description: Default::default(),
1172 name: "Three".into(),
1173 value: mir::EnumValue::Default,
1174 },
1175 mir::EnumVariant {
1176 cfg_attr: mir::Cfg::new(Some("yes")),
1177 description: Default::default(),
1178 name: "Four".into(),
1179 value: mir::EnumValue::CatchAll,
1180 }
1181 ],
1182 ),
1183 use_try: false
1184 }),
1185 field_address: 0..16,
1186 }],
1187 ..Default::default()
1188 })]
1189 );
1190
1191 assert_eq!(
1192 transform(
1193 syn::parse_str::<dsl_hir::Device>(
1194 "
1195 command Foo {
1196 const ADDRESS = 0;
1197
1198 in {
1199 val: int = 0,
1200 }
1201 }
1202 ",
1203 )
1204 .unwrap()
1205 )
1206 .unwrap_err()
1207 .to_string(),
1208 "Field `val` has a non-bool base type and must specify the start and the end address"
1209 );
1210
1211 assert_eq!(
1212 transform(
1213 syn::parse_str::<dsl_hir::Device>(
1214 "
1215 config {
1216 type DefaultByteOrder = LE;
1217 type DefaultBitOrder = MSB0;
1218 }
1219 command Bar {
1220 type ByteOrder = BE;
1221 type BitOrder = LSB0;
1222 const ADDRESS = 10;
1223
1224 in {
1225 val: bool = 0,
1226 }
1227 }
1228 ",
1229 )
1230 .unwrap()
1231 )
1232 .unwrap()
1233 .objects,
1234 &[mir::Object::Command(mir::Command {
1235 name: "Bar".into(),
1236 address: 10,
1237 byte_order: Some(mir::ByteOrder::BE),
1238 bit_order: mir::BitOrder::LSB0,
1239 in_fields: vec![mir::Field {
1240 cfg_attr: mir::Cfg::new(None),
1241 description: Default::default(),
1242 name: "val".into(),
1243 access: mir::Access::default(),
1244 base_type: mir::BaseType::Bool,
1245 field_conversion: None,
1246 field_address: 0..0,
1247 },],
1248 ..Default::default()
1249 })]
1250 );
1251
1252 assert_eq!(
1253 transform(
1254 syn::parse_str::<dsl_hir::Device>(
1255 "
1256 command Foo {
1257 const ADDRESS = 5;
1258 const ALLOW_BIT_OVERLAP = true;
1259 const ALLOW_ADDRESS_OVERLAP = true;
1260 }
1261 ",
1262 )
1263 .unwrap()
1264 )
1265 .unwrap()
1266 .objects,
1267 &[mir::Object::Command(mir::Command {
1268 name: "Foo".into(),
1269 address: 5,
1270 allow_bit_overlap: true,
1271 allow_address_overlap: true,
1272 ..Default::default()
1273 })]
1274 );
1275 }
1276
1277 #[test]
1278 fn max_one_cfg_attr() {
1279 assert_eq!(
1280 transform(
1281 syn::parse_str::<dsl_hir::Device>(
1282 "
1283 buffer Foo = 5
1284 "
1285 )
1286 .unwrap()
1287 )
1288 .unwrap()
1289 .objects,
1290 &[mir::Object::Buffer(mir::Buffer {
1291 cfg_attr: mir::Cfg::new(None),
1292 description: "".into(),
1293 name: "Foo".into(),
1294 access: mir::Access::default(),
1295 address: 5,
1296 })]
1297 );
1298 assert_eq!(
1299 transform(
1300 syn::parse_str::<dsl_hir::Device>(
1301 "
1302 #[cfg(foo)]
1303 buffer Foo = 5
1304 "
1305 )
1306 .unwrap()
1307 )
1308 .unwrap()
1309 .objects,
1310 &[mir::Object::Buffer(mir::Buffer {
1311 cfg_attr: mir::Cfg::new(Some("foo")),
1312 description: "".into(),
1313 name: "Foo".into(),
1314 access: mir::Access::default(),
1315 address: 5,
1316 })]
1317 );
1318 assert_eq!(
1319 transform(
1320 syn::parse_str::<dsl_hir::Device>(
1321 "
1322 #[cfg(foo)]
1323 #[cfg(too_many)]
1324 buffer Foo = 5
1325 "
1326 )
1327 .unwrap()
1328 )
1329 .unwrap_err()
1330 .to_string(),
1331 "Only one cfg attribute is allowed, but 2 are found"
1332 );
1333 }
1334
1335 #[test]
1336 fn ref_no_buffer_or_ref() {
1337 assert_eq!(
1338 transform(
1339 syn::parse_str::<dsl_hir::Device>(
1340 "
1341 ref Foo = buffer Bar
1342 "
1343 )
1344 .unwrap()
1345 )
1346 .unwrap_err()
1347 .to_string(),
1348 "Ref `Foo` cannot ref a buffer"
1349 );
1350
1351 assert_eq!(
1352 transform(
1353 syn::parse_str::<dsl_hir::Device>(
1354 "
1355 ref Foo = ref Bar = buffer X
1356 "
1357 )
1358 .unwrap()
1359 )
1360 .unwrap_err()
1361 .to_string(),
1362 "Ref `Foo` cannot ref another ref object"
1363 );
1364 }
1365
1366 #[test]
1367 fn ref_register() {
1368 assert_eq!(
1369 transform(
1370 syn::parse_str::<dsl_hir::Device>(
1371 "
1372 ref Foo = register Bar {}
1373 "
1374 )
1375 .unwrap()
1376 )
1377 .unwrap()
1378 .objects,
1379 &[mir::Object::Ref(mir::RefObject {
1380 cfg_attr: mir::Cfg::new(None),
1381 description: "".into(),
1382 name: "Foo".into(),
1383 object_override: mir::ObjectOverride::Register(mir::RegisterOverride {
1384 name: "Bar".into(),
1385 ..Default::default()
1386 })
1387 })]
1388 );
1389
1390 assert_eq!(
1391 transform(
1392 syn::parse_str::<dsl_hir::Device>(
1393 "
1394 ref Foo = register Bar {
1395 const ADDRESS = 5;
1396 const REPEAT = {
1397 count: 5,
1398 stride: 1,
1399 };
1400 type Access = WO;
1401 const RESET_VALUE = 123;
1402 const ALLOW_ADDRESS_OVERLAP = false;
1403 }
1404 "
1405 )
1406 .unwrap()
1407 )
1408 .unwrap()
1409 .objects,
1410 &[mir::Object::Ref(mir::RefObject {
1411 cfg_attr: mir::Cfg::new(None),
1412 description: "".into(),
1413 name: "Foo".into(),
1414 object_override: mir::ObjectOverride::Register(mir::RegisterOverride {
1415 name: "Bar".into(),
1416 address: Some(5),
1417 repeat: Some(mir::Repeat {
1418 count: 5,
1419 stride: 1
1420 }),
1421 access: Some(mir::Access::WO),
1422 reset_value: Some(mir::ResetValue::Integer(123)),
1423 ..Default::default()
1424 })
1425 })]
1426 );
1427
1428 assert_eq!(
1429 transform(
1430 syn::parse_str::<dsl_hir::Device>(
1431 "
1432 ref Foo = register Bar {
1433 const RESET_VALUE = [1, 2, 3];
1434 }
1435 "
1436 )
1437 .unwrap()
1438 )
1439 .unwrap()
1440 .objects,
1441 &[mir::Object::Ref(mir::RefObject {
1442 cfg_attr: mir::Cfg::new(None),
1443 description: "".into(),
1444 name: "Foo".into(),
1445 object_override: mir::ObjectOverride::Register(mir::RegisterOverride {
1446 name: "Bar".into(),
1447 reset_value: Some(mir::ResetValue::Array(vec![1, 2, 3])),
1448 ..Default::default()
1449 })
1450 })]
1451 );
1452
1453 assert_eq!(
1454 transform(
1455 syn::parse_str::<dsl_hir::Device>(
1456 "
1457 ref Foo = register Bar {
1458 type ByteOrder = BE;
1459 }
1460 "
1461 )
1462 .unwrap()
1463 )
1464 .unwrap_err()
1465 .to_string(),
1466 "No `ByteOrder` is allowed on register overrides"
1467 );
1468
1469 assert_eq!(
1470 transform(
1471 syn::parse_str::<dsl_hir::Device>(
1472 "
1473 ref Foo = register Bar {
1474 type BitOrder = LSB0;
1475 }
1476 "
1477 )
1478 .unwrap()
1479 )
1480 .unwrap_err()
1481 .to_string(),
1482 "No `BitOrder` is allowed on register overrides"
1483 );
1484
1485 assert_eq!(
1486 transform(
1487 syn::parse_str::<dsl_hir::Device>(
1488 "
1489 ref Foo = register Bar {
1490 const SIZE_BITS = 5;
1491 }
1492 "
1493 )
1494 .unwrap()
1495 )
1496 .unwrap_err()
1497 .to_string(),
1498 "No `SizeBits` is allowed on register overrides"
1499 );
1500
1501 assert_eq!(
1502 transform(
1503 syn::parse_str::<dsl_hir::Device>(
1504 "
1505 ref Foo = register Bar {
1506 const ALLOW_BIT_OVERLAP = false;
1507 }
1508 "
1509 )
1510 .unwrap()
1511 )
1512 .unwrap_err()
1513 .to_string(),
1514 "No `AllowBitOverlap` is allowed on register overrides"
1515 );
1516
1517 assert_eq!(
1518 transform(
1519 syn::parse_str::<dsl_hir::Device>(
1520 "
1521 ref Foo =
1522 /// Hi!
1523 register Bar { }
1524 "
1525 )
1526 .unwrap()
1527 )
1528 .unwrap_err()
1529 .to_string(),
1530 "No attributes (cfg or doc) are allowed on register overrides"
1531 );
1532
1533 assert_eq!(
1534 transform(
1535 syn::parse_str::<dsl_hir::Device>(
1536 "
1537 ref Foo = register Bar {
1538 val: bool = 0,
1539 }
1540 "
1541 )
1542 .unwrap()
1543 )
1544 .unwrap_err()
1545 .to_string(),
1546 "No fields are allowed on register overrides"
1547 );
1548
1549 assert_eq!(
1550 transform(
1551 syn::parse_str::<dsl_hir::Device>(
1552 "
1553 ref Foo = register Bar {
1554 const RESET_VALUE = 0x123456789012345678901234567890123;
1555 }
1556 "
1557 )
1558 .unwrap()
1559 )
1560 .unwrap_err()
1561 .to_string(),
1562 "number too large to fit in target type: number is parsed as an i128 or u128"
1563 );
1564 }
1565
1566 #[test]
1567 fn ref_command() {
1568 assert_eq!(
1569 transform(
1570 syn::parse_str::<dsl_hir::Device>(
1571 "
1572 ref Foo = command Bar {}
1573 "
1574 )
1575 .unwrap()
1576 )
1577 .unwrap()
1578 .objects,
1579 &[mir::Object::Ref(mir::RefObject {
1580 cfg_attr: mir::Cfg::new(None),
1581 description: "".into(),
1582 name: "Foo".into(),
1583 object_override: mir::ObjectOverride::Command(mir::CommandOverride {
1584 name: "Bar".into(),
1585 ..Default::default()
1586 })
1587 })]
1588 );
1589
1590 assert_eq!(
1591 transform(
1592 syn::parse_str::<dsl_hir::Device>(
1593 "
1594 ref Foo = command Bar {
1595 const ADDRESS = 6;
1596 const ALLOW_ADDRESS_OVERLAP = true;
1597 }
1598 "
1599 )
1600 .unwrap()
1601 )
1602 .unwrap()
1603 .objects,
1604 &[mir::Object::Ref(mir::RefObject {
1605 cfg_attr: mir::Cfg::new(None),
1606 description: "".into(),
1607 name: "Foo".into(),
1608 object_override: mir::ObjectOverride::Command(mir::CommandOverride {
1609 name: "Bar".into(),
1610 address: Some(6),
1611 allow_address_overlap: true,
1612 ..Default::default()
1613 })
1614 })]
1615 );
1616
1617 assert_eq!(
1618 transform(
1619 syn::parse_str::<dsl_hir::Device>(
1620 "
1621 ref Foo = command Bar {
1622 const ADDRESS = 7;
1623 const REPEAT = {
1624 count: 4,
1625 stride: 4,
1626 };
1627 }
1628 "
1629 )
1630 .unwrap()
1631 )
1632 .unwrap()
1633 .objects,
1634 &[mir::Object::Ref(mir::RefObject {
1635 cfg_attr: mir::Cfg::new(None),
1636 description: "".into(),
1637 name: "Foo".into(),
1638 object_override: mir::ObjectOverride::Command(mir::CommandOverride {
1639 name: "Bar".into(),
1640 address: Some(7),
1641 repeat: Some(mir::Repeat {
1642 count: 4,
1643 stride: 4
1644 }),
1645 ..Default::default()
1646 })
1647 })]
1648 );
1649
1650 assert_eq!(
1651 transform(
1652 syn::parse_str::<dsl_hir::Device>(
1653 "
1654 ref Foo = command Bar {
1655 const REPEAT = {
1656 count: 4,
1657 stride: 4,
1658 };
1659 }
1660 "
1661 )
1662 .unwrap()
1663 )
1664 .unwrap()
1665 .objects,
1666 &[mir::Object::Ref(mir::RefObject {
1667 cfg_attr: mir::Cfg::new(None),
1668 description: "".into(),
1669 name: "Foo".into(),
1670 object_override: mir::ObjectOverride::Command(mir::CommandOverride {
1671 name: "Bar".into(),
1672 repeat: Some(mir::Repeat {
1673 count: 4,
1674 stride: 4
1675 }),
1676 ..Default::default()
1677 })
1678 })]
1679 );
1680
1681 assert_eq!(
1682 transform(
1683 syn::parse_str::<dsl_hir::Device>(
1684 "
1685 ref Foo = command Bar
1686 "
1687 )
1688 .unwrap()
1689 )
1690 .unwrap_err()
1691 .to_string(),
1692 "A value is required on command overrides"
1693 );
1694
1695 assert_eq!(
1696 transform(
1697 syn::parse_str::<dsl_hir::Device>(
1698 "
1699 ref Foo = command Bar = 6
1700 "
1701 )
1702 .unwrap()
1703 )
1704 .unwrap_err()
1705 .to_string(),
1706 "No basic address specifier is allowed on command overrides. Use the extended syntax with `{ }` instead"
1707 );
1708
1709 assert_eq!(
1710 transform(
1711 syn::parse_str::<dsl_hir::Device>(
1712 "
1713 ref Foo =
1714 /// Illegal attribute!
1715 command Bar {}
1716 "
1717 )
1718 .unwrap()
1719 )
1720 .unwrap_err()
1721 .to_string(),
1722 "No attributes (cfg or doc) are allowed on command overrides"
1723 );
1724
1725 assert_eq!(
1726 transform(
1727 syn::parse_str::<dsl_hir::Device>(
1728 "
1729 ref Foo = command Bar {
1730 in {}
1731 }
1732 "
1733 )
1734 .unwrap()
1735 )
1736 .unwrap_err()
1737 .to_string(),
1738 "No `in` field list is allowed on command overrides"
1739 );
1740
1741 assert_eq!(
1742 transform(
1743 syn::parse_str::<dsl_hir::Device>(
1744 "
1745 ref Foo = command Bar {
1746 out {}
1747 }
1748 "
1749 )
1750 .unwrap()
1751 )
1752 .unwrap_err()
1753 .to_string(),
1754 "No `out` field list is allowed on command overrides"
1755 );
1756
1757 assert_eq!(
1758 transform(
1759 syn::parse_str::<dsl_hir::Device>(
1760 "
1761 ref Foo = command Bar {
1762 type ByteOrder = LE;
1763 }
1764 "
1765 )
1766 .unwrap()
1767 )
1768 .unwrap_err()
1769 .to_string(),
1770 "No `ByteOrder` is allowed on command overrides"
1771 );
1772
1773 assert_eq!(
1774 transform(
1775 syn::parse_str::<dsl_hir::Device>(
1776 "
1777 ref Foo = command Bar {
1778 type BitOrder = LSB0;
1779 }
1780 "
1781 )
1782 .unwrap()
1783 )
1784 .unwrap_err()
1785 .to_string(),
1786 "No `BitOrder` is allowed on command overrides"
1787 );
1788
1789 assert_eq!(
1790 transform(
1791 syn::parse_str::<dsl_hir::Device>(
1792 "
1793 ref Foo = command Bar {
1794 const SIZE_BITS_IN = 0;
1795 }
1796 "
1797 )
1798 .unwrap()
1799 )
1800 .unwrap_err()
1801 .to_string(),
1802 "No `SizeBitsIn` is allowed on command overrides"
1803 );
1804
1805 assert_eq!(
1806 transform(
1807 syn::parse_str::<dsl_hir::Device>(
1808 "
1809 ref Foo = command Bar {
1810 const SIZE_BITS_OUT = 0;
1811 }
1812 "
1813 )
1814 .unwrap()
1815 )
1816 .unwrap_err()
1817 .to_string(),
1818 "No `SizeBitsOut` is allowed on command overrides"
1819 );
1820
1821 assert_eq!(
1822 transform(
1823 syn::parse_str::<dsl_hir::Device>(
1824 "
1825 ref Foo = command Bar {
1826 const ALLOW_BIT_OVERLAP = true;
1827 }
1828 "
1829 )
1830 .unwrap()
1831 )
1832 .unwrap_err()
1833 .to_string(),
1834 "No `AllowBitOverlap` is allowed on command overrides"
1835 );
1836 }
1837
1838 #[test]
1839 fn ref_block() {
1840 assert_eq!(
1841 transform(
1842 syn::parse_str::<dsl_hir::Device>(
1843 "
1844 ref Foo = block Bar {}
1845 "
1846 )
1847 .unwrap()
1848 )
1849 .unwrap()
1850 .objects,
1851 &[mir::Object::Ref(mir::RefObject {
1852 cfg_attr: mir::Cfg::new(None),
1853 description: "".into(),
1854 name: "Foo".into(),
1855 object_override: mir::ObjectOverride::Block(mir::BlockOverride {
1856 name: "Bar".into(),
1857 address_offset: None,
1858 repeat: None
1859 })
1860 })]
1861 );
1862
1863 assert_eq!(
1864 transform(
1865 syn::parse_str::<dsl_hir::Device>(
1866 "
1867 ref Foo =
1868 /// Illegal comment!
1869 block Bar {}
1870 "
1871 )
1872 .unwrap()
1873 )
1874 .unwrap_err()
1875 .to_string(),
1876 "No attributes (cfg or doc) are allowed on block overrides"
1877 );
1878
1879 assert_eq!(
1880 transform(
1881 syn::parse_str::<dsl_hir::Device>(
1882 "
1883 ref Foo = block Bar {
1884 buffer Bla = 0,
1885 }
1886 "
1887 )
1888 .unwrap()
1889 )
1890 .unwrap_err()
1891 .to_string(),
1892 "No objects may be defined on block overrides"
1893 );
1894
1895 assert_eq!(
1896 transform(
1897 syn::parse_str::<dsl_hir::Device>(
1898 "
1899 /// Hi!
1900 #[cfg(bla)]
1901 ref Foo = block Bar {
1902 const ADDRESS_OFFSET = 5;
1903 }
1904 "
1905 )
1906 .unwrap()
1907 )
1908 .unwrap()
1909 .objects,
1910 &[mir::Object::Ref(mir::RefObject {
1911 cfg_attr: mir::Cfg::new(Some("bla")),
1912 description: " Hi!".into(),
1913 name: "Foo".into(),
1914 object_override: mir::ObjectOverride::Block(mir::BlockOverride {
1915 name: "Bar".into(),
1916 address_offset: Some(5),
1917 repeat: None
1918 })
1919 })]
1920 );
1921
1922 assert_eq!(
1923 transform(
1924 syn::parse_str::<dsl_hir::Device>(
1925 "
1926 ref Foo = block Bar {
1927 const REPEAT = {
1928 count: 6,
1929 stride: 2
1930 };
1931 }
1932 "
1933 )
1934 .unwrap()
1935 )
1936 .unwrap()
1937 .objects,
1938 &[mir::Object::Ref(mir::RefObject {
1939 cfg_attr: mir::Cfg::new(None),
1940 description: "".into(),
1941 name: "Foo".into(),
1942 object_override: mir::ObjectOverride::Block(mir::BlockOverride {
1943 name: "Bar".into(),
1944 address_offset: None,
1945 repeat: Some(mir::Repeat {
1946 count: 6,
1947 stride: 2
1948 })
1949 })
1950 })]
1951 );
1952 }
1953
1954 #[test]
1955 fn block() {
1956 assert_eq!(
1957 transform(
1958 syn::parse_str::<dsl_hir::Device>(
1959 "
1960 block Foo {
1961
1962 }
1963 "
1964 )
1965 .unwrap()
1966 )
1967 .unwrap()
1968 .objects,
1969 &[mir::Object::Block(mir::Block {
1970 cfg_attr: Default::default(),
1971 description: Default::default(),
1972 name: "Foo".into(),
1973 address_offset: 0,
1974 repeat: Default::default(),
1975 objects: Default::default(),
1976 })]
1977 );
1978
1979 assert_eq!(
1980 transform(
1981 syn::parse_str::<dsl_hir::Device>(
1982 "
1983 /// Hello!
1984 #[cfg(bar)]
1985 block Foo {
1986 const ADDRESS_OFFSET = 0x500;
1987 buffer Bla = 5,
1988 }
1989 "
1990 )
1991 .unwrap()
1992 )
1993 .unwrap()
1994 .objects,
1995 &[mir::Object::Block(mir::Block {
1996 cfg_attr: mir::Cfg::new(Some("bar")),
1997 description: " Hello!".into(),
1998 name: "Foo".into(),
1999 address_offset: 0x500,
2000 repeat: None,
2001 objects: vec![mir::Object::Buffer(mir::Buffer {
2002 cfg_attr: Default::default(),
2003 description: Default::default(),
2004 name: "Bla".into(),
2005 access: Default::default(),
2006 address: 5
2007 })],
2008 })]
2009 );
2010
2011 assert_eq!(
2012 transform(
2013 syn::parse_str::<dsl_hir::Device>(
2014 "
2015 block Foo {
2016 const REPEAT = {
2017 count: 4,
2018 stride: 4,
2019 };
2020 }
2021 "
2022 )
2023 .unwrap()
2024 )
2025 .unwrap()
2026 .objects,
2027 &[mir::Object::Block(mir::Block {
2028 cfg_attr: Default::default(),
2029 description: Default::default(),
2030 name: "Foo".into(),
2031 address_offset: 0,
2032 repeat: Some(mir::Repeat {
2033 count: 4,
2034 stride: 4
2035 }),
2036 objects: Default::default(),
2037 })]
2038 );
2039 }
2040
2041 #[test]
2042 fn register() {
2043 assert_eq!(
2044 transform(
2045 syn::parse_str::<dsl_hir::Device>(
2046 "
2047 register Foo {
2048 const SIZE_BITS = 16;
2049 }
2050 "
2051 )
2052 .unwrap()
2053 )
2054 .unwrap_err()
2055 .to_string(),
2056 "Register `Foo` must have an address"
2057 );
2058
2059 assert_eq!(
2060 transform(
2061 syn::parse_str::<dsl_hir::Device>(
2062 "
2063 register Foo {
2064 const ADDRESS = 5;
2065 }
2066 "
2067 )
2068 .unwrap()
2069 )
2070 .unwrap_err()
2071 .to_string(),
2072 "Register `Foo` must have size bits specified"
2073 );
2074
2075 assert_eq!(
2076 transform(
2077 syn::parse_str::<dsl_hir::Device>(
2078 "
2079 register Foo {
2080 const ADDRESS = 5;
2081 const SIZE_BITS = 16;
2082 }
2083 "
2084 )
2085 .unwrap()
2086 )
2087 .unwrap()
2088 .objects,
2089 &[mir::Object::Register(mir::Register {
2090 name: "Foo".into(),
2091 address: 5,
2092 size_bits: 16,
2093 ..Default::default()
2094 })]
2095 );
2096
2097 assert_eq!(
2098 transform(
2099 syn::parse_str::<dsl_hir::Device>(
2100 "
2101 /// This is foo
2102 register Foo {
2103 const ADDRESS = 5;
2104 type ByteOrder = LE;
2105 type BitOrder = MSB0;
2106 type Access = RO;
2107 const SIZE_BITS = 16;
2108 const REPEAT = {
2109 count: 2,
2110 stride: 120
2111 };
2112 const RESET_VALUE = 0x1234;
2113
2114 val: int = 0..16
2115 }
2116 "
2117 )
2118 .unwrap()
2119 )
2120 .unwrap()
2121 .objects,
2122 &[mir::Object::Register(mir::Register {
2123 description: " This is foo".into(),
2124 name: "Foo".into(),
2125 access: mir::Access::RO,
2126 byte_order: Some(mir::ByteOrder::LE),
2127 bit_order: mir::BitOrder::MSB0,
2128 address: 5,
2129 size_bits: 16,
2130 reset_value: Some(mir::ResetValue::Integer(0x1234)),
2131 repeat: Some(mir::Repeat {
2132 count: 2,
2133 stride: 120
2134 }),
2135 fields: vec![mir::Field {
2136 cfg_attr: Default::default(),
2137 description: Default::default(),
2138 name: "val".into(),
2139 access: Default::default(),
2140 base_type: mir::BaseType::Int,
2141 field_conversion: Default::default(),
2142 field_address: 0..16
2143 }],
2144 ..Default::default()
2145 })]
2146 );
2147
2148 assert_eq!(
2149 transform(
2150 syn::parse_str::<dsl_hir::Device>(
2151 "
2152 register Foo {
2153 const ADDRESS = 16;
2154 const SIZE_BITS = 136;
2155 const RESET_VALUE = 0x123456789ABCDEF000000000000000000;
2156 }
2157 "
2158 )
2159 .unwrap()
2160 )
2161 .unwrap_err()
2162 .to_string(),
2163 "number too large to fit in target type: number is parsed as an i128 or u128"
2164 );
2165
2166 assert_eq!(
2167 transform(
2168 syn::parse_str::<dsl_hir::Device>(
2169 "
2170 register Foo {
2171 const ADDRESS = 5;
2172 const SIZE_BITS = 16;
2173 const RESET_VALUE = [12, 34];
2174 }
2175 "
2176 )
2177 .unwrap()
2178 )
2179 .unwrap()
2180 .objects,
2181 &[mir::Object::Register(mir::Register {
2182 name: "Foo".into(),
2183 address: 5,
2184 reset_value: Some(mir::ResetValue::Array(vec![12, 34])),
2185 size_bits: 16,
2186 ..Default::default()
2187 })]
2188 );
2189
2190 assert_eq!(
2191 transform(
2192 syn::parse_str::<dsl_hir::Device>(
2193 "
2194 register Foo {
2195 const ADDRESS = 5;
2196 const SIZE_BITS = 16;
2197 const ALLOW_BIT_OVERLAP = true;
2198 const ALLOW_ADDRESS_OVERLAP = true;
2199 }
2200 "
2201 )
2202 .unwrap()
2203 )
2204 .unwrap()
2205 .objects,
2206 &[mir::Object::Register(mir::Register {
2207 name: "Foo".into(),
2208 address: 5,
2209 size_bits: 16,
2210 allow_bit_overlap: true,
2211 allow_address_overlap: true,
2212 ..Default::default()
2213 })]
2214 );
2215 }
2216
2217 #[test]
2218 fn test_integer_try_from_ident() {
2219 let test_cases = vec![
2221 ("u8", mir::Integer::U8),
2222 ("u16", mir::Integer::U16),
2223 ("u32", mir::Integer::U32),
2224 ("i8", mir::Integer::I8),
2225 ("i16", mir::Integer::I16),
2226 ("i32", mir::Integer::I32),
2227 ("i64", mir::Integer::I64),
2228 ];
2229
2230 for (ident_str, expected) in test_cases {
2231 let ident = syn::Ident::new(ident_str, Span::call_site());
2232 let result = mir::Integer::try_from(ident);
2233 assert_eq!(result.unwrap(), expected);
2234 }
2235
2236 let invalid_ident: syn::Ident = syn::parse_quote! { foo };
2238 let result = mir::Integer::try_from(invalid_ident);
2239
2240 assert_eq!(
2242 result.unwrap_err().to_string(),
2243 "Must be an integer type: u8, u16, u32, i8, i16, i32, i64"
2244 );
2245 }
2246}