gobject_ast/model/statement/
mod.rs1mod break_stmt;
2mod compound_stmt;
3mod continue_stmt;
4mod for_stmt;
5mod goto_stmt;
6mod if_stmt;
7mod labeled_stmt;
8mod return_stmt;
9mod switch_stmt;
10mod variable_decl;
11mod while_stmt;
12
13pub use break_stmt::BreakStatement;
14pub use compound_stmt::CompoundStatement;
15pub use continue_stmt::ContinueStatement;
16pub use for_stmt::{ForInit, ForStatement};
17pub use goto_stmt::GotoStatement;
18pub use if_stmt::IfStatement;
19pub use labeled_stmt::LabeledStatement;
20pub use return_stmt::ReturnStatement;
21use serde::Serialize;
22pub use switch_stmt::{CaseLabel, SwitchCase, SwitchStatement};
23pub use variable_decl::VariableDecl;
24pub use while_stmt::{DoWhileStatement, WhileStatement};
25
26use crate::model::{
27 Assignment, CallExpression, Comment, Expression, PreprocessorDirective, SourceLocation,
28};
29
30#[derive(Debug, Clone, Serialize)]
31#[serde(rename_all = "snake_case")]
32pub enum Statement {
33 Declaration(Box<VariableDecl>),
34 Expression(Box<Expression>),
35 If(IfStatement),
36 Return(ReturnStatement),
37 Goto(GotoStatement),
38 Labeled(LabeledStatement),
39 Compound(CompoundStatement),
40 Switch(SwitchStatement),
41 For(Box<ForStatement>),
42 While(WhileStatement),
43 DoWhile(DoWhileStatement),
44 Break(BreakStatement),
45 Continue(ContinueStatement),
46 Preprocessor(PreprocessorDirective),
47 Comment(Comment),
48}
49
50impl Statement {
51 pub fn walk<'s, F>(&'s self, f: &mut F)
55 where
56 F: FnMut(&'s Self),
57 {
58 f(self);
59 match self {
60 Self::If(if_stmt) => {
61 for stmt in &if_stmt.then_body {
62 stmt.walk(f);
63 }
64 if let Some(else_body) = &if_stmt.else_body {
65 for stmt in else_body {
66 stmt.walk(f);
67 }
68 }
69 }
70 Self::Compound(compound) => {
71 for stmt in &compound.statements {
72 stmt.walk(f);
73 }
74 }
75 Self::Labeled(labeled) => {
76 labeled.statement.walk(f);
77 }
78 Self::Switch(switch) => {
79 for case in &switch.cases {
80 for stmt in &case.body {
81 stmt.walk(f);
82 }
83 }
84 }
85 Self::For(for_stmt) => {
86 for stmt in &for_stmt.body {
87 stmt.walk(f);
88 }
89 }
90 Self::While(while_stmt) => {
91 for stmt in &while_stmt.body {
92 stmt.walk(f);
93 }
94 }
95 Self::DoWhile(do_while) => {
96 for stmt in &do_while.body {
97 stmt.walk(f);
98 }
99 }
100 Self::Declaration(_)
101 | Self::Expression(_)
102 | Self::Return(_)
103 | Self::Goto(_)
104 | Self::Break(_)
105 | Self::Continue(_)
106 | Self::Preprocessor(_)
107 | Self::Comment(_) => {}
108 }
109 }
110
111 pub fn for_each_child_block<F>(&self, mut f: F)
117 where
118 F: FnMut(&[Self]),
119 {
120 match self {
121 Self::If(if_stmt) => {
122 f(&if_stmt.then_body);
123 if let Some(else_body) = &if_stmt.else_body {
124 f(else_body);
125 }
126 }
127 Self::Compound(c) => f(&c.statements),
128 Self::Labeled(l) => f(std::slice::from_ref(&l.statement)),
129 Self::For(for_stmt) => f(&for_stmt.body),
130 Self::While(w) => f(&w.body),
131 Self::DoWhile(d) => f(&d.body),
132 Self::Switch(sw) => {
133 for case in &sw.cases {
134 f(&case.body);
135 }
136 }
137 Self::Declaration(_)
138 | Self::Expression(_)
139 | Self::Return(_)
140 | Self::Goto(_)
141 | Self::Break(_)
142 | Self::Continue(_)
143 | Self::Preprocessor(_)
144 | Self::Comment(_) => {}
145 }
146 }
147
148 pub fn visit_expressions<'s>(&'s self, f: &mut impl FnMut(&'s Expression)) {
153 match self {
154 Self::Expression(expr_stmt) => f(expr_stmt),
155 Self::Return(ret) => {
156 if let Some(v) = &ret.value {
157 f(v);
158 }
159 }
160 Self::Declaration(decl) => {
161 if let Some(init) = &decl.initializer {
162 f(init);
163 }
164 if let Some(size) = &decl.array_size {
165 f(size);
166 }
167 }
168 Self::If(if_stmt) => f(&if_stmt.condition),
169 Self::Switch(switch) => {
170 f(&switch.condition);
171 for case in &switch.cases {
172 if let Some(label_expr) = &case.label.value {
173 f(label_expr);
174 }
175 }
176 }
177 Self::For(for_stmt) => {
178 match &for_stmt.initializer {
179 Some(ForInit::Expr(init)) => f(init),
180 Some(ForInit::Decl(decl)) => {
181 if let Some(init) = &decl.initializer {
182 f(init);
183 }
184 }
185 None => {}
186 }
187 if let Some(cond) = &for_stmt.condition {
188 f(cond);
189 }
190 if let Some(update) = &for_stmt.update {
191 f(update);
192 }
193 }
194 Self::While(while_stmt) => f(&while_stmt.condition),
195 Self::DoWhile(do_while) => f(&do_while.condition),
196 Self::Goto(_)
197 | Self::Labeled(_)
198 | Self::Compound(_)
199 | Self::Break(_)
200 | Self::Continue(_)
201 | Self::Preprocessor(_)
202 | Self::Comment(_) => {}
203 }
204 }
205
206 pub fn location(&self) -> &SourceLocation {
207 match self {
208 Self::Declaration(d) => &d.location,
209 Self::Expression(e) => e.location(),
210 Self::If(i) => &i.location,
211 Self::Return(r) => &r.location,
212 Self::Goto(g) => &g.location,
213 Self::Labeled(l) => &l.location,
214 Self::Compound(c) => &c.location,
215 Self::Switch(s) => &s.location,
216 Self::For(f) => &f.location,
217 Self::While(w) => &w.location,
218 Self::DoWhile(d) => &d.location,
219 Self::Break(b) => &b.location,
220 Self::Continue(c) => &c.location,
221 Self::Preprocessor(p) => p.location(),
222 Self::Comment(c) => &c.location,
223 }
224 }
225
226 pub fn walk_expressions<'s, F>(&'s self, f: &mut F)
230 where
231 F: FnMut(&'s Expression),
232 {
233 self.walk(&mut |s| {
234 s.visit_expressions(f);
235 });
236 }
237
238 pub fn iter_switches<'s>(&'s self) -> impl Iterator<Item = &'s SwitchStatement> + 's {
240 let mut results: Vec<&'s SwitchStatement> = Vec::new();
241 self.walk(&mut |s| {
242 if let Self::Switch(sw) = s {
243 results.push(sw);
244 }
245 });
246 results.into_iter()
247 }
248
249 pub fn iter_if_statements<'s>(&'s self) -> impl Iterator<Item = &'s IfStatement> + 's {
251 let mut results: Vec<&'s IfStatement> = Vec::new();
252 self.walk(&mut |s| {
253 if let Self::If(if_stmt) = s {
254 results.push(if_stmt);
255 }
256 });
257 results.into_iter()
258 }
259
260 pub fn iter_declarations<'s>(&'s self) -> impl Iterator<Item = &'s VariableDecl> + 's {
263 let mut results: Vec<&'s VariableDecl> = Vec::new();
264 self.walk(&mut |s| {
265 if let Self::Declaration(decl) = s {
266 results.push(decl);
267 }
268 if let Self::For(for_stmt) = s
269 && let Some(ForInit::Decl(decl)) = &for_stmt.initializer
270 {
271 results.push(decl);
272 }
273 });
274 results.into_iter()
275 }
276
277 pub fn iter_returns<'s>(&'s self) -> impl Iterator<Item = &'s ReturnStatement> + 's {
279 let mut results: Vec<&'s ReturnStatement> = Vec::new();
280 self.walk(&mut |s| {
281 if let Self::Return(ret) = s {
282 results.push(ret);
283 }
284 });
285 results.into_iter()
286 }
287
288 pub fn iter_assignments<'s>(&'s self) -> impl Iterator<Item = &'s Assignment> + 's {
292 let mut results: Vec<&'s Assignment> = Vec::new();
293 self.walk(&mut |s| {
294 if let Self::Expression(expr_stmt) = s
295 && let Expression::Assignment(assign) = expr_stmt.as_ref()
296 {
297 results.push(assign);
298 }
299 });
300 results.into_iter()
301 }
302
303 pub fn iter_calls<'s>(&'s self) -> impl Iterator<Item = &'s CallExpression> + 's {
307 let mut exprs: Vec<&'s Expression> = Vec::new();
310 self.walk_expressions(&mut |expr| exprs.push(expr));
311
312 let mut results: Vec<&'s CallExpression> = Vec::new();
313 for expr in exprs {
314 expr.walk(&mut |e| {
315 if let Expression::Call(call) = e {
316 results.push(call);
317 }
318 });
319 }
320 results.into_iter()
321 }
322
323 pub fn extract_call(&self) -> Option<&CallExpression> {
326 if let Self::Expression(expr_stmt) = self
327 && let Expression::Call(call) = expr_stmt.as_ref()
328 {
329 return Some(call);
330 }
331 None
332 }
333
334 pub fn is_assignment_to<F>(&self, target_var: &str, value_check: F) -> bool
337 where
338 F: Fn(&Expression) -> bool,
339 {
340 if let Self::Expression(expr_stmt) = self
341 && let Expression::Assignment(assign) = expr_stmt.as_ref()
342 {
343 let lhs_text = assign.lhs.location().as_str().unwrap_or("");
344 return lhs_text.trim() == target_var.trim() && value_check(&assign.rhs);
345 }
346 false
347 }
348
349 pub fn extract_assignment(&self) -> Option<&Assignment> {
351 if let Self::Expression(expr_stmt) = self
352 && let Expression::Assignment(assign) = expr_stmt.as_ref()
353 {
354 return Some(assign);
355 }
356 None
357 }
358
359 pub fn is_null_assignment_to(&self, var_name: &str) -> bool {
361 self.is_assignment_to(var_name, Expression::is_null)
362 }
363
364 fn non_comments(stmts: &[Self]) -> Vec<&Self> {
365 stmts
366 .iter()
367 .filter(|s| !matches!(s, Self::Comment(_)))
368 .collect()
369 }
370
371 pub fn for_each_pair<F>(statements: &[Self], mut f: F)
373 where
374 F: FnMut(&Self, &Self),
375 {
376 let nc = Self::non_comments(statements);
377 for w in nc.windows(2) {
378 f(w[0], w[1]);
379 }
380 }
381
382 pub fn for_each_triple<F>(statements: &[Self], mut f: F)
384 where
385 F: FnMut(&Self, &Self, &Self),
386 {
387 let nc = Self::non_comments(statements);
388 for w in nc.windows(3) {
389 f(w[0], w[1], w[2]);
390 }
391 }
392
393 pub fn walk_pairs<F>(stmts: &[Self], f: &mut F)
397 where
398 F: FnMut(&Self, &Self),
399 {
400 let nc = Self::non_comments(stmts);
401 for w in nc.windows(2) {
402 f(w[0], w[1]);
403 }
404 for stmt in stmts {
405 match stmt {
406 Self::If(if_stmt) => {
407 Self::walk_pairs(&if_stmt.then_body, f);
408 if let Some(else_body) = &if_stmt.else_body {
409 Self::walk_pairs(else_body, f);
410 }
411 }
412 Self::Compound(c) => Self::walk_pairs(&c.statements, f),
413 Self::Labeled(l) => Self::walk_pairs(std::slice::from_ref(&l.statement), f),
414 Self::For(for_stmt) => Self::walk_pairs(&for_stmt.body, f),
415 Self::While(w) => Self::walk_pairs(&w.body, f),
416 Self::DoWhile(d) => Self::walk_pairs(&d.body, f),
417 Self::Switch(sw) => {
418 for case in &sw.cases {
419 Self::walk_pairs(&case.body, f);
420 }
421 }
422 Self::Declaration(_)
423 | Self::Expression(_)
424 | Self::Return(_)
425 | Self::Goto(_)
426 | Self::Break(_)
427 | Self::Continue(_)
428 | Self::Preprocessor(_)
429 | Self::Comment(_) => {}
430 }
431 }
432 }
433
434 pub fn walk_triples<F>(stmts: &[Self], f: &mut F)
437 where
438 F: FnMut(&Self, &Self, &Self),
439 {
440 let nc = Self::non_comments(stmts);
441 for w in nc.windows(3) {
442 f(w[0], w[1], w[2]);
443 }
444 for stmt in stmts {
445 match stmt {
446 Self::If(if_stmt) => {
447 Self::walk_triples(&if_stmt.then_body, f);
448 if let Some(else_body) = &if_stmt.else_body {
449 Self::walk_triples(else_body, f);
450 }
451 }
452 Self::Compound(c) => Self::walk_triples(&c.statements, f),
453 Self::Labeled(l) => Self::walk_triples(std::slice::from_ref(&l.statement), f),
454 Self::For(for_stmt) => Self::walk_triples(&for_stmt.body, f),
455 Self::While(w) => Self::walk_triples(&w.body, f),
456 Self::DoWhile(d) => Self::walk_triples(&d.body, f),
457 Self::Switch(sw) => {
458 for case in &sw.cases {
459 Self::walk_triples(&case.body, f);
460 }
461 }
462 Self::Declaration(_)
463 | Self::Expression(_)
464 | Self::Return(_)
465 | Self::Goto(_)
466 | Self::Break(_)
467 | Self::Continue(_)
468 | Self::Preprocessor(_)
469 | Self::Comment(_) => {}
470 }
471 }
472 }
473}