обновление 1.0.5

* стек теперь не бесконечный. задать можно через аргумент cli (максимум 65535, дефолт: 256)
This commit is contained in:
n3tael 2024-02-07 23:38:04 +02:00
parent 0eb3af2c47
commit 1e565164b0
Signed by: n3tael
GPG Key ID: F305925762F035A8
49 changed files with 269 additions and 189 deletions

1
.gitignore vendored
View File

@ -1,3 +1,2 @@
/target /target
/archive
/bin /bin

2
Cargo.lock generated
View File

@ -10,7 +10,7 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
[[package]] [[package]]
name = "labast" name = "labast"
version = "1.0.4" version = "1.0.5"
dependencies = [ dependencies = [
"fastrand", "fastrand",
"pico-args", "pico-args",

View File

@ -1,9 +1,9 @@
[package] [package]
name = "labast" name = "labast"
version = "1.0.4" version = "1.0.5"
authors = [ "n3tael" ] authors = [ "n3tael" ]
edition = "2021" edition = "2021"
description = "A zero-dependencies Labaski interpreter written in Rust." description = "A Labaski interpreter written in Rust."
readme = "README.md" readme = "README.md"
license = "MIT" license = "MIT"
publish = false publish = false

View File

@ -3,7 +3,9 @@ echo Building for Windows...
cargo build --release cargo build --release
echo Building for Linux... echo Building for Linux...
cargo zigbuild --release --target x86_64-unknown-linux-gnu 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\release\labast.exe bin\ /Y
copy target\x86_64-unknown-linux-gnu\release\labast 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! echo Done!

View File

@ -12,7 +12,7 @@
@ 2 @ 2
sub sub
meow dkdkd meow
quit quit
@ 3 @ 3

View File

@ -1,5 +1,19 @@
use std::fmt::Display; 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 { pub enum RunError {
RequestArgsInMainModule, RequestArgsInMainModule,
ExecuteItself(String), ExecuteItself(String),
@ -11,7 +25,6 @@ pub enum RunError {
FailToReadLineFromConsole, FailToReadLineFromConsole,
UnknownLabel(u16), UnknownLabel(u16),
InvalidExpressionUnknownOperator(String), InvalidExpressionUnknownOperator(String),
MemoryEmpty,
AttemptToInsertHashOrStringInst, AttemptToInsertHashOrStringInst,
AttemptToInsertEmptyConst, AttemptToInsertEmptyConst,
AttemptToInsertALabel AttemptToInsertALabel
@ -30,7 +43,6 @@ impl Display for RunError {
RunError::FailToReadLineFromConsole => write!(f, "Failed to read line from console"), RunError::FailToReadLineFromConsole => write!(f, "Failed to read line from console"),
RunError::UnknownLabel(label_name) => write!(f, "Unknown label: {}", label_name), RunError::UnknownLabel(label_name) => write!(f, "Unknown label: {}", label_name),
RunError::InvalidExpressionUnknownOperator(name) => write!(f, "Invalid expression: unknown operator '{}'", 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::AttemptToInsertHashOrStringInst => write!(f, "Attempt to insert a hash/string-instruction"),
RunError::AttemptToInsertEmptyConst => write!(f, "Attempt to insert an empty constant"), RunError::AttemptToInsertEmptyConst => write!(f, "Attempt to insert an empty constant"),
RunError::AttemptToInsertALabel => write!(f, "Attempt to insert a label"), RunError::AttemptToInsertALabel => write!(f, "Attempt to insert a label"),

View File

@ -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) { fn find_labels(stack: &mut Stack) {
while stack.program_counter < (stack.program.len() as u16) { 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() { if stack.labels[label.data as usize].is_some() {
eprintln!("Label {} already defined", label.data); eprintln!("Label {} already defined", label.data);
return; std::process::exit(2);
} }
if label.data == 0 { 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); 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_or(0) as u16;
stack.program_counter = stack.labels[0].unwrap() as u16;
} else {
stack.program_counter = 0;
}
} }
fn find_prefix_operators(instruction: &mut Instruction, memory: &mut Vec<u16>) { fn find_prefix_operators(instruction: &mut Instruction, memory: &mut StackVec) {
match instruction.name.chars().nth(0) { match instruction.name.chars().nth(0) {
Some('|') => { Some('|') => {
instruction.name = instruction.name.chars().skip(1).collect(); instruction.name = instruction.name.chars().skip(1).collect();
instruction.data = memory.pop();
instruction.data = memory.pop().expect(&format!("{}", RunError::MemoryEmpty));
}, },
Some('^') => { Some('^') => {
instruction.name = instruction.name.chars().skip(1).collect(); instruction.name = instruction.name.chars().skip(1).collect();
//dbg!(&instruction);
if instruction.name.chars().nth(0) != Some('#') { if instruction.name.chars().nth(0) != Some('#') {
println!("{0} {1}", instruction.name, instruction.data.to_string()); println!("{0} {1}", instruction.name, instruction.data.to_string());
} else if instruction.arg.is_empty() { } else if instruction.arg.is_empty() {
@ -51,7 +46,7 @@ fn find_prefix_operators(instruction: &mut Instruction, memory: &mut Vec<u16>) {
} }
} }
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); find_labels(stack);
while let Some(mut instruction) = stack.program.get_mut(stack.program_counter as usize) { 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() { match instruction.name.as_str() {
// Stack operations // 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), "pop" => instructions::pop::pop(&mut stack.memory),
"dup" => instructions::dup::dup(&mut stack.memory), "dup" => instructions::dup::dup(&mut stack.memory),
"swap" => instructions::swap::swap(&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 // Math
"add" => instructions::add::add(&mut stack.memory), "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), "bnot" => instructions::not::not(&mut stack.memory),
// Labels // Labels
"jmp" => instructions::jmp::jmp(&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), "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), "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), "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), "kjz" => instructions::kjz::kjz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, instruction.data),
// Input/Output // Input/Output
"putc" => instructions::putc::putc(&mut stack.memory), "putc" => instructions::putc::putc(&mut stack.memory),
"getc" => instructions::getc::getc(&mut stack.memory), "getc" => instructions::getc::getc(&mut stack.memory),
"scan" => instructions::scan::scan(&mut stack.memory), "scan" => instructions::scan::scan(&mut stack.memory),
"meow" => instructions::meow::meow(&mut stack.memory), "meow" => instructions::meow::meow(&mut stack.memory),
"#print" => instructions::print::print(&instruction.arg), "#print" => instructions::print::print(instruction.arg.clone()),
"$print" => instructions::print::print(&instruction.arg), "$print" => instructions::print::print(instruction.arg.clone()),
"#println" => instructions::println::println(&instruction.arg), "#println" => instructions::println::println(instruction.arg.clone()),
"$println" => instructions::println::println(&instruction.arg), "$println" => instructions::println::println(instruction.arg.clone()),
// Modules // 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" => { "#exec" => {
let arg = instruction.arg.clone(); let arg = instruction.arg.clone();
instructions::exec::exec(stack, &arg, &mod_name); instructions::exec::exec(stack, arg, mod_name.clone())
} },
// Self-modifying // Self-modifying
"#insert" => { "#insert" => {
let arg = instruction.arg.clone(); let arg = instruction.arg.clone();
let data = instruction.data.clone(); let data = instruction.data.clone();
instructions::insert::insert(&mut stack.program, arg, data)
instructions::insert::insert(&mut stack.program, &arg, &data)
}, },
// Special // Special
"dump" => instructions::dump::dump(&mut stack.memory), "dump" => instructions::dump::dump(&mut stack.memory),
"size" => instructions::size::size(&mut stack.memory), "size" => instructions::size::size(&mut stack.memory),
"maxsize" => instructions::maxsize::maxsize(&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, "nop" => continue,
"quit" => break, "quit" => break,
"exit" => instructions::exit::exit(&instruction.data), "exit" => instructions::exit::exit(instruction.data),
// Platform-specific // Platform-specific
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]

View File

@ -1,14 +1,14 @@
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use crate::RunError; use crate::stack::StackVec;
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
pub fn _unix_random(memory: &mut Vec<u16>) { pub fn _unix_random(memory: &mut StackVec) {
let mut rng = File::open("/dev/urandom").unwrap(); let mut rng = File::open("/dev/urandom").unwrap();
let mut buffer = [0u8; 2]; let mut buffer = [0u8; 2];
rng.read_exact(&mut buffer).unwrap(); rng.read_exact(&mut buffer).unwrap();
let data = &memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let data = memory.pop();
memory.push((u16::from_ne_bytes(buffer)) % (*data - 1)); memory.push((u16::from_ne_bytes(buffer)) % (data - 1));
} }

View File

@ -1,8 +1,8 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn add(memory: &mut Vec<u16>) { pub fn add(memory: &mut StackVec) {
let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let a: u16 = memory.pop();
let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let b: u16 = memory.pop();
memory.push(a + b); memory.push(a + b);
} }

View File

@ -1,8 +1,8 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn and(memory: &mut Vec<u16>) { pub fn and(memory: &mut StackVec) {
let a: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; let a: bool = memory.pop() == 1;
let b: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; let b: bool = memory.pop() == 1;
let c: u16 = if a && b { let c: u16 = if a && b {
1 1

View File

@ -1,15 +1,15 @@
use crate::{errors::RunError, stack::Stack}; use crate::{errors::RunError, stack::{Stack, StackVec}};
pub fn args(memory: &mut Vec<u16>, 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() { if let Some(origin_stack) = origin_stack.as_mut() {
let mut data = *data; let mut data = data;
if data == 0 { if data == 0 {
data = origin_stack.memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); data = origin_stack.memory.pop();
} }
for _ in 0..data { for _ in 0..data {
memory.push(origin_stack.memory.pop().expect(&format!("{}", RunError::MemoryEmpty))); memory.push(origin_stack.memory.pop());
} }
} else { } else {
eprintln!("{}", RunError::RequestArgsInMainModule); eprintln!("{}", RunError::RequestArgsInMainModule);

View File

@ -1,8 +1,8 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn band(memory: &mut Vec<u16>) { pub fn band(memory: &mut StackVec) {
let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let a: u16 = memory.pop();
let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let b: u16 = memory.pop();
memory.push(a & b); memory.push(a & b);
} }

View File

@ -1,8 +1,8 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn bnand(memory: &mut Vec<u16>) { pub fn bnand(memory: &mut StackVec) {
let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let a: u16 = memory.pop();
let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let b: u16 = memory.pop();
memory.push(!(a & b)); memory.push(!(a & b));
} }

View File

@ -1,8 +1,8 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn bor(memory: &mut Vec<u16>) { pub fn bor(memory: &mut StackVec) {
let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let a: u16 = memory.pop();
let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let b: u16 = memory.pop();
memory.push(a | b); memory.push(a | b);
} }

View File

@ -1,8 +1,8 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn bxor(memory: &mut Vec<u16>) { pub fn bxor(memory: &mut StackVec) {
let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let a: u16 = memory.pop();
let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let b: u16 = memory.pop();
memory.push(a ^ b); memory.push(a ^ b);
} }

View File

@ -1,8 +1,8 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn div(memory: &mut Vec<u16>) { pub fn div(memory: &mut StackVec) {
let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let a: u16 = memory.pop();
let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let b: u16 = memory.pop();
memory.push(b / a); memory.push(b / a);
} }

View File

@ -1,4 +1,6 @@
pub fn dump(memory: &mut Vec<u16>) { use crate::stack::StackVec;
pub fn dump(memory: &mut StackVec) {
if memory.is_empty() { if memory.is_empty() {
println!("Stack is empty."); println!("Stack is empty.");
return; return;

View File

@ -1,5 +1,6 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn dup(memory: &mut Vec<u16>) { pub fn dup(memory: &mut StackVec) {
memory.push(*memory.last().expect(&format!("{}", RunError::MemoryEmpty))); let data = memory.last();
memory.push(data);
} }

View File

@ -1,19 +1,19 @@
use std::fs; use std::fs;
use crate::{parse, execute, Stack, errors::RunError}; 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 { if mod_name == arg {
eprintln!("{}", RunError::ExecuteItself(arg.to_string())); eprintln!("{}", RunError::ExecuteItself(arg.to_string()));
std::process::exit(2); std::process::exit(2);
} }
let lines = fs::read_to_string(&arg).expect(&format!("{}", RunError::FailToReadFile)); 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); 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 { for item in temp_stack.memory.iter() {
stack.memory.push(item); stack.memory.push(*item);
} }
} }

View File

@ -1,3 +1,3 @@
pub fn exit(data: &u16) { pub fn exit(data: u16) {
std::process::exit((*data).into()); std::process::exit(data as i32);
} }

View File

@ -1,24 +1,27 @@
use crate::errors::RunError; use crate::{errors::RunError, stack::StackVec};
pub fn expr(memory: &mut Vec<u16>, arg: &String) { pub fn expr(memory: &mut StackVec, arg: String) {
for code in arg.chars() { for code in arg.chars() {
match code { match code {
'>' => memory.push(0), '>' => memory.push(0),
'$' => { memory.pop(); }, '$' => { 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 ax = memory.pop();
let ax2 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let ax2 = memory.pop();
memory.push(ax); memory.push(ax);
memory.push(ax2); memory.push(ax2);
} }
'+' => { '+' => {
let ax = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let ax = memory.pop();
memory.push(ax + 1); memory.push(ax + 1);
} }
'-' => { '-' => {
let ax = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let ax = memory.pop();
memory.push(ax - 1); memory.push(ax - 1);
} }

View File

@ -1,7 +1,7 @@
use std::io::Read; use std::io::Read;
use crate::errors::RunError; use crate::{errors::RunError, stack::StackVec};
pub fn getc(memory: &mut Vec<u16>) { pub fn getc(memory: &mut StackVec) {
let char = std::io::stdin() let char = std::io::stdin()
.bytes() .bytes()
.next() .next()

View File

@ -1,6 +1,6 @@
use crate::{errors::RunError, stack::Instruction}; use crate::{errors::RunError, stack::Instruction};
pub fn insert(program: &mut Vec<Instruction>, arg: &String, data: &u16) { pub fn insert(program: &mut Vec<Instruction>, arg: String, data: u16) {
let args: Vec<char> = arg.chars().collect(); let args: Vec<char> = arg.chars().collect();
if args[0] == '#' || args[0] == '$' { if args[0] == '#' || args[0] == '$' {
@ -21,6 +21,6 @@ pub fn insert(program: &mut Vec<Instruction>, arg: &String, data: &u16) {
program.push(Instruction { program.push(Instruction {
name: arg.to_string(), name: arg.to_string(),
arg: "\n".to_string(), arg: "\n".to_string(),
data: *data data
}); });
} }

View File

@ -1,10 +1,10 @@
use crate::errors::RunError; use crate::errors::RunError;
pub fn jmp(labels: &mut [Option<i16>; 256], program_counter: &mut u16, data: &u16) { pub fn jmp(labels: &mut [Option<i16>; 256], program_counter: &mut u16, data: u16) {
if labels[*data as usize].is_none() { if labels[data as usize].is_none() {
eprintln!("{}", RunError::UnknownLabel(*data)); eprintln!("{}", RunError::UnknownLabel(data));
std::process::exit(2); std::process::exit(2);
} }
*program_counter = (labels[*data as usize].unwrap() - 1) as u16; *program_counter = (labels[data as usize].unwrap() - 1) as u16;
} }

View File

@ -1,12 +1,12 @@
use crate::errors::RunError; use crate::{errors::RunError, stack::StackVec};
pub fn jnz(memory: &mut Vec<u16>, labels: &mut [Option<i16>; 256], program_counter: &mut u16, data: &u16) { pub fn jnz(memory: &mut StackVec, labels: &mut [Option<i16>; 256], program_counter: &mut u16, data: u16) {
if labels[*data as usize].is_none() { if labels[data as usize].is_none() {
eprintln!("{}", RunError::UnknownLabel(*data)); eprintln!("{}", RunError::UnknownLabel(data));
std::process::exit(2); std::process::exit(2);
} }
if memory.pop() != Some(0) { if memory.pop() != 0 {
*program_counter = (labels[*data as usize].unwrap() - 1) as u16; *program_counter = (labels[data as usize].unwrap() - 1) as u16;
} }
} }

View File

@ -1,12 +1,12 @@
use crate::errors::RunError; use crate::{errors::RunError, stack::StackVec};
pub fn jz(memory: &mut Vec<u16>, labels: &mut [Option<i16>; 256], program_counter: &mut u16, data: &u16) { pub fn jz(memory: &mut StackVec, labels: &mut [Option<i16>; 256], program_counter: &mut u16, data: u16) {
if labels[*data as usize].is_none() { if labels[data as usize].is_none() {
eprintln!("{}", RunError::UnknownLabel(*data)); eprintln!("{}", RunError::UnknownLabel(data));
std::process::exit(2); std::process::exit(2);
} }
if memory.pop() == Some(0) { if memory.pop() == 0 {
*program_counter = (labels[*data as usize].unwrap() - 1) as u16; *program_counter = (labels[data as usize].unwrap() - 1) as u16;
} }
} }

View File

@ -1,12 +1,12 @@
use crate::errors::RunError; use crate::{errors::RunError, stack::StackVec};
pub fn kjnz(memory: &mut Vec<u16>, labels: &mut [Option<i16>; 256], program_counter: &mut u16, data: &u16) { pub fn kjnz(memory: &mut StackVec, labels: &mut [Option<i16>; 256], program_counter: &mut u16, data: u16) {
if labels[*data as usize].is_none() { if labels[data as usize].is_none() {
eprintln!("{}", RunError::UnknownLabel(*data)); eprintln!("{}", RunError::UnknownLabel(data));
std::process::exit(2); std::process::exit(2);
} }
if memory.last() != Some(&0) { if memory.last() != 0 {
*program_counter = (labels[*data as usize].unwrap() - 1) as u16; *program_counter = (labels[data as usize].unwrap() - 1) as u16;
} }
} }

View File

@ -1,12 +1,12 @@
use crate::errors::RunError; use crate::{errors::RunError, stack::StackVec};
pub fn kjz(memory: &mut Vec<u16>, labels: &mut [Option<i16>; 256], program_counter: &mut u16, data: &u16) { pub fn kjz(memory: &mut StackVec, labels: &mut [Option<i16>; 256], program_counter: &mut u16, data: u16) {
if labels[*data as usize].is_none() { if labels[data as usize].is_none() {
eprintln!("{}", RunError::UnknownLabel(*data)); eprintln!("{}", RunError::UnknownLabel(data));
std::process::exit(2); std::process::exit(2);
} }
if memory.last() == Some(&0) { if memory.last() == 0 {
*program_counter = (labels[*data as usize].unwrap() - 1) as u16; *program_counter = (labels[data as usize].unwrap() - 1) as u16;
} }
} }

View File

@ -1,3 +1,5 @@
pub fn maxsize(memory: &mut Vec<u16>) { use crate::stack::StackVec;
memory.push(u16::MAX);
pub fn maxsize(memory: &mut StackVec) {
memory.push(memory.size() as u16);
} }

View File

@ -1,5 +1,5 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn meow(memory: &mut Vec<u16>) { pub fn meow(memory: &mut StackVec) {
println!("{}", memory.pop().expect(&format!("{}", RunError::MemoryEmpty))); println!("{}", memory.pop());
} }

View File

@ -1,8 +1,8 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn modulo(memory: &mut Vec<u16>) { pub fn modulo(memory: &mut StackVec) {
let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let a: u16 = memory.pop();
let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let b: u16 = memory.pop();
memory.push(b % a); memory.push(b % a);
} }

View File

@ -1,8 +1,8 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn mul(memory: &mut Vec<u16>) { pub fn mul(memory: &mut StackVec) {
let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let a: u16 = memory.pop();
let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let b: u16 = memory.pop();
memory.push(b * a); memory.push(b * a);
} }

View File

@ -1,8 +1,8 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn nand(memory: &mut Vec<u16>) { pub fn nand(memory: &mut StackVec) {
let a: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; let a: bool = memory.pop() == 1;
let b: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; let b: bool = memory.pop() == 1;
let c: u16 = if !(a && b) { let c: u16 = if !(a && b) {
1 1

View File

@ -1,7 +1,7 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn not(memory: &mut Vec<u16>) { pub fn not(memory: &mut StackVec) {
let a: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; let a: bool = memory.pop() == 1;
let c: u16 = if !a { let c: u16 = if !a {
1 1

View File

@ -1,8 +1,8 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn or(memory: &mut Vec<u16>) { pub fn or(memory: &mut StackVec) {
let a: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; let a: bool = memory.pop() == 1;
let b: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; let b: bool = memory.pop() == 1;
let c: u16 = if a || b { let c: u16 = if a || b {
1 1

View File

@ -1,11 +1,11 @@
use crate::errors::RunError; use crate::{errors::RunError, stack::StackVec};
pub fn pick(memory: &mut Vec<u16>, data: &u16) { pub fn pick(memory: &mut StackVec, data: u16) {
if *data > memory.len() as u16 { if data > memory.len() as u16 {
eprintln!("{}", RunError::PickTooDeep); eprintln!("{}", RunError::PickTooDeep);
std::process::exit(2); 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))); memory.push(*memory.get(memory.len() - (arg as usize) - 1).expect(&format!("{}", RunError::PickOutOfBounds)));
} }

View File

@ -1,3 +1,5 @@
pub fn pop(memory: &mut Vec<u16>) { use crate::stack::StackVec;
pub fn pop(memory: &mut StackVec) {
memory.pop(); memory.pop();
} }

View File

@ -1,3 +1,3 @@
pub fn print(arg: &String) { pub fn print(arg: String) {
print!("{}", arg); print!("{}", arg);
} }

View File

@ -1,3 +1,3 @@
pub fn println(arg: &String) { pub fn println(arg: String) {
println!("{}", arg); println!("{}", arg);
} }

View File

@ -1,3 +1,5 @@
pub fn push(memory: &mut Vec<u16>, data: &u16) { use crate::stack::StackVec;
memory.push(*data);
pub fn push(memory: &mut StackVec, data: u16) {
memory.push(data);
} }

View File

@ -1,5 +1,5 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn putc(memory: &mut Vec<u16>) { pub fn putc(memory: &mut StackVec) {
print!("{}", memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) as u8 as char); print!("{}", memory.pop() as u8 as char);
} }

View File

@ -1,7 +1,7 @@
use fastrand; use fastrand;
use crate::RunError; use crate::stack::StackVec;
pub fn random(memory: &mut Vec<u16>) { pub fn random(memory: &mut StackVec) {
let data = &memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let data = memory.pop();
memory.push(fastrand::u16(..) % (*data - 1)); memory.push(fastrand::u16(..) % (data - 1));
} }

View File

@ -1,6 +1,6 @@
use crate::errors::RunError; use crate::{errors::RunError, stack::StackVec};
pub fn scan(memory: &mut Vec<u16>) { pub fn scan(memory: &mut StackVec) {
let mut input = String::new(); let mut input = String::new();
std::io::stdin().read_line(&mut input).expect(&format!("{}", RunError::FailToReadLineFromConsole)); std::io::stdin().read_line(&mut input).expect(&format!("{}", RunError::FailToReadLineFromConsole));

View File

@ -1,3 +1,5 @@
pub fn size(memory: &mut Vec<u16>) { use crate::stack::StackVec;
pub fn size(memory: &mut StackVec) {
memory.push(memory.len() as u16); memory.push(memory.len() as u16);
} }

View File

@ -1,8 +1,8 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn sub(memory: &mut Vec<u16>) { pub fn sub(memory: &mut StackVec) {
let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let a: u16 = memory.pop();
let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let b: u16 = memory.pop();
memory.push(b - a); memory.push(b - a);
} }

View File

@ -1,8 +1,8 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn swap(memory: &mut Vec<u16>) { pub fn swap(memory: &mut StackVec) {
let a: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let a: u16 = memory.pop();
let b: u16 = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)); let b: u16 = memory.pop();
memory.push(a); memory.push(a);
memory.push(b); memory.push(b);

View File

@ -1,8 +1,8 @@
use crate::errors::RunError; use crate::stack::StackVec;
pub fn xor(memory: &mut Vec<u16>) { pub fn xor(memory: &mut StackVec) {
let a: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; let a: bool = memory.pop() == 1;
let b: bool = memory.pop().expect(&format!("{}", RunError::MemoryEmpty)) == 1; let b: bool = memory.pop() == 1;
let c: u16 = if !a != !b { let c: u16 = if !a != !b {
1 1

View File

@ -17,6 +17,7 @@ labast - Labaski interpreter written in Rust.
usage: labast [options] [ file.lb ] usage: labast [options] [ file.lb ]
options: options:
--stack-size sets stack max size (default: 256)
-h, --help prints help information -h, --help prints help information
-v, --version prints version -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() { if args.input.is_none() {
let mut line = String::new(); let mut line = String::new();
@ -46,21 +47,22 @@ fn main() {
stdin.lock().read_line(&mut line).unwrap(); stdin.lock().read_line(&mut line).unwrap();
parse(&mut stack, &line.trim()); parse(&mut stack, line.trim());
execute(&mut stack, None, &"inline".to_string()); execute(&mut stack, None, "inline".to_string());
} }
} else { } else {
let input = &args.input.expect("error: no input file"); let input = &args.input.expect("error: no input file");
let lines = fs::read_to_string(&input).expect(&format!("{}", RunError::FailToReadFile)); let lines = fs::read_to_string(&input).expect(&format!("{}", RunError::FailToReadFile));
parse(&mut stack, &lines); 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)] #[derive(Debug)]
struct AppArgs { struct AppArgs {
input: Option<std::path::PathBuf>, input: Option<std::path::PathBuf>,
stack_size: usize,
} }
fn parse_args() -> Result<AppArgs, pico_args::Error> { fn parse_args() -> Result<AppArgs, pico_args::Error> {
@ -77,6 +79,7 @@ fn parse_args() -> Result<AppArgs, pico_args::Error> {
} }
let args = AppArgs { let args = AppArgs {
stack_size: pargs.opt_value_from_fn("--stack-size", parse_stack_size)?.unwrap_or(256),
input: pargs.opt_free_from_str()?, input: pargs.opt_free_from_str()?,
}; };
@ -87,3 +90,14 @@ fn parse_args() -> Result<AppArgs, pico_args::Error> {
return Ok(args); return Ok(args);
} }
fn parse_stack_size(s: &str) -> Result<usize, &'static str> {
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())
}

View File

@ -1,3 +1,7 @@
use std::ops::Deref;
use crate::errors::StackError;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Instruction { pub struct Instruction {
pub name: String, pub name: String,
@ -5,21 +9,62 @@ pub struct Instruction {
pub data: u16 pub data: u16
} }
#[derive(Clone, Debug)]
pub struct Stack { pub struct Stack {
pub program: Vec<Instruction>, pub program: Vec<Instruction>,
pub program_counter: u16, pub program_counter: u16,
pub labels: [Option<i16>; 256], pub labels: [Option<i16>; 256],
pub memory: Vec<u16> pub memory: StackVec
} }
impl Stack { impl Stack {
pub fn new() -> Stack { pub fn new(stack_size: usize) -> Stack {
return Stack { return Stack {
program: Vec::new(), program: Vec::new(),
program_counter: 0, program_counter: 0,
labels: [None; 256], labels: [None; 256],
memory: Vec::new() memory: StackVec::new(stack_size)
}; };
} }
} }
pub struct StackVec {
data: Vec<u16>,
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<u16>;
fn deref(&self) -> &Self::Target {
&self.data
}
}