├── vm ├── .gitignore ├── src │ ├── jit │ │ ├── mod.rs │ │ └── cpu │ │ │ ├── x64 │ │ │ ├── mod.rs │ │ │ ├── param.rs │ │ │ └── reg.rs │ │ │ └── mod.rs │ ├── index.rs │ ├── static_root.rs │ ├── lib.rs │ ├── string.rs │ ├── main.rs │ ├── error.rs │ ├── object.rs │ ├── object_info.rs │ ├── frame.rs │ ├── object_pool.rs │ ├── function.rs │ ├── value.rs │ ├── opcodes.rs │ └── machine.rs ├── rustfmt.toml ├── simple_jazz │ ├── src │ │ ├── lib.rs │ │ ├── context.rs │ │ └── builder.rs │ ├── Cargo.toml │ ├── examples │ │ ├── simple_ast.rs │ │ └── math.rs │ └── Cargo.lock ├── bytecode │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ ├── main.rs │ │ ├── opcode.rs │ │ ├── assembler.rs │ │ └── parser.rs │ └── Cargo.lock ├── Cargo.toml ├── appveyor.yml ├── LICENSE ├── tests │ ├── load_at.rs │ ├── factorial.rs │ └── store_at_load_at.rs ├── benches │ └── factorial_bench.rs └── Cargo.lock ├── rewrite ├── .gitignore ├── src │ └── main.cc └── meson.build ├── .vscode ├── settings.json └── launch.json ├── examples ├── hello_world.jazz ├── for.jazz ├── access.jazz ├── while.jazz ├── variables.jazz ├── isa.jazz ├── map.jazz ├── classes.jazz └── factorial.jazz ├── .gitignore ├── src ├── lib.rs ├── main.rs ├── std_library │ └── mod.rs ├── class.rs ├── ircode.rs ├── builtins.rs └── compiler.rs ├── Cargo.toml ├── stdlib ├── io.jazz └── math.jazz ├── LICENSE ├── README.md ├── appveyor.yml └── Cargo.lock /vm/.gitignore: -------------------------------------------------------------------------------- 1 | /target -------------------------------------------------------------------------------- /rewrite/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /vm/src/jit/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cpu; 2 | -------------------------------------------------------------------------------- /vm/src/index.rs: -------------------------------------------------------------------------------- 1 | pub const CALL: u8 = 0; 2 | -------------------------------------------------------------------------------- /rewrite/src/main.cc: -------------------------------------------------------------------------------- 1 | int main() { 2 | 3 | } -------------------------------------------------------------------------------- /vm/src/jit/cpu/x64/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod param; 2 | pub mod reg; 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "debug.node.autoAttach": "off" 3 | } -------------------------------------------------------------------------------- /examples/hello_world.jazz: -------------------------------------------------------------------------------- 1 | func main() 2 | { 3 | System.print("Hello world!"); 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | /.idea 4 | ./simple_jazz/target 5 | /vm/target 6 | ./vm/target -------------------------------------------------------------------------------- /vm/rustfmt.toml: -------------------------------------------------------------------------------- 1 | merge_imports = true 2 | 3 | imports_layout = "Horizontal" 4 | brace_style = "AlwaysNextLine" -------------------------------------------------------------------------------- /vm/simple_jazz/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate jazz; 2 | 3 | 4 | pub use jazz::*; 5 | 6 | pub mod context; 7 | pub mod builder; -------------------------------------------------------------------------------- /examples/for.jazz: -------------------------------------------------------------------------------- 1 | func main() 2 | { 3 | for (var i = 0; i < 1000; i += 1) { 4 | 5 | } 6 | 7 | System.print(i); 8 | } -------------------------------------------------------------------------------- /examples/access.jazz: -------------------------------------------------------------------------------- 1 | func basic(a,b) { 2 | return a + b; 3 | } 4 | 5 | 6 | func main() { 7 | System.print(basic.disassemble()); 8 | } -------------------------------------------------------------------------------- /examples/while.jazz: -------------------------------------------------------------------------------- 1 | func main() 2 | { 3 | var i = 1000; 4 | while i > 0 { 5 | i = i - 1; 6 | } 7 | System.print(i); 8 | } 9 | -------------------------------------------------------------------------------- /vm/src/jit/cpu/x64/param.rs: -------------------------------------------------------------------------------- 1 | pub static OFFSTET: isize = 16; 2 | 3 | pub fn next_param_offset(param_offset: isize) -> isize 4 | { 5 | param_offset + 8 6 | } 7 | -------------------------------------------------------------------------------- /rewrite/meson.build: -------------------------------------------------------------------------------- 1 | project('jazz','cpp','c') 2 | 3 | 4 | incdir = include_directories(['src']) 5 | 6 | src = ['src/main.cc'] 7 | 8 | executable('jazz',src,include_directories: incdir) -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | 3 | pub mod builtins; 4 | pub mod class; 5 | pub mod compiler; 6 | pub mod ircode; 7 | pub mod parser; 8 | pub mod std_library; 9 | pub use self::compiler::Compiler; 10 | -------------------------------------------------------------------------------- /examples/variables.jazz: -------------------------------------------------------------------------------- 1 | func add2(n) 2 | { 3 | return n + 2; 4 | } 5 | 6 | 7 | func main() 8 | { 9 | var function = add2; 10 | 11 | System.print(function(4)); 12 | return 0; 13 | } 14 | 15 | 16 | -------------------------------------------------------------------------------- /vm/simple_jazz/src/context.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use jazz::function::Function; 3 | use jazz::opcodes::Instruction; 4 | use jazz::value::Value; 5 | 6 | #[derive(Debug,Clone)] 7 | pub struct Context { 8 | pub builder: (), 9 | } -------------------------------------------------------------------------------- /examples/isa.jazz: -------------------------------------------------------------------------------- 1 | func test(v) { 2 | if v~Int { 3 | return "Int"; 4 | } 5 | if v~Float { 6 | return "Float"; 7 | } 8 | } 9 | 10 | func main() { 11 | System.print(test(2)); 12 | System.print(test(2.5)) 13 | } -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jazz" 3 | version = "0.1.0" 4 | authors = ["Adel Prokurov "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | jazz-vm = {path = "vm"} 9 | time = "0.1.40" 10 | structopt = "0.2.13" 11 | float_duration = "0.3.3" 12 | -------------------------------------------------------------------------------- /vm/simple_jazz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "simple_jazz" 3 | version = "0.1.0" 4 | authors = ["Adel Prokurov "] 5 | edition = "2018" 6 | description = "Library used for simple code generation for JazzVM" 7 | license = "MIT" 8 | keywords = ["codegen","vm"] 9 | 10 | [dependencies] 11 | jazz = "0.1" 12 | mex = "0.1.0" -------------------------------------------------------------------------------- /vm/bytecode/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jazz_bytecode" 3 | version = "0.1.0" 4 | authors = ["Adel Prokurov "] 5 | edition = "2018" 6 | description = "Library used for encoding/decoding JazzVM instructions" 7 | license = "MIT" 8 | keywords = ["codegen","vm","encoding","decoding"] 9 | 10 | [dependencies] 11 | jazz = "0.2.0" -------------------------------------------------------------------------------- /stdlib/io.jazz: -------------------------------------------------------------------------------- 1 | class File { 2 | 3 | func init(name) { 4 | return this; 5 | } 6 | 7 | func read() { 8 | // TODO 9 | } 10 | 11 | func open() { 12 | // TODO 13 | } 14 | 15 | func create() { 16 | // TODO 17 | } 18 | 19 | func delete() { 20 | // TODO 21 | } 22 | 23 | func copy(to) { 24 | // TODO 25 | } 26 | } -------------------------------------------------------------------------------- /stdlib/math.jazz: -------------------------------------------------------------------------------- 1 | func pow(x,y) { 2 | var result = x; 3 | 4 | for (var i = 1; i < y; i += 1) { 5 | result = result + x; 6 | } 7 | 8 | return result; 9 | } 10 | 11 | 12 | 13 | 14 | /// TODO: Make this function working 15 | func sqrt(x) { 16 | var z = 1; 17 | for (var i = 0; i < 10; i += 1) { 18 | z -= (z*z - x) / (2 * z); 19 | } 20 | 21 | return z; 22 | } -------------------------------------------------------------------------------- /vm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jazz-vm" 3 | version = "0.2.2" 4 | authors = ["Adel Prokurov "] 5 | edition = "2018" 6 | description = "Jazz Virtual Machine" 7 | readme = "README.md" 8 | repository = "https://github.com/playXE/Jazz" 9 | keywords = ["vm","register","register-based"] 10 | license = "MIT" 11 | 12 | 13 | [profile.dev] 14 | 15 | [profile.release] 16 | lto = true 17 | 18 | [dependencies] 19 | time = "0.1.40" 20 | libc = "0.2.43" 21 | colored = "1.6.1" -------------------------------------------------------------------------------- /examples/map.jazz: -------------------------------------------------------------------------------- 1 | func map(array,fn) 2 | { 3 | var size = array.size(); 4 | var new_array = []; 5 | 6 | for (var k = 0; k < size;k += 1) { 7 | 8 | new_array.push(fn(array[k])); 9 | } 10 | return new_array; 11 | } 12 | 13 | func fib(n) { 14 | if n == 0 || n == 1 { 15 | return n; 16 | } 17 | 18 | return fib(n - 1) + fib(n - 2); 19 | } 20 | 21 | func main() 22 | { 23 | var array = []; 24 | var i = 0; 25 | while i < 10 { 26 | 27 | array.push(i); 28 | i += 1; 29 | } 30 | var ret = map(array,fib); 31 | return ret; 32 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Используйте IntelliSense, чтобы узнать о возможных атрибутах. 3 | // Наведите указатель мыши, чтобы просмотреть описания существующих атрибутов. 4 | // Для получения дополнительной информации посетите: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "lldb", 9 | "request": "launch", 10 | "name": "Debug", 11 | "program": "${workspaceFolder}/", 12 | "args": [], 13 | "cwd": "${workspaceFolder}" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /vm/bytecode/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | #![allow(non_upper_case_globals)] 3 | extern crate jazz; 4 | 5 | 6 | pub mod opcode; 7 | pub mod parser; 8 | pub mod assembler; 9 | 10 | #[macro_export] 11 | macro_rules! encode { 12 | ($v:expr; $t: ty) => { 13 | unsafe { 14 | ::std::mem::transmute::<$t,[u8;::std::mem::size_of::<$t>()]>($v) 15 | } 16 | }; 17 | } 18 | 19 | #[macro_export] 20 | macro_rules! decode { 21 | ($arr: expr; $t: ty) => { 22 | unsafe { 23 | ::std::mem::transmute::<[u8;::std::mem::size_of::<$t>()],$t>($arr) 24 | } 25 | }; 26 | } -------------------------------------------------------------------------------- /vm/bytecode/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate jazz_bytecode; 2 | extern crate jazz; 3 | use jazz_bytecode::opcode::*; 4 | use jazz_bytecode::parser::Parser; 5 | use jazz_bytecode::encode; 6 | use jazz_bytecode::assembler::Assembler; 7 | use jazz::opcodes::Instruction; 8 | 9 | fn main() { 10 | let mut assembler = Assembler::new(vec![ 11 | Instruction::LoadInt(1,12), 12 | Instruction::Move(1,2), 13 | ]); 14 | 15 | assembler.translate(); 16 | 17 | println!("{:?}",assembler.code); 18 | 19 | let mut parser = Parser::new(&assembler.code); 20 | let code = parser.parse(); 21 | println!("{:?}",code); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /examples/classes.jazz: -------------------------------------------------------------------------------- 1 | class Point { 2 | 3 | // x and y will be null 4 | var x; 5 | var y; 6 | 7 | func init(a,b) { 8 | this.x = a; 9 | this.y = b; 10 | return this; 11 | } 12 | 13 | func display() { 14 | System.print(this.toString()); 15 | } 16 | 17 | func move(x,y) { 18 | this.x = this.x + x; 19 | this.y = this.y + y; 20 | } 21 | 22 | func toString() { 23 | return concat("(",this.x,";",this.y,")"); 24 | } 25 | } 26 | 27 | func main() { 28 | var point = Point(2.5,5); // until initializing `Point` just a function 29 | point.display(); 30 | } -------------------------------------------------------------------------------- /examples/factorial.jazz: -------------------------------------------------------------------------------- 1 | func fac(n) { 2 | if n == 0 { 3 | return 1; 4 | } 5 | return fac(n - 1) * n; 6 | } 7 | 8 | class Factorial { 9 | func init(v) { 10 | this._v = v; 11 | return this; 12 | } 13 | 14 | func value() { 15 | if this._v == 0 { 16 | return 1; 17 | } 18 | 19 | var f = Factorial(this._v - 1); 20 | var v = this._v; 21 | 22 | 23 | return f.value() * v; 24 | } 25 | } 26 | 27 | func main() { 28 | var v = Factorial.value; 29 | System.print("Class based factorial(5) = ",Factorial(5).value()); 30 | System.print("Recursive factorial(5) = ",fac(5)); 31 | } -------------------------------------------------------------------------------- /vm/appveyor.yml: -------------------------------------------------------------------------------- 1 | os: Visual Studio 2015 2 | environment: 3 | global: 4 | PROJECT_NAME: Jazz 5 | RUSTUP_INIT_SKIP_MSVC_CHECK: 1 6 | matrix: 7 | - TARGET: x86_64-pc-windows-msvc 8 | CHANNEL: nightly 9 | 10 | install: 11 | - curl -sSf -o rustup-init.exe https://win.rustup.rs 12 | - rustup-init.exe --default-host %TARGET% --default-toolchain %CHANNEL% -y 13 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin 14 | - rustc -Vv 15 | - cargo -V 16 | 17 | before_test: 18 | - cd %APPVEYOR_BUILD_FOLDER% 19 | 20 | test_script: 21 | - cargo build --verbose 22 | - cargo test --verbose 23 | 24 | # 'cargo test' takes care of building for us, so disable Appveyor's build stage. This prevents 25 | # the "directory does not contain a project or solution file" error. 26 | # source: https://github.com/starkat99/appveyor-rust/blob/master/appveyor.yml#L113 27 | build: false 28 | -------------------------------------------------------------------------------- /vm/src/static_root.rs: -------------------------------------------------------------------------------- 1 | use crate::object::{Object, ObjectAddon}; 2 | use std::{any::Any, cell::RefCell}; 3 | #[derive(Default)] 4 | pub struct StaticRoot 5 | { 6 | children: RefCell>, 7 | } 8 | 9 | impl ObjectAddon for StaticRoot {} 10 | 11 | impl Object for StaticRoot 12 | { 13 | fn get_children(&self) -> Vec 14 | { 15 | self.children.borrow().clone() 16 | } 17 | 18 | fn as_any(&self) -> &dyn Any 19 | { 20 | self as &dyn Any 21 | } 22 | 23 | fn as_any_mut(&mut self) -> &mut dyn Any 24 | { 25 | self as &mut dyn Any 26 | } 27 | } 28 | 29 | impl StaticRoot 30 | { 31 | pub fn new() -> StaticRoot 32 | { 33 | StaticRoot { 34 | children: RefCell::new(Vec::new()), 35 | } 36 | } 37 | 38 | pub fn append_child(&self, id: usize) 39 | { 40 | self.children.borrow_mut().push(id); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate jazz; 2 | extern crate jazz_vm; 3 | extern crate structopt; 4 | use jazz::{ 5 | parser::{lex, parse}, 6 | Compiler, 7 | }; 8 | use jazz_vm::machine::Machine; 9 | 10 | use std::{fs::File, io::prelude::*, path::PathBuf}; 11 | use structopt::StructOpt; 12 | 13 | #[derive(StructOpt, Debug)] 14 | pub struct Options { 15 | #[structopt(name = "FILE", parse(from_os_str))] 16 | file: Option, 17 | #[structopt(short = "d", long = "debug")] 18 | debug: bool, 19 | } 20 | 21 | fn main() { 22 | let mut src = String::new(); 23 | 24 | let ops = Options::from_args(); 25 | 26 | if let Some(path) = ops.file { 27 | File::open(path).unwrap().read_to_string(&mut src).unwrap(); 28 | } else { 29 | panic!("You should enter file path"); 30 | } 31 | 32 | let lex = lex(&src); 33 | let parsed = parse(&mut lex.peekable()).unwrap(); 34 | let mut machine = Machine::new(); 35 | let mut cmpl = Compiler::new(&mut machine, 0, ops.debug); 36 | cmpl.compile(parsed); 37 | } 38 | -------------------------------------------------------------------------------- /vm/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Jazz Virtual Machine 2 | //! 3 | //! Jazz is a register-based virtual machine 4 | //! 5 | //! Jazz is still in active develop so it's not recommended to use Jazz for your purposes 6 | //! 7 | //! 8 | //! Example code: 9 | //!```asm 10 | //! LoadInt(0,12) // Load 12 into R(0) 11 | //! LoadInt(1,3) // Load 13 into R(1) 12 | //! Add(2,1,0) // Add value from R(1) to R(0) and store result in R(2) 13 | //! Ret(2) // Return value from R(2) 14 | //! ``` 15 | //! 16 | //! Jazz is heavily inspired by [Gravity](https://marcobambini.github.io/gravity/#/) language VM 17 | //! 18 | 19 | #![warn(rust_2018_idioms)] 20 | #![allow(non_snake_case)] 21 | 22 | pub mod frame; 23 | pub mod function; 24 | pub mod index; 25 | pub mod jit; 26 | pub mod machine; 27 | pub mod object; 28 | pub mod object_info; 29 | pub mod object_pool; 30 | pub mod opcodes; 31 | pub mod static_root; 32 | pub mod string; 33 | pub mod value; 34 | pub mod error; 35 | 36 | use time; 37 | 38 | pub mod prelude 39 | { 40 | #[allow(unused_imports)] 41 | use super::*; 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Adel Prokurov 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. 22 | -------------------------------------------------------------------------------- /vm/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Adel Prokurov 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. 22 | -------------------------------------------------------------------------------- /vm/bytecode/src/opcode.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | pub mod Opcode { 5 | pub const LoadI: u8 = 0x1; 6 | pub const LoadF: u8 = 0x2; 7 | pub const LoadL: u8 = 0x3; 8 | pub const LoadD: u8 = 0x4; 9 | 10 | pub const LoadG: u8 = 0xa1; 11 | pub const LoadAt: u8 = 0xa2; 12 | pub const StoreAt: u8 = 0xa3; 13 | pub const Ret: u8 = 0xa4; 14 | pub const Ret0: u8 = 0xa5; 15 | pub const Call: u8 = 0xa6; 16 | pub const StoreG: u8 = 0xa7; 17 | pub const Move: u8 = 0xa8; 18 | 19 | pub const Label: u8 = 0xa9; 20 | pub const Goto: u8 = 0xe1; 21 | pub const GotoT: u8 = 0xe2; 22 | pub const GotoF: u8 = 0xe3; 23 | 24 | pub fn to_string<'a>(op: u8) -> &'a str { 25 | match op { 26 | LoadI => "LoadI", 27 | Move => "Move", 28 | _ => "", 29 | } 30 | } 31 | } 32 | 33 | pub mod Size { 34 | pub const Float: u32 = ::std::mem::size_of::() as u32; 35 | pub const Double: u32 = ::std::mem::size_of::() as u32; 36 | pub const Int: u32 = ::std::mem::size_of::() as u32; 37 | pub const Long: u32 = ::std::mem::size_of::() as u32; 38 | pub const Bool: u32 = ::std::mem::size_of::() as u32; 39 | } -------------------------------------------------------------------------------- /vm/src/string.rs: -------------------------------------------------------------------------------- 1 | use crate::{machine::Machine, object::*, object_pool::ObjectPool}; 2 | 3 | impl ObjectAddon for String 4 | { 5 | fn to_String(&self, _: &mut Machine) -> String 6 | { 7 | self.clone() 8 | } 9 | 10 | fn to_double(&self, _: &mut Machine) -> f64 11 | { 12 | self.parse::().unwrap() 13 | } 14 | 15 | fn to_float(&self, _: &mut Machine) -> f32 16 | { 17 | self.parse::().unwrap() 18 | } 19 | fn to_int(&self, _: &mut Machine) -> i32 20 | { 21 | self.parse::().unwrap() 22 | } 23 | fn to_long(&self, _: &mut Machine) -> i64 24 | { 25 | self.parse::().unwrap() 26 | } 27 | fn typename(&self,_m: &mut Machine) -> String 28 | { 29 | String::from("Str") 30 | } 31 | } 32 | 33 | use std::any::Any; 34 | 35 | impl Object for String 36 | { 37 | 38 | 39 | fn initialize(&mut self, _: &mut ObjectPool) 40 | { 41 | } 42 | fn get_children(&self) -> Vec 43 | { 44 | vec![] 45 | } 46 | fn as_any(&self) -> &dyn Any 47 | { 48 | self as &dyn Any 49 | } 50 | fn as_any_mut(&mut self) -> &mut dyn Any 51 | { 52 | self as &mut dyn Any 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /vm/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate jazz_vm; 2 | 3 | use jazz_vm::{function::Function, machine::Machine, opcodes::Instruction, value::Value}; 4 | 5 | fn main() 6 | { 7 | let mut machine = Machine::new(); 8 | let string = machine.pool.allocate(Box::new(String::from("disassemble"))); 9 | 10 | let code = vec![ 11 | Instruction::LoadInt(2, 2), 12 | Instruction::Add(2, 1, 2), 13 | Instruction::Ret(2), 14 | ]; 15 | 16 | let func = Function::from_instructions(code, 1); 17 | 18 | let func = machine.pool.allocate(Box::new(func)); 19 | 20 | let code = vec![ 21 | Instruction::LoadConst(2, func), 22 | Instruction::LoadConst(1, string), 23 | Instruction::LoadArg(2), 24 | Instruction::LoadAt(2, 2, 1), 25 | Instruction::LoadArg(2), 26 | Instruction::Call(2, 2, 0), 27 | Instruction::Ret(2), 28 | ]; 29 | 30 | let func = Value::Object( 31 | machine 32 | .pool 33 | .allocate(Box::new(Function::from_instructions(code, 0))), 34 | ); 35 | let v = machine.invoke(func, vec![]); 36 | let obj = if let Value::Object(id) = v { 37 | machine.pool.get(id) 38 | } else { 39 | panic!(""); 40 | }; 41 | 42 | println!("{}", obj.to_String(&mut machine)); 43 | } 44 | -------------------------------------------------------------------------------- /vm/tests/load_at.rs: -------------------------------------------------------------------------------- 1 | extern crate jazz_vm; 2 | 3 | use jazz_vm::{function::Function, machine::Machine, opcodes::Instruction, value::Value}; 4 | 5 | #[test] 6 | fn load_at() 7 | { 8 | let mut machine = Machine::new(); 9 | let string = machine.pool.allocate(Box::new(String::from("disassemble"))); 10 | 11 | let code = vec![ 12 | Instruction::LoadInt(2, 2), 13 | Instruction::Add(2, 1, 2), 14 | Instruction::Ret(2), 15 | ]; 16 | 17 | let func = Function::from_instructions(code, 1); 18 | 19 | let func = machine.pool.allocate(Box::new(func)); 20 | 21 | let code = vec![ 22 | Instruction::LoadObject(2, func), 23 | Instruction::LoadObject(1, string), 24 | Instruction::PushArg(2), 25 | Instruction::LoadAt(2, 2, 1), 26 | Instruction::PushArg(2), 27 | Instruction::Call(2, 2, 0), 28 | Instruction::Ret(2), 29 | ]; 30 | 31 | let func = Value::Object( 32 | machine 33 | .pool 34 | .allocate(Box::new(Function::from_instructions(code, 0))), 35 | ); 36 | let v = machine.invoke(func, vec![]); 37 | let obj = if let Value::Object(id) = v { 38 | machine.pool.get(id) 39 | } else { 40 | panic!(""); 41 | }; 42 | 43 | println!("{}", obj.to_String(&mut machine)); 44 | } 45 | -------------------------------------------------------------------------------- /vm/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | 3 | #[derive(Debug)] 4 | pub enum VmError 5 | { 6 | RuntimeError(String), 7 | LabelNotFound(usize), 8 | GlobalNotFound(usize), 9 | Expected(String,String), 10 | } 11 | 12 | 13 | impl VmError { 14 | fn as_str(&self) -> String { 15 | match self.clone() { 16 | VmError::RuntimeError(cause) => format!("Runtime Error: `{}`",cause), 17 | VmError::LabelNotFound(id) => format!("Label `{}` not found",id), 18 | VmError::GlobalNotFound(id) => format!("Global `{}` not found",id), 19 | VmError::Expected(expected,found) => format!("Expected `{}` found `{}`",expected,found), 20 | } 21 | } 22 | } 23 | 24 | impl Error for VmError { 25 | fn description(&self) -> &str { 26 | match self { 27 | &VmError::Expected(_,_) => "Expected: ", 28 | &VmError::GlobalNotFound(_) => "GlobalNotFound:", 29 | &VmError::LabelNotFound(_) => "LabelNotFound:", 30 | &VmError::RuntimeError(_) => "RuntimeError:", 31 | } 32 | } 33 | 34 | fn cause(&self) -> Option<&dyn Error> { 35 | None 36 | } 37 | } 38 | 39 | use std::fmt; 40 | 41 | impl fmt::Display for VmError { 42 | fn fmt(&self,f: &mut fmt::Formatter<'_>) -> fmt::Result 43 | { 44 | write!(f,"{}",self.as_str()) 45 | } 46 | } 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /vm/src/jit/cpu/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod x64; 2 | 3 | pub const REG_COUNT: usize = 16; 4 | 5 | pub struct State 6 | { 7 | pub pc: usize, 8 | pub sp: usize, 9 | pub ra: usize, 10 | 11 | pub regs: [usize; REG_COUNT], 12 | } 13 | 14 | use std::fmt; 15 | 16 | impl fmt::Debug for State 17 | { 18 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 19 | { 20 | println!("State:"); 21 | println!("\t pc = {:?}", self.pc as *const u8); 22 | println!("\t sp = {:?}", self.sp as *const u8); 23 | println!("\t ra = {:?}", self.ra as *const u8); 24 | for (ind, &val) in self.regs.iter().enumerate() { 25 | println!("R[{:2}] = {:-20?} {:-20}", ind, val as *const u8, val) 26 | } 27 | write!(f, "") 28 | } 29 | } 30 | 31 | /// Register 32 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 33 | pub struct Reg(pub u8); 34 | 35 | impl From for u32 36 | { 37 | fn from(reg: Reg) -> u32 38 | { 39 | reg.0 as u32 40 | } 41 | } 42 | 43 | /// Float register 44 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 45 | pub struct FReg(pub u8); 46 | 47 | impl From for u32 48 | { 49 | fn from(reg: FReg) -> u32 50 | { 51 | reg.0 as u32 52 | } 53 | } 54 | 55 | pub enum Memory 56 | { 57 | Local(i32), 58 | Base(Reg, i32), 59 | Index(Reg, Reg, i32, i32), 60 | Offset(Reg, i32, i32), 61 | } 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jazz (Unmaintaned, please see https://github.com/jazz-lang/ 2 | [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/playXE/Jazz/blob/master/LICENSE) 3 | 4 | 5 | Jazz is a register-based virtual machine and lightweight programming language 6 | 7 | Jazz is heavily inspired by [Gravity](https://marcobambini.github.io/gravity/#/) language 8 | 9 | ## Goals 10 | * **Clear and simple syntax** 11 | * **Integration with Rust** 12 | * **Interfacing with other languages than Rust** 13 | * **Make VM suitable for object oriented programming** 14 | 15 | ## Non-goals 16 | * Write simple book for learning Jazz programming language 17 | * JIT compilation 18 | * Generating bytecode files 19 | 20 | 21 | # Example code 22 | 23 | ```swift 24 | func factorial(num) { 25 | if num == 0 { 26 | return 1; 27 | } else { 28 | return num * factorial(num - 1); 29 | } 30 | } 31 | 32 | func main() { 33 | print(factorial(5)); 34 | return 0; 35 | } 36 | ``` 37 | 38 | ```swift 39 | class Vector2 { 40 | var x; 41 | var y; 42 | func init(a,b) { 43 | this.x = a; 44 | this.y = b; 45 | return this; 46 | } 47 | 48 | func toString() { 49 | return concat("(",this.x,";",this.y,")"); 50 | } 51 | } 52 | 53 | func main() { 54 | var vector = Vector2(2,-2); 55 | print(vector.toString()); 56 | } 57 | 58 | ``` 59 | -------------------------------------------------------------------------------- /vm/tests/factorial.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | extern crate test; 3 | 4 | extern crate jazz_vm; 5 | 6 | use self::opcodes::Instruction; 7 | use jazz_vm::*; 8 | 9 | use self::{function::Function, value::Value}; 10 | 11 | #[test] 12 | fn factorial() 13 | { 14 | let mut machine = machine::Machine::new(); 15 | 16 | use self::Instruction::*; 17 | 18 | let factorial_code = vec![ 19 | LoadInt(2, 0), 20 | Eq(2, 1, 2), 21 | GotoF(2, 1), 22 | LoadInt(2, 1), 23 | Ret(2), 24 | Label(1), 25 | LoadGlobal(2, 3), 26 | LoadInt(5, 1), 27 | Sub(5, 1, 5), 28 | PushArg(5), 29 | PushArg(3), 30 | Call(3, 3, 1), 31 | Mul(3, 3, 1), 32 | Ret(3), 33 | ]; 34 | 35 | let fun = Function::from(factorial_code); 36 | let fun_v = Value::Object(machine.pool.allocate(Box::new(fun))); 37 | machine.globals.insert(2, fun_v); 38 | 39 | let main_code = vec![ 40 | LoadLong(1, 12), 41 | PushArg(1), 42 | LoadGlobal(2, 2), 43 | PushArg(2), 44 | Call(2, 2, 1), 45 | Ret(2), 46 | ]; 47 | 48 | let fun = Function::from(main_code); 49 | let fun_v = Value::Object(machine.pool.allocate(Box::new(fun))); 50 | let v = machine.invoke(fun_v, vec![]); 51 | let int = if let Value::Long(i) = v { 52 | i 53 | } else { 54 | panic!(""); 55 | }; 56 | assert_eq!(479001600, int); 57 | } 58 | -------------------------------------------------------------------------------- /vm/bytecode/src/assembler.rs: -------------------------------------------------------------------------------- 1 | use jazz::opcodes::Instruction; 2 | use crate::opcode::{Opcode,Size}; 3 | use crate::encode; 4 | 5 | #[derive(Clone,Debug)] 6 | pub struct Assembler { 7 | pub instructions: Vec, 8 | pub code: Vec, 9 | } 10 | 11 | impl Assembler { 12 | pub fn new(code: Vec) -> Assembler { 13 | Assembler { 14 | instructions: code, 15 | code: vec![] 16 | } 17 | } 18 | 19 | pub fn translate(&mut self) { 20 | let mut ip = 0; 21 | while ip < self.instructions.len() { 22 | let instruction = self.instructions[ip].clone(); 23 | 24 | match instruction { 25 | Instruction::LoadInt(reg,val) => { 26 | self.code.push(Opcode::LoadI); 27 | self.code.push(reg as u8); 28 | self.code.extend_from_slice(&encode!(val;i32)); 29 | } 30 | Instruction::Move(reg,reg2) => { 31 | self.code.push(Opcode::Move); 32 | self.code.push(reg as u8); 33 | self.code.push(reg2 as u8); 34 | } 35 | Instruction::LoadLong(reg,val) => { 36 | self.code.push(Opcode::LoadL); 37 | self.code.push(reg as u8); 38 | self.code.extend_from_slice(&encode!(val;i64)); 39 | } 40 | _ => unimplemented!(), 41 | } 42 | 43 | ip += 1; 44 | } 45 | self.code.push(self.instructions.len() as u8); 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /vm/benches/factorial_bench.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | extern crate test; 3 | 4 | extern crate jazz_vm; 5 | 6 | use self::opcodes::Instruction; 7 | use jazz_vm::*; 8 | 9 | use self::{function::Function, value::Value}; 10 | 11 | use self::test::Bencher; 12 | #[bench] 13 | fn factorial_bench(b: &mut Bencher) 14 | { 15 | b.iter(|| { 16 | let mut machine = machine::Machine::new(); 17 | 18 | use self::Instruction::*; 19 | 20 | let factorial_code = vec![ 21 | LoadInt(2, 0), 22 | Eq(2, 1, 2), 23 | GotoF(2, 1), 24 | LoadInt(2, 1), 25 | Ret(2), 26 | Label(1), 27 | LoadGlobal(2, 3), 28 | LoadInt(5, 1), 29 | Sub(5, 1, 5), 30 | PushArg(5), 31 | PushArg(3), 32 | Call(3, 3, 1), 33 | Mul(3, 3, 1), 34 | Ret(3), 35 | ]; 36 | 37 | let fun = Function::from(factorial_code); 38 | let fun_v = Value::Object(machine.pool.allocate(Box::new(fun))); 39 | machine.globals.insert(2, fun_v); 40 | 41 | let main_code = vec![ 42 | LoadLong(1, 12), 43 | PushArg(1), 44 | LoadGlobal(2, 2), 45 | PushArg(2), 46 | Call(2, 2, 1), 47 | Ret(2), 48 | ]; 49 | 50 | let fun = Function::from(main_code); 51 | let fun_v = Value::Object(machine.pool.allocate(Box::new(fun))); 52 | let v = machine.invoke(fun_v, vec![]); 53 | let int = if let Value::Long(i) = v { 54 | i 55 | } else { 56 | panic!(""); 57 | }; 58 | assert_eq!(479001600, int); 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /vm/simple_jazz/examples/simple_ast.rs: -------------------------------------------------------------------------------- 1 | extern crate simple_jazz; 2 | use simple_jazz::builder::FunctionBuilder; 3 | use simple_jazz::function::Function; 4 | use simple_jazz::opcodes::Instruction; 5 | 6 | #[derive(Debug,Clone)] 7 | pub enum SimpleAst { 8 | Int(i32), 9 | Add(Box,Box), 10 | Ret(Box), 11 | } 12 | 13 | pub fn translate(node: SimpleAst,b: &mut FunctionBuilder) { 14 | match node { 15 | SimpleAst::Int(integer) => { 16 | b.iconst(integer); 17 | } 18 | SimpleAst::Add(v1,v2) => { 19 | translate(*v1, b); 20 | translate(*v2,b); 21 | let r3 = b.register_pop(); 22 | let r2 = b.register_pop(); 23 | let r1 = b.register_push_temp(); 24 | b.insert_op(Instruction::Add(r1,r2,r3)); 25 | } 26 | SimpleAst::Ret(ret_a) => { 27 | translate(*ret_a, b); 28 | let r = b.register_pop(); 29 | b.insert_op(Instruction::Ret(r)); 30 | } 31 | } 32 | } 33 | 34 | pub fn compile(ast: Vec) -> Function { 35 | let mut builder = FunctionBuilder::new(0); 36 | builder.regs_used[0] = true; // 0 is a this value, just null for now 37 | for node in ast.iter() { 38 | translate(node.clone(), &mut builder); 39 | } 40 | 41 | builder.create_function() 42 | } 43 | 44 | use simple_jazz::machine; 45 | use simple_jazz::value::Value; 46 | use simple_jazz::opcodes::DebugCode; 47 | 48 | fn main() { 49 | let ast = vec![ 50 | SimpleAst::Ret(Box::new(SimpleAst::Add(Box::new(SimpleAst::Add(Box::new(SimpleAst::Int(2)),Box::new(SimpleAst::Int(2)))),Box::new(SimpleAst::Int(2))))) 51 | ]; 52 | 53 | let func = compile(ast); 54 | if let Function::Virtual(vf) = &func { 55 | println!("Generated code: \n{}",vf.code.toString()); 56 | } 57 | let mut machine = machine::Machine::new(); 58 | let obj = machine.pool.allocate(Box::new(func)); 59 | 60 | 61 | println!("{:?}",machine.invoke(Value::Object(obj),vec![])); 62 | } 63 | -------------------------------------------------------------------------------- /src/std_library/mod.rs: -------------------------------------------------------------------------------- 1 | use self::float_duration::FloatDuration; 2 | use crate::{builtins::*, class::Class}; 3 | use float_duration; 4 | use jazz_vm::{function::Function, machine::Machine, value::Value}; 5 | use std::{cell::UnsafeCell, collections::HashMap, time::Instant}; 6 | 7 | pub fn time(m: &mut Machine, _: Vec) -> Value { 8 | let now = Instant::now(); 9 | let duration = FloatDuration::from_std(now.elapsed()); 10 | 11 | let str = format!("{}", duration); 12 | let obj = Value::Object(m.pool.allocate(Box::new(str))); 13 | return obj; 14 | } 15 | 16 | pub fn system_class(m: &mut Machine) -> Class { 17 | let mut fields = HashMap::new(); 18 | let f = Function::from_native(Box::new(print)); 19 | fields.insert( 20 | "print".to_owned(), 21 | Value::Object(m.pool.allocate(Box::new(f))), 22 | ); 23 | fields.insert( 24 | "readln".to_owned(), 25 | Value::Object( 26 | m.pool 27 | .allocate(Box::new(Function::from_native(Box::new(readln)))), 28 | ), 29 | ); 30 | fields.insert( 31 | "time".to_owned(), 32 | Value::Object( 33 | m.pool 34 | .allocate(Box::new(Function::from_native(Box::new(time)))), 35 | ), 36 | ); 37 | Class { 38 | name: String::from("System"), 39 | fields: UnsafeCell::new(fields), 40 | } 41 | } 42 | 43 | pub fn unary_minus(m: &mut Machine) -> Value { 44 | use jazz_vm::opcodes::Instruction::*; 45 | 46 | let code = vec![LoadLong(2, 0), Move(3, 1), Sub(3, 2, 3), Ret(3)]; 47 | 48 | let func = Function::from_instructions(code, 1); 49 | Value::Object(m.pool.allocate(Box::new(func))) 50 | } 51 | 52 | pub fn int_class() -> Class { 53 | Class { 54 | name: String::from("Int"), 55 | fields: UnsafeCell::new(HashMap::new()), 56 | } 57 | } 58 | 59 | pub fn float_class() -> Class { 60 | Class { 61 | name: String::from("Float"), 62 | fields: UnsafeCell::new(HashMap::new()), 63 | } 64 | } 65 | 66 | pub fn str_class() -> Class { 67 | Class { 68 | name: String::from("Str"), 69 | fields: UnsafeCell::new(HashMap::new()), 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /vm/simple_jazz/examples/math.rs: -------------------------------------------------------------------------------- 1 | extern crate mex; 2 | extern crate simple_jazz; 3 | 4 | use mex::parser::ast::Node; 5 | 6 | use simple_jazz::builder::FunctionBuilder; 7 | use simple_jazz::opcodes::{Instruction,DebugCode}; 8 | use simple_jazz::machine::Machine; 9 | 10 | 11 | pub fn translate(node: Node,builder: &mut FunctionBuilder) { 12 | match node { 13 | Node::Number(num) => { 14 | builder.dconst(num); 15 | } 16 | Node::Infix{left,right,op} => { 17 | translate(*left, builder); 18 | translate(*right, builder); 19 | 20 | let r1 = builder.register_pop(); 21 | let r2 = builder.register_pop(); 22 | let dest = builder.register_push_temp(); 23 | 24 | let op: &str = &op; 25 | 26 | match op { 27 | "+" => { 28 | builder.insert_op(Instruction::Add(dest,r2,r1)); 29 | } 30 | "-" => { 31 | builder.insert_op(Instruction::Sub(dest,r2,r1)); 32 | } 33 | "*" => { 34 | builder.insert_op(Instruction::Mul(dest,r2,r1)); 35 | } 36 | "/" => { 37 | builder.insert_op(Instruction::Div(dest,r2,r1)); 38 | } 39 | _ => unimplemented!(), 40 | } 41 | } 42 | _ => unimplemented!(), 43 | } 44 | } 45 | use simple_jazz::function::Function; 46 | 47 | pub fn compile(node: Node) -> Function { 48 | let mut builder = FunctionBuilder::new(0); 49 | builder.regs_used[0] = true; 50 | translate(node, &mut builder); 51 | let ret = builder.register_pop(); 52 | 53 | builder.insert_op(Instruction::Ret(ret)); 54 | builder.create_function() 55 | 56 | } 57 | 58 | use simple_jazz::value::Value; 59 | use std::io::stdin; 60 | 61 | fn main() { 62 | let mut buffer = String::new(); 63 | 64 | println!("Enter simple mathematic expression(e.g `1 + 2 - 3`)"); 65 | stdin().read_line(&mut buffer).unwrap(); 66 | 67 | let v = mex::parser::Parser::new(buffer).parse().unwrap(); 68 | let v = compile(v); 69 | if let Function::Virtual(vf) = &v { 70 | println!("Generated code: \n{}",vf.code.toString()); 71 | }; 72 | 73 | let mut machine = Machine::new(); 74 | let obj = Value::Object(machine.pool.allocate(Box::new(v))); 75 | 76 | println!("Return: {:?}",machine.invoke(obj,vec![])); 77 | 78 | 79 | } -------------------------------------------------------------------------------- /vm/Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "jazz-vm" 3 | version = "0.2.2" 4 | dependencies = [ 5 | "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 6 | "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", 7 | ] 8 | 9 | [[package]] 10 | name = "libc" 11 | version = "0.2.43" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | 14 | [[package]] 15 | name = "redox_syscall" 16 | version = "0.1.40" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | 19 | [[package]] 20 | name = "time" 21 | version = "0.1.40" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | dependencies = [ 24 | "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 25 | "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", 26 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 27 | ] 28 | 29 | [[package]] 30 | name = "winapi" 31 | version = "0.3.6" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | dependencies = [ 34 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 35 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 36 | ] 37 | 38 | [[package]] 39 | name = "winapi-i686-pc-windows-gnu" 40 | version = "0.4.0" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | 43 | [[package]] 44 | name = "winapi-x86_64-pc-windows-gnu" 45 | version = "0.4.0" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | 48 | [metadata] 49 | "checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" 50 | "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" 51 | "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" 52 | "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" 53 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 54 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 55 | -------------------------------------------------------------------------------- /vm/src/object.rs: -------------------------------------------------------------------------------- 1 | use crate::{machine::Machine, object_pool::ObjectPool, value::Value}; 2 | use std::any::Any; 3 | pub trait Object: Send + ObjectAddon 4 | { 5 | 6 | /// Initialized 7 | fn initialize(&mut self, _: &mut ObjectPool) 8 | { 9 | } 10 | fn call(&self, _m: &mut Machine, _args: Vec) -> Value 11 | { 12 | Value::Null 13 | } 14 | 15 | fn store_at(&self, _m: &mut Machine, _args: Vec, _rindex: usize) 16 | { 17 | println!("{:?}", _args); 18 | panic!("Cannot store_at, {}", self.to_String(_m)); 19 | } 20 | 21 | fn load_at(&self, _m: &mut Machine, _args: Vec, _rindex: usize) 22 | { 23 | panic!("Cannot load_at. {:?}", self.to_String(_m)); 24 | } 25 | 26 | fn as_any(&self) -> &dyn Any; 27 | 28 | fn as_any_mut(&mut self) -> &mut dyn Any; 29 | 30 | fn get_children(&self) -> Vec; 31 | } 32 | 33 | pub trait ObjectAddon 34 | { 35 | fn typename(&self,_m: &mut Machine) -> String 36 | { 37 | String::from("Object") 38 | } 39 | 40 | fn o_clone(&self, _m: &mut Machine) -> Value 41 | { 42 | panic!("Cannot clone!"); 43 | } 44 | fn to_String(&self, _: &mut Machine) -> String 45 | { 46 | String::new() 47 | } 48 | 49 | fn as_bytes(&self, _: &mut Machine) -> Vec 50 | { 51 | Vec::new() 52 | } 53 | 54 | fn to_int(&self, _: &mut Machine) -> i32 55 | { 56 | 0 57 | } 58 | 59 | fn to_long(&self, _: &mut Machine) -> i64 60 | { 61 | 0 62 | } 63 | 64 | fn to_float(&self, _: &mut Machine) -> f32 65 | { 66 | 0.0 67 | } 68 | fn to_double(&self, _: &mut Machine) -> f64 69 | { 70 | 0.0 71 | } 72 | 73 | fn as_function(&self) -> &crate::function::Function 74 | { 75 | panic!() 76 | } 77 | 78 | fn eq(&self, _m: &mut Machine) -> bool 79 | { 80 | false 81 | } 82 | 83 | fn add(&self, _rhs: Value, _m: &mut Machine) -> Value 84 | { 85 | Value::Null 86 | } 87 | 88 | fn sub(&self, _rhs: Value, _m: &mut Machine) -> Value 89 | { 90 | Value::Null 91 | } 92 | 93 | fn div(&self, _rhs: Value, _m: &mut Machine) -> Value 94 | { 95 | Value::Null 96 | } 97 | 98 | fn not(&self, _m: &mut Machine) -> bool 99 | { 100 | false 101 | } 102 | 103 | fn isa(&self,s: String,m: &mut Machine) -> bool { 104 | self.typename(m) == s 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /vm/src/jit/cpu/x64/reg.rs: -------------------------------------------------------------------------------- 1 | use crate::jit::cpu::{FReg, Reg}; 2 | 3 | pub const REG_COUNT: usize = 16; 4 | pub static REG_PARAMS: [Reg; 6] = [RDI, RSI, RDX, RCX, R8, R9]; 5 | pub static SCRATCH: [Reg; 3] = [R9, R8, RDI]; 6 | 7 | pub const REG_RESULT: Reg = RAX; 8 | pub const REG_TMP1: Reg = R10; 9 | pub const REG_TMP2: Reg = R11; 10 | pub const REG_SP: Reg = RSP; 11 | pub const REG_FP: Reg = RBP; 12 | pub const REG_THREAD: Reg = R15; 13 | 14 | pub const RAX: Reg = Reg(0); 15 | pub const RCX: Reg = Reg(1); 16 | pub const RDX: Reg = Reg(2); 17 | pub const RBX: Reg = Reg(3); 18 | pub const RSP: Reg = Reg(4); 19 | pub const RBP: Reg = Reg(5); 20 | pub const RSI: Reg = Reg(6); 21 | pub const RDI: Reg = Reg(7); 22 | 23 | pub const R8: Reg = Reg(8); 24 | pub const R9: Reg = Reg(9); 25 | pub const R10: Reg = Reg(10); 26 | pub const R11: Reg = Reg(11); 27 | pub const R12: Reg = Reg(12); 28 | pub const R13: Reg = Reg(13); 29 | pub const R14: Reg = Reg(14); 30 | pub const R15: Reg = Reg(15); 31 | 32 | pub const RIP: Reg = Reg(16); 33 | 34 | pub const FREG_RESULT: FReg = XMM0; 35 | pub const FREG_TMP1: FReg = XMM1; 36 | 37 | pub static FREG_PARAMS: [FReg; 8] = [XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7]; 38 | 39 | pub const XMM0: FReg = FReg(0); 40 | pub const XMM1: FReg = FReg(1); 41 | pub const XMM2: FReg = FReg(2); 42 | pub const XMM3: FReg = FReg(3); 43 | pub const XMM4: FReg = FReg(4); 44 | pub const XMM5: FReg = FReg(5); 45 | pub const XMM6: FReg = FReg(6); 46 | pub const XMM7: FReg = FReg(7); 47 | pub const XMM8: FReg = FReg(8); 48 | pub const XMM9: FReg = FReg(9); 49 | pub const XMM10: FReg = FReg(10); 50 | pub const XMM11: FReg = FReg(11); 51 | pub const XMM12: FReg = FReg(12); 52 | pub const XMM13: FReg = FReg(13); 53 | pub const XMM14: FReg = FReg(14); 54 | pub const XMM15: FReg = FReg(15); 55 | 56 | impl Reg 57 | { 58 | // these four register need sometimes special treatment: e.g. because of bl vs bh 59 | // for byte operations 60 | pub fn is_basic_reg(self) -> bool 61 | { 62 | self == RAX || self == RBX || self == RCX || self == RDX 63 | } 64 | 65 | pub fn int(self) -> u8 66 | { 67 | assert!(self != RIP); 68 | 69 | self.0 70 | } 71 | 72 | pub fn msb(self) -> u8 73 | { 74 | assert!(self != RIP); 75 | 76 | (self.int() >> 3) & 0x01 77 | } 78 | 79 | pub fn and7(self) -> u8 80 | { 81 | assert!(self != RIP); 82 | 83 | self.int() & 0x07 84 | } 85 | } 86 | 87 | impl FReg 88 | { 89 | pub fn msb(self) -> u8 90 | { 91 | (self.0 >> 3) & 0x01 92 | } 93 | 94 | pub fn and7(self) -> u8 95 | { 96 | self.0 & 0x07 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /vm/bytecode/Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "jazz" 3 | version = "0.2.0" 4 | source = "registry+https://github.com/rust-lang/crates.io-index" 5 | dependencies = [ 6 | "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 7 | "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", 8 | ] 9 | 10 | [[package]] 11 | name = "jazz_bytecode" 12 | version = "0.1.0" 13 | dependencies = [ 14 | "jazz 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 15 | ] 16 | 17 | [[package]] 18 | name = "libc" 19 | version = "0.2.43" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | 22 | [[package]] 23 | name = "redox_syscall" 24 | version = "0.1.40" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | 27 | [[package]] 28 | name = "time" 29 | version = "0.1.40" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | dependencies = [ 32 | "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 33 | "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", 34 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 35 | ] 36 | 37 | [[package]] 38 | name = "winapi" 39 | version = "0.3.6" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | dependencies = [ 42 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 43 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 44 | ] 45 | 46 | [[package]] 47 | name = "winapi-i686-pc-windows-gnu" 48 | version = "0.4.0" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | 51 | [[package]] 52 | name = "winapi-x86_64-pc-windows-gnu" 53 | version = "0.4.0" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | 56 | [metadata] 57 | "checksum jazz 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3082c9a6cdfe935bff839d76f9794d0dc6b47b349b7debe5503c8d6399a45825" 58 | "checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" 59 | "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" 60 | "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" 61 | "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" 62 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 63 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 64 | -------------------------------------------------------------------------------- /vm/tests/store_at_load_at.rs: -------------------------------------------------------------------------------- 1 | extern crate time; 2 | 3 | extern crate jazz_vm; 4 | 5 | use jazz_vm::*; 6 | 7 | use std::collections::HashMap; 8 | 9 | use std::cell::RefCell; 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct TestObject 13 | { 14 | pub flds: RefCell>, 15 | pub inited: bool, 16 | } 17 | 18 | impl TestObject 19 | { 20 | pub fn new() -> TestObject 21 | { 22 | TestObject { 23 | flds: RefCell::new(HashMap::new()), 24 | inited: false, 25 | } 26 | } 27 | } 28 | 29 | use self::{ 30 | machine::Machine, object::{Object, ObjectAddon}, object_pool::ObjectPool, value::Value 31 | }; 32 | use std::any::Any; 33 | 34 | impl ObjectAddon for TestObject {} 35 | 36 | impl Object for TestObject 37 | { 38 | fn get_children(&self) -> Vec 39 | { 40 | vec![] 41 | } 42 | 43 | fn as_any(&self) -> &dyn Any 44 | { 45 | self as &dyn Any 46 | } 47 | 48 | fn as_any_mut(&mut self) -> &mut dyn Any 49 | { 50 | self as &mut dyn Any 51 | } 52 | 53 | fn initialize(&mut self, _: &mut ObjectPool) 54 | { 55 | } 56 | 57 | fn load_at(&self, m: &mut Machine, args: Vec, dest: usize) 58 | { 59 | let _this = args[0]; 60 | let idx = args[1]; 61 | 62 | if let Value::Int(i) = idx { 63 | let flds = self.flds.borrow(); 64 | let f = flds.get(&(i as usize)).expect("Field doesn't exists"); 65 | 66 | m.set(dest, *f); 67 | } else if let Value::Long(i) = idx { 68 | let flds = self.flds.borrow(); 69 | let f = flds.get(&(i as usize)).expect("Field doesn't exists"); 70 | 71 | m.set(dest, *f); 72 | } else { 73 | panic!("Expected Int or Long value as index"); 74 | } 75 | } 76 | 77 | fn store_at(&self, _m: &mut Machine, args: Vec, _rindex: usize) 78 | { 79 | let _this = args[0]; 80 | let idx = args[1]; 81 | let val = args[2]; 82 | let mut flds = self.flds.borrow_mut(); 83 | if let Value::Int(i) = idx { 84 | flds.insert(i as usize, val); 85 | } else if let Value::Long(i) = idx { 86 | flds.insert(i as usize, val); 87 | } else { 88 | panic!("Expected Int or Long value as index"); 89 | } 90 | } 91 | } 92 | 93 | use self::opcodes::Instruction::*; 94 | #[test] 95 | fn load_at_and_store_at() 96 | { 97 | let mut m = Machine::new(); 98 | 99 | let obj = m.pool.allocate(Box::new(TestObject::new())); 100 | 101 | let code = vec![ 102 | LoadObject(1, obj), 103 | LoadInt(2, 1), 104 | LoadFloat(3, 2.6), 105 | StoreAt(3, 1, 2), 106 | PushArg(1), 107 | LoadAt(4, 1, 2), 108 | Ret(4), 109 | ]; 110 | 111 | let func = self::function::Function::from(code); 112 | let func = m.pool.allocate(Box::new(func)); 113 | 114 | let value = m.invoke(Value::Object(func), vec![]); 115 | 116 | if let Value::Float(f) = value { 117 | assert_eq!(f, 2.6); 118 | } else { 119 | panic!(""); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /vm/simple_jazz/Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "jazz" 3 | version = "0.1.89" 4 | source = "registry+https://github.com/rust-lang/crates.io-index" 5 | dependencies = [ 6 | "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 7 | "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", 8 | ] 9 | 10 | [[package]] 11 | name = "libc" 12 | version = "0.2.43" 13 | source = "registry+https://github.com/rust-lang/crates.io-index" 14 | 15 | [[package]] 16 | name = "mex" 17 | version = "0.1.0" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | 20 | [[package]] 21 | name = "redox_syscall" 22 | version = "0.1.40" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | 25 | [[package]] 26 | name = "simple_jazz" 27 | version = "0.1.0" 28 | dependencies = [ 29 | "jazz 0.1.89 (registry+https://github.com/rust-lang/crates.io-index)", 30 | "mex 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 31 | ] 32 | 33 | [[package]] 34 | name = "time" 35 | version = "0.1.40" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | dependencies = [ 38 | "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 39 | "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", 40 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 41 | ] 42 | 43 | [[package]] 44 | name = "winapi" 45 | version = "0.3.6" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | dependencies = [ 48 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 49 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 50 | ] 51 | 52 | [[package]] 53 | name = "winapi-i686-pc-windows-gnu" 54 | version = "0.4.0" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | 57 | [[package]] 58 | name = "winapi-x86_64-pc-windows-gnu" 59 | version = "0.4.0" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | 62 | [metadata] 63 | "checksum jazz 0.1.89 (registry+https://github.com/rust-lang/crates.io-index)" = "a0a05d9a98d5549c474db78d1a000683ac135fe797c19cde0673dfa76d5ec803" 64 | "checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" 65 | "checksum mex 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f0a461e8655cd076eca1d35f44842ad93905c752ad394e78bb01493fc2340a19" 66 | "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" 67 | "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" 68 | "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" 69 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 70 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 71 | -------------------------------------------------------------------------------- /vm/src/object_info.rs: -------------------------------------------------------------------------------- 1 | use crate::object::Object; 2 | use std::{cell::Cell, ops::Deref, rc::Rc}; 3 | 4 | pub struct ObjectInfo 5 | { 6 | object: Box, 7 | native_ref_info: ObjectNativeRefInfo, 8 | } 9 | 10 | pub struct ObjectHandle<'a> 11 | { 12 | object: &'a dyn Object, 13 | _native_ref_info: ObjectNativeRefInfo, 14 | } 15 | 16 | impl<'a> Deref for ObjectHandle<'a> 17 | { 18 | type Target = &'a dyn Object; 19 | fn deref(&self) -> &&'a dyn Object 20 | { 21 | &self.object 22 | } 23 | } 24 | 25 | pub struct ObjectNativeRefInfo 26 | { 27 | // TODO: Remove Rc 28 | n_refs: Rc>, 29 | 30 | // in case n_refs becomes zero 31 | gc_notified: bool, 32 | } 33 | 34 | impl ObjectInfo 35 | { 36 | pub fn new(obj: Box) -> ObjectInfo 37 | { 38 | ObjectInfo { 39 | object: obj, 40 | native_ref_info: ObjectNativeRefInfo { 41 | n_refs: Rc::new(Cell::new(0)), 42 | gc_notified: false, 43 | }, 44 | } 45 | } 46 | 47 | pub fn gc_notify(&mut self) 48 | { 49 | self.native_ref_info.gc_notified = true; 50 | } 51 | 52 | pub fn as_object(&self) -> &dyn Object 53 | { 54 | &*self.object 55 | } 56 | 57 | pub fn has_native_refs(&self) -> bool 58 | { 59 | self.native_ref_info.n_refs.get() != 0 60 | } 61 | 62 | pub fn handle<'a>(&self) -> ObjectHandle<'a> 63 | { 64 | ObjectHandle { 65 | object: unsafe { 66 | ::std::mem::transmute::<&dyn Object, &'static dyn Object>(&*self.object) 67 | }, 68 | _native_ref_info: self.native_ref_info.clone(), 69 | } 70 | } 71 | } 72 | 73 | impl Drop for ObjectInfo 74 | { 75 | fn drop(&mut self) 76 | { 77 | if self.native_ref_info.n_refs.get() != 0 { 78 | eprintln!("Attempting to drop object with alive references"); 79 | ::std::process::abort(); 80 | } 81 | } 82 | } 83 | 84 | impl Clone for ObjectNativeRefInfo 85 | { 86 | fn clone(&self) -> Self 87 | { 88 | self.n_refs.replace(self.n_refs.get() + 1); 89 | ObjectNativeRefInfo { 90 | n_refs: self.n_refs.clone(), 91 | gc_notified: false, 92 | } 93 | } 94 | } 95 | 96 | impl Drop for ObjectNativeRefInfo 97 | { 98 | fn drop(&mut self) 99 | { 100 | let n_refs = self.n_refs.get(); 101 | 102 | if self.gc_notified { 103 | assert_eq!(n_refs, 0); 104 | } else { 105 | assert!(n_refs > 0); 106 | self.n_refs.replace(n_refs - 1); 107 | } 108 | } 109 | } 110 | 111 | pub struct TypedObjectHandle<'a, T> 112 | { 113 | _handle: ObjectHandle<'a>, 114 | value: &'a T, 115 | } 116 | 117 | impl<'a, T> Deref for TypedObjectHandle<'a, T> 118 | where 119 | T: 'a, 120 | { 121 | type Target = &'a T; 122 | fn deref(&self) -> &&'a T 123 | { 124 | &self.value 125 | } 126 | } 127 | 128 | impl<'a, T> TypedObjectHandle<'a, T> 129 | where 130 | T: 'static, 131 | { 132 | pub fn downcast_from(other: ObjectHandle<'a>) -> Option> 133 | { 134 | let value = match other.object.as_any().downcast_ref::() { 135 | Some(v) => v, 136 | None => return None, 137 | }; 138 | Some(TypedObjectHandle { 139 | _handle: other, 140 | value, 141 | }) 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /vm/src/frame.rs: -------------------------------------------------------------------------------- 1 | use crate::{opcodes::Instruction, value::Value}; 2 | 3 | ///CallFrame 4 | /// Stores register values, instructions, registers and arguments stack 5 | #[derive(Clone, Debug,Default)] 6 | pub struct CallFrame 7 | { 8 | /// pointer to current block 9 | pub ip: usize, 10 | /// Instructions 11 | pub code: Vec, 12 | /// registers stored in stack, default size of `stack` is 256 13 | pub stack: Vec, 14 | /// `arguments stack`: used by Call instruction 15 | pub arg_stack: Vec, 16 | } 17 | 18 | /// CallStack 19 | /// Stores frames 20 | #[derive(Clone, Debug)] 21 | pub struct CallStack 22 | { 23 | pub frames: Vec, 24 | pub n_frames: usize, 25 | pub limit: Option, 26 | } 27 | 28 | impl CallStack 29 | { 30 | pub fn new(len: usize) -> CallStack 31 | { 32 | let mut frames = Vec::with_capacity(len); 33 | for _ in 0..len { 34 | frames.push(CallFrame::new()); 35 | } 36 | 37 | CallStack { 38 | frames, 39 | n_frames: 1, 40 | limit: None, 41 | } 42 | } 43 | 44 | pub fn push(&mut self) 45 | { 46 | if self.n_frames >= self.frames.len() { 47 | panic!("Virtual stack overflow"); 48 | } 49 | if let Some(limit) = self.limit { 50 | if self.n_frames >= limit { 51 | panic!("Maximum stack depth exceeded"); 52 | } 53 | } 54 | 55 | self.n_frames += 1; 56 | } 57 | 58 | /// Reset last frame 59 | pub fn pop(&mut self) 60 | { 61 | if self.n_frames == 0 { 62 | panic!("Virtual stack underflow"); 63 | } 64 | self.frames[self.n_frames - 1].reset(); 65 | self.n_frames -= 1; 66 | } 67 | /// Get top frame 68 | pub fn top(&self) -> &CallFrame 69 | { 70 | if self.n_frames == 0 { 71 | panic!("Virtual stack underflow"); 72 | } 73 | &self.frames[self.n_frames - 1] 74 | } 75 | /// Get &mut CallFrame 76 | pub fn top_mut(&mut self) -> &mut CallFrame 77 | { 78 | if self.n_frames == 0 { 79 | panic!("Virtual stack underflow"); 80 | } 81 | &mut self.frames[self.n_frames - 1] 82 | } 83 | } 84 | 85 | ///Fiber 86 | /// Should be used in future 87 | /// 88 | /// Fiber must need to store upvalues and have a object pool 89 | #[derive(Clone, Debug)] 90 | pub struct Fiber 91 | { 92 | pub frames: Vec, 93 | } 94 | 95 | impl CallFrame 96 | { 97 | pub fn new() -> CallFrame 98 | { 99 | let mut vec = Vec::with_capacity(256); 100 | for _ in 0..256 { 101 | vec.push(Value::Null); 102 | } 103 | 104 | CallFrame { 105 | ip: 0, 106 | 107 | code: vec![], 108 | stack: vec, 109 | arg_stack: vec![], 110 | } 111 | } 112 | 113 | pub fn get(&self, r: usize) -> Value 114 | { 115 | self.stack[r] 116 | } 117 | 118 | pub fn set(&mut self, r: usize, v: Value) 119 | { 120 | self.stack[r] = v; 121 | } 122 | 123 | pub fn init_with_args(&mut self, args: &[Value]) 124 | { 125 | for arg in args { 126 | self.arg_stack.push(*arg); 127 | } 128 | } 129 | 130 | pub fn reset(&mut self) 131 | { 132 | for i in 0..self.stack.len() { 133 | self.stack[i] = Value::Null; 134 | } 135 | self.arg_stack.clear(); 136 | self.code.clear(); 137 | } 138 | 139 | pub fn jit_run(&mut self) -> Value 140 | { 141 | Value::Null 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /vm/bytecode/src/parser.rs: -------------------------------------------------------------------------------- 1 | use jazz::opcodes::Instruction; 2 | use super::opcode::{Opcode,Size}; 3 | use super::decode; 4 | 5 | #[derive(Clone,Debug)] 6 | pub struct Parser<'a> { 7 | pub code: &'a [u8], 8 | pub parsed_code: Vec, 9 | pub ip: usize, 10 | } 11 | 12 | 13 | impl<'a> Parser<'a> { 14 | pub fn new(code: &'a [u8]) -> Parser<'a> { 15 | Parser { 16 | code, 17 | parsed_code: vec![], 18 | ip: 0, 19 | } 20 | } 21 | 22 | pub fn read_next(&mut self) -> u8 { 23 | if self.ip < self.code.len() { 24 | let op = self.code[self.ip].clone(); 25 | 26 | self.ip += 1; 27 | op 28 | } else { 29 | 30 | return 0x0; 31 | } 32 | } 33 | pub fn parse(&mut self) -> Vec { 34 | let size = *self.code.last().unwrap() as usize; 35 | let mut ip = 0; 36 | while ip < size { 37 | if self.ip >= self.code.len() { 38 | break; 39 | } 40 | self.parse_opcode(); 41 | ip += 1; 42 | 43 | } 44 | 45 | return self.parsed_code.clone(); 46 | } 47 | 48 | pub fn parse_opcode(&mut self) { 49 | let op = &self.read_next(); 50 | println!("{:?}",Opcode::to_string(op.clone())); 51 | match op { 52 | &Opcode::Move => { 53 | let r1 = self.read_next(); 54 | let r2 = self.read_next(); 55 | self.parsed_code.push(Instruction::Move(r1 as usize,r2 as usize)); 56 | } 57 | 58 | &Opcode::LoadI => { 59 | 60 | let register = self.read_next() as usize; 61 | 62 | let array = { 63 | let mut array = [0u8;Size::Int as usize]; 64 | let mut i = 0; 65 | while i < Size::Int { 66 | let idx = self.read_next(); 67 | array[i as usize] = idx; 68 | i += 1; 69 | } 70 | array 71 | }; 72 | 73 | let int = decode!(array;i32); 74 | self.parsed_code.push(Instruction::LoadInt(register,int)); 75 | }, 76 | 77 | &Opcode::LoadL => { 78 | let register = self.read_next() as usize; 79 | 80 | let array = { 81 | let mut array = [0u8;Size::Long as usize]; 82 | for i in 0..Size::Long as usize { 83 | array[i] = self.read_next(); 84 | } 85 | array 86 | }; 87 | 88 | let long = decode!(array;i64); 89 | self.parsed_code.push(Instruction::LoadLong(register,long)); 90 | } 91 | &Opcode::LoadF => { 92 | let register = self.read_next() as usize; 93 | 94 | let array = { 95 | let mut array = [0u8;Size::Float as usize]; 96 | for i in 0..Size::Float as usize { 97 | array[i] = self.read_next(); 98 | } 99 | array 100 | }; 101 | 102 | let float = decode!(array;f32); 103 | self.parsed_code.push(Instruction::LoadFloat(register,float)); 104 | } 105 | &Opcode::Label => { 106 | let label_id = self.read_next() as usize; 107 | 108 | self.parsed_code.push(Instruction::Label(label_id)); 109 | } 110 | 111 | &Opcode::GotoF => { 112 | let reg = self.read_next(); 113 | let lbl_id = self.read_next(); 114 | 115 | self.parsed_code.push(Instruction::GotoF(reg as usize,lbl_id as usize)); 116 | } 117 | 118 | &Opcode::Goto => { 119 | let lbl_id = self.read_next(); 120 | 121 | self.parsed_code.push(Instruction::Goto(lbl_id as usize)); 122 | } 123 | 124 | _ => {} 125 | } 126 | } 127 | } -------------------------------------------------------------------------------- /src/class.rs: -------------------------------------------------------------------------------- 1 | use jazz_vm::{ 2 | machine::Machine, 3 | object::{Object, ObjectAddon}, 4 | object_pool::ObjectPool, 5 | value::Value, 6 | }; 7 | 8 | use std::{any::Any, cell::UnsafeCell, collections::HashMap}; 9 | /// Class 10 | /// 11 | /// Every value in Jazz is an object, but not every object is a instance of Class. 12 | /// 13 | /// Before initializing Class is just a `Function` object, after calling initializer `init` function returns `this` value 14 | /// 15 | /// For stroing fields used UnsafeCell because RefCell returns BorrowMutError in initializer 16 | /// 17 | /// 18 | #[derive(Debug)] 19 | pub struct Class { 20 | pub name: String, 21 | pub fields: UnsafeCell>, 22 | } 23 | 24 | impl Clone for Class { 25 | fn clone(&self) -> Class { 26 | let fields = unsafe { (*self.fields.get()).clone() }; 27 | Class { 28 | name: self.name.clone(), 29 | fields: UnsafeCell::new(fields), 30 | } 31 | } 32 | } 33 | 34 | impl Class { 35 | pub fn new() -> Class { 36 | Class { 37 | name: String::from(""), 38 | fields: UnsafeCell::new(HashMap::new()), 39 | } 40 | } 41 | } 42 | 43 | impl ObjectAddon for Class { 44 | fn o_clone(&self, m: &mut Machine) -> Value { 45 | let c = self.clone(); 46 | 47 | let v = Value::Object(m.pool.allocate(Box::new(c))); 48 | v 49 | } 50 | fn typename(&self, _: &mut Machine) -> String { 51 | return self.name.clone(); 52 | } 53 | 54 | fn to_String(&self, _m: &mut Machine) -> String { 55 | let fields: &HashMap = unsafe { &*self.fields.get() }; 56 | let mut string = String::new(); 57 | string.push_str(&format!("class {} {{ \n", self.name)); 58 | for (k, v) in fields.iter() { 59 | string.push_str(&format!( 60 | "\tvar {} = {};\n", 61 | k.to_String(_m), 62 | v.to_String(_m) 63 | )); 64 | } 65 | string.push_str("}"); 66 | 67 | string 68 | } 69 | } 70 | impl Object for Class { 71 | fn as_any(&self) -> &dyn Any { 72 | self as &dyn Any 73 | } 74 | fn as_any_mut(&mut self) -> &mut dyn Any { 75 | self as &mut dyn Any 76 | } 77 | fn initialize(&mut self, _p: &mut ObjectPool) {} 78 | 79 | fn get_children(&self) -> Vec { 80 | Vec::new() 81 | } 82 | 83 | fn call(&self, m: &mut Machine, args: Vec) -> Value { 84 | let class = if let Value::Object(id) = args[0] { 85 | let obj = m.pool.get(id); 86 | 87 | obj.as_any().downcast_ref::().unwrap() 88 | } else { 89 | panic!("Expected Value::Object"); 90 | }; 91 | 92 | let ret = { 93 | let fields = unsafe { &mut *class.fields.get() }; 94 | let field = fields.get("init").expect("Couldn't find initializer"); 95 | let mut args = args.clone(); 96 | args[0] = class.o_clone(m); 97 | let v = m.invoke(*field, args); 98 | m.stack.pop(); 99 | v 100 | }; 101 | ret 102 | } 103 | 104 | fn store_at(&self, m: &mut Machine, args: Vec, _: usize) { 105 | let fname = args[1].to_String(m); 106 | let fields = unsafe { &mut *self.fields.get() }; 107 | fields.insert(fname, args[2]); 108 | } 109 | 110 | fn load_at(&self, m: &mut Machine, args: Vec, rindex: usize) { 111 | let _this = args[0]; 112 | if let Value::Object(id) = args[1] { 113 | let str = m.pool.get(id).to_String(m); 114 | let fields = unsafe { &*self.fields.get() }; 115 | let field = fields.get(&str).expect(&format!("No such field {}", str)); 116 | 117 | m.set(rindex, *field); 118 | } 119 | if let Value::Int(_) = args[1] { 120 | let fields = unsafe { &*self.fields.get() }; 121 | let field = fields 122 | .get("__get__") 123 | .expect("Class doesn't have __get__ method"); 124 | let v = m.invoke(*field, args); 125 | m.set(rindex, v); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /vm/src/object_pool.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | object::Object, object_info::{ObjectHandle, ObjectInfo, TypedObjectHandle}, static_root::StaticRoot 3 | }; 4 | 5 | #[derive(Default)] 6 | /// An object pool that provides the backing object storage for executors. 7 | pub struct ObjectPool 8 | { 9 | objects: Vec>, 10 | object_idx_pool: Vec, 11 | alloc_count: usize, 12 | } 13 | 14 | impl ObjectPool 15 | { 16 | pub fn new() -> ObjectPool 17 | { 18 | ObjectPool { 19 | objects: vec![Some(ObjectInfo::new(Box::new(StaticRoot::new())))], 20 | object_idx_pool: vec![], 21 | alloc_count: 0, 22 | } 23 | } 24 | 25 | /// Pins an object to the pool. 26 | pub fn allocate(&mut self, mut inner: Box) -> usize 27 | { 28 | inner.initialize(self); 29 | 30 | let id = if let Some(id) = self.object_idx_pool.pop() { 31 | id 32 | } else { 33 | let objects = &mut self.objects; 34 | objects.push(None); 35 | objects.len() - 1 36 | }; 37 | self.objects[id] = Some(ObjectInfo::new(inner)); 38 | 39 | self.alloc_count += 1; 40 | 41 | id 42 | } 43 | 44 | #[allow(dead_code)] 45 | pub fn deallocate(&mut self, id: usize) 46 | { 47 | let objects = &mut self.objects; 48 | let pool = &mut self.object_idx_pool; 49 | 50 | assert!(objects[id].is_some()); 51 | 52 | objects[id] = None; 53 | pool.push(id); 54 | } 55 | 56 | /// Gets a handle to the object at `id`. 57 | /// 58 | /// The handle can be passed around safely and 59 | /// the underlying object will not be garbage 60 | /// collected until all handles to it are released. 61 | /// 62 | /// If the object pool gets destroyed before 63 | /// all handles are dropped, the process will be 64 | /// aborted because of memory unsafety introduced 65 | /// by reference invalidation. 66 | pub fn get<'a>(&self, id: usize) -> ObjectHandle<'a> 67 | { 68 | self.objects[id].as_ref().unwrap().handle() 69 | } 70 | 71 | /// Gets a direct reference to the object at `id`. 72 | pub fn get_direct(&self, id: usize) -> &dyn Object 73 | { 74 | self.objects[id].as_ref().unwrap().as_object() 75 | } 76 | 77 | /// Gets a direct typed reference to the object at `id`. 78 | /// If downcast fails, `None` is returned. 79 | pub fn get_direct_typed(&self, id: usize) -> Option<&T> 80 | { 81 | self.get_direct(id).as_any().downcast_ref::() 82 | } 83 | 84 | /// Gets a direct reference to the object at `id`. 85 | /// If downcast fails, this raises a `RuntimeError`. 86 | pub fn must_get_direct_typed(&self, id: usize) -> &T 87 | { 88 | self.get_direct_typed(id) 89 | .unwrap_or_else(|| panic!("Type mismatch")) 90 | } 91 | 92 | /// Gets a typed object handle to the object at `id`. 93 | /// If downcast fails, `None` is returned. 94 | pub fn get_typed<'a, T: 'static>(&self, id: usize) -> Option> 95 | { 96 | TypedObjectHandle::downcast_from(self.get(id)) 97 | } 98 | 99 | /// Gets a typed object handle to the object at `id`. 100 | /// If downcast fails, this raises a `RuntimeError`. 101 | pub fn must_get_typed<'a, T: 'static>(&self, id: usize) -> TypedObjectHandle<'a, T> 102 | { 103 | self.get_typed(id) 104 | .unwrap_or_else(|| panic!("Type mismatch")) 105 | } 106 | 107 | pub fn get_static_root<'a>(&self) -> TypedObjectHandle<'a, StaticRoot> 108 | { 109 | self.get_typed(0).unwrap() 110 | } 111 | 112 | pub fn get_direct_static_root(&self) -> &StaticRoot 113 | { 114 | self.get_direct_typed(0).unwrap() 115 | } 116 | 117 | pub fn get_alloc_count(&self) -> usize 118 | { 119 | self.alloc_count 120 | } 121 | 122 | pub fn reset_alloc_count(&mut self) 123 | { 124 | self.alloc_count = 0; 125 | } 126 | } 127 | 128 | impl Drop for ObjectPool 129 | { 130 | fn drop(&mut self) 131 | { 132 | for obj in &mut self.objects { 133 | if let Some(ref mut obj) = *obj { 134 | obj.gc_notify(); 135 | } 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /vm/src/function.rs: -------------------------------------------------------------------------------- 1 | use crate::{machine::Machine, object::Object, opcodes::*, value::Value}; 2 | use std::any::Any; 3 | 4 | #[derive(Debug)] 5 | pub enum Function 6 | { 7 | Virtual(VirtualFunction), 8 | Native(NativeFunction), 9 | } 10 | 11 | impl Clone for Function 12 | { 13 | fn clone(&self) -> Function 14 | { 15 | match self { 16 | Function::Virtual(vf) => Function::Virtual(vf.clone()), 17 | Function::Native(_) => panic!("Cannot clone native func"), 18 | } 19 | } 20 | } 21 | 22 | impl crate::object::ObjectAddon for Function 23 | { 24 | fn typename(&self,_: &mut Machine) -> String { 25 | return "Func".into() 26 | } 27 | 28 | fn as_function(&self) -> &Function 29 | { 30 | self 31 | } 32 | 33 | fn to_String(&self, _m: &mut Machine) -> String 34 | { 35 | String::from("function") 36 | } 37 | } 38 | 39 | impl Object for Function 40 | { 41 | fn as_any(&self) -> &dyn Any 42 | { 43 | self as &dyn Any 44 | } 45 | 46 | fn as_any_mut(&mut self) -> &mut dyn Any 47 | { 48 | self as &mut dyn Any 49 | } 50 | 51 | /// Get Object Id's(Used for GC) W.I.P 52 | fn get_children(&self) -> Vec 53 | { 54 | vec![] 55 | } 56 | 57 | fn load_at(&self, m: &mut Machine, _args: Vec, dest: usize) 58 | { 59 | let _this = _args[0]; 60 | let val = if let Value::Object(id) = &_args[1] { 61 | m.pool.get(*id) 62 | } else { 63 | panic!("Exptected object") 64 | }; 65 | 66 | let fname: &str = &val.to_String(m); 67 | 68 | match fname { 69 | "disassemble" => { 70 | let code = if let Function::Virtual(vf) = self { 71 | vf.code.toString() 72 | } else { 73 | "".to_string() 74 | }; 75 | let obj = m.pool.allocate(Box::new(code)); 76 | let code = vec![Instruction::LoadConst(1, obj), Instruction::Ret(1)]; 77 | let func = Function::from(code); 78 | let obj = m.pool.allocate(Box::new(func)); 79 | m.set(dest, Value::Object(obj)); 80 | } 81 | f => panic!("Unknown field `{}`", f), 82 | } 83 | } 84 | 85 | /// Call object 86 | fn call(&self, m: &mut Machine, args: Vec) -> Value 87 | { 88 | match self { 89 | Function::Virtual(ref vf) => { 90 | //println!("{:?}",args); 91 | let func = vf.clone(); 92 | //println!("{:?}",args[0].to_String(m)); 93 | m.last_frame_mut().stack[0] = args[0]; 94 | for i in 0..args.len() { 95 | m.last_frame_mut().stack[i] = args[i]; 96 | } 97 | let code = func.code; 98 | let v = m.run_code(code); 99 | match v { 100 | Ok(v) => return v, 101 | Err(e) => { 102 | eprintln!("{}",e); 103 | panic!(""); 104 | } 105 | } 106 | } 107 | 108 | Function::Native(nv) => nv.0(m, args), 109 | } 110 | } 111 | } 112 | 113 | #[derive(Clone, Debug)] 114 | pub struct VirtualFunction 115 | { 116 | pub code: Vec, 117 | pub argc: usize, 118 | } 119 | 120 | impl Function 121 | { 122 | pub fn from_instructions(code: Vec, args: usize) -> Function 123 | { 124 | Function::Virtual(VirtualFunction { code, argc: args }) 125 | } 126 | 127 | pub fn from_native(f: Box) -> Value + Send>) -> Function 128 | { 129 | Function::Native(NativeFunction(f)) 130 | } 131 | } 132 | 133 | impl From> for Function 134 | { 135 | fn from(f: Vec) -> Function 136 | { 137 | Function::Virtual(VirtualFunction { code: f, argc: 0 }) 138 | } 139 | } 140 | 141 | pub struct NativeFunction(pub Box) -> Value + Send>); 142 | 143 | impl NativeFunction 144 | { 145 | pub fn invoke(&self, m: &mut Machine, args: Vec) -> Value 146 | { 147 | self.0(m, args) 148 | } 149 | } 150 | 151 | use std::fmt; 152 | 153 | impl fmt::Debug for NativeFunction 154 | { 155 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 156 | { 157 | write!(f, "") 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | ## Operating System (VM environment) ## 2 | 3 | # Rust needs at least Visual Studio 2013 Appveyor OS for MSVC targets. 4 | os: Visual Studio 2015 5 | 6 | ## Build Matrix ## 7 | 8 | # This configuration will setup a build for each channel & target combination (12 windows 9 | # combinations in all). 10 | # 11 | # There are 3 channels: stable, beta, and nightly. 12 | # 13 | # Alternatively, the full version may be specified for the channel to build using that specific 14 | # version (e.g. channel: 1.5.0) 15 | # 16 | # The values for target are the set of windows Rust build targets. Each value is of the form 17 | # 18 | # ARCH-pc-windows-TOOLCHAIN 19 | # 20 | # Where ARCH is the target architecture, either x86_64 or i686, and TOOLCHAIN is the linker 21 | # toolchain to use, either msvc or gnu. See https://www.rust-lang.org/downloads.html#win-foot for 22 | # a description of the toolchain differences. 23 | # See https://github.com/rust-lang-nursery/rustup.rs/#toolchain-specification for description of 24 | # toolchains and host triples. 25 | # 26 | # Comment out channel/target combos you do not wish to build in CI. 27 | # 28 | # You may use the `cargoflags` and `RUSTFLAGS` variables to set additional flags for cargo commands 29 | # and rustc, respectively. For instance, you can uncomment the cargoflags lines in the nightly 30 | # channels to enable unstable features when building for nightly. Or you could add additional 31 | # matrix entries to test different combinations of features. 32 | environment: 33 | matrix: 34 | 35 | ### MSVC Toolchains ### 36 | 37 | # Stable 64-bit MSVC 38 | - channel: stable 39 | target: x86_64-pc-windows-msvc 40 | # Stable 32-bit MSVC 41 | - channel: stable 42 | target: i686-pc-windows-msvc 43 | # Beta 64-bit MSVC 44 | - channel: beta 45 | target: x86_64-pc-windows-msvc 46 | # Beta 32-bit MSVC 47 | - channel: beta 48 | target: i686-pc-windows-msvc 49 | # Nightly 64-bit MSVC 50 | - channel: nightly 51 | target: x86_64-pc-windows-msvc 52 | #cargoflags: --features "unstable" 53 | # Nightly 32-bit MSVC 54 | - channel: nightly 55 | target: i686-pc-windows-msvc 56 | #cargoflags: --features "unstable" 57 | 58 | ### GNU Toolchains ### 59 | 60 | # Stable 64-bit GNU 61 | - channel: stable 62 | target: x86_64-pc-windows-gnu 63 | # Stable 32-bit GNU 64 | - channel: stable 65 | target: i686-pc-windows-gnu 66 | # Beta 64-bit GNU 67 | - channel: beta 68 | target: x86_64-pc-windows-gnu 69 | # Beta 32-bit GNU 70 | - channel: beta 71 | target: i686-pc-windows-gnu 72 | # Nightly 64-bit GNU 73 | - channel: nightly 74 | target: x86_64-pc-windows-gnu 75 | #cargoflags: --features "unstable" 76 | # Nightly 32-bit GNU 77 | - channel: nightly 78 | target: i686-pc-windows-gnu 79 | #cargoflags: --features "unstable" 80 | 81 | ### Allowed failures ### 82 | 83 | # See Appveyor documentation for specific details. In short, place any channel or targets you wish 84 | # to allow build failures on (usually nightly at least is a wise choice). This will prevent a build 85 | # or test failure in the matching channels/targets from failing the entire build. 86 | matrix: 87 | allow_failures: 88 | - channel: nightly 89 | 90 | # If you only care about stable channel build failures, uncomment the following line: 91 | #- channel: beta 92 | 93 | ## Install Script ## 94 | 95 | # This is the most important part of the Appveyor configuration. This installs the version of Rust 96 | # specified by the 'channel' and 'target' environment variables from the build matrix. This uses 97 | # rustup to install Rust. 98 | # 99 | # For simple configurations, instead of using the build matrix, you can simply set the 100 | # default-toolchain and default-host manually here. 101 | install: 102 | - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe 103 | - rustup-init -yv --default-toolchain %channel% --default-host %target% 104 | - set PATH=%PATH%;%USERPROFILE%\.cargo\bin 105 | - rustc -vV 106 | - cargo -vV 107 | 108 | ## Build Script ## 109 | 110 | # 'cargo test' takes care of building for us, so disable Appveyor's build stage. This prevents 111 | # the "directory does not contain a project or solution file" error. 112 | build: false 113 | 114 | # Uses 'cargo test' to run tests and build. Alternatively, the project may call compiled programs 115 | #directly or perform other testing commands. Rust will automatically be placed in the PATH 116 | # environment variable. 117 | test_script: 118 | - cargo test --verbose %cargoflags% 119 | -------------------------------------------------------------------------------- /vm/simple_jazz/src/builder.rs: -------------------------------------------------------------------------------- 1 | use jazz::function::Function; 2 | use std::collections::HashMap; 3 | use jazz::opcodes::Instruction; 4 | 5 | 6 | ///Simple function builder 7 | #[derive(Debug)] 8 | pub struct FunctionBuilder { 9 | pub argc: usize, 10 | pub regs_used: Vec, 11 | pub registers: Vec, 12 | pub nlocals: usize, 13 | pub ntemps: usize, 14 | pub locals: Vec, 15 | list: Vec, 16 | } 17 | 18 | impl FunctionBuilder { 19 | pub fn new(argc: usize) -> FunctionBuilder { 20 | let mut vec = vec![]; 21 | for _ in 0..256 { 22 | vec.push(false); 23 | } 24 | 25 | 26 | 27 | 28 | FunctionBuilder { 29 | argc, 30 | list: vec![], 31 | regs_used: vec, 32 | registers: Vec::with_capacity(256), 33 | nlocals: argc, 34 | ntemps: 0, 35 | locals: vec![], 36 | } 37 | } 38 | 39 | pub fn create_function(&mut self) -> Function { 40 | self.list.push(Instruction::Ret0); 41 | 42 | let func = Function::from_instructions(self.list.clone(),self.argc); 43 | 44 | func 45 | } 46 | 47 | pub fn insert_op(&mut self,op: Instruction) { 48 | self.list.push(op); 49 | } 50 | 51 | pub fn iconst(&mut self, i: i32) -> usize { 52 | let register = self.register_push_temp(); 53 | self.list.push(Instruction::LoadInt(register,i)); 54 | register 55 | } 56 | 57 | pub fn lconst(&mut self, l: i64) -> usize { 58 | let register = self.register_push_temp(); 59 | self.list.push(Instruction::LoadLong(register,l)); 60 | register 61 | } 62 | 63 | pub fn dconst(&mut self, f: f64) -> usize { 64 | let register = self.register_push_temp(); 65 | self.list.push(Instruction::LoadDouble(register,f)); 66 | register 67 | } 68 | 69 | pub fn fconst(&mut self, f: f32) -> usize { 70 | let register = self.register_push_temp(); 71 | self.list.push(Instruction::LoadFloat(register,f)); 72 | register 73 | } 74 | 75 | 76 | pub fn register_pop_protect(&mut self,protect: bool) -> usize { 77 | let value = self.registers.pop().unwrap(); 78 | if protect { 79 | self.regs_used[value] = true; 80 | } else if value >= self.nlocals { 81 | self.regs_used[value] = false; 82 | } 83 | 84 | if protect && value >= self.nlocals { 85 | self.locals[value] = true; 86 | } 87 | 88 | return value; 89 | } 90 | 91 | pub fn register_pop(&mut self) -> usize { 92 | self.register_pop_protect(false) 93 | } 94 | pub fn new_register(&mut self) -> usize { 95 | for i in 0..255 { 96 | if self.regs_used[i] == false { 97 | self.regs_used[i] = true; 98 | return i; 99 | } 100 | } 101 | 102 | panic!("No registers availbale"); 103 | } 104 | /// create temp register 105 | pub fn register_push_temp(&mut self) -> usize{ 106 | let value = self.new_register(); 107 | self.registers.push(value); 108 | self.nlocals += 1; 109 | if value > 256 { 110 | panic!("ERROR!"); 111 | } 112 | 113 | return value; 114 | } 115 | 116 | pub fn register_is_temp(&self,nreg: usize) -> bool { 117 | return nreg >= self.nlocals; 118 | } 119 | 120 | pub fn register_push(&mut self,nreg: usize) -> usize { 121 | self.registers.push(nreg); 122 | 123 | if self.register_is_temp(nreg) { 124 | self.ntemps += 1; 125 | } 126 | nreg 127 | } 128 | 129 | 130 | pub fn first_temp_available(&mut self) -> usize { 131 | for i in 0..256 { 132 | if self.regs_used[i] == false { 133 | return i; 134 | } 135 | } 136 | 137 | println!("No available registers"); 138 | return 0; 139 | } 140 | 141 | pub fn register_last(&self) -> usize { 142 | self.registers.last().unwrap().clone() 143 | } 144 | } 145 | 146 | 147 | pub trait Load { 148 | fn load(f: &mut FunctionBuilder,v: T) -> usize; 149 | } 150 | 151 | impl Load for i32 { 152 | fn load(f: &mut FunctionBuilder,v: i32) -> usize { 153 | let reg = f.iconst(v); 154 | reg 155 | } 156 | } 157 | 158 | 159 | impl Load for i32 { 160 | fn load(f: &mut FunctionBuilder,v: i64) -> usize { 161 | let reg = f.lconst(v); 162 | reg 163 | } 164 | } 165 | 166 | impl Load for f32 { 167 | fn load(f: &mut FunctionBuilder,v: f32) -> usize { 168 | let reg = f.fconst(v); 169 | reg 170 | } 171 | } 172 | 173 | impl Load for f64 { 174 | fn load(f: &mut FunctionBuilder, v: f64) -> usize { 175 | let reg = f.dconst(v); 176 | reg 177 | } 178 | } 179 | 180 | 181 | pub trait InstBuilder> { 182 | 183 | } -------------------------------------------------------------------------------- /src/ircode.rs: -------------------------------------------------------------------------------- 1 | use jazz_vm::opcodes::Instruction; 2 | use std::collections::HashMap; 3 | 4 | pub const MAX_REGISTERS: usize = 256; 5 | 6 | #[derive(Clone)] 7 | pub struct FunctionBuilder { 8 | pub list: Vec, 9 | pub label_counter: usize, 10 | pub maxtemps: usize, 11 | pub ntemps: usize, 12 | pub nlocals: usize, 13 | pub locals: HashMap, 14 | pub state: [bool; MAX_REGISTERS], 15 | pub skipclear: [bool; MAX_REGISTERS], 16 | pub registers: Vec, 17 | pub context: Vec>, 18 | } 19 | 20 | impl FunctionBuilder { 21 | pub fn new(nlocals: usize) -> FunctionBuilder { 22 | let mut state = [false; MAX_REGISTERS]; 23 | state[0] = true; 24 | /*for i in 0..nlocals { 25 | state[i] = true; 26 | }*/ 27 | 28 | FunctionBuilder { 29 | label_counter: 0, 30 | nlocals, 31 | ntemps: 0, 32 | locals: HashMap::new(), 33 | maxtemps: 0, 34 | list: Vec::new(), 35 | registers: Vec::with_capacity(MAX_REGISTERS), 36 | context: Vec::new(), 37 | state, 38 | skipclear: [false; MAX_REGISTERS], 39 | } 40 | } 41 | 42 | pub fn new_local(&mut self, n: String, reg: usize) { 43 | self.state[reg] = true; 44 | self.nlocals += 1; 45 | self.locals.insert(n, reg); 46 | } 47 | 48 | pub fn get_local(&mut self, n: &str) -> usize { 49 | if self.locals.contains_key(n) { 50 | let r = self.locals.get(n).expect("Unknown local").clone(); 51 | r 52 | } else { 53 | panic!("Local `{}` doesn't exists", n); 54 | } 55 | } 56 | 57 | pub fn new_label(&mut self) -> usize { 58 | self.label_counter += 1; 59 | self.label_counter 60 | } 61 | 62 | pub fn label_here(&mut self, lc: usize) { 63 | self.list.push(Instruction::Label(lc)); 64 | } 65 | 66 | pub fn push_op(&mut self, ins: Instruction) { 67 | self.list.push(ins); 68 | } 69 | 70 | pub fn register_new(&mut self) -> usize { 71 | for i in 0..MAX_REGISTERS { 72 | if self.state[i] == false { 73 | self.state[i] = true; 74 | return i; 75 | } 76 | } 77 | println!("No registers available"); 78 | return 0; 79 | } 80 | 81 | pub fn register_push(&mut self, nreg: usize) -> usize { 82 | self.registers.push(nreg); 83 | if self.register_is_temp(nreg) { 84 | self.ntemps += 1; 85 | } 86 | return nreg; 87 | } 88 | 89 | pub fn register_first_temp_available(&mut self) -> usize { 90 | for i in 0..MAX_REGISTERS { 91 | if self.state[i] == false { 92 | return i; 93 | } 94 | } 95 | return 0; 96 | } 97 | 98 | pub fn register_push_temp(&mut self) -> usize { 99 | let value = self.register_new(); 100 | self.registers.push(value); 101 | if value > self.maxtemps { 102 | self.maxtemps = value; 103 | self.ntemps += 1; 104 | } 105 | 106 | return value; 107 | } 108 | 109 | pub fn get_insts(&mut self) -> Vec { 110 | self.list.clone() 111 | } 112 | 113 | pub fn register_pop_context_protect(&mut self, protect: bool) -> usize { 114 | if self.registers.len() == 0 { 115 | panic!("REGISTER ERROR"); 116 | } 117 | 118 | let value = self.registers.pop().unwrap_or_default(); 119 | 120 | if protect { 121 | self.state[value] = true; 122 | } else if value > self.nlocals { 123 | self.state[value] = false; 124 | } 125 | 126 | if protect && value >= self.nlocals { 127 | let ctx = self.context.last_mut().unwrap(); 128 | ctx[value] = true; 129 | } 130 | 131 | return value; 132 | } 133 | 134 | pub fn int_const(&mut self, int: i32) -> usize { 135 | let register = self.register_push_temp(); 136 | self.list.push(Instruction::LoadInt(register, int)); 137 | return register; 138 | } 139 | 140 | pub fn long_const(&mut self, long: i64) -> usize { 141 | let register = self.register_push_temp(); 142 | self.list.push(Instruction::LoadLong(register, long)); 143 | return register; 144 | } 145 | 146 | pub fn float_const(&mut self, float: f32) -> usize { 147 | let register = self.register_push_temp(); 148 | self.list.push(Instruction::LoadFloat(register, float)); 149 | return register; 150 | } 151 | 152 | pub fn double_const(&mut self, float: f64) -> usize { 153 | let register = self.register_push_temp(); 154 | self.list.push(Instruction::LoadDouble(register, float)); 155 | return register; 156 | } 157 | pub fn register_pop(&mut self) -> usize { 158 | self.register_pop_context_protect(false) 159 | } 160 | 161 | pub fn register_clear(&mut self, nreg: usize) { 162 | if nreg >= self.nlocals { 163 | self.state[nreg] = false; 164 | } 165 | } 166 | pub fn register_is_temp(&self, nreg: usize) -> bool { 167 | return nreg >= self.nlocals; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /vm/src/value.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, Debug, Copy)] 2 | pub enum Value 3 | { 4 | /// Integer or i32 in Rust 5 | Int(i32), 6 | /// Long or i64 in Rust 7 | Long(i64), 8 | /// Float or f32 in Rust 9 | Float(f32), 10 | /// Double or f64 in Rust 11 | Double(f64), 12 | /// Pointer to object in pool 13 | Object(usize), 14 | /// Null reference 15 | Null, 16 | /// Boolean 17 | Bool(bool), 18 | } 19 | 20 | use crate::{machine::Machine, object::ObjectAddon}; 21 | 22 | impl ObjectAddon for Value 23 | { 24 | fn o_clone(&self, m: &mut Machine) -> Value 25 | { 26 | match self { 27 | Value::Object(id) => { 28 | let obj = m.pool.get(*id); 29 | obj.o_clone(m) 30 | } 31 | v => *v, 32 | } 33 | } 34 | 35 | fn typename(&self,m: &mut Machine) -> String { 36 | match self { 37 | Value::Bool(_) => String::from("Bool"), 38 | Value::Double(_) => String::from("Float"), 39 | Value::Long(_) => String::from("Int"), 40 | Value::Object(id) => { 41 | let obj = m.pool.get(*id); 42 | obj.typename(m) 43 | } 44 | Value::Null => String::from("null"), 45 | _ => unimplemented!() 46 | } 47 | } 48 | fn to_double(&self, m: &mut Machine) -> f64 49 | { 50 | match self { 51 | Value::Double(d) => *d, 52 | Value::Float(f) => f64::from(*f), 53 | Value::Bool(b) => { 54 | if *b { 55 | 1.0 56 | } else { 57 | 0.0 58 | } 59 | } 60 | Value::Int(i) => f64::from(*i), 61 | Value::Long(i) => *i as f64, 62 | Value::Null => 0.0, 63 | Value::Object(id) => { 64 | let obj = m.pool.get(*id); 65 | obj.to_double(m) 66 | } 67 | } 68 | } 69 | 70 | fn to_float(&self, m: &mut Machine) -> f32 71 | { 72 | match self { 73 | Value::Double(d) => *d as f32, 74 | Value::Float(f) => *f, 75 | Value::Bool(b) => { 76 | if *b { 77 | 1.0 78 | } else { 79 | 0.0 80 | } 81 | } 82 | Value::Int(i) => *i as f32, 83 | Value::Long(i) => *i as f32, 84 | Value::Null => 0.0, 85 | Value::Object(id) => { 86 | let obj = m.pool.get(*id); 87 | obj.to_float(m) 88 | } 89 | } 90 | } 91 | 92 | fn to_int(&self, m: &mut Machine) -> i32 93 | { 94 | match self { 95 | Value::Double(d) => *d as i32, 96 | Value::Float(f) => *f as i32, 97 | Value::Bool(b) => { 98 | if *b { 99 | 1 100 | } else { 101 | 0 102 | } 103 | } 104 | Value::Int(i) => *i, 105 | Value::Long(i) => *i as i32, 106 | Value::Null => 0, 107 | Value::Object(id) => { 108 | let obj = m.pool.get(*id); 109 | obj.to_int(m) 110 | } 111 | } 112 | } 113 | 114 | fn to_long(&self, m: &mut Machine) -> i64 115 | { 116 | match self { 117 | Value::Double(d) => *d as i64, 118 | Value::Float(f) => *f as i64, 119 | Value::Bool(b) => { 120 | if *b { 121 | 1 122 | } else { 123 | 0 124 | } 125 | } 126 | Value::Int(i) => i64::from(*i), 127 | Value::Long(i) => *i, 128 | Value::Null => 0, 129 | Value::Object(id) => { 130 | let obj = m.pool.get(*id); 131 | obj.to_long(m) 132 | } 133 | } 134 | } 135 | 136 | fn as_bytes(&self, m: &mut Machine) -> Vec 137 | { 138 | let string: String = match self { 139 | Value::Double(d) => d.to_string(), 140 | Value::Float(f) => f.to_string(), 141 | Value::Bool(b) => { 142 | if *b { 143 | "true".to_string() 144 | } else { 145 | "false".to_string() 146 | } 147 | } 148 | Value::Int(i) => i.to_string(), 149 | Value::Long(i) => i.to_string(), 150 | Value::Null => "null".to_string(), 151 | Value::Object(id) => { 152 | let obj = m.pool.get(*id); 153 | obj.to_String(m) 154 | } 155 | }; 156 | string.into_bytes() 157 | } 158 | 159 | fn to_String(&self, m: &mut Machine) -> String 160 | { 161 | match self { 162 | Value::Double(d) => d.to_string(), 163 | Value::Float(f) => f.to_string(), 164 | Value::Bool(b) => { 165 | if *b { 166 | "true".to_string() 167 | } else { 168 | "false".to_string() 169 | } 170 | } 171 | Value::Int(i) => i.to_string(), 172 | Value::Long(i) => i.to_string(), 173 | Value::Null => "null".to_string(), 174 | Value::Object(id) => { 175 | let obj = m.pool.get(*id); 176 | obj.to_String(m) 177 | } 178 | } 179 | } 180 | 181 | fn not(&self, _m: &mut Machine) -> bool 182 | { 183 | match self { 184 | Value::Null => true, 185 | Value::Int(i) => { 186 | *i == 0 187 | } 188 | Value::Long(l) => { 189 | *l == 0 190 | } 191 | Value::Double(b) => { 192 | *b == 0.0 193 | } 194 | Value::Float(f) => { 195 | *f == 0.0 196 | } 197 | Value::Bool(b) => !b, 198 | _ => unimplemented!(), 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /src/builtins.rs: -------------------------------------------------------------------------------- 1 | use jazz_vm::{ 2 | function::Function, 3 | machine::Machine, 4 | object::{Object, ObjectAddon}, 5 | object_pool::ObjectPool, 6 | value::Value, 7 | }; 8 | 9 | use std::{cell::RefCell, io::stdin}; 10 | 11 | #[derive(Clone)] 12 | pub struct Array { 13 | elements: RefCell>, 14 | } 15 | 16 | pub fn array_pop(m: &mut Machine, args: Vec) -> Value { 17 | if let Value::Object(id) = &args[1] { 18 | let obj = m.pool.get(*id).as_any(); 19 | 20 | let array = if let Some(array) = obj.downcast_ref::() { 21 | array 22 | } else { 23 | panic!("Not a Array object!"); 24 | }; 25 | 26 | let v = array.pop(); 27 | return v; 28 | } else { 29 | panic!("Array::pop expects Array as argument!"); 30 | } 31 | } 32 | 33 | pub fn array_push(m: &mut Machine, args: Vec) -> Value { 34 | if let Value::Object(id) = &args[0] { 35 | let obj = m.pool.get(*id).as_any(); 36 | 37 | let array = if let Some(array) = obj.downcast_ref::() { 38 | array 39 | } else { 40 | panic!("Not a Array object!"); 41 | }; 42 | 43 | let v = args[1]; 44 | array.push(v); 45 | return Value::Null; 46 | } else { 47 | panic!("Array::push expects Array as argument!"); 48 | } 49 | } 50 | 51 | pub fn array_size(m: &mut Machine, args: Vec) -> Value { 52 | if let Value::Object(id) = &args[0] { 53 | let obj = m.pool.get(*id).as_any(); 54 | 55 | let array = if let Some(array) = obj.downcast_ref::() { 56 | array 57 | } else { 58 | panic!("Not a Array object!"); 59 | }; 60 | return Value::Int(array.elements.borrow().len() as i32); 61 | } else { 62 | panic!("Array::size expects Array as argument!"); 63 | } 64 | } 65 | 66 | pub fn array_get(m: &mut Machine, args: Vec) -> Value { 67 | if let Value::Object(id) = &args[0] { 68 | let obj = m.pool.get(*id).as_any(); 69 | let idx = match &args[1] { 70 | Value::Int(integer) => *integer as usize, 71 | Value::Long(long) => *long as usize, 72 | _ => panic!("Array::get expects Long or Int value as index"), 73 | }; 74 | let array = if let Some(array) = obj.downcast_ref::() { 75 | array 76 | } else { 77 | panic!("Not a Array object!"); 78 | }; 79 | return array.get(idx); 80 | } else { 81 | panic!("Array::get expects Array as argument!"); 82 | } 83 | } 84 | 85 | pub fn array_set(m: &mut Machine, args: Vec) -> Value { 86 | if let Value::Object(id) = &args[0] { 87 | let obj = m.pool.get(*id).as_any(); 88 | let idx = match &args[1] { 89 | Value::Int(integer) => *integer as usize, 90 | Value::Long(long) => *long as usize, 91 | _ => panic!("Array::set expects Long or Int value as index"), 92 | }; 93 | let array = if let Some(array) = obj.downcast_ref::() { 94 | array 95 | } else { 96 | panic!("Not a Array object!"); 97 | }; 98 | 99 | return array.get(idx); 100 | } else { 101 | panic!("Array::set expects Array as argument!"); 102 | } 103 | } 104 | 105 | impl Array { 106 | pub fn new() -> Array { 107 | Array { 108 | elements: RefCell::new(Vec::new()), 109 | } 110 | } 111 | 112 | pub fn push(&self, v: Value) { 113 | self.elements.borrow_mut().push(v); 114 | } 115 | 116 | pub fn pop(&self) -> Value { 117 | let mut elements = self.elements.borrow_mut(); 118 | let value = { 119 | let value = elements.pop(); 120 | if value.is_some() { 121 | value.unwrap() 122 | } else { 123 | Value::Null 124 | } 125 | }; 126 | value 127 | } 128 | 129 | pub fn set(&self, idx: usize, v: Value) { 130 | self.elements.borrow_mut()[idx] = v; 131 | } 132 | 133 | pub fn get(&self, idx: usize) -> Value { 134 | self.elements.borrow()[idx] 135 | } 136 | } 137 | 138 | use std::any::Any; 139 | 140 | 141 | impl ObjectAddon for Array { 142 | 143 | 144 | fn to_String(&self, m: &mut Machine) -> String { 145 | let elements = self.elements.borrow(); 146 | 147 | let mut string = String::new(); 148 | string.push_str("["); 149 | let mut i = 0; 150 | while i < elements.len() { 151 | string.push_str(&elements[i].to_String(m)); 152 | if i != elements.len() - 1 { 153 | string.push_str(","); 154 | } 155 | i += 1; 156 | } 157 | string.push_str("]"); 158 | 159 | string 160 | } 161 | } 162 | 163 | impl Object for Array { 164 | fn initialize(&mut self, _: &mut ObjectPool) {} 165 | fn as_any(&self) -> &dyn Any { 166 | self as &dyn Any 167 | } 168 | 169 | fn as_any_mut(&mut self) -> &mut dyn Any { 170 | self as &mut dyn Any 171 | } 172 | 173 | fn get_children(&self) -> Vec { 174 | Vec::new() 175 | } 176 | 177 | fn load_at(&self, m: &mut Machine, args: Vec, rindex: usize) { 178 | let _this = args[0]; 179 | if let Value::Object(id) = &args[1] { 180 | let str: &str = &m.pool.get(*id).to_String(m); 181 | 182 | match str { 183 | "pop" => { 184 | let function = Function::from_native(Box::new(array_pop)); 185 | let function_id = Value::Object(m.pool.allocate(Box::new(function))); 186 | m.set(rindex, function_id); 187 | } 188 | "push" => { 189 | let function = Function::from_native(Box::new(array_push)); 190 | let function_id = Value::Object(m.pool.allocate(Box::new(function))); 191 | m.set(rindex, function_id); 192 | } 193 | "set" => { 194 | let function = Function::from_native(Box::new(array_pop)); 195 | let function_id = Value::Object(m.pool.allocate(Box::new(function))); 196 | m.set(rindex, function_id); 197 | } 198 | "get" => { 199 | let function = Function::from_native(Box::new(array_get)); 200 | let function_id = Value::Object(m.pool.allocate(Box::new(function))); 201 | m.set(rindex, function_id); 202 | } 203 | "size" => { 204 | let function = Function::from_native(Box::new(array_size)); 205 | let function_id = Value::Object(m.pool.allocate(Box::new(function))); 206 | m.set(rindex, function_id); 207 | } 208 | v => panic!("{:?}", v), 209 | } 210 | return; 211 | } 212 | let elements = self.elements.borrow(); 213 | if let Value::Int(int) = &args[1] { 214 | let v = elements.get(*int as usize).unwrap(); 215 | 216 | m.set(rindex, v.clone()); 217 | } 218 | if let Value::Long(long) = &args[1] { 219 | let v = elements.get(*long as usize).unwrap(); 220 | m.set(rindex, v.clone()); 221 | } 222 | } 223 | 224 | fn store_at(&self, m: &mut Machine, args: Vec, _rindex: usize) { 225 | let idx = args[1]; 226 | let value = args[2]; 227 | 228 | let idx = idx.to_int(m) as usize; 229 | self.elements.borrow_mut()[idx] = value; 230 | } 231 | } 232 | 233 | pub fn new_array(m: &mut Machine, args: Vec) -> Value { 234 | let array = Array::new(); 235 | for i in 1..args.len() { 236 | array.push(args[args.len() - i]); 237 | } 238 | let object = Value::Object(m.pool.allocate(Box::new(array))); 239 | object 240 | } 241 | 242 | pub fn concat(m: &mut Machine, args: Vec) -> Value { 243 | let mut buffer = String::new(); 244 | for i in 1..args.len() { 245 | buffer.push_str(&args[i].to_String(m)); 246 | } 247 | let object = Value::Object(m.pool.allocate(Box::new(buffer))); 248 | object 249 | } 250 | 251 | pub fn print(m: &mut Machine, args: Vec) -> Value { 252 | for i in 1..args.len() { 253 | let str = args[i].to_String(m); 254 | 255 | print!("{}", str); 256 | } 257 | print!("\n"); 258 | Value::Null 259 | } 260 | 261 | pub fn readln(m: &mut Machine, _args: Vec) -> Value { 262 | let mut buffer = String::new(); 263 | stdin().read_line(&mut buffer).unwrap(); 264 | let obj = Value::Object(m.pool.allocate(Box::new(buffer))); 265 | obj 266 | } 267 | -------------------------------------------------------------------------------- /vm/src/opcodes.rs: -------------------------------------------------------------------------------- 1 | use colored; 2 | 3 | use self::colored::Colorize; 4 | 5 | #[derive(Clone)] 6 | pub enum Instruction 7 | { 8 | LoadString(usize, String), 9 | 10 | /// LoadBool R(A) = B 11 | /// 12 | /// Loading bool value B to register A 13 | LoadBool(usize, bool), 14 | 15 | ///LoadInt R(A) = B 16 | /// 17 | /// Loading integer value B to register A 18 | LoadInt(usize, i32), 19 | ///LoadLong R(A) = B 20 | /// 21 | /// Loading long value B to register A 22 | LoadLong(usize, i64), 23 | ///LoadFloat R(A) = B 24 | /// 25 | /// Loading float value B to register A 26 | LoadFloat(usize, f32), 27 | /// LoadDouble R(A) = B 28 | /// 29 | /// Loading double value B to register A 30 | LoadDouble(usize, f64), 31 | 32 | /// LoadConst R(A) = C(B) 33 | /// 34 | /// Load constant from object pool to register A 35 | LoadConst(usize, usize), 36 | /// LoadGlobal R(A) = G(B) 37 | /// 38 | /// Load global value B into register A 39 | LoadGlobal(usize, usize), 40 | /// LoadAt R(A) = R(B)\[C\] 41 | /// 42 | /// Load C from B and store in A 43 | LoadAt(usize, usize, usize), 44 | /// LoadSuper R(A) = R(B)\[C\] 45 | /// 46 | /// Load C from B and store in A 47 | LoadSuper(usize, usize, usize), 48 | /// Move R(A) = R(B) 49 | /// 50 | /// Move register 51 | Move(usize, usize), 52 | /// Store R(B)\[C\] = A 53 | /// 54 | /// Store A into R(B)\[C\] 55 | Store(usize, usize, usize), 56 | StoreAt(usize, usize, usize), 57 | /// StoreGlobal G(A) = R(B) 58 | /// 59 | /// Store global 60 | StoreGlobal(usize, usize), 61 | /// Jump IP 62 | Jump(usize), 63 | /// Jump (R(A) == false ? ip = B : continue) 64 | JumpF(usize, usize), 65 | 66 | /// Goto 67 | /// 68 | /// Same as Jump instructions, but uses labels 69 | Goto(usize), 70 | GotoF(usize, usize), 71 | 72 | /// Push value from R(A) to arguments stack 73 | LoadArg(usize), 74 | /// R(A) = B(Args), C - Arg count, args poped from arg stack 75 | Call(usize, usize, usize), 76 | 77 | Isa(usize,usize,usize), 78 | 79 | Not(usize, usize), 80 | ///Add R(A) = R(B) + R(C) 81 | Add(usize, usize, usize), 82 | ///Sub R(A) = R(B) - R(C) 83 | Sub(usize, usize, usize), 84 | ///Mul R(A) = R(B) * R(C) 85 | Mul(usize, usize, usize), 86 | ///Div R(A) = R(B) / R(C) 87 | Div(usize, usize, usize), 88 | Rem(usize, usize, usize), 89 | ///Gt R(A) = R(B) > R(C) 90 | Gt(usize, usize, usize), 91 | ///Lt R(A) = R(B) < R(C) 92 | Lt(usize, usize, usize), 93 | /// Ge R(A) = R(B) >= R(C) 94 | Ge(usize, usize, usize), 95 | /// Le R(A) = R(B) <= R(C) 96 | Le(usize, usize, usize), 97 | 98 | /// Eq R(A) = R(B) == R(C) 99 | Eq(usize, usize, usize), 100 | Neq(usize, usize, usize), 101 | /// Ret0 102 | /// 103 | /// return null value 104 | Ret0, 105 | /// Ret R(A) 106 | /// 107 | /// return value from R(A) 108 | Ret(usize), 109 | 110 | /// Create label with id A 111 | Label(usize), 112 | 113 | Shr(usize, usize, usize), 114 | Shl(usize, usize, usize), 115 | BitOr(usize, usize, usize), 116 | BitXor(usize, usize, usize), 117 | BitAnd(usize, usize, usize), 118 | And(usize, usize, usize), 119 | Or(usize, usize, usize), 120 | } 121 | 122 | use std::fmt; 123 | impl fmt::Display for Instruction 124 | { 125 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 126 | { 127 | use self::Instruction::*; 128 | 129 | match self { 130 | Neq(dest,r1,r2) => write!(f,"Neq {} {} {}",dest,r1,r2), 131 | Isa(dest,r1,r2) => write!(f,"Isa {} {} {}",dest,r1,r2), 132 | Not(r1, r2) => write!(f, "Not {} {}", r1, r2), 133 | Add(r3, r1, r2) => write!(f, "Add {} {} {}", r3, r1, r2), 134 | Sub(r3, r1, r2) => write!(f, "Sub {} {} {}", r3, r1, r2), 135 | Div(r3, r1, r2) => write!(f, "Div {} {} {}", r3, r1, r2), 136 | Mul(r3, r1, r2) => write!(f, "Mul {} {} {}", r3, r1, r2), 137 | Rem(r3, r1, r2) => write!(f, "Rem {} {} {}", r3, r1, r2), 138 | Gt(r3, r1, r2) => write!(f, "Gt {} {} {} ", r3, r1, r2), 139 | Lt(r3, r1, r2) => write!(f, "Lt {} {} {}", r3, r1, r2), 140 | Le(r3, r1, r2) => write!(f, "Le {} {} {}", r3, r1, r2), 141 | Ge(r3, r1, r2) => write!(f, "Ge {} {} {}", r3, r1, r2), 142 | Eq(r3, r1, r2) => write!(f, "Eq {} {} {}", r3, r1, r2), 143 | Ret0 => write!(f, "Ret0"), 144 | Ret(r1) => write!(f, "Ret {}", r1), 145 | Goto(label_id) => write!(f, "Goto {}", label_id), 146 | GotoF(r1, label_id) => write!(f, "GotoF {} {}", r1, label_id), 147 | Jump(ip) => write!(f, "Jump {}", ip), 148 | JumpF(r1, ip) => write!(f, "JumpF {} {}", r1, ip), 149 | LoadConst(r1, object_id) => write!(f, "LoadConst {} {}", r1, object_id), 150 | LoadGlobal(r1, global) => write!(f, "LoadGlobal {} {}", r1, global), 151 | LoadInt(r1, int) => write!(f, "LoadInt {} {}", r1, int), 152 | LoadLong(r1, long) => write!(f, "LoadLong {} {}", r1, long), 153 | LoadFloat(r1, float) => write!(f, "LoadFloat {} {}", r1, float), 154 | LoadDouble(r1, double) => write!(f, "LoadDouble {} {}", r1, double), 155 | LoadBool(r1, bool) => write!(f, "LoadBool {} {}", r1, bool), 156 | LoadString(r1, str) => write!(f, "LoadString {} \"{}\"", r1, str), 157 | StoreGlobal(r1, global) => write!(f, "StoreGlobal {} {}", r1, global), 158 | StoreAt(r1, r2, r3) => write!(f, "StoreAt {} {} {}", r1, r2, r3), 159 | Store(r1, r2, r3) => write!(f, "Store {} {} {}", r1, r2, r3), 160 | LoadAt(r1, r2, r3) => write!(f, "LoadAt {} {} {}", r1, r2, r3), 161 | BitAnd(r3, r1, r2) => write!(f, "BitAnd {} {} {}", r3, r1, r2), 162 | BitOr(r3, r1, r2) => write!(f, "BitOr {} {} {}", r3, r1, r2), 163 | BitXor(r3, r1, r2) => write!(f, "BitXor {} {} {}", r3, r1, r2), 164 | Or(r3, r1, r2) => write!(f, "Or {} {} {}", r3, r1, r2), 165 | And(r3, r1, r2) => write!(f, "And {} {} {}", r3, r1, r2), 166 | Shr(r3, r1, r2) => write!(f, "Shr {} {} {}", r3, r1, r2), 167 | Shl(r3, r1, r2) => write!(f, "Shl {} {} {}", r3, r1, r2), 168 | Label(id) => write!(f, "Label {}", id), 169 | Call(r3, r2, r1) => write!(f, "Call {} {} {}", r3, r2, r1), 170 | LoadArg(r1) => write!(f, "LoadArg {}", r1), 171 | Move(r1, r2) => write!(f, "Move {} {}", r1, r2), 172 | LoadSuper(r3, r2, r1) => write!(f, "LoadSuper {} {} {}", r3, r2, r1), 173 | } 174 | } 175 | } 176 | 177 | impl fmt::Debug for Instruction 178 | { 179 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 180 | { 181 | use self::Instruction::*; 182 | 183 | match self { 184 | Neq(dest,r1,r2) => write!(f,"Neq {} {} {}",dest,r1,r2), 185 | Isa(dest,r1,r2) => write!(f,"Isa {} {} {}",dest,r1,r2), 186 | Not(r1, r2) => write!(f, "Not {} {}", r1, r2), 187 | Add(r3, r1, r2) => write!(f, "Add {} {} {}", r3, r1, r2), 188 | Sub(r3, r1, r2) => write!(f, "Sub {} {} {}", r3, r1, r2), 189 | Div(r3, r1, r2) => write!(f, "Div {} {} {}", r3, r1, r2), 190 | Mul(r3, r1, r2) => write!(f, "Mul {} {} {}", r3, r1, r2), 191 | Rem(r3, r1, r2) => write!(f, "Rem {} {} {}", r3, r1, r2), 192 | Gt(r3, r1, r2) => write!(f, "Gt {} {} {} ", r3, r1, r2), 193 | Lt(r3, r1, r2) => write!(f, "Lt {} {} {}", r3, r1, r2), 194 | Le(r3, r1, r2) => write!(f, "Le {} {} {}", r3, r1, r2), 195 | Ge(r3, r1, r2) => write!(f, "Ge {} {} {}", r3, r1, r2), 196 | Eq(r3, r1, r2) => write!(f, "Eq {} {} {}", r3, r1, r2), 197 | Ret0 => write!(f, "Ret0"), 198 | Ret(r1) => write!(f, "Ret {}", r1), 199 | Goto(label_id) => write!(f, "Goto {}", label_id), 200 | GotoF(r1, label_id) => write!(f, "GotoF {} {}", r1, label_id), 201 | Jump(ip) => write!(f, "Jump {}", ip), 202 | JumpF(r1, ip) => write!(f, "JumpF {} {}", r1, ip), 203 | LoadConst(r1, object_id) => write!(f, "LoadConst {} {}", r1, object_id), 204 | LoadGlobal(r1, global) => write!(f, "LoadGlobal {} {}", r1, global), 205 | LoadInt(r1, int) => write!(f, "LoadInt {} {}", r1, int), 206 | LoadLong(r1, long) => write!(f, "LoadLong {} {}", r1, long), 207 | LoadFloat(r1, float) => write!(f, "LoadFloat {} {}", r1, float), 208 | LoadDouble(r1, double) => write!(f, "LoadDouble {} {}", r1, double), 209 | LoadBool(r1, bool) => write!(f, "LoadBool {} {}", r1, bool), 210 | LoadString(r1, str) => write!(f, "LoadString {} \"{}\"", r1, str), 211 | StoreGlobal(r1, global) => write!(f, "StoreGlobal {} {}", r1, global), 212 | StoreAt(r1, r2, r3) => write!(f, "StoreAt {} {} {}", r1, r2, r3), 213 | Store(r1, r2, r3) => write!(f, "Store {} {} {}", r1, r2, r3), 214 | LoadAt(r1, r2, r3) => write!(f, "LoadAt {} {} {}", r1, r2, r3), 215 | BitAnd(r3, r1, r2) => write!(f, "BitAnd {} {} {}", r3, r1, r2), 216 | BitOr(r3, r1, r2) => write!(f, "BitOr {} {} {}", r3, r1, r2), 217 | BitXor(r3, r1, r2) => write!(f, "BitXor {} {} {}", r3, r1, r2), 218 | Or(r3, r1, r2) => write!(f, "Or {} {} {}", r3, r1, r2), 219 | And(r3, r1, r2) => write!(f, "And {} {} {}", r3, r1, r2), 220 | Shr(r3, r1, r2) => write!(f, "Shr {} {} {}", r3, r1, r2), 221 | Shl(r3, r1, r2) => write!(f, "Shl {} {} {}", r3, r1, r2), 222 | Label(id) => write!(f, "Label {}", id), 223 | Call(r3, r2, r1) => write!(f, "Call {} {} {}", r3, r2, r1), 224 | LoadArg(r1) => write!(f, "LoadArg {}", r1), 225 | Move(r1, r2) => write!(f, "Move {} {}", r1, r2), 226 | LoadSuper(r3, r2, r1) => write!(f, "LoadSuper {} {} {}", r3, r2, r1), 227 | } 228 | } 229 | } 230 | 231 | ///Trait used for print Vec\ 232 | 233 | pub trait DebugCode 234 | { 235 | #[allow(non_snake_case)] 236 | fn toString(&self) -> String; 237 | } 238 | 239 | impl DebugCode for Vec 240 | { 241 | fn toString(&self) -> String 242 | { 243 | let mut str = String::new(); 244 | for i in 0..self.len() { 245 | str.push_str(&format!("{:04} {}", i, format!("{}", self[i]).white())); 246 | str.push('\n'); 247 | } 248 | str 249 | } 250 | } 251 | /// Stores instructions 252 | #[derive(Clone, Debug)] 253 | pub struct CodeBlock 254 | { 255 | pub code: Vec, 256 | pub ip: usize, 257 | } 258 | 259 | impl CodeBlock 260 | { 261 | /// Create new instance of CodeBlock 262 | pub fn new(ins: Vec) -> CodeBlock 263 | { 264 | CodeBlock { code: ins, ip: 0 } 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "ansi_term" 3 | version = "0.11.0" 4 | source = "registry+https://github.com/rust-lang/crates.io-index" 5 | dependencies = [ 6 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 7 | ] 8 | 9 | [[package]] 10 | name = "approx" 11 | version = "0.1.1" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | 14 | [[package]] 15 | name = "atty" 16 | version = "0.2.11" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | dependencies = [ 19 | "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 20 | "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 21 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 22 | ] 23 | 24 | [[package]] 25 | name = "bitflags" 26 | version = "1.0.4" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | 29 | [[package]] 30 | name = "chrono" 31 | version = "0.4.6" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | dependencies = [ 34 | "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", 35 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 36 | "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", 37 | ] 38 | 39 | [[package]] 40 | name = "clap" 41 | version = "2.32.0" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | dependencies = [ 44 | "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 45 | "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 46 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 47 | "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 48 | "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 49 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 50 | "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 51 | ] 52 | 53 | [[package]] 54 | name = "float_duration" 55 | version = "0.3.3" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | dependencies = [ 58 | "approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 59 | "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 60 | "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", 61 | "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", 62 | ] 63 | 64 | [[package]] 65 | name = "heck" 66 | version = "0.3.0" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | dependencies = [ 69 | "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 70 | ] 71 | 72 | [[package]] 73 | name = "jazz" 74 | version = "0.1.0" 75 | dependencies = [ 76 | "float_duration 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 77 | "jazz-vm 0.2.2", 78 | "structopt 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", 79 | "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", 80 | ] 81 | 82 | [[package]] 83 | name = "jazz-vm" 84 | version = "0.2.2" 85 | dependencies = [ 86 | "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 87 | "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", 88 | ] 89 | 90 | [[package]] 91 | name = "libc" 92 | version = "0.2.43" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | 95 | [[package]] 96 | name = "num-integer" 97 | version = "0.1.39" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | dependencies = [ 100 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 101 | ] 102 | 103 | [[package]] 104 | name = "num-traits" 105 | version = "0.2.6" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | 108 | [[package]] 109 | name = "proc-macro2" 110 | version = "0.4.24" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | dependencies = [ 113 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 114 | ] 115 | 116 | [[package]] 117 | name = "quote" 118 | version = "0.6.10" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | dependencies = [ 121 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 122 | ] 123 | 124 | [[package]] 125 | name = "redox_syscall" 126 | version = "0.1.42" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | 129 | [[package]] 130 | name = "redox_termios" 131 | version = "0.1.1" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | dependencies = [ 134 | "redox_syscall 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", 135 | ] 136 | 137 | [[package]] 138 | name = "serde" 139 | version = "1.0.80" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | 142 | [[package]] 143 | name = "strsim" 144 | version = "0.7.0" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | 147 | [[package]] 148 | name = "structopt" 149 | version = "0.2.13" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | dependencies = [ 152 | "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", 153 | "structopt-derive 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", 154 | ] 155 | 156 | [[package]] 157 | name = "structopt-derive" 158 | version = "0.2.13" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | dependencies = [ 161 | "heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 162 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 163 | "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 164 | "syn 0.15.21 (registry+https://github.com/rust-lang/crates.io-index)", 165 | ] 166 | 167 | [[package]] 168 | name = "syn" 169 | version = "0.15.21" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | dependencies = [ 172 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 173 | "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 174 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 175 | ] 176 | 177 | [[package]] 178 | name = "termion" 179 | version = "1.5.1" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | dependencies = [ 182 | "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 183 | "redox_syscall 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", 184 | "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 185 | ] 186 | 187 | [[package]] 188 | name = "textwrap" 189 | version = "0.10.0" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | dependencies = [ 192 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 193 | ] 194 | 195 | [[package]] 196 | name = "time" 197 | version = "0.1.40" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | dependencies = [ 200 | "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 201 | "redox_syscall 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", 202 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 203 | ] 204 | 205 | [[package]] 206 | name = "unicode-segmentation" 207 | version = "1.2.1" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | 210 | [[package]] 211 | name = "unicode-width" 212 | version = "0.1.5" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | 215 | [[package]] 216 | name = "unicode-xid" 217 | version = "0.1.0" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | 220 | [[package]] 221 | name = "vec_map" 222 | version = "0.8.1" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | 225 | [[package]] 226 | name = "winapi" 227 | version = "0.3.6" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | dependencies = [ 230 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 231 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 232 | ] 233 | 234 | [[package]] 235 | name = "winapi-i686-pc-windows-gnu" 236 | version = "0.4.0" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | 239 | [[package]] 240 | name = "winapi-x86_64-pc-windows-gnu" 241 | version = "0.4.0" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | 244 | [metadata] 245 | "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 246 | "checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" 247 | "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" 248 | "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" 249 | "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" 250 | "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" 251 | "checksum float_duration 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4aed8e3182af8f7f1227d88fe6203a83e7a0cff36a8f0af7195f11449217480e" 252 | "checksum heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82" 253 | "checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" 254 | "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" 255 | "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" 256 | "checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" 257 | "checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" 258 | "checksum redox_syscall 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "cf8fb82a4d1c9b28f1c26c574a5b541f5ffb4315f6c9a791fa47b6a04438fe93" 259 | "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" 260 | "checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef" 261 | "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" 262 | "checksum structopt 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "41c4a2479a078509940d82773d90ff824a8c89533ab3b59cd3ce8b0c0e369c02" 263 | "checksum structopt-derive 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "5352090cfae7a2c85e1a31146268b53396106c88ca5d6ccee2e3fae83b6e35c2" 264 | "checksum syn 0.15.21 (registry+https://github.com/rust-lang/crates.io-index)" = "816b7af21405b011a23554ea2dc3f6576dc86ca557047c34098c1d741f10f823" 265 | "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" 266 | "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" 267 | "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" 268 | "checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" 269 | "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" 270 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 271 | "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" 272 | "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" 273 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 274 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 275 | -------------------------------------------------------------------------------- /src/compiler.rs: -------------------------------------------------------------------------------- 1 | use crate::{builtins::*, class::Class, std_library::*}; 2 | 3 | use float_duration::TimePoint; 4 | use std::time::Instant; 5 | 6 | use std::collections::HashMap; 7 | 8 | use crate::{ 9 | ircode::FunctionBuilder, 10 | parser::{Expr, FnDef, Global, Op, Stmt}, 11 | }; 12 | use jazz_vm::{ 13 | function::Function, 14 | machine::Machine, 15 | object::ObjectAddon, 16 | opcodes::{DebugCode, Instruction}, 17 | value::Value, 18 | }; 19 | 20 | pub struct Compiler<'a> { 21 | pub machine: &'a mut Machine, 22 | pub builder: FunctionBuilder, 23 | pub gp: usize, 24 | pub globals: HashMap, 25 | pub debug: bool, 26 | } 27 | 28 | impl<'a> Compiler<'a> { 29 | pub fn new(m: &'a mut Machine, argc: usize, debug: bool) -> Compiler<'a> { 30 | let mut compiler = Compiler { 31 | machine: m, 32 | builder: FunctionBuilder::new(argc), 33 | globals: HashMap::new(), 34 | gp: 0, 35 | debug, 36 | }; 37 | compiler.register_builtins(); 38 | compiler 39 | } 40 | 41 | pub fn register_builtins(&mut self) { 42 | self.gp += 1; 43 | 44 | let id = self 45 | .machine 46 | .pool 47 | .allocate(Box::new(Function::from_native(Box::new(print)))); 48 | self.globals.insert("print".to_string(), self.gp); 49 | self.machine.globals.insert(self.gp, Value::Object(id)); 50 | self.gp += 1; 51 | let id = self 52 | .machine 53 | .pool 54 | .allocate(Box::new(Function::from_native(Box::new(readln)))); 55 | self.globals.insert("readln".to_string(), self.gp); 56 | self.machine.globals.insert(self.gp, Value::Object(id)); 57 | 58 | self.gp += 1; 59 | let id = self 60 | .machine 61 | .pool 62 | .allocate(Box::new(Function::from_native(Box::new(new_array)))); 63 | self.globals.insert("__new_array__".to_string(), self.gp); 64 | self.machine.globals.insert(self.gp, Value::Object(id)); 65 | self.gp += 1; 66 | let id = self 67 | .machine 68 | .pool 69 | .allocate(Box::new(Function::from_native(Box::new(concat)))); 70 | self.globals.insert("concat".to_owned(), self.gp); 71 | self.machine.globals.insert(self.gp, Value::Object(id)); 72 | self.gp += 1; 73 | let class = system_class(self.machine); 74 | let id = self.machine.pool.allocate(Box::new(class)); 75 | self.globals.insert("System".to_owned(), self.gp); 76 | self.machine.globals.insert(self.gp, Value::Object(id)); 77 | self.gp += 1; 78 | self.globals.insert("__unary_minus__".to_owned(), self.gp); 79 | let f = unary_minus(self.machine); 80 | self.machine.globals.insert(self.gp, f); 81 | self.gp += 1; 82 | let class = int_class(); 83 | let id = self.machine.pool.allocate(Box::new(class)); 84 | self.globals.insert("Int".to_owned(), self.gp); 85 | self.machine.globals.insert(self.gp, Value::Object(id)); 86 | self.gp += 1; 87 | let class = float_class(); 88 | let id = self.machine.pool.allocate(Box::new(class)); 89 | self.globals.insert("Float".to_owned(), self.gp); 90 | self.machine.globals.insert(self.gp, Value::Object(id)); 91 | self.gp += 1; 92 | let class = str_class(); 93 | let id = self.machine.pool.allocate(Box::new(class)); 94 | self.globals.insert("Str".to_owned(), self.gp); 95 | self.machine.globals.insert(self.gp, Value::Object(id)); 96 | } 97 | 98 | pub fn compile(&mut self, globals: Vec) -> Value { 99 | for global in globals.iter() { 100 | if let Global::ClassDefinition(ref class) = &global { 101 | let name = if let Expr::Identifier(ref n) = &*class.name { 102 | n.to_string() 103 | } else { 104 | "".to_string() 105 | }; 106 | self.machine.globals.insert(self.gp, Value::Int(255)); 107 | self.globals.insert(name, self.gp); 108 | }; 109 | 110 | if let Global::FnDefenition(ref fun) = &global { 111 | let name = if let Expr::Identifier(ref n) = &*fun.name { 112 | n.to_string() 113 | } else { 114 | "".to_string() 115 | }; 116 | self.machine.globals.insert(self.gp, Value::Int(0)); 117 | 118 | self.globals.insert(name.clone(), self.gp); 119 | } 120 | self.gp += 1; 121 | } 122 | 123 | for global in globals.iter() { 124 | if let Global::ClassDefinition(ref classdef) = global { 125 | let mut class = Class::new(); 126 | 127 | let name = if let Expr::Identifier(ref n) = &*classdef.name.clone() { 128 | n.to_string() 129 | } else { 130 | "".to_string() 131 | }; 132 | 133 | class.name = name.clone(); 134 | 135 | for fun in classdef.methods.iter() { 136 | let fun: FnDef = fun.clone(); 137 | let name = if let Expr::Identifier(ref n) = &*fun.name.clone() { 138 | n.to_string() 139 | } else { 140 | "".to_string() 141 | }; 142 | let builder = FunctionBuilder::new(fun.params.len()); 143 | self.builder = builder; 144 | for param in &fun.params { 145 | let reg = self.builder.register_first_temp_available(); 146 | self.builder.new_local(param.to_string(), reg); 147 | } 148 | self.translate_stmt(*fun.body); 149 | let code = self.builder.get_insts(); 150 | let func = Function::from_instructions(code, fun.params.len()); 151 | let func = self.machine.pool.allocate(Box::new(func)); 152 | unsafe { (&mut *class.fields.get()).insert(name, Value::Object(func)) }; 153 | } 154 | for (name, expr) in classdef.vars.iter() { 155 | let name = name.to_string(); 156 | if expr.is_some() { 157 | match &expr.clone().unwrap() { 158 | Expr::IntConst(int) => { 159 | unsafe { 160 | (&mut *class.fields.get()).insert(name, Value::Int(*int as i32)) 161 | }; 162 | } 163 | Expr::FloatConst(float) => { 164 | unsafe { 165 | (&mut *class.fields.get()) 166 | .insert(name, Value::Float(*float as f32)) 167 | }; 168 | } 169 | Expr::StringConst(str) => { 170 | let obj = Value::Object( 171 | self.machine.pool.allocate(Box::new(str.to_string())), 172 | ); 173 | unsafe { (&mut *class.fields.get()).insert(name, obj) }; 174 | } 175 | _ => unsafe { 176 | (&mut *class.fields.get()).insert(name, Value::Null); 177 | }, 178 | } 179 | } else { 180 | unsafe { 181 | (&mut *class.fields.get()).insert(name, Value::Null); 182 | }; 183 | } 184 | } 185 | 186 | let ptr = self.globals.get(&name).unwrap().clone(); 187 | 188 | let cls = self.machine.pool.allocate(Box::new(class)); 189 | self.machine.globals.insert(ptr, Value::Object(cls)); 190 | self.globals.insert(name, ptr); 191 | } 192 | 193 | if let Global::FnDefenition(ref fun) = global { 194 | let name = if let Expr::Identifier(ref n) = &*fun.name.clone() { 195 | n.to_string() 196 | } else { 197 | "main".to_string() 198 | }; 199 | 200 | let builder = FunctionBuilder::new(fun.params.len()); 201 | self.builder = builder; 202 | for param in &fun.params { 203 | let reg = self.builder.register_first_temp_available(); 204 | 205 | self.builder.new_local(param.to_string(), reg); 206 | } 207 | self.translate_stmt(*fun.clone().body); 208 | 209 | let code = self.builder.get_insts(); 210 | 211 | if self.debug { 212 | println!("function `{}` code: ", name); 213 | println!("{}", code.toString()); 214 | } 215 | 216 | let function = Function::from_instructions(code, fun.params.len()); 217 | let func = self.machine.pool.allocate(Box::new(function)); 218 | let ptr = self.globals.get(&name).unwrap().clone(); 219 | self.machine.globals.insert(ptr, Value::Object(func)); 220 | self.globals.insert(name, ptr); 221 | } 222 | } 223 | 224 | let main = self.globals.get("main").expect("main not found").clone(); 225 | let main = self.machine.globals.get(&main).expect("main not found"); 226 | let start = Instant::now(); 227 | let ret = self.machine.invoke(*main, vec![Value::Null]); 228 | let end = Instant::now(); 229 | println!( 230 | "RESULT: {} (in {})", 231 | ret.to_String(self.machine), 232 | end.float_duration_since(start).unwrap() 233 | ); 234 | ret 235 | } 236 | 237 | pub fn translate_stmt(&mut self, s: Stmt) { 238 | match s { 239 | Stmt::If(condition, then) => { 240 | let then = *then; 241 | let label_false = self.builder.new_label(); 242 | 243 | self.translate_expr(*condition); 244 | let reg = self.builder.register_pop(); 245 | self.builder.push_op(Instruction::GotoF(reg, label_false)); 246 | self.translate_stmt(then); 247 | self.builder.label_here(label_false); 248 | } 249 | 250 | Stmt::IfElse(condition, if_true, if_false) => { 251 | let label_false = self.builder.new_label(); 252 | 253 | self.translate_expr(*condition); 254 | let reg = self.builder.register_pop(); 255 | self.builder.push_op(Instruction::GotoF(reg, label_false)); 256 | self.translate_stmt(*if_true); 257 | self.builder.label_here(label_false); 258 | self.translate_stmt(*if_false); 259 | } 260 | 261 | Stmt::For(value, condition, expr, block) => { 262 | let compare = self.builder.new_label(); 263 | let end = self.builder.new_label(); 264 | 265 | self.translate_stmt(*value); 266 | self.builder.label_here(compare); 267 | 268 | self.translate_expr(*condition); 269 | let reg = self.builder.register_pop(); 270 | self.builder.push_op(Instruction::GotoF(reg, end)); 271 | self.translate_stmt(*block); 272 | self.translate_expr(*expr); 273 | self.builder.push_op(Instruction::Goto(compare)); 274 | self.builder.label_here(end); 275 | } 276 | 277 | Stmt::While(condition, block) => { 278 | let compare = self.builder.new_label(); 279 | let end = self.builder.new_label(); 280 | 281 | self.builder.label_here(compare); 282 | 283 | self.translate_expr(*condition); 284 | let reg = self.builder.register_pop(); 285 | self.builder.push_op(Instruction::GotoF(reg, end)); 286 | self.translate_stmt(*block); 287 | self.builder.push_op(Instruction::Goto(compare)); 288 | self.builder.label_here(end); 289 | } 290 | 291 | Stmt::Var(ref name, ref expr) => { 292 | let name = name.to_string(); 293 | let expr = expr.clone(); 294 | 295 | if expr.is_some() { 296 | self.translate_expr(*expr.unwrap().clone()); 297 | let r = self.builder.register_pop(); 298 | self.builder.new_local(name, r); 299 | } else { 300 | let r = self.builder.register_first_temp_available(); 301 | self.builder.new_local(name, r); 302 | } 303 | } 304 | Stmt::Return => { 305 | self.builder.push_op(Instruction::Ret0); 306 | } 307 | Stmt::ReturnWithVal(val) => { 308 | self.translate_expr(*val); 309 | let r = self.builder.register_pop(); 310 | self.builder.push_op(Instruction::Ret(r)); 311 | } 312 | 313 | Stmt::Block(body) => { 314 | for stmt in body.iter() { 315 | self.translate_stmt(stmt.clone()); 316 | } 317 | } 318 | Stmt::Expr(expr) => { 319 | self.translate_expr(*expr.clone()); 320 | } 321 | v => panic!("{:?}", v), 322 | } 323 | } 324 | 325 | pub fn translate_expr(&mut self, expr: Expr) { 326 | match expr { 327 | Expr::IntConst(int) => { 328 | self.builder.long_const(int); 329 | } 330 | Expr::FloatConst(float) => { 331 | self.builder.double_const(float); 332 | } 333 | 334 | Expr::This => { 335 | let r = self.builder.register_push_temp(); 336 | self.builder.push_op(Instruction::Move(r, 0)); 337 | } 338 | 339 | Expr::FnCall(ref fname, ref args) => { 340 | let mut args = args.clone(); 341 | args.reverse(); 342 | for arg in args.iter() { 343 | self.translate_expr(arg.clone()); 344 | let r = self.builder.register_pop(); 345 | self.builder.push_op(Instruction::LoadArg(r)); 346 | } 347 | 348 | let fptr = if !self.globals.contains_key(fname) { 349 | let r = self.builder.get_local(fname); 350 | r 351 | } else { 352 | let idx = self 353 | .globals 354 | .get(fname) 355 | .expect(&format!("Function not found `{}`", fname)); 356 | let register = self.builder.register_push_temp(); 357 | self.builder 358 | .push_op(Instruction::LoadGlobal(register, *idx)); 359 | register 360 | }; 361 | let mut dest = fptr; 362 | let mut _dest_is_temp = self.builder.register_is_temp(dest); 363 | if !_dest_is_temp { 364 | dest = self.builder.register_push_temp(); 365 | _dest_is_temp = true; 366 | } 367 | self.builder.push_op(Instruction::LoadArg(fptr)); 368 | self.builder 369 | .push_op(Instruction::Call(dest, fptr, args.len())); 370 | } 371 | 372 | Expr::New(name, args) => { 373 | let mut args = args.clone(); 374 | args.reverse(); 375 | for arg in args.iter() { 376 | self.translate_expr(arg.clone()); 377 | let r = self.builder.register_pop(); 378 | self.builder.push_op(Instruction::LoadArg(r)); 379 | } 380 | 381 | let dest = self.builder.register_push_temp(); 382 | let fptr = if !self.globals.contains_key(&name) { 383 | let r = self.builder.get_local(&name); 384 | r 385 | } else { 386 | let idx = self 387 | .globals 388 | .get(&name) 389 | .expect(&format!("Function not found `{}`", name)); 390 | let register = self.builder.register_first_temp_available(); 391 | self.builder 392 | .push_op(Instruction::LoadGlobal(register, *idx)); 393 | register 394 | }; 395 | 396 | self.builder.push_op(Instruction::LoadArg(fptr)); 397 | self.builder 398 | .push_op(Instruction::Call(dest, fptr, args.len())); 399 | } 400 | 401 | Expr::Array(arr_expr) => { 402 | for expr in arr_expr.iter() { 403 | self.translate_expr(expr.clone()); 404 | let r = self.builder.register_pop(); 405 | self.builder.push_op(Instruction::LoadArg(r)); 406 | } 407 | 408 | let id = self.globals.get("__new_array__").unwrap(); 409 | let reg = self.builder.register_push_temp(); 410 | self.builder.push_op(Instruction::LoadGlobal(reg, *id)); 411 | self.builder.push_op(Instruction::LoadArg(reg)); 412 | let dest = self.builder.register_push_temp(); 413 | self.builder 414 | .push_op(Instruction::Call(dest, reg, arr_expr.len())); 415 | } 416 | 417 | Expr::Op(op, e1, e2) => { 418 | self.translate_operation(op, e1, e2); 419 | } 420 | 421 | Expr::StringConst(ref s) => { 422 | let r = self.builder.register_push_temp(); 423 | self.builder 424 | .push_op(Instruction::LoadString(r, s.to_string())); 425 | } 426 | 427 | Expr::Identifier(ref name) => { 428 | if !self.globals.contains_key(name) { 429 | let r = self.builder.get_local(name); 430 | let r2 = self.builder.register_push_temp(); 431 | self.builder.push_op(Instruction::Move(r2, r)); 432 | } else { 433 | let idx = self.globals.get(name).unwrap(); 434 | let register = self.builder.register_push_temp(); 435 | self.builder 436 | .push_op(Instruction::LoadGlobal(register, *idx)); 437 | } 438 | } 439 | 440 | Expr::Assignment(e1, e2) => { 441 | let e1 = *e1; 442 | let e2 = *e2; 443 | 444 | if let Expr::Identifier(ref name) = e1 { 445 | self.translate_expr(e2.clone()); 446 | if self.globals.contains_key(name) { 447 | let id = self.globals.get(name).unwrap(); 448 | let r = self.builder.register_pop(); 449 | self.builder.push_op(Instruction::StoreGlobal(r, *id)); 450 | } else { 451 | let r1 = self.builder.get_local(name); 452 | let r2 = self.builder.register_pop(); 453 | self.builder.push_op(Instruction::Move(r1, r2)); 454 | } 455 | } 456 | if let Expr::Op(Op::Access, this, fname) = e1 { 457 | let r2 = self.builder.register_push_temp(); 458 | 459 | if let Expr::Identifier(n) = *fname { 460 | self.builder.push_op(Instruction::LoadString(r2, n)); 461 | } else { 462 | panic!(""); 463 | }; 464 | 465 | self.translate_expr(e2.clone()); 466 | let value = self.builder.register_pop(); 467 | self.builder.register_push_temp(); 468 | self.translate_expr(*this); 469 | let this = self.builder.register_pop(); 470 | self.builder.push_op(Instruction::StoreAt(value, this, r2)); 471 | } 472 | } 473 | Expr::False => { 474 | let reg = self.builder.register_push_temp(); 475 | self.builder.push_op(Instruction::LoadBool(reg, false)); 476 | } 477 | Expr::True => { 478 | let reg = self.builder.register_push_temp(); 479 | self.builder.push_op(Instruction::LoadBool(reg, true)); 480 | } 481 | Expr::Index(name, idx) => { 482 | let target = if self.globals.contains_key(&name) { 483 | let gp = self.globals.get(&name).unwrap(); 484 | let dest = self.builder.register_push_temp(); 485 | self.builder.push_op(Instruction::LoadGlobal(dest, *gp)); 486 | dest 487 | } else { 488 | let r = self.builder.get_local(&name); 489 | let r2 = self.builder.register_push_temp(); 490 | self.builder.push_op(Instruction::Move(r2, r)); 491 | r2 492 | }; 493 | self.translate_expr(*idx); 494 | let reg = self.builder.register_pop(); 495 | 496 | let dest = self.builder.register_push_temp(); 497 | self.builder.push_op(Instruction::LoadAt(dest, target, reg)); 498 | } 499 | Expr::Unit => { 500 | let _r = self.builder.register_push_temp(); 501 | } 502 | v => panic!("Unimplemented {:?}", v), 503 | } 504 | } 505 | 506 | pub fn translate_operation(&mut self, op: Op, e1: Box, e2: Box) { 507 | if op == Op::Access { 508 | match (*e1, *e2) { 509 | (this, Expr::Identifier(field)) => { 510 | let r2 = self.builder.register_push_temp(); 511 | self.translate_expr(this); 512 | let r1 = self.builder.register_pop(); 513 | self.builder.push_op(Instruction::LoadString(r2, field)); 514 | let r3 = self.builder.register_push_temp(); 515 | self.builder.push_op(Instruction::LoadAt(r3, r1, r2)); 516 | self.builder.register_clear(r1); 517 | self.builder.register_clear(r2); 518 | } 519 | (this, Expr::FnCall(fname, args)) => { 520 | let mut args = args.clone(); 521 | args.reverse(); 522 | for arg in args.iter() { 523 | self.translate_expr(arg.clone()); 524 | let r = self.builder.register_pop(); 525 | 526 | self.builder.push_op(Instruction::LoadArg(r)); 527 | } 528 | self.translate_expr(this); 529 | let r1 = self.builder.register_pop(); 530 | let mut r2 = self.builder.register_push_temp(); 531 | if self.builder.register_is_temp(r2) { 532 | r2 = self.builder.register_push_temp(); 533 | } 534 | let r3 = self.builder.register_push_temp(); 535 | self.builder.push_op(Instruction::LoadArg(r1)); 536 | 537 | self.builder.push_op(Instruction::LoadString(r2, fname)); 538 | 539 | self.builder.push_op(Instruction::LoadAt(r3, r1, r2)); 540 | //self.builder.register_pop(); 541 | let mut dest = self.builder.register_push_temp(); 542 | let mut _dest_is_temp = self.builder.register_is_temp(dest); 543 | if !_dest_is_temp { 544 | dest = self.builder.register_push_temp(); 545 | _dest_is_temp = true; 546 | } 547 | self.builder 548 | .push_op(Instruction::Call(dest, r3, args.len())); 549 | self.builder.register_clear(r3); 550 | self.builder.register_clear(r1); 551 | self.builder.register_clear(r2); 552 | } 553 | v => panic!("Unimplemented {:?}", v), 554 | } 555 | } else { 556 | if op == Op::Not { 557 | let e1 = *e1; 558 | 559 | self.translate_expr(e1); 560 | let r = self.builder.register_pop(); 561 | let r2 = self.builder.register_push_temp(); 562 | 563 | self.builder.push_op(Instruction::Not(r2, r)); 564 | return; 565 | } 566 | 567 | let e1 = *e1; 568 | let e2 = *e2; 569 | 570 | self.translate_expr(e1); 571 | self.translate_expr(e2); 572 | let r3 = self.builder.register_pop(); 573 | let r2 = self.builder.register_pop(); 574 | let r1 = self.builder.register_push_temp(); 575 | match op { 576 | Op::Ne => self.builder.push_op(Instruction::Neq(r1,r2,r3)), 577 | Op::Add => self.builder.push_op(Instruction::Add(r1, r2, r3)), 578 | Op::Sub => self.builder.push_op(Instruction::Sub(r1, r2, r3)), 579 | Op::Mul => self.builder.push_op(Instruction::Mul(r1, r2, r3)), 580 | Op::Div => self.builder.push_op(Instruction::Div(r1, r2, r3)), 581 | Op::Eq => self.builder.push_op(Instruction::Eq(r1, r2, r3)), 582 | Op::Gt => self.builder.push_op(Instruction::Gt(r1, r2, r3)), 583 | Op::Lt => self.builder.push_op(Instruction::Lt(r1, r2, r3)), 584 | Op::Le => self.builder.push_op(Instruction::Le(r1, r2, r3)), 585 | Op::Ge => self.builder.push_op(Instruction::Ge(r1, r2, r3)), 586 | Op::And => self.builder.push_op(Instruction::And(r1, r2, r3)), 587 | Op::Or => self.builder.push_op(Instruction::Or(r1, r2, r3)), 588 | Op::BitOr => self.builder.push_op(Instruction::BitOr(r1, r2, r3)), 589 | Op::BitAnd => self.builder.push_op(Instruction::BitAnd(r1, r2, r3)), 590 | Op::BitXor => self.builder.push_op(Instruction::BitXor(r1, r2, r3)), 591 | Op::Shl => self.builder.push_op(Instruction::Shl(r1, r2, r3)), 592 | Op::Shr => self.builder.push_op(Instruction::Shr(r1, r2, r3)), 593 | Op::Isa => self.builder.push_op(Instruction::Isa(r1, r2, r3)), 594 | _ => unimplemented!(), 595 | } 596 | self.builder.register_clear(r2); 597 | self.builder.register_clear(r3); 598 | } 599 | } 600 | } 601 | -------------------------------------------------------------------------------- /vm/src/machine.rs: -------------------------------------------------------------------------------- 1 | use crate::{frame::*, object::ObjectAddon, object_pool::ObjectPool, opcodes::*, value::Value}; 2 | use std::collections::HashMap; 3 | use crate::error::VmError; 4 | 5 | macro_rules! for_c { 6 | ($v:ident = $v1:expr; $e:expr;$ex:expr, $b: block) => { 7 | let mut $v = $v1; 8 | while $e { 9 | $b 10 | $ex 11 | } 12 | }; 13 | } 14 | 15 | ///Machine that executes code 16 | #[derive(Default)] 17 | pub struct Machine 18 | { 19 | pub stack: Vec, 20 | pub pool: ObjectPool, 21 | pub globals: HashMap, 22 | pub labels: HashMap, 23 | } 24 | 25 | impl Machine 26 | { 27 | pub fn new() -> Machine 28 | { 29 | Machine { 30 | stack: Vec::with_capacity(4096), 31 | pool: ObjectPool::new(), 32 | globals: HashMap::new(), 33 | labels: HashMap::new(), 34 | } 35 | } 36 | /// Get last frame in CallStack 37 | pub fn last_frame(&self) -> &CallFrame 38 | { 39 | self.stack.last().unwrap() 40 | } 41 | 42 | /// Get mutable reference to last frame in CallStack 43 | pub fn last_frame_mut(&mut self) -> &mut CallFrame 44 | { 45 | self.stack.last_mut().unwrap() 46 | } 47 | /// Get value for register 48 | pub fn get(&mut self, rnum: usize) -> Value 49 | { 50 | self.last_frame().get(rnum) 51 | } 52 | 53 | /// Set `this` value 54 | pub fn set_this(&mut self, v: Value) 55 | { 56 | self.last_frame_mut().stack[0] = v; 57 | } 58 | /// Set R(r) = v 59 | pub fn set(&mut self, r: usize, v: Value) 60 | { 61 | self.last_frame_mut().set(r, v); 62 | } 63 | /// Update instruction pointer 64 | pub fn dispatch(&mut self) 65 | { 66 | self.last_frame_mut().ip += 1; 67 | } 68 | /// Invoke callable object 69 | pub fn invoke(&mut self, callable: Value, args: Vec) -> Value 70 | { 71 | let id = match callable { 72 | Value::Object(id) => id, 73 | v => { 74 | panic!("Not callable {:?}", v); 75 | } 76 | }; 77 | 78 | let obj = self.pool.get(id); 79 | self.stack.push(CallFrame::new()); 80 | 81 | self.last_frame_mut().init_with_args(&args.as_slice()); 82 | obj.call(self, args) 83 | } 84 | /// Goto 85 | pub fn branch(&mut self, idx: usize) 86 | { 87 | self.last_frame_mut().ip = idx; 88 | } 89 | /// Run instructions 90 | pub fn run_code(&mut self, code: Vec) -> Result 91 | { 92 | for_c!(i = 0;i < code.len();i += 1, { 93 | if let Instruction::Label(lbl_id) = code[i] { 94 | 95 | self.labels.insert(lbl_id, i); 96 | 97 | }; 98 | }); 99 | 100 | self.last_frame_mut().code = code; 101 | self.last_frame_mut().ip = 0; 102 | 103 | self.execute_op() 104 | } 105 | /// Execute all opcodes in current frame 106 | pub fn execute_op(&mut self) -> Result 107 | { 108 | let mut returns = false; 109 | let mut ret = Value::Null; 110 | let start = super::time::PreciseTime::now(); 111 | 112 | while self.last_frame().ip < self.last_frame().code.len() { 113 | if returns { 114 | break; 115 | } 116 | 117 | let opcode = self.last_frame().code[self.last_frame().ip].clone(); 118 | self.last_frame_mut().ip += 1; 119 | //println!("{:?}",self.last_frame().code[self.last_frame().ip]); 120 | match &opcode { 121 | Instruction::Label(_label_id) => {} 122 | 123 | Instruction::LoadArg(r1) => { 124 | let value = self.get(*r1); 125 | self.last_frame_mut().arg_stack.push(value); 126 | } 127 | 128 | Instruction::LoadBool(dest, boolean) => { 129 | self.set(*dest, Value::Bool(*boolean)); 130 | } 131 | 132 | Instruction::LoadInt(dest, int) => { 133 | self.set(*dest, Value::Int(*int)); 134 | } 135 | 136 | Instruction::LoadString(r1, ref string) => { 137 | let string = string.to_string(); 138 | let object_id = self.pool.allocate(Box::new(string)); 139 | self.set(*r1, Value::Object(object_id)); 140 | } 141 | 142 | Instruction::LoadDouble(dest, double) => { 143 | self.set(*dest, Value::Double(*double)); 144 | } 145 | 146 | Instruction::LoadLong(dest, long) => { 147 | self.set(*dest, Value::Long(*long)); 148 | } 149 | 150 | Instruction::LoadFloat(dest, float) => { 151 | self.set(*dest, Value::Float(*float)); 152 | } 153 | 154 | Instruction::Isa(dest,r1,r2) => { 155 | let (v1,v2) = (self.get(*r1),self.get(*r2)); 156 | let n = v2.typename(self); 157 | println!("{:?}",v2.typename(self)); 158 | let result = v1.isa(n,self); 159 | self.set(*dest,Value::Bool(result)); 160 | } 161 | 162 | Instruction::Add(dest, r1, r2) => { 163 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 164 | 165 | let result = match (v1, v2) { 166 | (Value::Int(i), Value::Int(i2)) => Value::Int(i + i2), 167 | (Value::Float(f), Value::Float(f2)) => Value::Float(f + f2), 168 | (Value::Long(i), Value::Long(i2)) => Value::Long(i + i2), 169 | (Value::Double(f), Value::Double(f2)) => Value::Double(f + f2), 170 | (Value::Int(i), Value::Long(i2)) => Value::Long((i as i64) + i2), 171 | (Value::Long(i), Value::Int(i2)) => Value::Long(i + (i2 as i64)), 172 | (Value::Float(f), Value::Double(f2)) => Value::Double((f as f64) + f2), 173 | (Value::Double(f), Value::Float(f2)) => Value::Double(f + (f2 as f64)), 174 | (Value::Long(l), v) => Value::Long(l + v.to_long(self)), 175 | (Value::Int(i), v) => Value::Int(i + v.to_int(self)), 176 | (Value::Double(d), v) => Value::Double(d + v.to_double(self)), 177 | (Value::Float(f), v) => Value::Float(f + v.to_float(self)), 178 | (v, Value::Null) => v, 179 | (Value::Null, v) => v, 180 | v => panic!("{:?}", v), 181 | }; 182 | 183 | self.set(*dest, result); 184 | } 185 | 186 | Instruction::Call(dest, r2, argc) => { 187 | let args = { 188 | let mut temp: Vec = vec![]; 189 | let this = self 190 | .last_frame_mut() 191 | .arg_stack 192 | .pop() 193 | .expect("Expected this value"); 194 | 195 | temp.push(this); 196 | 197 | for _ in 0..*argc { 198 | let v = self.last_frame_mut().arg_stack.pop(); 199 | 200 | match v { 201 | None => temp.push(Value::Null), // if less arguments are passed then fill the holes with Null values 202 | Some(v) => temp.push(v), 203 | }; 204 | } 205 | 206 | temp 207 | }; 208 | 209 | let value = self.get(*r2); 210 | let v = self.invoke(value, args); 211 | self.stack.pop(); 212 | self.set(*dest, v); 213 | } 214 | Instruction::Sub(dest, r1, r2) => { 215 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 216 | 217 | let result = match (v1, v2) { 218 | (Value::Int(i), Value::Int(i2)) => Value::Int(i - i2), 219 | (Value::Float(f), Value::Float(f2)) => Value::Float(f - f2), 220 | (Value::Long(i), Value::Long(i2)) => Value::Long(i - i2), 221 | (Value::Double(f), Value::Double(f2)) => Value::Double(f - f2), 222 | (Value::Int(i), Value::Long(i2)) => Value::Long((i as i64) - i2), 223 | (Value::Long(i), Value::Int(i2)) => Value::Long(i - (i2 as i64)), 224 | (Value::Float(f), Value::Double(f2)) => Value::Double((f as f64) - f2), 225 | (Value::Double(f), Value::Float(f2)) => Value::Double(f - (f2 as f64)), 226 | (Value::Long(l), v) => Value::Long(l - v.to_long(self)), 227 | (Value::Int(i), v) => Value::Int(i - v.to_int(self)), 228 | (Value::Double(d), v) => Value::Double(d - v.to_double(self)), 229 | (Value::Float(f), v) => Value::Float(f - v.to_float(self)), 230 | (v, Value::Null) => v, 231 | (Value::Null, v) => v, 232 | _ => unimplemented!(), 233 | }; 234 | 235 | self.set(*dest, result); 236 | } 237 | 238 | Instruction::Div(dest, r1, r2) => { 239 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 240 | 241 | let result = match (v1, v2) { 242 | (Value::Int(i), Value::Int(i2)) => Value::Int(i / i2), 243 | (Value::Float(f), Value::Float(f2)) => Value::Float(f / f2), 244 | (Value::Long(i), Value::Long(i2)) => Value::Long(i / i2), 245 | (Value::Double(f), Value::Double(f2)) => Value::Double(f / f2), 246 | (Value::Int(i), Value::Long(i2)) => Value::Long((i as i64) / i2), 247 | (Value::Long(i), Value::Int(i2)) => Value::Long(i / (i2 as i64)), 248 | (Value::Float(f), Value::Double(f2)) => Value::Double((f as f64) / f2), 249 | (Value::Double(f), Value::Float(f2)) => Value::Double(f / (f2 as f64)), 250 | (Value::Long(l), v) => Value::Long(l / v.to_long(self)), 251 | (Value::Int(i), v) => Value::Int(i / v.to_int(self)), 252 | (Value::Double(d), v) => Value::Double(d / v.to_double(self)), 253 | (Value::Float(f), v) => Value::Float(f / v.to_float(self)), 254 | (v, Value::Null) => v, 255 | (Value::Null, v) => v, 256 | _ => unimplemented!(), 257 | }; 258 | 259 | self.set(*dest, result); 260 | } 261 | 262 | Instruction::Mul(dest, r1, r2) => { 263 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 264 | 265 | let result = match (v1, v2) { 266 | (Value::Int(i), Value::Int(i2)) => Value::Int(i * i2), 267 | (Value::Float(f), Value::Float(f2)) => Value::Float(f * f2), 268 | (Value::Long(i), Value::Long(i2)) => Value::Long(i * i2), 269 | (Value::Double(f), Value::Double(f2)) => Value::Double(f * f2), 270 | (Value::Int(i), Value::Long(i2)) => Value::Long((i as i64) * i2), 271 | (Value::Long(i), Value::Int(i2)) => Value::Long(i * (i2 as i64)), 272 | (Value::Float(f), Value::Double(f2)) => Value::Double((f as f64) * f2), 273 | (Value::Double(f), Value::Float(f2)) => Value::Double(f * (f2 as f64)), 274 | (Value::Long(l), v) => Value::Long(l * v.to_long(self)), 275 | (Value::Int(i), v) => Value::Int(i * v.to_int(self)), 276 | (Value::Double(d), v) => Value::Double(d * v.to_double(self)), 277 | (Value::Float(f), v) => Value::Float(f * v.to_float(self)), 278 | (v, Value::Null) => v, 279 | (Value::Null, v) => v, 280 | v => panic!("Cannot mul {:?}", v), 281 | }; 282 | 283 | self.set(*dest, result); 284 | } 285 | 286 | Instruction::LoadConst(r1, idx) => { 287 | self.set(*r1, Value::Object(*idx)); 288 | } 289 | 290 | Instruction::Not(r1, r2) => { 291 | let v = self.get(*r2); 292 | let result = Value::Bool(v.not(self)); 293 | self.set(*r1, result); 294 | } 295 | 296 | Instruction::Gt(dest, r1, r2) => { 297 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 298 | let result = match (v1, v2) { 299 | (Value::Int(i), Value::Int(i2)) => Value::Bool(i > i2), 300 | (Value::Long(i), Value::Long(i2)) => Value::Bool(i > i2), 301 | (Value::Float(f), Value::Float(f2)) => Value::Bool(f > f2), 302 | (Value::Double(f), Value::Double(f2)) => Value::Bool(f > f2), 303 | (Value::Int(i), Value::Long(i2)) => Value::Bool((i as i64) > i2), 304 | (Value::Long(i), Value::Int(i2)) => Value::Bool(i > (i2 as i64)), 305 | (Value::Float(f), Value::Double(f2)) => Value::Bool((f as f64) > f2), 306 | (Value::Double(f), Value::Float(f2)) => Value::Bool(f > (f2 as f64)), 307 | (Value::Long(l), v) => Value::Bool(l > v.to_long(self)), 308 | (Value::Int(i), v) => Value::Bool(i > v.to_int(self)), 309 | (Value::Double(d), v) => Value::Bool(d > v.to_double(self)), 310 | (Value::Float(f), v) => Value::Bool(f > v.to_float(self)), 311 | (v, Value::Null) => v, 312 | (Value::Null, v) => v, 313 | v => panic!("{:?}", v), 314 | }; 315 | 316 | self.set(*dest, result); 317 | } 318 | Instruction::Ge(dest, r1, r2) => { 319 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 320 | let result = match (v1, v2) { 321 | (Value::Int(i), Value::Int(i2)) => Value::Bool(i >= i2), 322 | (Value::Long(i), Value::Long(i2)) => Value::Bool(i >= i2), 323 | (Value::Float(f), Value::Float(f2)) => Value::Bool(f >= f2), 324 | (Value::Double(f), Value::Double(f2)) => Value::Bool(f >= f2), 325 | (Value::Int(i), Value::Long(i2)) => Value::Bool((i as i64) >= i2), 326 | (Value::Long(i), Value::Int(i2)) => Value::Bool(i >= (i2 as i64)), 327 | (Value::Float(f), Value::Double(f2)) => Value::Bool((f as f64) >= f2), 328 | (Value::Double(f), Value::Float(f2)) => Value::Bool(f >= (f2 as f64)), 329 | (Value::Long(l), v) => Value::Bool(l >= v.to_long(self)), 330 | (Value::Int(i), v) => Value::Bool(i >= v.to_int(self)), 331 | (Value::Double(d), v) => Value::Bool(d >= v.to_double(self)), 332 | (Value::Float(f), v) => Value::Bool(f >= v.to_float(self)), 333 | (v, Value::Null) => v, 334 | (Value::Null, v) => v, 335 | _ => unimplemented!(), 336 | }; 337 | 338 | self.set(*dest, result); 339 | } 340 | 341 | Instruction::Le(dest, r1, r2) => { 342 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 343 | let result = match (v1, v2) { 344 | (Value::Int(i), Value::Int(i2)) => Value::Bool(i <= i2), 345 | (Value::Long(i), Value::Long(i2)) => Value::Bool(i <= i2), 346 | (Value::Float(f), Value::Float(f2)) => Value::Bool(f <= f2), 347 | (Value::Double(f), Value::Double(f2)) => Value::Bool(f <= f2), 348 | (Value::Int(i), Value::Long(i2)) => Value::Bool((i as i64) <= i2), 349 | (Value::Long(i), Value::Int(i2)) => Value::Bool(i <= (i2 as i64)), 350 | (Value::Float(f), Value::Double(f2)) => Value::Bool((f as f64) <= f2), 351 | (Value::Double(f), Value::Float(f2)) => Value::Bool(f <= (f2 as f64)), 352 | (Value::Long(l), v) => Value::Bool(l <= v.to_long(self)), 353 | (Value::Int(i), v) => Value::Bool(i <= v.to_int(self)), 354 | (Value::Double(d), v) => Value::Bool(d <= v.to_double(self)), 355 | (Value::Float(f), v) => Value::Bool(f <= v.to_float(self)), 356 | (v, Value::Null) => v, 357 | (Value::Null, v) => v, 358 | v => panic!("Unimplemented {:?}",v), 359 | }; 360 | 361 | self.set(*dest, result); 362 | } 363 | 364 | Instruction::Lt(dest, r1, r2) => { 365 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 366 | let result = match (v1, v2) { 367 | (Value::Int(i), Value::Int(i2)) => Value::Bool(i < i2), 368 | (Value::Long(i), Value::Long(i2)) => Value::Bool(i < i2), 369 | (Value::Float(f), Value::Float(f2)) => Value::Bool(f < f2), 370 | (Value::Double(f), Value::Double(f2)) => Value::Bool(f < f2), 371 | (Value::Int(i), Value::Long(i2)) => Value::Bool((i as i64) < i2), 372 | (Value::Long(i), Value::Int(i2)) => Value::Bool(i < (i2 as i64)), 373 | (Value::Float(f), Value::Double(f2)) => Value::Bool((f as f64) < f2), 374 | (Value::Double(f), Value::Float(f2)) => Value::Bool(f < (f2 as f64)), 375 | (Value::Long(l), v) => Value::Bool(l < v.to_long(self)), 376 | (Value::Int(i), v) => Value::Bool(i < v.to_int(self)), 377 | (Value::Double(d), v) => Value::Bool(d < v.to_double(self)), 378 | (Value::Float(f), v) => Value::Bool(f < v.to_float(self)), 379 | (v, Value::Null) => v, 380 | (Value::Null, v) => v, 381 | (v, v1) => panic!("{:?} < {:?}", v.to_String(self), v1.to_String(self)), 382 | }; 383 | 384 | self.set(*dest, result); 385 | } 386 | Instruction::BitAnd(r3, r1, r2) => { 387 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 388 | 389 | let result = match (v1, v2) { 390 | (Value::Long(l), Value::Long(l1)) => Value::Long(l & l1), 391 | (Value::Int(i), Value::Int(i2)) => Value::Int(i & i2), 392 | v => panic!("BitAnd cannot be aplied to {:?}", v), 393 | }; 394 | self.set(*r3, result); 395 | } 396 | Instruction::BitOr(r3, r1, r2) => { 397 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 398 | 399 | let result = match (v1, v2) { 400 | (Value::Long(l), Value::Long(l1)) => Value::Long(l | l1), 401 | (Value::Int(i), Value::Int(i2)) => Value::Int(i | i2), 402 | v => panic!("BitOr cannot be aplied to {:?}", v), 403 | }; 404 | self.set(*r3, result); 405 | } 406 | Instruction::BitXor(r3, r1, r2) => { 407 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 408 | 409 | let result = match (v1, v2) { 410 | (Value::Long(l), Value::Long(l1)) => Value::Long(l ^ l1), 411 | (Value::Int(i), Value::Int(i2)) => Value::Int(i ^ i2), 412 | v => panic!("BitOr cannot be aplied to {:?}", v), 413 | }; 414 | self.set(*r3, result); 415 | } 416 | Instruction::Shl(r3, r1, r2) => { 417 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 418 | 419 | let result = match (v1, v2) { 420 | (Value::Long(l), Value::Long(l1)) => Value::Long(l << l1), 421 | (Value::Int(i), Value::Int(i2)) => Value::Int(i << i2), 422 | v => panic!("BitOr cannot be aplied to {:?}", v), 423 | }; 424 | self.set(*r3, result); 425 | } 426 | Instruction::Shr(r3, r1, r2) => { 427 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 428 | 429 | let result = match (v1, v2) { 430 | (Value::Long(l), Value::Long(l1)) => Value::Long(l >> l1), 431 | (Value::Int(i), Value::Int(i2)) => Value::Int(i >> i2), 432 | v => panic!("BitOr cannot be aplied to {:?}", v), 433 | }; 434 | self.set(*r3, result); 435 | } 436 | Instruction::And(r3, r1, r2) => { 437 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 438 | 439 | let result = match (v1, v2) { 440 | (Value::Bool(b), Value::Bool(b2)) => Value::Bool(b && b2), 441 | v => panic!("And cannot be aplied to {:?}", v), 442 | }; 443 | 444 | self.set(*r3, result); 445 | } 446 | Instruction::Or(r3, r1, r2) => { 447 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 448 | 449 | let result = match (v1, v2) { 450 | (Value::Bool(b), Value::Bool(b2)) => Value::Bool(b || b2), 451 | v => panic!("Or cannot be aplied to {:?}", v), 452 | }; 453 | 454 | self.set(*r3, result); 455 | } 456 | Instruction::Eq(r3, r1, r2) => { 457 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 458 | let result = match (v1, v2) { 459 | (Value::Int(i), Value::Int(i2)) => Value::Bool(i == i2), 460 | (Value::Long(i), Value::Long(i2)) => Value::Bool(i == i2), 461 | (Value::Float(f), Value::Float(f2)) => Value::Bool(f == f2), 462 | (Value::Double(f), Value::Double(f2)) => Value::Bool(f == f2), 463 | (Value::Int(i), Value::Long(i2)) => Value::Bool((i as i64) == i2), 464 | (Value::Long(i), Value::Int(i2)) => Value::Bool(i == (i2 as i64)), 465 | (Value::Float(f), Value::Double(f2)) => Value::Bool((f as f64) == f2), 466 | (Value::Double(f), Value::Float(f2)) => Value::Bool(f == (f2 as f64)), 467 | (Value::Long(l), v) => Value::Bool(l == v.to_long(self)), 468 | (Value::Int(i), v) => Value::Bool(i == v.to_int(self)), 469 | (Value::Double(d), v) => Value::Bool(d == v.to_double(self)), 470 | (Value::Float(f), v) => Value::Bool(f == v.to_float(self)), 471 | (_v, Value::Null) => Value::Bool(false), 472 | (Value::Null, _v) => Value::Bool(false), 473 | _ => unimplemented!(), 474 | }; 475 | 476 | self.set(*r3, result); 477 | } 478 | 479 | Instruction::Neq(r3, r1, r2) => { 480 | let (v1, v2) = (self.get(*r1), self.get(*r2)); 481 | let result = match (v1, v2) { 482 | (Value::Int(i), Value::Int(i2)) => Value::Bool(i != i2), 483 | (Value::Long(i), Value::Long(i2)) => Value::Bool(i != i2), 484 | (Value::Float(f), Value::Float(f2)) => Value::Bool(f != f2), 485 | (Value::Double(f), Value::Double(f2)) => Value::Bool(f != f2), 486 | (Value::Int(i), Value::Long(i2)) => Value::Bool((i as i64) != i2), 487 | (Value::Long(i), Value::Int(i2)) => Value::Bool(i == (i2 as i64)), 488 | (Value::Float(f), Value::Double(f2)) => Value::Bool((f as f64) != f2), 489 | (Value::Double(f), Value::Float(f2)) => Value::Bool(f != (f2 as f64)), 490 | (Value::Long(l), v) => Value::Bool(l != v.to_long(self)), 491 | (Value::Int(i), v) => Value::Bool(i != v.to_int(self)), 492 | (Value::Double(d), v) => Value::Bool(d != v.to_double(self)), 493 | (Value::Float(f), v) => Value::Bool(f != v.to_float(self)), 494 | (_v, Value::Null) => Value::Bool(false), 495 | (Value::Null, _v) => Value::Bool(false), 496 | _ => unimplemented!(), 497 | }; 498 | 499 | self.set(*r3, result); 500 | } 501 | 502 | Instruction::Goto(lbl_id) => { 503 | if self.labels.contains_key(lbl_id) { 504 | let idx = &self.labels[lbl_id]; 505 | self.branch(*idx + 1); 506 | } else { 507 | return Err(VmError::LabelNotFound(*lbl_id)); 508 | } 509 | } 510 | 511 | Instruction::GotoF(r1, lbl_id) => match self.get(*r1) { 512 | Value::Bool(b) => { 513 | if !b { 514 | if self.labels.contains_key(lbl_id) { 515 | let idx = &self.labels[lbl_id]; 516 | self.branch(*idx + 1); 517 | } else { 518 | return Err(VmError::LabelNotFound(*lbl_id)); 519 | } 520 | } 521 | } 522 | 523 | _v => return Err(VmError::RuntimeError("GotoF exptected Bool value".into())), 524 | }, 525 | 526 | Instruction::Jump(idx) => { 527 | self.branch(*idx); 528 | } 529 | 530 | Instruction::LoadGlobal(r1, index) => { 531 | if self.globals.contains_key(index) { 532 | let value = &self.globals[index]; 533 | self.set(*r1, *value); 534 | } else { 535 | return Err(VmError::GlobalNotFound(*index)); 536 | } 537 | } 538 | 539 | Instruction::StoreGlobal(r1, index) => { 540 | let value = self.get(*r1); 541 | self.globals.insert(*index, value); 542 | } 543 | 544 | Instruction::JumpF(r1, idx) => { 545 | let v = self.get(*r1); 546 | if let Value::Bool(b) = v { 547 | if !b { 548 | self.branch(*idx); 549 | } 550 | } else { 551 | return Err(VmError::RuntimeError("Expected Bool value; Op JumpF".into())); 552 | } 553 | } 554 | 555 | Instruction::Move(r1, r2) => { 556 | let v = self.get(*r2); 557 | 558 | self.last_frame_mut().stack[*r1] = v; 559 | } 560 | 561 | Instruction::Ret(idx) => { 562 | 563 | ret = self.get(*idx); 564 | returns = true; 565 | } 566 | 567 | Instruction::Ret0 => { 568 | returns = true; 569 | } 570 | 571 | Instruction::LoadAt(r1, r2, r3) => { 572 | let v2 = self.get(*r2); 573 | let v3 = self.get(*r3); 574 | 575 | if let Value::Object(obj_id) = v2 { 576 | let obj = self.pool.get(obj_id); 577 | let this = self.get(*r2); 578 | obj.load_at(self, vec![this, v3], *r1); 579 | } else { 580 | return Err(VmError::Expected("Value::Object".into(),format!("{:?}",v2))); 581 | } 582 | } 583 | 584 | Instruction::StoreAt(r1, r2, r3) => { 585 | let value = self.get(*r1); 586 | let target = self.get(*r2); 587 | let key = self.get(*r3); 588 | if let Value::Object(obj_id) = &target { 589 | let obj = self.pool.get(*obj_id); 590 | obj.store_at(self, vec![target, key, value], 0); 591 | } else { 592 | return Err(VmError::Expected("Value::Object".into(),format!("{:?}",&target))); 593 | } 594 | } 595 | 596 | v => panic!("{:?}", v), 597 | } 598 | 599 | } 600 | let end = super::time::PreciseTime::now(); 601 | 602 | let _result = start.to(end).num_milliseconds(); 603 | 604 | Ok(ret) 605 | } 606 | } 607 | --------------------------------------------------------------------------------