示例#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.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);

            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 colors.
                fValid &= CheckColorColumnType(type0, args[0], errors, ref nodeToCoercedTypeMap);
                // Borrow the return type from the 1st arg.
                returnType = type0;
                // Check arg1 below.
                otherArg  = args[1];
                otherType = type1;

                fValid &= CheckOtherType(otherType, otherArg, DType.Number, errors, ref nodeToCoercedTypeMap);

                Contracts.Assert(returnType.IsTable);
                Contracts.Assert(!fValid || returnType.IsColumn);
            }
            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:c]
                returnType = DType.CreateTable(new TypedName(DType.Color, OneColumnTableResultName));
                // Check arg0 below.
                otherArg  = args[0];
                otherType = type0;

                fValid &= CheckOtherType(otherType, otherArg, DType.Color, errors, ref nodeToCoercedTypeMap);

                Contracts.Assert(returnType.IsTable);
                Contracts.Assert(!fValid || returnType.IsColumn);
            }
            else
            {
                Contracts.Assert(returnType.IsTable);

                errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrTypeError_Ex1_Ex2_Found, TableKindString, DType.Color.GetKindString(), type0.GetKindString());
                errors.EnsureError(DocumentErrorSeverity.Severe, args[1], TexlStrings.ErrTypeError_Ex1_Ex2_Found, TableKindString, DType.Number.GetKindString(), type1.GetKindString());
                // Both args are invalid. No need to continue.
                return(false);
            }

            return(fValid);
        }
示例#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.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);

            Contracts.Assert(returnType.IsTable);

            returnType = argTypes[0];

            DType exprType = argTypes[1];

            if (!exprType.IsPrimitive || exprType.IsOptionSet)
            {
                fValid = false;
                errors.EnsureError(args[1], TexlStrings.ErrSortWrongType);
            }

            if (args.Length == 3 && argTypes[2] != DType.String)
            {
                fValid = false;
                errors.EnsureError(args[2], TexlStrings.ErrSortIncorrectOrder);
            }

            return(fValid);
        }
示例#3
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);

            // The argument should be a table of one column.
            DType argType = argTypes[0];

            if (!argType.IsTable)
            {
                fValid = false;
                errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrNeedTable_Func, Name);
            }
            else if (argType.GetNames(DPath.Root).Count() != 1)
            {
                fValid = false;
                errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrNeedTableCol_Func, Name);
            }

            return(fValid);
        }
示例#4
0
 public TexlError EnsureError(TexlNode node, ErrorResourceKey errKey, params object[] args)
 {
     if (DefaultSeverity <= maximumSeverity)
     {
         return(errors.EnsureError(node, errKey, args));
     }
     return(null);
 }
示例#5
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 == 2);
            Contracts.Assert(argTypes.Length == 2);
            Contracts.AssertValue(errors);


            if (!base.CheckInvocation(binding, args, argTypes, errors, out returnType, out nodeToCoercedTypeMap))
            {
                return(false);
            }

            // Check if first argument is poly type or an activity pointer
            if (!argTypes[0].IsPolymorphic && !argTypes[0].IsActivityPointer)
            {
                errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrBadType_ExpectedType_ProvidedType, DKind.Polymorphic.ToString(), argTypes[0].GetKindString());
                return(false);
            }

            // Check if table arg referrs to a connected data source.
            TexlNode            tableArg = args[1];
            FirstNameInfo       tableInfo;
            IExternalDataSource tableDsInfo;

            if (!binding.TryGetFirstNameInfo(tableArg.Id, out tableInfo) ||
                (tableDsInfo = (tableInfo.Data as IExternalDataSource)) == null ||
                !(tableDsInfo is IExternalTabularDataSource))
            {
                errors.EnsureError(tableArg, TexlStrings.ErrAsTypeAndIsTypeExpectConnectedDataSource);
                return(false);
            }

            if (binding.Document.Properties.EnabledFeatures.IsEnhancedDelegationEnabled && (tableDsInfo is IExternalCdsDataSource) && argTypes[0].HasPolymorphicInfo)
            {
                var expandInfo = argTypes[0].PolymorphicInfo.TryGetExpandInfo(tableDsInfo.TableMetadata.Name);
                if (expandInfo != null)
                {
                    returnType = argTypes[0].ExpandPolymorphic(argTypes[1], expandInfo);
                    return(true);
                }
            }

            returnType = argTypes[1].ToRecord();
            return(true);
        }
示例#6
0
        private bool CheckOtherType(DType otherType, TexlNode otherArg, DType expectedType, IErrorContainer errors, ref Dictionary <TexlNode, DType> nodeToCoercedTypeMap)
        {
            Contracts.Assert(otherType.IsValid);
            Contracts.AssertValue(otherArg);
            Contracts.Assert(expectedType == DType.Color || expectedType == DType.Number);
            Contracts.AssertValue(errors);

            if (otherType.IsTable)
            {
                // Ensure we have a one-column table of numerics/color values based on expected type.
                return(expectedType == DType.Number ? CheckNumericColumnType(otherType, otherArg, errors, ref nodeToCoercedTypeMap) : CheckColorColumnType(otherType, otherArg, errors, ref nodeToCoercedTypeMap));
            }

            if (expectedType.Accepts(otherType))
            {
                return(true);
            }

            if (otherType.CoercesTo(expectedType))
            {
                CollectionUtils.Add(ref nodeToCoercedTypeMap, otherArg, expectedType);
                return(true);
            }

            errors.EnsureError(DocumentErrorSeverity.Severe, otherArg, TexlStrings.ErrTypeError_Ex1_Ex2_Found, TableKindString, expectedType.GetKindString(), otherType.GetKindString());
            return(false);
        }
示例#7
0
        // Typecheck an input for this function, and get the cursor type for an invocation with that input.
        // arg0 and arg0Type correspond to the input and its type.
        // The cursor type for aggregate functions is generally the type of a row in the input schema (table),
        // for example Table in an invocation Average(Table, valueFunction).
        // Returns true on success, false if the input or its type are invalid with respect to this function's declaration
        // (and populate the error container accordingly).
        public virtual bool CheckInput(TexlNode inputNode, DType inputSchema, IErrorContainer errors, out DType typeScope)
        {
            Contracts.AssertValue(inputNode);
            Contracts.Assert(inputSchema.IsValid);
            Contracts.AssertValue(errors);

            CallNode callNode = inputNode.Parent.CastList().Parent.CastCall();

            Contracts.AssertValue(callNode);

            typeScope = inputSchema;

            bool fArgsValid = true;

            if (_function.ParamTypes.Length == 0)
            {
                switch (typeScope.Kind)
                {
                case DKind.Record:
                    break;

                case DKind.Error:
                    fArgsValid = false;
                    errors.EnsureError(inputNode, TexlStrings.ErrBadType);
                    break;

                default:
                    fArgsValid = false;
                    errors.Error(callNode, TexlStrings.ErrBadType);
                    break;
                }
            }
            else if (_function.ParamTypes[0].IsTable)
            {
                if (!typeScope.IsTable)
                {
                    errors.Error(callNode, TexlStrings.ErrNeedTable_Func, _function.Name);
                    fArgsValid = false;
                }
                // This assumes that the lambdas operate on the individual records
                // of the table, not the entire table.
                bool fError = false;
                typeScope   = typeScope.ToRecord(ref fError);
                fArgsValid &= !fError;
            }
            else
            {
                Contracts.Assert(_function.ParamTypes[0].IsRecord);
                if (!typeScope.IsRecord)
                {
                    errors.Error(callNode, TexlStrings.ErrNeedRecord_Func, _function.Name);
                    bool fError = false;
                    typeScope  = typeScope.ToRecord(ref fError);
                    fArgsValid = false;
                }
            }

            return(fArgsValid);
        }
示例#8
0
        // Typecheck an invocation of Table.
        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 isValid = base.CheckInvocation(args, argTypes, errors, out returnType, out nodeToCoercedTypeMap);

            Contracts.Assert(returnType.IsTable);

            // Ensure that all args (if any) are records with compatible schemas.
            DType rowType = DType.EmptyRecord;

            for (int i = 0; i < argTypes.Length; i++)
            {
                DType argType = argTypes[i];
                if (!argType.IsRecord)
                {
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[i], TexlStrings.ErrNeedRecord);
                    isValid = false;
                }
                else if (!rowType.CanUnionWith(argType))
                {
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[i], TexlStrings.ErrIncompatibleRecord);
                    isValid = false;
                }
                else
                {
                    bool isUnionError = false;
                    rowType = DType.Union(ref isUnionError, rowType, argType);
                    Contracts.Assert(!isUnionError);
                    Contracts.Assert(rowType.IsRecord);
                }
            }

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

            return(isValid);
        }
示例#9
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.AssertAllValid(argTypes);
            Contracts.Assert(args.Length == argTypes.Length);
            Contracts.AssertValue(errors);
            Contracts.Assert(MinArity <= args.Length && args.Length <= MaxArity);

            nodeToCoercedTypeMap = null;

            bool  isValid = true;
            DType argType = argTypes[0];

            if (!DType.Number.Accepts(argType) && !DType.String.Accepts(argType))
            {
                if (argType.CoercesTo(DType.DateTime) && !argType.IsControl)
                {
                    CollectionUtils.Add(ref nodeToCoercedTypeMap, args[0], DType.DateTime);
                }
                else
                {
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrNumberOrStringExpected);
                    isValid = false;
                }
            }

            if (args.Length > 1)
            {
                argType = argTypes[1];
                if (!DType.String.Accepts(argType))
                {
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[1], TexlStrings.ErrStringExpected);
                    isValid = false;
                }
            }

            returnType = DType.Number;
            return(isValid);
        }
示例#10
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);
            DType type0  = argTypes[0];

            // Arg0 should not be a Time
            if (type0.Kind == DKind.Time)
            {
                fValid = false;
                errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrDateExpected);
            }
            returnType = ReturnType;
            return(fValid);
        }
示例#11
0
        public void CheckLiteralPredicates(TexlNode[] args, IErrorContainer errors)
        {
            Contracts.AssertValue(args);
            Contracts.AssertValue(errors);

            if (!AcceptsLiteralPredicates)
            {
                for (int i = 0; i < args.Length; i++)
                {
                    if (_function.IsLambdaParam(i))
                    {
                        if (args[i].Kind == NodeKind.BoolLit ||
                            args[i].Kind == NodeKind.NumLit ||
                            args[i].Kind == NodeKind.StrLit)
                        {
                            errors.EnsureError(DocumentErrorSeverity.Warning, args[i], TexlStrings.WarnLiteralPredicate);
                        }
                    }
                }
            }
        }
示例#12
0
        public override bool CheckInvocation(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);

            Contracts.Assert(returnType == DType.Number);

            bool matchedWithCoercion;

            // Ensure that all the arguments are numeric/coercible to numeric.
            for (int i = 0; i < argTypes.Length; i++)
            {
                if (CheckType(args[i], argTypes[i], DType.Number, DefaultErrorContainer, out matchedWithCoercion))
                {
                    if (matchedWithCoercion)
                    {
                        CollectionUtils.Add(ref nodeToCoercedTypeMap, args[i], DType.Number, allowDupes: true);
                    }
                }
                else
                {
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[i], TexlStrings.ErrNumberExpected);
                    fValid = false;
                }
            }

            if (!fValid)
            {
                nodeToCoercedTypeMap = null;
            }

            return(fValid);
        }
示例#13
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);

            Contracts.Assert(returnType == DType.DateTime);

            DType type0 = argTypes[0];

            if (fValid)
            {
                // Arg0 should be either a DateTime or Date.
                if (type0.Kind == DKind.Date)
                {
                    // Max resolution we support right now is "Days". If we start supporting sub-day resolutions
                    // then we need to revisit this and return DateTime in those cases.
                    returnType = DType.Date;
                }
                else if (type0.Kind == DKind.DateTime)
                {
                    returnType = ReturnType;
                }
                else
                {
                    fValid = false;
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrDateExpected);
                    returnType = ReturnType;
                }
            }

            return(fValid);
        }
示例#14
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);

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

            Contracts.Assert(returnType == DType.Number);

            // Ensure that all the args starting at index 1 are booleans.
            for (int i = 1; i < args.Length; i++)
            {
                if (!DType.Boolean.Accepts(argTypes[i]))
                {
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[i], TexlStrings.ErrBooleanExpected);
                    fValid = false;
                }
            }

            return(fValid);
        }
示例#15
0
        public override bool CheckInvocation(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.Assert(args.Length == 1);
            Contracts.AssertValue(errors);

            var reifiedError      = ErrorType.ReifiedError();
            var acceptedFields    = reifiedError.GetNames(DPath.Root);
            var requiredKindField = acceptedFields.Where(tn => tn.Name == "Kind").First();

            Contracts.Assert(requiredKindField.Type.IsEnum);
            var optionalFields = acceptedFields.Where(tn => tn.Name != "Kind");

            returnType           = DType.ObjNull;
            nodeToCoercedTypeMap = null;

            var argument     = args[0];
            var argumentType = argTypes[0];

            if (argumentType.Kind != DKind.Record && argumentType.Kind != DKind.Table)
            {
                errors.EnsureError(argument, TexlStrings.ErrBadType);
                return(false);
            }

            // We cache the whole name list regardless of path.
            var names = argumentType.GetNames(DPath.Root).ToArray();

            // First handle required fields (currently only 'Kind')
            if (!names.Any(field => field.Name == requiredKindField.Name))
            {
                // Kind is required, point it out to the maker, and specify the enumeration type.
                errors.EnsureError(
                    argument,
                    TexlStrings.ErrBadSchema_ExpectedType,
                    reifiedError.GetKindString());
                errors.Error(
                    argument,
                    TexlStrings.ErrColumnMissing_ColName_ExpectedType,
                    requiredKindField.Name.Value,
                    "ErrorKind");
                return(false);
            }

            var argumentKindType = names.First(tn => tn.Name == requiredKindField.Name).Type;

            if (!argumentKindType.CoercesTo(requiredKindField.Type))
            {
                errors.EnsureError(
                    argument,
                    TexlStrings.ErrBadSchema_ExpectedType,
                    reifiedError.GetKindString());
                errors.Error(
                    argument,
                    TexlStrings.ErrBadRecordFieldType_FieldName_ExpectedType,
                    requiredKindField.Name.Value,
                    "ErrorKind");
                return(false);
            }

            bool valid = true;

            var record = argument.AsRecord();

            foreach (var name in names)
            {
                if (!acceptedFields.Any(field => field.Name == name.Name))
                {
                    // If they have a record literal, we can position the errors for rejected fields.
                    if (record != null)
                    {
                        errors.EnsureError(record.Children.Where((_, i) => record.Ids[i].Name == name.Name).FirstOrDefault() ?? record, TexlStrings.ErrErrorIrrelevantField);
                    }
                    else
                    {
                        errors.EnsureError(argument, TexlStrings.ErrErrorIrrelevantField);
                    }
                    valid = false;
                }
            }

            bool matchedWithCoercion;
            bool typeValid;

            if (argumentType.Kind == DKind.Record)
            {
                // A record with the proper types for the fields that are specified.
                var expectedOptionalFieldsRecord = DType.CreateRecord(
                    acceptedFields.Where(field =>
                                         // Kind has already been handled before
                                         field.Name != "Kind" && names.Any(name => name.Name == field.Name)));

                typeValid = CheckType(argument, argumentType, expectedOptionalFieldsRecord, errors, true, out matchedWithCoercion);
            }
            else
            {
                // A table with the proper types for the fields that are specified.
                var expectedOptionalFieldsTable = DType.CreateTable(
                    acceptedFields.Where(field =>
                                         // Kind has already been handled before
                                         field.Name != "Kind" && names.Any(name => name.Name == field.Name)));
                typeValid = CheckType(argument, argumentType, expectedOptionalFieldsTable, errors, true, out matchedWithCoercion);
            }

            if (!typeValid)
            {
                errors.EnsureError(DocumentErrorSeverity.Severe, argument, TexlStrings.ErrTypeError);
                valid = false;
            }
            else if (matchedWithCoercion && valid)
            {
                var recordOrTableSchema   = acceptedFields.Where(field => names.Any(name => name.Name == field.Name));
                var expectedRecordOrTable = argumentType.Kind == DKind.Record ?
                                            DType.CreateRecord(recordOrTableSchema) :
                                            DType.CreateTable(recordOrTableSchema);
                CollectionUtils.Add(ref nodeToCoercedTypeMap, argument, expectedRecordOrTable);
            }

            return(valid);
        }
示例#16
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);
        }
示例#17
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);

            Contracts.Assert(returnType.IsTable);

            if (!argTypes[0].IsTable)
            {
                fArgsValid = false;
                errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrNeedTable_Func, Name);
            }
            else
            {
                returnType = argTypes[0];
            }

            // The result type has N fewer columns, as specified by (args[1],args[2],args[3],...)
            int count = args.Length;

            for (var i = 1; i < count; i++)
            {
                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 DropColumns 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);

                // Verify that the name exists.
                DType columnType;
                if (!returnType.TryGetType(columnName, out columnType))
                {
                    fArgsValid = false;
                    returnType.ReportNonExistingName(FieldNameKind.Logical, errors, columnName, nameArg);
                    continue;
                }

                // Drop the specified column from the result type.
                bool fError = false;
                returnType = returnType.Drop(ref fError, DPath.Root, columnName);
                Contracts.Assert(!fError);
            }

            return(fArgsValid);
        }
示例#18
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);

            DType type0 = argTypes[0];
            DType type1 = argTypes[1];
            DType type2 = argTypes[2];

            // Arg0 should be either a string or a column of strings.
            // Its type dictates the function return type.
            if (type0.IsTable)
            {
                // Ensure we have a one-column table of strings
                fValid &= CheckStringColumnType(type0, args[0], errors, ref nodeToCoercedTypeMap);
                // Borrow the return type from the 1st arg
                returnType = type0;
            }
            else
            {
                returnType = DType.CreateTable(new TypedName(DType.String, OneColumnTableResultName));
                if (!DType.String.Accepts(type0))
                {
                    if (type0.CoercesTo(DType.String))
                    {
                        CollectionUtils.Add(ref nodeToCoercedTypeMap, args[0], DType.String);
                    }
                    else
                    {
                        fValid = false;
                        errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrStringExpected);
                    }
                }
            }

            // Arg1 should be either a string or a column of strings.
            if (type1.IsTable)
            {
                fValid &= CheckStringColumnType(type1, args[1], errors, ref nodeToCoercedTypeMap);
            }
            else if (!DType.String.Accepts(type1))
            {
                if (type1.CoercesTo(DType.String))
                {
                    CollectionUtils.Add(ref nodeToCoercedTypeMap, args[1], DType.String);
                }
                else
                {
                    fValid = false;
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[1], TexlStrings.ErrStringExpected);
                }
            }

            // Arg2 should be either a string or a column of strings.
            if (type2.IsTable)
            {
                fValid &= CheckStringColumnType(type2, args[2], errors, ref nodeToCoercedTypeMap);
            }
            else if (!DType.String.Accepts(type2))
            {
                if (type2.CoercesTo(DType.String))
                {
                    CollectionUtils.Add(ref nodeToCoercedTypeMap, args[2], DType.String);
                }
                else
                {
                    fValid = false;
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[2], TexlStrings.ErrStringExpected);
                }
            }

            bool hasCount = args.Length == 4;

            if (hasCount)
            {
                DType type3 = argTypes[3];

                // Arg3 should be either a number or a column of numbers.
                if (type3.IsTable)
                {
                    fValid &= CheckNumericColumnType(type3, args[3], errors, ref nodeToCoercedTypeMap);
                }
                else if (!DType.Number.Accepts(type3))
                {
                    if (type3.CoercesTo(DType.Number))
                    {
                        CollectionUtils.Add(ref nodeToCoercedTypeMap, args[3], DType.Number);
                    }
                    else
                    {
                        fValid = false;
                        errors.EnsureError(DocumentErrorSeverity.Severe, args[3], TexlStrings.ErrNumberExpected);
                    }
                }
            }

            // At least one arg has to be a table.
            if (!(type0.IsTable || type1.IsTable || type2.IsTable) && (!hasCount || !argTypes[3].IsTable))
            {
                fValid = false;
                errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrTypeError);
                errors.EnsureError(DocumentErrorSeverity.Severe, args[1], TexlStrings.ErrTypeError);
                errors.EnsureError(DocumentErrorSeverity.Severe, args[2], TexlStrings.ErrTypeError);
                if (hasCount)
                {
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[3], TexlStrings.ErrTypeError);
                }
            }

            return(fValid);
        }
示例#19
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);
        }
示例#20
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;
            DType type       = ReturnType;

            bool isBehavior = binding.IsBehavior;

            Contracts.Assert(type == DType.Unknown);
            for (int i = 0; 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)
                {
                    // One of the args is also of unknown type, so we can't resolve the type of IfError
                    type       = typeSuper;
                    fArgsValid = false;
                }
                else if (!type.IsError)
                {
                    // Types don't resolve normally, coercion needed
                    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--;
                }
            }

            returnType = type;
            return(fArgsValid);
        }
示例#21
0
        public override bool CheckInvocation(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);

            DType type0 = argTypes[0];
            DType type1 = argTypes[1];

            TexlNode arg0 = args[0];
            TexlNode arg1 = args[1];

            // Arg0 should be either a number or a column of number (coercion is ok).
            bool matchedWithCoercion;

            if (type0.IsTable)
            {
                // Ensure we have a one-column table of numbers.
                fValid &= CheckNumericColumnType(type0, arg0, errors, ref nodeToCoercedTypeMap);
            }
            else if (CheckType(arg0, type0, DType.Number, DefaultErrorContainer, out matchedWithCoercion))
            {
                if (matchedWithCoercion)
                {
                    CollectionUtils.Add(ref nodeToCoercedTypeMap, arg0, DType.Number);
                }
            }
            else
            {
                fValid = false;
                errors.EnsureError(DocumentErrorSeverity.Severe, arg0, TexlStrings.ErrNumberExpected);
            }

            // Arg1 should be either a number or a column of number (coercion is ok).
            if (type1.IsTable)
            {
                fValid &= CheckNumericColumnType(type1, arg1, errors, ref nodeToCoercedTypeMap);
            }
            else if (CheckType(arg1, type1, DType.Number, DefaultErrorContainer, out matchedWithCoercion))
            {
                if (matchedWithCoercion)
                {
                    CollectionUtils.Add(ref nodeToCoercedTypeMap, arg1, DType.Number);
                }
            }
            else
            {
                fValid = false;
                errors.EnsureError(DocumentErrorSeverity.Severe, arg1, TexlStrings.ErrNumberExpected);
            }

            returnType = DType.CreateTable(new TypedName(DType.Number, OneColumnTableResultName));

            // At least one arg has to be a table.
            if (!(type0.IsTable || type1.IsTable))
            {
                fValid = false;
            }

            if (!fValid)
            {
                nodeToCoercedTypeMap = null;
            }

            return(fValid);
        }
示例#22
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.Assert(args.Length >= 1);
            Contracts.AssertValue(errors);

            nodeToCoercedTypeMap = null;

            int   count        = args.Length;
            bool  fArgsValid   = true;
            bool  fArgsNonNull = false;
            DType type         = ReturnType;

            for (int i = 0; i < count; i++)
            {
                TexlNode nodeArg = args[i];
                DType    typeArg = argTypes[i];

                if (typeArg.Kind == DKind.ObjNull)
                {
                    continue;
                }

                fArgsNonNull = true;
                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)
                {
                    // One of the args is also of unknown type, so we can't resolve the type of IfError
                    type       = typeSuper;
                    fArgsValid = false;
                }
                else if (!type.IsError)
                {
                    // Types don't resolve normally, coercion needed
                    if (typeArg.CoercesTo(type))
                    {
                        CollectionUtils.Add(ref nodeToCoercedTypeMap, nodeArg, type);
                    }
                    else
                    {
                        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 (!fArgsNonNull)
            {
                type = DType.ObjNull;
            }

            returnType = type;
            return(fArgsValid);
        }
示例#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);

            DType type0 = argTypes[0];
            DType type1 = argTypes[1];

            returnType = DType.CreateTable(new TypedName(DType.Number, OneColumnTableResultName));

            // Arg0 should be either a date or a column of dates.
            if (type0.IsTable)
            {
                // Ensure we have a one-column table of dates
                fValid &= CheckDateColumnType(type0, args[0], errors, ref nodeToCoercedTypeMap);
            }
            else if (!DType.DateTime.Accepts(type0))
            {
                if (type0.CoercesTo(DType.DateTime))
                {
                    CollectionUtils.Add(ref nodeToCoercedTypeMap, args[0], DType.DateTime);
                }
                else
                {
                    fValid = false;
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrDateExpected);
                }
            }

            // Arg1 should be either a a date or a column of dates.
            if (type1.IsTable)
            {
                // Ensure we have a one-column table of dates
                fValid &= CheckDateColumnType(type1, args[1], errors, ref nodeToCoercedTypeMap);
            }
            else if (!DType.DateTime.Accepts(type1))
            {
                if (type1.CoercesTo(DType.DateTime))
                {
                    CollectionUtils.Add(ref nodeToCoercedTypeMap, args[1], DType.DateTime);
                }
                else
                {
                    fValid = false;
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[1], TexlStrings.ErrDateExpected);
                }
            }

            bool hasUnits = args.Length == 3;

            if (hasUnits && !DType.String.Accepts(argTypes[2]))
            {
                // Arg2 should be a string
                fValid = false;
                errors.EnsureError(DocumentErrorSeverity.Severe, args[2], TexlStrings.ErrStringExpected);
            }

            // At least one arg has to be a table.
            if (!(type0.IsTable || type1.IsTable))
            {
                fValid = false;
                errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrTypeError);
                errors.EnsureError(DocumentErrorSeverity.Severe, args[1], TexlStrings.ErrTypeError);
            }

            return(fValid);
        }
示例#24
0
        public override bool CheckInvocation(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 isValid = true;

            returnType           = DType.String;
            nodeToCoercedTypeMap = null;

            TexlNode arg0     = args[0];
            DType    arg0Type = argTypes[0];

            bool  matchedWithCoercion;
            bool  isValidString   = true;
            bool  isValidNumber   = CheckType(arg0, arg0Type, DType.Number, DefaultErrorContainer, out matchedWithCoercion);
            DType arg0CoercedType = matchedWithCoercion ? DType.Number : DType.Invalid;

            if (!isValidNumber || matchedWithCoercion)
            {
                if (DType.DateTime.Accepts(arg0Type))
                {
                    // No coercion needed for datetimes here.
                    arg0CoercedType = DType.Invalid;
                }
                else
                {
                    isValidString = CheckType(arg0, arg0Type, DType.String, DefaultErrorContainer, out matchedWithCoercion);

                    if (isValidString)
                    {
                        if (matchedWithCoercion)
                        {
                            // If both the matches were with coercion, we pick string over number.
                            // For instance Text(true) returns true in the case of EXCEL. If we picked
                            // number coercion, then we would return 1 and it will not match EXCEL behavior.
                            arg0CoercedType = DType.String;
                        }
                        else
                        {
                            arg0CoercedType = DType.Invalid;
                        }
                    }
                }
            }

            if (!isValidNumber && !isValidString)
            {
                errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrNumberOrStringExpected);
                isValid = false;
            }

            if (args.Length < 2)
            {
                if (isValid && arg0CoercedType.IsValid)
                {
                    CollectionUtils.Add(ref nodeToCoercedTypeMap, arg0, arg0CoercedType);
                    return(true);
                }

                return(isValid);
            }

            StrLitNode formatNode;

            if (!DType.String.Accepts(argTypes[1]))
            {
                errors.EnsureError(DocumentErrorSeverity.Severe, args[1], TexlStrings.ErrStringExpected);
                isValid = false;
            }
            else if ((formatNode = args[1].AsStrLit()) != null)
            {
                // Verify statically that the format string doesn't contain BOTH numeric and date/time
                // format specifiers. If it does, that's an error accd to Excel and our spec.
                string fmt = formatNode.Value;

                // But firstly skip any locale-prefix
                if (fmt.StartsWith("[$-"))
                {
                    int end = fmt.IndexOf(']', 3);
                    if (end > 0)
                    {
                        fmt = fmt.Substring(end + 1);
                    }
                }
                bool hasDateTimeFmt = fmt.IndexOfAny(new char[] { 'm', 'd', 'y', 'h', 'H', 's', 'a', 'A', 'p', 'P' }) >= 0;
                bool hasNumericFmt  = fmt.IndexOfAny(new char[] { '0', '#' }) >= 0;
                if (hasDateTimeFmt && hasNumericFmt)
                {
                    errors.EnsureError(DocumentErrorSeverity.Moderate, formatNode, TexlStrings.ErrIncorrectFormat_Func, Name);
                    isValid = false;
                }
            }

            if (args.Length > 2)
            {
                DType argType = argTypes[2];
                if (!DType.String.Accepts(argType))
                {
                    errors.EnsureError(DocumentErrorSeverity.Severe, args[2], TexlStrings.ErrStringExpected);
                    isValid = false;
                }
            }

            if (isValid)
            {
                if (arg0CoercedType.IsValid)
                {
                    CollectionUtils.Add(ref nodeToCoercedTypeMap, arg0, arg0CoercedType);
                    return(true);
                }
            }
            else
            {
                nodeToCoercedTypeMap = null;
            }

            return(isValid);
        }
示例#25
0
文件: If.cs 项目: jgrisham/Power-Fx
        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);
        }
示例#26
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);

            Contracts.Assert(returnType.IsTable);

            returnType = argTypes[0];
            DType      sourceType  = argTypes[0];
            TexlNode   nameArg     = args[1];
            DType      nameArgType = argTypes[1];
            StrLitNode nameNode    = null;
            DType      columnType  = DType.Invalid;

            if (nameArgType.Kind != DKind.String)
            {
                errors.EnsureError(DocumentErrorSeverity.Severe, nameArg, TexlStrings.ErrStringExpected);
                fValid = false;
            }
            else if ((nameNode = nameArg.AsStrLit()) != null)
            {
                // Verify that the name is valid.
                if (DName.IsValidDName(nameNode.Value))
                {
                    DName columnName = new DName(nameNode.Value);

                    // Verify that the name exists.
                    if (!sourceType.TryGetType(columnName, out columnType))
                    {
                        sourceType.ReportNonExistingName(FieldNameKind.Logical, errors, columnName, nameNode);
                        fValid = false;
                    }
                    else if (!columnType.IsPrimitive)
                    {
                        fValid = false;
                        errors.EnsureError(nameArg, TexlStrings.ErrSortWrongType);
                    }
                }
                else
                {
                    errors.EnsureError(DocumentErrorSeverity.Severe, nameNode, TexlStrings.ErrArgNotAValidIdentifier_Name, nameNode.Value);
                    fValid = false;
                }
            }

            TexlNode valuesArg = args[2];
            IEnumerable <TypedName> columns;

            if ((columns = argTypes[2].GetNames(DPath.Root)).Count() != 1)
            {
                errors.EnsureError(DocumentErrorSeverity.Severe, valuesArg, TexlStrings.ErrInvalidSchemaNeedCol);
                return(false);
            }

            TypedName column = columns.Single();

            if (nameNode != null && columnType.IsValid && !columnType.Accepts(column.Type))
            {
                errors.EnsureError(DocumentErrorSeverity.Severe, valuesArg, TexlStrings.ErrTypeError_Arg_Expected_Found, nameNode.Value,
                                   columnType.GetKindString(), column.Type.GetKindString());
                fValid = false;
            }

            return(fValid);
        }
示例#27
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);

            Contracts.Assert(returnType.IsTable);

            returnType = argTypes[0];

            DType sourceType = argTypes[0];

            for (int i = 1; i < args.Length; i += 2)
            {
                TexlNode   colNameArg     = args[i];
                DType      colNameArgType = argTypes[i];
                StrLitNode nameNode;

                if (colNameArgType.Kind != DKind.String)
                {
                    errors.EnsureError(DocumentErrorSeverity.Severe, colNameArg, TexlStrings.ErrStringExpected);
                    fValid = false;
                }
                else if ((nameNode = colNameArg.AsStrLit()) != null)
                {
                    // Verify that the name is valid.
                    if (DName.IsValidDName(nameNode.Value))
                    {
                        DName columnName = new DName(nameNode.Value);

                        // Verify that the name exists.
                        DType columnType;
                        if (!sourceType.TryGetType(columnName, out columnType))
                        {
                            sourceType.ReportNonExistingName(FieldNameKind.Logical, errors, columnName, args[i]);
                            fValid = false;
                        }
                        else if (!columnType.IsPrimitive || columnType.IsOptionSet)
                        {
                            fValid = false;
                            errors.EnsureError(colNameArg, TexlStrings.ErrSortWrongType);
                        }
                    }
                    else
                    {
                        errors.EnsureError(DocumentErrorSeverity.Severe, nameNode, TexlStrings.ErrArgNotAValidIdentifier_Name, nameNode.Value);
                        fValid = false;
                    }
                }

                int nextArgIdx = i + 1;
                if (nextArgIdx < args.Length && argTypes[nextArgIdx] != DType.String)
                {
                    fValid = false;
                    errors.EnsureError(args[i + 1], TexlStrings.ErrSortIncorrectOrder);
                }
            }

            return(fValid);
        }
示例#28
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 isValidInvocation = base.CheckInvocation(args, argTypes, errors, out returnType, out nodeToCoercedTypeMap);

            Contracts.Assert(returnType.IsTable);

            if (!argTypes[0].IsTable)
            {
                isValidInvocation = false;
                errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrNeedTable_Func, Name);
            }
            else
            {
                returnType = argTypes[0];
            }

            DType colsToKeep = DType.EmptyTable;

            // The result type has N columns, as specified by (args[1],args[2],args[3],...)
            int count = args.Length;

            for (var i = 1; i < count; i++)
            {
                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 ShowColumns executes).
                StrLitNode nameNode;
                if (nameArgType.Kind != DKind.String || (nameNode = nameArg.AsStrLit()) == null)
                {
                    isValidInvocation = false;
                    errors.EnsureError(DocumentErrorSeverity.Severe, nameArg, TexlStrings.ErrExpectedStringLiteralArg_Name, nameArg.ToString());
                    continue;
                }

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

                DName columnName = new DName(nameNode.Value);

                // Verify that the name exists.
                DType columnType;
                if (!returnType.TryGetType(columnName, out columnType))
                {
                    isValidInvocation = false;
                    returnType.ReportNonExistingName(FieldNameKind.Logical, errors, columnName, args[i]);
                    continue;
                }

                // Verify that the name was only specified once.
                DType existingColumnType;
                if (colsToKeep.TryGetType(columnName, out existingColumnType))
                {
                    isValidInvocation = false;
                    errors.EnsureError(DocumentErrorSeverity.Warning, nameArg, TexlStrings.WarnColumnNameSpecifiedMultipleTimes_Name, columnName);
                    continue;
                }

                // Make a note of which columns are being kept.
                Contracts.Assert(columnType.IsValid);
                colsToKeep = colsToKeep.Add(columnName, columnType);
            }

            // Drop everything but the columns that need to be kept.
            returnType = colsToKeep;

            return(isValidInvocation);
        }