add execute
This commit is contained in:
194
src/context.rs
194
src/context.rs
@@ -1,4 +1,6 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use super::ins::Instruction;
|
||||||
|
use super::err::RuntimeError;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
@@ -19,15 +21,193 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// label and ptr
|
||||||
|
pub fn define_label(&mut self, label: isize, ptr: isize) {
|
||||||
|
self.label_map.insert(label, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn find_label(&mut self, label: isize) -> Option<isize> {
|
||||||
|
// self.label_map.get(&label).map(|i| *i)
|
||||||
|
// }
|
||||||
|
|
||||||
// pub fn goto(&mut self, p: isize) {
|
// pub fn goto(&mut self, p: isize) {
|
||||||
// self.ptr = p;
|
// self.ptr = p;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// pub fn push(&mut self, n: isize) {
|
pub fn get_ptr(&self) -> isize {
|
||||||
// self.stack.push(n);
|
self.ptr
|
||||||
// }
|
}
|
||||||
|
|
||||||
// pub fn pop(&mut self) -> Option<isize> {
|
pub fn move_ptr_next(&mut self) {
|
||||||
// self.stack.pop()
|
self.ptr += 1;
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
// stack
|
||||||
|
pub fn get_at(&self, i: usize) -> Option<isize> {
|
||||||
|
self.stack.get(i).map(|i| *i)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, n: isize) {
|
||||||
|
self.stack.push(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&mut self) -> Option<isize> {
|
||||||
|
self.stack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// memory
|
||||||
|
pub fn mem_put(&mut self, addr: isize, val: isize) {
|
||||||
|
self.mem_map.insert(addr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mem_get(&self, addr: isize) -> Option<isize> {
|
||||||
|
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.mem_put(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.mem_get(addr) {
|
||||||
|
Some(val) => { context.mem_put(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) => return Err(RuntimeError::NotImplemented("GotoLabel".into())),
|
||||||
|
Instruction::GotoLabelE0(_i) => return Err(RuntimeError::NotImplemented("GotoLabelE0".into())),
|
||||||
|
Instruction::GotoLabelL0(_i) => return Err(RuntimeError::NotImplemented("GotoLabelL0".into())),
|
||||||
|
Instruction::ReturnCallAt => return Err(RuntimeError::NotImplemented("ReturnCallAt".into())),
|
||||||
|
Instruction::End => return Err(RuntimeError::EndVm),
|
||||||
|
Instruction::StdOutChar => match context.pop() {
|
||||||
|
Some(i) => println!("{}", 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) => println!("{}", 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<Instruction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vm {
|
||||||
|
|
||||||
|
pub fn new(instructions: Vec<Instruction>) -> 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 {
|
||||||
|
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) => 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))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
12
src/err.rs
12
src/err.rs
@@ -5,3 +5,15 @@ pub enum ParseError {
|
|||||||
#[error(display = "error syntax: {:?}", _0)]
|
#[error(display = "error syntax: {:?}", _0)]
|
||||||
ErrorSyntax(String),
|
ErrorSyntax(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum RuntimeError {
|
||||||
|
#[error(display = "error vm state: {:?}", _0)]
|
||||||
|
ErrorVmState(String),
|
||||||
|
|
||||||
|
#[error(display = "end vm")]
|
||||||
|
EndVm,
|
||||||
|
|
||||||
|
#[error(display = "not implemented: {:?}", _0)]
|
||||||
|
NotImplemented(String),
|
||||||
|
}
|
||||||
17
src/main.rs
17
src/main.rs
@@ -6,6 +6,8 @@ use err::*;
|
|||||||
use ins::*;
|
use ins::*;
|
||||||
use context::*;
|
use context::*;
|
||||||
|
|
||||||
|
// type XResult<T> = Result<T, Box<dyn std::error::Error>>;
|
||||||
|
|
||||||
const VALID_INSTRUCTION_CHARS: &str = "草泥马河蟹";
|
const VALID_INSTRUCTION_CHARS: &str = "草泥马河蟹";
|
||||||
|
|
||||||
// https://playsecurity.org/rawfile/grass_mud_horse_language_specification.md
|
// https://playsecurity.org/rawfile/grass_mud_horse_language_specification.md
|
||||||
@@ -13,14 +15,25 @@ const VALID_INSTRUCTION_CHARS: &str = "草泥马河蟹";
|
|||||||
fn main() {
|
fn main() {
|
||||||
let input = "草草草泥马 马草草草泥草草草草泥泥马 草马草 泥马草泥 草草草泥草泥草马 泥马草草 草草草泥马 泥草草草 草马草 草草草泥草泥泥马 泥草草泥 马泥草草泥草草草泥草泥马 马草马草泥草草草草泥泥马 马草草草泥草草草泥草泥马 草马马 马马马";
|
let input = "草草草泥马 马草草草泥草草草草泥泥马 草马草 泥马草泥 草草草泥草泥草马 泥马草草 草草草泥马 泥草草草 草马草 草草草泥草泥泥马 泥草草泥 马泥草草泥草草草泥草泥马 马草马草泥草草草草泥泥马 马草草草泥草草草泥草泥马 草马马 马马马";
|
||||||
|
|
||||||
let _instructions = match parse_lang(input) {
|
let instructions = match parse_lang(input) {
|
||||||
Ok(i) => i, Err(err) => {
|
Ok(i) => i, Err(err) => {
|
||||||
println!("Parse error: {}", err);
|
println!("Parse error: {}", err);
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let _context = Context::new();
|
let mut context = Context::new();
|
||||||
|
|
||||||
|
let vm = Vm::new(instructions);
|
||||||
|
vm.defint_labels(&mut context);
|
||||||
|
|
||||||
|
match vm.execute(&mut context) {
|
||||||
|
Err(RuntimeError::EndVm) => (),
|
||||||
|
Err(err) => println!("Vm error: {}", err),
|
||||||
|
Ok(_) => (),
|
||||||
|
}
|
||||||
|
println!("{:?}", vm);
|
||||||
|
println!("{:?}", context);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_lang(lang: &str) -> Result<Vec<Instruction>, ParseError> {
|
fn parse_lang(lang: &str) -> Result<Vec<Instruction>, ParseError> {
|
||||||
|
|||||||
Reference in New Issue
Block a user