1use core::fmt::{self, Write};
17
18use crate::ast::types::*;
19
20const INDENT: &str = " ";
21
22fn write_indent(f: &mut fmt::Formatter<'_>, depth: usize) -> fmt::Result {
27 for _ in 0..depth {
28 f.write_str(INDENT)?;
29 }
30 Ok(())
31}
32
33fn write_inline_annotations(f: &mut fmt::Formatter<'_>, anns: &[Annotation]) -> fmt::Result {
34 for ann in anns {
35 write!(f, "{ann} ")?;
36 }
37 Ok(())
38}
39
40fn write_block_annotations(
41 f: &mut fmt::Formatter<'_>,
42 anns: &[Annotation],
43 depth: usize,
44) -> fmt::Result {
45 for ann in anns {
46 write_indent(f, depth)?;
47 writeln!(f, "{ann}")?;
48 }
49 Ok(())
50}
51
52impl fmt::Display for Specification {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 for (i, def) in self.definitions.iter().enumerate() {
59 if i > 0 {
60 writeln!(f)?;
61 }
62 print_definition(f, def, 0)?;
63 }
64 Ok(())
65 }
66}
67
68fn print_definition(f: &mut fmt::Formatter<'_>, def: &Definition, depth: usize) -> fmt::Result {
70 match def {
71 Definition::Module(m) => print_module(f, m, depth),
72 Definition::Type(t) => {
73 print_type_decl(f, t, depth)?;
74 f.write_str(";\n")
75 }
76 Definition::Const(c) => {
77 write_block_annotations(f, &c.annotations, depth)?;
78 write_indent(f, depth)?;
79 print_const_decl(f, c)?;
80 f.write_str(";\n")
81 }
82 Definition::Except(e) => {
83 write_block_annotations(f, &e.annotations, depth)?;
84 print_except_decl(f, e, depth)?;
85 f.write_str(";\n")
86 }
87 Definition::Interface(i) => {
88 print_interface_dcl(f, i, depth)?;
89 f.write_str(";\n")
90 }
91 Definition::ValueBox(v) => {
92 write_block_annotations(f, &v.annotations, depth)?;
93 write_indent(f, depth)?;
94 write!(f, "valuetype {} ", v.name.text)?;
95 print_type_spec(f, &v.type_spec)?;
96 f.write_str(";\n")
97 }
98 Definition::ValueForward(v) => {
99 write_indent(f, depth)?;
100 writeln!(f, "valuetype {};", v.name.text)
101 }
102 Definition::Annotation(a) => print_annotation_dcl(f, a, depth),
103 Definition::ValueDef(_)
104 | Definition::TypeId(_)
105 | Definition::TypePrefix(_)
106 | Definition::Import(_)
107 | Definition::Component(_)
108 | Definition::Home(_)
109 | Definition::Event(_)
110 | Definition::Porttype(_)
111 | Definition::Connector(_)
112 | Definition::TemplateModule(_)
113 | Definition::TemplateModuleInst(_) => {
114 write_indent(f, depth)?;
115 writeln!(f, "/* corba/ccm/template construct (round-trip stub) */")
119 }
120 Definition::VendorExtension(v) => {
121 write_indent(f, depth)?;
122 writeln!(
127 f,
128 "/* vendor-extension {} (raw not preserved) */",
129 v.production_name
130 )
131 }
132 }
133}
134
135fn print_module(f: &mut fmt::Formatter<'_>, m: &ModuleDef, depth: usize) -> fmt::Result {
137 write_block_annotations(f, &m.annotations, depth)?;
138 write_indent(f, depth)?;
139 writeln!(f, "module {} {{", m.name.text)?;
140 for d in &m.definitions {
141 print_definition(f, d, depth + 1)?;
142 }
143 write_indent(f, depth)?;
144 f.write_str("};\n")
145}
146
147fn print_type_decl(f: &mut fmt::Formatter<'_>, td: &TypeDecl, depth: usize) -> fmt::Result {
152 match td {
153 TypeDecl::Constr(c) => print_constr_type_decl(f, c, depth),
154 TypeDecl::Typedef(t) => {
155 write_block_annotations(f, &t.annotations, depth)?;
156 write_indent(f, depth)?;
157 f.write_str("typedef ")?;
158 print_type_spec(f, &t.type_spec)?;
159 f.write_str(" ")?;
160 for (i, d) in t.declarators.iter().enumerate() {
161 if i > 0 {
162 f.write_str(", ")?;
163 }
164 print_declarator(f, d)?;
165 }
166 Ok(())
167 }
168 }
169}
170
171fn print_constr_type_decl(
172 f: &mut fmt::Formatter<'_>,
173 c: &ConstrTypeDecl,
174 depth: usize,
175) -> fmt::Result {
176 match c {
177 ConstrTypeDecl::Struct(s) => print_struct_dcl(f, s, depth),
178 ConstrTypeDecl::Union(u) => print_union_dcl(f, u, depth),
179 ConstrTypeDecl::Enum(e) => print_enum_def(f, e, depth),
180 ConstrTypeDecl::Bitset(b) => print_bitset_decl(f, b, depth),
181 ConstrTypeDecl::Bitmask(b) => print_bitmask_decl(f, b, depth),
182 }
183}
184
185fn print_struct_dcl(f: &mut fmt::Formatter<'_>, s: &StructDcl, depth: usize) -> fmt::Result {
190 match s {
191 StructDcl::Def(d) => {
192 write_block_annotations(f, &d.annotations, depth)?;
193 write_indent(f, depth)?;
194 write!(f, "struct {}", d.name.text)?;
195 if let Some(base) = &d.base {
196 write!(f, " : {base}")?;
197 }
198 f.write_str(" {")?;
199 if d.members.is_empty() {
200 f.write_str("}")?;
201 } else {
202 f.write_str("\n")?;
203 for m in &d.members {
204 print_member(f, m, depth + 1)?;
205 }
206 write_indent(f, depth)?;
207 f.write_str("}")?;
208 }
209 Ok(())
210 }
211 StructDcl::Forward(d) => {
212 write_indent(f, depth)?;
213 write!(f, "struct {}", d.name.text)
214 }
215 }
216}
217
218fn print_member(f: &mut fmt::Formatter<'_>, m: &Member, depth: usize) -> fmt::Result {
219 write_indent(f, depth)?;
220 write_inline_annotations(f, &m.annotations)?;
221 print_type_spec(f, &m.type_spec)?;
222 f.write_str(" ")?;
223 for (i, d) in m.declarators.iter().enumerate() {
224 if i > 0 {
225 f.write_str(", ")?;
226 }
227 print_declarator(f, d)?;
228 }
229 f.write_str(";\n")
230}
231
232fn print_union_dcl(f: &mut fmt::Formatter<'_>, u: &UnionDcl, depth: usize) -> fmt::Result {
237 match u {
238 UnionDcl::Def(d) => {
239 write_block_annotations(f, &d.annotations, depth)?;
240 write_indent(f, depth)?;
241 write!(f, "union {} switch (", d.name.text)?;
242 print_switch_type_spec(f, &d.switch_type)?;
243 f.write_str(") {")?;
244 if d.cases.is_empty() {
245 f.write_str("}")?;
246 } else {
247 f.write_str("\n")?;
248 for c in &d.cases {
249 print_case(f, c, depth + 1)?;
250 }
251 write_indent(f, depth)?;
252 f.write_str("}")?;
253 }
254 Ok(())
255 }
256 UnionDcl::Forward(d) => {
257 write_indent(f, depth)?;
258 write!(f, "union {}", d.name.text)
259 }
260 }
261}
262
263fn print_switch_type_spec(f: &mut fmt::Formatter<'_>, s: &SwitchTypeSpec) -> fmt::Result {
264 match s {
265 SwitchTypeSpec::Integer(i) => print_integer_type(f, *i),
266 SwitchTypeSpec::Char => f.write_str("char"),
267 SwitchTypeSpec::Boolean => f.write_str("boolean"),
268 SwitchTypeSpec::Octet => f.write_str("octet"),
269 SwitchTypeSpec::Scoped(s) => write!(f, "{s}"),
270 }
271}
272
273fn print_case(f: &mut fmt::Formatter<'_>, c: &Case, depth: usize) -> fmt::Result {
274 write_indent(f, depth)?;
275 write_inline_annotations(f, &c.annotations)?;
276 for label in &c.labels {
277 match label {
278 CaseLabel::Default => f.write_str("default: ")?,
279 CaseLabel::Value(e) => {
280 f.write_str("case ")?;
281 print_const_expr(f, e)?;
282 f.write_str(": ")?;
283 }
284 }
285 }
286 print_element_spec(f, &c.element)?;
287 f.write_str(";\n")
288}
289
290fn print_element_spec(f: &mut fmt::Formatter<'_>, e: &ElementSpec) -> fmt::Result {
291 write_inline_annotations(f, &e.annotations)?;
292 print_type_spec(f, &e.type_spec)?;
293 f.write_str(" ")?;
294 print_declarator(f, &e.declarator)
295}
296
297fn print_enum_def(f: &mut fmt::Formatter<'_>, e: &EnumDef, depth: usize) -> fmt::Result {
302 write_block_annotations(f, &e.annotations, depth)?;
303 write_indent(f, depth)?;
304 write!(f, "enum {} {{", e.name.text)?;
305 if e.enumerators.is_empty() {
306 f.write_str("}")?;
307 } else {
308 f.write_str("\n")?;
309 for (i, en) in e.enumerators.iter().enumerate() {
310 write_indent(f, depth + 1)?;
311 write_inline_annotations(f, &en.annotations)?;
312 f.write_str(&en.name.text)?;
313 if i + 1 < e.enumerators.len() {
314 f.write_str(",")?;
315 }
316 f.write_str("\n")?;
317 }
318 write_indent(f, depth)?;
319 f.write_str("}")?;
320 }
321 Ok(())
322}
323
324fn print_bitset_decl(f: &mut fmt::Formatter<'_>, b: &BitsetDecl, depth: usize) -> fmt::Result {
325 write_block_annotations(f, &b.annotations, depth)?;
326 write_indent(f, depth)?;
327 write!(f, "bitset {}", b.name.text)?;
328 if let Some(base) = &b.base {
329 write!(f, " : {base}")?;
330 }
331 f.write_str(" {")?;
332 if b.bitfields.is_empty() {
333 f.write_str("}")?;
334 } else {
335 f.write_str("\n")?;
336 for bf in &b.bitfields {
337 print_bitfield(f, bf, depth + 1)?;
338 }
339 write_indent(f, depth)?;
340 f.write_str("}")?;
341 }
342 Ok(())
343}
344
345fn print_bitfield(f: &mut fmt::Formatter<'_>, b: &Bitfield, depth: usize) -> fmt::Result {
346 write_indent(f, depth)?;
347 write_inline_annotations(f, &b.annotations)?;
348 f.write_str("bitfield<")?;
349 print_const_expr(f, &b.spec.width)?;
350 if let Some(dt) = &b.spec.dest_type {
351 f.write_str(", ")?;
352 print_primitive_type(f, *dt)?;
353 }
354 f.write_str(">")?;
355 if let Some(name) = &b.name {
356 write!(f, " {}", name.text)?;
357 }
358 f.write_str(";\n")
359}
360
361fn print_bitmask_decl(f: &mut fmt::Formatter<'_>, b: &BitmaskDecl, depth: usize) -> fmt::Result {
362 write_block_annotations(f, &b.annotations, depth)?;
363 write_indent(f, depth)?;
364 write!(f, "bitmask {} {{", b.name.text)?;
365 if b.values.is_empty() {
366 f.write_str("}")?;
367 } else {
368 f.write_str("\n")?;
369 for (i, v) in b.values.iter().enumerate() {
370 write_indent(f, depth + 1)?;
371 write_inline_annotations(f, &v.annotations)?;
372 f.write_str(&v.name.text)?;
373 if i + 1 < b.values.len() {
374 f.write_str(",")?;
375 }
376 f.write_str("\n")?;
377 }
378 write_indent(f, depth)?;
379 f.write_str("}")?;
380 }
381 Ok(())
382}
383
384fn print_declarator(f: &mut fmt::Formatter<'_>, d: &Declarator) -> fmt::Result {
389 match d {
390 Declarator::Simple(n) => f.write_str(&n.text),
391 Declarator::Array(a) => {
392 f.write_str(&a.name.text)?;
393 for sz in &a.sizes {
394 f.write_str("[")?;
395 print_const_expr(f, sz)?;
396 f.write_str("]")?;
397 }
398 Ok(())
399 }
400 }
401}
402
403fn print_const_decl(f: &mut fmt::Formatter<'_>, c: &ConstDecl) -> fmt::Result {
408 f.write_str("const ")?;
409 print_const_type(f, &c.type_)?;
410 write!(f, " {} = ", c.name.text)?;
411 print_const_expr(f, &c.value)
412}
413
414fn print_annotation_dcl(
416 f: &mut fmt::Formatter<'_>,
417 a: &AnnotationDcl,
418 depth: usize,
419) -> fmt::Result {
420 write_indent(f, depth)?;
421 writeln!(f, "@annotation {} {{", a.name.text)?;
422 for ec in &a.embedded_consts {
423 write_indent(f, depth + 1)?;
424 print_const_decl(f, ec)?;
425 f.write_str(";\n")?;
426 }
427 for et in &a.embedded_types {
428 print_type_decl(f, et, depth + 1)?;
429 f.write_str(";\n")?;
430 }
431 for m in &a.members {
432 write_indent(f, depth + 1)?;
433 print_const_type(f, &m.type_spec)?;
434 write!(f, " {}", m.name.text)?;
435 if let Some(d) = &m.default {
436 f.write_str(" default ")?;
437 print_const_expr(f, d)?;
438 }
439 f.write_str(";\n")?;
440 }
441 write_indent(f, depth)?;
442 f.write_str("};\n")
443}
444
445fn print_const_type(f: &mut fmt::Formatter<'_>, t: &ConstType) -> fmt::Result {
446 match t {
447 ConstType::Integer(i) => print_integer_type(f, *i),
448 ConstType::Floating(fl) => print_floating_type(f, *fl),
449 ConstType::Char => f.write_str("char"),
450 ConstType::WideChar => f.write_str("wchar"),
451 ConstType::Boolean => f.write_str("boolean"),
452 ConstType::Octet => f.write_str("octet"),
453 ConstType::String { wide: false } => f.write_str("string"),
454 ConstType::String { wide: true } => f.write_str("wstring"),
455 ConstType::Fixed => f.write_str("fixed"),
456 ConstType::Scoped(s) => write!(f, "{s}"),
457 }
458}
459
460fn print_const_expr(f: &mut fmt::Formatter<'_>, e: &ConstExpr) -> fmt::Result {
462 match e {
463 ConstExpr::Literal(l) => f.write_str(&l.raw),
464 ConstExpr::Scoped(s) => write!(f, "{s}"),
465 ConstExpr::Unary { op, operand, .. } => {
466 f.write_char(unary_op_char(*op))?;
467 print_const_expr(f, operand)
468 }
469 ConstExpr::Binary { op, lhs, rhs, .. } => {
470 f.write_str("(")?;
472 print_const_expr(f, lhs)?;
473 write!(f, " {} ", binary_op_str(*op))?;
474 print_const_expr(f, rhs)?;
475 f.write_str(")")
476 }
477 }
478}
479
480const fn unary_op_char(op: UnaryOp) -> char {
481 match op {
482 UnaryOp::Plus => '+',
483 UnaryOp::Minus => '-',
484 UnaryOp::BitNot => '~',
485 }
486}
487
488const fn binary_op_str(op: BinaryOp) -> &'static str {
489 match op {
490 BinaryOp::Or => "|",
491 BinaryOp::Xor => "^",
492 BinaryOp::And => "&",
493 BinaryOp::Shl => "<<",
494 BinaryOp::Shr => ">>",
495 BinaryOp::Add => "+",
496 BinaryOp::Sub => "-",
497 BinaryOp::Mul => "*",
498 BinaryOp::Div => "/",
499 BinaryOp::Mod => "%",
500 }
501}
502
503fn print_except_decl(f: &mut fmt::Formatter<'_>, e: &ExceptDecl, depth: usize) -> fmt::Result {
508 write_indent(f, depth)?;
509 write!(f, "exception {} {{", e.name.text)?;
510 if e.members.is_empty() {
511 f.write_str("}")?;
512 } else {
513 f.write_str("\n")?;
514 for m in &e.members {
515 print_member(f, m, depth + 1)?;
516 }
517 write_indent(f, depth)?;
518 f.write_str("}")?;
519 }
520 Ok(())
521}
522
523fn print_interface_dcl(f: &mut fmt::Formatter<'_>, i: &InterfaceDcl, depth: usize) -> fmt::Result {
528 match i {
529 InterfaceDcl::Def(d) => {
530 write_block_annotations(f, &d.annotations, depth)?;
531 write_indent(f, depth)?;
532 print_interface_kind(f, d.kind)?;
533 write!(f, "interface {}", d.name.text)?;
534 if !d.bases.is_empty() {
535 f.write_str(" : ")?;
536 for (idx, b) in d.bases.iter().enumerate() {
537 if idx > 0 {
538 f.write_str(", ")?;
539 }
540 write!(f, "{b}")?;
541 }
542 }
543 f.write_str(" {")?;
544 if d.exports.is_empty() {
545 f.write_str("}")?;
546 } else {
547 f.write_str("\n")?;
548 for e in &d.exports {
549 print_export(f, e, depth + 1)?;
550 }
551 write_indent(f, depth)?;
552 f.write_str("}")?;
553 }
554 Ok(())
555 }
556 InterfaceDcl::Forward(d) => {
557 write_indent(f, depth)?;
558 print_interface_kind(f, d.kind)?;
559 write!(f, "interface {}", d.name.text)
560 }
561 }
562}
563
564fn print_interface_kind(f: &mut fmt::Formatter<'_>, kind: InterfaceKind) -> fmt::Result {
565 match kind {
566 InterfaceKind::Plain => Ok(()),
567 InterfaceKind::Abstract => f.write_str("abstract "),
568 InterfaceKind::Local => f.write_str("local "),
569 }
570}
571
572fn print_export(f: &mut fmt::Formatter<'_>, e: &Export, depth: usize) -> fmt::Result {
573 match e {
574 Export::Op(o) => {
575 write_block_annotations(f, &o.annotations, depth)?;
576 write_indent(f, depth)?;
577 print_op_decl(f, o)?;
578 f.write_str(";\n")
579 }
580 Export::Attr(a) => {
581 write_block_annotations(f, &a.annotations, depth)?;
582 write_indent(f, depth)?;
583 print_attr_decl(f, a)?;
584 f.write_str(";\n")
585 }
586 Export::Type(t) => {
587 print_type_decl(f, t, depth)?;
588 f.write_str(";\n")
589 }
590 Export::Const(c) => {
591 write_block_annotations(f, &c.annotations, depth)?;
592 write_indent(f, depth)?;
593 print_const_decl(f, c)?;
594 f.write_str(";\n")
595 }
596 Export::Except(ex) => {
597 print_except_decl(f, ex, depth)?;
598 f.write_str(";\n")
599 }
600 }
601}
602
603fn print_op_decl(f: &mut fmt::Formatter<'_>, o: &OpDecl) -> fmt::Result {
604 if o.oneway {
605 f.write_str("oneway ")?;
606 }
607 match &o.return_type {
608 None => f.write_str("void")?,
609 Some(t) => print_type_spec(f, t)?,
610 }
611 write!(f, " {}(", o.name.text)?;
612 for (i, p) in o.params.iter().enumerate() {
613 if i > 0 {
614 f.write_str(", ")?;
615 }
616 print_param_decl(f, p)?;
617 }
618 f.write_str(")")?;
619 if !o.raises.is_empty() {
620 f.write_str(" raises (")?;
621 for (i, r) in o.raises.iter().enumerate() {
622 if i > 0 {
623 f.write_str(", ")?;
624 }
625 write!(f, "{r}")?;
626 }
627 f.write_str(")")?;
628 }
629 Ok(())
630}
631
632fn print_param_decl(f: &mut fmt::Formatter<'_>, p: &ParamDecl) -> fmt::Result {
633 write_inline_annotations(f, &p.annotations)?;
634 f.write_str(match p.attribute {
635 ParamAttribute::In => "in ",
636 ParamAttribute::Out => "out ",
637 ParamAttribute::InOut => "inout ",
638 })?;
639 print_type_spec(f, &p.type_spec)?;
640 write!(f, " {}", p.name.text)
641}
642
643fn print_attr_decl(f: &mut fmt::Formatter<'_>, a: &AttrDecl) -> fmt::Result {
644 if a.readonly {
645 f.write_str("readonly ")?;
646 }
647 f.write_str("attribute ")?;
648 print_type_spec(f, &a.type_spec)?;
649 write!(f, " {}", a.name.text)
650}
651
652fn print_type_spec(f: &mut fmt::Formatter<'_>, t: &TypeSpec) -> fmt::Result {
658 match t {
659 TypeSpec::Primitive(p) => print_primitive_type(f, *p),
660 TypeSpec::Scoped(s) => write!(f, "{s}"),
661 TypeSpec::Sequence(s) => {
662 f.write_str("sequence<")?;
663 print_type_spec(f, &s.elem)?;
664 if let Some(b) = &s.bound {
665 f.write_str(", ")?;
666 print_const_expr(f, b)?;
667 }
668 f.write_str(">")
669 }
670 TypeSpec::String(s) => {
671 f.write_str(if s.wide { "wstring" } else { "string" })?;
672 if let Some(b) = &s.bound {
673 f.write_str("<")?;
674 print_const_expr(f, b)?;
675 f.write_str(">")?;
676 }
677 Ok(())
678 }
679 TypeSpec::Fixed(p) => {
680 f.write_str("fixed<")?;
681 print_const_expr(f, &p.digits)?;
682 f.write_str(", ")?;
683 print_const_expr(f, &p.scale)?;
684 f.write_str(">")
685 }
686 TypeSpec::Map(m) => {
687 f.write_str("map<")?;
688 print_type_spec(f, &m.key)?;
689 f.write_str(", ")?;
690 print_type_spec(f, &m.value)?;
691 if let Some(b) = &m.bound {
692 f.write_str(", ")?;
693 print_const_expr(f, b)?;
694 }
695 f.write_str(">")
696 }
697 TypeSpec::Any => f.write_str("any"),
698 }
699}
700
701fn print_primitive_type(f: &mut fmt::Formatter<'_>, p: PrimitiveType) -> fmt::Result {
702 match p {
703 PrimitiveType::Integer(i) => print_integer_type(f, i),
704 PrimitiveType::Floating(fl) => print_floating_type(f, fl),
705 PrimitiveType::Char => f.write_str("char"),
706 PrimitiveType::WideChar => f.write_str("wchar"),
707 PrimitiveType::Boolean => f.write_str("boolean"),
708 PrimitiveType::Octet => f.write_str("octet"),
709 }
710}
711
712fn print_integer_type(f: &mut fmt::Formatter<'_>, i: IntegerType) -> fmt::Result {
713 f.write_str(match i {
714 IntegerType::Short => "short",
715 IntegerType::Long => "long",
716 IntegerType::LongLong => "long long",
717 IntegerType::UShort => "unsigned short",
718 IntegerType::ULong => "unsigned long",
719 IntegerType::ULongLong => "unsigned long long",
720 IntegerType::Int8 => "int8",
721 IntegerType::Int16 => "int16",
722 IntegerType::Int32 => "int32",
723 IntegerType::Int64 => "int64",
724 IntegerType::UInt8 => "uint8",
725 IntegerType::UInt16 => "uint16",
726 IntegerType::UInt32 => "uint32",
727 IntegerType::UInt64 => "uint64",
728 })
729}
730
731fn print_floating_type(f: &mut fmt::Formatter<'_>, fl: FloatingType) -> fmt::Result {
732 f.write_str(match fl {
733 FloatingType::Float => "float",
734 FloatingType::Double => "double",
735 FloatingType::LongDouble => "long double",
736 })
737}
738
739impl fmt::Display for ScopedName {
744 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
745 if self.absolute {
746 f.write_str("::")?;
747 }
748 for (i, p) in self.parts.iter().enumerate() {
749 if i > 0 {
750 f.write_str("::")?;
751 }
752 f.write_str(&p.text)?;
753 }
754 Ok(())
755 }
756}
757
758impl fmt::Display for Annotation {
759 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
760 write!(f, "@{}", self.name)?;
761 match &self.params {
762 AnnotationParams::None => Ok(()),
763 AnnotationParams::Empty => f.write_str("()"),
764 AnnotationParams::Single(e) => {
765 f.write_str("(")?;
766 print_const_expr(f, e)?;
767 f.write_str(")")
768 }
769 AnnotationParams::Named(items) => {
770 f.write_str("(")?;
771 for (i, p) in items.iter().enumerate() {
772 if i > 0 {
773 f.write_str(", ")?;
774 }
775 write!(f, "{}=", p.name.text)?;
776 print_const_expr(f, &p.value)?;
777 }
778 f.write_str(")")
779 }
780 }
781 }
782}
783
784#[cfg(test)]
785mod tests {
786 #![allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)]
787
788 use crate::config::ParserConfig;
789 use crate::parser::parse;
790
791 fn print(src: &str) -> String {
792 let ast = parse(src, &ParserConfig::default()).expect("parse");
793 format!("{ast}")
794 }
795
796 fn print_full(src: &str) -> String {
799 let cfg = ParserConfig::full_4_2();
800 let ast = parse(src, &cfg).expect("parse");
801 format!("{ast}")
802 }
803
804 #[test]
805 fn prints_empty_module() {
806 let out = print("module Empty {};");
807 assert!(out.contains("module Empty"), "got: {out}");
808 assert!(out.contains("};"));
809 }
810
811 #[test]
812 fn prints_struct_with_members() {
813 let out = print("struct P { long x; long y; };");
814 assert!(out.contains("struct P"), "got: {out}");
815 assert!(out.contains("long x;"));
816 assert!(out.contains("long y;"));
817 }
818
819 #[test]
820 fn prints_struct_with_inheritance() {
821 let out = print("struct D : Base { long x; };");
822 assert!(out.contains("struct D : Base"), "got: {out}");
823 }
824
825 #[test]
826 fn prints_typedef_sequence() {
827 let out = print("typedef sequence<long> Seq;");
828 assert!(out.contains("typedef sequence<long> Seq"), "got: {out}");
829 }
830
831 #[test]
832 fn prints_const_with_arithmetic() {
833 let out = print("const long V = 1 + 2 * 3;");
834 assert!(out.contains("const long V"), "got: {out}");
835 }
836
837 #[test]
838 fn prints_enum() {
839 let out = print("enum Color { RED, GREEN, BLUE };");
840 assert!(out.contains("enum Color"), "got: {out}");
841 assert!(out.contains("RED"));
842 assert!(out.contains("GREEN"));
843 }
844
845 #[test]
846 fn prints_annotated_struct() {
847 let out = print("@topic struct Foo { @key long id; };");
848 assert!(out.contains("@topic"), "got: {out}");
849 assert!(out.contains("@key long id"));
850 }
851
852 #[test]
853 fn prints_interface_with_op() {
854 let out = print("interface S { long add(in long a, in long b); };");
855 assert!(out.contains("interface S"), "got: {out}");
856 assert!(out.contains("long add"));
857 assert!(out.contains("in long a"));
858 }
859
860 #[test]
861 fn prints_oneway_op_with_raises() {
862 let out = print_full("interface S { oneway void log(in string m) raises (E); };");
864 assert!(out.contains("oneway void log"), "got: {out}");
865 assert!(out.contains("raises (E)"));
866 }
867
868 #[test]
869 fn prints_readonly_attribute() {
870 let out = print("interface C { readonly attribute long value; };");
871 assert!(out.contains("readonly attribute long value"), "got: {out}");
872 }
873
874 #[test]
875 fn prints_union() {
876 let out = print("union V switch (long) { case 1: long a; default: string b; };");
877 assert!(out.contains("union V switch (long)"), "got: {out}");
878 assert!(out.contains("case 1: long a"));
879 assert!(out.contains("default: string b"));
880 }
881
882 #[test]
883 fn prints_map() {
884 let out = print("typedef map<string, long> Idx;");
885 assert!(out.contains("map<string, long>"), "got: {out}");
886 }
887
888 #[test]
889 fn prints_bitset() {
890 let out = print("bitset F { bitfield<3> level; bitfield<1> on; };");
891 assert!(out.contains("bitset F"), "got: {out}");
892 assert!(out.contains("bitfield<3> level"));
893 }
894
895 #[test]
896 fn prints_bitmask() {
897 let out = print("bitmask P { READ, WRITE };");
898 assert!(out.contains("bitmask P"), "got: {out}");
899 assert!(out.contains("READ"));
900 assert!(out.contains("WRITE"));
901 }
902
903 #[test]
904 fn prints_value_box() {
905 let out = print("valuetype Name string;");
906 assert!(out.contains("valuetype Name string"), "got: {out}");
907 }
908
909 #[test]
910 fn prints_module_with_nested_struct() {
911 let out = print("module svc { struct Foo { long x; }; };");
912 assert!(out.contains("module svc"), "got: {out}");
913 assert!(out.contains("struct Foo"));
914 }
915
916 #[test]
917 fn prints_scoped_name() {
918 let out = print("typedef ::ns::T Alias;");
919 assert!(out.contains("::ns::T"), "got: {out}");
920 }
921
922 #[test]
923 fn prints_annotation_with_named_params() {
924 let out = print("struct S { @range(min=0, max=10) long x; };");
925 assert!(out.contains("@range(min=0, max=10)"), "got: {out}");
926 }
927}