AbstractRecordCompiler.java
package com.mackenziehigh.autumn.lang.compiler.compilers;
import autumn.lang.compiler.ast.commons.IRecord;
import autumn.lang.compiler.ast.nodes.DesignDefinition;
import autumn.lang.compiler.ast.nodes.Element;
import autumn.lang.compiler.ast.nodes.StructDefinition;
import autumn.lang.compiler.ast.nodes.TupleDefinition;
import autumn.lang.compiler.ast.nodes.TypeSpecifier;
import autumn.lang.internals.annotations.Getter;
import autumn.lang.internals.annotations.Setter;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.mackenziehigh.autumn.lang.compiler.typesystem.CustomDeclaredType;
import com.mackenziehigh.autumn.lang.compiler.typesystem.CustomFormalParameter;
import com.mackenziehigh.autumn.lang.compiler.typesystem.CustomMethod;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IAnnotation;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IConstructor;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IFormalParameter;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IInterfaceType;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IMethod;
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.BridgeMethod;
import com.mackenziehigh.autumn.lang.compiler.utils.CovarianceViolation;
import com.mackenziehigh.autumn.lang.compiler.utils.GetterMethod;
import com.mackenziehigh.autumn.lang.compiler.utils.RecordAnalyzer;
import com.mackenziehigh.autumn.lang.compiler.utils.SetterMethod;
import com.mackenziehigh.autumn.lang.compiler.utils.TypeSystemUtils;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.objectweb.asm.Opcodes;
/**
* This class provides a partial implementation of the ICompiler interface for compiling records.
*
* <p>
* This class provides the logic necessary to declare and type-check record-types.
* </p>
*
* @author Mackenzie High
*/
abstract class AbstractRecordCompiler
implements ICompiler
{
/**
* This method creates the type-system representation of the only constructor in the record.
*
* @return the aforedescribed constructor; or null, if no constructor is needed.
*/
protected abstract IConstructor typeofCtor();
/**
* This method creates the type-system representation of the instance() method.
*
* @return the aforedescribed method; or null, if no instance() method is needed.
*/
protected abstract IMethod typeofInstance();
/**
* Essentially, this is the program that is being compiled.
*/
public final ProgramCompiler program;
/**
* Essentially, this is the enclosing module that is also being compiled.
*/
public final ModuleCompiler module;
/**
* This is the Abstract-Syntax-Tree representation of the tuple's definition.
*/
public final IRecord node;
/**
* This will be the type-system representation of the tuple's definition.
*
* This field will be initialized during the type-declaration compiler pass.
*/
public CustomDeclaredType type;
/**
* This object is used to infer inherited elements and detect problems related thereto.
*
* This field will be initialized during the type-initialization compiler pass.
*/
protected RecordAnalyzer analyzer;
/**
* This list stores the keys of the record.
*
* Ordering of the keys is important!
*/
protected final Set<String> keys = Sets.newLinkedHashSet();
/**
* This flag is true, iff the record-type being compiled is a design-type.
*/
protected final boolean design;
/**
* This flag is true, iff the record-type being compiled is a struct-type.
*/
protected final boolean struct;
/**
* This flag is true, iff the record-type being compiled is a tuple-type.
*/
protected final boolean tuple;
/**
* These will be the bridge-methods associated with predefined methods.
*/
protected final List<BridgeMethod> special_bridges = Lists.newArrayList();
/**
* Sole Constructor.
*
* @param module is the module that contains the tuple being compiled.
* @param node is the AST node that represents the tuple being compiled.
*/
public AbstractRecordCompiler(final ModuleCompiler module,
final IRecord node)
{
assert module != null;
assert node != null;
this.program = module.program;
this.module = module;
this.node = node;
this.design = node instanceof DesignDefinition;
this.struct = node instanceof StructDefinition;
this.tuple = node instanceof TupleDefinition;
}
/**
* {@inheritDoc}
*/
@Override
public final void performTypeDeclaration()
{
/**
* Determine the descriptor of the tuple.
*/
final String namespace = module.type.getNamespace().replace('.', '/');
final String name = node.getName().getName();
final String descriptor = "L" + namespace + '/' + name + ';';
/**
* Ensure that the type was not already declared elsewhere.
*/
program.checker.requireNonDuplicateType(node.getName(), descriptor);
/**
* Declare the tuple.
*/
if (design)
{
this.type = program.typesystem.typefactory().newInterfaceType(descriptor);
}
else // struct | tuple
{
this.type = program.typesystem.typefactory().newClassType(descriptor);
}
}
/**
* {@inheritDoc}
*/
@Override
public final void performTypeInitialization()
{
/**
* Create the type-system representations of the annotation-list.
*/
type.setAnnotations(module.anno_utils.typesOf(node.getAnnotations()));
/**
* Add a special annotation.
*/
if (struct)
{
module.anno_utils.add(type, autumn.lang.internals.annotations.StructDefinition.class);
}
else if (tuple)
{
module.anno_utils.add(type, autumn.lang.internals.annotations.TupleDefinition.class);
}
else if (design)
{
module.anno_utils.add(type, autumn.lang.internals.annotations.DesignDefinition.class);
}
/**
* Check the list of annotations.
*/
program.checker.checkAnnotations(node.getAnnotations(), type.getAnnotations());
/**
* Set the type's modifier flags to public and final.
*/
if (struct || tuple)
{
type.setModifiers(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL);
}
else // design
{
type.setModifiers(Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE);
}
/**
* Set the superclass of the tuple's type.
*/
if (struct || tuple)
{
type.setSuperclass(program.typesystem.utils.ABSTRACT_RECORD);
}
else // design
{
type.setSuperclass(program.typesystem.utils.OBJECT);
}
/**
* These are the types of designs that this record implements.
*/
final List<IInterfaceType> superinterfaces = Lists.newLinkedList();
/**
* Every record-type is a subtype of the Record interface.
*/
superinterfaces.add(program.typesystem.utils.RECORD);
/**
* Each user-specified supertype of a record is really a superinterface.
*/
for (TypeSpecifier supertype : node.getSupers())
{
superinterfaces.add(module.imports.resolveInterfaceType(supertype));
}
/**
* Cause the record's type to implement the inherited designs.
*/
type.setSuperinterfaces(superinterfaces);
/**
* Add the types of the methods defined in the tuple to the tuple's type.
*/
final List<IMethod> methods = Lists.newLinkedList();
/**
* Create the getter and setter methods for each element declared directly in the record.
*/
for (Element entry : node.getElements().getElements())
{
final String element_name = entry.getName().getName();
final IVariableType element_type = module.imports.resolveVariableType(entry.getType());
/**
* Remember the name of the element for later use.
*/
keys.add(element_name);
/**
* Each element has an associated getter method and a setter method.
*/
methods.add(typeofSetter(new SetterMethod(type, type, element_name, element_type)));
methods.add(typeofGetter(new GetterMethod(type, element_type, element_name)));
}
/**
* Now we have generated the types of the methods directly declared in the tuple.
*/
type.setMethods(methods);
}
/**
* This method finishes type-initialization in order to avoid another compiler pass.
*/
private void finishTypeInitialization()
{
final List<IMethod> methods = Lists.newLinkedList();
/**
* Analyze the partially constructed record-type in order to detect inherited elements.
*/
this.analyzer = new RecordAnalyzer(type);
/**
* Clear the list of methods, because we are going to recreate the list.
* Bridge methods will be present in the new list.
* Replacing the entire list is the least bug-prone way to do this.
*/
type.setMethods(Lists.<IMethod>newLinkedList());
/**
* Add all the setter methods, including the bridge setters.
*/
for (SetterMethod setter : analyzer.setters())
{
methods.add(typeofSetter(setter));
}
/**
* Add all the getter methods, including the bridge getters.
*/
for (GetterMethod getter : analyzer.getters())
{
methods.add(typeofGetter(getter));
}
/**
* Add the type of the static instance() method.
*/
final IMethod instance = typeofInstance();
if (instance != null)
{
methods.add(instance);
}
/**
* Now we need to generate special bridge methods.
* Special bridge methods are for the methods defined in the Record interface.
* The bridge methods for the setters and getters will not be generated by this invocation.
*/
addTypesOfSpecialBridgeMethods();
for (BridgeMethod bridge : special_bridges)
{
methods.add(bridge.caller);
}
/**
* Now we have generated the types of the directly declared and inherited methods.
*/
type.setMethods(methods);
/**
* Add all the inherited keys.
*/
for (String key : analyzer.elements.keySet())
{
keys.add(key);
}
/**
* Structs sort their keys lexicographically.
*/
if (struct)
{
// Create a sorted set containing the keys in lexicographic order.
final TreeSet<String> sorted = Sets.newTreeSet(keys);
// Clear the original set of keys.
keys.clear();
// Replace the original unsorted keys with the sorted keys.
keys.addAll(sorted);
}
/**
* Add the type of the constructor defined in the tuple to the tuple's type.
*
* This cannot be done earlier, because they order of the keys is important.
* So, we must wait until all the keys are available and sorted.
*/
final IConstructor ctor = typeofCtor();
if (ctor != null)
{
type.setConstructors(Lists.newArrayList(ctor));
}
}
/**
* This method creates the type-system representation of the method that sets a tuple element.
*
* @param setter is a description of the setter.
* @return the aforedescribed method.
*/
private IMethod typeofSetter(final SetterMethod setter)
{
final IAnnotation SETTER = module.anno_utils.typeOf(Setter.class);
final CustomMethod method = new CustomMethod(program.typesystem.typefactory(), false);
final CustomFormalParameter param = new CustomFormalParameter();
param.setType(setter.parameter);
method.setAnnotations(Lists.newArrayList(SETTER));
method.setModifiers(Opcodes.ACC_PUBLIC);
method.setName(setter.name);
method.setOwner(setter.owner);
method.setParameters(Collections.<IFormalParameter>singletonList(param));
method.setReturnType(setter.returns);
method.setThrowsClause(new LinkedList());
return method;
}
/**
* This method creates the type-system representation of the method that gets a tuple element.
*
* @param getter is a description of the getter.
* @return the aforedescribed method.
*/
private IMethod typeofGetter(final GetterMethod getter)
{
final IAnnotation GETTER = module.anno_utils.typeOf(Getter.class);
final CustomMethod method = new CustomMethod(program.typesystem.typefactory(), false);
method.setAnnotations(Lists.newArrayList(GETTER));
method.setModifiers(Opcodes.ACC_PUBLIC);
method.setName(getter.name);
method.setOwner(type);
method.setParameters(new LinkedList());
method.setReturnType(getter.returns);
method.setThrowsClause(new LinkedList());
return method;
}
/**
* This method creates the special bridge methods.
*/
private void addTypesOfSpecialBridgeMethods()
{
final IInterfaceType RECORD = program.typesystem.utils.RECORD;
/**
* Method: set(int, Object)
*/
special_bridges.add(new BridgeMethod(type,
type,
TypeSystemUtils.find(RECORD.getAllVisibleMethods(),
"set",
"(ILjava/lang/Object;)" + RECORD.getDescriptor())));
}
/**
* {@inheritDoc}
*/
@Override
public final void performTypeStructureChecking()
{
/**
* Prevent circular inheritance.
*/
if (TypeSystemUtils.detectCircularInheritance(type))
{
program.checker.reportCircularInheritance(node, type);
}
/**
* TODO: add a new compiler pass for this
*/
finishTypeInitialization();
/**
* Detect and report direct supertypes that are not supposedly design-types.
*/
for (IInterfaceType supertype : type.getSuperinterfaces())
{
program.checker.requireDesignType(node, supertype);
}
/**
* Detect and report duplicate direct supertypes.
*/
final Set<IType> direct_supers = Sets.newHashSet();
for (IInterfaceType supertype : type.getSuperinterfaces())
{
if (direct_supers.contains(supertype))
{
program.checker.reportDuplicateDirectSupertype(node, supertype);
}
else
{
direct_supers.add(supertype);
}
}
/**
* Detect and report any duplicate elements.
*/
final Set<String> direct_elements = Sets.newTreeSet();
for (Element element : node.getElements().getElements().asMutableList())
{
if (direct_elements.contains(element.getName().getName()))
{
program.checker.reportDuplicateElement(element);
}
else
{
direct_elements.add(element.getName().getName());
}
}
/**
* Detect and report any covariance violations.
*/
for (CovarianceViolation violation : analyzer.violations)
{
program.checker.reportCovarianceViolation(node, violation);
}
}
/**
* {@inheritDoc}
*/
@Override
public final void performTypeUsageChecking()
{
// Pass
}
}