/* * This file is part of the X10 project (http://x10-lang.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.opensource.org/licenses/eclipse-1.0.php * * This file was originally derived from the Polyglot extensible compiler framework. * * (C) Copyright 2000-2007 Polyglot project group, Cornell University * (C) Copyright IBM Corporation 2007-2012. */ package polyglot.types; import java.util.*; import polyglot.frontend.ExtensionInfo; import polyglot.main.Reporter; import polyglot.util.*; import x10.util.CollectionFactory; /** * The <code>SystemResolver</code> is the main resolver for * fully-qualified names. */ public class SystemResolver extends CachingResolver implements TopLevelResolver { protected Map<QName,Boolean> packageCache; protected ExtensionInfo extInfo; /** * Create a caching resolver. * @param inner The resolver whose results this resolver caches. */ public SystemResolver(TopLevelResolver inner, ExtensionInfo extInfo) { super(inner, extInfo.getOptions().reporter); this.extInfo = extInfo; this.packageCache = CollectionFactory.newHashMap(); } /* public Object copy() { SystemResolver r = (SystemResolver) super.copy(); // todo: the inner resolver is not deep cloned. so I removed this copy method. If it is needed, then Resolver should extend Copy and we should implement copy for all Resolvers. r.packageCache = CollectionFactory.newHashMap(this.packageCache); return r; } */ public void installInAll(QName name, Type n) { this.install(name, n); } public boolean installedInAll(QName name, Type q) { if (check(name) != q) { return false; } return true; } /** Check if a package exists in the resolver cache. */ protected boolean packageExistsInCache(QName name) { for (Type n : cachedTypes()) { if (n instanceof Importable) { Importable im = (Importable) n; if (im.package_() != null && im.package_().fullName() != null && (im.package_().fullName().equals(name) || im.package_().fullName().startsWith(name))) { return true; } } } return false; } /** * Check if a package exists. */ @Override public boolean packageExists(QName name) { Boolean b = packageCache.get(name); if (b != null) { return b.booleanValue(); } else { QName prefix = name.qualifier(); if (prefix != null && packageCache.get(prefix) == Boolean.FALSE) { packageCache.put(name, Boolean.FALSE); return false; } boolean exists; exists = packageExistsInCache(name); if (! exists) { exists = ((TopLevelResolver) inner).packageExists(name); } if (exists) { packageCache.put(name, Boolean.TRUE); while (prefix != null) { packageCache.put(prefix, Boolean.TRUE); prefix = prefix.qualifier(); } } else { packageCache.put(name, Boolean.FALSE); } return exists; } } protected void cachePackage(Package p) { if (p != null) { packageCache.put(QName.make(p.fullName()), Boolean.TRUE); Package prefix = Types.get(p.prefix()); cachePackage(prefix); } } /** * Check if a type is in the cache, returning null if not. * @param name The name to search for. */ public Type checkType(QName name) { return (Type) check(name); } /** * Return the first element in the given list, or null if the list is null or empty. * @param l the given list * @return the first element (if any) */ public static <T> T first(List<T> l) { if (l != null) { for (T n : l) { return n; } } return null; } /** * Find a type by name. For most code, this should be called * with the Java source name (p.A.B), not the class file name (p.A$B). The * exceptions are for resolving names in deserialized types and in types * loaded from raw class files. */ @Override public List<Type> find(QName name) throws SemanticException { List<Type> n = super.find(name); if (reporter.should_report(TOPICS, 2)) reporter.report(2, "Returning from SR.find(" + name + "): " + n); return n; } /** * Find a package by name. For most code, this should be called * with the Java source name (p.A.B), not the class file name (p.A$B). The * exceptions are for resolving names in deserialized types and in types * loaded from raw class files. */ @Override public Package findPackage(QName name) throws SemanticException { Package p = super.findPackage(name); if (reporter.should_report(TOPICS, 2)) reporter.report(2, "Returning from SR.findPackage(" + name + "): " + p); return p; } @Override public void install(QName name, Type q) { if (reporter.should_report(TOPICS, 2) && check(name) == null) reporter.report(2, "SR installing " + name + "->" + q); super.install(name, q); } /** * Install a qualifier in the cache. * @param name The name of the qualifier to insert. * @param q The qualifier to insert. */ @Override public void addNamed(QName name, Type q) throws SemanticException { super.addNamed(name, q); if (q instanceof ClassType) { ClassType ct = (ClassType) q; QName containerName = name.qualifier(); if (containerName != null) { if (ct.isTopLevel()) { Package p = ((ClassType) q).package_(); cachePackage(p); if (p != null && containerName.equals(p.fullName())) { addPackage(containerName, p); } } else if (ct.isMember()) { if (name.equals(ct.fullName())) { // Check that the names match; we could be installing // a member class under its class file name, not its Java // source full name. addNamed(containerName, ct.outer()); } } } } else if (q instanceof Package) { Package p = (Package) q; cachePackage(p); QName containerName = name.qualifier(); Package prefix = Types.get(p.prefix()); if (prefix != null && containerName.equals(prefix.fullName())) { addPackage(containerName, prefix); } } if (false && q instanceof Type && packageExists(QName.make(null,name.name()))) { throw new SemanticException("Type \"" + name.name() +"\" clashes with package of the same name.", q.position()); // todo: see XTENLANG-2289 } } private static final Collection<String> TOPICS = CollectionUtil.list(Reporter.types, Reporter.resolver, Reporter.sysresolver); }