Version 5.3.8: Added dynamic host object projection (Issue #3), added support for overloaded indexers and indexed properties, interface targets now expose System.Object members, expanded caching for improved performance and memory usage, added many new tests, migrated to new V8 Persistent API. Tested with V8 3.22.11.

This commit is contained in:
ClearScript 2013-10-14 11:15:37 -04:00
Родитель 6d9fc280aa
Коммит f96174fc0e
33 изменённых файлов: 1988 добавлений и 266 удалений

Просмотреть файл

@ -63,5 +63,5 @@
#pragma once
#define CLEARSCRIPT_VERSION_STRING "5.3.7.0"
#define CLEARSCRIPT_VERSION_COMMA_SEPARATED 5,3,7,0
#define CLEARSCRIPT_VERSION_STRING "5.3.8.0"
#define CLEARSCRIPT_VERSION_COMMA_SEPARATED 5,3,8,0

Просмотреть файл

@ -61,8 +61,10 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.ClearScript.Util;
namespace Microsoft.ClearScript
@ -100,9 +102,9 @@ namespace Microsoft.ClearScript
/// </summary>
/// <returns>A new empty host object.</returns>
/// <remarks>
/// This function is provided for script languages that support "expando" functionality.
/// It creates an object that supports dynamic property addition and removal. The host
/// can manipulate it via the <see cref="IPropertyBag"/> interface.
/// This function is provided for script languages that do not support external
/// instantiation. It creates an object that supports dynamic property addition and
/// removal. The host can manipulate it via the <see cref="IPropertyBag"/> interface.
/// </remarks>
/// <example>
/// The following code creates an empty host object and adds several properties to it.
@ -127,8 +129,9 @@ namespace Microsoft.ClearScript
/// <param name="args">Optional constructor arguments.</param>
/// <returns>A new host object of the specified type.</returns>
/// <remarks>
/// For information about the mapping between host members and script-callable properties
/// and methods, see
/// This function is provided for script languages that do not support external
/// instantiation. For information about the mapping between host members and script-
/// callable properties and methods, see
/// <see cref="ScriptEngine.AddHostObject(string, HostItemFlags, object)">AddHostObject</see>.
/// </remarks>
/// <example>
@ -151,6 +154,29 @@ namespace Microsoft.ClearScript
return (T)typeof(T).CreateInstance(args);
}
/// <summary>
/// Performs dynamic instantiation.
/// </summary>
/// <param name="target">The dynamic host object that provides the instantiation operation to perform.</param>
/// <param name="args">Optional instantiation arguments.</param>
/// <returns>The result of the operation, which is usually a new dynamic host object.</returns>
/// <remarks>
/// This function is provided for script languages that do not support external
/// instantiation.
/// </remarks>
public object newObj(IDynamicMetaObjectProvider target, params object[] args)
{
MiscHelpers.VerifyNonNullArgument(target, "target");
object result;
if (target.GetMetaObject(Expression.Constant(target)).TryCreateInstance(args, out result))
{
return result;
}
throw new InvalidOperationException("Invalid dynamic instantiation");
}
/// <summary>
/// Creates a host array.
/// </summary>
@ -1000,6 +1026,209 @@ namespace Microsoft.ClearScript
return HostObject.Wrap(Convert.ToDecimal(value));
}
/// <summary>
/// Gets the value of a property in a dynamic host object that implements <see cref="IPropertyBag"/>.
/// </summary>
/// <param name="target">The dynamic host object that contains the property to get.</param>
/// <param name="name">The name of the property to get.</param>
/// <returns>The value of the specified property.</returns>
/// <remarks>
/// This function is provided for script languages that do not support dynamic properties.
/// </remarks>
public object getProperty(IPropertyBag target, string name)
{
MiscHelpers.VerifyNonNullArgument(target, "target");
object result;
if (target.TryGetValue(name, out result))
{
return result;
}
return Nonexistent.Value;
}
/// <summary>
/// Sets a property value in a dynamic host object that implements <see cref="IPropertyBag"/>.
/// </summary>
/// <param name="target">The dynamic host object that contains the property to set.</param>
/// <param name="name">The name of the property to set.</param>
/// <param name="value">The new value of the specified property.</param>
/// <returns>The result of the operation, which is usually the value assigned to the specified property.</returns>
/// <remarks>
/// This function is provided for script languages that do not support dynamic properties.
/// </remarks>
public object setProperty(IPropertyBag target, string name, object value)
{
MiscHelpers.VerifyNonNullArgument(target, "target");
return target[name] = value;
}
/// <summary>
/// Removes a property from a dynamic host object that implements <see cref="IPropertyBag"/>.
/// </summary>
/// <param name="target">The dynamic host object that contains the property to remove.</param>
/// <param name="name">The name of the property to remove.</param>
/// <returns><c>True</c> if the property was found and removed, <c>false</c> otherwise.</returns>
/// <remarks>
/// This function is provided for script languages that do not support dynamic properties.
/// </remarks>
public bool removeProperty(IPropertyBag target, string name)
{
MiscHelpers.VerifyNonNullArgument(target, "target");
return target.Remove(name);
}
/// <summary>
/// Gets the value of a property in a dynamic host object that implements <see cref="IDynamicMetaObjectProvider"/>.
/// </summary>
/// <param name="target">The dynamic host object that contains the property to get.</param>
/// <param name="name">The name of the property to get.</param>
/// <returns>The value of the specified property.</returns>
/// <remarks>
/// This function is provided for script languages that do not support dynamic properties.
/// </remarks>
public object getProperty(IDynamicMetaObjectProvider target, string name)
{
MiscHelpers.VerifyNonNullArgument(target, "target");
object result;
if (target.GetMetaObject(Expression.Constant(target)).TryGetMember(name, out result))
{
return result;
}
return Nonexistent.Value;
}
/// <summary>
/// Sets a property value in a dynamic host object that implements <see cref="IDynamicMetaObjectProvider"/>.
/// </summary>
/// <param name="target">The dynamic host object that contains the property to set.</param>
/// <param name="name">The name of the property to set.</param>
/// <param name="value">The new value of the specified property.</param>
/// <returns>The result of the operation, which is usually the value assigned to the specified property.</returns>
/// <remarks>
/// This function is provided for script languages that do not support dynamic properties.
/// </remarks>
public object setProperty(IDynamicMetaObjectProvider target, string name, object value)
{
MiscHelpers.VerifyNonNullArgument(target, "target");
object result;
if (target.GetMetaObject(Expression.Constant(target)).TrySetMember(name, value, out result))
{
return result;
}
throw new InvalidOperationException("Invalid dynamic property assignment");
}
/// <summary>
/// Removes a property from a dynamic host object that implements <see cref="IDynamicMetaObjectProvider"/>.
/// </summary>
/// <param name="target">The dynamic host object that contains the property to remove.</param>
/// <param name="name">The name of the property to remove.</param>
/// <returns><c>True</c> if the property was found and removed, <c>false</c> otherwise.</returns>
/// <remarks>
/// This function is provided for script languages that do not support dynamic properties.
/// </remarks>
public bool removeProperty(IDynamicMetaObjectProvider target, string name)
{
MiscHelpers.VerifyNonNullArgument(target, "target");
bool result;
if (target.GetMetaObject(Expression.Constant(target)).TryDeleteMember(name, out result))
{
return result;
}
throw new InvalidOperationException("Invalid dynamic property deletion");
}
/// <summary>
/// Gets the value of an element in a dynamic host object that implements <see cref="IDynamicMetaObjectProvider"/>.
/// </summary>
/// <param name="target">The dynamic host object that contains the element to get.</param>
/// <param name="indices">One or more indices that identify the element to get.</param>
/// <returns>The value of the specified element.</returns>
/// <remarks>
/// This function is provided for script languages that do not support general indexing.
/// </remarks>
public object getElement(IDynamicMetaObjectProvider target, params object[] indices)
{
MiscHelpers.VerifyNonNullArgument(target, "target");
object result;
if (target.GetMetaObject(Expression.Constant(target)).TryGetIndex(indices, out result))
{
return result;
}
return Nonexistent.Value;
}
/// <summary>
/// Sets an element value in a dynamic host object that implements <see cref="IDynamicMetaObjectProvider"/>.
/// </summary>
/// <param name="target">The dynamic host object that contains the element to set.</param>
/// <param name="value">The new value of the element.</param>
/// <param name="indices">One or more indices that identify the element to set.</param>
/// <returns>The result of the operation, which is usually the value assigned to the specified element.</returns>
/// <remarks>
/// This function is provided for script languages that do not support general indexing.
/// </remarks>
public object setElement(IDynamicMetaObjectProvider target, object value, params object[] indices)
{
MiscHelpers.VerifyNonNullArgument(target, "target");
object result;
if (target.GetMetaObject(Expression.Constant(target)).TrySetIndex(indices, value, out result))
{
return result;
}
throw new InvalidOperationException("Invalid dynamic element assignment");
}
/// <summary>
/// Removes an element from a dynamic host object that implements <see cref="IDynamicMetaObjectProvider"/>.
/// </summary>
/// <param name="target">The dynamic host object that contains the element to remove.</param>
/// <param name="indices">One or more indices that identify the element to remove.</param>
/// <returns><c>True</c> if the element was found and removed, <c>false</c> otherwise.</returns>
/// <remarks>
/// This function is provided for script languages that do not support general indexing.
/// </remarks>
public bool removeElement(IDynamicMetaObjectProvider target, params object[] indices)
{
MiscHelpers.VerifyNonNullArgument(target, "target");
bool result;
if (target.GetMetaObject(Expression.Constant(target)).TryDeleteIndex(indices, out result))
{
return result;
}
throw new InvalidOperationException("Invalid dynamic element deletion");
}
/// <summary>
/// Casts a dynamic host object to its static type.
/// </summary>
/// <param name="value">The object to cast to its static type.</param>
/// <returns>The specified object in its static type form, stripped of its dynamic members.</returns>
/// <remarks>
/// A dynamic host object that implements <see cref="IDynamicMetaObjectProvider"/> may have
/// dynamic members that override members of its static type. This function can be used to
/// gain access to type members overridden in this manner.
/// </remarks>
public object toStaticType(IDynamicMetaObjectProvider value)
{
return HostItem.Wrap(GetEngine(), value, HostItemFlags.HideDynamicMembers);
}
// ReSharper restore InconsistentNaming
#endregion

Просмотреть файл

@ -175,15 +175,18 @@ namespace Microsoft.ClearScript
private MethodBindResult BindMethodInternal(string name, Type[] typeArgs, object[] args, object[] bindArgs)
{
// create C# member invocation binder
const CSharpBinderFlags binderFlags = CSharpBinderFlags.InvokeSimpleName | CSharpBinderFlags.ResultDiscarded;
var binder = Binder.InvokeMember(binderFlags, name, typeArgs, accessContext ?? engine.AccessContext, CreateArgInfoEnum(bindArgs));
// perform default binding
var binding = DynamicHelpers.Bind((DynamicMetaObjectBinder)binder, target, bindArgs);
var rawResult = (new MethodBindingVisitor(target.InvokeTarget, name, binding.Expression)).Result;
var result = MethodBindResult.Create(name, rawResult, target, args);
if (!(result is MethodBindSuccess) && !(target is HostType) && target.Type.IsInterface)
{
// binding through interface failed; try base interfaces
foreach (var interfaceType in target.Type.GetInterfaces())
{
var tempTarget = HostObject.Wrap(target.InvokeTarget, interfaceType);
@ -196,6 +199,17 @@ namespace Microsoft.ClearScript
return tempResult;
}
}
// binding through base interfaces failed; try System.Object
var objectTarget = HostObject.Wrap(target.InvokeTarget, typeof(object));
binding = DynamicHelpers.Bind((DynamicMetaObjectBinder)binder, objectTarget, bindArgs);
rawResult = (new MethodBindingVisitor(target.InvokeTarget, name, binding.Expression)).Result;
var objectResult = MethodBindResult.Create(name, rawResult, target, args);
if (objectResult is MethodBindSuccess)
{
return objectResult;
}
}
return result;

Просмотреть файл

@ -66,6 +66,7 @@ using System.Diagnostics;
using System.Dynamic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.InteropServices.Expando;
using Microsoft.ClearScript.Util;
@ -88,6 +89,7 @@ namespace Microsoft.ClearScript
private IDynamic targetDynamic;
private IPropertyBag targetPropertyBag;
private IList targetList;
private DynamicMetaObject targetDynamicMetaObject;
private string[] cachedLocalEventNames;
private string[] cachedLocalFieldNames;
@ -109,6 +111,9 @@ namespace Microsoft.ClearScript
private int cachedListCount;
private HashSet<string> expandoMemberNames;
private Dictionary<string, HostMethod> hostMethodMap;
private Dictionary<string, HostIndexedProperty> hostIndexedPropertyMap;
private static readonly MemberMap<Field> fieldMap = new MemberMap<Field>();
private static readonly MemberMap<Method> methodMap = new MemberMap<Method>();
private static readonly MemberMap<Property> propertyMap = new MemberMap<Property>();
@ -249,7 +254,7 @@ namespace Microsoft.ClearScript
private static object BindOrCreate(ScriptEngine engine, object target, Type type, HostItemFlags flags)
{
return BindOrCreate(engine, (target as HostTarget) ?? HostObject.Wrap(target, type), flags);
return BindOrCreate(engine, HostObject.Wrap(target, type), flags);
}
private static object BindOrCreate(ScriptEngine engine, HostTarget target, HostItemFlags flags)
@ -283,12 +288,34 @@ namespace Microsoft.ClearScript
private void BindSpecialTarget()
{
BindSpecialTarget(out targetDynamic);
BindSpecialTarget(out targetPropertyBag);
BindSpecialTarget(out targetList);
if (BindSpecialTarget(out targetDynamic))
{
targetPropertyBag = null;
targetList = null;
targetDynamicMetaObject = null;
}
else if (BindSpecialTarget(out targetPropertyBag))
{
targetList = null;
targetDynamicMetaObject = null;
}
else
{
IDynamicMetaObjectProvider dynamicMetaObjectProvider;
if (!flags.HasFlag(HostItemFlags.HideDynamicMembers) && BindSpecialTarget(out dynamicMetaObjectProvider))
{
targetDynamicMetaObject = dynamicMetaObjectProvider.GetMetaObject(Expression.Constant(target.InvokeTarget));
targetList = null;
}
else
{
targetDynamicMetaObject = null;
BindSpecialTarget(out targetList);
}
}
}
private void BindSpecialTarget<T>(out T specialTarget) where T : class
private bool BindSpecialTarget<T>(out T specialTarget) where T : class
{
// The check here is required because the item may be bound to a specific target base
// class or interface - one that must not trigger special treatment.
@ -296,11 +323,11 @@ namespace Microsoft.ClearScript
if (typeof(T).IsAssignableFrom(target.Type))
{
specialTarget = target.InvokeTarget as T;
return specialTarget != null;
}
else
{
specialTarget = null;
}
specialTarget = null;
return false;
}
private BindingFlags GetCommonBindFlags()
@ -468,6 +495,7 @@ namespace Microsoft.ClearScript
else
{
names = names.Concat(GetLocalPropertyNames());
if (targetList != null)
{
cachedListCount = targetList.Count;
@ -476,6 +504,11 @@ namespace Microsoft.ClearScript
names = names.Concat(Enumerable.Range(0, cachedListCount).Select(index => index.ToString(CultureInfo.InvariantCulture)));
}
}
if (targetDynamicMetaObject != null)
{
names = names.Concat(targetDynamicMetaObject.GetDynamicMemberNames());
}
}
if (expandoMemberNames != null)
@ -518,6 +551,7 @@ namespace Microsoft.ClearScript
if ((cachedPropertyNames == null) ||
(targetDynamic != null) ||
(targetPropertyBag != null) ||
(targetDynamicMetaObject != null) ||
((targetList != null) && (cachedListCount != targetList.Count)))
{
cachedPropertyNames = GetAllPropertyNames();
@ -634,7 +668,7 @@ namespace Microsoft.ClearScript
}
object result;
if (InvokeHelpers.TryInvokeObject(value, invokeFlags, args, bindArgs, out result))
if (InvokeHelpers.TryInvokeObject(value, invokeFlags, args, bindArgs, true, out result))
{
return result;
}
@ -644,7 +678,7 @@ namespace Microsoft.ClearScript
return value;
}
throw new NotSupportedException("Object does not support invocation");
throw new NotSupportedException("Object does not support the requested invocation operation");
}
if (invokeFlags.HasFlag(BindingFlags.GetField))
@ -676,7 +710,7 @@ namespace Microsoft.ClearScript
if (invokeFlags.HasFlag(BindingFlags.InvokeMethod))
{
object result;
if (InvokeHelpers.TryInvokeObject(targetList[index], invokeFlags, args, bindArgs, out result))
if (InvokeHelpers.TryInvokeObject(targetList[index], invokeFlags, args, bindArgs, true, out result))
{
return result;
}
@ -686,7 +720,7 @@ namespace Microsoft.ClearScript
return targetList[index];
}
throw new NotSupportedException("Object does not support invocation");
throw new NotSupportedException("Object does not support the requested invocation operation");
}
if (invokeFlags.HasFlag(BindingFlags.GetField))
@ -733,7 +767,19 @@ namespace Microsoft.ClearScript
if (hostType != null)
{
args = args.Skip(typeArgs.Length).ToArray();
return hostType.GetSpecificType().CreateInstance(invokeFlags, args);
var specificType = hostType.GetSpecificType();
if (typeof(Delegate).IsAssignableFrom(specificType))
{
if (args.Length != 1)
{
throw new InvalidOperationException("Invalid constructor invocation");
}
return DelegateFactory.CreateDelegate(engine, args[0], specificType);
}
return specificType.CreateInstance(invokeFlags, args);
}
}
@ -755,6 +801,15 @@ namespace Microsoft.ClearScript
return type.CreateInstance(invokeFlags, args);
}
if (targetDynamicMetaObject != null)
{
object result;
if (targetDynamicMetaObject.TryCreateInstance(args, out result))
{
return result;
}
}
}
throw new InvalidOperationException("Invalid constructor invocation");
@ -765,7 +820,7 @@ namespace Microsoft.ClearScript
if (name == SpecialMemberNames.Default)
{
object result;
if (InvokeHelpers.TryInvokeObject(target, invokeFlags, args, bindArgs, out result))
if (InvokeHelpers.TryInvokeObject(target, invokeFlags, args, bindArgs, targetDynamicMetaObject != null, out result))
{
return result;
}
@ -775,7 +830,16 @@ namespace Microsoft.ClearScript
return target;
}
throw new NotSupportedException("Object does not support invocation");
throw new NotSupportedException("Object does not support the requested invocation operation");
}
if ((targetDynamicMetaObject != null) && (targetDynamicMetaObject.GetDynamicMemberNames().Contains(name)))
{
object result;
if (targetDynamicMetaObject.TryInvokeMember(name, invokeFlags, args, out result))
{
return result;
}
}
if (thisExpando.GetMethods(GetMethodBindFlags()).Any(method => method.Name == name))
@ -783,7 +847,7 @@ namespace Microsoft.ClearScript
return InvokeMethod(name, args, bindArgs);
}
var property = target.Type.GetScriptableProperty(name, GetCommonBindFlags());
var property = target.Type.GetScriptableProperty(name, GetCommonBindFlags(), MiscHelpers.GetEmptyArray<object>());
if ((property != null) && (typeof(Delegate).IsAssignableFrom(property.PropertyType)))
{
var del = (Delegate)property.GetValue(target.InvokeTarget, invokeFlags | BindingFlags.GetProperty, Type.DefaultBinder, MiscHelpers.GetEmptyArray<object>(), culture);
@ -799,96 +863,74 @@ namespace Microsoft.ClearScript
if (invokeFlags.HasFlag(BindingFlags.GetField))
{
return GetHostProperty(name, invokeFlags, args, culture);
return GetHostProperty(name, invokeFlags, args, bindArgs, culture);
}
throw new MissingMemberException(MiscHelpers.FormatInvariant("Object has no method named '{0}'", name));
throw new MissingMemberException(MiscHelpers.FormatInvariant("Object has no suitable method named '{0}'", name));
}
if (invokeFlags.HasFlag(BindingFlags.GetField))
{
return GetHostProperty(name, invokeFlags, args, culture);
return GetHostProperty(name, invokeFlags, args, bindArgs, culture);
}
if (invokeFlags.HasFlag(BindingFlags.SetField))
{
if (name == SpecialMemberNames.Default)
{
object result;
if (InvokeHelpers.TryInvokeObject(target, invokeFlags, args, bindArgs, out result))
{
return result;
}
throw new InvalidOperationException("Invalid property assignment");
}
var property = target.Type.GetScriptableProperty(name, invokeFlags);
if (property != null)
{
if (args.Length > 0)
{
if (property.IsReadOnlyForScript())
{
throw new UnauthorizedAccessException("Property is read-only");
}
var value = args[args.Length - 1];
if (property.PropertyType.IsAssignableFrom(ref value))
{
property.SetValue(target.InvokeTarget, value, invokeFlags, Type.DefaultBinder, args.Take(args.Length - 1).ToArray(), culture);
return value;
}
throw new ArgumentException("Invalid property assignment");
}
throw new InvalidOperationException("Invalid argument count");
}
var field = target.Type.GetScriptableField(name, invokeFlags);
if (field != null)
{
if (args.Length == 1)
{
if (field.IsReadOnlyForScript())
{
throw new UnauthorizedAccessException("Field is read-only");
}
var value = args[0];
if (field.FieldType.IsAssignableFrom(ref value))
{
field.SetValue(target.InvokeTarget, value);
return value;
}
throw new ArgumentException("Invalid field assignment");
}
throw new InvalidOperationException("Invalid argument count");
}
throw new MissingMemberException(MiscHelpers.FormatInvariant("Object has no property or field named '{0}'", name));
return SetHostProperty(name, invokeFlags, args, bindArgs, culture);
}
throw new InvalidOperationException("Invalid member invocation mode");
}
private object GetHostProperty(string name, BindingFlags invokeFlags, object[] args, CultureInfo culture)
private object GetHostProperty(string name, BindingFlags invokeFlags, object[] args, object[] bindArgs, CultureInfo culture)
{
var property = target.Type.GetScriptableProperty(name, invokeFlags);
if (property != null)
if ((targetDynamicMetaObject != null) && (targetDynamicMetaObject.GetDynamicMemberNames().Contains(name)))
{
if ((property.GetIndexParameters().Length > 0) && (args.Length < 1))
object result;
if (targetDynamicMetaObject.TryGetMember(name, out result))
{
return new HostIndexedProperty(this, name);
return result;
}
if (hostMethodMap == null)
{
hostMethodMap = new Dictionary<string, HostMethod>();
}
HostMethod hostMethod;
if (!hostMethodMap.TryGetValue(name, out hostMethod))
{
hostMethod = new HostMethod(this, name);
hostMethodMap.Add(name, hostMethod);
}
return hostMethod;
}
var property = target.Type.GetScriptableProperty(name, invokeFlags, bindArgs);
if (property != null)
{
var result = property.GetValue(target.InvokeTarget, invokeFlags, Type.DefaultBinder, args, culture);
return property.IsRestrictedForScript() ? HostObject.WrapResult(result, property.PropertyType) : result;
}
if (target.Type.GetScriptableProperties(name, invokeFlags).Any())
{
if (hostIndexedPropertyMap == null)
{
hostIndexedPropertyMap = new Dictionary<string, HostIndexedProperty>();
}
HostIndexedProperty hostIndexedProperty;
if (!hostIndexedPropertyMap.TryGetValue(name, out hostIndexedProperty))
{
hostIndexedProperty = new HostIndexedProperty(this, name);
hostIndexedPropertyMap.Add(name, hostIndexedProperty);
}
return hostIndexedProperty;
}
var field = target.Type.GetScriptableField(name, invokeFlags);
if (field != null)
{
@ -906,12 +948,97 @@ namespace Microsoft.ClearScript
var method = thisExpando.GetMethods(GetMethodBindFlags()).FirstOrDefault(testMethod => testMethod.Name == name);
if (method != null)
{
return new HostMethod(this, name);
if (hostMethodMap == null)
{
hostMethodMap = new Dictionary<string, HostMethod>();
}
HostMethod hostMethod;
if (!hostMethodMap.TryGetValue(name, out hostMethod))
{
hostMethod = new HostMethod(this, name);
hostMethodMap.Add(name, hostMethod);
}
return hostMethod;
}
return Nonexistent.Value;
}
private object SetHostProperty(string name, BindingFlags invokeFlags, object[] args, object[] bindArgs, CultureInfo culture)
{
if (name == SpecialMemberNames.Default)
{
// special case to enable JScript/VBScript "x(a) = b" syntax when x is a host indexed property
object result;
if (InvokeHelpers.TryInvokeObject(target, invokeFlags, args, bindArgs, false, out result))
{
return result;
}
throw new InvalidOperationException("Invalid property assignment");
}
if ((targetDynamicMetaObject != null) && (args.Length == 1))
{
object result;
if (targetDynamicMetaObject.TrySetMember(name, args[0], out result))
{
return result;
}
}
if (args.Length < 1)
{
throw new InvalidOperationException("Invalid argument count");
}
var property = target.Type.GetScriptableProperty(name, invokeFlags, bindArgs.Take(bindArgs.Length - 1).ToArray());
if (property != null)
{
if (property.IsReadOnlyForScript())
{
throw new UnauthorizedAccessException("Property is read-only");
}
var value = args[args.Length - 1];
if (property.PropertyType.IsAssignableFrom(ref value))
{
property.SetValue(target.InvokeTarget, value, invokeFlags, Type.DefaultBinder, args.Take(args.Length - 1).ToArray(), culture);
return value;
}
throw new ArgumentException("Invalid property assignment");
}
var field = target.Type.GetScriptableField(name, invokeFlags);
if (field != null)
{
if (field.IsReadOnlyForScript())
{
throw new UnauthorizedAccessException("Field is read-only");
}
if (args.Length == 1)
{
var value = args[0];
if (field.FieldType.IsAssignableFrom(ref value))
{
field.SetValue(target.InvokeTarget, value);
return value;
}
throw new ArgumentException("Invalid field assignment");
}
throw new InvalidOperationException("Invalid argument count");
}
throw new MissingMemberException(MiscHelpers.FormatInvariant("Object has no suitable property or field named '{0}'", name));
}
#endregion
#region Object overrides
@ -1179,7 +1306,7 @@ namespace Microsoft.ClearScript
{
return engine.HostInvoke(() =>
{
if ((targetDynamic != null) || ((targetPropertyBag != null) && !targetPropertyBag.IsReadOnly))
if ((targetDynamic != null) || ((targetPropertyBag != null) && !targetPropertyBag.IsReadOnly) || (targetDynamicMetaObject != null))
{
AddExpandoMemberName(name);
return fieldMap.GetMember(name);
@ -1193,7 +1320,7 @@ namespace Microsoft.ClearScript
{
return engine.HostInvoke(() =>
{
if ((targetDynamic != null) || ((targetPropertyBag != null) && !targetPropertyBag.IsReadOnly))
if ((targetDynamic != null) || ((targetPropertyBag != null) && !targetPropertyBag.IsReadOnly) || (targetDynamicMetaObject != null))
{
AddExpandoMemberName(name);
return propertyMap.GetMember(name);
@ -1234,6 +1361,14 @@ namespace Microsoft.ClearScript
RemoveExpandoMemberName(member.Name);
}
}
else if (targetDynamicMetaObject != null)
{
bool result;
if (targetDynamicMetaObject.TryDeleteMember(member.Name, out result) && result)
{
RemoveExpandoMemberName(member.Name);
}
}
else
{
throw new NotSupportedException("Object does not support dynamic members");
@ -1269,6 +1404,17 @@ namespace Microsoft.ClearScript
return targetPropertyBag.Remove(name);
}
if (targetDynamicMetaObject != null)
{
bool result;
if (targetDynamicMetaObject.TryDeleteMember(name, out result))
{
return result;
}
throw new InvalidOperationException("Invalid dynamic member deletion");
}
throw new NotSupportedException("Object does not support dynamic members");
});
}
@ -1319,6 +1465,17 @@ namespace Microsoft.ClearScript
return targetPropertyBag.Remove(index.ToString(CultureInfo.InvariantCulture));
}
if (targetDynamicMetaObject != null)
{
bool result;
if (targetDynamicMetaObject.TryDeleteMember(index.ToString(CultureInfo.InvariantCulture), out result))
{
return result;
}
throw new InvalidOperationException("Invalid dynamic member deletion");
}
return false;
});
}

Просмотреть файл

@ -60,6 +60,7 @@
//
using System;
using System.Dynamic;
namespace Microsoft.ClearScript
{
@ -82,6 +83,12 @@ namespace Microsoft.ClearScript
/// <summary>
/// Specifies that the host resource's non-public members are to be exposed.
/// </summary>
PrivateAccess = 0x00000002
PrivateAccess = 0x00000002,
/// <summary>
/// Specifies that the host resource's dynamic members are not to be exposed. This option
/// applies only to objects that implement <see cref="IDynamicMetaObjectProvider"/>.
/// </summary>
HideDynamicMembers = 0x00000004
}
}

Просмотреть файл

@ -175,7 +175,7 @@ namespace Microsoft.ClearScript
public object GetCanonicalRef(object obj)
{
if (obj.GetType().IsEnum)
if (obj is Enum)
{
lock (dataLock)
{

Просмотреть файл

@ -60,6 +60,7 @@
//
using System;
using System.Dynamic;
using System.Reflection;
using Microsoft.ClearScript.Util;
@ -183,7 +184,7 @@ namespace Microsoft.ClearScript
{
if (invokeFlags.HasFlag(BindingFlags.InvokeMethod))
{
if (InvokeHelpers.TryInvokeObject(value, invokeFlags, args, bindArgs, out result))
if (InvokeHelpers.TryInvokeObject(value, invokeFlags, args, bindArgs, typeof(IDynamicMetaObjectProvider).IsAssignableFrom(typeof(T)), out result))
{
return true;
}

Просмотреть файл

@ -73,5 +73,5 @@ using System.Runtime.InteropServices;
[assembly: InternalsVisibleTo("ClearScriptTest")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("5.3.7.0")]
[assembly: AssemblyFileVersion("5.3.7.0")]
[assembly: AssemblyVersion("5.3.8.0")]
[assembly: AssemblyFileVersion("5.3.8.0")]

Просмотреть файл

@ -73,12 +73,12 @@ namespace Microsoft.ClearScript
/// Represents a scriptable collection of named properties.
/// </summary>
/// <remarks>
/// If an object implementing this interface is added to a script engine (see
/// If an object that implements this interface is added to a script engine (see
/// <see cref="ScriptEngine.AddHostObject(string, object)">AddHostObject</see>), script code
/// will be able to access the properties stored in the collection as if they were members of
/// the object itself, using the script language's native syntax for member access. No
/// other members of the object will be accessible. This interface also allows objects to
/// implement "expando" functionality for script languages that support it.
/// implement dynamic properties for script languages that support them.
/// </remarks>
public interface IPropertyBag : IDictionary<string, object>
{

Просмотреть файл

@ -672,7 +672,8 @@ namespace Microsoft.ClearScript
internal object MarshalToScript(object obj)
{
return MarshalToScript(obj, HostItemFlags.None);
var hostItem = obj as HostItem;
return MarshalToScript(obj, (hostItem != null) ? hostItem.Flags : HostItemFlags.None);
}
internal object[] MarshalToScript(object[] args)
@ -875,14 +876,12 @@ namespace Microsoft.ClearScript
private readonly ConditionalWeakTable<object, List<WeakReference>> hostObjectHostItemCache = new ConditionalWeakTable<object, List<WeakReference>>();
private readonly ConditionalWeakTable<Type, List<WeakReference>> hostTypeHostItemCache = new ConditionalWeakTable<Type, List<WeakReference>>();
internal delegate HostItem HostItemFactory(ScriptEngine engine, HostTarget target, HostItemFlags flags);
internal HostItem GetOrCreateHostItem(HostTarget target, HostItemFlags flags, HostItemFactory createHostItem)
internal HostItem GetOrCreateHostItem(HostTarget target, HostItemFlags flags, Func<ScriptEngine, HostTarget, HostItemFlags, HostItem> createHostItem)
{
var hostObject = target as HostObject;
if (hostObject != null)
{
return GetOrCreateHostItemForHostObject(hostObject, flags, createHostItem);
return GetOrCreateHostItemForHostTarget(hostObject, flags, createHostItem);
}
var hostType = target as HostType;
@ -891,12 +890,24 @@ namespace Microsoft.ClearScript
return GetOrCreateHostItemForHostType(hostType, flags, createHostItem);
}
var hostMethod = target as HostMethod;
if (hostMethod != null)
{
return GetOrCreateHostItemForHostTarget(hostMethod, flags, createHostItem);
}
var hostIndexedProperty = target as HostIndexedProperty;
if (hostIndexedProperty != null)
{
return GetOrCreateHostItemForHostTarget(hostIndexedProperty, flags, createHostItem);
}
return createHostItem(this, target, flags);
}
private HostItem GetOrCreateHostItemForHostObject(HostObject hostObject, HostItemFlags flags, HostItemFactory createHostItem)
private HostItem GetOrCreateHostItemForHostTarget(HostTarget hostTarget, HostItemFlags flags, Func<ScriptEngine, HostTarget, HostItemFlags, HostItem> createHostItem)
{
var cacheEntry = hostObjectHostItemCache.GetOrCreateValue(hostObject.Target);
var cacheEntry = hostObjectHostItemCache.GetOrCreateValue(hostTarget.Target);
List<WeakReference> activeWeakRefs = null;
var staleWeakRefCount = 0;
@ -910,7 +921,7 @@ namespace Microsoft.ClearScript
}
else
{
if ((hostItem.Target.Type == hostObject.Type) && (hostItem.Flags == flags))
if ((hostItem.Target.Type == hostTarget.Type) && (hostItem.Flags == flags))
{
return hostItem;
}
@ -934,12 +945,12 @@ namespace Microsoft.ClearScript
}
}
var newHostItem = createHostItem(this, hostObject, flags);
var newHostItem = createHostItem(this, hostTarget, flags);
cacheEntry.Add(new WeakReference(newHostItem));
return newHostItem;
}
private HostItem GetOrCreateHostItemForHostType(HostType hostType, HostItemFlags flags, HostItemFactory createHostItem)
private HostItem GetOrCreateHostItemForHostType(HostType hostType, HostItemFlags flags, Func<ScriptEngine, HostTarget, HostItemFlags, HostItem> createHostItem)
{
if (hostType.Types.Length != 1)
{

Просмотреть файл

@ -217,115 +217,6 @@ namespace Microsoft.ClearScript.Util
return TryDynamicOperation(() => target.DeleteIndex(indices), out result);
}
public static object CreateInstance(this DynamicMetaObject target, object[] args)
{
var paramNames = Enumerable.Range(0, args.Length).Select(index => "a" + index).ToArray();
var paramExprs = paramNames.Select(paramName => Expression.Parameter(typeof(object), paramName)).ToArray();
var parameters = paramExprs.Select(paramExpr => new DynamicMetaObject(paramExpr, BindingRestrictions.Empty)).ToArray();
var bindResult = target.BindCreateInstance(new DynamicCreateInstanceBinder(paramNames), parameters);
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
return Invoke(block, paramExprs, args);
}
public static object Invoke(this DynamicMetaObject target, object[] args)
{
var paramNames = Enumerable.Range(0, args.Length).Select(index => "a" + index).ToArray();
var paramExprs = paramNames.Select(paramName => Expression.Parameter(typeof(object), paramName)).ToArray();
var parameters = paramExprs.Select(paramExpr => new DynamicMetaObject(paramExpr, BindingRestrictions.Empty)).ToArray();
var bindResult = target.BindInvoke(new DynamicInvokeBinder(paramNames), parameters);
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
return Invoke(block, paramExprs, args);
}
public static object InvokeMember(this DynamicMetaObject target, string name, BindingFlags invokeFlags, object[] args)
{
var paramNames = Enumerable.Range(0, args.Length).Select(index => "a" + index).ToArray();
var paramExprs = paramNames.Select(paramName => Expression.Parameter(typeof(object), paramName)).ToArray();
var parameters = paramExprs.Select(paramExpr => new DynamicMetaObject(paramExpr, BindingRestrictions.Empty)).ToArray();
var bindResult = target.BindInvokeMember(new DynamicInvokeMemberBinder(name, invokeFlags, paramNames), parameters);
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
return Invoke(block, paramExprs, args);
}
public static object GetMember(this DynamicMetaObject target, string name)
{
var bindResult = target.BindGetMember(new DynamicGetMemberBinder(name));
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
return Invoke(block);
}
public static object SetMember(this DynamicMetaObject target, string name, object value)
{
var bindResult = target.BindSetMember(new DynamicSetMemberBinder(name), CreateDynamicArg(value));
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
return Invoke(block);
}
public static bool DeleteMember(this DynamicMetaObject target, string name)
{
var bindResult = target.BindDeleteMember(new DynamicDeleteMemberBinder(name));
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
try
{
Invoke(block);
return true;
}
catch (TargetInvocationException exception)
{
if (exception.InnerException is InvalidDynamicOperationException)
{
return false;
}
throw;
}
}
public static object GetIndex(this DynamicMetaObject target, object[] indices)
{
var paramNames = Enumerable.Range(0, indices.Length).Select(index => "a" + index).ToArray();
var paramExprs = paramNames.Select(paramName => Expression.Parameter(typeof(object), paramName)).ToArray();
var parameters = paramExprs.Select(paramExpr => new DynamicMetaObject(paramExpr, BindingRestrictions.Empty)).ToArray();
var bindResult = target.BindGetIndex(new DynamicGetIndexBinder(paramNames), parameters);
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
return Invoke(block, paramExprs, indices);
}
public static object SetIndex(this DynamicMetaObject target, object[] indices, object value)
{
var paramNames = Enumerable.Range(0, indices.Length).Select(index => "a" + index).ToArray();
var paramExprs = paramNames.Select(paramName => Expression.Parameter(typeof(object), paramName)).ToArray();
var parameters = paramExprs.Select(paramExpr => new DynamicMetaObject(paramExpr, BindingRestrictions.Empty)).ToArray();
var bindResult = target.BindSetIndex(new DynamicSetIndexBinder(paramNames), parameters, CreateDynamicArg(value));
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
return Invoke(block, paramExprs, indices);
}
public static bool DeleteIndex(this DynamicMetaObject target, object[] indices)
{
var paramNames = Enumerable.Range(0, indices.Length).Select(index => "a" + index).ToArray();
var paramExprs = paramNames.Select(paramName => Expression.Parameter(typeof(object), paramName)).ToArray();
var parameters = paramExprs.Select(paramExpr => new DynamicMetaObject(paramExpr, BindingRestrictions.Empty)).ToArray();
var bindResult = target.BindDeleteIndex(new DynamicDeleteIndexBinder(paramNames), parameters);
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
try
{
Invoke(block, paramExprs, indices);
return true;
}
catch (TargetInvocationException exception)
{
if (exception.InnerException is InvalidDynamicOperationException)
{
return false;
}
throw;
}
}
#endregion
#region internal members
@ -419,27 +310,136 @@ namespace Microsoft.ClearScript.Util
}
}
private static object CreateInstance(this DynamicMetaObject target, object[] args)
{
var paramNames = Enumerable.Range(0, args.Length).Select(index => "a" + index).ToArray();
var paramExprs = paramNames.Select(paramName => Expression.Parameter(typeof(object), paramName)).ToArray();
var parameters = paramExprs.Select(paramExpr => new DynamicMetaObject(paramExpr, BindingRestrictions.Empty)).ToArray();
var bindResult = target.BindCreateInstance(new DynamicCreateInstanceBinder(paramNames), parameters);
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
return Invoke(block, paramExprs, args);
}
private static object Invoke(this DynamicMetaObject target, object[] args)
{
var paramNames = Enumerable.Range(0, args.Length).Select(index => "a" + index).ToArray();
var paramExprs = paramNames.Select(paramName => Expression.Parameter(typeof(object), paramName)).ToArray();
var parameters = paramExprs.Select(paramExpr => new DynamicMetaObject(paramExpr, BindingRestrictions.Empty)).ToArray();
var bindResult = target.BindInvoke(new DynamicInvokeBinder(paramNames), parameters);
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
return Invoke(block, paramExprs, args);
}
private static object InvokeMember(this DynamicMetaObject target, string name, BindingFlags invokeFlags, object[] args)
{
var paramNames = Enumerable.Range(0, args.Length).Select(index => "a" + index).ToArray();
var paramExprs = paramNames.Select(paramName => Expression.Parameter(typeof(object), paramName)).ToArray();
var parameters = paramExprs.Select(paramExpr => new DynamicMetaObject(paramExpr, BindingRestrictions.Empty)).ToArray();
var bindResult = target.BindInvokeMember(new DynamicInvokeMemberBinder(name, invokeFlags, paramNames), parameters);
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
return Invoke(block, paramExprs, args);
}
private static object GetMember(this DynamicMetaObject target, string name)
{
var bindResult = target.BindGetMember(new DynamicGetMemberBinder(name));
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
return Invoke(block);
}
private static object SetMember(this DynamicMetaObject target, string name, object value)
{
var bindResult = target.BindSetMember(new DynamicSetMemberBinder(name), CreateDynamicArg(value));
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
return Invoke(block);
}
private static bool DeleteMember(this DynamicMetaObject target, string name)
{
var bindResult = target.BindDeleteMember(new DynamicDeleteMemberBinder(name));
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
try
{
Invoke(block);
return true;
}
catch (TargetInvocationException exception)
{
if (exception.InnerException is InvalidDynamicOperationException)
{
return false;
}
throw;
}
}
private static object GetIndex(this DynamicMetaObject target, object[] indices)
{
var paramNames = Enumerable.Range(0, indices.Length).Select(index => "a" + index).ToArray();
var paramExprs = paramNames.Select(paramName => Expression.Parameter(typeof(object), paramName)).ToArray();
var parameters = paramExprs.Select(paramExpr => new DynamicMetaObject(paramExpr, BindingRestrictions.Empty)).ToArray();
var bindResult = target.BindGetIndex(new DynamicGetIndexBinder(paramNames), parameters);
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
return Invoke(block, paramExprs, indices);
}
private static object SetIndex(this DynamicMetaObject target, object[] indices, object value)
{
var paramNames = Enumerable.Range(0, indices.Length).Select(index => "a" + index).ToArray();
var paramExprs = paramNames.Select(paramName => Expression.Parameter(typeof(object), paramName)).ToArray();
var parameters = paramExprs.Select(paramExpr => new DynamicMetaObject(paramExpr, BindingRestrictions.Empty)).ToArray();
var bindResult = target.BindSetIndex(new DynamicSetIndexBinder(paramNames), parameters, CreateDynamicArg(value));
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
return Invoke(block, paramExprs, indices);
}
private static bool DeleteIndex(this DynamicMetaObject target, object[] indices)
{
var paramNames = Enumerable.Range(0, indices.Length).Select(index => "a" + index).ToArray();
var paramExprs = paramNames.Select(paramName => Expression.Parameter(typeof(object), paramName)).ToArray();
var parameters = paramExprs.Select(paramExpr => new DynamicMetaObject(paramExpr, BindingRestrictions.Empty)).ToArray();
var bindResult = target.BindDeleteIndex(new DynamicDeleteIndexBinder(paramNames), parameters);
var block = Expression.Block(Expression.Label(CallSiteBinder.UpdateLabel), bindResult.Expression);
try
{
Invoke(block, paramExprs, indices);
return true;
}
catch (TargetInvocationException exception)
{
if (exception.InnerException is InvalidDynamicOperationException)
{
return false;
}
throw;
}
}
private static DynamicMetaObject CreateDynamicTarget(object target)
{
var byRefArg = target as IByRefArg;
if (byRefArg != null)
{
return DynamicMetaObject.Create(byRefArg.Value, Expression.Parameter(byRefArg.Type.MakeByRefType()));
return CreateDynamicMetaObject(byRefArg.Value, Expression.Parameter(byRefArg.Type.MakeByRefType()));
}
var hostTarget = target as HostTarget;
if (hostTarget == null)
{
return DynamicMetaObject.Create(target, Expression.Constant(target));
return CreateDynamicMetaObject(target, Expression.Constant(target));
}
target = hostTarget.DynamicInvokeTarget;
if (hostTarget is HostType)
{
return DynamicMetaObject.Create(target, Expression.Constant(target));
return CreateDynamicMetaObject(target, Expression.Constant(target));
}
return DynamicMetaObject.Create(target, Expression.Constant(target, hostTarget.Type));
return CreateDynamicMetaObject(target, Expression.Constant(target, hostTarget.Type));
}
private static DynamicMetaObject CreateDynamicArg(object arg)
@ -447,22 +447,22 @@ namespace Microsoft.ClearScript.Util
var byRefArg = arg as IByRefArg;
if (byRefArg != null)
{
return DynamicMetaObject.Create(byRefArg.Value, Expression.Parameter(byRefArg.Type.MakeByRefType()));
return CreateDynamicMetaObject(byRefArg.Value, Expression.Parameter(byRefArg.Type.MakeByRefType()));
}
if (arg is HostType)
{
return DynamicMetaObject.Create(arg, Expression.Constant(arg));
return CreateDynamicMetaObject(arg, Expression.Constant(arg));
}
var hostTarget = arg as HostTarget;
if (hostTarget == null)
{
return DynamicMetaObject.Create(arg, Expression.Constant(arg));
return CreateDynamicMetaObject(arg, Expression.Constant(arg));
}
arg = hostTarget.Target;
return DynamicMetaObject.Create(arg, Expression.Constant(arg, hostTarget.Type));
return CreateDynamicMetaObject(arg, Expression.Constant(arg, hostTarget.Type));
}
private static DynamicMetaObject[] CreateDynamicArgs(object[] args)
@ -470,6 +470,11 @@ namespace Microsoft.ClearScript.Util
return args.Select(CreateDynamicArg).ToArray();
}
private static DynamicMetaObject CreateDynamicMetaObject(object value, Expression expr)
{
return new DynamicMetaObject(expr, BindingRestrictions.Empty, value);
}
private static Expression CreateThrowExpr<T>(string message) where T : Exception
{
var constructor = typeof(T).GetConstructor(new[] { typeof(string) });
@ -633,7 +638,7 @@ namespace Microsoft.ClearScript.Util
private static object InvokeMemberValue(object target, BindingFlags invokeFlags, object[] args)
{
object result;
if (InvokeHelpers.TryInvokeObject(target, BindingFlags.InvokeMethod, args, args, out result))
if (InvokeHelpers.TryInvokeObject(target, BindingFlags.InvokeMethod, args, args, true, out result))
{
return result;
}

Просмотреть файл

@ -61,6 +61,8 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq.Expressions;
using System.Reflection;
namespace Microsoft.ClearScript.Util
@ -161,7 +163,7 @@ namespace Microsoft.ClearScript.Util
return InvokeMethod(del, del.GetType().GetMethod("Invoke"), args);
}
public static bool TryInvokeObject(object target, BindingFlags invokeFlags, object[] args, object[] bindArgs, out object result)
public static bool TryInvokeObject(object target, BindingFlags invokeFlags, object[] args, object[] bindArgs, bool tryDynamic, out object result)
{
var hostTarget = target as HostTarget;
if (hostTarget != null)
@ -177,6 +179,7 @@ namespace Microsoft.ClearScript.Util
}
target = hostTarget.InvokeTarget;
tryDynamic = tryDynamic && typeof(IDynamicMetaObjectProvider).IsAssignableFrom(hostTarget.Type);
}
if ((target != null) && invokeFlags.HasFlag(BindingFlags.InvokeMethod))
@ -192,6 +195,18 @@ namespace Microsoft.ClearScript.Util
result = InvokeDelegate(del, args);
return true;
}
if (tryDynamic)
{
var dynamicMetaObjectProvider = target as IDynamicMetaObjectProvider;
if (dynamicMetaObjectProvider != null)
{
if (dynamicMetaObjectProvider.GetMetaObject(Expression.Constant(target)).TryInvoke(args, out result))
{
return true;
}
}
}
}
result = null;

Просмотреть файл

@ -268,6 +268,7 @@ namespace Microsoft.ClearScript.Util
if (type.IsInterface)
{
methods = methods.Concat(type.GetInterfaces().SelectMany(interfaceType => interfaceType.GetScriptableMethods(bindFlags)));
methods = methods.Concat(typeof(object).GetScriptableMethods(bindFlags));
}
return methods.Where(method => method.IsScriptable());
@ -289,9 +290,26 @@ namespace Microsoft.ClearScript.Util
return properties.Where(property => property.IsScriptable());
}
public static PropertyInfo GetScriptableProperty(this Type type, string name, BindingFlags bindFlags)
public static IEnumerable<PropertyInfo> GetScriptableProperties(this Type type, string name, BindingFlags bindFlags)
{
return type.GetScriptableProperties(bindFlags).FirstOrDefault(property => property.GetScriptName() == name);
return type.GetScriptableProperties(bindFlags).Where(property => property.GetScriptName() == name);
}
public static PropertyInfo GetScriptableProperty(this Type type, string name, BindingFlags bindFlags, object[] bindArgs)
{
var properties = type.GetScriptableProperties(name, bindFlags).ToArray();
if (properties.Length < 1)
{
return null;
}
if (bindArgs.Length < 1)
{
return properties.FirstOrDefault(property => property.GetIndexParameters().Length < 1);
}
return Type.DefaultBinder.SelectProperty(bindFlags, properties, null, bindArgs.Select(GetPropertyIndexType).ToArray(), null);
}
public static object CreateInstance(this Type type, params object[] args)
@ -467,5 +485,21 @@ namespace Microsoft.ClearScript.Util
var index = name.LastIndexOf('`');
return (index >= 0) ? name.Substring(0, index) : name;
}
private static Type GetPropertyIndexType(object bindArg)
{
var hostTarget = bindArg as HostTarget;
if (hostTarget != null)
{
return hostTarget.Type;
}
if (bindArg != null)
{
return bindArg.GetType();
}
throw new InvalidOperationException("Property index value must not be null");
}
}
}

Просмотреть файл

@ -102,8 +102,10 @@ using namespace std;
#ifdef _DEBUG
#define ASSERT_EVAL _ASSERTE
#define DEBUG_EVAL IGNORE_UNUSED
#else // !_DEBUG
#define ASSERT_EVAL IGNORE_UNUSED
#define DEBUG_EVAL _ASSERTE
#endif // !_DEBUG
//-----------------------------------------------------------------------------

Просмотреть файл

@ -67,28 +67,28 @@
static void* PtrFromObjectHandle(Persistent<Object> hObject)
{
return *hObject;
return hObject.ToPtr();
}
//-----------------------------------------------------------------------------
static Persistent<Object> ObjectHandleFromPtr(void* pvObject)
{
return Persistent<Object>(static_cast<Object*>(pvObject));
return Persistent<Object>::FromPtr(pvObject);
}
//-----------------------------------------------------------------------------
static void* PtrFromScriptHandle(Persistent<Script> hScript)
{
return *hScript;
return hScript.ToPtr();
}
//-----------------------------------------------------------------------------
static Persistent<Script> ScriptHandleFromPtr(void* pvScript)
{
return Persistent<Script>(static_cast<Script*>(pvScript));
return Persistent<Script>::FromPtr(pvScript);
}
//-----------------------------------------------------------------------------
@ -575,6 +575,12 @@ V8ContextImpl::~V8ContextImpl()
Dispose(m_hContext);
V8::ContextDisposedNotification();
// exit handle scope to maximize GC benefit (see below)
END_ISOLATE_SCOPE
BEGIN_ISOLATE_SCOPE
// The context is gone, but it may have contained host object holders
// that are now awaiting collection. Forcing collection will release
// the corresponding host objects. This isn't strictly necessary, but
@ -1204,12 +1210,13 @@ void V8ContextImpl::InvokeHostObject(const FunctionCallbackInfo<Value>& info)
void V8ContextImpl::DisposeWeakHandle(Isolate* pIsolate, Persistent<Object>* phObject, void* pvV8ObjectCache)
{
IGNORE_UNUSED(pIsolate);
auto pHolder = ::GetHostObjectHolder(*phObject);
ASSERT_EVAL(HostObjectHelpers::RemoveV8ObjectCacheEntry(pvV8ObjectCache, pHolder->GetObject()));
delete pHolder;
HostObjectHelpers::Release(pvV8ObjectCache);
phObject->Dispose(pIsolate);
phObject->Dispose();
}
//-----------------------------------------------------------------------------

Просмотреть файл

@ -121,7 +121,7 @@ private:
~Scope()
{
if (!uncaught_exception() &&m_pContextImpl->m_hContext->HasOutOfMemoryException())
if (!uncaught_exception() && m_pContextImpl->m_hContext->HasOutOfMemoryException())
{
m_pContextImpl->m_spIsolateImpl->ThrowOutOfMemoryException();
}
@ -174,16 +174,28 @@ private:
return m_spIsolateImpl->CreateLocal(hTarget);
}
template <typename T>
Local<T> CreateLocal(Persistent<T> hTarget)
{
return m_spIsolateImpl->CreateLocal(hTarget);
}
template <typename T>
Persistent<T> CreatePersistent(Handle<T> hTarget)
{
return m_spIsolateImpl->CreatePersistent(hTarget);
}
template <typename T, typename P>
Persistent<T> MakeWeak(Persistent<T> hTarget, P* pvArg, typename WeakReferenceCallbacks<T, P>::Revivable pCallback)
template <typename T>
Persistent<T> CreatePersistent(Persistent<T> hTarget)
{
return m_spIsolateImpl->MakeWeak(hTarget, pvArg, pCallback);
return m_spIsolateImpl->CreatePersistent(hTarget);
}
template <typename T, typename TArg>
Persistent<T> MakeWeak(Persistent<T> hTarget, TArg* pArg, void (*pCallback)(Isolate*, Persistent<T>*, TArg*))
{
return m_spIsolateImpl->MakeWeak(hTarget, pArg, pCallback);
}
template <typename T>

Просмотреть файл

@ -67,14 +67,14 @@
static void* PtrFromScriptHandle(Persistent<Script> hScript)
{
return *hScript;
return hScript.ToPtr();
}
//-----------------------------------------------------------------------------
static Persistent<Script> ScriptHandleFromPtr(void* pvScript)
{
return Persistent<Script>(static_cast<Script*>(pvScript));
return Persistent<Script>::FromPtr(pvScript);
}
//-----------------------------------------------------------------------------
@ -237,7 +237,7 @@ V8ScriptHolder* V8IsolateImpl::Compile(const wchar_t* pDocumentName, const wchar
BEGIN_ISOLATE_SCOPE
SharedPtr<V8ContextImpl> spContextImpl((m_ContextPtrs.size() > 0) ? m_ContextPtrs.front() : new V8ContextImpl(this, nullptr, false, true, 0));
return spContextImpl->Compile(pDocumentName, pCode);
return spContextImpl->Compile(pDocumentName, pCode);
END_ISOLATE_SCOPE
}

Просмотреть файл

@ -141,23 +141,34 @@ public:
return Local<T>::New(m_pIsolate, hTarget);
}
template <typename T>
Local<T> CreateLocal(Persistent<T> hTarget)
{
return hTarget.CreateLocal(m_pIsolate);
}
template <typename T>
Persistent<T> CreatePersistent(Handle<T> hTarget)
{
return Persistent<T>::New(m_pIsolate, hTarget);
}
template <typename T, typename P>
Persistent<T> MakeWeak(Persistent<T> hTarget, P* pvArg, typename WeakReferenceCallbacks<T, P>::Revivable pCallback)
template <typename T>
Persistent<T> CreatePersistent(Persistent<T> hTarget)
{
hTarget.MakeWeak(m_pIsolate, pvArg, pCallback);
return hTarget;
return Persistent<T>::New(m_pIsolate, hTarget);
}
template <typename T, typename TArg>
Persistent<T> MakeWeak(Persistent<T> hTarget, TArg* pArg, void (*pCallback)(Isolate*, Persistent<T>*, TArg*))
{
return hTarget.MakeWeak(m_pIsolate, pArg, pCallback);
}
template <typename T>
void Dispose(Persistent<T> hTarget)
{
hTarget.Dispose(m_pIsolate);
hTarget.Dispose();
}
void TerminateExecution()

Просмотреть файл

@ -67,9 +67,297 @@
#pragma warning(push, 3)
#define V8_USE_UNSAFE_HANDLES
#include "v8.h"
#include "v8-debug.h"
using namespace v8;
#pragma warning(pop)
//-----------------------------------------------------------------------------
// V8FastPersistent - a (nearly) drop-in replacement for classic v8::Persistent
//
// WARNING: This class breaks encapsulation in order to avoid heap allocation.
// It makes assumptions about v8::Persistent implementation and memory layout.
//-----------------------------------------------------------------------------
template <typename T>
class V8FastPersistent
{
template <typename TOther>
friend class V8FastPersistent;
public:
V8FastPersistent<T>():
m_pValue(nullptr)
{
}
template <typename TOther>
static V8FastPersistent<T> New(Isolate* pIsolate, const Handle<TOther>& hValue)
{
Persistent<T> hTemp(pIsolate, hValue);
return V8FastPersistent<T>(GetPtrAndClear(hTemp));
}
template <typename TOther>
static V8FastPersistent<T> New(Isolate* pIsolate, const V8FastPersistent<TOther>& hValue)
{
Persistent<T> hTemp(pIsolate, hValue.AsPersistent());
return V8FastPersistent<T>(GetPtrAndClear(hTemp));
}
bool IsEmpty() const
{
return AsPersistent().IsEmpty();
}
void* ToPtr() const
{
return m_pValue;
}
static V8FastPersistent<T> FromPtr(void* pvValue)
{
return V8FastPersistent<T>(static_cast<T*>(pvValue));
}
Handle<T> operator->() const
{
return CreateHandle();
}
template <typename TOther>
operator Handle<TOther>() const
{
return CreateHandle();
}
Local<T> CreateLocal(Isolate* pIsolate) const
{
return Local<T>::New(pIsolate, AsPersistent());
}
template <typename TArg>
V8FastPersistent<T> MakeWeak(Isolate* pIsolate, TArg* pArg, void (*pCallback)(Isolate*, V8FastPersistent<T>*, TArg*))
{
IGNORE_UNUSED(pIsolate);
AsPersistent().SetWeak(new WeakCallbackContext<TArg>(m_pValue, pArg, pCallback), WeakCallback);
return *this;
}
void Dispose()
{
AsPersistent().Dispose();
}
private:
explicit V8FastPersistent<T>(T* pValue):
m_pValue(pValue)
{
}
Handle<T> CreateHandle() const
{
return Handle<T>::New(Isolate::GetCurrent(), AsPersistent());
}
const Persistent<T>& AsPersistent() const
{
return *(reinterpret_cast<const Persistent<T>*>(&m_pValue));
}
Persistent<T>& AsPersistent()
{
return *(reinterpret_cast<Persistent<T>*>(&m_pValue));
}
static T* GetPtrAndClear(Persistent<T>& hValue)
{
auto ppValue = reinterpret_cast<T**>(&hValue);
auto pValue = *ppValue;
*ppValue = nullptr;
_ASSERTE(hValue.IsEmpty());
return pValue;
}
template <typename TArg>
class WeakCallbackContext
{
public:
WeakCallbackContext(T* pValue, TArg* pArg, void (*pCallback)(Isolate*, V8FastPersistent<T>*, TArg*)):
m_pValue(pValue),
m_pArg(pArg),
m_pCallback(pCallback)
{
}
void InvokeCallback(Isolate* pIsolate) const
{
V8FastPersistent<T> hTarget(m_pValue);
m_pCallback(pIsolate, &hTarget, m_pArg);
}
private:
T* m_pValue;
TArg* m_pArg;
void (*m_pCallback)(Isolate*, V8FastPersistent<T>*, TArg*);
};
template <typename TArg>
static void WeakCallback(const WeakCallbackData<T, TArg>& data)
{
auto pContext = data.GetParameter();
_ASSERTE(pContext);
pContext->InvokeCallback(data.GetIsolate());
delete pContext;
}
T* m_pValue;
};
//-----------------------------------------------------------------------------
// V8SafePersistent - a (nearly) drop-in replacement for classic v8::Persistent
//-----------------------------------------------------------------------------
template <typename T>
class V8SafePersistent
{
template <typename TOther>
friend class V8SafePersistent;
public:
V8SafePersistent<T>():
m_pImpl(nullptr)
{
}
template <typename TOther>
static V8SafePersistent<T> New(Isolate* pIsolate, const Handle<TOther>& hValue)
{
return V8SafePersistent<T>(new Persistent<T>(pIsolate, hValue));
}
template <typename TOther>
static V8SafePersistent<T> New(Isolate* pIsolate, const V8SafePersistent<TOther>& hValue)
{
return V8SafePersistent<T>(new Persistent<T>(pIsolate, hValue.GetImpl()));
}
bool IsEmpty() const
{
return (m_pImpl == nullptr) || m_pImpl->IsEmpty();
}
void* ToPtr() const
{
return m_pImpl;
}
static V8SafePersistent<T> FromPtr(void* pvImpl)
{
return V8SafePersistent<T>(static_cast<Persistent<T>*>(pvImpl));
}
Handle<T> operator->() const
{
return CreateHandle();
}
template <typename TOther>
operator Handle<TOther>() const
{
return CreateHandle();
}
Local<T> CreateLocal(Isolate* pIsolate) const
{
return Local<T>::New(pIsolate, GetImpl());
}
template <typename TArg>
V8SafePersistent<T> MakeWeak(Isolate* pIsolate, TArg* pArg, void (*pCallback)(Isolate*, V8SafePersistent<T>*, TArg*))
{
IGNORE_UNUSED(pIsolate);
_ASSERTE(m_pImpl != nullptr);
m_pImpl->SetWeak(new WeakCallbackContext<TArg>(m_pImpl, pArg, pCallback), WeakCallback);
return *this;
}
void Dispose()
{
if (m_pImpl != nullptr)
{
m_pImpl->Dispose();
delete m_pImpl;
m_pImpl = nullptr;
}
}
private:
explicit V8SafePersistent<T>(Persistent<T>* pImpl):
m_pImpl(pImpl)
{
}
Handle<T> CreateHandle() const
{
return Handle<T>::New(Isolate::GetCurrent(), GetImpl());
}
const Persistent<T>& GetImpl() const
{
return (m_pImpl != nullptr) ? *m_pImpl : ms_EmptyImpl;
}
template <typename TArg>
class WeakCallbackContext
{
public:
WeakCallbackContext(Persistent<T>* pImpl, TArg* pArg, void (*pCallback)(Isolate*, V8SafePersistent<T>*, TArg*)):
m_pImpl(pImpl),
m_pArg(pArg),
m_pCallback(pCallback)
{
}
void InvokeCallback(Isolate* pIsolate) const
{
V8SafePersistent<T> hTarget(m_pImpl);
m_pCallback(pIsolate, &hTarget, m_pArg);
}
private:
Persistent<T>* m_pImpl;
TArg* m_pArg;
void (*m_pCallback)(Isolate*, V8SafePersistent<T>*, TArg*);
};
template <typename TArg>
static void WeakCallback(const WeakCallbackData<T, TArg>& data)
{
auto pContext = data.GetParameter();
_ASSERTE(pContext);
pContext->InvokeCallback(data.GetIsolate());
delete pContext;
}
Persistent<T>* m_pImpl;
static const Persistent<T> ms_EmptyImpl;
};
template <typename T>
const Persistent<T> V8SafePersistent<T>::ms_EmptyImpl;
//-----------------------------------------------------------------------------
// define classic v8::Persistent replacement
//-----------------------------------------------------------------------------
#define Persistent V8FastPersistent

Просмотреть файл

@ -1,6 +1,6 @@
Index: src/utils.h
===================================================================
--- src/utils.h (revision 16272)
--- src/utils.h (revision 17179)
+++ src/utils.h (working copy)
@@ -109,7 +109,7 @@
// These are kind of 2's complement reciprocal of the divisors.
@ -13,7 +13,7 @@ Index: src/utils.h
// lithium-codegen-arm.cc : LCodeGen::TryEmitSignedIntegerDivisionByConstant().
Index: tools/gyp/v8.gyp
===================================================================
--- tools/gyp/v8.gyp (revision 16272)
--- tools/gyp/v8.gyp (revision 17179)
+++ tools/gyp/v8.gyp (working copy)
@@ -33,6 +33,7 @@
'targets': [

Двоичные данные
ClearScript/doc/Reference.chm

Двоичный файл не отображается.

Просмотреть файл

@ -69,5 +69,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("(c) Microsoft Corporation")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("5.3.7.0")]
[assembly: AssemblyFileVersion("5.3.7.0")]
[assembly: AssemblyVersion("5.3.8.0")]
[assembly: AssemblyFileVersion("5.3.8.0")]

Просмотреть файл

@ -69,5 +69,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("(c) Microsoft Corporation")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("5.3.7.0")]
[assembly: AssemblyFileVersion("5.3.7.0")]
[assembly: AssemblyVersion("5.3.8.0")]
[assembly: AssemblyFileVersion("5.3.8.0")]

Просмотреть файл

@ -254,6 +254,17 @@ namespace Microsoft.ClearScript.Test
}
}
[TestMethod, TestCategory("BugFix")]
public void BugFix_GenericDelegateConstructorWithArgument()
{
engine.AddHostType("Func", "System.Func");
engine.AddHostType("StringT", typeof(string));
engine.AddHostType("IntT", typeof(int));
var func = (Func<string, int>)engine.Evaluate("new Func(StringT, IntT, function (s) { return s.length; })");
const string testString = "floccinaucinihilipilification";
Assert.AreEqual(testString.Length, func(testString));
}
// ReSharper restore InconsistentNaming
#endregion

Просмотреть файл

@ -56,6 +56,7 @@
<Compile Include="BugFixTest.cs" />
<Compile Include="CrossEngineTest.cs" />
<Compile Include="DynamicHostItemTest.cs" />
<Compile Include="DynamicTestObject.cs" />
<Compile Include="ExplicitBaseInterfaceMemberAccessTest.cs" />
<Compile Include="BaseInterfaceMemberAccessTest.cs" />
<Compile Include="BaseMemberAccessTest.cs" />

Просмотреть файл

@ -0,0 +1,239 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Microsoft Public License (MS-PL)
//
// This license governs use of the accompanying software. If you use the
// software, you accept this license. If you do not accept the license, do not
// use the software.
//
// 1. Definitions
//
// The terms "reproduce," "reproduction," "derivative works," and
// "distribution" have the same meaning here as under U.S. copyright law. A
// "contribution" is the original software, or any additions or changes to
// the software. A "contributor" is any person that distributes its
// contribution under this license. "Licensed patents" are a contributor's
// patent claims that read directly on its contribution.
//
// 2. Grant of Rights
//
// (A) Copyright Grant- Subject to the terms of this license, including the
// license conditions and limitations in section 3, each contributor
// grants you a non-exclusive, worldwide, royalty-free copyright license
// to reproduce its contribution, prepare derivative works of its
// contribution, and distribute its contribution or any derivative works
// that you create.
//
// (B) Patent Grant- Subject to the terms of this license, including the
// license conditions and limitations in section 3, each contributor
// grants you a non-exclusive, worldwide, royalty-free license under its
// licensed patents to make, have made, use, sell, offer for sale,
// import, and/or otherwise dispose of its contribution in the software
// or derivative works of the contribution in the software.
//
// 3. Conditions and Limitations
//
// (A) No Trademark License- This license does not grant you rights to use
// any contributors' name, logo, or trademarks.
//
// (B) If you bring a patent claim against any contributor over patents that
// you claim are infringed by the software, your patent license from such
// contributor to the software ends automatically.
//
// (C) If you distribute any portion of the software, you must retain all
// copyright, patent, trademark, and attribution notices that are present
// in the software.
//
// (D) If you distribute any portion of the software in source code form, you
// may do so only under this license by including a complete copy of this
// license with your distribution. If you distribute any portion of the
// software in compiled or object code form, you may only do so under a
// license that complies with this license.
//
// (E) The software is licensed "as-is." You bear the risk of using it. The
// contributors give no express warranties, guarantees or conditions. You
// may have additional consumer rights under your local laws which this
// license cannot change. To the extent permitted under your local laws,
// the contributors exclude the implied warranties of merchantability,
// fitness for a particular purpose and non-infringement.
//
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
namespace Microsoft.ClearScript.Test
{
public sealed class DynamicTestObject : DynamicObject
{
private readonly Dictionary<string, object> memberMap = new Dictionary<string, object>();
private readonly Dictionary<string, object> indexMap = new Dictionary<string, object>();
public int SomeField = 12345;
public string SomeProperty
{
get { return "Bogus"; }
}
public double SomeMethod()
{
return Math.PI;
}
public string SomeMethod(string unused, params object[] args)
{
return string.Join("+", args);
}
public override bool TryCreateInstance(CreateInstanceBinder binder, object[] args, out object result)
{
if (args.Length > 0)
{
result = string.Join(" ", args);
return true;
}
return base.TryCreateInstance(binder, args, out result);
}
public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
{
if (args.Length > 0)
{
result = string.Join(",", args);
return true;
}
return base.TryInvoke(binder, args, out result);
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
if ((binder.Name == "DynamicMethod") && (args.Length > 0))
{
result = string.Join("-", args);
return true;
}
if ((binder.Name == "SomeField") && (args.Length > 0))
{
result = string.Join(".", args);
return true;
}
if ((binder.Name == "SomeProperty") && (args.Length > 0))
{
result = string.Join(":", args);
return true;
}
if ((binder.Name == "SomeMethod") && (args.Length > 0))
{
result = string.Join(";", args);
return true;
}
return base.TryInvokeMember(binder, args, out result);
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (!binder.Name.StartsWith("Z", StringComparison.Ordinal))
{
return memberMap.TryGetValue(binder.Name, out result);
}
return base.TryGetMember(binder, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (!binder.Name.StartsWith("Z", StringComparison.Ordinal))
{
memberMap[binder.Name] = value;
return true;
}
return base.TrySetMember(binder, value);
}
public override bool TryDeleteMember(DeleteMemberBinder binder)
{
if (!binder.Name.StartsWith("Z", StringComparison.Ordinal))
{
return memberMap.Remove(binder.Name);
}
return base.TryDeleteMember(binder);
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
if (indexes.All(index => (index is int) || (index is string)))
{
return indexMap.TryGetValue(string.Join(":", indexes), out result);
}
return base.TryGetIndex(binder, indexes, out result);
}
public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
{
if (indexes.All(index => (index is int) || (index is string)))
{
indexMap[string.Join(":", indexes)] = value;
return true;
}
return base.TrySetIndex(binder, indexes, value);
}
public override bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes)
{
if (indexes.All(index => (index is int) || (index is string)))
{
return indexMap.Remove(string.Join(":", indexes));
}
return base.TryDeleteIndex(binder, indexes);
}
public override bool TryConvert(ConvertBinder binder, out object result)
{
if (binder.ReturnType == typeof(int))
{
result = 98765;
return true;
}
if (binder.ReturnType == typeof(string))
{
result = "Booyakasha!";
return true;
}
return base.TryConvert(binder, out result);
}
public override IEnumerable<string> GetDynamicMemberNames()
{
foreach (var name in memberMap.Keys)
{
yield return name;
}
yield return "DynamicMethod";
yield return "SomeField";
yield return "SomeProperty";
yield return "SomeMethod";
}
public override string ToString()
{
return "Super Bass-O-Matic '76";
}
}
}

Просмотреть файл

@ -62,6 +62,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Linq;
@ -711,6 +712,221 @@ namespace Microsoft.ClearScript.Test
});
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_CreateInstance()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo bar baz qux", engine.Evaluate("new testObject('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_CreateInstance_Fail()
{
engine.Script.testObject = new DynamicTestObject();
TestUtil.AssertException<InvalidOperationException>(() => engine.Evaluate("new testObject()"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_Invoke()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo,bar,baz,qux", engine.Evaluate("testObject('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_Invoke_Fail()
{
engine.Script.testObject = new DynamicTestObject();
TestUtil.AssertException<InvalidOperationException>(() => engine.Evaluate("testObject()"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_InvokeMethod()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo-bar-baz-qux", engine.Evaluate("testObject.DynamicMethod('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_InvokeMethod_Fail()
{
engine.Script.testObject = new DynamicTestObject();
TestUtil.AssertException<MissingMemberException>(() => engine.Evaluate("testObject.DynamicMethod()"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_InvokeMethod_FieldOverride()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo.bar.baz.qux", engine.Evaluate("testObject.SomeField('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_InvokeMethod_FieldOverride_Fail()
{
engine.Script.testObject = new DynamicTestObject();
TestUtil.AssertException<MissingMemberException>(() => engine.Evaluate("testObject.SomeField()"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_InvokeMethod_PropertyOverride()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo:bar:baz:qux", engine.Evaluate("testObject.SomeProperty('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_InvokeMethod_PropertyOverride_Fail()
{
engine.Script.testObject = new DynamicTestObject();
TestUtil.AssertException<MissingMemberException>(() => engine.Evaluate("testObject.SomeProperty()"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_InvokeMethod_DynamicOverload()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo;bar;baz;qux", engine.Evaluate("testObject.SomeMethod('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_InvokeMethod_NonDynamicOverload()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual(Math.PI, engine.Evaluate("testObject.SomeMethod()"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_InvokeMethod_NonDynamic()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("Super Bass-O-Matic '76", engine.Evaluate("testObject.ToString()"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_StaticType_Field()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.IsInstanceOfType(engine.Evaluate("testObject.SomeField"), typeof(HostMethod));
Assert.AreEqual(12345, engine.Evaluate("host.toStaticType(testObject).SomeField"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_StaticType_Property()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.IsInstanceOfType(engine.Evaluate("testObject.SomeProperty"), typeof(HostMethod));
Assert.AreEqual("Bogus", engine.Evaluate("host.toStaticType(testObject).SomeProperty"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_StaticType_Method()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.AreEqual("bar+baz+qux", engine.Evaluate("host.toStaticType(testObject).SomeMethod('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_Property()
{
engine.Script.testObject = new DynamicTestObject();
Assert.IsInstanceOfType(engine.Evaluate("testObject.foo"), typeof(Undefined));
Assert.AreEqual(123, engine.Evaluate("testObject.foo = 123"));
Assert.AreEqual(123, engine.Evaluate("testObject.foo"));
Assert.IsTrue((bool)engine.Evaluate("delete testObject.foo"));
Assert.IsInstanceOfType(engine.Evaluate("testObject.foo"), typeof(Undefined));
TestUtil.AssertException<ScriptEngineException>(() => engine.Evaluate("delete testObject.foo"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_Property_Fail()
{
engine.Script.testObject = new DynamicTestObject();
Assert.IsInstanceOfType(engine.Evaluate("testObject.Zfoo"), typeof(Undefined));
TestUtil.AssertException<MissingMemberException>(() => engine.Evaluate("testObject.Zfoo = 123"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_Property_Invoke()
{
engine.Script.testObject = new DynamicTestObject();
Assert.IsInstanceOfType(engine.Evaluate("testObject.foo"), typeof(Undefined));
Assert.IsInstanceOfType(engine.Evaluate("testObject.foo = function(x) { return x.length; }"), typeof(DynamicObject));
Assert.AreEqual("floccinaucinihilipilification".Length, engine.Evaluate("testObject.foo('floccinaucinihilipilification')"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_Property_Invoke_Nested()
{
engine.Script.testObject = new DynamicTestObject();
Assert.IsInstanceOfType(engine.Evaluate("testObject.foo"), typeof(Undefined));
Assert.IsInstanceOfType(engine.Evaluate("testObject.foo = testObject"), typeof(DynamicTestObject));
Assert.AreEqual("foo,bar,baz,qux", engine.Evaluate("testObject.foo('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_Element()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.IsInstanceOfType(engine.Evaluate("host.getElement(testObject, 1, 2, 3, 'foo')"), typeof(Undefined));
Assert.AreEqual("bar", engine.Evaluate("host.setElement(testObject, 'bar', 1, 2, 3, 'foo')"));
Assert.AreEqual("bar", engine.Evaluate("host.getElement(testObject, 1, 2, 3, 'foo')"));
Assert.IsTrue((bool)engine.Evaluate("host.removeElement(testObject, 1, 2, 3, 'foo')"));
Assert.IsInstanceOfType(engine.Evaluate("host.getElement(testObject, 1, 2, 3, 'foo')"), typeof(Undefined));
Assert.IsFalse((bool)engine.Evaluate("host.removeElement(testObject, 1, 2, 3, 'foo')"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_Element_Fail()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.IsInstanceOfType(engine.Evaluate("host.getElement(testObject, 1, 2, 3, Math.PI)"), typeof(Undefined));
TestUtil.AssertException<InvalidOperationException>(() => engine.Evaluate("host.setElement(testObject, 'bar', 1, 2, 3, Math.PI)"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_DynamicHostObject_Element_Convert()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
engine.AddHostType("int_t", typeof(int));
engine.AddHostType("string_t", typeof(string));
Assert.AreEqual(98765, engine.Evaluate("host.cast(int_t, testObject)"));
Assert.AreEqual("Booyakasha!", engine.Evaluate("host.cast(string_t, testObject)"));
}
[TestMethod, TestCategory("JScriptEngine")]
public void JScriptEngine_HostIndexers()
{
engine.Script.testObject = new TestObject();
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item(123)"));
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item.get(123)"));
Assert.AreEqual(Math.PI, engine.Evaluate("testObject.Item(123) = Math.PI"));
Assert.AreEqual(Math.PI, engine.Evaluate("testObject.Item(123)"));
Assert.AreEqual(Math.E, engine.Evaluate("testObject.Item.set(123, Math.E)"));
Assert.AreEqual(Math.E, engine.Evaluate("testObject.Item.get(123)"));
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item('456')"));
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item.get('456')"));
Assert.AreEqual(Math.Sqrt(2), engine.Evaluate("testObject.Item('456') = Math.sqrt(2)"));
Assert.AreEqual(Math.Sqrt(2), engine.Evaluate("testObject.Item('456')"));
Assert.AreEqual(Math.Sqrt(3), engine.Evaluate("testObject.Item.set('456', Math.sqrt(3))"));
Assert.AreEqual(Math.Sqrt(3), engine.Evaluate("testObject.Item.get('456')"));
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item(123, '456', 789.987, -0.12345)"));
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item.get(123, '456', 789.987, -0.12345)"));
Assert.AreEqual(Math.Sqrt(5), engine.Evaluate("testObject.Item(123, '456', 789.987, -0.12345) = Math.sqrt(5)"));
Assert.AreEqual(Math.Sqrt(5), engine.Evaluate("testObject.Item(123, '456', 789.987, -0.12345)"));
Assert.AreEqual(Math.Sqrt(7), engine.Evaluate("testObject.Item.set(123, '456', 789.987, -0.12345, Math.sqrt(7))"));
Assert.AreEqual(Math.Sqrt(7), engine.Evaluate("testObject.Item.get(123, '456', 789.987, -0.12345)"));
}
// ReSharper restore InconsistentNaming
#endregion

Просмотреть файл

@ -69,5 +69,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("(c) Microsoft Corporation")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("5.3.7.0")]
[assembly: AssemblyFileVersion("5.3.7.0")]
[assembly: AssemblyVersion("5.3.8.0")]
[assembly: AssemblyFileVersion("5.3.8.0")]

Просмотреть файл

@ -60,6 +60,8 @@
//
using System;
using System.Collections.Generic;
using System.Globalization;
namespace Microsoft.ClearScript.Test
{
@ -109,6 +111,26 @@ namespace Microsoft.ClearScript.Test
return TestUtil.CalcTestValue(new Guid("06407870-c4dc-40f8-95ec-8d743c77c8b2"), this, typeof(T), arg);
}
private readonly Dictionary<string, object> dict = new Dictionary<string, object>();
public object this[string key]
{
get { return dict[key]; }
set { dict[key] = value; }
}
public object this[int index]
{
get { return dict[index.ToString(CultureInfo.InvariantCulture)]; }
set { dict[index.ToString(CultureInfo.InvariantCulture)] = value; }
}
public object this[object i1, object i2, object i3, object i4]
{
get { return dict[string.Join(":", i1, i2, i3, i4)]; }
set { dict[string.Join(":", i1, i2, i3, i4)] = value; }
}
#region Implementation of ITestInterface
public int[] InterfaceProperty { get; set; }

Просмотреть файл

@ -62,6 +62,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Linq;
@ -917,6 +918,215 @@ namespace Microsoft.ClearScript.Test
Assert.IsTrue(usedHeapSize > engine.GetRuntimeHeapInfo().UsedHeapSize);
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_CreateInstance()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo bar baz qux", engine.Evaluate("new testObject('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_CreateInstance_Fail()
{
engine.Script.testObject = new DynamicTestObject();
TestUtil.AssertException<InvalidOperationException>(() => engine.Evaluate("new testObject()"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_Invoke()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo,bar,baz,qux", engine.Evaluate("testObject('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_Invoke_Fail()
{
engine.Script.testObject = new DynamicTestObject();
TestUtil.AssertException<InvalidOperationException>(() => engine.Evaluate("testObject()"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_InvokeMethod()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo-bar-baz-qux", engine.Evaluate("testObject.DynamicMethod('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_InvokeMethod_Fail()
{
engine.Script.testObject = new DynamicTestObject();
TestUtil.AssertException<MissingMemberException>(() => engine.Evaluate("testObject.DynamicMethod()"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_InvokeMethod_FieldOverride()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo.bar.baz.qux", engine.Evaluate("testObject.SomeField('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_InvokeMethod_FieldOverride_Fail()
{
engine.Script.testObject = new DynamicTestObject();
TestUtil.AssertException<MissingMemberException>(() => engine.Evaluate("testObject.SomeField()"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_InvokeMethod_PropertyOverride()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo:bar:baz:qux", engine.Evaluate("testObject.SomeProperty('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_InvokeMethod_PropertyOverride_Fail()
{
engine.Script.testObject = new DynamicTestObject();
TestUtil.AssertException<MissingMemberException>(() => engine.Evaluate("testObject.SomeProperty()"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_InvokeMethod_DynamicOverload()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo;bar;baz;qux", engine.Evaluate("testObject.SomeMethod('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_InvokeMethod_NonDynamicOverload()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual(Math.PI, engine.Evaluate("testObject.SomeMethod()"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_InvokeMethod_NonDynamic()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("Super Bass-O-Matic '76", engine.Evaluate("testObject.ToString()"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_StaticType_Field()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.IsInstanceOfType(engine.Evaluate("testObject.SomeField"), typeof(HostMethod));
Assert.AreEqual(12345, engine.Evaluate("host.toStaticType(testObject).SomeField"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_StaticType_Property()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.IsInstanceOfType(engine.Evaluate("testObject.SomeProperty"), typeof(HostMethod));
Assert.AreEqual("Bogus", engine.Evaluate("host.toStaticType(testObject).SomeProperty"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_StaticType_Method()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.AreEqual("bar+baz+qux", engine.Evaluate("host.toStaticType(testObject).SomeMethod('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_Property()
{
engine.Script.testObject = new DynamicTestObject();
Assert.IsInstanceOfType(engine.Evaluate("testObject.foo"), typeof(Undefined));
Assert.AreEqual(123, engine.Evaluate("testObject.foo = 123"));
Assert.AreEqual(123, engine.Evaluate("testObject.foo"));
Assert.IsTrue((bool)engine.Evaluate("delete testObject.foo"));
Assert.IsInstanceOfType(engine.Evaluate("testObject.foo"), typeof(Undefined));
Assert.IsFalse((bool)engine.Evaluate("delete testObject.foo"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_Property_Fail()
{
engine.Script.testObject = new DynamicTestObject();
Assert.IsInstanceOfType(engine.Evaluate("testObject.Zfoo"), typeof(Undefined));
TestUtil.AssertException<MissingMemberException>(() => engine.Evaluate("testObject.Zfoo = 123"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_Property_Invoke()
{
engine.Script.testObject = new DynamicTestObject();
Assert.IsInstanceOfType(engine.Evaluate("testObject.foo"), typeof(Undefined));
Assert.IsInstanceOfType(engine.Evaluate("testObject.foo = function(x) { return x.length; }"), typeof(DynamicObject));
Assert.AreEqual("floccinaucinihilipilification".Length, engine.Evaluate("testObject.foo('floccinaucinihilipilification')"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_Property_Invoke_Nested()
{
engine.Script.testObject = new DynamicTestObject();
Assert.IsInstanceOfType(engine.Evaluate("testObject.foo"), typeof(Undefined));
Assert.IsInstanceOfType(engine.Evaluate("testObject.foo = testObject"), typeof(DynamicTestObject));
Assert.AreEqual("foo,bar,baz,qux", engine.Evaluate("testObject.foo('foo', 'bar', 'baz', 'qux')"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_Element()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.IsInstanceOfType(engine.Evaluate("host.getElement(testObject, 1, 2, 3, 'foo')"), typeof(Undefined));
Assert.AreEqual("bar", engine.Evaluate("host.setElement(testObject, 'bar', 1, 2, 3, 'foo')"));
Assert.AreEqual("bar", engine.Evaluate("host.getElement(testObject, 1, 2, 3, 'foo')"));
Assert.IsTrue((bool)engine.Evaluate("host.removeElement(testObject, 1, 2, 3, 'foo')"));
Assert.IsInstanceOfType(engine.Evaluate("host.getElement(testObject, 1, 2, 3, 'foo')"), typeof(Undefined));
Assert.IsFalse((bool)engine.Evaluate("host.removeElement(testObject, 1, 2, 3, 'foo')"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_Element_Fail()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.IsInstanceOfType(engine.Evaluate("host.getElement(testObject, 1, 2, 3, Math.PI)"), typeof(Undefined));
TestUtil.AssertException<InvalidOperationException>(() => engine.Evaluate("host.setElement(testObject, 'bar', 1, 2, 3, Math.PI)"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_DynamicHostObject_Element_Convert()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
engine.AddHostType("int_t", typeof(int));
engine.AddHostType("string_t", typeof(string));
Assert.AreEqual(98765, engine.Evaluate("host.cast(int_t, testObject)"));
Assert.AreEqual("Booyakasha!", engine.Evaluate("host.cast(string_t, testObject)"));
}
[TestMethod, TestCategory("V8ScriptEngine")]
public void V8ScriptEngine_HostIndexers()
{
engine.Script.testObject = new TestObject();
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item(123)"));
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item.get(123)"));
Assert.AreEqual(Math.E, engine.Evaluate("testObject.Item.set(123, Math.E)"));
Assert.AreEqual(Math.E, engine.Evaluate("testObject.Item.get(123)"));
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item('456')"));
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item.get('456')"));
Assert.AreEqual(Math.Sqrt(3), engine.Evaluate("testObject.Item.set('456', Math.sqrt(3))"));
Assert.AreEqual(Math.Sqrt(3), engine.Evaluate("testObject.Item.get('456')"));
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item(123, '456', 789.987, -0.12345)"));
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item.get(123, '456', 789.987, -0.12345)"));
Assert.AreEqual(Math.Sqrt(7), engine.Evaluate("testObject.Item.set(123, '456', 789.987, -0.12345, Math.sqrt(7))"));
Assert.AreEqual(Math.Sqrt(7), engine.Evaluate("testObject.Item.get(123, '456', 789.987, -0.12345)"));
}
// ReSharper restore InconsistentNaming
#endregion

Просмотреть файл

@ -62,6 +62,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Linq;
@ -640,6 +641,228 @@ namespace Microsoft.ClearScript.Test
});
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_CreateInstance()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.AreEqual("foo bar baz qux", engine.Evaluate("host.newObj(testObject, \"foo\", \"bar\", \"baz\", \"qux\")"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_CreateInstance_Fail()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
TestUtil.AssertException<InvalidOperationException>(() => engine.Evaluate("host.newObj(testObject)"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_Invoke()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo,bar,baz,qux", engine.Evaluate("testObject(\"foo\", \"bar\", \"baz\", \"qux\")"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_Invoke_Fail()
{
engine.Script.testObject = new DynamicTestObject();
TestUtil.AssertException<InvalidOperationException>(() => engine.Evaluate("testObject()"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_InvokeMethod()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo-bar-baz-qux", engine.Evaluate("testObject.DynamicMethod(\"foo\", \"bar\", \"baz\", \"qux\")"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_InvokeMethod_Fail()
{
engine.Script.testObject = new DynamicTestObject();
TestUtil.AssertException<MissingMemberException>(() => engine.Evaluate("testObject.DynamicMethod()"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_InvokeMethod_FieldOverride()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo.bar.baz.qux", engine.Evaluate("testObject.SomeField(\"foo\", \"bar\", \"baz\", \"qux\")"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_InvokeMethod_FieldOverride_Fail()
{
engine.Script.testObject = new DynamicTestObject();
TestUtil.AssertException<MissingMemberException>(() => engine.Evaluate("testObject.SomeField()"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_InvokeMethod_PropertyOverride()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo:bar:baz:qux", engine.Evaluate("testObject.SomeProperty(\"foo\", \"bar\", \"baz\", \"qux\")"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_InvokeMethod_PropertyOverride_Fail()
{
engine.Script.testObject = new DynamicTestObject();
TestUtil.AssertException<MissingMemberException>(() => engine.Evaluate("testObject.SomeProperty()"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_InvokeMethod_DynamicOverload()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("foo;bar;baz;qux", engine.Evaluate("testObject.SomeMethod(\"foo\", \"bar\", \"baz\", \"qux\")"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_InvokeMethod_NonDynamicOverload()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual(Math.PI, engine.Evaluate("testObject.SomeMethod()"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_InvokeMethod_NonDynamic()
{
engine.Script.testObject = new DynamicTestObject();
Assert.AreEqual("Super Bass-O-Matic '76", engine.Evaluate("testObject.ToString()"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_StaticType_Field()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.IsInstanceOfType(engine.Evaluate("testObject.SomeField"), typeof(HostMethod));
Assert.AreEqual(12345, engine.Evaluate("host.toStaticType(testObject).SomeField"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_StaticType_Property()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.IsInstanceOfType(engine.Evaluate("testObject.SomeProperty"), typeof(HostMethod));
Assert.AreEqual("Bogus", engine.Evaluate("host.toStaticType(testObject).SomeProperty"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_StaticType_Method()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.AreEqual("bar+baz+qux", engine.Evaluate("host.toStaticType(testObject).SomeMethod(\"foo\", \"bar\", \"baz\", \"qux\")"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_Property()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.IsInstanceOfType(engine.Evaluate("host.getProperty(testObject, \"foo\")"), typeof(Undefined));
Assert.AreEqual(123, engine.Evaluate("host.setProperty(testObject, \"foo\", clng(123))"));
Assert.AreEqual(123, engine.Evaluate("testObject.foo"));
Assert.IsTrue((bool)engine.Evaluate("host.removeProperty(testObject, \"foo\")"));
Assert.IsInstanceOfType(engine.Evaluate("host.getProperty(testObject, \"foo\")"), typeof(Undefined));
Assert.IsFalse((bool)engine.Evaluate("host.removeProperty(testObject, \"foo\")"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_Property_Fail()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.IsInstanceOfType(engine.Evaluate("host.getProperty(testObject, \"Zfoo\")"), typeof(Undefined));
TestUtil.AssertException<InvalidOperationException>(() => engine.Evaluate("host.setProperty(testObject, \"Zfoo\", clng(123))"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_Property_Invoke()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
engine.Execute("function secret(x) : secret = len(x) : end function");
Assert.IsInstanceOfType(engine.Evaluate("host.getProperty(testObject, \"foo\")"), typeof(Undefined));
Assert.IsInstanceOfType(engine.Evaluate("host.setProperty(testObject, \"foo\", GetRef(\"secret\"))"), typeof(DynamicObject));
Assert.AreEqual("floccinaucinihilipilification".Length, engine.Evaluate("testObject.foo(\"floccinaucinihilipilification\")"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_Property_Invoke_Nested()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.IsInstanceOfType(engine.Evaluate("host.getProperty(testObject, \"foo\")"), typeof(Undefined));
Assert.IsInstanceOfType(engine.Evaluate("host.setProperty(testObject, \"foo\", testObject)"), typeof(DynamicObject));
Assert.AreEqual("foo,bar,baz,qux", engine.Evaluate("testObject.foo(\"foo\", \"bar\", \"baz\", \"qux\")"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_Element()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.IsInstanceOfType(engine.Evaluate("host.getElement(testObject, clng(1), clng(2), clng(3), \"foo\")"), typeof(Undefined));
Assert.AreEqual("bar", engine.Evaluate("host.setElement(testObject, \"bar\", clng(1), clng(2), clng(3), \"foo\")"));
Assert.AreEqual("bar", engine.Evaluate("host.getElement(testObject, clng(1), clng(2), clng(3), \"foo\")"));
Assert.IsTrue((bool)engine.Evaluate("host.removeElement(testObject, clng(1), clng(2), clng(3), \"foo\")"));
Assert.IsInstanceOfType(engine.Evaluate("host.getElement(testObject, clng(1), clng(2), clng(3), \"foo\")"), typeof(Undefined));
Assert.IsFalse((bool)engine.Evaluate("host.removeElement(testObject, clng(1), clng(2), clng(3), \"foo\")"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_Element_Fail()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
Assert.IsInstanceOfType(engine.Evaluate("host.getElement(testObject, clng(1), clng(2), clng(3), pi)"), typeof(Undefined));
TestUtil.AssertException<InvalidOperationException>(() => engine.Evaluate("host.setElement(testObject, \"bar\", clng(1), clng(2), clng(3), pi)"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_DynamicHostObject_Element_Convert()
{
engine.Script.testObject = new DynamicTestObject();
engine.Script.host = new HostFunctions();
engine.AddHostType("int_t", typeof(int));
engine.AddHostType("string_t", typeof(string));
Assert.AreEqual(98765, engine.Evaluate("host.cast(int_t, testObject)"));
Assert.AreEqual("Booyakasha!", engine.Evaluate("host.cast(string_t, testObject)"));
}
[TestMethod, TestCategory("VBScriptEngine")]
public void VBScriptEngine_HostIndexers()
{
engine.Script.testObject = new TestObject();
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item(clng(123))"));
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item.get(clng(123))"));
engine.Execute("testObject.Item(clng(123)) = pi");
Assert.AreEqual(Math.PI, engine.Evaluate("testObject.Item(clng(123))"));
Assert.AreEqual(Math.E, engine.Evaluate("testObject.Item.set(clng(123), e)"));
Assert.AreEqual(Math.E, engine.Evaluate("testObject.Item.get(clng(123))"));
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item(\"456\")"));
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item.get(\"456\")"));
engine.Execute("testObject.Item(\"456\") = sqr(2)");
Assert.AreEqual(Math.Sqrt(2), engine.Evaluate("testObject.Item(\"456\")"));
Assert.AreEqual(Math.Sqrt(3), engine.Evaluate("testObject.Item.set(\"456\", sqr(3))"));
Assert.AreEqual(Math.Sqrt(3), engine.Evaluate("testObject.Item.get(\"456\")"));
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item(clng(123), \"456\", 789.987, -0.12345)"));
TestUtil.AssertException<KeyNotFoundException>(() => engine.Evaluate("testObject.Item.get(clng(123), \"456\", 789.987, -0.12345)"));
engine.Execute("testObject.Item(clng(123), \"456\", 789.987, -0.12345) = sqr(5)");
Assert.AreEqual(Math.Sqrt(5), engine.Evaluate("testObject.Item(clng(123), \"456\", 789.987, -0.12345)"));
Assert.AreEqual(Math.Sqrt(7), engine.Evaluate("testObject.Item.set(clng(123), \"456\", 789.987, -0.12345, sqr(7))"));
Assert.AreEqual(Math.Sqrt(7), engine.Evaluate("testObject.Item.get(clng(123), \"456\", 789.987, -0.12345)"));
}
// ReSharper restore InconsistentNaming
#endregion

Просмотреть файл

@ -5,8 +5,8 @@ setlocal
:: process arguments
::-----------------------------------------------------------------------------
set testedRevision=16272
set testedVersion=3.21.2
set testedRevision=17179
set testedVersion=3.22.11
:ProcessArgs
@ -128,7 +128,6 @@ cd v8
echo Patching V8 ...
svn patch --ignore-whitespace ..\..\V8Patch.txt >patchV8.log
if errorlevel 1 goto Error2
svn diff -x --ignore-space-change -x --ignore-eol-style >V8Patch.txt
:PatchV8Done
:DownloadGYP
@ -163,6 +162,14 @@ set GYP_MSVS_VERSION=2012
set PYTHONHOME=
set PYTHONPATH=
:CreatePatchFile
echo Creating patch file ...
cd v8
svn diff -x --ignore-space-change -x --ignore-eol-style >V8Patch.txt
if errorlevel 1 goto Error2
cd ..
:CreatePatchFileDone
:Copy32Bit
echo Building 32-bit V8 ...
if exist v8-ia32\ goto Copy32BitDone
@ -174,7 +181,7 @@ if errorlevel 1 goto Error1
:Build32Bit
cd v8-ia32
third_party\python_26\python build\gyp_v8 -Dtarget_arch=ia32 -Dcomponent=shared_library -Dv8_use_snapshot=false >gyp.log
third_party\python_26\python build\gyp_v8 -Dtarget_arch=ia32 -Dcomponent=shared_library -Dv8_use_snapshot=false -Dv8_enable_i18n_support=0 >gyp.log
if errorlevel 1 goto Error2
msbuild /p:Configuration=%mode% /p:Platform=Win32 /t:v8 tools\gyp\v8.sln >build.log
if errorlevel 1 goto Error2
@ -192,7 +199,7 @@ if errorlevel 1 goto Error1
:Build64Bit
cd v8-x64
third_party\python_26\python build\gyp_v8 -Dtarget_arch=x64 -Dcomponent=shared_library -Dv8_use_snapshot=false >gyp.log
third_party\python_26\python build\gyp_v8 -Dtarget_arch=x64 -Dcomponent=shared_library -Dv8_use_snapshot=false -Dv8_enable_i18n_support=0 >gyp.log
if errorlevel 1 goto Error2
msbuild /p:Configuration=%mode% /p:Platform=x64 /t:v8 tools\gyp\v8.sln >build.log
if errorlevel 1 goto Error2
@ -251,11 +258,11 @@ copy build\v8\include\*.* include\ >nul
if errorlevel 1 goto Error
:ImportHeadersDone
:UpdatePatchFile
echo Updating patch file ...
:ImportPatchFile
echo Importing patch file ...
copy build\v8\V8Patch.txt .\ >nul
if errorlevel 1 goto Error
:UpdatePatchFileDone
:ImportPatchFileDone
:ImportDone

Просмотреть файл

@ -1 +1 @@
<# var version = new Version(5, 3, 7, 0); #>
<# var version = new Version(5, 3, 8, 0); #>