public List <Schematic> resolve(sharptest.ModLibrary library) { if (library == null) { throw new ArgumentNullException("library"); } if (this.contents.Count == 0 || this.connections.Count == 0) { return(null); } if (!isFullyConnected()) { throw new ApplicationException("schematic is not fully connected"); } foreach (Element elm in this.contents.Values) { elm.populateAvail(library); } Schematic all = this.Clone(); Dictionary <int, Element> .Enumerator firstEnum = all.contents.GetEnumerator(); firstEnum.MoveNext(); Element first = firstEnum.Current.Value; Dictionary <int, bool> seen = new Dictionary <int, bool>(); return(resolveImpl(library, all, seen, first.circuitId)); }
public void populateAvail(sharptest.ModLibrary library) { if (library == null) { throw new ArgumentNullException("library"); } if (this.explicitAvail) { return; } availObjects = new List <signals.ICircuitConnectible>(); switch (this.type) { case ElementType.Module: List <List <signals.IBlockDriver> > blocks = library.block(this.name); if (blocks != null) { foreach (List <signals.IBlockDriver> variant in blocks) { foreach (signals.IBlockDriver driver in variant) { if (driver.canCreate) { this.availObjects.Add(driver); } if (driver.canDiscover) { signals.IBlock[] found = driver.Discover(); foreach (signals.IBlock discBlk in found) { if (this.nodeId == null || String.Compare(discBlk.NodeId, this.nodeId, true) == 0) { this.availObjects.Add(discBlk); } } } } } } break; case ElementType.Function: case ElementType.FunctionOnIn: case ElementType.FunctionOnOut: List <signals.IFunctionSpec> funcs = library.func(this.name); if (funcs != null) { foreach (signals.IFunctionSpec spec in funcs) { this.availObjects.Add(spec); } } break; } }
private static signals.IFunctionSpec findImplicitConversion(sharptest.ModLibrary library, signals.EType inpType, signals.EType outType) { List <signals.IFunctionSpec> idents = library.func("="); if (idents == null) { return(null); } foreach (signals.IFunctionSpec avail in idents) { signals.EType identInput = avail.Fingerprint.inputs[0]; signals.EType identOutput = avail.Fingerprint.outputs[0]; if (inpType == identInput && outType == identOutput) { return(avail); } } return(null); }
private static List <Schematic> resolveImpl(sharptest.ModLibrary library, Schematic here, Dictionary <int, bool> seen, int elmKey) { if (seen.ContainsKey(elmKey)) { return new List <Schematic> { here } } ; if (!here.contents.ContainsKey(elmKey)) { throw new ApplicationException("couldn't kind elmKey in contents"); } Element elm = here.contents[elmKey]; seen.Add(elmKey, true); try { List <Schematic> answers = new List <Schematic>(); ResolveFailure failure = new ResolveFailure(); if (elm.availObjects.Count == 0) { failure.Add(new CannotResolveElement(elm)); } foreach (signals.ICircuitConnectible avail in elm.availObjects) { Schematic newSchem = here.Clone(); Element newElem = newSchem.contents[elmKey]; newElem.availObjects.Clear(); newElem.availObjects.Add(avail); try { newSchem.resolveNeighbors(library, newElem); } catch (ResolveFailureReason fault) { failure.Add(fault); continue; } Dictionary <int, bool> recurseList = new Dictionary <int, bool>(); foreach (KeyValuePair <EndpointKey, EndpointKey> entry in newSchem.connections) { EndpointKey key = entry.Key; EndpointKey value = entry.Value; if (key.elem == newElem) { if (!seen.ContainsKey(value.elem.circuitId)) { recurseList.Add(value.elem.circuitId, true); } } else if (value.elem == newElem) { if (!seen.ContainsKey(key.elem.circuitId)) { recurseList.Add(key.elem.circuitId, true); } } } List <Schematic> possibles = new List <Schematic>(); possibles.Add(newSchem); foreach (KeyValuePair <int, bool> entry in recurseList) { List <Schematic> prevPass = possibles; possibles = new List <Schematic>(); foreach (Schematic possible in prevPass) { try { possibles.AddRange(resolveImpl(library, possible, seen, entry.Key)); } catch (ResolveFailure fail) { failure.Add(fail); } } } answers.AddRange(possibles); } if (answers.Count == 0 && failure.reasons.Count > 0) { throw failure; } return(answers); } finally { seen.Remove(elmKey); } }
private void resolveNeighbors(sharptest.ModLibrary library, Element elm) { if (elm.availObjects.Count != 1) { throw new ApplicationException("elm should contain a single availObject by this point"); } signals.ICircuitConnectible avail = elm.availObjects[0]; Dictionary <Element, bool> recurseList = new Dictionary <Element, bool>(); List <KeyValuePair <EndpointKey, EndpointKey> > tempCollect = new List <KeyValuePair <EndpointKey, EndpointKey> >(); tempCollect.AddRange(connections); foreach (KeyValuePair <EndpointKey, EndpointKey> entry in tempCollect) { EndpointKey key = entry.Key; EndpointKey value = entry.Value; if (key.elem == elm) { Element otherElm = value.elem; signals.EType ourType = key.OutputType(avail); bool changed = false; if (otherElm.availObjects.Count > 1) { // if we have more than one option here, just look for possible compatibility List <signals.ICircuitConnectible> newAvail = new List <signals.ICircuitConnectible>(); foreach (signals.ICircuitConnectible otherAvail in otherElm.availObjects) { signals.EType otherType = value.InputType(otherAvail); if (ourType != otherType && findImplicitConversion(library, ourType, otherType) == null) { changed = true; } else { newAvail.Add(otherAvail); } } otherElm.availObjects = newAvail; } if (otherElm.availObjects.Count == 1) { // if we're on one-to-one terms, we might add compat connections signals.ICircuitConnectible otherAvail = otherElm.availObjects[0]; signals.EType otherType = value.InputType(otherAvail); if (ourType != otherType) { signals.IFunctionSpec func = findImplicitConversion(library, ourType, otherType); if (func == null) { // only option isn't type-compatible? Looks like we broke a connection throw new LinkTypeFailure(entry.Key, ourType, entry.Value, otherType); } else { AddImplicitConversion(key, value, func); } } } else if (otherElm.availObjects.Count == 0) { // ran out of possible connections? Looks like we broke a connection throw new CannotResolveElement(otherElm); } if (changed) { recurseList.Add(value.elem, true); } } if (value.elem == elm) { Element otherElm = key.elem; signals.EType ourType = value.InputType(avail); bool changed = false; if (otherElm.availObjects.Count > 1) { // if we have more than one option here, just look for possible compatibility List <signals.ICircuitConnectible> newAvail = new List <signals.ICircuitConnectible>(); foreach (signals.ICircuitConnectible otherAvail in otherElm.availObjects) { signals.EType otherType = key.OutputType(otherAvail); if (ourType != otherType && findImplicitConversion(library, otherType, ourType) == null) { changed = true; } else { newAvail.Add(otherAvail); } } otherElm.availObjects = newAvail; } if (otherElm.availObjects.Count == 1) { // if we're on one-to-one terms, we might add compat connections signals.ICircuitConnectible otherAvail = otherElm.availObjects[0]; signals.EType otherType = key.OutputType(otherAvail); if (ourType != otherType) { signals.IFunctionSpec func = findImplicitConversion(library, otherType, ourType); if (func == null) { // only option isn't type-compatible? Looks like we broke a connection throw new LinkTypeFailure(entry.Key, otherType, entry.Value, ourType); } else { AddImplicitConversion(key, value, func); } } } else if (otherElm.availObjects.Count == 0) { // ran out of possible connections? Looks like we broke a connection throw new CannotResolveElement(otherElm); } if (changed) { recurseList.Add(value.elem, true); } } } foreach (KeyValuePair <Element, bool> entry in recurseList) { if (entry.Key.availObjects.Count == 1) { resolveNeighbors(library, entry.Key); } } }