private SyntaxBase ParseFunctionExpression()

in src/Bicep.Decompiler/TemplateConverter.cs [579:686]


        private SyntaxBase ParseFunctionExpression(FunctionExpression expression)
        {
            SyntaxBase? baseSyntax = null;
            switch (expression.Function.ToLowerInvariant())
            {
                case "parameters":
                    {
                        baseSyntax = ParseParamOrVarFunctionExpression(expression, NameType.Parameter);
                        break;
                    }
                case "variables":
                    {
                        baseSyntax = ParseParamOrVarFunctionExpression(expression, NameType.Variable);
                        break;
                    }
                case "reference":
                    {
                        if (expression.Parameters.Length == 1 && expression.Parameters[0] is FunctionExpression resourceIdExpression && resourceIdExpression.NameEquals("resourceid"))
                        {
                            // reference(resourceId(<...>))
                            // check if it's a reference to a known resource
                            if (TryLookupResource(expression.Parameters[0]) is { } resourceName)
                            {
                                baseSyntax = new PropertyAccessSyntax(
                                    new VariableAccessSyntax(SyntaxFactory.CreateIdentifier(resourceName)),
                                    SyntaxFactory.DotToken,
                                    null,
                                    SyntaxFactory.CreateIdentifier("properties"));
                            }
                        }
                        else if (expression.Parameters.Length == 1)
                        {
                            // reference(<name>)
                            // let's try looking the name up directly
                            if (TryLookupResource(expression.Parameters[0]) is { } resourceName)
                            {
                                baseSyntax = new PropertyAccessSyntax(
                                    new VariableAccessSyntax(SyntaxFactory.CreateIdentifier(resourceName)),
                                    SyntaxFactory.DotToken,
                                    null,
                                    SyntaxFactory.CreateIdentifier("properties"));
                            }
                        }
                        break;
                    }
                case "resourceid":
                    {
                        var resourceName = TryLookupResource(expression);

                        if (resourceName != null)
                        {
                            baseSyntax = new PropertyAccessSyntax(
                                new VariableAccessSyntax(SyntaxFactory.CreateIdentifier(resourceName)),
                                SyntaxFactory.DotToken,
                                null,
                                SyntaxFactory.CreateIdentifier("id"));
                        }
                        break;
                    }
                case "format":
                    {
                        baseSyntax = TryParseStringExpression(expression);
                        break;
                    }
                case "concat":
                    {
                        if (!CanInterpolate(expression))
                        {
                            // we might be dealing with an array
                            break;
                        }

                        baseSyntax = TryParseStringExpression(expression);
                        break;
                    }
                default:
                    if (TryReplaceBannedFunction(expression, out var replacedBannedSyntax))
                    {
                        baseSyntax = replacedBannedSyntax;
                    }
                    break;
            }

            if (baseSyntax == null)
            {
                // Try to correct the name - ARM JSON is case-insensitive, but Bicep is sensitive
                var functionName = SyntaxHelpers.CorrectWellKnownFunctionCasing(expression.Function);

                var expressions = expression.Parameters.Select(ParseLanguageExpression).ToArray();

                if (expression.Function.Split('.') is { } funcNameArr &&
                    funcNameArr.Length == 2 &&
                    nameResolver.TryLookupName(NameType.Function, GetBicepFunctionName(funcNameArr[0], funcNameArr[1])) is { } resolvedUdfName)
                {
                    // This is a reference to a user-defined function
                    return SyntaxFactory.CreateFunctionCall(resolvedUdfName, expressions);
                }

                baseSyntax = SyntaxFactory.CreateFunctionCall(functionName, expressions);
            }

            foreach (var property in expression.Properties)
            {
                baseSyntax = ParsePropertyAccess(baseSyntax, property);
            }

            return baseSyntax;
        }