изменен стиль кода, изменено расположение инструкций

This commit is contained in:
n3tael 2024-02-13 12:33:31 +02:00
parent 061238db49
commit 48b53dc991
Signed by: n3tael
GPG Key ID: F305925762F035A8
54 changed files with 524 additions and 484 deletions

View File

@ -27,23 +27,34 @@ pub enum RunError {
InvalidExpressionUnknownOperator(String),
AttemptToInsertHashOrStringInst,
AttemptToInsertEmptyConst,
AttemptToInsertALabel
AttemptToInsertALabel,
}
impl Display for RunError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RunError::RequestArgsInMainModule => write!(f, "Can't require arguments in the main module"),
RunError::ExecuteItself(mod_name) => write!(f, "Module {}: Can't execute itself", mod_name),
RunError::RequestArgsInMainModule => {
write!(f, "Can't require arguments in the main module")
}
RunError::ExecuteItself(mod_name) => {
write!(f, "Module {}: Can't execute itself", mod_name)
}
RunError::FailToReadFile => write!(f, "Unable to read file"),
RunError::FailToGetCharFromConsole => write!(f, "Failed to get character from console"),
RunError::InvalidInputUShortInt => write!(f, "Invalid input. Please enter a valid unsigned short integer"),
RunError::InvalidInputUShortInt => write!(
f,
"Invalid input. Please enter a valid unsigned short integer"
),
RunError::PickTooDeep => write!(f, "Picking too deep"),
RunError::PickOutOfBounds => write!(f, "Trying to get a value out of bounds"),
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::AttemptToInsertHashOrStringInst => write!(f, "Attempt to insert a hash/string-instruction"),
RunError::InvalidExpressionUnknownOperator(name) => {
write!(f, "Invalid expression: unknown operator '{}'", name)
}
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"),
}
@ -51,13 +62,17 @@ impl Display for RunError {
}
pub enum ParseError {
ArgumentNotRequired(String, usize, String)
ArgumentNotRequired(String, usize, String),
}
impl Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ParseError::ArgumentNotRequired(name, line_number, line) => write!(f, "ParseError:\n{1} | {2}\nerror: string argument for {0} not required", name, line_number, line),
ParseError::ArgumentNotRequired(name, line_number, line) => write!(
f,
"ParseError:\n{1} | {2}\nerror: string argument for {0} not required",
name, line_number, line
),
}
}
}
}

View File

@ -1,10 +1,13 @@
use crate::{instructions, stack::{Instruction, Stack, StackVec}};
use crate::{
instructions,
stack::{Instruction, Stack, StackVec},
};
fn find_labels(stack: &mut Stack) {
while stack.program_counter < (stack.program.len() as u16) {
let label = &stack.program[stack.program_counter as usize];
stack.program_counter += 1;
if !label.name.starts_with('@') {
continue;
}
@ -30,7 +33,7 @@ fn find_prefix_operators(instruction: &mut Instruction, memory: &mut StackVec) {
Some('|') => {
instruction.name = instruction.name.chars().skip(1).collect();
instruction.data = memory.pop();
},
}
Some('^') => {
instruction.name = instruction.name.chars().skip(1).collect();
@ -60,84 +63,113 @@ 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),
"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),
"push" => instructions::stack_manage::push(&mut stack.memory, instruction.data),
"pop" => instructions::stack_manage::pop(&mut stack.memory),
"dup" => instructions::stack_manage::dup(&mut stack.memory),
"swap" => instructions::stack_manage::swap(&mut stack.memory),
"pick" => instructions::stack_manage::pick(&mut stack.memory, instruction.data),
// Math
"add" => instructions::add::add(&mut stack.memory),
"sub" => instructions::sub::sub(&mut stack.memory),
"mul" => instructions::mul::mul(&mut stack.memory),
"div" => instructions::div::div(&mut stack.memory),
"mod" => instructions::modulo::modulo(&mut stack.memory),
// Math operations
"add" => instructions::math::add(&mut stack.memory),
"sub" => instructions::math::sub(&mut stack.memory),
"mul" => instructions::math::mul(&mut stack.memory),
"div" => instructions::math::div(&mut stack.memory),
"mod" => instructions::math::modulo(&mut stack.memory),
// Logic
"and" => instructions::and::and(&mut stack.memory),
"or" => instructions::or::or(&mut stack.memory),
"xor" => instructions::xor::xor(&mut stack.memory),
"nand" => instructions::nand::nand(&mut stack.memory),
"not" => instructions::not::not(&mut stack.memory),
"and" => instructions::logic::and(&mut stack.memory),
"or" => instructions::logic::or(&mut stack.memory),
"xor" => instructions::logic::xor(&mut stack.memory),
"nand" => instructions::logic::nand(&mut stack.memory),
"not" => instructions::logic::not(&mut stack.memory),
// Bitwise
"band" => instructions::band::band(&mut stack.memory),
"bor" => instructions::bor::bor(&mut stack.memory),
"bxor" => instructions::bxor::bxor(&mut stack.memory),
"bnand" => instructions::bnand::bnand(&mut stack.memory),
"bnot" => instructions::not::not(&mut stack.memory),
"band" => instructions::bitwise::band(&mut stack.memory),
"bor" => instructions::bitwise::bor(&mut stack.memory),
"bxor" => instructions::bitwise::bxor(&mut stack.memory),
"bnand" => instructions::bitwise::bnand(&mut stack.memory),
"bnot" => instructions::logic::not(&mut stack.memory),
// Labels
"jmp" => instructions::jmp::jmp(&mut stack.labels, &mut stack.program_counter, instruction.data),
"rjmp" => instructions::rjmp::rjmp(&mut stack.memory, &mut stack.labels, &mut stack.program_counter),
"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),
// Flow-control
"jmp" => instructions::flow_control::jmp(
&mut stack.labels,
&mut stack.program_counter,
instruction.data,
),
"rjmp" => instructions::specific::rjmp(
&mut stack.memory,
&mut stack.labels,
&mut stack.program_counter,
),
"jnz" => instructions::flow_control::jnz(
&mut stack.memory,
&mut stack.labels,
&mut stack.program_counter,
instruction.data,
),
"jz" => instructions::flow_control::jz(
&mut stack.memory,
&mut stack.labels,
&mut stack.program_counter,
instruction.data,
),
"kjnz" => instructions::flow_control::kjnz(
&mut stack.memory,
&mut stack.labels,
&mut stack.program_counter,
instruction.data,
),
"kjz" => instructions::flow_control::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.clone()),
"$print" => instructions::print::print(instruction.arg.clone()),
"#println" => instructions::println::println(instruction.arg.clone()),
"$println" => instructions::println::println(instruction.arg.clone()),
"putc" => instructions::io::putc(&mut stack.memory),
"getc" => instructions::io::getc(&mut stack.memory),
"scan" => instructions::io::scan(&mut stack.memory),
"meow" => instructions::io::meow(&mut stack.memory),
"#print" => instructions::io::print(instruction.arg.clone()),
"$print" => instructions::io::print(instruction.arg.clone()),
"#println" => instructions::io::println(instruction.arg.clone()),
"$println" => instructions::io::println(instruction.arg.clone()),
// Modules
"args" => instructions::args::args(&mut stack.memory, &mut origin_stack, instruction.data),
"args" => {
instructions::modules::args(&mut stack.memory, &mut origin_stack, instruction.data)
}
"#exec" => {
let arg = instruction.arg.clone();
instructions::exec::exec(stack, arg, mod_name.clone())
},
instructions::modules::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::self_modify::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.clone()),
"nop" => continue,
"quit" => break,
"exit" => instructions::exit::exit(instruction.data),
"dump" => instructions::special::dump(&mut stack.memory),
"size" => instructions::special::size(&mut stack.memory),
"maxsize" => instructions::special::maxsize(&mut stack.memory),
"#expr" => instructions::special::expr(&mut stack.memory, instruction.arg.clone()),
"nop" => continue,
"quit" => break,
"exit" => instructions::special::exit(instruction.data),
// Platform-specific
#[cfg(target_family = "unix")]
"_unix_random" => instructions::_unix_random::_unix_random(&mut stack.memory),
#[cfg(target_family = "unix")]
"_unix_random" => instructions::platform_specific::_unix_random(&mut stack.memory),
#[cfg(not(target_family = "unix"))]
"_unix_random" => instructions::random::random(&mut stack.memory),
#[cfg(not(target_family = "unix"))]
"_unix_random" => instructions::specific::random(&mut stack.memory),
// Labast-specific
"random" => instructions::random::random(&mut stack.memory),
"random" => instructions::specific::random(&mut stack.memory),
_ => {
eprintln!("Unknown instruction: {}", instruction.name);

View File

@ -1,8 +0,0 @@
use crate::stack::StackVec;
pub fn add(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(a + b);
}

View File

@ -1,14 +0,0 @@
use crate::stack::StackVec;
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
} else {
0
};
memory.push(c);
}

View File

@ -1,18 +0,0 @@
use crate::{errors::RunError, stack::{Stack, StackVec}};
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;
if data == 0 {
data = origin_stack.memory.pop();
}
for _ in 0..data {
memory.push(origin_stack.memory.pop());
}
} else {
eprintln!("{}", RunError::RequestArgsInMainModule);
std::process::exit(2);
}
}

View File

@ -1,8 +0,0 @@
use crate::stack::StackVec;
pub fn band(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(a & b);
}

View File

@ -0,0 +1,29 @@
use crate::stack::StackVec;
pub fn band(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(a & b);
}
pub fn bor(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(a | b);
}
pub fn bxor(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(a ^ b);
}
pub fn bnand(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(!(a & b));
}

View File

@ -1,8 +0,0 @@
use crate::stack::StackVec;
pub fn bnand(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(!(a & b));
}

View File

@ -1,8 +0,0 @@
use crate::stack::StackVec;
pub fn bor(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(a | b);
}

View File

@ -1,8 +0,0 @@
use crate::stack::StackVec;
pub fn bxor(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(a ^ b);
}

View File

@ -1,8 +0,0 @@
use crate::stack::StackVec;
pub fn div(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(b / a);
}

View File

@ -1,12 +0,0 @@
use crate::stack::StackVec;
pub fn dump(memory: &mut StackVec) {
if memory.is_empty() {
println!("Stack is empty.");
return;
}
for (i, entry) in memory.iter().enumerate() {
println!("{0}: {1}", i, entry);
}
}

View File

@ -1,6 +0,0 @@
use crate::stack::StackVec;
pub fn dup(memory: &mut StackVec) {
let data = memory.last();
memory.push(data);
}

View File

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

View File

@ -0,0 +1,74 @@
use crate::{errors::RunError, stack::StackVec};
pub fn jmp(labels: &mut [Option<i16>; 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;
}
pub fn jnz(
memory: &mut StackVec,
labels: &mut [Option<i16>; 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() != 0 {
*program_counter = (labels[data as usize].unwrap() - 1) as 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() {
eprintln!("{}", RunError::UnknownLabel(data));
std::process::exit(2);
}
if memory.pop() == 0 {
*program_counter = (labels[data as usize].unwrap() - 1) as 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() {
eprintln!("{}", RunError::UnknownLabel(data));
std::process::exit(2);
}
if memory.last() != 0 {
*program_counter = (labels[data as usize].unwrap() - 1) as 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() {
eprintln!("{}", RunError::UnknownLabel(data));
std::process::exit(2);
}
if memory.last() == 0 {
*program_counter = (labels[data as usize].unwrap() - 1) as u16;
}
}

View File

@ -1,13 +0,0 @@
use std::io::Read;
use crate::{errors::RunError, stack::StackVec};
pub fn getc(memory: &mut StackVec) {
let char = std::io::stdin()
.bytes()
.next()
.and_then(|result| result.ok())
.map(|byte| byte as u16)
.expect(&format!("{}", RunError::FailToGetCharFromConsole));
memory.push(char);
}

43
src/instructions/io.rs Normal file
View File

@ -0,0 +1,43 @@
use crate::{errors::RunError, stack::StackVec};
use std::io::Read;
pub fn putc(memory: &mut StackVec) {
print!("{}", memory.pop() as u8 as char);
}
pub fn getc(memory: &mut StackVec) {
let char = std::io::stdin()
.bytes()
.next()
.and_then(|result| result.ok())
.map(|byte| byte as u16)
.expect(&format!("{}", RunError::FailToGetCharFromConsole));
memory.push(char);
}
pub fn scan(memory: &mut StackVec) {
let mut input = String::new();
std::io::stdin()
.read_line(&mut input)
.expect(&format!("{}", RunError::FailToReadLineFromConsole));
let num = input
.trim()
.parse()
.expect(&format!("{}", RunError::InvalidInputUShortInt));
memory.push(num);
}
pub fn meow(memory: &mut StackVec) {
println!("{}", memory.pop());
}
pub fn print(arg: String) {
print!("{}", arg);
}
pub fn println(arg: String) {
println!("{}", arg);
}

View File

@ -1,10 +0,0 @@
use crate::errors::RunError;
pub fn jmp(labels: &mut [Option<i16>; 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;
}

View File

@ -1,12 +0,0 @@
use crate::{errors::RunError, stack::StackVec};
pub fn jnz(memory: &mut StackVec, labels: &mut [Option<i16>; 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() != 0 {
*program_counter = (labels[data as usize].unwrap() - 1) as u16;
}
}

View File

@ -1,12 +0,0 @@
use crate::{errors::RunError, stack::StackVec};
pub fn jz(memory: &mut StackVec, labels: &mut [Option<i16>; 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() == 0 {
*program_counter = (labels[data as usize].unwrap() - 1) as u16;
}
}

View File

@ -1,12 +0,0 @@
use crate::{errors::RunError, stack::StackVec};
pub fn kjnz(memory: &mut StackVec, labels: &mut [Option<i16>; 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() != 0 {
*program_counter = (labels[data as usize].unwrap() - 1) as u16;
}
}

View File

@ -1,12 +0,0 @@
use crate::{errors::RunError, stack::StackVec};
pub fn kjz(memory: &mut StackVec, labels: &mut [Option<i16>; 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() == 0 {
*program_counter = (labels[data as usize].unwrap() - 1) as u16;
}
}

45
src/instructions/logic.rs Normal file
View File

@ -0,0 +1,45 @@
use crate::stack::StackVec;
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 } else { 0 };
memory.push(c);
}
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 } else { 0 };
memory.push(c);
}
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 } else { 0 };
memory.push(c);
}
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 } else { 0 };
memory.push(c);
}
pub fn not(memory: &mut StackVec) {
let a: bool = memory.pop() == 1;
let c: u16 = if !a { 1 } else { 0 };
memory.push(c);
}

36
src/instructions/math.rs Normal file
View File

@ -0,0 +1,36 @@
use crate::stack::StackVec;
pub fn add(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(a + b);
}
pub fn sub(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(b - a);
}
pub fn mul(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(b * a);
}
pub fn div(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(b / a);
}
pub fn modulo(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(b % a);
}

View File

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

View File

@ -1,5 +0,0 @@
use crate::stack::StackVec;
pub fn meow(memory: &mut StackVec) {
println!("{}", memory.pop());
}

View File

@ -1,42 +1,11 @@
pub mod push;
pub mod pop;
pub mod dup;
pub mod swap;
pub mod add;
pub mod sub;
pub mod mul;
pub mod div;
pub mod jmp;
pub mod jnz;
pub mod jz;
pub mod pick;
pub mod putc;
pub mod getc;
pub mod meow;
pub mod dump;
pub mod scan;
pub mod exec;
pub mod args;
pub mod expr;
pub mod size;
pub mod exit;
pub mod maxsize;
#[cfg(target_family = "unix")]
pub mod _unix_random;
pub mod modulo;
pub mod and;
pub mod or;
pub mod xor;
pub mod nand;
pub mod band;
pub mod bor;
pub mod bxor;
pub mod bnand;
pub mod not;
pub mod kjnz;
pub mod kjz;
pub mod print;
pub mod println;
pub mod insert;
pub mod random;
pub mod rjmp;
pub mod bitwise;
pub mod flow_control;
pub mod io;
pub mod logic;
pub mod math;
pub mod modules;
pub mod platform_specific;
pub mod self_modify;
pub mod special;
pub mod specific;
pub mod stack_manage;

View File

@ -1,5 +1,22 @@
use crate::{errors::RunError, execute, parse, stack::StackVec, Stack};
use std::fs;
use crate::{parse, execute, Stack, errors::RunError};
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;
if data == 0 {
data = origin_stack.memory.pop();
}
for _ in 0..data {
memory.push(origin_stack.memory.pop());
}
} else {
eprintln!("{}", RunError::RequestArgsInMainModule);
std::process::exit(2);
}
}
pub fn exec(mut stack: &mut Stack, arg: String, mod_name: String) {
if mod_name == arg {
@ -16,4 +33,4 @@ pub fn exec(mut stack: &mut Stack, arg: String, mod_name: String) {
for item in temp_stack.memory.iter() {
stack.memory.push(*item);
}
}
}

View File

@ -1,8 +0,0 @@
use crate::stack::StackVec;
pub fn modulo(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(b % a);
}

View File

@ -1,8 +0,0 @@
use crate::stack::StackVec;
pub fn mul(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(b * a);
}

View File

@ -1,14 +0,0 @@
use crate::stack::StackVec;
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
} else {
0
};
memory.push(c);
}

View File

@ -1,13 +0,0 @@
use crate::stack::StackVec;
pub fn not(memory: &mut StackVec) {
let a: bool = memory.pop() == 1;
let c: u16 = if !a {
1
} else {
0
};
memory.push(c);
}

View File

@ -1,14 +0,0 @@
use crate::stack::StackVec;
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
} else {
0
};
memory.push(c);
}

View File

@ -1,11 +0,0 @@
use crate::{errors::RunError, stack::StackVec};
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();
memory.push(*memory.get(memory.len() - (arg as usize) - 1).expect(&format!("{}", RunError::PickOutOfBounds)));
}

View File

@ -1,6 +1,9 @@
use std::fs::File;
use std::io::Read;
#[cfg(target_family = "unix")]
use crate::stack::StackVec;
#[cfg(target_family = "unix")]
use std::fs::File;
#[cfg(target_family = "unix")]
use std::io::Read;
#[cfg(target_family = "unix")]
pub fn _unix_random(memory: &mut StackVec) {
@ -11,4 +14,4 @@ pub fn _unix_random(memory: &mut StackVec) {
let data = memory.pop();
memory.push((u16::from_ne_bytes(buffer)) % (data - 1));
}
}

View File

@ -1,5 +0,0 @@
use crate::stack::StackVec;
pub fn pop(memory: &mut StackVec) {
memory.pop();
}

View File

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

View File

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

View File

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

View File

@ -1,5 +0,0 @@
use crate::stack::StackVec;
pub fn putc(memory: &mut StackVec) {
print!("{}", memory.pop() as u8 as char);
}

View File

@ -1,7 +0,0 @@
use fastrand;
use crate::stack::StackVec;
pub fn random(memory: &mut StackVec) {
let data = memory.pop();
memory.push(fastrand::u16(..) % (data - 1));
}

View File

@ -1,9 +0,0 @@
use crate::{errors::RunError, stack::StackVec};
pub fn rjmp(memory: &mut StackVec, labels: &mut [Option<i16>; 256], program_counter: &mut u16) {
let start = memory.pop() as usize;
let end = memory.pop() as usize;
let rand = fastrand::usize(start..end + 1);
*program_counter = (labels[rand].expect(&format!("{}", RunError::UnknownLabel(rand as u16))) - 1) as u16;
}

View File

@ -1,10 +0,0 @@
use crate::{errors::RunError, stack::StackVec};
pub fn scan(memory: &mut StackVec) {
let mut input = String::new();
std::io::stdin().read_line(&mut input).expect(&format!("{}", RunError::FailToReadLineFromConsole));
let num = input.trim().parse().expect(&format!("{}", RunError::InvalidInputUShortInt));
memory.push(num);
}

View File

@ -2,25 +2,25 @@ use crate::{errors::RunError, stack::Instruction};
pub fn insert(program: &mut Vec<Instruction>, arg: String, data: u16) {
let args: Vec<char> = arg.chars().collect();
if args[0] == '#' || args[0] == '$' {
eprintln!("{}", RunError::AttemptToInsertHashOrStringInst);
std::process::exit(2);
}
if args[0] == '\n' {
eprintln!("{}", RunError::AttemptToInsertEmptyConst);
std::process::exit(2);
}
if args[0] == '@' || args[1] == ' ' {
eprintln!("{}", RunError::AttemptToInsertALabel);
std::process::exit(2);
}
program.push(Instruction {
name: arg.to_string(),
arg: "\n".to_string(),
data
name: arg.to_string(),
arg: "\n".to_string(),
data,
});
}
}

View File

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

View File

@ -1,5 +1,24 @@
use crate::{errors::RunError, stack::StackVec};
pub fn dump(memory: &mut StackVec) {
if memory.is_empty() {
println!("Stack is empty.");
return;
}
for (i, entry) in memory.iter().enumerate() {
println!("{0}: {1}", i, entry);
}
}
pub fn size(memory: &mut StackVec) {
memory.push(memory.len() as u16);
}
pub fn maxsize(memory: &mut StackVec) {
memory.push(memory.size() as u16);
}
pub fn expr(memory: &mut StackVec, arg: String) {
for code in arg.chars() {
match code {
@ -12,7 +31,7 @@ pub fn expr(memory: &mut StackVec, arg: String) {
'\\' => {
let ax = memory.pop();
let ax2 = memory.pop();
memory.push(ax);
memory.push(ax2);
}
@ -31,4 +50,8 @@ pub fn expr(memory: &mut StackVec, arg: String) {
}
}
}
}
pub fn exit(data: u16) {
std::process::exit(data as i32);
}

View File

@ -0,0 +1,16 @@
use crate::{errors::RunError, stack::StackVec};
use fastrand;
pub fn random(memory: &mut StackVec) {
let data = memory.pop();
memory.push(fastrand::u16(..) % (data - 1));
}
pub fn rjmp(memory: &mut StackVec, labels: &mut [Option<i16>; 256], program_counter: &mut u16) {
let start = memory.pop() as usize;
let end = memory.pop() as usize;
let rand = fastrand::usize(start..end + 1);
*program_counter =
(labels[rand].expect(&format!("{}", RunError::UnknownLabel(rand as u16))) - 1) as u16;
}

View File

@ -0,0 +1,36 @@
use crate::{errors::RunError, stack::StackVec};
pub fn push(memory: &mut StackVec, data: u16) {
memory.push(data);
}
pub fn pop(memory: &mut StackVec) {
memory.pop();
}
pub fn dup(memory: &mut StackVec) {
let data = memory.last();
memory.push(data);
}
pub fn swap(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(a);
memory.push(b);
}
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();
memory.push(
*memory
.get(memory.len() - (arg as usize) - 1)
.expect(&format!("{}", RunError::PickOutOfBounds)),
);
}

View File

@ -1,8 +0,0 @@
use crate::stack::StackVec;
pub fn sub(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(b - a);
}

View File

@ -1,9 +0,0 @@
use crate::stack::StackVec;
pub fn swap(memory: &mut StackVec) {
let a: u16 = memory.pop();
let b: u16 = memory.pop();
memory.push(a);
memory.push(b);
}

View File

@ -1,14 +0,0 @@
use crate::stack::StackVec;
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
} else {
0
};
memory.push(c);
}

View File

@ -1,15 +1,18 @@
use std::{fs, io::{BufRead, Write}};
use std::{
fs,
io::{BufRead, Write},
};
use errors::RunError;
use execute::execute;
use parse::parse;
use stack::Stack;
mod stack;
mod parse;
mod errors;
mod execute;
mod instructions;
mod errors;
mod parse;
mod stack;
const HELP: &str = "\
labast - Labaski interpreter written in Rust.
@ -39,9 +42,9 @@ fn main() {
loop {
line.clear();
stack.program.clear();
let stdin = std::io::stdin();
print!("> ");
std::io::stdout().flush().expect("Cannot flush the buffer.");
@ -55,7 +58,17 @@ fn main() {
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"),
),
);
}
}
@ -74,12 +87,17 @@ fn parse_args() -> Result<AppArgs, pico_args::Error> {
}
if pargs.contains(["-v", "--version"]) {
println!("labast version {}", option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"));
println!(
"labast version {}",
option_env!("CARGO_PKG_VERSION").unwrap_or("unknown")
);
std::process::exit(0);
}
let args = AppArgs {
stack_size: pargs.opt_value_from_fn("--stack-size", parse_stack_size)?.unwrap_or(256),
stack_size: pargs
.opt_value_from_fn("--stack-size", parse_stack_size)?
.unwrap_or(256),
input: pargs.opt_free_from_str()?,
};
@ -92,12 +110,14 @@ fn parse_args() -> Result<AppArgs, pico_args::Error> {
}
fn parse_stack_size(s: &str) -> Result<usize, &'static str> {
let number = s.parse().map_err(|_| "Argument for stack size is not a number");
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,4 +1,7 @@
use crate::{errors::ParseError, stack::{Instruction, Stack}};
use crate::{
errors::ParseError,
stack::{Instruction, Stack},
};
pub fn parse(stack: &mut Stack, file_content: &str) {
for (i, line) in file_content.lines().enumerate() {
@ -13,26 +16,33 @@ pub fn parse(stack: &mut Stack, file_content: &str) {
inst_line = line.trim().chars().collect();
}
let command: [String; 2] = inst_line.split_once(char::is_whitespace)
.map_or_else(|| [inst_line.trim().to_string(), "".to_string()],
|(first, second)| [first.trim().to_string(), second.trim().to_string()]);
let command: [String; 2] = inst_line.split_once(char::is_whitespace).map_or_else(
|| [inst_line.trim().to_string(), "".to_string()],
|(first, second)| [first.trim().to_string(), second.trim().to_string()],
);
let name: String;
let name: String = command[0].clone();
let mut arg: String = String::new();
let mut data: u16 = 0;
name = command[0].clone();
if !command[1].is_empty() {
if name.chars().nth(0) == Some('#') || name.chars().nth(1) == Some('#') {
let splited_data: Vec<String> = command[1].split_whitespace().map(String::from).collect();
if name.chars().nth(0) == Some('#') || name.chars().nth(1) == Some('#') {
let splited_data: Vec<String> =
command[1].split_whitespace().map(String::from).collect();
arg = splited_data.get(0).unwrap().clone();
} else if name.chars().nth(0) == Some('$') || name.chars().nth(1) == Some('$') {
arg = command[1].clone();
} else if let Ok(number) = command[1].parse::<i32>() {
data = number as u16;
} else {
eprintln!("{}", ParseError::ArgumentNotRequired(command[0].to_string(), i + 1, line.to_string()));
eprintln!(
"{}",
ParseError::ArgumentNotRequired(
command[0].to_string(),
i + 1,
line.to_string()
)
);
std::process::exit(2);
}
}

View File

@ -6,14 +6,14 @@ use crate::errors::StackError;
pub struct Instruction {
pub name: String,
pub arg: String,
pub data: u16
pub data: u16,
}
pub struct Stack {
pub program: Vec<Instruction>,
pub program_counter: u16,
pub labels: [Option<i16>; 256],
pub memory: StackVec
pub memory: StackVec,
}
impl Stack {
@ -22,14 +22,14 @@ impl Stack {
program: Vec::new(),
program_counter: 0,
labels: [None; 256],
memory: StackVec::new(stack_size)
memory: StackVec::new(stack_size),
};
}
}
pub struct StackVec {
data: Vec<u16>,
max_size: usize
max_size: usize,
}
impl StackVec {
@ -53,11 +53,16 @@ impl StackVec {
}
pub fn pop(&mut self) -> u16 {
self.data.pop().expect(&format!("{}", StackError::StackUnderflow))
self.data
.pop()
.expect(&format!("{}", StackError::StackUnderflow))
}
pub fn last(&mut self) -> u16 {
*self.data.last().expect(&format!("{}", StackError::StackUnderflow))
*self
.data
.last()
.expect(&format!("{}", StackError::StackUnderflow))
}
}
@ -67,4 +72,4 @@ impl Deref for StackVec {
fn deref(&self) -> &Self::Target {
&self.data
}
}
}