aspclassic-core/AspClassic.VBScript/Runtime/HelperFunctions.cs
Jelle Luteijn 484dbfc9d9 progress
2022-05-15 11:19:49 +02:00

667 lines
24 KiB
C#

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Threading;
#if USE35
using AspClassic.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
namespace Dlrsoft.VBScript.Runtime
{
public class HelperFunctions
{
public static object GetDefaultPropertyValue(object target)
{
if (target == null) return target;
while (target.GetType().IsCOMObject)
{
target = target.GetType().InvokeMember(string.Empty,
BindingFlags.Default | BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.GetProperty,
null,
target,
null);
}
return target;
}
public static object Concatenate(object left, object right)
{
bool leftDBNull = false;
if (left == null)
{
left = String.Empty;
}
else if (left is DBNull)
{
left = String.Empty;
leftDBNull = true;
}
else
{
if (left.GetType().IsCOMObject)
{
left = GetDefaultPropertyValue(left);
}
if (!(left is string))
{
left = left.ToString();
}
}
if (right == null)
{
right = string.Empty;
}
else if (right is DBNull)
{
if (leftDBNull) return DBNull.Value;
right = string.Empty;
}
else
{
if (right.GetType().IsCOMObject)
{
right = GetDefaultPropertyValue(right);
}
if (!(right is string))
{
right = right.ToString();
}
}
return (string)left + (string)right;
}
public static object BinaryOp(ExpressionType op, object left, object right)
{
if (left == null || right == null)
{
if (op == ExpressionType.Equal)
{
if (left == null && right == null)
{
return true;
}
else if (string.Empty.Equals(left) || string.Empty.Equals(right))
{
return true;
}
else
{
return false;
}
}
else if (op == ExpressionType.NotEqual)
{
if (left == null && right == null)
{
return false;
}
else if (string.Empty.Equals(left) || string.Empty.Equals(right))
{
return false;
}
else
{
return true;
}
}
else
{
return null;
}
}
Type ltype = left.GetType();
Type rtype = right.GetType();
if (op == ExpressionType.Equal)
{
if (left == right) return true;
}
if (ltype.IsCOMObject)
{
left = GetDefaultPropertyValue(left);
ltype = left.GetType();
}
if (rtype.IsCOMObject)
{
right = GetDefaultPropertyValue(right);
rtype = right.GetType();
}
if (!ltype.IsValueType && ltype != typeof(string))
{
left = left.ToString();
ltype = typeof(string);
}
if (!rtype.IsValueType && rtype != typeof(string))
{
right = right.ToString();
rtype = typeof(string);
}
Type targetType;
if (ltype == rtype || CanConvert(rtype, ltype))
{
targetType = ltype;
}
else
{
targetType = rtype;
}
switch (op)
{
case ExpressionType.Add:
if (targetType == typeof(int))
{
return Convert.ToInt32(left) + Convert.ToInt32(right);
}
else if (targetType == typeof(double))
{
return Convert.ToDouble(left) + Convert.ToDouble(right);
}
else if (targetType == typeof(long))
{
return Convert.ToInt64(left) + Convert.ToInt64(right);
}
else if (targetType == typeof(float))
{
return Convert.ToSingle(left) + Convert.ToSingle(right);
}
else if (targetType == typeof(decimal))
{
return Convert.ToDecimal(left) + Convert.ToDecimal(right);
}
else if (targetType == typeof(string))
{
return (string)left + (string)right;
}
break;
case ExpressionType.Subtract:
if (targetType == typeof(int))
{
return Convert.ToInt32(left) - Convert.ToInt32(right);
}
else if (targetType == typeof(double) || targetType == typeof(string))
{
return Convert.ToDouble(left) - Convert.ToDouble(right);
}
else if (targetType == typeof(long))
{
return Convert.ToInt64(left) - Convert.ToInt64(right);
}
else if (targetType == typeof(float))
{
return Convert.ToSingle(left) - Convert.ToSingle(right);
}
else if (targetType == typeof(decimal))
{
return Convert.ToDecimal(left) - Convert.ToDecimal(right);
}
break;
case ExpressionType.Multiply:
if (targetType == typeof(int))
{
return Convert.ToInt32(left) * Convert.ToInt32(right);
}
else if (targetType == typeof(double) || targetType == typeof(string))
{
return Convert.ToDouble(left) * Convert.ToDouble(right);
}
else if (targetType == typeof(long))
{
return Convert.ToInt64(left) * Convert.ToInt64(right);
}
else if (targetType == typeof(float))
{
return Convert.ToSingle(left) * Convert.ToSingle(right);
}
else if (targetType == typeof(decimal))
{
return Convert.ToDecimal(left) * Convert.ToDecimal(right);
}
break;
case ExpressionType.Divide:
if (targetType == typeof(int))
{
return Convert.ToInt32(left) / Convert.ToInt32(right);
}
else if (targetType == typeof(double) || targetType == typeof(string))
{
return Convert.ToDouble(left) / Convert.ToDouble(right);
}
else if (targetType == typeof(long))
{
return Convert.ToInt64(left) / Convert.ToInt64(right);
}
else if (targetType == typeof(float))
{
return Convert.ToSingle(left) / Convert.ToSingle(right);
}
else if (targetType == typeof(decimal))
{
return Convert.ToDecimal(left) / Convert.ToDecimal(right);
}
break;
case ExpressionType.Equal:
try
{
if (targetType == typeof(int))
{
return Convert.ToInt32(left) == Convert.ToInt32(right);
}
else if (targetType == typeof(double))
{
return Convert.ToDouble(left) == Convert.ToDouble(right);
}
else if (targetType == typeof(long))
{
return Convert.ToInt64(left) == Convert.ToInt64(right);
}
else if (targetType == typeof(float))
{
return Convert.ToSingle(left) == Convert.ToSingle(right);
}
else if (targetType == typeof(decimal))
{
return Convert.ToDecimal(left) == Convert.ToDecimal(right);
}
else if (targetType == typeof(string))
{
return ((string)left).Equals(right);
}
else
{
return left == right;
}
}
catch (Exception ex)
{
return false;
}
case ExpressionType.NotEqual:
try
{
if (targetType == typeof(int))
{
return Convert.ToInt32(left) != Convert.ToInt32(right);
}
else if (targetType == typeof(double))
{
return Convert.ToDouble(left) != Convert.ToDouble(right);
}
else if (targetType == typeof(long))
{
return Convert.ToInt64(left) != Convert.ToInt64(right);
}
else if (targetType == typeof(float))
{
return Convert.ToSingle(left) != Convert.ToSingle(right);
}
else if (targetType == typeof(decimal))
{
return Convert.ToDecimal(left) != Convert.ToDecimal(right);
}
else if (targetType == typeof(string))
{
return !((string)left).Equals(right);
}
else
{
return left != right;
}
}
catch (Exception ex)
{
return true;
}
case ExpressionType.GreaterThan:
if (targetType == typeof(int))
{
return Convert.ToInt32(left) > Convert.ToInt32(right);
}
else if (targetType == typeof(double))
{
return Convert.ToDouble(left) > Convert.ToDouble(right);
}
else if (targetType == typeof(long))
{
return Convert.ToInt64(left) > Convert.ToInt64(right);
}
else if (targetType == typeof(float))
{
return Convert.ToSingle(left) > Convert.ToSingle(right);
}
else if (targetType == typeof(decimal))
{
return Convert.ToDecimal(left) > Convert.ToDecimal(right);
}
else if (targetType == typeof(string))
{
int result = ((string)left).CompareTo(right);
return (result > 0);
}
break;
case ExpressionType.GreaterThanOrEqual:
if (targetType == typeof(int))
{
return Convert.ToInt32(left) >= Convert.ToInt32(right);
}
else if (targetType == typeof(double))
{
return Convert.ToDouble(left) >= Convert.ToDouble(right);
}
else if (targetType == typeof(long))
{
return Convert.ToInt64(left) >= Convert.ToInt64(right);
}
else if (targetType == typeof(float))
{
return Convert.ToSingle(left) >= Convert.ToSingle(right);
}
else if (targetType == typeof(decimal))
{
return Convert.ToDecimal(left) >= Convert.ToDecimal(right);
}
else if (targetType == typeof(string))
{
int result = ((string)left).CompareTo(right);
return (result >= 0);
}
break;
case ExpressionType.LessThan:
if (targetType == typeof(int))
{
return Convert.ToInt32(left) < Convert.ToInt32(right);
}
else if (targetType == typeof(double))
{
return Convert.ToDouble(left) < Convert.ToDouble(right);
}
else if (targetType == typeof(long))
{
return Convert.ToInt64(left) < Convert.ToInt64(right);
}
else if (targetType == typeof(float))
{
return Convert.ToSingle(left) < Convert.ToSingle(right);
}
else if (targetType == typeof(decimal))
{
return Convert.ToDecimal(left) < Convert.ToDecimal(right);
}
else if (targetType == typeof(string))
{
int result = ((string)left).CompareTo(right);
return (result < 0);
}
break;
case ExpressionType.LessThanOrEqual:
if (targetType == typeof(int))
{
return Convert.ToInt32(left) <= Convert.ToInt32(right);
}
else if (targetType == typeof(double))
{
return Convert.ToDouble(left) <= Convert.ToDouble(right);
}
else if (targetType == typeof(long))
{
return Convert.ToInt64(left) <= Convert.ToInt64(right);
}
else if (targetType == typeof(float))
{
return Convert.ToSingle(left) <= Convert.ToSingle(right);
}
else if (targetType == typeof(decimal))
{
return Convert.ToDecimal(left) <= Convert.ToDecimal(right);
}
else if (targetType == typeof(string))
{
int result = ((string)left).CompareTo(right);
return (result <= 0);
}
break;
case ExpressionType.And:
if (targetType == typeof(bool))
{
return (bool)left && (bool)right;
}
else if (targetType == typeof(int))
{
return Convert.ToInt32(left) & Convert.ToInt32(right);
}
else if (targetType == typeof(long))
{
return Convert.ToInt64(left) & Convert.ToInt64(right);
}
else
{
return (bool)BuiltInFunctions.CBool(left) && (bool)BuiltInFunctions.CBool(right);
}
break;
case ExpressionType.Or:
if (targetType == typeof(bool))
{
return (bool)left || (bool)right;
}
else if (targetType == typeof(int))
{
return Convert.ToInt32(left) | Convert.ToInt32(right);
}
else if (targetType == typeof(long))
{
return Convert.ToInt64(left) | Convert.ToInt64(right);
}
else
{
return (bool)BuiltInFunctions.CBool(left) || (bool)BuiltInFunctions.CBool(right);
}
break;
}
throw new ArgumentException(string.Format("Operation {0} between {1} and {2} is not implemeted.", op, ltype.Name, rtype.Name));
}
private static bool CanConvert(Type fromType, Type toType)
{
if (toType.IsAssignableFrom(fromType)) return true;
if (fromType == typeof(string) && (toType.IsPrimitive))
{
return true;
}
return false;
}
public static object Redim(Type t, params int[] ubounds)
{
return redimInternal(t, ubounds);
}
public static Array redimInternal(Type t, params int[] ubounds)
{
if (ubounds == null) throw new ArgumentException("Must supply bound(s) when redim an array.");
for (int i = 0; i < ubounds.Length; i++)
{
//Convert from ubound to length
ubounds[i] += 1;
}
return Array.CreateInstance(t, ubounds);
}
//public static object RedimPreserve(object array, int length1)
//{
// return redimPreserveInternal(array, length1);
//}
//public static object RedimPreserve(object array, int length1, int length2)
//{
// return redimPreserveInternal(array, length1, length2);
//}
//public static object RedimPreserve(object array, int length1, int length2, int length3)
//{
// return redimPreserveInternal(array, length1, length2, length3);
//}
//public static object RedimPreserve(object array, int length1, int length2, int length3, int length4)
//{
// return redimPreserveInternal(array, length1, length2, length3, length4);
//}
//public static object RedimPreserve(object array, int length1, int length2, int length3, int length4, int length5)
//{
// return redimPreserveInternal(array, length1, length2, length3, length4, length5);
//}
//public static object RedimPreserve(object array, int length1, int length2, int length3, int length4, int length5, int length6)
//{
// return redimPreserveInternal(array, length1, length2, length3, length4, length5, length6);
//}
public static object RedimPreserve(object array, params int[] lengths)
{
return redimPreserveInternal(array, lengths);
}
private static Array redimPreserveInternal(object array, params int[] lengths)
{
if (array == null) throw new ArgumentException("To redim an array, the array must be a previously declared array.");
Type t = array.GetType();
if (!t.IsArray) throw new ArgumentException("Redim variable is not an array.");
int oldDimension = ((Array)array).Rank;
int newDimension = lengths.Length;
if (oldDimension != newDimension) throw new ArgumentException(string.Format("Cannot change dimension of the array from {0} to {1}", oldDimension, newDimension));
int elementsToCopy = 1;
for (int i = 0; i < oldDimension - 1; i++)
{
int oldBound = ((Array)array).GetUpperBound(i);
if (oldBound != lengths[i])
throw new ArgumentException(string.Format("Can only resize the last dimension. You are trying to resize dimension {0} from {1} to {2}",
i + 1, oldBound, lengths[i]));
elementsToCopy *= ((Array)array).GetLength(i);
}
elementsToCopy *= (((Array)array).GetLength(oldDimension - 1) < lengths[oldDimension - 1]) ? ((Array)array).GetLength(oldDimension - 1) : lengths[oldDimension - 1];
Array newArray = redimInternal(t.GetElementType(), lengths);
Array.Copy((Array)array, newArray, elementsToCopy);
return newArray;
}
public static void SetError(ErrObject err, Exception ex)
{
//Don't catch ThreadAbortException since it is captured by Response.Redirect
if (ex is ThreadAbortException)
throw ex;
err.internalRaise(ex);
}
public static object Eqv(object left, object right)
{
if (left is DBNull || right is DBNull) return DBNull.Value;
CheckLogicOperand(ref left);
CheckLogicOperand(ref right);
if (left is int) BoolToInt(ref right);
if (right is int) BoolToInt(ref left);
if (left is bool)
return (bool)left == (bool)right;
return ~((int)left ^ (int)right);
}
public static object Imp(object left, object right)
{
throw new NotImplementedException("Imp method is not implemented.");
}
public static object Not(object target)
{
if (target == null) return null;
if (target.GetType().IsCOMObject)
{
target = GetDefaultPropertyValue(target);
}
return !(bool)BuiltInFunctions.CBool(target);
}
public static object Negate(object target)
{
if (target == null) return null;
if (target.GetType().IsCOMObject)
{
target = GetDefaultPropertyValue(target);
}
return -(double)BuiltInFunctions.CDbl(target);
}
private static void CheckLogicOperand(ref object value)
{
if (value == null) value = 0;
if (value is float || value is double)
{
value = Convert.ToInt32(value);
}
if (value is string)
{
bool boolResult;
int intResult;
if (bool.TryParse((string)value, out boolResult))
{
value = boolResult;
}
else if (int.TryParse((string)value, out intResult))
{
value = intResult;
}
}
if (value is bool || value is int) return;
throw new ArgumentException("Logic functions or operators requires arguments that can be converted to bool or int.");
}
private static void BoolToInt(ref object value)
{
if (value is bool) value = (bool)value ? -1 : 0;
}
}
}