add standard library / initial environment
This commit is contained in:
parent
ffbe99061f
commit
88fff1c119
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 ]
|
||||||
|
|
|
@ -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, [||])
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue