/*----------------------------------------------------------------------
Compiler Generator Coco/R,
Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
extended by M. Loeberbauer & A. Woess, Univ. of Linz
ported to C++ by Csaba Balazs, University of Szeged
with improvements by Pat Terry, Rhodes University

This program is free software; you can redistribute it and/or modify it 
under the terms of the GNU General Public License as published by the 
Free Software Foundation; either version 2, or (at your option) any 
later version.

This program is distributed in the hope that it will be useful, but 
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
for more details.

You should have received a copy of the GNU General Public License along 
with this program; if not, write to the Free Software Foundation, Inc., 
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

As an exception, it is allowed to write an extension of Coco/R that is
used as a plugin in non-free software.

If not otherwise stated, any source code generated by Coco/R (other than 
Coco/R itself) does not fall under the GNU General Public License.
-----------------------------------------------------------------------*/


#include <wchar.h>
#include "Parser.h"
#include "Scanner.h"




void Parser::SynErr(int n) {
	if (errDist >= minErrDist) errors->SynErr(la->line, la->col, n);
	errDist = 0;
}

void Parser::SemErr(const wchar_t* msg) {
	if (errDist >= minErrDist) errors->Error(t->line, t->col, msg);
	errDist = 0;
}

void Parser::Get() {
	for (;;) {
		t = la;
		la = scanner->Scan();
		if (la->kind <= maxT) { ++errDist; break; }

		if (dummyToken != t) {
			dummyToken->kind = t->kind;
			dummyToken->pos = t->pos;
			dummyToken->col = t->col;
			dummyToken->line = t->line;
			dummyToken->next = NULL;
			coco_string_delete(dummyToken->val);
			dummyToken->val = coco_string_create(t->val);
			t = dummyToken;
		}
		la = t;
	}
}

void Parser::Expect(int n) {
	if (la->kind==n) Get(); else { SynErr(n); }
}

void Parser::ExpectWeak(int n, int follow) {
	if (la->kind == n) Get();
	else {
		SynErr(n);
		while (!StartOf(follow)) Get();
	}
}

bool Parser::WeakSeparator(int n, int syFol, int repFol) {
	if (la->kind == n) {Get(); return true;}
	else if (StartOf(repFol)) {return false;}
	else {
		SynErr(n);
		while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) {
			Get();
		}
		return StartOf(syFol);
	}
}

void Parser::Xreate() {
		while (la->kind == _ident || la->kind == 26 /* "rule" */) {
			if (la->kind == _ident) {
				FDecl();
			} else {
				RuleDecl();
			}
		}
}

void Parser::FDecl() {
		std::wstring fname; std::wstring varname; TypeAnnotation typIn; TypeAnnotation typOut; 
		Ident(fname);
		Expect(_assign);
		Expect(10 /* "function" */);
		Expect(11 /* ":" */);
		Function f = Function(fname); 
		if (StartOf(1)) {
			Type(typOut);
			f.setReturnType(typOut); 
		} else if (la->kind == _lparen) {
			Get();
			if (la->kind == _ident) {
				Ident(varname);
				Expect(11 /* ":" */);
				Type(typIn);
				f.addArg(std::move(varname), move(typIn)); 
				while (la->kind == 12 /* "," */) {
					Get();
					Ident(varname);
					Expect(11 /* ":" */);
					Type(typIn);
					f.addArg(std::move(varname), move(typIn));
				}
			}
			Expect(_rparen);
			Expect(_implic);
			Type(typOut);
			f.setReturnType(typOut); 
			while (la->kind == 12 /* "," */) {
				Get();
				FnTag(f);
			}
		} else SynErr(37);
		BDecl(f.getEntryScope());
		root.add(f); 
}

void Parser::RuleDecl() {
		Expect(26 /* "rule" */);
		Expect(11 /* ":" */);
		RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; 
		Expect(_lparen);
		Ident(arg);
		Expect(11 /* ":" */);
		Domain(typ);
		args.add(arg, typ); 
		while (la->kind == 12 /* "," */) {
			Get();
			Ident(arg);
			Expect(11 /* ":" */);
			Domain(typ);
			args.add(arg, typ); 
		}
		Expect(_rparen);
		if (la->kind == 27 /* "case" */) {
			Get();
			RGuard(guards);
			while (la->kind == 12 /* "," */) {
				Get();
				RGuard(guards);
			}
		}
		Expect(19 /* "{" */);
		RBody(args, guards);
		Expect(20 /* "}" */);
}

void Parser::Ident(std::wstring& name) {
		Expect(_ident);
		name = t->val; 
}

void Parser::Type(TypeAnnotation& typ) {
		TypeAnnotation typ2; TypeAtom typ3; 
		if (la->kind == _lbrack) {
			Get();
			Type(typ2);
			Expect(_rbrack);
			typ = TypeAnnotation(TypeOperator::LIST, {typ2}); 
		} else if (StartOf(2)) {
			TypeTerm(typ3);
			typ = TypeAnnotation(typ3); 
		} else SynErr(38);
}

void Parser::FnTag(Function& f) {
		Expression tag; TagModifier mod = TagModifier::NONE; 
		MetaSimpExpr(tag);
		if (la->kind == 23 /* "-" */) {
			Get();
			TagMod(mod);
		}
		f.addTag(std::move(tag), mod); 
}

void Parser::BDecl(CodeScope& scope) {
		Expression body; 
		Expect(19 /* "{" */);
		while (StartOf(3)) {
			if (checkAssignment()) {
				VDecl(scope);
				Expect(18 /* ";" */);
			} else if (la->kind == 11 /* ":" */) {
				TagsDecl(scope);
				Expect(18 /* ";" */);
			} else {
				Expr(body);
				Expect(18 /* ";" */);
				scope.setBody(body); 
			}
		}
		Expect(20 /* "}" */);
}

void Parser::TypeTerm(TypeAtom& typ) {
		if (la->kind == 13 /* "string" */) {
			Get();
		} else if (la->kind == 14 /* "int" */) {
			Get();
		} else if (la->kind == 15 /* "num" */) {
			Get();
		} else if (la->kind == 16 /* "float" */) {
			Get();
		} else if (la->kind == 17 /* "bool" */) {
			Get();
		} else SynErr(39);
		typ = Atom<Type_t>(t->val); 
}

void Parser::VDecl(CodeScope& f) {
		std::wstring vname; Expression e; TypeAnnotation typ;  
		Ident(vname);
		Expect(_assign);
		if (la->kind == _lbrack) {
			ListLiteral(e);
			Expect(11 /* ":" */);
			Type(typ);
		} else if (la->kind == 21 /* "loop" */) {
			LoopDecl(e, typ);
			Expect(18 /* ";" */);
		} else if (StartOf(4)) {
			Expr(e);
			Expect(11 /* ":" */);
			Type(typ);
		} else SynErr(40);
		f.addDeclaration(move(vname), move(typ), move(e)); 
}

void Parser::ListLiteral(Expression& e) {
		Expression e2; 
		Expect(_lbrack);
		e.setOp(Operator::LIST); 
		if (StartOf(4)) {
			Expr(e2);
			e.addArg(std::move(e2)); 
			while (la->kind == 12 /* "," */) {
				Get();
				Expr(e2);
				e.addArg(std::move(e2)); 
			}
		}
		Expect(_rbrack);
}

void Parser::LoopDecl(Expression& e, TypeAnnotation& typOut) {
		std::wstring varIn, varEl; TypeAnnotation typEl; CodeScope block; 
		Expect(21 /* "loop" */);
		Expect(22 /* "map" */);
		Expect(_lparen);
		Ident(varIn);
		Expect(_implic);
		Ident(varEl);
		Expect(11 /* ":" */);
		Type(typEl);
		Expect(_rparen);
		Expect(11 /* ":" */);
		Type(typOut);
		BDecl(block);
		e = Expression(Operator::LOOP, {Expression(Atom<Identifier_t>(varIn))}); e.addBindings({Atom<Identifier_t>(varEl)});
		block.addArg(Atom<Identifier_t>(varEl), move(typEl)); e.addBlock(move(block)); 
}

void Parser::Expr(Expression& e) {
		Operator op; Expression e2; 
		SimExpr(e);
		if (la->kind == _assign || la->kind == 34 /* "<" */ || la->kind == 35 /* ">" */) {
			RelOp(op);
			SimExpr(e2);
			e = Expression(op, {e, e2});  
		}
}

void Parser::TagsDecl(CodeScope& f) {
		Expression tag; TagModifier mod = TagModifier::NONE; 
		Expect(11 /* ":" */);
		while (la->kind == _ident || la->kind == 23 /* "-" */) {
			MetaSimpExpr(tag);
			if (la->kind == 23 /* "-" */) {
				Get();
				TagMod(mod);
			}
			
		}
}

void Parser::MetaSimpExpr(Expression& e) {
		std::wstring i1, infix; Expression e2; 
		if (la->kind == 23 /* "-" */) {
			Get();
			MetaSimpExpr(e2);
			e = Expression(Operator::NEG, {e2}); 
		} else if (checkParametersList()) {
			Ident(i1);
			e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(i1))}); 
			Expect(_lparen);
			if (StartOf(4)) {
				CalleeParams(e);
			}
			Expect(_rparen);
		} else if (checkInfix()) {
			Ident(i1);
			Ident(infix);
			MetaSimpExpr(e2);
			e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(infix))});
			e.addArg(Expression(Atom<Identifier_t>(i1)));
			e.addArg(std::move(e2));
			
		} else if (la->kind == _ident) {
			Ident(i1);
			e = Expression(Atom<Identifier_t>(i1)); 
		} else SynErr(41);
}

void Parser::TagMod(TagModifier& mod) {
		if (la->kind == 24 /* "assert" */) {
			Get();
			mod = TagModifier::ASSERT; 
		} else if (la->kind == 25 /* "require" */) {
			Get();
			mod = TagModifier::REQUIRE; 
		} else SynErr(42);
}

void Parser::Domain(DomainAnnotation& dom) {
		if (la->kind == 10 /* "function" */) {
			Get();
			dom = DomainAnnotation::FUNCTION; 
		} else if (la->kind == 28 /* "variable" */) {
			Get();
			dom = DomainAnnotation::VARIABLE; 
		} else SynErr(43);
}

void Parser::RGuard(RuleGuards& guards) {
		Expression e; 
		MetaExpr(e);
		guards.add(std::move(e)); 
}

void Parser::RBody(const RuleArguments& args, const RuleGuards& guards) {
		Expression e; std::wstring msg; 
		Expect(29 /* "warning" */);
		MetaExpr(e);
		if (la->kind == 30 /* "message" */) {
			Get();
			Expect(_string);
			msg = t->val; 
		}
		root.add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom<String_t>(msg))); 
}

void Parser::MetaExpr(Expression& e) {
		Operator op; Expression e2; 
		MetaExpr2(e);
		if (la->kind == _implic) {
			MetaOp(op);
			MetaExpr2(e2);
			e = Expression(op, {e, e2}); 
		}
}

void Parser::MetaExpr2(Expression& e) {
		if (la->kind == _lparen) {
			Get();
			MetaExpr(e);
			Expect(_rparen);
		} else if (la->kind == _ident || la->kind == 23 /* "-" */) {
			MetaSimpExpr(e);
		} else SynErr(44);
}

void Parser::MetaOp(Operator& op) {
		Expect(_implic);
		op = Operator::IMPL; 
}

void Parser::CalleeParams(Expression& e) {
		Expression e2; 
		Expr(e2);
		e.addArg(std::move(e2)); 
		while (la->kind == 12 /* "," */) {
			Get();
			Expr(e2);
			e.addArg(std::move(e2)); 
		}
}

void Parser::SimExpr(Expression& e) {
		Operator op; Expression e2; 
		Term(e);
		while (la->kind == 23 /* "-" */ || la->kind == 31 /* "+" */) {
			AddOp(op);
			Term(e2);
			e = Expression(op, {e, e2});
		}
}

void Parser::RelOp(Operator& op) {
		op = Operator::EQU; 
		if (la->kind == _assign) {
			Get();
			Expect(_assign);
		} else if (la->kind == 34 /* "<" */) {
			Get();
			op = Operator::LSS; 
		} else if (la->kind == 35 /* ">" */) {
			Get();
			op = Operator::GTR; 
		} else SynErr(45);
}

void Parser::Term(Expression& e) {
		Operator op; Expression e2; 
		Factor(e);
		while (la->kind == 32 /* "*" */ || la->kind == 33 /* "/" */) {
			MulOp(op);
			Factor(e2);
			e = Expression(op, {e, e2}); 
		}
}

void Parser::AddOp(Operator& op) {
		op = Operator::ADD; 
		if (la->kind == 31 /* "+" */) {
			Get();
		} else if (la->kind == 23 /* "-" */) {
			Get();
			op = Operator::SUB; 
		} else SynErr(46);
}

void Parser::Factor(Expression& e) {
		std::wstring name;
		if (checkParametersList()) {
			Ident(name);
			e = Expression(Operator::CALL, {Atom<Identifier_t>(name)}); 
			Expect(_lparen);
			if (StartOf(4)) {
				CalleeParams(e);
			}
			Expect(_rparen);
		} else if (checkIndex()) {
			Ident(name);
			e = Expression(Operator::INDEX, {Atom<Identifier_t>(name)}); 
			Expect(_lbrack);
			CalleeParams(e);
			Expect(_rbrack);
		} else if (la->kind == _ident) {
			Ident(name);
			e = Expression(Atom<Identifier_t>(name)); 
		} else if (la->kind == _number) {
			Get();
			e = Expression(Atom<Number_t>(t->val)); 
		} else if (la->kind == 23 /* "-" */) {
			Get();
			Factor(e);
			e = Expression(Operator::NEG, {e}); 
		} else if (la->kind == _lparen) {
			Get();
			Expr(e);
			Expect(_rparen);
		} else SynErr(47);
}

void Parser::MulOp(Operator& op) {
		op = Operator::MUL; 
		if (la->kind == 32 /* "*" */) {
			Get();
		} else if (la->kind == 33 /* "/" */) {
			Get();
			op = Operator::DIV; 
		} else SynErr(48);
}




// If the user declared a method Init and a mehtod Destroy they should
// be called in the contructur and the destructor respctively.
//
// The following templates are used to recognize if the user declared
// the methods Init and Destroy.

template<typename T>
struct ParserInitExistsRecognizer {
	template<typename U, void (U::*)() = &U::Init>
	struct ExistsIfInitIsDefinedMarker{};

	struct InitIsMissingType {
		char dummy1;
	};
	
	struct InitExistsType {
		char dummy1; char dummy2;
	};

	// exists always
	template<typename U>
	static InitIsMissingType is_here(...);

	// exist only if ExistsIfInitIsDefinedMarker is defined
	template<typename U>
	static InitExistsType is_here(ExistsIfInitIsDefinedMarker<U>*);

	enum { InitExists = (sizeof(is_here<T>(NULL)) == sizeof(InitExistsType)) };
};

template<typename T>
struct ParserDestroyExistsRecognizer {
	template<typename U, void (U::*)() = &U::Destroy>
	struct ExistsIfDestroyIsDefinedMarker{};

	struct DestroyIsMissingType {
		char dummy1;
	};
	
	struct DestroyExistsType {
		char dummy1; char dummy2;
	};

	// exists always
	template<typename U>
	static DestroyIsMissingType is_here(...);

	// exist only if ExistsIfDestroyIsDefinedMarker is defined
	template<typename U>
	static DestroyExistsType is_here(ExistsIfDestroyIsDefinedMarker<U>*);

	enum { DestroyExists = (sizeof(is_here<T>(NULL)) == sizeof(DestroyExistsType)) };
};

// The folloing templates are used to call the Init and Destroy methods if they exist.

// Generic case of the ParserInitCaller, gets used if the Init method is missing
template<typename T, bool = ParserInitExistsRecognizer<T>::InitExists>
struct ParserInitCaller {
	static void CallInit(T *t) {
		// nothing to do
	}
};

// True case of the ParserInitCaller, gets used if the Init method exists
template<typename T>
struct ParserInitCaller<T, true> {
	static void CallInit(T *t) {
		t->Init();
	}
};

// Generic case of the ParserDestroyCaller, gets used if the Destroy method is missing
template<typename T, bool = ParserDestroyExistsRecognizer<T>::DestroyExists>
struct ParserDestroyCaller {
	static void CallDestroy(T *t) {
		// nothing to do
	}
};

// True case of the ParserDestroyCaller, gets used if the Destroy method exists
template<typename T>
struct ParserDestroyCaller<T, true> {
	static void CallDestroy(T *t) {
		t->Destroy();
	}
};

void Parser::Parse() {
	t = NULL;
	la = dummyToken = new Token();
	la->val = coco_string_create(L"Dummy Token");
	Get();
	Xreate();
	Expect(0);
}

Parser::Parser(Scanner *scanner) {
	maxT = 36;

	ParserInitCaller<Parser>::CallInit(this);
	dummyToken = NULL;
	t = la = NULL;
	minErrDist = 2;
	errDist = minErrDist;
	this->scanner = scanner;
	errors = new Errors();
}

bool Parser::StartOf(int s) {
	const bool T = true;
	const bool x = false;

	static bool set[5][38] = {
		{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,T,x, x,x,x,x, x,T,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,T,x, T,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,T,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x}
	};



	return set[s][la->kind];
}

Parser::~Parser() {
	ParserDestroyCaller<Parser>::CallDestroy(this);
	delete errors;
	delete dummyToken;
}

Errors::Errors() {
	count = 0;
}

void Errors::SynErr(int line, int col, int n) {
	wchar_t* s;
	switch (n) {
			case 0: s = coco_string_create(L"EOF expected"); break;
			case 1: s = coco_string_create(L"ident expected"); break;
			case 2: s = coco_string_create(L"number expected"); break;
			case 3: s = coco_string_create(L"string expected"); break;
			case 4: s = coco_string_create(L"lparen expected"); break;
			case 5: s = coco_string_create(L"rparen expected"); break;
			case 6: s = coco_string_create(L"lbrack expected"); break;
			case 7: s = coco_string_create(L"rbrack expected"); break;
			case 8: s = coco_string_create(L"assign expected"); break;
			case 9: s = coco_string_create(L"implic expected"); break;
			case 10: s = coco_string_create(L"\"function\" expected"); break;
			case 11: s = coco_string_create(L"\":\" expected"); break;
			case 12: s = coco_string_create(L"\",\" expected"); break;
			case 13: s = coco_string_create(L"\"string\" expected"); break;
			case 14: s = coco_string_create(L"\"int\" expected"); break;
			case 15: s = coco_string_create(L"\"num\" expected"); break;
			case 16: s = coco_string_create(L"\"float\" expected"); break;
			case 17: s = coco_string_create(L"\"bool\" expected"); break;
			case 18: s = coco_string_create(L"\";\" expected"); break;
			case 19: s = coco_string_create(L"\"{\" expected"); break;
			case 20: s = coco_string_create(L"\"}\" expected"); break;
			case 21: s = coco_string_create(L"\"loop\" expected"); break;
			case 22: s = coco_string_create(L"\"map\" expected"); break;
			case 23: s = coco_string_create(L"\"-\" expected"); break;
			case 24: s = coco_string_create(L"\"assert\" expected"); break;
			case 25: s = coco_string_create(L"\"require\" expected"); break;
			case 26: s = coco_string_create(L"\"rule\" expected"); break;
			case 27: s = coco_string_create(L"\"case\" expected"); break;
			case 28: s = coco_string_create(L"\"variable\" expected"); break;
			case 29: s = coco_string_create(L"\"warning\" expected"); break;
			case 30: s = coco_string_create(L"\"message\" expected"); break;
			case 31: s = coco_string_create(L"\"+\" expected"); break;
			case 32: s = coco_string_create(L"\"*\" expected"); break;
			case 33: s = coco_string_create(L"\"/\" expected"); break;
			case 34: s = coco_string_create(L"\"<\" expected"); break;
			case 35: s = coco_string_create(L"\">\" expected"); break;
			case 36: s = coco_string_create(L"??? expected"); break;
			case 37: s = coco_string_create(L"invalid FDecl"); break;
			case 38: s = coco_string_create(L"invalid Type"); break;
			case 39: s = coco_string_create(L"invalid TypeTerm"); break;
			case 40: s = coco_string_create(L"invalid VDecl"); break;
			case 41: s = coco_string_create(L"invalid MetaSimpExpr"); break;
			case 42: s = coco_string_create(L"invalid TagMod"); break;
			case 43: s = coco_string_create(L"invalid Domain"); break;
			case 44: s = coco_string_create(L"invalid MetaExpr2"); break;
			case 45: s = coco_string_create(L"invalid RelOp"); break;
			case 46: s = coco_string_create(L"invalid AddOp"); break;
			case 47: s = coco_string_create(L"invalid Factor"); break;
			case 48: s = coco_string_create(L"invalid MulOp"); break;

		default:
		{
			wchar_t format[20];
			coco_swprintf(format, 20, L"error %d", n);
			s = coco_string_create(format);
		}
		break;
	}
	wprintf(L"-- line %d col %d: %ls\n", line, col, s);
	coco_string_delete(s);
	count++;
}

void Errors::Error(int line, int col, const wchar_t *s) {
	wprintf(L"-- line %d col %d: %ls\n", line, col, s);
	count++;
}

void Errors::Warning(int line, int col, const wchar_t *s) {
	wprintf(L"-- line %d col %d: %ls\n", line, col, s);
}

void Errors::Warning(const wchar_t *s) {
	wprintf(L"%ls\n", s);
}

void Errors::Exception(const wchar_t* s) {
	wprintf(L"%ls", s); 
	exit(1);
}


