/* * 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.io.FileInputStream; import java.io.IOException; import java.util.IdentityHashMap; /** * Library of built-in predicates * @author Alex Benini */ public class BuiltIn extends Library { private EngineManager engineManager; private TheoryManager theoryManager; private LibraryManager libraryManager; private FlagManager flagManager; private PrimitiveManager primitiveManager; private OperatorManager operatorManager; public BuiltIn(Prolog mediator) { super(); setEngine(mediator); engineManager = mediator.getEngineManager(); theoryManager = mediator.getTheoryManager(); libraryManager = mediator.getLibraryManager(); flagManager = mediator.getFlagManager(); primitiveManager = mediator.getPrimitiveManager(); operatorManager = mediator.getOperatorManager(); } @Predicate("fail/0") public boolean fail() { return false; } @Predicate("true/0") public boolean success() { return true; } @Predicate("halt/0") public boolean halt() throws HaltException { throw new HaltException(); } @Predicate("halt/1") public boolean halt(Term arg0) throws HaltException { if (arg0 instanceof Number) throw new HaltException(((Number)arg0).intValue()); return false; } @Predicate("!/0") public boolean cut() { engineManager.cut(); return true; } @Predicate("asserta/1") public boolean assertA(Term arg0) { arg0 = arg0.getTerm(); if (arg0 instanceof Struct) { theoryManager.assertA((Struct) arg0, true, null,false); return true; } return false; } @Predicate("assertz/1") public boolean assertZ(Term arg0) { arg0 = arg0.getTerm(); if (arg0 instanceof Struct) { theoryManager.assertZ((Struct) arg0, true, null,false); return true; } return false; } @Predicate("$retract/1") public boolean retract(Term arg0) { arg0 = arg0.getTerm(); if (!(arg0 instanceof Struct)) return false; Struct sarg0 = (Struct) arg0; ClauseInfo c = theoryManager.retract(sarg0); // if clause to retract found -> retract + true if (c != null) { Struct clause = null; if (!sarg0.isClause()) clause = new Struct(":-", arg0, new Struct("true")); else clause = sarg0; unify(clause,c.getClause()); return true; } return false; } @Predicate("abolish/1") public boolean abolish(Term arg0) { arg0 = arg0.getTerm(); if (!(arg0 instanceof Struct) || !arg0.isGround()) return false; return theoryManager.abolish((Struct) arg0); } /** * Loads a library, given its Java class name. */ @Directive("load_library/1") @Predicate("load_library/1") public boolean loadLibrary(Term arg0) { arg0 = arg0.getTerm(); if (!arg0.isAtom()) return false; try { libraryManager.loadLibrary(((Struct) arg0).getName()); return true; } catch (Exception e) { String m = "An exception has been thrown during the execution " + "of the load_library/1 directive.\n" + e.getMessage(); getEngine().warn(m); return false; } } /** * Unloads a library, given its Java class name. */ @Predicate("unload_library/1") public boolean unloadLibrary(Term arg0) { arg0 = arg0.getTerm(); if (!arg0.isAtom()) return false; try { libraryManager.unloadLibrary(((Struct) arg0).getName()); return true; } catch (Exception ex) { return false; } } /** * Get flag list: flag_list(-List) */ @Predicate("flag_list/1") public boolean flagList(Term arg0) { arg0 = arg0.getTerm(); Struct flist = flagManager.getPrologFlagList(); return unify(arg0, flist); } @Predicate(",/2") public boolean comma(Term arg0, Term arg1) { arg0 = arg0.getTerm(); arg1 = arg1.getTerm(); Struct s = new Struct(",", arg0, arg1); engineManager.pushSubGoal(ClauseInfo.extractBody(s)); return true; } /** * It is the same as call/1, but it is not opaque to cut. */ @Predicate("$call/1") public boolean call(Term goal) { goal = goal.getTerm(); if ((goal instanceof Var) || !isCallable(goal)) return false; goal = convertTermToGoal(goal); if (goal == null) return false; engineManager.identify(goal); engineManager.pushSubGoal(ClauseInfo.extractBody(goal)); return true; } /** * Convert a term to a goal before executing it by means of * call/1. See section 7.6.2 of the ISO Standard for details. * <ul> * <li>If T is a variable then G is the control construct call, * whose argument is T.</li> * <li>If the principal functor of T is t �,�/2 or ;/2 or ->/2, * then each argument of T shall also be converted to a goal.</li> * <li>If T is an atom or compound term with principal functor FT, * then G is a predication whose predicate indicator is FT, and * the arguments, if any, of T and G are identical.</li> * </ul> * Note that a variable X and a term call(X) are converted to * identical bodies. Also note that if T is a number, then there * is no goal which corresponds to T. */ static Term convertTermToGoal(Term term) { if (term instanceof Number) return null; term = term.getTerm(); if (term instanceof Var) return new Struct("call", term); if (term instanceof Struct) { Struct s = (Struct) term; String pi = s.getPredicateIndicator(); if (pi.equals(";/2") || pi.equals(",/2") || pi.equals("->/2")) { for (int i = 0; i < s.getArity(); i++) { Term t = s.getArg(i); Term arg = convertTermToGoal(t); if (arg == null) return null; s.setArg(i, arg); } } } return term; } /** * A callable term is an atom of a compound term. See * the ISO Standard definition in section 3.24. */ private boolean isCallable(Term goal) { return (goal.isAtom() || goal.isCompound()); } @Predicate("is/2") public boolean is(Term arg0, Term arg1) { Term val1 = evalExpression(arg1); if (val1 == null) return false; else return unify(arg0.getTerm(), val1); } @Predicate("=/2") public boolean doUnify(Term arg0, Term arg1) { return unify(arg0, arg1); } // \= @Predicate("\\=/2") public boolean doNotUnify(Term arg0, Term arg1) { return !unify(arg0, arg1); } // $tolist @Predicate("$tolist/2") public boolean toList(Term arg0, Term arg1) { // transform arg0 to a list, unify it with arg1 arg0 = arg0.getTerm(); arg1 = arg1.getTerm(); if (arg0 instanceof Struct) { Term val0 = ((Struct) arg0).toList(); return (val0 != null && unify(arg1, val0)); } return false; } // $fromlist @Predicate("$fromlist/2") public boolean fromList(Term arg0, Term arg1) { // get the compound representation of the list // provided as arg1, and unify it with arg0 arg0 = arg0.getTerm(); arg1 = arg1.getTerm(); if (!arg1.isList()) return false; Term val1 = ((Struct) arg1).fromList(); return val1 != null && unify(arg0, val1); } @Predicate("copy_term/2") public boolean copyTerm(Term arg0, Term arg1) { // unify arg1 with a renamed copy of arg0 arg0 = arg0.getTerm(); arg1 = arg1.getTerm(); int id = engineManager.env.nDemoSteps; return unify(arg1, arg0.copy(new IdentityHashMap<Var, Var>(), id)); } // $append @Predicate("$append/2") public boolean append(Term arg0, Term arg1) { // append arg0 to arg1 arg0 = arg0.getTerm(); arg1 = arg1.getTerm(); if (!arg1.isList()) return false; ((Struct) arg1).append(arg0); return true; } // $find @Predicate("$find/2") public boolean find(Term arg0, Term arg1) { // look for clauses whose head unifies with arg0 and enqueue them to list arg1 arg0 = arg0.getTerm(); arg1 = arg1.getTerm(); if (!arg1.isList() || arg0 instanceof Var) return false; for (ClauseInfo b : theoryManager.find(arg0)) if (match(arg0,b.getHead())) { b.getClause().resolveTerm(); ((Struct) arg1).append(b.getClause()); } return true; } // set_prolog_flag(+Name,@Value) @Predicate("set_prolog_flag/2") public boolean setPrologFlag(Term arg0, Term arg1) { arg0 = arg0.getTerm(); arg1 = arg1.getTerm(); if ((!arg0.isAtom() && !(arg0 instanceof Struct)) || !arg1.isGround()) return false; String name = arg0.toString(); return flagManager.setFlag(name,arg1); } // get_prolog_flag(@Name,?Value) @Predicate("get_prolog_flag/2") public boolean getPrologFlag(Term arg0, Term arg1) { arg0 = arg0.getTerm(); arg1 = arg1.getTerm(); if (!arg0.isAtom() && !(arg0 instanceof Struct)) return false; String name = arg0.toString(); Term value = flagManager.getFlag(name); return (value != null) ? unify(value,arg1) : false; } @Directive("op/3") @Predicate("op/3") public boolean operator(Term arg0, Term arg1, Term arg2) { arg0 = arg0.getTerm(); arg1 = arg1.getTerm(); arg2 = arg2.getTerm(); if (!(arg0 instanceof Number) || !arg1.isAtom() || (!arg2.isAtom() && !arg2.isList())) return false; String specifier = ((Struct) arg1).getName(); if (arg2.isList()) { for (Term t : (Struct) arg2) { Struct operator = (Struct) t; createOperator(operator.getName(), specifier, ((Number) arg0).intValue()); } } else createOperator(((Struct) arg2).getName(), specifier, ((Number) arg0).intValue()); return true; } private void createOperator(String symbol, String specifier, int priority) { if (specifier.equals("fx")|specifier.equals("fy")|specifier.equals("xf")|specifier.equals("yf")| specifier.equals("xfx")|specifier.equals("yfx")|specifier.equals("xfy")) operatorManager.opNew(symbol, specifier, priority); } @Directive("flag/4") public boolean flag(Term flagName, Term flagSet, Term flagDefault, Term flagModifiable) { flagName = flagName.getTerm(); flagSet = flagSet.getTerm(); flagDefault = flagDefault.getTerm(); flagModifiable = flagModifiable.getTerm(); if (flagSet.isList() && (flagModifiable.equals(Term.TRUE) || flagModifiable.equals(Term.FALSE))) { String libName = ""; // TODO What's the future of libName? flagManager.defineFlag(flagName.toString(), (Struct)flagSet, flagDefault, flagModifiable.equals(Term.TRUE), libName); return true; } else return false; } @Directive("initialization/1") public boolean initialization(Term goal) { goal = goal.getTerm(); if (goal instanceof Struct) { primitiveManager.identifyPredicate(goal); theoryManager.addStartGoal((Struct) goal); return true; } else return false; } @Directive("include/1") public boolean include(Term theory) throws InvalidTheoryException, IOException { theory = theory.getTerm(); try { engine.addTheory(new Theory(new FileInputStream(theory.toStringWithoutApices()))); return true; } catch (Exception e) { String m = "An exception has been thrown during the execution " + "of the include/1 directive.\n" + e.getMessage(); getEngine().warn(m); return false; } } }