Browse Source

Merge pull request #63 from Rohansi/master

Add support for accessing static members (fixes #46)
Sébastien Ros 11 years ago
parent
commit
6d7da25a35

+ 1 - 0
Jint.Tests/Jint.Tests.csproj

@@ -57,6 +57,7 @@
     <Compile Include="Runtime\Converters\NegateBoolConverter.cs" />
     <Compile Include="Runtime\Converters\NegateBoolConverter.cs" />
     <Compile Include="Runtime\Domain\A.cs" />
     <Compile Include="Runtime\Domain\A.cs" />
     <Compile Include="Runtime\Domain\ClassWithField.cs" />
     <Compile Include="Runtime\Domain\ClassWithField.cs" />
+    <Compile Include="Runtime\Domain\ClassWithStaticFields.cs" />
     <Compile Include="Runtime\Domain\Colors.cs" />
     <Compile Include="Runtime\Domain\Colors.cs" />
     <Compile Include="Runtime\Domain\IPerson.cs" />
     <Compile Include="Runtime\Domain\IPerson.cs" />
     <Compile Include="Runtime\Domain\Person.cs" />
     <Compile Include="Runtime\Domain\Person.cs" />

+ 18 - 0
Jint.Tests/Runtime/Domain/ClassWithStaticFields.cs

@@ -0,0 +1,18 @@
+namespace Jint.Tests.Runtime.Domain
+{
+    public class ClassWithStaticFields
+    {
+        public static string Get = "Get";
+        public static string Set = "Set";
+
+        public static string Getter { get { return "Getter"; } }
+        public static string Setter { get; set; }
+
+        public static readonly string Readonly = "Readonly";
+
+        static ClassWithStaticFields()
+        {
+            Setter = "Setter";
+        }
+    }
+}

+ 59 - 0
Jint.Tests/Runtime/InteropTests.cs

@@ -648,6 +648,65 @@ namespace Jint.Tests.Runtime
             Assert.Equal("Mickey Mouse", o.Field);
             Assert.Equal("Mickey Mouse", o.Field);
         }
         }
 
 
+        [Fact]
+        public void CanGetStaticField()
+        {
+            RunTest(@"
+                var domain = importNamespace('Jint.Tests.Runtime.Domain');
+                var statics = domain.ClassWithStaticFields;
+                assert(statics.Get == 'Get');
+            ");
+        }
+
+        [Fact]
+        public void CanSetStaticField()
+        {
+            RunTest(@"
+                var domain = importNamespace('Jint.Tests.Runtime.Domain');
+                var statics = domain.ClassWithStaticFields;
+                statics.Set = 'hello';
+                assert(statics.Set == 'hello');
+            ");
+
+            Assert.Equal(ClassWithStaticFields.Set, "hello");
+        }
+
+        [Fact]
+        public void CanGetStaticAccessor()
+        {
+            RunTest(@"
+                var domain = importNamespace('Jint.Tests.Runtime.Domain');
+                var statics = domain.ClassWithStaticFields;
+                assert(statics.Getter == 'Getter');
+            ");
+        }
+
+        [Fact]
+        public void CanSetStaticAccessor()
+        {
+            RunTest(@"
+                var domain = importNamespace('Jint.Tests.Runtime.Domain');
+                var statics = domain.ClassWithStaticFields;
+                statics.Setter = 'hello';
+                assert(statics.Setter == 'hello');
+            ");
+
+            Assert.Equal(ClassWithStaticFields.Setter, "hello");
+        }
+
+        [Fact]
+        public void CantSetStaticReadonly()
+        {
+            RunTest(@"
+                var domain = importNamespace('Jint.Tests.Runtime.Domain');
+                var statics = domain.ClassWithStaticFields;
+                statics.Readonly = 'hello';
+                assert(statics.Readonly == 'Readonly');
+            ");
+
+            Assert.Equal(ClassWithStaticFields.Readonly, "Readonly");
+        }
+
         [Fact]
         [Fact]
         public void CanSetCustomConverters()
         public void CanSetCustomConverters()
         {
         {

+ 1 - 1
Jint/Runtime/Descriptors/Specialized/FieldInfoDescriptor.cs

@@ -16,7 +16,7 @@ namespace Jint.Runtime.Descriptors.Specialized
             _fieldInfo = fieldInfo;
             _fieldInfo = fieldInfo;
             _item = item;
             _item = item;
 
 
-            Writable = true; // a field is always writable
+            Writable = !fieldInfo.Attributes.HasFlag(FieldAttributes.InitOnly); // don't write to fields marked as readonly
         }
         }
 
 
         public override JsValue? Value
         public override JsValue? Value

+ 36 - 1
Jint/Runtime/Interop/TypeReference.cs

@@ -107,6 +107,35 @@ namespace Jint.Runtime.Interop
             return false;
             return false;
         }
         }
 
 
+        public override void Put(string propertyName, JsValue value, bool throwOnError)
+        {
+            if (!CanPut(propertyName))
+            {
+                if (throwOnError)
+                {
+                    throw new JavaScriptException(Engine.TypeError);
+                }
+
+                return;
+            }
+
+            var ownDesc = GetOwnProperty(propertyName);
+
+            if (ownDesc == null)
+            {
+                if (throwOnError)
+                {
+                    throw new JavaScriptException(Engine.TypeError, "Unknown member: " + propertyName);
+                }
+                else
+                {
+                    return;
+                }
+            }
+
+            ownDesc.Value = value;
+        }
+
         public override PropertyDescriptor GetOwnProperty(string propertyName)
         public override PropertyDescriptor GetOwnProperty(string propertyName)
         {
         {
             // todo: cache members locally
             // todo: cache members locally
@@ -126,12 +155,18 @@ namespace Jint.Runtime.Interop
                 return PropertyDescriptor.Undefined;
                 return PropertyDescriptor.Undefined;
             }
             }
 
 
-            var propertyInfo = Type.GetProperty(propertyName);
+            var propertyInfo = Type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Static);
             if (propertyInfo != null)
             if (propertyInfo != null)
             {
             {
                 return new PropertyInfoDescriptor(Engine, propertyInfo, Type);
                 return new PropertyInfoDescriptor(Engine, propertyInfo, Type);
             }
             }
 
 
+            var fieldInfo = Type.GetField(propertyName, BindingFlags.Public | BindingFlags.Static);
+            if (fieldInfo != null)
+            {
+                return new FieldInfoDescriptor(Engine, fieldInfo, Type);
+            }
+
             var methodInfo = Type
             var methodInfo = Type
                 .GetMethods(BindingFlags.Public | BindingFlags.Static)
                 .GetMethods(BindingFlags.Public | BindingFlags.Static)
                 .Where(mi => mi.Name == propertyName)
                 .Where(mi => mi.Name == propertyName)