1use super::syntax::*;
2use crate::span::Spanned;
3
4impl TranslationUnit {
5 pub fn new() -> Self {
7 Self::default()
8 }
9
10 pub fn remove_voids(&mut self) {
12 self.global_declarations
13 .retain_mut(|decl| match decl.node() {
14 GlobalDeclaration::Void => false,
15 _ => {
16 decl.remove_voids();
17 true
18 }
19 })
20 }
21}
22
23#[cfg(feature = "imports")]
24impl ModulePath {
25 pub fn new(origin: PathOrigin, components: Vec<String>) -> Self {
29 Self { origin, components }
30 }
31
32 pub fn new_root() -> Self {
38 Self::new(PathOrigin::Absolute, vec![])
39 }
40
41 pub fn from_path(path: impl AsRef<std::path::Path>) -> Self {
54 use std::path::Component;
55 let path = path.as_ref().with_extension("");
56 let mut parts = path.components().peekable();
57
58 let origin = match parts.next() {
59 Some(Component::Prefix(_)) => panic!("path starts with a Windows prefix"),
60 Some(Component::RootDir) => PathOrigin::Absolute,
61 Some(Component::CurDir) => PathOrigin::Relative(0),
62 Some(Component::ParentDir) => {
63 let mut n = 1;
64 while let Some(&Component::ParentDir) = parts.peek() {
65 n += 1;
66 parts.next().unwrap();
67 }
68 PathOrigin::Relative(n)
69 }
70 Some(Component::Normal(name)) => {
71 PathOrigin::Package(name.to_string_lossy().to_string())
72 }
73 None => panic!("path is empty"),
74 };
75
76 let components = parts
77 .map(|part| match part {
78 Component::Normal(name) => name.to_string_lossy().to_string(),
79 _ => panic!("unexpected path component"),
80 })
81 .collect::<Vec<_>>();
82
83 Self { origin, components }
84 }
85
86 pub fn to_path_buf(&self) -> std::path::PathBuf {
92 use std::path::PathBuf;
93 let mut fs_path = match &self.origin {
94 PathOrigin::Absolute => PathBuf::from("/"),
95 PathOrigin::Relative(0) => PathBuf::from("."),
96 PathOrigin::Relative(n) => PathBuf::from_iter((0..*n).map(|_| "..")),
97 PathOrigin::Package(name) => PathBuf::from(name),
98 };
99 fs_path.extend(&self.components);
100 fs_path
101 }
102
103 pub fn push(&mut self, item: &str) {
107 self.components.push(item.to_string());
108 }
109
110 pub fn first(&self) -> Option<&str> {
112 self.components.first().map(String::as_str)
113 }
114
115 pub fn last(&self) -> Option<&str> {
117 self.components.last().map(String::as_str)
118 }
119
120 pub fn join(mut self, suffix: impl IntoIterator<Item = String>) -> Self {
122 self.components.extend(suffix);
123 self
124 }
125
126 pub fn join_path(&self, suffix: &Self) -> Self {
137 match suffix.origin {
138 PathOrigin::Absolute => {
139 match self.origin {
140 PathOrigin::Absolute | PathOrigin::Relative(_) => suffix.clone(),
141 PathOrigin::Package(_) => {
142 let origin = self.origin.clone();
144 let components = suffix.components.clone();
145 Self { origin, components }
146 }
147 }
148 }
149 PathOrigin::Relative(n) => {
150 let to_keep = self.components.len().saturating_sub(n);
151 let components = self
152 .components
153 .iter()
154 .take(to_keep)
155 .chain(&suffix.components)
156 .cloned()
157 .collect::<Vec<_>>();
158 let origin = match self.origin {
159 PathOrigin::Absolute | PathOrigin::Package(_) => self.origin.clone(),
160 PathOrigin::Relative(m) => PathOrigin::Relative(m + n - to_keep),
161 };
162 Self { origin, components }
163 }
164 PathOrigin::Package(ref suffix_pkg) => {
165 match &self.origin {
166 PathOrigin::Absolute | PathOrigin::Relative(_) => suffix.clone(),
167 PathOrigin::Package(self_pkg) => {
168 let origin = PathOrigin::Package(format!("{self_pkg}/{suffix_pkg}"));
171 let components = suffix.components.clone();
172 Self { origin, components }
173 }
174 }
175 }
176 }
177 }
178
179 pub fn starts_with(&self, prefix: &Self) -> bool {
181 self.origin == prefix.origin
182 && self.components.len() >= prefix.components.len()
183 && prefix
184 .components
185 .iter()
186 .zip(&self.components)
187 .all(|(a, b)| a == b)
188 }
189
190 pub fn is_root(&self) -> bool {
194 self.origin.is_absolute() && self.components.is_empty()
195 }
196}
197
198#[cfg(feature = "imports")]
199#[test]
200fn test_module_path_join() {
201 use std::str::FromStr;
202 let cases = [
204 ("package::m1", "package::foo", "package::foo"),
205 ("package::m1", "self::foo", "package::m1::foo"),
206 ("package::m1", "super::foo", "package::foo"),
207 ("pkg::m1::m2", "package::foo", "pkg::foo"),
208 ("pkg::m1::m2", "self::foo", "pkg::m1::m2::foo"),
209 ("pkg::m1::m2", "super::foo", "pkg::m1::foo"),
210 ("pkg::m1", "super::super::foo", "pkg::foo"),
211 ("super", "super::foo", "super::super::foo"),
212 ("super", "self::foo", "super::foo"),
213 ("self", "super::foo", "super::foo"),
214 ];
215
216 for (parent, child, expect) in cases {
217 let parent = ModulePath::from_str(parent).unwrap();
218 let child = ModulePath::from_str(child).unwrap();
219 let expect = ModulePath::from_str(expect).unwrap();
220 println!("testing join_paths({parent}, {child}) -> {expect}");
221 assert_eq!(parent.join_path(&child), expect);
222 }
223}
224
225#[cfg(feature = "imports")]
226#[derive(Clone, Copy, PartialEq, Eq, Debug, thiserror::Error)]
227pub enum ModulePathParseError {
228 #[error("module name cannot be empty")]
229 Empty,
230 #[error("`package` must be a prefix of the module path")]
231 MisplacedPackage,
232 #[error("`self` must be a prefix of the module path")]
233 MisplacedSelf,
234 #[error("`super` must be a prefix of the module path")]
235 MisplacedSuper,
236}
237
238#[cfg(feature = "imports")]
239impl std::str::FromStr for ModulePath {
240 type Err = ModulePathParseError;
241
242 fn from_str(s: &str) -> Result<Self, Self::Err> {
247 let mut parts = s.split("::").peekable();
248
249 let origin = match parts.next() {
250 Some("package") => PathOrigin::Absolute,
251 Some("self") => PathOrigin::Relative(0),
252 Some("super") => {
253 let mut n = 1;
254 while let Some(&"super") = parts.peek() {
255 n += 1;
256 parts.next().unwrap();
257 }
258 PathOrigin::Relative(n)
259 }
260 Some("") | None => return Err(ModulePathParseError::Empty),
261 Some(name) => PathOrigin::Package(name.to_string()),
262 };
263
264 let components = parts
265 .map(|part| match part {
266 "package" => Err(ModulePathParseError::MisplacedPackage),
267 "self" => Err(ModulePathParseError::MisplacedSelf),
268 "super" => Err(ModulePathParseError::MisplacedSuper),
269 _ => Ok(part.to_string()),
270 })
271 .collect::<Result<Vec<_>, _>>()?;
272
273 Ok(Self { origin, components })
274 }
275}
276
277#[cfg(feature = "imports")]
278#[test]
279fn test_module_path_fromstr() {
280 use std::str::FromStr;
281
282 let ok_cases = [
283 ("self", ModulePath::new(PathOrigin::Relative(0), vec![])),
284 ("super", ModulePath::new(PathOrigin::Relative(1), vec![])),
285 ("package", ModulePath::new(PathOrigin::Absolute, vec![])),
286 (
287 "a",
288 ModulePath::new(PathOrigin::Package("a".to_string()), vec![]),
289 ),
290 (
291 "super::super::a",
292 ModulePath::new(PathOrigin::Relative(2), vec!["a".to_string()]),
293 ),
294 ];
295 let err_cases = [
296 ("", ModulePathParseError::Empty),
297 ("a::super", ModulePathParseError::MisplacedSuper),
298 ("super::self", ModulePathParseError::MisplacedSelf),
299 ("self::package", ModulePathParseError::MisplacedPackage),
300 ];
301
302 for (s, m) in ok_cases {
303 assert_eq!(ModulePath::from_str(s), Ok(m))
304 }
305 for (s, e) in err_cases {
306 assert_eq!(ModulePath::from_str(s), Err(e))
307 }
308}
309
310impl GlobalDeclaration {
311 pub fn remove_voids(&mut self) {
313 if let GlobalDeclaration::Function(decl) = self {
314 decl.body.remove_voids();
315 }
316 }
317}
318
319impl TypeAlias {
320 pub fn new(ident: Ident, ty: TypeExpression) -> Self {
321 Self {
322 #[cfg(feature = "attributes")]
323 attributes: Default::default(),
324 ident,
325 ty,
326 }
327 }
328}
329
330impl Struct {
331 pub fn new(ident: Ident) -> Self {
332 Self {
333 #[cfg(feature = "attributes")]
334 attributes: Default::default(),
335 ident,
336 members: Default::default(),
337 }
338 }
339}
340
341impl StructMember {
342 pub fn new(ident: Ident, ty: TypeExpression) -> Self {
343 Self {
344 attributes: Default::default(),
345 ident,
346 ty,
347 }
348 }
349}
350
351impl Function {
352 pub fn new(ident: Ident) -> Self {
353 Self {
354 attributes: Default::default(),
355 ident,
356 parameters: Default::default(),
357 return_attributes: Default::default(),
358 return_type: Default::default(),
359 body: Default::default(),
360 }
361 }
362}
363
364impl FormalParameter {
365 pub fn new(ident: Ident, ty: TypeExpression) -> Self {
366 Self {
367 attributes: Default::default(),
368 ident,
369 ty,
370 }
371 }
372}
373
374impl ConstAssert {
375 pub fn new(expression: Expression) -> Self {
376 Self {
377 #[cfg(feature = "attributes")]
378 attributes: Default::default(),
379 expression: expression.into(),
380 }
381 }
382}
383
384impl TypeExpression {
385 pub fn new(ident: Ident) -> Self {
387 Self {
388 #[cfg(feature = "imports")]
389 path: None,
390 ident,
391 template_args: None,
392 }
393 }
394}
395
396impl CompoundStatement {
397 pub fn remove_voids(&mut self) {
399 self.statements.retain_mut(|stmt| match stmt.node_mut() {
400 Statement::Void => false,
401 _ => {
402 stmt.remove_voids();
403 true
404 }
405 })
406 }
407}
408
409impl Statement {
410 pub fn remove_voids(&mut self) {
412 match self {
413 Statement::Compound(stmt) => {
414 stmt.remove_voids();
415 }
416 Statement::If(stmt) => {
417 stmt.if_clause.body.remove_voids();
418 for clause in &mut stmt.else_if_clauses {
419 clause.body.remove_voids();
420 }
421 if let Some(clause) = &mut stmt.else_clause {
422 clause.body.remove_voids();
423 }
424 }
425 Statement::Switch(stmt) => stmt
426 .clauses
427 .iter_mut()
428 .for_each(|clause| clause.body.remove_voids()),
429 Statement::Loop(stmt) => stmt.body.remove_voids(),
430 Statement::For(stmt) => stmt.body.remove_voids(),
431 Statement::While(stmt) => stmt.body.remove_voids(),
432 _ => (),
433 }
434 }
435}
436
437impl AccessMode {
438 pub fn is_read(&self) -> bool {
440 matches!(self, Self::Read | Self::ReadWrite)
441 }
442 pub fn is_write(&self) -> bool {
444 matches!(self, Self::Write | Self::ReadWrite)
445 }
446}
447
448impl From<Ident> for TypeExpression {
449 fn from(ident: Ident) -> Self {
450 Self::new(ident)
451 }
452}
453
454impl From<ExpressionNode> for ReturnStatement {
455 fn from(expression: ExpressionNode) -> Self {
456 Self {
457 #[cfg(feature = "attributes")]
458 attributes: Default::default(),
459 expression: Some(expression),
460 }
461 }
462}
463impl From<Expression> for ReturnStatement {
464 fn from(expression: Expression) -> Self {
465 Self::from(ExpressionNode::from(expression))
466 }
467}
468
469impl From<FunctionCall> for FunctionCallStatement {
470 fn from(call: FunctionCall) -> Self {
471 Self {
472 #[cfg(feature = "attributes")]
473 attributes: Default::default(),
474 call,
475 }
476 }
477}
478
479macro_rules! impl_transitive_from {
483 ($from:ident => $middle:ident => $into:ident) => {
484 impl From<$from> for $into {
485 fn from(value: $from) -> Self {
486 $into::from($middle::from(value))
487 }
488 }
489 };
490}
491
492impl_transitive_from!(bool => LiteralExpression => Expression);
493impl_transitive_from!(i64 => LiteralExpression => Expression);
494impl_transitive_from!(f64 => LiteralExpression => Expression);
495impl_transitive_from!(i32 => LiteralExpression => Expression);
496impl_transitive_from!(u32 => LiteralExpression => Expression);
497impl_transitive_from!(f32 => LiteralExpression => Expression);
498impl_transitive_from!(Ident => TypeExpression => Expression);
499
500impl GlobalDeclaration {
501 pub fn ident(&self) -> Option<&Ident> {
503 match self {
504 GlobalDeclaration::Void => None,
505 GlobalDeclaration::Declaration(decl) => Some(&decl.ident),
506 GlobalDeclaration::TypeAlias(decl) => Some(&decl.ident),
507 GlobalDeclaration::Struct(decl) => Some(&decl.ident),
508 GlobalDeclaration::Function(decl) => Some(&decl.ident),
509 GlobalDeclaration::ConstAssert(_) => None,
510 }
511 }
512 pub fn ident_mut(&mut self) -> Option<&mut Ident> {
514 match self {
515 GlobalDeclaration::Void => None,
516 GlobalDeclaration::Declaration(decl) => Some(&mut decl.ident),
517 GlobalDeclaration::TypeAlias(decl) => Some(&mut decl.ident),
518 GlobalDeclaration::Struct(decl) => Some(&mut decl.ident),
519 GlobalDeclaration::Function(decl) => Some(&mut decl.ident),
520 GlobalDeclaration::ConstAssert(_) => None,
521 }
522 }
523}
524
525pub trait Decorated {
527 fn attributes(&self) -> &[AttributeNode];
529 fn attributes_mut(&mut self) -> &mut [AttributeNode];
531 fn contains_attribute(&self, attribute: &Attribute) -> bool {
533 self.attributes().iter().any(|v| v.node() == attribute)
534 }
535 fn retain_attributes_mut<F>(&mut self, f: F)
537 where
538 F: FnMut(&mut Attribute) -> bool;
539}
540
541impl<T: Decorated> Decorated for Spanned<T> {
542 fn attributes(&self) -> &[AttributeNode] {
543 self.node().attributes()
544 }
545
546 fn attributes_mut(&mut self) -> &mut [AttributeNode] {
547 self.node_mut().attributes_mut()
548 }
549
550 fn retain_attributes_mut<F>(&mut self, mut f: F)
551 where
552 F: FnMut(&mut Attribute) -> bool,
553 {
554 self.node_mut().retain_attributes_mut(|v| f(v))
555 }
556}
557
558macro_rules! impl_decorated_struct {
559 ($ty:ty) => {
560 impl Decorated for $ty {
561 fn attributes(&self) -> &[AttributeNode] {
562 &self.attributes
563 }
564 fn attributes_mut(&mut self) -> &mut [AttributeNode] {
565 &mut self.attributes
566 }
567 fn retain_attributes_mut<F>(&mut self, mut f: F)
568 where
569 F: FnMut(&mut Attribute) -> bool,
570 {
571 self.attributes.retain_mut(|v| f(v))
572 }
573 }
574 };
575}
576
577#[cfg(all(feature = "imports", feature = "attributes"))]
578impl_decorated_struct!(ImportStatement);
579
580#[cfg(feature = "attributes")]
581impl Decorated for GlobalDirective {
582 fn attributes(&self) -> &[AttributeNode] {
583 match self {
584 GlobalDirective::Diagnostic(directive) => &directive.attributes,
585 GlobalDirective::Enable(directive) => &directive.attributes,
586 GlobalDirective::Requires(directive) => &directive.attributes,
587 }
588 }
589
590 fn attributes_mut(&mut self) -> &mut [AttributeNode] {
591 match self {
592 GlobalDirective::Diagnostic(directive) => &mut directive.attributes,
593 GlobalDirective::Enable(directive) => &mut directive.attributes,
594 GlobalDirective::Requires(directive) => &mut directive.attributes,
595 }
596 }
597
598 fn retain_attributes_mut<F>(&mut self, mut f: F)
599 where
600 F: FnMut(&mut Attribute) -> bool,
601 {
602 match self {
603 GlobalDirective::Diagnostic(directive) => directive.attributes.retain_mut(|v| f(v)),
604 GlobalDirective::Enable(directive) => directive.attributes.retain_mut(|v| f(v)),
605 GlobalDirective::Requires(directive) => directive.attributes.retain_mut(|v| f(v)),
606 }
607 }
608}
609
610#[cfg(feature = "attributes")]
611impl_decorated_struct!(DiagnosticDirective);
612
613#[cfg(feature = "attributes")]
614impl_decorated_struct!(EnableDirective);
615
616#[cfg(feature = "attributes")]
617impl_decorated_struct!(RequiresDirective);
618
619#[cfg(feature = "attributes")]
620impl Decorated for GlobalDeclaration {
621 fn attributes(&self) -> &[AttributeNode] {
622 match self {
623 GlobalDeclaration::Void => &[],
624 GlobalDeclaration::Declaration(decl) => &decl.attributes,
625 GlobalDeclaration::TypeAlias(decl) => &decl.attributes,
626 GlobalDeclaration::Struct(decl) => &decl.attributes,
627 GlobalDeclaration::Function(decl) => &decl.attributes,
628 GlobalDeclaration::ConstAssert(decl) => &decl.attributes,
629 }
630 }
631
632 fn attributes_mut(&mut self) -> &mut [AttributeNode] {
633 match self {
634 GlobalDeclaration::Void => &mut [],
635 GlobalDeclaration::Declaration(decl) => &mut decl.attributes,
636 GlobalDeclaration::TypeAlias(decl) => &mut decl.attributes,
637 GlobalDeclaration::Struct(decl) => &mut decl.attributes,
638 GlobalDeclaration::Function(decl) => &mut decl.attributes,
639 GlobalDeclaration::ConstAssert(decl) => &mut decl.attributes,
640 }
641 }
642
643 fn retain_attributes_mut<F>(&mut self, mut f: F)
644 where
645 F: FnMut(&mut Attribute) -> bool,
646 {
647 match self {
648 GlobalDeclaration::Void => {}
649 GlobalDeclaration::Declaration(decl) => decl.attributes.retain_mut(|v| f(v)),
650 GlobalDeclaration::TypeAlias(decl) => decl.attributes.retain_mut(|v| f(v)),
651 GlobalDeclaration::Struct(decl) => decl.attributes.retain_mut(|v| f(v)),
652 GlobalDeclaration::Function(decl) => decl.attributes.retain_mut(|v| f(v)),
653 GlobalDeclaration::ConstAssert(decl) => decl.attributes.retain_mut(|v| f(v)),
654 }
655 }
656}
657
658impl_decorated_struct!(Declaration);
659
660#[cfg(feature = "attributes")]
661impl_decorated_struct!(TypeAlias);
662
663#[cfg(feature = "attributes")]
664impl_decorated_struct!(Struct);
665
666impl_decorated_struct!(StructMember);
667
668impl_decorated_struct!(Function);
669
670impl_decorated_struct!(FormalParameter);
671
672#[cfg(feature = "attributes")]
673impl_decorated_struct!(ConstAssert);
674
675#[cfg(feature = "attributes")]
676impl Decorated for Statement {
677 fn attributes(&self) -> &[AttributeNode] {
678 match self {
679 Statement::Void => &[],
680 Statement::Compound(stmt) => &stmt.attributes,
681 Statement::Assignment(stmt) => &stmt.attributes,
682 Statement::Increment(stmt) => &stmt.attributes,
683 Statement::Decrement(stmt) => &stmt.attributes,
684 Statement::If(stmt) => &stmt.attributes,
685 Statement::Switch(stmt) => &stmt.attributes,
686 Statement::Loop(stmt) => &stmt.attributes,
687 Statement::For(stmt) => &stmt.attributes,
688 Statement::While(stmt) => &stmt.attributes,
689 Statement::Break(stmt) => &stmt.attributes,
690 Statement::Continue(stmt) => &stmt.attributes,
691 Statement::Return(stmt) => &stmt.attributes,
692 Statement::Discard(stmt) => &stmt.attributes,
693 Statement::FunctionCall(stmt) => &stmt.attributes,
694 Statement::ConstAssert(stmt) => &stmt.attributes,
695 Statement::Declaration(stmt) => &stmt.attributes,
696 }
697 }
698
699 fn attributes_mut(&mut self) -> &mut [AttributeNode] {
700 match self {
701 Statement::Void => &mut [],
702 Statement::Compound(stmt) => &mut stmt.attributes,
703 Statement::Assignment(stmt) => &mut stmt.attributes,
704 Statement::Increment(stmt) => &mut stmt.attributes,
705 Statement::Decrement(stmt) => &mut stmt.attributes,
706 Statement::If(stmt) => &mut stmt.attributes,
707 Statement::Switch(stmt) => &mut stmt.attributes,
708 Statement::Loop(stmt) => &mut stmt.attributes,
709 Statement::For(stmt) => &mut stmt.attributes,
710 Statement::While(stmt) => &mut stmt.attributes,
711 Statement::Break(stmt) => &mut stmt.attributes,
712 Statement::Continue(stmt) => &mut stmt.attributes,
713 Statement::Return(stmt) => &mut stmt.attributes,
714 Statement::Discard(stmt) => &mut stmt.attributes,
715 Statement::FunctionCall(stmt) => &mut stmt.attributes,
716 Statement::ConstAssert(stmt) => &mut stmt.attributes,
717 Statement::Declaration(stmt) => &mut stmt.attributes,
718 }
719 }
720
721 fn retain_attributes_mut<F>(&mut self, mut f: F)
722 where
723 F: FnMut(&mut Attribute) -> bool,
724 {
725 match self {
726 Statement::Void => {}
727 Statement::Compound(stmt) => stmt.attributes.retain_mut(|v| f(v)),
728 Statement::Assignment(stmt) => stmt.attributes.retain_mut(|v| f(v)),
729 Statement::Increment(stmt) => stmt.attributes.retain_mut(|v| f(v)),
730 Statement::Decrement(stmt) => stmt.attributes.retain_mut(|v| f(v)),
731 Statement::If(stmt) => stmt.attributes.retain_mut(|v| f(v)),
732 Statement::Switch(stmt) => stmt.attributes.retain_mut(|v| f(v)),
733 Statement::Loop(stmt) => stmt.attributes.retain_mut(|v| f(v)),
734 Statement::For(stmt) => stmt.attributes.retain_mut(|v| f(v)),
735 Statement::While(stmt) => stmt.attributes.retain_mut(|v| f(v)),
736 Statement::Break(stmt) => stmt.attributes.retain_mut(|v| f(v)),
737 Statement::Continue(stmt) => stmt.attributes.retain_mut(|v| f(v)),
738 Statement::Return(stmt) => stmt.attributes.retain_mut(|v| f(v)),
739 Statement::Discard(stmt) => stmt.attributes.retain_mut(|v| f(v)),
740 Statement::FunctionCall(stmt) => stmt.attributes.retain_mut(|v| f(v)),
741 Statement::ConstAssert(stmt) => stmt.attributes.retain_mut(|v| f(v)),
742 Statement::Declaration(stmt) => stmt.attributes.retain_mut(|v| f(v)),
743 }
744 }
745}
746
747impl_decorated_struct!(CompoundStatement);
748
749#[cfg(feature = "attributes")]
750impl_decorated_struct!(AssignmentStatement);
751
752#[cfg(feature = "attributes")]
753impl_decorated_struct!(IncrementStatement);
754
755#[cfg(feature = "attributes")]
756impl_decorated_struct!(DecrementStatement);
757
758impl_decorated_struct!(IfStatement);
759
760#[cfg(feature = "attributes")]
761impl_decorated_struct!(ElseIfClause);
762
763#[cfg(feature = "attributes")]
764impl_decorated_struct!(ElseClause);
765
766impl_decorated_struct!(SwitchStatement);
767
768#[cfg(feature = "attributes")]
769impl_decorated_struct!(SwitchClause);
770
771impl_decorated_struct!(LoopStatement);
772
773#[cfg(feature = "attributes")]
774impl_decorated_struct!(ContinuingStatement);
775
776#[cfg(feature = "attributes")]
777impl_decorated_struct!(BreakIfStatement);
778
779impl_decorated_struct!(ForStatement);
780
781impl_decorated_struct!(WhileStatement);
782
783#[cfg(feature = "attributes")]
784impl_decorated_struct!(BreakStatement);
785
786#[cfg(feature = "attributes")]
787impl_decorated_struct!(ContinueStatement);
788
789#[cfg(feature = "attributes")]
790impl_decorated_struct!(ReturnStatement);
791
792#[cfg(feature = "attributes")]
793impl_decorated_struct!(DiscardStatement);
794
795#[cfg(feature = "attributes")]
796impl_decorated_struct!(FunctionCallStatement);