compose_syntax/ast/
control_flow.rs1use crate::ast::macros::node;
2use crate::ast::{CodeBlock, Expr, Pattern};
3use crate::kind::SyntaxKind;
4use crate::SyntaxNode;
5
6node! {
7 struct Conditional
8}
9
10impl<'a> Conditional<'a> {
11 pub fn condition(self) -> Condition<'a> {
13 self.0.cast_first()
14 }
15
16 pub fn consequent(self) -> CodeBlock<'a> {
18 self.0.cast_first()
19 }
20
21 pub fn cond_alternates(self) -> impl DoubleEndedIterator<Item = ConditionalAlternate<'a>> {
23 self.0.children().filter_map(SyntaxNode::cast)
24 }
25
26 pub fn cond_else(self) -> Option<ConditionalElse<'a>> {
28 self.0.try_cast_last()
29 }
30}
31
32node! {
33 struct WhileLoop
34}
35
36impl<'a> WhileLoop<'a> {
37 pub fn condition(self) -> Condition<'a> {
38 self.0.cast_first()
39 }
40
41 pub fn body(self) -> CodeBlock<'a> {
42 self.0.cast_first()
43 }
44}
45
46node! {
47 struct ForLoop
48}
49
50impl<'a> ForLoop<'a> {
51 pub fn body(self) -> CodeBlock<'a> {
52 self.0.cast_last()
53 }
54
55 pub fn binding(self) -> Pattern<'a> {
56 self.0.cast_first()
57 }
58
59 pub fn iterable(self) -> Expr<'a> {
60 self.0
61 .children()
62 .skip_while(|n| n.kind() != SyntaxKind::In)
63 .find_map(SyntaxNode::cast)
64 .unwrap_or_default()
65 }
66}
67
68node! {
69 struct ConditionalAlternate
70}
71impl<'a> ConditionalAlternate<'a> {
72 pub fn condition(self) -> Condition<'a> {
73 self.0.cast_first()
74 }
75
76 pub fn consequent(self) -> CodeBlock<'a> {
77 self.0.cast_first()
78 }
79}
80
81node! {
82 struct ConditionalElse
83}
84
85impl<'a> ConditionalElse<'a> {
86 pub fn consequent(self) -> CodeBlock<'a> {
87 self.0.cast_first()
88 }
89}
90
91node! {
92 struct Condition
93}
94
95impl<'a> Condition<'a> {
96 pub fn expr(self) -> Expr<'a> {
97 self.0.cast_first()
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use crate::assert_ast;
105 use crate::ast::{FuncCall, Ident};
106 use crate::ast::Str;
107
108 #[test]
109 fn test_for_loop() {
110 assert_ast!(
111 r#"
112 for (c in "abc") {
113 println(c);
114 }
115 "#,
116 for_loop as ForLoop {
117 with binding: Ident = for_loop.binding() => {
118 assert_eq!(binding.get(), "c");
119 }
120 with iterable: Str = for_loop.iterable() => {
121 assert_eq!(iterable.get(), "abc");
122 }
123 with body: CodeBlock = for_loop.body() => {
124 body.statements() => [
125 call as FuncCall {
126 assert_eq!(call.to_text(), "println(c)");
127 }
128 ]
129 }
130 }
131 );
132 }
133
134 #[test]
135 fn test_while_loop() {
136 assert_ast!(
137 r#"
138 while (true) {
139 println("hello");
140 }
141 "#,
142 while_loop as WhileLoop {
143 with condition: Condition = while_loop.condition() => {
144 assert_eq!(condition.expr().to_text(), "true");
145 }
146 with body: CodeBlock = while_loop.body() => {
147 body.statements() => [
148 call as FuncCall {
149 assert_eq!(call.to_text(), "println(\"hello\")");
150 }
151 ]
152 }
153 }
154 )
155 }
156
157 #[test]
158 fn test_conditionals() {
159 assert_ast!(
160 r#"
161 if (true) {
162 println("hello");
163 } else if (false) {
164 println("bob");
165 } else {
166 println("world");
167 }
168 "#,
169 conditional as Conditional {
170 with condition: Condition = conditional.condition() => {
171 assert_eq!(condition.expr().to_text(), "true");
172 }
173 with consequent: CodeBlock = conditional.consequent() => {
174 consequent.statements() => [
175 call as FuncCall {
176 assert_eq!(call.to_text(), "println(\"hello\")");
177 }
178 ]
179 }
180 conditional.cond_alternates() => [
181 alternate as ConditionalAlternate {
182 with condition: Condition = alternate.condition() => {
183 assert_eq!(condition.expr().to_text(), "false");
184 }
185 with consequent: CodeBlock = alternate.consequent() => {
186 consequent.statements() => [
187 call as FuncCall {
188 assert_eq!(call.to_text(), "println(\"bob\")");
189 }
190 ]
191 }
192 }
193 ]
194 with alternate: ConditionalElse = conditional.cond_else().unwrap() => {
195 with consequent: CodeBlock = alternate.consequent() => {
196 consequent.statements() => [
197 call as FuncCall {
198 assert_eq!(call.to_text(), "println(\"world\")");
199 }
200 ]
201 }
202 }
203 }
204 )
205 }
206}