add string keys to dicts

This commit is contained in:
Scott Richmond 2025-07-03 12:41:00 -04:00
parent d334e483a5
commit 659fdd3506
2 changed files with 82 additions and 18 deletions

View File

@ -60,7 +60,15 @@ pub fn doc(f: &Value) -> Value {
pub fn assoc(dict: &Value, key: &Value, value: &Value) -> Value { pub fn assoc(dict: &Value, key: &Value, value: &Value) -> Value {
match (dict, key) { match (dict, key) {
(Value::Dict(d), Value::Keyword(k)) => Value::Dict(Box::new(d.update(k, value.clone()))), (Value::Dict(d), Value::Keyword(k)) => {
Value::Dict(Box::new(d.update(Key::Keyword(k), value.clone())))
}
(Value::Dict(d), Value::Interned(k)) => {
Value::Dict(Box::new(d.update(Key::Interned(k), value.clone())))
}
(Value::Dict(d), Value::String(s)) => {
Value::Dict(Box::new(d.update(Key::String(s.clone()), value.clone())))
}
_ => unreachable!("internal Ludus error calling assoc with ({dict}, {key}, {value})"), _ => unreachable!("internal Ludus error calling assoc with ({dict}, {key}, {value})"),
} }
} }
@ -175,7 +183,17 @@ pub fn dissoc(dict: &Value, key: &Value) -> Value {
match (dict, key) { match (dict, key) {
(Value::Dict(dict), Value::Keyword(key)) => { (Value::Dict(dict), Value::Keyword(key)) => {
let mut new = dict.clone(); let mut new = dict.clone();
new.remove(key); new.remove(&Key::Keyword(key));
Value::Dict(new)
}
(Value::Dict(dict), Value::Interned(key)) => {
let mut new = dict.clone();
new.remove(&Key::Interned(key));
Value::Dict(new)
}
(Value::Dict(dict), Value::String(key)) => {
let mut new = dict.clone();
new.remove(&Key::String(key.clone()));
Value::Dict(new) Value::Dict(new)
} }
_ => unreachable!("internal Ludus error"), _ => unreachable!("internal Ludus error"),
@ -220,7 +238,15 @@ pub fn at(ordered: &Value, i: &Value) -> Value {
pub fn get(dict: &Value, key: &Value) -> Value { pub fn get(dict: &Value, key: &Value) -> Value {
match (dict, key) { match (dict, key) {
(Value::Dict(dict), Value::Keyword(key)) => match dict.get(key) { (Value::Dict(dict), Value::Keyword(key)) => match dict.get(&Key::Keyword(key)) {
Some(x) => x.clone(),
None => Value::Nil,
},
(Value::Dict(dict), Value::Interned(key)) => match dict.get(&Key::Interned(key)) {
Some(x) => x.clone(),
None => Value::Nil,
},
(Value::Dict(dict), Value::String(key)) => match dict.get(&Key::String(key.clone())) {
Some(x) => x.clone(), Some(x) => x.clone(),
None => Value::Nil, None => Value::Nil,
}, },
@ -344,7 +370,7 @@ pub fn list(x: &Value) -> Value {
let kvs = d.iter(); let kvs = d.iter();
let mut list = vector![]; let mut list = vector![];
for (key, value) in kvs { for (key, value) in kvs {
let kv = Value::Tuple(Rc::new(vec![Value::Keyword(key), value.clone()])); let kv = Value::Tuple(Rc::new(vec![key.to_value(), value.clone()]));
list.push_back(kv); list.push_back(kv);
} }
Value::List(Box::new(list)) Value::List(Box::new(list))
@ -645,5 +671,9 @@ pub fn make_base() -> Value {
("unbox", Value::BaseFn(BaseFn::Unary("unbox", unbox))), ("unbox", Value::BaseFn(BaseFn::Unary("unbox", unbox))),
("upcase", Value::BaseFn(BaseFn::Unary("upcase", upcase))), ("upcase", Value::BaseFn(BaseFn::Unary("upcase", upcase))),
]; ];
let members = members
.iter()
.map(|(name, bfn)| (Key::Keyword(name), bfn.clone()))
.collect::<Vec<_>>();
Value::Dict(Box::new(HashMap::from(members))) Value::Dict(Box::new(HashMap::from(members)))
} }

View File

@ -112,6 +112,42 @@ pub struct Partial {
pub function: Value, pub function: Value,
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Key {
Keyword(&'static str),
Interned(&'static str),
String(Rc<String>),
}
impl std::fmt::Display for Key {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Key::Keyword(s) => write!(f, ":{s}"),
Key::Interned(s) => write!(f, "\"{s}\""),
Key::String(s) => write!(f, "\"{s}\""),
}
}
}
impl Key {
pub fn to_value(&self) -> Value {
match self {
Key::Keyword(s) => Value::Keyword(s),
Key::Interned(s) => Value::Interned(s),
Key::String(s) => Value::String(s.clone()),
}
}
pub fn from_value(value: Value) -> Key {
match value {
Value::Keyword(s) => Key::Keyword(s),
Value::Interned(s) => Key::Keyword(s),
Value::String(s) => Key::String(s.clone()),
_ => unreachable!("dict keys must be keywords or strings"),
}
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Value { pub enum Value {
Nothing, Nothing,
@ -124,7 +160,7 @@ pub enum Value {
Number(f64), Number(f64),
Tuple(Rc<Vec<Value>>), Tuple(Rc<Vec<Value>>),
List(Box<Vector<Value>>), List(Box<Vector<Value>>),
Dict(Box<HashMap<&'static str, Value>>), Dict(Box<HashMap<Key, Value>>),
Box(Rc<RefCell<Value>>), Box(Rc<RefCell<Value>>),
Fn(Rc<LFn>), Fn(Rc<LFn>),
BaseFn(BaseFn), BaseFn(BaseFn),
@ -234,9 +270,8 @@ impl Value {
let members = d let members = d
.iter() .iter()
.map(|(k, v)| { .map(|(k, v)| {
let key_show = Value::Keyword(k).show();
let value_show = v.show(); let value_show = v.show();
format!("{key_show} {value_show}") format!("{k} {value_show}")
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", "); .join(", ");
@ -338,9 +373,8 @@ impl Value {
let members = d let members = d
.iter() .iter()
.map(|(k, v)| { .map(|(k, v)| {
let key_show = Value::Keyword(k).stringify();
let value_show = v.stringify(); let value_show = v.stringify();
format!("{key_show} {value_show}") format!("{k} {value_show}")
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", "); .join(", ");
@ -437,13 +471,13 @@ impl Value {
Value::Tuple(Rc::new(vec)) Value::Tuple(Rc::new(vec))
} }
pub fn get_shared_box(&self, name: &'static str) -> Value { // pub fn get_shared_box(&self, name: &'static str) -> Value {
match self { // match self {
Value::Dict(dict) => dict // Value::Dict(dict) => dict
.get(name) // .get(name)
.expect("expected dict to have requested value") // .expect("expected dict to have requested value")
.clone(), // .clone(),
_ => unreachable!("expected dict"), // _ => unreachable!("expected dict"),
} // }
} // }
} }