Forráskód Böngészése

Implementing object expressions

Sebastien Ros 12 éve
szülő
commit
cd27168e76

+ 40 - 0
Jint.Tests/Runtime/EngineTests.cs

@@ -356,6 +356,46 @@ namespace Jint.Tests.Runtime
             ");
         }
 
+        [Fact]
+        public void WithStatement()
+        {
+            RunTest(@"
+                with (Math) {
+                  assert(cos(0) == 1);
+                }
+            ");
+        }
+
+        [Fact]
+        public void ObjectExpression()
+        {
+            RunTest(@"
+                var o = { x: 1 };
+                assert(o.x == 1);
+            ");
+        }
+
+        [Fact]
+        public void ScopeChainInWithStatement()
+        {
+            RunTest(@"
+                var x = 0;
+                var myObj = {x : 'obj'};
+
+                function f1(){
+                  var x = 1;
+                  function f2(){
+                    with(myObj){
+                      return x;
+                    }
+                  };
+                  return f2();
+                }
+
+                assert(f1() === 'obj');
+            ");
+        }
+
         /*
                         [Fact]
                         public void ()

+ 1 - 1
Jint/Parser/Ast/Property.cs

@@ -15,6 +15,6 @@ namespace Jint.Parser.Ast
     {
         public PropertyKind Kind;
         public IPropertyKeyExpression Key;
-        public object Value;
+        public Expression Value;
     }
 }

+ 2 - 2
Jint/Parser/JavascriptParser.cs

@@ -1620,7 +1620,7 @@ namespace Jint.Parser
                 };
         }
 
-        public Property CreateProperty(PropertyKind kind, IPropertyKeyExpression key, object value)
+        public Property CreateProperty(PropertyKind kind, IPropertyKeyExpression key, Expression value)
         {
             return new Property
                 {
@@ -2041,7 +2041,7 @@ namespace Jint.Parser
 
         private Property ParseObjectProperty()
         {
-            SyntaxNode value;
+            Expression value;
 
             Token token = _lookahead;
             SkipComment();

+ 77 - 5
Jint/Runtime/ExpressionIntepreter.cs

@@ -304,27 +304,99 @@ namespace Jint.Runtime
 
         public object EvaluateObjectExpression(ObjectExpression objectExpression)
         {
-            var value = _engine.Object.Construct(Arguments.Empty);
+            // http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.5
 
+            var obj = _engine.Object.Construct(Arguments.Empty);
             foreach (var property in objectExpression.Properties)
             {
+                var propName = property.Key.GetKey();
+                var previous = obj.GetOwnProperty(propName);
+                PropertyDescriptor propDesc;
+
                 switch (property.Kind)
                 {
                     case PropertyKind.Data:
-                        value.DefineOwnProperty(property.Key.GetKey(), new DataDescriptor(property.Value), false);
+                        var exprValue = _engine.EvaluateExpression(property.Value);
+                        var propValue = _engine.GetValue(exprValue);
+                        propDesc = new DataDescriptor(propValue) {Writable=true, Enumerable=true,Configurable = true};
                         break;
+
                     case PropertyKind.Get:
-                        throw new NotImplementedException();
+                        var getter = property.Value as FunctionExpression;
+
+                        if (getter == null)
+                        {
+                            throw new SyntaxError();
+                        }
+
+                        var get = new ScriptFunctionInstance(
+                            _engine,
+                            getter,
+                            _engine.Function.Prototype,
+                            _engine.Object.Construct(Arguments.Empty),
+                            _engine.ExecutionContext.LexicalEnvironment,
+                            getter.Strict || _engine.Options.IsStrict()
+                            );
+
+                        propDesc = new AccessorDescriptor(get) { Enumerable = true, Configurable = true};
                         break;
+                    
                     case PropertyKind.Set:
-                        throw new NotImplementedException();
+                        var setter = property.Value as FunctionExpression;
+
+                        if (setter == null)
+                        {
+                            throw new SyntaxError();
+                        }
+
+                        var set = new ScriptFunctionInstance(
+                            _engine,
+                            setter,
+                            _engine.Function.Prototype,
+                            _engine.Object.Construct(Arguments.Empty),
+                            _engine.ExecutionContext.LexicalEnvironment,
+                            setter.Strict || _engine.Options.IsStrict()
+                            );
+
+                        propDesc = new AccessorDescriptor(null, set) { Enumerable = true, Configurable = true};
                         break;
+
                     default:
                         throw new ArgumentOutOfRangeException();
                 }
+
+                if (previous != Undefined.Instance)
+                {
+                    var previousIsData = previous.IsDataDescriptor();
+                    var previousIsAccessor = previous.IsAccessorDescriptor();
+                    var propIsData = propDesc.IsDataDescriptor();
+                    var propIsAccessor = propDesc.IsAccessorDescriptor();
+
+                    if (_engine.Options.IsStrict() && previousIsData && propIsData)
+                    {
+                        throw new SyntaxError();
+                    }
+
+                    if (previousIsData && propIsAccessor)
+                    {
+                        throw new SyntaxError();
+                    }
+
+                    if (previousIsAccessor && propIsData)
+                    {
+                        throw new SyntaxError();
+                    }
+
+                    if (previousIsAccessor && propIsAccessor && ((previous.As<AccessorDescriptor>().Get != null && propDesc.As<AccessorDescriptor>().Get != null) || (previous.As<AccessorDescriptor>().Set != null && propDesc.As<AccessorDescriptor>().Set != null)))
+                    {
+                        throw new SyntaxError();
+                    }
+                }
+
+                obj.DefineOwnProperty(propName, propDesc, false);
             }
 
-            return value;
+            return obj;
         }
 
         public object EvaluateMemberExpression(MemberExpression memberExpression)

+ 25 - 0
Jint/Runtime/TypeConverter.cs

@@ -84,6 +84,11 @@ namespace Jint.Runtime
                 }
             }
 
+            if (o is int)
+            {
+                return ToBoolean((double) (int) o);
+            }
+
             return true;
         }
 
@@ -99,6 +104,11 @@ namespace Jint.Runtime
                 return (double)o;
             }
 
+            if (o is int)
+            {
+                return (int) o;
+            }
+
             if (o == Undefined.Instance)
             {
                 return double.NaN;
@@ -130,6 +140,11 @@ namespace Jint.Runtime
         /// <returns></returns>
         public static int ToInteger(object o)
         {
+            if (o is int)
+            {
+                return (int) o;
+            }
+
             var number = ToNumber(o);
             if (double.IsNaN(number))
             {
@@ -146,6 +161,11 @@ namespace Jint.Runtime
         /// <returns></returns>
         public static int ToInt32(object o)
         {
+            if (o is int)
+            {
+                return (int) o;
+            }
+
             var n = ToNumber(o);
             if (double.IsNaN(n) || double.IsInfinity(n) || n == 0)
             {
@@ -238,6 +258,11 @@ namespace Jint.Runtime
                 return n.ToString();
             }
 
+            if (o is int)
+            {
+                return ToString((double) (int) o);
+            }
+
             return ToString(ToPrimitive(o, TypeCode.String));
         }