Пример #1
0
        /// <summary>
        /// Associates a trigger with corresponding guards.
        /// </summary>
        /// <param name="trigger">The trigger to associate.</param>
        private void CalculateTriggerDependencies(ProductTrigger trigger)
        {
            var ct     = trigger.PreCondition;
            var gtpost = trigger.PostCondition;
            var gtpre  = ct;

            TraceDependencies("trigger '{0}' conditions [{1}, {2}] ...", trigger.Name, gtpre, gtpost);

            if (!trigger.ModifiedVariables.Any())
            {
                TraceDependencies("  does not modify state.");
                return;
            }

            foreach (var guard in Guards)
            {
                var gg = guard.PreCondition;
                TraceDependencies("  guard '{0}' precondition [{1}] ...", guard.Name, gg);

                var tg = new TriggerGuard(trigger, guard);

                if (guard.Transitions.Any())
                {
                    TraceDependencies("    state change guard ...");
                    if (!guard.ModifiedVariables.Intersect(trigger.ModifiedVariables).Any())
                    {
                        TraceDependencies("    no affected variable.");
                        continue;
                    }

                    var gatepre = Gate.ComposeAND(gtpre, gg);
                    if (gatepre.Type == GateType.Fixed)
                    {
                        TraceDependencies("    precondition does not match.");
                        continue;
                    }

                    var gatepost = Gate.ComposeAND(gtpost, guard.PostCondition);
                    if (gatepost.Type == GateType.Fixed)
                    {
                        TraceDependencies("    postcondition does not match.");
                        continue;
                    }

                    TraceDependencies("    combination ({0}, {1}) handler.", gatepre, gatepost);

                    tg.PreCondition  = gatepre;
                    tg.PostCondition = gatepost;
                }
                else
                {
                    TraceDependencies("    static condition [{0}] ...", gg);

                    Debug.Assert(guard.PreCondition.ID == guard.PostCondition.ID);

                    IGate genter, gleave;

                    if (guard.Type == GuardType.ENTER)
                    {
                        // PRE[trigger] AND NOT POST[guard]
                        // trigger condition met, guard condition not met
                        genter = Gate.ComposeAND(trigger.PreCondition, Gate.Invert(guard.PreCondition));

                        // PRE[trigger] AND PRE[guard]
                        // trigger condition met, guard conditon not met
                        gleave = Gate.ComposeAND(trigger.PostCondition, guard.PostCondition);
                    }
                    else
                    {
                        genter = Gate.ComposeAND(trigger.PreCondition, guard.PreCondition);
                        gleave = Gate.ComposeAND(trigger.PostCondition, Gate.Invert(guard.PostCondition));
                    }

                    var tgenter = genter;
                    var tgleave = gleave;

                    Gate.TraceDependencies(genter, gleave, "guard product");

                    // set all factors not appearing in the trigger to 1
                    genter = ReplaceTransitionVariables(trigger.Transitions, genter, true);
                    gleave = ReplaceTransitionVariables(trigger.Transitions, gleave, true);

                    Gate.TraceDependencies(genter, gleave, "inter product");

                    // set all factors not appearing in the guard to 1
                    genter = ReplaceNonGuardVariables(genter, guard);
                    gleave = ReplaceNonGuardVariables(gleave, guard);

                    /*genter = ReplaceTransitionVariables(guard.Transitions, genter, true);
                    *  gleave = ReplaceTransitionVariables(guard.Transitions, gleave, true);*/

                    Gate.TraceDependencies(genter, gleave, "guard match");

                    //if (genter is FalseGate || gleave is FalseGate)
                    if (genter.Type.IsFixed() || gleave.Type.IsFixed())
                    {
                        TraceDependencies("    condition does not match.");
                        continue;
                    }

                    /*tg.PreCondition = guard.PreCondition;
                     * tg.PostCondition = guard.PostCondition;*/
                    tg.PreCondition  = tgenter;
                    tg.PostCondition = tgleave;

                    Gate.TraceDependencies(tgenter, tgleave, "guard conditions");

                    // see if the transition set is non-empty
                    var transx = trigger.Transitions.Match(genter, gleave).ToArray();
                    if (transx.Length > 0)
                    {
                        if (guard.Type == GuardType.ENTER)
                        {
                            TraceDependencies("    entry handler.");
                        }
                        else if (guard.Type == GuardType.LEAVE)
                        {
                            TraceDependencies("    exit handler.");
                        }
                        else
                        {
                            throw new InvalidOperationException("unexpected guard type.");
                        }
                    }
                    else
                    {
                        TraceDependencies("    transition does not match.");
                        continue;
                    }
                }

                // associate the trigger with the guard and vice versa
                trigger.AddGuard(tg);
            }
        }
Пример #2
0
 internal static IGate Simplify(this IGate gate)
 {
     return(Gate.Simplify(gate));
 }
Пример #3
0
        /// <summary>
        /// Adds a trigger to the state machine.
        /// </summary>
        /// <param name="trigger">The trigger object to add.</param>
        public void AddTrigger(Trigger trigger)
        {
            var e = trigger.Event;

            SetModify();

            try
            {
                TraceDependencies("add trigger '{0}' ...", trigger.Name);

                // ValidateTrigger(trigger);

                var tlist = new List <ProductTrigger>();

                // examinate the precondition ...
                var precondition = trigger.PreCondition;

                if (precondition.Type == GateType.Fixed)
                {
                    // constant
                    if (precondition is FalseGate)
                    {
                        Trace("SMG033: warning: trigger '{0}' precondition is never met.", trigger);
                    }
                    else if (precondition is TrueGate)
                    {
                        Trace("SMG034: warning: trigger '{0}' precondition is always true.", trigger);
                        tlist.Add(new ProductTrigger(trigger));
                    }
                }
                else if (precondition.Type == GateType.OR)
                {
                    // OR combination, split into multiple simple triggers
                    var inputs = precondition.GetInputs();
                    TraceDependencies("split trigger [{0}] into its branches ...", inputs.ToSeparatorList());

                    // analyze conditions
                    // TraceDependencies("{0}", trigger.Transitions.ToDebugString());

                    // split into multiple triggers
                    foreach (var product in inputs)
                    {
                        // extract the transition subset for the guard condition
                        var tset = new TransitionSet(trigger.Transitions, product);
                        TraceDependencies("  transition set of branch [{0}]: {1}", product, tset.ToDebugString());

                        var pre  = ReplaceVariableCondition(tset, product, false);
                        var post = ReplaceVariableCondition(tset, product, true);

                        TraceDependencies("  branch conditions [{0} => {1}].", pre, post);

                        // add branch trigger
                        tlist.Add(new ProductTrigger(trigger, tset, pre, post));
                    }
                }
                else
                {
                    // add original trigger
                    tlist.Add(new ProductTrigger(trigger));
                }

                // process resulting triggers
                foreach (var t1 in tlist)
                {
                    TraceDependencies("product trigger {0} ...", t1);
                    TraceDependencies("  conditions [{0}, {1}] ...", t1.PreCondition, t1.PostCondition);
                    TraceDependencies("  transitions {0}", trigger.Transitions.ToDebugString());

                    t1.Qualify();

                    // check if any existing trigger is conflicting
                    foreach (var existingtrigger in e.Triggers)
                    {
                        // the new trigger precondition must not intersect any existing precondition
                        var product = Gate.ComposeAND(existingtrigger.PreCondition, t1.PreCondition);
                        product = ReplaceTransitionVariables(existingtrigger.Transitions, product, false);
                        if (!product.IsFalse())
                        {
                            throw new CompilerException(ErrorCode.AmbigousPreCondition, "ambigous transition conditions [" +
                                                        existingtrigger.PreCondition + ", " + t1.PreCondition + "].");
                        }
                    }

                    e.Triggers.Add(t1);
                }
            }
            catch (CompilerException ex)
            {
                AddError(ex);
            }
        }