Ejemplo n.º 1
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.AssertValue(argTypes);
            Contracts.Assert(args.Length == argTypes.Length);
            Contracts.AssertValue(errors);
            Contracts.Assert(MinArity <= args.Length && args.Length <= MaxArity);

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

            // The first arg determines the scope type for the lambda params, and the return type.
            DType typeScope;

            fArgsValid &= ScopeInfo.CheckInput(args[0], argTypes[0], errors, out typeScope);
            Contracts.Assert(typeScope.IsRecord);

            // The result type has N additional columns, as specified by (args[1],args[2]), (args[3],args[4]), ... etc.
            returnType = typeScope.ToTable();

            int count = args.Length;

            if ((count & 1) == 0)
            {
                errors.EnsureError(DocumentErrorSeverity.Severe, args[0].Parent.CastList().Parent.CastCall(), TexlStrings.ErrBadArityOdd, count);
            }

            for (var i = 1; i < count; i += 2)
            {
                TexlNode nameArg     = args[i];
                DType    nameArgType = argTypes[i];

                // Verify we have a string literal for the column name. Accd to spec, we don't support
                // arbitrary expressions that evaluate to string values, because these values contribute to
                // type analysis, so they need to be known upfront (before AddColumns executes).
                StrLitNode nameNode;
                if (nameArgType.Kind != DKind.String ||
                    (nameNode = nameArg.AsStrLit()) == null)
                {
                    fArgsValid = false;
                    errors.EnsureError(DocumentErrorSeverity.Severe, nameArg, TexlStrings.ErrExpectedStringLiteralArg_Name, nameArg.ToString());
                    continue;
                }

                // Verify that the name is valid.
                if (!DName.IsValidDName(nameNode.Value))
                {
                    fArgsValid = false;
                    errors.EnsureError(DocumentErrorSeverity.Severe, nameArg, TexlStrings.ErrArgNotAValidIdentifier_Name, nameNode.Value);
                    continue;
                }

                DName  columnName = new DName(nameNode.Value);
                string colName;
                if (DType.TryGetDisplayNameForColumn(typeScope, columnName, out colName))
                {
                    columnName = new DName(colName);
                }

                // Verify that the name doesn't already exist as either a logical or display name
                DType  columnType;
                string unused;
                if (typeScope.TryGetType(columnName, out columnType) || DType.TryGetLogicalNameForColumn(typeScope, columnName, out unused))
                {
                    fArgsValid = false;
                    errors.EnsureError(DocumentErrorSeverity.Moderate, nameArg, TexlStrings.ErrColExists_Name, columnName);
                    continue;
                }

                if (i + 1 >= count)
                {
                    break;
                }

                columnType = argTypes[i + 1];

                // Augment the result type to include the specified column, and verify that it
                // hasn't been specified already within the same invocation.
                bool fError = false;
                returnType = returnType.Add(ref fError, DPath.Root, columnName, columnType);
                if (fError)
                {
                    fArgsValid = false;
                    errors.EnsureError(DocumentErrorSeverity.Moderate, nameArg, TexlStrings.ErrColConflict_Name, columnName);
                    continue;
                }
            }

            return(fArgsValid);
        }
Ejemplo n.º 2
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.AssertValue(argTypes);
            Contracts.Assert(args.Length == argTypes.Length);
            Contracts.AssertValue(errors);
            nodeToCoercedTypeMap = null;
            int viewCount = 0;

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

            var dataSourceVisitor = new ViewFilterDataSourceVisitor(binding);

            // Ensure that all the args starting at index 1 are booleans or view
            for (int i = 1; i < args.Length; i++)
            {
                if (argTypes[i].Kind == DKind.ViewValue)
                {
                    if (++viewCount > 1)
                    {
                        // Only one view expected
                        errors.EnsureError(DocumentErrorSeverity.Severe, args[i], TexlStrings.ErrOnlyOneViewExpected);
                        fArgsValid = false;
                        continue;
                    }

                    // Use the visitor to get the datasource info and if a view was already used anywhere in the node tree.
                    args[0].Accept(dataSourceVisitor);
                    var dataSourceInfo = dataSourceVisitor.cdsDataSourceInfo;

                    if (dataSourceVisitor.ContainsViewFilter)
                    {
                        // Only one view expected
                        errors.EnsureError(DocumentErrorSeverity.Severe, args[i], TexlStrings.ErrOnlyOneViewExpected);
                        fArgsValid = false;
                        continue;
                    }

                    if (dataSourceInfo != null)
                    {
                        // Verify the view belongs to the same datasource
                        var viewInfo = argTypes[i].ViewInfo.VerifyValue();
                        if (viewInfo.RelatedEntityName != dataSourceInfo.Name)
                        {
                            errors.EnsureError(DocumentErrorSeverity.Severe, args[i], TexlStrings.ErrViewFromCurrentTableExpected, dataSourceInfo.Name);
                            fArgsValid = false;
                        }
                    }
                    else
                    {
                        errors.EnsureError(DocumentErrorSeverity.Severe, args[i], TexlStrings.ErrBooleanExpected);
                        fArgsValid = false;
                    }

                    continue;
                }
                else if (DType.Boolean.Accepts(argTypes[i]))
                {
                    continue;
                }
                else if (!argTypes[i].CoercesTo(DType.Boolean))
                {
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[i], TexlStrings.ErrBooleanExpected);
                    fArgsValid = false;
                    continue;
                }
            }

            // The first Texl function arg determines the cursor type, the scope type for the lambda params, and the return type.
            DType typeScope;

            fArgsValid &= ScopeInfo.CheckInput(args[0], argTypes[0], errors, out typeScope);

            Contracts.Assert(typeScope.IsRecord);
            returnType = typeScope.ToTable();

            return(fArgsValid);
        }