codexivo 0.0.0-stage → 0.2.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.
- package/CHANGELOG.md +15 -0
- package/README.md +158 -2
- package/bin/codexivo.exe +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +20 -0
- package/docs/README.md +25 -0
- package/docs/arquitectura.md +92 -0
- package/docs/especificacion-v1.md +595 -0
- package/docs/guia-aprender-desde-el-codigo.md +91 -0
- package/docs/lenguaje.md +162 -0
- package/docs/recetario.md +159 -0
- package/docs/repl.md +64 -0
- package/package.json +75 -4
- package/postinstall.mjs +38 -0
- package/src/engine.ts +97 -0
- package/src/errors.ts +56 -0
- package/src/index.ts +29 -0
- package/src/runtime/builtins.ts +133 -0
- package/src/runtime/compiler.ts +252 -0
- package/src/runtime/machine.ts +847 -0
- package/src/runtime/suggest.ts +33 -0
- package/src/runtime/values.ts +140 -0
- package/src/syntax/ast.ts +230 -0
- package/src/syntax/lexer.ts +232 -0
- package/src/syntax/parser.ts +666 -0
- package/src/syntax/token.ts +167 -0
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
# Codexivo v1 — Especificación del lenguaje
|
|
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.
|
|
5
|
+
>
|
|
6
|
+
> Las secciones marcadas con **✅ Decidido** fueron decisiones abiertas que ya se resolvieron.
|
|
7
|
+
|
|
8
|
+
## 0. Para qué existe este documento
|
|
9
|
+
|
|
10
|
+
Codexivo es un lenguaje para **practicar lógica**, no para construir productos. Si hoy una IA puede
|
|
11
|
+
escribir el código, lo que sigue siendo humano es entenderlo y verificarlo. Esta especificación define
|
|
12
|
+
un lenguaje que sirva para eso desde el primer `imprimir` hasta un recorrido en anchura sobre un grafo.
|
|
13
|
+
|
|
14
|
+
Principios, en orden de prioridad cuando chocan:
|
|
15
|
+
|
|
16
|
+
1. **Visible.** Todo lo que el lenguaje hace debe poder mostrarse paso a paso: cada decisión, cada
|
|
17
|
+
vuelta, cada valor. Si una característica no se puede visualizar con honestidad, no entra.
|
|
18
|
+
2. **Sin magia.** No hay conversiones implícitas ni comportamientos sorpresa. Cuando algo no tiene
|
|
19
|
+
sentido, el programa se detiene y explica por qué.
|
|
20
|
+
3. **Verbal y en español.** Palabras antes que símbolos, con `ñ` y acentos. Los símbolos clásicos se
|
|
21
|
+
conservan como alternativa porque el siguiente lenguaje que aprenda la persona los va a usar.
|
|
22
|
+
4. **Simple.** Pocos tipos, una sola forma recomendada de hacer cada cosa y nada de módulos ni
|
|
23
|
+
`importar`: todo lo necesario ya está disponible.
|
|
24
|
+
5. **En el navegador y determinista.** Sin instalar nada. El mismo programa con la misma entrada
|
|
25
|
+
produce siempre el mismo resultado y la misma cantidad de operaciones.
|
|
26
|
+
|
|
27
|
+
### Niveles
|
|
28
|
+
|
|
29
|
+
Cada característica pertenece a un nivel. Los niveles ordenan la documentación y los retos; no
|
|
30
|
+
bloquean nada en el editor.
|
|
31
|
+
|
|
32
|
+
| Nivel | Qué se practica |
|
|
33
|
+
| ------------------- | ---------------------------------------------------------------------- |
|
|
34
|
+
| 🟢 **Principiante** | Secuencia, variables, entrada/salida, condiciones, bucles |
|
|
35
|
+
| 🟡 **Intermedio** | Procedimientos, listas, texto, diccionarios, recursión |
|
|
36
|
+
| 🔴 **Avanzado** | Procedimientos como valores, estructuras de datos, algoritmos clásicos |
|
|
37
|
+
|
|
38
|
+
## 1. Estado actual frente a v1
|
|
39
|
+
|
|
40
|
+
Probado contra `main` (`1ca0398`), cuyos 56 tests pasaban sin cubrir estos casos. La columna "Estado" dice qué ya resolvió
|
|
41
|
+
la reescritura del núcleo (pasos 1 a 3 de §16).
|
|
42
|
+
|
|
43
|
+
| Caso | Antes | v1 | Estado |
|
|
44
|
+
| -------------------------------- | ---------------------------------------------------------------------------------------------------- | ----------------------------------------- | ---------------------------------- |
|
|
45
|
+
| `1 < 2 y 5 < 4` | Error. `y`/`o` tenían **más** precedencia que las comparaciones y se agrupaba como `1 < (2 y 5) < 4` | `falso` | ✅ |
|
|
46
|
+
| `no 1 == 2` | `falso` (se agrupaba como `(no 1) == 2`) | `verdadero` | ✅ |
|
|
47
|
+
| Varios `pero_si` seguidos | Solo se conservaba el último | Todas las ramas, en orden | ✅ |
|
|
48
|
+
| `procedimiento suma(a, b) { … }` | Error de sintaxis | Declaración con nombre | Paso 5 (hoy da un error con pista) |
|
|
49
|
+
| `// comentario` | Excepción de JavaScript (`value is null or undefined`) | Comentario | ✅ |
|
|
50
|
+
| `%`, `n++`, `n--` | Error de sintaxis | Soportados | Paso 4 |
|
|
51
|
+
| `a[0] = 9` | Error de sintaxis | Asignación por índice | Paso 5 |
|
|
52
|
+
| `nulo` | "identificador no encontrado" | Literal | ✅ |
|
|
53
|
+
| `imprimir(…)` / `leer()` | No existían; el programa solo devolvía su última expresión | Entrada y salida | ✅ |
|
|
54
|
+
| `1 / 0` | `Infinity` (el error `DIVISION_BY_ZERO` existía pero no se usaba) | Error | ✅ |
|
|
55
|
+
| `[1, 2] == [1, 2]` | `falso` | `verdadero` | ✅ |
|
|
56
|
+
| `mientras (verdadero) {}` | Bloqueaba el proceso | Error al superar el límite de operaciones | ✅ |
|
|
57
|
+
| `f(20000)` recursivo | `Maximum call stack size exceeded` | Funciona (límite configurable) | ✅ |
|
|
58
|
+
| `hasta_que` | Se tokenizaba como `WHILE` | Token propio `UNTIL` | ✅ |
|
|
59
|
+
| Mensajes de error | "en la linea" | "en la línea", con pista | ✅ |
|
|
60
|
+
| Docs y README | Usaban `sino`, `n++`, `%` y procedimientos con nombre que nunca funcionaron | Alineados con esta spec | ✅ (y se prueban) |
|
|
61
|
+
|
|
62
|
+
## 2. Léxico
|
|
63
|
+
|
|
64
|
+
### 2.1 Identificadores
|
|
65
|
+
|
|
66
|
+
- Letras del alfabeto latino con acentos y diéresis (`á é í ó ú ü ñ` y mayúsculas), dígitos y `_`.
|
|
67
|
+
- No pueden empezar con dígito. Distinguen mayúsculas de minúsculas.
|
|
68
|
+
- Convención recomendada: `minúsculas_con_guion_bajo`.
|
|
69
|
+
|
|
70
|
+
```codexivo
|
|
71
|
+
variable año = 2026;
|
|
72
|
+
variable canción_favorita = "Cielito lindo";
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 2.2 Comentarios
|
|
76
|
+
|
|
77
|
+
```codexivo
|
|
78
|
+
// comentario de una línea
|
|
79
|
+
/* comentario
|
|
80
|
+
de varias líneas */
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 2.3 Literales
|
|
84
|
+
|
|
85
|
+
| Literal | Ejemplos | Notas |
|
|
86
|
+
| ----------- | ------------------------------------- | ----------------------------------------------------------------------- |
|
|
87
|
+
| Número | `10`, `3.14`, `.5`, `1_000_000` | Un solo tipo numérico (doble precisión). `_` solo como separador visual |
|
|
88
|
+
| Texto | `"hola"`, `'mundo'`, `"línea\nnueva"` | Escapes: `\n`, `\t`, `\"`, `\'`, `\\` |
|
|
89
|
+
| Lógico | `verdadero`, `falso` | |
|
|
90
|
+
| Nulo | `nulo` | Ausencia de valor |
|
|
91
|
+
| Lista | `[1, 2, 3]`, `[]` | |
|
|
92
|
+
| Diccionario | `{ "nombre": "Ana", "edad": 16 }` | Ver §4.6 |
|
|
93
|
+
|
|
94
|
+
> **✅ Decidido — interpolación de texto.** ¿`"Hola, {nombre}"`? No en v1. `imprimir("Hola,", nombre)` resuelve el caso común sin agregar sintaxis
|
|
95
|
+
> dentro de las cadenas, y `texto(x)` cubre el resto.
|
|
96
|
+
|
|
97
|
+
### 2.4 Punto y coma
|
|
98
|
+
|
|
99
|
+
Separa sentencias. Es **opcional al final de línea**, como hoy; la documentación y el formateador del
|
|
100
|
+
sandbox siempre lo escriben.
|
|
101
|
+
|
|
102
|
+
### 2.5 Palabras reservadas
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
variable constante procedimiento regresa
|
|
106
|
+
si pero_si si_no
|
|
107
|
+
mientras hacer hasta_que para para_cada en repetir veces
|
|
108
|
+
romper continuar
|
|
109
|
+
verdadero falso nulo
|
|
110
|
+
y o no mod div
|
|
111
|
+
es_igual_a es_distinto_de es_menor_que es_mayor_que
|
|
112
|
+
es_menor_o_igual_a es_mayor_o_igual_a
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 2.6 Regla de acentos
|
|
116
|
+
|
|
117
|
+
Todo nombre que en español lleva acento lo lleva en su forma canónica (`máximo`, `número`,
|
|
118
|
+
`último`), y **también se acepta sin acento** (`maximo`, `numero`, `ultimo`), porque no todos los
|
|
119
|
+
teclados lo facilitan. La documentación y los mensajes usan siempre la forma canónica.
|
|
120
|
+
|
|
121
|
+
## 3. Tipos y valores
|
|
122
|
+
|
|
123
|
+
| Tipo (`tipo(x)`) | Valores |
|
|
124
|
+
| ----------------- | --------------------------------------------- |
|
|
125
|
+
| `"número"` | `0`, `-3`, `2.5` |
|
|
126
|
+
| `"texto"` | `"hola"` |
|
|
127
|
+
| `"lógico"` | `verdadero`, `falso` |
|
|
128
|
+
| `"nulo"` | `nulo` |
|
|
129
|
+
| `"lista"` | `[1, "a", verdadero]` |
|
|
130
|
+
| `"diccionario"` | `{ "a": 1 }` |
|
|
131
|
+
| `"procedimiento"` | Procedimientos del usuario y de la biblioteca |
|
|
132
|
+
|
|
133
|
+
- **Valor contra referencia.** Números, textos, lógicos y `nulo` se copian. Las listas y los
|
|
134
|
+
diccionarios se comparten: dos variables pueden apuntar a la misma lista. El sandbox lo dibuja con
|
|
135
|
+
flechas, porque es uno de los errores más comunes y más difíciles de ver.
|
|
136
|
+
- **Texto inmutable.** `t[0] = "x"` es un error; se construye un texto nuevo.
|
|
137
|
+
|
|
138
|
+
> **✅ Decidido — nombre del tipo de las listas.** Antes los errores decían `ARREGLO`. Ahora es `lista` en la superficie (docs, `tipo()`, mensajes). Es la palabra que alguien
|
|
139
|
+
> usa antes de saber qué es un arreglo, y "arreglo" se explica en los docs avanzados.
|
|
140
|
+
|
|
141
|
+
## 4. Expresiones
|
|
142
|
+
|
|
143
|
+
### 4.1 Precedencia (de menor a mayor)
|
|
144
|
+
|
|
145
|
+
| Nivel | Operadores | Asociatividad |
|
|
146
|
+
| ----- | ---------------------------------------------------- | ----------------- |
|
|
147
|
+
| 1 | `o` | izquierda |
|
|
148
|
+
| 2 | `y` | izquierda |
|
|
149
|
+
| 3 | `no` (`!`) | prefijo |
|
|
150
|
+
| 4 | `==` `!=` `<` `>` `<=` `>=` y sus formas en palabras | **sin encadenar** |
|
|
151
|
+
| 5 | `+` `-` | izquierda |
|
|
152
|
+
| 6 | `*` `/` `div` `mod` (`%`) | izquierda |
|
|
153
|
+
| 7 | `-` unario | prefijo |
|
|
154
|
+
| 8 | `^` (potencia) | **derecha** |
|
|
155
|
+
| 9 | llamada `f(x)`, índice `l[i]`, acceso `d.campo` | izquierda |
|
|
156
|
+
|
|
157
|
+
- `1 < x < 5` es un error con la pista _"escribe `1 < x y x < 5`"_. Encadenar comparaciones se ve
|
|
158
|
+
natural pero esconde dos comparaciones.
|
|
159
|
+
- `-2 ^ 2` es `-4`, como en matemáticas.
|
|
160
|
+
|
|
161
|
+
### 4.2 Operadores en palabras
|
|
162
|
+
|
|
163
|
+
Cada forma en palabras es **exactamente equivalente** a su símbolo. El sandbox puede mostrar
|
|
164
|
+
cualquiera de las dos.
|
|
165
|
+
|
|
166
|
+
| Símbolo | Palabra | Ejemplo |
|
|
167
|
+
| ------- | -------------------- | ------------------------------------- |
|
|
168
|
+
| `==` | `es_igual_a` | `si (respuesta es_igual_a 42)` |
|
|
169
|
+
| `!=` | `es_distinto_de` | `mientras (letra es_distinto_de "x")` |
|
|
170
|
+
| `<` | `es_menor_que` | `edad es_menor_que 18` |
|
|
171
|
+
| `>` | `es_mayor_que` | `puntos es_mayor_que récord` |
|
|
172
|
+
| `<=` | `es_menor_o_igual_a` | `i es_menor_o_igual_a 10` |
|
|
173
|
+
| `>=` | `es_mayor_o_igual_a` | `edad es_mayor_o_igual_a 18` |
|
|
174
|
+
| `%` | `mod` | `n mod 2 == 0` |
|
|
175
|
+
| — | `div` | `7 div 2` → `3` |
|
|
176
|
+
| `!` | `no` | `no encontrado` |
|
|
177
|
+
|
|
178
|
+
No hay `&&` ni `||`: solo `y` / `o`.
|
|
179
|
+
|
|
180
|
+
### 4.3 Aritmética
|
|
181
|
+
|
|
182
|
+
- `/` es división real: `7 / 2` → `3.5`.
|
|
183
|
+
- `div` es división entera hacia abajo: `7 div 2` → `3`, `-7 div 2` → `-4`.
|
|
184
|
+
- `mod` / `%` es el residuo consistente con `div`: `a == (a div b) * b + (a mod b)`. Así
|
|
185
|
+
`-7 mod 3` → `2`, que es lo que se espera al preguntar "¿es par?" o al dar vueltas en un círculo.
|
|
186
|
+
- Dividir entre cero (con `/`, `div` o `mod`) es un error.
|
|
187
|
+
- `+` suma números o une textos. **No mezcla**: `"Total: " + 5` es un error con la pista
|
|
188
|
+
_"convierte el número con `texto(5)` o usa `imprimir("Total:", 5)`"_.
|
|
189
|
+
|
|
190
|
+
### 4.4 Comparación e igualdad
|
|
191
|
+
|
|
192
|
+
- `==` compara por valor, también listas y diccionarios: `[1, 2] == [1, 2]` → `verdadero`.
|
|
193
|
+
- Comparar tipos distintos con `==` regresa `falso`. Con `<`, `>`, `<=`, `>=` es un error.
|
|
194
|
+
- Los textos se comparan en orden alfabético por carácter.
|
|
195
|
+
|
|
196
|
+
### 4.5 Lógica
|
|
197
|
+
|
|
198
|
+
`y` y `o` evalúan en cortocircuito; la visualización muestra cuándo una parte **no** se evaluó.
|
|
199
|
+
|
|
200
|
+
> **✅ Decidido — condiciones estrictas.** Antes `si (1)` funcionaba porque `0`, `""` y `nulo`
|
|
201
|
+
> contaban como falsos. En v1 las condiciones de `si`, `mientras`, `hasta_que`, `y`, `o` y `no` deben ser
|
|
202
|
+
> lógicas. `si (lista)` es un error con la pista _"¿quisiste decir `longitud(lista) > 0`?"_. Obliga a
|
|
203
|
+
> decir lo que uno quiere decir, que es justo lo que se practica.
|
|
204
|
+
|
|
205
|
+
### 4.6 Listas y diccionarios
|
|
206
|
+
|
|
207
|
+
```codexivo
|
|
208
|
+
variable números = [3, 1, 2];
|
|
209
|
+
números[0]; // 3
|
|
210
|
+
números[-1]; // 2 (desde el final)
|
|
211
|
+
números[0] = 10;
|
|
212
|
+
|
|
213
|
+
variable persona = { "nombre": "Ana", "edad": 16 };
|
|
214
|
+
persona["nombre"]; // "Ana"
|
|
215
|
+
persona.edad; // 16, azúcar para persona["edad"]
|
|
216
|
+
persona.ciudad = "León"; // agrega la clave
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
- Índices enteros desde `0`. Fuera de rango es un error que muestra el índice y la longitud.
|
|
220
|
+
- Las claves de un diccionario son textos o números. `d.campo` solo funciona con claves que sean
|
|
221
|
+
identificadores válidos.
|
|
222
|
+
- Leer una clave que no existe es un error con la pista _"usa `tiene(d, clave)` para preguntar
|
|
223
|
+
antes"_.
|
|
224
|
+
- Al inicio de una sentencia, `{` abre un bloque; en cualquier otra posición, un diccionario.
|
|
225
|
+
|
|
226
|
+
## 5. Sentencias
|
|
227
|
+
|
|
228
|
+
### 5.1 Variables y constantes
|
|
229
|
+
|
|
230
|
+
```codexivo
|
|
231
|
+
variable contador = 0;
|
|
232
|
+
constante PI = 3.14159;
|
|
233
|
+
contador = contador + 1;
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
- Asignar a una variable no declarada es un error: _"¿olvidaste escribir `variable`?"_.
|
|
237
|
+
- Declarar dos veces el mismo nombre en el mismo bloque es un error.
|
|
238
|
+
- Reasignar una `constante` es un error.
|
|
239
|
+
- **Alcance por bloque:** lo declarado dentro de `{ }` deja de existir al cerrar el bloque.
|
|
240
|
+
- Un nombre local puede ocultar uno de la biblioteca (`variable máximo = 0;`); el editor lo advierte.
|
|
241
|
+
|
|
242
|
+
### 5.2 Asignación compuesta, incremento y decremento
|
|
243
|
+
|
|
244
|
+
```codexivo
|
|
245
|
+
total += precio; // también -=, *=, /=, %=
|
|
246
|
+
i++;
|
|
247
|
+
i--;
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
`++` y `--` son **sentencias**, no expresiones: `x = i++` es un error. Así desaparece la pregunta de
|
|
251
|
+
"¿`i++` o `++i`?".
|
|
252
|
+
|
|
253
|
+
### 5.3 Condiciones
|
|
254
|
+
|
|
255
|
+
```codexivo
|
|
256
|
+
si (edad >= 18) {
|
|
257
|
+
imprimir("adulto");
|
|
258
|
+
} pero_si (edad >= 13) {
|
|
259
|
+
imprimir("adolescente");
|
|
260
|
+
} si_no {
|
|
261
|
+
imprimir("niño");
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Las llaves son obligatorias.
|
|
266
|
+
|
|
267
|
+
> **✅ Decidido — `según`/`caso`** (equivalente a `switch`): fuera de v1. Una cadena de `pero_si` cubre lo mismo y no hay que
|
|
268
|
+
> explicar por qué un caso "se cae" al siguiente.
|
|
269
|
+
|
|
270
|
+
### 5.4 Bucles
|
|
271
|
+
|
|
272
|
+
```codexivo
|
|
273
|
+
// 🟢 repite un número fijo de veces (herencia directa de Karel)
|
|
274
|
+
repetir 4 veces {
|
|
275
|
+
avanzar();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// 🟢 mientras la condición sea verdadera
|
|
279
|
+
mientras (intentos < 3) {
|
|
280
|
+
intentos++;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// 🟢 al menos una vez, hasta que la condición sea verdadera
|
|
284
|
+
hacer {
|
|
285
|
+
número = leer_número();
|
|
286
|
+
} hasta_que (número > 0);
|
|
287
|
+
|
|
288
|
+
// 🟡 recorrer una lista, un rango o un texto
|
|
289
|
+
para_cada fruta en ["mango", "piña"] {
|
|
290
|
+
imprimir(fruta);
|
|
291
|
+
}
|
|
292
|
+
para_cada i en rango(1, 10) {
|
|
293
|
+
imprimir(i);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// 🟡 recorrer un diccionario
|
|
297
|
+
para_cada clave, valor en persona {
|
|
298
|
+
imprimir(clave, valor);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// 🟡 forma clásica, puente hacia otros lenguajes
|
|
302
|
+
para (variable i = 0; i < 10; i++) {
|
|
303
|
+
imprimir(i);
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
- `romper` sale del bucle más cercano; `continuar` salta a la siguiente vuelta.
|
|
308
|
+
- `repetir n veces` exige un número entero no negativo.
|
|
309
|
+
- Modificar la longitud de una lista mientras se recorre con `para_cada` es un error.
|
|
310
|
+
|
|
311
|
+
### 5.5 Procedimientos
|
|
312
|
+
|
|
313
|
+
```codexivo
|
|
314
|
+
// 🟡 declaración con nombre
|
|
315
|
+
procedimiento área_rectángulo(base, altura) {
|
|
316
|
+
regresa base * altura;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// 🔴 como valor
|
|
320
|
+
variable doble = procedimiento(x) { regresa x * 2; };
|
|
321
|
+
mapear([1, 2, 3], doble); // [2, 4, 6]
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
- Las declaraciones con nombre se pueden usar antes de aparecer en su bloque; eso permite la
|
|
325
|
+
recursión mutua.
|
|
326
|
+
- Llamar con un número distinto de argumentos es un error. Hoy los faltantes se rellenan con `nulo`;
|
|
327
|
+
en v1 no.
|
|
328
|
+
- `regresa` sin valor regresa `nulo`, y un procedimiento que termina sin `regresa` también regresa `nulo`.
|
|
329
|
+
El valor de la última expresión **no** se regresa solo: devolver un valor siempre se dice con `regresa`.
|
|
330
|
+
- Los procedimientos capturan las variables de donde se crearon (closures).
|
|
331
|
+
- La profundidad de recursión solo la limita la configuración (por defecto 10 000), no JavaScript.
|
|
332
|
+
|
|
333
|
+
## 6. Entrada y salida
|
|
334
|
+
|
|
335
|
+
| Procedimiento | Qué hace |
|
|
336
|
+
| ------------------- | --------------------------------------------------------------------------- |
|
|
337
|
+
| `imprimir(a, b, …)` | Escribe los valores separados por un espacio y termina la línea |
|
|
338
|
+
| `leer()` | Lee la siguiente línea de entrada como texto. Si no hay más, regresa `nulo` |
|
|
339
|
+
| `leer_número()` | Lee la siguiente línea y la convierte en número; si no es un número, error |
|
|
340
|
+
|
|
341
|
+
- En el **sandbox libre**, `leer()` pausa el programa y pide el dato en la consola.
|
|
342
|
+
- En los **retos**, la entrada viene del caso de prueba.
|
|
343
|
+
- El valor de la última expresión se sigue mostrando en el REPL y en el sandbox como "resultado",
|
|
344
|
+
pero los retos solo comparan la salida o el valor regresado (§10).
|
|
345
|
+
|
|
346
|
+
## 7. Errores
|
|
347
|
+
|
|
348
|
+
Cada error es un objeto, no solo un texto:
|
|
349
|
+
|
|
350
|
+
```ts
|
|
351
|
+
{
|
|
352
|
+
tipo: "léxico" | "sintaxis" | "ejecución" | "límite",
|
|
353
|
+
código: "DIVISIÓN_ENTRE_CERO",
|
|
354
|
+
mensaje: "No se puede dividir entre cero.",
|
|
355
|
+
pista: "Revisa que `divisor` no valga 0 antes de dividir.",
|
|
356
|
+
inicio: { línea: 4, columna: 12 },
|
|
357
|
+
fin: { línea: 4, columna: 23 },
|
|
358
|
+
pila: ["programa", "promedio(lista)"]
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
- Los mensajes dicen **qué pasó** y la pista **qué revisar**, en español correcto y con acentos.
|
|
363
|
+
- El parser se recupera y reporta varios errores, pero el sandbox destaca el primero.
|
|
364
|
+
- `afirmar(condición, mensaje)` detiene el programa si la condición es falsa. Es la herramienta más
|
|
365
|
+
directa para practicar verificación.
|
|
366
|
+
- Sin `intentar`/`capturar` en v1: un error detiene el programa, y eso es lo que queremos que se vea.
|
|
367
|
+
|
|
368
|
+
## 8. Biblioteca estándar
|
|
369
|
+
|
|
370
|
+
Todo es global; no existe `importar`. Regla para listas: **`agregar`, `insertar`, `quitar` y `vaciar`
|
|
371
|
+
cambian la lista; todo lo demás regresa un valor nuevo.**
|
|
372
|
+
|
|
373
|
+
### 🟢 Básicos
|
|
374
|
+
|
|
375
|
+
| Nombre | Descripción |
|
|
376
|
+
| --------------------------------- | -------------------------------------------------------------- |
|
|
377
|
+
| `imprimir`, `leer`, `leer_número` | §6 |
|
|
378
|
+
| `tipo(x)` | Nombre del tipo (§3) |
|
|
379
|
+
| `texto(x)`, `número(x)` | Conversiones explícitas |
|
|
380
|
+
| `longitud(x)` | Elementos de una lista o diccionario, o caracteres de un texto |
|
|
381
|
+
| `afirmar(cond, mensaje)` | §7 |
|
|
382
|
+
|
|
383
|
+
### 🟢 Matemáticas
|
|
384
|
+
|
|
385
|
+
`absoluto`, `máximo(…)`, `mínimo(…)`, `redondear(x, decimales?)`, `piso`, `techo`, `raíz`, `entero`
|
|
386
|
+
(trunca), `aleatorio(a, b)` (entero entre `a` y `b` inclusive), la constante `PI`.
|
|
387
|
+
|
|
388
|
+
`aleatorio` usa una semilla por ejecución. El sandbox la muestra y permite repetirla, así un programa
|
|
389
|
+
"aleatorio" se puede depurar.
|
|
390
|
+
|
|
391
|
+
### 🟡 Texto
|
|
392
|
+
|
|
393
|
+
`mayúsculas`, `minúsculas`, `recortar`, `dividir(t, separador)`, `unir(lista, separador)`,
|
|
394
|
+
`reemplazar(t, buscar, poner)`, `contiene`, `empieza_con`, `termina_con`, `posición_de` (regresa `-1`
|
|
395
|
+
si no está), `subtexto(t, inicio, fin)`, `caracteres(t)`, `código_de(c)`, `carácter_de(n)`.
|
|
396
|
+
|
|
397
|
+
### 🟡 Listas
|
|
398
|
+
|
|
399
|
+
| Nombre | Descripción |
|
|
400
|
+
| -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
401
|
+
| `agregar(l, x)` · `insertar(l, i, x)` | Cambian la lista |
|
|
402
|
+
| `quitar(l, i)` · `quitar_último(l)` · `quitar_primero(l)` · `vaciar(l)` | Cambian la lista; los tres primeros regresan lo que quitaron |
|
|
403
|
+
| `primero`, `último`, `contiene`, `posición_de` | Consulta |
|
|
404
|
+
| `rango(a, b, paso?)` | Lista de `a` a `b` **inclusive** |
|
|
405
|
+
| `índices(l)` | `rango(0, longitud(l) - 1)` |
|
|
406
|
+
| `rebanar(l, inicio, fin)`, `invertir(l)`, `ordenar(l, comparador?)`, `copiar(l)` | Nuevas listas |
|
|
407
|
+
| `sumar(l)`, `lista_de(n, valor)`, `matriz(filas, columnas, valor)` | Construcción y resumen. `lista_de` y `matriz` copian el valor en cada casilla, para no compartir sublistas por accidente |
|
|
408
|
+
|
|
409
|
+
> **✅ Decidido — `rango` inclusivo.** `rango(1, 10)` incluye el 10. Es como lo dice una persona ("del 1 al 10"); `índices(l)` evita el
|
|
410
|
+
> `- 1` en el caso típico.
|
|
411
|
+
|
|
412
|
+
### 🟡 Diccionarios
|
|
413
|
+
|
|
414
|
+
`claves(d)`, `valores(d)`, `tiene(d, clave)`, `quitar(d, clave)`. El orden de recorrido es el de
|
|
415
|
+
inserción.
|
|
416
|
+
|
|
417
|
+
### 🔴 Procedimientos como valores
|
|
418
|
+
|
|
419
|
+
`mapear(l, f)`, `filtrar(l, f)`, `reducir(l, f, inicial)`, `alguno(l, f)`, `todos(l, f)`,
|
|
420
|
+
`buscar(l, f)` (el primero que cumple, o `nulo`).
|
|
421
|
+
|
|
422
|
+
### 🔴 Estructuras de datos
|
|
423
|
+
|
|
424
|
+
Pilas y colas son listas con un vocabulario propio, para que el algoritmo se lea como se explica:
|
|
425
|
+
|
|
426
|
+
| Pila | Cola | Equivale a |
|
|
427
|
+
| -------------- | --------------- | -------------------- |
|
|
428
|
+
| `apilar(p, x)` | `encolar(c, x)` | `agregar` |
|
|
429
|
+
| `desapilar(p)` | — | `quitar_último` |
|
|
430
|
+
| — | `desencolar(c)` | `quitar_primero` |
|
|
431
|
+
| `tope(p)` | `frente(c)` | `último` / `primero` |
|
|
432
|
+
|
|
433
|
+
Los conjuntos se modelan con diccionarios (`visitados[nodo] = verdadero`), y los registros con
|
|
434
|
+
diccionarios y `.`.
|
|
435
|
+
|
|
436
|
+
## 9. Ejemplos por nivel
|
|
437
|
+
|
|
438
|
+
```codexivo
|
|
439
|
+
// 🟢 FizzBuzz
|
|
440
|
+
para_cada n en rango(1, 15) {
|
|
441
|
+
si (n mod 15 == 0) {
|
|
442
|
+
imprimir("FizzBuzz");
|
|
443
|
+
} pero_si (n mod 3 == 0) {
|
|
444
|
+
imprimir("Fizz");
|
|
445
|
+
} pero_si (n mod 5 == 0) {
|
|
446
|
+
imprimir("Buzz");
|
|
447
|
+
} si_no {
|
|
448
|
+
imprimir(n);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
```codexivo
|
|
454
|
+
// 🟡 Búsqueda binaria
|
|
455
|
+
procedimiento buscar_binaria(lista, objetivo) {
|
|
456
|
+
variable inicio = 0;
|
|
457
|
+
variable fin = longitud(lista) - 1;
|
|
458
|
+
mientras (inicio <= fin) {
|
|
459
|
+
variable medio = (inicio + fin) div 2;
|
|
460
|
+
si (lista[medio] es_igual_a objetivo) {
|
|
461
|
+
regresa medio;
|
|
462
|
+
} pero_si (lista[medio] es_menor_que objetivo) {
|
|
463
|
+
inicio = medio + 1;
|
|
464
|
+
} si_no {
|
|
465
|
+
fin = medio - 1;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
regresa -1;
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
```codexivo
|
|
473
|
+
// 🔴 Recorrido en anchura: distancia mínima en un grafo
|
|
474
|
+
procedimiento distancia(grafo, origen, destino) {
|
|
475
|
+
variable visitados = { };
|
|
476
|
+
variable cola = [[origen, 0]];
|
|
477
|
+
visitados[origen] = verdadero;
|
|
478
|
+
|
|
479
|
+
mientras (longitud(cola) > 0) {
|
|
480
|
+
variable actual = desencolar(cola);
|
|
481
|
+
si (actual[0] == destino) {
|
|
482
|
+
regresa actual[1];
|
|
483
|
+
}
|
|
484
|
+
para_cada vecino en grafo[actual[0]] {
|
|
485
|
+
si (no tiene(visitados, vecino)) {
|
|
486
|
+
visitados[vecino] = verdadero;
|
|
487
|
+
encolar(cola, [vecino, actual[1] + 1]);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
regresa -1;
|
|
492
|
+
}
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
## 10. Ejecución, límites y determinismo
|
|
496
|
+
|
|
497
|
+
- **Operaciones.** Cada operación básica (leer una variable, poner un valor, sumar, comparar, asignar, decidir, llamar)
|
|
498
|
+
cuenta como una. Los procedimientos de la biblioteca
|
|
499
|
+
cuentan según el trabajo que hacen (por ejemplo, `ordenar` sobre `n` elementos cuesta
|
|
500
|
+
`n · log₂ n`). La misma ejecución da siempre el mismo número, y los retos lo usan en lugar del
|
|
501
|
+
tiempo.
|
|
502
|
+
- **Límites configurables** con valores por defecto: operaciones (10 millones en el sandbox; cada
|
|
503
|
+
reto define el suyo), profundidad de recursión (10 000) y tamaño de la salida (1 MB). Superarlos es
|
|
504
|
+
un error de tipo `límite` que explica qué se superó y dónde estaba el programa.
|
|
505
|
+
- **Ejecución reanudable.** El intérprete avanza un paso a la vez y se puede pausar, avanzar o esperar a
|
|
506
|
+
`leer()`. Retroceder es volver a ejecutar desde el inicio hasta el paso anterior con la misma entrada: como la
|
|
507
|
+
ejecución es determinista, el resultado es idéntico. En el sandbox corre en un Web Worker y cede el control cada
|
|
508
|
+
cierto número de operaciones para no congelar la página.
|
|
509
|
+
- **Contratos de los retos:**
|
|
510
|
+
- _Estilo HackerRank:_ el programa lee con `leer()` y se compara lo que imprime.
|
|
511
|
+
- _Estilo LeetCode:_ el reto llama a un procedimiento (`resolver(...)`) y compara lo que regresa.
|
|
512
|
+
|
|
513
|
+
## 11. Contrato para la visualización
|
|
514
|
+
|
|
515
|
+
Es lo que necesitan el sandbox, los diagramas, la máquina de estados y el modo mundo.
|
|
516
|
+
|
|
517
|
+
- Cada nodo del AST tiene un identificador estable y su **rango** en el código (inicio y fin, en
|
|
518
|
+
línea, columna y desplazamiento).
|
|
519
|
+
- Cada token conserva su rango, para la vista de tokens.
|
|
520
|
+
- La máquina emite eventos: `paso` (inicio de una sentencia), `declara`, `asigna` (antes/después),
|
|
521
|
+
`decide` (condición, valor y rama tomada), `opera` (operandos y resultado), `llama`/`regresa`,
|
|
522
|
+
`imprime`/`lee`, `error` y `fin`. Cada uno lleva el número de operaciones y la profundidad de llamadas.
|
|
523
|
+
- En cualquier pausa se puede pedir una fotografía (`snapshot`) con las llamadas activas y las variables de
|
|
524
|
+
cada alcance. Listas y diccionarios tienen un identificador de referencia, para dibujar cuándo dos
|
|
525
|
+
variables comparten el mismo valor.
|
|
526
|
+
- El diagrama de flujo se genera desde el AST; la máquina de estados se anima desde los eventos.
|
|
527
|
+
Ninguno de los dos inventa información que el intérprete no produjo.
|
|
528
|
+
|
|
529
|
+
## 12. Modo mundo (Karel)
|
|
530
|
+
|
|
531
|
+
El mismo lenguaje con procedimientos adicionales para controlar un robot en una cuadrícula. Solo
|
|
532
|
+
existen cuando el programa corre en un mundo.
|
|
533
|
+
|
|
534
|
+
| Acción | Pregunta |
|
|
535
|
+
| -------------------- | ----------------------------------------------------------------------------------- |
|
|
536
|
+
| `avanzar()` | `frente_libre()`, `izquierda_libre()`, `derecha_libre()` |
|
|
537
|
+
| `girar_izquierda()` | `hay_zumbador()` |
|
|
538
|
+
| `recoger_zumbador()` | `tengo_zumbadores()` |
|
|
539
|
+
| `dejar_zumbador()` | `mirando_al_norte()`, `mirando_al_sur()`, `mirando_al_este()`, `mirando_al_oeste()` |
|
|
540
|
+
| `apagar()` | |
|
|
541
|
+
|
|
542
|
+
Chocar con una pared o recoger donde no hay zumbadores es un error de ejecución, con la posición del
|
|
543
|
+
robot. No hay `girar_derecha()`: construirlo con tres `girar_izquierda()` es el primer ejercicio, igual
|
|
544
|
+
que en Karel.
|
|
545
|
+
|
|
546
|
+
## 13. Fuera de v1
|
|
547
|
+
|
|
548
|
+
Módulos e `importar`, clases y métodos, `intentar`/`capturar`, asincronía, archivos, red, tipos
|
|
549
|
+
estáticos y `según`/`caso`. Se pueden reconsiderar después, siempre con el principio 1 como filtro.
|
|
550
|
+
|
|
551
|
+
## 14. Cambios que rompen programas existentes
|
|
552
|
+
|
|
553
|
+
Codexivo no tiene usuarios todavía, así que v1 se permite romper compatibilidad:
|
|
554
|
+
|
|
555
|
+
- condiciones estrictas (si se aprueba §4.5);
|
|
556
|
+
- error al llamar con un número distinto de argumentos;
|
|
557
|
+
- error al redeclarar o al asignar sin declarar;
|
|
558
|
+
- `agregar` pasa a modificar la lista (antes regresaba una nueva);
|
|
559
|
+
- un procedimiento sin `regresa` regresa `nulo` (antes regresaba el valor de su última expresión);
|
|
560
|
+
- `1 / 0` pasa a ser error;
|
|
561
|
+
- `ARREGLO` pasa a llamarse `lista` en mensajes y en `tipo()`.
|
|
562
|
+
|
|
563
|
+
## 15. Decisiones
|
|
564
|
+
|
|
565
|
+
Todas aprobadas.
|
|
566
|
+
|
|
567
|
+
| # | Tema | Decisión |
|
|
568
|
+
| --- | ---------------------------------- | -------- |
|
|
569
|
+
| 1 | Interpolación de texto (§2.3) | No en v1 |
|
|
570
|
+
| 2 | Nombre del tipo de las listas (§3) | `lista` |
|
|
571
|
+
| 3 | Condiciones estrictas (§4.5) | Sí |
|
|
572
|
+
| 4 | `según`/`caso` (§5.3) | No en v1 |
|
|
573
|
+
| 5 | `rango` inclusivo (§8) | Sí |
|
|
574
|
+
|
|
575
|
+
## 16. Orden de implementación propuesto
|
|
576
|
+
|
|
577
|
+
1. ✅ **Cimientos:** Bun 1.4.4 (`bun check` en lugar de `tsc`; la única dependencia de desarrollo es
|
|
578
|
+
`@types/bun`), rangos en tokens y nodos, errores estructurados.
|
|
579
|
+
2. ✅ **Correcciones:** precedencia de `y`/`o`/`no`, `pero_si` encadenados, comentarios, `nulo`, división
|
|
580
|
+
entre cero, igualdad por valor, `hasta_que`.
|
|
581
|
+
3. ✅ **Ejecución reanudable:** el AST se compila a instrucciones para una máquina de pila con su propia
|
|
582
|
+
pila de llamadas, límites, eventos y fotografías (§10–11). Reemplaza al evaluador recursivo y al
|
|
583
|
+
`RuntimeTracer`. Se descartaron los generadores anidados porque, con `yield*`, la recursión profunda
|
|
584
|
+
vuelve a depender de la pila de JavaScript. Incluye `imprimir`, `leer`, `leer_número`, `tipo`, `texto`
|
|
585
|
+
y `número`, porque la entrada y salida son parte del contrato de la máquina.
|
|
586
|
+
4. **Nivel principiante:** `imprimir`/`leer`, `repetir … veces`, `++`/`--`, `%`/`mod`/`div`, `^`,
|
|
587
|
+
operadores en palabras, `constante`, alcance por bloque.
|
|
588
|
+
5. **Nivel intermedio:** procedimientos con nombre, `para_cada`, `romper`/`continuar`, asignación por
|
|
589
|
+
índice, diccionarios, biblioteca de texto y listas.
|
|
590
|
+
6. **Nivel avanzado:** procedimientos como valores, estructuras de datos, costo por operación de la
|
|
591
|
+
biblioteca.
|
|
592
|
+
7. **Modo mundo.**
|
|
593
|
+
|
|
594
|
+
Cada paso llega con tests y actualiza `lenguaje.md` para que la documentación nunca vuelva a prometer
|
|
595
|
+
lo que el código no hace.
|