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

1

Construcción de Intérpretes en Python desde Cero

2

Programación en Platzi: Compiladores e Intérpretes en Español

Construcción del lexer o tokenizador

3

Análisis Léxico: Creación de Tokens para Léxers

4

Tipos de Datos y Tokens en Python

5

Programación: Construcción de Lexer con Test-Driven Development

6

Pruebas Regulares en Python: Implementación de un Lexer

7

Tokens y Palabras Clave en Python: Gestión Avanzada

8

Tokens y Reconocimiento de Funciones en Lexers

9

Implementación de Operadores en Lexer de Platzi

10

Operadores Lógicos en Lenguajes de Programación

11

REPL en Python: Crear, Ejecutar y Probar Lexer Básico

Construcción del parser o analizador sintáctico

12

Construcción de un AST para Lenguaje Platzi

13

Creación de Nodos Abstractos para AST en Python

14

Parser de Lenguaje: Creación de Nodos AST en Python

15

Parseo de Let Statements en Lenguaje Platzi

16

Funciones de Tokenización en Lenguaje de Programación

17

Errores comunes al programar en Python

18

Base de Datos Relacional: Diseño y Consultas Básicas

19

Parsing con Pratt: Manejo de Precedencia y Asociatividad

20

Pruebas de AST para parsers en Python

21

Parseo de Expresiones con Pratt Parsing en Python

22

Parseo de Identificadores en AST Python

23

Parseo de Identificadores: Expresiones en PlatziLang

24

Parseo de Enteros en Python: Implementación y Pruebas

25

Operadores Prefijo en Parsers: Diseño e Implementación

26

Operadores InFix: Implementación y Pruebas en Python

27

Parseo de Operadores InFix en Python

28

Expresiones Booleanas en Lenguaje Platzi: Implementación y Testeo

29

"Precedencia de Operadores en Python"

30

Parentesis en Expresiones Matemáticas en Python

31

Tipos de Datos en el Lenguaje de Programación Platzi

32

Programación de Parsers en Lenguajes de Programación

33

Parsiendo Funciones en Lenguaje Platzi: Creación y Pruebas de Nodos AST

34

Programación Funcional: Construcción y Parsing en Python

35

Parentesis: Uso y Función en Llamadas a Procedimientos

36

Precedencia de Llamadas en Parsers: Implementación en AST

37

Parseo de Expresiones en LET y RETURN Statements

38

Construcción del REPL en Python: Lexer y Parser en Sintaxis Abstracta

Evaluación o análisis semántico

39

Análisis Semántico en Lenguajes de Programación

40

Evaluación de Código: Intérpretes vs Compiladores

41

Representación de Objetos en Python: Enteros, Booleanos y Null

42

Evaluación de enteros en Python: Crear y probar evaluador recursivo

43

Diseño de Patrones Singleton en Python

44

Semántica de Prefijos en Lenguajes de Programación

45

Evaluación de Expresiones Infix en Python

46

Condicionales en Lenguajes de Programación

47

Evaluación del Statement Return en Python

48

Manejo de Errores Semánticos en Lenguajes de Programación

49

Declaración de Variables y Ambientes en Lenguajes de Programación

50

Entornos y Cláusulas en Python: Manejo y Error Handling Avanzado

51

Declaración de Procedimientos en Lenguaje Platzi

52

Implementación y uso de closures en Platzi Programming

Mejora del intérprete

53

Implementación de strings en un intérprete Python

54

Operaciones en Strings: Concatenación y Comparación

55

Construcción de Funciones Built-in en Python

56

Función Longitud en Lenguaje Platzi

Siguientes pasos

57

Creación de Listas y Diccionarios en Python Avanzado

58

Construcción de intérpretes con Python desde cero

No tienes acceso a esta clase

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

Pruebas de AST para parsers en Python

20/58
Recursos

¿Cómo se crea y prueba un Abstract Syntax Tree (AST) en el desarrollo de un Parser?

En el mundo del desarrollo de un parser, uno de los componentes esenciales es el Abstract Syntax Tree (AST). Este árbol es la representación estructural que descompone un programa en sus componentes básicos, lo que permite al parser identificar y manipular el código de manera más eficiente. A lo largo de este artículo, exploraremos cómo se crea y se prueba un AST en el contexto del desarrollo de un parser.

¿Qué es un AST y por qué es fundamental?

Un AST es una estructura de datos que representa el código de un programa de manera jerárquica. Cada nodo del árbol representa una construcción en el lenguaje fuente. Esta estructura hace más sencillo el análisis, transformación y generación de código, por lo que resulta indispensable en compiladores e intérpretes.

La belleza del AST radica en su capacidad para modelar el programa de manera que las modificaciones y optimizaciones sean más sencillas de implementar. Además, nos permite verificar que el parser produce efectivamente la estructura correcta que esperamos.

¿Cómo construir pruebas unitarias para un AST?

Una parte crucial al construir parsers es asegurarse de que los ASTs se generan correctamente. En el siguiente ejemplo, comenzamos creando un archivo de prueba para nuestro AST y procedemos mostrando cómo generar un test para un let statement.

# Importamos las dependencias necesarias
from unittest import TestCase
from lpp_ast import Program, LetStatement, Identifier
from lpp_token import Token, TokenType

# Creamos la clase de pruebas
class ASTTest(TestCase):

    def test_let_statement(self):
        program = Program(statements=[])

        # Creamos un let statement para el AST
        token = Token(TokenType.LET, "let")
        name = Identifier(Token(TokenType.IDENT, "miVariable"), "miVariable")
        value = Identifier(Token(TokenType.IDENT, "otraVariable"), "otraVariable")
        
        let_stmt = LetStatement(token=token, name=name, value=value)
        program.statements.append(let_stmt)

        # Convertimos el programa a un string
        program_string = str(program)

        # Afirmamos que la conversión es correcta
        self.assertEqual(program_string, "let miVariable = otraVariable;")

¿Qué desafíos adicionales plantea la implementación de un AST?

A menudo, implementar un AST presenta retos como manejar statements complejos como return, manejos de expresiones y combinaciones con múltiples tipos. En el fragmento anterior, vemos cómo se creó y verificó un let statement. Tu reto es construir un return statement similar.

¿Cómo continuar tu aprendizaje?

Con estos primeros pasos, ya tienes una base sólida para construir parsers más complejos que manejen estructuras más sofisticadas como funciones, operaciones matemáticas y condicionales. Además, es fundamental compartir tus soluciones y problemas en comunidades o foros de desarrolladores para recibir retroalimentación y distintas perspectivas.

Recuerda, el aprendizaje continuo y la práctica constante son vitales para dominar el desarrollo de compiladores e intérpretes. Si alguna parte no quedó clara o necesitas mejorar algún aspecto, compartir tus inquietudes y descubrir nuevas formas de resolver problemas enriquecerá tu experiencia. ¡No olvides que el viaje del aprendizaje es con persistencia y colaboración!

Aportes 7

Preguntas 1

Ordenar por:

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

No funciona ésta clase. “The media could not be loaded, either because the server or network failed or because the format is not supported.”

Ya intenté con tres navegadores. Desde mi celular y la computadora de mi hermana.

No sé si está bien que haga esto pero lo paso igual, si está mal me lo pueden comentar y no lo vuelvo a hacer nunca más y borro el comentario, bueno la cosa que esta es mi implementación del reto pero con mi lenguaje hecho en Rust:

use ezcript_ast::ast::Program;
use ezcript_ast::expressions::{Expressions, Integer};
use ezcript_ast::statements::{ReturnStatement, Statements};
use ezcript_lexer::tokens::{Literal, Token, TokenKind};

#[test]
fn test_ast_return_statement() {
    let resource: &str = "return 0";
    let program: Option<Program> =
        Program::new(vec![Statements::ReturnStatement(ReturnStatement::new(
            Token {
                kind: TokenKind::Keyword,
                lexeme: "return".to_string(),
                literal: None,
                line: 1,
            },
            Some(Expressions::Integer(Integer::new(
                Token {
                    kind: TokenKind::Number,
                    lexeme: "0".to_string(),
                    literal: Some(Literal::Number(0.0)),
                    line: 1,
                },
                0,
                1,
            ))),
            1,
        ))]);

    is_not_none!(program);
    let program_str = program.unwrap().to_string();

    assert_eq!(program_str, "return 0".to_string());
}
Reto superado: ```python def test_return_statement(self) -> None: program: Program = Program(statements=[ ReturnStatement( token=Token(TokenType.RETURN, literal='vuelto'), return_value =Identifier( token=Token(TokenType.IDENT, literal='my_var'), value='my_var' ), ) ]) program_str = str(program) self.assertEqual(program_str, 'vuelto my_var;') ```

el video no se ve!!!

Listo, para mi test lo único que hice fue moduificar el mismo test de let jajaja, pero únicamente cambié el token que debería regresar y su return value:

def test_return_statement(self) -> None:

        program: Program = Program(statements=[

            ReturnStatement(

                token=Token(TokenType.RETURN, literal="regresa"),

                return_value=Identifier(
                    token=Token(TokenType.IDENT, literal="mi_var"),
                    value="mi_var"
                )

            )

        ])

        program_str = str(program)
        self.assertEquals(program_str, "regresa mi_var;")

En este caso, el return_value de la clase ReturnStatement recibe una expresion,pero como la clase Identifier extiende de la misma clase Expresion entonces puedo pasarle un Identifier sin problemas 😄

from unittest import TestCase

from frl.ast import ReturnStatement
from frl.token import (
	Token,
	TokenType
)


class ASTTest(TestCase):
	def test_return_statement(self): -> None:
		program: Program = Program(statements=[
			ReturnStatement(
				token=Token(TokenType.RETURN, literal="regresa"),
				return_value=Identifier(
					token=Token(TokenType.IDENT, literal="mi_var"),
					value="mi_var"
				)
			)
		])
	
		program_str = str(program)

		self.assertEquals(program_str, "regresa mi_var;")

Aquí esta mi solución al reto 😃