Entrega 3
Deadline: 22 de Octubre 2023
⚠ Importante
Recuerde las reglas del código de conducta.
Objetivos básicos de la entrega:
Implementación de tuplas
Mutación en el heap
Objetivo extra (a elección):
Records: acceso con nombres
Pattern-matching de tuplas
La evaluación se hace con specs grading, (vea los detalles aquí):
spec básica 4 pts
spec avanzada 1 pts
testing 0.5 pts
calidad del código 0.5 pts
1 Para empezar
Para partir, puede iniciar un nuevo branch en git con:
$ git checkout -b entrega3
⚠ Comentario
A partir de esta entrega, es opcional que hagan el merge con el repositorio de referencia
cdi
, porque resolver/debuggear los conflictors podría ser muy trabajoso, especialmente si implementaron tags en su AST. Si deciden no hacer el merge, miren el código del nuevo parser y AST como referencia para los cambios que deben hacer. Recuerde seguir la misma sintaxis concreta que usa el código de referencia y que se detalla en este enunciado. Esto es importante, pues su código será revisado con tests escritos usando dicha sintaxis.
luego puede actualizar el código de su intérprete de referencia con
$ git fetch cdi
$ git merge cdi/entrega3
Recuerde hacer un git commit
cada vez que avanza en su desarrollo,
y subir el código a su repositorio github para facilitar el acceso al código a los auxiliares en
caso de que necesiten ayuda.
Para entregar su solución, haga un release en github con nombre entrega3 y entregue el hash del commit en U-cursos junto con un archivo README.md con lo que intentaron hacer, lo que lograron hacer, y qué decisiones de diseño importantes tomaron en el proceso.
2 Tuplas
Extienda el compilador con soporte para tuplas con la sintaxis concreta (tup e1 .. en)
y la función de proyección (get e k)
que recupera el k
-ésimo elemento de la tupla e
.
Esto siguiendo la descripción en el apunte de tuplas.
Por ejemplo:
(let (t (tup (tup) true 42))
t)
produce el output:
(tup (tup) true 42)
Y además:
(get
(if
(<= 0 1)
(tup (print false) -3 42)
(tup true false 7))
(+ 1 1))
produce el output:
> false
42
Debe también actualizar su verificación dinámica de tipos para las operaciones sobre tuplas y agregar una verificación que asegure que el índice está en el rango correcto. Por ejemplo las siguientes expresiones
(get (+ 3 4) 1)
(set (tup 2 true) (tup) 12)
(get (tup 2) -3)
(set (tup true false) 2 false)
Type error: Expected tuple but got 7
Type error: Expected integer but got (tup)
Index out of bounds: Tried to access index -3 of (tup 2)
Index out of bounds: Tried to access index 2 of (tup true false)
3 Mutación
Añada la operación de mutación sobre tuplas (set e k v)
que asigna el k
-ésimo valor de la tupla e
a un nuevo valor v
.
Esta operación no crea una tupla nueva, sino que muta la memoria de la tupla existente.
Esto también siguiendo la descripción en el apunte de mutación.
Por ejemplo:
(get
(set
(tup (print false) -3 42)
(+ -1 1)
(print true))
0)
produce el output:
> false
> true
true
Recuerde añadir la verificación dinámica de tipos y el chequeo de índice para la operación set
.
4 Objetivo Extra: Records (1 pto)
⚠ Hint
Para estos dos objetivos extra deberá alterar el parser del lenguaje, estudie la implementación existente para guiarse en cómo hacerlo.
Añada la definición de records, es decir tuplas que se construyen con un constructor identificado por un record-id
y con campos nombrados que se emplean para proyectar.
Por ejemplo:
(
(record point3d x y z)
(def (addpoint3d p1 p2)
(point3d (+ (point3d-x p1) (point3d-x p2))
(+ (point3d-y p1) (point3d-y p2))
(+ (point3d-z p1) (point3d-z p2))))
(let (p (point3d 1 1 1))
(addpoint3d p p))
)
produce el output:
(tup 2 2 2)
Note que, al igual que las definiciones de funciones de primer orden, las definiciones de records son declaraciones y se ubican antes del cuerpo del programa. Es decir, la sintaxis concreta de las declaraciones y expresiones se extienden con las siguientes reglas en el BNF:
‹decl› ...( record recordId fieldId ... ) ‹expr› ...( recordId ‹expr› ... )( recordId-fieldId ‹expr› )
5 Objetivo Extra: Pattern-Matching de Tuplas (1 pto)
Extienda la funcionalidad de un let-binding para poder destruir una tupla de acuerdo con las siguientes reglas:
‹binding› ( IDENTIFIER ‹expr› )( ( tup IDENTIFIER ... ) ‹expr› ) ‹expr› ...( let ‹binding› ... ‹expr› )
Por ejemplo, el código siguiente
(def (f t)
(let
((tup x y z) t)
body))
es una sintaxis concisa para
(def (f t)
(let (x (get 0 t))
(let (y (get 1 t))
(let (z (get 2 t))
body))))
Y por lo tanto, el programa:
(
(def (f t)
(let ((tup x y z) t)
(+ (+ x y) z)))
(f (tup 2 3 5))
)
produce el output:
10
6 Testing
⚠ Importante
Asegúrese de estar utilizando la última versión de bbctester, para ello ejecute las siguientes instrucciones en la raíz del repositorio del bbctester.
$ make uninstall $ git pull $ make install
Recuerde que la documentación para escribir los tests se encuentra en este enlace.
Recuerde que la librería bbctester también permite probar códigos de test utilizando un intérprete usando |ORACLE
en la sección expected.
Use distintos directorios para definir tests que prueban funcionalidades diferentes, por ejemplo, tests/tup/create y tests/tup/get. También puede testear errores ocupando el campo STATUS: de los tests con CT error (compile time error) o RT error (runtime error) y el campo EXPECTED: con el mensaje de error que debería occurir.
Ejemplo de error:
NAME: if expression not tuple
DESCRIPTION: breaks with runtime error because the expression of a get isn't a tuple
STATUS: RT error
SRC:
(get true 0)
EXPECTED:
Type error: Expected tuple but got true
Además el oráculo debería simular estos errores, por ejemplo este test tiene el mismo resultado que el código anterior:
NAME: if expression not tuple
DESCRIPTION: breaks with runtime error because the expression of a get isn't a tuple
SRC:
(get true 0)
EXPECTED:
|ORACLE
Ejemplo de test usando intérprete de referencia sin errores:
NAME: conditional and arithmetic
DESCRIPTION: basic example using reference interpreter
SRC:
(add1 (if true
(+ 32 1)
(* 5 3)))
EXPECTED:
|ORACLE
⚠ Importante
Al poner un status de error, el mensaje dentro de EXPECTED: se interpreta como una expresión regular. La sintáxis de las expresiones y su interpretación se pueden ver en la documentación del modulo Str. En particular, los caracteres especiales $^\.*+?[] se deben escapar con un \, por ejemplo
(\+ 2 1)
.
Recuerde empezar cada linea de print
con el símbolo especial >.
NAME: printing within add1
DESCRIPTION: prints 1 and add 1 to the result
SRC:
(add1 (print 1))
EXPECTED:
> 1
2