🐛 bug: fix some stuff in calling native functions

main
_ 2023-10-01 01:06:15 -05:00
parent 06638574f7
commit a9820677e9
4 changed files with 130 additions and 17 deletions

View File

@ -29,6 +29,7 @@
- [x] Hash tables - [x] Hash tables
- [x] Fizzbuzz - [x] Fizzbuzz
- [ ] Closures - [ ] Closures
- [ ] Error handling
- [ ] Garbage collection - [ ] Garbage collection
- [ ] Long strings - [ ] Long strings
- [ ] Using arrays internally for tables - [ ] Using arrays internally for tables

View File

@ -59,8 +59,22 @@ pub struct State <'a> {
upvalues: &'a [Value], upvalues: &'a [Value],
} }
fn lw_print (l: &mut State) -> i32 { fn lw_io_write (l: &mut State, num_args: usize) -> usize {
for i in 0..u8::try_from (l.get_top ()).unwrap () { 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); let input = l.reg (i);
if i == 0 { if i == 0 {
@ -75,6 +89,49 @@ fn lw_print (l: &mut State) -> i32 {
1 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 { pub enum StepOutput {
ChunkReturned (Vec <Value>), ChunkReturned (Vec <Value>),
} }
@ -89,7 +146,9 @@ pub struct StepError {
impl <'a> State <'a> { impl <'a> State <'a> {
pub fn new (chunk: &'a Chunk, upvalues: &'a [Value]) -> Self { pub fn new (chunk: &'a Chunk, upvalues: &'a [Value]) -> Self {
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, top: 0,
stack: vec! [ stack: vec! [
StackFrame { StackFrame {
@ -115,9 +174,25 @@ impl <'a> State <'a> {
let arg = args.map (|s| Value::from (s)).enumerate (); let arg = args.map (|s| Value::from (s)).enumerate ();
let arg = Value::from_iter (arg.map (|(i, v)| (Value::from (i), v))); 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 = [ let env = [
("arg", arg), ("arg", arg),
("io", Value::from_iter (io.into_iter ())),
("math", Value::from_iter (math.into_iter ())),
("print", Value::RsFunc (lw_print)), ("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)); ].into_iter ().map (|(k, v)| (k.to_string (), v));
vec! [ vec! [
@ -179,7 +254,7 @@ impl <'a> State <'a> {
let k = &block.constants; let k = &block.constants;
let make_step_error = |msg| { let make_step_error = |msg| {
Err (self.make_step_error (msg, instruction)) self.make_step_error (msg, instruction)
}; };
match instruction { match instruction {
@ -213,7 +288,7 @@ impl <'a> State <'a> {
*self.reg_mut (*a) = x; *self.reg_mut (*a) = x;
}, },
Instruction::Call (a, b, _c) => { Instruction::Call (a, b, c) => {
let b = usize::from (*b); let b = usize::from (*b);
// Take arguments from registers [a + 1, a + 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 // 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 // Call
let num_results = x (self); let num_results = x (self, b - 1);
let popped_frame = self.stack.pop ().unwrap (); let popped_frame = self.stack.pop ().unwrap ();
let offset = popped_frame.register_offset - 1; let offset = popped_frame.register_offset - 1;
for i in (offset)..(offset + usize::try_from (num_results).unwrap ()) { 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; Err (make_step_error ("Cannot call value"))?;
panic! ("Cannot call value {a:?}. backtrace: {stack:?}");
}, },
} }
}, },
@ -314,7 +398,9 @@ impl <'a> State <'a> {
} }
else { else {
let v_b = v_b.as_float ().unwrap_or_else (|| panic! ("{v_b}")); 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) Value::from (v_b / v_c)
}; };
@ -362,9 +448,9 @@ impl <'a> State <'a> {
}, },
Instruction::GetField (a, b, c) => { Instruction::GetField (a, b, c) => {
let t = match self.reg (*b) { 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, 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)] { let key = match &k [usize::from (*c)] {
@ -449,11 +535,17 @@ impl <'a> State <'a> {
Instruction::Jmp (s_j) => next_pc += s_j, Instruction::Jmp (s_j) => next_pc += s_j,
Instruction::Len (a, b) => { Instruction::Len (a, b) => {
let len = match self.reg (*b) { let len = match self.reg (*b) {
Value::String (s) => s.len (), Value::BogusClosure (_) => Err (make_step_error ("attempt to get length of a function value"))?,
_ => unimplemented!(), 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) => { Instruction::LoadF (a, sbx) => {
*self.reg_mut (*a) = Value::Float (*sbx as f64); *self.reg_mut (*a) = Value::Float (*sbx as f64);

View File

@ -26,7 +26,7 @@ pub enum Value {
Float (f64), Float (f64),
Integer (i64), Integer (i64),
RsFunc (fn (&mut crate::state::State) -> i32), RsFunc (fn (&mut crate::state::State, usize) -> usize),
String (Rc <String>), String (Rc <String>),
Table (Rc <RefCell <Table>>), 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>>> { pub fn as_table (&self) -> Option <&Rc <RefCell <Table>>> {
match self { match self {
Self::Table (t) => Some (t), Self::Table (t) => Some (t),
@ -265,6 +272,15 @@ impl Table {
) { ) {
self.insert_inner (a.into (), b.into ()) 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 { impl FromIterator <(Value, Value)> for Table {

View File

@ -0,0 +1,4 @@
print ()
print ("asdf")
print (math.sqrt (16))
print (math.sqrt (16.0))