package edu.ucsd.arcum.interpreter.ast;
import java.util.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import edu.ucsd.arcum.exceptions.ArcumError;
import edu.ucsd.arcum.exceptions.SourceLocation;
import edu.ucsd.arcum.interpreter.ast.expressions.ConstraintExpression;
import edu.ucsd.arcum.interpreter.ast.expressions.TrueLiteral;
import edu.ucsd.arcum.interpreter.query.ArcumDeclarationTable;
import edu.ucsd.arcum.interpreter.query.EntityType;
import edu.ucsd.arcum.util.StringUtil;
public class TraitSignature extends ArcumDeclarationType
{
private String name;
private EnumSet<TraitModifier> modifiers;
private List<FormalParameter> formals;
private boolean isBuiltIn = false;
private boolean isSingleton = false;
private boolean isOptionLocal = false;
private ConstraintExpression interfaceConjunct = new TrueLiteral(SourceLocation.GENERATED);
private TraitSignature(List<TraitModifier> modifiers, String name,
List<FormalParameter> formals)
{
this.modifiers = modifiers.isEmpty() ? EnumSet.noneOf(TraitModifier.class)
: EnumSet.copyOf(modifiers);
this.name = name;
this.formals = formals;
this.isBuiltIn = false;
}
public static TraitSignature makeTraitSignature(String name,
List<FormalParameter> params)
{
List<TraitModifier> emptyList = Lists.newArrayList();
return new TraitSignature(emptyList, name, params);
}
public static TraitSignature makeAbstractTraitSignature(String name,
List<FormalParameter> params)
{
List<TraitModifier> modifiers = Lists.newArrayList(TraitModifier.ABSTRACT);
return new TraitSignature(modifiers, name, params);
}
public static TraitSignature makeStaticDefinition(String name,
List<FormalParameter> params)
{
return makeStaticDefinition(name, params.toArray(new FormalParameter[0]));
}
public static TraitSignature makeStaticDefinition(String name,
FormalParameter... params)
{
List<TraitModifier> modifiers = Lists.newArrayList(TraitModifier.DEFINE);
TraitSignature traitSignature;
traitSignature = new TraitSignature(modifiers, name, Arrays.asList(params));
traitSignature.isBuiltIn = true;
return traitSignature;
}
public static TraitSignature makeBuiltIn(String name, FormalParameter... params) {
List<TraitModifier> emptyList = Collections.emptyList();
TraitSignature traitSignature;
traitSignature = new TraitSignature(emptyList, name, Arrays.asList(params));
traitSignature.isBuiltIn = true;
return traitSignature;
}
public static TraitSignature makeSingleton(String name, FormalParameter... params) {
List<TraitModifier> emptyList = Collections.emptyList();
TraitSignature traitSignature;
traitSignature = new TraitSignature(emptyList, name, Arrays.asList(params));
traitSignature.isSingleton = true;
return traitSignature;
}
public static TraitSignature makeSingleton(String name, List<FormalParameter> params)
{
return makeSingleton(name, params.toArray(new FormalParameter[0]));
}
@Override public String toString() {
StringBuilder buff = new StringBuilder();
for (TraitModifier mod : modifiers) {
buff.append(mod.getKeyword());
buff.append(" ");
}
enterTraitNames(buff);
RealizationStatement.buildRequiresMessageString(buff, this);
return buff.toString();
}
public String toSignatureOnlyString() {
StringBuilder buff = new StringBuilder();
enterTraitNames(buff);
return buff.toString();
}
public void enterTraitNames(StringBuilder buff) {
buff.append(name);
buff.append("(");
StringUtil.separate(buff, formals, ", ");
buff.append(")");
}
public String getName() {
return name;
}
public List<FormalParameter> getFormals() {
return formals;
}
public int getNumberOfParameters() {
return formals.size();
}
public List<TraitModifier> getModifiers() {
return Lists.newArrayList(modifiers);
}
public boolean isStaticDefinition() {
return modifiers.contains(TraitModifier.DEFINE);
}
public boolean isBuiltIn() {
return isBuiltIn;
}
public boolean isSingleton() {
return isSingleton;
}
public void setOptionLocal(boolean optionLocal) {
this.isOptionLocal = optionLocal;
}
public boolean isOptionLocal() {
return isOptionLocal;
}
public boolean isAbstract() {
return modifiers.contains(TraitModifier.ABSTRACT);
}
public void setAbstract(boolean makeAbstract) {
if (makeAbstract) {
modifiers.add(TraitModifier.ABSTRACT);
}
else {
modifiers.remove(TraitModifier.ABSTRACT);
}
}
public EntityType lookupType(String id) {
for (FormalParameter formal : formals) {
if (formal.getIdentifier().equals(id)) {
return formal.getType();
}
}
ArcumError.fatalUserError(SourceLocation.coverAll(getRequireClauses()),
"The variable '%s' has not been declared", id);
return null;
}
public Collection<String> getNamesOfDeclaredFormals() {
List<String> result = Lists.newArrayList();
for (FormalParameter formal : formals) {
result.add(formal.getIdentifier());
}
return result;
}
// Returns true if the names are the same and the formals are the same
public boolean implementsSignature(TraitSignature interfaceSignature) {
if (!name.equals(interfaceSignature.name))
return false;
if (formals.size() != interfaceSignature.formals.size())
return false;
for (int i = 0; i < formals.size(); ++i) {
FormalParameter formal = formals.get(i);
FormalParameter interfaceFormal = interfaceSignature.formals.get(i);
if (!formal.equals(interfaceFormal))
return false;
}
return true;
}
public void inheritConstraints(TraitSignature intfSignature) {
List<ConstraintExpression> requireClauses = intfSignature.getRequireClauses();
List<ErrorMessage> errorMessages = intfSignature.getErrorMessages();
for (int i = 0; i < requireClauses.size(); ++i) {
ConstraintExpression constraintExpression = requireClauses.get(i);
ErrorMessage errorMessage = errorMessages.get(i);
this.addRequiresClause(constraintExpression, errorMessage);
}
}
public static Set<String> getGlobals(List<TraitSignature> signatures) {
Set<String> result = new HashSet<String>();
for (TraitSignature signature : signatures) {
if (signature.isSingleton) {
result.addAll(signature.getNamesOfDeclaredFormals());
}
}
result.add(ArcumDeclarationTable.SPECIAL_ANY_VARIABLE);
return result;
}
@Override protected Set<String> doGetVariablesInScope(Set<String> currentScope) {
Set<String> result = Sets.newHashSet(currentScope);
result.addAll(Lists.transform(formals, FormalParameter.getIdentifier));
return result;
}
public ConstraintExpression getInterfaceConjunct() {
return interfaceConjunct;
}
public void setInterfaceConjunct(ConstraintExpression conjunct) {
this.interfaceConjunct = conjunct;
}
}