/* * 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.api; import org.visage.api.*; import org.visage.api.tree.*; import java.io.IOException; import java.util.Map; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; import javax.tools.JavaFileObject; import com.sun.tools.mjavac.code.Kinds; import com.sun.tools.mjavac.code.Symbol.ClassSymbol; import com.sun.tools.mjavac.code.Symbol.TypeSymbol; import com.sun.tools.mjavac.code.Symbol; import com.sun.tools.mjavac.code.Symbol.PackageSymbol; import com.sun.tools.mjavac.tree.JCTree; import com.sun.tools.mjavac.util.Context; import com.sun.tools.mjavac.util.List; import com.sun.tools.mjavac.util.Log; import com.sun.tools.mjavac.util.Pair; import org.visage.tools.comp.VisageAttr; import org.visage.tools.comp.VisageAttrContext; import org.visage.tools.comp.VisageEnter; import org.visage.tools.comp.VisageEnv; import org.visage.tools.comp.VisageMemberEnter; import org.visage.tools.comp.VisageResolve; import org.visage.tools.tree.*; /** * Provides an implementation of Trees for the Visage compiler, based * on JavacTrees. * * @author Peter von der Ahé * @author Tom Ball */ public class VisagecTrees { private final VisageResolve resolve; private final VisageEnter enter; private final Log log; private final VisageMemberEnter memberEnter; private final VisageAttr attr; private final VisageTreeMaker visagemake; private final VisagecTaskImpl visagecTaskImpl; private final Context ctx; public static VisagecTrees instance(VisageCompiler.CompilationTask task) { if (!(task instanceof VisagecTaskImpl)) throw new IllegalArgumentException(); return instance(((VisagecTaskImpl)task).getContext()); } public static VisagecTrees instance(Context context) { VisagecTrees instance = context.get(VisagecTrees.class); if (instance == null) instance = new VisagecTrees(context); return instance; } private VisagecTrees(Context context) { context.put(VisagecTrees.class, this); ctx = context; attr = VisageAttr.instance(context); enter = VisageEnter.instance(context); log = Log.instance(context); resolve = VisageResolve.instance(context); visagemake = VisageTreeMaker.instance(context); memberEnter = VisageMemberEnter.instance(context); visagecTaskImpl = context.get(VisagecTaskImpl.class); } public SourcePositions getSourcePositions() { return new SourcePositions() { public long getStartPosition(UnitTree file, Tree tree) { return VisageTreeInfo.getStartPos((VisageTree) tree); } public long getEndPosition(UnitTree file, Tree tree) { Map<JCTree,Integer> endPositions = ((VisageScript) file).endPositions; return VisageTreeInfo.getEndPos((VisageTree)tree, endPositions); } }; } public ClassDeclarationTree getTree(TypeElement element) { return (ClassDeclarationTree) getTree((Element) element); } public FunctionDefinitionTree getTree(ExecutableElement method) { return (FunctionDefinitionTree) getTree((Element) method); } public Tree getTree(Element element) { Symbol symbol = (Symbol) element; TypeSymbol enclosing = symbol.enclClass(); VisageEnv<VisageAttrContext> env = enter.getEnv(enclosing); if (env == null) return null; VisageClassDeclaration classNode = env.enclClass; if (classNode != null) { if (VisageTreeInfo.symbolFor(classNode) == element) return classNode; for (VisageTree node : classNode.getMembers()) if (VisageTreeInfo.symbolFor(node) == element) return node; } return null; } public VisageTreePath getPath(UnitTree unit, Tree node) { return getPath(new VisageTreePath(unit), node); } public VisageTreePath getPath(Element e) { final Pair<VisageTree, VisageScript> treeTopLevel = getTreeAndTopLevel(e); if (treeTopLevel == null) return null; return getPath(treeTopLevel.snd, treeTopLevel.fst); } /** * Gets a tree path for a tree node within a subtree identified by a VisageTreePath object. * @return null if the node is not found */ public static VisageTreePath getPath(VisageTreePath path, Tree target) { path.getClass(); target.getClass(); class Result extends Error { static final long serialVersionUID = -5942088234594905625L; VisageTreePath path; Result(VisageTreePath path) { this.path = path; } } class PathFinder extends VisageTreePathScanner<VisageTreePath,Tree> { @Override public VisageTreePath scan(Tree tree, Tree target) { if (tree == target) throw new Result(new VisageTreePath(getCurrentPath(), target)); return super.scan(tree, target); } } try { new PathFinder().scan(path, target); } catch (Result result) { return result.path; } return null; } public Element getElement(VisageTreePath path) { Tree t = path.getLeaf(); return VisageTreeInfo.symbolFor((VisageTree) t); } public TypeMirror getTypeMirror(VisageTreePath path) { Tree t = path.getLeaf(); return ((VisageTree)t).type; } public VisagecScope getScope(VisageTreePath path) { return new VisagecScope(ctx, getAttrContext(path)); } public boolean isAccessible(Scope scope, TypeElement type) { if (scope instanceof VisagecScope && type instanceof ClassSymbol) { VisageEnv<VisageAttrContext> env = ((VisagecScope) scope).env; return resolve.isAccessible(env, (ClassSymbol)type); } else return false; } public boolean isAccessible(Scope scope, Element member, DeclaredType type) { if (scope instanceof VisagecScope && member instanceof Symbol && type instanceof com.sun.tools.mjavac.code.Type) { VisageEnv<VisageAttrContext> env = ((VisagecScope) scope).env; return resolve.isAccessible(env, (com.sun.tools.mjavac.code.Type)type, (Symbol)member); } else return false; } private VisageEnv<VisageAttrContext> getAttrContext(VisageTreePath path) { if (!(path.getLeaf() instanceof VisageTree)) // implicit null-check throw new IllegalArgumentException(); // if we're being invoked via from a JSR199 client, we need to make sure // all the classes have been entered; if we're being invoked from JSR269, // then the classes will already have been entered. if (visagecTaskImpl != null) { try { visagecTaskImpl.enter(); } catch (IOException e) { throw new Error("unexpected error while entering symbols: " + e); } } VisageScript unit = (VisageScript) path.getCompilationUnit(); Copier copier = new Copier(visagemake.forToplevel(unit)); copier.endPositions = unit.endPositions; VisageEnv<VisageAttrContext> env = null; VisageFunctionDefinition function = null; VisageVar field = null; List<Tree> l = List.nil(); VisageTreePath p = path; while (p != null) { l = l.prepend(p.getLeaf()); p = p.getParentPath(); } for ( ; l.nonEmpty(); l = l.tail) { Tree tree = l.head; if (tree instanceof VisageScript) { env = enter.getTopLevelEnv((VisageScript)tree); } else if (tree instanceof VisageClassDeclaration) { env = enter.getClassEnv(((VisageClassDeclaration)tree).sym); } else if (tree instanceof VisageFunctionDefinition) { function = (VisageFunctionDefinition)tree; } else if (tree instanceof VisageVar) { field = (VisageVar)tree; } else if (tree instanceof VisageBlock) { if (function != null) env = memberEnter.getMethodEnv(function, env); VisageTree body = copier.copy((VisageTree)tree, (VisageTree) path.getLeaf()); env = attribStatToTree(body, env, copier.leafCopy); return env; } else if (field != null && field.getInitializer() == tree) { env = memberEnter.getInitEnv(field, env); VisageExpression expr = copier.copy((VisageExpression)tree, (VisageTree) path.getLeaf()); env = attribExprToTree(expr, env, copier.leafCopy); return env; } } return field != null ? memberEnter.getInitEnv(field, env) : env; } private VisageEnv<VisageAttrContext> attribStatToTree(VisageTree stat, VisageEnv<VisageAttrContext>env, VisageTree tree) { JavaFileObject prev = log.useSource(env.toplevel.sourcefile); try { return attr.attribStatToTree(stat, env, tree); } finally { log.useSource(prev); } } private VisageEnv<VisageAttrContext> attribExprToTree(VisageExpression expr, VisageEnv<VisageAttrContext>env, VisageTree tree) { JavaFileObject prev = log.useSource(env.toplevel.sourcefile); try { return attr.attribExprToTree(expr, env, tree); } finally { log.useSource(prev); } } private Pair<VisageTree, VisageScript> getTreeAndTopLevel(Element e) { if (e == null) return null; Symbol sym = (Symbol)e; TypeSymbol ts = (sym.kind != Kinds.PCK) ? sym.enclClass() : (PackageSymbol) sym; VisageEnv<VisageAttrContext> enterEnv = ts != null ? enter.getEnv(ts) : null; if (enterEnv == null) return null; VisageTree tree = VisageTreeInfo.declarationFor(sym, enterEnv.tree); if (tree == null || enterEnv.toplevel == null) return null; return new Pair<VisageTree,VisageScript>(tree, enterEnv.toplevel); } public VisageEnv<VisageAttrContext> getFunctionEnv(VisageFunctionDefinition tree, VisageEnv<VisageAttrContext> env) { VisageEnv<VisageAttrContext> mEnv = memberEnter.methodEnv(tree, env); mEnv.info.lint = mEnv.info.lint.augment(tree.sym.attributes_field, tree.sym.flags()); for (List<VisageVar> l = tree.getParams(); l.nonEmpty(); l = l.tail) mEnv.info.scope.enterIfAbsent(l.head.sym); return mEnv; } public VisageEnv<VisageAttrContext> getInitEnv(VisageVar tree, VisageEnv<VisageAttrContext> env) { VisageEnv<VisageAttrContext> iEnv = memberEnter.initEnv(tree, env); return iEnv; } /** * Makes a copy of a tree, noting the value resulting from copying a particular leaf. **/ static class Copier extends VisageTreeCopier { VisageTree leaf; VisageTree leafCopy = null; Copier(VisageTreeMaker M) { super(M); } public <T extends VisageTree> T copy(T t, VisageTree leaf) { this.leaf = leaf; return copy(t); } @Override public <T extends VisageTree> T copy(T t) { T t2 = super.copy(t); if (t == leaf) leafCopy = t2; return t2; } @Override public void visitForExpressionInClause(VisageForExpressionInClause tree) { result = maker.InClause(copy(tree.var), copy(tree.getSequenceExpression()), copy(tree.getWhereExpression())); } } }