ghostscope_compiler/script/
ast.rs1#[derive(Debug, Clone)]
2pub enum Expr {
3 Int(i64),
4 Float(f64),
5 String(String),
6 Bool(bool),
7 UnaryNot(Box<Expr>),
8 UnaryBitNot(Box<Expr>),
9 Variable(String),
10 MemberAccess(Box<Expr>, String), PointerDeref(Box<Expr>), AddressOf(Box<Expr>), ArrayAccess(Box<Expr>, Box<Expr>), Cast {
15 expr: Box<Expr>,
16 target_type: String,
17 },
18 ChainAccess(Vec<String>), SpecialVar(String), BuiltinCall {
22 name: String,
23 args: Vec<Expr>,
24 },
25 BinaryOp {
26 left: Box<Expr>,
27 op: BinaryOp,
28 right: Box<Expr>,
29 },
30}
31
32#[derive(Debug, Clone, PartialEq)]
33pub enum BinaryOp {
34 Add,
35 Subtract,
36 Multiply,
37 Divide,
38 Modulo,
39 BitAnd,
41 BitXor,
42 BitOr,
43 ShiftLeft,
44 ShiftRight,
45 Equal,
47 NotEqual,
48 LessThan,
49 LessEqual,
50 GreaterThan,
51 GreaterEqual,
52 LogicalAnd,
54 LogicalOr,
55}
56
57#[derive(Debug, Clone, PartialEq)]
58pub enum VarType {
59 Int,
60 Float,
61 String,
62 Bool,
63}
64
65#[derive(Debug, Clone)]
66pub enum Statement {
67 Print(PrintStatement), Backtrace(BacktraceStatement),
69 Expr(Expr),
70 VarDeclaration {
71 name: String,
72 value: Expr,
73 },
74 AliasDeclaration {
77 name: String,
78 target: Expr,
79 },
80 TracePoint {
81 pattern: TracePattern,
82 body: Vec<Statement>,
83 },
84 If {
85 condition: Expr,
86 then_body: Vec<Statement>,
87 else_body: Option<Box<Statement>>,
88 },
89 Block(Vec<Statement>),
90}
91
92#[derive(Debug, Clone, PartialEq, Eq)]
93pub struct BacktraceStatement {
94 pub raw: bool,
95 pub full: bool,
96 pub inline: bool,
97}
98
99impl Default for BacktraceStatement {
100 fn default() -> Self {
101 Self {
102 raw: false,
103 full: false,
104 inline: true,
105 }
106 }
107}
108
109#[derive(Debug, Clone)]
111pub enum PrintStatement {
112 String(String),
114 Variable(String),
116 ComplexVariable(Expr),
118 Formatted { format: String, args: Vec<Expr> },
120}
121
122#[derive(Debug, Clone)]
123pub enum TracePattern {
124 FunctionName(String), Wildcard(String), Address(u64), AddressInModule {
128 module: String,
130 address: u64,
131 },
132 SourceLine {
133 file_path: String,
135 line_number: u32,
136 },
137}
138
139#[derive(Debug, Clone)]
141pub struct VariableContext {
142 pub current_address: Option<u64>,
143 pub available_vars: Vec<String>, }
145
146impl VariableContext {
147 pub fn new() -> Self {
148 Self {
149 current_address: None,
150 available_vars: vec![
151 "$arg0".to_string(),
153 "$arg1".to_string(),
154 "$arg2".to_string(),
155 "$arg3".to_string(),
156 "$retval".to_string(),
157 "$pc".to_string(),
158 "$sp".to_string(),
159 ],
160 }
161 }
162
163 pub fn is_variable_available(&self, var_name: &str) -> bool {
164 self.available_vars.contains(&var_name.to_string())
165 }
166
167 pub fn add_variable(&mut self, var_name: String) {
168 if !self.available_vars.contains(&var_name) {
169 self.available_vars.push(var_name);
170 }
171 }
172}
173
174impl Default for VariableContext {
175 fn default() -> Self {
176 Self::new()
177 }
178}
179
180#[derive(Debug, Clone)]
181pub struct Program {
182 pub statements: Vec<Statement>,
183}
184
185impl Program {
186 pub fn new() -> Self {
187 Program {
188 statements: Vec::new(),
189 }
190 }
191
192 pub fn add_statement(&mut self, statement: Statement) {
193 self.statements.push(statement);
194 }
195}
196
197impl Default for Program {
198 fn default() -> Self {
199 Self::new()
200 }
201}
202
203pub fn infer_type(expr: &Expr) -> Result<VarType, String> {
205 match expr {
206 Expr::Int(_) => Ok(VarType::Int),
207 Expr::Float(_) => Ok(VarType::Float),
208 Expr::String(_) => Ok(VarType::String),
209 Expr::Bool(_) => Ok(VarType::Bool),
210 Expr::UnaryNot(_) => Ok(VarType::Bool),
211 Expr::UnaryBitNot(inner) => match infer_type(inner)? {
212 VarType::Int | VarType::Bool => Ok(VarType::Int),
213 _ => Err("Bitwise NOT requires an integer or boolean operand".to_string()),
214 },
215 Expr::Variable(_) => Ok(VarType::Int), Expr::MemberAccess(_, _) => Ok(VarType::Int), Expr::PointerDeref(_) => Ok(VarType::Int), Expr::AddressOf(_) => Ok(VarType::Int), Expr::ArrayAccess(_, _) => Ok(VarType::Int), Expr::Cast { .. } => Ok(VarType::Int), Expr::ChainAccess(_) => Ok(VarType::Int), Expr::SpecialVar(_) => Ok(VarType::Int), Expr::BuiltinCall { name, args: _ } => match name.as_str() {
226 "strncmp" | "starts_with" | "memcmp" => Ok(VarType::Bool),
227 _ => Err(format!("Unknown builtin function: {name}")),
228 },
229 Expr::BinaryOp { left, op, right } => {
230 let left_is_literal = matches!(
232 left.as_ref(),
233 Expr::Int(_) | Expr::Float(_) | Expr::String(_)
234 );
235 let right_is_literal = matches!(
236 right.as_ref(),
237 Expr::Int(_) | Expr::Float(_) | Expr::String(_)
238 );
239
240 if left_is_literal && right_is_literal {
241 let left_type = infer_type(left)?;
242 let right_type = infer_type(right)?;
243
244 if left_type != right_type {
245 return Err(format!(
246 "Type mismatch: Cannot perform operation between {left_type:?} and {right_type:?}"
247 ));
248 }
249
250 if left_type == VarType::String
252 && !matches!(*op, BinaryOp::Add | BinaryOp::Equal | BinaryOp::NotEqual)
253 {
254 return Err(
255 "String type only supports addition and comparison operations".to_string(),
256 );
257 }
258
259 if matches!(
261 *op,
262 BinaryOp::Equal
263 | BinaryOp::NotEqual
264 | BinaryOp::LessThan
265 | BinaryOp::LessEqual
266 | BinaryOp::GreaterThan
267 | BinaryOp::GreaterEqual
268 ) {
269 return Ok(VarType::Bool);
270 }
271
272 if matches!(*op, BinaryOp::LogicalAnd | BinaryOp::LogicalOr) {
274 match (left_type, right_type) {
275 (VarType::Bool, VarType::Bool)
276 | (VarType::Bool, VarType::Int)
277 | (VarType::Int, VarType::Bool)
278 | (VarType::Int, VarType::Int) => return Ok(VarType::Bool),
279 _ => {
280 return Err("Logical operations require boolean or integer operands"
281 .to_string())
282 }
283 }
284 }
285
286 Ok(left_type)
287 } else {
288 if matches!(*op, BinaryOp::LogicalAnd | BinaryOp::LogicalOr)
291 || matches!(
292 *op,
293 BinaryOp::Equal
294 | BinaryOp::NotEqual
295 | BinaryOp::LessThan
296 | BinaryOp::LessEqual
297 | BinaryOp::GreaterThan
298 | BinaryOp::GreaterEqual
299 )
300 {
301 Ok(VarType::Bool)
302 } else {
303 Ok(VarType::Int)
304 }
305 }
306 }
307 }
308}