From 4b6c5119b1ceb6ce5ecc7c8a36c5f4fa8fcb145e Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Fri, 8 May 2020 08:03:19 +0800 Subject: [PATCH] add src/vm,src/parser --- src/context.rs | 179 ------------------------------------------------ src/main.rs | 75 ++------------------ src/parser.rs | 71 +++++++++++++++++++ src/vm.rs | 181 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 256 insertions(+), 250 deletions(-) create mode 100644 src/parser.rs create mode 100644 src/vm.rs diff --git a/src/context.rs b/src/context.rs index 795110e..5f1de31 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,6 +1,4 @@ use std::collections::HashMap; -use super::ins::Instruction; -use super::err::RuntimeError; #[derive(Debug)] pub struct Context { @@ -70,180 +68,3 @@ impl Context { self.mem_map.get(&addr).map(|i| *i) } } - -impl Instruction { - - pub fn execute(&self, context: &mut Context) -> Result<(), RuntimeError> { - match self { - Instruction::Push(i) => context.push(*i), - Instruction::Dup => match context.pop() { - Some(n) => { context.push(n); context.push(n); } - None => return Err(RuntimeError::ErrorVmState(format!("Stack is empty when call dup!"))), - }, - Instruction::CopyN(i) => match context.get_at(*i as usize) { - Some(n) => context.push(n), - None => return Err(RuntimeError::ErrorVmState(format!("Stack is empty when call dup!"))), - }, - Instruction::Swap => { - let a = context.pop(); - let b = context.pop(); - if let (Some(a), Some(b)) = (a, b) { - context.push(b); - context.push(a); - } else { - return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call swap!"))); - } - }, - Instruction::Pop => { context.pop(); }, - Instruction::PopN(i) => { for _ in 0..*i { context.pop(); } }, - Instruction::Add => { - let a = context.pop(); - let b = context.pop(); - if let (Some(a), Some(b)) = (a, b) { - context.push(a + b); - } else { - return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call add!"))); - } - }, - Instruction::Sub => { - let a = context.pop(); - let b = context.pop(); - if let (Some(a), Some(b)) = (a, b) { - context.push(b - a); - } else { - return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call sub!"))); - } - }, - Instruction::Mul => { - let a = context.pop(); - let b = context.pop(); - if let (Some(a), Some(b)) = (a, b) { - context.push(a * b); - } else { - return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call mul!"))); - } - }, - Instruction::Div => { - let a = context.pop(); - let b = context.pop(); - if let (Some(a), Some(b)) = (a, b) { - context.push(b / a); - } else { - return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call div!"))); - } - }, - Instruction::Mod => { - let a = context.pop(); - let b = context.pop(); - if let (Some(a), Some(b)) = (a, b) { - context.push(b % a); - } else { - return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call mod!"))); - } - }, - Instruction::Store => { - let val = context.pop(); - let addr = context.pop(); - if let (Some(val), Some(addr)) = (val, addr) { - context.put_mem(addr, val); - } else { - return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call store!"))); - } - }, - Instruction::Retrieve => { - let addr = context.pop(); - if let Some(addr) = addr { - match context.get_mem(addr) { - Some(val) => { context.put_mem(addr, val); }, - None => return Err(RuntimeError::ErrorVmState(format!("Memory addr not found: {}!", addr))), - } - } else { - return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call retrieve!"))); - } - } - Instruction::DefineLabel(_) => (), // JUST SKIP! - Instruction::CallAtLabel(_i) => return Err(RuntimeError::NotImplemented("CallAtLabel".into())), - Instruction::GotoLabel(i) => match context.find_label(*i) { - Some(ptr) => context.goto(ptr), - None => return Err(RuntimeError::ErrorVmState(format!("Label not found: {}", i))), - }, - Instruction::GotoLabelE0(i) => match context.pop() { - Some(v) => if v == 0 { - match context.find_label(*i) { - Some(ptr) => context.goto(ptr), - None => return Err(RuntimeError::ErrorVmState(format!("Label not found: {}", i))), - } - }, - None => return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call gotolabele0!"))), - }, - Instruction::GotoLabelL0(i) => match context.pop() { - Some(v) => if v < 0 { - match context.find_label(*i) { - Some(ptr) => context.goto(ptr), - None => return Err(RuntimeError::ErrorVmState(format!("Label not found: {}", i))), - } - }, - None => return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call gotolabell0!"))), - }, - Instruction::ReturnCallAt => return Err(RuntimeError::NotImplemented("ReturnCallAt".into())), - Instruction::End => return Err(RuntimeError::EndVm), - Instruction::StdOutChar => match context.pop() { - Some(i) => print!("{}", i as u8 as char), - None => return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call stdoutchar!"))), - }, - Instruction::StdOutNum => match context.pop() { - Some(i) => print!("{}", i), - None => return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call stdoutnum!"))), - }, - Instruction::StdInChar => return Err(RuntimeError::NotImplemented("StdInChar".into())), - Instruction::StdInNum => return Err(RuntimeError::NotImplemented("StdInNum".into())), - } - - Ok(()) - } -} - -#[derive(Debug)] -pub struct Vm { - instructions: Vec, -} - -impl Vm { - - pub fn new(instructions: Vec) -> Vm { - Vm { instructions, } - } - - pub fn defint_labels(&self, context: &mut Context) { - for (ptr, ins) in self.instructions.iter().enumerate() { - if let Instruction::DefineLabel(i) = ins { - if context.is_debug() { - println!("[DEBUG] Define label: {} -> {}", *i, ptr as isize); - } - context.define_label(*i, ptr as isize); - } - } - } - - pub fn execute(&self, context: &mut Context) -> Result<(), RuntimeError> { - loop { - let ptr = context.get_ptr(); - let ins = self.instructions.get(ptr as usize); - match ins { - Some(ins) => { - if context.is_debug() { - let is_define_label = if let Instruction::DefineLabel(_) = ins { true } else { false }; - if !is_define_label { - println!("[DEBUG] Execute instruction: {:?}", ins); - } - } - match ins.execute(context) { - Err(err) => return Err(err), - Ok(_) => context.move_ptr_next(), - } - }, - None => return Err(RuntimeError::ErrorVmState(format!("Instruction at {} not found", ptr))), - } - } - } -} diff --git a/src/main.rs b/src/main.rs index 85dfd48..477ed44 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,14 @@ mod err; mod ins; +mod parser; mod context; +mod vm; use err::*; -use ins::*; +use parser::*; use context::*; +use vm::*; -// type XResult = Result>; - -const VALID_INSTRUCTION_CHARS: &str = "草泥马河蟹"; // https://playsecurity.org/rawfile/grass_mud_horse_language_specification.md // https://p.rogram.me/grassmudhorse.js/grassmudhorse.js @@ -44,70 +44,3 @@ fn main() { println!("[DEBUG] Vm ended, context: {:?}", context); } } - -fn parse_lang(lang: &str) -> Result, ParseError> { - let mut r = vec![]; - - let instruction_tree_root = make_instruction_tree(); - let mut cs = lang.chars().filter(|c| { - VALID_INSTRUCTION_CHARS.chars().any(|vic| vic == *c) - }); - - loop { - match match_instruction(&instruction_tree_root, &mut cs) { - Err(err) => return Err(err), - Ok(None) => break, - Ok(Some(ins)) => r.push(ins), - } - } - - Ok(r) -} - -fn match_instruction(ins_coll: &InsColl, cs: &mut dyn Iterator) -> Result, ParseError> { - if let Some(c) = cs.next() { - for ins in &ins_coll.inses { - if ins.c == c { - match &ins.ins_type { - InsType::Path(ins_coll) => return match_instruction(&ins_coll, cs), - InsType::Node(ins) => { - let data = if ins.has_data() { Some(read_number(cs)?) } else { None }; - return Ok(Some(ins.new_instruction(data))); - }, - } - } - } - return Err(ParseError::ErrorSyntax("ERROR!!!! syntax error!".into())); - } - Ok(None) -} - -fn read_number(cs: &mut dyn Iterator) -> Result { - let is_positive = if let Some(c) = cs.next() { - if c == '草' { 1 } else if c == '泥' { -1 } else { - return Err(ParseError::ErrorSyntax("ERROR!!!! syntax error!".into())); - } - } else { - return Err(ParseError::ErrorSyntax("ERROR!!!! syntax error!".into())); - }; - let mut num = 0_isize; - loop { - if let Some(c) = cs.next() { - if c == '马' { - break; - } else { - num <<= 1; - num += if c == '草' { 0 } else { 1 }; - } - } - } - Ok(is_positive * num) -} - -#[test] -fn test_read_number() { - assert_eq!(read_number(&mut "草泥马".chars()).unwrap(), 1); - assert_eq!(read_number(&mut "草泥草草草草泥泥马".chars()).unwrap(), 67); - assert_eq!(read_number(&mut "草泥草泥泥马".chars()).unwrap(), 11); - assert_eq!(read_number(&mut "草泥草草草泥草泥马".chars()).unwrap(), 69); -} diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000..d9733f3 --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,71 @@ +use super::err::*; +use super::ins::*; + +pub const VALID_INSTRUCTION_CHARS: &str = "草泥马河蟹"; + +pub fn parse_lang(lang: &str) -> Result, ParseError> { + let mut r = vec![]; + + let instruction_tree_root = make_instruction_tree(); + let mut cs = lang.chars().filter(|c| { + VALID_INSTRUCTION_CHARS.chars().any(|vic| vic == *c) + }); + + loop { + match match_instruction(&instruction_tree_root, &mut cs) { + Err(err) => return Err(err), + Ok(None) => break, + Ok(Some(ins)) => r.push(ins), + } + } + + Ok(r) +} + +fn match_instruction(ins_coll: &InsColl, cs: &mut dyn Iterator) -> Result, ParseError> { + if let Some(c) = cs.next() { + for ins in &ins_coll.inses { + if ins.c == c { + match &ins.ins_type { + InsType::Path(ins_coll) => return match_instruction(&ins_coll, cs), + InsType::Node(ins) => { + let data = if ins.has_data() { Some(read_number(cs)?) } else { None }; + return Ok(Some(ins.new_instruction(data))); + }, + } + } + } + return Err(ParseError::ErrorSyntax("ERROR!!!! syntax error!".into())); + } + Ok(None) +} + +fn read_number(cs: &mut dyn Iterator) -> Result { + let is_positive = if let Some(c) = cs.next() { + if c == '草' { 1 } else if c == '泥' { -1 } else { + return Err(ParseError::ErrorSyntax("ERROR!!!! syntax error!".into())); + } + } else { + return Err(ParseError::ErrorSyntax("ERROR!!!! syntax error!".into())); + }; + let mut num = 0_isize; + loop { + if let Some(c) = cs.next() { + if c == '马' { + break; + } else { + num <<= 1; + num += if c == '草' { 0 } else { 1 }; + } + } + } + Ok(is_positive * num) +} + +#[test] +fn test_read_number() { + assert_eq!(read_number(&mut "草泥马".chars()).unwrap(), 1); + assert_eq!(read_number(&mut "草泥草草草草泥泥马".chars()).unwrap(), 67); + assert_eq!(read_number(&mut "草泥草泥泥马".chars()).unwrap(), 11); + assert_eq!(read_number(&mut "草泥草草草泥草泥马".chars()).unwrap(), 69); +} diff --git a/src/vm.rs b/src/vm.rs new file mode 100644 index 0000000..c633f47 --- /dev/null +++ b/src/vm.rs @@ -0,0 +1,181 @@ +use super::err::*; +use super::ins::*; +use super::context::*; + +impl Instruction { + + pub fn execute(&self, context: &mut Context) -> Result<(), RuntimeError> { + match self { + Instruction::Push(i) => context.push(*i), + Instruction::Dup => match context.pop() { + Some(n) => { context.push(n); context.push(n); } + None => return Err(RuntimeError::ErrorVmState(format!("Stack is empty when call dup!"))), + }, + Instruction::CopyN(i) => match context.get_at(*i as usize) { + Some(n) => context.push(n), + None => return Err(RuntimeError::ErrorVmState(format!("Stack is empty when call dup!"))), + }, + Instruction::Swap => { + let a = context.pop(); + let b = context.pop(); + if let (Some(a), Some(b)) = (a, b) { + context.push(b); + context.push(a); + } else { + return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call swap!"))); + } + }, + Instruction::Pop => { context.pop(); }, + Instruction::PopN(i) => { for _ in 0..*i { context.pop(); } }, + Instruction::Add => { + let a = context.pop(); + let b = context.pop(); + if let (Some(a), Some(b)) = (a, b) { + context.push(a + b); + } else { + return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call add!"))); + } + }, + Instruction::Sub => { + let a = context.pop(); + let b = context.pop(); + if let (Some(a), Some(b)) = (a, b) { + context.push(b - a); + } else { + return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call sub!"))); + } + }, + Instruction::Mul => { + let a = context.pop(); + let b = context.pop(); + if let (Some(a), Some(b)) = (a, b) { + context.push(a * b); + } else { + return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call mul!"))); + } + }, + Instruction::Div => { + let a = context.pop(); + let b = context.pop(); + if let (Some(a), Some(b)) = (a, b) { + context.push(b / a); + } else { + return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call div!"))); + } + }, + Instruction::Mod => { + let a = context.pop(); + let b = context.pop(); + if let (Some(a), Some(b)) = (a, b) { + context.push(b % a); + } else { + return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call mod!"))); + } + }, + Instruction::Store => { + let val = context.pop(); + let addr = context.pop(); + if let (Some(val), Some(addr)) = (val, addr) { + context.put_mem(addr, val); + } else { + return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call store!"))); + } + }, + Instruction::Retrieve => { + let addr = context.pop(); + if let Some(addr) = addr { + match context.get_mem(addr) { + Some(val) => { context.put_mem(addr, val); }, + None => return Err(RuntimeError::ErrorVmState(format!("Memory addr not found: {}!", addr))), + } + } else { + return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call retrieve!"))); + } + } + Instruction::DefineLabel(_) => (), // JUST SKIP! + Instruction::CallAtLabel(_i) => return Err(RuntimeError::NotImplemented("CallAtLabel".into())), + Instruction::GotoLabel(i) => match context.find_label(*i) { + Some(ptr) => context.goto(ptr), + None => return Err(RuntimeError::ErrorVmState(format!("Label not found: {}", i))), + }, + Instruction::GotoLabelE0(i) => match context.pop() { + Some(v) => if v == 0 { + match context.find_label(*i) { + Some(ptr) => context.goto(ptr), + None => return Err(RuntimeError::ErrorVmState(format!("Label not found: {}", i))), + } + }, + None => return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call gotolabele0!"))), + }, + Instruction::GotoLabelL0(i) => match context.pop() { + Some(v) => if v < 0 { + match context.find_label(*i) { + Some(ptr) => context.goto(ptr), + None => return Err(RuntimeError::ErrorVmState(format!("Label not found: {}", i))), + } + }, + None => return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call gotolabell0!"))), + }, + Instruction::ReturnCallAt => return Err(RuntimeError::NotImplemented("ReturnCallAt".into())), + Instruction::End => return Err(RuntimeError::EndVm), + Instruction::StdOutChar => match context.pop() { + Some(i) => print!("{}", i as u8 as char), + None => return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call stdoutchar!"))), + }, + Instruction::StdOutNum => match context.pop() { + Some(i) => print!("{}", i), + None => return Err(RuntimeError::ErrorVmState(format!("Stack is not enough when call stdoutnum!"))), + }, + Instruction::StdInChar => return Err(RuntimeError::NotImplemented("StdInChar".into())), + Instruction::StdInNum => return Err(RuntimeError::NotImplemented("StdInNum".into())), + } + + Ok(()) + } +} + +#[derive(Debug)] +pub struct Vm { + instructions: Vec, +} + +impl Vm { + + pub fn new(instructions: Vec) -> Vm { + Vm { instructions, } + } + + pub fn defint_labels(&self, context: &mut Context) { + for (ptr, ins) in self.instructions.iter().enumerate() { + if let Instruction::DefineLabel(i) = ins { + if context.is_debug() { + println!("[DEBUG] Define label: {} -> {}", *i, ptr as isize); + } + context.define_label(*i, ptr as isize); + } + } + } + + pub fn execute(&self, context: &mut Context) -> Result<(), RuntimeError> { + loop { + let ptr = context.get_ptr(); + let ins = self.instructions.get(ptr as usize); + match ins { + Some(ins) => { + if context.is_debug() { + let is_define_label = if let Instruction::DefineLabel(_) = ins { true } else { false }; + if !is_define_label { + println!("[DEBUG] Execute instruction: {:?}", ins); + } + } + match ins.execute(context) { + Err(err) => return Err(err), + Ok(_) => context.move_ptr_next(), + } + }, + None => return Err(RuntimeError::ErrorVmState(format!("Instruction at {} not found", ptr))), + } + } + } +} +