Java Groovy:如何从AST获取静态推断的返回类型

Java Groovy:如何从AST获取静态推断的返回类型,java,groovy,type-systems,static-compilation,Java,Groovy,Type Systems,Static Compilation,我使用Groovy允许用户编写和自定义Java应用程序的某些部分。我正在使用所有用户提供的脚本的静态编译 我的问题是:如果我的代码期望收到一个布尔类型的值作为用户脚本的结果,那么我是否可以检查提供的用户脚本是否总是返回布尔值而不实际执行脚本?换句话说,如何访问静态groovy编译器执行的类型推断的结果?我希望能够在用户编辑脚本内容时告诉用户“嘿,您的脚本并不总是返回布尔值”。与“典型”groovy不同——这是groovy的运行时类型和java的编译时静态类型之间的区别 例如,下面的方法是否将返回

我使用Groovy允许用户编写和自定义Java应用程序的某些部分。我正在使用所有用户提供的脚本的静态编译

我的问题是:如果我的代码期望收到一个布尔类型的值作为用户脚本的结果,那么我是否可以检查提供的用户脚本是否总是返回布尔值而不实际执行脚本?换句话说,如何访问静态groovy编译器执行的类型推断的结果?我希望能够在用户编辑脚本内容时告诉用户“嘿,您的脚本并不总是返回布尔值”。

与“典型”groovy不同——这是groovy的运行时类型和java的编译时静态类型之间的区别

例如,下面的方法是否将返回布尔值

def value(v) {
    return v;
}

然而,在2.0版中,有一个@CompileStatic注释,我认为它将强制所有类型在编译时都知道。但是,不确定您将如何为客户端的脚本代码强制启用此选项。

没有直接的方法,但这是可能的。布尔运算尤其困难,因为编译器会乐于应用各种类型的协同运算(例如,毫无怨言地将int转换为布尔运算)。我遇到了完全相同的问题,并执行了以下步骤:

  • ASTTransformation将返回类型设置为boolean(不是必需的,是早期半工作迭代的产物)
  • 将所有返回语句进行meterialize转换
  • TypeCheckingExtension访问ReturnStatements并验证它们是否为布尔类型
  • ASTTransformation使用TypeCheckingExtension执行静态类型转换
  • 对于1:

    扩展
    ClassCodeVisitorSupport
    ,在
    visitMethod
    中识别所有要返回布尔值的方法(例如检查匹配的命名约定)

    MethodNode
    returnType
    设置为
    ClassHelper.boolean\u TYPE

    对于2:

    对于与上面相同的方法,请调用
    org.codehaus.groovy.classgen.ReturnAdder.visitMethod

    对于3:

    扩展
    AbstractTypeCheckingExtension
    ,覆盖
    afterVisitMethod
    。此时,
    AbstractTypeCheckingExtension
    将推断出方法中所有表达式的下限。使用
    ClassCodeVisitorSupport
    子类并重写
    visitReturnStatement
    。使用
    getType(statement.expression)
    获取推断的类型。请注意,这可能不同于
    语句.expression.type
    (类型根据AST)。对非布尔类型调用
    addStaticTypeError

    对于4:

    扩展
    静态类型转换格式
    覆盖
    newVisitor
    并创建一个新的
    StaticTypeCheckingVisitor
    并在其上调用
    addTypeCheckingExtension
    以添加您的
    TypeCheckingExtension

    GitHub项目


    它甚至可以作为依赖项重用;)

    是的,这正是我们所做的。您可以将静态编译添加为AST定制器,这非常有效。我们面临的问题是如何访问分析结果,即带类型注释的AST。您是否可以要求用户使用其代码实现特定的接口?如果他没有返回一个布尔值,那么它应该无法编译。。。如果用户代码更像是一个“脚本”,那么在为他编译界面之前,您可以强制他的脚本实现一个界面。让用户自己实现一个界面(从语法上)显然是太难了。一种选择是在编译用户代码之前在其周围包装一个方法签名。但是,用户无法在脚本中定义帮助函数,因为方法不能嵌套在Groovy AFAIK中。AST转换比字符串串联更简单,但也可以完成这项工作。最干净的选择仍然是保持脚本不变并分析AST。问题是,我不知道如何在Groovy编译器API中做到这一点。感谢您的详细回复!我将尝试实施你的方法。在github上有这个例子肯定会有帮助。唉,关于Groovy的这些方面的信息在网上几乎找不到,包括一些尝试和错误。我会尽力的!好了: