diff --git a/bin/main.ml b/bin/main.ml index 1be7810..5d811dd 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -5,7 +5,7 @@ let () = Logs.set_level (Some Logs.Debug); try - let ast = parse "obj pos { val x = 3 val y = 4 } val result = pos.x" in + let ast = parse "val output = min(4, min(2, 7))" in let prog = compile ast in let ret = run prog in Fmt.pr "{\"program\":%a,\"output\":%a}" Code.pp_program prog Value.pp ret diff --git a/lib/compile/bcc.ml b/lib/compile/bcc.ml index aa6c3f7..11e7a1a 100644 --- a/lib/compile/bcc.ml +++ b/lib/compile/bcc.ml @@ -1,6 +1,7 @@ module Ast = Spice_syntax.Ast module Code = Spice_runtime.Code module Value = Spice_runtime.Value +module Interp = Spice_runtime.Interp module Env = Map.Make (String) type binding = { @@ -142,7 +143,11 @@ let compile modl = | Some ret -> ret in - let env = Env.empty in - emit_mov 0 (compile_obj env 0 modl.Ast.items); + let stdlib_env = + List.to_seq Interp.stdlib + |> Seq.mapi (fun i (name, _) -> name, { self = 0; elem = Value.Method i }) + |> Env.of_seq + in + emit_mov 0 (compile_obj stdlib_env 1 modl.Ast.items); emit RET; Code.make_program ep diff --git a/lib/runtime/interp.ml b/lib/runtime/interp.ml index cab2b87..ace9136 100644 --- a/lib/runtime/interp.ml +++ b/lib/runtime/interp.ml @@ -75,14 +75,6 @@ type frame = { mutable pc : Code.ins list; } -let make_frame prog = - { - regs = Array.make (Code.frame_size prog) Value.Nil; - pc = Code.instructions Code.(prog.entrypoint); - } - -let return_value fr = fr.regs.(0) - let eval fr = function | Code.Cst_nil -> Value.Nil | Code.Cst_true -> Value.True @@ -116,15 +108,63 @@ and call mthd self args = match mthd with | Code.Method pr -> if args <> [] then failwith "Interp.call: TODO: method arguments"; - run_program pr + run pr self | _ -> Value.call mthd self args -and run fr = - match fr.pc with - | [] -> return_value fr - | is :: rest -> - fr.pc <- rest; - exec fr is; - run fr +and run prog self = + let frame_size = 1 in + let frame_size = max frame_size (Code.frame_size prog) in + let fr = + let regs = Array.make frame_size Value.Nil in + let pc = Code.instructions prog.entrypoint in + { regs; pc } + in + let rec run_loop () = + match fr.pc with + | [] -> () + | ins :: rest -> + fr.pc <- rest; + exec fr ins; + run_loop () + in + fr.regs.(0) <- self; + run_loop (); + fr.regs.(0) -and run_program pr = run (make_frame pr) +let stdlib = + let println vs = + let pp ppf vs = + List.iteri + (fun i v -> + if i > 0 then Fmt.pf ppf " "; + Value.pp ppf v) + vs + in + Fmt.pr "%a\n" pp vs; + Value.Nil + in + let min = function + | [] -> runtime_error "zero arguments to min()" + | [ v ] -> v + | v :: vs -> + List.fold_left + (fun v1 v2 -> + match Op.lst v1 v2 with + | Value.True -> v1 + | _ -> v2) + v + vs + in + let max = function + | [] -> runtime_error "zero arguments to max()" + | [ v ] -> v + | v :: vs -> + List.fold_left + (fun v1 v2 -> + match Op.grt v1 v2 with + | Value.True -> v1 + | _ -> v2) + v + vs + in + [ "println", println; "min", min; "max", max ] diff --git a/lib/runtime/value.ml b/lib/runtime/value.ml index 5b2654e..d922a8c 100644 --- a/lib/runtime/value.ml +++ b/lib/runtime/value.ml @@ -63,9 +63,17 @@ and pp_obj ppf vtable slots = vtable.elems; Fmt.pf ppf "}" -type mthd += Native_function of (t -> t list -> t) +type mthd += Native_function of (t list -> t) -let call mthd self args = +let call mthd _self args = match mthd with - | Native_function f -> f self args + | Native_function f -> f args | _ -> raise Not_found + +let native_lib fns = + let elems = Hashtbl.create (List.length fns * 4) in + List.iteri (fun i (name, _) -> Hashtbl.add elems name (Method i)) fns; + let mthds = List.map (fun (_, f) -> Native_function f) fns in + let mthds = Array.of_list mthds in + let vtable = { n_slots = 0; elems; mthds } in + Obj (vtable, [||]) diff --git a/lib/spice.ml b/lib/spice.ml index 05a1e5b..ed1d8ed 100644 --- a/lib/spice.ml +++ b/lib/spice.ml @@ -15,5 +15,8 @@ let parse input = let compile ast = Spice_compile.Bcc.compile ast let run prog = - try Spice_runtime.Interp.run_program prog + try + let open Spice_runtime in + let stdlib = Value.native_lib Interp.stdlib in + Interp.run prog stdlib with Spice_runtime.Interp.Runtime_error msg -> failf "runtime error: %s" msg