Ejemplo n.º 1
0
        private TypeSymbol GetBinaryOperationType(TypeManagerContext context, BinaryOperationSyntax syntax)
        {
            var errors = new List <ErrorDiagnostic>();

            var operandType1 = this.GetTypeInfoInternal(context, syntax.LeftExpression);

            CollectErrors(errors, operandType1);

            var operandType2 = this.GetTypeInfoInternal(context, syntax.RightExpression);

            CollectErrors(errors, operandType2);

            if (errors.Any())
            {
                return(new ErrorTypeSymbol(errors));
            }

            // operands don't appear to have errors
            // let's match the operator now
            var operatorInfo = BinaryOperationResolver.TryMatchExact(syntax.Operator, operandType1, operandType2);

            if (operatorInfo != null)
            {
                // we found a match - use its return type
                return(operatorInfo.ReturnType);
            }

            // we do not have a match
            // operand types didn't match available operators
            return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax).BinaryOperatorInvalidType(Operators.BinaryOperatorToText[syntax.Operator], operandType1.Name, operandType2.Name)));
        }
Ejemplo n.º 2
0
        private LanguageExpression ConvertBinary(BinaryOperationSyntax syntax)
        {
            LanguageExpression operand1 = ConvertExpression(syntax.LeftExpression);
            LanguageExpression operand2 = ConvertExpression(syntax.RightExpression);

            return(syntax.Operator switch
            {
                BinaryOperator.LogicalOr => CreateFunction("or", operand1, operand2),
                BinaryOperator.LogicalAnd => CreateFunction("and", operand1, operand2),
                BinaryOperator.Equals => CreateFunction("equals", operand1, operand2),
                BinaryOperator.NotEquals => CreateFunction("not",
                                                           CreateFunction("equals", operand1, operand2)),
                BinaryOperator.EqualsInsensitive => CreateFunction("equals",
                                                                   CreateFunction("toLower", operand1),
                                                                   CreateFunction("toLower", operand2)),
                BinaryOperator.NotEqualsInsensitive => CreateFunction("not",
                                                                      CreateFunction("equals",
                                                                                     CreateFunction("toLower", operand1),
                                                                                     CreateFunction("toLower", operand2))),
                BinaryOperator.LessThan => CreateFunction("less", operand1, operand2),
                BinaryOperator.LessThanOrEqual => CreateFunction("lessOrEquals", operand1, operand2),
                BinaryOperator.GreaterThan => CreateFunction("greater", operand1, operand2),
                BinaryOperator.GreaterThanOrEqual => CreateFunction("greaterOrEquals", operand1, operand2),
                BinaryOperator.Add => CreateFunction("add", operand1, operand2),
                BinaryOperator.Subtract => CreateFunction("sub", operand1, operand2),
                BinaryOperator.Multiply => CreateFunction("mul", operand1, operand2),
                BinaryOperator.Divide => CreateFunction("div", operand1, operand2),
                BinaryOperator.Modulo => CreateFunction("mod", operand1, operand2),
                BinaryOperator.Coalesce => CreateFunction("coalesce", operand1, operand2),
                _ => throw new NotImplementedException($"Cannot emit unexpected binary operator '{syntax.Operator}'."),
            });
Ejemplo n.º 3
0
        public override void VisitBinaryOperationSyntax(BinaryOperationSyntax syntax)
        => AssignTypeWithCaching(syntax, () => {
            var errors = new List <ErrorDiagnostic>();

            var operandType1 = VisitAndReturnType(syntax.LeftExpression);
            CollectErrors(errors, operandType1);

            var operandType2 = VisitAndReturnType(syntax.RightExpression);
            CollectErrors(errors, operandType2);

            if (errors.Any())
            {
                return(new ErrorTypeSymbol(errors));
            }

            // operands don't appear to have errors
            // let's match the operator now
            var operatorInfo = BinaryOperationResolver.TryMatchExact(syntax.Operator, operandType1, operandType2);
            if (operatorInfo != null)
            {
                // we found a match - use its return type
                return(operatorInfo.ReturnType);
            }

            // we do not have a match
            // operand types didn't match available operators
            return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax).BinaryOperatorInvalidType(Operators.BinaryOperatorToText[syntax.Operator], operandType1.Name, operandType2.Name)));
        });
Ejemplo n.º 4
0
 public override void VisitBinaryOperationSyntax(BinaryOperationSyntax syntax) =>
 this.BuildWithSpread(() => base.VisitBinaryOperationSyntax(syntax));
Ejemplo n.º 5
0
        private LanguageExpression ConvertBinary(BinaryOperationSyntax syntax)
        {
            LanguageExpression operand1 = ConvertExpression(syntax.LeftExpression);
            LanguageExpression operand2 = ConvertExpression(syntax.RightExpression);

            switch (syntax.Operator)
            {
            case BinaryOperator.LogicalOr:
                return(CreateFunction("or", operand1, operand2));

            case BinaryOperator.LogicalAnd:
                return(CreateFunction("and", operand1, operand2));

            case BinaryOperator.Equals:
                return(CreateFunction("equals", operand1, operand2));

            case BinaryOperator.NotEquals:
                return(CreateFunction("not",
                                      CreateFunction("equals", operand1, operand2)));

            case BinaryOperator.EqualsInsensitive:
                return(CreateFunction("equals",
                                      CreateFunction("toLower", operand1),
                                      CreateFunction("toLower", operand2)));

            case BinaryOperator.NotEqualsInsensitive:
                return(CreateFunction("not",
                                      CreateFunction("equals",
                                                     CreateFunction("toLower", operand1),
                                                     CreateFunction("toLower", operand2))));

            case BinaryOperator.LessThan:
                return(CreateFunction("less", operand1, operand2));

            case BinaryOperator.LessThanOrEqual:
                return(CreateFunction("lessOrEquals", operand1, operand2));

            case BinaryOperator.GreaterThan:
                return(CreateFunction("greater", operand1, operand2));

            case BinaryOperator.GreaterThanOrEqual:
                return(CreateFunction("greaterOrEquals", operand1, operand2));

            case BinaryOperator.Add:
                return(CreateFunction("add", operand1, operand2));

            case BinaryOperator.Subtract:
                return(CreateFunction("sub", operand1, operand2));

            case BinaryOperator.Multiply:
                return(CreateFunction("mul", operand1, operand2));

            case BinaryOperator.Divide:
                return(CreateFunction("div", operand1, operand2));

            case BinaryOperator.Modulo:
                return(CreateFunction("mod", operand1, operand2));

            default:
                throw new NotImplementedException($"Cannot emit unexpected binary operator '{syntax.Operator}'.");
            }
        }
Ejemplo n.º 6
0
 public override void VisitBinaryOperationSyntax(BinaryOperationSyntax syntax)
 {
     this.AppendError(syntax);
 }
Ejemplo n.º 7
0
 public override void VisitBinaryOperationSyntax(BinaryOperationSyntax syntax)
 {
     this.buffer.Append('(');
     base.VisitBinaryOperationSyntax(syntax);
     this.buffer.Append(')');
 }
Ejemplo n.º 8
0
        private void EmitResource(JsonTextWriter jsonWriter, ResourceMetadata resource, ExpressionEmitter emitter)
        {
            jsonWriter.WriteStartObject();

            // Note: conditions STACK with nesting.
            //
            // Children inherit the conditions of their parents, etc. This avoids a problem
            // where we emit a dependsOn to something that's not in the template, or not
            // being evaulated i the template.
            var conditions = new List <SyntaxBase>();
            var loops      = new List <(string name, ForSyntax @for, SyntaxBase?input)>();

            var ancestors = this.context.SemanticModel.ResourceAncestors.GetAncestors(resource);

            foreach (var ancestor in ancestors)
            {
                if (ancestor.AncestorType == ResourceAncestorGraph.ResourceAncestorType.Nested &&
                    ancestor.Resource.Symbol.DeclaringResource.Value is IfConditionSyntax ifCondition)
                {
                    conditions.Add(ifCondition.ConditionExpression);
                }

                if (ancestor.AncestorType == ResourceAncestorGraph.ResourceAncestorType.Nested &&
                    ancestor.Resource.Symbol.DeclaringResource.Value is ForSyntax @for)
                {
                    loops.Add((ancestor.Resource.Symbol.Name, @for, null));
                }
            }

            // Unwrap the 'real' resource body if there's a condition
            var body = resource.Symbol.DeclaringResource.Value;

            switch (body)
            {
            case IfConditionSyntax ifCondition:
                body = ifCondition.Body;
                conditions.Add(ifCondition.ConditionExpression);
                break;

            case ForSyntax @for:
                loops.Add((resource.Symbol.Name, @for, null));
                if (@for.Body is IfConditionSyntax loopFilter)
                {
                    body = loopFilter.Body;
                    conditions.Add(loopFilter.ConditionExpression);
                }
                else
                {
                    body = @for.Body;
                }

                break;
            }

            if (conditions.Count == 1)
            {
                emitter.EmitProperty("condition", conditions[0]);
            }
            else if (conditions.Count > 1)
            {
                var @operator = new BinaryOperationSyntax(
                    conditions[0],
                    SyntaxFactory.CreateToken(TokenType.LogicalAnd),
                    conditions[1]);
                for (var i = 2; i < conditions.Count; i++)
                {
                    @operator = new BinaryOperationSyntax(
                        @operator,
                        SyntaxFactory.CreateToken(TokenType.LogicalAnd),
                        conditions[i]);
                }

                emitter.EmitProperty("condition", @operator);
            }

            if (loops.Count == 1)
            {
                var batchSize = GetBatchSize(resource.Symbol.DeclaringResource);
                emitter.EmitProperty("copy", () => emitter.EmitCopyObject(loops[0].name, loops[0].@for, loops[0].input, batchSize: batchSize));
            }
            else if (loops.Count > 1)
            {
                throw new InvalidOperationException("nested loops are not supported");
            }

            if (context.Settings.EnableSymbolicNames && resource.IsExistingResource)
            {
                jsonWriter.WritePropertyName("existing");
                jsonWriter.WriteValue(true);
            }

            var importSymbol = context.SemanticModel.Root.ImportDeclarations.FirstOrDefault(i => resource.Type.DeclaringNamespace.AliasNameEquals(i.Name));

            if (importSymbol is not null)
            {
                emitter.EmitProperty("import", importSymbol.Name);
            }

            if (resource.IsAzResource)
            {
                emitter.EmitProperty("type", resource.TypeReference.FormatType());
                if (resource.TypeReference.ApiVersion is not null)
                {
                    emitter.EmitProperty("apiVersion", resource.TypeReference.ApiVersion);
                }
            }
            else
            {
                emitter.EmitProperty("type", resource.TypeReference.FormatName());
            }

            if (context.SemanticModel.EmitLimitationInfo.ResourceScopeData.TryGetValue(resource, out var scopeData))
            {
                ScopeHelper.EmitResourceScopeProperties(context.SemanticModel, scopeData, emitter, body);
            }

            if (resource.IsAzResource)
            {
                emitter.EmitProperty(AzResourceTypeProvider.ResourceNamePropertyName, emitter.GetFullyQualifiedResourceName(resource));
                emitter.EmitObjectProperties((ObjectSyntax)body, ResourcePropertiesToOmit.Add(AzResourceTypeProvider.ResourceNamePropertyName));
            }
            else
            {
                jsonWriter.WritePropertyName("properties");
                jsonWriter.WriteStartObject();

                emitter.EmitObjectProperties((ObjectSyntax)body, ResourcePropertiesToOmit);

                jsonWriter.WriteEndObject();
            }

            this.EmitDependsOn(jsonWriter, resource.Symbol, emitter, body);

            // Since we don't want to be mutating the body of the original ObjectSyntax, we create an placeholder body in place
            // and emit its properties to merge decorator properties.
            foreach (var(property, val) in AddDecoratorsToBody(
                         resource.Symbol.DeclaringResource,
                         SyntaxFactory.CreateObject(Enumerable.Empty <ObjectPropertySyntax>()),
                         resource.Symbol.Type).ToNamedPropertyValueDictionary())
            {
                emitter.EmitProperty(property, val);
            }

            jsonWriter.WriteEndObject();
        }
Ejemplo n.º 9
0
        private void EmitResource(JsonTextWriter jsonWriter, ResourceMetadata resource, ExpressionEmitter emitter)
        {
            jsonWriter.WriteStartObject();

            // Note: conditions STACK with nesting.
            //
            // Children inherit the conditions of their parents, etc. This avoids a problem
            // where we emit a dependsOn to something that's not in the template, or not
            // being evaulated i the template.
            var conditions = new List <SyntaxBase>();
            var loops      = new List <(string name, ForSyntax @for, SyntaxBase?input)>();

            var ancestors = this.context.SemanticModel.ResourceAncestors.GetAncestors(resource);

            foreach (var ancestor in ancestors)
            {
                if (ancestor.AncestorType == ResourceAncestorGraph.ResourceAncestorType.Nested &&
                    ancestor.Resource.Symbol.DeclaringResource.Value is IfConditionSyntax ifCondition)
                {
                    conditions.Add(ifCondition.ConditionExpression);
                }

                if (ancestor.AncestorType == ResourceAncestorGraph.ResourceAncestorType.Nested &&
                    ancestor.Resource.Symbol.DeclaringResource.Value is ForSyntax @for)
                {
                    loops.Add((ancestor.Resource.Symbol.Name, @for, null));
                }
            }

            // Unwrap the 'real' resource body if there's a condition
            var body = resource.Symbol.DeclaringResource.Value;

            switch (body)
            {
            case IfConditionSyntax ifCondition:
                body = ifCondition.Body;
                conditions.Add(ifCondition.ConditionExpression);
                break;

            case ForSyntax @for:
                loops.Add((resource.Symbol.Name, @for, null));
                if (@for.Body is IfConditionSyntax loopFilter)
                {
                    body = loopFilter.Body;
                    conditions.Add(loopFilter.ConditionExpression);
                }
                else
                {
                    body = @for.Body;
                }

                break;
            }

            if (conditions.Count == 1)
            {
                emitter.EmitProperty("condition", conditions[0]);
            }
            else if (conditions.Count > 1)
            {
                var @operator = new BinaryOperationSyntax(
                    conditions[0],
                    SyntaxFactory.CreateToken(TokenType.LogicalAnd),
                    conditions[1]);
                for (var i = 2; i < conditions.Count; i++)
                {
                    @operator = new BinaryOperationSyntax(
                        @operator,
                        SyntaxFactory.CreateToken(TokenType.LogicalAnd),
                        conditions[i]);
                }

                emitter.EmitProperty("condition", @operator);
            }

            if (loops.Count == 1)
            {
                var batchSize = GetBatchSize(resource.Symbol.DeclaringResource);
                emitter.EmitProperty("copy", () => emitter.EmitCopyObject(loops[0].name, loops[0].@for, loops[0].input, batchSize: batchSize));
            }
            else if (loops.Count > 1)
            {
                throw new InvalidOperationException("nested loops are not supported");
            }

            emitter.EmitProperty("type", resource.TypeReference.FullyQualifiedType);
            emitter.EmitProperty("apiVersion", resource.TypeReference.ApiVersion);
            if (context.SemanticModel.EmitLimitationInfo.ResourceScopeData.TryGetValue(resource, out var scopeData))
            {
                ScopeHelper.EmitResourceScopeProperties(context.SemanticModel, scopeData, emitter, body);
            }

            emitter.EmitProperty("name", emitter.GetFullyQualifiedResourceName(resource));

            if (context.Settings.EnableSymbolicNames && resource.IsExistingResource)
            {
                jsonWriter.WritePropertyName("existing");
                jsonWriter.WriteValue(true);
            }

            body = AddDecoratorsToBody(resource.Symbol.DeclaringResource, (ObjectSyntax)body, resource.Type);
            emitter.EmitObjectProperties((ObjectSyntax)body, ResourcePropertiesToOmit);

            this.EmitDependsOn(jsonWriter, resource.Symbol, emitter, body);

            jsonWriter.WriteEndObject();
        }