sequence/lib/step.ml

362 lines
14 KiB
OCaml

open Instr
type result =
| Continue of { state : State.t; cont : Cont.t }
| Halted of value option
| Error of State.error
let step state cont : result =
if state.pc >= Array.length state.code then
Halted None
else
let instr = state.code.(state.pc) in
let next_pc = state.pc + 1 in
let next_state = State.with_pc state next_pc in
match instr with
| PUSH v ->
let new_state = State.push next_state v in
Continue { state = new_state; cont }
| POP ->
(match State.pop next_state with
| State.Error e -> Error e
| State.Ok (_, new_state) ->
Continue { state = new_state; cont })
| DUP ->
(match State.peek next_state with
| State.Error e -> Error e
| State.Ok v ->
let new_state = State.push next_state v in
Continue { state = new_state; cont })
| SWAP ->
(match State.pop_n next_state 2 with
| State.Error e -> Error e
| State.Ok ([a; b], new_state) ->
let new_state = State.push (State.push new_state a) b in
Continue { state = new_state; cont }
| State.Ok _ -> Error (State.TypeMismatch "SWAP"))
| OVER ->
(match State.pop_n next_state 2 with
| State.Error e -> Error e
| State.Ok ([a; b], new_state) ->
let new_state = State.push (State.push new_state b) a in
let new_state = State.push new_state b in
Continue { state = new_state; cont }
| State.Ok _ -> Error (State.TypeMismatch "OVER"))
| ROT ->
(match State.pop_n next_state 3 with
| State.Error e -> Error e
| State.Ok ([a; b; c], new_state) ->
let new_state = State.push (State.push (State.push new_state a) c) b in
Continue { state = new_state; cont }
| State.Ok _ -> Error (State.TypeMismatch "ROT"))
| ADD ->
(match State.pop_n next_state 2 with
| State.Error e -> Error e
| State.Ok ([Int a; Int b], new_state) ->
let new_state = State.push new_state (Int (a + b)) in
Continue { state = new_state; cont }
| State.Ok _ -> Error (State.TypeMismatch "ADD"))
| SUB ->
(match State.pop_n next_state 2 with
| State.Error e -> Error e
| State.Ok ([Int a; Int b], new_state) ->
let new_state = State.push new_state (Int (a - b)) in
Continue { state = new_state; cont }
| State.Ok _ -> Error (State.TypeMismatch "SUB"))
| MUL ->
(match State.pop_n next_state 2 with
| State.Error e -> Error e
| State.Ok ([Int a; Int b], new_state) ->
let new_state = State.push new_state (Int (a * b)) in
Continue { state = new_state; cont }
| State.Ok _ -> Error (State.TypeMismatch "MUL"))
| DIV ->
(match State.pop_n next_state 2 with
| State.Error e -> Error e
| State.Ok ([Int a; Int 0], _) -> Error State.DivisionByZero
| State.Ok ([Int a; Int b], new_state) ->
let new_state = State.push new_state (Int (a / b)) in
Continue { state = new_state; cont }
| State.Ok _ -> Error (State.TypeMismatch "DIV"))
| MOD ->
(match State.pop_n next_state 2 with
| State.Error e -> Error e
| State.Ok ([Int a; Int 0], _) -> Error State.DivisionByZero
| State.Ok ([Int a; Int b], new_state) ->
let new_state = State.push new_state (Int (a mod b)) in
Continue { state = new_state; cont }
| State.Ok _ -> Error (State.TypeMismatch "MOD"))
| EQ ->
(match State.pop_n next_state 2 with
| State.Error e -> Error e
| State.Ok ([Int a; Int b], new_state) ->
let new_state = State.push new_state (Int (if a = b then 1 else 0)) in
Continue { state = new_state; cont }
| State.Ok ([Bool a; Bool b], new_state) ->
let new_state = State.push new_state (Bool (a = b)) in
Continue { state = new_state; cont }
| State.Ok _ -> Error (State.TypeMismatch "EQ"))
| NE ->
(match State.pop_n next_state 2 with
| State.Error e -> Error e
| State.Ok ([Int a; Int b], new_state) ->
let new_state = State.push new_state (Int (if a <> b then 1 else 0)) in
Continue { state = new_state; cont }
| State.Ok ([Bool a; Bool b], new_state) ->
let new_state = State.push new_state (Bool (a <> b)) in
Continue { state = new_state; cont }
| State.Ok _ -> Error (State.TypeMismatch "NE"))
| LT ->
(match State.pop_n next_state 2 with
| State.Error e -> Error e
| State.Ok ([Int a; Int b], new_state) ->
let new_state = State.push new_state (Int (if a < b then 1 else 0)) in
Continue { state = new_state; cont }
| State.Ok _ -> Error (State.TypeMismatch "LT"))
| LE ->
(match State.pop_n next_state 2 with
| State.Error e -> Error e
| State.Ok ([Int a; Int b], new_state) ->
let new_state = State.push new_state (Int (if a <= b then 1 else 0)) in
Continue { state = new_state; cont }
| State.Ok _ -> Error (State.TypeMismatch "LE"))
| GT ->
(match State.pop_n next_state 2 with
| State.Error e -> Error e
| State.Ok ([Int a; Int b], new_state) ->
let new_state = State.push new_state (Int (if a > b then 1 else 0)) in
Continue { state = new_state; cont }
| State.Ok _ -> Error (State.TypeMismatch "GT"))
| GE ->
(match State.pop_n next_state 2 with
| State.Error e -> Error e
| State.Ok ([Int a; Int b], new_state) ->
let new_state = State.push new_state (Int (if a >= b then 1 else 0)) in
Continue { state = new_state; cont }
| State.Ok _ -> Error (State.TypeMismatch "GE"))
| AND ->
(match State.pop_n next_state 2 with
| State.Error e -> Error e
| State.Ok ([a; b], new_state) ->
(match (bool_of_value a, bool_of_value b) with
| (Some a', Some b') ->
let new_state = State.push new_state (Bool (a' && b')) in
Continue { state = new_state; cont }
| _ -> Error (State.TypeMismatch "AND")))
| OR ->
(match State.pop_n next_state 2 with
| State.Error e -> Error e
| State.Ok ([a; b], new_state) ->
(match (bool_of_value a, bool_of_value b) with
| (Some a', Some b') ->
let new_state = State.push new_state (Bool (a' || b')) in
Continue { state = new_state; cont }
| _ -> Error (State.TypeMismatch "OR")))
| NOT ->
(match State.pop next_state with
| State.Error e -> Error e
| State.Ok (v, new_state) ->
(match bool_of_value v with
| Some b ->
let new_state = State.push new_state (Bool (not b)) in
Continue { state = new_state; cont }
| None -> Error (State.TypeMismatch "NOT")))
| NEG ->
(match State.pop next_state with
| State.Error e -> Error e
| State.Ok (Int n, new_state) ->
let new_state = State.push new_state (Int (-n)) in
Continue { state = new_state; cont }
| State.Ok _ -> Error (State.TypeMismatch "NEG"))
| JMP offset ->
let new_pc = next_state.pc + offset - 1 in
if new_pc < 0 || new_pc >= Array.length state.code then
Error (State.InvalidJump new_pc)
else
let new_state = State.with_pc next_state new_pc in
Continue { state = new_state; cont }
| JMP_IF offset ->
(match State.pop next_state with
| State.Error e -> Error e
| State.Ok (v, new_state) ->
(match bool_of_value v with
| Some true ->
let new_pc = new_state.pc + offset - 1 in
if new_pc < 0 || new_pc >= Array.length state.code then
Error (State.InvalidJump new_pc)
else
let new_state = State.with_pc new_state new_pc in
Continue { state = new_state; cont }
| Some false ->
Continue { state = new_state; cont }
| None -> Error (State.TypeMismatch "JMP_IF")))
| JMP_IF_NOT offset ->
(match State.pop next_state with
| State.Error e -> Error e
| State.Ok (v, new_state) ->
(match bool_of_value v with
| Some false ->
let new_pc = new_state.pc + offset - 1 in
if new_pc < 0 || new_pc >= Array.length state.code then
Error (State.InvalidJump new_pc)
else
let new_state = State.with_pc new_state new_pc in
Continue { state = new_state; cont }
| Some true ->
Continue { state = new_state; cont }
| None -> Error (State.TypeMismatch "JMP_IF_NOT")))
| CALL ->
(match State.pop next_state with
| State.Error e -> Error e
| State.Ok (func, new_state) ->
(match func with
| Closure { code; env } ->
let new_state = State.push_env new_state in
let new_state = State.set_env new_state env in
let new_pc = code in
if new_pc < 0 || new_pc >= Array.length state.code then
Error (State.InvalidJump new_pc)
else
let new_state = State.with_pc new_state new_pc in
let new_cont = Cont.return_to cont in
Continue { state = new_state; cont = new_cont }
| _ -> Error State.InvalidClosure))
| RET ->
(match State.pop_env next_state with
| State.Error _ ->
(match cont with
| Return_to k ->
Continue { state = next_state; cont = k }
| Halt ->
Halted (match State.peek next_state with State.Ok v -> Some v | _ -> None)
| _ ->
Halted (match State.peek next_state with State.Ok v -> Some v | _ -> None))
| State.Ok (new_state, _) ->
(match cont with
| Return_to k ->
Continue { state = new_state; cont = k }
| Halt ->
Halted (match State.peek new_state with State.Ok v -> Some v | _ -> None)
| _ ->
Halted (match State.peek new_state with State.Ok v -> Some v | _ -> None)))
| MK_CLOSURE code ->
(match State.pop next_state with
| State.Error e -> Error e
| State.Ok (env_val, new_state) ->
let env = match env_val with
| Closure { env; _ } -> env
| _ -> State.get_env new_state
in
let closure = Closure { code; env } in
let new_state = State.push new_state closure in
Continue { state = new_state; cont })
| LOAD idx ->
if idx < 0 || idx >= List.length next_state.env then
Error (State.InvalidIndex idx)
else
let v = List.nth next_state.env idx in
let new_state = State.push next_state v in
Continue { state = new_state; cont }
| STORE idx ->
(match State.pop next_state with
| State.Error e -> Error e
| State.Ok (v, new_state) ->
let env = new_state.env in
let env' = if idx < List.length env then
let rec update i = function
| [] -> []
| x :: xs -> if i = idx then v :: xs else x :: update (i + 1) xs
in update 0 env
else
let padding = List.init (idx - List.length env) (fun _ -> Int 0) in
env @ padding @ [v]
in
let new_state = State.set_env new_state env' in
Continue { state = new_state; cont })
| PUSH_ENV ->
let new_state = State.push_env next_state in
Continue { state = new_state; cont }
| POP_ENV ->
(match State.pop_env next_state with
| State.Error e -> Error e
| State.Ok (new_state, _) ->
Continue { state = new_state; cont })
| TRY offset ->
let handler_pc = next_state.pc + offset - 1 in
if handler_pc < 0 || handler_pc >= Array.length state.code then
Error (State.InvalidJump handler_pc)
else
let handler_cont = Cont.eval_to (state.code.(handler_pc)) Cont.halt in
let new_cont = Cont.exception_to handler_cont cont in
Continue { state = next_state; cont = new_cont }
| RAISE ->
(match State.pop next_state with
| State.Error e -> Error e
| State.Ok (exn_val, new_state) ->
let new_state = State.with_exception new_state exn_val in
let rec find_handler = function
| Exception_to { handler; cont } ->
let new_state = State.clear_exception new_state in
let new_state = State.push new_state exn_val in
Continue { state = new_state; cont = handler }
| Return_to k -> find_handler k
| Apply_to { cont; _ } -> find_handler cont
| Eval_to { cont; _ } -> find_handler cont
| Pop_to { cont; _ } -> find_handler cont
| Halt -> Error State.NoExceptionHandler
in
find_handler cont)
| RERAISE ->
(match next_state.exception_value with
| None -> Error State.NoExceptionHandler
| Some exn_val ->
let rec find_handler = function
| Exception_to { handler; cont } ->
let new_state = State.clear_exception new_state in
let new_state = State.push new_state exn_val in
Continue { state = new_state; cont = handler }
| Return_to k -> find_handler k
| Apply_to { cont; _ } -> find_handler cont
| Eval_to { cont; _ } -> find_handler cont
| Pop_to { cont; _ } -> find_handler cont
| Halt -> Error State.NoExceptionHandler
in
find_handler cont)
| HALT ->
Halted (match State.peek next_state with State.Ok v -> Some v | _ -> None)