Add a recursive object merge strategy and bind it to *
This commit adds a jv_object_merge_recursive function, that performs recursive object merging, and binds it to multiply when applied to two objects. Added docs and tests. Closes #320
This commit is contained in:
1 parent
219bb9ecb7
commit
2aa8a43c5b
5 files changed
+44
-1
No files matched your search
@@ -172,6 +172,8 @@ static jv f_multiply(jv input, jv a, jv b) {
|
|||||||
return jv_null();
|
return jv_null();
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
} else if (jv_get_kind(a) == JV_KIND_OBJECT && jv_get_kind(b) == JV_KIND_OBJECT) {
|
||||||
|
return jv_object_merge_recursive(a, b);
|
||||||
} else {
|
} else {
|
||||||
return type_error2(a, b, "cannot be multiplied");
|
return type_error2(a, b, "cannot be multiplied");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -479,7 +479,8 @@ sections:
|
|||||||
- **Objects** are added by merging, that is, inserting all
|
- **Objects** are added by merging, that is, inserting all
|
||||||
the key-value pairs from both objects into a single
|
the key-value pairs from both objects into a single
|
||||||
combined object. If both objects contain a value for the
|
combined object. If both objects contain a value for the
|
||||||
same key, the object on the right of the `+` wins.
|
same key, the object on the right of the `+` wins. (For
|
||||||
|
recursive merge use the `*` operator.)
|
||||||
|
|
||||||
`null` can be added to any value, and returns the other
|
`null` can be added to any value, and returns the other
|
||||||
value unchanged.
|
value unchanged.
|
||||||
@@ -527,6 +528,11 @@ sections:
|
|||||||
Dividing a string by another splits the first using the second
|
Dividing a string by another splits the first using the second
|
||||||
as separators.
|
as separators.
|
||||||
|
|
||||||
|
Multiplying two objects will merge them recursively: this works
|
||||||
|
like addition but if both objects contain a value for the
|
||||||
|
same key, and the values are objects, the two are merged with
|
||||||
|
the same strategy.
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- program: '10 / . * 3'
|
- program: '10 / . * 3'
|
||||||
input: 5
|
input: 5
|
||||||
@@ -534,6 +540,9 @@ sections:
|
|||||||
- program: '. / ", "'
|
- program: '. / ", "'
|
||||||
input: '"a, b,c,d, e"'
|
input: '"a, b,c,d, e"'
|
||||||
output: ['["a","b,c,d","e"]']
|
output: ['["a","b,c,d","e"]']
|
||||||
|
- program: '{"k": {"a": 1, "b": 2}} * {"k": {"a": 0,"c": 3}}'
|
||||||
|
input: 'null'
|
||||||
|
output: ['{"k": {"a": 0, "b": 2, "c": 3}}']
|
||||||
|
|
||||||
- title: `length`
|
- title: `length`
|
||||||
body: |
|
body: |
|
||||||
|
|||||||
@@ -1106,6 +1106,25 @@ jv jv_object_merge(jv a, jv b) {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jv jv_object_merge_recursive(jv a, jv b) {
|
||||||
|
assert(jv_get_kind(a) == JV_KIND_OBJECT);
|
||||||
|
assert(jv_get_kind(b) == JV_KIND_OBJECT);
|
||||||
|
|
||||||
|
jv_object_foreach(b, k, v) {
|
||||||
|
jv elem = jv_object_get(jv_copy(a), jv_copy(k));
|
||||||
|
if (jv_is_valid(elem) &&
|
||||||
|
jv_get_kind(elem) == JV_KIND_OBJECT &&
|
||||||
|
jv_get_kind(v) == JV_KIND_OBJECT) {
|
||||||
|
a = jv_object_set(a, k, jv_object_merge_recursive(elem, v));
|
||||||
|
} else {
|
||||||
|
jv_free(elem);
|
||||||
|
a = jv_object_set(a, k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jv_free(b);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
int jv_object_contains(jv a, jv b) {
|
int jv_object_contains(jv a, jv b) {
|
||||||
assert(jv_get_kind(a) == JV_KIND_OBJECT);
|
assert(jv_get_kind(a) == JV_KIND_OBJECT);
|
||||||
assert(jv_get_kind(b) == JV_KIND_OBJECT);
|
assert(jv_get_kind(b) == JV_KIND_OBJECT);
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ jv jv_object_set(jv object, jv key, jv value);
|
|||||||
jv jv_object_delete(jv object, jv key);
|
jv jv_object_delete(jv object, jv key);
|
||||||
int jv_object_length(jv object);
|
int jv_object_length(jv object);
|
||||||
jv jv_object_merge(jv, jv);
|
jv jv_object_merge(jv, jv);
|
||||||
|
jv jv_object_merge_recursive(jv, jv);
|
||||||
|
|
||||||
int jv_object_iter(jv);
|
int jv_object_iter(jv);
|
||||||
int jv_object_iter_next(jv, int);
|
int jv_object_iter_next(jv, int);
|
||||||
|
|||||||
@@ -779,3 +779,15 @@ null
|
|||||||
map([1,2][0:.])
|
map([1,2][0:.])
|
||||||
[-1, 1, 2, 3, 1000000000000000000]
|
[-1, 1, 2, 3, 1000000000000000000]
|
||||||
[[1], [1], [1,2], [1,2], [1,2]]
|
[[1], [1], [1,2], [1,2], [1,2]]
|
||||||
|
|
||||||
|
{"k": {"a": 1, "b": 2}} * .
|
||||||
|
{"k": {"a": 0,"c": 3}}
|
||||||
|
{"k": {"a": 0, "b": 2, "c": 3}}
|
||||||
|
|
||||||
|
{"k": {"a": 1, "b": 2}, "hello": {"x": 1}} * .
|
||||||
|
{"k": {"a": 0,"c": 3}, "hello": 1}
|
||||||
|
{"k": {"a": 0, "b": 2, "c": 3}, "hello": 1}
|
||||||
|
|
||||||
|
{"k": {"a": 1, "b": 2}, "hello": 1} * .
|
||||||
|
{"k": {"a": 0,"c": 3}, "hello": {"x": 1}}
|
||||||
|
{"k": {"a": 0, "b": 2, "c": 3}, "hello": {"x": 1}}
|
||||||
Reference in new issue
Block a user