using System; using System.Collections; using System.Collections.Immutable; using System.Linq; using System.Reflection; using Upsilon.BaseTypes.Number; using Upsilon.BaseTypes.ScriptFunction; using Upsilon.BaseTypes.ScriptTypeInterfaces; using Upsilon.BaseTypes.UserData; namespace Upsilon.BaseTypes { internal static class TypeConversion { public static ScriptType ToScriptType(this object o) { if (o is ScriptType type) return type; switch (o) { case bool b: return new ScriptBoolean(b); case int i: return new ScriptNumberLong(i); case short s: return new ScriptNumberLong(s); case sbyte s: return new ScriptNumberLong(s); case byte s: return new ScriptNumberLong(s); case long i: return new ScriptNumberLong(i); case float f: return new ScriptNumberDouble(f); case double f: return new ScriptNumberDouble(f); case string s: return new ScriptString(s); case null: return new ScriptNull(); default: return ConvertUserData(o); } } private static ScriptType ConvertUserData(object o) { if (o is IList ls) { return new ListUserData(ls); } if (o is IDictionary dic) { return new DictionaryUserData(dic); } if (o.GetType().IsGenericType) { var generic = o.GetType().GetGenericTypeDefinition(); if (generic.FullName != null && generic.FullName.Contains("System.Func")) { var function = (Delegate)o; var method = new UserDataMethod(function.GetMethodInfo()); return new ScriptMethodInfoFunction(method, null, false, false, false); } if (generic.FullName != null && generic.FullName.Contains("System.Action")) { var function = (Delegate)o; var method = new UserDataMethod(function.GetMethodInfo()); return new ScriptMethodInfoFunction(method, null, false, false, false); } } if (o is IEnumerable enumerable) { return new ListUserData(enumerable.Cast().ToList()); } return new GenericUserData(o); } public static Type GetScriptType(object o) { if (o is ScriptType t) { return t.Type; } switch (o) { case bool _: return Type.Boolean; case int _: return Type.Number; case long _: return Type.Number; case float _: return Type.Number; case double _: return Type.Number; case string _: return Type.String; case null: return Type.Nil; default: return Type.UserData; } } public static TypeContainer GetScriptType(this System.Type t) { var typeCode = System.Type.GetTypeCode(t); switch (typeCode) { case TypeCode.Boolean: return Type.Boolean; case TypeCode.Char: case TypeCode.String: return Type.String; case TypeCode.Byte: case TypeCode.Decimal: case TypeCode.Double: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.SByte: case TypeCode.Single: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: return Type.Number; case TypeCode.Empty: return Type.Nil; } if (t == typeof(void)) return Type.Nil; if (t == typeof(ScriptString)) return Type.String; if (t == typeof(ScriptBoolean)) return Type.Boolean; if (typeof(ScriptNumber).IsAssignableFrom(t)) return Type.Number; if (typeof(ScriptFunction.ScriptFunction).IsAssignableFrom(t)) return Type.Function; if (typeof(ScriptTable.ScriptTable).IsAssignableFrom(t)) return Type.Table; if (t == typeof(IIterable)) return Type.Nil; if (t == typeof(SimpleScriptTable)) return Type.Table; if (t.IsArray) { var elementType = t.GetElementType(); return new CompositeTypeContainer(new TypeContainer[] {Type.Number, GetScriptType(elementType)} .ToImmutableArray()); } if (typeof(IList).IsAssignableFrom(t)) { var generic = t.GetGenericArguments()[0]; return new CompositeTypeContainer(new TypeContainer[] {Type.Number, GetScriptType(generic)} .ToImmutableArray()); } if (typeof(IDictionary).IsAssignableFrom(t)) { var key = t.GetGenericArguments()[0]; var value = t.GetGenericArguments()[1]; return new CompositeTypeContainer(new[] {GetScriptType(key), GetScriptType(value)}.ToImmutableArray()); } if (typeof(IEnumerable).IsAssignableFrom(t)) return Type.Table; if (typeof(IIndexable).IsAssignableFrom(t)) return Type.Table; if (t == typeof(ScriptType)) return Type.Unknown; return new UndefinedUserDataTypeContainer(t); } } }