1
1
Fork 0
mirror of https://github.com/azur1s/bobbylisp.git synced 2024-10-16 02:37:40 -05:00

refactor: a large amount of refactor

This commit is contained in:
Natapat Samutpong 2022-01-28 06:39:57 +07:00
parent 8382f0b5af
commit 83e0121dee
11 changed files with 232 additions and 340 deletions

View file

@ -24,3 +24,4 @@ Hello, World!
TODO: TODO:
- Quote, Quasiquote, etc. - Quote, Quasiquote, etc.
- Optimizing - Optimizing
- Remove unnecessary copying in the entire codebase

View file

@ -4,24 +4,38 @@ use structopt::StructOpt;
#[derive(StructOpt, Debug)] #[derive(StructOpt, Debug)]
#[structopt(name = "blspc")] #[structopt(name = "blspc")]
pub struct Args { pub struct Opts {
/// Verbose mode (-v, -vv, -vvv, etc.). Max is 2 currently. #[structopt(subcommand)]
#[structopt(short, long, parse(from_occurrences))] pub commands: Option<Args>,
pub verbose: u8, }
/// Compliation mode (-c). #[derive(StructOpt, Debug)]
#[structopt(short, long)] #[structopt(name = "args")]
pub compile: bool, pub enum Args {
#[structopt(name = "compile")]
Compile (CompileOpts),
#[structopt(name = "run")]
Run (RunOpts),
}
/// Run mode (-r). #[derive(StructOpt, Debug)]
#[structopt(short, long)] #[structopt(name = "compile", about = "Compile Options")]
pub run: bool, pub struct CompileOpts {
/// Files to process.
#[structopt(name = "FILE", parse(from_os_str))] #[structopt(name = "FILE", parse(from_os_str))]
pub file: PathBuf, pub file: PathBuf,
#[structopt(name = "OUTPUT", parse(from_os_str))]
/// Output file.
#[structopt(short, long, parse(from_os_str))]
pub output: Option<PathBuf>, pub output: Option<PathBuf>,
#[structopt(short, long)]
pub debug: bool,
#[structopt(short = "b", long)]
pub with_comment: bool,
}
#[derive(StructOpt, Debug)]
#[structopt(name = "run", about = "Run Options")]
pub struct RunOpts {
#[structopt(name = "FILE", parse(from_os_str))]
pub file: PathBuf,
#[structopt(short, long)]
pub debug: bool,
} }

View file

@ -2,7 +2,6 @@ use crate::{vm::instr::*, compiler::parser::Sexpr::{self, *}};
pub struct Compiler { pub struct Compiler {
pub instructions: Vec<Instr>, pub instructions: Vec<Instr>,
pub register_pointer: usize, pub register_pointer: usize,
pub label_pointer: usize,
} }
impl Compiler { impl Compiler {
@ -10,7 +9,6 @@ impl Compiler {
Compiler { Compiler {
instructions: Vec::new(), instructions: Vec::new(),
register_pointer: 1, register_pointer: 1,
label_pointer: 1,
} }
} }
@ -24,184 +22,89 @@ impl Compiler {
Register { value: self.register_pointer - 1 } Register { value: self.register_pointer - 1 }
} }
fn next_label(&mut self) -> usize { pub fn compile(&mut self, src: Sexpr) -> Result<Vec<Instr>, String> {
let l = self.label_pointer;
self.label_pointer += 1;
l
}
fn current_label(&self) -> usize {
self.label_pointer - 1
}
pub fn compile(&mut self, ast: Sexpr, depth: usize) -> Result<Vec<Instr>, String> {
let mut result = Vec::new(); let mut result = Vec::new();
let comp = src.clone(); // Used for commenting
match ast { 'tco: loop {
match src {
Cons(car, cdr) => { Cons(car, cdr) => {
match *car { match *car {
Symbol(ref s) => { Symbol(ref call) => {
match s.as_str() { match call.as_str() {
"do" => { "do" => {
for c in cdr { for c in cdr {
result.append(&mut self.compile(c, depth + 1)?); result.append(&mut self.compile(c)?);
} }
}, },
"if" => { "fun" => {
// TODO: Remove .clone() result.push(Instr::Comment { text: format!("--- {}", comp) });
let mut cond = self.compile(cdr[0].clone(), depth + 1)?; let function_name = match &cdr[0] {
result.append(&mut cond); Symbol(ref name) => format!("function_{}", name.clone()),
_ => return Err(format!("Expected function name, got {}", cdr[0])),
};
let body = &cdr[1];
result.push(Instr::PopJumpIfFalse { result.push(Instr::Label{ name: function_name });
to: 999, // To be replaced later result.append(&mut self.compile(body.clone())?);
label: self.next_label(), result.push(Instr::Return);
});
let mut then = self.compile(cdr[1].clone(), depth + 1)?;
let jump_label = self.next_label();
let mut else_ = self.compile(cdr[2].clone(), depth + 1)?;
let else_label = self.current_label() - else_.len() + 1;
let idx = result.len() - 1;
match result[idx] {
Instr::PopJumpIfFalse { to: _, label: l } => {
result[idx] = Instr::PopJumpIfFalse { to: else_label, label: l, };
}
_ => unreachable!(),
}
result.append(&mut then);
result.push(Instr::Jump {
to: self.current_label() + 1,
label: jump_label,
});
result.append(&mut else_);
}
_ => {
result.append(&mut self.compile_intrinsic(s, &cdr, depth + 1)?);
}
}
}
_ => return Err(format!("Expected symbol, got {:?}", car)),
}
}
_ => { result.append(&mut self.compile_atom(&ast, depth + 1)?); },
}
if depth == 0 {
result.push(Instr::Store {
address: self.next_register(),
value: Type::Int(0),
label: self.next_label(),
});
result.push(Instr::Return {
value: self.current_register(),
label: self.next_label(),
});
}
Ok(result)
}
fn compile_atom(&mut self, atom: &Sexpr, depth: usize) -> Result<Vec<Instr>, String> {
let mut result = Vec::new();
match atom {
Int(i) => {
result.push(Instr::Push {
value: Type::Int(*i),
label: self.next_label(),
});
}, },
Float(f) => {
result.push(Instr::Push {
value: Type::Float(*f),
label: self.next_label(),
});
},
Boolean(b) => {
result.push(Instr::Push {
value: Type::Boolean(*b),
label: self.next_label(),
});
},
Str(s) => {
result.push(Instr::Push {
value: Type::String(s.clone()),
label: self.next_label(),
});
},
_ => {
result.append(&mut self.compile(atom.clone(), depth + 1)?);
}
}
Ok(result)
}
fn compile_intrinsic(&mut self, intrinsic: &String, args: &[Sexpr], depth: usize) -> Result<Vec<Instr>, String> {
let mut result = Vec::new();
match intrinsic.as_str() {
"print" => { "print" => {
let mut arg = self.compile_atom(&args[0], depth + 1)?; result.append(&mut self.compile(cdr[0].clone())?);
result.append(&mut arg); let to = self.next_register();
let arg_pointer = self.current_register();
result.push(Instr::Pop {
address: arg_pointer,
label: self.next_label(),
});
let call_register = self.next_register(); let call_register = self.next_register();
result.push(Instr::Pop { address: to });
result.push(Instr::Store { result.push(Instr::Store {
address: call_register, address: call_register,
value: Type::Int(1), value: Type::Int(1),
label: self.next_label(),
}); });
result.push(Instr::Call { result.push(Instr::Call {
address: call_register, address: call_register,
args: arg_pointer, args: to,
label: self.next_label(),
}); });
}
_ => { dbg!(call); unimplemented!() },
} // End `match call`
}, // End `Symbol(call)`
_ => { dbg!(car); unimplemented!() },
} // End `match car`
}, // End `Cons(car, cdr)`
_ => { result.append(&mut self.compile_atom(src)?); },
} // End `match src`
break 'tco;
} // End `loop`
Ok(result)
}
fn compile_atom(&mut self, atom: Sexpr) -> Result<Vec<Instr>, String> {
let mut result = Vec::new();
let comp = atom.clone(); // Used for commenting
match atom {
Int(i) => {
result.push(Instr::Comment { text: format!("----- {}", comp) });
result.push(Instr::Push { value: Type::Int(i) });
}, },
"add" | "+" => { Float(f) => {
let mut lhs = self.compile_atom(&args[0], depth + 1)?; result.push(Instr::Comment { text: format!("----- {}", comp) });
result.append(&mut lhs); result.push(Instr::Push { value: Type::Float(f) });
let mut rhs = self.compile_atom(&args[1], depth + 1)?;
result.append(&mut rhs);
result.push(Instr::Add { label: self.next_label() });
}, },
"sub" | "-" => { Str(s) => {
let mut lhs = self.compile_atom(&args[0], depth + 1)?; result.push(Instr::Comment { text: format!("----- {}", comp) });
result.append(&mut lhs); result.push(Instr::Push { value: Type::String(s) });
let mut rhs = self.compile_atom(&args[1], depth + 1)?;
result.append(&mut rhs);
result.push(Instr::Sub { label: self.next_label() });
}, },
"mul" | "*" => { Boolean(b) => {
let mut lhs = self.compile_atom(&args[0], depth + 1)?; result.push(Instr::Comment { text: format!("----- {}", comp) });
result.append(&mut lhs); result.push(Instr::Push { value: Type::Boolean(b) });
let mut rhs = self.compile_atom(&args[1], depth + 1)?;
result.append(&mut rhs);
result.push(Instr::Mul { label: self.next_label() });
}, },
"div" | "/" => { Symbol(s) => {
let mut lhs = self.compile_atom(&args[0], depth + 1)?; result.push(Instr::Comment { text: format!("----- {} variable", comp) });
result.append(&mut lhs); result.push(Instr::Jump { to: format!("function_{}", s), });
let mut rhs = self.compile_atom(&args[1], depth + 1)?;
result.append(&mut rhs);
result.push(Instr::Div { label: self.next_label() });
}, },
_ => return Err(format!("Unknown intrinsic: {}", intrinsic)), _ => { dbg!(atom); unimplemented!() },
} }
Ok(result) Ok(result)

View file

@ -14,7 +14,7 @@ impl std::fmt::Display for Sexpr {
match self { match self {
Int(i) => write!(f, "{}", i), Int(i) => write!(f, "{}", i),
Float(fl) => write!(f, "{}", fl), Float(fl) => write!(f, "{}", fl),
Str(s) => write!(f, "{}", s), Str(s) => write!(f, "\"{}\"", s),
Boolean(b) => write!(f, "{}", b), Boolean(b) => write!(f, "{}", b),
Symbol(s) => write!(f, "{}", s), Symbol(s) => write!(f, "{}", s),
Cons(car, cdr) => { Cons(car, cdr) => {
@ -59,7 +59,6 @@ impl Parser {
Some(s) => match s.as_str() { Some(s) => match s.as_str() {
")" => Err(format!("Unexpected ')' at position {}", self.position)), ")" => Err(format!("Unexpected ')' at position {}", self.position)),
// TODO: Handle quote and that stuff. // TODO: Handle quote and that stuff.
"'" => { unimplemented!() },
"(" => self.parse_sequence(")"), "(" => self.parse_sequence(")"),
_ => self.parse_atom(), _ => self.parse_atom(),
} }
@ -86,24 +85,6 @@ impl Parser {
Ok(Sexpr::Cons(Box::new(car), cdr)) Ok(Sexpr::Cons(Box::new(car), cdr))
} }
fn parse_quote_sequence(&mut self, end: &str) -> ParseResult {
let car = Symbol("list".to_string());
self.next();
let mut cdr = Vec::new();
loop {
let token = match self.peek() {
Some(token) => token,
None => return Err(format!("Unexpected end of input, expected '{}'", end)),
};
if token == end { break; }
cdr.push(self.parse()?)
}
self.next();
Ok(Sexpr::Cons(Box::new(car), cdr))
}
fn parse_atom(&mut self) -> ParseResult { fn parse_atom(&mut self) -> ParseResult {
let token = self.next().unwrap(); let token = self.next().unwrap();
match token.as_str() { match token.as_str() {

View file

@ -3,7 +3,7 @@ use std::{fs::{read_to_string, File}, path::{Path, PathBuf}, io::{Write, Seek},
use structopt::StructOpt; use structopt::StructOpt;
mod args; mod args;
use args::Args; use args::Opts;
mod util; mod util;
use util::cover_paren; use util::cover_paren;
@ -16,43 +16,22 @@ use vm::{vm::VM, parser::parse_instr};
fn main() { fn main() {
let start = Instant::now(); let start = Instant::now();
let args = Args::from_args(); let args = Opts::from_args();
let debug = match args.verbose { if let Some(commands) = args.commands {
0 => false, match commands {
1 => true, args::Args::Compile(args) => {
2 => true,
_ => true,
};
match (args.compile, args.run) {
(true, true) => {
eprintln!("TODO: Compile and run at the same time.");
std::process::exit(1);
},
// Compile
(true, false) => {
let src = read_to_string(&args.file).unwrap(); let src = read_to_string(&args.file).unwrap();
let debug = args.debug;
compile_src(src, args.output, args.file, debug, start); compile_src(src, args.output, args.file, debug, start);
}, },
// Run args::Args::Run(args) => {
(false, true) => {
let src = read_to_string(&args.file).unwrap(); let src = read_to_string(&args.file).unwrap();
let debug = args.debug;
run_src(src, debug); run_src(src, debug);
}, },
(false, false) => {
if args.file.extension() == Some("blsp".as_ref()) {
let src = read_to_string(&args.file).unwrap();
compile_src(src, args.output, args.file, debug, start);
} else if args.file.extension() == Some("bsm".as_ref()) {
let src = read_to_string(&args.file).unwrap();
run_src(src, debug);
} else {
panic!("No mode specified");
} }
},
} }
} }
fn compile_src(src: String, path: Option<PathBuf>, file: PathBuf, debug: bool, start: Instant) { fn compile_src(src: String, path: Option<PathBuf>, file: PathBuf, debug: bool, start: Instant) {
@ -69,11 +48,12 @@ fn compile_src(src: String, path: Option<PathBuf>, file: PathBuf, debug: bool, s
match result { match result {
Ok(ast) => { Ok(ast) => {
let mut compiler = Compiler::new(); let mut compiler = Compiler::new();
let code = compiler.compile(ast, 0); let code = compiler.compile(ast);
match code { match code {
Ok(code) => { Ok(code) => {
let mut file = File::create(format!("{}.bsm", file_name)).unwrap(); let mut file = File::create(format!("{}.bsm", file_name)).unwrap();
for line in code { for line in code {
if line.to_string().starts_with(";") { continue; }
write!(file, "{}\n", line).unwrap(); write!(file, "{}\n", line).unwrap();
} }
file.seek(std::io::SeekFrom::End(-1)).unwrap(); // Trim last newline file.seek(std::io::SeekFrom::End(-1)).unwrap(); // Trim last newline

View file

@ -5,23 +5,22 @@ use crate::vm::vm::Error::{self, InvalidAriphmeticOperation};
/// Literal types for the assembler. /// Literal types for the assembler.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Type { pub enum Type {
Null, Null, StackGuard,
Int(i64), Int(i64),
Float(f64), Float(f64),
Boolean(bool), Boolean(bool),
String(String), String(String),
Array(Vec<Type>), Symbol(String),
} }
impl Type { impl Type {
pub fn as_bool(&self) -> bool { pub fn as_bool(&self) -> bool {
match self { match self {
Type::Null => false,
Type::Boolean(b) => *b, Type::Boolean(b) => *b,
Type::Int(i) => *i != 0, Type::Int(i) => *i != 0,
Type::Float(f) => *f != 0.0, Type::Float(f) => *f != 0.0,
Type::String(s) => !s.is_empty(), Type::String(s) => !s.is_empty(),
Type::Array(a) => !a.is_empty(), _ => unreachable!(),
} }
} }
@ -34,12 +33,8 @@ impl Type {
pub fn trim(&self) -> Type { pub fn trim(&self) -> Type {
match self { match self {
Type::Null => Type::Null,
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()), Type::String(s) => Type::String(s[1..s.len() - 1].to_string()),
Type::Array(a) => Type::Array(a.iter().map(|t| t.trim()).collect()), _ => self.clone(),
} }
} }
@ -53,15 +48,7 @@ impl Type {
false => "false".to_string(), false => "false".to_string(),
}, },
Type::String(s) => s.clone(), Type::String(s) => s.clone(),
Type::Array(a) => { _ => unreachable!(),
let mut s = "[".to_string();
for (i, t) in a.iter().enumerate() {
s.push_str(&t.fmt());
if i < a.len() - 1 { s.push_str(", "); }
}
s.push_str("]");
s
}
} }
} }
} }
@ -126,19 +113,12 @@ impl Div for Type {
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 {
Type::Null => write!(f, ":NULL"),
Type::Int(i) => write!(f, ":{}", i), Type::Int(i) => write!(f, ":{}", i),
Type::Float(fl) => write!(f, ":{}", fl), Type::Float(fl) => write!(f, ":{}", fl),
Type::Boolean(b) => write!(f, ":{}", b), Type::Boolean(b) => write!(f, ":{}", b),
Type::String(s) => write!(f, "$\"{}\"", s), Type::String(s) => write!(f, "$\"{}\"", s),
Type::Array(a) => { Type::Symbol(s) => write!(f, "function_{}", s),
write!(f, "[[ ")?; _ => unreachable!(),
for (i, t) in a.iter().enumerate() {
write!(f, "{}", t)?;
if i < a.len() - 1 { write!(f, ", ")?; }
}
write!(f, " ]]")
}
} }
} }
} }
@ -197,39 +177,41 @@ impl FromStr for Register {
/// Instructions for the assembler. /// Instructions for the assembler.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Instr { pub enum Instr {
// Load a literal value onto the stack. Label { name: String }, Comment { text: String },
// Load { address: Register, label: usize },
// Store a literal value into a register. // Store a literal value into a register.
Store { address: Register, value: Type, label: usize }, Store { address: Register, value: Type },
// Call intrinsic function. // Call intrinsic function.
Call { address: Register, args: Register, label: usize }, Call { address: Register, args: Register },
// Stack operations. // Stack operations.
Push { value: Type, label: usize }, Pop { address: Register, label: usize }, Push { value: Type }, Pop { address: Register },
// Stack arithmetic. // Stack arithmetic.
Add { label: usize }, Sub { label: usize }, Add, Sub,
Mul { label: usize }, Div { label: usize }, Mul, Div,
// Jumping // Jumping
Jump { to: usize, label: usize }, Jump { to: String },
PopJumpIfFalse { to: usize, label: usize }, PopJumpIfFalse { to: usize },
Return { value: Register, label: usize }, Return,
} }
impl Display for Instr { impl Display for Instr {
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 {
// Instr::Load { address, label } => write!(f, "{}: LOAD {}", label, address), // --4-- Padding
Instr::Store { address, value , label} => write!(f, "{} STORE {} {}", label, address, value), // ----------20--------- Parameter start
Instr::Call { address, args, label } => write!(f, "{} CALL {} {}", label, address, args), Instr::Label { name } => write!(f, ".{}:", name),
Instr::Push { value, label } => write!(f, "{} PUSH {}", label, value), Instr::Comment { text } => write!(f, ";{}", text),
Instr::Pop { address, label } => write!(f, "{} POP {}", label, address), Instr::Store { address, value } => write!(f, " STORE {} {}", address, value),
Instr::Add { label } => write!(f, "{} ADD", label), Instr::Call { address, args } => write!(f, " CALL {} {}", address, args),
Instr::Sub { label } => write!(f, "{} SUB", label), Instr::Push { value } => write!(f, " PUSH {}", value),
Instr::Mul { label } => write!(f, "{} MUL", label), Instr::Pop { address } => write!(f, " POP {}", address),
Instr::Div { label } => write!(f, "{} DIV", label), Instr::Add => write!(f, " ADD"),
Instr::Jump { to, label } => write!(f, "{} JMP {}", label, to), Instr::Sub => write!(f, " SUB"),
Instr::PopJumpIfFalse { to, label } => write!(f, "{} POP_JUMP_IF_FALSE {}", label, to), Instr::Mul => write!(f, " MUL"),
Instr::Return { value, label } => write!(f, "{} RETURN {}", label, value), Instr::Div => write!(f, " DIV"),
Instr::Jump { to } => write!(f, " JMP {}", to),
Instr::PopJumpIfFalse { to } => write!(f, " PJMPF {}", to),
Instr::Return => write!(f, " RET"),
} }
} }
} }

View file

@ -6,7 +6,6 @@ const REGEX: &str = r###"[^\s\$";]+|\$"[^"]*"|;.*"###;
macro_rules! value { ($s:expr) => { $s.parse::<Type>().unwrap() }; } macro_rules! value { ($s:expr) => { $s.parse::<Type>().unwrap() }; }
macro_rules! register { ($s:expr) => { $s.parse::<Register>().unwrap() }; } macro_rules! register { ($s:expr) => { $s.parse::<Register>().unwrap() }; }
macro_rules! label { ($s:expr) => { $s.parse::<usize>().unwrap() }; }
pub fn parse_instr(src: &str) -> Vec<Instr> { pub fn parse_instr(src: &str) -> Vec<Instr> {
let regex = Regex::new(REGEX).unwrap(); let regex = Regex::new(REGEX).unwrap();
@ -16,44 +15,30 @@ pub fn parse_instr(src: &str) -> Vec<Instr> {
let tokens = regex.find_iter(line).map(|m| m.as_str()).collect::<Vec<_>>(); let tokens = regex.find_iter(line).map(|m| m.as_str()).collect::<Vec<_>>();
if tokens[0].starts_with(";") { continue; } if tokens[0].starts_with(";") { continue; }
let label = label!(tokens[0]); match tokens[0] {
match tokens[1] {
"STORE" => { result.push(Instr::Store { "STORE" => { result.push(Instr::Store {
address: register!(tokens[2]), address: register!(tokens[1]),
value: value!(tokens[3]), value: value!(tokens[2]),
label,
}); }, }); },
"CALL" => { result.push(Instr::Call { "CALL" => { result.push(Instr::Call {
address: register!(tokens[2]), address: register!(tokens[1]),
args: register!(tokens[3]), args: register!(tokens[2]),
label,
}); }, }); },
"PUSH" => { result.push(Instr::Push { "PUSH" => { result.push(Instr::Push { value: value!(tokens[1]) }); },
value: value!(tokens[2]), "POP" => { result.push(Instr::Pop { address: register!(tokens[1]) }); },
label, "ADD" => { result.push(Instr::Add); },
}); }, "SUB" => { result.push(Instr::Sub); },
"POP" => { result.push(Instr::Pop { "MUL" => { result.push(Instr::Mul); },
address: register!(tokens[2]), "DIV" => { result.push(Instr::Div); },
label, "JMP" => { result.push(Instr::Jump { to: tokens[1].to_string() }); },
}); }, "PJMPF" => todo!(),
"ADD" => { result.push(Instr::Add { label }); }, "RET" => { result.push(Instr::Return); },
"SUB" => { result.push(Instr::Sub { label }); }, _ => {
"MUL" => { result.push(Instr::Mul { label }); }, if tokens[0].starts_with(".") {
"DIV" => { result.push(Instr::Div { label }); }, let name = &tokens[0][1..tokens[0].len() - 1];
"JMP" => { result.push(Instr::Jump { result.push(Instr::Label { name: name.to_string() });
to: label!(tokens[2]), }
label, },
}); },
"POP_JUMP_IF_FALSE" => { result.push(Instr::PopJumpIfFalse {
to: label!(tokens[2]),
label,
}); },
"RETURN" => { result.push(Instr::Return {
value: register!(tokens[2]),
label,
}); },
_ => panic!("Unknown instruction: {}", tokens[1]),
} }
} }

View file

@ -3,7 +3,9 @@ use std::fmt::Display;
use crate::vm::instr::{Instr::{self, *}, Type, Register}; use crate::vm::instr::{Instr::{self, *}, Type, Register};
pub enum Error { pub enum Error {
NoMainFunction,
StackOverflow, StackOverflow,
UnknownFunction(String),
UnknownFunctionCall(isize, isize), UnknownFunctionCall(isize, isize),
InvalidAriphmeticOperation, InvalidAriphmeticOperation,
} }
@ -11,7 +13,9 @@ pub enum Error {
impl Display for Error { impl Display for Error {
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 {
Error::NoMainFunction => write!(f, "Main function not found"),
Error::StackOverflow => write!(f, "Stack overflow"), Error::StackOverflow => write!(f, "Stack overflow"),
Error::UnknownFunction(name) => write!(f, "Unknown function: {}", name),
Error::UnknownFunctionCall(l, e) => write!(f, "Unknown function call at {}: {}", l, e), Error::UnknownFunctionCall(l, e) => write!(f, "Unknown function call at {}: {}", l, e),
Error::InvalidAriphmeticOperation => write!(f, "Invalid ariphmetic operation"), Error::InvalidAriphmeticOperation => write!(f, "Invalid ariphmetic operation"),
} }
@ -20,9 +24,11 @@ impl Display for Error {
#[derive(Debug)] #[derive(Debug)]
pub struct VM { pub struct VM {
pub instr_pointer: isize, instr_pointer: isize,
pub registers: Vec<Type>, jumped_from: isize,
pub stack: Vec<Type>, registers: Vec<Type>,
stack: Vec<Type>,
function_pointer: Vec<(String, isize)>, // (name, index)
} }
pub type VMReturn = Result<(), Error>; pub type VMReturn = Result<(), Error>;
@ -31,18 +37,34 @@ impl VM {
pub fn new() -> Self { pub fn new() -> Self {
VM { VM {
instr_pointer: 0, instr_pointer: 0,
jumped_from: 0,
registers: vec![Type::Null; 1024], registers: vec![Type::Null; 1024],
stack: Vec::new(), stack: Vec::new(),
function_pointer: Vec::new(),
} }
} }
pub fn run(&mut self, instrs: Vec<Instr>, debug: bool) -> VMReturn { pub fn run(&mut self, instrs: Vec<Instr>, debug: bool) -> VMReturn {
let mut result: VMReturn;
for (idx, instr) in instrs.iter().enumerate() {
match instr {
Label { name } => {
if name == "function_main" { self.instr_pointer = idx as isize; }
self.function_pointer.push((name.clone(), idx as isize));
},
_ => {}
}
}
'tco: loop { 'tco: loop {
self.instr_pointer += 1; self.instr_pointer += 1;
if self.instr_pointer - 1 == instrs.len() as isize { return Ok(()); } if self.instr_pointer - 1 == instrs.len() as isize {
result = Ok(());
break 'tco;
}
let instr = &instrs[self.instr_pointer as usize - 1]; let instr = &instrs[(self.instr_pointer - 1) as usize];
if debug { print_debug(&self, instr); }
match instr { match instr {
Store { address, value, .. } => { Store { address, value, .. } => {
self.store(&address, &value)?; self.store(&address, &value)?;
@ -54,53 +76,59 @@ impl VM {
call(address, args, self.instr_pointer)?; call(address, args, self.instr_pointer)?;
continue 'tco; continue 'tco;
}, },
Push { value, .. } => { Push { value } => {
self.push(value.trim().clone())?; self.push(value.trim().clone())?;
continue 'tco; continue 'tco;
}, },
Pop { address, .. } => { Pop { address } => {
let value = self.stack.pop(); let value = self.stack.pop();
self.store(&address, &value.unwrap())?; self.store(&address, &value.unwrap())?;
continue 'tco; continue 'tco;
}, },
Add { .. } => { Add => {
let lhs = self.stack.pop().unwrap(); let lhs = self.stack.pop().unwrap();
let rhs = self.stack.pop().unwrap(); let rhs = self.stack.pop().unwrap();
self.push((lhs + rhs)?)?; self.push((lhs + rhs)?)?;
continue 'tco; continue 'tco;
}, },
Sub { .. } => { Sub => {
let lhs = self.stack.pop().unwrap(); let lhs = self.stack.pop().unwrap();
let rhs = self.stack.pop().unwrap(); let rhs = self.stack.pop().unwrap();
self.push((lhs - rhs)?)?; self.push((lhs - rhs)?)?;
continue 'tco; continue 'tco;
}, },
Mul { .. } => { Mul => {
let lhs = self.stack.pop().unwrap(); let lhs = self.stack.pop().unwrap();
let rhs = self.stack.pop().unwrap(); let rhs = self.stack.pop().unwrap();
self.push((lhs * rhs)?)?; self.push((lhs * rhs)?)?;
continue 'tco; continue 'tco;
}, },
Div { .. } => { Div => {
let lhs = self.stack.pop().unwrap(); let lhs = self.stack.pop().unwrap();
let rhs = self.stack.pop().unwrap(); let rhs = self.stack.pop().unwrap();
self.push((lhs / rhs)?)?; self.push((lhs / rhs)?)?;
continue 'tco; continue 'tco;
}, },
Jump { to, .. } => { Jump { to } => {
self.instr_pointer = *to as isize - 1; let pointer = self.get_function_pointer(to.to_string())?;
self.jumped_from = self.instr_pointer;
self.instr_pointer = pointer;
continue 'tco; continue 'tco;
}, },
PopJumpIfFalse { to, .. } => { Return => {
let value = self.stack.pop().unwrap(); if self.jumped_from == 0 { return Ok(()); }
if !value.as_bool() { self.instr_pointer = *to as isize - 1; } self.instr_pointer = self.jumped_from;
self.jumped_from = 0;
continue 'tco; continue 'tco;
}, },
Return { .. } => return Ok(()), Label { .. } => {},
}; _ => unimplemented!(),
} }
} }
result
}
fn push(&mut self, value: Type) -> Result<(), Error> { fn push(&mut self, value: Type) -> Result<(), Error> {
if self.stack.len() >= 1024 { if self.stack.len() >= 1024 {
return Err(Error::StackOverflow); return Err(Error::StackOverflow);
@ -112,6 +140,15 @@ impl VM {
// TODO: Remove .clone() // TODO: Remove .clone()
Ok(self.registers[address.value()] = value.clone()) Ok(self.registers[address.value()] = value.clone())
} }
fn get_function_pointer(&mut self, name: String) -> Result<isize, Error> {
for (idx, (n, _)) in self.function_pointer.iter().enumerate() {
if n == &name {
return Ok(idx as isize);
}
}
Err(Error::UnknownFunction(name))
}
} }
fn print_debug(vm: &VM, curr_instr: &Instr) { fn print_debug(vm: &VM, curr_instr: &Instr) {

View file

@ -1 +1,4 @@
(print "Hello, world!") (fun str "Hello, world!")
(fun main
(print str))

View file

@ -1,6 +0,0 @@
(fun factorial (x)
(if (<= x 1)
1
(* x (factorial (- x 1)))))
(do
(print (factorial 7)))

12
test.sh Executable file
View file

@ -0,0 +1,12 @@
in=$1 # Get first's file name
name=${in%.*} # Remove extension
make debug
blspc compile $name.blsp
echo -e "------------------------------------------- SOURCE"
cat ./$name.blsp
echo -e "\n----------------------------------------- COMPILED"
cat ./$name.bsm
echo -e "------------------------------------------- OUTPUT"
blspc run $name.bsm
echo -e "--------------------------------------------------"