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); }
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); }
public override bool CheckInvocation(TexlBinding binding, TexlNode[] args, DType[] argTypes, IErrorContainer errors, out DType returnType, out Dictionary <TexlNode, DType> nodeToCoercedTypeMap) { Contracts.AssertValue(args); Contracts.AssertAllValues(args); Contracts.AssertValue(argTypes); Contracts.Assert(args.Length == argTypes.Length); Contracts.AssertValue(errors); Contracts.Assert(MinArity <= args.Length && args.Length <= MaxArity); bool fValid = base.CheckInvocation(args, argTypes, errors, out returnType, out nodeToCoercedTypeMap); if (argTypes.Length == 2) { DType type0 = argTypes[0]; DType type1 = argTypes[1]; DType otherType = DType.Invalid; TexlNode otherArg = null; // At least one of the arguments has to be a table. if (type0.IsTable) { // Ensure we have a one-column table of numerics fValid &= CheckNumericColumnType(type0, args[0], errors, ref nodeToCoercedTypeMap); // Borrow the return type from the 1st arg returnType = type0; // Check arg1 below. otherArg = args[1]; otherType = type1; } else if (type1.IsTable) { // Ensure we have a one-column table of numerics fValid &= CheckNumericColumnType(type1, args[1], errors, ref nodeToCoercedTypeMap); // Since the 1st arg is not a table, make a new table return type *[Result:n] returnType = DType.CreateTable(new TypedName(DType.Number, OneColumnTableResultName)); // Check arg0 below. otherArg = args[0]; otherType = type0; } else { Contracts.Assert(returnType.IsTable); errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrTypeError); errors.EnsureError(DocumentErrorSeverity.Severe, args[1], TexlStrings.ErrTypeError); // Both args are invalid. No need to continue. return(false); } Contracts.Assert(otherType.IsValid); Contracts.AssertValue(otherArg); Contracts.Assert(returnType.IsTable); Contracts.Assert(!fValid || returnType.IsColumn); if (otherType.IsTable) { // Ensure we have a one-column table of numerics fValid &= CheckNumericColumnType(otherType, otherArg, errors, ref nodeToCoercedTypeMap); } else if (!DType.Number.Accepts(otherType)) { if (otherType.CoercesTo(DType.Number)) { CollectionUtils.Add(ref nodeToCoercedTypeMap, otherArg, DType.Number); } else { fValid = false; errors.EnsureError(DocumentErrorSeverity.Severe, otherArg, TexlStrings.ErrTypeError); } } } else { DType type0 = argTypes[0]; if (type0.IsTable) { // Ensure we have a one-column table of numerics fValid &= CheckNumericColumnType(type0, args[0], errors, ref nodeToCoercedTypeMap); // Borrow the return type from the 1st arg returnType = type0; } else { Contracts.Assert(returnType.IsTable); errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrTypeError); return(false); } } return(fValid); }
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); }
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); }
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); }
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); }
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); }