add src/vm,src/parser
This commit is contained in:
179
src/context.rs
179
src/context.rs
@@ -1,6 +1,4 @@
|
|||||||
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 {
|
||||||
@@ -70,180 +68,3 @@ impl Context {
|
|||||||
self.mem_map.get(&addr).map(|i| *i)
|
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<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 {
|
|
||||||
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))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
75
src/main.rs
75
src/main.rs
@@ -1,14 +1,14 @@
|
|||||||
mod err;
|
mod err;
|
||||||
mod ins;
|
mod ins;
|
||||||
|
mod parser;
|
||||||
mod context;
|
mod context;
|
||||||
|
mod vm;
|
||||||
|
|
||||||
use err::*;
|
use err::*;
|
||||||
use ins::*;
|
use parser::*;
|
||||||
use context::*;
|
use context::*;
|
||||||
|
use vm::*;
|
||||||
|
|
||||||
// type XResult<T> = Result<T, Box<dyn std::error::Error>>;
|
|
||||||
|
|
||||||
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
|
||||||
// https://p.rogram.me/grassmudhorse.js/grassmudhorse.js
|
// https://p.rogram.me/grassmudhorse.js/grassmudhorse.js
|
||||||
@@ -44,70 +44,3 @@ fn main() {
|
|||||||
println!("[DEBUG] Vm ended, context: {:?}", context);
|
println!("[DEBUG] Vm ended, context: {:?}", context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_lang(lang: &str) -> Result<Vec<Instruction>, 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<Item=char>) -> Result<Option<Instruction>, 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<Item=char>) -> Result<isize, ParseError> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|||||||
71
src/parser.rs
Normal file
71
src/parser.rs
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
use super::err::*;
|
||||||
|
use super::ins::*;
|
||||||
|
|
||||||
|
pub const VALID_INSTRUCTION_CHARS: &str = "草泥马河蟹";
|
||||||
|
|
||||||
|
pub fn parse_lang(lang: &str) -> Result<Vec<Instruction>, 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<Item=char>) -> Result<Option<Instruction>, 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<Item=char>) -> Result<isize, ParseError> {
|
||||||
|
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);
|
||||||
|
}
|
||||||
181
src/vm.rs
Normal file
181
src/vm.rs
Normal file
@@ -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<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 {
|
||||||
|
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))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user