🐛 bug: fix a bug in OP_CALL when b or c is 0

main
_ 2023-10-02 00:59:30 -05:00
parent 8baea40e82
commit b88735a61b
3 changed files with 69 additions and 7 deletions

View File

@ -160,6 +160,7 @@ pub fn parse_inst (buf: [u8; 4]) -> Option <Inst>
0x4a => Inst::ForPrep (a, bx),
0x4e => Inst::SetList (a, b, c, k),
0x4f => Inst::Closure (a, bx),
0x50 => unimplemented! ("OP_VARARG"),
0x51 => Inst::VarArgPrep (a.into ()),
0x52 => Inst::ExtraArg (ax),
_ => return None,

View File

@ -82,7 +82,6 @@ fn lw_print (l: &mut State, num_args: usize) -> usize {
}
}
println! ("");
*l.reg_mut (0) = Value::from (1993);
1
}
@ -107,9 +106,39 @@ fn lw_string_format (l: &mut State, num_args: usize) -> usize {
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) {
fn lw_table_concat (l: &mut State, num_args: usize) -> usize {
assert_eq! (num_args, 2);
let s = {
let t = l.reg (0).as_table ().unwrap ().borrow ();
let joiner = l.reg (1).as_str ().unwrap ();
let mut s = String::new ();
for i in 0..t.length () {
if i > 0 {
s.push_str (joiner);
}
let x = t.get_int (i + 1);
s.push_str (&format! ("{}", x));
}
s
};
*l.reg_mut (0) = Value::from (s);
1
}
fn lw_table_pack (l: &mut State, num_args: usize) -> usize {
let mut v = vec! [];
for i in 0..num_args {
v.push (l.reg (u8::try_from (i).unwrap ()).clone ());
}
*l.reg_mut (0) = Value::from_iter (v.into_iter ());
1
}
fn tonumber (value: &Value) -> Value {
match value {
Value::Float (x) => Value::Float (*x),
Value::Integer (x) => Value::Integer (*x),
Value::String (x) => {
@ -124,7 +153,12 @@ fn lw_tonumber (l: &mut State, num_args: usize) -> usize {
}
},
_ => Value::Nil,
};
}
}
fn lw_tonumber (l: &mut State, num_args: usize) -> usize {
assert_eq! (num_args, 1, "tonumber only implemented for 1 argument");
let output = tonumber (l.reg (0));
*l.reg_mut (0) = output;
1
}
@ -182,12 +216,18 @@ impl State {
("format", Value::RsFunc (lw_string_format)),
].into_iter ().map (|(k, v)| (k.to_string (), v));
let table = [
("concat", Value::RsFunc (lw_table_concat)),
("pack", Value::RsFunc (lw_table_pack)),
].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 ())),
("table", Value::from_iter (table.into_iter ())),
("tonumber", Value::RsFunc (lw_tonumber)),
].into_iter ().map (|(k, v)| (k.to_string (), v));
@ -336,7 +376,7 @@ impl State {
});
let num_args = if b == 0 {
self.top - a as usize
self.top - new_offset
}
else {
b - 1
@ -385,7 +425,7 @@ impl State {
upvalues: new_upvalues,
});
},
Instruction::Concat (a, b) => {
Instruction::Concat (_a, _b) => {
unimplemented! ("OP_CONCAT")
},
Instruction::Div (a, b, c) => {

View File

@ -208,9 +208,30 @@ fn function_calls () {
vm.eval ("print (x ())").ok ();
vm.eval ("x = function () return 5 end").ok ();
// Currently failing because I don't have a way to jump into a Lua
// function that's no longer in the currently-executing chunk
vm.eval ("print (x ())").ok ();
}
#[test]
fn function_returns () {
let upvalues = crate::State::upvalues_from_args (vec! ["_exe_name".to_string ()].into_iter ());
let mut vm = crate::State::new (crate::Chunk::default (), upvalues);
assert_eq! (
vm.eval ("return ((function () return 5 end)())").unwrap (),
vec! [Value::from (5)]
);
assert_eq! (
vm.eval ("return (math.sqrt (25))").unwrap (),
vec! [Value::from (5.0)]
);
}
#[test]
fn heap () {
use std::{