package org.archstudio.prolog.term; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import org.archstudio.prolog.engine.ProofContext; import org.archstudio.prolog.engine.Signature; import org.archstudio.prolog.engine.UnificationContext; import org.archstudio.prolog.engine.UnificationEngine; import org.archstudio.prolog.op.Executable; import org.archstudio.prolog.op.iso.Neck; import com.google.common.base.Joiner; import com.google.common.collect.AbstractIterator; import com.google.common.collect.Lists; public class ComplexTerm extends AbstractTerm implements Term, Executable { private final String functor; private final List<? extends Term> terms; public ComplexTerm(String functor, List<? extends Term> terms) { this(functor, terms.size(), terms); } protected ComplexTerm(String functor, int arity, List<? extends Term> terms) { this.functor = checkNotNull(functor); this.terms = checkNotNull(terms); checkArgument(terms.size() > 0); checkArgument(terms.size() == arity, functor + "/" + arity + terms); for (Term term : terms) { checkNotNull(term); } } public int getArity() { return terms.size(); } public String getFunctor() { return functor; } public int getTermsSize() { return terms.size(); } public Term getTerm(int index) { return terms.get(index); } public List<Term> getTerms() { return Lists.newArrayList(terms); } public Signature getSignature() { return new Signature(functor, getArity()); } @Override public Term resolve(ProofContext proofContext, Map<VariableTerm, Term> variables) { List<Term> terms = Lists.newArrayListWithCapacity(getArity()); for (Term term : getTerms()) { terms.add(term.resolve(proofContext, variables)); } return proofContext.create(getFunctor(), terms); } @Override public String toString() { return functor + "(" + Joiner.on(',').join(terms) + ")"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (functor == null ? 0 : functor.hashCode()); result = prime * result + (terms == null ? 0 : terms.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } ComplexTerm other = (ComplexTerm) obj; if (functor == null) { if (other.functor != null) { return false; } } else if (!functor.equals(other.functor)) { return false; } if (terms == null) { if (other.terms != null) { return false; } } else if (!terms.equals(other.terms)) { return false; } return true; } @Override public Iterable<Map<VariableTerm, Term>> execute(final ProofContext proofContext, final UnificationEngine unificationEngine, final Term source, final Map<VariableTerm, Term> variables) { return new Iterable<Map<VariableTerm, Term>>() { @Override public Iterator<Map<VariableTerm, Term>> iterator() { return new AbstractIterator<Map<VariableTerm, Term>>() { List<ComplexTerm> kbTerms = proofContext.getKnowledgeBaseTerms(ComplexTerm.this, variables); int kbIndex = 0; Iterator<Map<VariableTerm, Term>> variablesIterator = Collections .<Map<VariableTerm, Term>> emptyList().iterator(); @Override protected Map<VariableTerm, Term> computeNext() { while (true) { if (proofContext.isCancelled()) { return endOfData(); } if (!proofContext.isCut() && variablesIterator.hasNext()) { return variablesIterator.next(); } if (!proofContext.isCut() && kbIndex < kbTerms.size()) { ComplexTerm kbTerm = kbTerms.get(kbIndex++); if (kbTerm instanceof Neck) { variablesIterator = ((Neck) kbTerm).execute(proofContext, unificationEngine, ComplexTerm.this, variables).iterator(); continue; } else { UnificationContext context = new UnificationContext(proofContext, ComplexTerm.this, kbTerm, variables); if (unificationEngine.unifies(proofContext, context)) { return context.variables; } } continue; } return endOfData(); } } }; } }; } }