
# API Reference

This section provides comprehensive documentation for all ε-prolog API functions, predicates, and usage patterns.

## Predicate Definition

### eprolog-define-prolog-predicate

Define a Prolog clause (fact or rule) and add it to the database.

```
(eprolog-define-prolog-predicate (name arg1 arg2 ...) goal1 goal2 ...)
```

The first argument is a head term containing the predicate name and its arguments. For facts with no arguments, you can omit the parentheses: `(eprolog-define-prolog-predicate name)`.

**Alias**: `eprolog-define-predicate`

### eprolog-define-prolog-predicate!

Define a Prolog clause, replacing existing clauses with the same arity.

```
(eprolog-define-prolog-predicate! (name arg1 arg2 ...) goal1 goal2 ...)
```

The first argument is a head term containing the predicate name and its arguments. For facts with no arguments, you can omit the parentheses: `(eprolog-define-prolog-predicate! name)`.

**Alias**: `eprolog-define-predicate!`

### eprolog-define-lisp-predicate

Define a predicate implemented in Emacs Lisp.

```
(eprolog-define-lisp-predicate name (arg1 arg2 ...)
  ;; Lisp code returning eprolog--make-success / eprolog--make-failure
  )
```

The body runs inside the iterative engine and must return
`eprolog--make-success` with the next engine state or
`eprolog--make-failure` on failure. Built-ins can access `engine` and
`frame`, followed by the declared predicate arguments.

## Query Execution

### eprolog-query

Execute an interactive Prolog query.

```
(eprolog-query goal1 goal2 ...)
```

### eprolog-solve

Programmatically solve goals with optional keyword callbacks.

```
;; Basic usage - just solve goals, ignore results
(eprolog-solve goals)

;; With success callback only
(eprolog-solve goals :success (lambda (bindings) ...))

;; With both callbacks
(eprolog-solve goals 
  :success (lambda (bindings) ...)
  :failure (lambda () ...))
```

## DCG Support

### eprolog-define-grammar

Define a DCG rule, adding to existing rules with the same arity.

```
(eprolog-define-grammar head body-element1 body-element2 ...)
```

Adds a new DCG rule without replacing existing ones. This allows multiple alternatives for the same non-terminal.

### eprolog-define-grammar!

Define a DCG rule, replacing existing rules with the same arity.

```
(eprolog-define-grammar! head body-element1 body-element2 ...)
```

Similar to `eprolog-define-grammar` but removes existing rules for the same non-terminal with the same arity before adding the new rule. Used for redefinition or when you want only one rule for a non-terminal.

## Test Runner

The test runner provides a convenient way to execute all tests and verify system functionality:

```emacs-lisp
(defun eprolog-usage-run-all-tests ()
  "Run all ε-prolog tests and display summary."
  (interactive)
  (let ((test-results (ert-run-tests-batch "eprolog-")))
    (message "ε-prolog test suite completed. Check *Messages* for detailed results.")
    test-results))

;; Test specific categories
(defun eprolog-usage-run-core-tests ()
  "Run core Prolog functionality tests."
  (interactive)
  (ert-run-tests-batch "eprolog-core-"))

(defun eprolog-usage-run-builtin-tests ()
  "Run built-in predicate tests."
  (interactive)
  (ert-run-tests-batch "eprolog-feature-builtin-"))

(defun eprolog-usage-run-control-flow-tests ()
  "Run control flow tests."
  (interactive)
  (ert-run-tests-batch "eprolog-feature-control-"))

(defun eprolog-usage-run-lisp-integration-tests ()
  "Run Lisp integration tests."
  (interactive)
  (ert-run-tests-batch "eprolog-feature-lisp-"))

(defun eprolog-usage-run-dcg-tests ()
  "Run DCG tests."
  (interactive)
  (ert-run-tests-batch "eprolog-feature-dcg-"))

(defun eprolog-usage-run-arithmetic-tests ()
  "Run arithmetic tests."
  (interactive)
  (ert-run-tests-batch "eprolog-feature-arithmetic-"))

(defun eprolog-usage-run-api-tests ()
  "Run API tests."
  (interactive)
  (ert-run-tests-batch "eprolog-api-"))

(defun eprolog-usage-run-example-tests ()
  "Run example tests."
  (interactive)
  (ert-run-tests-batch "eprolog-example-"))

;; Utility for running tests interactively
(defun eprolog-usage-run-interactive ()
  "Run ε-prolog tests interactively with ERT."
  (interactive)
  (ert "eprolog-"))
```

## API Tests

These tests verify the public API behavior including edge cases and error handling.

Note: Some tests are disabled as they test APIs that don't exist or are unstable.

### Predicate Definition Tests

```emacs-lisp
(ert-deftest eprolog-api-define-predicate ()
  "Test public predicate definition API."
  (eprolog-test--restore-builtins)

  ;; Test fact definition
  (eprolog-define-predicate (api-fact a))
  (should (eprolog-test--has-solution-p '((api-fact a))))

  ;; Test rule definition
  (eprolog-define-predicate (api-rule _x) (api-fact _x))
  (should (eprolog-test--has-solution-p '((api-rule a))))

  ;; Test fact without parentheses
  (eprolog-define-predicate api-atom)
  (should (eprolog-test--has-solution-p '((api-atom))))

  ;; Test multiple clauses
  (eprolog-define-predicate (multi 1))
  (eprolog-define-predicate (multi 2))
  (let ((solutions (eprolog-test--collect-solutions '((multi _x)))))
    (should (= (length solutions) 2))))

(ert-deftest eprolog-api-define-predicate! ()
  "Test predicate replacement API."
  (eprolog-test--restore-builtins)

  ;; Define initial predicates
  (eprolog-define-predicate (replace-test a))
  (eprolog-define-predicate (replace-test b))
  (should (= (length (eprolog-test--collect-solutions '((replace-test _x)))) 2))

  ;; Replace with single clause
  (eprolog-define-predicate! (replace-test c))
  (let ((solutions (eprolog-test--collect-solutions '((replace-test _x)))))
    (should (= (length solutions) 1))
    (should (equal (cdr (assoc '_x (car solutions))) 'c))))

(ert-deftest eprolog-api-define-lisp-predicate ()
  "Test Lisp predicate definition API."
  (eprolog-test--restore-builtins)

  (eprolog-define-lisp-predicate test-lisp-pred (x)
    (if (eq x 'success)
        (eprolog--make-success engine)
      (eprolog--make-failure)))

  (should (eprolog-test--has-solution-p '((test-lisp-pred success))))
  (should-not (eprolog-test--has-solution-p '((test-lisp-pred failure)))))

(ert-deftest eprolog-api-define-lisp-predicate-invalid-return ()
  "Lisp predicates must return success/failure objects."
  (eprolog-test--restore-builtins)

  (eprolog-define-lisp-predicate invalid-return-predicate ()
    'invalid)

  (should-error
   (eprolog-test--has-solution-p '((invalid-return-predicate)))))
```

### Query Execution Tests

```emacs-lisp
(ert-deftest eprolog-api-query ()
  "Test interactive query API."
  (eprolog-test--restore-builtins)

  ;; Define test facts
  (eprolog-define-predicate (query-test a))
  (eprolog-define-predicate (query-test b))

  ;; Test that query macro expands correctly
  (should (macrop 'eprolog-query))

  ;; Cannot test interactive behavior directly, but verify expansion
  (let ((expansion (macroexpand '(eprolog-query (query-test _x)))))
    (should expansion)))

;; NOTE: The following tests are disabled as they test APIs that don't exist
;; (ert-deftest eprolog-api-solve ()
;;   "Test programmatic solve API."
;;   (eprolog-test--restore-builtins)
;;   
;;   ;; Define test facts
;;   (eprolog-define-predicate (solve-test 1))
;;   (eprolog-define-predicate (solve-test 2))
;;   (eprolog-define-predicate (solve-test 3))
;;   
;;   ;; Test basic solve
;;   (let ((count 0))
;;     (eprolog-solve (solve-test _x)
;;       (lambda (bindings)
;;         (setq count (1+ count))))
;;     (should (= count 3)))
;;   
;;   ;; Test solve with multiple goals
;;   (let ((results nil))
;;     (eprolog-solve (solve-test _x) (= _y _x)
;;       (lambda (bindings)
;;         (push (cons (cdr (assoc '_x bindings))
;;                      (cdr (assoc '_y bindings)))
;;               results)))
;;     (should (= (length results) 3))
;;     ;; Check that _x equals _y in all solutions
;;     (dolist (pair results)
;;       (should (equal (car pair) (cdr pair))))))

;; (ert-deftest eprolog-api-solve-first ()
;;   "Test solve-first API."
;;   (eprolog-test--restore-builtins)
;;   
;;   ;; Define ordered facts
;;   (eprolog-define-predicate (ordered first))
;;   (eprolog-define-predicate (ordered second))
;;   (eprolog-define-predicate (ordered third))
;;   
;;   ;; Test getting first solution
;;   (let ((result nil))
;;     (eprolog-solve-first (ordered _x)
;;       (lambda (bindings)
;;         (setq result (cdr (assoc '_x bindings)))))
;;     (should (eq result 'first)))
;;   
;;   ;; Test with no solutions
;;   (let ((called nil))
;;     (eprolog-solve-first (nonexistent _x)
;;       (lambda (bindings)
;;         (setq called t)))
;;     (should-not called)))

;; (ert-deftest eprolog-api-solve-all ()
;;   "Test solve-all API."
;;   (eprolog-test--restore-builtins)
;;   
;;   ;; Define test facts
;;   (eprolog-define-predicate (collect a))
;;   (eprolog-define-predicate (collect b))
;;   (eprolog-define-predicate (collect c))
;;   
;;   ;; Test collecting all solutions
;;   (let ((solutions (eprolog-solve-all (collect _x)
;;                      (lambda (bindings)
;;                        (cdr (assoc '_x bindings))))))
;;     (should (= (length solutions) 3))
;;     (should (member 'a solutions))
;;     (should (member 'b solutions))
;;     (should (member 'c solutions)))
;;   
;;   ;; Test with no solutions
;;   (let ((solutions (eprolog-solve-all (no-such-pred _x)
;;                      (lambda (bindings) 'should-not-happen))))
;;     (should (null solutions))))
```

### Error Handling Tests

```emacs-lisp
(ert-deftest eprolog-api-error-handling ()
  "Test API error handling."
  (eprolog-test--restore-builtins)

  ;; Test handling of malformed goals
  (should-not (eprolog-test--has-solution-p '(())))  ;; Empty goal

  ;; Test unbound variables in arithmetic
  (should-not (eprolog-test--has-solution-p '((is _x (+ _y 1)))))

  ;; Test invalid predicate calls
  (should-not (eprolog-test--has-solution-p '((123 invalid))))  ;; Number as predicate

  ;; Test cyclic unification with occurs check
  (let ((eprolog-occurs-check t))
    (should-not (eprolog-test--has-solution-p '((= _x (f _x))))))

  ;; Test stack depth limit (if implemented)
  ;; Define infinitely recursive predicate
  (eprolog-define-predicate (infinite _x) (infinite _x))
  ;; This should eventually fail due to depth limit
  (condition-case nil
      (progn
        (eprolog-test--has-solution-p '((infinite a)))
        ;; If no error, predicate should not have succeeded
        (should-not (eprolog-test--has-solution-p '((infinite a)))))
    (error t)))  ;; Expected to error out

(ert-deftest eprolog-api-edge-cases ()
  "Test API edge cases."
  (eprolog-test--restore-builtins)

  ;; Test empty clause body (fact)
  (eprolog-define-predicate (edge-fact))
  (should (eprolog-test--has-solution-p '((edge-fact))))

  ;; Test predicate with many arguments
  (eprolog-define-predicate (many-args a b c d e f g h i j))
  (should (eprolog-test--has-solution-p 
           '((many-args a b c d e f g h i j))))

  ;; Test nested structures  
  (eprolog-define-predicate (nested-struct (a (b c))))
  (should (eprolog-test--has-solution-p '((nested-struct (a (b c))))))

  ;; Test special symbols in atoms
  (eprolog-define-predicate (special-chars |atom with spaces| +special+ /slash/))
  (should (eprolog-test--has-solution-p 
           '((special-chars |atom with spaces| +special+ /slash/)))))
```

## Conclusion

This comprehensive exploration of ε-prolog demonstrates the rich expressiveness and practical utility of logic programming within the Emacs environment. From basic facts and rules to sophisticated DCG parsing, from simple arithmetic to complex family relationship modeling, ε-prolog provides a powerful platform for declarative problem solving.

The modular documentation structure allows focused exploration of specific topics while maintaining comprehensive test coverage. Each example has been carefully crafted to be both educational and executable, ensuring that theory and practice remain tightly coupled.

The journey through these examples illustrates a fundamental truth about Prolog: it's not just a programming language, but a different way of thinking about computation. Instead of telling the computer how to solve problems, we describe what we know and what relationships exist, then let logical inference find the solutions.

This document serves multiple purposes: it's a learning resource for understanding ε-prolog's capabilities, a comprehensive test suite ensuring system reliability, and a demonstration of how logical programming can elegantly solve complex problems. Each example has been carefully crafted to be both educational and executable, ensuring that theory and practice remain tightly coupled.
