Exemplo n.º 1
0
        /// <summary>
        /// Checks that the given unifier is valid in terms of the type definitions.
        /// </summary>
        private bool IsUnifierValid(UnificationResult unifier, TrsTermBase matchedRuleHead)
        {
            // Variables at this level must be validated in a way that is sensitive to AC term type definitions
            // to account for semantics. If it is not add[:x,:y] will not match add[1,2,3] with limit :x,:y to $TrsNumber
            if (!unifier.Succeed)
            {
                return(false);
            }
            if (unifier.Unifier.Count == 0)
            {
                return(true);                      // equal terms, nothing to validate
            }
            // Keep track of variable parent cases
            Stack <TrsTermBase>            evalStack     = new Stack <TrsTermBase>();
            Dictionary <TrsVariable, bool> isAcParent    = new Dictionary <TrsVariable, bool>();
            Dictionary <TrsVariable, bool> isNonAcParent = new Dictionary <TrsVariable, bool>();
            Dictionary <TrsVariable, HashSet <string> > variableTermNames = new Dictionary <TrsVariable, HashSet <string> >();

            evalStack.Push(matchedRuleHead);
            Action <TrsVariable, bool, Dictionary <TrsVariable, bool> > updateLookups =
                delegate(TrsVariable v, bool b, Dictionary <TrsVariable, bool> target)
            {
                if (target.ContainsKey(v))
                {
                    target[v] = b;
                }
                else
                {
                    target.Add(v, b);
                }
            };

            while (evalStack.Count > 0)
            {
                var current = evalStack.Pop();
                // Variable only case ... this should not happen unless variable only reduction rule heads are allowed in the future
                var currentVariable = current as TrsVariable;
                if (currentVariable != null)
                {
                    updateLookups(currentVariable, false, isAcParent);
                    updateLookups(currentVariable, false, isNonAcParent);
                }
                else
                {
                    // Check arguments
                    var curTerm   = current as TrsTerm;
                    var curAcTerm = current as TrsAcTerm;
                    foreach (var variable in Enumerable.Concat(curTerm == null ? new TrsVariable[0] : curTerm.Arguments.Where(arg => arg is TrsVariable).Cast <TrsVariable>(),
                                                               curAcTerm == null ? new TrsVariable[0] : curAcTerm.OnfArguments.Where(arg => arg.Term is TrsVariable).Select(arg => arg.Term).Cast <TrsVariable>()))
                    {
                        updateLookups(variable, curTerm != null, isNonAcParent);
                        updateLookups(variable, curAcTerm != null, isAcParent);
                        if (curAcTerm != null)
                        {
                            HashSet <string> termNames;
                            if (!variableTermNames.TryGetValue(variable, out termNames))
                            {
                                variableTermNames.Add(variable, termNames = new HashSet <string>());
                            }
                            termNames.Add(curAcTerm.Name);
                        }
                    }
                }
            }

            bool isValid = true;

            foreach (var substitution in unifier.Unifier)
            {
                // It is possible that the variable being tested does not occur in the term head ...
                if (!isNonAcParent.ContainsKey(substitution.Variable) &&
                    !isAcParent.ContainsKey(substitution.Variable))
                {
                    isValid = isValid && typeChecker.IsSubstitutionValid(substitution);
                    continue;
                }

                // AC term case
                if (isNonAcParent.ContainsKey(substitution.Variable) &&
                    isNonAcParent[substitution.Variable])
                {
                    isValid = isValid && typeChecker.IsSubstitutionValid(substitution);
                }

                // Non-AC term case
                if (isAcParent.ContainsKey(substitution.Variable) &&
                    isAcParent[substitution.Variable])
                {
                    var acSubstitutionTerm = substitution.SubstitutionTerm as TrsAcTerm;
                    if (acSubstitutionTerm == null ||
                        !variableTermNames[substitution.Variable].Contains(acSubstitutionTerm.Name))
                    {
                        isValid = isValid && typeChecker.IsSubstitutionValid(substitution);
                    }
                    else
                    {
                        // In this case, test each nested argument of the AC substitution term to match the term head variable.
                        // This is due to the ONF convertion for AC terms. It keeps type checking in line with AC semantics.
                        foreach (var argTerm in acSubstitutionTerm.OnfArguments.Select(arg => arg.Term))
                        {
                            var testSubstitution = new Substitution {
                                Variable = substitution.Variable, SubstitutionTerm = argTerm
                            };
                            isValid = isValid && typeChecker.IsSubstitutionValid(testSubstitution);
                        }
                    }
                }
            }
            return(isValid);
        }