如何通过Nashorn遍历AST获取函数内部的语句?
嘿,我刚好对Nashorn的AST遍历有点经验,这就帮你解决问题!你说得没错,要拿到函数内部的语句,确实得用访问者模式深入遍历AST的子节点——你之前的代码应该只是处理了顶层的函数定义节点,没钻进去看函数体里的内容。
下面给你一步步讲怎么实现:
核心思路
Nashorn的jdk.nashorn.api.tree包提供了完整的AST访问者接口,最方便的是继承SimpleTreeVisitorES6(它默认实现了所有visit方法,你只需要重写关心的部分)。我们需要:
- 解析JS代码生成AST根节点
CompilationUnitTree - 自定义访问者,重写函数相关的visit方法,在方法里获取函数体并遍历其中的语句
- 递归处理函数体里的每个子节点(比如return语句)
完整代码示例
假设你的目标JS代码是:
function someFunction() { return b + 1; }
对应的Java实现代码如下:
首先导入必要的包:
import jdk.nashorn.api.tree.*; import jdk.nashorn.api.scripting.NashornScriptEngine; import javax.script.ScriptEngineManager; import java.util.List;
然后写自定义的访问者类:
class FunctionBodyVisitor extends SimpleTreeVisitorES6<Void, Void> { // 处理函数声明(比如function someFunc() {}) @Override public Void visitFunctionDeclaration(FunctionTree tree, Void unused) { System.out.println("找到函数声明: " + tree.getName().getIdentifier()); // 获取函数体的块节点 BlockTree functionBody = tree.getBody(); // 遍历函数体里的所有语句 visitBlock(functionBody, unused); return null; } // 处理函数表达式(比如let fn = function() {}) @Override public Void visitFunctionExpression(FunctionTree tree, Void unused) { String funcName = tree.getName() != null ? tree.getName().getIdentifier() : "匿名函数"; System.out.println("找到函数表达式: " + funcName); BlockTree functionBody = tree.getBody(); visitBlock(functionBody, unused); return null; } // 处理return语句 @Override public Void visitReturn(ReturnTree tree, Void unused) { System.out.println("找到return语句: " + tree.getExpression()); // 如果还想深入解析return里的表达式(比如b+1),可以继续调用tree.getExpression().accept(this, null) return null; } // 遍历代码块里的所有语句 @Override public Void visitBlock(BlockTree tree, Void unused) { List<? extends StatementTree> statements = tree.getStatements(); for (StatementTree stmt : statements) { // 递归调用accept,让访问者处理每个子语句 stmt.accept(this, null); } return null; } }
最后是主函数的解析和遍历逻辑:
public class NashornASTDemo { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); NashornScriptEngine engine = (NashornScriptEngine) manager.getEngineByName("nashorn"); String jsCode = "function someFunction() { return b + 1; }"; // 获取Nashorn的解析器,生成AST Parser parser = engine.getParser(); CompilationUnitTree astRoot = parser.parse("test.js", jsCode, null); // 使用自定义访问者遍历AST FunctionBodyVisitor visitor = new FunctionBodyVisitor(); astRoot.accept(visitor, null); } }
代码说明
- 重写
visitFunctionDeclaration和visitFunctionExpression是为了覆盖所有函数定义的场景,不管是声明式还是表达式式的函数。 FunctionTree.getBody()会返回函数体的BlockTree,调用它的getStatements()就能拿到函数内部的所有语句列表。- 通过递归调用
stmt.accept(this, null),访问者会自动匹配对应的visit方法(比如遇到return语句就触发visitReturn),这样就能深入到任何嵌套的节点里。
运行这段代码后,你应该能看到输出:
找到函数声明: someFunction 找到return语句: b + 1
完美拿到你想要的return b + 1语句啦!
内容的提问来源于stack exchange,提问作者Nathan Devery
相关产品推荐
相关产品推荐

