runtime.py 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. import modelverse_kernel.primitives as primitive_functions
  2. def interpret_function(function_id, named_arguments, **kwargs):
  3. """Makes the interpreter run the function with the given id with the specified
  4. argument dictionary."""
  5. user_root = kwargs['user_root']
  6. user_frame, = yield [("RD", [user_root, "frame"])]
  7. inst, = yield [("RD", [user_frame, "IP"])]
  8. body_id, = yield [("RD", [function_id, "body"])]
  9. # Create a new stack frame.
  10. frame_link, new_phase, new_frame, new_evalstack, new_symbols, new_returnvalue = \
  11. yield [("RDE", [user_root, "frame"]),
  12. ("CNV", ["init"]),
  13. ("CN", []),
  14. ("CN", []),
  15. ("CN", []),
  16. ("CN", []),
  17. ]
  18. _, _, _, _, _, _, _, _, _ = \
  19. yield [("CD", [user_root, "frame", new_frame]),
  20. ("CD", [new_frame, "evalstack", new_evalstack]),
  21. ("CD", [new_frame, "symbols", new_symbols]),
  22. ("CD", [new_frame, "returnvalue", new_returnvalue]),
  23. ("CD", [new_frame, "caller", inst]),
  24. ("CD", [new_frame, "phase", new_phase]),
  25. ("CD", [new_frame, "IP", body_id]),
  26. ("CD", [new_frame, "prev", user_frame]),
  27. ("DE", [frame_link]),
  28. ]
  29. # Put the parameters in the new stack frame's symbol table.
  30. kernel = kwargs['mvk']
  31. try:
  32. gen = kernel.jit.jit_parameters(body_id)
  33. inp = None
  34. while 1:
  35. inp = yield gen.send(inp)
  36. except primitive_functions.PrimitiveFinished as ex:
  37. parameter_vars, parameter_names = ex.result
  38. parameter_dict = dict(zip(parameter_names, parameter_vars))
  39. for (key, value) in named_arguments.items():
  40. param_var = parameter_dict[key]
  41. variable, = yield [("CN", [])]
  42. yield [("CD", [variable, "value", value])]
  43. symbol_edge, = yield [("CE", [new_symbols, variable])]
  44. yield [("CE", [symbol_edge, param_var])]
  45. username = kwargs['username']
  46. while 1:
  47. try:
  48. gen = kernel.execute_rule(username)
  49. inp = None
  50. while 1:
  51. inp = yield gen.send(inp)
  52. except StopIteration:
  53. # An instruction has been completed. Check if we've already returned.
  54. #
  55. # TODO: the statement below performs O(n) state reads whenever an instruction
  56. # finishes, where n is the number of 'interpret_function' stack frames.
  57. # I don't *think* that this is problematic (at least not in the short term),
  58. # but an O(1) solution would obviously be much better; that's the interpreter's
  59. # complexity. Perhaps we can annotate the stack frame we create here with a marker
  60. # that the kernel can pick up on? We could have the kernel throw an exception whenever
  61. # it encounters said marker.
  62. current_user_frame, = yield [("RD", [user_root, "frame"])]
  63. if current_user_frame == user_frame:
  64. # We're done here. Extract the return value and get out.
  65. returnvalue, = yield [("RD", [user_frame, "returnvalue"])]
  66. raise primitive_functions.PrimitiveFinished(returnvalue)
  67. else:
  68. yield None