Esempio n. 1
0
        public void Errors(TexlNode node, DType nodeType, KeyValuePair <string, DType> schemaDifference, DType schemaDifferenceType)
        {
            Contracts.AssertValue(node);
            Contracts.AssertValid(nodeType);

            Error(DocumentErrorSeverity.Severe, node, TexlStrings.ErrBadSchema_ExpectedType, nodeType.GetKindString());

            // If there's no schema difference, this was just an invalid type.
            if (string.IsNullOrEmpty(schemaDifference.Key))
            {
                return;
            }

            if (schemaDifferenceType.IsValid)
            {
                Error(
                    DocumentErrorSeverity.Severe,
                    node,
                    TexlStrings.ErrColumnTypeMismatch_ColName_ExpectedType_ActualType,
                    schemaDifference.Key,
                    schemaDifference.Value.GetKindString(),
                    schemaDifferenceType.GetKindString());
            }
            else
            {
                Error(
                    DocumentErrorSeverity.Severe,
                    node,
                    TexlStrings.ErrColumnMissing_ColName_ExpectedType,
                    schemaDifference.Key,
                    schemaDifference.Value.GetKindString());
            }
        }
Esempio 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(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);
        }
Esempio n. 3
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);
        }
Esempio n. 4
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);
        }
Esempio n. 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 == 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);
        }
Esempio n. 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);
        }
Esempio n. 7
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);
        }
Esempio n. 8
0
        private static CoercionKind FlattenCoercionMatrix(DType fromType, DType toType)
        {
            switch (toType.Kind)
            {
            case DKind.Number:
            case DKind.Currency:
                return(GetToNumberCoercion(fromType));

            case DKind.Color:
            case DKind.PenImage:
                // It is not safe to coerce these.
                Contracts.Assert(false, "Unsupported type coercion");
                break;

            case DKind.Hyperlink:
                if (DType.String.Accepts(fromType))
                {
                    switch (fromType.Kind)
                    {
                    case DKind.Blob:
                        return(CoercionKind.BlobToHyperlink);

                    case DKind.Image:
                        return(CoercionKind.ImageToHyperlink);

                    case DKind.Media:
                        return(CoercionKind.MediaToHyperlink);

                    default:
                        return(CoercionKind.TextToHyperlink);
                    }
                }

                Contracts.Assert(false, "Unsupported type coercion");
                break;

            case DKind.Image:
                if (fromType.IsLargeImage)
                {
                    return(CoercionKind.LargeImageToImage);
                }

                if (fromType.Kind != DKind.Media && fromType.Kind != DKind.Blob && DType.String.Accepts(fromType))
                {
                    return(CoercionKind.TextToImage);
                }

                Contracts.Assert(false, "Unsupported type coercion");
                break;

            case DKind.Media:
                if (fromType.Kind != DKind.Image && fromType.Kind != DKind.Blob && DType.String.Accepts(fromType))
                {
                    return(CoercionKind.TextToMedia);
                }

                Contracts.Assert(false, "Unsupported type coercion");
                break;

            case DKind.Blob:
                if (DType.String.Accepts(fromType))
                {
                    return(CoercionKind.TextToBlob);
                }

                Contracts.Assert(false, "Unsupported type coercion");
                break;

            case DKind.String:
                return(GetToStringCoercion(fromType));

            case DKind.Enum:
                return(GetToEnumCoercion(fromType, toType));

            case DKind.Boolean:
                Contracts.Assert(DType.Number.Accepts(fromType) || DType.String.Accepts(fromType) || (DType.OptionSetValue.Accepts(fromType) && (fromType.OptionSetInfo?.IsBooleanValued ?? false)), "Unsupported type coercion");
                if (DType.Number.Accepts(fromType))
                {
                    return(CoercionKind.NumberToBoolean);
                }

                if (DType.String.Accepts(fromType))
                {
                    return(CoercionKind.TextToBoolean);
                }

                if (DType.OptionSetValue.Accepts(fromType) && (fromType.OptionSetInfo?.IsBooleanValued ?? false))
                {
                    return(CoercionKind.BooleanOptionSetToBoolean);
                }

                return(CoercionKind.None);    // Implicit coercion?

            case DKind.Record:
                Contracts.Assert(fromType.IsAggregate);
                Contracts.Assert(fromType.Kind == toType.Kind);

                return(CoercionKind.RecordToRecord);

            case DKind.Table:
                Contracts.Assert(fromType.IsAggregate);
                Contracts.Assert(fromType.Kind == DKind.Table || fromType.Kind == DKind.Record);

                if (fromType.Kind == DKind.Table)
                {
                    return(CoercionKind.TableToTable);
                }

                if (fromType.Kind == DKind.Record)
                {
                    return(CoercionKind.RecordToTable);
                }

                Contracts.Assert(false, "Unexpected type for coercion.");
                break;

            case DKind.DateTime:
            case DKind.DateTimeNoTimeZone:
                Contracts.Assert(DType.String.Accepts(fromType) || DType.Number.Accepts(fromType) || DType.Time.Accepts(fromType) || DType.Date.Accepts(fromType), "Unsupported type coercion");
                if (DType.Number.Accepts(fromType))
                {
                    return(CoercionKind.NumberToDateTime);
                }
                else if (DType.Date.Accepts(fromType))
                {
                    return(CoercionKind.DateToDateTime);
                }
                else if (DType.Time.Accepts(fromType))
                {
                    return(CoercionKind.TimeToDateTime);
                }
                return(CoercionKind.TextToDateTime);

            case DKind.Time:
                Contracts.Assert(DType.String.Accepts(fromType) || DType.Number.Accepts(fromType) || DType.DateTime.Accepts(fromType) || DType.Date.Accepts(fromType), "Unsupported type coercion");
                if (DType.Number.Accepts(fromType))
                {
                    return(CoercionKind.NumberToTime);
                }
                else if (DType.Date.Accepts(fromType))
                {
                    return(CoercionKind.DateToTime);
                }
                else if (DType.DateTime.Accepts(fromType))
                {
                    return(CoercionKind.DateTimeToTime);
                }
                return(CoercionKind.TextToTime);

            case DKind.Date:
                Contracts.Assert(DType.String.Accepts(fromType) || DType.Number.Accepts(fromType) || DType.DateTime.Accepts(fromType) || DType.Time.Accepts(fromType), "Unsupported type coercion");
                if (DType.Number.Accepts(fromType))
                {
                    return(CoercionKind.NumberToDate);
                }
                else if (DType.Time.Accepts(fromType))
                {
                    return(CoercionKind.TimeToDate);
                }
                else if (DType.DateTime.Accepts(fromType))
                {
                    return(CoercionKind.DateTimeToDate);
                }
                return(CoercionKind.TextToDate);

            case DKind.OptionSetValue:
                Contracts.Assert(DType.OptionSetValue.Accepts(fromType) || (DType.Boolean.Accepts(fromType) && (toType.OptionSetInfo?.IsBooleanValued ?? false)), "Unsupported type coercion");

                if (DType.Boolean.Accepts(fromType) && (toType.OptionSetInfo?.IsBooleanValued ?? false))
                {
                    return(CoercionKind.BooleanToOptionSet);
                }

                return(CoercionKind.None);    // Implicit coercion?

            case DKind.ViewValue:
                Contracts.Assert(DType.ViewValue.Accepts(fromType), "Unsupported type coercion");
                return(CoercionKind.None);    // Implicit coercion?

            default:
                // Nothing else can be coerced.
                Contracts.Assert(false, "Unsupported type coercion");
                break;
            }
            // This should be impossible, the caller can catch and treat it as CoercionKind.None but should investigate.
            throw new InvalidCoercionException($"Attempting to generate invalid coercion from {fromType.GetKindString()} to {toType.GetKindString()}");
        }