/// <summary> /// Merge two nodes. Both of them become equiualent. /// /// In complex situation, 'secondary' node becomes reference to 'main' node, if it is possible /// </summary> public static void MergeInplace(TicNode main, TicNode secondary) { if (main == secondary) { return; } if (main.State is StateRefTo) { var nonreferenceMain = main.GetNonReference(); var nonreferenceSecondary = secondary.GetNonReference(); MergeInplace(nonreferenceMain, nonreferenceSecondary); return; } if (secondary.GetNonReference() == main) { return; } var res = GetMergedStateOrNull(main.State, secondary.State); if (res == null) { throw TicErrors.CannotMerge(main, secondary); } main.State = res; if (res is ITypeState t && t.IsSolved) { secondary.State = res; return; } main.AddAncestors(secondary.Ancestors.Where(a => a != main)); secondary.ClearAncestors(); secondary.State = new StateRefTo(main); }
public static void PushConstraints(TicNode descendant, TicNode ancestor) { if (descendant == ancestor) { return; } if (!ancestor.State.ApplyDescendant(PushConstraintsFunctions.Singletone, ancestor, descendant)) { throw TicErrors.IncompatibleNodes(ancestor, descendant); } }
private static void PullConstrains(TicNode descendant, TicNode ancestor) { if (descendant == ancestor) { return; } var res = ancestor.State.ApplyDescendant(PullConstraintsFunctions.SingleTone, ancestor, descendant); if (!res) { throw TicErrors.IncompatibleTypes(ancestor, descendant); } }
static void ThrowIfNodeHasRecursiveTypeDefenitionReq(TicNode node, int bypassNumber) { if (node.VisitMark == bypassNumber) { var route = new HashSet <TicNode>(); FindRecursionTypeRoute(node, route); throw TicErrors.RecursiveTypeDefinition(route.ToArray()); } var markBefore = node.VisitMark; node.VisitMark = bypassNumber; ThrowIfStateHasRecursiveTypeDefeinitionReq(node.State, bypassNumber); node.VisitMark = markBefore; }
/// <summary> /// Merge all node states. First non ref state (or first state) called 'main' /// 'main' state takes all constrains and ancestors /// /// All other nodes refs to 'main' /// /// Returns 'main' /// </summary> public static TicNode MergeGroup(IEnumerable <TicNode> cycleRoute) { var main = cycleRoute.FirstOrDefault(c => !(c.State is StateRefTo)) ?? cycleRoute.First(); foreach (var current in cycleRoute) { if (current == main) { continue; } if (current.State is StateRefTo refState) { if (!cycleRoute.Contains(refState.Node)) { throw new InvalidOperationException(); } } else { //merge main and current main.State = GetMergedStateOrNull(main.State, current.State) ?? throw TicErrors.CannotMergeGroup(cycleRoute.ToArray(), main, current); } main.AddAncestors(current.Ancestors.Where(c => c != main)); current.ClearAncestors(); if (!current.IsSolved) { current.State = new StateRefTo(main); } } var newAncestors = main.Ancestors .Where(r => !cycleRoute.Contains(r)) .Distinct() .ToList(); main.ClearAncestors(); main.AddAncestors(newAncestors); return(main); }
private void ThrowRecursiveTypeDefenition(TicNode node) { _cycle.Push(node); throw TicErrors.RecursiveTypeDefinition(_cycle.ToArray()); }