mirror of
https://github.com/SSCLI/sscli_20021101
synced 2026-06-08 12:28:57 +00:00
9fa3874800
Moved the original file to the archive subfolder.
3637 lines
153 KiB
C#
3637 lines
153 KiB
C#
// ==++==
|
|
//
|
|
//
|
|
// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
|
|
//
|
|
// The use and distribution terms for this software are contained in the file
|
|
// named license.txt, which can be found in the root of this distribution.
|
|
// By using this software in any fashion, you are agreeing to be bound by the
|
|
// terms of this license.
|
|
//
|
|
// You must not remove this notice, or any other, from this software.
|
|
//
|
|
//
|
|
// ==--==
|
|
namespace Microsoft.JScript
|
|
{
|
|
|
|
using Microsoft.JScript.Vsa;
|
|
using System;
|
|
using System.Globalization;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
using System.Text;
|
|
using System.Diagnostics;
|
|
|
|
enum PreferredType : int {Either, Number, String, LocaleString};
|
|
|
|
public sealed class Convert{
|
|
|
|
public static bool IsBadIndex(AST ast){
|
|
Int32 i;
|
|
if (!(ast is ConstantWrapper))
|
|
return false;
|
|
try{
|
|
i = (Int32)CoerceT(((ConstantWrapper)ast).value, typeof(System.Int32));
|
|
}catch(Exception){
|
|
return true;
|
|
}
|
|
return i < 0;
|
|
}
|
|
|
|
public static Double CheckIfDoubleIsInteger(Double d){
|
|
if (d == System.Math.Round(d)) return d;
|
|
throw new JScriptException(JSError.TypeMismatch);
|
|
}
|
|
|
|
public static Single CheckIfSingleIsInteger(Single s){
|
|
if (s == System.Math.Round(s)) return s;
|
|
throw new JScriptException(JSError.TypeMismatch);
|
|
}
|
|
|
|
//This routine converts a value to the desired type, if possible.
|
|
//It throws an exception if the conversion has not been provided for, as well as when loss of information will occur.
|
|
//For example, coercing 1.5 to type Int32 will throw an exception.
|
|
public static Object Coerce(Object value, Object type){
|
|
return Convert.Coerce(value, type, false);
|
|
}
|
|
|
|
internal static Object Coerce(Object value, Object type, bool explicitOK){
|
|
TypeExpression te = type as TypeExpression;
|
|
if (te != null)
|
|
type = te.ToIReflect();
|
|
TypedArray ta = type as TypedArray;
|
|
if (ta != null){
|
|
IReflect eIr = ta.elementType;
|
|
int rank = ta.rank;
|
|
Type eTy = eIr is Type ? (Type)eIr : eIr is ClassScope ? ((ClassScope)eIr).GetBakedSuperType() : Typeob.Object;
|
|
ArrayObject ao = value as ArrayObject;
|
|
if (ao != null)
|
|
return ao.ToNativeArray(eTy);
|
|
Array arr = value as Array;
|
|
if (arr != null && arr.Rank == rank)
|
|
type = Convert.ToType(TypedArray.ToRankString(rank), eTy);
|
|
if (value == null || value is DBNull)
|
|
return null;
|
|
}
|
|
ClassScope csc = type as ClassScope;
|
|
if (csc != null){
|
|
if (csc.HasInstance(value))
|
|
return value;
|
|
else{
|
|
EnumDeclaration ed = csc.owner as EnumDeclaration;
|
|
if (ed != null){
|
|
EnumWrapper ew = value as EnumWrapper;
|
|
if (ew != null)
|
|
if (ew.type == csc) return value; else throw new JScriptException(JSError.TypeMismatch);
|
|
return new EnumWrapper(Coerce(value, ed.baseType), null, csc);
|
|
}
|
|
if (value == null || value is DBNull) return null;
|
|
throw new JScriptException(JSError.TypeMismatch);
|
|
}
|
|
}else if (!(type is Type))
|
|
type = Convert.ToType((IReflect)type);
|
|
else if (type == Typeob.Type && value is ClassScope)
|
|
return value;
|
|
return Convert.CoerceT(value, (Type)type, explicitOK);
|
|
}
|
|
|
|
//This routine converts a value to the desired type, if possible.
|
|
//It throws an exception if the conversion has not been provided for, as well as when loss of information will occur.
|
|
//For example, coercing 1.5 to type Int32 will throw an exception.
|
|
internal static Object CoerceT(Object value, Type type){
|
|
return Convert.CoerceT(value, type, false);
|
|
}
|
|
|
|
public static Object CoerceT(Object value, Type t, bool explicitOK){
|
|
if (t == Typeob.Object) return value;
|
|
if (t == Typeob.String && value is String) return value;
|
|
if (t.IsEnum && !(t is EnumBuilder) && !(t is TypeBuilder)){
|
|
IConvertible ic = Convert.GetIConvertible(value);
|
|
TypeCode vc = Convert.GetTypeCode(value, ic);
|
|
if (vc == TypeCode.String)
|
|
return Enum.Parse(t, ic.ToString());
|
|
else{
|
|
if (!explicitOK && vc != TypeCode.Empty){
|
|
Type vty = value.GetType();
|
|
if (vty.IsEnum)
|
|
if (vty != t) throw new JScriptException(JSError.TypeMismatch); else return value;
|
|
}
|
|
return Enum.ToObject(t, Convert.CoerceT(value, Convert.GetUnderlyingType(t), explicitOK));
|
|
}
|
|
}
|
|
TypeCode c2 = Type.GetTypeCode(t);
|
|
if (c2 != TypeCode.Object)
|
|
return Convert.Coerce2(value, c2, explicitOK);
|
|
if (value is ConcatString) value = value.ToString();
|
|
if (value == null || (value == DBNull.Value && t != Typeob.Object) || value is Missing || value is System.Reflection.Missing)
|
|
if (t.IsValueType)
|
|
return Activator.CreateInstance(t);
|
|
else
|
|
return null;
|
|
else if (t.IsAssignableFrom(value.GetType()))
|
|
return value;
|
|
else if (typeof(Delegate).IsAssignableFrom(t)){
|
|
if (value is Closure)
|
|
return ((Closure)value).ConvertToDelegate(t);
|
|
else if (value is FunctionWrapper)
|
|
return ((FunctionWrapper)value).ConvertToDelegate(t);
|
|
else if (value is FunctionObject) //called at compile-time from ConstantWrapper
|
|
return value; //Do nothing, ConstantWrapper will do the right thing.
|
|
}else if (value is ArrayObject && Typeob.Array.IsAssignableFrom(t))
|
|
return ((ArrayObject)value).ToNativeArray(t.GetElementType());
|
|
else if (value is Array && t == Typeob.ArrayObject && ((Array)value).Rank == 1){
|
|
if (Globals.contextEngine == null){
|
|
Globals.contextEngine = new VsaEngine(true); //ASP+ case
|
|
Globals.contextEngine.InitVsaEngine("JS7://Microsoft.JScript.Vsa.VsaEngine", new DefaultVsaSite());
|
|
}
|
|
return Globals.contextEngine.GetOriginalArrayConstructor().ConstructWrapper((Array)value);
|
|
}else if (value is ClassScope && t == Typeob.Type)
|
|
return ((ClassScope)value).GetTypeBuilderOrEnumBuilder();
|
|
else if (value is TypedArray && t == Typeob.Type)
|
|
return ((TypedArray)value).ToType();
|
|
//Look for a suitable op_Implicit or op_Explicit conversion
|
|
Type source_type = value.GetType();
|
|
MethodInfo meth = null;
|
|
if (explicitOK){
|
|
meth = t.GetMethod("op_Explicit", BindingFlags.ExactBinding|BindingFlags.Public|BindingFlags.Static, null, new Type[]{source_type}, null);
|
|
if (meth != null && (meth.Attributes & MethodAttributes.SpecialName) != 0){
|
|
meth = new JSMethodInfo(meth);
|
|
return meth.Invoke(null, BindingFlags.SuppressChangeType, null, new Object[]{value}, null);
|
|
}
|
|
meth = Convert.GetToXXXXMethod(source_type, t, explicitOK);
|
|
if (meth != null && (meth.Attributes & MethodAttributes.SpecialName) != 0){
|
|
meth = new JSMethodInfo(meth);
|
|
if (meth.IsStatic)
|
|
return meth.Invoke(null, BindingFlags.SuppressChangeType, null, new Object[]{value}, null);
|
|
else
|
|
return meth.Invoke(value, BindingFlags.SuppressChangeType, null, new Object[]{}, null);
|
|
}
|
|
}
|
|
meth = t.GetMethod("op_Implicit", BindingFlags.ExactBinding|BindingFlags.Public|BindingFlags.Static, null, new Type[]{source_type}, null);
|
|
if (meth != null && (meth.Attributes & MethodAttributes.SpecialName) != 0){
|
|
meth = new JSMethodInfo(meth);
|
|
return meth.Invoke(null, BindingFlags.SuppressChangeType, null, new Object[]{value}, null);
|
|
}
|
|
meth = Convert.GetToXXXXMethod(source_type, t, false);
|
|
if (meth != null && (meth.Attributes & MethodAttributes.SpecialName) != 0){
|
|
meth = new JSMethodInfo(meth);
|
|
if (meth.IsStatic)
|
|
return meth.Invoke(null, BindingFlags.SuppressChangeType, null, new Object[]{value}, null);
|
|
else
|
|
return meth.Invoke(value, BindingFlags.SuppressChangeType, null, new Object[]{}, null);
|
|
}
|
|
if (t.IsByRef)
|
|
return Convert.CoerceT(value, t.GetElementType());
|
|
Type vt = value.GetType();
|
|
throw new JScriptException(JSError.TypeMismatch);
|
|
}
|
|
|
|
//Call this routine only for target TypeTokens other than Object and Empty
|
|
//It special cases the well known types with JScript specific conversion semantics
|
|
public static Object Coerce2(Object value, TypeCode target, bool truncationPermitted){
|
|
if (truncationPermitted) return Coerce2WithTruncationPermitted(value, target);
|
|
return Coerce2WithNoTrunctation(value, target);
|
|
}
|
|
|
|
private static Object Coerce2WithNoTrunctation(Object value, TypeCode target){
|
|
if (value is EnumWrapper)
|
|
value = ((EnumWrapper)value).value;
|
|
if (value is ConstantWrapper)
|
|
value = ((ConstantWrapper)value).value;
|
|
try{ checked{
|
|
IConvertible ic = Convert.GetIConvertible(value);
|
|
switch (Convert.GetTypeCode(value, ic)){
|
|
case TypeCode.Empty:
|
|
switch (target){
|
|
case TypeCode.DBNull: return DBNull.Value;
|
|
case TypeCode.Boolean: return false;
|
|
case TypeCode.Char: return (Char)0;
|
|
case TypeCode.SByte: return (SByte)0;
|
|
case TypeCode.Byte: return (Byte)0;
|
|
case TypeCode.Int16: return (Int16)0;
|
|
case TypeCode.UInt16: return (UInt16)0;
|
|
case TypeCode.Int32: return (Int32)0;
|
|
case TypeCode.UInt32: return (UInt32)0;
|
|
case TypeCode.Int64: return (Int64)0;
|
|
case TypeCode.UInt64: return (UInt64)0;
|
|
case TypeCode.Single: return Single.NaN;
|
|
case TypeCode.Double: return Double.NaN;
|
|
case TypeCode.Decimal: return (Decimal)0;
|
|
case TypeCode.DateTime: return new DateTime((Int64)0);
|
|
case TypeCode.String: return null;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Object:
|
|
if (value is System.Reflection.Missing || (value is Missing && target != TypeCode.Object)) goto case TypeCode.Empty;
|
|
switch (target){
|
|
case TypeCode.Boolean: return Convert.ToBoolean(value, false);
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.Decimal: return Coerce2WithNoTrunctation(Convert.ToNumber(value, ic), target);
|
|
case TypeCode.DateTime:
|
|
if (value is DateObject)
|
|
return DatePrototype.getVarDate((DateObject)value);
|
|
else
|
|
return Coerce2WithNoTrunctation(Convert.ToNumber(value, ic), target);
|
|
case TypeCode.String: return Convert.ToString(value, ic);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.DBNull:
|
|
switch (target){
|
|
case TypeCode.DBNull: return DBNull.Value;
|
|
case TypeCode.Boolean: return false;
|
|
case TypeCode.Char: return (Char)0;
|
|
case TypeCode.SByte: return (SByte)0;
|
|
case TypeCode.Byte: return (Byte)0;
|
|
case TypeCode.Int16: return (Int16)0;
|
|
case TypeCode.UInt16: return (UInt16)0;
|
|
case TypeCode.Int32: return (Int32)0;
|
|
case TypeCode.UInt32: return (UInt32)0;
|
|
case TypeCode.Int64: return (Int64)0;
|
|
case TypeCode.UInt64: return (UInt64)0;
|
|
case TypeCode.Single: return (Single)0;
|
|
case TypeCode.Double: return (Double)0;
|
|
case TypeCode.Decimal: return (Decimal)0;
|
|
case TypeCode.DateTime: return new DateTime((Int64)0);
|
|
case TypeCode.String: return null;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Boolean:
|
|
bool b = ic.ToBoolean(null);
|
|
int bi = b ? 1 : 0;
|
|
switch (target){
|
|
case TypeCode.Boolean: return b;
|
|
case TypeCode.Char: return (Char)bi;
|
|
case TypeCode.SByte: return (SByte)bi;
|
|
case TypeCode.Byte: return (Byte)bi;
|
|
case TypeCode.Int16: return (Int16)bi;
|
|
case TypeCode.UInt16: return (UInt16)bi;
|
|
case TypeCode.Int32: return (Int32)bi;
|
|
case TypeCode.UInt32: return (UInt32)bi;
|
|
case TypeCode.Int64: return (Int64)bi;
|
|
case TypeCode.UInt64: return (UInt64)bi;
|
|
case TypeCode.Single: return (Single)bi;
|
|
case TypeCode.Double: return (Double)bi;
|
|
case TypeCode.Decimal: return (Decimal)bi;
|
|
case TypeCode.DateTime: return new DateTime((Int64)bi);
|
|
case TypeCode.String: return b ? "true" : "false";
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Char:
|
|
Char ch = ic.ToChar(null);
|
|
UInt16 us = (UInt16)ch;
|
|
switch (target){
|
|
case TypeCode.Boolean: return us != 0;
|
|
case TypeCode.Char: return ch;
|
|
case TypeCode.SByte: return (SByte)us;
|
|
case TypeCode.Byte: return (Byte)us;
|
|
case TypeCode.Int16: return (Int16)us;
|
|
case TypeCode.UInt16: return us;
|
|
case TypeCode.Int32: return (Int32)us;
|
|
case TypeCode.UInt32: return (UInt32)us;
|
|
case TypeCode.Int64: return (Int64)us;
|
|
case TypeCode.UInt64: return (UInt64)us;
|
|
case TypeCode.Single: return (Single)us;
|
|
case TypeCode.Double: return (Double)us;
|
|
case TypeCode.Decimal: return (Decimal)us;
|
|
case TypeCode.DateTime: return new DateTime((Int64)us);
|
|
case TypeCode.String: return Char.ToString(ch);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.SByte:
|
|
SByte sb = ic.ToSByte(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return sb != 0;
|
|
case TypeCode.Char: return (Char)sb;
|
|
case TypeCode.SByte: return sb;
|
|
case TypeCode.Byte: return (Byte)sb;
|
|
case TypeCode.Int16: return (Int16)sb;
|
|
case TypeCode.UInt16: return (UInt16)sb;
|
|
case TypeCode.Int32: return (Int32)sb;
|
|
case TypeCode.UInt32: return (UInt32)sb;
|
|
case TypeCode.Int64: return (Int64)sb;
|
|
case TypeCode.UInt64: return (UInt64)sb;
|
|
case TypeCode.Single: return (Single)sb;
|
|
case TypeCode.Double: return (Double)sb;
|
|
case TypeCode.Decimal: return (Decimal)sb;
|
|
case TypeCode.DateTime: return new DateTime((Int64)sb);
|
|
case TypeCode.String: return sb.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Byte:
|
|
Byte ub = ic.ToByte(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return ub != 0;
|
|
case TypeCode.Char: return (Char)ub;
|
|
case TypeCode.SByte: return (SByte)ub;
|
|
case TypeCode.Byte: return ub;
|
|
case TypeCode.Int16: return (Int16)ub;
|
|
case TypeCode.UInt16: return (UInt16)ub;
|
|
case TypeCode.Int32: return (Int32)ub;
|
|
case TypeCode.UInt32: return (UInt32)ub;
|
|
case TypeCode.Int64: return (Int64)ub;
|
|
case TypeCode.UInt64: return (UInt64)ub;
|
|
case TypeCode.Single: return (Single)ub;
|
|
case TypeCode.Double: return (Double)ub;
|
|
case TypeCode.Decimal: return (Decimal)ub;
|
|
case TypeCode.DateTime: return new DateTime((Int64)ub);
|
|
case TypeCode.String: return ub.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Int16:
|
|
Int16 s = ic.ToInt16(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return s != 0;
|
|
case TypeCode.Char: return (Char)s;
|
|
case TypeCode.SByte: return (SByte)s;
|
|
case TypeCode.Byte: return (Byte)s;
|
|
case TypeCode.Int16: return s;
|
|
case TypeCode.UInt16: return (UInt16)s;
|
|
case TypeCode.Int32: return (Int32)s;
|
|
case TypeCode.UInt32: return (UInt32)s;
|
|
case TypeCode.Int64: return (Int64)s;
|
|
case TypeCode.UInt64: return (UInt64)s;
|
|
case TypeCode.Single: return (Single)s;
|
|
case TypeCode.Double: return (Double)s;
|
|
case TypeCode.Decimal: return (Decimal)s;
|
|
case TypeCode.DateTime: return new DateTime((Int64)s);
|
|
case TypeCode.String: return s.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.UInt16:
|
|
us = ic.ToUInt16(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return us != 0;
|
|
case TypeCode.Char: return (Char)us;
|
|
case TypeCode.SByte: return (SByte)us;
|
|
case TypeCode.Byte: return (Byte)us;
|
|
case TypeCode.Int16: return (Int16)us;
|
|
case TypeCode.UInt16: return us;
|
|
case TypeCode.Int32: return (Int32)us;
|
|
case TypeCode.UInt32: return (UInt32)us;
|
|
case TypeCode.Int64: return (Int64)us;
|
|
case TypeCode.UInt64: return (UInt64)us;
|
|
case TypeCode.Single: return (Single)us;
|
|
case TypeCode.Double: return (Double)us;
|
|
case TypeCode.Decimal: return (Decimal)us;
|
|
case TypeCode.DateTime: return new DateTime((Int64)us);
|
|
case TypeCode.String: return us.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Int32:
|
|
Int32 i = ic.ToInt32(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return i != 0;
|
|
case TypeCode.Char: return (Char)i;
|
|
case TypeCode.SByte: return (SByte)i;
|
|
case TypeCode.Byte: return (Byte)i;
|
|
case TypeCode.Int16: return (Int16)i;
|
|
case TypeCode.UInt16: return (UInt16)i;
|
|
case TypeCode.Int32: return i;
|
|
case TypeCode.UInt32: return (UInt32)i;
|
|
case TypeCode.Int64: return (Int64)i;
|
|
case TypeCode.UInt64: return (UInt64)i;
|
|
case TypeCode.Single: return (Single)i;
|
|
case TypeCode.Double: return (Double)i;
|
|
case TypeCode.Decimal: return (Decimal)i;
|
|
case TypeCode.DateTime: return new DateTime((Int64)i);
|
|
case TypeCode.String: return i.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.UInt32:
|
|
UInt32 ui = ic.ToUInt32(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return ui != 0;
|
|
case TypeCode.Char: return (Char)ui;
|
|
case TypeCode.SByte: return (SByte)ui;
|
|
case TypeCode.Byte: return (Byte)ui;
|
|
case TypeCode.Int16: return (Int16)ui;
|
|
case TypeCode.UInt16: return (UInt16)ui;
|
|
case TypeCode.Int32: return (Int32)ui;
|
|
case TypeCode.UInt32: return ui;
|
|
case TypeCode.Int64: return (Int64)ui;
|
|
case TypeCode.UInt64: return (UInt64)ui;
|
|
case TypeCode.Single: return (Single)ui;
|
|
case TypeCode.Double: return (Double)ui;
|
|
case TypeCode.Decimal: return (Decimal)ui;
|
|
case TypeCode.DateTime: return new DateTime((Int64)ui);
|
|
case TypeCode.String: return ui.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Int64:
|
|
Int64 l = ic.ToInt64(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return l != 0;
|
|
case TypeCode.Char: return (Char)l;
|
|
case TypeCode.SByte: return (SByte)l;
|
|
case TypeCode.Byte: return (Byte)l;
|
|
case TypeCode.Int16: return (Int16)l;
|
|
case TypeCode.UInt16: return (UInt16)l;
|
|
case TypeCode.Int32: return (Int32)l;
|
|
case TypeCode.UInt32: return (UInt32)l;
|
|
case TypeCode.Int64: return l;
|
|
case TypeCode.UInt64: return (UInt64)l;
|
|
case TypeCode.Single: return (Single)l;
|
|
case TypeCode.Double: return (Double)l;
|
|
case TypeCode.Decimal: return (Decimal)l;
|
|
case TypeCode.DateTime: return new DateTime(l);
|
|
case TypeCode.String: return l.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.UInt64:
|
|
UInt64 ul = ic.ToUInt64(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return ul != 0;
|
|
case TypeCode.Char: return (Char)ul;
|
|
case TypeCode.SByte: return (SByte)ul;
|
|
case TypeCode.Byte: return (Byte)ul;
|
|
case TypeCode.Int16: return (Int16)ul;
|
|
case TypeCode.UInt16: return (UInt16)ul;
|
|
case TypeCode.Int32: return (Int32)ul;
|
|
case TypeCode.UInt32: return (UInt32)ul;
|
|
case TypeCode.Int64: return (Int64)ul;
|
|
case TypeCode.UInt64: return ul;
|
|
case TypeCode.Single: return (Single)ul;
|
|
case TypeCode.Double: return (Double)ul;
|
|
case TypeCode.Decimal: return (Decimal)ul;
|
|
case TypeCode.DateTime: return new DateTime((Int64)ul);
|
|
case TypeCode.String: return ul.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Single:
|
|
Single f = ic.ToSingle(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: if (f != f) return false; else return f != 0;
|
|
case TypeCode.Single: return f;
|
|
case TypeCode.Double: return (Double)f;
|
|
case TypeCode.Decimal: return (Decimal)f;
|
|
case TypeCode.String: return Convert.ToString((double)f);
|
|
default:
|
|
if (System.Math.Round(f) == f){
|
|
switch (target){
|
|
case TypeCode.Char: return (Char)f;
|
|
case TypeCode.SByte: return (SByte)f;
|
|
case TypeCode.Byte: return (Byte)f;
|
|
case TypeCode.Int16: return (Int16)f;
|
|
case TypeCode.UInt16: return (UInt16)f;
|
|
case TypeCode.Int32: return (Int32)f;
|
|
case TypeCode.UInt32: return (UInt32)f;
|
|
case TypeCode.Int64: return (Int64)f;
|
|
case TypeCode.UInt64: return (UInt64)f;
|
|
case TypeCode.DateTime: return new DateTime((Int64)f);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Double:
|
|
Double d = ic.ToDouble(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return Convert.ToBoolean(d);
|
|
case TypeCode.Single: return (float)d;
|
|
case TypeCode.Double: return d;
|
|
case TypeCode.Decimal: return (Decimal)d;
|
|
case TypeCode.String: return Convert.ToString(d);
|
|
default:
|
|
if (System.Math.Round(d) == d){
|
|
switch (target){
|
|
case TypeCode.Char: return (Char)d;
|
|
case TypeCode.SByte: return (SByte)d;
|
|
case TypeCode.Byte: return (Byte)d;
|
|
case TypeCode.Int16: return (Int16)d;
|
|
case TypeCode.UInt16: return (UInt16)d;
|
|
case TypeCode.Int32: return (Int32)d;
|
|
case TypeCode.UInt32: return (UInt32)d;
|
|
case TypeCode.Int64: return (Int64)d;
|
|
case TypeCode.UInt64: return (UInt64)d;
|
|
case TypeCode.DateTime: return new DateTime((Int64)d);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Decimal:
|
|
Decimal dec = ic.ToDecimal(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return Convert.ToBoolean(Decimal.ToDouble(dec));
|
|
case TypeCode.Char: return (Char)Decimal.ToUInt16(dec);
|
|
case TypeCode.SByte: return Decimal.ToSByte(dec);
|
|
case TypeCode.Byte: return Decimal.ToByte(dec);
|
|
case TypeCode.Int16:return Decimal.ToInt16(dec);
|
|
case TypeCode.UInt16: return Decimal.ToUInt16(dec);
|
|
case TypeCode.Int32: return Decimal.ToInt32(dec);
|
|
case TypeCode.UInt32: return Decimal.ToUInt32(dec);
|
|
case TypeCode.Int64: return Decimal.ToInt64(dec);
|
|
case TypeCode.UInt64: return Decimal.ToUInt64(dec);
|
|
case TypeCode.Single: return Decimal.ToSingle(dec);
|
|
case TypeCode.Double: return Decimal.ToDouble(dec);
|
|
case TypeCode.Decimal: return dec;
|
|
case TypeCode.DateTime: return new DateTime(Decimal.ToInt64(dec));
|
|
case TypeCode.String: return dec.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.DateTime:
|
|
DateTime dt = ic.ToDateTime(null);
|
|
switch (target){
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.Decimal: return Coerce2WithNoTrunctation(dt.Ticks, target);
|
|
case TypeCode.DateTime: return dt;
|
|
case TypeCode.String: return dt.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.String:
|
|
String str = ic.ToString(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return Convert.ToBoolean(str, false);
|
|
case TypeCode.Char:
|
|
if (str.Length == 1) return str[0];
|
|
throw new JScriptException(JSError.TypeMismatch);
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Double: return Coerce2WithNoTrunctation(Convert.ToNumber(str), target);
|
|
case TypeCode.Single: try {return Single.Parse(str, CultureInfo.InvariantCulture);}catch(Exception){goto case TypeCode.Double;}
|
|
case TypeCode.Int64: try {return Int64.Parse(str, CultureInfo.InvariantCulture);}catch(Exception){goto case TypeCode.Double;}
|
|
case TypeCode.UInt64: try {return UInt64.Parse(str, CultureInfo.InvariantCulture);}catch(Exception){goto case TypeCode.Double;}
|
|
case TypeCode.Decimal: try {return Decimal.Parse(str, CultureInfo.InvariantCulture);}catch(Exception){goto case TypeCode.Double;}
|
|
case TypeCode.DateTime:
|
|
try{
|
|
return DateTime.Parse(str, CultureInfo.InvariantCulture);
|
|
}catch(Exception){
|
|
return DatePrototype.getVarDate(DateConstructor.ob.CreateInstance(DatePrototype.ParseDate(str)));
|
|
}
|
|
case TypeCode.String: return str;
|
|
}
|
|
break;
|
|
}
|
|
}}catch(OverflowException){}
|
|
throw new JScriptException(JSError.TypeMismatch);
|
|
}
|
|
|
|
//Call this routine only for target TypeTokens other than Object and Empty
|
|
//It special cases the well known types with JScript specific conversion semantics
|
|
private static Object Coerce2WithTruncationPermitted(Object value, TypeCode target){
|
|
if (value is EnumWrapper)
|
|
value = ((EnumWrapper)value).value;
|
|
if (value is ConstantWrapper)
|
|
value = ((ConstantWrapper)value).value;
|
|
IConvertible ic = Convert.GetIConvertible(value);
|
|
switch (Convert.GetTypeCode(value, ic)){
|
|
case TypeCode.Empty:
|
|
switch (target){
|
|
case TypeCode.DBNull: return DBNull.Value;
|
|
case TypeCode.Boolean: return false;
|
|
case TypeCode.Char: return (Char)0;
|
|
case TypeCode.SByte: return (SByte)0;
|
|
case TypeCode.Byte: return (Byte)0;
|
|
case TypeCode.Int16: return (Int16)0;
|
|
case TypeCode.UInt16: return (UInt16)0;
|
|
case TypeCode.Int32: return (Int32)0;
|
|
case TypeCode.UInt32: return (UInt32)0;
|
|
case TypeCode.Int64: return (Int64)0;
|
|
case TypeCode.UInt64: return (UInt64)0;
|
|
case TypeCode.Single: return Single.NaN;
|
|
case TypeCode.Double: return Double.NaN;
|
|
case TypeCode.Decimal: return (Decimal)0;
|
|
case TypeCode.DateTime: return new DateTime((Int64)0);
|
|
case TypeCode.String: return "undefined";
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Object:
|
|
if (value is System.Reflection.Missing || (value is Missing && target != TypeCode.Object)) goto case TypeCode.Empty;
|
|
switch (target){
|
|
case TypeCode.Boolean: return Convert.ToBoolean(value, ic);
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.Decimal: return Coerce2WithTruncationPermitted(Convert.ToNumber(value, ic), target);
|
|
case TypeCode.DateTime:
|
|
if (value is DateObject)
|
|
return DatePrototype.getVarDate((DateObject)value);
|
|
else
|
|
return Coerce2WithTruncationPermitted(Convert.ToNumber(value, ic), target);
|
|
case TypeCode.String: return Convert.ToString(value, ic);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.DBNull:
|
|
switch (target){
|
|
case TypeCode.DBNull: return DBNull.Value;
|
|
case TypeCode.Boolean: return false;
|
|
case TypeCode.Char: return (Char)0;
|
|
case TypeCode.SByte: return (SByte)0;
|
|
case TypeCode.Byte: return (Byte)0;
|
|
case TypeCode.Int16: return (Int16)0;
|
|
case TypeCode.UInt16: return (UInt16)0;
|
|
case TypeCode.Int32: return (Int32)0;
|
|
case TypeCode.UInt32: return (UInt32)0;
|
|
case TypeCode.Int64: return (Int64)0;
|
|
case TypeCode.UInt64: return (UInt64)0;
|
|
case TypeCode.Single: return (Single)0;
|
|
case TypeCode.Double: return (Double)0;
|
|
case TypeCode.Decimal: return (Decimal)0;
|
|
case TypeCode.DateTime: return new DateTime((Int64)0);
|
|
case TypeCode.String: return "null";
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Boolean:
|
|
bool b = ic.ToBoolean(null);
|
|
int bi = b ? 1 : 0;
|
|
switch (target){
|
|
case TypeCode.Boolean: return b;
|
|
case TypeCode.Char: return (Char)bi;
|
|
case TypeCode.SByte: return (SByte)bi;
|
|
case TypeCode.Byte: return (Byte)bi;
|
|
case TypeCode.Int16: return (Int16)bi;
|
|
case TypeCode.UInt16: return (UInt16)bi;
|
|
case TypeCode.Int32: return (Int32)bi;
|
|
case TypeCode.UInt32: return (UInt32)bi;
|
|
case TypeCode.Int64: return (Int64)bi;
|
|
case TypeCode.UInt64: return (UInt64)bi;
|
|
case TypeCode.Single: return (Single)bi;
|
|
case TypeCode.Double: return (Double)bi;
|
|
case TypeCode.Decimal: return (Decimal)bi;
|
|
case TypeCode.DateTime: return new DateTime((Int64)bi);
|
|
case TypeCode.String: return b ? "true" : "false";
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Char:
|
|
Char ch = ic.ToChar(null);
|
|
UInt16 us = (UInt16)ch;
|
|
switch (target){
|
|
case TypeCode.Boolean: return us != 0;
|
|
case TypeCode.Char: return ch;
|
|
case TypeCode.SByte: return (SByte)us;
|
|
case TypeCode.Byte: return (Byte)us;
|
|
case TypeCode.Int16: return (Int16)us;
|
|
case TypeCode.UInt16: return us;
|
|
case TypeCode.Int32: return (Int32)us;
|
|
case TypeCode.UInt32: return (UInt32)us;
|
|
case TypeCode.Int64: return (Int64)us;
|
|
case TypeCode.UInt64: return (UInt64)us;
|
|
case TypeCode.Single: return (Single)us;
|
|
case TypeCode.Double: return (Double)us;
|
|
case TypeCode.Decimal: return (Decimal)us;
|
|
case TypeCode.DateTime: return new DateTime((Int64)us);
|
|
case TypeCode.String: return Char.ToString(ch);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.SByte:
|
|
SByte sb = ic.ToSByte(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return sb != 0;
|
|
case TypeCode.Char: return (Char)sb;
|
|
case TypeCode.SByte: return sb;
|
|
case TypeCode.Byte: return (Byte)sb;
|
|
case TypeCode.Int16: return (Int16)sb;
|
|
case TypeCode.UInt16: return (UInt16)sb;
|
|
case TypeCode.Int32: return (Int32)sb;
|
|
case TypeCode.UInt32: return (UInt32)sb;
|
|
case TypeCode.Int64: return (Int64)sb;
|
|
case TypeCode.UInt64: return (UInt64)sb;
|
|
case TypeCode.Single: return (Single)sb;
|
|
case TypeCode.Double: return (Double)sb;
|
|
case TypeCode.Decimal: return (Decimal)sb;
|
|
case TypeCode.DateTime: return new DateTime((Int64)sb);
|
|
case TypeCode.String: return sb.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Byte:
|
|
Byte ub = ic.ToByte(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return ub != 0;
|
|
case TypeCode.Char: return (Char)ub;
|
|
case TypeCode.SByte: return (SByte)ub;
|
|
case TypeCode.Byte: return ub;
|
|
case TypeCode.Int16: return (Int16)ub;
|
|
case TypeCode.UInt16: return (UInt16)ub;
|
|
case TypeCode.Int32: return (Int32)ub;
|
|
case TypeCode.UInt32: return (UInt32)ub;
|
|
case TypeCode.Int64: return (Int64)ub;
|
|
case TypeCode.UInt64: return (UInt64)ub;
|
|
case TypeCode.Single: return (Single)ub;
|
|
case TypeCode.Double: return (Double)ub;
|
|
case TypeCode.Decimal: return (Decimal)ub;
|
|
case TypeCode.DateTime: return new DateTime((Int64)ub);
|
|
case TypeCode.String: return ub.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Int16:
|
|
Int16 s = ic.ToInt16(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return s != 0;
|
|
case TypeCode.Char: return (Char)s;
|
|
case TypeCode.SByte: return (SByte)s;
|
|
case TypeCode.Byte: return (Byte)s;
|
|
case TypeCode.Int16: return s;
|
|
case TypeCode.UInt16: return (UInt16)s;
|
|
case TypeCode.Int32: return (Int32)s;
|
|
case TypeCode.UInt32: return (UInt32)s;
|
|
case TypeCode.Int64: return (Int64)s;
|
|
case TypeCode.UInt64: return (UInt64)s;
|
|
case TypeCode.Single: return (Single)s;
|
|
case TypeCode.Double: return (Double)s;
|
|
case TypeCode.Decimal: return (Decimal)s;
|
|
case TypeCode.DateTime: return new DateTime((Int64)s);
|
|
case TypeCode.String: return s.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.UInt16:
|
|
us = ic.ToUInt16(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return us != 0;
|
|
case TypeCode.Char: return (Char)us;
|
|
case TypeCode.SByte: return (SByte)us;
|
|
case TypeCode.Byte: return (Byte)us;
|
|
case TypeCode.Int16: return (Int16)us;
|
|
case TypeCode.UInt16: return us;
|
|
case TypeCode.Int32: return (Int32)us;
|
|
case TypeCode.UInt32: return (UInt32)us;
|
|
case TypeCode.Int64: return (Int64)us;
|
|
case TypeCode.UInt64: return (UInt64)us;
|
|
case TypeCode.Single: return (Single)us;
|
|
case TypeCode.Double: return (Double)us;
|
|
case TypeCode.Decimal: return (Decimal)us;
|
|
case TypeCode.DateTime: return new DateTime((Int64)us);
|
|
case TypeCode.String: return us.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Int32:
|
|
Int32 i = ic.ToInt32(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return i != 0;
|
|
case TypeCode.Char: return (Char)i;
|
|
case TypeCode.SByte: return (SByte)i;
|
|
case TypeCode.Byte: return (Byte)i;
|
|
case TypeCode.Int16: return (Int16)i;
|
|
case TypeCode.UInt16: return (UInt16)i;
|
|
case TypeCode.Int32: return i;
|
|
case TypeCode.UInt32: return (UInt32)i;
|
|
case TypeCode.Int64: return (Int64)i;
|
|
case TypeCode.UInt64: return (UInt64)i;
|
|
case TypeCode.Single: return (Single)i;
|
|
case TypeCode.Double: return (Double)i;
|
|
case TypeCode.Decimal: return (Decimal)i;
|
|
case TypeCode.DateTime: return new DateTime((Int64)i);
|
|
case TypeCode.String: return i.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.UInt32:
|
|
UInt32 ui = ic.ToUInt32(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return ui != 0;
|
|
case TypeCode.Char: return (Char)ui;
|
|
case TypeCode.SByte: return (SByte)ui;
|
|
case TypeCode.Byte: return (Byte)ui;
|
|
case TypeCode.Int16: return (Int16)ui;
|
|
case TypeCode.UInt16: return (UInt16)ui;
|
|
case TypeCode.Int32: return (Int32)ui;
|
|
case TypeCode.UInt32: return ui;
|
|
case TypeCode.Int64: return (Int64)ui;
|
|
case TypeCode.UInt64: return (UInt64)ui;
|
|
case TypeCode.Single: return (Single)ui;
|
|
case TypeCode.Double: return (Double)ui;
|
|
case TypeCode.Decimal: return (Decimal)ui;
|
|
case TypeCode.DateTime: return new DateTime((Int64)ui);
|
|
case TypeCode.String: return ui.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Int64:
|
|
Int64 l = ic.ToInt64(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return l != 0;
|
|
case TypeCode.Char: return (Char)l;
|
|
case TypeCode.SByte: return (SByte)l;
|
|
case TypeCode.Byte: return (Byte)l;
|
|
case TypeCode.Int16: return (Int16)l;
|
|
case TypeCode.UInt16: return (UInt16)l;
|
|
case TypeCode.Int32: return (Int32)l;
|
|
case TypeCode.UInt32: return (UInt32)l;
|
|
case TypeCode.Int64: return l;
|
|
case TypeCode.UInt64: return (UInt64)l;
|
|
case TypeCode.Single: return (Single)l;
|
|
case TypeCode.Double: return (Double)l;
|
|
case TypeCode.Decimal: return (Decimal)l;
|
|
case TypeCode.DateTime: return new DateTime(l);
|
|
case TypeCode.String: return l.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.UInt64:
|
|
UInt64 ul = ic.ToUInt64(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return ul != 0;
|
|
case TypeCode.Char: return (Char)ul;
|
|
case TypeCode.SByte: return (SByte)ul;
|
|
case TypeCode.Byte: return (Byte)ul;
|
|
case TypeCode.Int16: return (Int16)ul;
|
|
case TypeCode.UInt16: return (UInt16)ul;
|
|
case TypeCode.Int32: return (Int32)ul;
|
|
case TypeCode.UInt32: return (UInt32)ul;
|
|
case TypeCode.Int64: return (Int64)ul;
|
|
case TypeCode.UInt64: return ul;
|
|
case TypeCode.Single: return (Single)ul;
|
|
case TypeCode.Double: return (Double)ul;
|
|
case TypeCode.Decimal: return (Decimal)ul;
|
|
case TypeCode.DateTime: return new DateTime((Int64)ul);
|
|
case TypeCode.String: return ul.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Single:
|
|
Single f = ic.ToSingle(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: if (f != f) return false; else return f != 0;
|
|
case TypeCode.Single: return f;
|
|
case TypeCode.Double: return (Double)f;
|
|
case TypeCode.Decimal: return (Decimal)f;
|
|
case TypeCode.String: return Convert.ToString((double)f);
|
|
case TypeCode.Char: return (Char)f;
|
|
case TypeCode.SByte: return (SByte)f;
|
|
case TypeCode.Byte: return (Byte)f;
|
|
case TypeCode.Int16: return (Int16)f;
|
|
case TypeCode.UInt16: return (UInt16)f;
|
|
case TypeCode.Int32: return (Int32)f;
|
|
case TypeCode.UInt32: return (UInt32)f;
|
|
case TypeCode.Int64: return (Int64)f;
|
|
case TypeCode.UInt64: return (UInt64)f;
|
|
case TypeCode.DateTime: return new DateTime((Int64)f);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Double:
|
|
Double d = ic.ToDouble(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return Convert.ToBoolean(d);
|
|
case TypeCode.Single: return (float)d;
|
|
case TypeCode.Double: return d;
|
|
case TypeCode.Decimal: return (Decimal)d;
|
|
case TypeCode.String: return Convert.ToString(d);
|
|
case TypeCode.Char: return (Char)d;
|
|
case TypeCode.SByte: return (SByte)d;
|
|
case TypeCode.Byte: return (Byte)d;
|
|
case TypeCode.Int16: return (Int16)d;
|
|
case TypeCode.UInt16: return (UInt16)d;
|
|
case TypeCode.Int32: return (Int32)d;
|
|
case TypeCode.UInt32: return (UInt32)d;
|
|
case TypeCode.Int64: return (Int64)d;
|
|
case TypeCode.UInt64: return (UInt64)d;
|
|
case TypeCode.DateTime: return new DateTime((Int64)d);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Decimal:
|
|
Decimal dec = ic.ToDecimal(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return Convert.ToBoolean(Decimal.ToDouble(dec));
|
|
case TypeCode.Char: return (Char)Decimal.ToUInt16(dec);
|
|
case TypeCode.SByte: return Decimal.ToSByte(dec);
|
|
case TypeCode.Byte: return Decimal.ToByte(dec);
|
|
case TypeCode.Int16:return Decimal.ToInt16(dec);
|
|
case TypeCode.UInt16: return Decimal.ToUInt16(dec);
|
|
case TypeCode.Int32: return Decimal.ToInt32(dec);
|
|
case TypeCode.UInt32: return Decimal.ToUInt32(dec);
|
|
case TypeCode.Int64: return Decimal.ToInt64(dec);
|
|
case TypeCode.UInt64: return Decimal.ToUInt64(dec);
|
|
case TypeCode.Single: return Decimal.ToSingle(dec);
|
|
case TypeCode.Double: return Decimal.ToDouble(dec);
|
|
case TypeCode.Decimal: return dec;
|
|
case TypeCode.DateTime: return new DateTime(Decimal.ToInt64(dec));
|
|
case TypeCode.String: return dec.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.DateTime:
|
|
DateTime dt = ic.ToDateTime(null);
|
|
switch (target){
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.Decimal: return Coerce2WithTruncationPermitted(dt.Ticks, target);
|
|
case TypeCode.DateTime: return dt;
|
|
case TypeCode.String: return dt.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
break;
|
|
|
|
case TypeCode.String:
|
|
String str = ic.ToString(null);
|
|
switch (target){
|
|
case TypeCode.Boolean: return Convert.ToBoolean(str, false);
|
|
case TypeCode.Char:
|
|
if (str.Length == 1) return str[0];
|
|
throw new JScriptException(JSError.TypeMismatch);
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Double: return Coerce2WithTruncationPermitted(Convert.ToNumber(str), target);
|
|
case TypeCode.Single: try {return Single.Parse(str, CultureInfo.InvariantCulture);}catch(Exception){goto case TypeCode.Double;}
|
|
case TypeCode.Int64:
|
|
try{
|
|
return Int64.Parse(str, CultureInfo.InvariantCulture);
|
|
}catch(Exception){
|
|
try{
|
|
return (long)UInt64.Parse(str, CultureInfo.InvariantCulture);
|
|
}catch(Exception){
|
|
goto case TypeCode.Double;
|
|
}
|
|
}
|
|
case TypeCode.UInt64: try {return UInt64.Parse(str, CultureInfo.InvariantCulture);}catch(Exception){goto case TypeCode.Double;}
|
|
case TypeCode.Decimal: try {return Decimal.Parse(str, CultureInfo.InvariantCulture);}catch(Exception){goto case TypeCode.Double;}
|
|
case TypeCode.DateTime: return DateTime.Parse(str, CultureInfo.InvariantCulture);
|
|
case TypeCode.String: return str;
|
|
}
|
|
break;
|
|
}
|
|
throw new JScriptException(JSError.TypeMismatch);
|
|
}
|
|
|
|
//This function emits a compiled version of Coerce for a particular (source_type, target_type) pair.
|
|
//It assumes that an operand of source_type is already on the operand stack. It consumes this operand
|
|
//and leaves a result of target_type in its place.
|
|
internal static void Emit(AST ast, ILGenerator il, Type source_type, Type target_type){
|
|
Convert.Emit(ast, il, source_type, target_type, false);
|
|
}
|
|
|
|
internal static void Emit(AST ast, ILGenerator il, Type source_type, Type target_type, bool truncationPermitted){
|
|
if (source_type == target_type) return;
|
|
if (target_type == Typeob.Void){
|
|
il.Emit(OpCodes.Pop);
|
|
return;
|
|
}
|
|
if (target_type.IsEnum){
|
|
if (source_type == Typeob.String || source_type == Typeob.Object){
|
|
il.Emit(OpCodes.Ldtoken, target_type);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.getTypeFromHandleMethod);
|
|
ConstantWrapper.TranslateToILInt(il, truncationPermitted ? 1 : 0);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.coerceTMethod);
|
|
Convert.EmitUnbox(il, target_type, Type.GetTypeCode(Convert.GetUnderlyingType(target_type)));
|
|
}else
|
|
Convert.Emit(ast, il, source_type, Convert.GetUnderlyingType(target_type));
|
|
return;
|
|
}
|
|
if (source_type.IsEnum){
|
|
if (target_type.IsPrimitive){
|
|
Convert.Emit(ast, il, Convert.GetUnderlyingType(source_type), target_type);
|
|
return;
|
|
}
|
|
if (target_type == Typeob.Object || target_type == typeof(Enum)){
|
|
il.Emit(OpCodes.Box, source_type);
|
|
return;
|
|
}
|
|
if (target_type == Typeob.String){
|
|
il.Emit(OpCodes.Box, source_type);
|
|
ConstantWrapper.TranslateToILInt(il, 0);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.toStringMethod);
|
|
return;
|
|
}
|
|
}
|
|
|
|
while (source_type is TypeBuilder){
|
|
source_type = source_type.BaseType;
|
|
if (source_type == null) source_type = Typeob.Object; //It is an interface
|
|
if (source_type == target_type) return;
|
|
}
|
|
|
|
if (source_type.IsArray && target_type.IsArray)
|
|
//This should only be called if the two types are known to be compatible, so:
|
|
return;
|
|
|
|
TypeCode source = Type.GetTypeCode(source_type);
|
|
TypeCode target = target_type is TypeBuilder ? TypeCode.Object : Type.GetTypeCode(target_type);
|
|
switch (source){
|
|
case TypeCode.Empty: //can never occur
|
|
return;
|
|
|
|
case TypeCode.Object:
|
|
if (source_type == Typeob.Void){
|
|
il.Emit(OpCodes.Ldnull);
|
|
source_type = Typeob.Object;
|
|
}
|
|
switch (target){
|
|
case TypeCode.Object:
|
|
//The conversion from function object to delegate never happens here. ConstantWrapper takes care of it.
|
|
//First check for array target type or TypeBuilder target type. These do not support IsAssignableFrom.
|
|
if (target_type.IsArray || target_type == Typeob.Array){
|
|
if (source_type == Typeob.ArrayObject || source_type == Typeob.Object){
|
|
if (target_type.IsArray)
|
|
il.Emit(OpCodes.Ldtoken, target_type.GetElementType());
|
|
else
|
|
il.Emit(OpCodes.Ldtoken, Typeob.Object);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.toNativeArrayMethod);
|
|
}
|
|
il.Emit(OpCodes.Castclass, target_type);
|
|
return;
|
|
}else if (target_type is TypeBuilder){
|
|
il.Emit(OpCodes.Castclass, target_type);
|
|
return;
|
|
}else if (target_type == typeof(Enum) && source_type.BaseType == typeof(Enum)){
|
|
il.Emit(OpCodes.Box, source_type);
|
|
return;
|
|
}else if (target_type == Typeob.Object || target_type.IsAssignableFrom(source_type)){
|
|
if (source_type.IsValueType)
|
|
il.Emit(OpCodes.Box, source_type);
|
|
return;
|
|
}
|
|
|
|
if (Typeob.JSObject.IsAssignableFrom(target_type)){
|
|
if (source_type.IsValueType)
|
|
il.Emit(OpCodes.Box, source_type);
|
|
ast.EmitILToLoadEngine(il);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.toObject2Method); //Do this here so that we need not pass engine to Coerce
|
|
il.Emit(OpCodes.Castclass, target_type);
|
|
return;
|
|
}
|
|
|
|
if (Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
|
|
return;
|
|
|
|
//Either no conversion is possible, or not enough information is available at compile time.
|
|
//PartialEvaluator is supposed to give errors when conversions are known to be impossible.
|
|
//Defer to run-time type checking
|
|
if (target_type.IsValueType || target_type.IsArray){
|
|
il.Emit(OpCodes.Ldtoken, target_type);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.getTypeFromHandleMethod);
|
|
ConstantWrapper.TranslateToILInt(il, truncationPermitted ? 1 : 0);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.coerceTMethod);
|
|
}
|
|
if (target_type.IsValueType)
|
|
Convert.EmitUnbox(il, target_type, target);
|
|
else
|
|
il.Emit(OpCodes.Castclass, target_type);
|
|
return;
|
|
|
|
case TypeCode.Boolean:
|
|
if (source_type.IsValueType)
|
|
il.Emit(OpCodes.Box, source_type);
|
|
ConstantWrapper.TranslateToILInt(il, truncationPermitted ? 1 : 0);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.toBooleanMethod);
|
|
return;
|
|
|
|
case TypeCode.Single:
|
|
if (source_type.IsValueType)
|
|
il.Emit(OpCodes.Box, source_type);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.toNumberMethod);
|
|
il.Emit(OpCodes.Conv_R4);
|
|
return;
|
|
|
|
case TypeCode.Double:
|
|
if (source_type.IsValueType)
|
|
il.Emit(OpCodes.Box, source_type);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.toNumberMethod);
|
|
return;
|
|
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Decimal:
|
|
case TypeCode.DateTime:
|
|
if (source_type.IsValueType)
|
|
il.Emit(OpCodes.Box, source_type);
|
|
if (truncationPermitted && target == TypeCode.Int32){
|
|
il.Emit(OpCodes.Call, CompilerGlobals.toInt32Method);
|
|
return;
|
|
}else{
|
|
ConstantWrapper.TranslateToILInt(il, (int)target);
|
|
ConstantWrapper.TranslateToILInt(il, truncationPermitted ? 1 : 0);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.coerce2Method);
|
|
}
|
|
if (target_type.IsValueType)
|
|
Convert.EmitUnbox(il, target_type, target);
|
|
return;
|
|
|
|
case TypeCode.String:
|
|
if (source_type.IsValueType)
|
|
il.Emit(OpCodes.Box, source_type);
|
|
if (truncationPermitted) //explict cast to type string
|
|
il.Emit(OpCodes.Castclass, Typeob.String);
|
|
else{
|
|
ConstantWrapper.TranslateToILInt(il, 1);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.toStringMethod);
|
|
}
|
|
return;
|
|
}
|
|
return;
|
|
|
|
case TypeCode.DBNull:
|
|
if (source_type.IsValueType) //Not likely, but a hacker might cause this to be true.
|
|
il.Emit(OpCodes.Box, source_type);
|
|
if (target == TypeCode.Object || (target == TypeCode.String && !truncationPermitted)){
|
|
if (target_type == Typeob.Object)
|
|
return;
|
|
if (!target_type.IsValueType){
|
|
il.Emit(OpCodes.Pop);
|
|
il.Emit(OpCodes.Ldnull);
|
|
return;
|
|
}
|
|
}
|
|
if (target_type.IsValueType){
|
|
il.Emit(OpCodes.Ldtoken, target_type);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.getTypeFromHandleMethod);
|
|
ConstantWrapper.TranslateToILInt(il, truncationPermitted ? 1 : 0);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.coerceTMethod);
|
|
Convert.EmitUnbox(il, target_type, target);
|
|
}else{
|
|
ConstantWrapper.TranslateToILInt(il, (int)target);
|
|
ConstantWrapper.TranslateToILInt(il, truncationPermitted ? 1 : 0);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.coerce2Method); //constructs and boxes whatever value is needed
|
|
}
|
|
return;
|
|
|
|
case TypeCode.Boolean:
|
|
switch (target){
|
|
case TypeCode.Object:
|
|
if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
|
|
return;
|
|
il.Emit(OpCodes.Box, source_type);
|
|
Convert.Emit(ast, il, Typeob.Object, target_type);
|
|
return;
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.Byte:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.UInt32:
|
|
return;
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
il.Emit(OpCodes.Conv_U8);
|
|
return;
|
|
case TypeCode.Single:
|
|
il.Emit(OpCodes.Conv_R4);
|
|
return;
|
|
case TypeCode.Double:
|
|
il.Emit(OpCodes.Conv_R8);
|
|
return;
|
|
case TypeCode.Decimal:
|
|
il.Emit(OpCodes.Call, CompilerGlobals.int32ToDecimalMethod);
|
|
return;
|
|
case TypeCode.DateTime:
|
|
il.Emit(OpCodes.Conv_I8);
|
|
il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
|
|
return;
|
|
case TypeCode.String:
|
|
Label false_label = il.DefineLabel();
|
|
Label end_label = il.DefineLabel();
|
|
il.Emit(OpCodes.Brfalse, false_label);
|
|
il.Emit(OpCodes.Ldstr, "true");
|
|
il.Emit(OpCodes.Br, end_label);
|
|
il.MarkLabel(false_label);
|
|
il.Emit(OpCodes.Ldstr, "false");
|
|
il.MarkLabel(end_label);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.SByte:
|
|
switch (target){
|
|
case TypeCode.Object:
|
|
if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
|
|
return;
|
|
il.Emit(OpCodes.Box, source_type);
|
|
Convert.Emit(ast, il, Typeob.Object, target_type);
|
|
return;
|
|
case TypeCode.SByte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.Int32:
|
|
return;
|
|
case TypeCode.Byte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U1);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U1);
|
|
return;
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U2);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U2);
|
|
return;
|
|
case TypeCode.UInt32:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U4);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U4);
|
|
return;
|
|
case TypeCode.Int64:
|
|
il.Emit(OpCodes.Conv_I8);
|
|
return;
|
|
case TypeCode.UInt64:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I8);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U8);
|
|
return;
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
il.Emit(OpCodes.Conv_R8);
|
|
return;
|
|
case TypeCode.Boolean:
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Ceq);
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Ceq);
|
|
return;
|
|
case TypeCode.Decimal:
|
|
il.Emit(OpCodes.Call, CompilerGlobals.int32ToDecimalMethod);
|
|
return;
|
|
case TypeCode.DateTime:
|
|
il.Emit(OpCodes.Conv_I8);
|
|
il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
|
|
return;
|
|
case TypeCode.String:
|
|
Convert.EmitLdloca(il, Typeob.Int32);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.int32ToStringMethod);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Byte:
|
|
switch (target){
|
|
case TypeCode.Object:
|
|
if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
|
|
return;
|
|
il.Emit(OpCodes.Box, source_type);
|
|
Convert.Emit(ast, il, Typeob.Object, target_type);
|
|
return;
|
|
case TypeCode.SByte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I1);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I1_Un);
|
|
return;
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
return;
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
il.Emit(OpCodes.Conv_U8);
|
|
return;
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
il.Emit(OpCodes.Conv_R_Un);
|
|
return;
|
|
case TypeCode.Boolean:
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Ceq);
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Ceq);
|
|
return;
|
|
case TypeCode.Decimal:
|
|
il.Emit(OpCodes.Call, CompilerGlobals.uint32ToDecimalMethod);
|
|
return;
|
|
case TypeCode.DateTime:
|
|
il.Emit(OpCodes.Conv_I8);
|
|
il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
|
|
return;
|
|
case TypeCode.String:
|
|
Convert.EmitLdloca(il, Typeob.UInt32);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.uint32ToStringMethod);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Int16:
|
|
switch (target){
|
|
case TypeCode.Object:
|
|
if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
|
|
return;
|
|
il.Emit(OpCodes.Box, source_type);
|
|
Convert.Emit(ast, il, Typeob.Object, target_type);
|
|
return;
|
|
case TypeCode.SByte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I1);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I1);
|
|
return;
|
|
case TypeCode.Int16:
|
|
case TypeCode.Int32:
|
|
return;
|
|
case TypeCode.Byte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U1);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U1);
|
|
return;
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U2);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U2);
|
|
return;
|
|
case TypeCode.UInt32:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U4);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U4);
|
|
return;
|
|
case TypeCode.Int64:
|
|
il.Emit(OpCodes.Conv_I8);
|
|
return;
|
|
case TypeCode.UInt64:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I8);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U8);
|
|
return;
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
il.Emit(OpCodes.Conv_R8);
|
|
return;
|
|
case TypeCode.Boolean:
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Ceq);
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Ceq);
|
|
return;
|
|
case TypeCode.Decimal:
|
|
il.Emit(OpCodes.Call, CompilerGlobals.int32ToDecimalMethod);
|
|
return;
|
|
case TypeCode.DateTime:
|
|
il.Emit(OpCodes.Conv_I8);
|
|
il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
|
|
return;
|
|
case TypeCode.String:
|
|
Convert.EmitLdloca(il, Typeob.Int32);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.int32ToStringMethod);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
switch (target){
|
|
case TypeCode.Object:
|
|
if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
|
|
return;
|
|
il.Emit(OpCodes.Box, source_type);
|
|
Convert.Emit(ast, il, Typeob.Object, target_type);
|
|
return;
|
|
case TypeCode.SByte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I1);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I1);
|
|
return;
|
|
case TypeCode.Byte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U1);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U1);
|
|
return;
|
|
case TypeCode.Int16:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I2);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I2);
|
|
return;
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
return;
|
|
case TypeCode.Int64:
|
|
il.Emit(OpCodes.Conv_I8);
|
|
return;
|
|
case TypeCode.UInt64:
|
|
il.Emit(OpCodes.Conv_U8);
|
|
return;
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
il.Emit(OpCodes.Conv_R_Un);
|
|
return;
|
|
case TypeCode.Boolean:
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Ceq);
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Ceq);
|
|
return;
|
|
case TypeCode.Decimal:
|
|
il.Emit(OpCodes.Call, CompilerGlobals.uint32ToDecimalMethod);
|
|
return;
|
|
case TypeCode.DateTime:
|
|
il.Emit(OpCodes.Conv_I8);
|
|
il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
|
|
return;
|
|
case TypeCode.String:
|
|
if (source == TypeCode.Char)
|
|
il.Emit(OpCodes.Call, CompilerGlobals.convertCharToStringMethod);
|
|
else{
|
|
Convert.EmitLdloca(il, Typeob.UInt32);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.uint32ToStringMethod);
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Int32:
|
|
switch (target){
|
|
case TypeCode.Object:
|
|
if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
|
|
return;
|
|
il.Emit(OpCodes.Box, source_type);
|
|
Convert.Emit(ast, il, Typeob.Object, target_type);
|
|
return;
|
|
case TypeCode.SByte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I1);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I1);
|
|
return;
|
|
case TypeCode.Int16:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I2);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I2);
|
|
return;
|
|
case TypeCode.Int32:
|
|
return;
|
|
case TypeCode.Byte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U1);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U1);
|
|
return;
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U2);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U2);
|
|
return;
|
|
case TypeCode.UInt32:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U4);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U4);
|
|
return;
|
|
case TypeCode.Int64:
|
|
il.Emit(OpCodes.Conv_I8);
|
|
return;
|
|
case TypeCode.UInt64:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U8);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U8);
|
|
return;
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
il.Emit(OpCodes.Conv_R8);
|
|
return;
|
|
case TypeCode.Boolean:
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Ceq);
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Ceq);
|
|
return;
|
|
case TypeCode.Decimal:
|
|
il.Emit(OpCodes.Call, CompilerGlobals.int32ToDecimalMethod);
|
|
return;
|
|
case TypeCode.DateTime:
|
|
il.Emit(OpCodes.Conv_I8);
|
|
il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
|
|
return;
|
|
case TypeCode.String:
|
|
Convert.EmitLdloca(il, Typeob.Int32);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.int32ToStringMethod);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.UInt32:
|
|
switch (target){
|
|
case TypeCode.Object:
|
|
if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
|
|
return;
|
|
il.Emit(OpCodes.Box, source_type);
|
|
Convert.Emit(ast, il, Typeob.Object, target_type);
|
|
return;
|
|
case TypeCode.SByte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I1);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I1);
|
|
return;
|
|
case TypeCode.Byte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U1);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U1);
|
|
return;
|
|
case TypeCode.Int16:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I2);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I2);
|
|
return;
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U2);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U2);
|
|
return;
|
|
case TypeCode.Int32:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I4);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I4_Un);
|
|
return;
|
|
case TypeCode.UInt32:
|
|
return;
|
|
case TypeCode.Int64:
|
|
il.Emit(OpCodes.Conv_I8);
|
|
return;
|
|
case TypeCode.UInt64:
|
|
il.Emit(OpCodes.Conv_U8);
|
|
return;
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
il.Emit(OpCodes.Conv_R_Un);
|
|
return;
|
|
case TypeCode.Boolean:
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Ceq);
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Ceq);
|
|
return;
|
|
case TypeCode.Decimal:
|
|
il.Emit(OpCodes.Call, CompilerGlobals.uint32ToDecimalMethod);
|
|
return;
|
|
case TypeCode.DateTime:
|
|
il.Emit(OpCodes.Conv_I8);
|
|
il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
|
|
return;
|
|
case TypeCode.String:
|
|
Convert.EmitLdloca(il, Typeob.UInt32);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.uint32ToStringMethod);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Int64:
|
|
switch (target){
|
|
case TypeCode.Object:
|
|
if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
|
|
return;
|
|
il.Emit(OpCodes.Box, source_type);
|
|
Convert.Emit(ast, il, Typeob.Object, target_type);
|
|
return;
|
|
case TypeCode.SByte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I1);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I1);
|
|
return;
|
|
case TypeCode.Int16:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I2);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I2);
|
|
return;
|
|
case TypeCode.Int32:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I4);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I4);
|
|
return;
|
|
case TypeCode.Byte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U1);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U1);
|
|
return;
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U2);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U2);
|
|
return;
|
|
case TypeCode.UInt32:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U4);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U4);
|
|
return;
|
|
case TypeCode.Int64:
|
|
return;
|
|
case TypeCode.UInt64:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U8);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U8);
|
|
return;
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
il.Emit(OpCodes.Conv_R8);
|
|
return;
|
|
case TypeCode.Boolean:
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Conv_I8);
|
|
il.Emit(OpCodes.Ceq);
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Ceq);
|
|
return;
|
|
case TypeCode.Decimal:
|
|
il.Emit(OpCodes.Call, CompilerGlobals.int64ToDecimalMethod);
|
|
return;
|
|
case TypeCode.DateTime:
|
|
il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
|
|
return;
|
|
case TypeCode.String:
|
|
Convert.EmitLdloca(il, Typeob.Int64);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.int64ToStringMethod);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.UInt64:
|
|
switch (target){
|
|
case TypeCode.Object:
|
|
if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
|
|
return;
|
|
il.Emit(OpCodes.Box, source_type);
|
|
Convert.Emit(ast, il, Typeob.Object, target_type);
|
|
return;
|
|
case TypeCode.SByte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I1);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I1);
|
|
return;
|
|
case TypeCode.Byte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U1);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U1);
|
|
return;
|
|
case TypeCode.Int16:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I2);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I2);
|
|
return;
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U2);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U2);
|
|
return;
|
|
case TypeCode.Int32:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I4);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I4);
|
|
return;
|
|
case TypeCode.UInt32:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U4);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_U4);
|
|
return;
|
|
case TypeCode.Int64:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I8);
|
|
else
|
|
il.Emit(OpCodes.Conv_Ovf_I8_Un);
|
|
return;
|
|
case TypeCode.UInt64:
|
|
return;
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
il.Emit(OpCodes.Conv_R_Un);
|
|
return;
|
|
case TypeCode.Boolean:
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Conv_I8);
|
|
il.Emit(OpCodes.Ceq);
|
|
il.Emit(OpCodes.Ldc_I4_0);
|
|
il.Emit(OpCodes.Ceq);
|
|
return;
|
|
case TypeCode.Decimal:
|
|
il.Emit(OpCodes.Call, CompilerGlobals.uint64ToDecimalMethod);
|
|
return;
|
|
case TypeCode.DateTime:
|
|
il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
|
|
return;
|
|
case TypeCode.String:
|
|
Convert.EmitLdloca(il, Typeob.UInt64);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.uint64ToStringMethod);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Single:
|
|
switch (target){
|
|
case TypeCode.Object:
|
|
if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
|
|
return;
|
|
il.Emit(OpCodes.Box, source_type);
|
|
Convert.Emit(ast, il, Typeob.Object, target_type);
|
|
return;
|
|
case TypeCode.SByte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I1);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_Ovf_I1);
|
|
}
|
|
return;
|
|
case TypeCode.Int16:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I2);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_Ovf_I2);
|
|
}
|
|
return;
|
|
case TypeCode.Int32:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I4);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_I4);
|
|
}
|
|
return;
|
|
case TypeCode.Byte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U1);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_Ovf_U1);
|
|
}
|
|
return;
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U2);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_Ovf_U2);
|
|
}
|
|
return;
|
|
case TypeCode.UInt32:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_Ovf_U4);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_Ovf_U4);
|
|
}
|
|
return;
|
|
case TypeCode.Int64:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I8);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_I8);
|
|
}
|
|
return;
|
|
case TypeCode.UInt64:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U8);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_Ovf_U8);
|
|
}
|
|
return;
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
return;
|
|
case TypeCode.DateTime:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I8);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_Ovf_I8);
|
|
}
|
|
il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
|
|
return;
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Decimal:
|
|
case TypeCode.String:
|
|
il.Emit(OpCodes.Conv_R8);
|
|
Convert.Emit(ast, il, Typeob.Double, target_type);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Double:
|
|
switch (target){
|
|
case TypeCode.Object:
|
|
if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
|
|
return;
|
|
il.Emit(OpCodes.Box, source_type);
|
|
Convert.Emit(ast, il, Typeob.Object, target_type);
|
|
return;
|
|
case TypeCode.SByte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I1);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_Ovf_I1);
|
|
}
|
|
return;
|
|
case TypeCode.Int16:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I2);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_Ovf_I2);
|
|
}
|
|
return;
|
|
case TypeCode.Int32:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I4);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_Ovf_I4);
|
|
}
|
|
return;
|
|
case TypeCode.Byte:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U1);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_Ovf_U1);
|
|
}
|
|
return;
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U2);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_Ovf_U2);
|
|
}
|
|
return;
|
|
case TypeCode.UInt32:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U4);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_Ovf_U4);
|
|
}
|
|
return;
|
|
case TypeCode.Int64:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I8);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_I8);
|
|
}
|
|
return;
|
|
case TypeCode.UInt64:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_U8);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfDoubleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_Ovf_U8);
|
|
}
|
|
return;
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
return;
|
|
case TypeCode.Boolean:
|
|
il.Emit(OpCodes.Call, CompilerGlobals.doubleToBooleanMethod);
|
|
return;
|
|
case TypeCode.Decimal:
|
|
il.Emit(OpCodes.Call, CompilerGlobals.doubleToDecimalMethod);
|
|
return;
|
|
case TypeCode.DateTime:
|
|
if (truncationPermitted)
|
|
il.Emit(OpCodes.Conv_I8);
|
|
else{
|
|
il.Emit(OpCodes.Call, CompilerGlobals.checkIfSingleIsIntegerMethod);
|
|
il.Emit(OpCodes.Conv_Ovf_I8);
|
|
}
|
|
il.Emit(OpCodes.Newobj, CompilerGlobals.dateTimeConstructor);
|
|
return;
|
|
case TypeCode.String:
|
|
il.Emit(OpCodes.Call, CompilerGlobals.doubleToStringMethod);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.Decimal:
|
|
switch (target){
|
|
case TypeCode.Object:
|
|
if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
|
|
return;
|
|
il.Emit(OpCodes.Box, source_type);
|
|
Convert.Emit(ast, il, Typeob.Object, target_type);
|
|
return;
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
if (truncationPermitted){
|
|
il.Emit(OpCodes.Call, CompilerGlobals.decimalToDoubleMethod);
|
|
il.Emit(OpCodes.Conv_I4);
|
|
}else
|
|
il.Emit(OpCodes.Call, CompilerGlobals.decimalToInt32Method);
|
|
Convert.Emit(ast, il, Typeob.Int32, target_type, truncationPermitted);
|
|
return;
|
|
case TypeCode.UInt32:
|
|
if (truncationPermitted){
|
|
il.Emit(OpCodes.Call, CompilerGlobals.decimalToDoubleMethod);
|
|
il.Emit(OpCodes.Conv_U4);
|
|
}else
|
|
il.Emit(OpCodes.Call, CompilerGlobals.decimalToUInt32Method);
|
|
return;
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
il.Emit(OpCodes.Call, CompilerGlobals.decimalToDoubleMethod);
|
|
Convert.Emit(ast, il, Typeob.Double, target_type, truncationPermitted);
|
|
return;
|
|
case TypeCode.Int64:
|
|
if (truncationPermitted){
|
|
il.Emit(OpCodes.Call, CompilerGlobals.decimalToDoubleMethod);
|
|
il.Emit(OpCodes.Conv_I8);
|
|
}else
|
|
il.Emit(OpCodes.Call, CompilerGlobals.decimalToInt64Method);
|
|
return;
|
|
case TypeCode.UInt64:
|
|
if (truncationPermitted){
|
|
il.Emit(OpCodes.Call, CompilerGlobals.decimalToDoubleMethod);
|
|
il.Emit(OpCodes.Conv_U8);
|
|
}else
|
|
il.Emit(OpCodes.Call, CompilerGlobals.decimalToUInt64Method);
|
|
return;
|
|
case TypeCode.Decimal:
|
|
return;
|
|
case TypeCode.DateTime:
|
|
if (truncationPermitted){
|
|
il.Emit(OpCodes.Call, CompilerGlobals.decimalToDoubleMethod);
|
|
il.Emit(OpCodes.Conv_I8);
|
|
}else
|
|
il.Emit(OpCodes.Call, CompilerGlobals.decimalToInt64Method);
|
|
Convert.Emit(ast, il, Typeob.Int64, target_type);
|
|
return;
|
|
case TypeCode.String:
|
|
Convert.EmitLdloca(il, source_type);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.decimalToStringMethod);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.DateTime:
|
|
switch (target){
|
|
case TypeCode.Object:
|
|
if (target_type != Typeob.Object && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
|
|
return;
|
|
il.Emit(OpCodes.Box, source_type);
|
|
Convert.Emit(ast, il, Typeob.Object, target_type);
|
|
return;
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.Decimal:
|
|
Convert.EmitLdloca(il, source_type);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.dateTimeToInt64Method);
|
|
Convert.Emit(ast, il, Typeob.Int64, target_type, truncationPermitted);
|
|
return;
|
|
case TypeCode.DateTime:
|
|
return;
|
|
case TypeCode.String:
|
|
Convert.EmitLdloca(il, source_type);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.dateTimeToStringMethod);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case TypeCode.String:
|
|
switch (target){
|
|
case TypeCode.Object:
|
|
if (target_type != Typeob.Object && !(target_type is TypeBuilder) && Convert.EmittedCallToConversionMethod(ast, il, source_type, target_type))
|
|
return;
|
|
Convert.Emit(ast, il, Typeob.Object, target_type);
|
|
return;
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.Decimal:
|
|
case TypeCode.DateTime:
|
|
//Resort to calling the Coerce routine. The extra call and the extra box/unbox adds neglible cost to such an expensive conversion.
|
|
if (truncationPermitted && target == TypeCode.Int32){
|
|
il.Emit(OpCodes.Call, CompilerGlobals.toInt32Method);
|
|
return;
|
|
}else{
|
|
ConstantWrapper.TranslateToILInt(il, (int)target);
|
|
ConstantWrapper.TranslateToILInt(il, truncationPermitted ? 1 : 0);
|
|
il.Emit(OpCodes.Call, CompilerGlobals.coerce2Method);
|
|
}
|
|
if (target_type.IsValueType) //Should always be true, but may as well check
|
|
Convert.EmitUnbox(il, target_type, target);
|
|
return;
|
|
case TypeCode.String:
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
Convert.Emit(ast, il, source_type, Typeob.Object); //The thing on the stack cannot be converted to target_type. Arrange for an error message.
|
|
il.Emit(OpCodes.Call, CompilerGlobals.throwTypeMismatch);
|
|
LocalBuilder tok = il.DeclareLocal(target_type); //Add dummy code to reassure the verifier.
|
|
il.Emit(OpCodes.Ldloc, tok);
|
|
}
|
|
|
|
internal static void EmitUnbox(ILGenerator il, Type target_type, TypeCode target){
|
|
il.Emit(OpCodes.Unbox, target_type);
|
|
switch(target){
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Byte:
|
|
il.Emit(OpCodes.Ldind_U1); return;
|
|
case TypeCode.Char:
|
|
case TypeCode.UInt16:
|
|
il.Emit(OpCodes.Ldind_U2); return;
|
|
case TypeCode.SByte:
|
|
il.Emit(OpCodes.Ldind_I1); return;
|
|
case TypeCode.Int16:
|
|
il.Emit(OpCodes.Ldind_I2); return;
|
|
case TypeCode.Int32:
|
|
il.Emit(OpCodes.Ldind_I4); return;
|
|
case TypeCode.UInt32:
|
|
il.Emit(OpCodes.Ldind_U4); return;
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
il.Emit(OpCodes.Ldind_I8); return;
|
|
case TypeCode.Single:
|
|
il.Emit(OpCodes.Ldind_R4); return;
|
|
case TypeCode.Double:
|
|
il.Emit(OpCodes.Ldind_R8); return;
|
|
default:
|
|
il.Emit(OpCodes.Ldobj, target_type); return;
|
|
}
|
|
}
|
|
|
|
private static bool EmittedCallToConversionMethod(AST ast, ILGenerator il, Type source_type, Type target_type){
|
|
//Look for an explicit conversion, call that if there is one
|
|
MethodInfo meth = target_type.GetMethod("op_Explicit", BindingFlags.ExactBinding|BindingFlags.Public|BindingFlags.Static, null, new Type[]{source_type}, null);
|
|
if (meth != null){
|
|
il.Emit(OpCodes.Call, meth);
|
|
Convert.Emit(ast, il, meth.ReturnType, target_type);
|
|
return true;
|
|
}
|
|
meth = Convert.GetToXXXXMethod(source_type, target_type, true);
|
|
if (meth != null){
|
|
il.Emit(OpCodes.Call, meth);
|
|
return true;
|
|
}
|
|
|
|
//Look for implicit conversion, call that if there is one
|
|
meth = target_type.GetMethod("op_Implicit", BindingFlags.ExactBinding|BindingFlags.Public|BindingFlags.Static, null, new Type[]{source_type}, null);
|
|
if (meth != null){
|
|
il.Emit(OpCodes.Call, meth);
|
|
Convert.Emit(ast, il, meth.ReturnType, target_type);
|
|
return true;
|
|
}
|
|
meth = Convert.GetToXXXXMethod(source_type, target_type, false);
|
|
if (meth != null){
|
|
il.Emit(OpCodes.Call, meth);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal static void EmitLdarg(ILGenerator il, short argNum){
|
|
switch(argNum){
|
|
case 0 : il.Emit(OpCodes.Ldarg_0); return;
|
|
case 1 : il.Emit(OpCodes.Ldarg_1); return;
|
|
case 2 : il.Emit(OpCodes.Ldarg_2); return;
|
|
case 3 : il.Emit(OpCodes.Ldarg_3); return;
|
|
}
|
|
if (argNum < 256)
|
|
il.Emit(OpCodes.Ldarg_S, (byte)argNum);
|
|
else
|
|
il.Emit(OpCodes.Ldarg, argNum);
|
|
}
|
|
|
|
internal static void EmitLdloca(ILGenerator il, Type source_type){
|
|
LocalBuilder tok = il.DeclareLocal(source_type);
|
|
il.Emit(OpCodes.Stloc, tok);
|
|
il.Emit(OpCodes.Ldloca, tok);
|
|
}
|
|
|
|
private static IReflect GetArrayElementType(IReflect ir){
|
|
if (ir is TypedArray)
|
|
return ((TypedArray)ir).elementType;
|
|
else if (ir is Type && ((Type)ir).IsArray)
|
|
return ((Type)ir).GetElementType();
|
|
else if (ir is ArrayObject || ir == Typeob.ArrayObject)
|
|
return Typeob.Object;
|
|
else
|
|
return null;
|
|
}
|
|
|
|
internal static int GetArrayRank(IReflect ir){
|
|
if (ir == Typeob.ArrayObject || ir is ArrayObject)
|
|
return 1;
|
|
else if (ir is TypedArray)
|
|
return ((TypedArray)ir).rank;
|
|
else if (ir is Type && ((Type)ir).IsArray)
|
|
return ((Type)ir).GetArrayRank();
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
internal static IConvertible GetIConvertible(Object ob){
|
|
return ob as IConvertible;
|
|
}
|
|
|
|
private static MethodInfo GetToXXXXMethod(IReflect ir, Type desiredType, bool explicitOK){
|
|
if ((ir is TypeBuilder) || (ir is EnumBuilder)) return null;
|
|
MemberInfo[] members = ir.GetMember(explicitOK ? "op_Explicit" : "op_Implicit", BindingFlags.Public|BindingFlags.Static);
|
|
if (members != null)
|
|
foreach(MemberInfo mem in members)
|
|
if (mem is MethodInfo)
|
|
if (((MethodInfo)mem).ReturnType == desiredType)
|
|
return (MethodInfo)mem;
|
|
return null;
|
|
}
|
|
|
|
internal static TypeCode GetTypeCode(Object ob, IConvertible ic){
|
|
if (ob == null) return TypeCode.Empty;
|
|
if (ic == null) return TypeCode.Object;
|
|
return ic.GetTypeCode();
|
|
}
|
|
|
|
internal static TypeCode GetTypeCode(Object ob){
|
|
return Convert.GetTypeCode(ob, Convert.GetIConvertible(ob));
|
|
}
|
|
|
|
private static Type GetUnderlyingType(Type type){
|
|
if (type is TypeBuilder) return type.UnderlyingSystemType;
|
|
return Enum.GetUnderlyingType(type);
|
|
}
|
|
|
|
internal static bool IsArray(IReflect ir){
|
|
return ir == Typeob.Array || ir == Typeob.ArrayObject || ir is TypedArray ||
|
|
ir is ArrayObject || (ir is Type && ((Type)ir).IsArray);
|
|
}
|
|
|
|
private static bool IsArrayElementTypeKnown(IReflect ir){
|
|
Debug.PreCondition(IsArray(ir));
|
|
return ir == Typeob.ArrayObject || ir is TypedArray ||
|
|
ir is ArrayObject || (ir is Type && ((Type)ir).IsArray);
|
|
}
|
|
|
|
internal static bool IsArrayRankKnown(IReflect ir) {
|
|
Debug.PreCondition(IsArray(ir));
|
|
return ir == Typeob.ArrayObject || ir is TypedArray ||
|
|
ir is ArrayObject || (ir is Type && ((Type)ir).IsArray);
|
|
}
|
|
|
|
internal static bool IsArrayType(IReflect ir){
|
|
return ir is TypedArray || ir == Typeob.Array || ir == Typeob.ArrayObject || (ir is Type && ((Type)ir).IsArray);
|
|
}
|
|
|
|
internal static bool IsJScriptArray(IReflect ir){
|
|
return ir is ArrayObject || ir == Typeob.ArrayObject;
|
|
}
|
|
|
|
internal static bool IsPrimitiveSignedNumericType(Type t){
|
|
switch(Type.GetTypeCode(t)){
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.Int64: return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal static bool IsPrimitiveSignedIntegerType(Type t){
|
|
switch(Type.GetTypeCode(t)){
|
|
case TypeCode.SByte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.Int64: return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal static bool IsPrimitiveUnsignedIntegerType(Type t){
|
|
switch(Type.GetTypeCode(t)){
|
|
case TypeCode.Byte:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.UInt64: return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal static bool IsPrimitiveIntegerType(Type t){
|
|
switch(Type.GetTypeCode(t)){
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64: return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal static bool IsPrimitiveNumericTypeCode(TypeCode tc){
|
|
switch(tc){
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double: return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal static bool IsPrimitiveNumericType(IReflect ir){
|
|
Type t = ir as Type;
|
|
if (t == null) return false;
|
|
return Convert.IsPrimitiveNumericTypeCode(Type.GetTypeCode(t));
|
|
}
|
|
|
|
internal static bool IsPrimitiveNumericTypeFitForDouble(IReflect ir){
|
|
Type t = ir as Type;
|
|
if (t == null) return false;
|
|
switch (Type.GetTypeCode(t)){
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double: return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* indicates whether all values of source type can be converted to the target type without loss of information */
|
|
private static bool[,] promotable = new bool[,]
|
|
{ /*target type*/
|
|
/*source Empty Object DBNull Boolean Char SByte Byte Int16 UInt16 Int32 UInt32 Int64 UInt64 Single Double Decimal DateTime TimeSpan String*/
|
|
/*Empty*/ { true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true},
|
|
/*Object*/ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
|
|
/*DBNull*/ { true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true},
|
|
/*Boolean*/ { false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false},
|
|
/*Char*/ { false, false, false, false, true, false, false, false, true, true, true, true, true, true, true, true, true, true, false},
|
|
/*SByte*/ { false, false, false, false, false, true, false, true, false, true, false, true, false, true, true, true, true, true, false},
|
|
/*Byte*/ { false, false, false, false, true, false, true, true, true, true, true, true, true, true, true, true, true, true, false},
|
|
/*Int16*/ { false, false, false, false, false, true, false, true, false, true, false, true, false, true, true, true, true, true, false},
|
|
/*UInt16*/ { false, false, false, false, true, false, false, false, true, true, true, true, true, true, true, true, true, true, false},
|
|
/*Int32*/ { false, false, false, false, false, false, false, false, false, true, false, true, false, false, true, true, true, true, false},
|
|
/*UInt32*/ { false, false, false, false, false, false, false, false, false, false, true, true, true, false, true, true, true, true, false},
|
|
/*Int64*/ { false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, true, true, false},
|
|
/*UInt64*/ { false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, true, true, true, false},
|
|
/*Single*/ { false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, true, false, false, false},
|
|
/*Double*/ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, false, false, false},
|
|
/*Decimal*/ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false},
|
|
/*DateTime*/ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false},
|
|
/*TimeSpan*/ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false},
|
|
/*String*/ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true}
|
|
};
|
|
// By "promotable" we mean that:
|
|
// * value types may be promoted to other value types if there is no possible loss of data
|
|
// (Int16 is promotable to Double, but Double is not promotable to Int16.)
|
|
// * value types may be promoted to their wrapper reference types
|
|
// (A boolean is promotable to a Boolean object.)
|
|
// * reference types may be promoted to reference types they inherit from, but not vice-versa.
|
|
// (A Derived is promotable to a Base, but a Base is not promotable to a Derived.)
|
|
|
|
private static bool IsPromotableTo(Type source_type, Type target_type){
|
|
TypeCode source = Type.GetTypeCode(source_type);
|
|
TypeCode target = Type.GetTypeCode(target_type);
|
|
if (Convert.promotable[(int)source, (int)target])
|
|
return true;
|
|
if ((source == TypeCode.Object || source == TypeCode.String) && target == TypeCode.Object){
|
|
if (target_type.IsAssignableFrom(source_type))
|
|
return true;
|
|
if (target_type == Typeob.BooleanObject && source_type == Typeob.Boolean)
|
|
return true;
|
|
if (target_type == Typeob.StringObject && source_type == Typeob.String)
|
|
return true;
|
|
if (target_type == Typeob.NumberObject && Convert.IsPromotableTo(source_type, Typeob.Double))
|
|
return true;
|
|
if (target_type == Typeob.Array || source_type == Typeob.Array || target_type.IsArray || source_type.IsArray)
|
|
return Convert.IsPromotableToArray(source_type, target_type);
|
|
}
|
|
if (source_type == Typeob.BooleanObject && target_type == Typeob.Boolean)
|
|
return true;
|
|
if (source_type == Typeob.StringObject && target_type == Typeob.String)
|
|
return true;
|
|
if (source_type == Typeob.DateObject && target_type == Typeob.DateTime)
|
|
return true;
|
|
if (source_type == Typeob.NumberObject)
|
|
return Convert.IsPrimitiveNumericType(target_type);
|
|
if (source_type.IsEnum) return !target_type.IsEnum && Convert.IsPromotableTo(Convert.GetUnderlyingType(source_type), target_type);
|
|
if (target_type.IsEnum) return !source_type.IsEnum && Convert.IsPromotableTo(source_type, Convert.GetUnderlyingType(target_type));
|
|
//Look for implicit conversions.
|
|
MethodInfo meth = target_type.GetMethod("op_Implicit", BindingFlags.ExactBinding|BindingFlags.Public|BindingFlags.Static, null, new Type[]{source_type}, null);
|
|
if (meth != null && (meth.Attributes & MethodAttributes.SpecialName) != 0) return true;
|
|
meth = Convert.GetToXXXXMethod(source_type, target_type, false);
|
|
if (meth != null && (meth.Attributes & MethodAttributes.SpecialName) != 0) return true;
|
|
return false;
|
|
}
|
|
|
|
internal static bool IsPromotableTo(IReflect source_ir, IReflect target_ir){
|
|
Type target_type;
|
|
if (source_ir is TypedArray || target_ir is TypedArray ||
|
|
source_ir is ArrayObject || target_ir is ArrayObject ||
|
|
source_ir == Typeob.ArrayObject || target_ir == Typeob.ArrayObject)
|
|
return Convert.IsPromotableToArray(source_ir, target_ir);
|
|
if (target_ir is ClassScope){
|
|
if (((ClassScope)target_ir).owner is EnumDeclaration){
|
|
if (Convert.IsPrimitiveNumericType(source_ir))
|
|
return IsPromotableTo(source_ir, ((EnumDeclaration)((ClassScope)target_ir).owner).baseType.ToType());
|
|
else if (source_ir == Typeob.String) return true;
|
|
else if (source_ir == target_ir) return true;
|
|
return false;
|
|
}
|
|
if (source_ir is ClassScope)
|
|
return (((ClassScope)source_ir).IsSameOrDerivedFrom((ClassScope)target_ir));
|
|
return false; //The source is not in the same compilation unit. Thus it can only extend the target type if there is a circular dependency and separate compilation. Can't handle that.
|
|
}else if (target_ir is Type){
|
|
if (target_ir == Typeob.Object) return !(source_ir is Type) || !((Type)source_ir).IsByRef;
|
|
target_type = (Type)target_ir;
|
|
}else if (target_ir is ScriptFunction)
|
|
target_type = Typeob.ScriptFunction;
|
|
else
|
|
//assert that target_ir is JSObject
|
|
target_type = target_ir.GetType();
|
|
if (source_ir is ClassScope)
|
|
return ((ClassScope)source_ir).IsPromotableTo(target_type);
|
|
else
|
|
return IsPromotableTo(source_ir is Type ? (Type)source_ir : source_ir.GetType(), target_type);
|
|
}
|
|
|
|
// IsPromotableToArray determines whether or not we _know_ at compile time
|
|
// that a given source type may be _promoted_ safely to a given target type.
|
|
// Here we are concerned about two things:
|
|
// (1) Is the target a base class of the source?
|
|
// (2) Is the target a wrapper class of the source?
|
|
//
|
|
// We wish to implement the following semantics:
|
|
//
|
|
// * No non-array is promotable to any array.
|
|
// * An array is only promotable to another array or Object.
|
|
// * Any array (regardless of element type or rank) is promotable to Object.
|
|
// * JScript arrays are not promotable to anything except JS Array and Object.
|
|
// * Every array (other than JScript array) is promotable to System.Array.
|
|
// * System.Array is not promotable to anything -- we do not have enough information
|
|
// to make a safe promotion. Note that System Arrays are _assignment compatible_ to
|
|
// JScript arrays but not _promotable_ to JScript arrays. We wish to be conservative
|
|
// here and we do not know if the System.Array is of rank one.
|
|
// * Any rank-one array (regardless of element type) is promotable to a JScript array
|
|
// via the wrapper class.
|
|
// * A source array is promotable to a typed array only if the source and the target
|
|
// are known to be both equal in rank and element-type compatible.
|
|
// * By "element type compatible" we mean the following: Value types are only compatible
|
|
// with equal value types. (Int16[] is not promotable to Int32[] even though Int16
|
|
// is promotable to Int32.) Value types are never compatible with reference types.
|
|
// (Int32[] is not promotable to Object[].) Reference types are only compatible if
|
|
// they are promotable. (Derived[] is promotable to Base[] but Base[] is not
|
|
// promotable to Derived[].)
|
|
|
|
private static bool IsPromotableToArray(IReflect source_ir, IReflect target_ir){
|
|
Debug.PreCondition(IsArray(source_ir) || IsArray(target_ir));
|
|
if (!IsArray(source_ir))
|
|
return false;
|
|
else if (target_ir == Typeob.Object)
|
|
return true;
|
|
else if (!IsArray(target_ir)){
|
|
if (target_ir is Type){
|
|
Type tt = (Type)target_ir;
|
|
if (tt.IsInterface && tt.IsAssignableFrom(Typeob.Array))
|
|
return source_ir is TypedArray || (source_ir is Type && ((Type)source_ir).IsArray);
|
|
}
|
|
return false;
|
|
}else if (IsJScriptArray(source_ir) && !IsJScriptArray(target_ir))
|
|
return false;
|
|
else if (target_ir == Typeob.Array)
|
|
return !IsJScriptArray(source_ir);
|
|
else if (source_ir == Typeob.Array)
|
|
return false;
|
|
else if (GetArrayRank(source_ir) == 1 && IsJScriptArray(target_ir))
|
|
return true;
|
|
else if (GetArrayRank(source_ir) != GetArrayRank(target_ir))
|
|
return false;
|
|
|
|
IReflect source_element_ir = GetArrayElementType(source_ir);
|
|
IReflect target_element_ir = GetArrayElementType(target_ir);
|
|
|
|
if (null == source_element_ir || null == target_element_ir)
|
|
return false;
|
|
|
|
if ((source_element_ir is Type && ((Type)source_element_ir).IsValueType) ||
|
|
(target_element_ir is Type && ((Type)target_element_ir).IsValueType))
|
|
return source_element_ir == target_element_ir;
|
|
else
|
|
return Convert.IsPromotableTo(source_element_ir, target_element_ir);
|
|
}
|
|
|
|
private static bool IsWhiteSpace(char c) {
|
|
switch (c) {
|
|
case (char)0x09:
|
|
case (char)0x0A:
|
|
case (char)0x0B:
|
|
case (char)0x0C:
|
|
case (char)0x0D:
|
|
case (char)0x20:
|
|
case (char)0xA0:
|
|
return true;
|
|
default:
|
|
if (c >= 128)
|
|
return Char.IsWhiteSpace(c);
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static bool IsWhiteSpaceTrailer(char[] s, int i, int max){
|
|
for (; i < max; i++)
|
|
if (!IsWhiteSpace(s[i])) return false;
|
|
return true;
|
|
}
|
|
|
|
internal static Object LiteralToNumber(String str){
|
|
return Convert.LiteralToNumber(str, null);
|
|
}
|
|
|
|
internal static Object LiteralToNumber(String str, Context context){
|
|
//Called from the parser for integer literals
|
|
uint r = 10;
|
|
if (str[0] == '0' && str.Length > 1)
|
|
if (str[1] == 'x' || str[1] == 'X')
|
|
r = 16;
|
|
else
|
|
r = 8;
|
|
Object result = Convert.parseRadix(str.ToCharArray(), r, r == 16 ? 2 : 0, 1, false);
|
|
if (result != null){
|
|
if (r == 8 && context != null && result is Int32 && ((int)result) > 7)
|
|
context.HandleError(JSError.OctalLiteralsAreDeprecated);
|
|
return result;
|
|
}
|
|
context.HandleError(JSError.BadOctalLiteral);
|
|
return Convert.parseRadix(str.ToCharArray(), 10, 0, 1, false);
|
|
}
|
|
|
|
internal static bool NeedsWrapper(TypeCode code){
|
|
switch (code){
|
|
case TypeCode.Boolean:
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.Decimal:
|
|
case TypeCode.String: return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static double DoubleParse(String str){
|
|
try{
|
|
return Double.Parse(str, NumberStyles.Float, CultureInfo.InvariantCulture);
|
|
}catch(OverflowException){
|
|
int i = 0; int n = str.Length;
|
|
while (i < n && IsWhiteSpace(str[i])) i++;
|
|
if (i < n && str[i] == '-')
|
|
return Double.NegativeInfinity;
|
|
else
|
|
return Double.PositiveInfinity;
|
|
}
|
|
}
|
|
|
|
private static Object parseRadix(char[] s, uint rdx, int i, int sign, bool ignoreTrailers){
|
|
int max = s.Length;
|
|
if (i >= max) return null;
|
|
ulong multmax = (ulong)(UInt64.MaxValue / rdx);
|
|
int digit = RadixDigit(s[i], rdx);
|
|
if (digit < 0) return null;
|
|
ulong result = (ulong)digit;
|
|
int saved_i = i;
|
|
for (;;){
|
|
if (++i == max) goto returnAsInteger;
|
|
digit = RadixDigit(s[i], rdx);
|
|
if (digit < 0)
|
|
if (ignoreTrailers || IsWhiteSpaceTrailer(s, i, max))
|
|
goto returnAsInteger;
|
|
else
|
|
return null;
|
|
if (result > multmax) goto returnAsDouble;
|
|
unchecked{
|
|
ulong r1 = result * rdx;
|
|
ulong r2 = r1 + (ulong)digit;
|
|
if (r1 > r2) goto returnAsDouble;
|
|
result = r2;
|
|
}
|
|
}
|
|
|
|
returnAsInteger:
|
|
if (sign < 0){
|
|
if (result <= 2147483648) return (int)(-(long)result);
|
|
if (result < 9223372036854775808) return -(long)result;
|
|
if (result == 9223372036854775808) return -9223372036854775808;
|
|
return -(double)result;
|
|
}
|
|
if (result <= 2147483647) return (int)result;
|
|
if (result <= 9223372036854775807) return (long)result;
|
|
return result;
|
|
|
|
returnAsDouble:
|
|
//too long for a ulong. Try double. Be consistent with Double.FromString.
|
|
if (rdx == 10)
|
|
try{
|
|
double r = DoubleParse(new String(s, saved_i, max-saved_i));
|
|
if (r == r) return sign*r;
|
|
if (!ignoreTrailers) return null;
|
|
}catch(Exception){}
|
|
|
|
//Get here for string with trailers, or for radix other than 10
|
|
//continue accummulating, but with loss of precision. Not quite as good as Double.FromString, but simple.
|
|
double double_result = ((double)result)*rdx + digit;
|
|
for (;;){
|
|
if (++i == max) return sign*double_result;
|
|
digit = RadixDigit(s[i], rdx);
|
|
if (digit < 0)
|
|
if (ignoreTrailers || IsWhiteSpaceTrailer(s, i, max))
|
|
return sign*double_result;
|
|
else
|
|
return null;
|
|
double_result = double_result*rdx + digit;
|
|
}
|
|
}
|
|
|
|
private static int RadixDigit(char c, uint r){
|
|
int d;
|
|
if (c >= '0' && c <= '9')
|
|
d = ((int)c) - ((int)'0');
|
|
else if (c >= 'A' && c <= 'Z')
|
|
d = 10 + ((int)c) - ((int)'A');
|
|
else if (c >= 'a' && c <= 'z')
|
|
d = 10 + ((int)c) - ((int)'a');
|
|
else
|
|
return -1;
|
|
if (d >= r)
|
|
return -1;
|
|
else
|
|
return d;
|
|
}
|
|
|
|
#if !DEBUG
|
|
[DebuggerStepThroughAttribute]
|
|
[DebuggerHiddenAttribute]
|
|
#endif
|
|
public static void ThrowTypeMismatch(Object val){
|
|
throw new JScriptException(JSError.TypeMismatch, new Context(new DocumentContext("", null), val.ToString()));
|
|
}
|
|
|
|
public static bool ToBoolean(double d){
|
|
return d == d && d != 0;
|
|
}
|
|
|
|
#if !DEBUG
|
|
[DebuggerStepThroughAttribute]
|
|
[DebuggerHiddenAttribute]
|
|
#endif
|
|
public static bool ToBoolean(Object value){
|
|
if (value is Boolean) return (bool)value;
|
|
return Convert.ToBoolean(value, Convert.GetIConvertible(value));
|
|
}
|
|
|
|
#if !DEBUG
|
|
[DebuggerStepThroughAttribute]
|
|
[DebuggerHiddenAttribute]
|
|
#endif
|
|
public static bool ToBoolean(Object value, bool explicitConversion){
|
|
if (value is Boolean) return (bool)value;
|
|
if (!explicitConversion && value is BooleanObject) return ((BooleanObject)value).value;
|
|
return Convert.ToBoolean(value, Convert.GetIConvertible(value));
|
|
}
|
|
|
|
#if !DEBUG
|
|
[DebuggerStepThroughAttribute]
|
|
[DebuggerHiddenAttribute]
|
|
#endif
|
|
internal static bool ToBoolean(Object value, IConvertible ic){
|
|
switch (Convert.GetTypeCode(value, ic)){
|
|
case TypeCode.Empty: return false;
|
|
case TypeCode.Object:
|
|
if (value is Missing || value is System.Reflection.Missing) return false;
|
|
Type t = value.GetType();
|
|
MethodInfo meth = t.GetMethod("op_True", BindingFlags.ExactBinding|BindingFlags.Public|BindingFlags.Static, null, new Type[]{t}, null);
|
|
if (meth != null && (meth.Attributes & MethodAttributes.SpecialName) != 0 && meth.ReturnType == Typeob.Boolean){
|
|
meth = new JSMethodInfo(meth);
|
|
return (bool)meth.Invoke(null, BindingFlags.SuppressChangeType, null, new Object[]{value}, null);
|
|
}
|
|
return true;
|
|
case TypeCode.DBNull: return false;
|
|
case TypeCode.Boolean: return ic.ToBoolean(null);
|
|
case TypeCode.Char: return ic.ToChar(null) != (Char)0;
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32: return ic.ToInt32(null) != 0;
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64: return ic.ToInt64(null) != 0;
|
|
case TypeCode.UInt64: return ic.ToUInt64(null) != 0;
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
double d = ic.ToDouble(null);
|
|
if (d != d) return false; else return d != 0;
|
|
case TypeCode.Decimal: return ic.ToDecimal(null) != (Decimal)0;
|
|
case TypeCode.DateTime: return true;
|
|
case TypeCode.String: return ic.ToString(null).Length != 0;
|
|
}
|
|
return false; //should never get here
|
|
}
|
|
|
|
internal static char ToChar(Object value){
|
|
return (char)Convert.ToUint32(value);
|
|
}
|
|
|
|
private static char ToDigit(int digit) {
|
|
return digit < 10 ? (char)('0' + digit) : (char)('a' + digit - 10);
|
|
}
|
|
|
|
public static Object ToForInObject(Object value, VsaEngine engine){
|
|
if (value is ScriptObject) return value;
|
|
IConvertible ic = Convert.GetIConvertible(value);
|
|
switch (Convert.GetTypeCode(value, ic)){
|
|
case TypeCode.Boolean: return engine.Globals.globalObject.originalBoolean.ConstructImplicitWrapper(ic.ToBoolean(null));
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.Decimal: return engine.Globals.globalObject.originalNumber.ConstructImplicitWrapper(value);
|
|
case TypeCode.String: return engine.Globals.globalObject.originalString.ConstructImplicitWrapper(ic.ToString(null));
|
|
case TypeCode.DateTime: return value;
|
|
case TypeCode.Object:
|
|
return value;
|
|
}
|
|
return engine.Globals.globalObject.originalObject.ConstructObject();
|
|
}
|
|
|
|
internal static double ToInteger(double number) {
|
|
if (number != number)
|
|
return 0;
|
|
long r = (long)number;
|
|
if (r < 0 && number > 0)
|
|
return Int64.MaxValue;
|
|
return r;
|
|
}
|
|
|
|
internal static double ToInteger(Object value){
|
|
if (value is Double) return Convert.ToInteger((double)value);
|
|
if (value is Int32) return (double)(int)value;
|
|
return Convert.ToInteger(value, Convert.GetIConvertible(value));
|
|
}
|
|
|
|
internal static double ToInteger(Object value, IConvertible ic){
|
|
switch (Convert.GetTypeCode(value, ic)){
|
|
case TypeCode.Empty: return 0;
|
|
case TypeCode.DBNull: return 0;
|
|
case TypeCode.Boolean: return ic.ToBoolean(null) ? 1 : 0;
|
|
case TypeCode.Char: return (double)ic.ToChar(null);
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64: return ic.ToDouble(null);
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.Decimal: return Convert.ToInteger(ic.ToDouble(null));
|
|
case TypeCode.Object:
|
|
case TypeCode.DateTime:
|
|
Object pval = Convert.ToPrimitive(value, PreferredType.Number, ref ic);
|
|
if (pval != value)
|
|
return Convert.ToInteger(Convert.ToNumber(pval, ic));
|
|
else
|
|
return Double.NaN;
|
|
case TypeCode.String: return Convert.ToInteger(Convert.ToNumber(ic.ToString(null)));
|
|
}
|
|
return 0; //should never get here
|
|
}
|
|
|
|
public static int ToInt32(Object value){
|
|
if (value is Double) return (int)(double)value;
|
|
if (value is Int32) return (int)value;
|
|
return Convert.ToInt32(value, Convert.GetIConvertible(value));
|
|
}
|
|
|
|
internal static int ToInt32(Object value, IConvertible ic){
|
|
switch (Convert.GetTypeCode(value, ic)){
|
|
case TypeCode.Empty: return 0;
|
|
case TypeCode.DBNull: return 0;
|
|
case TypeCode.Boolean: return ic.ToBoolean(null) ? 1 : 0;
|
|
case TypeCode.Char: return (int)ic.ToChar(null);
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32: return ic.ToInt32(null);
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64: return (int)ic.ToInt64(null);
|
|
case TypeCode.UInt64: return (int)ic.ToUInt64(null);
|
|
case TypeCode.Single: return (int)ic.ToSingle(null);
|
|
case TypeCode.Double:
|
|
case TypeCode.Decimal: return (int)ic.ToDouble(null);
|
|
case TypeCode.Object:
|
|
case TypeCode.DateTime:
|
|
Object pval = Convert.ToPrimitive(value, PreferredType.Number, ref ic);
|
|
if (pval != value)
|
|
return Convert.ToInt32(pval, ic);
|
|
else
|
|
return 0;
|
|
case TypeCode.String: return (int)Convert.ToNumber(ic.ToString(null));
|
|
}
|
|
return 0; //should never get here.
|
|
}
|
|
|
|
internal static IReflect ToIReflect(Type t, VsaEngine engine){
|
|
GlobalObject glob = engine.Globals.globalObject;
|
|
Object result = t;
|
|
if (t == Typeob.ArrayObject)
|
|
result = glob.originalArray.Construct();
|
|
else if (t == Typeob.BooleanObject)
|
|
result = glob.originalBoolean.Construct();
|
|
else if (t == Typeob.DateObject)
|
|
result = glob.originalDate.Construct(new Object[0]);
|
|
else if (t == typeof(EnumeratorObject))
|
|
result = glob.originalEnumerator.Construct(new Object[0]);
|
|
else if (t == Typeob.ErrorObject)
|
|
result = glob.originalError.Construct(new Object[0]);
|
|
else if (t == typeof(EvalErrorObject))
|
|
result = glob.originalEvalError.Construct(new Object[0]);
|
|
else if (t == Typeob.JSObject)
|
|
result = glob.originalObject.Construct(new Object[0]);
|
|
else if (t == Typeob.NumberObject)
|
|
result = glob.originalNumber.Construct();
|
|
else if (t == typeof(RangeErrorObject))
|
|
result = glob.originalRangeError.Construct(new Object[0]);
|
|
else if (t == typeof(ReferenceErrorObject))
|
|
result = glob.originalReferenceError.Construct(new Object[0]);
|
|
else if (t == Typeob.RegExpObject)
|
|
result = glob.originalRegExp.Construct(new Object[0]);
|
|
else if (t == Typeob.ScriptFunction)
|
|
result = FunctionPrototype.ob;
|
|
else if (t == Typeob.StringObject)
|
|
result = glob.originalString.Construct();
|
|
else if (t == typeof(SyntaxErrorObject))
|
|
result = glob.originalSyntaxError.Construct(new Object[0]);
|
|
else if (t == typeof(TypeErrorObject))
|
|
result = glob.originalTypeError.Construct(new Object[0]);
|
|
else if (t == typeof(URIErrorObject))
|
|
result = glob.originalURIError.Construct(new Object[0]);
|
|
else if (t == typeof(VBArrayObject))
|
|
result = glob.originalVBArray.Construct();
|
|
else if (t == typeof(ArgumentsObject))
|
|
result = glob.originalObject.Construct(new Object[0]);
|
|
return (IReflect)result;
|
|
}
|
|
|
|
public static double ToNumber(Object value){
|
|
if (value is Int32) return (double)(int)value;
|
|
if (value is Double) return (double)value;
|
|
return Convert.ToNumber(value, Convert.GetIConvertible(value));
|
|
}
|
|
|
|
internal static double ToNumber(Object value, IConvertible ic){
|
|
switch (Convert.GetTypeCode(value, ic)){
|
|
case TypeCode.Empty: return Double.NaN;
|
|
case TypeCode.DBNull: return 0;
|
|
case TypeCode.Boolean: return ic.ToBoolean(null) ? 1 : 0;
|
|
case TypeCode.Char: return (double)ic.ToChar(null);
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32: return (double)ic.ToInt32(null);
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64: return (double)ic.ToInt64(null);
|
|
case TypeCode.UInt64: return (double)ic.ToUInt64(null);
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.Decimal: return ic.ToDouble(null);
|
|
case TypeCode.Object:
|
|
case TypeCode.DateTime:
|
|
Object pval = Convert.ToPrimitive(value, PreferredType.Number, ref ic);
|
|
if (pval != value)
|
|
return Convert.ToNumber(pval, ic);
|
|
else
|
|
return Double.NaN;
|
|
case TypeCode.String: return Convert.ToNumber(ic.ToString(null));
|
|
}
|
|
return 0; //should never get here
|
|
}
|
|
|
|
public static double ToNumber(String str){
|
|
return Convert.ToNumber(str, true, false, Missing.Value);
|
|
}
|
|
|
|
internal static double ToNumber(String str, bool hexOK, bool octalOK, Object radix){
|
|
//Called from ToNumber, GlobalObject.parseFloat, GlobalObject.parseInt and from the parser for floating point literals
|
|
//ToNumber, parseFloat and parseInt each have their own pecularities when it comes to leading whitespace, trailing characters, signs and hex/octal.
|
|
//For ToNumber: hexOK = true, octalOK = false
|
|
//For parseFloat: hexOK = false, octalOK = false
|
|
//For parseInt: hexOK = true, octalOK = true and radix might be supplied,
|
|
//For floating point literals: hexOK = false, octalOK = false
|
|
|
|
if (!octalOK){ //only parseInt will set octalOK. Integers can always be converted without COM+ help
|
|
try{
|
|
double d = DoubleParse(str); //This should work (and be fastest) for the common case
|
|
if (d != 0) return d;
|
|
int i = 0, n = str.Length;
|
|
while (i < n && IsWhiteSpace(str[i])) i++;
|
|
if (i < n && str[i] == '-')
|
|
return (double)(-0.0);
|
|
else
|
|
return (double)0;
|
|
}catch{
|
|
//We might get here if there are trailing characters in the string that should be ignored.
|
|
//parseFloat ignores leading whitespace and any trailing characters which do not form part of a StrDecimalLiteral
|
|
//ToNumber ignores leading and trailing whitespace, but not other trailing characters
|
|
//We should never get here if called from the parser for a floating point literal (COM+ should always work for those).
|
|
int n = str.Length;
|
|
int j = n-1;
|
|
int i = 0;
|
|
//skip leading whitespace
|
|
while (i < n && IsWhiteSpace(str[i])) i++;
|
|
if (hexOK){ //The ToNumber case.
|
|
//Double.FromString might have failed because of trailing whitespace, or because this is a hexadecimal literal.
|
|
while (j >= i && IsWhiteSpace(str[j])) j--; //Strip any trailing whitespace
|
|
if (i > j) //String empty or all whitespace
|
|
return (double)0;
|
|
if (j < n-1) //Had some trailing whitespace, try COM+ again
|
|
return Convert.ToNumber(str.Substring(i, j-i+1), hexOK, octalOK, radix);
|
|
//otherwise drop through and try to parse the number as a hex literal
|
|
}else{ //The parseFloat case: all trailers are ignored. Prefix starting at i must match StrDecimalLiteral
|
|
//Might be "Infinity"
|
|
if (n-i >= 8 && String.CompareOrdinal(str, i, "Infinity", 0, 8) == 0)
|
|
return Double.PositiveInfinity;
|
|
else if (n-i >= 9 && String.CompareOrdinal(str, i, "-Infinity", 0, 8) == 0)
|
|
return Double.NegativeInfinity;
|
|
else if (n-i >= 9 && String.CompareOrdinal(str, i, "+Infinity", 0, 8) == 0)
|
|
return Double.PositiveInfinity;
|
|
//Reduce string length until last character is a decimal digit or '.'
|
|
char ch;
|
|
//If the last character is a digit there could be noise further upstream. First skip over trailing digits
|
|
while (j >= i){
|
|
ch = str[j];
|
|
if (!JSScanner.IsDigit(ch)) break;
|
|
j--;
|
|
}
|
|
while (j >= i){
|
|
ch = str[j];
|
|
if (JSScanner.IsDigit(ch)) break;
|
|
j--;
|
|
}
|
|
if (j < n-1) //Had some trailing noise, try COM+ again
|
|
return Convert.ToNumber(str.Substring(i, j-i+1), hexOK, octalOK, radix);
|
|
//Whatever is left in str does not parse to a double, give up and return NaN.
|
|
return Double.NaN;
|
|
}
|
|
}
|
|
}
|
|
//if we get here, we are dealing with an integer, or we might be dealing with (+|-)Infinity
|
|
//Never get here for parseFloat or floating point literals from the parser.
|
|
//For parseInt Only the prefix matters. Trailing characters (those that can not form part of an integer literal) are ignored.
|
|
//For ToNumber, any trailing characters must be whitespace.
|
|
{
|
|
int n = str.Length;
|
|
int i = 0;
|
|
//skip leading whitespace
|
|
while (i < n && IsWhiteSpace(str[i])) i++;
|
|
if (i >= n)
|
|
if (hexOK && octalOK)
|
|
return double.NaN; //parseInt case
|
|
else
|
|
return (double)0; //ToNumber case
|
|
int sign = 1;
|
|
bool explicitSign = false;
|
|
if (str[i] == '-'){
|
|
sign = -1; i++; explicitSign = true;
|
|
}else if (str[i] == '+'){
|
|
i++; explicitSign = true;
|
|
}
|
|
while (i < n && IsWhiteSpace(str[i])) i++;
|
|
bool radixMissing = radix == null || radix is Missing;
|
|
if (i+8 <= n && radixMissing && !octalOK && str.Substring(i, 8).Equals("Infinity"))
|
|
return sign > 0 ? Double.PositiveInfinity : Double.NegativeInfinity;
|
|
int r = 10;
|
|
if (!radixMissing)
|
|
r = Convert.ToInt32(radix);
|
|
if (r == 0){
|
|
radixMissing = true;
|
|
r = 10;
|
|
}else if (r < 2 || r > 36)
|
|
return Double.NaN;
|
|
if (i < n-2 && str[i] == '0')
|
|
if (str[i+1] == 'x' || str[i+1] == 'X'){
|
|
if (!hexOK)
|
|
return 0;
|
|
if (explicitSign && !octalOK) //ToNumber case
|
|
return Double.NaN;
|
|
if (radixMissing){
|
|
r = 16; i += 2;
|
|
}else if (r == 16)
|
|
i += 2;
|
|
}else if (octalOK && radixMissing)
|
|
r = 8;
|
|
if (i < n)
|
|
return Convert.ToNumber(Convert.parseRadix(str.ToCharArray(), (uint)r, i, sign, hexOK && octalOK));
|
|
else
|
|
return Double.NaN;
|
|
}
|
|
}
|
|
|
|
internal static String ToLocaleString(Object value){
|
|
return Convert.ToString(value, PreferredType.LocaleString, true);
|
|
}
|
|
|
|
public static Object ToNativeArray(Object value, RuntimeTypeHandle handle){
|
|
if (value is ArrayObject){
|
|
Type elementType = Type.GetTypeFromHandle(handle);
|
|
return ((ArrayObject)value).ToNativeArray(elementType);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
public static Object ToObject(Object value, VsaEngine engine){
|
|
if (value is ScriptObject) return value;
|
|
String str = value as String;
|
|
if (str != null) return engine.Globals.globalObject.originalString.ConstructImplicitWrapper(str);
|
|
IConvertible ic = Convert.GetIConvertible(value);
|
|
switch (Convert.GetTypeCode(value, ic)){
|
|
case TypeCode.Boolean: return engine.Globals.globalObject.originalBoolean.ConstructImplicitWrapper(ic.ToBoolean(null));
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.Decimal: return engine.Globals.globalObject.originalNumber.ConstructImplicitWrapper(value);
|
|
case TypeCode.String: return engine.Globals.globalObject.originalString.ConstructImplicitWrapper(ic.ToString(null));
|
|
case TypeCode.DateTime: return ic.ToDateTime(null);
|
|
case TypeCode.Object:
|
|
if (value is Array)
|
|
return engine.Globals.globalObject.originalArray.ConstructImplicitWrapper((Array)value);
|
|
else
|
|
return value;
|
|
}
|
|
throw new JScriptException(JSError.NeedObject);
|
|
}
|
|
|
|
public static Object ToObject2(Object value, VsaEngine engine){
|
|
if (value is ScriptObject) return value;
|
|
IConvertible ic = Convert.GetIConvertible(value);
|
|
switch (Convert.GetTypeCode(value, ic)){
|
|
case TypeCode.Boolean: return engine.Globals.globalObject.originalBoolean.ConstructImplicitWrapper(ic.ToBoolean(null));
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.Decimal: return engine.Globals.globalObject.originalNumber.ConstructImplicitWrapper(value);
|
|
case TypeCode.String: return engine.Globals.globalObject.originalString.ConstructImplicitWrapper(ic.ToString(null));
|
|
case TypeCode.DateTime: return ic.ToDateTime(null);
|
|
case TypeCode.Object:
|
|
if (value is Array)
|
|
return engine.Globals.globalObject.originalArray.ConstructImplicitWrapper((Array)value);
|
|
else
|
|
return value;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
internal static Object ToObject3(Object value, VsaEngine engine){
|
|
if (value is ScriptObject) return value;
|
|
IConvertible ic = Convert.GetIConvertible(value);
|
|
switch (Convert.GetTypeCode(value, ic)){
|
|
case TypeCode.Boolean: return engine.Globals.globalObject.originalBoolean.ConstructWrapper(ic.ToBoolean(null));
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double:
|
|
case TypeCode.Decimal: return engine.Globals.globalObject.originalNumber.ConstructWrapper(value);
|
|
case TypeCode.String: return engine.Globals.globalObject.originalString.ConstructWrapper(ic.ToString(null));
|
|
case TypeCode.DateTime: return ic.ToDateTime(null);
|
|
case TypeCode.Object:
|
|
if (value is Array)
|
|
return engine.Globals.globalObject.originalArray.ConstructWrapper((Array)value);
|
|
else
|
|
return value;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
#if !DEBUG
|
|
[DebuggerStepThroughAttribute]
|
|
[DebuggerHiddenAttribute]
|
|
#endif
|
|
internal static Object ToPrimitive(Object value, PreferredType preferredType){
|
|
IConvertible ic = Convert.GetIConvertible(value);
|
|
TypeCode tcode = Convert.GetTypeCode(value, ic);
|
|
return Convert.ToPrimitive(value, preferredType, ic, tcode);
|
|
}
|
|
|
|
#if !DEBUG
|
|
[DebuggerStepThroughAttribute]
|
|
[DebuggerHiddenAttribute]
|
|
#endif
|
|
internal static Object ToPrimitive(Object value, PreferredType preferredType, ref IConvertible ic){
|
|
TypeCode tcode = Convert.GetTypeCode(value, ic);
|
|
switch (tcode){
|
|
case TypeCode.Object:
|
|
case TypeCode.DateTime:
|
|
Object result = Convert.ToPrimitive(value, preferredType, ic, tcode);
|
|
if (result != value){
|
|
value = result;
|
|
ic = Convert.GetIConvertible(value);
|
|
}
|
|
break;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
|
|
#if !DEBUG
|
|
[DebuggerStepThroughAttribute]
|
|
[DebuggerHiddenAttribute]
|
|
#endif
|
|
private static Object ToPrimitive(Object value, PreferredType preferredType, IConvertible ic, TypeCode tcode){
|
|
switch (tcode){
|
|
case TypeCode.Object:
|
|
System.Array arr = value as System.Array;
|
|
if (arr != null && arr.Rank == 1) value = new ArrayWrapper(ArrayPrototype.ob, arr, true);
|
|
if (value is ScriptObject){
|
|
Object result = ((ScriptObject)value).GetDefaultValue(preferredType);
|
|
if (Convert.GetTypeCode(result) != TypeCode.Object)
|
|
return result;
|
|
else if (value == result && preferredType == PreferredType.String || preferredType == PreferredType.LocaleString){
|
|
if (value is JSObject){
|
|
ScriptObject proto = ((JSObject)value).GetParent();
|
|
if (proto is ClassScope)
|
|
return ((ClassScope)proto).GetFullName();
|
|
return "[object Object]";
|
|
}
|
|
return value.ToString();
|
|
}else
|
|
throw new JScriptException(JSError.TypeMismatch);
|
|
}else if (value is Missing || value is System.Reflection.Missing)
|
|
return null;
|
|
else{
|
|
IReflect ir;
|
|
if (value is IReflect && !(value is Type))
|
|
ir = (IReflect)value;
|
|
else
|
|
ir = value.GetType();
|
|
|
|
//Look for an op_Explicit conversion to String or Double (this always fails for IDispatch/Ex objects
|
|
MethodInfo meth = null;
|
|
if (preferredType == PreferredType.String || preferredType == PreferredType.LocaleString)
|
|
meth = Convert.GetToXXXXMethod(ir, Typeob.String, true);
|
|
else{
|
|
meth = Convert.GetToXXXXMethod(ir, Typeob.Double, true);
|
|
if (meth == null)
|
|
meth = Convert.GetToXXXXMethod(ir, Typeob.Int64, true);
|
|
if (meth == null)
|
|
meth = Convert.GetToXXXXMethod(ir, Typeob.UInt64, true);
|
|
}
|
|
if (meth != null){
|
|
meth = new JSMethodInfo(meth);
|
|
return meth.Invoke(null, BindingFlags.SuppressChangeType, null, new Object[]{value}, null);
|
|
}
|
|
|
|
//Invoke the default method/property or get the value of the default field. If an exception is thrown
|
|
//because the target doesn't have a non-paramterized default member, mask it and execute the
|
|
//default handling.
|
|
try{
|
|
try{
|
|
MemberInfo member = LateBinding.SelectMember(JSBinder.GetDefaultMembers(ir));
|
|
if (member != null){
|
|
switch(member.MemberType){
|
|
case MemberTypes.Field: return ((FieldInfo)member).GetValue(value);
|
|
case MemberTypes.Method: return ((MethodInfo)member).Invoke(value, new Object[0]);
|
|
case MemberTypes.Property: return JSProperty.GetValue((PropertyInfo)member, value, null);
|
|
case MemberTypes.Event: return null;
|
|
case MemberTypes.NestedType: return member;
|
|
}
|
|
}
|
|
|
|
|
|
return ir.InvokeMember(String.Empty, BindingFlags.ExactBinding|BindingFlags.SuppressChangeType|
|
|
BindingFlags.InvokeMethod|BindingFlags.GetProperty|BindingFlags.GetField,
|
|
null, value, new Object[0], null, null, new String[0]);
|
|
}catch(TargetInvocationException e){
|
|
throw e.InnerException;
|
|
}
|
|
}catch(ArgumentException){
|
|
}catch(IndexOutOfRangeException){
|
|
}catch(MissingMemberException){
|
|
}catch(TargetParameterCountException){
|
|
}
|
|
|
|
if (preferredType != PreferredType.Number)
|
|
if (value is Char[])
|
|
return new System.String((Char[])value);
|
|
else
|
|
return value.ToString();
|
|
return value;
|
|
}
|
|
case TypeCode.DateTime:
|
|
return DateConstructor.ob.Construct(ic.ToDateTime(null)).GetDefaultValue(preferredType);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
internal static String ToString(Object value){
|
|
return Convert.ToString(value, PreferredType.String, true);
|
|
}
|
|
|
|
#if !DEBUG
|
|
[DebuggerStepThroughAttribute]
|
|
[DebuggerHiddenAttribute]
|
|
#endif
|
|
public static String ToString(Object value, bool explicitOK){
|
|
return Convert.ToString(value, PreferredType.String, explicitOK);
|
|
}
|
|
|
|
#if !DEBUG
|
|
[DebuggerStepThroughAttribute]
|
|
[DebuggerHiddenAttribute]
|
|
#endif
|
|
internal static String ToString(Object value, IConvertible ic){
|
|
return Convert.ToString(value, PreferredType.String, ic, true);
|
|
}
|
|
|
|
#if !DEBUG
|
|
[DebuggerStepThroughAttribute]
|
|
[DebuggerHiddenAttribute]
|
|
#endif
|
|
internal static String ToString(Object value, PreferredType pref, bool explicitOK){
|
|
String str = value as String;
|
|
if (str != null) return str;
|
|
StringObject strObj = value as StringObject;
|
|
if (strObj != null && strObj.noExpando) return strObj.value;
|
|
return Convert.ToString(value, pref, Convert.GetIConvertible(value), explicitOK);
|
|
}
|
|
|
|
#if !DEBUG
|
|
[DebuggerStepThroughAttribute]
|
|
[DebuggerHiddenAttribute]
|
|
#endif
|
|
internal static String ToString(Object value, PreferredType pref, IConvertible ic, bool explicitOK){
|
|
Enum e = value as Enum;
|
|
if (e != null) return e.ToString("G");
|
|
EnumWrapper ew = value as EnumWrapper;
|
|
if (ew != null) return ew.ToString();
|
|
TypeCode code = Convert.GetTypeCode(value, ic);
|
|
if (pref == PreferredType.LocaleString){
|
|
switch (code){
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Single:
|
|
case TypeCode.Double: {
|
|
double d = ic.ToDouble(null);
|
|
return d.ToString(d <= -1e+15 || d >= 1e+15 ? "g" : "n", NumberFormatInfo.CurrentInfo);
|
|
}
|
|
case TypeCode.Int64: return ic.ToInt64(null).ToString("n", NumberFormatInfo.CurrentInfo);
|
|
case TypeCode.UInt64: return ic.ToUInt64(null).ToString("n", NumberFormatInfo.CurrentInfo);
|
|
case TypeCode.Decimal: return ic.ToDecimal(null).ToString("n", NumberFormatInfo.CurrentInfo);
|
|
}
|
|
}
|
|
switch (code){
|
|
case TypeCode.Empty: return explicitOK ? "undefined" : null;
|
|
case TypeCode.Object: return Convert.ToString(Convert.ToPrimitive(value, pref, ref ic), ic);
|
|
case TypeCode.DBNull: return explicitOK ? "null" : null;
|
|
case TypeCode.Boolean: return ic.ToBoolean(null) ? "true" : "false";
|
|
case TypeCode.Char:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Byte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
case TypeCode.Decimal:
|
|
case TypeCode.String: return ic.ToString(null);
|
|
case TypeCode.DateTime: return Convert.ToString(DateConstructor.ob.Construct(ic.ToDateTime(null)));
|
|
case TypeCode.Single:
|
|
case TypeCode.Double: return Convert.ToString(ic.ToDouble(null));
|
|
}
|
|
return null; //Should never get here
|
|
}
|
|
|
|
public static String ToString(bool b){
|
|
return b ? "true" : "false";
|
|
}
|
|
|
|
public static String ToString(double d){
|
|
long i = (long)d;
|
|
if ((double)i == d){
|
|
return i.ToString();
|
|
}else if (d != d)
|
|
return "NaN";
|
|
else if (Double.IsPositiveInfinity(d))
|
|
return "Infinity";
|
|
else if (Double.IsNegativeInfinity(d))
|
|
return "-Infinity";
|
|
else{
|
|
double e = d < 0 ? -d : d;
|
|
int k = 15;
|
|
String result = e.ToString("e14", CultureInfo.InvariantCulture);
|
|
if (DoubleParse(result) != e){
|
|
result = e.ToString("e15", CultureInfo.InvariantCulture);
|
|
k = 16;
|
|
if (DoubleParse(result) != e){
|
|
result = e.ToString("e16", CultureInfo.InvariantCulture);
|
|
k = 17;
|
|
if (DoubleParse(result) != e){
|
|
result = e.ToString("e17", CultureInfo.InvariantCulture);
|
|
k = 18;
|
|
}
|
|
}
|
|
}
|
|
int exp = Int32.Parse(result.Substring(k+2, result.Length-(k+2)), CultureInfo.InvariantCulture);
|
|
while (result[k] == '0') k--; //at the end of the loop, k == the number of significant digits
|
|
int n = exp + 1;
|
|
if (k <= n && n <= 21){
|
|
StringBuilder r = new StringBuilder(n+1);
|
|
if (d < 0)
|
|
r.Append('-');
|
|
r.Append(result[0]);
|
|
if (k > 1)
|
|
r.Append(result, 2, k-1);
|
|
if (exp-k >= 0)
|
|
r.Append('0', n-k);
|
|
return r.ToString();
|
|
}
|
|
if (0 < n && n <= 21){
|
|
StringBuilder r = new StringBuilder(k+2);
|
|
if (d < 0)
|
|
r.Append('-');
|
|
r.Append(result[0]);
|
|
if (n > 1)
|
|
r.Append(result, 2, n-1);
|
|
r.Append('.');
|
|
r.Append(result, n+1, k-n);
|
|
return r.ToString();
|
|
}
|
|
if (-6 < n && n <= 0){
|
|
StringBuilder r = new StringBuilder(2-n);
|
|
if (d < 0)
|
|
r.Append("-0.");
|
|
else
|
|
r.Append("0.");
|
|
if (n < 0)
|
|
r.Append('0', -n);
|
|
r.Append(result[0]);
|
|
r.Append(result, 2, k-1);
|
|
return r.ToString();
|
|
}
|
|
{
|
|
StringBuilder r = new StringBuilder(28);
|
|
if (d < 0)
|
|
r.Append('-');
|
|
r.Append(result.Substring(0, k == 1 ? 1 : k+1));
|
|
r.Append('e');
|
|
if (exp >= 0)
|
|
r.Append('+');
|
|
r.Append(exp);
|
|
return r.ToString();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static int[] rgcchSig = new int[] {
|
|
53, 34, 27, 24, 22, 20, 19, 18, 17, 17, 16, 16,
|
|
15, 15, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13,
|
|
13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 };
|
|
|
|
internal static String ToString(Object value, int radix) {
|
|
if (radix == 10 || radix < 2 || radix > 36)
|
|
return Convert.ToString(value);
|
|
double dbl = Convert.ToNumber(value);
|
|
if (dbl == 0.0)
|
|
return "0";
|
|
if (Double.IsNaN(dbl))
|
|
return "NaN";
|
|
if (Double.IsPositiveInfinity(dbl))
|
|
return "Infinity";
|
|
if (Double.IsNegativeInfinity(dbl))
|
|
return "-Infinity";
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
if (dbl < 0.0) {
|
|
sb.Append('-');
|
|
dbl = -dbl;
|
|
}
|
|
int cchMax = rgcchSig[radix - 2];
|
|
|
|
if (dbl < 8.67361737988403547206e-19 || dbl >= 2305843009213693952.0) {
|
|
// Exponential notation
|
|
|
|
int wExp = (int)Math.Log(dbl, radix) + 1;
|
|
double dblT = Math.Pow(radix, wExp);
|
|
if (Double.IsPositiveInfinity(dblT))
|
|
dblT = Math.Pow(radix, --wExp);
|
|
else if (dblT == 0.0)
|
|
dblT = Math.Pow(radix, ++wExp);
|
|
dbl /= dblT;
|
|
while (dbl < 1.0) {
|
|
dbl *= radix;
|
|
wExp--;
|
|
}
|
|
|
|
int wDig = (int)dbl;
|
|
sb.Append(Convert.ToDigit(wDig));
|
|
cchMax--;
|
|
dbl -= wDig;
|
|
|
|
if (dbl != 0.0) {
|
|
sb.Append('.');
|
|
while (dbl != 0.0 && cchMax-- > 0) {
|
|
dbl *= radix;
|
|
wDig = (int)dbl;
|
|
if (wDig >= radix)
|
|
wDig = radix - 1;
|
|
sb.Append(Convert.ToDigit(wDig));
|
|
dbl -= wDig;
|
|
}
|
|
}
|
|
|
|
sb.Append((wExp >= 0 ? "(e+" : "(e"));
|
|
sb.Append(wExp.ToString());
|
|
sb.Append(')');
|
|
|
|
} else {
|
|
// Regular notation
|
|
|
|
int wDig, cchSig;
|
|
if (dbl >= 1.0) {
|
|
// Integral portion
|
|
|
|
double dblDen, dblT;
|
|
cchSig = 1;
|
|
for (dblDen = 1.0; (dblT = dblDen * radix) <= dbl; dblDen = dblT)
|
|
cchSig++;
|
|
|
|
for (int cch = 0; cch < cchSig; cch++) {
|
|
wDig = (int)(dbl / dblDen);
|
|
if (wDig >= radix)
|
|
wDig = radix - 1;
|
|
sb.Append(Convert.ToDigit(wDig));
|
|
dbl -= wDig * dblDen;
|
|
dblDen /= radix;
|
|
}
|
|
} else {
|
|
sb.Append('0');
|
|
cchSig = 0;
|
|
}
|
|
|
|
if (dbl != 0.0 && cchSig < cchMax) {
|
|
// Fractional portion
|
|
|
|
sb.Append('.');
|
|
while (dbl != 0.0 && cchSig < cchMax) {
|
|
dbl *= radix;
|
|
wDig = (int)dbl;
|
|
if (wDig >= radix)
|
|
wDig = radix - 1;
|
|
sb.Append(Convert.ToDigit(wDig));
|
|
dbl -= wDig;
|
|
if (wDig != 0 || cchSig != 0)
|
|
cchSig++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
internal static Type ToType(IReflect ir){
|
|
if (ir is Type)
|
|
return (Type)ir;
|
|
if (ir is ClassScope)
|
|
return ((ClassScope)ir).GetTypeBuilderOrEnumBuilder();
|
|
if (ir is TypedArray){
|
|
return ((TypedArray)ir).ToType();
|
|
}
|
|
if (ir is ScriptFunction)
|
|
return Typeob.ScriptFunction;
|
|
return ir.GetType();
|
|
}
|
|
|
|
internal static Type ToType(String descriptor, Type elementType){
|
|
Module mod = elementType.Module;
|
|
if (mod is ModuleBuilder)
|
|
return mod.GetType(elementType.FullName+descriptor);
|
|
else
|
|
return mod.Assembly.GetType(elementType.FullName+descriptor);
|
|
}
|
|
|
|
internal static String ToTypeName(IReflect ir){
|
|
if (ir is ClassScope)
|
|
return ((ClassScope)ir).GetName();
|
|
else if (ir is JSObject)
|
|
return ((JSObject)ir).GetClassName();
|
|
else if (ir is GlobalScope)
|
|
return "Global Object";
|
|
else{
|
|
Debug.Assert(ir is Type || ir is TypedArray);
|
|
return ir.ToString();
|
|
}
|
|
}
|
|
|
|
internal static uint ToUint32(Object value){
|
|
if (value is UInt32) return (uint)value;
|
|
return Convert.ToUint32(value, Convert.GetIConvertible(value));
|
|
}
|
|
|
|
internal static uint ToUint32(Object value, IConvertible ic){
|
|
switch (Convert.GetTypeCode(value, ic)){
|
|
case TypeCode.Empty: return 0;
|
|
case TypeCode.DBNull: return 0;
|
|
case TypeCode.Boolean: return ic.ToBoolean(null) ? (uint)1 : (uint)0;
|
|
case TypeCode.Char: return (uint)ic.ToChar(null);
|
|
case TypeCode.Byte:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.UInt32: return ic.ToUInt32(null);
|
|
case TypeCode.UInt64: return (uint)ic.ToUInt64(null);
|
|
case TypeCode.SByte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.Int64: return (uint)ic.ToInt64(null);
|
|
case TypeCode.Single: return (uint)ic.ToSingle(null);
|
|
case TypeCode.Double:
|
|
case TypeCode.Decimal: return (uint)ic.ToDouble(null);
|
|
case TypeCode.Object:
|
|
case TypeCode.DateTime:
|
|
Object pval = Convert.ToPrimitive(value, PreferredType.Number, ref ic);
|
|
if (pval != value)
|
|
return Convert.ToUint32(pval, ic);
|
|
else
|
|
return 0;
|
|
case TypeCode.String: return (uint)Convert.ToNumber(ic.ToString(null));
|
|
}
|
|
return 0; //should never get here
|
|
}
|
|
|
|
}
|
|
}
|