Search code examples
c#code-generationlempec#

Is there way to "define" a macro in LeMP accepting the Type literal input


I am using LeMP v2.8.1 from the Extended CSharp and have the following shortcut for defining and initializing the fields in a class:

compileTimeAndRuntime 
{
    public partial class DI : IResolver
    {
        replace (T => ConcurrentDictionary<Type, Expression<Func<IResolver, object>>>) { public T Registrations = new T(); }
        replace (T => ConcurrentDictionary<Type, Func<IResolver, object>>) { public T DelegateCache = new T(); }
    }
}

The replace pattern is very similar except the public and internal modifiers. But let's skip them for a moment.

My question is there a way to factor this replace pattern into a single define macro, so that I don't need to repeat the pattern.

I tried something like define New($T, $F) { $T $F = new $T(); } but it spits the error when using it with Type argument like this New(ConcurrentDictionary<Type, Expression<Func<IResolver, object>>>, Registrations).


Solution

  • It works for me:

    compileTimeAndRuntime 
    {
        define New($T, $F) { $T $F = new $T(); }
        
        public partial class DI : IResolver
        {
            public New(ConcurrentDictionary<Type, Expression<Func<IResolver, object>>>, Registrations);
            internal New(ConcurrentDictionary<Type, Func<IResolver, object>>, DelegateCache);
        }
    }
    
    // Generated from Untitled.ecs by LeMP 2.8.2.0.
    public partial class DI : IResolver
    {
        public ConcurrentDictionary<Type, Expression<Func<IResolver, object>>> Registrations = new ConcurrentDictionary<Type, Expression<Func<IResolver, object>>>();
        internal ConcurrentDictionary<Type, Func<IResolver, object>> DelegateCache = new ConcurrentDictionary<Type, Func<IResolver, object>>();
    }
    

    Here's a more interesting version:

    // Matches variable declarations and replaces __var with the type name.
    // Useful to avoid repeating the type twice when declaring fields in classes.
    [Passive] // avoids warning on variable declarations that don't match
    define #var(__var, $name = new $T($(..args)) { $(..initializers) }) {
        $T $name = new $T($args) { $initializers };
    }
    
    public partial class DI : IResolver
    {
        public __var Registrations = new ConcurrentDictionary<Type, Expression<Func<IResolver, object>>>();
        internal __var DelegateCache = new ConcurrentDictionary<Type, Func<IResolver, object>>();
        private __var _array = new int[4] { 0, 10, 20, 30 };
    }
    
    // Generated from Untitled.ecs by LeMP 2.8.2.0.
    public partial class DI : IResolver
    {
        public ConcurrentDictionary<Type, Expression<Func<IResolver, object>>> Registrations = new ConcurrentDictionary<Type, Expression<Func<IResolver, object>>>();
        internal ConcurrentDictionary<Type, Func<IResolver, object>> DelegateCache = new ConcurrentDictionary<Type, Func<IResolver, object>>();
        private int[] _array = new int[4] { 
            0, 10, 20, 30
        };
    }
    

    This is based on my knowledge that T x = y has a Loyc tree of the form #var(T, x = y), but the replace macro allows you to do the same thing without this knowledge:

    replace (
        { __var $name = new $Type($(..args)) { $(..initializers) }; } =>
        { $Type $name = new $Type($(..args)) { $(..initializers) }; });
    

    Apologies for taking so long to answer.