Skip to main content

ghostscope_compiler/script/
ast.rs

1#[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),   // person.name
11    PointerDeref(Box<Expr>),           // *ptr
12    AddressOf(Box<Expr>),              // &expr
13    ArrayAccess(Box<Expr>, Box<Expr>), // arr[0] (new)
14    Cast {
15        expr: Box<Expr>,
16        target_type: String,
17    },
18    ChainAccess(Vec<String>), // person.name.first (new)
19    SpecialVar(String),       // For $arg0, $arg1, $retval, $pc, $sp etc.
20    // Builtin function call, e.g., strncmp(expr, "lit", n), starts_with(expr, "lit")
21    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    // Bitwise operators
40    BitAnd,
41    BitXor,
42    BitOr,
43    ShiftLeft,
44    ShiftRight,
45    // Comparison operators
46    Equal,
47    NotEqual,
48    LessThan,
49    LessEqual,
50    GreaterThan,
51    GreaterEqual,
52    // Logical operators
53    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), // Updated to use new PrintStatement
68    Backtrace(BacktraceStatement),
69    Expr(Expr),
70    VarDeclaration {
71        name: String,
72        value: Expr,
73    },
74    /// DWARF alias binding: `let name = <alias_expr>;` where alias_expr is address-of,
75    /// member/array/pointer deref/chain, or alias+constant offset. Resolved at use time.
76    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/// Print statement variants for new instruction system
110#[derive(Debug, Clone)]
111pub enum PrintStatement {
112    /// print "hello world"
113    String(String),
114    /// print variable_name
115    Variable(String),
116    /// print person.name or arr[0] (new: support complex expressions)
117    ComplexVariable(Expr),
118    /// print "format {} {}" arg1, arg2
119    Formatted { format: String, args: Vec<Expr> },
120}
121
122#[derive(Debug, Clone)]
123pub enum TracePattern {
124    FunctionName(String), // trace main { ... }
125    Wildcard(String),     // trace printf* { ... }
126    Address(u64),         // trace 0x400000 { ... }
127    AddressInModule {
128        // trace module_suffix:0xADDR { ... }
129        module: String,
130        address: u64,
131    },
132    SourceLine {
133        // trace file.c:123 { ... }
134        file_path: String,
135        line_number: u32,
136    },
137}
138
139/// Variable validation context
140#[derive(Debug, Clone)]
141pub struct VariableContext {
142    pub current_address: Option<u64>,
143    pub available_vars: Vec<String>, // Variables available at current context
144}
145
146impl VariableContext {
147    pub fn new() -> Self {
148        Self {
149            current_address: None,
150            available_vars: vec![
151                // Always available special variables
152                "$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
203// Add type inference function
204pub 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        // During parsing phase, we cannot know variable types, only check literal expressions
216        // For variable references, return a default type to allow compilation to continue, actual type checking will be done in code generation phase
217        Expr::Variable(_) => Ok(VarType::Int), // Temporarily assume variables are integer type to let parsing pass
218        Expr::MemberAccess(_, _) => Ok(VarType::Int), // Same as above
219        Expr::PointerDeref(_) => Ok(VarType::Int), // Same as above
220        Expr::AddressOf(_) => Ok(VarType::Int), // Address as integer/pointer value for now
221        Expr::ArrayAccess(_, _) => Ok(VarType::Int), // New: array access returns element type (assume int for now)
222        Expr::Cast { .. } => Ok(VarType::Int),       // Cast type is resolved during codegen.
223        Expr::ChainAccess(_) => Ok(VarType::Int), // New: chain access returns final member type (assume int for now)
224        Expr::SpecialVar(_) => Ok(VarType::Int),  // Special variables like $arg0, $retval etc.
225        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            // Only check types when both sides are literals
231            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                // Strings only support addition operation and comparison operations
251                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                // Comparison operations return boolean type
260                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                // Logical operations return boolean; allow Int literals as truthy (non-zero)
273                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 there are variable references, assume type compatibility to let parsing pass
289                // Actual type checking will be done in code generation phase
290                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}