;
; Support for matching of patterns containing contexts (holes)
; Chris Pressey, March 2008
;
; Copyright (c)2008 Cat's Eye Technologies. All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions
; are met:
;
; 1. Redistributions of source code must retain the above copyright
; notices, this list of conditions and the following disclaimer.
; 2. Redistributions in binary form must reproduce the above copyright
; notices, this list of conditions, and the following disclaimer in
; the documentation and/or other materials provided with the
; distribution.
; 3. Neither the names of the copyright holders nor the names of their
; contributors may be used to endorse or promote products derived
; from this software without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
; ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
; COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
; ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
; POSSIBILITY OF SUCH DAMAGE.
;
; A traditional unifier is a set of (variable name, value) pairs indicating
; what value is bound to each variable name. In our case, unifiers contain
; (name, term index) pairs which bind named to indices into the subject term.
; In a sense, conventional unifiers are unifiers "by value" while Treacle's
; are unifiers "by reference".
;
; Note also that in these unifiers, the same name can be bound to *multiple*
; positions within the subject, since the name may occur in any number of
; positions in the pattern, and will match as long as those subterms are
; equivalent.
;
;
; Create and return a new, empty unifier.
;
(define mk-empty-unifier
(lambda ()
'()))
;
; Extend the given unifier to one where the given name is associated with
; the given term index in the given subject term. If such an extension is
; not possible (i.e. the name is already bound to an inequivalent term at
; a different index in the subject,) then #f is returned.
;
(define bind-name
(lambda (subject index name unifier)
(if (scour-unifier? subject index name unifier)
(cons (cons name index) unifier)
#f)))
;
; Helper function for bind-name. Returns #t if it's OK to extend the
; unifier with the given name->index association, #f otherwise
;
(define scour-unifier?
(lambda (subject index name unifier)
(cond
((null? unifier)
#t)
(else
(let* ((pair (car unifier))
(bound-name (car pair))
(bound-index (cdr pair)))
(cond
((not (eq? name bound-name))
(scour-unifier? subject index name (cdr unifier)))
((eqv? index bound-index) ; already bound to same place: ok
(scour-unifier? subject index name (cdr unifier)))
((eqv? (term-index-fetch subject index) ; already bound to equiv
(term-index-fetch subject (cdr pair))) ; term: alright
(scour-unifier? subject index name (cdr unifier)))
(else ; already bound to something else: not good
#f)))))))
;
; Given a subject, a replacement, and a unifier, return a term which is like
; the replacement except where where each of the placeholders in the replacement
; has been replaced by the associated term referenced in the unifier.
;
(define expand-vars
(lambda (subject replacement unifier generation-id)
(cond ((is-named? replacement) ; variable - replace if in unifier
(let* ((pair (assq (get-name replacement) unifier)))
(cond ((pair? pair)
(term-index-fetch subject (cdr pair)))
(else
replacement))))
((is-newref? replacement)
(string->symbol (string-append "unique-ref-" (number->string generation-id))))
((list? replacement) ; list - recurse
(map (lambda (subpattern)
(expand-vars subject subpattern unifier generation-id))
replacement))
(else ; ground term - leave it alone.
replacement))))