Macro macro, burrito burrit

50 %
50 %
Information about Macro macro, burrito burrit

Published on December 15, 2016

Author: wiseslide

Source: slideshare.net

1. MACRO MACRO, BURRITOMACRO MACRO, BURRITOMACRO MACRO, BURRITOMACRO MACRO, BURRITOMACRO MACRO, BURRITOMACRO MACRO, BURRITO MACRO MACRO, BURRITO MACRO MACRO, BURRITO MACRO MACRO, BURRITO MACRO MACRO, BURRITO MACRO MACRO, BURRITO MACRO MACRO, BURRITO MACRO MACRO, BURRITO MACRO MACRO, BURRITO MACRO MACRO, BURRITOMACRO MACRO, BURRITO BURRITOBURRITOBURRITOBURRITOBURRITOBURRITO @marioggar 1

2. SOBRE MI Mario Garcia Trabajo en Kaleidos Programo con Groovy, JDK_8 https://twitter.com/marioggar http://kaleidos.net/ 2

3. DE QUE VOY A HABLAR ? Meta programacion Macros Asteroid 3

4. THEORY 101 Teoria basica para entender el api AST. 4

5. QUE 5 . 1

6. ABSTRACT SYNTAX TREE El compilador necesita una representacion de tu codigo: 5 . 2

7. EXPRESSIONS Una expresion es una combinacion de uno o mas valores, constantes variables, operadores, y funciones que el lenguage de programacion interpreta y ejecuta para producir otro valor. 5 . 3

8. BINARY ⇒ BOOLEAN BinaryExpression constant expression 1 token == constant expression 1 1 == 1 5 . 4

9. VARIABLE ⇒ CONSTANT ⇒ CALL variable expression ref constant myMethod param expression 3 ref.myMethod(3) 5 . 5

10. SENTENCIAS En programacion, una sentencia es la parte mas pequena de un lenguage de programacion imperativo que expresa una accion que se debe llevar a cabo. Una sentencia puede tener expresiones. 5 . 6

11. IF STATEMENT expression to evaluate statement to be executed if the boolean expression evaluates to true if(booleanExpression) { println "hello" // statement } 5 . 7

12. BLOCK STATEMENT A block statement is easily recognized by curly braces It is built from other statements containing expressions public void main(String[] args) { // block starts // this is inside a block statement } // block ends 5 . 8

13. BLOCK STATEMENT (CONT.) This block statement contains a return statement receiving a constant expression Hello Greach. public String greetings() { return "Hello Greach" } 5 . 9

14. NODES — Lord of the Rings A ring to rule them all 5 . 10

15. NODES (CONT.) Como esta estructurado nuestro programa. Agrupana sentencia y expressions. classes methods fields properties …​ 5 . 11

16. A CLASS NODE ClassNode may contain: methods, fields…​ MethodNode may contain statements, and expressions …​ class A { // ClassNode String greetings // FieldNode String hello() { // MethodNode } } 5 . 12

17. POR LO TANTO class A { // ClassNode String hello() // MethodNode { // blockStatement { return "Hello" // returnStatement(constantExpression) } // } } 5 . 13

18. CUANDO 6 . 1

19. EN QUE MOMENTOS PUEDO ENGANCHARME AL COMPILADOR PARA CAMBIAR EL AST ? Depends on type of transformation (Local vs Global) Depends on the Compilation Phase you need to target 6 . 2

20. COMPILATION PHASES Initialization, Parsing, Conversion, Semantic, Canonicalization, Instruction, Class, Output, Finalization Groovy Reference 6 . 3

21. RESUMIENDO Semantic Analysis Canonicalization Instruction Before that you have no types/scopes/imports…​ After that you better know ByteCode-Kunfu 6 . 4

22. META PROGRAMACION 7 . 1

23. 7 . 2

24. QUE ES ? "Metaprogramming bla bla blabla…​ It means that a program could be designed to read, generate, analyse or transform other programs, and even modify itself while running.bla blabla bla…​blabla bla blablabla minimize the number of lines of code to express a solution …​ y blablabla.  — https://en.wikipedia.org/wiki/Metaprogramming 7 . 3

25. RESUMIENDO…​ Leer, generar, analizar, transformar tu codigo Trata de expresar lo mismo con menos codigo 7 . 4

26. 7 . 5

27. DOS SABORES: En tiempo de EJECUCION En tiempo de COMPILACION 7 . 6

28. TIEMPO DE EJECUCION: PROS Sencillo Facil de testear 7 . 7

29. TIEMPO DE EJECUCION: CONS Dificil de aplicar aisladamente Problema de polucion del codigo Te das cuenta de los problemas en tiempo de ejecucion 7 . 8

30. EJEMPLOS: QUICK DEMO 7 . 9

31. TIEMPO DE EJECUCION: TABLA Name Category Difficulty invokeMethod Runtime Easy method/propertyMissing Runtime Easy MetaClass Runtime Easy/Tricky 7 . 10

32. TIEMPO DE COMPILACION: PROS Puedes controlar mejor como se aplican los cambios Puedes crear nuevas formas de expresar tu codigo Muchos problemas se detectan por el compilador 7 . 11

33. TIEMPO DE COMPILACION: CONS Hasta ahora curva de apredizaje parecida a…​ Haskell ? Desconocimiento del compilador de Groovy 7 . 12

34. TIEMPO DE COMPILACION: TABLA Name Category Difficulty Traits Compile time Super-Easy Extensions Compile time Easy Local Compile time Hard Global Compile time Hardcore 7 . 13

35. POR QUE SON NECESARIAS LAS MACROS ? 8

36. EN PARTE POR…​ 9

37. LA VIEJA TRANSFORMACION AST 10 . 1

38. 10 . 2

39. COSAS QUE NO CAMBIAN Transformaciones LOCALES Transformaciones GLOBALES 10 . 3

40. AST LOCALES 11 . 1

41. UN "SIMPLE" EJEMPLO: 11 . 2

42. ANOTACION package compile.old.local.md5 import org.codehaus.groovy.transform.GroovyASTTransformationClass 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]) @GroovyASTTransformationClass( ["compile.old.local.md5.MD5Transform"]) @interface MD5 { } 11 . 3

43. TRANSFORMATION import org.codehaus.groovy.ast.* import org.codehaus.groovy.control.* import org.codehaus.groovy.transform.* @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS) class MD5Transform extends AbstractASTTransformation { @Override void visit(ASTNode[] nodes, SourceUnit sourceUnit) { //... } } 11 . 4

44. APLICACION package compile.old.local.md5 @MD5 class Document { File file String name void printMD5() { println "===>${nameAsMD5()}" println "===>${fileAsMD5()}" } } 11 . 5

45. VEAMOS LA TRANSFORMACION…​ 11 . 6

46. 11 . 7

47. TRANSFORMACION (I) imports import static org.codehaus.groovy.ast.tools.GeneralUtils.* import static org.codehaus.groovy.ast.ClassHelper.* import org.codehaus.groovy.ast.* import org.codehaus.groovy.ast.expr.* import org.codehaus.groovy.ast.stmt.* import org.codehaus.groovy.control.* import org.codehaus.groovy.transform.* 11 . 8

48. TRANSFORMACION (II) clase transformacion @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS) class MD5Transform extends AbstractASTTransformation { 11 . 9

49. TRANSFORMACION (III) visit method @Override void visit(ASTNode[] nodes, SourceUnit sourceUnit) { ClassNode currentClass = (ClassNode) nodes[1] currentClass.fields.each { FieldNode field -> currentClass.addMethod(createMD5Method(field)) } } 11 . 10

50. TRANSFORMACION (IV) MethodNode createMD5Method(FieldNode node) { return new MethodNode("${node.name}asMD5", ACC_PUBLIC, ClassHelper.STRING_TYPE, [] as Parameter[], [] as ClassNode[], createBlock(node)) } 11 . 11

51. TRANSFORMACION (V) BlockStatement createBlock(FieldNode node) { return block( stmt( callX( callX( callX( callX( make(java.security.MessageDigest), 'getInstance', args(constX('MD5')) ), constX('digest'), args( callX( varX(node.name), constX('getBytes'), args(constX('UTF-8')) ) ) ), constX('encodeHex'), args() ), constX('toString'), 11 . 12

52. 11 . 13

53. QUE ESTA MAL EN EL EJEMPLO ? 11 . 14

54. AGGREGAR UN SIMPLE METODO…​ Requiere conocer bastante el API de AST Requiere saber como se construye el AST Requiere un monton de codigo :( 11 . 15

55. SE PODRIA HABER HECHO "MEJOR" ? 11 . 16

56. ASTBUILDER.BUILDFROMCODE AstBuilder.buildFromCode es el abuelo de las macros El codigo que genera es buggy Vamos que no lo uses! Si tienes que usar alguno, usa…​ 11 . 17

57. ASTBUILDER.BUILDFROMSTRING AstBuilder.buildFromString No tendras chequeo estatico de codigo pero…​ El codigo sera compatible a futuro 11 . 18

58. ASTBUILDER.BUILDFROMSTRING BlockStatement createBlock(FieldNode node) { return AstBuilder.buildFromString(""" return java.security.MessageDigest .getInstance('MD5') .digest(${node.name}.getBytes()) .encodeHex() .toString() """).first() as BlockStatement } 11 . 19

59. QUIERO ESTO MISMO…​PERO BIEN! 11 . 20

60. MACROS 12 . 1

61. 12 . 2

62. NOVETA!! NOVETA!! EN 2.5.0 Gracias a @bsideup y @melix http://docs.groovy-lang.org/docs/groovy-2.5.0- SNAPSHOT/ 12 . 3

63. QUE ES UNA MACRO ? — Wikipedia En programación, instrucción escrita en un lenguaje fuente que equivale a varias instrucciones de lenguaje máquina. 12 . 4

64. QUE ES UNA MACRO ? (CONT) En Groovy, una macro es una funcion que representa un set de instrucciones. En tiempo de compilacion se sustituye parte del codigo de tu aplicacion (marcadores) por el set de instrucciones que encapsulaban estas macros. 12 . 5

65. EJEMPLO ILUSTRATIVO Tenemos macroX = "hombre muy alto" Y sustituimos el marcador x en "John es un x" por el contenido de la macro Y tendriamos "John es un hombre muy alto" 12 . 6

66. QUE NOS DAN LAS MACROS Nos dan seguridad de tipos Nos permiten devolver expressiones o statements Nos permiten especificar el momento del compilador en el que se procesara el codigo Nos permiten substituir variables 12 . 7

67. COMO ENCAPULAMOS EL CODIGO ? 12 . 8

68. MACRO METHOD (I) En realidad es una meta-transformacion El codigo que encapsula lo transforma a llamadas del API AST Puede crear tanto Statements como Expresiones 12 . 9

69. MACRO METHOD (II) MethodCallExpression expression = macro { println "hey" } MethodCallExpression expression = callThisX('println', param(constX('hey'))) ConstantExpression expression = macro { 42 } ConstantExpression expression = new ConstantExpression(42) ReturnStatement statement = macro(true) { return 1 + 1 } ReturnStatement statement = new ReturnStatement( new BinaryExpression( new ConstantExpression(42... 12 . 10

70. MACRO METHOD (III) true si quieres que devuelva un Statement false si quieres que devuelva un Expression macro(boolean) { /* ...CODE... */} 12 . 11

71. EJEMPLO @Add aggrega el metodo getMessage() getMessage() devolvera siempre 42 @Add class A { } assert new A().getMessage() == 42 12 . 12

72. SIN MACROS ClassNode classNode = (ClassNode) nodes[1] ReturnStatement code = new ReturnStatement( new ConstantExpression(42)) MethodNode methodNode = new MethodNode( "getMessage", ACC_PUBLIC, ClassHelper.make(String), [] as Parameter[], [] as ClassNode[], code) classNode.addMethod(methodNode) 12 . 13

73. CON MACROS ClassNode classNode = (ClassNode) nodes[1] ReturnStatement code = macro { return "42" } MethodNode methodNode = new MethodNode( "getMessage", ACC_PUBLIC, ClassHelper.make(String), [] as Parameter[], [] as ClassNode[], code) classNode.addMethod(methodNode) 12 . 14

74. MACRO METHOD (CONT.) Fase de compilacion en el que quieras que se procese el codigo Puedes tambien indicar si devuelve un Statement o un Expression macro(CompilePhase, boolean) { /* ...CODE... */} 12 . 15

75. MD5 REVISITED BlockStatement createBlock(FieldNode node) { return block( stmt( callX( callX( callX( callX( make(java.security.MessageDigest), 'getInstance', args(constX('MD5')) ), constX('digest'), args( callX( varX(node.name), constX('getBytes'), args(constX('UTF-8')) ) ) ), constX('encodeHex'), args() ), constX('toString'), 12 . 16

76. CON MACROS BlockStatement createBlock(FieldNode node) { VariableExpression fieldVar = GeneralUtils.varX(fieldNode.name) return macro(CompilePhase.SEMANTIC_ANALYSIS, true) { return java.security.MessageDigest .getInstance('MD5') .digest($v { fieldVar} .getBytes()) .encodeHex() .toString() } } 12 . 17

77. AHORA…​ Es codigo normal, no un string o llamadas al API de AST Se puede compilar estaticamente Puedes sustituir variables 12 . 18

78. Y CREAR EL METODO ENTERO ? MacroClass Necesita @CompileDynamic http://docs.groovy-lang.org/docs/groovy-2.5.0- SNAPSHOT/html/documentation/#_macroclass 12 . 19

79. AUN ASI…​ Las ASTs siguen teniendo mucha ceremonia 12 . 20

80. ASTEROID 13 . 1

81. 13 . 2

82. QUE ES ASTEROID Es una biblioteca que Busca reducir el codigo de tus ASTs http://grooviter.github.io/asteroid/ 13 . 3

83. ORGANIZACION Abstracciones sobre transformaciones Locales y Globales Fluent API para crear expresiones, metodos y/o 13 . 4

84. EJEMPLO MD5 13 . 5

85. ANOTACION package compile.old.local.md5 import org.codehaus.groovy.transform.GroovyASTTransformationClass 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]) @GroovyASTTransformationClass( ["compile.old.local.md5.MD5Transform"]) @interface MD5 { } package compile.gro.local.md5 import asteroid.Local @Local(MD5Transform) @interface MD5 { } 13 . 6

86. DECLARACION AST antes ahora @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS) class MD5Transform extends AbstractASTTransformation { @Phase(Phase.LOCAL.SEMANTIC_ANALYSIS) class MD5Transform extends AbstractLocalTransformation<MD5, ClassNode> { 13 . 7

87. DECLARACION AST (CONT.) No te equivocas de fase de compilacion Declaras que tipo de anotacion va a procesar (MD5) Declaras sobre que tipo se va a aplicar (ClassNode) 13 . 8

88. METODO DOVISIT antes ahora @Override void visit(ASTNode[] nodes, SourceUnit sourceUnit) { ClassNode currentClass = (ClassNode) nodes[1] currentClass.fields.each { FieldNode field -> currentClass.addMethod(createMD5Method(field)) } } @Override void doVisit(AnnotationNode annotation, ClassNode node) { node.fields.each { FieldNode field -> node.addMethod(createMD5Method(field)) } } 13 . 9

89. METODO DOVISIT (CONT.) Ya no hacen falta el horrible casting de tipos 13 . 10

90. CREANDO METODO Los builders te guian si no conoces el API MethodNode createMD5Method(FieldNode node) { return A.NODES.method("${node.name}ToMD5") .modifiers(A.ACC.ACC_PUBLIC) .returnType(String) .code(createBlock(node)) .build() } 13 . 11

91. CREAR METODO MD5 BlockStatement createBlock(FieldNode node) { VariableExpression fieldVar = GeneralUtils.varX(node.name) return macro(CompilePhase.SEMANTIC_ANALYSIS, true) { return java.security.MessageDigest .getInstance('MD5') .digest($v { fieldVar }.getBytes()) .encodeHex() .toString() } } 13 . 12

92. CREAR METODO MD5 (CONT.) Todo es codigo compilado No pierdes dinamismo gracias a los placeholders Aun asi, necesitas saber si necesitas una Expr. o un Stmt. 13 . 13

93. QUE NO HE VISTO Y QUE MEREZCA LA PENA ? MacroClass ASTMatcher http://docs.groovy-lang.org/docs/groovy-2.5.0- SNAPSHOT/html/documentation/#_macroclass http://docs.groovy-lang.org/docs/groovy-2.5.0- SNAPSHOT/html/documentation/#_astmatcher 14 . 1

94. DE TODAS MANERAS Las ASTs con o sin macros no son el mejor sitio por donde empezar en serio Traits, extension modules, ASTs es el camino mas recomendado Revisar la documentacion de Groovy 14 . 2

95. :) 14 . 3

96. Q & A 14 . 4

97. RAFFLE 14 . 5

Add a comment