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.py
que contendrá la implementación del parser. - Se crea un archivo
parser_test.py
dentro de una carpetatest
para los test unitarios.
- Se genera un archivo
-
Importar Dependencias:
- Utilizamos
unittest.TestCase
para estructurar nuestros tests. - Inicializamos una clase
ParserTest
como 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
Programa
usandoparse_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
Program
como 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_program
Básico:- Inicializar un objeto
Programa
con 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.