Skip to content

Commit bb46283

Browse files
committed
Refactored namespace, added test coverage, cleaned up test names
1 parent 92c989a commit bb46283

File tree

2 files changed

+163
-32
lines changed

2 files changed

+163
-32
lines changed

src/environment.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ impl EnvironmentVal {
2626
self.curr_ns_sym.replace(name);
2727
}
2828
fn insert_into_namespace(&self, namespace: &Symbol, sym: Symbol, val: Rc<Value>) {
29-
self.namespaces.insert_into_namespace(namespace, sym, val);
29+
self.namespaces.insert_into_namespace(namespace, &sym, val);
3030
}
3131
fn insert_into_current_namespace(&self, sym: Symbol, val: Rc<Value>) {
3232
self.namespaces
33-
.insert_into_namespace(&*self.curr_ns_sym.borrow(), sym, val);
33+
.insert_into_namespace(&*self.curr_ns_sym.borrow(), &sym, val);
3434
}
3535
fn get_from_namespace(&self, namespace: &Symbol, sym: &Symbol) -> Rc<Value> {
3636
self.namespaces.get(namespace, sym)
@@ -44,9 +44,8 @@ impl EnvironmentVal {
4444
/// Default main environment
4545
fn new_main_val() -> EnvironmentVal {
4646
let curr_ns_sym = Symbol::intern("user");
47-
let curr_ns = Namespace::from_sym(curr_ns_sym.clone());
48-
let namespaces = Namespaces(RefCell::new(HashMap::new()));
49-
namespaces.insert(curr_ns_sym.clone(), curr_ns);
47+
let namespaces = Namespaces::new();
48+
namespaces.create_namespace(&curr_ns_sym);
5049
EnvironmentVal {
5150
curr_ns_sym: RefCell::new(curr_ns_sym),
5251
namespaces,

src/namespace.rs

Lines changed: 159 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,17 @@ pub struct Namespace {
1010
mappings: RefCell<HashMap<Symbol, Rc<Value>>>,
1111
}
1212
impl Namespace {
13-
pub fn new(name: Symbol, mappings: RefCell<HashMap<Symbol, Rc<Value>>>) -> Namespace {
14-
Namespace { name, mappings }
13+
pub fn new(name: &Symbol, mappings: RefCell<HashMap<Symbol, Rc<Value>>>) -> Namespace {
14+
Namespace { name: name.unqualified(), mappings }
1515
}
16-
pub fn from_sym(name: Symbol) -> Namespace {
16+
pub fn from_sym(name: &Symbol) -> Namespace {
1717
Namespace::new(name, RefCell::new(HashMap::new()))
1818
}
19-
pub fn insert(&self, sym: Symbol, val: Rc<Value>) {
20-
self.mappings.borrow_mut().insert(sym, val);
19+
pub fn insert(&self, sym: &Symbol, val: Rc<Value>) {
20+
self.mappings.borrow_mut().insert(sym.unqualified(), val);
2121
}
2222
pub fn get(&self, sym: &Symbol) -> Rc<Value> {
23-
match self.mappings.borrow_mut().get(sym) {
23+
match self.mappings.borrow_mut().get(&sym.unqualified()) {
2424
Some(val) => Rc::clone(val),
2525
None => Rc::new(Value::Condition(format!("1 Undefined symbol {}", sym.name))),
2626
}
@@ -33,13 +33,17 @@ impl Namespaces {
3333
pub fn new() -> Namespaces {
3434
Namespaces(RefCell::new(HashMap::new()))
3535
}
36-
/// Insert a new namespace of name (sym)
37-
pub fn insert(&self, sym: Symbol, namespace: Namespace) {
36+
fn insert(&self, namespace: Namespace) {
3837
// When storing / retrieving from namespaces, we want
3938
// namespace unqualified keys
40-
let sym = sym.unqualified();
41-
self.0.borrow_mut().insert(sym, namespace);
39+
self.0.borrow_mut().insert(namespace.name.unqualified(), namespace);
4240
}
41+
/// Adds a new namespace to internal HashMap (but does
42+
/// *not* return a Namespace or reference to one)
43+
pub fn create_namespace(&self,sym: &Symbol){
44+
self.insert(Namespace::from_sym(sym));
45+
}
46+
/// Insert a new namespace of name (sym)
4347
pub fn has_namespace(&self, namespace_sym: &Symbol) -> bool {
4448
let namespace_sym = namespace_sym.unqualified();
4549

@@ -50,32 +54,28 @@ impl Namespaces {
5054
None => false,
5155
}
5256
}
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
5857
/// Insert a binding (sym = val) *into* namespace (namespace)
59-
pub fn insert_into_namespace(&self, namespace_sym: &Symbol, sym: Symbol, val: Rc<Value>) {
58+
/// If namespace doesn't exist, create it
59+
pub fn insert_into_namespace(&self, namespace_sym: &Symbol, sym: &Symbol, val: Rc<Value>) {
6060
let mut namespace_sym = &namespace_sym.unqualified();
6161
// We will only use this if ns isn't ""
6262
let symbol_namespace_sym = Symbol::intern(&sym.ns);
6363

64-
if sym.ns != "" {
64+
if sym.has_ns() {
6565
namespace_sym = &symbol_namespace_sym;
6666
}
6767

6868
let namespaces = self.0.borrow();
6969
let namespace = namespaces.get(namespace_sym);
7070
match namespace {
7171
Some(namespace) => {
72-
namespace.insert(sym.unqualified(), val);
72+
namespace.insert(sym, val);
7373
}
7474
None => {
7575
drop(namespaces);
76-
let namespace = Namespace::from_sym(namespace_sym.clone());
77-
namespace.insert(sym.unqualified(), val);
78-
self.insert(namespace_sym.unqualified(), namespace);
76+
let namespace = Namespace::from_sym(namespace_sym);
77+
namespace.insert(sym, val);
78+
self.insert(namespace);
7979
}
8080
}
8181
}
@@ -87,7 +87,7 @@ impl Namespaces {
8787

8888
// @TODO just make it an Optional<String>
8989
// If our sym is namespace qualified, use that as our namespace
90-
if sym.ns != "" {
90+
if sym.has_ns() {
9191
namespace_sym = Symbol::intern(&sym.ns);
9292
}
9393

@@ -105,13 +105,145 @@ impl Namespaces {
105105

106106
#[cfg(test)]
107107
mod tests {
108+
// 'Struct' here because its not immediately clear why, when testing this,
109+
// why the word 'namespace' is repeated and that this is actually specifically
110+
// a struct
111+
mod namespace_struct {
112+
use crate::namespace::Namespace;
113+
use crate::symbol::Symbol;
114+
use crate::value::Value;
115+
use std::rc::Rc;
116+
use std::cell::RefCell;
117+
use std::collections::HashMap;
118+
119+
#[test]
120+
fn new() {
121+
let namespace = Namespace::new(&Symbol::intern("a"),RefCell::new(HashMap::new()));
122+
assert_eq!(namespace.name, Symbol::intern("a"));
123+
assert!(namespace.mappings.borrow().is_empty());
124+
}
125+
126+
#[test]
127+
fn new_removes_namespace_from_qualified_symbol() {
128+
let namespace = Namespace::new(&Symbol::intern_with_ns("ns","a"),RefCell::new(HashMap::new()));
129+
assert_eq!(namespace.name, Symbol::intern("a"));
130+
assert!(namespace.name != Symbol::intern_with_ns("ns","a"));
131+
assert!(namespace.mappings.borrow().is_empty());
132+
}
133+
#[test]
134+
fn new_namespace_starts_empty() {
135+
let namespace = Namespace::new(&Symbol::intern("a"),RefCell::new(HashMap::new()));
136+
let namespace2 = Namespace::new(&Symbol::intern_with_ns("ns","b"),RefCell::new(HashMap::new()));
137+
assert!(namespace.mappings.borrow().is_empty());
138+
assert!(namespace2.mappings.borrow().is_empty());
139+
}
140+
141+
#[test]
142+
fn from_sym() {
143+
let namespace = Namespace::from_sym(&Symbol::intern_with_ns("ns","name"));
144+
assert_eq!(namespace.name,Symbol::intern("name"));
145+
assert!(namespace.name != Symbol::intern_with_ns("ns","name"));
146+
assert!(namespace.mappings.borrow().is_empty());
147+
}
148+
#[test]
149+
fn insert() {
150+
let namespace = Namespace::from_sym(&Symbol::intern("name"));
151+
namespace.insert(&Symbol::intern("a"),Rc::new(Value::Nil));
152+
namespace.insert(&Symbol::intern_with_ns("ns","b"),Rc::new(Value::Nil));
153+
assert_eq!(namespace.name,Symbol::intern("name"));
154+
assert!(namespace.name != Symbol::intern("ns"));
155+
assert!(namespace.name != Symbol::intern_with_ns("ns","name"));
156+
157+
namespace.insert(&Symbol::intern("c"),Rc::new(Value::Nil));
158+
match &*namespace.get(&Symbol::intern("c")) {
159+
Value::Condition(_) => panic!("We are unable to get a symbol we've put into our namespace created with from_sym()"),
160+
_ => {}
161+
}
162+
}
163+
164+
#[test]
165+
fn get() {
166+
let namespace = Namespace::from_sym(&Symbol::intern("name"));
167+
namespace.insert(&Symbol::intern("a"),Rc::new(Value::Nil));
168+
namespace.insert(&Symbol::intern_with_ns("ns","b"),Rc::new(Value::Nil));
169+
match &*namespace.get(&Symbol::intern("a")) {
170+
Value::Condition(_) => panic!("We are unable to get a symbol we've put into our namespace created with from_sym()"),
171+
_ => {}
172+
}
108173

109-
mod namespaces {
174+
match &*namespace.get(&Symbol::intern("b")) {
175+
Value::Condition(_) => panic!("We are unable to get a symbol we've put into our namespace created with from_sym()"),
176+
_ => {}
177+
}
178+
179+
match &*namespace.get(&Symbol::intern("ns")) {
180+
Value::Condition(_) => {}
181+
_ => panic!("We are able to get a symbol whose name is the namespace of another symbol we inserted (and note, that namesapce should be dropped altogether on insert)"),
182+
}
183+
184+
match &*namespace.get(&Symbol::intern("sassafrass")) {
185+
Value::Condition(_) => {}
186+
_ => panic!("We are able to get a symbol we didn't insert without a Condition being thrown"),
187+
}
188+
189+
match &*namespace.get(&Symbol::intern_with_ns("ns","b")) {
190+
Value::Condition(_) => panic!("We are unable to get a symbol by trying to get a namespace qualified version of it (the namespace normally should be irrelevant and automatically drop)"),
191+
_ => {}
192+
}
193+
194+
match &*namespace.get(&Symbol::intern_with_ns("chicken","a")) {
195+
Value::Condition(_) => panic!("We are unable to get a symbol by trying to get a namespace qualified (with a random namespace) version of it (the namespace normally should be irrelevant and automatically drop)"),
196+
_ => {}
197+
}
198+
}
199+
}
200+
mod namespaces_newtype {
201+
use crate::namespace::Namespace;
110202
use crate::namespace::Namespaces;
111203
use crate::symbol::Symbol;
112204
use crate::value::Value;
113205
use std::rc::Rc;
206+
fn new() {
207+
let namespaces = Namespaces::new();
208+
assert!(namespaces.0.borrow().is_empty());
209+
}
210+
fn insert() {
211+
let namespaces = Namespaces::new();
212+
let namespace = Namespace::from_sym(&Symbol::intern("clojure.core"));
213+
namespace.insert(&Symbol::intern("+"),Rc::new(Value::Nil));
214+
// Namespace should be dropped; doesn't matter when inserting into
215+
// a namespace
216+
namespace.insert(&Symbol::intern_with_ns("clojure.math","+"),Rc::new(Value::Nil));
217+
/////////////////////////////////////////////////////////////
218+
namespaces.insert(namespace);
114219

220+
assert_eq!(Value::Nil,*namespaces.get(&Symbol::intern("clojure.core"),&Symbol::intern("+")));
221+
assert_eq!(Value::Nil,*namespaces.get(&Symbol::intern_with_ns("ns-doesn't-matter","clojure.core"),&Symbol::intern("+")));
222+
assert_eq!(Value::Nil,*namespaces.get(&Symbol::intern_with_ns("ns-doesn't-matter","clojure.core"),&Symbol::intern_with_ns("ns-still-doesn't-matter","+")));
223+
//Ie, we should get a Condition, because there is no clojure.math/+
224+
assert!(Value::Nil != *namespaces.get(&Symbol::intern("clojure.math"),&Symbol::intern("+")));
225+
}
226+
fn has_namespace() {
227+
let namespaces = Namespaces::new();
228+
let namespace = Namespace::from_sym(&Symbol::intern("clojure.core"));
229+
namespace.insert(&Symbol::intern("+"),Rc::new(Value::Nil));
230+
231+
assert!(namespaces.has_namespace(&Symbol::intern("clojure.core")));
232+
assert!(namespaces.has_namespace(&Symbol::intern_with_ns("ns-doesn't-matter","clojure.core")));
233+
assert!(!namespaces.has_namespace(&Symbol::intern("+")));
234+
// Note; ns-doesn't-matter *isn't* the namespace this time
235+
assert!(!namespaces.has_namespace(&Symbol::intern_with_ns("clojure.core","ns-doesn't-matter")));
236+
}
237+
fn insert_into_namespace() {
238+
let namespaces = Namespaces::new();
239+
namespaces.insert_into_namespace(&Symbol::intern("clojure.core"), &Symbol::intern("+"), Rc::new(Value::Nil));
240+
assert!(!namespaces.has_namespace(&Symbol::intern("random_ns")));
241+
assert!(namespaces.has_namespace(&Symbol::intern("clojure.core")));
242+
243+
assert_eq!(Value::Nil, *namespaces.get(&Symbol::intern("clojure.core"),&Symbol::intern("+")));
244+
assert!(Value::Nil != *namespaces.get(&Symbol::intern("clojure.core"),&Symbol::intern("other-sym")));
245+
assert!(Value::Nil != *namespaces.get(&Symbol::intern("other-ns"),&Symbol::intern("+")));
246+
}
115247
////////////////////////////////////////////////////////////////////////////////////////////////////
116248
//
117249
// pub fn get(&self,namespace_sym: &Symbol,sym: &Symbol) -> Rc<Value>
@@ -139,7 +271,7 @@ mod tests {
139271
let clojure_core1_plus_1 = Symbol::intern("clojure.core1/+1");
140272
namespaces.insert_into_namespace(
141273
&Symbol::intern("clojure.core1"),
142-
Symbol::intern("+1"),
274+
&Symbol::intern("+1"),
143275
Rc::new(Value::Nil),
144276
);
145277
match &*namespaces.get(&Symbol::intern("clojure.your"), &clojure_core1_plus_1) {
@@ -162,7 +294,7 @@ mod tests {
162294
let clojure_core_plus = Symbol::intern("clojure.core/+");
163295
namespaces.insert_into_namespace(
164296
&Symbol::intern("clojure.core"),
165-
Symbol::intern("+"),
297+
&Symbol::intern("+"),
166298
Rc::new(Value::Nil),
167299
);
168300
// Really means get +/+, but is overwritten to mean get clojure.core/+
@@ -185,7 +317,7 @@ mod tests {
185317
let plus_2 = Symbol::intern("+2");
186318
namespaces.insert_into_namespace(
187319
&Symbol::intern("core2"),
188-
Symbol::intern("+2"),
320+
&Symbol::intern("+2"),
189321
Rc::new(Value::Nil),
190322
);
191323
// Get intern("core2/+2")
@@ -208,7 +340,7 @@ mod tests {
208340
let namespaces = Namespaces::new();
209341
namespaces.insert_into_namespace(
210342
&Symbol::intern("core2"),
211-
Symbol::intern("+2"),
343+
&Symbol::intern("+2"),
212344
Rc::new(Value::Nil),
213345
);
214346

0 commit comments

Comments
 (0)