@@ -13,15 +13,217 @@ impl Namespace {
13
13
pub fn new ( name : Symbol , mappings : RefCell < HashMap < Symbol , Rc < Value > > > ) -> Namespace {
14
14
Namespace { name, mappings }
15
15
}
16
+ pub fn from_sym ( name : Symbol ) -> Namespace {
17
+ Namespace :: new ( name, RefCell :: new ( HashMap :: new ( ) ) )
18
+ }
16
19
pub fn insert ( & self , sym : Symbol , val : Rc < Value > ) {
17
20
self . mappings . borrow_mut ( ) . insert ( sym, val) ;
18
21
}
19
22
pub fn get ( & self , sym : & Symbol ) -> Rc < Value > {
20
23
match self . mappings . borrow_mut ( ) . get ( sym) {
21
24
Some ( val) => Rc :: clone ( val) ,
22
- None => Rc :: new ( Value :: Condition ( format ! ( "Undefined symbol {}" , sym. name) ) ) ,
25
+ None => Rc :: new ( Value :: Condition ( format ! ( "1 Undefined symbol {}" , sym. name) ) ) ,
23
26
}
24
27
}
25
28
}
26
29
#[ derive( Debug , Clone ) ]
27
30
pub struct Namespaces ( pub RefCell < HashMap < Symbol , Namespace > > ) ;
31
+
32
+ impl Namespaces {
33
+ pub fn new ( ) -> Namespaces {
34
+ Namespaces ( RefCell :: new ( HashMap :: new ( ) ) )
35
+ }
36
+ /// Insert a new namespace of name (sym)
37
+ pub fn insert ( & self , sym : Symbol , namespace : Namespace ) {
38
+ // When storing / retrieving from namespaces, we want
39
+ // namespace unqualified keys
40
+ let sym = sym. unqualified ( ) ;
41
+ self . 0 . borrow_mut ( ) . insert ( sym, namespace) ;
42
+ }
43
+ pub fn has_namespace ( & self , namespace_sym : & Symbol ) -> bool {
44
+ let namespace_sym = namespace_sym. unqualified ( ) ;
45
+
46
+ let namespaces = self . 0 . borrow ( ) ;
47
+ let namespace = namespaces. get ( & namespace_sym) ;
48
+ match namespace {
49
+ Some ( _) => true ,
50
+ None => false
51
+ }
52
+ }
53
+ // @TODO Consider writing `sym` as reference here, because we clone it anyways
54
+ // Only reason to keep it is `inserts` are pass-by-value here normally,
55
+ // since the idea normally is you are literally inserting the keys too
56
+ // I'd prefer that consistency, unless we find it has a noticeable
57
+ // performance impact
58
+ /// Insert a binding (sym = val) *into* namespace (namespace)
59
+ pub fn insert_into_namespace ( & self , namespace_sym : & Symbol , sym : Symbol , val : Rc < Value > ) {
60
+ let mut namespace_sym = & namespace_sym. unqualified ( ) ;
61
+ // We will only use this if ns isn't ""
62
+ let symbol_namespace_sym = Symbol :: intern ( & sym. ns ) ;
63
+
64
+ if sym. ns != "" {
65
+ namespace_sym = & symbol_namespace_sym;
66
+ }
67
+
68
+ let namespaces = self . 0 . borrow ( ) ;
69
+ let namespace = namespaces. get ( namespace_sym) ;
70
+ match namespace {
71
+ Some ( namespace) => {
72
+ namespace. insert ( sym. unqualified ( ) , val) ;
73
+ } ,
74
+ None => {
75
+ drop ( namespaces) ;
76
+ let namespace = Namespace :: from_sym ( namespace_sym. clone ( ) ) ;
77
+ namespace. insert ( sym. unqualified ( ) , val) ;
78
+ self . insert ( namespace_sym. unqualified ( ) , namespace) ;
79
+ }
80
+ }
81
+ }
82
+ /// Get value of sym at namespace
83
+ pub fn get ( & self , namespace_sym : & Symbol , sym : & Symbol ) -> Rc < Value >
84
+ {
85
+ // When storing / retrieving from namespaces, we want
86
+ // namespace_sym unqualified keys
87
+ let mut namespace_sym = namespace_sym. unqualified ( ) ;
88
+
89
+ // @TODO just make it an Optional<String>
90
+ // If our sym is namespace qualified, use that as our namespace
91
+ if sym. ns != "" {
92
+ namespace_sym = Symbol :: intern ( & sym. ns ) ;
93
+ }
94
+
95
+ let sym = sym. unqualified ( ) ;
96
+ let namespaces = self . 0 . borrow ( ) ;
97
+ let namespace = namespaces. get ( & namespace_sym) ;
98
+
99
+ match namespace {
100
+ Some ( namespace) => Rc :: clone ( & namespace. get ( & sym) ) ,
101
+ // @TODO should this be a condition or nil?
102
+ _ => Rc :: new ( Value :: Condition ( format ! ( "Undefined symbol {}" , sym. name) ) ) ,
103
+ }
104
+
105
+ }
106
+ }
107
+
108
+ #[ cfg( test) ]
109
+ mod tests {
110
+
111
+ mod namespaces_tests {
112
+ use crate :: namespace:: Namespace ;
113
+ use crate :: namespace:: Namespaces ;
114
+ use crate :: symbol:: Symbol ;
115
+ use crate :: value:: Value ;
116
+ use std:: rc:: Rc ;
117
+
118
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
119
+ //
120
+ // pub fn get(&self,namespace_sym: &Symbol,sym: &Symbol) -> Rc<Value>
121
+ //
122
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
123
+ #[ test]
124
+ fn test_get_namespace__get_empty_and_fail ( ) {
125
+ let namespaces = Namespaces :: new ( ) ;
126
+ let clojure_core__plus = Symbol :: intern ( "clojure.core/+" ) ;
127
+ match & * namespaces. get ( & Symbol :: intern ( "clojure.your/+" ) , & clojure_core__plus) {
128
+ Value :: Condition ( cond) => { } ,
129
+ _ => { panic ! ( "Symbol {} somehow succeeded in {:#?}" , clojure_core__plus, namespaces) ; }
130
+ }
131
+ }
132
+
133
+ #[ test]
134
+ fn test_get_namespace__qualified_symbol_overriding_namespace ( ) {
135
+ let namespaces = Namespaces :: new ( ) ;
136
+
137
+ let clojure_core1__plus_1 = Symbol :: intern ( "clojure.core1/+1" ) ;
138
+ namespaces. insert_into_namespace (
139
+ & Symbol :: intern ( "clojure.core1" ) ,
140
+ Symbol :: intern ( "+1" ) ,
141
+ Rc :: new ( Value :: Nil )
142
+ ) ;
143
+ match & * namespaces. get ( & Symbol :: intern ( "clojure.your" ) , & clojure_core1__plus_1) {
144
+ Value :: Condition ( cond) => {
145
+ panic ! ( "Symbol {} somehow failed in {:#?}" , clojure_core1__plus_1, namespaces) ;
146
+ } ,
147
+ _ => { assert ! ( true ) ; }
148
+ }
149
+ }
150
+
151
+ #[ test]
152
+ fn test_get_namespace__overwritten_namespace_again ( ) {
153
+ let namespaces = Namespaces :: new ( ) ;
154
+
155
+ let clojure_core__plus = Symbol :: intern ( "clojure.core/+" ) ;
156
+ namespaces. insert_into_namespace (
157
+ & Symbol :: intern ( "clojure.core" ) ,
158
+ Symbol :: intern ( "+" ) ,
159
+ Rc :: new ( Value :: Nil )
160
+ ) ;
161
+ // Really means get +/+, but is overwritten to mean get clojure.core/+
162
+ match & * namespaces. get ( & Symbol :: intern ( "clojure.core/+" ) , & clojure_core__plus) {
163
+ Value :: Condition ( cond) => { panic ! ( "Symbol {} somehow failed in {:#?}" , clojure_core__plus, namespaces) ; } ,
164
+ _ => { }
165
+ }
166
+
167
+ }
168
+
169
+ #[ test]
170
+ fn test_get_namespace__namespace_symbol_and_symbol_separate ( ) {
171
+ let namespaces = Namespaces :: new ( ) ;
172
+
173
+
174
+ // add namespace core2/+2
175
+ let plus_2 = Symbol :: intern ( "+2" ) ;
176
+ namespaces. insert_into_namespace (
177
+ & Symbol :: intern ( "core2" ) ,
178
+ Symbol :: intern ( "+2" ) ,
179
+ Rc :: new ( Value :: Nil )
180
+ ) ;
181
+ // Get intern("core2/+2")
182
+ // ----------------------
183
+ // Here is the part where namespace symbol and symbol are separate;
184
+ // rather than having &plus_2 qualified fully as 'core2/+2'
185
+ // ---------------------
186
+ // Should succeed
187
+ match & * namespaces. get ( & Symbol :: intern ( "core2" ) , & plus_2) {
188
+ Value :: Condition ( cond) => {
189
+ panic ! ( "Symbol {} somehow failed in {:#?}" , & plus_2, namespaces) ;
190
+ } ,
191
+ _ => { assert ! ( true ) ; }
192
+ }
193
+ }
194
+ #[ test]
195
+ fn test_get_namespace__wrong_ns_right_name ( ) {
196
+ let namespaces = Namespaces :: new ( ) ;
197
+ namespaces. insert_into_namespace (
198
+ & Symbol :: intern ( "core2" ) ,
199
+ Symbol :: intern ( "+2" ) ,
200
+ Rc :: new ( Value :: Nil )
201
+ ) ;
202
+
203
+ let plus_2 = Symbol :: intern ( "+2" ) ;
204
+ // get intern("core1/+2")
205
+ // Should fail
206
+ match & * namespaces. get ( & Symbol :: intern ( "clojure.core1" ) , & plus_2) {
207
+ Value :: Condition ( cond) => {
208
+ assert ! ( true ) ;
209
+ } ,
210
+ _ => { panic ! ( "Symbol {} somehow failed in {:#?}" , & plus_2, namespaces) ; }
211
+ }
212
+
213
+ // Make sure it normally works
214
+ // get intern("core2/+2")
215
+ // Should succeed
216
+ match & * namespaces. get ( & Symbol :: intern ( "core2" ) , & plus_2) {
217
+ Value :: Condition ( cond) => {
218
+ panic ! ( "Symbol {} somehow failed in {:#?}" , & plus_2, namespaces) ;
219
+ } ,
220
+ _ => { assert ! ( true ) ; }
221
+ }
222
+ }
223
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
224
+ //
225
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
226
+
227
+ //let namespaces.insert_into_namespace(&Symbol::intern("clojure.core/+"), , ${3:val: Rc<Value>})
228
+ }
229
+ }
0 commit comments