// pexl.cpp
// ````````

#define PX_INTERNAL_SOURCE
#include "px_internal.h"
#include "px_plexer.h"
#include "px_typechecker.h"
#include "px_compiler.h"

#include "platform.h"

void preprocessor_walk(token* t) {

	bool stashed = false;
	std::string stash;

	if (t->type == TOK_INCLUDE_STATEMENT) {
			
		std::string targetfile = t->children[1]->data;

		std::string child_body = file_get_contents(const_cast<char*>(targetfile.c_str())); // handles failure internally

		token* nested_file = parse_easy(TOK_BODY, child_body);

		// We can't replace TOK_INCLUDE_STATEMENT with a TOK_BODY, but a TOK_BLOCK can go in its place
		// This causes the behaviour that local variables are private to the included file.

		t->clear(TOK_BLOCK);
		t->children.push_back(new token(TOK_CBRACE_OPEN));
		t->children.push_back(nested_file); // TOK_BODY pointer copy
		t->children.push_back(new token(TOK_CBRACE_CLOSE));

		// Handled

		stash = get_working_directory();
		stashed = true;
		set_working_directory(dirname_from_path(targetfile).c_str()); // now future recursion will be cwd-relative
	}

	// Walk children
	for (size_t i = 0, e = t->children.size(); i != e; ++i) {
		preprocessor_walk(t->children[i]);
	}

	// Restore cwd
	if (stashed) {
		set_working_directory(stash.c_str()); // pop
	}

};

std::string pexl_compile(enum pexl_compile_targets type, std::string pexl_src, bool verbose, bool should_optimise) {

	if (! pexl_src.length()) {
		return "%fatal \"Zero-length input\"";
	}

	parse_initGrammar();

	switch(type) {

		case PEXL_X86_NASM: {
			token* ast = parse_easy( TOK_BODY, pexl_src );

			preprocessor_walk(ast);

			if (verbose) {
				fprintf(stderr, "--\n");
				pexl_pprint_ast(ast);
			}

			if (! typecheck(ast)) {
				delete ast;
				return "%fatal \"TypeError\"";
			}

			if (verbose) {
				fprintf(stderr, "--\n");
				pexl_pprint_ast(ast);
			}

			std::string strasm = compile_easy(ast, should_optimise);
			delete ast;
			return strasm;
		} break;

		default: {
			return "%fatal \"Unsupported compilation target\"\n";
		} break;

	};

}