Upsilon/Upsilon/BaseTypes/TypeConversion.cs

182 lines
6.2 KiB
C#

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<object>().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);
}
}
}