Introducción
Las Transformaciones AST (Abstract Syntax Tree) son una característica poderosa de Groovy que permite modificar el árbol de sintaxis abstracta del código durante la compilación. Esto permite a los desarrolladores agregar comportamientos adicionales, optimizar el código y realizar verificaciones en tiempo de compilación.
Conceptos Clave
- AST (Abstract Syntax Tree): Representación estructurada del código fuente en forma de árbol, donde cada nodo representa una construcción sintáctica.
- Transformaciones AST: Modificaciones que se aplican al AST durante la fase de compilación.
- Anotaciones: Utilizadas para marcar clases, métodos o campos que deben ser transformados.
Tipos de Transformaciones AST
- Transformaciones Locales: Aplicadas a elementos específicos del código, como métodos o clases.
- Transformaciones Globales: Aplicadas a todo el código fuente durante la compilación.
Ejemplo Práctico: @ToString
Una de las transformaciones AST más comunes en Groovy es la anotación @ToString
, que genera automáticamente un método toString()
para una clase.
Ejemplo de Código
import groovy.transform.ToString @ToString class Persona { String nombre int edad } def persona = new Persona(nombre: 'Juan', edad: 30) println persona.toString()
Explicación
- Anotación
@ToString
: Indica que se debe generar un métodotoString()
para la clasePersona
. - Clase
Persona
: Contiene dos campos,nombre
yedad
. - Instancia de
Persona
: Se crea una instancia dePersona
y se imprime su representación en cadena.
Salida Esperada
Creación de Transformaciones AST Personalizadas
Paso 1: Crear la Anotación
import java.lang.annotation.ElementType import java.lang.annotation.Retention import java.lang.annotation.RetentionPolicy import java.lang.annotation.Target @Retention(RetentionPolicy.SOURCE) @Target([ElementType.TYPE]) @interface MiTransformacion { }
Paso 2: Implementar la Transformación
import org.codehaus.groovy.ast.* import org.codehaus.groovy.ast.builder.AstBuilder import org.codehaus.groovy.ast.expr.* import org.codehaus.groovy.ast.stmt.* import org.codehaus.groovy.control.* import org.codehaus.groovy.transform.* @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS) class MiTransformacionAST implements ASTTransformation { void visit(ASTNode[] nodes, SourceUnit source) { if (nodes.length != 2 || !(nodes[0] instanceof AnnotationNode) || !(nodes[1] instanceof AnnotatedNode)) { return } AnnotatedNode parent = (AnnotatedNode) nodes[1] if (parent instanceof ClassNode) { ClassNode classNode = (ClassNode) parent addMetodoSaludar(classNode) } } private void addMetodoSaludar(ClassNode classNode) { MethodNode metodoSaludar = new MethodNode( 'saludar', ACC_PUBLIC, ClassHelper.VOID_TYPE, [] as Parameter[], [] as ClassNode[], new BlockStatement( [new ExpressionStatement(new MethodCallExpression( new VariableExpression('this'), 'println', new ConstantExpression('¡Hola desde la transformación AST!') ))], new VariableScope() ) ) classNode.addMethod(metodoSaludar) } }
Paso 3: Usar la Transformación
Explicación
- Anotación
@MiTransformacion
: Marca la claseMiClase
para aplicar la transformación. - Transformación
MiTransformacionAST
: Implementa la lógica para agregar un métodosaludar
a la clase anotada. - Método
saludar
: Imprime un mensaje cuando se llama.
Salida Esperada
Ejercicio Práctico
Ejercicio
Crea una transformación AST que agregue un método despedir
a cualquier clase anotada con @Despedida
. El método debe imprimir "¡Adiós desde la transformación AST!".
Solución
- Crear la Anotación
@Despedida
:
import java.lang.annotation.ElementType import java.lang.annotation.Retention import java.lang.annotation.RetentionPolicy import java.lang.annotation.Target @Retention(RetentionPolicy.SOURCE) @Target([ElementType.TYPE]) @interface Despedida { }
- Implementar la Transformación
DespedidaAST
:
import org.codehaus.groovy.ast.* import org.codehaus.groovy.ast.builder.AstBuilder import org.codehaus.groovy.ast.expr.* import org.codehaus.groovy.ast.stmt.* import org.codehaus.groovy.control.* import org.codehaus.groovy.transform.* @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS) class DespedidaAST implements ASTTransformation { void visit(ASTNode[] nodes, SourceUnit source) { if (nodes.length != 2 || !(nodes[0] instanceof AnnotationNode) || !(nodes[1] instanceof AnnotatedNode)) { return } AnnotatedNode parent = (AnnotatedNode) nodes[1] if (parent instanceof ClassNode) { ClassNode classNode = (ClassNode) parent addMetodoDespedir(classNode) } } private void addMetodoDespedir(ClassNode classNode) { MethodNode metodoDespedir = new MethodNode( 'despedir', ACC_PUBLIC, ClassHelper.VOID_TYPE, [] as Parameter[], [] as ClassNode[], new BlockStatement( [new ExpressionStatement(new MethodCallExpression( new VariableExpression('this'), 'println', new ConstantExpression('¡Adiós desde la transformación AST!') ))], new VariableScope() ) ) classNode.addMethod(metodoDespedir) } }
- Usar la Transformación:
Salida Esperada
Conclusión
Las transformaciones AST en Groovy son una herramienta poderosa para modificar y mejorar el código durante la compilación. Permiten agregar comportamientos adicionales, realizar optimizaciones y verificaciones en tiempo de compilación. Con la práctica, puedes crear transformaciones personalizadas que se adapten a tus necesidades específicas y mejoren la eficiencia y la calidad de tu código.
Curso de Programación Groovy
Módulo 1: Introducción a Groovy
Módulo 2: Sintaxis de Groovy y Características del Lenguaje
Módulo 3: Programación Orientada a Objetos en Groovy
Módulo 4: Características Avanzadas de Groovy
Módulo 5: Groovy en la Práctica
- Entrada/Salida de Archivos
- Trabajando con XML y JSON
- Acceso a Bases de Datos
- Desarrollo Web con Groovy
Módulo 6: Pruebas y Depuración
Módulo 7: Ecosistema y Herramientas de Groovy
- Herramienta de Construcción Gradle
- Framework de Pruebas Spock
- Framework Grails
- Otras Bibliotecas y Herramientas de Groovy
Módulo 8: Mejores Prácticas y Temas Avanzados
- Estilo de Código y Convenciones
- Optimización del Rendimiento
- Consideraciones de Seguridad
- Concurrencia en Groovy