Определите тип возвращаемого значения выражения Java в строке во время выполнения
Во время выполнения в моей 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"}));
}
}
3 ответа
Я думаю, что это зависит от диапазона ввода, который вы хотите обработать.
Видите ли, в конце вы спрашиваете: как мне вычислить строковые выражения во время выполнения.
Итак, короткий ответ: вам нужна какая-то реализация интерпретатора / REPL; или, по крайней мере, "части" этого.
Другой подход может состоять в том, чтобы использовать компилятор javax, чтобы просто скомпилировать объект, а затем вывести тип, как здесь.
Другие варианты будут соответствовать определенным темам "компиляции", таким как постоянное сворачивание.
Я не пробовал это...
Оберните свое выражение в коде так:
public class Test { private Test xxx = <<insert expression>>; }
Скомпилируйте код.
- Разобрать сообщение об ошибке компиляции, чтобы извлечь представление компилятора о типе RHS.
Проблема в том, что выражение как Math.nextInt()
может потребоваться, чтобы импорт был компилируемым, и я сомневаюсь, что существует надежный способ сделать вывод о том, каким должен быть импорт. Тем не менее, это должно работать для полезного набора выражений.
Этот подход также хрупок и непереносим, поскольку он зависит от точной формы сообщения об ошибке компиляции, которое может зависеть от компилятора / версии.
Лучшее решение (но больше работы) было бы реализовать синтаксический анализатор и проверку типов для вашего языка выражений подмножества Java.
Чтобы сделать это для произвольных выражений, вам нужен полный интерфейс Java, который будет анализировать строку и определять ее тип. По сути, вам нужно то, что делает компилятор.
Eclipse JDT может предложить решение; Я не очень знаком с этим.
Это можно сделать с помощью нашего набора инструментов для реинжиниринга программного обеспечения DMS с полным интерфейсом Java DMS. DMS анализирует источник в соответствии с внешним интерфейсом, который он использует, а затем может вызывать внешние службы для анализа этого кода.
Интерфейс Java обеспечивает синтаксический анализ Java в различных версиях и различных способов синтаксического анализа (файл, поток, строка), а затем создает дерево для проанализированного текста. Для распознавателя имен Java, встроенного во внешний интерфейс, может быть предложено вычислить тип произвольного выражения в соответствии с правилами области действия, действующими в конкретной точке кода.
Для OP это может быть не то, что он хочет, так как он настаивает на ответе на основе Java, а DMS не на основе Java (он просил "... любую другую зависимость"). Самый близкий из них - это вызвать DMS как подпроцесс и попросить DMS напечатать тип выражения. Если его выражения имеют чрезвычайно малое количество типов, как показано в его примере, это, вероятно, сработает. Если нет, ему понадобится сложный механизм для чтения типов выражений, который во всей своей красе (например, в форме с разрешением на пакеты, в шаблонной форме) может быть довольно сложным.
Если OP хочет строго ограничить класс выражений, которые ему нужно обработать, простой арифметикой, он может создать собственный синтаксический анализатор выражений и сам определить тип. Смотрите мой SO-ответ о том, как вручную создать синтаксический анализатор рекурсивного спуска: /questions/2016396/est-li-alternativa-flexbison-kotoruyu-mozhno-ispolzovat-v-8-bitnyih-vstroennyih-sistemah/2016399#2016399 этой же ветке ответов также показано, как построить дерево и "оценить" его; он может оценить его по типу, а не по вычисленному результату.
В противном случае ему понадобится большой молоток.