⎇ fa65f202065abca26e0fb28581427117b84af85c
crates/modules/charka/charka-ir/src/ast.rs
History
Who touched what
raw
feat(charka): INITIALIZE — resetear datos y grupos
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 árbol de [`DataItem`] tal cual lo produjo `charka-parser`,
12 /// con su estructura de grupos.
13 pub data: Vec<DataItem>,
14 /// El modelo de datos resuelto: los datos elementales aplanados y
15 /// los nombres de condición (nivel 88).
16 pub model: crate::model::DataModel,
17 /// Los párrafos del PROCEDURE, con sus statements ya tipados.
18 pub procedures: Vec<Procedure>,
19}
20
21/// Un párrafo del PROCEDURE: un nombre y un cuerpo de statements.
22#[derive(Debug, Clone, PartialEq, Default)]
23pub struct Procedure {
24 /// Nombre del párrafo en mayúsculas; "" para el párrafo implícito.
25 pub name: String,
26 /// Los statements del párrafo, en orden.
27 pub body: Vec<Stmt>,
28}
29
30/// Un operando: lo que puede ir donde se espera un valor.
31#[derive(Debug, Clone, PartialEq)]
32pub enum Operand {
33 /// Referencia a un dato, por nombre (en mayúsculas).
34 Data(String),
35 /// Referencia a un elemento de tabla: `name(index)`. El subíndice
36 /// es 1-based, como en COBOL.
37 Indexed { name: String, index: Box<Operand> },
38 /// Literal numérico (texto, posiblemente con signo).
39 Num(String),
40 /// Literal de texto.
41 Str(String),
42 /// Constante figurativa (`ZERO`, `SPACE`...).
43 Figurative(Figurative),
44}
45
46/// Las constantes figurativas de COBOL.
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub enum Figurative {
49 Zero,
50 Space,
51 HighValue,
52 LowValue,
53 Quote,
54 Null,
55}
56
57/// Una expresión aritmética (la parte derecha de un `COMPUTE`).
58#[derive(Debug, Clone, PartialEq)]
59pub enum Expr {
60 /// Un operando hoja.
61 Operand(Operand),
62 /// Negación unaria.
63 Neg(Box<Expr>),
64 /// Operación binaria.
65 Binary {
66 op: BinOp,
67 lhs: Box<Expr>,
68 rhs: Box<Expr>,
69 },
70}
71
72/// Operador aritmético binario.
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub enum BinOp {
75 Add,
76 Sub,
77 Mul,
78 Div,
79 /// Exponenciación (`**`).
80 Pow,
81}
82
83/// Una condición (la guarda de un `IF` o de un `PERFORM UNTIL`).
84#[derive(Debug, Clone, PartialEq)]
85pub enum Cond {
86 /// Comparación relacional `lhs op rhs`.
87 Compare {
88 lhs: Operand,
89 op: CmpOp,
90 rhs: Operand,
91 },
92 /// Un nombre de condición (un dato de nivel 88) usado solo.
93 Named(String),
94 /// Negación lógica.
95 Not(Box<Cond>),
96 /// Conjunción lógica.
97 And(Box<Cond>, Box<Cond>),
98 /// Disyunción lógica.
99 Or(Box<Cond>, Box<Cond>),
100}
101
102/// Operador relacional.
103#[derive(Debug, Clone, Copy, PartialEq, Eq)]
104pub enum CmpOp {
105 Eq,
106 Ne,
107 Lt,
108 Gt,
109 Le,
110 Ge,
111}
112
113/// Un statement del PROCEDURE division.
114#[derive(Debug, Clone, PartialEq)]
115pub enum Stmt {
116 /// `MOVE from TO to...`
117 Move { from: Operand, to: Vec<Operand> },
118 /// `DISPLAY items...`
119 Display { items: Vec<Operand> },
120 /// `ACCEPT into`
121 Accept { into: Operand },
122 /// `COMPUTE targets... [ROUNDED] = expr`
123 Compute {
124 targets: Vec<Operand>,
125 rounded: bool,
126 expr: Expr,
127 },
128 /// `ADD addends... TO to... [GIVING giving...]`
129 Add {
130 addends: Vec<Operand>,
131 to: Vec<Operand>,
132 giving: Vec<Operand>,
133 rounded: bool,
134 },
135 /// `SUBTRACT amounts... FROM from... [GIVING giving...]`
136 Subtract {
137 amounts: Vec<Operand>,
138 from: Vec<Operand>,
139 giving: Vec<Operand>,
140 rounded: bool,
141 },
142 /// `MULTIPLY left BY by [GIVING giving...]`
143 Multiply {
144 left: Operand,
145 by: Operand,
146 giving: Vec<Operand>,
147 rounded: bool,
148 },
149 /// `DIVIDE left {BY|INTO} right [GIVING giving...]`. `by_form` es
150 /// true para `BY` (`left/right`), false para `INTO` (`right/left`).
151 Divide {
152 left: Operand,
153 right: Operand,
154 by_form: bool,
155 giving: Vec<Operand>,
156 rounded: bool,
157 },
158 /// `IF cond [THEN] then_branch [ELSE else_branch] [END-IF]`
159 If {
160 cond: Cond,
161 then_branch: Vec<Stmt>,
162 else_branch: Vec<Stmt>,
163 },
164 /// `EVALUATE subject WHEN ... [WHEN OTHER ...] END-EVALUATE` — el
165 /// `case` de COBOL. Una rama se elige si `subject` es igual a
166 /// alguno de sus valores; sin caída entre ramas.
167 Evaluate {
168 subject: Operand,
169 whens: Vec<WhenBranch>,
170 /// El cuerpo de `WHEN OTHER` (vacío si no hay).
171 other: Vec<Stmt>,
172 },
173 /// `STRING sources... DELIMITED BY SIZE INTO into` — concatena el
174 /// texto de los `sources` en `into`.
175 StringConcat {
176 sources: Vec<Operand>,
177 into: Operand,
178 },
179 /// `UNSTRING source DELIMITED BY delimiter INTO into...` — parte el
180 /// texto de `source` por `delimiter` y reparte los trozos.
181 Unstring {
182 source: Operand,
183 delimiter: Operand,
184 into: Vec<Operand>,
185 },
186 /// `INSPECT target ...` — cuenta o reemplaza caracteres.
187 Inspect { target: Operand, op: InspectOp },
188 /// `INITIALIZE targets...` — pone cada dato (o grupo) en su valor
189 /// por defecto: 0 los numéricos, espacios los alfanuméricos.
190 Initialize { targets: Vec<Operand> },
191 /// `PERFORM ...` — ver [`Perform`].
192 Perform(Perform),
193 /// `GO TO target`
194 GoTo { target: String },
195 /// `STOP RUN`
196 StopRun,
197 /// `GOBACK`
198 Goback,
199 /// `EXIT` (y sus variantes `EXIT PROGRAM`/`PARAGRAPH`...).
200 Exit,
201 /// `CONTINUE` — el no-op de COBOL.
202 Continue,
203 /// Un verbo que la v1 no parsea: se conserva crudo para que las
204 /// etapas siguientes (o un humano) lo revisen.
205 Unknown { verb: String, tokens: Vec<Token> },
206}
207
208/// La operación de un `INSPECT`.
209#[derive(Debug, Clone, PartialEq)]
210pub enum InspectOp {
211 /// `TALLYING counter FOR ALL search` — suma a `counter` la cantidad
212 /// de apariciones de `search` en el destino.
213 TallyingForAll { counter: Operand, search: Operand },
214 /// `REPLACING ALL from BY to` — reemplaza las apariciones de `from`.
215 ReplacingAll { from: Operand, to: Operand },
216}
217
218/// Cómo una rama `WHEN` decide si se dispara.
219#[derive(Debug, Clone, PartialEq)]
220pub enum WhenTest {
221 /// El sujeto es igual a este valor.
222 Value(Operand),
223 /// El sujeto está en el rango `[lo, hi]` (`WHEN lo THRU hi`).
224 Range(Operand, Operand),
225 /// La condición se cumple — la forma `EVALUATE TRUE WHEN cond`.
226 Cond(Cond),
227}
228
229/// Una rama `WHEN` de un `EVALUATE`: las pruebas que la disparan
230/// (varios `WHEN` apilados comparten cuerpo) y el cuerpo a ejecutar.
231/// La rama se dispara si **alguna** de sus pruebas pasa.
232#[derive(Debug, Clone, PartialEq)]
233pub struct WhenBranch {
234 pub tests: Vec<WhenTest>,
235 pub body: Vec<Stmt>,
236}
237
238/// Un statement `PERFORM`: a quién ejecuta y cuántas veces.
239#[derive(Debug, Clone, PartialEq)]
240pub struct Perform {
241 pub target: PerformTarget,
242 pub control: PerformControl,
243}
244
245/// El cuerpo que un `PERFORM` ejecuta.
246#[derive(Debug, Clone, PartialEq)]
247pub enum PerformTarget {
248 /// `PERFORM PARA [THRU PARA2]` — ejecuta uno o un rango de párrafos.
249 Paragraph { name: String, thru: Option<String> },
250 /// `PERFORM ... statements ... END-PERFORM` — cuerpo en línea.
251 Inline(Vec<Stmt>),
252}
253
254/// Cuántas veces se ejecuta el cuerpo de un `PERFORM`.
255#[derive(Debug, Clone, PartialEq)]
256pub enum PerformControl {
257 /// Una sola vez.
258 Once,
259 /// `n TIMES`.
260 Times(Operand),
261 /// `UNTIL cond`.
262 Until(Cond),
263 /// `VARYING var FROM from BY by UNTIL until` — el bucle con
264 /// variable de control: `var = from`; mientras no se cumpla
265 /// `until`, ejecuta el cuerpo y hace `var = var + by`.
266 Varying {
267 var: String,
268 from: Operand,
269 by: Operand,
270 until: Cond,
271 },
272}