获取函数内部最后计算的表达式 [英] Get last evaluated expression inside function
问题描述
这与另一个问题有关:
但是我想提供更多有关我想做的事情的详细信息,并说明如何最终解决该问题。一些用户在评论中要求。
But I wanted to provide more details about what I wanted to do and show how I finally solved the problem as some users requested in the comments.
我有一些由我的应用程序用户编写的Javascript代码段。此代码段需要转到这样的模板:
I have snippets of Javascript that are written by users of my app. This snippets need to go to a kind of template like this:
var foo1 = function(data, options) {
<snippet of code written by user>
}
var foo2 = function(data, options) {
<snippet of code written by user>
}
...
表达式可能会非常不同,例如:
Expressions can be very different, from simple things like this:
data.price * data.qty
像这样更复杂的东西:
if (data.isExternal) {
data.email;
} else {
data.userId;
}
该函数返回的值应始终为最后计算的表达式。
The value returned by the function should be always the last evaluated expression.
在我们遇到这样的事情之前:
Before we had something like this:
var foo1 = function(data, options) {
return eval(<snippet of code written by user>);
}
但是由于我们进行了优化和更改,我们无法继续使用eval,但是我们需要返回最后一个求值的表达式。
But due to optimizations and changes we are making, we cannot keep using eval, but we need to return the last evaluated expression.
仅添加'return'关键字将不起作用,因为表达式可以包含多个语句。因此,我需要使这些函数返回最后计算的表达式。
Just adding a 'return' keyword won't work because expressions can have several statements. So I need to make those functions return the last evaluated expressions.
限制和说明:
- 我不能强迫用户将'return'关键字添加到他们拥有的所有脚本中,因为已经编写了许多脚本,对于像'a * b'这样的简单表达式来说也不是很直观。
- 我正在使用Java和Rhino在服务器端运行Javascript。
推荐答案
正如人们在 Java中最后评估的表达式中指出的那样,获取最后一个评估的表达式在标准Javascript中是不可能的。
As people pointed out in Last evaluated expression in Javascript, getting the last evaluated expression is not possible in standard Javascript.
正如FelixKling所建议的,我最终要做的是操纵用户编写的脚本的AST。这样,我存储了用户编写的脚本和修改后的版本,这是我最终运行的版本。
What I finally ended up doing, as suggested by FelixKling, was to manipulate the AST of the script written by the user. This way I store the user written script and the modified version, which is the one I finally run.
为了操纵AST,我使用了Rhino并基本上将所有EXPR_RESULT节点修改为将结果存储在变量中,最后在脚本末尾返回。这是执行此操作的代码:
For manipulating the AST I used Rhino and basically modify all EXPR_RESULT nodes to store the result in a variable that I finally return at the end of the script. Here is the code to do that:
公共类ScriptsManipulationService {
private static final Logger logger = LoggerFactory.getLogger(ScriptsManipulationService.class);
public class ScriptsManipulationService { private static final Logger logger = LoggerFactory.getLogger(ScriptsManipulationService.class);
public String returnLastExpressionEvaluated(String script) {
Parser jsParser = new Parser();
try {
AstRoot ast = jsParser.parse(script, "script", 1);
ast.getType();
ast.visitAll(new NodeVisitor() {
@Override
public boolean visit(AstNode node) {
if (node.getType() == Token.EXPR_RESULT) {
ExpressionStatement exprNode = (ExpressionStatement) node;
Assignment assignmentNode = createAssignmentNode("_returnValue", exprNode.getExpression());
assignmentNode.setParent(exprNode);
exprNode.setExpression(assignmentNode);
}
return true;
}
});
StringBuilder result = new StringBuilder();
result.append("var _returnValue;\n");
result.append(ast.toSource());
result.append("return _returnValue;\n");
return result.toString();
} catch (Exception e) {
logger.debug(LogUtils.format("Error parsing script"), e);
return script;
}
}
private Assignment createAssignmentNode(String varName, AstNode rightNode) {
Assignment assignmentNode = new Assignment();
assignmentNode.setType(Token.ASSIGN);
Name leftNode = new Name();
leftNode.setType(Token.NAME);
leftNode.setIdentifier(varName);
leftNode.setParent(assignmentNode);
assignmentNode.setLeft(leftNode);
rightNode.setParent(assignmentNode);
assignmentNode.setRight(rightNode);
return assignmentNode;
}
}
这样,如果您传递以下脚本:
This way, if you pass the following script:
data.price * data.qty;
您将回来:
var _returnValue;
_returnValue = data.price * data.qty;
return _returnValue;
或者如果您通过:
var _returnValue;
if (data.isExternal) {
_returnValue = data.email;
} else {
_returnValue = data.userId;
}
return _returnValue;
请记住,我还没有进行详尽的测试,并且会随着时间的推移进行完善,但这应该可以显示总体思路。
Please keep in mind that I haven't done an exhaustive testing and will be polishing it over time, but this should show the general idea.
这篇关于获取函数内部最后计算的表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!