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 Variable(String),
9 MemberAccess(Box<Expr>, String), PointerDeref(Box<Expr>), AddressOf(Box<Expr>), ArrayAccess(Box<Expr>, Box<Expr>), ChainAccess(Vec<String>), SpecialVar(String), BuiltinCall {
17 name: String,
18 args: Vec<Expr>,
19 },
20 BinaryOp {
21 left: Box<Expr>,
22 op: BinaryOp,
23 right: Box<Expr>,
24 },
25}
26
27#[derive(Debug, Clone, PartialEq)]
28pub enum BinaryOp {
29 Add,
30 Subtract,
31 Multiply,
32 Divide,
33 Equal,
35 NotEqual,
36 LessThan,
37 LessEqual,
38 GreaterThan,
39 GreaterEqual,
40 LogicalAnd,
42 LogicalOr,
43}
44
45#[derive(Debug, Clone, PartialEq)]
46pub enum VarType {
47 Int,
48 Float,
49 String,
50 Bool,
51}
52
53#[derive(Debug, Clone)]
54pub enum Statement {
55 Print(PrintStatement), Backtrace,
57 Expr(Expr),
58 VarDeclaration {
59 name: String,
60 value: Expr,
61 },
62 AliasDeclaration {
65 name: String,
66 target: Expr,
67 },
68 TracePoint {
69 pattern: TracePattern,
70 body: Vec<Statement>,
71 },
72 If {
73 condition: Expr,
74 then_body: Vec<Statement>,
75 else_body: Option<Box<Statement>>,
76 },
77 Block(Vec<Statement>),
78}
79
80#[derive(Debug, Clone)]
82pub enum PrintStatement {
83 String(String),
85 Variable(String),
87 ComplexVariable(Expr),
89 Formatted { format: String, args: Vec<Expr> },
91}
92
93#[derive(Debug, Clone)]
94pub enum TracePattern {
95 FunctionName(String), Wildcard(String), Address(u64), AddressInModule {
99 module: String,
101 address: u64,
102 },
103 SourceLine {
104 file_path: String,
106 line_number: u32,
107 },
108}
109
110#[derive(Debug, Clone)]
112pub struct VariableContext {
113 pub current_address: Option<u64>,
114 pub available_vars: Vec<String>, }
116
117impl VariableContext {
118 pub fn new() -> Self {
119 Self {
120 current_address: None,
121 available_vars: vec![
122 "$arg0".to_string(),
124 "$arg1".to_string(),
125 "$arg2".to_string(),
126 "$arg3".to_string(),
127 "$retval".to_string(),
128 "$pc".to_string(),
129 "$sp".to_string(),
130 ],
131 }
132 }
133
134 pub fn is_variable_available(&self, var_name: &str) -> bool {
135 self.available_vars.contains(&var_name.to_string())
136 }
137
138 pub fn add_variable(&mut self, var_name: String) {
139 if !self.available_vars.contains(&var_name) {
140 self.available_vars.push(var_name);
141 }
142 }
143}
144
145impl Default for VariableContext {
146 fn default() -> Self {
147 Self::new()
148 }
149}
150
151#[derive(Debug, Clone)]
152pub struct Program {
153 pub statements: Vec<Statement>,
154}
155
156impl Program {
157 pub fn new() -> Self {
158 Program {
159 statements: Vec::new(),
160 }
161 }
162
163 pub fn add_statement(&mut self, statement: Statement) {
164 self.statements.push(statement);
165 }
166}
167
168impl Default for Program {
169 fn default() -> Self {
170 Self::new()
171 }
172}
173
174pub fn infer_type(expr: &Expr) -> Result<VarType, String> {
176 match expr {
177 Expr::Int(_) => Ok(VarType::Int),
178 Expr::Float(_) => Ok(VarType::Float),
179 Expr::String(_) => Ok(VarType::String),
180 Expr::Bool(_) => Ok(VarType::Bool),
181 Expr::UnaryNot(_) => Ok(VarType::Bool),
182 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::ChainAccess(_) => Ok(VarType::Int), Expr::SpecialVar(_) => Ok(VarType::Int), Expr::BuiltinCall { name, args: _ } => match name.as_str() {
192 "strncmp" | "starts_with" | "memcmp" => Ok(VarType::Bool),
193 _ => Err(format!("Unknown builtin function: {name}")),
194 },
195 Expr::BinaryOp { left, op, right } => {
196 let left_is_literal = matches!(
198 left.as_ref(),
199 Expr::Int(_) | Expr::Float(_) | Expr::String(_)
200 );
201 let right_is_literal = matches!(
202 right.as_ref(),
203 Expr::Int(_) | Expr::Float(_) | Expr::String(_)
204 );
205
206 if left_is_literal && right_is_literal {
207 let left_type = infer_type(left)?;
208 let right_type = infer_type(right)?;
209
210 if left_type != right_type {
211 return Err(format!(
212 "Type mismatch: Cannot perform operation between {left_type:?} and {right_type:?}"
213 ));
214 }
215
216 if left_type == VarType::String
218 && !matches!(*op, BinaryOp::Add | BinaryOp::Equal | BinaryOp::NotEqual)
219 {
220 return Err(
221 "String type only supports addition and comparison operations".to_string(),
222 );
223 }
224
225 if matches!(
227 *op,
228 BinaryOp::Equal
229 | BinaryOp::NotEqual
230 | BinaryOp::LessThan
231 | BinaryOp::LessEqual
232 | BinaryOp::GreaterThan
233 | BinaryOp::GreaterEqual
234 ) {
235 return Ok(VarType::Bool);
236 }
237
238 if matches!(*op, BinaryOp::LogicalAnd | BinaryOp::LogicalOr) {
240 match (left_type, right_type) {
241 (VarType::Bool, VarType::Bool)
242 | (VarType::Bool, VarType::Int)
243 | (VarType::Int, VarType::Bool)
244 | (VarType::Int, VarType::Int) => return Ok(VarType::Bool),
245 _ => {
246 return Err("Logical operations require boolean or integer operands"
247 .to_string())
248 }
249 }
250 }
251
252 Ok(left_type)
253 } else {
254 if matches!(*op, BinaryOp::LogicalAnd | BinaryOp::LogicalOr)
257 || matches!(
258 *op,
259 BinaryOp::Equal
260 | BinaryOp::NotEqual
261 | BinaryOp::LessThan
262 | BinaryOp::LessEqual
263 | BinaryOp::GreaterThan
264 | BinaryOp::GreaterEqual
265 )
266 {
267 Ok(VarType::Bool)
268 } else {
269 Ok(VarType::Int)
270 }
271 }
272 }
273 }
274}