Compare commits
No commits in common. "130330b688acb309216759962de51c4df22fccca" and "bba98043c75be16d1d1e4c05ded79e07c90f7779" have entirely different histories.
130330b688
...
bba98043c7
|
@ -22,8 +22,6 @@ fn lunar_wave (args: Vec <String>) -> Result <Vec <lwvm::Value>, lwvm::StepError
|
||||||
let mut arg_iter = args.iter ();
|
let mut arg_iter = args.iter ();
|
||||||
let _exe_name = arg_iter.next ().unwrap ();
|
let _exe_name = arg_iter.next ().unwrap ();
|
||||||
|
|
||||||
let mut si = lwvm::Interner::default ();
|
|
||||||
|
|
||||||
while let Some (arg) = arg_iter.next () {
|
while let Some (arg) = arg_iter.next () {
|
||||||
match arg.as_str () {
|
match arg.as_str () {
|
||||||
"--break" => {
|
"--break" => {
|
||||||
|
@ -42,7 +40,7 @@ fn lunar_wave (args: Vec <String>) -> Result <Vec <lwvm::Value>, lwvm::StepError
|
||||||
let mut buf = vec! [];
|
let mut buf = vec! [];
|
||||||
std::io::stdin ().read_to_end (&mut buf).unwrap ();
|
std::io::stdin ().read_to_end (&mut buf).unwrap ();
|
||||||
let bc = lwvm::ensure_bytecode (buf).unwrap ();
|
let bc = lwvm::ensure_bytecode (buf).unwrap ();
|
||||||
chunk = Some (lwvm::parse_chunk (&bc, &mut si).unwrap ());
|
chunk = Some (lwvm::parse_chunk (&bc).unwrap ());
|
||||||
|
|
||||||
lua_args = vec! ["-".to_string ()];
|
lua_args = vec! ["-".to_string ()];
|
||||||
},
|
},
|
||||||
|
@ -53,7 +51,7 @@ fn lunar_wave (args: Vec <String>) -> Result <Vec <lwvm::Value>, lwvm::StepError
|
||||||
}
|
}
|
||||||
else if chunk.is_none () {
|
else if chunk.is_none () {
|
||||||
let bc = lwvm::compile_bytecode_from_file (x);
|
let bc = lwvm::compile_bytecode_from_file (x);
|
||||||
chunk = Some (lwvm::parse_chunk (&bc, &mut si).unwrap ());
|
chunk = Some (lwvm::parse_chunk (&bc).unwrap ());
|
||||||
|
|
||||||
lua_args = vec! [x.to_string ()];
|
lua_args = vec! [x.to_string ()];
|
||||||
}
|
}
|
||||||
|
@ -70,12 +68,10 @@ fn lunar_wave (args: Vec <String>) -> Result <Vec <lwvm::Value>, lwvm::StepError
|
||||||
chunk,
|
chunk,
|
||||||
list_bytecode,
|
list_bytecode,
|
||||||
lua_args,
|
lua_args,
|
||||||
si,
|
|
||||||
}),
|
}),
|
||||||
None => repl (ReplParams {
|
None => repl (ReplParams {
|
||||||
list_bytecode,
|
list_bytecode,
|
||||||
lua_args,
|
lua_args,
|
||||||
si,
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,13 +81,11 @@ struct DebuggerParams {
|
||||||
chunk: lwvm::Chunk,
|
chunk: lwvm::Chunk,
|
||||||
list_bytecode: bool,
|
list_bytecode: bool,
|
||||||
lua_args: Vec <String>,
|
lua_args: Vec <String>,
|
||||||
si: lwvm::Interner,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ReplParams {
|
struct ReplParams {
|
||||||
list_bytecode: bool,
|
list_bytecode: bool,
|
||||||
lua_args: Vec <String>,
|
lua_args: Vec <String>,
|
||||||
si: lwvm::Interner,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The interpreter mode, which has optional debugging abilities
|
/// The interpreter mode, which has optional debugging abilities
|
||||||
|
@ -103,7 +97,9 @@ fn debugger (params: DebuggerParams) -> Result <Vec <lwvm::Value>, lwvm::StepErr
|
||||||
dbg! (¶ms.chunk);
|
dbg! (¶ms.chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut vm = lwvm::State::new_with_args (params.chunk, params.si, params.lua_args.into_iter ());
|
let upvalues = lwvm::State::upvalues_from_args (params.lua_args.into_iter ());
|
||||||
|
|
||||||
|
let mut vm = lwvm::State::new (params.chunk, upvalues);
|
||||||
if std::env::var("LWVM_DEBUG").is_ok() {
|
if std::env::var("LWVM_DEBUG").is_ok() {
|
||||||
vm.debug_print = true;
|
vm.debug_print = true;
|
||||||
}
|
}
|
||||||
|
@ -164,7 +160,9 @@ fn debugger (params: DebuggerParams) -> Result <Vec <lwvm::Value>, lwvm::StepErr
|
||||||
|
|
||||||
fn repl (params: ReplParams) -> Result <Vec <lwvm::Value>, lwvm::StepError>
|
fn repl (params: ReplParams) -> Result <Vec <lwvm::Value>, lwvm::StepError>
|
||||||
{
|
{
|
||||||
let mut vm = lwvm::State::new_with_args (lwvm::Chunk::default (), params.si, params.lua_args.into_iter ());
|
let upvalues = lwvm::State::upvalues_from_args (params.lua_args.into_iter ());
|
||||||
|
|
||||||
|
let mut vm = lwvm::State::new (lwvm::Chunk::default (), upvalues);
|
||||||
|
|
||||||
println! ("Lunar Wave 0.1.0-modified Copyright (C) 2023 ReactorScram (implements Lua 5.4 Copyright (C) 1994-2022 Lua.org, PUC-Rio");
|
println! ("Lunar Wave 0.1.0-modified Copyright (C) 2023 ReactorScram (implements Lua 5.4 Copyright (C) 1994-2022 Lua.org, PUC-Rio");
|
||||||
|
|
||||||
|
@ -190,7 +188,7 @@ fn repl (params: ReplParams) -> Result <Vec <lwvm::Value>, lwvm::StepError>
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let chunk = lwvm::parse_chunk (&bytecode, &mut vm.si).unwrap ();
|
let chunk = lwvm::parse_chunk (&bytecode).unwrap ();
|
||||||
|
|
||||||
if params.list_bytecode {
|
if params.list_bytecode {
|
||||||
dbg! (&chunk);
|
dbg! (&chunk);
|
||||||
|
|
|
@ -1,636 +0,0 @@
|
||||||
use std::{
|
|
||||||
collections::{BTreeMap, HashMap},
|
|
||||||
time::Instant,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn main () {
|
|
||||||
// PUC Lua is 250 ms
|
|
||||||
// I'm using AOT Rust here so anything more than that
|
|
||||||
// is simply embarrassing
|
|
||||||
|
|
||||||
fn timer <F: Fn ()> (f: F, label: &str) {
|
|
||||||
let start = Instant::now ();
|
|
||||||
f ();
|
|
||||||
let stop = Instant::now ();
|
|
||||||
println! ("{}: {} ms", label, (stop - start).as_millis ());
|
|
||||||
}
|
|
||||||
|
|
||||||
// timer (|| n_body::<BTreeTable> (100000), "BTreeTable");
|
|
||||||
// timer (|| n_body::<BTreeTable2> (100000), "BTreeTable2");
|
|
||||||
// timer (|| n_body::<HashTable> (100000), "HashTable");
|
|
||||||
// timer (|| n_body_2::<HashTable2> (100000), "HashTable2");
|
|
||||||
|
|
||||||
// Fastest on my system, at 83 ms
|
|
||||||
timer (|| n_body_2::<BTreeTable3> (100000), "BTreeTable3");
|
|
||||||
timer (|| n_body_2::<BTreeTable3> (500000), "BTreeTable3");
|
|
||||||
timer (|| n_body_3::<BTreeTable4> (500000), "BTreeTable4");
|
|
||||||
}
|
|
||||||
|
|
||||||
trait Table {
|
|
||||||
fn get (&self, key: &str) -> f64;
|
|
||||||
fn set (&mut self, key: &'static str, value: f64);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive (Default)]
|
|
||||||
struct BTreeTable (BTreeMap <String, f64>);
|
|
||||||
|
|
||||||
impl Table for BTreeTable {
|
|
||||||
fn get (&self, key: &str) -> f64 {
|
|
||||||
*self.0.get (key).unwrap ()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set (&mut self, key: &str, value: f64) {
|
|
||||||
self.0.insert (key.to_string (), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive (Default)]
|
|
||||||
struct BTreeTable2 (BTreeMap <&'static str, f64>);
|
|
||||||
|
|
||||||
impl Table for BTreeTable2 {
|
|
||||||
fn get (&self, key: &str) -> f64 {
|
|
||||||
*self.0.get (key).unwrap ()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set (&mut self, key: &'static str, value: f64) {
|
|
||||||
self.0.insert (key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive (Default)]
|
|
||||||
struct HashTable (HashMap <String, f64>);
|
|
||||||
|
|
||||||
impl Table for HashTable {
|
|
||||||
fn get (&self, key: &str) -> f64 {
|
|
||||||
*self.0.get (key).unwrap ()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set (&mut self, key: &str, value: f64) {
|
|
||||||
self.0.insert (key.to_string (), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const PI: f64 = 3.141592653589793f64;
|
|
||||||
const SOLAR_MASS: f64 = 4.0 * PI * PI;
|
|
||||||
|
|
||||||
fn n_body <T: Default + Table> (num_iters: usize) {
|
|
||||||
const X: &str = "x";
|
|
||||||
const Y: &str = "y";
|
|
||||||
const Z: &str = "z";
|
|
||||||
const VX: &str = "vx";
|
|
||||||
const VY: &str = "vy";
|
|
||||||
const VZ: &str = "vz";
|
|
||||||
const MASS: &str = "mass";
|
|
||||||
|
|
||||||
let days_per_year = 365.24;
|
|
||||||
|
|
||||||
let mut bodies = vec! [];
|
|
||||||
{
|
|
||||||
let mut t = T::default ();
|
|
||||||
t.set (X, 0.0);
|
|
||||||
t.set (Y, 0.0);
|
|
||||||
t.set (Z, 0.0);
|
|
||||||
t.set (VX, 0.0);
|
|
||||||
t.set (VY, 0.0);
|
|
||||||
t.set (VZ, 0.0);
|
|
||||||
t.set (MASS, SOLAR_MASS);
|
|
||||||
|
|
||||||
bodies.push (t);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let mut t = T::default ();
|
|
||||||
t.set (X, 4.84143144246472090e+00);
|
|
||||||
t.set (Y, -1.16032004402742839e+00);
|
|
||||||
t.set (Z, -1.03622044471123109e-01);
|
|
||||||
t.set (VX, 1.66007664274403694e-03 * days_per_year);
|
|
||||||
t.set (VY, 7.69901118419740425e-03 * days_per_year);
|
|
||||||
t.set (VZ, -6.90460016972063023e-05 * days_per_year);
|
|
||||||
t.set (MASS, 9.54791938424326609e-04 * SOLAR_MASS);
|
|
||||||
|
|
||||||
bodies.push (t);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let mut t = T::default ();
|
|
||||||
t.set (X, 8.34336671824457987e+00);
|
|
||||||
t.set (Y, 4.12479856412430479e+00);
|
|
||||||
t.set (Z, -4.03523417114321381e-01);
|
|
||||||
t.set (VX, -2.76742510726862411e-03 * days_per_year);
|
|
||||||
t.set (VY, 4.99852801234917238e-03 * days_per_year);
|
|
||||||
t.set (VZ, 2.30417297573763929e-05 * days_per_year);
|
|
||||||
t.set (MASS, 2.85885980666130812e-04 * SOLAR_MASS);
|
|
||||||
|
|
||||||
bodies.push (t);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let mut t = T::default ();
|
|
||||||
t.set (X, 1.28943695621391310e+01);
|
|
||||||
t.set (Y, -1.51111514016986312e+01);
|
|
||||||
t.set (Z, -2.23307578892655734e-01);
|
|
||||||
t.set (VX, 2.96460137564761618e-03 * days_per_year);
|
|
||||||
t.set (VY, 2.37847173959480950e-03 * days_per_year);
|
|
||||||
t.set (VZ, -2.96589568540237556e-05 * days_per_year);
|
|
||||||
t.set (MASS, 4.36624404335156298e-05 * SOLAR_MASS);
|
|
||||||
|
|
||||||
bodies.push (t);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let mut t = T::default ();
|
|
||||||
t.set (X, 1.53796971148509165e+01);
|
|
||||||
t.set (Y, -2.59193146099879641e+01);
|
|
||||||
t.set (Z, 1.79258772950371181e-01);
|
|
||||||
t.set (VX, 2.68067772490389322e-03 * days_per_year);
|
|
||||||
t.set (VY, 1.62824170038242295e-03 * days_per_year);
|
|
||||||
t.set (VZ, -9.51592254519715870e-05 * days_per_year);
|
|
||||||
t.set (MASS, 5.15138902046611451e-05 * SOLAR_MASS);
|
|
||||||
|
|
||||||
bodies.push (t);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance <T: Table> (bodies: &mut [T], dt: f64) {
|
|
||||||
let nbody = bodies.len ();
|
|
||||||
|
|
||||||
for i in 0..nbody {
|
|
||||||
let bix;
|
|
||||||
let biy;
|
|
||||||
let biz;
|
|
||||||
let bimass;
|
|
||||||
let mut bivx;
|
|
||||||
let mut bivy;
|
|
||||||
let mut bivz;
|
|
||||||
{
|
|
||||||
let bi = &mut bodies [i];
|
|
||||||
bix = bi.get (X);
|
|
||||||
biy = bi.get (Y);
|
|
||||||
biz = bi.get (Z);
|
|
||||||
bimass = bi.get (MASS);
|
|
||||||
bivx = bi.get (VX);
|
|
||||||
bivy = bi.get (VY);
|
|
||||||
bivz = bi.get (VZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
for j in i + 1..nbody {
|
|
||||||
let bj = &mut bodies [j];
|
|
||||||
let dx = bix - bj.get (X);
|
|
||||||
let dy = biy - bj.get (Y);
|
|
||||||
let dz = biz - bj.get (Z);
|
|
||||||
let mut mag = (dx * dx + dy * dy + dz * dz).sqrt ();
|
|
||||||
mag = dt / (mag * mag * mag);
|
|
||||||
let mut bm = bj.get (MASS) * mag;
|
|
||||||
bivx -= dx * bm;
|
|
||||||
bivy -= dy * bm;
|
|
||||||
bivz -= dz * bm;
|
|
||||||
bm = bimass * mag;
|
|
||||||
bj.set (VX, bj.get (VX) + dx * bm);
|
|
||||||
bj.set (VY, bj.get (VY) + dy * bm);
|
|
||||||
bj.set (VZ, bj.get (VZ) + dz * bm);
|
|
||||||
}
|
|
||||||
|
|
||||||
let bi = &mut bodies [i];
|
|
||||||
bi.set (VX, bivx);
|
|
||||||
bi.set (VY, bivy);
|
|
||||||
bi.set (VZ, bivz);
|
|
||||||
bi.set (X, bix + dt * bivx);
|
|
||||||
bi.set (Y, biy + dt * bivy);
|
|
||||||
bi.set (Z, biz + dt * bivz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn energy <T: Table> (bodies: &[T]) -> f64 {
|
|
||||||
let mut e = 0.0;
|
|
||||||
for (i, bi) in bodies.iter ().enumerate () {
|
|
||||||
let vx = bi.get (VX);
|
|
||||||
let vy = bi.get (VY);
|
|
||||||
let vz = bi.get (VZ);
|
|
||||||
let bim = bi.get (MASS);
|
|
||||||
|
|
||||||
e += 0.5 * bim * (vx * vx + vy * vy + vz * vz);
|
|
||||||
|
|
||||||
for j in i + 1..bodies.len () {
|
|
||||||
let bj = &bodies [j];
|
|
||||||
let dx = bi.get (X) - bj.get (X);
|
|
||||||
let dy = bi.get (Y) - bj.get (Y);
|
|
||||||
let dz = bi.get (Z) - bj.get (Z);
|
|
||||||
let distance = (dx * dx + dy * dy + dz * dz).sqrt ();
|
|
||||||
e -= (bim * bj.get (MASS)) / distance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e
|
|
||||||
}
|
|
||||||
|
|
||||||
fn offset_momentum <T: Table> (b: &mut [T]) {
|
|
||||||
let mut px = 0.0;
|
|
||||||
let mut py = 0.0;
|
|
||||||
let mut pz = 0.0;
|
|
||||||
|
|
||||||
for bi in b.iter () {
|
|
||||||
let bim = bi.get (MASS);
|
|
||||||
px += bi.get (VX) * bim;
|
|
||||||
py += bi.get (VY) * bim;
|
|
||||||
pz += bi.get (VZ) * bim;
|
|
||||||
}
|
|
||||||
|
|
||||||
let bimass = b [0].get (MASS);
|
|
||||||
b [0].set (VX, -px / bimass);
|
|
||||||
b [0].set (VY, -py / bimass);
|
|
||||||
b [0].set (VZ, -pz / bimass);
|
|
||||||
}
|
|
||||||
|
|
||||||
offset_momentum (&mut bodies);
|
|
||||||
println! ("{:0.9}", energy (&bodies));
|
|
||||||
for _ in 0..num_iters {
|
|
||||||
advance (&mut bodies, 0.01);
|
|
||||||
}
|
|
||||||
println! ("{:0.9}", energy (&bodies));
|
|
||||||
}
|
|
||||||
|
|
||||||
trait Table2 {
|
|
||||||
fn get (&self, key: i64) -> f64;
|
|
||||||
fn set (&mut self, key: i64, value: f64);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive (Default)]
|
|
||||||
struct BTreeTable3 (BTreeMap <i64, f64>);
|
|
||||||
|
|
||||||
impl Table2 for BTreeTable3 {
|
|
||||||
fn get (&self, key: i64) -> f64 {
|
|
||||||
*self.0.get (&key).unwrap ()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set (&mut self, key: i64, value: f64) {
|
|
||||||
self.0.insert (key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive (Default)]
|
|
||||||
struct HashTable2 (HashMap <i64, f64>);
|
|
||||||
|
|
||||||
impl Table2 for HashTable2 {
|
|
||||||
fn get (&self, key: i64) -> f64 {
|
|
||||||
*self.0.get (&key).unwrap ()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set (&mut self, key: i64, value: f64) {
|
|
||||||
self.0.insert (key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn n_body_2 <T: Default + Table2> (num_iters: usize) {
|
|
||||||
const X: i64 = 1;
|
|
||||||
const Y: i64 = 2;
|
|
||||||
const Z: i64 = 3;
|
|
||||||
const VX: i64 = 4;
|
|
||||||
const VY: i64 = 5;
|
|
||||||
const VZ: i64 = 6;
|
|
||||||
const MASS: i64 = 7;
|
|
||||||
|
|
||||||
let days_per_year = 365.24;
|
|
||||||
|
|
||||||
let mut bodies = vec! [];
|
|
||||||
{
|
|
||||||
let mut t = T::default ();
|
|
||||||
t.set (X, 0.0);
|
|
||||||
t.set (Y, 0.0);
|
|
||||||
t.set (Z, 0.0);
|
|
||||||
t.set (VX, 0.0);
|
|
||||||
t.set (VY, 0.0);
|
|
||||||
t.set (VZ, 0.0);
|
|
||||||
t.set (MASS, SOLAR_MASS);
|
|
||||||
|
|
||||||
bodies.push (t);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let mut t = T::default ();
|
|
||||||
t.set (X, 4.84143144246472090e+00);
|
|
||||||
t.set (Y, -1.16032004402742839e+00);
|
|
||||||
t.set (Z, -1.03622044471123109e-01);
|
|
||||||
t.set (VX, 1.66007664274403694e-03 * days_per_year);
|
|
||||||
t.set (VY, 7.69901118419740425e-03 * days_per_year);
|
|
||||||
t.set (VZ, -6.90460016972063023e-05 * days_per_year);
|
|
||||||
t.set (MASS, 9.54791938424326609e-04 * SOLAR_MASS);
|
|
||||||
|
|
||||||
bodies.push (t);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let mut t = T::default ();
|
|
||||||
t.set (X, 8.34336671824457987e+00);
|
|
||||||
t.set (Y, 4.12479856412430479e+00);
|
|
||||||
t.set (Z, -4.03523417114321381e-01);
|
|
||||||
t.set (VX, -2.76742510726862411e-03 * days_per_year);
|
|
||||||
t.set (VY, 4.99852801234917238e-03 * days_per_year);
|
|
||||||
t.set (VZ, 2.30417297573763929e-05 * days_per_year);
|
|
||||||
t.set (MASS, 2.85885980666130812e-04 * SOLAR_MASS);
|
|
||||||
|
|
||||||
bodies.push (t);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let mut t = T::default ();
|
|
||||||
t.set (X, 1.28943695621391310e+01);
|
|
||||||
t.set (Y, -1.51111514016986312e+01);
|
|
||||||
t.set (Z, -2.23307578892655734e-01);
|
|
||||||
t.set (VX, 2.96460137564761618e-03 * days_per_year);
|
|
||||||
t.set (VY, 2.37847173959480950e-03 * days_per_year);
|
|
||||||
t.set (VZ, -2.96589568540237556e-05 * days_per_year);
|
|
||||||
t.set (MASS, 4.36624404335156298e-05 * SOLAR_MASS);
|
|
||||||
|
|
||||||
bodies.push (t);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let mut t = T::default ();
|
|
||||||
t.set (X, 1.53796971148509165e+01);
|
|
||||||
t.set (Y, -2.59193146099879641e+01);
|
|
||||||
t.set (Z, 1.79258772950371181e-01);
|
|
||||||
t.set (VX, 2.68067772490389322e-03 * days_per_year);
|
|
||||||
t.set (VY, 1.62824170038242295e-03 * days_per_year);
|
|
||||||
t.set (VZ, -9.51592254519715870e-05 * days_per_year);
|
|
||||||
t.set (MASS, 5.15138902046611451e-05 * SOLAR_MASS);
|
|
||||||
|
|
||||||
bodies.push (t);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance <T: Table2> (bodies: &mut [T], dt: f64) {
|
|
||||||
let nbody = bodies.len ();
|
|
||||||
|
|
||||||
for i in 0..nbody {
|
|
||||||
let bix;
|
|
||||||
let biy;
|
|
||||||
let biz;
|
|
||||||
let bimass;
|
|
||||||
let mut bivx;
|
|
||||||
let mut bivy;
|
|
||||||
let mut bivz;
|
|
||||||
{
|
|
||||||
let bi = &mut bodies [i];
|
|
||||||
bix = bi.get (X);
|
|
||||||
biy = bi.get (Y);
|
|
||||||
biz = bi.get (Z);
|
|
||||||
bimass = bi.get (MASS);
|
|
||||||
bivx = bi.get (VX);
|
|
||||||
bivy = bi.get (VY);
|
|
||||||
bivz = bi.get (VZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
for j in i + 1..nbody {
|
|
||||||
let bj = &mut bodies [j];
|
|
||||||
let dx = bix - bj.get (X);
|
|
||||||
let dy = biy - bj.get (Y);
|
|
||||||
let dz = biz - bj.get (Z);
|
|
||||||
let mut mag = (dx * dx + dy * dy + dz * dz).sqrt ();
|
|
||||||
mag = dt / (mag * mag * mag);
|
|
||||||
let mut bm = bj.get (MASS) * mag;
|
|
||||||
bivx -= dx * bm;
|
|
||||||
bivy -= dy * bm;
|
|
||||||
bivz -= dz * bm;
|
|
||||||
bm = bimass * mag;
|
|
||||||
bj.set (VX, bj.get (VX) + dx * bm);
|
|
||||||
bj.set (VY, bj.get (VY) + dy * bm);
|
|
||||||
bj.set (VZ, bj.get (VZ) + dz * bm);
|
|
||||||
}
|
|
||||||
|
|
||||||
let bi = &mut bodies [i];
|
|
||||||
bi.set (VX, bivx);
|
|
||||||
bi.set (VY, bivy);
|
|
||||||
bi.set (VZ, bivz);
|
|
||||||
bi.set (X, bix + dt * bivx);
|
|
||||||
bi.set (Y, biy + dt * bivy);
|
|
||||||
bi.set (Z, biz + dt * bivz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn energy <T: Table2> (bodies: &[T]) -> f64 {
|
|
||||||
let mut e = 0.0;
|
|
||||||
for (i, bi) in bodies.iter ().enumerate () {
|
|
||||||
let vx = bi.get (VX);
|
|
||||||
let vy = bi.get (VY);
|
|
||||||
let vz = bi.get (VZ);
|
|
||||||
let bim = bi.get (MASS);
|
|
||||||
|
|
||||||
e += 0.5 * bim * (vx * vx + vy * vy + vz * vz);
|
|
||||||
|
|
||||||
for j in i + 1..bodies.len () {
|
|
||||||
let bj = &bodies [j];
|
|
||||||
let dx = bi.get (X) - bj.get (X);
|
|
||||||
let dy = bi.get (Y) - bj.get (Y);
|
|
||||||
let dz = bi.get (Z) - bj.get (Z);
|
|
||||||
let distance = (dx * dx + dy * dy + dz * dz).sqrt ();
|
|
||||||
e -= (bim * bj.get (MASS)) / distance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e
|
|
||||||
}
|
|
||||||
|
|
||||||
fn offset_momentum <T: Table2> (b: &mut [T]) {
|
|
||||||
let mut px = 0.0;
|
|
||||||
let mut py = 0.0;
|
|
||||||
let mut pz = 0.0;
|
|
||||||
|
|
||||||
for bi in b.iter () {
|
|
||||||
let bim = bi.get (MASS);
|
|
||||||
px += bi.get (VX) * bim;
|
|
||||||
py += bi.get (VY) * bim;
|
|
||||||
pz += bi.get (VZ) * bim;
|
|
||||||
}
|
|
||||||
|
|
||||||
let bimass = b [0].get (MASS);
|
|
||||||
b [0].set (VX, -px / bimass);
|
|
||||||
b [0].set (VY, -py / bimass);
|
|
||||||
b [0].set (VZ, -pz / bimass);
|
|
||||||
}
|
|
||||||
|
|
||||||
offset_momentum (&mut bodies);
|
|
||||||
println! ("{:0.9}", energy (&bodies));
|
|
||||||
for _ in 0..num_iters {
|
|
||||||
advance (&mut bodies, 0.01);
|
|
||||||
}
|
|
||||||
println! ("{:0.9}", energy (&bodies));
|
|
||||||
}
|
|
||||||
|
|
||||||
trait Table3 {
|
|
||||||
fn get (&self, key: u64) -> f64;
|
|
||||||
fn set (&mut self, key: u64, value: f64);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive (Default)]
|
|
||||||
struct BTreeTable4 (BTreeMap <u64, f64>);
|
|
||||||
|
|
||||||
impl Table3 for BTreeTable4 {
|
|
||||||
fn get (&self, key: u64) -> f64 {
|
|
||||||
*self.0.get (&key).unwrap ()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set (&mut self, key: u64, value: f64) {
|
|
||||||
self.0.insert (key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn n_body_3 <T: Default + Table3> (num_iters: usize) {
|
|
||||||
const X: u64 = 1;
|
|
||||||
const Y: u64 = 2;
|
|
||||||
const Z: u64 = 3;
|
|
||||||
const VX: u64 = 4;
|
|
||||||
const VY: u64 = 5;
|
|
||||||
const VZ: u64 = 6;
|
|
||||||
const MASS: u64 = 7;
|
|
||||||
|
|
||||||
let days_per_year = 365.24;
|
|
||||||
|
|
||||||
let mut bodies = vec! [];
|
|
||||||
{
|
|
||||||
let mut t = T::default ();
|
|
||||||
t.set (X, 0.0);
|
|
||||||
t.set (Y, 0.0);
|
|
||||||
t.set (Z, 0.0);
|
|
||||||
t.set (VX, 0.0);
|
|
||||||
t.set (VY, 0.0);
|
|
||||||
t.set (VZ, 0.0);
|
|
||||||
t.set (MASS, SOLAR_MASS);
|
|
||||||
|
|
||||||
bodies.push (t);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let mut t = T::default ();
|
|
||||||
t.set (X, 4.84143144246472090e+00);
|
|
||||||
t.set (Y, -1.16032004402742839e+00);
|
|
||||||
t.set (Z, -1.03622044471123109e-01);
|
|
||||||
t.set (VX, 1.66007664274403694e-03 * days_per_year);
|
|
||||||
t.set (VY, 7.69901118419740425e-03 * days_per_year);
|
|
||||||
t.set (VZ, -6.90460016972063023e-05 * days_per_year);
|
|
||||||
t.set (MASS, 9.54791938424326609e-04 * SOLAR_MASS);
|
|
||||||
|
|
||||||
bodies.push (t);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let mut t = T::default ();
|
|
||||||
t.set (X, 8.34336671824457987e+00);
|
|
||||||
t.set (Y, 4.12479856412430479e+00);
|
|
||||||
t.set (Z, -4.03523417114321381e-01);
|
|
||||||
t.set (VX, -2.76742510726862411e-03 * days_per_year);
|
|
||||||
t.set (VY, 4.99852801234917238e-03 * days_per_year);
|
|
||||||
t.set (VZ, 2.30417297573763929e-05 * days_per_year);
|
|
||||||
t.set (MASS, 2.85885980666130812e-04 * SOLAR_MASS);
|
|
||||||
|
|
||||||
bodies.push (t);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let mut t = T::default ();
|
|
||||||
t.set (X, 1.28943695621391310e+01);
|
|
||||||
t.set (Y, -1.51111514016986312e+01);
|
|
||||||
t.set (Z, -2.23307578892655734e-01);
|
|
||||||
t.set (VX, 2.96460137564761618e-03 * days_per_year);
|
|
||||||
t.set (VY, 2.37847173959480950e-03 * days_per_year);
|
|
||||||
t.set (VZ, -2.96589568540237556e-05 * days_per_year);
|
|
||||||
t.set (MASS, 4.36624404335156298e-05 * SOLAR_MASS);
|
|
||||||
|
|
||||||
bodies.push (t);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let mut t = T::default ();
|
|
||||||
t.set (X, 1.53796971148509165e+01);
|
|
||||||
t.set (Y, -2.59193146099879641e+01);
|
|
||||||
t.set (Z, 1.79258772950371181e-01);
|
|
||||||
t.set (VX, 2.68067772490389322e-03 * days_per_year);
|
|
||||||
t.set (VY, 1.62824170038242295e-03 * days_per_year);
|
|
||||||
t.set (VZ, -9.51592254519715870e-05 * days_per_year);
|
|
||||||
t.set (MASS, 5.15138902046611451e-05 * SOLAR_MASS);
|
|
||||||
|
|
||||||
bodies.push (t);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance <T: Table3> (bodies: &mut [T], dt: f64) {
|
|
||||||
let nbody = bodies.len ();
|
|
||||||
|
|
||||||
for i in 0..nbody {
|
|
||||||
let bix;
|
|
||||||
let biy;
|
|
||||||
let biz;
|
|
||||||
let bimass;
|
|
||||||
let mut bivx;
|
|
||||||
let mut bivy;
|
|
||||||
let mut bivz;
|
|
||||||
{
|
|
||||||
let bi = &mut bodies [i];
|
|
||||||
bix = bi.get (X);
|
|
||||||
biy = bi.get (Y);
|
|
||||||
biz = bi.get (Z);
|
|
||||||
bimass = bi.get (MASS);
|
|
||||||
bivx = bi.get (VX);
|
|
||||||
bivy = bi.get (VY);
|
|
||||||
bivz = bi.get (VZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
for j in i + 1..nbody {
|
|
||||||
let bj = &mut bodies [j];
|
|
||||||
let dx = bix - bj.get (X);
|
|
||||||
let dy = biy - bj.get (Y);
|
|
||||||
let dz = biz - bj.get (Z);
|
|
||||||
let mut mag = (dx * dx + dy * dy + dz * dz).sqrt ();
|
|
||||||
mag = dt / (mag * mag * mag);
|
|
||||||
let mut bm = bj.get (MASS) * mag;
|
|
||||||
bivx -= dx * bm;
|
|
||||||
bivy -= dy * bm;
|
|
||||||
bivz -= dz * bm;
|
|
||||||
bm = bimass * mag;
|
|
||||||
bj.set (VX, bj.get (VX) + dx * bm);
|
|
||||||
bj.set (VY, bj.get (VY) + dy * bm);
|
|
||||||
bj.set (VZ, bj.get (VZ) + dz * bm);
|
|
||||||
}
|
|
||||||
|
|
||||||
let bi = &mut bodies [i];
|
|
||||||
bi.set (VX, bivx);
|
|
||||||
bi.set (VY, bivy);
|
|
||||||
bi.set (VZ, bivz);
|
|
||||||
bi.set (X, bix + dt * bivx);
|
|
||||||
bi.set (Y, biy + dt * bivy);
|
|
||||||
bi.set (Z, biz + dt * bivz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn energy <T: Table3> (bodies: &[T]) -> f64 {
|
|
||||||
let mut e = 0.0;
|
|
||||||
for (i, bi) in bodies.iter ().enumerate () {
|
|
||||||
let vx = bi.get (VX);
|
|
||||||
let vy = bi.get (VY);
|
|
||||||
let vz = bi.get (VZ);
|
|
||||||
let bim = bi.get (MASS);
|
|
||||||
|
|
||||||
e += 0.5 * bim * (vx * vx + vy * vy + vz * vz);
|
|
||||||
|
|
||||||
for j in i + 1..bodies.len () {
|
|
||||||
let bj = &bodies [j];
|
|
||||||
let dx = bi.get (X) - bj.get (X);
|
|
||||||
let dy = bi.get (Y) - bj.get (Y);
|
|
||||||
let dz = bi.get (Z) - bj.get (Z);
|
|
||||||
let distance = (dx * dx + dy * dy + dz * dz).sqrt ();
|
|
||||||
e -= (bim * bj.get (MASS)) / distance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e
|
|
||||||
}
|
|
||||||
|
|
||||||
fn offset_momentum <T: Table3> (b: &mut [T]) {
|
|
||||||
let mut px = 0.0;
|
|
||||||
let mut py = 0.0;
|
|
||||||
let mut pz = 0.0;
|
|
||||||
|
|
||||||
for bi in b.iter () {
|
|
||||||
let bim = bi.get (MASS);
|
|
||||||
px += bi.get (VX) * bim;
|
|
||||||
py += bi.get (VY) * bim;
|
|
||||||
pz += bi.get (VZ) * bim;
|
|
||||||
}
|
|
||||||
|
|
||||||
let bimass = b [0].get (MASS);
|
|
||||||
b [0].set (VX, -px / bimass);
|
|
||||||
b [0].set (VY, -py / bimass);
|
|
||||||
b [0].set (VZ, -pz / bimass);
|
|
||||||
}
|
|
||||||
|
|
||||||
offset_momentum (&mut bodies);
|
|
||||||
println! ("{:0.9}", energy (&bodies));
|
|
||||||
for _ in 0..num_iters {
|
|
||||||
advance (&mut bodies, 0.01);
|
|
||||||
}
|
|
||||||
println! ("{:0.9}", energy (&bodies));
|
|
||||||
}
|
|
|
@ -2,7 +2,6 @@ mod error;
|
||||||
mod instruction;
|
mod instruction;
|
||||||
mod loader;
|
mod loader;
|
||||||
mod state;
|
mod state;
|
||||||
mod string_interner;
|
|
||||||
mod value;
|
mod value;
|
||||||
|
|
||||||
pub use error::Error as Error;
|
pub use error::Error as Error;
|
||||||
|
@ -16,7 +15,6 @@ pub use state::Chunk as Chunk;
|
||||||
pub use state::State as State;
|
pub use state::State as State;
|
||||||
pub use state::StepError as StepError;
|
pub use state::StepError as StepError;
|
||||||
pub use state::StepOutput as StepOutput;
|
pub use state::StepOutput as StepOutput;
|
||||||
pub use string_interner::Interner as Interner;
|
|
||||||
pub use value::Value as Value;
|
pub use value::Value as Value;
|
||||||
|
|
||||||
#[cfg (test)]
|
#[cfg (test)]
|
||||||
|
|
|
@ -5,8 +5,7 @@ use crate::{
|
||||||
state::{
|
state::{
|
||||||
Block,
|
Block,
|
||||||
Chunk,
|
Chunk,
|
||||||
},
|
}
|
||||||
string_interner::Interner,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn compile_bytecode_from_file (path: &str) -> Vec <u8> {
|
pub fn compile_bytecode_from_file (path: &str) -> Vec <u8> {
|
||||||
|
@ -243,7 +242,7 @@ fn parse_i64 <R: Read> (rdr: &mut R) -> Option <i64> {
|
||||||
// code, but I don't like recursion in general, and I don't know
|
// code, but I don't like recursion in general, and I don't know
|
||||||
// why PUC wrote it that way.
|
// why PUC wrote it that way.
|
||||||
|
|
||||||
pub fn parse_block <R: Read> (rdr: &mut R, si: &mut Interner, blocks: &mut Vec <Block>)
|
pub fn parse_block <R: Read> (rdr: &mut R, blocks: &mut Vec <Block>)
|
||||||
-> Option <()>
|
-> Option <()>
|
||||||
{
|
{
|
||||||
// Ignore things I haven't implemented yet
|
// Ignore things I haven't implemented yet
|
||||||
|
@ -274,12 +273,12 @@ pub fn parse_block <R: Read> (rdr: &mut R, si: &mut Interner, blocks: &mut Vec <
|
||||||
|
|
||||||
let val = match const_type {
|
let val = match const_type {
|
||||||
3 => parse_i64 (rdr).unwrap ().into (),
|
3 => parse_i64 (rdr).unwrap ().into (),
|
||||||
4 => si.to_value (parse_string (rdr).unwrap ().as_str ()),
|
4 => parse_string (rdr).unwrap ().into (),
|
||||||
|
|
||||||
// For LUA_TNUMBER, PUC Lua uses a macro that adds 16 to signify a float
|
// For LUA_TNUMBER, PUC Lua uses a macro that adds 16 to signify a float
|
||||||
19 => parse_float (rdr).unwrap ().into (),
|
19 => parse_float (rdr).unwrap ().into (),
|
||||||
// 0x10 + 4 = long string
|
// 0x10 + 4 = long string
|
||||||
20 => si.to_value (parse_string (rdr).unwrap ().as_str ()),
|
20 => parse_string (rdr).unwrap ().into (),
|
||||||
x => panic! ("Constant {} has type {}", i, x),
|
x => panic! ("Constant {} has type {}", i, x),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -313,7 +312,7 @@ pub fn parse_block <R: Read> (rdr: &mut R, si: &mut Interner, blocks: &mut Vec <
|
||||||
// Subfunctions. PUC calls them protos.
|
// Subfunctions. PUC calls them protos.
|
||||||
let protos_count = parse_int (rdr).unwrap ();
|
let protos_count = parse_int (rdr).unwrap ();
|
||||||
for _ in 0..protos_count {
|
for _ in 0..protos_count {
|
||||||
parse_block (rdr, si, blocks).unwrap ();
|
parse_block (rdr, blocks).unwrap ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip over debug stuff
|
// Skip over debug stuff
|
||||||
|
@ -349,12 +348,12 @@ pub fn parse_block <R: Read> (rdr: &mut R, si: &mut Interner, blocks: &mut Vec <
|
||||||
Some (())
|
Some (())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_chunk (buf: &[u8], si: &mut Interner) -> Option <Chunk> {
|
pub fn parse_chunk (buf: &[u8]) -> Option <Chunk> {
|
||||||
let mut rdr = std::io::Cursor::new (buf);
|
let mut rdr = std::io::Cursor::new (buf);
|
||||||
parse_chunk_from_reader (&mut rdr, si)
|
parse_chunk_from_reader (&mut rdr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_chunk_from_reader <R: Read> (rdr: &mut R, si: &mut Interner) -> Option <Chunk> {
|
pub fn parse_chunk_from_reader <R: Read> (rdr: &mut R) -> Option <Chunk> {
|
||||||
// Discard 32 bytes from the start of the file.
|
// Discard 32 bytes from the start of the file.
|
||||||
// This is magic number, version number, etc.
|
// This is magic number, version number, etc.
|
||||||
|
|
||||||
|
@ -365,7 +364,7 @@ pub fn parse_chunk_from_reader <R: Read> (rdr: &mut R, si: &mut Interner) -> Opt
|
||||||
|
|
||||||
let mut blocks = vec![];
|
let mut blocks = vec![];
|
||||||
|
|
||||||
parse_block (rdr, si, &mut blocks).unwrap ();
|
parse_block (rdr, &mut blocks).unwrap ();
|
||||||
|
|
||||||
Some (Chunk {
|
Some (Chunk {
|
||||||
blocks,
|
blocks,
|
||||||
|
@ -374,8 +373,6 @@ pub fn parse_chunk_from_reader <R: Read> (rdr: &mut R, si: &mut Interner) -> Opt
|
||||||
|
|
||||||
#[cfg (test)]
|
#[cfg (test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn load_size () {
|
fn load_size () {
|
||||||
let f = |input: &[u8]| {
|
let f = |input: &[u8]| {
|
||||||
|
@ -444,8 +441,6 @@ mod tests {
|
||||||
fn parse_nested_functions () {
|
fn parse_nested_functions () {
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
let mut si = Interner::default ();
|
|
||||||
|
|
||||||
let bytecode = include_bytes! ("../test_vectors/functions.luac");
|
let bytecode = include_bytes! ("../test_vectors/functions.luac");
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -456,7 +451,7 @@ mod tests {
|
||||||
|
|
||||||
let mut blocks = vec! [];
|
let mut blocks = vec! [];
|
||||||
|
|
||||||
super::parse_block (&mut rdr, &mut si, &mut blocks).unwrap ();
|
super::parse_block (&mut rdr, &mut blocks).unwrap ();
|
||||||
|
|
||||||
assert_eq! (blocks [0].instructions.len (), 15);
|
assert_eq! (blocks [0].instructions.len (), 15);
|
||||||
assert_eq! (blocks [1].instructions.len (), 6);
|
assert_eq! (blocks [1].instructions.len (), 6);
|
||||||
|
@ -466,7 +461,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
if false {
|
if false {
|
||||||
let file = crate::loader::parse_chunk (bytecode, &mut si).unwrap ();
|
let file = crate::loader::parse_chunk (bytecode).unwrap ();
|
||||||
|
|
||||||
assert_eq! (file.blocks.len (), 5);
|
assert_eq! (file.blocks.len (), 5);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
instruction::Instruction,
|
instruction::Instruction,
|
||||||
string_interner::Interner,
|
|
||||||
value::{
|
value::{
|
||||||
BogusClosure,
|
BogusClosure,
|
||||||
Value,
|
Value,
|
||||||
|
@ -55,10 +54,7 @@ pub struct State {
|
||||||
pub debug_print: bool,
|
pub debug_print: bool,
|
||||||
step_count: u32,
|
step_count: u32,
|
||||||
chunk: Chunk,
|
chunk: Chunk,
|
||||||
pub upvalues: Vec <Value>,
|
upvalues: Vec <Value>,
|
||||||
pub si: Interner,
|
|
||||||
register_offset: usize,
|
|
||||||
block_idx: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lw_io_write (l: &mut State, num_args: usize) -> usize {
|
fn lw_io_write (l: &mut State, num_args: usize) -> usize {
|
||||||
|
@ -66,7 +62,7 @@ fn lw_io_write (l: &mut State, num_args: usize) -> usize {
|
||||||
match l.reg (i) {
|
match l.reg (i) {
|
||||||
Value::Float (x) => print! ("{}", x),
|
Value::Float (x) => print! ("{}", x),
|
||||||
Value::Integer (x) => print! ("{}", x),
|
Value::Integer (x) => print! ("{}", x),
|
||||||
Value::String (x) => print! ("{}", l.si.get (*x)),
|
Value::String (x) => print! ("{}", x),
|
||||||
_ => panic! ("Can't io.write this value"),
|
_ => panic! ("Can't io.write this value"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,12 +97,12 @@ fn lw_string_format (l: &mut State, num_args: usize) -> usize {
|
||||||
assert! (num_args >= 1, "string.format needs at least 1 argument");
|
assert! (num_args >= 1, "string.format needs at least 1 argument");
|
||||||
assert_eq! (l.get_top (), 2, "string.format not fully implemented");
|
assert_eq! (l.get_top (), 2, "string.format not fully implemented");
|
||||||
let f_string = l.reg (0).as_str ().unwrap ();
|
let f_string = l.reg (0).as_str ().unwrap ();
|
||||||
assert_eq! (Value::String (f_string), l.to_string ("%0.9f"));
|
assert_eq! (f_string, "%0.9f");
|
||||||
let num = l.reg (1).as_float ().unwrap ();
|
let num = l.reg (1).as_float ().unwrap ();
|
||||||
|
|
||||||
let output = format! ("{:0.9}", num);
|
let output = format! ("{:0.9}", num);
|
||||||
|
|
||||||
*l.reg_mut (0) = l.to_string (&output);
|
*l.reg_mut (0) = Value::from (output);
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,14 +117,14 @@ fn lw_table_concat (l: &mut State, num_args: usize) -> usize {
|
||||||
|
|
||||||
for i in 0..t.length () {
|
for i in 0..t.length () {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
s.push_str (l.si.get (joiner));
|
s.push_str (joiner);
|
||||||
}
|
}
|
||||||
let x = t.get_int (i + 1);
|
let x = t.get_int (i + 1);
|
||||||
s.push_str (&format! ("{}", x));
|
s.push_str (&format! ("{}", x));
|
||||||
}
|
}
|
||||||
s
|
s
|
||||||
};
|
};
|
||||||
*l.reg_mut (0) = l.to_string (&s);
|
*l.reg_mut (0) = Value::from (s);
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,15 +137,15 @@ fn lw_table_pack (l: &mut State, num_args: usize) -> usize {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tonumber (l: &State, value: &Value) -> Value {
|
fn tonumber (value: &Value) -> Value {
|
||||||
match value {
|
match value {
|
||||||
Value::Float (x) => Value::Float (*x),
|
Value::Float (x) => Value::Float (*x),
|
||||||
Value::Integer (x) => Value::Integer (*x),
|
Value::Integer (x) => Value::Integer (*x),
|
||||||
Value::String (x) => {
|
Value::String (x) => {
|
||||||
if let Ok (x) = str::parse::<i64> (l.si.get (*x)) {
|
if let Ok (x) = str::parse::<i64> (x) {
|
||||||
Value::from (x)
|
Value::from (x)
|
||||||
}
|
}
|
||||||
else if let Ok (x) = str::parse::<f64> (l.si.get (*x)) {
|
else if let Ok (x) = str::parse::<f64> (x) {
|
||||||
Value::from (x)
|
Value::from (x)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -162,7 +158,7 @@ fn tonumber (l: &State, value: &Value) -> Value {
|
||||||
|
|
||||||
fn lw_tonumber (l: &mut State, num_args: usize) -> usize {
|
fn lw_tonumber (l: &mut State, num_args: usize) -> usize {
|
||||||
assert_eq! (num_args, 1, "tonumber only implemented for 1 argument");
|
assert_eq! (num_args, 1, "tonumber only implemented for 1 argument");
|
||||||
let output = tonumber (&l, l.reg (0));
|
let output = tonumber (l.reg (0));
|
||||||
*l.reg_mut (0) = output;
|
*l.reg_mut (0) = output;
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
@ -195,30 +191,6 @@ impl State {
|
||||||
step_count: 0,
|
step_count: 0,
|
||||||
chunk,
|
chunk,
|
||||||
upvalues,
|
upvalues,
|
||||||
si: Default::default (),
|
|
||||||
register_offset: 0,
|
|
||||||
block_idx: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_with_args <I: Iterator <Item = String>> (chunk: Chunk, mut si: Interner, args: I) -> Self {
|
|
||||||
let upvalues = Self::upvalues_from_args (&mut si, args);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
// 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::default (),
|
|
||||||
],
|
|
||||||
debug_print: false,
|
|
||||||
step_count: 0,
|
|
||||||
chunk,
|
|
||||||
upvalues,
|
|
||||||
si,
|
|
||||||
register_offset: 0,
|
|
||||||
block_idx: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,27 +199,27 @@ impl State {
|
||||||
frame.block_idx == bp.block_idx && frame.program_counter == bp.program_counter
|
frame.block_idx == bp.block_idx && frame.program_counter == bp.program_counter
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upvalues_from_args <I: Iterator <Item = String>> (si: &mut Interner, args: I) -> Vec <Value>
|
pub fn upvalues_from_args <I: Iterator <Item = String>> (args: I) -> Vec <Value>
|
||||||
{
|
{
|
||||||
let arg = args.map (|s| si.intern (&s)).enumerate ();
|
let arg = args.map (|s| Value::from (s)).enumerate ();
|
||||||
let arg = Value::from_iter (arg.map (|(i, v)| (Value::from (i), Value::String (v))));
|
let arg = Value::from_iter (arg.map (|(i, v)| (Value::from (i), v)));
|
||||||
|
|
||||||
let io: Vec <_> = [
|
let io = [
|
||||||
("write", Value::RsFunc (lw_io_write)),
|
("write", Value::RsFunc (lw_io_write)),
|
||||||
].into_iter ().map (|(k, v)| (si.intern (k), v)).collect ();
|
].into_iter ().map (|(k, v)| (k.to_string (), v));
|
||||||
|
|
||||||
let math: Vec <_> = [
|
let math = [
|
||||||
("sqrt", Value::RsFunc (lw_sqrt)),
|
("sqrt", Value::RsFunc (lw_sqrt)),
|
||||||
].into_iter ().map (|(k, v)| (si.intern (k), v)).collect ();
|
].into_iter ().map (|(k, v)| (k.to_string (), v));
|
||||||
|
|
||||||
let string: Vec <_> = [
|
let string = [
|
||||||
("format", Value::RsFunc (lw_string_format)),
|
("format", Value::RsFunc (lw_string_format)),
|
||||||
].into_iter ().map (|(k, v)| (si.intern (k), v)).collect ();
|
].into_iter ().map (|(k, v)| (k.to_string (), v));
|
||||||
|
|
||||||
let table: Vec <_> = [
|
let table = [
|
||||||
("concat", Value::RsFunc (lw_table_concat)),
|
("concat", Value::RsFunc (lw_table_concat)),
|
||||||
("pack", Value::RsFunc (lw_table_pack)),
|
("pack", Value::RsFunc (lw_table_pack)),
|
||||||
].into_iter ().map (|(k, v)| (si.intern (k), v)).collect ();
|
].into_iter ().map (|(k, v)| (k.to_string (), v));
|
||||||
|
|
||||||
let env = [
|
let env = [
|
||||||
("arg", arg),
|
("arg", arg),
|
||||||
|
@ -257,7 +229,7 @@ impl State {
|
||||||
("string", Value::from_iter (string.into_iter ())),
|
("string", Value::from_iter (string.into_iter ())),
|
||||||
("table", Value::from_iter (table.into_iter ())),
|
("table", Value::from_iter (table.into_iter ())),
|
||||||
("tonumber", Value::RsFunc (lw_tonumber)),
|
("tonumber", Value::RsFunc (lw_tonumber)),
|
||||||
].into_iter ().map (|(k, v)| (si.intern (k), v));
|
].into_iter ().map (|(k, v)| (k.to_string (), v));
|
||||||
|
|
||||||
vec! [
|
vec! [
|
||||||
Value::from_iter (env.into_iter ()),
|
Value::from_iter (env.into_iter ()),
|
||||||
|
@ -272,11 +244,13 @@ impl State {
|
||||||
/// Short form to get access to a register within our window
|
/// Short form to get access to a register within our window
|
||||||
|
|
||||||
pub fn reg (&self, i: u8) -> &Value {
|
pub fn reg (&self, i: u8) -> &Value {
|
||||||
&self.registers [self.register_offset + i as usize]
|
let frame = self.stack.last ().unwrap ();
|
||||||
|
&self.registers [frame.register_offset + i as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reg_mut (&mut self, i: u8) -> &mut Value {
|
pub fn reg_mut (&mut self, i: u8) -> &mut Value {
|
||||||
&mut self.registers [self.register_offset + i as usize]
|
let frame = self.stack.last ().unwrap ();
|
||||||
|
&mut self.registers [frame.register_offset + i as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
// For native functions to check how many args they got
|
// For native functions to check how many args they got
|
||||||
|
@ -293,120 +267,18 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_add (&mut self, a: u8, b: u8, c: u8) -> bool {
|
|
||||||
let v_b = self.reg (b);
|
|
||||||
let v_c = self.reg (c);
|
|
||||||
|
|
||||||
*self.reg_mut (a) = match (v_b, v_c) {
|
|
||||||
(Value::Float (b), Value::Float (c)) => Value::from (b + c),
|
|
||||||
(Value::Integer (b), Value::Integer (c)) => Value::from (b + c),
|
|
||||||
(Value::Integer (b), Value::Float (c)) => Value::from (*b as f64 + c),
|
|
||||||
(Value::Float (b), Value::Integer (c)) => Value::from (b + *c as f64),
|
|
||||||
_ => return false,
|
|
||||||
};
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn op_get_field (&mut self, a: u8, b: u8, c: u8) {
|
|
||||||
let block = self.chunk.blocks.get (self.block_idx).unwrap ();
|
|
||||||
let constants = &block.constants;
|
|
||||||
|
|
||||||
let key = match &constants [usize::from (c)] {
|
|
||||||
Value::String (s) => s,
|
|
||||||
_ => panic! ("K[C] must be a string"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let val = match &self.registers [self.register_offset + usize::from (b)] {
|
|
||||||
Value::Nil => panic! ("R[B] must not be nil"),
|
|
||||||
Value::Table (t) => t.borrow ().get_str (*key).clone (),
|
|
||||||
_ => panic! ("R[B] must be a table"),
|
|
||||||
};
|
|
||||||
|
|
||||||
*self.reg_mut (a) = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn op_get_table (&mut self, a: u8, b: u8, c: u8) {
|
|
||||||
let t = match self.reg (b) {
|
|
||||||
Value::Table (t) => t,
|
|
||||||
_ => panic! ("R[B] must be a table"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let key = self.reg (c);
|
|
||||||
|
|
||||||
let val = t.borrow ().get (key.clone ()).clone ();
|
|
||||||
|
|
||||||
*self.reg_mut (a) = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn op_mmbin (&mut self, a: u8, b: u8, _c: u8) {
|
|
||||||
let a = self.reg (a);
|
|
||||||
let b = self.reg (b);
|
|
||||||
|
|
||||||
if a.as_float().is_some() && b.as_float().is_some () {
|
|
||||||
// No need for metamethods
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
panic! ("Not sure how to implement OP_MMBIN for these 2 values {a:?}, {b:?}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn op_mul (&mut self, a: u8, b: u8, c: u8) -> bool {
|
|
||||||
let v_b = self.reg (b);
|
|
||||||
let v_c = self.reg (c);
|
|
||||||
|
|
||||||
*self.reg_mut (a) = match (v_b, v_c) {
|
|
||||||
(Value::Float (b), Value::Float (c)) => Value::from (b * c),
|
|
||||||
(Value::Integer (b), Value::Integer (c)) => Value::from (b * c),
|
|
||||||
(Value::Integer (b), Value::Float (c)) => Value::from (*b as f64 * c),
|
|
||||||
(Value::Float (b), Value::Integer (c)) => Value::from (b * *c as f64),
|
|
||||||
_ => return false,
|
|
||||||
};
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn op_set_field (&mut self, a: u8, b: u8, c: u8, k: bool) {
|
|
||||||
let frame = self.stack.last ().unwrap ();
|
|
||||||
let block = self.chunk.blocks.get (frame.block_idx).unwrap ();
|
|
||||||
let constants = &block.constants;
|
|
||||||
|
|
||||||
let value = if k {
|
|
||||||
&constants [usize::from (c)]
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
self.reg (c)
|
|
||||||
}
|
|
||||||
.clone ();
|
|
||||||
|
|
||||||
let b = usize::try_from (b).unwrap ();
|
|
||||||
|
|
||||||
let key = match constants.get (b).unwrap () {
|
|
||||||
Value::String (s) => *s,
|
|
||||||
_ => panic! ("SetField only supports string keys"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut dst = self.reg (a).as_table ()
|
|
||||||
.expect ("SetField only works on tables").borrow_mut ();
|
|
||||||
|
|
||||||
dst.insert_str (key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn step (&mut self) -> Result <Option <StepOutput>, StepError>
|
pub fn step (&mut self) -> Result <Option <StepOutput>, StepError>
|
||||||
{
|
{
|
||||||
self.step_count += 1;
|
self.step_count += 1;
|
||||||
|
|
||||||
let frame = self.stack.last ().unwrap ();
|
let frame = self.stack.last_mut ().unwrap ().clone ();
|
||||||
self.block_idx = frame.block_idx;
|
let block = self.chunk.blocks.get (frame.block_idx).unwrap ();
|
||||||
self.register_offset = frame.register_offset;
|
|
||||||
let block_idx = frame.block_idx;
|
|
||||||
let block = self.chunk.blocks.get (block_idx).unwrap ();
|
|
||||||
|
|
||||||
let mut next_pc = frame.program_counter;
|
let mut next_pc = frame.program_counter;
|
||||||
|
|
||||||
let pc = usize::try_from (frame.program_counter).expect ("program_counter is not a valid usize");
|
let pc = usize::try_from (frame.program_counter).expect ("program_counter is not a valid usize");
|
||||||
let instruction = match block.instructions.get (pc) {
|
let instruction = match block.instructions.get (pc) {
|
||||||
Some (x) => *x,
|
Some (x) => x,
|
||||||
None => {
|
None => {
|
||||||
dbg! (&self.stack);
|
dbg! (&self.stack);
|
||||||
panic! ("program_counter went out of bounds");
|
panic! ("program_counter went out of bounds");
|
||||||
|
@ -417,14 +289,25 @@ impl State {
|
||||||
let k = &block.constants;
|
let k = &block.constants;
|
||||||
|
|
||||||
let make_step_error = |msg| {
|
let make_step_error = |msg| {
|
||||||
self.make_step_error (msg, &instruction)
|
self.make_step_error (msg, instruction)
|
||||||
};
|
};
|
||||||
|
|
||||||
match instruction {
|
match instruction.clone () {
|
||||||
Instruction::Add (a, b, c) => {
|
Instruction::Add (a, b, c) => {
|
||||||
if self.op_add (a, b, c) {
|
let v_b = self.reg (b);
|
||||||
next_pc += 1;
|
let v_c = self.reg (c);
|
||||||
|
|
||||||
|
let x = if let (Some (v_b), Some (v_c)) = (v_b.as_int (), v_c.as_int ())
|
||||||
|
{
|
||||||
|
Value::from (v_b + v_c)
|
||||||
}
|
}
|
||||||
|
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}"));
|
||||||
|
Value::from (v_b + v_c)
|
||||||
|
};
|
||||||
|
|
||||||
|
*self.reg_mut (a) = x;
|
||||||
},
|
},
|
||||||
Instruction::AddI (a, b, s_c) => {
|
Instruction::AddI (a, b, s_c) => {
|
||||||
let v_b = self.reg (b);
|
let v_b = self.reg (b);
|
||||||
|
@ -460,12 +343,15 @@ impl State {
|
||||||
Value::BogusClosure (rc) => {
|
Value::BogusClosure (rc) => {
|
||||||
let idx = rc.borrow ().idx;
|
let idx = rc.borrow ().idx;
|
||||||
|
|
||||||
|
let block_idx = frame.block_idx;
|
||||||
let target_block = idx;
|
let target_block = idx;
|
||||||
|
|
||||||
|
let current_frame = self.stack.last ().unwrap ();
|
||||||
|
|
||||||
self.stack.push (StackFrame {
|
self.stack.push (StackFrame {
|
||||||
program_counter: 0,
|
program_counter: 0,
|
||||||
block_idx: target_block,
|
block_idx: target_block,
|
||||||
register_offset: self.register_offset + a as usize + 1,
|
register_offset: current_frame.register_offset + a as usize + 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
if self.debug_print {
|
if self.debug_print {
|
||||||
|
@ -478,19 +364,19 @@ impl State {
|
||||||
return Ok (None);
|
return Ok (None);
|
||||||
},
|
},
|
||||||
Value::RsFunc (x) => {
|
Value::RsFunc (x) => {
|
||||||
let old_offset = self.register_offset;
|
let current_frame = self.stack.last ().unwrap ();
|
||||||
self.register_offset = old_offset + usize::from (a) + 1;
|
let new_offset = current_frame.register_offset + usize::from (a) + 1;
|
||||||
|
|
||||||
// Trash the stack frame so it doesn't point to a
|
// Trash the stack frame so it doesn't point to a
|
||||||
// valid Lua function
|
// valid Lua function
|
||||||
self.stack.push (StackFrame {
|
self.stack.push (StackFrame {
|
||||||
program_counter: 65535, // Bogus for native functions
|
program_counter: 65535, // Bogus for native functions
|
||||||
block_idx: 65535, // Bogus
|
block_idx: 65535, // Bogus
|
||||||
register_offset: self.register_offset,
|
register_offset: new_offset,
|
||||||
});
|
});
|
||||||
|
|
||||||
let num_args = if b == 0 {
|
let num_args = if b == 0 {
|
||||||
self.top - self.register_offset
|
self.top - new_offset
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
b - 1
|
b - 1
|
||||||
|
@ -500,8 +386,7 @@ impl State {
|
||||||
let num_results = x (self, num_args);
|
let num_results = x (self, num_args);
|
||||||
|
|
||||||
let popped_frame = self.stack.pop ().unwrap ();
|
let popped_frame = self.stack.pop ().unwrap ();
|
||||||
self.register_offset = old_offset;
|
let offset = popped_frame.register_offset - 1;
|
||||||
let offset = old_offset + usize::from (a);
|
|
||||||
|
|
||||||
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].take ();
|
self.registers [i] = self.registers [i + 1].take ();
|
||||||
|
@ -594,10 +479,32 @@ impl State {
|
||||||
*self.reg_mut (a + 3) = start.into ();
|
*self.reg_mut (a + 3) = start.into ();
|
||||||
},
|
},
|
||||||
Instruction::GetField (a, b, c) => {
|
Instruction::GetField (a, b, c) => {
|
||||||
self.op_get_field (a, b, c);
|
let t = match self.reg (b) {
|
||||||
|
Value::Nil => Err (make_step_error ("R[B] must not be nil"))?,
|
||||||
|
Value::Table (t) => t,
|
||||||
|
_ => Err (make_step_error ("R[B] must be a table"))?,
|
||||||
|
};
|
||||||
|
|
||||||
|
let key = match &k [usize::from (c)] {
|
||||||
|
Value::String (s) => s,
|
||||||
|
_ => panic! ("K[C] must be a string"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let val = t.borrow ().get_str (key.as_str ()).clone ();
|
||||||
|
|
||||||
|
*self.reg_mut (a) = val;
|
||||||
},
|
},
|
||||||
Instruction::GetTable (a, b, c) => {
|
Instruction::GetTable (a, b, c) => {
|
||||||
self.op_get_table (a, b, c);
|
let t = match self.reg (b) {
|
||||||
|
Value::Table (t) => t,
|
||||||
|
_ => panic! ("R[B] must be a table"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let key = self.reg (c);
|
||||||
|
|
||||||
|
let val = t.borrow ().get (key.clone ());
|
||||||
|
|
||||||
|
*self.reg_mut (a) = val;
|
||||||
},
|
},
|
||||||
Instruction::GetTabUp (a, b, c) => {
|
Instruction::GetTabUp (a, b, c) => {
|
||||||
let b = usize::try_from (b).unwrap ();
|
let b = usize::try_from (b).unwrap ();
|
||||||
|
@ -623,18 +530,18 @@ impl State {
|
||||||
let table = value.as_table ().expect ("GetTabUp only works on tables").borrow ();
|
let table = value.as_table ().expect ("GetTabUp only works on tables").borrow ();
|
||||||
|
|
||||||
let key = match k.get (c).unwrap () {
|
let key = match k.get (c).unwrap () {
|
||||||
Value::String (s) => *s,
|
Value::String (s) => String::from (s.as_ref()),
|
||||||
_ => panic! ("GetTabUp only supports string keys"),
|
_ => panic! ("GetTabUp only supports string keys"),
|
||||||
};
|
};
|
||||||
|
|
||||||
*self.reg_mut (a) = table.get_str (key).clone ();
|
*self.reg_mut (a) = table.get (key);
|
||||||
},
|
},
|
||||||
Instruction::GetI (a, b, c) => {
|
Instruction::GetI (a, b, c) => {
|
||||||
let key = i64::try_from (c).unwrap ();
|
let key = i64::try_from (c).unwrap ();
|
||||||
|
|
||||||
let value = {
|
let value = {
|
||||||
let table = self.reg (b).as_table ().expect ("GetI only works on tables").borrow ();
|
let table = self.reg (b).as_table ().expect ("GetI only works on tables").borrow ();
|
||||||
table.get_int (key).clone ()
|
table.get_int (key)
|
||||||
};
|
};
|
||||||
|
|
||||||
*self.reg_mut (a) = value;
|
*self.reg_mut (a) = value;
|
||||||
|
@ -666,7 +573,7 @@ impl State {
|
||||||
Value::Integer (_) => 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::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::RsFunc (_) => Err (make_step_error ("attempt to get length of a function value"))?,
|
||||||
Value::String (s) => self.si.get (*s).len ().into (),
|
Value::String (s) => s.len ().into (),
|
||||||
Value::Table (t) => t.borrow ().length ().into (),
|
Value::Table (t) => t.borrow ().length ().into (),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -692,8 +599,16 @@ impl State {
|
||||||
Instruction::LoadTrue (a) => {
|
Instruction::LoadTrue (a) => {
|
||||||
*self.reg_mut (a) = true.into ();
|
*self.reg_mut (a) = true.into ();
|
||||||
},
|
},
|
||||||
Instruction::MmBin (a, b, c) => {
|
Instruction::MmBin (a, b, _c) => {
|
||||||
self.op_mmbin (a, b, c);
|
let a = self.reg (a);
|
||||||
|
let b = self.reg (b);
|
||||||
|
|
||||||
|
if a.as_float().is_some() && b.as_float().is_some () {
|
||||||
|
// No need for metamethods
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
panic! ("Not sure how to implememtn OP_MMBIN for these 2 values {a:?}, {b:?}");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Instruction::MmBinI (_a, _s_b, _c, _k) => {
|
Instruction::MmBinI (_a, _s_b, _c, _k) => {
|
||||||
// Ignore
|
// Ignore
|
||||||
|
@ -714,12 +629,20 @@ impl State {
|
||||||
*self.reg_mut (a) = self.reg (b).clone ();
|
*self.reg_mut (a) = self.reg (b).clone ();
|
||||||
},
|
},
|
||||||
Instruction::Mul (a, b, c) => {
|
Instruction::Mul (a, b, c) => {
|
||||||
// If we handled the mul as a regular int or float,
|
let v_b = self.reg (b);
|
||||||
// skip the OP_MMBIN that probably comes after this
|
let v_c = self.reg (c);
|
||||||
|
|
||||||
if self.op_mul (a, b, c) {
|
let x = if let (Some (v_b), Some (v_c)) = (v_b.as_int (), v_c.as_int ())
|
||||||
next_pc += 1;
|
{
|
||||||
|
Value::from (v_b * v_c)
|
||||||
}
|
}
|
||||||
|
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}"));
|
||||||
|
Value::from (v_b * v_c)
|
||||||
|
};
|
||||||
|
|
||||||
|
*self.reg_mut (a) = x;
|
||||||
},
|
},
|
||||||
Instruction::MulK (a, b, c) => {
|
Instruction::MulK (a, b, c) => {
|
||||||
let v_b = self.reg (b);
|
let v_b = self.reg (b);
|
||||||
|
@ -831,7 +754,25 @@ impl State {
|
||||||
self.top = popped_frame.register_offset - 1 + 1;
|
self.top = popped_frame.register_offset - 1 + 1;
|
||||||
},
|
},
|
||||||
Instruction::SetField (a, b, c, k_flag) => {
|
Instruction::SetField (a, b, c, k_flag) => {
|
||||||
self.op_set_field (a, b, c, k_flag);
|
let value = if k_flag {
|
||||||
|
&k [usize::from (c)]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.reg (c)
|
||||||
|
}
|
||||||
|
.clone ();
|
||||||
|
|
||||||
|
let b = usize::try_from (b).unwrap ();
|
||||||
|
|
||||||
|
let key = match k.get (b).unwrap () {
|
||||||
|
Value::String (s) => s.as_ref (),
|
||||||
|
_ => panic! ("SetField only supports string keys"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut dst = self.reg (a).as_table ()
|
||||||
|
.expect ("SetField only works on tables").borrow_mut ();
|
||||||
|
|
||||||
|
dst.insert_str (key.as_str (), value);
|
||||||
},
|
},
|
||||||
Instruction::SetI (a, b, c, k_flag) => {
|
Instruction::SetI (a, b, c, k_flag) => {
|
||||||
let value = if k_flag {
|
let value = if k_flag {
|
||||||
|
@ -1005,7 +946,7 @@ impl State {
|
||||||
pub fn eval (&mut self, src: &str) -> Result <Vec <Value>, crate::Error>
|
pub fn eval (&mut self, src: &str) -> Result <Vec <Value>, crate::Error>
|
||||||
{
|
{
|
||||||
let bytecode = crate::compile_bytecode (src.as_bytes ().to_vec ())?;
|
let bytecode = crate::compile_bytecode (src.as_bytes ().to_vec ())?;
|
||||||
let chunk = crate::parse_chunk (&bytecode, &mut self.si).unwrap ();
|
let chunk = crate::parse_chunk (&bytecode).unwrap ();
|
||||||
|
|
||||||
self.set_chunk (chunk);
|
self.set_chunk (chunk);
|
||||||
Ok (self.execute ()?)
|
Ok (self.execute ()?)
|
||||||
|
@ -1030,8 +971,4 @@ impl State {
|
||||||
self.stack = vec! [Default::default ()];
|
self.stack = vec! [Default::default ()];
|
||||||
self.chunk = chunk;
|
self.chunk = chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_string (&mut self, s: &str) -> Value {
|
|
||||||
Value::String (self.si.intern (s))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
use std::collections::BTreeMap;
|
|
||||||
|
|
||||||
use crate::value::Value;
|
|
||||||
|
|
||||||
#[derive (Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
|
||||||
pub struct InternedString (i64);
|
|
||||||
|
|
||||||
#[derive (Debug, Default)]
|
|
||||||
pub struct Interner {
|
|
||||||
table_fwd: BTreeMap <String, i64>,
|
|
||||||
table_rev: BTreeMap <i64, String>,
|
|
||||||
counter: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Interner {
|
|
||||||
pub fn get (&self, s: InternedString) -> &str {
|
|
||||||
self.table_rev.get (&s.0).unwrap ()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn intern (&mut self, s: &str) -> InternedString {
|
|
||||||
match self.table_fwd.get (s) {
|
|
||||||
Some (x) => InternedString (*x),
|
|
||||||
None => {
|
|
||||||
self.counter += 1;
|
|
||||||
if self.counter == i64::MAX {
|
|
||||||
panic! ("Out of IDs");
|
|
||||||
}
|
|
||||||
self.table_fwd.insert (s.to_string (), self.counter);
|
|
||||||
self.table_rev.insert (self.counter, s.to_string ());
|
|
||||||
InternedString (self.counter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_value (&mut self, s: &str) -> Value {
|
|
||||||
Value::from (self.intern (s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg (test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test () {
|
|
||||||
let mut interner = Interner::default ();
|
|
||||||
|
|
||||||
assert_eq! (interner.intern ("x").0, 1);
|
|
||||||
assert_eq! (interner.intern ("x").0, 1);
|
|
||||||
assert_eq! (interner.intern ("y").0, 2);
|
|
||||||
assert_eq! (interner.intern ("z").0, 3);
|
|
||||||
assert_eq! (interner.intern ("y").0, 2);
|
|
||||||
|
|
||||||
assert_eq! (interner.intern ("asdf").0, 4);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,7 +8,6 @@ use crate::{
|
||||||
Chunk,
|
Chunk,
|
||||||
State,
|
State,
|
||||||
},
|
},
|
||||||
string_interner::Interner,
|
|
||||||
value::Value,
|
value::Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,18 +22,18 @@ fn calculate_hash<T: Hash>(t: &T) -> u64 {
|
||||||
/// Takes arguments and a parsed Lua chunk, runs its,
|
/// Takes arguments and a parsed Lua chunk, runs its,
|
||||||
/// and returns the output
|
/// and returns the output
|
||||||
|
|
||||||
fn run_chunk (vm: &mut State, args: &[&str], chunk: Chunk) -> Vec <Value> {
|
fn run_chunk (args: &[&str], chunk: Chunk) -> Vec <Value> {
|
||||||
vm.upvalues = State::upvalues_from_args(&mut vm.si, args.into_iter ().map (|s| s.to_string ()));
|
let upvalues = State::upvalues_from_args (args.into_iter ().map (|s| s.to_string ()));
|
||||||
vm.set_chunk (chunk);
|
let mut vm = State::new (chunk, upvalues);
|
||||||
vm.execute ().unwrap ()
|
vm.execute ().unwrap ()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes arguments and Lua bytecode, loads it, runs it,
|
/// Takes arguments and Lua bytecode, loads it, runs it,
|
||||||
/// and return the output
|
/// and return the output
|
||||||
|
|
||||||
fn run_bytecode (vm: &mut State, args: &[&str], bc: &[u8]) -> Vec <Value> {
|
fn run_bytecode (args: &[&str], bc: &[u8]) -> Vec <Value> {
|
||||||
let chunk = loader::parse_chunk (&bc, &mut vm.si).unwrap ();
|
let chunk = loader::parse_chunk (&bc).unwrap ();
|
||||||
run_chunk (vm, args, chunk)
|
run_chunk (args, chunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes arguments and Lua source code,
|
/// Takes arguments and Lua source code,
|
||||||
|
@ -42,9 +41,9 @@ fn run_bytecode (vm: &mut State, args: &[&str], bc: &[u8]) -> Vec <Value> {
|
||||||
/// runs it,
|
/// runs it,
|
||||||
/// and returns the output
|
/// and returns the output
|
||||||
|
|
||||||
fn run_source (vm: &mut State, args: &[&str], s: &str) -> Vec <Value> {
|
fn run_source (args: &[&str], s: &str) -> Vec <Value> {
|
||||||
let bc = loader::compile_bytecode (s.as_bytes ().to_vec ()).unwrap ();
|
let bc = loader::compile_bytecode (s.as_bytes ().to_vec ()).unwrap ();
|
||||||
run_bytecode (vm, args, &bc)
|
run_bytecode (args, &bc)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -63,8 +62,6 @@ fn bools () {
|
||||||
return x
|
return x
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let mut si = Interner::default ();
|
|
||||||
|
|
||||||
let chunk = Chunk {
|
let chunk = Chunk {
|
||||||
blocks: vec! [
|
blocks: vec! [
|
||||||
Block {
|
Block {
|
||||||
|
@ -93,8 +90,8 @@ fn bools () {
|
||||||
Inst::Return (2, 1, 1, false),
|
Inst::Return (2, 1, 1, false),
|
||||||
],
|
],
|
||||||
constants: vec! [
|
constants: vec! [
|
||||||
si.to_value ("arg"),
|
"arg".into (),
|
||||||
si.to_value ("print"),
|
"print".into (),
|
||||||
],
|
],
|
||||||
upvalues: vec! [],
|
upvalues: vec! [],
|
||||||
},
|
},
|
||||||
|
@ -115,15 +112,15 @@ fn bools () {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut vm = crate::State::new_with_args (Chunk::default (), si, vec! [].into_iter());
|
|
||||||
|
|
||||||
for (arg, expected) in [
|
for (arg, expected) in [
|
||||||
(vec! ["_exe_name"], vec! [98.into ()]),
|
(vec! ["_exe_name"], vec! [98.into ()]),
|
||||||
(vec! ["_exe_name", "asdf"], vec! [99.into ()]),
|
(vec! ["_exe_name", "asdf"], vec! [99.into ()]),
|
||||||
] {
|
] {
|
||||||
let expected: Vec <Value> = expected;
|
let expected: Vec <Value> = expected;
|
||||||
|
|
||||||
let actual = run_chunk (&mut vm, &arg, chunk.clone ());
|
let upvalues = State::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ()));
|
||||||
|
let mut vm = State::new (chunk.clone (), upvalues);
|
||||||
|
let actual = vm.execute ().unwrap ();
|
||||||
assert_eq! (actual, expected);
|
assert_eq! (actual, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,11 +129,9 @@ fn bools () {
|
||||||
fn closure () {
|
fn closure () {
|
||||||
let source = include_bytes! ("../test_vectors/closure.lua");
|
let source = include_bytes! ("../test_vectors/closure.lua");
|
||||||
let bytecode = &crate::loader::compile_bytecode (source.to_vec ()).unwrap ();
|
let bytecode = &crate::loader::compile_bytecode (source.to_vec ()).unwrap ();
|
||||||
let mut si = Interner::default ();
|
let chunk = crate::loader::parse_chunk (bytecode).unwrap ();
|
||||||
let chunk = crate::loader::parse_chunk (bytecode, &mut si).unwrap ();
|
|
||||||
|
|
||||||
let mut vm = crate::State::new_with_args (Chunk::default (), si, vec! [].into_iter());
|
assert_eq! (run_chunk (&["_exe_name"], chunk), vec! [Value::from (23i64)]);
|
||||||
assert_eq! (run_chunk (&mut vm, &["_exe_name"], chunk), vec! [Value::from (23i64)]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -151,8 +146,6 @@ fn floats () {
|
||||||
return x
|
return x
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let mut si = Interner::default ();
|
|
||||||
|
|
||||||
let block = Block {
|
let block = Block {
|
||||||
instructions: vec! [
|
instructions: vec! [
|
||||||
Inst::VarArgPrep (0),
|
Inst::VarArgPrep (0),
|
||||||
|
@ -168,7 +161,7 @@ fn floats () {
|
||||||
],
|
],
|
||||||
constants: vec! [
|
constants: vec! [
|
||||||
0.5.into (),
|
0.5.into (),
|
||||||
si.to_value ("print"),
|
"print".into (),
|
||||||
],
|
],
|
||||||
upvalues: vec! [],
|
upvalues: vec! [],
|
||||||
};
|
};
|
||||||
|
@ -176,14 +169,14 @@ fn floats () {
|
||||||
blocks: vec! [block],
|
blocks: vec! [block],
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut vm = crate::State::new_with_args (Chunk::default (), si, vec! [].into_iter());
|
|
||||||
|
|
||||||
for (arg, expected) in [
|
for (arg, expected) in [
|
||||||
(vec! ["_exe_name"], vec! [3.5.into ()]),
|
(vec! ["_exe_name"], vec! [3.5.into ()]),
|
||||||
(vec! ["_exe_name", " "], vec! [3.5.into ()]),
|
(vec! ["_exe_name", " "], vec! [3.5.into ()]),
|
||||||
] {
|
] {
|
||||||
let expected: Vec <Value> = expected;
|
let expected: Vec <Value> = expected;
|
||||||
let actual = run_chunk (&mut vm, &arg, chunk.clone ());
|
let upvalues = State::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ()));
|
||||||
|
let mut vm = State::new (chunk.clone (), upvalues);
|
||||||
|
let actual = vm.execute ().unwrap ();
|
||||||
|
|
||||||
assert_eq! (actual, expected);
|
assert_eq! (actual, expected);
|
||||||
}
|
}
|
||||||
|
@ -192,15 +185,15 @@ fn floats () {
|
||||||
#[test]
|
#[test]
|
||||||
fn fma () {
|
fn fma () {
|
||||||
let source = include_bytes! ("../test_vectors/fma.lua");
|
let source = include_bytes! ("../test_vectors/fma.lua");
|
||||||
let mut si = Interner::default ();
|
|
||||||
let bytecode = &crate::loader::compile_bytecode (source.to_vec ()).unwrap ();
|
let bytecode = &crate::loader::compile_bytecode (source.to_vec ()).unwrap ();
|
||||||
let chunk = crate::loader::parse_chunk (bytecode, &mut si).unwrap ();
|
let chunk = crate::loader::parse_chunk (bytecode).unwrap ();
|
||||||
assert_eq! (chunk.blocks.len (), 5);
|
assert_eq! (chunk.blocks.len (), 5);
|
||||||
|
|
||||||
assert_eq! (chunk.blocks [3].upvalues.len (), 2);
|
assert_eq! (chunk.blocks [3].upvalues.len (), 2);
|
||||||
|
|
||||||
|
let arg = vec! ["_exe_name"];
|
||||||
let mut vm = crate::State::new_with_args (chunk, si, vec! ["_exe_name".to_string ()].into_iter ());
|
let upvalues = State::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ()));
|
||||||
|
let mut vm = State::new (chunk, upvalues);
|
||||||
let actual = vm.execute ().unwrap ();
|
let actual = vm.execute ().unwrap ();
|
||||||
let expected = vec! [Value::from (122)];
|
let expected = vec! [Value::from (122)];
|
||||||
|
|
||||||
|
@ -209,8 +202,9 @@ fn fma () {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn function_calls () {
|
fn function_calls () {
|
||||||
let si = Interner::default ();
|
let upvalues = crate::State::upvalues_from_args (vec! ["_exe_name".to_string ()].into_iter ());
|
||||||
let mut vm = crate::State::new_with_args (crate::Chunk::default (), si, vec! ["_exe_name".to_string ()].into_iter ());
|
|
||||||
|
let mut vm = crate::State::new (crate::Chunk::default (), upvalues);
|
||||||
|
|
||||||
vm.eval ("print (x ())").ok ();
|
vm.eval ("print (x ())").ok ();
|
||||||
vm.eval ("x = function () return 5 end").ok ();
|
vm.eval ("x = function () return 5 end").ok ();
|
||||||
|
@ -222,8 +216,9 @@ fn function_calls () {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn function_returns () {
|
fn function_returns () {
|
||||||
let si = Interner::default ();
|
let upvalues = crate::State::upvalues_from_args (vec! ["_exe_name".to_string ()].into_iter ());
|
||||||
let mut vm = crate::State::new_with_args (crate::Chunk::default (), si, vec! ["_exe_name".to_string ()].into_iter ());
|
|
||||||
|
let mut vm = crate::State::new (crate::Chunk::default (), upvalues);
|
||||||
|
|
||||||
assert_eq! (
|
assert_eq! (
|
||||||
vm.eval ("return ((function () return 5 end)())").unwrap (),
|
vm.eval ("return ((function () return 5 end)())").unwrap (),
|
||||||
|
@ -246,8 +241,6 @@ fn heap () {
|
||||||
};
|
};
|
||||||
use crate::value::Table;
|
use crate::value::Table;
|
||||||
|
|
||||||
let mut si = Interner::default ();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut allocations = HashMap::new ();
|
let mut allocations = HashMap::new ();
|
||||||
let mut ctr = 0;
|
let mut ctr = 0;
|
||||||
|
@ -262,7 +255,7 @@ fn heap () {
|
||||||
|
|
||||||
allocations.get_mut (&a).unwrap ().insert (1, c);
|
allocations.get_mut (&a).unwrap ().insert (1, c);
|
||||||
|
|
||||||
allocations.get_mut (&c).unwrap ().insert (2, si.to_value ("eee"));
|
allocations.get_mut (&c).unwrap ().insert (2, "eee");
|
||||||
}
|
}
|
||||||
|
|
||||||
if true {
|
if true {
|
||||||
|
@ -299,12 +292,10 @@ fn heap () {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn is_93 () {
|
fn is_93 () {
|
||||||
let mut si = Interner::default ();
|
assert_eq! (Value::from ("93"), Value::from ("93"));
|
||||||
|
assert_ne! (Value::from ("94"), Value::from ("93"));
|
||||||
assert_eq! (si.to_value ("93"), si.to_value ("93"));
|
assert_ne! (calculate_hash (&Value::from ("94")), calculate_hash (&Value::from ("93")));
|
||||||
assert_ne! (si.to_value ("94"), si.to_value ("93"));
|
assert_ne! (Value::Nil, Value::from ("93"));
|
||||||
assert_ne! (calculate_hash (&si.to_value ("94")), calculate_hash (&si.to_value ("93")));
|
|
||||||
assert_ne! (Value::Nil, si.to_value ("93"));
|
|
||||||
|
|
||||||
let src = br#"
|
let src = br#"
|
||||||
if arg [1] == "93" then
|
if arg [1] == "93" then
|
||||||
|
@ -317,17 +308,15 @@ fn is_93 () {
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let bc = loader::compile_bytecode (src.to_vec ()).unwrap ();
|
let bc = loader::compile_bytecode (src.to_vec ()).unwrap ();
|
||||||
let chunk = loader::parse_chunk (&bc, &mut si).unwrap ();
|
let chunk = loader::parse_chunk (&bc).unwrap ();
|
||||||
|
|
||||||
assert_eq! (chunk.blocks [0].instructions [3], Inst::EqK (0, 1, false));
|
assert_eq! (chunk.blocks [0].instructions [3], Inst::EqK (0, 1, false));
|
||||||
|
|
||||||
let mut vm = crate::State::new_with_args (Chunk::default (), si, vec! [].into_iter());
|
|
||||||
|
|
||||||
let run = run_chunk;
|
let run = run_chunk;
|
||||||
|
|
||||||
assert_eq! (run (&mut vm, &[""], chunk.clone ()), vec! [Value::from (1)]);
|
assert_eq! (run (&[""], chunk.clone ()), vec! [Value::from (1)]);
|
||||||
assert_eq! (run (&mut vm, &["", "93"], chunk.clone ()), vec! [Value::from (0)]);
|
assert_eq! (run (&["", "93"], chunk.clone ()), vec! [Value::from (0)]);
|
||||||
assert_eq! (run (&mut vm, &["", "94"], chunk.clone ()), vec! [Value::from (1)]);
|
assert_eq! (run (&["", "94"], chunk.clone ()), vec! [Value::from (1)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -380,9 +369,7 @@ fn tables_1 () {
|
||||||
print (t ["t"][1])
|
print (t ["t"][1])
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let si = Interner::default ();
|
run_source (&[], src);
|
||||||
let mut vm = crate::State::new_with_args (Chunk::default (), si, vec! [].into_iter());
|
|
||||||
run_source (&mut vm, &[], src);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -397,29 +384,23 @@ fn tables_2 () {
|
||||||
print (a [2])
|
print (a [2])
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let si = Interner::default ();
|
run_source (&[], src);
|
||||||
let mut vm = crate::State::new_with_args (Chunk::default (), si, vec! [].into_iter());
|
|
||||||
run_source (&mut vm, &[], src);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tailcall () {
|
fn tailcall () {
|
||||||
use crate::instruction::Instruction;
|
use crate::instruction::Instruction;
|
||||||
|
|
||||||
let mut si = Interner::default ();
|
|
||||||
|
|
||||||
let src = br#"
|
let src = br#"
|
||||||
return tonumber ("5")
|
return tonumber ("5")
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let bc = loader::compile_bytecode (src.to_vec ()).unwrap ();
|
let bc = loader::compile_bytecode (src.to_vec ()).unwrap ();
|
||||||
let chunk = loader::parse_chunk (&bc, &mut si).unwrap ();
|
let chunk = loader::parse_chunk (&bc).unwrap ();
|
||||||
|
|
||||||
assert_eq! (chunk.blocks [0].instructions [3], Instruction::TailCall (0, 2, 1, false));
|
assert_eq! (chunk.blocks [0].instructions [3], Instruction::TailCall (0, 2, 1, false));
|
||||||
|
|
||||||
let mut vm = crate::State::new_with_args (Chunk::default (), si, vec! [].into_iter());
|
let actual = run_chunk (&[], chunk);
|
||||||
|
|
||||||
let actual = run_chunk (&mut vm, &[], chunk);
|
|
||||||
let expected = vec! [Value::from (5)];
|
let expected = vec! [Value::from (5)];
|
||||||
|
|
||||||
assert_eq! (actual, expected);
|
assert_eq! (actual, expected);
|
||||||
|
|
|
@ -4,16 +4,11 @@ use std::{
|
||||||
Eq,
|
Eq,
|
||||||
PartialEq,
|
PartialEq,
|
||||||
},
|
},
|
||||||
collections::{BTreeMap, HashMap},
|
collections::HashMap,
|
||||||
fmt,
|
fmt,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::string_interner::{
|
|
||||||
Interner,
|
|
||||||
InternedString,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive (Debug, Eq, PartialEq)]
|
#[derive (Debug, Eq, PartialEq)]
|
||||||
pub struct BogusClosure {
|
pub struct BogusClosure {
|
||||||
// I'm pretty sure this should be absolute?
|
// I'm pretty sure this should be absolute?
|
||||||
|
@ -32,7 +27,7 @@ pub enum Value {
|
||||||
|
|
||||||
Integer (i64),
|
Integer (i64),
|
||||||
RsFunc (fn (&mut crate::state::State, usize) -> usize),
|
RsFunc (fn (&mut crate::state::State, usize) -> usize),
|
||||||
String (InternedString),
|
String (Rc <String>),
|
||||||
Table (Rc <RefCell <Table>>),
|
Table (Rc <RefCell <Table>>),
|
||||||
|
|
||||||
// These are all bogus, I haven't figured out how to implement
|
// These are all bogus, I haven't figured out how to implement
|
||||||
|
@ -52,7 +47,7 @@ impl fmt::Debug for Value {
|
||||||
Value::Float (x) => write! (f, "{:?}", x),
|
Value::Float (x) => write! (f, "{:?}", x),
|
||||||
Value::Integer (x) => write! (f, "{}", x),
|
Value::Integer (x) => write! (f, "{}", x),
|
||||||
Value::RsFunc (x) => write! (f, "function: {:?}", x),
|
Value::RsFunc (x) => write! (f, "function: {:?}", x),
|
||||||
Value::String (s) => write! (f, "unimplemented Debug",),
|
Value::String (s) => write! (f, "\"{}\"", s),
|
||||||
Value::Table (t) => write! (f, "{:?}", t.borrow ()),
|
Value::Table (t) => write! (f, "{:?}", t.borrow ()),
|
||||||
|
|
||||||
Value::BogusClosure (x) => write! (f, "{:?}", x.borrow ()),
|
Value::BogusClosure (x) => write! (f, "{:?}", x.borrow ()),
|
||||||
|
@ -75,7 +70,7 @@ impl fmt::Display for Value {
|
||||||
Value::Float (x) => write! (f, "{:?}", x),
|
Value::Float (x) => write! (f, "{:?}", x),
|
||||||
Value::Integer (x) => write! (f, "{}", x),
|
Value::Integer (x) => write! (f, "{}", x),
|
||||||
Value::RsFunc (x) => write! (f, "function: {:?}", x),
|
Value::RsFunc (x) => write! (f, "function: {:?}", x),
|
||||||
Value::String (s) => write! (f, "unimplemented Display"),
|
Value::String (s) => write! (f, "{}", s),
|
||||||
Value::Table (t) => write! (f, "table: {:?}", std::rc::Rc::as_ptr (t)),
|
Value::Table (t) => write! (f, "table: {:?}", std::rc::Rc::as_ptr (t)),
|
||||||
|
|
||||||
Value::BogusClosure (x) => write! (f, "BogusClosure: {:?}", std::rc::Rc::as_ptr (x)),
|
Value::BogusClosure (x) => write! (f, "BogusClosure: {:?}", std::rc::Rc::as_ptr (x)),
|
||||||
|
@ -95,6 +90,18 @@ impl From <bool> for Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From <String> for Value {
|
||||||
|
fn from (x: String) -> Self {
|
||||||
|
Self::String (x.into ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From <&str> for Value {
|
||||||
|
fn from (x: &str) -> Self {
|
||||||
|
Self::from (String::from (x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From <i32> for Value {
|
impl From <i32> for Value {
|
||||||
fn from (x: i32) -> Self {
|
fn from (x: i32) -> Self {
|
||||||
Self::Integer (i64::from (x))
|
Self::Integer (i64::from (x))
|
||||||
|
@ -119,12 +126,6 @@ impl From <usize> for Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From <InternedString> for Value {
|
|
||||||
fn from (x: InternedString) -> Self {
|
|
||||||
Self::String (x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From <Table> for Value {
|
impl From <Table> for Value {
|
||||||
fn from (x: Table) -> Self {
|
fn from (x: Table) -> Self {
|
||||||
Self::Table (Rc::new (RefCell::new (x)))
|
Self::Table (Rc::new (RefCell::new (x)))
|
||||||
|
@ -138,9 +139,9 @@ impl FromIterator <(Value, Value)> for Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromIterator <(InternedString, Value)> for Value {
|
impl FromIterator <(String, Value)> for Value {
|
||||||
fn from_iter <I: IntoIterator <Item=(InternedString, Value)>> (i: I) -> Self {
|
fn from_iter <I: IntoIterator <Item=(String, Value)>> (i: I) -> Self {
|
||||||
Self::from_iter (i.into_iter ().map (|(s, v)| (Value::String (s), v)))
|
Self::from_iter (i.into_iter ().map (|(s, v)| (Value::from (s), v)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,9 +209,9 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_str (&self) -> Option <InternedString> {
|
pub fn as_str (&self) -> Option <&str> {
|
||||||
match self {
|
match self {
|
||||||
Self::String (x) => Some (*x),
|
Self::String (x) => Some (x.as_str ()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,10 +223,6 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_str (si: &mut Interner, s: &str) -> Value {
|
|
||||||
Value::String (si.intern (s))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_truthy (&self) -> bool {
|
pub fn is_truthy (&self) -> bool {
|
||||||
// And this is something Lua does better than JS and Python.
|
// And this is something Lua does better than JS and Python.
|
||||||
|
|
||||||
|
@ -247,40 +244,55 @@ impl Value {
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
array: Vec <Value>,
|
array: Vec <Value>,
|
||||||
hash: HashMap <Value, Value>,
|
hash: HashMap <Value, Value>,
|
||||||
map: BTreeMap <InternedString, Value>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Table {
|
impl fmt::Debug for Table {
|
||||||
fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write! (f, "Table {:#?}", self.map)?;
|
write! (f, "Table {:#?}", self.hash)?;
|
||||||
|
|
||||||
Ok (())
|
Ok (())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Table {
|
impl Table {
|
||||||
fn get_inner (&self, key: &Value) -> &Value {
|
fn get_inner (&self, key: &Value) -> Value {
|
||||||
match key {
|
// self.hash.get (key).cloned ().unwrap_or_default ()
|
||||||
Value::Nil => &NIL,
|
for (hay, value) in &self.hash {
|
||||||
Value::String (x) => self.map.get (x).unwrap_or (&NIL),
|
if key == hay {
|
||||||
Value::Integer (x) => self.array.get (usize::try_from (*x).unwrap ()).unwrap_or (&NIL),
|
return value.clone ();
|
||||||
x => self.hash.get (x).unwrap_or (&NIL),
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value::Nil
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get <A: Into <Value>> (&self, key: A) -> &Value {
|
pub fn get <A: Into <Value>> (&self, key: A) -> Value {
|
||||||
self.get_inner (&(key.into ()))
|
self.get_inner (&(key.into ()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_int (&self, key: i64) -> &Value {
|
pub fn get_int (&self, key: i64) -> Value {
|
||||||
self.array.get (usize::try_from (key).unwrap ()).unwrap_or (&NIL)
|
self.get_inner (&(key.into ()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_str (&self, key: InternedString) -> &Value {
|
pub fn get_str (&self, key: &str) -> &Value {
|
||||||
match self.map.get (&key) {
|
for (hay, value) in &self.hash {
|
||||||
None => &NIL,
|
if Some (key) == hay.as_str () {
|
||||||
Some (x) => x,
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&NIL
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_inner (&mut self, a: Value, b: Value) {
|
||||||
|
for (hay, value) in &mut self.hash {
|
||||||
|
if &a == hay {
|
||||||
|
*value = b;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.hash.insert (a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert value at arbitrary key
|
/// Insert value at arbitrary key
|
||||||
|
@ -290,34 +302,30 @@ impl Table {
|
||||||
a: A,
|
a: A,
|
||||||
b: B,
|
b: B,
|
||||||
) {
|
) {
|
||||||
match a.into () {
|
self.insert_inner (a.into (), b.into ())
|
||||||
Value::Integer (x) => self.insert_int (x, b),
|
|
||||||
Value::Nil => (),
|
|
||||||
Value::String (x) => {
|
|
||||||
self.map.insert (x, b.into ());
|
|
||||||
},
|
|
||||||
x => {
|
|
||||||
self.hash.insert (x, b.into ());
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert value at integer key
|
/// Insert value at integer key
|
||||||
|
|
||||||
pub fn insert_int <A: Into <Value>> (&mut self, k: i64, v: A)
|
pub fn insert_int <A: Into <Value>> (&mut self, k: i64, v: A)
|
||||||
{
|
{
|
||||||
let k = usize::try_from (k).unwrap ();
|
self.insert_inner (k.into (), v.into ())
|
||||||
self.array.resize (k + 1, NIL);
|
|
||||||
self.array [k] = v.into ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_str (&mut self, key: InternedString, v: Value) {
|
pub fn insert_str (&mut self, key: &str, v: Value) {
|
||||||
self.map.insert (key, v);
|
for (hay, value) in &mut self.hash {
|
||||||
|
if Some (key) == hay.as_str () {
|
||||||
|
*value = v;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.hash.insert (key.into (), v);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn length (&self) -> i64 {
|
pub fn length (&self) -> i64 {
|
||||||
for i in 1..i64::MAX {
|
for i in 1..i64::MAX {
|
||||||
if self.get (i) == &NIL {
|
if self.get (i) == Value::Nil {
|
||||||
return i - 1;
|
return i - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,18 +336,21 @@ impl Table {
|
||||||
impl FromIterator <(Value, Value)> for Table {
|
impl FromIterator <(Value, Value)> for Table {
|
||||||
fn from_iter<I: IntoIterator<Item = (Value, Value)>> (i: I) -> Self
|
fn from_iter<I: IntoIterator<Item = (Value, Value)>> (i: I) -> Self
|
||||||
{
|
{
|
||||||
let mut that = Self::default ();
|
let hash = i.into_iter ().collect ();
|
||||||
for (k, v) in i.into_iter () {
|
Self {
|
||||||
that.insert (k, v);
|
array: Default::default (),
|
||||||
|
hash,
|
||||||
}
|
}
|
||||||
that
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg (test)]
|
#[cfg (test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use super::*;
|
use super::{
|
||||||
|
Table,
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn smoke () {
|
fn smoke () {
|
||||||
|
@ -353,26 +364,25 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn tables () {
|
fn tables () {
|
||||||
let nil = Value::Nil;
|
let nil = Value::Nil;
|
||||||
let mut si = Interner::default ();
|
|
||||||
|
|
||||||
assert_ne! (Value::from (18.0), Value::from (19.0));
|
assert_ne! (Value::from (18.0), Value::from (19.0));
|
||||||
|
|
||||||
let mut t = HashMap::new ();
|
let mut t = HashMap::new ();
|
||||||
t.insert (Value::from_str (&mut si, "x"), Value::from (19.0));
|
t.insert (Value::from ("x"), Value::from (19.0));
|
||||||
assert_eq! (t.get (&Value::from_str (&mut si, "x")), Some (&Value::from (19.0)));
|
assert_eq! (t.get (&Value::from ("x")), Some (&Value::from (19.0)));
|
||||||
|
|
||||||
let mut t = Table::default ();
|
let mut t = Table::default ();
|
||||||
|
|
||||||
assert_eq! (t.get (si.intern ("a")), &nil);
|
assert_eq! (t.get ("a"), nil);
|
||||||
assert_eq! (t.get (si.intern ("b")), &nil);
|
assert_eq! (t.get ("b"), nil);
|
||||||
|
|
||||||
t.insert (si.to_value ("a"), 1993);
|
t.insert ("a", 1993);
|
||||||
t.insert (si.to_value ("b"), 2007);
|
t.insert ("b", 2007);
|
||||||
|
|
||||||
assert_eq! (t.get (si.intern ("a")), &Value::from (1993));
|
assert_eq! (t.get ("a"), 1993);
|
||||||
assert_eq! (t.get (si.intern ("b")), &Value::from (2007));
|
assert_eq! (t.get ("b"), 2007);
|
||||||
|
|
||||||
t.insert (19, 93);
|
t.insert (19, 93);
|
||||||
assert_eq! (t.get (19), &Value::from (93));
|
assert_eq! (t.get (19), 93);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,18 +19,16 @@ fn embedding () {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut si = lwvm::Interner::default ();
|
|
||||||
|
|
||||||
let bc = lwvm::compile_bytecode (src.to_vec ()).unwrap ();
|
let bc = lwvm::compile_bytecode (src.to_vec ()).unwrap ();
|
||||||
let chunk = lwvm::parse_chunk (&bc, &mut si).unwrap ();
|
let chunk = lwvm::parse_chunk (&bc).unwrap ();
|
||||||
|
|
||||||
let host_lib = [
|
let host_lib = [
|
||||||
("add", Value::RsFunc (host_add)),
|
("add", Value::RsFunc (host_add)),
|
||||||
].into_iter ().map (|(k, v)| (si.intern (k), v));
|
].into_iter ().map (|(k, v)| (k.to_string (), v));
|
||||||
|
|
||||||
let env = [
|
let env = [
|
||||||
("host_lib", Value::from_iter (host_lib.into_iter ())),
|
("host_lib", Value::from_iter (host_lib.into_iter ())),
|
||||||
].into_iter ().map (|(k, v)| (si.intern (k), v));
|
].into_iter ().map (|(k, v)| (k.to_string (), v));
|
||||||
|
|
||||||
let upvalues = vec! [
|
let upvalues = vec! [
|
||||||
Value::from_iter (env.into_iter ()),
|
Value::from_iter (env.into_iter ()),
|
||||||
|
|
Loading…
Reference in New Issue