;;; assoc/member
;;; Copyright (C) 2023, 2024 Igalia, S.L.
;;;
;;; Licensed under the Apache License, Version 2.0 (the "License");
;;; you may not use this file except in compliance with the License.
;;; You may obtain a copy of the License at
;;;
;;;    http://www.apache.org/licenses/LICENSE-2.0
;;;
;;; Unless required by applicable law or agreed to in writing, software
;;; distributed under the License is distributed on an "AS IS" BASIS,
;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;;; See the License for the specific language governing permissions and
;;; limitations under the License.

;;; Commentary:
;;;
;;; assoc, member, and friends.
;;;
;;; Code:

(library (hoot assoc)
  (export assq assv assoc
          assq-ref assv-ref assoc-ref
          memq memv member)
  (import (hoot eq)
          (hoot equal)
          (hoot lists)
          (hoot not)
          (hoot pairs)
          (hoot syntax))

  (define-syntax-rule (define-member+assoc member assoc assoc-ref compare
                        optarg ...)
    (begin
      (define* (member v l optarg ...)
        (let lp ((l l))
          (cond
           ((null? l) #f)
           ((compare v (car l)) l)
           (else (lp (cdr l))))))
      (define* (assoc v l optarg ...)
        (let lp ((l l))
          (and (not (null? l))
               (let ((head (car l)))
                 (if (compare v (car head))
                     head
                     (lp (cdr l)))))))
      (define (assoc-ref l k)
        (cond
         ((assoc k l) => cdr)
         (else #f)))))

  (define-member+assoc memq assq assq-ref eq?)
  (define-member+assoc memv assv assv-ref eqv?)
  (define-member+assoc member assoc assoc-ref compare
    #:optional (compare equal?)))
