/// <summary> /// Gets a "meta" operation on this userdata. If a descriptor does not support this functionality, /// it should return "null" (not a nil). /// See <see cref="IUserDataDescriptor.MetaIndex" /> for further details. /// /// If a method exists marked with <see cref="MoonSharpUserDataMetamethodAttribute" /> for the specific /// metamethod requested, that method is returned. /// /// If the above fails, the following dispatching occur: /// /// __add, __sub, __mul, __div, __mod and __unm are dispatched to C# operator overloads (if they exist) /// __eq is dispatched to System.Object.Equals. /// __lt and __le are dispatched IComparable.Compare, if the type implements IComparable or IComparable{object} /// __len is dispatched to Length and Count properties, if those exist. /// __iterator is handled if the object implements IEnumerable or IEnumerator. /// __tonumber is dispatched to implicit or explicit conversion operators to standard numeric types. /// __tobool is dispatched to an implicit or explicit conversion operator to bool. If that fails, operator true is used. /// /// <param name="script">The script originating the request</param> /// <param name="obj">The object (null if a static request is done)</param> /// <param name="metaname">The name of the metamember.</param> /// </summary> /// <returns></returns> public virtual DynValue MetaIndex(Script script, object obj, string metaname) { IMemberDescriptor desc = m_MetaMembers.GetOrDefault(metaname); if (desc != null) { return(desc.GetValue(script, obj)); } switch (metaname) { case "__add": return(DispatchMetaOnMethod(script, obj, "op_Addition")); case "__sub": return(DispatchMetaOnMethod(script, obj, "op_Subtraction")); case "__mul": return(DispatchMetaOnMethod(script, obj, "op_Multiply")); case "__div": return(DispatchMetaOnMethod(script, obj, "op_Division")); case "__mod": return(DispatchMetaOnMethod(script, obj, "op_Modulus")); case "__unm": return(DispatchMetaOnMethod(script, obj, "op_UnaryNegation")); case "__eq": return(MultiDispatchEqual(script, obj)); case "__lt": return(MultiDispatchLessThan(script, obj)); case "__le": return(MultiDispatchLessThanOrEqual(script, obj)); case "__len": return(TryDispatchLength(script, obj)); case "__tonumber": return(TryDispatchToNumber(script, obj)); case "__tobool": return(TryDispatchToBool(script, obj)); case "__iterator": return(ClrToScriptConversions.EnumerationToDynValue(script, obj)); default: return(null); } }
private DynValue DispatchMetaOnMethod(Script script, object obj, string methodName) { IMemberDescriptor desc = m_Members.GetOrDefault(methodName); if (desc != null) { return(desc.GetValue(script, obj)); } else { return(null); } }
/// <summary> /// Executes the specified indexer method. /// </summary> /// <param name="ecToken">The execution control token used to cancel scripts if needed.</param> /// <param name="mdesc">The method descriptor</param> /// <param name="script">The script.</param> /// <param name="obj">The object.</param> /// <param name="index">The indexer parameter</param> /// <param name="value">The dynvalue to set on a setter, or null.</param> /// <exception cref="System.NotImplementedException"></exception> protected virtual DynValue ExecuteIndexer(ExecutionControlToken ecToken, IMemberDescriptor mdesc, Script script, object obj, DynValue index, DynValue value) { IList <DynValue> values; if (index.Type == DataType.Tuple) { if (value == null) { values = index.Tuple; } else { values = new List <DynValue>(index.Tuple); values.Add(value); } } else { if (value == null) { values = new[] { index }; } else { values = new[] { index, value }; } } var args = new CallbackArguments(values, false); var execCtx = script.CreateDynamicExecutionContext(ecToken); var v = mdesc.GetValue(script, obj); if (v.Type != DataType.ClrFunction) { throw new ScriptRuntimeException("a clr callback was expected in member {0}, while a {1} was found", mdesc.Name, v.Type); } return(v.Callback.ClrCallback(execCtx, args)); }
/// <summary> /// Gets the getter of the member as a DynValue containing a callback /// </summary> /// <param name="desc">The descriptor instance.</param> /// <param name="script">The script.</param> /// <param name="obj">The object.</param> /// <returns></returns> public static DynValue GetGetterCallbackAsDynValue(this IMemberDescriptor desc, Script script, object obj) { return(DynValue.NewCallback((p1, p2) => desc.GetValue(script, obj))); }
/// <summary> /// Executes the specified indexer method. /// </summary> /// <param name="mdesc">The method descriptor</param> /// <param name="script">The script.</param> /// <param name="obj">The object.</param> /// <param name="index">The indexer parameter</param> /// <param name="value">The dynvalue to set on a setter, or null.</param> /// <returns></returns> /// <exception cref="System.NotImplementedException"></exception> protected virtual DynValue ExecuteIndexer(IMemberDescriptor mdesc, Script script, object obj, DynValue index, DynValue value) { IList<DynValue> values; if (index.Type == DataType.Tuple) { if (value == null) { values = index.Tuple; } else { values = new List<DynValue>(index.Tuple); values.Add(value); } } else { if (value == null) { values = new DynValue[] { index }; } else { values = new DynValue[] { index, value }; } } CallbackArguments args = new CallbackArguments(values, false); ScriptExecutionContext execCtx = script.CreateDynamicExecutionContext(); DynValue v = mdesc.GetValue(script, obj); if (v.Type != DataType.ClrFunction) throw new ScriptRuntimeException("a clr callback was expected in member {0}, while a {1} was found", mdesc.Name, v.Type); return v.Callback.ClrCallback(execCtx, args); }