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