├── .gitignore ├── debug.log ├── Cargo.toml ├── src ├── script │ ├── error.rs │ ├── variable.rs │ ├── parser.rs │ └── mod.rs ├── vm.rs ├── main.rs └── default_opcodes.rs ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /debug.log: -------------------------------------------------------------------------------- 1 | [0112/012824:ERROR:tcp_listen_socket.cc(76)] Could not bind socket to 127.0.0.1:6004 2 | [0112/012824:ERROR:node_debugger.cc(86)] Cannot start debugger server 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cleovm" 3 | version = "0.1.0" 4 | authors = ["ZOTTCE "] 5 | 6 | [dependencies] 7 | byteorder = "*" 8 | time = "*" 9 | docopt = "*" 10 | rustc-serialize = "*" -------------------------------------------------------------------------------- /src/script/error.rs: -------------------------------------------------------------------------------- 1 | // use std::error; 2 | use std::fmt; 3 | 4 | #[derive(Debug)] 5 | pub enum OpcodeHandlerErr { 6 | CannotParseArg, 7 | UndefinedCondArg, 8 | NotCorrectType(String), 9 | } 10 | 11 | impl fmt::Display for OpcodeHandlerErr { 12 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 13 | match *self { 14 | OpcodeHandlerErr::CannotParseArg => write!(f, "Cannot parse arguments of opcode"), 15 | OpcodeHandlerErr::UndefinedCondArg => write!(f, "Undefined an argument of condition"), 16 | OpcodeHandlerErr::NotCorrectType(ref text) => write!(f, "This type is not correct. Expected type is {}", text), 17 | } 18 | } 19 | } 20 | 21 | /* TODO 22 | impl error::Error for OpcodeHandlerErr { 23 | 24 | } 25 | */ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CLEO Virtual Machine 2 | ## About Opcodes 3 | Every opcode has the syntax: `0001: wait %d%` where `0001` is an opcode id, `%d` any param. 4 | 5 | For example `0002: jump 0xABCD` as bytecode `02 00 05 CD AB`. 6 | 7 | CLEO VM has the following types of arguments: 8 | 9 | | Type | ID | Example | Result | 10 | |-------------|----|----------------------|------------| 11 | | Int8 | 04 | 04 EA | 0xEA | 12 | | Int16 | 05 | 05 AB CD | 0xCDAB | 13 | | Int32 | 01 | 01 AB CD EF 00 | 0x00EFCDAB | 14 | | Float | 06 | 06 5C 8F C2 3F | 1.52 | 15 | | Local var | 03 | 03 0A 00 | 10@ | 16 | | Global var* | 02 | 02 0A 0F | $3850 | 17 | | String | 0E | 0E 05 68 65 6C 6C 6F | "hello" | 18 | 19 | \* Global variables unimplemented yet. 20 | 21 | ## Current Default Opcodes 22 | ### 0001: wait @int 23 | Set a wake up timer for the script. 24 | Example: `0001: wait 10` 25 | 26 | ### 0002: jump @label 27 | Jump to address. 28 | Example: `0002: jump @some_label` 29 | 30 | ### 0003: @var = @any 31 | Binding a variable (local). 32 | Example: `0003: 0@ = 10` 33 | 34 | ### Some math opcodes 35 | Work same as opcode `0003`. **Any value except String** 36 | ``` 37 | 0004: @var += @any 38 | 0005: @var -= @any 39 | 0006: @var *= @any 40 | 0007: @var /= @any 41 | ``` 42 | 43 | ### 0008: if @int 44 | Set flags of VM. 45 | `@int = 0` - only one opcode must be true (not or). `LogicalOpcode::One`. 46 | `@int = 1 .. 7` - same as AND. `LogicalOpcode::And`. 47 | `@int = 21 .. 27` - same as OR. `LogicalOpcode::Or`. 48 | 49 | ### 0009: jump_if_false @int 50 | Jump to label if a condition is false. Example 51 | ``` 52 | 0008: if and 53 | 00AB: some_opcode 10 50 54 | 0AF0: some_opcode 2@ 55 | 0009: jump_if_false @condition_false 56 | // here is true 57 | 58 | 59 | :condition_false 60 | // here is false 61 | 62 | ``` 63 | 64 | ### 000A: print @any 65 | Print in IO any value. 66 | ``` 67 | 0003: 10@ = 2.8 68 | 000A: print 10@ // will print "10@ = 2.8" 69 | 000A: print 5.1 // will print "5.1" 70 | ``` 71 | 72 | ### 0010: @var == @any 73 | Using in conditions. 74 | ``` 75 | 0008: if 76 | 0010: 10@ > 5 77 | 0009: jump_if_false @less_than_5 78 | < do something > 79 | ``` 80 | ### Some logical opcodes 81 | **Always return false for strings!** You have to implement custom opcodes or upgrade current. 82 | ``` 83 | 0011: @var != @any 84 | 0012: @var > @any 85 | 0013: @var < @any 86 | 0014: @var >= @any 87 | 0015: @var <= @any 88 | ``` -------------------------------------------------------------------------------- /src/vm.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::cell::RefCell; 3 | use std::rc::Rc; 4 | use script::Script; 5 | use script::error::OpcodeHandlerErr; 6 | 7 | pub struct VirtualMachine { 8 | vars: Rc>>, 9 | scripts: HashMap, 10 | handlers: HashMap Result>>, 11 | } 12 | 13 | impl VirtualMachine { 14 | pub fn new() -> VirtualMachine { 15 | VirtualMachine { 16 | vars: Rc::new(RefCell::new(Vec::new())), 17 | scripts: HashMap::new(), 18 | handlers: HashMap::new(), 19 | } 20 | } 21 | 22 | pub fn tick(&mut self) { 23 | for (name, mut script) in self.scripts.iter_mut() { 24 | if !script.is_active() { 25 | continue; 26 | } 27 | 28 | if let Some(opcode) = script.get_opcode() { 29 | if let Some(handler) = self.handlers.get(&opcode) { 30 | match handler(&mut script) { 31 | Ok(result) => script.set_cond_result(result), 32 | Err(e) => { 33 | let (offset, bytes) = script.get_error(); 34 | println!("Error: Script \"{}\" at [{:04X}]{} ({}), desc: {}", name, opcode, offset, pretty_bytes(bytes), e); 35 | } 36 | } 37 | } else { 38 | let (offset, bytes) = script.get_error(); 39 | println!("Error: Script \"{}\" called undefined opcode {:X} at position {}, code: {:?}", name, opcode, offset, pretty_bytes(bytes)); 40 | } 41 | } else { 42 | script.done = true; 43 | } 44 | } 45 | } 46 | 47 | pub fn append_script(&mut self, name: String, bytes: Vec) { 48 | let script = Script::new(&name, bytes, self.vars.clone()); 49 | self.scripts.insert(name, script); 50 | } 51 | 52 | pub fn set_handler(&mut self, opcode: u16, handler: F) where F: Fn(&mut Script) -> Result + 'static { 53 | self.handlers.insert(opcode, Box::new(handler)); 54 | } 55 | 56 | pub fn is_done(&self, name: String) -> bool { 57 | match self.scripts.get(&name) { 58 | Some(ref script) => script.done, 59 | None => false, 60 | } 61 | } 62 | } 63 | 64 | pub fn pretty_bytes(bytes: &[u8]) -> String { 65 | let mut string = String::from("[ "); 66 | 67 | for byte in bytes.iter() { 68 | string.push_str(format!("{:02X}, ", byte).as_str()); 69 | } 70 | 71 | string.pop(); 72 | string.pop(); 73 | string.push_str(" ]"); 74 | 75 | string 76 | } -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code, unused_variables)] 2 | #![feature(heap_api, alloc)] 3 | extern crate rustc_serialize; 4 | extern crate docopt; 5 | 6 | mod script; 7 | mod vm; 8 | mod default_opcodes; 9 | 10 | use default_opcodes::DefaultOpcodes; 11 | use docopt::Docopt; 12 | 13 | #[derive(RustcDecodable)] 14 | struct Args { 15 | arg_name: String, 16 | arg_bytecode: String 17 | } 18 | 19 | fn main() { 20 | /*//let bytecode: Vec = vec![0x00, 0x00, 0x03, 0x00, 0x03, 0x01, 0x00, 0x04, 0x05, 0x0A, 0x00, 0x03, 0x01, 0x00, 0x04, 0x00, 0x03, 0x01, 0x00, 0x04, 0x05, 0x0A, 0x00, 0x03, 0x01, 0x00, 0x05, 0x00, 0x03, 0x01, 0x00, 0x04, 0x01, 0x0A, 0x00, 0x03, 0x01, 0x00, 0x06, 0x00, 0x03, 0x01, 0x00, 0x04, 0x04, 0x0A, 0x00, 0x03, 0x01, 0x00, 0x07, 0x00, 0x03, 0x01, 0x00, 0x04, 0x04, 0x0A, 0x00, 0x03, 0x01, 0x00]; 21 | //let bytecode: Vec = vec![0x00, 0x00, 0x03, 0x00, 0x03, 0x01, 0x00, 0x04, 0x05, 0x0A, 0x00, 0x03, 0x01, 0x00, 0x0E, 0x00, 0x01, 0xCF, 0xFF, 0xFF, 0xFF, 0x04, 0x02, 0x03, 0x01, 0x00, 0x04, 0x0A, 0x03, 0x02, 0x00, 0x00, 0x0A, 0x00, 0x03, 0x01, 0x00, 0x0A, 0x00, 0x03, 0x02, 0x00, 0x02, 0x00, 0x01, 0xF7, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x03, 0x19, 0x00, 0x03, 0x00, 0x00, 0x04, 0x00, 0x03, 0x19, 0x00, 0x03, 0x01, 0x00, 0x0E, 0x00, 0x01, 0xAA, 0xFF, 0xFF, 0xFF, 0x04, 0x01, 0x03, 0x19, 0x00, 0x00, 0x0F, 0x00, 0x04, 0x01, 0x03, 0x19, 0x00, 0x00, 0x0A, 0x00, 0x03, 0x00, 0x00, 0x0F, 0x00, 0x04, 0x00, 0x00]; 22 | let bytecode: Vec = vec![0x00, 0x00, 0x03, 0x00, 0x03, 0x01, 0x00, 0x0E, 0x11, 0x48, 0x45, 0x4C, 0x4C, 0x4F, 0x57, 0x20, 0x4D, 0x59, 0x20, 0x46, 0x52, 0x49, 0x45, 0x4E, 0x44, 0x21, 0x0A, 0x00, 0x03, 0x01, 0x00]; 23 | let mut vm = vm::VirtualMachine::new(); 24 | 25 | vm.append_script("test".to_string(), bytecode); 26 | vm.set_default_opcodes(); 27 | 28 | loop { 29 | vm.tick(); 30 | }*/ 31 | 32 | let usage = "Usage: cleovm "; 33 | let args: Args = Docopt::new(usage) 34 | .and_then(|d| d.argv(std::env::args()).decode()) 35 | .unwrap_or_else(|e| e.exit()); 36 | 37 | //println!("{}, {}", args.arg_name, args.arg_bytecode); 38 | let bytecode = text_to_bytes(&args.arg_bytecode); 39 | 40 | 41 | let mut vm = vm::VirtualMachine::new(); 42 | 43 | // .\cleovm.exe "test" "000003000301000E1148454C4C4F57204D5920465249454E44210A00030100" 44 | 45 | vm.append_script(args.arg_name.clone(), bytecode); 46 | vm.set_default_opcodes(); 47 | 48 | while !vm.is_done(args.arg_name.clone()) { 49 | vm.tick(); 50 | } 51 | } 52 | 53 | fn text_to_bytes(text: &String) -> Vec { 54 | let mut i = 0; 55 | let mut bytes: Vec = Vec::new(); 56 | 57 | while i < text.len() { 58 | let byte = &text[i..i+2]; 59 | bytes.push(parse_byte(&byte)); 60 | i += 2; 61 | } 62 | 63 | return bytes; 64 | } 65 | 66 | fn parse_byte(text: &str) -> u8 { 67 | let mut value = 0; 68 | let mut idx = 1; 69 | 70 | for byte in text.bytes() { 71 | let half = match byte { 72 | b'0'...b'9' => byte - b'0', 73 | b'A'...b'F' => byte - b'A' + 10, 74 | _ => panic!("fuck gg"), 75 | }; 76 | 77 | value += half << (4 * idx); 78 | 79 | idx -= 1; 80 | } 81 | 82 | return value; 83 | } -------------------------------------------------------------------------------- /src/script/variable.rs: -------------------------------------------------------------------------------- 1 | extern crate alloc; 2 | 3 | #[derive(Clone, PartialEq)] 4 | pub enum VariableKind { 5 | Integer, 6 | Float, 7 | String, 8 | } 9 | 10 | pub struct Variable { 11 | pub kind: VariableKind, 12 | ptr: *mut u8, 13 | pub id: usize, 14 | } 15 | 16 | pub struct VarInfo { 17 | kind: VariableKind, 18 | value: usize, 19 | } 20 | 21 | pub enum VariableType { 22 | Global(usize), 23 | Local(usize), 24 | } 25 | 26 | impl Variable { 27 | pub fn new(kind: VariableKind, value: T, id: usize) -> Variable { 28 | unsafe { 29 | let var = Variable { 30 | kind: kind, 31 | ptr: alloc::heap::allocate(32, 32), 32 | id: id, 33 | }; 34 | 35 | *(var.ptr as *mut T) = value; 36 | 37 | var 38 | } 39 | } 40 | 41 | pub fn from_raw(id: usize, raw: &VarInfo) -> Variable { 42 | Variable::new(raw.kind.clone(), raw.value, id) 43 | } 44 | 45 | pub fn into_raw(&self) -> VarInfo { 46 | VarInfo { 47 | kind: self.kind.clone(), 48 | value: self.get(), 49 | } 50 | } 51 | 52 | pub fn from(&mut self, other: &Variable) { 53 | self.kind = other.kind.clone(); 54 | self.set(other.get::()); 55 | } 56 | 57 | pub fn clone(&self) -> Variable { 58 | Variable::new(self.kind.clone(), self.get::(), self.id) 59 | } 60 | 61 | pub fn do_stuff(&mut self, other: &Variable, f: F) where F: Fn(T, T) -> T { 62 | let a = self.get::(); 63 | let b = other.get::(); 64 | self.set(f(a, b)); 65 | } 66 | 67 | pub fn get(&self) -> T { 68 | unsafe { 69 | ::std::ptr::read(self.ptr as *const T) 70 | } 71 | } 72 | 73 | pub fn set(&mut self, value: T) { 74 | unsafe { 75 | *(self.ptr as *mut T) = value; 76 | } 77 | } 78 | 79 | pub fn get_str(&self) -> String { 80 | unsafe { 81 | ::std::ffi::CString::from_raw(self.get()).into_string().unwrap() 82 | } 83 | } 84 | 85 | pub fn set_str(&mut self, val: String) { 86 | unsafe { 87 | let len = val.bytes().len(); 88 | let ptr = alloc::heap::allocate(len + 1, 8); 89 | ::std::ptr::copy(val.as_ptr(), ptr, len); 90 | self.set(ptr as usize); 91 | } 92 | } 93 | 94 | pub fn change(&mut self, kind: VariableKind) { 95 | self.kind = kind; 96 | } 97 | 98 | pub fn eq_types(&self, other: &Variable) -> bool { 99 | self.kind == other.kind 100 | } 101 | } 102 | 103 | impl Drop for Variable { 104 | fn drop(&mut self) { 105 | unsafe { 106 | alloc::heap::deallocate(self.ptr, 32, 32); 107 | } 108 | } 109 | } 110 | 111 | impl PartialEq for Variable { 112 | fn eq(&self, other: &Variable) -> bool { 113 | self.eq_types(&other) && self.get::() == other.get::() 114 | } 115 | } 116 | 117 | impl ::std::fmt::Display for Variable { 118 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 119 | match self.kind { 120 | VariableKind::Integer => write!(f, "{}@: integer {}", self.id, self.get::()), 121 | VariableKind::Float => write!(f, "{}@: float {}", self.id, self.get::()), 122 | VariableKind::String => write!(f, "{}@: string \"{}\"", self.id, self.get_str()), 123 | } 124 | } 125 | } -------------------------------------------------------------------------------- /src/script/parser.rs: -------------------------------------------------------------------------------- 1 | extern crate byteorder; 2 | 3 | use std::rc::Rc; 4 | use std::cell::RefCell; 5 | use std::io::Cursor; 6 | use self::byteorder::{LittleEndian, ReadBytesExt}; 7 | use ::script::variable::{Variable, VariableType}; 8 | 9 | pub enum ArgType { 10 | None, 11 | Integer(u32), 12 | Float(f32), 13 | String(String), 14 | Var(Rc>), 15 | } 16 | 17 | pub trait Parser { 18 | fn parse_int(&mut self) -> Option; 19 | fn parse_float(&mut self) -> Option; 20 | fn parse_string(&mut self) -> Option; 21 | fn parse_var(&mut self) -> Option>>; 22 | fn parse_any_arg(&mut self) -> Option; 23 | } 24 | 25 | impl Parser for super::Script { 26 | fn parse_int(&mut self) -> Option { 27 | let offset = self.offset; 28 | /* 29 | 0x01 - 32 bits 30 | 0x04 - 8 bits 31 | 0x05 - 16 bits 32 | */ 33 | 34 | if offset >= self.bytes.len() { 35 | return None; 36 | } 37 | 38 | match self.bytes[offset] { 39 | 0x01 => { 40 | self.offset += 5; 41 | let mut buffer = Cursor::new(&self.bytes[offset + 1 .. offset + 5]); 42 | buffer.read_u32::().ok() 43 | }, 44 | 0x04 => { 45 | self.offset += 2; 46 | Some(self.bytes[offset + 1] as u32) 47 | }, 48 | 0x05 => { 49 | self.offset += 3; 50 | let mut buffer = Cursor::new(&self.bytes[offset + 1 .. offset + 3]); 51 | Some(buffer.read_u16::().unwrap() as u32) 52 | }, 53 | _ => None, 54 | } 55 | } 56 | 57 | fn parse_float(&mut self) -> Option { 58 | let offset = self.offset; 59 | 60 | if offset + 4 < self.bytes.len() && self.bytes[offset] == 0x06 { 61 | self.offset += 5; 62 | let mut buffer = Cursor::new(&self.bytes[offset + 1 .. offset + 5]); 63 | buffer.read_f32::().ok() 64 | } else { 65 | None 66 | } 67 | } 68 | 69 | fn parse_string(&mut self) -> Option { 70 | let offset = self.offset; 71 | 72 | if self.bytes[offset] == 0x0E && offset + 1 < self.bytes.len() { 73 | let length = self.bytes[offset + 1] as usize; 74 | 75 | if length + offset <= self.bytes.len() { 76 | self.offset += 2 + length; 77 | String::from_utf8(Vec::from(&self.bytes[offset + 2 .. offset + 2 + length])).ok() 78 | } else { 79 | None 80 | } 81 | } else { 82 | None 83 | } 84 | } 85 | 86 | fn parse_var(&mut self) -> Option>> { 87 | /* 88 | 0x02 - Variable::Global 89 | 0x03 - Variable::Local 90 | */ 91 | 92 | let offset = self.offset; 93 | 94 | let var = match self.bytes[offset] { 95 | 0x02 => { 96 | self.offset += 3; 97 | let mut buffer = Cursor::new(&self.bytes[offset + 1 .. offset + 3]); 98 | Some(VariableType::Global(buffer.read_u16::().unwrap() as usize)) 99 | }, 100 | 0x03 => { 101 | self.offset += 3; 102 | let mut buffer = Cursor::new(&self.bytes[offset + 1 .. offset + 3]); 103 | Some(VariableType::Local(buffer.read_u16::().unwrap() as usize)) 104 | }, 105 | _ => None, 106 | }; 107 | 108 | if let Some(variable) = var { 109 | Some(self.get_variable(variable)) 110 | } else { 111 | None 112 | } 113 | } 114 | 115 | fn parse_any_arg(&mut self) -> Option { 116 | match self.bytes[self.offset] { 117 | 0x01 | 0x04 | 0x05 => self.parse_int().and_then(|val| Some(ArgType::Integer(val))), 118 | 0x02 | 0x03 => self.parse_var().and_then(|val| Some(ArgType::Var(val))), 119 | 0x06 => self.parse_float().and_then(|val| Some(ArgType::Float(val))), 120 | 0x0E => self.parse_string().and_then(|val| Some(ArgType::String(val))), 121 | _ => Some(ArgType::None), 122 | } 123 | } 124 | } 125 | 126 | impl ::std::fmt::Display for ArgType { 127 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 128 | match *self { 129 | ArgType::Integer(val) => write!(f, "{}", val), 130 | ArgType::Float(val) => write!(f, "{}", val), 131 | ArgType::String(ref val) => write!(f, "{}", val), 132 | ArgType::Var(ref val) => write!(f, "{}", *val.borrow()), 133 | ArgType::None => write!(f, "None value"), 134 | } 135 | } 136 | } -------------------------------------------------------------------------------- /src/script/mod.rs: -------------------------------------------------------------------------------- 1 | extern crate time; 2 | 3 | use std::cell::RefCell; 4 | use std::rc::Rc; 5 | use self::time::Duration; 6 | use std::time::Instant; 7 | 8 | pub mod parser; 9 | pub mod error; 10 | pub mod variable; 11 | 12 | use self::parser::Parser; 13 | use self::variable::*; 14 | 15 | pub enum LogicalOpcode { 16 | One, 17 | And, 18 | Or, 19 | } 20 | 21 | pub struct Script { 22 | pub bytes: Vec, 23 | name: String, 24 | pub offset: usize, 25 | pub local_vars: Vec>>, 26 | global_vars: Rc>>, 27 | active: bool, 28 | pub done: bool, 29 | pub cond_result: bool, 30 | logical_opcode: LogicalOpcode, 31 | pub stack: Vec, 32 | wake_up: u32, 33 | instant: Instant, 34 | not_flag: bool, 35 | } 36 | 37 | impl Script { 38 | pub fn new(name: &String, bytes: Vec, vars: Rc>>) -> Script { 39 | let mut local_vars: Vec>> = Vec::new(); 40 | 41 | for i in 0..32 { 42 | local_vars.push(Rc::new(RefCell::new(Variable::new(VariableKind::Integer, 0, i)))); 43 | } 44 | 45 | Script { 46 | bytes: bytes, 47 | name: name.clone(), 48 | offset: 0, 49 | local_vars: local_vars, 50 | global_vars: vars, 51 | active: true, 52 | cond_result: false, 53 | logical_opcode: LogicalOpcode::One, 54 | stack: Vec::new(), 55 | wake_up: 0, 56 | instant: Instant::now(), 57 | not_flag: false, 58 | done: false, 59 | } 60 | } 61 | 62 | pub fn get_error(&self) -> (usize, &[u8]) { 63 | let length = if self.offset + 3 >= self.bytes.len() { 64 | self.bytes.len() 65 | } else { 66 | self.offset + 3 67 | }; 68 | (self.offset, &self.bytes[self.offset - 2..length]) 69 | } 70 | 71 | pub fn get_opcode(&mut self) -> Option { 72 | if self.offset + 1 >= self.bytes.len() { 73 | None 74 | } else { 75 | let opcode: u16 = ((self.bytes[self.offset + 1] as u16) << 8) + (self.bytes[self.offset] as u16); 76 | self.offset += 2; 77 | 78 | if opcode & 0x8000 != 0 { 79 | self.not_flag = true; 80 | Some(opcode ^ 0x8000) 81 | } else { 82 | self.not_flag = false; 83 | Some(opcode) 84 | } 85 | } 86 | } 87 | 88 | pub fn set_cond_result(&mut self, result: bool) { 89 | let new = result ^ self.not_flag; 90 | 91 | match self.logical_opcode { 92 | LogicalOpcode::One => self.cond_result = new, 93 | LogicalOpcode::And => self.cond_result &= new, 94 | LogicalOpcode::Or => self.cond_result |= new, 95 | } 96 | } 97 | 98 | pub fn set_logical_opcode(&mut self, result: LogicalOpcode) -> bool { 99 | self.logical_opcode = result; 100 | true 101 | } 102 | 103 | pub fn get_variable(&mut self, var: VariableType) -> Rc> { 104 | match var { 105 | VariableType::Local(id) => self.local_vars[id].clone(), 106 | VariableType::Global(id) => unimplemented!(), 107 | } 108 | } 109 | 110 | pub fn skip_args(&mut self, count: usize) -> bool { 111 | for _ in 0..count { 112 | match self.parse_any_arg() { 113 | Some(_) => continue, 114 | None => return false, 115 | } 116 | } 117 | 118 | true 119 | } 120 | 121 | pub fn jump_to(&mut self, address: usize) -> bool { 122 | self.offset = 0xFFFFFFFF - address + 1; 123 | true 124 | } 125 | 126 | pub fn set_wake_up(&mut self, time: u32) -> bool { 127 | self.wake_up = time; 128 | self.instant = Instant::now(); 129 | true 130 | } 131 | 132 | pub fn is_active(&mut self) -> bool { 133 | if self.active { 134 | match Duration::from_std(self.instant.elapsed()) { 135 | Ok(duration) => duration.num_milliseconds() >= self.wake_up as i64, 136 | Err(_) => false, 137 | } 138 | } else { 139 | false 140 | } 141 | } 142 | } -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [root] 2 | name = "cleovm" 3 | version = "0.1.0" 4 | dependencies = [ 5 | "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 6 | "docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 7 | "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", 8 | "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", 9 | ] 10 | 11 | [[package]] 12 | name = "aho-corasick" 13 | version = "0.6.3" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | dependencies = [ 16 | "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 17 | ] 18 | 19 | [[package]] 20 | name = "byteorder" 21 | version = "1.0.0" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | 24 | [[package]] 25 | name = "docopt" 26 | version = "0.7.0" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | dependencies = [ 29 | "lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", 30 | "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 31 | "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", 32 | "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", 33 | ] 34 | 35 | [[package]] 36 | name = "kernel32-sys" 37 | version = "0.2.2" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | dependencies = [ 40 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 41 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 42 | ] 43 | 44 | [[package]] 45 | name = "lazy_static" 46 | version = "0.2.4" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | 49 | [[package]] 50 | name = "libc" 51 | version = "0.2.21" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | 54 | [[package]] 55 | name = "memchr" 56 | version = "1.0.1" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | dependencies = [ 59 | "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", 60 | ] 61 | 62 | [[package]] 63 | name = "redox_syscall" 64 | version = "0.1.16" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | 67 | [[package]] 68 | name = "regex" 69 | version = "0.2.1" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | dependencies = [ 72 | "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", 73 | "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 74 | "regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 75 | "thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 76 | "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 77 | ] 78 | 79 | [[package]] 80 | name = "regex-syntax" 81 | version = "0.4.0" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | 84 | [[package]] 85 | name = "rustc-serialize" 86 | version = "0.3.23" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | 89 | [[package]] 90 | name = "strsim" 91 | version = "0.6.0" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | 94 | [[package]] 95 | name = "thread-id" 96 | version = "3.0.0" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | dependencies = [ 99 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 100 | "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", 101 | ] 102 | 103 | [[package]] 104 | name = "thread_local" 105 | version = "0.3.3" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | dependencies = [ 108 | "thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 109 | "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 110 | ] 111 | 112 | [[package]] 113 | name = "time" 114 | version = "0.1.36" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | dependencies = [ 117 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 118 | "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", 119 | "redox_syscall 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", 120 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 121 | ] 122 | 123 | [[package]] 124 | name = "unreachable" 125 | version = "0.1.1" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | dependencies = [ 128 | "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 129 | ] 130 | 131 | [[package]] 132 | name = "utf8-ranges" 133 | version = "1.0.0" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | 136 | [[package]] 137 | name = "void" 138 | version = "1.0.2" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | 141 | [[package]] 142 | name = "winapi" 143 | version = "0.2.8" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | 146 | [[package]] 147 | name = "winapi-build" 148 | version = "0.1.1" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | 151 | [metadata] 152 | "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" 153 | "checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" 154 | "checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8" 155 | "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 156 | "checksum lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7291b1dd97d331f752620b02dfdbc231df7fc01bf282a00769e1cdb963c460dc" 157 | "checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" 158 | "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" 159 | "checksum redox_syscall 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd35cc9a8bdec562c757e3d43c1526b5c6d2653e23e2315065bc25556550753" 160 | "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" 161 | "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" 162 | "checksum rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "684ce48436d6465300c9ea783b6b14c4361d6b8dcbb1375b486a69cc19e2dfb0" 163 | "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" 164 | "checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a" 165 | "checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7" 166 | "checksum time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "211b63c112206356ef1ff9b19355f43740fc3f85960c598a93d3a3d3ba7beade" 167 | "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" 168 | "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" 169 | "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 170 | "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 171 | "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 172 | -------------------------------------------------------------------------------- /src/default_opcodes.rs: -------------------------------------------------------------------------------- 1 | extern crate alloc; 2 | 3 | use std::rc::Rc; 4 | use std::cell::RefCell; 5 | use ::script::error::OpcodeHandlerErr; 6 | use self::alloc::heap; 7 | use ::std::mem::transmute; 8 | use ::script::parser::ArgType; 9 | use ::script::LogicalOpcode; 10 | use ::script::variable::{Variable, VariableKind, VariableType, VarInfo}; 11 | use ::script::parser::Parser; 12 | 13 | macro_rules! math_op { 14 | ( $name:ident, $opcode:expr, $ops:tt ) => ( 15 | $name.set_handler($opcode, |thread| { 16 | match thread.parse_var() { 17 | Some(rc_var) => { 18 | let mut var = rc_var.borrow_mut(); 19 | thread.parse_any_arg() 20 | .ok_or(OpcodeHandlerErr::CannotParseArg) 21 | .map(|arg| { 22 | match arg { 23 | ArgType::Integer(value) => { 24 | let last = var.get::(); 25 | var.set(last $ops value); 26 | }, 27 | ArgType::Float(value) => { 28 | let last = var.get::(); 29 | var.set(last $ops value); 30 | }, 31 | ArgType::Var(rc_var_r) => { 32 | let var_r = rc_var_r.borrow(); 33 | match var_r.kind { 34 | VariableKind::Float => var.do_stuff(&var_r, |a: f32, b: f32| a $ops b), 35 | VariableKind::Integer => var.do_stuff(&var_r, |a: u32, b: u32| a $ops b), 36 | _ => unimplemented!(), 37 | }; 38 | }, 39 | _ => unimplemented!(), 40 | }; 41 | true 42 | }) 43 | } 44 | None => Err(OpcodeHandlerErr::NotCorrectType("var".to_string())), 45 | } 46 | }); 47 | ) 48 | } 49 | 50 | macro_rules! cond_op { 51 | ( $name:ident, $opcode:expr, $ops:tt ) => ( 52 | $name.set_handler($opcode, |thread| { 53 | match thread.parse_var() { 54 | Some(rc_var) => { 55 | if let Some(arg) = thread.parse_any_arg() { 56 | let var = rc_var.borrow(); 57 | match arg { 58 | ArgType::Integer(value) => Ok(var.get::() $ops value), 59 | ArgType::Float(value) => Ok(var.get::() $ops value), 60 | ArgType::Var(ref rc_var_r) => { 61 | let var_r = rc_var_r.borrow(); 62 | if var_r.eq_types(&var) { 63 | match var.kind.clone() { 64 | VariableKind::Float => Ok(var.get::() $ops var_r.get::()), 65 | VariableKind::Integer => Ok(var.get::() $ops var_r.get::()), 66 | VariableKind::String => Ok(false), 67 | } 68 | } 69 | else { 70 | Ok(false) 71 | } 72 | } 73 | _ => Ok(false), 74 | } 75 | } else { 76 | Err(OpcodeHandlerErr::CannotParseArg) 77 | } 78 | }, 79 | None => Err(OpcodeHandlerErr::NotCorrectType("var".to_string())), 80 | } 81 | }); 82 | ) 83 | } 84 | 85 | #[derive(Debug)] 86 | struct StackInfo { 87 | args_count: usize, 88 | return_ptr: usize, 89 | } 90 | 91 | pub trait DefaultOpcodes { 92 | fn set_default_opcodes(&mut self); 93 | } 94 | 95 | impl DefaultOpcodes for ::vm::VirtualMachine { 96 | fn set_default_opcodes(&mut self) { 97 | // 0000: NOP 98 | self.set_handler(0x0000, |thread| { 99 | Ok(true) 100 | }); 101 | 102 | // 0001: wait %int% 103 | self.set_handler(0x0001, |thread| { 104 | thread.parse_int().map(|time| thread.set_wake_up(time as u32)).ok_or(OpcodeHandlerErr::CannotParseArg) 105 | }); 106 | 107 | // 0002: jump %int% 108 | self.set_handler(0x0002, |thread| { 109 | thread.parse_int().map(|address| thread.jump_to(address as usize)).ok_or(OpcodeHandlerErr::CannotParseArg) 110 | }); 111 | 112 | // 0003: %var% = %any% 113 | self.set_handler(0x0003, |thread| { 114 | match thread.parse_var() { 115 | Some(rc_var) => { 116 | let mut var = rc_var.borrow_mut(); 117 | thread.parse_any_arg().ok_or(OpcodeHandlerErr::CannotParseArg).map(|arg| { 118 | match arg { 119 | ArgType::Integer(value) => { 120 | var.kind = VariableKind::Integer; 121 | var.set(value); 122 | true 123 | } 124 | ArgType::Float(value) => { 125 | var.kind = VariableKind::Float; 126 | var.set(value); 127 | true 128 | } 129 | ArgType::Var(var_r) => { 130 | var.from(&var_r.borrow()); 131 | true 132 | } 133 | ArgType::String(value) => { 134 | var.kind = VariableKind::String; 135 | var.set_str(value); 136 | true 137 | } 138 | _ => false, 139 | } 140 | }) 141 | } 142 | None => Err(OpcodeHandlerErr::CannotParseArg), 143 | } 144 | }); 145 | 146 | // 0004-0007: %var% `op`= %any% 147 | math_op!(self, 0x0004, +); 148 | math_op!(self, 0x0005, -); 149 | math_op!(self, 0x0006, *); 150 | math_op!(self, 0x0007, /); 151 | 152 | // 0008: if %int% 153 | self.set_handler(0x0008, |thread| { 154 | if let Some(arg) = thread.parse_int() { 155 | match arg { 156 | 0 => Ok(thread.set_logical_opcode(LogicalOpcode::One)), 157 | 1 ... 7 => Ok(thread.set_logical_opcode(LogicalOpcode::And)), 158 | 21 ... 27 => Ok(thread.set_logical_opcode(LogicalOpcode::Or)), 159 | _ => Err(OpcodeHandlerErr::UndefinedCondArg), 160 | } 161 | } else { 162 | Err(OpcodeHandlerErr::CannotParseArg) 163 | } 164 | }); 165 | 166 | // 0009: jump_if_false %int% 167 | self.set_handler(0x0009, |thread| { 168 | match thread.parse_int() { 169 | Some(offset) => { 170 | if !thread.cond_result { 171 | thread.jump_to(offset as usize); 172 | } 173 | 174 | Ok(thread.cond_result) 175 | }, 176 | None => Err(OpcodeHandlerErr::CannotParseArg), 177 | } 178 | }); 179 | 180 | // 000A: print %any% 181 | self.set_handler(0x000A, |thread| { 182 | if let Some(arg) = thread.parse_any_arg() { 183 | match arg { 184 | ArgType::Var(rc_var) => println!("{}", *rc_var.borrow()), 185 | _ => println!("{}", arg), 186 | } 187 | Ok(true) 188 | } else { 189 | Err(OpcodeHandlerErr::CannotParseArg) 190 | } 191 | }); 192 | 193 | // 000B: get_label_address %int% to %var% 194 | self.set_handler(0x000B, |thread| { 195 | match thread.parse_int() { 196 | Some(label) => { 197 | match thread.parse_var() { 198 | Some(rc_var) => { 199 | let mut var = rc_var.borrow_mut(); 200 | 201 | let address: u32 = unsafe { 202 | let temp = &thread.bytes[0xFFFFFFFF - (label as usize) + 1]; 203 | transmute(temp) 204 | }; 205 | var.set(address); 206 | Ok(true) 207 | }, 208 | None => Err(OpcodeHandlerErr::CannotParseArg), 209 | } 210 | }, 211 | None => Err(OpcodeHandlerErr::CannotParseArg), 212 | } 213 | }); 214 | 215 | // 000C: allocate %int% to %var% 216 | self.set_handler(0x000C, |thread| { 217 | match thread.parse_int() { 218 | Some(size) => { 219 | match thread.parse_var() { 220 | Some(rc_var) => { 221 | let mut var = rc_var.borrow_mut(); 222 | 223 | let address: *mut u8 = unsafe { 224 | heap::allocate(size as usize, 1) 225 | }; 226 | 227 | var.set(address as u32); 228 | Ok(true) 229 | }, 230 | None => Err(OpcodeHandlerErr::CannotParseArg), 231 | } 232 | }, 233 | None => Err(OpcodeHandlerErr::CannotParseArg), 234 | } 235 | }); 236 | 237 | // 000D: deallocate %var% size %int% 238 | self.set_handler(0x000D, |thread| { 239 | match thread.parse_var() { 240 | Some(rc_var) => { 241 | match thread.parse_int() { 242 | Some(size) => { 243 | let var = rc_var.borrow(); 244 | 245 | let ptr: *mut u8 = unsafe { 246 | transmute(var.get::()) 247 | }; 248 | 249 | if ptr as usize != 0 { 250 | unsafe { 251 | heap::deallocate(ptr, size as usize, 1); 252 | } 253 | Ok(true) 254 | } else { 255 | Ok(false) 256 | } 257 | }, 258 | None => Err(OpcodeHandlerErr::CannotParseArg), 259 | } 260 | }, 261 | None => Err(OpcodeHandlerErr::CannotParseArg), 262 | } 263 | }); 264 | 265 | // 000E: call %int% args %int% %args...% %ret...% 266 | self.set_handler(0x000E, |thread| { 267 | let label = thread.parse_int().unwrap() as usize; 268 | let count = thread.parse_int().unwrap() as usize; 269 | 270 | for i in 0 .. count { 271 | let info = thread.get_variable(VariableType::Local(i as usize)); 272 | let mut var = info.borrow_mut(); 273 | 274 | thread.stack.push(Box::into_raw(Box::new(var.into_raw())) as usize); 275 | match thread.parse_any_arg() { 276 | Some(ArgType::Var(rc_var)) => { 277 | let var_r = rc_var.borrow(); 278 | var.from(&var_r); 279 | } 280 | Some(ArgType::Integer(value)) => var.set(value), 281 | Some(ArgType::Float(value)) => var.set(value), 282 | _ => unimplemented!() 283 | } 284 | } 285 | 286 | let info = Box::new(StackInfo { 287 | args_count: count, 288 | return_ptr: thread.offset, 289 | }); 290 | 291 | thread.stack.push(Box::into_raw(info) as usize); 292 | thread.jump_to(label); 293 | 294 | Ok(true) 295 | }); 296 | 297 | // 000F: ret %int% args %int% %args...% 298 | self.set_handler(0x000F, |thread| { 299 | let count = thread.parse_int().unwrap(); 300 | let mut ret_args: Vec = Vec::new(); 301 | 302 | for _ in 0 .. count { 303 | ret_args.push(thread.parse_any_arg().unwrap()); 304 | } 305 | 306 | let info: Box = { 307 | let raw_info = thread.stack.pop().unwrap(); 308 | unsafe { 309 | Box::from_raw(raw_info as *mut StackInfo) 310 | } 311 | }; 312 | 313 | thread.offset = info.return_ptr; 314 | 315 | for i in 0 .. info.args_count { 316 | let raw = { 317 | let t = thread.stack.pop().unwrap(); 318 | unsafe { 319 | Box::from_raw(t as *mut VarInfo) 320 | } 321 | }; 322 | thread.local_vars[i] = Rc::new(RefCell::new(Variable::from_raw(i, &raw))); 323 | } 324 | 325 | for i in 0 .. count { 326 | let rc_var = thread.parse_var().unwrap(); 327 | let mut var = rc_var.borrow_mut(); 328 | 329 | match ret_args[i as usize] { 330 | ArgType::Integer(value) => var.set(value), 331 | ArgType::Float(value) => var.set(value), 332 | ArgType::Var(ref rc_var_r) => { 333 | let var_r = rc_var_r.borrow(); 334 | var.from(&var_r); 335 | } 336 | _ => unimplemented!(), 337 | } 338 | } 339 | 340 | thread.offset += 1; 341 | Ok(true) 342 | }); 343 | 344 | // 0010: %var% == %any% 345 | cond_op!(self, 0x0010, ==); 346 | cond_op!(self, 0x0011, !=); 347 | cond_op!(self, 0x0012, >); 348 | cond_op!(self, 0x0013, <); 349 | cond_op!(self, 0x0014, >=); 350 | cond_op!(self, 0x0015, <=); 351 | 352 | /* 353 | TODO: 354 | logical opcodes for usize 355 | 356 | math_op!(self, 0x0016, &); 357 | math_op!(self, 0x0017, |); 358 | math_op!(self, 0x0018, ^); 359 | math_op!(self, 0x0019, %); 360 | */ 361 | } 362 | } --------------------------------------------------------------------------------