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:
- Quote, Quasiquote, etc.
- Optimizing
- Remove unnecessary copying in the entire codebase

View file

@ -4,24 +4,38 @@ use structopt::StructOpt;
#[derive(StructOpt, Debug)]
#[structopt(name = "blspc")]
pub struct Args {
/// Verbose mode (-v, -vv, -vvv, etc.). Max is 2 currently.
#[structopt(short, long, parse(from_occurrences))]
pub verbose: u8,
pub struct Opts {
#[structopt(subcommand)]
pub commands: Option<Args>,
}
/// Compliation mode (-c).
#[structopt(short, long)]
pub compile: bool,
#[derive(StructOpt, Debug)]
#[structopt(name = "args")]
pub enum Args {
#[structopt(name = "compile")]
Compile (CompileOpts),
#[structopt(name = "run")]
Run (RunOpts),
}
/// Run mode (-r).
#[structopt(short, long)]
pub run: bool,
/// Files to process.
#[derive(StructOpt, Debug)]
#[structopt(name = "compile", about = "Compile Options")]
pub struct CompileOpts {
#[structopt(name = "FILE", parse(from_os_str))]
pub file: PathBuf,
/// Output file.
#[structopt(short, long, parse(from_os_str))]
#[structopt(name = "OUTPUT", parse(from_os_str))]
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 instructions: Vec<Instr>,
pub register_pointer: usize,
pub label_pointer: usize,
}
impl Compiler {
@ -10,7 +9,6 @@ impl Compiler {
Compiler {
instructions: Vec::new(),
register_pointer: 1,
label_pointer: 1,
}
}
@ -24,184 +22,89 @@ impl Compiler {
Register { value: self.register_pointer - 1 }
}
fn next_label(&mut self) -> usize {
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> {
pub fn compile(&mut self, src: Sexpr) -> Result<Vec<Instr>, String> {
let mut result = Vec::new();
let comp = src.clone(); // Used for commenting
match ast {
Cons(car, cdr) => {
match *car {
Symbol(ref s) => {
match s.as_str() {
"do" => {
for c in cdr {
result.append(&mut self.compile(c, depth + 1)?);
}
},
"if" => {
// TODO: Remove .clone()
let mut cond = self.compile(cdr[0].clone(), depth + 1)?;
result.append(&mut cond);
result.push(Instr::PopJumpIfFalse {
to: 999, // To be replaced later
label: self.next_label(),
});
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, };
'tco: loop {
match src {
Cons(car, cdr) => {
match *car {
Symbol(ref call) => {
match call.as_str() {
"do" => {
for c in cdr {
result.append(&mut self.compile(c)?);
}
_ => unreachable!(),
},
"fun" => {
result.push(Instr::Comment { text: format!("--- {}", comp) });
let function_name = match &cdr[0] {
Symbol(ref name) => format!("function_{}", name.clone()),
_ => return Err(format!("Expected function name, got {}", cdr[0])),
};
let body = &cdr[1];
result.push(Instr::Label{ name: function_name });
result.append(&mut self.compile(body.clone())?);
result.push(Instr::Return);
},
"print" => {
result.append(&mut self.compile(cdr[0].clone())?);
let to = self.next_register();
let call_register = self.next_register();
result.push(Instr::Pop { address: to });
result.push(Instr::Store {
address: call_register,
value: Type::Int(1),
});
result.push(Instr::Call {
address: call_register,
args: to,
});
}
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)?); },
}
_ => { 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`
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> {
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::Push {
value: Type::Int(*i),
label: self.next_label(),
});
result.push(Instr::Comment { text: format!("----- {}", comp) });
result.push(Instr::Push { value: Type::Int(i) });
},
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(),
});
result.push(Instr::Comment { text: format!("----- {}", comp) });
result.push(Instr::Push { value: Type::Float(f) });
},
Str(s) => {
result.push(Instr::Push {
value: Type::String(s.clone()),
label: self.next_label(),
});
result.push(Instr::Comment { text: format!("----- {}", comp) });
result.push(Instr::Push { value: Type::String(s) });
},
_ => {
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" => {
let mut arg = self.compile_atom(&args[0], depth + 1)?;
result.append(&mut arg);
let arg_pointer = self.current_register();
result.push(Instr::Pop {
address: arg_pointer,
label: self.next_label(),
});
let call_register = self.next_register();
result.push(Instr::Store {
address: call_register,
value: Type::Int(1),
label: self.next_label(),
});
result.push(Instr::Call {
address: call_register,
args: arg_pointer,
label: self.next_label(),
});
Boolean(b) => {
result.push(Instr::Comment { text: format!("----- {}", comp) });
result.push(Instr::Push { value: Type::Boolean(b) });
},
"add" | "+" => {
let mut lhs = self.compile_atom(&args[0], depth + 1)?;
result.append(&mut lhs);
let mut rhs = self.compile_atom(&args[1], depth + 1)?;
result.append(&mut rhs);
result.push(Instr::Add { label: self.next_label() });
Symbol(s) => {
result.push(Instr::Comment { text: format!("----- {} variable", comp) });
result.push(Instr::Jump { to: format!("function_{}", s), });
},
"sub" | "-" => {
let mut lhs = self.compile_atom(&args[0], depth + 1)?;
result.append(&mut lhs);
let mut rhs = self.compile_atom(&args[1], depth + 1)?;
result.append(&mut rhs);
result.push(Instr::Sub { label: self.next_label() });
},
"mul" | "*" => {
let mut lhs = self.compile_atom(&args[0], depth + 1)?;
result.append(&mut lhs);
let mut rhs = self.compile_atom(&args[1], depth + 1)?;
result.append(&mut rhs);
result.push(Instr::Mul { label: self.next_label() });
},
"div" | "/" => {
let mut lhs = self.compile_atom(&args[0], depth + 1)?;
result.append(&mut lhs);
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)

View file

@ -14,7 +14,7 @@ impl std::fmt::Display for Sexpr {
match self {
Int(i) => write!(f, "{}", i),
Float(fl) => write!(f, "{}", fl),
Str(s) => write!(f, "{}", s),
Str(s) => write!(f, "\"{}\"", s),
Boolean(b) => write!(f, "{}", b),
Symbol(s) => write!(f, "{}", s),
Cons(car, cdr) => {
@ -59,7 +59,6 @@ impl Parser {
Some(s) => match s.as_str() {
")" => Err(format!("Unexpected ')' at position {}", self.position)),
// TODO: Handle quote and that stuff.
"'" => { unimplemented!() },
"(" => self.parse_sequence(")"),
_ => self.parse_atom(),
}
@ -85,24 +84,6 @@ impl Parser {
self.next();
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 {
let token = self.next().unwrap();

View file

@ -3,7 +3,7 @@ use std::{fs::{read_to_string, File}, path::{Path, PathBuf}, io::{Write, Seek},
use structopt::StructOpt;
mod args;
use args::Args;
use args::Opts;
mod util;
use util::cover_paren;
@ -16,43 +16,22 @@ use vm::{vm::VM, parser::parse_instr};
fn main() {
let start = Instant::now();
let args = Args::from_args();
let debug = match args.verbose {
0 => false,
1 => true,
2 => true,
_ => true,
};
let args = Opts::from_args();
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();
compile_src(src, args.output, args.file, debug, start);
},
// Run
(false, true) => {
let src = read_to_string(&args.file).unwrap();
run_src(src, debug);
},
(false, false) => {
if args.file.extension() == Some("blsp".as_ref()) {
if let Some(commands) = args.commands {
match commands {
args::Args::Compile(args) => {
let src = read_to_string(&args.file).unwrap();
let debug = args.debug;
compile_src(src, args.output, args.file, debug, start);
} else if args.file.extension() == Some("bsm".as_ref()) {
},
args::Args::Run(args) => {
let src = read_to_string(&args.file).unwrap();
let debug = args.debug;
run_src(src, debug);
} else {
panic!("No mode specified");
}
},
},
}
}
}
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 {
Ok(ast) => {
let mut compiler = Compiler::new();
let code = compiler.compile(ast, 0);
let code = compiler.compile(ast);
match code {
Ok(code) => {
let mut file = File::create(format!("{}.bsm", file_name)).unwrap();
for line in code {
if line.to_string().starts_with(";") { continue; }
write!(file, "{}\n", line).unwrap();
}
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.
#[derive(Clone, Debug)]
pub enum Type {
Null,
Null, StackGuard,
Int(i64),
Float(f64),
Boolean(bool),
String(String),
Array(Vec<Type>),
Symbol(String),
}
impl Type {
pub fn as_bool(&self) -> bool {
match self {
Type::Null => false,
Type::Boolean(b) => *b,
Type::Int(i) => *i != 0,
Type::Float(f) => *f != 0.0,
Type::String(s) => !s.is_empty(),
Type::Array(a) => !a.is_empty(),
_ => unreachable!(),
}
}
@ -34,12 +33,8 @@ impl Type {
pub fn trim(&self) -> Type {
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::Array(a) => Type::Array(a.iter().map(|t| t.trim()).collect()),
_ => self.clone(),
}
}
@ -53,15 +48,7 @@ impl Type {
false => "false".to_string(),
},
Type::String(s) => s.clone(),
Type::Array(a) => {
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
}
_ => unreachable!(),
}
}
}
@ -126,19 +113,12 @@ impl Div for Type {
impl Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Type::Null => write!(f, ":NULL"),
Type::Int(i) => write!(f, ":{}", i),
Type::Float(fl) => write!(f, ":{}", fl),
Type::Boolean(b) => write!(f, ":{}", b),
Type::String(s) => write!(f, "$\"{}\"", s),
Type::Array(a) => {
write!(f, "[[ ")?;
for (i, t) in a.iter().enumerate() {
write!(f, "{}", t)?;
if i < a.len() - 1 { write!(f, ", ")?; }
}
write!(f, " ]]")
}
Type::Symbol(s) => write!(f, "function_{}", s),
_ => unreachable!(),
}
}
}
@ -197,39 +177,41 @@ impl FromStr for Register {
/// Instructions for the assembler.
#[derive(Clone, Debug)]
pub enum Instr {
// Load a literal value onto the stack.
// Load { address: Register, label: usize },
Label { name: String }, Comment { text: String },
// Store a literal value into a register.
Store { address: Register, value: Type, label: usize },
Store { address: Register, value: Type },
// Call intrinsic function.
Call { address: Register, args: Register, label: usize },
Call { address: Register, args: Register },
// Stack operations.
Push { value: Type, label: usize }, Pop { address: Register, label: usize },
Push { value: Type }, Pop { address: Register },
// Stack arithmetic.
Add { label: usize }, Sub { label: usize },
Mul { label: usize }, Div { label: usize },
Add, Sub,
Mul, Div,
// Jumping
Jump { to: usize, label: usize },
PopJumpIfFalse { to: usize, label: usize },
Jump { to: String },
PopJumpIfFalse { to: usize },
Return { value: Register, label: usize },
Return,
}
impl Display for Instr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
// Instr::Load { address, label } => write!(f, "{}: LOAD {}", label, address),
Instr::Store { address, value , label} => write!(f, "{} STORE {} {}", label, address, value),
Instr::Call { address, args, label } => write!(f, "{} CALL {} {}", label, address, args),
Instr::Push { value, label } => write!(f, "{} PUSH {}", label, value),
Instr::Pop { address, label } => write!(f, "{} POP {}", label, address),
Instr::Add { label } => write!(f, "{} ADD", label),
Instr::Sub { label } => write!(f, "{} SUB", label),
Instr::Mul { label } => write!(f, "{} MUL", label),
Instr::Div { label } => write!(f, "{} DIV", label),
Instr::Jump { to, label } => write!(f, "{} JMP {}", label, to),
Instr::PopJumpIfFalse { to, label } => write!(f, "{} POP_JUMP_IF_FALSE {}", label, to),
Instr::Return { value, label } => write!(f, "{} RETURN {}", label, value),
// --4-- Padding
// ----------20--------- Parameter start
Instr::Label { name } => write!(f, ".{}:", name),
Instr::Comment { text } => write!(f, ";{}", text),
Instr::Store { address, value } => write!(f, " STORE {} {}", address, value),
Instr::Call { address, args } => write!(f, " CALL {} {}", address, args),
Instr::Push { value } => write!(f, " PUSH {}", value),
Instr::Pop { address } => write!(f, " POP {}", address),
Instr::Add => write!(f, " ADD"),
Instr::Sub => write!(f, " SUB"),
Instr::Mul => write!(f, " MUL"),
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! register { ($s:expr) => { $s.parse::<Register>().unwrap() }; }
macro_rules! label { ($s:expr) => { $s.parse::<usize>().unwrap() }; }
pub fn parse_instr(src: &str) -> Vec<Instr> {
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<_>>();
if tokens[0].starts_with(";") { continue; }
let label = label!(tokens[0]);
match tokens[1] {
match tokens[0] {
"STORE" => { result.push(Instr::Store {
address: register!(tokens[2]),
value: value!(tokens[3]),
label,
address: register!(tokens[1]),
value: value!(tokens[2]),
}); },
"CALL" => { result.push(Instr::Call {
address: register!(tokens[2]),
args: register!(tokens[3]),
label,
address: register!(tokens[1]),
args: register!(tokens[2]),
}); },
"PUSH" => { result.push(Instr::Push {
value: value!(tokens[2]),
label,
}); },
"POP" => { result.push(Instr::Pop {
address: register!(tokens[2]),
label,
}); },
"ADD" => { result.push(Instr::Add { label }); },
"SUB" => { result.push(Instr::Sub { label }); },
"MUL" => { result.push(Instr::Mul { label }); },
"DIV" => { result.push(Instr::Div { label }); },
"JMP" => { result.push(Instr::Jump {
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]),
"PUSH" => { result.push(Instr::Push { value: value!(tokens[1]) }); },
"POP" => { result.push(Instr::Pop { address: register!(tokens[1]) }); },
"ADD" => { result.push(Instr::Add); },
"SUB" => { result.push(Instr::Sub); },
"MUL" => { result.push(Instr::Mul); },
"DIV" => { result.push(Instr::Div); },
"JMP" => { result.push(Instr::Jump { to: tokens[1].to_string() }); },
"PJMPF" => todo!(),
"RET" => { result.push(Instr::Return); },
_ => {
if tokens[0].starts_with(".") {
let name = &tokens[0][1..tokens[0].len() - 1];
result.push(Instr::Label { name: name.to_string() });
}
},
}
}

View file

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

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 "--------------------------------------------------"