Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cons and proof of concept for when and cond utilizing cons #70

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion src/clojure/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
(def *print-readably* true)

(defmacro when [test & body]
(list 'if test (concat (list 'do) body)))
(list 'if test (cons 'do body)))

(def list (fn [& ls] ls))

Expand Down Expand Up @@ -66,3 +66,23 @@

(defn ffirst [x]
(first (first x)))


; proof of concept: cond

; cond requires exceptions, temporary work around
; should use special form
(defmacro throw
[exception-form]
(println (str (first exception-form)) ": " (second exception-form)))

; proof of concept: cond as expressed (almost) in Clojure
(defmacro cond
[& clauses]
(when clauses
(list 'if (first clauses)
(if (next clauses)
(second clauses)
(throw (IllegalArgumentException
"cond requires an even number of forms")))
(cons 'clojure.core/cond (next (next clauses))))))
2 changes: 2 additions & 0 deletions src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ impl 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));
let cons_fn = rust_core::ConsFn {};
// @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
Expand Down Expand Up @@ -454,6 +455,7 @@ impl Environment {
environment.insert(Symbol::intern("more"), more_fn.to_rc_value());
environment.insert(Symbol::intern("first"), first_fn.to_rc_value());
environment.insert(Symbol::intern("second"), second_fn.to_rc_value());
environment.insert(Symbol::intern("cons"), cons_fn.to_rc_value());
// input and output
environment.insert(
Symbol::intern("system-newline"),
Expand Down
17 changes: 10 additions & 7 deletions src/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ fn is_period_char(chr: char) -> bool {
///
/// Clojure defines a whitespace as either a comma or an unicode whitespace.
fn is_clojure_whitespace(c: char) -> bool {
c.is_whitespace() || c == ','
c.is_whitespace() || c == ','
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// End predicates
Expand All @@ -169,16 +169,16 @@ fn consume_clojure_whitespaces_parser(input: &str) -> IResult<&str, ()> {

named!(whitespace_parser<&str,()>,
value!((),
many0!(alt!(comment_parser |
many0!(alt!(comment_parser |
take_while1!(is_clojure_whitespace))))
);

named!(no_whitespace_parser<&str,()>, value!((),tag!("")));

// @TODO rename / check that all parsers are consistent?
// @TODO rename / check that all parsers are consistent?
named!(parser<&str,()>,
// Because 'whitespace_parser' loops, we cannot include the case where there's no whitespace at all in
// its definition -- nom wouldn't allow it, as it would loop forever consuming no whitespace
// its definition -- nom wouldn't allow it, as it would loop forever consuming no whitespace
// So instead, we eat up all the whitespace first, and then use the no_whitespace_parser as our sort-of
// base-case after
alt!(whitespace_parser | no_whitespace_parser)
Expand Down Expand Up @@ -560,12 +560,15 @@ pub fn read<R: BufRead>(reader: &mut R) -> Value {
// loop over and ask for more lines, accumulating them in input_buffer until we can read
loop {
let maybe_line = reader.by_ref().lines().next();

match maybe_line {
Some(Err(e)) => return Value::Condition(format!("Reader error: {}", e)),
// `lines` does not include \n, but \n is part of the whitespace given to the reader
// (and is important for reading comments) so we will push a newline as well
Some(Ok(line)) => { input_buffer.push_str(&line); input_buffer.push_str("\n"); },
// (and is important for reading comments) so we will push a newline as well
Some(Ok(line)) => {
input_buffer.push_str(&line);
input_buffer.push_str("\n");
}
None => {
return Value::Condition(String::from("Tried to read empty stream; unexpected EOF"))
}
Expand Down
2 changes: 2 additions & 0 deletions src/rust_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ pub(crate) mod get;
pub use self::get::*;
pub(crate) mod map;
pub use self::map::*;
pub(crate) mod cons;
pub use self::cons::*;

pub(crate) mod more;
pub use self::more::*;
Expand Down
49 changes: 49 additions & 0 deletions src/rust_core/concat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,52 @@ impl IFn for ConcatFn {
Value::PersistentList(concatted_vec.into_iter().collect::<PersistentList>())
}
}

#[cfg(test)]
mod tests {
mod concat_tests {
use crate::ifn::IFn;
use crate::persistent_list::PersistentList;
use crate::persistent_vector::PersistentVector;
use crate::rust_core::ConcatFn;
use crate::value::Value;
use std::rc::Rc;

#[test]
fn concat_test() {
let concat = ConcatFn {};
let s = "insert as first";
let args = vec![
Rc::new(Value::PersistentVector(
vec![
Rc::new(Value::String(String::from("1.1"))),
Rc::new(Value::String(String::from("1.2"))),
]
.into_iter()
.collect::<PersistentVector>(),
)),
Rc::new(Value::PersistentVector(
vec![
Rc::new(Value::String(String::from("2.1"))),
Rc::new(Value::String(String::from("2.2"))),
]
.into_iter()
.collect::<PersistentVector>(),
)),
];
assert_eq!(
Value::PersistentList(
vec![
Rc::new(Value::String(String::from("1.1"))),
Rc::new(Value::String(String::from("1.2"))),
Rc::new(Value::String(String::from("2.1"))),
Rc::new(Value::String(String::from("2.2")))
]
.into_iter()
.collect::<PersistentList>()
),
concat.invoke(args)
);
}
}
}
75 changes: 75 additions & 0 deletions src/rust_core/cons.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use crate::ifn::IFn;
use crate::value::{ToValue, Value};
use std::rc::Rc;

use crate::error_message;
use crate::iterable::Iterable;
use crate::persistent_list::ToPersistentList;
use crate::protocol::ProtocolCastable;

/// (cons x seq)
/// inserts x as first element of seq
#[derive(Debug, Clone)]
pub struct ConsFn {}
impl ToValue for ConsFn {
fn to_value(&self) -> Value {
Value::IFn(Rc::new(self.clone()))
}
}
impl IFn for ConsFn {
fn invoke(&self, args: Vec<Rc<Value>>) -> Value {
if args.len() != 2 {
return error_message::wrong_arg_count(2, args.len());
}

let mut coll_vec = match args.get(1).unwrap().try_as_protocol::<Iterable>() {
Some(iterable) => iterable.clone().iter().collect(),
_ => vec![],
};

coll_vec.insert(0, args.get(0).unwrap().to_owned());

return Value::PersistentList(coll_vec.into_list());
}
}

#[cfg(test)]
mod tests {
mod cons_tests {
use crate::ifn::IFn;
use crate::persistent_list::PersistentList;
use crate::persistent_vector::PersistentVector;
use crate::rust_core::ConsFn;
use crate::value::Value;
use std::rc::Rc;

#[test]
fn cons_test() {
let cons = ConsFn {};
let s = "insert as first";
let args = vec![
Rc::new(Value::String(String::from(s))),
Rc::new(Value::PersistentVector(
vec![
Rc::new(Value::String(String::from("second"))),
Rc::new(Value::String(String::from("third"))),
]
.into_iter()
.collect::<PersistentVector>(),
)),
];
assert_eq!(
Value::PersistentList(
vec![
Rc::new(Value::String(String::from("insert as first"))),
Rc::new(Value::String(String::from("second"))),
Rc::new(Value::String(String::from("third")))
]
.into_iter()
.collect::<PersistentList>()
),
cons.invoke(args)
);
}
}
}
2 changes: 1 addition & 1 deletion src/rust_core/refer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::environment::Environment;
use crate::error_message;
use crate::ifn::IFn;
use crate::keyword::Keyword;
use crate::persistent_vector::{ToPersistentVectorIter};
use crate::persistent_vector::ToPersistentVectorIter;
use crate::symbol::Symbol;
use crate::type_tag::TypeTag;
use crate::util::IsOdd;
Expand Down