Skip to content

Commit

Permalink
Merge branch 'feature/namespaces/refers' so far ( (ns 'blah), (refer
Browse files Browse the repository at this point in the history
'ns), (refer 'ns :only '[a b c]))
  • Loading branch information
Tko1 committed Jun 3, 2020
2 parents 735ca1b + 20af47b commit 54d6e40
Show file tree
Hide file tree
Showing 10 changed files with 991 additions and 40 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ rand = "0.7"
itertools= "0.9"
url = "2.1.1"
regex = "1.3.7"
if_chain = "1.0"
reqwest = { version = "0.10.4", features = ["blocking"] }
104 changes: 87 additions & 17 deletions src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,48 @@ pub struct EnvironmentVal {
namespaces: Namespaces,
}
impl EnvironmentVal {
// @TODO is this wrapper really necessary, or is it just inviting an invariant break?
/// Note; do not use. Does not enforce the invariant that namespace exist
/// Use change_or_create_namespace instead
fn change_namespace(&self, name: Symbol) {
self.curr_ns_sym.replace(name);
}
fn insert_into_namespace(&self, namespace: &Symbol, sym: Symbol, val: Rc<Value>) {
self.namespaces.insert_into_namespace(namespace, &sym, val);
fn change_or_create_namespace(&self, symbol: &Symbol) {
if self.has_namespace(symbol) {
self.change_namespace(symbol.unqualified());
} else {
self.create_namespace(symbol);
self.change_namespace(symbol.unqualified());
}
}
fn add_referred_syms(&self, namespace_sym: &Symbol, syms: HashMap<Symbol, Vec<Symbol>>) {
self.namespaces.add_referred_syms(namespace_sym, syms);
}
fn add_referred_namespace(&self, namespace_sym: &Symbol, referred_namespace_sym: &Symbol) {
self.namespaces
.add_referred_namespace(namespace_sym, referred_namespace_sym);
}
fn insert_into_namespace(&self, namespace_sym: &Symbol, sym: Symbol, val: Rc<Value>) {
self.namespaces
.insert_into_namespace(namespace_sym, &sym, val);
}
fn insert_into_current_namespace(&self, sym: Symbol, val: Rc<Value>) {
self.namespaces
.insert_into_namespace(&*self.curr_ns_sym.borrow(), &sym, val);
}
fn has_namespace(&self, namespace: &Symbol) -> bool {
self.namespaces.has_namespace(namespace)
}
fn get_from_namespace(&self, namespace: &Symbol, sym: &Symbol) -> Rc<Value> {
self.namespaces.get(namespace, sym)
}
fn get_current_namespace(&self) -> Symbol {
self.curr_ns_sym.borrow().clone()
}

fn create_namespace(&self, symbol: &Symbol) {
self.namespaces.create_namespace(symbol);
}
// @TODO as mentioned, we've been working with a memory model where values exist
// in our system once-ish and we reference them all over with Rc<..>
// Look into possibly working this into that (if its even significant);
Expand Down Expand Up @@ -68,16 +94,60 @@ pub enum Environment {
}
use Environment::*;
impl Environment {
pub fn change_namespace(&self, symbol: Symbol) {
let symbol = symbol.unqualified();

pub fn has_namespace(&self, symbol: &Symbol) -> bool {
match self.get_main_environment() {
MainEnvironment(EnvironmentVal { curr_ns_sym, .. }) => {
curr_ns_sym.replace(symbol);
MainEnvironment(env_val) => env_val.has_namespace(symbol),
LocalEnvironment(..) => panic!(
"get_main_environment() returns LocalEnvironment,\
but by definition should only return MainEnvironment"
),
}
}
pub fn add_referred_syms(&self, namespace_sym: &Symbol, syms: HashMap<Symbol, Vec<Symbol>>) {
match self.get_main_environment() {
MainEnvironment(env_val) => {
env_val.add_referred_syms(namespace_sym, syms);
}
LocalEnvironment(..) => panic!(
"get_main_environment() returns LocalEnvironment,\
but by definition should only return MainEnvironment"
but by definition should only return MainEnvironment"
),
}
}
pub fn add_referred_syms_to_curr_namespace(&self, syms: HashMap<Symbol, Vec<Symbol>>) {
match self.get_main_environment() {
MainEnvironment(env_val) => {
let namespace_sym = self.get_current_namespace();
env_val.add_referred_syms(&namespace_sym, syms);
}
LocalEnvironment(..) => panic!(
"get_main_environment() returns LocalEnvironment,\
but by definition should only return MainEnvironment"
),
}
}
pub fn add_referred_namespace_to_curr_namespace(&self, referred_namespace_sym: &Symbol) {
match self.get_main_environment() {
MainEnvironment(env_val) => {
let namespace_sym = self.get_current_namespace();
env_val.add_referred_namespace(&namespace_sym, referred_namespace_sym);
}
LocalEnvironment(..) => panic!(
"get_main_environment() returns LocalEnvironment,\
but by definition should only return MainEnvironment"
),
}
}
/// Changes the current namespace, or creates one first if
/// namespace doesn't already exist
pub fn change_or_create_namespace(&self, symbol: &Symbol) {
match self.get_main_environment() {
MainEnvironment(env_val) => {
env_val.change_or_create_namespace(symbol);
}
LocalEnvironment(..) => panic!(
"get_main_environment() returns LocalEnvironment,\
but by definition should only return MainEnvironment"
),
}
}
Expand Down Expand Up @@ -155,14 +225,11 @@ impl Environment {
MainEnvironment(env_val) => {
// If we've recieved a qualified symbol like
// clojure.core/+
if sym.ns != "" {
if sym.has_ns() {
// Use that namespace
env_val.get_from_namespace(&Symbol::intern(&sym.ns), sym)
} else {
env_val.get_from_namespace(
&env_val.get_current_namespace(),
&Symbol::intern(&sym.name),
)
env_val.get_from_namespace(&env_val.get_current_namespace(), &sym)
}
}
LocalEnvironment(parent_env, mappings) => {
Expand Down Expand Up @@ -239,10 +306,11 @@ impl Environment {
let eval_fn = rust_core::EvalFn::new(Rc::clone(&environment));
let ns_macro = rust_core::NsMacro::new(Rc::clone(&environment));
let load_file_fn = rust_core::LoadFileFn::new(Rc::clone(&environment));
let refer_fn = rust_core::ReferFn::new(Rc::clone(&environment));
// @TODO after we merge this with all the other commits we have,
// just change all the `insert`s here to use insert_in_namespace
// I prefer explicity and the non-dependence-on-environmental-factors
environment.change_namespace(Symbol::intern("clojure.core"));
environment.change_or_create_namespace(&Symbol::intern("clojure.core"));

environment.insert(Symbol::intern("+"), add_fn.to_rc_value());
environment.insert(Symbol::intern("-"), subtract_fn.to_rc_value());
Expand Down Expand Up @@ -402,6 +470,8 @@ impl Environment {
environment.insert(Symbol::intern("read-line"), read_line_fn.to_rc_value());

environment.insert(Symbol::intern("="), equals_fn.to_rc_value());
environment.insert(Symbol::intern("refer"), refer_fn.to_rc_value());

//
// Read in clojure.core
//
Expand All @@ -411,7 +481,7 @@ impl Environment {
let _ = Repl::new(Rc::clone(&environment)).try_eval_file("./src/clojure/string.clj");

// We can add this back once we have requires
// environment.change_namespace(Symbol::intern("user"));
// environment.change_or_create_namespace(Symbol::intern("user"));

environment
}
Expand All @@ -437,11 +507,11 @@ mod tests {

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

env_val.change_namespace(Symbol::intern("core"));
env_val.change_or_create_namespace(&Symbol::intern("core"));
assert_eq!(Symbol::intern("core"), env_val.get_current_namespace());

// @TODO add this invariant back next, and remove this comment; 5.9.2020
// env_val.change_namespace(Symbol::intern_with_ns("not-ns","ns"));
// env_val.change_or_create_namespace(Symbol::intern_with_ns("not-ns","ns"));
// assert_eq!(Symbol::intern("ns"),env_val.get_current_namespace())

// @TODO add case for local environment
Expand Down
1 change: 1 addition & 0 deletions src/error_message.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::type_tag::TypeTag;
use crate::value::Value;
use std::error::Error;
use std::fmt;

pub fn type_mismatch(expected: TypeTag, got: &Value) -> Value {
Value::Condition(format!(
Expand Down
3 changes: 3 additions & 0 deletions src/keyword.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ pub struct Keyword {
pub sym: Symbol,
}
impl Keyword {
pub fn name(&self) -> &str {
self.sym.name()
}
pub fn intern(name: &str) -> Keyword {
Keyword {
sym: Symbol::intern(name),
Expand Down
Loading

0 comments on commit 54d6e40

Please sign in to comment.