package edu.ucsd.arcum.interpreter.ast.expressions; import static edu.ucsd.arcum.interpreter.query.EntityDataBase.BUILT_IN_TRAIT_TYPES; import java.util.List; import java.util.Map; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import edu.ucsd.arcum.exceptions.ArcumError; import edu.ucsd.arcum.exceptions.SourceLocation; import edu.ucsd.arcum.interpreter.ast.FormalParameter; import edu.ucsd.arcum.interpreter.ast.TraitSignature; import edu.ucsd.arcum.interpreter.query.EntityTuple; import edu.ucsd.arcum.interpreter.query.EntityType; import edu.ucsd.arcum.interpreter.query.IEntityLookup; import edu.ucsd.arcum.interpreter.query.TraitValue; import edu.ucsd.arcum.interpreter.satisfier.BindingMap; import edu.ucsd.arcum.interpreter.satisfier.BindingsSet; public class TraitFunction implements IFunction { private String traitName; public TraitFunction(String traitName) { this.traitName = traitName; } // An arg in the "args" list is either a program entity, the special // Entity.ANY_ENTITY, or a NameReference @Override public BindingsSet evaluate(List<Object> args, IEntityLookup entityLookup, BindingMap theta, boolean matchingMode, SourceLocation location) { BindingsSet result; if (!matchingMode && BUILT_IN_TRAIT_TYPES.containsKey(traitName)) { // In generation mode (i.e., not matching mode) we assert that all // built-in traits are true. Note that the non-built-in traits are // looked up even in generation mode. result = BindingsSet.newEmptySet(); BindingMap assertedEntry = BindingMap.newEmptyMap(); TraitSignature type = BUILT_IN_TRAIT_TYPES.get(traitName); List<FormalParameter> formals = type.getFormals(); TraitValue tuples = new TraitValue(traitName, type); Map<String, Object> values = Maps.newHashMap(); for (int i = 0; i < args.size(); ++i) { String paramName = formals.get(i).getIdentifier(); values.put(paramName, args.get(i)); } EntityTuple tuple = new EntityTuple(type, values, null); tuples.addTuple(tuple); assertedEntry.bind(traitName, tuples, EntityType.TRAIT); assertedEntry.addBindings(theta); result.addEntry(assertedEntry); } else { Object lookup = entityLookup.lookupEntity(traitName); TraitValue traitValue = (TraitValue)lookup; result = traitValue.getMatches(args, theta); } return result; } @Override public List<EntityType> checkArgs(SourceLocation location, List<TraitSignature> tupleSets, int numGiven) { boolean isInList = false; List<FormalParameter> formals = null; checking: for (TraitSignature declaration : tupleSets) { if (declaration.getName().equals(traitName)) { int numExpectedArgs = declaration.getNumberOfParameters(); if (numExpectedArgs == numGiven) { isInList = true; } else { ArcumError.fatalUserError(location, "The predicate \"%s\" expects %d arguments, instead found %d", traitName, numExpectedArgs, numGiven); } formals = declaration.getFormals(); break checking; } } if (!isInList) { ArcumError.fatalUserError(location, "The predicate \"%s\" is undefined", traitName); } List<EntityType> result = Lists.transform(formals, FormalParameter.getType); return result; } @Override public String toString() { return traitName; } @Override public String getName() { return traitName; } }