@@ -23,22 +23,48 @@ pub struct EnvironmentVal {
23
23
namespaces : Namespaces ,
24
24
}
25
25
impl EnvironmentVal {
26
+ // @TODO is this wrapper really necessary, or is it just inviting an invariant break?
27
+ /// Note; do not use. Does not enforce the invariant that namespace exist
28
+ /// Use change_or_create_namespace instead
26
29
fn change_namespace ( & self , name : Symbol ) {
27
30
self . curr_ns_sym . replace ( name) ;
28
31
}
29
- fn insert_into_namespace ( & self , namespace : & Symbol , sym : Symbol , val : Rc < Value > ) {
30
- self . namespaces . insert_into_namespace ( namespace, & sym, val) ;
32
+ fn change_or_create_namespace ( & self , symbol : & Symbol ) {
33
+ if self . has_namespace ( symbol) {
34
+ self . change_namespace ( symbol. unqualified ( ) ) ;
35
+ } else {
36
+ self . create_namespace ( symbol) ;
37
+ self . change_namespace ( symbol. unqualified ( ) ) ;
38
+ }
39
+ }
40
+ fn add_referred_syms ( & self , namespace_sym : & Symbol , syms : HashMap < Symbol , Vec < Symbol > > ) {
41
+ self . namespaces . add_referred_syms ( namespace_sym, syms) ;
42
+ }
43
+ fn add_referred_namespace ( & self , namespace_sym : & Symbol , referred_namespace_sym : & Symbol ) {
44
+ self . namespaces
45
+ . add_referred_namespace ( namespace_sym, referred_namespace_sym) ;
46
+ }
47
+ fn insert_into_namespace ( & self , namespace_sym : & Symbol , sym : Symbol , val : Rc < Value > ) {
48
+ self . namespaces
49
+ . insert_into_namespace ( namespace_sym, & sym, val) ;
31
50
}
32
51
fn insert_into_current_namespace ( & self , sym : Symbol , val : Rc < Value > ) {
33
52
self . namespaces
34
53
. insert_into_namespace ( & * self . curr_ns_sym . borrow ( ) , & sym, val) ;
35
54
}
55
+ fn has_namespace ( & self , namespace : & Symbol ) -> bool {
56
+ self . namespaces . has_namespace ( namespace)
57
+ }
36
58
fn get_from_namespace ( & self , namespace : & Symbol , sym : & Symbol ) -> Rc < Value > {
37
59
self . namespaces . get ( namespace, sym)
38
60
}
39
61
fn get_current_namespace ( & self ) -> Symbol {
40
62
self . curr_ns_sym . borrow ( ) . clone ( )
41
63
}
64
+
65
+ fn create_namespace ( & self , symbol : & Symbol ) {
66
+ self . namespaces . create_namespace ( symbol) ;
67
+ }
42
68
// @TODO as mentioned, we've been working with a memory model where values exist
43
69
// in our system once-ish and we reference them all over with Rc<..>
44
70
// Look into possibly working this into that (if its even significant);
@@ -68,16 +94,60 @@ pub enum Environment {
68
94
}
69
95
use Environment :: * ;
70
96
impl Environment {
71
- pub fn change_namespace ( & self , symbol : Symbol ) {
72
- let symbol = symbol. unqualified ( ) ;
73
-
97
+ pub fn has_namespace ( & self , symbol : & Symbol ) -> bool {
74
98
match self . get_main_environment ( ) {
75
- MainEnvironment ( EnvironmentVal { curr_ns_sym, .. } ) => {
76
- curr_ns_sym. replace ( symbol) ;
99
+ MainEnvironment ( env_val) => env_val. has_namespace ( symbol) ,
100
+ LocalEnvironment ( ..) => panic ! (
101
+ "get_main_environment() returns LocalEnvironment,\
102
+ but by definition should only return MainEnvironment"
103
+ ) ,
104
+ }
105
+ }
106
+ pub fn add_referred_syms ( & self , namespace_sym : & Symbol , syms : HashMap < Symbol , Vec < Symbol > > ) {
107
+ match self . get_main_environment ( ) {
108
+ MainEnvironment ( env_val) => {
109
+ env_val. add_referred_syms ( namespace_sym, syms) ;
77
110
}
78
111
LocalEnvironment ( ..) => panic ! (
79
112
"get_main_environment() returns LocalEnvironment,\
80
- but by definition should only return MainEnvironment"
113
+ but by definition should only return MainEnvironment"
114
+ ) ,
115
+ }
116
+ }
117
+ pub fn add_referred_syms_to_curr_namespace ( & self , syms : HashMap < Symbol , Vec < Symbol > > ) {
118
+ match self . get_main_environment ( ) {
119
+ MainEnvironment ( env_val) => {
120
+ let namespace_sym = self . get_current_namespace ( ) ;
121
+ env_val. add_referred_syms ( & namespace_sym, syms) ;
122
+ }
123
+ LocalEnvironment ( ..) => panic ! (
124
+ "get_main_environment() returns LocalEnvironment,\
125
+ but by definition should only return MainEnvironment"
126
+ ) ,
127
+ }
128
+ }
129
+ pub fn add_referred_namespace_to_curr_namespace ( & self , referred_namespace_sym : & Symbol ) {
130
+ match self . get_main_environment ( ) {
131
+ MainEnvironment ( env_val) => {
132
+ let namespace_sym = self . get_current_namespace ( ) ;
133
+ env_val. add_referred_namespace ( & namespace_sym, referred_namespace_sym) ;
134
+ }
135
+ LocalEnvironment ( ..) => panic ! (
136
+ "get_main_environment() returns LocalEnvironment,\
137
+ but by definition should only return MainEnvironment"
138
+ ) ,
139
+ }
140
+ }
141
+ /// Changes the current namespace, or creates one first if
142
+ /// namespace doesn't already exist
143
+ pub fn change_or_create_namespace ( & self , symbol : & Symbol ) {
144
+ match self . get_main_environment ( ) {
145
+ MainEnvironment ( env_val) => {
146
+ env_val. change_or_create_namespace ( symbol) ;
147
+ }
148
+ LocalEnvironment ( ..) => panic ! (
149
+ "get_main_environment() returns LocalEnvironment,\
150
+ but by definition should only return MainEnvironment"
81
151
) ,
82
152
}
83
153
}
@@ -155,14 +225,11 @@ impl Environment {
155
225
MainEnvironment ( env_val) => {
156
226
// If we've recieved a qualified symbol like
157
227
// clojure.core/+
158
- if sym. ns != "" {
228
+ if sym. has_ns ( ) {
159
229
// Use that namespace
160
230
env_val. get_from_namespace ( & Symbol :: intern ( & sym. ns ) , sym)
161
231
} else {
162
- env_val. get_from_namespace (
163
- & env_val. get_current_namespace ( ) ,
164
- & Symbol :: intern ( & sym. name ) ,
165
- )
232
+ env_val. get_from_namespace ( & env_val. get_current_namespace ( ) , & sym)
166
233
}
167
234
}
168
235
LocalEnvironment ( parent_env, mappings) => {
@@ -239,10 +306,11 @@ impl Environment {
239
306
let eval_fn = rust_core:: EvalFn :: new ( Rc :: clone ( & environment) ) ;
240
307
let ns_macro = rust_core:: NsMacro :: new ( Rc :: clone ( & environment) ) ;
241
308
let load_file_fn = rust_core:: LoadFileFn :: new ( Rc :: clone ( & environment) ) ;
309
+ let refer_fn = rust_core:: ReferFn :: new ( Rc :: clone ( & environment) ) ;
242
310
// @TODO after we merge this with all the other commits we have,
243
311
// just change all the `insert`s here to use insert_in_namespace
244
312
// I prefer explicity and the non-dependence-on-environmental-factors
245
- environment. change_namespace ( Symbol :: intern ( "clojure.core" ) ) ;
313
+ environment. change_or_create_namespace ( & Symbol :: intern ( "clojure.core" ) ) ;
246
314
247
315
environment. insert ( Symbol :: intern ( "+" ) , add_fn. to_rc_value ( ) ) ;
248
316
environment. insert ( Symbol :: intern ( "-" ) , subtract_fn. to_rc_value ( ) ) ;
@@ -402,6 +470,8 @@ impl Environment {
402
470
environment. insert ( Symbol :: intern ( "read-line" ) , read_line_fn. to_rc_value ( ) ) ;
403
471
404
472
environment. insert ( Symbol :: intern ( "=" ) , equals_fn. to_rc_value ( ) ) ;
473
+ environment. insert ( Symbol :: intern ( "refer" ) , refer_fn. to_rc_value ( ) ) ;
474
+
405
475
//
406
476
// Read in clojure.core
407
477
//
@@ -411,7 +481,7 @@ impl Environment {
411
481
let _ = Repl :: new ( Rc :: clone ( & environment) ) . try_eval_file ( "./src/clojure/string.clj" ) ;
412
482
413
483
// We can add this back once we have requires
414
- // environment.change_namespace (Symbol::intern("user"));
484
+ // environment.change_or_create_namespace (Symbol::intern("user"));
415
485
416
486
environment
417
487
}
@@ -437,11 +507,11 @@ mod tests {
437
507
438
508
assert_eq ! ( Symbol :: intern( "user" ) , env_val. get_current_namespace( ) ) ;
439
509
440
- env_val. change_namespace ( Symbol :: intern ( "core" ) ) ;
510
+ env_val. change_or_create_namespace ( & Symbol :: intern ( "core" ) ) ;
441
511
assert_eq ! ( Symbol :: intern( "core" ) , env_val. get_current_namespace( ) ) ;
442
512
443
513
// @TODO add this invariant back next, and remove this comment; 5.9.2020
444
- // env_val.change_namespace (Symbol::intern_with_ns("not-ns","ns"));
514
+ // env_val.change_or_create_namespace (Symbol::intern_with_ns("not-ns","ns"));
445
515
// assert_eq!(Symbol::intern("ns"),env_val.get_current_namespace())
446
516
447
517
// @TODO add case for local environment
0 commit comments