Esempio n. 1
0
        public override ParseTree Parse(Lexer lexer, ParserState state)
        {
            state.RuntimeState.Runtime.ParseTrace.Enter(this, lexer.CurrentSource(), "Pattern " + Type.Name);

            int start = lexer.Position;

            if (state.Excluded.Contains(this))
            {
                state.RuntimeState.Runtime.ParseTrace.No(this, lexer.CurrentSource(), "Excluded");
                return(ParseTree.No);
            }

            Precedence oldCurrentPrecedence = state.CurrentPrecedence;

            if (Precedence.Overwrites(state.CurrentPrecedence))
            {
                state.CurrentPrecedence = Precedence;
            }

            ParseTree tree = ParseGraph.Parse(lexer, state);

            state.CurrentPrecedence = oldCurrentPrecedence;

            if (tree == ParseTree.No)
            {
                state.RuntimeState.Runtime.ParseTrace.No(this, lexer.SourceFrom(start));
                return(ParseTree.No);
            }

            state.RuntimeState.Runtime.ParseTrace.Yes(this, lexer.SourceFrom(start));

            return(tree);
        }
        void DecorateCore()
        {
            ReadSettings();

            var productions = _config.Productions;
            var initial     = productions.Count;

            PopulateUsings();

            for (var i = 0; i < initial; i++)
            {
                DecorateProduction(productions[i]);
            }

            if (productions.Count == 0)
            {
                _reporter.AddError(1, 1, 1, 1, "No productions defined.");
                return;
            }

            PopulateTopLevelSegments();
            DetectUnreachableNonTerminals();

            if (!VerifyProductionReferences())
            {
                return;
            }

            _config.UseErrorRecovery = _terminals.ContainsKey(Segment.Error.Name);
            _config.Graph            = ParseGraph.ConstructGraph(_config);

            ValidateGraph();
        }
Esempio n. 3
0
        public virtual bool Update(Pattern updated)
        {
            bool updates = ParseGraph.Update(updated);

            if (updates)
            {
                Updated();
            }

            return(updates);
        }
Esempio n. 4
0
        static object GenerateParseGraph(string text)
        {
            var errorReporter = new Mock <IErrorReporter>(MockBehavior.Strict);

            var parser = new ConfigParser(errorReporter.Object);
            var config = parser.Parse(new ConfigScanner(text));

            SyntaxTreeDecorator.Decorate(config, errorReporter.Object);
            var parse = ParseGraph.ConstructGraph(config);

            return(parse.Graph);
        }
Esempio n. 5
0
            public string StartPointsRenderer(ParseGraph parseGraph)
            {
                var bulider = new StringBuilder();

                foreach (var pair in parseGraph)
                {
                    pair.Key.AppendTo(bulider);
                    bulider.Append(": ");
                    bulider.Append(GetID(pair.Value).ToString(CultureInfo.InvariantCulture));
                    bulider.AppendLine();
                }

                return(bulider.ToString());
            }
Esempio n. 6
0
        public void ConstructDFA1()
        {
            var parseGraph = ParseGraph.ConstructGraph(ConstructSample1());

            const string expected =
                "0 (S)                     -- <A> --> 1                        \r\n" +
                "[<A'> -> • <A>, EOF]                 [<A'> -> <A> •, EOF]     \r\n" +
                "[<A> -> • a, EOF]                                             \r\n" +
                "[<A> -> • ( <A> ), EOF]                                       \r\n" +
                "0 (S)                     -- a --> 2                        \r\n" +
                "[<A'> -> • <A>, EOF]               [<A> -> a •, )/EOF]      \r\n" +
                "[<A> -> • a, EOF]                                           \r\n" +
                "[<A> -> • ( <A> ), EOF]                                     \r\n" +
                "0 (S)                     -- ( --> 3                        \r\n" +
                "[<A'> -> • <A>, EOF]               [<A> -> • a, )]          \r\n" +
                "[<A> -> • a, EOF]                  [<A> -> • ( <A> ), )]    \r\n" +
                "[<A> -> • ( <A> ), EOF]            [<A> -> ( • <A> ), )/EOF]\r\n" +
                "3                         -- a --> 2                        \r\n" +
                "[<A> -> • a, )]                    [<A> -> a •, )/EOF]      \r\n" +
                "[<A> -> • ( <A> ), )]                                       \r\n" +
                "[<A> -> ( • <A> ), )/EOF]                                   \r\n" +
                "3                         -- ( --> 3                        \r\n" +
                "[<A> -> • a, )]                    [<A> -> • a, )]          \r\n" +
                "[<A> -> • ( <A> ), )]              [<A> -> • ( <A> ), )]    \r\n" +
                "[<A> -> ( • <A> ), )/EOF]          [<A> -> ( • <A> ), )/EOF]\r\n" +
                "3                         -- <A> --> 4                        \r\n" +
                "[<A> -> • a, )]                      [<A> -> ( <A> • ), EOF]  \r\n" +
                "[<A> -> • ( <A> ), )]                                         \r\n" +
                "[<A> -> ( • <A> ), )/EOF]                                     \r\n" +
                "4                         -- ) --> 5                        \r\n" +
                "[<A> -> ( <A> • ), EOF]            [<A> -> ( <A> ) •, )/EOF]\r\n" +
                "";

            const string expectedStartPoints =
                "<A>: 0\r\n" +
                "";

            var renderer = new ParseRenderer();

            Assert.That(renderer.Render(parseGraph.Graph, 25), Is.EqualTo(expected));
            Assert.That(renderer.StartPointsRenderer(parseGraph), Is.EqualTo(expectedStartPoints));
        }
Esempio n. 7
0
        public override Block CompileNew(Runtime runtime, StateForCompiler state)
        {
            ParserBlock block = new ParserBlock(runtime);

            block.Comment("start of abstract pattern -------------");

            BlockLabel returnLabel = new BlockLabel("return");

            block.Enter(this, Type.Name);

            block.BeginScope();

            BlockLocal start = block.SavePosition();

            BlockLabel notExcluded = new BlockLabel("notExcluded");

            block.LoadState();
            block.GetProperty(typeof(ParserState).GetProperty("Excluded"));
            block.Load(this);
            block.Call(typeof(Multiset <Pattern>).GetMethod("Contains"));
            block.BranchIfFalse(notExcluded);

            block.No(this);

            block.LoadNo();
            block.Branch(returnLabel);

            block.MarkLabel(notExcluded);

            BlockLocal oldCurrentPrecedence = new BlockLocal(typeof(Precedence));

            block.DeclareLocal(oldCurrentPrecedence);
            block.LoadState();
            block.GetProperty(typeof(ParserState).GetProperty("CurrentPrecedence"));
            block.StoreLocal(oldCurrentPrecedence);

            BlockLabel doesntOverwrite = new BlockLabel("doesntOverwrite");

            block.Load(Precedence);
            block.LoadLocal(oldCurrentPrecedence);
            block.Call(typeof(Precedence).GetMethod("Overwrites"));
            block.BranchIfFalse(doesntOverwrite);

            block.LoadState();
            block.Load(Precedence);
            block.SetProperty(typeof(ParserState).GetProperty("CurrentPrecedence"));

            block.MarkLabel(doesntOverwrite);

            block.Emit(ParseGraph.Compile(runtime, state));

            block.LoadState();
            block.LoadLocal(oldCurrentPrecedence);
            block.SetProperty(typeof(ParserState).GetProperty("CurrentPrecedence"));

            block.Dup();

            BlockLabel yes = new BlockLabel("yes");

            block.BranchIfNotNo(yes);

            block.No(this, start);

            block.Branch(returnLabel);

            block.MarkLabel(yes);

            block.Yes(this, start);

            block.EndScope();

            block.MarkLabel(returnLabel);

            block.Comment("end of abstract pattern -------------");

            return(block);
        }
Esempio n. 8
0
        public void ConstructDFA2()
        {
            var parseGraph = ParseGraph.ConstructGraph(ConstructSample2());

            const string expected =
                "0 (S)                      -- <E> --> 1                         \r\n" +
                "[<E'> -> • <E>, EOF]                  [<E'> -> <E> •, EOF]      \r\n" +
                "[<E> -> • n, EOF]                                               \r\n" +
                "[<E> -> • <V>, EOF]                                             \r\n" +
                "[<V> -> • id, EOF]                                              \r\n" +
                "0 (S)                      -- n --> 2                         \r\n" +
                "[<E'> -> • <E>, EOF]                [<E> -> n •, EOF]         \r\n" +
                "[<E> -> • n, EOF]                                             \r\n" +
                "[<E> -> • <V>, EOF]                                           \r\n" +
                "[<V> -> • id, EOF]                                            \r\n" +
                "0 (S)                      -- <V> --> 3                         \r\n" +
                "[<E'> -> • <E>, EOF]                  [<E> -> <V> •, EOF]       \r\n" +
                "[<E> -> • n, EOF]                                               \r\n" +
                "[<E> -> • <V>, EOF]                                             \r\n" +
                "[<V> -> • id, EOF]                                              \r\n" +
                "0 (S)                      -- id --> 4                         \r\n" +
                "[<E'> -> • <E>, EOF]                 [<V> -> id •, EOF]        \r\n" +
                "[<E> -> • n, EOF]                                              \r\n" +
                "[<E> -> • <V>, EOF]                                            \r\n" +
                "[<V> -> • id, EOF]                                             \r\n" +
                "5 (S)                      -- <S> --> 6                         \r\n" +
                "[<S'> -> • <S>, EOF]                  [<S'> -> <S> •, EOF]      \r\n" +
                "[<S> -> • id, EOF]                                              \r\n" +
                "[<S> -> • <V> := <E>, EOF]                                      \r\n" +
                "[<V> -> • id, :=]                                               \r\n" +
                "5 (S)                      -- id --> 7                         \r\n" +
                "[<S'> -> • <S>, EOF]                 [<S> -> id •, EOF]        \r\n" +
                "[<S> -> • id, EOF]                   [<V> -> id •, :=]         \r\n" +
                "[<S> -> • <V> := <E>, EOF]                                     \r\n" +
                "[<V> -> • id, :=]                                              \r\n" +
                "5 (S)                      -- <V> --> 8                         \r\n" +
                "[<S'> -> • <S>, EOF]                  [<S> -> <V> • := <E>, EOF]\r\n" +
                "[<S> -> • id, EOF]                                              \r\n" +
                "[<S> -> • <V> := <E>, EOF]                                      \r\n" +
                "[<V> -> • id, :=]                                               \r\n" +
                "8                          -- := --> 9                         \r\n" +
                "[<S> -> <V> • := <E>, EOF]           [<E> -> • n, EOF]         \r\n" +
                "                                     [<E> -> • <V>, EOF]       \r\n" +
                "                                     [<V> -> • id, EOF]        \r\n" +
                "                                     [<S> -> <V> := • <E>, EOF]\r\n" +
                "9                          -- n --> 2                         \r\n" +
                "[<E> -> • n, EOF]                   [<E> -> n •, EOF]         \r\n" +
                "[<E> -> • <V>, EOF]                                           \r\n" +
                "[<V> -> • id, EOF]                                            \r\n" +
                "[<S> -> <V> := • <E>, EOF]                                    \r\n" +
                "9                          -- <V> --> 3                         \r\n" +
                "[<E> -> • n, EOF]                     [<E> -> <V> •, EOF]       \r\n" +
                "[<E> -> • <V>, EOF]                                             \r\n" +
                "[<V> -> • id, EOF]                                              \r\n" +
                "[<S> -> <V> := • <E>, EOF]                                      \r\n" +
                "9                          -- id --> 4                         \r\n" +
                "[<E> -> • n, EOF]                    [<V> -> id •, EOF]        \r\n" +
                "[<E> -> • <V>, EOF]                                            \r\n" +
                "[<V> -> • id, EOF]                                             \r\n" +
                "[<S> -> <V> := • <E>, EOF]                                     \r\n" +
                "9                          -- <E> --> 10                        \r\n" +
                "[<E> -> • n, EOF]                     [<S> -> <V> := <E> •, EOF]\r\n" +
                "[<E> -> • <V>, EOF]                                             \r\n" +
                "[<V> -> • id, EOF]                                              \r\n" +
                "[<S> -> <V> := • <E>, EOF]                                      \r\n" +
                "";

            const string expectedStartPoints =
                "<E>: 0\r\n" +
                "<S>: 5\r\n" +
                "";

            var renderer = new ParseRenderer();

            Assert.That(renderer.Render(parseGraph.Graph, 26), Is.EqualTo(expected));
            Assert.That(renderer.StartPointsRenderer(parseGraph), Is.EqualTo(expectedStartPoints));
        }
Esempio n. 9
0
        public override ParseTree Parse(Lexer lexer, ParserState state)
        {
            int start = lexer.Position;

            state.RuntimeState.Runtime.ParseTrace.Enter(this, lexer.CurrentSource(), "Pattern " + Type.Name);

            /*state.RuntimeState.Runtime.ParseTrace.Enter(this, lexer.CurrentSource(), "Excluded:");
             *
             * foreach (Pattern excluded in state.Excluded)
             *  state.RuntimeState.Runtime.ParseTrace.Single(excluded.Type.Name);
             *
             * state.RuntimeState.Runtime.ParseTrace.Leave(this);*/

            if (state.Excluded.Contains(this))
            {
                state.RuntimeState.Runtime.ParseTrace.No(this, lexer.CurrentSource(), "Excluded");
                return(ParseTree.No);
            }

            ParserMemoryKey key = new ParserMemoryKey(this, start);

            bool oldSkipMemoryForLeftRecursion = state.SkipMemoryForLeftRecursion;

            if (state.SkipMemoryForLeftRecursion)
            {
                state.SkipMemoryForLeftRecursion = false;
            }
            else
            {
                ParserMemoryEntry entry;

                if (state.Memory.TryGetValue(key, out entry))
                {
                    state.RuntimeState.Runtime.ParseTrace.LinkNext(entry.Tag);

                    if (entry.Tree == ParseTree.No)
                    {
                        state.RuntimeState.Runtime.ParseTrace.No(this, lexer.SourceFrom(start), "From memory");
                    }
                    else
                    {
                        state.RuntimeState.Runtime.ParseTrace.Yes(this, lexer.SourceFrom(start), "From memory");
                        lexer.Position = entry.End;
                    }

                    return(entry.Tree);
                }
            }

            ConcretePattern oldRecursionExclude = state.RecursionExclude;

            if (RecursionBehaviour != RecursionBehaviour.Recursive)
            {
                if (state.RecursionExclude != null)
                {
                    state.Excluded.Remove(state.RecursionExclude);
                }

                state.RecursionExclude = this;

                state.Excluded.Add(this);
            }

            RecursionBehaviour oldRecursionBehaviour = state.RecursionBehaviour;

            state.RecursionBehaviour = RecursionBehaviour;

            Precedence oldCurrentPrecedence = state.CurrentPrecedence;

            if (Precedence.Overwrites(state.CurrentPrecedence))
            {
                state.CurrentPrecedence = Precedence;
            }

            bool oldPrecedenceCanEqualCurrent = state.PrecedenceCanEqualCurrent;

            state.PrecedenceCanEqualCurrent = RecursionBehaviour == RecursionBehaviour.Recursive;

            ParseTree tree = ParseGraph.Parse(lexer, state);

            state.CurrentPrecedence          = oldCurrentPrecedence;
            state.PrecedenceCanEqualCurrent  = oldPrecedenceCanEqualCurrent;
            state.RecursionBehaviour         = oldRecursionBehaviour;
            state.RecursionExclude           = oldRecursionExclude;
            state.SkipMemoryForLeftRecursion = oldSkipMemoryForLeftRecursion;

            if (RecursionBehaviour != RecursionBehaviour.Recursive)
            {
                if (oldRecursionExclude != null)
                {
                    state.Excluded.Add(oldRecursionExclude);
                }

                state.Excluded.Remove(this);
            }

            if (tree != ParseTree.No)
            {
                lexer.Whitespace(state.RuntimeState);
                tree = Instantiate(lexer, state, start, tree);
            }

            object nextTag = new object();

            state.RuntimeState.Runtime.ParseTrace.TagNext(nextTag);

            if (tree == ParseTree.No)
            {
                state.RuntimeState.Runtime.ParseTrace.No(this, lexer.SourceFrom(start));
            }
            else
            {
                state.RuntimeState.Runtime.ParseTrace.Yes(this, lexer.SourceFrom(start));

                if (RecursionBehaviour == RecursionBehaviour.LeftRecursive)
                {
                    tree = LeftRecurse(lexer, state, start, tree);
                }
            }

            // TODO - can remove some other code if not remembering

            if (ShouldRemember)
            {
                state.Memory[key] = new ParserMemoryEntry(tree, lexer.Position, nextTag);
            }

            return(tree);
        }
Esempio n. 10
0
        public override Block CompileNew(Runtime runtime, StateForCompiler state)
        {
            ParserBlock block = new ParserBlock(runtime);

            block.Comment("start of concrete pattern -------------");

            BlockLabel returnLabel = new BlockLabel("return");

            block.BeginScope();

            block.Enter(this, Type.Name);

            BlockLocal start = block.SavePosition();

            BlockLabel notExcluded = new BlockLabel("notExcluded");

            block.LoadState();
            block.GetProperty(typeof(ParserState).GetProperty("Excluded"));
            block.Load(this);
            block.Call(typeof(Multiset <Pattern>).GetMethod("Contains"));
            block.BranchIfFalse(notExcluded);

            block.No(this, "Excluded");

            block.LoadNo();
            block.Branch(returnLabel);

            block.MarkLabel(notExcluded);

            BlockLocal key = new BlockLocal(typeof(ParserMemoryKey));

            block.DeclareLocal(key);
            block.Load(this);
            block.LoadLocal(start);
            block.New(typeof(ParserMemoryKey).GetConstructor(new Type[] { typeof(ConcretePattern), typeof(int) }));
            block.StoreLocal(key);

            BlockLocal oldSkipMemoryForLeftRecursion = new BlockLocal(typeof(bool));

            block.DeclareLocal(oldSkipMemoryForLeftRecursion);
            block.LoadState();
            block.GetProperty(typeof(ParserState).GetProperty("SkipMemoryForLeftRecursion"));
            block.Dup();
            block.StoreLocal(oldSkipMemoryForLeftRecursion);

            BlockLabel checkMemory = new BlockLabel("checkMemory");

            block.BranchIfFalse(checkMemory);

            block.LoadState();
            block.Load(false);
            block.SetProperty(typeof(ParserState).GetProperty("SkipMemoryForLeftRecursion"));

            BlockLabel setRecursion = new BlockLabel("setRecursion");

            block.Branch(setRecursion);

            block.MarkLabel(checkMemory);

            block.BeginScope();

            BlockLocal entry = new BlockLocal(typeof(ParserMemoryEntry));

            block.DeclareLocal(entry);

            block.LoadState();
            block.GetProperty(typeof(ParserState).GetProperty("Memory"));
            block.LoadLocal(key);
            block.LoadLocalAddress(entry);
            block.Call(typeof(Dictionary <ParserMemoryKey, ParserMemoryEntry>).GetMethod("TryGetValue"));
            block.BranchIfFalse(setRecursion);

            // todo link next

            BlockLabel memoryYes = new BlockLabel("memoryYes");

            block.LoadLocal(entry);
            block.GetProperty(typeof(ParserMemoryEntry).GetProperty("Tree"));

            BlockLabel returnTree = new BlockLabel("returnTree");

            block.BranchIfNotNo(memoryYes);

            block.No(this, start, "from memory");

            block.Branch(returnTree);

            block.MarkLabel(memoryYes);

            block.Yes(this, start, "from memory");

            block.LoadLexer();
            block.LoadLocal(entry);
            block.GetProperty(typeof(ParserMemoryEntry).GetProperty("End"));
            block.SetProperty(typeof(Lexer).GetProperty("Position"));

            block.MarkLabel(returnTree);

            block.LoadLocal(entry);
            block.GetProperty(typeof(ParserMemoryEntry).GetProperty("Tree"));

            block.Branch(returnLabel);

            block.MarkLabel(setRecursion);

            BlockLocal oldRecursionExclude = new BlockLocal(typeof(ConcretePattern));

            block.DeclareLocal(oldRecursionExclude);
            block.LoadState();
            block.GetProperty(typeof(ParserState).GetProperty("RecursionExclude"));
            block.StoreLocal(oldRecursionExclude);

            if (RecursionBehaviour != RecursionBehaviour.Recursive)
            {
                BlockLabel recursionExcludeSaveNull = new BlockLabel("recursionExcludeSaveNull");
                block.LoadLocal(oldRecursionExclude);
                block.BranchIfNull(recursionExcludeSaveNull);

                block.LoadState();
                block.GetProperty(typeof(ParserState).GetProperty("Excluded"));
                block.LoadLocal(oldRecursionExclude);
                block.Call(typeof(Multiset <Pattern>).GetMethod("Remove", new Type[] { typeof(Pattern) }));

                block.MarkLabel(recursionExcludeSaveNull);

                block.LoadState();
                block.Load(this);
                block.SetProperty(typeof(ParserState).GetProperty("RecursionExclude"));

                block.LoadState();
                block.GetProperty(typeof(ParserState).GetProperty("Excluded"));
                block.Load(this);
                block.Call(typeof(Multiset <Pattern>).GetMethod("Add", new Type[] { typeof(Pattern) }));
            }

            BlockLocal oldRecursionBehaviour = new BlockLocal(typeof(RecursionBehaviour));

            block.DeclareLocal(oldRecursionBehaviour);
            block.LoadState();
            block.GetProperty(typeof(ParserState).GetProperty("RecursionBehaviour"));
            block.StoreLocal(oldRecursionBehaviour);

            block.LoadState();
            block.Load(Convert.ToInt32(RecursionBehaviour));
            block.SetProperty(typeof(ParserState).GetProperty("RecursionBehaviour"));

            RecursionBehaviour oldRecursionBehaviourState = state.RecursionBehaviour;

            state.RecursionBehaviour = RecursionBehaviour;

            BlockLocal oldCurrentPrecedence = new BlockLocal(typeof(Precedence));

            block.DeclareLocal(oldCurrentPrecedence);
            block.LoadState();
            block.GetProperty(typeof(ParserState).GetProperty("CurrentPrecedence"));
            block.StoreLocal(oldCurrentPrecedence);

            BlockLabel doesntOverwrite = new BlockLabel("doesntOverwrite");

            block.Load(Precedence);
            block.LoadLocal(oldCurrentPrecedence);
            block.Call(typeof(Precedence).GetMethod("Overwrites"));
            block.BranchIfFalse(doesntOverwrite);

            block.LoadState();
            block.Load(Precedence);
            block.SetProperty(typeof(ParserState).GetProperty("CurrentPrecedence"));

            block.MarkLabel(doesntOverwrite);

            BlockLocal oldPrecedenceCanEqualCurrent = new BlockLocal(typeof(bool));

            block.DeclareLocal(oldPrecedenceCanEqualCurrent);
            block.LoadState();
            block.GetProperty(typeof(ParserState).GetProperty("PrecedenceCanEqualCurrent"));
            block.StoreLocal(oldPrecedenceCanEqualCurrent);

            block.LoadState();
            block.Load(RecursionBehaviour == RecursionBehaviour.Recursive);
            block.SetProperty(typeof(ParserState).GetProperty("PrecedenceCanEqualCurrent"));

            BlockLocal tree = new BlockLocal(typeof(ParseTree));

            block.DeclareLocal(tree);
            block.Emit(ParseGraph.Compile(runtime, state));
            block.StoreLocal(tree);

            block.LoadState();
            block.LoadLocal(oldCurrentPrecedence);
            block.SetProperty(typeof(ParserState).GetProperty("CurrentPrecedence"));

            block.LoadState();
            block.LoadLocal(oldPrecedenceCanEqualCurrent);
            block.SetProperty(typeof(ParserState).GetProperty("PrecedenceCanEqualCurrent"));

            block.LoadState();
            block.LoadLocal(oldRecursionBehaviour);
            block.SetProperty(typeof(ParserState).GetProperty("RecursionBehaviour"));

            state.RecursionBehaviour = oldRecursionBehaviourState;

            block.LoadState();
            block.LoadLocal(oldRecursionExclude);
            block.SetProperty(typeof(ParserState).GetProperty("RecursionExclude"));

            block.LoadState();
            block.LoadLocal(oldSkipMemoryForLeftRecursion);
            block.SetProperty(typeof(ParserState).GetProperty("SkipMemoryForLeftRecursion"));

            if (RecursionBehaviour != RecursionBehaviour.Recursive)
            {
                BlockLabel recursionExcludeRestoreNull = new BlockLabel("recursionExcludeRestoreNull");
                block.LoadLocal(oldRecursionExclude);
                block.BranchIfNull(recursionExcludeRestoreNull);

                block.LoadState();
                block.GetProperty(typeof(ParserState).GetProperty("Excluded"));
                block.LoadLocal(oldRecursionExclude);
                block.Call(typeof(Multiset <Pattern>).GetMethod("Add", new Type[] { typeof(Pattern) }));

                block.MarkLabel(recursionExcludeRestoreNull);

                block.LoadState();
                block.GetProperty(typeof(ParserState).GetProperty("Excluded"));
                block.Load(this);
                block.Call(typeof(Multiset <Pattern>).GetMethod("Remove", new Type[] { typeof(Pattern) }));
            }

            BlockLabel no = new BlockLabel("yes1");

            block.LoadLocal(tree);
            block.BranchIfNo(no);

            block.Whitespace(runtime, state);

            CompileInstantiate(block, start, tree);

            block.MarkLabel(no);

            BlockLocal nextTag = new BlockLocal(typeof(object));

            block.DeclareLocal(nextTag);
            block.New(typeof(object));
            block.StoreLocal(nextTag);

            // todo tag next

            BlockLabel yes = new BlockLabel("yes");

            block.LoadLocal(tree);
            block.BranchIfNotNo(yes);

            block.No(this, start, "a");

            BlockLabel finish = new BlockLabel("finish");

            block.Branch(finish);

            block.MarkLabel(yes);

            block.Yes(this, start);

            if (RecursionBehaviour == RecursionBehaviour.LeftRecursive)
            {
                CompileLeftRecurse(runtime, state, block, start, tree);
            }

            block.MarkLabel(finish);

            if (ShouldRemember)
            {
                // TODO - can remove some other code if not remembering

                block.LoadState();
                block.GetProperty(typeof(ParserState).GetProperty("Memory"));
                block.LoadLocal(key);

                block.LoadLocal(tree);
                block.LoadLexer();
                block.GetProperty(typeof(Lexer).GetProperty("Position"));
                block.LoadLocal(nextTag);
                block.New(typeof(ParserMemoryEntry).GetConstructor(new Type[] { typeof(ParseTree), typeof(int), typeof(object) }));

                block.SetProperty(typeof(Dictionary <ParserMemoryKey, ParserMemoryEntry>).GetProperty("Item"));
            }

            block.LoadLocal(tree);

            block.EndScope();

            block.MarkLabel(returnLabel);

            block.Comment("end of concrete pattern -------------");

            return(block);
        }