Platzi
Platzi

¡Invierte en ti y celebremos! Adquiere un plan Expert o Expert+ a precio especial.

Antes: $349
$259
Currency
Antes: $349
Ahorras: $90
COMIENZA AHORA
Termina en: 9D : 4H : 17M : 49S

Debes iniciar sesión

Para ver esta clase crea una cuenta sin costo o inicia sesión

Lectura de caracteres y tokens

5/58

Efectivamente los errores fueron mis amigos jaja, tuve otros errores porque había escrito mal una sintaxis en Python, y me decía: “Error en la línea X” y fui a ver la línea X y así encontré mis errores 😄
.
Apenas estamos iniciando pero ando con hype jajaja, me gusta el TDD. Por cierto, algo curioso es que, por la forma en la que se leen los tokens ilegales, el orden en el que los comparamos en el expected_tokens debe ser el mismo que el orden en el que pusimos los tokens en source, de lo contrario el assert fallará aunque los tokens sí sean ilegales simplemente por el orden

A mí los test no me fallaban, solo me decía Ran 0 tests in 0.007s (se corrieron cero pruebas en 0.007 segundos) y al final lo solucioné usando el comando:

mypy . && py -m unittest discover  -p "*_test.py"

en vez de

mypy . && nosetests

A ver, entendamos lo que tenemos por acá:

def test_ilegal(self) -> None:
        source: str = '!¿@'
        lexer: Lexer = Lexer(source)
        tokens: List[Token] = []

        for i in range(len(source)):
            tokens.append(lexer.next_token())

        expected_tokens: List[Token] = [
            Token(TokenType.ILLEGAL, '!'),
            Token(TokenType.ILLEGAL, '¿'),
            Token(TokenType.ILLEGAL, '@')
        ]

        self.assertEquals(tokens, expected_tokens)

Aquí tenemos un test en el que estamos cargando una lista con caracteres inválidos para nuestro lenguaje. Luego de esto creamos una lista de los tokens esperados, en este caso queremos que el Lexer devuelva que los tres caracteres son ilegales como TokenType.ILLEGAL Para hacer esto alimentamos el lexer con la línea de texto que contiene los caracteres ilegales. Esta línea es revisada por el lexer en next_token Method validando que el carácter sea ilegal y devolviendo un TokenType.ILLEGAL Sin embargo, debemos notar que en este punto el Lexer siempre va a devolver Token.ILLEGAL para lo que sea que lea, podemos meterle cualquier carácter alfanumérico que siempre va a devolver Token.ILLEGAL ya que aún no estamos haciendo ninguna validación.

def next_token(self) -> Token:
        token = Token(TokenType.ILLEGAL, self._character)
        self._read_character()
        return token

En el método next_token devolvemos siempre Tokens Ilegales por cada carácter recibido en la línea.

def _read_character(self) -> None:
        if self._read_position >= len(self._source):
            self._character = ''
        else:
            self._character = self._source[self._read_position]
        self._position = self._read_position
        self._read_position += 1

Solamente está moviendo la lectura un carácter hacia adelante de la lista recibida en la línea de texto.

  • Rescatamos acá un par de cosas, los Lexer van a moverse linea a linea por cada archivo de código fuente.

  • Los token nos van a permitir usar los Enum para identificar el tipo de elemento que tenemos en cada línea

  • Tendremos que encontrar una forma de pasear o validar palabras más allá de caracteres simples, es como veíamos en la clase pasada lo que haremos con los espacios en blanco.

Muy cool el TDD!!!

Nota mental, para que los tests corran hay que estar en la carpeta raíz que contiene la carpeta lpp. De lo contrario se muestra un error como este:

. is not a valid Python package name

Tengo que darle un par de vueltas más. Complicado el tema

Efectivamente los errores fueron mis amigos jaja, tuve otros errores porque había escrito mal una sintaxis en Python, y me decía: “Error en la línea X” y fui a ver la línea X y así encontré mis errores 😄
.
Apenas estamos iniciando pero ando con hype jajaja, me gusta el TDD. Por cierto, algo curioso es que, por la forma en la que se leen los tokens ilegales, el orden en el que los comparamos en el expected_tokens debe ser el mismo que el orden en el que pusimos los tokens en source, de lo contrario el assert fallará aunque los tokens sí sean ilegales simplemente por el orden

A mí los test no me fallaban, solo me decía Ran 0 tests in 0.007s (se corrieron cero pruebas en 0.007 segundos) y al final lo solucioné usando el comando:

mypy . && py -m unittest discover  -p "*_test.py"

en vez de

mypy . && nosetests

A ver, entendamos lo que tenemos por acá:

def test_ilegal(self) -> None:
        source: str = '!¿@'
        lexer: Lexer = Lexer(source)
        tokens: List[Token] = []

        for i in range(len(source)):
            tokens.append(lexer.next_token())

        expected_tokens: List[Token] = [
            Token(TokenType.ILLEGAL, '!'),
            Token(TokenType.ILLEGAL, '¿'),
            Token(TokenType.ILLEGAL, '@')
        ]

        self.assertEquals(tokens, expected_tokens)

Aquí tenemos un test en el que estamos cargando una lista con caracteres inválidos para nuestro lenguaje. Luego de esto creamos una lista de los tokens esperados, en este caso queremos que el Lexer devuelva que los tres caracteres son ilegales como TokenType.ILLEGAL Para hacer esto alimentamos el lexer con la línea de texto que contiene los caracteres ilegales. Esta línea es revisada por el lexer en next_token Method validando que el carácter sea ilegal y devolviendo un TokenType.ILLEGAL Sin embargo, debemos notar que en este punto el Lexer siempre va a devolver Token.ILLEGAL para lo que sea que lea, podemos meterle cualquier carácter alfanumérico que siempre va a devolver Token.ILLEGAL ya que aún no estamos haciendo ninguna validación.

def next_token(self) -> Token:
        token = Token(TokenType.ILLEGAL, self._character)
        self._read_character()
        return token

En el método next_token devolvemos siempre Tokens Ilegales por cada carácter recibido en la línea.

def _read_character(self) -> None:
        if self._read_position >= len(self._source):
            self._character = ''
        else:
            self._character = self._source[self._read_position]
        self._position = self._read_position
        self._read_position += 1

Solamente está moviendo la lectura un carácter hacia adelante de la lista recibida en la línea de texto.

  • Rescatamos acá un par de cosas, los Lexer van a moverse linea a linea por cada archivo de código fuente.

  • Los token nos van a permitir usar los Enum para identificar el tipo de elemento que tenemos en cada línea

  • Tendremos que encontrar una forma de pasear o validar palabras más allá de caracteres simples, es como veíamos en la clase pasada lo que haremos con los espacios en blanco.

Muy cool el TDD!!!

Nota mental, para que los tests corran hay que estar en la carpeta raíz que contiene la carpeta lpp. De lo contrario se muestra un error como este:

. is not a valid Python package name

Tengo que darle un par de vueltas más. Complicado el tema