Metaprogramming: get your hands dirty

Topics: General
Oct 26, 2014 at 4:55 PM
Edited Nov 14, 2014 at 6:12 AM
There is an old Chinese saying, 临渊羡鱼不如退而结网(better spinning than desiring the fish near the pool.) Why not get your hands dirty to do some metaprogramming experiments? I've implemented an almost complete C# parser using ANTLR3 (https://metah.codeplex.com/SourceControl/latest#Source/Metah.Compilation/AntlrParsing/W.g3) and a routine creating Roslyn syntax tree from the parsing tree (https://metah.codeplex.com/SourceControl/latest#Source/Metah.Compilation/Base.cs line 19). So you can extend C# syntax easily and analyze your semantic model and generate code.
Okay, this way(using Roslyn as binary components) is just for experiments. I think it's very hard for those who are not in Redmond to implement metaprogramming by extending Roslyn source code.
Oct 27, 2014 at 1:52 AM
Edited Oct 29, 2014 at 4:26 AM
An example. The following extended syntax code
using System;
using System.Activities;

namespace NS1.NS2
{
    public class SomeClass<T> where T : class, new()
    {
        internal T Create() { return new T(); }
    }
    public interface ISomeInterface
    {
        string Greeting();
    }

    [Serializable]
    public sealed activity A1<T>(int Arg1, ref string Arg2, out DateTime Arg3, [RequiredArgument]SomeClass<T> Arg4) as T
        : ISomeInterface where T : class, new()
    {
        if (Arg1 < 0) throw new ArgumentOutOfRangeException("Invalid Arg1: " + Arg1);
        Console.WriteLine("Arg1: {0}, Arg2: {1}", Arg1, Arg2);
        Arg2 += " world";
        Arg3 = DateTime.Now;
        Result = Arg4.Create();
        delay TimeSpan.FromSeconds(Arg1);
    }
    ##
    {
        private int _i;
        public string Greeting() { return "Hello" + ++_i; }
    }

    activity A2()
    {
        string s;
        DateTime dt;
        Exception ex;
        s = "Hello";
        ex = new A1<Exception>().Invoke(3, ref s, out dt, new SomeClass<Exception>());
        Console.WriteLine("s: {0}, dt: {1}", s, dt);
    }

    class Program
    {
        static void Main()
        {
            WorkflowInvoker.Invoke(new A2());
        }
    }
}
will be translated into the following C# implementation code
//
//Auto-generated, DO NOT EDIT
//Visit http://metah.codeplex.com for more information
//
using System;
using System.Activities;

namespace NS1.NS2
{
    public class SomeClass<T>
        where T : class, new ()
    {
        internal T Create()
        {
            return new T();
        }
    }

    public interface ISomeInterface
    {
        string Greeting();
    }

    class Program
    {
        static void Main()
        {
            WorkflowInvoker.Invoke(new A2());
        }
    }

    [Serializable]
    public sealed class A1<T> : global::System.Activities.Activity<T>, ISomeInterface where T : class, new ()
    {
        private int _i;
        public string Greeting()
        {
            return "Hello" + ++_i;
        }

        public global::System.Activities.InArgument<int> Arg1
        {
            get;
            set;
        }

        public global::System.Activities.InOutArgument<string> Arg2
        {
            get;
            set;
        }

        public global::System.Activities.OutArgument<DateTime> Arg3
        {
            get;
            set;
        }

        [RequiredArgument]
        public global::System.Activities.InArgument<SomeClass<T>> Arg4
        {
            get;
            set;
        }

        private global::System.Activities.Activity __GetImplementation__()
        {
            global::System.Activities.Activity __vroot__;
            {
                var __v__0 = new global::System.Activities.Statements.Sequence();
                var __v__1 = new global::System.Activities.Statements.If();
                __v__1.Condition = new global::System.Activities.InArgument<bool>(new global::MetahWFuncActivity<bool>(__ctx__ => Arg1.Get(__ctx__) < 0));
                var __v__2 = new global::System.Activities.Statements.Throw();
                __v__2.Exception = new global::System.Activities.InArgument<global::System.Exception>(new global::MetahWFuncActivity<global::System.Exception>(__ctx__ => new ArgumentOutOfRangeException("Invalid Arg1: " + Arg1.Get(__ctx__))));
                __v__1.Then = __v__2;
                __v__0.Activities.Add(__v__1);
                var __v__3 = new global::MetahWActionActivity(__ctx__ =>
                {
                    Console.WriteLine("Arg1: {0}, Arg2: {1}", Arg1.Get(__ctx__), Arg2.Get(__ctx__));
                    Arg2.SetEx(__ctx__, Arg2.Get(__ctx__) + " world");
                    Arg3.SetEx(__ctx__, DateTime.Now);
                    Result.SetEx(__ctx__, Arg4.Get(__ctx__).Create());
                }

                );
                __v__0.Activities.Add(__v__3);
                var __v__4 = new global::System.Activities.Statements.Delay();
                __v__4.Duration = new global::System.Activities.InArgument<global::System.TimeSpan>(new global::MetahWFuncActivity<global::System.TimeSpan>(__ctx__ => TimeSpan.FromSeconds(Arg1.Get(__ctx__))));
                __v__0.Activities.Add(__v__4);
                __vroot__ = __v__0;
            }

            return __vroot__;
        }

        private global::System.Func<global::System.Activities.Activity> __implementation__;
        protected override global::System.Func<global::System.Activities.Activity> Implementation
        {
            get
            {
                return __implementation__ ?? (__implementation__ = __GetImplementation__);
            }

            set
            {
                throw new global::System.NotSupportedException();
            }
        }
    }

    class A2 : global::System.Activities.Activity
    {
        private global::System.Activities.Activity __GetImplementation__()
        {
            global::System.Activities.Activity __vroot__;
            {
                var __v__0 = new global::System.Activities.Statements.Sequence();
                var s = new global::System.Activities.Variable<string>();
                __v__0.Variables.Add(s);
                var dt = new global::System.Activities.Variable<DateTime>();
                __v__0.Variables.Add(dt);
                var ex = new global::System.Activities.Variable<Exception>();
                __v__0.Variables.Add(ex);
                var __v__1 = new global::MetahWActionActivity(__ctx__ =>
                {
                    s.SetEx(__ctx__, "Hello");
                }

                );
                var __v__2 = new A1<Exception>().Initialize(__activity__ =>
                {
                    __activity__.Arg1 = new global::System.Activities.InArgument<int>(new global::MetahWFuncActivity<int>(__ctx__ => 3));
                    __activity__.Arg2 = new global::System.Activities.InOutArgument<string>(new global::MetahWLocationActivity<string>(s));
                    __activity__.Arg3 = new global::System.Activities.OutArgument<global::System.DateTime>(new global::MetahWLocationActivity<global::System.DateTime>(dt));
                    __activity__.Arg4 = new global::System.Activities.InArgument<global::NS1.NS2.SomeClass<global::System.Exception>>(new global::MetahWFuncActivity<global::NS1.NS2.SomeClass<global::System.Exception>>(__ctx__ => new SomeClass<Exception>()));
                    __activity__.Result = new global::System.Activities.OutArgument<global::System.Exception>(new global::MetahWLocationActivity<global::System.Exception>(ex));
                }

                );
                var __v__3 = new global::MetahWActionActivity(__ctx__ =>
                {
                    Console.WriteLine("s: {0}, dt: {1}", s.Get(__ctx__), dt.Get(__ctx__));
                }

                );
                __v__0.Activities.Add(__v__1);
                __v__0.Activities.Add(__v__2);
                __v__0.Activities.Add(__v__3);
                __vroot__ = __v__0;
            }

            return __vroot__;
        }

        private global::System.Func<global::System.Activities.Activity> __implementation__;
        protected override global::System.Func<global::System.Activities.Activity> Implementation
        {
            get
            {
                return __implementation__ ?? (__implementation__ = __GetImplementation__);
            }

            set
            {
                throw new global::System.NotSupportedException();
            }
        }
    }
}
//helper code omitted
Oct 27, 2014 at 10:29 AM
Knat wrote:
I think it's very hard for those who are not in Redmond to implement metaprogramming by extending Roslyn source code.
Maybe I should put more time on reading and thinking Roslyn source code.
Dec 17, 2014 at 2:32 PM
"Metah.W: A Workflow Metaprogramming Language" is an interesting C#-derived metaprogramming language. Visit https://github.com/knat/Metah