From 70a2a36436b48fc894eeb0242c3addee1a690b5d Mon Sep 17 00:00:00 2001 From: objmalloc Date: Mon, 28 May 2018 10:40:51 +0300 Subject: [PATCH 1/3] DateTime, Byte, ClrInstanceWrapper, object conversions --- Jurassic/Core/TypeConverter.cs | 14 +++++++++++++- Jurassic/Library/Date/DateConstructor.cs | 9 +++++++++ Jurassic/Library/Date/DateInstance.cs | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Jurassic/Core/TypeConverter.cs b/Jurassic/Core/TypeConverter.cs index 070bdaef..5608d29c 100644 --- a/Jurassic/Core/TypeConverter.cs +++ b/Jurassic/Core/TypeConverter.cs @@ -80,6 +80,8 @@ public static bool ToBoolean(object value) return false; if (value is bool) return (bool)value; + if (value is byte) + return ((byte)value) != 0; if (value is int) return ((int)value) != 0; if (value is uint) @@ -90,7 +92,7 @@ public static bool ToBoolean(object value) return ((string)value).Length > 0; if (value is ConcatenatedString) return ((ConcatenatedString)value).Length > 0; - if (value is ObjectInstance) + if (value is Object && !(value is DBNull)) // All non null objects, except DBNull are converted to true return true; throw new ArgumentException(string.Format("Cannot convert object of type '{0}' to a boolean.", value.GetType()), nameof(value)); } @@ -104,6 +106,8 @@ public static double ToNumber(object value) { if (value is double) return (double)value; + if (value is byte) + return (double)(byte)value; if (value is int) return (double)(int)value; if (value is uint) @@ -146,6 +150,8 @@ public static string ToString(object value) return "null"; if (value is bool) return (bool)value ? "true" : "false"; + if (value is byte) + return ((byte)value).ToString(); if (value is int) return ((int)value).ToString(); if (value is uint) @@ -224,6 +230,8 @@ public static ObjectInstance ToObject(ScriptEngine engine, object value, int lin ObjectInstance result; if (value is bool) result = engine.Boolean.Construct((bool)value); + else if (value is byte) + result = engine.Number.Construct((byte)value); else if (value is int) result = engine.Number.Construct((int)value); else if (value is uint) @@ -234,6 +242,10 @@ public static ObjectInstance ToObject(ScriptEngine engine, object value, int lin result = engine.String.Construct((string)value); else if (value is ConcatenatedString) result = engine.String.Construct(value.ToString()); + else if (value is DateTime) + result = engine.Date.Construct((DateTime)value); + else if (value is object && engine.EnableExposedClrTypes) + result = new ClrInstanceWrapper(engine, value); else throw new ArgumentException(string.Format("Cannot convert object of type '{0}' to an object.", value.GetType()), nameof(value)); result.IsExtensible = false; diff --git a/Jurassic/Library/Date/DateConstructor.cs b/Jurassic/Library/Date/DateConstructor.cs index 2c2d6b8f..f95babe2 100644 --- a/Jurassic/Library/Date/DateConstructor.cs +++ b/Jurassic/Library/Date/DateConstructor.cs @@ -67,6 +67,15 @@ public DateInstance Construct(string dateStr) return new DateInstance(this.InstancePrototype, dateStr); } + /// + /// Creates a new Date object from a DateTime. + /// + /// A regular DateTime + public DateInstance Construct(DateTime date) + { + return new DateInstance(this.InstancePrototype, date); + } + /// /// Creates a new Date object from various date components, expressed in local time. /// diff --git a/Jurassic/Library/Date/DateInstance.cs b/Jurassic/Library/Date/DateInstance.cs index 11e77436..5dbd70f1 100644 --- a/Jurassic/Library/Date/DateInstance.cs +++ b/Jurassic/Library/Date/DateInstance.cs @@ -80,7 +80,7 @@ public DateInstance(ObjectInstance prototype, int year, int month, int day = 1, /// /// The next object in the prototype chain. /// The date to set the instance value to. - private DateInstance(ObjectInstance prototype, DateTime dateTime) + public DateInstance(ObjectInstance prototype, DateTime dateTime) : base(prototype) { this.value = dateTime; From 626a9187d1d1b9cd17d886d5c81649acfe08290c Mon Sep 17 00:00:00 2001 From: objmalloc Date: Wed, 21 Nov 2018 11:17:48 +0200 Subject: [PATCH 2/3] Support of all numeric types and Enum --- Jurassic/Core/TypeComparer.cs | 156 +++++++++++++++++++++++++++++++++ Jurassic/Core/TypeConverter.cs | 72 ++++++++++++++- Jurassic/Core/TypeUtilities.cs | 32 +++++-- 3 files changed, 254 insertions(+), 6 deletions(-) diff --git a/Jurassic/Core/TypeComparer.cs b/Jurassic/Core/TypeComparer.cs index 989591dc..82187169 100644 --- a/Jurassic/Core/TypeComparer.cs +++ b/Jurassic/Core/TypeComparer.cs @@ -20,14 +20,54 @@ public static class TypeComparer { x = x ?? Undefined.Value; y = y ?? Undefined.Value; + if (x is sbyte) + x = (double)(sbyte)x; + if (x is byte) + x = (double)(byte)x; + if (x is char) + x = (double)(char)x; + if (x is short) + x = (double)(short)x; + if (x is ushort) + x = (double)(ushort)x; if (x is int) x = (double)(int)x; if (x is uint) x = (double)(uint)x; + if (x is long) + x = (double)(long)x; + if (x is ulong) + x = (double)(ulong)x; + if (x is Enum) + x = (double)(int)x; + if (x is float) + x = (double)(float)x; + if (x is decimal) + x = decimal.ToDouble((decimal)x); + if (y is sbyte) + y = (double)(sbyte)y; + if (y is byte) + y = (double)(byte)y; + if (y is char) + y = (double)(char)y; + if (y is short) + y = (double)(short)y; + if (y is ushort) + y = (double)(ushort)y; if (y is int) y = (double)(int)y; if (y is uint) y = (double)(uint)y; + if (y is long) + y = (double)(long)y; + if (y is ulong) + y = (double)(ulong)y; + if (y is Enum) + y = (double)(int)y; + if (y is float) + y = (double)(float)y; + if (y is decimal) + y = decimal.ToDouble((decimal)y); if (x is ConcatenatedString) x = x.ToString(); if (y is ConcatenatedString) @@ -81,14 +121,50 @@ public static bool StrictEquals(object x, object y) { x = x ?? Undefined.Value; y = y ?? Undefined.Value; + if (x is sbyte) + x = (double)(sbyte)x; + if (x is byte) + x = (double)(byte)x; + if (x is char) + x = (double)(char)x; + if (x is short) + x = (double)(short)x; + if (x is ushort) + x = (double)(ushort)x; if (x is int) x = (double)(int)x; if (x is uint) x = (double)(uint)x; + if (x is long) + x = (double)(long)x; + if (x is ulong) + x = (double)(ulong)x; + if (x is float) + x = (double)(float)x; + if (x is decimal) + x = decimal.ToDouble((decimal)x); + if (y is sbyte) + y = (double)(sbyte)y; + if (y is byte) + y = (double)(byte)y; + if (y is char) + y = (double)(char)y; + if (y is short) + y = (double)(short)y; + if (y is ushort) + y = (double)(ushort)y; if (y is int) y = (double)(int)y; if (y is uint) y = (double)(uint)y; + if (y is long) + y = (double)(long)y; + if (y is ulong) + y = (double)(ulong)y; + if (y is float) + y = (double)(float)y; + if (y is decimal) + y = decimal.ToDouble((decimal)y); if (x is double && double.IsNaN((double)x) == true) return false; if (x is ConcatenatedString) @@ -224,14 +300,54 @@ public static bool SameValue(object x, object y) x = Undefined.Value; if (y == null) y = Undefined.Value; + if (x is sbyte) + x = (double)(sbyte)x; + if (x is byte) + x = (double)(byte)x; + if (x is char) + x = (double)(char)x; + if (x is short) + x = (double)(short)x; + if (x is ushort) + x = (double)(ushort)x; if (x is int) x = (double)(int)x; if (x is uint) x = (double)(uint)x; + if (x is long) + x = (double)(long)x; + if (x is ulong) + x = (double)(ulong)x; + if (x is Enum) + x = (double)(int)x; + if (x is float) + x = (double)(float)x; + if (x is decimal) + x = decimal.ToDouble((decimal)x); + if (y is sbyte) + y = (double)(sbyte)y; + if (y is byte) + y = (double)(byte)y; + if (y is char) + y = (double)(char)y; + if (y is short) + y = (double)(short)y; + if (y is ushort) + y = (double)(ushort)y; if (y is int) y = (double)(int)y; if (y is uint) y = (double)(uint)y; + if (y is long) + y = (double)(long)y; + if (y is ulong) + y = (double)(ulong)y; + if (y is Enum) + y = (double)(int)y; + if (y is float) + y = (double)(float)y; + if (y is decimal) + y = decimal.ToDouble((decimal)y); if (x is double && (double) x == 0.0 && y is double && (double)y == 0.0) if ((1 / (double)x) != (1 / (double)y)) return false; @@ -260,14 +376,54 @@ public static bool SameValueZero(object x, object y) x = Undefined.Value; if (y == null) y = Undefined.Value; + if (x is sbyte) + x = (double)(sbyte)x; + if (x is byte) + x = (double)(byte)x; + if (x is char) + x = (double)(char)x; + if (x is short) + x = (double)(short)x; + if (x is ushort) + x = (double)(ushort)x; if (x is int) x = (double)(int)x; if (x is uint) x = (double)(uint)x; + if (x is long) + x = (double)(long)x; + if (x is ulong) + x = (double)(ulong)x; + if (x is Enum) + x = (double)(int)x; + if (x is float) + x = (double)(float)x; + if (x is decimal) + x = decimal.ToDouble((decimal)x); + if (y is sbyte) + y = (double)(sbyte)y; + if (y is byte) + y = (double)(byte)y; + if (y is char) + y = (double)(char)y; + if (y is short) + y = (double)(short)y; + if (y is ushort) + y = (double)(ushort)y; if (y is int) y = (double)(int)y; if (y is uint) y = (double)(uint)y; + if (y is long) + y = (double)(long)y; + if (y is ulong) + y = (double)(ulong)y; + if (y is Enum) + y = (double)(int)y; + if (y is float) + y = (double)(float)y; + if (y is decimal) + y = decimal.ToDouble((decimal)y); if (x is ConcatenatedString) x = x.ToString(); if (y is ConcatenatedString) diff --git a/Jurassic/Core/TypeConverter.cs b/Jurassic/Core/TypeConverter.cs index 5608d29c..47fbcd69 100644 --- a/Jurassic/Core/TypeConverter.cs +++ b/Jurassic/Core/TypeConverter.cs @@ -80,14 +80,32 @@ public static bool ToBoolean(object value) return false; if (value is bool) return (bool)value; + if (value is sbyte) + return ((sbyte)value) != 0; if (value is byte) return ((byte)value) != 0; + if (value is char) + return ((char)value) != 0; + if (value is short) + return ((short)value) != 0; + if (value is ushort) + return ((ushort)value) != 0; if (value is int) return ((int)value) != 0; if (value is uint) return ((uint)value) != 0; + if (value is long) + return ((long)value) != 0; + if (value is ulong) + return ((ulong)value) != 0; + if (value is Enum ) + return ((int)value) != 0; + if (value is float) + return ((float)value) != 0 && float.IsNaN((float)value) == false; if (value is double) return ((double)value) != 0 && double.IsNaN((double)value) == false; + if (value is decimal) + return ((decimal)value) != 0; if (value is string) return ((string)value).Length > 0; if (value is ConcatenatedString) @@ -104,14 +122,32 @@ public static bool ToBoolean(object value) /// A primitive number value. public static double ToNumber(object value) { + if (value is float) + return (double)(float)value; if (value is double) return (double)value; + if (value is decimal) + return decimal.ToDouble((decimal)value); + if (value is sbyte) + return (double)(sbyte)value; if (value is byte) return (double)(byte)value; + if (value is char) + return (double)(char)value; + if (value is short) + return (double)(short)value; + if (value is ushort) + return (double)(ushort)value; if (value is int) return (double)(int)value; if (value is uint) return (double)(uint)value; + if (value is long) + return (double)(long)value; + if (value is ulong) + return (double)(ulong)value; + if (value is Enum) + return (int)value; if (value == null || value == Undefined.Value) return double.NaN; if (value == Null.Value) @@ -150,13 +186,27 @@ public static string ToString(object value) return "null"; if (value is bool) return (bool)value ? "true" : "false"; + if (value is sbyte) + return ((sbyte)value).ToString(); if (value is byte) return ((byte)value).ToString(); + if (value is char) + return ((char)value).ToString(); + if (value is short) + return ((short)value).ToString(); + if (value is ushort) + return ((ushort)value).ToString(); if (value is int) return ((int)value).ToString(); if (value is uint) return ((uint)value).ToString(); - if (value is double) + if (value is long) + return ((long)value).ToString(); + if (value is ulong) + return ((ulong)value).ToString(); + if (value is Enum) + return value.ToString(); + if (value is double || value is float) { // Check if the value is in the cache. double doubleValue = (double)value; @@ -173,6 +223,8 @@ public static string ToString(object value) return result; } + if (value is decimal) + return ((decimal)value).ToString(); if (value is string) return (string)value; if (value is ConcatenatedString) @@ -230,14 +282,32 @@ public static ObjectInstance ToObject(ScriptEngine engine, object value, int lin ObjectInstance result; if (value is bool) result = engine.Boolean.Construct((bool)value); + else if (value is sbyte) + result = engine.Number.Construct((sbyte)value); else if (value is byte) result = engine.Number.Construct((byte)value); + else if (value is char) + result = engine.Number.Construct((char)value); + else if (value is short) + result = engine.Number.Construct((short)value); + else if (value is ushort) + result = engine.Number.Construct((ushort)value); else if (value is int) result = engine.Number.Construct((int)value); else if (value is uint) result = engine.Number.Construct((uint)value); + else if (value is long) + result = engine.Number.Construct((long)value); + else if (value is ulong) + result = engine.Number.Construct((ulong)value); + else if (value is Enum) + result = engine.Number.Construct((int)value); + else if (value is float) + result = engine.Number.Construct((float)value); else if (value is double) result = engine.Number.Construct((double)value); + else if (value is decimal) + result = engine.Number.Construct(decimal.ToDouble((decimal)value)); else if (value is string) result = engine.String.Construct((string)value); else if (value is ConcatenatedString) diff --git a/Jurassic/Core/TypeUtilities.cs b/Jurassic/Core/TypeUtilities.cs index f87e41b0..df278f00 100644 --- a/Jurassic/Core/TypeUtilities.cs +++ b/Jurassic/Core/TypeUtilities.cs @@ -24,7 +24,12 @@ public static string TypeOf(object obj) return "object"; if (obj is bool) return "boolean"; - if (obj is double || obj is int || obj is uint) + if (obj is float || obj is double || obj is decimal || + obj is sbyte || obj is byte || obj is char || + obj is short || obj is ushort || + obj is int || obj is uint || + obj is long || obj is ulong || + obj is Enum) return "number"; if (obj is string || obj is ConcatenatedString) return "string"; @@ -55,7 +60,12 @@ internal static bool IsUndefined(object obj) /// otherwise. internal static bool IsNumeric(object obj) { - return obj is double || obj is int || obj is uint; + return obj is float || obj is double || obj is decimal || + obj is sbyte || obj is byte || obj is char || + obj is short || obj is ushort || + obj is int || obj is uint || + obj is long || obj is ulong || + obj is Enum; } /// @@ -78,7 +88,7 @@ internal static object NormalizeValue(object obj) { if (obj == null) return Undefined.Value; - else if (obj is double) + else if (obj is float || obj is double || obj is decimal) { var numericResult = (double)obj; if (((int)numericResult) == numericResult) @@ -95,6 +105,8 @@ internal static object NormalizeValue(object obj) obj = ((ConcatenatedString)obj).ToString(); else if (obj is ClrInstanceWrapper) obj = ((ClrInstanceWrapper)obj).WrappedInstance; + else if (obj is ClrInstanceTypeWrapper) + obj = ((ClrInstanceTypeWrapper)obj).WrappedType; else if (obj is ClrStaticTypeWrapper) obj = ((ClrStaticTypeWrapper)obj).WrappedType; return obj; @@ -178,7 +190,12 @@ public static bool IsPrimitive(object value) return true; var type = value.GetType(); return type == typeof(bool) || - type == typeof(int) || type == typeof(uint) || type == typeof(double) || + type == typeof(sbyte) || type == typeof(byte) || type == typeof(char) || + type == typeof(short) || type == typeof(ushort) || + type == typeof(int) || type == typeof(uint) || + type == typeof(long) || type == typeof(ulong) || + type.IsEnum || + type == typeof(float) || type == typeof(double) || type == typeof(decimal) || type == typeof(string) || type == typeof(ConcatenatedString) || type == typeof(Null) || type == typeof(Undefined) || type == typeof(SymbolInstance); @@ -197,7 +214,12 @@ public static bool IsPrimitiveOrObject(object value) return true; var type = value.GetType(); return type == typeof(bool) || - type == typeof(int) || type == typeof(uint) || type == typeof(double) || + type == typeof(sbyte) || type == typeof(byte) || type == typeof(char) || + type == typeof(short) || type == typeof(ushort) || + type == typeof(int) || type == typeof(uint) || + type == typeof(long) || type == typeof(ulong) || + type.IsEnum || + type == typeof(float) || type == typeof(double) || type == typeof(decimal) || type == typeof(string) || type == typeof(ConcatenatedString) || type == typeof(Null) || type == typeof(Undefined) || typeof(ObjectInstance).IsAssignableFrom(type); From c8d8fc675fe49005d099558d6f678ad36cb5e19c Mon Sep 17 00:00:00 2001 From: objmalloc Date: Fri, 9 Nov 2018 15:22:23 +0200 Subject: [PATCH 3/3] DBNull suport --- Jurassic/Compiler/Binders/BinderUtilities.cs | 2 +- Jurassic/Compiler/Binders/ClrBinder.cs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Jurassic/Compiler/Binders/BinderUtilities.cs b/Jurassic/Compiler/Binders/BinderUtilities.cs index f2eac035..3e1a13b3 100644 --- a/Jurassic/Compiler/Binders/BinderUtilities.cs +++ b/Jurassic/Compiler/Binders/BinderUtilities.cs @@ -96,6 +96,7 @@ public static int ResolveOverloads(RuntimeMethodHandle[] methodHandles, ScriptEn demeritPoints[i] += disqualification; break; + case TypeCode.DBNull: case TypeCode.DateTime: case TypeCode.Object: if (input == null || input == Undefined.Value) @@ -115,7 +116,6 @@ public static int ResolveOverloads(RuntimeMethodHandle[] methodHandles, ScriptEn case TypeCode.Empty: - case TypeCode.DBNull: throw new NotSupportedException(string.Format("{0} is not a supported parameter type.", outputType)); } } diff --git a/Jurassic/Compiler/Binders/ClrBinder.cs b/Jurassic/Compiler/Binders/ClrBinder.cs index 39818a17..c0b66f39 100644 --- a/Jurassic/Compiler/Binders/ClrBinder.cs +++ b/Jurassic/Compiler/Binders/ClrBinder.cs @@ -191,8 +191,6 @@ internal static void EmitConversionToType(ILGenerator generator, Type toType, bo generator.LoadInt32(0); generator.Call(ReflectionHelpers.String_GetChars); break; - case TypeCode.DBNull: - throw new NotSupportedException("DBNull is not a supported parameter type."); case TypeCode.Decimal: EmitConversion.ToNumber(generator, PrimitiveType.Any); generator.NewObject(ReflectionHelpers.Decimal_Constructor_Double); @@ -213,6 +211,7 @@ internal static void EmitConversionToType(ILGenerator generator, Type toType, bo generator.ConvertToInt64(); break; + case TypeCode.DBNull: case TypeCode.DateTime: case TypeCode.Object: // Check if the type must be unwrapped. @@ -340,8 +339,6 @@ internal static void EmitConversionToObject(ILGenerator generator, Type fromType generator.NewObject(ReflectionHelpers.String_Constructor_Char_Int); break; - case TypeCode.DBNull: - throw new NotSupportedException("DBNull is not a supported return type."); case TypeCode.Decimal: generator.Call(ReflectionHelpers.Decimal_ToDouble); generator.Box(typeof(double)); @@ -362,6 +359,7 @@ internal static void EmitConversionToObject(ILGenerator generator, Type fromType generator.Box(typeof(double)); break; + case TypeCode.DBNull: case TypeCode.DateTime: case TypeCode.Object: // Check if the type must be wrapped with a ClrInstanceWrapper.