# Laboratorio de la semana 15: terminar el intérprete

Hay dos sesiones de 2 horas. Cada una está pensada para unos 90 minutos de trabajo. Los comandos se corren desde
`code/week-15`. Las ideas están en los apuntes, en la sección "El laboratorio, paso a paso".

Lo que escribieron en las semanas 13 y 14 ya viene hecho, y ampliado para las variantes nuevas. Su propio código funciona, pero
así todos empiezan desde el mismo punto y el evaluador no carga con un bug de otra semana.

| Archivo | Qué es | ¿Lo cambian? |
|---|---|---|
| `env.h`, `env.c` | La tabla de variables de cada marco. Se usa solo por su encabezado | No |
| `expr.h`, `expr.c` | El árbol de la semana 13, con `EXPR_IF` y `EXPR_CALL`, y sus constructores | No |
| `lexer.h`, `lexer.c` | El análisis léxico de la semana 14, completo | No |
| `stmt.h`, `stmt.c` | Las instrucciones: `Stmt`, sus constructores y `stmt_free` | No |
| `parser.h` | La interfaz del parser | No |
| `parser.c` | Las expresiones ya están. Faltan `parse_if`, `parse_call`, `parse_let`, `parse_print` y el final de `parse_def` | **Sí** |
| `interp.h` | La interfaz del intérprete | No |
| `interp.c` | La tabla de funciones y lo aritmético ya están. Faltan `eval_if`, el final de `eval_call` y dos casos de `exec_statement` | **Sí** |
| `mini.c` | El programa: lee un archivo, lo analiza y lo corre | No |
| `programs/` | Programas de Mini de ejemplo, también los que deben fallar | No |
| `mine/` | Sus propios programas de Mini, con el resultado esperado | **Sí** |

```sh
make lab                         # compila el intérprete en build/lab/mini
build/lab/mini lab/programs/fact.mini
make test-lab                    # comprueba todo el laboratorio; falla hasta que terminen
```

Se puede correr un grupo de pruebas solo:

```sh
LAB_DIR=lab python3 -m unittest test_lab.LetAndPrint
```

Todo se compila con ASan y UBSan. Una fuga también hace fallar la prueba, aunque el resultado esté bien.

## Sesión 1: unir las partes

### Parte 1: leer (unos 15 minutos)

Lean `stmt.h`, `parse_parameters` y `parse_program` en `parser.c`, y luego `interp.c` hasta `eval`. Respondan por escrito:

1. En `run_program`, ¿quién es owner del marco global? ¿Y de cada `Stmt`?
2. Una entrada de `Function` guarda un `const Stmt *`. ¿Por qué no se libera ese `Stmt` en `free_functions`?
3. `Interp` va por parámetro a todas las funciones. ¿De qué semana es esa idea, y qué evita?
4. Si `parse_program` devuelve `NULL`, ¿cómo se distingue un error de sintaxis de un programa vacío?

### Parte 2: `let` y `print` (unos 15 minutos)

En `parser.c`, escriban `parse_let` y `parse_print`. En `interp.c`, los casos `STMT_LET` y `STMT_PRINT` de `exec_statement`.
Con eso, el intérprete ya corre programas desde un archivo. Creen uno propio con un `let` y un `print`, y córranlo.

```sh
make lab
LAB_DIR=lab python3 -m unittest test_lab.LetAndPrint
```

### Parte 3: `if` (unos 15 minutos)

Escriban `parse_if` y `eval_if`. El parser debe liberar lo que ya leyó si algo falla a la mitad. `eval_if` solo evalúa la rama
elegida, y eso es parte del lenguaje, no una optimización.

```sh
make lab
LAB_DIR=lab python3 -m unittest test_lab.IfExpression
```

### Parte 4: `def` y llamadas (unos 45 minutos)

1. Terminen `parse_def`, y escriban `parse_call` con un arreglo que crece, como en `parse_parameters`.
2. Antes de escribir `eval_call`, dibujen en papel los marcos de `fact(3)`, en el formato de la semana 3.
3. Terminen `eval_call`, siguiendo los cuatro pasos de su comentario. **El marco nuevo cuelga del global.**

```sh
make lab
build/lab/mini lab/programs/fact.mini
build/lab/mini lab/programs/fib.mini
LAB_DIR=lab python3 -m unittest test_lab.Calls
```

**Si no alcanza el tiempo:** lo que falte de `eval_call` lo terminan antes de la sesión 2, que empieza dándolo por hecho.

## Sesión 2: probar y repasar

### Parte 5: el conjunto de pruebas (unos 25 minutos)

```sh
make test-lab
```

Vayan grupo por grupo: `Programs`, `RunErrors`, `SyntaxErrors` e `Interface`. Si hay una fuga, el informe de ASan dice en qué
línea se reservó ese bloque. La pregunta es siempre la misma: ¿qué camino de error salió de la función sin liberarlo? También corran,
y lean, lo que pasa con los programas de `lab/programs` que deben fallar.

```sh
build/lab/mini lab/programs/caller_local.mini
build/lab/mini lab/programs/wrong_args.mini
build/lab/mini lab/programs/runaway.mini
```

### Parte 6: su programa, y una prueba que encuentre un bug (unos 30 minutos)

1. Escriban en `lab/mine/` un programa propio de Mini que haga algo que les interese, con su resultado en un `.expected` del mismo
   nombre. `example.mini` es el modelo. `make test-lab` corre todo lo que haya en esa carpeta.
2. Ahora introduzcan un bug a propósito en `interp.c`, uno por vez. El capítulo trabaja un ejemplo, `env_new((Env *) frame)`. Con estos
   otros dos, escriban en `lab/mine/` un programa que lo atrape, y que dé bien sin el bug. Antes, comprueben que `fact.mini` y `fib.mini` no
   lo atrapan:
   - `eval_call` define los parámetros al revés: `params[count - 1 - i]`.
   - `eval_if` trata como falso a todo lo que no sea positivo: `condition > 0`.
3. Corran su programa con el bug: debe fallar. Deshagan cada cambio, y comprueben que vuelve a pasar. Si encontraron un bug
   real de su intérprete en el camino, mejor: déjenlo anotado en un comentario del programa que lo atrapó.

### Parte 7: repaso (unos 35 minutos)

Sin mirar los apuntes, respondan las preguntas de repaso de la guía de la semana 15. Luego tomen la tabla "Qué idea sirvió en
cada parte" de los apuntes, tápenla, y digan para cada parte del intérprete de qué semana salió, y señalen una línea de código
donde se ve. Terminen con los ejercicios que el capítulo marca como de repaso.

## Si sobra tiempo

1. Agreguen un límite de profundidad: un contador en `Interp` y un error de ejecución en vez de un stack overflow. ¿Qué
   valor le ponen, y por qué ese? ¿Hace falta otro cuidado si cambia el tamaño de la pila?
2. Permitan `print` de varios valores: `print a, b`. ¿Qué cambia en la gramática, en `Stmt` y en `stmt_free`?
3. Hagan que un `def` con dos parámetros del mismo nombre sea un error de sintaxis. Hoy, gana el último.
