⭐ allow Lua to call native Rust functions
And Value::BogusPrint is gone. So the only Bogus remaining is closures.main
							parent
							
								
									5ab30ac5b4
								
							
						
					
					
						commit
						bebc96916b
					
				
							
								
								
									
										61
									
								
								src/state.rs
								
								
								
								
							
							
						
						
									
										61
									
								
								src/state.rs
								
								
								
								
							|  | @ -40,6 +40,8 @@ pub struct Breakpoint { | |||
| #[derive (Debug)] | ||||
| pub struct State { | ||||
| 	registers: Vec <Value>, | ||||
| 	// Currently only used for native function calls
 | ||||
| 	top: usize, | ||||
| 	stack: Vec <StackFrame>, | ||||
| 	
 | ||||
| 	pub debug_print: bool, | ||||
|  | @ -51,6 +53,7 @@ impl Default for State { | |||
| 	fn default () -> Self { | ||||
| 		Self { | ||||
| 			registers: vec! [Value::Nil; 16], | ||||
| 			top: 0, | ||||
| 			stack: vec! [ | ||||
| 				StackFrame { | ||||
| 					program_counter: 0, | ||||
|  | @ -65,6 +68,22 @@ impl Default for State { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn lw_print (l: &mut State) -> i32 { | ||||
| 	for i in 0..u8::try_from (l.get_top ()).unwrap () { | ||||
| 		let input = l.reg (i); | ||||
| 		
 | ||||
| 		if i == 0 { | ||||
| 			print! ("{input}"); | ||||
| 		} | ||||
| 		else { | ||||
| 			print! ("\t{input}"); | ||||
| 		} | ||||
| 	} | ||||
| 	println! (""); | ||||
| 	*l.reg_mut (0) = Value::from (1993); | ||||
| 	1 | ||||
| } | ||||
| 
 | ||||
| impl State { | ||||
| 	pub fn upvalues_from_args <I: Iterator <Item = String>> (args: I) -> Vec <Value> | ||||
| 	{ | ||||
|  | @ -73,7 +92,7 @@ impl State { | |||
| 		
 | ||||
| 		let env = [ | ||||
| 			("arg", arg), | ||||
| 			("print", Value::BogusPrint), | ||||
| 			("print", Value::RsFunc (lw_print)), | ||||
| 		].into_iter ().map (|(k, v)| (k.to_string (), v)); | ||||
| 		
 | ||||
| 		vec! [ | ||||
|  | @ -98,6 +117,11 @@ impl State { | |||
| 		&mut self.registers [frame.register_offset + i as usize] | ||||
| 	} | ||||
| 	
 | ||||
| 	// For native functions to check how many args they got
 | ||||
| 	pub fn get_top (&self) -> usize { | ||||
| 		self.top - self.stack.last ().unwrap ().register_offset | ||||
| 	} | ||||
| 	
 | ||||
| 	pub fn execute_chunk (&mut self, chunk: &Chunk, upvalues: &[Value]) 
 | ||||
| 	-> Vec <Value> { | ||||
| 		let max_iters = 2000; | ||||
|  | @ -136,7 +160,9 @@ impl State { | |||
| 					
 | ||||
| 					*self.reg_mut (*a) = Value::from (v_b + v_c); | ||||
| 				}, | ||||
| 				Instruction::Call (a, _b, c) => { | ||||
| 				Instruction::Call (a, b, _c) => { | ||||
| 					let b = usize::from (*b); | ||||
| 					
 | ||||
| 					// Take arguments from registers [a + 1, a + b)
 | ||||
| 					// Call the function in register [a]
 | ||||
| 					// Return values in registers [a, a + c - 1)
 | ||||
|  | @ -145,9 +171,10 @@ impl State { | |||
| 					// 
 | ||||
| 					// e.g. CALL 0 2 1 mean "Call 0 with 1 argument, return 1 value", like for printing a constant
 | ||||
| 					
 | ||||
| 					// TODO: Only implement printing values for now
 | ||||
| 					// Do a clone here to avoid a borow problem.
 | ||||
| 					// Should be fixable with more clever code.
 | ||||
| 					
 | ||||
| 					let v_a = self.reg (*a); | ||||
| 					let v_a = self.reg (*a).clone (); | ||||
| 					
 | ||||
| 					match v_a { | ||||
| 						Value::BogusClosure (rc) => { | ||||
|  | @ -173,17 +200,27 @@ impl State { | |||
| 							// Skip the PC increment at the bottom of the loop
 | ||||
| 							continue; | ||||
| 						}, | ||||
| 						Value::BogusPrint => { | ||||
| 							// In real Lua, print is a function inside
 | ||||
| 							// the runtime. Here it's bogus.
 | ||||
| 						Value::RsFunc (x) => { | ||||
| 							let current_frame = self.stack.last ().unwrap (); | ||||
| 							let new_offset = current_frame.register_offset + usize::from (*a) + 1; | ||||
| 							self.stack.push (StackFrame { | ||||
| 								program_counter: 65535, // Bogus for native functions
 | ||||
| 								block_idx: 65535, // Bogus
 | ||||
| 								register_offset: new_offset, | ||||
| 							}); | ||||
| 							
 | ||||
| 							// assert_eq! (*b, 2);
 | ||||
| 							assert_eq! (*c, 1); | ||||
| 							// No clue what the '1' is doing here
 | ||||
| 							self.top = new_offset + b - 1; | ||||
| 							
 | ||||
| 							let value = self.reg (a + 1); | ||||
| 							println! ("{}", value); | ||||
| 							// Call
 | ||||
| 							let num_results = x (self); | ||||
| 							
 | ||||
| 							*self.reg_mut (*a) = self.reg_mut (*a + 1).take (); | ||||
| 							let popped_frame = self.stack.pop ().unwrap (); | ||||
| 							let offset = popped_frame.register_offset - 1; | ||||
| 							
 | ||||
| 							for i in (offset)..(offset + usize::try_from (num_results).unwrap ()) { | ||||
| 								self.registers [i] = self.registers [i + 1 + usize::from (*a)].take (); | ||||
| 							} | ||||
| 						}, | ||||
| 						_ => { | ||||
| 							let stack = &self.stack; | ||||
|  |  | |||
							
								
								
									
										21
									
								
								src/tests.rs
								
								
								
								
							
							
						
						
									
										21
									
								
								src/tests.rs
								
								
								
								
							|  | @ -301,6 +301,27 @@ fn is_93 () { | |||
| 	assert_eq! (run (&["", "94"], &chunk), vec! [Value::from (1)]); | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn native_functions () { | ||||
| 	fn add (l: &mut State) -> i32 { | ||||
| 		0 | ||||
| 	} | ||||
| 	
 | ||||
| 	fn multiply (l: &mut State) -> i32 { | ||||
| 		0 | ||||
| 	} | ||||
| 	
 | ||||
| 	fn greet (l: &mut State) -> i32 { | ||||
| 		0 | ||||
| 	} | ||||
| 	
 | ||||
| 	let _funcs = [ | ||||
| 		add, | ||||
| 		multiply, | ||||
| 		greet, | ||||
| 	]; | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn tables_1 () { | ||||
| 	// I don't capture stdout yet, but I can at least make sure basic table
 | ||||
|  |  | |||
|  | @ -25,6 +25,7 @@ pub enum Value { | |||
| 	Float (f64), | ||||
| 	
 | ||||
| 	Integer (i64), | ||||
| 	RsFunc (fn (&mut crate::state::State) -> i32), | ||||
| 	String (Rc <String>), | ||||
| 	Table (Rc <RefCell <Table>>), | ||||
| 	
 | ||||
|  | @ -32,7 +33,6 @@ pub enum Value { | |||
| 	// closures yet
 | ||||
| 	
 | ||||
| 	BogusClosure (Rc <BogusClosure>), | ||||
| 	BogusPrint, | ||||
| } | ||||
| 
 | ||||
| impl Default for Value { | ||||
|  | @ -49,11 +49,11 @@ impl fmt::Display for Value { | |||
| 			Value::Boolean (true) => write! (f, "true"), | ||||
| 			Value::Float (x) => write! (f, "{:?}", x), | ||||
| 			Value::Integer (x) => write! (f, "{}", x), | ||||
| 			Value::RsFunc (x) => write! (f, "function: {:?}", x), | ||||
| 			Value::String (s) => write! (f, "{}", s), | ||||
| 			Value::Table (t) => write! (f, "table: {:?}", std::rc::Rc::as_ptr (t)), | ||||
| 			
 | ||||
| 			Value::BogusClosure (_) => write! (f, "BogusClosure"), | ||||
| 			Value::BogusPrint => write! (f, "BogusPrint"), | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -139,12 +139,12 @@ impl std::hash::Hash for Value { | |||
| 			Self::Float (x) => x.to_ne_bytes ().hash (state), | ||||
| 			Self::Integer (x) => x.hash (state), | ||||
| 			
 | ||||
| 			Self::RsFunc (x) => x.hash (state), | ||||
| 			// TODO: Implement string interning so we don't hash the whole string here
 | ||||
| 			Self::String (x) => x.hash (state), | ||||
| 			Self::Table (x) => Rc::as_ptr (&x).hash (state), | ||||
| 			
 | ||||
| 			Self::BogusClosure (_) => panic! ("can't hash Bogus values"), | ||||
| 			Self::BogusPrint => panic! ("can't hash Bogus values"), | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -1,37 +1,4 @@ | |||
| print " 1" | ||||
| 
 | ||||
| print (nil) | ||||
| print (false) | ||||
| print (true) | ||||
| print (1993) | ||||
| print (1993.00) | ||||
| print "Hello." | ||||
| 
 | ||||
| print " 2" | ||||
| 
 | ||||
| local t = {} | ||||
| print (t) | ||||
| print (t [1]) | ||||
| t [1] = "asdf" | ||||
| print (t [1]) | ||||
| t.x = 1993 | ||||
| print (t.x) | ||||
| 
 | ||||
| t.t = { 3.14159 } | ||||
| print (t ["t"][1]) | ||||
| 
 | ||||
| print " 3" | ||||
| 
 | ||||
| local c = {} | ||||
| c [1] = "ddd" | ||||
| 
 | ||||
| local a = { c } | ||||
| local b = { c } | ||||
| 
 | ||||
| print (a [1][2]) | ||||
| print (b [1][2]) | ||||
| 
 | ||||
| c [2] = "eee" | ||||
| 
 | ||||
| print (a [1][2]) | ||||
| print (b [1][2]) | ||||
| print ("Hi!", 2) | ||||
| print () | ||||
| print ("Hi!") | ||||
| print ("You've _gotta_ admit this is **cool**!") | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 _
						_