#lang s-exp "lang.ss"
(require "env.ss")
(require "toplevel.ss")
(require "helpers.ss")
(require "modules.ss")
(require "rbtree.ss")
(require "labeled-translation.ss")
(require "../collects/moby/runtime/error-struct.ss")
(require "../collects/moby/runtime/permission-struct.ss")
(require "../collects/moby/runtime/binding.ss")
(require "../collects/moby/runtime/stx.ss")
(define-struct pinfo (env modules used-bindings-hash gensym-counter provided-names defined-names
shared-expressions
with-location-emits?
allow-redefinition?
module-resolver module-path-resolver current-module-path
))
(define default-current-module-path "")
(define empty-pinfo
(make-pinfo empty-env
empty
empty-rbtree
0
empty-rbtree
empty-rbtree
empty-rbtree
true
true
default-module-resolver
default-module-path-resolver
default-current-module-path))
(define (pinfo-used-bindings a-pinfo)
(map second (rbtree->list (pinfo-used-bindings-hash a-pinfo))))
(define (pinfo-update-env a-pinfo an-env)
(make-pinfo
an-env
(pinfo-modules a-pinfo)
(pinfo-used-bindings-hash a-pinfo)
(pinfo-gensym-counter a-pinfo)
(pinfo-provided-names a-pinfo)
(pinfo-defined-names a-pinfo)
(pinfo-shared-expressions a-pinfo)
(pinfo-with-location-emits? a-pinfo)
(pinfo-allow-redefinition? a-pinfo)
(pinfo-module-resolver a-pinfo)
(pinfo-module-path-resolver a-pinfo)
(pinfo-current-module-path a-pinfo)))
(define (pinfo-update-provided-names a-pinfo provided-names)
(make-pinfo
(pinfo-env a-pinfo)
(pinfo-modules a-pinfo)
(pinfo-used-bindings-hash a-pinfo)
(pinfo-gensym-counter a-pinfo)
provided-names
(pinfo-defined-names a-pinfo)
(pinfo-shared-expressions a-pinfo)
(pinfo-with-location-emits? a-pinfo)
(pinfo-allow-redefinition? a-pinfo)
(pinfo-module-resolver a-pinfo)
(pinfo-module-path-resolver a-pinfo)
(pinfo-current-module-path a-pinfo)))
(define (pinfo-update-defined-names a-pinfo defined-names)
(make-pinfo
(pinfo-env a-pinfo)
(pinfo-modules a-pinfo)
(pinfo-used-bindings-hash a-pinfo)
(pinfo-gensym-counter a-pinfo)
(pinfo-provided-names a-pinfo)
defined-names
(pinfo-shared-expressions a-pinfo)
(pinfo-with-location-emits? a-pinfo)
(pinfo-allow-redefinition? a-pinfo)
(pinfo-module-resolver a-pinfo)
(pinfo-module-path-resolver a-pinfo)
(pinfo-current-module-path a-pinfo)))
(define (pinfo-update-with-location-emits? a-pinfo with-location-emits?)
(make-pinfo (pinfo-env a-pinfo)
(pinfo-modules a-pinfo)
(pinfo-used-bindings-hash a-pinfo)
(pinfo-gensym-counter a-pinfo)
(pinfo-provided-names a-pinfo)
(pinfo-defined-names a-pinfo)
(pinfo-shared-expressions a-pinfo)
with-location-emits?
(pinfo-allow-redefinition? a-pinfo)
(pinfo-module-resolver a-pinfo)
(pinfo-module-path-resolver a-pinfo)
(pinfo-current-module-path a-pinfo)))
(define (pinfo-update-module-resolver a-pinfo module-resolver)
(make-pinfo (pinfo-env a-pinfo)
(pinfo-modules a-pinfo)
(pinfo-used-bindings-hash a-pinfo)
(pinfo-gensym-counter a-pinfo)
(pinfo-provided-names a-pinfo)
(pinfo-defined-names a-pinfo)
(pinfo-shared-expressions a-pinfo)
(pinfo-with-location-emits? a-pinfo)
(pinfo-allow-redefinition? a-pinfo)
module-resolver
(pinfo-module-path-resolver a-pinfo)
(pinfo-current-module-path a-pinfo)))
(define (pinfo-update-module-path-resolver a-pinfo module-path-resolver)
(make-pinfo (pinfo-env a-pinfo)
(pinfo-modules a-pinfo)
(pinfo-used-bindings-hash a-pinfo)
(pinfo-gensym-counter a-pinfo)
(pinfo-provided-names a-pinfo)
(pinfo-defined-names a-pinfo)
(pinfo-shared-expressions a-pinfo)
(pinfo-with-location-emits? a-pinfo)
(pinfo-allow-redefinition? a-pinfo)
(pinfo-module-resolver a-pinfo)
module-path-resolver
(pinfo-current-module-path a-pinfo)))
(define (pinfo-update-current-module-path a-pinfo current-module-path)
(make-pinfo (pinfo-env a-pinfo)
(pinfo-modules a-pinfo)
(pinfo-used-bindings-hash a-pinfo)
(pinfo-gensym-counter a-pinfo)
(pinfo-provided-names a-pinfo)
(pinfo-defined-names a-pinfo)
(pinfo-shared-expressions a-pinfo)
(pinfo-with-location-emits? a-pinfo)
(pinfo-allow-redefinition? a-pinfo)
(pinfo-module-resolver a-pinfo)
(pinfo-module-path-resolver a-pinfo)
current-module-path))
(define (pinfo-accumulate-shared-expression a-shared-expression a-translation a-pinfo)
(make-pinfo (pinfo-env a-pinfo)
(pinfo-modules a-pinfo)
(pinfo-used-bindings-hash a-pinfo)
(add1 (pinfo-gensym-counter a-pinfo))
(pinfo-provided-names a-pinfo)
(pinfo-defined-names a-pinfo)
(rbtree-insert expression<?
(pinfo-shared-expressions a-pinfo)
a-shared-expression
(make-labeled-translation (pinfo-gensym-counter a-pinfo)
a-translation))
(pinfo-with-location-emits? a-pinfo)
(pinfo-allow-redefinition? a-pinfo)
(pinfo-module-resolver a-pinfo)
(pinfo-module-path-resolver a-pinfo)
(pinfo-current-module-path a-pinfo)))
(define (pinfo-accumulate-defined-binding a-binding a-pinfo)
(cond
[(pinfo-allow-redefinition? a-pinfo)
(make-pinfo (env-extend (pinfo-env a-pinfo) a-binding)
(pinfo-modules a-pinfo)
(pinfo-used-bindings-hash a-pinfo)
(pinfo-gensym-counter a-pinfo)
(pinfo-provided-names a-pinfo)
(rbtree-insert symbol<
(pinfo-defined-names a-pinfo)
(binding-id a-binding)
a-binding)
(pinfo-shared-expressions a-pinfo)
(pinfo-with-location-emits? a-pinfo)
(pinfo-allow-redefinition? a-pinfo)
(pinfo-module-resolver a-pinfo)
(pinfo-module-path-resolver a-pinfo)
(pinfo-current-module-path a-pinfo))]
[else
(make-pinfo (env-extend (pinfo-env a-pinfo) a-binding)
(pinfo-modules a-pinfo)
(pinfo-used-bindings-hash a-pinfo)
(pinfo-gensym-counter a-pinfo)
(pinfo-provided-names a-pinfo)
(rbtree-insert symbol<
(pinfo-defined-names a-pinfo)
(binding-id a-binding)
a-binding)
(pinfo-shared-expressions a-pinfo)
(pinfo-with-location-emits? a-pinfo)
(pinfo-allow-redefinition? a-pinfo)
(pinfo-module-resolver a-pinfo)
(pinfo-module-path-resolver a-pinfo)
(pinfo-current-module-path a-pinfo))]))
(define (pinfo-accumulate-defined-bindings bindings a-pinfo)
(foldl pinfo-accumulate-defined-binding
a-pinfo
bindings))
(define (pinfo-accumulate-module-bindings bindings a-pinfo)
(foldl (lambda (a-binding a-pinfo)
(make-pinfo (env-extend (pinfo-env a-pinfo) a-binding)
(pinfo-modules a-pinfo)
(pinfo-used-bindings-hash a-pinfo)
(pinfo-gensym-counter a-pinfo)
(pinfo-provided-names a-pinfo)
(pinfo-defined-names a-pinfo)
(pinfo-shared-expressions a-pinfo)
(pinfo-with-location-emits? a-pinfo)
(pinfo-allow-redefinition? a-pinfo)
(pinfo-module-resolver a-pinfo)
(pinfo-module-path-resolver a-pinfo)
(pinfo-current-module-path a-pinfo)))
a-pinfo
bindings))
(define (pinfo-accumulate-module a-module a-pinfo)
(make-pinfo (pinfo-env a-pinfo)
(cons a-module (pinfo-modules a-pinfo))
(pinfo-used-bindings-hash a-pinfo)
(pinfo-gensym-counter a-pinfo)
(pinfo-provided-names a-pinfo)
(pinfo-defined-names a-pinfo)
(pinfo-shared-expressions a-pinfo)
(pinfo-with-location-emits? a-pinfo)
(pinfo-allow-redefinition? a-pinfo)
(pinfo-module-resolver a-pinfo)
(pinfo-module-path-resolver a-pinfo)
(pinfo-current-module-path a-pinfo)))
(define (pinfo-accumulate-binding-use a-binding a-pinfo)
(make-pinfo (pinfo-env a-pinfo)
(pinfo-modules a-pinfo)
(rbtree-insert symbol<
(pinfo-used-bindings-hash a-pinfo)
(binding-id a-binding)
a-binding)
(pinfo-gensym-counter a-pinfo)
(pinfo-provided-names a-pinfo)
(pinfo-defined-names a-pinfo)
(pinfo-shared-expressions a-pinfo)
(pinfo-with-location-emits? a-pinfo)
(pinfo-allow-redefinition? a-pinfo)
(pinfo-module-resolver a-pinfo)
(pinfo-module-path-resolver a-pinfo)
(pinfo-current-module-path a-pinfo)))
(define (pinfo-gensym a-pinfo a-label)
(list (make-pinfo (pinfo-env a-pinfo)
(pinfo-modules a-pinfo)
(pinfo-used-bindings-hash a-pinfo)
(add1 (pinfo-gensym-counter a-pinfo))
(pinfo-provided-names a-pinfo)
(pinfo-defined-names a-pinfo)
(pinfo-shared-expressions a-pinfo)
(pinfo-with-location-emits? a-pinfo)
(pinfo-allow-redefinition? a-pinfo)
(pinfo-module-resolver a-pinfo)
(pinfo-module-path-resolver a-pinfo)
(pinfo-current-module-path a-pinfo))
(string->symbol
(string-append (symbol->string a-label)
(number->string (pinfo-gensym-counter a-pinfo))))))
(define (pinfo-permissions a-pinfo)
(local [ (define (unique lst)
(cond [(empty? lst)
empty]
[(member? (first lst)
(rest lst))
(unique (rest lst))]
[else
(cons (first lst)
(unique (rest lst)))]))
(define (member? x lst)
(cond
[(empty? lst)
false]
[(eq? (first lst) x)
true]
[else
(member? x (rest lst))]))]
(unique
(foldl (lambda (a-binding permissions)
(cond [(binding:function? a-binding)
(append (binding:function-permissions a-binding)
permissions)]
[(binding:constant? a-binding)
(append (binding:constant-permissions a-binding)
permissions)]))
empty
(pinfo-used-bindings a-pinfo)))))
(define (get-base-pinfo language)
(cond
[(symbol=? language 'moby)
(pinfo-update-env empty-pinfo
(extend-env/module-binding (get-toplevel-env language)
moby-module-binding))]
[(symbol=? language 'base)
(pinfo-update-env empty-pinfo
(get-toplevel-env language))]))
(define-struct provide-binding:id (stx))
(define-struct provide-binding:struct-id (stx))
(define (provide-binding? x)
(or (provide-binding:id? x)
(provide-binding:struct-id? x)))
(define (provide-binding-stx a-provide-binding)
(cond
[(provide-binding:id? a-provide-binding)
(provide-binding:id-stx a-provide-binding)]
[(provide-binding:struct-id? a-provide-binding)
(provide-binding:struct-id-stx a-provide-binding)]))
(define (pinfo-get-exposed-bindings a-pinfo)
(local [ (define (lookup-provide-binding-in-definition-bindings a-provide-binding)
(local [(define list-or-false
(rbtree-lookup symbol<
(pinfo-defined-names a-pinfo)
(stx-e (provide-binding-stx a-provide-binding))))
(define the-binding
(cond
[(list? list-or-false)
(check-binding-compatibility a-provide-binding
(second list-or-false))]
[else
(raise (make-moby-error (stx-loc (provide-binding-stx a-provide-binding))
(make-moby-error-type:provided-name-not-defined
(stx-e (provide-binding-stx a-provide-binding)))))]))
(define (ref id)
(second (rbtree-lookup symbol< (pinfo-defined-names a-pinfo) id)))]
(cond
[(provide-binding:struct-id? a-provide-binding)
(append (list the-binding
(ref (binding:structure-constructor the-binding))
(ref (binding:structure-predicate the-binding)))
(map ref (binding:structure-accessors the-binding))
(map ref (binding:structure-mutators the-binding))
)]
[else
(list the-binding)])))
(define (check-binding-compatibility a-provide-binding a-binding)
(cond
[(provide-binding:struct-id? a-provide-binding)
(cond [(binding:structure? a-binding)
a-binding]
[else
(raise (make-moby-error
(stx-loc (provide-binding-stx a-provide-binding))
(make-moby-error-type:provided-structure-not-structure
(stx-e (provide-binding-stx a-provide-binding)))))])]
[else
a-binding]))]
(rbtree-fold (pinfo-provided-names a-pinfo)
(lambda (id a-provide-binding acc)
(append (lookup-provide-binding-in-definition-bindings a-provide-binding)
acc))
empty)))
(provide/contract [struct pinfo ([env env?]
[modules (listof module-binding?)]
[used-bindings-hash rbtree?]
[gensym-counter number?]
[provided-names rbtree?]
[defined-names rbtree?]
[shared-expressions rbtree?]
[with-location-emits? boolean?]
[allow-redefinition? boolean?]
[module-resolver (module-name? . -> . (or/c module-binding? false/c))]
[module-path-resolver (module-path? module-path? . -> . module-name?)]
[current-module-path module-path?])]
[empty-pinfo pinfo?]
[get-base-pinfo (symbol? . -> . pinfo?)]
[pinfo-used-bindings (pinfo? . -> . (listof binding?))]
[pinfo-accumulate-module (module-binding? pinfo? . -> . pinfo?)]
[pinfo-accumulate-defined-binding (binding? pinfo? . -> . pinfo?)]
[pinfo-accumulate-binding-use (binding? pinfo? . -> . pinfo?)]
[pinfo-accumulate-defined-bindings ((listof binding?) pinfo? . -> . pinfo?)]
[pinfo-accumulate-module-bindings ((listof binding?) pinfo? . -> . pinfo?)]
[pinfo-accumulate-shared-expression (expression? string? pinfo? . -> . pinfo?)]
[pinfo-update-provided-names (pinfo? rbtree? . -> . pinfo?)]
[pinfo-update-defined-names (pinfo? rbtree? . -> . pinfo?)]
[pinfo-update-env (pinfo? env? . -> . pinfo?)]
[pinfo-update-with-location-emits? (pinfo? boolean? . -> . pinfo?)]
[pinfo-update-module-resolver (pinfo? (module-name? . -> . (or/c module-binding? false/c))
. -> . pinfo?)]
[pinfo-update-module-path-resolver (pinfo? (module-path? module-path? . -> . (or/c module-name? false/c))
. -> . pinfo?)]
[pinfo-update-current-module-path (pinfo? module-path? . -> . pinfo?)]
[pinfo-gensym (pinfo? symbol? . -> . (list/c pinfo? symbol?))]
[pinfo-permissions (pinfo? . -> . (listof permission?))]
[pinfo-get-exposed-bindings (pinfo? . -> . (listof binding?))]
[struct provide-binding:id ([stx stx?])]
[struct provide-binding:struct-id ([stx stx?])]
[provide-binding? (any/c . -> . boolean?)]
[provide-binding-stx (provide-binding? . -> . stx?)])