protected OperatorImplementation AddConverter(Type fromType, Type toType, UnaryOperatorMethod method)
 {
     var key = new OperatorDispatchKey(ExpressionType.ConvertChecked, fromType, toType);
     var impl = new OperatorImplementation(key, toType, method);
     OperatorImplementations[key] = impl;
     return impl;
 }
        public object ExecuteBinaryOperator(ExpressionType op, object arg1, object arg2, ref OperatorImplementation previousUsed)
        {
            // 1. Get arg types
            Type arg1Type, arg2Type;
            try
            {
                arg1Type = arg1.GetType();
                arg2Type = arg2.GetType();
            }
            catch (NullReferenceException)
            {
                // arg1 or arg2 is null - which means never assigned.
                CheckUnassigned(arg1);
                CheckUnassigned(arg2);
                throw;
            }

            // 2. If we had prev impl, check if current args types match it; first copy it into local variable
            // Note: BinaryExpression node might already have tried it directly, without any checks, and 
            // apparently failed. At some point this attempt in BinaryExpressionNode can become disabled.
            // But we might still try it here, with proper checks
            var currentImpl = previousUsed;
            if (currentImpl != null && (arg1Type != currentImpl.Key.Arg1Type || arg2Type != currentImpl.Key.Arg2Type))
                currentImpl = null;

            // 3. Find implementation for arg types
            OperatorDispatchKey key;
            if (currentImpl == null)
            {
                key = new OperatorDispatchKey(op, arg1Type, arg2Type);
                if (!OperatorImplementations.TryGetValue(key, out currentImpl))
                    ThrowScriptError(Resources.ErrOpNotDefinedForTypes, op, arg1Type, arg2Type);
            }

            // 4. Actually call 
            try
            {
                previousUsed = currentImpl;
                return currentImpl.EvaluateBinary(arg1, arg2);
            }
            catch (OverflowException)
            {
                if (currentImpl.OverflowHandler == null) throw;
                previousUsed = currentImpl.OverflowHandler; //set previousUsed to overflowHandler, so it will be used next time
                return ExecuteBinaryOperator(op, arg1, arg2, ref previousUsed); //call self recursively
            }
            catch (IndexOutOfRangeException)
            {
                //We can get here only if we use SmartBoxing - the result is out of range of pre-allocated boxes, 
                // so attempt to lookup a boxed value in _boxes dictionary fails with outOfRange exc
                if (currentImpl.NoBoxImplementation == null) throw;
                // If NoBoxImpl is not null, then it is implementation with auto-boxing. 
                // Auto-boxing failed - the result is outside the range of our boxes array. Let's call no-box version.
                // we also set previousUsed to no-box implementation, so we use it in the future calls
                previousUsed = currentImpl.NoBoxImplementation;
                return ExecuteBinaryOperator(op, arg1, arg2, ref previousUsed); //call self recursively
            }

        }//method
 protected OperatorImplementation AddBinary(ExpressionType op, Type commonType,
                  BinaryOperatorMethod binaryMethod, UnaryOperatorMethod resultConverter)
 {
     var key = new OperatorDispatchKey(op, commonType, commonType);
     var impl = new OperatorImplementation(key, commonType, binaryMethod, null, null, resultConverter);
     OperatorImplementations[key] = impl;
     return impl;
 }
 protected OperatorImplementation AddUnary(ExpressionType op, Type commonType, UnaryOperatorMethod unaryMethod) {
   var key = new OperatorDispatchKey(op, commonType);
   var impl = new OperatorImplementation(key, commonType, null, unaryMethod, null, null);
   OperatorImplementations[key] = impl;
   return impl;
 }
 // Important: returns null if fromType == toType
 public virtual UnaryOperatorMethod GetConverter(Type fromType, Type toType) {
   if (fromType == toType)
     return (x => x);
   var key = new OperatorDispatchKey(ExpressionType.ConvertChecked, fromType, toType);
   OperatorImplementation impl;
   if (!OperatorImplementations.TryGetValue(key, out impl))
     return null;
   return impl.Arg1Converter;
 }
 private OperatorImplementation FindBaseImplementation(ExpressionType op, Type commonType) {
   var baseKey = new OperatorDispatchKey(op, commonType, commonType);
   OperatorImplementation baseImpl;
   OperatorImplementations.TryGetValue(baseKey, out baseImpl);
   return baseImpl;
 }
 protected virtual OperatorImplementation CreateBinaryOperatorImplementation(ExpressionType op, Type arg1Type, Type arg2Type, 
                Type commonType, BinaryOperatorMethod method, UnaryOperatorMethod resultConverter) {
   OperatorDispatchKey key = new OperatorDispatchKey(op, arg1Type, arg2Type);
   UnaryOperatorMethod arg1Converter = arg1Type == commonType ? null : GetConverter(arg1Type, commonType);
   UnaryOperatorMethod arg2Converter = arg2Type == commonType ? null : GetConverter(arg2Type, commonType);
   var impl = new OperatorImplementation(
     key, commonType, method, arg1Converter, arg2Converter, resultConverter);
   return impl; 
 }
예제 #8
0
        public object ExecuteUnaryOperator(ExpressionType op, object arg1, ref OperatorImplementation previousUsed)
        {
            // 1. Get arg type
              Type arg1Type;
              try {
            arg1Type = arg1.GetType();
              } catch (NullReferenceException) {
            CheckUnassigned(arg1);
            throw;
              }

              // 2. If we had prev impl, check if current args types match it; first copy it into local variable
              OperatorDispatchKey key;
              var currentImpl = previousUsed;
              if (currentImpl != null && arg1Type != currentImpl.Key.Arg1Type)
            currentImpl = null;

              // 3. Find implementation for arg type
              if (currentImpl == null) {
            key = new OperatorDispatchKey(op, arg1Type);
            if (!OperatorImplementations.TryGetValue(key, out currentImpl))
              ThrowError(Resources.ErrOpNotDefinedForType, op, arg1Type);
              }

              // 4. Actually call
              try {
            previousUsed = currentImpl; //set previousUsed so next time we'll try this impl first
            return currentImpl.Arg1Converter(arg1);
              } catch (OverflowException) {
            if (currentImpl.OverflowHandler == null)
              throw;
            previousUsed = currentImpl.OverflowHandler; //set previousUsed to overflowHandler, so it will be used next time
            return ExecuteUnaryOperator(op, arg1, ref previousUsed); //call self recursively
              }
        }