[英]How do I track variable dependencies in Nashorn?
我想将Nashorn引擎用作通用计算引擎。 它功能强大,快速,具有大量内置函数,并且使用@FunctionalInterface或静态方法非常容易添加新函数。 更好的是,它还提供诸如循环依赖项检查,语法检查等增值。
但是,当依赖项更改时,我需要自动更新“输出”变量。
一般的想法是,在Java中,我会得到类似以下内容的信息:
class CalculationEngine {
Data addData(String name, Number value){
...
}
Data addData(String name, String formula){
...
}
String getScript(){
...
}
}
CalculationEngine engine = new CalculationEngine();
Data datum1 = engine.addData("datum1", 1); // Constant integer 1
Data datum2 = engine.addData("datum2", 2); // Constant integer 2
Data datum3 = engine.addData("datum3", "datum1*10");
Data datum4 = engine.addData("datum4", "datum3+datum2");
CalculationEngine服务类知道如何使用Nashorn从如下所示的Data
对象中创建脚本字符串:
final String script = engine.getScript(); // "var datum1=1; var datum2=2; var datum3=datum1*10; var datum4=datum3+datum2;"
我知道我可以使用Nashorn Parser解析脚本:
final CompilationUnitTree tree = parser.parse("test", script, null);
但是我如何提取依赖关系:
List<Data> whatDependsOn(Data input){
// Process the parsed tree
return list;
}
这样whatDependsOn(datum2)
返回[datum4],而whatDependsOn(datum1)
返回[datum3,datum4]吗?
或反函数getReferencedVariables
,使getReferencedVariables(datum3)
返回[datum1], getReferencedVariables(datum4)
返回[datum2,datum3](并且我可以递归查询getReferencedVariables
直到找到所有引用的变量)。
基本上,当我的一个Data
对象的“值”发生变化(由于外部事件)时,我如何确定哪个脚本公式受到影响并需要重新计算?
我知道可以解析Nashorn脚本,但是我不知道如何使用SimpleTreeVisitorES6
建立变量依赖图:
final CompilationUnitTree tree = parser.parse("test", script, null);
if (tree != null) {
tree.accept(new SimpleTreeVisitorES6<Void, Void>() {
@Override
public Void visitVariable(VariableTree tree, Void v) {
final Kind kind = tree.getKind();
System.out.println("Found a variable: " + kind);
System.out.println(" name: " + kind.toString());
IdentifierTree binding = (IdentifierTree) tree.getBinding();
System.out.println(" kind: " + binding.getKind().name());
System.out.println(" name: " + binding.getName());
System.out.println(" val: " + kind.name());
return null;
}
}, null);
}
Nashorn开发人员之一。 您想要做的是在源代码上计算所谓的def-use关系(很可能是它们的传递闭包,但是我离题了)。 这是一个很好理解的编译器理论概念。 好消息是, CompilationUnitTree
和朋友应该为您提供足够的信息,以实现用于计算此信息的算法。 坏消息是,恐怕您将不得不袖手旁观并自行实施。 您基本上必须收集这些信息,在控制流连接点(循环的后边缘和出口,if语句的末端)产生合并,但是还必须处理更多奇特的东西,例如switch / case及其后缀语义和还尝试/捕获/最终,这是最不有趣的,因为基本上控制权可以从try块中的任何地方转移到catch块。)您的算法还必须反复评估循环主体,直到收集到的静态信息达到不动点。
FWIW,在编写Nashorn时,我不得不使用Nashorn的内部解析器API来实现这些事情几次(这是不同的,但类似于公共的)。 如果您想获得启发,可以查看Nashorn静态类型分析器的源代码,以推断 JavaScript函数中的局部变量类型,这是我几年前写的。 如果没有其他问题,它将为您提供一个思路,如何走一棵AST树并跟踪控制流边缘以及边缘处的部分计算的静态分析数据。
我希望有一个更简单的方法可以执行此操作……FWIW,可以帮助您保持流控制的布尔值的通用静态分析器。 祝好运。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.