use crate::push::instructions::Instruction;
use crate::push::instructions::InstructionCache;
use crate::push::random::CodeGenerator;
use crate::push::state::PushState;
use crate::push::state::*;
use std::collections::HashMap;
pub fn load_name_instructions(map: &mut HashMap<String, Instruction>) {
map.insert(String::from("NAME.="), Instruction::new(name_equal));
map.insert(String::from("NAME.CAT"), Instruction::new(name_cat));
map.insert(String::from("NAME.DUP"), Instruction::new(name_dup));
map.insert(String::from("NAME.FLUSH"), Instruction::new(name_flush));
map.insert(String::from("NAME.ID"), Instruction::new(name_id));
map.insert(String::from("NAME.POP"), Instruction::new(name_pop));
map.insert(String::from("NAME.QUOTE"), Instruction::new(name_quote));
map.insert(String::from("NAME.RAND"), Instruction::new(name_rand));
map.insert(
String::from("NAME.RANDBOUNDNAME"),
Instruction::new(name_rand_bound),
);
map.insert(String::from("NAME.ROT"), Instruction::new(name_rot));
map.insert(String::from("NAME.SEND"), Instruction::new(name_send));
map.insert(String::from("NAME.SHOVE"), Instruction::new(name_shove));
map.insert(
String::from("NAME.STACKDEPTH"),
Instruction::new(name_stack_depth),
);
map.insert(String::from("NAME.SWAP"), Instruction::new(name_swap));
map.insert(String::from("NAME.YANK"), Instruction::new(name_yank));
map.insert(
String::from("NAME.YANKDUP"),
Instruction::new(name_yank_dup),
);
}
pub fn name_id(push_state: &mut PushState, _instruction_set: &InstructionCache) {
push_state.int_stack.push(NAME_STACK_ID);
}
fn name_cat(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
if let Some(nvals) = push_state.name_stack.pop_vec(2) {
let mut catstr = nvals[0].clone();
catstr.push_str(&" ".to_string());
catstr.push_str(&nvals[1]);
push_state.name_stack.push(catstr);
}
}
fn name_equal(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
if let Some(nvals) = push_state.name_stack.pop_vec(2) {
push_state.bool_stack.push(nvals[0] == nvals[1]);
}
}
pub fn name_dup(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
if let Some(nval) = push_state.name_stack.copy(0) {
push_state.name_stack.push(nval);
}
}
pub fn name_flush(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
push_state.name_stack.flush();
}
pub fn name_pop(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
push_state.name_stack.pop();
}
pub fn name_quote(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
push_state.quote_name = true;
}
pub fn name_rand(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
push_state.name_stack.push(CodeGenerator::new_random_name());
}
pub fn name_rand_bound(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
push_state
.name_stack
.push(CodeGenerator::existing_random_name(push_state));
}
pub fn name_rot(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
push_state.name_stack.yank(2);
}
pub fn name_send(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
push_state.send_name = true;
}
pub fn name_shove(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
if let Some(shove_index) = push_state.int_stack.pop() {
let corr_index = i32::max(
i32::min((push_state.name_stack.size() as i32) - 1, shove_index),
0,
) as usize;
push_state.name_stack.shove(corr_index as usize);
}
}
pub fn name_stack_depth(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
push_state
.int_stack
.push(push_state.name_stack.size() as i32);
}
pub fn name_swap(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
push_state.name_stack.shove(1);
}
pub fn name_yank(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
if let Some(index) = push_state.int_stack.pop() {
let corr_index = i32::max(
i32::min((push_state.name_stack.size() as i32) - 1, index),
0,
) as usize;
push_state.name_stack.yank(corr_index as usize);
}
}
pub fn name_yank_dup(push_state: &mut PushState, _instruction_cache: &InstructionCache) {
if let Some(index) = push_state.int_stack.pop() {
let corr_index = i32::max(
i32::min((push_state.name_stack.size() as i32) - 1, index),
0,
) as usize;
if let Some(deep_item) = push_state.name_stack.copy(corr_index) {
push_state.name_stack.push(deep_item);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::push::item::Item;
pub fn icache() -> InstructionCache {
InstructionCache::new(vec![])
}
#[test]
fn name_cat_appends_second_item() {
let mut test_state = PushState::new();
test_state.name_stack.push(String::from("Test"));
test_state.name_stack.push(String::from("Test"));
name_cat(&mut test_state, &icache());
assert_eq!(test_state.name_stack.pop().unwrap(), "Test Test".to_string());
}
#[test]
fn name_equal_pushes_result() {
let mut test_state = PushState::new();
test_state.name_stack.push(String::from("Test"));
test_state.name_stack.push(String::from("Test"));
name_equal(&mut test_state, &icache());
assert_eq!(test_state.bool_stack.pop().unwrap(), true);
}
#[test]
fn name_dup_copies_top_element() {
let mut test_state = PushState::new();
test_state.name_stack.push(String::from("Test"));
name_dup(&mut test_state, &icache());
assert_eq!(test_state.name_stack.to_string(), "Test Test");
}
#[test]
fn name_flush_empties_stack() {
let mut test_state = PushState::new();
test_state.name_stack.push(String::from("I1"));
test_state.name_stack.push(String::from("I2"));
name_flush(&mut test_state, &icache());
assert_eq!(test_state.name_stack.to_string(), "");
}
#[test]
fn name_rand_generates_value() {
let mut test_state = PushState::new();
name_rand(&mut test_state, &icache());
assert_eq!(test_state.name_stack.size(), 1);
}
#[test]
fn name_rand_bound_generates_value() {
let mut test_state = PushState::new();
test_state
.name_bindings
.insert(CodeGenerator::new_random_name(), Item::int(1));
name_rand_bound(&mut test_state, &icache());
assert_eq!(test_state.name_stack.size(), 1);
}
#[test]
fn name_rot_shuffles_elements() {
let mut test_state = PushState::new();
test_state.name_stack.push(String::from("Test3"));
test_state.name_stack.push(String::from("Test2"));
test_state.name_stack.push(String::from("Test1"));
assert_eq!(
test_state.name_stack.to_string(),
"Test1 Test2 Test3"
);
name_rot(&mut test_state, &icache());
assert_eq!(
test_state.name_stack.to_string(),
"Test3 Test1 Test2"
);
}
#[test]
fn name_shove_inserts_at_right_position() {
let mut test_state = PushState::new();
test_state.name_stack.push(String::from("Test4"));
test_state.name_stack.push(String::from("Test3"));
test_state.name_stack.push(String::from("Test2"));
test_state.name_stack.push(String::from("Test1"));
assert_eq!(
test_state.name_stack.to_string(),
"Test1 Test2 Test3 Test4"
);
test_state.int_stack.push(2);
name_shove(&mut test_state, &icache());
assert_eq!(
test_state.name_stack.to_string(),
"Test2 Test3 Test1 Test4"
);
}
#[test]
fn name_stack_depth_returns_size() {
let mut test_state = PushState::new();
test_state.name_stack.push(String::from("Test4"));
test_state.name_stack.push(String::from("Test3"));
test_state.name_stack.push(String::from("Test2"));
test_state.name_stack.push(String::from("Test1"));
name_stack_depth(&mut test_state, &icache());
assert_eq!(test_state.int_stack.to_string(), "4");
}
#[test]
fn name_swaps_top_elements() {
let mut test_state = PushState::new();
test_state.name_stack.push(String::from("Test2"));
test_state.name_stack.push(String::from("Test1"));
assert_eq!(test_state.name_stack.to_string(), "Test1 Test2");
name_swap(&mut test_state, &icache());
assert_eq!(test_state.name_stack.to_string(), "Test2 Test1");
}
#[test]
fn name_yank_brings_item_to_top() {
let mut test_state = PushState::new();
test_state.name_stack.push(String::from("Test5"));
test_state.name_stack.push(String::from("Test4"));
test_state.name_stack.push(String::from("Test3"));
test_state.name_stack.push(String::from("Test2"));
test_state.name_stack.push(String::from("Test1"));
assert_eq!(
test_state.name_stack.to_string(),
"Test1 Test2 Test3 Test4 Test5"
);
test_state.int_stack.push(3);
name_yank(&mut test_state, &icache());
assert_eq!(
test_state.name_stack.to_string(),
"Test4 Test1 Test2 Test3 Test5"
);
}
#[test]
fn name_yank_dup_copies_item_to_top() {
let mut test_state = PushState::new();
test_state.name_stack.push(String::from("Test5"));
test_state.name_stack.push(String::from("Test4"));
test_state.name_stack.push(String::from("Test3"));
test_state.name_stack.push(String::from("Test2"));
test_state.name_stack.push(String::from("Test1"));
assert_eq!(
test_state.name_stack.to_string(),
"Test1 Test2 Test3 Test4 Test5"
);
test_state.int_stack.push(3);
name_yank_dup(&mut test_state, &icache());
assert_eq!(
test_state.name_stack.to_string(),
"Test4 Test1 Test2 Test3 Test4 Test5"
);
}
}