add standard library / initial environment

This commit is contained in:
tali 2023-12-02 16:06:57 -05:00
parent ffbe99061f
commit 88fff1c119
5 changed files with 80 additions and 24 deletions

View File

@ -5,7 +5,7 @@ let () =
Logs.set_level (Some Logs.Debug); Logs.set_level (Some Logs.Debug);
try 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 prog = compile ast in
let ret = run prog in let ret = run prog in
Fmt.pr "{\"program\":%a,\"output\":%a}" Code.pp_program prog Value.pp ret Fmt.pr "{\"program\":%a,\"output\":%a}" Code.pp_program prog Value.pp ret

View File

@ -1,6 +1,7 @@
module Ast = Spice_syntax.Ast module Ast = Spice_syntax.Ast
module Code = Spice_runtime.Code module Code = Spice_runtime.Code
module Value = Spice_runtime.Value module Value = Spice_runtime.Value
module Interp = Spice_runtime.Interp
module Env = Map.Make (String) module Env = Map.Make (String)
type binding = { type binding = {
@ -142,7 +143,11 @@ let compile modl =
| Some ret -> ret | Some ret -> ret
in in
let env = Env.empty in let stdlib_env =
emit_mov 0 (compile_obj env 0 modl.Ast.items); 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; emit RET;
Code.make_program ep Code.make_program ep

View File

@ -75,14 +75,6 @@ type frame = {
mutable pc : Code.ins list; 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 let eval fr = function
| Code.Cst_nil -> Value.Nil | Code.Cst_nil -> Value.Nil
| Code.Cst_true -> Value.True | Code.Cst_true -> Value.True
@ -116,15 +108,63 @@ and call mthd self args =
match mthd with match mthd with
| Code.Method pr -> | Code.Method pr ->
if args <> [] then failwith "Interp.call: TODO: method arguments"; if args <> [] then failwith "Interp.call: TODO: method arguments";
run_program pr run pr self
| _ -> Value.call mthd self args | _ -> Value.call mthd self args
and run fr = and run prog self =
match fr.pc with let frame_size = 1 in
| [] -> return_value fr let frame_size = max frame_size (Code.frame_size prog) in
| is :: rest -> let fr =
fr.pc <- rest; let regs = Array.make frame_size Value.Nil in
exec fr is; let pc = Code.instructions prog.entrypoint in
run fr { 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 ]

View File

@ -63,9 +63,17 @@ and pp_obj ppf vtable slots =
vtable.elems; vtable.elems;
Fmt.pf ppf "}" 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 match mthd with
| Native_function f -> f self args | Native_function f -> f args
| _ -> raise Not_found | _ -> 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, [||])

View File

@ -15,5 +15,8 @@ let parse input =
let compile ast = Spice_compile.Bcc.compile ast let compile ast = Spice_compile.Bcc.compile ast
let run prog = 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 with Spice_runtime.Interp.Runtime_error msg -> failf "runtime error: %s" msg