Groovy - 类型检查AST生成的代码

时间:2015-11-27 06:05:26

标签: groovy typechecking

我有一个Groovy应用程序可以被我写的一个小Groovy DSL custimized。启动时,应用程序加载多个Groovy脚本,应用一些AST转换,最后执行脚本中指定的任何内容。

其中一个AST转换将几行代码插入到某些方法中。这工作正常,我可以在运行时看到不同的行为。但是,有时生成的代码不正确。虽然我使用TypeChecked自定义程序加载了脚本,但我生成的代码从不检查以确保完整性。

为了表明我的问题,我构建了一个极端的例子。我有以下脚本:

int test = 10
println test // prints 10 when executed without AST

我加载此脚本并在testprintln声明之间插入一行新代码:

public void visitBlockStatement(BlockStatement block) {
    def assignment = (new AstBuilder().buildFromSpec {
        binary {
            variable "test"
            token "="
            constant 15
        }
    }).first()
    def newStmt = new ExpressionStatement(assignment)
    newStmt.setSourcePosition(block.statements[1])  
    block.statements.add(2, newStmt)
    super.visitBlockStatement(block)
}

应用此AST后,脚本打印15 。当我使用AstNodeToScriptVisitor打印生成的脚本的Groovy代码时,我可以看到新的分配已添加到代码中。

然而,如果我将作业的值更改为String值:

// ...
def assignment = (new AstBuilder().buildFromSpec {
    binary {
        variable "test"
        token "="
        constant "some value"
    }
}).first()
// ...

我在运行时得到GroovyCastExcpetion。虽然生成的脚本如下所示:

int test = 10
test = "some value" // no compile error but a GroovyCastException at runtime here. WHY?
println test

TypeChecked未引发任何错误。我在this mailing list中读到,您需要设置要生成的代码的源位置,但是我这样做仍然无法正常工作。谁能提供一些我做错的反馈?非常感谢你!

更新

我通过将AST附加到GroovyShell来调用AST:

def config = new CompilerConfiguration()
config.addCompilationCustomizers(
    new ASTTransformationCustomizer(TypeChecked)
)
config.addCompilationCustomizers(
    new ASTTransformationCustomizer(new AddAssignmentAST())
)
def shell = new GroovyShell(config)
shell.evaluate(new File("./path/to/file.groovy"))

AST本身的类看起来像这样:

@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
class AddAssignmentAST implements ASTTransformation {

    @Override
    public void visit(ASTNode[] nodes, SourceUnit source) {
        def transformer = new AddAssignmentTransformer()
        source.getAST().getStatementBlock().visit(transformer)
    }

    private class AddAssignmentTransformer extends CodeVisitorSupport {

        @Override
        public void visitBlockStatement(BlockStatement block) {
            // already posted above
        }

    }
}

由于我的Groovy脚本只包含一个块(对于这个小例子),visitBlockStatement方法只调用一次,添加了赋值(我可以在输出更改时验证)但不是永远抛出编译时错误。

0 个答案:

没有答案