private static MondValue JsonValueProperty(MondValue key, MondValue value) { var property = MondValue.Object(); property["name"] = key.ToString(); property["nameType"] = key.Type.GetName(); property["value"] = value.ToString(); property["valueType"] = value.Type.GetName(); return(property); }
public static bool MatchType( MondValue value, Type type ) { if( type == typeof( char ) ) return value.Type == MondValueType.String && value.ToString().Length == 1; if( value.Type == MondValueType.Object ) return value.UserData != null && type.IsAssignableFrom( value.UserData.GetType() ); return MatchType( value.Type, type ); }
public static bool MatchType(MondValue value, Type type) { if (type == typeof(char)) { return((value.Type == MondValueType.String) && (value.ToString().Length == 1)); } if (value.Type == MondValueType.Object) { return((type == typeof(MondValue)) || ((value.UserData != null) && type.IsInstanceOfType(value.UserData))); } return(TypeConverter.MatchType(value.Type, type)); }
public static string Format([MondInstance] MondValue instance, params MondValue[] arguments) { var values = arguments.Select <MondValue, object>(x => { // System.String.Format has certain format specifiers // that are valid for integers but not floats // (ex. String.Format( "{0:x2}", 1.23f ); throws FormatException // So we treat all whole numbers as integers, everything else // remains unchanged. if (x.Type == MondValueType.Number) { if (x % 1.0 == 0.0) { return((int)x); } return((double)x); } return(x.ToString()); }).ToArray(); return(string.Format(instance.ToString(), values)); }
public static object MarshalToClr( MondValue value, Type expectedType, MondState state ) { if( !MatchType( value, expectedType ) ) throw new ArgumentException( "Given value does not match expected type", "value" ); if( expectedType == typeof( MondValue ) ) return value; switch( value.Type ) { case MondValueType.False: case MondValueType.True: return (bool)value; case MondValueType.Null: case MondValueType.Undefined: return null; case MondValueType.String: var str = value.ToString(); if( expectedType == typeof( char ) ) { if( str.Length != 1 ) throw new ArgumentException( "Value cannot be converted to char", "value" ); return str[0]; } return str; case MondValueType.Number: if( expectedType.IsEnum ) { var underlying = Enum.GetUnderlyingType( expectedType ); var rawValue = Convert.ChangeType( (double)value, underlying ); var valueName = Enum.GetName( expectedType, rawValue ); return Enum.Parse( expectedType, valueName ); } return Convert.ChangeType( (double)value, expectedType ); case MondValueType.Object: return value.UserData; case MondValueType.Function: Func<object[], object> shim = delegate( object[] args ) { var result = null as MondValue; if( args == null ) result = state.Call( value ); else { var mondTypes = ToMondTypes( args.Select( a => a.GetType() ).ToArray() ); var mondValues = MarshalToMond( args, mondTypes ); result = state.Call( value, mondValues ); } var clrType = ToClrType( result ); return MarshalToClr( result, clrType, state ); }; return shim; default: UnsupportedMondTypeError( value.Type ); break; } return null; // we should never get here }
public static string ToString([MondInstance] MondValue instance) { return(instance.ToString()); }
private static MondValue ToString(MondState state, MondValue instance, params MondValue[] args) { return(instance.ToString()); }
public static object MarshalToClr( MondValue value, Type expectedType, MondState state, MondBindingOptions options) { if (!TypeConverter.MatchType(value, expectedType)) { throw new ArgumentException("Given value does not match expected type", nameof(value)); } if (expectedType == typeof(MondValue)) { return(value); } // ReSharper disable once SwitchStatementMissingSomeCases switch (value.Type) { case MondValueType.False: case MondValueType.True: return((bool)value); case MondValueType.Null: case MondValueType.Undefined: if (!expectedType.GetTypeInfo().IsValueType) { return(null); } if (expectedType.IsConstructedGenericType && (expectedType.GetGenericTypeDefinition() == typeof(Nullable <>))) { return(Activator.CreateInstance(expectedType)); } throw new InvalidOperationException( $"Cannot bind {value.Type.GetName()} value to " + $"{expectedType.FullName} because it is a value type"); case MondValueType.String: var str = value.ToString(); if (expectedType != typeof(char)) { return(str); } if (str.Length != 1) { throw new ArgumentException("Value cannot be converted to char", nameof(value)); } return(str[0]); case MondValueType.Number: if (expectedType.IsConstructedGenericType && (expectedType.GetGenericTypeDefinition() == typeof(Nullable <>))) { var innerType = expectedType.GetGenericArguments()[0]; var converted = Convert.ChangeType((double)value, innerType); return(Activator.CreateInstance(expectedType, converted)); } if (!expectedType.GetTypeInfo().IsEnum) { return(Convert.ChangeType((double)value, expectedType)); } var underlying = Enum.GetUnderlyingType(expectedType); var rawValue = Convert.ChangeType((double)value, underlying); var valueName = Enum.GetName(expectedType, rawValue); // ReSharper disable once AssignNullToNotNullAttribute return(Enum.Parse(expectedType, valueName)); case MondValueType.Object: return(value.UserData); case MondValueType.Function: object Shim(object[] args) { MondValue result; if ((args == null) || (args.Length == 0)) { result = state.Call(value); } else { var mondTypes = TypeConverter.ToMondTypes( args.Select(a => a.GetType()).ToArray()); var mondValues = TypeConverter.MarshalToMond(args, mondTypes, state, options); result = state.Call(value, mondValues); } if ((result.Type == MondValueType.Null) || (result.Type == MondValueType.Undefined)) { return(null); } var clrType = TypeConverter.ToClrType(result); return(TypeConverter.MarshalToClr(result, clrType, state, options)); } if (!typeof(Delegate).IsAssignableFrom(expectedType)) { return((Func <object[], object>)Shim); } var invoke = expectedType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.Instance); var parameters = invoke.GetParameters().Select(p => p.ParameterType).ToArray(); var delegateType = invoke.ReturnType == typeof(void) ? Expression.GetActionType(parameters) : Expression.GetFuncType(parameters.Concat(invoke.ReturnType).ToArray()); var shim = (Func <object[], object>)Shim; var paramsExpr = parameters.Select(Expression.Parameter).ToArray(); // ReSharper disable once CoVariantArrayConversion var paramsArr = Expression.NewArrayInit(typeof(object), paramsExpr); var invokeExpr = Expression.Call( Expression.Constant(shim.Target), shim.GetMethodInfo(), paramsArr); // ReSharper disable once TooWideLocalVariableScope BlockExpression body; if (invoke.ReturnType == typeof(void)) { body = Expression.Block(invokeExpr); } else { var castExpr = Expression.Convert(invokeExpr, invoke.ReturnType); body = Expression.Block(castExpr); } var method = typeof(Expression) .GetMethods(BindingFlags.Public | BindingFlags.Static) .Where(m => m.Name == "Lambda") .First(m => m.IsGenericMethodDefinition); var lambda = method.MakeGenericMethod(delegateType); return(((LambdaExpression)lambda.Invoke(null, new object[] { body, paramsExpr })).Compile()); default: TypeConverter.UnsupportedMondTypeError(value.Type); break; } return(null); // we should never get here }