Compilar una aplicación es un cargo build de verdad: el proyecto generado depende de cobolt-ast y cobolt-runtime por ruta (path), así que las fuentes Rust de la plataforma tienen que existir en la máquina. Un IDE copiado por su cuenta a cualquier sitio no lleva ninguna, y toda compilación moría en el mismo punto, con un mensaje que tenía tres defectos: nombraba BuildOptions.workspace_root, una API interna de Rust que ningún usuario puede alcanzar; no listaba ninguna carpeta en la que hubiera mirado de verdad; y sus dos estrategias no podían tener éxito en una copia instalada — una sube desde el ejecutable buscando un manifiesto [workspace], y una instalación nunca está dentro del árbol de fuentes; la otra usaba la ruta grabada al compilar el binario, que es una carpeta de la máquina que lo compiló.
Código:
Build failed: could not locate the PowerRustCOBOL workspace crates: looked via
the running executable and the build-time path, but found no 'crates/cobolt-ast'.
Pass BuildOptions.workspace_root, or run the IDE from within the PowerRustCOBOL
source tree.
El SDK de la plataforma ahora se distribuye. SDK_CRATES nombra los diez crates contra los que compila de verdad una aplicación construida — el cierre por path = de cobolt-ast, cobolt-runtime y cobolt-form-host — dejando fuera los seis que solo construyen las herramientas, y un test demuestra que el conjunto es cerrado: ningún crate distribuido puede depender de uno que se quedó atrás. Prepararlo es un solo comando, cargo run -p cobolt-compiler --example stage_sdk -- <install-dir>, y cuesta 6.0 MB. El manifiesto de workspace preparado conserva [workspace.package] y [workspace.dependencies] — cada crate de la plataforma hereda de ellos version.workspace y serde = { workspace = true }, así que una carpeta crates/ sin ese manifiesto encima falla en cuanto cargo lee el primer miembro — y recorta members a exactamente lo copiado, cosa que fija un segundo test.
- Los crates no son todo el SDK. SDK_EXTRA_PATHS distribuye además assets/images/powerrustcobol-icon.png y assets/themes. El icono no es decoración: cobolt-form-host lo incrusta con include_bytes!, así que un árbol sin él no compila NINGUNA aplicación de formularios — y falla en el primer Build del desarrollador, no al preparar el SDK. Los temas importan más silenciosamente: sin ellos, un proyecto diseñado en Cobalt Steel o Neumorphic compila igualmente y sale en Liquid Glass sin aviso. Un SDK preparado ocupa 18.9 MB.
- sdk_covers_every_compile_time_asset recorre cada crate del SDK buscando rutas de include_bytes! / include_str! que salen del crate y falla cuando alguna no se distribuye. Esa guardia existe porque la primera versión de este cambio no copiaba assets/: el árbol preparado se resolvía limpio bajo cargo metadata — que lee manifiestos sin compilar — y luego moría en el icono.
- La búsqueda mira ahora donde una instalación coloca las cosas: junto al ejecutable, en una subcarpeta sdk/, un nivel más arriba y dentro de Resources de un bundle de macOS. Una carpeta solo califica cuando contiene A LA VEZ Cargo.toml y crates/cobolt-ast; exigir solo lo segundo es lo que dejaba pasar por válido un árbol copiado a medias. Cuando no se encuentra nada, el error nombra ahora cada carpeta que probó.
- Help -> Platform SDK Location fija la carpeta a mano para un checkout que vive en otra parte. Es un ajuste de todo el IDE (ui.toml, junto al idioma y a Beautify), nunca cobolt.toml: la ruta es una propiedad de esta máquina, y un colega que abra el mismo proyecto no debe heredar una carpeta que solo existe en el disco de otro. Una entrada en blanco significa "buscar automáticamente", no "usar el directorio de trabajo". El diálogo muestra qué carpeta está en vigor y si fue encontrada o elegida, y el ajuste llega también a la sonda de conflictos de External Crates y al escaneo de System-closure, no solo a Build.
=== PowerRustCOBOL 1.62.7 — 2026-08-25 ===
• Un bloque EXEC RUST en un segundo formulario nunca se ejecutaba
Una aplicación no es un solo programa. El COBOL generado del formulario principal es uno, y cada formulario que puede abrir es otro (051): cada uno corre en su propio intérprete, y todos resuelven un bloque compilado a través del registro ÚNICO del proceso. Tres piezas de esto trataban "el programa" como el archivo de entrada a solas, y un bloque escrito en cualquier otro formulario se colaba por las tres. Nunca llegaba a un compilador: Run decide entre el intérprete y una compilación preguntando si el programa contiene un bloque — el del formulario que se ejecuta, y solo ese. Un bloque en el manejador de eventos de un formulario hijo contestaba "no", así que el IDE arrancaba rcrun run-form, que por diseño no puede ejecutar un bloque. En Run no había nada mal; el fallo llegaba después, cuando el desarrollador pulsaba el botón que alcanzaba el bloque. La pregunta cubre ahora todos los formularios que contiene el proyecto, que es exactamente el conjunto que compila la build.
Compilar tampoco lo salvaba: exec_rust::generate recorría el programa de entrada, así que el bloque de un formulario hijo nunca se emitía ni se registraba — el binario construido fallaba en el mismo clic, tras una compilación que informó de éxito. La generación toma ahora todos los programas que el binario puede ejecutar. Y los ids colisionaban: los ids de bloque salen de un contador por análisis que empieza en cero, así que el primer bloque del formulario principal y el primero de un formulario hijo eran ambos 0. Emitir los dos sin arreglar eso habría sido peor que el bug: register(0, ...) dos veces, gana el último, y un botón ejecutando en silencio el Rust de otro formulario. parse_from continúa la numeración en su lugar, y el compilador la enhebra por todos los programas de formulario — los ids que lleva el AST y los que registra el módulo generado salen de una misma secuencia.
Un error de rustc dentro de un bloque nombra ahora EL FORMULARIO en el que se escribió. Un solo módulo contiene los bloques de todos los programas, así que el informe antiguo — siempre el archivo de entrada, en la línea propia del bloque — apuntaba al archivo que la build llamara main, con toda fiabilidad el equivocado cuando el error estaba en otra parte. Los bloques a nivel de elemento de todos los formularios se emiten juntos a ámbito de módulo, que es lo que hace que una fn auxiliar escrita en un formulario sea invocable desde un bloque de otro. Es el mismo compartir a nivel de proceso que la guía ya promete para el puente de objetos; era cierto para los handles y no para el código.
=== PowerRustCOBOL 1.62.8 — 2026-08-25 ===
• El COBOL-85 clásico ya compila: --source-format=fixed
El COBOL en imagen de tarjeta no compilaba. No "una parte": nada en absoluto. Ante la suite oficial de validación NIST COBOL-85 (CCVS85 4.0, 459 programas, 28 MB), RustCOBOL analizó 0 de ellos. Faltaban dos reglas del formato de referencia. Columnas 73-80: el estándar las reserva para el área de identificación y el compilador las ignora; nosotros las leíamos como fuente, así que cada línea de CCVS85 terminaba con su sello de programa — NC1014.2 — pegado a la sentencia, y el parser no encontraba PROGRAM-ID en un solo programa. Líneas de continuación: un guion en la columna 7 continúa la línea anterior; no las uníamos en absoluto — los fragmentos se emitían como líneas separadas, así que un literal partido en dos líneas dejaba una comilla sin pareja, y la regla de cadenas del léxer seguía más allá del fin de línea buscando su comilla de cierre, tragándose cantidades arbitrarias de programa. 396 de los 459 programas contienen un literal así. El síntoma era siempre el mismo y siempre engañoso: un expected PROCEDURE DIVISION a fin de archivo, señalando lejos de la causa.
Código:
rcrun run --source-format=fixed program.cbl
rcrun check --source-format=fixed program.cbl
Ambas reglas están ahora implementadas, tras un selector explícito. fixed es el formato de referencia clásico — área de secuencia, columna indicadora, fuente en las columnas 8-72, área de identificación descartada, líneas de continuación unidas para literales y para palabras. free (el valor por defecto), fixed-relaxed y auto son los otros valores; COBOLT_SOURCE_FORMAT fija un valor por defecto. Nada del comportamiento existente cambió: la lectura fixed relajada es una variante separada y sigue ejecutando una línea hasta donde el desarrollador la escribió. Eso importa: imponer el límite de 72 columnas en todas partes es lo que rompió EXEC RUST en los fuentes de formulario generados el 2026-08-05, ya que un .cbl generado abre con un rótulo cuyo * cae en la columna 7 y el Rust embebido no tiene ninguna regla de columnas. El formato estricto nunca se elige por detección — solo pidiéndolo.
Una decisión de criterio merece constar. Un carácter en la columna 7 que no es un indicador COBOL-85 se lee como fuente ORDINARIA, no se rechaza. CCVS85 usa el área del indicador como selector, marcando líneas opcionales con Y, P, C, S y otras once letras — 4.830 líneas Y solo de esa clase. Rechazarlas haría fallar la suite; descartarlas borraría código en silencio. Medido sobre la distribución intacta, solo el front end: 0 -> 224 de 459 (48.8 %), y el cubo de causa raíz expected PROCEDURE DIVISION cayó de 48 programas a 6. Lo que queda son lagunas reales del lenguaje — literales numéricos con punto decimal inicial, comas y puntos y comas separadores, FUNCTION x(ALL), CLOSE ... WITH LOCK — cada una especificada en specs/nist/.
=== PowerRustCOBOL 1.62.9 — 2026-08-25 ===
• Toda aplicación compilaba SQLite, así que toda compilación necesitaba un compilador de C
rusqlite está fijado con su feature bundled, que compila la amalgama en C de SQLite. cobolt-runtime la tomaba incondicionalmente, y toda aplicación generada depende de cobolt-runtime — así que un programa de consola que solo hace DISPLAY seguía construyendo una biblioteca C, y seguía necesitando una toolchain de C (link.exe en Windows, cc en el resto) además de rustc. BUILDING-en.md ya documentaba las tres cosas como requisitos que el desarrollador debe instalar; una de ellas la exigían programas que no le daban ningún uso. El fallo que producía no nombraba nada que el desarrollador hubiera escrito — un error del enlazador, contra una dependencia que nunca eligió — y aterrizaba en la máquina que compila, nunca en la que ejecuta.
El puente SQL es ahora una feature. La feature sql de cobolt-runtime lleva juntos SQLite, PostgreSQL y MySQL y está activada por defecto, así que rcrun, el IDE y todos los tests conservan la superficie que tenían. El manifiesto generado es lo único que la apaga, y lo hace para un programa del que la build puede demostrar que nunca alcanza un verbo SQL. libsqlite3-sys sale entonces por completo del grafo de dependencias, y la compilación necesita solo Rust. cobolt-form-host reenvía la misma feature en lugar de poseerla: Cargo une las features a lo largo de un grafo, así que una aplicación de formularios que recortara SQL del runtime lo habría recibido de vuelta directamente del host — un test fija ambas líneas, porque ese fallo es invisible: la compilación sigue funcionando y sigue necesitando la toolchain de C.
La lectura es deliberadamente tímida, porque equivocarse aquí es peor que desperdiciar: el IDE interpreta con el runtime completo, así que un programa mal juzgado funcionaría bajo Run Form y fallaría solo una vez compilado. La duda enlaza los drivers — un CALL que nombra un verbo SQL, un CALL cuyo destino es un elemento de datos en vez de un literal (el nombre solo se conoce en ejecución) o un bloque EXEC RUST que menciona los módulos SQL. Solo un programa donde no aparece nada de eso pierde SQL. El examen cubre el programa de cada formulario, no solo el de entrada, así que una base de datos abierta por un formulario hijo sigue enlazando. Si de algún modo llega un verbo que la build no pudo ver, el runtime dice qué decisión lo produjo y qué cambiar, en vez de informar de un fallo de conexión ordinario. Advertencia: native-tls sigue llegando a OpenSSL en Linux, así que HTTP y Maps siguen siendo allí una dependencia de biblioteca del sistema. Este cambio cubre solo SQLite.
=== PowerRustCOBOL 1.62.10 — 2026-08-25 ===
• Corregido — un literal numérico puede comenzar con punto decimal
.5 es un medio. COBOL-85 establece que un literal numérico únicamente no puede terminar con un punto decimal; uno inicial está permitido de forma explícita. RustCOBOL exigía un dígito delante, de modo que .999 se leía como un punto de fin de sentencia seguido del entero 999 — y como un punto sitúa al léxico en lo que considera un comienzo de línea, .00001 salía como un número de nivel. El daño era peor dentro de una llamada a función, donde el punto extraviado cerraba antes de tiempo la lista de argumentos; así es como el módulo de funciones intrínsecas de NIST escribe todas y cada una de sus pruebas, por lo que el módulo era en gran parte inalcanzable.
Código:
COMPUTE WS-NUM = FUNCTION ACOS(.999).
Ahora se admite en todos los lugares donde cabe un literal numérico: VALUE, MOVE, COMPUTE, condiciones, argumentos de FUNCTION, WHEN, valores de nivel 88 — incluidas las formas con signo (-.5, +.5) y, bajo DECIMAL-POINT IS COMMA, la escritura ,5. Los ceros iniciales son exactos: .000000001 es una milmillonésima, no una décima. Los dígitos escritos son los que fijan la escala, así que .000000001 * 1000000000 es exactamente 1 — comprobado ejecutando el programa y leyendo su salida, no con un parseo limpio. La distinción importa aquí: VALUE .11111 tampoco producía diagnóstico alguno antes de esta corrección; simplemente almacenaba el número equivocado, en silencio.
Qué no cambió: un punto seguido de un espacio o de un salto de línea sigue siendo un terminador de sentencia, y una PICTURE numérica editada que comienza con punto decimal — PIC .9999/99999,99999,99 — queda intacta. Las dos cosas se distinguen por la ausencia de espacio, que es como el propio COBOL-85 las separa; también es la razón de que esto se resuelva cuando el literal se parsea y no cuando se lexifica, donde una picture y un literal son indistinguibles. Un fuente malformado como MOVE X TO Y.5 sigue siendo un error de compilación en lugar de reinterpretarse en silencio. Medido sobre la suite NIST CCVS85, solo front end: dentro de alcance 222 -> 237 de 434 (51.2 % -> 54.6 %). Funciones intrínsecas 21 -> 29, Nucleus 25 -> 29, Sort/Merge 27 -> 30. Nueva suite de pruebas tests/cobol/numeric/leading-decimal-point.cbl (11 casos, con resumen cuantificado).
=== PowerRustCOBOL 1.62.11 — 2026-08-25 ===
• Corregido — los párrafos descriptivos de la IDENTIFICATION DIVISION
AUTHOR, INSTALLATION, DATE-WRITTEN, DATE-COMPILED, SECURITY — y REMARKS, que COBOL-85 eliminó pero que el fuente antiguo todavía arrastra — llevan un comment-entry: texto libre que puede contener palabras reservadas y puntos, y que se extiende hasta el siguiente encabezado de párrafo o de división. Tres cosas estaban mal. Primera: DATE-COMPILED no se manejaba nunca; al ser una palabra clave no llegaba a la rama genérica de párrafos, caía a través y terminaba la división antes de tiempo, con lo que el parser exigía un encabezado de división donde había un nombre de párrafo. Segunda: el texto terminaba en el primer punto, cuando un comment-entry es prosa y los contiene de forma rutinaria; de este ejemplo de la suite NIST, de nueve líneas, solo sobrevivía la primera. Tercera: las palabras reservadas del texto se tomaban literalmente — la recolección se detenía en el DATA de la tercera línea, concluía que había empezado la DATA DIVISION, buscaba DIVISION y encontraba AND.
Código:
INSTALLATION.
GENERAL SERVICES ADMINISTRATION
AUTOMATED DATA AND TELECOMMUNICATION SERVICE.
5203 LEESBURG PIKE SUITE 1100
FALLS CHURCH VIRGINIA 22041.
DATE-WRITTEN.
Una entrada ahora termina solo en un token que comienza una línea y que además parece un encabezado — una palabra clave de párrafo, o una palabra clave de división seguida de DIVISION. Hacen falta ambas mitades: la primera permite que la prosa contenga DATA, la segunda permite que una línea empiece legítimamente con esa palabra. La misma regla se aplicó a la comprobación de divisiones duplicadas, que examina tokens crudos antes del parseo; sin ella, SECURITY. SEE THE PROCEDURE DIVISION BELOW. se habría reportado como una PROCEDURE DIVISION redeclarada. INSTALLATION, SECURITY y REMARKS se reconocen únicamente dentro de la IDENTIFICATION DIVISION y deliberadamente no se convirtieron en palabras reservadas — un item de datos llamado SECURITY sigue funcionando.
Medido sobre la suite NIST CCVS85, solo front end: dentro de alcance 237 -> 241 de 434 (54.6 % -> 55.5 %), Debug 5 -> 9. El grupo de 32 programas que esto despejó es mayor que la ganancia: 9 de ellos son programas de Communication, que siguen fuera de alcance, y la mayoría del resto tropieza de inmediato con un segundo bloqueo. También destapó un defecto que esta corrección no puede arreglar: seis programas fallan ahora por una comilla suelta dentro de la prosa de un comment-entry — THE COMPILER"S ABILITY abre un literal que corre hasta la siguiente comilla en cualquier punto del archivo. El lexificado precede al parseo, así que el léxico no puede saber que está dentro de un comment-entry; la corrección pertenece al trabajo de literales sin terminar ya registrado en specs/nist/NIST-spec-literal-continuation.md R6.
=== PowerRustCOBOL 1.62.12 — 2026-08-25 ===
• Corregido — una sola comilla suelta podía desplazar un programa entero
Un literal ahora termina al final de su línea. Antes podía continuar más allá del salto de línea, a la caza de una comilla de cierre, y eso convertía una errata en algo mucho peor que una errata. Los programas donde se encontró el problema contienen cada uno un número par de comillas — nada estaba sin terminar. Una sola comilla dentro de prosa corriente, como el comentario *> THIS PROGRAM CHECKS THE COMPILER"S ABILITY TO HANDLE EIGHT, abría un literal que se cerraba en la siguiente comilla varias líneas más abajo, tragándose lo que hubiera en medio — en un caso, un encabezado ENVIRONMENT DIVISION entero — tras lo cual cada comilla restante del archivo se emparejaba con la pareja equivocada. Un solo carácter cambiaba la paridad del programa completo, y el error afloraba a cientos de líneas de su causa, o como un "expected PROCEDURE DIVISION" a fin de archivo sin nada que señalar.
Confinar un literal a su línea hace que el daño se autocorrija en el siguiente salto de línea: se reporta la línea infractora, y la línea siguiente vuelve a emparejarse correctamente. Un literal sin cerrar ahora lo dice, allí donde está escrito:
Código:
unterminated alphanumeric literal — a literal cannot span source lines. In fixed
format, continue it on the next line with `-` in column 7 and reopen with the
same quotation mark; in free format there is no continuation, so the literal
must fit on one line.
La continuación no se ve afectada: un - en la columna 7 sigue uniendo un literal entre líneas, sigue extendiendo el fragmento continuado hasta la columna 72 con sus espacios finales y sigue reensamblándolo byte a byte — ese trabajo ocurre en el preprocesador, antes de que el léxico vea nada. Verificado ejecutando programas y leyendo su salida, no con un parseo limpio: el HYPHEN-LINE de CCVS85 se reensambla exactamente a los 54 caracteres que declara su PICTURE X(54). Los bloques EXEC RUST tampoco se ven afectados — incluidas las cadenas multilínea propias de Rust — porque un bloque se captura por corte de offsets entre RUST y END-EXEC. Medido sobre la suite NIST CCVS85, solo front end: dentro de alcance 241 -> 242 de 434. Una ganancia pequeña por un grupo de 6 programas despejado, y la razón merece decirse: un programa ahora pasa, y cuatro avanzaron hasta SORT-PARA SECTION 69. — un número de prioridad de segmento, que es una carencia distinta. Segmentation sigue marcando 0 / 13, pero su verdadero bloqueo ya es visible.
=== PowerRustCOBOL 1.62.13 — 2026-08-26 ===
• Corregido — una coma es puntuación, no un error
COBOL-85 define una coma separadora y un punto y coma separador como una coma o un punto y coma seguidos de un espacio. Son pura decoración: pueden aparecer en cualquier lugar donde pueda aparecer un espacio y significan exactamente lo que significa un espacio. Todo desarrollador COBOL los escribe, y PowerRustCOBOL los rechazaba todos:
Código:
MOVE ZERO TO DN3, DN4.
CALL "SUB" USING TABLE-01, TABLE-02, DN3.
PROCEDURE DIVISION USING TABLE-1, TABLE-2, DN1.
READ SQ-FS1 ; AT END GO TO READ-EOF.
01 WRK-AN-X-18-1, REDEFINES WRK-XN-18-1 PIC A(18).
Los cinco casos parsean ahora, junto con cualquier otro lugar donde pueda aparecer un separador — listas de ENTRY, argumentos de FUNCTION, listas de literales de VALUE, listas OCCURS ... KEY, entradas SELECT. La coma se descarta en el léxico en lugar de saltarse en cada punto de la gramática, de modo que un sitio que nadie ha escrito todavía ya es correcto. Qué conserva su coma, porque una coma no seguida de espacio nunca es un separador: 1,5 bajo DECIMAL-POINT IS COMMA sigue siendo uno y medio, y en PIC ZZ,ZZ9.99 la coma sigue siendo la coma de edición de la plantilla — ambos sin cambios.
• Corregido — subíndices separados por espacios
El único separador que COBOL-85 exige entre subíndices es un espacio. MOVE 1 TO CELL (1 2). y MOVE 1 TO CELL (1, 2). son la misma referencia, y antes solo parseaba la segunda.
• Corregido — un subíndice tras un nombre calificado
COBOL-85 coloca el subíndice después del nombre calificado completo — data-name-1 [OF data-name-2]... [(subíndice...)]. Ese orden era imposible de parsear en cualquiera de sus dos escrituras, por ejemplo MOVE W-3 TO CELL OF COLS OF ROWS (IDX-A IDX-B). El subíndice solo se leía antes de la cadena de OF, así que la lista final caía en la regla ordinaria de expresión entre paréntesis y reportaba expected RParen en el segundo subíndice. Ahora se aceptan ambos órdenes.
• Corregido — una comilla duplicada dentro de un literal
COBOL-85 no tiene escape con barra invertida. El propio delimitador de un literal se escribe dos veces, de modo que 'IT''S' es el valor de cuatro caracteres IT'S y """" es una sola comilla. El léxico no decodificaba la duplicación: 'IT''S' se convertía, en silencio, en los dos literales separados IT y S, así que DISPLAY 'IT''S WORKING'. mostraba IT ... S WORKING. El preprocesador de formato de fuente sí había implementado esta regla desde siempre al decidir si una línea de formato fijo termina dentro de un literal, con lo que las dos mitades del compilador discrepaban sobre el mismo texto.
• Corregido — un Caption con apóstrofo o con salto de línea rompía la compilación