feat(tvix/eval): implement nested '?' operator

Implements the nested presence check operator for attribuet sets by
traversing the chain of lookups through instructions that push/pop
sequentially deeper attribute sets onto the stack.

Note that this commit introduces a bug in case of nested attributes
not being found, which is fixed in a later commit.

Change-Id: Ic8b4c8648736f6cb048e3aa52592e4d075bf0544
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6163
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
Reviewed-by: grfn <grfn@gws.fyi>
This commit is contained in:
Vincent Ambo 2022-08-11 17:23:08 +03:00 committed by tazjin
parent cf3e3b784b
commit dd8f5f1dc8

View file

@ -448,9 +448,11 @@ impl Compiler {
//
// Otherwise, the right hand side is the (only) key expression
// itself and can be compiled directly.
let rhs = node.rhs().unwrap();
let mut next = node.rhs().unwrap();
let mut fragments = vec![];
if matches!(rhs.kind(), rnix::SyntaxKind::NODE_SELECT) {
loop {
if matches!(next.kind(), rnix::SyntaxKind::NODE_SELECT) {
// Keep nesting deeper until we encounter something
// different than `NODE_SELECT` on the left side. This is
// required because `rnix` parses nested keys as select
@ -458,12 +460,22 @@ impl Compiler {
//
// The parsed tree will nest something like `a.b.c.d.e.f`
// as (((((a, b), c), d), e), f).
todo!("nested '?' check")
fragments.push(next.last_child().unwrap());
next = next.first_child().unwrap();
} else {
self.compile_with_literal_ident(rhs)?;
self.compile_with_literal_ident(next)?;
for fragment in fragments.into_iter().rev() {
println!("fragment: {}", fragment);
self.chunk.add_op(OpCode::OpAttrsSelect);
self.compile_with_literal_ident(fragment)?;
}
self.chunk.add_op(OpCode::OpAttrsIsSet);
break;
}
}
Ok(())
}