internal override bool TryAddSuggestionsForNodeKind(IntellisenseData.IntellisenseData intellisenseData)
            {
                Contracts.AssertValue(intellisenseData);

                TexlNode curNode = intellisenseData.CurNode;
                // Cursor is in the operation token.
                // Suggest binary operators.
                BinaryOpNode binaryOpNode = curNode.CastBinaryOp();
                var          tokenSpan    = binaryOpNode.Token.Span;

                string keyword           = binaryOpNode.Op == BinaryOp.Error ? tokenSpan.GetFragment(intellisenseData.Script) : TexlParser.GetTokString(binaryOpNode.Token.Kind);
                int    replacementLength = tokenSpan.Min == intellisenseData.CursorPos ? 0 : tokenSpan.Lim - tokenSpan.Min;

                intellisenseData.SetMatchArea(tokenSpan.Min, intellisenseData.CursorPos, replacementLength);
                intellisenseData.BoundTo = binaryOpNode.Op == BinaryOp.Error ? string.Empty : keyword;
                AddSuggestionsForBinaryOperatorKeyWords(intellisenseData);

                return(true);
            }
Example #2
0
        public bool HasErrorsInTree(TexlNode rootNode, DocumentErrorSeverity severity = DocumentErrorSeverity.Suggestion)
        {
            Contracts.AssertValue(rootNode);

            if (CollectionUtils.Size(_errors) == 0)
            {
                return(false);
            }

            foreach (var err in _errors)
            {
                if (err.Node.InTree(rootNode) && err.Severity >= severity)
                {
                    return(true);
                }
            }

            return(false);
        }
            private static bool TryGetLocalScopeInfo(TexlNode node, TexlBinding binding, out ScopedNameLookupInfo info)
            {
                Contracts.AssertValue(node);
                Contracts.AssertValue(binding);

                if (node.Kind == NodeKind.FirstName)
                {
                    FirstNameNode curNode       = node.CastFirstName();
                    var           firstNameInfo = binding.GetInfo(curNode);
                    if (firstNameInfo.Kind == BindKind.ScopeArgument)
                    {
                        info = (ScopedNameLookupInfo)firstNameInfo.Data;
                        return(true);
                    }
                }

                info = new ScopedNameLookupInfo();
                return(false);
            }
Example #4
0
            // 1.
            // <CallNode>
            //    |
            //  <ListNode>
            //    |
            //  <Error RecordNode>[Cursor position]

            // For example, Patch(Accounts, OldRecord, UpdateRecord, {<Cursor position>

            // 2.
            // <CallNode>
            //    |
            //  <ListNode>
            //    |
            //  <RecordNode>
            //    |
            //  <Error Node>[Cursor position]

            // For example, Patch(Accounts, OldRecord, UpdateRecord, {A:"",<cursor position>})

            // 3.
            // <CallNode>
            //    |
            //  <ListNode>
            //    |
            //  <VariadicOpNode>
            //    |
            //  <RecordNode>
            //    |
            //  <Error Identifier Node> [Cursor position]
            // For example, Patch(Accounts, OldRecord, UpdateRecord, { 'Account Name': ""});
            //              Patch(Accounts, OldRecord, UpdateRecord,{<Cursor position>);
            private static bool TryGetRecordNodeWithinACallNode(TexlNode node, out RecordNode recordNode, out CallNode callNode)
            {
                Contracts.AssertValue(node);

                if (!TryGetParentRecordNode(node, out recordNode) || !TryGetParentListNode(recordNode, out ListNode listNode))
                {
                    callNode = null;
                    return(false);
                }

                if (!(listNode.Parent is CallNode cNode))
                {
                    callNode = null;
                    return(false);
                }

                callNode = cNode;
                return(true);
            }
Example #5
0
            private static bool TryGetParentListNode(RecordNode node, out ListNode listNode)
            {
                Contracts.AssertValue(node);

                TexlNode parentNode = node;

                while (parentNode != null)
                {
                    if (parentNode.Kind == NodeKind.List)
                    {
                        listNode = parentNode.AsList();
                        return(true);
                    }

                    parentNode = parentNode.Parent;
                }

                listNode = null;
                return(false);
            }
Example #6
0
            private static bool TryGetParentRecordNode(TexlNode node, out RecordNode recordNode)
            {
                Contracts.AssertValue(node);

                TexlNode parentNode = node;

                while (parentNode != null)
                {
                    if (parentNode.Kind == NodeKind.Record)
                    {
                        recordNode = parentNode.AsRecord();
                        return(true);
                    }

                    parentNode = parentNode.Parent;
                }

                recordNode = null;
                return(false);
            }
Example #7
0
        // Helper used to provide hints when we detect non-delegable parts of the expression due to server restrictions.
        protected void SuggestDelegationHint(TexlNode node, TexlBinding binding, ErrorResourceKey?suggestionKey, params object[] args)
        {
            Contracts.AssertValue(node);
            Contracts.AssertValue(binding);
            Contracts.Assert(suggestionKey == null || suggestionKey?.Key != string.Empty);

            if (suggestionKey == null)
            {
                suggestionKey = TexlStrings.SuggestRemoteExecutionHint;
            }

            if (args == null || args.Length == 0)
            {
                binding.ErrorContainer.EnsureError(DocumentErrorSeverity.Warning, node, (ErrorResourceKey)suggestionKey, _function.Name);
            }
            else
            {
                binding.ErrorContainer.EnsureError(DocumentErrorSeverity.Warning, node, (ErrorResourceKey)suggestionKey, args);
            }
        }
Example #8
0
        public bool TryGetValidValue(TexlNode argNode, TexlBinding binding, out IExpandInfo entityInfo)
        {
            Contracts.AssertValue(argNode);
            Contracts.AssertValue(binding);

            entityInfo = null;
            switch (argNode.Kind)
            {
            case NodeKind.FirstName:
                return(TryGetEntityInfo(argNode.AsFirstName(), binding, out entityInfo));

            case NodeKind.Call:
                return(TryGetEntityInfo(argNode.AsCall(), binding, out entityInfo));

            case NodeKind.DottedName:
                return(TryGetEntityInfo(argNode.AsDottedName(), binding, out entityInfo));
            }

            return(false);
        }
Example #9
0
        private TexlNode ParseExprChain(TexlNode node, ITexlSource leftTrivia)
        {
            Contracts.AssertValue(node);
            Contracts.Assert(_curs.TidCur == TokKind.Semicolon);

            var delimiters  = new List <Token>(1);
            var expressions = new List <TexlNode>(2);

            expressions.Add(node);

            var sourceList = new List <ITexlSource>();

            sourceList.Add(new NodeSource(node));
            sourceList.Add(leftTrivia);

            while (_curs.TidCur == TokKind.Semicolon)
            {
                var delimiter = _curs.TokMove();
                delimiters.Add(delimiter);
                sourceList.Add(new TokenSource(delimiter));
                sourceList.Add(ParseTrivia());

                if (_curs.TidCur == TokKind.Eof || _curs.TidCur == TokKind.Comma || _curs.TidCur == TokKind.ParenClose)
                {
                    break;
                }

                // SingleExpr here means we don't want chains on the RHS, but individual expressions.
                var expression = ParseExpr(Precedence.SingleExpr);
                expressions.Add(expression);
                sourceList.Add(new NodeSource(expression));
                sourceList.Add(ParseTrivia());
            }

            return(new VariadicOpNode(
                       ref _idNext,
                       VariadicOp.Chain,
                       expressions.ToArray(),
                       delimiters.ToArray(),
                       new SourceList(sourceList)));
        }
Example #10
0
        public override bool PreVisit(BinaryOpNode node)
        {
            Contracts.AssertValue(node);

            // Cursor is in the left node.
            if (_cursorPosition <= node.Token.Span.Min)
            {
                node.Left.Accept(this);
                return(false);
            }

            // Cursor is inside the operation token.
            if (_cursorPosition <= node.Token.Span.Lim)
            {
                _result = node;
                return(false);
            }

            node.Right.Accept(this);
            return(false);
        }
Example #11
0
        private bool IsValidSortOrderNode(TexlNode node, SortOpMetadata metadata, TexlBinding binding, DPath columnPath)
        {
            Contracts.AssertValue(node);
            Contracts.AssertValue(metadata);
            Contracts.AssertValue(binding);
            Contracts.AssertValid(columnPath);

            if (binding.IsAsync(node))
            {
                AddSuggestionMessageToTelemetry("Async sortorder node.", node, binding);
                DelegationTrackerCore.SetDelegationTrackerStatus(DelegationStatus.AsyncSortOrder, node, binding, this, DelegationTelemetryInfo.CreateEmptyDelegationTelemetryInfo());
                return(false);
            }

            string sortOrder;

            switch (node.Kind)
            {
            case NodeKind.FirstName:
            case NodeKind.StrLit:
                return(_sortOrderValidator.TryGetValidValue(node, binding, out sortOrder) &&
                       IsSortOrderSuppportedByColumn(node, binding, sortOrder, metadata, columnPath));

            case NodeKind.DottedName:
            case NodeKind.Call:
                if (_sortOrderValidator.TryGetValidValue(node, binding, out sortOrder) &&
                    IsSortOrderSuppportedByColumn(node, binding, sortOrder, metadata, columnPath))
                {
                    return(true);
                }

                // If both ascending and descending are supported then we can support this.
                return(IsSortOrderSuppportedByColumn(node, binding, LanguageConstants.DescendingSortOrderString, metadata, columnPath) &&
                       IsSortOrderSuppportedByColumn(node, binding, LanguageConstants.AscendingSortOrderString, metadata, columnPath));

            default:
                AddSuggestionMessageToTelemetry("Unsupported sortorder node kind.", node, binding);
                return(false);
            }
        }
Example #12
0
        private bool IsValidSortOrderNode(TexlNode node, SortOpMetadata metadata, TexlBinding binding, DPath columnPath)
        {
            Contracts.AssertValue(node);
            Contracts.AssertValue(metadata);
            Contracts.AssertValue(binding);
            Contracts.AssertValid(columnPath);

            if (binding.IsAsync(node))
            {
                var message = string.Format("Function:{0}, SortOrderNode is async", Name);
                AddSuggestionMessageToTelemetry(message, node, binding);
                return(false);
            }

            string sortOrder;

            switch (node.Kind)
            {
            case NodeKind.FirstName:
            case NodeKind.StrLit:
                return(_sortOrderValidator.TryGetValidValue(node, binding, out sortOrder) &&
                       IsSortOrderSuppportedByColumn(sortOrder, metadata, columnPath));

            case NodeKind.DottedName:
            case NodeKind.Call:
                if (_sortOrderValidator.TryGetValidValue(node, binding, out sortOrder) &&
                    IsSortOrderSuppportedByColumn(sortOrder, metadata, columnPath))
                {
                    return(true);
                }

                // If both ascending and descending are supported then we can support this.
                return(IsSortOrderSuppportedByColumn(Microsoft.PowerFx.Core.Utils.LanguageConstants.DescendingSortOrderString, metadata, columnPath) &&
                       IsSortOrderSuppportedByColumn(Microsoft.PowerFx.Core.Utils.LanguageConstants.AscendingSortOrderString, metadata, columnPath));

            default:
                AddSuggestionMessageToTelemetry("Unsupported sortorder node.", node, binding);
                return(false);
            }
        }
Example #13
0
        public override bool PreVisit(RecordNode node)
        {
            Contracts.AssertValue(node);
            Contracts.Assert(node.Token.Kind == TokKind.CurlyOpen || node.Token.Kind == TokKind.Ident);

            if (_cursorPosition <= node.Token.Span.Min || // If cursor position is before the open curly return the record node.
                node.Count == 0 ||  // Or if the record node is empty, return the record node.
                (node.CurlyClose != null && node.CurlyClose.Span.Lim <= _cursorPosition))    // Cursor is after the closed curly.
            {
                _result = node;
                return(false);
            }

            // Cursor is between the open and closed curly.
            int length = CollectionUtils.Size(node.Commas);

            for (int i = 0; i < length; i++)
            {
                Token tokComma = node.Commas[i];

                // Cursor position is inside ith child.
                if (_cursorPosition <= tokComma.Span.Min)
                {
                    node.Children[i].Accept(this);
                    return(false);
                }
            }

            if (node.CurlyClose == null || _cursorPosition <= node.CurlyClose.Span.Min)
            {
                // Cursor is within the last child.
                node.Children[node.Children.Length - 1].Accept(this);
                return(false);
            }

            // Cursor is after the closing curly.
            _result = node;
            return(false);
        }
Example #14
0
        public static DType ScopeTypeForArgumentSuggestions(CallNode callNode, IntellisenseData.IntellisenseData intellisenseData)
        {
            Contracts.AssertValue(callNode);
            Contracts.AssertValue(intellisenseData);


            var info = intellisenseData.Binding.GetInfo(callNode);

            if (info.Function.UseParentScopeForArgumentSuggestions)
            {
                return(ClosestParentScopeTypeForSuggestions(callNode, intellisenseData));
            }

            if (callNode.Args.Count <= info.Function.SuggestionTypeReferenceParamIndex)
            {
                return(DType.Unknown);
            }

            TexlNode referenceArg = callNode.Args.Children[info.Function.SuggestionTypeReferenceParamIndex];

            return(info.Function.UsesEnumNamespace ? GetEnumType(intellisenseData, referenceArg) : intellisenseData.Binding.GetType(referenceArg));
        }
Example #15
0
        internal static DType ClosestParentScopeTypeForSuggestions(CallNode callNode, IntellisenseData.IntellisenseData intellisenseData)
        {
            Contracts.AssertValue(callNode);
            Contracts.AssertValue(intellisenseData);

            TexlNode currentNode = callNode;

            while (currentNode.Parent != null)
            {
                currentNode = currentNode.Parent;
                if (currentNode is CallNode callNodeCurr)
                {
                    DType parentScopeType = ScopeTypeForArgumentSuggestions(callNodeCurr, intellisenseData);
                    if (parentScopeType != null && parentScopeType != DType.Unknown)
                    {
                        return(parentScopeType);
                    }
                }
            }

            return(DType.Unknown);
        }
Example #16
0
        private LazyList <string> Basic(TexlNode node, Context context)
        {
            return(LazyList <string> .Of(
                       node.SourceList.Sources
                       .SelectMany(source =>
            {
                var nodeSource = source as NodeSource;

                if (nodeSource != null)
                {
                    return nodeSource.Node.Accept(this, context);
                }
                else if (source is WhitespaceSource)
                {
                    return LazyList <string> .Of(" ");
                }
                else
                {
                    return source.Tokens.Select(GetScriptForToken);
                }
            })));
        }
            private static bool TryGetNamespaceFunctions(TexlNode node, TexlBinding binding, out IEnumerable <TexlFunction> functions)
            {
                Contracts.AssertValue(node);
                Contracts.AssertValue(binding);

                FirstNameNode curNode = node.AsFirstName();

                if (curNode == null)
                {
                    functions = EmptyEnumerator <TexlFunction> .Instance;
                    return(false);
                }

                FirstNameInfo firstNameInfo = binding.GetInfo(curNode).VerifyValue();

                Contracts.AssertValid(firstNameInfo.Name);

                DPath namespacePath = new DPath().Append(firstNameInfo.Name);

                functions = binding.NameResolver.LookupFunctionsInNamespace(namespacePath);

                return(functions.Any());
            }
        public bool TryGetValidValue(TexlNode argNode, TexlBinding binding, out IExternalDataSource dsInfo)
        {
            Contracts.AssertValue(argNode);
            Contracts.AssertValue(binding);

            dsInfo = null;
            switch (argNode.Kind)
            {
            case NodeKind.FirstName:
                return(TryGetDsInfo(argNode.AsFirstName(), binding, out dsInfo));

            case NodeKind.Call:
                return(TryGetDsInfo(argNode.AsCall(), binding, out dsInfo));

            case NodeKind.DottedName:
                return(TryGetDsInfo(argNode.AsDottedName(), binding, out dsInfo));

            case NodeKind.As:
                return(TryGetValidValue(argNode.AsAsNode().Left, binding, out dsInfo));
            }

            return(false);
        }
Example #19
0
            internal override bool TryAddSuggestionsForNodeKind(IntellisenseData.IntellisenseData intellisenseData)
            {
                Contracts.AssertValue(intellisenseData);

                // For Error Kind, suggest top level values only in the context of a callNode and
                // ThisItemProperties only in the context of thisItem.
                TexlNode curNode = intellisenseData.CurNode;

                // Three methods that implement custom behavior here, one that adds suggestions before
                // top level suggestions are added, one after, and one to handle the case where there aren't
                // any top level suggestions to add.
                if (intellisenseData.AddSuggestionsBeforeTopLevelErrorNodeSuggestions())
                {
                    return(true);
                }

                if (!IntellisenseHelper.AddSuggestionsForTopLevel(intellisenseData, curNode))
                {
                    intellisenseData.AddAlternativeTopLevelSuggestionsForErrorNode();
                }

                intellisenseData.AddSuggestionsAfterTopLevelErrorNodeSuggestions();
                return(true);
            }
            internal override bool TryAddSuggestionsForNodeKind(IntellisenseData.IntellisenseData intellisenseData)
            {
                Contracts.AssertValue(intellisenseData);

                TexlNode curNode   = intellisenseData.CurNode;
                int      cursorPos = intellisenseData.CursorPos;

                var tokenSpan = curNode.Token.Span;

                // Only suggest after record nodes
                if (cursorPos <= tokenSpan.Lim)
                {
                    return(true);
                }

                if (IntellisenseHelper.CanSuggestAfterValue(cursorPos, intellisenseData.Script))
                {
                    // Verify that cursor is after a space after the current node's token.
                    // Suggest binary keywords.
                    IntellisenseHelper.AddSuggestionsForAfterValue(intellisenseData, DType.EmptyTable);
                }

                return(true);
            }
Example #21
0
        private bool TryGetValidSortOrderNode(DottedNameNode node, TexlBinding binding, out string sortOrder)
        {
            Contracts.AssertValue(node);
            Contracts.AssertValue(binding);

            sortOrder = "";
            TexlNode lhsNode   = node.Left;
            var      orderEnum = lhsNode.AsFirstName();

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

            // Verify order enum
            if (!VerifyFirstNameNodeIsValidSortOrderEnum(orderEnum, binding))
            {
                return(false);
            }

            string order = node.Right.Name.Value;

            return(IsValidOrderString(order, out sortOrder));
        }
Example #22
0
        private bool TryGetDSNodes(TexlBinding binding, TexlNode[] args, out IList<FirstNameNode> dsNodes)
        {
            dsNodes = new List<FirstNameNode>();

            var count = args.Count();
            for (int i = 2; i < count;)
            {
                TexlNode nodeArg = args[i];

                IList<FirstNameNode> tmpDsNodes;
                if (ArgValidators.DataSourceArgNodeValidator.TryGetValidValue(nodeArg, binding, out tmpDsNodes))
                {
                    foreach (var node in tmpDsNodes)
                        dsNodes.Add(node);
                }

                // If there are an odd number of args, the last arg also participates.
                i += 2;
                if (i == count)
                    i--;
            }

            return dsNodes.Any();
        }
Example #23
0
        public override bool CheckInvocation(TexlBinding binding, TexlNode[] args, DType[] argTypes, IErrorContainer errors, out DType returnType, out Dictionary <TexlNode, DType> nodeToCoercedTypeMap)
        {
            Contracts.AssertValue(args);
            Contracts.AssertAllValues(args);
            Contracts.AssertValue(argTypes);
            Contracts.Assert(args.Length == argTypes.Length);
            Contracts.AssertValue(errors);
            Contracts.Assert(MinArity <= args.Length && args.Length <= MaxArity);

            bool fValid = base.CheckInvocation(args, argTypes, errors, out returnType, out nodeToCoercedTypeMap);

            if (argTypes.Length == 2)
            {
                DType type0 = argTypes[0];
                DType type1 = argTypes[1];

                DType    otherType = DType.Invalid;
                TexlNode otherArg  = null;

                // At least one of the arguments has to be a table.
                if (type0.IsTable)
                {
                    // Ensure we have a one-column table of numerics
                    fValid &= CheckNumericColumnType(type0, args[0], errors, ref nodeToCoercedTypeMap);
                    // Borrow the return type from the 1st arg
                    returnType = type0;
                    // Check arg1 below.
                    otherArg  = args[1];
                    otherType = type1;
                }
                else if (type1.IsTable)
                {
                    // Ensure we have a one-column table of numerics
                    fValid &= CheckNumericColumnType(type1, args[1], errors, ref nodeToCoercedTypeMap);
                    // Since the 1st arg is not a table, make a new table return type *[Result:n]
                    returnType = DType.CreateTable(new TypedName(DType.Number, OneColumnTableResultName));
                    // Check arg0 below.
                    otherArg  = args[0];
                    otherType = type0;
                }
                else
                {
                    Contracts.Assert(returnType.IsTable);
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrTypeError);
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[1], TexlStrings.ErrTypeError);
                    // Both args are invalid. No need to continue.
                    return(false);
                }

                Contracts.Assert(otherType.IsValid);
                Contracts.AssertValue(otherArg);
                Contracts.Assert(returnType.IsTable);
                Contracts.Assert(!fValid || returnType.IsColumn);

                if (otherType.IsTable)
                {
                    // Ensure we have a one-column table of numerics
                    fValid &= CheckNumericColumnType(otherType, otherArg, errors, ref nodeToCoercedTypeMap);
                }
                else if (!DType.Number.Accepts(otherType))
                {
                    if (otherType.CoercesTo(DType.Number))
                    {
                        CollectionUtils.Add(ref nodeToCoercedTypeMap, otherArg, DType.Number);
                    }
                    else
                    {
                        fValid = false;
                        errors.EnsureError(DocumentErrorSeverity.Severe, otherArg, TexlStrings.ErrTypeError);
                    }
                }
            }
            else
            {
                DType type0 = argTypes[0];

                if (type0.IsTable)
                {
                    // Ensure we have a one-column table of numerics
                    fValid &= CheckNumericColumnType(type0, args[0], errors, ref nodeToCoercedTypeMap);
                    // Borrow the return type from the 1st arg
                    returnType = type0;
                }
                else
                {
                    Contracts.Assert(returnType.IsTable);
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrTypeError);
                    return(false);
                }
            }

            return(fValid);
        }
Example #24
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);
        }
Example #25
0
        public override bool CheckInvocation(TexlBinding binding, TexlNode[] args, DType[] argTypes, IErrorContainer errors, out DType returnType, out Dictionary <TexlNode, DType> nodeToCoercedTypeMap)
        {
            Contracts.AssertValue(binding);
            Contracts.AssertValue(args);
            Contracts.AssertAllValues(args);
            Contracts.AssertValue(argTypes);
            Contracts.Assert(args.Length == argTypes.Length);
            Contracts.AssertValue(errors);
            Contracts.Assert(MinArity <= args.Length && args.Length <= MaxArity);

            int count = args.Length;

            nodeToCoercedTypeMap = null;

            // Check the predicates.
            bool fArgsValid = true;

            for (int i = 0; i < (count & ~1); i += 2)
            {
                bool withCoercion;
                fArgsValid &= CheckType(args[i], argTypes[i], DType.Boolean, errors, true, out withCoercion);

                if (withCoercion)
                {
                    CollectionUtils.Add(ref nodeToCoercedTypeMap, args[i], DType.Boolean);
                }
            }

            DType type = ReturnType;

            // Are we on a behavior property?
            bool isBehavior = binding.IsBehavior;

            // Compute the result type by joining the types of all non-predicate args.
            Contracts.Assert(type == DType.Unknown);
            for (int i = 1; i < count;)
            {
                TexlNode nodeArg = args[i];
                DType    typeArg = argTypes[i];
                if (typeArg.IsError)
                {
                    errors.EnsureError(args[i], TexlStrings.ErrTypeError);
                }

                DType typeSuper = DType.Supertype(type, typeArg);

                if (!typeSuper.IsError)
                {
                    type = typeSuper;
                }
                else if (type.Kind == DKind.Unknown)
                {
                    type       = typeSuper;
                    fArgsValid = false;
                }
                else if (!type.IsError)
                {
                    if (typeArg.CoercesTo(type))
                    {
                        CollectionUtils.Add(ref nodeToCoercedTypeMap, nodeArg, type);
                    }
                    else if (!isBehavior || !IsArgTypeInconsequential(nodeArg))
                    {
                        errors.EnsureError(DocumentErrorSeverity.Severe, nodeArg, TexlStrings.ErrBadType_ExpectedType_ProvidedType,
                                           type.GetKindString(),
                                           typeArg.GetKindString());
                        fArgsValid = false;
                    }
                }
                else if (typeArg.Kind != DKind.Unknown)
                {
                    type       = typeArg;
                    fArgsValid = false;
                }

                // If there are an odd number of args, the last arg also participates.
                i += 2;
                if (i == count)
                {
                    i--;
                }
            }

            // Update the return type based on the specified invocation args.
            returnType = type;

            return(fArgsValid);
        }
Example #26
0
        public virtual bool IsOpSupportedByTable(OperationCapabilityMetadata metadata, TexlNode node, TexlBinding binding)
        {
            Contracts.AssertValue(metadata);
            Contracts.AssertValue(node);
            Contracts.AssertValue(binding);

            if (!metadata.IsBinaryOpInDelegationSupported(_binaryOp))
            {
                SuggestDelegationHint(node, binding, TexlStrings.OpNotSupportedByClientSuggestionMessage_OpNotSupportedByClient, _binaryOp.ToString());
                return(false);
            }

            if (!metadata.IsBinaryOpSupportedByTable(_binaryOp))
            {
                SuggestDelegationHint(node, binding, TexlStrings.OpNotSupportedByServiceSuggestionMessage_OpNotSupportedByService, _binaryOp.ToString());
                return(false);
            }

            return(true);
        }
Example #27
0
        private LazyList <string> PrettyBinary(string strOp, Precedence parentPrecedence, Precedence precLeft, Precedence precRight, TexlNode left, TexlNode right)
        {
            Contracts.AssertNonEmpty(strOp);

            return(ApplyPrecedence(
                       parentPrecedence,
                       precLeft,
                       left.Accept(this, precLeft)
                       .With(strOp)
                       .With(right.Accept(this, precRight))));
        }
Example #28
0
 // For left associative operators: precRight == precLeft + 1.
 private LazyList <string> PrettyBinary(string strOp, Precedence parentPrecedence, Precedence precLeft, TexlNode left, TexlNode right)
 {
     return(PrettyBinary(strOp, parentPrecedence, precLeft, precLeft + 1, left, right));
 }
Example #29
0
 public virtual string GetRightToken(TexlNode leftNode, Identifier right)
 {
     return(right.Token.ToString());
 }
Example #30
0
        // Verifies if given kind of node is supported by function delegation.
        private bool IsSupportedNode(TexlNode node, OperationCapabilityMetadata metadata, TexlBinding binding, IOpDelegationStrategy opDelStrategy, bool isRHSNode)
        {
            Contracts.AssertValue(node);
            Contracts.AssertValue(metadata);
            Contracts.AssertValue(binding);
            Contracts.AssertValue(opDelStrategy);

            if (!binding.IsRowScope(node))
            {
                // Check whether this is -
                //  1) in operator delegation and
                //  2) it is verifying if RHS node is supported and
                //  3) it is not an async node and
                //  4) it is a single column table and
                //  5) metadata belongs to cds datasource that supports delegation of CdsIn
                // If this check fails, verify if it is simply a valid node..
                // Eg of valid delegation functions -
                // Filter(Accounts, 'Account Name' in ["Foo", Bar"]) - Direct table use
                // Set(Names, ["Foo", Bar"]); Filter(Accounts, 'Account Name' in Names) - Using variable of type table
                // ClearCollect(Names, Accounts); Filter(Accounts, 'Account Name' in Names.'Account Name') - using column from collection.
                // This won't be delegated - Filter(Accounts, 'Account Name' in Accounts.'Account Name') as Accounts.'Account Name' is async.
                if ((binding.Document.Properties.EnabledFeatures.IsEnhancedDelegationEnabled &&
                     isRHSNode && (opDelStrategy as BinaryOpDelegationStrategy)?.Op == BinaryOp.In && !binding.IsAsync(node) && binding.GetType(node).IsTable&& binding.GetType(node).IsColumn&&
                     metadata.IsDelegationSupportedByTable(DelegationCapability.CdsIn)) ||
                    IsValidNode(node, binding))
                {
                    return(true);
                }
            }

            switch (node.Kind)
            {
            case NodeKind.DottedName:
            {
                if (!opDelStrategy.IsOpSupportedByTable(metadata, node, binding))
                {
                    return(false);
                }

                var dottedNodeValStrategy = _function.GetDottedNameNodeDelegationStrategy();
                return(dottedNodeValStrategy.IsValidDottedNameNode(node.AsDottedName(), binding, metadata, opDelStrategy));
            }

            case NodeKind.Call:
            {
                if (!opDelStrategy.IsOpSupportedByTable(metadata, node, binding))
                {
                    return(false);
                }

                var cNodeValStrategy = _function.GetCallNodeDelegationStrategy();
                return(cNodeValStrategy.IsValidCallNode(node.AsCall(), binding, metadata));
            }

            case NodeKind.FirstName:
            {
                var firstNameNodeValStrategy = _function.GetFirstNameNodeDelegationStrategy();
                return(firstNameNodeValStrategy.IsValidFirstNameNode(node.AsFirstName(), binding, opDelStrategy));
            }

            case NodeKind.UnaryOp:
            {
                if (!opDelStrategy.IsOpSupportedByTable(metadata, node, binding))
                {
                    return(false);
                }

                var unaryopNode = node.AsUnaryOpLit();
                IOpDelegationStrategy unaryOpNodeDelegationStrategy = _function.GetOpDelegationStrategy(unaryopNode.Op);
                return(unaryOpNodeDelegationStrategy.IsSupportedOpNode(unaryopNode, metadata, binding));
            }

            case NodeKind.BinaryOp:
            {
                if (!opDelStrategy.IsOpSupportedByTable(metadata, node, binding))
                {
                    return(false);
                }

                var binaryOpNode = node.AsBinaryOp().VerifyValue();
                opDelStrategy = _function.GetOpDelegationStrategy(binaryOpNode.Op, binaryOpNode);

                var binaryOpDelStrategy = (opDelStrategy as BinaryOpDelegationStrategy).VerifyValue();
                Contracts.Assert(binaryOpNode.Op == binaryOpDelStrategy.Op);

                if (!opDelStrategy.IsSupportedOpNode(node, metadata, binding))
                {
                    SuggestDelegationHint(binaryOpNode, binding);
                    return(false);
                }

                break;
            }

            default:
            {
                var kind = node.Kind;
                if (kind != NodeKind.BoolLit && kind != NodeKind.StrLit && kind != NodeKind.NumLit)
                {
                    var telemetryMessage = string.Format("NodeKind {0} unsupported.", kind);
                    SuggestDelegationHintAndAddTelemetryMessage(node, binding, telemetryMessage);
                    return(false);
                }

                break;
            }
            }

            return(true);
        }