
рд╣рд╛рд▓ рд╣реА рдореЗрдВ, рдЖрдкрдХреЛ рдЕрдХреНрд╕рд░
рдХрдВрдкрд╛рдЗрд▓-рдЯрд╛рдЗрдо рдПрдПрд╕рдЯреА рдЯреНрд░рд╛рдВрд╕рдлрд╝реЙрд░реНрдореЗрд╢рди рдЬреИрд╕реЗ рд╢рдХреНрддрд┐рд╢рд╛рд▓реА рдЧреНрд░реВрд╡реА рдлреАрдЪрд░ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рдкрдбрд╝рддрд╛ рд╣реИред
рдЪреВрдВрдХрд┐ рдореИрдВ рдЕрддреНрдпрдзрд┐рдХ рдбрд╛рдпрдирд╛рдорд┐рдХреНрд╕ рдХреА рддрд░рд╣ рдирд╣реАрдВ рд╣реВрдВ, рдЗрд╕рд▓рд┐рдП рдЕрдзрд┐рдХрд╛рдВрд╢ DSL рд╕рддреНрдпрд╛рдкрди рдЬрд╛рдВрдЪ рд╣рдо рд╕рдВрдХрд▓рди рдЪрд░рдг рдореЗрдВ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рд╣рдо рдмрд╣реБрдд рд╕реА рдХреЛрдб рдкреАрдврд╝реА рдХрд╛ рднреА рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рдЗрд╕рд▓рд┐рдП, рд╣рд░ рджрд┐рди рдЖрдкрдХреЛ рдПрдПрд╕рдЯреАрдПрдиреЛрдб-рдПрд╕ рдХреЛ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рд╕рдВрдХрд▓рд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред
def someVariable = new ConstantExpression("someValue"); def returnStatement = new ReturnStatement( new ConstructorCallExpression( ClassHelper.make(SomeCoolClass), new ArgumentListExpression(someVariable) ) );
рджрд░реНрджрдирд╛рдХ рдкрд░рд┐рдЪрд┐рдд рдбрд┐рдЬрд╛рдЗрди, рд╣реИ рдирд╛? рдХреНрдпрд╛ рдпрд╣ рдРрд╕рд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ?
def someVariable = macro { "someValue" } def returnStatement = macro { return new SomeCoolClass($v{ someVariable }) }
рдпрд╛ рдРрд╕рд╛ рднреА?
def constructorCall = macro { new SomeCoolClass($v{ macro { "someValue" } }) }
рдпрд╣ рд▓реЗрдЦ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЗ рдореЗрд░реЗ рд╕рдорд╛рдзрд╛рди рдкрд░ рдЪрд░реНрдЪрд╛ рдХрд░реЗрдЧрд╛, рдЬрд┐рддрдирд╛ рд╕рдВрднрд╡ рд╣реЛ рд╕рдХреЗ рдЧреНрд░реВрд╡реА рдХреЗ рдореВрд▓ рд╕рдорд╛рдзрд╛рди рдХреЗ рдХрд░реАрдм -
github.com/bsideup/MacroGroovyAstBuilder
Groovy 1.7
AstBuilder рдЬреИрд╕реА рдПрдХ рдЖрд╢реНрдЪрд░реНрдпрдЬрдирдХ рд░реВрдк рд╕реЗ рдЕрджреНрднреБрдд рдЪреАрдЬ рд▓рд╛рдпрд╛, рдЬреЛ рд╣рдореЗрдВ AST рдмрдирд╛рдиреЗ рдХреЗ 3 рддрд░реАрдХреЗ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ:
AstBuilder.buildFromString
рд╣рдо рдХреЛрдб рдХреЗ рд╕рд╛рде рд▓рд╛рдЗрди рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ, рдЖрдЙрдЯрдкреБрдЯ рдореЗрдВ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдПрд╕рдПрдиреЛрдбреЗ рдХреА рд╕реВрдЪреА рд╣реИ:
List<ASTNode> nodes = new AstBuilder().buildFromString("\"Hello\"")
рд▓рд╛рдн
- рдЗрдирдкреБрдЯ - рд╕реНрдЯреНрд░рд┐рдВрдЧ, рдХрд╣реАрдВ рд╕реЗ рднреА рд▓рд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ;
- рдпрд╣ рд╕рдордЭрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ рдХрд┐ ASTNode-s рдХреА рд╡реНрдпрд╡рд╕реНрдерд╛ рдХреИрд╕реЗ рдХреА рдЬрд╛рддреА рд╣реИ;
- рдЖрдкрдХреЛ CompilePhase рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ;
- рд▓рдЧрднрдЧ 100% рд╡реИрдз рдХреЛрдб рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИ;
- рд╡рд┐рд╢реНрд╡рд╕рдиреАрдп - рдпрджрд┐ Groovy рдореЗрдВ ASTNode-s рдХреА рд╕рдВрд░рдЪрдирд╛ рдмрджрд▓ рдЧрдИ рд╣реИ рддреЛ рдЖрдкрдХреЛ рдЕрдкрдиреЗ рдХреЛрдб рдореЗрдВ рдмрджрд▓рд╛рд╡ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред
рдХрдорд┐рдпреЛрдВ
- рдЖрдИрдбреАрдИ рдЖрдкрдХреЛ рд╕рд┐рдВрдЯреИрдХреНрд╕ рдЪреЗрдХрд┐рдВрдЧ рдореЗрдВ рдорджрдж рдирд╣реАрдВ рдХрд░реЗрдЧрд╛;
- рдЖрдИрдбреАрдИ рдореЗрдВ рд░рд┐рдлреИрдХреНрдЯрд░рд┐рдВрдЧ рднреА рдХрд╛рдо рдирд╣реАрдВ рдХрд░реЗрдЧрд╛;
- рдХреБрдЫ рд╕рдВрд╕реНрдерд╛рдПрдБ рдирд╣реАрдВ рдмрдирд╛рдИ рдЬрд╛ рд╕рдХрддреАрдВ - рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рд╡рд░реНрдЧ рдХреНрд╖реЗрддреНрд░ рдШреЛрд╖рд┐рдд рдХрд░рдирд╛ред
рдЗрди рдХрдорд┐рдпреЛрдВ рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╡рд┐рдзрд┐ рдХреЛ рд╕рд╣реА рдХрд░рдиреЗ рдХрд╛ рдЗрд░рд╛рджрд╛ рд╣реИред
AstBuilder.buildFromCode
рд╣рдо рдХреЛрдб рдХреЗ рд╕рд╛рде рдПрдХ рдХреНрд▓реЛрдЬрд░ (рдЙрд░реНрдл рдХреНрд▓реЛрдЬрд░) рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ, рдЖрдЙрдЯрдкреБрдЯ рдкрд░ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдиреЛрдбреНрд╕ рдХреА рдПрдХ рд╕реВрдЪреА рд╣реИ:
List<ASTNode> nodes = new AstBuilder().buildFromCode { "Hello" }
рд▓рд╛рдн (рдкрд┐рдЫрд▓реА рдкрджреНрдзрддрд┐ рдХреЗ рд▓рд╛рднреЛрдВ рдХреЗ рдЕрд▓рд╛рд╡рд╛)
- рдЖрдИрдбреАрдИ рдЖрдкрдХреЛ рдПрдХ рдмрдВрдж рдореЗрдВ рд╕реНрд╡рдд: рдкреВрд░реНрдг, рд╡рд╛рдХреНрдпрд╡рд┐рдиреНрдпрд╛рд╕ рдЬрд╛рдБрдЪ, рдФрд░ рд░реАрдлрд╝реИрдХреНрдЯрд░рд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред
рдиреБрдХрд╕рд╛рди:
рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЬрд┐рдирдХреЗ рдкрд╛рд╕ рджреЛрдиреЛрдВ рддрд░реАрдХреЛрдВ рдХреА рдХрдореА рд╣реИ, рдПрдХ рддреАрд╕рд░рд╛ рддрд░реАрдХрд╛ рд╣реИ:
AstBuilder.buildFromSpec
рдпрд╣ рд╡рд┐рдзрд┐ рдмрдВрдж рд╣реЛ рдЬрд╛рддреА рд╣реИ (рд╡реИрд╕реЗ, рдЖрдк рдореЗрд░реЗ рдЕрдиреБрд░реЛрдз рдХреЗ рд▓рд┐рдП рд╡реЛрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрд╛ рдкреБрд▓ рдЕрдиреБрд░реЛрдз рдкрд░ рдЯрд┐рдкреНрдкрдгреА рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рдЗрд╕ рдкрджреНрдзрддрд┐ рдкрд░ рдПрдХ рдЕрдЪреНрдЫрд╛ DelegatesTo рдПрдиреЛрдЯреЗрд╢рди рджрд┐рдЦрд╛рдИ рджреЗ), рдЬреЛ рдПрдПрд╕рдЯреА рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЗ рд▓рд┐рдП рдПрдХ рдбреАрдПрд╕рдПрд▓ рд╣реИ:
List<ASTNode> nodes = new AstBuilder().buildFromSpec { block { returnStatement { constant "Hello" } } }
рд▓рд╛рдн
- рдЖрдкрдХреЛ рдиреЛрдбреНрд╕ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЧреНрд░реВрд╡реА рддрд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ;
- рд▓рдЧрднрдЧ рдХрд┐рд╕реА рднреА рдореМрдЬреВрджрд╛ ASTNode рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреА рдХреНрд╖рдорддрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ;
- рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдкреНрд▓рд╕, рдХреЗ рд░реВрдк рдореЗрдВ рдЧреНрд░реВрд╡реА рдХреА рдПрдПрд╕рдЯреА рдкреАрдврд╝реА рд╡рд┐рд╖рдп рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдкреНрд░рд▓реЗрдЦрд┐рдд рдирд╣реАрдВ рд╣реИ: рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдкреНрд░рд▓реЗрдЦрд┐рдд рд╣реИ рдФрд░ рдЯреЗрд╕реНрдЯрдХреЗрд╕ рдореЗрдВ рд╡реНрдпрд╛рдкрдХ рдЙрдкрдпреЛрдЧ рдХреЗ рдорд╛рдорд▓реЗ рд╣реИрдВ ред
рдХрдорд┐рдпреЛрдВ
- рдХрднреА-рдХрднреА рдпрд╣ рд╕рдордЭрдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реЛрддрд╛ рд╣реИ рдХрд┐ рд╡рд╛рдВрдЫрд┐рдд рдкрд░рд┐рдгрд╛рдо рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХреНрдпрд╛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ;
- рдиреЛрдб рдмрд┐рд▓реНрдбрд░реЛрдВ рдХреЛ рдХреЙрд▓ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдХрдо рдХреНрд░рд┐рдпрд╛, рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА рдРрд╕рд╛ рд░рд╣рддрд╛ рд╣реИ;
- рдПрдХ рдЕрдЬреАрдм рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди - рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдХреБрдЫ рд╡рд┐рдзрд┐рдпрд╛рдВ рдХреНрд▓рд╛рд╕рдиреЙрдб рдХреЗ рдмрдЬрд╛рдп рдПрдХ рдХрдХреНрд╖рд╛ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддреА рд╣реИрдВ, рдЬреЛ рдЗрд╕рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЛ рдирдХрд╛рд░рддреА рд╣реИ;
- рдЕрд╡рд┐рд╢реНрд╡рд╕рдиреАрдп - рдПрдПрд╕рдЯреА рдкреНрд░рдореБрдЦ рднрд╛рд╖рд╛ рд░рд┐рд▓реАрдЬ рдХреЗ рд╕рд╛рде рдмрджрд▓ рд╕рдХрддрд╛ рд╣реИ;
- рдЖрдкрдХреЛ рдпрд╣ рдЬрд╛рдирдиреЗ рдХреА рдЬрд╝рд░реВрд░рдд рд╣реИ рдХрд┐ рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рд╕рдВрдХрд▓рди рдЪрд░рдг рдореЗрдВ рдЖрдкрдХреЗ рдПрдПрд╕рдЯреА рдХреЛ рдХреИрд╕рд╛ рджрд┐рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП;
- рдЕрдм рддрдХ рдЖрдИрдбреАрдИ (рдкреБрд▓ рдЕрдиреБрд░реЛрдз рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдореЗрд░реА рдЯрд┐рдкреНрдкрдгреА рджреЗрдЦреЗрдВ) рдЗрд╕ рдбреАрдПрд╕рдПрд▓ рдХреЗ рд▓рд┐рдП рд╕реНрд╡рдд: рдкреВрд░реНрдг рдХрд╛ рд╕рдорд░реНрдерди рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВред
рд╡рд┐рдзрд┐рдпреЛрдВ рдХрд╛ рд╕рдВрдпреЛрдЬрди
рдпрд╣ рднреА рдЙрд▓реНрд▓реЗрдЦрдиреАрдп рд╣реИ рдХрд┐ рдЖрдк рдЗрди рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ:
List<ASTNode> result = new AstBuilder().buildFromSpec { method('myMethod', Opcodes.ACC_PUBLIC, String) { parameters { parameter 'parameter': String.class } exceptions {} block { owner.expression.addAll new AstBuilder().buildFromCode { println 'Hello from a synthesized method!' println "Parameter value: $parameter" } } annotations {} } }
MacroGroovy
рддреЛ, рд╕рдВрднрд╛рд╡рдирд╛рдУрдВ рдХреА рдЗрддрдиреА рд╡реНрдпрд╛рдкрдХ рд╕рдореАрдХреНрд╖рд╛ рдХреЗ рдмрд╛рдж, рдЖрдк рдкреВрдЫ рд╕рдХрддреЗ рд╣реИрдВ: рддреЛ ... * рдЕрд╣рдо * ... рдЕрдВрдЬреАрд░ MacroGroovy рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ?
рдкреЛрд╕реНрдЯ рд╣реЗрдбрд░ рд╕реЗ рдЙрджрд╛рд╣рд░рдг рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ:
def someVariable = new ConstantExpression("someValue"); def returnStatement = new ReturnStatement( new ConstructorCallExpression( ClassHelper.make(SomeCoolClass), new ArgumentListExpression(someVariable) ) );
рджреЗрдЦреЗрдВ рддрд░реНрдХ рд╕реВрдЪреА рдирд┐рд░реНрдорд╛рддрд╛ рдХреЛ рджрд┐рдП рдЧрдП рдХреБрдЫ рд╡реИрд░рд┐рдПрдмрд▓ рджреЗрдЦреЗрдВ? рдореЗрд░рд╛ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдХрд░реЛ, рдпрд╣ рд╕реНрдерд┐рддрд┐ рдмрд╣реБрдд, рдмрд╣реБрдд рдЖрдо рд╣реИред рдФрд░ рд╡рд╣ рддреБрд░рдВрдд buildFromCode рдФрд░ buildFromString рд╕реНрд╡реАрдк рдХрд░рддреА рд╣реИред рддреЛ рдХреЗрд╡рд▓ buildFromSpec рдмрдиреА рд╣реБрдИ рд╣реИ, рд▓реЗрдХрд┐рди рдХреНрдпрд╛ рдЖрдкрдХреЛ рдЗрд╕рдХреА рдХрдорд┐рдпреЛрдВ рдХреА рд╕реВрдЪреА рдпрд╛рдж рд╣реИ? рдпрд╣ рд╡рд╣ рдЬрдЧрд╣ рд╣реИ рдЬрд╣рд╛рдБ рдореИрдХреНрд░реЛрдЧреНрд░реЛрд╡реА рдмрдЪрд╛рд╡ рдХреЗ рд▓рд┐рдП рдЖрддрд╛ рд╣реИ:
def someVariable = macro { "someValue" }; def returnStatement = macro { return new SomeCoolClass($v{ someVariable }) }
рд▓рд╛рднрдХрдорд┐рдпреЛрдВ- рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдЖрдкрдиреЗ рдореИрдХреНрд░реЛ {} рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рд╡рд░реНрдЧ рдлрд╝реАрд▓реНрдб рдирд╣реАрдВ рдмрдирд╛рдпрд╛;
- CompilePhase рдХреА рдХреЛрдИ рд╕рдВрднрд╛рд╡рдирд╛ рдирд╣реАрдВ рд╣реИ;
рд╡реИрд╕реЗ, рдЖрдк рдЕрднреА рднреА buildFromSpec рдФрд░ рдореИрдХреНрд░реЛ рдХреЛ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ:
List<ASTNode> result = new AstBuilder().buildFromSpec { method('myMethod', Opcodes.ACC_PUBLIC, String) { parameters { parameter 'parameter': String.class } exceptions {} block { owner.expression.addAll macro { println 'Hello from a synthesized method!' println "Parameter value: $parameter" } } annotations {} } }
рдореИрдВ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдПрдХ рд▓рд┐рдВрдХ рдЫреЛрдбрд╝ рджреВрдВрдЧрд╛, рдЬрд┐рд╕рдореЗрдВ рджрд┐рдЦрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдореИрдХреНрд░реЛрдЧреНрд░реЛрд╡реА рдХреИрд╕реЗ рдХрдИ рдмрд╛рд░ рдХреЛрдб рдХреА рдорд╛рддреНрд░рд╛ рдХрдо рдХрд░рддрд╛ рд╣реИ:
github.com/bsideup/MacroGroovy/blob/master/example/basicExample/src/test/groovy/ru/trylogic/groovy/macro/examples/basic/BasicTest.groovyрдирд┐рд╖реНрдХрд░реНрд╖
рд╡рд┐рдзрд┐рдпреЛрдВ рдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдХреЗ рдкрд╛рд╕ рдЗрд╕рдХреЗ рдкреЗрд╢реЗрд╡рд░реЛрдВ рдФрд░ рд╡рд┐рдкрдХреНрд╖ рд╣реИрдВ, рдФрд░ рдореИрдВрдиреЗ рдЕрднреА рдЕрдиреНрдп рддрд░реАрдХреЛрдВ рдХреЗ рдиреБрдХрд╕рд╛рдиреЛрдВ рдХреЛ рджреВрд░ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рд╣реИред рдЖрдкрдХреЗ рдкреБрд▓ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рдкрд░реАрдХреНрд╖рдг рдореЗрдВ рдорджрдж рдХреЗ рд▓рд┐рдП рдореИрдВ рдЖрднрд╛рд░реА рд░рд╣реВрдВрдЧрд╛ред
рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдорд╛рд╡реЗрди рд╕реЗрдВрдЯреНрд░рд▓ рдореЗрдВ рдЙрдкрд▓рдмреНрдз рд╣реИ, рдореИрдВ рдПрдХ рд▓рд┐рдВрдХ рдЫреЛрдбрд╝ рджреВрдВрдЧрд╛ рдЬрд╣рд╛рдВ рдЖрдк рд╣рдореЗрд╢рд╛ рдирд╡реАрдирддрдо рд╕рдВрд╕реНрдХрд░рдг рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВ:
search.maven.org/#search%7Cga%7C1%7Cmacro-groovyрдЖрдкрдХрд╛ рдзрдиреНрдпрд╡рд╛рдж