From 3cad7d73f8ce1baf291a334628fb96a93c5fafe6 Mon Sep 17 00:00:00 2001 From: ghostly_zsh Date: Fri, 23 Aug 2024 13:53:10 -0500 Subject: [PATCH] list initialization and subscripting --- kabel/opcodes.txt | 3 ++ kabel/src/codegen.rs | 42 ++++++++++++++--------- kabel/src/debug.rs | 18 +++++++++- kabel/src/opcodes.rs | 9 +++++ kabel/src/runtime_error.rs | 3 ++ kabel/src/vm.rs | 70 ++++++++++++++++++++++++++++++++++++-- kabel/tmp.kab | 16 ++++----- 7 files changed, 131 insertions(+), 30 deletions(-) diff --git a/kabel/opcodes.txt b/kabel/opcodes.txt index 4e77058590e696559691d046c2e1eae332a8b6b9..dbd3c59e34d7ce9a7eed419391c5a920590da44e 100644 --- a/kabel/opcodes.txt +++ b/kabel/opcodes.txt @@ -29,5 +29,8 @@ JNE ELSE ; 0x17 CALL NUMARGS ; 0x18 RET ; 0x19 +LIST LEN ; 0x1A +SCR ; 0x1B + POP COUNT ; 0xFD PRINT ; 0xFE diff --git a/kabel/src/codegen.rs b/kabel/src/codegen.rs index e6e068f73137e82d830afec145826763b917240b..3bcb98552d9e6521c554e58be3efe476298cee2c 100644 --- a/kabel/src/codegen.rs +++ b/kabel/src/codegen.rs @@ -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) { - /*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)] diff --git a/kabel/src/debug.rs b/kabel/src/debug.rs index 54e27a8c84849b3bfaad3193a46c6ca123e9b95a..a150b509cfa4ed6a84d97286c2fc9e84d557921c 100644 --- a/kabel/src/debug.rs +++ b/kabel/src/debug.rs @@ -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 => { diff --git a/kabel/src/opcodes.rs b/kabel/src/opcodes.rs index eee4999a6823d32da9895acbfa661f8654dc04a1..95600255f9b3a744ec196556886ccd8883aaccca 100644 --- a/kabel/src/opcodes.rs +++ b/kabel/src/opcodes.rs @@ -33,6 +33,9 @@ pub enum OpCode { CALL, RET, + LIST, + SCR, + POP, PRINT, ERR, @@ -73,6 +76,9 @@ impl From for u8 { CALL => 0x18, RET => 0x19, + LIST => 0x1A, + SCR => 0x1B, + POP => 0xFD, PRINT => 0xFE, ERR => 0xFF @@ -113,6 +119,9 @@ impl From for OpCode { 0x18 => CALL, 0x19 => RET, + 0x1A => LIST, + 0x1B => SCR, + 0xFD => POP, 0xFE => PRINT, _ => ERR diff --git a/kabel/src/runtime_error.rs b/kabel/src/runtime_error.rs index 28dbbd9c477f2338c892fae76f57ee93b479450b..09f355ad6be2422913df8134990572a708e8eb01 100644 --- a/kabel/src/runtime_error.rs +++ b/kabel/src/runtime_error.rs @@ -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 for usize { MismatchedTypes => 0x00, WrongType => 0x01, IncorrectArity => 0x02, + ArrayOutOfBounds => 0x03, } } } diff --git a/kabel/src/vm.rs b/kabel/src/vm.rs index 424ed87f5834e9770a4708c9917fb794661bcc4b..9ed5efa3af77c9d6bdb01827e91937898e88b13e 100644 --- a/kabel/src/vm.rs +++ b/kabel/src/vm.rs @@ -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!("", 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), 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!("", v.unit_ptr), + } + } +} #[derive(Debug, Clone, Copy)] pub struct Function { diff --git a/kabel/tmp.kab b/kabel/tmp.kab index 3524b2707b9e9e84244f3d7724a03bfd82acfd7b..9831809e6da0588be8c2d07567676aa9e61d8ad7 100644 --- a/kabel/tmp.kab +++ b/kabel/tmp.kab @@ -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);