;;; Modules
;;; Copyright (C) 2026 David Thompson <dave@spritely.institute>
;;;
;;; 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:
;;;
;;; Macros for runtime module system.
;;;
;;; Code:

(library (hoot module-syntax)
  (export define-module use-modules)
  (import (hoot cond-expand)
          (hoot interfaces)
          (hoot library)
          (hoot lists)
          (hoot modules)
          (hoot pairs)
          (hoot syntax)
          (hoot syntax-objects)
          (ice-9 match))

  (cond-expand
   (runtime-modules
    (define (define-module* modname ifaces exports)
      (let ((mod (resolve-module (the-root-module) modname #:define? #t)))
        (for-each (lambda (iface) (import-interface! mod iface)) ifaces)
        (for-each (match-lambda
                    ((local-name . exported-name)
                     (module-export! mod exported-name local-name #:replace? #t)))
                  exports)
        mod))

    (define-syntax define-module
      (lambda (stx)
        (match (parse-guile-library stx #'() #f)
          (($ <library> src name version trusted? duplicates exports
                        replacements isets body)
           (with-syntax (((name ...) (datum->syntax stx name))
                         ((iface ...) (parse-isets/syntax stx isets))
                         ((export ...) (datum->syntax stx exports)))
             #'(define-module* '(name ...) (list iface ...) '(export ...)))))))

    (define-syntax use-modules
      (lambda (stx)
        (syntax-case stx ()
          ((use-modules import-spec ...)
           #`(let ((mod (current-module use-modules)))
               (for-each (lambda (iface) (import-interface! mod iface))
                         (list #,@(parse-isets/syntax
                                   stx
                                   (map parse-guile-import
                                        #'(import-spec ...)))))))))))
   (else
    (define-syntax-rule (define-module . args)
      (syntax-error "No run-time module registry; recompile with -gruntime-modules"))
    (define-syntax-rule (use-modules . args)
      (syntax-error "No run-time module registry; recompile with -gruntime-modules")))))
