Skip to main content

xidl_parser/hir/
mod.rs

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}