#lang racket/base
(require "../private/planet.rkt")
(require
(for-syntax
racket/base
racket/list
racket/match
racket/block
planet/util
syntax/parse
syntax/boundmap
racket/require-transform
(cce syntax)
(cce values)
(cce text)
"static-rep.rkt"
"syntax-meta.rkt"
"../lang/acl2-module-v.rkt"
"../proof/proof.rkt"
"../proof/syntax.rkt")
mzlib/etc
(cce require-provide)
"keywords.rkt"
"dynamic-rep.rkt"
"../lang/defun.rkt"
"../lang/check.rkt"
"../lang/theorems.rkt")
(provide module-macro)
(define-for-syntax (matcher . ids)
(let* ([table (make-free-identifier-mapping)])
(for ([id ids])
(free-identifier-mapping-put! table id #t))
(lambda (stx)
(syntax-case stx ()
[(name . _)
(identifier? #'name)
(free-identifier-mapping-get table #'name (lambda () #f))]
[_ #f]))))
(define-for-syntax (expand-module-export port id)
(let* ([source (port/static-source port)]
[concrete (export/static-concrete port)]
[internals (port/static-sig-names/internal port)]
[externals (port/static-sig-names/external port)]
[arguments (port/static-sig-args port)])
(with-syntax ([exp/dynamic id]
[puts externals]
[gets internals])
(values
concrete
(syntax/loc source
(define-values ()
(begin
(for ([sym (in-list 'puts)]
[fun (in-list (unchecked-arity (list . gets)))])
(interface/dynamic-put-function! exp/dynamic sym fun))
(values))))
#'(begin)))))
(define-for-syntax (expand-module-import port id)
(let* ([source (port/static-source port)]
[abstract (import/static-abstract port)]
[internals (port/static-sig-names/internal port)]
[externals (port/static-sig-names/external port)]
[arguments (port/static-sig-args port)]
[axioms (port/static-con-names/internal port)])
(with-syntax ([imp/dynamic id]
[gets externals]
[(put ...) internals]
[(tmp ...) (generate-temporaries externals)]
[(args ...) arguments]
[axs axioms])
(values
abstract
(syntax/loc source
(begin
(define-values [tmp ...]
(apply values
(for/list ([sym (in-list 'gets)])
(interface/dynamic-get-function imp/dynamic sym))))
(mutual-recursion (defun put args (tmp . args)) ...)
(define-theorems "axiom" . axs)))
#'(begin)))))
(define-for-syntax (expand-definition stx)
(syntax-case* stx (include-book :dir :system :teachpacks) text=?
[(include-book file :dir :teachpacks)
(string-literal? #'file)
(let*-values ([(module-path)
(datum->syntax stx (make-teachpack-require-syntax
(text->string #'file ".rkt")))]
[(imports sources) (expand-import module-path)]
[(names) (map import-local-id imports)])
(with-syntax ([spec module-path]
[(name ...) names]
[(temp ...) (generate-temporaries names)])
(values stx
(syntax/loc stx (rename-below [temp name] ...))
(syntax/loc stx (require (rename-in spec [name temp] ...))))))]
[(include-book file :dir :system)
(string-literal? #'file)
(values stx (syntax/loc stx (begin)) (syntax/loc stx (begin)))]
[(include-book file)
(string-literal? #'file)
(syntax-error
stx
"modules cannot include local books; convert the book to a module")]
[(include-book . _)
(syntax-error
stx
"expected a book name with :dir :system or :dir :teachpacks")]
[_ (values stx stx (syntax/loc stx (begin)))]))
(define-for-syntax (expand-module-body imp exp body)
(cond
[(import/static? body) (expand-module-import body imp)]
[(export/static? body) (expand-module-export body exp)]
[else (expand-definition body)]))
(define-for-syntax (expand-dynamic stx)
(syntax-case stx ()
[(_ static-name)
(let* ([import-name #'imp/dynamic]
[export-name #'exp/dynamic]
[mod (syntax->meta #:message "not a module" #'static-name)]
[source (module/static-source mod)])
(let*-values ([(defs runs reqs)
(for/lists [defs runs reqs]
([stx (in-list (module/static-body mod))])
(expand-module-body import-name export-name stx))])
(with-syntax ([(run ...) runs]
[(req ...) reqs]
[dynamic-name (refresh-identifier
(module/static-dynamic mod))])
(annotate-part
(make-part
(syntax-e #'static-name)
(syntax->loc stx)
(map syntax->term defs))
(syntax/loc source
(begin
req ...
(define dynamic-name
(make-module/dynamic
(lambda (imp/dynamic)
(define exp/dynamic (empty-interface/dynamic))
(begin-below run ...)
(interface/dynamic-join
exp/dynamic
imp/dynamic))))))))))]))
(define-for-syntax (parse-port make-port/static rev-ports stx)
(syntax-case stx ()
[(_ ifc [ext int] ...)
(let* ([ifc (syntax->meta #:message "not an interface" #'ifc)])
(make-port/static
stx
ifc
(map cons
(syntax->list #'(ext ...))
(syntax->list #'(int ...)))
(map (lambda (inc)
(or
(findf (lambda (port)
(interface/static-external=?
inc (port/static-interface port)))
rev-ports)
(syntax-error stx
"no im/export of ~a (required by ~a)"
(syntax-e (interface/static-name inc))
(syntax-e (interface/static-name ifc)))))
(interface/static-includes ifc))))]))
(define-for-syntax (parse-body prior stxs)
(match stxs
[(list) (list)]
[(list* stx stxs)
(syntax-case stx (import export)
[(import . _)
(block
(define port
(parse-port
make-import/static
(filter import/static? prior)
stx))
(cons port
(parse-body (cons port prior) stxs)))]
[(export . _)
(block
(define port
(parse-port
make-export/static
prior
stx))
(cons port
(parse-body (cons port prior) stxs)))]
[_ (cons stx (parse-body prior stxs))])]))
(define-for-syntax (expand-static stx)
(syntax-case stx ()
[(_ static-name original def ...)
(syntax/loc #'original
(define-syntax static-name
(make-syntax-meta
(make-module/static
#'static-name
#'dynamic-name
#'original
(parse-body null (list (quote-syntax def) ...)))
(expand-keyword "cannot be used as an expression"))))]))
(define-for-syntax (expand-module stx)
(parameterize ([current-syntax stx])
(syntax-case stx ()
[(_ static-name . body)
(parameterize ([current-syntax stx])
(with-syntax ([original stx])
(syntax/loc stx
(begin
(define-syntaxes (define-static) expand-static)
(define-syntaxes (define-dynamic) expand-dynamic)
(define-static static-name original . body)
(define-dynamic static-name)))))])))
(define-syntax module-macro expand-module)