Introducción al desarrollo de intérpretes y lenguajes de programación

1

Aprende a desarrollar lenguajes de programación con intérpretes

2

Desarrolla LPP o Lenguaje de Programación Platzi

Construcción del lexer o tokenizador

3

¿Qué es análisis léxico? Funcionamiento del lexer y tokens

4

Estructura y definición de tokens en Python

5

Lectura de caracteres y tokens

6

Tokens ilegales, operadores de un solo carácter y delimitadores

7

Reconocimiento y diferenciación entre letras y números

8

Declaración y ejecución de funciones

9

Extensión del lexer: condicionales, operaciones y booleanos

10

Operadores de dos caracteres

11

Primera versión del REPL con tokens

Construcción del parser o analizador sintáctico

12

¿Qué es un parser y AST?

13

Estructura y definición de nodos del AST en Python

14

Parseo del programa o nodo principal

15

Parseo de assignment statements

16

Parseo de let statements

17

Parseo de errores

18

Parseo del return statement

19

Técnicas de parsing y pratt parsing

20

Pruebas del AST

21

Implementación del pratt parser

22

Parseo de Identifiers: testing

23

Parseo de Identifiers: implementación

24

Parseo de enteros

25

Prefix operators: negación y negativos

26

Infix operators y orden de las operaciones: testing

27

Infix operators y orden de las operaciones: implementación

28

Parseo de booleanos

29

Desafío: testing de infix operators y booleanos

30

Parseo de expresiones agrupadas

31

Parseo de condicionales: testing y AST

32

Parseo de condicionales: implementación

33

Parseo de declaración de funciones: testing

34

Parseo de declaración de funciones: AST e implementación

35

Parseo de llamadas a funciones: testing y AST

36

Parseo de llamadas a funciones: implementación

37

Completando los TODOs o pendientes del lexer

38

Segunda versión del REPL con AST

Evaluación o análisis semántico

39

Significado de símbolos

40

Estrategias de evaluación para intérpretes de software

41

Representación de objetos

42

Evaluación de expresiones: enteros

43

Evaluación de expresiones: booleanos y nulos

44

Evaluación de expresiones: prefix

45

Evaluación de expresiones: infix

46

Evaluación de condicionales

47

Evaluación del return statement

48

Manejo de errores

49

Ambiente

50

Bindings

51

Evaluación de funciones

52

Llamadas a funciones

Mejora del intérprete

53

Implementación de strings

54

Operaciones con strings

55

Built-in functions: objeto y tests

56

Built-in functions: evaluación

Siguientes pasos

57

Retos para expandir tu intérprete

58

Continúa con el Curso de Creación de Compiladores de Software

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Convierte tus certificados en títulos universitarios en USA

Antes: $249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

16 Días
12 Hrs
48 Min
39 Seg

Parseo de let statements

16/58
Recursos

Aportes 10

Preguntas 1

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Muy bien, mi solución es poco eficiente comparada con la del profesor, pero antes de ponerla, explicaré un par de cosas importantes (tuve que ver la solución del profesor porque no entendía qué pasaba xD)
.
Mi idea era que, en program.statements estaban guardados cada uno de los statements, por lo que basándome en la clase LetStatement, debería tener un nombre disponible, así que mi idea era hacer esto:

self.assertEqual(program.statements[0].name, "x")
self.assertEqual(program.statements[1].name, "y")
self.assertEqual(program.statements[2].name, "foo")

Sin embargo, me salía un error de que name no existía en el statement y yo estaba de “¡¿Cómo así que noe existe?! No tas viendo que ahí está definido dentro de la clase?”
.
Quería hacer prints desde los tests para debuguear, pero no podía usar la función print() desde los tests, no se imprimía nada, de ahi descubrí que si quieres usar prints en los tests tienes que correr este comando:

mypy . && nosetests -s

Así se imprime lo que quiera debuguear, gracias a esto descrubrí que cada statement era un string, y por eso no estaba definida la propiedad name… ¡Pues claro!, LetStatement tiene el dunder method __str__ que hace que cada vez que se consulte una instancia de statement esta devuelva un string… revisando el código del profesor ví que el estaba usando una función llamada cast(), no sé exactamente lo que hace pero intuyo que esa función convierte ese string generado por el dunder method a una instancia de LetStatement, así que aplicándolo, llegue a esta conclusión:

self.assertEqual(cast(LetStatement, program.statements[0]).name, "x")
self.assertEqual(cast(LetStatement, program.statements[1]).name, "y")
self.assertEqual(cast(LetStatement, program.statements[2]).name, "foo")

Todo bien pero… en el atributo name se guarda una instancia de Identifier, así que tenía que acceder a su value (propiedad de la clase Identifier).

self.assertEqual(cast(LetStatement, program.statements[0]).name.value, "x")
self.assertEqual(cast(LetStatement, program.statements[1]).name.value, "y")
self.assertEqual(cast(LetStatement, program.statements[2]).name.value, "foo")

Pero soprresa, Identifier también tiene un dunder method xD Así que al final mi solución quedó así jaja:

self.assertEqual(cast(Identifier, cast(LetStatement, program.statements[0]).name).value, "x")
self.assertEqual(cast(Identifier, cast(LetStatement, program.statements[1]).name).value, "y")
self.assertEqual(cast(Identifier, cast(LetStatement, program.statements[2]).name).value, "foo")

Y solo hay que importar los módulos requeridos:

from typing import (
    cast
)

from lpp.ast import (
    Identifier,
    LetStatement,
    Program,
)

Después vi el código del profesor y el lo hizo con listas y bah! xD Al menos lo logré jaja, una hora para lograrlo:'D

Tal y como funciona el programa actualmente, si al quien prepare la prueba automatizada o al usuario que escriba el código, se le olvida escribir el punto y coma al final del último statement, el programa quedará en un loop infinito de todas maneras.

Para solucionar esto basta con cambiar la línea del archivo parse.py que tiene esto:

while self._current_token.token_type != TokenType.SEMICOLON:

y sustituirlo por esto

while self._current_token.token_type != TokenType.SEMICOLON and self._current_token.token_type != TokenType.EOF:
Toco vear la explicación del profe porque estaba díficil. En mi caso use `foo, bar y fizz` , y simplemente es de hacer la lista de nombres a esperar y la que se comparara. La lista díficil de sacar es la de que se comprara, para sacarla es de prestar atención que `Program` guarda una `List[Statement]` en estas pueden ir `LetStatement` ya que esta hereda de `Statement`, así que en este caso como todas son `LetStatement` podemos acceder a su atributo `name` y por parte de `name` como es declarada en el constructor de `LetStatement` como `Optional[Identifier]` podemos acceder a s u clase `Identifier` para obtener su atributo `value`. ```python expected_names = ['foo', 'bar', 'fizz'] names: List[str] = [] for statement in program.statements: names.append(statement.name.value) self.assertEqual(names, expected_names) ```
```python expected_names = ['foo', 'bar', 'fizz'] names: List[str] = [] for statement in program.statements: names.append(statement.name.value) self.assertEqual(names, expected_names) ```Toco vear la explicación del profe porque estaba díficil. En mi caso use `foo`, `bar` y `fizz`, y simplemente es de hacer la lista de nombres a esperar y la que se comparara. La lista díficil de sacar es la de que se comprara, para sacarla es de prestar atención que Program guarda una `List[Statement]` en estas pueden ir `LetStatement` ya que esta hereda de `Statement`, así que en este caso como todas son `LetStatement` podemos acceder a su atributo `name` y por parte de name como es declarada en el constructor de `LetStatement` como `Optional[Identifier]` podemos acceder a s u clase `Identifier` para obtener su atributo `value`.

Mi solucion usando la funcion zip de python.

El archivo de parser_test.py es:

    def test_identifiers(self) -> None:
        source: str = """
            variable x =  5;
            variable y = 10;
            variable foo = 20;
        """
        lexer: Lexer = Lexer(source)
        parser: Parser = Parser(lexer)

        program: Program = parser.parse_program()
        
        self.assertEqual(len(program.statements), 3)

        nombres = ['x','y','foo']
        for statement, nombre in zip(program.statements, nombres):
            self.assertEqual(statement.name.value,nombre)

Aqui les dejo el reto.

        self.assertEqual(cast(Identifier, cast(LetStatement, program.statements[0]).name).value ,'x')
        self.assertEqual(cast(Identifier, cast(LetStatement, program.statements[1]).name).value ,'y')
        self.assertEqual(cast(Identifier, cast(LetStatement, program.statements[2]).name).value ,'foo')

Por lo que entendi segun la documentacion:
https://mypy.readthedocs.io/en/stable/casts.html

La funcion cast(1, 2), basicamente lo que hace es decirle a mypy que trate al valor 2 como si fuera un tipo de valor 1.
En nuestro caso, ocupabamos que tratara a nuestro Statement, como un tipo de valor LetStatament, ya que al momento de declarar la lista de statements en program,

 def __init__(self, statements: List[Statement]) -> None:

le estamos diciendo que la lista va a contener valores de tipo Statement, pero la lista a la cual le estamos haciendo el test, contiene valores de tipo LetStatement, por lo que, cuando intentamos acceder a el name.value de el elemento de la lista, mypy nos dice " creo que eso no se va a poder", ya que el elemento de la lista se supone que tiene valores de tipo Statement, y este no tiene la propiedad .name. Por lo que aqui es donde entra cast, el cual de dice a mypy, "Trata a ese elemento de la lista que se supone que es un Statement, como un LetStatement y trata a su prop .name como un Identifier.

Eso fue lo que entendí de la documentación, si es que alguien se da cuenta que estoy incorrecto, porfavor dime jajaja.

Resolución del reto dentro del test_let_statements

letStatement = cast(LetStatement,program.statements[0])
        identifier = cast(Identifier, letStatement.name) 
        self.assertEqual(identifier.value,'x')
        letStatement = cast(LetStatement, program.statements[1])
        identifier = cast(Identifier, letStatement.name)
        self.assertEqual(identifier.value, 'y')
        letStatement = cast(LetStatement, program.statements[2])
        identifier = cast(Identifier, letStatement.name)
        self.assertEqual(identifier.value, 'foo')

Inicialización de current y peek tokens

En caso de que a alguien más le suceda, yo moví mi carpeta de trabajo a otra carpeta en otra ubicación y perdí nose, después de estar buscando pude volver a instalarlo en el entorno virtual usando

sudo pip3 install nose

Implementación de _expected_token y _advance_token