public LanguageExpression ConvertExpression()

in src/Bicep.Core/Emit/ExpressionConverter.cs [54:215]


        public LanguageExpression ConvertExpression(Expression expression)
        {
            switch (expression)
            {
                case BooleanLiteralExpression @bool:
                    return CreateFunction(@bool.Value ? "true" : "false");

                case IntegerLiteralExpression @int:
                    return @int.Value switch
                    {
                        // Bicep permits long values, but ARM's parser only permits int jtoken expressions.
                        // We can work around this by using the `json()` function to represent non-integer numerics.
                        > int.MaxValue or < int.MinValue => CreateFunction("json", new JTokenExpression(@int.Value.ToString(CultureInfo.InvariantCulture))),
                        _ => new JTokenExpression(@int.Value),
                    };

                case StringLiteralExpression @string:
                    return new JTokenExpression(@string.Value);

                case NullLiteralExpression _:
                    return CreateFunction("null");

                case InterpolatedStringExpression @string:
                    return ConvertString(@string);

                case ObjectExpression @object:
                    return ConvertObject(@object);

                case ArrayExpression array:
                    return ConvertArray(array);

                case UnaryExpression unary:
                    return ConvertUnary(unary);

                case BinaryExpression binary:
                    return ConvertBinary(binary);

                case TernaryExpression ternary:
                    return CreateFunction(
                        "if",
                        ConvertExpression(ternary.Condition),
                        ConvertExpression(ternary.True),
                        ConvertExpression(ternary.False));

                case FunctionCallExpression function:
                    return CreateFunction(
                        function.Name,
                        function.Parameters.Select(ConvertExpression));

                case UserDefinedFunctionCallExpression function:
                    return CreateFunction(
                        $"{EmitConstants.UserDefinedFunctionsNamespace}.{function.Symbol.Name}",
                        function.Parameters.Select(ConvertExpression));

                case SynthesizedUserDefinedFunctionCallExpression function:
                    return CreateFunction(
                        $"{function.Namespace}.{function.Name}",
                        function.Parameters.Select(ConvertExpression));

                case ImportedUserDefinedFunctionCallExpression importedFunction:
                    {
                        var (namespaceName, functionName) = GetFunctionName(context.SemanticModel.ImportClosureInfo.ImportedSymbolNames[importedFunction.Symbol]);
                        return CreateFunction(
                            $"{namespaceName}.{functionName}",
                            importedFunction.Parameters.Select(ConvertExpression));
                    }

                case WildcardImportInstanceFunctionCallExpression importedFunction:
                    {
                        var (namespaceName, functionName) = GetFunctionName(
                            context.SemanticModel.ImportClosureInfo.WildcardImportPropertyNames[new(importedFunction.ImportSymbol, importedFunction.MethodName)]);
                        return CreateFunction(
                            $"{namespaceName}.{functionName}",
                            importedFunction.Parameters.Select(ConvertExpression));
                    }

                case ResourceFunctionCallExpression listFunction when listFunction.Name.StartsWithOrdinalInsensitively(LanguageConstants.ListFunctionPrefix):
                    {
                        var resource = listFunction.Resource.Metadata;

                        var functionTargetExpression =
                            context.Settings.EnableSymbolicNames && resource is DeclaredResourceMetadata declared
                                ? GenerateSymbolicReference(declared, listFunction.Resource.IndexContext)
                                : ConvertExpression(new PropertyAccessExpression(
                                    listFunction.Resource.SourceSyntax,
                                    listFunction.Resource,
                                    "id",
                                    AccessExpressionFlags.None));

                        var apiVersion = resource.TypeReference.ApiVersion ?? throw new InvalidOperationException($"Expected resource type {resource.TypeReference.FormatName()} to contain version");
                        var apiVersionExpression = new JTokenExpression(apiVersion);

                        var listArgs = listFunction.Parameters.Length switch
                        {
                            0 => new LanguageExpression[] { functionTargetExpression, apiVersionExpression, },
                            _ => new LanguageExpression[] { functionTargetExpression, }.Concat(listFunction.Parameters.Select(ConvertExpression)),
                        };

                        return CreateFunction(listFunction.Name, listArgs);
                    }

                case PropertyAccessExpression exp:
                    return ConvertPropertyAccessExpression(exp);

                case ModuleOutputPropertyAccessExpression exp:
                    return ConvertModuleOutputPropertyAccessExpression(exp);

                case AccessExpression exp:
                    return ConvertAccessExpression(exp);

                case ResourceReferenceExpression exp:
                    return GetReferenceExpression(exp.Metadata, exp.IndexContext, true);

                case ModuleReferenceExpression exp:
                    return GetModuleReferenceExpression(exp.Module, exp.IndexContext, false);

                case VariableReferenceExpression exp:
                    return CreateFunction("variables", new JTokenExpression(exp.Variable.Name));

                case SynthesizedVariableReferenceExpression exp:
                    return CreateFunction("variables", new JTokenExpression(exp.Name));

                case ImportedVariableReferenceExpression exp:
                    return CreateFunction("variables", new JTokenExpression(context.SemanticModel.ImportClosureInfo.ImportedSymbolNames[exp.Variable]));

                case WildcardImportVariablePropertyReferenceExpression exp:
                    return CreateFunction("variables",
                    new JTokenExpression(context.SemanticModel.ImportClosureInfo.WildcardImportPropertyNames[new(exp.ImportSymbol, exp.PropertyName)]));

                case ParametersReferenceExpression exp:
                    return CreateFunction("parameters", new JTokenExpression(exp.Parameter.Name));

                case ParametersAssignmentReferenceExpression exp:
                    return CreateFunction("parameters", new JTokenExpression(exp.Parameter.Name));

                case ExtensionReferenceExpression exp:
                    return CreateFunction("extensions", new JTokenExpression(exp.ExtensionNamespace.Name));

                case LambdaExpression exp:
                    var variableNames = exp.Parameters.Select(x => new JTokenExpression(x));
                    var body = ConvertExpression(exp.Body);

                    return CreateFunction(
                        "lambda",
                        variableNames.Concat(body));

                case LambdaVariableReferenceExpression exp:
                    if (exp.IsFunctionLambda)
                    {
                        return CreateFunction("parameters", new JTokenExpression(exp.Variable.Name));
                    }
                    return CreateFunction("lambdaVariables", new JTokenExpression(exp.Variable.Name));

                case CopyIndexExpression exp:
                    return exp.Name is null
                        ? CreateFunction("copyIndex")
                        : CreateFunction("copyIndex", new JTokenExpression(exp.Name));

                default:
                    throw new NotImplementedException($"Cannot emit unexpected expression of type {expression.GetType().Name}");
            }
        }