(module aspect-scheme-2 mzscheme
(require (only (lib "list.ss") foldl foldr))
(define-struct aspect (pc adv))
(define-struct jp (target args))
(define-struct (call-jp jp)( ))
(define-struct (exec-jp jp)( ))
(define-struct (adv-jp jp)( ))
(define-syntax (fluid-let-parameter stx)
(syntax-case stx ()
[(_ ([p v]) e ...)
(syntax (let ([y v])
(let ([swap (lambda ()
(let ([t (p)])
(p y)
(set! y t)))])
(dynamic-wind swap
(lambda () e ...)
swap))))]))
(define dynamic-aspects (make-parameter '()))
(define-syntax (fluid-around stx)
(syntax-case stx ()
[(_ pc adv body ...)
(syntax
(fluid-let-parameter ([dynamic-aspects
(cons (make-aspect pc adv) (dynamic-aspects))])
body ...))]))
(define static-aspects (make-parameter '()))
(define-syntax (around stx)
(syntax-case stx ()
[(_ pc adv body ...)
(syntax
(fluid-let-parameter ([static-aspects (cons (make-aspect pc adv) (static-aspects))])
body ...))]))
(define-syntax (lambda/static stx)
(syntax-case stx ()
[(_ params body ...)
(syntax
(let ([aspects (static-aspects)])
(lambda params
(fluid-let-parameter ([static-aspects aspects])
body ...))))]))
(define toplevel-aspects (make-parameter '()))
(define (toplevel-around pc adv)
(toplevel-aspects (cons (make-aspect pc adv) (toplevel-aspects))))
(define (current-aspects)
(append (dynamic-aspects)
(static-aspects)
(toplevel-aspects)))
(define (jp-context)
(continuation-mark-set->list
(current-continuation-marks)
'joinpoint))
(define-syntax (with-joinpoint stx)
(syntax-case stx ()
[(_ jp body ...)
(syntax ((lambda (x) x)
(with-continuation-mark 'joinpoint jp
(begin body ...))))]))
(define-syntax (app/weave stx)
(syntax-case stx ()
[(_ f a ...) (syntax (app/weave/rt f a ...))]))
(define (app/weave/rt fun-val . arg-vals)
(if (primitive? fun-val)
(apply fun-val arg-vals)
(let ([jp (make-call-jp fun-val arg-vals)])
(with-joinpoint jp
(apply (weave (lambda arg-vals
(with-joinpoint (make-exec-jp fun-val arg-vals)
(apply fun-val arg-vals)))
'() jp (jp-context)
(current-aspects))
arg-vals)))))
(define (weave fun-val jp- jp jp+ aspects)
(foldr (lambda (aspect fun)
(cond
[((aspect-pc aspect) jp- jp jp+)
=> (lambda (ctxt-vals)
(with-joinpoint (make-adv-jp (aspect-adv aspect) ctxt-vals)
(apply ((aspect-adv aspect) fun) ctxt-vals)))]
[else fun]))
fun-val
aspects))
(define ((&& . pcs) jp- jp jp+)
(let loop ([pcs pcs]
[res '()])
(if (null? pcs)
(reverse res)
(let ([r ((car pcs) jp- jp jp+)])
(and r
(loop (cdr pcs) (append (reverse r) res)))))))
(define ((|| . pcs) jp- jp jp+)
(let loop ([pcs pcs])
(and (not (null? pcs))
(or ((car pcs) jp- jp jp+)
(loop (cdr pcs))))))
(define ((! pc) jp- jp jp+)
(and (not (pc jp- jp jp+))
'()))
(define (top? jp- jp jp+)
(and (null? jp+)
'()))
(define (top pc)
(&& pc
(! (cflowbelow pc))))
(define ((below pc) jp- jp jp+)
(and (not (null? jp+))
(pc (cons jp jp-) (car jp+) (cdr jp+))))
(define ((above pc) jp- jp jp+)
(and (not (null? jp-))
(pc (cdr jp-) (car jp-) (cons jp jp+))))
(define (bottom pc)
(&& pc
(! (cflowabove pc))))
(define (bottom? jp- jp jp+)
(and (null? jp-)
'()))
(define (target jp- jp jp+)
(list (jp-target jp)))
(define (args jp- jp jp+)
(jp-args jp))
(define ((some-args as) jp- jp jp+)
(foldl (lambda (a v l)
(if a
(cons v l)
l))
'()
as
(jp-args jp)))
(define ((kind= k?) jp- jp jp+)
(and (k? jp)
'()))
(define call? (kind= call-jp?))
(define exec? (kind= exec-jp?))
(define adv? (kind= adv-jp?))
(define ((target= f) jp- jp jp+)
(and (eq? f (jp-target jp))
'()))
(define (call f)
(&& call?
(target= f)))
(define (exec f)
(&& exec?
(target= f)))
(define (adv a)
(&& adv?
(target= a)))
(define (((cflow-walk step end) pc) jp- jp jp+)
((|| pc
(&& (! end)
(step ((cflow-walk step end) pc)))) jp- jp jp+))
(define (cflowtop pc)
(cflowbelow (top pc)))
(define (cflowbelow pc)
(below ((cflow-walk below top?) pc)))
(define (cflowabove pc)
(above ((cflow-walk above bottom) pc)))
(define (cflowbottom pc)
(cflowbelow (bottom pc)))
(define (cflow pc)
((cflow-walk below top?) pc))
(define (within f)
(cflowbelow (&& (exec f)
(! (cflowabove call?)))))
(provide (all-from-except mzscheme #%app lambda)
(rename app/weave #%app)
(rename #%app app/prim)
fluid-around
(rename lambda/static lambda)
around
toplevel-around
&& || !
top? top below above bottom bottom?
target args some-args
call? exec? adv? call exec adv
cflowtop cflowbelow cflowbottom cflowabove
cflow within
))