Skip to content

Commit eb3d221

Browse files
Address comments from #771 review (#807)
* Fixes for comments on #771 * Simplify CanConvertToArmJson logic
1 parent b845482 commit eb3d221

File tree

8 files changed

+49
-40
lines changed

8 files changed

+49
-40
lines changed

src/Bicep.Core.Samples/Files/Variables_LF/main.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,9 @@
155155
"isFalse": "[not(variables('isTrue'))]",
156156
"someText": "[if(variables('isTrue'), concat('a', concat('b', 'c')), 'someText')]",
157157
"scopesWithoutArmRepresentation": {
158-
"tenant": "[json('{}')]",
159-
"subscription": "[json('{}')]",
160-
"resourceGroup": "[json('{}')]"
158+
"tenant": "[createObject()]",
159+
"subscription": "[createObject()]",
160+
"resourceGroup": "[createObject()]"
161161
}
162162
},
163163
"resources": []

src/Bicep.Core/Emit/ExpressionConverter.cs

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33
using System;
4+
using System.Collections;
5+
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
47
using System.Linq;
58
using Arm.Expression.Expressions;
69
using Bicep.Core.Resources;
@@ -71,29 +74,14 @@ public LanguageExpression ConvertExpression(SyntaxBase expression)
7174
Array.Empty<LanguageExpression>());
7275

7376
case FunctionCallSyntax function:
74-
var returnValueType = context.SemanticModel.GetTypeInfo(function);
75-
if (returnValueType is IResourceScopeType resourceScopeType && !ScopeHelper.CanConvertToArmJson(resourceScopeType))
76-
{
77-
// return an empty object - there is no ARM equivalent to return
78-
return new FunctionExpression("json", new LanguageExpression [] { new JTokenExpression("{}") }, new LanguageExpression[0]);
79-
}
80-
8177
return ConvertFunction(
8278
function.Name.IdentifierName,
8379
function.Arguments.Select(a => ConvertExpression(a.Expression)).ToArray());
8480

8581
case InstanceFunctionCallSyntax instanceFunctionCall:
8682
var namespaceSymbol = context.SemanticModel.GetSymbolInfo(instanceFunctionCall.BaseExpression);
87-
8883
Assert(namespaceSymbol is NamespaceSymbol, $"BaseExpression must be a NamespaceSymbol, instead got: '{namespaceSymbol?.Kind}'");
8984

90-
var returnValueType2 = context.SemanticModel.GetTypeInfo(instanceFunctionCall);
91-
if (returnValueType2 is IResourceScopeType resourceScopeType2 && !ScopeHelper.CanConvertToArmJson(resourceScopeType2))
92-
{
93-
// return an empty object - there is no ARM equivalent to return
94-
return new FunctionExpression("json", new LanguageExpression [] { new JTokenExpression("{}") }, new LanguageExpression[0]);
95-
}
96-
9785
return ConvertFunction(
9886
instanceFunctionCall.Name.IdentifierName,
9987
instanceFunctionCall.Arguments.Select(a => ConvertExpression(a.Expression)).ToArray());
@@ -374,9 +362,31 @@ private static LanguageExpression ConvertFunction(string functionName, LanguageE
374362
return arguments.Single();
375363
}
376364

365+
if (ShouldReplaceUnsupportedFunction(functionName, arguments, out var replacementExpression))
366+
{
367+
return replacementExpression;
368+
}
369+
377370
return new FunctionExpression(functionName, arguments, Array.Empty<LanguageExpression>());
378371
}
379372

373+
private static bool ShouldReplaceUnsupportedFunction(string functionName, LanguageExpression[] arguments, [NotNullWhen(true)] out LanguageExpression? replacementExpression)
374+
{
375+
switch (functionName)
376+
{
377+
// These functions have not yet been implemented in ARM. For now, we will just return an empty object if they are accessed directly.
378+
case "tenant":
379+
case "managementGroup":
380+
case "subscription" when arguments.Length > 0:
381+
case "resourceGroup" when arguments.Length > 0:
382+
replacementExpression = GetCreateObjectExpression();
383+
return true;
384+
}
385+
386+
replacementExpression = null;
387+
return false;
388+
}
389+
380390
private FunctionExpression ConvertArray(ArraySyntax syntax)
381391
{
382392
// we are using the createArray() function as a proxy for an array literal
@@ -402,12 +412,12 @@ private FunctionExpression ConvertObject(ObjectSyntax syntax)
402412
}
403413

404414
// we are using the createObject() funciton as a proy for an object literal
405-
return new FunctionExpression(
406-
"createObject",
407-
parameters,
408-
Array.Empty<LanguageExpression>());
415+
return GetCreateObjectExpression(parameters);
409416
}
410417

418+
private static FunctionExpression GetCreateObjectExpression(params LanguageExpression[] parameters)
419+
=> new FunctionExpression("createObject", parameters, Array.Empty<LanguageExpression>());
420+
411421
private LanguageExpression ConvertBinary(BinaryOperationSyntax syntax)
412422
{
413423
LanguageExpression operand1 = ConvertExpression(syntax.LeftExpression);

src/Bicep.Core/Emit/ScopeHelper.cs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,5 @@ private static IReadOnlyDictionary<string, LanguageExpression> ToPropertyDiction
8080
resourceGroup: expressionConverter.ConvertExpression(scopeType.Arguments[1].Expression)),
8181
_ => null,
8282
};
83-
84-
public static bool CanConvertToArmJson(IResourceScopeType resourceScopeType)
85-
=> resourceScopeType switch {
86-
TenantScopeType _ => false,
87-
ManagementGroupScopeType _ => false,
88-
SubscriptionScopeType subscriptionScopeType => subscriptionScopeType.Arguments.Length == 0,
89-
ResourceGroupScopeType resourceGroupScopeType => resourceGroupScopeType.Arguments.Length == 0,
90-
_ => true,
91-
};
9283
}
9384
}

src/Bicep.Core/Parser/ParseDiagnosticsVisitor.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@ public override void VisitProgramSyntax(ProgramSyntax syntax)
2727
this.diagnosticWriter.WriteMultiple(syntax.LexerDiagnostics);
2828

2929
var targetScopeSyntaxes = syntax.Children.OfType<TargetScopeSyntax>().ToList();
30-
foreach (var targetScope in targetScopeSyntaxes.Skip(1))
30+
if (targetScopeSyntaxes.Count > 1)
3131
{
32-
this.diagnosticWriter.Write(targetScope.Keyword, x => x.TargetScopeMultipleDeclarations());
32+
foreach (var targetScope in targetScopeSyntaxes)
33+
{
34+
this.diagnosticWriter.Write(targetScope.Keyword, x => x.TargetScopeMultipleDeclarations());
35+
}
3336
}
3437
}
3538

src/Bicep.Core/Parser/Parser.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,10 @@ private static RecoveryFlags GetSuppressionFlag(SyntaxBase precedingNode)
111111
private SyntaxBase TargetScope()
112112
{
113113
var keyword = ExpectKeyword(LanguageConstants.TargetScopeKeyword);
114-
var assignmentToken = this.Expect(TokenType.Assignment, b => b.ExpectedCharacter("="));
114+
var assignment = this.WithRecovery(this.Assignment, RecoveryFlags.None, TokenType.NewLine);
115115
var value = this.WithRecovery(() => this.Expression(allowComplexLiterals: true), RecoveryFlags.None, TokenType.NewLine);
116116

117-
return new TargetScopeSyntax(keyword, assignmentToken, value);
117+
return new TargetScopeSyntax(keyword, assignment, value);
118118
}
119119

120120
private SyntaxBase ParameterDeclaration()

src/Bicep.Core/Syntax/TargetScopeSyntax.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ namespace Bicep.Core.Syntax
88
{
99
public class TargetScopeSyntax : SyntaxBase, IDeclarationSyntax
1010
{
11-
public TargetScopeSyntax(Token keyword, Token assignment, SyntaxBase value)
11+
public TargetScopeSyntax(Token keyword, SyntaxBase assignment, SyntaxBase value)
1212
{
1313
AssertKeyword(keyword, nameof(keyword), LanguageConstants.TargetScopeKeyword);
14-
AssertTokenType(assignment, nameof(assignment), TokenType.Assignment);
14+
AssertSyntaxType(assignment, nameof(assignment), typeof(Token), typeof(SkippedTriviaSyntax));
15+
AssertTokenType(assignment as Token, nameof(assignment), TokenType.Assignment);
1516

1617
this.Keyword = keyword;
1718
this.Assignment = assignment;
@@ -20,7 +21,7 @@ public TargetScopeSyntax(Token keyword, Token assignment, SyntaxBase value)
2021

2122
public Token Keyword { get; }
2223

23-
public Token Assignment { get; }
24+
public SyntaxBase Assignment { get; }
2425

2526
public SyntaxBase Value { get; }
2627

src/Bicep.Core/TypeSystem/ModuleType.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
3-
using System.Collections.Generic;
43

54
namespace Bicep.Core.TypeSystem
65
{
@@ -12,7 +11,7 @@ public ModuleType(string name, ITypeReference body)
1211
Body = body;
1312
}
1413

15-
public override TypeKind TypeKind => TypeKind.Resource;
14+
public override TypeKind TypeKind => TypeKind.Module;
1615

1716
public ITypeReference Body { get; }
1817

src/Bicep.Core/TypeSystem/TypeKind.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,10 @@ public enum TypeKind
5858
/// A reference to a resource scope.
5959
/// </summary>
6060
ResourceScopeReference,
61+
62+
/// <summary>
63+
/// Module type
64+
/// </summary>
65+
Module,
6166
}
6267
}

0 commit comments

Comments
 (0)