예제 #1
0
        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));
        }
예제 #2
0
 private TTarget Reduce(LabeledTree <TSourceNodeType> labeled) => ReduceCore(labeled);
예제 #3
0
        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);
        }