From 50c33989dcfdff7638d0e8705e595e34c6473424 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Mon, 29 Aug 2022 21:33:15 +0300 Subject: chore(tvix/eval): thread `slot` value through Compiler:compile_attr This threads the current local slot through the `compile_attr` function and all of its callers. At the moment this does not improve any user-facing behaviour, just internally changes the way in which some correct expressions would fail to run. Eventually this slot will need to reach everywhere ... Change-Id: Iba73123dd1ced421093d8fc18ebeeffc16efacf8 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6355 Tested-by: BuildkiteCI Reviewed-by: sterni --- tvix/eval/src/compiler/mod.rs | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) (limited to 'tvix/eval/src') diff --git a/tvix/eval/src/compiler/mod.rs b/tvix/eval/src/compiler/mod.rs index e3cb15032a14..1c8d0182a7c1 100644 --- a/tvix/eval/src/compiler/mod.rs +++ b/tvix/eval/src/compiler/mod.rs @@ -113,10 +113,10 @@ impl Compiler { ast::Expr::Str(s) => self.compile_str(s), ast::Expr::UnaryOp(op) => self.compile_unary_op(op), ast::Expr::BinOp(op) => self.compile_binop(op), - ast::Expr::HasAttr(has_attr) => self.compile_has_attr(has_attr), + ast::Expr::HasAttr(has_attr) => self.compile_has_attr(slot, has_attr), ast::Expr::List(list) => self.compile_list(list), - ast::Expr::AttrSet(attrs) => self.compile_attr_set(attrs), - ast::Expr::Select(select) => self.compile_select(select), + ast::Expr::AttrSet(attrs) => self.compile_attr_set(slot, attrs), + ast::Expr::Select(select) => self.compile_select(slot, select), ast::Expr::Assert(assert) => self.compile_assert(assert), ast::Expr::IfElse(if_else) => self.compile_if_else(if_else), ast::Expr::LetIn(let_in) => self.compile_let_in(let_in), @@ -334,7 +334,7 @@ impl Compiler { self.chunk().push_op(OpCode::OpAssertBool); } - fn compile_has_attr(&mut self, node: ast::HasAttr) { + fn compile_has_attr(&mut self, slot: Option, node: ast::HasAttr) { // Put the attribute set on the stack. self.compile(None, node.expr().unwrap()); @@ -345,7 +345,7 @@ impl Compiler { self.chunk().push_op(OpCode::OpAttrsTrySelect); } - self.compile_attr(fragment); + self.compile_attr(slot, fragment); } // After the last fragment, emit the actual instruction that @@ -353,9 +353,9 @@ impl Compiler { self.chunk().push_op(OpCode::OpAttrsIsSet); } - fn compile_attr(&mut self, node: ast::Attr) { + fn compile_attr(&mut self, slot: Option, node: ast::Attr) { match node { - ast::Attr::Dynamic(dynamic) => self.compile(None, dynamic.expr().unwrap()), + ast::Attr::Dynamic(dynamic) => self.compile(slot, dynamic.expr().unwrap()), ast::Attr::Str(s) => self.compile_str(s), ast::Attr::Ident(ident) => self.emit_literal_ident(&ident), } @@ -386,7 +386,7 @@ impl Compiler { // 1. Keys can be dynamically constructed through interpolation. // 2. Keys can refer to nested attribute sets. // 3. Attribute sets can (optionally) be recursive. - fn compile_attr_set(&mut self, node: ast::AttrSet) { + fn compile_attr_set(&mut self, slot: Option, node: ast::AttrSet) { if node.rec_token().is_some() { todo!("recursive attribute sets are not yet implemented") } @@ -413,7 +413,7 @@ impl Compiler { // instruction followed by a merge, rather // than pushing/popping the same attrs // potentially a lot of times. - self.compile(None, from.expr().unwrap()); + self.compile(slot, from.expr().unwrap()); self.emit_literal_ident(&ident); self.chunk().push_op(OpCode::OpAttrsSelect); } @@ -461,7 +461,7 @@ impl Compiler { let mut key_count = 0; for fragment in kv.attrpath().unwrap().attrs() { key_count += 1; - self.compile_attr(fragment); + self.compile_attr(slot, fragment); } // We're done with the key if there was only one fragment, @@ -474,18 +474,18 @@ impl Compiler { // The value is just compiled as normal so that its // resulting value is on the stack when the attribute set // is constructed at runtime. - self.compile(None, kv.value().unwrap()); + self.compile(slot, kv.value().unwrap()); } self.chunk().push_op(OpCode::OpAttrs(Count(count))); } - fn compile_select(&mut self, node: ast::Select) { + fn compile_select(&mut self, slot: Option, node: ast::Select) { let set = node.expr().unwrap(); let path = node.attrpath().unwrap(); if node.or_token().is_some() { - self.compile_select_or(set, path, node.default_expr().unwrap()); + self.compile_select_or(slot, set, path, node.default_expr().unwrap()); return; } @@ -497,7 +497,7 @@ impl Compiler { // TODO: multi-select instruction to avoid re-pushing attrs on // nested selects. for fragment in path.attrs() { - self.compile_attr(fragment); + self.compile_attr(slot, fragment); self.chunk().push_op(OpCode::OpAttrsSelect); } } @@ -531,12 +531,18 @@ impl Compiler { /// │ 14 ... │ │ .. .... │ /// └────────────────────────────┘ └─────────────────────────┘ /// ``` - fn compile_select_or(&mut self, set: ast::Expr, path: ast::Attrpath, default: ast::Expr) { + fn compile_select_or( + &mut self, + slot: Option, + set: ast::Expr, + path: ast::Attrpath, + default: ast::Expr, + ) { self.compile(None, set); let mut jumps = vec![]; for fragment in path.attrs() { - self.compile_attr(fragment); + self.compile_attr(slot, fragment); self.chunk().push_op(OpCode::OpAttrsTrySelect); jumps.push( self.chunk() @@ -552,7 +558,7 @@ impl Compiler { // Compile the default value expression and patch the final // jump to point *beyond* it. - self.compile(None, default); + self.compile(slot, default); self.patch_jump(final_jump); } -- cgit 1.4.1