使用Gradle构建和应用AST转换

最近,我想在Gradle项目中构建并应用本地ast转换。 虽然我可以找到一些有关如何编写转换的示例,但找不到完整的示例来显示完整的构建过程。 转换必须单独编译,然后放在类路径中,因此其源代码不能简单地放在Groovy源代码树的其余部分中。 这是让我绊倒了一段时间的细节。

最初,我设置了一个单独的GroovyCompile任务来处理其余注释,然后再处理其余注释(摘自Peter Niederwieser在Gradle论坛上的有用建议)。 在此可行的同时,要应用转换的一个更简单的解决方案是设置多项目构建。 主项目依赖于具有ast转换源文件的子项目。 这是一个最小示例的目录结构:

ast/build.gradle
ast构建文件
ast/src/main/groovy/com/cholick/ast/Marker.groovy 标记界面 ast/src/main/groovy/com/cholick/ast/Transform.groovy AST转型 build.gradle 主构建文件 settings.gradle 项目层次结构配置 src/main/groovy/com/cholick/main/Main.groovy 转换源

对于完整的工作源(具有简单的测试,没有*导入),请克隆https://github.com/cholick/gradle_ast_example

根build.gradle文件包含对ast项目的依赖项:

dependencies {
    ...
    compile(project(':ast'))
}

根settings.gradle定义ast子项目:

include 'ast'

基础项目还具有src / main / groovy / com / cholick / main / Main.groovy,其中包含要转换的源文件。 在此示例中,我编写的ast转换将名为“ added”的方法添加到类中。

package com.cholick.main

import com.cholick.ast.Marker

@Marker
class Main {
    static void main(String[] args) {
        new Main().run()
    }
    def run() {
        println 'Running main'
        assert this.class.declaredMethods.find { it.name == 'added' }
        added()
    }
}

在ast子项目中,ast / src / main / groovy / com / cholick / ast / Marker.groovy定义一个接口来标记ast转换的类:

package com.cholick.ast

import org.codehaus.groovy.transform.GroovyASTTransformationClass

import java.lang.annotation.*

@Retention(RetentionPolicy.SOURCE)
@Target([ElementType.TYPE])
@GroovyASTTransformationClass(['com.cholick.ast.Transform'])
public @interface Marker {}

最后,ast转换类处理源类并添加一个方法:

package com.cholick.ast

import org.codehaus.groovy.ast.*
import org.codehaus.groovy.ast.builder.AstBuilder
import org.codehaus.groovy.control.*
import org.codehaus.groovy.transform.*

@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
class Transform implements ASTTransformation {
    void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
        if (!astNodes) return
        if (!astNodes[0]) return
        if (!astNodes[1]) return
        if (!(astNodes[0] instanceof AnnotationNode)) return
        if (astNodes[0].classNode?.name != Marker.class.name) return

        ClassNode annotatedClass = (ClassNode) astNodes[1]
        MethodNode newMethod = makeMethod(annotatedClass)
        annotatedClass.addMethod(newMethod)
    }
    MethodNode makeMethod(ClassNode source) {
        def ast = new AstBuilder().buildFromString(CompilePhase.INSTRUCTION_SELECTION, false,
                "def added() { println 'Added' }"
        )
        return (MethodNode) ast[1].methods.find { it.name == 'added' }
    }
}

感谢Hamlet D'Arcy提供的一个出色的AST转换示例,并感谢Peter Niederwieser在论坛上回答了我的问题

翻译自: https://www.javacodegeeks.com/2014/09/using-gradle-to-build-apply-ast-transformations.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值