package tarau.jinni; import java.util.Enumeration; /** * For a given clause g= A0:-,A1,A2...,An, used as resolvent * iterates over its possible unfoldings (LD-resolution steps) * with clauses of the form B0:-B1,...,Bm in the default database. * For each such step, a new clause (A0:-B1,...,Bm,A2...,An)mgu(A1,B0) * is built and returned by the Unfolder's getElement method. * Before the actual unfolding operations, builtins in Guard are executed, * possibly providing bindings for some variables or failing. * In case of failure of Guard or of unification, getElement() returns null. */ class Unfolder extends Source { private int oldtop; private Enumeration e; private Clause goal; private Prog prog; /** * Creates an Unfolder based on goal clause g for resolution * step in program p */ public Unfolder(Clause g,Prog p) { super(p); this.goal=g; this.prog=p; this.e=null; trace_goal(g); reduceBuiltins(); if(null!=goal) { Term first=goal.getFirst(); if(null!=first) { oldtop=prog.getTrail().size(); this.e=Init.default_db.toEnumerationFor(first.getKey()); if(!e.hasMoreElements()) trace_nomatch(first); } } else trace_failing(g); } /** * Overrides default trailing by empty action */ protected void trailMe(Prog p) { //IO.mes("not trailing"+this); }; /** * Extracts an answer at the end of an AND-derivation */ Clause getAnswer() { if(null!=goal && goal.getBody() instanceof true_) return goal.ccopy(); else return null; } /** * Checks if this clause is the last one, allowing LCO */ final boolean notLastClause() { return (null!=e) && e.hasMoreElements(); } /** * Reduces builtin functions after the neck of a clause, before a "real" atom is unfolded */ final void reduceBuiltins() { for(;;) { Term first=goal.getFirst(); if(null==first) break; // cannot reduce further if(first instanceof Conj) { // advances to next (possibly) inline builtin goal=new Clause(goal.getHead(), Clause.appendConj(first,goal.getRest()) ); first=goal.getFirst(); } int ok=first.exec(prog); // (possibly) executes builtin switch(ok) { case -1: // nothing to do, this is not a builtin break; case 1: // builtin suceeds //IO.mes("advancing: "+goal); goal=new Clause(goal.getHead(),goal.getRest()); continue; // advance case 0: // builtin fails goal=null; break; // get out default: // unexpected code: programming error IO.errmes("Bad return code:"+ok+") in builtin: "+first); goal=null; break; } //IO.mes("leaving reduceBuiltins: "+goal); break; // leaves loop } } /** * Returns a new clause by unfolding the goal with a matching * clause in the database, or null if no such clause exists. */ public Term getElement() { if(null==e) return null; Clause unfolded_goal=null; while(e.hasMoreElements()) { Term T=(Term)e.nextElement(); if(!(T instanceof Clause)) continue; // resolution step, over goal/resolvent of the form: // Answer:-G1,G2,...,Gn. prog.getTrail().unwind(oldtop); unfolded_goal=T.toClause().unfold_with_goal(goal,prog.getTrail()); if(null!=unfolded_goal) break; } return unfolded_goal; } /** * Stops production of more alternatives by setting the clause enumerator to null */ public void stop() { e=null; } /** * Tracer on entering g */ final void trace_goal(Clause g) { switch(Prog.tracing) { case 2: IO.println(">>>: "+g.getFirst()); break; case 3: IO.println(">>>: "+g.pprint()); break; } } /** * Tracer on exiting g */ final void trace_failing(Clause g) { switch(Prog.tracing) { case 2: IO.println("FAILING CALL IN<<<: "+g.getFirst()); break; case 3: IO.println("FAILING CALL IN<<<: "+g.pprint()); break; } } /** * Tracer for undefined predicates */ final void trace_nomatch(Term first) { if(Prog.tracing>0) { IO.println("*** UNDEFINED CALL: "+first.pprint()); } } /** * Returns a string representation of this unfolder, based * on the original clause it is based on. */ public String toString() { return (null==goal)?"{Unfolder}":"{Unfolder=> "+goal.pprint()+"}"; } }