/* ____ ____ ____ ____ ______ *\ ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** ** /_____/\____/\___/\____/____/ ** ** ** ** $Id$ \* */ package scalac.ast; import scalac.ApplicationError; import scalac.util.Name; import scalac.util.Names; import scalac.symtab.Type; import scalac.symtab.Symbol; import scalac.symtab.Modifiers; import java.util.LinkedList; public class TreeInfo { public static boolean isTerm(Tree tree) { return tree.isTerm(); } public static boolean isType(Tree tree) { return tree.isType(); } public static boolean isOwnerDefinition(Tree tree) { switch (tree) { case PackageDef(_, _): case ClassDef(_, _, _, _, _, _): case ModuleDef(_, _, _, _): case DefDef(_, _, _, _, _, _): case Import(_, _): return true; default: return false; } } public static boolean isDefinition(Tree tree) { switch (tree) { case PackageDef(_, _): case ClassDef(_, _, _, _, _, _): case ModuleDef(_, _, _, _): case DefDef(_, _, _, _, _, _): case ValDef(_, _, _, _): case AbsTypeDef(_, _, _, _): case AliasTypeDef(_, _, _, _): case Import(_, _): return true; default: return false; } } public static boolean isDeclaration(Tree tree) { switch (tree) { case DefDef(_, _, _, _, _, Tree rhs): return rhs == Tree.Empty; case ValDef(_, _, _, Tree rhs): return rhs == Tree.Empty; case AbsTypeDef(_, _, _, _): case AliasTypeDef(_, _, _, _): return true; default: return false; } } /** Is tree a pure definition? */ public static boolean isPureDef(Tree tree) { switch (tree) { case Tree.Empty: case ClassDef(_, _, _, _, _, _): case ModuleDef(_, _, _, _): case AbsTypeDef(_, _, _, _): case AliasTypeDef(_, _, _, _): case Import(_, _): return true; case DefDef(_, Name name, _, _, _, _): return name != Names.CONSTRUCTOR; case ValDef(int mods, _, _, Tree rhs): return (mods & Modifiers.MUTABLE) == 0 && isPureExpr(rhs); case DocDef(_, Tree definition): return isPureDef(definition); default: return false; } } /** Is tree a stable & pure expression? */ public static boolean isPureExpr(Tree tree) { switch (tree) { case Empty: case This(_): case Super(_, _): return true; case Ident(_): assert tree.type != null : tree.toString(); return tree.symbol().isStable(); case Select(Tree qual, _): return tree.symbol().isStable() && isPureExpr(qual); case Apply(Tree fn, Tree[] args): return isPureExpr(fn) && args.length == 0; case TypeApply(Tree fn, Tree[] targs): return isPureExpr(fn); case Typed(Tree expr, _): return isPureExpr(expr); case Literal(_): return true; default: return false; } } /** Is tree a pure constructor? */ public static boolean isPureConstr(Tree tree) { switch (tree) { case Ident(_): case Select(_, _): return tree.symbol() != null && tree.symbol().isPrimaryConstructor(); case TypeApply(Tree constr, _): return isPureConstr(constr); case Apply(Tree fn, Tree[] args): return args.length == 0 && isPureConstr(fn); default: return false; } } /** Is tree a self constructor call? */ public static boolean isSelfConstrCall(Tree tree) { switch (tree) { case Ident(Name name): return name == Names.CONSTRUCTOR; case TypeApply(Tree constr, _): return isSelfConstrCall(constr); case Apply(Tree constr, _): return isSelfConstrCall(constr); default: return false; } } /** Is tree a variable pattern */ public static boolean isVarPattern(Tree pat) { switch (pat) { case Ident(Name name): return name.isVariable(); default: return false; } } /** Is tree a this node which belongs to `enclClass'? */ public static boolean isSelf(Tree tree, Symbol enclClass) { switch (tree) { case This(_): return tree.symbol() == enclClass; default: return false; } } /** The method symbol of an application node, or Symbol.NONE, if none exists. */ public static Symbol methSymbol(Tree tree) { Tree meth = methPart(tree); if (meth.hasSymbol()) return meth.symbol(); else return Symbol.NONE; } /** The method part of an application node */ public static Tree methPart(Tree tree) { switch (tree) { case Apply(Tree fn, _): return methPart(fn); case TypeApply(Tree fn, _): return methPart(fn); case AppliedType(Tree fn, _): return methPart(fn); default: return tree; } } /** The symbol with name `name' imported from import clause `tree'. */ public static Symbol importedSymbol(Tree tree, Name name) { switch (tree) { case Import(Tree expr, Name[] selectors): Type pre = tree.symbol().type(); if (pre != Type.ErrorType) { boolean renamed = false; for (int i = 0; i < selectors.length; i = i + 2) { if (i + 1 < selectors.length && name.toTermName() == selectors[i + 1]) { if (name.isTypeName()) return pre.lookupNonPrivate(selectors[i].toTypeName()); else return pre.lookupNonPrivate(selectors[i]); } else if (name.toTermName() == selectors[i]) { renamed = true; } else if (selectors[i] == Names.IMPORT_WILDCARD && !renamed) { return pre.lookupNonPrivate(name); } } } return Symbol.NONE; default: throw new ApplicationError(); } } /** returns true if the tree is a sequence-valued pattern. * precondition: tree is a pattern. * calls isSequenceValued( Tree, List ) because needs to remember bound * values. */ public static boolean isSequenceValued( Tree tree ) { return isSequenceValued( tree, new LinkedList() ); } /** returns true if the tree is a sequence-valued pattern. * precondition: tree is a pattern */ public static boolean isSequenceValued( Tree tree, LinkedList recVars ) { switch( tree ) { case Bind(_, Tree t): recVars.addFirst( tree.symbol() ); boolean res = isSequenceValued( t ); recVars.removeFirst(); return res; case Sequence(_): return true; case Alternative(Tree[] ts): for( int i = 0; i < ts.length; i++ ) { if( isSequenceValued( ts[ i ] ) ) return true; } return false; case Ident(Name n): // if Ident is a recursive var, then true return recVars.contains( tree.symbol() ); case Apply( _, _ ): case Literal( _ ): case Select(_,_): case Typed(_,_): return false; default: throw new scalac.ApplicationError("Unexpected pattern "+tree.getClass()); } } /** returns true if the argument is an empty sequence pattern */ public static boolean isEmptySequence( Tree tree ) { switch( tree ) { case Sequence( Tree ts[] ): return ( ts.length == 0 ); default: return false; } } /** this test should correspond to the one used in TransMatch phase */ public static boolean isRegularPattern( Tree tree ) { switch (tree) { case Alternative(_): return true; case Bind(_, Tree pat): return isRegularPattern( pat ); case Ident(_): return false; case CaseDef(Tree pat, _, _): isRegularPattern(pat); break; case Sequence( Tree[] trees): return true; case Apply( _, Tree[] trees ): for( int i = 0; i < trees.length; i++ ) if( isRegularPattern( trees[i] ) ) return true; case Literal( _ ): return false; } return false; } /** @todo replace with cleaner test (e.g. of a symbol flag) */ public static boolean isNameOfStarPattern( Name n ) { String s = n.toString(); return (s.indexOf("$") != -1) &&(!s.startsWith("nest")); } }