1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
(* Environment *)
module SMap = Map.Make (String)
type locals = string SMap.t
type 'a t =
{ values : 'a ref SMap.t
; globals : string SMap.t
; locals : locals
; loaded_packages : 'a list SMap.t
}
(* hack: "unit option *" to get the right exception format (Ast.location option * string) *)
exception Env_error of unit option * string
let error message = raise (Env_error (None, message))
let fresh =
let count = ref ~-1 in
fun () ->
incr count;
Format.sprintf "v%d" !count
let add_global n default_value env =
let default_value = ref default_value in
let fresh_name = fresh () in
let values = SMap.add fresh_name default_value env.values in
let globals = SMap.add n fresh_name env.globals in
(fresh_name, { env with values; globals })
let add_global_force n v env =
let v = ref v in
let values = SMap.add n v env.values in
let globals = SMap.add n n env.globals in
{ env with values; globals }
let add_local n default_value env =
let default_value = ref default_value in
let fresh_name = fresh () in
let values = SMap.add fresh_name default_value env.values in
let locals = SMap.add n fresh_name env.locals in
(fresh_name, { env with values; locals })
let add_local_force n v env =
let v = ref v in
let values = SMap.add n v env.values in
let locals = SMap.add n n env.locals in
{ env with values; locals }
let get_name n default_value env =
let default_value = ref default_value in
match SMap.find_opt n env.locals with
| Some n -> (n, env)
| None -> (
match SMap.find_opt n env.globals with
| Some n -> (n, env)
| None -> add_global n !default_value env )
let get_value n env =
match SMap.find_opt n env.values with
| None ->
error (Format.sprintf "name: %s not found in get_value env.values" n)
| Some v -> Ok !v
let update_value n v env =
let v = ref v in
match SMap.find_opt n env.values with
| None ->
error (Format.sprintf "name: %s not found in update_value env.values" n)
| Some value ->
value := !v;
Ok ()
let add_value n v env =
let v = ref v in
match SMap.find_opt n env.values with
| None ->
error (Format.sprintf "name: %s not found in add_value env.values" n)
| Some _ ->
let values = SMap.add n v env.values in
Ok { env with values }
let get_locals env = env.locals
let with_locals env locals = { env with locals }
let add_package n vl env =
let loaded_packages = SMap.add n vl env.loaded_packages in
{ env with loaded_packages }
let get_package n env =
match SMap.find_opt n env.loaded_packages with
| None -> Error (None, Format.sprintf "package name: %s not loaded" n)
| Some vl -> Ok vl
let is_package_loaded n env =
let find_opt = SMap.find_opt n env.loaded_packages in
Option.is_some find_opt
let empty () =
let values = SMap.empty in
let globals = SMap.empty in
let locals = SMap.empty in
let loaded_packages = SMap.empty in
{ values; globals; locals; loaded_packages }