From 697012f0ac641246a797e121dbec23c80a41a5a5 Mon Sep 17 00:00:00 2001 From: Natapat Samutpong Date: Thu, 27 Jan 2022 12:30:16 +0700 Subject: [PATCH] feat: it works :tada: :tada: --- blspc/src/main.rs | 23 ++++--- blspc/src/vm/instr.rs | 106 +++++++++++++++++++++++++++++--- blspc/src/vm/mod.rs | 4 +- blspc/src/vm/vm.rs | 137 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 253 insertions(+), 17 deletions(-) create mode 100644 blspc/src/vm/vm.rs diff --git a/blspc/src/main.rs b/blspc/src/main.rs index c4fd3c1..fc75fac 100644 --- a/blspc/src/main.rs +++ b/blspc/src/main.rs @@ -1,4 +1,4 @@ -use std::{fs::{read_to_string, File}, path::{Path, PathBuf}, io::{Write, Seek}, time::Instant}; +use std::{fs::{read_to_string, File}, path::{Path, PathBuf}, io::{Write, Seek}, time::Instant, process::exit}; use structopt::StructOpt; @@ -12,7 +12,7 @@ mod compiler; use compiler::{compile::Compiler, parser::{tokenize, Parser}}; mod vm; -use vm::parser::parse_instr; +use vm::{vm::VM, parser::parse_instr}; fn main() { let start = Instant::now(); @@ -31,7 +31,7 @@ fn main() { // Run (false, true) => { let src = read_to_string(&args.file).unwrap(); - run_src(src, start); + run_src(src); }, (false, false) => { if args.file.extension() == Some("blsp".as_ref()) { @@ -39,7 +39,7 @@ fn main() { compile_src(src, args.output, args.file, start); } else if args.file.extension() == Some("bsm".as_ref()) { let src = read_to_string(&args.file).unwrap(); - run_src(src, start); + run_src(src); } else { panic!("No mode specified"); } @@ -84,11 +84,16 @@ fn compile_src(src: String, path: Option, file: PathBuf, start: Instant } } -fn run_src(src: String, start: Instant) { +fn run_src(src: String) { let instrs = parse_instr(&src); - for i in instrs { - println!("{}", i); + let mut vm = VM::new(); + match vm.run(instrs) { + Ok(()) => { + exit(0); + }, + Err(e) => { + eprintln!("{}", e); + exit(1); + } } - let elapsed = start.elapsed(); - println!("Executed in {}.{}s", elapsed.as_secs(), elapsed.subsec_millis()); } diff --git a/blspc/src/vm/instr.rs b/blspc/src/vm/instr.rs index 707fdf2..1d7ddb9 100644 --- a/blspc/src/vm/instr.rs +++ b/blspc/src/vm/instr.rs @@ -1,4 +1,6 @@ -use std::{fmt::Display, str::FromStr}; +use std::{fmt::Display, str::FromStr, ops::{Add, Sub, Mul, Div}}; + +use crate::vm::vm::Error::{self, InvalidAriphmeticOperation}; /// Literal types for the assembler. #[derive(Clone, Debug)] @@ -9,6 +11,92 @@ pub enum Type { String(String), } +impl Type { + pub fn as_bool(&self) -> bool { + match self { + Type::Boolean(b) => *b, + Type::Int(i) => *i != 0, + Type::Float(f) => *f != 0.0, + Type::String(s) => !s.is_empty(), + } + } + + pub fn trim(&self) -> Type { + match self { + Type::Int(i) => Type::Int(*i), + Type::Float(f) => Type::Float(*f), + Type::Boolean(b) => Type::Boolean(*b), + Type::String(s) => Type::String(s[1..s.len() - 1].to_string()), + } + } + + pub fn fmt(&self) -> String { + match self { + Type::Int(i) => i.to_string(), + Type::Float(f) => f.to_string(), + Type::Boolean(b) => b.to_string(), + Type::String(s) => s.clone(), + } + } +} + +impl Add for Type { + type Output = Result; + + fn add(self, other: Type) -> Result { + match (self, other) { + (Type::Int(lhs), Type::Int(rhs)) => Ok(Type::Int(lhs + rhs)), + (Type::Int(lhs), Type::Float(rhs)) => Ok(Type::Float(lhs as f64 + rhs)), + (Type::Float(lhs), Type::Int(rhs)) => Ok(Type::Float(lhs + rhs as f64)), + (Type::Float(lhs), Type::Float(rhs)) => Ok(Type::Float(lhs + rhs)), + (Type::String(lhs), Type::String(rhs)) => Ok(Type::String(format!("{}{}", lhs, rhs))), + _ => Err(InvalidAriphmeticOperation), + } + } +} + +impl Sub for Type { + type Output = Result; + + fn sub(self, other: Type) -> Result { + match (self, other) { + (Type::Int(lhs), Type::Int(rhs)) => Ok(Type::Int(lhs - rhs)), + (Type::Int(lhs), Type::Float(rhs)) => Ok(Type::Float(lhs as f64 - rhs)), + (Type::Float(lhs), Type::Int(rhs)) => Ok(Type::Float(lhs - rhs as f64)), + (Type::Float(lhs), Type::Float(rhs)) => Ok(Type::Float(lhs - rhs)), + _ => Err(InvalidAriphmeticOperation), + } + } +} + +impl Mul for Type { + type Output = Result; + + fn mul(self, other: Type) -> Result { + match (self, other) { + (Type::Int(lhs), Type::Int(rhs)) => Ok(Type::Int(lhs * rhs)), + (Type::Int(lhs), Type::Float(rhs)) => Ok(Type::Float(lhs as f64 * rhs)), + (Type::Float(lhs), Type::Int(rhs)) => Ok(Type::Float(lhs * rhs as f64)), + (Type::Float(lhs), Type::Float(rhs)) => Ok(Type::Float(lhs * rhs)), + _ => Err(InvalidAriphmeticOperation), + } + } +} + +impl Div for Type { + type Output = Result; + + fn div(self, other: Type) -> Result { + match (self, other) { + (Type::Int(lhs), Type::Int(rhs)) => Ok(Type::Int(lhs / rhs)), + (Type::Int(lhs), Type::Float(rhs)) => Ok(Type::Float(lhs as f64 / rhs)), + (Type::Float(lhs), Type::Int(rhs)) => Ok(Type::Float(lhs / rhs as f64)), + (Type::Float(lhs), Type::Float(rhs)) => Ok(Type::Float(lhs / rhs)), + _ => Err(InvalidAriphmeticOperation), + } + } +} + impl Display for Type { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { @@ -33,13 +121,13 @@ impl FromStr for Type { "true" => Ok(Type::Boolean(true)), "false" => Ok(Type::Boolean(false)), _ => { - let fl = s.parse::(); - if fl.is_ok() { - Ok(Type::Float(fl.unwrap())) + let i = s.parse::(); + if i.is_ok() { + Ok(Type::Int(i.unwrap())) } else { - let i = s.parse::(); - if i.is_ok() { - Ok(Type::Int(i.unwrap())) + let fl = s.parse::(); + if fl.is_ok() { + Ok(Type::Float(fl.unwrap())) } else { Ok(Type::String(s.to_string())) } @@ -52,6 +140,10 @@ impl FromStr for Type { #[derive(Clone, Copy, Debug)] pub struct Register { pub value: usize } +impl Register { + pub fn value(&self) -> usize { self.value } +} + impl Display for Register { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "r{}", self.value) diff --git a/blspc/src/vm/mod.rs b/blspc/src/vm/mod.rs index 3699eaf..b12f2b9 100644 --- a/blspc/src/vm/mod.rs +++ b/blspc/src/vm/mod.rs @@ -1,4 +1,6 @@ /// Definition of the VM instructions. pub mod instr; /// Definition of the instruction parser. -pub mod parser; \ No newline at end of file +pub mod parser; +/// Definition of the virtual machine. +pub mod vm; \ No newline at end of file diff --git a/blspc/src/vm/vm.rs b/blspc/src/vm/vm.rs new file mode 100644 index 0000000..f459187 --- /dev/null +++ b/blspc/src/vm/vm.rs @@ -0,0 +1,137 @@ +use std::fmt::Display; + +use crate::vm::instr::{Instr::{self, *}, Type, Register}; + +pub enum Error { + StackOverflow, + UnknownFunctionCall(isize, isize), + InvalidAriphmeticOperation, +} + +impl Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Error::StackOverflow => write!(f, "Stack overflow"), + Error::UnknownFunctionCall(l, e) => write!(f, "Unknown function call at {}: {}", l, e), + Error::InvalidAriphmeticOperation => write!(f, "Invalid ariphmetic operation"), + } + } +} + +#[derive(Debug)] +pub struct VM { + pub instr_pointer: isize, + pub registers: Vec, + pub stack: Vec, +} + +pub type VMReturn = Result<(), Error>; + +impl VM { + pub fn new() -> Self { + VM { + instr_pointer: 0, + registers: vec![Type::Int(0); 1024], + stack: Vec::new(), + } + } + + pub fn run(&mut self, instrs: Vec) -> VMReturn { + 'tco: loop { + self.instr_pointer += 1; + if self.instr_pointer - 1 == instrs.len() as isize { + dbg!("VM: HALT"); + return Ok(()); + } + + let instr = &instrs[self.instr_pointer as usize - 1]; + match instr { + Store { address, value, .. } => { + self.store(&address, &value)?; + continue 'tco; + }, + Call { address, args, .. } => { + let args = &self.registers[args.value()]; + let address = &self.registers[address.value()]; + call(address, args, self.instr_pointer)?; + continue 'tco; + }, + Push { value, .. } => { + self.push(value.trim().clone())?; + continue 'tco; + }, + Pop { address, .. } => { + let value = self.stack.pop(); + self.store(&address, &value.unwrap())?; + continue 'tco; + }, + Add { .. } => { + let lhs = self.stack.pop().unwrap(); + let rhs = self.stack.pop().unwrap(); + self.push((lhs + rhs)?)?; + continue 'tco; + }, + Sub { .. } => { + let lhs = self.stack.pop().unwrap(); + let rhs = self.stack.pop().unwrap(); + self.push((lhs - rhs)?)?; + continue 'tco; + }, + Mul { .. } => { + let lhs = self.stack.pop().unwrap(); + let rhs = self.stack.pop().unwrap(); + self.push((lhs * rhs)?)?; + continue 'tco; + }, + Div { .. } => { + let lhs = self.stack.pop().unwrap(); + let rhs = self.stack.pop().unwrap(); + self.push((lhs / rhs)?)?; + continue 'tco; + }, + Jump { to, .. } => { + self.instr_pointer = *to as isize; + continue 'tco; + }, + PopJumpIfFalse { to, .. } => { + let value = self.stack.pop().unwrap(); + if !value.as_bool() { + self.instr_pointer = *to as isize; + } + continue 'tco; + }, + Return { .. } => { + return Ok(()); + }, + }; + } + } + + fn push(&mut self, value: Type) -> Result<(), Error> { + if self.stack.len() >= 1024 { + return Err(Error::StackOverflow); + } + Ok(self.stack.push(value)) + } + + fn store(&mut self, address: &Register, value: &Type) -> Result<(), Error> { + // TODO: Remove .clone() + Ok(self.registers[address.value()] = value.clone()) + } +} + +fn call(index: &Type, args: &Type, line: isize) -> Result<(), Error> { + match index { + Type::Int(i) => { + match i { + 0 => Err(Error::UnknownFunctionCall(line, 0)), + 1 => { + println!("{}", args.fmt()); + Ok(()) + }, + _ => Err(Error::UnknownFunctionCall(line, *i as isize)), + } + } + _ => {dbg!(index); Err(Error::UnknownFunctionCall(line, -1))}, + } +} \ No newline at end of file