#lang s-exp "lang.ss"
(require "env.ss")
(require "pinfo.ss")
(require "helpers.ss")
(require "modules.ss")
(require "permission.ss")
(define (program-analyze a-program)
(program-analyze/pinfo a-program (get-base-pinfo 'base)))
(define (program-analyze/pinfo a-program pinfo)
(local [(define pinfo-1
(program-analyze-collect-definitions a-program pinfo))]
(program-analyze-uses a-program pinfo-1)))
(define (program-analyze-collect-definitions a-program pinfo)
(cond [(empty? a-program)
pinfo]
[else
(local [(define updated-pinfo
(cond [(defn? (first a-program))
(definition-analyze-collect-definitions (first a-program) pinfo)]
[(test-case? (first a-program))
pinfo]
[(library-require? (first a-program))
(require-analyze (second (stx-e (first a-program))) pinfo)]
[(expression? (first a-program))
pinfo]))]
(program-analyze-collect-definitions (rest a-program)
updated-pinfo))]))
(define (program-analyze-uses a-program pinfo)
(cond [(empty? a-program)
pinfo]
[else
(local [(define updated-pinfo
(cond [(defn? (first a-program))
(definition-analyze-uses (first a-program) pinfo)]
[(test-case? (first a-program))
pinfo]
[(library-require? (first a-program))
pinfo]
[(expression? (first a-program))
(expression-analyze-uses (first a-program)
pinfo
(pinfo-env pinfo))]))]
(program-analyze-uses (rest a-program)
updated-pinfo))]))
(define (bf name module-path arity vararity? java-string)
(make-binding:function name module-path arity vararity? java-string empty false))
(define (definition-analyze-collect-definitions a-definition pinfo)
(case-analyze-definition
a-definition
(lambda (id args body)
(pinfo-accumulate-binding (bf (stx-e id)
false
(length args)
false
(symbol->string
(identifier->munged-java-identifier (stx-e id))))
pinfo))
(lambda (id expr)
(pinfo-accumulate-binding (make-binding:constant (stx-e id)
(symbol->string
(identifier->munged-java-identifier (stx-e id)))
empty)
pinfo))
(lambda (id fields)
(pinfo-accumulate-bindings (struct-definition-bindings (stx-e id)
(map stx-e fields))
pinfo))))
(define (struct-definition-bindings id fields)
(local [(define constructor-id
(string->symbol (string-append "make-" (symbol->string id))))
(define constructor-binding
(bf constructor-id false (length fields) false
(symbol->string
(identifier->munged-java-identifier constructor-id))))
(define predicate-id
(string->symbol (string-append (symbol->string id) "?")))
(define predicate-binding
(bf predicate-id false 1 false
(symbol->string
(identifier->munged-java-identifier predicate-id))))
(define selector-ids
(map (lambda (f)
(string->symbol (string-append (symbol->string id) "-" (symbol->string f))))
fields))
(define selector-bindings
(map (lambda (sel-id)
(bf sel-id false 1 false
(symbol->string
(identifier->munged-java-identifier sel-id))))
selector-ids))
(define mutator-ids
(map (lambda (f)
(string->symbol (string-append "set-" (symbol->string id) "-" (symbol->string f) "!")))
fields))
(define mutator-bindings
(map (lambda (mut-id)
(bf mut-id false 2 false
(symbol->string (identifier->munged-java-identifier mut-id))))
mutator-ids))]
(append (list constructor-binding) (list predicate-binding) selector-bindings mutator-bindings)))
(define (definition-analyze-uses a-definition pinfo)
(case-analyze-definition a-definition
(lambda (id args body)
(function-definition-analyze-uses id args body pinfo))
(lambda (id expr)
(expression-analyze-uses expr pinfo (pinfo-env pinfo)))
(lambda (id fields)
pinfo)))
(define (function-definition-analyze-uses fun args body pinfo)
(local [(define env-1 (pinfo-env pinfo))
(define env-2
(env-extend env-1 (bf (stx-e fun) false (length args) false
(symbol->string (identifier->munged-java-identifier (stx-e fun))))))]
(lambda-expression-analyze-uses args body (pinfo-update-env pinfo env-2))))
(define (lambda-expression-analyze-uses args body pinfo)
(local [(define env-1 (pinfo-env pinfo))
(define env-2
(foldl (lambda (arg-id env)
(env-extend env (make-binding:constant (stx-e arg-id)
(symbol->string
(stx-e arg-id))
empty)))
env-1
args))]
(expression-analyze-uses body pinfo env-2)))
(define (expression-analyze-uses an-expression pinfo env)
(cond
[(stx-begins-with? an-expression 'local)
(local-expression-analyze-uses an-expression pinfo env)]
[(stx-begins-with? an-expression 'begin)
(begin-expression-analyze-uses an-expression pinfo env)]
[(stx-begins-with? an-expression 'if)
(if-expression-analyze-uses an-expression pinfo env)]
[(stx-begins-with? an-expression 'and)
(local [(define exprs (rest (stx-e an-expression)))]
(foldl (lambda (e p) (expression-analyze-uses e p env))
pinfo
exprs))]
[(stx-begins-with? an-expression 'or)
(local [(define exprs (rest (stx-e an-expression)))]
(foldl (lambda (e p) (expression-analyze-uses e p env))
pinfo
exprs))]
[(stx-begins-with? an-expression 'lambda)
(local [(define args (stx-e (second (stx-e an-expression))))
(define body (third (stx-e an-expression)))]
(lambda-expression-analyze-uses args body pinfo))]
[(number? (stx-e an-expression))
pinfo]
[(string? (stx-e an-expression))
pinfo]
[(boolean? (stx-e an-expression))
pinfo]
[(char? (stx-e an-expression))
pinfo]
[(symbol? (stx-e an-expression))
(cond
[(env-contains? env (stx-e an-expression))
(pinfo-accumulate-binding-use (env-lookup env (stx-e an-expression)) pinfo)]
[else
pinfo])]
[(stx-begins-with? an-expression 'quote)
pinfo]
[(pair? (stx-e an-expression))
(application-expression-analyze-uses an-expression pinfo env)]))
(define (local-expression-analyze-uses an-expression pinfo env)
(local [(define defns (stx-e (second (stx-e an-expression))))
(define body (third (stx-e an-expression)))
(define nested-pinfo (foldl (lambda (a-defn a-pinfo)
(definition-analyze-uses a-defn a-pinfo))
pinfo
defns))]
(pinfo-update-env
(expression-analyze-uses body
nested-pinfo
(pinfo-env nested-pinfo))
(pinfo-env pinfo))))
(define (begin-expression-analyze-uses an-expression pinfo env)
(foldl (lambda (e p)
(expression-analyze-uses e p env))
pinfo
(rest (stx-e an-expression))))
(define (if-expression-analyze-uses an-expression pinfo env)
(local [(define test (second (stx-e an-expression)))
(define consequent (third (stx-e an-expression)))
(define alternative (fourth (stx-e an-expression)))]
(foldl (lambda (e p) (expression-analyze-uses e p env))
pinfo
(list test consequent alternative))))
(define (application-expression-analyze-uses an-expression pinfo env)
(local [(define updated-pinfo
(foldl (lambda (e p)
(expression-analyze-uses e p env))
pinfo
(stx-e an-expression)))
(define (handle-image-url-kludge expr a-pinfo env)
(cond
[(and (stx-begins-with? expr 'open-image-url)
(stx:list? expr)
(= (length (stx-e expr)) 2)
(string? (stx-e (second (stx-e expr))))
(env-contains? env 'open-image-url)
(binding:function? (env-lookup env 'open-image-url))
(string=? (binding:function-java-string (env-lookup env 'open-image-url))
"plt.world.Kernel.openImageUrl"))
(local [(define b (env-lookup env 'open-image-url))]
(pinfo-accumulate-binding-use (make-binding:function (string->symbol
(format "~a-~a" (binding:function-name b)
(stx-e (second (stx-e expr)))))
(binding:function-module-source b)
(binding:function-min-arity b)
(binding:function-var-arity? b)
(binding:function-java-string b)
(list (make-permission:open-image-url
(stx-e (second (stx-e expr)))))
(binding:function-cps? b))
a-pinfo))]
[else a-pinfo]))]
(handle-image-url-kludge an-expression updated-pinfo env)))
(define (require-analyze require-path pinfo)
(local [(define (loop modules)
(cond
[(empty? modules)
(syntax-error (format "Moby doesn't know about module ~s yet"
(stx-e require-path))
require-path)]
[(string=? (stx-e require-path)
(module-binding-source (first modules)))
(pinfo-accumulate-module
(first modules)
(pinfo-accumulate-bindings
(module-binding-bindings (first modules))
pinfo))]
[else
(loop (rest modules))]))]
(loop known-modules)))
(provide/contract [program-analyze (program? . -> . pinfo?)]
[program-analyze/pinfo (program? pinfo? . -> . pinfo?)])