Ejemplo n.º 1
0
        /// <summary>
        /// Adds suggestions for a given node.
        /// </summary>
        /// <param name="node">Node for which suggestions are needed.</param>
        /// <param name="hasSpecificSuggestions">Flag to indicate if inner most function has any specific suggestions.</param>
        /// <param name="currentNode">Current node in the traversal.</param>
        public static bool AddTopLevelSuggestionsForGivenNode(IntellisenseData.IntellisenseData intellisenseData, TexlNode node, TexlNode currentNode)
        {
            Contracts.AssertValue(intellisenseData);
            Contracts.AssertValue(node);
            Contracts.AssertValue(currentNode);

            CallNode callNode = GetNearestCallNode(currentNode);

            if (callNode == null)
            {
                return(false);
            }

            if (callNode.Args.Count == 0)
            {
                AddTopLevelSuggestionsForCursorType(intellisenseData, callNode, 0);
                return(TryAddSpecificSuggestionsForGivenArgPosition(intellisenseData, callNode, 0));
            }

            for (int i = 0; i < callNode.Args.Count; i++)
            {
                if (node.InTree(callNode.Args.Children[i]))
                {
                    AddTopLevelSuggestionsForCursorType(intellisenseData, callNode, i);
                    if (Object.ReferenceEquals(node, currentNode) && TryAddSpecificSuggestionsForGivenArgPosition(intellisenseData, callNode, i))
                    {
                        return(true);
                    }
                }
            }

            if (callNode.Parent != null)
            {
                return(AddTopLevelSuggestionsForGivenNode(intellisenseData, node, callNode.Parent));
            }

            return(false);
        }
Ejemplo n.º 2
0
        private bool IsArgTypeInconsequential(TexlNode arg)
        {
            Contracts.AssertValue(arg);
            Contracts.Assert(arg.Parent is ListNode);
            Contracts.Assert(arg.Parent.Parent is CallNode);
            Contracts.Assert(arg.Parent.Parent.AsCall().Head.Name == Name);

            CallNode call = arg.Parent.Parent.AsCall().VerifyValue();

            // Pattern: OnSelect = If(cond, argT, argF)
            // Pattern: OnSelect = If(cond, arg1, cond, arg2, ..., argK, argF)
            // Pattern: OnSelect = If(cond, arg1, If(cond, argT, argF))
            // Pattern: OnSelect = If(cond, arg1, If(cond, arg2, cond, arg3, ...))
            // Pattern: OnSelect = If(cond, arg1, cond, If(cond, arg2, cond, arg3, ...), ...)
            // ...etc.
            CallNode ancestor = call;

            while (ancestor.Head.Name == Name)
            {
                if (ancestor.Parent == null && ancestor.Args.Children.Length > 0)
                {
                    for (int i = 0; i < ancestor.Args.Children.Length; i += 2)
                    {
                        // If the given node is part of a condition arg of an outer If invocation,
                        // then it's NOT inconsequential. Note that the very last arg to an If
                        // is not a condition -- it's the "else" branch, hence the test below.
                        if (i != ancestor.Args.Children.Length - 1 && arg.InTree(ancestor.Args.Children[i]))
                        {
                            return(false);
                        }
                    }
                    return(true);
                }

                // Deal with the possibility that the ancestor may be contributing to a chain.
                // This also lets us cover the following patterns:
                // Pattern: OnSelect = X; If(cond, arg1, arg2); Y; Z
                // Pattern: OnSelect = X; If(cond, arg1;arg11;...;arg1k, arg2;arg21;...;arg2k); Y; Z
                // ...etc.
                VariadicOpNode chainNode;
                if ((chainNode = ancestor.Parent.AsVariadicOp()) != null && chainNode.Op == VariadicOp.Chain)
                {
                    // Top-level chain in a behavior rule.
                    if (chainNode.Parent == null)
                    {
                        return(true);
                    }
                    // A chain nested within a larger non-call structure.
                    if (!(chainNode.Parent is ListNode) || !(chainNode.Parent.Parent is CallNode))
                    {
                        return(false);
                    }
                    // Only the last chain segment is consequential.
                    int numSegments = chainNode.Children.Length;
                    if (numSegments > 0 && !arg.InTree(chainNode.Children[numSegments - 1]))
                    {
                        return(true);
                    }
                    // The node is in the last segment of a chain nested within a larger invocation.
                    ancestor = chainNode.Parent.Parent.AsCall();
                    continue;
                }

                // Walk up the parent chain to the outer invocation.
                if (!(ancestor.Parent is ListNode) || !(ancestor.Parent.Parent is CallNode))
                {
                    return(false);
                }

                ancestor = ancestor.Parent.Parent.AsCall();
            }

            // Exhausted all supported patterns.
            return(false);
        }
Ejemplo n.º 3
0
        // In behavior properties, the arg type is irrelevant if nothing actually depends
        // on the output type of IfError (see If.cs, Switch.cs)
        private bool IsArgTypeInconsequential(TexlNode arg)
        {
            Contracts.AssertValue(arg);
            Contracts.Assert(arg.Parent is ListNode);
            Contracts.Assert(arg.Parent.Parent is CallNode);
            Contracts.Assert(arg.Parent.Parent.AsCall().Head.Name == Name);

            CallNode call = arg.Parent.Parent.AsCall().VerifyValue();

            // Pattern: OnSelect = IfError(arg1, arg2, ... argK)
            // Pattern: OnSelect = IfError(arg1, IfError(arg1, arg2,...), ... argK)
            // ...etc.
            CallNode ancestor = call;

            while (ancestor.Head.Name == Name)
            {
                if (ancestor.Parent == null && ancestor.Args.Children.Length > 0)
                {
                    return(true);
                }

                // Deal with the possibility that the ancestor may be contributing to a chain.
                // This also lets us cover the following patterns:
                // Pattern: OnSelect = X; IfError(arg1, arg2); Y; Z
                // Pattern: OnSelect = X; IfError(arg1;arg11;...;arg1k, arg2;arg21;...;arg2k); Y; Z
                // ...etc.
                VariadicOpNode chainNode;
                if ((chainNode = ancestor.Parent.AsVariadicOp()) != null && chainNode.Op == VariadicOp.Chain)
                {
                    // Top-level chain in a behavior rule.
                    if (chainNode.Parent == null)
                    {
                        return(true);
                    }

                    // A chain nested within a larger non-call structure.
                    if (!(chainNode.Parent is ListNode) || !(chainNode.Parent.Parent is CallNode))
                    {
                        return(false);
                    }

                    // Only the last chain segment is consequential.
                    int numSegments = chainNode.Children.Length;
                    if (numSegments > 0 && !arg.InTree(chainNode.Children[numSegments - 1]))
                    {
                        return(true);
                    }
                    // The node is in the last segment of a chain nested within a larger invocation.
                    ancestor = chainNode.Parent.Parent.AsCall();
                    continue;
                }

                // Walk up the parent chain to the outer invocation.
                if (!(ancestor.Parent is ListNode) || !(ancestor.Parent.Parent is CallNode))
                {
                    return(false);
                }

                ancestor = ancestor.Parent.Parent.AsCall();
            }

            // Exhausted all supported patterns.
            return(false);
        }