Example #1
0
        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);
            }
        }
Example #2
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);
        }