⎇ 28ee1ae2602662b216549ba4db0d34a9b55b8deb
crates/modules/charka/charka-ir/src/ast.rs
Ñawpa willay
Pi imata llamkarqan
ch'uya
feat(charka): nivel 88 + modelo de datos compartido en charka-ir
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 /// Literal numérico (texto, posiblemente con signo).
36 Num(String),
37 /// Literal de texto.
38 Str(String),
39 /// Constante figurativa (`ZERO`, `SPACE`...).
40 Figurative(Figurative),
41}
42
43/// Las constantes figurativas de COBOL.
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum Figurative {
46 Zero,
47 Space,
48 HighValue,
49 LowValue,
50 Quote,
51 Null,
52}
53
54/// Una expresión aritmética (la parte derecha de un `COMPUTE`).
55#[derive(Debug, Clone, PartialEq)]
56pub enum Expr {
57 /// Un operando hoja.
58 Operand(Operand),
59 /// Negación unaria.
60 Neg(Box<Expr>),
61 /// Operación binaria.
62 Binary {
63 op: BinOp,
64 lhs: Box<Expr>,
65 rhs: Box<Expr>,
66 },
67}
68
69/// Operador aritmético binario.
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71pub enum BinOp {
72 Add,
73 Sub,
74 Mul,
75 Div,
76 /// Exponenciación (`**`).
77 Pow,
78}
79
80/// Una condición (la guarda de un `IF` o de un `PERFORM UNTIL`).
81#[derive(Debug, Clone, PartialEq)]
82pub enum Cond {
83 /// Comparación relacional `lhs op rhs`.
84 Compare {
85 lhs: Operand,
86 op: CmpOp,
87 rhs: Operand,
88 },
89 /// Un nombre de condición (un dato de nivel 88) usado solo.
90 Named(String),
91 /// Negación lógica.
92 Not(Box<Cond>),
93 /// Conjunción lógica.
94 And(Box<Cond>, Box<Cond>),
95 /// Disyunción lógica.
96 Or(Box<Cond>, Box<Cond>),
97}
98
99/// Operador relacional.
100#[derive(Debug, Clone, Copy, PartialEq, Eq)]
101pub enum CmpOp {
102 Eq,
103 Ne,
104 Lt,
105 Gt,
106 Le,
107 Ge,
108}
109
110/// Un statement del PROCEDURE division.
111#[derive(Debug, Clone, PartialEq)]
112pub enum Stmt {
113 /// `MOVE from TO to...`
114 Move { from: Operand, to: Vec<String> },
115 /// `DISPLAY items...`
116 Display { items: Vec<Operand> },
117 /// `ACCEPT into`
118 Accept { into: String },
119 /// `COMPUTE targets... [ROUNDED] = expr`
120 Compute {
121 targets: Vec<String>,
122 rounded: bool,
123 expr: Expr,
124 },
125 /// `ADD addends... TO to... [GIVING giving...]`
126 Add {
127 addends: Vec<Operand>,
128 to: Vec<String>,
129 giving: Vec<String>,
130 rounded: bool,
131 },
132 /// `SUBTRACT amounts... FROM from... [GIVING giving...]`
133 Subtract {
134 amounts: Vec<Operand>,
135 from: Vec<String>,
136 giving: Vec<String>,
137 rounded: bool,
138 },
139 /// `MULTIPLY left BY by [GIVING giving...]`
140 Multiply {
141 left: Operand,
142 by: Operand,
143 giving: Vec<String>,
144 rounded: bool,
145 },
146 /// `DIVIDE left {BY|INTO} right [GIVING giving...]`. `by_form` es
147 /// true para `BY` (`left/right`), false para `INTO` (`right/left`).
148 Divide {
149 left: Operand,
150 right: Operand,
151 by_form: bool,
152 giving: Vec<String>,
153 rounded: bool,
154 },
155 /// `IF cond [THEN] then_branch [ELSE else_branch] [END-IF]`
156 If {
157 cond: Cond,
158 then_branch: Vec<Stmt>,
159 else_branch: Vec<Stmt>,
160 },
161 /// `EVALUATE subject WHEN ... [WHEN OTHER ...] END-EVALUATE` — el
162 /// `case` de COBOL. Una rama se elige si `subject` es igual a
163 /// alguno de sus valores; sin caída entre ramas.
164 Evaluate {
165 subject: Operand,
166 whens: Vec<WhenBranch>,
167 /// El cuerpo de `WHEN OTHER` (vacío si no hay).
168 other: Vec<Stmt>,
169 },
170 /// `PERFORM ...` — ver [`Perform`].
171 Perform(Perform),
172 /// `GO TO target`
173 GoTo { target: String },
174 /// `STOP RUN`
175 StopRun,
176 /// `GOBACK`
177 Goback,
178 /// `EXIT` (y sus variantes `EXIT PROGRAM`/`PARAGRAPH`...).
179 Exit,
180 /// `CONTINUE` — el no-op de COBOL.
181 Continue,
182 /// Un verbo que la v1 no parsea: se conserva crudo para que las
183 /// etapas siguientes (o un humano) lo revisen.
184 Unknown { verb: String, tokens: Vec<Token> },
185}
186
187/// Una rama `WHEN` de un `EVALUATE`: los valores que la disparan
188/// (varios `WHEN` apilados comparten cuerpo) y el cuerpo a ejecutar.
189#[derive(Debug, Clone, PartialEq)]
190pub struct WhenBranch {
191 pub values: Vec<Operand>,
192 pub body: Vec<Stmt>,
193}
194
195/// Un statement `PERFORM`: a quién ejecuta y cuántas veces.
196#[derive(Debug, Clone, PartialEq)]
197pub struct Perform {
198 pub target: PerformTarget,
199 pub control: PerformControl,
200}
201
202/// El cuerpo que un `PERFORM` ejecuta.
203#[derive(Debug, Clone, PartialEq)]
204pub enum PerformTarget {
205 /// `PERFORM PARA [THRU PARA2]` — ejecuta uno o un rango de párrafos.
206 Paragraph { name: String, thru: Option<String> },
207 /// `PERFORM ... statements ... END-PERFORM` — cuerpo en línea.
208 Inline(Vec<Stmt>),
209}
210
211/// Cuántas veces se ejecuta el cuerpo de un `PERFORM`.
212#[derive(Debug, Clone, PartialEq)]
213pub enum PerformControl {
214 /// Una sola vez.
215 Once,
216 /// `n TIMES`.
217 Times(Operand),
218 /// `UNTIL cond`.
219 Until(Cond),
220 /// `VARYING var FROM from BY by UNTIL until` — el bucle con
221 /// variable de control: `var = from`; mientras no se cumpla
222 /// `until`, ejecuta el cuerpo y hace `var = var + by`.
223 Varying {
224 var: String,
225 from: Operand,
226 by: Operand,
227 until: Cond,
228 },
229}