Skip to content

Instantly share code, notes, and snippets.

@ilyash-b
Created February 9, 2022 11:02
Show Gist options
  • Save ilyash-b/fd87050fd55e5d0de65a19cbee4b3ceb to your computer and use it in GitHub Desktop.
Save ilyash-b/fd87050fd55e5d0de65a19cbee4b3ceb to your computer and use it in GitHub Desktop.
Autovivification for Next Generation Shell - experiment
# 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"]})
})
@ilyash-b
Copy link
Author

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 use h["what ever"]
  • For objects, including user defined, the dot access syntax h.a access becomes h.("what ever")

@ilyash-b
Copy link
Author

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.

@ilyash-b
Copy link
Author

deep_set(path, null)

mm... absence of an element is different than having it with null value in NGS.

@ilyash-b
Copy link
Author

I guess it's time to try the "discussions" feature of GitHub. Did not have the chance yet.

@ilyash-b
Copy link
Author

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