/* * public MetaObjectBase FindMetaObject(object target) { * //built-in objects - lookup in MetaObjects table * MetaObjectBase meta; * if (_runtime.MetaObjects.TryGetValue(target.GetType(), out meta)) * return meta; * //Check scriptObject * var scriptObj = target as ScriptObjectBase; * if (scriptObj != null) * return scriptObj.MetaObject; * return null; * } * * public MethodImp FindMethod(object target, string methodName, int argCount) { * var metaObj = FindMetaObject(target); * if (metaObj == null) * throw new RuntimeException(String.Format("MetaObject not found for object {0}, method {1}", target, methodName)); * return metaObj.FindMethod(_context, target, methodName, argCount); * } * * public void ExecuteMethod(object target, string methodName, int argCount) { * var method = FindMethod(target, methodName, argCount); * if (method == null) * throw new Exception("Method not found: " + methodName); * _context.CurrentFrame = new StackFrame(method, _context.CurrentFrame, method.OwnerFrame, _context.Data, argCount); * method.Execute(_context, target, argCount); * //return back new frame * _context.PopFrame(); * object result = _context.LastResult; * _context.Data.Replace(argCount + 1, result); * }//method */ //node parameter is used for error reporting public void ExecuteBinaryOperator(string op) { var arg1 = _context.Data[1]; var arg2 = _context.Data[0]; var key = OperatorDispatchKey.CreateFromArgs(op, arg1, arg2); OperatorImplementation opImpl; if (!OperatorImplementations.TryGetValue(key, out opImpl)) { opImpl = _runtime.AddOperatorImplementation(OperatorImplementations, key); } if (opImpl != null) { try { var result = opImpl.Evaluate(arg1, arg2); _context.Data.Replace(2, result); return; } catch (OverflowException) { if (TryConvertArgsOnOverflow(opImpl.BaseType)) { ExecuteBinaryOperator(op); //call self recursively, now with new arg types return; } throw; } //catch } //if //Treating as normal call - first comes implementor (arg1), then argument (ag2); something like: // a + b => a._add(b) //ExecuteMethod(arg1, op, 1); _context.ThrowError(Resources.ErrOpNotImplemented, op); }//method
private OperatorImplementation FindBaseImplementation(ExpressionType op, Type commonType) { var baseKey = new OperatorDispatchKey(op, commonType, commonType); OperatorImplementations.TryGetValue(baseKey, out OperatorImplementation baseImpl); return(baseImpl); }
protected void AddImplementation(string op, Type baseType, BinaryOperatorMethod baseMethod, TypeConverter resultConverter) { var key = OperatorDispatchKey.CreateFromTypes(op, baseType, baseType); var imp = new OperatorImplementation(key, baseType, baseMethod, null, null, resultConverter); _baseOperatorImplementations.Add(key, imp); }
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); }
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); }
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); }
//Constructor for unary operators and type converters public OperatorImplementation(OperatorDispatchKey key, Type type, UnaryOperatorMethod method) { Key = key; CommonType = type; Arg1Converter = method; Arg2Converter = null; ResultConverter = null; BaseBinaryMethod = null; }
protected virtual OperatorImplementation CreateBinaryOperatorImplementation(ExpressionType op, Type arg1Type, Type arg2Type, Type commonType, BinaryOperatorMethod method, UnaryOperatorMethod resultConverter) { var key = new OperatorDispatchKey(op, arg1Type, arg2Type); var arg1Converter = arg1Type == commonType ? null : GetConverter(arg1Type, commonType); var arg2Converter = arg2Type == commonType ? null : GetConverter(arg2Type, commonType); var impl = new OperatorImplementation(key, commonType, method, arg1Converter, arg2Converter, resultConverter); return(impl); }
public OperatorImplementation(OperatorDispatchKey key, Type baseType, BinaryOperatorMethod baseMethod, TypeConverter arg1Converter, TypeConverter arg2Converter, TypeConverter resultConverter) { Key = key; BaseType = baseType; Arg1Converter = arg1Converter; Arg2Converter = arg2Converter; ResultConverter = resultConverter; BaseMethod = baseMethod; SetupEvaluationMethod(); }
// 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); return(!OperatorImplementations.TryGetValue(key, out OperatorImplementation impl) ? null : impl.Arg1Converter); }
//Constructor for binary operators public OperatorImplementation(OperatorDispatchKey key, Type resultType, BinaryOperatorMethod baseBinaryMethod, UnaryOperatorMethod arg1Converter, UnaryOperatorMethod arg2Converter, UnaryOperatorMethod resultConverter) { Key = key; CommonType = resultType; Arg1Converter = arg1Converter; Arg2Converter = arg2Converter; ResultConverter = resultConverter; BaseBinaryMethod = baseBinaryMethod; SetupEvaluationMethod(); }
private object ConvertValue(object value, Type toType) { var key = OperatorDispatchKey.CreateForTypeConverter(value.GetType(), toType); TypeConverter converter; if (_runtime.TypeConverters.TryGetValue(key, out converter)) { var result = converter.Invoke(value); return(result); } throw new Exception(string.Format("Failed to convert value '%1' to type %2.", value, toType)); }
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 } }
/* * public virtual FunctionBindingInfo GetFunctionBindingInfo(string name, AstNodeList parameters) { * return FunctionBindings.Find(name, parameters.Count); * } * //Utility methods for adding library functions * public FunctionBindingInfo AddFunction(string name, int paramCount) { * return null; * } * public FunctionBindingInfo AddFunction(string name, int paramCount, FunctionFlags flags) { * FunctionBindingInfo info = new FunctionBindingInfo(name, paramCount, null, flags); * FunctionBindings.Add(name, info); * return info; * } */ #region Operator implementations // When an implementation for exact type pair is not found, we find implementation for base type and create // implementation for exact types using type converters public virtual OperatorImplementation AddOperatorImplementation(OperatorImplementationTable implementations, OperatorDispatchKey forKey) { Type baseType = GetBaseTypeForExpression(forKey.OpSymbol, forKey.Arg1Type, forKey.Arg2Type); if (baseType == null) { return(null); } TypeConverter arg1Converter = GetConverter(forKey.Arg1Type, baseType); TypeConverter arg2Converter = GetConverter(forKey.Arg2Type, baseType); //Get base method for the operator and common type var baseKey = OperatorDispatchKey.CreateFromTypes(forKey.OpSymbol, baseType, baseType); OperatorImplementation baseImpl; if (!_baseOperatorImplementations.TryGetValue(baseKey, out baseImpl)) { throw new Exception(string.Format(Resources.ErrOpNotDefinedForTypes, forKey.OpSymbol, forKey.Arg1Type, forKey.Arg2Type)); } var impl = new OperatorImplementation(forKey, baseType, baseImpl.BaseMethod, arg1Converter, arg2Converter, baseImpl.ResultConverter); implementations[forKey] = 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