/*
 * GNF.h
 *
 * Created on: Sep 27, 2017
 * Author: Jan Travnicek
 */

#ifndef _STRING_GNF_H_
#define _STRING_GNF_H_

#include <grammar/ContextFree/GNF.h>
#include <core/stringApi.hpp>

#include <grammar/GrammarFromStringLexer.h>

#include <grammar/string/common/GrammarFromStringParserCommon.h>
#include <grammar/string/common/GrammarToStringComposerCommon.h>

#include <grammar/properties/IsFITDefinition.h>
#include <grammar/simplify/MakeFITDefinition.h>

namespace core {

template < class TerminalSymbolType, class NonterminalSymbolType >
struct stringApi < grammar::GNF < TerminalSymbolType, NonterminalSymbolType > > {
	static grammar::GNF < TerminalSymbolType, NonterminalSymbolType > parse ( std::istream & input );
	static bool first ( std::istream & input );
	static void compose ( std::ostream & output, const grammar::GNF < TerminalSymbolType, NonterminalSymbolType > & grammar );
};

template < class TerminalSymbolType, class NonterminalSymbolType >
grammar::GNF < TerminalSymbolType, NonterminalSymbolType > stringApi < grammar::GNF < TerminalSymbolType, NonterminalSymbolType > >::parse ( std::istream & input ) {
	grammar::GrammarFromStringLexer::Token token = grammar::GrammarFromStringLexer::next(input);
	if(token.type != grammar::GrammarFromStringLexer::TokenType::GNF)
		throw exception::CommonException("Unrecognised GNF token.");

	grammar::GNF < TerminalSymbolType, NonterminalSymbolType > grammar = grammar::GrammarFromStringParserCommon::parseCFLikeGrammar < grammar::GNF < TerminalSymbolType, NonterminalSymbolType > > ( input );

	if ( ! grammar::properties::IsFITDefinition::isFITDefinition ( grammar ) )
		throw exception::CommonException("Init on RHS when generate eps");

	return grammar;
}

template < class TerminalSymbolType, class NonterminalSymbolType >
bool stringApi < grammar::GNF < TerminalSymbolType, NonterminalSymbolType > >::first ( std::istream & input ) {
	grammar::GrammarFromStringLexer::Token token = grammar::GrammarFromStringLexer::next ( input );
	bool res = token.type == grammar::GrammarFromStringLexer::TokenType::GNF;
	grammar::GrammarFromStringLexer::putback ( input, token );
	return res;
}

template < class TerminalSymbolType, class NonterminalSymbolType >
void stringApi < grammar::GNF < TerminalSymbolType, NonterminalSymbolType > >::compose ( std::ostream & output, const grammar::GNF < TerminalSymbolType, NonterminalSymbolType > & grammar ) {
	output << "GNF";
	grammar::GrammarToStringComposerCommon::composeCFLikeGrammar ( output, grammar::simplify::MakeFITDefinition::makeFITDefinition ( grammar ) );
}

} /* namespace core */

#endif /* _STRING_GNF_H_ */
