#include <catch2/catch.hpp>
#include <common/createUnique.hpp>

#include "grammar/ContextFree/CFG.h"
#include "grammar/transform/GrammarAlternation.h"

TEST_CASE ( "Grammar Alternation", "[unit][algo][grammar][transform]" ) {
	SECTION ( "Test CFG" ) {
		{
			ext::pair < DefaultSymbolType, unsigned > S1 = ext::make_pair ( DefaultSymbolType ( "S" ), 1 );
			ext::pair < DefaultSymbolType, unsigned > A1 = ext::make_pair ( DefaultSymbolType ( "A" ), 1 );
			ext::pair < DefaultSymbolType, unsigned > S2 = ext::make_pair ( DefaultSymbolType ( "S" ), 2 );
			ext::pair < DefaultSymbolType, unsigned > A2 = ext::make_pair ( DefaultSymbolType ( "A" ), 2 );
			DefaultSymbolType S = DefaultSymbolType ( "S" );
			DefaultSymbolType A = DefaultSymbolType ( "A" );

			DefaultSymbolType a = DefaultSymbolType ( 'a' );
			DefaultSymbolType b = DefaultSymbolType ( 'b' );

			grammar::CFG < DefaultSymbolType, DefaultSymbolType > grammar1 ( { S, A }, { a, b }, S );
			grammar::CFG < DefaultSymbolType, DefaultSymbolType > grammar2 ( { S, A }, { a, b }, S );

			ext::pair < DefaultSymbolType, unsigned > S0 = ext::make_pair ( common::createUnique ( label::InitialStateLabel::instance < DefaultSymbolType > ( ), grammar1.getNonterminalAlphabet ( ), grammar2.getNonterminalAlphabet ( ) ), 0 );
			grammar::CFG < DefaultSymbolType, ext::pair < DefaultSymbolType, unsigned > > grammar3 ( { S0, S1, A1, S2, A2 }, { a, b }, S0 );

			grammar1.addRule ( S, { } );
			grammar1.addRule ( S, { a, A } );
			grammar1.addRule ( S, { a, S } );
			grammar1.addRule ( A, { a, A } );
			grammar1.addRule ( A, { } );

			grammar2.addRule ( S, { } );
			grammar2.addRule ( S, { a, A } );
			grammar2.addRule ( S, { a, S } );
			grammar2.addRule ( A, { a, A } );
			grammar2.addRule ( A, { } );

			grammar3.addRule ( S0, { S1 } );
			grammar3.addRule ( S0, { S2 } );

			grammar3.addRule ( S1, { } );
			grammar3.addRule ( S1, { a, A1 } );
			grammar3.addRule ( S1, { a, S1 } );
			grammar3.addRule ( A1, { a, A1 } );
			grammar3.addRule ( A1, { } );

			grammar3.addRule ( S2, { } );
			grammar3.addRule ( S2, { a, A2 } );
			grammar3.addRule ( S2, { a, S2 } );
			grammar3.addRule ( A2, { a, A2 } );
			grammar3.addRule ( A2, { } );

			CHECK ( grammar3 == grammar::transform::GrammarAlternation::alternation ( grammar1, grammar2 ) );
		}
	}
}
