/* * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package org.visage.tools.tree; import org.visage.api.tree.Tree; import java.util.Map; import com.sun.tools.mjavac.util.*; import com.sun.tools.mjavac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.mjavac.code.*; import com.sun.tools.mjavac.tree.JCTree; import org.visage.tools.code.VisageFlags; /** Utility class containing inspector methods for trees. * * <p><b>This is NOT part of any API supported by Sun Microsystems. If * you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice.</b> */ public class VisageTreeInfo { /** The names of all operators. */ protected Name[] opname = new Name[VisageTag.MOD.ordinal() - VisageTag.NEG.ordinal() + 1]; protected static final Context.Key<VisageTreeInfo> visageTreeInfoKey = new Context.Key<VisageTreeInfo>(); public static VisageTreeInfo instance(Context context) { VisageTreeInfo instance = context.get(visageTreeInfoKey); if (instance == null) instance = new VisageTreeInfo(context); return instance; } protected VisageTreeInfo(Context context) { Name.Table names = Name.Table.instance(context); int base = VisageTag.NEG.ordinal(); opname = new Name[VisageTag.VISAGE_OP_LAST.ordinal() - base + 1]; opname[VisageTag.NEG .ordinal() - base] = names.hyphen; opname[VisageTag.NOT .ordinal() - base] = names.fromString("!"); opname[VisageTag.PREINC .ordinal() - base] = names.fromString("++"); opname[VisageTag.PREDEC .ordinal() - base] = names.fromString("--"); opname[VisageTag.POSTINC.ordinal() - base] = names.fromString("++"); opname[VisageTag.POSTDEC.ordinal() - base] = names.fromString("--"); opname[VisageTag.NULLCHK.ordinal() - base] = names.fromString("<*nullchk*>"); opname[VisageTag.OR .ordinal() - base] = names.fromString("or"); opname[VisageTag.AND .ordinal() - base] = names.fromString("and"); opname[VisageTag.EQ .ordinal() - base] = names.fromString("=="); opname[VisageTag.NE .ordinal() - base] = names.fromString("<>"); opname[VisageTag.LT .ordinal() - base] = names.fromString("<"); opname[VisageTag.GT .ordinal() - base] = names.fromString(">"); opname[VisageTag.LE .ordinal() - base] = names.fromString("<="); opname[VisageTag.GE .ordinal() - base] = names.fromString(">="); opname[VisageTag.PLUS .ordinal() - base] = names.fromString("+"); opname[VisageTag.MINUS .ordinal() - base] = names.hyphen; opname[VisageTag.MUL .ordinal() - base] = names.asterisk; opname[VisageTag.DIV .ordinal() - base] = names.slash; opname[VisageTag.MOD .ordinal() - base] = names.fromString("%"); opname[VisageTag.XOR .ordinal() - base] = names.fromString("xor"); opname[VisageTag.SIZEOF .ordinal() - base] = names.fromString("sizeof"); opname[VisageTag.INDEXOF .ordinal() - base] = names.fromString("indexof"); opname[VisageTag.REVERSE .ordinal() - base] = names.fromString("reverse"); } /** Return name of operator with given tree tag. */ public Name operatorName(VisageTag tag) { return opname[tag.ordinal() - VisageTag.NEG.ordinal()]; } /** A DiagnosticPosition with the preferred position set to the * end position of given tree, if it is a block with * defined endpos. */ public static DiagnosticPosition diagEndPos(final VisageTree tree) { final int endPos = VisageTreeInfo.endPos(tree); return new DiagnosticPosition() { public VisageTree getTree() { return tree; } public int getStartPosition() { return VisageTreeInfo.getStartPos(tree); } public int getPreferredPosition() { return endPos; } public int getEndPosition(Map<JCTree, Integer> endPosTable) { return VisageTreeInfo.getEndPos(tree, endPosTable); } }; } public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final VisageTree tree) { VisageTree decl = declarationFor(sym, tree); return ((decl != null) ? decl : tree).pos(); } /** Find the declaration for a symbol, where * that symbol is defined somewhere in the given tree. */ public static VisageTree declarationFor(final Symbol sym, final VisageTree tree) { class DeclScanner extends VisageTreeScanner { VisageTree result = null; @Override public void scan(VisageTree tree) { if ( tree != null && result == null ) { tree.accept(this); } } @Override public void visitClassDeclaration(VisageClassDeclaration that) { if (that.sym == sym) { result = that; } else { super.visitClassDeclaration(that); } } @Override public void visitScript(VisageScript that) { if ( that.packge == sym ) { result = that; } else { super.visitScript(that); } } @Override public void visitFunctionDefinition(VisageFunctionDefinition that) { if ( that.sym == sym ) { result = that; } else { super.visitFunctionDefinition(that); } } @Override public void visitVar(VisageVar that) { if ( that.sym == sym ) { result = that; } else { super.visitVar(that); } } } DeclScanner s = new DeclScanner(); tree.accept(s); return s.result; } public static List<VisageTree> pathFor(final VisageTree node, final VisageScript unit) { class Result extends Error { static final long serialVersionUID = -5942088234594905625L; List<VisageTree> path; Result(List<VisageTree> path) { this.path = path; } } class PathFinder extends VisageTreeScanner { List<VisageTree> path = List.nil(); @Override public void scan(VisageTree tree) { if (tree != null) { path = path.prepend(tree); if (tree == node) throw new Result(path); super.scan(tree); path = path.tail; } } } try { new PathFinder().scan(unit); } catch (Result result) { return result.path; } return List.nil(); } /** Return first (smallest) flag in `flags': * pre: flags != 0 */ public static long firstFlag(long flags) { for (int i = 0; i < 63; ++i) { long flag = 1L << i; if ((flag & flags) != 0) { return flag; } } throw new AssertionError(); } /** Return flags as a string, separated by " ". */ public static String flagNames(long flags) { return flagNames(flags, false); } /** Return flags as a string, separated by " ". */ public static String flagNames(long flags, boolean pretty) { StringBuffer fsb = new StringBuffer(Flags.toString(flags)); if ((flags & VisageFlags.PACKAGE_ACCESS) != 0) { fsb.append("package "); } if (!pretty && (flags & VisageFlags.SCRIPT_PRIVATE) != 0) { fsb.append("script only (default) "); } if ((flags & VisageFlags.PUBLIC_READ) != 0) { fsb.append("public-read "); } if ((flags & VisageFlags.PUBLIC_INIT) != 0) { fsb.append("public-init "); } if ((flags & VisageFlags.DEFAULT) != 0) { fsb.append("default "); } if ((flags & VisageFlags.BOUND) != 0) { fsb.append("bound "); } if ((flags & VisageFlags.MIXIN) != 0) { fsb.append("mixin "); } if ((flags & VisageFlags.OVERRIDE) != 0) { fsb.append("override "); } return fsb.toString().trim(); } /** Operator precedences values. */ public static final int notExpression = -1, // not an expression noPrec = 0, // no enclosing expression assignPrec = 1, assignopPrec = 2, orPrec = 3, andPrec = 4, eqPrec = 5, ordPrec = 6, addPrec = 7, mulPrec = 8, prefixPrec = 9, postfixPrec = 10, precCount = 11; /** Map operators to their precedence levels. */ public static int opPrec(VisageTag op) { switch(op) { case ASSIGN: // Java distinguished, Visage doesn't -- Java-style return assignPrec; case PLUS_ASG: case MINUS_ASG: case MUL_ASG: case DIV_ASG: return assignopPrec; case OR: case XOR: return orPrec; case AND: return andPrec; case EQ: case NE: return eqPrec; case LT: case GT: case LE: case GE: return ordPrec; case PLUS: case MINUS: return addPrec; case MUL: case DIV: case MOD: return mulPrec; case TYPETEST: return ordPrec; case NEG: case NOT: case PREINC: case PREDEC: case REVERSE: case INDEXOF: case SIZEOF: return prefixPrec; case POSTINC: case POSTDEC: case NULLCHK: return postfixPrec; default: throw new AssertionError("Unexpected operator precidence request: " + op); } } static Tree.VisageKind tagToKind(VisageTag tag) { switch (tag) { // Postfix expressions case POSTINC: // _ ++ return Tree.VisageKind.POSTFIX_INCREMENT; case POSTDEC: // _ -- return Tree.VisageKind.POSTFIX_DECREMENT; // Unary operators case PREINC: // ++ _ return Tree.VisageKind.PREFIX_INCREMENT; case PREDEC: // -- _ return Tree.VisageKind.PREFIX_DECREMENT; case NEG: // - return Tree.VisageKind.UNARY_MINUS; case NOT: // ! return Tree.VisageKind.LOGICAL_COMPLEMENT; // Binary operators // Multiplicative operators case MUL: // * return Tree.VisageKind.MULTIPLY; case DIV: // / return Tree.VisageKind.DIVIDE; case MOD: // % return Tree.VisageKind.REMAINDER; // Additive operators case PLUS: // + return Tree.VisageKind.PLUS; case MINUS: // - return Tree.VisageKind.MINUS; // Relational operators case LT: // < return Tree.VisageKind.LESS_THAN; case GT: // > return Tree.VisageKind.GREATER_THAN; case LE: // <= return Tree.VisageKind.LESS_THAN_EQUAL; case GE: // >= return Tree.VisageKind.GREATER_THAN_EQUAL; // Equality operators case EQ: // == return Tree.VisageKind.EQUAL_TO; case NE: // != return Tree.VisageKind.NOT_EQUAL_TO; // Conditional operators case AND: // && return Tree.VisageKind.CONDITIONAL_AND; case OR: // || return Tree.VisageKind.CONDITIONAL_OR; // Assignment operators case MUL_ASG: // *= return Tree.VisageKind.MULTIPLY_ASSIGNMENT; case DIV_ASG: // /= return Tree.VisageKind.DIVIDE_ASSIGNMENT; case PLUS_ASG: // += return Tree.VisageKind.PLUS_ASSIGNMENT; case MINUS_ASG: // -= return Tree.VisageKind.MINUS_ASSIGNMENT; // Null check (implementation detail), for example, __.getClass() case NULLCHK: return Tree.VisageKind.OTHER; // Visage tags which are used in javac trees case SIZEOF: return Tree.VisageKind.OTHER; case REVERSE: return Tree.VisageKind.OTHER; default: return null; } } public static void setSymbol(VisageTree tree, Symbol sym) { tree = skipParens(tree); switch (tree.getVisageTag()) { case IDENT: ((VisageIdent) tree).sym = sym; break; case SELECT: ((VisageSelect) tree).sym = sym; break; } } /** If this tree is an identifier or a field, return its symbol, * otherwise return null. */ public static Symbol symbol(VisageTree tree) { tree = skipParens(tree); switch (tree.getVisageTag()) { case IDENT: return ((VisageIdent) tree).sym; case SELECT: return ((VisageSelect) tree).sym; case SEQUENCE_INDEXED: return symbol(((VisageSequenceIndexed) tree).getSequence()); case SEQUENCE_SLICE: return symbol(((VisageSequenceSlice) tree).getSequence()); case VAR_REF: return ((VisageVarRef)tree).getVarSymbol(); default: return null; } } /** Skip parens and return the enclosed expression */ public static VisageTree skipParens(VisageTree tree) { if (tree == null) return tree; if (tree.getVisageTag() == VisageTag.PARENS) return skipParens(((VisageParens)tree).expr); else return tree; } /** If this tree is a qualified identifier, its return fully qualified name, * otherwise return null. */ public static Name fullName(VisageTree tree) { // Protect against a missing tree // if (tree == null) return null; tree = skipParens(tree); switch (tree.getVisageTag()) { case IDENT: return ((VisageIdent) tree).getName(); case SELECT: Name sname = fullName(((VisageSelect) tree).selected); return sname == null ? null : sname.append('.', name(tree)); default: return null; } } /** If this tree is an identifier or a field or a parameterized type, * return its name, otherwise return null. */ public static Name name(VisageTree tree) { switch (tree.getVisageTag()) { case IDENT: return ((VisageIdent) tree).getName(); case SELECT: return ((VisageSelect) tree).name; default: return null; } } public static Symbol symbolFor(VisageTree node) { if (node == null) { return null; } node = skipParens(node); switch (node.getVisageTag()) { case VAR_DEF: return ((VisageVar) node).sym; case VAR_SCRIPT_INIT: return ((VisageVarInit) node).getSymbol(); case CLASS_DEF: return ((VisageClassDeclaration) node).sym; case FUNCTION_DEF: return ((VisageFunctionDefinition) node).sym; case FUNCTIONEXPRESSION: return symbolFor(((VisageFunctionValue) node).definition); case OBJECT_LITERAL_PART: return ((VisageObjectLiteralPart) node).sym; case TYPECLASS: return symbolFor(((VisageTypeClass) node).getTypeExpression()); case IDENT: return ((VisageIdent) node).sym; case INDEXOF: VisageForExpressionInClause clause = ((VisageIndexof) node).clause; return clause == null ? null : clause.var.sym; case SELECT: return ((VisageSelect) node).sym; case APPLY: return symbolFor(((VisageFunctionInvocation) node).meth); case TOPLEVEL: return ((VisageScript) node).packge; case ON_REPLACE: return symbolFor(((VisageOnReplace) node).getOldValue()); case OVERRIDE_ATTRIBUTE_DEF: return symbolFor(((VisageOverrideClassVar) node).getId()); case INIT_DEF: return ((VisageInitDefinition) node).sym; case POSTINIT_DEF: return ((VisagePostInitDefinition) node).sym; default: return null; } } /** Get the start position for a tree node. The start position is * defined to be the position of the first character of the first * token of the node's source text. * @param tree The tree node */ public static int getStartPos(VisageTree tree) { if (tree == null) { return Position.NOPOS; } switch (tree.getVisageTag()) { case APPLY: return getStartPos(((VisageFunctionInvocation) tree).meth); case ASSIGN: return getStartPos(((VisageAssign) tree).lhs); case PLUS_ASG: case MINUS_ASG: case MUL_ASG: case DIV_ASG: return getStartPos(((VisageAssignOp) tree).lhs); case OR: case AND: case EQ: case NE: case LT: case GT: case LE: case GE: case PLUS: case MINUS: case MUL: case DIV: case MOD: return getStartPos(((VisageBinary) tree).lhs); case SELECT: return getStartPos(((VisageSelect) tree).selected); case TYPETEST: return getStartPos(((VisageInstanceOf) tree).expr); case POSTINC: case POSTDEC: return getStartPos(((VisageUnary) tree).arg); case ERRONEOUS: // Erroneous nodes are created with the correct start // position in the source as their pos position, so we do // not need to interrogate the list. // return tree.pos; default: return tree.pos; } } /** The end position of given tree, if it is a block with * defined endpos. */ public static int endPos(VisageTree tree) { if (tree.getVisageTag() == VisageTag.BLOCK_EXPRESSION && ((VisageBlock) tree).endpos != Position.NOPOS) return ((VisageBlock) tree).endpos; else if (tree.getVisageTag() == VisageTag.TRY) { VisageTry t = (VisageTry) tree; return endPos((t.finalizer != null) ? t.finalizer : t.catchers.last().body); } else return tree.pos; } /** The end position of given tree, given a table of end positions generated by the parser */ public static int getEndPos(VisageTree tree, Map<JCTree, Integer> endPositions) { if (tree == null) return Position.NOPOS; if (endPositions == null) { // fall back on limited info in the tree return tree instanceof VisageBlock ? ((VisageBlock)tree).endpos : VisageTreeInfo.endPos(tree); } Integer mapPos = endPositions.get(tree); if (mapPos != null) return mapPos; switch(tree.getVisageTag()) { case INIT_DEF: return getEndPos((VisageTree) ((VisageInitDefinition) tree).getBody(), endPositions); case POSTINIT_DEF: return getEndPos((VisageTree) ((VisagePostInitDefinition) tree).getBody(), endPositions); case OVERRIDE_ATTRIBUTE_DEF: { VisageOverrideClassVar t = (VisageOverrideClassVar)tree; if (t.getOnReplace() != null) return getEndPos(t.getOnReplace(), endPositions); return getEndPos(t.getInitializer(), endPositions); } case ON_REPLACE: return getEndPos(((VisageOnReplace) tree).getBody(), endPositions); case OBJECT_LITERAL_PART: return getEndPos(((VisageObjectLiteralPart) tree).getExpression(), endPositions); case STRING_EXPRESSION: return tree.pos + ((VisageStringExpression) tree).translationKey.length(); case FOR_EXPRESSION: return getEndPos(((VisageForExpression) tree).getBodyExpression(), endPositions); case FOR_EXPRESSION_IN_CLAUSE: return getEndPos(((VisageForExpressionInClause) tree).getWhereExpression(), endPositions); case TYPECLASS: return getEndPos(((VisageTypeClass) tree).getClassName(), endPositions); case TIME_LITERAL: return tree.pos + tree.toString().length(); } return VisageTreeInfo.getStartPos(tree); } }