<commit_before>#include <chi/Context.hpp>
#include <chi/GraphModule.hpp>
#include <chi/JsonSerializer.hpp>
#include <chi/Support/Result.hpp>
#include <chi/Support/Subprocess.hpp>

#include <boost/filesystem.hpp>

#include <llvm/ADT/STLExtras.h>
#include <llvm/IR/Argument.h>
#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Type.h>
#include <llvm/IRReader/IRReader.h>
#include <llvm/Support/Casting.h>
#include <llvm/Support/ManagedStatic.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/raw_ostream.h>

using namespace chi;
using namespace nlohmann;

namespace fs = boost::filesystem;

const char* exesuffix =
#ifdef WIN32
    "exe"
#else
    ""
#endif
    ;

std::string areArrayEqualUnordered(json lhs, json rhs) {
	std::vector<json> objects;

	for (auto& obj : lhs) { objects.push_back(obj); }

	for (auto& obj : rhs) {
		auto iter = std::find(objects.begin(), objects.end(), obj);

		if (iter == objects.end()) return "object: " + obj.dump(2) + " not in serialized";

		objects.erase(iter);
	}

	if (!objects.empty()) {
		std::string errstring = "objects in lhs that aren't in original: \n\n";
		for (auto obj : objects) {
			errstring += obj.dump(2);
			errstring += "\n\n";
		}
		return errstring;
	}

	return "";
}

std::string areJsonEqual(json lhs, json rhs) {
	std::string errstring;

	errstring = areArrayEqualUnordered(lhs["dependencies"], rhs["dependencies"]);
	if (!errstring.empty()) return "dependencies not equal: " + errstring;

	if (lhs["has_c_support"] != rhs["has_c_support"]) {
		return "has_c_support doesn't match: serialized: " + lhs["has_c_support"].dump(-1) +
		       " original: " + rhs["has_c_support"].dump(-1);
	}

	auto& lgraphs = lhs["graphs"];
	auto& rgraphs = rhs["graphs"];

	if (lgraphs.size() != rgraphs.size()) return "different number of graphs";

	for (size_t iter = 0; iter != lgraphs.size(); ++iter) {
		auto& lgraph = lgraphs[0];
		auto& rgraph = rgraphs[0];

		errstring = areArrayEqualUnordered(lgraph["connections"], rgraph["connections"]);
		if (!errstring.empty())
			return "connections not equal in graph #" + std::to_string(iter) + " " + errstring;

		if (lgraph["name"] != rgraph["name"]) {
			return "graph name in graph #" + std::to_string(iter) +
			       " not equal; serialized: " + lgraph["name"].dump(-1) +
			       "  original: " + rgraph["name"].dump(-1);
		}
		if (lgraph["description"] != rgraph["description"]) {
			return "graph description in graph #" + std::to_string(iter) +
			       " not equal; serialized: " + lgraph["description"].dump(-1) +
			       "  original: " + rgraph["description"].dump(-1);
		}
		// compare nodes
		for (auto nodeIter = lgraph["nodes"].begin(); nodeIter != lgraph["nodes"].end();
		     ++nodeIter) {
			auto& lnode = nodeIter.value();
			auto& rnode = rgraph["nodes"][nodeIter.key()];
			if (std::abs(float(lnode["location"][0]) - float(rnode["location"][0])) >= .00001) {
				return "node with id: " + nodeIter.key() + " in graph #" + std::to_string(iter) +
				       " has a non-matching x location. Original: " +
				       std::to_string(float(lnode["location"][0])) +
				       " Serialized: " + std::to_string(float(rnode["location"][0]));
			}

			if (std::abs(float(lnode["location"][1]) - float(rnode["location"][1])) >= .00001) {
				return "node with id: " + nodeIter.key() + " in graph #" + std::to_string(iter) +
				       " has a non-matching y location. Original: " +
				       std::to_string(float(lnode["location"][1])) +
				       " Serialized: " + std::to_string(float(rnode["location"][1]));
			}

			if (lnode["data"].dump(-1) != rnode["data"].dump(-1)) {
				return "node with id: " + nodeIter.key() + " in graph #" + std::to_string(iter) +
				       " have non-matching data. Original: \n\n" + rnode["data"].dump(-1) +
				       "\n\nSerialized: \n\n" + lnode["data"].dump(-1);
			}

			if (lnode["type"] != rnode["type"]) {
				return "node with id: " + nodeIter.key() + " in graph #" + std::to_string(iter) +
				       " have non-matching types. Original: \n\n" + rnode["type"].dump(-1) +
				       "\n\nSerialized: \n\n" + lnode["type"].dump(-1);
			}
		}
		if (lgraph["type"] != rgraph["type"]) {
			return "graph name in graph #" + std::to_string(iter) +
			       "not equal; serialized: " + lgraph["type"].dump(-1) +
			       "  original: " + rgraph["type"].dump(-1);
		}
		if (lgraph["data_inputs"] != rgraph["data_inputs"]) {
			return "graph data inputs in graph #" + std::to_string(iter) +
			       "not equal; serialized: " + lgraph["inputs"].dump(-1) +
			       "  original: " + rgraph["inputs"].dump(-1);
		}
		if (lgraph["data_outputs"] != rgraph["data_outputs"]) {
			return "graph data outputs in graph #" + std::to_string(iter) +
			       "not equal; serialized: " + lgraph["outputs"].dump(-1) +
			       "  original: " + rgraph["outputs"].dump(-1);
		}
		if (lgraph["exec_inputs"] != rgraph["exec_inputs"]) {
			return "graph exec inputs in graph #" + std::to_string(iter) +
			       "not equal; serialized: " + lgraph["inputs"].dump(-1) +
			       "  original: " + rgraph["inputs"].dump(-1);
		}
		if (lgraph["exec_outputs"] != rgraph["exec_outputs"]) {
			return "graph exec outputs in graph #" + std::to_string(iter) +
			       "not equal; serialized: " + lgraph["outputs"].dump(-1) +
			       "  original: " + rgraph["outputs"].dump(-1);
		}
		if (lgraph["local_variables"] != rgraph["local_variables"]) {
			return "graph local_variables in graph #" + std::to_string(iter) +
			       "not equal; serialized: " + lgraph["local_variables"].dump(-1) +
			       " original: " + rgraph["local_variables"].dump(-1);
		}
	}

	return "";
}

int main(int argc, char** argv) {
	if (argc != 2) {
		std::cerr << "Usage: codegen_tester <path to module>" << std::endl;
		return 1;
	}

	fs::path moduleDir = argv[1];
	if (!fs::is_directory(moduleDir)) {
		std::cerr << moduleDir << " is not a directory" << std::endl;
		return 1;
	}
	std::string testName = moduleDir.filename().string();

	fs::path JSONfile = moduleDir / (testName + ".json");
	// load the file

	if (!fs::is_regular_file(JSONfile)) {
		std::cerr << JSONfile << " doesn't exist" << std::endl;
		return 1;
	}

	fs::ifstream jsonstream{JSONfile};

	json j;

	// parse the JSON
	try {
		jsonstream >> j;
	} catch (std::exception& e) {
		std::cerr << "Error parsing file " << JSONfile << " " << e.what() << std::endl;<commit_msg>Add debug printing<commit_after>#include <chi/Context.hpp>
#include <chi/GraphModule.hpp>
#include <chi/JsonSerializer.hpp>
#include <chi/Support/Result.hpp>
#include <chi/Support/Subprocess.hpp>
#include <chi/Support/LibCLocator.hpp>

#include <boost/filesystem.hpp>

#include <llvm/ADT/STLExtras.h>
#include <llvm/IR/Argument.h>
#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Type.h>
#include <llvm/IRReader/IRReader.h>
#include <llvm/Support/Casting.h>
#include <llvm/Support/ManagedStatic.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/raw_ostream.h>

using namespace chi;
using namespace nlohmann;

namespace fs = boost::filesystem;

const char* exesuffix =
#ifdef WIN32
    "exe"
#else
    ""
#endif
    ;

std::string areArrayEqualUnordered(json lhs, json rhs) {
	std::vector<json> objects;

	for (auto& obj : lhs) { objects.push_back(obj); }

	for (auto& obj : rhs) {
		auto iter = std::find(objects.begin(), objects.end(), obj);

		if (iter == objects.end()) return "object: " + obj.dump(2) + " not in serialized";

		objects.erase(iter);
	}

	if (!objects.empty()) {
		std::string errstring = "objects in lhs that aren't in original: \n\n";
		for (auto obj : objects) {
			errstring += obj.dump(2);
			errstring += "\n\n";
		}
		return errstring;
	}

	return "";
}

std::string areJsonEqual(json lhs, json rhs) {
	std::string errstring;

	errstring = areArrayEqualUnordered(lhs["dependencies"], rhs["dependencies"]);
	if (!errstring.empty()) return "dependencies not equal: " + errstring;

	if (lhs["has_c_support"] != rhs["has_c_support"]) {
		return "has_c_support doesn't match: serialized: " + lhs["has_c_support"].dump(-1) +
		       " original: " + rhs["has_c_support"].dump(-1);
	}

	auto& lgraphs = lhs["graphs"];
	auto& rgraphs = rhs["graphs"];

	if (lgraphs.size() != rgraphs.size()) return "different number of graphs";

	for (size_t iter = 0; iter != lgraphs.size(); ++iter) {
		auto& lgraph = lgraphs[0];
		auto& rgraph = rgraphs[0];

		errstring = areArrayEqualUnordered(lgraph["connections"], rgraph["connections"]);
		if (!errstring.empty())
			return "connections not equal in graph #" + std::to_string(iter) + " " + errstring;

		if (lgraph["name"] != rgraph["name"]) {
			return "graph name in graph #" + std::to_string(iter) +
			       " not equal; serialized: " + lgraph["name"].dump(-1) +
			       "  original: " + rgraph["name"].dump(-1);
		}
		if (lgraph["description"] != rgraph["description"]) {
			return "graph description in graph #" + std::to_string(iter) +
			       " not equal; serialized: " + lgraph["description"].dump(-1) +
			       "  original: " + rgraph["description"].dump(-1);
		}
		// compare nodes
		for (auto nodeIter = lgraph["nodes"].begin(); nodeIter != lgraph["nodes"].end();
		     ++nodeIter) {
			auto& lnode = nodeIter.value();
			auto& rnode = rgraph["nodes"][nodeIter.key()];
			if (std::abs(float(lnode["location"][0]) - float(rnode["location"][0])) >= .00001) {
				return "node with id: " + nodeIter.key() + " in graph #" + std::to_string(iter) +
				       " has a non-matching x location. Original: " +
				       std::to_string(float(lnode["location"][0])) +
				       " Serialized: " + std::to_string(float(rnode["location"][0]));
			}

			if (std::abs(float(lnode["location"][1]) - float(rnode["location"][1])) >= .00001) {
				return "node with id: " + nodeIter.key() + " in graph #" + std::to_string(iter) +
				       " has a non-matching y location. Original: " +
				       std::to_string(float(lnode["location"][1])) +
				       " Serialized: " + std::to_string(float(rnode["location"][1]));
			}

			if (lnode["data"].dump(-1) != rnode["data"].dump(-1)) {
				return "node with id: " + nodeIter.key() + " in graph #" + std::to_string(iter) +
				       " have non-matching data. Original: \n\n" + rnode["data"].dump(-1) +
				       "\n\nSerialized: \n\n" + lnode["data"].dump(-1);
			}

			if (lnode["type"] != rnode["type"]) {
				return "node with id: " + nodeIter.key() + " in graph #" + std::to_string(iter) +
				       " have non-matching types. Original: \n\n" + rnode["type"].dump(-1) +
				       "\n\nSerialized: \n\n" + lnode["type"].dump(-1);
			}
		}
		if (lgraph["type"] != rgraph["type"]) {
			return "graph name in graph #" + std::to_string(iter) +
			       "not equal; serialized: " + lgraph["type"].dump(-1) +
			       "  original: " + rgraph["type"].dump(-1);
		}
		if (lgraph["data_inputs"] != rgraph["data_inputs"]) {
			return "graph data inputs in graph #" + std::to_string(iter) +
			       "not equal; serialized: " + lgraph["inputs"].dump(-1) +
			       "  original: " + rgraph["inputs"].dump(-1);
		}
		if (lgraph["data_outputs"] != rgraph["data_outputs"]) {
			return "graph data outputs in graph #" + std::to_string(iter) +
			       "not equal; serialized: " + lgraph["outputs"].dump(-1) +
			       "  original: " + rgraph["outputs"].dump(-1);
		}
		if (lgraph["exec_inputs"] != rgraph["exec_inputs"]) {
			return "graph exec inputs in graph #" + std::to_string(iter) +
			       "not equal; serialized: " + lgraph["inputs"].dump(-1) +
			       "  original: " + rgraph["inputs"].dump(-1);
		}
		if (lgraph["exec_outputs"] != rgraph["exec_outputs"]) {
			return "graph exec outputs in graph #" + std::to_string(iter) +
			       "not equal; serialized: " + lgraph["outputs"].dump(-1) +
			       "  original: " + rgraph["outputs"].dump(-1);
		}
		if (lgraph["local_variables"] != rgraph["local_variables"]) {
			return "graph local_variables in graph #" + std::to_string(iter) +
			       "not equal; serialized: " + lgraph["local_variables"].dump(-1) +
			       " original: " + rgraph["local_variables"].dump(-1);
		}
	}

	return "";
}

int main(int argc, char** argv) {
	if (argc != 2) {
		std::cerr << "Usage: codegen_tester <path to module>" << std::endl;
		return 1;
	}

	fs::path moduleDir = argv[1];
	if (!fs::is_directory(moduleDir)) {
		std::cerr << moduleDir << " is not a directory" << std::endl;
		return 1;
	}
	std::string testName = moduleDir.filename().string();

	fs::path JSONfile = moduleDir / (testName + ".json");
	// load the file

	if (!fs::is_regular_file(JSONfile)) {
		std::cerr << JSONfile << " doesn't exist" << std::endl;
		return 1;
	}
	
	// print the C include paths for debugging
	std::vector<fs::path> paths;
    stdCIncludePaths(paths);
    
    std::cout << "Standard C include paths: " << std::endl;
    for (const auto& p : paths) {
      std::cout << p.string() << std::endl;
    }
    std::cout << std::endl;

	fs::ifstream jsonstream{JSONfile};

	json j;

	// parse the JSON
	try {
		jsonstream >> j;
	} catch (std::exception& e) {
		std::cerr << "Error parsing file " << JSONfile << " " << e.what() << std::endl;
{'fraction_non_alphanumeric': 0.19677324296449095, 'fraction_numerical': 0.007956387210844261, 'mean_word_length': 3.5830519918973667, 'pattern_counts': {'":': 0, '<': 117, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6935692', 'n_tokens_mistral': 5192, 'n_tokens_neox': 4671, 'n_words': 985}