172 lines
6.7 KiB
Racket
172 lines
6.7 KiB
Racket
#lang typed/racket/base
|
|
|
|
(require racket/list
|
|
"lexical-structs.rkt"
|
|
"sets.rkt")
|
|
(provide find-variable
|
|
extend-lexical-environment
|
|
extend-lexical-environment/names
|
|
extend-lexical-environment/boxed-names
|
|
extend-lexical-environment/placeholders
|
|
collect-lexical-references
|
|
lexical-references->compile-time-environment
|
|
place-prefix-mask)
|
|
|
|
|
|
;; find-variable: symbol compile-time-environment -> lexical-address
|
|
;; Find where the variable should be located.
|
|
(: find-variable (Symbol CompileTimeEnvironment -> LexicalAddress))
|
|
(define (find-variable name cenv)
|
|
(: find-pos (Symbol (Listof (U Symbol False)) -> Natural))
|
|
(define (find-pos sym los)
|
|
(cond
|
|
[(eq? sym (car los))
|
|
0]
|
|
[else
|
|
(add1 (find-pos sym (cdr los)))]))
|
|
(let: loop : LexicalAddress ([cenv : CompileTimeEnvironment cenv]
|
|
[depth : Natural 0])
|
|
(cond [(empty? cenv)
|
|
(error 'find-variable "Unable to find ~s in the environment" name)]
|
|
[else
|
|
(let: ([elt : CompileTimeEnvironmentEntry (first cenv)])
|
|
(cond
|
|
[(Prefix? elt)
|
|
(cond [(member name (Prefix-names elt))
|
|
(make-EnvPrefixReference depth
|
|
(find-pos name (Prefix-names elt))
|
|
name)]
|
|
[else
|
|
(loop (rest cenv) (add1 depth))])]
|
|
|
|
[(NamedBinding? elt)
|
|
(cond
|
|
[(eq? (NamedBinding-name elt) name)
|
|
(make-EnvLexicalReference depth #f)]
|
|
[else
|
|
(loop (rest cenv) (add1 depth))])]
|
|
|
|
[(box? elt)
|
|
(cond
|
|
[(eq? (NamedBinding-name (unbox elt)) name)
|
|
(make-EnvLexicalReference depth #t)]
|
|
[else
|
|
(loop (rest cenv) (add1 depth))])]
|
|
|
|
[(eq? elt #f)
|
|
(loop (rest cenv) (add1 depth))]))])))
|
|
|
|
|
|
(: list-index (All (A) A (Listof A) -> (U #f Natural)))
|
|
(define (list-index x l)
|
|
(let: loop : (U #f Natural) ([i : Natural 0]
|
|
[l : (Listof A) l])
|
|
(cond
|
|
[(empty? l)
|
|
#f]
|
|
[(eq? x (first l))
|
|
i]
|
|
[else
|
|
(loop (add1 i) (rest l))])))
|
|
|
|
|
|
(: extend-lexical-environment
|
|
(CompileTimeEnvironment CompileTimeEnvironmentEntry -> CompileTimeEnvironment))
|
|
;; Extends the lexical environment with procedure bindings.
|
|
(define (extend-lexical-environment cenv extension)
|
|
(cons extension cenv))
|
|
|
|
|
|
|
|
(: extend-lexical-environment/names (CompileTimeEnvironment (Listof Symbol) -> CompileTimeEnvironment))
|
|
(define (extend-lexical-environment/names cenv names)
|
|
(append (map make-NamedBinding names) cenv))
|
|
|
|
|
|
(: extend-lexical-environment/boxed-names (CompileTimeEnvironment (Listof Symbol) -> CompileTimeEnvironment))
|
|
(define (extend-lexical-environment/boxed-names cenv names)
|
|
(append (map (inst box NamedBinding)
|
|
(map make-NamedBinding names))
|
|
cenv))
|
|
|
|
|
|
(: extend-lexical-environment/placeholders
|
|
(CompileTimeEnvironment Natural -> CompileTimeEnvironment))
|
|
;; Add placeholders to the lexical environment (This represents what happens during procedure application.)
|
|
(define (extend-lexical-environment/placeholders cenv n)
|
|
(append (build-list n (lambda: ([i : Natural]) #f))
|
|
cenv))
|
|
|
|
|
|
|
|
|
|
(: collect-lexical-references ((Listof LexicalAddress)
|
|
->
|
|
(Listof (U EnvLexicalReference EnvWholePrefixReference))))
|
|
;; Given a list of lexical addresses, computes a set of unique references.
|
|
;; Multiple lexical addresses to a single prefix should be treated identically.
|
|
(define (collect-lexical-references addresses)
|
|
(let: ([prefix-references : (Setof EnvWholePrefixReference) (new-set)]
|
|
[lexical-references : (Setof EnvLexicalReference) (new-set)])
|
|
(let: loop : (Listof (U EnvLexicalReference EnvWholePrefixReference))
|
|
([addresses : (Listof LexicalAddress) addresses])
|
|
(cond
|
|
[(empty? addresses)
|
|
(append (set->list prefix-references) (set->list lexical-references))]
|
|
[else
|
|
(let ([addr (first addresses)])
|
|
(cond
|
|
[(EnvLexicalReference? addr)
|
|
(set-insert! lexical-references
|
|
addr)
|
|
(loop (rest addresses))]
|
|
[(EnvPrefixReference? addr)
|
|
(set-insert! prefix-references
|
|
(make-EnvWholePrefixReference (EnvPrefixReference-depth addr)))
|
|
(loop (rest addresses))]))]))))
|
|
|
|
|
|
|
|
(: lexical-references->compile-time-environment ((Listof EnvReference) CompileTimeEnvironment CompileTimeEnvironment
|
|
(Listof Symbol)
|
|
-> CompileTimeEnvironment))
|
|
;; Creates a lexical environment containing the closure's bindings.
|
|
(define (lexical-references->compile-time-environment refs cenv new-cenv symbols-to-keep)
|
|
(let: loop : CompileTimeEnvironment ([refs : (Listof EnvReference) (reverse refs)]
|
|
[new-cenv : CompileTimeEnvironment new-cenv])
|
|
(cond
|
|
[(empty? refs)
|
|
new-cenv]
|
|
[else
|
|
(let: ([a-ref : EnvReference (first refs)])
|
|
(cond
|
|
[(EnvLexicalReference? a-ref)
|
|
(loop (rest refs)
|
|
(cons (list-ref cenv (EnvLexicalReference-depth a-ref))
|
|
new-cenv))]
|
|
[(EnvWholePrefixReference? a-ref)
|
|
(loop (rest refs)
|
|
(cons (place-prefix-mask
|
|
(ensure-Prefix (list-ref cenv (EnvWholePrefixReference-depth a-ref)))
|
|
symbols-to-keep)
|
|
new-cenv))]))])))
|
|
|
|
(: ensure-Prefix (Any -> Prefix))
|
|
(define (ensure-Prefix x)
|
|
(if (Prefix? x)
|
|
x
|
|
(error 'ensure-Prefix "~s" x)))
|
|
|
|
|
|
|
|
(: place-prefix-mask (Prefix (Listof Symbol) -> Prefix))
|
|
;; Masks elements of the prefix off.
|
|
(define (place-prefix-mask a-prefix symbols-to-keep)
|
|
(make-Prefix
|
|
(map (lambda: ([n : (U Symbol False)])
|
|
(cond [(symbol? n)
|
|
(if (member n symbols-to-keep)
|
|
n
|
|
#f)]
|
|
[else n]))
|
|
(Prefix-names a-prefix)))) |