编译时AST转换:赋值给字段



我目前正在尝试实现一些Groovy编译时AST转换,但是我遇到了麻烦:

我如何为一个字段的赋值语句指定AST转换?即AST转换应该转换以下代码:

class MyClass {
    @MyTransformation
    String myField
    public void init() {
    }
}

变成了

class MyClass {
    String myField
    public void init() {
        this.myField = "initialized!"
    }
}

我尝试用这个AST构建器调用:

def ast = new AstBuilder().buildFromSpec {
        expression{
            declaration {
                variable "myField"
                token "="
                constant "initialized!"
            }
        }
}

但是在将结果语句插入声明类的"init"方法后,它插入了一个变量赋值,如

所示
java.lang.Object myField = "initialized!"

我查看了Ast Builder TestCase中包含的示例,但是它们只涵盖了类主体中的字段声明,而不是对字段的赋值。我自己使用fieldNode的尝试都导致了编译器错误。我将编译阶段设置为INSTRUCTION_SELECTION;我想这应该没问题。

我如何做到这一点?基于AstBuilder#buildFromSpec方法的解决方案是首选的,但任何帮助将是非常感谢的。

我通常不建议使用AST构建器。这对原型制作很有用,但你无法真正控制它生成的内容。特别是,在这里,它不能处理您创建的变量表达式应该引用字段节点这一事实。AST Builder非常适合学习AST,但不应该在生产代码中使用。

这是一个独立的例子,演示了如何实现你想要的。@ASTTest中的代码将对应于您的转换代码:

import groovy.transform.ASTTest                                                         
import org.codehaus.groovy.ast.expr.BinaryExpression                            
import org.codehaus.groovy.ast.expr.VariableExpression                          
import org.codehaus.groovy.ast.expr.ConstantExpression                          
import org.codehaus.groovy.ast.stmt.ExpressionStatement                         
import org.codehaus.groovy.syntax.Token                                         
import org.codehaus.groovy.syntax.Types      
class MyClass {                                                                         
    String myField                                                                      
    @ASTTest(phase=SEMANTIC_ANALYSIS,value={                                            
            def classNode = node.declaringClass                                         
            def field = classNode.getDeclaredField('myField')                           
            def assignment = new BinaryExpression(                                      
              new VariableExpression(field),                                              
              Token.newSymbol(Types.EQUAL, 0, 0),                                         
              new ConstantExpression('initialized!')                                      
            )                                                                                   
            node.code.addStatement(new ExpressionStatement(assignment))                 
    })                                                                          
    public void init() {                                                                
    }                                                                                   
}                                                                                       
def c = new MyClass()                                                                   
c.init()                                                                                
println c.myField

希望这对你有帮助!

最新更新