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