/* * * 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.apache.flex.compiler.internal.projects; import java.io.File; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.flex.compiler.common.DependencyType; import org.apache.flex.compiler.common.DependencyTypeSet; import org.apache.flex.compiler.common.Multiname; import org.apache.flex.compiler.constants.IASLanguageConstants; import org.apache.flex.compiler.constants.IASLanguageConstants.BuiltinType; import org.apache.flex.compiler.definitions.IDefinition; import org.apache.flex.compiler.definitions.IFunctionDefinition; import org.apache.flex.compiler.definitions.INamespaceDefinition; import org.apache.flex.compiler.definitions.ITypeDefinition; import org.apache.flex.compiler.internal.definitions.ClassDefinition; import org.apache.flex.compiler.internal.definitions.FunctionDefinition; import org.apache.flex.compiler.internal.definitions.NamespaceDefinition; import org.apache.flex.compiler.internal.embedding.EmbedData; import org.apache.flex.compiler.internal.parsing.as.IProjectConfigVariables; import org.apache.flex.compiler.internal.scopes.ASProjectScope; import org.apache.flex.compiler.internal.scopes.ASScope; import org.apache.flex.compiler.internal.scopes.ASScopeCache; import org.apache.flex.compiler.internal.targets.AppSWFTarget; import org.apache.flex.compiler.internal.targets.Target; import org.apache.flex.compiler.internal.units.EmbedCompilationUnit; import org.apache.flex.compiler.internal.workspaces.Workspace; import org.apache.flex.compiler.problems.ICompilerProblem; import org.apache.flex.compiler.problems.MissingBuiltinProblem; import org.apache.flex.compiler.projects.ICompilerProject; import org.apache.flex.compiler.scopes.IASScope; import org.apache.flex.compiler.targets.ISWFTarget; import org.apache.flex.compiler.targets.ITargetProgressMonitor; import org.apache.flex.compiler.targets.ITargetSettings; import org.apache.flex.compiler.tree.as.IASNode; import org.apache.flex.compiler.units.ICompilationUnit; import org.apache.flex.compiler.units.requests.IFileScopeRequestResult; import org.apache.flex.compiler.units.requests.IRequest; import org.apache.flex.utils.FilenameNormalization; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; /** * Abstract class used to share implementation of some ICompilerProject methods * across multiple concrete implementation classes. */ public abstract class CompilerProject implements ICompilerProject { private final ASProjectScope projectScope; private final Workspace workspace; protected Set<Target> targets; private final ReadWriteLock unfoundDependenciesLock; private final Map<String, Map<ICompilationUnit, Object>> unfoundDefinitionDependencies; protected Collection<ICompilerProblem> problems; /** * These are files that compilation units have tried to find and failed. At the moment these are * Embedded files and included files. Should these files be added to the Builder workspace, the project * will be notified and can in turn re-compiler the units that are missing these files */ private final Map<String, Map<ICompilationUnit, Object>> unfoundReferencedSourceFileDependencies; private final Map<EmbedData, EmbedCompilationUnit> embedCompilationUnits; /** * Helper class to create new Scope Caches on the fly, when the scope cache map misses */ static class ScopeCacheLoader extends CacheLoader<ASScope, ASScopeCache> { CompilerProject project; public ScopeCacheLoader(CompilerProject project) { this.project = project; } @Override public ASScopeCache load(ASScope scope) { ASScopeCache cache = new ASScopeCache(project, scope); project.projectScope.addScopeToCompilationUnitScopeList(scope); return cache; } } /** * Map that holds caches for each scope in the project - uses a Concurrent Map, with weak keys so that the caches * will go away once the corresponding scope has been gc'ed. Uses soft values so the caches may be collected * if the VM is running out of memory */ private LoadingCache<ASScope, ASScopeCache> scopeCaches = CacheBuilder.newBuilder() .weakKeys() .softValues() .build(new ScopeCacheLoader(this)); /** This thread local is to avoid every thread contending for access to the scopeCaches map, which is shared * across the entire Project. * When a scope cache is requested, we first check the thread local cache. If the entry is not present in * the thread local, then we hit the shared scopeCaches map. The result from the scopeCaches map is then also * cached in the thread local. This way, most of the time, we'll find the scope cache in the thread local, and * won't have to do any locking. */ private ThreadLocal<Map<ASScope, WeakReference<ASScopeCache>> > threadLocalScopeCache; /** * Dependency graph is used to keep track of which {@link ICompilationUnit} * 's are in this project. The dependency graph is in this shared base class * instead of being in {@link ASProject} because {@link ICompilationUnit} * implementations will want to update the dependency graph and * {@link ICompilationUnit} implementations should be able to behave the * same irrespective of what type of {@link CompilerProject} they are in. */ protected final DependencyGraph dependencyGraph; /** * If true, use parallel code generation of method bodies. */ private boolean useParallelCodeGen; /** * If true, use function inlining in code generation. */ private boolean enableInlining; private final boolean useAS3; /** * used to track config variables and return config information back to clients, such as the parser */ private final ConfigManager configManager; public CompilerProject(Workspace workspace, boolean useAS3) { this.workspace = workspace; targets = new HashSet<Target>(); unfoundDependenciesLock = new ReentrantReadWriteLock(); unfoundDefinitionDependencies = new HashMap<String, Map<ICompilationUnit, Object>>(); unfoundReferencedSourceFileDependencies = new HashMap<String, Map<ICompilationUnit, Object>>(); embedCompilationUnits = new HashMap<EmbedData, EmbedCompilationUnit>(); dependencyGraph = new DependencyGraph(); // ** TODO Instantiate real scope object. projectScope = initProjectScope(this); this.useAS3 = useAS3; initThreadLocalCaches(); configManager = new ConfigManager(); useParallelCodeGen = false; enableInlining = false; workspace.addProject(this); } /** * Init the project scope. Allow subclasses to contribute their own if needed. Default will create a new {@link ASProjectScope} * @param project the project to build the scope from * @return a new {@link ASProjectScope} */ protected ASProjectScope initProjectScope(CompilerProject project) { return new ASProjectScope(project); } /** * Init the thread local cache - will reset the thread local cache to it's initial, empty state. */ private void initThreadLocalCaches() { threadLocalScopeCache = new ThreadLocal<Map<ASScope, WeakReference<ASScopeCache>>>() { @Override protected Map<ASScope, WeakReference<ASScopeCache>> initialValue() { // Use a WeakHashMap with WeakRefs as values - the ASScopes and ASScopeCaches // will be kept alive or not by the Project return new WeakHashMap<ASScope, WeakReference<ASScopeCache>>(); } }; } @Override public ASProjectScope getScope() { return this.projectScope; } @Override public Workspace getWorkspace() { return workspace; } @Override public List<ICompilationUnit> getReachableCompilationUnitsInSWFOrder(Collection<ICompilationUnit> roots) { return dependencyGraph.topologicalSort(roots); } /** * Updates the {@link ASProjectScope} to contain reference to public and * internal definitions in those compilation units. * * @param units {@link ICompilationUnit}'s to add to the project. */ public void updatePublicAndInternalDefinitions(Collection<ICompilationUnit> units) throws InterruptedException { if (units.isEmpty()) return; ArrayList<IRequest<IFileScopeRequestResult, ICompilationUnit>> scopeRequests = new ArrayList<IRequest<IFileScopeRequestResult, ICompilationUnit>>(units.size()); for (ICompilationUnit unit : units) { ICompilerProject unitProject = unit.getProject(); assert (unitProject == this) || (unitProject == null) : "ICompilationUnit should be in this project or not in any project"; if (unitProject == this) scopeRequests.add(unit.getFileScopeRequest()); } scopeCaches.invalidateAll(); initThreadLocalCaches(); projectScope.addAllExternallyVisibleDefinitions(scopeRequests); } /** * Adds compilation units to the project and updates the public and private * definitions. Eventually this method should be removed, but it is * convenient for testing because it allows custom created * {@link ICompilationUnit}'s to be injected into a project. * * @param compilationUnits A collection of compilation units. */ public void addCompilationUnitsAndUpdateDefinitions(Collection<ICompilationUnit> compilationUnits) throws InterruptedException { addCompilationUnits(compilationUnits); updatePublicAndInternalDefinitions(compilationUnits); } public void addEmbedCompilationUnit(EmbedCompilationUnit unit) throws InterruptedException { dependencyGraph.addEmbedCompilationUnit(unit); workspace.addCompilationUnit(unit); embedCompilationUnits.put(unit.getEmbedData(), unit); updatePublicAndInternalDefinitions(Collections.<ICompilationUnit>singletonList(unit)); } /** * Add a {@link ICompilationUnit} to the project. Calling this method does not * trigger the {@link ICompilationUnit} to be compiled. * * @param unit {@link ICompilationUnit} to add */ public void addCompilationUnit(ICompilationUnit unit) { assert !(unit instanceof EmbedCompilationUnit) : "Embed compilation unit should be added with addEmbedCompilationUnit!"; dependencyGraph.addCompilationUnit(unit); workspace.addCompilationUnit(unit); } /** * Add compilation units to the project. Calling this method does not * trigger the compilation units to be compiled. * * @param units compilation units */ public void addCompilationUnits(Collection<ICompilationUnit> units) { for (ICompilationUnit compilationUnit : units) { addCompilationUnit(compilationUnit); } } /** * Removes a {@link ICompilationUnit} from the project. * @param unit {@link ICompilationUnit} to remove. */ public void removeCompilationUnit(ICompilationUnit unit) { dependencyGraph.removeCompilationUnit(unit); workspace.removeCompilationUnit(unit); unit.clearProject(); if (unit instanceof EmbedCompilationUnit) { EmbedData embedData = ((EmbedCompilationUnit)unit).getEmbedData(); embedCompilationUnits.remove(embedData); } } /** * Don't call this from production code. Normally library managers take care of this. * This function is only for unit tests. */ public void unitTestingEntryPointForRemovingCompilationUnit(ICompilationUnit unit) { removeCompilationUnits( Collections.singleton(unit) ); } /** * Removes a set of {@link ICompilationUnit}'s from the project. * @param unitsToRemove {@link ICompilationUnit}'s to remove. */ public void removeCompilationUnits(Collection<ICompilationUnit> unitsToRemove) { if ((unitsToRemove == null) || (unitsToRemove.size() == 0)) return; // TODO pre-remove invalidation // Factor this into a method and un-comment at some point! // Set<ICompilationUnit> workSet = new HashSet<ICompilationUnit>(unitsToRemove); // Set<ICompilationUnit> visited = new HashSet<ICompilationUnit>(unitsToRemove.size()); // EnumSet<DependencyGraph.DependencyType> inheritanceTypeSet = // EnumSet.of(DependencyGraph.DependencyType.INHERITANCE); // while (workSet.size() >= 0) // { // ICompilationUnit unit = workSet.iterator().next(); // workSet.remove(unit); // if (!visited.contains(unit)) // { // visited.add(unit); // unit.invalidate(DependencyGraph.DependencyType.INHERITANCE); // workSet.addAll(dependencyGraph.getDirectReverseDependencies(unit, inheritanceTypeSet)); // } // } // TODO add code behind the invalidate all above or here to // invalidation name resolution caches. // unhook all the compilation units to remove from the project scope. projectScope.removeCompilationUnits(unitsToRemove); for (ICompilationUnit unit : unitsToRemove) { removeCompilationUnit(unit); } } @Override public Collection<ICompilationUnit> getCompilationUnits() { return dependencyGraph.getCompilationUnits(); } @Override public Collection<ICompilationUnit> getCompilationUnits(String filename) { return workspace.getCompilationUnits(FilenameNormalization.normalize(filename), this); } @Override public Collection<ICompilationUnit> getIncludingCompilationUnits(String filename) { return workspace.getIncludingCompilationUnits(FilenameNormalization.normalize(filename), this); } public void addUnfoundDefinitionDependency(String definitionBaseName, ICompilationUnit compilationUnit) { unfoundDependenciesLock.writeLock().lock(); try { Map<ICompilationUnit, Object> dependentUnits = unfoundDefinitionDependencies.get(definitionBaseName); if (dependentUnits == null) { dependentUnits = new WeakHashMap<ICompilationUnit, Object>(); unfoundDefinitionDependencies.put(definitionBaseName, dependentUnits); } dependentUnits.put(compilationUnit, null); } finally { unfoundDependenciesLock.writeLock().unlock(); } } public Set<ICompilationUnit> getDependenciesOnUnfoundDefinition(String definitionBaseName) { unfoundDependenciesLock.readLock().lock(); try { Map<ICompilationUnit, Object> dependentUnits = unfoundDefinitionDependencies.get(definitionBaseName); if (dependentUnits == null) { dependentUnits = Collections.emptyMap(); } return dependentUnits.keySet(); } finally { unfoundDependenciesLock.readLock().unlock(); } } private void removeAnyUnfoundDefinitionDependency(ICompilationUnit compilationUnit) { for (Map<ICompilationUnit, Object> dependentUnits : unfoundDefinitionDependencies.values()) { dependentUnits.remove(compilationUnit); } } /** * Notify project that a compilation unit could not find a referenced file. * * "Referenced" here means that the compilation unit references the file in some way other than the normal * language level manner. For example, embedded and included files are "referenced", whereas files that * defined referenced types are not. * * Calling this function will allow incremental re-compiation to be kicked off when/if the required * file comes into existence. * * @param sourceFilename The full path to the required file * @param compilationUnit The compilation unit that requires the referenced file */ public void addUnfoundReferencedSourceFileDependency(String sourceFilename, ICompilationUnit compilationUnit) { unfoundDependenciesLock.writeLock().lock(); try { String filenameNoPath = new File(sourceFilename).getName(); Map<ICompilationUnit, Object> dependentUnits = unfoundReferencedSourceFileDependencies.get(filenameNoPath); if (dependentUnits == null) { dependentUnits = new WeakHashMap<ICompilationUnit, Object>(); unfoundReferencedSourceFileDependencies.put(filenameNoPath, dependentUnits); } dependentUnits.put(compilationUnit, null); } finally { unfoundDependenciesLock.writeLock().unlock(); } } /** * gets the set of all compilation units that have an unsatisfied reference to a given file. * @param sourceFilename The path to the file. */ public Set<ICompilationUnit> getDependenciesOnUnfoundReferencedSourceFile(String sourceFilename) { unfoundDependenciesLock.readLock().lock(); try { String filenameNoPath = new File(sourceFilename).getName(); Map<ICompilationUnit, Object> dependentUnits = unfoundReferencedSourceFileDependencies.get(filenameNoPath); if (dependentUnits == null) { dependentUnits = Collections.emptyMap(); } return dependentUnits.keySet(); } finally { unfoundDependenciesLock.readLock().unlock(); } } private void removeAnyUnfoundReferencedSourceFileDependency(ICompilationUnit compilationUnit) { for (Map<ICompilationUnit, Object> dependentUnits : unfoundReferencedSourceFileDependencies.values()) { dependentUnits.remove(compilationUnit); } } public void removeAnyUnfoundDependencies(ICompilationUnit compilationUnit) { // we could probably get away without locking when a remove is done, as // this is only called from a call to clean() on a compilation unit, and // that should only happen in a single thread. but let's just play it safe // and lock anyway in case someone in future calls this method from somewhere else. unfoundDependenciesLock.writeLock().lock(); try { removeAnyUnfoundDefinitionDependency(compilationUnit); removeAnyUnfoundReferencedSourceFileDependency(compilationUnit); } finally { unfoundDependenciesLock.writeLock().unlock(); } } public Set<ICompilationUnit> getDependenciesOnDefinition(String definitionBaseName) { Set<ICompilationUnit> dependentUnits = new HashSet<ICompilationUnit>(); Set<ICompilationUnit> definingUnits = projectScope.getCompilationUnitsByDefinitionName(definitionBaseName); DependencyTypeSet dependencyTypes = DependencyTypeSet.allOf(); for (ICompilationUnit definingUnit : definingUnits) { dependentUnits.addAll(dependencyGraph.getDirectReverseDependencies(definingUnit, dependencyTypes)); } return dependentUnits; } @Override public void clean() { Map<ICompilerProject, Set<ICompilationUnit>> cusToUpdate = new HashMap<ICompilerProject, Set<ICompilationUnit>>(); workspace.startIdleState(); try { Collection<ICompilationUnit> compilationUnits = getCompilationUnits(); for (ICompilationUnit compilationUnit : compilationUnits) { compilationUnit.clean(null, cusToUpdate, true); } scopeCaches.invalidateAll(); initThreadLocalCaches(); } finally { workspace.endIdleState(cusToUpdate); } } @Override public void delete() { Collection<ICompilationUnit> compilationUnits = getCompilationUnits(); for (ICompilationUnit compilationUnit : compilationUnits) { workspace.removeCompilationUnit(compilationUnit); } workspace.deleteProject(this); } @Override public ISWFTarget createSWFTarget(ITargetSettings targetSettings, ITargetProgressMonitor progressMonitor) throws InterruptedException { return new AppSWFTarget(this, targetSettings, progressMonitor); } /** * Adds a dependency from one {@link ICompilationUnit} to another * {@link ICompilationUnit}. * * @param from {@link ICompilationUnit} that depends on "to". * @param to {@link ICompilationUnit} that is depended on by "from". * @param dt The types of dependencies to add. * @param qname The qname of the target dependency added */ public void addDependency(ICompilationUnit from, ICompilationUnit to, DependencyTypeSet dt, String qname) { dependencyGraph.addDependency(from, to, dt, qname); } /** * Adds a dependency from one {@link ICompilationUnit} to another * {@link ICompilationUnit}. * * @param from {@link ICompilationUnit} that depends on "to". * @param to {@link ICompilationUnit} that is depended on by "from". * @param dt The type of dependency to add. * @param qname The qname of the target dependency added */ public void addDependency(ICompilationUnit from, ICompilationUnit to, DependencyType dt, String qname) { dependencyGraph.addDependency(from, to, dt, qname); } /** * Adds an anonymous dependency from one {@link ICompilationUnit} to another * {@link ICompilationUnit}. This dependency will not be used in the link report. * * @param from {@link ICompilationUnit} that depends on "to". * @param to {@link ICompilationUnit} that is depended on by "from". * @param dt The type of dependency to add. */ public void addDependency(ICompilationUnit from, ICompilationUnit to, DependencyType dt) { dependencyGraph.addDependency(from, to, dt); } /** * Removes the outgoing dependencies of a collection of {@link ICompilationUnit}. * * @param units {@link ICompilationUnit} to remove dependencies from. */ public void removeDependencies(Collection<ICompilationUnit> units) { for (ICompilationUnit unit : units) dependencyGraph.removeDependencies(unit); } /** * Gets the set of dependencies referenced by the specified * {@link ICompilationUnit}. in the absence of wierd things like * defaults/theme css, this is just the set of {@link ICompilationUnit}'s * that define definitions directly referenced by the specified * {@link ICompilationUnit}. * <p> * This method can be overridden by subclasses to add additional * dependencies that are not in the dependency graph. * * @param cu {@link ICompilationUnit} to retrieve dependencies for. * @return A new Set of {@link ICompilationUnit}'s that the specified * {@link ICompilationUnit} directly depends on. */ public Set<ICompilationUnit> getDependencies(ICompilationUnit cu) throws InterruptedException { // The process of finding semantic problems updates the dependency graph // so wait for semantic analysis pass to finish. // TODO possible revisit how we wait for the dependency graph to be updated // or at least better document it in ICompilationUnit. cu.getOutgoingDependenciesRequest().get(); return dependencyGraph.getDirectDependencies(cu); } /** * Gets project level {@link ICompilerProblem}'s target are not specific to any * one target created by the project. */ public abstract void collectProblems(Collection<ICompilerProblem> problems); /** * Gets the project level {@link ICompilerProblem}'s that come from parsing the * config options, from the command line, or a configuration file * @param problems the Collection to add the config problems to. */ protected void collectConfigProblems(Collection<ICompilerProblem> problems) { problems.addAll(configManager.getProjectConfig(this).getProblems()); } /** * Get the cache for a particular scope * @param scope the scope you want the cache for. * @return the ASScopeCache for the scope */ public ASScopeCache getCacheForScope(ASScope scope) { ASScopeCache scopeCache = null; // First check and see if we have the result cached in the thread local cache Map<ASScope, WeakReference<ASScopeCache>> cache = threadLocalScopeCache.get(); WeakReference<ASScopeCache> ref = cache.get(scope); scopeCache = ref != null ? ref.get() : null; if( scopeCache == null ) { // Didn't find it in the thread local, hit the shared cache, and cache those results // in the thread local so that we won't have to hit the shared cache next time. scopeCache = scopeCaches.getUnchecked(scope); cache.put(scope, new WeakReference<ASScopeCache>(scopeCache)); } return scopeCache; } /** * Clears all the {@link ASScopeCache}s associated with the specified * {@link ICompilationUnit} and removes all the {@link IASScope}s build by * the {@link ICompilationUnit} from the list of scopes associated with the * {@link ICompilationUnit}. This method should only be called when a * {@link ICompilationUnit} is being removed from a project. * * @param compilationUnit {@link ICompilationUnit} whose scope caches should * be cleared and whose scope list should be emptied. */ public void clearScopeCacheForCompilationUnit(ICompilationUnit compilationUnit) { Collection<IASScope> relatedScopes = projectScope.clearCompilationUnitScopeList(compilationUnit); if (relatedScopes == null) return; resetScopeCaches(relatedScopes); } /** * Resets all the {@link ASScopeCache}s associated with the specified * {@link ICompilationUnit}. * * @param compilationUnit {@link ICompilationUnit} whose scope caches should * be cleared */ public void resetScopeCacheForCompilationUnit(ICompilationUnit compilationUnit) { Collection<IASScope> relatedScopes = projectScope.getCompilationUnitScopeList(compilationUnit); assert relatedScopes != null; if (relatedScopes.isEmpty()) return; resetScopeCaches(relatedScopes); } private void resetScopeCaches(Iterable<IASScope> scopes) { assert scopes != null; for (IASScope scope : scopes) { scopeCaches.invalidate(scope); } initThreadLocalCaches(); } public void addGlobalUsedNamespacesToNamespaceSet(Set<INamespaceDefinition> nsSet) { nsSet.add(NamespaceDefinition.getPublicNamespaceDefinition()); if (this.useAS3) nsSet.add(NamespaceDefinition.getAS3NamespaceDefinition()); } /** * Called by * {@link Workspace#fileAdded(org.apache.flex.compiler.filespecs.IFileSpecification)} * for each project in the workspace. Each subclass of this class must * decide when an added file is interesting or should be ignored. * * @param addedFile File that was added. * @return true if any new compilation units were created as a result of * adding the file, false otherwise. */ public abstract boolean handleAddedFile(File addedFile); /** * Return the compilation unit related this EmbedData, or it's equivalent. If * there is no equiv., null will be returned * @param data The embedding data. * @return related EmbedCompilationUnit. Can be null */ public EmbedCompilationUnit getCompilationUnit(EmbedData data) { return embedCompilationUnits.get(data); } public final DependencyGraph getDependencyGraph() { return dependencyGraph; } /** * Sets project config variables for use on this project * @see org.apache.flex.compiler.internal.projects.ConfigManager#addConfigVariables(Map) * @param map the mapping of config names to their expressions */ public void addConfigVariables(Map<String, String> map) { configManager.addConfigVariables(map); // TODO: in future we could be smarter about incrementally invalidating // the project based on what the config variables affect, but for now // just blow away the whole project. clean(); } /** * Sets project config variable for use on this project * @see org.apache.flex.compiler.internal.projects.ConfigManager#addConfigVariables(Map) * @param namespace the config namespace * @param expression the config expression for the namespace */ public void addConfigVariable(String namespace, String expression) { configManager.addConfigVariable(namespace, expression); // TODO: in future we could be smarter about incrementally invalidating // the project based on what the config variables affect, but for now // just blow away the whole project. clean(); } /** * Returns an {@link IProjectConfigVariables} struct that contains all the config data for this project * @return an {@link IProjectConfigVariables} object, never null */ public IProjectConfigVariables getProjectConfigVariables() { return configManager.getProjectConfig(this); } @Override public IDefinition resolveQNameToDefinition(final String qName) { assert qName != null : "qName can't be null."; final Multiname multiname = Multiname.crackDottedQName(this, qName); return getScope().findDefinitionByName(multiname, false); } @Override public ICompilationUnit resolveQNameToCompilationUnit(final String qName) { IDefinition definition = resolveQNameToDefinition(qName); if (definition == null) return null; return projectScope.getCompilationUnitForDefinition(definition); } // List of Builtin types that must be present for compilation // to succeed. private static final BuiltinType[] REQUIRED_BUILTINS = { BuiltinType.OBJECT, BuiltinType.ARRAY, BuiltinType.STRING, BuiltinType.ANY_TYPE, BuiltinType.VOID, BuiltinType.NUMBER, BuiltinType.INT, BuiltinType.UINT }; /** * Check for fatal problems, that would prevent us from successfully compiling. * Currently this just checks that all of the builtin types are present. */ public Collection<ICompilerProblem> getFatalProblems() { Collection<ICompilerProblem> fatalProblems = null; for(IASLanguageConstants.BuiltinType builtinType : REQUIRED_BUILTINS ) { if (getBuiltinType(builtinType) == null) { if (fatalProblems == null) fatalProblems = new ArrayList<ICompilerProblem>(); fatalProblems.add(new MissingBuiltinProblem(builtinType.getName())); break; } } return fatalProblems == null ? Collections.<ICompilerProblem>emptyList() : fatalProblems; } @Override public ITypeDefinition getBuiltinType(IASLanguageConstants.BuiltinType type) { switch( type ) { case OBJECT: return projectScope.getObjectDefinition(); case STRING: return projectScope.getStringDefinition(); case ARRAY: return projectScope.getArrayDefinition(); case XML: return projectScope.getXMLDefinition(); case XMLLIST: return projectScope.getXMLListDefinition(); case BOOLEAN: return projectScope.getBooleanDefinition(); case INT: return projectScope.getIntDefinition(); case UINT: return projectScope.getUIntDefinition(); case NUMBER: return projectScope.getNumberDefinition(); case CLASS: return projectScope.getClassDefinition(); case FUNCTION: return projectScope.getFunctionDefinition(); case NAMESPACE: return projectScope.getNamespaceDefinition(); case VECTOR: return projectScope.getVectorDefinition(); case NULL: return ClassDefinition.getNullClassDefinition(); case VOID: return ClassDefinition.getVoidClassDefinition(); case Undefined: return ClassDefinition.getUndefinedClassDefinition(); case ANY_TYPE: return ClassDefinition.getAnyTypeClassDefinition(); } String name = type.getName(); ITypeDefinition definition = (ITypeDefinition)getScope().findDefinitionByName(name); // Don't have playerglobal.abc/swc with float yet. assert definition != null : "Error, builtin type '"+ type.getName()+ "' can't be found!"; return definition; } @Override public IDefinition getUndefinedValue() { return projectScope.getUndefinedValueDefinition(); } /** * Gets a boolean that indicates whether or not parallel code generation of method bodies is enabled. * @return true if method bodies should be generated in parallel, false otherwise. */ public boolean getUseParallelCodeGeneration() { return useParallelCodeGen; } @Override public void setUseParallelCodeGeneration(boolean useParallelCodeGeneration) { this.useParallelCodeGen = useParallelCodeGeneration; } @Override public Set<ICompilationUnit> getDirectDependencies(ICompilationUnit cu) { return dependencyGraph.getDirectDependencies(cu); } @Override public Set<ICompilationUnit> getDirectReverseDependencies(ICompilationUnit cu, DependencyTypeSet types) { return dependencyGraph.getDirectReverseDependencies(cu, types); } @Override public boolean isInliningEnabled() { return enableInlining; } /** * Set whether or not function inlining is enabled. * * @param enableInlining true to enable inlining. */ public void setEnableInlining(boolean enableInlining) { this.enableInlining = enableInlining; clean(); } /** * Add AST to cache. By default, not added to any cache. * * @param ast The AST. */ public void addToASTCache(IASNode ast) { } /** * Override this to permit package aliasing on imports and elsewhere * * @param packageName The package name */ public String getActualPackageName(String packageName) { return packageName; } /** * Override this to disambiguate between two ambiguous definitinos * * @param scope The current scope. * @param name Definition name. * @param def1 One possibility. * @param def2 The other possibility. * @return null if still ambiguous or else def1 or def2. */ public IDefinition doubleCheckAmbiguousDefinition(ASScope scope, String name, IDefinition def1, IDefinition def2) { return null; } /** * @return collection of compiler problems. */ public Collection<ICompilerProblem> getProblems() { return problems; } /** * collection of compiler problems. */ public void setProblems(Collection<ICompilerProblem> problems) { this.problems = problems; } public boolean isCompatibleOverrideReturnType(IFunctionDefinition func, ITypeDefinition overrideDefinition, ITypeDefinition baseDefinition) { return (baseDefinition == overrideDefinition); } public boolean isValidTypeConversion(IASNode node, IDefinition actualDefinition, IDefinition expectedDefinition, FunctionDefinition func) { return false; } public boolean isCompatibleOverrideParameterType(IFunctionDefinition func, ITypeDefinition overrideDefinition, ITypeDefinition baseDefinition, int i) { return (baseDefinition == overrideDefinition); } }