Search code examples
javascriptjavanashorn

Using Nashorn to parse JavaScript into a syntax tree


I'm writing a Java program that needs to parse JavaScript to a syntax tree. Trying the Nashorn API in JDK 9, which is said to be able to do this. The documentation on the datatype returned by the parser doesn't look terribly enlightening: https://docs.oracle.com/javase/9/docs/api/jdk/nashorn/api/tree/CompilationUnitTree.html

I've tried writing and running some code that looks like this:

        Parser              parser = Parser.create();
        CompilationUnitTree tree   = parser.parse(file, new InputStreamReader(stream), null);
        System.out.println(tree.getSourceElements());
        for (Object o : tree.getSourceElements()) {
            System.out.println(o);
        }

but the output looks like this:

[jdk.nashorn.api.tree.ExpressionStatementTreeImpl@32eebfca]
jdk.nashorn.api.tree.ExpressionStatementTreeImpl@32eebfca

What am I missing?

To be clear, I'm not asking why the output consists only of symbols with @ signs - obviously that's just the default toString - I'm pointing out that the obvious way to get information out of the returned data doesn't do anything, so presumably the intended way is something nonobvious.


Solution

  • tree.getSourceElements() gives you a list of elements of type Tree which has the method getKind​() that gives you the Tree.Kind of the element:

    Parser parser = Parser.create();
    CompilationUnitTree tree = parser.parse(file, new InputStreamReader(stream), null);
    
    for (Tree tree : tree.getSourceElements()) {
        System.out.println(tree.getKind());
    
        switch(tree.getKind()) {
            case FUNCTION:
                [...]
        }
    }
    

    If you want to run down the AST you can then implement the interface TreeVisitor<R,D> to visit the nodes:

    Parser parser = Parser.create();
    CompilationUnitTree tree = parser.parse(file, new InputStreamReader(stream), null);
    
    if (tree != null) {
        tree.accept(new BasicTreeVisitor<Void, Void>() {
            public Void visitFunctionCall(FunctionCallTree functionCallTree, Void v) {
                 System.out.println("Found a functionCall: " + functionCallTree.getFunctionSelect().getKind​());
                 return null;
             }
         }, null);
    }