codexivo 0.2.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  # Codexivo v1 — Especificación del lenguaje
2
2
 
3
- > **Estado:** aprobada. Se implementa por pasos (§16). Lo que ya funciona está en
4
- > [`lenguaje.md`](./lenguaje.md), y todos sus ejemplos se prueban automáticamente.
3
+ > **Estado:** implementada en la versión 1.0.0 (§16). Lo que funciona está en [`lenguaje.md`](./lenguaje.md), y todos sus
4
+ > ejemplos se prueban automáticamente.
5
5
  >
6
6
  > Las secciones marcadas con **✅ Decidido** fueron decisiones abiertas que ya se resolvieron.
7
7
 
@@ -429,24 +429,26 @@ calculadora.suma(1, 3); // 4
429
429
 
430
430
  ## 7. Errores
431
431
 
432
- Cada error es un objeto, no solo un texto:
432
+ Cada error es un objeto, no solo un texto. Los campos de la API van en inglés, como el resto (`kind`, `span`); todo lo que
433
+ lee quien aprende va en español:
433
434
 
434
435
  ```ts
435
436
  {
436
- tipo: "léxico" | "sintaxis" | "ejecución" | "límite",
437
- código: "DIVISIÓN_ENTRE_CERO",
438
- mensaje: "No se puede dividir entre cero.",
439
- pista: "Revisa que `divisor` no valga 0 antes de dividir.",
440
- inicio: { línea: 4, columna: 12 },
441
- fin: { línea: 4, columna: 23 },
442
- pila: ["programa", "promedio(lista)"]
437
+ kind: "léxico" | "sintaxis" | "ejecución" | "límite",
438
+ code: "DIVISIÓN_ENTRE_CERO",
439
+ message: "No se puede dividir entre cero.",
440
+ hint: "Revisa que `divisor` no valga 0 antes de dividir.",
441
+ span: { start: { line: 4, column: 12, offset: 80 }, end: { line: 4, column: 23, offset: 91 } },
442
+ callStack: ["programa", "promedio"]
443
443
  }
444
444
  ```
445
445
 
446
+ Cada `code` tiene una explicación larga en el catálogo (`catalog.errors`).
447
+
446
448
  - Los mensajes dicen **qué pasó** y la pista **qué revisar**, en español correcto y con acentos.
447
449
  - El parser se recupera y reporta varios errores, pero el sandbox destaca el primero.
448
- - `afirmar(condición, mensaje)` detiene el programa si la condición es falsa. Es la herramienta más
449
- directa para practicar verificación.
450
+ - `afirmar(condición, mensaje)` detiene el programa con `AFIRMACIÓN_FALLIDA` si la condición es falsa; el mensaje
451
+ es opcional. Es la herramienta más directa para practicar verificación.
450
452
  - Sin `intentar`/`capturar` en v1: un error detiene el programa, y eso es lo que queremos que se vea.
451
453
 
452
454
  ## 8. Biblioteca estándar
@@ -655,13 +657,16 @@ estáticos y `según`/`caso`. Se pueden reconsiderar después, siempre con el pr
655
657
 
656
658
  Codexivo no tiene usuarios todavía, así que v1 se permite romper compatibilidad:
657
659
 
658
- - condiciones estrictas (si se aprueba §4.5);
660
+ - condiciones estrictas (§4.5);
659
661
  - error al llamar con un número distinto de argumentos;
660
662
  - error al redeclarar o al asignar sin declarar;
661
663
  - `agregar` pasa a modificar la lista (antes regresaba una nueva);
662
664
  - un procedimiento sin `regresa` regresa `nulo` (antes regresaba el valor de su última expresión);
663
665
  - `1 / 0` pasa a ser error;
664
- - `ARREGLO` pasa a llamarse `lista` en mensajes y en `tipo()`.
666
+ - `ARREGLO` pasa a llamarse `lista` en mensajes y en `tipo()`;
667
+ - palabras reservadas nuevas (§2.5): `constante`, `dominio`, `repetir`, `veces`, `desde`, `hasta`, `con_paso`,
668
+ `para_cada`, `en`, `romper`, `continuar`, `mod`, `div` y las comparaciones en palabras ya no sirven como nombres;
669
+ - sin `;`, el salto de línea termina la expresión (§2.4): una expresión partida antes de un operador es un error.
665
670
 
666
671
  ## 15. Decisiones
667
672
 
package/docs/lenguaje.md CHANGED
@@ -381,14 +381,15 @@ Todo está disponible sin importar nada. Los nombres con acento también se acep
381
381
 
382
382
  ### Entrada, salida y tipos
383
383
 
384
- | Procedimiento | Qué hace |
385
- | ----------------------- | -------------------------------------------------------------------------------------------------------- |
386
- | `imprimir(a, b, …)` | Escribe los valores separados por un espacio y termina la línea |
387
- | `leer()` | Siguiente línea de entrada como texto, o `nulo` si ya no hay |
388
- | `leer_número()` | Siguiente línea de entrada como número |
389
- | `tipo(x)` | `"número"`, `"texto"`, `"lógico"`, `"nulo"`, `"lista"`, `"diccionario"`, `"dominio"` o `"procedimiento"` |
390
- | `texto(x)`, `número(x)` | Conversiones explícitas |
391
- | `longitud(x)` | Caracteres de un texto, elementos de una lista o claves de un diccionario |
384
+ | Procedimiento | Qué hace |
385
+ | ------------------------------ | -------------------------------------------------------------------------------------------------------- |
386
+ | `imprimir(a, b, …)` | Escribe los valores separados por un espacio y termina la línea |
387
+ | `leer()` | Siguiente línea de entrada como texto, o `nulo` si ya no hay |
388
+ | `leer_número()` | Siguiente línea de entrada como número |
389
+ | `tipo(x)` | `"número"`, `"texto"`, `"lógico"`, `"nulo"`, `"lista"`, `"diccionario"`, `"dominio"` o `"procedimiento"` |
390
+ | `texto(x)`, `número(x)` | Conversiones explícitas |
391
+ | `longitud(x)` | Caracteres de un texto, elementos de una lista o claves de un diccionario |
392
+ | `afirmar(condición, mensaje?)` | Detiene el programa si la condición es falsa (ver [Errores](#errores)) |
392
393
 
393
394
  ### Matemáticas
394
395
 
@@ -493,6 +494,19 @@ Error de ejecución en la línea 2, columna 5: No se puede dividir entre cero.
493
494
  Pista: Revisa que el divisor no valga 0 antes de dividir.
494
495
  ```
495
496
 
497
+ Con `afirmar` se escribe lo que se espera que sea cierto. Si no lo es, el programa se detiene en esa línea, antes de que el
498
+ error llegue más lejos:
499
+
500
+ ```codexivo
501
+ variable precio = 120
502
+ variable descuento = 20
503
+ variable total = precio - descuento
504
+ afirmar(total es_menor_que precio, "el descuento tenía que bajar el precio")
505
+ imprimir("Total:", total)
506
+ ```
507
+
508
+ Un error detiene el programa: no hay forma de atraparlo y seguir, porque lo que se busca es verlo.
509
+
496
510
  ## Puente hacia otros lenguajes
497
511
 
498
512
  Muchos lenguajes (C, Java, JavaScript) cuentan con un `for` de tres partes. Codexivo también lo tiene, para practicar antes de
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codexivo",
3
- "version": "0.2.3",
3
+ "version": "1.0.0",
4
4
  "description": "Lenguaje de programación en español para practicar lógica y algoritmos, que se ejecuta en el navegador.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/catalog.ts CHANGED
@@ -227,6 +227,7 @@ const library: ProcedureEntry[] = [
227
227
  const CATEGORIES: ProcedureCategory[] = [
228
228
  'entrada y salida',
229
229
  'tipos',
230
+ 'verificación',
230
231
  'matemáticas',
231
232
  'texto',
232
233
  'listas',
@@ -186,6 +186,11 @@ export const ERROR_CODES: Readonly<Record<string, { kind: ErrorKind; explanation
186
186
  },
187
187
 
188
188
  // ejecución
189
+ AFIRMACIÓN_FALLIDA: {
190
+ kind: 'ejecución',
191
+ explanation:
192
+ 'Una llamada a `afirmar(condición, mensaje)` encontró que su condición era falsa. Afirmar es escribir lo que esperas que sea cierto en ese punto del programa; si no lo es, el programa se detiene ahí, antes de que el error llegue más lejos. Revisa los valores de las variables justo antes de esa línea.',
193
+ },
189
194
  CANTIDAD_DE_ARGUMENTOS: {
190
195
  kind: 'ejecución',
191
196
  explanation:
@@ -358,6 +358,50 @@ const library: NativeValue[] = [
358
358
  },
359
359
  ),
360
360
 
361
+ // verificación
362
+ define(
363
+ 'afirmar',
364
+ [1, 2],
365
+ {
366
+ level: 'principiante',
367
+ category: 'verificación',
368
+ params: [
369
+ { name: 'condición', type: 'lógico' },
370
+ { name: 'mensaje', type: 'texto', optional: true },
371
+ ],
372
+ returns: 'nulo',
373
+ description:
374
+ 'Detiene el programa con un error si la condición es falsa. Sirve para escribir lo que esperas que sea cierto y comprobarlo.',
375
+ examples: [
376
+ { code: 'variable total = 2 + 2\nafirmar(total es_igual_a 4, "la suma está mal")\ntotal', result: '4' },
377
+ ],
378
+ },
379
+ (args, context) => {
380
+ const condition = args[0]!;
381
+ if (typeof condition !== 'boolean') {
382
+ throw context.fail(
383
+ 'TIPO_DE_ARGUMENTO',
384
+ `\`afirmar\` espera una condición \`verdadero\` o \`falso\`, pero recibió ${describeType(typeOf(condition))} (${repr(condition)}).`,
385
+ '¿Quisiste comparar? Por ejemplo: `afirmar(x es_mayor_que 0)`.',
386
+ );
387
+ }
388
+ const message = args[1];
389
+ if (message !== undefined && typeof message !== 'string') {
390
+ throw context.fail(
391
+ 'TIPO_DE_ARGUMENTO',
392
+ `El mensaje de \`afirmar\` tiene que ser un texto, pero es ${describeType(typeOf(message))}.`,
393
+ 'Escribe el mensaje entre comillas: `afirmar(x es_mayor_que 0, "x tenía que ser positivo")`.',
394
+ );
395
+ }
396
+ if (condition) return null;
397
+ throw context.fail(
398
+ 'AFIRMACIÓN_FALLIDA',
399
+ message ? `La afirmación no se cumplió: ${message}` : 'La afirmación no se cumplió.',
400
+ 'Lo que afirmaste que era cierto no lo es en este punto. Revisa los valores de las variables justo antes de esta línea.',
401
+ );
402
+ },
403
+ ),
404
+
361
405
  // matemáticas
362
406
  define(
363
407
  'absoluto',
@@ -68,6 +68,7 @@ export type ProcedureLevel = 'principiante' | 'intermedio' | 'avanzado';
68
68
  export type ProcedureCategory =
69
69
  | 'entrada y salida'
70
70
  | 'tipos'
71
+ | 'verificación'
71
72
  | 'matemáticas'
72
73
  | 'texto'
73
74
  | 'listas'