feat(charka): charka-ir — representación intermedia con statements tipados

Tercera etapa del transpilador: Program -> Ir. El PROCEDURE division
pasa de sentencias con tokens crudos a un árbol de instrucciones
tipadas.

- lower(&Program) -> Ir: total y tolerante, nunca falla. La DATA
  division pasa tal cual y sirve de tabla de símbolos.
- Stmt cubre MOVE, DISPLAY, ACCEPT, COMPUTE, ADD, SUBTRACT, MULTIPLY,
  DIVIDE, IF/ELSE/END-IF, PERFORM (fuera de línea, en línea, TIMES,
  UNTIL), GO TO, STOP RUN, GOBACK, EXIT, CONTINUE.
- Expresiones de COMPUTE con precedencia y paréntesis (Pratt).
  Condiciones con comparadores símbolo/palabra, AND/OR/NOT y nombres
  de condición (nivel 88).
- Delimita statements por palabras frontera (COBOL no los separa con
  un símbolo). Verbo no soportado -> Stmt::Unknown con tokens crudos.
- Módulos: ast / kw / cursor / expr / stmt. 17 tests; fmt + clippy
  limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-21 20:23:19 +00:00
parent b95383b01a
commit 71a4068d12
11 changed files with 1462 additions and 4 deletions
+101
View File
@@ -0,0 +1,101 @@
//! Predicados sobre las palabras clave de COBOL. COBOL no termina los
//! statements con un símbolo: una sentencia es una secuencia de
//! statements que se delimitan por la aparición del siguiente verbo.
//! Estos predicados le dicen al parser dónde corta un statement.
/// ¿Es `w` un verbo que inicia un statement? (En mayúsculas.)
pub(crate) fn is_verb(w: &str) -> bool {
matches!(
w,
"ACCEPT"
| "ADD"
| "ALTER"
| "CALL"
| "CANCEL"
| "CLOSE"
| "COMPUTE"
| "CONTINUE"
| "DELETE"
| "DISPLAY"
| "DIVIDE"
| "EVALUATE"
| "EXIT"
| "GO"
| "GOBACK"
| "IF"
| "INITIALIZE"
| "INSPECT"
| "MERGE"
| "MOVE"
| "MULTIPLY"
| "OPEN"
| "PERFORM"
| "READ"
| "RELEASE"
| "RETURN"
| "REWRITE"
| "SEARCH"
| "SET"
| "SORT"
| "START"
| "STOP"
| "STRING"
| "SUBTRACT"
| "UNSTRING"
| "WRITE"
)
}
/// ¿Es `w` un terminador de ámbito (`END-IF`, `ELSE`, `WHEN`...)?
pub(crate) fn is_terminator(w: &str) -> bool {
matches!(
w,
"ELSE"
| "WHEN"
| "END-IF"
| "END-PERFORM"
| "END-EVALUATE"
| "END-ADD"
| "END-SUBTRACT"
| "END-MULTIPLY"
| "END-DIVIDE"
| "END-COMPUTE"
| "END-READ"
| "END-WRITE"
| "END-CALL"
| "END-STRING"
| "END-UNSTRING"
| "END-SEARCH"
| "END-START"
| "END-DELETE"
| "END-REWRITE"
| "END-RETURN"
)
}
/// ¿Es `w` una palabra de conexión de una cláusula (`TO`, `GIVING`...)?
fn is_connector(w: &str) -> bool {
matches!(
w,
"TO" | "FROM"
| "GIVING"
| "BY"
| "INTO"
| "THRU"
| "THROUGH"
| "UNTIL"
| "TIMES"
| "ROUNDED"
| "THEN"
| "WITH"
| "UPON"
| "REMAINDER"
| "VARYING"
)
}
/// ¿Marca `w` el final de una lista de operandos o de nombres? Es así
/// para todo verbo, terminador o conector — ninguno puede ser un dato.
pub(crate) fn is_boundary(w: &str) -> bool {
is_verb(w) || is_terminator(w) || is_connector(w)
}