public void TestTrueGenericsAmbiguity()
        {
            var name                      = new NonTerminal("Name");
            var argList                   = new NonTerminal("List<Exp>");
            var genericParameters         = new NonTerminal("Gen");
            var optionalGenericParameters = new NonTerminal("Opt<Gen>");
            var cmp = new NonTerminal("Cmp");

            var rules = new[]
            {
                new Rule(Start, Exp),

                new Rule(Exp, ID),
                new Rule(Exp, OPEN_PAREN, Exp, CLOSE_PAREN),
                new Rule(Exp, ID, cmp, Exp),
                new Rule(Exp, name, OPEN_PAREN, argList, CLOSE_PAREN),

                new Rule(cmp, LT),
                new Rule(cmp, GT),

                new Rule(argList, Exp),
                new Rule(argList, Exp, COMMA, argList),

                new Rule(name, ID, optionalGenericParameters),

                new Rule(optionalGenericParameters),
                new Rule(optionalGenericParameters, genericParameters),

                new Rule(genericParameters, LT, ID, GT)
            };

            // currently this fails due to duplicate prefixes
            var ex = Assert.Throws <NotSupportedException>(() => ParserBuilder.CreateParser(rules));

            this.output.WriteLine(ex.Message);

            var nodes = ParserBuilder.CreateParser(
                rules,
                new Dictionary <IReadOnlyList <Symbol>, Rule>
            {
                {
                    // note: this is more minimal than ideal; id<id>() is not ambiguous
                    new[] { ID, LT, ID, GT, OPEN_PAREN, ID },
                    rules.Single(r => r.Symbols.SequenceEqual(new Symbol[] { name, OPEN_PAREN, argList, CLOSE_PAREN }))
                },
            }
                );
            var parser   = new ParserNodeParser(nodes, Start, this.output.WriteLine);
            var listener = new TreeListener();

            // compares: id < id > (id) vs. call: id<id>(id) => our resolution says call
            parser.Parse(new[] { ID, LT, ID, GT, OPEN_PAREN, ID, CLOSE_PAREN }, listener);
            this.output.WriteLine(listener.Root.Flatten().ToString());
            listener.Root.Flatten().ToString().ShouldEqual("Start(Exp(Name(ID, Opt<Gen>(Gen(<, ID, >))), (, List<Exp>(Exp(ID)), )))");
        }
        public void TestGenericsAmbiguity()
        {
            var name                      = new NonTerminal("Name");
            var nameListOption            = new NonTerminal("Opt<List<Name>>");
            var nameList                  = new NonTerminal("List<Name>");
            var genericParameters         = new NonTerminal("Gen");
            var optionalGenericParameters = new NonTerminal("Opt<Gen>");

            var rules = new[]
            {
                new Rule(Exp, name),
                new Rule(name, ID, optionalGenericParameters),
                new Rule(optionalGenericParameters),
                new Rule(optionalGenericParameters, genericParameters),
                new Rule(genericParameters, LT, nameListOption, GT),
                new Rule(nameListOption),
                new Rule(nameListOption, nameList),
                new Rule(nameList, name),
                new Rule(nameList, name, COMMA, nameList)
            };

            var nodes1    = ParserBuilder.CreateParser(rules);
            var parser1   = new ParserNodeParser(nodes1, Exp, this.output.WriteLine);
            var listener1 = new TreeListener();

            parser1.Parse(new[] { ID, LT, ID, COMMA, ID, GT }, listener1);
            this.output.WriteLine(listener1.Root.Flatten().ToString());
            listener1.Root.Flatten().ToString().ShouldEqual("Exp(Name(ID, Opt<Gen>(Gen(<, Opt<List<Name>>(List<Name>(Name(ID, Opt<Gen>()), ,, Name(ID, Opt<Gen>()))), >))))");

            var cmp            = new NonTerminal("Cmp");
            var ambiguousRules = rules.Concat(new[]
            {
                new Rule(cmp, LT),
                new Rule(cmp, GT),
                new Rule(Exp, ID, cmp, Exp),
            })
                                 .ToArray();

            this.output.WriteLine("*********** MORE AMBIGUOUS CASE ***********");
            var nodes2    = ParserBuilder.CreateParser(ambiguousRules);
            var parser2   = new ParserNodeParser(nodes2, Exp, this.output.WriteLine);
            var listener2 = new TreeListener();

            // id < id<id<id>>
            parser2.Parse(new[] { ID, LT, ID, LT, ID, LT, ID, GT, GT }, listener2);
            this.output.WriteLine(listener2.Root.Flatten().ToString());
            listener2.Root.Flatten()
            .ToString()
            .ShouldEqual("Exp(ID, Cmp(<), Exp(Name(ID, Opt<Gen>(Gen(<, Opt<List<Name>>(List<Name>(Name(ID, Opt<Gen>(Gen(<, Opt<List<Name>>(List<Name>(Name(ID, Opt<Gen>()))), >))))), >)))))");
        }
        public void TestCastAmbiguity()
        {
            var cast  = new NonTerminal("Cast");
            var term  = new NonTerminal("Term");
            var minus = new Token("-");

            var rules = new[]
            {
                new Rule(Start, Exp),

                new Rule(Exp, term),
                new Rule(Exp, term, minus, Exp),

                new Rule(term, ID),
                new Rule(term, OPEN_PAREN, Exp, CLOSE_PAREN),
                new Rule(term, cast),

                new Rule(cast, OPEN_PAREN, ID, CLOSE_PAREN, Exp),
            };

            var ex = Assert.Throws <NotSupportedException>(() => ParserBuilder.CreateParser(rules));

            this.output.WriteLine(ex.Message);

            var nodes = ParserBuilder.CreateParser(
                rules,
                new Dictionary <IReadOnlyList <Symbol>, Rule>
            {
                {
                    new[] { term },
                    rules.Single(r => r.Symbols.SequenceEqual(new Symbol[] { term, minus, Exp }))
                },
            }
                );
            var parser   = new ParserNodeParser(nodes, Start, this.output.WriteLine);
            var listener = new TreeListener();

            // (id)((id) - id)
            parser.Parse(new[] { OPEN_PAREN, ID, CLOSE_PAREN, OPEN_PAREN, OPEN_PAREN, ID, CLOSE_PAREN, minus, ID, CLOSE_PAREN }, listener);
            this.output.WriteLine(listener.Root.Flatten().ToString());
            listener.Root.Flatten().ToString()
            .ShouldEqual("Start(Exp(Term(Cast((, ID, ), Exp(Term((, Exp(Term((, Exp(Term(ID)), )), -, Exp(Term(ID))), )))))))");
        }
        public void TestExpressionVsStatementListConflict()
        {
            var rules = new[]
            {
                new Rule(Start, Stmt),
                new Rule(Stmt, Exp, SEMICOLON),
                new Rule(Exp, ID),
                new Rule(Exp, OPEN_BRACKET, ExpList, CLOSE_BRACKET),
                new Rule(Exp, OPEN_BRACKET, Stmt, StmtList, CLOSE_BRACKET),
                new Rule(ExpList),
                new Rule(ExpList, Exp, ExpList),
                new Rule(StmtList),
                new Rule(StmtList, Stmt, StmtList)
            };

            var nodes = ParserBuilder.CreateParser(rules);
            //var parser = new ParserGenerator(rules).Create();

            var parser1   = new ParserNodeParser(nodes, Start);
            var listener1 = new TreeListener();

            // [];
            parser1.Parse(new[] { OPEN_BRACKET, CLOSE_BRACKET, SEMICOLON }, listener1);
            this.output.WriteLine(listener1.Root.Flatten().ToString());
            listener1.Root.Flatten().ToString().ShouldEqual("Start(Stmt(Exp([, List<Exp>(), ]), ;))");

            this.output.WriteLine(Environment.NewLine + "///////////////// CASE 2 /////////////////" + Environment.NewLine);

            var parser2   = new ParserNodeParser(nodes, Start, this.output.WriteLine);
            var listener2 = new TreeListener();

            // [ [ id; ] [ [] id ] ];
            parser2.Parse(new[] { OPEN_BRACKET, OPEN_BRACKET, ID, SEMICOLON, CLOSE_BRACKET, OPEN_BRACKET, OPEN_BRACKET, CLOSE_BRACKET, ID, CLOSE_BRACKET, CLOSE_BRACKET, SEMICOLON }, listener2);
            this.output.WriteLine(listener2.Root.Flatten().ToString());
            listener2.Root.Flatten().ToString().ShouldEqual("Start(Stmt(Exp([, List<Exp>(Exp([, Stmt(Exp(ID), ;), List<Stmt>(), ]), Exp([, List<Exp>(Exp([, List<Exp>(), ]), Exp(ID)), ])), ]), ;))");
        }
        public void TestLL1()
        {
            var rules = new[]
            {
                new Rule(Start, StmtList),
                new Rule(StmtList),
                new Rule(StmtList, Stmt, StmtList),
                new Rule(Stmt, Exp, SEMICOLON),
                new Rule(Exp, ID),
                new Rule(Exp, OPEN_BRACKET, ExpList, CLOSE_BRACKET),
                new Rule(ExpList),
                new Rule(ExpList, Exp, ExpList)
            };
            var nodes  = ParserBuilder.CreateParser(rules);
            var parser = new ParserNodeParser(nodes, Start, this.output.WriteLine);

            var listener = new TreeListener();

            parser.Parse(new[] { ID, SEMICOLON, OPEN_BRACKET, ID, OPEN_BRACKET, ID, ID, CLOSE_BRACKET, CLOSE_BRACKET, SEMICOLON }, listener);

            this.output.WriteLine(listener.Root.Flatten().ToString());
            listener.Root.Flatten().ToString()
            .ShouldEqual("Start(List<Stmt>(Stmt(Exp(ID), ;), Stmt(Exp([, List<Exp>(Exp(ID), Exp([, List<Exp>(Exp(ID), Exp(ID)), ])), ]), ;)))");
        }