mirror of
https://github.com/azur1s/bobbylisp.git
synced 2024-10-16 02:37:40 -05:00
feat: it works 🎉 🎉
This commit is contained in:
parent
cac125bd1c
commit
697012f0ac
|
@ -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<PathBuf>, 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());
|
||||
}
|
||||
|
|
|
@ -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<Type, Error>;
|
||||
|
||||
fn add(self, other: Type) -> Result<Type, Error> {
|
||||
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<Type, Error>;
|
||||
|
||||
fn sub(self, other: Type) -> Result<Type, Error> {
|
||||
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<Type, Error>;
|
||||
|
||||
fn mul(self, other: Type) -> Result<Type, Error> {
|
||||
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<Type, Error>;
|
||||
|
||||
fn div(self, other: Type) -> Result<Type, Error> {
|
||||
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::<f64>();
|
||||
if fl.is_ok() {
|
||||
Ok(Type::Float(fl.unwrap()))
|
||||
} else {
|
||||
let i = s.parse::<i64>();
|
||||
if i.is_ok() {
|
||||
Ok(Type::Int(i.unwrap()))
|
||||
} else {
|
||||
let fl = s.parse::<f64>();
|
||||
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)
|
||||
|
|
|
@ -2,3 +2,5 @@
|
|||
pub mod instr;
|
||||
/// Definition of the instruction parser.
|
||||
pub mod parser;
|
||||
/// Definition of the virtual machine.
|
||||
pub mod vm;
|
137
blspc/src/vm/vm.rs
Normal file
137
blspc/src/vm/vm.rs
Normal file
|
@ -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<Type>,
|
||||
pub stack: Vec<Type>,
|
||||
}
|
||||
|
||||
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<Instr>) -> 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))},
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue