Skip to content

Commit 1f35872

Browse files
committed
first, ffirst, second, more, next, rest, when
1 parent 6fc04e0 commit 1f35872

File tree

11 files changed

+317
-35
lines changed

11 files changed

+317
-35
lines changed

src/clojure/core.clj

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1+
"strings work as temporary comments"
2+
13
(def *flush-on-newline* true)
24
(def *print-readably* true)
35

6+
"TODO: #Condition[Execution Error: clojure.lang.Nil cannot be cast to clojure.lang.IFn] when succesful"
7+
"Bug in do"
8+
9+
(defmacro when [test & body]
10+
(list 'if test (list 'do body) nil))
11+
412
(def list (fn [& ls] ls))
513

614
(defmacro defn [name args & body]
@@ -22,10 +30,13 @@
2230
(defn pr [& more]
2331
(print-string (apply str more)))
2432

33+
"TODO: use when"
2534
(defn prn [& more]
2635
(apply pr more)
2736
(newline)
28-
(flush))
37+
(if *flush-on-newline*
38+
(flush)
39+
nil))
2940

3041
(defn print [& more]
3142
(apply pr more))
@@ -47,3 +58,17 @@
4758

4859
(defn slurp [f & opts]
4960
(rust-slurp f opts))
61+
62+
"basic operations on collections"
63+
64+
(defn rest [x]
65+
(more x))
66+
67+
(defn next [x]
68+
(let [result (rest x)]
69+
(if (= '() result)
70+
nil
71+
result)))
72+
73+
(defn ffirst [x]
74+
(first (first x)))

src/clojure_string/blank_qmark_.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl IFn for BlankFn {
4242

4343
#[cfg(test)]
4444
mod tests {
45-
mod reverse_tests {
45+
mod blank_tests {
4646
use crate::clojure_string::blank_qmark_::BlankFn;
4747
use crate::ifn::IFn;
4848
use crate::value::Value;

src/clojure_string/ends_with_qmark_.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl IFn for EndsWithFn {
3333

3434
#[cfg(test)]
3535
mod tests {
36-
mod reverse_tests {
36+
mod ends_with_tests {
3737
use crate::clojure_string::ends_with_qmark_::EndsWithFn;
3838
use crate::ifn::IFn;
3939
use crate::value::Value;

src/clojure_string/includes_qmark_.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl IFn for IncludesFn {
3333

3434
#[cfg(test)]
3535
mod tests {
36-
mod reverse_tests {
36+
mod includes_tests {
3737
use crate::clojure_string::includes_qmark_::IncludesFn;
3838
use crate::ifn::IFn;
3939
use crate::value::Value;

src/clojure_string/join.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use crate::iterable::Iterable;
21
use crate::ifn::IFn;
2+
use crate::iterable::Iterable;
33
use crate::value::{ToValue, Value};
44
use std::rc::Rc;
55

@@ -22,7 +22,7 @@ impl IFn for JoinFn {
2222
if args.len() != 1 && args.len() != 2 {
2323
return error_message::wrong_varg_count(&[1, 2], args.len());
2424
}
25-
25+
2626
let separator = if args.len() == 1 {
2727
String::from("")
2828
} else {
@@ -40,19 +40,17 @@ impl IFn for JoinFn {
4040
.iter()
4141
.map(|x| x.to_string())
4242
.collect::<Vec<std::string::String>>()
43-
.join(&separator)
43+
.join(&separator),
4444
)
45-
}
46-
else {
45+
} else {
4746
Value::String(String::from(""))
4847
}
49-
5048
}
5149
}
5250

5351
#[cfg(test)]
5452
mod tests {
55-
mod reverse_tests {
53+
mod join_tests {
5654
use crate::clojure_string::join::JoinFn;
5755
use crate::ifn::IFn;
5856
use crate::persistent_list::PersistentList;

src/clojure_string/starts_with_qmark_.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl IFn for StartsWithFn {
3333

3434
#[cfg(test)]
3535
mod tests {
36-
mod reverse_tests {
36+
mod starts_with_tests {
3737
use crate::clojure_string::starts_with_qmark_::StartsWithFn;
3838
use crate::ifn::IFn;
3939
use crate::value::Value;

src/environment.rs

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::clojure_std;
22
use crate::clojure_string;
3-
use crate::namespace::{Namespaces};
3+
use crate::namespace::Namespaces;
44
use crate::repl::Repl;
55
use crate::rust_core;
66
use crate::symbol::Symbol;
@@ -194,6 +194,9 @@ impl Environment {
194194
let print_string_fn = rust_core::PrintStringFn {};
195195
let read_line_fn = rust_core::ReadLineFn {};
196196
let assoc_fn = rust_core::AssocFn {};
197+
let more_fn = rust_core::MoreFn {};
198+
let first_fn = rust_core::FirstFn {};
199+
let second_fn = rust_core::SecondFn {};
197200

198201
// rust implementations of core functions
199202
let slurp_fn = rust_core::slurp::SlurpFn {};
@@ -255,23 +258,23 @@ impl Environment {
255258
environment.insert(Symbol::intern("eval"), eval_fn.to_rc_value());
256259

257260
// Thread namespace
258-
environment.insert_into_namespace(
259-
&Symbol::intern("Thread"),
260-
Symbol::intern("sleep"),
261-
thread_sleep_fn.to_rc_value()
262-
);
263-
264-
// System namespace
265-
environment.insert_into_namespace(
266-
&Symbol::intern("System"),
267-
Symbol::intern("nanoTime"),
268-
nanotime_fn.to_rc_value()
269-
);
270-
environment.insert_into_namespace(
271-
&Symbol::intern("System"),
272-
Symbol::intern("getenv"),
273-
get_env_fn.to_rc_value()
274-
);
261+
environment.insert_into_namespace(
262+
&Symbol::intern("Thread"),
263+
Symbol::intern("sleep"),
264+
thread_sleep_fn.to_rc_value(),
265+
);
266+
267+
// System namespace
268+
environment.insert_into_namespace(
269+
&Symbol::intern("System"),
270+
Symbol::intern("nanoTime"),
271+
nanotime_fn.to_rc_value(),
272+
);
273+
environment.insert_into_namespace(
274+
&Symbol::intern("System"),
275+
Symbol::intern("getenv"),
276+
get_env_fn.to_rc_value(),
277+
);
275278

276279
// core.clj wraps calls to the rust implementations
277280
// @TODO add this to clojure.rs.core namespace as clojure.rs.core/slurp
@@ -373,7 +376,9 @@ impl Environment {
373376
environment.insert(Symbol::intern("assoc"), assoc_fn.to_rc_value());
374377
environment.insert(Symbol::intern("get"), get_fn.to_rc_value());
375378
environment.insert(Symbol::intern("concat"), concat_fn.to_rc_value());
376-
379+
environment.insert(Symbol::intern("more"), more_fn.to_rc_value());
380+
environment.insert(Symbol::intern("first"), first_fn.to_rc_value());
381+
environment.insert(Symbol::intern("second"), second_fn.to_rc_value());
377382
// input and output
378383
environment.insert(
379384
Symbol::intern("system-newline"),
@@ -389,7 +394,7 @@ impl Environment {
389394
);
390395
environment.insert(Symbol::intern("read-line"), read_line_fn.to_rc_value());
391396

392-
environment.insert(Symbol::intern("="),equals_fn.to_rc_value());
397+
environment.insert(Symbol::intern("="), equals_fn.to_rc_value());
393398
//
394399
// Read in clojure.core
395400
//
@@ -528,8 +533,7 @@ mod tests {
528533
MainEnvironment(EnvironmentVal {
529534
curr_ns_sym: _,
530535
namespaces,
531-
}) => namespaces
532-
.get(&Symbol::intern("user"),&Symbol::intern("+")),
536+
}) => namespaces.get(&Symbol::intern("user"), &Symbol::intern("+")),
533537
_ => panic!("new_main_environment() should return Main"),
534538
};
535539

src/rust_core.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ pub use self::get::*;
4747
pub(crate) mod map;
4848
pub use self::map::*;
4949

50+
pub(crate) mod more;
51+
pub use self::more::*;
52+
pub(crate) mod first;
53+
pub use self::first::*;
54+
pub(crate) mod second;
55+
pub use self::second::*;
56+
5057
// input and output
5158
pub(crate) mod system_newline;
5259
pub use self::system_newline::*;
@@ -59,7 +66,6 @@ pub use self::string_print::*;
5966
pub(crate) mod read_line;
6067
pub use self::read_line::*;
6168

62-
6369
// other
6470
pub(crate) mod slurp;
6571
pub use self::slurp::*;

src/rust_core/first.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use crate::error_message;
2+
use crate::ifn::IFn;
3+
use crate::iterable::Iterable;
4+
use crate::persistent_list::PersistentList;
5+
use crate::protocol::{Protocol, ProtocolCastable};
6+
use crate::type_tag::TypeTag;
7+
use crate::value::{ToValue, Value};
8+
use std::rc::Rc;
9+
10+
/// (first x)
11+
/// returns first element or nil
12+
/// TODO: support for strings
13+
#[derive(Debug, Clone)]
14+
pub struct FirstFn {}
15+
impl ToValue for FirstFn {
16+
fn to_value(&self) -> Value {
17+
Value::IFn(Rc::new(self.clone()))
18+
}
19+
}
20+
impl IFn for FirstFn {
21+
fn invoke(&self, args: Vec<Rc<Value>>) -> Value {
22+
if args.len() != 1 {
23+
return error_message::wrong_arg_count(1, args.len());
24+
}
25+
match args.get(0).unwrap().try_as_protocol::<Iterable>() {
26+
Some(iterable) => match iterable.iter().next() {
27+
Some(val) => val.to_value(),
28+
_ => Value::Nil,
29+
},
30+
_ => error_message::type_mismatch(TypeTag::ISeq, args.get(0).unwrap()),
31+
}
32+
}
33+
}
34+
35+
#[cfg(test)]
36+
mod tests {
37+
mod first_tests {
38+
use crate::ifn::IFn;
39+
use crate::persistent_list::PersistentList;
40+
use crate::persistent_vector::PersistentVector;
41+
use crate::rust_core::first::FirstFn;
42+
use crate::value::Value;
43+
use std::rc::Rc;
44+
45+
#[test]
46+
fn first_on_empty_iterable() {
47+
let first = FirstFn {};
48+
let args = vec![Rc::new(Value::PersistentList(
49+
vec![].into_iter().collect::<PersistentList>(),
50+
))];
51+
assert_eq!(Value::Nil, first.invoke(args));
52+
}
53+
54+
#[test]
55+
fn first_on_iterable_with_one_value_list() {
56+
let first = FirstFn {};
57+
let args = vec![Rc::new(Value::PersistentList(
58+
vec![Rc::new(Value::Boolean(true))]
59+
.into_iter()
60+
.collect::<PersistentList>(),
61+
))];
62+
assert_eq!(Value::Boolean(true), first.invoke(args));
63+
}
64+
65+
#[test]
66+
#[should_panic]
67+
fn first_on_non_iterable_value() {
68+
let first = FirstFn {};
69+
let args = vec![Rc::new(Value::Nil)];
70+
assert_eq!(Value::Nil, first.invoke(args));
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)