In this concluding episode of "My Tryst with Groovy DSL" we are going to stress on building various components with Groovy DSL.
Lets say,
We have an annotation Imitate as:
@Retention (RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
@GroovyASTTransformationClass("com.groovy.ast.transformers.ImitateTransformation")
@interface Imitate {
}
Ohhh Yes the Groovy Transformation class is ImitateTransformation, soon we will get to know its role soon.
and the Usage of the annotation is like:
@Main
class MainExample {
static def name = "MICKY"
@Imitate
def testMeth(def args,def m){
def x = 0
m(args)
}
def m2={String ok ->
println "Okkkk haishaaaa $ok"
}
}
class MyClass {
static def args33 = "Mic in MyClass"
}
Now our Objective is something like this:
public Object mi3 = {String args21 ->
this.println '##### Closure Declaration ######'
}
public static Object mi4 = {String args31 ->
this.println args33
this.println args31
}
public void NEWOKNew1(String args)
{
this.testMeth(args) {String args2 ->
this.println 'Closure Call Done'
this.println args2
}
this.mi3()
mi4.setResolveStrategy(Closure.DELEGATE_FIRST)
mi4.setDelegate(new MyClass())
MainExample.mi4(args)
}
So, to put it in words, our objective is:
To declare two closures (mi3,mi4) one having static scope.
Then we will declare a new method NEWOKNew1() and invoke the closures in order and all these operation we going to implement with Groovy AST using transformation class.
The GroovyASTTransformationClass class is:
@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
class ImitateTransformation implements ASTTransformation {
@Override
public void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
// TODO Auto-generated method stub
def statement = astNodes[1].code
def varscope = statement.variableScope
Map referencedLocalVariablesMap = varscope.referencedLocalVariables
referencedLocalVariablesMap.each { key , value ->
println "-->${key.class}"
println "-->${value.class}"
}
/**
*
* Source Unit is the Groovy Source Code File
* containing the annotation.
*
*/
println "===========The SourceUnit is ${sourceUnit.name}"
def shareVariables = { variableScope ->
println "The variable scope is: ${variableScope.referencedClassVariables}"
//def scope = variableScope.copy()
def map = variableScope.referencedLocalVariables
println "&&&& The map is:$map"
map.each{ key, value ->
println "***** The Variable is $value.name"
value.setClosureSharedVariable(true)
}
variableScope
}
shareVariables(statement.variableScope)
// create new block statement
/* BlockStatement block = new BlockStatement()
block.variableScope = shareVariables(statement.variableScope)
// create closure expression, use code as an argument
ClosureExpression closure = new ClosureExpression(Parameter.EMPTY_ARRAY, statement)
closure.variableScope = statement.variableScope.copy()
// create method call expression, use the closure as an argument
MethodCallExpression methodCall = new MethodCallExpression(new VariableExpression('this'),
'NewOk', new ArgumentListExpression(closure))
// add method call to the block statement
block.addStatement(new ExpressionStatement(methodCall))
nodes[1].code = block
*/
MethodNode annotatedMethod = astNodes[1]
ClassNode declaringClass = astNodes[1].declaringClass
def closre = new AstBuilder().buildFromSpec {
closure {
parameters {
parameter 'args2': String.class
}
block {
expression {
methodCall {
variable "this"
constant "println"
argumentList {
constant "Closure Call Done"
//parameter "args2"
}
//constant "OKKK"
}
}
expression {
methodCall {
variable "this"
constant "println"
argumentList {
//constant "Closure Call Done"
variable "args2"
}
}
}
}
}
}
closre[0].variableScope = new VariableScope()
/**
*
* @author MIC
*
* Defining another Closure
*
*/
def closre2 = new AstBuilder().buildFromSpec {
closure {
parameters {
parameter 'args21': String.class
}
block {
expression {
methodCall {
variable "this"
constant "println"
argumentList {
constant "##### Closure Declaration ######"
}
}
}
/*expression {
methodCall {
variable "this"
constant "println"
argumentList {
//constant "Closure Call Done"
variable "args"
}
}
}*/
}
}
}
closre2[0].variableScope = new VariableScope();//shareVariables(astNodes[1].getVariableScope())
/**
* Defining a static Closure
*/
def closre3 = new AstBuilder().buildFromSpec {
closure {
parameters {
parameter 'args31': String.class
}
block {
expression {
methodCall {
variable "this"
constant "println"
argumentList {
variable "args33"
}
}
}
expression {
methodCall {
variable "this"
constant "println"
argumentList {
variable "args31"
}
}
}
}
}
}
closre3[0].variableScope = new VariableScope()
//End of Closure Declaration
/**
* @author MIC
*
* Adding a field node to a class
*
*/
FieldNode fieldNode= new FieldNode('mi3', 1, new ClassNode(Object.class), new ClassNode(declaringClass.getClass()), closre2[0])
FieldNode staticFieldNode= new FieldNode('mi4', ACC_PUBLIC | ACC_STATIC, new ClassNode(Object.class), new ClassNode(declaringClass.getClass()), closre3[0])
//End of Adding a FieldNode
def ast = new AstBuilder().buildFromSpec {
method('NEWOKNew1', ACC_PUBLIC , Void.TYPE) {
parameters {
parameter 'args': String.class
}
exceptions{
}
}
}
def consCallExpr = new ConstructorCallExpression(new ClassNode(MyClass.class), MethodCallExpression.NO_ARGUMENTS);
def methCallExpr = new MethodCallExpression(new VariableExpression("mi4"), "setDelegate", consCallExpr);
PropertyExpression propertyExpression = new PropertyExpression(new ClassExpression(new ClassNode(Closure.class)), "DELEGATE_FIRST")
def methCallExpr2 = new MethodCallExpression(new VariableExpression("mi4"), "setResolveStrategy", propertyExpression);
ArgumentListExpression argListExpr = new ArgumentListExpression()
argListExpr.addExpression(new VariableExpression("args"))
argListExpr.addExpression(closre[0])
ArgumentListExpression argListExpr2 = new ArgumentListExpression()
argListExpr2.addExpression(new VariableExpression("args"))
MethodCallExpression methodCall = new MethodCallExpression(new VariableExpression('this'),
'testMeth',argListExpr)
MethodCallExpression methodCall2 = new MethodCallExpression(new VariableExpression('this'),
'mi3', new ArgumentListExpression())
StaticMethodCallExpression methodCall3 = new StaticMethodCallExpression(new ClassNode(MainExample.class), 'mi4', argListExpr2)
def methNode = ast[0]
def blockStatementList = [new ExpressionStatement(methodCall), new ExpressionStatement(methodCall2), new ExpressionStatement(methCallExpr2) ,new ExpressionStatement(methCallExpr), new ExpressionStatement(methodCall3)]
BlockStatement blockStatement = new BlockStatement(blockStatementList, new VariableScope())
methNode.setCode(blockStatement)
declaringClass.addProperty(new PropertyNode(fieldNode, ACC_PUBLIC, null, null));
declaringClass.addProperty(new PropertyNode(staticFieldNode, ACC_PUBLIC, null, null));
declaringClass.addMethod(methNode)
}
}
Now lets explain the the groovy transformation code :
At the beginning lies my some of findings with VariableScope, but really I was not able to figure it out how it is applicable and its true scope, It would be a great help, if someone could point me so, or help me in getting hold some resources, which will clarify my doubts :-) :-)
The there comes the closure declarations, closre, closre2 & closre3 and we also set variablescope for each of them, otherwise the AST changes won't be applied.
Like:
def closre = new AstBuilder().buildFromSpec {
closure {
parameters {
parameter 'args2': String.class
}
block {
expression {
methodCall {
variable "this"
constant "println"
argumentList {
constant "Closure Call Done"
//parameter "args2"
}
//constant "OKKK"
}
}
expression {
methodCall {
variable "this"
constant "println"
argumentList {
//constant "Closure Call Done"
variable "args2"
}
}
}
}
}
}
closre[0].variableScope = new VariableScope()
.........
Then we decalre two properties of type FieldNode, and they point to closre2 & closre3 respectively.
FieldNode fieldNode= new FieldNode('mi3', 1, new ClassNode(Object.class), new ClassNode(declaringClass.getClass()), closre2[0])
FieldNode staticFieldNode= new FieldNode('mi4', ACC_PUBLIC | ACC_STATIC, new ClassNode(Object.class), new ClassNode(declaringClass.getClass()), closre3[0])
Then we declare the new method NEWOKNew1(),
def ast = new AstBuilder().buildFromSpec {
method('NEWOKNew1', ACC_PUBLIC , Void.TYPE) {
parameters {
parameter 'args': String.class
}
exceptions{
}
}
}
followed by setting Delegate & ResolveStrategy for closure pointed by mi4.
def consCallExpr = new ConstructorCallExpression(new ClassNode(MyClass.class), MethodCallExpression.NO_ARGUMENTS);
def methCallExpr = new MethodCallExpression(new VariableExpression("mi4"), "setDelegate", consCallExpr);
PropertyExpression propertyExpression = new PropertyExpression(new ClassExpression(new ClassNode(Closure.class)), "DELEGATE_FIRST")
def methCallExpr2 = new MethodCallExpression(new VariableExpression("mi4"), "setResolveStrategy", propertyExpression);
Then we declare the Argument List to be passed to testMeth(), mi3(), & mi4() respectively and we also defined the MethodCall expressions for testMeth(), mi3(), & mi4() with the help of Argument List prepared earlier.
ArgumentListExpression argListExpr = new ArgumentListExpression()
argListExpr.addExpression(new VariableExpression("args"))
argListExpr.addExpression(closre[0])
ArgumentListExpression argListExpr2 = new ArgumentListExpression()
argListExpr2.addExpression(new VariableExpression("args"))
MethodCallExpression methodCall = new MethodCallExpression(new VariableExpression('this'),
'testMeth',argListExpr)
MethodCallExpression methodCall2 = new MethodCallExpression(new VariableExpression('this'),
'mi3', new ArgumentListExpression())
StaticMethodCallExpression methodCall3 = new StaticMethodCallExpression(new ClassNode(MainExample.class), 'mi4', argListExpr2)
Lastly, we put all those MethodCall Expressions and PropertyExpressions in BlockStatement with a new VariableScope and it to the newly created method NEWOKNew1()
def methNode = ast[0] def blockStatementList = [new ExpressionStatement(methodCall), new ExpressionStatement(methodCall2), new ExpressionStatement(methCallExpr2) ,new ExpressionStatement(methCallExpr), new ExpressionStatement(methodCall3)] BlockStatement blockStatement = new BlockStatement(blockStatementList, new VariableScope()) declaringClass.addProperty(new PropertyNode(fieldNode, ACC_PUBLIC, null, null)); declaringClass.addProperty(new PropertyNode(staticFieldNode, ACC_PUBLIC, null, null)); declaringClass.addMethod(methNode) methNode.setCode(blockStatement)So, for this time thats all that I had been doing with Groovy AST.
No comments:
Post a Comment