[Mono-list] Implementing attribute-based code generation

Kamil Skalski nazgul@nemerle.org
Thu, 13 Jan 2005 15:10:22 +0100


Dnia czwartek, 13 stycznia 2005 14:47, Stephen Touset napisa=C5=82:
> Shawn Vose wrote:
> > Use System.Reflection to read available methods, attributes and
> > properties for a dll. You can use it to do so at runtime. I know there
> > has been a few questions and answers on Relection in the archives
>
> What I'm trying to accomplish is slightly different, and cannot be done
> with the current design of attributes.

Of course it is reasonable that you want to stick in C# and you will have t=
o=20
change architecture of mcs to accomplish it. Implementation, which you are=
=20
describing is exactly what we do in Nemerle. Compiler is looking at=20
attrubutes and for some of them it runs a macro operating on compiler's=20
internal structures.

So instead (besides) of attatching some metadata to generated assembly, it=
=20
runs external program modifing method's body. Seeing this feature in mcs=20
would be nice.=20
Probably a little problem would be easy generation of code - you will have =
to=20
use mcs's API to build syntax trees. In Nemerle we have special syntax for=
=20
this, so implementation of pre-condition macro Requires is:

  /// Example: [Requires (i !=3D 4 && boo (), throw ArgumentException ())] =
foo=20
(i : int) : void { ... }
  /// Example: [Requires (i !=3D 4)] foo (i : int) : void { ... }
  [Nemerle.MacroUsage (Nemerle.MacroPhase.BeforeInheritance,
                       Nemerle.MacroTargets.Method,
                       Inherited =3D true, AllowMultiple =3D true)]
  macro Requires (_ : TypeBuilder, m : ParsedMethod, assertion, otherwise =
=3D=20
null)
  {
    def check =3D
      if (otherwise !=3D null)
        <[ unless ($assertion) $otherwise ]>
      else
        <[ assert ($assertion, "The ``Requires'' contract of method `" +
                   $(m.name.GetName ().Id : string) + "' has been=20
violated.") ]>;
       =20
    m.Body =3D <[
      $check;
      $(m.Body)
    ]>
  }

Here, generated program it is quite small, but in case of invariant it is m=
uch=20
more complex.

In future we are planing to provide a C# fronend to Nemerle compiler, so yo=
u=20
would have Design By Contrace also in pure C#.

>
> As an example, I want to be able to place preconditions and
> postconditions on methods and invariants on classes. These attributes
> need to follow inheritance rules for Design By Contract as well:
> postconditions are logically ORed with any inherited postconditions from
> base classes, while postconditions and invariants are logically ANDed
> with inherited ones from their base classes. This is not possible with
> the current implementation of attributes.
>
> Nor is the ability for an attribute to consitently, automatically, and
> predictable modify the way a method or class works. Attributes cannot
> access the methods they belong to, nor can they generate code
> dynamically. There is also no way to have them transparently invoke code
> upon method execution.
>
> Because of this, something would need to be written to have certain
> attributes generate code in the methods they modify, or in all the
> methods of the classes they modify. Also, these attributes would need to
> be inherited upon their base classes as well, automatically. A script
> could theoretically do it, but that would require a lot of additional
> work, reimplementing a C# parser that already exists with Mono.
>
> If you can find a way to do this with System.Reflection, please let me
> know. It would save me a bundle of time.
> _______________________________________________
> Mono-list maillist  -  Mono-list@lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-list