/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.codehaus.groovy.antlr.treewalker; import org.codehaus.groovy.antlr.GroovySourceAST; import org.codehaus.groovy.antlr.LineColumn; import org.codehaus.groovy.antlr.SourceBuffer; import org.codehaus.groovy.antlr.parser.GroovyTokenTypes; import java.io.PrintStream; /** * An antlr AST visitor that prints a format suitable for viewing in http://freemind.sourceforge.net * * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a> */ public class MindMapPrinter extends VisitorAdapter { private final String[] tokenNames; private final PrintStream out; private int depth; private SourceBuffer sourceBuffer; /** * A visitor that prints a format suitable for viewing in http://freemind.sourceforge.net * @param out where to print the mindmap file contents to * @param tokenNames an array of token names from antlr */ public MindMapPrinter(PrintStream out,String[] tokenNames) { this.tokenNames = tokenNames; this.out = out; } public MindMapPrinter(PrintStream out,String[] tokenNames, SourceBuffer sourceBuffer) { this.tokenNames = tokenNames; this.out = out; this.sourceBuffer = sourceBuffer; } public void setUp() { depth = 0; out.println("<map version='0.7.1'><node TEXT='AST'>"); } public void visitDefault(GroovySourceAST t,int visit) { if (visit == OPENING_VISIT) { depth++; String name = getName(t); String colour = getColour(t); String folded = getFolded(t); out.print("<node TEXT='" + name + "' POSITION='right'" + colour + folded + ">"); } else if (visit == CLOSING_VISIT) { out.println("</node>"); depth--; } } public void tearDown() { out.println("</node></map>"); } private String getFolded(GroovySourceAST t) { if (depth > 2 && t.getNumberOfChildren() > 0) { switch (t.getType()) { case GroovyTokenTypes.EXPR : case GroovyTokenTypes.METHOD_DEF : case GroovyTokenTypes.VARIABLE_DEF : return " FOLDED='true'"; } } if (t.getType() == GroovyTokenTypes.IMPORT) { return " FOLDED='true'"; } return ""; } private static String getColour(GroovySourceAST t) { String colour = ""; String black = " COLOR=\"#000000\""; String cyan = " COLOR=\"#006699\""; String blue = " COLOR=\"#17178B\""; String green = " COLOR=\"#008000\""; switch (t.getType()) { case GroovyTokenTypes.ABSTRACT : case GroovyTokenTypes.ANNOTATION : case GroovyTokenTypes.ANNOTATIONS : case GroovyTokenTypes.ANNOTATION_ARRAY_INIT : case GroovyTokenTypes.ANNOTATION_DEF : case GroovyTokenTypes.ANNOTATION_FIELD_DEF : case GroovyTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR : case GroovyTokenTypes.ARRAY_DECLARATOR : case GroovyTokenTypes.ASSIGN : case GroovyTokenTypes.AT : case GroovyTokenTypes.BAND : case GroovyTokenTypes.BAND_ASSIGN : case GroovyTokenTypes.BIG_SUFFIX : case GroovyTokenTypes.BLOCK : case GroovyTokenTypes.BNOT : case GroovyTokenTypes.BOR : case GroovyTokenTypes.BOR_ASSIGN : case GroovyTokenTypes.BSR : case GroovyTokenTypes.BSR_ASSIGN : case GroovyTokenTypes.BXOR : case GroovyTokenTypes.BXOR_ASSIGN : case GroovyTokenTypes.CASE_GROUP : case GroovyTokenTypes.CLOSABLE_BLOCK : case GroovyTokenTypes.CLOSABLE_BLOCK_OP : case GroovyTokenTypes.COLON : case GroovyTokenTypes.COMMA : case GroovyTokenTypes.COMPARE_TO : case GroovyTokenTypes.CTOR_CALL : case GroovyTokenTypes.CTOR_IDENT : case GroovyTokenTypes.DEC : case GroovyTokenTypes.DIGIT : case GroovyTokenTypes.DIV : case GroovyTokenTypes.DIV_ASSIGN : case GroovyTokenTypes.DOLLAR : case GroovyTokenTypes.DOT : case GroovyTokenTypes.DYNAMIC_MEMBER : case GroovyTokenTypes.ELIST : case GroovyTokenTypes.EMPTY_STAT : case GroovyTokenTypes.ENUM_CONSTANT_DEF : case GroovyTokenTypes.ENUM_DEF : case GroovyTokenTypes.EOF : case GroovyTokenTypes.EQUAL : case GroovyTokenTypes.ESC : case GroovyTokenTypes.EXPONENT : case GroovyTokenTypes.EXPR : case GroovyTokenTypes.FINAL : case GroovyTokenTypes.FLOAT_SUFFIX : case GroovyTokenTypes.FOR_CONDITION : case GroovyTokenTypes.FOR_EACH_CLAUSE : case GroovyTokenTypes.FOR_INIT : case GroovyTokenTypes.FOR_IN_ITERABLE : case GroovyTokenTypes.FOR_ITERATOR : case GroovyTokenTypes.GE : case GroovyTokenTypes.GT : case GroovyTokenTypes.HEX_DIGIT : case GroovyTokenTypes.IMPLICIT_PARAMETERS : case GroovyTokenTypes.INC : case GroovyTokenTypes.INDEX_OP : case GroovyTokenTypes.INSTANCE_INIT : case GroovyTokenTypes.INTERFACE_DEF : case GroovyTokenTypes.LABELED_ARG : case GroovyTokenTypes.LABELED_STAT : case GroovyTokenTypes.LAND : case GroovyTokenTypes.LBRACK : case GroovyTokenTypes.LCURLY : case GroovyTokenTypes.LE : case GroovyTokenTypes.LETTER : case GroovyTokenTypes.LIST_CONSTRUCTOR : case GroovyTokenTypes.LNOT : case GroovyTokenTypes.LOR : case GroovyTokenTypes.LPAREN : case GroovyTokenTypes.LT : case GroovyTokenTypes.MAP_CONSTRUCTOR : case GroovyTokenTypes.MEMBER_POINTER : case GroovyTokenTypes.METHOD_CALL : case GroovyTokenTypes.METHOD_DEF : case GroovyTokenTypes.MINUS : case GroovyTokenTypes.MINUS_ASSIGN : case GroovyTokenTypes.ML_COMMENT : case GroovyTokenTypes.MOD : case GroovyTokenTypes.MODIFIERS : case GroovyTokenTypes.MOD_ASSIGN : case GroovyTokenTypes.NLS : case GroovyTokenTypes.NOT_EQUAL : case GroovyTokenTypes.NULL_TREE_LOOKAHEAD : case GroovyTokenTypes.NUM_BIG_DECIMAL : case GroovyTokenTypes.NUM_BIG_INT : case GroovyTokenTypes.NUM_DOUBLE : case GroovyTokenTypes.NUM_FLOAT : case GroovyTokenTypes.NUM_INT : case GroovyTokenTypes.NUM_LONG : case GroovyTokenTypes.OBJBLOCK : case GroovyTokenTypes.ONE_NL : case GroovyTokenTypes.OPTIONAL_DOT : case GroovyTokenTypes.PARAMETERS : case GroovyTokenTypes.PARAMETER_DEF : case GroovyTokenTypes.PLUS : case GroovyTokenTypes.PLUS_ASSIGN : case GroovyTokenTypes.POST_DEC : case GroovyTokenTypes.POST_INC : case GroovyTokenTypes.QUESTION : case GroovyTokenTypes.RANGE_EXCLUSIVE : case GroovyTokenTypes.RANGE_INCLUSIVE : case GroovyTokenTypes.RBRACK : case GroovyTokenTypes.RCURLY : case GroovyTokenTypes.REGEXP_CTOR_END : case GroovyTokenTypes.REGEXP_SYMBOL : case GroovyTokenTypes.REGEX_FIND : case GroovyTokenTypes.REGEX_MATCH : case GroovyTokenTypes.RPAREN : case GroovyTokenTypes.SELECT_SLOT : case GroovyTokenTypes.SEMI : case GroovyTokenTypes.SH_COMMENT : case GroovyTokenTypes.SL : case GroovyTokenTypes.SLIST : case GroovyTokenTypes.SL_ASSIGN : case GroovyTokenTypes.SL_COMMENT : case GroovyTokenTypes.SPREAD_ARG : case GroovyTokenTypes.SPREAD_DOT : case GroovyTokenTypes.SPREAD_MAP_ARG : case GroovyTokenTypes.SR : case GroovyTokenTypes.SR_ASSIGN : case GroovyTokenTypes.STAR : case GroovyTokenTypes.STAR_ASSIGN : case GroovyTokenTypes.STAR_STAR : case GroovyTokenTypes.STAR_STAR_ASSIGN : case GroovyTokenTypes.STATIC_IMPORT : case GroovyTokenTypes.STATIC_INIT : case GroovyTokenTypes.STRICTFP : case GroovyTokenTypes.STRING_CH : case GroovyTokenTypes.STRING_CONSTRUCTOR : case GroovyTokenTypes.STRING_CTOR_END : case GroovyTokenTypes.STRING_CTOR_MIDDLE : case GroovyTokenTypes.STRING_CTOR_START : case GroovyTokenTypes.STRING_NL : case GroovyTokenTypes.SUPER_CTOR_CALL : case GroovyTokenTypes.TRIPLE_DOT : case GroovyTokenTypes.TYPECAST : case GroovyTokenTypes.TYPE_ARGUMENT : case GroovyTokenTypes.TYPE_ARGUMENTS : case GroovyTokenTypes.TYPE_LOWER_BOUNDS : case GroovyTokenTypes.TYPE_PARAMETER : case GroovyTokenTypes.TYPE_PARAMETERS : case GroovyTokenTypes.TYPE_UPPER_BOUNDS : case GroovyTokenTypes.UNARY_MINUS : case GroovyTokenTypes.UNARY_PLUS : case GroovyTokenTypes.UNUSED_CONST : case GroovyTokenTypes.UNUSED_DO : case GroovyTokenTypes.UNUSED_GOTO : case GroovyTokenTypes.VARIABLE_DEF : case GroovyTokenTypes.VARIABLE_PARAMETER_DEF : case GroovyTokenTypes.VOCAB : case GroovyTokenTypes.WILDCARD_TYPE : case GroovyTokenTypes.WS : colour = black; break; case GroovyTokenTypes.STRING_LITERAL : case GroovyTokenTypes.REGEXP_LITERAL : case GroovyTokenTypes.DOLLAR_REGEXP_LITERAL : colour = green; break; case GroovyTokenTypes.CLASS_DEF : case GroovyTokenTypes.EXTENDS_CLAUSE : case GroovyTokenTypes.IMPLEMENTS_CLAUSE : case GroovyTokenTypes.IMPORT : case GroovyTokenTypes.LITERAL_as : case GroovyTokenTypes.LITERAL_assert : case GroovyTokenTypes.LITERAL_boolean : case GroovyTokenTypes.LITERAL_break : case GroovyTokenTypes.LITERAL_byte : case GroovyTokenTypes.LITERAL_case : case GroovyTokenTypes.LITERAL_catch : case GroovyTokenTypes.LITERAL_char : case GroovyTokenTypes.LITERAL_class : case GroovyTokenTypes.LITERAL_continue : case GroovyTokenTypes.LITERAL_def : case GroovyTokenTypes.LITERAL_default : case GroovyTokenTypes.LITERAL_double : case GroovyTokenTypes.LITERAL_else : case GroovyTokenTypes.LITERAL_enum : case GroovyTokenTypes.LITERAL_extends : case GroovyTokenTypes.LITERAL_false : case GroovyTokenTypes.LITERAL_finally : case GroovyTokenTypes.LITERAL_float : case GroovyTokenTypes.LITERAL_for : case GroovyTokenTypes.LITERAL_if : case GroovyTokenTypes.LITERAL_implements : case GroovyTokenTypes.LITERAL_import : case GroovyTokenTypes.LITERAL_in : case GroovyTokenTypes.LITERAL_instanceof : case GroovyTokenTypes.LITERAL_int : case GroovyTokenTypes.LITERAL_interface : case GroovyTokenTypes.LITERAL_long : case GroovyTokenTypes.LITERAL_native : case GroovyTokenTypes.LITERAL_new : case GroovyTokenTypes.LITERAL_null : case GroovyTokenTypes.LITERAL_package : case GroovyTokenTypes.LITERAL_private : case GroovyTokenTypes.LITERAL_protected : case GroovyTokenTypes.LITERAL_public : case GroovyTokenTypes.LITERAL_return : case GroovyTokenTypes.LITERAL_short : case GroovyTokenTypes.LITERAL_static : case GroovyTokenTypes.LITERAL_super : case GroovyTokenTypes.LITERAL_switch : case GroovyTokenTypes.LITERAL_synchronized : case GroovyTokenTypes.LITERAL_this : case GroovyTokenTypes.LITERAL_threadsafe : case GroovyTokenTypes.LITERAL_throw : case GroovyTokenTypes.LITERAL_throws : case GroovyTokenTypes.LITERAL_transient : case GroovyTokenTypes.LITERAL_true : case GroovyTokenTypes.LITERAL_try : case GroovyTokenTypes.LITERAL_void : case GroovyTokenTypes.LITERAL_volatile : case GroovyTokenTypes.LITERAL_while : case GroovyTokenTypes.PACKAGE_DEF : case GroovyTokenTypes.TYPE : colour = blue; break; case GroovyTokenTypes.IDENT : colour = cyan; break; default: colour = black; break; } // leaf nodes that haven't been coloured yet if (black.equals(colour) && t.getNumberOfChildren() == 0) { colour = cyan; } return colour; } private String getName(GroovySourceAST t) { String name = tokenNames[t.getType()] + " <" + t.getType() + ">"; if (!(escape(tokenNames[t.getType()]).equals(escape(t.getText())))) { name = name + " : " + t.getText(); } switch (t.getType()) { case GroovyTokenTypes.METHOD_DEF : case GroovyTokenTypes.VARIABLE_DEF : GroovySourceAST identNode = t.childOfType(GroovyTokenTypes.IDENT); if (identNode != null) { name = name + " : " + identNode.getText() + ""; } } name = escape(name); if (sourceBuffer != null) { name += " "; name += t.getLine() + "," + t.getColumn() + " - " + t.getLineLast() + "," + t.getColumnLast(); name += " "; name += escape(sourceBuffer.getSnippet(new LineColumn(t.getLine(), t.getColumn()), new LineColumn(t.getLineLast(), t.getColumnLast()))); } return name; } private static String escape(String name) { if (name == null) return null; // remove middle of large bits of text if (name.length() > 200) { name = name.substring(0,100) + " ..... " + name.substring(name.length() - 100); } name = name.replace('"',' '); name = name.replace('\'',' '); name = name.replaceAll("&","&"); name = name.replaceAll("<","<"); name = name.replaceAll(">",">"); name = name.trim(); return name; } }