123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- using System;
- using System.Collections.Generic;
- using Jint.Native.Function;
- using Jint.Native.Object;
- using Jint.Runtime;
- using Jint.Runtime.Descriptors;
- using Jint.Runtime.Descriptors.Specialized;
- using Jint.Runtime.Environments;
- namespace Jint.Native.Argument
- {
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-10.6
- /// </summary>
- public class ArgumentsInstance : ObjectInstance
- {
- private ArgumentsInstance(Engine engine, Action<ArgumentsInstance> initializer) : base(engine)
- {
- _initializer = initializer;
- _initialized = false;
- }
- public bool Strict { get; set; }
- private Action<ArgumentsInstance> _initializer;
- private bool _initialized;
- protected override void EnsureInitialized()
- {
- if(_initialized)
- {
- return;
- }
- _initialized = true;
- _initializer(this);
- }
- public static ArgumentsInstance CreateArgumentsObject(Engine engine, FunctionInstance func, string[] names, JsValue[] args, EnvironmentRecord env, bool strict)
- {
- var obj = new ArgumentsInstance(engine, self =>
- {
- var len = args.Length;
- self.FastAddProperty("length", len, true, false, true);
- var map = engine.Object.Construct(Arguments.Empty);
- var mappedNamed = new List<string>();
- var indx = 0;
- while (indx <= len - 1)
- {
- var indxStr = TypeConverter.ToString(indx);
- var val = args[indx];
- self.FastAddProperty(indxStr, val, true, true, true);
- if (indx < names.Length)
- {
- var name = names[indx];
- if (!strict && !mappedNamed.Contains(name))
- {
- mappedNamed.Add(name);
- Func<JsValue, JsValue> g = n => env.GetBindingValue(name, false);
- var p = new Action<JsValue, JsValue>((n, o) => env.SetMutableBinding(name, o, true));
- map.DefineOwnProperty(indxStr, new ClrAccessDescriptor(engine, g, p) { Configurable = true }, false);
- }
- }
- indx++;
- }
- // step 12
- if (mappedNamed.Count > 0)
- {
- self.ParameterMap = map;
- }
- // step 13
- if (!strict)
- {
- self.FastAddProperty("callee", func, true, false, true);
- }
- // step 14
- else
- {
- var thrower = engine.Function.ThrowTypeError;
- self.DefineOwnProperty("caller", new PropertyDescriptor(get: thrower, set: thrower, enumerable: false, configurable: false), false);
- self.DefineOwnProperty("callee", new PropertyDescriptor(get: thrower, set: thrower, enumerable: false, configurable: false), false);
- }
- });
- // These properties are pre-initialized as their don't trigger
- // the EnsureInitialized() event and are cheap
- obj.Prototype = engine.Object.PrototypeObject;
- obj.Extensible = true;
- obj.Strict = strict;
- return obj;
- }
- public ObjectInstance ParameterMap { get; set; }
- public override string Class
- {
- get
- {
- return "Arguments";
- }
- }
- public override PropertyDescriptor GetOwnProperty(string propertyName)
- {
- EnsureInitialized();
- if (!Strict && ParameterMap != null)
- {
- var desc = base.GetOwnProperty(propertyName);
- if (desc == PropertyDescriptor.Undefined)
- {
- return desc;
- }
- var isMapped = ParameterMap.GetOwnProperty(propertyName);
- if (isMapped != PropertyDescriptor.Undefined)
- {
- desc.Value = ParameterMap.Get(propertyName);
- }
- return desc;
- }
- return base.GetOwnProperty(propertyName);
- }
- /// Implementation from ObjectInstance official specs as the one
- /// in ObjectInstance is optimized for the general case and wouldn't work
- /// for arrays
- public override void Put(string propertyName, JsValue value, bool throwOnError)
- {
- EnsureInitialized();
- if (!CanPut(propertyName))
- {
- if (throwOnError)
- {
- throw new JavaScriptException(Engine.TypeError);
- }
- return;
- }
- var ownDesc = GetOwnProperty(propertyName);
- if (ownDesc.IsDataDescriptor())
- {
- var valueDesc = new PropertyDescriptor(value: value, writable: null, enumerable: null, configurable: null);
- DefineOwnProperty(propertyName, valueDesc, throwOnError);
- return;
- }
- // property is an accessor or inherited
- var desc = GetProperty(propertyName);
- if (desc.IsAccessorDescriptor())
- {
- var setter = desc.Set.TryCast<ICallable>();
- setter.Call(new JsValue(this), new[] { value });
- }
- else
- {
- var newDesc = new PropertyDescriptor(value, true, true, true);
- DefineOwnProperty(propertyName, newDesc, throwOnError);
- }
- }
- public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
- {
- EnsureInitialized();
- if (!Strict && ParameterMap != null)
- {
- var map = ParameterMap;
- var isMapped = map.GetOwnProperty(propertyName);
- var allowed = base.DefineOwnProperty(propertyName, desc, false);
- if (!allowed)
- {
- if (throwOnError)
- {
- throw new JavaScriptException(Engine.TypeError);
- }
- }
- if (isMapped != PropertyDescriptor.Undefined)
- {
- if (desc.IsAccessorDescriptor())
- {
- map.Delete(propertyName, false);
- }
- else
- {
- if (desc.Value != null && desc.Value != Undefined.Instance)
- {
- map.Put(propertyName, desc.Value, throwOnError);
- }
- if (desc.Writable.HasValue && desc.Writable.Value == false)
- {
- map.Delete(propertyName, false);
- }
- }
- }
- return true;
- }
- return base.DefineOwnProperty(propertyName, desc, throwOnError);
- }
- public override bool Delete(string propertyName, bool throwOnError)
- {
- EnsureInitialized();
- if (!Strict && ParameterMap != null)
- {
- var map = ParameterMap;
- var isMapped = map.GetOwnProperty(propertyName);
- var result = base.Delete(propertyName, throwOnError);
- if (result && isMapped != PropertyDescriptor.Undefined)
- {
- map.Delete(propertyName, false);
- }
- return result;
- }
- return base.Delete(propertyName, throwOnError);
- }
- }
- }
|