@@ 301,13 301,13 @@ macro_rules! push_codegen {
#[macro_export]
macro_rules! vm_boolean_equality {
($self:expr, $oper:tt) => {
- match ($self.stacks[$self.stack_ptr].pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))),
- $self.stacks[$self.stack_ptr].pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) {
- (Num(v1), Num(v2)) => $self.stacks[$self.stack_ptr].push(Bool(v1 $oper v2)),
- (Str(v1), Str(v2)) => $self.stacks[$self.stack_ptr].push(Bool(v1 $oper v2)),
- (Bool(v1), Bool(v2)) => $self.stacks[$self.stack_ptr].push(Bool(v1 $oper v2)),
- (Null, Null) => $self.stacks[$self.stack_ptr].push(Bool(true)),
- (_v1, _v2) => $self.stacks[$self.stack_ptr].push(Bool(false)),
+ match ($self.stack.pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))),
+ $self.stack.pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) {
+ (Num(v1), Num(v2)) => $self.stack.push(Bool(v1 $oper v2)),
+ (Str(v1), Str(v2)) => $self.stack.push(Bool(v1 $oper v2)),
+ (Bool(v1), Bool(v2)) => $self.stack.push(Bool(v1 $oper v2)),
+ (Null, Null) => $self.stack.push(Bool(true)),
+ (_v1, _v2) => $self.stack.push(Bool(false)),
}
};
}
@@ 315,14 315,14 @@ macro_rules! vm_boolean_equality {
#[macro_export]
macro_rules! vm_boolean_comparison {
($self:expr, $oper:tt) => {
- match ($self.stacks[$self.stack_ptr].pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))),
- $self.stacks[$self.stack_ptr].pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) {
- (Num(v1), Num(v2)) => $self.stacks[$self.stack_ptr].push(Bool(v1 $oper v2)),
- (Str(v1), Str(v2)) => $self.stacks[$self.stack_ptr].push(Bool(v1 $oper v2)),
- (Bool(v1), Bool(v2)) => $self.stacks[$self.stack_ptr].push(Bool(v1 $oper v2)),
+ match ($self.stack.pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))),
+ $self.stack.pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) {
+ (Num(v1), Num(v2)) => $self.stack.push(Bool(v1 $oper v2)),
+ (Str(v1), Str(v2)) => $self.stack.push(Bool(v1 $oper v2)),
+ (Bool(v1), Bool(v2)) => $self.stack.push(Bool(v1 $oper v2)),
(Null, _) => return Err(vm_error!($self, RuntimeErrorKind::WrongType, "Tried to perform comparison \"{}\" on value null", stringify!($tt))),
(_, Null) => return Err(vm_error!($self, RuntimeErrorKind::WrongType, "Tried to perform comparison \"{}\" on value null", stringify!($tt))),
- (_v1, _v2) => $self.stacks[$self.stack_ptr].push(Bool(false)),
+ (_v1, _v2) => $self.stack.push(Bool(false)),
}
};
}
@@ 30,9 30,10 @@ pub struct VM {
pub ip: usize,
pub unit_ptr: usize,
pub stack_ptr: usize,
- pub call_stack: Vec<(usize, usize)>, // (unit_ptr, ip)
+ pub call_stack: Vec<(usize, usize, usize)>, // (unit_ptr, ip, stack_offset)
pub units: Vec<Unit>,
- pub stacks: Vec<Vec<Value>>,
+ pub stack: Vec<Value>,
+ pub stack_offset: usize,
text: Vec<String>
}
@@ 43,9 44,10 @@ impl VM {
ip: 0,
unit_ptr: 0,
stack_ptr: 0,
- call_stack: Vec::new(),
+ call_stack: vec![(0, 0, 0)],
units: vec![Unit::new(bytecode, pool, lines)],
- stacks: vec![Vec::new()],
+ stack: Vec::new(),
+ stack_offset: 0,
text: text.lines().map(|s| s.to_string()).collect::<Vec<String>>(),
}
}
@@ 56,25 58,28 @@ impl VM {
0x00 => { // LOAD
let byte = self.read() as usize;
let value = self.units[self.unit_ptr].pool[byte].clone();
- self.stacks[self.stack_ptr].push(value);
+ self.stack.push(value);
}
0x01 => { // VAR
let ptr = self.read() as usize;
- let value = self.stacks[self.stack_ptr][ptr].clone();
- self.stacks[self.stack_ptr].push(value);
+ let value = self.stack[ptr+self.stack_offset].clone();
+ //println!("offset {} ptr {}", offset, ptr);
+ //println!("stack {:?}", self.stack);
+ self.stack.push(value);
}
// ASSIGN
0x02 => {
- let value = self.stacks[self.stack_ptr].pop().unwrap();
+ let value = self.stack.pop().unwrap();
let ptr = self.read();
- self.stacks[self.stack_ptr][ptr as usize] = value.clone();
- self.stacks[self.stack_ptr].push(value);
+ let offset = self.call_stack.last().expect("var call stack last").2;
+ self.stack[ptr as usize + offset] = value.clone();
+ self.stack.push(value);
}
0x03 => { // ADD
- match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) {
- (Num(v1), Num(v2)) => self.stacks[self.stack_ptr].push(Num(v1 + v2)),
+ match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ (Num(v1), Num(v2)) => self.stack.push(Num(v1 + v2)),
(Str(v1), Str(v2)) => {
- self.stacks[self.stack_ptr].push(Str(v1 + &v2));
+ self.stack.push(Str(v1 + &v2));
},
(Bool(_v1), Bool(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot add booleans"))
@@ 85,8 90,8 @@ impl VM {
}
}
0x04 => { // SUB
- match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) {
- (Num(v1), Num(v2)) => self.stacks[self.stack_ptr].push(Num(v1 - v2)),
+ match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ (Num(v1), Num(v2)) => self.stack.push(Num(v1 - v2)),
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot subtract strings"))
},
@@ 99,11 104,11 @@ impl VM {
}
}
0x05 => { // MUL
- match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) {
- (Num(v1), Num(v2)) => self.stacks[self.stack_ptr].push(Num(v1 * v2)),
+ match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ (Num(v1), Num(v2)) => self.stack.push(Num(v1 * v2)),
(Str(v1), Num(v2)) => {
if v2.fract() == 0.0 {
- self.stacks[self.stack_ptr].push(Str(v1.repeat(v2 as usize)));
+ self.stack.push(Str(v1.repeat(v2 as usize)));
} else {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Number must be an integer"))
}
@@ 120,8 125,8 @@ impl VM {
}
}
0x06 => { // DIV
- match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) {
- (Num(v1), Num(v2)) => self.stacks[self.stack_ptr].push(Num(v1 / v2)),
+ match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ (Num(v1), Num(v2)) => self.stack.push(Num(v1 / v2)),
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot divide strings"))
},
@@ 134,8 139,8 @@ impl VM {
}
}
0x07 => { // MOD
- match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) {
- (Num(v1), Num(v2)) => self.stacks[self.stack_ptr].push(Num(v1 % v2)),
+ match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ (Num(v1), Num(v2)) => self.stack.push(Num(v1 % v2)),
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform modulus on strings"))
},
@@ 148,7 153,7 @@ impl VM {
}
}
0x08 => { // BITAND
- match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) {
+ match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => {
if v1.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise AND on {}", v1))
@@ 156,7 161,7 @@ impl VM {
if v2.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise AND on {}", v2))
}
- self.stacks[self.stack_ptr].push(Num((v1 as u32 & v2 as u32) as f32))
+ self.stack.push(Num((v1 as u32 & v2 as u32) as f32))
}
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise AND on strings"))
@@ 170,7 175,7 @@ impl VM {
}
}
0x09 => { // BITXOR
- match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) {
+ match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => {
if v1.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise XOR on {}", v1))
@@ 178,7 183,7 @@ impl VM {
if v2.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise XOR on {}", v2))
}
- self.stacks[self.stack_ptr].push(Num((v1 as u32 ^ v2 as u32) as f32))
+ self.stack.push(Num((v1 as u32 ^ v2 as u32) as f32))
}
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise XOR on strings"))
@@ 192,7 197,7 @@ impl VM {
}
}
0x0A => { // BITOR
- match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) {
+ match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => {
if v1.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise OR on {}", v1))
@@ 200,7 205,7 @@ impl VM {
if v2.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise OR on {}", v2))
}
- self.stacks[self.stack_ptr].push(Num((v1 as u32 | v2 as u32) as f32))
+ self.stack.push(Num((v1 as u32 | v2 as u32) as f32))
}
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise OR on strings"))
@@ 226,14 231,14 @@ impl VM {
// LE
0x10 => vm_boolean_comparison!(self, <=),
// OR
- 0x11 => match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) {
+ 0x11 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(_v1), Num(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"||\" on non-boolean numbers"))
}
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"||\" on non-boolean strings"))
},
- (Bool(v1), Bool(v2)) => self.stacks[self.stack_ptr].push(Bool(v1 || v2)),
+ (Bool(v1), Bool(v2)) => self.stack.push(Bool(v1 || v2)),
(Null, _) => return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"||\" on non-boolean value null")),
(_, Null) => return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"||\" on non-boolean value null")),
(v1, v2) => {
@@ 241,14 246,14 @@ impl VM {
}
}
// AND
- 0x12 => match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) {
+ 0x12 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(_v1), Num(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"&&\" on non-boolean numbers"))
}
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"&&\" on non-boolean strings"))
},
- (Bool(v1), Bool(v2)) => self.stacks[self.stack_ptr].push(Bool(v1 && v2)),
+ (Bool(v1), Bool(v2)) => self.stack.push(Bool(v1 && v2)),
(Null, _) => return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"&&\" on non-boolean value null")),
(_, Null) => return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"&&\" on non-boolean value null")),
(v1, v2) => {
@@ 256,7 261,7 @@ impl VM {
}
}
// NOT
- 0x13 => match self.stacks[self.stack_ptr].pop().unwrap() {
+ 0x13 => match self.stack.pop().unwrap() {
Null => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean value null")) }
Num(_v1) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean number"))
@@ 264,15 269,15 @@ impl VM {
Str(_v1) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean string"))
}
- Bool(v1) => self.stacks[self.stack_ptr].push(Bool(!v1)),
+ Bool(v1) => self.stack.push(Bool(!v1)),
Fun(_v1) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean function"))
}
}
// NEG
- 0x14 => match self.stacks[self.stack_ptr].pop().unwrap() {
+ 0x14 => match self.stack.pop().unwrap() {
Null => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number value null")) }
- Num(v1) => self.stacks[self.stack_ptr].push(Num(-v1)),
+ Num(v1) => self.stack.push(Num(-v1)),
Str(_v1) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number string"))
}
@@ 295,7 300,7 @@ impl VM {
}
// JNE
0x17 => {
- let condition = self.stacks[self.stack_ptr].pop().unwrap();
+ let condition = self.stack.pop().unwrap();
if let Value::Bool(condition) = condition {
if !condition {
let loc = self.read_u16();
@@ 311,18 316,19 @@ impl VM {
// CALL
0x18 => {
let num_args = self.read();
- let function = self.stacks[self.stack_ptr].pop().expect("Stack was empty in call");
+ let function = self.stack.pop().expect("Stack was empty in call");
if let Value::Fun(function) = function {
- self.stacks.push(Vec::new());
if num_args as usize != function.arity {
return Err(vm_error!(self, RuntimeErrorKind::IncorrectArity, "Function has {} arguments, {} provided", function.arity, num_args))
}
- self.call_stack.push((self.unit_ptr, self.ip));
- self.stacks[self.stack_ptr+1].push(Value::Fun(function));
+ self.stack_offset = self.stack.len()-1;
+ self.call_stack.push((self.unit_ptr, self.ip, self.stack_offset));
for _ in 0..num_args {
- let arg = self.stacks[self.stack_ptr].pop().expect("Missing arguments in call");
- self.stacks[self.stack_ptr+1].push(arg);
+ let arg = self.stack.pop().expect("Missing arguments in call");
+ self.stack.push(arg);
}
+ self.stack.insert(self.stack.len()-num_args as usize, Value::Fun(function));
+ //println!("stack call {:?}", self.stack);
self.stack_ptr += 1;
self.ip = 0;
self.unit_ptr = function.unit_ptr as usize;
@@ 332,25 338,25 @@ impl VM {
}
// RET
0x19 => {
- let (unit_ptr, ip) = self.call_stack.pop().expect("Call stack empty on RET");
- let ret = self.stacks[self.stack_ptr].pop().expect("Missing return value");
- //self.stacks[self.stack_ptr].clear();
+ let (unit_ptr, ip, stack_offset) = self.call_stack.pop().expect("Call stack empty on RET");
+ let ret = self.stack.pop().expect("Missing return value");
+ self.stack = self.stack[..stack_offset].to_vec();
+ self.stack_offset = self.call_stack.last().expect("call stack empty").2;
self.unit_ptr = unit_ptr;
self.ip = ip;
// returned to code
self.stack_ptr -= 1;
- self.stacks.pop().expect("RET pop stacks failed");
- self.stacks[self.stack_ptr].push(ret);
+ self.stack.push(ret);
}
0xFD => { // POP
let times = self.read();
for _ in 0..times {
- self.stacks[self.stack_ptr].pop().expect(&format!("{}: Unable to pop stack", self.ip));
+ self.stack.pop().expect(&format!("{}: Unable to pop stack", self.ip));
}
}
0xFE => { // PRINT
- let value = self.stacks[self.stack_ptr].pop().unwrap();
+ let value = self.stack.pop().unwrap();
match value {
Null => *output += "null",
Num(v) => *output += &v.to_string(),