added closures

This commit is contained in:
Moritz Gmeiner 2024-08-28 23:58:55 +02:00
commit b425a59db5
5 changed files with 59 additions and 28 deletions

View file

@ -6,8 +6,7 @@ module Hashtbl = struct
let contains tbl key = find_opt tbl key |> Option.is_some let contains tbl key = find_opt tbl key |> Option.is_some
end end
type env_table = (string, lox_value) Hashtbl.t type environment = Value.environment
type environment = { globals : env_table ref; locals : env_table list }
module Env = struct module Env = struct
type t = environment type t = environment

View file

@ -140,7 +140,7 @@ let rec interpret_expr (env : environment) (expr_node : expr_node) : lox_value i
RuntimeError.make pos msg |> error RuntimeError.make pos msg |> error
else else
match fn args with Ok value -> Ok value | Error s -> RuntimeError.make pos s |> error) match fn args with Ok value -> Ok value | Error s -> RuntimeError.make pos s |> error)
| Function { name; arity; arg_names; body } -> ( | Function { name; env; arity; arg_names; body } -> (
let args_len = List.length args in let args_len = List.length args in
if args_len <> arity then if args_len <> arity then
let msg = let msg =
@ -149,7 +149,8 @@ let rec interpret_expr (env : environment) (expr_node : expr_node) : lox_value i
in in
RuntimeError.make pos msg |> error RuntimeError.make pos msg |> error
else else
let env = Env.push_frame env in (* let env = Env.push_frame env in *)
let env = Env.enter env in
let () = let () =
List.iter2 (fun name value -> assert (Env.define env name value)) arg_names args List.iter2 (fun name value -> assert (Env.define env name value)) arg_names args
in in
@ -190,7 +191,7 @@ and interpret_stmt (env : environment) (stmt_node : stmt_node) : unit interprete
in in
RuntimeError.make pos msg |> error RuntimeError.make pos msg |> error
| FunDecl { name; arg_names; body } -> | FunDecl { name; arg_names; body } ->
let fn = make_lox_function name arg_names body in let fn = make_lox_function name env arg_names body in
let success = Env.define env name fn in let success = Env.define env name fn in
if success then Ok () if success then Ok ()
else else

View file

@ -419,7 +419,6 @@ and fun_declaration (state : state) : stmt_result =
let* () = consume state RightParen in let* () = consume state RightParen in
let* body = with_is_in_fun block state in let* body = with_is_in_fun block state in
make_fun_decl pos name arg_names body |> Result.ok make_fun_decl pos name arg_names body |> Result.ok
(* make_nil pos |> make_expr_stmt pos |> Result.ok *)
and declaration (state : state) : stmt_result = and declaration (state : state) : stmt_result =
match peek_tt state with match peek_tt state with

View file

@ -1,12 +1,12 @@
type lox_function = { type lox_function = {
name : string; name : string;
env : environment;
arity : int; arity : int;
(* env : Environment.environment; [@printer fun fmt _ -> fprintf fmt "<env>"] *)
arg_names : string list; arg_names : string list;
body : Stmt.stmt_node; [@printer fun fmt _ -> fprintf fmt "<body>"] body : Stmt.stmt_node; [@printer fun fmt _ -> fprintf fmt "<body>"]
} }
type native_function = { and native_function = {
name : string; name : string;
arity : int; arity : int;
fn : lox_value list -> (lox_value, string) result; fn : lox_value list -> (lox_value, string) result;
@ -20,6 +20,9 @@ and lox_value =
| Bool of bool | Bool of bool
| Nil | Nil
and env_table = (string, lox_value) Hashtbl.t
and environment = { globals : env_table ref; locals : env_table list }
let string_of_lox_value lox_value = let string_of_lox_value lox_value =
match lox_value with match lox_value with
| Function { name; arity; _ } -> Printf.sprintf "<fn %s/%d>" name arity | Function { name; arity; _ } -> Printf.sprintf "<fn %s/%d>" name arity
@ -40,7 +43,7 @@ let type_string_of_lox_value lox_value =
let lox_value_to_bool lox_value = match lox_value with Bool b -> b | Nil -> false | _ -> true let lox_value_to_bool lox_value = match lox_value with Bool b -> b | Nil -> false | _ -> true
let make_lox_function (name : string) (arg_names : string list) (body : Stmt.stmt_node) : lox_value let make_lox_function (name : string) (env : environment) (arg_names : string list)
= (body : Stmt.stmt_node) : lox_value =
let arity = List.length arg_names in let arity = List.length arg_names in
Function { name; arity; arg_names; body } Function { name; env; arity; arg_names; body }

View file

@ -206,18 +206,27 @@ $ mlox class/reference_self.lox
file closure/assign_to_closure.lox file closure/assign_to_closure.lox
$ mlox closure/assign_to_closure.lox $ mlox closure/assign_to_closure.lox
local
after f
after f
after g
file closure/assign_to_shadowed_later.lox file closure/assign_to_shadowed_later.lox
$ mlox closure/assign_to_shadowed_later.lox $ mlox closure/assign_to_shadowed_later.lox
inner
assigned
file closure/close_over_function_parameter.lox file closure/close_over_function_parameter.lox
$ mlox closure/close_over_function_parameter.lox $ mlox closure/close_over_function_parameter.lox
param
file closure/close_over_later_variable.lox file closure/close_over_later_variable.lox
$ mlox closure/close_over_later_variable.lox $ mlox closure/close_over_later_variable.lox
b
a
file closure/close_over_method_parameter.lox file closure/close_over_method_parameter.lox
@ -226,34 +235,47 @@ $ mlox closure/close_over_method_parameter.lox
file closure/closed_closure_in_function.lox file closure/closed_closure_in_function.lox
$ mlox closure/closed_closure_in_function.lox $ mlox closure/closed_closure_in_function.lox
local
file closure/nested_closure.lox file closure/nested_closure.lox
$ mlox closure/nested_closure.lox $ mlox closure/nested_closure.lox
a
b
c
file closure/open_closure_in_function.lox file closure/open_closure_in_function.lox
$ mlox closure/open_closure_in_function.lox $ mlox closure/open_closure_in_function.lox
local
file closure/reference_closure_multiple_times.lox file closure/reference_closure_multiple_times.lox
$ mlox closure/reference_closure_multiple_times.lox $ mlox closure/reference_closure_multiple_times.lox
a
a
file closure/reuse_closure_slot.lox file closure/reuse_closure_slot.lox
$ mlox closure/reuse_closure_slot.lox $ mlox closure/reuse_closure_slot.lox
a
file closure/shadow_closure_with_local.lox file closure/shadow_closure_with_local.lox
$ mlox closure/shadow_closure_with_local.lox $ mlox closure/shadow_closure_with_local.lox
closure
shadow
closure
file closure/unused_closure.lox file closure/unused_closure.lox
$ mlox closure/unused_closure.lox $ mlox closure/unused_closure.lox
ok
file closure/unused_later_closure.lox file closure/unused_later_closure.lox
$ mlox closure/unused_later_closure.lox $ mlox closure/unused_later_closure.lox
a
file comments/line_at_eof.lox file comments/line_at_eof.lox
@ -1080,6 +1102,7 @@ file print/missing_argument.lox
file regression/40.lox file regression/40.lox
$ mlox regression/40.lox $ mlox regression/40.lox
false
file regression/394.lox file regression/394.lox
@ -1268,6 +1291,8 @@ file variable/duplicate_parameter.lox
file variable/early_bound.lox file variable/early_bound.lox
$ mlox variable/early_bound.lox $ mlox variable/early_bound.lox
outer
outer
file variable/in_middle_of_block.lox file variable/in_middle_of_block.lox
@ -1380,6 +1405,9 @@ $ mlox while/class_in_body.lox
file while/closure_in_body.lox file while/closure_in_body.lox
$ mlox while/closure_in_body.lox $ mlox while/closure_in_body.lox
1
2
3
file while/fun_in_body.lox file while/fun_in_body.lox
@ -1391,6 +1419,7 @@ file while/fun_in_body.lox
file while/return_closure.lox file while/return_closure.lox
$ mlox while/return_closure.lox $ mlox while/return_closure.lox
i
file while/return_inside.lox file while/return_inside.lox