Importer.java
package com.mackenziehigh.autumn.lang.compiler.compilers;
import autumn.lang.compiler.ast.nodes.TypeSpecifier;
import autumn.util.F;
import autumn.util.functors.Action;
import autumn.util.functors.Function0;
import autumn.util.functors.Function1;
import autumn.util.functors.Function2;
import autumn.util.functors.Function3;
import autumn.util.functors.Function4;
import autumn.util.functors.Function5;
import autumn.util.functors.Function6;
import autumn.util.functors.Function7;
import autumn.util.functors.Function8;
import autumn.util.functors.Function9;
import autumn.util.functors.Ordering;
import autumn.util.functors.Predicate;
import autumn.util.functors.ProxyHandler;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IClassType;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IDeclaredType;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IExpressionType;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IInterfaceType;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IReferenceType;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IReturnType;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IType;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IVariableType;
import com.mackenziehigh.autumn.lang.compiler.utils.Utils;
import com.mackenziehigh.autumn.resources.Finished;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
* Essentially, an instance of this class implements import-directives.
*
* @author Mackenzie High
*/
@Finished("2015/01/17")
public final class Importer
{
/**
* Essentially, this is the module that contains the import-directives implemented herein.
*/
private final ModuleCompiler module;
/**
* This map maps type aliases to the fully-qualified names of types.
*
* <p>
* Example: String => java.lang.String
* </p>
*/
private final Map<String, String> imports = Maps.newTreeMap();
/**
* Sole Constructor.
*
* @param module is essentially the module that is being compiled.
* @throws NullPointerException if module is null.
*/
public Importer(final ModuleCompiler module)
{
this.module = module;
// autumn.lang
importClass(autumn.lang.Delegate.class);
importClass(autumn.lang.Functor.class);
importClass(autumn.lang.Lambda.class);
importClass(autumn.lang.Local.class);
importClass(autumn.lang.LocalsMap.class);
importClass(autumn.lang.Module.class);
importClass(autumn.lang.ModuleInfo.class);
importClass(autumn.lang.Record.class);
importClass(autumn.lang.DefinedFunctor.class);
importClass(autumn.lang.TypedFunctor.class);
// autumn.lang.annotations
importClass(autumn.lang.annotations.Author.class);
importClass(autumn.lang.annotations.Hide.class);
importClass(autumn.lang.annotations.Infer.class);
importClass(autumn.lang.annotations.Setup.class);
importClass(autumn.lang.annotations.Start.class);
importClass(autumn.lang.annotations.Sync.class);
// autumn.lang.compiler
importClass(autumn.lang.compiler.Autumn.class);
// autumn.lang.exceptions
importClass(autumn.lang.exceptions.AssertionFailedException.class);
importClass(autumn.lang.exceptions.AssumptionFailedException.class);
importClass(autumn.lang.exceptions.CheckedException.class);
importClass(autumn.lang.exceptions.DispatchException.class);
importClass(autumn.lang.exceptions.UnexpectedTerminationException.class);
// autumn.util
importClass(autumn.util.Bitwise.class);
importClass(autumn.util.F.class);
importClass(autumn.util.FileIO.class);
// autumn.util.test
importClass(autumn.util.test.MalformedTestException.class);
importClass(autumn.util.test.Test.class);
importClass(autumn.util.test.TestCase.class);
importClass(autumn.util.test.TestResult.class);
importClass(autumn.util.test.TestResults.class);
importClass(autumn.util.test.Tester.class);
importClass(autumn.util.test.UnitTester.class);
// autumn.util.functors
importClass(Action.class);
importClass(Function0.class);
importClass(Function1.class);
importClass(Function2.class);
importClass(Function3.class);
importClass(Function4.class);
importClass(Function5.class);
importClass(Function6.class);
importClass(Function7.class);
importClass(Function8.class);
importClass(Function9.class);
importClass(Ordering.class);
importClass(Predicate.class);
importClass(ProxyHandler.class);
// java.lang.annotation
importClass(java.lang.annotation.Annotation.class);
// java.lang
importClass(java.lang.ArithmeticException.class);
importClass(java.lang.Boolean.class);
importClass(java.lang.Byte.class);
importClass(java.lang.Character.class);
importClass(java.lang.CharSequence.class);
importClass(java.lang.Class.class);
importClass(java.lang.ClassCastException.class);
importClass(java.lang.Comparable.class);
importClass(java.lang.Double.class);
importClass(java.lang.Enum.class);
importClass(java.lang.Exception.class);
importClass(java.lang.Float.class);
importClass(java.lang.IllegalArgumentException.class);
importClass(java.lang.IllegalStateException.class);
importClass(java.lang.IndexOutOfBoundsException.class);
importClass(java.lang.Integer.class);
importClass(java.lang.Iterable.class);
importClass(java.lang.Long.class);
importClass(java.lang.Math.class);
importClass(java.lang.NegativeArraySizeException.class);
importClass(java.lang.NullPointerException.class);
importClass(java.lang.Number.class);
importClass(java.lang.NumberFormatException.class);
importClass(java.lang.Object.class);
importClass(java.lang.RuntimeException.class);
importClass(java.lang.Short.class);
importClass(java.lang.String.class);
importClass(java.lang.StringBuilder.class);
importClass(java.lang.System.class);
importClass(java.lang.Throwable.class);
importClass(java.lang.UnsupportedOperationException.class);
// java.math
importClass(java.math.BigDecimal.class);
importClass(java.math.BigInteger.class);
// java.util
importClass(java.util.ArrayList.class);
importClass(java.util.Collection.class);
importClass(java.util.Collections.class);
importClass(java.util.HashMap.class);
importClass(java.util.HashSet.class);
importClass(java.util.Iterator.class);
importClass(java.util.LinkedList.class);
importClass(java.util.List.class);
importClass(java.util.Map.class);
importClass(java.util.NoSuchElementException.class);
importClass(java.util.Set.class);
importClass(java.util.TreeMap.class);
importClass(java.util.TreeSet.class);
importClass(java.util.Random.class);
/**
* When Autumn is used as a plugin, the user may specify classes to import into every module.
*/
if (module != null)
{
for (Class type : module.program.imported)
{
importClass(type);
}
}
}
/**
* This method ensures that a type is actually accessible from where it is used.
*
* @param specifier is the Abstract-Syntax-Tree node that represents the usage of the type.
* @param type is the type-system representation of the specified type.
* @throws TypeCheckFailed if the specified type is not accessible.
* @throws NullPointerException if specifier is null.
* @throws NullPointerException if type is null.
*/
private void checkAccess(final TypeSpecifier specifier,
final IType type)
{
Preconditions.checkNotNull(specifier);
Preconditions.checkNotNull(type);
/**
* Only declared-types can have restricted access due to access modifiers.
*/
if (type instanceof IDeclaredType == false)
{
return;
}
/**
* This is the type that may be restricted.
*/
final IDeclaredType used = (IDeclaredType) type;
/**
* This is the type of the module that contains the code
* that is attempting to use the potentially restricted type.
*/
final IDeclaredType user = module.type;
/**
* This is true, if access to the type is *not* restricted.
*/
final boolean accessible = module.program.typesystem.utils.isAccessible(user, used);
/**
* If access to the type is restricted, then issue a compile-time warning.
*/
if (!accessible)
{
/**
* This invocation always throws an exception.
*/
module.program.checker.reportInaccessibleType(specifier, used);
}
}
/**
* This method creates a set containing the fully-qualified names of the imported types.
*
* @return the aforedescribed immutable set.
*/
public Set<String> imported()
{
return F.unmodifiable(new TreeSet(imports.values()));
}
/**
* This method converts a type-alias to a fully-qualified type-name.
*
* <p>
* The alias may refer to a type that was imported.
* Otherwise, the alias must refer to a type declared in the enclosing module.
* So, create a string that hopefully is the fully-qualified name of the type.
* However, if the type does not really exist, then the result is really meaningless.
* </p>
*
* @param alias is the type-alias.
* @return the fully-qualified name of the aliased type.
*/
private String dealisTypeName(final String alias)
{
final String full_name = imports.containsKey(alias) ? imports.get(alias) : alias;
final String dealiased = full_name.contains(".")
? full_name
: module.type.getNamespace() + '.' + alias;
return dealiased;
}
/**
* This method retrieves the type that is specified by a type-specifier.
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is either non existent or inaccessible.
* </p>
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is not a return-type.
* </p>
*
* @param specifier specifies the type to retrieve.
* @return the specified type, if it exists and is accessible.
* @throws NullPointerException if the specifier is null.
* @throws TypeCheckFailed if the specified type is either non existent or inaccessible.
* @throws TypeCheckFailed if the specified type is not a return-type.
*/
public IReturnType resolveReturnType(final TypeSpecifier specifier)
{
/**
* Get the name of the type, as it appear in the specifier.
*/
final String alias = module.program.typesystem.utils.extractTypeName(specifier);
/**
* This is the number of array dimensions in the specifier.
* If the specifier does not specify an array, then this variable will be null.
*/
final Integer dimensions = specifier.getDimensions();
final IExpressionType result;
if (Utils.isKeyword(alias))
{
/**
* Special Case: The specifier specifies a primitive-type or the void-type.
*/
return module.program.typesystem.utils.findType(alias, dimensions);
}
else
{
final String typename = dealisTypeName(alias);
result = module.program.typesystem.utils.findType(typename, dimensions);
}
/**
* Issue a compiler-warning, if the type does not actually exist.
*/
module.program.checker.requireType(specifier, result);
/**
* Issue a compiler warning, if the type is cannot be a return-type.
*/
module.program.checker.requireReturnType(specifier, result);
/**
* Issue a compiler warning, if the type is not accessible.
*/
checkAccess(specifier, result);
/**
* This checked-cast will always succeed.
*/
return (IReturnType) result;
}
/**
* This method retrieves the type that is specified by a type-specifier.
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is either non existent or inaccessible.
* </p>
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is not a variable-type.
* </p>
*
* @param specifier specifies the type to retrieve.
* @return the specified type, if it exists and is accessible.
* @throws NullPointerException if the specifier is null.
* @throws TypeCheckFailed if the specified type is either non existent or inaccessible.
* @throws TypeCheckFailed if the specified type is not a variable-type.
*/
public IVariableType resolveVariableType(final TypeSpecifier specifier)
{
final IReturnType type = resolveReturnType(specifier);
/**
* Issue a compiler warning, if the type cannot be the type of a variable.
*/
module.program.checker.requireVariableType(specifier, type);
/**
* This checked-cast will always succeed.
*/
return (IVariableType) type;
}
/**
* This method retrieves the type that is specified by a type-specifier.
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is either non existent or inaccessible.
* </p>
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is not a module-type.
* </p>
*
* @param specifier specifies the type to retrieve.
* @return the specified type, if it exists and is accessible.
* @throws NullPointerException if the specifier is null.
* @throws TypeCheckFailed if the specified type is either non existent or inaccessible.
* @throws TypeCheckFailed if the specified type is not a module-type.
*/
public IClassType resolveModuleType(final TypeSpecifier specifier)
{
final IReturnType type = resolveReturnType(specifier);
/**
* Issue a compiler warning, if the type cannot be the type of a module.
*/
module.program.checker.requireModule(specifier, type);
/**
* This checked-cast will always succeed.
*/
return (IClassType) type;
}
/**
* This method retrieves the type that is specified by a type-specifier.
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is either non existent or inaccessible.
* </p>
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is not a functor-type.
* </p>
*
* @param specifier specifies the type to retrieve.
* @return the specified type, if it exists and is accessible.
* @throws NullPointerException if the specifier is null.
* @throws TypeCheckFailed if the specified type is either non existent or inaccessible.
* @throws TypeCheckFailed if the specified type is not a functor-type.
*/
public IClassType resolveDefinedFunctorType(final TypeSpecifier specifier)
{
final IReturnType type = resolveReturnType(specifier);
/**
* Issue a compiler warning, if the type cannot be the type of a defined-functor.
*/
module.program.checker.requireDefinedFunctorType(specifier, type);
/**
* Issue a compiler warning, if the type cannot be a class-type.
*/
module.program.checker.requireClassType(specifier, type);
/**
* This checked-cast will always succeed.
*/
return (IClassType) type;
}
/**
* This method retrieves the type that is specified by a type-specifier.
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is either non existent or inaccessible.
* </p>
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is not an interface-type.
* </p>
*
* @param specifier specifies the type to retrieve.
* @return the specified type, if it exists and is accessible.
* @throws NullPointerException if the specifier is null.
* @throws TypeCheckFailed if the specified type is either non existent or inaccessible.
* @throws TypeCheckFailed if the specified type is not an interface-type.
*/
public IInterfaceType resolveInterfaceType(final TypeSpecifier specifier)
{
final IReturnType type = resolveReturnType(specifier);
/**
* Issue a compiler warning, if the type cannot be a interface-type.
*/
module.program.checker.requireInterfaceType(specifier, type);
/**
* This checked-cast will always succeed.
*/
return (IInterfaceType) type;
}
/**
* This method retrieves the type that is specified by a type-specifier.
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is either non existent or inaccessible.
* </p>
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is not a design-type.
* </p>
*
* @param specifier specifies the type to retrieve.
* @return the specified type, if it exists and is accessible.
* @throws NullPointerException if the specifier is null.
* @throws TypeCheckFailed if the specified type is either non existent or inaccessible.
* @throws TypeCheckFailed if the specified type is not a design-type.
*/
public IInterfaceType resolveDesignType(final TypeSpecifier specifier)
{
final IReturnType type = resolveReturnType(specifier);
/**
* Issue a compiler warning, if the type cannot be the type of a design.
*/
module.program.checker.requireDesignType(specifier, type);
/**
* This checked-cast will always succeed.
*/
return (IInterfaceType) type;
}
/**
* This method retrieves the type that is specified by a type-specifier.
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is either non existent or inaccessible.
* </p>
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is not a reference-type.
* </p>
*
* @param specifier specifies the type to retrieve.
* @return the specified type, if it exists and is accessible.
* @throws NullPointerException if the specifier is null.
* @throws TypeCheckFailed if the specified type is either non existent or inaccessible.
* @throws TypeCheckFailed if the specified type is not a reference-type.
*/
public IReferenceType resolveReferenceType(final TypeSpecifier specifier)
{
final IReturnType type = resolveReturnType(specifier);
/**
* Issue a compiler warning, if the type cannot be a reference-type.
*/
module.program.checker.requireReferenceType(specifier, type);
/**
* This checked-cast will always succeed.
*/
return (IReferenceType) type;
}
/**
* This method retrieves the type that is specified by a type-specifier.
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is either non existent or inaccessible.
* </p>
*
* @param specifier specifies the type to retrieve.
* @return the specified type, if it exists and is accessible.
* @throws NullPointerException if the specifier is null.
* @throws TypeCheckFailed if the specified type is either non existent or inaccessible.
* @throws TypeCheckFailed if the specified type is not a class-type.
*/
public IClassType resolveClassType(final TypeSpecifier specifier)
{
final IReturnType type = resolveReturnType(specifier);
/**
* Issue a compiler warning, if the type cannot be a class-type.
*/
module.program.checker.requireClassType(specifier, type);
/**
* This checked-cast will always succeed.
*/
return (IClassType) type;
}
/**
* This method retrieves the type that is specified by a type-specifier.
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is either non existent or inaccessible.
* </p>
*
* <p>
* This method causes a compiler-warning to be issued,
* if the specified type is not a declared-type.
* </p>
*
* @param specifier specifies the type to retrieve.
* @return the specified type, if it exists and is accessible.
* @throws NullPointerException if the specifier is null.
* @throws TypeCheckFailed if the specified type is either non existent or inaccessible.
* @throws TypeCheckFailed if the specified type is not a declared-type.
*/
public IDeclaredType resolveDeclaredType(final TypeSpecifier specifier)
{
final IReturnType type = resolveReturnType(specifier);
/**
* Issue a compiler warning, if the type cannot be a class-type.
*/
module.program.checker.requireDeclaredType(specifier, type);
/**
* This checked-cast will always succeed.
*/
return (IDeclaredType) type;
}
/**
* This method creates a type-alias.
*
* @param alias is the alias to use for the type.
* @param type is the fully-qualified name of the type.
* @throws NullPointerException if alias is null.
* @throws NullPointerException if type is null.
*/
public void importType(final String alias,
final String type)
{
Preconditions.checkNotNull(alias);
Preconditions.checkNotNull(type);
imports.put(alias, type);
}
/**
* This method creates a type-alias.
*
* @param type is the type to import.
* @throws NullPointerException if type is null.
*/
public void importClass(final Class type)
{
Preconditions.checkNotNull(type);
imports.put(type.getSimpleName(), type.getName());
}
}