⎇ 82ba0b7a1a04b7ff2d7e2175ac74766da0d16066
crates/modules/charka/charka-ir/src/ast.rs
History
Who touched what
raw
feat(charka): SET ... TO TRUE — escribir nombres de condición (88)
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 /// `SET cond-name... TO TRUE` — hace verdaderos esos nombres de
192 /// condición (nivel 88): asigna a su dato padre el valor del 88.
193 SetTrue { conditions: Vec<String> },
194 /// `PERFORM ...` — ver [`Perform`].
195 Perform(Perform),
196 /// `GO TO target`
197 GoTo { target: String },
198 /// `STOP RUN`
199 StopRun,
200 /// `GOBACK`
201 Goback,
202 /// `EXIT` (y sus variantes `EXIT PROGRAM`/`PARAGRAPH`...).
203 Exit,
204 /// `CONTINUE` — el no-op de COBOL.
205 Continue,
206 /// Un verbo que la v1 no parsea: se conserva crudo para que las
207 /// etapas siguientes (o un humano) lo revisen.
208 Unknown { verb: String, tokens: Vec<Token> },
209}
210
211/// La operación de un `INSPECT`.
212#[derive(Debug, Clone, PartialEq)]
213pub enum InspectOp {
214 /// `TALLYING counter FOR ALL search` — suma a `counter` la cantidad
215 /// de apariciones de `search` en el destino.
216 TallyingForAll { counter: Operand, search: Operand },
217 /// `REPLACING ALL from BY to` — reemplaza las apariciones de `from`.
218 ReplacingAll { from: Operand, to: Operand },
219}
220
221/// Cómo una rama `WHEN` decide si se dispara.
222#[derive(Debug, Clone, PartialEq)]
223pub enum WhenTest {
224 /// El sujeto es igual a este valor.
225 Value(Operand),
226 /// El sujeto está en el rango `[lo, hi]` (`WHEN lo THRU hi`).
227 Range(Operand, Operand),
228 /// La condición se cumple — la forma `EVALUATE TRUE WHEN cond`.
229 Cond(Cond),
230}
231
232/// Una rama `WHEN` de un `EVALUATE`: las pruebas que la disparan
233/// (varios `WHEN` apilados comparten cuerpo) y el cuerpo a ejecutar.
234/// La rama se dispara si **alguna** de sus pruebas pasa.
235#[derive(Debug, Clone, PartialEq)]
236pub struct WhenBranch {
237 pub tests: Vec<WhenTest>,
238 pub body: Vec<Stmt>,
239}
240
241/// Un statement `PERFORM`: a quién ejecuta y cuántas veces.
242#[derive(Debug, Clone, PartialEq)]
243pub struct Perform {
244 pub target: PerformTarget,
245 pub control: PerformControl,
246}
247
248/// El cuerpo que un `PERFORM` ejecuta.
249#[derive(Debug, Clone, PartialEq)]
250pub enum PerformTarget {
251 /// `PERFORM PARA [THRU PARA2]` — ejecuta uno o un rango de párrafos.
252 Paragraph { name: String, thru: Option<String> },
253 /// `PERFORM ... statements ... END-PERFORM` — cuerpo en línea.
254 Inline(Vec<Stmt>),
255}
256
257/// Cuántas veces se ejecuta el cuerpo de un `PERFORM`.
258#[derive(Debug, Clone, PartialEq)]
259pub enum PerformControl {
260 /// Una sola vez.
261 Once,
262 /// `n TIMES`.
263 Times(Operand),
264 /// `UNTIL cond`.
265 Until(Cond),
266 /// `VARYING var FROM from BY by UNTIL until` — el bucle con
267 /// variable de control: `var = from`; mientras no se cumpla
268 /// `until`, ejecuta el cuerpo y hace `var = var + by`.
269 Varying {
270 var: String,
271 from: Operand,
272 by: Operand,
273 until: Cond,
274 },
275}