// expand an ambiguous direction throughout a rule // error if more than one in pattern IList <AtomicRule> ExpandDirectionMulti(AtomicRule oldrule, Direction olddir) { var pcells = oldrule.Patterns.SelectMany(p => p.Cells .SelectMany(c => c.Where(a => a.Direction == olddir))); if (pcells.Count() != 1) { _parser.CompileError("'{0}' in action cannot be matched", olddir); } // expand one rule per single direction var newrules = new List <AtomicRule>(); foreach (var newdir in _expanddirlookup[olddir]) { var newrule = oldrule.Clone(); for (var riter = new RuleIterator { Rule = oldrule }; !riter.Done; riter.Step()) { newrule.Patterns[riter.SubRuleIndex].Cells[riter.CellIndex] = ReplaceDirection(riter.PatternAtoms, olddir, newdir); newrule.Actions[riter.SubRuleIndex].Cells[riter.CellIndex] = ReplaceDirection(riter.ActionAtoms, olddir, newdir); } newrules.AddRange(ExpandRule(newrule)); } return(newrules); }
// expand an OR symbol throughout a rule // error if more than one in pattern IList <AtomicRule> ExpandSymbolMulti(AtomicRule oldrule, ObjectSymbol oldsym) { var pcells = oldrule.Patterns.SelectMany(p => p.Cells .SelectMany(c => c.Where(a => a.Symbol == oldsym && !a.IsNegated))); if (pcells.Count() != 1) { return(null); } // expand one rule per object id var newrules = new List <AtomicRule>(); foreach (var newobj in oldsym.ObjectIds) { var newrule = oldrule.Clone(); for (var riter = new RuleIterator { Rule = oldrule }; !riter.Done; riter.Step()) { newrule.Patterns[riter.SubRuleIndex].Cells[riter.CellIndex] = ReplaceObject(riter.PatternAtoms, oldsym, newobj); newrule.Actions[riter.SubRuleIndex].Cells[riter.CellIndex] = ReplaceObject(riter.ActionAtoms, oldsym, newobj); } newrules.AddRange(ExpandRule(newrule)); } return(newrules); }
// limited substitution of pattern direction IList <AtomicRule> ExpandDirectionSingle(RuleIterator riter, Direction olddir) { var newrules = new List <AtomicRule>(); foreach (var newdir in _expanddirlookup[olddir]) { var newrule = riter.Rule.Clone(); newrule.Patterns[riter.SubRuleIndex].Cells[riter.CellIndex] = ReplaceDirection(riter.PatternAtoms, olddir, newdir); if (riter.HasAction) { newrule.Actions[riter.SubRuleIndex].Cells[riter.CellIndex] = ReplaceDirection(riter.ActionAtoms, olddir, newdir); } newrules.AddRange(ExpandRule(newrule)); } return(newrules); }
// expand ambiguous directions in rule pattern known to have no matching action // replacing by individuals (absolute or relative) // abs could be fixed by more powerful vm code IList <AtomicRule> ExpandDirectionSimple(AtomicRule oldrule) { for (var riter = new RuleIterator { Rule = oldrule }; !riter.Done; riter.Step()) { // look for any ambiguous unmatched pattern directions, just one each time var patom = riter.PatternAtoms.FirstOrDefault(a => _expanddirlookup.ContainsKey(a.Direction)); if (patom != null) { return(ExpandDirectionSingle(riter, patom.Direction)); } } return(new List <AtomicRule> { oldrule }); }
// expand a rule where an occurrence on an action does not match its pattern // replacing combination directions and symbols by individuals (absolute or relative) // could be fixed by more powerful vm code IList <AtomicRule> ExpandRule(AtomicRule oldrule) { if (!oldrule.HasAction) { return(ExpandDirectionSimple(oldrule)); } // check each cell of each subrule for (var riter = new RuleIterator { Rule = oldrule }; !riter.Done; riter.Step()) { // Do no expansion on random actions if (riter.ActionAtoms.Any(a => a.IsRandom)) { oldrule.Prefixes.Add(RulePrefix.Final); } else { // check for action atom with ambiguous direction and no matching pattern atom var datom = riter.ActionAtoms.FirstOrDefault(a => _expanddirlookup.ContainsKey(a.Direction) && !riter.PatternAtoms.Any(p => p.Matches(a) && p.Direction == a.Direction)); if (datom != null) { return(ExpandDirectionMulti(oldrule, datom.Direction)); } // check for action atom with property symbol and no matching pattern atom var satom = riter.ActionAtoms.FirstOrDefault(a => a.Symbol.Kind == SymbolKind.Property && !a.IsNegated && !a.IsRandom && !riter.PatternAtoms.Any(p => p.Matches(a))); if (satom != null) { var newrules = ExpandSymbolMulti(oldrule, satom.Symbol) ?? ExpandPropertyMatcher(riter); if (newrules == null) { _parser.CompileError("'{0}' in action cannot be matched", satom.Symbol.Name); } else { return(newrules); } } } } return(ExpandDirectionSimple(oldrule)); }
// look for matching property objects in pattern and action, expand matching pairwise IList <AtomicRule> ExpandPropertyMatcher(RuleIterator riter) { var patom = riter.PatternAtoms.FirstOrDefault(a => a.Symbol.Kind == SymbolKind.Property && !a.IsNegated && !a.IsRandom); var aatom = riter.ActionAtoms.FirstOrDefault(a => a.Symbol.Kind == SymbolKind.Property && !a.IsNegated && !a.IsRandom); if (patom != null && aatom != null && patom.Symbol.ObjectIds.Count == aatom.Symbol.ObjectIds.Count) { var newrules = new List <AtomicRule>(); for (int i = 0; i < patom.Symbol.ObjectIds.Count; i++) { var newrule = riter.Rule.Clone(); newrule.Prefixes.Add(RulePrefix.Final); newrule.Patterns[riter.SubRuleIndex].Cells[riter.CellIndex] = ReplaceObject(riter.PatternAtoms, patom.Symbol, patom.Symbol.ObjectIds[i]); newrule.Actions[riter.SubRuleIndex].Cells[riter.CellIndex] = ReplaceObject(riter.ActionAtoms, aatom.Symbol, aatom.Symbol.ObjectIds[i]); newrules.Add(newrule); } return(newrules); } return(null); }