M kabel/opcodes.txt => kabel/opcodes.txt +3 -0
@@ 29,5 29,8 @@ JNE ELSE ; 0x17
CALL NUMARGS ; 0x18
RET ; 0x19
+LIST LEN ; 0x1A
+SCR ; 0x1B
+
POP COUNT ; 0xFD
PRINT ; 0xFE
M kabel/src/codegen.rs => kabel/src/codegen.rs +25 -17
@@ 62,6 62,9 @@ impl Codegen {
Assign(ref name, ref expr) => {
self.visit_assign(&ast, name.clone(), *expr.clone());
}
+ Subscript(ref left, ref right) => {
+ self.visit_subscript(&ast, *left.clone(), *right.clone());
+ }
Binary(left, oper, right) => {
self.visit_binary(*left, oper, *right);
}
@@ 143,23 146,6 @@ 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 {
@@ 462,6 448,16 @@ impl Codegen {
self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 1;
}
}
+ pub fn visit_subscript(&mut self, ast: &AST, left: AST, right: AST) {
+ self.visit(left);
+ self.visit(right);
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::SCR.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_binary(&mut self, left: AST, oper: BinOp, right: AST) {
use crate::ast::BinOp::*;
codegen_binary!(self, left, right, oper, Add, ADD, Sub, SUB, Mul, MUL,
@@ 507,6 503,18 @@ impl Codegen {
self.vm.units[self.vm.unit_ptr].lines.last_mut().unwrap().1 += 2;
}
}
+ Lit::Array(exprs) => {
+ for expr in &exprs {
+ self.visit(expr.clone());
+ }
+ self.vm.units[self.vm.unit_ptr].code.push(OpCode::LIST.into());
+ self.vm.units[self.vm.unit_ptr].code.push(exprs.len() as u8);
+ if self.vm.units[self.vm.unit_ptr].lines.len() == 0 || 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;
+ }
+ }
Lit::Ident(_name) => {
self.vm.units[self.vm.unit_ptr].code.push(OpCode::VAR.into());
#[allow(irrefutable_let_patterns)]
M kabel/src/debug.rs => kabel/src/debug.rs +17 -1
@@ 299,7 299,23 @@ pub fn debug_bytecode(vm: &VM) -> String {
output += &vm.ip.to_string();
output += " ";
output += &vm.find_line().to_string();
- output += " RET ";
+ output += " RET";
+ output += "\n";
+ }
+ LIST => {
+ output += &vm.ip.to_string();
+ output += " ";
+ output += &vm.find_line().to_string();
+ output += " LIST ";
+ vm.ip += 1;
+ output += &(vm.units[vm.unit_ptr].code[vm.ip]).to_string();
+ output += "\n";
+ }
+ SCR => {
+ output += &vm.ip.to_string();
+ output += " ";
+ output += &vm.find_line().to_string();
+ output += " SCR";
output += "\n";
}
POP => {
M kabel/src/opcodes.rs => kabel/src/opcodes.rs +9 -0
@@ 33,6 33,9 @@ pub enum OpCode {
CALL,
RET,
+ LIST,
+ SCR,
+
POP,
PRINT,
ERR,
@@ 73,6 76,9 @@ impl From<OpCode> for u8 {
CALL => 0x18,
RET => 0x19,
+ LIST => 0x1A,
+ SCR => 0x1B,
+
POP => 0xFD,
PRINT => 0xFE,
ERR => 0xFF
@@ 113,6 119,9 @@ impl From<u8> for OpCode {
0x18 => CALL,
0x19 => RET,
+ 0x1A => LIST,
+ 0x1B => SCR,
+
0xFD => POP,
0xFE => PRINT,
_ => ERR
M kabel/src/runtime_error.rs => kabel/src/runtime_error.rs +3 -0
@@ 43,6 43,7 @@ pub enum RuntimeErrorKind {
MismatchedTypes,
WrongType,
IncorrectArity,
+ ArrayOutOfBounds,
}
impl std::fmt::Display for RuntimeErrorKind {
@@ 52,6 53,7 @@ impl std::fmt::Display for RuntimeErrorKind {
MismatchedTypes => f.write_str("Mismatched types"),
WrongType => f.write_str("Wrong type"),
IncorrectArity => f.write_str("Incorrect arity"),
+ ArrayOutOfBounds => f.write_str("Array out of bounds"),
}
}
}
@@ 63,6 65,7 @@ impl From<RuntimeErrorKind> for usize {
MismatchedTypes => 0x00,
WrongType => 0x01,
IncorrectArity => 0x02,
+ ArrayOutOfBounds => 0x03,
}
}
}
M kabel/src/vm.rs => kabel/src/vm.rs +67 -3
@@ 270,6 270,9 @@ impl VM {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean string"))
}
Bool(v1) => self.stack.push(Bool(!v1)),
+ List(_v1) => {
+ return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean list"))
+ }
Fun(_v1) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-boolean function"))
}
@@ 284,6 287,9 @@ impl VM {
Bool(_v1) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number boolean"))
}
+ List(_v1) => {
+ return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"!\" on non-number list"))
+ }
Fun(_v1) => {
return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Tried to perform \"-\" on non-number function"))
}
@@ 348,6 354,33 @@ impl VM {
self.stack_ptr -= 1;
self.stack.push(ret);
}
+ // LIST
+ 0x1A => {
+ let len = self.read();
+ let list = self.stack.drain(self.stack.len()-len as usize..).collect();
+ self.stack.push(Value::List(list));
+ }
+ // SCR
+ 0x1B => {
+ 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 {
+ 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(list) = list {
+ if index > list.len() {
+ return Err(vm_error!(self, RuntimeErrorKind::ArrayOutOfBounds, "List length is {} but found index {}", list.len(), index))
+ }
+ self.stack.push(list[index].clone());
+ } 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()))
+ }
+ }
0xFD => { // POP
let times = self.read();
@@ 357,13 390,21 @@ impl VM {
}
0xFE => { // PRINT
let value = self.stack.pop().unwrap();
- match value {
+ /*match value {
Null => *output += "null",
Num(v) => *output += &v.to_string(),
Str(v) => *output += &v,
Bool(v) => *output += &v.to_string(),
+ List(v) => {
+ *output += "[";
+ for value in v {
+ *output += &format!("", value);
+ }
+ *output += "[";
+ }
Fun(v) => *output += &format!("<function {}>", v.unit_ptr),
- }
+ }*/
+ *output += &value.to_string();
*output += "\n";
}
_ => {}
@@ 398,7 439,7 @@ impl VM {
#[derive(Debug, Clone)]
pub enum Value {
- Null, Num(f32), Str(String), Bool(bool), Fun(Function)
+ Null, Num(f32), Str(String), Bool(bool), List(Vec<Value>), Fun(Function)
}
impl Value {
@@ 408,10 449,33 @@ impl Value {
Value::Num(_) => "number".to_string(),
Value::Str(_) => "string".to_string(),
Value::Bool(_) => "bool".to_string(),
+ Value::List(_) => "list".to_string(),
Value::Fun(_) => "function".to_string(),
}
}
}
+impl ToString for Value {
+ fn to_string(&self) -> String {
+ use Value::*;
+ match self {
+ Null => "null".to_string(),
+ Num(v) => v.to_string(),
+ Str(v) => v.to_string(),
+ Bool(v) => v.to_string(),
+ List(v) => {
+ let mut output = "".to_string();
+ output += "[";
+ for value in v {
+ output += &value.to_string();
+ output += ",";
+ }
+ output += "]";
+ output
+ }
+ Fun(v) => format!("<function {}>", v.unit_ptr),
+ }
+ }
+}
#[derive(Debug, Clone, Copy)]
pub struct Function {
M kabel/tmp.kab => kabel/tmp.kab +7 -9
@@ 1,10 1,8 @@
-function fib(x) {
- if(x == 0) {
- return 0;
- }
- if(x == 1 || x == 2) {
- return 1;
- }
- return fib(x-1) + fib(x-2);
+function foo(bar) {
+ bar();
}
-print fib(35);
+function bar() {
+ print 3;
+}
+
+foo(bar);