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    /// Getline statement (various forms)
186    Getline {
187        var: Option<String>,
188        input: Option<GetlineInput>,
189        location: SourceLocation,
190    },
191
192    /// Empty statement (just a semicolon)
193    Empty,
194}
195
196/// Output redirection for print/printf
197#[derive(Debug, Clone)]
198pub enum OutputRedirect {
199    /// > file
200    Truncate(Expr),
201    /// >> file
202    Append(Expr),
203    /// | command
204    Pipe(Expr),
205}
206
207/// Input source for getline
208#[derive(Debug, Clone)]
209pub enum GetlineInput {
210    /// < file
211    File(Box<Expr>),
212    /// command |
213    Pipe(Box<Expr>),
214}
215
216/// Expression types
217#[derive(Debug, Clone)]
218pub enum Expr {
219    /// Numeric literal
220    Number(f64, SourceLocation),
221
222    /// String literal
223    String(String, SourceLocation),
224
225    /// Regex literal
226    Regex(String, SourceLocation),
227
228    /// Variable reference
229    Var(String, SourceLocation),
230
231    /// Field access: $expr
232    Field(Box<Expr>, SourceLocation),
233
234    /// Array access: arr[index] or arr[i,j]
235    ArrayAccess {
236        array: String,
237        indices: Vec<Expr>,
238        location: SourceLocation,
239    },
240
241    /// Binary operation
242    Binary {
243        left: Box<Expr>,
244        op: BinaryOp,
245        right: Box<Expr>,
246        location: SourceLocation,
247    },
248
249    /// Unary operation
250    Unary {
251        op: UnaryOp,
252        operand: Box<Expr>,
253        location: SourceLocation,
254    },
255
256    /// Assignment
257    Assign {
258        target: Box<Expr>,
259        op: AssignOp,
260        value: Box<Expr>,
261        location: SourceLocation,
262    },
263
264    /// Pre-increment: ++x
265    PreIncrement(Box<Expr>, SourceLocation),
266
267    /// Pre-decrement: --x
268    PreDecrement(Box<Expr>, SourceLocation),
269
270    /// Post-increment: x++
271    PostIncrement(Box<Expr>, SourceLocation),
272
273    /// Post-decrement: x--
274    PostDecrement(Box<Expr>, SourceLocation),
275
276    /// Ternary: cond ? then : else
277    Ternary {
278        condition: Box<Expr>,
279        then_expr: Box<Expr>,
280        else_expr: Box<Expr>,
281        location: SourceLocation,
282    },
283
284    /// Function call
285    Call {
286        name: String,
287        args: Vec<Expr>,
288        location: SourceLocation,
289    },
290
291    /// Array membership: (key) in array
292    InArray {
293        key: Vec<Expr>,
294        array: String,
295        location: SourceLocation,
296    },
297
298    /// Regex match: expr ~ /regex/ or expr !~ /regex/
299    Match {
300        expr: Box<Expr>,
301        pattern: Box<Expr>,
302        negated: bool,
303        location: SourceLocation,
304    },
305
306    /// Concatenation (implicit when expressions are adjacent)
307    Concat(Vec<Expr>, SourceLocation),
308
309    /// Getline as expression (returns status)
310    Getline {
311        var: Option<String>,
312        input: Option<GetlineInput>,
313        location: SourceLocation,
314    },
315
316    /// Grouping parentheses (for precedence)
317    Group(Box<Expr>, SourceLocation),
318}
319
320impl Expr {
321    pub fn location(&self) -> SourceLocation {
322        match self {
323            Expr::Number(_, loc)
324            | Expr::String(_, loc)
325            | Expr::Regex(_, loc)
326            | Expr::Var(_, loc)
327            | Expr::Field(_, loc)
328            | Expr::ArrayAccess { location: loc, .. }
329            | Expr::Binary { location: loc, .. }
330            | Expr::Unary { location: loc, .. }
331            | Expr::Assign { location: loc, .. }
332            | Expr::PreIncrement(_, loc)
333            | Expr::PreDecrement(_, loc)
334            | Expr::PostIncrement(_, loc)
335            | Expr::PostDecrement(_, loc)
336            | Expr::Ternary { location: loc, .. }
337            | Expr::Call { location: loc, .. }
338            | Expr::InArray { location: loc, .. }
339            | Expr::Match { location: loc, .. }
340            | Expr::Concat(_, loc)
341            | Expr::Getline { location: loc, .. }
342            | Expr::Group(_, loc) => *loc,
343        }
344    }
345}
346
347/// Binary operators
348#[derive(Debug, Clone, Copy, PartialEq, Eq)]
349pub enum BinaryOp {
350    // Arithmetic
351    Add,
352    Sub,
353    Mul,
354    Div,
355    Mod,
356    Pow,
357
358    // Comparison
359    Lt,
360    Le,
361    Gt,
362    Ge,
363    Eq,
364    Ne,
365
366    // Logical
367    And,
368    Or,
369
370    // String
371    Concat,
372}
373
374/// Unary operators
375#[derive(Debug, Clone, Copy, PartialEq, Eq)]
376pub enum UnaryOp {
377    Neg, // -x
378    Pos, // +x
379    Not, // !x
380}
381
382/// Assignment operators
383#[derive(Debug, Clone, Copy, PartialEq, Eq)]
384pub enum AssignOp {
385    Assign,    // =
386    AddAssign, // +=
387    SubAssign, // -=
388    MulAssign, // *=
389    DivAssign, // /=
390    ModAssign, // %=
391    PowAssign, // ^=
392}