From d6e290f916a085207e68432d005f185e8ead525c Mon Sep 17 00:00:00 2001 From: n3tael Date: Wed, 7 Feb 2024 23:38:04 +0200 Subject: [PATCH] =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=201.0.5=20*=20=D1=81=D1=82=D0=B5=D0=BA=20?= =?UTF-8?q?=D1=82=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20=D0=BD=D0=B5=20=D0=B1?= =?UTF-8?q?=D0=B5=D1=81=D0=BA=D0=BE=D0=BD=D0=B5=D1=87=D0=BD=D1=8B=D0=B9.?= =?UTF-8?q?=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=82=D1=8C=20=D0=BC=D0=BE=D0=B6?= =?UTF-8?q?=D0=BD=D0=BE=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20=D0=B0=D1=80?= =?UTF-8?q?=D0=B3=D1=83=D0=BC=D0=B5=D0=BD=D1=82=20cli=20(=D0=BC=D0=B0?= =?UTF-8?q?=D0=BA=D1=81=D0=B8=D0=BC=D1=83=D0=BC=2065535,=20=D0=B4=D0=B5?= =?UTF-8?q?=D1=84=D0=BE=D0=BB=D1=82:=20256)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - Cargo.lock | 2 +- Cargo.toml | 4 +-- build.bat | 4 ++- scripts/calc.lb | 2 +- src/errors.rs | 16 +++++++-- src/execute.rs | 56 ++++++++++++++------------------ src/instructions/_unix_random.rs | 8 ++--- src/instructions/add.rs | 8 ++--- src/instructions/and.rs | 8 ++--- src/instructions/args.rs | 10 +++--- src/instructions/band.rs | 8 ++--- src/instructions/bnand.rs | 8 ++--- src/instructions/bor.rs | 8 ++--- src/instructions/bxor.rs | 8 ++--- src/instructions/div.rs | 8 ++--- src/instructions/dump.rs | 4 ++- src/instructions/dup.rs | 7 ++-- src/instructions/exec.rs | 10 +++--- src/instructions/exit.rs | 4 +-- src/instructions/expr.rs | 17 ++++++---- src/instructions/getc.rs | 4 +-- src/instructions/insert.rs | 4 +-- src/instructions/jmp.rs | 8 ++--- src/instructions/jnz.rs | 12 +++---- src/instructions/jz.rs | 12 +++---- src/instructions/kjnz.rs | 12 +++---- src/instructions/kjz.rs | 12 +++---- src/instructions/maxsize.rs | 6 ++-- src/instructions/meow.rs | 6 ++-- src/instructions/modulo.rs | 8 ++--- src/instructions/mul.rs | 8 ++--- src/instructions/nand.rs | 8 ++--- src/instructions/not.rs | 6 ++-- src/instructions/or.rs | 8 ++--- src/instructions/pick.rs | 8 ++--- src/instructions/pop.rs | 4 ++- src/instructions/print.rs | 2 +- src/instructions/println.rs | 2 +- src/instructions/push.rs | 6 ++-- src/instructions/putc.rs | 6 ++-- src/instructions/random.rs | 8 ++--- src/instructions/scan.rs | 4 +-- src/instructions/size.rs | 4 ++- src/instructions/sub.rs | 8 ++--- src/instructions/swap.rs | 8 ++--- src/instructions/xor.rs | 8 ++--- src/main.rs | 22 ++++++++++--- src/stack.rs | 53 +++++++++++++++++++++++++++--- 49 files changed, 269 insertions(+), 189 deletions(-) diff --git a/.gitignore b/.gitignore index 92e31db..84a4913 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ /target -/archive /bin \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 8930960..bef5943 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,7 +10,7 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "labast" -version = "1.0.4" +version = "1.0.5" dependencies = [ "fastrand", "pico-args", diff --git a/Cargo.toml b/Cargo.toml index ae95f2c..4316d42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "labast" -version = "1.0.4" +version = "1.0.5" authors = [ "n3tael" ] edition = "2021" -description = "A zero-dependencies Labaski interpreter written in Rust." +description = "A Labaski interpreter written in Rust." readme = "README.md" license = "MIT" publish = false diff --git a/build.bat b/build.bat index 9bf316b..48cf4f7 100644 --- a/build.bat +++ b/build.bat @@ -3,7 +3,9 @@ echo Building for Windows... cargo build --release echo Building for Linux... cargo zigbuild --release --target x86_64-unknown-linux-gnu -echo Copy to bin... +echo Copy binaries to bin folder... copy target\release\labast.exe bin\ /Y copy target\x86_64-unknown-linux-gnu\release\labast bin\ /Y +echo Creating source code tar.gz archive... +tar --exclude="./bin" --exclude="./target" --exclude=".git" -cvzf bin\labast-latest.tar.gz * echo Done! \ No newline at end of file diff --git a/scripts/calc.lb b/scripts/calc.lb index be58127..6ef7039 100644 --- a/scripts/calc.lb +++ b/scripts/calc.lb @@ -12,7 +12,7 @@ @ 2 sub - meow dkdkd + meow quit @ 3 diff --git a/src/errors.rs b/src/errors.rs index 4209d4f..5c24d11 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,5 +1,19 @@ use std::fmt::Display; +pub enum StackError { + StackOverflow, + StackUnderflow, +} + +impl Display for StackError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + StackError::StackOverflow => write!(f, "Stack overflow!"), + StackError::StackUnderflow => write!(f, "Stack underflow!"), + } + } +} + pub enum RunError { RequestArgsInMainModule, ExecuteItself(String), @@ -11,7 +25,6 @@ pub enum RunError { FailToReadLineFromConsole, UnknownLabel(u16), InvalidExpressionUnknownOperator(String), - MemoryEmpty, AttemptToInsertHashOrStringInst, AttemptToInsertEmptyConst, AttemptToInsertALabel @@ -30,7 +43,6 @@ impl Display for RunError { RunError::FailToReadLineFromConsole => write!(f, "Failed to read line from console"), RunError::UnknownLabel(label_name) => write!(f, "Unknown label: {}", label_name), RunError::InvalidExpressionUnknownOperator(name) => write!(f, "Invalid expression: unknown operator '{}'", name), - RunError::MemoryEmpty => write!(f, "No elements in memory!"), RunError::AttemptToInsertHashOrStringInst => write!(f, "Attempt to insert a hash/string-instruction"), RunError::AttemptToInsertEmptyConst => write!(f, "Attempt to insert an empty constant"), RunError::AttemptToInsertALabel => write!(f, "Attempt to insert a label"), diff --git a/src/execute.rs b/src/execute.rs index 7b4fa6b..25dc1ee 100644 --- a/src/execute.rs +++ b/src/execute.rs @@ -1,4 +1,4 @@ -use crate::{errors::RunError, instructions, stack::{Instruction, Stack}}; +use crate::{instructions, stack::{Instruction, Stack, StackVec}}; fn find_labels(stack: &mut Stack) { while stack.program_counter < (stack.program.len() as u16) { @@ -11,7 +11,7 @@ fn find_labels(stack: &mut Stack) { if stack.labels[label.data as usize].is_some() { eprintln!("Label {} already defined", label.data); - return; + std::process::exit(2); } if label.data == 0 { @@ -22,23 +22,18 @@ fn find_labels(stack: &mut Stack) { stack.labels[label.data as usize] = Some(stack.program_counter as i16); } - if stack.labels[0].is_some() { - stack.program_counter = stack.labels[0].unwrap() as u16; - } else { - stack.program_counter = 0; - } + stack.program_counter = stack.labels[0].unwrap_or(0) as u16; } -fn find_prefix_operators(instruction: &mut Instruction, memory: &mut Vec) { +fn find_prefix_operators(instruction: &mut Instruction, memory: &mut StackVec) { match instruction.name.chars().nth(0) { Some('|') => { instruction.name = instruction.name.chars().skip(1).collect(); - - instruction.data = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); + instruction.data = memory.pop(); }, Some('^') => { instruction.name = instruction.name.chars().skip(1).collect(); - //dbg!(&instruction); + if instruction.name.chars().nth(0) != Some('#') { println!("{0} {1}", instruction.name, instruction.data.to_string()); } else if instruction.arg.is_empty() { @@ -51,7 +46,7 @@ fn find_prefix_operators(instruction: &mut Instruction, memory: &mut Vec) { } } -pub fn execute(stack: &mut Stack, mut origin_stack: Option<&mut Stack>, mod_name: &String) { +pub fn execute(stack: &mut Stack, mut origin_stack: Option<&mut Stack>, mod_name: String) { find_labels(stack); while let Some(mut instruction) = stack.program.get_mut(stack.program_counter as usize) { @@ -65,11 +60,11 @@ pub fn execute(stack: &mut Stack, mut origin_stack: Option<&mut Stack>, mod_name match instruction.name.as_str() { // Stack operations - "push" => instructions::push::push(&mut stack.memory, &instruction.data), + "push" => instructions::push::push(&mut stack.memory, instruction.data), "pop" => instructions::pop::pop(&mut stack.memory), "dup" => instructions::dup::dup(&mut stack.memory), "swap" => instructions::swap::swap(&mut stack.memory), - "pick" => instructions::pick::pick(&mut stack.memory, &instruction.data), + "pick" => instructions::pick::pick(&mut stack.memory, instruction.data), // Math "add" => instructions::add::add(&mut stack.memory), @@ -93,46 +88,45 @@ pub fn execute(stack: &mut Stack, mut origin_stack: Option<&mut Stack>, mod_name "bnot" => instructions::not::not(&mut stack.memory), // Labels - "jmp" => instructions::jmp::jmp(&mut stack.labels, &mut stack.program_counter, &instruction.data), - "jnz" => instructions::jnz::jnz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, &instruction.data), - "jz" => instructions::jz::jz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, &instruction.data), - "kjnz" => instructions::kjnz::kjnz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, &instruction.data), - "kjz" => instructions::kjz::kjz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, &instruction.data), + "jmp" => instructions::jmp::jmp(&mut stack.labels, &mut stack.program_counter, instruction.data), + "jnz" => instructions::jnz::jnz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, instruction.data), + "jz" => instructions::jz::jz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, instruction.data), + "kjnz" => instructions::kjnz::kjnz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, instruction.data), + "kjz" => instructions::kjz::kjz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, instruction.data), // Input/Output "putc" => instructions::putc::putc(&mut stack.memory), "getc" => instructions::getc::getc(&mut stack.memory), "scan" => instructions::scan::scan(&mut stack.memory), "meow" => instructions::meow::meow(&mut stack.memory), - "#print" => instructions::print::print(&instruction.arg), - "$print" => instructions::print::print(&instruction.arg), - "#println" => instructions::println::println(&instruction.arg), - "$println" => instructions::println::println(&instruction.arg), + "#print" => instructions::print::print(instruction.arg.clone()), + "$print" => instructions::print::print(instruction.arg.clone()), + "#println" => instructions::println::println(instruction.arg.clone()), + "$println" => instructions::println::println(instruction.arg.clone()), // Modules - "args" => instructions::args::args(&mut stack.memory, &mut origin_stack, &instruction.data), + "args" => instructions::args::args(&mut stack.memory, &mut origin_stack, instruction.data), "#exec" => { let arg = instruction.arg.clone(); - instructions::exec::exec(stack, &arg, &mod_name); - } - + instructions::exec::exec(stack, arg, mod_name.clone()) + }, + // Self-modifying "#insert" => { let arg = instruction.arg.clone(); let data = instruction.data.clone(); - - instructions::insert::insert(&mut stack.program, &arg, &data) + instructions::insert::insert(&mut stack.program, arg, data) }, // Special "dump" => instructions::dump::dump(&mut stack.memory), "size" => instructions::size::size(&mut stack.memory), "maxsize" => instructions::maxsize::maxsize(&mut stack.memory), - "#expr" => instructions::expr::expr(&mut stack.memory, &instruction.arg), + "#expr" => instructions::expr::expr(&mut stack.memory, instruction.arg.clone()), "nop" => continue, "quit" => break, - "exit" => instructions::exit::exit(&instruction.data), + "exit" => instructions::exit::exit(instruction.data), // Platform-specific #[cfg(target_family = "unix")] diff --git a/src/instructions/_unix_random.rs b/src/instructions/_unix_random.rs index 75fa8b0..c88e3de 100644 --- a/src/instructions/_unix_random.rs +++ b/src/instructions/_unix_random.rs @@ -1,14 +1,14 @@ use std::fs::File; use std::io::Read; -use crate::RunError; +use crate::stack::StackVec; #[cfg(target_family = "unix")] -pub fn _unix_random(memory: &mut Vec) { +pub fn _unix_random(memory: &mut StackVec) { let mut rng = File::open("/dev/urandom").unwrap(); let mut buffer = [0u8; 2]; rng.read_exact(&mut buffer).unwrap(); - let data = &memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); - memory.push((u16::from_ne_bytes(buffer)) % (*data - 1)); + let data = memory.pop(); + memory.push((u16::from_ne_bytes(buffer)) % (data - 1)); } \ No newline at end of file diff --git a/src/instructions/add.rs b/src/instructions/add.rs index 6bbd0c2..6cd35bf 100644 --- a/src/instructions/add.rs +++ b/src/instructions/add.rs @@ -1,8 +1,8 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn add(memory: &mut Vec) { - let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); - let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); +pub fn add(memory: &mut StackVec) { + let a: u16 = memory.pop(); + let b: u16 = memory.pop(); memory.push(a + b); } \ No newline at end of file diff --git a/src/instructions/and.rs b/src/instructions/and.rs index c3061d2..5e97bb1 100644 --- a/src/instructions/and.rs +++ b/src/instructions/and.rs @@ -1,8 +1,8 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn and(memory: &mut Vec) { - let a: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; - let b: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; +pub fn and(memory: &mut StackVec) { + let a: bool = memory.pop() == 1; + let b: bool = memory.pop() == 1; let c: u16 = if a && b { 1 diff --git a/src/instructions/args.rs b/src/instructions/args.rs index c0958f4..d8140e6 100644 --- a/src/instructions/args.rs +++ b/src/instructions/args.rs @@ -1,15 +1,15 @@ -use crate::{errors::RunError, stack::Stack}; +use crate::{errors::RunError, stack::{Stack, StackVec}}; -pub fn args(memory: &mut Vec, origin_stack: &mut Option<&mut Stack>, data: &u16) { +pub fn args(memory: &mut StackVec, origin_stack: &mut Option<&mut Stack>, data: u16) { if let Some(origin_stack) = origin_stack.as_mut() { - let mut data = *data; + let mut data = data; if data == 0 { - data = origin_stack.memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); + data = origin_stack.memory.pop(); } for _ in 0..data { - memory.push(origin_stack.memory.pop().expect(&format!("{}", RunError::MemoryEmpty))); + memory.push(origin_stack.memory.pop()); } } else { eprintln!("{}", RunError::RequestArgsInMainModule); diff --git a/src/instructions/band.rs b/src/instructions/band.rs index 111acd4..a128209 100644 --- a/src/instructions/band.rs +++ b/src/instructions/band.rs @@ -1,8 +1,8 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn band(memory: &mut Vec) { - let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); - let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); +pub fn band(memory: &mut StackVec) { + let a: u16 = memory.pop(); + let b: u16 = memory.pop(); memory.push(a & b); } diff --git a/src/instructions/bnand.rs b/src/instructions/bnand.rs index 5e40052..ea948f3 100644 --- a/src/instructions/bnand.rs +++ b/src/instructions/bnand.rs @@ -1,8 +1,8 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn bnand(memory: &mut Vec) { - let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); - let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); +pub fn bnand(memory: &mut StackVec) { + let a: u16 = memory.pop(); + let b: u16 = memory.pop(); memory.push(!(a & b)); } diff --git a/src/instructions/bor.rs b/src/instructions/bor.rs index 9cf8942..53a208c 100644 --- a/src/instructions/bor.rs +++ b/src/instructions/bor.rs @@ -1,8 +1,8 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn bor(memory: &mut Vec) { - let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); - let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); +pub fn bor(memory: &mut StackVec) { + let a: u16 = memory.pop(); + let b: u16 = memory.pop(); memory.push(a | b); } diff --git a/src/instructions/bxor.rs b/src/instructions/bxor.rs index e16c576..c3b061e 100644 --- a/src/instructions/bxor.rs +++ b/src/instructions/bxor.rs @@ -1,8 +1,8 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn bxor(memory: &mut Vec) { - let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); - let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); +pub fn bxor(memory: &mut StackVec) { + let a: u16 = memory.pop(); + let b: u16 = memory.pop(); memory.push(a ^ b); } diff --git a/src/instructions/div.rs b/src/instructions/div.rs index b1bc4b0..4e1b888 100644 --- a/src/instructions/div.rs +++ b/src/instructions/div.rs @@ -1,8 +1,8 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn div(memory: &mut Vec) { - let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); - let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); +pub fn div(memory: &mut StackVec) { + let a: u16 = memory.pop(); + let b: u16 = memory.pop(); memory.push(b / a); } \ No newline at end of file diff --git a/src/instructions/dump.rs b/src/instructions/dump.rs index bfd1825..731fe45 100644 --- a/src/instructions/dump.rs +++ b/src/instructions/dump.rs @@ -1,4 +1,6 @@ -pub fn dump(memory: &mut Vec) { +use crate::stack::StackVec; + +pub fn dump(memory: &mut StackVec) { if memory.is_empty() { println!("Stack is empty."); return; diff --git a/src/instructions/dup.rs b/src/instructions/dup.rs index dfeb398..9972e0e 100644 --- a/src/instructions/dup.rs +++ b/src/instructions/dup.rs @@ -1,5 +1,6 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn dup(memory: &mut Vec) { - memory.push(*memory.last().expect(&format!("{}", RunError::MemoryEmpty))); +pub fn dup(memory: &mut StackVec) { + let data = memory.last(); + memory.push(data); } \ No newline at end of file diff --git a/src/instructions/exec.rs b/src/instructions/exec.rs index ebf8b39..d78f2ff 100644 --- a/src/instructions/exec.rs +++ b/src/instructions/exec.rs @@ -1,19 +1,19 @@ use std::fs; use crate::{parse, execute, Stack, errors::RunError}; -pub fn exec(mut stack: &mut Stack, arg: &String, mod_name: &String) { +pub fn exec(mut stack: &mut Stack, arg: String, mod_name: String) { if mod_name == arg { eprintln!("{}", RunError::ExecuteItself(arg.to_string())); std::process::exit(2); } let lines = fs::read_to_string(&arg).expect(&format!("{}", RunError::FailToReadFile)); - let mut temp_stack = Stack::new(); + let mut temp_stack = Stack::new(stack.memory.size()); parse(&mut temp_stack, &lines); - execute(&mut temp_stack, Some(&mut stack), &arg.clone()); + execute(&mut temp_stack, Some(&mut stack), arg.clone()); - for item in temp_stack.memory { - stack.memory.push(item); + for item in temp_stack.memory.iter() { + stack.memory.push(*item); } } \ No newline at end of file diff --git a/src/instructions/exit.rs b/src/instructions/exit.rs index 32038ac..5e9101a 100644 --- a/src/instructions/exit.rs +++ b/src/instructions/exit.rs @@ -1,3 +1,3 @@ -pub fn exit(data: &u16) { - std::process::exit((*data).into()); +pub fn exit(data: u16) { + std::process::exit(data as i32); } \ No newline at end of file diff --git a/src/instructions/expr.rs b/src/instructions/expr.rs index eca34be..b3c00de 100644 --- a/src/instructions/expr.rs +++ b/src/instructions/expr.rs @@ -1,24 +1,27 @@ -use crate::errors::RunError; +use crate::{errors::RunError, stack::StackVec}; -pub fn expr(memory: &mut Vec, arg: &String) { +pub fn expr(memory: &mut StackVec, arg: String) { for code in arg.chars() { match code { '>' => memory.push(0), '$' => { memory.pop(); }, - ':' => memory.push(*memory.last().expect(&format!("{}", RunError::MemoryEmpty))), + ':' => { + let data = memory.last().clone(); + memory.push(data); + }, '\\' => { - let ax = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); - let ax2 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); + let ax = memory.pop(); + let ax2 = memory.pop(); memory.push(ax); memory.push(ax2); } '+' => { - let ax = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); + let ax = memory.pop(); memory.push(ax + 1); } '-' => { - let ax = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); + let ax = memory.pop(); memory.push(ax - 1); } diff --git a/src/instructions/getc.rs b/src/instructions/getc.rs index 3575913..01e071a 100644 --- a/src/instructions/getc.rs +++ b/src/instructions/getc.rs @@ -1,7 +1,7 @@ use std::io::Read; -use crate::errors::RunError; +use crate::{errors::RunError, stack::StackVec}; -pub fn getc(memory: &mut Vec) { +pub fn getc(memory: &mut StackVec) { let char = std::io::stdin() .bytes() .next() diff --git a/src/instructions/insert.rs b/src/instructions/insert.rs index c5b5367..8f84829 100644 --- a/src/instructions/insert.rs +++ b/src/instructions/insert.rs @@ -1,6 +1,6 @@ use crate::{errors::RunError, stack::Instruction}; -pub fn insert(program: &mut Vec, arg: &String, data: &u16) { +pub fn insert(program: &mut Vec, arg: String, data: u16) { let args: Vec = arg.chars().collect(); if args[0] == '#' || args[0] == '$' { @@ -21,6 +21,6 @@ pub fn insert(program: &mut Vec, arg: &String, data: &u16) { program.push(Instruction { name: arg.to_string(), arg: "\n".to_string(), - data: *data + data }); } \ No newline at end of file diff --git a/src/instructions/jmp.rs b/src/instructions/jmp.rs index 788249e..cf8a418 100644 --- a/src/instructions/jmp.rs +++ b/src/instructions/jmp.rs @@ -1,10 +1,10 @@ use crate::errors::RunError; -pub fn jmp(labels: &mut [Option; 256], program_counter: &mut u16, data: &u16) { - if labels[*data as usize].is_none() { - eprintln!("{}", RunError::UnknownLabel(*data)); +pub fn jmp(labels: &mut [Option; 256], program_counter: &mut u16, data: u16) { + if labels[data as usize].is_none() { + eprintln!("{}", RunError::UnknownLabel(data)); std::process::exit(2); } - *program_counter = (labels[*data as usize].unwrap() - 1) as u16; + *program_counter = (labels[data as usize].unwrap() - 1) as u16; } \ No newline at end of file diff --git a/src/instructions/jnz.rs b/src/instructions/jnz.rs index 2093234..59db119 100644 --- a/src/instructions/jnz.rs +++ b/src/instructions/jnz.rs @@ -1,12 +1,12 @@ -use crate::errors::RunError; +use crate::{errors::RunError, stack::StackVec}; -pub fn jnz(memory: &mut Vec, labels: &mut [Option; 256], program_counter: &mut u16, data: &u16) { - if labels[*data as usize].is_none() { - eprintln!("{}", RunError::UnknownLabel(*data)); +pub fn jnz(memory: &mut StackVec, labels: &mut [Option; 256], program_counter: &mut u16, data: u16) { + if labels[data as usize].is_none() { + eprintln!("{}", RunError::UnknownLabel(data)); std::process::exit(2); } - if memory.pop() != Some(0) { - *program_counter = (labels[*data as usize].unwrap() - 1) as u16; + if memory.pop() != 0 { + *program_counter = (labels[data as usize].unwrap() - 1) as u16; } } \ No newline at end of file diff --git a/src/instructions/jz.rs b/src/instructions/jz.rs index f85838d..148de65 100644 --- a/src/instructions/jz.rs +++ b/src/instructions/jz.rs @@ -1,12 +1,12 @@ -use crate::errors::RunError; +use crate::{errors::RunError, stack::StackVec}; -pub fn jz(memory: &mut Vec, labels: &mut [Option; 256], program_counter: &mut u16, data: &u16) { - if labels[*data as usize].is_none() { - eprintln!("{}", RunError::UnknownLabel(*data)); +pub fn jz(memory: &mut StackVec, labels: &mut [Option; 256], program_counter: &mut u16, data: u16) { + if labels[data as usize].is_none() { + eprintln!("{}", RunError::UnknownLabel(data)); std::process::exit(2); } - if memory.pop() == Some(0) { - *program_counter = (labels[*data as usize].unwrap() - 1) as u16; + if memory.pop() == 0 { + *program_counter = (labels[data as usize].unwrap() - 1) as u16; } } \ No newline at end of file diff --git a/src/instructions/kjnz.rs b/src/instructions/kjnz.rs index e5aec9e..da9cca3 100644 --- a/src/instructions/kjnz.rs +++ b/src/instructions/kjnz.rs @@ -1,12 +1,12 @@ -use crate::errors::RunError; +use crate::{errors::RunError, stack::StackVec}; -pub fn kjnz(memory: &mut Vec, labels: &mut [Option; 256], program_counter: &mut u16, data: &u16) { - if labels[*data as usize].is_none() { - eprintln!("{}", RunError::UnknownLabel(*data)); +pub fn kjnz(memory: &mut StackVec, labels: &mut [Option; 256], program_counter: &mut u16, data: u16) { + if labels[data as usize].is_none() { + eprintln!("{}", RunError::UnknownLabel(data)); std::process::exit(2); } - if memory.last() != Some(&0) { - *program_counter = (labels[*data as usize].unwrap() - 1) as u16; + if memory.last() != 0 { + *program_counter = (labels[data as usize].unwrap() - 1) as u16; } } \ No newline at end of file diff --git a/src/instructions/kjz.rs b/src/instructions/kjz.rs index 94329b5..39deda3 100644 --- a/src/instructions/kjz.rs +++ b/src/instructions/kjz.rs @@ -1,12 +1,12 @@ -use crate::errors::RunError; +use crate::{errors::RunError, stack::StackVec}; -pub fn kjz(memory: &mut Vec, labels: &mut [Option; 256], program_counter: &mut u16, data: &u16) { - if labels[*data as usize].is_none() { - eprintln!("{}", RunError::UnknownLabel(*data)); +pub fn kjz(memory: &mut StackVec, labels: &mut [Option; 256], program_counter: &mut u16, data: u16) { + if labels[data as usize].is_none() { + eprintln!("{}", RunError::UnknownLabel(data)); std::process::exit(2); } - if memory.last() == Some(&0) { - *program_counter = (labels[*data as usize].unwrap() - 1) as u16; + if memory.last() == 0 { + *program_counter = (labels[data as usize].unwrap() - 1) as u16; } } \ No newline at end of file diff --git a/src/instructions/maxsize.rs b/src/instructions/maxsize.rs index 4a3f1b7..ae9c57e 100644 --- a/src/instructions/maxsize.rs +++ b/src/instructions/maxsize.rs @@ -1,3 +1,5 @@ -pub fn maxsize(memory: &mut Vec) { - memory.push(u16::MAX); +use crate::stack::StackVec; + +pub fn maxsize(memory: &mut StackVec) { + memory.push(memory.size() as u16); } \ No newline at end of file diff --git a/src/instructions/meow.rs b/src/instructions/meow.rs index 4cb4797..6ec244e 100644 --- a/src/instructions/meow.rs +++ b/src/instructions/meow.rs @@ -1,5 +1,5 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn meow(memory: &mut Vec) { - println!("{}", memory.pop().expect(&format!("{}", RunError::MemoryEmpty))); +pub fn meow(memory: &mut StackVec) { + println!("{}", memory.pop()); } \ No newline at end of file diff --git a/src/instructions/modulo.rs b/src/instructions/modulo.rs index c753150..da26082 100644 --- a/src/instructions/modulo.rs +++ b/src/instructions/modulo.rs @@ -1,8 +1,8 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn modulo(memory: &mut Vec) { - let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); - let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); +pub fn modulo(memory: &mut StackVec) { + let a: u16 = memory.pop(); + let b: u16 = memory.pop(); memory.push(b % a); } \ No newline at end of file diff --git a/src/instructions/mul.rs b/src/instructions/mul.rs index d92fbda..6263c22 100644 --- a/src/instructions/mul.rs +++ b/src/instructions/mul.rs @@ -1,8 +1,8 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn mul(memory: &mut Vec) { - let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); - let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); +pub fn mul(memory: &mut StackVec) { + let a: u16 = memory.pop(); + let b: u16 = memory.pop(); memory.push(b * a); } \ No newline at end of file diff --git a/src/instructions/nand.rs b/src/instructions/nand.rs index c0bd344..bf7e6ab 100644 --- a/src/instructions/nand.rs +++ b/src/instructions/nand.rs @@ -1,8 +1,8 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn nand(memory: &mut Vec) { - let a: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; - let b: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; +pub fn nand(memory: &mut StackVec) { + let a: bool = memory.pop() == 1; + let b: bool = memory.pop() == 1; let c: u16 = if !(a && b) { 1 diff --git a/src/instructions/not.rs b/src/instructions/not.rs index 85ea584..05e6bf9 100644 --- a/src/instructions/not.rs +++ b/src/instructions/not.rs @@ -1,7 +1,7 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn not(memory: &mut Vec) { - let a: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; +pub fn not(memory: &mut StackVec) { + let a: bool = memory.pop() == 1; let c: u16 = if !a { 1 diff --git a/src/instructions/or.rs b/src/instructions/or.rs index 52c1e02..01d53a5 100644 --- a/src/instructions/or.rs +++ b/src/instructions/or.rs @@ -1,8 +1,8 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn or(memory: &mut Vec) { - let a: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; - let b: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; +pub fn or(memory: &mut StackVec) { + let a: bool = memory.pop() == 1; + let b: bool = memory.pop() == 1; let c: u16 = if a || b { 1 diff --git a/src/instructions/pick.rs b/src/instructions/pick.rs index 9a2143f..0e9e297 100644 --- a/src/instructions/pick.rs +++ b/src/instructions/pick.rs @@ -1,11 +1,11 @@ -use crate::errors::RunError; +use crate::{errors::RunError, stack::StackVec}; -pub fn pick(memory: &mut Vec, data: &u16) { - if *data > memory.len() as u16 { +pub fn pick(memory: &mut StackVec, data: u16) { + if data > memory.len() as u16 { eprintln!("{}", RunError::PickTooDeep); std::process::exit(2); } - let arg = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); + let arg = memory.pop(); memory.push(*memory.get(memory.len() - (arg as usize) - 1).expect(&format!("{}", RunError::PickOutOfBounds))); } \ No newline at end of file diff --git a/src/instructions/pop.rs b/src/instructions/pop.rs index 8f45b61..af94e27 100644 --- a/src/instructions/pop.rs +++ b/src/instructions/pop.rs @@ -1,3 +1,5 @@ -pub fn pop(memory: &mut Vec) { +use crate::stack::StackVec; + +pub fn pop(memory: &mut StackVec) { memory.pop(); } \ No newline at end of file diff --git a/src/instructions/print.rs b/src/instructions/print.rs index 679d7ca..8649fe9 100644 --- a/src/instructions/print.rs +++ b/src/instructions/print.rs @@ -1,3 +1,3 @@ -pub fn print(arg: &String) { +pub fn print(arg: String) { print!("{}", arg); } \ No newline at end of file diff --git a/src/instructions/println.rs b/src/instructions/println.rs index 927f406..34be1aa 100644 --- a/src/instructions/println.rs +++ b/src/instructions/println.rs @@ -1,3 +1,3 @@ -pub fn println(arg: &String) { +pub fn println(arg: String) { println!("{}", arg); } \ No newline at end of file diff --git a/src/instructions/push.rs b/src/instructions/push.rs index 028c9d8..21664b7 100644 --- a/src/instructions/push.rs +++ b/src/instructions/push.rs @@ -1,3 +1,5 @@ -pub fn push(memory: &mut Vec, data: &u16) { - memory.push(*data); +use crate::stack::StackVec; + +pub fn push(memory: &mut StackVec, data: u16) { + memory.push(data); } \ No newline at end of file diff --git a/src/instructions/putc.rs b/src/instructions/putc.rs index 6165051..06103e9 100644 --- a/src/instructions/putc.rs +++ b/src/instructions/putc.rs @@ -1,5 +1,5 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn putc(memory: &mut Vec) { - print!("{}", memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) as u8 as char); +pub fn putc(memory: &mut StackVec) { + print!("{}", memory.pop() as u8 as char); } \ No newline at end of file diff --git a/src/instructions/random.rs b/src/instructions/random.rs index a63b609..192a644 100644 --- a/src/instructions/random.rs +++ b/src/instructions/random.rs @@ -1,7 +1,7 @@ use fastrand; -use crate::RunError; +use crate::stack::StackVec; -pub fn random(memory: &mut Vec) { - let data = &memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); - memory.push(fastrand::u16(..) % (*data - 1)); +pub fn random(memory: &mut StackVec) { + let data = memory.pop(); + memory.push(fastrand::u16(..) % (data - 1)); } \ No newline at end of file diff --git a/src/instructions/scan.rs b/src/instructions/scan.rs index fca29f8..5144e48 100644 --- a/src/instructions/scan.rs +++ b/src/instructions/scan.rs @@ -1,6 +1,6 @@ -use crate::errors::RunError; +use crate::{errors::RunError, stack::StackVec}; -pub fn scan(memory: &mut Vec) { +pub fn scan(memory: &mut StackVec) { let mut input = String::new(); std::io::stdin().read_line(&mut input).expect(&format!("{}", RunError::FailToReadLineFromConsole)); diff --git a/src/instructions/size.rs b/src/instructions/size.rs index fea8032..d94225f 100644 --- a/src/instructions/size.rs +++ b/src/instructions/size.rs @@ -1,3 +1,5 @@ -pub fn size(memory: &mut Vec) { +use crate::stack::StackVec; + +pub fn size(memory: &mut StackVec) { memory.push(memory.len() as u16); } \ No newline at end of file diff --git a/src/instructions/sub.rs b/src/instructions/sub.rs index 064419f..88e8713 100644 --- a/src/instructions/sub.rs +++ b/src/instructions/sub.rs @@ -1,8 +1,8 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn sub(memory: &mut Vec) { - let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); - let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); +pub fn sub(memory: &mut StackVec) { + let a: u16 = memory.pop(); + let b: u16 = memory.pop(); memory.push(b - a); } \ No newline at end of file diff --git a/src/instructions/swap.rs b/src/instructions/swap.rs index 2655af4..5ebba5b 100644 --- a/src/instructions/swap.rs +++ b/src/instructions/swap.rs @@ -1,8 +1,8 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn swap(memory: &mut Vec) { - let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); - let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); +pub fn swap(memory: &mut StackVec) { + let a: u16 = memory.pop(); + let b: u16 = memory.pop(); memory.push(a); memory.push(b); diff --git a/src/instructions/xor.rs b/src/instructions/xor.rs index 39da94a..363bf69 100644 --- a/src/instructions/xor.rs +++ b/src/instructions/xor.rs @@ -1,8 +1,8 @@ -use crate::errors::RunError; +use crate::stack::StackVec; -pub fn xor(memory: &mut Vec) { - let a: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; - let b: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; +pub fn xor(memory: &mut StackVec) { + let a: bool = memory.pop() == 1; + let b: bool = memory.pop() == 1; let c: u16 = if !a != !b { 1 diff --git a/src/main.rs b/src/main.rs index edf6a4d..c8673f8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,7 @@ labast - Labaski interpreter written in Rust. usage: labast [options] [ file.lb ] options: + --stack-size sets stack max size (default: 256) -h, --help prints help information -v, --version prints version "; @@ -30,7 +31,7 @@ fn main() { } }; - let mut stack = Stack::new(); + let mut stack = Stack::new(args.stack_size); if args.input.is_none() { let mut line = String::new(); @@ -46,21 +47,22 @@ fn main() { stdin.lock().read_line(&mut line).unwrap(); - parse(&mut stack, &line.trim()); - execute(&mut stack, None, &"inline".to_string()); + parse(&mut stack, line.trim()); + execute(&mut stack, None, "inline".to_string()); } } else { let input = &args.input.expect("error: no input file"); let lines = fs::read_to_string(&input).expect(&format!("{}", RunError::FailToReadFile)); parse(&mut stack, &lines); - execute(&mut stack, None, &String::from(input.file_name().expect("Failed to read file name.").to_str().expect("Failed to convert file name to string"))); + execute(&mut stack, None, String::from(input.file_name().expect("Failed to read file name.").to_str().expect("Failed to convert file name to string"))); } } #[derive(Debug)] struct AppArgs { input: Option, + stack_size: usize, } fn parse_args() -> Result { @@ -77,6 +79,7 @@ fn parse_args() -> Result { } let args = AppArgs { + stack_size: pargs.opt_value_from_fn("--stack-size", parse_stack_size)?.unwrap_or(256), input: pargs.opt_free_from_str()?, }; @@ -86,4 +89,15 @@ fn parse_args() -> Result { } return Ok(args); +} + +fn parse_stack_size(s: &str) -> Result { + let number = s.parse().map_err(|_| "Argument for stack size is not a number"); + + if number > Ok(u16::MAX) { + eprintln!("Stack size cannot be more than 65535"); + std::process::exit(2); + } + + Ok(number?.into()) } \ No newline at end of file diff --git a/src/stack.rs b/src/stack.rs index 7a191b3..121fce5 100644 --- a/src/stack.rs +++ b/src/stack.rs @@ -1,3 +1,7 @@ +use std::ops::Deref; + +use crate::errors::StackError; + #[derive(Clone, Debug)] pub struct Instruction { pub name: String, @@ -5,21 +9,62 @@ pub struct Instruction { pub data: u16 } -#[derive(Clone, Debug)] pub struct Stack { pub program: Vec, pub program_counter: u16, pub labels: [Option; 256], - pub memory: Vec + pub memory: StackVec } impl Stack { - pub fn new() -> Stack { + pub fn new(stack_size: usize) -> Stack { return Stack { program: Vec::new(), program_counter: 0, labels: [None; 256], - memory: Vec::new() + memory: StackVec::new(stack_size) }; } +} + +pub struct StackVec { + data: Vec, + max_size: usize +} + +impl StackVec { + fn new(max_size: usize) -> Self { + StackVec { + data: Vec::new(), + max_size, + } + } + + pub fn size(&self) -> usize { + self.max_size + } + + pub fn push(&mut self, item: u16) { + if self.data.len() + 1 > self.max_size { + panic!("{}", StackError::StackOverflow); + } else { + self.data.push(item); + } + } + + pub fn pop(&mut self) -> u16 { + self.data.pop().expect(&format!("{}", StackError::StackUnderflow)) + } + + pub fn last(&mut self) -> u16 { + *self.data.last().expect(&format!("{}", StackError::StackUnderflow)) + } +} + +impl Deref for StackVec { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.data + } } \ No newline at end of file