Skip to main content

awk_rs/
ast.rs

1use crate::error::SourceLocation;
2
3/// A complete AWK program
4#[derive(Debug, Clone)]
5pub struct Program {
6    pub rules: Vec<Rule>,
7    pub functions: Vec<FunctionDef>,
8}
9
10impl Program {
11    pub fn new() -> Self {
12        Self {
13            rules: Vec::new(),
14            functions: Vec::new(),
15        }
16    }
17}
18
19impl Default for Program {
20    fn default() -> Self {
21        Self::new()
22    }
23}
24
25/// A pattern-action rule
26#[derive(Debug, Clone)]
27pub struct Rule {
28    pub pattern: Option<Pattern>,
29    pub action: Option<Block>,
30    pub location: SourceLocation,
31}
32
33/// Pattern types that can trigger a rule
34#[derive(Debug, Clone)]
35pub enum Pattern {
36    /// BEGIN - runs before any input
37    Begin,
38    /// END - runs after all input
39    End,
40    /// BEGINFILE - runs at the start of each input file (gawk extension)
41    BeginFile,
42    /// ENDFILE - runs at the end of each input file (gawk extension)
43    EndFile,
44    /// Expression that evaluates to true/false
45    Expr(Expr),
46    /// Regex pattern: /pattern/
47    Regex(String),
48    /// Range pattern: /start/,/end/
49    Range {
50        start: Box<Pattern>,
51        end: Box<Pattern>,
52    },
53    /// Compound patterns with logical operators
54    And(Box<Pattern>, Box<Pattern>),
55    Or(Box<Pattern>, Box<Pattern>),
56    Not(Box<Pattern>),
57}
58
59/// User-defined function
60#[derive(Debug, Clone)]
61pub struct FunctionDef {
62    pub name: String,
63    pub params: Vec<String>,
64    pub body: Block,
65    pub location: SourceLocation,
66}
67
68/// A block of statements
69#[derive(Debug, Clone)]
70pub struct Block {
71    pub statements: Vec<Stmt>,
72    pub location: SourceLocation,
73}
74
75impl Block {
76    pub fn new(statements: Vec<Stmt>, location: SourceLocation) -> Self {
77        Self {
78            statements,
79            location,
80        }
81    }
82
83    pub fn empty(location: SourceLocation) -> Self {
84        Self {
85            statements: Vec::new(),
86            location,
87        }
88    }
89}
90
91/// Statement types
92#[derive(Debug, Clone)]
93pub enum Stmt {
94    /// Expression statement (e.g., function call, assignment)
95    Expr(Expr),
96
97    /// Print statement: print expr, expr, ...
98    Print {
99        args: Vec<Expr>,
100        output: Option<OutputRedirect>,
101        location: SourceLocation,
102    },
103
104    /// Printf statement: printf format, expr, ...
105    Printf {
106        format: Expr,
107        args: Vec<Expr>,
108        output: Option<OutputRedirect>,
109        location: SourceLocation,
110    },
111
112    /// If statement
113    If {
114        condition: Expr,
115        then_branch: Box<Stmt>,
116        else_branch: Option<Box<Stmt>>,
117        location: SourceLocation,
118    },
119
120    /// While loop
121    While {
122        condition: Expr,
123        body: Box<Stmt>,
124        location: SourceLocation,
125    },
126
127    /// Do-while loop
128    DoWhile {
129        body: Box<Stmt>,
130        condition: Expr,
131        location: SourceLocation,
132    },
133
134    /// For loop (C-style)
135    For {
136        init: Option<Box<Stmt>>,
137        condition: Option<Expr>,
138        update: Option<Expr>,
139        body: Box<Stmt>,
140        location: SourceLocation,
141    },
142
143    /// For-in loop (array iteration)
144    ForIn {
145        var: String,
146        array: String,
147        body: Box<Stmt>,
148        location: SourceLocation,
149    },
150
151    /// Block of statements
152    Block(Block),
153
154    /// Break statement
155    Break { location: SourceLocation },
156
157    /// Continue statement
158    Continue { location: SourceLocation },
159
160    /// Next statement (skip to next record)
161    Next { location: SourceLocation },
162
163    /// Nextfile statement (skip to next file)
164    Nextfile { location: SourceLocation },
165
166    /// Exit statement
167    Exit {
168        code: Option<Expr>,
169        location: SourceLocation,
170    },
171
172    /// Return statement
173    Return {
174        value: Option<Expr>,
175        location: SourceLocation,
176    },
177
178    /// Delete statement: delete array\[index\]
179    Delete {
180        array: String,
181        index: Vec<Expr>,
182        location: SourceLocation,
183    },
184
185    /// Empty statement (just a semicolon)
186    Empty,
187}
188
189/// Output redirection for print/printf
190#[derive(Debug, Clone)]
191pub enum OutputRedirect {
192    /// > file
193    Truncate(Expr),
194    /// >> file
195    Append(Expr),
196    /// | command
197    Pipe(Expr),
198}
199
200/// Input source for getline
201#[derive(Debug, Clone)]
202pub enum GetlineInput {
203    /// < file
204    File(Box<Expr>),
205    /// command |
206    Pipe(Box<Expr>),
207}
208
209/// Expression types
210#[derive(Debug, Clone)]
211pub enum Expr {
212    /// Numeric literal
213    Number(f64, SourceLocation),
214
215    /// String literal
216    String(String, SourceLocation),
217
218    /// Regex literal
219    Regex(String, SourceLocation),
220
221    /// Variable reference
222    Var(String, SourceLocation),
223
224    /// Field access: $expr
225    Field(Box<Expr>, SourceLocation),
226
227    /// Array access: arr\[index\] or arr\[i,j\]
228    ArrayAccess {
229        array: String,
230        indices: Vec<Expr>,
231        location: SourceLocation,
232    },
233
234    /// Binary operation
235    Binary {
236        left: Box<Expr>,
237        op: BinaryOp,
238        right: Box<Expr>,
239        location: SourceLocation,
240    },
241
242    /// Unary operation
243    Unary {
244        op: UnaryOp,
245        operand: Box<Expr>,
246        location: SourceLocation,
247    },
248
249    /// Assignment
250    Assign {
251        target: Box<Expr>,
252        op: AssignOp,
253        value: Box<Expr>,
254        location: SourceLocation,
255    },
256
257    /// Pre-increment: ++x
258    PreIncrement(Box<Expr>, SourceLocation),
259
260    /// Pre-decrement: --x
261    PreDecrement(Box<Expr>, SourceLocation),
262
263    /// Post-increment: x++
264    PostIncrement(Box<Expr>, SourceLocation),
265
266    /// Post-decrement: x--
267    PostDecrement(Box<Expr>, SourceLocation),
268
269    /// Ternary: cond ? then : else
270    Ternary {
271        condition: Box<Expr>,
272        then_expr: Box<Expr>,
273        else_expr: Box<Expr>,
274        location: SourceLocation,
275    },
276
277    /// Function call
278    Call {
279        name: String,
280        args: Vec<Expr>,
281        location: SourceLocation,
282    },
283
284    /// Array membership: (key) in array
285    InArray {
286        key: Vec<Expr>,
287        array: String,
288        location: SourceLocation,
289    },
290
291    /// Regex match: expr ~ /regex/ or expr !~ /regex/
292    Match {
293        expr: Box<Expr>,
294        pattern: Box<Expr>,
295        negated: bool,
296        location: SourceLocation,
297    },
298
299    /// Getline as expression (returns status)
300    Getline {
301        /// Target lvalue (variable, array element, or field); `None` sets $0.
302        var: Option<Box<Expr>>,
303        input: Option<GetlineInput>,
304        location: SourceLocation,
305    },
306
307    /// Grouping parentheses (for precedence)
308    Group(Box<Expr>, SourceLocation),
309}
310
311impl Expr {
312    pub fn location(&self) -> SourceLocation {
313        match self {
314            Expr::Number(_, loc)
315            | Expr::String(_, loc)
316            | Expr::Regex(_, loc)
317            | Expr::Var(_, loc)
318            | Expr::Field(_, loc)
319            | Expr::ArrayAccess { location: loc, .. }
320            | Expr::Binary { location: loc, .. }
321            | Expr::Unary { location: loc, .. }
322            | Expr::Assign { location: loc, .. }
323            | Expr::PreIncrement(_, loc)
324            | Expr::PreDecrement(_, loc)
325            | Expr::PostIncrement(_, loc)
326            | Expr::PostDecrement(_, loc)
327            | Expr::Ternary { location: loc, .. }
328            | Expr::Call { location: loc, .. }
329            | Expr::InArray { location: loc, .. }
330            | Expr::Match { location: loc, .. }
331            | Expr::Getline { location: loc, .. }
332            | Expr::Group(_, loc) => *loc,
333        }
334    }
335}
336
337/// Binary operators
338#[derive(Debug, Clone, Copy, PartialEq, Eq)]
339pub enum BinaryOp {
340    // Arithmetic
341    Add,
342    Sub,
343    Mul,
344    Div,
345    Mod,
346    Pow,
347
348    // Comparison
349    Lt,
350    Le,
351    Gt,
352    Ge,
353    Eq,
354    Ne,
355
356    // Logical
357    And,
358    Or,
359
360    // String
361    Concat,
362}
363
364/// Unary operators
365#[derive(Debug, Clone, Copy, PartialEq, Eq)]
366pub enum UnaryOp {
367    Neg, // -x
368    Pos, // +x
369    Not, // !x
370}
371
372/// Assignment operators
373#[derive(Debug, Clone, Copy, PartialEq, Eq)]
374pub enum AssignOp {
375    Assign,    // =
376    AddAssign, // +=
377    SubAssign, // -=
378    MulAssign, // *=
379    DivAssign, // /=
380    ModAssign, // %=
381    PowAssign, // ^=
382}