⎇ 321e6f8e27aea06b5a868b37598148e15bf71f57
crates/modules/charka/charka-ir/src/ast.rs
History
Who touched what
raw
feat(charka): PERFORM VARYING — el bucle con variable de control
1//! Los tipos del IR: el programa COBOL con su PROCEDURE division ya
2//! parseada a instrucciones tipadas.
3
4pub use charka_parser::{DataItem, Token};
5
6/// Un programa COBOL en representación intermedia.
7#[derive(Debug, Clone, PartialEq, Default)]
8pub struct Ir {
9 /// El `PROGRAM-ID` ("" si el programa no lo declara).
10 pub program_id: String,
11 /// El modelo de datos — el árbol de [`DataItem`] tal cual lo
12 /// produjo `charka-parser`. Sirve de tabla de símbolos.
13 pub data: Vec<DataItem>,
14 /// Los párrafos del PROCEDURE, con sus statements ya tipados.
15 pub procedures: Vec<Procedure>,
16}
17
18/// Un párrafo del PROCEDURE: un nombre y un cuerpo de statements.
19#[derive(Debug, Clone, PartialEq, Default)]
20pub struct Procedure {
21 /// Nombre del párrafo en mayúsculas; "" para el párrafo implícito.
22 pub name: String,
23 /// Los statements del párrafo, en orden.
24 pub body: Vec<Stmt>,
25}
26
27/// Un operando: lo que puede ir donde se espera un valor.
28#[derive(Debug, Clone, PartialEq)]
29pub enum Operand {
30 /// Referencia a un dato, por nombre (en mayúsculas).
31 Data(String),
32 /// Literal numérico (texto, posiblemente con signo).
33 Num(String),
34 /// Literal de texto.
35 Str(String),
36 /// Constante figurativa (`ZERO`, `SPACE`...).
37 Figurative(Figurative),
38}
39
40/// Las constantes figurativas de COBOL.
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub enum Figurative {
43 Zero,
44 Space,
45 HighValue,
46 LowValue,
47 Quote,
48 Null,
49}
50
51/// Una expresión aritmética (la parte derecha de un `COMPUTE`).
52#[derive(Debug, Clone, PartialEq)]
53pub enum Expr {
54 /// Un operando hoja.
55 Operand(Operand),
56 /// Negación unaria.
57 Neg(Box<Expr>),
58 /// Operación binaria.
59 Binary {
60 op: BinOp,
61 lhs: Box<Expr>,
62 rhs: Box<Expr>,
63 },
64}
65
66/// Operador aritmético binario.
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum BinOp {
69 Add,
70 Sub,
71 Mul,
72 Div,
73 /// Exponenciación (`**`).
74 Pow,
75}
76
77/// Una condición (la guarda de un `IF` o de un `PERFORM UNTIL`).
78#[derive(Debug, Clone, PartialEq)]
79pub enum Cond {
80 /// Comparación relacional `lhs op rhs`.
81 Compare {
82 lhs: Operand,
83 op: CmpOp,
84 rhs: Operand,
85 },
86 /// Un nombre de condición (un dato de nivel 88) usado solo.
87 Named(String),
88 /// Negación lógica.
89 Not(Box<Cond>),
90 /// Conjunción lógica.
91 And(Box<Cond>, Box<Cond>),
92 /// Disyunción lógica.
93 Or(Box<Cond>, Box<Cond>),
94}
95
96/// Operador relacional.
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98pub enum CmpOp {
99 Eq,
100 Ne,
101 Lt,
102 Gt,
103 Le,
104 Ge,
105}
106
107/// Un statement del PROCEDURE division.
108#[derive(Debug, Clone, PartialEq)]
109pub enum Stmt {
110 /// `MOVE from TO to...`
111 Move { from: Operand, to: Vec<String> },
112 /// `DISPLAY items...`
113 Display { items: Vec<Operand> },
114 /// `ACCEPT into`
115 Accept { into: String },
116 /// `COMPUTE targets... [ROUNDED] = expr`
117 Compute {
118 targets: Vec<String>,
119 rounded: bool,
120 expr: Expr,
121 },
122 /// `ADD addends... TO to... [GIVING giving...]`
123 Add {
124 addends: Vec<Operand>,
125 to: Vec<String>,
126 giving: Vec<String>,
127 rounded: bool,
128 },
129 /// `SUBTRACT amounts... FROM from... [GIVING giving...]`
130 Subtract {
131 amounts: Vec<Operand>,
132 from: Vec<String>,
133 giving: Vec<String>,
134 rounded: bool,
135 },
136 /// `MULTIPLY left BY by [GIVING giving...]`
137 Multiply {
138 left: Operand,
139 by: Operand,
140 giving: Vec<String>,
141 rounded: bool,
142 },
143 /// `DIVIDE left {BY|INTO} right [GIVING giving...]`. `by_form` es
144 /// true para `BY` (`left/right`), false para `INTO` (`right/left`).
145 Divide {
146 left: Operand,
147 right: Operand,
148 by_form: bool,
149 giving: Vec<String>,
150 rounded: bool,
151 },
152 /// `IF cond [THEN] then_branch [ELSE else_branch] [END-IF]`
153 If {
154 cond: Cond,
155 then_branch: Vec<Stmt>,
156 else_branch: Vec<Stmt>,
157 },
158 /// `PERFORM ...` — ver [`Perform`].
159 Perform(Perform),
160 /// `GO TO target`
161 GoTo { target: String },
162 /// `STOP RUN`
163 StopRun,
164 /// `GOBACK`
165 Goback,
166 /// `EXIT` (y sus variantes `EXIT PROGRAM`/`PARAGRAPH`...).
167 Exit,
168 /// `CONTINUE` — el no-op de COBOL.
169 Continue,
170 /// Un verbo que la v1 no parsea: se conserva crudo para que las
171 /// etapas siguientes (o un humano) lo revisen.
172 Unknown { verb: String, tokens: Vec<Token> },
173}
174
175/// Un statement `PERFORM`: a quién ejecuta y cuántas veces.
176#[derive(Debug, Clone, PartialEq)]
177pub struct Perform {
178 pub target: PerformTarget,
179 pub control: PerformControl,
180}
181
182/// El cuerpo que un `PERFORM` ejecuta.
183#[derive(Debug, Clone, PartialEq)]
184pub enum PerformTarget {
185 /// `PERFORM PARA [THRU PARA2]` — ejecuta uno o un rango de párrafos.
186 Paragraph { name: String, thru: Option<String> },
187 /// `PERFORM ... statements ... END-PERFORM` — cuerpo en línea.
188 Inline(Vec<Stmt>),
189}
190
191/// Cuántas veces se ejecuta el cuerpo de un `PERFORM`.
192#[derive(Debug, Clone, PartialEq)]
193pub enum PerformControl {
194 /// Una sola vez.
195 Once,
196 /// `n TIMES`.
197 Times(Operand),
198 /// `UNTIL cond`.
199 Until(Cond),
200 /// `VARYING var FROM from BY by UNTIL until` — el bucle con
201 /// variable de control: `var = from`; mientras no se cumpla
202 /// `until`, ejecuta el cuerpo y hace `var = var + by`.
203 Varying {
204 var: String,
205 from: Operand,
206 by: Operand,
207 until: Cond,
208 },
209}