1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- import modelverse_kernel.primitives as primitive_functions
- def interpret_function(function_id, named_arguments, **kwargs):
- """Makes the interpreter run the function with the given id with the specified
- argument dictionary."""
- user_root = kwargs['user_root']
- user_frame, = yield [("RD", [user_root, "frame"])]
- inst, = yield [("RD", [user_frame, "IP"])]
- body_id, = yield [("RD", [function_id, "body"])]
- # Create a new stack frame.
- frame_link, new_phase, new_frame, new_evalstack, new_symbols, new_returnvalue = \
- yield [("RDE", [user_root, "frame"]),
- ("CNV", ["init"]),
- ("CN", []),
- ("CN", []),
- ("CN", []),
- ("CN", []),
- ]
- _, _, _, _, _, _, _, _, _ = \
- yield [("CD", [user_root, "frame", new_frame]),
- ("CD", [new_frame, "evalstack", new_evalstack]),
- ("CD", [new_frame, "symbols", new_symbols]),
- ("CD", [new_frame, "returnvalue", new_returnvalue]),
- ("CD", [new_frame, "caller", inst]),
- ("CD", [new_frame, "phase", new_phase]),
- ("CD", [new_frame, "IP", body_id]),
- ("CD", [new_frame, "prev", user_frame]),
- ("DE", [frame_link]),
- ]
- # Put the parameters in the new stack frame's symbol table.
- kernel = kwargs['mvk']
- try:
- gen = kernel.jit.jit_parameters(body_id)
- inp = None
- while 1:
- inp = yield gen.send(inp)
- except primitive_functions.PrimitiveFinished as ex:
- parameter_vars, parameter_names = ex.result
- parameter_dict = dict(zip(parameter_names, parameter_vars))
- for (key, value) in named_arguments.items():
- param_var = parameter_dict[key]
- variable, = yield [("CN", [])]
- yield [("CD", [variable, "value", value])]
- symbol_edge, = yield [("CE", [new_symbols, variable])]
- yield [("CE", [symbol_edge, param_var])]
- username = kwargs['username']
- while 1:
- try:
- gen = kernel.execute_rule(username)
- inp = None
- while 1:
- inp = yield gen.send(inp)
- except StopIteration:
- # An instruction has been completed. Check if we've already returned.
- #
- # TODO: the statement below performs O(n) state reads whenever an instruction
- # finishes, where n is the number of 'interpret_function' stack frames.
- # I don't *think* that this is problematic (at least not in the short term),
- # but an O(1) solution would obviously be much better; that's the interpreter's
- # complexity. Perhaps we can annotate the stack frame we create here with a marker
- # that the kernel can pick up on? We could have the kernel throw an exception whenever
- # it encounters said marker.
- current_user_frame, = yield [("RD", [user_root, "frame"])]
- if current_user_frame == user_frame:
- # We're done here. Extract the return value and get out.
- returnvalue, = yield [("RD", [user_frame, "returnvalue"])]
- raise primitive_functions.PrimitiveFinished(returnvalue)
- else:
- yield None
|