open Instr open State open Cont open Step open Trampoline type t = { code : Instr.t array; initial_state : State.t; } type execution_result = | Success of value option | Failure of State.error | Timeout let create code = let state = State.create code in { code; initial_state = state } let execute ?(config = Trampoline.default_config) vm = let state = vm.initial_state in let cont = Cont.halt in match Trampoline.run ~config (fun () -> step state cont) with | Some v -> Success v | None -> Failure NoExceptionHandler let execute_with_limit vm max_steps = let config = { Trampoline.default_config with max_steps = Some max_steps } in execute ~config vm let execute_program ?(config = Trampoline.default_config) code = let vm = create code in execute ~config vm let execute_program_with_limit code max_steps = let vm = create code in execute_with_limit vm max_steps let execute_with_trace code = let config = { Trampoline.default_config with trace = true } in let result = execute_program ~config code in (result, Trampoline.get_trace config) let disassemble code = Array.mapi (fun i instr -> (i, Instr.show instr)) code |> Array.to_list let validate code = let errors = ref [] in Array.iteri (fun i instr -> match instr with | JMP offset | JMP_IF offset | JMP_IF_NOT offset | TRY offset -> let target = i + 1 + offset - 1 in if target < 0 || target >= Array.length code then errors := (i, State.InvalidJump target) :: !errors | MK_CLOSURE code_addr -> if code_addr < 0 || code_addr >= Array.length code then errors := (i, State.InvalidJump code_addr) :: !errors | _ -> ()) code; List.rev !errors