Skip to content

Commit

Permalink
stdlib: Add set
Browse files Browse the repository at this point in the history
  • Loading branch information
slotThe committed Mar 23, 2024
1 parent edc5957 commit 4ff7bb1
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 4 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,11 @@ The type system looks as follows:
-- `get i x` gets the i'th thing out of x. I should be (evaluate to) a
-- number or a string, with x evaluating to array or object, respectively.
get : JSON → JSON → JSON
-- `set i x` coll sets the i'th thing in coll to x, where i
-- should be a number or a string, and coll should evaluate to
-- an array or object.
set : JSON → JSON → JSON → JSON
```

## REPL
Expand Down
32 changes: 29 additions & 3 deletions src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ impl Display for EvalError {
}
}

macro_rules! eval_err {
(WrongIndex, $ix:expr, $x:expr $(,)?) => {
EvalError::WrongIndex($ix.to_string(), $x.reify()?)
};
}

fn num_vars(names: &[String], var: &str) -> isize {
names.iter().filter(|&v| v == var).count() as isize
}
Expand Down Expand Up @@ -77,6 +83,8 @@ impl Sem {
Sem::App(Box::new(self.clone()), Box::new(s2.clone()))
}

fn str(s: &str) -> Self { Self::SConst(Const::String(s.to_string())) }

fn is_truthy(&self) -> bool {
!matches!(
self,
Expand Down Expand Up @@ -144,12 +152,30 @@ impl Sem {
// Get
(App(box SBuiltin(Get), box SConst(Const::Num(i))), Arr(xs)) => xs
.get(**i as usize)
.ok_or(EvalError::WrongIndex(i.to_string(), x.reify()?))
.ok_or(eval_err!(WrongIndex, i, x))
.cloned(),
(App(box SBuiltin(Get), box SConst(Const::String(s))), Obj(ob)) => ob
.get(&SConst(Const::String(s.to_string())))
.ok_or(EvalError::WrongIndex(s.to_string(), x.reify()?))
.get(&Sem::str(s))
.ok_or(eval_err!(WrongIndex, s, x))
.cloned(),
// Set
(App(box App(box SBuiltin(Set), box SConst(Const::Num(i))), box to), Arr(xs)) => {
let mut ys = xs.clone();
*ys
.get_mut(**i as usize)
.ok_or(eval_err!(WrongIndex, i, x))? = to.clone();
Ok(Arr(ys))
},
(
App(box App(box SBuiltin(Set), box SConst(Const::String(s))), box to),
Obj(ob),
) => {
let mut res = ob.clone();
*res
.get_mut(&Sem::str(s))
.ok_or(eval_err!(WrongIndex, s, x))? = to.clone();
Ok(Obj(res))
},
// Map
(App(box SBuiltin(Map), closure), Arr(xs)) => {
Ok(Arr(xs.iter().flat_map(|x| closure.apply(x)).collect()))
Expand Down
18 changes: 18 additions & 0 deletions src/eval/stdlib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub enum Builtin {
Id,
BConst,
Get,
Set,
Map,
Filter,
Foldl,
Expand Down Expand Up @@ -147,6 +148,23 @@ pub static STDLIB: LazyLock<BTreeMap<Builtin, StdFun>> = LazyLock::new(|| {
.fancy("x")
.plain("should evaluate to an array or object.")
),
mk_fun!(
Builtin::Set,
Type::arr(JSON, Type::arr(JSON, Type::arr(JSON, JSON))),
Blocks::new()
.fancy("set i x coll")
.plain("sets the")
.fancy("i'th")
.plain("thing in")
.fancy("coll")
.plain("to")
.fancy("x,")
.plain("where")
.fancy("i")
.plain("should be a number or a string, and")
.fancy("coll")
.plain("should evaluate to an array or object.")
),
mk_fun!(
Builtin::Map, // (a → b) → [a] → [b]
Type::forall(
Expand Down
1 change: 1 addition & 0 deletions src/eval/stdlib/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ impl Builtin {
Builtin::Id => "id",
Builtin::BConst => "const",
Builtin::Get => "get",
Builtin::Set => "set",
Builtin::Map => "map",
Builtin::Filter => "filter",
Builtin::Foldl => "foldl",
Expand Down
4 changes: 3 additions & 1 deletion src/eval/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
mod evaluator {
use std::assert_matches::assert_matches;

use crate::{eval::stdlib::{STDLIB_CTX, STDLIB_TYPES}, expr::{arr, λ, num, obj, parser::parse, var, Expr}, TCExpr};
use crate::{eval::stdlib::{STDLIB_CTX, STDLIB_TYPES}, expr::{arr, expr_str, num, obj, parser::parse, var, λ, Expr}, TCExpr};

macro_rules! eval_eq {
($left:expr, $right:expr $(,)?) => {
Expand Down Expand Up @@ -73,6 +73,8 @@ mod evaluator {
eval_eq!("map (- 1) [1, 2, 3, 4]", arr(&[num(0), num(1), num(2), num(3)]));
eval_eq!("map (1 +) [1, 2, 3, 4]", arr(&[num(2), num(3), num(4), num(5)]));
eval_eq!("(filter (get \"age\" | (>= 42)) | map .age | foldl (+) 0) [{name: \"A\", age: 43},{name:\"B\"},{name:\"C\", age:42}]", num(85));
eval_eq!("set 1 2 [ 1, 10, 3, 4 ]", arr(&[num(1), num(2), num(3), num(4)]));
eval_eq!("(λx → set 1 x.name [ 1, 10, 3, 4 ]) { name: \"bob\" }", arr(&[num(1), expr_str("bob"), num(3), num(4)]));
}

}

0 comments on commit 4ff7bb1

Please sign in to comment.