⭐ allow Lua to call native Rust functions
And Value::BogusPrint is gone. So the only Bogus remaining is closures.main
parent
5ab30ac5b4
commit
bebc96916b
61
src/state.rs
61
src/state.rs
|
@ -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;
|
||||
|
|
21
src/tests.rs
21
src/tests.rs
|
@ -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
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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**!")
|
||||
|
|
Loading…
Reference in New Issue