Some CodeDom fun for you…


Check out the BCL site… we just posted some new CodeDom samples:

 

MSIL Code Provider
The Microsoft Intermediate Language (MSIL) code provider takes a CodeDom tree and generates MSIL syntax. MSIL code provider generates all the CodeDom elements that are part of the 1.1 conformance spec. MSIL code provider generates code for most of the CodeDom types that shipped in V1.1.   


Subset Code Provider
This CodeDom provider consumes CodeDom trees in the way the C# code provider does, but whenever a node that does not fall into the subset is encountered, it emits a #error in the generated code. This will alert to the CodeDom tree builder of any place in their code where they don’t meet subset conformance.   

 

Comments (13)

  1. Andy says:

    Would it be possible for this to be converted into a .NET v1.1 code provider? I didn’t realize that it required .NET v2.0 until I went to compile it with .NET v1.1, and I got a ton of compilation errors.

    It seems like since it generates .NET v1.1 code (at least that’s the idea that I got from the ReadMe), that it would make a lot of sense for it to be built using .NET v1.1 as well.

  2. I’m only guessing, but I suspect that an MSIL provider under 1.1 may not be possible. I faced some of the same issues when writing a (partial) provider for IKVM’s implementation of Java, which requires things like knowing the true name of the property for an indexer and the names of setters and getters for properties. In the CodeDom API as it existed in 1.1 it was impossible to get these things right – you could only follow the normal naming convention (Item, set_(whatever) and get_(whatever) respectively) and hope for the best.

    If it’s now possible to write an MSIL provider that does these things *right*, it may rely on new features in the CodeDom API of 2.0. When I was writing the Java CodeDom my wishlist of features needed to get everything right wasn’t all that long – less than ten items, and each of them individually was small. It may be that those items have now been added in the 2.0 CodeDom API.

    Brad, could you confirm or deny my suspicions?

  3. Andy says:

    Yeah, that could very well be. I actually spent some time this morning attempting to get it to compile under .NET v1.1, but I gave up once the only errors left involved the new syntax for delegates (I think – I haven’t done all that much with .NET 2.0 yet). It also looked like it actually generates .NET 2.0 code, not 1.1 code, since it was reading and writing out the arguments for Types (which I took to mean Generics).

    If that is the case, it would be a good idea to update the doc saying that it requires .NET 2.0, and also works against .NET 2.0 types.

  4. eden li says:

    Hi Andy,

    I’m the intern who wrote the MSIL provider. As it stands currently, it would have made more sense for me to have written the provider in v1.1, but I was trying to target v2.0 features with it; in the 3-4 weeks before the end of my internship I was only able to reach v1.1. It still needs a bit of work, but it wouldn’t be difficult to allow it to consume/produce v2.0 CodeDom trees… I’ve already implemented partial type support and started the work for generic type consumption (it’s halfway there).

    Another reason for using v2.0 CLR, I wanted to learn how to use new nifty C# features such as anonymous delegates, iterators, generics, and the like.

    Stuart,

    It’s possible to write an MSIL provider for v1.1; you just imitate what the C#/VB code providers do for the cases in which you have to "hope for the best".

  5. Andy says:

    Thanks for the explanation, eden. If I get some time I might look into getting it to compile with .NET v1.1 and see what happens.

  6. Eden,

    Actually you *can’t* imitate what the C# and VB code providers do in those cases. Consider the case of string, whose indexer is called "Chars" instead of the standard "Item".

    The C# and VB providers can just emit myString[whatever] or myString(whatever) and not *care* about this difference. But in MSIL, and also in Java, the provider can only hope for the best and give myString.get_Item(whatever), and it will be wrong.

    Sure, you can get reasonable results a lot of the time with a provider like this. I assume it’s how the MSIL one is written already because there really isn’t any alternative. But "reasonable a lot of the time" isn’t the same as "correct", and with CodeDom as it stands it’s impossible to write a correct provider for MSIL and Java and potentially many other languages. It seems clear that the CodeDom API was only designed with C# and VB in mind, with no input from creators of any other languages, and I think that sucks. It would have been so easy to make an API that really could work with most languages, but they just didn’t bother.

  7. eden li says:

    While I agree with you that the CodeDom API is C#/VB centric, it’s not impossible to write a *correct* Indexer expression generator for MSIL even in v1.1. The answer is to use reflection. That is reflect on the type to find the DefaultMemberAttribute for a that type and use that as the indexer name.

    In fact, in order to make up for a lot of missing information required to produce proper IL, I had rely extensively on reflection. This only works for types that are already compiled and are not being produced by the CodeDom tree that you’re currently generating for. To solve this, I wrote another class that allows you to discover this kind of information from a given CodeDom tree. If you look at the source for the MsilCodeProvider, you’ll see this manifest in the two files ReflectedTypeInfo (for compiled types) and DeclaredTypeInfo (for CodeDom-declared types).

    Some other examples of where I had to use reflection to discover things that weren’t in the CodeDom tree include:

    1) knowing if a type member was static or not so that I generate the proper call to it (in IL, the call syntax changes depending on the static-ness of the member),

    2) knowing the class heirarchy of type of a given variable so I could generate the proper method calls on it (this also required keeping variable scope information for any given code block),

    I could go on and on, but you see how little information is currently provided by the CodeDom API as it stands today. But, if the amount of information a CodeDom tree stores is increased, then it puts a burden on CodeDom tree producers to provide more information about what they’re trying to produce. For example, someone coming from C#/VB will say "Why do I have to specify the indexer name for CodeIndexerExpression? It should know already what the name is from the type!"

    I think it’s a difficult balancing act, and I think that’s the reason for something like the CodeDom reach usage guidelines (the CodeDom subset). I don’t know if the CodeDom API will be enriched in any way in the future — it seems the usage of the CodeDom is quite low compared to the other .NET types/API calls. Perhaps as more and more languages become introduced to the CLR, the need for a new CodeDom API will manifest…

  8. Wow, that library for finding out type information regardless of whether a type is available by reflection or from the same CodeDom tree sounds *unbelievably* useful to any CodeDom implementor (except for VB and C# of course 😉 ). Do you have any plans on making it available as a standalone library or even suggesting it to the BCL team for inclusion in Whidbey (System.CodeDom.Utils or something 😉 ) – probably too late for that kind of feature addition I guess but you never know.

    Since I still plan on someday completing my work on the IKVM provider (I got it to the point where it should generate mostly correct code, but never figured out how to do the compilation process) I’d love to have this library available so that I could generate code that was *really* correct, rather than mostly. Seems a shame to reinvent your great work, and I’d hate to do a cut’n’paste job even if it were legal.

  9. eden li says:

    I don’t think I own the code, so I couldn’t really publish it separately as a standalone library. I guess it depends on the EULA (included in the archive) for how the code can be used… I haven’t read it yet.

    I tried to write it as isolated as possible, so it should be easy enough to extract from the project. However, it *was* designed around providing information for producing IL, so more methods may need to be defined to garner other kinds of information depending on the requirements of the language being generated. Although, IL did require a lot of info, so maybe most of the features are already covered :)

    To me, it seems demand driven as to whether or not this (or something like it) would appear in future revisions of the BCL. If enough people voice the need, maybe it’ll be done. Brad? 😉

  10. I’d be quite impressed if there was a language which needed any more information than IL did. Being lower-level than IL while still targetting managed code would be quite a good trick 😉

    I guess it would be up to whoever arranged the release of the MSIL provider in the first place to decide whether it could be released as standalone. I haven’t read the license either but I have noticed that a lot of stuff MS has released lately has been licensed very liberally – some of it even (in my uneducated opinion) probably qualifying as Open Source. If that’s the case here it should certainly be possible to make a standalone library of it.

    If anyone’s taking votes, I’d love to see something like this appear in the BCL (in case that wasn’t obvious from my previous statements).

  11. eden li says:

    hmm.. I just read the EULA. I’m no lawyer, but it *seems* that someone could lift the type discovery classes that we’ve been talking about out of the archive, modify and redistribute it.

    So, in case this doesn’t make it into the BCL’s radar, someone could always extend, improve and release what work has been done in the area.