M kabel/opcodes.txt => kabel/opcodes.txt +1 -1
@@ 1,4 1,4 @@
-CONSTANT VAL ; 0x00
+LOAD VAL ; 0x00
VAR STACKPTR ; 0x01
ASSIGN PTR ; 0x02
M kabel/src/codegen.rs => kabel/src/codegen.rs +39 -7
@@ 28,6 28,9 @@ impl Codegen {
Function(name, args, block) => {
self.visit_function(name, args, *block);
}
+ Return(ref expr) => {
+ self.visit_return(&ast, *expr.clone());
+ }
While(condition, block) => {
self.visit_while(*condition, *block);
}
@@ 88,27 91,56 @@ impl Codegen {
}
match self.vm.units[self.vm.unit_ptr].code.last() {
Some(instr) => {
- if *instr != OpCode::RET.into() {
+ if *instr != <OpCode as Into<u8>>::into(OpCode::RET) {
+ self.vm.units[self.vm.unit_ptr].pool.push(Value::Null);
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::LOAD.into());
+ let loc = (self.vm.units[self.vm.unit_ptr].pool.len()-1) as u8;
+ self.vm.units[self.vm.unit_ptr].code.push(loc);
self.vm.units[self.vm.unit_ptr].code.push(OpCode::RET.into());
if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != block.end_line {
- self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 1));
+ self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 3));
} else {
- self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 3;
}
}
}
None => {
+ self.vm.units[self.vm.unit_ptr].pool.push(Value::Null);
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::LOAD.into());
+ let loc = (self.vm.units[self.vm.unit_ptr].pool.len()-1) as u8;
+ self.vm.units[self.vm.unit_ptr].code.push(loc);
self.vm.units[self.vm.unit_ptr].code.push(OpCode::RET.into());
if self.vm.units[self.vm.unit_ptr].lines.last().unwrap().0 != block.end_line {
- self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 1));
+ self.vm.units[self.vm.unit_ptr].lines.push((block.end_line, 3));
} else {
- self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 3;
}
}
};
self.vm.unit_ptr = old_unit_ptr;
self.vm.ip = old_ip;
}
+ pub fn visit_return(&mut self, ast: &AST, expr: Option<AST>) {
+ if let Some(expr) = expr {
+ self.visit(expr);
+ } else {
+ self.vm.units[self.vm.unit_ptr].pool.push(Value::Null);
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::LOAD.into());
+ let loc = (self.vm.units[self.vm.unit_ptr].pool.len()-1) as u8;
+ self.vm.units[self.vm.unit_ptr].code.push(loc);
+ 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;
+ }
+ }
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::RET.into());
+ 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, 1));
+ } else {
+ self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
+ }
+ }
pub fn visit_while(&mut self, condition: AST, block: AST) {
self.break_stack.push(Vec::new());
self.continue_stack.push(Vec::new());
@@ 459,8 491,8 @@ impl Codegen {
}
}
pub fn visit_call(&mut self, ast: &AST, _name: Name, args: Vec<AST>) {
- for arg in args.clone() {
- self.visit(arg);
+ for arg in args.iter().rev() {
+ self.visit(arg.clone());
}
self.vm.units[self.vm.unit_ptr].code.push(OpCode::CALL.into());
self.vm.units[self.vm.unit_ptr].code.push(args.len() as u8);
M kabel/src/debug.rs => kabel/src/debug.rs +12 -0
@@ 286,6 286,18 @@ pub fn debug_bytecode(vm: &VM) -> String {
output += &(byte_one | byte_two).to_string();
output += "\n";
}
+ CALL => {
+ output += &vm.ip.to_string();
+ output += " ";
+ output += &vm.find_line().to_string();
+ output += " CALL ";
+ vm.ip += 1;
+ output += &(vm.units[vm.unit_ptr].code[vm.ip]).to_string();
+ output += " ";
+ vm.ip += 1;
+ output += &(vm.units[vm.unit_ptr].code[vm.ip]).to_string();
+ output += "\n";
+ }
RET => {
output += &vm.ip.to_string();
output += " ";
M kabel/src/macros.rs => kabel/src/macros.rs +24 -9
@@ 276,8 276,8 @@ macro_rules! codegen_unary {
match $match_to {
$( $oper => {
$self.visit($right);
- $self.vm.units[0].code.push(OpCode::$code.into());
- $self.vm.units[0].lines.last_mut().unwrap().1 += 1;
+ $self.vm.units[$self.vm.unit_ptr].code.push(OpCode::$code.into());
+ $self.vm.units[$self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
} )*
}
};
@@ 298,16 298,31 @@ 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)),
+ }
+ };
+}
#[macro_export]
-macro_rules! vm_boolean_binary {
+macro_rules! vm_boolean_comparison {
($self:expr, $oper:tt) => {
- match ($self.units[0].stack.pop().expect(&("Couldn't pop left side of ".to_owned() + stringify!($oper))),
- $self.units[0].stack.pop().expect(&("Couldn't pop right side of ".to_owned() + stringify!($oper)))) {
- (Num(v1), Num(v2)) => $self.units[0].stack.push(Bool(v1 $oper v2)),
- (Str(v1), Str(v2)) => $self.units[0].stack.push(Bool(v1 $oper v2)),
- (Bool(v1), Bool(v2)) => $self.units[0].stack.push(Bool(v1 $oper v2)),
- (_v1, _v2) => $self.units[0].stack.push(Bool(false)),
+ 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, _) => 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)),
}
};
}
M kabel/src/main.rs => kabel/src/main.rs +1 -0
@@ 61,6 61,7 @@ fn main() {
output += "\n";
}
vm.unit_ptr = 0;
+ println!("{}", output);
output += "\n";
match vm.run(&mut output) {
M kabel/src/name_resolution.rs => kabel/src/name_resolution.rs +1 -1
@@ 287,7 287,7 @@ impl Resolver {
}
return AST {
ast_type: Call(ident, n_args),
- extensions: vec![Extension::Resolution(self.scope, place)],
+ extensions: vec![Extension::Resolution(self.scope, place+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 +36 -19
@@ 1,5 1,5 @@
-use crate::{runtime_error::{KabelRuntimeError, RuntimeErrorKind}, vm_boolean_binary};
+use crate::{runtime_error::{KabelRuntimeError, RuntimeErrorKind}, vm_boolean_comparison, vm_boolean_equality};
use crate::vm_error;
#[derive(Debug, Clone)]
@@ 213,26 213,28 @@ impl VM {
}
}
// EQ
- 0x0b => vm_boolean_binary!(self, ==),
+ 0x0b => vm_boolean_equality!(self, ==),
// NE
- 0x0C => vm_boolean_binary!(self, !=),
+ 0x0C => vm_boolean_equality!(self, !=),
// GR
- 0x0D => vm_boolean_binary!(self, >),
+ 0x0D => vm_boolean_comparison!(self, >),
// GE
- 0x0E => vm_boolean_binary!(self, >=),
+ 0x0E => vm_boolean_comparison!(self, >=),
// LS
- 0x0F => vm_boolean_binary!(self, <),
+ 0x0F => vm_boolean_comparison!(self, <),
// LE
- 0x10 => vm_boolean_binary!(self, <=),
+ 0x10 => vm_boolean_comparison!(self, <=),
// OR
0x11 => match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
(Num(_v1), Num(_v2)) => {
- return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical OR on numbers"))
+ 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, "Cannot perform logical OR on strings"))
+ 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)),
+ (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) => {
return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str()))
}
@@ 240,34 242,38 @@ impl VM {
// AND
0x12 => match (self.units[self.unit_ptr].stack.pop().unwrap(), self.units[self.unit_ptr].stack.pop().unwrap()) {
(Num(_v1), Num(_v2)) => {
- return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical AND on numbers"))
+ 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, "Cannot perform logical AND on strings"))
+ 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)),
+ (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) => {
return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str()))
}
}
// NOT
0x13 => match self.units[self.unit_ptr].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, "Cannot perform logical NOT on numbers"))
+ return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean number"))
}
Str(_v1) => {
- return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical NOT on strings"))
+ 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)),
}
// NEG
0x14 => match self.units[self.unit_ptr].stack.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)),
Str(_v1) => {
- return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot negate strings"))
+ return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number string"))
}
Bool(_v1) => {
- return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot negate bools"))
+ return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number boolean"))
}
}
// JMP
@@ 300,13 306,22 @@ impl VM {
let num_args = self.read();
let unit_ptr = self.read();
self.call_stack.push((self.unit_ptr, self.ip));
- for i in 0..num_args {
-
+ for _ in 0..num_args {
+ let arg = self.units[self.unit_ptr].stack.pop().expect("Missing arguments in call");
+ self.units[unit_ptr as usize].stack.push(arg);
}
+ self.ip = 0;
+ self.unit_ptr = unit_ptr as usize;
}
// 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();
+ self.unit_ptr = unit_ptr;
+ self.ip = ip;
+ // returned to code
+ self.units[self.unit_ptr].stack.push(ret);
}
0xFD => { // POP
@@ 318,6 333,7 @@ impl VM {
0xFE => { // PRINT
let value = self.units[self.unit_ptr].stack.pop().unwrap();
match value {
+ Null => *output += "null",
Num(v) => *output += &v.to_string(),
Str(v) => *output += &v,
Bool(v) => *output += &v.to_string(),
@@ 356,12 372,13 @@ impl VM {
#[derive(Debug, Clone)]
pub enum Value {
- Num(f32), Str(String), Bool(bool),
+ Null, Num(f32), Str(String), Bool(bool),
}
impl Value {
pub fn type_str(&self) -> String {
match self {
+ Value::Null => "null".to_string(),
Value::Num(_) => "number".to_string(),
Value::Str(_) => "string".to_string(),
Value::Bool(_) => "bool".to_string(),
M kabel/tmp.kab => kabel/tmp.kab +7 -3
@@ 1,4 1,8 @@
-function i(j) {
- j+1;
+var k = 0;
+function bar(i) {
+ return i+2;
}
-print i(2);
+function foo(i) {
+ return i+1;
+}
+print foo(2);