codexivo 0.2.0 → 0.2.3
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 +1 -1
- package/README.md +26 -25
- package/dist/index.js +151 -9
- package/dist/index.js.map +22 -12
- package/dist/worker.js +153 -0
- package/dist/worker.js.map +25 -0
- package/docs/README.md +2 -0
- package/docs/arquitectura.md +86 -4
- package/docs/especificacion-v1.md +192 -86
- package/docs/guia-aprender-desde-el-codigo.md +5 -5
- package/docs/integracion.md +104 -0
- package/docs/lenguaje.md +435 -60
- package/docs/modo-mundo.md +128 -0
- package/docs/recetario.md +63 -63
- package/package.json +11 -20
- package/src/catalog.ts +256 -0
- package/src/challenge.ts +138 -0
- package/src/engine.ts +7 -0
- package/src/error-codes.ts +427 -0
- package/src/flow.ts +385 -0
- package/src/index.ts +53 -1
- package/src/printer.ts +133 -0
- package/src/runtime/builtins.ts +1358 -65
- package/src/runtime/compiler.ts +278 -31
- package/src/runtime/costs.ts +96 -0
- package/src/runtime/machine.ts +722 -48
- package/src/runtime/prelude.ts +230 -0
- package/src/runtime/values.ts +119 -18
- package/src/sandbox-host.ts +310 -0
- package/src/sandbox.ts +95 -0
- package/src/syntax/ast.ts +120 -6
- package/src/syntax/lexer.ts +39 -5
- package/src/syntax/parser.ts +496 -72
- package/src/syntax/token.ts +49 -1
- package/src/worker.ts +18 -0
- package/src/world.ts +518 -0
- package/bin/codexivo.exe +0 -1
- package/postinstall.mjs +0 -38
package/docs/lenguaje.md
CHANGED
|
@@ -5,8 +5,9 @@ donde va el lenguaje está en la [especificación v1](./especificacion-v1.md); l
|
|
|
5
5
|
|
|
6
6
|
## Un programa
|
|
7
7
|
|
|
8
|
-
Un programa es una lista de sentencias. El punto y coma
|
|
9
|
-
línea. El valor de un programa es el de su última expresión, o lo que
|
|
8
|
+
Un programa es una lista de sentencias, una por línea. El punto y coma solo hace falta para poner dos sentencias en la misma
|
|
9
|
+
línea (`x = 1; y = 2`); los ejemplos de esta guía no lo usan. El valor de un programa es el de su última expresión, o lo que
|
|
10
|
+
regrese con `regresa`.
|
|
10
11
|
|
|
11
12
|
El mismo lenguaje funciona mediante la biblioteca ESM `codexivo`, el comando npm `codexivo` (sin instalar Bun) y los ejecutables
|
|
12
13
|
autónomos de cada sistema. Consulta [REPL y terminal](./repl.md) para ejecutar archivos y proporcionar entrada estándar.
|
|
@@ -22,52 +23,104 @@ imprimir("Hola,", nombre)
|
|
|
22
23
|
## Palabras reservadas
|
|
23
24
|
|
|
24
25
|
```
|
|
25
|
-
variable procedimiento regresa
|
|
26
|
-
si pero_si si_no
|
|
27
|
-
|
|
26
|
+
variable constante procedimiento regresa dominio
|
|
27
|
+
si pero_si si_no
|
|
28
|
+
mientras hacer hasta_que para desde hasta con_paso para_cada en repetir veces
|
|
29
|
+
romper continuar
|
|
30
|
+
verdadero falso nulo
|
|
31
|
+
y o no mod div
|
|
32
|
+
es_igual_a es_distinto_de es_menor_que es_mayor_que
|
|
33
|
+
es_menor_o_igual_a es_mayor_o_igual_a
|
|
28
34
|
```
|
|
29
35
|
|
|
30
36
|
## Valores
|
|
31
37
|
|
|
32
38
|
| Tipo | Ejemplos |
|
|
33
39
|
| ------------- | ----------------------------------------------------------------------------- |
|
|
34
|
-
| número | `10`, `3.14`, `.5`, `-2`
|
|
40
|
+
| número | `10`, `3.14`, `.5`, `-2`, `1_000_000` (el `_` solo separa grupos de dígitos) |
|
|
35
41
|
| texto | `"hola"`, `'mundo'`, `"línea\nnueva"` (escapes: `\n`, `\t`, `\\`, `\"`, `\'`) |
|
|
36
42
|
| lógico | `verdadero`, `falso` |
|
|
37
43
|
| nulo | `nulo` |
|
|
38
44
|
| lista | `[1, "a", verdadero]` |
|
|
45
|
+
| diccionario | `{ "nombre": "Ana", "edad": 16 }` |
|
|
39
46
|
| procedimiento | `procedimiento(x) { regresa x * 2; }` |
|
|
40
47
|
|
|
41
|
-
Las listas se comparten: si dos variables apuntan a la misma lista, un cambio se ve desde las dos.
|
|
48
|
+
Las listas y los diccionarios se comparten: si dos variables apuntan a la misma lista, un cambio se ve desde las dos.
|
|
42
49
|
|
|
43
50
|
## Variables
|
|
44
51
|
|
|
45
52
|
```codexivo
|
|
46
|
-
variable contador = 0
|
|
47
|
-
contador = contador + 1
|
|
48
|
-
|
|
53
|
+
variable contador = 0
|
|
54
|
+
contador = contador + 1
|
|
55
|
+
|
|
56
|
+
constante LADOS = 4
|
|
57
|
+
imprimir(LADOS * contador)
|
|
49
58
|
```
|
|
50
59
|
|
|
51
60
|
- Toda variable se declara una vez con `variable` y un valor inicial.
|
|
61
|
+
- `=` **no** es una igualdad: guarda en la variable de la izquierda el valor de la derecha. `contador = contador + 1` se lee
|
|
62
|
+
«calcula `contador + 1` y guarda el resultado en `contador`». En el sandbox se ve el valor entrando en la variable.
|
|
52
63
|
- Asignar a una variable sin declararla es un error.
|
|
64
|
+
- Una `constante` no se puede cambiar: reasignarla es un error.
|
|
53
65
|
- Lo que se declara dentro de un bloque `{ }` solo existe dentro de él.
|
|
54
66
|
|
|
55
67
|
Los nombres pueden llevar `ñ`, acentos y diéresis: `año`, `canción`, `pingüino`.
|
|
56
68
|
|
|
69
|
+
### Atajos
|
|
70
|
+
|
|
71
|
+
Cuando ya se entiende la asignación, hay formas cortas para los cambios más comunes:
|
|
72
|
+
|
|
73
|
+
```codexivo
|
|
74
|
+
variable total = 10
|
|
75
|
+
total += 5 // lo mismo que total = total + 5; también -=, *=, /=, %=
|
|
76
|
+
total++ // suma 1
|
|
77
|
+
total-- // resta 1
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`++` y `--` son sentencias, no expresiones: `x = i++` es un error. Se escribe `i++` en su propia línea.
|
|
81
|
+
|
|
57
82
|
## Operadores
|
|
58
83
|
|
|
59
84
|
De menor a mayor precedencia:
|
|
60
85
|
|
|
61
|
-
| Operadores
|
|
62
|
-
|
|
|
63
|
-
| `o`
|
|
64
|
-
| `y`
|
|
65
|
-
| `no`, `!`
|
|
66
|
-
| `==` `!=` `<` `>` `<=` `>=`
|
|
67
|
-
| `+` `-`
|
|
68
|
-
| `*` `/`
|
|
69
|
-
| `-` (signo)
|
|
70
|
-
|
|
|
86
|
+
| Operadores | Notas |
|
|
87
|
+
| ---------------------------------------------------- | ------------------------------------------------------------------------ |
|
|
88
|
+
| `o` | Cortocircuito |
|
|
89
|
+
| `y` | Cortocircuito |
|
|
90
|
+
| `no`, `!` | |
|
|
91
|
+
| `==` `!=` `<` `>` `<=` `>=` y sus formas en palabras | No se pueden encadenar: `1 < x < 5` es un error; escribe `1 < x y x < 5` |
|
|
92
|
+
| `+` `-` | `+` también une dos textos |
|
|
93
|
+
| `*` `/` `div` `mod` (`%`) | Dividir entre cero (con `/`, `div` o `mod`) es un error |
|
|
94
|
+
| `-` (signo) | |
|
|
95
|
+
| `^` | Potencia, asociativa a la derecha: `2 ^ 3 ^ 2` es `2 ^ 9` |
|
|
96
|
+
| llamadas `f(x)`, índices `lista[i]` | |
|
|
97
|
+
|
|
98
|
+
```codexivo
|
|
99
|
+
7 / 2 // 3.5, división real
|
|
100
|
+
7 div 2 // 3, división entera hacia abajo
|
|
101
|
+
-7 div 2 // -4
|
|
102
|
+
7 mod 3 // 1, el residuo (también 7 % 3)
|
|
103
|
+
-7 mod 3 // 2: siempre se cumple a == (a div b) * b + (a mod b)
|
|
104
|
+
-2 ^ 2 // -4, como en matemáticas: la potencia va antes que el signo
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Cada comparación tiene una forma en palabras que significa exactamente lo mismo:
|
|
108
|
+
|
|
109
|
+
| Símbolo | Palabra |
|
|
110
|
+
| ------- | -------------------- |
|
|
111
|
+
| `==` | `es_igual_a` |
|
|
112
|
+
| `!=` | `es_distinto_de` |
|
|
113
|
+
| `<` | `es_menor_que` |
|
|
114
|
+
| `>` | `es_mayor_que` |
|
|
115
|
+
| `<=` | `es_menor_o_igual_a` |
|
|
116
|
+
| `>=` | `es_mayor_o_igual_a` |
|
|
117
|
+
|
|
118
|
+
```codexivo
|
|
119
|
+
variable edad = 16
|
|
120
|
+
si (edad es_mayor_o_igual_a 13 y edad es_menor_que 18) {
|
|
121
|
+
imprimir("adolescente")
|
|
122
|
+
}
|
|
123
|
+
```
|
|
71
124
|
|
|
72
125
|
- `==` compara por valor, también listas: `[1, 2] == [1, 2]` es `verdadero`.
|
|
73
126
|
- `+` no mezcla textos y números: `"Total: " + 5` es un error. Usa `texto(5)` o `imprimir("Total:", 5)`.
|
|
@@ -76,76 +129,360 @@ De menor a mayor precedencia:
|
|
|
76
129
|
## Condiciones y bucles
|
|
77
130
|
|
|
78
131
|
```codexivo
|
|
79
|
-
variable edad = 15
|
|
80
|
-
si (edad
|
|
81
|
-
imprimir("adulto")
|
|
82
|
-
} pero_si (edad
|
|
83
|
-
imprimir("adolescente")
|
|
132
|
+
variable edad = 15
|
|
133
|
+
si (edad es_mayor_o_igual_a 18) {
|
|
134
|
+
imprimir("adulto")
|
|
135
|
+
} pero_si (edad es_mayor_o_igual_a 13) {
|
|
136
|
+
imprimir("adolescente")
|
|
84
137
|
} si_no {
|
|
85
|
-
imprimir("niño")
|
|
138
|
+
imprimir("niño")
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Hay una forma de bucle para cada intención:
|
|
143
|
+
|
|
144
|
+
| Para… | Se escribe |
|
|
145
|
+
| --------------------------------------- | --------------------------------- |
|
|
146
|
+
| Repetir algo n veces | `repetir n veces { }` |
|
|
147
|
+
| Contar | `para i desde a hasta b { }` |
|
|
148
|
+
| Repetir mientras se cumpla algo | `mientras (condición) { }` |
|
|
149
|
+
| Repetir hasta que se cumpla algo | `hacer { } hasta_que (condición)` |
|
|
150
|
+
| Recorrer una lista, texto o diccionario | `para_cada x en colección { }` |
|
|
151
|
+
|
|
152
|
+
```codexivo
|
|
153
|
+
repetir 3 veces {
|
|
154
|
+
imprimir("¡hola!")
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
variable suma = 0
|
|
158
|
+
para i desde 1 hasta 10 {
|
|
159
|
+
suma = suma + i
|
|
160
|
+
}
|
|
161
|
+
imprimir("La suma es", suma)
|
|
162
|
+
|
|
163
|
+
para i desde 10 hasta 0 con_paso -2 {
|
|
164
|
+
imprimir(i)
|
|
86
165
|
}
|
|
87
166
|
|
|
88
|
-
variable
|
|
89
|
-
mientras (
|
|
90
|
-
|
|
167
|
+
variable intentos = 0
|
|
168
|
+
mientras (intentos es_menor_que 3) {
|
|
169
|
+
intentos = intentos + 1
|
|
91
170
|
}
|
|
92
171
|
|
|
93
172
|
hacer {
|
|
94
|
-
|
|
95
|
-
} hasta_que (
|
|
173
|
+
intentos = intentos - 1
|
|
174
|
+
} hasta_que (intentos es_igual_a 0)
|
|
96
175
|
|
|
97
|
-
|
|
98
|
-
imprimir(
|
|
176
|
+
para_cada fruta en ["mango", "piña"] {
|
|
177
|
+
imprimir(fruta)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
para n desde 1 hasta 10 {
|
|
181
|
+
si (n mod 2 es_igual_a 0) {
|
|
182
|
+
continuar // salta a la siguiente vuelta
|
|
183
|
+
}
|
|
184
|
+
si (n es_mayor_que 7) {
|
|
185
|
+
romper // sale del bucle
|
|
186
|
+
}
|
|
187
|
+
imprimir(n)
|
|
99
188
|
}
|
|
100
189
|
```
|
|
101
190
|
|
|
191
|
+
- `para i desde a hasta b` incluye los dos extremos. El paso es 1 si no se escribe `con_paso`.
|
|
192
|
+
- `i` se crea sola, sin `variable`, es nueva en cada vuelta y solo existe dentro del cuerpo. Avanza sola: cambiarla
|
|
193
|
+
dentro del bucle es un error.
|
|
194
|
+
- `desde`, `hasta` y `con_paso` se calculan **una vez**, al empezar. Si después cambia la variable que se usó en
|
|
195
|
+
`hasta`, el bucle no se entera.
|
|
196
|
+
- Para contar hacia atrás hay que decirlo: `para i desde 10 hasta 1` es un error; se escribe `con_paso -1`. Un paso 0
|
|
197
|
+
también es un error.
|
|
198
|
+
- `repetir n veces` evalúa `n` una sola vez, al empezar. Tiene que ser un número entero, 0 o más; con 0 el bloque no se
|
|
199
|
+
ejecuta. Lleva la cuenta por dentro, sin crear ninguna variable.
|
|
102
200
|
- `hacer … hasta_que` ejecuta el bloque al menos una vez y repite **hasta que** la condición sea verdadera.
|
|
103
|
-
-
|
|
201
|
+
- `para_cada x en …` recorre una lista, un texto o un diccionario. `x` es nueva en cada vuelta y solo existe dentro del
|
|
202
|
+
cuerpo. Cambiar elementos de la lista mientras se recorre está bien; agregar o quitar elementos es un error.
|
|
203
|
+
- `romper` sale del bucle más cercano y `continuar` salta a su siguiente vuelta. Fuera de un bucle son un error, también
|
|
204
|
+
dentro de un procedimiento que se llama desde un bucle.
|
|
104
205
|
|
|
105
206
|
## Procedimientos
|
|
106
207
|
|
|
107
208
|
```codexivo
|
|
209
|
+
procedimiento área(base, altura) {
|
|
210
|
+
regresa base * altura
|
|
211
|
+
}
|
|
212
|
+
área(3, 4)
|
|
213
|
+
|
|
214
|
+
// también como valor, guardado en una variable
|
|
108
215
|
variable saludar = procedimiento(nombre) {
|
|
109
|
-
regresa "Hola, " + nombre
|
|
110
|
-
}
|
|
111
|
-
saludar("Uriel")
|
|
216
|
+
regresa "Hola, " + nombre
|
|
217
|
+
}
|
|
218
|
+
saludar("Uriel")
|
|
112
219
|
```
|
|
113
220
|
|
|
114
|
-
-
|
|
221
|
+
- Un procedimiento con nombre existe desde el inicio de su bloque: se puede llamar antes de la línea donde se declara, y
|
|
222
|
+
dos procedimientos pueden llamarse entre sí. Su nombre no se puede repetir en el mismo bloque.
|
|
115
223
|
- Hay que llamarlos con exactamente tantos valores como parámetros.
|
|
116
224
|
- Sin `regresa`, un procedimiento regresa `nulo`.
|
|
117
225
|
- Recuerdan las variables de donde se crearon (closures) y pueden llamarse a sí mismos.
|
|
118
226
|
|
|
119
|
-
Los procedimientos con nombre (`procedimiento saludar(nombre) { … }`) llegarán con la v1.
|
|
120
|
-
|
|
121
227
|
## Listas y textos
|
|
122
228
|
|
|
123
229
|
```codexivo
|
|
124
|
-
variable números = [10, 20, 30]
|
|
125
|
-
números[0]
|
|
126
|
-
números[-1]
|
|
127
|
-
"hola"[1]
|
|
230
|
+
variable números = [10, 20, 30]
|
|
231
|
+
números[0] // 10
|
|
232
|
+
números[-1] // 30, desde el final
|
|
233
|
+
"hola"[1] // "o"
|
|
234
|
+
|
|
235
|
+
números[0] = 15
|
|
236
|
+
números[-1] += 1
|
|
237
|
+
números[1]++
|
|
238
|
+
|
|
239
|
+
variable matriz = [[1, 2], [3, 4]]
|
|
240
|
+
matriz[1][0] = 9
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
- Los índices son enteros desde 0; un índice fuera de rango es un error que dice cuántos elementos hay.
|
|
244
|
+
- Los textos no se pueden cambiar letra por letra: `t[0] = "H"` es un error. Se construye un texto nuevo.
|
|
245
|
+
|
|
246
|
+
## Diccionarios
|
|
247
|
+
|
|
248
|
+
```codexivo
|
|
249
|
+
variable persona = { "nombre": "Ana", "edad": 16 }
|
|
250
|
+
persona["nombre"] // "Ana"
|
|
251
|
+
persona.edad // 16, lo mismo que persona["edad"]
|
|
252
|
+
persona.ciudad = "León" // agrega la clave
|
|
253
|
+
persona.edad += 1
|
|
254
|
+
|
|
255
|
+
para_cada clave, valor en persona {
|
|
256
|
+
imprimir(clave, valor)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
si (tiene(persona, "correo")) {
|
|
260
|
+
imprimir(persona.correo)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
variable calculadora = {
|
|
264
|
+
"suma": procedimiento(a, b) { regresa a + b; },
|
|
265
|
+
}
|
|
266
|
+
calculadora.suma(1, 3) // 4
|
|
128
267
|
```
|
|
129
268
|
|
|
130
|
-
|
|
269
|
+
- Las claves son textos o números (`1` y `"1"` son claves distintas) y van entre comillas: `{ nombre: "Ana" }` es un
|
|
270
|
+
error. Para usar el valor de una variable como clave, escríbela entre paréntesis: `{ (clave): 1 }`.
|
|
271
|
+
- `d.campo` funciona con claves que son nombres válidos; para las demás, `d["clave con espacios"]`.
|
|
272
|
+
- Leer una clave que no existe es un error; pregunta antes con `tiene(d, clave)`.
|
|
273
|
+
- Se recorren en el orden en que se agregaron las claves: `para_cada clave en d` da solo las claves y
|
|
274
|
+
`para_cada clave, valor en d`, las dos. Agregar o quitar claves mientras se recorre es un error.
|
|
275
|
+
- `==` compara por valor sin importar el orden: `{ "a": 1, "b": 2 } == { "b": 2, "a": 1 }` es `verdadero`.
|
|
276
|
+
- Al inicio de una sentencia, `{` abre un bloque; en cualquier otra posición, un diccionario.
|
|
277
|
+
|
|
278
|
+
## Dominios
|
|
279
|
+
|
|
280
|
+
Un `dominio` es un espacio de nombres: agrupa procedimientos, variables y constantes bajo un nombre, y desde fuera se usan
|
|
281
|
+
con `.`. No es un módulo ni hay que importarlo: se declara en el mismo programa.
|
|
282
|
+
|
|
283
|
+
```codexivo
|
|
284
|
+
dominio calculadora {
|
|
285
|
+
constante PRECISIÓN = 2
|
|
286
|
+
variable operaciones = 0
|
|
287
|
+
|
|
288
|
+
procedimiento suma(a, b) {
|
|
289
|
+
operaciones++
|
|
290
|
+
regresa redondear(a + b, PRECISIÓN)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
procedimiento promedio(a, b) {
|
|
294
|
+
regresa suma(a, b) / 2 // dentro del dominio, sin prefijo
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
calculadora.suma(1, 3) // 4
|
|
299
|
+
calculadora.promedio(2, 3) // 2.5
|
|
300
|
+
calculadora.operaciones // 2
|
|
301
|
+
|
|
302
|
+
dominio geometría {
|
|
303
|
+
dominio círculo {
|
|
304
|
+
procedimiento área(r) {
|
|
305
|
+
regresa PI * r ^ 2
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
geometría.círculo.área(1)
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
- Dentro de un dominio solo van declaraciones: `variable`, `constante`, `procedimiento` y otros `dominio`. Un `si` o un
|
|
313
|
+
`imprimir` van dentro de un procedimiento del dominio o fuera de él.
|
|
314
|
+
- Dentro, los miembros se usan sin prefijo y ven lo que está fuera del dominio. Fuera, se usan con `.`:
|
|
315
|
+
`calculadora.suma`. Sin el prefijo no existen.
|
|
316
|
+
- Desde fuera solo se pueden cambiar los miembros declarados con `variable` (`calculadora.operaciones = 0`). Las
|
|
317
|
+
constantes, los procedimientos y los dominios que contiene quedan fijos, y no se pueden agregar miembros nuevos.
|
|
318
|
+
- El nombre del dominio no se puede reasignar. `tipo(calculadora)` es `"dominio"`.
|
|
319
|
+
|
|
320
|
+
## Procedimientos como valores
|
|
321
|
+
|
|
322
|
+
Un procedimiento es un valor como cualquier otro: se guarda en variables, en listas y diccionarios, y se le pasa a otros
|
|
323
|
+
procedimientos. La biblioteca trae varios que reciben uno:
|
|
324
|
+
|
|
325
|
+
```codexivo
|
|
326
|
+
variable números = [3, 8, 1, 6]
|
|
327
|
+
procedimiento es_par(n) {
|
|
328
|
+
regresa n mod 2 == 0
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
mapear(números, procedimiento(n) { regresa n * 10; }) // [30, 80, 10, 60]
|
|
332
|
+
filtrar(números, es_par) // [8, 6]
|
|
333
|
+
reducir(números, procedimiento(total, n) { regresa total + n; }, 0) // 18
|
|
334
|
+
alguno(números, es_par) // verdadero
|
|
335
|
+
todos(números, es_par) // falso
|
|
336
|
+
buscar(números, procedimiento(n) { regresa n > 5; }) // 8
|
|
337
|
+
ordenar(números, procedimiento(a, b) { regresa a > b; }) // [8, 6, 3, 1]
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
| Procedimiento | Qué hace |
|
|
341
|
+
| ---------------------------- | --------------------------------------------------------------------------------------- |
|
|
342
|
+
| `mapear(lista, f)` | Lista nueva con `f(x)` de cada elemento |
|
|
343
|
+
| `filtrar(lista, f)` | Lista nueva con los elementos para los que `f(x)` es `verdadero` |
|
|
344
|
+
| `reducir(lista, f, inicial)` | Junta todo en un valor: empieza con `inicial` y en cada elemento hace `f(acumulado, x)` |
|
|
345
|
+
| `alguno(lista, f)` | `verdadero` si `f(x)` es `verdadero` para al menos un elemento |
|
|
346
|
+
| `todos(lista, f)` | `verdadero` si `f(x)` es `verdadero` para todos |
|
|
347
|
+
| `buscar(lista, f)` | El primer elemento con `f(x)` `verdadero`, o `nulo` |
|
|
348
|
+
| `ordenar(lista, va_antes)` | Lista nueva ordenada; `va_antes(a, b)` responde «¿va `a` antes que `b`?» |
|
|
349
|
+
|
|
350
|
+
- `f` de `filtrar`, `alguno`, `todos` y `buscar`, y el comparador de `ordenar`, tienen que regresar `verdadero` o `falso`.
|
|
351
|
+
- `ordenar` es estable: los elementos que el comparador no distingue conservan su orden.
|
|
352
|
+
- Un error dentro de `f` dice dónde está y desde dónde se llamó: `programa > mapear > f`.
|
|
353
|
+
|
|
354
|
+
## Pilas y colas
|
|
355
|
+
|
|
356
|
+
Son listas con un vocabulario propio, para que el algoritmo se lea como se explica:
|
|
357
|
+
|
|
358
|
+
| Pila | Cola | Qué hace |
|
|
359
|
+
| -------------- | --------------- | -------------------------------------- |
|
|
360
|
+
| `apilar(p, x)` | `encolar(c, x)` | Agrega al final |
|
|
361
|
+
| `desapilar(p)` | `desencolar(c)` | Quita y regresa el último / el primero |
|
|
362
|
+
| `tope(p)` | `frente(c)` | Regresa, sin quitarlo, el que saldría |
|
|
363
|
+
|
|
364
|
+
```codexivo
|
|
365
|
+
variable pendientes = []
|
|
366
|
+
encolar(pendientes, "lavar")
|
|
367
|
+
encolar(pendientes, "secar")
|
|
368
|
+
imprimir(desencolar(pendientes), frente(pendientes))
|
|
369
|
+
|
|
370
|
+
variable pila = []
|
|
371
|
+
apilar(pila, 1)
|
|
372
|
+
apilar(pila, 2)
|
|
373
|
+
imprimir(desapilar(pila), tope(pila))
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Sacar de una pila o cola vacía es un error: _"No se puede `desencolar` de una cola vacía."_
|
|
131
377
|
|
|
132
378
|
## Biblioteca
|
|
133
379
|
|
|
134
|
-
Los nombres con acento también se aceptan sin él (`máximo` o `maximo`).
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
|
139
|
-
|
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
143
|
-
| `
|
|
144
|
-
| `
|
|
145
|
-
| `
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
380
|
+
Todo está disponible sin importar nada. Los nombres con acento también se aceptan sin él (`máximo` o `maximo`).
|
|
381
|
+
|
|
382
|
+
### Entrada, salida y tipos
|
|
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 |
|
|
392
|
+
|
|
393
|
+
### Matemáticas
|
|
394
|
+
|
|
395
|
+
| Procedimiento | Qué hace |
|
|
396
|
+
| -------------------------- | ---------------------------------------------------------------------- |
|
|
397
|
+
| `absoluto(x)` | Valor absoluto |
|
|
398
|
+
| `máximo(…)`, `mínimo(…)` | De varios números o de una lista |
|
|
399
|
+
| `redondear(x, decimales?)` | Redondea; los `.5` se alejan del cero |
|
|
400
|
+
| `piso(x)`, `techo(x)` | Redondea hacia abajo o hacia arriba: `piso(-2.1)` es `-3` |
|
|
401
|
+
| `entero(x)` | Quita los decimales: `entero(-2.7)` es `-2` |
|
|
402
|
+
| `raíz(x)` | Raíz cuadrada; de un número negativo es un error |
|
|
403
|
+
| `aleatorio(a, b)` | Un entero al azar entre `a` y `b`, los dos incluidos |
|
|
404
|
+
| `PI` | La constante 3.14159…; una variable tuya con el mismo nombre la oculta |
|
|
405
|
+
|
|
406
|
+
`aleatorio` usa una semilla por ejecución: con la misma semilla, el programa da exactamente los mismos números. `run`
|
|
407
|
+
regresa la semilla que usó en `seed`, y se puede fijar con la opción `seed`.
|
|
408
|
+
|
|
409
|
+
```codexivo
|
|
410
|
+
variable dado = aleatorio(1, 6)
|
|
411
|
+
imprimir("Salió", dado)
|
|
412
|
+
imprimir(piso(7 / 2), techo(7 / 2), raíz(16))
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Texto
|
|
416
|
+
|
|
417
|
+
Ninguno cambia el texto original (los textos no cambian nunca): todos regresan un valor nuevo.
|
|
418
|
+
|
|
419
|
+
| Procedimiento | Qué hace |
|
|
420
|
+
| ------------------------------------------------ | --------------------------------------------------------------------------------------- |
|
|
421
|
+
| `mayúsculas(t)`, `minúsculas(t)` | El mismo texto en mayúsculas o en minúsculas |
|
|
422
|
+
| `recortar(t)` | Sin espacios ni saltos de línea al principio y al final |
|
|
423
|
+
| `dividir(t, separador)` | Lista con los pedazos de `t` entre cada separador |
|
|
424
|
+
| `unir(lista, separador)` | Un texto con los elementos de la lista separados por `separador` |
|
|
425
|
+
| `reemplazar(t, buscar, poner)` | Cambia cada aparición de `buscar` por `poner` |
|
|
426
|
+
| `contiene(t, parte)` | `verdadero` si `parte` aparece en `t` |
|
|
427
|
+
| `empieza_con(t, parte)`, `termina_con(t, parte)` | Si `t` empieza o termina con `parte` |
|
|
428
|
+
| `posición_de(t, parte)` | Dónde empieza la primera aparición de `parte`, o `-1` si no está |
|
|
429
|
+
| `subtexto(t, inicio, fin)` | Los caracteres de `inicio` hasta **antes** de `fin`: `subtexto("hola", 1, 3)` es `"ol"` |
|
|
430
|
+
| `caracteres(t)` | Lista con cada carácter |
|
|
431
|
+
| `invertir(t)` | El texto al revés |
|
|
432
|
+
| `código_de(c)`, `carácter_de(n)` | El código Unicode de un carácter, y el carácter de un código |
|
|
433
|
+
|
|
434
|
+
```codexivo
|
|
435
|
+
variable frase = " El sol sale "
|
|
436
|
+
variable palabras = dividir(recortar(frase), " ")
|
|
437
|
+
imprimir(unir(palabras, "-"))
|
|
438
|
+
imprimir(mayúsculas(palabras[1]), contiene(frase, "sol"), posición_de(frase, "sale"))
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Listas
|
|
442
|
+
|
|
443
|
+
Regla: **`agregar`, `insertar`, `quitar` (y sus variantes) y `vaciar` cambian la lista; todo lo demás regresa un valor
|
|
444
|
+
nuevo.** Los índices siguen la misma convención que `[ ]`: desde 0, y los negativos cuentan desde el final.
|
|
445
|
+
|
|
446
|
+
| Procedimiento | Qué hace |
|
|
447
|
+
| ----------------------------------------------- | ------------------------------------------------------------------------------ |
|
|
448
|
+
| `agregar(lista, x)` | Agrega al final |
|
|
449
|
+
| `insertar(lista, i, x)` | Pone `x` en la posición `i` y recorre los demás |
|
|
450
|
+
| `quitar(lista, i)` | Quita el elemento en la posición `i` y lo regresa |
|
|
451
|
+
| `quitar_último(lista)`, `quitar_primero(lista)` | Quitan el último o el primero y lo regresan |
|
|
452
|
+
| `vaciar(lista)` | Quita todos los elementos (también sirve con un diccionario) |
|
|
453
|
+
| `primero(lista)`, `último(lista)` | Primer y último elemento |
|
|
454
|
+
| `contiene(lista, x)`, `posición_de(lista, x)` | Si `x` está (comparando por valor) y en qué posición, o `-1` |
|
|
455
|
+
| `rango(a, b, paso?)` | Lista de `a` a `b`, **incluyendo** `b`; con `paso` negativo cuenta hacia abajo |
|
|
456
|
+
| `índices(lista)` | Las posiciones válidas: `rango(0, longitud(lista) - 1)` |
|
|
457
|
+
| `rebanar(lista, inicio, fin)` | Los elementos de `inicio` hasta **antes** de `fin` |
|
|
458
|
+
| `invertir(lista)`, `copiar(lista)` | Una lista nueva al revés, o igual |
|
|
459
|
+
| `ordenar(lista)` | Una lista nueva ordenada; todos números o todos textos |
|
|
460
|
+
| `sumar(lista)` | La suma de sus números |
|
|
461
|
+
| `lista_de(n, valor)` | Lista con `n` copias de `valor` |
|
|
462
|
+
| `matriz(filas, columnas, valor)` | Lista de filas, cada una con `columnas` copias de `valor` |
|
|
463
|
+
|
|
464
|
+
`lista_de` y `matriz` copian el valor en cada casilla, así cambiar una no cambia las demás:
|
|
465
|
+
|
|
466
|
+
```codexivo
|
|
467
|
+
variable tablero = matriz(3, 3, ".")
|
|
468
|
+
tablero[1][1] = "X"
|
|
469
|
+
para_cada fila en tablero {
|
|
470
|
+
imprimir(unir(fila, " "))
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
variable números = [5, 3, 8]
|
|
474
|
+
insertar(números, 0, 1)
|
|
475
|
+
imprimir(ordenar(números), sumar(números), quitar_último(números), números)
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### Diccionarios
|
|
479
|
+
|
|
480
|
+
| Procedimiento | Qué hace |
|
|
481
|
+
| ------------------------- | ----------------------------------------------------------------- |
|
|
482
|
+
| `claves(d)`, `valores(d)` | Listas nuevas con las claves o los valores, en orden de inserción |
|
|
483
|
+
| `tiene(d, clave)` | `verdadero` si el diccionario tiene esa clave |
|
|
484
|
+
| `quitar(d, clave)` | Quita la clave y regresa su valor (cambia el diccionario) |
|
|
485
|
+
| `copiar(d)` | Un diccionario nuevo con las mismas claves y valores |
|
|
149
486
|
|
|
150
487
|
## Errores
|
|
151
488
|
|
|
@@ -156,7 +493,45 @@ Error de ejecución en la línea 2, columna 5: No se puede dividir entre cero.
|
|
|
156
493
|
Pista: Revisa que el divisor no valga 0 antes de dividir.
|
|
157
494
|
```
|
|
158
495
|
|
|
496
|
+
## Puente hacia otros lenguajes
|
|
497
|
+
|
|
498
|
+
Muchos lenguajes (C, Java, JavaScript) cuentan con un `for` de tres partes. Codexivo también lo tiene, para practicar antes de
|
|
499
|
+
pasar a ellos:
|
|
500
|
+
|
|
501
|
+
```codexivo
|
|
502
|
+
para (variable i = 1; i <= 10; i += 1) {
|
|
503
|
+
imprimir(i)
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
Es el mismo bucle que `para i desde 1 hasta 10`, escrito a mano:
|
|
508
|
+
|
|
509
|
+
| Parte | Qué hace | En `para … desde … hasta` |
|
|
510
|
+
| ---------------- | ---------------------------------------------------- | ------------------------- |
|
|
511
|
+
| `variable i = 1` | Se ejecuta una vez, al empezar | `desde 1` |
|
|
512
|
+
| `i <= 10` | Se revisa antes de cada vuelta; si es falsa, termina | `hasta 10` |
|
|
513
|
+
| `i += 1` | Se ejecuta al final de cada vuelta | `con_paso 1` |
|
|
514
|
+
|
|
515
|
+
La diferencia es que aquí todo es explícito y modificable: la condición se vuelve a evaluar en cada vuelta y la variable se
|
|
516
|
+
puede cambiar dentro del cuerpo. Cualquiera de las tres partes puede faltar (`para (; condición;)`). La variable solo existe
|
|
517
|
+
dentro del bucle.
|
|
518
|
+
|
|
159
519
|
## Límites
|
|
160
520
|
|
|
161
521
|
Para que un error nunca congele la página, la ejecución se detiene con un error de límite al superar 10 000 000 de
|
|
162
522
|
operaciones, 10 000 llamadas anidadas o 1 000 000 de caracteres impresos. Los tres se pueden configurar.
|
|
523
|
+
|
|
524
|
+
## Operaciones
|
|
525
|
+
|
|
526
|
+
Cada operación básica (leer una variable, poner un valor, sumar, comparar, asignar, decidir, llamar) cuesta 1. Los
|
|
527
|
+
procedimientos de la biblioteca cuestan según el trabajo que hacen, con `n` el tamaño de su primer argumento:
|
|
528
|
+
|
|
529
|
+
| Costo | Procedimientos |
|
|
530
|
+
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
531
|
+
| `n · ⌈log₂ n⌉` | `ordenar` |
|
|
532
|
+
| `n` | `contiene`, `posición_de`, `copiar`, `invertir`, `sumar`, `insertar`, `quitar`, `quitar_primero`, `desencolar`, `claves`, `valores`, `índices`, `máximo`, `mínimo`, `mapear`, `filtrar`, `reducir`, `alguno`, `todos`, `buscar`, y los de texto que recorren el texto |
|
|
533
|
+
| lo que crean | `rango`, `rebanar`, `subtexto`, `lista_de`, `matriz` |
|
|
534
|
+
| 1 | todos los demás |
|
|
535
|
+
|
|
536
|
+
Lo que hace el procedimiento que recibe `mapear` (y los demás) se cuenta aparte, como cualquier código. El mismo programa con
|
|
537
|
+
la misma entrada siempre da el mismo número de operaciones, y los retos lo usan en lugar del tiempo.
|