#include "lexer.h"

#include "rapidcsv.h"
#include "algo.h"

enum{
//	LINE,
	JUMP,
	DESTINATION,
	ASSIGNMENT,
	OPR1,
	OPERATOR,
	OPR2,
	COMMENT
};

inline unsigned long long instruction_counter = 1;

void lex_file(const char* const f){
	rapidcsv::Document doc(f, rapidcsv::LabelParams(-1, -1),
								rapidcsv::SeparatorParams(';')
							);
	std::vector<std::string> buf;

	for(unsigned head = 1, end = doc.GetRowCount()+1; head < end; head++){
		#ifdef DEBUG
			printf(BOLD BLUE "%0#6llx" NORMAL "|", instruction_counter++);
			printf(BOLD "%s:%d: " NORMAL, f, head);
		#endif
		const std::string c = doc.GetCell<std::string>(0, head-1);
		if(c[0] == '"'){ // skip comments
			#ifdef DEBUG
				printf(GREEN "Comment: %s\n" NORMAL, c.c_str());
			#endif
			continue;
		}
		buf = doc.GetRow<std::string>(head-1);
		lex_row(buf, head);
	}
}

void lex_row(std::vector<std::string> &v, unsigned &head){
	/* --- MUST COMPUTE --- */
	algo::do_eval(v[OPR1], v[OPERATOR][0], v[OPR2]);
	/* --- */

	/* --- INSTRUCTION BREANCHING --- */
	/* Is jump*/
	if(v[JUMP][0] != algo::EMPTY_VAL){
		algo::jmp j;
		try{
			j = (algo::jmp)(stoi(v[JUMP]));
		}catch(...){
			puts(RED "Non sensical jump condition." NORMAL);
			return;
		}
		#ifdef DEBUG
			printf(MAGENTA "Jump condition %s (%s) %s %s (%s) with %d. " NORMAL,
					v[OPR1].c_str(),
					algo::deref(v[OPR1]).c_str(),
					v[OPERATOR].c_str(),
					algo::deref(v[OPR2]).c_str(),
					v[OPR2].c_str(),
					(int)j
				);
		#endif
		if(algo::jump(head, j, v[DESTINATION], v[ASSIGNMENT][0])){
			--head;
			#ifdef DEBUG
				puts(MAGENTA "Continueing." NORMAL);
			#endif
		}else{
			#ifdef DEBUG
				puts(MAGENTA "Falling through." NORMAL);
			#endif
		}
		return;
	}
	/* Is assignemt */
	if(v[ASSIGNMENT][0] != algo::EMPTY_VAL){
		algo::assign(algo::arref(v[DESTINATION]), algo::vars["eval"]);
		#ifdef DEBUG
			printf(CYAN "Assigned '%s' to '%s' (%s). (%s %s %s %c %s)\n" NORMAL,
						algo::vars["eval"].c_str(),
						v[DESTINATION].c_str(),
						algo::arref(v[DESTINATION]).c_str(),
						//
						v[DESTINATION].c_str(),
						v[ASSIGNMENT].c_str(),
						v[OPR1].c_str(),
						v[OPERATOR][0],
						v[OPR2].c_str());
		#endif
		return;
	}
	/* --- */
}
