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;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ mod compiler;
|
||||||
use compiler::{compile::Compiler, parser::{tokenize, Parser}};
|
use compiler::{compile::Compiler, parser::{tokenize, Parser}};
|
||||||
|
|
||||||
mod vm;
|
mod vm;
|
||||||
use vm::parser::parse_instr;
|
use vm::{vm::VM, parser::parse_instr};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
@ -31,7 +31,7 @@ fn main() {
|
||||||
// Run
|
// Run
|
||||||
(false, true) => {
|
(false, true) => {
|
||||||
let src = read_to_string(&args.file).unwrap();
|
let src = read_to_string(&args.file).unwrap();
|
||||||
run_src(src, start);
|
run_src(src);
|
||||||
},
|
},
|
||||||
(false, false) => {
|
(false, false) => {
|
||||||
if args.file.extension() == Some("blsp".as_ref()) {
|
if args.file.extension() == Some("blsp".as_ref()) {
|
||||||
|
@ -39,7 +39,7 @@ fn main() {
|
||||||
compile_src(src, args.output, args.file, start);
|
compile_src(src, args.output, args.file, start);
|
||||||
} else if args.file.extension() == Some("bsm".as_ref()) {
|
} else if args.file.extension() == Some("bsm".as_ref()) {
|
||||||
let src = read_to_string(&args.file).unwrap();
|
let src = read_to_string(&args.file).unwrap();
|
||||||
run_src(src, start);
|
run_src(src);
|
||||||
} else {
|
} else {
|
||||||
panic!("No mode specified");
|
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);
|
let instrs = parse_instr(&src);
|
||||||
for i in instrs {
|
let mut vm = VM::new();
|
||||||
println!("{}", i);
|
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.
|
/// Literal types for the assembler.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -9,6 +11,92 @@ pub enum Type {
|
||||||
String(String),
|
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 {
|
impl Display for Type {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
@ -33,13 +121,13 @@ impl FromStr for Type {
|
||||||
"true" => Ok(Type::Boolean(true)),
|
"true" => Ok(Type::Boolean(true)),
|
||||||
"false" => Ok(Type::Boolean(false)),
|
"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>();
|
let i = s.parse::<i64>();
|
||||||
if i.is_ok() {
|
if i.is_ok() {
|
||||||
Ok(Type::Int(i.unwrap()))
|
Ok(Type::Int(i.unwrap()))
|
||||||
|
} else {
|
||||||
|
let fl = s.parse::<f64>();
|
||||||
|
if fl.is_ok() {
|
||||||
|
Ok(Type::Float(fl.unwrap()))
|
||||||
} else {
|
} else {
|
||||||
Ok(Type::String(s.to_string()))
|
Ok(Type::String(s.to_string()))
|
||||||
}
|
}
|
||||||
|
@ -52,6 +140,10 @@ impl FromStr for Type {
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Register { pub value: usize }
|
pub struct Register { pub value: usize }
|
||||||
|
|
||||||
|
impl Register {
|
||||||
|
pub fn value(&self) -> usize { self.value }
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for Register {
|
impl Display for Register {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
write!(f, "r{}", self.value)
|
write!(f, "r{}", self.value)
|
||||||
|
|
|
@ -2,3 +2,5 @@
|
||||||
pub mod instr;
|
pub mod instr;
|
||||||
/// Definition of the instruction parser.
|
/// Definition of the instruction parser.
|
||||||
pub mod 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