4

在运行时,在我的 Java 程序中,给定一个字符串,我想知道返回类型。例如:

  • 1 + 1返回int
  • 1L + 1L返回long
  • 1L + 1返回long
  • 1 + 1.5返回double
  • 1 + 2 - 3 * 4 / 5返回int
  • 1 / 0返回int
  • 1 + Math.nextInt()返回int
  • 1.5 + Math.nextInt()返回double
  • Color.RED返回java.awt.Color
  • 鉴于这a是一个 int:a + 1返回int
  • 鉴于这a是一个 int:a + 1.5返回double

无需实际评估代码:我只需要返回类型。如何使用 JDK 运行时编译器、ECJ JDT 或任何其他纯 Java 依赖项来做到这一点?


详细代码:这是此代码的简化伪代码单元测试:

public static void ExpressionTyper {
    public String determineType(String expression, Map<String, String> variableTypes) {
       ... // How do I implement this?
    }
}
public void ExpressionTyperTest {
    @Test public void determineType() {
        assertEquals("int", ExpressionTyper.determineType("1 + 1", emptyMap());
        assertEquals("long", ExpressionTyper.determineType("1 + 1L", emptyMap());
        assertEquals("double", ExpressionTyper.determineType("1 + 1.5", emptyMap());
        assertEquals("int", ExpressionTyper.determineType("a + 1", mapOf({"a", "int"}));
        assertEquals("int", ExpressionTyper.determineType("a + b", mapOf({"a", "int"}, {"b", "int"}));
        assertEquals("double", ExpressionTyper.determineType("a + b", mapOf({"a", "double"}, {"b", "int"}));
    }
}
4

3 回答 3

5

我认为这取决于您希望能够处理的输入范围。

你看,最后你问的是:我如何在运行时评估字符串表达式。

所以,简短的回答是:你需要某种解释器/REPL 实现;或者至少是其中的“部分”。

另一种方法是使用 javax 编译器简单地编译事物,然后推断类型,就像这里一样。

其他选项将遵循某些“编译器构造”主题,例如常量折叠

于 2016-07-06T07:38:31.850 回答
3

这个我没试过。。。

  1. 用这样的代码包装你的表达式:

      public class Test {
          private Test xxx = <<insert expression>>;
      }
    
  2. 编译代码。

  3. 解析编译错误信息以提取编译器对 RHS 类型的想法。

问题是一个表达式Math.nextInt()可能需要一个可编译的导入,我怀疑是否有一种防弹的方法来推断导入应该是什么。不过,这应该适用于有用的表达式子集。

这种方法也是脆弱且不可移植的,因为它取决于编译错误消息的精确形式,而编译错误消息可能取决于编译器/版本。


更好的解决方案(但更多的工作)是为您的 Java 子集表达式语言实现解析器和类型检查器。

于 2016-07-06T07:40:06.697 回答
1

要对任意表达式执行此操作,您需要一个完整的 Java 前端来解析字符串并确定其类型。本质上,您需要编译器的功能。

Eclipse JDT 可能会提供一个解决方案;我对它不是很熟悉。

我们的带有 DMS 完整 Java 前端的 DMS 软件再造工具包可以做到这一点。DMS 根据它正在使用的前端解析源代码,然后可以调用前端服务来分析该代码。

Java 前端提供各种版本的 Java 解析和各种解析方式(文件、流、字符串),然后将为解析的文本构建树。可以要求内置于前端的 Java 名称解析器根据代码中特定点处有效的范围规则计算任意表达式的类型。

对于 OP,这可能不是他想要的,因为他坚持基于 Java 的答案并且 DMS 不是基于 Java 的(他确实要求“......任何其他依赖项”)。最接近的可能是调用 DMS 作为子进程,并要求 DMS 打印表达式的类型。如果他的表达式具有极少的类型,如他的示例所示,这可能会起作用。如果不是这样,他将需要一些复杂的机器来读取表达式类型,在它们的全部荣耀中(例如,包解析、模板形式)可能非常复杂。

If OP is willing to severely restrict the class of expressions he needs to handle to just simple arithmetic, he might be able to build his own expression parser and work out the type for himself. See my SO answer on how to build a recursive descent parser by hand: https://stackoverflow.com/a/2336769/120163 This same thread of answers also shows how to build a tree and 'evaluate' it; he can evaluate it for the type rather than the computed result.

Otherwise he is going to need the big hammer.

于 2016-07-06T09:55:57.467 回答