1 Installing Aspect Scheme
1.1 Installing the Aspect Scheme Language
1.2 Programming using the planet package
2 Aspect Scheme - the language
3 Pointcuts
3.1 Fundamental Pointcuts
call
exec
advice
3.2 Binding Pointcuts
target
args
some-args
with-args
3.3 Contextual Pointcuts
cflowtop
cflowbelow
cflowabove
cflowbottom
cflow
3.4 Pointcut Combinators
&&
||
!
3.5 Primitive Pointcuts
3.5.1 Join Point Stream
focus-jp
4 Advice
5 Aspects
5.1 Static Aspects around
around
5.1.1 Common Static Aspect Control Structures
before
after-throwing
after-returning
after-
5.2 Fluid Aspects fluid-around
fluid-around
5.2.1 Common Fluid- Aspect Control Structures
fluid-before
fluid-after-throwing
fluid-after-returning
fluid-after
5.3 Top-Level Aspects top-level-around
top-level-around
5.3.1 Common Top-Level Aspect Control Structures
top-level-before
top-level-after-throwing
top-level-after-returning
top-level-after
Version: 4.0.2

AspectScheme

 #lang aspectscheme

This is the documentation for the implementation of aspectscheme language, introduced in Aspects in Higher-Order Languages.

It can be found online at .

The language implementation can be found at .

    1 Installing AspectScheme

      1.1 Installing the AspectScheme Language

      1.2 Programming using the planet package

    2 AspectScheme - the language

    3 Pointcuts

      3.1 Fundamental Pointcuts

      3.2 Binding Pointcuts

      3.3 Contextual Pointcuts

      3.4 Pointcut Combinators

      3.5 Primitive Pointcuts

        3.5.1 Join Point Stream

    4 Advice

    5 Aspects

      5.1 Static Aspects around

        5.1.1 Common Static Aspect Control Structures

      5.2 Fluid Aspects fluid-around

        5.2.1 Common Fluid- Aspect Control Structures

      5.3 Top-Level Aspects top-level-around

        5.3.1 Common Top-Level Aspect Control Structures

1 Installing AspectScheme

AspectScheme comes in two forms:

1.1 Installing the AspectScheme Language

Use the PLT Menu item File -> Install to install the provided aspectscheme.plt file. Then select AspectScheme as your default language; or write your code in a module based on the aspectscheme language.

To enable this language in DrScheme, under the Language menu, select Choose Language.... Under the section Experimental Languages, you will find the following language:

It is also available as the module language aspectscheme.

1.2 Programming using the planet package

Preface your code with

(require (planet "aspectscheme.ss" ("dutchyn" "aspectscheme.plt" 4 0)))

2 AspectScheme - the language

AspectScheme is derived from the scheme language, providing support for pointcuts and advice aspect-oriented programming.

AspectScheme considers procedure applications as join points, within a context of in-progress join points. These join points in context are recognized by pointcuts – predicates over the join point and context (represented as a list of join points). When a pointcut matches, advice transforms the join point into a new procedure.

3 Pointcuts

Pointcuts identify join points, principled locations in the execution of the program. Derived from continuations, the fundamental join points for a Scheme program are procedure calls, procedure executions, and by extension, advice executions.

3.1 Fundamental Pointcuts

(call _proc)  (or/c '() #f)

  _proc : procedure?

recognizes a call to proc

(exec _proc)  (or/c '() #f)

  _proc : procedure?

recognizes an execution of proc

(advice _proc)  (or/c '() #f)

  _proc : procedure?

recognizes an execution of advice proc

3.2 Binding Pointcuts

These pointcuts expose the arguments available at the matched join point.

target : [pointcut]

exposes the target (procedure or advice) of the matched join point as part of the context values

args : pointcut

] exposes the entire list of arguments to the matched join point as part of the context values

(some-args as)  pointcut?

  as : (listof boolean?)

exposes the selected (by #t) items in the context matched.

(with-args _val ...)  pointcut?

  _val : any?

appends additional values to the context

3.3 Contextual Pointcuts

In addition, join points may be filtered by control-flow context (i.e. continuation nesting).

(cflowtop _pc)  (or/c (listof any?) #f)

  _pc : pointcut?

recognizes all join points which are below a join point matching pc, but with no intervening join points matching that pointcut. Values bound by the pointcut are inserted into the context argument of the advice.

(cflowbelow _pc)  (or/c (listof any?) #f)

  _pc : pointcut?

Recognizes all join points which are strictly below a join point matching pc. The values bound by the pointcut are taken from the nearest enclosing join point that matches pc. Using this construct, one may peel away join point context from the current join point upwards toward the top level. Nesting these allows one to access levels of nesting from the inside to the outside.

(cflowabove _pc)  (or/c (listof any?) #f)

  _pc : pointcut?

recognizes join points which are strictly above a join point matching pc. The values bound by the pointcut are taken from the nearest enclosed join point that matches pc. Using this construct, one may worm back into join point context toward the currrently instantiated join point. This is useful for locating outermost executions from a known contextual join point identified by cflowtop or cflowbelow. Nestin these allows one to access levels of nesting from the outside to the inside.

(cflowbottom _pc)  (or/c (listof any?) #f)

  _pc : pointcut?

recognizes all join points which do not enclose another join point that matches

(cflow _pc)  (or/c (listof any?) #f)

  _pc : pointcut?

(for compatibility) matches join points at the current level or any below; note that context values exposed by the binding join points are not replaceable in a proceed (unlike AspectJ), the replaceable arguments are supplied separately to the advice.

3.4 Pointcut Combinators

(&& _pc ...)  (or/c (listof any?) #f)

  _pc : pointcut?

merges many sub-pointcuts into one where all sub-pointcuts must match; context is merged from left-to-right to expose the context from all of the sub-pointcuts

(|| _pc ...)  (or/c (listof any?) #f)

  _pc : pointcut?

merges many sub-pointcuts into one where at least one of the sub-pointcuts must match; context is exposed in a short-circuit fashion: sub-pointcuts are tested until the first match, and its context is exposed. All sub-pointcuts must return the same number of context values (the some-args and with-args pointcuts may help satisfy this restriction); but, this is not statically checked.

(! _pc)  (or/c '() #f)

  _pc : pointcut?

matches any join point that does not match the given sub-pointcut. Note that all context built up by the sub-pointcut is discarded.

3.5 Primitive Pointcuts

All the above pointcuts are actually derived from a few primitive pointcuts, using the higher-order property of pointcuts.

3.5.1 Join Point Stream

The primitive level pointcuts actually know about the join point stream. The join point stream is the list of join points currently extant between the start of program execution (the top) and the current expression to be evaluated (the bottom). As suggested by the connection between join points and continuations (hence the use of continuation-marks), the stream of join points corresponds with the continuations awaiting their values. Whenever a new join point is created, it needs to be matched against the available (dynamic and static) aspects. But that matching process can entail join points in the rest of the stream from the bottom to the top. In particular, cflowbelow forces a sub-match that climbs up the join point stream toward the top, looking for the first match in the awaiting join points. That is, cflowbelow tests whether the current join point of interest is below one that corresponds to the sub-match. Naturally, the cflowbelow sub-match is another match, looking at join points of interest and moving upwards.

AspectScheme reifies the join point stream for any joinpoint matcher (i.e. pointcut) as three arguments jp- jp jp+:

Dually, this could all be phrased in terms of cflowabove, where the join point of interest traversal moves down the list.

For each pointcut, the join point stream starts as '() njp jp-stream) where njp is the newly-created join point, and jp-stream is the stream of join points leading to njp.

Each join point knows (has access to)

A pointcut is a function from the jp stream to a list of context values – the targets and arguments (as appropriate) from the join points when they match.

((focus-jp _p?) _jp- _jp _jp+)  (or/c (listof any) #f)

  _p? : procedure?

  _jp- : (listof joinpoint?)

  _jp : joinpoint

  _jp+ : (listof joinpoint?)

simply focuses the join point predicate onto _jp, the join point of interest.

The primitive pointcuts call, exec, adv are a simple combination of focus-jp and a tag check of the join point of interest.

The primitive pointcuts target and args simply return take the appropriate fields of the join point of interest as a list of context values.

With two step functions,

, two pointcuts that recognize the end of the join point stream

and a simple iterator, cflow-walk, that takes a step function and a end recognizer, all of the control flow pointcuts are constructed.

4 Advice

(lambda (proceed) (lambda (ctxt_id ...) (lambda (arg_id ...) body)))

is the general form of advice. It takes

and performs the desired semantic behaviour, including continuing the computation (potentially with new arguments) via

(proceed new_arg ...)

zero, one, or multiple times; or performing some completely different operation.

It is important to note that context values and current join point arguments are disjoint in our model. This makes clear what values are actually replacable by an around advice. Context values are not, but join point arguments are; hence the proceed only takes arguments. In contrast, AspectJ does not separate these, and pretends to proceed with new context values; but they’re not used: only the values bound in arguments are actually seen as changed. This can get tricky with cflow because it might match

5 Aspects

Pointcuts and advice are combined by an aspect declaration. These combinations can be static, dynamic, or top-level.

5.1 Static Aspects around

(around [_pc pointcut?] [_adv advice?] _body ...)

indicates whenever the pointcut pc matches within the static scope of the body ..., the advice adv is given control. These aspects apply lexically; outside of the lexical scope of the body ... they do not apply.

5.1.1 Common Static Aspect Control Structures

For convenience, several simpler versions are provided to satisfy common situations of performing semantic actions in addition to the usual ones. In these cases, proceed may not be called, although it must be present in the advice definition.

(before _pc _adv _body ...)

at join points matching pc, the advice adv is performed, then the join point continues with the original arguments.

(after-throwing _pc _adv _body ...)

at join points statically within body ... matching pc, the join point proceeds with the original arguments, and if an exception is thrown, the advice adv is performed; then the exception is re-thrown.

(after-returning _pc _adv _body ...)

at join points statically within body ... matching pc, the join point proceeds with the original arguments, and if an exception is not thrown, the advice adv is performed; then result returned by the join point is returned.

(after- _pc _adv _body ...)

at join points statically within body ... matching pc, the join point proceeds with the original arguments, and if an exception is not thrown, the advice adv is performed; then result returned by the join point is returned. If an exception is thrown within the proceeding join point, the advice adv is performed and then the exception is re-thrown.

5.2 Fluid Aspects fluid-around

(fluid-around [_pc pointcut?] [_adv advice?] body ...)

just like around, but using dynamic scoping. Hence, the implementation essentially uses fluid-let to provide this facility. Unfortunately, fluid-let fails across module boundaries, so a replacement fluid-let-parameter is implemented using dynamic-wind and let-parameter.

5.2.1 Common Fluid- Aspect Control Structures

(fluid-before _pc _adv _body)

(fluid-after-throwing _pc _adv _body)

(fluid-after-returning _pc _adv _body)

(fluid-after _pc _adv _body)

5.3 Top-Level Aspects top-level-around

(top-level-around [_pc pointcut?] [_adv advice?])

These aspects apply for the remainder of the program. They are installed at the top level and continue until execution terminates.

5.3.1 Common Top-Level Aspect Control Structures

(top-level-before _pc _adv)

(top-level-after-throwing _pc _adv)

(top-level-after-returning _pc _adv)

(top-level-after _pc _adv)