javaastviewer.js revision 970:f82b83cf73ae
1#// Usage: jjs -fx javaastviewer.js -- <.java files>
2
3/*
4 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 *   - Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 *
13 *   - Redistributions in binary form must reproduce the above copyright
14 *     notice, this list of conditions and the following disclaimer in the
15 *     documentation and/or other materials provided with the distribution.
16 *
17 *   - Neither the name of Oracle nor the names of its
18 *     contributors may be used to endorse or promote products derived
19 *     from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34// This example demonstrates Java subclassing by Java.extend
35// and javac Compiler and Tree API. This example also uses
36// -fx and javafx TreeView to visualize Java AST as TreeView
37
38if (!$OPTIONS._fx || arguments.length == 0) {
39    print("Usage: jjs -fx javaastviewer.js -- <.java files>");
40    exit(1);
41}
42
43// Java types used
44var Enum = Java.type("java.lang.Enum");
45var HashSet  = Java.type("java.util.HashSet");
46var Name = Java.type("javax.lang.model.element.Name");
47var List = Java.type("java.util.List");
48var Set  = Java.type("java.util.Set");
49var SimpleTreeVisitor = Java.type("com.sun.source.util.SimpleTreeVisitor");
50var StringArray = Java.type("java.lang.String[]");
51var ToolProvider = Java.type("javax.tools.ToolProvider");
52var Tree = Java.type("com.sun.source.tree.Tree");
53
54function javaASTToScriptObject(args) {
55    // properties ignored (javac implementation class properties) in AST view.
56    // may not be exhaustive - any getAbc would become "abc" property or
57    // public field becomes a property of same name.
58    var ignoredProps = new HashSet();
59    for each (var word in
60        ['extending', 'implementing', 'init', 'mods', 'clazz', 'defs',
61         'expr', 'tag', 'preferredPosition', 'qualid', 'recvparam',
62         'restype', 'params', 'startPosition', 'thrown',
63         'tree', 'typarams', 'typetag', 'vartype']) {
64        ignoredProps.add(word);
65    }
66
67    // get the system compiler tool
68    var compiler = ToolProvider.systemJavaCompiler;
69
70    // get standard file manager
71    var fileMgr = compiler.getStandardFileManager(null, null, null);
72
73    // make a list of compilation unit from command line argument file names
74    // Using Java.to convert script array (arguments) to a Java String[]
75    var compUnits = fileMgr.getJavaFileObjects(Java.to(args, StringArray));
76
77    // create a new compilation task
78    var task = compiler.getTask(null, fileMgr, null, null, null, compUnits);
79
80    // subclass SimpleTreeVisitor - converts Java AST node to
81    // a simple script object by walking through it
82    var ConverterVisitor = Java.extend(SimpleTreeVisitor);
83
84    var visitor = new ConverterVisitor() {
85        // convert java AST node to a friendly script object
86        // which can be viewed. Every node ends up in defaultAction
87        // method of SimpleTreeVisitor method.
88
89        defaultAction: function (node, p) {
90            var resultObj = {};
91            // Nashorn does not iterate properties and methods of Java objects
92            // But, we can bind properties of any object (including java objects)
93            // to a script object and iterate it!
94            var obj = {};
95            Object.bindProperties(obj, node);
96
97            // we don't want every property, method of java object
98            for (var prop in obj) {
99                var val = obj[prop];
100                var type = typeof val;
101                // ignore 'method' members
102                if (type == 'function' || type == 'undefined') {
103                    continue;
104                }
105
106                // ignore properties from Javac implementation
107                // classes - hack by name!!
108                if (ignoredProps.contains(prop)) {
109                    continue;
110                }
111
112                // subtree - recurse it
113                if (val instanceof Tree) {
114                    resultObj[prop] = visitor.visit(val, p);
115                } else if (val instanceof List) {
116                    // List of trees - recurse each and make an array
117                    var len = val.size();
118                    if (len != 0) {
119                        var arr = [];
120                        for (var j = 0; j < len; j++) {
121                            var e = val[j];
122                            if (e instanceof Tree) {
123                                arr.push(visitor.visit(e, p));
124                            }
125                        }
126                        resultObj[prop] = arr;
127                    }
128                } else if (val instanceof Set) {
129                    // Set - used for modifier flags
130                    // make array
131                    var len = val.size();
132                    if (len != 0) {
133                        var arr = [];
134                        for each (var e in val) {
135                            if (e instanceof Enum || typeof e == 'string') {
136                                arr.push(e.toString());
137                            }
138                        }
139                        resultObj[prop] = arr;
140                    }
141                } else if (val instanceof Enum || val instanceof Name) {
142                    // make string for any Enum or Name
143                    resultObj[prop] = val.toString();
144                } else if (type != 'object') {
145                    // primitives 'as is'
146                    resultObj[prop] = val;
147                }
148            }
149            return resultObj;
150        }
151    }
152
153    // top level object with one property for each compilation unit
154    var scriptObj = {};
155    for each (var cu in task.parse()) {
156        scriptObj[cu.sourceFile.name] = cu.accept(visitor, null);
157    }
158
159    return scriptObj;
160}
161
162// JavaFX classes used
163var StackPane = Java.type("javafx.scene.layout.StackPane");
164var Scene     = Java.type("javafx.scene.Scene");
165var TreeItem  = Java.type("javafx.scene.control.TreeItem");
166var TreeView  = Java.type("javafx.scene.control.TreeView");
167
168// Create a javafx TreeItem to view a script object
169function treeItemForObject(obj, name) {
170    var item = new TreeItem(name);
171    for (var prop in obj) {
172       var node = obj[prop];
173       if (typeof node == 'object') {
174           if (node == null) {
175               // skip nulls
176               continue;
177           }
178           var subitem = treeItemForObject(node, prop);
179       } else {
180           var subitem = new TreeItem(prop + ": " + node);
181       }
182       item.children.add(subitem);
183    }
184
185    item.expanded = true;
186    return item;
187}
188
189var commandArgs = arguments;
190
191// JavaFX start method
192function start(stage) {
193    var obj = javaASTToScriptObject(commandArgs);
194    stage.title = "Java AST Viewer"
195    var rootItem = treeItemForObject(obj, "AST");
196    rootItem.expanded = true;
197    var tree = new TreeView(rootItem);
198    var root = new StackPane();
199    root.children.add(tree);
200    stage.scene = new Scene(root, 300, 450);
201    stage.show();
202}
203