Desarrollo de un AST en Python: Creación de la Clase Programa
Clase 14 de 58 • Curso de Creación de Lenguajes de Programación: Intérpretes
Resumen
¿Cómo crear un nodo principal para un AST?
La creación del Abstract Syntax Tree (AST) en programación es crucial para interpretar y transformar el código de una manera estructurada. El nodo principal que representa al AST es fundamental, ya que es él quien contiene todos los sub-nodos, ya sean expresiones o declaraciones. Vamos a desarrollar una clase de programa que será un nodo principal en el AST, junto con un test básico para verificar su implementación.
¿Cómo inicializar el nodo principal del AST?
Para establecer correctamente la base de nuestro AST, necesitamos crear una clase Programa, que será de tipo AST Node. Esto requerirá también del diseño de un test denominado test_parse_program, que nos indicará si el parser es capaz de devolver correctamente un objeto de tipo Programa. Para llegar a este punto, seguimos estos pasos:
- 
Crear Archivos Necesarios: - Se genera un archivo parser.pyque contendrá la implementación del parser.
- Se crea un archivo parser_test.pydentro de una carpetatestpara los test unitarios.
 
- Se genera un archivo 
- 
Importar Dependencias: - Utilizamos unittest.TestCasepara estructurar nuestros tests.
- Inicializamos una clase ParserTestcomo subclase deTestCase.
 
- Utilizamos 
- 
Implementación del Test: - Se inicia el test test_parse_program, donde el enfoque es en las aserciones.
- Se introduce una simple estructura de programa: "variable x es igual a 5".
- Se genera un lexer para convertir el código en tokens, y se crea un parser que usará esos tokens.
 
- Se inicia el test 
¿Cómo crear el test inicial para el parser?
Al seguir la metodología Test Driven Development (TDD), es vital desarrollar los tests primero y luego el código necesario para que los tests pasen exitosamente. Aquí algunos pasos básicos:
- 
Definir las Aserciones: - Comprobar que el objeto generado no es None.
- Verificar que el objeto es de tipo Programa.
 
- Comprobar que el objeto generado no es 
- 
Configurar el Parser: - Se busca que el parser tome un lexer y devuelva un objeto de Programausandoparse_program.
 
- Se busca que el parser tome un lexer y devuelva un objeto de 
Veamos cómo se refleja esto en código:
from unittest import TestCase
class ParserTest(TestCase):
    def test_parse_program(self):
        program = "variable x = 5"
        lexer = Lexer(program)
        parser = Parser(lexer)
        parsed_program = parser.parse_program()
        
        self.assertIsNotNone(parsed_program)
        self.assertIsInstance(parsed_program, Program)
¿Cómo definir la clase Programa?
La clase Programa debe estar bien estructurada para recibir los Statements que forman parte de nuestro AST. Esta clase requiere de un constructor y una implementación mínima de varios métodos:
- 
Estructura de la Clase: - Se define la clase Programcomo una subclase deASTNode.
- Su constructor debe recibir una lista de Statements.
 
- Se define la clase 
- 
Implementar Métodos Requeridos: - token_literal: Devuelve el token literal del primer statement o una cadena vacía en caso de que no haya ninguno.
- __str__: Retornar una concatenación de todos los statements en forma de string.
 
Aquí un ejemplo simplificado de cómo se podría implementar la clase:
class Program(ASTNode):
    def __init__(self, statements):
        self.statements = statements
    
    def token_literal(self):
        if len(self.statements) > 0:
            return self.statements[0].token_literal()
        return ""
    
    def __str__(self):
        return "".join(str(statement) for statement in self.statements)
¿Cómo implementar un parser básico?
La implementación del parser es el siguiente paso después de confirmar que tenemos la clase Programa correctamente configurada. Un parser básico puede inicializarse de la siguiente manera:
- 
Definir el Constructor del Parser: - El constructor debe aceptar un lexer.
- Es necesario asignar el lexer a una variable interna para su uso posterior.
 
- 
Implementar parse_programBásico:- Inicializar un objeto Programacon una lista vacía de statements.
- Retornar el objeto Programa.
 
- Inicializar un objeto 
Aquí hay una representación básica del parser:
class Parser:
    def __init__(self, lexer):
        self.lexer = lexer
    def parse_program(self):
        return Program([])
Con cada componente correctamente implementado y testeado, podemos estar seguros de que nuestro nodo principal para el AST está listo para ampliaciones futuras. Esto incluye añadir más tipos de statements y seguir comprobando cada nueva adición con tests adicionales. Recuerda siempre acudir al sistema de comentarios ante cualquier duda o esclarecimiento necesario durante tu aprendizaje en programación.