;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; File:         match.el
; Description:  grammer-style string matching
; Author:       Brent Baccala
; Created:      Mar-96
; Language:     ELISP
; RCS           $Header: /usr/home/baccala/Frolic/RCS/match.el,v 1.1 1996/03/02 09:37:13 baccala Exp baccala $
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; This program uses the Prolog-like capabilities of FROLIC's prolog.el
; to implement a backtracking search capability.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(clear-rules)

;; "setq" is a very useful prolog expression that acts just like
;; you would think, except that it restores the variable's old
;; value upon backtracking
;;
;; *lisp-hook-state* is a list containing one item - the value of the LISP
;; variable.  It's implemented as a list so that a nil variable will
;; set *lisp-hook-state* to "(nil)", not "nil", which would confuse the
;; Prolog engine

(*- (setq _LispVar _LispVal) (*lisp-query*
			      (cond ((null *lisp-hook-state*)
				     (setq *lisp-hook-state* (list _LispVar))
				     (setq _LispVar _LispVal)
				     t)
				    (t
				     (setq _LispVar (car *lisp-hook-state*))
				     (setq *lisp-hook-state* nil)
				     nil)) ))

;; "boundp" tests to see if a Prolog variable is bound or not.

(*- (boundp _Var) (= _Var some-string-thing-that-only-matches-unbounds)
                  (cut) (fail))
(*- (boundp _Var))


;; match-exact is the prolog interface to "looking-at"
;; Are we looking at this RegEx at a certain spot?
;;
;; The starting position is passed in; the ending position is returned

(defun match-exact (RegEx Start)
  (save-excursion
    (goto-char Start)
    (cond ((looking-at RegEx)
	   (list (match-end 0)))
	  (t (list *impossible*)) )))

(*- (match-exact _RegEx _Start _End)
    (is _End (*lisp-query* (match-exact _RegEx _Start))))


;; match-forward is the prolog interface to "re-search-forward"
;; Can we match this RegEx by scanning forward in the buffer?
;;
;; Note that, unlike match-exact, match-forward can succeed multiple times
;;
;; The starting and ending positions are returned
;;
;; *lisp-hook-state* is a pointer to the start of the next match

(defun match-forward (RegEx Begin)
  (save-excursion
    (goto-char (cond (*lisp-hook-state* *lisp-hook-state*)
		     (t Begin)))
    (cond ((re-search-forward RegEx nil t)
	   (setq *lisp-hook-state* (1+ (match-beginning 0)))
	   (list (match-beginning 0) (match-end 0)) )
	  (t
	   (setq *lisp-hook-state* nil)
	   (list *impossible*)) )))

(*- (match-forward _RegEx _Begin _Start _End)
    (is _Start _End (*lisp-query* (match-forward _RegEx _Begin))))


;; match is the generic match function, that can do both exact and
;; forward matches, depending on the setting of a global flag.
;; The global flag is set by calling (match-anything), and reset
;; by any match operation.  In other words, (match-anything) has
;; the apparent function of matching, well, anything...

(*- (match _RegEx _Start _End)
    (boundp _Start)
    (cut)
    (match-exact _RegEx _Start _End))

(*- (match _RegEx _Start _End)
    (match-forward _RegEx 0 _Start _End))


(*- (match-contents-line _Start _End)
    (match "^\\s-*<A HREF=.*</A>\n" _Start _End))


(*- (match-contents-lines _Start _End)
    (match-contents-line _Start _X)
    (match "\\s-*<BR>\n" _X _Y)
    (match-contents-lines _Y _End))
(*- (match-contents-lines _Start _End)
    (match-contents-line _Start _X)
    (match "\\s-*</UL>\n" _X _End))
(*- (match-contents-lines _Start _End)
    (match-contents-line _Start _X)
    (match-contents-list _X _Y)
    (match-contents-lines _Y _End))
(*- (match-contents-lines _Start _End)
    (match-contents-line _Start _X)
    (match-contents-list _X _Y)
    (match "\\s-*</UL>\n" _Y _End))

(*- (match-contents-list _Start _End)
    (match "\\s-*<UL>\n" _Start _X)
    (match-contents-lines _X _End))
