// Gets if the type can be constructed from the given list of expressions public static bool CanConstructType(ShaderType type, List <ExprResult> args, out string error) { error = null; if (type == ShaderType.Void) { error = "Cannot construct the 'void' type."; return(false); } if (type.IsHandleType()) { error = $"Cannot manually construct a handle type ('{type}')."; return(false); } // Immediately fail if any arguments are arrays or handle types var badarg = args.FindIndex(arg => arg.IsArray || arg.Type.IsHandleType()); if (badarg != -1) { error = $"Type construction argument {badarg} cannot be an array or handle type ({args[badarg].Type}[{args[badarg].IsArray}]."; return(false); } if (!type.IsMatrixType()) // Vectors and scalars { var ccount = type.GetComponentCount(); if (ccount == 1) // Scalars { if (args.Count != 1) { error = "Scalar constructors can only have one argument."; return(false); } if (!args[0].Type.IsScalarType()) { error = "Scalars can only be constructed from other non-array scalar types."; return(false); } return(true); } else // Vectors { var comptype = type.GetComponentType(); if (args.Count > ccount) // Too many arguments { error = $"Too many arguments for constructing vector type '{type}'."; return(false); } if (args.Count == 1) // Direct casting between vectors -or- filling out entire vector with one value { if (args[0].Type.IsScalarType()) { if (!args[0].Type.CanPromoteTo(comptype)) { error = $"Cannot construct vector type '{type}' from scalar type '{args[0].Type}'."; return(false); } return(true); } if (!args[0].Type.IsVectorType() || (args[0].Type.GetComponentCount() < ccount)) { error = "Can only cast between vector types of the same size or larger (through concatenation)."; return(false); } if (!args[0].Type.CanPromoteTo(type)) { error = $"No casting rules exist to cast a '{args[0].Type}' vector to a '{type}' vector."; return(false); } return(true); } if (args.Count == ccount) // Directly supplying each component { var bidx = args.FindIndex(arg => !arg.Type.IsScalarType() || !arg.Type.CanPromoteTo(comptype)); if (bidx != -1) { error = $"Type constructor argument {bidx} must be a '{comptype}' compatible non-array scalar type."; return(false); } return(true); } else // Some mix of other argument types { var bidx = args.FindIndex(arg => arg.Type.IsMatrixType() || !arg.Type.GetComponentType().CanPromoteTo(comptype)); if (bidx != -1) { error = $"The type constructor argument {bidx} must be a '{comptype}' compatible non-array scalar or vector type."; return(false); } var csum = args.Sum(arg => arg.Type.GetComponentCount()); if (csum != ccount) { error = $"The type constructor arguments must provide the exact numer of components required ({ccount} != {csum})."; return(false); } return(true); } } } else // Matrices { if (args.Count == 1) // Constructing a diagonal matrix, or a direct matrix cast { if (args[0].Type.IsMatrixType()) { return(true); // Direct matrix casts always work } if (!args[0].Type.IsScalarType() || !args[0].Type.CanPromoteTo(ShaderType.Float)) { error = $"Diagonal matrices can only be constructed from capatible scalar types."; return(false); } return(true); } // Simply need enough compatible arguments to fill each matrix component exactly var bidx = args.FindIndex(arg => arg.Type.IsMatrixType() || !arg.Type.GetComponentType().CanPromoteTo(ShaderType.Float)); if (bidx != -1) { error = $"The matrix constructor argument {bidx} must be a 'Float' compatible scalar or vector type."; return(false); } var csum = args.Sum(arg => arg.Type.GetComponentCount()); var tsum = (type == ShaderType.Mat2) ? 4 : (type == ShaderType.Mat3) ? 9 : 16; if (tsum != csum) { error = $"Matrix constructors must be given exactly enough arguments to fill their components ({csum} != {tsum})."; return(false); } return(true); } }