public bool ValidateExpression(GrapeCodeGeneratorConfiguration config, GrapeExpression expression) { if (expression != null) { GrapeAst ast = config.Ast; string errorMessage = ""; if (GrapeAstVisitor.IsTypeInTypeArray(expression.GetType(), accessExpressionValidator.NodeType)) { return accessExpressionValidator.ValidateNode(expression); } else if (expression.GetType() == typeof(GrapeAddExpression)) { GrapeAddExpression addExpression = expression as GrapeAddExpression; if (!(typeCheckingUtils.DoesExpressionResolveToType(config, expression, addExpression.Left, "int_base") && typeCheckingUtils.DoesExpressionResolveToType(config, expression, addExpression.Right, "int_base", ref errorMessage)) || !(typeCheckingUtils.DoesExpressionResolveToType(config, expression, addExpression.Left, "fixed_base", ref errorMessage) && typeCheckingUtils.DoesExpressionResolveToType(config, expression, addExpression.Right, "fixed_base", ref errorMessage)) || !(typeCheckingUtils.DoesExpressionResolveToType(config, expression, addExpression.Left, "string_base", ref errorMessage) && typeCheckingUtils.DoesExpressionResolveToType(config, expression, addExpression.Right, "string_base", ref errorMessage))) { errorSink.AddError(new GrapeErrorSink.Error { Description = "Cannot resolve addition expressions to the same type or addition expressions resolve to a type that is unable to be merged. " + errorMessage, FileName = expression.FileName, Entity = addExpression }); if (!config.ContinueOnError) { return false; } } } else if (expression.GetType() == typeof(GrapeConditionalExpression)) { GrapeConditionalExpression conditionalExpression = expression as GrapeConditionalExpression; if (conditionalExpression.Type == GrapeConditionalExpression.GrapeConditionalExpressionType.BinaryAnd || conditionalExpression.Type == GrapeConditionalExpression.GrapeConditionalExpressionType.BinaryOr) { if (!typeCheckingUtils.DoesExpressionResolveToType(config, expression, conditionalExpression.Left, "int_base", ref errorMessage) || !typeCheckingUtils.DoesExpressionResolveToType(config, expression, conditionalExpression.Right, "int_base", ref errorMessage)) { errorSink.AddError(new GrapeErrorSink.Error { Description = "Cannot resolve expression to the type 'int_base'. " + errorMessage, FileName = expression.FileName, Entity = conditionalExpression }); if (!config.ContinueOnError) { return false; } } } else { if (!typeCheckingUtils.DoesExpressionResolveToType(config, expression, conditionalExpression.Left, "bool_base", ref errorMessage) || !typeCheckingUtils.DoesExpressionResolveToType(config, expression, conditionalExpression.Right, "bool_base", ref errorMessage)) { errorSink.AddError(new GrapeErrorSink.Error { Description = "Cannot resolve expression to the type 'bool_base'. " + errorMessage, FileName = expression.FileName, Entity = conditionalExpression }); if (!config.ContinueOnError) { return false; } } } } else if (expression.GetType() == typeof(GrapeMultiplicationExpression)) { GrapeMultiplicationExpression multiplicationExpression = expression as GrapeMultiplicationExpression; if (!(typeCheckingUtils.DoesExpressionResolveToType(config, expression, multiplicationExpression.Left, "int_base", ref errorMessage) && typeCheckingUtils.DoesExpressionResolveToType(config, expression, multiplicationExpression.Right, "int_base", ref errorMessage)) || !(typeCheckingUtils.DoesExpressionResolveToType(config, expression, multiplicationExpression.Left, "fixed_base", ref errorMessage) && typeCheckingUtils.DoesExpressionResolveToType(config, expression, multiplicationExpression.Right, "fixed_base", ref errorMessage))) { errorSink.AddError(new GrapeErrorSink.Error { Description = "Cannot resolve addition expressions to the same type or addition expressions resolve to a type that is unable to be merged. " + errorMessage, FileName = expression.FileName, Entity = expression }); if (!config.ContinueOnError) { return false; } } } else if (expression.GetType() == typeof(GrapeNameofExpression)) { GrapeNameofExpression nameofExpression = expression as GrapeNameofExpression; if (nameofExpression.Value.GetType() != typeof(GrapeMemberExpression)) { errorSink.AddError(new GrapeErrorSink.Error { Description = "Cannot resolve expression to type, field or function.", FileName = expression.FileName, Entity = expression }); if (!config.ContinueOnError) { return false; } } string qualifiedId = nameofExpression.Value.ToString(); GrapeEntity valueEntity = (new List<GrapeEntity>(typeCheckingUtils.GetEntitiesForAccessExpression(config, nameofExpression.Value, expression, out errorMessage, false)))[0]; if (valueEntity == null) { errorSink.AddError(new GrapeErrorSink.Error { Description = "Cannot find entity for expression '" + qualifiedId + "'. " + errorMessage, FileName = expression.FileName, Entity = expression }); if (!config.ContinueOnError) { return false; } } GrapeClass c = expression.GetLogicalParentOfEntityType<GrapeClass>(); GrapeModifier.GrapeModifierType modifiers = c.GetAppropriateModifiersForEntityAccess(config, valueEntity); GrapeModifier.GrapeModifierType potentialModifiers = valueEntity.GetPotentialModifiersOfEntity(); bool invalidModifiers = false; if (modifiers != 0) { if (potentialModifiers == 0) { if (modifiers == GrapeModifier.GrapeModifierType.Public) { invalidModifiers = false; } else { invalidModifiers = true; } } else { if (modifiers != potentialModifiers) { invalidModifiers = true; } } } else { invalidModifiers = true; } if (invalidModifiers) { errorSink.AddError(new GrapeErrorSink.Error { Description = "Cannot access member '" + qualifiedId + "'.", FileName = expression.FileName, Entity = expression }); if (!config.ContinueOnError) { return false; } } } else if (expression.GetType() == typeof(GrapeShiftExpression)) { GrapeShiftExpression shiftExpression = expression as GrapeShiftExpression; if (!(typeCheckingUtils.DoesExpressionResolveToType(config, expression, shiftExpression.Left, "int_base", ref errorMessage) && typeCheckingUtils.DoesExpressionResolveToType(config, expression, shiftExpression.Right, "int_base", ref errorMessage))) { errorSink.AddError(new GrapeErrorSink.Error { Description = "Cannot resolve shift expressions to the same type or addition expressions resolve to a type that is unable to be merged. " + errorMessage, FileName = expression.FileName, Entity = expression }); if (!config.ContinueOnError) { return false; } } } else if (expression.GetType() == typeof(GrapeTypecastExpression)) { GrapeTypecastExpression typecastExpression = expression as GrapeTypecastExpression; if (typeCheckingUtils.DoesExpressionResolveToType(config, typecastExpression, typecastExpression.Value, "text_base")) { errorSink.AddError(new GrapeErrorSink.Error { Description = "Cannot cast from type 'text_base'.", FileName = expression.FileName, Entity = expression }); if (!config.ContinueOnError) { return false; } } return typeCheckingUtils.DoesExpressionResolveToType(config, expression, typecastExpression.Value, typecastExpression.TypeName); } else if (expression.GetType() == typeof(GrapeUnaryExpression)) { GrapeUnaryExpression unaryExpression = expression as GrapeUnaryExpression; if (unaryExpression.Type == GrapeUnaryExpression.GrapeUnaryExpressionType.Not) { if (!typeCheckingUtils.DoesExpressionResolveToType(config, expression, unaryExpression.Value, "bool_base", ref errorMessage)) { errorSink.AddError(new GrapeErrorSink.Error { Description = "Cannot resolve expression to the type 'bool_base'. " + errorMessage, FileName = expression.FileName, Entity = expression }); if (!config.ContinueOnError) { return false; } } } else if (!(typeCheckingUtils.DoesExpressionResolveToType(config, expression, unaryExpression.Value, "int_base", ref errorMessage))) { errorSink.AddError(new GrapeErrorSink.Error { Description = "Cannot resolve expression to the type 'int_base'. " + errorMessage, FileName = expression.FileName, Entity = expression }); if (!config.ContinueOnError) { return false; } } } } return true; }
public bool DoesExpressionResolveToType(GrapeCodeGeneratorConfiguration config, GrapeEntity parent, GrapeExpression expression, string typeName, ref string errorMessage) { if (parent == null) { throw new ArgumentNullException("parent"); } if (expression is GrapeLiteralExpression) { if (typeName == literalTypes[((GrapeLiteralExpression)expression).Type]) { return true; } else { GrapeClass c = astUtils.GetClassWithNameFromImportedPackagesInFile(config.Ast, typeName, expression.FileName); if (c != null && c.IsClassInInheritanceTree(config, astUtils.GetClassWithNameFromImportedPackagesInFile(config.Ast, literalTypes[((GrapeLiteralExpression)expression).Type], expression.FileName))) { return true; } } return false; } else if (expression is GrapeConditionalExpression) { GrapeConditionalExpression conditionalExpression = expression as GrapeConditionalExpression; if (conditionalExpression.Type == GrapeConditionalExpression.GrapeConditionalExpressionType.BinaryAnd || conditionalExpression.Type == GrapeConditionalExpression.GrapeConditionalExpressionType.BinaryOr) { return DoesExpressionResolveToType(config, parent, conditionalExpression.Left, "int_base", ref errorMessage) && DoesExpressionResolveToType(config, parent, conditionalExpression.Right, "int_base", ref errorMessage); } string leftType = GetTypeNameForTypeAccessExpression(config, conditionalExpression.Left, ref errorMessage); string rightType = GetTypeNameForTypeAccessExpression(config, conditionalExpression.Right, ref errorMessage); if (errorMessage != "") { return false; } bool result = leftType == rightType; if (!result) { GrapeClass left = astUtils.GetClassWithNameFromImportedPackagesInFile(config.Ast, leftType, parent.FileName); GrapeClass right = astUtils.GetClassWithNameFromImportedPackagesInFile(config.Ast, rightType, parent.FileName); if (left != null && right != null) { if (left.IsClassInInheritanceTree(config, right)) { return true; } } } if (!result) { errorMessage = "Cannot resolve left and right expressions to the same type. The resolved left type is '" + leftType + "' and the resolved right type is '" + rightType + "'."; } return result; } else if (expression is GrapeMemberExpression) { GrapeEntity entity = (new List<GrapeEntity>(GetEntitiesForAccessExpression(config, expression as GrapeMemberExpression, parent, out errorMessage)))[0]; if (entity != null) { GrapeClass type = null; if (entity is GrapeVariable) { type = astUtils.GetClassWithNameFromImportedPackagesInFile(config.Ast, GetCorrectNativeTypeName(GetTypeNameForTypeAccessExpression(config, ((GrapeVariable)entity).Type, ref errorMessage)), parent.FileName); } else if (entity is GrapeMethod) { type = astUtils.GetClassWithNameFromImportedPackagesInFile(config.Ast, GetCorrectNativeTypeName(GetTypeNameForTypeAccessExpression(config, ((GrapeMethod)entity).ReturnType, ref errorMessage)), parent.FileName); } else if (entity is GrapeClass) { type = entity as GrapeClass; } if (type != null) { return type.Name == GetCorrectNativeTypeName(typeName) || IsTypeInClassInheritanceTree(config, typeName, type); } } else { if (expression.GetType() == typeof(GrapeMemberExpression)) { string qualifiedId = ((GrapeMemberExpression)expression).GetAccessExpressionQualifiedId(); foreach (GalaxyConstantAttribute constant in GalaxyNativeInterfaceAggregator.Constants) { if (constant.Name == qualifiedId) { return GetCorrectNativeTypeName(constant.Type) == GetCorrectNativeTypeName(typeName); } } } else if (expression.GetType() == typeof(GrapeCallExpression)) { GrapeCallExpression callExpression = expression as GrapeCallExpression; GrapeAccessExpression accessExpression = callExpression.GetAccessExpressionInAccessExpression(); string qualifiedId = accessExpression.GetAccessExpressionQualifiedId(); foreach (GalaxyFunctionAttribute function in GalaxyNativeInterfaceAggregator.Functions) { if (function.Name == qualifiedId) { if (!IsSignatureValid(config, function, callExpression, out errorMessage)) { return false; } return GetCorrectNativeTypeName(function.Type) == GetCorrectNativeTypeName(typeName); } } } } } else if (expression is GrapeNameofExpression) { GrapeNameofExpression nameofExpression = expression as GrapeNameofExpression; if (nameofExpression.Value.GetType() != typeof(GrapeMemberExpression)) { errorMessage = "Cannot resolve expression to type, field or method."; if (!config.ContinueOnError) { return false; } } string qualifiedId = nameofExpression.Value.ToString(); GrapeEntity valueEntity = (new List<GrapeEntity>(GetEntitiesForAccessExpression(config, nameofExpression.Value, expression, out errorMessage, false)))[0]; if (valueEntity == null) { errorMessage = "Cannot find entity for expression '" + qualifiedId + "'. " + errorMessage; if (!config.ContinueOnError) { return false; } } GrapeClass c = expression.GetLogicalParentOfEntityType<GrapeClass>(); GrapeModifier.GrapeModifierType modifiers = c.GetAppropriateModifiersForEntityAccess(config, valueEntity); GrapeModifier.GrapeModifierType potentialModifiers = valueEntity.GetPotentialModifiersOfEntity(); bool invalidModifiers = false; if (modifiers != 0) { if (potentialModifiers == 0) { if (modifiers == GrapeModifier.GrapeModifierType.Public) { invalidModifiers = false; } else { invalidModifiers = true; } } else { if (modifiers != potentialModifiers) { invalidModifiers = true; } } } else { invalidModifiers = true; } if (invalidModifiers) { errorMessage = "Cannot access member '" + qualifiedId + "'."; if (!config.ContinueOnError) { return false; } } return typeName == "string_base"; } else if (expression is GrapeAddExpression) { GrapeAddExpression addExpression = expression as GrapeAddExpression; string leftType = GetTypeNameForTypeAccessExpression(config, addExpression.Left, ref errorMessage); string rightType = GetTypeNameForTypeAccessExpression(config, addExpression.Right, ref errorMessage); if (errorMessage != "") { return false; } return leftType == rightType; } else if (expression is GrapeMultiplicationExpression) { GrapeMultiplicationExpression multiplicationExpression = expression as GrapeMultiplicationExpression; string leftType = GetTypeNameForTypeAccessExpression(config, multiplicationExpression.Left, ref errorMessage); string rightType = GetTypeNameForTypeAccessExpression(config, multiplicationExpression.Right, ref errorMessage); if (errorMessage != "") { return false; } return leftType == rightType; } else if (expression is GrapeShiftExpression) { GrapeShiftExpression shiftExpression = expression as GrapeShiftExpression; string leftType = GetTypeNameForTypeAccessExpression(config, shiftExpression.Left, ref errorMessage); string rightType = GetTypeNameForTypeAccessExpression(config, shiftExpression.Right, ref errorMessage); if (errorMessage != "") { return false; } return leftType == rightType; } else if (expression is GrapeTypecastExpression) { GrapeTypecastExpression typecastExpression = expression as GrapeTypecastExpression; if (DoesExpressionResolveToType(config, typecastExpression, typecastExpression.Value, "text_base")) { errorMessage = "Cannot cast from type 'text_base'."; return false; } return DoesExpressionResolveToType(config, parent, typecastExpression.TypeName, typeName, ref errorMessage); } else if (expression is GrapeUnaryExpression) { GrapeUnaryExpression unaryExpression = expression as GrapeUnaryExpression; return DoesExpressionResolveToType(config, parent, unaryExpression.Value, typeName, ref errorMessage); } return false; }