tawasuyu

tawasuyu/brahman

Rust 582TOML 222Markdown 83JSON 198635 Definiciones

⎇ 82ba0b7a1a04b7ff2d7e2175ac74766da0d16066 crates/modules/charka/charka-ir/src/ast.rs Rust · 275 líneas · 8.0 KB Historia Quién tocó qué crudo

feat(charka): SET ... TO TRUE — escribir nombres de condición (88) 82ba0b7a1 · sergio ·

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}