Created
February 9, 2022 11:02
-
-
Save ilyash-b/fd87050fd55e5d0de65a19cbee4b3ceb to your computer and use it in GitHub Desktop.
Autovivification for Next Generation Shell - experiment
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Following line will be needed when files will be auto-wrapped in "ns { ... }" | |
{ global deep_get, deep_set, deep_get_step, deep_set_step, deep_index_to_container_type } | |
doc %STATUS - experimental | |
F deep_get_step(node, _) { | |
throw LookupFail().set(container=node) | |
} | |
doc %STATUS - experimental | |
F deep_set_step(container, idx_or_key, next_idx_or_key) throw NotImplemented() | |
doc %STATUS - experimental | |
F deep_get_step(node, key) { | |
guard node =~ AnyOf(Hash, HashLike) | |
node[key] | |
} | |
doc %STATUS - experimental | |
F deep_set_step(node, key, val) { | |
guard node =~ AnyOf(Hash, HashLike) | |
node[key] = val | |
} | |
doc %STATUS - experimental | |
F deep_index_to_container_type(key) Hash | |
doc %STATUS - experimental | |
F deep_get_step(node:NormalTypeInstance, field:Str) { | |
node.(field) | |
} | |
doc %STATUS - experimental | |
F deep_set_step(node:NormalTypeInstance, field:Str, val) { | |
node.(field) = val | |
} | |
doc %STATUS - experimental | |
F deep_get_step(node, idx:Int) { | |
guard node =~ AnyOf(Arr, ArrLike) | |
node[idx] | |
} | |
doc %STATUS - experimental | |
F deep_set_step(node, idx:Int, val) { | |
guard node =~ AnyOf(Arr, ArrLike) | |
section "Ensure array is long enough" for(i=len(node);i<=idx;i+=1) { | |
node.push(null) | |
} | |
node[idx] = val | |
} | |
doc %STATUS - experimental | |
F deep_index_to_container_type(idx:Int) Arr | |
doc %STATUS - experimental | |
F deep_get(root, path, default=null) block b { | |
node = root | |
for p in path { | |
try { | |
node = deep_get_step(node, p) | |
} catch(lf:LookupFail) { | |
guard lf.container === node | |
b.return(default) | |
} | |
} | |
node | |
} | |
doc %STATUS - experimental | |
F deep_set(root, path:Arr, val) { | |
assert(path, 'path is expected to have at least one element, deep_set can not set the root') | |
path_iter = Iter(path) | |
container = null | |
idx_or_key = null | |
node = section "Navigate to last present element" block b { | |
node = root | |
while path_iter { | |
try { | |
container = node | |
idx_or_key = path_iter.next() | |
node = deep_get_step(node, idx_or_key) | |
} catch(lf:LookupFail) { | |
guard lf.container === node | |
b.return(node) | |
} | |
} | |
node | |
} | |
# echo("P $path_iter") | |
for p in path_iter { | |
# echo("P $path_iter $p") | |
next_container = deep_index_to_container_type(p)() | |
node = deep_set_step(container, idx_or_key, next_container) | |
container = next_container | |
idx_or_key = p | |
# echo("for end: container $container idx_or_key $idx_or_key") | |
} | |
deep_set_step(container, idx_or_key, val) | |
root | |
} | |
test("get existing hash->hash", { | |
h = {"a": {"b": 1}} | |
deep_get(h, ['a', 'b']).assert(1) | |
}) | |
test("get non-existing hash->hash", { | |
h = {"a": {"b": 1}} | |
deep_get(h, ['a', 'bx']).assert(null) | |
deep_get(h, ['a', 'b', 'c']).assert(null) | |
}) | |
test("set first level on custom type", { | |
type T | |
t = T() | |
t.deep_set(['field1'], 'val1').assert(T, 'deep_set should return object of type T') | |
t.assert({"field1": "val1"}) | |
}) | |
test("set two levels on custom type (hash)", { | |
type T | |
t = T() | |
t.deep_set(['field1', 'key1'], 'val1').assert(T, 'deep_set should return object of type T') | |
t.assert({"field1": {"key1": "val1"}}) | |
}) | |
test("set two levels on custom type (arr)", { | |
type T | |
t = T() | |
t.deep_set(['field1', 2], 'val1').assert(T, 'deep_set should return object of type T') | |
t.assert({"field1": [null, null, "val1"]}) | |
}) | |
The keys a, b and c are identifiers
Correct.
constraint
Nope. There is no constraint because of alternative syntax:
- For
Hash
, like in JavaScript, one can useh["what ever"]
- For objects, including user defined, the dot access syntax
h.a
access becomesh.("what ever")
For short, using get() would have a well explained and understood side effect
Somehow I think that anything with get
should not have side effects. We can maybe add deep_make()
or deep_ensure()
or anything of that sort to act like deep_set()
but without the final step of setting the leaf value.
deep_set(path, null)
mm... absence of an element is different than having it with null
value in NGS.
I guess it's time to try the "discussions" feature of GitHub. Did not have the chance yet.
Moving discussion to ngs-lang/ngs#550
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Another comment to something you wrote earlier
You wrote
I assume that in
The keys a, b and c are identifiers, that is they match the following RE
Whereas using any of the deep_*() functions you would free the user from that constraint and allow any string of characters to be used when doing deep parkour along path which may be specified in pieces or components where each could be one of
At least that is how I see it.