private Match GetMatch(int state, LabeledTree <TSourceNodeType> self) { if (_finals.TryGetValue(state, out RuleBase <TSource, TTarget> rule)) { var cost = rule.Cost; foreach (var wildcardBinding in rule.RecurseOnWildcards(self)) { // // Basic consistency check below. Making sure the fact the rule led us to bind // a wildcard originates from indeed having a wildcard label. // // Note: To check state table consistency, we could check whether the labeled // tree (wildcardBinding.Tree.Value.Tree) can be assigned to any of // the wildcards, using an Any predicate. (For debugging only.) // var labels = wildcardBinding.Tree.Value.Labels; Invariant.Assert(labels.OfType <Match.Wildcard>().Any(), "No assignable wildcard found."); // // In case of optimizers we can be faced with partial coverings. The reduction // phase will make sure we can cover the whole tree if needed. // var cheapest = labels.OfType <Match.Final>().OrderBy(final => final.Cost).FirstOrDefault(); if (cheapest != null) { cost += cheapest.Cost; } } return(new Match.Final(state, cost)); } return(new Match(state)); }
private TTarget Reduce(LabeledTree <TSourceNodeType> labeled) => ReduceCore(labeled);
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); }