package org.archstudio.prolog.op.iso; import java.math.BigInteger; import java.util.Collections; import java.util.List; import java.util.Map; import org.archstudio.prolog.engine.PrologUtils; import org.archstudio.prolog.engine.ProofContext; import org.archstudio.prolog.engine.UnificationContext; import org.archstudio.prolog.engine.UnificationEngine; import org.archstudio.prolog.op.Executable; import org.archstudio.prolog.term.ComplexTerm; import org.archstudio.prolog.term.ConstantTerm; import org.archstudio.prolog.term.ListTerm; import org.archstudio.prolog.term.Term; import org.archstudio.prolog.term.VariableTerm; import com.google.common.collect.Lists; public class Length extends ComplexTerm implements Executable { public Length(String name, List<? extends Term> terms) { super(name, 2, terms); } @Override public Iterable<Map<VariableTerm, Term>> execute(final ProofContext proofContext, final UnificationEngine unificationEngine, Term source, final Map<VariableTerm, Term> variables) { Term list = getTerm(0); Term length = getTerm(1); if (list instanceof VariableTerm) { java.lang.Number bLength = PrologUtils.evaluate(proofContext, length, variables); if (bLength instanceof BigInteger) { List<VariableTerm> variableList = Lists.newArrayList(); for (int i = 0; i < bLength.intValue(); i++) { variableList.add(PrologUtils.getTemporaryVariableTerm()); } ListTerm listTerm = ListTerm.asListTerm(variableList); UnificationContext context = new UnificationContext(proofContext, list, listTerm, variables); if (unificationEngine.unifies(proofContext, context)) { return Collections.singleton(context.variables); } return Collections.emptyList(); } } // TODO: Handle this situation better else if (list instanceof ListTerm && getVariableLength((ListTerm) list) instanceof VariableTerm) { VariableTerm tail = getVariableLength((ListTerm) list); int actualLength = getListLength((ListTerm) list); java.lang.Number bLength = PrologUtils.evaluate(proofContext, length, variables); if (actualLength <= bLength.intValue()) { List<VariableTerm> variableList = Lists.newArrayList(); for (int i = actualLength; i < bLength.intValue(); i++) { variableList.add(PrologUtils.getTemporaryVariableTerm()); } ListTerm listTerm = ListTerm.asListTerm(variableList); UnificationContext context = new UnificationContext(proofContext, tail, listTerm, variables); if (unificationEngine.unifies(proofContext, context)) { return Collections.singleton(context.variables); } } return Collections.emptyList(); } else { Term bLength = new ConstantTerm(BigInteger.valueOf(((ListTerm) list).length())); UnificationContext context = new UnificationContext(proofContext, length, bLength, variables); if (unificationEngine.unifies(proofContext, context)) { return Collections.singleton(context.variables); } return Collections.emptyList(); } throw new UnsupportedOperationException("Cannot satisfy length: " + this); } private VariableTerm getVariableLength(ListTerm list) { Term tail = list.getTail(); if (tail instanceof VariableTerm) { return (VariableTerm) tail; } if (tail instanceof ListTerm) { return getVariableLength((ListTerm) tail); } return null; } private int getListLength(ListTerm list) { Term tail = list.getTail(); if (tail instanceof VariableTerm) { return 1; } if (tail instanceof ListTerm) { return 1 + getListLength((ListTerm) tail); } return 0; } }