labast/src/execute.rs
2024-02-08 23:45:03 +05:00

148 lines
6.2 KiB
Rust

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;
}
if stack.labels[label.data as usize].is_some() {
eprintln!("Label {} already defined", label.data);
std::process::exit(2);
}
if label.data == 0 {
stack.labels[0] = Some(stack.program_counter as i16);
continue;
}
stack.labels[label.data as usize] = Some(stack.program_counter as i16);
}
stack.program_counter = stack.labels[0].unwrap_or(0) as u16;
}
fn find_prefix_operators(instruction: &mut Instruction, memory: &mut StackVec) {
match instruction.name.chars().nth(0) {
Some('|') => {
instruction.name = instruction.name.chars().skip(1).collect();
instruction.data = memory.pop();
},
Some('^') => {
instruction.name = instruction.name.chars().skip(1).collect();
if instruction.name.chars().nth(0) != Some('#') {
println!("{0} {1}", instruction.name, instruction.data.to_string());
} else if instruction.arg.is_empty() {
println!("{}", instruction.name);
} else {
println!("{0} {1}", instruction.name, instruction.arg);
}
}
_ => {}
}
}
pub fn execute(stack: &mut Stack, mut origin_stack: Option<&mut Stack>, mod_name: String) {
find_labels(stack);
while let Some(mut instruction) = stack.program.get_mut(stack.program_counter as usize) {
stack.program_counter += 1;
find_prefix_operators(&mut instruction, &mut stack.memory);
if instruction.name.starts_with('@') {
continue;
}
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),
// 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),
// 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),
// 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),
// Labels
"jmp" => instructions::jmp::jmp(&mut stack.labels, &mut stack.program_counter, instruction.data),
"jnz" => instructions::jnz::jnz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, instruction.data),
"jz" => instructions::jz::jz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, instruction.data),
"kjnz" => instructions::kjnz::kjnz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, instruction.data),
"kjz" => instructions::kjz::kjz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, instruction.data),
// 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()),
// Modules
"args" => instructions::args::args(&mut stack.memory, &mut origin_stack, instruction.data),
"#exec" => {
let arg = instruction.arg.clone();
instructions::exec::exec(stack, arg, mod_name.clone())
},
// Self-modifying
"#insert" => {
let arg = instruction.arg.clone();
let data = instruction.data.clone();
instructions::insert::insert(&mut stack.program, arg, data)
},
// Special
"dump" => instructions::dump::dump(&mut stack.memory),
"size" => instructions::size::size(&mut stack.memory),
"maxsize" => instructions::maxsize::maxsize(&mut stack.memory),
"#expr" => instructions::expr::expr(&mut stack.memory, instruction.arg.clone()),
"nop" => continue,
"quit" => break,
"exit" => instructions::exit::exit(instruction.data),
// Platform-specific
#[cfg(target_family = "unix")]
"_unix_random" => instructions::_unix_random::_unix_random(&mut stack.memory),
#[cfg(not(target_family = "unix"))]
"_unix_random" => instructions::random::random(&mut stack.memory),
// Labast-specific
"random" => instructions::random::random(&mut stack.memory),
_ => {
eprintln!("Unknown instruction: {}", instruction.name);
std::process::exit(2);
}
}
}
}