Skip to content

Commit c351ee5

Browse files
committed
Added meta and with-meta
1 parent 35b1073 commit c351ee5

File tree

4 files changed

+113
-1
lines changed

4 files changed

+113
-1
lines changed

src/environment.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,8 @@ impl Environment {
336336
let ns_macro = rust_core::NsMacro::new(Rc::clone(&environment));
337337
let load_file_fn = rust_core::LoadFileFn::new(Rc::clone(&environment));
338338
let refer_fn = rust_core::ReferFn::new(Rc::clone(&environment));
339-
//let meta_fn = rust_core::MetaFn::new(Rc::clone(&environment));
339+
let meta_fn = rust_core::MetaFn::new(Rc::clone(&environment));
340+
let with_meta_fn = rust_core::WithMetaFn::new(Rc::clone(&environment));
340341
let var_fn = rust_core::special_form::VarFn::new(Rc::clone(&environment));
341342
// @TODO after we merge this with all the other commits we have,
342343
// just change all the `insert`s here to use insert_in_namespace
@@ -356,6 +357,8 @@ impl Environment {
356357
environment.insert(Symbol::intern("fn"), fn_macro.to_rc_value());
357358
environment.insert(Symbol::intern("defmacro"), defmacro_macro.to_rc_value());
358359
environment.insert(Symbol::intern("eval"), eval_fn.to_rc_value());
360+
environment.insert(Symbol::intern("meta"), meta_fn.to_rc_value());
361+
environment.insert(Symbol::intern("with-meta"), with_meta_fn.to_rc_value());
359362
environment.insert(Symbol::intern("var-fn*"), var_fn.to_rc_value());
360363

361364
// Thread namespace

src/rust_core.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ pub use self::special_form::*;
99
pub(crate) mod eval;
1010
pub use self::eval::*;
1111

12+
pub(crate) mod meta;
13+
pub use self::meta::*;
14+
pub(crate) mod with_meta;
15+
pub use self::with_meta::*;
1216
// macros
1317
pub(crate) mod do_macro;
1418
pub use self::do_macro::*;

src/rust_core/meta.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use crate::environment::Environment;
2+
use crate::error_message;
3+
use crate::ifn::IFn;
4+
use crate::type_tag::TypeTag;
5+
use crate::protocol::ProtocolCastable;
6+
use crate::protocols;
7+
use crate::traits::IMeta;
8+
use crate::value::{ToValue, Value};
9+
use std::rc::Rc;
10+
11+
/// Returns meta for symbol
12+
/// Todo: currently uses form (meta 'clojure.string/join)
13+
/// should use #'var-form
14+
/// TODO: macro: true/false
15+
/// TODO: argslists for functions
16+
#[derive(Debug, Clone)]
17+
pub struct MetaFn {
18+
enclosing_environment: Rc<Environment>,
19+
}
20+
impl MetaFn {
21+
pub fn new(enclosing_environment: Rc<Environment>) -> MetaFn {
22+
MetaFn {
23+
enclosing_environment,
24+
}
25+
}
26+
}
27+
impl ToValue for MetaFn {
28+
fn to_value(&self) -> Value {
29+
Value::IFn(Rc::new(self.clone()))
30+
}
31+
}
32+
impl IFn for MetaFn {
33+
fn invoke(&self, args: Vec<Rc<Value>>) -> Value {
34+
if args.len() != 1 {
35+
return error_message::wrong_arg_count(1, args.len());
36+
}
37+
match args.get(0).unwrap().try_as_protocol::<protocols::IMeta>() {
38+
Some(imeta) => imeta.meta().to_value(),
39+
// In order to avoid having the cryptic error messages of Clojure, we're experimenting here
40+
// already with some other error messages. As we finds ones we like, they will likewise be
41+
// abstracted out to their own functions -- for now, they're just one offs
42+
_ => error_message::custom(&format!(
43+
"In (meta ..), .. must be an instance of IMeta, and {} is of type {}, which is not",
44+
args.get(0).unwrap(),
45+
args.get(0).unwrap().type_tag())
46+
)
47+
//error_message::cast_error(Cast("IMeta"), TypeTag::PersistentListMap)
48+
}
49+
}
50+
}

src/rust_core/with_meta.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use crate::environment::Environment;
2+
use crate::error_message;
3+
use crate::ifn::IFn;
4+
use crate::protocol::ProtocolCastable;
5+
use crate::protocols;
6+
use crate::protocol::Protocol;
7+
use crate::traits::IObj;
8+
use crate::persistent_list_map::PersistentListMap;
9+
use crate::type_tag::TypeTag;
10+
use crate::value::{ToValue, Value};
11+
use std::rc::Rc;
12+
13+
/// (with-meta obj m)
14+
/// returns object with given metadata
15+
#[derive(Debug, Clone)]
16+
pub struct WithMetaFn {
17+
enclosing_environment: Rc<Environment>,
18+
}
19+
impl WithMetaFn {
20+
pub fn new(enclosing_environment: Rc<Environment>) -> WithMetaFn {
21+
WithMetaFn {
22+
enclosing_environment,
23+
}
24+
}
25+
}
26+
impl ToValue for WithMetaFn {
27+
fn to_value(&self) -> Value {
28+
Value::IFn(Rc::new(self.clone()))
29+
}
30+
}
31+
impl IFn for WithMetaFn {
32+
fn invoke(&self, args: Vec<Rc<Value>>) -> Value {
33+
if args.len() != 2 {
34+
return error_message::wrong_arg_count(2, args.len());
35+
}
36+
37+
match args.get(0).unwrap().try_as_protocol::<protocols::IObj>() {
38+
Some(obj) => match args.get(1).unwrap().to_value() {
39+
Value::PersistentListMap(plistmap) => {
40+
obj.with_meta(plistmap).unwrap().to_value()
41+
}
42+
_ => error_message::type_mismatch(
43+
TypeTag::PersistentListMap,
44+
args.get(0).unwrap(),
45+
),
46+
}
47+
// Again, this will likely be swapped for a proper error function, we are currently
48+
// experimenting with new error messages
49+
_ => error_message::custom(&format!(
50+
"In with-meta: first argument is supposed to be of instance IObj, but its type {} is not",
51+
args.get(0).unwrap().type_tag()
52+
))
53+
}
54+
}
55+
}

0 commit comments

Comments
 (0)