@@ -26,10 +26,12 @@ private class FindVariableNMethodCall : CSharpSyntaxWalker
26
26
public List < IdentifierNameSyntax > identifiers = new List < IdentifierNameSyntax > ( ) ;
27
27
public List < InvocationExpressionSyntax > methodCall = new List < InvocationExpressionSyntax > ( ) ;
28
28
public List < MemberAccessExpressionSyntax > memberAccesses = new List < MemberAccessExpressionSyntax > ( ) ;
29
+ public List < ElementAccessExpressionSyntax > elementAccess = new List < ElementAccessExpressionSyntax > ( ) ;
29
30
public List < object > argValues = new List < object > ( ) ;
30
31
public Dictionary < string , JObject > memberAccessValues = new Dictionary < string , JObject > ( ) ;
31
32
private int visitCount ;
32
33
public bool hasMethodCalls ;
34
+ public bool hasElementAccesses ;
33
35
34
36
public void VisitInternal ( SyntaxNode node )
35
37
{
@@ -44,14 +46,16 @@ public override void Visit(SyntaxNode node)
44
46
if ( node is MemberAccessExpressionSyntax maes
45
47
&& node . Kind ( ) == SyntaxKind . SimpleMemberAccessExpression
46
48
&& ! ( node . Parent is MemberAccessExpressionSyntax )
47
- && ! ( node . Parent is InvocationExpressionSyntax ) )
49
+ && ! ( node . Parent is InvocationExpressionSyntax )
50
+ && ! ( node . Parent is ElementAccessExpressionSyntax ) )
48
51
{
49
52
memberAccesses . Add ( maes ) ;
50
53
}
51
54
52
55
if ( node is IdentifierNameSyntax identifier
53
56
&& ! ( identifier . Parent is MemberAccessExpressionSyntax )
54
57
&& ! ( identifier . Parent is InvocationExpressionSyntax )
58
+ && ! ( node . Parent is ElementAccessExpressionSyntax )
55
59
&& ! identifiers . Any ( x => x . Identifier . Text == identifier . Identifier . Text ) )
56
60
{
57
61
identifiers . Add ( identifier ) ;
@@ -65,15 +69,23 @@ public override void Visit(SyntaxNode node)
65
69
hasMethodCalls = true ;
66
70
}
67
71
72
+ if ( node is ElementAccessExpressionSyntax )
73
+ {
74
+ if ( visitCount == 1 )
75
+ elementAccess . Add ( node as ElementAccessExpressionSyntax ) ;
76
+ hasElementAccesses = true ;
77
+ }
78
+
68
79
if ( node is AssignmentExpressionSyntax )
69
80
throw new Exception ( "Assignment is not implemented yet" ) ;
70
81
base . Visit ( node ) ;
71
82
}
72
83
73
- public SyntaxTree ReplaceVars ( SyntaxTree syntaxTree , IEnumerable < JObject > ma_values , IEnumerable < JObject > id_values , IEnumerable < JObject > method_values )
84
+ public SyntaxTree ReplaceVars ( SyntaxTree syntaxTree , IEnumerable < JObject > ma_values , IEnumerable < JObject > id_values , IEnumerable < JObject > method_values , IEnumerable < JObject > ea_values )
74
85
{
75
86
var memberAccessToParamName = new Dictionary < string , string > ( ) ;
76
87
var methodCallToParamName = new Dictionary < string , string > ( ) ;
88
+ var elementAccessToParamName = new Dictionary < string , string > ( ) ;
77
89
78
90
CompilationUnitSyntax root = syntaxTree . GetCompilationUnitRoot ( ) ;
79
91
@@ -110,6 +122,22 @@ public SyntaxTree ReplaceVars(SyntaxTree syntaxTree, IEnumerable<JObject> ma_val
110
122
return SyntaxFactory . IdentifierName ( id_name ) ;
111
123
} ) ;
112
124
125
+ // 1.2 Replace all this.a[x] occurrences with this_a_ABDE
126
+ root = root . ReplaceNodes ( elementAccess , ( ea , _ ) =>
127
+ {
128
+ string eaStr = ea . ToString ( ) ;
129
+ if ( ! elementAccessToParamName . TryGetValue ( eaStr , out string id_name ) )
130
+ {
131
+ // Generate a random suffix
132
+ string suffix = Guid . NewGuid ( ) . ToString ( ) . Substring ( 0 , 5 ) ;
133
+ string prefix = eaStr . Trim ( ) . Replace ( "." , "_" ) . Replace ( "[" , "_" ) . Replace ( "]" , "_" ) ;
134
+ id_name = $ "{ prefix } _{ suffix } ";
135
+ elementAccessToParamName [ eaStr ] = id_name ;
136
+ }
137
+
138
+ return SyntaxFactory . IdentifierName ( id_name ) ;
139
+ } ) ;
140
+
113
141
var paramsSet = new HashSet < string > ( ) ;
114
142
115
143
// 2. For every unique member ref, add a corresponding method param
@@ -148,6 +176,18 @@ public SyntaxTree ReplaceVars(SyntaxTree syntaxTree, IEnumerable<JObject> ma_val
148
176
}
149
177
}
150
178
179
+ if ( ea_values != null )
180
+ {
181
+ foreach ( ( ElementAccessExpressionSyntax eas , JObject value ) in elementAccess . Zip ( ea_values ) )
182
+ {
183
+ string node_str = eas . ToString ( ) ;
184
+ if ( ! elementAccessToParamName . TryGetValue ( node_str , out string id_name ) )
185
+ {
186
+ throw new Exception ( $ "BUG: Expected to find an id name for the element access string: { node_str } ") ;
187
+ }
188
+ root = UpdateWithNewMethodParam ( root , id_name , value ) ;
189
+ }
190
+ }
151
191
152
192
return syntaxTree . WithRootAndOptions ( root , syntaxTree . Options ) ;
153
193
@@ -281,6 +321,20 @@ private static async Task<IList<JObject>> ResolveMethodCalls(IEnumerable<Invocat
281
321
return values ;
282
322
}
283
323
324
+ private static async Task < IList < JObject > > ResolveElementAccess ( IEnumerable < ElementAccessExpressionSyntax > elementAccesses , Dictionary < string , JObject > memberAccessValues , MemberReferenceResolver resolver , CancellationToken token )
325
+ {
326
+ var values = new List < JObject > ( ) ;
327
+ JObject index = null ;
328
+ foreach ( ElementAccessExpressionSyntax elementAccess in elementAccesses . Reverse ( ) )
329
+ {
330
+ index = await resolver . Resolve ( elementAccess , memberAccessValues , index , token ) ;
331
+ if ( index == null )
332
+ throw new ReturnAsErrorException ( $ "Failed to resolve element access for { elementAccess } ", "ReferenceError" ) ;
333
+ }
334
+ values . Add ( index ) ;
335
+ return values ;
336
+ }
337
+
284
338
[ UnconditionalSuppressMessage ( "SingleFile" , "IL3000:Avoid accessing Assembly file path when publishing as a single file" ,
285
339
Justification = "Suppressing the warning until gets fixed, see https://github.com/dotnet/runtime/issues/51202" ) ]
286
340
internal static async Task < JObject > CompileAndRunTheExpression ( string expression , MemberReferenceResolver resolver , CancellationToken token )
@@ -330,7 +384,7 @@ public static object Evaluate()
330
384
331
385
IList < JObject > identifierValues = await ResolveIdentifiers ( findVarNMethodCall . identifiers , resolver , token ) ;
332
386
333
- syntaxTree = findVarNMethodCall . ReplaceVars ( syntaxTree , memberAccessValues , identifierValues , null ) ;
387
+ syntaxTree = findVarNMethodCall . ReplaceVars ( syntaxTree , memberAccessValues , identifierValues , null , null ) ;
334
388
335
389
if ( findVarNMethodCall . hasMethodCalls )
336
390
{
@@ -340,7 +394,19 @@ public static object Evaluate()
340
394
341
395
IList < JObject > methodValues = await ResolveMethodCalls ( findVarNMethodCall . methodCall , findVarNMethodCall . memberAccessValues , resolver , token ) ;
342
396
343
- syntaxTree = findVarNMethodCall . ReplaceVars ( syntaxTree , null , null , methodValues ) ;
397
+ syntaxTree = findVarNMethodCall . ReplaceVars ( syntaxTree , null , null , methodValues , null ) ;
398
+ }
399
+
400
+ // eg. "elements[0]"
401
+ if ( findVarNMethodCall . hasElementAccesses )
402
+ {
403
+ expressionTree = GetExpressionFromSyntaxTree ( syntaxTree ) ;
404
+
405
+ findVarNMethodCall . VisitInternal ( expressionTree ) ;
406
+
407
+ IList < JObject > elementAccessValues = await ResolveElementAccess ( findVarNMethodCall . elementAccess , findVarNMethodCall . memberAccessValues , resolver , token ) ;
408
+
409
+ syntaxTree = findVarNMethodCall . ReplaceVars ( syntaxTree , null , null , null , elementAccessValues ) ;
344
410
}
345
411
346
412
expressionTree = GetExpressionFromSyntaxTree ( syntaxTree ) ;
0 commit comments