Skip to content

Commit c0fefbe

Browse files
author
Sasha
authored
Merge branch 'master' into master
2 parents 8834057 + f8bbd78 commit c0fefbe

16 files changed

+1215
-1117
lines changed

.github/workflows/rust.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Rust
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
pull_request:
7+
branches: [ master ]
8+
9+
jobs:
10+
build:
11+
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- uses: actions/checkout@v2
16+
- name: Build
17+
run: cargo build --verbose
18+
- name: Run tests
19+
run: cargo test --verbose

src/environment.rs

Lines changed: 92 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,128 @@
1-
use crate::value::{Value,ToValue};
2-
use crate::namespace::{Namespace,Namespaces};
3-
use crate::Symbol;
1+
use crate::namespace::{Namespace, Namespaces};
42
use crate::rust_core;
5-
use crate::rust_core::{AddFn,StrFn};
3+
use crate::value::{ToValue, Value};
4+
use crate::Symbol;
5+
use crate::repl;
66

7+
use std::cell::RefCell;
78
use std::collections::HashMap;
89
use std::rc::Rc;
9-
use std::cell::RefCell;
10-
1110

1211
// @TODO lookup naming convention
1312
/// Inner value of our environment
14-
/// See Environment for overall purpose
15-
#[derive(Debug,Clone)]
13+
/// See Environment for overall purpose
14+
#[derive(Debug, Clone)]
1615
pub struct EnvironmentVal {
17-
curr_ns : Namespace,
18-
namespaces : Namespaces
16+
curr_ns: Namespace,
17+
namespaces: Namespaces,
1918
}
2019
impl EnvironmentVal {
21-
/// Default main environment
20+
/// Default main environment
2221
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-
}
22+
EnvironmentVal {
23+
curr_ns: Namespace::new(Symbol::intern("user"), RefCell::new(HashMap::new())),
24+
namespaces: Namespaces(RefCell::new(HashMap::new())),
25+
}
2826
}
2927
}
3028
/// Our environment keeps track of the meaning of things 'right here', relative to where
3129
/// something is at (meaning, a form inside of a let might have a different meaning for
3230
/// the symbol x than a form outside of it, with a let introducing an additional local environment
3331
///
3432
/// Stores our namespaces and our current namespace, which themselves personally store our symbols
35-
/// mapped to values
36-
#[derive(Debug,Clone)]
33+
/// mapped to values
34+
#[derive(Debug, Clone)]
3735
pub enum Environment {
3836
MainEnvironment(EnvironmentVal),
3937
/// Points to parent environment
40-
/// Introduced by Closures, and by let
41-
LocalEnvironment(Rc<Environment>,RefCell<HashMap<Symbol,Rc<Value>>>)
38+
/// Introduced by Closures, and by let
39+
LocalEnvironment(Rc<Environment>, RefCell<HashMap<Symbol, Rc<Value>>>),
4240
}
4341
use Environment::*;
4442
impl Environment {
4543
pub fn new_main_environment() -> Environment {
46-
MainEnvironment(EnvironmentVal::new_main_val())
44+
MainEnvironment(EnvironmentVal::new_main_val())
4745
}
4846
pub fn new_local_environment(outer_environment: Rc<Environment>) -> Environment {
49-
LocalEnvironment(outer_environment,RefCell::new(HashMap::new()))
47+
LocalEnvironment(outer_environment, RefCell::new(HashMap::new()))
5048
}
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-
}
49+
pub fn insert(&self, sym: Symbol, val: Rc<Value>) {
50+
match self {
51+
MainEnvironment(EnvironmentVal { curr_ns, .. }) => {
52+
curr_ns.insert(sym, val);
53+
}
54+
LocalEnvironment(_, mappings) => {
55+
mappings.borrow_mut().insert(sym, val);
56+
}
57+
}
6158
}
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-
}
59+
pub fn get(&self, sym: &Symbol) -> Rc<Value> {
60+
match self {
61+
MainEnvironment(EnvironmentVal { curr_ns, .. }) => curr_ns.get(sym),
62+
63+
LocalEnvironment(parent_env, mappings) => match mappings.borrow().get(sym) {
64+
Some(val) => Rc::clone(val),
65+
None => parent_env.get(sym),
66+
},
67+
}
7468
}
7569
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{};
70+
// Register our macros / functions ahead of time
71+
let add_fn = rust_core::AddFn {};
72+
let str_fn = rust_core::StrFn {};
73+
let do_fn = rust_core::DoFn {};
74+
let nth_fn = rust_core::NthFn {};
75+
let do_macro = rust_core::DoMacro {};
76+
let concat_fn = rust_core::ConcatFn {};
77+
let print_string_fn = rust_core::PrintStringFn {};
78+
// Hardcoded fns
79+
let lexical_eval_fn = Value::LexicalEvalFn {};
7980
// 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));
81+
let let_macro = Value::LetMacro {};
82+
let quote_macro = Value::QuoteMacro {};
83+
let def_macro = Value::DefMacro {};
84+
let fn_macro = Value::FnMacro {};
85+
let defmacro_macro = Value::DefmacroMacro {};
86+
let environment = Rc::new(Environment::new_main_environment());
87+
88+
let eval_fn = rust_core::EvalFn::new(Rc::clone(&environment));
8989

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());
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());
9898

99-
environment
99+
environment.insert(Symbol::intern("+"), add_fn.to_rc_value());
100+
environment.insert(Symbol::intern("let"), let_macro.to_rc_value());
101+
environment.insert(Symbol::intern("str"), str_fn.to_rc_value());
102+
environment.insert(Symbol::intern("quote"), quote_macro.to_rc_value());
103+
environment.insert(Symbol::intern("do-fn*"), do_fn.to_rc_value());
104+
environment.insert(Symbol::intern("do"), do_macro.to_rc_value());
105+
environment.insert(Symbol::intern("def"), def_macro.to_rc_value());
106+
environment.insert(Symbol::intern("fn"), fn_macro.to_rc_value());
107+
environment.insert(Symbol::intern("defmacro"), defmacro_macro.to_rc_value());
108+
environment.insert(Symbol::intern("eval"), eval_fn.to_rc_value());
109+
environment.insert(
110+
Symbol::intern("lexical-eval"),
111+
lexical_eval_fn.to_rc_value(),
112+
);
113+
114+
environment.insert(Symbol::intern("nth"), nth_fn.to_rc_value());
115+
environment.insert(Symbol::intern("concat"), concat_fn.to_rc_value());
116+
environment.insert(
117+
Symbol::intern("print-string"),
118+
print_string_fn.to_rc_value(),
119+
);
120+
121+
//
122+
// Read in clojure.core
123+
//
124+
let _ = repl::try_eval_file(&environment, "./src/clojure/core.clj");
125+
126+
environment
100127
}
101128
}

src/ifn.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! Trait for function-like things
1+
//! Trait for function-like things
22
//!
33
//! An IFn is something that can be invoked on arguments, like:
44
//! a function,
@@ -9,7 +9,7 @@
99
//! (:name {:name "Blah" :age 20})
1010
//! a map
1111
//! ({:name "Blah" :age 20} :name)
12-
//! As well as a few more types.
12+
//! As well as a few more types.
1313
use crate::value::Value;
1414

1515
use dyn_clone::DynClone;
@@ -18,25 +18,25 @@ use std::fmt::Debug;
1818
use std::hash::Hash;
1919

2020
//
21-
// Based on: clojure.lang.IFn
21+
// Based on: clojure.lang.IFn
2222
//
23-
// Naming this is a bit difficult, as
24-
// 1. Rust already has a Fn trait
23+
// Naming this is a bit difficult, as
24+
// 1. Rust already has a Fn trait
2525
// 2. Naming this IFn or not naming this IFn introduces consistency and inconsistency;
2626
//
2727
// Keeping 'IFn' introduces consistency because not just does the
2828
// original ClojureJVM have an IFn in the Java underneath, but
2929
// Clojure itself carries on this idea even as we leave the JVM (as,
3030
// for instance, ifn is implemented in Clojurescript via)
3131
//
32-
// Inconsistency, because Rust surely does not name traits 'ITrait'.
32+
// Inconsistency, because Rust surely does not name traits 'ITrait'.
3333
//
3434
// I've regardless kept it as IFn, and you might say IFn here is
3535
// referring to the Clojure idea of an IFn, implemented in Rust with a
3636
// trait, rather than saying 'this is an interface called Fn'
3737
//
38-
39-
pub trait IFn : Debug + DynClone {
40-
fn invoke(&self,args: Vec<&Value>) -> Value;
38+
39+
pub trait IFn: Debug + DynClone {
40+
fn invoke(&self, args: Vec<&Value>) -> Value;
4141
}
4242
dyn_clone::clone_trait_object!(IFn);

src/lambda.rs

Lines changed: 44 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,63 @@
11
use crate::environment::Environment;
22
use crate::ifn::IFn;
3-
use crate::value::{Value,ToValue,Evaluable};
43
use crate::persistent_list::ToPersistentList;
5-
use std::rc::Rc;
64
use crate::symbol::Symbol;
5+
use crate::value::{Evaluable, ToValue, Value};
6+
use std::rc::Rc;
77

8-
#[derive(Debug,Clone)]
8+
#[derive(Debug, Clone)]
99
pub struct Fn {
1010
pub body: Rc<Value>,
11-
// Closed over variables
11+
// Closed over variables
1212
pub enclosing_environment: Rc<Environment>,
13-
pub arg_syms: Vec<Symbol>
13+
pub arg_syms: Vec<Symbol>,
1414
}
1515
impl ToValue for Fn {
1616
fn to_value(&self) -> Value {
1717
Value::IFn(Rc::new(self.clone()))
1818
}
1919
}
2020
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)));
21+
fn invoke(&self, args: Vec<&Value>) -> Value {
22+
let local_environment = Rc::new(Environment::new_local_environment(Rc::clone(
23+
&self.enclosing_environment,
24+
)));
25+
26+
let argc = self.arg_syms.len();
27+
28+
let mut var_args = false;
29+
if (argc >= 2) {
30+
if let Some(sym) = self.arg_syms.get(argc - 2) {
31+
if sym.to_string() == "&" {
32+
var_args = true;
33+
let last_sym = self.arg_syms.get(argc - 1).unwrap();
34+
local_environment.insert(last_sym.clone(), Rc::new(Value::Nil));
35+
}
36+
}
37+
}
2338

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-
}
39+
if !var_args && args.len() != argc {
40+
return Value::Condition(format!(
41+
"Wrong number of arguments given to function (Given: {}, Expected: {})",
42+
args.len(),
43+
argc
44+
));
45+
}
4146

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)
47+
for (i, arg) in args.iter().enumerate() {
48+
let curr_sym = self.arg_syms.get(i).unwrap();
49+
// We can bind the rest of the arguments, then, to the next variable and blow this popsicle stand
50+
if curr_sym.to_string() == "&" {
51+
if (!var_args) {
52+
return Value::Condition(String::from("Invalid function argument '&' in non-variable-argument function definition"));
53+
}
54+
let last_sym = self.arg_syms.get(i + 1).unwrap();
55+
let rest_args = args.get(i..).unwrap().to_vec().into_list().to_rc_value();
56+
local_environment.insert(last_sym.clone(), rest_args);
57+
break;
58+
}
59+
local_environment.insert(curr_sym.clone(), arg.to_rc_value());
60+
}
61+
self.body.eval(local_environment)
5762
}
5863
}

0 commit comments

Comments
 (0)