1- using System . Collections . Concurrent ;
1+ using System . Collections ;
2+ using System . Collections . Concurrent ;
23using System . Collections . Immutable ;
3- using System . Diagnostics ;
44using System . Reflection ;
55using System . Runtime . CompilerServices ;
6+ using System . Text . Json . Serialization ;
7+ using System . Text . RegularExpressions ;
68using Hyperbee . Templating . Text ;
79using Microsoft . CodeAnalysis ;
810using Microsoft . CodeAnalysis . CSharp ;
@@ -16,10 +18,14 @@ internal sealed class RoslynTokenExpressionProvider : ITokenExpressionProvider
1618 private static readonly ImmutableArray < MetadataReference > MetadataReferences =
1719 [
1820 MetadataReference . CreateFromFile ( typeof ( object ) . Assembly . Location ) ,
19- MetadataReference . CreateFromFile ( typeof ( object ) . Assembly . Location . Replace ( "System.Private.CoreLib" , "System.Runtime" ) ) ,
2021 MetadataReference . CreateFromFile ( typeof ( RuntimeBinderException ) . Assembly . Location ) ,
2122 MetadataReference . CreateFromFile ( typeof ( DynamicAttribute ) . Assembly . Location ) ,
22- MetadataReference . CreateFromFile ( typeof ( RoslynTokenExpressionProvider ) . Assembly . Location )
23+ MetadataReference . CreateFromFile ( typeof ( RoslynTokenExpressionProvider ) . Assembly . Location ) ,
24+ MetadataReference . CreateFromFile ( typeof ( Regex ) . Assembly . Location ) ,
25+ MetadataReference . CreateFromFile ( typeof ( Enumerable ) . Assembly . Location ) ,
26+
27+ MetadataReference . CreateFromFile ( typeof ( object ) . Assembly . Location . Replace ( "System.Private.CoreLib" , "System.Runtime" ) ) ,
28+ MetadataReference . CreateFromFile ( typeof ( IList ) . Assembly . Location . Replace ( "System.Private.CoreLib" , "System.Collections" ) )
2329 ] ;
2430
2531 private sealed class RuntimeContext ( ImmutableArray < MetadataReference > metadataReferences )
@@ -35,33 +41,40 @@ private sealed class RuntimeContext( ImmutableArray<MetadataReference> metadataR
3541 new ( OutputKind . DynamicallyLinkedLibrary , optimizationLevel : OptimizationLevel . Release ) ;
3642
3743 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
38- public TokenExpression GetTokenExpression ( string codeExpression )
44+ public TokenExpression GetTokenExpression ( string codeExpression , MemberDictionary members )
3945 {
40- return __runtimeContext . TokenExpressions . GetOrAdd ( codeExpression , Compile ) ;
46+ return __runtimeContext . TokenExpressions . GetOrAdd ( codeExpression , Compile ( codeExpression , members ) ) ;
4147 }
4248
4349 public static void Reset ( )
4450 {
4551 __runtimeContext = new RuntimeContext ( MetadataReferences ) ;
4652 }
4753
48- private static TokenExpression Compile ( string codeExpression )
54+ private static TokenExpression Compile ( string codeExpression , MemberDictionary members )
4955 {
5056 // Create a shim to compile the expression
57+ //AF: I added the linq and regular Expression usings
58+ //AF: the error is in the Regex as it doesn't know what the people are.
5159 var codeShim =
52- $$ """
53- using Hyperbee.Templating.Text;
54- using Hyperbee.Templating.Compiler;
55-
56- public static class TokenExpressionInvoker
57- {
58- public static object Invoke( {{ nameof ( IReadOnlyMemberDictionary ) }} members )
59- {
60- TokenExpression expr = {{ codeExpression }} ;
61- return expr( members );
62- }
63- }
64- """ ;
60+ $$$ """
61+ using System;
62+ using System.Linq;
63+ using System.Text.RegularExpressions;
64+ using System.Collections;
65+ using System.Collections.Generic;
66+ using Hyperbee.Templating.Text;
67+ using Hyperbee.Templating.Compiler;
68+
69+ public static class TokenExpressionInvoker
70+ {
71+ public static object Invoke( {{{ nameof ( IReadOnlyMemberDictionary ) }}} members )
72+ {
73+ TokenExpression expr = {{{ codeExpression }}} ;
74+ return expr( members );
75+ }
76+ }
77+ """ ;
6578
6679 // Parse the code expression
6780 var syntaxTree = CSharpSyntaxTree . ParseText ( codeShim ) ;
@@ -80,10 +93,10 @@ public static object Invoke( {{nameof( IReadOnlyMemberDictionary )}} members )
8093 } ;
8194
8295 // Rewrite the lambda expression to use the dictionary lookup
83- var rewriter = new TokenExpressionRewriter ( parameterName ) ;
96+ var rewriter = new TokenExpressionRewriter ( parameterName , members ) ;
8497 var rewrittenSyntaxTree = rewriter . Visit ( root ) ;
8598
86- // var rewrittenCode = rewrittenSyntaxTree.ToFullString(); // Keep for debugging
99+ var rewrittenCode = rewrittenSyntaxTree . ToFullString ( ) ; // Keep for debugging
87100
88101 // Compile the rewritten code
89102 var counter = Interlocked . Increment ( ref __counter ) ;
@@ -101,9 +114,9 @@ public static object Invoke( {{nameof( IReadOnlyMemberDictionary )}} members )
101114 {
102115 var failures = result . Diagnostics . Where ( diagnostic =>
103116 diagnostic . IsWarningAsError ||
104- diagnostic . Severity == DiagnosticSeverity . Error ) ;
117+ diagnostic . Severity == DiagnosticSeverity . Error ) . ToArray ( ) ;
105118
106- throw new InvalidOperationException ( "Compilation failed: " + string . Join ( " \n " , failures . Select ( diagnostic => diagnostic . GetMessage ( ) ) ) ) ;
119+ throw new TokenExpressionProviderException ( "Compilation failed: " + failures [ 0 ] ? . GetMessage ( ) , failures ) ;
107120 }
108121
109122 peStream . Seek ( 0 , SeekOrigin . Begin ) ;
@@ -118,16 +131,36 @@ public static object Invoke( {{nameof( IReadOnlyMemberDictionary )}} members )
118131 }
119132}
120133
134+ [ Serializable ]
135+ internal class TokenExpressionProviderException : Exception
136+ {
137+ public Diagnostic [ ] Diagnostic { get ; }
138+ public string Id => Diagnostic != null && Diagnostic . Length > 0 ? Diagnostic [ 0 ] . Id : string . Empty ;
139+
140+ public TokenExpressionProviderException ( string message , Diagnostic [ ] diagnostic )
141+ : base ( message )
142+ {
143+ Diagnostic = diagnostic ;
144+ }
145+
146+ public TokenExpressionProviderException ( string message , Diagnostic [ ] diagnostic , Exception innerException )
147+ : base ( message , innerException )
148+ {
149+ Diagnostic = diagnostic ;
150+ }
151+
152+ }
153+
121154// This rewriter will transform the lambda expression to use dictionary lookup
122155// for property access, method invocation, and 'generic' property casting.
123156//
124157// we want to transform these syntactic-sugar patterns:
125158//
126159// 1. x => x.someProp to x["someProp"]
127160// 2. x => x.someProp<T> to x.GetValueAs<T>("someProp")
128- // 3. x => x.someMethod(..) to x.InvokeMethod ("someMethod", ..)
161+ // 3. x => x.someMethod(..) to x.Invoke ("someMethod", ..)
129162
130- internal class TokenExpressionRewriter ( string parameterName ) : CSharpSyntaxRewriter
163+ internal class TokenExpressionRewriter ( string parameterName , MemberDictionary members ) : CSharpSyntaxRewriter
131164{
132165 private readonly HashSet < string > _aliases = [ parameterName ] ;
133166
@@ -151,7 +184,12 @@ memberAccess.Expression is IdentifierNameSyntax identifier &&
151184 _aliases . Contains ( identifier . Identifier . Text ) )
152185 {
153186 // Handle method invocation rewrite
154- return RewriteMethodInvocation ( memberAccess , node ) ;
187+
188+ if ( members . Methods . ContainsKey ( memberAccess . Name . Identifier . Text ) )
189+ return RewriteMethodInvocation ( memberAccess , node ) ;
190+
191+ return node . Update ( node . Expression , ( ArgumentListSyntax ) VisitArgumentList ( node . ArgumentList ) ! ) ;
192+ //return RewriteMethodInvocation( memberAccess, node ); //BF this rewrite causes the error. we need to disambiguate calls to template lambdas methods
155193 }
156194
157195 return base . VisitInvocationExpression ( node ) ;
@@ -232,12 +270,12 @@ private InvocationExpressionSyntax RewriteMethodInvocation( MemberAccessExpressi
232270 . Select ( arg => ( ExpressionSyntax ) Visit ( arg . Expression ) )
233271 . ToArray ( ) ;
234272
235- // Create the InvokeMethod call: x.InvokeMethod ("MethodName", arg1, arg2, ...)
273+ // Create the InvokeMethod call: x.Invoke ("MethodName", arg1, arg2, ...)
236274 var invokeMethodCall = SyntaxFactory . InvocationExpression (
237275 SyntaxFactory . MemberAccessExpression (
238276 SyntaxKind . SimpleMemberAccessExpression ,
239277 memberAccess . Expression , // This is `x`
240- SyntaxFactory . IdentifierName ( "InvokeMethod " )
278+ SyntaxFactory . IdentifierName ( "Invoke " )
241279 ) ,
242280 SyntaxFactory . ArgumentList (
243281 SyntaxFactory . SeparatedList (
0 commit comments