Пример #1
0
 public static UnaryExpression GetParamsList(StandardRule <T> rule)
 {
     return(Ast.Convert(
                rule.Parameters[rule.ParameterCount - 1],
                typeof(IList <object>)
                ));
 }
Пример #2
0
        public override RuleSet <T> AddRule(StandardRule <T> newRule)
        {
            // Can the rule become invalidated between its creation and
            // its insertion into the set?
            Debug.Assert(newRule.IsValid, "Adding an invalid rule");

            IList <StandardRule <T> > newRules = new List <StandardRule <T> >();

            newRules.Add(newRule);
            foreach (StandardRule <T> rule in _rules)
            {
                if (rule.IsValid)
                {
                    newRules.Add(rule);
                }
            }

            if (newRules.Count > MaxRules)
            {
                return(EmptyRuleSet <T> .FixedInstance);
            }
            else
            {
                return(new SmallRuleSet <T>(newRules));
            }
        }
Пример #3
0
        public StandardRule <T> GetRule <T>(CodeContext callerContext, DynamicAction action, object[] args)
        {
            Contract.RequiresNotNull(action, "action");
            //Debug.Assert(action.Kind != ActionKind.GetMember || ((GetMemberAction)action).Name != SymbolTable.StringToId("x"));

            StandardRule <T> rule = _ruleCache.FindRule <T>(callerContext, action, args);

            if (rule != null)
            {
                return(rule);
            }

            NoteRuleCreation(action, args);

            IDynamicObject ndo = args[0] as IDynamicObject;

            if (ndo != null)
            {
                rule = ndo.GetRule <T>(action, callerContext, args);
                Debug.Assert(rule == null || rule.Target != null && rule.Test != null);
            }

            rule = rule ?? MakeRule <T>(callerContext, action, args);
            Debug.Assert(rule != null && rule.Target != null && rule.Test != null);
#if DEBUG
            AstWriter.Dump(rule);
#endif
            return(rule);
        }
Пример #4
0
        /// <summary>
        /// Internal helper to produce the actual expression used for the error when emitting
        /// the error into a rule.
        /// </summary>
        public Statement MakeErrorForRule(StandardRule rule, ActionBinder binder) {
            if (_value != null) {
                rule.IsError = true;
                return rule.MakeReturn(binder, _value);
            }

            return rule.MakeError(_exception);
        } 
Пример #5
0
 /// <summary>
 /// Provides a way for the binder to provide a custom error message when lookup fails.  Just
 /// doing this for the time being until we get a more robust error return mechanism.
 /// </summary>
 public virtual Statement MakeReadOnlyMemberError <T>(StandardRule <T> rule, Type type, string name)
 {
     return(rule.MakeError(
                Ast.Ast.New(
                    typeof(MissingMemberException).GetConstructor(new Type[] { typeof(string) }),
                    Ast.Ast.Constant(name)
                    )
                ));
 }
Пример #6
0
        /// <summary>
        /// Internal helper to produce the actual expression used for the error when emitting
        /// the error into a rule.
        /// </summary>
        public Statement MakeErrorForRule(StandardRule rule, ActionBinder binder)
        {
            if (_value != null)
            {
                rule.IsError = true;
                return(rule.MakeReturn(binder, _value));
            }

            return(rule.MakeError(_exception));
        }
Пример #7
0
 public override RuleSet <T> AddRule(StandardRule <T> newRule)
 {
     if (_supportAdding)
     {
         return(newRule.MonomorphicRuleSet);
     }
     else
     {
         return(this);
     }
 }
Пример #8
0
        /// <summary>
        /// Gets a rule, updates the site that called, and then returns the result of executing the rule.
        /// </summary>
        /// <typeparam name="T">The type of the DynamicSite the rule is being produced for.</typeparam>
        /// <param name="action">The Action the rule is being produced for.</param>
        /// <param name="args">The arguments to the rule as provided from the call site at runtime.</param>
        /// <param name="callerContext">The CodeContext that is requesting the rule and that should be used for conversions.</param>
        /// <param name="rules"></param>
        /// <param name="site"></param>
        /// <param name="target"></param>
        /// <returns>The result of executing the rule.</returns>
        internal object UpdateSiteAndExecute <T>(CodeContext callerContext, DynamicAction action, object[] args, object site, ref T target, ref RuleSet <T> rules)
        {
            Contract.RequiresNotNull(action, "action");
            //Debug.Assert(action.Kind != ActionKind.GetMember || ((GetMemberAction)action).Name != SymbolTable.StringToId("x"));
            object result;

            StandardRule <T> rule = _ruleCache.ExecuteRuleAndUpdateSite <T>(callerContext, action, args, site, ref target, ref rules, out result);

            if (rule != null)
            {
                return(result);
            }

            NoteRuleCreation(action, args);

            for (; ;)
            {
                IDynamicObject ndo = args[0] as IDynamicObject;
                if (ndo != null)
                {
                    rule = ndo.GetRule <T>(action, callerContext, args);
                    Debug.Assert(rule == null || rule.Target != null && rule.Test != null);
                }

                rule = rule ?? MakeRule <T>(callerContext, action, args);
                Debug.Assert(rule != null && rule.Target != null && rule.Test != null);
#if DEBUG
                AstWriter.Dump(rule);
#endif
                object[] callArgs = args;
                if (args.Length > 6)
                {
                    // BigDynamicSite
                    callArgs = new object[] { Tuple.MakeTuple(rule.ParamVariables[0].Type, args) };
                }

                CodeContext tmpCtx = callerContext.Scope.GetTemporaryVariableContext(callerContext, rule.ParamVariables, callArgs);
                try {
                    if ((bool)rule.Test.Evaluate(tmpCtx))
                    {
                        if (site != null)
                        {
                            DynamicSiteHelpers.UpdateSite <T>(callerContext, site, ref target, ref rules, rule);
                        }

                        _ruleCache.AddRule(action, args, rule);

                        return(rule.Target.Execute(tmpCtx));
                    }
                } finally {
                    tmpCtx.Scope.TemporaryStorage.Clear();
                }
            }
        }
Пример #9
0
        /// <summary>
        /// Updates the provided rule to use the previously created templated rule with the newly provided parameters.
        /// </summary>
        public void CopyTemplateToRule(CodeContext context, StandardRule <T> rule)
        {
            if (_rule.TemplateParameterCount != rule.TemplateParameterCount)
            {
                throw new ArgumentException(String.Format("Incompatible rules.  Expected {0} template parameters, got {1}", _rule.TemplateParameterCount, rule.TemplateParameterCount));
            }

            Delegate existingDelegate = (Delegate)(object)_rule.MonomorphicRuleSet.GetOrMakeTarget(context);

            rule.MonomorphicRuleSet.RawTarget = CloneDelegate(rule.TemplateData, existingDelegate);
        }
Пример #10
0
 public static Expression MakeParamsTest(StandardRule <T> rule, object paramArg, Expression listArg)
 {
     return(Ast.AndAlso(
                Ast.TypeIs(listArg, typeof(ICollection <object>)),
                Ast.Equal(
                    Ast.ReadProperty(
                        Ast.Convert(listArg, typeof(ICollection <object>)),
                        typeof(ICollection <object>).GetProperty("Count")
                        ),
                    rule.AddTemplatedConstant(typeof(int), ((IList <object>)paramArg).Count)
                    )
                ));
 }
        public Tret UpdateBindingAndInvoke(CodeContext context, T0 arg0)
        {
            StandardRule <BigDynamicSiteTarget <T0, Tret> > rule = _rules.GetRule(context, arg0);

            if (rule != null)
            {
                // site is truly polymorphic, build the polymorphic method
                _target = _rules.GetOrMakeTarget(context);
                return(_target(this, context, arg0));
            }

            return((Tret)context.LanguageContext.Binder.UpdateSiteAndExecute <BigDynamicSiteTarget <T0, Tret> >(context, Action, Tuple.GetTupleValues(arg0), this, ref _target, ref _rules));
        }
Пример #12
0
        public MethodBinderContext(ActionBinder actionBinder
#if FULL
, StandardRule rule 
#endif
)
        {
            _actionBinder = actionBinder;

#if FULL
 _rule = rule; 
#endif

        }
        public Tret UpdateBindingAndInvoke(T0 arg0)
        {
            StandardRule <FastDynamicSiteTarget <T0, Tret> > rule = _rules.GetRule(Context, arg0);

            if (rule != null)
            {
                // site is truly polymorphic, build the polymorphic method
                _target = _rules.GetOrMakeTarget(Context);
                return(_target(this, arg0));
            }


            return((Tret)Context.LanguageContext.Binder.UpdateSiteAndExecute <FastDynamicSiteTarget <T0, Tret> >(Context, Action, new object[] { arg0 }, this, ref _target, ref _rules));
        }
Пример #14
0
 /// <summary>
 /// Sees if the target is implemented with ActionOnCallAttribute and if so attempts to get a rule from the attribute.
 /// </summary>
 /// <returns>True if the method implements ActionOnCall, false if not.</returns>
 private bool MakeActionOnCallRule(MethodBase target)
 {
     // see if the method provides a custom inline action
     object[] attrs = target.GetCustomAttributes(typeof(ActionOnCallAttribute), false);
     if (attrs.Length > 0)
     {
         StandardRule <T> rule = ((ActionOnCallAttribute)attrs[0]).GetRule <T>(Context, _args);
         if (rule != null)
         {
             _rule = rule;
             return(true);
         }
     }
     return(false);
 }
Пример #15
0
        public static Expression MakeNecessaryTests(StandardRule <T> rule, IList <Type[]> necessaryTests, Expression [] arguments)
        {
            Expression typeTest = Ast.Constant(true);

            if (necessaryTests.Count > 0)
            {
                Type[] testTypes = null;

                for (int i = 0; i < necessaryTests.Count; i++)
                {
                    if (necessaryTests[i] == null)
                    {
                        continue;
                    }
                    if (testTypes == null)
                    {
                        testTypes = new Type[necessaryTests[i].Length];
                    }

                    for (int j = 0; j < necessaryTests[i].Length; j++)
                    {
                        if (testTypes[j] == null || testTypes[j].IsAssignableFrom(necessaryTests[i][j]))
                        {
                            // no test yet or more specific test
                            testTypes[j] = necessaryTests[i][j];
                        }
                    }
                }

                if (testTypes != null)
                {
                    for (int i = 0; i < testTypes.Length; i++)
                    {
                        if (testTypes[i] != null)
                        {
                            Debug.Assert(i < arguments.Length);
                            typeTest = Ast.AndAlso(typeTest, rule.MakeTypeTest(testTypes[i], arguments[i]));
                        }
                    }
                }
            }
            return(typeTest);
        }
Пример #16
0
        public MemberBinderHelper(CodeContext context, TActionKind action, object [] args)
            : base(context, action)
        {
            Contract.RequiresNotNull(args, "args");
            if (args.Length == 0)
            {
                throw new ArgumentException("args must have at least one member");
            }

            _args = args;

            _target = args[0];
            if (CompilerHelpers.IsStrongBox(_target))
            {
                _strongBoxType = _target.GetType();
                _target        = ((IStrongBox)_target).Value;
            }

            _rule = new StandardRule <T>();
        }
Пример #17
0
        public override StandardRule <T> GetRule(CodeContext context, params object[] args)
        {
            context = DynamicSiteHelpers.GetEvaluationContext <T>(context, ref args);

            for (int i = 0; i < _rules.Count; i++)
            {
                StandardRule <T> rule = _rules[i];
                if (!rule.IsValid)
                {
                    continue;
                }

                CodeContext tmpCtx = context.Scope.GetTemporaryVariableContext(context, rule.ParamVariables, args);
                try {
                    if ((bool)rule.Test.Evaluate(tmpCtx))
                    {
                        return(rule);
                    }
                } finally {
                    tmpCtx.Scope.TemporaryStorage.Clear();
                }
            }
            return(null);
        }
Пример #18
0
        public virtual Statement MakeInvalidParametersError(MethodBinder binder, DynamicAction action, CallType callType, IList <MethodBase> targets, StandardRule rule, object [] args)
        {
            int  minArgs = Int32.MaxValue;
            int  maxArgs = Int32.MinValue;
            int  maxDflt = Int32.MinValue;
            int  argsProvided = args.Length - 1; // -1 to remove the object we're calling
            bool hasArgList = false, hasNamedArgument = false;
            Dictionary <string, bool> namedArgs = new Dictionary <string, bool>();

            CallAction ca = action as CallAction;

            if (ca != null)
            {
                hasNamedArgument = ca.Signature.HasNamedArgument();
                int dictArgIndex = ca.Signature.IndexOf(ArgumentKind.Dictionary);

                if (dictArgIndex > -1)
                {
                    argsProvided--;
                    IAttributesCollection iac = args[dictArgIndex + 1] as IAttributesCollection;
                    if (iac != null)
                    {
                        foreach (KeyValuePair <object, object> kvp in iac)
                        {
                            namedArgs[(string)kvp.Key] = false;
                        }
                    }
                }

                argsProvided += GetParamsArgumentCountAdjust(ca, args);
                foreach (SymbolId si in ca.Signature.GetArgumentNames())
                {
                    namedArgs[SymbolTable.IdToString(si)] = false;
                }
            }
            else
            {
                maxArgs = minArgs = rule.Parameters.Length;
                maxDflt = 0;
            }

            foreach (MethodBase mb in targets)
            {
                if (callType == CallType.ImplicitInstance && CompilerHelpers.IsStatic(mb))
                {
                    continue;
                }

                ParameterInfo[] pis  = mb.GetParameters();
                int             cnt  = pis.Length;
                int             dflt = 0;

                if (!CompilerHelpers.IsStatic(mb) && callType == CallType.None)
                {
                    cnt++;
                }

                foreach (ParameterInfo pi in pis)
                {
                    if (pi.ParameterType == typeof(CodeContext))
                    {
                        cnt--;
                    }
                    else if (CompilerHelpers.IsParamArray(pi))
                    {
                        cnt--;
                        hasArgList = true;
                    }
                    else if (CompilerHelpers.IsParamDictionary(pi))
                    {
                        cnt--;
                    }
                    else if (!CompilerHelpers.IsMandatoryParameter(pi))
                    {
                        dflt++;
                        cnt--;
                    }

                    namedArgs[pi.Name] = true;
                }

                minArgs = System.Math.Min(cnt, minArgs);
                maxArgs = System.Math.Max(cnt, maxArgs);
                maxDflt = System.Math.Max(dflt, maxDflt);
            }

            foreach (KeyValuePair <string, bool> kvp in namedArgs)
            {
                if (kvp.Value == false)
                {
                    // unbound named argument.
                    return(rule.MakeError(
                               Ast.Ast.Call(
                                   typeof(RuntimeHelpers).GetMethod("TypeErrorForExtraKeywordArgument"),
                                   Ast.Ast.Constant(binder._name, typeof(string)),
                                   Ast.Ast.Constant(kvp.Key, typeof(string))
                                   )
                               ));
                }
            }

            return(rule.MakeError(
                       Ast.Ast.Call(
                           typeof(RuntimeHelpers).GetMethod("TypeErrorForIncorrectArgumentCount", new Type[] {
                typeof(string), typeof(int), typeof(int), typeof(int), typeof(int), typeof(bool), typeof(bool)
            }),
                           Ast.Ast.Constant(binder._name, typeof(string)), // name
                           Ast.Ast.Constant(minArgs),                      // min formal normal arg cnt
                           Ast.Ast.Constant(maxArgs),                      // max formal normal arg cnt
                           Ast.Ast.Constant(maxDflt),                      // default cnt
                           Ast.Ast.Constant(argsProvided),                 // args provided
                           Ast.Ast.Constant(hasArgList),                   // hasArgList
                           Ast.Ast.Constant(hasNamedArgument)              // kwargs provided
                           )
                       ));
        }
Пример #19
0
 public abstract RuleSet <T> AddRule(StandardRule <T> newRule);
Пример #20
0
 public void AddRule <T>(object[] args, StandardRule <T> newRule)
 {
     GetOrMakeTree <T>().AddRule(args, newRule);
 }
Пример #21
0
        protected Expression[] GetICallableParameters(Type t, StandardRule <T> rule)
        {
            List <Expression> plainArgs = new List <Expression>();
            List <KeyValuePair <SymbolId, Expression> > named = new List <KeyValuePair <SymbolId, Expression> >();
            Expression splat = null, kwSplat = null;
            Expression instance = null;

            for (int i = 1; i < rule.Parameters.Length; i++)
            {
                switch (Action.Signature.GetArgumentKind(i - 1))
                {
                case ArgumentKind.Simple: plainArgs.Add(rule.Parameters[i]); break;

                case ArgumentKind.List: splat = rule.Parameters[i]; break;

                case ArgumentKind.Dictionary: kwSplat = rule.Parameters[i]; break;

                case ArgumentKind.Named: named.Add(new KeyValuePair <SymbolId, Expression>(Action.Signature.GetArgumentName(i - 1), rule.Parameters[i])); break;

                case ArgumentKind.Instance: instance = rule.Parameters[i]; break;

                case ArgumentKind.Block:
                default:
                    throw new NotImplementedException();
                }
            }

            Expression argsArray = Ast.NewArrayHelper(typeof(object[]), plainArgs.ToArray());

            if (splat != null)
            {
                argsArray = Ast.Call(
                    typeof(BinderOps).GetMethod("GetCombinedParameters"),
                    argsArray,
                    Ast.ConvertHelper(splat, typeof(object))
                    );
            }

            if (kwSplat != null || named.Count > 0)
            {
                // IFancyCallable.Call(context, args, names)
                Debug.Assert(instance == null); // not supported, no IFancyCallableWithInstance
                Expression names;

                if (named.Count > 0)
                {
                    List <Expression> constNames  = new List <Expression>();
                    List <Expression> namedValues = new List <Expression>();
                    foreach (KeyValuePair <SymbolId, Expression> kvp in named)
                    {
                        constNames.Add(Ast.Constant(SymbolTable.IdToString(kvp.Key)));
                        namedValues.Add(kvp.Value);
                    }

                    argsArray = Ast.Call(
                        typeof(BinderOps).GetMethod("GetCombinedParameters"),
                        argsArray,
                        Ast.NewArrayHelper(typeof(object[]), namedValues.ToArray())
                        );

                    names = Ast.NewArrayHelper(typeof(string[]), constNames.ToArray());
                }
                else
                {
                    names = Ast.Null(typeof(string[]));
                }

                if (kwSplat != null)
                {
                    Variable namesVar = rule.GetTemporary(typeof(string[]), "names");
                    argsArray = Ast.Comma(
                        Ast.Assign(namesVar, names),
                        Ast.Call(
                            typeof(BinderOps).GetMethod("GetCombinedKeywordParameters"),
                            argsArray,
                            Ast.ConvertHelper(kwSplat, typeof(IAttributesCollection)),
                            Ast.Read(namesVar)
                            )
                        );

                    return(new Expression[] { Ast.CodeContext(), argsArray, Ast.Read(namesVar) });
                }
                return(new Expression[] { Ast.CodeContext(), argsArray, names });
            }

            // ICallable.Call(context, args)
            if (instance != null && typeof(ICallableWithThis).IsAssignableFrom(t))
            {
                return(new Expression[] { Ast.CodeContext(), instance, argsArray });
            }

            return(new Expression[] { Ast.CodeContext(), argsArray });
        }
Пример #22
0
        /// <summary>
        /// Creates a call to this MethodTarget with the specified parameters.  Casts are inserted to force
        /// the types to the provided known types.
        /// </summary>
        /// <param name="binder"></param>
        /// <param name="rule"></param>
        /// <param name="parameters"></param>
        /// <param name="knownTypes"></param>
        /// <returns></returns>
        public Expression MakeExpression(ActionBinder binder, StandardRule rule, Expression[] parameters, Type[] knownTypes) {
            Expression[] args = parameters;
            if (knownTypes != null) {
                args = new Expression[parameters.Length];
                for (int i = 0; i < args.Length; i++) {
                    args[i] = parameters[i];
                    if (knownTypes[i] != null && !knownTypes[i].IsAssignableFrom(parameters[i].Type)) {
                        args[i] = Ast.Convert(parameters[i], CompilerHelpers.GetVisibleType(knownTypes[i]));
                    }
                }
            }

            return MakeExpression(binder, rule, args);
        } 
Пример #23
0
public Expression MakeExpression(ActionBinder binder, StandardRule rule, Expression[] parameters) {
            MethodBinderContext context = new MethodBinderContext(binder, rule);

            Expression check = Ast.True();
            if (_binder.IsBinaryOperator) {
                // TODO: only if we have a narrowing level

                // need to emit check to see if args are convertible...
                for (int i = 0; i < _argBuilders.Count; i++) {
                    Expression checkedExpr = _argBuilders[i].CheckExpression(context, parameters);
                    if(checkedExpr != null) {
                        check = Ast.AndAlso(check, checkedExpr);
                    }
                }
            }

            Expression[] args = new Expression[_argBuilders.Count];
            for (int i = 0; i < _argBuilders.Count; i++) {
                args[i] = _argBuilders[i].ToExpression(context, parameters);
            }

            MethodInfo mi = Method as MethodInfo;
            Expression ret, call;
            if (!Method.IsPublic || !Method.DeclaringType.IsVisible) {
                if (mi != null) {
                    mi = CompilerHelpers.GetCallableMethod(mi);
                }
            }

            if (Method.IsPublic && Method.DeclaringType.IsVisible) {
                // public method
                if (mi != null) {
                    Expression instance = mi.IsStatic ? null : _instanceBuilder.ToExpression(context, parameters);
                    call = Ast.SimpleCallHelper(instance, mi, args);
                } else {
                    call = Ast.SimpleNewHelper((ConstructorInfo)Method, args);
                }
            } else {
                // Private binding, invoke via reflection
                if (mi != null) {
                    Expression instance = mi.IsStatic ? null : _instanceBuilder.ToExpression(context, parameters);
                    call = Ast.Call(
                        Ast.RuntimeConstant(mi),
                        typeof(MethodInfo).GetMethod("Invoke", new Type[] { typeof(object), typeof(object[]) }),
                        Ast.ConvertHelper(instance, typeof(object)),
                        Ast.NewArrayHelper(typeof(object[]), args)
                    );
                } else {
                    call = Ast.Call(
                        Ast.RuntimeConstant((ConstructorInfo)Method),
                        typeof(ConstructorInfo).GetMethod("Invoke", new Type[] { typeof(object[]) }), 
                        Ast.NewArrayHelper(typeof(object[]), args)
                    ); 
                }
            }

            ret = _returnBuilder.ToExpression(context, _argBuilders, parameters, call);

            List<Expression> updates = null;
            for (int i = 0; i < _argBuilders.Count; i++) {                
                Expression next = _argBuilders[i].UpdateFromReturn(context, parameters);
                if (next != null) {
                    if (updates == null) updates = new List<Expression>();
                    updates.Add(next);
                }
            }

            if (updates != null) {
                updates.Insert(0, ret);
                ret = Ast.Comma(0, updates.ToArray());
            }

            if (!check.IsConstant(true)) {
                ret = Ast.Condition(
                    check,
                    Ast.ConvertHelper(ret, typeof(object)),
                    GetNotImplemented()
                );
            }
            return ret;
      } 
Пример #24
0
 public void AddRule(object[] args, StandardRule <T> rule)
 {
     GetRuleList(args).AddLast(rule);
 }
Пример #25
0
        /// <summary>
        /// This function is a little complex:
        ///
        /// 1.	It needs to be thread-safe and atomic.  This means the iteration over the list
        ///     needs to happen w/o releasing a lock, and the tests also get run under lock
        ///     (they’re simple operations and therefore are safe to do this).  But the target
        ///     is not safe to run under a lock because it may block and cause a deadlock.  Therefore
        ///     we need to release the lock before running the target.
        /// 2.	The code for doing the evaluation is a little complex, and the threading issues makes
        ///     it more complex.  Therefore factoring it into a version which just looks for a rule,
        ///     and a version which looks and executes a rule is either going to obscure the locking issues
        ///     or result in a reasonable duplication of code which may be error prone to maintain.
        /// 3.	The updates of the sites needs to happen before the execution of the rule.  This
        ///     is due to both stack overflow and performance issues.  If a function goes recursive and we
        ///     haven’t updated the recursive-call site before then we’ll repeatedly generate and evaluate
        ///     rules until we stack overflow, and if we don’t stack overflow our perf will
        ///     suck until the method unwinds once.
        ///
        /// For those reasons we get the one big method  which takes 7 parameters to handle both updating
        /// and executing.  One of those parameters is the bool flag to indicate that we should execute
        /// the rule (that’s how that decision is made).  3 more are the result of the execution and the
        /// target/rule list to update for the caller.  One more is the site object which we need to lock
        /// on to make the update to the site atomic.  And finally we get the CodeContext which now flows
        /// in instead of having RuleTree hold onto a LanguageContext.  This is because we need
        /// the full CodeContext to execute the test/target and it needs to be the real CodeContext so
        /// we get the proper set of locals/globals flowing through.
        /// </summary>
        private StandardRule <T> GetRuleMaybeExecute(CodeContext callerContext, object[] args, bool execute, object site, ref T target, ref RuleSet <T> rules, out object result)
        {
            // TODO: We can do better granularity than just types.
            LinkedList <StandardRule <T> > ruleList = GetRuleList(args);

            if (DynamicSiteHelpers.IsBigTarget(typeof(T)))
            {
                args = new object[] { Tuple.MakeTuple(typeof(T).GetGenericArguments()[0], args) };
            }

            bool lockReleased = false;
            int  index        = 0;

            Monitor.Enter(ruleList);
            try {
                LinkedListNode <StandardRule <T> > node = ruleList.First;
                while (node != null)
                {
                    StandardRule <T> rule = node.Value;
                    if (!rule.IsValid)
                    {
                        LinkedListNode <StandardRule <T> > nodeToRemove = node;
                        node = node.Next;
                        ruleList.Remove(nodeToRemove);
                        continue;
                    }
                    PerfTrack.NoteEvent(PerfTrack.Categories.RuleEvaluation, "Evaluating " + index++ + " rule in tree");

                    CodeContext tmpCtx = callerContext.Scope.GetTemporaryVariableContext(callerContext, rule.ParamVariables, args);
                    try {
                        if ((bool)rule.Test.Evaluate(tmpCtx))
                        {
                            // Tentative optimization of moving rule to front of list when found
                            ruleList.Remove(node);
                            ruleList.AddFirst(node);

                            if (site != null)
                            {
                                DynamicSiteHelpers.UpdateSite <T>(callerContext, site, ref target, ref rules, rule);
                            }

                            // release the lock for calling the target which may block, we assume
                            // the test performs no synchronization
                            Monitor.Exit(ruleList);
                            lockReleased = true;

                            if (execute)
                            {
                                result = rule.Target.Execute(tmpCtx);
                            }
                            else
                            {
                                result = null;
                            }

                            return(rule);
                        }
                    } finally {
                        tmpCtx.Scope.TemporaryStorage.Clear();
                    }

                    node = node.Next;
                }
            } finally {
                if (!lockReleased)
                {
                    Monitor.Exit(ruleList);
                }
            }


            PerfTrack.NoteEvent(PerfTrack.Categories.Rules, "NoMatch" + index);

            result = null;
            return(null);
        }
Пример #26
0
        internal void AddRule <T>(DynamicAction action, object[] args, StandardRule <T> rule)
        {
            ActionRuleCache actionRuleCache = FindActionRuleCache(action);

            actionRuleCache.AddRule <T>(args, rule);
        }
Пример #27
0
 /// <summary>
 /// Provides a way for the binder to provide a custom error message when lookup fails.  Just
 /// doing this for the time being until we get a more robust error return mechanism.
 /// </summary>
 public virtual Statement MakeUndeletableMemberError <T>(StandardRule <T> rule, Type type, string name)
 {
     return(MakeReadOnlyMemberError <T>(rule, type, name));
 }
Пример #28
0
        internal static void UpdateSite <T>(CodeContext callerContext, object site, ref T target, ref RuleSet <T> rules, StandardRule <T> rule)
        {
            lock (site) {
                bool monomorphic = rules.HasMonomorphicTarget(target);

                rules = rules.AddRule(rule);
                if (monomorphic || rules == EmptyRuleSet <T> .FixedInstance)
                {
                    target = rule.MonomorphicRuleSet.GetOrMakeTarget(callerContext);
                }
                else
                {
                    target = rules.GetOrMakeTarget(callerContext);
                }
            }
        }
Пример #29
0
 internal TemplatedRuleBuilder(StandardRule <T> template)
 {
     _rule = template;
 }