public bool TryGetValue(TKey key, out NAryMapOrLeaf <TKey, TValue> res) { res = default; if (Levels == 1) { var ok = _leaf.TryGetValue(key, out TValue i); if (ok) { res = NAryMapOrLeaf <TKey, TValue> .CreateLeaf(i); } return(ok); } else { var ok = _map.TryGetValue(key, out NAryMap <TKey, TValue> m); if (ok) { res = NAryMapOrLeaf <TKey, TValue> .CreateMap(m); } return(ok); } }
private LabeledTree <TSourceNodeType> LabelCore(ITree <TSourceNodeType> node) { var matches = GetWildcardMatches(node).ToList(); var label = new Label <TSourceNodeType>(node, matches); var res = new LabeledTree <TSourceNodeType>(label, node.Children.Select(childNode => LabelCore(childNode))); if (res.Children.Count == 0) { var sourceNode = (TSource)node; if (_constants.TryGetValue(sourceNode, out int constantState)) { matches.Add(GetMatch(constantState, res)); } foreach (var leafTest in _leafTests) { if (leafTest.Key(sourceNode)) { var leafState = leafTest.Value; matches.Add(GetMatch(leafState, res)); } } } else { // TODO: How should we deal with the concept of "base definitions"? // What about string.Equals(string) match against string.Equals(object)? // Contravariance for signatures based on child nodes and a property of the tree node? if (_states.TryGetValue(node.Value, out NAryMap <int, int> operatorStateMap) && res.Children.Count == operatorStateMap.Levels) { var maps = new List <NAryMapOrLeaf <int, int> > { NAryMapOrLeaf <int, int> .CreateMap(operatorStateMap) }; // // This is the core of the labeling algorithm. We scan the recursively labeled children // (which correspond to the operator's operands) one-by-one, trying to make progress in // the state map for the operator by indexing one operand state at a time. // // E.g. [1,3] (op) [2,4,7] // // Given the state transition map of operator (op), we index into the map using the // matching states associated with the first operand, i.e. [1,3]. This will give us // at most two new maps, resembling partial application of (op) with only the first // operand. Next, we index into those maps using the second child's matching states // (i.e. [2,4,7]) which gives us the next (and final "leaf") level of maps. // foreach (var labeledChild in res.Children) { var newMap = new List <NAryMapOrLeaf <int, int> >(); // // All of the possible states for current child (operand) need to be attempted in the // current maps. This gives us the next level of maps. // var labels = labeledChild.Value.Labels; foreach (var childLabel in labels) { foreach (var map in maps) { if (map.Map.TryGetValue(childLabel.State, out NAryMapOrLeaf <int, int> nxt)) { newMap.Add(nxt); } } } maps = newMap; } foreach (var map in maps) { matches.Add(GetMatch(map.Leaf, res)); } } } // // If a node is assignable to a wildcard but has no available reduction, we can try the // fallback strategy of local evaluation by funcletizing the remainder tree. // if (ShouldConsiderFallback(matches)) { var sourceNode = (TSource)node; foreach (var fallbackTest in _fallbackTests) { if (fallbackTest.Key(sourceNode)) { var fallbackState = fallbackTest.Value; matches.Add(GetMatch(fallbackState, res)); } } } return(res); }