Skip to content

Commit 668c158

Browse files
committed
Mass commit; changes unfortunately not made under source control
1 parent fd91452 commit 668c158

File tree

13 files changed

+1511
-71
lines changed

13 files changed

+1511
-71
lines changed

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,8 @@ edition = "2018"
77
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
88

99
[dependencies]
10-
dyn-clone = "*"
10+
dyn-clone = "*"
11+
pest = "*"
12+
pest_derive = "*"
13+
nom = "*"
14+
text_io = "*"

src/environment.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use crate::value::{Value,ToValue};
2+
use crate::namespace::{Namespace,Namespaces};
3+
use crate::Symbol;
4+
use crate::rust_core;
5+
use crate::rust_core::{AddFn,StrFn};
6+
7+
use std::collections::HashMap;
8+
use std::rc::Rc;
9+
use std::cell::RefCell;
10+
11+
12+
// @TODO lookup naming convention
13+
/// Inner value of our environment
14+
/// See Environment for overall purpose
15+
#[derive(Debug,Clone)]
16+
pub struct EnvironmentVal {
17+
curr_ns : Namespace,
18+
namespaces : Namespaces
19+
}
20+
impl EnvironmentVal {
21+
/// Default main environment
22+
fn new_main_val() -> EnvironmentVal {
23+
EnvironmentVal {
24+
curr_ns: Namespace::new(Symbol::intern("user"),
25+
RefCell::new(HashMap::new())),
26+
namespaces: Namespaces(RefCell::new(HashMap::new()))
27+
}
28+
}
29+
}
30+
/// Our environment keeps track of the meaning of things 'right here', relative to where
31+
/// something is at (meaning, a form inside of a let might have a different meaning for
32+
/// the symbol x than a form outside of it, with a let introducing an additional local environment
33+
///
34+
/// Stores our namespaces and our current namespace, which themselves personally store our symbols
35+
/// mapped to values
36+
#[derive(Debug,Clone)]
37+
pub enum Environment {
38+
MainEnvironment(EnvironmentVal),
39+
/// Points to parent environment
40+
/// Introduced by Closures, and by let
41+
LocalEnvironment(Rc<Environment>,RefCell<HashMap<Symbol,Rc<Value>>>)
42+
}
43+
use Environment::*;
44+
impl Environment {
45+
pub fn new_main_environment() -> Environment {
46+
MainEnvironment(EnvironmentVal::new_main_val())
47+
}
48+
pub fn new_local_environment(outer_environment: Rc<Environment>) -> Environment {
49+
LocalEnvironment(outer_environment,RefCell::new(HashMap::new()))
50+
}
51+
pub fn insert(&self,sym: Symbol,val: Rc<Value>)
52+
{
53+
match self {
54+
MainEnvironment(EnvironmentVal {curr_ns,..}) => {
55+
curr_ns.insert(sym,val);
56+
},
57+
LocalEnvironment(_,mappings) => {
58+
mappings.borrow_mut().insert(sym,val);
59+
}
60+
}
61+
}
62+
pub fn get(&self, sym: &Symbol) -> Rc<Value>
63+
{
64+
match self {
65+
MainEnvironment(EnvironmentVal {curr_ns,..}) => curr_ns.get(sym),
66+
67+
LocalEnvironment(parent_env,mappings) => {
68+
match mappings.borrow().get(sym) {
69+
Some(val) => Rc::clone(val),
70+
None => parent_env.get(sym)
71+
}
72+
}
73+
}
74+
}
75+
pub fn clojure_core_environment() -> Rc<Environment> {
76+
// Register our macros / functions ahead of time
77+
let add_fn = rust_core::AddFn{};
78+
let str_fn = rust_core::StrFn{};
79+
// Hardcoded macros
80+
let let_macro = Value::LetMacro{};
81+
let quote_macro = Value::QuoteMacro{};
82+
let def_macro = Value::DefMacro{};
83+
let fn_macro = Value::FnMacro{};
84+
let defmacro_macro = Value::DefmacroMacro{};
85+
86+
let mut environment = Rc::new(Environment::new_main_environment());
87+
88+
let eval_fn = rust_core::EvalFn::new(Rc::clone(&environment));
89+
90+
environment.insert(Symbol::intern("+"),add_fn.to_rc_value());
91+
environment.insert(Symbol::intern("let"),let_macro.to_rc_value());
92+
environment.insert(Symbol::intern("str"),str_fn.to_rc_value());
93+
environment.insert(Symbol::intern("quote"),quote_macro.to_rc_value());
94+
environment.insert(Symbol::intern("def"),def_macro.to_rc_value());
95+
environment.insert(Symbol::intern("fn"),fn_macro.to_rc_value());
96+
environment.insert(Symbol::intern("defmacro"),defmacro_macro.to_rc_value());
97+
environment.insert(Symbol::intern("eval"),eval_fn.to_rc_value());
98+
99+
environment
100+
}
101+
}

src/ifn.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//! Trait for function-like things
2+
//!
3+
//! An IFn is something that can be invoked on arguments, like:
4+
//! a function,
5+
//! (+ 1 2)
6+
//! a macro
7+
//! (-> 1 (+ 5) (* 10)))
8+
//! a keyword
9+
//! (:name {:name "Blah" :age 20})
10+
//! a map
11+
//! ({:name "Blah" :age 20} :name)
12+
//! As well as a few more types.
13+
use crate::value::Value;
14+
use dyn_clone::DynClone;
15+
use std::fmt::Debug;
16+
17+
//
18+
// Based on: clojure.lang.IFn
19+
//
20+
// Naming this is a bit difficult, as
21+
// 1. Rust already has a Fn trait
22+
// 2. Naming this IFn or not naming this IFn introduces consistency and inconsistency;
23+
//
24+
// Keeping 'IFn' introduces consistency because not just does the
25+
// original ClojureJVM have an IFn in the Java underneath, but
26+
// Clojure itself carries on this idea even as we leave the JVM (as,
27+
// for instance, ifn is implemented in Clojurescript via)
28+
//
29+
// Inconsistency, because Rust surely does not name traits 'ITrait'.
30+
//
31+
// I've regardless kept it as IFn, and you might say IFn here is
32+
// referring to the Clojure idea of an IFn, implemented in Rust with a
33+
// trait, rather than saying 'this is an interface called Fn'
34+
//
35+
36+
pub trait IFn : Debug + DynClone {
37+
fn invoke(&self,args: Vec<&Value>) -> Value;
38+
}
39+
dyn_clone::clone_trait_object!(IFn);

src/lambda.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use crate::environment::Environment;
2+
use crate::ifn::IFn;
3+
use crate::value::{Value,ToValue,Evaluable};
4+
use crate::persistent_list::ToPersistentList;
5+
use std::rc::Rc;
6+
use crate::symbol::Symbol;
7+
8+
#[derive(Debug,Clone)]
9+
pub struct Fn {
10+
pub body: Rc<Value>,
11+
// Closed over variables
12+
pub enclosing_environment: Rc<Environment>,
13+
pub arg_syms: Vec<Symbol>
14+
}
15+
impl ToValue for Fn {
16+
fn to_value(&self) -> Value {
17+
Value::IFn(Rc::new(self.clone()))
18+
}
19+
}
20+
impl IFn for Fn {
21+
fn invoke(&self,args: Vec<&Value>) -> Value {
22+
let local_environment = Rc::new(Environment::new_local_environment(Rc::clone(&self.enclosing_environment)));
23+
24+
let argc = self.arg_syms.len();
25+
26+
let mut var_args = false;
27+
if(argc >= 2) {
28+
if let Some(sym) = self.arg_syms.get(argc - 2)
29+
{
30+
if sym.to_string() == "&" {
31+
var_args = true;
32+
let last_sym = self.arg_syms.get(argc - 1).unwrap();
33+
local_environment.insert(last_sym.clone(),Rc::new(Value::Nil));
34+
}
35+
}
36+
}
37+
38+
if !var_args && args.len() != argc {
39+
return Value::Condition(format!("Wrong number of arguments given to function (Given: {}, Expected: {})",args.len(),argc));
40+
}
41+
42+
for (i,arg) in args.iter().enumerate() {
43+
let curr_sym = self.arg_syms.get(i).unwrap();
44+
// We can bind the rest of the arguments, then, to the next variable and blow this popsicle stand
45+
if curr_sym.to_string() == "&" {
46+
if (!var_args) {
47+
return Value::Condition(String::from("Invalid function argument '&' in non-variable-argument function definition"));
48+
}
49+
let last_sym = self.arg_syms.get(i + 1).unwrap();
50+
let rest_args = args.get(i..).unwrap().to_vec().into_list().to_rc_value();
51+
local_environment.insert(last_sym.clone(),rest_args);
52+
break;
53+
}
54+
local_environment.insert(curr_sym.clone(),arg.to_rc_value());
55+
}
56+
self.body.eval(local_environment)
57+
}
58+
}

src/main.rs

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,90 @@
1+
#[macro_use]
2+
extern crate nom;
3+
14
mod rust_core;
25
mod symbol;
36
mod type_tag;
47
mod value;
5-
6-
use rust_core::AddFn;
7-
use crate::value::{IFn,ToValue};
8+
mod environment;
9+
mod namespace;
10+
mod ifn;
11+
mod lambda;
12+
mod reader;
13+
mod persistent_list;
14+
mod persistent_vector;
15+
16+
use environment::Environment;
17+
18+
use std::collections::HashMap;
19+
use std::rc::Rc;
20+
use std::io::{self,Read};
21+
use std::str::FromStr;
22+
use std::io::BufRead;
23+
use std::fs::File;
24+
25+
use rust_core::{AddFn,StrFn};
26+
use symbol::Symbol;
27+
use crate::value::{ToValue,Evaluable};
28+
use crate::persistent_list::{PersistentList,ToPersistentList};
29+
use crate::persistent_vector::{PersistentVector,ToPersistentVector};
30+
use crate::value::Value;
831

932
fn main()
1033
{
11-
let add_fn = AddFn{};
12-
let result = add_fn.invoke(&[&5_i32.to_value(),&6_i32.to_value(),&10_i32.to_value()]);
13-
14-
println!("{:?}",result);
34+
// Register our macros / functions ahead of time
35+
let add_fn = rust_core::AddFn{};
36+
let str_fn = rust_core::StrFn{};
37+
let do_fn = rust_core::DoFn{};
38+
let nth_fn = rust_core::NthFn{};
39+
let do_macro = rust_core::DoMacro{};
40+
let concat_fn = rust_core::ConcatFn{};
41+
// Hardcoded macros
42+
let let_macro = Value::LetMacro{};
43+
let quote_macro = Value::QuoteMacro{};
44+
let def_macro = Value::DefMacro{};
45+
let fn_macro = Value::FnMacro{};
46+
let defmacro_macro = Value::DefmacroMacro{};
47+
48+
let environment = Rc::new(Environment::new_main_environment());
49+
50+
let eval_fn = rust_core::EvalFn::new(Rc::clone(&environment));
51+
52+
environment.insert(Symbol::intern("+"),add_fn.to_rc_value());
53+
environment.insert(Symbol::intern("let"),let_macro.to_rc_value());
54+
environment.insert(Symbol::intern("str"),str_fn.to_rc_value());
55+
environment.insert(Symbol::intern("quote"),quote_macro.to_rc_value());
56+
environment.insert(Symbol::intern("do-fn*"),do_fn.to_rc_value());
57+
environment.insert(Symbol::intern("do"),do_macro.to_rc_value());
58+
environment.insert(Symbol::intern("def"),def_macro.to_rc_value());
59+
environment.insert(Symbol::intern("fn"),fn_macro.to_rc_value());
60+
environment.insert(Symbol::intern("defmacro"),defmacro_macro.to_rc_value());
61+
environment.insert(Symbol::intern("eval"),eval_fn.to_rc_value());
62+
environment.insert(Symbol::intern("nth"),nth_fn.to_rc_value());
63+
environment.insert(Symbol::intern("concat"),concat_fn.to_rc_value());
64+
//
65+
// Start repl
66+
//
67+
let stdin = io::stdin();
68+
print!("user=> ");
69+
for line in stdin.lock().lines() {
70+
let line = line.unwrap();
71+
let mut remaining_input = line.as_bytes();
72+
loop {
73+
let next_read_parse = reader::try_read(remaining_input);
74+
match next_read_parse {
75+
Ok((_remaining_input,value)) => {
76+
print!("{} ",value.eval(Rc::clone(&environment)).to_string_explicit());
77+
remaining_input = _remaining_input;
78+
},
79+
_ => {
80+
break;
81+
}
82+
}
83+
}
84+
println!();
85+
print!("user=> ");
86+
}
87+
1588
}
1689

1790

src/namespace.rs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,32 @@
1+
use crate::value::{Value};
2+
use crate::value::ToValue;
3+
use crate::Symbol;
4+
use crate::rust_core::{AddFn,StrFn};
15
use std::collections::HashMap;
2-
use symbol::Symbol;
3-
use value::Value;
6+
use std::rc::Rc;
7+
use std::cell::RefCell;
48

9+
#[derive(Debug,Clone)]
510
pub struct Namespace {
6-
name: Symbol,
7-
mappings: HashMap<Symbol,Value>
11+
pub name: Symbol,
12+
mappings: RefCell<HashMap<Symbol,Rc<Value>>>
813
}
14+
impl Namespace {
15+
pub fn new(name: Symbol, mappings: RefCell<HashMap<Symbol,Rc<Value>>>) -> Namespace {
16+
Namespace { name,mappings }
17+
}
18+
pub fn insert(&self,sym: Symbol, val: Rc<Value>)
19+
{
20+
self.mappings.borrow_mut().insert(sym,val);
21+
}
22+
pub fn get(&self, sym: &Symbol) -> Rc<Value>
23+
{
24+
match self.mappings.borrow_mut().get(sym) {
25+
Some(val) => Rc::clone(val),
26+
None => Rc::new(Value::Condition(format!("Undefined symbol {}",sym.name)))
27+
}
28+
}
29+
}
30+
#[derive(Debug,Clone)]
31+
pub struct Namespaces(pub RefCell<HashMap<Symbol,Namespace>>);
932

10-
struct Namespaces(HashMap<Symbol,Namespace>);

0 commit comments

Comments
 (0)