Skip to content

Commit

Permalink
Add core update function and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mikera committed Sep 21, 2024
1 parent d7f82d3 commit eb0cd5b
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 11 deletions.
33 changes: 22 additions & 11 deletions convex-core/src/main/cvx/convex/core/core.cvx
Original file line number Diff line number Diff line change
Expand Up @@ -646,20 +646,18 @@
(compile (quote ~code))))

(defmacro tailcall
^{:doc {:description ["Advanced feature. While `return` stops the execution of a function and return, `tailcall` calls another one without consuming additional stack depth."
"Rest of the current function will never be executed."]
^{:doc {:description ["Perform a tail call to a function without consuming additional stack depth."
"Assumes tail position: rest of the current function, if any, will not be executed."]
:examples [{:code "(tailcall (some-function 1 2 3))"}]
:signature [{:params [[f & args]] }]}}
[callspec]
(let []
(when-not (list? callspec)
(fail :ARGUMENT
"tailcall requires a list representing function invocation"))
(let [n (count callspec)]
(if (== n 0)
(fail :ARGUMENT "Tailcall requires at least a function argument in call list"))
(cons 'tailcall*
callspec))))
(cond
(not (list? callspec))
(fail :ARGUMENT "tailcall requires a list representing function invocation")
(empty? callspec) (fail :ARGUMENT "tailcall requires a function argument")
(cons
'tailcall*
callspec)))

(defmacro undef
^{:doc {:description "Opposite of `def`. Undefines a symbol, removing the mapping from the current environment if it exists."
Expand All @@ -678,3 +676,16 @@
(let [new-value# ~(cons 'do body)]
(recur ~change new-value#))
value#)))

(defn update
^{:doc {:description "Update a value in a associative data structure by applying a function."
:examples [{:code "(update {:count 1} :count inc)"}]
:signature [{:params [m k f & args]}]}}
([m k f]
(assoc m k (f (get m k))))

([m k f x]
(assoc m k (f (get m k) x)))

([m k f x & more]
(assoc m k (apply f (get m k) more))))
23 changes: 23 additions & 0 deletions convex-core/src/test/java/convex/core/lang/CoreTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1322,6 +1322,29 @@ public void testAssocSets() {
assertArityError(step("(assoc #{} 1 2 3)")); // arity before cast
assertArityError(step("(assoc #{} 1)"));
}

@Test
public void testUpdate() {
assertEquals(Vectors.of(1,2,4),eval("(update [1 2 3] 2 inc)"));
assertEquals(Vectors.of(3),eval("(update [[1 2 3]] 0 count)"));

assertEquals(Vectors.of(1,2,3),eval("(update [1 2 3] 1 identity)"));

// nil works as empty map
assertEquals(Maps.of(2,Sets.of(2,3)),eval("(update nil 2 union #{2,3})"));

assertEquals(2L, evalL("(:count (update {:count 1} :count inc))")); // Example from docstring

// 666 is a bad value in all cases
assertCastError(step("(update [1 2 3] 2 666)"));
assertCastError(step("(update 666 2 inc)"));

assertArityError(step("(update)"));
assertArityError(step("(update {} :k)"));

// arity error on count
assertArityError(step("(update [[2]] 0 count 666)"));
}

@Test
public void testAssocIn() {
Expand Down

0 comments on commit eb0cd5b

Please sign in to comment.