├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── bytecode_gen ├── recursive_dis.py └── source.py ├── compile_to_json.bat ├── compile_to_json_and_run.bat ├── run.bat └── src └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | 4 | bytecode.json 5 | 6 | .idea -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "itoa" 5 | version = "0.4.5" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | [[package]] 9 | name = "proc-macro2" 10 | version = "1.0.9" 11 | source = "registry+https://github.com/rust-lang/crates.io-index" 12 | dependencies = [ 13 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 14 | ] 15 | 16 | [[package]] 17 | name = "py_vm" 18 | version = "0.1.0" 19 | dependencies = [ 20 | "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", 21 | "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", 22 | ] 23 | 24 | [[package]] 25 | name = "quote" 26 | version = "1.0.3" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | dependencies = [ 29 | "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", 30 | ] 31 | 32 | [[package]] 33 | name = "ryu" 34 | version = "1.0.3" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | 37 | [[package]] 38 | name = "serde" 39 | version = "1.0.105" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | dependencies = [ 42 | "serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", 43 | ] 44 | 45 | [[package]] 46 | name = "serde_derive" 47 | version = "1.0.105" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | dependencies = [ 50 | "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", 51 | "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 52 | "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", 53 | ] 54 | 55 | [[package]] 56 | name = "serde_json" 57 | version = "1.0.48" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | dependencies = [ 60 | "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", 61 | "ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 62 | "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", 63 | ] 64 | 65 | [[package]] 66 | name = "syn" 67 | version = "1.0.17" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | dependencies = [ 70 | "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", 71 | "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 72 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 73 | ] 74 | 75 | [[package]] 76 | name = "unicode-xid" 77 | version = "0.2.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | 80 | [metadata] 81 | "checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" 82 | "checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" 83 | "checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" 84 | "checksum ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" 85 | "checksum serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" 86 | "checksum serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" 87 | "checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25" 88 | "checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" 89 | "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 90 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "py_vm" 3 | version = "0.1.0" 4 | authors = ["Fatih Kilic <***REMOVED***>"] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | serde_json = "1.0" 11 | serde = { version = "1.0", features = ["derive", "rc"] } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Fatih Kılıç 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyVM 2 | PyVM is a Python Virtual Machine implemented in Rust. For learning purposes. 3 | 4 | ## What can it run? 5 | Not much. Only 39 instruction types are implemented and there are 130 different types of instructions in Python 3.8. Also, not all types are implemented neither built-in functions (but hey, we have the `print` function). 6 | 7 | So basically these are implemented: 8 | - Variables 9 | - `int`, `bool`, `float`, `str` and `None` types. 10 | - `add`, `subtract`, `multiply`, `true_divide` and `floor_divide` operations. 11 | - `<`, `<=`, `==`, `!=`, `>` and `>=` comparison operations 12 | - Only `if/elif/else` and `while` because `for` requires more thing to be implemented 13 | - Supports only functions with positional arguments 14 | - Global and local scope but not `global` keyword 15 | - Deleting variables (only from local) 16 | 17 | ## Then, what is the purpose? 18 | The purpose is learning about both Python's Virtual Machine and Rust. Hence the code is ugly and slow but this is my first program in Rust, so this is expected. 19 | 20 | ## Usage 21 | 1. Edit `bytecode_gen/source.py` 22 | 1. Run any of the batch files according to the situation: 23 | - `compile_to_json.bat`: Creates a file called `bytecode.json` that contains instructions and all that stuff. 24 | - `run.bat`: Runs the virtual machine with the instructions from `bytecode.json` 25 | - `compile_to_json_and_run.bat`: Creates `bytecode.json` and runs the virtual machine 26 | -------------------------------------------------------------------------------- /bytecode_gen/recursive_dis.py: -------------------------------------------------------------------------------- 1 | import dis, sys, types, json 2 | 3 | 4 | def to_camel_case(str): 5 | return "".join(map(lambda x: x[0].upper() + x[1:].lower(), str.split("_"))) 6 | 7 | 8 | def parse_code(code, parsed_code={"instructions": [], "constants": []}): 9 | parsed_code["co_names"] = code.co_names 10 | parsed_code["co_varnames"] = code.co_varnames 11 | 12 | bytecode = dis.Bytecode(code) 13 | for instruction in bytecode: 14 | parsed_code["instructions"].append( 15 | {to_camel_case(instruction.opname): instruction.arg} 16 | ) 17 | 18 | for constant in code.co_consts: 19 | if isinstance(constant, types.CodeType): 20 | code = {"instructions": [], "constants": []} 21 | parse_code(constant, code) 22 | parsed_code["constants"].append({"Frame": code}) 23 | else: 24 | parsed_code["constants"].append({to_camel_case(type(constant).__name__): constant}) 25 | 26 | return parsed_code 27 | 28 | 29 | if __name__ == "__main__": 30 | with open(sys.argv[1]) as source_file: 31 | source = source_file.read() 32 | code = compile(source, sys.argv[1], "exec") 33 | print(json.dumps(parse_code(code))) 34 | -------------------------------------------------------------------------------- /bytecode_gen/source.py: -------------------------------------------------------------------------------- 1 | # source: https://www.geeksforgeeks.org/python-program-for-program-for-fibonacci-numbers-2/ 2 | 3 | def fibonacci(n): 4 | if n < 0: 5 | print("Incorrect input") 6 | elif n == 1: 7 | return 0 8 | elif n == 2: 9 | return 1 10 | else: 11 | 12 | return fibonacci(n - 1) + fibonacci(n - 2) 13 | 14 | print(fibonacci(9)) -------------------------------------------------------------------------------- /compile_to_json.bat: -------------------------------------------------------------------------------- 1 | py bytecode_gen\recursive_dis.py bytecode_gen\source.py > bytecode.json 2 | pause -------------------------------------------------------------------------------- /compile_to_json_and_run.bat: -------------------------------------------------------------------------------- 1 | py bytecode_gen\recursive_dis.py bytecode_gen\source.py > bytecode.json 2 | cargo run bytecode.json 3 | pause -------------------------------------------------------------------------------- /run.bat: -------------------------------------------------------------------------------- 1 | cargo run bytecode.json 2 | pause -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::Ordering; 2 | use std::collections::HashMap; 3 | use std::env; 4 | use std::fs; 5 | use std::ops::{Add, Sub, Mul, Div}; 6 | use std::rc::Rc; 7 | use std::time::Instant; 8 | 9 | use serde::Deserialize; 10 | use serde_json; 11 | 12 | enum CompareOps { 13 | LessThan, 14 | LessThanOrEqual, 15 | Equal, 16 | NotEqual, 17 | GreaterThan, 18 | GreaterThanOrEqual 19 | } 20 | 21 | impl From for CompareOps { 22 | fn from(op: usize) -> Self { 23 | match op { 24 | 0 => Self::LessThan, 25 | 1 => Self::LessThanOrEqual, 26 | 2 => Self::Equal, 27 | 3 => Self::NotEqual, 28 | 4 => Self::GreaterThan, 29 | 5 => Self::GreaterThanOrEqual, 30 | _ => panic!("Unimplemented cmp_op") 31 | } 32 | } 33 | } 34 | 35 | #[derive(Copy, Clone, Debug, Deserialize)] 36 | enum Instruction { 37 | LoadConst(usize), 38 | StoreName(usize), 39 | LoadName(usize), 40 | DeleteName(usize), 41 | StoreFast(usize), 42 | LoadFast(usize), 43 | DeleteFast(usize), 44 | StoreGlobal(usize), 45 | LoadGlobal(usize), 46 | DeleteGlobal(usize), 47 | CompareOp(usize), 48 | JumpForward(usize), 49 | PopJumpIfTrue(usize), 50 | PopJumpIfFalse(usize), 51 | JumpIfTrueOrPop(usize), 52 | JumpIfFalseOrPop(usize), 53 | MakeFunction(usize), 54 | CallFunction(usize), 55 | JumpAbsolute(usize), 56 | ReturnValue, 57 | InplaceAdd, 58 | InplaceSubtract, 59 | InplaceMultiply, 60 | InplaceTrueDivide, 61 | InplaceFloorDivide, 62 | BinaryAdd, 63 | BinarySubtract, 64 | BinaryMultiply, 65 | BinaryTrueDivide, 66 | BinaryFloorDivide, 67 | Nop, 68 | PopTop, 69 | RotTwo, 70 | RotThree, 71 | RotFour, 72 | DupTop, 73 | DupTopTwo, 74 | UnaryPositive, 75 | UnaryNegative, 76 | 77 | Print, 78 | } 79 | 80 | #[derive(Clone, Debug, Deserialize)] 81 | enum Value { 82 | Int(i32), 83 | Bool(bool), 84 | Float(f32), 85 | Str(String), 86 | Nonetype, 87 | Frame(Frame) 88 | } 89 | 90 | impl Default for Value { 91 | fn default() -> Self { Value::Nonetype } 92 | } 93 | 94 | impl PartialEq for Value { 95 | fn eq(&self, other: &Self) -> bool { 96 | match (self, other) { 97 | (Value::Int(first), Value::Int(second)) => first == second, 98 | (Value::Bool(first), Value::Bool(second)) => first == second, 99 | (Value::Str(first), Value::Str(second)) => first == second, 100 | (Value::Float(first), Value::Float(second)) => first == second, 101 | 102 | (Value::Float(first), Value::Int(second)) | (Value::Int(second), Value::Float(first)) => (*second as f32).eq( first), 103 | (Value::Float(first), Value::Bool(second)) | (Value::Bool(second), Value::Float(first)) => first == &((*second as i32) as f32), 104 | (Value::Bool(first), Value::Int(second)) | (Value::Int(second), Value::Bool(first)) => (*first as i32).eq(second), 105 | 106 | _ => panic!("Unimplemented comparision between {:?} and {:?}", self, other) 107 | } 108 | } 109 | } 110 | 111 | impl PartialOrd for Value { 112 | fn partial_cmp(&self, other: &Self) -> Option { 113 | match (self, other) { 114 | (Value::Int(first), Value::Int(second)) => first.partial_cmp(second), 115 | (Value::Bool(first), Value::Bool(second)) => first.partial_cmp(second), 116 | (Value::Str(first), Value::Str(second)) => first.partial_cmp(second), 117 | (Value::Float(first), Value::Float(second)) => first.partial_cmp(second), 118 | 119 | (Value::Float(first), Value::Int(second)) | (Value::Int(second), Value::Float(first)) => first.partial_cmp(&(*second as f32)), 120 | (Value::Float(first), Value::Bool(second)) | (Value::Bool(second), Value::Float(first)) => first.partial_cmp(&((*second as i32) as f32)), 121 | (Value::Bool(first), Value::Int(second)) | (Value::Int(second), Value::Bool(first)) => (*first as i32).partial_cmp(second), 122 | 123 | _ => panic!("Unimplemented comparision between {:?} and {:?}", self, other) 124 | } 125 | } 126 | } 127 | 128 | impl Add for Value { 129 | type Output = Value; 130 | 131 | fn add(self, rhs: Self) -> Self::Output { 132 | match (&self, &rhs) { 133 | (Value::Int(first), Value::Int(second)) => Value::Int(first + second), 134 | (Value::Float(first), Value::Float(second)) => Value::Float(first + second), 135 | (Value::Bool(first), Value::Bool(second)) => Value::Int((*first as i32) + (*second as i32)), 136 | (Value::Str(first), Value::Str(second)) => Value::Str(first.clone() + second), 137 | (Value::Float(first), Value::Int(second)) | (Value::Int(second), Value::Float(first)) => Value::Float(first + (*second as f32)), 138 | (Value::Bool(first), Value::Int(second)) | (Value::Int(second), Value::Bool(first)) => Value::Int((*first as i32) + second), 139 | 140 | _ => panic!("Unimplemented 'add' operation between {:?} and {:?}", self, rhs) 141 | } 142 | } 143 | } 144 | 145 | impl Sub for Value { 146 | type Output = Value; 147 | 148 | fn sub(self, rhs: Self) -> Self::Output { 149 | match (&self, &rhs) { 150 | (Value::Int(first), Value::Int(second)) => Value::Int(first - second), 151 | (Value::Float(first), Value::Float(second)) => Value::Float(first - second), 152 | (Value::Bool(first), Value::Bool(second)) => Value::Int((*first as i32) - (*second as i32)), 153 | (Value::Float(first), Value::Int(second)) | (Value::Int(second), Value::Float(first)) => Value::Float(first - (*second as f32)), 154 | (Value::Bool(first), Value::Int(second)) | (Value::Int(second), Value::Bool(first)) => Value::Int((*first as i32) - second), 155 | 156 | _ => panic!("Unimplemented 'add' operation between {:?} and {:?}", self, rhs) 157 | } 158 | } 159 | } 160 | 161 | impl Mul for Value { 162 | type Output = Value; 163 | 164 | fn mul(self, rhs: Self) -> Self::Output { 165 | match (&self, &rhs) { 166 | (Value::Int(first), Value::Int(second)) => Value::Int(first * second), 167 | (Value::Float(first), Value::Float(second)) => Value::Float(first * second), 168 | (Value::Bool(first), Value::Bool(second)) => Value::Int((*first as i32) * (*second as i32)), 169 | (Value::Str(first), Value::Int(second)) | (Value::Int(second), Value::Str(first)) => { 170 | let mut res = first.clone(); 171 | for _ in 1..*second { 172 | res += first; 173 | }; 174 | Value::Str(res) 175 | }, 176 | (Value::Float(first), Value::Int(second)) | (Value::Int(second), Value::Float(first)) => Value::Float(first * (*second as f32)), 177 | (Value::Bool(first), Value::Int(second)) | (Value::Int(second), Value::Bool(first)) => Value::Int((*first as i32) * second), 178 | 179 | _ => panic!("Unimplemented 'add' operation between {:?} and {:?}", self, rhs) 180 | } 181 | } 182 | } 183 | 184 | impl Div for Value { 185 | type Output = Value; 186 | 187 | fn div(self, rhs: Self) -> Self::Output { 188 | match (&self, &rhs) { 189 | (Value::Int(first), Value::Int(second)) => Value::Float((*first as f32) / (*second as f32)), 190 | (Value::Float(first), Value::Float(second)) => Value::Float(first / second), 191 | (Value::Bool(first), Value::Bool(second)) => Value::Float((*first as i32) as f32 / (*second as i32) as f32), 192 | (Value::Float(first), Value::Int(second)) | (Value::Int(second), Value::Float(first)) => Value::Float(first / (*second as f32)), 193 | (Value::Bool(first), Value::Int(second)) | (Value::Int(second), Value::Bool(first)) => Value::Float((*first as i32) as f32 / (*second as i32) as f32), 194 | 195 | _ => panic!("Unimplemented 'add' operation between {:?} and {:?}", self, rhs) 196 | } 197 | } 198 | } 199 | 200 | #[derive(Clone, Debug, Deserialize)] 201 | struct Frame { 202 | instructions: Vec, 203 | constants: Vec, 204 | co_names: Vec>, 205 | co_varnames: Vec>, 206 | 207 | #[serde(default)] 208 | stack: Vec, 209 | #[serde(default)] 210 | index: usize, 211 | #[serde(default)] 212 | globals: HashMap, Value>, 213 | #[serde(default)] 214 | locals: HashMap, Value>, 215 | #[serde(default)] 216 | return_value: Box, 217 | #[serde(default)] 218 | depth: usize, 219 | } 220 | 221 | impl Frame { 222 | fn run(&mut self) { 223 | while let Some(instruction) = self.instructions.get(self.index) { 224 | match *instruction { 225 | Instruction::LoadConst(arg) => self.load_const(arg), 226 | Instruction::StoreName(arg) => self.store_name(arg), 227 | Instruction::LoadName(arg) => self.load_name(arg), 228 | Instruction::DeleteName(arg) => self.delete_name(arg), 229 | Instruction::StoreFast(arg) => self.store_fast(arg), 230 | Instruction::LoadFast(arg) => self.load_fast(arg), 231 | Instruction::DeleteFast(arg) => self.delete_fast(arg), 232 | Instruction::StoreGlobal(arg) => self.store_global(arg), 233 | Instruction::LoadGlobal(arg) => self.load_global(arg), 234 | Instruction::DeleteGlobal(arg) => self.delete_global(arg), 235 | Instruction::CompareOp(arg) => self.compare_op(arg), 236 | Instruction::JumpForward(arg) => { self.index += arg / 2 + 1; }, 237 | Instruction::PopJumpIfTrue(arg) => self.pop_jump_if_true(arg), 238 | Instruction::PopJumpIfFalse(arg) => self.pop_jump_if_false(arg), 239 | Instruction::JumpIfTrueOrPop(arg) => self.jump_if_true_or_pop(arg), 240 | Instruction::JumpIfFalseOrPop(arg) => self.jump_if_false_or_pop(arg), 241 | Instruction::JumpAbsolute(arg) => { self.index = arg / 2; }, 242 | Instruction::MakeFunction(arg) => self.make_function(arg), 243 | Instruction::CallFunction(arg) => self.call_function(arg), 244 | Instruction::ReturnValue => self.return_value(), 245 | Instruction::InplaceAdd => self.add(), 246 | Instruction::InplaceSubtract => self.subtract(), 247 | Instruction::InplaceMultiply => self.multiply(), 248 | Instruction::InplaceTrueDivide => self.true_divide(), 249 | Instruction::InplaceFloorDivide => self.floor_divide(), 250 | Instruction::BinaryAdd => self.add(), 251 | Instruction::BinarySubtract => self.subtract(), 252 | Instruction::BinaryMultiply => self.multiply(), 253 | Instruction::BinaryTrueDivide => self.true_divide(), 254 | Instruction::BinaryFloorDivide => self.floor_divide(), 255 | Instruction::Nop => { self.index += 1; }, 256 | Instruction::PopTop => self.pop_top(), 257 | Instruction::RotTwo => self.rot_two(), 258 | Instruction::RotThree => self.rot_three(), 259 | Instruction::RotFour => self.rot_four(), 260 | Instruction::DupTop => self.dup_top(), 261 | Instruction::DupTopTwo => self.dup_top_two(), 262 | Instruction::UnaryPositive => { self.index += 1 }, 263 | Instruction::UnaryNegative => self.unary_negative(), 264 | 265 | Instruction::Print => self.print(), 266 | }; 267 | }; 268 | } 269 | 270 | fn load_const(&mut self, arg: usize) { 271 | self.stack.push(self.constants[arg].clone()); 272 | 273 | self.index += 1; 274 | } 275 | 276 | fn store_name(&mut self, arg: usize) { 277 | self.locals.insert(Rc::clone(&self.co_names[arg]), self.stack.pop().unwrap()); 278 | 279 | self.index += 1; 280 | } 281 | 282 | fn load_name(&mut self, arg: usize) { 283 | self.stack.push(self.locals[&self.co_names[arg]].clone()); 284 | 285 | self.index += 1; 286 | } 287 | 288 | fn delete_name(&mut self, arg: usize) { 289 | self.locals.remove(&self.co_names[arg]); 290 | 291 | self.index += 1; 292 | } 293 | 294 | fn store_fast(&mut self, arg: usize) { 295 | self.locals.insert(Rc::clone(&self.co_varnames[arg]), self.stack.pop().unwrap()); 296 | 297 | self.index += 1; 298 | } 299 | 300 | fn load_fast(&mut self, arg: usize) { 301 | self.stack.push(self.locals.get(&self.co_varnames[arg]).unwrap().clone()); 302 | 303 | self.index += 1; 304 | } 305 | 306 | fn delete_fast(&mut self, arg: usize) { 307 | self.locals.remove(&self.co_varnames[arg]); 308 | 309 | self.index += 1; 310 | } 311 | 312 | fn store_global(&mut self, arg: usize) { 313 | self.globals.insert(Rc::clone(&self.co_names[arg]), self.stack.pop().unwrap()); 314 | 315 | self.index += 1; 316 | } 317 | 318 | fn load_global(&mut self, arg: usize) { 319 | self.stack.push(self.globals.get(&self.co_names[arg]).unwrap().clone()); 320 | 321 | self.index += 1; 322 | } 323 | 324 | fn delete_global(&mut self, arg: usize) { 325 | self.globals.remove(&self.co_names[arg]); 326 | 327 | self.index += 1; 328 | } 329 | 330 | fn compare_op(&mut self, arg: usize) { 331 | let second_var = self.stack.pop().unwrap(); 332 | let first_var = self.stack.pop().unwrap(); 333 | 334 | self.stack.push(Value::Bool( 335 | match CompareOps::from(arg) { 336 | CompareOps::LessThan => first_var < second_var, 337 | CompareOps::LessThanOrEqual => first_var <= second_var, 338 | CompareOps::Equal => first_var == second_var, 339 | CompareOps::NotEqual => first_var != second_var, 340 | CompareOps::GreaterThan => first_var > second_var, 341 | CompareOps::GreaterThanOrEqual => first_var >= second_var, 342 | } 343 | )); 344 | 345 | self.index += 1; 346 | } 347 | 348 | fn pop_jump_if_true(&mut self, arg: usize) { 349 | if let Value::Bool(result) = self.stack.pop().unwrap() { 350 | if result { 351 | self.index = arg / 2; 352 | } else { 353 | self.index += 1; 354 | } 355 | } else { 356 | panic!("Invalid `Value` passed to compare"); 357 | } 358 | } 359 | 360 | fn pop_jump_if_false(&mut self, arg: usize) { 361 | if let Value::Bool(result) = self.stack.pop().unwrap() { 362 | if !result { 363 | self.index = arg / 2; 364 | } else { 365 | self.index += 1; 366 | } 367 | } else { 368 | panic!("Invalid `Value` passed to compare"); 369 | } 370 | } 371 | 372 | fn jump_if_true_or_pop(&mut self, arg: usize) { 373 | if let Value::Bool(result) = self.stack.last().unwrap() { 374 | if *result { 375 | self.index = arg / 2; 376 | } else { 377 | self.stack.pop(); 378 | 379 | self.index += 1; 380 | } 381 | } else { 382 | panic!("Invalid `Value` passed to compare"); 383 | } 384 | } 385 | 386 | fn jump_if_false_or_pop(&mut self, arg: usize) { 387 | if let Value::Bool(result) = self.stack.last().unwrap() { 388 | if !(*result) { 389 | self.index = arg / 2; 390 | } else { 391 | self.stack.pop(); 392 | 393 | self.index += 1; 394 | } 395 | } else { 396 | panic!("Invalid `Value` passed to compare"); 397 | } 398 | } 399 | 400 | fn make_function(&mut self, arg: usize) { 401 | if arg != 0 { 402 | panic!("Unimplemented function flag") 403 | } 404 | 405 | if let (Value::Str(_), Value::Frame(frame)) = (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { 406 | self.stack.push( Value::Frame(frame)); 407 | } else { 408 | panic!("Wrong types for TOS and TOS1") 409 | } 410 | 411 | self.index += 1; 412 | } 413 | 414 | fn call_function(&mut self, arg: usize) { 415 | if let Value::Frame(mut frame) = self.stack.remove(self.stack.len() - arg - 1) { 416 | for i in 0..arg { 417 | frame.locals.insert(Rc::clone(&frame.co_varnames[frame.co_varnames.len() - i - 1]), self.stack.pop().unwrap()); 418 | }; 419 | // These were not supposed to be clones but lifetimes are hard 420 | if self.depth == 0 { 421 | frame.globals = self.locals.clone(); 422 | } else { 423 | frame.globals = self.globals.clone(); 424 | } 425 | frame.depth += self.depth + 1; 426 | frame.run(); 427 | self.stack.push(*frame.return_value); 428 | } else { 429 | panic!("Wrong type for TOS"); 430 | } 431 | 432 | self.index += 1; 433 | } 434 | 435 | fn return_value(&mut self) { 436 | self.return_value = Box::new(self.stack.pop().unwrap()); 437 | 438 | self.index = self.instructions.len(); 439 | } 440 | 441 | fn add(&mut self) { 442 | let mut result = self.stack.pop().unwrap(); 443 | result = self.stack.pop().unwrap() + result; 444 | self.stack.push(result); 445 | 446 | self.index += 1; 447 | } 448 | 449 | fn subtract(&mut self) { 450 | let mut result = self.stack.pop().unwrap(); 451 | result = self.stack.pop().unwrap() - result; 452 | self.stack.push(result); 453 | 454 | self.index += 1; 455 | } 456 | 457 | fn multiply(&mut self) { 458 | let mut result = self.stack.pop().unwrap(); 459 | result = self.stack.pop().unwrap() * result; 460 | self.stack.push(result); 461 | 462 | self.index += 1; 463 | } 464 | 465 | fn true_divide(&mut self) { 466 | let mut result = self.stack.pop().unwrap(); 467 | result = self.stack.pop().unwrap() / result; 468 | self.stack.push(result); 469 | 470 | self.index += 1; 471 | } 472 | 473 | fn floor_divide(&mut self) { 474 | let mut result = self.stack.pop().unwrap(); 475 | result = self.stack.pop().unwrap() / result; 476 | if let Value::Float(result) = result { 477 | self.stack.push(Value::Int(result as i32)); 478 | } else { 479 | self.stack.push(result); 480 | } 481 | 482 | self.index += 1; 483 | } 484 | 485 | fn pop_top(&mut self) { 486 | self.stack.pop(); 487 | 488 | self.index += 1; 489 | } 490 | 491 | fn rot_two(&mut self) { 492 | let last_pos = self.stack.len() - 1; 493 | self.stack.swap(last_pos, last_pos - 1); 494 | 495 | self.index += 1; 496 | } 497 | 498 | fn rot_three(&mut self) { 499 | let last_pos = self.stack.len() - 1; 500 | self.stack.swap(last_pos, last_pos - 1); 501 | self.stack.swap(last_pos - 1, last_pos - 2); 502 | 503 | self.index += 1; 504 | } 505 | 506 | fn rot_four(&mut self) { 507 | let last_pos = self.stack.len() - 1; 508 | self.stack.swap(last_pos, last_pos - 1); 509 | self.stack.swap(last_pos - 1, last_pos - 2); 510 | self.stack.swap(last_pos - 2, last_pos - 3); 511 | 512 | self.index += 1; 513 | } 514 | 515 | fn dup_top(&mut self) { 516 | self.stack.push(self.stack.last().unwrap().clone()); 517 | 518 | self.index += 1; 519 | } 520 | 521 | fn dup_top_two(&mut self) { 522 | self.stack.push(self.stack[self.stack.len() - 1].clone()); 523 | self.stack.insert(self.stack.len() - 3, self.stack[self.stack.len() - 3].clone()); 524 | 525 | self.index += 1; 526 | } 527 | 528 | fn unary_negative(&mut self) { 529 | let negative = Value::Int(0) - self.stack.pop().unwrap(); 530 | self.stack.push(negative); 531 | 532 | self.index += 1; 533 | } 534 | 535 | fn create_print_frame() -> Frame { 536 | Frame { 537 | instructions: vec![ 538 | Instruction::LoadFast(0), 539 | Instruction::Print 540 | ], 541 | constants: vec![Value::Str(String::from("to_print"))], 542 | co_names: vec![], 543 | co_varnames: vec![Rc::new(String::from("to_print"))], 544 | stack: vec![], 545 | index: 0, 546 | globals: Default::default(), 547 | locals: Default::default(), 548 | return_value: Box::new(Value::Nonetype), 549 | depth: 0 550 | } 551 | } 552 | 553 | fn print(&mut self) { 554 | match self.stack.pop().unwrap() { 555 | Value::Int(val) => println!("{}", val), 556 | Value::Bool(val) => println!("{}", val), 557 | Value::Float(val) => println!("{}", val), 558 | Value::Str(val) => println!("{}", val), 559 | Value::Nonetype => println!("None"), 560 | Value::Frame(val) => println!("{:#?}", val) 561 | } 562 | 563 | self.index += 1; 564 | } 565 | } 566 | 567 | fn main() { 568 | let args: Vec = env::args().collect(); 569 | let mut frame: Frame = serde_json::from_str(&fs::read_to_string(&args[1]).unwrap()).unwrap(); 570 | frame.locals.insert(Rc::new(String::from("print")), Value::Frame(Frame::create_print_frame())); 571 | 572 | let now = Instant::now(); 573 | frame.run(); 574 | println!("Running Took: {:?}", now.elapsed()); 575 | } 576 | --------------------------------------------------------------------------------