include "primitives.alh" include "utils.alh" include "random.alh" // This function must be kept internally, only called through the "sleep" and "interruptable_sleep" functions Float function __sleep(a : Float, b : Boolean) = ?primitives/__sleep Element function list_create(): return create_node()! Element function dict_create(): return create_node()! Element function set_create(): return create_node()! Boolean function value_neq(a : Element, b : Element): return bool_not(value_eq(a, b))! Boolean function integer_gt(a : Element, b : Element): return bool_not(bool_or(integer_lt(a, b), value_eq(a, b)))! Boolean function float_gt(a : Element, b : Element): return bool_not(bool_or(float_lt(a, b), value_eq(a, b)))! Element function dict_add(a : Element, b : Element, c : Element): create_edge(create_edge(a, c), b) return a! Boolean function element_neq(a : Element, b : Element): return bool_not(element_eq(a, b))! Integer function dict_len(a : Element): return read_nr_out(a)! Integer function list_len(a : Element): return read_nr_out(a)! Integer function set_len(a : Element): return read_nr_out(a)! Float function float_neg(a : Float): return float_subtraction(0, a)! Integer function integer_neg(a : Integer): return integer_subtraction(0, a)! Element function list_read(a : Element, b : Integer): return dict_read(a, b)! Element function list_append(a : Element, b : Element): dict_add(a, list_len(a), b) return a! Element function set_add(a : Element, b : Element): if (bool_not(set_in(a, b))): // Treat set as a dictionary with a mock-value dict_add(a, b, a) return a! Element function set_add_node(a : Element, b : Element): if (bool_not(set_in_node(a, b))): // Treat set as a dictionary with a mock-value dict_add(a, b, a) return a! Element function set_pop(a : Element): if (integer_gt(set_len(a), 0)): Element edge Element result edge = read_out(a, 0) result = read_edge_dst(read_out(edge, 0)) delete_element(edge) return result! else: return read_root()! Element function set_read(a : Element): if (integer_gt(set_len(a), 0)): return read_edge_dst(read_out(read_out(a, 0), 0))! else: return read_root()! Void function sleep(a : Float): __sleep(a, False) return! Void function interruptable_sleep(a : Float): __sleep(a, True) return! 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)), bool_or(is_physical_none(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! i = i + 1 return result! String function string_replace(a : String, b : String, c : String): Element lst String result lst = string_split(a, b) result = cast_string(list_pop_final(lst)) while (set_len(lst) > 0): result = cast_string(list_pop_final(lst)) + c + 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 task_root task_root = read_taskroot() task_root = task_root["globals"][name]["value"] return task_root! Integer function integer_modulo(a : Integer, b : Integer): return a - b * (a / b)! Boolean function has_input(): return dict_in(dict_read(read_taskroot(), "input"), "value")! Element function list_pop(lst : Element, index : Integer): Element v v = list_read(lst, index) list_delete(lst, index) return v! Element function list_pop_final(lst : Element): return list_pop(lst, list_len(lst) - 1)! Element function set_copy(a : Element): return dict_keys(a)! String function set_to_string(s : Element): String result result = "{" s = set_copy(s) while (set_len(s) > 0): result = (result + cast_value(set_pop(s))) + ", " result = result + "}" return result! String function list_to_string(s : Element): String result Integer i result = "[" i = 0 while (i < list_len(s)): result = result + cast_value(list_read(s, i)) result = result + ", " i = i + 1 result = result + "]" return result! Element function create_tuple(a : Element, b : Element): Element tuple tuple = list_create() list_append(tuple, a) list_append(tuple, b) return tuple! String function dict_to_string(d : Element): String result Element keys Element key result = "{" keys = dict_keys(d) while (set_len(keys) > 0): key = set_pop(keys) result = result + cast_value(key) result = result + ": " result = result + cast_value(dict_read_node(d, key)) if (set_len(keys) > 0): result = result + ", " result = result + "}" return result! Element function set_overlap(sa : Element, sb : Element): Element result Element elem if (set_len(sa) > set_len(sb)): // Pick the smallest set to iterate over, so switch if sa is not the smallest result = sa sa = sb sb = result result = set_create() sa = set_copy(sa) // Iterate over each element of sa and only add it to the result if it is also in sb while (set_len(sa) > 0): elem = set_pop(sa) if (set_in(sb, elem)): // Shared between both set_add(result, elem) return result! Boolean function set_equality(sa : Element, sb : Element): if (set_len(sa) != set_len(sb)): return False! sa = set_copy(sa) while (0 < set_len(sa)): if (bool_not(set_in(sb, set_pop(sa)))): return False! return True! Boolean function dict_eq(da : Element, db : Element): if (bool_not(set_equality(dict_keys(da), dict_keys(db)))): // They don't even share the same keys return False! Element keys Element key keys = dict_keys(da) while (set_len(keys) > 0): key = set_pop(keys) if (value_neq(da[key], db[key])): // Value that is not equal return False! return True! Element function dict_copy(d : Element): String result Element keys Element key result = dict_create() keys = dict_keys(d) while (set_len(keys) > 0): key = set_pop(keys) dict_add_fast(result, key, dict_read_node(d, key)) return result! Element function list_copy(lst : Element): Integer counter Element result result = list_create() counter = 0 while (counter < list_len(lst)): list_append(result, lst[counter]) counter = counter + 1 return result! Element function set_to_list(s : Element): Element result Element tmp result = list_create() tmp = set_copy(s) while (set_len(tmp) > 0): list_append(result, set_pop(tmp)) return result! Element function list_to_set(s : Element): Element result Integer i i = 0 result = set_create() while (i < list_len(s)): set_add(result, s[i]) i = i + 1 return result! Void function dict_overwrite(d : Element, key : Element, value : Element): if (dict_in(d, key)): dict_delete(d, key) if (dict_in_node(d, key)): dict_delete_node(d, key) dict_add(d, key, value) return ! Void function set_merge(a : Element, b : Element): b = set_copy(b) while (set_len(b) > 0): set_add(a, set_pop(b)) return! Element function make_reverse_dictionary(dict : Element): Element keys Element reverse String key String value reverse = dict_create() keys = dict_keys(dict) while (set_len(keys) > 0): key = set_pop(keys) value = cast_id(dict[key]) if (dict_in(reverse, value)): dict_delete(reverse, value) dict_add(reverse, value, key) return reverse! Element function set_remove(a: Element, b: Element): return dict_delete(a, b)! Element function set_remove_node(a: Element, b: Element): return dict_delete_node(a, b)! Boolean function set_in(a: Element, b: Element): return dict_in(a, b)! Element function set_in_node(a: Element, b: Element): return dict_in_node(a, b)! String function reverseKeyLookup(dict : Element, element : Element): // TODO don't know if this AL will actually work... Integer nr_in Integer nr_out Integer counter Element link nr_in = read_nr_in(element) counter = 0 while (counter < nr_in): if (element_eq(read_edge_src(read_in(element, counter)), dict)): // Got a match return (read_edge_dst(read_out(read_in(element, counter), 0)))! counter = counter + 1 return ""! Element function reverseKeyLookupMulti(dict : Element, element : Element): // TODO don't know if this AL will actually work... Integer nr_in Integer nr_out Integer counter Element link Element result result = set_create() nr_in = read_nr_in(element) counter = 0 while (counter < nr_in): if (element_eq(read_edge_src(read_in(element, counter)), dict)): // Got a match set_add(result, read_edge_dst(read_out(read_in(element, counter), 0))) counter = counter + 1 return result! Boolean function list_in(list : Element, elem : Element): Integer i i = 0 while (i < list_len(list)): if (value_eq(list_read(list, i), elem)): return True! i = i + 1 return False! Element function dict_values(dict : Element): Element result result = set_create() Element keys keys = dict_keys(dict) while (set_len(keys) > 0): set_add(result, dict[set_pop(keys)]) return result! Element function set_difference(sa : Element, sb : Element): Element result Element elem result = set_copy(sa) sb = set_copy(sb) while (set_len(sb) > 0): elem = set_pop(sb) if (set_in(sa, elem)): // Shared between both set_remove(result, elem) return result! Void function set_subtract(set1 : Element, set2 : Element): Element elem set2 = set_copy(set2) while (set_len(set2) > 0): elem = set_pop(set2) if (set_in(set1, elem)): set_remove(set1, elem) return! Element function range(max : Integer): Element result Integer counter result = list_create() counter = 0 while (counter < max): list_append(result, counter) counter = counter + 1 return result! String function spawn(function : Element, arguments : Element): // Define a new task, with all the required stack information // This is taken from the "task_management" code Element task_root Element task_frame Element output_value Element input_value Element root root = read_root() task_root = create_node() task_frame = create_node() output_value = create_node() input_value = create_node() dict_add_fast(task_root, "frame", task_frame) dict_add_fast(task_root, "output", output_value) dict_add_fast(task_root, "last_output", output_value) dict_add_fast(task_root, "input", input_value) dict_add_fast(task_root, "last_input", input_value) dict_add_fast(task_frame, "evalstack", create_node()) dict_add_fast(task_frame, "returnvalue", create_node()) dict_add_fast(task_frame, "phase", "init") dict_add_fast(task_frame, "symbols", create_node()) // Instead of just spawning, we set a different IP dict_add_fast(task_frame, "IP", function["body"]) // Additionally, we copy over all globals that we previously had dict_add_fast(task_root, "globals", dict_copy(root[get_taskname()]["globals"])) if (dict_in(function, "params")): // And add the arguments to the symbol table Element symbols String arg_names_call Element param_dict Integer arg_i symbols = task_frame["symbols"] arg_names_call = "abcdefghijklmnopqrstuvwxyz" arg_i = 0 param_dict = function["params"] arguments = list_copy(arguments) Element t Element entry while (list_len(arguments) > 0): entry = create_node() dict_add(entry, "value", list_pop(arguments, 0)) t = create_edge(symbols, entry) create_edge(t, param_dict[string_get(arg_names_call, arg_i)]) arg_i = arg_i + 1 // Add this only at the end, as otherwise the task will already be detected and executed String taskname taskname = random_string(30) while (dict_in(read_root(), taskname)): taskname = random_string(30) dict_add_fast(read_root(), taskname, task_root) return taskname!