123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- import time as python_time
- import json
- import sys
- class InterpretedFunctionFinished(Exception):
- """Exception to indicate the result value of an interpreted function, as a return
- cannot be used."""
- def __init__(self, value):
- Exception.__init__(self)
- self.result = value
- class SleepKernel(Exception):
- """Exception to indicate the kernel to sleep for some time."""
- def __init__(self, timeout, interruptable):
- Exception.__init__(self)
- self.timeout = timeout
- self.interruptable = interruptable
- # Functions annotated with __exception_return use the JIT's calling convention instead of
- # returnvalue is not modified.
- #
- # ### Rationale for __exception_return
- #
- # __exception_return is a useful mechanism because it allows us to have a __call_function
- # implementation that has O(1) state read overhead. A previous implementation of
- # __call_function checked if the caller's frame had been popped whenever
- # ModelverseKernel.execute_yield threw a StopIteration exception. However, that incurs O(n) overhead
- # _per call,_ where n is the number of StopIteration exceptions that are thrown during the call.
- # O(n) is pretty bad, but this actually becomes O(n * m) when m calls to __call_function are
- # nested. And that's just not acceptable.
- # __exception_return requires kernel support, but I think the complexity gains are well worth it;
- # I reckon JIT-to-interpreter switches aren't going to get a whole lot cheaper than this.
- EXCEPTION_RETURN_KEY = "__exception_return"
- """A dictionary key for functions which request that the kernel throw a InterpretedFunctionFinished
- exception with the return value instead of injecting the return value in the caller's frame."""
- def integer_subtraction(a, b, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- yield [("RETURN", [{'value': a['value'] - b['value']}])]
- def integer_addition(a, b, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- yield [("RETURN", [{'value': a['value'] + b['value']}])]
- def integer_multiplication(a, b, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- yield [("RETURN", [{'value': a['value'] * b['value']}])]
- def integer_division(a, b, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- yield [("RETURN", [{'value': int(a['value']) // b['value']}])]
- def integer_lt(a, b, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- yield [("RETURN", [{'value': a['value'] < b['value']}])]
- def bool_and(a, b, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- yield [("RETURN", [{'value': a['value'] and b['value']}])]
- def bool_or(a, b, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- yield [("RETURN", [{'value': a['value'] or b['value']}])]
- def bool_not(a, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- yield [("RETURN", [{'value': not a['value']}])]
- def float_subtraction(a, b, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- yield [("RETURN", [{'value': a['value'] - b['value']}])]
- def float_addition(a, b, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- yield [("RETURN", [{'value': a['value'] + b['value']}])]
- def float_multiplication(a, b, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- yield [("RETURN", [{'value': a['value'] * b['value']}])]
- def float_division(a, b, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- yield [("RETURN", [{'value': float(a['value']) / b['value']}])]
- def float_lt(a, b, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- yield [("RETURN", [{'value': a['value'] < b['value']}])]
- def string_join(a, b, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- yield [("RETURN", [{'value': str(a['value']) + str(b['value'])}])]
- def string_split(a, b, **remainder):
- # TODO make non-primitive, though compiled
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- result = a['value'].split(b['value'])
- elems = yield [("CN", [])] + [("CNV", [v]) for v in result]
- new_val = elems[0]
- yield [("CD", [new_val, i, v]) for i, v in enumerate(elems[1:])]
- yield [("RETURN", [{'id': new_val}])]
- def string_get(a, b, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- yield [("RETURN", [{'value': a['value'][b['value']]}])]
- def string_len(a, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- yield [("RETURN", [{'value': len(a['value'])}])]
- def value_eq(a, b, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if 'value' not in b:
- b['value'], = yield [("RV", [b['id']])]
- yield [("RETURN", [{'value': a['value'] == b['value']}])]
- def element_eq(a, b, **remainder):
- if "id" not in a:
- #print("MATERIALIZING A element_eq")
- a['id'], = yield [("CNV", [a['value']])]
- if "id" not in b:
- #print("MATERIALIZING B element_eq")
- b['id'], = yield [("CNV", [b['value']])]
- yield [("RETURN", [{'value': a['id'] == b['id']}])]
- def cast_string(a, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if isinstance(a['value'], dict):
- yield [("RETURN", [{'value': str(a['value']['value'])}])]
- else:
- yield [("RETURN", [{'value': str(a['value'])}])]
- def cast_float(a, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- yield [("RETURN", [{'value': float(a['value'])}])]
- def cast_boolean(a, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- yield [("RETURN", [{'value': bool(a['value'])}])]
- def cast_integer(a, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- yield [("RETURN", [{'value': int(a['value'])}])]
- def cast_value(a, **remainder):
- if 'value' not in a:
- a['value'], = yield [("RV", [a['id']])]
- if isinstance(a['value'], dict):
- yield [("RETURN", [{'value': str(a['value']['value'])}])]
- else:
- yield [("RETURN", [{'value': json.dumps(a['value'])}])]
- def cast_id(a, **remainder):
- if "id" not in a:
- #print("MATERIALIZING A cast_id")
- a['id'], = yield [("CNV", [a['value']])]
- yield [("RETURN", [{'value': str(a['id'])}])]
- def dict_add_fast(a, b, c, **remainder):
- # TODO deprecate, as dict_add is now also efficient
- if "value" not in b:
- b['value'], = yield [("RV", [b['id']])]
- if "id" not in c:
- #print("MATERIALIZING C dict_add_fast")
- c['id'], = yield [("CNV", [c['value']])]
- yield [("CD", [a['id'], b['value'], c['id']])]
- yield [("RETURN", [a])]
- def dict_delete(a, b, **remainder):
- if "value" not in b:
- b['value'], = yield [("RV", [b['id']])]
- edge, = yield [("RDE", [a['id'], b['value']])]
- if edge is None:
- print("Failed dict_delete for value '%s'!" % b['value'])
- keys, = yield [("RDK", [a['id']])]
- keys = yield [("RV", [i]) for i in keys]
- print("Keys: " + str(keys))
- raise Exception()
- yield [("DE", [edge])]
- yield [("RETURN", [a])]
- def dict_delete_node(a, b, **remainder):
- edge, = yield [("RDNE", [a['id'], b['id']])]
- if edge is None:
- print("Failed dict_delete_node!")
- yield [("DE", [edge])]
- yield [("RETURN", [a])]
- def dict_read(a, b, **remainder):
- if "value" not in b:
- b['value'], = yield [("RV", [b['id']])]
- result, = yield [("RD", [a['id'], b['value']])]
- yield [("RETURN", [{'id': result}])]
- def dict_read_edge(a, b, **remainder):
- if "value" not in b:
- b['value'], = yield [("RV", [b['id']])]
- result, = yield [("RDE", [a['id'], b['value']])]
- yield [("RETURN", [{'id': result}])]
- def dict_read_node(a, b, **remainder):
- result, = yield [("RDN", [a['id'], b['id']])]
- yield [("RETURN", [{'id': result}])]
- def dict_in(a, b, **remainder):
- if "value" not in b:
- b['value'], = yield [("RV", [b['id']])]
- value, = yield [("RD", [a['id'], b['value']])]
- yield [("RETURN", [{'value': value is not None}])]
- def dict_in_node(a, b, **remainder):
- if "id" not in b:
- # Not even allocated the node, so it is certain not to be in the dictionary
- yield [("RETURN", [{'value': False}])]
- value, = yield [("RDN", [a['id'], b['id']])]
- yield [("RETURN", [{'value': value is not None}])]
- def dict_keys(a, **remainder):
- keys, result = yield [("RDK", [a['id']]), ("CN", [])]
- edges = yield [("CE", [result, result]) for _ in keys]
- _ = yield [("CE", [edge, key]) for edge, key in zip(edges, keys)]
- yield [("RETURN", [{'id': result}])]
- def is_physical_int(a, **remainder):
- if "value" not in a:
- a['value'], = yield [("RV", [a['id']])]
- try:
- yield [("RETURN", [{'value': isinstance(a['value'], int) or isinstance(a['value'], long)}])]
- except NameError:
- yield [("RETURN", [{'value': isinstance(a['value'], int)}])]
- def is_physical_string(a, **remainder):
- if "value" not in a:
- a['value'], = yield [("RV", [a['id']])]
- try:
- yield [("RETURN", [{'value': isinstance(a['value'], str) or isinstance(a['value'], unicode)}])]
- except NameError:
- yield [("RETURN", [{'value': isinstance(a['value'], str)}])]
- def is_physical_float(a, **remainder):
- if "value" not in a:
- a['value'], = yield [("RV", [a['id']])]
- yield [("RETURN", [{'value': isinstance(a['value'], float)}])]
- def is_physical_boolean(a, **remainder):
- if "value" not in a:
- a['value'], = yield [("RV", [a['id']])]
- yield [("RETURN", [{'value': isinstance(a['value'], bool)}])]
- def is_physical_action(a, **remainder):
- if "value" not in a:
- a['value'], = yield [("RV", [a['id']])]
- yield [("RETURN", [{'value': isinstance(a['value'], dict) and a['value']["value"] in ["if", "while", "assign", "call", "break", "continue", "return", "resolve", "access", "constant", "global", "declare"]}])]
- def is_physical_none(a, **remainder):
- if "value" not in a:
- a['value'], = yield [("RV", [a['id']])]
- yield [("RETURN", [{'value': isinstance(a['value'], dict) and a['value']["value"] == "none"}])]
- def create_node(**remainder):
- result, = yield [("CN", [])]
- yield [("RETURN", [{'id': result}])]
- def create_edge(a, b, **remainder):
- if "id" not in a:
- #print("MATERIALIZING A create_edge")
- a['id'], = yield [("CNV", [a['value']])]
- if "id" not in b:
- #print("MATERIALIZING B create_edge")
- b['id'], = yield [("CNV", [b['value']])]
- result, = yield [("CE", [a['id'], b['id']])]
- yield [("RETURN", [{'id': result}])]
- def create_value(a, **remainder):
- if "value" not in a:
- a['value'], = yield [("RV", [a['id']])]
- yield [("RETURN", [{'value': a['value']}])]
- def read_nr_out(a, **remainder):
- if "id" not in a:
- yield [("RETURN", [{'value': 0}])]
- else:
- outgoing, = yield [("RO", [a['id']])]
- yield [("RETURN", [{'value': len(outgoing)}])]
- def read_out(a, b, root, **remainder):
- if "id" not in a:
- a['id'], = yield [("CNV", [a['value']])]
- if "value" not in b:
- b['value'], = yield [("RV", [b['id']])]
- outgoing, = yield [("RO", [a['id']])]
- yield [("RETURN", [{'id': sorted(outgoing)[b['value']] if len(outgoing) > b['value'] else root}])]
- def read_nr_in(a, **remainder):
- if "id" not in a:
- yield [("RETURN", [{'value': 0}])]
- else:
- incoming, = yield [("RI", [a['id']])]
- yield [("RETURN", [{'value': len(incoming)}])]
- def read_in(a, b, root, **remainder):
- if "id" not in a:
- a['id'], = yield [("CNV", [a['value']])]
- if "value" not in b:
- b['value'], = yield [("RV", [b['id']])]
- incoming, = yield [("RI", [a['id']])]
- yield [("RETURN", [{'id': sorted(incoming)[b['value']] if len(incoming) > b['value'] else root}])]
- def read_edge_src(a, **remainder):
- result, = yield [("RE", [a['id']])]
- yield [("RETURN", [{'id': result[0]}])]
- def read_edge_dst(a, **remainder):
- result, = yield [("RE", [a['id']])]
- yield [("RETURN", [{'id': result[1]}])]
- def delete_element(a, **remainder):
- if "id" not in a:
- yield [("RETURN", [{'value': False}])]
- edge, = yield [("RE", [a['id']])]
- if edge[0] is None:
- # Not an edge:
- yield [("DN", [a['id']])]
- yield [("RETURN", [{'value': False}])]
- else:
- yield [("DE", [a['id']])]
- yield [("RETURN", [{'value': True}])]
- def read_root(root, **remainder):
- yield [("RETURN", [{'id': root}])]
- def is_edge(a, **remainder):
- if "id" not in a:
- yield [("RETURN", [{'value': False}])]
- edge, = yield [("RE", [a['id']])]
- yield [("RETURN", [{'value': edge[0] is not None}])]
- def log(a, **remainder):
- if "value" not in a:
- a['value'], = yield [("RV", [a['id']])]
- print("== LOG == " + str(a['value']))
- yield [("RETURN", [a])]
- def read_taskroot(task_root, **remainder):
- yield [("RETURN", [{'id': task_root}])]
- def time(**remainder):
- yield [("RETURN", [{'value': python_time.time()}])]
- def hash(a, **remainder):
- if "value" not in a:
- a['value'], = yield [("RV", [a['id']])]
- import hashlib
- try:
- value = hashlib.sha512(a['value']).hexdigest()
- except TypeError:
- value = hashlib.sha512(a['value'].encode()).hexdigest()
- yield [("RETURN", [{'value': value}])]
- def __sleep(a, b, **remainder):
- if "value" not in a:
- a['value'], = yield [("RV", [a['id']])]
- if "value" not in b:
- b['value'], = yield [("RV", [b['id']])]
- timeout = a['value']
- interruptable = b['value']
- yield [("SLEEP", [timeout, interruptable])]
- yield [("RETURN", [a])]
- def is_error(a, **remainder):
- if a['id'] is None:
- yield [("RETURN", [{'value': True}])]
- else:
- yield [("RETURN", [{'value': False}])]
- def list_sort(a, **remainder):
- elements, = yield [("RO", [a['id']])]
- values = yield [("RD", [a['id'], i]) for i in range(elements)]
- values = yield [("RV", [i]) for i in values]
- new_list, = yield [("CN", [])]
- values = yield [("CNV", [v]) for v in sorted(values))
- yield [("CD", [new_list, i, v]) for i, v in enumerate(values)]
- yield [("RETURN", [{'id': new_list}])]
|