public Context From(string source)
        {
            var stream = new ANTLRStringStream(source);
            var lexer = new MessageContractsLexer(stream);

            var tokens = new CommonTokenStream(lexer);

            var parser = new MessageContractsParser(tokens)
            {
                TreeAdaptor = new CommonTreeAdaptor()
            };

            var program = parser.GetProgram();

            var commonTree = (CommonTree)program.Tree;

            var node = commonTree as CommonErrorNode;

            if (node != null)
            {
                throw new InvalidOperationException(node.ToString());
            }

            var ctx = new Context();
            foreach (var child in commonTree.Children)
            {
                WalkDeclarations(child, ctx);
            }
            return ctx;
        }
        public void WalkDeclarations(ITree tree, Context context)
        {
            var t = tree;
            switch (t.Type)
            {
                case MessageContractsLexer.FragmentEntry:
                    var fragmentId = t.GetChild(0).Text;
                    var fragmentType = t.GetChild(1).Text;
                    var fragmentName = t.GetChild(2).Text;
                    context.Fragments[fragmentId] = new Fragment(fragmentType, fragmentName);
                    break;
                case MessageContractsLexer.ModifierDefinition:
                    var modifier = t.GetChild(0).Text;
                    context.CurrentEntity.Modifiers.Remove(modifier);
                    for (int i = 1; i < t.ChildCount; i++)
                    {
                        context.CurrentEntity.Modifiers.Add(modifier, t.GetChild(i).Text);
                    }
                    break;
                case MessageContractsLexer.TypeToken:
                    var name = t.GetChild(0).Text;
                    var block = t.GetChild(1);

                    var modifiers = new List<Modifier>();
                    for (int i = 2; i < t.ChildCount; i++)
                    {
                        var mod = t.GetChild(i).Text;
                        var used = context.CurrentEntity.Modifiers.GetValues(mod);
                        if (null == used || used.Length == 0)
                        {
                            var format = string.Format("Entity '{0}' does not have modifier reference: '{1}'",
                                context.CurrentEntity.Name, mod);
                            throw new InvalidOperationException(format);
                        }
                        foreach (var s in used)
                        {
                            modifiers.Add(new Modifier(mod, s));
                        }
                    }

                    var message = new Message(name, modifiers);
                    if (modifiers.Any())
                    {
                        // only commands and events have modifiers
                        foreach (var member in context.Entities.Peek().FixedMembers)
                        {
                            message.Members.Add(member);
                        }
                    }

                    for (int i = 0; i < block.ChildCount; i++)
                    {
                        var members = WalkContractMember(block.GetChild(i), context).ToArray();
                        message.Members.AddRange(members.Where(m => m.Kind == Member.Kinds.Field));

                        var stringRepresentations =
                            members.Where(m => m.Kind == Member.Kinds.StringRepresentation).ToArray();
                        switch (stringRepresentations.Length)
                        {
                            case 0:
                                break;
                            case 1:
                                message.StringRepresentation = stringRepresentations[0].Name;
                                break;
                            default:
                                throw new InvalidOperationException("Only one string representation per message");
                        }
                    }

                    context.Contracts.Add(message);
                    context.CurrentEntity.Messages.Add(message);

                    break;

                case MessageContractsLexer.EntityDefinition:
                    var entityName = t.GetChild(0).Text;
                    var entityBlock = t.GetChild(1);

                    var entity = new Entity(entityName);
                    for (int i = 0; i < entityBlock.ChildCount; i++)
                    {
                        entity.FixedMembers.AddRange(WalkContractMember(entityBlock.GetChild(i), context));
                    }
                    context.PushEntity(entity);

                    for (int i = 2; i < t.ChildCount; i++)
                    {
                        WalkDeclarations(t.GetChild(i), context);
                    }
                    break;
                case MessageContractsLexer.NamespaceToken:
                    var ns = string.Join(".", t.Children().Select(s => s.Text));
                    context.CurrentNamespace = ns;
                    break;
                case MessageContractsLexer.ExternToken:
                    var text = t.GetChild(0).Text;
                    context.CurrentExtern = text;
                    break;
                case MessageContractsLexer.UsingToken:
                    var us = string.Join(".", t.Children().Select(s => s.Text));
                    context.Using.Add(us);
                    break;
                default:
                    throw new InvalidOperationException("Unexpected token: " + t.Text);
            }
        }
        public void WalkDeclarations(object tree, Context context)
        {
            var t = (CommonTree)tree;
            switch (t.Type)
            {
                case MessageContractsLexer.FragmentEntry:
                    var fragmentId = t.GetChild(0).Text;
                    var fragmentType = t.GetChild(1).Text;
                    var fragmentName = t.GetChild(2).Text;
                    context.Fragments[fragmentId] = new Fragment(fragmentType, fragmentName);
                    break;
                case MessageContractsLexer.ModifierDefinition:
                    Console.WriteLine(t);

                    var modifier = t.GetChild(1).Text;
                    var type = t.GetChild(0).Text;
                    context.CurrentEntity.Modifiers[modifier] = type;
                    break;

                case MessageContractsLexer.TypeToken:
                    var name = t.GetChild(0).Text;
                    var block = t.GetChild(1);

                    var modifiers = new List<Modifier>();
                    if (t.ChildCount>2)
                    {
                        var mod = t.GetChild(2).Text;
                        string typeName;
                        if (!context.CurrentEntity.Modifiers.TryGetValue(mod, out typeName))
                        {
                            var format = string.Format("Entity '{0}' does not have modifier reference: '{1}'", context.CurrentEntity.Name, mod);
                            throw new InvalidOperationException(format);
                        }
                        modifiers.Add(new Modifier(mod, typeName));
                    }

                    var message = new Message(name, modifiers);
                    if (modifiers.Any())
                    {
                        // only commands and events have modifiers
                        foreach (var member in context.Entities.Peek().FixedMembers)
                        {
                            message.Members.Add(member);
                        }
                    }

                    for (int i = 0; i < block.ChildCount; i++)
                    {
                        message.Members.AddRange(WalkContractMember(block.GetChild(i), context));
                    }

                    context.Contracts.Add(message);
                    context.CurrentEntity.Messages.Add(message);

                    break;

                case MessageContractsLexer.EntityDefinition:
                    var entityName = t.GetChild(0).Text;
                    var entityBlock = t.GetChild(1);

                    var entity = new Entity(entityName);
                    for (int i = 0; i < entityBlock.ChildCount; i++)
                    {
                        entity.FixedMembers.AddRange(WalkContractMember(entityBlock.GetChild(i), context));
                    }

                    context.Entities.Push(entity);

                    break;
                default:
                    throw new InvalidOperationException("Unexpected token: " + t.Text);
            }
        }
        static IEnumerable<Member> WalkContractMember(ITree tree, Context context)
        {
            if (tree.Type == MessageContractsLexer.FragmentReference)
            {
                var fragmentId = tree.GetChild(0).Text;

                if (!context.Fragments.ContainsKey(fragmentId))
                {
                    throw new InvalidOperationException(string.Format("Unknown fragment '{0}'", fragmentId));
                }

                var fragment = context.Fragments[fragmentId];
                yield return new Member(fragment.Type, fragment.Name, fragmentId);
                yield break;
            }
            if (tree.Type == MessageContractsLexer.MemberToken)
            {
                var type = tree.GetChild(0).Text;
                var name = tree.GetChild(1).Text;
                if (type == "ref")
                {
                    var match = context.Contracts.Where(c => c.Name == name).ToArray();
                    if (match.Length == 1)
                    {
                        foreach (var member in match[0].Members)
                        {
                            yield return member;
                        }
                        yield break;
                    }
                    throw new InvalidOperationException(string.Format("Unknown include '{0}'", name));
                }
                yield return (new Member(type, name, name));
                yield break;
            }
            if (tree.Type == MessageContractsLexer.StringRepresentationToken)
            {
                var text = tree.GetChild(0).Text;
                yield return new Member(null, text, null, Member.Kinds.StringRepresentation);
                yield break;
            }
            throw new InvalidOperationException("Unexpected token: " + tree.Text);
        }
        public void Generate(Context context, IndentedTextWriter outer)
        {
            var writer = new CodeWriter(outer);

            foreach (var source in context.Using.Distinct().OrderBy(s => s))
            {
                writer.WriteLine("using {0};", source);
            }

            writer.WriteLine(@"
            // ReSharper disable PartialTypeWithSinglePart
            // ReSharper disable UnusedMember.Local");

            writer.WriteLine("namespace {0}", context.CurrentNamespace);
            writer.WriteLine("{");

            writer.Indent += 1;

            if (!string.IsNullOrEmpty(Region))
            {
                writer.WriteLine("#region {0}", Region);
            }

            WriteContext(writer, context);

            if (!string.IsNullOrEmpty(Region))
            {
                writer.WriteLine("#endregion");
            }

            writer.Indent -= 1;
            writer.WriteLine("}");
        }
        private void WriteContext(CodeWriter writer, Context context)
        {
            foreach (var contract in context.Contracts)
            {
                if (contract.InteropData != null)
                    WriteInteropData(writer, contract);

                writer.Write(ClassNameTemplate, contract.Name, context.CurrentExtern);

                if (contract.Modifiers.Any())
                    writer.Write(" : {0}", string.Join(", ", contract.Modifiers.Select(s => s.Interface).ToArray()));

                writer.WriteLine();

                writer.WriteLine("{");
                writer.Indent += 1;

                if (contract.Members.Count > 0)
                {
                    WriteMembers(contract, writer);

                    writer.WriteLine();
                    WriteNotSoPrivateAnymoreCtor(writer, contract);

                    writer.Write("public {0} (", contract.Name);
                    WriteParameters(contract, writer);
                    writer.WriteLine(")");
                    writer.WriteLine("{");

                    writer.Indent += 1;
                    WriteAssignments(contract, writer);
                    writer.Indent -= 1;

                    writer.WriteLine("}");

                }
                WriteToString(writer, contract);
                writer.Indent -= 1;
                writer.WriteLine("}");
            }
            foreach (var entity in context.Entities)
            {
                if ((entity.Name ?? "default") == "default")
                    continue;

                GenerateEntityInterface(entity, writer, "?", "public interface I{0}ApplicationService");
                GenerateEntityInterface(entity, writer, "!", "public interface I{0}State");
            }
        }
        static IEnumerable<Member> WalkContractMember(ITree tree, Context context)
        {
            if (tree.Type == MessageContractsLexer.FragmentReference)
            {
                var fragmentId = tree.GetChild(0).Text;

                if (!context.Fragments.ContainsKey(fragmentId))
                {
                    var errorNode = (CommonTree)tree;
                    throw new InvalidOperationException(string.Format("Line: {0}\r\nUnknown fragment: {1}", errorNode.Line, errorNode.Text));
                }

                var fragment = context.Fragments[fragmentId];
                yield return new Member(null, fragment.Type, fragment.Name, fragmentId);
                yield break;
            }
            if (tree.Type == MessageContractsLexer.MemberToken ||
                tree.Type == MessageContractsLexer.MemberAnnToken)
            {
                string type;
                string name;
                string annotation;
                if (tree.Type == MessageContractsLexer.MemberToken)
                {
                    type = tree.GetChild(0).Text;
                    name = tree.GetChild(1).Text;
                    annotation = string.Empty;
                }
                else
                {
                    annotation = tree.GetChild(0).Text;
                    type = tree.GetChild(1).Text;
                    name = tree.GetChild(2).Text;
                }
                if (type == "ref")
                {
                    var match = context.Contracts.Where(c => c.Name == name).ToArray();
                    if (match.Length == 1)
                    {
                        foreach (var member in match[0].Members)
                        {
                            yield return member;
                        }
                        yield break;
                    }
                    throw new InvalidOperationException(string.Format("Unknown include '{0}'", name));
                }
                yield return (new Member(annotation, type, name, name));
                yield break;
            }
            if (tree.Type == MessageContractsLexer.StringRepresentationToken)
            {
                var text = tree.GetChild(0).Text;
                yield return new Member(null, null, text, null, Member.Kinds.StringRepresentation);
                yield break;
            }

            if (tree.Type == MessageContractsLexer.MemberAnnToken)
            {

                //var text = tree.GetChild(0).Text;

                //yield return new Member(null, text, null, Member.Kinds.StringRepresentation);

                yield break;

            }
            var node = (Antlr.Runtime.Tree.CommonErrorNode) tree;
            throw new InvalidOperationException(string.Format("Line: {0}\r\nUnknown fragment: {1}", node.start.Line, node.Text));
        }
        public void Generate(Context context, IndentedTextWriter outer)
        {
            var writer = new CodeWriter(outer);
            if (!string.IsNullOrEmpty(Namespace))
            {
                writer.WriteLine("namespace {0}", Namespace);
                writer.WriteLine("{");
            }
            writer.Indent += 1;

            if (!string.IsNullOrEmpty(Region))
            {
                writer.WriteLine("#region {0}", Region);
            }

            WriteContext(writer, context);

            if (!string.IsNullOrEmpty(Region))
            {
                writer.WriteLine("#endregion");
            }

            writer.Indent -= 1;

            if (!string.IsNullOrEmpty(Namespace))
            {
                writer.WriteLine("}");
            }
        }
        private void WriteContext(CodeWriter writer, Context context)
        {
            foreach (var contract in context.Contracts)
            {
                writer.Write(ClassNameTemplate, contract.Name);

                if (contract.Modifiers.Any())
                {
                    writer.Write(" : {0}", string.Join(", ", contract.Modifiers.Select(s => s.Interface).ToArray()));
                }
                writer.WriteLine();

                writer.WriteLine("{");
                writer.Indent += 1;

                if (contract.Members.Count > 0)
                {
                    WriteMembers(contract, writer);
                    writer.WriteLine(PrivateCtorTemplate, contract.Name);
                    writer.Write("public {0} (", contract.Name);
                    WriteParameters(contract, writer);
                    writer.WriteLine(")");
                    writer.WriteLine("{");

                    writer.Indent += 1;
                    WriteAssignments(contract, writer);
                    writer.Indent -= 1;

                    writer.WriteLine("}");

                }

                writer.Indent -= 1;
                writer.WriteLine("}");
            }

            var split = (GenerateInterfaceForEntityWithModifiers ?? "")
                .Split(new[]{','}, StringSplitOptions.RemoveEmptyEntries);
            foreach (var entity in context.Entities)
            {
                if ((entity.Name??"null") == "null")
                    continue;
                var matches = entity.Messages.Where(m => m.Modifiers.Select(s =>s.Identifier).Intersect(split).Any()).ToList();
                if (matches.Any())
                {
                    writer.WriteLine();
                    writer.WriteLine(TemplateForInterfaceName, entity.Name);
                    writer.WriteLine("{");
                    writer.Indent += 1;
                    foreach (var contract in matches)
                    {
                        writer.WriteLine(TemplateForInterfaceMember, contract.Name);
                    }
                    writer.Indent -= 1;
                    writer.WriteLine("}");
                }
            }
        }
        private void WriteContext(CodeWriter writer, Context context)
        {
            foreach (var contract in context.Contracts)
            {
                if (contract.Modifiers.Any())
                {
                    if (contract.Modifiers.FirstOrDefault(c => c.Identifier == "!" && c.Interface != "IIdentity") != null)
                    {
                        writer.Write(TemplateForEventInterfaceName, contract.Name,
                                     string.Join(", ", contract.Modifiers.Select(s => s.Interface).ToArray()));
                        writer.WriteLine();

                        writer.WriteLine("{");
                        writer.Indent += 1;

                        if (contract.Members.Count > 0)
                        {
                            WriteInterfaceMembers(contract, writer);

                            writer.WriteLine();
                        }
                        writer.Indent -= 1;

                        writer.WriteLine("}");
                    }
                }

                writer.Write(ClassNameTemplate, contract.Name, context.CurrentExtern, string.Empty);
                //}

                if (contract.Modifiers.Any())
                {
                    if (contract.Modifiers.FirstOrDefault(c => c.Identifier == "!" && c.Interface != "IIdentity") !=
                       null)
                    {
                        //writer.Write(" : DomainEvent, {0}", string.Join(", ", contract.Modifiers.Select(s => s.Interface).ToArray()));
                        writer.Write(" : DomainEvent, {0}", string.Format("I{0}", contract.Name));
                    }
                    //else if (contract.Modifiers.FirstOrDefault(c => c.Identifier == "?" && c.Interface != "IIdentity") != null)
                    //{
                    //	writer.Write(" : DomainCommand, {0}", string.Join(", ", contract.Modifiers.Select(s => s.Interface).ToArray()));
                    //}
                    else
                    {
                        writer.Write(" : {0}", string.Join(", ", contract.Modifiers.Select(s => s.Interface).ToArray()));
                    }
                }
                writer.WriteLine();

                writer.WriteLine("{");
                writer.Indent += 1;

                if (contract.Members.Count > 0)
                {
                    WriteMembers(contract, writer);

                    writer.WriteLine();
                    WritePrivateCtor(writer, contract);
                    if (contract.Modifiers.FirstOrDefault(c => c.Identifier == "!" && c.Interface != "IIdentity") != null)
                    {
                        writer.Write("public {0} (TenancyId tenancyId, int aggregateVersion, ", contract.Name);
                    }
                    else if (contract.Modifiers.FirstOrDefault(c => c.Interface == "DomainCommand") != null)
                    {
                        writer.Write("public {0} (TenancyId tenancyId, int aggregateVersion, ", contract.Name);
                    }
                    else
                    {
                        writer.Write("public {0} (", contract.Name);
                    }
                    WriteParameters(contract, writer);
                    if (contract.Modifiers.FirstOrDefault(c => c.Identifier == "!" && c.Interface != "IIdentity") != null)
                    {
                        writer.WriteLine(") : base(tenancyId, id, aggregateVersion)");
                    }
                        else if (contract.Modifiers.FirstOrDefault(c => c.Interface == "DomainCommand") != null)
                        {
                            writer.WriteLine(") : base(tenancyId, aggregateVersion)");
                        }
                        else
                        {
                            writer.WriteLine(")");
                        }
                    writer.WriteLine("{");

                    writer.Indent += 1;
                    WriteAssignments(contract, writer);
                    writer.Indent -= 1;

                    writer.WriteLine("}");

                }
                WriteToString(writer, contract);
                if (contract.Modifiers.FirstOrDefault(c => c.Identifier == "!" && c.Interface == "IIdentity") != null)
                {
                    writer.WriteLine(@"public override string ToString()
            {{
            return Id.ToString();
            }}

            protected bool Equals({0} other)
            {{
            return Id.Equals(other.Id);
            }}

            public override bool Equals(object obj)
            {{
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != this.GetType()) return false;
            return Equals(({0}) obj);
            }}

            public override int GetHashCode()
            {{
            return Id.GetHashCode();
            }}

            public static bool operator ==({0} a, {0} b)
            {{
            if (ReferenceEquals(a, b))
            {{
                return true;
            }}
            if (((object) a == null) || ((object) b == null))
            {{
                return false;
            }}
            return a.Equals(b);
            }}

            public static bool operator !=({0} a, {0} b)
            {{
            return !(a == b);
            }}

            public static {0} New()
            {{
            return new {0}(Guid.NewGuid());
            }}

            public static {0} Empty()
            {{
            return new {0}(Guid.Empty);
            }}", contract.Name);
                }
                writer.Indent -= 1;
                writer.WriteLine("}");
            }
            foreach (var entity in context.Entities)
            {
                if ((entity.Name ?? "default") == "default")
                    continue;

                GenerateEntityInterface(entity, writer, "?", "public interface I{0}Aggregate");
                GenerateEntityInterface(entity, writer, "!", "public interface I{0}AggregateState");
            }
        }
        public void Generate(Context context, IndentedTextWriter outer)
        {
            // Apply templates
            foreach (var template in context.Templates)
            {
                if(String.IsNullOrWhiteSpace(template.Key) || String.IsNullOrWhiteSpace(template.Value)) continue;

                var propertyInfo = GetType().GetProperty(template.Key);
                if(propertyInfo == null) continue;

                try
                {
                    propertyInfo.SetValue(this, template.Value, null);
                }
                catch (Exception)
                {
                    Console.WriteLine("Error when setting value for template '{0}", template.Key);
                }
            }

            var writer = new CodeWriter(outer);

            foreach (var source in context.Using.Distinct().OrderBy(s => s))
            {
                writer.WriteLine("using {0};", source);
            }

            writer.WriteLine(@"
            // ReSharper disable PartialTypeWithSinglePart
            // ReSharper disable UnusedMember.Local");

            writer.WriteLine("namespace {0}", context.CurrentNamespace);
            writer.WriteLine("{");

            writer.Indent += 1;

            if (!string.IsNullOrEmpty(Region))
            {
                writer.WriteLine("#region {0}", Region);
            }

            WriteContext(writer, context);

            if (!string.IsNullOrEmpty(Region))
            {
                writer.WriteLine("#endregion");
            }

            writer.Indent -= 1;
            writer.WriteLine("}");
        }