M kabel/src/codegen.rs => kabel/src/codegen.rs +23 -0
@@ 95,12 95,18 @@ impl Codegen {
} else {
self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 2;
}
+ self.scopes.last_mut().expect("codegen scopes vec was empty").1 += 1;
let old_unit_ptr = self.vm.unit_ptr;
let old_ip = self.vm.ip;
// set unit to write to
self.vm.unit_ptr = new_unit_ptr;
self.vm.ip = 0;
+ self.vm.units[self.vm.unit_ptr].pool.push(Value::Fun(Function {
+ unit_ptr: new_unit_ptr,
+ arity: args.len(),
+ }));
+ self.scopes.last_mut().expect("codegen scopes vec was empty").1 += args.len();
if let ASTType::Block(ref stmts) = block.ast_type {
self.visit_block(&block, stmts.clone(), ScopeType::Function);
@@ 137,6 143,23 @@ impl Codegen {
self.vm.ip = old_ip;
}
pub fn visit_return(&mut self, ast: &AST, expr: Option<AST>) {
+ let mut scopes = self.scopes.clone();
+ let mut pop_count = 0;
+ /*loop {
+ let (scope_type, scope) = scopes.pop().expect("scopes empty in return");
+ pop_count += scope;
+ if scope_type == ScopeType::Function {
+ break;
+ }
+ }*/
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::POP.into());
+ self.vm.units[self.vm.unit_ptr].code.push(pop_count as u8);
+ if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != ast.end_line {
+ self.vm.units[self.vm.unit_ptr].lines.push((ast.end_line, 2));
+ } else {
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 2;
+ }
+
if let Some(expr) = expr {
self.visit(expr);
} else {
M kabel/src/macros.rs => kabel/src/macros.rs +13 -13
@@ 301,13 301,13 @@ macro_rules! push_codegen {
#[macro_export]
macro_rules! vm_boolean_equality {
($self:expr, $oper:tt) => {
- match ($self.units[$self.unit_ptr].stack.pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))),
- $self.units[$self.unit_ptr].stack.pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) {
- (Num(v1), Num(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)),
- (Str(v1), Str(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)),
- (Bool(v1), Bool(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)),
- (Null, Null) => $self.units[$self.unit_ptr].stack.push(Bool(true)),
- (_v1, _v2) => $self.units[$self.unit_ptr].stack.push(Bool(false)),
+ 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)),
}
};
}
@@ 315,14 315,14 @@ macro_rules! vm_boolean_equality {
#[macro_export]
macro_rules! vm_boolean_comparison {
($self:expr, $oper:tt) => {
- match ($self.units[$self.unit_ptr].stack.pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))),
- $self.units[$self.unit_ptr].stack.pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) {
- (Num(v1), Num(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)),
- (Str(v1), Str(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)),
- (Bool(v1), Bool(v2)) => $self.units[$self.unit_ptr].stack.push(Bool(v1 $oper v2)),
+ 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, _) => 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.units[$self.unit_ptr].stack.push(Bool(false)),
+ (_v1, _v2) => $self.stacks[$self.stack_ptr].push(Bool(false)),
}
};
}
M kabel/src/main.rs => kabel/src/main.rs +1 -1
@@ 52,9 52,9 @@ fn main() {
let codegen = run_codegen(program.to_string(), ast);
let mut vm = codegen.vm;
- output += &debug_stack(&vm.units[0].stack);
for (index, _) in vm.units.iter().enumerate() {
vm.unit_ptr = index;
+ output += &format!("{:?}", vm.units[vm.unit_ptr].pool);
output += "unit ptr: ";
output += &vm.unit_ptr.to_string();
output += "\n";
M kabel/src/name_resolution.rs => kabel/src/name_resolution.rs +20 -14
@@ 5,7 5,7 @@ use crate::{ast::{ASTType, AST}, ast_error, ast_from_ast, error::{ErrorKind, Kab
pub struct Resolver {
text: Vec<String>,
symbol_table: Vec<HashMap<String, (Symbol, usize)>>, // (Symbol, reference to locals)
- pub locals: Vec<usize>, // scope
+ pub locals: Vec<Vec<usize>>, // scope
pub scope: usize,
pub errors: Vec<KabelError>,
}
@@ 15,7 15,7 @@ impl Resolver {
Self {
text: text.lines().collect::<Vec<&str>>().iter().map(|s| s.to_string()).collect(),
symbol_table: vec![HashMap::new()],
- locals: Vec::new(),
+ locals: vec![Vec::new()],
scope: 0,
errors: Vec::new(),
}
@@ 61,18 61,24 @@ impl Resolver {
} else {}
}
}
+ self.locals.last_mut().expect("locals last in function push").push(self.scope);
+ self.symbol_table.last_mut().unwrap().insert(name.name.clone(),
+ (Symbol::Function(args.len()), self.locals.last().expect("locals last in function symbol len").len()-1));
+
+ self.locals.push(Vec::new());
self.symbol_table.push(HashMap::new());
+ self.locals.last_mut().expect("locals last in function self-reference push").push(self.scope+1);
+ self.symbol_table.last_mut().unwrap().insert(name.name.clone(), (Symbol::Var,self.locals.last().expect("locals last in function self-reference len").len()-1));
for arg in args.clone() {
- self.symbol_table.last_mut().unwrap().insert(arg.name, (Symbol::Var,0));
+ self.locals.last_mut().expect("locals last in function arg push").push(self.scope+1);
+ self.symbol_table.last_mut().unwrap().insert(arg.name, (Symbol::Var,self.locals.last().expect("locals last in function arg len").len()-1));
}
let block = self.visit(*block);
self.symbol_table.pop();
- self.locals.push(self.scope);
- self.symbol_table.last_mut().unwrap().insert(name.name.clone(),
- (Symbol::Function(args.len()), self.locals.len()-1));
+ self.locals.pop();
AST {
ast_type: Function(name, args, Box::new(block)),
- extensions: vec![Extension::Resolution(self.scope, self.locals.len()-1)],
+ extensions: vec![Extension::Resolution(self.scope, self.locals.last().expect("locals last in function ast len").len()-1)],
start_line: ast.start_line,
end_line: ast.end_line,
start_column: ast.start_column,
@@ 113,9 119,9 @@ impl Resolver {
n_expr3 = Some(self.visit(expr));
}
let block = self.visit(*block);
- while let Some(scope) = self.locals.last() {
+ while let Some(scope) = self.locals.last().expect("locals failed in For").last() {
if self.scope == *scope {
- self.locals.pop();
+ self.locals.last_mut().expect("locals failed in For pop").pop();
} else {
break;
}
@@ 145,9 151,9 @@ impl Resolver {
self.locals.remove(index);
}
}*/
- while let Some(scope) = self.locals.last() {
+ while let Some(scope) = self.locals.last().expect("locals last in block").last() {
if self.scope == *scope {
- self.locals.pop();
+ self.locals.last_mut().expect("locals last in block pop").pop();
} else {
break;
}
@@ 158,7 164,7 @@ impl Resolver {
}
Decl(name, expr) => {
let expr = self.visit(*expr);
- self.locals.push(self.scope);
+ self.locals.last_mut().expect("locals last in decl push").push(self.scope);
if self.resolve_var(&name.name).0 {
self.errors.push(out_of_scope_var!(self,
ErrorKind::VariableAlreadyDeclaredVariable, ast,
@@ 181,10 187,10 @@ impl Resolver {
} else {}
}
}
- self.symbol_table.last_mut().unwrap().insert(name.name.clone(), (Symbol::Var, self.locals.len()-1));
+ self.symbol_table.last_mut().unwrap().insert(name.name.clone(), (Symbol::Var, self.locals.last().expect("locals last in decl symbol").len()-1));
AST {
ast_type: Decl(name, Box::new(expr)),
- extensions: vec![Extension::Resolution(self.scope, self.locals.len()-1)],
+ extensions: vec![Extension::Resolution(self.scope, self.locals.last().expect("locals last in decl ast").len()-1)],
start_line: ast.start_line,
end_line: ast.end_line,
start_column: ast.start_column,
M kabel/src/vm.rs => kabel/src/vm.rs +53 -47
@@ 5,15 5,13 @@ use crate::vm_error;
#[derive(Debug, Clone)]
pub struct Unit {
pub code: Vec<u8>,
- pub stack: Vec<Value>,
pub pool: Vec<Value>,
pub lines: Vec<(usize, usize)>, // line #, repeats number of instructions
}
impl Unit {
- pub fn new(code: Vec<u8>, stack: Vec<Value>, pool: Vec<Value>, lines: Vec<(usize, usize)>) -> Self {
+ pub fn new(code: Vec<u8>, pool: Vec<Value>, lines: Vec<(usize, usize)>) -> Self {
Self {
code,
- stack,
pool,
lines,
}
@@ 21,7 19,6 @@ impl Unit {
pub fn new_empty() -> Self {
Self {
code: Vec::new(),
- stack: Vec::new(),
pool: Vec::new(),
lines: Vec::new(),
}
@@ 32,8 29,10 @@ impl Unit {
pub struct VM {
pub ip: usize,
pub unit_ptr: usize,
+ pub stack_ptr: usize,
pub call_stack: Vec<(usize, usize)>, // (unit_ptr, ip)
pub units: Vec<Unit>,
+ pub stacks: Vec<Vec<Value>>,
text: Vec<String>
}
@@ 43,8 42,10 @@ impl VM {
Self {
ip: 0,
unit_ptr: 0,
+ stack_ptr: 0,
call_stack: Vec::new(),
- units: vec![Unit::new(bytecode, Vec::new(), pool, lines)],
+ units: vec![Unit::new(bytecode, pool, lines)],
+ stacks: vec![Vec::new()],
text: text.lines().map(|s| s.to_string()).collect::<Vec<String>>(),
}
}
@@ 55,25 56,25 @@ impl VM {
0x00 => { // LOAD
let byte = self.read() as usize;
let value = self.units[self.unit_ptr].pool[byte].clone();
- self.units[self.unit_ptr].stack.push(value);
+ self.stacks[self.stack_ptr].push(value);
}
0x01 => { // VAR
let ptr = self.read() as usize;
- let value = self.units[self.unit_ptr].stack[ptr].clone();
- self.units[self.unit_ptr].stack.push(value);
+ let value = self.stacks[self.stack_ptr][ptr].clone();
+ self.stacks[self.stack_ptr].push(value);
}
// ASSIGN
0x02 => {
- let value = self.units[self.unit_ptr].stack.pop().unwrap();
+ let value = self.stacks[self.stack_ptr].pop().unwrap();
let ptr = self.read();
- self.units[self.unit_ptr].stack[ptr as usize] = value.clone();
- self.units[self.unit_ptr].stack.push(value);
+ self.stacks[self.stack_ptr][ptr as usize] = value.clone();
+ self.stacks[self.stack_ptr].push(value);
}
0x03 => { // ADD
- match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
- (Num(v1), Num(v2)) => self.units[self.unit_ptr].stack.push(Num(v1 + v2)),
+ 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)),
(Str(v1), Str(v2)) => {
- self.units[self.unit_ptr].stack.push(Str(v1 + &v2));
+ self.stacks[self.stack_ptr].push(Str(v1 + &v2));
},
(Bool(_v1), Bool(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot add booleans"))
@@ 84,8 85,8 @@ impl VM {
}
}
0x04 => { // SUB
- match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
- (Num(v1), Num(v2)) => self.units[self.unit_ptr].stack.push(Num(v1 - v2)),
+ 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)),
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot subtract strings"))
},
@@ 98,11 99,11 @@ impl VM {
}
}
0x05 => { // MUL
- match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
- (Num(v1), Num(v2)) => self.units[self.unit_ptr].stack.push(Num(v1 * v2)),
+ 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)),
(Str(v1), Num(v2)) => {
if v2.fract() == 0.0 {
- self.units[self.unit_ptr].stack.push(Str(v1.repeat(v2 as usize)));
+ self.stacks[self.stack_ptr].push(Str(v1.repeat(v2 as usize)));
} else {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Number must be an integer"))
}
@@ 119,8 120,8 @@ impl VM {
}
}
0x06 => { // DIV
- match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
- (Num(v1), Num(v2)) => self.units[self.unit_ptr].stack.push(Num(v1 / v2)),
+ 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)),
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot divide strings"))
},
@@ 133,8 134,8 @@ impl VM {
}
}
0x07 => { // MOD
- match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
- (Num(v1), Num(v2)) => self.units[self.unit_ptr].stack.push(Num(v1 % v2)),
+ 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)),
(Str(_v1), Str(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform modulus on strings"))
},
@@ 147,7 148,7 @@ impl VM {
}
}
0x08 => { // BITAND
- match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
+ match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) {
(Num(v1), Num(v2)) => {
if v1.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise AND on {}", v1))
@@ 155,7 156,7 @@ impl VM {
if v2.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise AND on {}", v2))
}
- self.units[self.unit_ptr].stack.push(Num((v1 as u32 & v2 as u32) as f32))
+ self.stacks[self.stack_ptr].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"))
@@ 169,7 170,7 @@ impl VM {
}
}
0x09 => { // BITXOR
- match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
+ match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) {
(Num(v1), Num(v2)) => {
if v1.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise XOR on {}", v1))
@@ 177,7 178,7 @@ impl VM {
if v2.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise XOR on {}", v2))
}
- self.units[self.unit_ptr].stack.push(Num((v1 as u32 ^ v2 as u32) as f32))
+ self.stacks[self.stack_ptr].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"))
@@ 191,7 192,7 @@ impl VM {
}
}
0x0A => { // BITOR
- match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
+ match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].pop().unwrap()) {
(Num(v1), Num(v2)) => {
if v1.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise OR on {}", v1))
@@ 199,7 200,7 @@ impl VM {
if v2.fract() != 0.0 {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise OR on {}", v2))
}
- self.units[self.unit_ptr].stack.push(Num((v1 as u32 | v2 as u32) as f32))
+ self.stacks[self.stack_ptr].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"))
@@ 225,14 226,14 @@ impl VM {
// LE
0x10 => vm_boolean_comparison!(self, <=),
// OR
- 0x11 => match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
+ 0x11 => match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].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.units[self.unit_ptr].stack.push(Bool(v1 || v2)),
+ (Bool(v1), Bool(v2)) => self.stacks[self.stack_ptr].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) => {
@@ 240,14 241,14 @@ impl VM {
}
}
// AND
- 0x12 => match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
+ 0x12 => match (self.stacks[self.stack_ptr].pop().unwrap(), self.stacks[self.stack_ptr].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.units[self.unit_ptr].stack.push(Bool(v1 && v2)),
+ (Bool(v1), Bool(v2)) => self.stacks[self.stack_ptr].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) => {
@@ 255,7 256,7 @@ impl VM {
}
}
// NOT
- 0x13 => match self.units[self.unit_ptr].stack.pop().unwrap() {
+ 0x13 => match self.stacks[self.stack_ptr].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"))
@@ 263,15 264,15 @@ impl VM {
Str(_v1) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean string"))
}
- Bool(v1) => self.units[self.unit_ptr].stack.push(Bool(!v1)),
+ Bool(v1) => self.stacks[self.stack_ptr].push(Bool(!v1)),
Fun(_v1) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean function"))
}
}
// NEG
- 0x14 => match self.units[self.unit_ptr].stack.pop().unwrap() {
+ 0x14 => match self.stacks[self.stack_ptr].pop().unwrap() {
Null => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number value null")) }
- Num(v1) => self.units[self.unit_ptr].stack.push(Num(-v1)),
+ Num(v1) => self.stacks[self.stack_ptr].push(Num(-v1)),
Str(_v1) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number string"))
}
@@ 294,7 295,7 @@ impl VM {
}
// JNE
0x17 => {
- let condition = self.units[self.unit_ptr].stack.pop().unwrap();
+ let condition = self.stacks[self.stack_ptr].pop().unwrap();
if let Value::Bool(condition) = condition {
if !condition {
let loc = self.read_u16();
@@ 310,16 311,19 @@ impl VM {
// CALL
0x18 => {
let num_args = self.read();
- let function = self.units[self.unit_ptr].stack.pop().expect("Stack was empty in call");
+ let function = self.stacks[self.stack_ptr].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));
for _ in 0..num_args {
- let arg = self.units[self.unit_ptr].stack.pop().expect("Missing arguments in call");
- self.units[function.unit_ptr as usize].stack.push(arg);
+ let arg = self.stacks[self.stack_ptr].pop().expect("Missing arguments in call");
+ self.stacks[self.stack_ptr+1].push(arg);
}
+ self.stack_ptr += 1;
self.ip = 0;
self.unit_ptr = function.unit_ptr as usize;
} else {
@@ 329,22 333,24 @@ impl VM {
// RET
0x19 => {
let (unit_ptr, ip) = self.call_stack.pop().expect("Call stack empty on RET");
- let ret = self.units[self.unit_ptr].stack.pop().expect("Missing return value");
- self.units[self.unit_ptr].stack.clear();
+ let ret = self.stacks[self.stack_ptr].pop().expect("Missing return value");
+ //self.stacks[self.stack_ptr].clear();
self.unit_ptr = unit_ptr;
self.ip = ip;
// returned to code
- self.units[self.unit_ptr].stack.push(ret);
+ self.stack_ptr -= 1;
+ self.stacks.pop().expect("RET pop stacks failed");
+ self.stacks[self.stack_ptr].push(ret);
}
0xFD => { // POP
let times = self.read();
for _ in 0..times {
- self.units[self.unit_ptr].stack.pop().expect(&format!("{}: Unable to pop stack", self.ip));
+ self.stacks[self.stack_ptr].pop().expect(&format!("{}: Unable to pop stack", self.ip));
}
}
0xFE => { // PRINT
- let value = self.units[self.unit_ptr].stack.pop().unwrap();
+ let value = self.stacks[self.stack_ptr].pop().unwrap();
match value {
Null => *output += "null",
Num(v) => *output += &v.to_string(),
@@ 401,7 407,7 @@ impl Value {
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Copy)]
pub struct Function {
pub unit_ptr: usize,
pub arity: usize,
M kabel/test/runtime/fn_absent_block.out => kabel/test/runtime/fn_absent_block.out +1 -1
@@ 1,3 1,3 @@
-Error 0004: Function "foo" not in scope at line 3, column 5
+Error 0004: Variable "foo" not in scope at line 3, column 5
foo();
^
A kabel/test/runtime/max.kab => kabel/test/runtime/max.kab +12 -0
@@ 0,0 1,12 @@
+function max(first, second) {
+ if(first > second) {
+ return first;
+ } else {
+ return second;
+ }
+}
+
+print max(1, 2); // 2
+print max(3, 6); // 6
+print max(-5.2, 5); // 5
+print max(5, -5.2); // 5
A kabel/test/runtime/max.out => kabel/test/runtime/max.out +4 -0
A kabel/test/runtime/recursive_fib.kab => kabel/test/runtime/recursive_fib.kab +13 -0
@@ 0,0 1,13 @@
+function fib(x) {
+ if(x == 0) {
+ return 0;
+ }
+ if(x == 1 || x == 2) {
+ return 1;
+ }
+ return fib(x-1) + fib(x-2);
+}
+print fib(2); // 1
+print fib(3); // 2
+print fib(4); // 3
+print fib(5); // 5
A kabel/test/runtime/recursive_fib.out => kabel/test/runtime/recursive_fib.out +4 -0
M kabel/test/syntax/assignment.out => kabel/test/syntax/assignment.out +3 -3
@@ 1,8 1,8 @@
Program
-| Decl i
+| Decl i []
| | Lit 0
| Expr
-| | Assign i
+| | Assign i []
| | | Lit string
-| Decl _foo
+| Decl _foo []
| | Lit 3
M kabel/test/syntax/function.out => kabel/test/syntax/function.out +3 -3
@@ 1,7 1,7 @@
Program
-| Function foo one two
+| Function foo one two []
| | Block
| | | Return
| | | | Binary Add
-| | | | | Lit one
-| | | | | Lit two
+| | | | | Lit one []
+| | | | | Lit two []
M kabel/test/syntax/if_else.out => kabel/test/syntax/if_else.out +5 -5
@@ 1,23 1,23 @@
Program
| If
| | Binary Eq
-| | | Lit i
+| | | Lit i []
| | | Lit 0
| | Block
| | | Expr
-| | | | Assign i
+| | | | Assign i []
| | | | | Lit 1
| Else
| | If
| | | Binary Eq
-| | | | Lit i
+| | | | Lit i []
| | | | Lit 1
| | | Block
| | | | Expr
-| | | | | Assign i
+| | | | | Assign i []
| | | | | | Lit 2
| | Else
| | | Block
| | | | Expr
-| | | | | Assign i
+| | | | | Assign i []
| | | | | | Lit 3
M kabel/tmp.kab => kabel/tmp.kab +9 -7
@@ 1,8 1,10 @@
-var k = 0;
-function bar(i) {
- return i+2;
+function fib(x) {
+ if(x == 0) {
+ return 0;
+ }
+ if(x == 1 || x == 2) {
+ return 1;
+ }
+ return fib(x-1) + fib(x-2);
}
-function foo(i) {
- return i+1;
-}
-print foo(bar(k));
+print fib(35);