/* * Copyright © 2011, Petro Protsyk, Denys Vuika * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; namespace Scripting.SSharp { public static class DynamicMath { static Dictionary>>> converters = new Dictionary>>>(); public static void AddConverter(Func> function) { Type leftType = typeof(TLeft); Dictionary>> funcs = null; if (!converters.TryGetValue(leftType, out funcs)) { funcs = new Dictionary>>(); converters[leftType] = funcs; } funcs[typeof(TRight)] = function; } public static Tuple TryConvert(dynamic left, dynamic right) { // Denys Vuika: the code below crash for mono 2.8 though should work fine, // slightly rewriting to make the code mono-compatible /* Dictionary>> funcs = null; if (converters.TryGetValue(left.GetType(), out funcs)) { Func> function = null; if (funcs.TryGetValue(right.GetType(), out function)) return function(left, right); } */ if (left == null || right == null) return null; Type leftType = left.GetType(); if (converters.ContainsKey(leftType)) { var funcs = converters[leftType]; Type rightType = right.GetType(); if (funcs.ContainsKey(rightType)) return funcs[rightType](left, right); } return null; } static DynamicMath() { AddConverter((left, right) => new Tuple((double)left, right)); AddConverter((left, right) => new Tuple(left, (double)right)); AddConverter((left, right) => new Tuple((float)left, right)); AddConverter((left, right) => new Tuple(left, (float)right)); Func> rightToString = (left, right) => new Tuple(left, right.ToString()); Func> leftToString = (left, right) => new Tuple(left.ToString(), right); AddConverter(rightToString); AddConverter(rightToString); AddConverter(rightToString); AddConverter(rightToString); AddConverter(rightToString); AddConverter(rightToString); AddConverter(leftToString); AddConverter(leftToString); AddConverter(leftToString); AddConverter(leftToString); AddConverter(leftToString); AddConverter(leftToString); AddConverter(rightToString); AddConverter(leftToString); } public static bool Eq(dynamic left, dynamic right) { Tuple converted = TryConvert(left, right); if (converted != null) return ((converted.Item1 == converted.Item2) || (((converted.Item1 != null) && (converted.Item2 != null)) && converted.Item1.Equals(converted.Item2))); // Use such comparsion instead of object.Equals(left, right); in order to force appropriate == operator // and to avoid boxing for primitive types return ((left == right) || (((left != null) && (right != null)) && left.Equals(right))); } public static bool Neq(dynamic left, dynamic right) { return !Eq(left, right); } public static dynamic Add(dynamic left, dynamic right) { Tuple converted = TryConvert(left, right); if (converted != null) return converted.Item1 + converted.Item2; return (left + right); } public static dynamic Subtract(dynamic left, dynamic right) { Tuple converted = TryConvert(left, right); if (converted != null) return converted.Item1 - converted.Item2; return (left - right); } public static dynamic Multiply(dynamic left, dynamic right) { Tuple converted = TryConvert(left, right); if (converted != null) return converted.Item1 * converted.Item2; return left * right; } public static bool Less(dynamic left, dynamic right) { if (left is string && right is string) return string.Compare(left, right) < 0; Tuple converted = TryConvert(left, right); if (converted != null) return converted.Item1 < converted.Item2; return left < right; } public static bool LessOrEquals(dynamic left, dynamic right) { if (left is string && right is string) return string.Compare(left, right) <= 0; Tuple converted = TryConvert(left, right); if (converted != null) return converted.Item1 <= converted.Item2; return left <= right; } public static bool Greater(dynamic left, dynamic right) { if (left is string && right is string) return string.Compare(left, right) > 0; Tuple converted = TryConvert(left, right); if (converted != null) return converted.Item1 > converted.Item2; return left > right; } public static bool GreaterOrEquals(dynamic left, dynamic right) { if (left is string && right is string) return string.Compare(left, right) >= 0; Tuple converted = TryConvert(left, right); if (converted != null) return converted.Item1 >= converted.Item2; return left >= right; } public static dynamic Mod(dynamic left, dynamic right) { Tuple converted = TryConvert(left, right); if (converted != null) return converted.Item1 % converted.Item2; return left % right; } public static dynamic Div(dynamic left, dynamic right) { Tuple converted = TryConvert(left, right); if (converted != null) return converted.Item1 / converted.Item2; return left / right; } public static dynamic And(dynamic left, dynamic right) { return left & right; } public static bool ConditionalAnd(dynamic left, dynamic right) { return left && right; } public static dynamic Or(dynamic left, dynamic right) { return left | right; } public static bool ConditionalOr(dynamic left, dynamic right) { return left || right; } } }