From 83e0121deec127a4259ecad2ad98939fcb9c8b01 Mon Sep 17 00:00:00 2001 From: Natapat Samutpong Date: Fri, 28 Jan 2022 06:39:57 +0700 Subject: [PATCH] refactor: a large amount of refactor --- README.md | 1 + blspc/src/args.rs | 44 ++++--- blspc/src/compiler/compile.rs | 225 ++++++++++------------------------ blspc/src/compiler/parser.rs | 21 +--- blspc/src/main.rs | 46 ++----- blspc/src/vm/instr.rs | 80 +++++------- blspc/src/vm/parser.rs | 55 +++------ blspc/src/vm/vm.rs | 77 +++++++++--- example/hello.blsp | 5 +- example/s.blsp | 6 - test.sh | 12 ++ 11 files changed, 232 insertions(+), 340 deletions(-) create mode 100755 test.sh diff --git a/README.md b/README.md index fb70f12..6e7b6f4 100644 --- a/README.md +++ b/README.md @@ -24,3 +24,4 @@ Hello, World! TODO: - Quote, Quasiquote, etc. - Optimizing +- Remove unnecessary copying in the entire codebase diff --git a/blspc/src/args.rs b/blspc/src/args.rs index 0fee70d..95eee7f 100644 --- a/blspc/src/args.rs +++ b/blspc/src/args.rs @@ -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, +} - /// 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, + #[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, } \ No newline at end of file diff --git a/blspc/src/compiler/compile.rs b/blspc/src/compiler/compile.rs index 64d26eb..4af76d0 100644 --- a/blspc/src/compiler/compile.rs +++ b/blspc/src/compiler/compile.rs @@ -2,7 +2,6 @@ use crate::{vm::instr::*, compiler::parser::Sexpr::{self, *}}; pub struct Compiler { pub instructions: Vec, 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, String> { + pub fn compile(&mut self, src: Sexpr) -> Result, 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, String> { + fn compile_atom(&mut self, atom: Sexpr) -> Result, 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, 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) diff --git a/blspc/src/compiler/parser.rs b/blspc/src/compiler/parser.rs index 97bbf24..74a9dd8 100644 --- a/blspc/src/compiler/parser.rs +++ b/blspc/src/compiler/parser.rs @@ -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(); diff --git a/blspc/src/main.rs b/blspc/src/main.rs index a7b4507..6c6977f 100644 --- a/blspc/src/main.rs +++ b/blspc/src/main.rs @@ -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, file: PathBuf, debug: bool, start: Instant) { @@ -69,11 +48,12 @@ fn compile_src(src: String, path: Option, 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 diff --git a/blspc/src/vm/instr.rs b/blspc/src/vm/instr.rs index 08acac3..a910d94 100644 --- a/blspc/src/vm/instr.rs +++ b/blspc/src/vm/instr.rs @@ -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), + 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"), } } } \ No newline at end of file diff --git a/blspc/src/vm/parser.rs b/blspc/src/vm/parser.rs index 1bc597b..a9673a2 100644 --- a/blspc/src/vm/parser.rs +++ b/blspc/src/vm/parser.rs @@ -6,7 +6,6 @@ const REGEX: &str = r###"[^\s\$";]+|\$"[^"]*"|;.*"###; macro_rules! value { ($s:expr) => { $s.parse::().unwrap() }; } macro_rules! register { ($s:expr) => { $s.parse::().unwrap() }; } -macro_rules! label { ($s:expr) => { $s.parse::().unwrap() }; } pub fn parse_instr(src: &str) -> Vec { let regex = Regex::new(REGEX).unwrap(); @@ -16,44 +15,30 @@ pub fn parse_instr(src: &str) -> Vec { let tokens = regex.find_iter(line).map(|m| m.as_str()).collect::>(); 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() }); + } + }, } } diff --git a/blspc/src/vm/vm.rs b/blspc/src/vm/vm.rs index c5d3b1d..9024a9c 100644 --- a/blspc/src/vm/vm.rs +++ b/blspc/src/vm/vm.rs @@ -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, - pub stack: Vec, + instr_pointer: isize, + jumped_from: isize, + registers: Vec, + stack: Vec, + 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, 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 { + 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) { diff --git a/example/hello.blsp b/example/hello.blsp index 0ae84b3..800e785 100644 --- a/example/hello.blsp +++ b/example/hello.blsp @@ -1 +1,4 @@ -(print "Hello, world!") \ No newline at end of file +(fun str "Hello, world!") + +(fun main + (print str)) \ No newline at end of file diff --git a/example/s.blsp b/example/s.blsp index e87d6cd..e69de29 100644 --- a/example/s.blsp +++ b/example/s.blsp @@ -1,6 +0,0 @@ -(fun factorial (x) - (if (<= x 1) - 1 - (* x (factorial (- x 1))))) -(do - (print (factorial 7))) \ No newline at end of file diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..28d4bb6 --- /dev/null +++ b/test.sh @@ -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 "--------------------------------------------------"