2023-11-29 21:50:26 +00:00
|
|
|
exception Runtime_error of string
|
|
|
|
|
2023-12-02 22:02:40 +00:00
|
|
|
let runtime_error f =
|
|
|
|
Fmt.kstr (fun s -> raise (Runtime_error s)) f
|
2023-12-02 20:31:29 +00:00
|
|
|
|
2023-12-07 01:30:42 +00:00
|
|
|
module Prim = struct
|
|
|
|
let intop name ( ** ) v1 v2 =
|
2023-11-29 21:50:26 +00:00
|
|
|
match v1, v2 with
|
2023-12-07 01:30:42 +00:00
|
|
|
| Value.Int x, Value.Int y -> Value.Int (x ** y)
|
|
|
|
| _, _ -> runtime_error "cannot %s non integer values" name
|
2023-11-29 21:50:26 +00:00
|
|
|
|
2023-12-07 01:30:42 +00:00
|
|
|
let cmpop ( </> ) v1 v2 =
|
2023-11-29 21:50:26 +00:00
|
|
|
match v1, v2 with
|
2023-12-07 01:30:42 +00:00
|
|
|
| Value.Int x, Value.Int y -> Value.of_bool (Int64.compare x y </> 0)
|
2023-12-02 20:31:29 +00:00
|
|
|
| _, _ -> runtime_error "cannot compare non integer values"
|
2023-11-30 18:16:20 +00:00
|
|
|
|
2023-12-07 01:30:42 +00:00
|
|
|
let add = intop "add" Int64.add
|
|
|
|
let sub = intop "sub" Int64.sub
|
|
|
|
let mul = intop "mul" Int64.mul
|
|
|
|
let lst = cmpop ( < )
|
|
|
|
let grt = cmpop ( > )
|
|
|
|
let eql v1 v2 = Value.of_bool (Value.equal v1 v2)
|
|
|
|
let not v = Value.of_bool (not (Value.truthy v))
|
|
|
|
|
|
|
|
let loc obj name =
|
|
|
|
try
|
|
|
|
match obj with
|
|
|
|
| Value.Obj (vtable, _) ->
|
|
|
|
Value.of_elem (Hashtbl.find vtable.elems name)
|
|
|
|
| _ ->
|
|
|
|
(* TODO: vtable of primitive types *)
|
|
|
|
raise Not_found
|
|
|
|
with
|
|
|
|
Not_found -> runtime_error "no such element %S" name
|
|
|
|
|
2023-12-21 23:13:26 +00:00
|
|
|
let get (obj, loc) =
|
2023-12-07 01:30:42 +00:00
|
|
|
match obj, Value.to_elem loc with
|
|
|
|
| Value.Obj (_, s), Field i -> s.(i)
|
|
|
|
| Value.Obj (_, _), Method _ -> failwith "Interp.Prim.get: TODO: fcf"
|
2023-12-02 20:31:29 +00:00
|
|
|
| exception Invalid_argument _ -> runtime_error "invalid index"
|
|
|
|
| _ -> runtime_error "get field of non-object"
|
|
|
|
|
2023-12-21 23:13:26 +00:00
|
|
|
let set (obj, loc) v =
|
2023-12-07 01:30:42 +00:00
|
|
|
match obj, Value.to_elem loc with
|
|
|
|
| Value.Obj (_, s), Field i -> s.(i) <- v
|
2023-12-02 20:31:29 +00:00
|
|
|
| Value.Obj (_, _), Method _ -> runtime_error "cannot reassign method"
|
|
|
|
| exception Invalid_argument _ -> runtime_error "invalid index"
|
|
|
|
| _ -> runtime_error "set field of non-object"
|
|
|
|
|
2023-12-21 23:13:26 +00:00
|
|
|
let mthd (obj, loc) =
|
2023-12-07 01:30:42 +00:00
|
|
|
match obj, Value.to_elem loc with
|
2023-12-02 20:31:29 +00:00
|
|
|
| Value.Obj (vtable, _), Method i -> obj, vtable.mthds.(i)
|
2023-12-07 01:30:42 +00:00
|
|
|
| Value.Obj (_, _), Field _ -> failwith "Interp.Prim.mthd: TODO: fcf"
|
2023-12-02 20:31:29 +00:00
|
|
|
| exception Invalid_argument _ -> runtime_error "invalid index"
|
|
|
|
| _ ->
|
2023-12-07 01:30:42 +00:00
|
|
|
(* TODO: vtable of primitive types *)
|
|
|
|
runtime_error "call method of non-object"
|
2023-11-29 21:50:26 +00:00
|
|
|
end
|
|
|
|
|
2023-12-23 19:12:35 +00:00
|
|
|
type frame = Value.t array
|
2023-11-29 21:50:26 +00:00
|
|
|
|
2023-12-23 19:12:35 +00:00
|
|
|
let get fr (`R a) = fr.(a)
|
|
|
|
let set fr (`R a) b = fr.(a) <- b
|
2023-12-21 23:13:26 +00:00
|
|
|
let arg fr = function
|
|
|
|
| #Code.reg as r -> get fr r
|
|
|
|
| `Cst v -> v
|
|
|
|
|
|
|
|
let opr = function
|
|
|
|
| Code.ADD -> Prim.add
|
|
|
|
| Code.SUB -> Prim.sub
|
|
|
|
| Code.MUL -> Prim.mul
|
|
|
|
| Code.DIV -> failwith "Interp: TODO(DIV)"
|
|
|
|
| Code.MOD -> Prim.add
|
|
|
|
| Code.NOT -> fun _ v -> Prim.not v
|
|
|
|
| Code.NEG -> failwith "Interp: TODO(NEG)"
|
|
|
|
| Code.Cmp EQ -> Prim.eql
|
|
|
|
| Code.Cmp GT -> Prim.grt
|
|
|
|
| Code.Cmp LT -> Prim.lst
|
|
|
|
|
|
|
|
let loc fr = function
|
|
|
|
| a, (#Code.reg as b) -> get fr a, get fr b
|
|
|
|
| a, (`Ofs ofs) -> get fr a, Value.of_int ofs
|
|
|
|
|
2023-12-23 19:12:35 +00:00
|
|
|
let rec run fn self args =
|
2023-12-13 21:40:44 +00:00
|
|
|
let Code.{ n_args; frame_size; entry } = fn in
|
|
|
|
if List.length args <> n_args then
|
|
|
|
runtime_error "wrong number of arguments, expected %d, got %d"
|
|
|
|
n_args (List.length args);
|
|
|
|
|
2023-12-23 19:12:35 +00:00
|
|
|
let fr = Array.make frame_size Value.Nil in
|
|
|
|
fr.(0) <- self;
|
|
|
|
List.iteri (fun i v -> fr.(i + 1) <- v) args;
|
|
|
|
|
|
|
|
step fr entry
|
|
|
|
|
|
|
|
and step fr t =
|
|
|
|
match t.Code.edge with
|
|
|
|
| I0 (Ret a) -> arg fr a
|
|
|
|
|
|
|
|
| I1 (i, t1) ->
|
|
|
|
begin match i with
|
|
|
|
| Mov (a, b) -> set fr a (arg fr b)
|
|
|
|
| Opr (op, a, b) -> set fr a (opr op (get fr a) (arg fr b))
|
|
|
|
| Get (a, b) -> set fr a (Prim.get (loc fr b))
|
|
|
|
| Set (bc, a) -> Prim.set (loc fr bc) (arg fr a)
|
|
|
|
| Loc (a, b, nam) -> set fr a (Prim.loc (get fr b) nam)
|
|
|
|
| Con (a, vtb) -> set fr a (Value.make_obj vtb)
|
|
|
|
| Cal (a, f, args) ->
|
|
|
|
let obj, mthd = Prim.mthd (loc fr f) in
|
|
|
|
let args = List.map (arg fr) args in
|
|
|
|
set fr a (call mthd obj args)
|
|
|
|
end; step fr t1
|
|
|
|
|
|
|
|
| I2 (i, t1, t2) ->
|
|
|
|
let cond = match i with
|
|
|
|
| IfT a -> Value.truthy (arg fr a)
|
|
|
|
| i -> Fmt.failwith "TODO: Interp.step: %a" Code.pp_i2 i
|
|
|
|
in
|
|
|
|
step fr (if cond then t1 else t2)
|
2023-12-13 21:40:44 +00:00
|
|
|
|
2023-12-23 19:12:35 +00:00
|
|
|
and call mthd self args =
|
|
|
|
match mthd with
|
|
|
|
| Code.Function fn -> run fn self args
|
|
|
|
| _ -> Value.call mthd self args
|
2023-12-07 03:03:49 +00:00
|
|
|
|