From a9820677e9f22e536e2ea18b4bb4d08d6b1807e5 Mon Sep 17 00:00:00 2001 From: _ <_@_> Date: Sun, 1 Oct 2023 01:06:15 -0500 Subject: [PATCH] :bug: bug: fix some stuff in calling native functions --- README.md | 1 + src/state.rs | 124 ++++++++++++++++++++++++++---- src/value.rs | 18 ++++- test_vectors/n_body_new_stuff.lua | 4 + 4 files changed, 130 insertions(+), 17 deletions(-) create mode 100644 test_vectors/n_body_new_stuff.lua diff --git a/README.md b/README.md index b40a7ca..117a989 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ - [x] Hash tables - [x] Fizzbuzz - [ ] Closures +- [ ] Error handling - [ ] Garbage collection - [ ] Long strings - [ ] Using arrays internally for tables diff --git a/src/state.rs b/src/state.rs index ec4efbe..346eb0d 100644 --- a/src/state.rs +++ b/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:: (x) { + Value::from (x) + } + else if let Ok (x) = str::parse:: (x) { + Value::from (x) + } + else { + Value::Nil + } + }, + _ => Value::Nil, + }; + *l.reg_mut (0) = output; + 1 +} + pub enum StepOutput { ChunkReturned (Vec ), } @@ -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); diff --git a/src/value.rs b/src/value.rs index 7e8fdae..9f87ceb 100644 --- a/src/value.rs +++ b/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 ), Table (Rc >), @@ -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 >> { 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 { diff --git a/test_vectors/n_body_new_stuff.lua b/test_vectors/n_body_new_stuff.lua new file mode 100644 index 0000000..d8556f3 --- /dev/null +++ b/test_vectors/n_body_new_stuff.lua @@ -0,0 +1,4 @@ +print () +print ("asdf") +print (math.sqrt (16)) +print (math.sqrt (16.0))