Boolean function value_eq(a: Element, b: Element) = ?primitives/value_eq
Boolean function value_neq(a: Element, b: Element) = ?primitives/value_neq
Boolean function bool_and(a: Boolean, b: Boolean) = ?primitives/bool_and
Boolean function bool_or(a: Boolean, b: Boolean) = ?primitives/bool_or
Boolean function bool_not(a: Boolean) = ?primitives/bool_not
Element function create_node() = ?primitives/create_node
Element function create_edge(a: Element, b: Element) = ?primitives/create_edge
Element function create_value(a: Element) = ?primitives/create_value
Boolean function is_edge(a: Element) = ?primitives/is_edge
Integer function read_nr_out(a: Element) = ?primitives/read_nr_out
Element function read_out(a: Element, b: Integer) = ?primitives/read_out
Integer function read_nr_in(a: Element) = ?primitives/read_nr_in
Element function read_in(a: Element, b: Integer) = ?primitives/read_in
Element function read_edge_src(a: Element) = ?primitives/read_edge_src
Element function read_edge_dst(a: Element) = ?primitives/read_edge_dst
Boolean function delete_element(a: Element) = ?primitives/delete_element
Boolean function element_eq(a: Element, b: Element) = ?primitives/element_eq
Boolean function element_neq(a: Element, b: Element) = ?primitives/element_neq
Float function cast_i2f(a: Integer) = ?primitives/cast_i2f
String function cast_i2s(a: Integer) = ?primitives/cast_i2s
Boolean function cast_i2b(a: Integer) = ?primitives/cast_i2b
Integer function cast_f2i(a: Float) = ?primitives/cast_f2i
Boolean function cast_f2b(a: Float) = ?primitives/cast_f2b
String function cast_f2s(a: Float) = ?primitives/cast_f2s
Integer function cast_s2i(a: String) = ?primitives/cast_s2i
Float function cast_s2f(a: String) = ?primitives/cast_s2f
Boolean function cast_s2b(a: String) = ?primitives/cast_s2b
Integer function cast_b2i(a: Boolean) = ?primitives/cast_b2i
Float function cast_b2f(a: Boolean) = ?primitives/cast_b2f
String function cast_b2s(a: Boolean) = ?primitives/cast_b2s
String function cast_e2s(a: Element) = ?primitives/cast_e2s
String function cast_a2s(a: Action) = ?primitives/cast_a2s
String function cast_v2s(a: Element) = ?primitives/cast_v2s
String function cast_id2s(a: Element) = ?primitives/cast_id2s
Element function dict_add(a: Element, b: Element, c: Element) = ?primitives/dict_add
Element function dict_delete(a: Element, b: Element) = ?primitives/dict_delete
Element function dict_read(a: Element, b: Element) = ?primitives/dict_read
Element function dict_read_edge(a: Element, b: Element) = ?primitives/dict_read_edge
Element function dict_read_node(a: Element, b: Element) = ?primitives/dict_read_node
Integer function dict_len(a: Element) = ?primitives/dict_len
Boolean function dict_in(a: Element, b: Element) = ?primitives/dict_in
Boolean function dict_in_node(a: Element, b: Element) = ?primitives/dict_in_node
Element function dict_keys(a: Element) = ?primitives/dict_keys
Float function float_addition(a: Float, b: Float) = ?primitives/float_addition
Float function float_subtraction(a: Float, b: Float) = ?primitives/float_subtraction
Float function float_multiplication(a: Float, b: Float) = ?primitives/float_multiplication
Float function float_division(a: Float, b: Float) = ?primitives/float_division
Boolean function float_gt(a: Float, b: Float) = ?primitives/float_gt
Boolean function float_lt(a: Float, b: Float) = ?primitives/float_lt
Boolean function float_neg(a: Float) = ?primitives/float_neg
Integer function integer_addition(a: Integer, b: Integer) = ?primitives/integer_addition
Integer function integer_subtraction(a: Integer, b: Integer) = ?primitives/integer_subtraction
Integer function integer_multiplication(a: Integer, b: Integer) = ?primitives/integer_multiplication
Integer function integer_division(a: Integer, b: Integer) = ?primitives/integer_division
Boolean function integer_gt(a: Integer, b: Integer) = ?primitives/integer_gt
Boolean function integer_lt(a: Integer, b: Integer) = ?primitives/integer_lt
Boolean function integer_neg(a: Integer) = ?primitives/integer_neg
Element function list_read(a: Element, b: Integer) = ?primitives/list_read
Element function list_append(a: Element, b: Element) = ?primitives/list_append
Element function list_insert(a: Element, b: Element, c: Integer) = ?primitives/list_insert
Element function list_delete(a: Element, b: Integer) = ?primitives/list_delete
Integer function list_len(a: Element) = ?primitives/list_len
Element function set_add(a: Element, b: Element) = ?primitives/set_add
Element function set_pop(a: Element) = ?primitives/set_pop
Element function set_remove(a: Element, b: Element) = ?primitives/set_remove
Boolean function set_in(a: Element, b: Element) = ?primitives/set_in
Element function set_remove_node(a: Element, b: Element) = ?primitives/set_remove_node
Element function set_in_node(a: Element, b: Element) = ?primitives/set_in_node
String function string_join(a: String, b: String) = ?primitives/string_join
String function string_get(a: String, b: Integer) = ?primitives/string_get
Element function string_split(a: String, b: String) = ?primitives/string_split
Integer function string_len(a: String) = ?primitives/string_len
Element function deserialize(a: String) = ?primitives/deserialize
Element function log(a: String) = ?primitives/log
Element function read_root() = ?primitives/read_root
Element function read_userroot() = ?primitives/read_userroot
Boolean function is_physical_int(a: Element) = ?primitives/is_physical_int
Boolean function is_physical_float(a: Element) = ?primitives/is_physical_float
Boolean function is_physical_string(a: Element) = ?primitives/is_physical_string
Boolean function is_physical_boolean(a: Element) = ?primitives/is_physical_boolean
Boolean function is_physical_action(a: Element) = ?primitives/is_physical_action

Element function exec(first_instr : Element):
	// This does very ugly things, so beware!
	// Basically, we dynamically construct an if True condition with as body the provided instructions
	// after the if conditional, we append a return of an empty element, as we need a return at the end
	// returns in the code are therefore allowed (and will be the return value), but not necessarily
	Element n
	Element exec_if
	Element exec_const_true
	Element exec_return

	n = create_node()
	exec_if = create_value(!if)
	exec_const_true = create_value(!constant)
	exec_return = create_value(!return)

	dict_add(n, "params", create_node())
	dict_add(exec_const_true, "node", create_value(True))
	dict_add(exec_if, "cond", exec_const_true)
	dict_add(exec_if, "then", first_instr)
	dict_add(n, "body", exec_if)
	dict_add(exec_if, "next", exec_return)

	return n()

Boolean function string_startswith(a: String, b: String):
	Integer i
	i = 0
	if (string_len(b) > string_len(a)):
		return False

	while (i < string_len(b)):
		if (string_get(a, i) != string_get(b, i)):
			return False
		i = i + 1
	
	return True

Boolean function has_value(a: Element):
	return bool_or(bool_or(bool_or(is_physical_action, is_physical_int(a)), is_physical_float(a)), bool_or(is_physical_string(a), is_physical_boolean(a)))

Boolean function float_gte(a: Float, b: Float):
	return bool_or(float_gt(a, b), value_eq(a, b))

Boolean function float_lte(a: Float, b: Float):
	return bool_or(float_lt(a, b), value_eq(a, b))

Boolean function integer_lte(a: Integer, b: Integer):
	return bool_or(integer_lt(a, b), value_eq(a, b))
	
Boolean function integer_gte(a: Integer, b: Integer):
	return bool_or(integer_gt(a, b), value_eq(a, b))

String function string_substr(a: String, b: Integer, c: Integer):
	String result
	Integer i

	// First handle corner cases!

	// If the string is too short for b to even start, return empty
	if (b > string_len(a)):
		return ""

	// If the part we want to snip is negative, we return empty
	if (b > c):
		return ""

	i = 0
	result = ""
	while (i < string_len(a)):
		if (bool_and(i > b, i < c)):
			result = result + string_get(a, i)

		if (i > c):
			return result
	return result
	
Element function resolve(name : String):
	// Could directly access it through introspection
	// But seems safer to create some code and execute it...
	Element user_root
	user_root = read_userroot()
	user_root = user_root["globals"][name]["value"]
	return user_root

Integer function integer_modulo(a : Integer, b : Integer):
	return a - b * (a / b)
