refactor(tvix/eval): add compiler accessor for current scope
Change-Id: I7488087d95c1b3fb7f70fc29af0d5b0d0a25a428 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6245 Tested-by: BuildkiteCI Reviewed-by: grfn <grfn@gws.fyi>
This commit is contained in:
		
							parent
							
								
									a060c8f467
								
							
						
					
					
						commit
						9d1451773b
					
				
					 1 changed files with 42 additions and 38 deletions
				
			
		|  | @ -33,7 +33,7 @@ pub struct CompilationResult { | ||||||
|     pub errors: Vec<Error>, |     pub errors: Vec<Error>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Represents a single local already known to the compiler.
 | /// Represents a single local already known to the compiler.
 | ||||||
| struct Local { | struct Local { | ||||||
|     // Definition name, which can be different kinds of tokens (plain
 |     // Definition name, which can be different kinds of tokens (plain
 | ||||||
|     // string or identifier). Nix does not allow dynamic names inside
 |     // string or identifier). Nix does not allow dynamic names inside
 | ||||||
|  | @ -106,6 +106,14 @@ impl Compiler { | ||||||
|             .expect("compiler flaw: long-lived chunk reference") |             .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) { |     fn emit_constant(&mut self, value: Value) { | ||||||
|         let idx = self.chunk().push_constant(value); |         let idx = self.chunk().push_constant(value); | ||||||
|         self.chunk().push_op(OpCode::OpConstant(idx)); |         self.chunk().push_op(OpCode::OpConstant(idx)); | ||||||
|  | @ -658,9 +666,9 @@ impl Compiler { | ||||||
|             // optimised information about any "weird" stuff that's
 |             // optimised information about any "weird" stuff that's
 | ||||||
|             // happened to the scope (such as overrides of these
 |             // happened to the scope (such as overrides of these
 | ||||||
|             // literals, or builtins).
 |             // literals, or builtins).
 | ||||||
|             "true" if self.scope.poisoned_true == 0 => self.chunk().push_op(OpCode::OpTrue), |             "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), |             "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), |             "null" if self.scope().poisoned_null == 0 => self.chunk().push_op(OpCode::OpNull), | ||||||
| 
 | 
 | ||||||
|             name => { |             name => { | ||||||
|                 // Note: `with` and some other special scoping
 |                 // Note: `with` and some other special scoping
 | ||||||
|  | @ -668,7 +676,7 @@ impl Compiler { | ||||||
|                 match self.resolve_local(name) { |                 match self.resolve_local(name) { | ||||||
|                     Some(idx) => self.chunk().push_op(OpCode::OpGetLocal(idx)), |                     Some(idx) => self.chunk().push_op(OpCode::OpGetLocal(idx)), | ||||||
|                     None => { |                     None => { | ||||||
|                         if self.scope.with_stack.is_empty() { |                         if self.scope().with_stack.is_empty() { | ||||||
|                             self.emit_error( |                             self.emit_error( | ||||||
|                                 node.syntax().clone(), |                                 node.syntax().clone(), | ||||||
|                                 ErrorKind::UnknownStaticVariable, |                                 ErrorKind::UnknownStaticVariable, | ||||||
|  | @ -696,11 +704,10 @@ impl Compiler { | ||||||
|         self.compile(node.namespace().unwrap()); |         self.compile(node.namespace().unwrap()); | ||||||
| 
 | 
 | ||||||
|         self.declare_phantom(); |         self.declare_phantom(); | ||||||
|         self.scope.with_stack.push(With { |         let depth = self.scope().scope_depth; | ||||||
|             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.chunk().push_op(OpCode::OpPushWith(with_idx)); | ||||||
| 
 | 
 | ||||||
|         self.compile(node.body().unwrap()); |         self.compile(node.body().unwrap()); | ||||||
|  | @ -729,25 +736,25 @@ impl Compiler { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn begin_scope(&mut self) { |     fn begin_scope(&mut self) { | ||||||
|         self.scope.scope_depth += 1; |         self.scope_mut().scope_depth += 1; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn end_scope(&mut self) { |     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,
 |         // If this scope poisoned any builtins or special identifiers,
 | ||||||
|         // they need to be reset.
 |         // they need to be reset.
 | ||||||
|         if self.scope.poisoned_true == self.scope.scope_depth { |         if self.scope().poisoned_true == self.scope().scope_depth { | ||||||
|             self.scope.poisoned_true = 0; |             self.scope_mut().poisoned_true = 0; | ||||||
|         } |         } | ||||||
|         if self.scope.poisoned_false == self.scope.scope_depth { |         if self.scope().poisoned_false == self.scope().scope_depth { | ||||||
|             self.scope.poisoned_false = 0; |             self.scope_mut().poisoned_false = 0; | ||||||
|         } |         } | ||||||
|         if self.scope.poisoned_null == self.scope.scope_depth { |         if self.scope().poisoned_null == self.scope().scope_depth { | ||||||
|             self.scope.poisoned_null = 0; |             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
 |         // When ending a scope, all corresponding locals need to be
 | ||||||
|         // removed, but the value of the body needs to remain on the
 |         // 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
 |         // TL;DR - iterate from the back while things belonging to the
 | ||||||
|         // ended scope still exist.
 |         // ended scope still exist.
 | ||||||
|         while !self.scope.locals.is_empty() |         while !self.scope().locals.is_empty() | ||||||
|             && self.scope.locals[self.scope.locals.len() - 1].depth > self.scope.scope_depth |             && self.scope().locals[self.scope().locals.len() - 1].depth > self.scope().scope_depth | ||||||
|         { |         { | ||||||
|             pops += 1; |             pops += 1; | ||||||
| 
 | 
 | ||||||
|  | @ -768,7 +775,7 @@ impl Compiler { | ||||||
|                 node: Some(node), |                 node: Some(node), | ||||||
|                 used, |                 used, | ||||||
|                 .. |                 .. | ||||||
|             }) = self.scope.locals.pop() |             }) = self.scope_mut().locals.pop() | ||||||
|             { |             { | ||||||
|                 if !used { |                 if !used { | ||||||
|                     self.emit_warning(node, WarningKind::UnusedBinding); |                     self.emit_warning(node, WarningKind::UnusedBinding); | ||||||
|  | @ -780,11 +787,12 @@ impl Compiler { | ||||||
|             self.chunk().push_op(OpCode::OpCloseScope(pops)); |             self.chunk().push_op(OpCode::OpCloseScope(pops)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         while !self.scope.with_stack.is_empty() |         while !self.scope().with_stack.is_empty() | ||||||
|             && self.scope.with_stack[self.scope.with_stack.len() - 1].depth > self.scope.scope_depth |             && self.scope().with_stack[self.scope().with_stack.len() - 1].depth | ||||||
|  |                 > self.scope().scope_depth | ||||||
|         { |         { | ||||||
|             self.chunk().push_op(OpCode::OpPopWith); |             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) { |     fn declare_local<S: Into<String>>(&mut self, node: rnix::SyntaxNode, name: S) { | ||||||
|         // Set up scope poisoning if required.
 |         // Set up scope poisoning if required.
 | ||||||
|         let name = name.into(); |         let name = name.into(); | ||||||
|  |         let mut scope = self.scope_mut(); | ||||||
|         match name.as_str() { |         match name.as_str() { | ||||||
|             "true" if self.scope.poisoned_true == 0 => { |             "true" if scope.poisoned_true == 0 => scope.poisoned_true = scope.scope_depth, | ||||||
|                 self.scope.poisoned_true = self.scope.scope_depth |  | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             "false" if self.scope.poisoned_false == 0 => { |             "false" if scope.poisoned_false == 0 => scope.poisoned_false = scope.scope_depth, | ||||||
|                 self.scope.poisoned_false = self.scope.scope_depth |  | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             "null" if self.scope.poisoned_null == 0 => { |             "null" if scope.poisoned_null == 0 => scope.poisoned_null = scope.scope_depth, | ||||||
|                 self.scope.poisoned_null = self.scope.scope_depth |  | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             _ => {} |             _ => {} | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         self.scope.locals.push(Local { |         scope.locals.push(Local { | ||||||
|             name: name.into(), |             name: name.into(), | ||||||
|             node: Some(node), |             node: Some(node), | ||||||
|             depth: self.scope.scope_depth, |             depth: scope.scope_depth, | ||||||
|             phantom: false, |             phantom: false, | ||||||
|             used: false, |             used: false, | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn declare_phantom(&mut self) { |     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(), |             name: "".into(), | ||||||
|             node: None, |             node: None, | ||||||
|             depth: self.scope.scope_depth, |  | ||||||
|             phantom: true, |             phantom: true, | ||||||
|             used: true, |             used: true, | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn resolve_local(&mut self, name: &str) -> Option<usize> { |     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() { |         for (idx, local) in scope.locals.iter_mut().enumerate().rev() { | ||||||
|             if !local.phantom && local.name == name { |             if !local.phantom && local.name == name { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue