fholm / IronJS

IronJS - A JavaScript implementation for .NET
http://ironjs.wordpress.com
Apache License 2.0
680 stars 79 forks source link

Wiki page request: C# version of "Exposing a CLR function as a native JavaScript functionCLR-function-as-a-native-JavaScript-function" #44

Closed axefrog closed 13 years ago

axefrog commented 13 years ago

As per issue title.

Do you guys have any plans to include XML comments in the public methods? This would make it easier to figure out what some of the parameters are supposed to do. The "length" parameter of CreateFunction has me a bit stumped. Length of what?

This is what I've tried so far and I get an exception:

class Program
{
    static void Main(string[] args)
    {
        var ctx = new CSharp.Context();
        ctx.SetGlobal("getRandom", Utils.CreateFunction<Func<int>>(ctx.Environment, 0, GetRandom));
        System.Console.WriteLine(ctx.Execute("var x = getRandom();"));
    }

    static int GetRandom()
    {
        return new Random().Next(10, 20);
    }
}

I listened to the Hanselminutes podcast about IronJS and you mentioned plans to streamline CLR object/function integration so that it doesn't require a whole lot of code to expose CLR code and JS code back and forth. How is that going?

otac0n commented 13 years ago

JavaScript functions have a length property that indicates the number of parameters it accepts.

However, you can always call a JS function with as many arguments as you want. The ES3 spec indicates that, if parameters cannot be filled in from the arguments, then they get a default value of undefined.

So, as you can see, the number of parameters to a function is not always the same as its length.

All that being said, it looks like what you have should work. Could you post the exception details?

axefrog commented 13 years ago

Sure, the exception that is thrown by my code above is as follows:

Unhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentExcept
ion: Expression of type 'System.Int32' cannot be used for assignment to type 'System.Object'
   at System.Linq.Expressions.Expression.Assign(Expression left, Expression right)
   at IronJS.Compiler.Utils.box@85.Invoke(ParameterExpression tmp) in C:\dev\IronJS\Src\IronJS\Compiler.Utils.fs:line 86
   at IronJS.Dlr.blockTmp(Type type', FSharpFunc`2 f) in C:\dev\IronJS\Src\IronJS\Dlr.fs:line 168
   at IronJS.Compiler.HostFunction.compile$cont@130-1[a](Type callsiteType, Type hostType, ParameterExpression func, ParameterExpression this, Unit unitVar) in C:\dev\IronJS\Src\IronJS\Compiler.HostFunction.fs:line 178
   at IronJS.Compiler.HostFunction.compile$cont@74[a](Type callsiteType, Type hostType, ParameterExpression func, ParameterExpression this, Boolean hostIsVariadic, Boolean callsiteIsVariadic, Boolean hostIsStatic, Boolean callsiteIsStatic, Unit unitVar) in C:\dev\IronJS\Src\IronJS\Compiler.HostFunction.fs:line 130
   at IronJS.Compiler.HostFunction.compile[a](FunctionObject f, Type callsiteType) in C:\dev\IronJS\Src\IronJS\Compiler.HostFunction.fs:line 74
   at IronJS.Runtime.Optimizations.InlineInvokeCache.Invoke(FunctionObject func, CommonObject this) in C:\dev\IronJS\Src\IronJS\InlineCaches.fs:line 84
   at lambda_method(Closure , FunctionObject , CommonObject )
   --- End of inner exception stack trace ---
   at IronJS.Hosting.FSharp.run(Delegate compiled, T t) in C:\dev\IronJS\Src\IronJS\Hosting.fs:line 152
   at ServerX.Console.Program.Main(String[] args) in C:\dev\ServerX\ServerX.Console\Program.cs:line 17
otac0n commented 13 years ago

Interesting... it looks like the return value needs to be boxed...

Could you try boxing it manually? (I'm marking this as a bug.)

axefrog commented 13 years ago

I changed the code as follows, but the exception is still thrown:


static void Main(string[] args)
{
    var ctx = new CSharp.Context();
    ctx.SetGlobal("getRandom", Utils.CreateFunction<Func<int>>(ctx.Environment, 0, GetRandom));
    int val = (int)ctx.Execute("var x = getRandom();");
    System.Console.WriteLine(val);
}
fholm commented 13 years ago

This has to do with the fact that IronJS only deals in doubles currently, this is a drawback but it's according to the ECMA3 spec (yes you can make optimizations so that it uses ints where possible, but that's currently not in place).

There is also no built in conversion between number types in IronJS, the exception you're getting is thrown from the DLR due to that you can't assign an System.Int32 to a System.Object variable without explicit boxing.

Basically to fix this for now: make sure you only accept and return doubles from any functions that interact with IronJS in any way.

axefrog commented 13 years ago

Ah cool. Thanks for the info.