allow Lua to call native Rust functions

And Value::BogusPrint is gone. So the only Bogus remaining is closures.
main
_ 2023-09-27 01:46:53 -05:00
parent 5ab30ac5b4
commit bebc96916b
4 changed files with 77 additions and 52 deletions

View File

@ -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;

View File

@ -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

View File

@ -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"),
}
}
}

View File

@ -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**!")