gobject_ast/model/expression/
mod.rs1mod alloc_call;
2mod assignment;
3mod binary;
4mod call;
5mod cast;
6mod conditional;
7mod field_access;
8mod identifier;
9mod initializer_list;
10mod literal;
11mod offsetof;
12mod sizeof;
13mod subscript;
14mod unary;
15mod update;
16
17use std::collections::HashMap;
18
19pub use alloc_call::AllocCallExpression;
20pub use assignment::Assignment;
21pub use binary::BinaryExpression;
22pub use call::CallExpression;
23pub use cast::CastExpression;
24pub use conditional::ConditionalExpression;
25pub use field_access::FieldAccessExpression;
26pub use identifier::IdentifierExpression;
27pub use initializer_list::{Designator, InitializerItem, InitializerListExpression};
28pub use literal::{
29 BooleanExpression, CharLiteralExpression, CommentExpression, GenericExpression, NullExpression,
30 NumberLiteralExpression, StringLiteralExpression,
31};
32pub use offsetof::{OffsetField, OffsetOfExpression};
33use serde::Serialize;
34pub use sizeof::{SizeofExpression, SizeofOperand};
35pub use subscript::SubscriptExpression;
36pub use unary::UnaryExpression;
37pub use update::UpdateExpression;
38
39use crate::model::{DefineValue, SourceLocation};
40
41#[derive(Debug, Clone, Serialize)]
42#[serde(rename_all = "snake_case")]
43pub enum Expression {
44 Call(CallExpression),
45 AllocCall(AllocCallExpression),
46 Assignment(Assignment),
47 Binary(BinaryExpression),
48 Unary(UnaryExpression),
49 Identifier(IdentifierExpression),
50 FieldAccess(FieldAccessExpression),
51 StringLiteral(StringLiteralExpression),
52 NumberLiteral(NumberLiteralExpression),
53 Null(NullExpression),
54 Boolean(BooleanExpression),
55 Cast(CastExpression),
56 Conditional(ConditionalExpression),
57 Sizeof(SizeofExpression),
58 Subscript(SubscriptExpression),
59 InitializerList(InitializerListExpression),
60 CharLiteral(CharLiteralExpression),
61 Update(UpdateExpression),
62 Comment(CommentExpression),
63 OffsetOf(OffsetOfExpression),
64 Generic(GenericExpression),
65}
66
67impl Expression {
68 pub fn location(&self) -> &SourceLocation {
69 match self {
70 Self::Call(c) => &c.location,
71 Self::AllocCall(a) => &a.location,
72 Self::Assignment(a) => &a.location,
73 Self::Binary(b) => &b.location,
74 Self::Unary(u) => &u.location,
75 Self::Identifier(i) => &i.location,
76 Self::FieldAccess(f) => &f.location,
77 Self::StringLiteral(s) => &s.location,
78 Self::NumberLiteral(n) => &n.location,
79 Self::Null(n) => &n.location,
80 Self::Boolean(b) => &b.location,
81 Self::Cast(c) => &c.location,
82 Self::Conditional(c) => &c.location,
83 Self::Sizeof(s) => &s.location,
84 Self::Subscript(s) => &s.location,
85 Self::InitializerList(i) => &i.location,
86 Self::CharLiteral(c) => &c.location,
87 Self::Update(u) => &u.location,
88 Self::Comment(c) => &c.location,
89 Self::OffsetOf(o) => &o.location,
90 Self::Generic(g) => &g.location,
91 }
92 }
93
94 pub fn is_falsy(&self) -> bool {
95 match self {
96 Self::Boolean(b) => !b.value,
97 Self::NumberLiteral(n) => n.value == "0",
98 Self::Identifier(id) => id.name == "FALSE",
99 _ => false,
100 }
101 }
102
103 pub fn is_truthy(&self) -> bool {
104 match self {
105 Self::Boolean(b) => b.value,
106 Self::NumberLiteral(n) => n.value == "1",
107 Self::Identifier(id) => id.name == "TRUE",
108 _ => false,
109 }
110 }
111
112 pub fn walk<'s, F>(&'s self, f: &mut F)
116 where
117 F: FnMut(&'s Self),
118 {
119 f(self);
120 match self {
121 Self::Call(call) => {
122 call.function.walk(f);
123 for arg in &call.arguments {
124 arg.walk(f);
125 }
126 }
127 Self::AllocCall(alloc) => {
128 alloc.function.walk(f);
129 for arg in &alloc.arguments {
130 arg.walk(f);
131 }
132 }
133 Self::Assignment(assign) => {
134 assign.lhs.walk(f);
135 assign.rhs.walk(f);
136 }
137 Self::Unary(unary) => {
138 unary.operand.walk(f);
139 }
140 Self::Binary(binary) => {
141 binary.left.walk(f);
142 binary.right.walk(f);
143 }
144 Self::Cast(cast) => {
145 cast.operand.walk(f);
146 }
147 Self::Conditional(cond) => {
148 cond.condition.walk(f);
149 cond.then_expr.walk(f);
150 cond.else_expr.walk(f);
151 }
152 Self::Subscript(subscript) => {
153 subscript.array.walk(f);
154 subscript.index.walk(f);
155 }
156 Self::Update(update) => {
157 update.operand.walk(f);
158 }
159 Self::FieldAccess(field) => {
160 field.base.walk(f);
161 }
162 Self::InitializerList(init) => {
163 for item in &init.items {
164 if let Some(Designator::Subscript(idx)) = &item.designator {
165 idx.walk(f);
166 }
167 item.value.walk(f);
168 }
169 }
170 Self::Identifier(_)
171 | Self::StringLiteral(_)
172 | Self::NumberLiteral(_)
173 | Self::Null(_)
174 | Self::Boolean(_)
175 | Self::Sizeof(_)
176 | Self::CharLiteral(_)
177 | Self::Comment(_)
178 | Self::OffsetOf(_)
179 | Self::Generic(_) => {}
180 }
181 }
182
183 pub fn extract_variable_name(&self) -> Option<&str> {
186 match self {
187 Self::Identifier(_) | Self::FieldAccess(_) => self.location().as_str(),
188 _ => None,
189 }
190 }
191
192 pub fn extract_identifier_name(&self) -> Option<&str> {
195 match self {
196 Self::Identifier(id) => Some(&id.name),
197 Self::Call(call) => call.get_arg(0)?.extract_identifier_name(),
198 Self::Cast(cast) => cast.operand.extract_identifier_name(),
199 _ => None,
200 }
201 }
202
203 pub fn is_null(&self) -> bool {
207 matches!(self, Self::Null(_)) || matches!(self, Self::Identifier(id) if id.name == "NULL")
208 }
209
210 pub fn is_zero(&self) -> bool {
212 matches!(self, Self::NumberLiteral(n) if n.value.trim() == "0")
213 }
214
215 pub fn is_string_literal(&self) -> bool {
217 matches!(self, Self::StringLiteral(_))
218 }
219
220 pub fn extract_string_value(&self) -> Option<String> {
223 match self {
224 Self::StringLiteral(lit) => Some(lit.value.trim_matches('"').to_string()),
225 Self::Call(call) => call.get_arg(0)?.extract_string_value(),
226 _ => None,
227 }
228 }
229
230 pub fn resolve_string_value(&self, defines: &HashMap<String, DefineValue>) -> Option<String> {
234 if let Some(s) = self.extract_string_value() {
235 return Some(s);
236 }
237 match self {
238 Self::Identifier(id) => match defines.get(&id.name)? {
239 DefineValue::StringLiteral(s) => Some(s.clone()),
240 _ => None,
241 },
242 Self::Call(call) => {
243 let arg = call.get_arg(0)?;
244 if let Self::Identifier(id) = arg {
245 match defines.get(&id.name)? {
246 DefineValue::StringLiteral(s) => Some(s.clone()),
247 _ => None,
248 }
249 } else {
250 None
251 }
252 }
253 _ => None,
254 }
255 }
256
257 pub fn is_string_or_macro_string(&self) -> bool {
259 self.extract_string_value().is_some()
260 }
261
262 pub fn contains_identifier(&self, name: &str) -> bool {
265 let mut found = false;
266 self.walk(&mut |e| {
267 if let Self::Identifier(id) = e
268 && id.name == name
269 {
270 found = true;
271 }
272 });
273 found
274 }
275
276 pub fn collect_identifiers(&self) -> Vec<String> {
279 let mut identifiers = Vec::new();
280 self.walk(&mut |e| {
281 if let Self::Identifier(id) = e {
282 identifiers.push(id.name.clone());
283 }
284 });
285 identifiers
286 }
287
288 pub fn is_call_to(&self, function_name: &str) -> bool {
290 matches!(self, Self::Call(call) if call.is_function(function_name))
291 }
292
293 pub fn is_call_to_any(&self, function_names: &[&str]) -> bool {
295 matches!(self, Self::Call(call) if call.function_name_str().is_some_and(|name| function_names.contains(&name)))
296 }
297}