/// <summary> /// Constructor. /// </summary> /// <param name="rule"></param> /// <param name="validatedExpression"></param> public CastExpression(CoercionRule rule, IExpression validatedExpression) : this(validatedExpression.Location, CoercionKind.Implicit, rule.CastingType.Name, validatedExpression) { this.rule = rule; SemanticType = rule.CastingType; Expression = validatedExpression; }
/// <summary> /// Validation: Checks whether the type really exists and whether the conversion is allowed. /// </summary> /// <param name="context"></param> /// <returns></returns> public CastExpression Validate(IValidationScope context) { var type = context.TypeSystem.GetTypeByName(CastTypeName)?.NativeType; if (type == null) { throw new LocateableException(Location, $"There is no type {CastTypeName}!"); } Expression = Expression.Validate(context); rule = context.TypeSystem.GetCoercionRule(Expression.SemanticType, type); if (rule == null) { throw new LocateableException(Location, $"Can not convert type into a '{CastTypeName}'."); } SemanticType = type; return(this); }
/// <summary> /// Adds a new coercion rule. Trys to avoid cyclic implicit casts chains. /// </summary> /// <typeparam name="TOriginalType"></typeparam> /// <typeparam name="TCastingType"></typeparam> /// <param name="kind"></param> /// <param name="cast"></param> public void AddCoercionRule <TOriginalType, TCastingType>(CoercionKind kind, Func <TOriginalType, TCastingType> cast) { var original = typeof(TOriginalType); var casting = typeof(TCastingType); if (GetTypeByNative(original) == null) { throw new UnknownTypeException(original); } if (GetTypeByNative(casting) == null) { throw new UnknownTypeException(casting); } var rule = new CoercionRule(kind, original, casting, a => cast((TOriginalType)a)); if (allCoercionRules.TryGetEdge(original, casting, out TaggedEdge <Type, CoercionRule> existingEdge)) { throw new InvalidOperationException("Such a rule does already exist!"); } var edge = new TaggedEdge <System.Type, CoercionRule>(original, casting, rule); if (kind == CoercionKind.Implicit) { implicitCoercionRules.AddVertex(original); implicitCoercionRules.AddVertex(casting); implicitCoercionRules.AddEdge(edge); if (implicitCoercionRules.StronglyConnectedComponents(out IDictionary <Type, int> components) != implicitCoercionRules.Vertices.Count()) { implicitCoercionRules.RemoveEdge(edge); throw new InvalidOperationException("This action would create an implicit conversion cycle!"); } } allCoercionRules.AddVertex(original); allCoercionRules.AddVertex(casting); allCoercionRules.AddEdge(edge); Debug.WriteLine($"- added coercion rule from '{original.Name}' to '{casting.Name}'"); }