;; Type utilities.
;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.

(define-module (gdb types)
  #:use-module (gdb)
  #:use-module (gdb iterator)
  #:use-module (gdb support))

(define-public (type-has-field-deep? type field-name)
  "Return #t if the type, including baseclasses, has the specified field.

  Arguments:
    type: The type to examine.  It must be a struct or union.
    field-name: The name of the field to look up.

  Returns:
    True if the field is present either in type_ or any baseclass.

  Raises:
    wrong-type-arg: The type is not a struct or union."

  (define (search-class type)
    (let ((find-in-baseclass (lambda (field)
			       (if (field-baseclass? field)
				   (search-class (field-type field))
				   ;; Not a baseclass, search ends now.
				   ;; Return #:end to end search.
				   #:end))))
      (let ((search-baseclasses
	     (lambda (type)
	       (iterator-until find-in-baseclass
			       (make-field-iterator type)))))
	(or (type-has-field? type field-name)
	    (not (eq? (search-baseclasses type) #:end))))))

  (if (= (type-code type) TYPE_CODE_REF)
      (set! type (type-target type)))
  (set! type (type-strip-typedefs type))

  (assert-type (memq (type-code type) (list TYPE_CODE_STRUCT TYPE_CODE_UNION))
	       type SCM_ARG1 'type-has-field-deep? "struct or union")

  (search-class type))

(define-public (make-enum-hashtable enum-type)
  "Return a hash table from a program's enum type.

  Elements in the hash table are fetched with hashq-ref.

  Arguments:
    enum-type: The enum to compute the hash table for.

  Returns:
    The hash table of the enum.

  Raises:
    wrong-type-arg: The type is not an enum."

  (assert-type (= (type-code enum-type) TYPE_CODE_ENUM)
	       enum-type SCM_ARG1 'make-enum-hashtable "enum")
  (let ((htab (make-hash-table)))
    (for-each (lambda (enum)
		(hash-set! htab (field-name enum) (field-enumval enum)))
	      (type-fields enum-type))
    htab))
