M kabel/opcodes.txt => kabel/opcodes.txt +31 -26
@@ 1,32 1,37 @@
LOAD VAL ; 0x00
VAR STACKPTR ; 0x01
-ASSIGN PTR ; 0x02
+ASN PTR ; 0x02
+ASNARR ; 0x03
+DECL ; 0x04
-ADD ; 0x03
-SUB ; 0x04
-MUL ; 0x05
-DIV ; 0x06
-MOD ; 0x07
-BITAND ; 0x08
-BITXOR ; 0x09
-BITOR ; 0x0a
-EQ ; 0x0B
-NE ; 0x0C
-GR ; 0x0D
-GE ; 0x0E
-LS ; 0x0F
-LE ; 0x10
-OR ; 0x11
-AND ; 0x12
-NOT ; 0x13
-NEG ; 0x14
-JMP LOC ; 0x15
-JMP_UP LOC ; 0x16
-JNE ELSE ; 0x17
-CALL ARITY ; 0x18
-RET ; 0x19
-LIST LEN ; 0x1A
-SCR ; 0x1B
+ADD ; 0x05
+SUB ; 0x06
+MUL ; 0x07
+DIV ; 0x08
+MOD ; 0x09
+BITAND ; 0x0a
+BITXOR ; 0x0b
+BITOR ; 0x0c
+EQ ; 0x0D
+NE ; 0x0E
+GR ; 0x0F
+GE ; 0x10
+LS ; 0x11
+LE ; 0x12
+OR ; 0x13
+AND ; 0x14
+NOT ; 0x15
+NEG ; 0x16
+
+JMP LOC ; 0x17
+JMP_UP LOC ; 0x18
+JNE ELSE ; 0x19
+
+CALL ARITY ; 0x1A
+RET ; 0x1B
+
+LIST LEN ; 0x1C
+SCR ; 0x1D
POP COUNT ; 0xFD
PRINT ; 0xFE
M kabel/src/codegen.rs => kabel/src/codegen.rs +31 -15
@@ 1,4 1,4 @@
-use crate::{ast::{ASTType, BinOp, LhsAssign, Lit, Name, UnOp, AST}, codegen_binary, codegen_unary, extension::Extension, opcodes::OpCode, vm::{Function, Unit, Value, VM}};
+use crate::{ast::{ASTType, BinOp, LhsAssign, LhsAssignType, Lit, Name, UnOp, AST}, codegen_binary, codegen_unary, extension::Extension, opcodes::OpCode, vm::{Function, Unit, Value, VM}};
pub struct Codegen {
pub vm: VM,
@@ 407,6 407,12 @@ impl Codegen {
}
pub fn visit_decl(&mut self, ast: &AST, _name: Name, expr: AST) {
self.visit(expr);
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::DECL.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;
+ }
#[allow(irrefutable_let_patterns)]
if let Extension::Resolution(_scope, _ptr) = ast.extensions[0] {
self.scopes.last_mut().expect("codegen scopes vec was empty").1 += 1;
@@ 432,23 438,33 @@ impl Codegen {
self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
}
}
- pub fn visit_assign(&mut self, ast: &AST, _name: LhsAssign, expr: AST) {
+ pub fn visit_assign(&mut self, ast: &AST, name: LhsAssign, expr: AST) {
self.visit(expr);
// pop stack to get value. then find variable in stack. set variable to value.
- self.vm.units[self.vm.unit_ptr].code.push(OpCode::ASSIGN.into());
- #[allow(irrefutable_let_patterns)]
- if let Extension::Resolution(_scope, ptr) = ast.extensions[0] {
- self.vm.units[self.vm.unit_ptr].code.push(ptr 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, 1));
- } else {
- self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
+ match name.kind {
+ LhsAssignType::Ident(_) => {
+ #[allow(irrefutable_let_patterns)]
+ if let Extension::Resolution(_scope, ptr) = ast.extensions[0] {
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::ASN.into());
+ self.vm.units[self.vm.unit_ptr].code.push(ptr 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;
+ }
+ }
+ }
+ LhsAssignType::Subscript(name, index) => {
+ self.visit(*index);
+ self.visit(*name);
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::ASNARR.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;
+ }
}
- }
- 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_anonymous(&mut self, params: Vec<Name>, block: AST) {
M kabel/src/debug.rs => kabel/src/debug.rs +17 -3
@@ 247,7 247,7 @@ pub fn debug_bytecode(vm: &VM) -> String {
output += &vm.ip.to_string();
output += " ";
output += &vm.find_line().to_string();
- output += " CONSTANT ";
+ output += " LOAD ";
vm.ip += 1;
output += &vm.units[vm.unit_ptr].code[vm.ip].to_string();
output += "\n";
@@ 261,15 261,29 @@ pub fn debug_bytecode(vm: &VM) -> String {
output += &vm.units[vm.unit_ptr].code[vm.ip].to_string();
output += "\n";
}
- ASSIGN => {
+ ASN => {
output += &vm.ip.to_string();
output += " ";
output += &vm.find_line().to_string();
- output += " ASSIGN ";
+ output += " ASN ";
vm.ip += 1;
output += &vm.units[vm.unit_ptr].code[vm.ip].to_string();
output += "\n";
}
+ ASNARR => {
+ output += &vm.ip.to_string();
+ output += " ";
+ output += &vm.find_line().to_string();
+ output += " ASNARR";
+ output += "\n";
+ }
+ DECL => {
+ output += &vm.ip.to_string();
+ output += " ";
+ output += &vm.find_line().to_string();
+ output += " DECL";
+ output += "\n";
+ }
JMP => {
output += &vm.ip.to_string();
M kabel/src/opcodes.rs => kabel/src/opcodes.rs +69 -63
@@ 4,7 4,9 @@
pub enum OpCode {
LOAD,
VAR,
- ASSIGN,
+ ASN,
+ ASNARR,
+ DECL,
ADD,
SUB,
@@ 47,37 49,39 @@ impl From<OpCode> for u8 {
match value {
LOAD => 0x00,
VAR => 0x01,
- ASSIGN => 0x02,
-
- ADD => 0x03,
- SUB => 0x04,
- MUL => 0x05,
- DIV => 0x06,
- MOD => 0x07,
- BITAND => 0x08,
- BITXOR => 0x09,
- BITOR => 0x0a,
- EQ => 0x0B,
- NE => 0x0C,
- GR => 0x0D,
- GE => 0x0E,
- LS => 0x0F,
- LE => 0x10,
- OR => 0x11,
- AND => 0x12,
-
- NOT => 0x13,
- NEG => 0x14,
-
- JMP => 0x15,
- JMP_UP => 0x16,
- JNE => 0x17,
-
- CALL => 0x18,
- RET => 0x19,
-
- LIST => 0x1A,
- SCR => 0x1B,
+ ASN => 0x02,
+ ASNARR => 0x03,
+ DECL => 0x04,
+
+ ADD => 0x05,
+ SUB => 0x06,
+ MUL => 0x07,
+ DIV => 0x08,
+ MOD => 0x09,
+ BITAND => 0x0a,
+ BITXOR => 0x0b,
+ BITOR => 0x0c,
+ EQ => 0x0D,
+ NE => 0x0E,
+ GR => 0x0F,
+ GE => 0x10,
+ LS => 0x11,
+ LE => 0x12,
+ OR => 0x13,
+ AND => 0x14,
+
+ NOT => 0x15,
+ NEG => 0x16,
+
+ JMP => 0x17,
+ JMP_UP => 0x18,
+ JNE => 0x19,
+
+ CALL => 0x1A,
+ RET => 0x1B,
+
+ LIST => 0x1C,
+ SCR => 0x1D,
POP => 0xFD,
PRINT => 0xFE,
@@ 90,37 94,39 @@ impl From<u8> for OpCode {
use OpCode::*; match value {
0x00 => LOAD,
0x01 => VAR,
- 0x02 => ASSIGN,
-
- 0x03 => ADD,
- 0x04 => SUB,
- 0x05 => MUL,
- 0x06 => DIV,
- 0x07 => MOD,
- 0x08 => BITAND,
- 0x09 => BITXOR,
- 0x0a => BITOR,
- 0x0B => EQ,
- 0x0C => NE,
- 0x0D => GR,
- 0x0E => GE,
- 0x0F => LS,
- 0x10 => LE,
- 0x11 => OR,
- 0x12 => AND,
-
- 0x13 => NOT,
- 0x14 => NEG,
-
- 0x15 => JMP,
- 0x16 => JMP_UP,
- 0x17 => JNE,
-
- 0x18 => CALL,
- 0x19 => RET,
-
- 0x1A => LIST,
- 0x1B => SCR,
+ 0x02 => ASN,
+ 0x03 => ASNARR,
+ 0x04 => DECL,
+
+ 0x05 => ADD,
+ 0x06 => SUB,
+ 0x07 => MUL,
+ 0x08 => DIV,
+ 0x09 => MOD,
+ 0x0A => BITAND,
+ 0x0b => BITXOR,
+ 0x0c => BITOR,
+ 0x0D => EQ,
+ 0x0E => NE,
+ 0x0F => GR,
+ 0x10 => GE,
+ 0x11 => LS,
+ 0x12 => LE,
+ 0x13 => OR,
+ 0x14 => AND,
+
+ 0x15 => NOT,
+ 0x16 => NEG,
+
+ 0x17 => JMP,
+ 0x18 => JMP_UP,
+ 0x19 => JNE,
+
+ 0x1A => CALL,
+ 0x1b => RET,
+
+ 0x1C => LIST,
+ 0x1D => SCR,
0xFD => POP,
0xFE => PRINT,
M kabel/src/vm.rs => kabel/src/vm.rs +70 -41
@@ 1,4 1,6 @@
+use std::rc::Rc;
+
use crate::{runtime_error::{KabelRuntimeError, RuntimeErrorKind}, vm_boolean_comparison, vm_boolean_equality};
use crate::vm_error;
@@ 32,7 34,8 @@ pub struct VM {
pub call_stack: Vec<(usize, usize, usize)>, // (unit_ptr, ip, stack_offset)
pub units: Vec<Unit>,
pub stack: Vec<Value>,
- pub stack_offset: usize,
+ pub variables: Vec<Value>,
+ pub variables_offset: usize,
text: Vec<String>
}
@@ 45,7 48,8 @@ impl VM {
call_stack: vec![(0, 0, 0)],
units: vec![Unit::new(bytecode, pool, lines)],
stack: Vec::new(),
- stack_offset: 0,
+ variables: Vec::new(),
+ variables_offset: 0,
text: text.lines().map(|s| s.to_string()).collect::<Vec<String>>(),
}
}
@@ 60,24 64,49 @@ impl VM {
}
0x01 => { // VAR
let ptr = self.read() as usize;
- let value = self.stack[ptr+self.stack_offset].clone();
- //println!("offset {} ptr {}", offset, ptr);
- //println!("stack {:?}", self.stack);
+ let value = self.variables[ptr+self.variables_offset].clone();
self.stack.push(value);
}
- // ASSIGN
- 0x02 => {
+ 0x02 => { // ASN
let value = self.stack.pop().unwrap();
let ptr = self.read();
let offset = self.call_stack.last().expect("var call stack last").2;
- self.stack[ptr as usize + offset] = value.clone();
+ self.variables[ptr as usize + offset] = value.clone();
self.stack.push(value);
}
- 0x03 => { // ADD
+ 0x03 => { // ASNARR
+ let mut list = self.stack.pop().unwrap();
+ let index = self.stack.pop().unwrap();
+ let value = self.stack.pop().unwrap();
+ if let Value::Num(index) = index {
+ if index.fract() != 0.0 {
+ return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Subscript index must be an integer but found {}", index))
+ }
+ let index = index as usize;
+ if let Value::List(ref mut list) = list {
+ let len = list.len();
+ if index > len {
+ return Err(vm_error!(self, RuntimeErrorKind::ArrayOutOfBounds, "List length is {} but found index {}", len, index))
+ }
+ println!("index: {}", index);
+ list[index] = value.clone();
+ self.stack.push(value);
+ } else {
+ return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to subscript non-list type {}", list.type_str()))
+ }
+ } else {
+ return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to use non-integer type {} to subscript list", index.type_str()))
+ }
+ }
+ 0x04 => { // DECL
+ let value = self.stack.pop().unwrap();
+ self.variables.push(value);
+ }
+ 0x05 => { // ADD
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => self.stack.push(Num(v1 + v2)),
(Str(v1), Str(v2)) => {
- self.stack.push(Str(v1 + &v2));
+ self.stack.push(Str(v1.clone() + &v2));
},
(Bool(_v1), Bool(_v2)) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot add booleans"))
@@ 87,7 116,7 @@ impl VM {
}
}
}
- 0x04 => { // SUB
+ 0x06 => { // SUB
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => self.stack.push(Num(v1 - v2)),
(Str(_v1), Str(_v2)) => {
@@ 101,7 130,7 @@ impl VM {
}
}
}
- 0x05 => { // MUL
+ 0x07 => { // MUL
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => self.stack.push(Num(v1 * v2)),
(Str(v1), Num(v2)) => {
@@ 122,7 151,7 @@ impl VM {
}
}
}
- 0x06 => { // DIV
+ 0x08 => { // DIV
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => self.stack.push(Num(v1 / v2)),
(Str(_v1), Str(_v2)) => {
@@ 136,7 165,7 @@ impl VM {
}
}
}
- 0x07 => { // MOD
+ 0x09 => { // MOD
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => self.stack.push(Num(v1 % v2)),
(Str(_v1), Str(_v2)) => {
@@ 150,7 179,7 @@ impl VM {
}
}
}
- 0x08 => { // BITAND
+ 0x0A => { // BITAND
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => {
if v1.fract() != 0.0 {
@@ 172,7 201,7 @@ impl VM {
}
}
}
- 0x09 => { // BITXOR
+ 0x0B => { // BITXOR
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => {
if v1.fract() != 0.0 {
@@ 194,7 223,7 @@ impl VM {
}
}
}
- 0x0A => { // BITOR
+ 0x0C => { // BITOR
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => {
if v1.fract() != 0.0 {
@@ 217,19 246,19 @@ impl VM {
}
}
// EQ
- 0x0b => vm_boolean_equality!(self, ==),
+ 0x0D => vm_boolean_equality!(self, ==),
// NE
- 0x0C => vm_boolean_equality!(self, !=),
+ 0x0E => vm_boolean_equality!(self, !=),
// GR
- 0x0D => vm_boolean_comparison!(self, >),
+ 0x0F => vm_boolean_comparison!(self, >),
// GE
- 0x0E => vm_boolean_comparison!(self, >=),
+ 0x10 => vm_boolean_comparison!(self, >=),
// LS
- 0x0F => vm_boolean_comparison!(self, <),
+ 0x11 => vm_boolean_comparison!(self, <),
// LE
- 0x10 => vm_boolean_comparison!(self, <=),
+ 0x12 => vm_boolean_comparison!(self, <=),
// OR
- 0x11 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ 0x13 => 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"))
}
@@ 244,7 273,7 @@ impl VM {
}
}
// AND
- 0x12 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ 0x14 => 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"))
}
@@ 259,7 288,7 @@ impl VM {
}
}
// NOT
- 0x13 => match self.stack.pop().unwrap() {
+ 0x15 => 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"))
@@ 276,7 305,7 @@ impl VM {
}
}
// NEG
- 0x14 => match self.stack.pop().unwrap() {
+ 0x16 => match self.stack.pop().unwrap() {
Null => { return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number value null")) }
Num(v1) => self.stack.push(Num(-v1)),
Str(_v1) => {
@@ 293,17 322,17 @@ impl VM {
}
}
// JMP
- 0x15 => {
+ 0x17 => {
let loc = self.read_u16();
self.ip += loc as usize;
}
// JMP_UP
- 0x16 => {
+ 0x18 => {
let loc = self.read_u16();
self.ip -= loc as usize;
}
// JNE
- 0x17 => {
+ 0x19 => {
let condition = self.stack.pop().unwrap();
if let Value::Bool(condition) = condition {
if !condition {
@@ 318,15 347,15 @@ impl VM {
}
// CALL
- 0x18 => {
+ 0x1A => {
let num_args = self.read();
let function = self.stack.pop().expect("Stack was empty in call");
if let Value::Fun(function) = function {
if num_args as usize != function.arity {
return Err(vm_error!(self, RuntimeErrorKind::IncorrectArity, "Function has {} arguments, {} provided", function.arity, num_args))
}
- self.stack_offset = self.stack.len() - num_args as usize;
- self.call_stack.push((self.unit_ptr, self.ip, self.stack_offset));
+ self.variables_offset = self.stack.len() - num_args as usize;
+ self.call_stack.push((self.unit_ptr, self.ip, self.variables_offset));
self.stack.insert(self.stack.len()-num_args as usize, Value::Fun(function));
self.ip = 0;
self.unit_ptr = function.unit_ptr as usize;
@@ 335,11 364,11 @@ impl VM {
}
}
// RET
- 0x19 => {
- let (unit_ptr, ip, stack_offset) = self.call_stack.pop().expect("Call stack empty on RET");
+ 0x1B => {
+ let (unit_ptr, ip, variables_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.stack = self.stack[..variables_offset].to_vec();
+ self.variables_offset = self.call_stack.last().expect("call stack empty").2;
self.unit_ptr = unit_ptr;
self.ip = ip;
// returned to code
@@ 347,13 376,13 @@ impl VM {
}
// LIST
- 0x1A => {
+ 0x1C => {
let len = self.read();
let list = self.stack.drain(self.stack.len()-len as usize..).collect();
self.stack.push(Value::List(list));
}
// SCR
- 0x1B => {
+ 0x1D => {
let index = self.stack.pop().expect("stack empty on subscript index");
let list = self.stack.pop().expect("stack empty on subscript list");
if let Value::Num(index) = index {
@@ 430,7 459,7 @@ impl VM {
#[derive(Debug, Clone)]
pub enum Value {
- Null, Num(f32), Str(String), Bool(bool), List(Vec<Value>), Fun(Function)
+ Null, Num(f32), Str(String), Bool(bool), List(Vec<Value>), Fun(Function),
}
impl Value {
@@ 456,7 485,7 @@ impl ToString for Value {
List(v) => {
let mut output = "".to_string();
output += "[";
- for value in v {
+ for value in <Vec<Value>>::clone(&v).into_iter() {
output += &value.to_string();
output += ",";
}
M kabel/tmp.kab => kabel/tmp.kab +5 -1
@@ 1,2 1,6 @@
+// put [3, 2] on stack
var i = [3, 2];
-i[0] = 3;
+// get reference to i
+// set index 0 from i to 3
+i[0] = 1;
+print i;