Commit | Line | Data |
---|---|---|
2cc3804b NF |
1 | %%% |
2 | %%% Environement | |
3 | %%% | |
4 | ||
5 | -module(env). | |
6 | ||
a61ea75a | 7 | -export([new/0, new/1, bind/3, set/3, get/2, fallback/2]). |
583a62df | 8 | |
a61ea75a | 9 | -record(env, {outer, data, fallback=undefined}). |
583a62df NF |
10 | |
11 | %% | |
12 | %% Public API | |
13 | %% | |
14 | ||
a61ea75a NF |
15 | -spec new() -> Env |
16 | when Env :: #env{}. | |
17 | new() -> | |
18 | new(undefined). | |
19 | ||
583a62df NF |
20 | -spec new(Outer) -> Env |
21 | when Outer :: #env{}, | |
22 | Env :: #env{}. | |
583a62df NF |
23 | new(Outer) -> |
24 | #env{outer=Outer, data=#{}}. | |
25 | ||
a61ea75a NF |
26 | -spec bind(Env1, Names, Values) -> Env2 |
27 | when Env1 :: #env{}, | |
28 | Names :: [term()], | |
29 | Values :: [term()], | |
30 | Env2 :: #env{}. | |
31 | bind(Env, [], []) -> | |
32 | Env; | |
33 | bind(Env, [{symbol, "&"},Name], Values) -> | |
34 | set(Env, Name, {list, Values}); | |
35 | bind(Env, [Name|Ntail], [Value|Vtail]) -> | |
36 | bind(set(Env, Name, Value), Ntail, Vtail). | |
37 | ||
583a62df NF |
38 | -spec set(Env1, Key, Value) -> Env2 |
39 | when Env1 :: #env{}, | |
40 | Key :: {symbol, term()}, | |
41 | Value :: term(), | |
42 | Env2 :: #env{}. | |
43 | set(Env, Key, Value) -> | |
44 | case Key of | |
45 | {symbol, Name} -> | |
46 | Map = maps:put(Name, Value, Env#env.data), | |
47 | #env{outer=Env#env.outer, data=Map}; | |
48 | _ -> throw("env:set/3 called with non-symbol key") | |
49 | end. | |
50 | ||
51 | -spec get(Env, Key) -> Value | |
52 | when Env :: #env{}, | |
53 | Key :: {symbol, term()}, | |
54 | Value :: term(). | |
55 | get(Env, Key) -> | |
56 | case Key of | |
57 | {symbol, Name} -> | |
58 | case find(Env, Name) of | |
59 | nil -> throw(io_lib:format("'~s' not found", [Name])); | |
60 | E -> maps:get(Name, E#env.data) | |
61 | end; | |
62 | _ -> throw("env:get/2 called with non-symbol key") | |
63 | end. | |
64 | ||
a61ea75a NF |
65 | -spec fallback(Env1, Fallback) -> Env2 |
66 | when Env1 :: #env{}, | |
67 | Fallback :: #env{}, | |
68 | Env2 :: #env{}. | |
69 | fallback(Env, Fallback) -> | |
70 | #env{outer=Env#env.outer, data=Env#env.data, fallback=Fallback}. | |
71 | ||
583a62df NF |
72 | %% |
73 | %% Internal functions | |
74 | %% | |
75 | ||
76 | find(Env, Name) -> | |
77 | case maps:is_key(Name, Env#env.data) of | |
78 | true -> Env; | |
79 | false -> | |
80 | case Env#env.outer of | |
a61ea75a NF |
81 | undefined -> |
82 | case Env#env.fallback of | |
83 | undefined -> nil; | |
84 | Fallback -> find(Fallback, Name) | |
85 | end; | |
583a62df NF |
86 | Outer -> find(Outer, Name) |
87 | end | |
88 | end. |