diff --git a/src/errors.rs b/src/errors.rs index 5c24d11..1c99bc9 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -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 + ), } } -} \ No newline at end of file +} diff --git a/src/execute.rs b/src/execute.rs index 1f91f90..3691d44 100644 --- a/src/execute.rs +++ b/src/execute.rs @@ -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); diff --git a/src/instructions/add.rs b/src/instructions/add.rs deleted file mode 100644 index 6cd35bf..0000000 --- a/src/instructions/add.rs +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/src/instructions/and.rs b/src/instructions/and.rs deleted file mode 100644 index 5e97bb1..0000000 --- a/src/instructions/and.rs +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/src/instructions/args.rs b/src/instructions/args.rs deleted file mode 100644 index d8140e6..0000000 --- a/src/instructions/args.rs +++ /dev/null @@ -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); - } -} \ No newline at end of file diff --git a/src/instructions/band.rs b/src/instructions/band.rs deleted file mode 100644 index a128209..0000000 --- a/src/instructions/band.rs +++ /dev/null @@ -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); -} diff --git a/src/instructions/bitwise.rs b/src/instructions/bitwise.rs new file mode 100644 index 0000000..24f99d3 --- /dev/null +++ b/src/instructions/bitwise.rs @@ -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)); +} diff --git a/src/instructions/bnand.rs b/src/instructions/bnand.rs deleted file mode 100644 index ea948f3..0000000 --- a/src/instructions/bnand.rs +++ /dev/null @@ -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)); -} diff --git a/src/instructions/bor.rs b/src/instructions/bor.rs deleted file mode 100644 index 53a208c..0000000 --- a/src/instructions/bor.rs +++ /dev/null @@ -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); -} diff --git a/src/instructions/bxor.rs b/src/instructions/bxor.rs deleted file mode 100644 index c3b061e..0000000 --- a/src/instructions/bxor.rs +++ /dev/null @@ -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); -} diff --git a/src/instructions/div.rs b/src/instructions/div.rs deleted file mode 100644 index 4e1b888..0000000 --- a/src/instructions/div.rs +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/src/instructions/dump.rs b/src/instructions/dump.rs deleted file mode 100644 index 731fe45..0000000 --- a/src/instructions/dump.rs +++ /dev/null @@ -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); - } -} \ No newline at end of file diff --git a/src/instructions/dup.rs b/src/instructions/dup.rs deleted file mode 100644 index 9972e0e..0000000 --- a/src/instructions/dup.rs +++ /dev/null @@ -1,6 +0,0 @@ -use crate::stack::StackVec; - -pub fn dup(memory: &mut StackVec) { - let data = memory.last(); - memory.push(data); -} \ No newline at end of file diff --git a/src/instructions/exit.rs b/src/instructions/exit.rs deleted file mode 100644 index 5e9101a..0000000 --- a/src/instructions/exit.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub fn exit(data: u16) { - std::process::exit(data as i32); -} \ No newline at end of file diff --git a/src/instructions/flow_control.rs b/src/instructions/flow_control.rs new file mode 100644 index 0000000..ae39cb5 --- /dev/null +++ b/src/instructions/flow_control.rs @@ -0,0 +1,74 @@ +use crate::{errors::RunError, stack::StackVec}; + +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; +} + +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() != 0 { + *program_counter = (labels[data as usize].unwrap() - 1) as u16; + } +} + +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() == 0 { + *program_counter = (labels[data as usize].unwrap() - 1) as u16; + } +} + +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() != 0 { + *program_counter = (labels[data as usize].unwrap() - 1) as u16; + } +} + +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() == 0 { + *program_counter = (labels[data as usize].unwrap() - 1) as u16; + } +} diff --git a/src/instructions/getc.rs b/src/instructions/getc.rs deleted file mode 100644 index 01e071a..0000000 --- a/src/instructions/getc.rs +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/src/instructions/io.rs b/src/instructions/io.rs new file mode 100644 index 0000000..78bbcf7 --- /dev/null +++ b/src/instructions/io.rs @@ -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); +} diff --git a/src/instructions/jmp.rs b/src/instructions/jmp.rs deleted file mode 100644 index cf8a418..0000000 --- a/src/instructions/jmp.rs +++ /dev/null @@ -1,10 +0,0 @@ -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)); - std::process::exit(2); - } - - *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 deleted file mode 100644 index 59db119..0000000 --- a/src/instructions/jnz.rs +++ /dev/null @@ -1,12 +0,0 @@ -use crate::{errors::RunError, stack::StackVec}; - -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() != 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 deleted file mode 100644 index 148de65..0000000 --- a/src/instructions/jz.rs +++ /dev/null @@ -1,12 +0,0 @@ -use crate::{errors::RunError, stack::StackVec}; - -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() == 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 deleted file mode 100644 index da9cca3..0000000 --- a/src/instructions/kjnz.rs +++ /dev/null @@ -1,12 +0,0 @@ -use crate::{errors::RunError, stack::StackVec}; - -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() != 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 deleted file mode 100644 index 39deda3..0000000 --- a/src/instructions/kjz.rs +++ /dev/null @@ -1,12 +0,0 @@ -use crate::{errors::RunError, stack::StackVec}; - -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() == 0 { - *program_counter = (labels[data as usize].unwrap() - 1) as u16; - } -} \ No newline at end of file diff --git a/src/instructions/logic.rs b/src/instructions/logic.rs new file mode 100644 index 0000000..3f036d1 --- /dev/null +++ b/src/instructions/logic.rs @@ -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); +} diff --git a/src/instructions/math.rs b/src/instructions/math.rs new file mode 100644 index 0000000..1dab88c --- /dev/null +++ b/src/instructions/math.rs @@ -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); +} diff --git a/src/instructions/maxsize.rs b/src/instructions/maxsize.rs deleted file mode 100644 index ae9c57e..0000000 --- a/src/instructions/maxsize.rs +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 6ec244e..0000000 --- a/src/instructions/meow.rs +++ /dev/null @@ -1,5 +0,0 @@ -use crate::stack::StackVec; - -pub fn meow(memory: &mut StackVec) { - println!("{}", memory.pop()); -} \ No newline at end of file diff --git a/src/instructions/mod.rs b/src/instructions/mod.rs index dff22a4..a08c315 100644 --- a/src/instructions/mod.rs +++ b/src/instructions/mod.rs @@ -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; \ No newline at end of file +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; diff --git a/src/instructions/exec.rs b/src/instructions/modules.rs similarity index 50% rename from src/instructions/exec.rs rename to src/instructions/modules.rs index d78f2ff..e869135 100644 --- a/src/instructions/exec.rs +++ b/src/instructions/modules.rs @@ -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); } -} \ No newline at end of file +} diff --git a/src/instructions/modulo.rs b/src/instructions/modulo.rs deleted file mode 100644 index da26082..0000000 --- a/src/instructions/modulo.rs +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/src/instructions/mul.rs b/src/instructions/mul.rs deleted file mode 100644 index 6263c22..0000000 --- a/src/instructions/mul.rs +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/src/instructions/nand.rs b/src/instructions/nand.rs deleted file mode 100644 index bf7e6ab..0000000 --- a/src/instructions/nand.rs +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/src/instructions/not.rs b/src/instructions/not.rs deleted file mode 100644 index 05e6bf9..0000000 --- a/src/instructions/not.rs +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/src/instructions/or.rs b/src/instructions/or.rs deleted file mode 100644 index 01d53a5..0000000 --- a/src/instructions/or.rs +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/src/instructions/pick.rs b/src/instructions/pick.rs deleted file mode 100644 index 0e9e297..0000000 --- a/src/instructions/pick.rs +++ /dev/null @@ -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))); -} \ No newline at end of file diff --git a/src/instructions/_unix_random.rs b/src/instructions/platform_specific.rs similarity index 79% rename from src/instructions/_unix_random.rs rename to src/instructions/platform_specific.rs index c88e3de..790f073 100644 --- a/src/instructions/_unix_random.rs +++ b/src/instructions/platform_specific.rs @@ -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)); -} \ No newline at end of file +} diff --git a/src/instructions/pop.rs b/src/instructions/pop.rs deleted file mode 100644 index af94e27..0000000 --- a/src/instructions/pop.rs +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 8649fe9..0000000 --- a/src/instructions/print.rs +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index 34be1aa..0000000 --- a/src/instructions/println.rs +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index 21664b7..0000000 --- a/src/instructions/push.rs +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 06103e9..0000000 --- a/src/instructions/putc.rs +++ /dev/null @@ -1,5 +0,0 @@ -use crate::stack::StackVec; - -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 deleted file mode 100644 index 192a644..0000000 --- a/src/instructions/random.rs +++ /dev/null @@ -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)); -} \ No newline at end of file diff --git a/src/instructions/rjmp.rs b/src/instructions/rjmp.rs deleted file mode 100644 index c3922d2..0000000 --- a/src/instructions/rjmp.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::{errors::RunError, stack::StackVec}; - -pub fn rjmp(memory: &mut StackVec, labels: &mut [Option; 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; -} \ No newline at end of file diff --git a/src/instructions/scan.rs b/src/instructions/scan.rs deleted file mode 100644 index 5144e48..0000000 --- a/src/instructions/scan.rs +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/src/instructions/insert.rs b/src/instructions/self_modify.rs similarity index 86% rename from src/instructions/insert.rs rename to src/instructions/self_modify.rs index 8f84829..ec75b49 100644 --- a/src/instructions/insert.rs +++ b/src/instructions/self_modify.rs @@ -2,25 +2,25 @@ use crate::{errors::RunError, stack::Instruction}; pub fn insert(program: &mut Vec, arg: String, data: u16) { let args: Vec = 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, }); -} \ No newline at end of file +} diff --git a/src/instructions/size.rs b/src/instructions/size.rs deleted file mode 100644 index d94225f..0000000 --- a/src/instructions/size.rs +++ /dev/null @@ -1,5 +0,0 @@ -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/expr.rs b/src/instructions/special.rs similarity index 67% rename from src/instructions/expr.rs rename to src/instructions/special.rs index b3c00de..b892739 100644 --- a/src/instructions/expr.rs +++ b/src/instructions/special.rs @@ -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); } \ No newline at end of file diff --git a/src/instructions/specific.rs b/src/instructions/specific.rs new file mode 100644 index 0000000..00db330 --- /dev/null +++ b/src/instructions/specific.rs @@ -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; 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; +} diff --git a/src/instructions/stack_manage.rs b/src/instructions/stack_manage.rs new file mode 100644 index 0000000..a9201cf --- /dev/null +++ b/src/instructions/stack_manage.rs @@ -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)), + ); +} diff --git a/src/instructions/sub.rs b/src/instructions/sub.rs deleted file mode 100644 index 88e8713..0000000 --- a/src/instructions/sub.rs +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/src/instructions/swap.rs b/src/instructions/swap.rs deleted file mode 100644 index 5ebba5b..0000000 --- a/src/instructions/swap.rs +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/src/instructions/xor.rs b/src/instructions/xor.rs deleted file mode 100644 index 363bf69..0000000 --- a/src/instructions/xor.rs +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index c8673f8..5091cb2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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 { } 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 { } fn parse_stack_size(s: &str) -> Result { - 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()) -} \ No newline at end of file +} diff --git a/src/parse.rs b/src/parse.rs index db340e7..075fff7 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -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 = command[1].split_whitespace().map(String::from).collect(); + if name.chars().nth(0) == Some('#') || name.chars().nth(1) == Some('#') { + let splited_data: Vec = + 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::() { 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); } } diff --git a/src/stack.rs b/src/stack.rs index 121fce5..601be6b 100644 --- a/src/stack.rs +++ b/src/stack.rs @@ -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, pub program_counter: u16, pub labels: [Option; 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, - 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 } -} \ No newline at end of file +}