🐛 bug: fix some stuff in calling native functions
							parent
							
								
									06638574f7
								
							
						
					
					
						commit
						a9820677e9
					
				|  | @ -29,6 +29,7 @@ | |||
| - [x] Hash tables | ||||
| - [x] Fizzbuzz | ||||
| - [ ] Closures | ||||
| - [ ] Error handling | ||||
| - [ ] Garbage collection | ||||
| - [ ] Long strings | ||||
| - [ ] Using arrays internally for tables | ||||
|  |  | |||
							
								
								
									
										124
									
								
								src/state.rs
								
								
								
								
							
							
						
						
									
										124
									
								
								src/state.rs
								
								
								
								
							|  | @ -59,8 +59,22 @@ pub struct State <'a> { | |||
| 	upvalues: &'a [Value], | ||||
| } | ||||
| 
 | ||||
| fn lw_print (l: &mut State) -> i32 { | ||||
| 	for i in 0..u8::try_from (l.get_top ()).unwrap () { | ||||
| fn lw_io_write (l: &mut State, num_args: usize) -> usize { | ||||
| 	for i in 0..u8::try_from (num_args).unwrap () { | ||||
| 		match l.reg (i) { | ||||
| 			Value::Float (x) => print! ("{}", x), | ||||
| 			Value::Integer (x) => print! ("{}", x), | ||||
| 			Value::String (x) => print! ("{}", x), | ||||
| 			_ => panic! ("Can't io.write this value"), | ||||
| 		} | ||||
| 	} | ||||
| 	println! (""); | ||||
| 	// TODO: PUC Lua actually returns the file handle here.
 | ||||
| 	0 | ||||
| } | ||||
| 
 | ||||
| fn lw_print (l: &mut State, num_args: usize) -> usize { | ||||
| 	for i in 0..u8::try_from (num_args).unwrap () { | ||||
| 		let input = l.reg (i); | ||||
| 		
 | ||||
| 		if i == 0 { | ||||
|  | @ -75,6 +89,49 @@ fn lw_print (l: &mut State) -> i32 { | |||
| 	1 | ||||
| } | ||||
| 
 | ||||
| fn lw_sqrt (l: &mut State, num_args: usize) -> usize { | ||||
| 	assert! (num_args >= 1, "math.sqrt needs 1 argument"); | ||||
| 	let input = l.reg (0).as_float ().unwrap (); | ||||
| 	let output = input.sqrt (); | ||||
| 	*l.reg_mut (0) = Value::from (output); | ||||
| 	1 | ||||
| } | ||||
| 
 | ||||
| fn lw_string_format (l: &mut State, num_args: usize) -> usize { | ||||
| 	assert! (num_args >= 1, "string.format needs at least 1 argument"); | ||||
| 	assert_eq! (l.get_top (), 2, "string.format not fully implemented"); | ||||
| 	let f_string = l.reg (0).as_str ().unwrap (); | ||||
| 	assert_eq! (f_string, "%0.9f"); | ||||
| 	let num = l.reg (1).as_float ().unwrap (); | ||||
| 	
 | ||||
| 	let output = format! ("{}", num); | ||||
| 	
 | ||||
| 	*l.reg_mut (0) = Value::from (output); | ||||
| 	1 | ||||
| } | ||||
| 
 | ||||
| fn lw_tonumber (l: &mut State, num_args: usize) -> usize { | ||||
| 	assert_eq! (num_args, 1, "tonumber only implemented for 1 argument"); | ||||
| 	let output = match l.reg (0) { | ||||
| 		Value::Float (x) => Value::Float (*x), | ||||
| 		Value::Integer (x) => Value::Integer (*x), | ||||
| 		Value::String (x) => { | ||||
| 			if let Ok (x) = str::parse::<i64> (x) { | ||||
| 				Value::from (x) | ||||
| 			} | ||||
| 			else if let Ok (x) = str::parse::<f64> (x) { | ||||
| 				Value::from (x) | ||||
| 			} | ||||
| 			else { | ||||
| 				Value::Nil | ||||
| 			} | ||||
| 		}, | ||||
| 		_ => Value::Nil, | ||||
| 	}; | ||||
| 	*l.reg_mut (0) = output; | ||||
| 	1 | ||||
| } | ||||
| 
 | ||||
| pub enum StepOutput { | ||||
| 	ChunkReturned (Vec <Value>), | ||||
| } | ||||
|  | @ -89,7 +146,9 @@ pub struct StepError { | |||
| impl <'a> State <'a> { | ||||
| 	pub fn new (chunk: &'a Chunk, upvalues: &'a [Value]) -> Self { | ||||
| 		Self { | ||||
| 			registers: vec! [Value::Nil; 16], | ||||
| 			// TODO: Stack is actually supposed to grow to a limit of
 | ||||
| 			// idk 10,000. I thought it was fixed at 256.
 | ||||
| 			registers: vec! [Value::Nil; 256], | ||||
| 			top: 0, | ||||
| 			stack: vec! [ | ||||
| 				StackFrame { | ||||
|  | @ -115,9 +174,25 @@ impl <'a> State <'a> { | |||
| 		let arg = args.map (|s| Value::from (s)).enumerate (); | ||||
| 		let arg = Value::from_iter (arg.map (|(i, v)| (Value::from (i), v))); | ||||
| 		
 | ||||
| 		let io = [ | ||||
| 			("write", Value::RsFunc (lw_io_write)), | ||||
| 		].into_iter ().map (|(k, v)| (k.to_string (), v)); | ||||
| 		
 | ||||
| 		let math = [ | ||||
| 			("sqrt", Value::RsFunc (lw_sqrt)), | ||||
| 		].into_iter ().map (|(k, v)| (k.to_string (), v)); | ||||
| 		
 | ||||
| 		let string = [ | ||||
| 			("format", Value::RsFunc (lw_string_format)), | ||||
| 		].into_iter ().map (|(k, v)| (k.to_string (), v)); | ||||
| 		
 | ||||
| 		let env = [ | ||||
| 			("arg", arg), | ||||
| 			("io", Value::from_iter (io.into_iter ())), | ||||
| 			("math", Value::from_iter (math.into_iter ())), | ||||
| 			("print", Value::RsFunc (lw_print)), | ||||
| 			("string", Value::from_iter (string.into_iter ())), | ||||
| 			("tonumber", Value::RsFunc (lw_tonumber)), | ||||
| 		].into_iter ().map (|(k, v)| (k.to_string (), v)); | ||||
| 		
 | ||||
| 		vec! [ | ||||
|  | @ -179,7 +254,7 @@ impl <'a> State <'a> { | |||
| 		let k = &block.constants; | ||||
| 		
 | ||||
| 		let make_step_error = |msg| { | ||||
| 			Err (self.make_step_error (msg, instruction)) | ||||
| 			self.make_step_error (msg, instruction) | ||||
| 		}; | ||||
| 		
 | ||||
| 		match instruction { | ||||
|  | @ -213,7 +288,7 @@ impl <'a> State <'a> { | |||
| 				
 | ||||
| 				*self.reg_mut (*a) = x; | ||||
| 			}, | ||||
| 			Instruction::Call (a, b, _c) => { | ||||
| 			Instruction::Call (a, b, c) => { | ||||
| 				let b = usize::from (*b); | ||||
| 				
 | ||||
| 				// Take arguments from registers [a + 1, a + b)
 | ||||
|  | @ -263,21 +338,30 @@ impl <'a> State <'a> { | |||
| 						}); | ||||
| 						
 | ||||
| 						// No clue what the '1' is doing here
 | ||||
| 						self.top = new_offset + b - 1; | ||||
| 						let b = if b == 0 { | ||||
| 							self.top - *a as usize | ||||
| 						} | ||||
| 						else { | ||||
| 							b | ||||
| 						}; | ||||
| 						
 | ||||
| 						// Call
 | ||||
| 						let num_results = x (self); | ||||
| 						let num_results = x (self, b - 1); | ||||
| 						
 | ||||
| 						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 (); | ||||
| 							self.registers [i] = self.registers [i + 1].take (); | ||||
| 						} | ||||
| 						
 | ||||
| 						// Set up top for the next call
 | ||||
| 						if *c == 0 { | ||||
| 							self.top = popped_frame.register_offset - 1 + num_results; | ||||
| 						} | ||||
| 					}, | ||||
| 					_ => { | ||||
| 						let stack = &self.stack; | ||||
| 						panic! ("Cannot call value {a:?}. backtrace: {stack:?}"); | ||||
| 						Err (make_step_error ("Cannot call value"))?; | ||||
| 					}, | ||||
| 				} | ||||
| 			}, | ||||
|  | @ -314,7 +398,9 @@ impl <'a> State <'a> { | |||
| 				} | ||||
| 				else { | ||||
| 					let v_b = v_b.as_float ().unwrap_or_else (|| panic! ("{v_b}")); | ||||
| 					let v_c = v_c.as_float ().unwrap_or_else (|| panic! ("{v_c}")); | ||||
| 					
 | ||||
| 					let v_c = v_c.as_float ().ok_or_else (|| make_step_error ("C must be a number"))?; | ||||
| 					
 | ||||
| 					Value::from (v_b / v_c) | ||||
| 				}; | ||||
| 				
 | ||||
|  | @ -362,9 +448,9 @@ impl <'a> State <'a> { | |||
| 			}, | ||||
| 			Instruction::GetField (a, b, c) => { | ||||
| 				let t = match self.reg (*b) { | ||||
| 					Value::Nil => make_step_error ("R[B] must not be nil")?, | ||||
| 					Value::Nil => Err (make_step_error ("R[B] must not be nil"))?, | ||||
| 					Value::Table (t) => t, | ||||
| 					_ => make_step_error ("R[B] must be a table")?, | ||||
| 					_ => Err (make_step_error ("R[B] must be a table"))?, | ||||
| 				}; | ||||
| 				
 | ||||
| 				let key = match &k [usize::from (*c)] { | ||||
|  | @ -449,11 +535,17 @@ impl <'a> State <'a> { | |||
| 			Instruction::Jmp (s_j) => next_pc += s_j, | ||||
| 			Instruction::Len (a, b) => { | ||||
| 				let len = match self.reg (*b) { | ||||
| 					Value::String (s) => s.len (), | ||||
| 					_ => unimplemented!(), | ||||
| 					Value::BogusClosure (_) => Err (make_step_error ("attempt to get length of a function value"))?, | ||||
| 					Value::Boolean (_) => Err (make_step_error ("attempt to get length of a boolean value"))?, | ||||
| 					Value::Float (_) => Err (make_step_error ("attempt to get length of a number value"))?, | ||||
| 					Value::Integer (_) => Err (make_step_error ("attempt to get length of a number value"))?, | ||||
| 					Value::Nil => Err (make_step_error ("attempt to get length of a nil value"))?, | ||||
| 					Value::RsFunc (_) => Err (make_step_error ("attempt to get length of a function value"))?, | ||||
| 					Value::String (s) => s.len ().into (), | ||||
| 					Value::Table (t) => t.borrow ().length ().into (), | ||||
| 				}; | ||||
| 				
 | ||||
| 				*self.reg_mut (*a) = len.into (); | ||||
| 				*self.reg_mut (*a) = len; | ||||
| 			} | ||||
| 			Instruction::LoadF (a, sbx) => { | ||||
| 				*self.reg_mut (*a) = Value::Float (*sbx as f64); | ||||
|  |  | |||
							
								
								
									
										18
									
								
								src/value.rs
								
								
								
								
							
							
						
						
									
										18
									
								
								src/value.rs
								
								
								
								
							|  | @ -26,7 +26,7 @@ pub enum Value { | |||
| 	Float (f64), | ||||
| 	
 | ||||
| 	Integer (i64), | ||||
| 	RsFunc (fn (&mut crate::state::State) -> i32), | ||||
| 	RsFunc (fn (&mut crate::state::State, usize) -> usize), | ||||
| 	String (Rc <String>), | ||||
| 	Table (Rc <RefCell <Table>>), | ||||
| 	
 | ||||
|  | @ -207,6 +207,13 @@ impl Value { | |||
| 		} | ||||
| 	} | ||||
| 	
 | ||||
| 	pub fn as_str (&self) -> Option <&str> { | ||||
| 		match self { | ||||
| 			Self::String (x) => Some (x.as_str ()), | ||||
| 			_ => None, | ||||
| 		} | ||||
| 	} | ||||
| 	
 | ||||
| 	pub fn as_table (&self) -> Option <&Rc <RefCell <Table>>> { | ||||
| 		match self { | ||||
| 			Self::Table (t) => Some (t), | ||||
|  | @ -265,6 +272,15 @@ impl Table { | |||
| 	) { | ||||
| 		self.insert_inner (a.into (), b.into ()) | ||||
| 	} | ||||
| 	
 | ||||
| 	pub fn length (&self) -> i64 { | ||||
| 		for i in 1..i64::MAX { | ||||
| 			if self.get (i) == Value::Nil { | ||||
| 				return i - 1; | ||||
| 			} | ||||
| 		} | ||||
| 		0 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl FromIterator <(Value, Value)> for Table { | ||||
|  |  | |||
|  | @ -0,0 +1,4 @@ | |||
| print () | ||||
| print ("asdf") | ||||
| print (math.sqrt (16)) | ||||
| print (math.sqrt (16.0)) | ||||
		Loading…
	
		Reference in New Issue
	
	 _
						_