Skip to main content

patch_rexx/
ast.rs

1//! REXX abstract syntax tree.
2//!
3//! REXX programs are sequences of clauses. Each clause is either a label,
4//! an instruction, a command (string sent to the environment), or an
5//! assignment.
6
7use crate::error::SourceLoc;
8
9/// A complete REXX program.
10#[derive(Debug, Clone)]
11pub struct Program {
12    pub clauses: Vec<Clause>,
13}
14
15/// A single REXX clause with its source location.
16#[derive(Debug, Clone)]
17pub struct Clause {
18    pub kind: ClauseKind,
19    pub loc: SourceLoc,
20}
21
22#[derive(Debug, Clone)]
23pub enum ClauseKind {
24    /// A label (e.g., `myLabel:`)
25    Label(String),
26
27    /// Variable assignment: `symbol = expr`
28    Assignment { target: AssignTarget, expr: Expr },
29
30    /// SAY expr
31    Say(Expr),
32
33    /// CALL routine [args...]
34    Call { name: String, args: Vec<Expr> },
35
36    /// DO block (many variants)
37    Do(Box<DoBlock>),
38
39    /// IF expr THEN clause [ELSE clause]
40    If {
41        condition: Expr,
42        then_clause: Box<Clause>,
43        else_clause: Option<Box<Clause>>,
44    },
45
46    /// SELECT [WHEN expr THEN clause]... [OTHERWISE clause...] END
47    Select {
48        when_clauses: Vec<(Expr, Vec<Clause>)>,
49        otherwise: Option<Vec<Clause>>,
50    },
51
52    /// RETURN [expr]
53    Return(Option<Expr>),
54
55    /// EXIT [expr]
56    Exit(Option<Expr>),
57
58    /// ITERATE [name]
59    Iterate(Option<String>),
60
61    /// LEAVE [name]
62    Leave(Option<String>),
63
64    /// NOP
65    Nop,
66
67    /// PARSE [UPPER] source template
68    Parse {
69        upper: bool,
70        source: ParseSource,
71        template: ParseTemplate,
72    },
73
74    /// SIGNAL label | SIGNAL ON condition | SIGNAL OFF condition
75    Signal(SignalAction),
76
77    /// NUMERIC DIGITS [expr] | NUMERIC FORM ... | NUMERIC FUZZ [expr]
78    Numeric(NumericSetting),
79
80    /// ADDRESS environment [command] | ADDRESS [VALUE] expr
81    Address(AddressAction),
82
83    /// DROP name [name...]
84    Drop(Vec<String>),
85
86    /// PROCEDURE [EXPOSE name [name...]]
87    Procedure(Option<Vec<String>>),
88
89    /// PUSH [expr] — push onto external data queue
90    Push(Option<Expr>),
91
92    /// PULL [template] — pull from queue or stdin, uppercase
93    Pull(Option<ParseTemplate>),
94
95    /// QUEUE [expr] — queue onto external data queue
96    Queue(Option<Expr>),
97
98    /// TRACE setting
99    Trace(Expr),
100
101    /// INTERPRET expr
102    Interpret(Expr),
103
104    /// ARG template — shorthand for PARSE UPPER ARG template
105    Arg(ParseTemplate),
106
107    /// A command clause: expression evaluated and sent to current environment
108    Command(Expr),
109}
110
111/// Assignment targets — simple variables or stem compounds.
112#[derive(Debug, Clone)]
113pub enum AssignTarget {
114    /// Simple variable: `x = 5`
115    Simple(String),
116    /// Stem compound: `stem.tail = 5`
117    Stem {
118        stem: String,
119        tail: Vec<TailElement>,
120    },
121}
122
123/// Elements of a compound variable tail.
124#[derive(Debug, Clone)]
125pub enum TailElement {
126    Const(String),
127    Var(String),
128}
129
130/// DO block variants.
131#[derive(Debug, Clone)]
132pub struct DoBlock {
133    pub kind: DoKind,
134    pub body: Vec<Clause>,
135    /// Optional label name for LEAVE/ITERATE targeting.
136    pub name: Option<String>,
137}
138
139#[derive(Debug, Clone)]
140pub enum DoKind {
141    /// DO; ... END (simple grouping)
142    Simple,
143    /// DO FOREVER; ... END
144    Forever,
145    /// DO expr; ... END (counted loop)
146    Count(Expr),
147    /// DO WHILE expr; ... END
148    While(Expr),
149    /// DO UNTIL expr; ... END
150    Until(Expr),
151    /// DO var = start TO end [BY step] [FOR count]; ... END
152    Controlled(Box<ControlledLoop>),
153}
154
155/// Controlled DO loop parameters.
156#[derive(Debug, Clone)]
157pub struct ControlledLoop {
158    pub var: String,
159    pub start: Expr,
160    pub to: Option<Expr>,
161    pub by: Option<Expr>,
162    pub r#for: Option<Expr>,
163    pub while_cond: Option<Expr>,
164    pub until_cond: Option<Expr>,
165}
166
167/// PARSE sources.
168#[derive(Debug, Clone)]
169pub enum ParseSource {
170    /// PARSE ARG — subroutine arguments
171    Arg,
172    /// PARSE PULL — data queue or stdin
173    Pull,
174    /// PARSE SOURCE — program source info
175    Source,
176    /// PARSE VERSION — interpreter version
177    Version,
178    /// PARSE LINEIN — read from stdin
179    LineIn,
180    /// PARSE VALUE expr WITH — expression result
181    Value(Expr),
182    /// PARSE VAR name — variable contents
183    Var(String),
184}
185
186/// PARSE template — a sequence of targets and patterns.
187#[derive(Debug, Clone)]
188pub struct ParseTemplate {
189    pub elements: Vec<TemplateElement>,
190}
191
192#[derive(Debug, Clone)]
193pub enum TemplateElement {
194    /// A variable name to receive data.
195    Variable(String),
196    /// A literal string pattern to match.
197    Literal(String),
198    /// An absolute column position.
199    AbsolutePos(Expr),
200    /// A relative column position (+ or -).
201    RelativePos(i32),
202    /// A variable holding a pattern string.
203    VariablePattern(String),
204    /// The dot placeholder (discard data).
205    Dot,
206    /// Comma separating multiple argument strings.
207    Comma,
208}
209
210/// SIGNAL variants.
211#[derive(Debug, Clone)]
212pub enum SignalAction {
213    /// SIGNAL label
214    Label(String),
215    /// SIGNAL VALUE expr
216    Value(Expr),
217    /// SIGNAL ON condition [NAME label]
218    On {
219        condition: Condition,
220        name: Option<String>,
221    },
222    /// SIGNAL OFF condition
223    Off(Condition),
224}
225
226/// Trappable conditions.
227#[derive(Debug, Clone, PartialEq, Eq, Hash)]
228pub enum Condition {
229    Error,
230    Failure,
231    Halt,
232    NoValue,
233    NotReady,
234    Syntax,
235    LostDigits,
236}
237
238/// NUMERIC instruction settings.
239#[derive(Debug, Clone)]
240pub enum NumericSetting {
241    Digits(Option<Expr>),
242    Form(NumericFormSetting),
243    Fuzz(Option<Expr>),
244}
245
246#[derive(Debug, Clone)]
247pub enum NumericFormSetting {
248    Scientific,
249    Engineering,
250    Value(Expr),
251}
252
253/// ADDRESS instruction actions.
254#[derive(Debug, Clone)]
255pub enum AddressAction {
256    /// ADDRESS environment — set default
257    SetEnvironment(String),
258    /// ADDRESS environment command — one-shot
259    Temporary { environment: String, command: Expr },
260    /// ADDRESS VALUE expr — dynamic environment name
261    Value(Expr),
262}
263
264/// Expressions.
265#[derive(Debug, Clone)]
266pub enum Expr {
267    /// String literal
268    StringLit(String),
269    /// Number literal (stored as string per REXX semantics)
270    Number(String),
271    /// Variable reference
272    Symbol(String),
273    /// Compound variable: stem.tail
274    Compound {
275        stem: String,
276        tail: Vec<TailElement>,
277    },
278    /// Binary operation
279    BinOp {
280        left: Box<Expr>,
281        op: BinOp,
282        right: Box<Expr>,
283    },
284    /// Unary prefix operation
285    UnaryOp { op: UnaryOp, operand: Box<Expr> },
286    /// Function call: name(args)
287    FunctionCall { name: String, args: Vec<Expr> },
288    /// Parenthesized expression
289    Paren(Box<Expr>),
290}
291
292#[derive(Debug, Clone, Copy, PartialEq, Eq)]
293pub enum BinOp {
294    Add,
295    Sub,
296    Mul,
297    Div,
298    IntDiv,
299    Remainder,
300    Power,
301    Concat,      // abuttal or ||
302    ConcatBlank, // implicit blank concatenation
303
304    // Comparison
305    Eq,
306    NotEq,
307    Gt,
308    Lt,
309    GtEq,
310    LtEq,
311    StrictEq,
312    StrictNotEq,
313    StrictGt,
314    StrictLt,
315    StrictGtEq,
316    StrictLtEq,
317
318    // Logical
319    And,
320    Or,
321    Xor,
322}
323
324#[derive(Debug, Clone, Copy, PartialEq, Eq)]
325pub enum UnaryOp {
326    Plus,
327    Minus,
328    Not,
329}