1mod enum_dcl;
2pub use enum_dcl::*;
3
4mod struct_dcl;
5pub use struct_dcl::*;
6
7mod annotation;
8pub use annotation::*;
9
10mod expr;
11pub use expr::*;
12
13mod declarator;
14pub use declarator::*;
15
16mod types;
17pub use types::*;
18
19mod const_dcl;
20pub use const_dcl::*;
21
22mod interface;
23pub use interface::*;
24
25mod type_dcl;
26pub use type_dcl::*;
27
28mod exception_dcl;
29pub use exception_dcl::*;
30
31mod interface_codegen;
32
33use serde::{Deserialize, Serialize};
34use serde_json::Value;
35use std::collections::HashMap;
36
37#[derive(Debug, Serialize, Deserialize, Clone)]
38pub struct Specification(pub Vec<Definition>);
39
40pub type ParserProperties = HashMap<String, Value>;
41
42#[derive(Debug, Serialize, Deserialize, Clone)]
43pub enum Definition {
44 ModuleDcl(ModuleDcl),
45 Pragma(Pragma),
46 ConstrTypeDcl(ConstrTypeDcl),
47 TypeDcl(TypeDcl),
48 ConstDcl(ConstDcl),
49 ExceptDcl(ExceptDcl),
50 InterfaceDcl(InterfaceDcl),
51}
52
53#[derive(Debug, Serialize, Deserialize, Clone)]
54pub struct ModuleDcl {
55 pub annotations: Vec<Annotation>,
56 pub ident: String,
57 pub definition: Vec<Definition>,
58}
59
60#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
61pub enum SerializeKind {
62 Cdr,
63 PlainCdr,
64 PlCdr,
65 PlainCdr2,
66 DelimitedCdr,
67 PlCdr2,
68}
69
70#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
71pub enum SerializeVersion {
72 Xcdr1,
73 Xcdr2,
74}
75
76#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy)]
77pub struct SerializeConfig {
78 pub explicit_kind: Option<SerializeKind>,
79 pub version: Option<SerializeVersion>,
80}
81
82#[derive(Debug, Serialize, Deserialize, Clone)]
83pub enum Pragma {
84 XidlcSerialize(SerializeKind),
85 XidlcVersion(SerializeVersion),
86 XidlcPackage(String),
87 XidlcOpenApiVersion(String),
88}
89
90#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
91pub enum Extensibility {
92 Final,
93 Appendable,
94 Mutable,
95 None,
96}
97
98impl SerializeConfig {
99 pub fn apply_pragma(&mut self, pragma: Pragma) {
100 match pragma {
101 Pragma::XidlcSerialize(kind) => {
102 self.explicit_kind = Some(kind);
103 }
104 Pragma::XidlcVersion(version) => {
105 self.version = Some(version);
106 self.explicit_kind = None;
107 }
108 Pragma::XidlcPackage(_) | Pragma::XidlcOpenApiVersion(_) => {}
109 }
110 }
111
112 pub fn resolve(&self, extensibility: Extensibility) -> SerializeKind {
113 if let Some(kind) = self.explicit_kind {
114 return kind;
115 }
116
117 match self.version {
118 None => SerializeKind::Cdr,
119 Some(SerializeVersion::Xcdr1) => match extensibility {
120 Extensibility::Mutable => SerializeKind::PlCdr,
121 Extensibility::Final | Extensibility::Appendable => SerializeKind::Cdr,
122 Extensibility::None => SerializeKind::PlainCdr,
123 },
124 Some(SerializeVersion::Xcdr2) => match extensibility {
125 Extensibility::Final => SerializeKind::PlainCdr2,
126 Extensibility::Appendable => SerializeKind::DelimitedCdr,
127 Extensibility::Mutable => SerializeKind::PlCdr2,
128 Extensibility::None => SerializeKind::Cdr,
129 },
130 }
131 }
132
133 pub fn resolve_for_annotations(&self, annotations: &[Annotation]) -> SerializeKind {
134 self.resolve(extensibility_from_annotations(annotations))
135 }
136}
137
138pub fn extensibility_from_annotations(annotations: &[Annotation]) -> Extensibility {
139 let mut final_flag = false;
140 let mut appendable = false;
141 let mut mutable = false;
142 for anno in annotations {
143 if let Annotation::Builtin { name, .. } = anno {
144 if name.eq_ignore_ascii_case("final") {
145 final_flag = true;
146 } else if name.eq_ignore_ascii_case("appendable") {
147 appendable = true;
148 } else if name.eq_ignore_ascii_case("mutable") {
149 mutable = true;
150 }
151 }
152 if let Annotation::Builtin { name, params } = anno {
153 if name.eq_ignore_ascii_case("extensibility") {
154 if let Some(AnnotationParams::Raw(raw)) = params {
155 let value = raw.trim().trim_matches('"');
156 if value.eq_ignore_ascii_case("final") {
157 final_flag = true;
158 } else if value.eq_ignore_ascii_case("appendable") {
159 appendable = true;
160 } else if value.eq_ignore_ascii_case("mutable") {
161 mutable = true;
162 }
163 }
164 }
165 }
166 }
167
168 if mutable {
169 Extensibility::Mutable
170 } else if appendable {
171 Extensibility::Appendable
172 } else if final_flag {
173 Extensibility::Final
174 } else {
175 Extensibility::None
176 }
177}
178
179#[derive(Debug, Serialize, Deserialize, Clone)]
180pub enum ConstrTypeDcl {
181 StructForwardDcl(StructForwardDcl),
182 StructDcl(StructDcl),
183 EnumDcl(EnumDcl),
184 UnionForwardDcl(UnionForwardDcl),
185 UnionDef(UnionDef),
186 BitsetDcl(BitsetDcl),
187 BitmaskDcl(BitmaskDcl),
188}
189
190#[derive(Debug, Serialize, Deserialize, Clone)]
191pub struct UnionForwardDcl {
192 pub annotations: Vec<Annotation>,
193 pub ident: String,
194}
195
196#[derive(Debug, Serialize, Deserialize, Clone)]
197pub struct UnionDef {
198 pub annotations: Vec<Annotation>,
199 pub ident: String,
200 pub switch_type_spec: SwitchTypeSpec,
201 pub case: Vec<Case>,
202}
203
204impl UnionDef {
205 pub fn serialize_kind(&self, config: &SerializeConfig) -> SerializeKind {
206 config.resolve_for_annotations(&self.annotations)
207 }
208}
209
210#[derive(Debug, Serialize, Deserialize, Clone)]
211pub struct Case {
212 pub label: Vec<CaseLabel>,
213 pub element: ElementSpec,
214}
215
216#[derive(Debug, Serialize, Deserialize, Clone)]
217pub enum CaseLabel {
218 Value(ConstExpr),
219 Default,
220}
221
222#[derive(Debug, Serialize, Deserialize, Clone)]
223pub struct ElementSpec {
224 pub annotations: Vec<Annotation>,
225 pub ty: ElementSpecTy,
226 pub value: Declarator,
227 pub field_id: Option<u32>,
228}
229
230#[derive(Debug, Serialize, Deserialize, Clone)]
231pub enum ElementSpecTy {
232 TypeSpec(TypeSpec),
233 ConstrTypeDcl(ConstrTypeDcl),
234}
235
236#[derive(Debug, Serialize, Deserialize, Clone)]
237pub enum SwitchTypeSpec {
238 IntegerType(IntegerType),
239 CharType,
240 WideCharType,
241 BooleanType,
242 ScopedName(ScopedName),
243 OctetType,
244}
245
246#[derive(Debug, Serialize, Deserialize, Clone)]
247pub struct BitsetDcl {
248 pub annotations: Vec<Annotation>,
249 pub ident: String,
250 pub parent: Option<ScopedName>,
251 pub field: Vec<BitField>,
252}
253
254impl BitsetDcl {
255 pub fn serialize_kind(&self, config: &SerializeConfig) -> SerializeKind {
256 config.resolve_for_annotations(&self.annotations)
257 }
258}
259
260#[derive(Clone, Debug, Serialize, Deserialize)]
261pub enum BitFieldType {
262 Bool,
263 Octec,
264 SignedInt,
265 UnsignedInt,
266}
267
268#[derive(Debug, Serialize, Deserialize, Clone)]
269pub struct BitField {
270 pub ident: String,
271 pub pos: PositiveIntConst,
272 pub ty: Option<BitFieldType>,
273}
274
275#[derive(Debug, Serialize, Deserialize, Clone)]
276pub struct BitmaskDcl {
277 pub annotations: Vec<Annotation>,
278 pub ident: String,
279 pub value: Vec<BitValue>,
280}
281
282impl BitmaskDcl {
283 pub fn serialize_kind(&self, config: &SerializeConfig) -> SerializeKind {
284 config.resolve_for_annotations(&self.annotations)
285 }
286}
287
288#[derive(Debug, Serialize, Deserialize, Clone)]
289pub struct BitValue {
290 pub annotations: Vec<Annotation>,
291 pub ident: String,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize)]
295pub struct ScopedName {
296 pub name: Vec<String>,
297 pub is_root: bool,
298}
299
300impl From<crate::typed_ast::ScopedName> for ScopedName {
301 fn from(typed_ast: crate::typed_ast::ScopedName) -> Self {
302 let is_root = typed_ast.node_text.starts_with("::");
303 let mut v = vec![];
304 get_scoped_name(&mut v, &typed_ast);
305 let name = v.into_iter().map(ToOwned::to_owned).collect();
306
307 Self { name, is_root }
308 }
309}
310
311fn get_scoped_name<'a>(pre: &mut Vec<&'a str>, value: &'a crate::typed_ast::ScopedName) {
312 if let Some(value) = &value.scoped_name {
313 get_scoped_name(pre, value);
314 }
315
316 pre.push(&value.identifier.0);
317}
318
319impl From<crate::typed_ast::Specification> for Specification {
320 fn from(value: crate::typed_ast::Specification) -> Self {
321 spec_from_typed_ast(value, true)
322 }
323}
324
325impl Specification {
326 pub fn from_typed_ast_with_properties(
327 value: crate::typed_ast::Specification,
328 properties: ParserProperties,
329 ) -> Self {
330 let expand_interface = properties
331 .get("expand_interface")
332 .and_then(Value::as_bool)
333 .unwrap_or(true);
334 spec_from_typed_ast(value, expand_interface)
335 }
336}
337
338pub(crate) fn spec_from_typed_ast(
339 value: crate::typed_ast::Specification,
340 expand_interfaces: bool,
341) -> Specification {
342 let mut defs = Vec::new();
343 let mut modules = Vec::new();
344 collect_defs(value.0, &mut modules, expand_interfaces, &mut defs);
345 Specification(defs)
346}
347
348fn collect_defs(
349 defs: Vec<crate::typed_ast::Definition>,
350 modules: &mut Vec<String>,
351 expand_interfaces: bool,
352 out: &mut Vec<Definition>,
353) {
354 for def in defs {
355 match def {
356 crate::typed_ast::Definition::ModuleDcl(module) => {
357 let ident = module.ident.0;
358 let annotations = expand_annotations(module.annotations);
359 modules.push(ident.clone());
360 let mut inner = Vec::new();
361 collect_defs(module.definition, modules, expand_interfaces, &mut inner);
362 modules.pop();
363 out.push(Definition::ModuleDcl(ModuleDcl {
364 annotations,
365 ident,
366 definition: inner,
367 }));
368 }
369 crate::typed_ast::Definition::PreprocCall(call) => {
370 if let Some(pragma) = parse_xidlc_pragma(&call) {
371 out.push(Definition::Pragma(pragma));
372 }
373 }
374 crate::typed_ast::Definition::TypeDcl(type_dcl) => {
375 let type_dcl: TypeDcl = type_dcl.into();
376 out.push(Definition::TypeDcl(type_dcl));
377 }
378 crate::typed_ast::Definition::ConstDcl(const_dcl) => {
379 out.push(Definition::ConstDcl(const_dcl.into()));
380 }
381 crate::typed_ast::Definition::ExceptDcl(except_dcl) => {
382 out.push(Definition::ExceptDcl(except_dcl.into()));
383 }
384 crate::typed_ast::Definition::InterfaceDcl(interface_dcl) => {
385 let interface: InterfaceDcl = interface_dcl.into();
386 if expand_interfaces {
387 let extra = interface_codegen::expand_interface(&interface, modules)
388 .unwrap_or_else(|err| {
389 panic!("interface expansion failed: {err}");
390 });
391 out.extend(extra);
392 }
393 out.push(Definition::InterfaceDcl(interface));
394 }
395 crate::typed_ast::Definition::TemplateModuleDcl(_)
396 | crate::typed_ast::Definition::TemplateModuleInst(_)
397 | crate::typed_ast::Definition::PreprocInclude(_)
398 | crate::typed_ast::Definition::PreprocDefine(_) => {}
399 }
400 }
401}
402
403fn parse_xidlc_pragma(call: &crate::typed_ast::PreprocCall) -> Option<Pragma> {
404 let directive = call.directive.0.as_str();
405 if !directive.eq_ignore_ascii_case("#pragma") && !directive.eq_ignore_ascii_case("#progma") {
406 return None;
407 }
408 let arg = call.argument.as_ref()?.0.as_str();
409 let mut parts = arg.split_whitespace();
410 let namespace = parts.next()?;
411 if !namespace.eq_ignore_ascii_case("xidlc") {
412 return None;
413 }
414 let token = parts.next()?;
415 let rest = parts.collect::<Vec<_>>().join(" ");
416
417 if token.eq_ignore_ascii_case("XCDR1") {
418 return Some(Pragma::XidlcVersion(SerializeVersion::Xcdr1));
419 }
420 if token.eq_ignore_ascii_case("XCDR2") {
421 return Some(Pragma::XidlcVersion(SerializeVersion::Xcdr2));
422 }
423 if token.eq_ignore_ascii_case("package") {
424 if !rest.is_empty() {
425 return Some(Pragma::XidlcPackage(trim_pragma_value(&rest)));
426 }
427 return None;
428 }
429 if token.eq_ignore_ascii_case("version") {
430 if !rest.is_empty() {
431 return Some(Pragma::XidlcOpenApiVersion(trim_pragma_value(&rest)));
432 }
433 return None;
434 }
435
436 if let Some(inner) = token
437 .strip_prefix("serialize(")
438 .and_then(|value| value.strip_suffix(')'))
439 {
440 let inner = inner.trim();
441 if inner.eq_ignore_ascii_case("XCDR1") {
442 return Some(Pragma::XidlcVersion(SerializeVersion::Xcdr1));
443 }
444 if inner.eq_ignore_ascii_case("XCDR2") {
445 return Some(Pragma::XidlcVersion(SerializeVersion::Xcdr2));
446 }
447 if let Some(kind) = parse_serialize_kind(inner) {
448 return Some(Pragma::XidlcSerialize(kind));
449 }
450 }
451
452 None
453}
454
455fn trim_pragma_value(value: &str) -> String {
456 let value = value.trim();
457 if value.len() >= 2 {
458 let first = value.chars().next().unwrap();
459 let last = value.chars().last().unwrap();
460 if (first == '"' && last == '"') || (first == '\'' && last == '\'') {
461 return value[1..value.len() - 1].to_string();
462 }
463 }
464 value.to_string()
465}
466
467fn parse_serialize_kind(value: &str) -> Option<SerializeKind> {
468 let value = value.trim();
469 if value.eq_ignore_ascii_case("CDR") {
470 Some(SerializeKind::Cdr)
471 } else if value.eq_ignore_ascii_case("PLAIN_CDR") {
472 Some(SerializeKind::PlainCdr)
473 } else if value.eq_ignore_ascii_case("PL_CDR") {
474 Some(SerializeKind::PlCdr)
475 } else if value.eq_ignore_ascii_case("PLAIN_CDR2") {
476 Some(SerializeKind::PlainCdr2)
477 } else if value.eq_ignore_ascii_case("DELIMITED_CDR") {
478 Some(SerializeKind::DelimitedCdr)
479 } else if value.eq_ignore_ascii_case("PL_CDR2") {
480 Some(SerializeKind::PlCdr2)
481 } else {
482 None
483 }
484}
485
486impl From<crate::typed_ast::ConstrTypeDcl> for ConstrTypeDcl {
487 fn from(value: crate::typed_ast::ConstrTypeDcl) -> Self {
488 match value {
489 crate::typed_ast::ConstrTypeDcl::StructDcl(struct_dcl) => struct_dcl.into(),
490 crate::typed_ast::ConstrTypeDcl::UnionDcl(union_dcl) => union_dcl.into(),
491 crate::typed_ast::ConstrTypeDcl::EnumDcl(enum_dcl) => Self::EnumDcl(enum_dcl.into()),
492 crate::typed_ast::ConstrTypeDcl::BitsetDcl(bitset_dcl) => {
493 Self::BitsetDcl(bitset_dcl.into())
494 }
495 crate::typed_ast::ConstrTypeDcl::BitmaskDcl(bitmask_dcl) => {
496 Self::BitmaskDcl(bitmask_dcl.into())
497 }
498 }
499 }
500}
501
502impl From<crate::typed_ast::StructDcl> for ConstrTypeDcl {
503 fn from(value: crate::typed_ast::StructDcl) -> Self {
504 match value {
505 crate::typed_ast::StructDcl::StructForwardDcl(forward) => {
506 Self::StructForwardDcl(forward.into())
507 }
508 crate::typed_ast::StructDcl::StructDef(def) => Self::StructDcl(def.into()),
509 }
510 }
511}
512
513impl From<crate::typed_ast::UnionDcl> for ConstrTypeDcl {
514 fn from(value: crate::typed_ast::UnionDcl) -> Self {
515 match value {
516 crate::typed_ast::UnionDcl::UnionForwardDcl(forward) => {
517 Self::UnionForwardDcl(forward.into())
518 }
519 crate::typed_ast::UnionDcl::UnionDef(def) => Self::UnionDef(def.into()),
520 }
521 }
522}
523
524impl From<crate::typed_ast::UnionForwardDcl> for UnionForwardDcl {
525 fn from(value: crate::typed_ast::UnionForwardDcl) -> Self {
526 Self {
527 annotations: vec![],
528 ident: value.0.0,
529 }
530 }
531}
532
533impl From<crate::typed_ast::UnionDef> for UnionDef {
534 fn from(value: crate::typed_ast::UnionDef) -> Self {
535 let mut cases = value
536 .case
537 .into_iter()
538 .map(Into::into)
539 .collect::<Vec<Case>>();
540 let mut member_ids = std::collections::HashMap::new();
541 let mut next_field_id = 1u32;
542 for case in cases.iter_mut() {
543 let name = declarator_name(&case.element.value).to_string();
544 if let Some(id) = case.element.field_id {
545 let entry = member_ids.entry(name.clone()).or_insert(id);
546 case.element.field_id = Some(*entry);
547 continue;
548 }
549 if let Some(existing) = member_ids.get(&name) {
550 case.element.field_id = Some(*existing);
551 continue;
552 }
553 member_ids.insert(name, next_field_id);
554 case.element.field_id = Some(next_field_id);
555 next_field_id += 1;
556 }
557 Self {
558 annotations: vec![],
559 ident: value.ident.0,
560 switch_type_spec: value.switch_type_spec.into(),
561 case: cases,
562 }
563 }
564}
565
566impl From<crate::typed_ast::Case> for Case {
567 fn from(value: crate::typed_ast::Case) -> Self {
568 Self {
569 label: value.label.into_iter().map(Into::into).collect(),
570 element: value.element.into(),
571 }
572 }
573}
574
575impl From<crate::typed_ast::CaseLabel> for CaseLabel {
576 fn from(value: crate::typed_ast::CaseLabel) -> Self {
577 match value {
578 crate::typed_ast::CaseLabel::Case(expr) => Self::Value(expr.into()),
579 crate::typed_ast::CaseLabel::Default => Self::Default,
580 }
581 }
582}
583
584impl From<crate::typed_ast::ElementSpec> for ElementSpec {
585 fn from(value: crate::typed_ast::ElementSpec) -> Self {
586 let annotations = expand_annotations(value.annotations);
587 let field_id = annotation_id_value(&annotations);
588 Self {
589 annotations,
590 ty: value.ty.into(),
591 value: value.value.into(),
592 field_id,
593 }
594 }
595}
596
597impl From<crate::typed_ast::ElementSpecTy> for ElementSpecTy {
598 fn from(value: crate::typed_ast::ElementSpecTy) -> Self {
599 match value {
600 crate::typed_ast::ElementSpecTy::TypeSpec(ty) => Self::TypeSpec(ty.into()),
601 crate::typed_ast::ElementSpecTy::ConstrTypeDcl(constr) => {
602 Self::ConstrTypeDcl(constr.into())
603 }
604 }
605 }
606}
607
608impl From<crate::typed_ast::SwitchTypeSpec> for SwitchTypeSpec {
609 fn from(value: crate::typed_ast::SwitchTypeSpec) -> Self {
610 match value {
611 crate::typed_ast::SwitchTypeSpec::IntegerType(integer_type) => {
612 Self::IntegerType(integer_type.into())
613 }
614 crate::typed_ast::SwitchTypeSpec::CharType(_) => Self::CharType,
615 crate::typed_ast::SwitchTypeSpec::WideCharType(_) => Self::WideCharType,
616 crate::typed_ast::SwitchTypeSpec::BooleanType(_) => Self::BooleanType,
617 crate::typed_ast::SwitchTypeSpec::ScopedName(scoped_name) => {
618 Self::ScopedName(scoped_name.into())
619 }
620 crate::typed_ast::SwitchTypeSpec::OctetType(_) => Self::OctetType,
621 }
622 }
623}
624
625fn declarator_name(value: &Declarator) -> &str {
626 match value {
627 Declarator::SimpleDeclarator(value) => &value.0,
628 Declarator::ArrayDeclarator(value) => &value.ident,
629 }
630}
631
632impl From<crate::typed_ast::BitsetDcl> for BitsetDcl {
633 fn from(value: crate::typed_ast::BitsetDcl) -> Self {
634 let mut field = Vec::new();
635 for bitfield in value.field {
636 let pos = bitfield.spec.pos;
637 let ty = bitfield.spec.dst_ty.map(Into::into);
638 for ident in bitfield.ident {
639 field.push(BitField {
640 ident: ident.0,
641 pos: pos.clone().into(),
642 ty: ty.clone(),
643 });
644 }
645 }
646
647 Self {
648 annotations: vec![],
649 ident: value.ident.0,
650 parent: value.parent.map(Into::into),
651 field,
652 }
653 }
654}
655
656impl From<crate::typed_ast::DestinationType> for BitFieldType {
657 fn from(value: crate::typed_ast::DestinationType) -> Self {
658 match value {
659 crate::typed_ast::DestinationType::BooleanType(_) => Self::Bool,
660 crate::typed_ast::DestinationType::OctetType(_) => Self::Octec,
661 crate::typed_ast::DestinationType::IntegerType(integer_type) => {
662 if matches!(integer_type, crate::typed_ast::IntegerType::SignedInt(_)) {
663 Self::SignedInt
664 } else {
665 Self::UnsignedInt
666 }
667 }
668 }
669 }
670}
671
672impl From<crate::typed_ast::BitmaskDcl> for BitmaskDcl {
673 fn from(value: crate::typed_ast::BitmaskDcl) -> Self {
674 Self {
675 annotations: vec![],
676 ident: value.ident.0,
677 value: value.value.into_iter().map(Into::into).collect(),
678 }
679 }
680}
681
682impl From<crate::typed_ast::BitValue> for BitValue {
683 fn from(value: crate::typed_ast::BitValue) -> Self {
684 Self {
685 annotations: expand_annotations(value.annotations),
686 ident: value.ident.0,
687 }
688 }
689}