#region Copyright & License Information /* * Copyright 2007-2014 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, * see COPYING. */ #endregion using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Eluant; namespace OpenRA.Scripting { public class ScriptMemberWrapper { readonly ScriptContext context; public readonly object Target; public readonly MemberInfo Member; public readonly bool IsMethod; public readonly bool IsGetProperty; public readonly bool IsSetProperty; public ScriptMemberWrapper(ScriptContext context, object target, MemberInfo mi) { this.context = context; Target = target; Member = mi; var property = mi as PropertyInfo; if (property != null) { IsGetProperty = property.GetGetMethod() != null; IsSetProperty = property.GetSetMethod() != null; } else IsMethod = true; } LuaValue Invoke(LuaVararg args) { if (!IsMethod) throw new LuaException("Trying to invoke a ScriptMemberWrapper that isn't a method!"); var mi = (MethodInfo)Member; var pi = mi.GetParameters(); var clrArgs = new object[pi.Length]; var argCount = args.Count; for (var i = 0; i < pi.Length; i++) { if (i >= argCount) { if (!pi[i].IsOptional) throw new LuaException("Argument '{0}' of '{1}' is not optional.".F(pi[i].LuaDocString(), Member.LuaDocString())); clrArgs[i] = pi[i].DefaultValue; continue; } if (!args[i].TryGetClrValue(pi[i].ParameterType, out clrArgs[i])) throw new LuaException("Unable to convert parameter {0} to {1}".F(i, pi[i].ParameterType.Name)); } var ret = (mi.Invoke(Target, clrArgs)); return ret.ToLuaValue(context); } public LuaValue Get(LuaRuntime runtime) { if (IsMethod) return runtime.CreateFunctionFromDelegate((Func)Invoke); if (IsGetProperty) { var pi = Member as PropertyInfo; return pi.GetValue(Target, null).ToLuaValue(context); } throw new LuaException("The property '{0}' is write-only".F(Member.Name)); } public void Set(LuaRuntime runtime, LuaValue value) { if (IsSetProperty) { var pi = Member as PropertyInfo; object clrValue; if (!value.TryGetClrValue(pi.PropertyType, out clrValue)) throw new LuaException("Unable to convert '{0}' to Clr type '{1}'".F(value.WrappedClrType().Name, pi.PropertyType)); pi.SetValue(Target, clrValue, null); } else throw new LuaException("The property '{0}' is read-only".F(Member.Name)); } public static IEnumerable WrappableMembers(Type t) { // Only expose defined public non-static methods that were explicitly declared by the author var flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; return t.GetMembers(flags).Where(mi => { // Properties are always wrappable if (mi is PropertyInfo) return true; // Methods are allowed if they aren't generic, and aren't generated by the compiler var method = mi as MethodInfo; if (method != null && !method.IsGenericMethodDefinition && !method.IsSpecialName) return true; // Fields aren't allowed return false; }); } } }