// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
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
{
///
/// Provides optional script-callable utility functions.
///
///
/// Use AddHostObject to expose a
/// HostFunctions instance to script code. Each instance can only be exposed in one
/// script engine.
///
public class HostFunctions : IScriptableObject
{
private ScriptEngine engine;
// ReSharper disable EmptyConstructor
///
/// Initializes a new instance.
///
public HostFunctions()
{
// the help file builder (SHFB) insists on an empty constructor here
}
// ReSharper restore EmptyConstructor
#region script-callable interface
// ReSharper disable InconsistentNaming
///
/// Creates an empty host object.
///
/// A new empty host object.
///
/// 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 interface.
///
///
/// The following code creates an empty host object and adds several properties to it.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// var item = host.newObj();
/// item.label = "Widget";
/// item.weight = 123.45;
///
///
public PropertyBag newObj()
{
return new PropertyBag();
}
///
/// Creates a host object of the specified type. This version is invoked if the specified
/// type can be used as a type argument.
///
/// The type of object to create.
/// Optional constructor arguments.
/// A new host object of the specified type.
///
///
/// This function is provided for script languages that do not support external
/// instantiation. It is overloaded with and
/// selected at runtime if can be used as a type argument.
///
///
/// For information about the mapping between host members and script-callable properties
/// and methods, see
/// AddHostObject.
///
///
///
/// The following code imports the class, creates an
/// instance using the
/// Random(Int32)
/// constructor, and calls the method.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// var RandomT = host.type("System.Random");
/// var random = host.newObj(RandomT, 100);
/// var value = random.NextDouble();
///
///
///
public T newObj(params object[] args)
{
return (T)typeof(T).CreateInstance(args);
}
///
/// Creates a host object of the specified type. This version is invoked if the specified
/// type cannot be used as a type argument.
///
/// The type of object to create.
/// Optional constructor arguments.
/// A new host object of the specified type.
///
///
/// This function is provided for script languages that do not support external
/// instantiation. It is overloaded with and selected at runtime if
/// cannot be used as a type argument. Note that this applies
/// to some host types that support instantiation, such as certain COM/ActiveX types.
///
///
/// For information about the mapping between host members and script-callable properties
/// and methods, see
/// AddHostObject.
///
///
public object newObj(object type, params object[] args)
{
return GetUniqueHostType(type, "type").CreateInstance(args);
}
///
/// Performs dynamic instantiation.
///
/// The dynamic host object that provides the instantiation operation to perform.
/// Optional instantiation arguments.
/// The result of the operation, which is usually a new dynamic host object.
///
/// This function is provided for script languages that do not support external
/// instantiation.
///
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");
}
///
/// Creates a host array with the specified element type.
///
/// The element type of the array to create.
/// One or more integers representing the array dimension lengths.
/// A new host array with the specified element type.
///
/// For information about the mapping between host members and script-callable properties
/// and methods, see
/// AddHostObject.
///
///
/// The following code creates a 5x3 host array of strings.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// var StringT = host.type("System.String");
/// var array = host.newArr(StringT, 5, 3);
///
///
///
///
public object newArr(params int[] lengths)
{
return Array.CreateInstance(typeof(T), lengths);
}
///
/// Creates a host array with as the element type.
///
/// One or more integers representing the array dimension lengths.
/// A new host array with as the element type.
///
/// For information about the mapping between host members and script-callable properties
/// and methods, see
/// AddHostObject.
///
///
public object newArr(params int[] lengths)
{
return newArr(lengths);
}
///
/// Creates a host variable of the specified type.
///
/// The type of variable to create.
/// An optional initial value for the variable.
/// A new host variable of the specified type.
///
///
/// A host variable is a strongly typed object that holds a value of the specified type.
/// Host variables are useful for passing method arguments by reference. In addition to
/// being generally interchangeable with their stored values, host variables support the
/// following properties:
///
///
///
///
/// Property
/// Access
/// Description
///
///
/// value
/// read-write
/// The current value of the host variable.
///
///
/// out
/// read-only
/// A reference to the host variable that can be passed as an out argument.
///
///
/// ref
/// read-only
/// A reference to the host variable that can be passed as a ref argument.
///
///
///
///
///
/// The following code demonstrates using a host variable to invoke a method with an
/// out parameter.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // import a dictionary type
/// var StringT = host.type("System.String");
/// var StringDictT = host.type("System.Collections.Generic.Dictionary", StringT, StringT);
/// // create and populate a dictionary
/// var dict = host.newObj(StringDictT);
/// dict.Add("foo", "bar");
/// dict.Add("baz", "qux");
/// // look up a dictionary entry
/// var result = host.newVar(StringT);
/// var found = dict.TryGetValue("baz", result.out);
///
///
///
public object newVar(T initValue = default(T))
{
return new HostVariable(initValue);
}
///
/// Creates a delegate that invokes a script function.
///
/// The type of delegate to create.
/// The script function for which to create a delegate.
/// A new delegate that invokes the specified script function.
///
/// If the delegate signature includes parameters passed by reference, the corresponding
/// arguments to the script function will be host variables.
/// The script function can set the value of an output argument by assigning the
/// corresponding host variable's value property.
///
///
/// The following code demonstrates delegating a callback to a script function.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // create and populate an array of integers
/// var EnumerableT = host.type("System.Linq.Enumerable", "System.Core");
/// var array = EnumerableT.Range(1, 5).ToArray();
/// // import the callback type required to call Array.ForEach
/// var Int32T = host.type("System.Int32");
/// var CallbackT = host.type("System.Action", Int32T);
/// // use Array.ForEach to calculate a sum
/// var sum = 0;
/// var ArrayT = host.type("System.Array");
/// ArrayT.ForEach(array, host.del(CallbackT, function (value) { sum += value; }));
///
///
///
///
public T del(object scriptFunc)
{
return DelegateFactory.CreateDelegate(GetEngine(), scriptFunc);
}
///
/// Creates a delegate that invokes a script function and returns no value.
///
/// The number of arguments to pass to the script function.
/// The script function for which to create a delegate.
/// A new delegate that invokes the specified script function and returns no value.
///
/// This function creates a delegate that accepts arguments and
/// returns no value. The type of all parameters is . Such a
/// delegate is often useful in strongly typed contexts because of
/// contravariance.
///
///
/// The following code demonstrates delegating a callback to a script function.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // create and populate an array of strings
/// var StringT = host.type("System.String");
/// var array = host.newArr(StringT, 3);
/// array.SetValue("first", 0);
/// array.SetValue("second", 1);
/// array.SetValue("third", 2);
/// // use Array.ForEach to generate console output
/// var ArrayT = host.type("System.Array");
/// var ConsoleT = host.type("System.Console");
/// ArrayT.ForEach(array, host.proc(1, function (value) { ConsoleT.WriteLine(value); }));
///
///
///
///
public object proc(int argCount, object scriptFunc)
{
return DelegateFactory.CreateProc(GetEngine(), scriptFunc, argCount);
}
///
/// Creates a delegate that invokes a script function and returns a value of the specified type.
///
/// The return value type.
/// The number of arguments to pass to the script function.
/// The script function for which to create a delegate.
/// A new delegate that invokes the specified script function and returns a value of the specified type.
///
/// This function creates a delegate that accepts arguments and
/// returns a value of the specified type. The type of all parameters is
/// . Such a delegate is often useful in strongly typed contexts
/// because of
/// contravariance.
///
///
/// The following code demonstrates delegating a callback to a script function.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // create and populate an array of strings
/// var StringT = host.type("System.String");
/// var array = host.newArr(StringT, 3);
/// array.SetValue("first", 0);
/// array.SetValue("second", 1);
/// array.SetValue("third", 2);
/// // import LINQ extensions
/// var EnumerableT = host.type("System.Linq.Enumerable", "System.Core");
/// // use LINQ to create an array of modified strings
/// var selector = host.func(StringT, 1, function (value) { return value.toUpperCase(); });
/// array = array.Select(selector).ToArray();
///
///
///
///
///
public object func(int argCount, object scriptFunc)
{
return DelegateFactory.CreateFunc(GetEngine(), scriptFunc, argCount);
}
///
/// Creates a delegate that invokes a script function and returns its result value.
///
/// The number of arguments to pass to the script function.
/// The script function for which to create a delegate.
/// A new delegate that invokes the specified script function and returns its result value.
///
///
/// This function creates a delegate that accepts arguments and
/// returns the result of invoking . The type of all
/// parameters and the return value is . Such a delegate is
/// often useful in strongly typed contexts because of
/// contravariance.
///
///
/// For information about the types of result values that script code can return, see
/// .
///
///
///
public object func(int argCount, object scriptFunc)
{
return func(argCount, scriptFunc);
}
///
/// Gets the for the specified host type. This version is invoked
/// if the specified object can be used as a type argument.
///
/// The host type for which to get the .
/// The for the specified host type.
///
///
/// This function is similar to C#'s
/// typeof
/// operator. It is overloaded with and selected at runtime if
/// can be used as a type argument.
///
///
/// This function throws an exception if the script engine's
/// property is set to false.
///
///
///
/// The following code retrieves the assembly-qualified name of a host type.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// var StringT = host.type("System.String");
/// var name = host.typeOf(StringT).AssemblyQualifiedName;
///
///
///
public Type typeOf()
{
GetEngine().CheckReflection();
return typeof(T);
}
///
/// Gets the for the specified host type. This version is invoked
/// if the specified object cannot be used as a type argument.
///
/// The host type for which to get the .
/// The for the specified host type.
///
///
/// This function is similar to C#'s
/// typeof
/// operator. It is overloaded with and selected at runtime if
/// cannot be used as a type argument. Note that this applies to
/// some host types; examples are static types and overloaded generic type groups.
///
///
/// This function throws an exception if the script engine's
/// property is set to false.
///
///
///
/// The following code retrieves the assembly-qualified name of a host type.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// var ConsoleT = host.type("System.Console");
/// var name = host.typeOf(ConsoleT).AssemblyQualifiedName;
///
///
///
public Type typeOf(object value)
{
GetEngine().CheckReflection();
return GetUniqueHostType(value, "value");
}
///
/// Determines whether an object is compatible with the specified host type.
///
/// The host type with which to test for compatibility.
/// The object to test for compatibility with the specified host type.
/// True if is compatible with the specified type, false otherwise.
///
/// This function is similar to C#'s
/// is
/// operator.
///
///
/// The following code defines a function that determines whether an object implements
/// .
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// function isComparable(value)
/// {
/// var IComparableT = host.type("System.IComparable");
/// return host.isType(IComparableT, value);
/// }
///
///
///
public bool isType(object value)
{
return value is T;
}
///
/// Casts an object to the specified host type, returning null if the cast fails.
///
/// The host type to which to cast .
/// The object to cast to the specified host type.
/// The result of the cast if successful, null otherwise.
///
/// This function is similar to C#'s
/// as
/// operator.
///
///
/// The following code defines a function that disposes an object if it implements
/// .
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// function dispose(value)
/// {
/// var IDisposableT = host.type("System.IDisposable");
/// var disposable = host.asType(IDisposableT, value);
/// if (disposable) {
/// disposable.Dispose();
/// }
/// }
///
///
///
public object asType(object value) where T : class
{
return HostItem.Wrap(GetEngine(), value as T, typeof(T));
}
///
/// Casts an object to the specified host type.
///
/// The host type to which to cast .
/// The object to cast to the specified host type.
/// The result of the cast.
///
/// If the cast fails, this function throws an exception.
///
///
/// The following code casts a floating-point value to a 32-bit integer.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// var Int32T = host.type("System.Int32");
/// var intValue = host.cast(Int32T, 12.5);
///
///
///
public object cast(object value)
{
return HostItem.Wrap(GetEngine(), value.DynamicCast(), typeof(T));
}
///
/// Determines whether an object is a host type. This version is invoked if the specified
/// object cannot be used as a type argument.
///
/// The object to test.
/// True if is a host type, false otherwise.
///
/// This function is overloaded with and selected at runtime if
/// cannot be used as a type argument. Note that this applies to
/// some host types; examples are static types and overloaded generic type groups.
///
public bool isTypeObj(object value)
{
return value is HostType;
}
// ReSharper disable UnusedTypeParameter
///
/// Determines whether an object is a host type. This version is invoked if the specified
/// object can be used as a type argument.
///
/// The host type (ignored).
/// True.
///
/// This function is overloaded with and selected at
/// runtime if can be used as a type argument. Because type
/// arguments are always host types, this method ignores its type argument and always
/// returns true.
///
public bool isTypeObj()
{
return true;
}
// ReSharper restore UnusedTypeParameter
///
/// Determines whether the specified value is null.
///
/// The value to test.
/// True if is null, false otherwise.
///
/// Use this function to test field, property, and method return values when null
/// result wrapping is in effect (see
/// and
/// ).
///
///
///
public bool isNull(object value)
{
return value == null;
}
///
/// Creates a strongly typed flag set.
///
/// The type of flag set to create.
/// The flags to include in the flag set.
/// A strongly typed flag set containing the specified flags.
///
/// This function throws an exception if is not a flag set type.
///
///
/// The following code demonstrates using a strongly typed flag set.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // import URI types
/// var UriT = host.type("System.Uri", "System");
/// var UriFormatT = host.type("System.UriFormat", "System");
/// var UriComponentsT = host.type("System.UriComponents", "System");
/// // create a URI
/// var uri = host.newObj(UriT, "http://www.example.com:8080/path/to/file/sample.htm?x=1&y=2");
/// // extract URI components
/// var components = host.flags(UriComponentsT.Scheme, UriComponentsT.Host, UriComponentsT.Path);
/// var result = uri.GetComponents(components, UriFormatT.Unescaped);
///
///
///
public T flags(params T[] args)
{
var type = typeof(T);
if (!type.IsFlagsEnum())
{
throw new InvalidOperationException(MiscHelpers.FormatInvariant("{0} is not a flag set type", type.GetFullFriendlyName()));
}
try
{
return args.Aggregate(0UL, (flags, arg) => flags | Convert.ToUInt64(arg, CultureInfo.InvariantCulture)).DynamicCast();
}
catch (OverflowException)
{
return args.Aggregate(0L, (flags, arg) => flags | Convert.ToInt64(arg, CultureInfo.InvariantCulture)).DynamicCast();
}
}
///
/// Converts the specified value to a strongly typed instance.
///
/// The value to convert.
/// An object that can be passed to a parameter of type .
///
/// This function converts to and
/// packages the result to retain its numeric type across the host-script boundary. It may
/// be useful for passing arguments to parameters if the script
/// engine does not support that type natively.
///
///
/// The following code adds an element of type to a strongly
/// typed list.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // import types
/// var ElementT = host.type("System.SByte");
/// var ListT = host.type("System.Collections.Generic.List", ElementT);
/// // create a list
/// var list = host.newObj(ListT);
/// // add a list element
/// list.Add(host.toSByte(42));
///
///
///
public object toSByte(IConvertible value)
{
return HostObject.Wrap(Convert.ToSByte(value));
}
///
/// Converts the specified value to a strongly typed instance.
///
/// The value to convert.
/// An object that can be passed to a parameter of type .
///
/// This function converts to and
/// packages the result to retain its numeric type across the host-script boundary. It may
/// be useful for passing arguments to parameters if the script
/// engine does not support that type natively.
///
///
/// The following code adds an element of type to a strongly
/// typed list.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // import types
/// var ElementT = host.type("System.Byte");
/// var ListT = host.type("System.Collections.Generic.List", ElementT);
/// // create a list
/// var list = host.newObj(ListT);
/// // add a list element
/// list.Add(host.toByte(42));
///
///
///
public object toByte(IConvertible value)
{
return HostObject.Wrap(Convert.ToByte(value));
}
///
/// Converts the specified value to a strongly typed instance.
///
/// The value to convert.
/// An object that can be passed to a parameter of type .
///
/// This function converts to and
/// packages the result to retain its numeric type across the host-script boundary. It may
/// be useful for passing arguments to parameters if the script
/// engine does not support that type natively.
///
///
/// The following code adds an element of type to a strongly
/// typed list.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // import types
/// var ElementT = host.type("System.Int16");
/// var ListT = host.type("System.Collections.Generic.List", ElementT);
/// // create a list
/// var list = host.newObj(ListT);
/// // add a list element
/// list.Add(host.toInt16(42));
///
///
///
public object toInt16(IConvertible value)
{
return HostObject.Wrap(Convert.ToInt16(value));
}
///
/// Converts the specified value to a strongly typed instance.
///
/// The value to convert.
/// An object that can be passed to a parameter of type .
///
/// This function converts to and
/// packages the result to retain its numeric type across the host-script boundary. It may
/// be useful for passing arguments to parameters if the script
/// engine does not support that type natively.
///
///
/// The following code adds an element of type to a strongly
/// typed list.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // import types
/// var ElementT = host.type("System.UInt16");
/// var ListT = host.type("System.Collections.Generic.List", ElementT);
/// // create a list
/// var list = host.newObj(ListT);
/// // add a list element
/// list.Add(host.toUInt16(42));
///
///
///
public object toUInt16(IConvertible value)
{
return HostObject.Wrap(Convert.ToUInt16(value));
}
///
/// Converts the specified value to a strongly typed instance.
///
/// The value to convert.
/// An object that can be passed to a parameter of type .
///
/// This function converts to and
/// packages the result to retain its numeric type across the host-script boundary. It may
/// be useful for passing arguments to parameters if the script
/// engine does not support that type natively.
///
///
/// The following code adds an element of type to a strongly
/// typed list.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // import types
/// var ElementT = host.type("System.Char");
/// var ListT = host.type("System.Collections.Generic.List", ElementT);
/// // create a list
/// var list = host.newObj(ListT);
/// // add a list element
/// list.Add(host.toChar(42));
///
///
///
public object toChar(IConvertible value)
{
return HostObject.Wrap(Convert.ToChar(value));
}
///
/// Converts the specified value to a strongly typed instance.
///
/// The value to convert.
/// An object that can be passed to a parameter of type .
///
/// This function converts to and
/// packages the result to retain its numeric type across the host-script boundary. It may
/// be useful for passing arguments to parameters if the script
/// engine does not support that type natively.
///
///
/// The following code adds an element of type to a strongly
/// typed list.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // import types
/// var ElementT = host.type("System.Int32");
/// var ListT = host.type("System.Collections.Generic.List", ElementT);
/// // create a list
/// var list = host.newObj(ListT);
/// // add a list element
/// list.Add(host.toInt32(42));
///
///
///
public object toInt32(IConvertible value)
{
return HostObject.Wrap(Convert.ToInt32(value));
}
///
/// Converts the specified value to a strongly typed instance.
///
/// The value to convert.
/// An object that can be passed to a parameter of type .
///
/// This function converts to and
/// packages the result to retain its numeric type across the host-script boundary. It may
/// be useful for passing arguments to parameters if the script
/// engine does not support that type natively.
///
///
/// The following code adds an element of type to a strongly
/// typed list.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // import types
/// var ElementT = host.type("System.UInt32");
/// var ListT = host.type("System.Collections.Generic.List", ElementT);
/// // create a list
/// var list = host.newObj(ListT);
/// // add a list element
/// list.Add(host.toUInt32(42));
///
///
///
public object toUInt32(IConvertible value)
{
return HostObject.Wrap(Convert.ToUInt32(value));
}
///
/// Converts the specified value to a strongly typed instance.
///
/// The value to convert.
/// An object that can be passed to a parameter of type .
///
/// This function converts to and
/// packages the result to retain its numeric type across the host-script boundary. It may
/// be useful for passing arguments to parameters if the script
/// engine does not support that type natively.
///
///
/// The following code adds an element of type to a strongly
/// typed list.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // import types
/// var ElementT = host.type("System.Int64");
/// var ListT = host.type("System.Collections.Generic.List", ElementT);
/// // create a list
/// var list = host.newObj(ListT);
/// // add a list element
/// list.Add(host.toInt64(42));
///
///
///
public object toInt64(IConvertible value)
{
return HostObject.Wrap(Convert.ToInt64(value));
}
///
/// Converts the specified value to a strongly typed instance.
///
/// The value to convert.
/// An object that can be passed to a parameter of type .
///
/// This function converts to and
/// packages the result to retain its numeric type across the host-script boundary. It may
/// be useful for passing arguments to parameters if the script
/// engine does not support that type natively.
///
///
/// The following code adds an element of type to a strongly
/// typed list.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // import types
/// var ElementT = host.type("System.UInt64");
/// var ListT = host.type("System.Collections.Generic.List", ElementT);
/// // create a list
/// var list = host.newObj(ListT);
/// // add a list element
/// list.Add(host.toUInt64(42));
///
///
///
public object toUInt64(IConvertible value)
{
return HostObject.Wrap(Convert.ToUInt64(value));
}
///
/// Converts the specified value to a strongly typed instance.
///
/// The value to convert.
/// An object that can be passed to a parameter of type .
///
/// This function converts to and
/// packages the result to retain its numeric type across the host-script boundary. It may
/// be useful for passing arguments to parameters if the script
/// engine does not support that type natively.
///
///
/// The following code adds an element of type to a strongly
/// typed list.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // import types
/// var ElementT = host.type("System.Single");
/// var ListT = host.type("System.Collections.Generic.List", ElementT);
/// // create a list
/// var list = host.newObj(ListT);
/// // add a list element
/// list.Add(host.toSingle(42));
///
///
///
public object toSingle(IConvertible value)
{
return HostObject.Wrap(Convert.ToSingle(value));
}
///
/// Converts the specified value to a strongly typed instance.
///
/// The value to convert.
/// An object that can be passed to a parameter of type .
///
/// This function converts to and
/// packages the result to retain its numeric type across the host-script boundary. It may
/// be useful for passing arguments to parameters if the script
/// engine does not support that type natively.
///
///
/// The following code adds an element of type to a strongly
/// typed list.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // import types
/// var ElementT = host.type("System.Double");
/// var ListT = host.type("System.Collections.Generic.List", ElementT);
/// // create a list
/// var list = host.newObj(ListT);
/// // add a list element
/// list.Add(host.toDouble(42));
///
///
///
public object toDouble(IConvertible value)
{
return HostObject.Wrap(Convert.ToDouble(value));
}
///
/// Converts the specified value to a strongly typed instance.
///
/// The value to convert.
/// An object that can be passed to a parameter of type .
///
/// This function converts to and
/// packages the result to retain its numeric type across the host-script boundary. It may
/// be useful for passing arguments to parameters if the script
/// engine does not support that type natively.
///
///
/// The following code adds an element of type to a strongly
/// typed list.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // import types
/// var ElementT = host.type("System.Decimal");
/// var ListT = host.type("System.Collections.Generic.List", ElementT);
/// // create a list
/// var list = host.newObj(ListT);
/// // add a list element
/// list.Add(host.toDecimal(42));
///
///
///
public object toDecimal(IConvertible value)
{
return HostObject.Wrap(Convert.ToDecimal(value));
}
///
/// Gets the value of a property in a dynamic host object that implements .
///
/// The dynamic host object that contains the property to get.
/// The name of the property to get.
/// The value of the specified property.
///
/// This function is provided for script languages that do not support dynamic properties.
///
public object getProperty(IPropertyBag target, string name)
{
MiscHelpers.VerifyNonNullArgument(target, "target");
object result;
if (target.TryGetValue(name, out result))
{
return result;
}
return Nonexistent.Value;
}
///
/// Sets a property value in a dynamic host object that implements .
///
/// The dynamic host object that contains the property to set.
/// The name of the property to set.
/// The new value of the specified property.
/// The result of the operation, which is usually the value assigned to the specified property.
///
/// This function is provided for script languages that do not support dynamic properties.
///
public object setProperty(IPropertyBag target, string name, object value)
{
MiscHelpers.VerifyNonNullArgument(target, "target");
return target[name] = value;
}
///
/// Removes a property from a dynamic host object that implements .
///
/// The dynamic host object that contains the property to remove.
/// The name of the property to remove.
/// True if the property was found and removed, false otherwise.
///
/// This function is provided for script languages that do not support dynamic properties.
///
public bool removeProperty(IPropertyBag target, string name)
{
MiscHelpers.VerifyNonNullArgument(target, "target");
return target.Remove(name);
}
///
/// Gets the value of a property in a dynamic host object that implements .
///
/// The dynamic host object that contains the property to get.
/// The name of the property to get.
/// The value of the specified property.
///
/// This function is provided for script languages that do not support dynamic properties.
///
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;
}
///
/// Sets a property value in a dynamic host object that implements .
///
/// The dynamic host object that contains the property to set.
/// The name of the property to set.
/// The new value of the specified property.
/// The result of the operation, which is usually the value assigned to the specified property.
///
/// This function is provided for script languages that do not support dynamic properties.
///
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");
}
///
/// Removes a property from a dynamic host object that implements .
///
/// The dynamic host object that contains the property to remove.
/// The name of the property to remove.
/// True if the property was found and removed, false otherwise.
///
/// This function is provided for script languages that do not support dynamic properties.
///
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");
}
///
/// Gets the value of an element in a dynamic host object that implements .
///
/// The dynamic host object that contains the element to get.
/// One or more indices that identify the element to get.
/// The value of the specified element.
///
/// This function is provided for script languages that do not support general indexing.
///
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;
}
///
/// Sets an element value in a dynamic host object that implements .
///
/// The dynamic host object that contains the element to set.
/// The new value of the element.
/// One or more indices that identify the element to set.
/// The result of the operation, which is usually the value assigned to the specified element.
///
/// This function is provided for script languages that do not support general indexing.
///
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");
}
///
/// Removes an element from a dynamic host object that implements .
///
/// The dynamic host object that contains the element to remove.
/// One or more indices that identify the element to remove.
/// True if the element was found and removed, false otherwise.
///
/// This function is provided for script languages that do not support general indexing.
///
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");
}
///
/// Casts a dynamic host object to its static type.
///
/// The object to cast to its static type.
/// The specified object in its static type form, stripped of its dynamic members.
///
/// A dynamic host object that implements 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.
///
public object toStaticType(IDynamicMetaObjectProvider value)
{
return HostItem.Wrap(GetEngine(), value, HostItemFlags.HideDynamicMembers);
}
///
/// Allows script code to handle host exceptions.
///
/// A script function that invokes one or more host methods or properties.
/// A script function to invoke if throws an exception.
/// An optional script function that performs cleanup for the operation.
/// True if completed successfully, false if it threw an exception that was handled by .
///
/// This function uses a try-catch-finally statement to invoke
/// . If an exception is thrown, it is caught and passed to
/// for analysis. If returns
/// false, the exception is rethrown. Regardless of the outcome,
/// , if specified, is invoked as a final step before the
/// function exits.
///
///
/// The following code demonstrates handling host exceptions in script code.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// // import types
/// var ConsoleT = host.type("System.Console");
/// var WebClientT = host.type("System.Net.WebClient", "System");
/// // create a web client
/// var webClient = host.newObj(WebClientT);
/// host.tryCatch(
/// function () {
/// // download web document
/// ConsoleT.WriteLine(webClient.DownloadString("http://cnn.com"));
/// },
/// function (exception) {
/// // dump exception
/// ConsoleT.WriteLine("*** ERROR: " + exception.GetBaseException().ToString());
/// return true;
/// },
/// function () {
/// // clean up
/// ConsoleT.WriteLine("*** CLEANING UP ***");
/// webClient.Dispose();
/// }
/// );
///
///
///
///
public bool tryCatch(object tryFunc, object catchFunc, object finallyFunc = null)
{
MiscHelpers.VerifyNonNullArgument(tryFunc, "tryFunc");
MiscHelpers.VerifyNonNullArgument(catchFunc, "catchFunc");
try
{
((dynamic)tryFunc)();
return true;
}
catch (Exception exception)
{
if (!((dynamic)catchFunc)(exception))
{
throw;
}
return false;
}
finally
{
if (finallyFunc != null)
{
((dynamic)finallyFunc)();
}
}
}
// ReSharper restore InconsistentNaming
#endregion
internal ScriptEngine GetEngine()
{
var activeEngine = ScriptEngine.Current ?? engine;
if (activeEngine == null)
{
throw new InvalidOperationException("Operation requires a script engine");
}
return activeEngine;
}
internal static Type GetUniqueHostType(object type, string paramName)
{
var hostType = type as HostType;
if (hostType == null)
{
throw new ArgumentException("Invalid host type", paramName);
}
if (hostType.Types.Length > 1)
{
throw new ArgumentException(MiscHelpers.FormatInvariant("'{0}' does not identify a unique host type", hostType.Types[0].GetLocator()), paramName);
}
return hostType.Types[0];
}
#region IScriptableObject implementation
// ReSharper disable ParameterHidesMember
[SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "This member is not expected to be re-implemented in derived classes.")]
void IScriptableObject.OnExposedToScriptCode(ScriptEngine engine)
{
MiscHelpers.VerifyNonNullArgument(engine, "engine");
this.engine = engine;
}
// ReSharper restore ParameterHidesMember
#endregion
}
///
/// Provides optional script-callable utility functions. This extended version allows script
/// code to import host types.
///
public class ExtendedHostFunctions : HostFunctions
{
// ReSharper disable EmptyConstructor
///
/// Initializes a new instance.
///
public ExtendedHostFunctions()
{
// the help file builder (SHFB) insists on an empty constructor here
}
// ReSharper restore EmptyConstructor
#region script-callable interface
// ReSharper disable InconsistentNaming
///
/// Imports a host type by name.
///
/// The fully qualified name of the host type to import.
/// Optional generic type arguments.
/// The imported host type.
///
///
/// Host types are imported in the form of objects whose properties and methods are bound
/// to the host type's static members and nested types. If refers
/// to a generic type, the corresponding object will be invocable with type arguments to
/// yield a specific type.
///
///
/// For more information about the mapping between host members and script-callable
/// properties and methods, see
/// AddHostObject.
///
///
///
/// The following code imports the
/// Dictionary
/// generic type and uses it to create a string dictionary.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// var DictT = host.type("System.Collections.Generic.Dictionary");
/// var StringT = host.type("System.String");
/// var dict = host.newObj(DictT(StringT, StringT));
///
/// Another way to create a string dictionary is to import the specific type directly.
///
/// var StringT = host.type("System.String");
/// var StringDictT = host.type("System.Collections.Generic.Dictionary", StringT, StringT);
/// var dict = host.newObj(StringDictT);
///
///
public object type(string name, params object[] hostTypeArgs)
{
return TypeHelpers.ImportType(name, null, false, hostTypeArgs);
}
///
/// Imports a host type by name from the specified assembly.
///
/// The fully qualified name of the host type to import.
/// The name of the assembly that contains the host type to import.
/// Optional generic type arguments.
/// The imported host type.
///
///
/// Host types are imported in the form of objects whose properties and methods are bound
/// to the host type's static members and nested types. If refers
/// to a generic type, the corresponding object will be invocable with type arguments to
/// yield a specific type.
///
///
/// For more information about the mapping between host members and script-callable
/// properties and methods, see
/// AddHostObject.
///
///
///
/// The following code imports and uses it to create
/// an array of strings.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// var EnumerableT = host.type("System.Linq.Enumerable", "System.Core");
/// var Int32T = host.type("System.Int32");
/// var StringT = host.type("System.String");
/// var SelectorT = host.type("System.Func", Int32T, StringT);
/// var selector = host.del(SelectorT, function (num) { return StringT.Format("The number is {0}.", num); });
/// var array = EnumerableT.Range(0, 5).Select(selector).ToArray();
///
///
///
public object type(string name, string assemblyName, params object[] hostTypeArgs)
{
return TypeHelpers.ImportType(name, assemblyName, true, hostTypeArgs);
}
///
/// Imports the host type for the specified .
///
/// The that specifies the host type to import.
/// The imported host type.
///
///
/// Host types are imported in the form of objects whose properties and methods are bound
/// to the host type's static members and nested types. If refers
/// to a generic type, the corresponding object will be invocable with type arguments to
/// yield a specific type.
///
///
/// For more information about the mapping between host members and script-callable
/// properties and methods, see
/// AddHostObject.
///
///
public object type(Type type)
{
return HostType.Wrap(type);
}
///
/// Imports the host array type for the specified element type.
///
/// The element type for the host array type to import.
/// The number of dimensions for the host array type to import.
/// The imported host array type.
public object arrType(int rank = 1)
{
return HostType.Wrap(typeof(T).MakeArrayType(rank));
}
///
/// Imports types from one or more host assemblies.
///
/// The names of the assemblies that contain the types to import.
/// The imported host type collection.
///
/// Host type collections provide convenient scriptable access to all the types defined in one
/// or more host assemblies. They are hierarchical collections where leaf nodes represent types
/// and parent nodes represent namespaces. For example, if an assembly contains a type named
/// "Acme.Gadgets.Button", the corresponding collection will have a property named "Acme" whose
/// value is an object with a property named "Gadgets" whose value is an object with a property
/// named "Button" whose value represents the Acme.Gadgets.Button host type.
///
///
/// The following code imports types from several core assemblies and uses
/// to create an array of integers.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// var clr = host.lib("mscorlib", "System", "System.Core");
/// var array = clr.System.Linq.Enumerable.Range(0, 5).ToArray();
///
///
public HostTypeCollection lib(params string[] assemblyNames)
{
return lib(null, assemblyNames);
}
///
/// Imports types from one or more host assemblies and merges them with an existing host type collection.
///
/// The host type collection with which to merge types from the specified assemblies.
/// The names of the assemblies that contain the types to import.
/// A host type collection: if it is not null, a new host type collection otherwise.
///
/// Host type collections provide convenient scriptable access to all the types defined in one
/// or more host assemblies. They are hierarchical collections where leaf nodes represent types
/// and parent nodes represent namespaces. For example, if an assembly contains a type named
/// "Acme.Gadgets.Button", the corresponding collection will have a property named "Acme" whose
/// value is an object with a property named "Gadgets" whose value is an object with a property
/// named "Button" whose value represents the Acme.Gadgets.Button host type.
///
///
/// The following code imports types from several core assemblies and uses
/// to create an array of integers.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// var clr = host.lib("mscorlib");
/// host.lib(clr, "System");
/// host.lib(clr, "System.Core");
/// var array = clr.System.Linq.Enumerable.Range(0, 5).ToArray();
///
///
public HostTypeCollection lib(HostTypeCollection collection, params string[] assemblyNames)
{
var target = collection ?? new HostTypeCollection();
Array.ForEach(assemblyNames, target.AddAssembly);
return target;
}
///
/// Imports a COM/ActiveX type.
///
/// The programmatic identifier (ProgID) of the registered class to import.
/// An optional name that specifies the server from which to import the type.
/// The imported COM/ActiveX type.
///
/// The argument can be a class identifier (CLSID) in standard
/// GUID format with braces (e.g., "{0D43FE01-F093-11CF-8940-00A0C9054228}").
///
///
/// The following code imports the
/// Scripting.Dictionary
/// class and uses it to create and populate an instance.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// var DictT = host.comType('Scripting.Dictionary');
/// var dict = host.newObj(DictT);
/// dict.Add('foo', 123);
/// dict.Add('bar', 456.789);
/// dict.Add('baz', 'abc');
///
///
public object comType(string progID, string serverName = null)
{
return HostType.Wrap(MiscHelpers.GetCOMType(progID, serverName));
}
///
/// Creates a COM/ActiveX object of the specified type.
///
/// The programmatic identifier (ProgID) of the registered class to instantiate.
/// An optional name that specifies the server on which to create the object.
/// A new COM/ActiveX object of the specified type.
///
/// The argument can be a class identifier (CLSID) in standard
/// GUID format with braces (e.g., "{0D43FE01-F093-11CF-8940-00A0C9054228}").
///
///
/// The following code creates a
/// Scripting.FileSystemObject
/// instance and uses it to list the drives on the local machine.
/// It assumes that an instance of is exposed under
/// the name "host"
/// (see AddHostObject).
///
/// var fso = host.newComObj('Scripting.FileSystemObject');
/// var ConsoleT = host.type('System.Console');
/// for (en = fso.Drives.GetEnumerator(); en.MoveNext();) {
/// ConsoleT.WriteLine(en.Current.Path);
/// }
///
///
public object newComObj(string progID, string serverName = null)
{
return MiscHelpers.CreateCOMObject(progID, serverName);
}
// ReSharper restore InconsistentNaming
#endregion
}
}