gobject_ast/model/expression/
mod.rs1mod assignment;
2mod binary;
3mod call;
4mod cast;
5mod conditional;
6mod field_access;
7mod identifier;
8mod initializer_list;
9mod literal;
10mod offsetof;
11mod sizeof;
12mod subscript;
13mod unary;
14mod update;
15
16pub use assignment::Assignment;
17pub use binary::BinaryExpression;
18pub use call::{Argument, CallExpression};
19pub use cast::CastExpression;
20pub use conditional::ConditionalExpression;
21pub use field_access::FieldAccessExpression;
22pub use identifier::IdentifierExpression;
23pub use initializer_list::{Designator, InitializerItem, InitializerListExpression};
24pub use literal::{
25 BooleanExpression, CharLiteralExpression, CommentExpression, GenericExpression, NullExpression,
26 NumberLiteralExpression, StringLiteralExpression,
27};
28pub use offsetof::{OffsetOfExpression, StructField};
29use serde::Serialize;
30pub use sizeof::{SizeofExpression, SizeofOperand};
31pub use subscript::SubscriptExpression;
32pub use unary::UnaryExpression;
33pub use update::UpdateExpression;
34
35use crate::model::SourceLocation;
36
37#[derive(Debug, Clone, Serialize)]
38#[serde(rename_all = "snake_case")]
39pub enum Expression {
40 Call(CallExpression),
41 Assignment(Assignment),
42 Binary(BinaryExpression),
43 Unary(UnaryExpression),
44 Identifier(IdentifierExpression),
45 FieldAccess(FieldAccessExpression),
46 StringLiteral(StringLiteralExpression),
47 NumberLiteral(NumberLiteralExpression),
48 Null(NullExpression),
49 Boolean(BooleanExpression),
50 Cast(CastExpression),
51 Conditional(ConditionalExpression),
52 Sizeof(SizeofExpression),
53 Subscript(SubscriptExpression),
54 InitializerList(InitializerListExpression),
55 CharLiteral(CharLiteralExpression),
56 Update(UpdateExpression),
57 Comment(CommentExpression),
58 OffsetOf(OffsetOfExpression),
59 Generic(GenericExpression),
60}
61
62impl Expression {
63 pub fn location(&self) -> &SourceLocation {
64 match self {
65 Self::Call(c) => &c.location,
66 Self::Assignment(a) => &a.location,
67 Self::Binary(b) => &b.location,
68 Self::Unary(u) => &u.location,
69 Self::Identifier(i) => &i.location,
70 Self::FieldAccess(f) => &f.location,
71 Self::StringLiteral(s) => &s.location,
72 Self::NumberLiteral(n) => &n.location,
73 Self::Null(n) => &n.location,
74 Self::Boolean(b) => &b.location,
75 Self::Cast(c) => &c.location,
76 Self::Conditional(c) => &c.location,
77 Self::Sizeof(s) => &s.location,
78 Self::Subscript(s) => &s.location,
79 Self::InitializerList(i) => &i.location,
80 Self::CharLiteral(c) => &c.location,
81 Self::Update(u) => &u.location,
82 Self::Comment(c) => &c.location,
83 Self::OffsetOf(o) => &o.location,
84 Self::Generic(g) => &g.location,
85 }
86 }
87
88 pub fn to_source_string<'a>(&self, source: &'a [u8]) -> Option<&'a str> {
90 let loc = self.location();
91 std::str::from_utf8(&source[loc.start_byte..loc.end_byte]).ok()
92 }
93
94 pub fn walk<'s, F>(&'s self, f: &mut F)
98 where
99 F: FnMut(&'s Self),
100 {
101 f(self);
102 match self {
103 Self::Call(call) => {
104 call.function.walk(f);
105 for arg in &call.arguments {
106 let Argument::Expression(e) = arg;
107 e.walk(f);
108 }
109 }
110 Self::Assignment(assign) => {
111 assign.lhs.walk(f);
112 assign.rhs.walk(f);
113 }
114 Self::Unary(unary) => {
115 unary.operand.walk(f);
116 }
117 Self::Binary(binary) => {
118 binary.left.walk(f);
119 binary.right.walk(f);
120 }
121 Self::Cast(cast) => {
122 cast.operand.walk(f);
123 }
124 Self::Conditional(cond) => {
125 cond.condition.walk(f);
126 cond.then_expr.walk(f);
127 cond.else_expr.walk(f);
128 }
129 Self::Subscript(subscript) => {
130 subscript.array.walk(f);
131 subscript.index.walk(f);
132 }
133 Self::Update(update) => {
134 update.operand.walk(f);
135 }
136 Self::FieldAccess(field) => {
137 field.base.walk(f);
138 }
139 Self::InitializerList(init) => {
140 for item in &init.items {
141 if let Some(Designator::Subscript(idx)) = &item.designator {
142 idx.walk(f);
143 }
144 item.value.walk(f);
145 }
146 }
147 Self::Identifier(_)
148 | Self::StringLiteral(_)
149 | Self::NumberLiteral(_)
150 | Self::Null(_)
151 | Self::Boolean(_)
152 | Self::Sizeof(_)
153 | Self::CharLiteral(_)
154 | Self::Comment(_)
155 | Self::OffsetOf(_)
156 | Self::Generic(_) => {}
157 }
158 }
159
160 pub fn extract_variable_name<'a>(&self, source: &'a [u8]) -> Option<&'a str> {
163 match self {
164 Self::Identifier(_) | Self::FieldAccess(_) => self.location().as_str(source),
165 _ => None,
166 }
167 }
168
169 pub fn is_null(&self) -> bool {
173 matches!(self, Self::Null(_)) || matches!(self, Self::Identifier(id) if id.name == "NULL")
174 }
175
176 pub fn is_zero(&self) -> bool {
178 matches!(self, Self::NumberLiteral(n) if n.value.trim() == "0")
179 }
180
181 pub fn is_string_literal(&self) -> bool {
183 matches!(self, Self::StringLiteral(_))
184 }
185
186 pub fn extract_string_value(&self) -> Option<String> {
189 match self {
190 Self::StringLiteral(lit) => Some(lit.value.trim_matches('"').to_string()),
191 _ => None,
192 }
193 }
194
195 pub fn is_string_or_macro_string(&self) -> bool {
197 self.extract_string_value().is_some()
198 }
199
200 pub fn contains_identifier(&self, name: &str) -> bool {
203 let mut found = false;
204 self.walk(&mut |e| {
205 if let Self::Identifier(id) = e
206 && id.name == name
207 {
208 found = true;
209 }
210 });
211 found
212 }
213
214 pub fn collect_identifiers(&self) -> Vec<String> {
217 let mut identifiers = Vec::new();
218 self.walk(&mut |e| {
219 if let Self::Identifier(id) = e {
220 identifiers.push(id.name.clone());
221 }
222 });
223 identifiers
224 }
225
226 pub fn is_call_to(&self, function_name: &str) -> bool {
228 matches!(self, Self::Call(call) if call.is_function(function_name))
229 }
230
231 pub fn is_call_to_any(&self, function_names: &[&str]) -> bool {
233 matches!(self, Self::Call(call) if call.function_name_str().is_some_and(|name| function_names.contains(&name)))
234 }
235}