Skip to content

Commit 54d6e40

Browse files
committed
Merge branch 'feature/namespaces/refers' so far ( (ns 'blah), (refer
'ns), (refer 'ns :only '[a b c]))
2 parents 735ca1b + 20af47b commit 54d6e40

File tree

10 files changed

+991
-40
lines changed

10 files changed

+991
-40
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ rand = "0.7"
1313
itertools= "0.9"
1414
url = "2.1.1"
1515
regex = "1.3.7"
16+
if_chain = "1.0"
1617
reqwest = { version = "0.10.4", features = ["blocking"] }

src/environment.rs

Lines changed: 87 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,48 @@ pub struct EnvironmentVal {
2323
namespaces: Namespaces,
2424
}
2525
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
2629
fn change_namespace(&self, name: Symbol) {
2730
self.curr_ns_sym.replace(name);
2831
}
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);
3150
}
3251
fn insert_into_current_namespace(&self, sym: Symbol, val: Rc<Value>) {
3352
self.namespaces
3453
.insert_into_namespace(&*self.curr_ns_sym.borrow(), &sym, val);
3554
}
55+
fn has_namespace(&self, namespace: &Symbol) -> bool {
56+
self.namespaces.has_namespace(namespace)
57+
}
3658
fn get_from_namespace(&self, namespace: &Symbol, sym: &Symbol) -> Rc<Value> {
3759
self.namespaces.get(namespace, sym)
3860
}
3961
fn get_current_namespace(&self) -> Symbol {
4062
self.curr_ns_sym.borrow().clone()
4163
}
64+
65+
fn create_namespace(&self, symbol: &Symbol) {
66+
self.namespaces.create_namespace(symbol);
67+
}
4268
// @TODO as mentioned, we've been working with a memory model where values exist
4369
// in our system once-ish and we reference them all over with Rc<..>
4470
// Look into possibly working this into that (if its even significant);
@@ -68,16 +94,60 @@ pub enum Environment {
6894
}
6995
use Environment::*;
7096
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 {
7498
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);
77110
}
78111
LocalEnvironment(..) => panic!(
79112
"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"
81151
),
82152
}
83153
}
@@ -155,14 +225,11 @@ impl Environment {
155225
MainEnvironment(env_val) => {
156226
// If we've recieved a qualified symbol like
157227
// clojure.core/+
158-
if sym.ns != "" {
228+
if sym.has_ns() {
159229
// Use that namespace
160230
env_val.get_from_namespace(&Symbol::intern(&sym.ns), sym)
161231
} 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)
166233
}
167234
}
168235
LocalEnvironment(parent_env, mappings) => {
@@ -239,10 +306,11 @@ impl Environment {
239306
let eval_fn = rust_core::EvalFn::new(Rc::clone(&environment));
240307
let ns_macro = rust_core::NsMacro::new(Rc::clone(&environment));
241308
let load_file_fn = rust_core::LoadFileFn::new(Rc::clone(&environment));
309+
let refer_fn = rust_core::ReferFn::new(Rc::clone(&environment));
242310
// @TODO after we merge this with all the other commits we have,
243311
// just change all the `insert`s here to use insert_in_namespace
244312
// 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"));
246314

247315
environment.insert(Symbol::intern("+"), add_fn.to_rc_value());
248316
environment.insert(Symbol::intern("-"), subtract_fn.to_rc_value());
@@ -402,6 +470,8 @@ impl Environment {
402470
environment.insert(Symbol::intern("read-line"), read_line_fn.to_rc_value());
403471

404472
environment.insert(Symbol::intern("="), equals_fn.to_rc_value());
473+
environment.insert(Symbol::intern("refer"), refer_fn.to_rc_value());
474+
405475
//
406476
// Read in clojure.core
407477
//
@@ -411,7 +481,7 @@ impl Environment {
411481
let _ = Repl::new(Rc::clone(&environment)).try_eval_file("./src/clojure/string.clj");
412482

413483
// 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"));
415485

416486
environment
417487
}
@@ -437,11 +507,11 @@ mod tests {
437507

438508
assert_eq!(Symbol::intern("user"), env_val.get_current_namespace());
439509

440-
env_val.change_namespace(Symbol::intern("core"));
510+
env_val.change_or_create_namespace(&Symbol::intern("core"));
441511
assert_eq!(Symbol::intern("core"), env_val.get_current_namespace());
442512

443513
// @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"));
445515
// assert_eq!(Symbol::intern("ns"),env_val.get_current_namespace())
446516

447517
// @TODO add case for local environment

src/error_message.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::type_tag::TypeTag;
22
use crate::value::Value;
33
use std::error::Error;
4+
use std::fmt;
45

56
pub fn type_mismatch(expected: TypeTag, got: &Value) -> Value {
67
Value::Condition(format!(

src/keyword.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ pub struct Keyword {
88
pub sym: Symbol,
99
}
1010
impl Keyword {
11+
pub fn name(&self) -> &str {
12+
self.sym.name()
13+
}
1114
pub fn intern(name: &str) -> Keyword {
1215
Keyword {
1316
sym: Symbol::intern(name),

0 commit comments

Comments
 (0)