diff options
Diffstat (limited to 'tvix')
-rw-r--r-- | tvix/eval/src/compiler.rs | 80 |
1 files changed, 42 insertions, 38 deletions
diff --git a/tvix/eval/src/compiler.rs b/tvix/eval/src/compiler.rs index 167ac731d68c..2167dce77d53 100644 --- a/tvix/eval/src/compiler.rs +++ b/tvix/eval/src/compiler.rs @@ -33,7 +33,7 @@ pub struct CompilationResult { pub errors: Vec<Error>, } -// Represents a single local already known to the compiler. +/// Represents a single local already known to the compiler. struct Local { // Definition name, which can be different kinds of tokens (plain // string or identifier). Nix does not allow dynamic names inside @@ -106,6 +106,14 @@ impl Compiler { .expect("compiler flaw: long-lived chunk reference") } + fn scope(&self) -> &Scope { + &self.scope + } + + fn scope_mut(&mut self) -> &mut Scope { + &mut self.scope + } + fn emit_constant(&mut self, value: Value) { let idx = self.chunk().push_constant(value); self.chunk().push_op(OpCode::OpConstant(idx)); @@ -658,9 +666,9 @@ impl Compiler { // optimised information about any "weird" stuff that's // happened to the scope (such as overrides of these // literals, or builtins). - "true" if self.scope.poisoned_true == 0 => self.chunk().push_op(OpCode::OpTrue), - "false" if self.scope.poisoned_false == 0 => self.chunk().push_op(OpCode::OpFalse), - "null" if self.scope.poisoned_null == 0 => self.chunk().push_op(OpCode::OpNull), + "true" if self.scope().poisoned_true == 0 => self.chunk().push_op(OpCode::OpTrue), + "false" if self.scope().poisoned_false == 0 => self.chunk().push_op(OpCode::OpFalse), + "null" if self.scope().poisoned_null == 0 => self.chunk().push_op(OpCode::OpNull), name => { // Note: `with` and some other special scoping @@ -668,7 +676,7 @@ impl Compiler { match self.resolve_local(name) { Some(idx) => self.chunk().push_op(OpCode::OpGetLocal(idx)), None => { - if self.scope.with_stack.is_empty() { + if self.scope().with_stack.is_empty() { self.emit_error( node.syntax().clone(), ErrorKind::UnknownStaticVariable, @@ -696,11 +704,10 @@ impl Compiler { self.compile(node.namespace().unwrap()); self.declare_phantom(); - self.scope.with_stack.push(With { - depth: self.scope.scope_depth, - }); + let depth = self.scope().scope_depth; + self.scope_mut().with_stack.push(With { depth }); - let with_idx = self.scope.locals.len() - 1; + let with_idx = self.scope().locals.len() - 1; self.chunk().push_op(OpCode::OpPushWith(with_idx)); self.compile(node.body().unwrap()); @@ -729,25 +736,25 @@ impl Compiler { } fn begin_scope(&mut self) { - self.scope.scope_depth += 1; + self.scope_mut().scope_depth += 1; } fn end_scope(&mut self) { - debug_assert!(self.scope.scope_depth != 0, "can not end top scope"); + debug_assert!(self.scope().scope_depth != 0, "can not end top scope"); // If this scope poisoned any builtins or special identifiers, // they need to be reset. - if self.scope.poisoned_true == self.scope.scope_depth { - self.scope.poisoned_true = 0; + if self.scope().poisoned_true == self.scope().scope_depth { + self.scope_mut().poisoned_true = 0; } - if self.scope.poisoned_false == self.scope.scope_depth { - self.scope.poisoned_false = 0; + if self.scope().poisoned_false == self.scope().scope_depth { + self.scope_mut().poisoned_false = 0; } - if self.scope.poisoned_null == self.scope.scope_depth { - self.scope.poisoned_null = 0; + if self.scope().poisoned_null == self.scope().scope_depth { + self.scope_mut().poisoned_null = 0; } - self.scope.scope_depth -= 1; + self.scope_mut().scope_depth -= 1; // When ending a scope, all corresponding locals need to be // removed, but the value of the body needs to remain on the @@ -756,8 +763,8 @@ impl Compiler { // TL;DR - iterate from the back while things belonging to the // ended scope still exist. - while !self.scope.locals.is_empty() - && self.scope.locals[self.scope.locals.len() - 1].depth > self.scope.scope_depth + while !self.scope().locals.is_empty() + && self.scope().locals[self.scope().locals.len() - 1].depth > self.scope().scope_depth { pops += 1; @@ -768,7 +775,7 @@ impl Compiler { node: Some(node), used, .. - }) = self.scope.locals.pop() + }) = self.scope_mut().locals.pop() { if !used { self.emit_warning(node, WarningKind::UnusedBinding); @@ -780,11 +787,12 @@ impl Compiler { self.chunk().push_op(OpCode::OpCloseScope(pops)); } - while !self.scope.with_stack.is_empty() - && self.scope.with_stack[self.scope.with_stack.len() - 1].depth > self.scope.scope_depth + while !self.scope().with_stack.is_empty() + && self.scope().with_stack[self.scope().with_stack.len() - 1].depth + > self.scope().scope_depth { self.chunk().push_op(OpCode::OpPopWith); - self.scope.with_stack.pop(); + self.scope_mut().with_stack.pop(); } } @@ -794,43 +802,39 @@ impl Compiler { fn declare_local<S: Into<String>>(&mut self, node: rnix::SyntaxNode, name: S) { // Set up scope poisoning if required. let name = name.into(); + let mut scope = self.scope_mut(); match name.as_str() { - "true" if self.scope.poisoned_true == 0 => { - self.scope.poisoned_true = self.scope.scope_depth - } + "true" if scope.poisoned_true == 0 => scope.poisoned_true = scope.scope_depth, - "false" if self.scope.poisoned_false == 0 => { - self.scope.poisoned_false = self.scope.scope_depth - } + "false" if scope.poisoned_false == 0 => scope.poisoned_false = scope.scope_depth, - "null" if self.scope.poisoned_null == 0 => { - self.scope.poisoned_null = self.scope.scope_depth - } + "null" if scope.poisoned_null == 0 => scope.poisoned_null = scope.scope_depth, _ => {} }; - self.scope.locals.push(Local { + scope.locals.push(Local { name: name.into(), node: Some(node), - depth: self.scope.scope_depth, + depth: scope.scope_depth, phantom: false, used: false, }); } fn declare_phantom(&mut self) { - self.scope.locals.push(Local { + let depth = self.scope().scope_depth; + self.scope_mut().locals.push(Local { + depth, name: "".into(), node: None, - depth: self.scope.scope_depth, phantom: true, used: true, }); } fn resolve_local(&mut self, name: &str) -> Option<usize> { - let scope = &mut self.scope; + let scope = self.scope_mut(); for (idx, local) in scope.locals.iter_mut().enumerate().rev() { if !local.phantom && local.name == name { |