[banshee] [JavaScriptCore] Initial function support
- From: Aaron Bockover <abock src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [banshee] [JavaScriptCore] Initial function support
- Date: Mon, 25 Oct 2010 19:12:22 +0000 (UTC)
commit a070c7187c7533d707419d8da62919ff496cf43a
Author: Aaron Bockover <abockover novell com>
Date: Mon Oct 25 13:20:39 2010 -0400
[JavaScriptCore] Initial function support
Supports declaring 'native' functions (body written in .NET) and
accessible from a JSC context. Also JSObject now sports the
CallAsFunction method, enabling invoking JSC functions from .NET.
.../Banshee.WebBrowser/Banshee.WebBrowser.csproj | 2 +
src/Core/Banshee.WebBrowser/Makefile.am | 2 +
.../Ossifer.JavaScriptCore/JSFunction.cs | 73 ++++++++++++
.../Ossifer.JavaScriptCore/JSObject.cs | 22 ++++
.../Tests/JSFunctionTests.cs | 120 ++++++++++++++++++++
5 files changed, 219 insertions(+), 0 deletions(-)
---
diff --git a/src/Core/Banshee.WebBrowser/Banshee.WebBrowser.csproj b/src/Core/Banshee.WebBrowser/Banshee.WebBrowser.csproj
index ae0465f..19d59c6 100644
--- a/src/Core/Banshee.WebBrowser/Banshee.WebBrowser.csproj
+++ b/src/Core/Banshee.WebBrowser/Banshee.WebBrowser.csproj
@@ -125,5 +125,7 @@
<Compile Include="Ossifer.JavaScriptCore\Tests\JSStringTests.cs" />
<Compile Include="Ossifer.JavaScriptCore\Tests\JSObjectTests.cs" />
<Compile Include="Ossifer.JavaScriptCore\JSPropertyNameArray.cs" />
+ <Compile Include="Ossifer.JavaScriptCore\JSFunction.cs" />
+ <Compile Include="Ossifer.JavaScriptCore\Tests\JSFunctionTests.cs" />
</ItemGroup>
</Project>
diff --git a/src/Core/Banshee.WebBrowser/Makefile.am b/src/Core/Banshee.WebBrowser/Makefile.am
index bee71ed..d571206 100644
--- a/src/Core/Banshee.WebBrowser/Makefile.am
+++ b/src/Core/Banshee.WebBrowser/Makefile.am
@@ -21,6 +21,7 @@ SOURCES = \
Ossifer.JavaScriptCore/JSClassDefinition.cs \
Ossifer.JavaScriptCore/JSContext.cs \
Ossifer.JavaScriptCore/JSException.cs \
+ Ossifer.JavaScriptCore/JSFunction.cs \
Ossifer.JavaScriptCore/JSObject.cs \
Ossifer.JavaScriptCore/JSPropertyAttribute.cs \
Ossifer.JavaScriptCore/JSPropertyNameAccumulator.cs \
@@ -29,6 +30,7 @@ SOURCES = \
Ossifer.JavaScriptCore/JSType.cs \
Ossifer.JavaScriptCore/JSValue.cs \
Ossifer.JavaScriptCore/ManagedPropertyBagClass.cs \
+ Ossifer.JavaScriptCore/Tests/JSFunctionTests.cs \
Ossifer.JavaScriptCore/Tests/JSObjectTests.cs \
Ossifer.JavaScriptCore/Tests/JSStringTests.cs \
Ossifer.JavaScriptCore/Tests/JSValueTests.cs
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSFunction.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSFunction.cs
new file mode 100644
index 0000000..0b4a63a
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSFunction.cs
@@ -0,0 +1,73 @@
+//
+// JSFunction.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2010 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ossifer.JavaScriptCore
+{
+ public delegate JSValue JSFunctionHandler (JSFunction function, JSObject thisObject, JSValue [] args);
+
+ public class JSFunction : JSObject
+ {
+ [DllImport (JSContext.NATIVE_IMPORT)]
+ private static extern IntPtr JSObjectMakeFunctionWithCallback (IntPtr ctx, JSString name,
+ CallAsFunctionCallback callAsFunction);
+
+ #pragma warning disable 0414
+ private JSObject.CallAsFunctionCallback native_callback;
+ #pragma warning restore 0414
+
+ private JSFunctionHandler handler;
+
+ public JSFunction (JSContext context, string name, JSFunctionHandler handler) : base (context, IntPtr.Zero)
+ {
+ this.handler = handler;
+ var native_name = JSString.New (name);
+ Raw = JSObjectMakeFunctionWithCallback (context.Raw, native_name,
+ native_callback = new JSObject.CallAsFunctionCallback (JSCallback));
+ native_name.Release ();
+ }
+
+ private IntPtr JSCallback (IntPtr ctx, IntPtr function, IntPtr thisObject,
+ IntPtr argumentCount, IntPtr arguments, ref IntPtr exception)
+ {
+ var context = new JSContext (ctx);
+
+ if (handler == null) {
+ return JSValue.NewUndefined (context).Raw;
+ }
+
+ var args = new JSValue[argumentCount.ToInt32 ()];
+
+ for (int i = 0; i < args.Length; i++) {
+ args[i] = new JSValue (context, Marshal.ReadIntPtr (arguments, i * IntPtr.Size));
+ }
+
+ return handler (this, new JSObject (context, thisObject), args).Raw;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSObject.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSObject.cs
index 980f0a0..f387b1d 100644
--- a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSObject.cs
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/JSObject.cs
@@ -186,5 +186,27 @@ namespace Ossifer.JavaScriptCore
public bool IsFunction {
get { return JSObjectIsFunction (Context.Raw, Raw); }
}
+
+ [DllImport (JSContext.NATIVE_IMPORT)]
+ private static extern IntPtr JSObjectCallAsFunction (IntPtr ctx, IntPtr obj, IntPtr thisObject,
+ IntPtr argumentCount, IntPtr [] arguments, ref IntPtr exception);
+
+ public JSValue CallAsFunction (JSObject thisObject, JSValue [] args)
+ {
+ var exception = IntPtr.Zero;
+ var args_native = new IntPtr[args.Length];
+
+ for (int i = 0; i < args.Length; i++) {
+ args_native[i] = args[i].Raw;
+ }
+
+ var result = new JSValue (Context.Raw, JSObjectCallAsFunction (Context.Raw, Raw,
+ thisObject == null ? IntPtr.Zero : thisObject.Raw, new IntPtr (args.Length),
+ args_native, ref exception));
+
+ JSException.Proxy (Context, exception);
+
+ return result;
+ }
}
}
diff --git a/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/Tests/JSFunctionTests.cs b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/Tests/JSFunctionTests.cs
new file mode 100644
index 0000000..5ec95ef
--- /dev/null
+++ b/src/Core/Banshee.WebBrowser/Ossifer.JavaScriptCore/Tests/JSFunctionTests.cs
@@ -0,0 +1,120 @@
+//
+// JSFunctionTests.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2010 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#if ENABLE_TESTS
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+
+namespace Ossifer.JavaScriptCore.Tests
+{
+ [TestFixture]
+ public class JSFunctionTests
+ {
+ private JSContext context;
+
+ [TestFixtureSetUp]
+ public void Init ()
+ {
+ context = new JSContext ();
+ }
+
+ [Test]
+ public void TestArguments ()
+ {
+ var r = new List<JSValue> ();
+
+ context.GlobalObject.SetProperty ("go", new JSFunction (context, "go", (fn, ths, args) => {
+ r.AddRange (args);
+ return new JSValue (fn.Context, 42);
+ }));
+
+ var go = context.GlobalObject.GetProperty ("go");
+ Assert.AreEqual (JSType.Object, go.JSType);
+ Assert.AreEqual ("function go() {\n [native code]\n}", go.ToString ());
+
+ context.EvaluateScript ("this.go = go (1, 'hi', false, go ({a:'str', b:go ()}, go (0.272, true, go)))");
+
+ Assert.AreEqual (JSType.Number, r[0].JSType);
+ Assert.AreEqual (0.272, r[0].NumberValue);
+ Assert.AreEqual (JSType.Boolean, r[1].JSType);
+ Assert.AreEqual (true, r[1].BooleanValue);
+ Assert.AreEqual (JSType.Object, r[2].JSType);
+ Assert.AreEqual ("function go() {\n [native code]\n}", r[2].ToString ());
+
+ Assert.AreEqual (JSType.Object, r[3].JSType);
+ Assert.AreEqual ("{\"a\":\"str\",\"b\":42}", r[3].ToString ());
+ Assert.AreEqual (JSType.Number, r[4].JSType);
+ Assert.AreEqual (42, r[4].NumberValue);
+
+ Assert.AreEqual (JSType.Number, r[5].JSType);
+ Assert.AreEqual (1, r[5].NumberValue);
+ Assert.AreEqual (JSType.String, r[6].JSType);
+ Assert.AreEqual ("hi", r[6].StringValue);
+ Assert.AreEqual (JSType.Boolean, r[7].JSType);
+ Assert.AreEqual (false, r[7].BooleanValue);
+
+ go = context.GlobalObject.GetProperty ("go");
+ Assert.AreEqual (JSType.Number, go.JSType);
+ Assert.AreEqual (42, go.NumberValue);
+ }
+
+ private JSValue Fib_1 (JSFunction function, JSObject @this, JSValue [] args)
+ {
+ return args[0].NumberValue <= 1 ? new JSValue (@this.Context, 1) : new JSValue (@this.Context,
+ Fib_1 (function, @this, new [] { new JSValue (@this.Context, args[0].NumberValue - 1) }).NumberValue +
+ Fib_1 (function, @this, new [] { new JSValue (@this.Context, args[0].NumberValue - 2) }).NumberValue
+ );
+ }
+
+ private int Fib_2 (int n)
+ {
+ return n <= 1 ? 1 : Fib_2 (n - 1) + Fib_2 (n - 2);
+ }
+
+ [Test]
+ public void TestRecursion ()
+ {
+ context.GlobalObject.SetProperty ("fib", new JSFunction (context, null, Fib_1));
+ for (int i = 0; i <= 25; i++) {
+ context.EvaluateScript ("this.fib_" + i + " = fib (" + i + ")");
+ Assert.AreEqual (Fib_2 (i), context.GlobalObject.GetProperty ("fib_" + i).NumberValue);
+ }
+ }
+
+ [Test]
+ public void TestRecursionNoScript ()
+ {
+ var fib = new JSFunction (context, null, Fib_1);
+ for (int i = 0; i <= 25; i++) {
+ Assert.AreEqual (Fib_2 (i), fib.CallAsFunction (null, new [] { new JSValue (context, i) }).NumberValue);
+ }
+ }
+ }
+}
+
+#endif
\ No newline at end of file
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]