include "primitives.alh"
include "constructors.alh"
include "conformance_scd.alh"

Void function compilation_manager():
	String operation
	String object_name
	Element root
	Element mv_root
	Element node

	mv_root = read_root()
	root = mv_root["__hierarchy"]["objects"]

	operation = input()
	if (operation == "upload"):
		object_name = input()
		node = create_node()
		dict_add(node, "hash_md5", input())
		if (input()):
			dict_add(node, "initializers", construct_top())
		else:
			dict_add(node, "initializers", deserialize(input()))

		Element symbols
		symbols = create_node()
		dict_add(node, "symbols", symbols)
		while (input()):
			dict_add(symbols, input(), input())

		if (dict_in(root, object_name)):
			// Already exists, so remove first
			dict_delete(root, object_name)
		dict_add(root, object_name, node)
	elif (operation == "read_initializers"):
		node = root[input()]["initializers"]
		output(node)
	elif (operation == "link_and_load"):
		Element objs
		String obj

		objs = create_node()
		obj = input()
		while (obj != ""):
			if (dict_in(root, obj)):
				set_add(objs, obj)
			else:
				log("ERROR: couldn't find obj " + obj)
			obj = input()

		link_and_load(root, input(), objs)
	elif (operation == "is_defined"):
		object_name = input()
		if (dict_in(root, object_name)):
			output(root[object_name]["hash_md5"])
		else:
			output(create_node())
	else:
		log("Failed to understand command")

	return!

String function check_symbols(root : Element, main_function : String, objs : Element):
	Element symbols
	String obj
	Element keys
	String key
	Element copy_objs

	// We always need a main variable
	symbols = create_node()
	dict_add(symbols, main_function, False)

	// Resolve all symbols
	copy_objs = set_copy(objs)
	while (0 < list_len(copy_objs)):
		obj = set_pop(copy_objs)
		keys = dict_keys(root[obj]["symbols"])
		while (0 < list_len(keys)):
			key = set_pop(keys)

			if (root[obj]["symbols"][key]):
				// Defines
				if (bool_not(dict_in(symbols, key))):
					// Not yet in dictionary
					dict_add(symbols, key, True)
				elif (symbols[key]):
					// Already in dictionary, and it was already defined
					return "ERROR: multiple definition of symbol " + key!
				else:
					// Already in dictionary, but only used
					dict_delete(symbols, key)
					dict_add(symbols, key, True)
			else:
				// Uses
				if (bool_not(dict_in(symbols, key))):
					dict_add(symbols, key, False)

	// Check whether we have everything
	keys = dict_keys(symbols)
	while (0 < list_len(keys)):
		key = set_pop(keys)
		if (bool_not(symbols[key])):
			if (bool_not(bool_or(key == "output", key == "input"))):
				return "ERROR: undefined symbol " + key!

	return "OK"!

Void function link_and_load(root : Element, main_function : String, objs : Element):
	String obj
	Element func
	Element main_f
	String result

	result = check_symbols(root, main_function, objs)
	output(result)

	if (result == "OK"):
		// Symbols verified OK, start execution
		// Call all initializers in turn
		while (0 < list_len(objs)):
			obj = set_pop(objs)
			func = root[obj]["initializers"]
			exec(func)

		// Resolve the main function, which should now be in (global) scope, and execute it
		main_f = resolve(main_function)
		main_f()
	return!
