/* * tuProlog - Copyright (C) 2001-2002 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.lang.reflect.Method; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; import java.util.Map; /** * This abstract class is the base class for developing * tuProlog built-in libraries, which can be dynamically * loaded by prolog objects. * <p> * Each library can expose to engine: * <ul> * <li> a theory (as a string assigned to theory field) * <li> builtin predicates: each method whose signature is * boolean name_arity(Term arg0, Term arg1,...) * is considered a built-in predicate provided by the library * <li> builtin evaluable functors: each method whose signature is * Term name_arity(Term arg0, Term arg1, ...) * is considered a built-in functors provided by the library * </ul> */ public abstract class Library implements IPrimitives { /** prolog core which loaded the library */ protected Prolog engine; public Library() { } /** * Gets the name of the library. * * By default the name is the class name. * * @return the library name */ public String getName() { return getClass().getName(); } /** * Gets the theory provided with the library. * * Empty theory is provided by default. */ public String getTheory() { return ""; } /** * Gets the engine to which the library is bound. * * @return the engine */ public Prolog getEngine() { return engine; } void setEngine(Prolog en) { engine = en; } /** * Tries to unify two terms. * * The runtime (demonstration) context currently used by the engine * is deployed and altered. */ protected boolean unify(Term a0,Term a1) { return engine.unify(a0,a1); } /** * Tries to unify two terms. * * The runtime (demonstration) context currently used by the engine * is deployed and altered. */ protected boolean match(Term a0,Term a1) { return engine.match(a0,a1); } /** * Evaluates an expression. Returns null value if the argument * is not an evaluable expression. * * The runtime (demo) context currently used by the engine * is deployed and altered. */ protected Term evalExpression(Term term) { if (term == null) return null; Term val = term.getTerm(); if (val instanceof Struct) { Struct t = (Struct) val; if (term != t) if (!t.isPrimitive()) engine.identifyFunctor(t); if (t.isPrimitive()) { PrimitiveInfo bt = t.getPrimitive(); // check for library functors if (bt.isFunctor()) return bt.evalAsFunctor(t); } } else if (val instanceof Number) { return val; } return null; } /** * Method invoked by prolog engine when library is * going to be removed. */ public void dismiss() {} /** * Method invoked when the engine is going * to demonstrate a goal. */ public void onSolveBegin(Term goal) {} /** * Method invoked when the engine has * finished a demonstration. */ public void onSolveEnd() {} /** * Gets the list of predicates defined in the library. */ @Override public Map<PrimitiveInfo.Type, List<PrimitiveInfo>> getPrimitives() { try { Method[] mlist = this.getClass().getMethods(); Map<PrimitiveInfo.Type, List<PrimitiveInfo>> tablePrimitives = new EnumMap<PrimitiveInfo.Type, List<PrimitiveInfo>>(PrimitiveInfo.Type.class); tablePrimitives.put(PrimitiveInfo.Type.DIRECTIVE, new ArrayList<PrimitiveInfo>()); tablePrimitives.put(PrimitiveInfo.Type.PREDICATE, new ArrayList<PrimitiveInfo>()); tablePrimitives.put(PrimitiveInfo.Type.FUNCTOR, new ArrayList<PrimitiveInfo>()); for (int i = 0; i < mlist.length; i++) { Method method = mlist[i]; Class<?> returnType = method.getReturnType(); if (method.isAnnotationPresent(Predicate.class)) { if (returnType != Boolean.TYPE) { String m = "Method " + method.getName() + "is declared " + "as Predicate but does not return a boolean."; getEngine().warn(m); continue; } Predicate annotation = method.getAnnotation(Predicate.class); String name = annotation.value(); addValidMethod(tablePrimitives, PrimitiveInfo.Type.PREDICATE, method, name); } if (method.isAnnotationPresent(Functor.class)) { if (returnType != Term.class) { String m = "Method " + method.getName() + "is declared " + "as Functor but does not return a Term."; getEngine().warn(m); continue; } Functor annotation = method.getAnnotation(Functor.class); String name = annotation.value(); addValidMethod(tablePrimitives, PrimitiveInfo.Type.FUNCTOR, method, name); } if (method.isAnnotationPresent(Directive.class)) { if (returnType != Boolean.TYPE) { String m = "Method " + method.getName() + "is declared " + "as Directive but does not return a boolean."; getEngine().warn(m); continue; } Directive annotation = method.getAnnotation(Directive.class); String name = annotation.value(); addValidMethod(tablePrimitives, PrimitiveInfo.Type.DIRECTIVE, method, name); } } return tablePrimitives; } catch (Exception e) { return null; } } private void addValidMethod(Map<PrimitiveInfo.Type, List<PrimitiveInfo>> table, PrimitiveInfo.Type type, Method method, String name) { int index = name.lastIndexOf('/'); if (index != -1) { Class<?>[] clist = method.getParameterTypes(); try { int arity = Integer.parseInt(name.substring(index + 1, name.length())); // check the number of arguments if (clist.length == arity) { boolean valid = true; for (int j = 0; j < arity; j++) if (!(Term.class.isAssignableFrom(clist[j]))) { valid = false; break; } if (valid) { PrimitiveInfo p = new PrimitiveInfo(type, name, this, method, arity); table.get(type).add(p); } } } catch (Exception e) {} } } }