1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 package jTrolog.engine;
40
41 import jTrolog.errors.*;
42 import jTrolog.lib.BasicLibrary;
43 import jTrolog.lib.Library;
44 import jTrolog.lib.BuiltIn;
45 import jTrolog.parser.Parser;
46 import jTrolog.terms.*;
47 import jTrolog.terms.Number;
48
49 import java.io.Serializable;
50 import java.io.BufferedReader;
51 import java.io.InputStreamReader;
52 import java.io.PrintStream;
53 import java.io.IOException;
54 import java.util.*;
55 import java.lang.reflect.InvocationTargetException;
56 import java.lang.reflect.Method;
57
58
59
60
61 @SuppressWarnings({ "rawtypes", "unchecked","serial", "unused" })
62 public class Prolog implements Serializable {
63
64 public static final String VERSION = "2.1";
65 public static final int OP_LOW = 1;
66 public static final int OP_HIGH = 1200;
67
68 private LibraryAndTheoryManager libraryAndTheoryManager;
69
70
71 private OperatorTable opTable;
72
73 private PrintStream currentPS = System.out;
74 private Struct currentQuery;
75 private Engine currentEngine;
76 public static final Prolog defaultMachine = new DefaultProlog();
77 public static final int FX = 0;
78 public static final int FY = 1;
79 public static final int XFX = 2;
80 public static final int XFY = 3;
81 public static final int YFX = 4;
82 public static final int XF = 5;
83 public static final int YF = 6;
84
85
86
87
88
89 public Prolog() {
90 this(new String[] { "jTrolog.lib.BasicLibrary", "jTrolog.lib.ISOLibrary", "jTrolog.lib.IOLibrary" });
91 }
92
93
94
95
96
97
98
99
100 public Prolog(String extraLib) {
101 this();
102 try {
103 loadLibrary(extraLib);
104 } catch (InvalidLibraryException e) {
105 warn(e.toString());
106 }
107 }
108
109
110
111
112
113
114
115 public Prolog(String[] libNames) {
116 opTable = new OperatorTable();
117 libraryAndTheoryManager = new LibraryAndTheoryManager(this);
118 try {
119 loadLibrary(new BuiltIn(this));
120 } catch (InvalidLibraryException e) {
121 warn(e.toString());
122 }
123
124 if (libNames == null)
125 return;
126 for (int i = 0; i < libNames.length; i++) {
127 try {
128 loadLibrary(libNames[i]);
129 } catch (InvalidLibraryException e) {
130 warn(e.toString());
131 }
132 }
133 }
134
135
136
137
138
139
140 public static void main(String[] args) throws IOException {
141 Prolog vm = new Prolog();
142 System.out.println("jTrolog - Java Trondheim Prolog - v.2.1");
143 System.out.print("?- ");
144 BufferedReader consoleIn = new BufferedReader(new InputStreamReader(System.in));
145 String input = "";
146 String tmp;
147 while ((tmp = consoleIn.readLine()) != null) {
148 input += tmp;
149 try {
150 if (input.trim().endsWith(".")) {
151 Solution x = vm.solve(input);
152 System.out.println("\nresult: " + x);
153 System.out.println(x.bindingsToString());
154 } else if (input.trim().length() == 0) {
155 Solution x = vm.solveNext();
156 System.out.println("\nresult: " + x);
157 System.out.println(x.bindingsToString());
158 }
159 } catch (Throwable throwable) {
160 System.out.println("Prolog error (but don't be alarmed):\n" + throwable.getMessage());
161 } finally {
162 input = "";
163 System.out.print("?- ");
164 }
165 }
166 }
167
168
169
170
171 public void assertZ(Clause toBeAsserted) throws PrologException {
172 String index = toBeAsserted.head.predicateIndicator;
173 if (staticDBContainsPredicate(index))
174 throw new PrologException("permission_error(modify, static_procedure, " + index + ")");
175 libraryAndTheoryManager.assertZ(toBeAsserted, index);
176 }
177
178 public void assertA(Clause toBeAsserted) throws PrologException {
179 String index = toBeAsserted.head.predicateIndicator;
180 if (staticDBContainsPredicate(index))
181 throw new PrologException("permission_error(modify, static_procedure, " + index + ")");
182 libraryAndTheoryManager.assertA(toBeAsserted, index);
183 }
184
185 public Struct retract(Struct sarg0) throws PrologException {
186 String index = ((Struct) sarg0.getArg(0)).predicateIndicator;
187 if (staticDBContainsPredicate(index))
188 throw new PrologException("permission_error(modify, static_procedure, " + index + ")");
189 Struct struct = libraryAndTheoryManager.retract(sarg0, index);
190 if (struct != null)
191 warn("DELETE: " + struct + "\n");
192 return struct;
193 }
194
195 private boolean staticDBContainsPredicate(String key) {
196 return libraryAndTheoryManager.isLibraryRule(key) || hasPrimitive(key);
197 }
198
199 public void abolish(String predicateIndicator) throws PrologException {
200 if (staticDBContainsPredicate(predicateIndicator))
201 throw new PrologException("permission_error(modify, static_procedure, " + predicateIndicator + ")");
202 List l = libraryAndTheoryManager.abolish(predicateIndicator);
203 }
204
205 public void setDynamicPredicateIndicator(String predicateIndicator) throws PrologException {
206 if (staticDBContainsPredicate(predicateIndicator))
207 throw new PrologException("permission_error(modify, static_procedure, " + predicateIndicator + ")");
208 libraryAndTheoryManager.setDynamic(predicateIndicator);
209 }
210
211 public List find(String predIndicator) throws PrologException {
212 List rulesFromDatabase = libraryAndTheoryManager.find(predIndicator);
213 if (rulesFromDatabase == null)
214 throw new PrologException("The predicate " + predIndicator + " is unknown.");
215 return rulesFromDatabase;
216 }
217
218 public Iterator dynamicPredicateIndicators() {
219 return libraryAndTheoryManager.dynamicPredicateIndicators();
220 }
221
222
223
224
225
226
227
228
229
230
231 public void setTheory(String newTheory) throws PrologException {
232 libraryAndTheoryManager.clear();
233 addTheory(newTheory);
234 }
235
236
237
238
239 public void clearTheory() {
240 libraryAndTheoryManager.clear();
241 }
242
243
244
245
246
247
248
249 public void addTheory(String theory) throws PrologException {
250 libraryAndTheoryManager.consult(theory);
251 }
252
253
254
255
256 public String getTheory() {
257 return libraryAndTheoryManager.getTheory(true);
258 }
259
260
261
262
263 public String getLastConsultedTheory() {
264 return libraryAndTheoryManager.getLastConsultedTheory();
265 }
266
267
268
269
270
271
272
273
274
275
276
277
278 public synchronized Library loadLibrary(String className) throws InvalidLibraryException {
279 try {
280 return loadLibrary((Library) Class.forName(className).newInstance());
281 } catch (Exception e) {
282 throw new InvalidLibraryException(className);
283 }
284 }
285
286
287
288
289
290
291
292
293
294
295
296 public Library loadLibrary(Library lib) throws InvalidLibraryException {
297 String name = lib.getName();
298 if (getLibrary(name) != null)
299 throw new InvalidLibraryException("library " + name + " already loaded.");
300
301 lib.setEngine(this);
302
303 addPrimitives(lib);
304 try {
305 return libraryAndTheoryManager.consultLib(lib);
306 } catch (PrologException e) {
307 throw new InvalidLibraryException(lib.getName(), e);
308 }
309 }
310
311
312
313
314
315
316
317 public void unloadLibrary(String name) throws InvalidLibraryException {
318 Library library = getLibrary(name);
319 if (library == null)
320 throw new InvalidLibraryException(name);
321 Library unloaded = libraryAndTheoryManager.unconsultLib(library);
322 removePrimitives(unloaded);
323 }
324
325 public Library getLibrary(String name) {
326 return libraryAndTheoryManager.getLibrary(name);
327 }
328
329
330
331
332 public Iterator getCurrentLibraries() {
333 return libraryAndTheoryManager.getCurrentLibraries();
334 }
335
336
337
338
339
340 public void setPrintStream(PrintStream ps) {
341 currentPS = ps;
342 }
343
344
345
346
347 public PrintStream getPrintStream() {
348 return currentPS;
349 }
350
351
352
353
354
355
356
357
358
359
360 public synchronized Iterator getCurrentOperators() {
361 return opTable.getAllOperators();
362 }
363
364 public int getOperatorPriority(String name, int type) {
365 return opTable.getOperatorPriority(name, type);
366 }
367
368 public void opNew(String name, int type, int i) {
369 opTable.addOperator(name, type, i);
370 }
371
372 public void opNew(String name, String type, int i) {
373 if (type.equalsIgnoreCase("fx"))
374 opTable.addOperator(name, FX, i);
375 if (type.equalsIgnoreCase("fy"))
376 opTable.addOperator(name, FY, i);
377 if (type.equalsIgnoreCase("xfx"))
378 opTable.addOperator(name, XFX, i);
379 if (type.equalsIgnoreCase("xfy"))
380 opTable.addOperator(name, XFY, i);
381 if (type.equalsIgnoreCase("yfx"))
382 opTable.addOperator(name, YFX, i);
383 if (type.equalsIgnoreCase("yf"))
384 opTable.addOperator(name, YF, i);
385 if (type.equalsIgnoreCase("xf"))
386 opTable.addOperator(name, XF, i);
387
388 }
389
390
391
392
393
394
395
396
397
398
399
400
401
402 public synchronized Solution solve(String st) throws Throwable {
403 Parser p = new Parser(st, this);
404 Term t = p.nextTerm(true);
405 if (!(t instanceof Struct))
406
407 return new Solution(t);
408
409 try {
410 Struct g = (Struct) t;
411 if (getPrimitiveExp(g) != null)
412 return new Solution(new BindingsTable().evalExpression(this, g));
413 return solve(g);
414 } catch (InvocationTargetException e) {
415 Throwable cause = e;
416 while (cause instanceof InvocationTargetException)
417 cause = cause.getCause();
418 throw cause;
419 }
420 }
421
422
423
424
425
426
427
428
429
430 public synchronized Solution solve(Struct g) throws Throwable {
431 onSolveBegin(g);
432 currentQuery = (Struct) BuiltIn.convertTermToClauseBody(g);
433 currentEngine = new Engine(this, BuiltIn.convertTermToClauseBody2(currentQuery));
434 BindingsTable result = currentEngine.runFirst();
435 onSolveEnd();
436 return SolutionManager.prepareSolution(currentQuery, result);
437 }
438
439
440
441
442
443
444
445
446
447 public synchronized Solution solveNext() throws Throwable {
448 if (currentEngine == null || !currentEngine.hasAlternatives())
449 throw new NoMorePrologSolutions();
450 BindingsTable result = currentEngine.run(Engine.BACK);
451 onSolveEnd();
452 return SolutionManager.prepareSolution(currentQuery, result);
453 }
454
455 public synchronized void onSolveBegin(Term g) {
456 for (Iterator it = getCurrentLibraries(); it.hasNext();)
457 ((Library) it.next()).onSolveBegin(g);
458 }
459
460 public synchronized void onSolveEnd() {
461 for (Iterator it = getCurrentLibraries(); it.hasNext();)
462 ((Library) it.next()).onSolveEnd();
463 }
464
465
466
467
468
469
470
471 public synchronized boolean hasOpenAlternatives() throws Throwable {
472 return currentEngine.hasAlternatives();
473 }
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488 public static synchronized boolean match(Term t0, Term t1) {
489 if (t0 instanceof Var || t1 instanceof Var)
490 return true;
491
492 if (t0 instanceof Number && t1 instanceof jTrolog.terms.Number)
493 return BasicLibrary.number_equality_2((Number) t0, (Number) t1);
494
495 if (t0 instanceof StructAtom && t1 instanceof StructAtom)
496 return t0.equals(t1);
497
498 if (t0 instanceof Struct && t1 instanceof Struct) {
499 Struct s0 = (Struct) t0;
500 Struct s1 = (Struct) t1;
501 if (s0.arity != s1.arity)
502 return false;
503 for (int i = 0; i < s1.arity; i++) {
504 if (!match(s0.getArg(i), s1.getArg(i)))
505 return false;
506 }
507 return true;
508 }
509 return false;
510 }
511
512
513
514
515 private HashMap directives = new HashMap();
516 private HashMap expressions = new HashMap();
517
518 public boolean hasPrimitive(String predicateIndiciator) {
519 return directives.containsKey(predicateIndiciator) || expressions.containsKey(predicateIndiciator);
520 }
521
522 public boolean hasPrimitiveExp(String predicateIndiciator) {
523 return expressions.containsKey(predicateIndiciator);
524 }
525
526
527
528
529
530 final PrimitiveInfo getPrimitive(Struct struct) {
531 return (PrimitiveInfo) directives.get(struct.predicateIndicator);
532 }
533
534 final PrimitiveInfo getPrimitiveExp(Struct struct) {
535 return (PrimitiveInfo) expressions.get(struct.predicateIndicator);
536 }
537
538 private void addPrimitives(Library src) {
539 List prims = getPrimitives(src);
540 for (int i = 0; i < prims.size(); i++) {
541 PrimitiveInfo p = (PrimitiveInfo) prims.get(i);
542 if (p.method.getReturnType() == Term.class)
543 expressions.put(p.key, p);
544 else
545 directives.put(p.key, p);
546 }
547 }
548
549 private void removePrimitives(Library src) {
550 List prims = getPrimitives(src);
551 for (int i = 0; i < prims.size(); i++) {
552 PrimitiveInfo p = (PrimitiveInfo) prims.get(i);
553 directives.remove(p.key);
554 expressions.remove(p.key);
555 }
556 }
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573 private static List getPrimitives(Library library) {
574 ArrayList result = new ArrayList();
575
576 Method[] mlist = library.getClass().getMethods();
577 methodLoop: for (int i = 0; i < mlist.length; i++) {
578 Method m = mlist[i];
579 String mName = m.getName();
580 Class[] params = m.getParameterTypes();
581
582 Class retType = m.getReturnType();
583 if (!(retType == boolean.class || retType == Term.class || retType == void.class))
584 continue;
585
586 int index = mName.lastIndexOf('_');
587 if (index == -1)
588 continue;
589
590
591 int arity = Integer.parseInt(mName.substring(index + 1, mName.length()));
592 if (params.length - 1 != arity)
593 continue;
594
595 for (int j = 1; j < arity; j++) {
596 if (!Term.class.isAssignableFrom(params[j]))
597 continue methodLoop;
598 }
599
600 String rawName = mName.substring(0, index);
601 result.add(new PrimitiveInfo(library, m, rawName, arity));
602
603
604 String[] synonyms = library.getSynonym(rawName);
605 if (synonyms != null) {
606 for (int j = 0; j < synonyms.length; j++)
607 result.add(new PrimitiveInfo(library, m, synonyms[j], arity));
608 }
609 }
610 return result;
611 }
612
613
614
615
616 List warnings = new LinkedList();
617
618 public synchronized void resetWarningList() {
619 warnings.clear();
620 }
621
622 public List getAndResetWarnings() {
623 List tmp = warnings;
624 warnings = new LinkedList();
625 return tmp;
626 }
627
628
629
630
631
632 public void warn(String m) {
633 warnings.add(m);
634 }
635
636
637
638
639 private HashMap flags = new HashMap();
640
641 public void defineFlag(String name, Struct valueList, Term defValue, boolean modifiable) {
642 flags.put(name, new Flag(name, valueList, defValue, modifiable));
643 }
644
645 public Flag getFlag(String name) {
646 return (Flag) flags.get(name);
647 }
648
649 public Term getFlagValue(String name) {
650 Flag flag = (Flag) flags.get(name);
651 return flag == null ? null : flag.getValue();
652 }
653
654 public Term getPrologFlagList() {
655 Struct flist = Term.emptyList;
656 for (Iterator it = flags.values().iterator(); it.hasNext();) {
657 Flag fl = (Flag) it.next();
658 Term at0 = new Struct("flag", new Term[] { new StructAtom(fl.getName()), fl.getValue() });
659 flist = new Struct(".", new Term[] { at0, flist });
660 }
661 return flist;
662 }
663
664 public static boolean evalPrimitive(PrimitiveInfo prim, Object[] primitive_args) throws Throwable {
665 Method method = prim.method;
666 try {
667 if (method.getReturnType() == void.class) {
668 method.invoke(prim.source, primitive_args);
669 return true;
670 }
671 return ((Boolean) method.invoke(prim.source, primitive_args)).booleanValue();
672 } catch (IllegalArgumentException e) {
673 Class[] expectedArgs = method.getParameterTypes();
674 for (int i = 1; i < primitive_args.length; i++) {
675 Term actual = (Term) primitive_args[i];
676 Class expectedClass = expectedArgs[i];
677 if (expectedClass.isAssignableFrom(actual.getClass()))
678 continue;
679 if (actual instanceof Var)
680 throw new PrologException("instantiation_error");
681
682
683
684 String expected = expectedClass.getName();
685 expected = expected.substring(expected.lastIndexOf('.') + 1);
686 throw new PrologException("type_error(" + expected + ", " + actual + ")");
687 }
688 throw new PrologException("WTF: Bug in system.");
689 }
690 }
691 }