Sign in to follow this  
benryves

[.net] Parsing expressions made up of any .NET object

Recommended Posts

I have built an assembler that has a primitive (and buggy) arrangement to parse expressions. It supports two types internally (strings and doubles) and each label the user creates can be one or the other. Each operator checks both operands and performs what it deems to be the most sensible operation on them. I need to rewrite the way that labels and expressions are handled due to the aforementioned bugs, and was pondering whether it would be practical to support all .NET types, and what the easiest way to handle that would be. Internally each label value could be an object, but how exactly would one add two objects together and get a meaningful result? It doesn't appear to be possible to invoke operators via reflection. PowerShell manages it somehow ($x = 123; $y = 456; [console]::writeline($x+$y)), and it would of course be possible to check for the standard primitive types and handle those yourself manually, but that seems rather clunky.

Share this post


Link to post
Share on other sites
Quote:
Original post by benryves
It doesn't appear to be possible to invoke operators via reflection.

You're right that it's not possible to invoke operators on primitive types via reflection, as those are handled directly by MSIL instructions.

However, it is possible to invoke overloaded operators via reflection, as they are nothing more than methods handled specially by the compiler. To find them via reflection, they have names like "op_Addition" and "op_Multiply". Additionally, they will have the IsSpecialName property set to true to distinguish them from normal methods.

So yes, you will have to end up special casing the primitive types. This should be pretty easy to do by having simple helper methods that do nothing more than add/multiply/etc two ints/doubles/what-have-you. To make it easier to detect primitive types, you can use the IsPrimitive property of your operand's type object.

Share this post


Link to post
Share on other sites
Indeed. For the non-primatives, there will be a static function on the first param's type (iirc) that defines the operator. Primatives will need to be hard-coded or redirected to a mostly hard-coded intermediary.

For Tangent, I created the mostly hard-coded intermediaries and the plus operator acts as a global method group. The 'best candidate' picking works on the standard behavior of the language off of that.

Share this post


Link to post
Share on other sites
Thanks for the replies. I'd seen complaints and suggested workarounds for people attempting to constrain generic types on operators before, so I wasn't too hopeful. I was more concerned about doing it the manual way only to find out that it was in fact possible to do it in a more elegant solution. Cheers!

Share this post


Link to post
Share on other sites
This isn't anything I've tried, but in theory, if you aren't targeting the compact framework, at the point when you try foo @ bar, you can create a function:

object magic(FooType a, BarType b) {
return a @ b;
}

and run it through the compiler at runtime. If the compiler accepts the function, then load the function into a map and keep it around if you ever need that kind of magic again. There are probably still some corner cases involving primitives that would need to be resolved, but it should be a bit less work than trying to code everything manually.

Share this post


Link to post
Share on other sites
Looks like .NET 3.5 makes this nice and easy.

static object Add(object a, object b) {
var Parameters = new[] {
Expression.Parameter(a.GetType(), "a"),
Expression.Parameter(b.GetType(), "b"),
};
var Adder = Expression.Lambda(Expression.Add(Parameters[0], Parameters[1]), Parameters).Compile();
return Adder.DynamicInvoke(a, b);
}

That appears to be able to add any two objects you feed it, provided the two have some sort of addition defined. Primitive types work fine, as do types with overloaded operators. Nifty!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this