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