Browse Source

Implementing object interop

Sebastien Ros 11 years ago
parent
commit
6fb1d4789d

+ 1 - 1
Jint.Repl/Program.cs

@@ -9,7 +9,7 @@ namespace Jint.Repl
         static void Main(string[] args)
         static void Main(string[] args)
         {
         {
             var engine = new Engine()
             var engine = new Engine()
-                .WithMember("log", new Action<object>(Console.WriteLine))
+                .SetValue("log", new Action<object>(Console.WriteLine))
             ;
             ;
 
 
             while (true)
             while (true)

+ 2 - 2
Jint.Tests/Runtime/EngineTests.cs

@@ -12,8 +12,8 @@ namespace Jint.Tests.Runtime
         private Engine RunTest(string source)
         private Engine RunTest(string source)
         {
         {
             var engine = new Engine()
             var engine = new Engine()
-                .WithMember("log", new Action<object>(Console.WriteLine))
-                .WithMember("assert", new Action<bool>(Assert.True))
+                .SetValue("log", new Action<object>(Console.WriteLine))
+                .SetValue("assert", new Action<bool>(Assert.True))
                 ;
                 ;
 
 
             engine.Execute(source);
             engine.Execute(source);

+ 56 - 3
Jint.Tests/Runtime/InteropTests.cs

@@ -10,8 +10,8 @@ namespace Jint.Tests.Runtime
         public InteropTests()
         public InteropTests()
         {
         {
             _engine = new Engine()
             _engine = new Engine()
-                .WithMember("log", new Action<object>(Console.WriteLine))
-                .WithMember("assert", new Action<bool>(Assert.True))
+                .SetValue("log", new Action<object>(Console.WriteLine))
+                .SetValue("assert", new Action<bool>(Assert.True))
                 ;
                 ;
         }
         }
 
 
@@ -41,11 +41,64 @@ namespace Jint.Tests.Runtime
         [Fact]
         [Fact]
         public void DelegatesCanBeSet()
         public void DelegatesCanBeSet()
         {
         {
-            _engine.WithMember("square", new Func<double, double>(x => x * x));
+            _engine.SetValue("square", new Func<double, double>(x => x * x));
 
 
             RunTest(@"
             RunTest(@"
                 assert(square(10) === 100);
                 assert(square(10) === 100);
             ");
             ");
         }
         }
+
+        [Fact]
+        public void CanGetObjectProperties()
+        {
+            var p = new Person
+            {
+                Name = "Mickey Mouse"
+            };
+
+            _engine.WithMember("p", p);
+
+            RunTest(@"
+                assert(p.Name === 'Mickey Mouse');
+            ");
+        }
+
+        [Fact]
+        public void CanSetObjectProperties()
+        {
+            var p = new Person
+            {
+                Name = "Mickey Mouse"
+            };
+
+            _engine.WithMember("p", p);
+
+            RunTest(@"
+                p.Name = 'Donald Duck';
+                assert(p.Name === 'Donald Duck');
+            ");
+
+            Assert.Equal("Donald Duck", p.Name);
+        }
+
+        [Fact]
+        public void CanAccessAnonymousObject()
+        {
+            var p = new
+            {
+                Name = "Mickey Mouse",
+            };
+
+            _engine.WithMember("p", p);
+
+            RunTest(@"
+                assert(p.Name === 'Mickey Mouse');
+            ");
+        }
+
+        public class Person
+        {
+            public string Name { get; set; }
+        }
     }
     }
 }
 }

+ 2 - 2
Jint.Tests/Runtime/SunSpiderTests.cs

@@ -10,8 +10,8 @@ namespace Jint.Tests.Runtime
         private Engine RunTest(string source)
         private Engine RunTest(string source)
         {
         {
             var engine = new Engine()
             var engine = new Engine()
-                .WithMember("log", new Action<object>(Console.WriteLine))
-                .WithMember("assert", new Action<bool>(Assert.True))
+                .SetValue("log", new Action<object>(Console.WriteLine))
+                .SetValue("assert", new Action<bool>(Assert.True))
             ;
             ;
 
 
             engine.Execute(source);
             engine.Execute(source);

+ 7 - 1
Jint/Engine.cs

@@ -156,7 +156,7 @@ namespace Jint
             return executionContext;
             return executionContext;
         }
         }
 
 
-        public Engine WithMember(string name, Delegate value)
+        public Engine SetValue(string name, Delegate value)
         {
         {
             Global.FastAddProperty(name, new DelegateWrapper(this, value), true, false, true);
             Global.FastAddProperty(name, new DelegateWrapper(this, value), true, false, true);
             return this;
             return this;
@@ -186,6 +186,12 @@ namespace Jint
             return this;
             return this;
         }
         }
 
 
+        public Engine WithMember(string name, Object obj)
+        {
+            Global.FastAddProperty(name, new ObjectWrapper(this, obj), true, false, true);
+            return this;
+        }
+
         public void LeaveExecutionContext()
         public void LeaveExecutionContext()
         {
         {
             _executionContexts.Pop();
             _executionContexts.Pop();

+ 1 - 0
Jint/Jint.csproj

@@ -157,6 +157,7 @@
     <Compile Include="Runtime\Environments\ObjectEnvironmentRecord.cs" />
     <Compile Include="Runtime\Environments\ObjectEnvironmentRecord.cs" />
     <Compile Include="Runtime\ExpressionIntepreter.cs" />
     <Compile Include="Runtime\ExpressionIntepreter.cs" />
     <Compile Include="Runtime\Interop\ClrFunctionInstance.cs" />
     <Compile Include="Runtime\Interop\ClrFunctionInstance.cs" />
+    <Compile Include="Runtime\Interop\ObjectWrapper .cs" />
     <Compile Include="Runtime\Interop\SetterFunctionInstance.cs" />
     <Compile Include="Runtime\Interop\SetterFunctionInstance.cs" />
     <Compile Include="Runtime\Interop\GetterFunctionInstance.cs" />
     <Compile Include="Runtime\Interop\GetterFunctionInstance.cs" />
     <Compile Include="Runtime\Interop\DelegateWrapper.cs" />
     <Compile Include="Runtime\Interop\DelegateWrapper.cs" />

+ 1 - 1
Jint/Runtime/Descriptors/PropertyDescriptor.cs

@@ -72,7 +72,7 @@ namespace Jint.Runtime.Descriptors
         public JsValue? Enumerable { get; set; }
         public JsValue? Enumerable { get; set; }
         public JsValue? Writable { get; set; }
         public JsValue? Writable { get; set; }
         public JsValue? Configurable { get; set; }
         public JsValue? Configurable { get; set; }
-        public JsValue? Value { get; set; }
+        public virtual JsValue? Value { get; set; }
         
         
         public bool IsAccessorDescriptor()
         public bool IsAccessorDescriptor()
         {
         {

+ 25 - 4
Jint/Runtime/Descriptors/Specialized/ClrDataDescriptor.cs

@@ -1,14 +1,35 @@
-using System;
+using System.Reflection;
 using Jint.Native;
 using Jint.Native;
-using Jint.Runtime.Interop;
 
 
 namespace Jint.Runtime.Descriptors.Specialized
 namespace Jint.Runtime.Descriptors.Specialized
 {
 {
     public sealed class ClrDataDescriptor : PropertyDescriptor
     public sealed class ClrDataDescriptor : PropertyDescriptor
     {
     {
-        public ClrDataDescriptor(Engine engine, Func<JsValue, JsValue[], JsValue> func)
-            : base(value: new ClrFunctionInstance(engine, func), writable: null, enumerable: null, configurable: null)
+        private readonly PropertyInfo _propertyInfo;
+        private readonly object _item;
+        private JsValue? _value;
+
+        public ClrDataDescriptor(PropertyInfo propertyInfo, object item)
+        {
+            _propertyInfo = propertyInfo;
+            _item = item;
+
+            _value = JsValue.FromObject(_propertyInfo.GetValue(_item, null));
+            Writable = propertyInfo.CanWrite;
+        }
+
+        public override JsValue? Value
         {
         {
+            get
+            {
+                return _value;
+            }
+
+            set
+            {
+                _value = value;
+                _propertyInfo.SetValue(_item, _value.GetValueOrDefault().ToObject(), null);
+            }
         }
         }
     }
     }
 }
 }

+ 47 - 0
Jint/Runtime/Interop/ObjectWrapper .cs

@@ -0,0 +1,47 @@
+using System;
+using System.Linq;
+using System.Reflection;
+using Jint.Native.Object;
+using Jint.Runtime.Descriptors;
+using Jint.Runtime.Descriptors.Specialized;
+
+namespace Jint.Runtime.Interop
+{
+    /// <summary>
+    /// Wrapps a CLR instance
+    /// </summary>
+    public sealed class ObjectWrapper : ObjectInstance
+    {
+        private readonly Object _obj;
+
+        public ObjectWrapper(Engine engine, Object obj): base(engine)
+        {
+            _obj = obj;
+        }
+
+        public override PropertyDescriptor GetOwnProperty(string propertyName)
+        {
+            PropertyDescriptor x;
+            if (Properties.TryGetValue(propertyName, out x))
+            {
+                return x;
+            }
+
+            var type = _obj.GetType();
+            var property = type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
+                .FirstOrDefault(m => m.Name == propertyName);
+
+            if (property == null)
+            {
+                return PropertyDescriptor.Undefined;
+            }
+            else
+            {
+                var descriptor = new ClrDataDescriptor(property, _obj);
+                Properties.Add(propertyName, descriptor);
+                return descriptor;
+            }
+            
+        }
+    }
+}