1 //tabstop=4 2 //*****************************************************************************/ 3 // Project: jpl 4 // 5 // File: $Id$ 6 // Date: $Date$ 7 // Author: Fred Dushin <fadushin@syr.edu> 8 // 9 // 10 // Description: 11 // 12 // 13 // ------------------------------------------------------------------------- 14 // Copyright (c) 2004 Paul Singleton 15 // Copyright (c) 1998 Fred Dushin 16 // All rights reserved. 17 // 18 // This library is free software; you can redistribute it and/or 19 // modify it under the terms of the GNU Library Public License 20 // as published by the Free Software Foundation; either version 2 21 // of the License, or (at your option) any later version. 22 // 23 // This library is distributed in the hope that it will be useful, 24 // but WITHOUT ANY WARRANTY; without even the implied warranty of 25 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 // GNU Library Public License for more details. 27 //*****************************************************************************/ 28 package jpl; 29 30 import java.util.Hashtable; 31 import java.util.Iterator; 32 import java.util.Map; 33 import jpl.fli.DoubleHolder; 34 import jpl.fli.Int64Holder; 35 import jpl.fli.IntHolder; 36 import jpl.fli.Prolog; 37 import jpl.fli.StringHolder; 38 import jpl.fli.term_t; 39 40 //----------------------------------------------------------------------/ 41 // Term 42 /** 43 * Term is the abstract base class for 44 * Compound, Atom, Variable, Integer and Float, which comprise a Java-oriented concrete syntax for Prolog. 45 * You cannot create instances of Term directly; rather, you should create 46 * instances of Term's concrete subclasses. 47 * Alternatively, use textToTerm() to construct a Term from its conventional 48 * Prolog source text representation. 49 * 50 * <hr><i> 51 * Copyright (C) 2004 Paul Singleton<p> 52 * Copyright (C) 1998 Fred Dushin<p> 53 * 54 * This library is free software; you can redistribute it and/or 55 * modify it under the terms of the GNU Library Public License 56 * as published by the Free Software Foundation; either version 2 57 * of the License, or (at your option) any later version.<p> 58 * 59 * This library is distributed in the hope that it will be useful, 60 * but WITHOUT ANY WARRANTY; without even the implied warranty of 61 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 62 * GNU Library Public License for more details.<p> 63 * </i><hr> 64 * @author Fred Dushin <fadushin@syr.edu> 65 * @version $Revision$ 66 */ 67 public abstract class Term { 68 //==================================================================/ 69 // Attributes 70 //==================================================================/ 71 72 //==================================================================/ 73 // Constructors 74 //==================================================================/ 75 76 /** 77 * This default constructor is provided in order for subclasses 78 * to be able to define their own default constructors. 79 */ Term()80 protected Term() { 81 } 82 83 //==================================================================/ 84 // Methods (abstract, common) 85 //==================================================================/ 86 87 /** 88 * returns the ano-th (1+) argument of a (Compound) Term 89 * throws a JPLException for any other subclass 90 * 91 * @return the ano-th argument of a (Compound) Term 92 */ arg(int ano)93 public abstract Term arg(int ano); 94 95 /** 96 * returns, as a Term[], the arguments of a Compound 97 * returns an empty Term[] from an Atom, Integer or Float 98 * throws a JPLException from a Variable 99 * 100 * @return the arguments of a Compound as a Term[ 101 */ args()102 public abstract Term[] args(); 103 104 /** 105 * Tests whether this Term's functor has (String) 'name' and 'arity' 106 * Returns false if called inappropriately 107 * 108 * @return whether this Term's functor has (String) 'name' and 'arity' 109 */ hasFunctor(String name, int arity)110 public abstract boolean hasFunctor(String name, int arity); 111 112 /** 113 * Tests whether this Term's functor has (int) 'name' and 'arity' 114 * Returns false if called inappropriately 115 * 116 * @return whether this Term's functor has (int) 'name' and 'arity' 117 */ hasFunctor(int value, int arity)118 public abstract boolean hasFunctor(int value, int arity); 119 /** 120 * Tests whether this Term's functor has (double) 'name' and 'arity' 121 * Returns false if called inappropriately 122 * 123 * @return whether this Term's functor has (double) 'name' and 'arity' 124 */ hasFunctor(double value, int arity)125 public abstract boolean hasFunctor(double value, int arity); 126 127 /** 128 * returns, as a String, the name of a Compound, Atom or Variable 129 * throws a JPLException from an Integer or Float 130 * 131 * @return the name of a Compound, Atom or Variable 132 */ name()133 public String name() { 134 throw new JPLException("jpl." + this.typeName() + ".name() is undefined"); 135 }; 136 137 /** 138 * returns, as an int, the arity of a Compound, Atom, Integer or Float 139 * throws a JPLException from a Variable 140 * 141 * @return the arity of a Compound, Atom, Integer or Float 142 */ arity()143 public int arity() { 144 throw new JPLException("jpl." + this.typeName() + ".arity() is undefined"); 145 }; 146 147 /** 148 * returns the value (as an int) of an Integer or Float 149 * throws a JPLException from a Compound, Atom or Variable 150 * 151 * @return the value (as an int) of an Integer or Float 152 */ intValue()153 public int intValue() { 154 throw new JPLException("jpl." + this.typeName() + ".intValue() is undefined"); 155 } 156 /** 157 * returns the value (as a long) of an Integer or Float 158 * throws a JPLException from a Compound, Atom or Variable 159 * 160 * @return the value (as a long) of an Integer or Float 161 */ longValue()162 public long longValue() { 163 throw new JPLException("jpl." + this.typeName() + ".longValue() is undefined"); 164 } 165 /** 166 * returns the value (as a float) of an Integer or Float 167 * throws a JPLException from a Compound, Atom or Variable 168 * 169 * @return the value (as a float) of an Integer or Float 170 */ floatValue()171 public float floatValue() { 172 throw new JPLException("jpl." + this.typeName() + ".floatValue() is undefined"); 173 } 174 175 /** 176 * returns the value (as a double) of an Integer or Float 177 * throws a JPLException from any other subclass 178 * 179 * @return the value (as an double) of an Integer or Float 180 */ doubleValue()181 public double doubleValue() { 182 throw new JPLException("jpl." + this.typeName() + ".doubleValue() is undefined"); 183 } 184 185 //==================================================================/ 186 // Methods (common) 187 //==================================================================/ 188 189 /** 190 * returns the type of this term, as one of jpl.fli.Prolog.COMPOUND, .ATOM, .VARIABLE, .INTEGER, .FLOAT etc 191 * 192 * @return the type of this term, as one of jpl.fli.Prolog.COMPOUND, .ATOM, .VARIABLE, .INTEGER, .FLOAT etc 193 */ type()194 public abstract int type(); 195 196 /** 197 * returns the name of the type of this term, as one of "Compound", "Atom", "Variable", "Integer", "Float" etc 198 * 199 * @return the name of the type of this term, as one of "Compound", "Atom", "Variable", "Integer", "Float" etc 200 */ typeName()201 public abstract String typeName(); 202 203 /** 204 * whether this Term represents an atom 205 * 206 * @return whether this Term represents an atom 207 */ isAtom()208 public boolean isAtom() { 209 return this instanceof Atom; 210 } 211 212 /** 213 * whether this Term represents a compound term 214 * 215 * @return whether this Term represents a compound atom 216 */ isCompound()217 public boolean isCompound() { 218 return this instanceof Compound; 219 } 220 221 /** 222 * whether this Term represents an atom 223 * 224 * @return whether this Term represents an atom 225 */ isFloat()226 public boolean isFloat() { 227 return this instanceof Float; 228 } 229 230 /** 231 * whether this Term represents an atom 232 * 233 * @return whether this Term represents an atom 234 */ isInteger()235 public boolean isInteger() { 236 return this instanceof Integer; 237 } 238 239 /** 240 * whether this Term is a variable 241 * 242 * @return whether this Term is a variable 243 */ isVariable()244 public boolean isVariable() { 245 return this instanceof Variable; 246 } 247 248 /** 249 * whether this Term is a 'jfalse' structure, i.e. @(false) 250 * 251 * @return whether this Term is a 'jfalse' structure, i.e. @(false) 252 */ isJFalse()253 public boolean isJFalse() { 254 return false; // overridden in Compound, where it might sometimes be true 255 } 256 257 /** 258 * whether this Term is a 'jtrue' structure, i.e. @(true) 259 * 260 * @return whether this Term is a 'jtrue' structure, i.e. @(true) 261 */ isJTrue()262 public boolean isJTrue() { 263 return false; // overridden in Compound, where it might sometimes be true 264 } 265 266 /** 267 * whether this Term is a 'jnull' structure, i.e. @(null) 268 * 269 * @return whether this Term is a 'jnull' structure, i.e. @(null) 270 */ isJNull()271 public boolean isJNull() { 272 return false; // overridden in Compound, where it might sometimes be true 273 } 274 275 /** 276 * whether this Term is a 'jvoid' structure, i.e. @(void) 277 * 278 * @return whether this Term is a 'jvoid' structure, i.e. @(void) 279 */ isJVoid()280 public boolean isJVoid() { 281 return false; // overridden in Compound, where it might sometimes be true 282 } 283 284 /** 285 * whether this Term is a 'jobject' structure, i.e. @(Tag) 286 * 287 * @return whether this Term is a 'jobject' structure, i.e. @(Tag) 288 */ isJObject()289 public boolean isJObject() { 290 return false; // overridden in Compound, where it might sometimes be true 291 } 292 293 /** 294 * whether this Term is a 'jref' structure, i.e. @(Tag) or @(null) 295 * 296 * @return whether this Term is a 'jref' structure, i.e. @(Tag) or @(null) 297 */ isJRef()298 public boolean isJRef() { 299 return false; // overridden in Compound, where it might sometimes be true 300 } 301 jrefToObject()302 public abstract Object jrefToObject(); 303 304 // objectToJRef(Object) 305 /** 306 * returns a new Term instance which represents the given object 307 */ objectToJRef(Object obj)308 public static Term objectToJRef(Object obj) { 309 return new Compound( "@", new Term[]{new Atom(Prolog.object_to_tag(obj))}); 310 } 311 putParams(Term[] ps)312 public Term putParams(Term[] ps) { 313 IntHolder next = new IntHolder(); 314 next.value = 0; 315 Term t2 = this.putParams1(next, ps); 316 if (next.value != ps.length) { 317 throw new JPLException("Term.putParams: more actual params than formal"); 318 } 319 return t2; 320 } 321 putParams(Term plist)322 public Term putParams(Term plist) { 323 Term[] ps = plist.toTermArray(); 324 return putParams(ps); 325 } 326 putParams1(IntHolder next, Term[] ps)327 protected Term putParams1(IntHolder next, Term[] ps) { 328 switch (this.type()) { 329 case Prolog.COMPOUND : 330 return new Compound(this.name(), putParams2(this.args(), next, ps)); 331 case Prolog.ATOM : 332 if (this.name().equals("?")) { 333 if (next.value >= ps.length) { 334 throw new JPLException("Term.putParams: fewer actual params than formal params"); 335 } 336 return ps[next.value++]; 337 } // else drop through to default 338 default : 339 return this; 340 } 341 } 342 putParams2(Term[] ts, IntHolder next, Term[] ps)343 static protected Term[] putParams2(Term[] ts, IntHolder next, Term[] ps) { 344 int n = ts.length; 345 Term[] ts2 = new Term[n]; 346 for (int i = 0; i < n; i++) { 347 ts2[i] = ts[i].putParams1(next, ps); 348 } 349 return ts2; 350 } 351 352 /** 353 * the length of this list, iff it is one, else an exception is thrown 354 * 355 * @throws JPLException 356 * @return the length (as an int) of this list, iff it is one 357 */ listLength()358 public int listLength() { 359 if (this.hasFunctor(".", 2)) { 360 return 1 + this.arg(2).listLength(); 361 } else if (this.hasFunctor("[]", 0)) { 362 return 0; 363 } else { 364 throw new JPLException("Term.listLength: term is not a list"); 365 } 366 } 367 368 /** returns an array of terms which are the successive members of this list, if it is a list, else throws an exception 369 * 370 * @throws JPLException 371 * @return an array of terms which are the successive members of this list, if it is a list 372 */ toTermArray()373 public Term[] toTermArray() { 374 try { 375 int len = this.listLength(); 376 Term[] ts = new Term[len]; 377 Term t = this; 378 379 for (int i = 0; i < len; i++) { 380 ts[i] = t.arg(1); 381 t = t.arg(2); 382 } 383 return ts; 384 } catch (JPLException e) { 385 throw new JPLException("Term.toTermArray: term is not a proper list"); 386 } 387 } 388 389 //==================================================================/ 390 // Methods (deprecated) 391 //==================================================================/ 392 393 /** 394 * Returns a debug-friendly representation of a Term 395 * 396 * @return a debug-friendly representation of a Term 397 * @deprecated 398 */ debugString()399 public abstract String debugString(); 400 401 /** 402 * Returns a debug-friendly representation of a list of Terms 403 * 404 * @return a debug-friendly representation of a list of Terms 405 * @deprecated 406 */ debugString(Term arg[])407 public static String debugString(Term arg[]) { 408 String s = "["; 409 410 for (int i = 0; i < arg.length; ++i) { 411 s += arg[i].debugString(); 412 if (i != arg.length - 1) { 413 s += ", "; 414 } 415 } 416 return s + "]"; 417 } 418 419 //==================================================================/ 420 // Converting JPL Terms to Prolog terms 421 // 422 // To convert a Term to a term_t, we need to traverse the Term 423 // structure and build a corresponding Prolog term_t object. 424 // There are some issues: 425 // 426 // - Prolog term_ts rely on the *consecutive* nature of term_t 427 // references. In particular, to build a compound structure 428 // in the Prolog FLI, one must *first* determine the arity of the 429 // compound, create a *sequence* of term_t references, and then 430 // put atoms, functors, etc. into those term references. We 431 // do this in these methods by first determining the arity of the 432 // Compound, and then by "put"-ing a type into a term_t. 433 // The "put" method is implemented differently in each of Term's 434 // five subclasses. 435 // 436 // - What if we are trying to make a term_t from a Term, but the 437 // Term has multiple instances of the same Variable? We want 438 // to ensure that _one_ Prolog variable will be created, or else 439 // queries will give incorrect answers. We thus pass a Hashtable 440 // (var_table) through these methods. The table contains term_t 441 // instances, keyed on Variable instances. 442 //==================================================================/ 443 put( term_t term)444 public void put( term_t term){ 445 put( new Hashtable(), term); 446 } 447 /** 448 * Cache the reference to the Prolog term_t here. 449 * 450 * @param varnames_to_vars A Map from variable names to JPL Variables. 451 * @param term A (previously created) term_t which is to be 452 * put with a Prolog term-type appropriate to the Term type 453 * (e.g., Atom, Variable, Compound, etc.) on which the method is 454 * invoked.) 455 */ put(Map varnames_to_vars, term_t term)456 protected abstract void put(Map varnames_to_vars, term_t term); 457 458 /** 459 * This static method converts an array of Terms to a *consecutive* 460 * sequence of term_t objects. Note that the first term_t object 461 * returned is a term_t class (structure); the succeeding term_t 462 * objects are consecutive references obtained by incrementing the 463 * *value* field of the term_t. 464 * 465 * @param varnames_to_vars Map from variable names to JPL Variables. 466 * @param args An array of jpl.Term references. 467 * @return consecutive term_t references (first of which is 468 * a structure) 469 */ putTerms(Map varnames_to_vars, Term[] args)470 protected static term_t putTerms(Map varnames_to_vars, Term[] args) { 471 472 // first create a sequence of term_ts. The 0th term_t 473 // will be a jpl.fli.term_t. Successive Prolog term_t 474 // references will reside in the Prolog engine, and 475 // can be obtained by term0.value+i. 476 // 477 term_t term0 = Prolog.new_term_refs(args.length); 478 479 // for each new term reference, construct a Prolog term 480 // by putting an appropriate Prolog type into the reference. 481 // 482 long ith_term_t = term0.value; 483 for (int i = 0; i < args.length; ++i, ++ith_term_t) { 484 term_t term = new term_t(); 485 term.value = ith_term_t; 486 args[i].put(varnames_to_vars, term); // each subclass defines its own put() 487 } 488 489 return term0; 490 } 491 492 // experiment: for jni_jobject_to_term_byval/2 in jpl.c putTerm( Object obj, term_t termref)493 public static void putTerm( Object obj, term_t termref){ 494 if (obj instanceof Term){ 495 ((Term)obj).put(termref); 496 } else { 497 throw new JPLException("not a Term"); 498 } 499 } 500 501 //==================================================================/ 502 // Converting Prolog terms to JPL Terms 503 // 504 // Converting back from term_ts to Terms is simple, since 505 // the (simplified) Term representation is canonical (there is only one 506 // correct structure for any given Prolog term). 507 // 508 // One problem concerns variable bindings. We illustrate 509 // with several examples. First, consider the Prolog fact 510 // 511 // p( f(X,X)). 512 // 513 // And the query 514 // 515 // ?- p( Y). 516 // 517 // A solution should be 518 // 519 // y = f(X,X) 520 // 521 // and indeed, if this query is run, the term_t to which Y will 522 // be unified is a compound, f(X,X). The problem is, how do 523 // we know, in converting the term_ts to Terms in the compound f/2 524 // whether we should create one Variable or two? This begs the 525 // question, how do we _identify_ Variables in JPL? The answer 526 // to the latter question is, by reference; two Variable (Java) 527 // references refer to the same variable iff they are, in memory, 528 // the same Variable object. That is, they satisfy the Java == relation. 529 // (Note that this condition is _not_ true of the other Term types.) 530 // 531 // Given this design decision, therefore, we should create a 532 // single Variable instance and a Compound instance whose two arg 533 // values refer to the same Variable object. We therefore need to keep 534 // track, in converting a term_t to a Term (in particular, in 535 // converting a term_t whose type is variable to a Variable), of 536 // which Variables have been created. We do this by using the vars 537 // Hashtable, which gets passed recursively though the from_term_t 538 // methods; this table holds the Variable instances that have been 539 // created, keyed by the unique and internal-to-Prolog string 540 // representation of the variable (I'm not sure about this...). 541 //==================================================================/ 542 543 /** 544 * This method calls from_term_t on each term in the n consecutive term_ts. 545 * A temporary jpl.term_t "holder" (byref) structure must be created 546 * in order to extract type information from the Prolog engine. 547 * 548 * @param vars_to_Vars A Map from Prolog variables to jpl.Variable instances 549 * @param n The number of consecutive term_ts 550 * @param term0 The 0th term_t (structure); subsequent 551 * term_ts are not structures. 552 * @return An array of converted Terms 553 */ 554 /* 555 protected static Term[] from_term_ts(Map vars_to_Vars, int n, term_t term0) { 556 557 // create an (uninitialised) array of n Term references 558 Term[] terms = new Term[n]; 559 560 // for each term_t (from 0...n-1), create a term_t 561 // (temporary) structure and dispatch the translation 562 // to a Term to the static from_term_t method of the Term 563 // class. This will perform (Prolog) type analysis on the 564 // term_t and call the appropriate static method to create 565 // a Term of the right type (e.g., Atom, Variable, List, etc.) 566 // 567 long ith_term_t = term0.value; 568 for (int i = 0; i < n; ++i, ++ith_term_t) { 569 term_t term = new term_t(); 570 term.value = ith_term_t; 571 572 terms[i] = Term.from_term_t(vars_to_Vars, term); 573 } 574 575 return terms; 576 } 577 */ 578 579 /** 580 * We discover the Prolog type of the term, then forward the 581 * call to the appropriate subclass 582 * 583 * @param vars A Map from Prolog variables to jpl.Variable instances 584 * @param term The Prolog term (in a term_t holder) to convert 585 * @return The converted Term subtype instance. 586 */ getTerm1(Map vars_to_Vars, term_t term)587 protected static Term getTerm1(Map vars_to_Vars, term_t term) { 588 int type = Prolog.term_type(term); 589 590 switch (type) { 591 case Prolog.VARIABLE : 592 return Variable.getTerm(vars_to_Vars, term); 593 case Prolog.ATOM : 594 return Atom.getTerm(vars_to_Vars, term); 595 case Prolog.STRING : 596 return Atom.getString(vars_to_Vars, term); 597 case Prolog.INTEGER : 598 return Integer.getTerm(vars_to_Vars, term); 599 case Prolog.FLOAT : 600 return Float.getTerm(vars_to_Vars, term); 601 case Prolog.COMPOUND : 602 return Compound.getTerm(vars_to_Vars, term); 603 default : 604 // should never happen... 605 throw new JPLException("Term.from_term_t: unknown term type=" + type); 606 } 607 } 608 getTerm(Map vars_to_Vars, term_t term)609 protected static Term getTerm(Map vars_to_Vars, term_t term) { 610 StringHolder hString; 611 IntHolder hInt; 612 Int64Holder hInt64; 613 // int type = Prolog.term_type(term); 614 switch (Prolog.term_type(term)) { 615 case Prolog.VARIABLE: 616 for (Iterator i = vars_to_Vars.keySet().iterator(); i.hasNext();) { 617 term_t varX = (term_t) i.next(); // a previously seen Prolog variable 618 if (Prolog.compare(varX, term) == 0) { // identical Prolog variables? 619 return (Term) vars_to_Vars.get(varX); // return the associated JPL Variable 620 } 621 } 622 // otherwise, the Prolog variable in term has not been seen before 623 Variable Var = new Variable(); // allocate a new (sequentially named) Variable to represent it 624 Var.term_ = term; // this should become redundant... 625 vars_to_Vars.put(term, Var); // use Hashtable(var,null), but only need set(var) 626 return Var; 627 case Prolog.ATOM: // return Atom.getTerm(vars_to_Vars, term); 628 hString = new StringHolder(); 629 Prolog.get_atom_chars(term, hString); // ignore return val; assume success... 630 return new Atom(hString.value); 631 case Prolog.STRING: // return Atom.getString(vars_to_Vars, term); 632 hString = new StringHolder(); 633 Prolog.get_string_chars(term, hString); // ignore return val; assume success... 634 return new Atom(hString.value); 635 case Prolog.INTEGER: // return Integer.getTerm(vars_to_Vars, term); 636 hInt64 = new Int64Holder(); 637 Prolog.get_integer(term, hInt64); // assume it succeeds... 638 return new jpl.Integer(hInt64.value); 639 case Prolog.FLOAT: // return Float.getTerm(vars_to_Vars, term); 640 DoubleHolder hFloatValue = new DoubleHolder(); 641 Prolog.get_float(term, hFloatValue); // assume it succeeds... 642 return new jpl.Float(hFloatValue.value); 643 case Prolog.COMPOUND: // return Compound.getTerm(vars_to_Vars, term); 644 hString = new StringHolder(); 645 hInt = new IntHolder(); 646 Prolog.get_name_arity(term, hString, hInt); // assume it succeeds 647 Term args[] = new Term[hInt.value]; 648 // term_t term1 = Prolog.new_term_refs(hArity.value); 649 for (int i = 1; i <= hInt.value; i++) { 650 term_t termi = Prolog.new_term_ref(); 651 Prolog.get_arg(i, term, termi); 652 args[i - 1] = Term.getTerm(vars_to_Vars, termi); 653 } 654 return new Compound(hString.value, args); 655 default: 656 // should never happen... 657 throw new JPLException("Term.from_term_t: unknown term type=" + Prolog.term_type(term)); 658 } 659 } 660 getTerm( term_t term)661 protected static Term getTerm( term_t term){ 662 return getTerm( new Hashtable(), term); 663 } 664 665 //==================================================================/ 666 // Computing Substitutions 667 // 668 // Once a solution has been found, the Prolog term_t references 669 // will have been instantiated and will refer to new terms. To compute 670 // a substitution, we traverse the (original) Term structure, looking 671 // at the term_t reference in the Term. The only case we really care 672 // about is if the (original) Term is a Variable; if so, the term_t 673 // back in the Prolog engine may be instantiated (non Variable parts 674 // of the original Term cannot change or become uninstantiated). In 675 // this case, we can store this term in a Hashtable, keyed by the 676 // Variable with which the term was unified. 677 //==================================================================/ 678 679 //------------------------------------------------------------------/ 680 // getSubst 681 /** 682 * This method computes a substitution from a Term. The bindings 683 * Hashtable stores Terms, keyed by Variables. Thus, a 684 * substitution is as it is in mathematical logic, a sequence 685 * of the form \sigma = {t_0/x_0, ..., t_n/x_n}. Once the 686 * substitution is computed, the substitution should satisfy 687 * 688 * \sigma T = t 689 * 690 * where T is the Term from which the substitution is computed, 691 * and t is the term_t which results from the Prolog query.<p> 692 * 693 * A second Hashtable, vars, is required; this table holds 694 * the Variables that occur (thus far) in the unified term. 695 * The Variable instances in this table are guaranteed to be 696 * unique and are keyed on Strings which are Prolog internal 697 * representations of the variables. 698 * 699 * @param bindings table holding Term substitutions, keyed on 700 * Variables. 701 * @param vars A Hashtable holding the Variables that occur 702 * thus far in the term; keyed by internal (Prolog) string rep. 703 */ getSubst(Map varnames_to_Terms, Map vars_to_Vars)704 protected abstract void getSubst(Map varnames_to_Terms, Map vars_to_Vars); 705 706 //------------------------------------------------------------------/ 707 // getSubsts 708 /** 709 * Just calls computeSubstitution for each Term in the array. 710 * 711 * @param varnames_to_Terms a Map from variable names to Terms 712 * @param vars_to_Vars a Map from Prolog variables to JPL Variables 713 * @param arg a list of Terms 714 */ getSubsts(Map varnames_to_Terms, Map vars_to_Vars, Term[] args)715 protected static void getSubsts(Map varnames_to_Terms, Map vars_to_Vars, Term[] args) { 716 for (int i = 0; i < args.length; ++i) { 717 args[i].getSubst(varnames_to_Terms, vars_to_Vars); 718 } 719 } 720 721 //------------------------------------------------------------------/ 722 // terms_equals 723 /** 724 * This method is used (by Compound.equals) to determine the Terms in two Term arrays 725 * are pairwise equal, where two Terms are equal if they satisfy 726 * the equals predicate (defined differently in each Term subclass). 727 * 728 * @param t1 an array of Terms 729 * @param t2 another array of Terms 730 * @return true if all of the Terms in the (same-length) arrays are pairwise equal 731 */ terms_equals(Term[] t1, Term[] t2)732 protected static boolean terms_equals(Term[] t1, Term[] t2) { 733 if (t1.length != t2.length) { 734 return false; 735 } 736 737 for (int i = 0; i < t1.length; ++i) { 738 if (!t1[i].equals(t2[i])) { 739 return false; 740 } 741 } 742 return true; 743 } 744 745 //------------------------------------------------------------------/ 746 // toString 747 /** 748 * Converts a list of Terms to a String. 749 * 750 * @param args An array of Terms to convert 751 * @return String representation of a list of Terms 752 */ toString(Term[] args)753 public static String toString(Term[] args) { 754 String s = ""; 755 756 for (int i = 0; i < args.length; ++i) { 757 s += args[i].toString(); 758 if (i != args.length - 1) { 759 s += ", "; 760 } 761 } 762 763 return s; 764 } 765 766 } 767 768 //345678901234567890123456789012346578901234567890123456789012345678901234567890 769