Skip to content

Commit fe0ae54

Browse files
committed
Added if built-in macro and the ability to read nil
1 parent f3c2fc3 commit fe0ae54

File tree

4 files changed

+49
-6
lines changed

4 files changed

+49
-6
lines changed

src/environment.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ impl Environment {
8585
let def_macro = Value::DefMacro {};
8686
let fn_macro = Value::FnMacro {};
8787
let defmacro_macro = Value::DefmacroMacro {};
88+
let if_macro = Value::IfMacro {};
8889
let environment = Rc::new(Environment::new_main_environment());
8990

9091
let eval_fn = rust_core::EvalFn::new(Rc::clone(&environment));
@@ -106,6 +107,7 @@ impl Environment {
106107
environment.insert(Symbol::intern("do"), do_macro.to_rc_value());
107108
environment.insert(Symbol::intern("def"), def_macro.to_rc_value());
108109
environment.insert(Symbol::intern("fn"), fn_macro.to_rc_value());
110+
environment.insert(Symbol::intern("if"), if_macro.to_rc_value());
109111
environment.insert(Symbol::intern("defmacro"), defmacro_macro.to_rc_value());
110112
environment.insert(Symbol::intern("eval"), eval_fn.to_rc_value());
111113
environment.insert(

src/reader.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,18 @@ pub fn try_read_symbol(input: &str) -> IResult<&str, Value> {
227227
to_value_parser(symbol_parser)(input)
228228
}
229229

230+
231+
/// Tries to parse a &str that says 'nil' into Value::Nil
232+
/// Example Successes:
233+
/// nil => Value::Nil
234+
pub fn try_read_nil(input: &str) -> IResult<&str, Value> {
235+
named!(nil<&str, &str>, preceded!(consume_clojure_whitespaces, tag!("nil")));
236+
237+
let (rest_input, _) = nil(input)?;
238+
239+
Ok((rest_input,Value::Nil))
240+
}
241+
230242
// @TODO allow escaped strings
231243
/// Tries to parse &str into Value::String
232244
/// Example Successes:
@@ -320,6 +332,7 @@ pub fn try_read(input: &str) -> IResult<&str, Value> {
320332
preceded(
321333
consume_clojure_whitespaces,
322334
alt((
335+
try_read_nil,
323336
try_read_map,
324337
try_read_string,
325338
try_read_i32,

src/rust_core.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,6 @@ impl IFn for AssocFn {
281281
for (key_value, val_value) in args.into_iter().skip(1).tuples() {
282282
let key = key_value.to_rc_value();
283283
let val = val_value.to_rc_value();
284-
println!("key: {:?}, val: {:?}", key, val);
285284
retval = pmap.assoc(key, val);
286285
}
287286
return Value::PersistentListMap(retval);

src/value.rs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,16 @@ pub enum Value {
5454
DefMacro,
5555
FnMacro,
5656
LetMacro,
57+
IfMacro,
5758

5859
String(std::string::String),
5960
Nil,
6061
}
6162
use crate::value::Value::*;
6263

63-
// @TODO since I have already manually defined hash, surely this should just be defined
64-
// in terms of that?
6564
impl PartialEq for Value {
66-
// @TODO derive from Hash in some way? Note; can't derive with derive because of
67-
// our trait objects in IFn and Macro
6865
// @TODO implement our generic IFns some other way? After all, again, this isn't Java
66+
// @TODO improve this? This is a hack
6967
fn eq(&self, other: &Value) -> bool {
7068
//
7169
if let I32(i) = self {
@@ -146,6 +144,11 @@ impl PartialEq for Value {
146144
return true;
147145
}
148146
}
147+
if let IfMacro = self {
148+
if let IfMacro = other {
149+
return true;
150+
}
151+
}
149152

150153
if let String(string) = self {
151154
if let String(string2) = other {
@@ -172,6 +175,7 @@ enum ValueHash {
172175
DefmacroMacro,
173176
DefMacro,
174177
FnMacro,
178+
IfMacro,
175179
LetMacro,
176180
Nil,
177181
}
@@ -204,6 +208,7 @@ impl Hash for Value {
204208
DefMacro => ValueHash::DefMacro.hash(state),
205209
FnMacro => ValueHash::FnMacro.hash(state),
206210
LetMacro => ValueHash::LetMacro.hash(state),
211+
IfMacro => ValueHash::IfMacro.hash(state),
207212

208213
String(string) => string.hash(state),
209214
Nil => ValueHash::Nil.hash(state),
@@ -229,6 +234,7 @@ impl fmt::Display for Value {
229234
DefMacro => std::string::String::from("#macro[def*]"),
230235
DefmacroMacro => std::string::String::from("#macro[defmacro*]"),
231236
FnMacro => std::string::String::from("#macro[fn*]"),
237+
IfMacro => std::string::String::from("#macro[if*]"),
232238
LetMacro => std::string::String::from("#macro[let*]"),
233239
Value::String(string) => string.clone(),
234240
Nil => std::string::String::from("nil"),
@@ -270,6 +276,7 @@ impl Value {
270276
Value::DefmacroMacro => TypeTag::Macro,
271277
Value::LetMacro => TypeTag::Macro,
272278
Value::FnMacro => TypeTag::Macro,
279+
Value::IfMacro => TypeTag::Macro,
273280
Value::String(_) => TypeTag::String,
274281
Value::Nil => TypeTag::Nil,
275282
}
@@ -558,7 +565,23 @@ impl Value {
558565
)))),
559566
Ordering::Equal => Some(args.nth(0)),
560567
}
561-
}
568+
},
569+
IfMacro => {
570+
if args.len() != 2 && args.len() != 3 {
571+
return Some(Rc::new(Value::Condition(format!(
572+
"Wrong number of arguments (Given: {}, Expected: 2 or 3)",
573+
args.len()
574+
))))
575+
}
576+
let arg_refs = PersistentList::iter(args).collect::<Vec<Rc<Value>>>();
577+
let condition = arg_refs.get(0).unwrap().eval(Rc::clone(environment));
578+
579+
if condition.is_truthy() {
580+
Some(arg_refs.get(1).unwrap().eval_to_rc(Rc::clone(environment)))
581+
} else {
582+
Some(arg_refs.get(2).unwrap_or(&Rc::new(Value::Nil)).eval_to_rc(Rc::clone(environment)))
583+
}
584+
}
562585
//
563586
// If we're not a valid IFn
564587
//
@@ -568,6 +591,12 @@ impl Value {
568591
////////////////////////////////////////////////////////////////////////////////////////////////////
569592
// Eval Helper
570593
////////////////////////////////////////////////////////////////////////////////////////////////////
594+
fn is_truthy(&self) -> bool {
595+
if let Value::Nil = self {
596+
return false;
597+
}
598+
true
599+
}
571600
}
572601
pub trait ToValue {
573602
fn to_value(&self) -> Value;

0 commit comments

Comments
 (0)