/*
* tuProlog - Copyright (C) 2001-2007 aliCE team at deis.unibo.it
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package alice.tuprolog;
import java.util.ArrayList;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Term class is the root abstract class for Prolog data type.
*
* @see Struct
* @see Var
* @see Number
*/
public abstract class Term {
// true and false constants
public static final Term TRUE = new Struct("true");
public static final Term FALSE = new Struct("false");
// checking type and properties of the Term
/** is this term a null term?*/
public abstract boolean isEmptyList();
/** is this term a constant prolog term? */
public abstract boolean isAtomic();
/** is this term a prolog compound term? */
public abstract boolean isCompound();
/** is this term a prolog (alphanumeric) atom? */
public abstract boolean isAtom();
/** is this term a prolog list? */
public abstract boolean isList();
/** is this term a ground term? */
public abstract boolean isGround();
/**
* Tests for the equality of two object terms
*
* The comparison follows the same semantic of
* the isEqual method.
*/
@Override
public boolean equals(Object t) {
if (!(t instanceof Term))
return false;
return isEqual((Term) t);
}
/**
* is term greater than term t?
*/
public abstract boolean isGreater(Term t);
/**
* Tests if this term is (logically) equal to another
*/
public abstract boolean isEqual(Term t);
/**
* Gets the actual term referred by this Term.
*
* If the Term is a bound variable, the method gets
* the Term linked to the variable.
*/
public abstract Term getTerm();
/**
* Unlink variables inside the term.
*/
public abstract void free();
/**
* Resolves variables inside the term, starting from a specific time count.
*
* If the variables has been already resolved, no renaming is done.
* @param count new starting time count for resolving process
* @return the new time count, after resolving process
*/
abstract long resolveTerm(long count);
/**
* Resolves variables inside the term.
*
* If the variables has been already resolved, no renaming is done.
*/
public void resolveTerm() {
resolveTerm(System.currentTimeMillis());
}
/**
* Gets a copy of this term for the output.
*/
public Term copyResult(Collection<Var> goalVars, List<Var> resultVars) {
Map<Var, Var> originals = new IdentityHashMap<Var, Var>();
for (Var key : goalVars) {
Var clone = new Var();
if (!key.isAnonymous())
clone = new Var(key.getOriginalName());
originals.put(key, clone);
resultVars.add(clone);
}
return copy(originals, new IdentityHashMap<Var, Var>());
}
/**
* Gets a copy (with renamed variables) of the term.
*
* The list argument passed contains the list of variables to be renamed
* (if empty list then no renaming)
* @param idExecCtx Execution Context identifier
*/
abstract Term copy(Map<Var, Var> vMap, int idExecCtx);
/**
* Gets a copy for result.
*/
abstract Term copy(Map<Var, Var> vMap, Map<Var, Var> substMap);
/**
* Try to unify two terms
* @param mediator have the reference of EngineManager
* @param t1 the term to unify
* @return true if the term is unifiable with this one
*/
public boolean unify(Prolog mediator, Term t1) {
EngineManager engine = mediator.getEngineManager();
resolveTerm();
t1.resolveTerm();
List<Var> v1 = new ArrayList<Var>();
List<Var> v2 = new ArrayList<Var>();
boolean ok = unify(v1, v2, t1);
if (ok) {
ExecutionContext ec = engine.getCurrentContext();
if (ec != null) {
// Update trailingVars
ec.trailingVars = new OneWayList<List<Var>>(v1, ec.trailingVars);
// Renaming after unify because its utility regards not the engine but the user
// int id = (engine.env == null) ? Var.PROGRESSIVE : engine.env.nDemoSteps;
// int count = 0;
// for (Var v : v1)
// v.rename(id, count);
// for (Var v : v2)
// v.rename(id, count);
}
return true;
}
Var.free(v1);
Var.free(v2);
return false;
}
/**
* Tests if this term is unifiable with an other term.
* No unification is done.
*
* The test is done outside any demonstration context.
*
* @param t the term to checked
* @return true if the term is unifiable with this one
*/
public boolean match(Term t) {
resolveTerm();
t.resolveTerm();
List<Var> v1 = new ArrayList<Var>();
List<Var> v2 = new ArrayList<Var>();
boolean ok = unify(v1, v2, t);
Var.free(v1);
Var.free(v2);
return ok;
}
/**
* Tries to unify two terms, given a demonstration context
* identified by the mark integer.
*
* Try the unification among the term and the term specified.
*
* @param varsUnifiedArg1 Vars unified in myself
* @param varsUnifiedArg2 Vars unified in term t
*/
abstract boolean unify(List<Var> varsUnifiedArg1, List<Var> varsUnifiedArg2, Term t);
/**
* Static service to create a Term from a string.
*
* @param st the string representation of the term
* @return the term represented by the string
* @throws InvalidTermException if the string does not represent a valid term
*/
public static Term createTerm(String st) {
return Parser.parseSingleTerm(st);
}
/**
* Static service to create a Term from a string, providing an
* external operator manager.
*
* @param st the string representation of the term
* @param op the operator manager used to build the term
* @return the term represented by the string
* @throws InvalidTermException if the string does not represent a valid term
*/
public static Term createTerm(String st, OperatorManager op) {
return Parser.parseSingleTerm(st, op);
}
/**
* Gets an iterator providing a term stream from a source text.
*/
public static Iterator<Term> getIterator(String text) {
return new Parser(text).iterator();
}
// term representation
/**
* Gets the string representation of this term as an X argument
* of an operator, considering the associative property.
*/
String toStringAsArgX(OperatorManager op,int prio) {
return toStringAsArg(op,prio,true);
}
/**
* Gets the string representation of this term as an Y argument
* of an operator, considering the associative property.
*/
String toStringAsArgY(OperatorManager op,int prio) {
return toStringAsArg(op,prio,false);
}
/**
* Gets the string representation of this term as an argument
* of an operator, considering the associative property.
*
* If the boolean argument is true, then the term must be considered as
* X arg, otherwise as Y arg (referring to prolog associative rules).
*/
String toStringAsArg(OperatorManager op,int prio,boolean x) {
return toString();
}
public String toStringWithoutApices() {
String s = toString();
if (s.startsWith("'") && s.endsWith("'"))
return s.substring(1, s.length() - 1);
else
return s;
}
//
/**
* The iterated-goal term G of a term T is a term defined
* recursively as follows:
* <ul>
* <li>if T unifies with ^(_, Goal) then G is the iterated-goal
* term of Goal</li>
* <li>else G is T</li>
* </ul>
*/
public Term iteratedGoalTerm() {
return this;
}
}