Получить переменные из выражения javascript (Rhino)

Я использую Rhino для оценки выражений js, помещая все возможные значения переменных в область видимости и оценивая анонимную функцию. Однако выражения довольно просты, и я хотел бы указать только значения, используемые в выражении, для производительности.

Пример кода:

    Context cx = Context.enter();

    Scriptable scope = cx.initStandardObjects(null);

    // Build javascript anonymous function
    String script = "(function () {" ;

    for (String key : values.keySet()) {
        ScriptableObject.putProperty(scope, key, values.get(key));
    }
    script += "return " + expression + ";})();";

    Object result = cx.evaluateString(scope, script, "<cmd>", 1, null);

Я хочу получить все токены из выражений, которые являются именами переменных.

Например, если выражение

(V1ND < 0 ? Math.abs(V1ND) : 0)

он вернет V1ND.


person Lluis Martinez    schedule 24.08.2012    source источник
comment
Связанный вопрос: Получение имен функций и их аргументов из оцененного JS с помощью Rhino   -  person McDowell    schedule 22.01.2013


Ответы (1)


В Rhino 1.7 R3 появился пакет AST который можно использовать для поиска имен:

import java.util.*;
import org.mozilla.javascript.Parser;
import org.mozilla.javascript.ast.*;

public class VarFinder {
  public static void main(String[] args) throws IOException {
    final Set<String> names = new HashSet<String>();
    class Visitor implements NodeVisitor {
      @Override public boolean visit(AstNode node) {
        if (node instanceof Name) {
          names.add(node.getString());
        }
        return true;
      }
    }
    String script = "(V1ND < 0 ? Math.abs(V1ND) : 0)";
    AstNode node = new Parser().parse(script, "<cmd>", 1);
    node.visit(new Visitor());
    System.out.println(names);
  }
}

Вывод:

[V1ND, abs, Math]

Однако я не уверен, что это сильно поможет с эффективностью, если выражения не поддаются кэшированию. Вы будете анализировать код дважды, и если вам нужно устранить неоднозначность переменной abs из функции Math, потребуется дополнительная проверка.

person McDowell    schedule 22.01.2013
comment
Я решил это прошлым летом с помощью библиотеки Runcc (с упрощенной грамматикой JS). Но ваше решение выглядит потрясающе, я буду использовать его для будущего рефакторинга. - person Lluis Martinez; 05.02.2013